{"thread":{"id":"8994","subject":"[PATCH 2/4] Add matching and parsing for fetch-side refspec rules","startedAt":"2007-07-12T01:37:05Z","lastAt":"2007-07-12T01:37:05Z","messageCount":1,"participants":["Daniel Barkalow"],"isPatch":true,"patchVersion":1,"patchTotal":4},"messages":[{"id":"47102","messageId":"Pine.LNX.4.64.0707112107270.6977@iabervon.org","threadId":"8994","inReplyTo":null,"subject":"[PATCH 2/4] Add matching and parsing for fetch-side refspec rules","fromName":"Daniel Barkalow","fromEmail":"barkalow@iabervon.org","sentAt":"2007-07-12T01:37:05Z","receivedAt":"2007-07-12T01:37:05Z","isPatch":true,"sender":{"key":"barkalow@iabervon.org","avatar":"https://avatars.githubusercontent.com/u/55364219?v=4"},"body":"Also exports parse_ref_spec() and reads the \"tagopt\" config option.\n\nSigned-off-by: Daniel Barkalow <barkalow@iabervon.org>\n---\n remote.c |  125 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-\n remote.h |   24 ++++++++++++\n 2 files changed, 148 insertions(+), 1 deletions(-)\n\ndiff --git a/remote.c b/remote.c\nindex fa4af05..bba44c3 100644\n--- a/remote.c\n+++ b/remote.c\n@@ -208,6 +208,7 @@ static void read_branches_file(struct remote *remote)\n \t}\n \tadd_uri(remote, p);\n \tadd_fetch_refspec(remote, branch);\n+\tremote->fetch_tags = 1; /* always auto-follow */\n }\n \n static int handle_config(const char *key, const char *value)\n@@ -274,6 +275,9 @@ static int handle_config(const char *key, const char *value)\n \t\t\tremote->uploadpack = xstrdup(value);\n \t\telse\n \t\t\terror(\"more than one uploadpack given, using the first\");\n+\t} else if (!strcmp(subkey, \".tagopt\")) {\n+\t\tif (!strcmp(value, \"--no-tags\"))\n+\t\t\tremote->fetch_tags = -1;\n \t}\n \treturn 0;\n }\n@@ -296,7 +300,7 @@ static void read_config(void)\n \tgit_config(handle_config);\n }\n \n-static struct refspec *parse_ref_spec(int nr_refspec, const char **refspec)\n+struct refspec *parse_ref_spec(int nr_refspec, const char **refspec)\n {\n \tint i;\n \tstruct refspec *rs = xcalloc(sizeof(*rs), nr_refspec);\n@@ -352,6 +356,10 @@ struct remote *remote_get(const char *name)\n \t\tadd_uri(ret, name);\n \tif (!ret->uri)\n \t\treturn NULL;\n+\tif (!strcmp(name, \".\")) {\n+\t\t// we always fetch \"refs/*:refs/*\", which is trivial\n+\t\tadd_fetch_refspec(ret, \"refs/*:refs/*\");\n+\t}\n \tret->fetch = parse_ref_spec(ret->fetch_refspec_nr, ret->fetch_refspec);\n \tret->push = parse_ref_spec(ret->push_refspec_nr, ret->push_refspec);\n \treturn ret;\n@@ -424,6 +432,14 @@ struct ref *alloc_ref(unsigned namelen)\n \treturn ret;\n }\n \n+static struct ref *copy_ref(struct ref *ref)\n+{\n+\tstruct ref *ret = xmalloc(sizeof(struct ref) + strlen(ref->name) + 1);\n+\tmemcpy(ret, ref, sizeof(struct ref) + strlen(ref->name) + 1);\n+\tret->next = NULL;\n+\treturn ret;\n+}\n+\n void free_refs(struct ref *ref)\n {\n \tstruct ref *next;\n@@ -734,3 +750,110 @@ int branch_merges(struct branch *branch, const char *refname)\n \t}\n \treturn 0;\n }\n+\n+static struct ref *get_expanded_map(struct ref *remote_refs,\n+\t\t\t\t    const struct refspec *refspec)\n+{\n+\tstruct ref *ref;\n+\tstruct ref *ret = NULL;\n+\tstruct ref **tail = &ret;\n+\n+\tint remote_prefix_len = strlen(refspec->src);\n+\tint local_prefix_len = strlen(refspec->dst);\n+\n+\tfor (ref = remote_refs; ref; ref = ref->next) {\n+\t\tif (strchr(ref->name, '^'))\n+\t\t\tcontinue; /* a dereference item */\n+\t\tif (!prefixcmp(ref->name, refspec->src)) {\n+\t\t\tchar *match;\n+\t\t\tstruct ref *cpy = copy_ref(ref);\n+\t\t\tmatch = ref->name + remote_prefix_len;\n+\n+\t\t\tcpy->peer_ref = alloc_ref(local_prefix_len +\n+\t\t\t\t\t\t  strlen(match) + 1);\n+\t\t\tsprintf(cpy->peer_ref->name, \"%s%s\",\n+\t\t\t\trefspec->dst, match);\n+\t\t\tif (refspec->force)\n+\t\t\t\tcpy->peer_ref->force = 1;\n+\t\t\t*tail = cpy;\n+\t\t\ttail = &cpy->next;\n+\t\t}\n+\t}\n+\n+\treturn ret;\n+}\n+\n+static struct ref *find_ref_by_name_abbrev(struct ref *refs, const char *name)\n+{\n+\tstruct ref *ref;\n+\tfor (ref = refs; ref; ref = ref->next) {\n+\t\tif (ref_matches_abbrev(name, ref->name))\n+\t\t\treturn ref;\n+\t}\n+\treturn NULL;\n+}\n+\n+struct ref *get_remote_ref(struct ref *remote_refs, const char *name)\n+{\n+\tstruct ref *ref = find_ref_by_name_abbrev(remote_refs, name);\n+\n+\tif (!ref)\n+\t\tdie(\"Couldn't find remote ref %s\\n\", name);\n+\n+\treturn copy_ref(ref);\n+}\n+\n+static struct ref *get_local_ref(const char *name)\n+{\n+\tstruct ref *ret;\n+\tif (!name)\n+\t\treturn NULL;\n+\n+\tif (!prefixcmp(name, \"refs/\")) {\n+\t\tret = alloc_ref(strlen(name) + 1);\n+\t\tstrcpy(ret->name, name);\n+\t\treturn ret;\n+\t}\n+\n+\tif (!prefixcmp(name, \"heads/\") ||\n+\t    !prefixcmp(name, \"tags/\") ||\n+\t    !prefixcmp(name, \"remotes/\")) {\n+\t\tret = alloc_ref(strlen(name) + 6);\n+\t\tsprintf(ret->name, \"refs/%s\", name);\n+\t\treturn ret;\n+\t}\n+\n+\tret = alloc_ref(strlen(name) + 12);\n+\tsprintf(ret->name, \"refs/heads/%s\", name);\n+\treturn ret;\n+}\n+\n+int get_fetch_map(struct ref *remote_refs,\n+\t\t  const struct refspec *refspec,\n+\t\t  struct ref ***tail)\n+{\n+\tstruct ref *ref_map, *rm;\n+\n+\tif (refspec->pattern) {\n+\t\tref_map = get_expanded_map(remote_refs, refspec);\n+\t} else {\n+\t\tref_map = get_remote_ref(remote_refs,\n+\t\t\t\t\t refspec->src[0] ?\n+\t\t\t\t\t refspec->src : \"HEAD\");\n+\n+\t\tref_map->peer_ref = get_local_ref(refspec->dst);\n+\n+\t\tif (refspec->force)\n+\t\t\tref_map->peer_ref->force = 1;\n+\t}\n+\n+\tfor (rm = ref_map; rm; rm = rm->next) {\n+\t\tif (rm->peer_ref && check_ref_format(rm->peer_ref->name + 5))\n+\t\t\tdie(\"* refusing to create funny ref '%s' locally\",\n+\t\t\t    rm->peer_ref->name);\n+\t}\n+\n+\ttail_link_ref(ref_map, tail);\n+\n+\treturn 0;\n+}\ndiff --git a/remote.h b/remote.h\nindex 56e0ba6..2a5e87e 100644\n--- a/remote.h\n+++ b/remote.h\n@@ -15,6 +15,14 @@ struct remote {\n \tstruct refspec *fetch;\n \tint fetch_refspec_nr;\n \n+\t/*\n+\t * -1 to never fetch tags\n+\t * 0 to auto-follow tags on heuristic (default)\n+\t * 1 to always auto-follow tags\n+\t * 2 to always fetch tags\n+\t */\n+\tint fetch_tags;\n+\n \tconst char *receivepack;\n \tconst char *uploadpack;\n };\n@@ -38,10 +46,26 @@ struct ref *alloc_ref(unsigned namelen);\n  */\n void free_refs(struct ref *ref);\n \n+struct refspec *parse_ref_spec(int nr_refspec, const char **refspec);\n+\n int match_refs(struct ref *src, struct ref *dst, struct ref ***dst_tail,\n \t       int nr_refspec, char **refspec, int all);\n \n /*\n+ * Given a list of the remote refs and the specification of things to\n+ * fetch, makes a (separate) list of the refs to fetch and the local\n+ * refs to store into.\n+ *\n+ * *tail is the pointer to the tail pointer of the list of results\n+ * beforehand, and will be set to the tail pointer of the list of\n+ * results afterward.\n+ */\n+int get_fetch_map(struct ref *remote_refs, const struct refspec *refspec,\n+\t\t  struct ref ***tail);\n+\n+struct ref *get_remote_ref(struct ref *remote_refs, const char *name);\n+\n+/*\n  * For the given remote, reads the refspec's src and sets the other fields.\n  */\n int remote_find_tracking(struct remote *remote, struct refspec *refspec);\n-- \n1.5.2.2.1600.ga4e5\n"}]}