All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 00/35] refactoring refspecs
@ 2018-05-14 21:55 Brandon Williams
  2018-05-14 21:55 ` [PATCH 01/35] refspec: move refspec parsing logic into its own file Brandon Williams
                   ` (38 more replies)
  0 siblings, 39 replies; 112+ messages in thread
From: Brandon Williams @ 2018-05-14 21:55 UTC (permalink / raw)
  To: git, bmwill; +Cc: Brandon Williams

When working on protocol v2 I noticed that working with refspecs was a
little difficult because of the various api's that existed.  Some
functions expected an array of "const char *" while others expected an
array of "struct refspec".  In all cases a length parameter needed to be
passed as a parameter as well.  This makes working with refspecs a
little challenging because of the different expectations different parts
of the code base have.

This series refactors how refspecs are handled through out the code base
by renaming the existing struct refspec to refspec_item and introducing
a new 'struct refspec' which is a container of refspec_items, much like
how a pathspec contains pathspec_items.  This simplifies many callers
and makes handling pathspecs a bit easier.

I have some follow on work which I'll build on top of this series, but
since this was already getting a bit lengthy at 35 patches I'll save
that for another time.

Brandon Williams (35):
  refspec: move refspec parsing logic into its own file
  refspec: factor out parsing a single refspec
  refspec: rename struct refspec to struct refspec_item
  refspec: introduce struct refspec
  refspec: convert valid_fetch_refspec to use parse_refspec
  submodule--helper: convert push_check to use struct refspec
  pull: convert get_tracking_branch to use refspec_item_init
  transport: convert transport_push to use struct refspec
  remote: convert check_push_refs to use struct refspec
  remote: convert match_push_refs to use struct refspec
  clone: convert cmd_clone to use refspec_item_init
  fast-export: convert to use struct refspec
  remote: convert push refspecs to struct refspec
  remote: convert fetch refspecs to struct refspec
  transport-helper: convert to use struct refspec
  fetch: convert fetch_one to use struct refspec
  fetch: convert refmap to use struct refspec
  refspec: remove the deprecated functions
  fetch: convert do_fetch to take a struct refspec
  fetch: convert get_ref_map to take a struct refspec
  fetch: convert prune_refs to take a struct refspec
  remote: convert get_stale_heads to take a struct refspec
  remote: convert apply_refspecs to take a struct refspec
  remote: convert query_refspecs to take a struct refspec
  remote: convert get_ref_match to take a struct refspec
  remote: convert match_explicit_refs to take a struct refspec
  push: check for errors earlier
  push: convert to use struct refspec
  transport: convert transport_push to take a struct refspec
  send-pack: store refspecs in a struct refspec
  transport: remove transport_verify_remote_names
  http-push: store refspecs in a struct refspec
  remote: convert match_push_refs to take a struct refspec
  remote: convert check_push_refs to take a struct refspec
  submodule: convert push_unpushed_submodules to take a struct refspec

 Makefile                    |   1 +
 branch.c                    |   7 +-
 builtin/clone.c             |  13 +-
 builtin/fast-export.c       |  22 +--
 builtin/fetch.c             | 128 +++++++-------
 builtin/merge.c             |   1 +
 builtin/pull.c              |   9 +-
 builtin/push.c              |  80 ++++-----
 builtin/remote.c            |  37 ++--
 builtin/send-pack.c         |  24 +--
 builtin/submodule--helper.c |  14 +-
 checkout.c                  |   5 +-
 http-push.c                 |  18 +-
 refspec.c                   | 194 +++++++++++++++++++++
 refspec.h                   |  44 +++++
 remote.c                    | 324 ++++++++----------------------------
 remote.h                    |  48 ++----
 submodule.c                 |  19 +--
 submodule.h                 |   3 +-
 transport-helper.c          |  39 ++---
 transport.c                 |  51 ++----
 transport.h                 |   4 +-
 22 files changed, 514 insertions(+), 571 deletions(-)
 create mode 100644 refspec.c
 create mode 100644 refspec.h

-- 
2.17.0.441.gb46fe60e1d-goog


^ permalink raw reply	[flat|nested] 112+ messages in thread

* [PATCH 01/35] refspec: move refspec parsing logic into its own file
  2018-05-14 21:55 [PATCH 00/35] refactoring refspecs Brandon Williams
@ 2018-05-14 21:55 ` Brandon Williams
  2018-05-15  8:06   ` Junio C Hamano
  2018-05-14 21:55 ` [PATCH 02/35] refspec: factor out parsing a single refspec Brandon Williams
                   ` (37 subsequent siblings)
  38 siblings, 1 reply; 112+ messages in thread
From: Brandon Williams @ 2018-05-14 21:55 UTC (permalink / raw)
  To: git, bmwill; +Cc: Brandon Williams

In preperation for performing a refactor on refspec related code, move
the refspec parsing logic into its own file.

Signed-off-by: Brandon Williams <bmwill@google.com>
---
 Makefile                    |   1 +
 branch.c                    |   1 +
 builtin/clone.c             |   1 +
 builtin/fast-export.c       |   1 +
 builtin/fetch.c             |   1 +
 builtin/merge.c             |   1 +
 builtin/pull.c              |   1 +
 builtin/push.c              |   1 +
 builtin/remote.c            |   1 +
 builtin/submodule--helper.c |   1 +
 checkout.c                  |   1 +
 refspec.c                   | 168 ++++++++++++++++++++++++++++++++++++
 refspec.h                   |  23 +++++
 remote.c                    | 165 +----------------------------------
 remote.h                    |  20 -----
 transport-helper.c          |   1 +
 transport.c                 |   1 +
 17 files changed, 205 insertions(+), 184 deletions(-)
 create mode 100644 refspec.c
 create mode 100644 refspec.h

diff --git a/Makefile b/Makefile
index ad880d1fc..4bca65383 100644
--- a/Makefile
+++ b/Makefile
@@ -928,6 +928,7 @@ LIB_OBJS += refs/files-backend.o
 LIB_OBJS += refs/iterator.o
 LIB_OBJS += refs/packed-backend.o
 LIB_OBJS += refs/ref-cache.o
+LIB_OBJS += refspec.o
 LIB_OBJS += ref-filter.o
 LIB_OBJS += remote.o
 LIB_OBJS += replace-object.o
diff --git a/branch.c b/branch.c
index 2672054f0..32ccefc6b 100644
--- a/branch.c
+++ b/branch.c
@@ -3,6 +3,7 @@
 #include "config.h"
 #include "branch.h"
 #include "refs.h"
+#include "refspec.h"
 #include "remote.h"
 #include "commit.h"
 #include "worktree.h"
diff --git a/builtin/clone.c b/builtin/clone.c
index 84f1473d1..6d1614ed3 100644
--- a/builtin/clone.c
+++ b/builtin/clone.c
@@ -14,6 +14,7 @@
 #include "parse-options.h"
 #include "fetch-pack.h"
 #include "refs.h"
+#include "refspec.h"
 #include "tree.h"
 #include "tree-walk.h"
 #include "unpack-trees.h"
diff --git a/builtin/fast-export.c b/builtin/fast-export.c
index 530df12f0..a13b7c8ef 100644
--- a/builtin/fast-export.c
+++ b/builtin/fast-export.c
@@ -7,6 +7,7 @@
 #include "cache.h"
 #include "config.h"
 #include "refs.h"
+#include "refspec.h"
 #include "commit.h"
 #include "object.h"
 #include "tag.h"
diff --git a/builtin/fetch.c b/builtin/fetch.c
index 7ee83ac0f..1fce68e9a 100644
--- a/builtin/fetch.c
+++ b/builtin/fetch.c
@@ -5,6 +5,7 @@
 #include "config.h"
 #include "repository.h"
 #include "refs.h"
+#include "refspec.h"
 #include "commit.h"
 #include "builtin.h"
 #include "string-list.h"
diff --git a/builtin/merge.c b/builtin/merge.c
index 9db5a2cf1..c362cfe90 100644
--- a/builtin/merge.c
+++ b/builtin/merge.c
@@ -14,6 +14,7 @@
 #include "run-command.h"
 #include "diff.h"
 #include "refs.h"
+#include "refspec.h"
 #include "commit.h"
 #include "diffcore.h"
 #include "revision.h"
diff --git a/builtin/pull.c b/builtin/pull.c
index 71aac5005..6247c956d 100644
--- a/builtin/pull.c
+++ b/builtin/pull.c
@@ -15,6 +15,7 @@
 #include "remote.h"
 #include "dir.h"
 #include "refs.h"
+#include "refspec.h"
 #include "revision.h"
 #include "submodule.h"
 #include "submodule-config.h"
diff --git a/builtin/push.c b/builtin/push.c
index ac3705370..fa65999b2 100644
--- a/builtin/push.c
+++ b/builtin/push.c
@@ -4,6 +4,7 @@
 #include "cache.h"
 #include "config.h"
 #include "refs.h"
+#include "refspec.h"
 #include "run-command.h"
 #include "builtin.h"
 #include "remote.h"
diff --git a/builtin/remote.c b/builtin/remote.c
index 8708e584e..c49513995 100644
--- a/builtin/remote.c
+++ b/builtin/remote.c
@@ -7,6 +7,7 @@
 #include "strbuf.h"
 #include "run-command.h"
 #include "refs.h"
+#include "refspec.h"
 #include "argv-array.h"
 
 static const char * const builtin_remote_usage[] = {
diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
index c2403a915..6ab032acb 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -12,6 +12,7 @@
 #include "run-command.h"
 #include "remote.h"
 #include "refs.h"
+#include "refspec.h"
 #include "connect.h"
 #include "revision.h"
 #include "diffcore.h"
diff --git a/checkout.c b/checkout.c
index ac42630f7..193ba8567 100644
--- a/checkout.c
+++ b/checkout.c
@@ -1,5 +1,6 @@
 #include "cache.h"
 #include "remote.h"
+#include "refspec.h"
 #include "checkout.h"
 
 struct tracking_name_data {
diff --git a/refspec.c b/refspec.c
new file mode 100644
index 000000000..ecb0bdff3
--- /dev/null
+++ b/refspec.c
@@ -0,0 +1,168 @@
+#include "cache.h"
+#include "refs.h"
+#include "refspec.h"
+
+static struct refspec s_tag_refspec = {
+	0,
+	1,
+	0,
+	0,
+	"refs/tags/*",
+	"refs/tags/*"
+};
+
+/* See TAG_REFSPEC for the string version */
+const struct refspec *tag_refspec = &s_tag_refspec;
+
+static struct refspec *parse_refspec_internal(int nr_refspec, const char **refspec, int fetch, int verify)
+{
+	int i;
+	struct refspec *rs = xcalloc(nr_refspec, sizeof(*rs));
+
+	for (i = 0; i < nr_refspec; i++) {
+		size_t llen;
+		int is_glob;
+		const char *lhs, *rhs;
+		int flags;
+
+		is_glob = 0;
+
+		lhs = refspec[i];
+		if (*lhs == '+') {
+			rs[i].force = 1;
+			lhs++;
+		}
+
+		rhs = strrchr(lhs, ':');
+
+		/*
+		 * Before going on, special case ":" (or "+:") as a refspec
+		 * for pushing matching refs.
+		 */
+		if (!fetch && rhs == lhs && rhs[1] == '\0') {
+			rs[i].matching = 1;
+			continue;
+		}
+
+		if (rhs) {
+			size_t rlen = strlen(++rhs);
+			is_glob = (1 <= rlen && strchr(rhs, '*'));
+			rs[i].dst = xstrndup(rhs, rlen);
+		}
+
+		llen = (rhs ? (rhs - lhs - 1) : strlen(lhs));
+		if (1 <= llen && memchr(lhs, '*', llen)) {
+			if ((rhs && !is_glob) || (!rhs && fetch))
+				goto invalid;
+			is_glob = 1;
+		} else if (rhs && is_glob) {
+			goto invalid;
+		}
+
+		rs[i].pattern = is_glob;
+		rs[i].src = xstrndup(lhs, llen);
+		flags = REFNAME_ALLOW_ONELEVEL | (is_glob ? REFNAME_REFSPEC_PATTERN : 0);
+
+		if (fetch) {
+			struct object_id unused;
+
+			/* LHS */
+			if (!*rs[i].src)
+				; /* empty is ok; it means "HEAD" */
+			else if (llen == GIT_SHA1_HEXSZ && !get_oid_hex(rs[i].src, &unused))
+				rs[i].exact_sha1 = 1; /* ok */
+			else if (!check_refname_format(rs[i].src, flags))
+				; /* valid looking ref is ok */
+			else
+				goto invalid;
+			/* RHS */
+			if (!rs[i].dst)
+				; /* missing is ok; it is the same as empty */
+			else if (!*rs[i].dst)
+				; /* empty is ok; it means "do not store" */
+			else if (!check_refname_format(rs[i].dst, flags))
+				; /* valid looking ref is ok */
+			else
+				goto invalid;
+		} else {
+			/*
+			 * LHS
+			 * - empty is allowed; it means delete.
+			 * - when wildcarded, it must be a valid looking ref.
+			 * - otherwise, it must be an extended SHA-1, but
+			 *   there is no existing way to validate this.
+			 */
+			if (!*rs[i].src)
+				; /* empty is ok */
+			else if (is_glob) {
+				if (check_refname_format(rs[i].src, flags))
+					goto invalid;
+			}
+			else
+				; /* anything goes, for now */
+			/*
+			 * RHS
+			 * - missing is allowed, but LHS then must be a
+			 *   valid looking ref.
+			 * - empty is not allowed.
+			 * - otherwise it must be a valid looking ref.
+			 */
+			if (!rs[i].dst) {
+				if (check_refname_format(rs[i].src, flags))
+					goto invalid;
+			} else if (!*rs[i].dst) {
+				goto invalid;
+			} else {
+				if (check_refname_format(rs[i].dst, flags))
+					goto invalid;
+			}
+		}
+	}
+	return rs;
+
+ invalid:
+	if (verify) {
+		/*
+		 * nr_refspec must be greater than zero and i must be valid
+		 * since it is only possible to reach this point from within
+		 * the for loop above.
+		 */
+		free_refspec(i+1, rs);
+		return NULL;
+	}
+	die("Invalid refspec '%s'", refspec[i]);
+}
+
+int valid_fetch_refspec(const char *fetch_refspec_str)
+{
+	struct refspec *refspec;
+
+	refspec = parse_refspec_internal(1, &fetch_refspec_str, 1, 1);
+	free_refspec(1, refspec);
+	return !!refspec;
+}
+
+struct refspec *parse_fetch_refspec(int nr_refspec, const char **refspec)
+{
+	return parse_refspec_internal(nr_refspec, refspec, 1, 0);
+}
+
+struct refspec *parse_push_refspec(int nr_refspec, const char **refspec)
+{
+	return parse_refspec_internal(nr_refspec, refspec, 0, 0);
+}
+
+void free_refspec(int nr_refspec, struct refspec *refspec)
+{
+	int i;
+
+	if (!refspec)
+		return;
+
+	for (i = 0; i < nr_refspec; i++) {
+		free(refspec[i].src);
+		free(refspec[i].dst);
+	}
+	free(refspec);
+}
+
diff --git a/refspec.h b/refspec.h
new file mode 100644
index 000000000..b1db91918
--- /dev/null
+++ b/refspec.h
@@ -0,0 +1,23 @@
+#ifndef REFSPEC_H
+#define REFSPEC_H
+
+#define TAG_REFSPEC "refs/tags/*:refs/tags/*"
+const struct refspec *tag_refspec;
+
+struct refspec {
+	unsigned force : 1;
+	unsigned pattern : 1;
+	unsigned matching : 1;
+	unsigned exact_sha1 : 1;
+
+	char *src;
+	char *dst;
+};
+
+int valid_fetch_refspec(const char *refspec);
+struct refspec *parse_fetch_refspec(int nr_refspec, const char **refspec);
+struct refspec *parse_push_refspec(int nr_refspec, const char **refspec);
+
+void free_refspec(int nr_refspec, struct refspec *refspec);
+
+#endif /* REFSPEC_H */
diff --git a/remote.c b/remote.c
index 91eb010ca..4d67c061a 100644
--- a/remote.c
+++ b/remote.c
@@ -2,6 +2,7 @@
 #include "config.h"
 #include "remote.h"
 #include "refs.h"
+#include "refspec.h"
 #include "commit.h"
 #include "diff.h"
 #include "revision.h"
@@ -13,18 +14,6 @@
 
 enum map_direction { FROM_SRC, FROM_DST };
 
-static struct refspec s_tag_refspec = {
-	0,
-	1,
-	0,
-	0,
-	"refs/tags/*",
-	"refs/tags/*"
-};
-
-/* See TAG_REFSPEC for the string version */
-const struct refspec *tag_refspec = &s_tag_refspec;
-
 struct counted_string {
 	size_t len;
 	const char *s;
@@ -499,158 +488,6 @@ static void read_config(void)
 	alias_all_urls();
 }
 
-static struct refspec *parse_refspec_internal(int nr_refspec, const char **refspec, int fetch, int verify)
-{
-	int i;
-	struct refspec *rs = xcalloc(nr_refspec, sizeof(*rs));
-
-	for (i = 0; i < nr_refspec; i++) {
-		size_t llen;
-		int is_glob;
-		const char *lhs, *rhs;
-		int flags;
-
-		is_glob = 0;
-
-		lhs = refspec[i];
-		if (*lhs == '+') {
-			rs[i].force = 1;
-			lhs++;
-		}
-
-		rhs = strrchr(lhs, ':');
-
-		/*
-		 * Before going on, special case ":" (or "+:") as a refspec
-		 * for pushing matching refs.
-		 */
-		if (!fetch && rhs == lhs && rhs[1] == '\0') {
-			rs[i].matching = 1;
-			continue;
-		}
-
-		if (rhs) {
-			size_t rlen = strlen(++rhs);
-			is_glob = (1 <= rlen && strchr(rhs, '*'));
-			rs[i].dst = xstrndup(rhs, rlen);
-		}
-
-		llen = (rhs ? (rhs - lhs - 1) : strlen(lhs));
-		if (1 <= llen && memchr(lhs, '*', llen)) {
-			if ((rhs && !is_glob) || (!rhs && fetch))
-				goto invalid;
-			is_glob = 1;
-		} else if (rhs && is_glob) {
-			goto invalid;
-		}
-
-		rs[i].pattern = is_glob;
-		rs[i].src = xstrndup(lhs, llen);
-		flags = REFNAME_ALLOW_ONELEVEL | (is_glob ? REFNAME_REFSPEC_PATTERN : 0);
-
-		if (fetch) {
-			struct object_id unused;
-
-			/* LHS */
-			if (!*rs[i].src)
-				; /* empty is ok; it means "HEAD" */
-			else if (llen == GIT_SHA1_HEXSZ && !get_oid_hex(rs[i].src, &unused))
-				rs[i].exact_sha1 = 1; /* ok */
-			else if (!check_refname_format(rs[i].src, flags))
-				; /* valid looking ref is ok */
-			else
-				goto invalid;
-			/* RHS */
-			if (!rs[i].dst)
-				; /* missing is ok; it is the same as empty */
-			else if (!*rs[i].dst)
-				; /* empty is ok; it means "do not store" */
-			else if (!check_refname_format(rs[i].dst, flags))
-				; /* valid looking ref is ok */
-			else
-				goto invalid;
-		} else {
-			/*
-			 * LHS
-			 * - empty is allowed; it means delete.
-			 * - when wildcarded, it must be a valid looking ref.
-			 * - otherwise, it must be an extended SHA-1, but
-			 *   there is no existing way to validate this.
-			 */
-			if (!*rs[i].src)
-				; /* empty is ok */
-			else if (is_glob) {
-				if (check_refname_format(rs[i].src, flags))
-					goto invalid;
-			}
-			else
-				; /* anything goes, for now */
-			/*
-			 * RHS
-			 * - missing is allowed, but LHS then must be a
-			 *   valid looking ref.
-			 * - empty is not allowed.
-			 * - otherwise it must be a valid looking ref.
-			 */
-			if (!rs[i].dst) {
-				if (check_refname_format(rs[i].src, flags))
-					goto invalid;
-			} else if (!*rs[i].dst) {
-				goto invalid;
-			} else {
-				if (check_refname_format(rs[i].dst, flags))
-					goto invalid;
-			}
-		}
-	}
-	return rs;
-
- invalid:
-	if (verify) {
-		/*
-		 * nr_refspec must be greater than zero and i must be valid
-		 * since it is only possible to reach this point from within
-		 * the for loop above.
-		 */
-		free_refspec(i+1, rs);
-		return NULL;
-	}
-	die("Invalid refspec '%s'", refspec[i]);
-}
-
-int valid_fetch_refspec(const char *fetch_refspec_str)
-{
-	struct refspec *refspec;
-
-	refspec = parse_refspec_internal(1, &fetch_refspec_str, 1, 1);
-	free_refspec(1, refspec);
-	return !!refspec;
-}
-
-struct refspec *parse_fetch_refspec(int nr_refspec, const char **refspec)
-{
-	return parse_refspec_internal(nr_refspec, refspec, 1, 0);
-}
-
-struct refspec *parse_push_refspec(int nr_refspec, const char **refspec)
-{
-	return parse_refspec_internal(nr_refspec, refspec, 0, 0);
-}
-
-void free_refspec(int nr_refspec, struct refspec *refspec)
-{
-	int i;
-
-	if (!refspec)
-		return;
-
-	for (i = 0; i < nr_refspec; i++) {
-		free(refspec[i].src);
-		free(refspec[i].dst);
-	}
-	free(refspec);
-}
-
 static int valid_remote_nick(const char *name)
 {
 	if (!name[0] || is_dot_or_dotdot(name))
diff --git a/remote.h b/remote.h
index 2b3180f94..386ced901 100644
--- a/remote.h
+++ b/remote.h
@@ -68,18 +68,6 @@ int for_each_remote(each_remote_fn fn, void *priv);
 
 int remote_has_url(struct remote *remote, const char *url);
 
-struct refspec {
-	unsigned force : 1;
-	unsigned pattern : 1;
-	unsigned matching : 1;
-	unsigned exact_sha1 : 1;
-
-	char *src;
-	char *dst;
-};
-
-extern const struct refspec *tag_refspec;
-
 struct ref {
 	struct ref *next;
 	struct object_id old_oid;
@@ -175,12 +163,6 @@ int ref_newer(const struct object_id *new_oid, const struct object_id *old_oid);
  */
 struct ref *ref_remove_duplicates(struct ref *ref_map);
 
-int valid_fetch_refspec(const char *refspec);
-struct refspec *parse_fetch_refspec(int nr_refspec, const char **refspec);
-extern struct refspec *parse_push_refspec(int nr_refspec, const char **refspec);
-
-void free_refspec(int nr_refspec, struct refspec *refspec);
-
 extern int query_refspecs(struct refspec *specs, int nr, struct refspec *query);
 char *apply_refspecs(struct refspec *refspecs, int nr_refspec,
 		     const char *name);
@@ -313,8 +295,6 @@ extern int parseopt_push_cas_option(const struct option *, const char *arg, int
 extern int is_empty_cas(const struct push_cas_option *);
 void apply_push_cas(struct push_cas_option *, struct remote *, struct ref *);
 
-#define TAG_REFSPEC "refs/tags/*:refs/tags/*"
-
 void add_prune_tags_to_fetch_refspec(struct remote *remote);
 
 #endif
diff --git a/transport-helper.c b/transport-helper.c
index 11f1055b4..b99e1cce9 100644
--- a/transport-helper.c
+++ b/transport-helper.c
@@ -11,6 +11,7 @@
 #include "sigchain.h"
 #include "argv-array.h"
 #include "refs.h"
+#include "refspec.h"
 #include "transport-internal.h"
 #include "protocol.h"
 
diff --git a/transport.c b/transport.c
index 37410d8aa..2cf63d18b 100644
--- a/transport.c
+++ b/transport.c
@@ -11,6 +11,7 @@
 #include "bundle.h"
 #include "dir.h"
 #include "refs.h"
+#include "refspec.h"
 #include "branch.h"
 #include "url.h"
 #include "submodule.h"
-- 
2.17.0.441.gb46fe60e1d-goog


^ permalink raw reply related	[flat|nested] 112+ messages in thread

* [PATCH 02/35] refspec: factor out parsing a single refspec
  2018-05-14 21:55 [PATCH 00/35] refactoring refspecs Brandon Williams
  2018-05-14 21:55 ` [PATCH 01/35] refspec: move refspec parsing logic into its own file Brandon Williams
@ 2018-05-14 21:55 ` Brandon Williams
  2018-05-14 21:55 ` [PATCH 03/35] refspec: rename struct refspec to struct refspec_item Brandon Williams
                   ` (36 subsequent siblings)
  38 siblings, 0 replies; 112+ messages in thread
From: Brandon Williams @ 2018-05-14 21:55 UTC (permalink / raw)
  To: git, bmwill; +Cc: Brandon Williams

Factor out the logic which parses a single refspec into its own
function.  This makes it easier to reuse this logic in a future patch.

Signed-off-by: Brandon Williams <bmwill@google.com>
---
 refspec.c | 195 +++++++++++++++++++++++++++++-------------------------
 1 file changed, 104 insertions(+), 91 deletions(-)

diff --git a/refspec.c b/refspec.c
index ecb0bdff3..3cfcbd37d 100644
--- a/refspec.c
+++ b/refspec.c
@@ -14,110 +14,123 @@ static struct refspec s_tag_refspec = {
 /* See TAG_REFSPEC for the string version */
 const struct refspec *tag_refspec = &s_tag_refspec;
 
-static struct refspec *parse_refspec_internal(int nr_refspec, const char **refspec, int fetch, int verify)
+/*
+ * Parses 'refspec' and populates 'rs'.  returns 1 if successful and 0 if the
+ * refspec is invalid.
+ */
+static int parse_refspec(struct refspec *rs, const char *refspec, int fetch)
 {
-	int i;
-	struct refspec *rs = xcalloc(nr_refspec, sizeof(*rs));
+	size_t llen;
+	int is_glob;
+	const char *lhs, *rhs;
+	int flags;
 
-	for (i = 0; i < nr_refspec; i++) {
-		size_t llen;
-		int is_glob;
-		const char *lhs, *rhs;
-		int flags;
+	is_glob = 0;
 
-		is_glob = 0;
+	lhs = refspec;
+	if (*lhs == '+') {
+		rs->force = 1;
+		lhs++;
+	}
 
-		lhs = refspec[i];
-		if (*lhs == '+') {
-			rs[i].force = 1;
-			lhs++;
-		}
+	rhs = strrchr(lhs, ':');
 
-		rhs = strrchr(lhs, ':');
+	/*
+	 * Before going on, special case ":" (or "+:") as a refspec
+	 * for pushing matching refs.
+	 */
+	if (!fetch && rhs == lhs && rhs[1] == '\0') {
+		rs->matching = 1;
+		return 1;
+	}
 
+	if (rhs) {
+		size_t rlen = strlen(++rhs);
+		is_glob = (1 <= rlen && strchr(rhs, '*'));
+		rs->dst = xstrndup(rhs, rlen);
+	}
+
+	llen = (rhs ? (rhs - lhs - 1) : strlen(lhs));
+	if (1 <= llen && memchr(lhs, '*', llen)) {
+		if ((rhs && !is_glob) || (!rhs && fetch))
+			return 0;
+		is_glob = 1;
+	} else if (rhs && is_glob) {
+		return 0;
+	}
+
+	rs->pattern = is_glob;
+	rs->src = xstrndup(lhs, llen);
+	flags = REFNAME_ALLOW_ONELEVEL | (is_glob ? REFNAME_REFSPEC_PATTERN : 0);
+
+	if (fetch) {
+		struct object_id unused;
+
+		/* LHS */
+		if (!*rs->src)
+			; /* empty is ok; it means "HEAD" */
+		else if (llen == GIT_SHA1_HEXSZ && !get_oid_hex(rs->src, &unused))
+			rs->exact_sha1 = 1; /* ok */
+		else if (!check_refname_format(rs->src, flags))
+			; /* valid looking ref is ok */
+		else
+			return 0;
+		/* RHS */
+		if (!rs->dst)
+			; /* missing is ok; it is the same as empty */
+		else if (!*rs->dst)
+			; /* empty is ok; it means "do not store" */
+		else if (!check_refname_format(rs->dst, flags))
+			; /* valid looking ref is ok */
+		else
+			return 0;
+	} else {
 		/*
-		 * Before going on, special case ":" (or "+:") as a refspec
-		 * for pushing matching refs.
+		 * LHS
+		 * - empty is allowed; it means delete.
+		 * - when wildcarded, it must be a valid looking ref.
+		 * - otherwise, it must be an extended SHA-1, but
+		 *   there is no existing way to validate this.
 		 */
-		if (!fetch && rhs == lhs && rhs[1] == '\0') {
-			rs[i].matching = 1;
-			continue;
+		if (!*rs->src)
+			; /* empty is ok */
+		else if (is_glob) {
+			if (check_refname_format(rs->src, flags))
+				return 0;
 		}
-
-		if (rhs) {
-			size_t rlen = strlen(++rhs);
-			is_glob = (1 <= rlen && strchr(rhs, '*'));
-			rs[i].dst = xstrndup(rhs, rlen);
+		else
+			; /* anything goes, for now */
+		/*
+		 * RHS
+		 * - missing is allowed, but LHS then must be a
+		 *   valid looking ref.
+		 * - empty is not allowed.
+		 * - otherwise it must be a valid looking ref.
+		 */
+		if (!rs->dst) {
+			if (check_refname_format(rs->src, flags))
+				return 0;
+		} else if (!*rs->dst) {
+			return 0;
+		} else {
+			if (check_refname_format(rs->dst, flags))
+				return 0;
 		}
+	}
 
-		llen = (rhs ? (rhs - lhs - 1) : strlen(lhs));
-		if (1 <= llen && memchr(lhs, '*', llen)) {
-			if ((rhs && !is_glob) || (!rhs && fetch))
-				goto invalid;
-			is_glob = 1;
-		} else if (rhs && is_glob) {
-			goto invalid;
-		}
+	return 1;
+}
 
-		rs[i].pattern = is_glob;
-		rs[i].src = xstrndup(lhs, llen);
-		flags = REFNAME_ALLOW_ONELEVEL | (is_glob ? REFNAME_REFSPEC_PATTERN : 0);
-
-		if (fetch) {
-			struct object_id unused;
-
-			/* LHS */
-			if (!*rs[i].src)
-				; /* empty is ok; it means "HEAD" */
-			else if (llen == GIT_SHA1_HEXSZ && !get_oid_hex(rs[i].src, &unused))
-				rs[i].exact_sha1 = 1; /* ok */
-			else if (!check_refname_format(rs[i].src, flags))
-				; /* valid looking ref is ok */
-			else
-				goto invalid;
-			/* RHS */
-			if (!rs[i].dst)
-				; /* missing is ok; it is the same as empty */
-			else if (!*rs[i].dst)
-				; /* empty is ok; it means "do not store" */
-			else if (!check_refname_format(rs[i].dst, flags))
-				; /* valid looking ref is ok */
-			else
-				goto invalid;
-		} else {
-			/*
-			 * LHS
-			 * - empty is allowed; it means delete.
-			 * - when wildcarded, it must be a valid looking ref.
-			 * - otherwise, it must be an extended SHA-1, but
-			 *   there is no existing way to validate this.
-			 */
-			if (!*rs[i].src)
-				; /* empty is ok */
-			else if (is_glob) {
-				if (check_refname_format(rs[i].src, flags))
-					goto invalid;
-			}
-			else
-				; /* anything goes, for now */
-			/*
-			 * RHS
-			 * - missing is allowed, but LHS then must be a
-			 *   valid looking ref.
-			 * - empty is not allowed.
-			 * - otherwise it must be a valid looking ref.
-			 */
-			if (!rs[i].dst) {
-				if (check_refname_format(rs[i].src, flags))
-					goto invalid;
-			} else if (!*rs[i].dst) {
-				goto invalid;
-			} else {
-				if (check_refname_format(rs[i].dst, flags))
-					goto invalid;
-			}
-		}
+static struct refspec *parse_refspec_internal(int nr_refspec, const char **refspec, int fetch, int verify)
+{
+	int i;
+	struct refspec *rs = xcalloc(nr_refspec, sizeof(*rs));
+
+	for (i = 0; i < nr_refspec; i++) {
+		if (!parse_refspec(&rs[i], refspec[i], fetch))
+			goto invalid;
 	}
+
 	return rs;
 
  invalid:
-- 
2.17.0.441.gb46fe60e1d-goog


^ permalink raw reply related	[flat|nested] 112+ messages in thread

* [PATCH 03/35] refspec: rename struct refspec to struct refspec_item
  2018-05-14 21:55 [PATCH 00/35] refactoring refspecs Brandon Williams
  2018-05-14 21:55 ` [PATCH 01/35] refspec: move refspec parsing logic into its own file Brandon Williams
  2018-05-14 21:55 ` [PATCH 02/35] refspec: factor out parsing a single refspec Brandon Williams
@ 2018-05-14 21:55 ` Brandon Williams
  2018-05-15  8:17   ` Junio C Hamano
  2018-05-14 21:55 ` [PATCH 04/35] refspec: introduce struct refspec Brandon Williams
                   ` (35 subsequent siblings)
  38 siblings, 1 reply; 112+ messages in thread
From: Brandon Williams @ 2018-05-14 21:55 UTC (permalink / raw)
  To: git, bmwill; +Cc: Brandon Williams

In preperation for introducing an abstraction around a collection of
refspecs (much like how a 'struct pathspec' is a collection of 'struct
pathspec_item's) rename the existing 'struct refspec' to 'struct
refspec_item'.

Signed-off-by: Brandon Williams <bmwill@google.com>
---
 branch.c                    |  6 ++---
 builtin/clone.c             |  4 +--
 builtin/fast-export.c       |  4 +--
 builtin/fetch.c             | 12 ++++-----
 builtin/pull.c              |  2 +-
 builtin/push.c              |  4 +--
 builtin/remote.c            |  8 +++---
 builtin/submodule--helper.c |  4 +--
 checkout.c                  |  4 +--
 refspec.c                   | 19 +++++++-------
 refspec.h                   | 10 ++++----
 remote.c                    | 50 ++++++++++++++++++-------------------
 remote.h                    | 16 ++++++------
 transport-helper.c          |  2 +-
 transport.c                 |  4 +--
 15 files changed, 74 insertions(+), 75 deletions(-)

diff --git a/branch.c b/branch.c
index 32ccefc6b..f967c98f6 100644
--- a/branch.c
+++ b/branch.c
@@ -9,7 +9,7 @@
 #include "worktree.h"
 
 struct tracking {
-	struct refspec spec;
+	struct refspec_item spec;
 	char *src;
 	const char *remote;
 	int matches;
@@ -219,8 +219,8 @@ int validate_new_branchname(const char *name, struct strbuf *ref, int force)
 static int check_tracking_branch(struct remote *remote, void *cb_data)
 {
 	char *tracking_branch = cb_data;
-	struct refspec query;
-	memset(&query, 0, sizeof(struct refspec));
+	struct refspec_item query;
+	memset(&query, 0, sizeof(struct refspec_item));
 	query.dst = tracking_branch;
 	return !remote_find_tracking(remote, &query);
 }
diff --git a/builtin/clone.c b/builtin/clone.c
index 6d1614ed3..854088a3a 100644
--- a/builtin/clone.c
+++ b/builtin/clone.c
@@ -547,7 +547,7 @@ static struct ref *find_remote_branch(const struct ref *refs, const char *branch
 }
 
 static struct ref *wanted_peer_refs(const struct ref *refs,
-		struct refspec *refspec)
+		struct refspec_item *refspec)
 {
 	struct ref *head = copy_ref(find_ref_by_name(refs, "HEAD"));
 	struct ref *local_refs = head;
@@ -895,7 +895,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
 	int err = 0, complete_refs_before_fetch = 1;
 	int submodule_progress;
 
-	struct refspec *refspec;
+	struct refspec_item *refspec;
 	const char *fetch_pattern;
 
 	fetch_if_missing = 0;
diff --git a/builtin/fast-export.c b/builtin/fast-export.c
index a13b7c8ef..6f105dc79 100644
--- a/builtin/fast-export.c
+++ b/builtin/fast-export.c
@@ -36,7 +36,7 @@ static int use_done_feature;
 static int no_data;
 static int full_tree;
 static struct string_list extra_refs = STRING_LIST_INIT_NODUP;
-static struct refspec *refspecs;
+static struct refspec_item *refspecs;
 static int refspecs_nr;
 static int anonymize;
 
@@ -979,7 +979,7 @@ static void handle_deletes(void)
 {
 	int i;
 	for (i = 0; i < refspecs_nr; i++) {
-		struct refspec *refspec = &refspecs[i];
+		struct refspec_item *refspec = &refspecs[i];
 		if (*refspec->src)
 			continue;
 
diff --git a/builtin/fetch.c b/builtin/fetch.c
index 1fce68e9a..745020a10 100644
--- a/builtin/fetch.c
+++ b/builtin/fetch.c
@@ -203,7 +203,7 @@ static void add_merge_config(struct ref **head,
 
 	for (i = 0; i < branch->merge_nr; i++) {
 		struct ref *rm, **old_tail = *tail;
-		struct refspec refspec;
+		struct refspec_item refspec;
 
 		for (rm = *head; rm; rm = rm->next) {
 			if (branch_merge_matches(branch, i, rm->name)) {
@@ -340,7 +340,7 @@ static void find_non_local_tags(struct transport *transport,
 }
 
 static struct ref *get_ref_map(struct transport *transport,
-			       struct refspec *refspecs, int refspec_count,
+			       struct refspec_item *refspecs, int refspec_count,
 			       int tags, int *autotags)
 {
 	int i;
@@ -371,7 +371,7 @@ static struct ref *get_ref_map(struct transport *transport,
 	argv_array_clear(&ref_prefixes);
 
 	if (refspec_count) {
-		struct refspec *fetch_refspec;
+		struct refspec_item *fetch_refspec;
 		int fetch_refspec_nr;
 
 		for (i = 0; i < refspec_count; i++) {
@@ -965,7 +965,7 @@ static int fetch_refs(struct transport *transport, struct ref *ref_map)
 	return ret;
 }
 
-static int prune_refs(struct refspec *refs, int ref_count, struct ref *ref_map,
+static int prune_refs(struct refspec_item *refs, int ref_count, struct ref *ref_map,
 		const char *raw_url)
 {
 	int url_len, i, result = 0;
@@ -1115,7 +1115,7 @@ static void backfill_tags(struct transport *transport, struct ref *ref_map)
 }
 
 static int do_fetch(struct transport *transport,
-		    struct refspec *refs, int ref_count)
+		    struct refspec_item *refs, int ref_count)
 {
 	struct string_list existing_refs = STRING_LIST_INIT_DUP;
 	struct ref *ref_map;
@@ -1357,7 +1357,7 @@ static inline void fetch_one_setup_partial(struct remote *remote)
 static int fetch_one(struct remote *remote, int argc, const char **argv, int prune_tags_ok)
 {
 	static const char **refs = NULL;
-	struct refspec *refspec;
+	struct refspec_item *refspec;
 	int ref_nr = 0;
 	int j = 0;
 	int exit_code;
diff --git a/builtin/pull.c b/builtin/pull.c
index 6247c956d..5a79deae5 100644
--- a/builtin/pull.c
+++ b/builtin/pull.c
@@ -676,7 +676,7 @@ static const char *get_upstream_branch(const char *remote)
  */
 static const char *get_tracking_branch(const char *remote, const char *refspec)
 {
-	struct refspec *spec;
+	struct refspec_item *spec;
 	const char *spec_src;
 	const char *merge_branch;
 
diff --git a/builtin/push.c b/builtin/push.c
index fa65999b2..00d81fb1d 100644
--- a/builtin/push.c
+++ b/builtin/push.c
@@ -80,8 +80,8 @@ static const char *map_refspec(const char *ref,
 		return ref;
 
 	if (remote->push) {
-		struct refspec query;
-		memset(&query, 0, sizeof(struct refspec));
+		struct refspec_item query;
+		memset(&query, 0, sizeof(struct refspec_item));
 		query.src = matched->name;
 		if (!query_refspecs(remote->push, remote->push_refspec_nr, &query) &&
 		    query.dst) {
diff --git a/builtin/remote.c b/builtin/remote.c
index c49513995..d9da82dc8 100644
--- a/builtin/remote.c
+++ b/builtin/remote.c
@@ -442,7 +442,7 @@ static int get_push_ref_states_noquery(struct ref_states *states)
 		info->dest = xstrdup(item->string);
 	}
 	for (i = 0; i < remote->push_refspec_nr; i++) {
-		struct refspec *spec = remote->push + i;
+		struct refspec_item *spec = remote->push + i;
 		if (spec->matching)
 			item = string_list_append(&states->push, _("(matching)"));
 		else if (strlen(spec->src))
@@ -462,7 +462,7 @@ static int get_head_names(const struct ref *remote_refs, struct ref_states *stat
 {
 	struct ref *ref, *matches;
 	struct ref *fetch_map = NULL, **fetch_map_tail = &fetch_map;
-	struct refspec refspec;
+	struct refspec_item refspec;
 
 	refspec.force = 0;
 	refspec.pattern = 1;
@@ -515,7 +515,7 @@ static int add_branch_for_removal(const char *refname,
 	const struct object_id *oid, int flags, void *cb_data)
 {
 	struct branches_for_remote *branches = cb_data;
-	struct refspec refspec;
+	struct refspec_item refspec;
 	struct known_remote *kr;
 
 	memset(&refspec, 0, sizeof(refspec));
@@ -834,7 +834,7 @@ static int append_ref_to_tracked_list(const char *refname,
 	const struct object_id *oid, int flags, void *cb_data)
 {
 	struct ref_states *states = cb_data;
-	struct refspec refspec;
+	struct refspec_item refspec;
 
 	if (flags & REF_ISSYMREF)
 		return 0;
diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
index 6ab032acb..c0c4db007 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -1746,11 +1746,11 @@ static int push_check(int argc, const char **argv, const char *prefix)
 	if (argc > 2) {
 		int i, refspec_nr = argc - 2;
 		struct ref *local_refs = get_local_heads();
-		struct refspec *refspec = parse_push_refspec(refspec_nr,
+		struct refspec_item *refspec = parse_push_refspec(refspec_nr,
 							     argv + 2);
 
 		for (i = 0; i < refspec_nr; i++) {
-			struct refspec *rs = refspec + i;
+			struct refspec_item *rs = refspec + i;
 
 			if (rs->pattern || rs->matching)
 				continue;
diff --git a/checkout.c b/checkout.c
index 193ba8567..bdefc888b 100644
--- a/checkout.c
+++ b/checkout.c
@@ -13,8 +13,8 @@ struct tracking_name_data {
 static int check_tracking_name(struct remote *remote, void *cb_data)
 {
 	struct tracking_name_data *cb = cb_data;
-	struct refspec query;
-	memset(&query, 0, sizeof(struct refspec));
+	struct refspec_item query;
+	memset(&query, 0, sizeof(struct refspec_item));
 	query.src = cb->src_ref;
 	if (remote_find_tracking(remote, &query) ||
 	    get_oid(query.dst, cb->dst_oid)) {
diff --git a/refspec.c b/refspec.c
index 3cfcbd37d..cef513ad8 100644
--- a/refspec.c
+++ b/refspec.c
@@ -2,7 +2,7 @@
 #include "refs.h"
 #include "refspec.h"
 
-static struct refspec s_tag_refspec = {
+static struct refspec_item s_tag_refspec = {
 	0,
 	1,
 	0,
@@ -12,13 +12,13 @@ static struct refspec s_tag_refspec = {
 };
 
 /* See TAG_REFSPEC for the string version */
-const struct refspec *tag_refspec = &s_tag_refspec;
+const struct refspec_item *tag_refspec = &s_tag_refspec;
 
 /*
  * Parses 'refspec' and populates 'rs'.  returns 1 if successful and 0 if the
  * refspec is invalid.
  */
-static int parse_refspec(struct refspec *rs, const char *refspec, int fetch)
+static int parse_refspec(struct refspec_item *rs, const char *refspec, int fetch)
 {
 	size_t llen;
 	int is_glob;
@@ -121,10 +121,10 @@ static int parse_refspec(struct refspec *rs, const char *refspec, int fetch)
 	return 1;
 }
 
-static struct refspec *parse_refspec_internal(int nr_refspec, const char **refspec, int fetch, int verify)
+static struct refspec_item *parse_refspec_internal(int nr_refspec, const char **refspec, int fetch, int verify)
 {
 	int i;
-	struct refspec *rs = xcalloc(nr_refspec, sizeof(*rs));
+	struct refspec_item *rs = xcalloc(nr_refspec, sizeof(*rs));
 
 	for (i = 0; i < nr_refspec; i++) {
 		if (!parse_refspec(&rs[i], refspec[i], fetch))
@@ -148,24 +148,24 @@ static struct refspec *parse_refspec_internal(int nr_refspec, const char **refsp
 
 int valid_fetch_refspec(const char *fetch_refspec_str)
 {
-	struct refspec *refspec;
+	struct refspec_item *refspec;
 
 	refspec = parse_refspec_internal(1, &fetch_refspec_str, 1, 1);
 	free_refspec(1, refspec);
 	return !!refspec;
 }
 
-struct refspec *parse_fetch_refspec(int nr_refspec, const char **refspec)
+struct refspec_item *parse_fetch_refspec(int nr_refspec, const char **refspec)
 {
 	return parse_refspec_internal(nr_refspec, refspec, 1, 0);
 }
 
-struct refspec *parse_push_refspec(int nr_refspec, const char **refspec)
+struct refspec_item *parse_push_refspec(int nr_refspec, const char **refspec)
 {
 	return parse_refspec_internal(nr_refspec, refspec, 0, 0);
 }
 
-void free_refspec(int nr_refspec, struct refspec *refspec)
+void free_refspec(int nr_refspec, struct refspec_item *refspec)
 {
 	int i;
 
@@ -178,4 +178,3 @@ void free_refspec(int nr_refspec, struct refspec *refspec)
 	}
 	free(refspec);
 }
-
diff --git a/refspec.h b/refspec.h
index b1db91918..173cea882 100644
--- a/refspec.h
+++ b/refspec.h
@@ -2,9 +2,9 @@
 #define REFSPEC_H
 
 #define TAG_REFSPEC "refs/tags/*:refs/tags/*"
-const struct refspec *tag_refspec;
+const struct refspec_item *tag_refspec;
 
-struct refspec {
+struct refspec_item {
 	unsigned force : 1;
 	unsigned pattern : 1;
 	unsigned matching : 1;
@@ -15,9 +15,9 @@ struct refspec {
 };
 
 int valid_fetch_refspec(const char *refspec);
-struct refspec *parse_fetch_refspec(int nr_refspec, const char **refspec);
-struct refspec *parse_push_refspec(int nr_refspec, const char **refspec);
+struct refspec_item *parse_fetch_refspec(int nr_refspec, const char **refspec);
+struct refspec_item *parse_push_refspec(int nr_refspec, const char **refspec);
 
-void free_refspec(int nr_refspec, struct refspec *refspec);
+void free_refspec(int nr_refspec, struct refspec_item *refspec);
 
 #endif /* REFSPEC_H */
diff --git a/remote.c b/remote.c
index 4d67c061a..89820c476 100644
--- a/remote.c
+++ b/remote.c
@@ -97,7 +97,7 @@ void add_prune_tags_to_fetch_refspec(struct remote *remote)
 {
 	int nr = remote->fetch_refspec_nr;
 	int bufsize = nr  + 1;
-	int size = sizeof(struct refspec);
+	int size = sizeof(struct refspec_item);
 
 	remote->fetch = xrealloc(remote->fetch, size  * bufsize);
 	memcpy(&remote->fetch[nr], tag_refspec, size);
@@ -724,7 +724,7 @@ static int match_name_with_pattern(const char *key, const char *name,
 	return ret;
 }
 
-static void query_refspecs_multiple(struct refspec *refs, int ref_count, struct refspec *query, struct string_list *results)
+static void query_refspecs_multiple(struct refspec_item *refs, int ref_count, struct refspec_item *query, struct string_list *results)
 {
 	int i;
 	int find_src = !query->src;
@@ -733,7 +733,7 @@ static void query_refspecs_multiple(struct refspec *refs, int ref_count, struct
 		error("query_refspecs_multiple: need either src or dst");
 
 	for (i = 0; i < ref_count; i++) {
-		struct refspec *refspec = &refs[i];
+		struct refspec_item *refspec = &refs[i];
 		const char *key = find_src ? refspec->dst : refspec->src;
 		const char *value = find_src ? refspec->src : refspec->dst;
 		const char *needle = find_src ? query->dst : query->src;
@@ -750,7 +750,7 @@ static void query_refspecs_multiple(struct refspec *refs, int ref_count, struct
 	}
 }
 
-int query_refspecs(struct refspec *refs, int ref_count, struct refspec *query)
+int query_refspecs(struct refspec_item *refs, int ref_count, struct refspec_item *query)
 {
 	int i;
 	int find_src = !query->src;
@@ -761,7 +761,7 @@ int query_refspecs(struct refspec *refs, int ref_count, struct refspec *query)
 		return error("query_refspecs: need either src or dst");
 
 	for (i = 0; i < ref_count; i++) {
-		struct refspec *refspec = &refs[i];
+		struct refspec_item *refspec = &refs[i];
 		const char *key = find_src ? refspec->dst : refspec->src;
 		const char *value = find_src ? refspec->src : refspec->dst;
 
@@ -781,12 +781,12 @@ int query_refspecs(struct refspec *refs, int ref_count, struct refspec *query)
 	return -1;
 }
 
-char *apply_refspecs(struct refspec *refspecs, int nr_refspec,
+char *apply_refspecs(struct refspec_item *refspecs, int nr_refspec,
 		     const char *name)
 {
-	struct refspec query;
+	struct refspec_item query;
 
-	memset(&query, 0, sizeof(struct refspec));
+	memset(&query, 0, sizeof(struct refspec_item));
 	query.src = (char *)name;
 
 	if (query_refspecs(refspecs, nr_refspec, &query))
@@ -795,7 +795,7 @@ char *apply_refspecs(struct refspec *refspecs, int nr_refspec,
 	return query.dst;
 }
 
-int remote_find_tracking(struct remote *remote, struct refspec *refspec)
+int remote_find_tracking(struct remote *remote, struct refspec_item *refspec)
 {
 	return query_refspecs(remote->fetch, remote->fetch_refspec_nr, refspec);
 }
@@ -1004,7 +1004,7 @@ static char *guess_ref(const char *name, struct ref *peer)
 }
 
 static int match_explicit_lhs(struct ref *src,
-			      struct refspec *rs,
+			      struct refspec_item *rs,
 			      struct ref **match,
 			      int *allocated_match)
 {
@@ -1030,7 +1030,7 @@ static int match_explicit_lhs(struct ref *src,
 
 static int match_explicit(struct ref *src, struct ref *dst,
 			  struct ref ***dst_tail,
-			  struct refspec *rs)
+			  struct refspec_item *rs)
 {
 	struct ref *matched_src, *matched_dst;
 	int allocated_src;
@@ -1099,7 +1099,7 @@ static int match_explicit(struct ref *src, struct ref *dst,
 }
 
 static int match_explicit_refs(struct ref *src, struct ref *dst,
-			       struct ref ***dst_tail, struct refspec *rs,
+			       struct ref ***dst_tail, struct refspec_item *rs,
 			       int rs_nr)
 {
 	int i, errs;
@@ -1108,10 +1108,10 @@ static int match_explicit_refs(struct ref *src, struct ref *dst,
 	return errs;
 }
 
-static char *get_ref_match(const struct refspec *rs, int rs_nr, const struct ref *ref,
-		int send_mirror, int direction, const struct refspec **ret_pat)
+static char *get_ref_match(const struct refspec_item *rs, int rs_nr, const struct ref *ref,
+		int send_mirror, int direction, const struct refspec_item **ret_pat)
 {
-	const struct refspec *pat;
+	const struct refspec_item *pat;
 	char *name;
 	int i;
 	int matching_refs = -1;
@@ -1282,12 +1282,12 @@ static void prepare_ref_index(struct string_list *ref_index, struct ref *ref)
  */
 int check_push_refs(struct ref *src, int nr_refspec, const char **refspec_names)
 {
-	struct refspec *refspec = parse_push_refspec(nr_refspec, refspec_names);
+	struct refspec_item *refspec = parse_push_refspec(nr_refspec, refspec_names);
 	int ret = 0;
 	int i;
 
 	for (i = 0; i < nr_refspec; i++) {
-		struct refspec *rs = refspec + i;
+		struct refspec_item *rs = refspec + i;
 
 		if (rs->pattern || rs->matching)
 			continue;
@@ -1310,7 +1310,7 @@ int check_push_refs(struct ref *src, int nr_refspec, const char **refspec_names)
 int match_push_refs(struct ref *src, struct ref **dst,
 		    int nr_refspec, const char **refspec, int flags)
 {
-	struct refspec *rs;
+	struct refspec_item *rs;
 	int send_all = flags & MATCH_REFS_ALL;
 	int send_mirror = flags & MATCH_REFS_MIRROR;
 	int send_prune = flags & MATCH_REFS_PRUNE;
@@ -1330,7 +1330,7 @@ int match_push_refs(struct ref *src, struct ref **dst,
 	for (ref = src; ref; ref = ref->next) {
 		struct string_list_item *dst_item;
 		struct ref *dst_peer;
-		const struct refspec *pat = NULL;
+		const struct refspec_item *pat = NULL;
 		char *dst_name;
 
 		dst_name = get_ref_match(rs, nr_refspec, ref, send_mirror, FROM_SRC, &pat);
@@ -1686,7 +1686,7 @@ static int ignore_symref_update(const char *refname)
  * local symbolic ref.
  */
 static struct ref *get_expanded_map(const struct ref *remote_refs,
-				    const struct refspec *refspec)
+				    const struct refspec_item *refspec)
 {
 	const struct ref *ref;
 	struct ref *ret = NULL;
@@ -1751,7 +1751,7 @@ static struct ref *get_local_ref(const char *name)
 }
 
 int get_fetch_map(const struct ref *remote_refs,
-		  const struct refspec *refspec,
+		  const struct refspec_item *refspec,
 		  struct ref ***tail,
 		  int missing_ok)
 {
@@ -2089,7 +2089,7 @@ struct ref *guess_remote_head(const struct ref *head,
 struct stale_heads_info {
 	struct string_list *ref_names;
 	struct ref **stale_refs_tail;
-	struct refspec *refs;
+	struct refspec_item *refs;
 	int ref_count;
 };
 
@@ -2098,9 +2098,9 @@ static int get_stale_heads_cb(const char *refname, const struct object_id *oid,
 {
 	struct stale_heads_info *info = cb_data;
 	struct string_list matches = STRING_LIST_INIT_DUP;
-	struct refspec query;
+	struct refspec_item query;
 	int i, stale = 1;
-	memset(&query, 0, sizeof(struct refspec));
+	memset(&query, 0, sizeof(struct refspec_item));
 	query.dst = (char *)refname;
 
 	query_refspecs_multiple(info->refs, info->ref_count, &query, &matches);
@@ -2131,7 +2131,7 @@ static int get_stale_heads_cb(const char *refname, const struct object_id *oid,
 	return 0;
 }
 
-struct ref *get_stale_heads(struct refspec *refs, int ref_count, struct ref *fetch_map)
+struct ref *get_stale_heads(struct refspec_item *refs, int ref_count, struct ref *fetch_map)
 {
 	struct ref *ref, *stale_refs = NULL;
 	struct string_list ref_names = STRING_LIST_INIT_NODUP;
diff --git a/remote.h b/remote.h
index 386ced901..3657bd43d 100644
--- a/remote.h
+++ b/remote.h
@@ -28,12 +28,12 @@ struct remote {
 	int pushurl_alloc;
 
 	const char **push_refspec;
-	struct refspec *push;
+	struct refspec_item *push;
 	int push_refspec_nr;
 	int push_refspec_alloc;
 
 	const char **fetch_refspec;
-	struct refspec *fetch;
+	struct refspec_item *fetch;
 	int fetch_refspec_nr;
 	int fetch_refspec_alloc;
 
@@ -163,8 +163,8 @@ int ref_newer(const struct object_id *new_oid, const struct object_id *old_oid);
  */
 struct ref *ref_remove_duplicates(struct ref *ref_map);
 
-extern int query_refspecs(struct refspec *specs, int nr, struct refspec *query);
-char *apply_refspecs(struct refspec *refspecs, int nr_refspec,
+extern int query_refspecs(struct refspec_item *specs, int nr, struct refspec_item *query);
+char *apply_refspecs(struct refspec_item *refspecs, int nr_refspec,
 		     const char *name);
 
 int check_push_refs(struct ref *src, int nr_refspec, const char **refspec);
@@ -185,7 +185,7 @@ void set_ref_status_for_push(struct ref *remote_refs, int send_mirror,
  * missing_ok is usually false, but when we are adding branch.$name.merge
  * it is Ok if the branch is not at the remote anymore.
  */
-int get_fetch_map(const struct ref *remote_refs, const struct refspec *refspec,
+int get_fetch_map(const struct ref *remote_refs, const struct refspec_item *refspec,
 		  struct ref ***tail, int missing_ok);
 
 struct ref *get_remote_ref(const struct ref *remote_refs, const char *name);
@@ -193,7 +193,7 @@ struct ref *get_remote_ref(const struct ref *remote_refs, const char *name);
 /*
  * For the given remote, reads the refspec's src and sets the other fields.
  */
-int remote_find_tracking(struct remote *remote, struct refspec *refspec);
+int remote_find_tracking(struct remote *remote, struct refspec_item *refspec);
 
 struct branch {
 	const char *name;
@@ -203,7 +203,7 @@ struct branch {
 	const char *pushremote_name;
 
 	const char **merge_name;
-	struct refspec **merge;
+	struct refspec_item **merge;
 	int merge_nr;
 	int merge_alloc;
 
@@ -272,7 +272,7 @@ struct ref *guess_remote_head(const struct ref *head,
 			      int all);
 
 /* Return refs which no longer exist on remote */
-struct ref *get_stale_heads(struct refspec *refs, int ref_count, struct ref *fetch_map);
+struct ref *get_stale_heads(struct refspec_item *refs, int ref_count, struct ref *fetch_map);
 
 /*
  * Compare-and-swap
diff --git a/transport-helper.c b/transport-helper.c
index b99e1cce9..b156a37e7 100644
--- a/transport-helper.c
+++ b/transport-helper.c
@@ -36,7 +36,7 @@ struct helper_data {
 	char *export_marks;
 	char *import_marks;
 	/* These go from remote name (as in "list") to private name */
-	struct refspec *refspecs;
+	struct refspec_item *refspecs;
 	int refspec_nr;
 	/* Transport options for fetch-pack/send-pack (should one of
 	 * those be invoked).
diff --git a/transport.c b/transport.c
index 2cf63d18b..3ad4d37dc 100644
--- a/transport.c
+++ b/transport.c
@@ -390,7 +390,7 @@ int transport_refs_pushed(struct ref *ref)
 
 void transport_update_tracking_ref(struct remote *remote, struct ref *ref, int verbose)
 {
-	struct refspec rs;
+	struct refspec_item rs;
 
 	if (ref->status != REF_STATUS_OK && ref->status != REF_STATUS_UPTODATE)
 		return;
@@ -1111,7 +1111,7 @@ int transport_push(struct transport *transport,
 		int porcelain = flags & TRANSPORT_PUSH_PORCELAIN;
 		int pretend = flags & TRANSPORT_PUSH_DRY_RUN;
 		int push_ret, ret, err;
-		struct refspec *tmp_rs;
+		struct refspec_item *tmp_rs;
 		struct argv_array ref_prefixes = ARGV_ARRAY_INIT;
 		int i;
 
-- 
2.17.0.441.gb46fe60e1d-goog


^ permalink raw reply related	[flat|nested] 112+ messages in thread

* [PATCH 04/35] refspec: introduce struct refspec
  2018-05-14 21:55 [PATCH 00/35] refactoring refspecs Brandon Williams
                   ` (2 preceding siblings ...)
  2018-05-14 21:55 ` [PATCH 03/35] refspec: rename struct refspec to struct refspec_item Brandon Williams
@ 2018-05-14 21:55 ` Brandon Williams
  2018-05-15  9:37   ` Junio C Hamano
  2018-05-14 21:55 ` [PATCH 05/35] refspec: convert valid_fetch_refspec to use parse_refspec Brandon Williams
                   ` (34 subsequent siblings)
  38 siblings, 1 reply; 112+ messages in thread
From: Brandon Williams @ 2018-05-14 21:55 UTC (permalink / raw)
  To: git, bmwill; +Cc: Brandon Williams

Introduce 'struct refspec', an abstraction around a collection of
'struct refspec_item's much like how 'struct pathspec' holds a
collection of 'struct pathspec_item's.

A refspec struct also contains an array of the original refspec strings
which will be used to facilitate the migration to using this new
abstraction throughout the code base.

Signed-off-by: Brandon Williams <bmwill@google.com>
---
 refspec.c | 64 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 refspec.h | 25 ++++++++++++++++++++++
 2 files changed, 89 insertions(+)

diff --git a/refspec.c b/refspec.c
index cef513ad8..2b898c922 100644
--- a/refspec.c
+++ b/refspec.c
@@ -178,3 +178,67 @@ void free_refspec(int nr_refspec, struct refspec_item *refspec)
 	}
 	free(refspec);
 }
+
+void refspec_item_init(struct refspec_item *item, const char *refspec, int fetch)
+{
+	memset(item, 0, sizeof(*item));
+
+	if (!parse_refspec(item, refspec, fetch))
+		die("Invalid refspec '%s'", refspec);
+}
+
+void refspec_item_clear(struct refspec_item *item)
+{
+	FREE_AND_NULL(item->src);
+	FREE_AND_NULL(item->dst);
+	item->force = 0;
+	item->pattern = 0;
+	item->matching = 0;
+	item->exact_sha1 = 0;
+}
+
+void refspec_init(struct refspec *rs, int fetch)
+{
+	memset(rs, 0, sizeof(*rs));
+	rs->fetch = fetch;
+}
+
+void refspec_append(struct refspec *rs, const char *refspec)
+{
+	struct refspec_item item;
+
+	refspec_item_init(&item, refspec, rs->fetch);
+
+	ALLOC_GROW(rs->items, rs->nr + 1, rs->alloc);
+	rs->items[rs->nr++] = item;
+
+	ALLOC_GROW(rs->raw, rs->raw_nr + 1, rs->raw_alloc);
+	rs->raw[rs->raw_nr++] = xstrdup(refspec);
+}
+
+void refspec_appendn(struct refspec *rs, const char **refspecs, int nr)
+{
+	int i;
+	for (i = 0; i < nr; i++)
+		refspec_append(rs, refspecs[i]);
+}
+
+void refspec_clear(struct refspec *rs)
+{
+	int i;
+
+	for (i = 0; i < rs->nr; i++)
+		refspec_item_clear(&rs->items[i]);
+
+	FREE_AND_NULL(rs->items);
+	rs->alloc = 0;
+	rs->nr = 0;
+
+	for (i = 0; i < rs->raw_nr; i++)
+		free((char *)rs->raw[i]);
+	FREE_AND_NULL(rs->raw);
+	rs->raw_alloc = 0;
+	rs->raw_nr = 0;
+
+	rs->fetch = 0;
+}
diff --git a/refspec.h b/refspec.h
index 173cea882..f6fb251f3 100644
--- a/refspec.h
+++ b/refspec.h
@@ -20,4 +20,29 @@ struct refspec_item *parse_push_refspec(int nr_refspec, const char **refspec);
 
 void free_refspec(int nr_refspec, struct refspec_item *refspec);
 
+#define REFSPEC_FETCH 1
+#define REFSPEC_PUSH 0
+
+#define REFSPEC_INIT_FETCH { .fetch = REFSPEC_FETCH }
+#define REFSPEC_INIT_PUSH { .fetch = REFSPEC_PUSH }
+
+struct refspec {
+	struct refspec_item *items;
+	int alloc;
+	int nr;
+
+	const char **raw;
+	int raw_alloc;
+	int raw_nr;
+
+	int fetch;
+};
+
+void refspec_item_init(struct refspec_item *item, const char *refspec, int fetch);
+void refspec_item_clear(struct refspec_item *item);
+void refspec_init(struct refspec *rs, int fetch);
+void refspec_append(struct refspec *rs, const char *refspec);
+void refspec_appendn(struct refspec *rs, const char **refspecs, int nr);
+void refspec_clear(struct refspec *rs);
+
 #endif /* REFSPEC_H */
-- 
2.17.0.441.gb46fe60e1d-goog


^ permalink raw reply related	[flat|nested] 112+ messages in thread

* [PATCH 05/35] refspec: convert valid_fetch_refspec to use parse_refspec
  2018-05-14 21:55 [PATCH 00/35] refactoring refspecs Brandon Williams
                   ` (3 preceding siblings ...)
  2018-05-14 21:55 ` [PATCH 04/35] refspec: introduce struct refspec Brandon Williams
@ 2018-05-14 21:55 ` Brandon Williams
  2018-05-15  9:41   ` Junio C Hamano
  2018-05-14 21:55 ` [PATCH 06/35] submodule--helper: convert push_check to use struct refspec Brandon Williams
                   ` (33 subsequent siblings)
  38 siblings, 1 reply; 112+ messages in thread
From: Brandon Williams @ 2018-05-14 21:55 UTC (permalink / raw)
  To: git, bmwill; +Cc: Brandon Williams

Convert 'valid_fetch_refspec()' to use the new 'parse_refspec()'
function to only parse a single refspec an eliminate an allocation.

Signed-off-by: Brandon Williams <bmwill@google.com>
---
 refspec.c | 17 ++++++++---------
 refspec.h |  3 ++-
 2 files changed, 10 insertions(+), 10 deletions(-)

diff --git a/refspec.c b/refspec.c
index 2b898c922..98c99cd84 100644
--- a/refspec.c
+++ b/refspec.c
@@ -146,15 +146,6 @@ static struct refspec_item *parse_refspec_internal(int nr_refspec, const char **
 	die("Invalid refspec '%s'", refspec[i]);
 }
 
-int valid_fetch_refspec(const char *fetch_refspec_str)
-{
-	struct refspec_item *refspec;
-
-	refspec = parse_refspec_internal(1, &fetch_refspec_str, 1, 1);
-	free_refspec(1, refspec);
-	return !!refspec;
-}
-
 struct refspec_item *parse_fetch_refspec(int nr_refspec, const char **refspec)
 {
 	return parse_refspec_internal(nr_refspec, refspec, 1, 0);
@@ -242,3 +233,11 @@ void refspec_clear(struct refspec *rs)
 
 	rs->fetch = 0;
 }
+
+int valid_fetch_refspec(const char *fetch_refspec_str)
+{
+	struct refspec_item refspec;
+	int ret = parse_refspec(&refspec, fetch_refspec_str, REFSPEC_FETCH);
+	refspec_item_clear(&refspec);
+	return ret;
+}
diff --git a/refspec.h b/refspec.h
index f6fb251f3..b009440c0 100644
--- a/refspec.h
+++ b/refspec.h
@@ -14,7 +14,6 @@ struct refspec_item {
 	char *dst;
 };
 
-int valid_fetch_refspec(const char *refspec);
 struct refspec_item *parse_fetch_refspec(int nr_refspec, const char **refspec);
 struct refspec_item *parse_push_refspec(int nr_refspec, const char **refspec);
 
@@ -45,4 +44,6 @@ void refspec_append(struct refspec *rs, const char *refspec);
 void refspec_appendn(struct refspec *rs, const char **refspecs, int nr);
 void refspec_clear(struct refspec *rs);
 
+int valid_fetch_refspec(const char *refspec);
+
 #endif /* REFSPEC_H */
-- 
2.17.0.441.gb46fe60e1d-goog


^ permalink raw reply related	[flat|nested] 112+ messages in thread

* [PATCH 06/35] submodule--helper: convert push_check to use struct refspec
  2018-05-14 21:55 [PATCH 00/35] refactoring refspecs Brandon Williams
                   ` (4 preceding siblings ...)
  2018-05-14 21:55 ` [PATCH 05/35] refspec: convert valid_fetch_refspec to use parse_refspec Brandon Williams
@ 2018-05-14 21:55 ` Brandon Williams
  2018-05-14 21:55 ` [PATCH 07/35] pull: convert get_tracking_branch to use refspec_item_init Brandon Williams
                   ` (32 subsequent siblings)
  38 siblings, 0 replies; 112+ messages in thread
From: Brandon Williams @ 2018-05-14 21:55 UTC (permalink / raw)
  To: git, bmwill; +Cc: Brandon Williams

Convert 'push_check()' to use 'struct refspec'.

Signed-off-by: Brandon Williams <bmwill@google.com>
---
 builtin/submodule--helper.c | 13 +++++++------
 1 file changed, 7 insertions(+), 6 deletions(-)

diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
index c0c4db007..88a149a2c 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -1744,13 +1744,14 @@ static int push_check(int argc, const char **argv, const char *prefix)
 
 	/* Check the refspec */
 	if (argc > 2) {
-		int i, refspec_nr = argc - 2;
+		int i;
 		struct ref *local_refs = get_local_heads();
-		struct refspec_item *refspec = parse_push_refspec(refspec_nr,
-							     argv + 2);
+		struct refspec refspec = REFSPEC_INIT_PUSH;
 
-		for (i = 0; i < refspec_nr; i++) {
-			struct refspec_item *rs = refspec + i;
+		refspec_appendn(&refspec, argv + 2, argc - 2);
+
+		for (i = 0; i < refspec.nr; i++) {
+			const struct refspec_item *rs = &refspec.items[i];
 
 			if (rs->pattern || rs->matching)
 				continue;
@@ -1777,7 +1778,7 @@ static int push_check(int argc, const char **argv, const char *prefix)
 				    rs->src);
 			}
 		}
-		free_refspec(refspec_nr, refspec);
+		refspec_clear(&refspec);
 	}
 	free(head);
 
-- 
2.17.0.441.gb46fe60e1d-goog


^ permalink raw reply related	[flat|nested] 112+ messages in thread

* [PATCH 07/35] pull: convert get_tracking_branch to use refspec_item_init
  2018-05-14 21:55 [PATCH 00/35] refactoring refspecs Brandon Williams
                   ` (5 preceding siblings ...)
  2018-05-14 21:55 ` [PATCH 06/35] submodule--helper: convert push_check to use struct refspec Brandon Williams
@ 2018-05-14 21:55 ` Brandon Williams
  2018-05-14 21:55 ` [PATCH 08/35] transport: convert transport_push to use struct refspec Brandon Williams
                   ` (31 subsequent siblings)
  38 siblings, 0 replies; 112+ messages in thread
From: Brandon Williams @ 2018-05-14 21:55 UTC (permalink / raw)
  To: git, bmwill; +Cc: Brandon Williams

Convert 'get_tracking_branch()' to use 'refspec_item_init()' instead of
the old 'parse_fetch_refspec()' function.

Signed-off-by: Brandon Williams <bmwill@google.com>
---
 builtin/pull.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/builtin/pull.c b/builtin/pull.c
index 5a79deae5..09575fd23 100644
--- a/builtin/pull.c
+++ b/builtin/pull.c
@@ -676,12 +676,12 @@ static const char *get_upstream_branch(const char *remote)
  */
 static const char *get_tracking_branch(const char *remote, const char *refspec)
 {
-	struct refspec_item *spec;
+	struct refspec_item spec;
 	const char *spec_src;
 	const char *merge_branch;
 
-	spec = parse_fetch_refspec(1, &refspec);
-	spec_src = spec->src;
+	refspec_item_init(&spec, refspec, REFSPEC_FETCH);
+	spec_src = spec.src;
 	if (!*spec_src || !strcmp(spec_src, "HEAD"))
 		spec_src = "HEAD";
 	else if (skip_prefix(spec_src, "heads/", &spec_src))
@@ -701,7 +701,7 @@ static const char *get_tracking_branch(const char *remote, const char *refspec)
 	} else
 		merge_branch = NULL;
 
-	free_refspec(1, spec);
+	refspec_item_clear(&spec);
 	return merge_branch;
 }
 
-- 
2.17.0.441.gb46fe60e1d-goog


^ permalink raw reply related	[flat|nested] 112+ messages in thread

* [PATCH 08/35] transport: convert transport_push to use struct refspec
  2018-05-14 21:55 [PATCH 00/35] refactoring refspecs Brandon Williams
                   ` (6 preceding siblings ...)
  2018-05-14 21:55 ` [PATCH 07/35] pull: convert get_tracking_branch to use refspec_item_init Brandon Williams
@ 2018-05-14 21:55 ` Brandon Williams
  2018-05-14 21:56 ` [PATCH 09/35] remote: convert check_push_refs " Brandon Williams
                   ` (30 subsequent siblings)
  38 siblings, 0 replies; 112+ messages in thread
From: Brandon Williams @ 2018-05-14 21:55 UTC (permalink / raw)
  To: git, bmwill; +Cc: Brandon Williams

Convert the logic in 'transport_push()' which calculates a list of
ref-prefixes to use 'struct refspec'.

Signed-off-by: Brandon Williams <bmwill@google.com>
---
 transport.c | 17 +++++++++--------
 1 file changed, 9 insertions(+), 8 deletions(-)

diff --git a/transport.c b/transport.c
index 3ad4d37dc..181db4d4d 100644
--- a/transport.c
+++ b/transport.c
@@ -1111,21 +1111,22 @@ int transport_push(struct transport *transport,
 		int porcelain = flags & TRANSPORT_PUSH_PORCELAIN;
 		int pretend = flags & TRANSPORT_PUSH_DRY_RUN;
 		int push_ret, ret, err;
-		struct refspec_item *tmp_rs;
+		struct refspec tmp_rs = REFSPEC_INIT_PUSH;
 		struct argv_array ref_prefixes = ARGV_ARRAY_INIT;
 		int i;
 
 		if (check_push_refs(local_refs, refspec_nr, refspec) < 0)
 			return -1;
 
-		tmp_rs = parse_push_refspec(refspec_nr, refspec);
-		for (i = 0; i < refspec_nr; i++) {
+		refspec_appendn(&tmp_rs, refspec, refspec_nr);
+		for (i = 0; i < tmp_rs.nr; i++) {
+			const struct refspec_item *item = &tmp_rs.items[i];
 			const char *prefix = NULL;
 
-			if (tmp_rs[i].dst)
-				prefix = tmp_rs[i].dst;
-			else if (tmp_rs[i].src && !tmp_rs[i].exact_sha1)
-				prefix = tmp_rs[i].src;
+			if (item->dst)
+				prefix = item->dst;
+			else if (item->src && !item->exact_sha1)
+				prefix = item->src;
 
 			if (prefix) {
 				const char *glob = strchr(prefix, '*');
@@ -1142,7 +1143,7 @@ int transport_push(struct transport *transport,
 							       &ref_prefixes);
 
 		argv_array_clear(&ref_prefixes);
-		free_refspec(refspec_nr, tmp_rs);
+		refspec_clear(&tmp_rs);
 
 		if (flags & TRANSPORT_PUSH_ALL)
 			match_flags |= MATCH_REFS_ALL;
-- 
2.17.0.441.gb46fe60e1d-goog


^ permalink raw reply related	[flat|nested] 112+ messages in thread

* [PATCH 09/35] remote: convert check_push_refs to use struct refspec
  2018-05-14 21:55 [PATCH 00/35] refactoring refspecs Brandon Williams
                   ` (7 preceding siblings ...)
  2018-05-14 21:55 ` [PATCH 08/35] transport: convert transport_push to use struct refspec Brandon Williams
@ 2018-05-14 21:56 ` Brandon Williams
  2018-05-14 21:56 ` [PATCH 10/35] remote: convert match_push_refs " Brandon Williams
                   ` (29 subsequent siblings)
  38 siblings, 0 replies; 112+ messages in thread
From: Brandon Williams @ 2018-05-14 21:56 UTC (permalink / raw)
  To: git, bmwill; +Cc: Brandon Williams

Convert 'check_push_refs()' to use 'struct refspec'.

Signed-off-by: Brandon Williams <bmwill@google.com>
---
 remote.c | 10 ++++++----
 1 file changed, 6 insertions(+), 4 deletions(-)

diff --git a/remote.c b/remote.c
index 89820c476..191855118 100644
--- a/remote.c
+++ b/remote.c
@@ -1282,12 +1282,14 @@ static void prepare_ref_index(struct string_list *ref_index, struct ref *ref)
  */
 int check_push_refs(struct ref *src, int nr_refspec, const char **refspec_names)
 {
-	struct refspec_item *refspec = parse_push_refspec(nr_refspec, refspec_names);
+	struct refspec refspec = REFSPEC_INIT_PUSH;
 	int ret = 0;
 	int i;
 
-	for (i = 0; i < nr_refspec; i++) {
-		struct refspec_item *rs = refspec + i;
+	refspec_appendn(&refspec, refspec_names, nr_refspec);
+
+	for (i = 0; i < refspec.nr; i++) {
+		struct refspec_item *rs = &refspec.items[i];
 
 		if (rs->pattern || rs->matching)
 			continue;
@@ -1295,7 +1297,7 @@ int check_push_refs(struct ref *src, int nr_refspec, const char **refspec_names)
 		ret |= match_explicit_lhs(src, rs, NULL, NULL);
 	}
 
-	free_refspec(nr_refspec, refspec);
+	refspec_clear(&refspec);
 	return ret;
 }
 
-- 
2.17.0.441.gb46fe60e1d-goog


^ permalink raw reply related	[flat|nested] 112+ messages in thread

* [PATCH 10/35] remote: convert match_push_refs to use struct refspec
  2018-05-14 21:55 [PATCH 00/35] refactoring refspecs Brandon Williams
                   ` (8 preceding siblings ...)
  2018-05-14 21:56 ` [PATCH 09/35] remote: convert check_push_refs " Brandon Williams
@ 2018-05-14 21:56 ` Brandon Williams
  2018-05-14 21:56 ` [PATCH 11/35] clone: convert cmd_clone to use refspec_item_init Brandon Williams
                   ` (28 subsequent siblings)
  38 siblings, 0 replies; 112+ messages in thread
From: Brandon Williams @ 2018-05-14 21:56 UTC (permalink / raw)
  To: git, bmwill; +Cc: Brandon Williams

Convert 'match_push_refs()' to use struct refspec.

Signed-off-by: Brandon Williams <bmwill@google.com>
---
 remote.c | 13 ++++++++-----
 1 file changed, 8 insertions(+), 5 deletions(-)

diff --git a/remote.c b/remote.c
index 191855118..bce6e7ce4 100644
--- a/remote.c
+++ b/remote.c
@@ -1312,7 +1312,7 @@ int check_push_refs(struct ref *src, int nr_refspec, const char **refspec_names)
 int match_push_refs(struct ref *src, struct ref **dst,
 		    int nr_refspec, const char **refspec, int flags)
 {
-	struct refspec_item *rs;
+	struct refspec rs = REFSPEC_INIT_PUSH;
 	int send_all = flags & MATCH_REFS_ALL;
 	int send_mirror = flags & MATCH_REFS_MIRROR;
 	int send_prune = flags & MATCH_REFS_PRUNE;
@@ -1325,8 +1325,8 @@ int match_push_refs(struct ref *src, struct ref **dst,
 		nr_refspec = 1;
 		refspec = default_refspec;
 	}
-	rs = parse_push_refspec(nr_refspec, (const char **) refspec);
-	errs = match_explicit_refs(src, *dst, &dst_tail, rs, nr_refspec);
+	refspec_appendn(&rs, refspec, nr_refspec);
+	errs = match_explicit_refs(src, *dst, &dst_tail, rs.items, rs.nr);
 
 	/* pick the remainder */
 	for (ref = src; ref; ref = ref->next) {
@@ -1335,7 +1335,7 @@ int match_push_refs(struct ref *src, struct ref **dst,
 		const struct refspec_item *pat = NULL;
 		char *dst_name;
 
-		dst_name = get_ref_match(rs, nr_refspec, ref, send_mirror, FROM_SRC, &pat);
+		dst_name = get_ref_match(rs.items, rs.nr, ref, send_mirror, FROM_SRC, &pat);
 		if (!dst_name)
 			continue;
 
@@ -1384,7 +1384,7 @@ int match_push_refs(struct ref *src, struct ref **dst,
 				/* We're already sending something to this ref. */
 				continue;
 
-			src_name = get_ref_match(rs, nr_refspec, ref, send_mirror, FROM_DST, NULL);
+			src_name = get_ref_match(rs.items, rs.nr, ref, send_mirror, FROM_DST, NULL);
 			if (src_name) {
 				if (!src_ref_index.nr)
 					prepare_ref_index(&src_ref_index, src);
@@ -1396,6 +1396,9 @@ int match_push_refs(struct ref *src, struct ref **dst,
 		}
 		string_list_clear(&src_ref_index, 0);
 	}
+
+	refspec_clear(&rs);
+
 	if (errs)
 		return -1;
 	return 0;
-- 
2.17.0.441.gb46fe60e1d-goog


^ permalink raw reply related	[flat|nested] 112+ messages in thread

* [PATCH 11/35] clone: convert cmd_clone to use refspec_item_init
  2018-05-14 21:55 [PATCH 00/35] refactoring refspecs Brandon Williams
                   ` (9 preceding siblings ...)
  2018-05-14 21:56 ` [PATCH 10/35] remote: convert match_push_refs " Brandon Williams
@ 2018-05-14 21:56 ` Brandon Williams
  2018-05-14 21:56 ` [PATCH 12/35] fast-export: convert to use struct refspec Brandon Williams
                   ` (27 subsequent siblings)
  38 siblings, 0 replies; 112+ messages in thread
From: Brandon Williams @ 2018-05-14 21:56 UTC (permalink / raw)
  To: git, bmwill; +Cc: Brandon Williams

Convert 'cmd_clone()' to use 'refspec_item_init()' instead of relying on
the old 'parse_fetch_refspec()' to initialize a single refspec item.

Signed-off-by: Brandon Williams <bmwill@google.com>
---
 builtin/clone.c | 10 ++++------
 1 file changed, 4 insertions(+), 6 deletions(-)

diff --git a/builtin/clone.c b/builtin/clone.c
index 854088a3a..8c5f4d8f0 100644
--- a/builtin/clone.c
+++ b/builtin/clone.c
@@ -895,8 +895,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
 	int err = 0, complete_refs_before_fetch = 1;
 	int submodule_progress;
 
-	struct refspec_item *refspec;
-	const char *fetch_pattern;
+	struct refspec_item refspec;
 
 	fetch_if_missing = 0;
 
@@ -1078,8 +1077,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
 	if (option_required_reference.nr || option_optional_reference.nr)
 		setup_reference();
 
-	fetch_pattern = value.buf;
-	refspec = parse_fetch_refspec(1, &fetch_pattern);
+	refspec_item_init(&refspec, value.buf, REFSPEC_FETCH);
 
 	strbuf_reset(&value);
 
@@ -1139,7 +1137,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
 	refs = transport_get_remote_refs(transport, NULL);
 
 	if (refs) {
-		mapped_refs = wanted_peer_refs(refs, refspec);
+		mapped_refs = wanted_peer_refs(refs, &refspec);
 		/*
 		 * transport_get_remote_refs() may return refs with null sha-1
 		 * in mapped_refs (see struct transport->get_refs_list
@@ -1233,6 +1231,6 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
 	strbuf_release(&value);
 	junk_mode = JUNK_LEAVE_ALL;
 
-	free(refspec);
+	refspec_item_clear(&refspec);
 	return err;
 }
-- 
2.17.0.441.gb46fe60e1d-goog


^ permalink raw reply related	[flat|nested] 112+ messages in thread

* [PATCH 12/35] fast-export: convert to use struct refspec
  2018-05-14 21:55 [PATCH 00/35] refactoring refspecs Brandon Williams
                   ` (10 preceding siblings ...)
  2018-05-14 21:56 ` [PATCH 11/35] clone: convert cmd_clone to use refspec_item_init Brandon Williams
@ 2018-05-14 21:56 ` Brandon Williams
  2018-05-14 21:56 ` [PATCH 13/35] remote: convert push refspecs to " Brandon Williams
                   ` (26 subsequent siblings)
  38 siblings, 0 replies; 112+ messages in thread
From: Brandon Williams @ 2018-05-14 21:56 UTC (permalink / raw)
  To: git, bmwill; +Cc: Brandon Williams

Convert fast-export to use 'struct refspec' instead of using a list of
refspec_item's.

Signed-off-by: Brandon Williams <bmwill@google.com>
---
 builtin/fast-export.c | 21 +++++++--------------
 1 file changed, 7 insertions(+), 14 deletions(-)

diff --git a/builtin/fast-export.c b/builtin/fast-export.c
index 6f105dc79..143999738 100644
--- a/builtin/fast-export.c
+++ b/builtin/fast-export.c
@@ -36,8 +36,7 @@ static int use_done_feature;
 static int no_data;
 static int full_tree;
 static struct string_list extra_refs = STRING_LIST_INIT_NODUP;
-static struct refspec_item *refspecs;
-static int refspecs_nr;
+static struct refspec refspecs = REFSPEC_INIT_FETCH;
 static int anonymize;
 
 static int parse_opt_signed_tag_mode(const struct option *opt,
@@ -830,9 +829,9 @@ static void get_tags_and_duplicates(struct rev_cmdline_info *info)
 		if (dwim_ref(e->name, strlen(e->name), &oid, &full_name) != 1)
 			continue;
 
-		if (refspecs) {
+		if (refspecs.nr) {
 			char *private;
-			private = apply_refspecs(refspecs, refspecs_nr, full_name);
+			private = apply_refspecs(refspecs.items, refspecs.nr, full_name);
 			if (private) {
 				free(full_name);
 				full_name = private;
@@ -978,8 +977,8 @@ static void import_marks(char *input_file)
 static void handle_deletes(void)
 {
 	int i;
-	for (i = 0; i < refspecs_nr; i++) {
-		struct refspec_item *refspec = &refspecs[i];
+	for (i = 0; i < refspecs.nr; i++) {
+		struct refspec_item *refspec = &refspecs.items[i];
 		if (*refspec->src)
 			continue;
 
@@ -1040,18 +1039,12 @@ int cmd_fast_export(int argc, const char **argv, const char *prefix)
 		usage_with_options (fast_export_usage, options);
 
 	if (refspecs_list.nr) {
-		const char **refspecs_str;
 		int i;
 
-		ALLOC_ARRAY(refspecs_str, refspecs_list.nr);
 		for (i = 0; i < refspecs_list.nr; i++)
-			refspecs_str[i] = refspecs_list.items[i].string;
-
-		refspecs_nr = refspecs_list.nr;
-		refspecs = parse_fetch_refspec(refspecs_nr, refspecs_str);
+			refspec_append(&refspecs, refspecs_list.items[i].string);
 
 		string_list_clear(&refspecs_list, 1);
-		free(refspecs_str);
 	}
 
 	if (use_done_feature)
@@ -1090,7 +1083,7 @@ int cmd_fast_export(int argc, const char **argv, const char *prefix)
 	if (use_done_feature)
 		printf("done\n");
 
-	free_refspec(refspecs_nr, refspecs);
+	refspec_clear(&refspecs);
 
 	return 0;
 }
-- 
2.17.0.441.gb46fe60e1d-goog


^ permalink raw reply related	[flat|nested] 112+ messages in thread

* [PATCH 13/35] remote: convert push refspecs to struct refspec
  2018-05-14 21:55 [PATCH 00/35] refactoring refspecs Brandon Williams
                   ` (11 preceding siblings ...)
  2018-05-14 21:56 ` [PATCH 12/35] fast-export: convert to use struct refspec Brandon Williams
@ 2018-05-14 21:56 ` Brandon Williams
  2018-05-14 21:56 ` [PATCH 14/35] remote: convert fetch " Brandon Williams
                   ` (25 subsequent siblings)
  38 siblings, 0 replies; 112+ messages in thread
From: Brandon Williams @ 2018-05-14 21:56 UTC (permalink / raw)
  To: git, bmwill; +Cc: Brandon Williams

Convert the set of push refspecs stored in 'struct remote' to use
'struct refspec'.

Signed-off-by: Brandon Williams <bmwill@google.com>
---
 builtin/push.c   | 10 +++++-----
 builtin/remote.c | 14 +++++++-------
 remote.c         | 23 +++++++++--------------
 remote.h         |  6 ++----
 4 files changed, 23 insertions(+), 30 deletions(-)

diff --git a/builtin/push.c b/builtin/push.c
index 00d81fb1d..509dc6677 100644
--- a/builtin/push.c
+++ b/builtin/push.c
@@ -79,11 +79,11 @@ static const char *map_refspec(const char *ref,
 	if (count_refspec_match(ref, local_refs, &matched) != 1)
 		return ref;
 
-	if (remote->push) {
+	if (remote->push.nr) {
 		struct refspec_item query;
 		memset(&query, 0, sizeof(struct refspec_item));
 		query.src = matched->name;
-		if (!query_refspecs(remote->push, remote->push_refspec_nr, &query) &&
+		if (!query_refspecs(remote->push.items, remote->push.nr, &query) &&
 		    query.dst) {
 			struct strbuf buf = STRBUF_INIT;
 			strbuf_addf(&buf, "%s%s:%s",
@@ -436,9 +436,9 @@ static int do_push(const char *repo, int flags,
 	}
 
 	if (!refspec && !(flags & TRANSPORT_PUSH_ALL)) {
-		if (remote->push_refspec_nr) {
-			refspec = remote->push_refspec;
-			refspec_nr = remote->push_refspec_nr;
+		if (remote->push.raw_nr) {
+			refspec = remote->push.raw;
+			refspec_nr = remote->push.raw_nr;
 		} else if (!(flags & TRANSPORT_PUSH_MIRROR))
 			setup_default_push_refspecs(remote);
 	}
diff --git a/builtin/remote.c b/builtin/remote.c
index d9da82dc8..fb84729d6 100644
--- a/builtin/remote.c
+++ b/builtin/remote.c
@@ -388,8 +388,8 @@ static int get_push_ref_states(const struct ref *remote_refs,
 	local_refs = get_local_heads();
 	push_map = copy_ref_list(remote_refs);
 
-	match_push_refs(local_refs, &push_map, remote->push_refspec_nr,
-			remote->push_refspec, MATCH_REFS_NONE);
+	match_push_refs(local_refs, &push_map, remote->push.raw_nr,
+			remote->push.raw, MATCH_REFS_NONE);
 
 	states->push.strdup_strings = 1;
 	for (ref = push_map; ref; ref = ref->next) {
@@ -435,14 +435,14 @@ static int get_push_ref_states_noquery(struct ref_states *states)
 		return 0;
 
 	states->push.strdup_strings = 1;
-	if (!remote->push_refspec_nr) {
+	if (!remote->push.nr) {
 		item = string_list_append(&states->push, _("(matching)"));
 		info = item->util = xcalloc(1, sizeof(struct push_info));
 		info->status = PUSH_STATUS_NOTQUERIED;
 		info->dest = xstrdup(item->string);
 	}
-	for (i = 0; i < remote->push_refspec_nr; i++) {
-		struct refspec_item *spec = remote->push + i;
+	for (i = 0; i < remote->push.nr; i++) {
+		const struct refspec_item *spec = &remote->push.items[i];
 		if (spec->matching)
 			item = string_list_append(&states->push, _("(matching)"));
 		else if (strlen(spec->src))
@@ -586,8 +586,8 @@ static int migrate_file(struct remote *remote)
 		git_config_set_multivar(buf.buf, remote->url[i], "^$", 0);
 	strbuf_reset(&buf);
 	strbuf_addf(&buf, "remote.%s.push", remote->name);
-	for (i = 0; i < remote->push_refspec_nr; i++)
-		git_config_set_multivar(buf.buf, remote->push_refspec[i], "^$", 0);
+	for (i = 0; i < remote->push.raw_nr; i++)
+		git_config_set_multivar(buf.buf, remote->push.raw[i], "^$", 0);
 	strbuf_reset(&buf);
 	strbuf_addf(&buf, "remote.%s.fetch", remote->name);
 	for (i = 0; i < remote->fetch_refspec_nr; i++)
diff --git a/remote.c b/remote.c
index bce6e7ce4..090110c37 100644
--- a/remote.c
+++ b/remote.c
@@ -79,10 +79,7 @@ static const char *alias_url(const char *url, struct rewrites *r)
 
 static void add_push_refspec(struct remote *remote, const char *ref)
 {
-	ALLOC_GROW(remote->push_refspec,
-		   remote->push_refspec_nr + 1,
-		   remote->push_refspec_alloc);
-	remote->push_refspec[remote->push_refspec_nr++] = ref;
+	refspec_append(&remote->push, ref);
 }
 
 static void add_fetch_refspec(struct remote *remote, const char *ref)
@@ -175,9 +172,11 @@ static struct remote *make_remote(const char *name, int len)
 	ret = xcalloc(1, sizeof(struct remote));
 	ret->prune = -1;  /* unspecified */
 	ret->prune_tags = -1;  /* unspecified */
+	ret->name = xstrndup(name, len);
+	refspec_init(&ret->push, REFSPEC_PUSH);
+
 	ALLOC_GROW(remotes, remotes_nr + 1, remotes_alloc);
 	remotes[remotes_nr++] = ret;
-	ret->name = xstrndup(name, len);
 
 	hashmap_entry_init(ret, lookup_entry.hash);
 	replaced = hashmap_put(&remotes_hash, ret);
@@ -542,9 +541,9 @@ const char *remote_ref_for_branch(struct branch *branch, int for_push,
 				pushremote_for_branch(branch, NULL);
 			struct remote *remote = remote_get(remote_name);
 
-			if (remote && remote->push_refspec_nr &&
-			    (dst = apply_refspecs(remote->push,
-						  remote->push_refspec_nr,
+			if (remote && remote->push.nr &&
+			    (dst = apply_refspecs(remote->push.items,
+						  remote->push.nr,
 						  branch->refname))) {
 				if (explicit)
 					*explicit = 1;
@@ -582,7 +581,6 @@ static struct remote *remote_get_1(const char *name,
 	if (!valid_remote(ret))
 		return NULL;
 	ret->fetch = parse_fetch_refspec(ret->fetch_refspec_nr, ret->fetch_refspec);
-	ret->push = parse_push_refspec(ret->push_refspec_nr, ret->push_refspec);
 	return ret;
 }
 
@@ -616,9 +614,6 @@ int for_each_remote(each_remote_fn fn, void *priv)
 		if (!r->fetch)
 			r->fetch = parse_fetch_refspec(r->fetch_refspec_nr,
 						       r->fetch_refspec);
-		if (!r->push)
-			r->push = parse_push_refspec(r->push_refspec_nr,
-						     r->push_refspec);
 		result = fn(r, priv);
 	}
 	return result;
@@ -1613,11 +1608,11 @@ static const char *branch_get_push_1(struct branch *branch, struct strbuf *err)
 				 _("branch '%s' has no remote for pushing"),
 				 branch->name);
 
-	if (remote->push_refspec_nr) {
+	if (remote->push.nr) {
 		char *dst;
 		const char *ret;
 
-		dst = apply_refspecs(remote->push, remote->push_refspec_nr,
+		dst = apply_refspecs(remote->push.items, remote->push.nr,
 				     branch->refname);
 		if (!dst)
 			return error_buf(err,
diff --git a/remote.h b/remote.h
index 3657bd43d..637fc5d0c 100644
--- a/remote.h
+++ b/remote.h
@@ -3,6 +3,7 @@
 
 #include "parse-options.h"
 #include "hashmap.h"
+#include "refspec.h"
 
 enum {
 	REMOTE_UNCONFIGURED = 0,
@@ -27,10 +28,7 @@ struct remote {
 	int pushurl_nr;
 	int pushurl_alloc;
 
-	const char **push_refspec;
-	struct refspec_item *push;
-	int push_refspec_nr;
-	int push_refspec_alloc;
+	struct refspec push;
 
 	const char **fetch_refspec;
 	struct refspec_item *fetch;
-- 
2.17.0.441.gb46fe60e1d-goog


^ permalink raw reply related	[flat|nested] 112+ messages in thread

* [PATCH 14/35] remote: convert fetch refspecs to struct refspec
  2018-05-14 21:55 [PATCH 00/35] refactoring refspecs Brandon Williams
                   ` (12 preceding siblings ...)
  2018-05-14 21:56 ` [PATCH 13/35] remote: convert push refspecs to " Brandon Williams
@ 2018-05-14 21:56 ` Brandon Williams
  2018-05-15  8:31   ` Ævar Arnfjörð Bjarmason
  2018-05-14 21:56 ` [PATCH 15/35] transport-helper: convert to use " Brandon Williams
                   ` (24 subsequent siblings)
  38 siblings, 1 reply; 112+ messages in thread
From: Brandon Williams @ 2018-05-14 21:56 UTC (permalink / raw)
  To: git, bmwill; +Cc: Brandon Williams

Convert the set of fetch refspecs stored in 'struct remote' to use
'struct refspec'.

Signed-off-by: Brandon Williams <bmwill@google.com>
---
 builtin/fetch.c  | 20 ++++++++++----------
 builtin/remote.c | 18 +++++++++---------
 remote.c         | 24 ++++++------------------
 remote.h         |  5 +----
 4 files changed, 26 insertions(+), 41 deletions(-)

diff --git a/builtin/fetch.c b/builtin/fetch.c
index 745020a10..30083d4bc 100644
--- a/builtin/fetch.c
+++ b/builtin/fetch.c
@@ -407,8 +407,8 @@ static struct ref *get_ref_map(struct transport *transport,
 			fetch_refspec = parse_fetch_refspec(refmap_nr, refmap_array);
 			fetch_refspec_nr = refmap_nr;
 		} else {
-			fetch_refspec = transport->remote->fetch;
-			fetch_refspec_nr = transport->remote->fetch_refspec_nr;
+			fetch_refspec = transport->remote->fetch.items;
+			fetch_refspec_nr = transport->remote->fetch.nr;
 		}
 
 		for (i = 0; i < fetch_refspec_nr; i++)
@@ -421,16 +421,16 @@ static struct ref *get_ref_map(struct transport *transport,
 		struct branch *branch = branch_get(NULL);
 		int has_merge = branch_has_merge_config(branch);
 		if (remote &&
-		    (remote->fetch_refspec_nr ||
+		    (remote->fetch.nr ||
 		     /* Note: has_merge implies non-NULL branch->remote_name */
 		     (has_merge && !strcmp(branch->remote_name, remote->name)))) {
-			for (i = 0; i < remote->fetch_refspec_nr; i++) {
-				get_fetch_map(remote_refs, &remote->fetch[i], &tail, 0);
-				if (remote->fetch[i].dst &&
-				    remote->fetch[i].dst[0])
+			for (i = 0; i < remote->fetch.nr; i++) {
+				get_fetch_map(remote_refs, &remote->fetch.items[i], &tail, 0);
+				if (remote->fetch.items[i].dst &&
+				    remote->fetch.items[i].dst[0])
 					*autotags = 1;
 				if (!i && !has_merge && ref_map &&
-				    !remote->fetch[0].pattern)
+				    !remote->fetch.items[0].pattern)
 					ref_map->fetch_head_status = FETCH_HEAD_MERGE;
 			}
 			/*
@@ -1166,8 +1166,8 @@ static int do_fetch(struct transport *transport,
 		if (ref_count) {
 			prune_refs(refs, ref_count, ref_map, transport->url);
 		} else {
-			prune_refs(transport->remote->fetch,
-				   transport->remote->fetch_refspec_nr,
+			prune_refs(transport->remote->fetch.items,
+				   transport->remote->fetch.nr,
 				   ref_map,
 				   transport->url);
 		}
diff --git a/builtin/remote.c b/builtin/remote.c
index fb84729d6..94dfcb78b 100644
--- a/builtin/remote.c
+++ b/builtin/remote.c
@@ -333,10 +333,10 @@ static int get_ref_states(const struct ref *remote_refs, struct ref_states *stat
 	struct ref *ref, *stale_refs;
 	int i;
 
-	for (i = 0; i < states->remote->fetch_refspec_nr; i++)
-		if (get_fetch_map(remote_refs, states->remote->fetch + i, &tail, 1))
+	for (i = 0; i < states->remote->fetch.nr; i++)
+		if (get_fetch_map(remote_refs, &states->remote->fetch.items[i], &tail, 1))
 			die(_("Could not get fetch map for refspec %s"),
-				states->remote->fetch_refspec[i]);
+				states->remote->fetch.raw[i]);
 
 	states->new_refs.strdup_strings = 1;
 	states->tracked.strdup_strings = 1;
@@ -347,8 +347,8 @@ static int get_ref_states(const struct ref *remote_refs, struct ref_states *stat
 		else
 			string_list_append(&states->tracked, abbrev_branch(ref->name));
 	}
-	stale_refs = get_stale_heads(states->remote->fetch,
-				     states->remote->fetch_refspec_nr, fetch_map);
+	stale_refs = get_stale_heads(states->remote->fetch.items,
+				     states->remote->fetch.nr, fetch_map);
 	for (ref = stale_refs; ref; ref = ref->next) {
 		struct string_list_item *item =
 			string_list_append(&states->stale, abbrev_branch(ref->name));
@@ -590,8 +590,8 @@ static int migrate_file(struct remote *remote)
 		git_config_set_multivar(buf.buf, remote->push.raw[i], "^$", 0);
 	strbuf_reset(&buf);
 	strbuf_addf(&buf, "remote.%s.fetch", remote->name);
-	for (i = 0; i < remote->fetch_refspec_nr; i++)
-		git_config_set_multivar(buf.buf, remote->fetch_refspec[i], "^$", 0);
+	for (i = 0; i < remote->fetch.raw_nr; i++)
+		git_config_set_multivar(buf.buf, remote->fetch.raw[i], "^$", 0);
 	if (remote->origin == REMOTE_REMOTES)
 		unlink_or_warn(git_path("remotes/%s", remote->name));
 	else if (remote->origin == REMOTE_BRANCHES)
@@ -646,11 +646,11 @@ static int mv(int argc, const char **argv)
 	strbuf_addf(&buf, "remote.%s.fetch", rename.new_name);
 	git_config_set_multivar(buf.buf, NULL, NULL, 1);
 	strbuf_addf(&old_remote_context, ":refs/remotes/%s/", rename.old_name);
-	for (i = 0; i < oldremote->fetch_refspec_nr; i++) {
+	for (i = 0; i < oldremote->fetch.raw_nr; i++) {
 		char *ptr;
 
 		strbuf_reset(&buf2);
-		strbuf_addstr(&buf2, oldremote->fetch_refspec[i]);
+		strbuf_addstr(&buf2, oldremote->fetch.raw[i]);
 		ptr = strstr(buf2.buf, old_remote_context.buf);
 		if (ptr) {
 			refspec_updated = 1;
diff --git a/remote.c b/remote.c
index 090110c37..db1e4edb7 100644
--- a/remote.c
+++ b/remote.c
@@ -84,21 +84,12 @@ static void add_push_refspec(struct remote *remote, const char *ref)
 
 static void add_fetch_refspec(struct remote *remote, const char *ref)
 {
-	ALLOC_GROW(remote->fetch_refspec,
-		   remote->fetch_refspec_nr + 1,
-		   remote->fetch_refspec_alloc);
-	remote->fetch_refspec[remote->fetch_refspec_nr++] = ref;
+	refspec_append(&remote->fetch, ref);
 }
 
 void add_prune_tags_to_fetch_refspec(struct remote *remote)
 {
-	int nr = remote->fetch_refspec_nr;
-	int bufsize = nr  + 1;
-	int size = sizeof(struct refspec_item);
-
-	remote->fetch = xrealloc(remote->fetch, size  * bufsize);
-	memcpy(&remote->fetch[nr], tag_refspec, size);
-	add_fetch_refspec(remote, xstrdup(TAG_REFSPEC));
+	refspec_append(&remote->fetch, TAG_REFSPEC);
 }
 
 static void add_url(struct remote *remote, const char *url)
@@ -174,6 +165,7 @@ static struct remote *make_remote(const char *name, int len)
 	ret->prune_tags = -1;  /* unspecified */
 	ret->name = xstrndup(name, len);
 	refspec_init(&ret->push, REFSPEC_PUSH);
+	refspec_init(&ret->fetch, REFSPEC_FETCH);
 
 	ALLOC_GROW(remotes, remotes_nr + 1, remotes_alloc);
 	remotes[remotes_nr++] = ret;
@@ -580,7 +572,6 @@ static struct remote *remote_get_1(const char *name,
 		add_url_alias(ret, name);
 	if (!valid_remote(ret))
 		return NULL;
-	ret->fetch = parse_fetch_refspec(ret->fetch_refspec_nr, ret->fetch_refspec);
 	return ret;
 }
 
@@ -611,9 +602,6 @@ int for_each_remote(each_remote_fn fn, void *priv)
 		struct remote *r = remotes[i];
 		if (!r)
 			continue;
-		if (!r->fetch)
-			r->fetch = parse_fetch_refspec(r->fetch_refspec_nr,
-						       r->fetch_refspec);
 		result = fn(r, priv);
 	}
 	return result;
@@ -792,7 +780,7 @@ char *apply_refspecs(struct refspec_item *refspecs, int nr_refspec,
 
 int remote_find_tracking(struct remote *remote, struct refspec_item *refspec)
 {
-	return query_refspecs(remote->fetch, remote->fetch_refspec_nr, refspec);
+	return query_refspecs(remote->fetch.items, remote->fetch.nr, refspec);
 }
 
 static struct ref *alloc_ref_with_prefix(const char *prefix, size_t prefixlen,
@@ -1590,7 +1578,7 @@ static const char *tracking_for_push_dest(struct remote *remote,
 {
 	char *ret;
 
-	ret = apply_refspecs(remote->fetch, remote->fetch_refspec_nr, refname);
+	ret = apply_refspecs(remote->fetch.items, remote->fetch.nr, refname);
 	if (!ret)
 		return error_buf(err,
 				 _("push destination '%s' on remote '%s' has no local tracking branch"),
@@ -2224,7 +2212,7 @@ static int remote_tracking(struct remote *remote, const char *refname,
 {
 	char *dst;
 
-	dst = apply_refspecs(remote->fetch, remote->fetch_refspec_nr, refname);
+	dst = apply_refspecs(remote->fetch.items, remote->fetch.nr, refname);
 	if (!dst)
 		return -1; /* no tracking ref for refname at remote */
 	if (read_ref(dst, oid))
diff --git a/remote.h b/remote.h
index 637fc5d0c..e7d00fe2a 100644
--- a/remote.h
+++ b/remote.h
@@ -30,10 +30,7 @@ struct remote {
 
 	struct refspec push;
 
-	const char **fetch_refspec;
-	struct refspec_item *fetch;
-	int fetch_refspec_nr;
-	int fetch_refspec_alloc;
+	struct refspec fetch;
 
 	/*
 	 * -1 to never fetch tags
-- 
2.17.0.441.gb46fe60e1d-goog


^ permalink raw reply related	[flat|nested] 112+ messages in thread

* [PATCH 15/35] transport-helper: convert to use struct refspec
  2018-05-14 21:55 [PATCH 00/35] refactoring refspecs Brandon Williams
                   ` (13 preceding siblings ...)
  2018-05-14 21:56 ` [PATCH 14/35] remote: convert fetch " Brandon Williams
@ 2018-05-14 21:56 ` Brandon Williams
  2018-05-14 21:56 ` [PATCH 16/35] fetch: convert fetch_one " Brandon Williams
                   ` (23 subsequent siblings)
  38 siblings, 0 replies; 112+ messages in thread
From: Brandon Williams @ 2018-05-14 21:56 UTC (permalink / raw)
  To: git, bmwill; +Cc: Brandon Williams

Convert the refspecs in transport-helper.c to be stored in a
'struct refspec'.

Signed-off-by: Brandon Williams <bmwill@google.com>
---
 transport-helper.c | 38 ++++++++++++--------------------------
 1 file changed, 12 insertions(+), 26 deletions(-)

diff --git a/transport-helper.c b/transport-helper.c
index b156a37e7..33f51ebfc 100644
--- a/transport-helper.c
+++ b/transport-helper.c
@@ -36,8 +36,7 @@ struct helper_data {
 	char *export_marks;
 	char *import_marks;
 	/* These go from remote name (as in "list") to private name */
-	struct refspec_item *refspecs;
-	int refspec_nr;
+	struct refspec rs;
 	/* Transport options for fetch-pack/send-pack (should one of
 	 * those be invoked).
 	 */
@@ -107,9 +106,6 @@ static struct child_process *get_helper(struct transport *transport)
 	struct helper_data *data = transport->data;
 	struct strbuf buf = STRBUF_INIT;
 	struct child_process *helper;
-	const char **refspecs = NULL;
-	int refspec_nr = 0;
-	int refspec_alloc = 0;
 	int duped;
 	int code;
 
@@ -139,6 +135,7 @@ static struct child_process *get_helper(struct transport *transport)
 
 	data->helper = helper;
 	data->no_disconnect_req = 0;
+	refspec_init(&data->rs, REFSPEC_FETCH);
 
 	/*
 	 * Open the output as FILE* so strbuf_getline_*() family of
@@ -184,11 +181,8 @@ static struct child_process *get_helper(struct transport *transport)
 			data->export = 1;
 		else if (!strcmp(capname, "check-connectivity"))
 			data->check_connectivity = 1;
-		else if (!data->refspecs && skip_prefix(capname, "refspec ", &arg)) {
-			ALLOC_GROW(refspecs,
-				   refspec_nr + 1,
-				   refspec_alloc);
-			refspecs[refspec_nr++] = xstrdup(arg);
+		else if (skip_prefix(capname, "refspec ", &arg)) {
+			refspec_append(&data->rs, arg);
 		} else if (!strcmp(capname, "connect")) {
 			data->connect = 1;
 		} else if (!strcmp(capname, "stateless-connect")) {
@@ -207,14 +201,7 @@ static struct child_process *get_helper(struct transport *transport)
 			    capname);
 		}
 	}
-	if (refspecs) {
-		int i;
-		data->refspec_nr = refspec_nr;
-		data->refspecs = parse_fetch_refspec(refspec_nr, refspecs);
-		for (i = 0; i < refspec_nr; i++)
-			free((char *)refspecs[i]);
-		free(refspecs);
-	} else if (data->import || data->bidi_import || data->export) {
+	if (!data->rs.nr && (data->import || data->bidi_import || data->export)) {
 		warning("This remote helper should implement refspec capability.");
 	}
 	strbuf_release(&buf);
@@ -378,8 +365,7 @@ static int release_helper(struct transport *transport)
 {
 	int res = 0;
 	struct helper_data *data = transport->data;
-	free_refspec(data->refspec_nr, data->refspecs);
-	data->refspecs = NULL;
+	refspec_clear(&data->rs);
 	res = disconnect_helper(transport);
 	free(transport->data);
 	return res;
@@ -536,8 +522,8 @@ static int fetch_with_import(struct transport *transport,
 		if (posn->status & REF_STATUS_UPTODATE)
 			continue;
 		name = posn->symref ? posn->symref : posn->name;
-		if (data->refspecs)
-			private = apply_refspecs(data->refspecs, data->refspec_nr, name);
+		if (data->rs.nr)
+			private = apply_refspecs(data->rs.items, data->rs.nr, name);
 		else
 			private = xstrdup(name);
 		if (private) {
@@ -815,11 +801,11 @@ static int push_update_refs_status(struct helper_data *data,
 		if (push_update_ref_status(&buf, &ref, remote_refs))
 			continue;
 
-		if (flags & TRANSPORT_PUSH_DRY_RUN || !data->refspecs || data->no_private_update)
+		if (flags & TRANSPORT_PUSH_DRY_RUN || !data->rs.nr || data->no_private_update)
 			continue;
 
 		/* propagate back the update to the remote namespace */
-		private = apply_refspecs(data->refspecs, data->refspec_nr, ref->name);
+		private = apply_refspecs(data->rs.items, data->rs.nr, ref->name);
 		if (!private)
 			continue;
 		update_ref("update by helper", private, &ref->new_oid, NULL,
@@ -939,7 +925,7 @@ static int push_refs_with_export(struct transport *transport,
 	struct string_list revlist_args = STRING_LIST_INIT_DUP;
 	struct strbuf buf = STRBUF_INIT;
 
-	if (!data->refspecs)
+	if (!data->rs.nr)
 		die("remote-helper doesn't support push; refspec needed");
 
 	set_common_push_options(transport, data->name, flags);
@@ -956,7 +942,7 @@ static int push_refs_with_export(struct transport *transport,
 		char *private;
 		struct object_id oid;
 
-		private = apply_refspecs(data->refspecs, data->refspec_nr, ref->name);
+		private = apply_refspecs(data->rs.items, data->rs.nr, ref->name);
 		if (private && !get_oid(private, &oid)) {
 			strbuf_addf(&buf, "^%s", private);
 			string_list_append_nodup(&revlist_args,
-- 
2.17.0.441.gb46fe60e1d-goog


^ permalink raw reply related	[flat|nested] 112+ messages in thread

* [PATCH 16/35] fetch: convert fetch_one to use struct refspec
  2018-05-14 21:55 [PATCH 00/35] refactoring refspecs Brandon Williams
                   ` (14 preceding siblings ...)
  2018-05-14 21:56 ` [PATCH 15/35] transport-helper: convert to use " Brandon Williams
@ 2018-05-14 21:56 ` Brandon Williams
  2018-05-14 21:56 ` [PATCH 17/35] fetch: convert refmap " Brandon Williams
                   ` (22 subsequent siblings)
  38 siblings, 0 replies; 112+ messages in thread
From: Brandon Williams @ 2018-05-14 21:56 UTC (permalink / raw)
  To: git, bmwill; +Cc: Brandon Williams

Convert 'fetch_one()' to use 'struct refspec'.

Signed-off-by: Brandon Williams <bmwill@google.com>
---
 builtin/fetch.c | 46 +++++++++++++++++++---------------------------
 1 file changed, 19 insertions(+), 27 deletions(-)

diff --git a/builtin/fetch.c b/builtin/fetch.c
index 30083d4bc..769f9d2be 100644
--- a/builtin/fetch.c
+++ b/builtin/fetch.c
@@ -1356,10 +1356,8 @@ static inline void fetch_one_setup_partial(struct remote *remote)
 
 static int fetch_one(struct remote *remote, int argc, const char **argv, int prune_tags_ok)
 {
-	static const char **refs = NULL;
-	struct refspec_item *refspec;
-	int ref_nr = 0;
-	int j = 0;
+	struct refspec rs = REFSPEC_INIT_FETCH;
+	int i;
 	int exit_code;
 	int maybe_prune_tags;
 	int remote_via_config = remote_is_configured(remote, 0);
@@ -1394,35 +1392,29 @@ static int fetch_one(struct remote *remote, int argc, const char **argv, int pru
 	if (maybe_prune_tags && remote_via_config)
 		add_prune_tags_to_fetch_refspec(remote);
 
-	if (argc > 0 || (maybe_prune_tags && !remote_via_config)) {
-		size_t nr_alloc = st_add3(argc, maybe_prune_tags, 1);
-		refs = xcalloc(nr_alloc, sizeof(const char *));
-		if (maybe_prune_tags) {
-			refs[j++] = xstrdup("refs/tags/*:refs/tags/*");
-			ref_nr++;
-		}
-	}
+	if (maybe_prune_tags && (argc || !remote_via_config))
+		refspec_append(&rs, TAG_REFSPEC);
 
-	if (argc > 0) {
-		int i;
-		for (i = 0; i < argc; i++) {
-			if (!strcmp(argv[i], "tag")) {
-				i++;
-				if (i >= argc)
-					die(_("You need to specify a tag name."));
-				refs[j++] = xstrfmt("refs/tags/%s:refs/tags/%s",
-						    argv[i], argv[i]);
-			} else
-				refs[j++] = argv[i];
-			ref_nr++;
+	for (i = 0; i < argc; i++) {
+		if (!strcmp(argv[i], "tag")) {
+			char *tag;
+			i++;
+			if (i >= argc)
+				die(_("You need to specify a tag name."));
+
+			tag = xstrfmt("refs/tags/%s:refs/tags/%s",
+				      argv[i], argv[i]);
+			refspec_append(&rs, tag);
+			free(tag);
+		} else {
+			refspec_append(&rs, argv[i]);
 		}
 	}
 
 	sigchain_push_common(unlock_pack_on_signal);
 	atexit(unlock_pack);
-	refspec = parse_fetch_refspec(ref_nr, refs);
-	exit_code = do_fetch(gtransport, refspec, ref_nr);
-	free_refspec(ref_nr, refspec);
+	exit_code = do_fetch(gtransport, rs.items, rs.nr);
+	refspec_clear(&rs);
 	transport_disconnect(gtransport);
 	gtransport = NULL;
 	return exit_code;
-- 
2.17.0.441.gb46fe60e1d-goog


^ permalink raw reply related	[flat|nested] 112+ messages in thread

* [PATCH 17/35] fetch: convert refmap to use struct refspec
  2018-05-14 21:55 [PATCH 00/35] refactoring refspecs Brandon Williams
                   ` (15 preceding siblings ...)
  2018-05-14 21:56 ` [PATCH 16/35] fetch: convert fetch_one " Brandon Williams
@ 2018-05-14 21:56 ` Brandon Williams
  2018-05-14 21:56 ` [PATCH 18/35] refspec: remove the deprecated functions Brandon Williams
                   ` (21 subsequent siblings)
  38 siblings, 0 replies; 112+ messages in thread
From: Brandon Williams @ 2018-05-14 21:56 UTC (permalink / raw)
  To: git, bmwill; +Cc: Brandon Williams

Convert the refmap in builtin/fetch.c to be stored in a
'struct refspec'.

Signed-off-by: Brandon Williams <bmwill@google.com>
---
 builtin/fetch.c | 17 +++++++----------
 1 file changed, 7 insertions(+), 10 deletions(-)

diff --git a/builtin/fetch.c b/builtin/fetch.c
index 769f9d2be..e2f2f290e 100644
--- a/builtin/fetch.c
+++ b/builtin/fetch.c
@@ -60,8 +60,7 @@ static const char *submodule_prefix = "";
 static int recurse_submodules = RECURSE_SUBMODULES_DEFAULT;
 static int recurse_submodules_default = RECURSE_SUBMODULES_ON_DEMAND;
 static int shown_url = 0;
-static int refmap_alloc, refmap_nr;
-static const char **refmap_array;
+static struct refspec refmap = REFSPEC_INIT_FETCH;
 static struct list_objects_filter_options filter_options;
 
 static int git_fetch_config(const char *k, const char *v, void *cb)
@@ -108,14 +107,12 @@ static int gitmodules_fetch_config(const char *var, const char *value, void *cb)
 
 static int parse_refmap_arg(const struct option *opt, const char *arg, int unset)
 {
-	ALLOC_GROW(refmap_array, refmap_nr + 1, refmap_alloc);
-
 	/*
 	 * "git fetch --refmap='' origin foo"
 	 * can be used to tell the command not to store anywhere
 	 */
-	if (*arg)
-		refmap_array[refmap_nr++] = arg;
+	refspec_append(&refmap, arg);
+
 	return 0;
 }
 
@@ -403,9 +400,9 @@ static struct ref *get_ref_map(struct transport *transport,
 		 * by ref_remove_duplicates() in favor of one of these
 		 * opportunistic entries with FETCH_HEAD_IGNORE.
 		 */
-		if (refmap_array) {
-			fetch_refspec = parse_fetch_refspec(refmap_nr, refmap_array);
-			fetch_refspec_nr = refmap_nr;
+		if (refmap.nr) {
+			fetch_refspec = refmap.items;
+			fetch_refspec_nr = refmap.nr;
 		} else {
 			fetch_refspec = transport->remote->fetch.items;
 			fetch_refspec_nr = transport->remote->fetch.nr;
@@ -413,7 +410,7 @@ static struct ref *get_ref_map(struct transport *transport,
 
 		for (i = 0; i < fetch_refspec_nr; i++)
 			get_fetch_map(ref_map, &fetch_refspec[i], &oref_tail, 1);
-	} else if (refmap_array) {
+	} else if (refmap.nr) {
 		die("--refmap option is only meaningful with command-line refspec(s).");
 	} else {
 		/* Use the defaults */
-- 
2.17.0.441.gb46fe60e1d-goog


^ permalink raw reply related	[flat|nested] 112+ messages in thread

* [PATCH 18/35] refspec: remove the deprecated functions
  2018-05-14 21:55 [PATCH 00/35] refactoring refspecs Brandon Williams
                   ` (16 preceding siblings ...)
  2018-05-14 21:56 ` [PATCH 17/35] fetch: convert refmap " Brandon Williams
@ 2018-05-14 21:56 ` Brandon Williams
  2018-05-14 21:56 ` [PATCH 19/35] fetch: convert do_fetch to take a struct refspec Brandon Williams
                   ` (20 subsequent siblings)
  38 siblings, 0 replies; 112+ messages in thread
From: Brandon Williams @ 2018-05-14 21:56 UTC (permalink / raw)
  To: git, bmwill; +Cc: Brandon Williams

Now that there are no callers of 'parse_push_refspec()',
'parse_fetch_refspec()', and 'free_refspec()', remove these
functions.

Signed-off-by: Brandon Williams <bmwill@google.com>
---
 refspec.c | 49 -------------------------------------------------
 refspec.h |  5 -----
 2 files changed, 54 deletions(-)

diff --git a/refspec.c b/refspec.c
index 98c99cd84..7953a70d0 100644
--- a/refspec.c
+++ b/refspec.c
@@ -121,55 +121,6 @@ static int parse_refspec(struct refspec_item *rs, const char *refspec, int fetch
 	return 1;
 }
 
-static struct refspec_item *parse_refspec_internal(int nr_refspec, const char **refspec, int fetch, int verify)
-{
-	int i;
-	struct refspec_item *rs = xcalloc(nr_refspec, sizeof(*rs));
-
-	for (i = 0; i < nr_refspec; i++) {
-		if (!parse_refspec(&rs[i], refspec[i], fetch))
-			goto invalid;
-	}
-
-	return rs;
-
- invalid:
-	if (verify) {
-		/*
-		 * nr_refspec must be greater than zero and i must be valid
-		 * since it is only possible to reach this point from within
-		 * the for loop above.
-		 */
-		free_refspec(i+1, rs);
-		return NULL;
-	}
-	die("Invalid refspec '%s'", refspec[i]);
-}
-
-struct refspec_item *parse_fetch_refspec(int nr_refspec, const char **refspec)
-{
-	return parse_refspec_internal(nr_refspec, refspec, 1, 0);
-}
-
-struct refspec_item *parse_push_refspec(int nr_refspec, const char **refspec)
-{
-	return parse_refspec_internal(nr_refspec, refspec, 0, 0);
-}
-
-void free_refspec(int nr_refspec, struct refspec_item *refspec)
-{
-	int i;
-
-	if (!refspec)
-		return;
-
-	for (i = 0; i < nr_refspec; i++) {
-		free(refspec[i].src);
-		free(refspec[i].dst);
-	}
-	free(refspec);
-}
-
 void refspec_item_init(struct refspec_item *item, const char *refspec, int fetch)
 {
 	memset(item, 0, sizeof(*item));
diff --git a/refspec.h b/refspec.h
index b009440c0..374f8ea63 100644
--- a/refspec.h
+++ b/refspec.h
@@ -14,11 +14,6 @@ struct refspec_item {
 	char *dst;
 };
 
-struct refspec_item *parse_fetch_refspec(int nr_refspec, const char **refspec);
-struct refspec_item *parse_push_refspec(int nr_refspec, const char **refspec);
-
-void free_refspec(int nr_refspec, struct refspec_item *refspec);
-
 #define REFSPEC_FETCH 1
 #define REFSPEC_PUSH 0
 
-- 
2.17.0.441.gb46fe60e1d-goog


^ permalink raw reply related	[flat|nested] 112+ messages in thread

* [PATCH 19/35] fetch: convert do_fetch to take a struct refspec
  2018-05-14 21:55 [PATCH 00/35] refactoring refspecs Brandon Williams
                   ` (17 preceding siblings ...)
  2018-05-14 21:56 ` [PATCH 18/35] refspec: remove the deprecated functions Brandon Williams
@ 2018-05-14 21:56 ` Brandon Williams
  2018-05-14 21:56 ` [PATCH 20/35] fetch: convert get_ref_map " Brandon Williams
                   ` (19 subsequent siblings)
  38 siblings, 0 replies; 112+ messages in thread
From: Brandon Williams @ 2018-05-14 21:56 UTC (permalink / raw)
  To: git, bmwill; +Cc: Brandon Williams

Convert 'do_fetch()' to take a 'struct refspec' as a parameter instead
of a list of 'struct refspec_item'.

Signed-off-by: Brandon Williams <bmwill@google.com>
---
 builtin/fetch.c | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/builtin/fetch.c b/builtin/fetch.c
index e2f2f290e..733feb19c 100644
--- a/builtin/fetch.c
+++ b/builtin/fetch.c
@@ -1112,7 +1112,7 @@ static void backfill_tags(struct transport *transport, struct ref *ref_map)
 }
 
 static int do_fetch(struct transport *transport,
-		    struct refspec_item *refs, int ref_count)
+		    struct refspec *rs)
 {
 	struct string_list existing_refs = STRING_LIST_INIT_DUP;
 	struct ref *ref_map;
@@ -1136,7 +1136,7 @@ static int do_fetch(struct transport *transport,
 			goto cleanup;
 	}
 
-	ref_map = get_ref_map(transport, refs, ref_count, tags, &autotags);
+	ref_map = get_ref_map(transport, rs->items, rs->nr, tags, &autotags);
 	if (!update_head_ok)
 		check_not_current_branch(ref_map);
 
@@ -1160,8 +1160,8 @@ static int do_fetch(struct transport *transport,
 		 * explicitly (via command line or configuration); we
 		 * don't care whether --tags was specified.
 		 */
-		if (ref_count) {
-			prune_refs(refs, ref_count, ref_map, transport->url);
+		if (rs->nr) {
+			prune_refs(rs->items, rs->nr, ref_map, transport->url);
 		} else {
 			prune_refs(transport->remote->fetch.items,
 				   transport->remote->fetch.nr,
@@ -1410,7 +1410,7 @@ static int fetch_one(struct remote *remote, int argc, const char **argv, int pru
 
 	sigchain_push_common(unlock_pack_on_signal);
 	atexit(unlock_pack);
-	exit_code = do_fetch(gtransport, rs.items, rs.nr);
+	exit_code = do_fetch(gtransport, &rs);
 	refspec_clear(&rs);
 	transport_disconnect(gtransport);
 	gtransport = NULL;
-- 
2.17.0.441.gb46fe60e1d-goog


^ permalink raw reply related	[flat|nested] 112+ messages in thread

* [PATCH 20/35] fetch: convert get_ref_map to take a struct refspec
  2018-05-14 21:55 [PATCH 00/35] refactoring refspecs Brandon Williams
                   ` (18 preceding siblings ...)
  2018-05-14 21:56 ` [PATCH 19/35] fetch: convert do_fetch to take a struct refspec Brandon Williams
@ 2018-05-14 21:56 ` Brandon Williams
  2018-05-14 21:56 ` [PATCH 21/35] fetch: convert prune_refs " Brandon Williams
                   ` (18 subsequent siblings)
  38 siblings, 0 replies; 112+ messages in thread
From: Brandon Williams @ 2018-05-14 21:56 UTC (permalink / raw)
  To: git, bmwill; +Cc: Brandon Williams

Convert 'get_ref_map()' to take a 'struct refspec' as a parameter
instead of a list of 'struct refspec_item'.

Signed-off-by: Brandon Williams <bmwill@google.com>
---
 builtin/fetch.c | 43 ++++++++++++++++++++-----------------------
 1 file changed, 20 insertions(+), 23 deletions(-)

diff --git a/builtin/fetch.c b/builtin/fetch.c
index 733feb19c..86a7f103f 100644
--- a/builtin/fetch.c
+++ b/builtin/fetch.c
@@ -337,7 +337,7 @@ static void find_non_local_tags(struct transport *transport,
 }
 
 static struct ref *get_ref_map(struct transport *transport,
-			       struct refspec_item *refspecs, int refspec_count,
+			       struct refspec *rs,
 			       int tags, int *autotags)
 {
 	int i;
@@ -351,15 +351,16 @@ static struct ref *get_ref_map(struct transport *transport,
 
 	const struct ref *remote_refs;
 
-	for (i = 0; i < refspec_count; i++) {
-		if (!refspecs[i].exact_sha1) {
-			const char *glob = strchr(refspecs[i].src, '*');
+	for (i = 0; i < rs->nr; i++) {
+		const struct refspec_item *item = &rs->items[i];
+		if (!item->exact_sha1) {
+			const char *glob = strchr(item->src, '*');
 			if (glob)
 				argv_array_pushf(&ref_prefixes, "%.*s",
-						 (int)(glob - refspecs[i].src),
-						 refspecs[i].src);
+						 (int)(glob - item->src),
+						 item->src);
 			else
-				expand_ref_prefix(&ref_prefixes, refspecs[i].src);
+				expand_ref_prefix(&ref_prefixes, item->src);
 		}
 	}
 
@@ -367,13 +368,12 @@ static struct ref *get_ref_map(struct transport *transport,
 
 	argv_array_clear(&ref_prefixes);
 
-	if (refspec_count) {
-		struct refspec_item *fetch_refspec;
-		int fetch_refspec_nr;
+	if (rs->nr) {
+		struct refspec *fetch_refspec;
 
-		for (i = 0; i < refspec_count; i++) {
-			get_fetch_map(remote_refs, &refspecs[i], &tail, 0);
-			if (refspecs[i].dst && refspecs[i].dst[0])
+		for (i = 0; i < rs->nr; i++) {
+			get_fetch_map(remote_refs, &rs->items[i], &tail, 0);
+			if (rs->items[i].dst && rs->items[i].dst[0])
 				*autotags = 1;
 		}
 		/* Merge everything on the command line (but not --tags) */
@@ -400,16 +400,13 @@ static struct ref *get_ref_map(struct transport *transport,
 		 * by ref_remove_duplicates() in favor of one of these
 		 * opportunistic entries with FETCH_HEAD_IGNORE.
 		 */
-		if (refmap.nr) {
-			fetch_refspec = refmap.items;
-			fetch_refspec_nr = refmap.nr;
-		} else {
-			fetch_refspec = transport->remote->fetch.items;
-			fetch_refspec_nr = transport->remote->fetch.nr;
-		}
+		if (refmap.nr)
+			fetch_refspec = &refmap;
+		else
+			fetch_refspec = &transport->remote->fetch;
 
-		for (i = 0; i < fetch_refspec_nr; i++)
-			get_fetch_map(ref_map, &fetch_refspec[i], &oref_tail, 1);
+		for (i = 0; i < fetch_refspec->nr; i++)
+			get_fetch_map(ref_map, &fetch_refspec->items[i], &oref_tail, 1);
 	} else if (refmap.nr) {
 		die("--refmap option is only meaningful with command-line refspec(s).");
 	} else {
@@ -1136,7 +1133,7 @@ static int do_fetch(struct transport *transport,
 			goto cleanup;
 	}
 
-	ref_map = get_ref_map(transport, rs->items, rs->nr, tags, &autotags);
+	ref_map = get_ref_map(transport, rs, tags, &autotags);
 	if (!update_head_ok)
 		check_not_current_branch(ref_map);
 
-- 
2.17.0.441.gb46fe60e1d-goog


^ permalink raw reply related	[flat|nested] 112+ messages in thread

* [PATCH 21/35] fetch: convert prune_refs to take a struct refspec
  2018-05-14 21:55 [PATCH 00/35] refactoring refspecs Brandon Williams
                   ` (19 preceding siblings ...)
  2018-05-14 21:56 ` [PATCH 20/35] fetch: convert get_ref_map " Brandon Williams
@ 2018-05-14 21:56 ` Brandon Williams
  2018-05-14 21:56 ` [PATCH 22/35] remote: convert get_stale_heads " Brandon Williams
                   ` (17 subsequent siblings)
  38 siblings, 0 replies; 112+ messages in thread
From: Brandon Williams @ 2018-05-14 21:56 UTC (permalink / raw)
  To: git, bmwill; +Cc: Brandon Williams

Convert 'prune_refs()' to take a 'struct refspec' as a parameter instead
of a list of 'struct refspec_item'.

Signed-off-by: Brandon Williams <bmwill@google.com>
---
 builtin/fetch.c | 11 +++++------
 1 file changed, 5 insertions(+), 6 deletions(-)

diff --git a/builtin/fetch.c b/builtin/fetch.c
index 86a7f103f..eebeebfd8 100644
--- a/builtin/fetch.c
+++ b/builtin/fetch.c
@@ -959,11 +959,11 @@ static int fetch_refs(struct transport *transport, struct ref *ref_map)
 	return ret;
 }
 
-static int prune_refs(struct refspec_item *refs, int ref_count, struct ref *ref_map,
-		const char *raw_url)
+static int prune_refs(struct refspec *rs, struct ref *ref_map,
+		      const char *raw_url)
 {
 	int url_len, i, result = 0;
-	struct ref *ref, *stale_refs = get_stale_heads(refs, ref_count, ref_map);
+	struct ref *ref, *stale_refs = get_stale_heads(rs->items, rs->nr, ref_map);
 	char *url;
 	int summary_width = transport_summary_width(stale_refs);
 	const char *dangling_msg = dry_run
@@ -1158,10 +1158,9 @@ static int do_fetch(struct transport *transport,
 		 * don't care whether --tags was specified.
 		 */
 		if (rs->nr) {
-			prune_refs(rs->items, rs->nr, ref_map, transport->url);
+			prune_refs(rs, ref_map, transport->url);
 		} else {
-			prune_refs(transport->remote->fetch.items,
-				   transport->remote->fetch.nr,
+			prune_refs(&transport->remote->fetch,
 				   ref_map,
 				   transport->url);
 		}
-- 
2.17.0.441.gb46fe60e1d-goog


^ permalink raw reply related	[flat|nested] 112+ messages in thread

* [PATCH 22/35] remote: convert get_stale_heads to take a struct refspec
  2018-05-14 21:55 [PATCH 00/35] refactoring refspecs Brandon Williams
                   ` (20 preceding siblings ...)
  2018-05-14 21:56 ` [PATCH 21/35] fetch: convert prune_refs " Brandon Williams
@ 2018-05-14 21:56 ` Brandon Williams
  2018-05-14 21:56 ` [PATCH 23/35] remote: convert apply_refspecs " Brandon Williams
                   ` (16 subsequent siblings)
  38 siblings, 0 replies; 112+ messages in thread
From: Brandon Williams @ 2018-05-14 21:56 UTC (permalink / raw)
  To: git, bmwill; +Cc: Brandon Williams

Convert 'get_stale_heads()' to take a 'struct refspec' as a parameter instead
of a list of 'struct refspec_item'.

Signed-off-by: Brandon Williams <bmwill@google.com>
---
 builtin/fetch.c  |  2 +-
 builtin/remote.c |  3 +--
 remote.c         | 18 +++++++++---------
 remote.h         |  2 +-
 4 files changed, 12 insertions(+), 13 deletions(-)

diff --git a/builtin/fetch.c b/builtin/fetch.c
index eebeebfd8..af7064dce 100644
--- a/builtin/fetch.c
+++ b/builtin/fetch.c
@@ -963,7 +963,7 @@ static int prune_refs(struct refspec *rs, struct ref *ref_map,
 		      const char *raw_url)
 {
 	int url_len, i, result = 0;
-	struct ref *ref, *stale_refs = get_stale_heads(rs->items, rs->nr, ref_map);
+	struct ref *ref, *stale_refs = get_stale_heads(rs, ref_map);
 	char *url;
 	int summary_width = transport_summary_width(stale_refs);
 	const char *dangling_msg = dry_run
diff --git a/builtin/remote.c b/builtin/remote.c
index 94dfcb78b..b8e66589f 100644
--- a/builtin/remote.c
+++ b/builtin/remote.c
@@ -347,8 +347,7 @@ static int get_ref_states(const struct ref *remote_refs, struct ref_states *stat
 		else
 			string_list_append(&states->tracked, abbrev_branch(ref->name));
 	}
-	stale_refs = get_stale_heads(states->remote->fetch.items,
-				     states->remote->fetch.nr, fetch_map);
+	stale_refs = get_stale_heads(&states->remote->fetch, fetch_map);
 	for (ref = stale_refs; ref; ref = ref->next) {
 		struct string_list_item *item =
 			string_list_append(&states->stale, abbrev_branch(ref->name));
diff --git a/remote.c b/remote.c
index db1e4edb7..f2e97c545 100644
--- a/remote.c
+++ b/remote.c
@@ -707,7 +707,9 @@ static int match_name_with_pattern(const char *key, const char *name,
 	return ret;
 }
 
-static void query_refspecs_multiple(struct refspec_item *refs, int ref_count, struct refspec_item *query, struct string_list *results)
+static void query_refspecs_multiple(struct refspec *rs,
+				    struct refspec_item *query,
+				    struct string_list *results)
 {
 	int i;
 	int find_src = !query->src;
@@ -715,8 +717,8 @@ static void query_refspecs_multiple(struct refspec_item *refs, int ref_count, st
 	if (find_src && !query->dst)
 		error("query_refspecs_multiple: need either src or dst");
 
-	for (i = 0; i < ref_count; i++) {
-		struct refspec_item *refspec = &refs[i];
+	for (i = 0; i < rs->nr; i++) {
+		struct refspec_item *refspec = &rs->items[i];
 		const char *key = find_src ? refspec->dst : refspec->src;
 		const char *value = find_src ? refspec->src : refspec->dst;
 		const char *needle = find_src ? query->dst : query->src;
@@ -2077,8 +2079,7 @@ struct ref *guess_remote_head(const struct ref *head,
 struct stale_heads_info {
 	struct string_list *ref_names;
 	struct ref **stale_refs_tail;
-	struct refspec_item *refs;
-	int ref_count;
+	struct refspec *rs;
 };
 
 static int get_stale_heads_cb(const char *refname, const struct object_id *oid,
@@ -2091,7 +2092,7 @@ static int get_stale_heads_cb(const char *refname, const struct object_id *oid,
 	memset(&query, 0, sizeof(struct refspec_item));
 	query.dst = (char *)refname;
 
-	query_refspecs_multiple(info->refs, info->ref_count, &query, &matches);
+	query_refspecs_multiple(info->rs, &query, &matches);
 	if (matches.nr == 0)
 		goto clean_exit; /* No matches */
 
@@ -2119,7 +2120,7 @@ static int get_stale_heads_cb(const char *refname, const struct object_id *oid,
 	return 0;
 }
 
-struct ref *get_stale_heads(struct refspec_item *refs, int ref_count, struct ref *fetch_map)
+struct ref *get_stale_heads(struct refspec *rs, struct ref *fetch_map)
 {
 	struct ref *ref, *stale_refs = NULL;
 	struct string_list ref_names = STRING_LIST_INIT_NODUP;
@@ -2127,8 +2128,7 @@ struct ref *get_stale_heads(struct refspec_item *refs, int ref_count, struct ref
 
 	info.ref_names = &ref_names;
 	info.stale_refs_tail = &stale_refs;
-	info.refs = refs;
-	info.ref_count = ref_count;
+	info.rs = rs;
 	for (ref = fetch_map; ref; ref = ref->next)
 		string_list_append(&ref_names, ref->name);
 	string_list_sort(&ref_names);
diff --git a/remote.h b/remote.h
index e7d00fe2a..5ac7536f5 100644
--- a/remote.h
+++ b/remote.h
@@ -267,7 +267,7 @@ struct ref *guess_remote_head(const struct ref *head,
 			      int all);
 
 /* Return refs which no longer exist on remote */
-struct ref *get_stale_heads(struct refspec_item *refs, int ref_count, struct ref *fetch_map);
+struct ref *get_stale_heads(struct refspec *rs, struct ref *fetch_map);
 
 /*
  * Compare-and-swap
-- 
2.17.0.441.gb46fe60e1d-goog


^ permalink raw reply related	[flat|nested] 112+ messages in thread

* [PATCH 23/35] remote: convert apply_refspecs to take a struct refspec
  2018-05-14 21:55 [PATCH 00/35] refactoring refspecs Brandon Williams
                   ` (21 preceding siblings ...)
  2018-05-14 21:56 ` [PATCH 22/35] remote: convert get_stale_heads " Brandon Williams
@ 2018-05-14 21:56 ` Brandon Williams
  2018-05-14 21:56 ` [PATCH 24/35] remote: convert query_refspecs " Brandon Williams
                   ` (15 subsequent siblings)
  38 siblings, 0 replies; 112+ messages in thread
From: Brandon Williams @ 2018-05-14 21:56 UTC (permalink / raw)
  To: git, bmwill; +Cc: Brandon Williams

Convert 'apply_refspecs()' to take a 'struct refspec' as a parameter instead
of a list of 'struct refspec_item'.

Signed-off-by: Brandon Williams <bmwill@google.com>
---
 builtin/fast-export.c |  2 +-
 remote.c              | 15 ++++++---------
 remote.h              |  3 +--
 transport-helper.c    |  6 +++---
 4 files changed, 11 insertions(+), 15 deletions(-)

diff --git a/builtin/fast-export.c b/builtin/fast-export.c
index 143999738..41fe49e4d 100644
--- a/builtin/fast-export.c
+++ b/builtin/fast-export.c
@@ -831,7 +831,7 @@ static void get_tags_and_duplicates(struct rev_cmdline_info *info)
 
 		if (refspecs.nr) {
 			char *private;
-			private = apply_refspecs(refspecs.items, refspecs.nr, full_name);
+			private = apply_refspecs(&refspecs, full_name);
 			if (private) {
 				free(full_name);
 				full_name = private;
diff --git a/remote.c b/remote.c
index f2e97c545..54297de3d 100644
--- a/remote.c
+++ b/remote.c
@@ -534,8 +534,7 @@ const char *remote_ref_for_branch(struct branch *branch, int for_push,
 			struct remote *remote = remote_get(remote_name);
 
 			if (remote && remote->push.nr &&
-			    (dst = apply_refspecs(remote->push.items,
-						  remote->push.nr,
+			    (dst = apply_refspecs(&remote->push,
 						  branch->refname))) {
 				if (explicit)
 					*explicit = 1;
@@ -766,15 +765,14 @@ int query_refspecs(struct refspec_item *refs, int ref_count, struct refspec_item
 	return -1;
 }
 
-char *apply_refspecs(struct refspec_item *refspecs, int nr_refspec,
-		     const char *name)
+char *apply_refspecs(struct refspec *rs, const char *name)
 {
 	struct refspec_item query;
 
 	memset(&query, 0, sizeof(struct refspec_item));
 	query.src = (char *)name;
 
-	if (query_refspecs(refspecs, nr_refspec, &query))
+	if (query_refspecs(rs->items, rs->nr, &query))
 		return NULL;
 
 	return query.dst;
@@ -1580,7 +1578,7 @@ static const char *tracking_for_push_dest(struct remote *remote,
 {
 	char *ret;
 
-	ret = apply_refspecs(remote->fetch.items, remote->fetch.nr, refname);
+	ret = apply_refspecs(&remote->fetch, refname);
 	if (!ret)
 		return error_buf(err,
 				 _("push destination '%s' on remote '%s' has no local tracking branch"),
@@ -1602,8 +1600,7 @@ static const char *branch_get_push_1(struct branch *branch, struct strbuf *err)
 		char *dst;
 		const char *ret;
 
-		dst = apply_refspecs(remote->push.items, remote->push.nr,
-				     branch->refname);
+		dst = apply_refspecs(&remote->push, branch->refname);
 		if (!dst)
 			return error_buf(err,
 					 _("push refspecs for '%s' do not include '%s'"),
@@ -2212,7 +2209,7 @@ static int remote_tracking(struct remote *remote, const char *refname,
 {
 	char *dst;
 
-	dst = apply_refspecs(remote->fetch.items, remote->fetch.nr, refname);
+	dst = apply_refspecs(&remote->fetch, refname);
 	if (!dst)
 		return -1; /* no tracking ref for refname at remote */
 	if (read_ref(dst, oid))
diff --git a/remote.h b/remote.h
index 5ac7536f5..4e7590b55 100644
--- a/remote.h
+++ b/remote.h
@@ -159,8 +159,7 @@ int ref_newer(const struct object_id *new_oid, const struct object_id *old_oid);
 struct ref *ref_remove_duplicates(struct ref *ref_map);
 
 extern int query_refspecs(struct refspec_item *specs, int nr, struct refspec_item *query);
-char *apply_refspecs(struct refspec_item *refspecs, int nr_refspec,
-		     const char *name);
+char *apply_refspecs(struct refspec *rs, const char *name);
 
 int check_push_refs(struct ref *src, int nr_refspec, const char **refspec);
 int match_push_refs(struct ref *src, struct ref **dst,
diff --git a/transport-helper.c b/transport-helper.c
index 33f51ebfc..1f8ff7e94 100644
--- a/transport-helper.c
+++ b/transport-helper.c
@@ -523,7 +523,7 @@ static int fetch_with_import(struct transport *transport,
 			continue;
 		name = posn->symref ? posn->symref : posn->name;
 		if (data->rs.nr)
-			private = apply_refspecs(data->rs.items, data->rs.nr, name);
+			private = apply_refspecs(&data->rs, name);
 		else
 			private = xstrdup(name);
 		if (private) {
@@ -805,7 +805,7 @@ static int push_update_refs_status(struct helper_data *data,
 			continue;
 
 		/* propagate back the update to the remote namespace */
-		private = apply_refspecs(data->rs.items, data->rs.nr, ref->name);
+		private = apply_refspecs(&data->rs, ref->name);
 		if (!private)
 			continue;
 		update_ref("update by helper", private, &ref->new_oid, NULL,
@@ -942,7 +942,7 @@ static int push_refs_with_export(struct transport *transport,
 		char *private;
 		struct object_id oid;
 
-		private = apply_refspecs(data->rs.items, data->rs.nr, ref->name);
+		private = apply_refspecs(&data->rs, ref->name);
 		if (private && !get_oid(private, &oid)) {
 			strbuf_addf(&buf, "^%s", private);
 			string_list_append_nodup(&revlist_args,
-- 
2.17.0.441.gb46fe60e1d-goog


^ permalink raw reply related	[flat|nested] 112+ messages in thread

* [PATCH 24/35] remote: convert query_refspecs to take a struct refspec
  2018-05-14 21:55 [PATCH 00/35] refactoring refspecs Brandon Williams
                   ` (22 preceding siblings ...)
  2018-05-14 21:56 ` [PATCH 23/35] remote: convert apply_refspecs " Brandon Williams
@ 2018-05-14 21:56 ` Brandon Williams
  2018-05-14 21:56 ` [PATCH 25/35] remote: convert get_ref_match " Brandon Williams
                   ` (14 subsequent siblings)
  38 siblings, 0 replies; 112+ messages in thread
From: Brandon Williams @ 2018-05-14 21:56 UTC (permalink / raw)
  To: git, bmwill; +Cc: Brandon Williams

Convert 'query_refspecs()' to take a 'struct refspec' as a parameter instead
of a list of 'struct refspec_item'.

Signed-off-by: Brandon Williams <bmwill@google.com>
---
 builtin/push.c |  3 +--
 remote.c       | 10 +++++-----
 remote.h       |  2 +-
 3 files changed, 7 insertions(+), 8 deletions(-)

diff --git a/builtin/push.c b/builtin/push.c
index 509dc6677..6b7e45890 100644
--- a/builtin/push.c
+++ b/builtin/push.c
@@ -83,8 +83,7 @@ static const char *map_refspec(const char *ref,
 		struct refspec_item query;
 		memset(&query, 0, sizeof(struct refspec_item));
 		query.src = matched->name;
-		if (!query_refspecs(remote->push.items, remote->push.nr, &query) &&
-		    query.dst) {
+		if (!query_refspecs(&remote->push, &query) && query.dst) {
 			struct strbuf buf = STRBUF_INIT;
 			strbuf_addf(&buf, "%s%s:%s",
 				    query.force ? "+" : "",
diff --git a/remote.c b/remote.c
index 54297de3d..3d7bc7504 100644
--- a/remote.c
+++ b/remote.c
@@ -734,7 +734,7 @@ static void query_refspecs_multiple(struct refspec *rs,
 	}
 }
 
-int query_refspecs(struct refspec_item *refs, int ref_count, struct refspec_item *query)
+int query_refspecs(struct refspec *rs, struct refspec_item *query)
 {
 	int i;
 	int find_src = !query->src;
@@ -744,8 +744,8 @@ int query_refspecs(struct refspec_item *refs, int ref_count, struct refspec_item
 	if (find_src && !query->dst)
 		return error("query_refspecs: need either src or dst");
 
-	for (i = 0; i < ref_count; i++) {
-		struct refspec_item *refspec = &refs[i];
+	for (i = 0; i < rs->nr; i++) {
+		struct refspec_item *refspec = &rs->items[i];
 		const char *key = find_src ? refspec->dst : refspec->src;
 		const char *value = find_src ? refspec->src : refspec->dst;
 
@@ -772,7 +772,7 @@ char *apply_refspecs(struct refspec *rs, const char *name)
 	memset(&query, 0, sizeof(struct refspec_item));
 	query.src = (char *)name;
 
-	if (query_refspecs(rs->items, rs->nr, &query))
+	if (query_refspecs(rs, &query))
 		return NULL;
 
 	return query.dst;
@@ -780,7 +780,7 @@ char *apply_refspecs(struct refspec *rs, const char *name)
 
 int remote_find_tracking(struct remote *remote, struct refspec_item *refspec)
 {
-	return query_refspecs(remote->fetch.items, remote->fetch.nr, refspec);
+	return query_refspecs(&remote->fetch, refspec);
 }
 
 static struct ref *alloc_ref_with_prefix(const char *prefix, size_t prefixlen,
diff --git a/remote.h b/remote.h
index 4e7590b55..edcfc3600 100644
--- a/remote.h
+++ b/remote.h
@@ -158,7 +158,7 @@ int ref_newer(const struct object_id *new_oid, const struct object_id *old_oid);
  */
 struct ref *ref_remove_duplicates(struct ref *ref_map);
 
-extern int query_refspecs(struct refspec_item *specs, int nr, struct refspec_item *query);
+int query_refspecs(struct refspec *rs, struct refspec_item *query);
 char *apply_refspecs(struct refspec *rs, const char *name);
 
 int check_push_refs(struct ref *src, int nr_refspec, const char **refspec);
-- 
2.17.0.441.gb46fe60e1d-goog


^ permalink raw reply related	[flat|nested] 112+ messages in thread

* [PATCH 25/35] remote: convert get_ref_match to take a struct refspec
  2018-05-14 21:55 [PATCH 00/35] refactoring refspecs Brandon Williams
                   ` (23 preceding siblings ...)
  2018-05-14 21:56 ` [PATCH 24/35] remote: convert query_refspecs " Brandon Williams
@ 2018-05-14 21:56 ` Brandon Williams
  2018-05-14 21:56 ` [PATCH 26/35] remote: convert match_explicit_refs " Brandon Williams
                   ` (13 subsequent siblings)
  38 siblings, 0 replies; 112+ messages in thread
From: Brandon Williams @ 2018-05-14 21:56 UTC (permalink / raw)
  To: git, bmwill; +Cc: Brandon Williams

Convert 'get_ref_match()' to take a 'struct refspec' as a parameter
instead of a list of 'struct refspec_item'.

Signed-off-by: Brandon Williams <bmwill@google.com>
---
 remote.c | 26 ++++++++++++++------------
 1 file changed, 14 insertions(+), 12 deletions(-)

diff --git a/remote.c b/remote.c
index 3d7bc7504..0879ee587 100644
--- a/remote.c
+++ b/remote.c
@@ -1091,27 +1091,29 @@ static int match_explicit_refs(struct ref *src, struct ref *dst,
 	return errs;
 }
 
-static char *get_ref_match(const struct refspec_item *rs, int rs_nr, const struct ref *ref,
-		int send_mirror, int direction, const struct refspec_item **ret_pat)
+static char *get_ref_match(const struct refspec *rs, const struct ref *ref,
+			   int send_mirror, int direction,
+			   const struct refspec_item **ret_pat)
 {
 	const struct refspec_item *pat;
 	char *name;
 	int i;
 	int matching_refs = -1;
-	for (i = 0; i < rs_nr; i++) {
-		if (rs[i].matching &&
-		    (matching_refs == -1 || rs[i].force)) {
+	for (i = 0; i < rs->nr; i++) {
+		const struct refspec_item *item = &rs->items[i];
+		if (item->matching &&
+		    (matching_refs == -1 || item->force)) {
 			matching_refs = i;
 			continue;
 		}
 
-		if (rs[i].pattern) {
-			const char *dst_side = rs[i].dst ? rs[i].dst : rs[i].src;
+		if (item->pattern) {
+			const char *dst_side = item->dst ? item->dst : item->src;
 			int match;
 			if (direction == FROM_SRC)
-				match = match_name_with_pattern(rs[i].src, ref->name, dst_side, &name);
+				match = match_name_with_pattern(item->src, ref->name, dst_side, &name);
 			else
-				match = match_name_with_pattern(dst_side, ref->name, rs[i].src, &name);
+				match = match_name_with_pattern(dst_side, ref->name, item->src, &name);
 			if (match) {
 				matching_refs = i;
 				break;
@@ -1121,7 +1123,7 @@ static char *get_ref_match(const struct refspec_item *rs, int rs_nr, const struc
 	if (matching_refs == -1)
 		return NULL;
 
-	pat = rs + matching_refs;
+	pat = &rs->items[matching_refs];
 	if (pat->matching) {
 		/*
 		 * "matching refs"; traditionally we pushed everything
@@ -1318,7 +1320,7 @@ int match_push_refs(struct ref *src, struct ref **dst,
 		const struct refspec_item *pat = NULL;
 		char *dst_name;
 
-		dst_name = get_ref_match(rs.items, rs.nr, ref, send_mirror, FROM_SRC, &pat);
+		dst_name = get_ref_match(&rs, ref, send_mirror, FROM_SRC, &pat);
 		if (!dst_name)
 			continue;
 
@@ -1367,7 +1369,7 @@ int match_push_refs(struct ref *src, struct ref **dst,
 				/* We're already sending something to this ref. */
 				continue;
 
-			src_name = get_ref_match(rs.items, rs.nr, ref, send_mirror, FROM_DST, NULL);
+			src_name = get_ref_match(&rs, ref, send_mirror, FROM_DST, NULL);
 			if (src_name) {
 				if (!src_ref_index.nr)
 					prepare_ref_index(&src_ref_index, src);
-- 
2.17.0.441.gb46fe60e1d-goog


^ permalink raw reply related	[flat|nested] 112+ messages in thread

* [PATCH 26/35] remote: convert match_explicit_refs to take a struct refspec
  2018-05-14 21:55 [PATCH 00/35] refactoring refspecs Brandon Williams
                   ` (24 preceding siblings ...)
  2018-05-14 21:56 ` [PATCH 25/35] remote: convert get_ref_match " Brandon Williams
@ 2018-05-14 21:56 ` Brandon Williams
  2018-05-14 21:56 ` [PATCH 27/35] push: check for errors earlier Brandon Williams
                   ` (12 subsequent siblings)
  38 siblings, 0 replies; 112+ messages in thread
From: Brandon Williams @ 2018-05-14 21:56 UTC (permalink / raw)
  To: git, bmwill; +Cc: Brandon Williams

Convert 'match_explicit_refs()' to take a 'struct refspec' as a
parameter instead of a list of 'struct refspec_item'.

Signed-off-by: Brandon Williams <bmwill@google.com>
---
 remote.c | 9 ++++-----
 1 file changed, 4 insertions(+), 5 deletions(-)

diff --git a/remote.c b/remote.c
index 0879ee587..73d462f24 100644
--- a/remote.c
+++ b/remote.c
@@ -1082,12 +1082,11 @@ static int match_explicit(struct ref *src, struct ref *dst,
 }
 
 static int match_explicit_refs(struct ref *src, struct ref *dst,
-			       struct ref ***dst_tail, struct refspec_item *rs,
-			       int rs_nr)
+			       struct ref ***dst_tail, struct refspec *rs)
 {
 	int i, errs;
-	for (i = errs = 0; i < rs_nr; i++)
-		errs += match_explicit(src, dst, dst_tail, &rs[i]);
+	for (i = errs = 0; i < rs->nr; i++)
+		errs += match_explicit(src, dst, dst_tail, &rs->items[i]);
 	return errs;
 }
 
@@ -1311,7 +1310,7 @@ int match_push_refs(struct ref *src, struct ref **dst,
 		refspec = default_refspec;
 	}
 	refspec_appendn(&rs, refspec, nr_refspec);
-	errs = match_explicit_refs(src, *dst, &dst_tail, rs.items, rs.nr);
+	errs = match_explicit_refs(src, *dst, &dst_tail, &rs);
 
 	/* pick the remainder */
 	for (ref = src; ref; ref = ref->next) {
-- 
2.17.0.441.gb46fe60e1d-goog


^ permalink raw reply related	[flat|nested] 112+ messages in thread

* [PATCH 27/35] push: check for errors earlier
  2018-05-14 21:55 [PATCH 00/35] refactoring refspecs Brandon Williams
                   ` (25 preceding siblings ...)
  2018-05-14 21:56 ` [PATCH 26/35] remote: convert match_explicit_refs " Brandon Williams
@ 2018-05-14 21:56 ` Brandon Williams
  2018-05-14 21:56 ` [PATCH 28/35] push: convert to use struct refspec Brandon Williams
                   ` (11 subsequent siblings)
  38 siblings, 0 replies; 112+ messages in thread
From: Brandon Williams @ 2018-05-14 21:56 UTC (permalink / raw)
  To: git, bmwill; +Cc: Brandon Williams

Move the error checking for using the "--mirror", "--all", and "--tags"
options earlier and explicitly check for the presence of the flags
instead of checking for a side-effect of the flag.

Signed-off-by: Brandon Williams <bmwill@google.com>
---
 builtin/push.c | 31 ++++++++++++++-----------------
 1 file changed, 14 insertions(+), 17 deletions(-)

diff --git a/builtin/push.c b/builtin/push.c
index 6b7e45890..df5df6c0d 100644
--- a/builtin/push.c
+++ b/builtin/push.c
@@ -417,23 +417,6 @@ static int do_push(const char *repo, int flags,
 	if (push_options->nr)
 		flags |= TRANSPORT_PUSH_OPTIONS;
 
-	if ((flags & TRANSPORT_PUSH_ALL) && refspec) {
-		if (!strcmp(*refspec, "refs/tags/*"))
-			return error(_("--all and --tags are incompatible"));
-		return error(_("--all can't be combined with refspecs"));
-	}
-
-	if ((flags & TRANSPORT_PUSH_MIRROR) && refspec) {
-		if (!strcmp(*refspec, "refs/tags/*"))
-			return error(_("--mirror and --tags are incompatible"));
-		return error(_("--mirror can't be combined with refspecs"));
-	}
-
-	if ((flags & (TRANSPORT_PUSH_ALL|TRANSPORT_PUSH_MIRROR)) ==
-				(TRANSPORT_PUSH_ALL|TRANSPORT_PUSH_MIRROR)) {
-		return error(_("--all and --mirror are incompatible"));
-	}
-
 	if (!refspec && !(flags & TRANSPORT_PUSH_ALL)) {
 		if (remote->push.raw_nr) {
 			refspec = remote->push.raw;
@@ -625,6 +608,20 @@ int cmd_push(int argc, const char **argv, const char *prefix)
 		die(_("--delete is incompatible with --all, --mirror and --tags"));
 	if (deleterefs && argc < 2)
 		die(_("--delete doesn't make sense without any refs"));
+	if (flags & TRANSPORT_PUSH_ALL) {
+		if (tags)
+			die(_("--all and --tags are incompatible"));
+		if (argc >= 2)
+			die(_("--all can't be combined with refspecs"));
+	}
+	if (flags & TRANSPORT_PUSH_MIRROR) {
+		if (tags)
+			die(_("--mirror and --tags are incompatible"));
+		if (argc >= 2)
+			die(_("--mirror can't be combined with refspecs"));
+	}
+	if ((flags & TRANSPORT_PUSH_ALL) && (flags & TRANSPORT_PUSH_MIRROR))
+		die(_("--all and --mirror are incompatible"));
 
 	if (recurse_submodules == RECURSE_SUBMODULES_CHECK)
 		flags |= TRANSPORT_RECURSE_SUBMODULES_CHECK;
-- 
2.17.0.441.gb46fe60e1d-goog


^ permalink raw reply related	[flat|nested] 112+ messages in thread

* [PATCH 28/35] push: convert to use struct refspec
  2018-05-14 21:55 [PATCH 00/35] refactoring refspecs Brandon Williams
                   ` (26 preceding siblings ...)
  2018-05-14 21:56 ` [PATCH 27/35] push: check for errors earlier Brandon Williams
@ 2018-05-14 21:56 ` Brandon Williams
  2018-05-14 21:56 ` [PATCH 29/35] transport: convert transport_push to take a " Brandon Williams
                   ` (10 subsequent siblings)
  38 siblings, 0 replies; 112+ messages in thread
From: Brandon Williams @ 2018-05-14 21:56 UTC (permalink / raw)
  To: git, bmwill; +Cc: Brandon Williams

Convert the refspecs in builtin/push.c to be stored in a 'struct
refspec' instead of being stored in a list of 'struct refspec_item's.

Signed-off-by: Brandon Williams <bmwill@google.com>
---
 builtin/push.c | 38 +++++++++++++++-----------------------
 1 file changed, 15 insertions(+), 23 deletions(-)

diff --git a/builtin/push.c b/builtin/push.c
index df5df6c0d..ef42979d1 100644
--- a/builtin/push.c
+++ b/builtin/push.c
@@ -57,19 +57,10 @@ static enum transport_family family;
 
 static struct push_cas_option cas;
 
-static const char **refspec;
-static int refspec_nr;
-static int refspec_alloc;
+static struct refspec rs = REFSPEC_INIT_PUSH;
 
 static struct string_list push_options_config = STRING_LIST_INIT_DUP;
 
-static void add_refspec(const char *ref)
-{
-	refspec_nr++;
-	ALLOC_GROW(refspec, refspec_nr, refspec_alloc);
-	refspec[refspec_nr-1] = ref;
-}
-
 static const char *map_refspec(const char *ref,
 			       struct remote *remote, struct ref *local_refs)
 {
@@ -138,7 +129,7 @@ static void set_refspecs(const char **refs, int nr, const char *repo)
 			}
 			ref = map_refspec(ref, remote, local_refs);
 		}
-		add_refspec(ref);
+		refspec_append(&rs, ref);
 	}
 }
 
@@ -226,7 +217,7 @@ static void setup_push_upstream(struct remote *remote, struct branch *branch,
 	}
 
 	strbuf_addf(&refspec, "%s:%s", branch->refname, branch->merge[0]->src);
-	add_refspec(refspec.buf);
+	refspec_append(&rs, refspec.buf);
 }
 
 static void setup_push_current(struct remote *remote, struct branch *branch)
@@ -236,7 +227,7 @@ static void setup_push_current(struct remote *remote, struct branch *branch)
 	if (!branch)
 		die(_(message_detached_head_die), remote->name);
 	strbuf_addf(&refspec, "%s:%s", branch->refname, branch->refname);
-	add_refspec(refspec.buf);
+	refspec_append(&rs, refspec.buf);
 }
 
 static int is_workflow_triangular(struct remote *remote)
@@ -253,7 +244,7 @@ static void setup_default_push_refspecs(struct remote *remote)
 	switch (push_default) {
 	default:
 	case PUSH_DEFAULT_MATCHING:
-		add_refspec(":");
+		refspec_append(&rs, ":");
 		break;
 
 	case PUSH_DEFAULT_UNSPECIFIED:
@@ -341,7 +332,8 @@ static void advise_ref_needs_force(void)
 	advise(_(message_advice_ref_needs_force));
 }
 
-static int push_with_options(struct transport *transport, int flags)
+static int push_with_options(struct transport *transport, struct refspec *rs,
+			     int flags)
 {
 	int err;
 	unsigned int reject_reasons;
@@ -363,7 +355,7 @@ static int push_with_options(struct transport *transport, int flags)
 
 	if (verbosity > 0)
 		fprintf(stderr, _("Pushing to %s\n"), transport->url);
-	err = transport_push(transport, refspec_nr, refspec, flags,
+	err = transport_push(transport, rs->raw_nr, rs->raw, flags,
 			     &reject_reasons);
 	if (err != 0) {
 		fprintf(stderr, "%s", push_get_color(PUSH_COLOR_ERROR));
@@ -397,6 +389,7 @@ static int do_push(const char *repo, int flags,
 	struct remote *remote = pushremote_get(repo);
 	const char **url;
 	int url_nr;
+	struct refspec *push_refspec = &rs;
 
 	if (!remote) {
 		if (repo)
@@ -417,10 +410,9 @@ static int do_push(const char *repo, int flags,
 	if (push_options->nr)
 		flags |= TRANSPORT_PUSH_OPTIONS;
 
-	if (!refspec && !(flags & TRANSPORT_PUSH_ALL)) {
-		if (remote->push.raw_nr) {
-			refspec = remote->push.raw;
-			refspec_nr = remote->push.raw_nr;
+	if (!push_refspec->nr && !(flags & TRANSPORT_PUSH_ALL)) {
+		if (remote->push.nr) {
+			push_refspec = &remote->push;
 		} else if (!(flags & TRANSPORT_PUSH_MIRROR))
 			setup_default_push_refspecs(remote);
 	}
@@ -432,7 +424,7 @@ static int do_push(const char *repo, int flags,
 				transport_get(remote, url[i]);
 			if (flags & TRANSPORT_PUSH_OPTIONS)
 				transport->push_options = push_options;
-			if (push_with_options(transport, flags))
+			if (push_with_options(transport, push_refspec, flags))
 				errs++;
 		}
 	} else {
@@ -440,7 +432,7 @@ static int do_push(const char *repo, int flags,
 			transport_get(remote, NULL);
 		if (flags & TRANSPORT_PUSH_OPTIONS)
 			transport->push_options = push_options;
-		if (push_with_options(transport, flags))
+		if (push_with_options(transport, push_refspec, flags))
 			errs++;
 	}
 	return !!errs;
@@ -631,7 +623,7 @@ int cmd_push(int argc, const char **argv, const char *prefix)
 		flags |= TRANSPORT_RECURSE_SUBMODULES_ONLY;
 
 	if (tags)
-		add_refspec("refs/tags/*");
+		refspec_append(&rs, "refs/tags/*");
 
 	if (argc > 0) {
 		repo = argv[0];
-- 
2.17.0.441.gb46fe60e1d-goog


^ permalink raw reply related	[flat|nested] 112+ messages in thread

* [PATCH 29/35] transport: convert transport_push to take a struct refspec
  2018-05-14 21:55 [PATCH 00/35] refactoring refspecs Brandon Williams
                   ` (27 preceding siblings ...)
  2018-05-14 21:56 ` [PATCH 28/35] push: convert to use struct refspec Brandon Williams
@ 2018-05-14 21:56 ` Brandon Williams
  2018-05-14 21:56 ` [PATCH 30/35] send-pack: store refspecs in " Brandon Williams
                   ` (9 subsequent siblings)
  38 siblings, 0 replies; 112+ messages in thread
From: Brandon Williams @ 2018-05-14 21:56 UTC (permalink / raw)
  To: git, bmwill; +Cc: Brandon Williams

Convert 'transport_push()' to take a 'struct refspec' as a
parameter instead of an array of strings which represent
refspecs.

Signed-off-by: Brandon Williams <bmwill@google.com>
---
 builtin/push.c |  3 +--
 transport.c    | 17 +++++++----------
 transport.h    |  2 +-
 3 files changed, 9 insertions(+), 13 deletions(-)

diff --git a/builtin/push.c b/builtin/push.c
index ef42979d1..9cd8e8cd5 100644
--- a/builtin/push.c
+++ b/builtin/push.c
@@ -355,8 +355,7 @@ static int push_with_options(struct transport *transport, struct refspec *rs,
 
 	if (verbosity > 0)
 		fprintf(stderr, _("Pushing to %s\n"), transport->url);
-	err = transport_push(transport, rs->raw_nr, rs->raw, flags,
-			     &reject_reasons);
+	err = transport_push(transport, rs, flags, &reject_reasons);
 	if (err != 0) {
 		fprintf(stderr, "%s", push_get_color(PUSH_COLOR_ERROR));
 		error(_("failed to push some refs to '%s'"), transport->url);
diff --git a/transport.c b/transport.c
index 181db4d4d..a89f17744 100644
--- a/transport.c
+++ b/transport.c
@@ -1093,11 +1093,11 @@ static int run_pre_push_hook(struct transport *transport,
 }
 
 int transport_push(struct transport *transport,
-		   int refspec_nr, const char **refspec, int flags,
+		   struct refspec *rs, int flags,
 		   unsigned int *reject_reasons)
 {
 	*reject_reasons = 0;
-	transport_verify_remote_names(refspec_nr, refspec);
+	transport_verify_remote_names(rs->raw_nr, rs->raw);
 
 	if (transport_color_config() < 0)
 		return -1;
@@ -1111,16 +1111,14 @@ int transport_push(struct transport *transport,
 		int porcelain = flags & TRANSPORT_PUSH_PORCELAIN;
 		int pretend = flags & TRANSPORT_PUSH_DRY_RUN;
 		int push_ret, ret, err;
-		struct refspec tmp_rs = REFSPEC_INIT_PUSH;
 		struct argv_array ref_prefixes = ARGV_ARRAY_INIT;
 		int i;
 
-		if (check_push_refs(local_refs, refspec_nr, refspec) < 0)
+		if (check_push_refs(local_refs, rs->raw_nr, rs->raw) < 0)
 			return -1;
 
-		refspec_appendn(&tmp_rs, refspec, refspec_nr);
-		for (i = 0; i < tmp_rs.nr; i++) {
-			const struct refspec_item *item = &tmp_rs.items[i];
+		for (i = 0; i < rs->nr; i++) {
+			const struct refspec_item *item = &rs->items[i];
 			const char *prefix = NULL;
 
 			if (item->dst)
@@ -1143,7 +1141,6 @@ int transport_push(struct transport *transport,
 							       &ref_prefixes);
 
 		argv_array_clear(&ref_prefixes);
-		refspec_clear(&tmp_rs);
 
 		if (flags & TRANSPORT_PUSH_ALL)
 			match_flags |= MATCH_REFS_ALL;
@@ -1155,7 +1152,7 @@ int transport_push(struct transport *transport,
 			match_flags |= MATCH_REFS_FOLLOW_TAGS;
 
 		if (match_push_refs(local_refs, &remote_refs,
-				    refspec_nr, refspec, match_flags)) {
+				    rs->raw_nr, rs->raw, match_flags)) {
 			return -1;
 		}
 
@@ -1186,7 +1183,7 @@ int transport_push(struct transport *transport,
 
 			if (!push_unpushed_submodules(&commits,
 						      transport->remote,
-						      refspec, refspec_nr,
+						      rs->raw, rs->raw_nr,
 						      transport->push_options,
 						      pretend)) {
 				oid_array_clear(&commits);
diff --git a/transport.h b/transport.h
index e783cfa07..e2c809af4 100644
--- a/transport.h
+++ b/transport.h
@@ -197,7 +197,7 @@ void transport_set_verbosity(struct transport *transport, int verbosity,
 #define REJECT_NEEDS_FORCE     0x10
 
 int transport_push(struct transport *connection,
-		   int refspec_nr, const char **refspec, int flags,
+		   struct refspec *rs, int flags,
 		   unsigned int * reject_reasons);
 
 /*
-- 
2.17.0.441.gb46fe60e1d-goog


^ permalink raw reply related	[flat|nested] 112+ messages in thread

* [PATCH 30/35] send-pack: store refspecs in a struct refspec
  2018-05-14 21:55 [PATCH 00/35] refactoring refspecs Brandon Williams
                   ` (28 preceding siblings ...)
  2018-05-14 21:56 ` [PATCH 29/35] transport: convert transport_push to take a " Brandon Williams
@ 2018-05-14 21:56 ` Brandon Williams
  2018-05-14 21:56 ` [PATCH 31/35] transport: remove transport_verify_remote_names Brandon Williams
                   ` (8 subsequent siblings)
  38 siblings, 0 replies; 112+ messages in thread
From: Brandon Williams @ 2018-05-14 21:56 UTC (permalink / raw)
  To: git, bmwill; +Cc: Brandon Williams

Convert send-pack.c to store refspecs in a 'struct refspec' instead of
as an array of 'const char *'.

Signed-off-by: Brandon Williams <bmwill@google.com>
---
 builtin/send-pack.c | 24 +++++++-----------------
 1 file changed, 7 insertions(+), 17 deletions(-)

diff --git a/builtin/send-pack.c b/builtin/send-pack.c
index b5427f75e..ef512616f 100644
--- a/builtin/send-pack.c
+++ b/builtin/send-pack.c
@@ -126,8 +126,7 @@ static int send_pack_config(const char *k, const char *v, void *cb)
 
 int cmd_send_pack(int argc, const char **argv, const char *prefix)
 {
-	int i, nr_refspecs = 0;
-	const char **refspecs = NULL;
+	struct refspec rs = REFSPEC_INIT_PUSH;
 	const char *remote_name = NULL;
 	struct remote *remote = NULL;
 	const char *dest = NULL;
@@ -189,8 +188,7 @@ int cmd_send_pack(int argc, const char **argv, const char *prefix)
 	argc = parse_options(argc, argv, prefix, options, send_pack_usage, 0);
 	if (argc > 0) {
 		dest = argv[0];
-		refspecs = (const char **)(argv + 1);
-		nr_refspecs = argc - 1;
+		refspec_appendn(&rs, argv + 1, argc - 1);
 	}
 
 	if (!dest)
@@ -209,31 +207,23 @@ int cmd_send_pack(int argc, const char **argv, const char *prefix)
 	args.push_options = push_options.nr ? &push_options : NULL;
 
 	if (from_stdin) {
-		struct argv_array all_refspecs = ARGV_ARRAY_INIT;
-
-		for (i = 0; i < nr_refspecs; i++)
-			argv_array_push(&all_refspecs, refspecs[i]);
-
 		if (args.stateless_rpc) {
 			const char *buf;
 			while ((buf = packet_read_line(0, NULL)))
-				argv_array_push(&all_refspecs, buf);
+				refspec_append(&rs, buf);
 		} else {
 			struct strbuf line = STRBUF_INIT;
 			while (strbuf_getline(&line, stdin) != EOF)
-				argv_array_push(&all_refspecs, line.buf);
+				refspec_append(&rs, line.buf);
 			strbuf_release(&line);
 		}
-
-		refspecs = all_refspecs.argv;
-		nr_refspecs = all_refspecs.argc;
 	}
 
 	/*
 	 * --all and --mirror are incompatible; neither makes sense
 	 * with any refspecs.
 	 */
-	if ((nr_refspecs > 0 && (send_all || args.send_mirror)) ||
+	if ((rs.nr > 0 && (send_all || args.send_mirror)) ||
 	    (send_all && args.send_mirror))
 		usage_with_options(send_pack_usage, options);
 
@@ -275,7 +265,7 @@ int cmd_send_pack(int argc, const char **argv, const char *prefix)
 		BUG("unknown protocol version");
 	}
 
-	transport_verify_remote_names(nr_refspecs, refspecs);
+	transport_verify_remote_names(rs.raw_nr, rs.raw);
 
 	local_refs = get_local_heads();
 
@@ -287,7 +277,7 @@ int cmd_send_pack(int argc, const char **argv, const char *prefix)
 		flags |= MATCH_REFS_MIRROR;
 
 	/* match them up */
-	if (match_push_refs(local_refs, &remote_refs, nr_refspecs, refspecs, flags))
+	if (match_push_refs(local_refs, &remote_refs, rs.raw_nr, rs.raw, flags))
 		return -1;
 
 	if (!is_empty_cas(&cas))
-- 
2.17.0.441.gb46fe60e1d-goog


^ permalink raw reply related	[flat|nested] 112+ messages in thread

* [PATCH 31/35] transport: remove transport_verify_remote_names
  2018-05-14 21:55 [PATCH 00/35] refactoring refspecs Brandon Williams
                   ` (29 preceding siblings ...)
  2018-05-14 21:56 ` [PATCH 30/35] send-pack: store refspecs in " Brandon Williams
@ 2018-05-14 21:56 ` Brandon Williams
  2018-05-14 21:56 ` [PATCH 32/35] http-push: store refspecs in a struct refspec Brandon Williams
                   ` (7 subsequent siblings)
  38 siblings, 0 replies; 112+ messages in thread
From: Brandon Williams @ 2018-05-14 21:56 UTC (permalink / raw)
  To: git, bmwill; +Cc: Brandon Williams

Remove 'transprot_verify_remote_names()' because all callers have
migrated to using 'struct refspec' which performs the same checks in
'parse_refspec()'.

Signed-off-by: Brandon Williams <bmwill@google.com>
---
 builtin/send-pack.c |  2 --
 transport.c         | 24 ------------------------
 transport.h         |  2 --
 3 files changed, 28 deletions(-)

diff --git a/builtin/send-pack.c b/builtin/send-pack.c
index ef512616f..7c34bf467 100644
--- a/builtin/send-pack.c
+++ b/builtin/send-pack.c
@@ -265,8 +265,6 @@ int cmd_send_pack(int argc, const char **argv, const char *prefix)
 		BUG("unknown protocol version");
 	}
 
-	transport_verify_remote_names(rs.raw_nr, rs.raw);
-
 	local_refs = get_local_heads();
 
 	flags = MATCH_REFS_NONE;
diff --git a/transport.c b/transport.c
index a89f17744..fe96c0b80 100644
--- a/transport.c
+++ b/transport.c
@@ -619,29 +619,6 @@ void transport_print_push_status(const char *dest, struct ref *refs,
 	free(head);
 }
 
-void transport_verify_remote_names(int nr_heads, const char **heads)
-{
-	int i;
-
-	for (i = 0; i < nr_heads; i++) {
-		const char *local = heads[i];
-		const char *remote = strrchr(heads[i], ':');
-
-		if (*local == '+')
-			local++;
-
-		/* A matching refspec is okay.  */
-		if (remote == local && remote[1] == '\0')
-			continue;
-
-		remote = remote ? (remote + 1) : local;
-		if (check_refname_format(remote,
-				REFNAME_ALLOW_ONELEVEL|REFNAME_REFSPEC_PATTERN))
-			die("remote part of refspec is not a valid name in %s",
-				heads[i]);
-	}
-}
-
 static int git_transport_push(struct transport *transport, struct ref *remote_refs, int flags)
 {
 	struct git_transport_data *data = transport->data;
@@ -1097,7 +1074,6 @@ int transport_push(struct transport *transport,
 		   unsigned int *reject_reasons)
 {
 	*reject_reasons = 0;
-	transport_verify_remote_names(rs->raw_nr, rs->raw);
 
 	if (transport_color_config() < 0)
 		return -1;
diff --git a/transport.h b/transport.h
index e2c809af4..bac085ce0 100644
--- a/transport.h
+++ b/transport.h
@@ -227,8 +227,6 @@ int transport_helper_init(struct transport *transport, const char *name);
 int bidirectional_transfer_loop(int input, int output);
 
 /* common methods used by transport.c and builtin/send-pack.c */
-void transport_verify_remote_names(int nr_heads, const char **heads);
-
 void transport_update_tracking_ref(struct remote *remote, struct ref *ref, int verbose);
 
 int transport_refs_pushed(struct ref *ref);
-- 
2.17.0.441.gb46fe60e1d-goog


^ permalink raw reply related	[flat|nested] 112+ messages in thread

* [PATCH 32/35] http-push: store refspecs in a struct refspec
  2018-05-14 21:55 [PATCH 00/35] refactoring refspecs Brandon Williams
                   ` (30 preceding siblings ...)
  2018-05-14 21:56 ` [PATCH 31/35] transport: remove transport_verify_remote_names Brandon Williams
@ 2018-05-14 21:56 ` Brandon Williams
  2018-05-14 21:56 ` [PATCH 33/35] remote: convert match_push_refs to take " Brandon Williams
                   ` (6 subsequent siblings)
  38 siblings, 0 replies; 112+ messages in thread
From: Brandon Williams @ 2018-05-14 21:56 UTC (permalink / raw)
  To: git, bmwill; +Cc: Brandon Williams

Convert http-push.c to store refspecs in a 'struct refspec' instead of
in an array of 'const char *'.

Signed-off-by: Brandon Williams <bmwill@google.com>
---
 http-push.c | 17 ++++++++---------
 1 file changed, 8 insertions(+), 9 deletions(-)

diff --git a/http-push.c b/http-push.c
index f308ce019..a724ef03f 100644
--- a/http-push.c
+++ b/http-push.c
@@ -1692,8 +1692,7 @@ int cmd_main(int argc, const char **argv)
 {
 	struct transfer_request *request;
 	struct transfer_request *next_request;
-	int nr_refspec = 0;
-	const char **refspec = NULL;
+	struct refspec rs = REFSPEC_INIT_PUSH;
 	struct remote_lock *ref_lock = NULL;
 	struct remote_lock *info_ref_lock = NULL;
 	struct rev_info revs;
@@ -1756,8 +1755,7 @@ int cmd_main(int argc, const char **argv)
 			}
 			continue;
 		}
-		refspec = argv;
-		nr_refspec = argc - i;
+		refspec_appendn(&rs, argv, argc - i);
 		break;
 	}
 
@@ -1768,7 +1766,7 @@ int cmd_main(int argc, const char **argv)
 	if (!repo->url)
 		usage(http_push_usage);
 
-	if (delete_branch && nr_refspec != 1)
+	if (delete_branch && rs.nr != 1)
 		die("You must specify only one branch name when deleting a remote branch");
 
 	setup_git_directory();
@@ -1814,18 +1812,19 @@ int cmd_main(int argc, const char **argv)
 
 	/* Remove a remote branch if -d or -D was specified */
 	if (delete_branch) {
-		if (delete_remote_branch(refspec[0], force_delete) == -1) {
+		const char *branch = rs.items[i].src;
+		if (delete_remote_branch(branch, force_delete) == -1) {
 			fprintf(stderr, "Unable to delete remote branch %s\n",
-				refspec[0]);
+				branch);
 			if (helper_status)
-				printf("error %s cannot remove\n", refspec[0]);
+				printf("error %s cannot remove\n", branch);
 		}
 		goto cleanup;
 	}
 
 	/* match them up */
 	if (match_push_refs(local_refs, &remote_refs,
-			    nr_refspec, (const char **) refspec, push_all)) {
+			    rs.raw_nr, rs.raw, push_all)) {
 		rc = -1;
 		goto cleanup;
 	}
-- 
2.17.0.441.gb46fe60e1d-goog


^ permalink raw reply related	[flat|nested] 112+ messages in thread

* [PATCH 33/35] remote: convert match_push_refs to take a struct refspec
  2018-05-14 21:55 [PATCH 00/35] refactoring refspecs Brandon Williams
                   ` (31 preceding siblings ...)
  2018-05-14 21:56 ` [PATCH 32/35] http-push: store refspecs in a struct refspec Brandon Williams
@ 2018-05-14 21:56 ` Brandon Williams
  2018-05-14 21:56 ` [PATCH 34/35] remote: convert check_push_refs " Brandon Williams
                   ` (5 subsequent siblings)
  38 siblings, 0 replies; 112+ messages in thread
From: Brandon Williams @ 2018-05-14 21:56 UTC (permalink / raw)
  To: git, bmwill; +Cc: Brandon Williams

Convert 'match_push_refs()' to take a 'struct refspec' as a parameter
instead of an array of 'const char *'.

Signed-off-by: Brandon Williams <bmwill@google.com>
---
 builtin/remote.c    |  3 +--
 builtin/send-pack.c |  2 +-
 http-push.c         |  3 +--
 remote.c            | 21 ++++++++-------------
 remote.h            |  2 +-
 transport.c         |  4 +---
 6 files changed, 13 insertions(+), 22 deletions(-)

diff --git a/builtin/remote.c b/builtin/remote.c
index b8e66589f..b84175cc6 100644
--- a/builtin/remote.c
+++ b/builtin/remote.c
@@ -387,8 +387,7 @@ static int get_push_ref_states(const struct ref *remote_refs,
 	local_refs = get_local_heads();
 	push_map = copy_ref_list(remote_refs);
 
-	match_push_refs(local_refs, &push_map, remote->push.raw_nr,
-			remote->push.raw, MATCH_REFS_NONE);
+	match_push_refs(local_refs, &push_map, &remote->push, MATCH_REFS_NONE);
 
 	states->push.strdup_strings = 1;
 	for (ref = push_map; ref; ref = ref->next) {
diff --git a/builtin/send-pack.c b/builtin/send-pack.c
index 7c34bf467..4923b1058 100644
--- a/builtin/send-pack.c
+++ b/builtin/send-pack.c
@@ -275,7 +275,7 @@ int cmd_send_pack(int argc, const char **argv, const char *prefix)
 		flags |= MATCH_REFS_MIRROR;
 
 	/* match them up */
-	if (match_push_refs(local_refs, &remote_refs, rs.raw_nr, rs.raw, flags))
+	if (match_push_refs(local_refs, &remote_refs, &rs, flags))
 		return -1;
 
 	if (!is_empty_cas(&cas))
diff --git a/http-push.c b/http-push.c
index a724ef03f..ea5af6227 100644
--- a/http-push.c
+++ b/http-push.c
@@ -1823,8 +1823,7 @@ int cmd_main(int argc, const char **argv)
 	}
 
 	/* match them up */
-	if (match_push_refs(local_refs, &remote_refs,
-			    rs.raw_nr, rs.raw, push_all)) {
+	if (match_push_refs(local_refs, &remote_refs, &rs, push_all)) {
 		rc = -1;
 		goto cleanup;
 	}
diff --git a/remote.c b/remote.c
index 73d462f24..0e882d812 100644
--- a/remote.c
+++ b/remote.c
@@ -1294,23 +1294,20 @@ int check_push_refs(struct ref *src, int nr_refspec, const char **refspec_names)
  * dst (e.g. pushing to a new branch, done in match_explicit_refs).
  */
 int match_push_refs(struct ref *src, struct ref **dst,
-		    int nr_refspec, const char **refspec, int flags)
+		    struct refspec *rs, int flags)
 {
-	struct refspec rs = REFSPEC_INIT_PUSH;
 	int send_all = flags & MATCH_REFS_ALL;
 	int send_mirror = flags & MATCH_REFS_MIRROR;
 	int send_prune = flags & MATCH_REFS_PRUNE;
 	int errs;
-	static const char *default_refspec[] = { ":", NULL };
 	struct ref *ref, **dst_tail = tail_ref(dst);
 	struct string_list dst_ref_index = STRING_LIST_INIT_NODUP;
 
-	if (!nr_refspec) {
-		nr_refspec = 1;
-		refspec = default_refspec;
-	}
-	refspec_appendn(&rs, refspec, nr_refspec);
-	errs = match_explicit_refs(src, *dst, &dst_tail, &rs);
+	/* If no refspec is provided, use the default ":" */
+	if (!rs->nr)
+		refspec_append(rs, ":");
+
+	errs = match_explicit_refs(src, *dst, &dst_tail, rs);
 
 	/* pick the remainder */
 	for (ref = src; ref; ref = ref->next) {
@@ -1319,7 +1316,7 @@ int match_push_refs(struct ref *src, struct ref **dst,
 		const struct refspec_item *pat = NULL;
 		char *dst_name;
 
-		dst_name = get_ref_match(&rs, ref, send_mirror, FROM_SRC, &pat);
+		dst_name = get_ref_match(rs, ref, send_mirror, FROM_SRC, &pat);
 		if (!dst_name)
 			continue;
 
@@ -1368,7 +1365,7 @@ int match_push_refs(struct ref *src, struct ref **dst,
 				/* We're already sending something to this ref. */
 				continue;
 
-			src_name = get_ref_match(&rs, ref, send_mirror, FROM_DST, NULL);
+			src_name = get_ref_match(rs, ref, send_mirror, FROM_DST, NULL);
 			if (src_name) {
 				if (!src_ref_index.nr)
 					prepare_ref_index(&src_ref_index, src);
@@ -1381,8 +1378,6 @@ int match_push_refs(struct ref *src, struct ref **dst,
 		string_list_clear(&src_ref_index, 0);
 	}
 
-	refspec_clear(&rs);
-
 	if (errs)
 		return -1;
 	return 0;
diff --git a/remote.h b/remote.h
index edcfc3600..d5b5f24ac 100644
--- a/remote.h
+++ b/remote.h
@@ -163,7 +163,7 @@ char *apply_refspecs(struct refspec *rs, const char *name);
 
 int check_push_refs(struct ref *src, int nr_refspec, const char **refspec);
 int match_push_refs(struct ref *src, struct ref **dst,
-		    int nr_refspec, const char **refspec, int all);
+		    struct refspec *rs, int flags);
 void set_ref_status_for_push(struct ref *remote_refs, int send_mirror,
 	int force_update);
 
diff --git a/transport.c b/transport.c
index fe96c0b80..24a97d9e8 100644
--- a/transport.c
+++ b/transport.c
@@ -1127,10 +1127,8 @@ int transport_push(struct transport *transport,
 		if (flags & TRANSPORT_PUSH_FOLLOW_TAGS)
 			match_flags |= MATCH_REFS_FOLLOW_TAGS;
 
-		if (match_push_refs(local_refs, &remote_refs,
-				    rs->raw_nr, rs->raw, match_flags)) {
+		if (match_push_refs(local_refs, &remote_refs, rs, match_flags))
 			return -1;
-		}
 
 		if (transport->smart_options &&
 		    transport->smart_options->cas &&
-- 
2.17.0.441.gb46fe60e1d-goog


^ permalink raw reply related	[flat|nested] 112+ messages in thread

* [PATCH 34/35] remote: convert check_push_refs to take a struct refspec
  2018-05-14 21:55 [PATCH 00/35] refactoring refspecs Brandon Williams
                   ` (32 preceding siblings ...)
  2018-05-14 21:56 ` [PATCH 33/35] remote: convert match_push_refs to take " Brandon Williams
@ 2018-05-14 21:56 ` Brandon Williams
  2018-05-14 21:56 ` [PATCH 35/35] submodule: convert push_unpushed_submodules " Brandon Williams
                   ` (4 subsequent siblings)
  38 siblings, 0 replies; 112+ messages in thread
From: Brandon Williams @ 2018-05-14 21:56 UTC (permalink / raw)
  To: git, bmwill; +Cc: Brandon Williams

Convert 'check_push_refs()' to take a 'struct refspec' as a parameter
instead of an array of 'const char *'.

Signed-off-by: Brandon Williams <bmwill@google.com>
---
 remote.c    | 14 +++++---------
 remote.h    |  2 +-
 transport.c |  2 +-
 3 files changed, 7 insertions(+), 11 deletions(-)

diff --git a/remote.c b/remote.c
index 0e882d812..8e6522f4d 100644
--- a/remote.c
+++ b/remote.c
@@ -1264,24 +1264,20 @@ static void prepare_ref_index(struct string_list *ref_index, struct ref *ref)
  * but we can catch some errors early before even talking to the
  * remote side.
  */
-int check_push_refs(struct ref *src, int nr_refspec, const char **refspec_names)
+int check_push_refs(struct ref *src, struct refspec *rs)
 {
-	struct refspec refspec = REFSPEC_INIT_PUSH;
 	int ret = 0;
 	int i;
 
-	refspec_appendn(&refspec, refspec_names, nr_refspec);
-
-	for (i = 0; i < refspec.nr; i++) {
-		struct refspec_item *rs = &refspec.items[i];
+	for (i = 0; i < rs->nr; i++) {
+		struct refspec_item *item = &rs->items[i];
 
-		if (rs->pattern || rs->matching)
+		if (item->pattern || item->matching)
 			continue;
 
-		ret |= match_explicit_lhs(src, rs, NULL, NULL);
+		ret |= match_explicit_lhs(src, item, NULL, NULL);
 	}
 
-	refspec_clear(&refspec);
 	return ret;
 }
 
diff --git a/remote.h b/remote.h
index d5b5f24ac..9014f707f 100644
--- a/remote.h
+++ b/remote.h
@@ -161,7 +161,7 @@ struct ref *ref_remove_duplicates(struct ref *ref_map);
 int query_refspecs(struct refspec *rs, struct refspec_item *query);
 char *apply_refspecs(struct refspec *rs, const char *name);
 
-int check_push_refs(struct ref *src, int nr_refspec, const char **refspec);
+int check_push_refs(struct ref *src, struct refspec *rs);
 int match_push_refs(struct ref *src, struct ref **dst,
 		    struct refspec *rs, int flags);
 void set_ref_status_for_push(struct ref *remote_refs, int send_mirror,
diff --git a/transport.c b/transport.c
index 24a97d9e8..e32bc320c 100644
--- a/transport.c
+++ b/transport.c
@@ -1090,7 +1090,7 @@ int transport_push(struct transport *transport,
 		struct argv_array ref_prefixes = ARGV_ARRAY_INIT;
 		int i;
 
-		if (check_push_refs(local_refs, rs->raw_nr, rs->raw) < 0)
+		if (check_push_refs(local_refs, rs) < 0)
 			return -1;
 
 		for (i = 0; i < rs->nr; i++) {
-- 
2.17.0.441.gb46fe60e1d-goog


^ permalink raw reply related	[flat|nested] 112+ messages in thread

* [PATCH 35/35] submodule: convert push_unpushed_submodules to take a struct refspec
  2018-05-14 21:55 [PATCH 00/35] refactoring refspecs Brandon Williams
                   ` (33 preceding siblings ...)
  2018-05-14 21:56 ` [PATCH 34/35] remote: convert check_push_refs " Brandon Williams
@ 2018-05-14 21:56 ` Brandon Williams
  2018-05-15  8:11   ` Ævar Arnfjörð Bjarmason
  2018-05-14 23:08 ` [PATCH 00/35] refactoring refspecs Stefan Beller
                   ` (3 subsequent siblings)
  38 siblings, 1 reply; 112+ messages in thread
From: Brandon Williams @ 2018-05-14 21:56 UTC (permalink / raw)
  To: git, bmwill; +Cc: Brandon Williams

Convert 'push_unpushed_submodules()' to take a 'struct refspec' as a
parameter instead of an array of 'const char *'.

Signed-off-by: Brandon Williams <bmwill@google.com>
---
 submodule.c | 19 +++++++++----------
 submodule.h |  3 ++-
 transport.c |  2 +-
 3 files changed, 12 insertions(+), 12 deletions(-)

diff --git a/submodule.c b/submodule.c
index 74d35b257..cdeadd80e 100644
--- a/submodule.c
+++ b/submodule.c
@@ -968,7 +968,7 @@ int find_unpushed_submodules(struct oid_array *commits,
 
 static int push_submodule(const char *path,
 			  const struct remote *remote,
-			  const char **refspec, int refspec_nr,
+			  const struct refspec *rs,
 			  const struct string_list *push_options,
 			  int dry_run)
 {
@@ -991,8 +991,8 @@ static int push_submodule(const char *path,
 		if (remote->origin != REMOTE_UNCONFIGURED) {
 			int i;
 			argv_array_push(&cp.args, remote->name);
-			for (i = 0; i < refspec_nr; i++)
-				argv_array_push(&cp.args, refspec[i]);
+			for (i = 0; i < rs->raw_nr; i++)
+				argv_array_push(&cp.args, rs->raw[i]);
 		}
 
 		prepare_submodule_repo_env(&cp.env_array);
@@ -1013,7 +1013,7 @@ static int push_submodule(const char *path,
  */
 static void submodule_push_check(const char *path, const char *head,
 				 const struct remote *remote,
-				 const char **refspec, int refspec_nr)
+				 const struct refspec *rs)
 {
 	struct child_process cp = CHILD_PROCESS_INIT;
 	int i;
@@ -1023,8 +1023,8 @@ static void submodule_push_check(const char *path, const char *head,
 	argv_array_push(&cp.args, head);
 	argv_array_push(&cp.args, remote->name);
 
-	for (i = 0; i < refspec_nr; i++)
-		argv_array_push(&cp.args, refspec[i]);
+	for (i = 0; i < rs->raw_nr; i++)
+		argv_array_push(&cp.args, rs->raw[i]);
 
 	prepare_submodule_repo_env(&cp.env_array);
 	cp.git_cmd = 1;
@@ -1043,7 +1043,7 @@ static void submodule_push_check(const char *path, const char *head,
 
 int push_unpushed_submodules(struct oid_array *commits,
 			     const struct remote *remote,
-			     const char **refspec, int refspec_nr,
+			     const struct refspec *rs,
 			     const struct string_list *push_options,
 			     int dry_run)
 {
@@ -1069,8 +1069,7 @@ int push_unpushed_submodules(struct oid_array *commits,
 
 		for (i = 0; i < needs_pushing.nr; i++)
 			submodule_push_check(needs_pushing.items[i].string,
-					     head, remote,
-					     refspec, refspec_nr);
+					     head, remote, rs);
 		free(head);
 	}
 
@@ -1078,7 +1077,7 @@ int push_unpushed_submodules(struct oid_array *commits,
 	for (i = 0; i < needs_pushing.nr; i++) {
 		const char *path = needs_pushing.items[i].string;
 		fprintf(stderr, "Pushing submodule '%s'\n", path);
-		if (!push_submodule(path, remote, refspec, refspec_nr,
+		if (!push_submodule(path, remote, rs,
 				    push_options, dry_run)) {
 			fprintf(stderr, "Unable to push submodule '%s'\n", path);
 			ret = 0;
diff --git a/submodule.h b/submodule.h
index e5526f6aa..aae0c9c8f 100644
--- a/submodule.h
+++ b/submodule.h
@@ -100,9 +100,10 @@ extern int submodule_touches_in_range(struct object_id *a,
 extern int find_unpushed_submodules(struct oid_array *commits,
 				    const char *remotes_name,
 				    struct string_list *needs_pushing);
+struct refspec;
 extern int push_unpushed_submodules(struct oid_array *commits,
 				    const struct remote *remote,
-				    const char **refspec, int refspec_nr,
+				    const struct refspec *rs,
 				    const struct string_list *push_options,
 				    int dry_run);
 /*
diff --git a/transport.c b/transport.c
index e32bc320c..7e0b9abba 100644
--- a/transport.c
+++ b/transport.c
@@ -1157,7 +1157,7 @@ int transport_push(struct transport *transport,
 
 			if (!push_unpushed_submodules(&commits,
 						      transport->remote,
-						      rs->raw, rs->raw_nr,
+						      rs,
 						      transport->push_options,
 						      pretend)) {
 				oid_array_clear(&commits);
-- 
2.17.0.441.gb46fe60e1d-goog


^ permalink raw reply related	[flat|nested] 112+ messages in thread

* Re: [PATCH 00/35] refactoring refspecs
  2018-05-14 21:55 [PATCH 00/35] refactoring refspecs Brandon Williams
                   ` (34 preceding siblings ...)
  2018-05-14 21:56 ` [PATCH 35/35] submodule: convert push_unpushed_submodules " Brandon Williams
@ 2018-05-14 23:08 ` Stefan Beller
  2018-05-15  8:05 ` Junio C Hamano
                   ` (2 subsequent siblings)
  38 siblings, 0 replies; 112+ messages in thread
From: Stefan Beller @ 2018-05-14 23:08 UTC (permalink / raw)
  To: Brandon Williams; +Cc: git

>  22 files changed, 514 insertions(+), 571 deletions(-)
>  create mode 100644 refspec.c
>  create mode 100644 refspec.h

This looks promising. I'll hope to find time to review it.

Stefan

^ permalink raw reply	[flat|nested] 112+ messages in thread

* Re: [PATCH 00/35] refactoring refspecs
  2018-05-14 21:55 [PATCH 00/35] refactoring refspecs Brandon Williams
                   ` (35 preceding siblings ...)
  2018-05-14 23:08 ` [PATCH 00/35] refactoring refspecs Stefan Beller
@ 2018-05-15  8:05 ` Junio C Hamano
  2018-05-15  8:39 ` Ævar Arnfjörð Bjarmason
  2018-05-16 22:57 ` [PATCH v2 00/36] " Brandon Williams
  38 siblings, 0 replies; 112+ messages in thread
From: Junio C Hamano @ 2018-05-15  8:05 UTC (permalink / raw)
  To: Brandon Williams; +Cc: git

Brandon Williams <bmwill@google.com> writes:

> This series refactors how refspecs are handled through out the code base
> by renaming the existing struct refspec to refspec_item and introducing
> a new 'struct refspec' which is a container of refspec_items, much like
> how a pathspec contains pathspec_items.  This simplifies many callers
> and makes handling pathspecs a bit easier.

Good.  IOW, a refspec is a set of refspec items, just like a
pathspec is a set of pathspec items.  The two level abstraction
would naturally let us work on individual items as well as the whole
thing as a single set, which is quite nice.


^ permalink raw reply	[flat|nested] 112+ messages in thread

* Re: [PATCH 01/35] refspec: move refspec parsing logic into its own file
  2018-05-14 21:55 ` [PATCH 01/35] refspec: move refspec parsing logic into its own file Brandon Williams
@ 2018-05-15  8:06   ` Junio C Hamano
  2018-05-15 16:51     ` Brandon Williams
  0 siblings, 1 reply; 112+ messages in thread
From: Junio C Hamano @ 2018-05-15  8:06 UTC (permalink / raw)
  To: Brandon Williams; +Cc: git

Brandon Williams <bmwill@google.com> writes:

> In preperation for performing a refactor on refspec related code, move

Preparation?

> the refspec parsing logic into its own file.
>
> Signed-off-by: Brandon Williams <bmwill@google.com>
> ---
>  Makefile                    |   1 +
>  branch.c                    |   1 +
>  builtin/clone.c             |   1 +
>  builtin/fast-export.c       |   1 +
>  builtin/fetch.c             |   1 +
>  builtin/merge.c             |   1 +
>  builtin/pull.c              |   1 +
>  builtin/push.c              |   1 +
>  builtin/remote.c            |   1 +
>  builtin/submodule--helper.c |   1 +
>  checkout.c                  |   1 +
>  refspec.c                   | 168 ++++++++++++++++++++++++++++++++++++
>  refspec.h                   |  23 +++++
>  remote.c                    | 165 +----------------------------------
>  remote.h                    |  20 -----
>  transport-helper.c          |   1 +
>  transport.c                 |   1 +
>  17 files changed, 205 insertions(+), 184 deletions(-)
>  create mode 100644 refspec.c
>  create mode 100644 refspec.h
>
> diff --git a/Makefile b/Makefile
> index ad880d1fc..4bca65383 100644
> --- a/Makefile
> +++ b/Makefile
> @@ -928,6 +928,7 @@ LIB_OBJS += refs/files-backend.o
>  LIB_OBJS += refs/iterator.o
>  LIB_OBJS += refs/packed-backend.o
>  LIB_OBJS += refs/ref-cache.o
> +LIB_OBJS += refspec.o
>  LIB_OBJS += ref-filter.o
>  LIB_OBJS += remote.o
>  LIB_OBJS += replace-object.o
> diff --git a/branch.c b/branch.c
> index 2672054f0..32ccefc6b 100644
> --- a/branch.c
> +++ b/branch.c
> @@ -3,6 +3,7 @@
>  #include "config.h"
>  #include "branch.h"
>  #include "refs.h"
> +#include "refspec.h"
>  #include "remote.h"
>  #include "commit.h"
>  #include "worktree.h"
> diff --git a/builtin/clone.c b/builtin/clone.c
> index 84f1473d1..6d1614ed3 100644
> --- a/builtin/clone.c
> +++ b/builtin/clone.c
> @@ -14,6 +14,7 @@
>  #include "parse-options.h"
>  #include "fetch-pack.h"
>  #include "refs.h"
> +#include "refspec.h"
>  #include "tree.h"
>  #include "tree-walk.h"
>  #include "unpack-trees.h"
> diff --git a/builtin/fast-export.c b/builtin/fast-export.c
> index 530df12f0..a13b7c8ef 100644
> --- a/builtin/fast-export.c
> +++ b/builtin/fast-export.c
> @@ -7,6 +7,7 @@
>  #include "cache.h"
>  #include "config.h"
>  #include "refs.h"
> +#include "refspec.h"
>  #include "commit.h"
>  #include "object.h"
>  #include "tag.h"
> diff --git a/builtin/fetch.c b/builtin/fetch.c
> index 7ee83ac0f..1fce68e9a 100644
> --- a/builtin/fetch.c
> +++ b/builtin/fetch.c
> @@ -5,6 +5,7 @@
>  #include "config.h"
>  #include "repository.h"
>  #include "refs.h"
> +#include "refspec.h"
>  #include "commit.h"
>  #include "builtin.h"
>  #include "string-list.h"
> diff --git a/builtin/merge.c b/builtin/merge.c
> index 9db5a2cf1..c362cfe90 100644
> --- a/builtin/merge.c
> +++ b/builtin/merge.c
> @@ -14,6 +14,7 @@
>  #include "run-command.h"
>  #include "diff.h"
>  #include "refs.h"
> +#include "refspec.h"
>  #include "commit.h"
>  #include "diffcore.h"
>  #include "revision.h"
> diff --git a/builtin/pull.c b/builtin/pull.c
> index 71aac5005..6247c956d 100644
> --- a/builtin/pull.c
> +++ b/builtin/pull.c
> @@ -15,6 +15,7 @@
>  #include "remote.h"
>  #include "dir.h"
>  #include "refs.h"
> +#include "refspec.h"
>  #include "revision.h"
>  #include "submodule.h"
>  #include "submodule-config.h"
> diff --git a/builtin/push.c b/builtin/push.c
> index ac3705370..fa65999b2 100644
> --- a/builtin/push.c
> +++ b/builtin/push.c
> @@ -4,6 +4,7 @@
>  #include "cache.h"
>  #include "config.h"
>  #include "refs.h"
> +#include "refspec.h"
>  #include "run-command.h"
>  #include "builtin.h"
>  #include "remote.h"
> diff --git a/builtin/remote.c b/builtin/remote.c
> index 8708e584e..c49513995 100644
> --- a/builtin/remote.c
> +++ b/builtin/remote.c
> @@ -7,6 +7,7 @@
>  #include "strbuf.h"
>  #include "run-command.h"
>  #include "refs.h"
> +#include "refspec.h"
>  #include "argv-array.h"
>  
>  static const char * const builtin_remote_usage[] = {
> diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
> index c2403a915..6ab032acb 100644
> --- a/builtin/submodule--helper.c
> +++ b/builtin/submodule--helper.c
> @@ -12,6 +12,7 @@
>  #include "run-command.h"
>  #include "remote.h"
>  #include "refs.h"
> +#include "refspec.h"
>  #include "connect.h"
>  #include "revision.h"
>  #include "diffcore.h"
> diff --git a/checkout.c b/checkout.c
> index ac42630f7..193ba8567 100644
> --- a/checkout.c
> +++ b/checkout.c
> @@ -1,5 +1,6 @@
>  #include "cache.h"
>  #include "remote.h"
> +#include "refspec.h"
>  #include "checkout.h"
>  
>  struct tracking_name_data {
> diff --git a/refspec.c b/refspec.c
> new file mode 100644
> index 000000000..ecb0bdff3
> --- /dev/null
> +++ b/refspec.c
> @@ -0,0 +1,168 @@
> +#include "cache.h"
> +#include "refs.h"
> +#include "refspec.h"
> +
> +static struct refspec s_tag_refspec = {
> +	0,
> +	1,
> +	0,
> +	0,
> +	"refs/tags/*",
> +	"refs/tags/*"
> +};
> +
> +/* See TAG_REFSPEC for the string version */
> +const struct refspec *tag_refspec = &s_tag_refspec;
> +
> +static struct refspec *parse_refspec_internal(int nr_refspec, const char **refspec, int fetch, int verify)
> +{
> +	int i;
> +	struct refspec *rs = xcalloc(nr_refspec, sizeof(*rs));
> +
> +	for (i = 0; i < nr_refspec; i++) {
> +		size_t llen;
> +		int is_glob;
> +		const char *lhs, *rhs;
> +		int flags;
> +
> +		is_glob = 0;
> +
> +		lhs = refspec[i];
> +		if (*lhs == '+') {
> +			rs[i].force = 1;
> +			lhs++;
> +		}
> +
> +		rhs = strrchr(lhs, ':');
> +
> +		/*
> +		 * Before going on, special case ":" (or "+:") as a refspec
> +		 * for pushing matching refs.
> +		 */
> +		if (!fetch && rhs == lhs && rhs[1] == '\0') {
> +			rs[i].matching = 1;
> +			continue;
> +		}
> +
> +		if (rhs) {
> +			size_t rlen = strlen(++rhs);
> +			is_glob = (1 <= rlen && strchr(rhs, '*'));
> +			rs[i].dst = xstrndup(rhs, rlen);
> +		}
> +
> +		llen = (rhs ? (rhs - lhs - 1) : strlen(lhs));
> +		if (1 <= llen && memchr(lhs, '*', llen)) {
> +			if ((rhs && !is_glob) || (!rhs && fetch))
> +				goto invalid;
> +			is_glob = 1;
> +		} else if (rhs && is_glob) {
> +			goto invalid;
> +		}
> +
> +		rs[i].pattern = is_glob;
> +		rs[i].src = xstrndup(lhs, llen);
> +		flags = REFNAME_ALLOW_ONELEVEL | (is_glob ? REFNAME_REFSPEC_PATTERN : 0);
> +
> +		if (fetch) {
> +			struct object_id unused;
> +
> +			/* LHS */
> +			if (!*rs[i].src)
> +				; /* empty is ok; it means "HEAD" */
> +			else if (llen == GIT_SHA1_HEXSZ && !get_oid_hex(rs[i].src, &unused))
> +				rs[i].exact_sha1 = 1; /* ok */
> +			else if (!check_refname_format(rs[i].src, flags))
> +				; /* valid looking ref is ok */
> +			else
> +				goto invalid;
> +			/* RHS */
> +			if (!rs[i].dst)
> +				; /* missing is ok; it is the same as empty */
> +			else if (!*rs[i].dst)
> +				; /* empty is ok; it means "do not store" */
> +			else if (!check_refname_format(rs[i].dst, flags))
> +				; /* valid looking ref is ok */
> +			else
> +				goto invalid;
> +		} else {
> +			/*
> +			 * LHS
> +			 * - empty is allowed; it means delete.
> +			 * - when wildcarded, it must be a valid looking ref.
> +			 * - otherwise, it must be an extended SHA-1, but
> +			 *   there is no existing way to validate this.
> +			 */
> +			if (!*rs[i].src)
> +				; /* empty is ok */
> +			else if (is_glob) {
> +				if (check_refname_format(rs[i].src, flags))
> +					goto invalid;
> +			}
> +			else
> +				; /* anything goes, for now */
> +			/*
> +			 * RHS
> +			 * - missing is allowed, but LHS then must be a
> +			 *   valid looking ref.
> +			 * - empty is not allowed.
> +			 * - otherwise it must be a valid looking ref.
> +			 */
> +			if (!rs[i].dst) {
> +				if (check_refname_format(rs[i].src, flags))
> +					goto invalid;
> +			} else if (!*rs[i].dst) {
> +				goto invalid;
> +			} else {
> +				if (check_refname_format(rs[i].dst, flags))
> +					goto invalid;
> +			}
> +		}
> +	}
> +	return rs;
> +
> + invalid:
> +	if (verify) {
> +		/*
> +		 * nr_refspec must be greater than zero and i must be valid
> +		 * since it is only possible to reach this point from within
> +		 * the for loop above.
> +		 */
> +		free_refspec(i+1, rs);
> +		return NULL;
> +	}
> +	die("Invalid refspec '%s'", refspec[i]);
> +}
> +
> +int valid_fetch_refspec(const char *fetch_refspec_str)
> +{
> +	struct refspec *refspec;
> +
> +	refspec = parse_refspec_internal(1, &fetch_refspec_str, 1, 1);
> +	free_refspec(1, refspec);
> +	return !!refspec;
> +}
> +
> +struct refspec *parse_fetch_refspec(int nr_refspec, const char **refspec)
> +{
> +	return parse_refspec_internal(nr_refspec, refspec, 1, 0);
> +}
> +
> +struct refspec *parse_push_refspec(int nr_refspec, const char **refspec)
> +{
> +	return parse_refspec_internal(nr_refspec, refspec, 0, 0);
> +}
> +
> +void free_refspec(int nr_refspec, struct refspec *refspec)
> +{
> +	int i;
> +
> +	if (!refspec)
> +		return;
> +
> +	for (i = 0; i < nr_refspec; i++) {
> +		free(refspec[i].src);
> +		free(refspec[i].dst);
> +	}
> +	free(refspec);
> +}
> +
> diff --git a/refspec.h b/refspec.h
> new file mode 100644
> index 000000000..b1db91918
> --- /dev/null
> +++ b/refspec.h
> @@ -0,0 +1,23 @@
> +#ifndef REFSPEC_H
> +#define REFSPEC_H
> +
> +#define TAG_REFSPEC "refs/tags/*:refs/tags/*"
> +const struct refspec *tag_refspec;
> +
> +struct refspec {
> +	unsigned force : 1;
> +	unsigned pattern : 1;
> +	unsigned matching : 1;
> +	unsigned exact_sha1 : 1;
> +
> +	char *src;
> +	char *dst;
> +};
> +
> +int valid_fetch_refspec(const char *refspec);
> +struct refspec *parse_fetch_refspec(int nr_refspec, const char **refspec);
> +struct refspec *parse_push_refspec(int nr_refspec, const char **refspec);
> +
> +void free_refspec(int nr_refspec, struct refspec *refspec);
> +
> +#endif /* REFSPEC_H */
> diff --git a/remote.c b/remote.c
> index 91eb010ca..4d67c061a 100644
> --- a/remote.c
> +++ b/remote.c
> @@ -2,6 +2,7 @@
>  #include "config.h"
>  #include "remote.h"
>  #include "refs.h"
> +#include "refspec.h"
>  #include "commit.h"
>  #include "diff.h"
>  #include "revision.h"
> @@ -13,18 +14,6 @@
>  
>  enum map_direction { FROM_SRC, FROM_DST };
>  
> -static struct refspec s_tag_refspec = {
> -	0,
> -	1,
> -	0,
> -	0,
> -	"refs/tags/*",
> -	"refs/tags/*"
> -};
> -
> -/* See TAG_REFSPEC for the string version */
> -const struct refspec *tag_refspec = &s_tag_refspec;
> -
>  struct counted_string {
>  	size_t len;
>  	const char *s;
> @@ -499,158 +488,6 @@ static void read_config(void)
>  	alias_all_urls();
>  }
>  
> -static struct refspec *parse_refspec_internal(int nr_refspec, const char **refspec, int fetch, int verify)
> -{
> -	int i;
> -	struct refspec *rs = xcalloc(nr_refspec, sizeof(*rs));
> -
> -	for (i = 0; i < nr_refspec; i++) {
> -		size_t llen;
> -		int is_glob;
> -		const char *lhs, *rhs;
> -		int flags;
> -
> -		is_glob = 0;
> -
> -		lhs = refspec[i];
> -		if (*lhs == '+') {
> -			rs[i].force = 1;
> -			lhs++;
> -		}
> -
> -		rhs = strrchr(lhs, ':');
> -
> -		/*
> -		 * Before going on, special case ":" (or "+:") as a refspec
> -		 * for pushing matching refs.
> -		 */
> -		if (!fetch && rhs == lhs && rhs[1] == '\0') {
> -			rs[i].matching = 1;
> -			continue;
> -		}
> -
> -		if (rhs) {
> -			size_t rlen = strlen(++rhs);
> -			is_glob = (1 <= rlen && strchr(rhs, '*'));
> -			rs[i].dst = xstrndup(rhs, rlen);
> -		}
> -
> -		llen = (rhs ? (rhs - lhs - 1) : strlen(lhs));
> -		if (1 <= llen && memchr(lhs, '*', llen)) {
> -			if ((rhs && !is_glob) || (!rhs && fetch))
> -				goto invalid;
> -			is_glob = 1;
> -		} else if (rhs && is_glob) {
> -			goto invalid;
> -		}
> -
> -		rs[i].pattern = is_glob;
> -		rs[i].src = xstrndup(lhs, llen);
> -		flags = REFNAME_ALLOW_ONELEVEL | (is_glob ? REFNAME_REFSPEC_PATTERN : 0);
> -
> -		if (fetch) {
> -			struct object_id unused;
> -
> -			/* LHS */
> -			if (!*rs[i].src)
> -				; /* empty is ok; it means "HEAD" */
> -			else if (llen == GIT_SHA1_HEXSZ && !get_oid_hex(rs[i].src, &unused))
> -				rs[i].exact_sha1 = 1; /* ok */
> -			else if (!check_refname_format(rs[i].src, flags))
> -				; /* valid looking ref is ok */
> -			else
> -				goto invalid;
> -			/* RHS */
> -			if (!rs[i].dst)
> -				; /* missing is ok; it is the same as empty */
> -			else if (!*rs[i].dst)
> -				; /* empty is ok; it means "do not store" */
> -			else if (!check_refname_format(rs[i].dst, flags))
> -				; /* valid looking ref is ok */
> -			else
> -				goto invalid;
> -		} else {
> -			/*
> -			 * LHS
> -			 * - empty is allowed; it means delete.
> -			 * - when wildcarded, it must be a valid looking ref.
> -			 * - otherwise, it must be an extended SHA-1, but
> -			 *   there is no existing way to validate this.
> -			 */
> -			if (!*rs[i].src)
> -				; /* empty is ok */
> -			else if (is_glob) {
> -				if (check_refname_format(rs[i].src, flags))
> -					goto invalid;
> -			}
> -			else
> -				; /* anything goes, for now */
> -			/*
> -			 * RHS
> -			 * - missing is allowed, but LHS then must be a
> -			 *   valid looking ref.
> -			 * - empty is not allowed.
> -			 * - otherwise it must be a valid looking ref.
> -			 */
> -			if (!rs[i].dst) {
> -				if (check_refname_format(rs[i].src, flags))
> -					goto invalid;
> -			} else if (!*rs[i].dst) {
> -				goto invalid;
> -			} else {
> -				if (check_refname_format(rs[i].dst, flags))
> -					goto invalid;
> -			}
> -		}
> -	}
> -	return rs;
> -
> - invalid:
> -	if (verify) {
> -		/*
> -		 * nr_refspec must be greater than zero and i must be valid
> -		 * since it is only possible to reach this point from within
> -		 * the for loop above.
> -		 */
> -		free_refspec(i+1, rs);
> -		return NULL;
> -	}
> -	die("Invalid refspec '%s'", refspec[i]);
> -}
> -
> -int valid_fetch_refspec(const char *fetch_refspec_str)
> -{
> -	struct refspec *refspec;
> -
> -	refspec = parse_refspec_internal(1, &fetch_refspec_str, 1, 1);
> -	free_refspec(1, refspec);
> -	return !!refspec;
> -}
> -
> -struct refspec *parse_fetch_refspec(int nr_refspec, const char **refspec)
> -{
> -	return parse_refspec_internal(nr_refspec, refspec, 1, 0);
> -}
> -
> -struct refspec *parse_push_refspec(int nr_refspec, const char **refspec)
> -{
> -	return parse_refspec_internal(nr_refspec, refspec, 0, 0);
> -}
> -
> -void free_refspec(int nr_refspec, struct refspec *refspec)
> -{
> -	int i;
> -
> -	if (!refspec)
> -		return;
> -
> -	for (i = 0; i < nr_refspec; i++) {
> -		free(refspec[i].src);
> -		free(refspec[i].dst);
> -	}
> -	free(refspec);
> -}
> -
>  static int valid_remote_nick(const char *name)
>  {
>  	if (!name[0] || is_dot_or_dotdot(name))
> diff --git a/remote.h b/remote.h
> index 2b3180f94..386ced901 100644
> --- a/remote.h
> +++ b/remote.h
> @@ -68,18 +68,6 @@ int for_each_remote(each_remote_fn fn, void *priv);
>  
>  int remote_has_url(struct remote *remote, const char *url);
>  
> -struct refspec {
> -	unsigned force : 1;
> -	unsigned pattern : 1;
> -	unsigned matching : 1;
> -	unsigned exact_sha1 : 1;
> -
> -	char *src;
> -	char *dst;
> -};
> -
> -extern const struct refspec *tag_refspec;
> -
>  struct ref {
>  	struct ref *next;
>  	struct object_id old_oid;
> @@ -175,12 +163,6 @@ int ref_newer(const struct object_id *new_oid, const struct object_id *old_oid);
>   */
>  struct ref *ref_remove_duplicates(struct ref *ref_map);
>  
> -int valid_fetch_refspec(const char *refspec);
> -struct refspec *parse_fetch_refspec(int nr_refspec, const char **refspec);
> -extern struct refspec *parse_push_refspec(int nr_refspec, const char **refspec);
> -
> -void free_refspec(int nr_refspec, struct refspec *refspec);
> -
>  extern int query_refspecs(struct refspec *specs, int nr, struct refspec *query);
>  char *apply_refspecs(struct refspec *refspecs, int nr_refspec,
>  		     const char *name);
> @@ -313,8 +295,6 @@ extern int parseopt_push_cas_option(const struct option *, const char *arg, int
>  extern int is_empty_cas(const struct push_cas_option *);
>  void apply_push_cas(struct push_cas_option *, struct remote *, struct ref *);
>  
> -#define TAG_REFSPEC "refs/tags/*:refs/tags/*"
> -
>  void add_prune_tags_to_fetch_refspec(struct remote *remote);
>  
>  #endif
> diff --git a/transport-helper.c b/transport-helper.c
> index 11f1055b4..b99e1cce9 100644
> --- a/transport-helper.c
> +++ b/transport-helper.c
> @@ -11,6 +11,7 @@
>  #include "sigchain.h"
>  #include "argv-array.h"
>  #include "refs.h"
> +#include "refspec.h"
>  #include "transport-internal.h"
>  #include "protocol.h"
>  
> diff --git a/transport.c b/transport.c
> index 37410d8aa..2cf63d18b 100644
> --- a/transport.c
> +++ b/transport.c
> @@ -11,6 +11,7 @@
>  #include "bundle.h"
>  #include "dir.h"
>  #include "refs.h"
> +#include "refspec.h"
>  #include "branch.h"
>  #include "url.h"
>  #include "submodule.h"

^ permalink raw reply	[flat|nested] 112+ messages in thread

* Re: [PATCH 35/35] submodule: convert push_unpushed_submodules to take a struct refspec
  2018-05-14 21:56 ` [PATCH 35/35] submodule: convert push_unpushed_submodules " Brandon Williams
@ 2018-05-15  8:11   ` Ævar Arnfjörð Bjarmason
  2018-05-15 16:52     ` Stefan Beller
  2018-05-15 16:59     ` Brandon Williams
  0 siblings, 2 replies; 112+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2018-05-15  8:11 UTC (permalink / raw)
  To: Brandon Williams; +Cc: git


On Mon, May 14 2018, Brandon Williams wrote:

> Convert 'push_unpushed_submodules()' to take a 'struct refspec' as a
> parameter instead of an array of 'const char *'.
> [...]
> diff --git a/submodule.h b/submodule.h
> index e5526f6aa..aae0c9c8f 100644
> --- a/submodule.h
> +++ b/submodule.h
> @@ -100,9 +100,10 @@ extern int submodule_touches_in_range(struct object_id *a,
>  extern int find_unpushed_submodules(struct oid_array *commits,
>  				    const char *remotes_name,
>  				    struct string_list *needs_pushing);
> +struct refspec;
>  extern int push_unpushed_submodules(struct oid_array *commits,
>  				    const struct remote *remote,
> -				    const char **refspec, int refspec_nr,
> +				    const struct refspec *rs,
>  				    const struct string_list *push_options,
>  				    int dry_run);
>  /*

Why do you prefer doing this to having this on top?:
    
    diff --git a/submodule.h b/submodule.h
    index aae0c9c8ff..c3f206ce17 100644
    --- a/submodule.h
    +++ b/submodule.h
    @@ -1,5 +1,6 @@
     #ifndef SUBMODULE_H
     #define SUBMODULE_H
    +#include "refspec.h"
     
     struct repository;
     struct diff_options;
    @@ -100,7 +101,6 @@ extern int submodule_touches_in_range(struct object_id *a,
     extern int find_unpushed_submodules(struct oid_array *commits,
                                        const char *remotes_name,
                                        struct string_list *needs_pushing);
    -struct refspec;
     extern int push_unpushed_submodules(struct oid_array *commits,
                                        const struct remote *remote,
                                        const struct refspec *rs,

^ permalink raw reply	[flat|nested] 112+ messages in thread

* Re: [PATCH 03/35] refspec: rename struct refspec to struct refspec_item
  2018-05-14 21:55 ` [PATCH 03/35] refspec: rename struct refspec to struct refspec_item Brandon Williams
@ 2018-05-15  8:17   ` Junio C Hamano
  2018-05-15 18:19     ` Brandon Williams
  0 siblings, 1 reply; 112+ messages in thread
From: Junio C Hamano @ 2018-05-15  8:17 UTC (permalink / raw)
  To: Brandon Williams; +Cc: git

Brandon Williams <bmwill@google.com> writes:

> In preperation for introducing an abstraction around a collection of
> refspecs (much like how a 'struct pathspec' is a collection of 'struct
> pathspec_item's) rename the existing 'struct refspec' to 'struct
> refspec_item'.

Makes sense.

>  /* See TAG_REFSPEC for the string version */
> -const struct refspec *tag_refspec = &s_tag_refspec;
> +const struct refspec_item *tag_refspec = &s_tag_refspec;
>  
>  /*
>   * Parses 'refspec' and populates 'rs'.  returns 1 if successful and 0 if the
>   * refspec is invalid.
>   */
> -static int parse_refspec(struct refspec *rs, const char *refspec, int fetch)
> +static int parse_refspec(struct refspec_item *rs, const char *refspec, int fetch)

The new comment given to the function in the previous step talks
in terms of the variable name and not type, so technically it is
still valid after this change without updating.

I however wonder if it makes more sense to go one step further and
rename the "const char *" variable that is a string form of a single
refspec item to something other than "refspec".  Which would
invalidate the commit you gave to the function and make it necessary
to be updated in this step.

I wonder if the early part of the series becomes easier to read if
patches 2 and 3 are swapped.  That may result in less code/comment
churn.

^ permalink raw reply	[flat|nested] 112+ messages in thread

* Re: [PATCH 14/35] remote: convert fetch refspecs to struct refspec
  2018-05-14 21:56 ` [PATCH 14/35] remote: convert fetch " Brandon Williams
@ 2018-05-15  8:31   ` Ævar Arnfjörð Bjarmason
  2018-05-15 17:57     ` Brandon Williams
  0 siblings, 1 reply; 112+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2018-05-15  8:31 UTC (permalink / raw)
  To: Brandon Williams; +Cc: git


On Mon, May 14 2018, Brandon Williams wrote:

>  void add_prune_tags_to_fetch_refspec(struct remote *remote)
>  {
> -	int nr = remote->fetch_refspec_nr;
> -	int bufsize = nr  + 1;
> -	int size = sizeof(struct refspec_item);
> -
> -	remote->fetch = xrealloc(remote->fetch, size  * bufsize);
> -	memcpy(&remote->fetch[nr], tag_refspec, size);
> -	add_fetch_refspec(remote, xstrdup(TAG_REFSPEC));
> +	refspec_append(&remote->fetch, TAG_REFSPEC);
>  }

Thanks for fixing the hack I needed to put in place in 97716d217c
("fetch: add a --prune-tags option and fetch.pruneTags config",
2018-02-09).

I'm not sure where it belongs in this series, but I think this makes
sense on top of the whole thing:

    diff --git a/builtin/fetch.c b/builtin/fetch.c
    index af7064dce3..9a523249f5 100644
    --- a/builtin/fetch.c
    +++ b/builtin/fetch.c
    @@ -1383,7 +1383,8 @@ static int fetch_one(struct remote *remote, int argc, const char **argv, int pru

            maybe_prune_tags = prune_tags_ok && prune_tags;
            if (maybe_prune_tags && remote_via_config)
    -               add_prune_tags_to_fetch_refspec(remote);
    +               refspec_append(&remote->fetch, TAG_REFSPEC);
    +

            if (maybe_prune_tags && (argc || !remote_via_config))
                    refspec_append(&rs, TAG_REFSPEC);
    diff --git a/remote.c b/remote.c
    index 8e6522f4d0..946b95d18d 100644
    --- a/remote.c
    +++ b/remote.c
    @@ -87,11 +87,6 @@ static void add_fetch_refspec(struct remote *remote, const char *ref)
            refspec_append(&remote->fetch, ref);
     }

    -void add_prune_tags_to_fetch_refspec(struct remote *remote)
    -{
    -       refspec_append(&remote->fetch, TAG_REFSPEC);
    -}
    -
     static void add_url(struct remote *remote, const char *url)
     {
            ALLOC_GROW(remote->url, remote->url_nr + 1, remote->url_alloc);
    diff --git a/remote.h b/remote.h
    index 9014f707f0..62a6566594 100644
    --- a/remote.h
    +++ b/remote.h
    @@ -289,6 +289,4 @@ extern int parseopt_push_cas_option(const struct option *, const char *arg, int
     extern int is_empty_cas(const struct push_cas_option *);
     void apply_push_cas(struct push_cas_option *, struct remote *, struct ref *);

    -void add_prune_tags_to_fetch_refspec(struct remote *remote);
    -
     #endif

I.e. the whole reason we have this function is because of my above
commit where I had to very carefully hack around the fact that we didn't
have something which could ALLOW_GROW() the structure after it had been
created.

So I added the add_prune_tags_to_fetch_refspec() function to very
carefully do *only* that so others wouldn't be tempted to use this hack
more generally.

But now we have a nice API for it, so we can just throw away the
wrapper, and use the same API everywhere. You already did the other half
of that in your e69b54f53a ("fetch: convert fetch_one to use struct
refspec", 2018-05-11).

^ permalink raw reply	[flat|nested] 112+ messages in thread

* Re: [PATCH 00/35] refactoring refspecs
  2018-05-14 21:55 [PATCH 00/35] refactoring refspecs Brandon Williams
                   ` (36 preceding siblings ...)
  2018-05-15  8:05 ` Junio C Hamano
@ 2018-05-15  8:39 ` Ævar Arnfjörð Bjarmason
  2018-05-15 18:01   ` Brandon Williams
  2018-05-16 22:57 ` [PATCH v2 00/36] " Brandon Williams
  38 siblings, 1 reply; 112+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2018-05-15  8:39 UTC (permalink / raw)
  To: Brandon Williams; +Cc: git


On Mon, May 14 2018, Brandon Williams wrote:

> When working on protocol v2 I noticed that working with refspecs was a
> little difficult because of the various api's that existed.  Some
> functions expected an array of "const char *" while others expected an
> array of "struct refspec".  In all cases a length parameter needed to be
> passed as a parameter as well.  This makes working with refspecs a
> little challenging because of the different expectations different parts
> of the code base have.
>
> This series refactors how refspecs are handled through out the code base
> by renaming the existing struct refspec to refspec_item and introducing
> a new 'struct refspec' which is a container of refspec_items, much like
> how a pathspec contains pathspec_items.  This simplifies many callers
> and makes handling pathspecs a bit easier.

This looks really good to me. The API you're replacing is one of the
worst I've had a chance to encounter in git.git (as noted in my
https://public-inbox.org/git/87in7p2ucb.fsf@evledraar.gmail.com/ but
maybe I haven't looked widely enough), and now it's really nice.

> I have some follow on work which I'll build on top of this series, but
> since this was already getting a bit lengthy at 35 patches I'll save
> that for another time.

In addition to my other suggestions for stuff to put on top, which I see
now you may have just had in your local tree but didn't submit, I think
this makes sense:

    diff --git a/remote.c b/remote.c
    index 946b95d18d..cb97e662e8 100644
    --- a/remote.c
    +++ b/remote.c
    @@ -77,16 +77,6 @@ static const char *alias_url(const char *url, struct rewrites *r)
     	return xstrfmt("%s%s", r->rewrite[longest_i]->base, url + longest->len);
     }

    -static void add_push_refspec(struct remote *remote, const char *ref)
    -{
    -	refspec_append(&remote->push, ref);
    -}
    -
    -static void add_fetch_refspec(struct remote *remote, const char *ref)
    -{
    -	refspec_append(&remote->fetch, ref);
    -}
    -
     static void add_url(struct remote *remote, const char *url)
     {
     	ALLOC_GROW(remote->url, remote->url_nr + 1, remote->url_alloc);
    @@ -261,9 +251,9 @@ static void read_remotes_file(struct remote *remote)
     		if (skip_prefix(buf.buf, "URL:", &v))
     			add_url_alias(remote, xstrdup(skip_spaces(v)));
     		else if (skip_prefix(buf.buf, "Push:", &v))
    -			add_push_refspec(remote, xstrdup(skip_spaces(v)));
    +			refspec_append(&remote->push, xstrdup(skip_spaces(v)));
     		else if (skip_prefix(buf.buf, "Pull:", &v))
    -			add_fetch_refspec(remote, xstrdup(skip_spaces(v)));
    +			refspec_append(&remote->fetch, xstrdup(skip_spaces(v)));
     	}
     	strbuf_release(&buf);
     	fclose(f);
    @@ -302,14 +292,14 @@ static void read_branches_file(struct remote *remote)
     		frag = "master";

     	add_url_alias(remote, strbuf_detach(&buf, NULL));
    -	add_fetch_refspec(remote, xstrfmt("refs/heads/%s:refs/heads/%s",
    -					  frag, remote->name));
    +	refspec_append(&remote->fetch, xstrfmt("refs/heads/%s:refs/heads/%s",
    +					       frag, remote->name));

     	/*
     	 * Cogito compatible push: push current HEAD to remote #branch
     	 * (master if missing)
     	 */
    -	add_push_refspec(remote, xstrfmt("HEAD:refs/heads/%s", frag));
    +	refspec_append(&remote->push, xstrfmt("HEAD:refs/heads/%s", frag));
     	remote->fetch_tags = 1; /* always auto-follow */
     }

    @@ -395,12 +385,12 @@ static int handle_config(const char *key, const char *value, void *cb)
     		const char *v;
     		if (git_config_string(&v, key, value))
     			return -1;
    -		add_push_refspec(remote, v);
    +		refspec_append(&remote->push, v);
     	} else if (!strcmp(subkey, "fetch")) {
     		const char *v;
     		if (git_config_string(&v, key, value))
     			return -1;
    -		add_fetch_refspec(remote, v);
    +		refspec_append(&remote->fetch, v);
     	} else if (!strcmp(subkey, "receivepack")) {
     		const char *v;
     		if (git_config_string(&v, key, value))

I.e. the reason we have add_{push,fetch}_refspec() in the first place is
because without your series it's tricky to add new ones, but now it's
trivial, so let's not leave behind wrapper static functions whose sole
purpose is to just call another exported API as-is.

I've pushed all the patches I quoted inline in this review at
avar-bwill/refspec in github.com/avar/git, consider them all signed-off,
and depending on whether you agree/disagree etc. please squash
them/adapt them/drop them however you see fit.

^ permalink raw reply	[flat|nested] 112+ messages in thread

* Re: [PATCH 04/35] refspec: introduce struct refspec
  2018-05-14 21:55 ` [PATCH 04/35] refspec: introduce struct refspec Brandon Williams
@ 2018-05-15  9:37   ` Junio C Hamano
  2018-05-15 18:37     ` Brandon Williams
  0 siblings, 1 reply; 112+ messages in thread
From: Junio C Hamano @ 2018-05-15  9:37 UTC (permalink / raw)
  To: Brandon Williams; +Cc: git

Brandon Williams <bmwill@google.com> writes:

> diff --git a/refspec.h b/refspec.h
> index 173cea882..f6fb251f3 100644
> --- a/refspec.h
> +++ b/refspec.h
> @@ -20,4 +20,29 @@ struct refspec_item *parse_push_refspec(int nr_refspec, const char **refspec);
>  
>  void free_refspec(int nr_refspec, struct refspec_item *refspec);
>  
> +#define REFSPEC_FETCH 1
> +#define REFSPEC_PUSH 0

The reversed order of these two definitions looks somewhat unusual.
I guess the reason why you made FETCH true and PUSH false is
probably because quite a lot of places in the existing code we do

	if (fetch)
		do the fetch thing;
 	else
		do the push thing;

i.e. "fetch" variable is used as "is this a fetch: yes/no?"
boolean, and a caller that mysteriously passes "1" (or "0")
is harder to read than necessary.  Being able to pass REFSPEC_PUSH
instead of "0" would certainly make the caller easier to read.  But
as long as the variable is understood as "is_fetch? Yes/no", the
caller can pass Yes or No and be still descriptive enough.

I think the way to make such a code more readable would not be to
rewrite the above to

	if (fetch_or_push)
		do the fetch thing;
 	else
		do the push thing;

Rather it would be 

	if (fetch_or_push == REFSPEC_FETCH)
		do the fetch thing;
 	else
		do the push thing;

And once you have gone that far, the actual "enum" value assignment
no longer makes difference.

> +#define REFSPEC_INIT_FETCH { .fetch = REFSPEC_FETCH }
> +#define REFSPEC_INIT_PUSH { .fetch = REFSPEC_PUSH }
> +
> +struct refspec {
> +	struct refspec_item *items;
> +	int alloc;
> +	int nr;
> +
> +	const char **raw;
> +	int raw_alloc;
> +	int raw_nr;
> +
> +	int fetch;
> +};
> +
> +void refspec_item_init(struct refspec_item *item, const char *refspec, int fetch);
> +void refspec_item_clear(struct refspec_item *item);
> +void refspec_init(struct refspec *rs, int fetch);
> +void refspec_append(struct refspec *rs, const char *refspec);
> +void refspec_appendn(struct refspec *rs, const char **refspecs, int nr);
> +void refspec_clear(struct refspec *rs);
> +
>  #endif /* REFSPEC_H */

^ permalink raw reply	[flat|nested] 112+ messages in thread

* Re: [PATCH 05/35] refspec: convert valid_fetch_refspec to use parse_refspec
  2018-05-14 21:55 ` [PATCH 05/35] refspec: convert valid_fetch_refspec to use parse_refspec Brandon Williams
@ 2018-05-15  9:41   ` Junio C Hamano
  0 siblings, 0 replies; 112+ messages in thread
From: Junio C Hamano @ 2018-05-15  9:41 UTC (permalink / raw)
  To: Brandon Williams; +Cc: git

Brandon Williams <bmwill@google.com> writes:

> Convert 'valid_fetch_refspec()' to use the new 'parse_refspec()'
> function to only parse a single refspec an eliminate an allocation.

s/an/and/, perhaps?

> -int valid_fetch_refspec(const char *fetch_refspec_str)
> -{
> -	struct refspec_item *refspec;
> -
> -	refspec = parse_refspec_internal(1, &fetch_refspec_str, 1, 1);
> -	free_refspec(1, refspec);
> -	return !!refspec;
> -}
> -
>  struct refspec_item *parse_fetch_refspec(int nr_refspec, const char **refspec)
>  {
>  	return parse_refspec_internal(nr_refspec, refspec, 1, 0);
> @@ -242,3 +233,11 @@ void refspec_clear(struct refspec *rs)
>  
>  	rs->fetch = 0;
>  }
> +
> +int valid_fetch_refspec(const char *fetch_refspec_str)
> +{
> +	struct refspec_item refspec;
> +	int ret = parse_refspec(&refspec, fetch_refspec_str, REFSPEC_FETCH);
> +	refspec_item_clear(&refspec);
> +	return ret;
> +}

Makes quite a lot of sense.  The function name may eventually want
to become parse_refspec_item(), though?



^ permalink raw reply	[flat|nested] 112+ messages in thread

* Re: [PATCH 01/35] refspec: move refspec parsing logic into its own file
  2018-05-15  8:06   ` Junio C Hamano
@ 2018-05-15 16:51     ` Brandon Williams
  2018-05-16  0:40       ` Junio C Hamano
  0 siblings, 1 reply; 112+ messages in thread
From: Brandon Williams @ 2018-05-15 16:51 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git

On 05/15, Junio C Hamano wrote:
> Brandon Williams <bmwill@google.com> writes:
> 
> > In preperation for performing a refactor on refspec related code, move
> 
> Preparation?

Oops, I'll fix that.


-- 
Brandon Williams

^ permalink raw reply	[flat|nested] 112+ messages in thread

* Re: [PATCH 35/35] submodule: convert push_unpushed_submodules to take a struct refspec
  2018-05-15  8:11   ` Ævar Arnfjörð Bjarmason
@ 2018-05-15 16:52     ` Stefan Beller
  2018-05-15 16:59     ` Brandon Williams
  1 sibling, 0 replies; 112+ messages in thread
From: Stefan Beller @ 2018-05-15 16:52 UTC (permalink / raw)
  To: Ævar Arnfjörð Bjarmason; +Cc: Brandon Williams, git

On Tue, May 15, 2018 at 1:11 AM, Ævar Arnfjörð Bjarmason
<avarab@gmail.com> wrote:
>
> On Mon, May 14 2018, Brandon Williams wrote:
>
>> Convert 'push_unpushed_submodules()' to take a 'struct refspec' as a
>> parameter instead of an array of 'const char *'.
>> [...]
>> diff --git a/submodule.h b/submodule.h
>> index e5526f6aa..aae0c9c8f 100644
>> --- a/submodule.h
>> +++ b/submodule.h
>> @@ -100,9 +100,10 @@ extern int submodule_touches_in_range(struct object_id *a,
>>  extern int find_unpushed_submodules(struct oid_array *commits,
>>                                   const char *remotes_name,
>>                                   struct string_list *needs_pushing);
>> +struct refspec;
>>  extern int push_unpushed_submodules(struct oid_array *commits,
>>                                   const struct remote *remote,
>> -                                 const char **refspec, int refspec_nr,
>> +                                 const struct refspec *rs,
>>                                   const struct string_list *push_options,
>>                                   int dry_run);
>>  /*
>
> Why do you prefer doing this to having this on top?:

The fewer includes in header files the better, as then the headers
themselves don't have dependencies. (Otherwise we'd end up
multiplying cache.h ;)

In the source files we have to include all needed headers, but for
the headers, it is better if we can just get away with declaring the
existence of a struct.

This way we reduce compile time, so I'd am not keen on your patch
on top.

This is discussed a lot on stackoverflow, e.g.:
https://softwareengineering.stackexchange.com/questions/195806/forward-declaration-vs-include
https://stackoverflow.com/a/15828094

Stefan

^ permalink raw reply	[flat|nested] 112+ messages in thread

* Re: [PATCH 35/35] submodule: convert push_unpushed_submodules to take a struct refspec
  2018-05-15  8:11   ` Ævar Arnfjörð Bjarmason
  2018-05-15 16:52     ` Stefan Beller
@ 2018-05-15 16:59     ` Brandon Williams
  1 sibling, 0 replies; 112+ messages in thread
From: Brandon Williams @ 2018-05-15 16:59 UTC (permalink / raw)
  To: Ævar Arnfjörð Bjarmason; +Cc: git

On 05/15, Ævar Arnfjörð Bjarmason wrote:
> 
> On Mon, May 14 2018, Brandon Williams wrote:
> 
> > Convert 'push_unpushed_submodules()' to take a 'struct refspec' as a
> > parameter instead of an array of 'const char *'.
> > [...]
> > diff --git a/submodule.h b/submodule.h
> > index e5526f6aa..aae0c9c8f 100644
> > --- a/submodule.h
> > +++ b/submodule.h
> > @@ -100,9 +100,10 @@ extern int submodule_touches_in_range(struct object_id *a,
> >  extern int find_unpushed_submodules(struct oid_array *commits,
> >  				    const char *remotes_name,
> >  				    struct string_list *needs_pushing);
> > +struct refspec;
> >  extern int push_unpushed_submodules(struct oid_array *commits,
> >  				    const struct remote *remote,
> > -				    const char **refspec, int refspec_nr,
> > +				    const struct refspec *rs,
> >  				    const struct string_list *push_options,
> >  				    int dry_run);
> >  /*
> 
> Why do you prefer doing this to having this on top?:
>     
>     diff --git a/submodule.h b/submodule.h
>     index aae0c9c8ff..c3f206ce17 100644
>     --- a/submodule.h
>     +++ b/submodule.h
>     @@ -1,5 +1,6 @@
>      #ifndef SUBMODULE_H
>      #define SUBMODULE_H
>     +#include "refspec.h"
>      
>      struct repository;
>      struct diff_options;
>     @@ -100,7 +101,6 @@ extern int submodule_touches_in_range(struct object_id *a,
>      extern int find_unpushed_submodules(struct oid_array *commits,
>                                         const char *remotes_name,
>                                         struct string_list *needs_pushing);
>     -struct refspec;
>      extern int push_unpushed_submodules(struct oid_array *commits,
>                                         const struct remote *remote,
>                                         const struct refspec *rs,

Basically for the reason that stefan pointed out, though in practice I
don't know how much that would actually impact compile times given we
already are including cache.h and a bunch of others everywhere.

-- 
Brandon Williams

^ permalink raw reply	[flat|nested] 112+ messages in thread

* Re: [PATCH 14/35] remote: convert fetch refspecs to struct refspec
  2018-05-15  8:31   ` Ævar Arnfjörð Bjarmason
@ 2018-05-15 17:57     ` Brandon Williams
  0 siblings, 0 replies; 112+ messages in thread
From: Brandon Williams @ 2018-05-15 17:57 UTC (permalink / raw)
  To: Ævar Arnfjörð Bjarmason; +Cc: git

On 05/15, Ævar Arnfjörð Bjarmason wrote:
> 
> On Mon, May 14 2018, Brandon Williams wrote:
> 
> >  void add_prune_tags_to_fetch_refspec(struct remote *remote)
> >  {
> > -	int nr = remote->fetch_refspec_nr;
> > -	int bufsize = nr  + 1;
> > -	int size = sizeof(struct refspec_item);
> > -
> > -	remote->fetch = xrealloc(remote->fetch, size  * bufsize);
> > -	memcpy(&remote->fetch[nr], tag_refspec, size);
> > -	add_fetch_refspec(remote, xstrdup(TAG_REFSPEC));
> > +	refspec_append(&remote->fetch, TAG_REFSPEC);
> >  }
> 
> Thanks for fixing the hack I needed to put in place in 97716d217c
> ("fetch: add a --prune-tags option and fetch.pruneTags config",
> 2018-02-09).
> 
> I'm not sure where it belongs in this series, but I think this makes
> sense on top of the whole thing:

This actually would work well immediately after this patch, so I'll add
it here :)

Thanks!

> 
>     diff --git a/builtin/fetch.c b/builtin/fetch.c
>     index af7064dce3..9a523249f5 100644
>     --- a/builtin/fetch.c
>     +++ b/builtin/fetch.c
>     @@ -1383,7 +1383,8 @@ static int fetch_one(struct remote *remote, int argc, const char **argv, int pru
> 
>             maybe_prune_tags = prune_tags_ok && prune_tags;
>             if (maybe_prune_tags && remote_via_config)
>     -               add_prune_tags_to_fetch_refspec(remote);
>     +               refspec_append(&remote->fetch, TAG_REFSPEC);
>     +
> 
>             if (maybe_prune_tags && (argc || !remote_via_config))
>                     refspec_append(&rs, TAG_REFSPEC);
>     diff --git a/remote.c b/remote.c
>     index 8e6522f4d0..946b95d18d 100644
>     --- a/remote.c
>     +++ b/remote.c
>     @@ -87,11 +87,6 @@ static void add_fetch_refspec(struct remote *remote, const char *ref)
>             refspec_append(&remote->fetch, ref);
>      }
> 
>     -void add_prune_tags_to_fetch_refspec(struct remote *remote)
>     -{
>     -       refspec_append(&remote->fetch, TAG_REFSPEC);
>     -}
>     -
>      static void add_url(struct remote *remote, const char *url)
>      {
>             ALLOC_GROW(remote->url, remote->url_nr + 1, remote->url_alloc);
>     diff --git a/remote.h b/remote.h
>     index 9014f707f0..62a6566594 100644
>     --- a/remote.h
>     +++ b/remote.h
>     @@ -289,6 +289,4 @@ extern int parseopt_push_cas_option(const struct option *, const char *arg, int
>      extern int is_empty_cas(const struct push_cas_option *);
>      void apply_push_cas(struct push_cas_option *, struct remote *, struct ref *);
> 
>     -void add_prune_tags_to_fetch_refspec(struct remote *remote);
>     -
>      #endif
> 
> I.e. the whole reason we have this function is because of my above
> commit where I had to very carefully hack around the fact that we didn't
> have something which could ALLOW_GROW() the structure after it had been
> created.
> 
> So I added the add_prune_tags_to_fetch_refspec() function to very
> carefully do *only* that so others wouldn't be tempted to use this hack
> more generally.
> 
> But now we have a nice API for it, so we can just throw away the
> wrapper, and use the same API everywhere. You already did the other half
> of that in your e69b54f53a ("fetch: convert fetch_one to use struct
> refspec", 2018-05-11).

-- 
Brandon Williams

^ permalink raw reply	[flat|nested] 112+ messages in thread

* Re: [PATCH 00/35] refactoring refspecs
  2018-05-15  8:39 ` Ævar Arnfjörð Bjarmason
@ 2018-05-15 18:01   ` Brandon Williams
  0 siblings, 0 replies; 112+ messages in thread
From: Brandon Williams @ 2018-05-15 18:01 UTC (permalink / raw)
  To: Ævar Arnfjörð Bjarmason; +Cc: git

On 05/15, Ævar Arnfjörð Bjarmason wrote:
> 
> On Mon, May 14 2018, Brandon Williams wrote:
> 
> > When working on protocol v2 I noticed that working with refspecs was a
> > little difficult because of the various api's that existed.  Some
> > functions expected an array of "const char *" while others expected an
> > array of "struct refspec".  In all cases a length parameter needed to be
> > passed as a parameter as well.  This makes working with refspecs a
> > little challenging because of the different expectations different parts
> > of the code base have.
> >
> > This series refactors how refspecs are handled through out the code base
> > by renaming the existing struct refspec to refspec_item and introducing
> > a new 'struct refspec' which is a container of refspec_items, much like
> > how a pathspec contains pathspec_items.  This simplifies many callers
> > and makes handling pathspecs a bit easier.
> 
> This looks really good to me. The API you're replacing is one of the
> worst I've had a chance to encounter in git.git (as noted in my
> https://public-inbox.org/git/87in7p2ucb.fsf@evledraar.gmail.com/ but
> maybe I haven't looked widely enough), and now it's really nice.

Thanks! Yeah its one of the rougher edges I've worked with and I'm glad
I finally got around to fixing it.

> 
> > I have some follow on work which I'll build on top of this series, but
> > since this was already getting a bit lengthy at 35 patches I'll save
> > that for another time.
> 
> In addition to my other suggestions for stuff to put on top, which I see
> now you may have just had in your local tree but didn't submit, I think
> this makes sense:

Yes these changes make sense, though I'll need to tweak them to avoid
some memory leaks.  I'll probably go ahead and squash it into the two
patches which effect those two functions.

Thanks for catching this.

> 
>     diff --git a/remote.c b/remote.c
>     index 946b95d18d..cb97e662e8 100644
>     --- a/remote.c
>     +++ b/remote.c
>     @@ -77,16 +77,6 @@ static const char *alias_url(const char *url, struct rewrites *r)
>      	return xstrfmt("%s%s", r->rewrite[longest_i]->base, url + longest->len);
>      }
> 
>     -static void add_push_refspec(struct remote *remote, const char *ref)
>     -{
>     -	refspec_append(&remote->push, ref);
>     -}
>     -
>     -static void add_fetch_refspec(struct remote *remote, const char *ref)
>     -{
>     -	refspec_append(&remote->fetch, ref);
>     -}
>     -
>      static void add_url(struct remote *remote, const char *url)
>      {
>      	ALLOC_GROW(remote->url, remote->url_nr + 1, remote->url_alloc);
>     @@ -261,9 +251,9 @@ static void read_remotes_file(struct remote *remote)
>      		if (skip_prefix(buf.buf, "URL:", &v))
>      			add_url_alias(remote, xstrdup(skip_spaces(v)));
>      		else if (skip_prefix(buf.buf, "Push:", &v))
>     -			add_push_refspec(remote, xstrdup(skip_spaces(v)));
>     +			refspec_append(&remote->push, xstrdup(skip_spaces(v)));
>      		else if (skip_prefix(buf.buf, "Pull:", &v))
>     -			add_fetch_refspec(remote, xstrdup(skip_spaces(v)));
>     +			refspec_append(&remote->fetch, xstrdup(skip_spaces(v)));
>      	}
>      	strbuf_release(&buf);
>      	fclose(f);
>     @@ -302,14 +292,14 @@ static void read_branches_file(struct remote *remote)
>      		frag = "master";
> 
>      	add_url_alias(remote, strbuf_detach(&buf, NULL));
>     -	add_fetch_refspec(remote, xstrfmt("refs/heads/%s:refs/heads/%s",
>     -					  frag, remote->name));
>     +	refspec_append(&remote->fetch, xstrfmt("refs/heads/%s:refs/heads/%s",
>     +					       frag, remote->name));
> 
>      	/*
>      	 * Cogito compatible push: push current HEAD to remote #branch
>      	 * (master if missing)
>      	 */
>     -	add_push_refspec(remote, xstrfmt("HEAD:refs/heads/%s", frag));
>     +	refspec_append(&remote->push, xstrfmt("HEAD:refs/heads/%s", frag));
>      	remote->fetch_tags = 1; /* always auto-follow */
>      }
> 
>     @@ -395,12 +385,12 @@ static int handle_config(const char *key, const char *value, void *cb)
>      		const char *v;
>      		if (git_config_string(&v, key, value))
>      			return -1;
>     -		add_push_refspec(remote, v);
>     +		refspec_append(&remote->push, v);
>      	} else if (!strcmp(subkey, "fetch")) {
>      		const char *v;
>      		if (git_config_string(&v, key, value))
>      			return -1;
>     -		add_fetch_refspec(remote, v);
>     +		refspec_append(&remote->fetch, v);
>      	} else if (!strcmp(subkey, "receivepack")) {
>      		const char *v;
>      		if (git_config_string(&v, key, value))
> 
> I.e. the reason we have add_{push,fetch}_refspec() in the first place is
> because without your series it's tricky to add new ones, but now it's
> trivial, so let's not leave behind wrapper static functions whose sole
> purpose is to just call another exported API as-is.
> 
> I've pushed all the patches I quoted inline in this review at
> avar-bwill/refspec in github.com/avar/git, consider them all signed-off,
> and depending on whether you agree/disagree etc. please squash
> them/adapt them/drop them however you see fit.

-- 
Brandon Williams

^ permalink raw reply	[flat|nested] 112+ messages in thread

* Re: [PATCH 03/35] refspec: rename struct refspec to struct refspec_item
  2018-05-15  8:17   ` Junio C Hamano
@ 2018-05-15 18:19     ` Brandon Williams
  0 siblings, 0 replies; 112+ messages in thread
From: Brandon Williams @ 2018-05-15 18:19 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git

On 05/15, Junio C Hamano wrote:
> Brandon Williams <bmwill@google.com> writes:
> 
> > In preperation for introducing an abstraction around a collection of
> > refspecs (much like how a 'struct pathspec' is a collection of 'struct
> > pathspec_item's) rename the existing 'struct refspec' to 'struct
> > refspec_item'.
> 
> Makes sense.
> 
> >  /* See TAG_REFSPEC for the string version */
> > -const struct refspec *tag_refspec = &s_tag_refspec;
> > +const struct refspec_item *tag_refspec = &s_tag_refspec;
> >  
> >  /*
> >   * Parses 'refspec' and populates 'rs'.  returns 1 if successful and 0 if the
> >   * refspec is invalid.
> >   */
> > -static int parse_refspec(struct refspec *rs, const char *refspec, int fetch)
> > +static int parse_refspec(struct refspec_item *rs, const char *refspec, int fetch)
> 
> The new comment given to the function in the previous step talks
> in terms of the variable name and not type, so technically it is
> still valid after this change without updating.
> 
> I however wonder if it makes more sense to go one step further and
> rename the "const char *" variable that is a string form of a single
> refspec item to something other than "refspec".  Which would
> invalidate the commit you gave to the function and make it necessary
> to be updated in this step.
> 
> I wonder if the early part of the series becomes easier to read if
> patches 2 and 3 are swapped.  That may result in less code/comment
> churn.

I'll go ahead and switch these two patches and fixup the comment and
function name.

-- 
Brandon Williams

^ permalink raw reply	[flat|nested] 112+ messages in thread

* Re: [PATCH 04/35] refspec: introduce struct refspec
  2018-05-15  9:37   ` Junio C Hamano
@ 2018-05-15 18:37     ` Brandon Williams
  0 siblings, 0 replies; 112+ messages in thread
From: Brandon Williams @ 2018-05-15 18:37 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git

On 05/15, Junio C Hamano wrote:
> Brandon Williams <bmwill@google.com> writes:
> 
> > diff --git a/refspec.h b/refspec.h
> > index 173cea882..f6fb251f3 100644
> > --- a/refspec.h
> > +++ b/refspec.h
> > @@ -20,4 +20,29 @@ struct refspec_item *parse_push_refspec(int nr_refspec, const char **refspec);
> >  
> >  void free_refspec(int nr_refspec, struct refspec_item *refspec);
> >  
> > +#define REFSPEC_FETCH 1
> > +#define REFSPEC_PUSH 0
> 
> The reversed order of these two definitions looks somewhat unusual.
> I guess the reason why you made FETCH true and PUSH false is
> probably because quite a lot of places in the existing code we do

Yeah I really just made the choice based on what the existing logic did
(parse_refspec takes in a parameter 'fetch' which is 1 if we are parsing
the refspec for a fetch and 0 for push).  So it wouldn't be too
difficult to go and make this change here since all future callers use
the #defines themselves, because it is significantly easier to read
'REFSPEC_PUSH' than to read a 0 like you point out below :)

> 
> 	if (fetch)
> 		do the fetch thing;
>  	else
> 		do the push thing;
> 
> i.e. "fetch" variable is used as "is this a fetch: yes/no?"
> boolean, and a caller that mysteriously passes "1" (or "0")
> is harder to read than necessary.  Being able to pass REFSPEC_PUSH
> instead of "0" would certainly make the caller easier to read.  But
> as long as the variable is understood as "is_fetch? Yes/no", the
> caller can pass Yes or No and be still descriptive enough.
> 
> I think the way to make such a code more readable would not be to
> rewrite the above to
> 
> 	if (fetch_or_push)
> 		do the fetch thing;
>  	else
> 		do the push thing;
> 
> Rather it would be 
> 
> 	if (fetch_or_push == REFSPEC_FETCH)
> 		do the fetch thing;
>  	else
> 		do the push thing;
> 
> And once you have gone that far, the actual "enum" value assignment
> no longer makes difference.
> 
> > +#define REFSPEC_INIT_FETCH { .fetch = REFSPEC_FETCH }
> > +#define REFSPEC_INIT_PUSH { .fetch = REFSPEC_PUSH }
> > +
> > +struct refspec {
> > +	struct refspec_item *items;
> > +	int alloc;
> > +	int nr;
> > +
> > +	const char **raw;
> > +	int raw_alloc;
> > +	int raw_nr;
> > +
> > +	int fetch;
> > +};
> > +
> > +void refspec_item_init(struct refspec_item *item, const char *refspec, int fetch);
> > +void refspec_item_clear(struct refspec_item *item);
> > +void refspec_init(struct refspec *rs, int fetch);
> > +void refspec_append(struct refspec *rs, const char *refspec);
> > +void refspec_appendn(struct refspec *rs, const char **refspecs, int nr);
> > +void refspec_clear(struct refspec *rs);
> > +
> >  #endif /* REFSPEC_H */

-- 
Brandon Williams

^ permalink raw reply	[flat|nested] 112+ messages in thread

* Re: [PATCH 01/35] refspec: move refspec parsing logic into its own file
  2018-05-15 16:51     ` Brandon Williams
@ 2018-05-16  0:40       ` Junio C Hamano
  0 siblings, 0 replies; 112+ messages in thread
From: Junio C Hamano @ 2018-05-16  0:40 UTC (permalink / raw)
  To: Brandon Williams; +Cc: git

Brandon Williams <bmwill@google.com> writes:

> On 05/15, Junio C Hamano wrote:
>> Brandon Williams <bmwill@google.com> writes:
>> 
>> > In preperation for performing a refactor on refspec related code, move
>> 
>> Preparation?
>
> Oops, I'll fix that.

Thanks.  And sorry for forcing you to page thru 600+ lines only to
find that I commented on only that line.  I'll try harder to make
sure I trim quotes from my responses.


^ permalink raw reply	[flat|nested] 112+ messages in thread

* [PATCH v2 00/36] refactoring refspecs
  2018-05-14 21:55 [PATCH 00/35] refactoring refspecs Brandon Williams
                   ` (37 preceding siblings ...)
  2018-05-15  8:39 ` Ævar Arnfjörð Bjarmason
@ 2018-05-16 22:57 ` Brandon Williams
  2018-05-16 22:57   ` [PATCH v2 01/36] refspec: move refspec parsing logic into its own file Brandon Williams
                     ` (36 more replies)
  38 siblings, 37 replies; 112+ messages in thread
From: Brandon Williams @ 2018-05-16 22:57 UTC (permalink / raw)
  To: git, avarab, gitster, sbeller, bmwill
  Cc: avarab, gitster, sbeller, Brandon Williams

Changes in v2:
 * added missing extern keyword in the first patch
 * reordered patch 2 and 3 and updated some comments to be clearer.
 * fixed some memory leaks
 * squashed in some changes recommended by Aevar 

Brandon Williams (36):
  refspec: move refspec parsing logic into its own file
  refspec: rename struct refspec to struct refspec_item
  refspec: factor out parsing a single refspec
  refspec: introduce struct refspec
  refspec: convert valid_fetch_refspec to use parse_refspec
  submodule--helper: convert push_check to use struct refspec
  pull: convert get_tracking_branch to use refspec_item_init
  transport: convert transport_push to use struct refspec
  remote: convert check_push_refs to use struct refspec
  remote: convert match_push_refs to use struct refspec
  clone: convert cmd_clone to use refspec_item_init
  fast-export: convert to use struct refspec
  remote: convert push refspecs to struct refspec
  remote: convert fetch refspecs to struct refspec
  remote: remove add_prune_tags_to_fetch_refspec
  transport-helper: convert to use struct refspec
  fetch: convert fetch_one to use struct refspec
  fetch: convert refmap to use struct refspec
  refspec: remove the deprecated functions
  fetch: convert do_fetch to take a struct refspec
  fetch: convert get_ref_map to take a struct refspec
  fetch: convert prune_refs to take a struct refspec
  remote: convert get_stale_heads to take a struct refspec
  remote: convert apply_refspecs to take a struct refspec
  remote: convert query_refspecs to take a struct refspec
  remote: convert get_ref_match to take a struct refspec
  remote: convert match_explicit_refs to take a struct refspec
  push: check for errors earlier
  push: convert to use struct refspec
  transport: convert transport_push to take a struct refspec
  send-pack: store refspecs in a struct refspec
  transport: remove transport_verify_remote_names
  http-push: store refspecs in a struct refspec
  remote: convert match_push_refs to take a struct refspec
  remote: convert check_push_refs to take a struct refspec
  submodule: convert push_unpushed_submodules to take a struct refspec

 Makefile                    |   1 +
 branch.c                    |   7 +-
 builtin/clone.c             |  13 +-
 builtin/fast-export.c       |  22 +--
 builtin/fetch.c             | 134 ++++++--------
 builtin/merge.c             |   1 +
 builtin/pull.c              |   9 +-
 builtin/push.c              |  80 ++++----
 builtin/remote.c            |  37 ++--
 builtin/send-pack.c         |  24 +--
 builtin/submodule--helper.c |  14 +-
 checkout.c                  |   5 +-
 http-push.c                 |  18 +-
 refspec.c                   | 194 ++++++++++++++++++++
 refspec.h                   |  44 +++++
 remote.c                    | 353 ++++++++----------------------------
 remote.h                    |  50 ++---
 submodule.c                 |  19 +-
 submodule.h                 |   3 +-
 transport-helper.c          |  39 ++--
 transport.c                 |  51 ++----
 transport.h                 |   4 +-
 22 files changed, 527 insertions(+), 595 deletions(-)
 create mode 100644 refspec.c
 create mode 100644 refspec.h

-- 
2.17.0.441.gb46fe60e1d-goog


^ permalink raw reply	[flat|nested] 112+ messages in thread

* [PATCH v2 01/36] refspec: move refspec parsing logic into its own file
  2018-05-16 22:57 ` [PATCH v2 00/36] " Brandon Williams
@ 2018-05-16 22:57   ` Brandon Williams
  2018-05-16 22:57   ` [PATCH v2 02/36] refspec: rename struct refspec to struct refspec_item Brandon Williams
                     ` (35 subsequent siblings)
  36 siblings, 0 replies; 112+ messages in thread
From: Brandon Williams @ 2018-05-16 22:57 UTC (permalink / raw)
  To: git, avarab, gitster, sbeller, bmwill
  Cc: avarab, gitster, sbeller, Brandon Williams

In preparation for performing a refactor on refspec related code, move
the refspec parsing logic into its own file.

Signed-off-by: Brandon Williams <bmwill@google.com>
---
 Makefile                    |   1 +
 branch.c                    |   1 +
 builtin/clone.c             |   1 +
 builtin/fast-export.c       |   1 +
 builtin/fetch.c             |   1 +
 builtin/merge.c             |   1 +
 builtin/pull.c              |   1 +
 builtin/push.c              |   1 +
 builtin/remote.c            |   1 +
 builtin/submodule--helper.c |   1 +
 checkout.c                  |   1 +
 refspec.c                   | 168 ++++++++++++++++++++++++++++++++++++
 refspec.h                   |  23 +++++
 remote.c                    | 165 +----------------------------------
 remote.h                    |  20 -----
 transport-helper.c          |   1 +
 transport.c                 |   1 +
 17 files changed, 205 insertions(+), 184 deletions(-)
 create mode 100644 refspec.c
 create mode 100644 refspec.h

diff --git a/Makefile b/Makefile
index ad880d1fc..4bca65383 100644
--- a/Makefile
+++ b/Makefile
@@ -928,6 +928,7 @@ LIB_OBJS += refs/files-backend.o
 LIB_OBJS += refs/iterator.o
 LIB_OBJS += refs/packed-backend.o
 LIB_OBJS += refs/ref-cache.o
+LIB_OBJS += refspec.o
 LIB_OBJS += ref-filter.o
 LIB_OBJS += remote.o
 LIB_OBJS += replace-object.o
diff --git a/branch.c b/branch.c
index 2672054f0..32ccefc6b 100644
--- a/branch.c
+++ b/branch.c
@@ -3,6 +3,7 @@
 #include "config.h"
 #include "branch.h"
 #include "refs.h"
+#include "refspec.h"
 #include "remote.h"
 #include "commit.h"
 #include "worktree.h"
diff --git a/builtin/clone.c b/builtin/clone.c
index 84f1473d1..6d1614ed3 100644
--- a/builtin/clone.c
+++ b/builtin/clone.c
@@ -14,6 +14,7 @@
 #include "parse-options.h"
 #include "fetch-pack.h"
 #include "refs.h"
+#include "refspec.h"
 #include "tree.h"
 #include "tree-walk.h"
 #include "unpack-trees.h"
diff --git a/builtin/fast-export.c b/builtin/fast-export.c
index 530df12f0..a13b7c8ef 100644
--- a/builtin/fast-export.c
+++ b/builtin/fast-export.c
@@ -7,6 +7,7 @@
 #include "cache.h"
 #include "config.h"
 #include "refs.h"
+#include "refspec.h"
 #include "commit.h"
 #include "object.h"
 #include "tag.h"
diff --git a/builtin/fetch.c b/builtin/fetch.c
index 7ee83ac0f..1fce68e9a 100644
--- a/builtin/fetch.c
+++ b/builtin/fetch.c
@@ -5,6 +5,7 @@
 #include "config.h"
 #include "repository.h"
 #include "refs.h"
+#include "refspec.h"
 #include "commit.h"
 #include "builtin.h"
 #include "string-list.h"
diff --git a/builtin/merge.c b/builtin/merge.c
index 9db5a2cf1..c362cfe90 100644
--- a/builtin/merge.c
+++ b/builtin/merge.c
@@ -14,6 +14,7 @@
 #include "run-command.h"
 #include "diff.h"
 #include "refs.h"
+#include "refspec.h"
 #include "commit.h"
 #include "diffcore.h"
 #include "revision.h"
diff --git a/builtin/pull.c b/builtin/pull.c
index 71aac5005..6247c956d 100644
--- a/builtin/pull.c
+++ b/builtin/pull.c
@@ -15,6 +15,7 @@
 #include "remote.h"
 #include "dir.h"
 #include "refs.h"
+#include "refspec.h"
 #include "revision.h"
 #include "submodule.h"
 #include "submodule-config.h"
diff --git a/builtin/push.c b/builtin/push.c
index ac3705370..fa65999b2 100644
--- a/builtin/push.c
+++ b/builtin/push.c
@@ -4,6 +4,7 @@
 #include "cache.h"
 #include "config.h"
 #include "refs.h"
+#include "refspec.h"
 #include "run-command.h"
 #include "builtin.h"
 #include "remote.h"
diff --git a/builtin/remote.c b/builtin/remote.c
index 8708e584e..c49513995 100644
--- a/builtin/remote.c
+++ b/builtin/remote.c
@@ -7,6 +7,7 @@
 #include "strbuf.h"
 #include "run-command.h"
 #include "refs.h"
+#include "refspec.h"
 #include "argv-array.h"
 
 static const char * const builtin_remote_usage[] = {
diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
index c2403a915..6ab032acb 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -12,6 +12,7 @@
 #include "run-command.h"
 #include "remote.h"
 #include "refs.h"
+#include "refspec.h"
 #include "connect.h"
 #include "revision.h"
 #include "diffcore.h"
diff --git a/checkout.c b/checkout.c
index ac42630f7..193ba8567 100644
--- a/checkout.c
+++ b/checkout.c
@@ -1,5 +1,6 @@
 #include "cache.h"
 #include "remote.h"
+#include "refspec.h"
 #include "checkout.h"
 
 struct tracking_name_data {
diff --git a/refspec.c b/refspec.c
new file mode 100644
index 000000000..ecb0bdff3
--- /dev/null
+++ b/refspec.c
@@ -0,0 +1,168 @@
+#include "cache.h"
+#include "refs.h"
+#include "refspec.h"
+
+static struct refspec s_tag_refspec = {
+	0,
+	1,
+	0,
+	0,
+	"refs/tags/*",
+	"refs/tags/*"
+};
+
+/* See TAG_REFSPEC for the string version */
+const struct refspec *tag_refspec = &s_tag_refspec;
+
+static struct refspec *parse_refspec_internal(int nr_refspec, const char **refspec, int fetch, int verify)
+{
+	int i;
+	struct refspec *rs = xcalloc(nr_refspec, sizeof(*rs));
+
+	for (i = 0; i < nr_refspec; i++) {
+		size_t llen;
+		int is_glob;
+		const char *lhs, *rhs;
+		int flags;
+
+		is_glob = 0;
+
+		lhs = refspec[i];
+		if (*lhs == '+') {
+			rs[i].force = 1;
+			lhs++;
+		}
+
+		rhs = strrchr(lhs, ':');
+
+		/*
+		 * Before going on, special case ":" (or "+:") as a refspec
+		 * for pushing matching refs.
+		 */
+		if (!fetch && rhs == lhs && rhs[1] == '\0') {
+			rs[i].matching = 1;
+			continue;
+		}
+
+		if (rhs) {
+			size_t rlen = strlen(++rhs);
+			is_glob = (1 <= rlen && strchr(rhs, '*'));
+			rs[i].dst = xstrndup(rhs, rlen);
+		}
+
+		llen = (rhs ? (rhs - lhs - 1) : strlen(lhs));
+		if (1 <= llen && memchr(lhs, '*', llen)) {
+			if ((rhs && !is_glob) || (!rhs && fetch))
+				goto invalid;
+			is_glob = 1;
+		} else if (rhs && is_glob) {
+			goto invalid;
+		}
+
+		rs[i].pattern = is_glob;
+		rs[i].src = xstrndup(lhs, llen);
+		flags = REFNAME_ALLOW_ONELEVEL | (is_glob ? REFNAME_REFSPEC_PATTERN : 0);
+
+		if (fetch) {
+			struct object_id unused;
+
+			/* LHS */
+			if (!*rs[i].src)
+				; /* empty is ok; it means "HEAD" */
+			else if (llen == GIT_SHA1_HEXSZ && !get_oid_hex(rs[i].src, &unused))
+				rs[i].exact_sha1 = 1; /* ok */
+			else if (!check_refname_format(rs[i].src, flags))
+				; /* valid looking ref is ok */
+			else
+				goto invalid;
+			/* RHS */
+			if (!rs[i].dst)
+				; /* missing is ok; it is the same as empty */
+			else if (!*rs[i].dst)
+				; /* empty is ok; it means "do not store" */
+			else if (!check_refname_format(rs[i].dst, flags))
+				; /* valid looking ref is ok */
+			else
+				goto invalid;
+		} else {
+			/*
+			 * LHS
+			 * - empty is allowed; it means delete.
+			 * - when wildcarded, it must be a valid looking ref.
+			 * - otherwise, it must be an extended SHA-1, but
+			 *   there is no existing way to validate this.
+			 */
+			if (!*rs[i].src)
+				; /* empty is ok */
+			else if (is_glob) {
+				if (check_refname_format(rs[i].src, flags))
+					goto invalid;
+			}
+			else
+				; /* anything goes, for now */
+			/*
+			 * RHS
+			 * - missing is allowed, but LHS then must be a
+			 *   valid looking ref.
+			 * - empty is not allowed.
+			 * - otherwise it must be a valid looking ref.
+			 */
+			if (!rs[i].dst) {
+				if (check_refname_format(rs[i].src, flags))
+					goto invalid;
+			} else if (!*rs[i].dst) {
+				goto invalid;
+			} else {
+				if (check_refname_format(rs[i].dst, flags))
+					goto invalid;
+			}
+		}
+	}
+	return rs;
+
+ invalid:
+	if (verify) {
+		/*
+		 * nr_refspec must be greater than zero and i must be valid
+		 * since it is only possible to reach this point from within
+		 * the for loop above.
+		 */
+		free_refspec(i+1, rs);
+		return NULL;
+	}
+	die("Invalid refspec '%s'", refspec[i]);
+}
+
+int valid_fetch_refspec(const char *fetch_refspec_str)
+{
+	struct refspec *refspec;
+
+	refspec = parse_refspec_internal(1, &fetch_refspec_str, 1, 1);
+	free_refspec(1, refspec);
+	return !!refspec;
+}
+
+struct refspec *parse_fetch_refspec(int nr_refspec, const char **refspec)
+{
+	return parse_refspec_internal(nr_refspec, refspec, 1, 0);
+}
+
+struct refspec *parse_push_refspec(int nr_refspec, const char **refspec)
+{
+	return parse_refspec_internal(nr_refspec, refspec, 0, 0);
+}
+
+void free_refspec(int nr_refspec, struct refspec *refspec)
+{
+	int i;
+
+	if (!refspec)
+		return;
+
+	for (i = 0; i < nr_refspec; i++) {
+		free(refspec[i].src);
+		free(refspec[i].dst);
+	}
+	free(refspec);
+}
+
diff --git a/refspec.h b/refspec.h
new file mode 100644
index 000000000..62625c23a
--- /dev/null
+++ b/refspec.h
@@ -0,0 +1,23 @@
+#ifndef REFSPEC_H
+#define REFSPEC_H
+
+#define TAG_REFSPEC "refs/tags/*:refs/tags/*"
+extern const struct refspec *tag_refspec;
+
+struct refspec {
+	unsigned force : 1;
+	unsigned pattern : 1;
+	unsigned matching : 1;
+	unsigned exact_sha1 : 1;
+
+	char *src;
+	char *dst;
+};
+
+int valid_fetch_refspec(const char *refspec);
+struct refspec *parse_fetch_refspec(int nr_refspec, const char **refspec);
+struct refspec *parse_push_refspec(int nr_refspec, const char **refspec);
+
+void free_refspec(int nr_refspec, struct refspec *refspec);
+
+#endif /* REFSPEC_H */
diff --git a/remote.c b/remote.c
index 91eb010ca..4d67c061a 100644
--- a/remote.c
+++ b/remote.c
@@ -2,6 +2,7 @@
 #include "config.h"
 #include "remote.h"
 #include "refs.h"
+#include "refspec.h"
 #include "commit.h"
 #include "diff.h"
 #include "revision.h"
@@ -13,18 +14,6 @@
 
 enum map_direction { FROM_SRC, FROM_DST };
 
-static struct refspec s_tag_refspec = {
-	0,
-	1,
-	0,
-	0,
-	"refs/tags/*",
-	"refs/tags/*"
-};
-
-/* See TAG_REFSPEC for the string version */
-const struct refspec *tag_refspec = &s_tag_refspec;
-
 struct counted_string {
 	size_t len;
 	const char *s;
@@ -499,158 +488,6 @@ static void read_config(void)
 	alias_all_urls();
 }
 
-static struct refspec *parse_refspec_internal(int nr_refspec, const char **refspec, int fetch, int verify)
-{
-	int i;
-	struct refspec *rs = xcalloc(nr_refspec, sizeof(*rs));
-
-	for (i = 0; i < nr_refspec; i++) {
-		size_t llen;
-		int is_glob;
-		const char *lhs, *rhs;
-		int flags;
-
-		is_glob = 0;
-
-		lhs = refspec[i];
-		if (*lhs == '+') {
-			rs[i].force = 1;
-			lhs++;
-		}
-
-		rhs = strrchr(lhs, ':');
-
-		/*
-		 * Before going on, special case ":" (or "+:") as a refspec
-		 * for pushing matching refs.
-		 */
-		if (!fetch && rhs == lhs && rhs[1] == '\0') {
-			rs[i].matching = 1;
-			continue;
-		}
-
-		if (rhs) {
-			size_t rlen = strlen(++rhs);
-			is_glob = (1 <= rlen && strchr(rhs, '*'));
-			rs[i].dst = xstrndup(rhs, rlen);
-		}
-
-		llen = (rhs ? (rhs - lhs - 1) : strlen(lhs));
-		if (1 <= llen && memchr(lhs, '*', llen)) {
-			if ((rhs && !is_glob) || (!rhs && fetch))
-				goto invalid;
-			is_glob = 1;
-		} else if (rhs && is_glob) {
-			goto invalid;
-		}
-
-		rs[i].pattern = is_glob;
-		rs[i].src = xstrndup(lhs, llen);
-		flags = REFNAME_ALLOW_ONELEVEL | (is_glob ? REFNAME_REFSPEC_PATTERN : 0);
-
-		if (fetch) {
-			struct object_id unused;
-
-			/* LHS */
-			if (!*rs[i].src)
-				; /* empty is ok; it means "HEAD" */
-			else if (llen == GIT_SHA1_HEXSZ && !get_oid_hex(rs[i].src, &unused))
-				rs[i].exact_sha1 = 1; /* ok */
-			else if (!check_refname_format(rs[i].src, flags))
-				; /* valid looking ref is ok */
-			else
-				goto invalid;
-			/* RHS */
-			if (!rs[i].dst)
-				; /* missing is ok; it is the same as empty */
-			else if (!*rs[i].dst)
-				; /* empty is ok; it means "do not store" */
-			else if (!check_refname_format(rs[i].dst, flags))
-				; /* valid looking ref is ok */
-			else
-				goto invalid;
-		} else {
-			/*
-			 * LHS
-			 * - empty is allowed; it means delete.
-			 * - when wildcarded, it must be a valid looking ref.
-			 * - otherwise, it must be an extended SHA-1, but
-			 *   there is no existing way to validate this.
-			 */
-			if (!*rs[i].src)
-				; /* empty is ok */
-			else if (is_glob) {
-				if (check_refname_format(rs[i].src, flags))
-					goto invalid;
-			}
-			else
-				; /* anything goes, for now */
-			/*
-			 * RHS
-			 * - missing is allowed, but LHS then must be a
-			 *   valid looking ref.
-			 * - empty is not allowed.
-			 * - otherwise it must be a valid looking ref.
-			 */
-			if (!rs[i].dst) {
-				if (check_refname_format(rs[i].src, flags))
-					goto invalid;
-			} else if (!*rs[i].dst) {
-				goto invalid;
-			} else {
-				if (check_refname_format(rs[i].dst, flags))
-					goto invalid;
-			}
-		}
-	}
-	return rs;
-
- invalid:
-	if (verify) {
-		/*
-		 * nr_refspec must be greater than zero and i must be valid
-		 * since it is only possible to reach this point from within
-		 * the for loop above.
-		 */
-		free_refspec(i+1, rs);
-		return NULL;
-	}
-	die("Invalid refspec '%s'", refspec[i]);
-}
-
-int valid_fetch_refspec(const char *fetch_refspec_str)
-{
-	struct refspec *refspec;
-
-	refspec = parse_refspec_internal(1, &fetch_refspec_str, 1, 1);
-	free_refspec(1, refspec);
-	return !!refspec;
-}
-
-struct refspec *parse_fetch_refspec(int nr_refspec, const char **refspec)
-{
-	return parse_refspec_internal(nr_refspec, refspec, 1, 0);
-}
-
-struct refspec *parse_push_refspec(int nr_refspec, const char **refspec)
-{
-	return parse_refspec_internal(nr_refspec, refspec, 0, 0);
-}
-
-void free_refspec(int nr_refspec, struct refspec *refspec)
-{
-	int i;
-
-	if (!refspec)
-		return;
-
-	for (i = 0; i < nr_refspec; i++) {
-		free(refspec[i].src);
-		free(refspec[i].dst);
-	}
-	free(refspec);
-}
-
 static int valid_remote_nick(const char *name)
 {
 	if (!name[0] || is_dot_or_dotdot(name))
diff --git a/remote.h b/remote.h
index 2b3180f94..386ced901 100644
--- a/remote.h
+++ b/remote.h
@@ -68,18 +68,6 @@ int for_each_remote(each_remote_fn fn, void *priv);
 
 int remote_has_url(struct remote *remote, const char *url);
 
-struct refspec {
-	unsigned force : 1;
-	unsigned pattern : 1;
-	unsigned matching : 1;
-	unsigned exact_sha1 : 1;
-
-	char *src;
-	char *dst;
-};
-
-extern const struct refspec *tag_refspec;
-
 struct ref {
 	struct ref *next;
 	struct object_id old_oid;
@@ -175,12 +163,6 @@ int ref_newer(const struct object_id *new_oid, const struct object_id *old_oid);
  */
 struct ref *ref_remove_duplicates(struct ref *ref_map);
 
-int valid_fetch_refspec(const char *refspec);
-struct refspec *parse_fetch_refspec(int nr_refspec, const char **refspec);
-extern struct refspec *parse_push_refspec(int nr_refspec, const char **refspec);
-
-void free_refspec(int nr_refspec, struct refspec *refspec);
-
 extern int query_refspecs(struct refspec *specs, int nr, struct refspec *query);
 char *apply_refspecs(struct refspec *refspecs, int nr_refspec,
 		     const char *name);
@@ -313,8 +295,6 @@ extern int parseopt_push_cas_option(const struct option *, const char *arg, int
 extern int is_empty_cas(const struct push_cas_option *);
 void apply_push_cas(struct push_cas_option *, struct remote *, struct ref *);
 
-#define TAG_REFSPEC "refs/tags/*:refs/tags/*"
-
 void add_prune_tags_to_fetch_refspec(struct remote *remote);
 
 #endif
diff --git a/transport-helper.c b/transport-helper.c
index 11f1055b4..b99e1cce9 100644
--- a/transport-helper.c
+++ b/transport-helper.c
@@ -11,6 +11,7 @@
 #include "sigchain.h"
 #include "argv-array.h"
 #include "refs.h"
+#include "refspec.h"
 #include "transport-internal.h"
 #include "protocol.h"
 
diff --git a/transport.c b/transport.c
index 37410d8aa..2cf63d18b 100644
--- a/transport.c
+++ b/transport.c
@@ -11,6 +11,7 @@
 #include "bundle.h"
 #include "dir.h"
 #include "refs.h"
+#include "refspec.h"
 #include "branch.h"
 #include "url.h"
 #include "submodule.h"
-- 
2.17.0.441.gb46fe60e1d-goog


^ permalink raw reply related	[flat|nested] 112+ messages in thread

* [PATCH v2 02/36] refspec: rename struct refspec to struct refspec_item
  2018-05-16 22:57 ` [PATCH v2 00/36] " Brandon Williams
  2018-05-16 22:57   ` [PATCH v2 01/36] refspec: move refspec parsing logic into its own file Brandon Williams
@ 2018-05-16 22:57   ` Brandon Williams
  2018-05-16 22:57   ` [PATCH v2 03/36] refspec: factor out parsing a single refspec Brandon Williams
                     ` (34 subsequent siblings)
  36 siblings, 0 replies; 112+ messages in thread
From: Brandon Williams @ 2018-05-16 22:57 UTC (permalink / raw)
  To: git, avarab, gitster, sbeller, bmwill
  Cc: avarab, gitster, sbeller, Brandon Williams

In preparation for introducing an abstraction around a collection of
refspecs (much like how a 'struct pathspec' is a collection of 'struct
pathspec_item's) rename the existing 'struct refspec' to 'struct
refspec_item'.

Signed-off-by: Brandon Williams <bmwill@google.com>
---
 branch.c                    |  6 ++---
 builtin/clone.c             |  4 +--
 builtin/fast-export.c       |  4 +--
 builtin/fetch.c             | 12 ++++-----
 builtin/pull.c              |  2 +-
 builtin/push.c              |  4 +--
 builtin/remote.c            |  8 +++---
 builtin/submodule--helper.c |  4 +--
 checkout.c                  |  4 +--
 refspec.c                   | 17 ++++++-------
 refspec.h                   | 10 ++++----
 remote.c                    | 50 ++++++++++++++++++-------------------
 remote.h                    | 16 ++++++------
 transport-helper.c          |  2 +-
 transport.c                 |  4 +--
 15 files changed, 73 insertions(+), 74 deletions(-)

diff --git a/branch.c b/branch.c
index 32ccefc6b..f967c98f6 100644
--- a/branch.c
+++ b/branch.c
@@ -9,7 +9,7 @@
 #include "worktree.h"
 
 struct tracking {
-	struct refspec spec;
+	struct refspec_item spec;
 	char *src;
 	const char *remote;
 	int matches;
@@ -219,8 +219,8 @@ int validate_new_branchname(const char *name, struct strbuf *ref, int force)
 static int check_tracking_branch(struct remote *remote, void *cb_data)
 {
 	char *tracking_branch = cb_data;
-	struct refspec query;
-	memset(&query, 0, sizeof(struct refspec));
+	struct refspec_item query;
+	memset(&query, 0, sizeof(struct refspec_item));
 	query.dst = tracking_branch;
 	return !remote_find_tracking(remote, &query);
 }
diff --git a/builtin/clone.c b/builtin/clone.c
index 6d1614ed3..854088a3a 100644
--- a/builtin/clone.c
+++ b/builtin/clone.c
@@ -547,7 +547,7 @@ static struct ref *find_remote_branch(const struct ref *refs, const char *branch
 }
 
 static struct ref *wanted_peer_refs(const struct ref *refs,
-		struct refspec *refspec)
+		struct refspec_item *refspec)
 {
 	struct ref *head = copy_ref(find_ref_by_name(refs, "HEAD"));
 	struct ref *local_refs = head;
@@ -895,7 +895,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
 	int err = 0, complete_refs_before_fetch = 1;
 	int submodule_progress;
 
-	struct refspec *refspec;
+	struct refspec_item *refspec;
 	const char *fetch_pattern;
 
 	fetch_if_missing = 0;
diff --git a/builtin/fast-export.c b/builtin/fast-export.c
index a13b7c8ef..6f105dc79 100644
--- a/builtin/fast-export.c
+++ b/builtin/fast-export.c
@@ -36,7 +36,7 @@ static int use_done_feature;
 static int no_data;
 static int full_tree;
 static struct string_list extra_refs = STRING_LIST_INIT_NODUP;
-static struct refspec *refspecs;
+static struct refspec_item *refspecs;
 static int refspecs_nr;
 static int anonymize;
 
@@ -979,7 +979,7 @@ static void handle_deletes(void)
 {
 	int i;
 	for (i = 0; i < refspecs_nr; i++) {
-		struct refspec *refspec = &refspecs[i];
+		struct refspec_item *refspec = &refspecs[i];
 		if (*refspec->src)
 			continue;
 
diff --git a/builtin/fetch.c b/builtin/fetch.c
index 1fce68e9a..745020a10 100644
--- a/builtin/fetch.c
+++ b/builtin/fetch.c
@@ -203,7 +203,7 @@ static void add_merge_config(struct ref **head,
 
 	for (i = 0; i < branch->merge_nr; i++) {
 		struct ref *rm, **old_tail = *tail;
-		struct refspec refspec;
+		struct refspec_item refspec;
 
 		for (rm = *head; rm; rm = rm->next) {
 			if (branch_merge_matches(branch, i, rm->name)) {
@@ -340,7 +340,7 @@ static void find_non_local_tags(struct transport *transport,
 }
 
 static struct ref *get_ref_map(struct transport *transport,
-			       struct refspec *refspecs, int refspec_count,
+			       struct refspec_item *refspecs, int refspec_count,
 			       int tags, int *autotags)
 {
 	int i;
@@ -371,7 +371,7 @@ static struct ref *get_ref_map(struct transport *transport,
 	argv_array_clear(&ref_prefixes);
 
 	if (refspec_count) {
-		struct refspec *fetch_refspec;
+		struct refspec_item *fetch_refspec;
 		int fetch_refspec_nr;
 
 		for (i = 0; i < refspec_count; i++) {
@@ -965,7 +965,7 @@ static int fetch_refs(struct transport *transport, struct ref *ref_map)
 	return ret;
 }
 
-static int prune_refs(struct refspec *refs, int ref_count, struct ref *ref_map,
+static int prune_refs(struct refspec_item *refs, int ref_count, struct ref *ref_map,
 		const char *raw_url)
 {
 	int url_len, i, result = 0;
@@ -1115,7 +1115,7 @@ static void backfill_tags(struct transport *transport, struct ref *ref_map)
 }
 
 static int do_fetch(struct transport *transport,
-		    struct refspec *refs, int ref_count)
+		    struct refspec_item *refs, int ref_count)
 {
 	struct string_list existing_refs = STRING_LIST_INIT_DUP;
 	struct ref *ref_map;
@@ -1357,7 +1357,7 @@ static inline void fetch_one_setup_partial(struct remote *remote)
 static int fetch_one(struct remote *remote, int argc, const char **argv, int prune_tags_ok)
 {
 	static const char **refs = NULL;
-	struct refspec *refspec;
+	struct refspec_item *refspec;
 	int ref_nr = 0;
 	int j = 0;
 	int exit_code;
diff --git a/builtin/pull.c b/builtin/pull.c
index 6247c956d..5a79deae5 100644
--- a/builtin/pull.c
+++ b/builtin/pull.c
@@ -676,7 +676,7 @@ static const char *get_upstream_branch(const char *remote)
  */
 static const char *get_tracking_branch(const char *remote, const char *refspec)
 {
-	struct refspec *spec;
+	struct refspec_item *spec;
 	const char *spec_src;
 	const char *merge_branch;
 
diff --git a/builtin/push.c b/builtin/push.c
index fa65999b2..00d81fb1d 100644
--- a/builtin/push.c
+++ b/builtin/push.c
@@ -80,8 +80,8 @@ static const char *map_refspec(const char *ref,
 		return ref;
 
 	if (remote->push) {
-		struct refspec query;
-		memset(&query, 0, sizeof(struct refspec));
+		struct refspec_item query;
+		memset(&query, 0, sizeof(struct refspec_item));
 		query.src = matched->name;
 		if (!query_refspecs(remote->push, remote->push_refspec_nr, &query) &&
 		    query.dst) {
diff --git a/builtin/remote.c b/builtin/remote.c
index c49513995..d9da82dc8 100644
--- a/builtin/remote.c
+++ b/builtin/remote.c
@@ -442,7 +442,7 @@ static int get_push_ref_states_noquery(struct ref_states *states)
 		info->dest = xstrdup(item->string);
 	}
 	for (i = 0; i < remote->push_refspec_nr; i++) {
-		struct refspec *spec = remote->push + i;
+		struct refspec_item *spec = remote->push + i;
 		if (spec->matching)
 			item = string_list_append(&states->push, _("(matching)"));
 		else if (strlen(spec->src))
@@ -462,7 +462,7 @@ static int get_head_names(const struct ref *remote_refs, struct ref_states *stat
 {
 	struct ref *ref, *matches;
 	struct ref *fetch_map = NULL, **fetch_map_tail = &fetch_map;
-	struct refspec refspec;
+	struct refspec_item refspec;
 
 	refspec.force = 0;
 	refspec.pattern = 1;
@@ -515,7 +515,7 @@ static int add_branch_for_removal(const char *refname,
 	const struct object_id *oid, int flags, void *cb_data)
 {
 	struct branches_for_remote *branches = cb_data;
-	struct refspec refspec;
+	struct refspec_item refspec;
 	struct known_remote *kr;
 
 	memset(&refspec, 0, sizeof(refspec));
@@ -834,7 +834,7 @@ static int append_ref_to_tracked_list(const char *refname,
 	const struct object_id *oid, int flags, void *cb_data)
 {
 	struct ref_states *states = cb_data;
-	struct refspec refspec;
+	struct refspec_item refspec;
 
 	if (flags & REF_ISSYMREF)
 		return 0;
diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
index 6ab032acb..c0c4db007 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -1746,11 +1746,11 @@ static int push_check(int argc, const char **argv, const char *prefix)
 	if (argc > 2) {
 		int i, refspec_nr = argc - 2;
 		struct ref *local_refs = get_local_heads();
-		struct refspec *refspec = parse_push_refspec(refspec_nr,
+		struct refspec_item *refspec = parse_push_refspec(refspec_nr,
 							     argv + 2);
 
 		for (i = 0; i < refspec_nr; i++) {
-			struct refspec *rs = refspec + i;
+			struct refspec_item *rs = refspec + i;
 
 			if (rs->pattern || rs->matching)
 				continue;
diff --git a/checkout.c b/checkout.c
index 193ba8567..bdefc888b 100644
--- a/checkout.c
+++ b/checkout.c
@@ -13,8 +13,8 @@ struct tracking_name_data {
 static int check_tracking_name(struct remote *remote, void *cb_data)
 {
 	struct tracking_name_data *cb = cb_data;
-	struct refspec query;
-	memset(&query, 0, sizeof(struct refspec));
+	struct refspec_item query;
+	memset(&query, 0, sizeof(struct refspec_item));
 	query.src = cb->src_ref;
 	if (remote_find_tracking(remote, &query) ||
 	    get_oid(query.dst, cb->dst_oid)) {
diff --git a/refspec.c b/refspec.c
index ecb0bdff3..22188f010 100644
--- a/refspec.c
+++ b/refspec.c
@@ -2,7 +2,7 @@
 #include "refs.h"
 #include "refspec.h"
 
-static struct refspec s_tag_refspec = {
+static struct refspec_item s_tag_refspec = {
 	0,
 	1,
 	0,
@@ -12,12 +12,12 @@ static struct refspec s_tag_refspec = {
 };
 
 /* See TAG_REFSPEC for the string version */
-const struct refspec *tag_refspec = &s_tag_refspec;
+const struct refspec_item *tag_refspec = &s_tag_refspec;
 
-static struct refspec *parse_refspec_internal(int nr_refspec, const char **refspec, int fetch, int verify)
+static struct refspec_item *parse_refspec_internal(int nr_refspec, const char **refspec, int fetch, int verify)
 {
 	int i;
-	struct refspec *rs = xcalloc(nr_refspec, sizeof(*rs));
+	struct refspec_item *rs = xcalloc(nr_refspec, sizeof(*rs));
 
 	for (i = 0; i < nr_refspec; i++) {
 		size_t llen;
@@ -135,24 +135,24 @@ static struct refspec *parse_refspec_internal(int nr_refspec, const char **refsp
 
 int valid_fetch_refspec(const char *fetch_refspec_str)
 {
-	struct refspec *refspec;
+	struct refspec_item *refspec;
 
 	refspec = parse_refspec_internal(1, &fetch_refspec_str, 1, 1);
 	free_refspec(1, refspec);
 	return !!refspec;
 }
 
-struct refspec *parse_fetch_refspec(int nr_refspec, const char **refspec)
+struct refspec_item *parse_fetch_refspec(int nr_refspec, const char **refspec)
 {
 	return parse_refspec_internal(nr_refspec, refspec, 1, 0);
 }
 
-struct refspec *parse_push_refspec(int nr_refspec, const char **refspec)
+struct refspec_item *parse_push_refspec(int nr_refspec, const char **refspec)
 {
 	return parse_refspec_internal(nr_refspec, refspec, 0, 0);
 }
 
-void free_refspec(int nr_refspec, struct refspec *refspec)
+void free_refspec(int nr_refspec, struct refspec_item *refspec)
 {
 	int i;
 
@@ -165,4 +165,3 @@ void free_refspec(int nr_refspec, struct refspec *refspec)
 	}
 	free(refspec);
 }
-
diff --git a/refspec.h b/refspec.h
index 62625c23a..fc9c1af77 100644
--- a/refspec.h
+++ b/refspec.h
@@ -2,9 +2,9 @@
 #define REFSPEC_H
 
 #define TAG_REFSPEC "refs/tags/*:refs/tags/*"
-extern const struct refspec *tag_refspec;
+extern const struct refspec_item *tag_refspec;
 
-struct refspec {
+struct refspec_item {
 	unsigned force : 1;
 	unsigned pattern : 1;
 	unsigned matching : 1;
@@ -15,9 +15,9 @@ struct refspec {
 };
 
 int valid_fetch_refspec(const char *refspec);
-struct refspec *parse_fetch_refspec(int nr_refspec, const char **refspec);
-struct refspec *parse_push_refspec(int nr_refspec, const char **refspec);
+struct refspec_item *parse_fetch_refspec(int nr_refspec, const char **refspec);
+struct refspec_item *parse_push_refspec(int nr_refspec, const char **refspec);
 
-void free_refspec(int nr_refspec, struct refspec *refspec);
+void free_refspec(int nr_refspec, struct refspec_item *refspec);
 
 #endif /* REFSPEC_H */
diff --git a/remote.c b/remote.c
index 4d67c061a..89820c476 100644
--- a/remote.c
+++ b/remote.c
@@ -97,7 +97,7 @@ void add_prune_tags_to_fetch_refspec(struct remote *remote)
 {
 	int nr = remote->fetch_refspec_nr;
 	int bufsize = nr  + 1;
-	int size = sizeof(struct refspec);
+	int size = sizeof(struct refspec_item);
 
 	remote->fetch = xrealloc(remote->fetch, size  * bufsize);
 	memcpy(&remote->fetch[nr], tag_refspec, size);
@@ -724,7 +724,7 @@ static int match_name_with_pattern(const char *key, const char *name,
 	return ret;
 }
 
-static void query_refspecs_multiple(struct refspec *refs, int ref_count, struct refspec *query, struct string_list *results)
+static void query_refspecs_multiple(struct refspec_item *refs, int ref_count, struct refspec_item *query, struct string_list *results)
 {
 	int i;
 	int find_src = !query->src;
@@ -733,7 +733,7 @@ static void query_refspecs_multiple(struct refspec *refs, int ref_count, struct
 		error("query_refspecs_multiple: need either src or dst");
 
 	for (i = 0; i < ref_count; i++) {
-		struct refspec *refspec = &refs[i];
+		struct refspec_item *refspec = &refs[i];
 		const char *key = find_src ? refspec->dst : refspec->src;
 		const char *value = find_src ? refspec->src : refspec->dst;
 		const char *needle = find_src ? query->dst : query->src;
@@ -750,7 +750,7 @@ static void query_refspecs_multiple(struct refspec *refs, int ref_count, struct
 	}
 }
 
-int query_refspecs(struct refspec *refs, int ref_count, struct refspec *query)
+int query_refspecs(struct refspec_item *refs, int ref_count, struct refspec_item *query)
 {
 	int i;
 	int find_src = !query->src;
@@ -761,7 +761,7 @@ int query_refspecs(struct refspec *refs, int ref_count, struct refspec *query)
 		return error("query_refspecs: need either src or dst");
 
 	for (i = 0; i < ref_count; i++) {
-		struct refspec *refspec = &refs[i];
+		struct refspec_item *refspec = &refs[i];
 		const char *key = find_src ? refspec->dst : refspec->src;
 		const char *value = find_src ? refspec->src : refspec->dst;
 
@@ -781,12 +781,12 @@ int query_refspecs(struct refspec *refs, int ref_count, struct refspec *query)
 	return -1;
 }
 
-char *apply_refspecs(struct refspec *refspecs, int nr_refspec,
+char *apply_refspecs(struct refspec_item *refspecs, int nr_refspec,
 		     const char *name)
 {
-	struct refspec query;
+	struct refspec_item query;
 
-	memset(&query, 0, sizeof(struct refspec));
+	memset(&query, 0, sizeof(struct refspec_item));
 	query.src = (char *)name;
 
 	if (query_refspecs(refspecs, nr_refspec, &query))
@@ -795,7 +795,7 @@ char *apply_refspecs(struct refspec *refspecs, int nr_refspec,
 	return query.dst;
 }
 
-int remote_find_tracking(struct remote *remote, struct refspec *refspec)
+int remote_find_tracking(struct remote *remote, struct refspec_item *refspec)
 {
 	return query_refspecs(remote->fetch, remote->fetch_refspec_nr, refspec);
 }
@@ -1004,7 +1004,7 @@ static char *guess_ref(const char *name, struct ref *peer)
 }
 
 static int match_explicit_lhs(struct ref *src,
-			      struct refspec *rs,
+			      struct refspec_item *rs,
 			      struct ref **match,
 			      int *allocated_match)
 {
@@ -1030,7 +1030,7 @@ static int match_explicit_lhs(struct ref *src,
 
 static int match_explicit(struct ref *src, struct ref *dst,
 			  struct ref ***dst_tail,
-			  struct refspec *rs)
+			  struct refspec_item *rs)
 {
 	struct ref *matched_src, *matched_dst;
 	int allocated_src;
@@ -1099,7 +1099,7 @@ static int match_explicit(struct ref *src, struct ref *dst,
 }
 
 static int match_explicit_refs(struct ref *src, struct ref *dst,
-			       struct ref ***dst_tail, struct refspec *rs,
+			       struct ref ***dst_tail, struct refspec_item *rs,
 			       int rs_nr)
 {
 	int i, errs;
@@ -1108,10 +1108,10 @@ static int match_explicit_refs(struct ref *src, struct ref *dst,
 	return errs;
 }
 
-static char *get_ref_match(const struct refspec *rs, int rs_nr, const struct ref *ref,
-		int send_mirror, int direction, const struct refspec **ret_pat)
+static char *get_ref_match(const struct refspec_item *rs, int rs_nr, const struct ref *ref,
+		int send_mirror, int direction, const struct refspec_item **ret_pat)
 {
-	const struct refspec *pat;
+	const struct refspec_item *pat;
 	char *name;
 	int i;
 	int matching_refs = -1;
@@ -1282,12 +1282,12 @@ static void prepare_ref_index(struct string_list *ref_index, struct ref *ref)
  */
 int check_push_refs(struct ref *src, int nr_refspec, const char **refspec_names)
 {
-	struct refspec *refspec = parse_push_refspec(nr_refspec, refspec_names);
+	struct refspec_item *refspec = parse_push_refspec(nr_refspec, refspec_names);
 	int ret = 0;
 	int i;
 
 	for (i = 0; i < nr_refspec; i++) {
-		struct refspec *rs = refspec + i;
+		struct refspec_item *rs = refspec + i;
 
 		if (rs->pattern || rs->matching)
 			continue;
@@ -1310,7 +1310,7 @@ int check_push_refs(struct ref *src, int nr_refspec, const char **refspec_names)
 int match_push_refs(struct ref *src, struct ref **dst,
 		    int nr_refspec, const char **refspec, int flags)
 {
-	struct refspec *rs;
+	struct refspec_item *rs;
 	int send_all = flags & MATCH_REFS_ALL;
 	int send_mirror = flags & MATCH_REFS_MIRROR;
 	int send_prune = flags & MATCH_REFS_PRUNE;
@@ -1330,7 +1330,7 @@ int match_push_refs(struct ref *src, struct ref **dst,
 	for (ref = src; ref; ref = ref->next) {
 		struct string_list_item *dst_item;
 		struct ref *dst_peer;
-		const struct refspec *pat = NULL;
+		const struct refspec_item *pat = NULL;
 		char *dst_name;
 
 		dst_name = get_ref_match(rs, nr_refspec, ref, send_mirror, FROM_SRC, &pat);
@@ -1686,7 +1686,7 @@ static int ignore_symref_update(const char *refname)
  * local symbolic ref.
  */
 static struct ref *get_expanded_map(const struct ref *remote_refs,
-				    const struct refspec *refspec)
+				    const struct refspec_item *refspec)
 {
 	const struct ref *ref;
 	struct ref *ret = NULL;
@@ -1751,7 +1751,7 @@ static struct ref *get_local_ref(const char *name)
 }
 
 int get_fetch_map(const struct ref *remote_refs,
-		  const struct refspec *refspec,
+		  const struct refspec_item *refspec,
 		  struct ref ***tail,
 		  int missing_ok)
 {
@@ -2089,7 +2089,7 @@ struct ref *guess_remote_head(const struct ref *head,
 struct stale_heads_info {
 	struct string_list *ref_names;
 	struct ref **stale_refs_tail;
-	struct refspec *refs;
+	struct refspec_item *refs;
 	int ref_count;
 };
 
@@ -2098,9 +2098,9 @@ static int get_stale_heads_cb(const char *refname, const struct object_id *oid,
 {
 	struct stale_heads_info *info = cb_data;
 	struct string_list matches = STRING_LIST_INIT_DUP;
-	struct refspec query;
+	struct refspec_item query;
 	int i, stale = 1;
-	memset(&query, 0, sizeof(struct refspec));
+	memset(&query, 0, sizeof(struct refspec_item));
 	query.dst = (char *)refname;
 
 	query_refspecs_multiple(info->refs, info->ref_count, &query, &matches);
@@ -2131,7 +2131,7 @@ static int get_stale_heads_cb(const char *refname, const struct object_id *oid,
 	return 0;
 }
 
-struct ref *get_stale_heads(struct refspec *refs, int ref_count, struct ref *fetch_map)
+struct ref *get_stale_heads(struct refspec_item *refs, int ref_count, struct ref *fetch_map)
 {
 	struct ref *ref, *stale_refs = NULL;
 	struct string_list ref_names = STRING_LIST_INIT_NODUP;
diff --git a/remote.h b/remote.h
index 386ced901..3657bd43d 100644
--- a/remote.h
+++ b/remote.h
@@ -28,12 +28,12 @@ struct remote {
 	int pushurl_alloc;
 
 	const char **push_refspec;
-	struct refspec *push;
+	struct refspec_item *push;
 	int push_refspec_nr;
 	int push_refspec_alloc;
 
 	const char **fetch_refspec;
-	struct refspec *fetch;
+	struct refspec_item *fetch;
 	int fetch_refspec_nr;
 	int fetch_refspec_alloc;
 
@@ -163,8 +163,8 @@ int ref_newer(const struct object_id *new_oid, const struct object_id *old_oid);
  */
 struct ref *ref_remove_duplicates(struct ref *ref_map);
 
-extern int query_refspecs(struct refspec *specs, int nr, struct refspec *query);
-char *apply_refspecs(struct refspec *refspecs, int nr_refspec,
+extern int query_refspecs(struct refspec_item *specs, int nr, struct refspec_item *query);
+char *apply_refspecs(struct refspec_item *refspecs, int nr_refspec,
 		     const char *name);
 
 int check_push_refs(struct ref *src, int nr_refspec, const char **refspec);
@@ -185,7 +185,7 @@ void set_ref_status_for_push(struct ref *remote_refs, int send_mirror,
  * missing_ok is usually false, but when we are adding branch.$name.merge
  * it is Ok if the branch is not at the remote anymore.
  */
-int get_fetch_map(const struct ref *remote_refs, const struct refspec *refspec,
+int get_fetch_map(const struct ref *remote_refs, const struct refspec_item *refspec,
 		  struct ref ***tail, int missing_ok);
 
 struct ref *get_remote_ref(const struct ref *remote_refs, const char *name);
@@ -193,7 +193,7 @@ struct ref *get_remote_ref(const struct ref *remote_refs, const char *name);
 /*
  * For the given remote, reads the refspec's src and sets the other fields.
  */
-int remote_find_tracking(struct remote *remote, struct refspec *refspec);
+int remote_find_tracking(struct remote *remote, struct refspec_item *refspec);
 
 struct branch {
 	const char *name;
@@ -203,7 +203,7 @@ struct branch {
 	const char *pushremote_name;
 
 	const char **merge_name;
-	struct refspec **merge;
+	struct refspec_item **merge;
 	int merge_nr;
 	int merge_alloc;
 
@@ -272,7 +272,7 @@ struct ref *guess_remote_head(const struct ref *head,
 			      int all);
 
 /* Return refs which no longer exist on remote */
-struct ref *get_stale_heads(struct refspec *refs, int ref_count, struct ref *fetch_map);
+struct ref *get_stale_heads(struct refspec_item *refs, int ref_count, struct ref *fetch_map);
 
 /*
  * Compare-and-swap
diff --git a/transport-helper.c b/transport-helper.c
index b99e1cce9..b156a37e7 100644
--- a/transport-helper.c
+++ b/transport-helper.c
@@ -36,7 +36,7 @@ struct helper_data {
 	char *export_marks;
 	char *import_marks;
 	/* These go from remote name (as in "list") to private name */
-	struct refspec *refspecs;
+	struct refspec_item *refspecs;
 	int refspec_nr;
 	/* Transport options for fetch-pack/send-pack (should one of
 	 * those be invoked).
diff --git a/transport.c b/transport.c
index 2cf63d18b..3ad4d37dc 100644
--- a/transport.c
+++ b/transport.c
@@ -390,7 +390,7 @@ int transport_refs_pushed(struct ref *ref)
 
 void transport_update_tracking_ref(struct remote *remote, struct ref *ref, int verbose)
 {
-	struct refspec rs;
+	struct refspec_item rs;
 
 	if (ref->status != REF_STATUS_OK && ref->status != REF_STATUS_UPTODATE)
 		return;
@@ -1111,7 +1111,7 @@ int transport_push(struct transport *transport,
 		int porcelain = flags & TRANSPORT_PUSH_PORCELAIN;
 		int pretend = flags & TRANSPORT_PUSH_DRY_RUN;
 		int push_ret, ret, err;
-		struct refspec *tmp_rs;
+		struct refspec_item *tmp_rs;
 		struct argv_array ref_prefixes = ARGV_ARRAY_INIT;
 		int i;
 
-- 
2.17.0.441.gb46fe60e1d-goog


^ permalink raw reply related	[flat|nested] 112+ messages in thread

* [PATCH v2 03/36] refspec: factor out parsing a single refspec
  2018-05-16 22:57 ` [PATCH v2 00/36] " Brandon Williams
  2018-05-16 22:57   ` [PATCH v2 01/36] refspec: move refspec parsing logic into its own file Brandon Williams
  2018-05-16 22:57   ` [PATCH v2 02/36] refspec: rename struct refspec to struct refspec_item Brandon Williams
@ 2018-05-16 22:57   ` Brandon Williams
  2018-05-16 22:57   ` [PATCH v2 04/36] refspec: introduce struct refspec Brandon Williams
                     ` (33 subsequent siblings)
  36 siblings, 0 replies; 112+ messages in thread
From: Brandon Williams @ 2018-05-16 22:57 UTC (permalink / raw)
  To: git, avarab, gitster, sbeller, bmwill
  Cc: avarab, gitster, sbeller, Brandon Williams

Factor out the logic which parses a single refspec into its own
function.  This makes it easier to reuse this logic in a future patch.

Signed-off-by: Brandon Williams <bmwill@google.com>
---
 refspec.c | 195 +++++++++++++++++++++++++++++-------------------------
 1 file changed, 104 insertions(+), 91 deletions(-)

diff --git a/refspec.c b/refspec.c
index 22188f010..8bf4ebbd3 100644
--- a/refspec.c
+++ b/refspec.c
@@ -14,110 +14,123 @@ static struct refspec_item s_tag_refspec = {
 /* See TAG_REFSPEC for the string version */
 const struct refspec_item *tag_refspec = &s_tag_refspec;
 
-static struct refspec_item *parse_refspec_internal(int nr_refspec, const char **refspec, int fetch, int verify)
+/*
+ * Parses the provided refspec 'refspec' and populates the refspec_item 'item'.
+ * Returns 1 if successful and 0 if the refspec is invalid.
+ */
+static int parse_refspec(struct refspec_item *item, const char *refspec, int fetch)
 {
-	int i;
-	struct refspec_item *rs = xcalloc(nr_refspec, sizeof(*rs));
+	size_t llen;
+	int is_glob;
+	const char *lhs, *rhs;
+	int flags;
 
-	for (i = 0; i < nr_refspec; i++) {
-		size_t llen;
-		int is_glob;
-		const char *lhs, *rhs;
-		int flags;
+	is_glob = 0;
 
-		is_glob = 0;
+	lhs = refspec;
+	if (*lhs == '+') {
+		item->force = 1;
+		lhs++;
+	}
 
-		lhs = refspec[i];
-		if (*lhs == '+') {
-			rs[i].force = 1;
-			lhs++;
-		}
+	rhs = strrchr(lhs, ':');
 
-		rhs = strrchr(lhs, ':');
+	/*
+	 * Before going on, special case ":" (or "+:") as a refspec
+	 * for pushing matching refs.
+	 */
+	if (!fetch && rhs == lhs && rhs[1] == '\0') {
+		item->matching = 1;
+		return 1;
+	}
 
+	if (rhs) {
+		size_t rlen = strlen(++rhs);
+		is_glob = (1 <= rlen && strchr(rhs, '*'));
+		item->dst = xstrndup(rhs, rlen);
+	}
+
+	llen = (rhs ? (rhs - lhs - 1) : strlen(lhs));
+	if (1 <= llen && memchr(lhs, '*', llen)) {
+		if ((rhs && !is_glob) || (!rhs && fetch))
+			return 0;
+		is_glob = 1;
+	} else if (rhs && is_glob) {
+		return 0;
+	}
+
+	item->pattern = is_glob;
+	item->src = xstrndup(lhs, llen);
+	flags = REFNAME_ALLOW_ONELEVEL | (is_glob ? REFNAME_REFSPEC_PATTERN : 0);
+
+	if (fetch) {
+		struct object_id unused;
+
+		/* LHS */
+		if (!*item->src)
+			; /* empty is ok; it means "HEAD" */
+		else if (llen == GIT_SHA1_HEXSZ && !get_oid_hex(item->src, &unused))
+			item->exact_sha1 = 1; /* ok */
+		else if (!check_refname_format(item->src, flags))
+			; /* valid looking ref is ok */
+		else
+			return 0;
+		/* RHS */
+		if (!item->dst)
+			; /* missing is ok; it is the same as empty */
+		else if (!*item->dst)
+			; /* empty is ok; it means "do not store" */
+		else if (!check_refname_format(item->dst, flags))
+			; /* valid looking ref is ok */
+		else
+			return 0;
+	} else {
 		/*
-		 * Before going on, special case ":" (or "+:") as a refspec
-		 * for pushing matching refs.
+		 * LHS
+		 * - empty is allowed; it means delete.
+		 * - when wildcarded, it must be a valid looking ref.
+		 * - otherwise, it must be an extended SHA-1, but
+		 *   there is no existing way to validate this.
 		 */
-		if (!fetch && rhs == lhs && rhs[1] == '\0') {
-			rs[i].matching = 1;
-			continue;
+		if (!*item->src)
+			; /* empty is ok */
+		else if (is_glob) {
+			if (check_refname_format(item->src, flags))
+				return 0;
 		}
-
-		if (rhs) {
-			size_t rlen = strlen(++rhs);
-			is_glob = (1 <= rlen && strchr(rhs, '*'));
-			rs[i].dst = xstrndup(rhs, rlen);
+		else
+			; /* anything goes, for now */
+		/*
+		 * RHS
+		 * - missing is allowed, but LHS then must be a
+		 *   valid looking ref.
+		 * - empty is not allowed.
+		 * - otherwise it must be a valid looking ref.
+		 */
+		if (!item->dst) {
+			if (check_refname_format(item->src, flags))
+				return 0;
+		} else if (!*item->dst) {
+			return 0;
+		} else {
+			if (check_refname_format(item->dst, flags))
+				return 0;
 		}
+	}
 
-		llen = (rhs ? (rhs - lhs - 1) : strlen(lhs));
-		if (1 <= llen && memchr(lhs, '*', llen)) {
-			if ((rhs && !is_glob) || (!rhs && fetch))
-				goto invalid;
-			is_glob = 1;
-		} else if (rhs && is_glob) {
-			goto invalid;
-		}
+	return 1;
+}
 
-		rs[i].pattern = is_glob;
-		rs[i].src = xstrndup(lhs, llen);
-		flags = REFNAME_ALLOW_ONELEVEL | (is_glob ? REFNAME_REFSPEC_PATTERN : 0);
-
-		if (fetch) {
-			struct object_id unused;
-
-			/* LHS */
-			if (!*rs[i].src)
-				; /* empty is ok; it means "HEAD" */
-			else if (llen == GIT_SHA1_HEXSZ && !get_oid_hex(rs[i].src, &unused))
-				rs[i].exact_sha1 = 1; /* ok */
-			else if (!check_refname_format(rs[i].src, flags))
-				; /* valid looking ref is ok */
-			else
-				goto invalid;
-			/* RHS */
-			if (!rs[i].dst)
-				; /* missing is ok; it is the same as empty */
-			else if (!*rs[i].dst)
-				; /* empty is ok; it means "do not store" */
-			else if (!check_refname_format(rs[i].dst, flags))
-				; /* valid looking ref is ok */
-			else
-				goto invalid;
-		} else {
-			/*
-			 * LHS
-			 * - empty is allowed; it means delete.
-			 * - when wildcarded, it must be a valid looking ref.
-			 * - otherwise, it must be an extended SHA-1, but
-			 *   there is no existing way to validate this.
-			 */
-			if (!*rs[i].src)
-				; /* empty is ok */
-			else if (is_glob) {
-				if (check_refname_format(rs[i].src, flags))
-					goto invalid;
-			}
-			else
-				; /* anything goes, for now */
-			/*
-			 * RHS
-			 * - missing is allowed, but LHS then must be a
-			 *   valid looking ref.
-			 * - empty is not allowed.
-			 * - otherwise it must be a valid looking ref.
-			 */
-			if (!rs[i].dst) {
-				if (check_refname_format(rs[i].src, flags))
-					goto invalid;
-			} else if (!*rs[i].dst) {
-				goto invalid;
-			} else {
-				if (check_refname_format(rs[i].dst, flags))
-					goto invalid;
-			}
-		}
+static struct refspec_item *parse_refspec_internal(int nr_refspec, const char **refspec, int fetch, int verify)
+{
+	int i;
+	struct refspec_item *rs = xcalloc(nr_refspec, sizeof(*rs));
+
+	for (i = 0; i < nr_refspec; i++) {
+		if (!parse_refspec(&rs[i], refspec[i], fetch))
+			goto invalid;
 	}
+
 	return rs;
 
  invalid:
-- 
2.17.0.441.gb46fe60e1d-goog


^ permalink raw reply related	[flat|nested] 112+ messages in thread

* [PATCH v2 04/36] refspec: introduce struct refspec
  2018-05-16 22:57 ` [PATCH v2 00/36] " Brandon Williams
                     ` (2 preceding siblings ...)
  2018-05-16 22:57   ` [PATCH v2 03/36] refspec: factor out parsing a single refspec Brandon Williams
@ 2018-05-16 22:57   ` Brandon Williams
  2018-05-16 22:57   ` [PATCH v2 05/36] refspec: convert valid_fetch_refspec to use parse_refspec Brandon Williams
                     ` (32 subsequent siblings)
  36 siblings, 0 replies; 112+ messages in thread
From: Brandon Williams @ 2018-05-16 22:57 UTC (permalink / raw)
  To: git, avarab, gitster, sbeller, bmwill
  Cc: avarab, gitster, sbeller, Brandon Williams

Introduce 'struct refspec', an abstraction around a collection of
'struct refspec_item's much like how 'struct pathspec' holds a
collection of 'struct pathspec_item's.

A refspec struct also contains an array of the original refspec strings
which will be used to facilitate the migration to using this new
abstraction throughout the code base.

Signed-off-by: Brandon Williams <bmwill@google.com>
---
 refspec.c | 64 +++++++++++++++++++++++++++++++++++++++++++++++++++++++
 refspec.h | 25 ++++++++++++++++++++++
 2 files changed, 89 insertions(+)

diff --git a/refspec.c b/refspec.c
index 8bf4ebbd3..af9d0d4b3 100644
--- a/refspec.c
+++ b/refspec.c
@@ -178,3 +178,67 @@ void free_refspec(int nr_refspec, struct refspec_item *refspec)
 	}
 	free(refspec);
 }
+
+void refspec_item_init(struct refspec_item *item, const char *refspec, int fetch)
+{
+	memset(item, 0, sizeof(*item));
+
+	if (!parse_refspec(item, refspec, fetch))
+		die("Invalid refspec '%s'", refspec);
+}
+
+void refspec_item_clear(struct refspec_item *item)
+{
+	FREE_AND_NULL(item->src);
+	FREE_AND_NULL(item->dst);
+	item->force = 0;
+	item->pattern = 0;
+	item->matching = 0;
+	item->exact_sha1 = 0;
+}
+
+void refspec_init(struct refspec *rs, int fetch)
+{
+	memset(rs, 0, sizeof(*rs));
+	rs->fetch = fetch;
+}
+
+void refspec_append(struct refspec *rs, const char *refspec)
+{
+	struct refspec_item item;
+
+	refspec_item_init(&item, refspec, rs->fetch);
+
+	ALLOC_GROW(rs->items, rs->nr + 1, rs->alloc);
+	rs->items[rs->nr++] = item;
+
+	ALLOC_GROW(rs->raw, rs->raw_nr + 1, rs->raw_alloc);
+	rs->raw[rs->raw_nr++] = xstrdup(refspec);
+}
+
+void refspec_appendn(struct refspec *rs, const char **refspecs, int nr)
+{
+	int i;
+	for (i = 0; i < nr; i++)
+		refspec_append(rs, refspecs[i]);
+}
+
+void refspec_clear(struct refspec *rs)
+{
+	int i;
+
+	for (i = 0; i < rs->nr; i++)
+		refspec_item_clear(&rs->items[i]);
+
+	FREE_AND_NULL(rs->items);
+	rs->alloc = 0;
+	rs->nr = 0;
+
+	for (i = 0; i < rs->raw_nr; i++)
+		free((char *)rs->raw[i]);
+	FREE_AND_NULL(rs->raw);
+	rs->raw_alloc = 0;
+	rs->raw_nr = 0;
+
+	rs->fetch = 0;
+}
diff --git a/refspec.h b/refspec.h
index fc9c1af77..da3135825 100644
--- a/refspec.h
+++ b/refspec.h
@@ -20,4 +20,29 @@ struct refspec_item *parse_push_refspec(int nr_refspec, const char **refspec);
 
 void free_refspec(int nr_refspec, struct refspec_item *refspec);
 
+#define REFSPEC_FETCH 1
+#define REFSPEC_PUSH 0
+
+#define REFSPEC_INIT_FETCH { .fetch = REFSPEC_FETCH }
+#define REFSPEC_INIT_PUSH { .fetch = REFSPEC_PUSH }
+
+struct refspec {
+	struct refspec_item *items;
+	int alloc;
+	int nr;
+
+	const char **raw;
+	int raw_alloc;
+	int raw_nr;
+
+	int fetch;
+};
+
+void refspec_item_init(struct refspec_item *item, const char *refspec, int fetch);
+void refspec_item_clear(struct refspec_item *item);
+void refspec_init(struct refspec *rs, int fetch);
+void refspec_append(struct refspec *rs, const char *refspec);
+void refspec_appendn(struct refspec *rs, const char **refspecs, int nr);
+void refspec_clear(struct refspec *rs);
+
 #endif /* REFSPEC_H */
-- 
2.17.0.441.gb46fe60e1d-goog


^ permalink raw reply related	[flat|nested] 112+ messages in thread

* [PATCH v2 05/36] refspec: convert valid_fetch_refspec to use parse_refspec
  2018-05-16 22:57 ` [PATCH v2 00/36] " Brandon Williams
                     ` (3 preceding siblings ...)
  2018-05-16 22:57   ` [PATCH v2 04/36] refspec: introduce struct refspec Brandon Williams
@ 2018-05-16 22:57   ` Brandon Williams
  2018-06-03 17:13     ` Martin Ågren
  2018-05-16 22:57   ` [PATCH v2 06/36] submodule--helper: convert push_check to use struct refspec Brandon Williams
                     ` (31 subsequent siblings)
  36 siblings, 1 reply; 112+ messages in thread
From: Brandon Williams @ 2018-05-16 22:57 UTC (permalink / raw)
  To: git, avarab, gitster, sbeller, bmwill
  Cc: avarab, gitster, sbeller, Brandon Williams

Convert 'valid_fetch_refspec()' to use the new 'parse_refspec()'
function to only parse a single refspec and eliminate an allocation.

Signed-off-by: Brandon Williams <bmwill@google.com>
---
 refspec.c | 17 ++++++++---------
 refspec.h |  3 ++-
 2 files changed, 10 insertions(+), 10 deletions(-)

diff --git a/refspec.c b/refspec.c
index af9d0d4b3..ab37b5ba1 100644
--- a/refspec.c
+++ b/refspec.c
@@ -146,15 +146,6 @@ static struct refspec_item *parse_refspec_internal(int nr_refspec, const char **
 	die("Invalid refspec '%s'", refspec[i]);
 }
 
-int valid_fetch_refspec(const char *fetch_refspec_str)
-{
-	struct refspec_item *refspec;
-
-	refspec = parse_refspec_internal(1, &fetch_refspec_str, 1, 1);
-	free_refspec(1, refspec);
-	return !!refspec;
-}
-
 struct refspec_item *parse_fetch_refspec(int nr_refspec, const char **refspec)
 {
 	return parse_refspec_internal(nr_refspec, refspec, 1, 0);
@@ -242,3 +233,11 @@ void refspec_clear(struct refspec *rs)
 
 	rs->fetch = 0;
 }
+
+int valid_fetch_refspec(const char *fetch_refspec_str)
+{
+	struct refspec_item refspec;
+	int ret = parse_refspec(&refspec, fetch_refspec_str, REFSPEC_FETCH);
+	refspec_item_clear(&refspec);
+	return ret;
+}
diff --git a/refspec.h b/refspec.h
index da3135825..1063c64cc 100644
--- a/refspec.h
+++ b/refspec.h
@@ -14,7 +14,6 @@ struct refspec_item {
 	char *dst;
 };
 
-int valid_fetch_refspec(const char *refspec);
 struct refspec_item *parse_fetch_refspec(int nr_refspec, const char **refspec);
 struct refspec_item *parse_push_refspec(int nr_refspec, const char **refspec);
 
@@ -45,4 +44,6 @@ void refspec_append(struct refspec *rs, const char *refspec);
 void refspec_appendn(struct refspec *rs, const char **refspecs, int nr);
 void refspec_clear(struct refspec *rs);
 
+int valid_fetch_refspec(const char *refspec);
+
 #endif /* REFSPEC_H */
-- 
2.17.0.441.gb46fe60e1d-goog


^ permalink raw reply related	[flat|nested] 112+ messages in thread

* [PATCH v2 06/36] submodule--helper: convert push_check to use struct refspec
  2018-05-16 22:57 ` [PATCH v2 00/36] " Brandon Williams
                     ` (4 preceding siblings ...)
  2018-05-16 22:57   ` [PATCH v2 05/36] refspec: convert valid_fetch_refspec to use parse_refspec Brandon Williams
@ 2018-05-16 22:57   ` Brandon Williams
  2018-05-16 22:57   ` [PATCH v2 07/36] pull: convert get_tracking_branch to use refspec_item_init Brandon Williams
                     ` (30 subsequent siblings)
  36 siblings, 0 replies; 112+ messages in thread
From: Brandon Williams @ 2018-05-16 22:57 UTC (permalink / raw)
  To: git, avarab, gitster, sbeller, bmwill
  Cc: avarab, gitster, sbeller, Brandon Williams

Convert 'push_check()' to use 'struct refspec'.

Signed-off-by: Brandon Williams <bmwill@google.com>
---
 builtin/submodule--helper.c | 13 +++++++------
 1 file changed, 7 insertions(+), 6 deletions(-)

diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
index c0c4db007..88a149a2c 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -1744,13 +1744,14 @@ static int push_check(int argc, const char **argv, const char *prefix)
 
 	/* Check the refspec */
 	if (argc > 2) {
-		int i, refspec_nr = argc - 2;
+		int i;
 		struct ref *local_refs = get_local_heads();
-		struct refspec_item *refspec = parse_push_refspec(refspec_nr,
-							     argv + 2);
+		struct refspec refspec = REFSPEC_INIT_PUSH;
 
-		for (i = 0; i < refspec_nr; i++) {
-			struct refspec_item *rs = refspec + i;
+		refspec_appendn(&refspec, argv + 2, argc - 2);
+
+		for (i = 0; i < refspec.nr; i++) {
+			const struct refspec_item *rs = &refspec.items[i];
 
 			if (rs->pattern || rs->matching)
 				continue;
@@ -1777,7 +1778,7 @@ static int push_check(int argc, const char **argv, const char *prefix)
 				    rs->src);
 			}
 		}
-		free_refspec(refspec_nr, refspec);
+		refspec_clear(&refspec);
 	}
 	free(head);
 
-- 
2.17.0.441.gb46fe60e1d-goog


^ permalink raw reply related	[flat|nested] 112+ messages in thread

* [PATCH v2 07/36] pull: convert get_tracking_branch to use refspec_item_init
  2018-05-16 22:57 ` [PATCH v2 00/36] " Brandon Williams
                     ` (5 preceding siblings ...)
  2018-05-16 22:57   ` [PATCH v2 06/36] submodule--helper: convert push_check to use struct refspec Brandon Williams
@ 2018-05-16 22:57   ` Brandon Williams
  2018-05-16 22:57   ` [PATCH v2 08/36] transport: convert transport_push to use struct refspec Brandon Williams
                     ` (29 subsequent siblings)
  36 siblings, 0 replies; 112+ messages in thread
From: Brandon Williams @ 2018-05-16 22:57 UTC (permalink / raw)
  To: git, avarab, gitster, sbeller, bmwill
  Cc: avarab, gitster, sbeller, Brandon Williams

Convert 'get_tracking_branch()' to use 'refspec_item_init()' instead of
the old 'parse_fetch_refspec()' function.

Signed-off-by: Brandon Williams <bmwill@google.com>
---
 builtin/pull.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/builtin/pull.c b/builtin/pull.c
index 5a79deae5..09575fd23 100644
--- a/builtin/pull.c
+++ b/builtin/pull.c
@@ -676,12 +676,12 @@ static const char *get_upstream_branch(const char *remote)
  */
 static const char *get_tracking_branch(const char *remote, const char *refspec)
 {
-	struct refspec_item *spec;
+	struct refspec_item spec;
 	const char *spec_src;
 	const char *merge_branch;
 
-	spec = parse_fetch_refspec(1, &refspec);
-	spec_src = spec->src;
+	refspec_item_init(&spec, refspec, REFSPEC_FETCH);
+	spec_src = spec.src;
 	if (!*spec_src || !strcmp(spec_src, "HEAD"))
 		spec_src = "HEAD";
 	else if (skip_prefix(spec_src, "heads/", &spec_src))
@@ -701,7 +701,7 @@ static const char *get_tracking_branch(const char *remote, const char *refspec)
 	} else
 		merge_branch = NULL;
 
-	free_refspec(1, spec);
+	refspec_item_clear(&spec);
 	return merge_branch;
 }
 
-- 
2.17.0.441.gb46fe60e1d-goog


^ permalink raw reply related	[flat|nested] 112+ messages in thread

* [PATCH v2 08/36] transport: convert transport_push to use struct refspec
  2018-05-16 22:57 ` [PATCH v2 00/36] " Brandon Williams
                     ` (6 preceding siblings ...)
  2018-05-16 22:57   ` [PATCH v2 07/36] pull: convert get_tracking_branch to use refspec_item_init Brandon Williams
@ 2018-05-16 22:57   ` Brandon Williams
  2018-05-16 22:57   ` [PATCH v2 09/36] remote: convert check_push_refs " Brandon Williams
                     ` (28 subsequent siblings)
  36 siblings, 0 replies; 112+ messages in thread
From: Brandon Williams @ 2018-05-16 22:57 UTC (permalink / raw)
  To: git, avarab, gitster, sbeller, bmwill
  Cc: avarab, gitster, sbeller, Brandon Williams

Convert the logic in 'transport_push()' which calculates a list of
ref-prefixes to use 'struct refspec'.

Signed-off-by: Brandon Williams <bmwill@google.com>
---
 transport.c | 17 +++++++++--------
 1 file changed, 9 insertions(+), 8 deletions(-)

diff --git a/transport.c b/transport.c
index 3ad4d37dc..181db4d4d 100644
--- a/transport.c
+++ b/transport.c
@@ -1111,21 +1111,22 @@ int transport_push(struct transport *transport,
 		int porcelain = flags & TRANSPORT_PUSH_PORCELAIN;
 		int pretend = flags & TRANSPORT_PUSH_DRY_RUN;
 		int push_ret, ret, err;
-		struct refspec_item *tmp_rs;
+		struct refspec tmp_rs = REFSPEC_INIT_PUSH;
 		struct argv_array ref_prefixes = ARGV_ARRAY_INIT;
 		int i;
 
 		if (check_push_refs(local_refs, refspec_nr, refspec) < 0)
 			return -1;
 
-		tmp_rs = parse_push_refspec(refspec_nr, refspec);
-		for (i = 0; i < refspec_nr; i++) {
+		refspec_appendn(&tmp_rs, refspec, refspec_nr);
+		for (i = 0; i < tmp_rs.nr; i++) {
+			const struct refspec_item *item = &tmp_rs.items[i];
 			const char *prefix = NULL;
 
-			if (tmp_rs[i].dst)
-				prefix = tmp_rs[i].dst;
-			else if (tmp_rs[i].src && !tmp_rs[i].exact_sha1)
-				prefix = tmp_rs[i].src;
+			if (item->dst)
+				prefix = item->dst;
+			else if (item->src && !item->exact_sha1)
+				prefix = item->src;
 
 			if (prefix) {
 				const char *glob = strchr(prefix, '*');
@@ -1142,7 +1143,7 @@ int transport_push(struct transport *transport,
 							       &ref_prefixes);
 
 		argv_array_clear(&ref_prefixes);
-		free_refspec(refspec_nr, tmp_rs);
+		refspec_clear(&tmp_rs);
 
 		if (flags & TRANSPORT_PUSH_ALL)
 			match_flags |= MATCH_REFS_ALL;
-- 
2.17.0.441.gb46fe60e1d-goog


^ permalink raw reply related	[flat|nested] 112+ messages in thread

* [PATCH v2 09/36] remote: convert check_push_refs to use struct refspec
  2018-05-16 22:57 ` [PATCH v2 00/36] " Brandon Williams
                     ` (7 preceding siblings ...)
  2018-05-16 22:57   ` [PATCH v2 08/36] transport: convert transport_push to use struct refspec Brandon Williams
@ 2018-05-16 22:57   ` Brandon Williams
  2018-05-16 22:57   ` [PATCH v2 10/36] remote: convert match_push_refs " Brandon Williams
                     ` (27 subsequent siblings)
  36 siblings, 0 replies; 112+ messages in thread
From: Brandon Williams @ 2018-05-16 22:57 UTC (permalink / raw)
  To: git, avarab, gitster, sbeller, bmwill
  Cc: avarab, gitster, sbeller, Brandon Williams

Convert 'check_push_refs()' to use 'struct refspec'.

Signed-off-by: Brandon Williams <bmwill@google.com>
---
 remote.c | 10 ++++++----
 1 file changed, 6 insertions(+), 4 deletions(-)

diff --git a/remote.c b/remote.c
index 89820c476..191855118 100644
--- a/remote.c
+++ b/remote.c
@@ -1282,12 +1282,14 @@ static void prepare_ref_index(struct string_list *ref_index, struct ref *ref)
  */
 int check_push_refs(struct ref *src, int nr_refspec, const char **refspec_names)
 {
-	struct refspec_item *refspec = parse_push_refspec(nr_refspec, refspec_names);
+	struct refspec refspec = REFSPEC_INIT_PUSH;
 	int ret = 0;
 	int i;
 
-	for (i = 0; i < nr_refspec; i++) {
-		struct refspec_item *rs = refspec + i;
+	refspec_appendn(&refspec, refspec_names, nr_refspec);
+
+	for (i = 0; i < refspec.nr; i++) {
+		struct refspec_item *rs = &refspec.items[i];
 
 		if (rs->pattern || rs->matching)
 			continue;
@@ -1295,7 +1297,7 @@ int check_push_refs(struct ref *src, int nr_refspec, const char **refspec_names)
 		ret |= match_explicit_lhs(src, rs, NULL, NULL);
 	}
 
-	free_refspec(nr_refspec, refspec);
+	refspec_clear(&refspec);
 	return ret;
 }
 
-- 
2.17.0.441.gb46fe60e1d-goog


^ permalink raw reply related	[flat|nested] 112+ messages in thread

* [PATCH v2 10/36] remote: convert match_push_refs to use struct refspec
  2018-05-16 22:57 ` [PATCH v2 00/36] " Brandon Williams
                     ` (8 preceding siblings ...)
  2018-05-16 22:57   ` [PATCH v2 09/36] remote: convert check_push_refs " Brandon Williams
@ 2018-05-16 22:57   ` Brandon Williams
  2018-05-16 22:57   ` [PATCH v2 11/36] clone: convert cmd_clone to use refspec_item_init Brandon Williams
                     ` (26 subsequent siblings)
  36 siblings, 0 replies; 112+ messages in thread
From: Brandon Williams @ 2018-05-16 22:57 UTC (permalink / raw)
  To: git, avarab, gitster, sbeller, bmwill
  Cc: avarab, gitster, sbeller, Brandon Williams

Convert 'match_push_refs()' to use struct refspec.

Signed-off-by: Brandon Williams <bmwill@google.com>
---
 remote.c | 13 ++++++++-----
 1 file changed, 8 insertions(+), 5 deletions(-)

diff --git a/remote.c b/remote.c
index 191855118..bce6e7ce4 100644
--- a/remote.c
+++ b/remote.c
@@ -1312,7 +1312,7 @@ int check_push_refs(struct ref *src, int nr_refspec, const char **refspec_names)
 int match_push_refs(struct ref *src, struct ref **dst,
 		    int nr_refspec, const char **refspec, int flags)
 {
-	struct refspec_item *rs;
+	struct refspec rs = REFSPEC_INIT_PUSH;
 	int send_all = flags & MATCH_REFS_ALL;
 	int send_mirror = flags & MATCH_REFS_MIRROR;
 	int send_prune = flags & MATCH_REFS_PRUNE;
@@ -1325,8 +1325,8 @@ int match_push_refs(struct ref *src, struct ref **dst,
 		nr_refspec = 1;
 		refspec = default_refspec;
 	}
-	rs = parse_push_refspec(nr_refspec, (const char **) refspec);
-	errs = match_explicit_refs(src, *dst, &dst_tail, rs, nr_refspec);
+	refspec_appendn(&rs, refspec, nr_refspec);
+	errs = match_explicit_refs(src, *dst, &dst_tail, rs.items, rs.nr);
 
 	/* pick the remainder */
 	for (ref = src; ref; ref = ref->next) {
@@ -1335,7 +1335,7 @@ int match_push_refs(struct ref *src, struct ref **dst,
 		const struct refspec_item *pat = NULL;
 		char *dst_name;
 
-		dst_name = get_ref_match(rs, nr_refspec, ref, send_mirror, FROM_SRC, &pat);
+		dst_name = get_ref_match(rs.items, rs.nr, ref, send_mirror, FROM_SRC, &pat);
 		if (!dst_name)
 			continue;
 
@@ -1384,7 +1384,7 @@ int match_push_refs(struct ref *src, struct ref **dst,
 				/* We're already sending something to this ref. */
 				continue;
 
-			src_name = get_ref_match(rs, nr_refspec, ref, send_mirror, FROM_DST, NULL);
+			src_name = get_ref_match(rs.items, rs.nr, ref, send_mirror, FROM_DST, NULL);
 			if (src_name) {
 				if (!src_ref_index.nr)
 					prepare_ref_index(&src_ref_index, src);
@@ -1396,6 +1396,9 @@ int match_push_refs(struct ref *src, struct ref **dst,
 		}
 		string_list_clear(&src_ref_index, 0);
 	}
+
+	refspec_clear(&rs);
+
 	if (errs)
 		return -1;
 	return 0;
-- 
2.17.0.441.gb46fe60e1d-goog


^ permalink raw reply related	[flat|nested] 112+ messages in thread

* [PATCH v2 11/36] clone: convert cmd_clone to use refspec_item_init
  2018-05-16 22:57 ` [PATCH v2 00/36] " Brandon Williams
                     ` (9 preceding siblings ...)
  2018-05-16 22:57   ` [PATCH v2 10/36] remote: convert match_push_refs " Brandon Williams
@ 2018-05-16 22:57   ` Brandon Williams
  2018-05-16 22:57   ` [PATCH v2 12/36] fast-export: convert to use struct refspec Brandon Williams
                     ` (25 subsequent siblings)
  36 siblings, 0 replies; 112+ messages in thread
From: Brandon Williams @ 2018-05-16 22:57 UTC (permalink / raw)
  To: git, avarab, gitster, sbeller, bmwill
  Cc: avarab, gitster, sbeller, Brandon Williams

Convert 'cmd_clone()' to use 'refspec_item_init()' instead of relying on
the old 'parse_fetch_refspec()' to initialize a single refspec item.

Signed-off-by: Brandon Williams <bmwill@google.com>
---
 builtin/clone.c | 10 ++++------
 1 file changed, 4 insertions(+), 6 deletions(-)

diff --git a/builtin/clone.c b/builtin/clone.c
index 854088a3a..8c5f4d8f0 100644
--- a/builtin/clone.c
+++ b/builtin/clone.c
@@ -895,8 +895,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
 	int err = 0, complete_refs_before_fetch = 1;
 	int submodule_progress;
 
-	struct refspec_item *refspec;
-	const char *fetch_pattern;
+	struct refspec_item refspec;
 
 	fetch_if_missing = 0;
 
@@ -1078,8 +1077,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
 	if (option_required_reference.nr || option_optional_reference.nr)
 		setup_reference();
 
-	fetch_pattern = value.buf;
-	refspec = parse_fetch_refspec(1, &fetch_pattern);
+	refspec_item_init(&refspec, value.buf, REFSPEC_FETCH);
 
 	strbuf_reset(&value);
 
@@ -1139,7 +1137,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
 	refs = transport_get_remote_refs(transport, NULL);
 
 	if (refs) {
-		mapped_refs = wanted_peer_refs(refs, refspec);
+		mapped_refs = wanted_peer_refs(refs, &refspec);
 		/*
 		 * transport_get_remote_refs() may return refs with null sha-1
 		 * in mapped_refs (see struct transport->get_refs_list
@@ -1233,6 +1231,6 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
 	strbuf_release(&value);
 	junk_mode = JUNK_LEAVE_ALL;
 
-	free(refspec);
+	refspec_item_clear(&refspec);
 	return err;
 }
-- 
2.17.0.441.gb46fe60e1d-goog


^ permalink raw reply related	[flat|nested] 112+ messages in thread

* [PATCH v2 12/36] fast-export: convert to use struct refspec
  2018-05-16 22:57 ` [PATCH v2 00/36] " Brandon Williams
                     ` (10 preceding siblings ...)
  2018-05-16 22:57   ` [PATCH v2 11/36] clone: convert cmd_clone to use refspec_item_init Brandon Williams
@ 2018-05-16 22:57   ` Brandon Williams
  2018-05-16 22:58   ` [PATCH v2 13/36] remote: convert push refspecs to " Brandon Williams
                     ` (24 subsequent siblings)
  36 siblings, 0 replies; 112+ messages in thread
From: Brandon Williams @ 2018-05-16 22:57 UTC (permalink / raw)
  To: git, avarab, gitster, sbeller, bmwill
  Cc: avarab, gitster, sbeller, Brandon Williams

Convert fast-export to use 'struct refspec' instead of using a list of
refspec_item's.

Signed-off-by: Brandon Williams <bmwill@google.com>
---
 builtin/fast-export.c | 21 +++++++--------------
 1 file changed, 7 insertions(+), 14 deletions(-)

diff --git a/builtin/fast-export.c b/builtin/fast-export.c
index 6f105dc79..143999738 100644
--- a/builtin/fast-export.c
+++ b/builtin/fast-export.c
@@ -36,8 +36,7 @@ static int use_done_feature;
 static int no_data;
 static int full_tree;
 static struct string_list extra_refs = STRING_LIST_INIT_NODUP;
-static struct refspec_item *refspecs;
-static int refspecs_nr;
+static struct refspec refspecs = REFSPEC_INIT_FETCH;
 static int anonymize;
 
 static int parse_opt_signed_tag_mode(const struct option *opt,
@@ -830,9 +829,9 @@ static void get_tags_and_duplicates(struct rev_cmdline_info *info)
 		if (dwim_ref(e->name, strlen(e->name), &oid, &full_name) != 1)
 			continue;
 
-		if (refspecs) {
+		if (refspecs.nr) {
 			char *private;
-			private = apply_refspecs(refspecs, refspecs_nr, full_name);
+			private = apply_refspecs(refspecs.items, refspecs.nr, full_name);
 			if (private) {
 				free(full_name);
 				full_name = private;
@@ -978,8 +977,8 @@ static void import_marks(char *input_file)
 static void handle_deletes(void)
 {
 	int i;
-	for (i = 0; i < refspecs_nr; i++) {
-		struct refspec_item *refspec = &refspecs[i];
+	for (i = 0; i < refspecs.nr; i++) {
+		struct refspec_item *refspec = &refspecs.items[i];
 		if (*refspec->src)
 			continue;
 
@@ -1040,18 +1039,12 @@ int cmd_fast_export(int argc, const char **argv, const char *prefix)
 		usage_with_options (fast_export_usage, options);
 
 	if (refspecs_list.nr) {
-		const char **refspecs_str;
 		int i;
 
-		ALLOC_ARRAY(refspecs_str, refspecs_list.nr);
 		for (i = 0; i < refspecs_list.nr; i++)
-			refspecs_str[i] = refspecs_list.items[i].string;
-
-		refspecs_nr = refspecs_list.nr;
-		refspecs = parse_fetch_refspec(refspecs_nr, refspecs_str);
+			refspec_append(&refspecs, refspecs_list.items[i].string);
 
 		string_list_clear(&refspecs_list, 1);
-		free(refspecs_str);
 	}
 
 	if (use_done_feature)
@@ -1090,7 +1083,7 @@ int cmd_fast_export(int argc, const char **argv, const char *prefix)
 	if (use_done_feature)
 		printf("done\n");
 
-	free_refspec(refspecs_nr, refspecs);
+	refspec_clear(&refspecs);
 
 	return 0;
 }
-- 
2.17.0.441.gb46fe60e1d-goog


^ permalink raw reply related	[flat|nested] 112+ messages in thread

* [PATCH v2 13/36] remote: convert push refspecs to struct refspec
  2018-05-16 22:57 ` [PATCH v2 00/36] " Brandon Williams
                     ` (11 preceding siblings ...)
  2018-05-16 22:57   ` [PATCH v2 12/36] fast-export: convert to use struct refspec Brandon Williams
@ 2018-05-16 22:58   ` Brandon Williams
  2018-05-16 22:58   ` [PATCH v2 14/36] remote: convert fetch " Brandon Williams
                     ` (23 subsequent siblings)
  36 siblings, 0 replies; 112+ messages in thread
From: Brandon Williams @ 2018-05-16 22:58 UTC (permalink / raw)
  To: git, avarab, gitster, sbeller, bmwill
  Cc: avarab, gitster, sbeller, Brandon Williams

Convert the set of push refspecs stored in 'struct remote' to use
'struct refspec'.

Signed-off-by: Brandon Williams <bmwill@google.com>
---
 builtin/push.c   | 10 +++++-----
 builtin/remote.c | 14 +++++++-------
 remote.c         | 35 ++++++++++++++---------------------
 remote.h         |  6 ++----
 4 files changed, 28 insertions(+), 37 deletions(-)

diff --git a/builtin/push.c b/builtin/push.c
index 00d81fb1d..509dc6677 100644
--- a/builtin/push.c
+++ b/builtin/push.c
@@ -79,11 +79,11 @@ static const char *map_refspec(const char *ref,
 	if (count_refspec_match(ref, local_refs, &matched) != 1)
 		return ref;
 
-	if (remote->push) {
+	if (remote->push.nr) {
 		struct refspec_item query;
 		memset(&query, 0, sizeof(struct refspec_item));
 		query.src = matched->name;
-		if (!query_refspecs(remote->push, remote->push_refspec_nr, &query) &&
+		if (!query_refspecs(remote->push.items, remote->push.nr, &query) &&
 		    query.dst) {
 			struct strbuf buf = STRBUF_INIT;
 			strbuf_addf(&buf, "%s%s:%s",
@@ -436,9 +436,9 @@ static int do_push(const char *repo, int flags,
 	}
 
 	if (!refspec && !(flags & TRANSPORT_PUSH_ALL)) {
-		if (remote->push_refspec_nr) {
-			refspec = remote->push_refspec;
-			refspec_nr = remote->push_refspec_nr;
+		if (remote->push.raw_nr) {
+			refspec = remote->push.raw;
+			refspec_nr = remote->push.raw_nr;
 		} else if (!(flags & TRANSPORT_PUSH_MIRROR))
 			setup_default_push_refspecs(remote);
 	}
diff --git a/builtin/remote.c b/builtin/remote.c
index d9da82dc8..fb84729d6 100644
--- a/builtin/remote.c
+++ b/builtin/remote.c
@@ -388,8 +388,8 @@ static int get_push_ref_states(const struct ref *remote_refs,
 	local_refs = get_local_heads();
 	push_map = copy_ref_list(remote_refs);
 
-	match_push_refs(local_refs, &push_map, remote->push_refspec_nr,
-			remote->push_refspec, MATCH_REFS_NONE);
+	match_push_refs(local_refs, &push_map, remote->push.raw_nr,
+			remote->push.raw, MATCH_REFS_NONE);
 
 	states->push.strdup_strings = 1;
 	for (ref = push_map; ref; ref = ref->next) {
@@ -435,14 +435,14 @@ static int get_push_ref_states_noquery(struct ref_states *states)
 		return 0;
 
 	states->push.strdup_strings = 1;
-	if (!remote->push_refspec_nr) {
+	if (!remote->push.nr) {
 		item = string_list_append(&states->push, _("(matching)"));
 		info = item->util = xcalloc(1, sizeof(struct push_info));
 		info->status = PUSH_STATUS_NOTQUERIED;
 		info->dest = xstrdup(item->string);
 	}
-	for (i = 0; i < remote->push_refspec_nr; i++) {
-		struct refspec_item *spec = remote->push + i;
+	for (i = 0; i < remote->push.nr; i++) {
+		const struct refspec_item *spec = &remote->push.items[i];
 		if (spec->matching)
 			item = string_list_append(&states->push, _("(matching)"));
 		else if (strlen(spec->src))
@@ -586,8 +586,8 @@ static int migrate_file(struct remote *remote)
 		git_config_set_multivar(buf.buf, remote->url[i], "^$", 0);
 	strbuf_reset(&buf);
 	strbuf_addf(&buf, "remote.%s.push", remote->name);
-	for (i = 0; i < remote->push_refspec_nr; i++)
-		git_config_set_multivar(buf.buf, remote->push_refspec[i], "^$", 0);
+	for (i = 0; i < remote->push.raw_nr; i++)
+		git_config_set_multivar(buf.buf, remote->push.raw[i], "^$", 0);
 	strbuf_reset(&buf);
 	strbuf_addf(&buf, "remote.%s.fetch", remote->name);
 	for (i = 0; i < remote->fetch_refspec_nr; i++)
diff --git a/remote.c b/remote.c
index bce6e7ce4..1b7258f77 100644
--- a/remote.c
+++ b/remote.c
@@ -77,14 +77,6 @@ static const char *alias_url(const char *url, struct rewrites *r)
 	return xstrfmt("%s%s", r->rewrite[longest_i]->base, url + longest->len);
 }
 
-static void add_push_refspec(struct remote *remote, const char *ref)
-{
-	ALLOC_GROW(remote->push_refspec,
-		   remote->push_refspec_nr + 1,
-		   remote->push_refspec_alloc);
-	remote->push_refspec[remote->push_refspec_nr++] = ref;
-}
-
 static void add_fetch_refspec(struct remote *remote, const char *ref)
 {
 	ALLOC_GROW(remote->fetch_refspec,
@@ -175,9 +167,11 @@ static struct remote *make_remote(const char *name, int len)
 	ret = xcalloc(1, sizeof(struct remote));
 	ret->prune = -1;  /* unspecified */
 	ret->prune_tags = -1;  /* unspecified */
+	ret->name = xstrndup(name, len);
+	refspec_init(&ret->push, REFSPEC_PUSH);
+
 	ALLOC_GROW(remotes, remotes_nr + 1, remotes_alloc);
 	remotes[remotes_nr++] = ret;
-	ret->name = xstrndup(name, len);
 
 	hashmap_entry_init(ret, lookup_entry.hash);
 	replaced = hashmap_put(&remotes_hash, ret);
@@ -275,7 +269,7 @@ static void read_remotes_file(struct remote *remote)
 		if (skip_prefix(buf.buf, "URL:", &v))
 			add_url_alias(remote, xstrdup(skip_spaces(v)));
 		else if (skip_prefix(buf.buf, "Push:", &v))
-			add_push_refspec(remote, xstrdup(skip_spaces(v)));
+			refspec_append(&remote->push, skip_spaces(v));
 		else if (skip_prefix(buf.buf, "Pull:", &v))
 			add_fetch_refspec(remote, xstrdup(skip_spaces(v)));
 	}
@@ -323,8 +317,10 @@ static void read_branches_file(struct remote *remote)
 	 * Cogito compatible push: push current HEAD to remote #branch
 	 * (master if missing)
 	 */
-	add_push_refspec(remote, xstrfmt("HEAD:refs/heads/%s", frag));
+	strbuf_addf(&buf, "HEAD:refs/heads/%s", frag);
+	refspec_append(&remote->push, buf.buf);
 	remote->fetch_tags = 1; /* always auto-follow */
+	strbuf_release(&buf);
 }
 
 static int handle_config(const char *key, const char *value, void *cb)
@@ -409,7 +405,8 @@ static int handle_config(const char *key, const char *value, void *cb)
 		const char *v;
 		if (git_config_string(&v, key, value))
 			return -1;
-		add_push_refspec(remote, v);
+		refspec_append(&remote->push, v);
+		free((char *)v);
 	} else if (!strcmp(subkey, "fetch")) {
 		const char *v;
 		if (git_config_string(&v, key, value))
@@ -542,9 +539,9 @@ const char *remote_ref_for_branch(struct branch *branch, int for_push,
 				pushremote_for_branch(branch, NULL);
 			struct remote *remote = remote_get(remote_name);
 
-			if (remote && remote->push_refspec_nr &&
-			    (dst = apply_refspecs(remote->push,
-						  remote->push_refspec_nr,
+			if (remote && remote->push.nr &&
+			    (dst = apply_refspecs(remote->push.items,
+						  remote->push.nr,
 						  branch->refname))) {
 				if (explicit)
 					*explicit = 1;
@@ -582,7 +579,6 @@ static struct remote *remote_get_1(const char *name,
 	if (!valid_remote(ret))
 		return NULL;
 	ret->fetch = parse_fetch_refspec(ret->fetch_refspec_nr, ret->fetch_refspec);
-	ret->push = parse_push_refspec(ret->push_refspec_nr, ret->push_refspec);
 	return ret;
 }
 
@@ -616,9 +612,6 @@ int for_each_remote(each_remote_fn fn, void *priv)
 		if (!r->fetch)
 			r->fetch = parse_fetch_refspec(r->fetch_refspec_nr,
 						       r->fetch_refspec);
-		if (!r->push)
-			r->push = parse_push_refspec(r->push_refspec_nr,
-						     r->push_refspec);
 		result = fn(r, priv);
 	}
 	return result;
@@ -1613,11 +1606,11 @@ static const char *branch_get_push_1(struct branch *branch, struct strbuf *err)
 				 _("branch '%s' has no remote for pushing"),
 				 branch->name);
 
-	if (remote->push_refspec_nr) {
+	if (remote->push.nr) {
 		char *dst;
 		const char *ret;
 
-		dst = apply_refspecs(remote->push, remote->push_refspec_nr,
+		dst = apply_refspecs(remote->push.items, remote->push.nr,
 				     branch->refname);
 		if (!dst)
 			return error_buf(err,
diff --git a/remote.h b/remote.h
index 3657bd43d..637fc5d0c 100644
--- a/remote.h
+++ b/remote.h
@@ -3,6 +3,7 @@
 
 #include "parse-options.h"
 #include "hashmap.h"
+#include "refspec.h"
 
 enum {
 	REMOTE_UNCONFIGURED = 0,
@@ -27,10 +28,7 @@ struct remote {
 	int pushurl_nr;
 	int pushurl_alloc;
 
-	const char **push_refspec;
-	struct refspec_item *push;
-	int push_refspec_nr;
-	int push_refspec_alloc;
+	struct refspec push;
 
 	const char **fetch_refspec;
 	struct refspec_item *fetch;
-- 
2.17.0.441.gb46fe60e1d-goog


^ permalink raw reply related	[flat|nested] 112+ messages in thread

* [PATCH v2 14/36] remote: convert fetch refspecs to struct refspec
  2018-05-16 22:57 ` [PATCH v2 00/36] " Brandon Williams
                     ` (12 preceding siblings ...)
  2018-05-16 22:58   ` [PATCH v2 13/36] remote: convert push refspecs to " Brandon Williams
@ 2018-05-16 22:58   ` Brandon Williams
  2018-05-16 22:58   ` [PATCH v2 15/36] remote: remove add_prune_tags_to_fetch_refspec Brandon Williams
                     ` (22 subsequent siblings)
  36 siblings, 0 replies; 112+ messages in thread
From: Brandon Williams @ 2018-05-16 22:58 UTC (permalink / raw)
  To: git, avarab, gitster, sbeller, bmwill
  Cc: avarab, gitster, sbeller, Brandon Williams

Convert the set of fetch refspecs stored in 'struct remote' to use
'struct refspec'.

Signed-off-by: Brandon Williams <bmwill@google.com>
---
 builtin/fetch.c  | 20 ++++++++++----------
 builtin/remote.c | 18 +++++++++---------
 remote.c         | 38 ++++++++++++--------------------------
 remote.h         |  5 +----
 4 files changed, 32 insertions(+), 49 deletions(-)

diff --git a/builtin/fetch.c b/builtin/fetch.c
index 745020a10..30083d4bc 100644
--- a/builtin/fetch.c
+++ b/builtin/fetch.c
@@ -407,8 +407,8 @@ static struct ref *get_ref_map(struct transport *transport,
 			fetch_refspec = parse_fetch_refspec(refmap_nr, refmap_array);
 			fetch_refspec_nr = refmap_nr;
 		} else {
-			fetch_refspec = transport->remote->fetch;
-			fetch_refspec_nr = transport->remote->fetch_refspec_nr;
+			fetch_refspec = transport->remote->fetch.items;
+			fetch_refspec_nr = transport->remote->fetch.nr;
 		}
 
 		for (i = 0; i < fetch_refspec_nr; i++)
@@ -421,16 +421,16 @@ static struct ref *get_ref_map(struct transport *transport,
 		struct branch *branch = branch_get(NULL);
 		int has_merge = branch_has_merge_config(branch);
 		if (remote &&
-		    (remote->fetch_refspec_nr ||
+		    (remote->fetch.nr ||
 		     /* Note: has_merge implies non-NULL branch->remote_name */
 		     (has_merge && !strcmp(branch->remote_name, remote->name)))) {
-			for (i = 0; i < remote->fetch_refspec_nr; i++) {
-				get_fetch_map(remote_refs, &remote->fetch[i], &tail, 0);
-				if (remote->fetch[i].dst &&
-				    remote->fetch[i].dst[0])
+			for (i = 0; i < remote->fetch.nr; i++) {
+				get_fetch_map(remote_refs, &remote->fetch.items[i], &tail, 0);
+				if (remote->fetch.items[i].dst &&
+				    remote->fetch.items[i].dst[0])
 					*autotags = 1;
 				if (!i && !has_merge && ref_map &&
-				    !remote->fetch[0].pattern)
+				    !remote->fetch.items[0].pattern)
 					ref_map->fetch_head_status = FETCH_HEAD_MERGE;
 			}
 			/*
@@ -1166,8 +1166,8 @@ static int do_fetch(struct transport *transport,
 		if (ref_count) {
 			prune_refs(refs, ref_count, ref_map, transport->url);
 		} else {
-			prune_refs(transport->remote->fetch,
-				   transport->remote->fetch_refspec_nr,
+			prune_refs(transport->remote->fetch.items,
+				   transport->remote->fetch.nr,
 				   ref_map,
 				   transport->url);
 		}
diff --git a/builtin/remote.c b/builtin/remote.c
index fb84729d6..94dfcb78b 100644
--- a/builtin/remote.c
+++ b/builtin/remote.c
@@ -333,10 +333,10 @@ static int get_ref_states(const struct ref *remote_refs, struct ref_states *stat
 	struct ref *ref, *stale_refs;
 	int i;
 
-	for (i = 0; i < states->remote->fetch_refspec_nr; i++)
-		if (get_fetch_map(remote_refs, states->remote->fetch + i, &tail, 1))
+	for (i = 0; i < states->remote->fetch.nr; i++)
+		if (get_fetch_map(remote_refs, &states->remote->fetch.items[i], &tail, 1))
 			die(_("Could not get fetch map for refspec %s"),
-				states->remote->fetch_refspec[i]);
+				states->remote->fetch.raw[i]);
 
 	states->new_refs.strdup_strings = 1;
 	states->tracked.strdup_strings = 1;
@@ -347,8 +347,8 @@ static int get_ref_states(const struct ref *remote_refs, struct ref_states *stat
 		else
 			string_list_append(&states->tracked, abbrev_branch(ref->name));
 	}
-	stale_refs = get_stale_heads(states->remote->fetch,
-				     states->remote->fetch_refspec_nr, fetch_map);
+	stale_refs = get_stale_heads(states->remote->fetch.items,
+				     states->remote->fetch.nr, fetch_map);
 	for (ref = stale_refs; ref; ref = ref->next) {
 		struct string_list_item *item =
 			string_list_append(&states->stale, abbrev_branch(ref->name));
@@ -590,8 +590,8 @@ static int migrate_file(struct remote *remote)
 		git_config_set_multivar(buf.buf, remote->push.raw[i], "^$", 0);
 	strbuf_reset(&buf);
 	strbuf_addf(&buf, "remote.%s.fetch", remote->name);
-	for (i = 0; i < remote->fetch_refspec_nr; i++)
-		git_config_set_multivar(buf.buf, remote->fetch_refspec[i], "^$", 0);
+	for (i = 0; i < remote->fetch.raw_nr; i++)
+		git_config_set_multivar(buf.buf, remote->fetch.raw[i], "^$", 0);
 	if (remote->origin == REMOTE_REMOTES)
 		unlink_or_warn(git_path("remotes/%s", remote->name));
 	else if (remote->origin == REMOTE_BRANCHES)
@@ -646,11 +646,11 @@ static int mv(int argc, const char **argv)
 	strbuf_addf(&buf, "remote.%s.fetch", rename.new_name);
 	git_config_set_multivar(buf.buf, NULL, NULL, 1);
 	strbuf_addf(&old_remote_context, ":refs/remotes/%s/", rename.old_name);
-	for (i = 0; i < oldremote->fetch_refspec_nr; i++) {
+	for (i = 0; i < oldremote->fetch.raw_nr; i++) {
 		char *ptr;
 
 		strbuf_reset(&buf2);
-		strbuf_addstr(&buf2, oldremote->fetch_refspec[i]);
+		strbuf_addstr(&buf2, oldremote->fetch.raw[i]);
 		ptr = strstr(buf2.buf, old_remote_context.buf);
 		if (ptr) {
 			refspec_updated = 1;
diff --git a/remote.c b/remote.c
index 1b7258f77..26842ce37 100644
--- a/remote.c
+++ b/remote.c
@@ -77,23 +77,9 @@ static const char *alias_url(const char *url, struct rewrites *r)
 	return xstrfmt("%s%s", r->rewrite[longest_i]->base, url + longest->len);
 }
 
-static void add_fetch_refspec(struct remote *remote, const char *ref)
-{
-	ALLOC_GROW(remote->fetch_refspec,
-		   remote->fetch_refspec_nr + 1,
-		   remote->fetch_refspec_alloc);
-	remote->fetch_refspec[remote->fetch_refspec_nr++] = ref;
-}
-
 void add_prune_tags_to_fetch_refspec(struct remote *remote)
 {
-	int nr = remote->fetch_refspec_nr;
-	int bufsize = nr  + 1;
-	int size = sizeof(struct refspec_item);
-
-	remote->fetch = xrealloc(remote->fetch, size  * bufsize);
-	memcpy(&remote->fetch[nr], tag_refspec, size);
-	add_fetch_refspec(remote, xstrdup(TAG_REFSPEC));
+	refspec_append(&remote->fetch, TAG_REFSPEC);
 }
 
 static void add_url(struct remote *remote, const char *url)
@@ -169,6 +155,7 @@ static struct remote *make_remote(const char *name, int len)
 	ret->prune_tags = -1;  /* unspecified */
 	ret->name = xstrndup(name, len);
 	refspec_init(&ret->push, REFSPEC_PUSH);
+	refspec_init(&ret->fetch, REFSPEC_FETCH);
 
 	ALLOC_GROW(remotes, remotes_nr + 1, remotes_alloc);
 	remotes[remotes_nr++] = ret;
@@ -271,7 +258,7 @@ static void read_remotes_file(struct remote *remote)
 		else if (skip_prefix(buf.buf, "Push:", &v))
 			refspec_append(&remote->push, skip_spaces(v));
 		else if (skip_prefix(buf.buf, "Pull:", &v))
-			add_fetch_refspec(remote, xstrdup(skip_spaces(v)));
+			refspec_append(&remote->fetch, skip_spaces(v));
 	}
 	strbuf_release(&buf);
 	fclose(f);
@@ -310,13 +297,15 @@ static void read_branches_file(struct remote *remote)
 		frag = "master";
 
 	add_url_alias(remote, strbuf_detach(&buf, NULL));
-	add_fetch_refspec(remote, xstrfmt("refs/heads/%s:refs/heads/%s",
-					  frag, remote->name));
+	strbuf_addf(&buf, "refs/heads/%s:refs/heads/%s",
+		    frag, remote->name);
+	refspec_append(&remote->fetch, buf.buf);
 
 	/*
 	 * Cogito compatible push: push current HEAD to remote #branch
 	 * (master if missing)
 	 */
+	strbuf_reset(&buf);
 	strbuf_addf(&buf, "HEAD:refs/heads/%s", frag);
 	refspec_append(&remote->push, buf.buf);
 	remote->fetch_tags = 1; /* always auto-follow */
@@ -411,7 +400,8 @@ static int handle_config(const char *key, const char *value, void *cb)
 		const char *v;
 		if (git_config_string(&v, key, value))
 			return -1;
-		add_fetch_refspec(remote, v);
+		refspec_append(&remote->fetch, v);
+		free((char *)v);
 	} else if (!strcmp(subkey, "receivepack")) {
 		const char *v;
 		if (git_config_string(&v, key, value))
@@ -578,7 +568,6 @@ static struct remote *remote_get_1(const char *name,
 		add_url_alias(ret, name);
 	if (!valid_remote(ret))
 		return NULL;
-	ret->fetch = parse_fetch_refspec(ret->fetch_refspec_nr, ret->fetch_refspec);
 	return ret;
 }
 
@@ -609,9 +598,6 @@ int for_each_remote(each_remote_fn fn, void *priv)
 		struct remote *r = remotes[i];
 		if (!r)
 			continue;
-		if (!r->fetch)
-			r->fetch = parse_fetch_refspec(r->fetch_refspec_nr,
-						       r->fetch_refspec);
 		result = fn(r, priv);
 	}
 	return result;
@@ -790,7 +776,7 @@ char *apply_refspecs(struct refspec_item *refspecs, int nr_refspec,
 
 int remote_find_tracking(struct remote *remote, struct refspec_item *refspec)
 {
-	return query_refspecs(remote->fetch, remote->fetch_refspec_nr, refspec);
+	return query_refspecs(remote->fetch.items, remote->fetch.nr, refspec);
 }
 
 static struct ref *alloc_ref_with_prefix(const char *prefix, size_t prefixlen,
@@ -1588,7 +1574,7 @@ static const char *tracking_for_push_dest(struct remote *remote,
 {
 	char *ret;
 
-	ret = apply_refspecs(remote->fetch, remote->fetch_refspec_nr, refname);
+	ret = apply_refspecs(remote->fetch.items, remote->fetch.nr, refname);
 	if (!ret)
 		return error_buf(err,
 				 _("push destination '%s' on remote '%s' has no local tracking branch"),
@@ -2222,7 +2208,7 @@ static int remote_tracking(struct remote *remote, const char *refname,
 {
 	char *dst;
 
-	dst = apply_refspecs(remote->fetch, remote->fetch_refspec_nr, refname);
+	dst = apply_refspecs(remote->fetch.items, remote->fetch.nr, refname);
 	if (!dst)
 		return -1; /* no tracking ref for refname at remote */
 	if (read_ref(dst, oid))
diff --git a/remote.h b/remote.h
index 637fc5d0c..e7d00fe2a 100644
--- a/remote.h
+++ b/remote.h
@@ -30,10 +30,7 @@ struct remote {
 
 	struct refspec push;
 
-	const char **fetch_refspec;
-	struct refspec_item *fetch;
-	int fetch_refspec_nr;
-	int fetch_refspec_alloc;
+	struct refspec fetch;
 
 	/*
 	 * -1 to never fetch tags
-- 
2.17.0.441.gb46fe60e1d-goog


^ permalink raw reply related	[flat|nested] 112+ messages in thread

* [PATCH v2 15/36] remote: remove add_prune_tags_to_fetch_refspec
  2018-05-16 22:57 ` [PATCH v2 00/36] " Brandon Williams
                     ` (13 preceding siblings ...)
  2018-05-16 22:58   ` [PATCH v2 14/36] remote: convert fetch " Brandon Williams
@ 2018-05-16 22:58   ` Brandon Williams
  2018-05-16 22:58   ` [PATCH v2 16/36] transport-helper: convert to use struct refspec Brandon Williams
                     ` (21 subsequent siblings)
  36 siblings, 0 replies; 112+ messages in thread
From: Brandon Williams @ 2018-05-16 22:58 UTC (permalink / raw)
  To: git, avarab, gitster, sbeller, bmwill
  Cc: avarab, gitster, sbeller, Brandon Williams

Remove 'add_prune_tags_to_fetch_refspec()' function and instead have the
only caller directly add the tag refspec using 'refspec_append()'.

Signed-off-by: Brandon Williams <bmwill@google.com>
---
 builtin/fetch.c | 2 +-
 remote.c        | 5 -----
 remote.h        | 2 --
 3 files changed, 1 insertion(+), 8 deletions(-)

diff --git a/builtin/fetch.c b/builtin/fetch.c
index 30083d4bc..7a1637d35 100644
--- a/builtin/fetch.c
+++ b/builtin/fetch.c
@@ -1392,7 +1392,7 @@ static int fetch_one(struct remote *remote, int argc, const char **argv, int pru
 
 	maybe_prune_tags = prune_tags_ok && prune_tags;
 	if (maybe_prune_tags && remote_via_config)
-		add_prune_tags_to_fetch_refspec(remote);
+		refspec_append(&remote->fetch, TAG_REFSPEC);
 
 	if (argc > 0 || (maybe_prune_tags && !remote_via_config)) {
 		size_t nr_alloc = st_add3(argc, maybe_prune_tags, 1);
diff --git a/remote.c b/remote.c
index 26842ce37..4a9bddf0d 100644
--- a/remote.c
+++ b/remote.c
@@ -77,11 +77,6 @@ static const char *alias_url(const char *url, struct rewrites *r)
 	return xstrfmt("%s%s", r->rewrite[longest_i]->base, url + longest->len);
 }
 
-void add_prune_tags_to_fetch_refspec(struct remote *remote)
-{
-	refspec_append(&remote->fetch, TAG_REFSPEC);
-}
-
 static void add_url(struct remote *remote, const char *url)
 {
 	ALLOC_GROW(remote->url, remote->url_nr + 1, remote->url_alloc);
diff --git a/remote.h b/remote.h
index e7d00fe2a..4ffbc0082 100644
--- a/remote.h
+++ b/remote.h
@@ -290,6 +290,4 @@ extern int parseopt_push_cas_option(const struct option *, const char *arg, int
 extern int is_empty_cas(const struct push_cas_option *);
 void apply_push_cas(struct push_cas_option *, struct remote *, struct ref *);
 
-void add_prune_tags_to_fetch_refspec(struct remote *remote);
-
 #endif
-- 
2.17.0.441.gb46fe60e1d-goog


^ permalink raw reply related	[flat|nested] 112+ messages in thread

* [PATCH v2 16/36] transport-helper: convert to use struct refspec
  2018-05-16 22:57 ` [PATCH v2 00/36] " Brandon Williams
                     ` (14 preceding siblings ...)
  2018-05-16 22:58   ` [PATCH v2 15/36] remote: remove add_prune_tags_to_fetch_refspec Brandon Williams
@ 2018-05-16 22:58   ` Brandon Williams
  2018-05-16 22:58   ` [PATCH v2 17/36] fetch: convert fetch_one " Brandon Williams
                     ` (20 subsequent siblings)
  36 siblings, 0 replies; 112+ messages in thread
From: Brandon Williams @ 2018-05-16 22:58 UTC (permalink / raw)
  To: git, avarab, gitster, sbeller, bmwill
  Cc: avarab, gitster, sbeller, Brandon Williams

Convert the refspecs in transport-helper.c to be stored in a
'struct refspec'.

Signed-off-by: Brandon Williams <bmwill@google.com>
---
 transport-helper.c | 38 ++++++++++++--------------------------
 1 file changed, 12 insertions(+), 26 deletions(-)

diff --git a/transport-helper.c b/transport-helper.c
index b156a37e7..33f51ebfc 100644
--- a/transport-helper.c
+++ b/transport-helper.c
@@ -36,8 +36,7 @@ struct helper_data {
 	char *export_marks;
 	char *import_marks;
 	/* These go from remote name (as in "list") to private name */
-	struct refspec_item *refspecs;
-	int refspec_nr;
+	struct refspec rs;
 	/* Transport options for fetch-pack/send-pack (should one of
 	 * those be invoked).
 	 */
@@ -107,9 +106,6 @@ static struct child_process *get_helper(struct transport *transport)
 	struct helper_data *data = transport->data;
 	struct strbuf buf = STRBUF_INIT;
 	struct child_process *helper;
-	const char **refspecs = NULL;
-	int refspec_nr = 0;
-	int refspec_alloc = 0;
 	int duped;
 	int code;
 
@@ -139,6 +135,7 @@ static struct child_process *get_helper(struct transport *transport)
 
 	data->helper = helper;
 	data->no_disconnect_req = 0;
+	refspec_init(&data->rs, REFSPEC_FETCH);
 
 	/*
 	 * Open the output as FILE* so strbuf_getline_*() family of
@@ -184,11 +181,8 @@ static struct child_process *get_helper(struct transport *transport)
 			data->export = 1;
 		else if (!strcmp(capname, "check-connectivity"))
 			data->check_connectivity = 1;
-		else if (!data->refspecs && skip_prefix(capname, "refspec ", &arg)) {
-			ALLOC_GROW(refspecs,
-				   refspec_nr + 1,
-				   refspec_alloc);
-			refspecs[refspec_nr++] = xstrdup(arg);
+		else if (skip_prefix(capname, "refspec ", &arg)) {
+			refspec_append(&data->rs, arg);
 		} else if (!strcmp(capname, "connect")) {
 			data->connect = 1;
 		} else if (!strcmp(capname, "stateless-connect")) {
@@ -207,14 +201,7 @@ static struct child_process *get_helper(struct transport *transport)
 			    capname);
 		}
 	}
-	if (refspecs) {
-		int i;
-		data->refspec_nr = refspec_nr;
-		data->refspecs = parse_fetch_refspec(refspec_nr, refspecs);
-		for (i = 0; i < refspec_nr; i++)
-			free((char *)refspecs[i]);
-		free(refspecs);
-	} else if (data->import || data->bidi_import || data->export) {
+	if (!data->rs.nr && (data->import || data->bidi_import || data->export)) {
 		warning("This remote helper should implement refspec capability.");
 	}
 	strbuf_release(&buf);
@@ -378,8 +365,7 @@ static int release_helper(struct transport *transport)
 {
 	int res = 0;
 	struct helper_data *data = transport->data;
-	free_refspec(data->refspec_nr, data->refspecs);
-	data->refspecs = NULL;
+	refspec_clear(&data->rs);
 	res = disconnect_helper(transport);
 	free(transport->data);
 	return res;
@@ -536,8 +522,8 @@ static int fetch_with_import(struct transport *transport,
 		if (posn->status & REF_STATUS_UPTODATE)
 			continue;
 		name = posn->symref ? posn->symref : posn->name;
-		if (data->refspecs)
-			private = apply_refspecs(data->refspecs, data->refspec_nr, name);
+		if (data->rs.nr)
+			private = apply_refspecs(data->rs.items, data->rs.nr, name);
 		else
 			private = xstrdup(name);
 		if (private) {
@@ -815,11 +801,11 @@ static int push_update_refs_status(struct helper_data *data,
 		if (push_update_ref_status(&buf, &ref, remote_refs))
 			continue;
 
-		if (flags & TRANSPORT_PUSH_DRY_RUN || !data->refspecs || data->no_private_update)
+		if (flags & TRANSPORT_PUSH_DRY_RUN || !data->rs.nr || data->no_private_update)
 			continue;
 
 		/* propagate back the update to the remote namespace */
-		private = apply_refspecs(data->refspecs, data->refspec_nr, ref->name);
+		private = apply_refspecs(data->rs.items, data->rs.nr, ref->name);
 		if (!private)
 			continue;
 		update_ref("update by helper", private, &ref->new_oid, NULL,
@@ -939,7 +925,7 @@ static int push_refs_with_export(struct transport *transport,
 	struct string_list revlist_args = STRING_LIST_INIT_DUP;
 	struct strbuf buf = STRBUF_INIT;
 
-	if (!data->refspecs)
+	if (!data->rs.nr)
 		die("remote-helper doesn't support push; refspec needed");
 
 	set_common_push_options(transport, data->name, flags);
@@ -956,7 +942,7 @@ static int push_refs_with_export(struct transport *transport,
 		char *private;
 		struct object_id oid;
 
-		private = apply_refspecs(data->refspecs, data->refspec_nr, ref->name);
+		private = apply_refspecs(data->rs.items, data->rs.nr, ref->name);
 		if (private && !get_oid(private, &oid)) {
 			strbuf_addf(&buf, "^%s", private);
 			string_list_append_nodup(&revlist_args,
-- 
2.17.0.441.gb46fe60e1d-goog


^ permalink raw reply related	[flat|nested] 112+ messages in thread

* [PATCH v2 17/36] fetch: convert fetch_one to use struct refspec
  2018-05-16 22:57 ` [PATCH v2 00/36] " Brandon Williams
                     ` (15 preceding siblings ...)
  2018-05-16 22:58   ` [PATCH v2 16/36] transport-helper: convert to use struct refspec Brandon Williams
@ 2018-05-16 22:58   ` Brandon Williams
  2018-05-16 22:58   ` [PATCH v2 18/36] fetch: convert refmap " Brandon Williams
                     ` (19 subsequent siblings)
  36 siblings, 0 replies; 112+ messages in thread
From: Brandon Williams @ 2018-05-16 22:58 UTC (permalink / raw)
  To: git, avarab, gitster, sbeller, bmwill
  Cc: avarab, gitster, sbeller, Brandon Williams

Convert 'fetch_one()' to use 'struct refspec'.

Signed-off-by: Brandon Williams <bmwill@google.com>
---
 builtin/fetch.c | 46 +++++++++++++++++++---------------------------
 1 file changed, 19 insertions(+), 27 deletions(-)

diff --git a/builtin/fetch.c b/builtin/fetch.c
index 7a1637d35..18704c6cd 100644
--- a/builtin/fetch.c
+++ b/builtin/fetch.c
@@ -1356,10 +1356,8 @@ static inline void fetch_one_setup_partial(struct remote *remote)
 
 static int fetch_one(struct remote *remote, int argc, const char **argv, int prune_tags_ok)
 {
-	static const char **refs = NULL;
-	struct refspec_item *refspec;
-	int ref_nr = 0;
-	int j = 0;
+	struct refspec rs = REFSPEC_INIT_FETCH;
+	int i;
 	int exit_code;
 	int maybe_prune_tags;
 	int remote_via_config = remote_is_configured(remote, 0);
@@ -1394,35 +1392,29 @@ static int fetch_one(struct remote *remote, int argc, const char **argv, int pru
 	if (maybe_prune_tags && remote_via_config)
 		refspec_append(&remote->fetch, TAG_REFSPEC);
 
-	if (argc > 0 || (maybe_prune_tags && !remote_via_config)) {
-		size_t nr_alloc = st_add3(argc, maybe_prune_tags, 1);
-		refs = xcalloc(nr_alloc, sizeof(const char *));
-		if (maybe_prune_tags) {
-			refs[j++] = xstrdup("refs/tags/*:refs/tags/*");
-			ref_nr++;
-		}
-	}
+	if (maybe_prune_tags && (argc || !remote_via_config))
+		refspec_append(&rs, TAG_REFSPEC);
 
-	if (argc > 0) {
-		int i;
-		for (i = 0; i < argc; i++) {
-			if (!strcmp(argv[i], "tag")) {
-				i++;
-				if (i >= argc)
-					die(_("You need to specify a tag name."));
-				refs[j++] = xstrfmt("refs/tags/%s:refs/tags/%s",
-						    argv[i], argv[i]);
-			} else
-				refs[j++] = argv[i];
-			ref_nr++;
+	for (i = 0; i < argc; i++) {
+		if (!strcmp(argv[i], "tag")) {
+			char *tag;
+			i++;
+			if (i >= argc)
+				die(_("You need to specify a tag name."));
+
+			tag = xstrfmt("refs/tags/%s:refs/tags/%s",
+				      argv[i], argv[i]);
+			refspec_append(&rs, tag);
+			free(tag);
+		} else {
+			refspec_append(&rs, argv[i]);
 		}
 	}
 
 	sigchain_push_common(unlock_pack_on_signal);
 	atexit(unlock_pack);
-	refspec = parse_fetch_refspec(ref_nr, refs);
-	exit_code = do_fetch(gtransport, refspec, ref_nr);
-	free_refspec(ref_nr, refspec);
+	exit_code = do_fetch(gtransport, rs.items, rs.nr);
+	refspec_clear(&rs);
 	transport_disconnect(gtransport);
 	gtransport = NULL;
 	return exit_code;
-- 
2.17.0.441.gb46fe60e1d-goog


^ permalink raw reply related	[flat|nested] 112+ messages in thread

* [PATCH v2 18/36] fetch: convert refmap to use struct refspec
  2018-05-16 22:57 ` [PATCH v2 00/36] " Brandon Williams
                     ` (16 preceding siblings ...)
  2018-05-16 22:58   ` [PATCH v2 17/36] fetch: convert fetch_one " Brandon Williams
@ 2018-05-16 22:58   ` Brandon Williams
  2018-05-16 22:58   ` [PATCH v2 19/36] refspec: remove the deprecated functions Brandon Williams
                     ` (18 subsequent siblings)
  36 siblings, 0 replies; 112+ messages in thread
From: Brandon Williams @ 2018-05-16 22:58 UTC (permalink / raw)
  To: git, avarab, gitster, sbeller, bmwill
  Cc: avarab, gitster, sbeller, Brandon Williams

Convert the refmap in builtin/fetch.c to be stored in a
'struct refspec'.

Signed-off-by: Brandon Williams <bmwill@google.com>
---
 builtin/fetch.c | 17 +++++++----------
 1 file changed, 7 insertions(+), 10 deletions(-)

diff --git a/builtin/fetch.c b/builtin/fetch.c
index 18704c6cd..6b909cd5b 100644
--- a/builtin/fetch.c
+++ b/builtin/fetch.c
@@ -60,8 +60,7 @@ static const char *submodule_prefix = "";
 static int recurse_submodules = RECURSE_SUBMODULES_DEFAULT;
 static int recurse_submodules_default = RECURSE_SUBMODULES_ON_DEMAND;
 static int shown_url = 0;
-static int refmap_alloc, refmap_nr;
-static const char **refmap_array;
+static struct refspec refmap = REFSPEC_INIT_FETCH;
 static struct list_objects_filter_options filter_options;
 
 static int git_fetch_config(const char *k, const char *v, void *cb)
@@ -108,14 +107,12 @@ static int gitmodules_fetch_config(const char *var, const char *value, void *cb)
 
 static int parse_refmap_arg(const struct option *opt, const char *arg, int unset)
 {
-	ALLOC_GROW(refmap_array, refmap_nr + 1, refmap_alloc);
-
 	/*
 	 * "git fetch --refmap='' origin foo"
 	 * can be used to tell the command not to store anywhere
 	 */
-	if (*arg)
-		refmap_array[refmap_nr++] = arg;
+	refspec_append(&refmap, arg);
+
 	return 0;
 }
 
@@ -403,9 +400,9 @@ static struct ref *get_ref_map(struct transport *transport,
 		 * by ref_remove_duplicates() in favor of one of these
 		 * opportunistic entries with FETCH_HEAD_IGNORE.
 		 */
-		if (refmap_array) {
-			fetch_refspec = parse_fetch_refspec(refmap_nr, refmap_array);
-			fetch_refspec_nr = refmap_nr;
+		if (refmap.nr) {
+			fetch_refspec = refmap.items;
+			fetch_refspec_nr = refmap.nr;
 		} else {
 			fetch_refspec = transport->remote->fetch.items;
 			fetch_refspec_nr = transport->remote->fetch.nr;
@@ -413,7 +410,7 @@ static struct ref *get_ref_map(struct transport *transport,
 
 		for (i = 0; i < fetch_refspec_nr; i++)
 			get_fetch_map(ref_map, &fetch_refspec[i], &oref_tail, 1);
-	} else if (refmap_array) {
+	} else if (refmap.nr) {
 		die("--refmap option is only meaningful with command-line refspec(s).");
 	} else {
 		/* Use the defaults */
-- 
2.17.0.441.gb46fe60e1d-goog


^ permalink raw reply related	[flat|nested] 112+ messages in thread

* [PATCH v2 19/36] refspec: remove the deprecated functions
  2018-05-16 22:57 ` [PATCH v2 00/36] " Brandon Williams
                     ` (17 preceding siblings ...)
  2018-05-16 22:58   ` [PATCH v2 18/36] fetch: convert refmap " Brandon Williams
@ 2018-05-16 22:58   ` Brandon Williams
  2018-05-16 22:58   ` [PATCH v2 20/36] fetch: convert do_fetch to take a struct refspec Brandon Williams
                     ` (17 subsequent siblings)
  36 siblings, 0 replies; 112+ messages in thread
From: Brandon Williams @ 2018-05-16 22:58 UTC (permalink / raw)
  To: git, avarab, gitster, sbeller, bmwill
  Cc: avarab, gitster, sbeller, Brandon Williams

Now that there are no callers of 'parse_push_refspec()',
'parse_fetch_refspec()', and 'free_refspec()', remove these
functions.

Signed-off-by: Brandon Williams <bmwill@google.com>
---
 refspec.c | 49 -------------------------------------------------
 refspec.h |  5 -----
 2 files changed, 54 deletions(-)

diff --git a/refspec.c b/refspec.c
index ab37b5ba1..97e76e8b1 100644
--- a/refspec.c
+++ b/refspec.c
@@ -121,55 +121,6 @@ static int parse_refspec(struct refspec_item *item, const char *refspec, int fet
 	return 1;
 }
 
-static struct refspec_item *parse_refspec_internal(int nr_refspec, const char **refspec, int fetch, int verify)
-{
-	int i;
-	struct refspec_item *rs = xcalloc(nr_refspec, sizeof(*rs));
-
-	for (i = 0; i < nr_refspec; i++) {
-		if (!parse_refspec(&rs[i], refspec[i], fetch))
-			goto invalid;
-	}
-
-	return rs;
-
- invalid:
-	if (verify) {
-		/*
-		 * nr_refspec must be greater than zero and i must be valid
-		 * since it is only possible to reach this point from within
-		 * the for loop above.
-		 */
-		free_refspec(i+1, rs);
-		return NULL;
-	}
-	die("Invalid refspec '%s'", refspec[i]);
-}
-
-struct refspec_item *parse_fetch_refspec(int nr_refspec, const char **refspec)
-{
-	return parse_refspec_internal(nr_refspec, refspec, 1, 0);
-}
-
-struct refspec_item *parse_push_refspec(int nr_refspec, const char **refspec)
-{
-	return parse_refspec_internal(nr_refspec, refspec, 0, 0);
-}
-
-void free_refspec(int nr_refspec, struct refspec_item *refspec)
-{
-	int i;
-
-	if (!refspec)
-		return;
-
-	for (i = 0; i < nr_refspec; i++) {
-		free(refspec[i].src);
-		free(refspec[i].dst);
-	}
-	free(refspec);
-}
-
 void refspec_item_init(struct refspec_item *item, const char *refspec, int fetch)
 {
 	memset(item, 0, sizeof(*item));
diff --git a/refspec.h b/refspec.h
index 1063c64cc..7e1ff94ac 100644
--- a/refspec.h
+++ b/refspec.h
@@ -14,11 +14,6 @@ struct refspec_item {
 	char *dst;
 };
 
-struct refspec_item *parse_fetch_refspec(int nr_refspec, const char **refspec);
-struct refspec_item *parse_push_refspec(int nr_refspec, const char **refspec);
-
-void free_refspec(int nr_refspec, struct refspec_item *refspec);
-
 #define REFSPEC_FETCH 1
 #define REFSPEC_PUSH 0
 
-- 
2.17.0.441.gb46fe60e1d-goog


^ permalink raw reply related	[flat|nested] 112+ messages in thread

* [PATCH v2 20/36] fetch: convert do_fetch to take a struct refspec
  2018-05-16 22:57 ` [PATCH v2 00/36] " Brandon Williams
                     ` (18 preceding siblings ...)
  2018-05-16 22:58   ` [PATCH v2 19/36] refspec: remove the deprecated functions Brandon Williams
@ 2018-05-16 22:58   ` Brandon Williams
  2018-05-16 22:58   ` [PATCH v2 21/36] fetch: convert get_ref_map " Brandon Williams
                     ` (16 subsequent siblings)
  36 siblings, 0 replies; 112+ messages in thread
From: Brandon Williams @ 2018-05-16 22:58 UTC (permalink / raw)
  To: git, avarab, gitster, sbeller, bmwill
  Cc: avarab, gitster, sbeller, Brandon Williams

Convert 'do_fetch()' to take a 'struct refspec' as a parameter instead
of a list of 'struct refspec_item'.

Signed-off-by: Brandon Williams <bmwill@google.com>
---
 builtin/fetch.c | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/builtin/fetch.c b/builtin/fetch.c
index 6b909cd5b..ec54b1dfe 100644
--- a/builtin/fetch.c
+++ b/builtin/fetch.c
@@ -1112,7 +1112,7 @@ static void backfill_tags(struct transport *transport, struct ref *ref_map)
 }
 
 static int do_fetch(struct transport *transport,
-		    struct refspec_item *refs, int ref_count)
+		    struct refspec *rs)
 {
 	struct string_list existing_refs = STRING_LIST_INIT_DUP;
 	struct ref *ref_map;
@@ -1136,7 +1136,7 @@ static int do_fetch(struct transport *transport,
 			goto cleanup;
 	}
 
-	ref_map = get_ref_map(transport, refs, ref_count, tags, &autotags);
+	ref_map = get_ref_map(transport, rs->items, rs->nr, tags, &autotags);
 	if (!update_head_ok)
 		check_not_current_branch(ref_map);
 
@@ -1160,8 +1160,8 @@ static int do_fetch(struct transport *transport,
 		 * explicitly (via command line or configuration); we
 		 * don't care whether --tags was specified.
 		 */
-		if (ref_count) {
-			prune_refs(refs, ref_count, ref_map, transport->url);
+		if (rs->nr) {
+			prune_refs(rs->items, rs->nr, ref_map, transport->url);
 		} else {
 			prune_refs(transport->remote->fetch.items,
 				   transport->remote->fetch.nr,
@@ -1410,7 +1410,7 @@ static int fetch_one(struct remote *remote, int argc, const char **argv, int pru
 
 	sigchain_push_common(unlock_pack_on_signal);
 	atexit(unlock_pack);
-	exit_code = do_fetch(gtransport, rs.items, rs.nr);
+	exit_code = do_fetch(gtransport, &rs);
 	refspec_clear(&rs);
 	transport_disconnect(gtransport);
 	gtransport = NULL;
-- 
2.17.0.441.gb46fe60e1d-goog


^ permalink raw reply related	[flat|nested] 112+ messages in thread

* [PATCH v2 21/36] fetch: convert get_ref_map to take a struct refspec
  2018-05-16 22:57 ` [PATCH v2 00/36] " Brandon Williams
                     ` (19 preceding siblings ...)
  2018-05-16 22:58   ` [PATCH v2 20/36] fetch: convert do_fetch to take a struct refspec Brandon Williams
@ 2018-05-16 22:58   ` Brandon Williams
  2018-05-16 22:58   ` [PATCH v2 22/36] fetch: convert prune_refs " Brandon Williams
                     ` (15 subsequent siblings)
  36 siblings, 0 replies; 112+ messages in thread
From: Brandon Williams @ 2018-05-16 22:58 UTC (permalink / raw)
  To: git, avarab, gitster, sbeller, bmwill
  Cc: avarab, gitster, sbeller, Brandon Williams

Convert 'get_ref_map()' to take a 'struct refspec' as a parameter
instead of a list of 'struct refspec_item'.

Signed-off-by: Brandon Williams <bmwill@google.com>
---
 builtin/fetch.c | 43 ++++++++++++++++++++-----------------------
 1 file changed, 20 insertions(+), 23 deletions(-)

diff --git a/builtin/fetch.c b/builtin/fetch.c
index ec54b1dfe..836eb7545 100644
--- a/builtin/fetch.c
+++ b/builtin/fetch.c
@@ -337,7 +337,7 @@ static void find_non_local_tags(struct transport *transport,
 }
 
 static struct ref *get_ref_map(struct transport *transport,
-			       struct refspec_item *refspecs, int refspec_count,
+			       struct refspec *rs,
 			       int tags, int *autotags)
 {
 	int i;
@@ -351,15 +351,16 @@ static struct ref *get_ref_map(struct transport *transport,
 
 	const struct ref *remote_refs;
 
-	for (i = 0; i < refspec_count; i++) {
-		if (!refspecs[i].exact_sha1) {
-			const char *glob = strchr(refspecs[i].src, '*');
+	for (i = 0; i < rs->nr; i++) {
+		const struct refspec_item *item = &rs->items[i];
+		if (!item->exact_sha1) {
+			const char *glob = strchr(item->src, '*');
 			if (glob)
 				argv_array_pushf(&ref_prefixes, "%.*s",
-						 (int)(glob - refspecs[i].src),
-						 refspecs[i].src);
+						 (int)(glob - item->src),
+						 item->src);
 			else
-				expand_ref_prefix(&ref_prefixes, refspecs[i].src);
+				expand_ref_prefix(&ref_prefixes, item->src);
 		}
 	}
 
@@ -367,13 +368,12 @@ static struct ref *get_ref_map(struct transport *transport,
 
 	argv_array_clear(&ref_prefixes);
 
-	if (refspec_count) {
-		struct refspec_item *fetch_refspec;
-		int fetch_refspec_nr;
+	if (rs->nr) {
+		struct refspec *fetch_refspec;
 
-		for (i = 0; i < refspec_count; i++) {
-			get_fetch_map(remote_refs, &refspecs[i], &tail, 0);
-			if (refspecs[i].dst && refspecs[i].dst[0])
+		for (i = 0; i < rs->nr; i++) {
+			get_fetch_map(remote_refs, &rs->items[i], &tail, 0);
+			if (rs->items[i].dst && rs->items[i].dst[0])
 				*autotags = 1;
 		}
 		/* Merge everything on the command line (but not --tags) */
@@ -400,16 +400,13 @@ static struct ref *get_ref_map(struct transport *transport,
 		 * by ref_remove_duplicates() in favor of one of these
 		 * opportunistic entries with FETCH_HEAD_IGNORE.
 		 */
-		if (refmap.nr) {
-			fetch_refspec = refmap.items;
-			fetch_refspec_nr = refmap.nr;
-		} else {
-			fetch_refspec = transport->remote->fetch.items;
-			fetch_refspec_nr = transport->remote->fetch.nr;
-		}
+		if (refmap.nr)
+			fetch_refspec = &refmap;
+		else
+			fetch_refspec = &transport->remote->fetch;
 
-		for (i = 0; i < fetch_refspec_nr; i++)
-			get_fetch_map(ref_map, &fetch_refspec[i], &oref_tail, 1);
+		for (i = 0; i < fetch_refspec->nr; i++)
+			get_fetch_map(ref_map, &fetch_refspec->items[i], &oref_tail, 1);
 	} else if (refmap.nr) {
 		die("--refmap option is only meaningful with command-line refspec(s).");
 	} else {
@@ -1136,7 +1133,7 @@ static int do_fetch(struct transport *transport,
 			goto cleanup;
 	}
 
-	ref_map = get_ref_map(transport, rs->items, rs->nr, tags, &autotags);
+	ref_map = get_ref_map(transport, rs, tags, &autotags);
 	if (!update_head_ok)
 		check_not_current_branch(ref_map);
 
-- 
2.17.0.441.gb46fe60e1d-goog


^ permalink raw reply related	[flat|nested] 112+ messages in thread

* [PATCH v2 22/36] fetch: convert prune_refs to take a struct refspec
  2018-05-16 22:57 ` [PATCH v2 00/36] " Brandon Williams
                     ` (20 preceding siblings ...)
  2018-05-16 22:58   ` [PATCH v2 21/36] fetch: convert get_ref_map " Brandon Williams
@ 2018-05-16 22:58   ` Brandon Williams
  2018-05-16 22:58   ` [PATCH v2 23/36] remote: convert get_stale_heads " Brandon Williams
                     ` (14 subsequent siblings)
  36 siblings, 0 replies; 112+ messages in thread
From: Brandon Williams @ 2018-05-16 22:58 UTC (permalink / raw)
  To: git, avarab, gitster, sbeller, bmwill
  Cc: avarab, gitster, sbeller, Brandon Williams

Convert 'prune_refs()' to take a 'struct refspec' as a parameter instead
of a list of 'struct refspec_item'.

Signed-off-by: Brandon Williams <bmwill@google.com>
---
 builtin/fetch.c | 11 +++++------
 1 file changed, 5 insertions(+), 6 deletions(-)

diff --git a/builtin/fetch.c b/builtin/fetch.c
index 836eb7545..5e46df70c 100644
--- a/builtin/fetch.c
+++ b/builtin/fetch.c
@@ -959,11 +959,11 @@ static int fetch_refs(struct transport *transport, struct ref *ref_map)
 	return ret;
 }
 
-static int prune_refs(struct refspec_item *refs, int ref_count, struct ref *ref_map,
-		const char *raw_url)
+static int prune_refs(struct refspec *rs, struct ref *ref_map,
+		      const char *raw_url)
 {
 	int url_len, i, result = 0;
-	struct ref *ref, *stale_refs = get_stale_heads(refs, ref_count, ref_map);
+	struct ref *ref, *stale_refs = get_stale_heads(rs->items, rs->nr, ref_map);
 	char *url;
 	int summary_width = transport_summary_width(stale_refs);
 	const char *dangling_msg = dry_run
@@ -1158,10 +1158,9 @@ static int do_fetch(struct transport *transport,
 		 * don't care whether --tags was specified.
 		 */
 		if (rs->nr) {
-			prune_refs(rs->items, rs->nr, ref_map, transport->url);
+			prune_refs(rs, ref_map, transport->url);
 		} else {
-			prune_refs(transport->remote->fetch.items,
-				   transport->remote->fetch.nr,
+			prune_refs(&transport->remote->fetch,
 				   ref_map,
 				   transport->url);
 		}
-- 
2.17.0.441.gb46fe60e1d-goog


^ permalink raw reply related	[flat|nested] 112+ messages in thread

* [PATCH v2 23/36] remote: convert get_stale_heads to take a struct refspec
  2018-05-16 22:57 ` [PATCH v2 00/36] " Brandon Williams
                     ` (21 preceding siblings ...)
  2018-05-16 22:58   ` [PATCH v2 22/36] fetch: convert prune_refs " Brandon Williams
@ 2018-05-16 22:58   ` Brandon Williams
  2018-05-16 22:58   ` [PATCH v2 24/36] remote: convert apply_refspecs " Brandon Williams
                     ` (13 subsequent siblings)
  36 siblings, 0 replies; 112+ messages in thread
From: Brandon Williams @ 2018-05-16 22:58 UTC (permalink / raw)
  To: git, avarab, gitster, sbeller, bmwill
  Cc: avarab, gitster, sbeller, Brandon Williams

Convert 'get_stale_heads()' to take a 'struct refspec' as a parameter instead
of a list of 'struct refspec_item'.

Signed-off-by: Brandon Williams <bmwill@google.com>
---
 builtin/fetch.c  |  2 +-
 builtin/remote.c |  3 +--
 remote.c         | 18 +++++++++---------
 remote.h         |  2 +-
 4 files changed, 12 insertions(+), 13 deletions(-)

diff --git a/builtin/fetch.c b/builtin/fetch.c
index 5e46df70c..3fad1f0db 100644
--- a/builtin/fetch.c
+++ b/builtin/fetch.c
@@ -963,7 +963,7 @@ static int prune_refs(struct refspec *rs, struct ref *ref_map,
 		      const char *raw_url)
 {
 	int url_len, i, result = 0;
-	struct ref *ref, *stale_refs = get_stale_heads(rs->items, rs->nr, ref_map);
+	struct ref *ref, *stale_refs = get_stale_heads(rs, ref_map);
 	char *url;
 	int summary_width = transport_summary_width(stale_refs);
 	const char *dangling_msg = dry_run
diff --git a/builtin/remote.c b/builtin/remote.c
index 94dfcb78b..b8e66589f 100644
--- a/builtin/remote.c
+++ b/builtin/remote.c
@@ -347,8 +347,7 @@ static int get_ref_states(const struct ref *remote_refs, struct ref_states *stat
 		else
 			string_list_append(&states->tracked, abbrev_branch(ref->name));
 	}
-	stale_refs = get_stale_heads(states->remote->fetch.items,
-				     states->remote->fetch.nr, fetch_map);
+	stale_refs = get_stale_heads(&states->remote->fetch, fetch_map);
 	for (ref = stale_refs; ref; ref = ref->next) {
 		struct string_list_item *item =
 			string_list_append(&states->stale, abbrev_branch(ref->name));
diff --git a/remote.c b/remote.c
index 4a9bddf0d..358442e4b 100644
--- a/remote.c
+++ b/remote.c
@@ -698,7 +698,9 @@ static int match_name_with_pattern(const char *key, const char *name,
 	return ret;
 }
 
-static void query_refspecs_multiple(struct refspec_item *refs, int ref_count, struct refspec_item *query, struct string_list *results)
+static void query_refspecs_multiple(struct refspec *rs,
+				    struct refspec_item *query,
+				    struct string_list *results)
 {
 	int i;
 	int find_src = !query->src;
@@ -706,8 +708,8 @@ static void query_refspecs_multiple(struct refspec_item *refs, int ref_count, st
 	if (find_src && !query->dst)
 		error("query_refspecs_multiple: need either src or dst");
 
-	for (i = 0; i < ref_count; i++) {
-		struct refspec_item *refspec = &refs[i];
+	for (i = 0; i < rs->nr; i++) {
+		struct refspec_item *refspec = &rs->items[i];
 		const char *key = find_src ? refspec->dst : refspec->src;
 		const char *value = find_src ? refspec->src : refspec->dst;
 		const char *needle = find_src ? query->dst : query->src;
@@ -2068,8 +2070,7 @@ struct ref *guess_remote_head(const struct ref *head,
 struct stale_heads_info {
 	struct string_list *ref_names;
 	struct ref **stale_refs_tail;
-	struct refspec_item *refs;
-	int ref_count;
+	struct refspec *rs;
 };
 
 static int get_stale_heads_cb(const char *refname, const struct object_id *oid,
@@ -2082,7 +2083,7 @@ static int get_stale_heads_cb(const char *refname, const struct object_id *oid,
 	memset(&query, 0, sizeof(struct refspec_item));
 	query.dst = (char *)refname;
 
-	query_refspecs_multiple(info->refs, info->ref_count, &query, &matches);
+	query_refspecs_multiple(info->rs, &query, &matches);
 	if (matches.nr == 0)
 		goto clean_exit; /* No matches */
 
@@ -2110,7 +2111,7 @@ static int get_stale_heads_cb(const char *refname, const struct object_id *oid,
 	return 0;
 }
 
-struct ref *get_stale_heads(struct refspec_item *refs, int ref_count, struct ref *fetch_map)
+struct ref *get_stale_heads(struct refspec *rs, struct ref *fetch_map)
 {
 	struct ref *ref, *stale_refs = NULL;
 	struct string_list ref_names = STRING_LIST_INIT_NODUP;
@@ -2118,8 +2119,7 @@ struct ref *get_stale_heads(struct refspec_item *refs, int ref_count, struct ref
 
 	info.ref_names = &ref_names;
 	info.stale_refs_tail = &stale_refs;
-	info.refs = refs;
-	info.ref_count = ref_count;
+	info.rs = rs;
 	for (ref = fetch_map; ref; ref = ref->next)
 		string_list_append(&ref_names, ref->name);
 	string_list_sort(&ref_names);
diff --git a/remote.h b/remote.h
index 4ffbc0082..1a45542cd 100644
--- a/remote.h
+++ b/remote.h
@@ -267,7 +267,7 @@ struct ref *guess_remote_head(const struct ref *head,
 			      int all);
 
 /* Return refs which no longer exist on remote */
-struct ref *get_stale_heads(struct refspec_item *refs, int ref_count, struct ref *fetch_map);
+struct ref *get_stale_heads(struct refspec *rs, struct ref *fetch_map);
 
 /*
  * Compare-and-swap
-- 
2.17.0.441.gb46fe60e1d-goog


^ permalink raw reply related	[flat|nested] 112+ messages in thread

* [PATCH v2 24/36] remote: convert apply_refspecs to take a struct refspec
  2018-05-16 22:57 ` [PATCH v2 00/36] " Brandon Williams
                     ` (22 preceding siblings ...)
  2018-05-16 22:58   ` [PATCH v2 23/36] remote: convert get_stale_heads " Brandon Williams
@ 2018-05-16 22:58   ` Brandon Williams
  2018-05-16 22:58   ` [PATCH v2 25/36] remote: convert query_refspecs " Brandon Williams
                     ` (12 subsequent siblings)
  36 siblings, 0 replies; 112+ messages in thread
From: Brandon Williams @ 2018-05-16 22:58 UTC (permalink / raw)
  To: git, avarab, gitster, sbeller, bmwill
  Cc: avarab, gitster, sbeller, Brandon Williams

Convert 'apply_refspecs()' to take a 'struct refspec' as a parameter instead
of a list of 'struct refspec_item'.

Signed-off-by: Brandon Williams <bmwill@google.com>
---
 builtin/fast-export.c |  2 +-
 remote.c              | 15 ++++++---------
 remote.h              |  3 +--
 transport-helper.c    |  6 +++---
 4 files changed, 11 insertions(+), 15 deletions(-)

diff --git a/builtin/fast-export.c b/builtin/fast-export.c
index 143999738..41fe49e4d 100644
--- a/builtin/fast-export.c
+++ b/builtin/fast-export.c
@@ -831,7 +831,7 @@ static void get_tags_and_duplicates(struct rev_cmdline_info *info)
 
 		if (refspecs.nr) {
 			char *private;
-			private = apply_refspecs(refspecs.items, refspecs.nr, full_name);
+			private = apply_refspecs(&refspecs, full_name);
 			if (private) {
 				free(full_name);
 				full_name = private;
diff --git a/remote.c b/remote.c
index 358442e4b..89415a263 100644
--- a/remote.c
+++ b/remote.c
@@ -525,8 +525,7 @@ const char *remote_ref_for_branch(struct branch *branch, int for_push,
 			struct remote *remote = remote_get(remote_name);
 
 			if (remote && remote->push.nr &&
-			    (dst = apply_refspecs(remote->push.items,
-						  remote->push.nr,
+			    (dst = apply_refspecs(&remote->push,
 						  branch->refname))) {
 				if (explicit)
 					*explicit = 1;
@@ -757,15 +756,14 @@ int query_refspecs(struct refspec_item *refs, int ref_count, struct refspec_item
 	return -1;
 }
 
-char *apply_refspecs(struct refspec_item *refspecs, int nr_refspec,
-		     const char *name)
+char *apply_refspecs(struct refspec *rs, const char *name)
 {
 	struct refspec_item query;
 
 	memset(&query, 0, sizeof(struct refspec_item));
 	query.src = (char *)name;
 
-	if (query_refspecs(refspecs, nr_refspec, &query))
+	if (query_refspecs(rs->items, rs->nr, &query))
 		return NULL;
 
 	return query.dst;
@@ -1571,7 +1569,7 @@ static const char *tracking_for_push_dest(struct remote *remote,
 {
 	char *ret;
 
-	ret = apply_refspecs(remote->fetch.items, remote->fetch.nr, refname);
+	ret = apply_refspecs(&remote->fetch, refname);
 	if (!ret)
 		return error_buf(err,
 				 _("push destination '%s' on remote '%s' has no local tracking branch"),
@@ -1593,8 +1591,7 @@ static const char *branch_get_push_1(struct branch *branch, struct strbuf *err)
 		char *dst;
 		const char *ret;
 
-		dst = apply_refspecs(remote->push.items, remote->push.nr,
-				     branch->refname);
+		dst = apply_refspecs(&remote->push, branch->refname);
 		if (!dst)
 			return error_buf(err,
 					 _("push refspecs for '%s' do not include '%s'"),
@@ -2203,7 +2200,7 @@ static int remote_tracking(struct remote *remote, const char *refname,
 {
 	char *dst;
 
-	dst = apply_refspecs(remote->fetch.items, remote->fetch.nr, refname);
+	dst = apply_refspecs(&remote->fetch, refname);
 	if (!dst)
 		return -1; /* no tracking ref for refname at remote */
 	if (read_ref(dst, oid))
diff --git a/remote.h b/remote.h
index 1a45542cd..0b1fcc051 100644
--- a/remote.h
+++ b/remote.h
@@ -159,8 +159,7 @@ int ref_newer(const struct object_id *new_oid, const struct object_id *old_oid);
 struct ref *ref_remove_duplicates(struct ref *ref_map);
 
 extern int query_refspecs(struct refspec_item *specs, int nr, struct refspec_item *query);
-char *apply_refspecs(struct refspec_item *refspecs, int nr_refspec,
-		     const char *name);
+char *apply_refspecs(struct refspec *rs, const char *name);
 
 int check_push_refs(struct ref *src, int nr_refspec, const char **refspec);
 int match_push_refs(struct ref *src, struct ref **dst,
diff --git a/transport-helper.c b/transport-helper.c
index 33f51ebfc..1f8ff7e94 100644
--- a/transport-helper.c
+++ b/transport-helper.c
@@ -523,7 +523,7 @@ static int fetch_with_import(struct transport *transport,
 			continue;
 		name = posn->symref ? posn->symref : posn->name;
 		if (data->rs.nr)
-			private = apply_refspecs(data->rs.items, data->rs.nr, name);
+			private = apply_refspecs(&data->rs, name);
 		else
 			private = xstrdup(name);
 		if (private) {
@@ -805,7 +805,7 @@ static int push_update_refs_status(struct helper_data *data,
 			continue;
 
 		/* propagate back the update to the remote namespace */
-		private = apply_refspecs(data->rs.items, data->rs.nr, ref->name);
+		private = apply_refspecs(&data->rs, ref->name);
 		if (!private)
 			continue;
 		update_ref("update by helper", private, &ref->new_oid, NULL,
@@ -942,7 +942,7 @@ static int push_refs_with_export(struct transport *transport,
 		char *private;
 		struct object_id oid;
 
-		private = apply_refspecs(data->rs.items, data->rs.nr, ref->name);
+		private = apply_refspecs(&data->rs, ref->name);
 		if (private && !get_oid(private, &oid)) {
 			strbuf_addf(&buf, "^%s", private);
 			string_list_append_nodup(&revlist_args,
-- 
2.17.0.441.gb46fe60e1d-goog


^ permalink raw reply related	[flat|nested] 112+ messages in thread

* [PATCH v2 25/36] remote: convert query_refspecs to take a struct refspec
  2018-05-16 22:57 ` [PATCH v2 00/36] " Brandon Williams
                     ` (23 preceding siblings ...)
  2018-05-16 22:58   ` [PATCH v2 24/36] remote: convert apply_refspecs " Brandon Williams
@ 2018-05-16 22:58   ` Brandon Williams
  2018-05-16 22:58   ` [PATCH v2 26/36] remote: convert get_ref_match " Brandon Williams
                     ` (11 subsequent siblings)
  36 siblings, 0 replies; 112+ messages in thread
From: Brandon Williams @ 2018-05-16 22:58 UTC (permalink / raw)
  To: git, avarab, gitster, sbeller, bmwill
  Cc: avarab, gitster, sbeller, Brandon Williams

Convert 'query_refspecs()' to take a 'struct refspec' as a parameter instead
of a list of 'struct refspec_item'.

Signed-off-by: Brandon Williams <bmwill@google.com>
---
 builtin/push.c |  3 +--
 remote.c       | 10 +++++-----
 remote.h       |  2 +-
 3 files changed, 7 insertions(+), 8 deletions(-)

diff --git a/builtin/push.c b/builtin/push.c
index 509dc6677..6b7e45890 100644
--- a/builtin/push.c
+++ b/builtin/push.c
@@ -83,8 +83,7 @@ static const char *map_refspec(const char *ref,
 		struct refspec_item query;
 		memset(&query, 0, sizeof(struct refspec_item));
 		query.src = matched->name;
-		if (!query_refspecs(remote->push.items, remote->push.nr, &query) &&
-		    query.dst) {
+		if (!query_refspecs(&remote->push, &query) && query.dst) {
 			struct strbuf buf = STRBUF_INIT;
 			strbuf_addf(&buf, "%s%s:%s",
 				    query.force ? "+" : "",
diff --git a/remote.c b/remote.c
index 89415a263..dd68e6b22 100644
--- a/remote.c
+++ b/remote.c
@@ -725,7 +725,7 @@ static void query_refspecs_multiple(struct refspec *rs,
 	}
 }
 
-int query_refspecs(struct refspec_item *refs, int ref_count, struct refspec_item *query)
+int query_refspecs(struct refspec *rs, struct refspec_item *query)
 {
 	int i;
 	int find_src = !query->src;
@@ -735,8 +735,8 @@ int query_refspecs(struct refspec_item *refs, int ref_count, struct refspec_item
 	if (find_src && !query->dst)
 		return error("query_refspecs: need either src or dst");
 
-	for (i = 0; i < ref_count; i++) {
-		struct refspec_item *refspec = &refs[i];
+	for (i = 0; i < rs->nr; i++) {
+		struct refspec_item *refspec = &rs->items[i];
 		const char *key = find_src ? refspec->dst : refspec->src;
 		const char *value = find_src ? refspec->src : refspec->dst;
 
@@ -763,7 +763,7 @@ char *apply_refspecs(struct refspec *rs, const char *name)
 	memset(&query, 0, sizeof(struct refspec_item));
 	query.src = (char *)name;
 
-	if (query_refspecs(rs->items, rs->nr, &query))
+	if (query_refspecs(rs, &query))
 		return NULL;
 
 	return query.dst;
@@ -771,7 +771,7 @@ char *apply_refspecs(struct refspec *rs, const char *name)
 
 int remote_find_tracking(struct remote *remote, struct refspec_item *refspec)
 {
-	return query_refspecs(remote->fetch.items, remote->fetch.nr, refspec);
+	return query_refspecs(&remote->fetch, refspec);
 }
 
 static struct ref *alloc_ref_with_prefix(const char *prefix, size_t prefixlen,
diff --git a/remote.h b/remote.h
index 0b1fcc051..9050ff75a 100644
--- a/remote.h
+++ b/remote.h
@@ -158,7 +158,7 @@ int ref_newer(const struct object_id *new_oid, const struct object_id *old_oid);
  */
 struct ref *ref_remove_duplicates(struct ref *ref_map);
 
-extern int query_refspecs(struct refspec_item *specs, int nr, struct refspec_item *query);
+int query_refspecs(struct refspec *rs, struct refspec_item *query);
 char *apply_refspecs(struct refspec *rs, const char *name);
 
 int check_push_refs(struct ref *src, int nr_refspec, const char **refspec);
-- 
2.17.0.441.gb46fe60e1d-goog


^ permalink raw reply related	[flat|nested] 112+ messages in thread

* [PATCH v2 26/36] remote: convert get_ref_match to take a struct refspec
  2018-05-16 22:57 ` [PATCH v2 00/36] " Brandon Williams
                     ` (24 preceding siblings ...)
  2018-05-16 22:58   ` [PATCH v2 25/36] remote: convert query_refspecs " Brandon Williams
@ 2018-05-16 22:58   ` Brandon Williams
  2018-05-16 22:58   ` [PATCH v2 27/36] remote: convert match_explicit_refs " Brandon Williams
                     ` (10 subsequent siblings)
  36 siblings, 0 replies; 112+ messages in thread
From: Brandon Williams @ 2018-05-16 22:58 UTC (permalink / raw)
  To: git, avarab, gitster, sbeller, bmwill
  Cc: avarab, gitster, sbeller, Brandon Williams

Convert 'get_ref_match()' to take a 'struct refspec' as a parameter
instead of a list of 'struct refspec_item'.

Signed-off-by: Brandon Williams <bmwill@google.com>
---
 remote.c | 26 ++++++++++++++------------
 1 file changed, 14 insertions(+), 12 deletions(-)

diff --git a/remote.c b/remote.c
index dd68e6b22..9eb79ea19 100644
--- a/remote.c
+++ b/remote.c
@@ -1082,27 +1082,29 @@ static int match_explicit_refs(struct ref *src, struct ref *dst,
 	return errs;
 }
 
-static char *get_ref_match(const struct refspec_item *rs, int rs_nr, const struct ref *ref,
-		int send_mirror, int direction, const struct refspec_item **ret_pat)
+static char *get_ref_match(const struct refspec *rs, const struct ref *ref,
+			   int send_mirror, int direction,
+			   const struct refspec_item **ret_pat)
 {
 	const struct refspec_item *pat;
 	char *name;
 	int i;
 	int matching_refs = -1;
-	for (i = 0; i < rs_nr; i++) {
-		if (rs[i].matching &&
-		    (matching_refs == -1 || rs[i].force)) {
+	for (i = 0; i < rs->nr; i++) {
+		const struct refspec_item *item = &rs->items[i];
+		if (item->matching &&
+		    (matching_refs == -1 || item->force)) {
 			matching_refs = i;
 			continue;
 		}
 
-		if (rs[i].pattern) {
-			const char *dst_side = rs[i].dst ? rs[i].dst : rs[i].src;
+		if (item->pattern) {
+			const char *dst_side = item->dst ? item->dst : item->src;
 			int match;
 			if (direction == FROM_SRC)
-				match = match_name_with_pattern(rs[i].src, ref->name, dst_side, &name);
+				match = match_name_with_pattern(item->src, ref->name, dst_side, &name);
 			else
-				match = match_name_with_pattern(dst_side, ref->name, rs[i].src, &name);
+				match = match_name_with_pattern(dst_side, ref->name, item->src, &name);
 			if (match) {
 				matching_refs = i;
 				break;
@@ -1112,7 +1114,7 @@ static char *get_ref_match(const struct refspec_item *rs, int rs_nr, const struc
 	if (matching_refs == -1)
 		return NULL;
 
-	pat = rs + matching_refs;
+	pat = &rs->items[matching_refs];
 	if (pat->matching) {
 		/*
 		 * "matching refs"; traditionally we pushed everything
@@ -1309,7 +1311,7 @@ int match_push_refs(struct ref *src, struct ref **dst,
 		const struct refspec_item *pat = NULL;
 		char *dst_name;
 
-		dst_name = get_ref_match(rs.items, rs.nr, ref, send_mirror, FROM_SRC, &pat);
+		dst_name = get_ref_match(&rs, ref, send_mirror, FROM_SRC, &pat);
 		if (!dst_name)
 			continue;
 
@@ -1358,7 +1360,7 @@ int match_push_refs(struct ref *src, struct ref **dst,
 				/* We're already sending something to this ref. */
 				continue;
 
-			src_name = get_ref_match(rs.items, rs.nr, ref, send_mirror, FROM_DST, NULL);
+			src_name = get_ref_match(&rs, ref, send_mirror, FROM_DST, NULL);
 			if (src_name) {
 				if (!src_ref_index.nr)
 					prepare_ref_index(&src_ref_index, src);
-- 
2.17.0.441.gb46fe60e1d-goog


^ permalink raw reply related	[flat|nested] 112+ messages in thread

* [PATCH v2 27/36] remote: convert match_explicit_refs to take a struct refspec
  2018-05-16 22:57 ` [PATCH v2 00/36] " Brandon Williams
                     ` (25 preceding siblings ...)
  2018-05-16 22:58   ` [PATCH v2 26/36] remote: convert get_ref_match " Brandon Williams
@ 2018-05-16 22:58   ` Brandon Williams
  2018-05-16 22:58   ` [PATCH v2 28/36] push: check for errors earlier Brandon Williams
                     ` (9 subsequent siblings)
  36 siblings, 0 replies; 112+ messages in thread
From: Brandon Williams @ 2018-05-16 22:58 UTC (permalink / raw)
  To: git, avarab, gitster, sbeller, bmwill
  Cc: avarab, gitster, sbeller, Brandon Williams

Convert 'match_explicit_refs()' to take a 'struct refspec' as a
parameter instead of a list of 'struct refspec_item'.

Signed-off-by: Brandon Williams <bmwill@google.com>
---
 remote.c | 9 ++++-----
 1 file changed, 4 insertions(+), 5 deletions(-)

diff --git a/remote.c b/remote.c
index 9eb79ea19..84dda3fd0 100644
--- a/remote.c
+++ b/remote.c
@@ -1073,12 +1073,11 @@ static int match_explicit(struct ref *src, struct ref *dst,
 }
 
 static int match_explicit_refs(struct ref *src, struct ref *dst,
-			       struct ref ***dst_tail, struct refspec_item *rs,
-			       int rs_nr)
+			       struct ref ***dst_tail, struct refspec *rs)
 {
 	int i, errs;
-	for (i = errs = 0; i < rs_nr; i++)
-		errs += match_explicit(src, dst, dst_tail, &rs[i]);
+	for (i = errs = 0; i < rs->nr; i++)
+		errs += match_explicit(src, dst, dst_tail, &rs->items[i]);
 	return errs;
 }
 
@@ -1302,7 +1301,7 @@ int match_push_refs(struct ref *src, struct ref **dst,
 		refspec = default_refspec;
 	}
 	refspec_appendn(&rs, refspec, nr_refspec);
-	errs = match_explicit_refs(src, *dst, &dst_tail, rs.items, rs.nr);
+	errs = match_explicit_refs(src, *dst, &dst_tail, &rs);
 
 	/* pick the remainder */
 	for (ref = src; ref; ref = ref->next) {
-- 
2.17.0.441.gb46fe60e1d-goog


^ permalink raw reply related	[flat|nested] 112+ messages in thread

* [PATCH v2 28/36] push: check for errors earlier
  2018-05-16 22:57 ` [PATCH v2 00/36] " Brandon Williams
                     ` (26 preceding siblings ...)
  2018-05-16 22:58   ` [PATCH v2 27/36] remote: convert match_explicit_refs " Brandon Williams
@ 2018-05-16 22:58   ` Brandon Williams
  2018-05-16 22:58   ` [PATCH v2 29/36] push: convert to use struct refspec Brandon Williams
                     ` (8 subsequent siblings)
  36 siblings, 0 replies; 112+ messages in thread
From: Brandon Williams @ 2018-05-16 22:58 UTC (permalink / raw)
  To: git, avarab, gitster, sbeller, bmwill
  Cc: avarab, gitster, sbeller, Brandon Williams

Move the error checking for using the "--mirror", "--all", and "--tags"
options earlier and explicitly check for the presence of the flags
instead of checking for a side-effect of the flag.

Signed-off-by: Brandon Williams <bmwill@google.com>
---
 builtin/push.c | 31 ++++++++++++++-----------------
 1 file changed, 14 insertions(+), 17 deletions(-)

diff --git a/builtin/push.c b/builtin/push.c
index 6b7e45890..df5df6c0d 100644
--- a/builtin/push.c
+++ b/builtin/push.c
@@ -417,23 +417,6 @@ static int do_push(const char *repo, int flags,
 	if (push_options->nr)
 		flags |= TRANSPORT_PUSH_OPTIONS;
 
-	if ((flags & TRANSPORT_PUSH_ALL) && refspec) {
-		if (!strcmp(*refspec, "refs/tags/*"))
-			return error(_("--all and --tags are incompatible"));
-		return error(_("--all can't be combined with refspecs"));
-	}
-
-	if ((flags & TRANSPORT_PUSH_MIRROR) && refspec) {
-		if (!strcmp(*refspec, "refs/tags/*"))
-			return error(_("--mirror and --tags are incompatible"));
-		return error(_("--mirror can't be combined with refspecs"));
-	}
-
-	if ((flags & (TRANSPORT_PUSH_ALL|TRANSPORT_PUSH_MIRROR)) ==
-				(TRANSPORT_PUSH_ALL|TRANSPORT_PUSH_MIRROR)) {
-		return error(_("--all and --mirror are incompatible"));
-	}
-
 	if (!refspec && !(flags & TRANSPORT_PUSH_ALL)) {
 		if (remote->push.raw_nr) {
 			refspec = remote->push.raw;
@@ -625,6 +608,20 @@ int cmd_push(int argc, const char **argv, const char *prefix)
 		die(_("--delete is incompatible with --all, --mirror and --tags"));
 	if (deleterefs && argc < 2)
 		die(_("--delete doesn't make sense without any refs"));
+	if (flags & TRANSPORT_PUSH_ALL) {
+		if (tags)
+			die(_("--all and --tags are incompatible"));
+		if (argc >= 2)
+			die(_("--all can't be combined with refspecs"));
+	}
+	if (flags & TRANSPORT_PUSH_MIRROR) {
+		if (tags)
+			die(_("--mirror and --tags are incompatible"));
+		if (argc >= 2)
+			die(_("--mirror can't be combined with refspecs"));
+	}
+	if ((flags & TRANSPORT_PUSH_ALL) && (flags & TRANSPORT_PUSH_MIRROR))
+		die(_("--all and --mirror are incompatible"));
 
 	if (recurse_submodules == RECURSE_SUBMODULES_CHECK)
 		flags |= TRANSPORT_RECURSE_SUBMODULES_CHECK;
-- 
2.17.0.441.gb46fe60e1d-goog


^ permalink raw reply related	[flat|nested] 112+ messages in thread

* [PATCH v2 29/36] push: convert to use struct refspec
  2018-05-16 22:57 ` [PATCH v2 00/36] " Brandon Williams
                     ` (27 preceding siblings ...)
  2018-05-16 22:58   ` [PATCH v2 28/36] push: check for errors earlier Brandon Williams
@ 2018-05-16 22:58   ` Brandon Williams
  2018-05-16 22:58   ` [PATCH v2 30/36] transport: convert transport_push to take a " Brandon Williams
                     ` (7 subsequent siblings)
  36 siblings, 0 replies; 112+ messages in thread
From: Brandon Williams @ 2018-05-16 22:58 UTC (permalink / raw)
  To: git, avarab, gitster, sbeller, bmwill
  Cc: avarab, gitster, sbeller, Brandon Williams

Convert the refspecs in builtin/push.c to be stored in a 'struct
refspec' instead of being stored in a list of 'struct refspec_item's.

Signed-off-by: Brandon Williams <bmwill@google.com>
---
 builtin/push.c | 38 +++++++++++++++-----------------------
 1 file changed, 15 insertions(+), 23 deletions(-)

diff --git a/builtin/push.c b/builtin/push.c
index df5df6c0d..ef42979d1 100644
--- a/builtin/push.c
+++ b/builtin/push.c
@@ -57,19 +57,10 @@ static enum transport_family family;
 
 static struct push_cas_option cas;
 
-static const char **refspec;
-static int refspec_nr;
-static int refspec_alloc;
+static struct refspec rs = REFSPEC_INIT_PUSH;
 
 static struct string_list push_options_config = STRING_LIST_INIT_DUP;
 
-static void add_refspec(const char *ref)
-{
-	refspec_nr++;
-	ALLOC_GROW(refspec, refspec_nr, refspec_alloc);
-	refspec[refspec_nr-1] = ref;
-}
-
 static const char *map_refspec(const char *ref,
 			       struct remote *remote, struct ref *local_refs)
 {
@@ -138,7 +129,7 @@ static void set_refspecs(const char **refs, int nr, const char *repo)
 			}
 			ref = map_refspec(ref, remote, local_refs);
 		}
-		add_refspec(ref);
+		refspec_append(&rs, ref);
 	}
 }
 
@@ -226,7 +217,7 @@ static void setup_push_upstream(struct remote *remote, struct branch *branch,
 	}
 
 	strbuf_addf(&refspec, "%s:%s", branch->refname, branch->merge[0]->src);
-	add_refspec(refspec.buf);
+	refspec_append(&rs, refspec.buf);
 }
 
 static void setup_push_current(struct remote *remote, struct branch *branch)
@@ -236,7 +227,7 @@ static void setup_push_current(struct remote *remote, struct branch *branch)
 	if (!branch)
 		die(_(message_detached_head_die), remote->name);
 	strbuf_addf(&refspec, "%s:%s", branch->refname, branch->refname);
-	add_refspec(refspec.buf);
+	refspec_append(&rs, refspec.buf);
 }
 
 static int is_workflow_triangular(struct remote *remote)
@@ -253,7 +244,7 @@ static void setup_default_push_refspecs(struct remote *remote)
 	switch (push_default) {
 	default:
 	case PUSH_DEFAULT_MATCHING:
-		add_refspec(":");
+		refspec_append(&rs, ":");
 		break;
 
 	case PUSH_DEFAULT_UNSPECIFIED:
@@ -341,7 +332,8 @@ static void advise_ref_needs_force(void)
 	advise(_(message_advice_ref_needs_force));
 }
 
-static int push_with_options(struct transport *transport, int flags)
+static int push_with_options(struct transport *transport, struct refspec *rs,
+			     int flags)
 {
 	int err;
 	unsigned int reject_reasons;
@@ -363,7 +355,7 @@ static int push_with_options(struct transport *transport, int flags)
 
 	if (verbosity > 0)
 		fprintf(stderr, _("Pushing to %s\n"), transport->url);
-	err = transport_push(transport, refspec_nr, refspec, flags,
+	err = transport_push(transport, rs->raw_nr, rs->raw, flags,
 			     &reject_reasons);
 	if (err != 0) {
 		fprintf(stderr, "%s", push_get_color(PUSH_COLOR_ERROR));
@@ -397,6 +389,7 @@ static int do_push(const char *repo, int flags,
 	struct remote *remote = pushremote_get(repo);
 	const char **url;
 	int url_nr;
+	struct refspec *push_refspec = &rs;
 
 	if (!remote) {
 		if (repo)
@@ -417,10 +410,9 @@ static int do_push(const char *repo, int flags,
 	if (push_options->nr)
 		flags |= TRANSPORT_PUSH_OPTIONS;
 
-	if (!refspec && !(flags & TRANSPORT_PUSH_ALL)) {
-		if (remote->push.raw_nr) {
-			refspec = remote->push.raw;
-			refspec_nr = remote->push.raw_nr;
+	if (!push_refspec->nr && !(flags & TRANSPORT_PUSH_ALL)) {
+		if (remote->push.nr) {
+			push_refspec = &remote->push;
 		} else if (!(flags & TRANSPORT_PUSH_MIRROR))
 			setup_default_push_refspecs(remote);
 	}
@@ -432,7 +424,7 @@ static int do_push(const char *repo, int flags,
 				transport_get(remote, url[i]);
 			if (flags & TRANSPORT_PUSH_OPTIONS)
 				transport->push_options = push_options;
-			if (push_with_options(transport, flags))
+			if (push_with_options(transport, push_refspec, flags))
 				errs++;
 		}
 	} else {
@@ -440,7 +432,7 @@ static int do_push(const char *repo, int flags,
 			transport_get(remote, NULL);
 		if (flags & TRANSPORT_PUSH_OPTIONS)
 			transport->push_options = push_options;
-		if (push_with_options(transport, flags))
+		if (push_with_options(transport, push_refspec, flags))
 			errs++;
 	}
 	return !!errs;
@@ -631,7 +623,7 @@ int cmd_push(int argc, const char **argv, const char *prefix)
 		flags |= TRANSPORT_RECURSE_SUBMODULES_ONLY;
 
 	if (tags)
-		add_refspec("refs/tags/*");
+		refspec_append(&rs, "refs/tags/*");
 
 	if (argc > 0) {
 		repo = argv[0];
-- 
2.17.0.441.gb46fe60e1d-goog


^ permalink raw reply related	[flat|nested] 112+ messages in thread

* [PATCH v2 30/36] transport: convert transport_push to take a struct refspec
  2018-05-16 22:57 ` [PATCH v2 00/36] " Brandon Williams
                     ` (28 preceding siblings ...)
  2018-05-16 22:58   ` [PATCH v2 29/36] push: convert to use struct refspec Brandon Williams
@ 2018-05-16 22:58   ` Brandon Williams
  2018-05-16 22:58   ` [PATCH v2 31/36] send-pack: store refspecs in " Brandon Williams
                     ` (6 subsequent siblings)
  36 siblings, 0 replies; 112+ messages in thread
From: Brandon Williams @ 2018-05-16 22:58 UTC (permalink / raw)
  To: git, avarab, gitster, sbeller, bmwill
  Cc: avarab, gitster, sbeller, Brandon Williams

Convert 'transport_push()' to take a 'struct refspec' as a
parameter instead of an array of strings which represent
refspecs.

Signed-off-by: Brandon Williams <bmwill@google.com>
---
 builtin/push.c |  3 +--
 transport.c    | 17 +++++++----------
 transport.h    |  2 +-
 3 files changed, 9 insertions(+), 13 deletions(-)

diff --git a/builtin/push.c b/builtin/push.c
index ef42979d1..9cd8e8cd5 100644
--- a/builtin/push.c
+++ b/builtin/push.c
@@ -355,8 +355,7 @@ static int push_with_options(struct transport *transport, struct refspec *rs,
 
 	if (verbosity > 0)
 		fprintf(stderr, _("Pushing to %s\n"), transport->url);
-	err = transport_push(transport, rs->raw_nr, rs->raw, flags,
-			     &reject_reasons);
+	err = transport_push(transport, rs, flags, &reject_reasons);
 	if (err != 0) {
 		fprintf(stderr, "%s", push_get_color(PUSH_COLOR_ERROR));
 		error(_("failed to push some refs to '%s'"), transport->url);
diff --git a/transport.c b/transport.c
index 181db4d4d..a89f17744 100644
--- a/transport.c
+++ b/transport.c
@@ -1093,11 +1093,11 @@ static int run_pre_push_hook(struct transport *transport,
 }
 
 int transport_push(struct transport *transport,
-		   int refspec_nr, const char **refspec, int flags,
+		   struct refspec *rs, int flags,
 		   unsigned int *reject_reasons)
 {
 	*reject_reasons = 0;
-	transport_verify_remote_names(refspec_nr, refspec);
+	transport_verify_remote_names(rs->raw_nr, rs->raw);
 
 	if (transport_color_config() < 0)
 		return -1;
@@ -1111,16 +1111,14 @@ int transport_push(struct transport *transport,
 		int porcelain = flags & TRANSPORT_PUSH_PORCELAIN;
 		int pretend = flags & TRANSPORT_PUSH_DRY_RUN;
 		int push_ret, ret, err;
-		struct refspec tmp_rs = REFSPEC_INIT_PUSH;
 		struct argv_array ref_prefixes = ARGV_ARRAY_INIT;
 		int i;
 
-		if (check_push_refs(local_refs, refspec_nr, refspec) < 0)
+		if (check_push_refs(local_refs, rs->raw_nr, rs->raw) < 0)
 			return -1;
 
-		refspec_appendn(&tmp_rs, refspec, refspec_nr);
-		for (i = 0; i < tmp_rs.nr; i++) {
-			const struct refspec_item *item = &tmp_rs.items[i];
+		for (i = 0; i < rs->nr; i++) {
+			const struct refspec_item *item = &rs->items[i];
 			const char *prefix = NULL;
 
 			if (item->dst)
@@ -1143,7 +1141,6 @@ int transport_push(struct transport *transport,
 							       &ref_prefixes);
 
 		argv_array_clear(&ref_prefixes);
-		refspec_clear(&tmp_rs);
 
 		if (flags & TRANSPORT_PUSH_ALL)
 			match_flags |= MATCH_REFS_ALL;
@@ -1155,7 +1152,7 @@ int transport_push(struct transport *transport,
 			match_flags |= MATCH_REFS_FOLLOW_TAGS;
 
 		if (match_push_refs(local_refs, &remote_refs,
-				    refspec_nr, refspec, match_flags)) {
+				    rs->raw_nr, rs->raw, match_flags)) {
 			return -1;
 		}
 
@@ -1186,7 +1183,7 @@ int transport_push(struct transport *transport,
 
 			if (!push_unpushed_submodules(&commits,
 						      transport->remote,
-						      refspec, refspec_nr,
+						      rs->raw, rs->raw_nr,
 						      transport->push_options,
 						      pretend)) {
 				oid_array_clear(&commits);
diff --git a/transport.h b/transport.h
index e783cfa07..e2c809af4 100644
--- a/transport.h
+++ b/transport.h
@@ -197,7 +197,7 @@ void transport_set_verbosity(struct transport *transport, int verbosity,
 #define REJECT_NEEDS_FORCE     0x10
 
 int transport_push(struct transport *connection,
-		   int refspec_nr, const char **refspec, int flags,
+		   struct refspec *rs, int flags,
 		   unsigned int * reject_reasons);
 
 /*
-- 
2.17.0.441.gb46fe60e1d-goog


^ permalink raw reply related	[flat|nested] 112+ messages in thread

* [PATCH v2 31/36] send-pack: store refspecs in a struct refspec
  2018-05-16 22:57 ` [PATCH v2 00/36] " Brandon Williams
                     ` (29 preceding siblings ...)
  2018-05-16 22:58   ` [PATCH v2 30/36] transport: convert transport_push to take a " Brandon Williams
@ 2018-05-16 22:58   ` Brandon Williams
  2018-05-16 22:58   ` [PATCH v2 32/36] transport: remove transport_verify_remote_names Brandon Williams
                     ` (5 subsequent siblings)
  36 siblings, 0 replies; 112+ messages in thread
From: Brandon Williams @ 2018-05-16 22:58 UTC (permalink / raw)
  To: git, avarab, gitster, sbeller, bmwill
  Cc: avarab, gitster, sbeller, Brandon Williams

Convert send-pack.c to store refspecs in a 'struct refspec' instead of
as an array of 'const char *'.

Signed-off-by: Brandon Williams <bmwill@google.com>
---
 builtin/send-pack.c | 24 +++++++-----------------
 1 file changed, 7 insertions(+), 17 deletions(-)

diff --git a/builtin/send-pack.c b/builtin/send-pack.c
index b5427f75e..ef512616f 100644
--- a/builtin/send-pack.c
+++ b/builtin/send-pack.c
@@ -126,8 +126,7 @@ static int send_pack_config(const char *k, const char *v, void *cb)
 
 int cmd_send_pack(int argc, const char **argv, const char *prefix)
 {
-	int i, nr_refspecs = 0;
-	const char **refspecs = NULL;
+	struct refspec rs = REFSPEC_INIT_PUSH;
 	const char *remote_name = NULL;
 	struct remote *remote = NULL;
 	const char *dest = NULL;
@@ -189,8 +188,7 @@ int cmd_send_pack(int argc, const char **argv, const char *prefix)
 	argc = parse_options(argc, argv, prefix, options, send_pack_usage, 0);
 	if (argc > 0) {
 		dest = argv[0];
-		refspecs = (const char **)(argv + 1);
-		nr_refspecs = argc - 1;
+		refspec_appendn(&rs, argv + 1, argc - 1);
 	}
 
 	if (!dest)
@@ -209,31 +207,23 @@ int cmd_send_pack(int argc, const char **argv, const char *prefix)
 	args.push_options = push_options.nr ? &push_options : NULL;
 
 	if (from_stdin) {
-		struct argv_array all_refspecs = ARGV_ARRAY_INIT;
-
-		for (i = 0; i < nr_refspecs; i++)
-			argv_array_push(&all_refspecs, refspecs[i]);
-
 		if (args.stateless_rpc) {
 			const char *buf;
 			while ((buf = packet_read_line(0, NULL)))
-				argv_array_push(&all_refspecs, buf);
+				refspec_append(&rs, buf);
 		} else {
 			struct strbuf line = STRBUF_INIT;
 			while (strbuf_getline(&line, stdin) != EOF)
-				argv_array_push(&all_refspecs, line.buf);
+				refspec_append(&rs, line.buf);
 			strbuf_release(&line);
 		}
-
-		refspecs = all_refspecs.argv;
-		nr_refspecs = all_refspecs.argc;
 	}
 
 	/*
 	 * --all and --mirror are incompatible; neither makes sense
 	 * with any refspecs.
 	 */
-	if ((nr_refspecs > 0 && (send_all || args.send_mirror)) ||
+	if ((rs.nr > 0 && (send_all || args.send_mirror)) ||
 	    (send_all && args.send_mirror))
 		usage_with_options(send_pack_usage, options);
 
@@ -275,7 +265,7 @@ int cmd_send_pack(int argc, const char **argv, const char *prefix)
 		BUG("unknown protocol version");
 	}
 
-	transport_verify_remote_names(nr_refspecs, refspecs);
+	transport_verify_remote_names(rs.raw_nr, rs.raw);
 
 	local_refs = get_local_heads();
 
@@ -287,7 +277,7 @@ int cmd_send_pack(int argc, const char **argv, const char *prefix)
 		flags |= MATCH_REFS_MIRROR;
 
 	/* match them up */
-	if (match_push_refs(local_refs, &remote_refs, nr_refspecs, refspecs, flags))
+	if (match_push_refs(local_refs, &remote_refs, rs.raw_nr, rs.raw, flags))
 		return -1;
 
 	if (!is_empty_cas(&cas))
-- 
2.17.0.441.gb46fe60e1d-goog


^ permalink raw reply related	[flat|nested] 112+ messages in thread

* [PATCH v2 32/36] transport: remove transport_verify_remote_names
  2018-05-16 22:57 ` [PATCH v2 00/36] " Brandon Williams
                     ` (30 preceding siblings ...)
  2018-05-16 22:58   ` [PATCH v2 31/36] send-pack: store refspecs in " Brandon Williams
@ 2018-05-16 22:58   ` Brandon Williams
  2018-05-16 22:58   ` [PATCH v2 33/36] http-push: store refspecs in a struct refspec Brandon Williams
                     ` (4 subsequent siblings)
  36 siblings, 0 replies; 112+ messages in thread
From: Brandon Williams @ 2018-05-16 22:58 UTC (permalink / raw)
  To: git, avarab, gitster, sbeller, bmwill
  Cc: avarab, gitster, sbeller, Brandon Williams

Remove 'transprot_verify_remote_names()' because all callers have
migrated to using 'struct refspec' which performs the same checks in
'parse_refspec()'.

Signed-off-by: Brandon Williams <bmwill@google.com>
---
 builtin/send-pack.c |  2 --
 transport.c         | 24 ------------------------
 transport.h         |  2 --
 3 files changed, 28 deletions(-)

diff --git a/builtin/send-pack.c b/builtin/send-pack.c
index ef512616f..7c34bf467 100644
--- a/builtin/send-pack.c
+++ b/builtin/send-pack.c
@@ -265,8 +265,6 @@ int cmd_send_pack(int argc, const char **argv, const char *prefix)
 		BUG("unknown protocol version");
 	}
 
-	transport_verify_remote_names(rs.raw_nr, rs.raw);
-
 	local_refs = get_local_heads();
 
 	flags = MATCH_REFS_NONE;
diff --git a/transport.c b/transport.c
index a89f17744..fe96c0b80 100644
--- a/transport.c
+++ b/transport.c
@@ -619,29 +619,6 @@ void transport_print_push_status(const char *dest, struct ref *refs,
 	free(head);
 }
 
-void transport_verify_remote_names(int nr_heads, const char **heads)
-{
-	int i;
-
-	for (i = 0; i < nr_heads; i++) {
-		const char *local = heads[i];
-		const char *remote = strrchr(heads[i], ':');
-
-		if (*local == '+')
-			local++;
-
-		/* A matching refspec is okay.  */
-		if (remote == local && remote[1] == '\0')
-			continue;
-
-		remote = remote ? (remote + 1) : local;
-		if (check_refname_format(remote,
-				REFNAME_ALLOW_ONELEVEL|REFNAME_REFSPEC_PATTERN))
-			die("remote part of refspec is not a valid name in %s",
-				heads[i]);
-	}
-}
-
 static int git_transport_push(struct transport *transport, struct ref *remote_refs, int flags)
 {
 	struct git_transport_data *data = transport->data;
@@ -1097,7 +1074,6 @@ int transport_push(struct transport *transport,
 		   unsigned int *reject_reasons)
 {
 	*reject_reasons = 0;
-	transport_verify_remote_names(rs->raw_nr, rs->raw);
 
 	if (transport_color_config() < 0)
 		return -1;
diff --git a/transport.h b/transport.h
index e2c809af4..bac085ce0 100644
--- a/transport.h
+++ b/transport.h
@@ -227,8 +227,6 @@ int transport_helper_init(struct transport *transport, const char *name);
 int bidirectional_transfer_loop(int input, int output);
 
 /* common methods used by transport.c and builtin/send-pack.c */
-void transport_verify_remote_names(int nr_heads, const char **heads);
-
 void transport_update_tracking_ref(struct remote *remote, struct ref *ref, int verbose);
 
 int transport_refs_pushed(struct ref *ref);
-- 
2.17.0.441.gb46fe60e1d-goog


^ permalink raw reply related	[flat|nested] 112+ messages in thread

* [PATCH v2 33/36] http-push: store refspecs in a struct refspec
  2018-05-16 22:57 ` [PATCH v2 00/36] " Brandon Williams
                     ` (31 preceding siblings ...)
  2018-05-16 22:58   ` [PATCH v2 32/36] transport: remove transport_verify_remote_names Brandon Williams
@ 2018-05-16 22:58   ` Brandon Williams
  2018-05-16 22:58   ` [PATCH v2 34/36] remote: convert match_push_refs to take " Brandon Williams
                     ` (3 subsequent siblings)
  36 siblings, 0 replies; 112+ messages in thread
From: Brandon Williams @ 2018-05-16 22:58 UTC (permalink / raw)
  To: git, avarab, gitster, sbeller, bmwill
  Cc: avarab, gitster, sbeller, Brandon Williams

Convert http-push.c to store refspecs in a 'struct refspec' instead of
in an array of 'const char *'.

Signed-off-by: Brandon Williams <bmwill@google.com>
---
 http-push.c | 17 ++++++++---------
 1 file changed, 8 insertions(+), 9 deletions(-)

diff --git a/http-push.c b/http-push.c
index f308ce019..a724ef03f 100644
--- a/http-push.c
+++ b/http-push.c
@@ -1692,8 +1692,7 @@ int cmd_main(int argc, const char **argv)
 {
 	struct transfer_request *request;
 	struct transfer_request *next_request;
-	int nr_refspec = 0;
-	const char **refspec = NULL;
+	struct refspec rs = REFSPEC_INIT_PUSH;
 	struct remote_lock *ref_lock = NULL;
 	struct remote_lock *info_ref_lock = NULL;
 	struct rev_info revs;
@@ -1756,8 +1755,7 @@ int cmd_main(int argc, const char **argv)
 			}
 			continue;
 		}
-		refspec = argv;
-		nr_refspec = argc - i;
+		refspec_appendn(&rs, argv, argc - i);
 		break;
 	}
 
@@ -1768,7 +1766,7 @@ int cmd_main(int argc, const char **argv)
 	if (!repo->url)
 		usage(http_push_usage);
 
-	if (delete_branch && nr_refspec != 1)
+	if (delete_branch && rs.nr != 1)
 		die("You must specify only one branch name when deleting a remote branch");
 
 	setup_git_directory();
@@ -1814,18 +1812,19 @@ int cmd_main(int argc, const char **argv)
 
 	/* Remove a remote branch if -d or -D was specified */
 	if (delete_branch) {
-		if (delete_remote_branch(refspec[0], force_delete) == -1) {
+		const char *branch = rs.items[i].src;
+		if (delete_remote_branch(branch, force_delete) == -1) {
 			fprintf(stderr, "Unable to delete remote branch %s\n",
-				refspec[0]);
+				branch);
 			if (helper_status)
-				printf("error %s cannot remove\n", refspec[0]);
+				printf("error %s cannot remove\n", branch);
 		}
 		goto cleanup;
 	}
 
 	/* match them up */
 	if (match_push_refs(local_refs, &remote_refs,
-			    nr_refspec, (const char **) refspec, push_all)) {
+			    rs.raw_nr, rs.raw, push_all)) {
 		rc = -1;
 		goto cleanup;
 	}
-- 
2.17.0.441.gb46fe60e1d-goog


^ permalink raw reply related	[flat|nested] 112+ messages in thread

* [PATCH v2 34/36] remote: convert match_push_refs to take a struct refspec
  2018-05-16 22:57 ` [PATCH v2 00/36] " Brandon Williams
                     ` (32 preceding siblings ...)
  2018-05-16 22:58   ` [PATCH v2 33/36] http-push: store refspecs in a struct refspec Brandon Williams
@ 2018-05-16 22:58   ` Brandon Williams
  2018-05-16 22:58   ` [PATCH v2 35/36] remote: convert check_push_refs " Brandon Williams
                     ` (2 subsequent siblings)
  36 siblings, 0 replies; 112+ messages in thread
From: Brandon Williams @ 2018-05-16 22:58 UTC (permalink / raw)
  To: git, avarab, gitster, sbeller, bmwill
  Cc: avarab, gitster, sbeller, Brandon Williams

Convert 'match_push_refs()' to take a 'struct refspec' as a parameter
instead of an array of 'const char *'.

Signed-off-by: Brandon Williams <bmwill@google.com>
---
 builtin/remote.c    |  3 +--
 builtin/send-pack.c |  2 +-
 http-push.c         |  3 +--
 remote.c            | 21 ++++++++-------------
 remote.h            |  2 +-
 transport.c         |  4 +---
 6 files changed, 13 insertions(+), 22 deletions(-)

diff --git a/builtin/remote.c b/builtin/remote.c
index b8e66589f..b84175cc6 100644
--- a/builtin/remote.c
+++ b/builtin/remote.c
@@ -387,8 +387,7 @@ static int get_push_ref_states(const struct ref *remote_refs,
 	local_refs = get_local_heads();
 	push_map = copy_ref_list(remote_refs);
 
-	match_push_refs(local_refs, &push_map, remote->push.raw_nr,
-			remote->push.raw, MATCH_REFS_NONE);
+	match_push_refs(local_refs, &push_map, &remote->push, MATCH_REFS_NONE);
 
 	states->push.strdup_strings = 1;
 	for (ref = push_map; ref; ref = ref->next) {
diff --git a/builtin/send-pack.c b/builtin/send-pack.c
index 7c34bf467..4923b1058 100644
--- a/builtin/send-pack.c
+++ b/builtin/send-pack.c
@@ -275,7 +275,7 @@ int cmd_send_pack(int argc, const char **argv, const char *prefix)
 		flags |= MATCH_REFS_MIRROR;
 
 	/* match them up */
-	if (match_push_refs(local_refs, &remote_refs, rs.raw_nr, rs.raw, flags))
+	if (match_push_refs(local_refs, &remote_refs, &rs, flags))
 		return -1;
 
 	if (!is_empty_cas(&cas))
diff --git a/http-push.c b/http-push.c
index a724ef03f..ea5af6227 100644
--- a/http-push.c
+++ b/http-push.c
@@ -1823,8 +1823,7 @@ int cmd_main(int argc, const char **argv)
 	}
 
 	/* match them up */
-	if (match_push_refs(local_refs, &remote_refs,
-			    rs.raw_nr, rs.raw, push_all)) {
+	if (match_push_refs(local_refs, &remote_refs, &rs, push_all)) {
 		rc = -1;
 		goto cleanup;
 	}
diff --git a/remote.c b/remote.c
index 84dda3fd0..0046d4e28 100644
--- a/remote.c
+++ b/remote.c
@@ -1285,23 +1285,20 @@ int check_push_refs(struct ref *src, int nr_refspec, const char **refspec_names)
  * dst (e.g. pushing to a new branch, done in match_explicit_refs).
  */
 int match_push_refs(struct ref *src, struct ref **dst,
-		    int nr_refspec, const char **refspec, int flags)
+		    struct refspec *rs, int flags)
 {
-	struct refspec rs = REFSPEC_INIT_PUSH;
 	int send_all = flags & MATCH_REFS_ALL;
 	int send_mirror = flags & MATCH_REFS_MIRROR;
 	int send_prune = flags & MATCH_REFS_PRUNE;
 	int errs;
-	static const char *default_refspec[] = { ":", NULL };
 	struct ref *ref, **dst_tail = tail_ref(dst);
 	struct string_list dst_ref_index = STRING_LIST_INIT_NODUP;
 
-	if (!nr_refspec) {
-		nr_refspec = 1;
-		refspec = default_refspec;
-	}
-	refspec_appendn(&rs, refspec, nr_refspec);
-	errs = match_explicit_refs(src, *dst, &dst_tail, &rs);
+	/* If no refspec is provided, use the default ":" */
+	if (!rs->nr)
+		refspec_append(rs, ":");
+
+	errs = match_explicit_refs(src, *dst, &dst_tail, rs);
 
 	/* pick the remainder */
 	for (ref = src; ref; ref = ref->next) {
@@ -1310,7 +1307,7 @@ int match_push_refs(struct ref *src, struct ref **dst,
 		const struct refspec_item *pat = NULL;
 		char *dst_name;
 
-		dst_name = get_ref_match(&rs, ref, send_mirror, FROM_SRC, &pat);
+		dst_name = get_ref_match(rs, ref, send_mirror, FROM_SRC, &pat);
 		if (!dst_name)
 			continue;
 
@@ -1359,7 +1356,7 @@ int match_push_refs(struct ref *src, struct ref **dst,
 				/* We're already sending something to this ref. */
 				continue;
 
-			src_name = get_ref_match(&rs, ref, send_mirror, FROM_DST, NULL);
+			src_name = get_ref_match(rs, ref, send_mirror, FROM_DST, NULL);
 			if (src_name) {
 				if (!src_ref_index.nr)
 					prepare_ref_index(&src_ref_index, src);
@@ -1372,8 +1369,6 @@ int match_push_refs(struct ref *src, struct ref **dst,
 		string_list_clear(&src_ref_index, 0);
 	}
 
-	refspec_clear(&rs);
-
 	if (errs)
 		return -1;
 	return 0;
diff --git a/remote.h b/remote.h
index 9050ff75a..74c557457 100644
--- a/remote.h
+++ b/remote.h
@@ -163,7 +163,7 @@ char *apply_refspecs(struct refspec *rs, const char *name);
 
 int check_push_refs(struct ref *src, int nr_refspec, const char **refspec);
 int match_push_refs(struct ref *src, struct ref **dst,
-		    int nr_refspec, const char **refspec, int all);
+		    struct refspec *rs, int flags);
 void set_ref_status_for_push(struct ref *remote_refs, int send_mirror,
 	int force_update);
 
diff --git a/transport.c b/transport.c
index fe96c0b80..24a97d9e8 100644
--- a/transport.c
+++ b/transport.c
@@ -1127,10 +1127,8 @@ int transport_push(struct transport *transport,
 		if (flags & TRANSPORT_PUSH_FOLLOW_TAGS)
 			match_flags |= MATCH_REFS_FOLLOW_TAGS;
 
-		if (match_push_refs(local_refs, &remote_refs,
-				    rs->raw_nr, rs->raw, match_flags)) {
+		if (match_push_refs(local_refs, &remote_refs, rs, match_flags))
 			return -1;
-		}
 
 		if (transport->smart_options &&
 		    transport->smart_options->cas &&
-- 
2.17.0.441.gb46fe60e1d-goog


^ permalink raw reply related	[flat|nested] 112+ messages in thread

* [PATCH v2 35/36] remote: convert check_push_refs to take a struct refspec
  2018-05-16 22:57 ` [PATCH v2 00/36] " Brandon Williams
                     ` (33 preceding siblings ...)
  2018-05-16 22:58   ` [PATCH v2 34/36] remote: convert match_push_refs to take " Brandon Williams
@ 2018-05-16 22:58   ` Brandon Williams
  2018-05-16 22:58   ` [PATCH v2 36/36] submodule: convert push_unpushed_submodules " Brandon Williams
  2018-05-16 23:48   ` [PATCH 0/2] generating ref-prefixes for configured refspecs Brandon Williams
  36 siblings, 0 replies; 112+ messages in thread
From: Brandon Williams @ 2018-05-16 22:58 UTC (permalink / raw)
  To: git, avarab, gitster, sbeller, bmwill
  Cc: avarab, gitster, sbeller, Brandon Williams

Convert 'check_push_refs()' to take a 'struct refspec' as a parameter
instead of an array of 'const char *'.

Signed-off-by: Brandon Williams <bmwill@google.com>
---
 remote.c    | 14 +++++---------
 remote.h    |  2 +-
 transport.c |  2 +-
 3 files changed, 7 insertions(+), 11 deletions(-)

diff --git a/remote.c b/remote.c
index 0046d4e28..0d1a3d07f 100644
--- a/remote.c
+++ b/remote.c
@@ -1255,24 +1255,20 @@ static void prepare_ref_index(struct string_list *ref_index, struct ref *ref)
  * but we can catch some errors early before even talking to the
  * remote side.
  */
-int check_push_refs(struct ref *src, int nr_refspec, const char **refspec_names)
+int check_push_refs(struct ref *src, struct refspec *rs)
 {
-	struct refspec refspec = REFSPEC_INIT_PUSH;
 	int ret = 0;
 	int i;
 
-	refspec_appendn(&refspec, refspec_names, nr_refspec);
-
-	for (i = 0; i < refspec.nr; i++) {
-		struct refspec_item *rs = &refspec.items[i];
+	for (i = 0; i < rs->nr; i++) {
+		struct refspec_item *item = &rs->items[i];
 
-		if (rs->pattern || rs->matching)
+		if (item->pattern || item->matching)
 			continue;
 
-		ret |= match_explicit_lhs(src, rs, NULL, NULL);
+		ret |= match_explicit_lhs(src, item, NULL, NULL);
 	}
 
-	refspec_clear(&refspec);
 	return ret;
 }
 
diff --git a/remote.h b/remote.h
index 74c557457..62a656659 100644
--- a/remote.h
+++ b/remote.h
@@ -161,7 +161,7 @@ struct ref *ref_remove_duplicates(struct ref *ref_map);
 int query_refspecs(struct refspec *rs, struct refspec_item *query);
 char *apply_refspecs(struct refspec *rs, const char *name);
 
-int check_push_refs(struct ref *src, int nr_refspec, const char **refspec);
+int check_push_refs(struct ref *src, struct refspec *rs);
 int match_push_refs(struct ref *src, struct ref **dst,
 		    struct refspec *rs, int flags);
 void set_ref_status_for_push(struct ref *remote_refs, int send_mirror,
diff --git a/transport.c b/transport.c
index 24a97d9e8..e32bc320c 100644
--- a/transport.c
+++ b/transport.c
@@ -1090,7 +1090,7 @@ int transport_push(struct transport *transport,
 		struct argv_array ref_prefixes = ARGV_ARRAY_INIT;
 		int i;
 
-		if (check_push_refs(local_refs, rs->raw_nr, rs->raw) < 0)
+		if (check_push_refs(local_refs, rs) < 0)
 			return -1;
 
 		for (i = 0; i < rs->nr; i++) {
-- 
2.17.0.441.gb46fe60e1d-goog


^ permalink raw reply related	[flat|nested] 112+ messages in thread

* [PATCH v2 36/36] submodule: convert push_unpushed_submodules to take a struct refspec
  2018-05-16 22:57 ` [PATCH v2 00/36] " Brandon Williams
                     ` (34 preceding siblings ...)
  2018-05-16 22:58   ` [PATCH v2 35/36] remote: convert check_push_refs " Brandon Williams
@ 2018-05-16 22:58   ` Brandon Williams
  2018-05-16 23:48   ` [PATCH 0/2] generating ref-prefixes for configured refspecs Brandon Williams
  36 siblings, 0 replies; 112+ messages in thread
From: Brandon Williams @ 2018-05-16 22:58 UTC (permalink / raw)
  To: git, avarab, gitster, sbeller, bmwill
  Cc: avarab, gitster, sbeller, Brandon Williams

Convert 'push_unpushed_submodules()' to take a 'struct refspec' as a
parameter instead of an array of 'const char *'.

Signed-off-by: Brandon Williams <bmwill@google.com>
---
 submodule.c | 19 +++++++++----------
 submodule.h |  3 ++-
 transport.c |  2 +-
 3 files changed, 12 insertions(+), 12 deletions(-)

diff --git a/submodule.c b/submodule.c
index 74d35b257..cdeadd80e 100644
--- a/submodule.c
+++ b/submodule.c
@@ -968,7 +968,7 @@ int find_unpushed_submodules(struct oid_array *commits,
 
 static int push_submodule(const char *path,
 			  const struct remote *remote,
-			  const char **refspec, int refspec_nr,
+			  const struct refspec *rs,
 			  const struct string_list *push_options,
 			  int dry_run)
 {
@@ -991,8 +991,8 @@ static int push_submodule(const char *path,
 		if (remote->origin != REMOTE_UNCONFIGURED) {
 			int i;
 			argv_array_push(&cp.args, remote->name);
-			for (i = 0; i < refspec_nr; i++)
-				argv_array_push(&cp.args, refspec[i]);
+			for (i = 0; i < rs->raw_nr; i++)
+				argv_array_push(&cp.args, rs->raw[i]);
 		}
 
 		prepare_submodule_repo_env(&cp.env_array);
@@ -1013,7 +1013,7 @@ static int push_submodule(const char *path,
  */
 static void submodule_push_check(const char *path, const char *head,
 				 const struct remote *remote,
-				 const char **refspec, int refspec_nr)
+				 const struct refspec *rs)
 {
 	struct child_process cp = CHILD_PROCESS_INIT;
 	int i;
@@ -1023,8 +1023,8 @@ static void submodule_push_check(const char *path, const char *head,
 	argv_array_push(&cp.args, head);
 	argv_array_push(&cp.args, remote->name);
 
-	for (i = 0; i < refspec_nr; i++)
-		argv_array_push(&cp.args, refspec[i]);
+	for (i = 0; i < rs->raw_nr; i++)
+		argv_array_push(&cp.args, rs->raw[i]);
 
 	prepare_submodule_repo_env(&cp.env_array);
 	cp.git_cmd = 1;
@@ -1043,7 +1043,7 @@ static void submodule_push_check(const char *path, const char *head,
 
 int push_unpushed_submodules(struct oid_array *commits,
 			     const struct remote *remote,
-			     const char **refspec, int refspec_nr,
+			     const struct refspec *rs,
 			     const struct string_list *push_options,
 			     int dry_run)
 {
@@ -1069,8 +1069,7 @@ int push_unpushed_submodules(struct oid_array *commits,
 
 		for (i = 0; i < needs_pushing.nr; i++)
 			submodule_push_check(needs_pushing.items[i].string,
-					     head, remote,
-					     refspec, refspec_nr);
+					     head, remote, rs);
 		free(head);
 	}
 
@@ -1078,7 +1077,7 @@ int push_unpushed_submodules(struct oid_array *commits,
 	for (i = 0; i < needs_pushing.nr; i++) {
 		const char *path = needs_pushing.items[i].string;
 		fprintf(stderr, "Pushing submodule '%s'\n", path);
-		if (!push_submodule(path, remote, refspec, refspec_nr,
+		if (!push_submodule(path, remote, rs,
 				    push_options, dry_run)) {
 			fprintf(stderr, "Unable to push submodule '%s'\n", path);
 			ret = 0;
diff --git a/submodule.h b/submodule.h
index e5526f6aa..aae0c9c8f 100644
--- a/submodule.h
+++ b/submodule.h
@@ -100,9 +100,10 @@ extern int submodule_touches_in_range(struct object_id *a,
 extern int find_unpushed_submodules(struct oid_array *commits,
 				    const char *remotes_name,
 				    struct string_list *needs_pushing);
+struct refspec;
 extern int push_unpushed_submodules(struct oid_array *commits,
 				    const struct remote *remote,
-				    const char **refspec, int refspec_nr,
+				    const struct refspec *rs,
 				    const struct string_list *push_options,
 				    int dry_run);
 /*
diff --git a/transport.c b/transport.c
index e32bc320c..7e0b9abba 100644
--- a/transport.c
+++ b/transport.c
@@ -1157,7 +1157,7 @@ int transport_push(struct transport *transport,
 
 			if (!push_unpushed_submodules(&commits,
 						      transport->remote,
-						      rs->raw, rs->raw_nr,
+						      rs,
 						      transport->push_options,
 						      pretend)) {
 				oid_array_clear(&commits);
-- 
2.17.0.441.gb46fe60e1d-goog


^ permalink raw reply related	[flat|nested] 112+ messages in thread

* [PATCH 0/2] generating ref-prefixes for configured refspecs
  2018-05-16 22:57 ` [PATCH v2 00/36] " Brandon Williams
                     ` (35 preceding siblings ...)
  2018-05-16 22:58   ` [PATCH v2 36/36] submodule: convert push_unpushed_submodules " Brandon Williams
@ 2018-05-16 23:48   ` Brandon Williams
  2018-05-16 23:48     ` [PATCH 1/2] refspec: consolidate ref-prefix generation logic Brandon Williams
                       ` (2 more replies)
  36 siblings, 3 replies; 112+ messages in thread
From: Brandon Williams @ 2018-05-16 23:48 UTC (permalink / raw)
  To: git, bmwill; +Cc: Brandon Williams

Here's my short follow on series to the refspec refactoring.

When v2 was introduced ref-prefixes were only generated for user
provided refspecs (given via the command line).  This means that you can
only benefit from server-side ref filtering if you explicitly provide a
refspec, so this short series extends this to generate the ref-prefixes
even for the refspecs which are configured in 'remote.<name>.fetch'.

This series is based on the v2 of the refspec refactoring series.

Brandon Williams (2):
  refspec: consolidate ref-prefix generation logic
  fetch: generate ref-prefixes when using a configured refspec

 builtin/fetch.c        | 19 ++++++++-----------
 refspec.c              | 29 +++++++++++++++++++++++++++++
 refspec.h              |  4 ++++
 t/t5702-protocol-v2.sh | 14 ++++++++++++++
 transport.c            | 21 +--------------------
 5 files changed, 56 insertions(+), 31 deletions(-)

-- 
2.17.0.441.gb46fe60e1d-goog


^ permalink raw reply	[flat|nested] 112+ messages in thread

* [PATCH 1/2] refspec: consolidate ref-prefix generation logic
  2018-05-16 23:48   ` [PATCH 0/2] generating ref-prefixes for configured refspecs Brandon Williams
@ 2018-05-16 23:48     ` Brandon Williams
  2018-05-31  0:43       ` Jonathan Nieder
  2018-05-31  7:23       ` [PATCH] fetch: do not pass ref-prefixes for fetch by exact SHA1 Jonathan Nieder
  2018-05-16 23:48     ` [PATCH 2/2] fetch: generate ref-prefixes when using a configured refspec Brandon Williams
  2018-05-17 21:32     ` [PATCH 0/2] generating ref-prefixes for configured refspecs Junio C Hamano
  2 siblings, 2 replies; 112+ messages in thread
From: Brandon Williams @ 2018-05-16 23:48 UTC (permalink / raw)
  To: git, bmwill; +Cc: Brandon Williams

When using protocol v2 a client constructs a list of ref-prefixes which
are sent across the wire so that the server can do server-side filtering
of the ref-advertisement.  The logic that does this exists for both
fetch and push (even though no push support for v2 currently exists yet)
and is roughly the same so lets consolidate this logic and make it
general enough that it can be used for both the push and fetch cases.

Signed-off-by: Brandon Williams <bmwill@google.com>
---
 builtin/fetch.c | 13 +------------
 refspec.c       | 29 +++++++++++++++++++++++++++++
 refspec.h       |  4 ++++
 transport.c     | 21 +--------------------
 4 files changed, 35 insertions(+), 32 deletions(-)

diff --git a/builtin/fetch.c b/builtin/fetch.c
index 3fad1f0db..80bb14370 100644
--- a/builtin/fetch.c
+++ b/builtin/fetch.c
@@ -351,18 +351,7 @@ static struct ref *get_ref_map(struct transport *transport,
 
 	const struct ref *remote_refs;
 
-	for (i = 0; i < rs->nr; i++) {
-		const struct refspec_item *item = &rs->items[i];
-		if (!item->exact_sha1) {
-			const char *glob = strchr(item->src, '*');
-			if (glob)
-				argv_array_pushf(&ref_prefixes, "%.*s",
-						 (int)(glob - item->src),
-						 item->src);
-			else
-				expand_ref_prefix(&ref_prefixes, item->src);
-		}
-	}
+	refspec_ref_prefixes(rs, &ref_prefixes);
 
 	remote_refs = transport_get_remote_refs(transport, &ref_prefixes);
 
diff --git a/refspec.c b/refspec.c
index 97e76e8b1..c59a4ccf1 100644
--- a/refspec.c
+++ b/refspec.c
@@ -1,4 +1,5 @@
 #include "cache.h"
+#include "argv-array.h"
 #include "refs.h"
 #include "refspec.h"
 
@@ -192,3 +193,31 @@ int valid_fetch_refspec(const char *fetch_refspec_str)
 	refspec_item_clear(&refspec);
 	return ret;
 }
+
+void refspec_ref_prefixes(const struct refspec *rs,
+			  struct argv_array *ref_prefixes)
+{
+	int i;
+	for (i = 0; i < rs->nr; i++) {
+		const struct refspec_item *item = &rs->items[i];
+		const char *prefix = NULL;
+
+		if (rs->fetch == REFSPEC_FETCH)
+			prefix = item->src;
+		else if (item->dst)
+			prefix = item->dst;
+		else if (item->src && !item->exact_sha1)
+			prefix = item->src;
+
+		if (prefix) {
+			if (item->pattern) {
+				const char *glob = strchr(prefix, '*');
+				argv_array_pushf(ref_prefixes, "%.*s",
+						 (int)(glob - prefix),
+						 prefix);
+			} else {
+				expand_ref_prefix(ref_prefixes, prefix);
+			}
+		}
+	}
+}
diff --git a/refspec.h b/refspec.h
index 7e1ff94ac..01b700e09 100644
--- a/refspec.h
+++ b/refspec.h
@@ -41,4 +41,8 @@ void refspec_clear(struct refspec *rs);
 
 int valid_fetch_refspec(const char *refspec);
 
+struct argv_array;
+void refspec_ref_prefixes(const struct refspec *rs,
+			  struct argv_array *ref_prefixes);
+
 #endif /* REFSPEC_H */
diff --git a/transport.c b/transport.c
index 7e0b9abba..cbf0044c3 100644
--- a/transport.c
+++ b/transport.c
@@ -1088,30 +1088,11 @@ int transport_push(struct transport *transport,
 		int pretend = flags & TRANSPORT_PUSH_DRY_RUN;
 		int push_ret, ret, err;
 		struct argv_array ref_prefixes = ARGV_ARRAY_INIT;
-		int i;
 
 		if (check_push_refs(local_refs, rs) < 0)
 			return -1;
 
-		for (i = 0; i < rs->nr; i++) {
-			const struct refspec_item *item = &rs->items[i];
-			const char *prefix = NULL;
-
-			if (item->dst)
-				prefix = item->dst;
-			else if (item->src && !item->exact_sha1)
-				prefix = item->src;
-
-			if (prefix) {
-				const char *glob = strchr(prefix, '*');
-				if (glob)
-					argv_array_pushf(&ref_prefixes, "%.*s",
-							 (int)(glob - prefix),
-							 prefix);
-				else
-					expand_ref_prefix(&ref_prefixes, prefix);
-			}
-		}
+		refspec_ref_prefixes(rs, &ref_prefixes);
 
 		remote_refs = transport->vtable->get_refs_list(transport, 1,
 							       &ref_prefixes);
-- 
2.17.0.441.gb46fe60e1d-goog


^ permalink raw reply related	[flat|nested] 112+ messages in thread

* [PATCH 2/2] fetch: generate ref-prefixes when using a configured refspec
  2018-05-16 23:48   ` [PATCH 0/2] generating ref-prefixes for configured refspecs Brandon Williams
  2018-05-16 23:48     ` [PATCH 1/2] refspec: consolidate ref-prefix generation logic Brandon Williams
@ 2018-05-16 23:48     ` Brandon Williams
  2018-05-17 21:32     ` [PATCH 0/2] generating ref-prefixes for configured refspecs Junio C Hamano
  2 siblings, 0 replies; 112+ messages in thread
From: Brandon Williams @ 2018-05-16 23:48 UTC (permalink / raw)
  To: git, bmwill; +Cc: Brandon Williams

Teach fetch to generate ref-prefixes, to be used for server-side
filtering of the ref-advertisement, based on the configured fetch
refspec ('remote.<name>.fetch') when no user provided refspec exists.

Signed-off-by: Brandon Williams <bmwill@google.com>
---
 builtin/fetch.c        | 10 +++++++++-
 t/t5702-protocol-v2.sh | 14 ++++++++++++++
 2 files changed, 23 insertions(+), 1 deletion(-)

diff --git a/builtin/fetch.c b/builtin/fetch.c
index 80bb14370..7cc7a52de 100644
--- a/builtin/fetch.c
+++ b/builtin/fetch.c
@@ -351,7 +351,15 @@ static struct ref *get_ref_map(struct transport *transport,
 
 	const struct ref *remote_refs;
 
-	refspec_ref_prefixes(rs, &ref_prefixes);
+	if (rs->nr)
+		refspec_ref_prefixes(rs, &ref_prefixes);
+	else if (transport->remote && transport->remote->fetch.nr)
+		refspec_ref_prefixes(&transport->remote->fetch, &ref_prefixes);
+
+	if (ref_prefixes.argc &&
+	    (tags == TAGS_SET || (tags == TAGS_DEFAULT && !rs->nr))) {
+		argv_array_push(&ref_prefixes, "refs/tags/");
+	}
 
 	remote_refs = transport_get_remote_refs(transport, &ref_prefixes);
 
diff --git a/t/t5702-protocol-v2.sh b/t/t5702-protocol-v2.sh
index 56f7c3c32..b6c72ab51 100755
--- a/t/t5702-protocol-v2.sh
+++ b/t/t5702-protocol-v2.sh
@@ -201,6 +201,20 @@ test_expect_success 'ref advertisment is filtered during fetch using protocol v2
 	! grep "refs/tags/three" log
 '
 
+test_expect_success 'default refspec is used to filter ref when fetchcing' '
+	test_when_finished "rm -f log" &&
+
+	GIT_TRACE_PACKET="$(pwd)/log" git -C file_child -c protocol.version=2 \
+		fetch origin &&
+
+	git -C file_child log -1 --format=%s three >actual &&
+	git -C file_parent log -1 --format=%s three >expect &&
+	test_cmp expect actual &&
+
+	grep "ref-prefix refs/heads/" log &&
+	grep "ref-prefix refs/tags/" log
+'
+
 # Test protocol v2 with 'http://' transport
 #
 . "$TEST_DIRECTORY"/lib-httpd.sh
-- 
2.17.0.441.gb46fe60e1d-goog


^ permalink raw reply related	[flat|nested] 112+ messages in thread

* Re: [PATCH 0/2] generating ref-prefixes for configured refspecs
  2018-05-16 23:48   ` [PATCH 0/2] generating ref-prefixes for configured refspecs Brandon Williams
  2018-05-16 23:48     ` [PATCH 1/2] refspec: consolidate ref-prefix generation logic Brandon Williams
  2018-05-16 23:48     ` [PATCH 2/2] fetch: generate ref-prefixes when using a configured refspec Brandon Williams
@ 2018-05-17 21:32     ` Junio C Hamano
  2 siblings, 0 replies; 112+ messages in thread
From: Junio C Hamano @ 2018-05-17 21:32 UTC (permalink / raw)
  To: Brandon Williams; +Cc: git

Brandon Williams <bmwill@google.com> writes:

> Here's my short follow on series to the refspec refactoring.
>
> When v2 was introduced ref-prefixes were only generated for user
> provided refspecs (given via the command line).  This means that you can
> only benefit from server-side ref filtering if you explicitly provide a
> refspec, so this short series extends this to generate the ref-prefixes
> even for the refspecs which are configured in 'remote.<name>.fetch'.
>
> This series is based on the v2 of the refspec refactoring series.

Makes sense.

>
> Brandon Williams (2):
>   refspec: consolidate ref-prefix generation logic
>   fetch: generate ref-prefixes when using a configured refspec
>
>  builtin/fetch.c        | 19 ++++++++-----------
>  refspec.c              | 29 +++++++++++++++++++++++++++++
>  refspec.h              |  4 ++++
>  t/t5702-protocol-v2.sh | 14 ++++++++++++++
>  transport.c            | 21 +--------------------
>  5 files changed, 56 insertions(+), 31 deletions(-)

^ permalink raw reply	[flat|nested] 112+ messages in thread

* Re: [PATCH 1/2] refspec: consolidate ref-prefix generation logic
  2018-05-16 23:48     ` [PATCH 1/2] refspec: consolidate ref-prefix generation logic Brandon Williams
@ 2018-05-31  0:43       ` Jonathan Nieder
  2018-05-31  1:07         ` Jonathan Nieder
  2018-05-31  7:23       ` [PATCH] fetch: do not pass ref-prefixes for fetch by exact SHA1 Jonathan Nieder
  1 sibling, 1 reply; 112+ messages in thread
From: Jonathan Nieder @ 2018-05-31  0:43 UTC (permalink / raw)
  To: Brandon Williams; +Cc: git

Hi,

Brandon Williams wrote:

> When using protocol v2 a client constructs a list of ref-prefixes which
> are sent across the wire so that the server can do server-side filtering
> of the ref-advertisement.  The logic that does this exists for both
> fetch and push (even though no push support for v2 currently exists yet)
> and is roughly the same so lets consolidate this logic and make it
> general enough that it can be used for both the push and fetch cases.
>
> Signed-off-by: Brandon Williams <bmwill@google.com>
> ---
>  builtin/fetch.c | 13 +------------
>  refspec.c       | 29 +++++++++++++++++++++++++++++
>  refspec.h       |  4 ++++
>  transport.c     | 21 +--------------------
>  4 files changed, 35 insertions(+), 32 deletions(-)

I assume this is meant to be a refactoring with no functional change.
Alas, it's causing fetch-by-SHA-1 to fail for me:

 $ rm -fr /tmp/r
 $ git init /tmp/r
 Initialized empty Git repository in /tmp/r/.git/
 $ bin-wrappers/git -C /tmp/r -c protocol.version=2 fetch \
	https://kernel.googlesource.com/pub/scm/git/git \
	6373cb598e1a4e0340583ad75d5abba01ff79774
 fatal: no matching remote head

The parent commit succeeds.

Known issue?

Thanks,
Jonathan

^ permalink raw reply	[flat|nested] 112+ messages in thread

* Re: [PATCH 1/2] refspec: consolidate ref-prefix generation logic
  2018-05-31  0:43       ` Jonathan Nieder
@ 2018-05-31  1:07         ` Jonathan Nieder
  0 siblings, 0 replies; 112+ messages in thread
From: Jonathan Nieder @ 2018-05-31  1:07 UTC (permalink / raw)
  To: Brandon Williams; +Cc: git

Jonathan Nieder wrote:
> Brandon Williams wrote:

>> When using protocol v2 a client constructs a list of ref-prefixes which
>> are sent across the wire so that the server can do server-side filtering
>> of the ref-advertisement.  The logic that does this exists for both
>> fetch and push (even though no push support for v2 currently exists yet)
>> and is roughly the same so lets consolidate this logic and make it
>> general enough that it can be used for both the push and fetch cases.
>>
>> Signed-off-by: Brandon Williams <bmwill@google.com>
>> ---
>>  builtin/fetch.c | 13 +------------
>>  refspec.c       | 29 +++++++++++++++++++++++++++++
>>  refspec.h       |  4 ++++
>>  transport.c     | 21 +--------------------
>>  4 files changed, 35 insertions(+), 32 deletions(-)
>
> I assume this is meant to be a refactoring with no functional change.
> Alas, it's causing fetch-by-SHA-1 to fail for me:
[...]
>  $ bin-wrappers/git -C /tmp/r -c protocol.version=2 fetch \
> 	https://kernel.googlesource.com/pub/scm/git/git \
> 	6373cb598e1a4e0340583ad75d5abba01ff79774
>  fatal: no matching remote head

Backtrace:

 #0  0x0000555555671e09 in fetch_pack (args=0x7fffffffda80, fd=0x555555a6a9b0, conn=0x555555a65780, ref=0x0, 
     dest=0x555555a64900 "https://kernel.googlesource.com/pub/scm/git/git", sought=0x555555a69a80, nr_sought=1, shallow=0x555555a6a9d8, 
     pack_lockfile=0x555555a631c8, version=protocol_v2) at fetch-pack.c:1562
 #1  0x00005555557290b9 in fetch_refs_via_pack (transport=0x555555a63190, nr_heads=1, to_fetch=0x555555a69a80) at transport.c:326
 #2  0x000055555572b712 in transport_fetch_refs (transport=0x555555a63190, refs=0x555555a65520) at transport.c:1247
 #3  0x000055555559a2a6 in fetch_refs (transport=0x555555a63190, ref_map=0x555555a65520) at builtin/fetch.c:942
 #4  0x000055555559ac3e in do_fetch (transport=0x555555a63190, rs=0x7fffffffdc30) at builtin/fetch.c:1157
 #5  0x000055555559b535 in fetch_one (remote=0x555555a63870, argc=1, argv=0x7fffffffdff8, prune_tags_ok=0) at builtin/fetch.c:1398
 #6  0x000055555559b9a3 in cmd_fetch (argc=1, argv=0x7fffffffdff8, prefix=0x0) at builtin/fetch.c:1487
 #7  0x000055555556764b in run_builtin (p=0x555555a0fa30 <commands+816>, argc=3, argv=0x7fffffffdff0) at git.c:350
 #8  0x000055555556795f in handle_builtin (argc=3, argv=0x7fffffffdff0) at git.c:565
 #9  0x0000555555567b07 in run_argv (argcp=0x7fffffffde8c, argv=0x7fffffffde80) at git.c:617
 #10 0x0000555555567cbc in cmd_main (argc=3, argv=0x7fffffffdff0) at git.c:694
 #11 0x000055555560774c in main (argc=8, argv=0x7fffffffdfc8) at common-main.c:45

Both refs_tmp and transport->remote_refs are NULL.

When refspec_ref_prefixes gets called, it produces the usual
argv_array with 6373cb598e1a4e0340583ad75d5abba01ff79774,
refs/6373cb598e1a4e0340583ad75d5abba01ff79774, etc.

In the old code, this doesn't happen because we trigger the
item->exact_sha1 test.

Would something like the following make sense?  It passes tests and
appears to avoid trouble but I haven't looked any closer than that.

Signed-off-by: Jonathan Nieder <jrnieder@gmail.com>

--- i/refspec.c
+++ w/refspec.c
@@ -202,6 +202,8 @@ void refspec_ref_prefixes(const struct refspec *rs,
 		const struct refspec_item *item = &rs->items[i];
 		const char *prefix = NULL;
 
+		if (item->exact_sha1)
+			continue;
 		if (rs->fetch == REFSPEC_FETCH)
 			prefix = item->src;
 		else if (item->dst)

^ permalink raw reply	[flat|nested] 112+ messages in thread

* [PATCH] fetch: do not pass ref-prefixes for fetch by exact SHA1
  2018-05-16 23:48     ` [PATCH 1/2] refspec: consolidate ref-prefix generation logic Brandon Williams
  2018-05-31  0:43       ` Jonathan Nieder
@ 2018-05-31  7:23       ` Jonathan Nieder
  2018-05-31 15:44         ` Brandon Williams
  2018-06-01  2:12         ` Junio C Hamano
  1 sibling, 2 replies; 112+ messages in thread
From: Jonathan Nieder @ 2018-05-31  7:23 UTC (permalink / raw)
  To: Brandon Williams; +Cc: git, Junio C Hamano

When v2.18.0-rc0~10^2~1 (refspec: consolidate ref-prefix generation
logic, 2018-05-16) factored out the ref-prefix generation code for
reuse, it left out the 'if (!item->exact_sha1)' test in the original
ref-prefix generation code. As a result, fetches by SHA-1 generate
ref-prefixes as though the SHA-1 being fetched were an abbreviated ref
name:

 $ GIT_TRACE_PACKET=1 bin-wrappers/git -c protocol.version=2 \
	fetch origin 12039e008f9a4e3394f3f94f8ea897785cb09448
[...]
 packet:        fetch> ref-prefix 12039e008f9a4e3394f3f94f8ea897785cb09448
 packet:        fetch> ref-prefix refs/12039e008f9a4e3394f3f94f8ea897785cb09448
 packet:        fetch> ref-prefix refs/tags/12039e008f9a4e3394f3f94f8ea897785cb09448
 packet:        fetch> ref-prefix refs/heads/12039e008f9a4e3394f3f94f8ea897785cb09448
 packet:        fetch> ref-prefix refs/remotes/12039e008f9a4e3394f3f94f8ea897785cb09448
 packet:        fetch> ref-prefix refs/remotes/12039e008f9a4e3394f3f94f8ea897785cb09448/HEAD
 packet:        fetch> 0000

If there is another ref name on the command line or the object being
fetched is already available locally, then that's mostly harmless.
But otherwise, we error out with

 fatal: no matching remote head

since the server did not send any refs we are interested in.  Filter
out the exact_sha1 refspecs to avoid this.

This patch adds a test to check this behavior that notices another
behavior difference between protocol v0 and v2 in the process.  Add a
NEEDSWORK comment to clear it up.

Signed-off-by: Jonathan Nieder <jrnieder@gmail.com>
---
Here's the change described in
https://public-inbox.org/git/20180531010739.GB36515@aiede.svl.corp.google.com/
as a proper patch.

Thoughts of all kinds welcome, as always.

 refspec.c             |  2 ++
 refspec.h             |  4 ++++
 t/t5516-fetch-push.sh | 19 +++++++++++++++++++
 3 files changed, 25 insertions(+)

diff --git a/refspec.c b/refspec.c
index c59a4ccf1e..ada7854f7a 100644
--- a/refspec.c
+++ b/refspec.c
@@ -202,6 +202,8 @@ void refspec_ref_prefixes(const struct refspec *rs,
 		const struct refspec_item *item = &rs->items[i];
 		const char *prefix = NULL;
 
+		if (item->exact_sha1)
+			continue;
 		if (rs->fetch == REFSPEC_FETCH)
 			prefix = item->src;
 		else if (item->dst)
diff --git a/refspec.h b/refspec.h
index 01b700e094..3a9363887c 100644
--- a/refspec.h
+++ b/refspec.h
@@ -42,6 +42,10 @@ void refspec_clear(struct refspec *rs);
 int valid_fetch_refspec(const char *refspec);
 
 struct argv_array;
+/*
+ * Determine what <prefix> values to pass to the peer in ref-prefix lines
+ * (see Documentation/technical/protocol-v2.txt).
+ */
 void refspec_ref_prefixes(const struct refspec *rs,
 			  struct argv_array *ref_prefixes);
 
diff --git a/t/t5516-fetch-push.sh b/t/t5516-fetch-push.sh
index f4d28288f0..a5077d8b7c 100755
--- a/t/t5516-fetch-push.sh
+++ b/t/t5516-fetch-push.sh
@@ -1121,6 +1121,25 @@ test_expect_success 'fetch exact SHA1' '
 	)
 '
 
+test_expect_success 'fetch exact SHA1 in protocol v2' '
+	mk_test testrepo heads/master hidden/one &&
+	git push testrepo master:refs/hidden/one &&
+	git -C testrepo config transfer.hiderefs refs/hidden &&
+	check_push_result testrepo $the_commit hidden/one &&
+
+	mk_child testrepo child &&
+	git -C child config protocol.version 2 &&
+
+	# make sure $the_commit does not exist here
+	git -C child repack -a -d &&
+	git -C child prune &&
+	test_must_fail git -C child cat-file -t $the_commit &&
+
+	# fetching the hidden object succeeds by default
+	# NEEDSWORK: should this match the v0 behavior instead?
+	git -C child fetch -v ../testrepo $the_commit:refs/heads/copy
+'
+
 for configallowtipsha1inwant in true false
 do
 	test_expect_success "shallow fetch reachable SHA1 (but not a ref), allowtipsha1inwant=$configallowtipsha1inwant" '
-- 
2.17.1.1185.g55be947832


^ permalink raw reply related	[flat|nested] 112+ messages in thread

* Re: [PATCH] fetch: do not pass ref-prefixes for fetch by exact SHA1
  2018-05-31  7:23       ` [PATCH] fetch: do not pass ref-prefixes for fetch by exact SHA1 Jonathan Nieder
@ 2018-05-31 15:44         ` Brandon Williams
  2018-06-01  2:12         ` Junio C Hamano
  1 sibling, 0 replies; 112+ messages in thread
From: Brandon Williams @ 2018-05-31 15:44 UTC (permalink / raw)
  To: Jonathan Nieder; +Cc: Git Mailing List, Junio C Hamano

Thanks for finding this, I don't know how I missed moving that bit
over when factoring it out.  Well I guess I sort of rewrote it and
combined two pieces of logic so that's how.  Anyway, this looks right
and thanks for adding the test.

On Thu, May 31, 2018 at 12:23 AM, Jonathan Nieder <jrnieder@gmail.com> wrote:
> When v2.18.0-rc0~10^2~1 (refspec: consolidate ref-prefix generation
> logic, 2018-05-16) factored out the ref-prefix generation code for
> reuse, it left out the 'if (!item->exact_sha1)' test in the original
> ref-prefix generation code. As a result, fetches by SHA-1 generate
> ref-prefixes as though the SHA-1 being fetched were an abbreviated ref
> name:
>
>  $ GIT_TRACE_PACKET=1 bin-wrappers/git -c protocol.version=2 \
>         fetch origin 12039e008f9a4e3394f3f94f8ea897785cb09448
> [...]
>  packet:        fetch> ref-prefix 12039e008f9a4e3394f3f94f8ea897785cb09448
>  packet:        fetch> ref-prefix refs/12039e008f9a4e3394f3f94f8ea897785cb09448
>  packet:        fetch> ref-prefix refs/tags/12039e008f9a4e3394f3f94f8ea897785cb09448
>  packet:        fetch> ref-prefix refs/heads/12039e008f9a4e3394f3f94f8ea897785cb09448
>  packet:        fetch> ref-prefix refs/remotes/12039e008f9a4e3394f3f94f8ea897785cb09448
>  packet:        fetch> ref-prefix refs/remotes/12039e008f9a4e3394f3f94f8ea897785cb09448/HEAD
>  packet:        fetch> 0000
>
> If there is another ref name on the command line or the object being
> fetched is already available locally, then that's mostly harmless.
> But otherwise, we error out with
>
>  fatal: no matching remote head
>
> since the server did not send any refs we are interested in.  Filter
> out the exact_sha1 refspecs to avoid this.
>
> This patch adds a test to check this behavior that notices another
> behavior difference between protocol v0 and v2 in the process.  Add a
> NEEDSWORK comment to clear it up.
>
> Signed-off-by: Jonathan Nieder <jrnieder@gmail.com>
> ---
> Here's the change described in
> https://public-inbox.org/git/20180531010739.GB36515@aiede.svl.corp.google.com/
> as a proper patch.
>
> Thoughts of all kinds welcome, as always.
>
>  refspec.c             |  2 ++
>  refspec.h             |  4 ++++
>  t/t5516-fetch-push.sh | 19 +++++++++++++++++++
>  3 files changed, 25 insertions(+)
>
> diff --git a/refspec.c b/refspec.c
> index c59a4ccf1e..ada7854f7a 100644
> --- a/refspec.c
> +++ b/refspec.c
> @@ -202,6 +202,8 @@ void refspec_ref_prefixes(const struct refspec *rs,
>                 const struct refspec_item *item = &rs->items[i];
>                 const char *prefix = NULL;
>
> +               if (item->exact_sha1)
> +                       continue;
>                 if (rs->fetch == REFSPEC_FETCH)
>                         prefix = item->src;
>                 else if (item->dst)
> diff --git a/refspec.h b/refspec.h
> index 01b700e094..3a9363887c 100644
> --- a/refspec.h
> +++ b/refspec.h
> @@ -42,6 +42,10 @@ void refspec_clear(struct refspec *rs);
>  int valid_fetch_refspec(const char *refspec);
>
>  struct argv_array;
> +/*
> + * Determine what <prefix> values to pass to the peer in ref-prefix lines
> + * (see Documentation/technical/protocol-v2.txt).
> + */
>  void refspec_ref_prefixes(const struct refspec *rs,
>                           struct argv_array *ref_prefixes);
>
> diff --git a/t/t5516-fetch-push.sh b/t/t5516-fetch-push.sh
> index f4d28288f0..a5077d8b7c 100755
> --- a/t/t5516-fetch-push.sh
> +++ b/t/t5516-fetch-push.sh
> @@ -1121,6 +1121,25 @@ test_expect_success 'fetch exact SHA1' '
>         )
>  '
>
> +test_expect_success 'fetch exact SHA1 in protocol v2' '
> +       mk_test testrepo heads/master hidden/one &&
> +       git push testrepo master:refs/hidden/one &&
> +       git -C testrepo config transfer.hiderefs refs/hidden &&
> +       check_push_result testrepo $the_commit hidden/one &&
> +
> +       mk_child testrepo child &&
> +       git -C child config protocol.version 2 &&
> +
> +       # make sure $the_commit does not exist here
> +       git -C child repack -a -d &&
> +       git -C child prune &&
> +       test_must_fail git -C child cat-file -t $the_commit &&
> +
> +       # fetching the hidden object succeeds by default
> +       # NEEDSWORK: should this match the v0 behavior instead?
> +       git -C child fetch -v ../testrepo $the_commit:refs/heads/copy
> +'
> +
>  for configallowtipsha1inwant in true false
>  do
>         test_expect_success "shallow fetch reachable SHA1 (but not a ref), allowtipsha1inwant=$configallowtipsha1inwant" '
> --
> 2.17.1.1185.g55be947832
>

^ permalink raw reply	[flat|nested] 112+ messages in thread

* Re: [PATCH] fetch: do not pass ref-prefixes for fetch by exact SHA1
  2018-05-31  7:23       ` [PATCH] fetch: do not pass ref-prefixes for fetch by exact SHA1 Jonathan Nieder
  2018-05-31 15:44         ` Brandon Williams
@ 2018-06-01  2:12         ` Junio C Hamano
  2018-06-01  2:49           ` Jonathan Nieder
  1 sibling, 1 reply; 112+ messages in thread
From: Junio C Hamano @ 2018-06-01  2:12 UTC (permalink / raw)
  To: Jonathan Nieder; +Cc: Brandon Williams, git

Jonathan Nieder <jrnieder@gmail.com> writes:

> When v2.18.0-rc0~10^2~1 (refspec: consolidate ref-prefix generation
> logic, 2018-05-16) factored out the ref-prefix generation code for
> reuse, it left out the 'if (!item->exact_sha1)' test in the original
> ref-prefix generation code. As a result, fetches by SHA-1 generate
> ref-prefixes as though the SHA-1 being fetched were an abbreviated ref
> name:
>
>  $ GIT_TRACE_PACKET=1 bin-wrappers/git -c protocol.version=2 \
> 	fetch origin 12039e008f9a4e3394f3f94f8ea897785cb09448
> [...]
>  packet:        fetch> ref-prefix 12039e008f9a4e3394f3f94f8ea897785cb09448
>  packet:        fetch> ref-prefix refs/12039e008f9a4e3394f3f94f8ea897785cb09448
>  packet:        fetch> ref-prefix refs/tags/12039e008f9a4e3394f3f94f8ea897785cb09448
>  packet:        fetch> ref-prefix refs/heads/12039e008f9a4e3394f3f94f8ea897785cb09448
>  packet:        fetch> ref-prefix refs/remotes/12039e008f9a4e3394f3f94f8ea897785cb09448
>  packet:        fetch> ref-prefix refs/remotes/12039e008f9a4e3394f3f94f8ea897785cb09448/HEAD
>  packet:        fetch> 0000
>
> If there is another ref name on the command line or the object being
> fetched is already available locally, then that's mostly harmless.
> But otherwise, we error out with
>
>  fatal: no matching remote head
>
> since the server did not send any refs we are interested in.  Filter
> out the exact_sha1 refspecs to avoid this.
>
> This patch adds a test to check this behavior that notices another
> behavior difference between protocol v0 and v2 in the process.  Add a
> NEEDSWORK comment to clear it up.

Thanks.

I wonder if there is a more effective way to smoke out other bugs
remaining in proto v2.  When the fetch-by-SHA1 feature was added
originally, we certainly would have added a test or two to make sure
it won't break.  The root cause of this breakage is that we lack the
ability to easily exercise proto v2 on these existing tests that
were written back in the proto v0 days.  It there were such a way
(like, a common set of tests that are run with all supported
protos), we would have caught the breakge even before the topic hit
'next'.



^ permalink raw reply	[flat|nested] 112+ messages in thread

* Re: [PATCH] fetch: do not pass ref-prefixes for fetch by exact SHA1
  2018-06-01  2:12         ` Junio C Hamano
@ 2018-06-01  2:49           ` Jonathan Nieder
  0 siblings, 0 replies; 112+ messages in thread
From: Jonathan Nieder @ 2018-06-01  2:49 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: Brandon Williams, git

Junio C Hamano wrote:
> Jonathan Nieder <jrnieder@gmail.com> writes:

>> This patch adds a test to check this behavior that notices another
>> behavior difference between protocol v0 and v2 in the process.  Add a
>> NEEDSWORK comment to clear it up.
>
> Thanks.
>
> I wonder if there is a more effective way to smoke out other bugs
> remaining in proto v2.  When the fetch-by-SHA1 feature was added
> originally, we certainly would have added a test or two to make sure
> it won't break.  The root cause of this breakage is that we lack the
> ability to easily exercise proto v2 on these existing tests that
> were written back in the proto v0 days.  It there were such a way
> (like, a common set of tests that are run with all supported
> protos), we would have caught the breakge even before the topic hit
> 'next'.

I had a similar thought.

I am not sure I agree about the root cause, but root causes are
generally slippery to define.  Because this bug had significant
internal impact, we came up with a few next steps:

- shore up protocol v2 test coverage, as you described

- arrange for long refactoring series we submit to be divided up for
  the team to review, to avoid reviewer fatigue.  Hopefully this will
  make us a better example for other submitters of long series.  We're
  open to cooperating with others --- maybe we can set up a volunteer
  reviewer brigade to get a more diverse set of eyes on each series
  --- though organizing that is harder.

- improve telemetry for our internal deployment, to get earlier notice
  when Git is producing more errors.  I suspect other installations
  may want something like this too --- e.g. I think this is one of the
  benefits of what Jeff Hostetler is starting to build with json-writer.

- help internal users triage errors from Git (like those decision
  trees parents have to help decide when to bring a child to the
  doctor), so that we get earlier notice and can roll back and report
  upstream more quickly when they've run into a Git bug

Or in other words, please expect more in this area soon, and feel free
to pester me if the test coverage doesn't arrive. :)

Thanks,
Jonathan

^ permalink raw reply	[flat|nested] 112+ messages in thread

* Re: [PATCH v2 05/36] refspec: convert valid_fetch_refspec to use parse_refspec
  2018-05-16 22:57   ` [PATCH v2 05/36] refspec: convert valid_fetch_refspec to use parse_refspec Brandon Williams
@ 2018-06-03 17:13     ` Martin Ågren
  2018-06-04 14:43       ` [PATCH] refspec: initalize `refspec_item` in `valid_fetch_refspec()` Martin Ågren
  0 siblings, 1 reply; 112+ messages in thread
From: Martin Ågren @ 2018-06-03 17:13 UTC (permalink / raw)
  To: Brandon Williams
  Cc: Git Mailing List, Ævar Arnfjörð Bjarmason,
	Junio C Hamano, Stefan Beller

Hi Brandon,

On 17 May 2018 at 00:57, Brandon Williams <bmwill@google.com> wrote:
> Convert 'valid_fetch_refspec()' to use the new 'parse_refspec()'
> function to only parse a single refspec and eliminate an allocation.
>
> Signed-off-by: Brandon Williams <bmwill@google.com>
> ---
>  refspec.c | 17 ++++++++---------
>  refspec.h |  3 ++-
>  2 files changed, 10 insertions(+), 10 deletions(-)
>
> diff --git a/refspec.c b/refspec.c
> index af9d0d4b3..ab37b5ba1 100644
> --- a/refspec.c
> +++ b/refspec.c
> @@ -146,15 +146,6 @@ static struct refspec_item *parse_refspec_internal(int nr_refspec, const char **
>         die("Invalid refspec '%s'", refspec[i]);
>  }
>
> -int valid_fetch_refspec(const char *fetch_refspec_str)
> -{
> -       struct refspec_item *refspec;
> -
> -       refspec = parse_refspec_internal(1, &fetch_refspec_str, 1, 1);
> -       free_refspec(1, refspec);
> -       return !!refspec;
> -}
> -
>  struct refspec_item *parse_fetch_refspec(int nr_refspec, const char **refspec)
>  {
>         return parse_refspec_internal(nr_refspec, refspec, 1, 0);
> @@ -242,3 +233,11 @@ void refspec_clear(struct refspec *rs)
>
>         rs->fetch = 0;
>  }
> +
> +int valid_fetch_refspec(const char *fetch_refspec_str)
> +{
> +       struct refspec_item refspec;
> +       int ret = parse_refspec(&refspec, fetch_refspec_str, REFSPEC_FETCH);
> +       refspec_item_clear(&refspec);
> +       return ret;
> +}

My compiler warned about this function. The `dst` and `src` pointers
will equal some random data on the stack, then they may or may not be
assigned to, then we will call `free()` on them.

At least I *think* that we "may or may not" assign to them. I don't have
much or any time to really dig into this right now unfortunately.

I suppose this could use a REFSPEC_ITEM_INIT, or a memset inside
`parse_refspec()`, but I am very unfamiliar with this code.

Martin

^ permalink raw reply	[flat|nested] 112+ messages in thread

* [PATCH] refspec: initalize `refspec_item` in `valid_fetch_refspec()`
  2018-06-03 17:13     ` Martin Ågren
@ 2018-06-04 14:43       ` Martin Ågren
  2018-06-04 17:36         ` Brandon Williams
  2018-06-04 21:55         ` Ævar Arnfjörð Bjarmason
  0 siblings, 2 replies; 112+ messages in thread
From: Martin Ågren @ 2018-06-04 14:43 UTC (permalink / raw)
  To: git
  Cc: Brandon Williams, Ævar Arnfjörð Bjarmason,
	Junio C Hamano, Stefan Beller

We allocate a `struct refspec_item` on the stack without initializing
it. In particular, its `dst` and `src` members will contain some random
data from the stack. When we later call `refspec_item_clear()`, it will
call `free()` on those pointers. So if the call to `parse_refspec()` did
not assign to them, we will be freeing some random "pointers". This is
undefined behavior.

To the best of my understanding, this cannot currently be triggered by
user-provided data. And for what it's worth, the test-suite does not
trigger this with SANITIZE=address. It can be provoked by calling
`valid_fetch_refspec(":*")`.

Zero the struct, as is done in other users of `struct refspec_item`.

Signed-off-by: Martin Ågren <martin.agren@gmail.com>
---
I found some time to look into this. It does not seem to be a
user-visible bug, so not particularly critical.

 refspec.c | 5 ++++-
 1 file changed, 4 insertions(+), 1 deletion(-)

diff --git a/refspec.c b/refspec.c
index ada7854f7a..7dd7e361e5 100644
--- a/refspec.c
+++ b/refspec.c
@@ -189,7 +189,10 @@ void refspec_clear(struct refspec *rs)
 int valid_fetch_refspec(const char *fetch_refspec_str)
 {
 	struct refspec_item refspec;
-	int ret = parse_refspec(&refspec, fetch_refspec_str, REFSPEC_FETCH);
+	int ret;
+
+	memset(&refspec, 0, sizeof(refspec));
+	ret = parse_refspec(&refspec, fetch_refspec_str, REFSPEC_FETCH);
 	refspec_item_clear(&refspec);
 	return ret;
 }
-- 
2.18.0.rc0.43.gb85e7bcbff


^ permalink raw reply related	[flat|nested] 112+ messages in thread

* Re: [PATCH] refspec: initalize `refspec_item` in `valid_fetch_refspec()`
  2018-06-04 14:43       ` [PATCH] refspec: initalize `refspec_item` in `valid_fetch_refspec()` Martin Ågren
@ 2018-06-04 17:36         ` Brandon Williams
  2018-06-04 21:55         ` Ævar Arnfjörð Bjarmason
  1 sibling, 0 replies; 112+ messages in thread
From: Brandon Williams @ 2018-06-04 17:36 UTC (permalink / raw)
  To: Martin Ågren
  Cc: git, Ævar Arnfjörð Bjarmason, Junio C Hamano,
	Stefan Beller

On 06/04, Martin Ågren wrote:
> We allocate a `struct refspec_item` on the stack without initializing
> it. In particular, its `dst` and `src` members will contain some random
> data from the stack. When we later call `refspec_item_clear()`, it will
> call `free()` on those pointers. So if the call to `parse_refspec()` did
> not assign to them, we will be freeing some random "pointers". This is
> undefined behavior.
> 
> To the best of my understanding, this cannot currently be triggered by
> user-provided data. And for what it's worth, the test-suite does not
> trigger this with SANITIZE=address. It can be provoked by calling
> `valid_fetch_refspec(":*")`.
> 
> Zero the struct, as is done in other users of `struct refspec_item`.
> 
> Signed-off-by: Martin Ågren <martin.agren@gmail.com>
> ---
> I found some time to look into this. It does not seem to be a
> user-visible bug, so not particularly critical.

Thanks for fixing this.  I don't think I noticed this because at some
point in developing this series I had a memset call in parse_refspec.
I don't remember why I ended up removing it, but maybe it would have
been better to leave it in there.

> 
>  refspec.c | 5 ++++-
>  1 file changed, 4 insertions(+), 1 deletion(-)
> 
> diff --git a/refspec.c b/refspec.c
> index ada7854f7a..7dd7e361e5 100644
> --- a/refspec.c
> +++ b/refspec.c
> @@ -189,7 +189,10 @@ void refspec_clear(struct refspec *rs)
>  int valid_fetch_refspec(const char *fetch_refspec_str)
>  {
>  	struct refspec_item refspec;
> -	int ret = parse_refspec(&refspec, fetch_refspec_str, REFSPEC_FETCH);
> +	int ret;
> +
> +	memset(&refspec, 0, sizeof(refspec));
> +	ret = parse_refspec(&refspec, fetch_refspec_str, REFSPEC_FETCH);
>  	refspec_item_clear(&refspec);
>  	return ret;
>  }
> -- 
> 2.18.0.rc0.43.gb85e7bcbff
> 

-- 
Brandon Williams

^ permalink raw reply	[flat|nested] 112+ messages in thread

* Re: [PATCH] refspec: initalize `refspec_item` in `valid_fetch_refspec()`
  2018-06-04 14:43       ` [PATCH] refspec: initalize `refspec_item` in `valid_fetch_refspec()` Martin Ågren
  2018-06-04 17:36         ` Brandon Williams
@ 2018-06-04 21:55         ` Ævar Arnfjörð Bjarmason
  2018-06-05  5:10           ` Martin Ågren
  2018-06-05 16:29           ` Brandon Williams
  1 sibling, 2 replies; 112+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2018-06-04 21:55 UTC (permalink / raw)
  To: Martin Ågren; +Cc: git, Brandon Williams, Junio C Hamano, Stefan Beller


On Mon, Jun 04 2018, Martin Ågren wrote:

> We allocate a `struct refspec_item` on the stack without initializing
> it. In particular, its `dst` and `src` members will contain some random
> data from the stack. When we later call `refspec_item_clear()`, it will
> call `free()` on those pointers. So if the call to `parse_refspec()` did
> not assign to them, we will be freeing some random "pointers". This is
> undefined behavior.
>
> To the best of my understanding, this cannot currently be triggered by
> user-provided data. And for what it's worth, the test-suite does not
> trigger this with SANITIZE=address. It can be provoked by calling
> `valid_fetch_refspec(":*")`.
>
> Zero the struct, as is done in other users of `struct refspec_item`.
>
> Signed-off-by: Martin Ågren <martin.agren@gmail.com>
> ---
> I found some time to look into this. It does not seem to be a
> user-visible bug, so not particularly critical.
>
>  refspec.c | 5 ++++-
>  1 file changed, 4 insertions(+), 1 deletion(-)
>
> diff --git a/refspec.c b/refspec.c
> index ada7854f7a..7dd7e361e5 100644
> --- a/refspec.c
> +++ b/refspec.c
> @@ -189,7 +189,10 @@ void refspec_clear(struct refspec *rs)
>  int valid_fetch_refspec(const char *fetch_refspec_str)
>  {
>  	struct refspec_item refspec;
> -	int ret = parse_refspec(&refspec, fetch_refspec_str, REFSPEC_FETCH);
> +	int ret;
> +
> +	memset(&refspec, 0, sizeof(refspec));
> +	ret = parse_refspec(&refspec, fetch_refspec_str, REFSPEC_FETCH);
>  	refspec_item_clear(&refspec);
>  	return ret;
>  }

I think this makes more sense instead of this fix:

diff --git a/builtin/clone.c b/builtin/clone.c
index 99e73dae85..74a804f2e8 100644
--- a/builtin/clone.c
+++ b/builtin/clone.c
@@ -1077,7 +1077,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
 	if (option_required_reference.nr || option_optional_reference.nr)
 		setup_reference();

-	refspec_item_init(&refspec, value.buf, REFSPEC_FETCH);
+	refspec_item_init_or_die(&refspec, value.buf, REFSPEC_FETCH);

 	strbuf_reset(&value);

diff --git a/builtin/pull.c b/builtin/pull.c
index 1f2ecf3a88..bb64631d98 100644
--- a/builtin/pull.c
+++ b/builtin/pull.c
@@ -684,7 +684,7 @@ static const char *get_tracking_branch(const char *remote, const char *refspec)
 	const char *spec_src;
 	const char *merge_branch;

-	refspec_item_init(&spec, refspec, REFSPEC_FETCH);
+	refspec_item_init_or_die(&spec, refspec, REFSPEC_FETCH);
 	spec_src = spec.src;
 	if (!*spec_src || !strcmp(spec_src, "HEAD"))
 		spec_src = "HEAD";
diff --git a/refspec.c b/refspec.c
index 78edc48ae8..8806df0fd2 100644
--- a/refspec.c
+++ b/refspec.c
@@ -124,11 +124,16 @@ static int parse_refspec(struct refspec_item *item, const char *refspec, int fet
 	return 1;
 }

-void refspec_item_init(struct refspec_item *item, const char *refspec, int fetch)
+int refspec_item_init(struct refspec_item *item, const char *refspec, int fetch)
 {
 	memset(item, 0, sizeof(*item));
+	int ret = parse_refspec(item, refspec, fetch);
+	return ret;
+}

-	if (!parse_refspec(item, refspec, fetch))
+void refspec_item_init_or_die(struct refspec_item *item, const char *refspec, int fetch)
+{
+	if (!refspec_item_init(item, refspec, fetch))
 		die("Invalid refspec '%s'", refspec);
 }

@@ -152,7 +157,7 @@ void refspec_append(struct refspec *rs, const char *refspec)
 {
 	struct refspec_item item;

-	refspec_item_init(&item, refspec, rs->fetch);
+	refspec_item_init_or_die(&item, refspec, rs->fetch);

 	ALLOC_GROW(rs->items, rs->nr + 1, rs->alloc);
 	rs->items[rs->nr++] = item;
@@ -191,7 +196,7 @@ void refspec_clear(struct refspec *rs)
 int valid_fetch_refspec(const char *fetch_refspec_str)
 {
 	struct refspec_item refspec;
-	int ret = parse_refspec(&refspec, fetch_refspec_str, REFSPEC_FETCH);
+	int ret = refspec_item_init(&refspec, fetch_refspec_str, REFSPEC_FETCH);
 	refspec_item_clear(&refspec);
 	return ret;
 }
diff --git a/refspec.h b/refspec.h
index 3a9363887c..ed5d997f7f 100644
--- a/refspec.h
+++ b/refspec.h
@@ -32,7 +32,8 @@ struct refspec {
 	int fetch;
 };

-void refspec_item_init(struct refspec_item *item, const char *refspec, int fetch);
+int refspec_item_init(struct refspec_item *item, const char *refspec, int fetch);
+void refspec_item_init_or_die(struct refspec_item *item, const char *refspec, int fetch);
 void refspec_item_clear(struct refspec_item *item);
 void refspec_init(struct refspec *rs, int fetch);
 void refspec_append(struct refspec *rs, const char *refspec);

I.e. let's fix the bug, but with this admittedly more verbose fix we're
left with exactly two memset() in refspec.c, one for each type of struct
that's initialized by the API.

The reason this is difficult now is because the current API conflates
the init function with an init_or_die, which is what most callers want,
so let's just split those concerns up. Then we're left with one init
function that does the memset.

^ permalink raw reply related	[flat|nested] 112+ messages in thread

* Re: [PATCH] refspec: initalize `refspec_item` in `valid_fetch_refspec()`
  2018-06-04 21:55         ` Ævar Arnfjörð Bjarmason
@ 2018-06-05  5:10           ` Martin Ågren
  2018-06-05 16:29           ` Brandon Williams
  1 sibling, 0 replies; 112+ messages in thread
From: Martin Ågren @ 2018-06-05  5:10 UTC (permalink / raw)
  To: Ævar Arnfjörð Bjarmason
  Cc: Git Mailing List, Brandon Williams, Junio C Hamano, Stefan Beller

On 4 June 2018 at 23:55, Ævar Arnfjörð Bjarmason <avarab@gmail.com> wrote:

> I think this makes more sense instead of this fix:
[...]
> -void refspec_item_init(struct refspec_item *item, const char *refspec, int fetch)
> +int refspec_item_init(struct refspec_item *item, const char *refspec, int fetch)
>  {
>         memset(item, 0, sizeof(*item));
> +       int ret = parse_refspec(item, refspec, fetch);
> +       return ret;
> +}

Nit: Declaration after statement. Intriguingly, you do use a `ret`
variable, so I suspect you sort of thought about it but left the final
cleaning up for later. ;-)

> -void refspec_item_init(struct refspec_item *item, const char *refspec, int fetch);
> +int refspec_item_init(struct refspec_item *item, const char *refspec, int fetch);
> +void refspec_item_init_or_die(struct refspec_item *item, const char *refspec, int fetch);
>  void refspec_item_clear(struct refspec_item *item);
>  void refspec_init(struct refspec *rs, int fetch);
>  void refspec_append(struct refspec *rs, const char *refspec);
>
> I.e. let's fix the bug, but with this admittedly more verbose fix we're
> left with exactly two memset() in refspec.c, one for each type of struct
> that's initialized by the API.
>
> The reason this is difficult now is because the current API conflates
> the init function with an init_or_die, which is what most callers want,
> so let's just split those concerns up. Then we're left with one init
> function that does the memset.

I didn't test this, but it looks sane in general IMHO, and should fix
the issue I saw. Should we be worried that someone might already depend
on `refspec_item_init()` to die, and we'll silently break that
assumption?

Martin

^ permalink raw reply	[flat|nested] 112+ messages in thread

* Re: [PATCH] refspec: initalize `refspec_item` in `valid_fetch_refspec()`
  2018-06-04 21:55         ` Ævar Arnfjörð Bjarmason
  2018-06-05  5:10           ` Martin Ågren
@ 2018-06-05 16:29           ` Brandon Williams
  2018-06-05 19:54             ` [PATCH 0/3] refspec: refactor & fix free() behavior Ævar Arnfjörð Bjarmason
                               ` (3 more replies)
  1 sibling, 4 replies; 112+ messages in thread
From: Brandon Williams @ 2018-06-05 16:29 UTC (permalink / raw)
  To: Ævar Arnfjörð Bjarmason
  Cc: Martin Ågren, git, Junio C Hamano, Stefan Beller

On 06/04, Ævar Arnfjörð Bjarmason wrote:
> 
> On Mon, Jun 04 2018, Martin Ågren wrote:
> 
> > We allocate a `struct refspec_item` on the stack without initializing
> > it. In particular, its `dst` and `src` members will contain some random
> > data from the stack. When we later call `refspec_item_clear()`, it will
> > call `free()` on those pointers. So if the call to `parse_refspec()` did
> > not assign to them, we will be freeing some random "pointers". This is
> > undefined behavior.
> >
> > To the best of my understanding, this cannot currently be triggered by
> > user-provided data. And for what it's worth, the test-suite does not
> > trigger this with SANITIZE=address. It can be provoked by calling
> > `valid_fetch_refspec(":*")`.
> >
> > Zero the struct, as is done in other users of `struct refspec_item`.
> >
> > Signed-off-by: Martin Ågren <martin.agren@gmail.com>
> > ---
> > I found some time to look into this. It does not seem to be a
> > user-visible bug, so not particularly critical.
> >
> >  refspec.c | 5 ++++-
> >  1 file changed, 4 insertions(+), 1 deletion(-)
> >
> > diff --git a/refspec.c b/refspec.c
> > index ada7854f7a..7dd7e361e5 100644
> > --- a/refspec.c
> > +++ b/refspec.c
> > @@ -189,7 +189,10 @@ void refspec_clear(struct refspec *rs)
> >  int valid_fetch_refspec(const char *fetch_refspec_str)
> >  {
> >  	struct refspec_item refspec;
> > -	int ret = parse_refspec(&refspec, fetch_refspec_str, REFSPEC_FETCH);
> > +	int ret;
> > +
> > +	memset(&refspec, 0, sizeof(refspec));
> > +	ret = parse_refspec(&refspec, fetch_refspec_str, REFSPEC_FETCH);
> >  	refspec_item_clear(&refspec);
> >  	return ret;
> >  }
> 
> I think this makes more sense instead of this fix:

I like this diff.  The only nit I have is the same as what Martin
pointed out.  At least this way all memory will be initialized by the
time a call to parse_refspec is made.

> 
> diff --git a/builtin/clone.c b/builtin/clone.c
> index 99e73dae85..74a804f2e8 100644
> --- a/builtin/clone.c
> +++ b/builtin/clone.c
> @@ -1077,7 +1077,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
>  	if (option_required_reference.nr || option_optional_reference.nr)
>  		setup_reference();
> 
> -	refspec_item_init(&refspec, value.buf, REFSPEC_FETCH);
> +	refspec_item_init_or_die(&refspec, value.buf, REFSPEC_FETCH);
> 
>  	strbuf_reset(&value);
> 
> diff --git a/builtin/pull.c b/builtin/pull.c
> index 1f2ecf3a88..bb64631d98 100644
> --- a/builtin/pull.c
> +++ b/builtin/pull.c
> @@ -684,7 +684,7 @@ static const char *get_tracking_branch(const char *remote, const char *refspec)
>  	const char *spec_src;
>  	const char *merge_branch;
> 
> -	refspec_item_init(&spec, refspec, REFSPEC_FETCH);
> +	refspec_item_init_or_die(&spec, refspec, REFSPEC_FETCH);
>  	spec_src = spec.src;
>  	if (!*spec_src || !strcmp(spec_src, "HEAD"))
>  		spec_src = "HEAD";
> diff --git a/refspec.c b/refspec.c
> index 78edc48ae8..8806df0fd2 100644
> --- a/refspec.c
> +++ b/refspec.c
> @@ -124,11 +124,16 @@ static int parse_refspec(struct refspec_item *item, const char *refspec, int fet
>  	return 1;
>  }
> 
> -void refspec_item_init(struct refspec_item *item, const char *refspec, int fetch)
> +int refspec_item_init(struct refspec_item *item, const char *refspec, int fetch)
>  {
>  	memset(item, 0, sizeof(*item));
> +	int ret = parse_refspec(item, refspec, fetch);
> +	return ret;
> +}
> 
> -	if (!parse_refspec(item, refspec, fetch))
> +void refspec_item_init_or_die(struct refspec_item *item, const char *refspec, int fetch)
> +{
> +	if (!refspec_item_init(item, refspec, fetch))
>  		die("Invalid refspec '%s'", refspec);
>  }
> 
> @@ -152,7 +157,7 @@ void refspec_append(struct refspec *rs, const char *refspec)
>  {
>  	struct refspec_item item;
> 
> -	refspec_item_init(&item, refspec, rs->fetch);
> +	refspec_item_init_or_die(&item, refspec, rs->fetch);
> 
>  	ALLOC_GROW(rs->items, rs->nr + 1, rs->alloc);
>  	rs->items[rs->nr++] = item;
> @@ -191,7 +196,7 @@ void refspec_clear(struct refspec *rs)
>  int valid_fetch_refspec(const char *fetch_refspec_str)
>  {
>  	struct refspec_item refspec;
> -	int ret = parse_refspec(&refspec, fetch_refspec_str, REFSPEC_FETCH);
> +	int ret = refspec_item_init(&refspec, fetch_refspec_str, REFSPEC_FETCH);
>  	refspec_item_clear(&refspec);
>  	return ret;
>  }
> diff --git a/refspec.h b/refspec.h
> index 3a9363887c..ed5d997f7f 100644
> --- a/refspec.h
> +++ b/refspec.h
> @@ -32,7 +32,8 @@ struct refspec {
>  	int fetch;
>  };
> 
> -void refspec_item_init(struct refspec_item *item, const char *refspec, int fetch);
> +int refspec_item_init(struct refspec_item *item, const char *refspec, int fetch);
> +void refspec_item_init_or_die(struct refspec_item *item, const char *refspec, int fetch);
>  void refspec_item_clear(struct refspec_item *item);
>  void refspec_init(struct refspec *rs, int fetch);
>  void refspec_append(struct refspec *rs, const char *refspec);
> 
> I.e. let's fix the bug, but with this admittedly more verbose fix we're
> left with exactly two memset() in refspec.c, one for each type of struct
> that's initialized by the API.
> 
> The reason this is difficult now is because the current API conflates
> the init function with an init_or_die, which is what most callers want,
> so let's just split those concerns up. Then we're left with one init
> function that does the memset.

-- 
Brandon Williams

^ permalink raw reply	[flat|nested] 112+ messages in thread

* [PATCH 0/3] refspec: refactor & fix free() behavior
  2018-06-05 16:29           ` Brandon Williams
@ 2018-06-05 19:54             ` Ævar Arnfjörð Bjarmason
  2018-06-05 19:58               ` Brandon Williams
  2018-06-05 19:54             ` [PATCH 1/3] refspec: s/refspec_item_init/&_or_die/g Ævar Arnfjörð Bjarmason
                               ` (2 subsequent siblings)
  3 siblings, 1 reply; 112+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2018-06-05 19:54 UTC (permalink / raw)
  To: git
  Cc: Junio C Hamano, Martin Ågren, Brandon Williams,
	Stefan Beller, Ævar Arnfjörð Bjarmason

Since Martin & Brandon both liked this direction I've fixed it
up.

Martin: I didn't want to be the author of the actual fix for the bug
you found, so I rewrote your commit in 3/3. The diff is different, and
I slightly modified the 3rd paragraph of the commit message & added my
sign-off, but otherwise it's the same.

Martin Ågren (1):
  refspec: initalize `refspec_item` in `valid_fetch_refspec()`

Ævar Arnfjörð Bjarmason (2):
  refspec: s/refspec_item_init/&_or_die/g
  refspec: add back a refspec_item_init() function

 builtin/clone.c |  2 +-
 builtin/pull.c  |  2 +-
 refspec.c       | 13 +++++++++----
 refspec.h       |  5 ++++-
 4 files changed, 15 insertions(+), 7 deletions(-)

-- 
2.17.0.290.gded63e768a


^ permalink raw reply	[flat|nested] 112+ messages in thread

* [PATCH 1/3] refspec: s/refspec_item_init/&_or_die/g
  2018-06-05 16:29           ` Brandon Williams
  2018-06-05 19:54             ` [PATCH 0/3] refspec: refactor & fix free() behavior Ævar Arnfjörð Bjarmason
@ 2018-06-05 19:54             ` Ævar Arnfjörð Bjarmason
  2018-06-05 19:54             ` [PATCH 2/3] refspec: add back a refspec_item_init() function Ævar Arnfjörð Bjarmason
  2018-06-05 19:54             ` [PATCH 3/3] refspec: initalize `refspec_item` in `valid_fetch_refspec()` Ævar Arnfjörð Bjarmason
  3 siblings, 0 replies; 112+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2018-06-05 19:54 UTC (permalink / raw)
  To: git
  Cc: Junio C Hamano, Martin Ågren, Brandon Williams,
	Stefan Beller, Ævar Arnfjörð Bjarmason

Rename the refspec_item_init() function introduced in
6d4c057859 ("refspec: introduce struct refspec", 2018-05-16) to
refspec_item_init_or_die().

This follows the convention of other *_or_die() functions, and is done
in preparation for making it a wrapper for a non-fatal variant.

Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
 builtin/clone.c | 2 +-
 builtin/pull.c  | 2 +-
 refspec.c       | 5 +++--
 refspec.h       | 3 ++-
 4 files changed, 7 insertions(+), 5 deletions(-)

diff --git a/builtin/clone.c b/builtin/clone.c
index 99e73dae85..74a804f2e8 100644
--- a/builtin/clone.c
+++ b/builtin/clone.c
@@ -1077,7 +1077,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
 	if (option_required_reference.nr || option_optional_reference.nr)
 		setup_reference();
 
-	refspec_item_init(&refspec, value.buf, REFSPEC_FETCH);
+	refspec_item_init_or_die(&refspec, value.buf, REFSPEC_FETCH);
 
 	strbuf_reset(&value);
 
diff --git a/builtin/pull.c b/builtin/pull.c
index 1f2ecf3a88..bb64631d98 100644
--- a/builtin/pull.c
+++ b/builtin/pull.c
@@ -684,7 +684,7 @@ static const char *get_tracking_branch(const char *remote, const char *refspec)
 	const char *spec_src;
 	const char *merge_branch;
 
-	refspec_item_init(&spec, refspec, REFSPEC_FETCH);
+	refspec_item_init_or_die(&spec, refspec, REFSPEC_FETCH);
 	spec_src = spec.src;
 	if (!*spec_src || !strcmp(spec_src, "HEAD"))
 		spec_src = "HEAD";
diff --git a/refspec.c b/refspec.c
index 78edc48ae8..0fd392e96b 100644
--- a/refspec.c
+++ b/refspec.c
@@ -124,7 +124,8 @@ static int parse_refspec(struct refspec_item *item, const char *refspec, int fet
 	return 1;
 }
 
-void refspec_item_init(struct refspec_item *item, const char *refspec, int fetch)
+void refspec_item_init_or_die(struct refspec_item *item, const char *refspec,
+			      int fetch)
 {
 	memset(item, 0, sizeof(*item));
 
@@ -152,7 +153,7 @@ void refspec_append(struct refspec *rs, const char *refspec)
 {
 	struct refspec_item item;
 
-	refspec_item_init(&item, refspec, rs->fetch);
+	refspec_item_init_or_die(&item, refspec, rs->fetch);
 
 	ALLOC_GROW(rs->items, rs->nr + 1, rs->alloc);
 	rs->items[rs->nr++] = item;
diff --git a/refspec.h b/refspec.h
index 3a9363887c..4caaf1f8e3 100644
--- a/refspec.h
+++ b/refspec.h
@@ -32,7 +32,8 @@ struct refspec {
 	int fetch;
 };
 
-void refspec_item_init(struct refspec_item *item, const char *refspec, int fetch);
+void refspec_item_init_or_die(struct refspec_item *item, const char *refspec,
+			      int fetch);
 void refspec_item_clear(struct refspec_item *item);
 void refspec_init(struct refspec *rs, int fetch);
 void refspec_append(struct refspec *rs, const char *refspec);
-- 
2.17.0.290.gded63e768a


^ permalink raw reply related	[flat|nested] 112+ messages in thread

* [PATCH 2/3] refspec: add back a refspec_item_init() function
  2018-06-05 16:29           ` Brandon Williams
  2018-06-05 19:54             ` [PATCH 0/3] refspec: refactor & fix free() behavior Ævar Arnfjörð Bjarmason
  2018-06-05 19:54             ` [PATCH 1/3] refspec: s/refspec_item_init/&_or_die/g Ævar Arnfjörð Bjarmason
@ 2018-06-05 19:54             ` Ævar Arnfjörð Bjarmason
  2018-06-05 19:54             ` [PATCH 3/3] refspec: initalize `refspec_item` in `valid_fetch_refspec()` Ævar Arnfjörð Bjarmason
  3 siblings, 0 replies; 112+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2018-06-05 19:54 UTC (permalink / raw)
  To: git
  Cc: Junio C Hamano, Martin Ågren, Brandon Williams,
	Stefan Beller, Ævar Arnfjörð Bjarmason

Re-add the non-fatal version of refspec_item_init_or_die() renamed
away in an earlier change to get a more minimal diff. This should be
used by callers that have their own error handling.

This new function could be marked "static" since nothing outside of
refspec.c uses it, but expecting future use of it, let's make it
available to other users.

Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
 refspec.c | 10 +++++++---
 refspec.h |  2 ++
 2 files changed, 9 insertions(+), 3 deletions(-)

diff --git a/refspec.c b/refspec.c
index 0fd392e96b..a35493e35e 100644
--- a/refspec.c
+++ b/refspec.c
@@ -124,12 +124,16 @@ static int parse_refspec(struct refspec_item *item, const char *refspec, int fet
 	return 1;
 }
 
-void refspec_item_init_or_die(struct refspec_item *item, const char *refspec,
-			      int fetch)
+int refspec_item_init(struct refspec_item *item, const char *refspec, int fetch)
 {
 	memset(item, 0, sizeof(*item));
+	return parse_refspec(item, refspec, fetch);
+}
 
-	if (!parse_refspec(item, refspec, fetch))
+void refspec_item_init_or_die(struct refspec_item *item, const char *refspec,
+			      int fetch)
+{
+	if (!refspec_item_init(item, refspec, fetch))
 		die("Invalid refspec '%s'", refspec);
 }
 
diff --git a/refspec.h b/refspec.h
index 4caaf1f8e3..9b6e64a824 100644
--- a/refspec.h
+++ b/refspec.h
@@ -32,6 +32,8 @@ struct refspec {
 	int fetch;
 };
 
+int refspec_item_init(struct refspec_item *item, const char *refspec,
+		      int fetch);
 void refspec_item_init_or_die(struct refspec_item *item, const char *refspec,
 			      int fetch);
 void refspec_item_clear(struct refspec_item *item);
-- 
2.17.0.290.gded63e768a


^ permalink raw reply related	[flat|nested] 112+ messages in thread

* [PATCH 3/3] refspec: initalize `refspec_item` in `valid_fetch_refspec()`
  2018-06-05 16:29           ` Brandon Williams
                               ` (2 preceding siblings ...)
  2018-06-05 19:54             ` [PATCH 2/3] refspec: add back a refspec_item_init() function Ævar Arnfjörð Bjarmason
@ 2018-06-05 19:54             ` Ævar Arnfjörð Bjarmason
  3 siblings, 0 replies; 112+ messages in thread
From: Ævar Arnfjörð Bjarmason @ 2018-06-05 19:54 UTC (permalink / raw)
  To: git
  Cc: Junio C Hamano, Martin Ågren, Brandon Williams,
	Stefan Beller, Ævar Arnfjörð Bjarmason

From: Martin Ågren <martin.agren@gmail.com>

We allocate a `struct refspec_item` on the stack without initializing
it. In particular, its `dst` and `src` members will contain some random
data from the stack. When we later call `refspec_item_clear()`, it will
call `free()` on those pointers. So if the call to `parse_refspec()` did
not assign to them, we will be freeing some random "pointers". This is
undefined behavior.

To the best of my understanding, this cannot currently be triggered by
user-provided data. And for what it's worth, the test-suite does not
trigger this with SANITIZE=address. It can be provoked by calling
`valid_fetch_refspec(":*")`.

Zero the struct, as is done in other users of `struct refspec_item` by
using the refspec_item_init() initialization function.

Signed-off-by: Martin Ågren <martin.agren@gmail.com>
Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>
---
 refspec.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/refspec.c b/refspec.c
index a35493e35e..e8010dce0c 100644
--- a/refspec.c
+++ b/refspec.c
@@ -196,7 +196,7 @@ void refspec_clear(struct refspec *rs)
 int valid_fetch_refspec(const char *fetch_refspec_str)
 {
 	struct refspec_item refspec;
-	int ret = parse_refspec(&refspec, fetch_refspec_str, REFSPEC_FETCH);
+	int ret = refspec_item_init(&refspec, fetch_refspec_str, REFSPEC_FETCH);
 	refspec_item_clear(&refspec);
 	return ret;
 }
-- 
2.17.0.290.gded63e768a


^ permalink raw reply related	[flat|nested] 112+ messages in thread

* Re: [PATCH 0/3] refspec: refactor & fix free() behavior
  2018-06-05 19:54             ` [PATCH 0/3] refspec: refactor & fix free() behavior Ævar Arnfjörð Bjarmason
@ 2018-06-05 19:58               ` Brandon Williams
  2018-06-05 20:20                 ` Martin Ågren
  0 siblings, 1 reply; 112+ messages in thread
From: Brandon Williams @ 2018-06-05 19:58 UTC (permalink / raw)
  To: Ævar Arnfjörð Bjarmason
  Cc: git, Junio C Hamano, Martin Ågren, Stefan Beller

On 06/05, Ævar Arnfjörð Bjarmason wrote:
> Since Martin & Brandon both liked this direction I've fixed it
> up.
> 
> Martin: I didn't want to be the author of the actual fix for the bug
> you found, so I rewrote your commit in 3/3. The diff is different, and
> I slightly modified the 3rd paragraph of the commit message & added my
> sign-off, but otherwise it's the same.

Thanks for writing up a proper patch series for this fix.  I liked
breaking up your diff into two different patches to make it clear that
all callers of refpsec_item_init relying on dieing.

> 
> Martin Ågren (1):
>   refspec: initalize `refspec_item` in `valid_fetch_refspec()`
> 
> Ævar Arnfjörð Bjarmason (2):
>   refspec: s/refspec_item_init/&_or_die/g
>   refspec: add back a refspec_item_init() function
> 
>  builtin/clone.c |  2 +-
>  builtin/pull.c  |  2 +-
>  refspec.c       | 13 +++++++++----
>  refspec.h       |  5 ++++-
>  4 files changed, 15 insertions(+), 7 deletions(-)
> 
> -- 
> 2.17.0.290.gded63e768a
> 

-- 
Brandon Williams

^ permalink raw reply	[flat|nested] 112+ messages in thread

* Re: [PATCH 0/3] refspec: refactor & fix free() behavior
  2018-06-05 19:58               ` Brandon Williams
@ 2018-06-05 20:20                 ` Martin Ågren
  0 siblings, 0 replies; 112+ messages in thread
From: Martin Ågren @ 2018-06-05 20:20 UTC (permalink / raw)
  To: Brandon Williams
  Cc: Ævar Arnfjörð Bjarmason, Git Mailing List,
	Junio C Hamano, Stefan Beller

On 5 June 2018 at 21:58, Brandon Williams <bmwill@google.com> wrote:
> On 06/05, Ævar Arnfjörð Bjarmason wrote:
>> Since Martin & Brandon both liked this direction I've fixed it
>> up.
>>
>> Martin: I didn't want to be the author of the actual fix for the bug
>> you found, so I rewrote your commit in 3/3. The diff is different, and
>> I slightly modified the 3rd paragraph of the commit message & added my
>> sign-off, but otherwise it's the same.
>
> Thanks for writing up a proper patch series for this fix.  I liked
> breaking up your diff into two different patches to make it clear that
> all callers of refpsec_item_init relying on dieing.

Me too.

>> Martin Ågren (1):
>>   refspec: initalize `refspec_item` in `valid_fetch_refspec()`

I was a bit surprised at first that this wasn't a "while at it" in the
second patch, but on second thought, it does make sense to keep this
separate. Thanks for picking this up and polishing it.

Just noticed: s/initalize/initialize/. That would be my fault...

Martin

^ permalink raw reply	[flat|nested] 112+ messages in thread

end of thread, other threads:[~2018-06-05 20:20 UTC | newest]

Thread overview: 112+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-05-14 21:55 [PATCH 00/35] refactoring refspecs Brandon Williams
2018-05-14 21:55 ` [PATCH 01/35] refspec: move refspec parsing logic into its own file Brandon Williams
2018-05-15  8:06   ` Junio C Hamano
2018-05-15 16:51     ` Brandon Williams
2018-05-16  0:40       ` Junio C Hamano
2018-05-14 21:55 ` [PATCH 02/35] refspec: factor out parsing a single refspec Brandon Williams
2018-05-14 21:55 ` [PATCH 03/35] refspec: rename struct refspec to struct refspec_item Brandon Williams
2018-05-15  8:17   ` Junio C Hamano
2018-05-15 18:19     ` Brandon Williams
2018-05-14 21:55 ` [PATCH 04/35] refspec: introduce struct refspec Brandon Williams
2018-05-15  9:37   ` Junio C Hamano
2018-05-15 18:37     ` Brandon Williams
2018-05-14 21:55 ` [PATCH 05/35] refspec: convert valid_fetch_refspec to use parse_refspec Brandon Williams
2018-05-15  9:41   ` Junio C Hamano
2018-05-14 21:55 ` [PATCH 06/35] submodule--helper: convert push_check to use struct refspec Brandon Williams
2018-05-14 21:55 ` [PATCH 07/35] pull: convert get_tracking_branch to use refspec_item_init Brandon Williams
2018-05-14 21:55 ` [PATCH 08/35] transport: convert transport_push to use struct refspec Brandon Williams
2018-05-14 21:56 ` [PATCH 09/35] remote: convert check_push_refs " Brandon Williams
2018-05-14 21:56 ` [PATCH 10/35] remote: convert match_push_refs " Brandon Williams
2018-05-14 21:56 ` [PATCH 11/35] clone: convert cmd_clone to use refspec_item_init Brandon Williams
2018-05-14 21:56 ` [PATCH 12/35] fast-export: convert to use struct refspec Brandon Williams
2018-05-14 21:56 ` [PATCH 13/35] remote: convert push refspecs to " Brandon Williams
2018-05-14 21:56 ` [PATCH 14/35] remote: convert fetch " Brandon Williams
2018-05-15  8:31   ` Ævar Arnfjörð Bjarmason
2018-05-15 17:57     ` Brandon Williams
2018-05-14 21:56 ` [PATCH 15/35] transport-helper: convert to use " Brandon Williams
2018-05-14 21:56 ` [PATCH 16/35] fetch: convert fetch_one " Brandon Williams
2018-05-14 21:56 ` [PATCH 17/35] fetch: convert refmap " Brandon Williams
2018-05-14 21:56 ` [PATCH 18/35] refspec: remove the deprecated functions Brandon Williams
2018-05-14 21:56 ` [PATCH 19/35] fetch: convert do_fetch to take a struct refspec Brandon Williams
2018-05-14 21:56 ` [PATCH 20/35] fetch: convert get_ref_map " Brandon Williams
2018-05-14 21:56 ` [PATCH 21/35] fetch: convert prune_refs " Brandon Williams
2018-05-14 21:56 ` [PATCH 22/35] remote: convert get_stale_heads " Brandon Williams
2018-05-14 21:56 ` [PATCH 23/35] remote: convert apply_refspecs " Brandon Williams
2018-05-14 21:56 ` [PATCH 24/35] remote: convert query_refspecs " Brandon Williams
2018-05-14 21:56 ` [PATCH 25/35] remote: convert get_ref_match " Brandon Williams
2018-05-14 21:56 ` [PATCH 26/35] remote: convert match_explicit_refs " Brandon Williams
2018-05-14 21:56 ` [PATCH 27/35] push: check for errors earlier Brandon Williams
2018-05-14 21:56 ` [PATCH 28/35] push: convert to use struct refspec Brandon Williams
2018-05-14 21:56 ` [PATCH 29/35] transport: convert transport_push to take a " Brandon Williams
2018-05-14 21:56 ` [PATCH 30/35] send-pack: store refspecs in " Brandon Williams
2018-05-14 21:56 ` [PATCH 31/35] transport: remove transport_verify_remote_names Brandon Williams
2018-05-14 21:56 ` [PATCH 32/35] http-push: store refspecs in a struct refspec Brandon Williams
2018-05-14 21:56 ` [PATCH 33/35] remote: convert match_push_refs to take " Brandon Williams
2018-05-14 21:56 ` [PATCH 34/35] remote: convert check_push_refs " Brandon Williams
2018-05-14 21:56 ` [PATCH 35/35] submodule: convert push_unpushed_submodules " Brandon Williams
2018-05-15  8:11   ` Ævar Arnfjörð Bjarmason
2018-05-15 16:52     ` Stefan Beller
2018-05-15 16:59     ` Brandon Williams
2018-05-14 23:08 ` [PATCH 00/35] refactoring refspecs Stefan Beller
2018-05-15  8:05 ` Junio C Hamano
2018-05-15  8:39 ` Ævar Arnfjörð Bjarmason
2018-05-15 18:01   ` Brandon Williams
2018-05-16 22:57 ` [PATCH v2 00/36] " Brandon Williams
2018-05-16 22:57   ` [PATCH v2 01/36] refspec: move refspec parsing logic into its own file Brandon Williams
2018-05-16 22:57   ` [PATCH v2 02/36] refspec: rename struct refspec to struct refspec_item Brandon Williams
2018-05-16 22:57   ` [PATCH v2 03/36] refspec: factor out parsing a single refspec Brandon Williams
2018-05-16 22:57   ` [PATCH v2 04/36] refspec: introduce struct refspec Brandon Williams
2018-05-16 22:57   ` [PATCH v2 05/36] refspec: convert valid_fetch_refspec to use parse_refspec Brandon Williams
2018-06-03 17:13     ` Martin Ågren
2018-06-04 14:43       ` [PATCH] refspec: initalize `refspec_item` in `valid_fetch_refspec()` Martin Ågren
2018-06-04 17:36         ` Brandon Williams
2018-06-04 21:55         ` Ævar Arnfjörð Bjarmason
2018-06-05  5:10           ` Martin Ågren
2018-06-05 16:29           ` Brandon Williams
2018-06-05 19:54             ` [PATCH 0/3] refspec: refactor & fix free() behavior Ævar Arnfjörð Bjarmason
2018-06-05 19:58               ` Brandon Williams
2018-06-05 20:20                 ` Martin Ågren
2018-06-05 19:54             ` [PATCH 1/3] refspec: s/refspec_item_init/&_or_die/g Ævar Arnfjörð Bjarmason
2018-06-05 19:54             ` [PATCH 2/3] refspec: add back a refspec_item_init() function Ævar Arnfjörð Bjarmason
2018-06-05 19:54             ` [PATCH 3/3] refspec: initalize `refspec_item` in `valid_fetch_refspec()` Ævar Arnfjörð Bjarmason
2018-05-16 22:57   ` [PATCH v2 06/36] submodule--helper: convert push_check to use struct refspec Brandon Williams
2018-05-16 22:57   ` [PATCH v2 07/36] pull: convert get_tracking_branch to use refspec_item_init Brandon Williams
2018-05-16 22:57   ` [PATCH v2 08/36] transport: convert transport_push to use struct refspec Brandon Williams
2018-05-16 22:57   ` [PATCH v2 09/36] remote: convert check_push_refs " Brandon Williams
2018-05-16 22:57   ` [PATCH v2 10/36] remote: convert match_push_refs " Brandon Williams
2018-05-16 22:57   ` [PATCH v2 11/36] clone: convert cmd_clone to use refspec_item_init Brandon Williams
2018-05-16 22:57   ` [PATCH v2 12/36] fast-export: convert to use struct refspec Brandon Williams
2018-05-16 22:58   ` [PATCH v2 13/36] remote: convert push refspecs to " Brandon Williams
2018-05-16 22:58   ` [PATCH v2 14/36] remote: convert fetch " Brandon Williams
2018-05-16 22:58   ` [PATCH v2 15/36] remote: remove add_prune_tags_to_fetch_refspec Brandon Williams
2018-05-16 22:58   ` [PATCH v2 16/36] transport-helper: convert to use struct refspec Brandon Williams
2018-05-16 22:58   ` [PATCH v2 17/36] fetch: convert fetch_one " Brandon Williams
2018-05-16 22:58   ` [PATCH v2 18/36] fetch: convert refmap " Brandon Williams
2018-05-16 22:58   ` [PATCH v2 19/36] refspec: remove the deprecated functions Brandon Williams
2018-05-16 22:58   ` [PATCH v2 20/36] fetch: convert do_fetch to take a struct refspec Brandon Williams
2018-05-16 22:58   ` [PATCH v2 21/36] fetch: convert get_ref_map " Brandon Williams
2018-05-16 22:58   ` [PATCH v2 22/36] fetch: convert prune_refs " Brandon Williams
2018-05-16 22:58   ` [PATCH v2 23/36] remote: convert get_stale_heads " Brandon Williams
2018-05-16 22:58   ` [PATCH v2 24/36] remote: convert apply_refspecs " Brandon Williams
2018-05-16 22:58   ` [PATCH v2 25/36] remote: convert query_refspecs " Brandon Williams
2018-05-16 22:58   ` [PATCH v2 26/36] remote: convert get_ref_match " Brandon Williams
2018-05-16 22:58   ` [PATCH v2 27/36] remote: convert match_explicit_refs " Brandon Williams
2018-05-16 22:58   ` [PATCH v2 28/36] push: check for errors earlier Brandon Williams
2018-05-16 22:58   ` [PATCH v2 29/36] push: convert to use struct refspec Brandon Williams
2018-05-16 22:58   ` [PATCH v2 30/36] transport: convert transport_push to take a " Brandon Williams
2018-05-16 22:58   ` [PATCH v2 31/36] send-pack: store refspecs in " Brandon Williams
2018-05-16 22:58   ` [PATCH v2 32/36] transport: remove transport_verify_remote_names Brandon Williams
2018-05-16 22:58   ` [PATCH v2 33/36] http-push: store refspecs in a struct refspec Brandon Williams
2018-05-16 22:58   ` [PATCH v2 34/36] remote: convert match_push_refs to take " Brandon Williams
2018-05-16 22:58   ` [PATCH v2 35/36] remote: convert check_push_refs " Brandon Williams
2018-05-16 22:58   ` [PATCH v2 36/36] submodule: convert push_unpushed_submodules " Brandon Williams
2018-05-16 23:48   ` [PATCH 0/2] generating ref-prefixes for configured refspecs Brandon Williams
2018-05-16 23:48     ` [PATCH 1/2] refspec: consolidate ref-prefix generation logic Brandon Williams
2018-05-31  0:43       ` Jonathan Nieder
2018-05-31  1:07         ` Jonathan Nieder
2018-05-31  7:23       ` [PATCH] fetch: do not pass ref-prefixes for fetch by exact SHA1 Jonathan Nieder
2018-05-31 15:44         ` Brandon Williams
2018-06-01  2:12         ` Junio C Hamano
2018-06-01  2:49           ` Jonathan Nieder
2018-05-16 23:48     ` [PATCH 2/2] fetch: generate ref-prefixes when using a configured refspec Brandon Williams
2018-05-17 21:32     ` [PATCH 0/2] generating ref-prefixes for configured refspecs Junio C Hamano

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.