{"thread":{"id":"8940","subject":"[PATCH] Report information on branches from remote.h","startedAt":"2007-07-09T05:10:25Z","lastAt":"2007-07-09T05:10:25Z","messageCount":1,"participants":["Daniel Barkalow"],"isPatch":true,"patchVersion":1,"patchTotal":null},"messages":[{"id":"46825","messageId":"Pine.LNX.4.64.0707090107390.6977@iabervon.org","threadId":"8940","inReplyTo":null,"subject":"[PATCH] Report information on branches from remote.h","fromName":"Daniel Barkalow","fromEmail":"barkalow@iabervon.org","sentAt":"2007-07-09T05:10:25Z","receivedAt":"2007-07-09T05:10:25Z","isPatch":true,"sender":{"key":"barkalow@iabervon.org","avatar":"https://avatars.githubusercontent.com/u/55364219?v=4"},"body":"This adds full parsing for branch.<name> sections and functions to\ninterpret the results usefully. It incidentally corrects the fetch\nconfiguration information for legacy branches/* files with '#'\ncharacters in the URLs.\n\nSigned-off-by: Daniel Barkalow <barkalow@iabervon.org>\n---\n remote.c |  157 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++----\n remote.h |   18 +++++++\n 2 files changed, 164 insertions(+), 11 deletions(-)\n\ndiff --git a/remote.c b/remote.c\nindex 500ca4d..4ea15b9 100644\n--- a/remote.c\n+++ b/remote.c\n@@ -5,6 +5,12 @@\n static struct remote **remotes;\n static int allocated_remotes;\n \n+static struct branch **branches;\n+static int allocated_branches;\n+\n+static struct branch *current_branch;\n+static const char *default_remote_name;\n+\n #define BUF_SIZE (2048)\n static char buffer[BUF_SIZE];\n \n@@ -67,6 +73,54 @@ static struct remote *make_remote(const char *name, int len)\n \treturn remotes[empty];\n }\n \n+static void add_merge(struct branch *branch, const char *name)\n+{\n+\tint nr = branch->merge_nr + 1;\n+\tbranch->merge_name =\n+\t\txrealloc(branch->merge_name, nr * sizeof(char *));\n+\tbranch->merge_name[nr-1] = name;\n+\tbranch->merge_nr = nr;\n+}\n+\n+static struct branch *make_branch(const char *name, int len)\n+{\n+\tint i, empty = -1;\n+\tchar *refname;\n+\n+\tfor (i = 0; i < allocated_branches; i++) {\n+\t\tif (!branches[i]) {\n+\t\t\tif (empty < 0)\n+\t\t\t\tempty = i;\n+\t\t} else {\n+\t\t\tif (len ? (!strncmp(name, branches[i]->name, len) &&\n+\t\t\t\t   !branches[i]->name[len]) :\n+\t\t\t    !strcmp(name, branches[i]->name))\n+\t\t\t\treturn branches[i];\n+\t\t}\n+\t}\n+\n+\tif (empty < 0) {\n+\t\tempty = allocated_branches;\n+\t\tallocated_branches += allocated_branches ? allocated_branches : 1;\n+\t\tbranches = xrealloc(branches,\n+\t\t\t\t   sizeof(*branches) * allocated_branches);\n+\t\tmemset(branches + empty, 0,\n+\t\t       (allocated_branches - empty) * sizeof(*branches));\n+\t}\n+\tbranches[empty] = xcalloc(1, sizeof(struct branch));\n+\tif (len)\n+\t\tbranches[empty]->name = xstrndup(name, len);\n+\telse\n+\t\tbranches[empty]->name = xstrdup(name);\n+\trefname = malloc(strlen(name) + strlen(\"refs/heads/\") + 1);\n+\tstrcpy(refname, \"refs/heads/\");\n+\tstrcpy(refname + strlen(\"refs/heads/\"),\n+\t       branches[empty]->name);\n+\tbranches[empty]->refname = refname;\n+\n+\treturn branches[empty];\n+}\n+\n static void read_remotes_file(struct remote *remote)\n {\n \tFILE *f = fopen(git_path(\"remotes/%s\", remote->name), \"r\");\n@@ -116,6 +170,8 @@ static void read_remotes_file(struct remote *remote)\n static void read_branches_file(struct remote *remote)\n {\n \tconst char *slash = strchr(remote->name, '/');\n+\tchar *frag;\n+\tchar *branch;\n \tint n = slash ? slash - remote->name : 1000;\n \tFILE *f = fopen(git_path(\"branches/%.*s\", n, remote->name), \"r\");\n \tchar *s, *p;\n@@ -141,23 +197,40 @@ static void read_branches_file(struct remote *remote)\n \tstrcpy(p, s);\n \tif (slash)\n \t\tstrcat(p, slash);\n+\tfrag = strchr(p, '#');\n+\tif (frag) {\n+\t\t*(frag++) = '\\0';\n+\t\tbranch = xmalloc(strlen(frag) + 12);\n+\t\tstrcpy(branch, \"refs/heads/\");\n+\t\tstrcat(branch, frag);\n+\t} else {\n+\t\tbranch = \"refs/heads/master\";\n+\t}\n \tadd_uri(remote, p);\n+\tadd_fetch_refspec(remote, branch);\n }\n \n-static char *default_remote_name = NULL;\n-static const char *current_branch = NULL;\n-static int current_branch_len = 0;\n-\n static int handle_config(const char *key, const char *value)\n {\n \tconst char *name;\n \tconst char *subkey;\n \tstruct remote *remote;\n-\tif (!prefixcmp(key, \"branch.\") && current_branch &&\n-\t    !strncmp(key + 7, current_branch, current_branch_len) &&\n-\t    !strcmp(key + 7 + current_branch_len, \".remote\")) {\n-\t\tfree(default_remote_name);\n-\t\tdefault_remote_name = xstrdup(value);\n+\tstruct branch *branch;\n+\tif (!prefixcmp(key, \"branch.\")) {\n+\t\tname = key + 7;\n+\t\tsubkey = strrchr(name, '.');\n+\t\tbranch = make_branch(name, subkey - name);\n+\t\tif (!subkey)\n+\t\t\treturn 0;\n+\t\tif (!value)\n+\t\t\treturn 0;\n+\t\tif (!strcmp(subkey, \".remote\")) {\n+\t\t\tbranch->remote_name = xstrdup(value);\n+\t\t\tif (branch == current_branch)\n+\t\t\t\tdefault_remote_name = branch->remote_name;\n+\t\t} else if (!strcmp(subkey, \".merge\"))\n+\t\t\tadd_merge(branch, xstrdup(value));\n+\t\treturn 0;\n \t}\n \tif (prefixcmp(key,  \"remote.\"))\n \t\treturn 0;\n@@ -212,8 +285,8 @@ static void read_config(void)\n \thead_ref = resolve_ref(\"HEAD\", sha1, 0, &flag);\n \tif (head_ref && (flag & REF_ISSYMREF) &&\n \t    !prefixcmp(head_ref, \"refs/heads/\")) {\n-\t\tcurrent_branch = head_ref + strlen(\"refs/heads/\");\n-\t\tcurrent_branch_len = strlen(current_branch);\n+\t\tcurrent_branch =\n+\t\t\tmake_branch(head_ref + strlen(\"refs/heads/\"), 0);\n \t}\n \tgit_config(handle_config);\n }\n@@ -289,6 +362,25 @@ int remote_has_uri(struct remote *remote, const char *uri)\n \treturn 0;\n }\n \n+/*\n+ * Returns true if, under the matching rules for fetching, name is the\n+ * same as the given full name.\n+ */\n+static int ref_matches_abbrev(const char *name, const char *full)\n+{\n+\tif (!prefixcmp(name, \"refs/\") || !strcmp(name, \"HEAD\"))\n+\t\treturn !strcmp(name, full);\n+\tif (prefixcmp(full, \"refs/\"))\n+\t\treturn 0;\n+\tif (!prefixcmp(name, \"heads/\") ||\n+\t    !prefixcmp(name, \"tags/\") ||\n+\t    !prefixcmp(name, \"remotes/\"))\n+\t\treturn !strcmp(name, full + 5);\n+\tif (prefixcmp(full + 5, \"heads/\"))\n+\t\treturn 0;\n+\treturn !strcmp(full + 11, name);\n+}\n+\n int remote_find_tracking(struct remote *remote, struct refspec *refspec)\n {\n \tint i;\n@@ -574,3 +666,46 @@ int match_refs(struct ref *src, struct ref *dst, struct ref ***dst_tail,\n \t}\n \treturn 0;\n }\n+\n+struct branch *branch_get(const char *name)\n+{\n+\tstruct branch *ret;\n+\n+\tread_config();\n+\tif (!name || !*name || !strcmp(name, \"HEAD\"))\n+\t\tret = current_branch;\n+\telse\n+\t\tret = make_branch(name, 0);\n+\tif (ret && ret->remote_name) {\n+\t\tret->remote = remote_get(ret->remote_name);\n+\t\tif (ret->merge_nr) {\n+\t\t\tint i;\n+\t\t\tret->merge = xcalloc(sizeof(*ret->merge),\n+\t\t\t\t\t     ret->merge_nr);\n+\t\t\tfor (i = 0; i < ret->merge_nr; i++) {\n+\t\t\t\tret->merge[i] = xcalloc(1, sizeof(**ret->merge));\n+\t\t\t\tret->merge[i]->src = ret->merge_name[i];\n+\t\t\t\tremote_find_tracking(ret->remote,\n+\t\t\t\t\t\t     ret->merge[i]);\n+\t\t\t}\n+\t\t}\n+\t}\n+\treturn ret;\n+}\n+\n+int branch_has_merge_config(struct branch *branch)\n+{\n+\treturn branch && !!branch->merge;\n+}\n+\n+int branch_merges(struct branch *branch, const char *refname)\n+{\n+\tint i;\n+\tif (!branch)\n+\t\treturn 0;\n+\tfor (i = 0; i < branch->merge_nr; i++) {\n+\t\tif (ref_matches_abbrev(branch->merge[i]->src, refname))\n+\t\t\treturn 1;\n+\t}\n+\treturn 0;\n+}\ndiff --git a/remote.h b/remote.h\nindex 01dbcef..9824a0d 100644\n--- a/remote.h\n+++ b/remote.h\n@@ -38,4 +38,22 @@ int match_refs(struct ref *src, struct ref *dst, struct ref ***dst_tail,\n  */\n int remote_find_tracking(struct remote *remote, struct refspec *refspec);\n \n+struct branch {\n+\tconst char *name;\n+\tconst char *refname;\n+\n+\tconst char *remote_name;\n+\tstruct remote *remote;\n+\n+\tconst char **merge_name;\n+\tstruct refspec **merge;\n+\tint merge_nr;\n+};\n+\n+struct branch *branch_get(const char *name);\n+\n+int branch_has_merge_config(struct branch *branch);\n+\n+int branch_merges(struct branch *branch, const char *refname);\n+\n #endif\n-- \n1.5.2.2.1399.g097d5-dirty\n"}]}