{"thread":{"id":"17965","subject":"[PATCH 03/13] remote: fix two inconsistencies in the output of \"show <remote>\"","startedAt":"2009-02-23T06:28:48Z","lastAt":"2009-02-24T07:12:19Z","messageCount":38,"participants":["Jay Soffian","Jeff King","Johannes Sixt","Marc Branchaud","Junio C Hamano"],"isPatch":true,"patchVersion":1,"patchTotal":13},"messages":[{"id":"105853","messageId":"cover.1235368324.git.jaysoffian@gmail.com","threadId":"17965","inReplyTo":null,"subject":"[PATCH 00/13] New output style for git remote show","fromName":"Jay Soffian","fromEmail":"jaysoffian@gmail.com","sentAt":"2009-02-23T06:28:48Z","receivedAt":"2009-02-23T06:28:48Z","isPatch":true,"sender":{"key":"jaysoffian@gmail.com","avatar":"https://avatars.githubusercontent.com/u/155970?v=4"},"body":"Junio, this is based on pu, as it builds on my and Jeff's git remote\nchanges. Patches 1-7 are about new output style for \"git remote show\"\nfor everything but the push refspecs. Patches 8-13 then culiminate in\nteaching it a new output style for push refspecs as well.\n\n1-4 were previously a single patch which I broke up per your feedback\n(gmane 110806).\n\nJay Soffian (13):\n  remote: rename variable and eliminate redundant function call\n  remote: remove unused code in get_ref_states\n  remote: fix two inconsistencies in the output of \"show <remote>\"\n  remote: make get_remote_ref_states() always populate states.tracked\n  remote: name remote_refs consistently\n  string-list: new for_each_string_list() function\n  remote: new show output style\n  refactor duplicated get_local_heads() to remote.c\n  refactor duplicated ref_newer() to remote.c\n  remote.c: make match_refs() copy src ref before assigning to peer_ref\n  remote.c: don't short-circuit match_refs() when error in\n    match_explicit_refs()\n  remote.c: refactor get_remote_ref_states()\n  remote: new show output style for push refspecs\n\n builtin-remote.c    |  469 ++++++++++++++++++++++++++++++++++++++++-----------\n builtin-send-pack.c |   78 +---------\n http-push.c         |   72 +--------\n remote.c            |   88 +++++++++-\n remote.h            |    2 +\n string-list.c       |   10 +\n string-list.h       |    5 +\n t/t5505-remote.sh   |   66 +++++---\n 8 files changed, 516 insertions(+), 274 deletions(-)\n"},{"id":"105855","messageId":"3d0d9b7fe0d4f7c52a0790fedba0da8f37b70720.1235368324.git.jaysoffian@gmail.com","threadId":"17965","inReplyTo":"cover.1235368324.git.jaysoffian@gmail.com","subject":"[PATCH 01/13] remote: rename variable and eliminate redundant function call","fromName":"Jay Soffian","fromEmail":"jaysoffian@gmail.com","sentAt":"2009-02-23T06:28:49Z","receivedAt":"2009-02-23T06:28:49Z","isPatch":true,"sender":{"key":"jaysoffian@gmail.com","avatar":"https://avatars.githubusercontent.com/u/155970?v=4"},"body":"The variable name \"remote\" is used as both a \"char *\" and as a \"struct\nremote *\"; this is confusing, so rename the former to remote_name.\n\nThere is no need to call \"sort_string_list(&branch_list)\" as branch_list\nis populated via string_list_insert(), which maintains its order.\n\nSigned-off-by: Jay Soffian <jaysoffian@gmail.com>\n---\n builtin-remote.c |   13 ++++++-------\n 1 files changed, 6 insertions(+), 7 deletions(-)\n\ndiff --git a/builtin-remote.c b/builtin-remote.c\nindex d6958d4..1603219 100644\n--- a/builtin-remote.c\n+++ b/builtin-remote.c\n@@ -144,7 +144,7 @@ static int add(int argc, const char **argv)\n }\n \n struct branch_info {\n-\tchar *remote;\n+\tchar *remote_name;\n \tstruct string_list merge;\n };\n \n@@ -183,9 +183,9 @@ static int config_read_branches(const char *key, const char *value, void *cb)\n \t\t\titem->util = xcalloc(sizeof(struct branch_info), 1);\n \t\tinfo = item->util;\n \t\tif (type == REMOTE) {\n-\t\t\tif (info->remote)\n+\t\t\tif (info->remote_name)\n \t\t\t\twarning(\"more than one branch.%s\", key);\n-\t\t\tinfo->remote = xstrdup(value);\n+\t\t\tinfo->remote_name = xstrdup(value);\n \t\t} else {\n \t\t\tchar *space = strchr(value, ' ');\n \t\t\tvalue = abbrev_branch(value);\n@@ -207,7 +207,6 @@ static void read_branches(void)\n \tif (branch_list.nr)\n \t\treturn;\n \tgit_config(config_read_branches, NULL);\n-\tsort_string_list(&branch_list);\n }\n \n struct ref_states {\n@@ -490,7 +489,7 @@ static int mv(int argc, const char **argv)\n \tfor (i = 0; i < branch_list.nr; i++) {\n \t\tstruct string_list_item *item = branch_list.items + i;\n \t\tstruct branch_info *info = item->util;\n-\t\tif (info->remote && !strcmp(info->remote, rename.old)) {\n+\t\tif (info->remote_name && !strcmp(info->remote_name, rename.old)) {\n \t\t\tstrbuf_reset(&buf);\n \t\t\tstrbuf_addf(&buf, \"branch.%s.remote\", item->string);\n \t\t\tif (git_config_set(buf.buf, rename.new)) {\n@@ -600,7 +599,7 @@ static int rm(int argc, const char **argv)\n \tfor (i = 0; i < branch_list.nr; i++) {\n \t\tstruct string_list_item *item = branch_list.items + i;\n \t\tstruct branch_info *info = item->util;\n-\t\tif (info->remote && !strcmp(info->remote, remote->name)) {\n+\t\tif (info->remote_name && !strcmp(info->remote_name, remote->name)) {\n \t\t\tconst char *keys[] = { \"remote\", \"merge\", NULL }, **k;\n \t\t\tfor (k = keys; *k; k++) {\n \t\t\t\tstrbuf_reset(&buf);\n@@ -743,7 +742,7 @@ static int show(int argc, const char **argv)\n \t\t\tstruct branch_info *info = branch->util;\n \t\t\tint j;\n \n-\t\t\tif (!info->merge.nr || strcmp(*argv, info->remote))\n+\t\t\tif (!info->merge.nr || strcmp(*argv, info->remote_name))\n \t\t\t\tcontinue;\n \t\t\tprintf(\"  Remote branch%s merged with 'git pull' \"\n \t\t\t\t\"while on branch %s\\n   \",\n-- \n1.6.2.rc1.223.gfed32\n"},{"id":"105854","messageId":"f9c6cc9cdcb6d95ca9589d66dd0291ac807a89c6.1235368324.git.jaysoffian@gmail.com","threadId":"17965","inReplyTo":"cover.1235368324.git.jaysoffian@gmail.com","subject":"[PATCH 02/13] remote: remove unused code in get_ref_states","fromName":"Jay Soffian","fromEmail":"jaysoffian@gmail.com","sentAt":"2009-02-23T06:28:50Z","receivedAt":"2009-02-23T06:28:50Z","isPatch":true,"sender":{"key":"jaysoffian@gmail.com","avatar":"https://avatars.githubusercontent.com/u/155970?v=4"},"body":"get_ref_states() populates the util pointer of the string_list_item's\nthat it adds to states->new and states->tracked, but nothing ever uses\nthe pointer, so we can get rid of the extra code.\n\nSigned-off-by: Jay Soffian <jaysoffian@gmail.com>\n---\n builtin-remote.c |   13 +++----------\n 1 files changed, 3 insertions(+), 10 deletions(-)\n\ndiff --git a/builtin-remote.c b/builtin-remote.c\nindex 1603219..f2ef08a 100644\n--- a/builtin-remote.c\n+++ b/builtin-remote.c\n@@ -250,18 +250,11 @@ static int get_ref_states(const struct ref *ref, struct ref_states *states)\n \n \tstates->new.strdup_strings = states->tracked.strdup_strings = 1;\n \tfor (ref = fetch_map; ref; ref = ref->next) {\n-\t\tstruct string_list *target = &states->tracked;\n \t\tunsigned char sha1[20];\n-\t\tvoid *util = NULL;\n-\n \t\tif (!ref->peer_ref || read_ref(ref->peer_ref->name, sha1))\n-\t\t\ttarget = &states->new;\n-\t\telse {\n-\t\t\ttarget = &states->tracked;\n-\t\t\tif (hashcmp(sha1, ref->new_sha1))\n-\t\t\t\tutil = &states;\n-\t\t}\n-\t\tstring_list_append(abbrev_branch(ref->name), target)->util = util;\n+\t\t\tstring_list_append(abbrev_branch(ref->name), &states->new);\n+\t\telse\n+\t\t\tstring_list_append(abbrev_branch(ref->name), &states->tracked);\n \t}\n \tfree_refs(fetch_map);\n \n-- \n1.6.2.rc1.223.gfed32\n"},{"id":"105852","messageId":"30b0e9a2ad91f17f9ebbfe9954522dcbf3b24f5e.1235368324.git.jaysoffian@gmail.com","threadId":"17965","inReplyTo":"cover.1235368324.git.jaysoffian@gmail.com","subject":"[PATCH 03/13] remote: fix two inconsistencies in the output of \"show <remote>\"","fromName":"Jay Soffian","fromEmail":"jaysoffian@gmail.com","sentAt":"2009-02-23T06:28:51Z","receivedAt":"2009-02-23T06:28:51Z","isPatch":true,"sender":{"key":"jaysoffian@gmail.com","avatar":"https://avatars.githubusercontent.com/u/155970?v=4"},"body":"Remote and stale branches are emitted in alphabetical order, but new and\ntracked branches are not. So sort the latter to be consistent with the\nformer. This also lets us use more efficient string_list_has_string()\ninstead of unsorted_string_list_has_string().\n\n\"show <remote>\" prunes symrefs, but \"show <remote> -n\" does not. Fix the\nlatter to match the former.\n\nSigned-off-by: Jay Soffian <jaysoffian@gmail.com>\n---\n builtin-remote.c  |   15 ++++++++++-----\n t/t5505-remote.sh |    2 +-\n 2 files changed, 11 insertions(+), 6 deletions(-)\n\ndiff --git a/builtin-remote.c b/builtin-remote.c\nindex f2ef08a..31fbd1e 100644\n--- a/builtin-remote.c\n+++ b/builtin-remote.c\n@@ -227,10 +227,8 @@ static int handle_one_branch(const char *refname,\n \t\tconst char *name = abbrev_branch(refspec.src);\n \t\t/* symbolic refs pointing nowhere were handled already */\n \t\tif ((flags & REF_ISSYMREF) ||\n-\t\t\t\tunsorted_string_list_has_string(&states->tracked,\n-\t\t\t\t\tname) ||\n-\t\t\t\tunsorted_string_list_has_string(&states->new,\n-\t\t\t\t\tname))\n+\t\t    string_list_has_string(&states->tracked, name) ||\n+\t\t    string_list_has_string(&states->new, name))\n \t\t\treturn 0;\n \t\titem = string_list_append(name, &states->stale);\n \t\titem->util = xstrdup(refname);\n@@ -258,6 +256,8 @@ static int get_ref_states(const struct ref *ref, struct ref_states *states)\n \t}\n \tfree_refs(fetch_map);\n \n+\tsort_string_list(&states->new);\n+\tsort_string_list(&states->tracked);\n \tfor_each_ref(handle_one_branch, states);\n \tsort_string_list(&states->stale);\n \n@@ -688,6 +688,9 @@ static int append_ref_to_tracked_list(const char *refname,\n \tstruct ref_states *states = cb_data;\n \tstruct refspec refspec;\n \n+\tif (flags & REF_ISSYMREF)\n+\t\treturn 0;\n+\n \tmemset(&refspec, 0, sizeof(refspec));\n \trefspec.dst = (char *)refname;\n \tif (!remote_find_tracking(states->remote, &refspec))\n@@ -754,8 +757,10 @@ static int show(int argc, const char **argv)\n \t\t\t\t\"prune')\", &states.stale, \"\");\n \t\t}\n \n-\t\tif (no_query)\n+\t\tif (no_query) {\n \t\t\tfor_each_ref(append_ref_to_tracked_list, &states);\n+\t\t\tsort_string_list(&states.tracked);\n+\t\t}\n \t\tshow_list(\"  Tracked remote branch%s\", &states.tracked, \"\");\n \n \t\tif (states.remote->push_refspec_nr) {\ndiff --git a/t/t5505-remote.sh b/t/t5505-remote.sh\nindex 104433d..fdc4a29 100755\n--- a/t/t5505-remote.sh\n+++ b/t/t5505-remote.sh\n@@ -142,8 +142,8 @@ cat > test/expect << EOF\n   New remote branch (next fetch will store in remotes/origin)\n     master\n   Tracked remote branches\n-    side\n     master\n+    side\n   Local branches pushed with 'git push'\n     master:upstream\n     +refs/tags/lastbackup\n-- \n1.6.2.rc1.223.gfed32\n"},{"id":"105857","messageId":"2185ca69c518d60276ba1bc613b7699a6bca7c68.1235368324.git.jaysoffian@gmail.com","threadId":"17965","inReplyTo":"cover.1235368324.git.jaysoffian@gmail.com","subject":"[PATCH 04/13] remote: make get_remote_ref_states() always populate states.tracked","fromName":"Jay Soffian","fromEmail":"jaysoffian@gmail.com","sentAt":"2009-02-23T06:28:52Z","receivedAt":"2009-02-23T06:28:52Z","isPatch":true,"sender":{"key":"jaysoffian@gmail.com","avatar":"https://avatars.githubusercontent.com/u/155970?v=4"},"body":"When not querying the remote, show() was having to populate\nstates.tracked itself. It makes more sense for get_remote_ref_states()\nto do this consistently. Since show() is the only caller of\nget_remote_ref_states() with query=0, this change does not affect the\nother call sites.\n\nSigned-off-by: Jay Soffian <jaysoffian@gmail.com>\n---\n builtin-remote.c |   41 ++++++++++++++++++++---------------------\n 1 files changed, 20 insertions(+), 21 deletions(-)\n\ndiff --git a/builtin-remote.c b/builtin-remote.c\nindex 31fbd1e..b61f754 100644\n--- a/builtin-remote.c\n+++ b/builtin-remote.c\n@@ -656,6 +656,23 @@ static void free_remote_ref_states(struct ref_states *states)\n \tstring_list_clear(&states->heads, 0);\n }\n \n+static int append_ref_to_tracked_list(const char *refname,\n+\tconst unsigned char *sha1, int flags, void *cb_data)\n+{\n+\tstruct ref_states *states = cb_data;\n+\tstruct refspec refspec;\n+\n+\tif (flags & REF_ISSYMREF)\n+\t\treturn 0;\n+\n+\tmemset(&refspec, 0, sizeof(refspec));\n+\trefspec.dst = (char *)refname;\n+\tif (!remote_find_tracking(states->remote, &refspec))\n+\t\tstring_list_append(abbrev_branch(refspec.src), &states->tracked);\n+\n+\treturn 0;\n+}\n+\n static int get_remote_ref_states(const char *name,\n \t\t\t\t struct ref_states *states,\n \t\t\t\t int query)\n@@ -677,28 +694,14 @@ static int get_remote_ref_states(const char *name,\n \n \t\tget_head_names(ref, name, states);\n \t\tget_ref_states(ref, states);\n+\t} else {\n+\t\tfor_each_ref(append_ref_to_tracked_list, states);\n+\t\tsort_string_list(&states->tracked);\n \t}\n \n \treturn 0;\n }\n \n-static int append_ref_to_tracked_list(const char *refname,\n-\tconst unsigned char *sha1, int flags, void *cb_data)\n-{\n-\tstruct ref_states *states = cb_data;\n-\tstruct refspec refspec;\n-\n-\tif (flags & REF_ISSYMREF)\n-\t\treturn 0;\n-\n-\tmemset(&refspec, 0, sizeof(refspec));\n-\trefspec.dst = (char *)refname;\n-\tif (!remote_find_tracking(states->remote, &refspec))\n-\t\tstring_list_append(abbrev_branch(refspec.src), &states->tracked);\n-\n-\treturn 0;\n-}\n-\n static int show(int argc, const char **argv)\n {\n \tint no_query = 0, result = 0;\n@@ -757,10 +760,6 @@ static int show(int argc, const char **argv)\n \t\t\t\t\"prune')\", &states.stale, \"\");\n \t\t}\n \n-\t\tif (no_query) {\n-\t\t\tfor_each_ref(append_ref_to_tracked_list, &states);\n-\t\t\tsort_string_list(&states.tracked);\n-\t\t}\n \t\tshow_list(\"  Tracked remote branch%s\", &states.tracked, \"\");\n \n \t\tif (states.remote->push_refspec_nr) {\n-- \n1.6.2.rc1.223.gfed32\n"},{"id":"105858","messageId":"81ae3692383f006b730c0f5fa35842149c2da4b2.1235368324.git.jaysoffian@gmail.com","threadId":"17965","inReplyTo":"cover.1235368324.git.jaysoffian@gmail.com","subject":"[PATCH 05/13] remote: name remote_refs consistently","fromName":"Jay Soffian","fromEmail":"jaysoffian@gmail.com","sentAt":"2009-02-23T06:28:53Z","receivedAt":"2009-02-23T06:28:53Z","isPatch":true,"sender":{"key":"jaysoffian@gmail.com","avatar":"https://avatars.githubusercontent.com/u/155970?v=4"},"body":"Clarify the code a bit by consistently referring to the remote refs\nreturned by transport_get_remote_refs() as remote_refs.\n\nSigned-off-by: Jay Soffian <jaysoffian@gmail.com>\n---\n builtin-remote.c |   22 +++++++++++-----------\n 1 files changed, 11 insertions(+), 11 deletions(-)\n\ndiff --git a/builtin-remote.c b/builtin-remote.c\nindex b61f754..df6b525 100644\n--- a/builtin-remote.c\n+++ b/builtin-remote.c\n@@ -236,13 +236,14 @@ static int handle_one_branch(const char *refname,\n \treturn 0;\n }\n \n-static int get_ref_states(const struct ref *ref, struct ref_states *states)\n+static int get_ref_states(const struct ref *remote_refs, struct ref_states *states)\n {\n \tstruct ref *fetch_map = NULL, **tail = &fetch_map;\n+\tstruct ref *ref;\n \tint i;\n \n \tfor (i = 0; i < states->remote->fetch_refspec_nr; i++)\n-\t\tif (get_fetch_map(ref, states->remote->fetch + i, &tail, 1))\n+\t\tif (get_fetch_map(remote_refs, states->remote->fetch + i, &tail, 1))\n \t\t\tdie(\"Could not get fetch map for refspec %s\",\n \t\t\t\tstates->remote->fetch_refspec[i]);\n \n@@ -264,7 +265,7 @@ static int get_ref_states(const struct ref *ref, struct ref_states *states)\n \treturn 0;\n }\n \n-static int get_head_names(const struct ref *refs,\n+static int get_head_names(const struct ref *remote_refs,\n \tconst char *remote_name, struct ref_states *states)\n {\n \tstruct ref *ref, *matches;\n@@ -275,9 +276,9 @@ static int get_head_names(const struct ref *refs,\n \trefspec.pattern = 1;\n \trefspec.src = refspec.dst = \"refs/heads/\";\n \tstates->heads.strdup_strings = 1;\n-\tget_fetch_map(refs, &refspec, &fetch_map_tail, 0);\n-\tmatches = guess_remote_head(find_ref_by_name(refs, \"HEAD\"),\n-\t\t\t\t\tfetch_map, 1);\n+\tget_fetch_map(remote_refs, &refspec, &fetch_map_tail, 0);\n+\tmatches = guess_remote_head(find_ref_by_name(remote_refs, \"HEAD\"),\n+\t\t\t\t    fetch_map, 1);\n \tfor(ref = matches; ref; ref = ref->next)\n \t\tstring_list_append(abbrev_branch(ref->name), &states->heads);\n \n@@ -678,7 +679,7 @@ static int get_remote_ref_states(const char *name,\n \t\t\t\t int query)\n {\n \tstruct transport *transport;\n-\tconst struct ref *ref;\n+\tconst struct ref *remote_refs;\n \n \tstates->remote = remote_get(name);\n \tif (!states->remote)\n@@ -689,11 +690,10 @@ static int get_remote_ref_states(const char *name,\n \tif (query) {\n \t\ttransport = transport_get(NULL, states->remote->url_nr > 0 ?\n \t\t\tstates->remote->url[0] : NULL);\n-\t\tref = transport_get_remote_refs(transport);\n+\t\tremote_refs = transport_get_remote_refs(transport);\n \t\ttransport_disconnect(transport);\n-\n-\t\tget_head_names(ref, name, states);\n-\t\tget_ref_states(ref, states);\n+\t\tget_head_names(remote_refs, name, states);\n+\t\tget_ref_states(remote_refs, states);\n \t} else {\n \t\tfor_each_ref(append_ref_to_tracked_list, states);\n \t\tsort_string_list(&states->tracked);\n-- \n1.6.2.rc1.223.gfed32\n"},{"id":"105856","messageId":"a9a03697661905ebaa836d19eb03762c046e4a7a.1235368324.git.jaysoffian@gmail.com","threadId":"17965","inReplyTo":"cover.1235368324.git.jaysoffian@gmail.com","subject":"[PATCH 06/13] string-list: new for_each_string_list() function","fromName":"Jay Soffian","fromEmail":"jaysoffian@gmail.com","sentAt":"2009-02-23T06:28:54Z","receivedAt":"2009-02-23T06:28:54Z","isPatch":true,"sender":{"key":"jaysoffian@gmail.com","avatar":"https://avatars.githubusercontent.com/u/155970?v=4"},"body":"Add a convenience function for iterating over a string_list's items via\na callback.\n\nSigned-off-by: Jay Soffian <jaysoffian@gmail.com>\n---\n string-list.c |   10 ++++++++++\n string-list.h |    5 +++++\n 2 files changed, 15 insertions(+), 0 deletions(-)\n\ndiff --git a/string-list.c b/string-list.c\nindex 15e14cf..1ac536e 100644\n--- a/string-list.c\n+++ b/string-list.c\n@@ -92,6 +92,16 @@ struct string_list_item *string_list_lookup(const char *string, struct string_li\n \treturn list->items + i;\n }\n \n+int for_each_string_list(string_list_each_func_t fn,\n+\t\t\t struct string_list *list, void *cb_data)\n+{\n+\tint i, ret = 0;\n+\tfor (i = 0; i < list->nr; i++)\n+\t\tif ((ret = fn(&list->items[i], cb_data)))\n+\t\t\tbreak;\n+\treturn ret;\n+}\n+\n void string_list_clear(struct string_list *list, int free_util)\n {\n \tif (list->items) {\ndiff --git a/string-list.h b/string-list.h\nindex d32ba05..14bbc47 100644\n--- a/string-list.h\n+++ b/string-list.h\n@@ -20,6 +20,11 @@ void string_list_clear(struct string_list *list, int free_util);\n typedef void (*string_list_clear_func_t)(void *p, const char *str);\n void string_list_clear_func(struct string_list *list, string_list_clear_func_t clearfunc);\n \n+/* Use this function to iterate over each item */\n+typedef int (*string_list_each_func_t)(struct string_list_item *, void *);\n+int for_each_string_list(string_list_each_func_t,\n+\t\t\t struct string_list *list, void *cb_data);\n+\n /* Use these functions only on sorted lists: */\n int string_list_has_string(const struct string_list *list, const char *string);\n int string_list_find_insert_index(const struct string_list *list, const char *string,\n-- \n1.6.2.rc1.223.gfed32\n"},{"id":"105861","messageId":"904c2d8fe812fb5400d1b9946795c146de68eaca.1235368324.git.jaysoffian@gmail.com","threadId":"17965","inReplyTo":"cover.1235368324.git.jaysoffian@gmail.com","subject":"[PATCH 07/13] remote: new show output style","fromName":"Jay Soffian","fromEmail":"jaysoffian@gmail.com","sentAt":"2009-02-23T06:28:55Z","receivedAt":"2009-02-23T06:28:55Z","isPatch":true,"sender":{"key":"jaysoffian@gmail.com","avatar":"https://avatars.githubusercontent.com/u/155970?v=4"},"body":"The existing output of \"git remote show <remote>\" is too verbose for the\ninformation it provides. This patch teaches it to provide more\ninformation in less space.\n\nThe output for push refspecs is addressed in followup patch.\n\nBefore the patch:\n\n$ git remote show origin\n* remote origin\n  URL: git://git.kernel.org/pub/scm/git/git.git\n  HEAD branch: master\n  Remote branch merged with 'git pull' while on branch master\n    master\n  Remote branch merged with 'git pull' while on branch next\n    next\n  Remote branches merged with 'git pull' while on branch octopus\n    foo bar baz frotz\n  New remote branch (next fetch will store in remotes/origin)\n    html\n  Stale tracking branch (use 'git remote prune')\n    bogus\n  Tracked remote branches\n    maint\n    man\n    master\n    next\n    pu\n    todo\n\nAfter this patch:\n\n$ git remote show origin\n* remote origin\n  URL: git://git.kernel.org/pub/scm/git/git.git\n  HEAD branch: master\n  Remote branches:\n    bogus  stale (use 'git remote prune' to remove)\n    html   new (next fetch will store in remotes/origin)\n    maint  tracked\n    man    tracked\n    master tracked\n    next   tracked\n    pu     tracked\n    todo   tracked\n  Local branches configured for 'git pull':\n    master  rebases onto remote master\n    next    rebases onto remote next\n    octopus  merges with remote foo\n                and with remote bar\n                and with remote baz\n                and with remote frotz\n\n$ git remote show origin -n\n* remote origin\n  URL: git://git.kernel.org/pub/scm/git/git.git\n  HEAD branch: (not queried)\n  Remote branches: (status not queried)\n    bogus\n    maint\n    man\n    master\n    next\n    pu\n    todo\n  Local branches configured for 'git pull':\n    master  rebases onto remote master\n    next    rebases onto remote next\n    octopus  merges with remote foo\n                and with remote bar\n                and with remote baz\n                and with remote frotz\n\nSigned-off-by: Jay Soffian <jaysoffian@gmail.com>\n---\nI incorporated the feedback I received to gmane 110626. As the commit\nmessage mentions, the push refspec output is addressed in a later patch\nin this series.\n\n builtin-remote.c  |  187 ++++++++++++++++++++++++++++++++++++++++-------------\n t/t5505-remote.sh |   31 ++++++----\n 2 files changed, 161 insertions(+), 57 deletions(-)\n\ndiff --git a/builtin-remote.c b/builtin-remote.c\nindex df6b525..4975a0e 100644\n--- a/builtin-remote.c\n+++ b/builtin-remote.c\n@@ -146,6 +146,7 @@ static int add(int argc, const char **argv)\n struct branch_info {\n \tchar *remote_name;\n \tstruct string_list merge;\n+\tint rebase;\n };\n \n static struct string_list branch_list;\n@@ -162,10 +163,11 @@ static const char *abbrev_ref(const char *name, const char *prefix)\n static int config_read_branches(const char *key, const char *value, void *cb)\n {\n \tif (!prefixcmp(key, \"branch.\")) {\n+\t\tconst char *orig_key = key;\n \t\tchar *name;\n \t\tstruct string_list_item *item;\n \t\tstruct branch_info *info;\n-\t\tenum { REMOTE, MERGE } type;\n+\t\tenum { REMOTE, MERGE, REBASE } type;\n \n \t\tkey += 7;\n \t\tif (!postfixcmp(key, \".remote\")) {\n@@ -174,6 +176,9 @@ static int config_read_branches(const char *key, const char *value, void *cb)\n \t\t} else if (!postfixcmp(key, \".merge\")) {\n \t\t\tname = xstrndup(key, strlen(key) - 6);\n \t\t\ttype = MERGE;\n+\t\t} else if (!postfixcmp(key, \".rebase\")) {\n+\t\t\tname = xstrndup(key, strlen(key) - 7);\n+\t\t\ttype = REBASE;\n \t\t} else\n \t\t\treturn 0;\n \n@@ -184,9 +189,9 @@ static int config_read_branches(const char *key, const char *value, void *cb)\n \t\tinfo = item->util;\n \t\tif (type == REMOTE) {\n \t\t\tif (info->remote_name)\n-\t\t\t\twarning(\"more than one branch.%s\", key);\n+\t\t\t\twarning(\"more than one %s\", orig_key);\n \t\t\tinfo->remote_name = xstrdup(value);\n-\t\t} else {\n+\t\t} else if (type == MERGE) {\n \t\t\tchar *space = strchr(value, ' ');\n \t\t\tvalue = abbrev_branch(value);\n \t\t\twhile (space) {\n@@ -197,7 +202,8 @@ static int config_read_branches(const char *key, const char *value, void *cb)\n \t\t\t\tspace = strchr(value, ' ');\n \t\t\t}\n \t\t\tstring_list_append(xstrdup(value), &info->merge);\n-\t\t}\n+\t\t} else\n+\t\t\tinfo->rebase = git_config_bool(orig_key, value);\n \t}\n \treturn 0;\n }\n@@ -212,6 +218,7 @@ static void read_branches(void)\n struct ref_states {\n \tstruct remote *remote;\n \tstruct string_list new, stale, tracked, heads;\n+\tint queried;\n };\n \n static int handle_one_branch(const char *refname,\n@@ -635,20 +642,6 @@ static int rm(int argc, const char **argv)\n \treturn result;\n }\n \n-static void show_list(const char *title, struct string_list *list,\n-\t\t      const char *extra_arg)\n-{\n-\tint i;\n-\n-\tif (!list->nr)\n-\t\treturn;\n-\n-\tprintf(title, list->nr > 1 ? \"es\" : \"\", extra_arg);\n-\tprintf(\"\\n\");\n-\tfor (i = 0; i < list->nr; i++)\n-\t\tprintf(\"    %s\\n\", list->items[i].string);\n-}\n-\n static void free_remote_ref_states(struct ref_states *states)\n {\n \tstring_list_clear(&states->new, 0);\n@@ -698,6 +691,105 @@ static int get_remote_ref_states(const char *name,\n \t\tfor_each_ref(append_ref_to_tracked_list, states);\n \t\tsort_string_list(&states->tracked);\n \t}\n+\tstates->queried = query;\n+\n+\treturn 0;\n+}\n+\n+struct show_info {\n+\tstruct string_list *list;\n+\tstruct ref_states *states;\n+\tint width;\n+\tint any_rebase;\n+};\n+\n+int add_remote_to_show_info(struct string_list_item *item, void *cb_data)\n+{\n+\tstruct show_info *info = cb_data;\n+\tint n = strlen(item->string);\n+\tif (n > info->width)\n+\t\tinfo->width = n;\n+\tstring_list_insert(item->string, info->list);\n+\treturn 0;\n+}\n+\n+int show_remote_info_item(struct string_list_item *item, void *cb_data)\n+{\n+\tstruct show_info *info = cb_data;\n+\tstruct ref_states *states = info->states;\n+\tconst char *name = item->string;\n+\n+\tif (states->queried) {\n+\t\tconst char *fmt = \"%s\";\n+\t\tconst char *arg = \"\";\n+\t\tif (string_list_has_string(&states->new, name)) {\n+\t\t\tfmt = \" new (next fetch will store in remotes/%s)\";\n+\t\t\targ = states->remote->name;\n+\t\t} else if (string_list_has_string(&states->tracked, name))\n+\t\t\targ = \" tracked\";\n+\t\telse if (string_list_has_string(&states->stale, name))\n+\t\t\targ = \" stale (use 'git remote prune' to remove)\";\n+\t\telse\n+\t\t\targ = \" ???\";\n+\t\tprintf(\"    %-*s\", info->width, name);\n+\t\tprintf(fmt, arg);\n+\t\tprintf(\"\\n\");\n+\t} else\n+\t\tprintf(\"    %s\\n\", name);\n+\n+\treturn 0;\n+}\n+\n+int add_local_to_show_info(struct string_list_item *branch_item, void *cb_data)\n+{\n+\tstruct show_info *show_info = cb_data;\n+\tstruct ref_states *states = show_info->states;\n+\tstruct branch_info *branch_info = branch_item->util;\n+\tstruct string_list_item *item;\n+\tint n;\n+\n+\tif (!branch_info->merge.nr || !branch_info->remote_name ||\n+\t    strcmp(states->remote->name, branch_info->remote_name))\n+\t\treturn 0;\n+\tif ((n = strlen(branch_item->string)) > show_info->width)\n+\t\tshow_info->width = n;\n+\tif (branch_info->rebase)\n+\t\tshow_info->any_rebase = 1;\n+\n+\titem = string_list_insert(branch_item->string, show_info->list);\n+\titem->util = branch_info;\n+\n+\treturn 0;\n+}\n+\n+int show_local_info_item(struct string_list_item *item, void *cb_data)\n+{\n+\tstruct show_info *show_info = cb_data;\n+\tstruct branch_info *branch_info = item->util;\n+\tstruct string_list *merge = &branch_info->merge;\n+\tconst char *also;\n+\tint i;\n+\n+\tif (branch_info->rebase && branch_info->merge.nr > 1) {\n+\t\terror(\"invalid branch.%s.merge; cannot rebase onto > 1 branch\",\n+\t\t\titem->string);\n+\t\treturn 0;\n+\t}\n+\n+\tprintf(\"    %-*s \", show_info->width, item->string);\n+\tif (branch_info->rebase) {\n+\t\tprintf(\"rebases onto remote %s\\n\", merge->items[0].string);\n+\t\treturn 0;\n+\t} else if (show_info->any_rebase) {\n+\t\tprintf(\" merges with remote %s\\n\", merge->items[0].string);\n+\t\talso = \"    and with remote\";\n+\t} else {\n+\t\tprintf(\"merges with remote %s\\n\", merge->items[0].string);\n+\t\talso = \"   and with remote\";\n+\t}\n+\tfor (i = 1; i < merge->nr; i++)\n+\t\tprintf(\"    %-*s %s %s\\n\", show_info->width, \"\", also,\n+\t\t       merge->items[i].string);\n \n \treturn 0;\n }\n@@ -711,6 +803,8 @@ static int show(int argc, const char **argv)\n \t\tOPT_END()\n \t};\n \tstruct ref_states states;\n+\tstruct string_list info_list = { NULL, 0, 0, 0 };\n+\tstruct show_info info;\n \n \targc = parse_options(argc, argv, options, builtin_remote_usage, 0);\n \n@@ -718,6 +812,9 @@ static int show(int argc, const char **argv)\n \t\treturn show_all();\n \n \tmemset(&states, 0, sizeof(states));\n+\tmemset(&info, 0, sizeof(info));\n+\tinfo.states = &states;\n+\tinfo.list = &info_list;\n \tfor (; argc; argc--, argv++) {\n \t\tint i;\n \n@@ -731,37 +828,37 @@ static int show(int argc, const char **argv)\n \t\telse if (!states.heads.nr)\n \t\t\tprintf(\"  HEAD branch: (unknown)\\n\");\n \t\telse if (states.heads.nr == 1)\n-\t\t\tprintf(\"  HEAD branch: %s\\n\",\n-\t\t\t\tstates.heads.items[0].string);\n-\t\telse\n-\t\t\tshow_list(\"  HEAD branch%s:\", &states.heads, \"\");\n-\n-\t\tfor (i = 0; i < branch_list.nr; i++) {\n-\t\t\tstruct string_list_item *branch = branch_list.items + i;\n-\t\t\tstruct branch_info *info = branch->util;\n-\t\t\tint j;\n-\n-\t\t\tif (!info->merge.nr || strcmp(*argv, info->remote_name))\n-\t\t\t\tcontinue;\n-\t\t\tprintf(\"  Remote branch%s merged with 'git pull' \"\n-\t\t\t\t\"while on branch %s\\n   \",\n-\t\t\t\tinfo->merge.nr > 1 ? \"es\" : \"\",\n-\t\t\t\tbranch->string);\n-\t\t\tfor (j = 0; j < info->merge.nr; j++)\n-\t\t\t\tprintf(\" %s\", info->merge.items[j].string);\n-\t\t\tprintf(\"\\n\");\n+\t\t\tprintf(\"  HEAD branch: %s\\n\", states.heads.items[0].string);\n+\t\telse {\n+\t\t\tprintf(\"  HEAD branch (remote HEAD is ambiguous,\"\n+\t\t\t       \" may be one of the following):\\n\");\n+\t\t\tfor (i = 0; i < states.heads.nr; i++)\n+\t\t\t\tprintf(\"    %s\\n\", states.heads.items[i].string);\n \t\t}\n \n-\t\tif (!no_query) {\n-\t\t\tshow_list(\"  New remote branch%s (next fetch \"\n-\t\t\t\t\"will store in remotes/%s)\",\n-\t\t\t\t&states.new, states.remote->name);\n-\t\t\tshow_list(\"  Stale tracking branch%s (use 'git remote \"\n-\t\t\t\t\"prune')\", &states.stale, \"\");\n-\t\t}\n+\t\t/* remote branch info */\n+\t\tinfo.width = 0;\n+\t\tfor_each_string_list(add_remote_to_show_info, &states.new, &info);\n+\t\tfor_each_string_list(add_remote_to_show_info, &states.tracked, &info);\n+\t\tfor_each_string_list(add_remote_to_show_info, &states.stale, &info);\n+\t\tif (info.list->nr)\n+\t\t\tprintf(\"  Remote branch%s:%s\\n\",\n+\t\t\t       info.list->nr > 1 ? \"es\" : \"\",\n+\t\t\t\tno_query ? \" (status not queried)\" : \"\");\n+\t\tfor_each_string_list(show_remote_info_item, info.list, &info);\n+\t\tstring_list_clear(info.list, 0);\n \n-\t\tshow_list(\"  Tracked remote branch%s\", &states.tracked, \"\");\n+\t\t/* git pull info */\n+\t\tinfo.width = 0;\n+\t\tinfo.any_rebase = 0;\n+\t\tfor_each_string_list(add_local_to_show_info, &branch_list, &info);\n+\t\tif (info.list->nr)\n+\t\t\tprintf(\"  Local branch%s configured for 'git pull':\\n\",\n+\t\t\t       info.list->nr > 1 ? \"es\" : \"\");\n+\t\tfor_each_string_list(show_local_info_item, info.list, &info);\n+\t\tstring_list_clear(info.list, 0);\n \n+\t\t/* git push info */\n \t\tif (states.remote->push_refspec_nr) {\n \t\t\tprintf(\"  Local branch%s pushed with 'git push'\\n\",\n \t\t\t\tstates.remote->push_refspec_nr > 1 ?\ndiff --git a/t/t5505-remote.sh b/t/t5505-remote.sh\nindex fdc4a29..6dd971e 100755\n--- a/t/t5505-remote.sh\n+++ b/t/t5505-remote.sh\n@@ -28,7 +28,7 @@ tokens_match () {\n }\n \n check_remote_track () {\n-\tactual=$(git remote show \"$1\" | sed -e '1,/Tracked/d') &&\n+\tactual=$(git remote show \"$1\" | sed -ne 's|^    \\(.*\\) tracked$|\\1|p')\n \tshift &&\n \ttokens_match \"$*\" \"$actual\"\n }\n@@ -137,19 +137,21 @@ cat > test/expect << EOF\n * remote origin\n   URL: $(pwd)/one\n   HEAD branch: master\n-  Remote branch merged with 'git pull' while on branch master\n-    master\n-  New remote branch (next fetch will store in remotes/origin)\n-    master\n-  Tracked remote branches\n-    master\n-    side\n+  Remote branches:\n+    master new (next fetch will store in remotes/origin)\n+    side   tracked\n+  Local branches configured for 'git pull':\n+    foo    rebases onto remote master\n+    master  merges with remote master\n+    oct     merges with remote topic-a\n+               and with remote topic-b\n+               and with remote topic-c\n   Local branches pushed with 'git push'\n     master:upstream\n     +refs/tags/lastbackup\n * remote two\n   URL: ../two\n-  HEAD branches:\n+  HEAD branch (remote HEAD is ambiguous, may be one of the following):\n     another\n     master\n EOF\n@@ -159,8 +161,12 @@ test_expect_success 'show' '\n \t git config --add remote.origin.fetch \\\n \t\trefs/heads/master:refs/heads/upstream &&\n \t git fetch &&\n+\t git branch --track oct origin/master &&\n+\t git branch --track foo origin/master &&\n \t git branch -d -r origin/master &&\n \t git config --add remote.two.url ../two &&\n+\t git config branch.foo.rebase true &&\n+\t git config branch.oct.merge \"topic-a topic-b topic-c\" &&\n \t (cd ../one &&\n \t  echo 1 > file &&\n \t  test_tick &&\n@@ -170,6 +176,7 @@ test_expect_success 'show' '\n \t git config --add remote.origin.push \\\n \t\t+refs/tags/lastbackup &&\n \t git remote show origin two > output &&\n+\t git branch -d foo oct &&\n \t test_cmp expect output)\n '\n \n@@ -177,11 +184,11 @@ cat > test/expect << EOF\n * remote origin\n   URL: $(pwd)/one\n   HEAD branch: (not queried)\n-  Remote branch merged with 'git pull' while on branch master\n-    master\n-  Tracked remote branches\n+  Remote branches: (status not queried)\n     master\n     side\n+  Local branch configured for 'git pull':\n+    master merges with remote master\n   Local branches pushed with 'git push'\n     master:upstream\n     +refs/tags/lastbackup\n-- \n1.6.2.rc1.223.gfed32\n"},{"id":"105859","messageId":"3ce9371505d954095392b758061057b754a4dfa0.1235368324.git.jaysoffian@gmail.com","threadId":"17965","inReplyTo":"cover.1235368324.git.jaysoffian@gmail.com","subject":"[PATCH 08/13] refactor duplicated get_local_heads() to remote.c","fromName":"Jay Soffian","fromEmail":"jaysoffian@gmail.com","sentAt":"2009-02-23T06:28:56Z","receivedAt":"2009-02-23T06:28:56Z","isPatch":true,"sender":{"key":"jaysoffian@gmail.com","avatar":"https://avatars.githubusercontent.com/u/155970?v=4"},"body":"get_local_heads() appears to have been copied from builtin-send-pack.c\nto http-push.c via cut and paste. This patch moves the function and its\nhelper one_local_ref() to remote.c.\n\nThe two copies of one_local_ref() were not identical. I used the more\nrecent version from builtin-send-pack.c after confirming with Jeff King\nthat it was an oversight that commit 30affa1e did not update both\ncopies.\n\nSigned-off-by: Jay Soffian <jaysoffian@gmail.com>\n---\n builtin-send-pack.c |   29 ++---------------------------\n http-push.c         |   23 ++---------------------\n remote.c            |   26 ++++++++++++++++++++++++++\n remote.h            |    1 +\n 4 files changed, 31 insertions(+), 48 deletions(-)\n\ndiff --git a/builtin-send-pack.c b/builtin-send-pack.c\nindex d65d019..2fbfc29 100644\n--- a/builtin-send-pack.c\n+++ b/builtin-send-pack.c\n@@ -133,33 +133,8 @@ static int ref_newer(const unsigned char *new_sha1,\n \treturn found;\n }\n \n-static struct ref *local_refs, **local_tail;\n static struct ref *remote_refs, **remote_tail;\n \n-static int one_local_ref(const char *refname, const unsigned char *sha1, int flag, void *cb_data)\n-{\n-\tstruct ref *ref;\n-\tint len;\n-\n-\t/* we already know it starts with refs/ to get here */\n-\tif (check_ref_format(refname + 5))\n-\t\treturn 0;\n-\n-\tlen = strlen(refname) + 1;\n-\tref = xcalloc(1, sizeof(*ref) + len);\n-\thashcpy(ref->new_sha1, sha1);\n-\tmemcpy(ref->name, refname, len);\n-\t*local_tail = ref;\n-\tlocal_tail = &ref->next;\n-\treturn 0;\n-}\n-\n-static void get_local_heads(void)\n-{\n-\tlocal_tail = &local_refs;\n-\tfor_each_ref(one_local_ref, NULL);\n-}\n-\n static int receive_status(int in, struct ref *refs)\n {\n \tstruct ref *hint;\n@@ -387,7 +362,7 @@ static int refs_pushed(struct ref *ref)\n \n static int do_send_pack(int in, int out, struct remote *remote, const char *dest, int nr_refspec, const char **refspec)\n {\n-\tstruct ref *ref;\n+\tstruct ref *ref, *local_refs;\n \tint new_refs;\n \tint ask_for_status_report = 0;\n \tint allow_deleting_refs = 0;\n@@ -405,7 +380,7 @@ static int do_send_pack(int in, int out, struct remote *remote, const char *dest\n \t/* No funny business with the matcher */\n \tremote_tail = get_remote_heads(in, &remote_refs, 0, NULL, REF_NORMAL,\n \t\t\t\t       &extra_have);\n-\tget_local_heads();\n+\tlocal_refs = get_local_heads();\n \n \t/* Does the other end support the reporting? */\n \tif (server_supports(\"report-status\"))\ndiff --git a/http-push.c b/http-push.c\nindex 30d2d34..cfeed81 100644\n--- a/http-push.c\n+++ b/http-push.c\n@@ -1792,21 +1792,8 @@ static int update_remote(unsigned char *sha1, struct remote_lock *lock)\n \treturn 1;\n }\n \n-static struct ref *local_refs, **local_tail;\n static struct ref *remote_refs, **remote_tail;\n \n-static int one_local_ref(const char *refname, const unsigned char *sha1, int flag, void *cb_data)\n-{\n-\tstruct ref *ref;\n-\tint len = strlen(refname) + 1;\n-\tref = xcalloc(1, sizeof(*ref) + len);\n-\thashcpy(ref->new_sha1, sha1);\n-\tmemcpy(ref->name, refname, len);\n-\t*local_tail = ref;\n-\tlocal_tail = &ref->next;\n-\treturn 0;\n-}\n-\n static void one_remote_ref(char *refname)\n {\n \tstruct ref *ref;\n@@ -1839,12 +1826,6 @@ static void one_remote_ref(char *refname)\n \tremote_tail = &ref->next;\n }\n \n-static void get_local_heads(void)\n-{\n-\tlocal_tail = &local_refs;\n-\tfor_each_ref(one_local_ref, NULL);\n-}\n-\n static void get_dav_remote_heads(void)\n {\n \tremote_tail = &remote_refs;\n@@ -2195,7 +2176,7 @@ int main(int argc, char **argv)\n \tint rc = 0;\n \tint i;\n \tint new_refs;\n-\tstruct ref *ref;\n+\tstruct ref *ref, *local_refs;\n \tchar *rewritten_url = NULL;\n \n \tgit_extract_argv0_path(argv[0]);\n@@ -2302,7 +2283,7 @@ int main(int argc, char **argv)\n \t\tfetch_indices();\n \n \t/* Get a list of all local and remote heads to validate refspecs */\n-\tget_local_heads();\n+\tlocal_refs = get_local_heads();\n \tfprintf(stderr, \"Fetching remote heads...\\n\");\n \tget_dav_remote_heads();\n \ndiff --git a/remote.c b/remote.c\nindex 9f4821c..2c010a1 100644\n--- a/remote.c\n+++ b/remote.c\n@@ -1427,3 +1427,29 @@ struct ref *guess_remote_head(const struct ref *head,\n \n \treturn list;\n }\n+\n+static int one_local_ref(const char *refname, const unsigned char *sha1, int flag, void *cb_data)\n+{\n+\tstruct ref ***local_tail = cb_data;\n+\tstruct ref *ref;\n+\tint len;\n+\n+\t/* we already know it starts with refs/ to get here */\n+\tif (check_ref_format(refname + 5))\n+\t\treturn 0;\n+\n+\tlen = strlen(refname) + 1;\n+\tref = xcalloc(1, sizeof(*ref) + len);\n+\thashcpy(ref->new_sha1, sha1);\n+\tmemcpy(ref->name, refname, len);\n+\t**local_tail = ref;\n+\t*local_tail = &ref->next;\n+\treturn 0;\n+}\n+\n+struct ref *get_local_heads(void)\n+{\n+\tstruct ref *local_refs, **local_tail = &local_refs;\n+\tfor_each_ref(one_local_ref, &local_tail);\n+\treturn local_refs;\n+}\ndiff --git a/remote.h b/remote.h\nindex 98aeeb8..41b7ac2 100644\n--- a/remote.h\n+++ b/remote.h\n@@ -149,4 +149,5 @@ struct ref *guess_remote_head(const struct ref *head,\n \t\t\t      const struct ref *refs,\n \t\t\t      int all);\n \n+struct ref *get_local_heads(void);\n #endif\n-- \n1.6.2.rc1.223.gfed32\n"},{"id":"105862","messageId":"7f19e98ccc330d4094ffbb55ea06c35b91da9e55.1235368324.git.jaysoffian@gmail.com","threadId":"17965","inReplyTo":"cover.1235368324.git.jaysoffian@gmail.com","subject":"[PATCH 09/13] refactor duplicated ref_newer() to remote.c","fromName":"Jay Soffian","fromEmail":"jaysoffian@gmail.com","sentAt":"2009-02-23T06:28:57Z","receivedAt":"2009-02-23T06:28:57Z","isPatch":true,"sender":{"key":"jaysoffian@gmail.com","avatar":"https://avatars.githubusercontent.com/u/155970?v=4"},"body":"ref_newer() appears to have been copied from builtin-send-pack.c to\nhttp-push.c via cut and paste. This patch moves the function and its\nhelper unmark_and_free() to remote.c.\n\nSigned-off-by: Jay Soffian <jaysoffian@gmail.com>\n---\nHmm, I just noticed that the version in builtin-send-pack.c uses 1\nwhereas http-push.c uses TMP_MARK as the mark argument. I used the\nversion from builtin-send-pack.c. I don't know if this is signfificant.\n\n builtin-send-pack.c |   49 -------------------------------------------------\n http-push.c         |   49 -------------------------------------------------\n remote.c            |   49 +++++++++++++++++++++++++++++++++++++++++++++++++\n remote.h            |    1 +\n 4 files changed, 50 insertions(+), 98 deletions(-)\n\ndiff --git a/builtin-send-pack.c b/builtin-send-pack.c\nindex 2fbfc29..186cecb 100644\n--- a/builtin-send-pack.c\n+++ b/builtin-send-pack.c\n@@ -84,55 +84,6 @@ static int pack_objects(int fd, struct ref *refs, struct extra_have_objects *ext\n \treturn 0;\n }\n \n-static void unmark_and_free(struct commit_list *list, unsigned int mark)\n-{\n-\twhile (list) {\n-\t\tstruct commit_list *temp = list;\n-\t\ttemp->item->object.flags &= ~mark;\n-\t\tlist = temp->next;\n-\t\tfree(temp);\n-\t}\n-}\n-\n-static int ref_newer(const unsigned char *new_sha1,\n-\t\t     const unsigned char *old_sha1)\n-{\n-\tstruct object *o;\n-\tstruct commit *old, *new;\n-\tstruct commit_list *list, *used;\n-\tint found = 0;\n-\n-\t/* Both new and old must be commit-ish and new is descendant of\n-\t * old.  Otherwise we require --force.\n-\t */\n-\to = deref_tag(parse_object(old_sha1), NULL, 0);\n-\tif (!o || o->type != OBJ_COMMIT)\n-\t\treturn 0;\n-\told = (struct commit *) o;\n-\n-\to = deref_tag(parse_object(new_sha1), NULL, 0);\n-\tif (!o || o->type != OBJ_COMMIT)\n-\t\treturn 0;\n-\tnew = (struct commit *) o;\n-\n-\tif (parse_commit(new) < 0)\n-\t\treturn 0;\n-\n-\tused = list = NULL;\n-\tcommit_list_insert(new, &list);\n-\twhile (list) {\n-\t\tnew = pop_most_recent_commit(&list, 1);\n-\t\tcommit_list_insert(new, &used);\n-\t\tif (new == old) {\n-\t\t\tfound = 1;\n-\t\t\tbreak;\n-\t\t}\n-\t}\n-\tunmark_and_free(list, 1);\n-\tunmark_and_free(used, 1);\n-\treturn found;\n-}\n-\n static struct ref *remote_refs, **remote_tail;\n \n static int receive_status(int in, struct ref *refs)\ndiff --git a/http-push.c b/http-push.c\nindex cfeed81..392533a 100644\n--- a/http-push.c\n+++ b/http-push.c\n@@ -1843,55 +1843,6 @@ static int is_zero_sha1(const unsigned char *sha1)\n \treturn 1;\n }\n \n-static void unmark_and_free(struct commit_list *list, unsigned int mark)\n-{\n-\twhile (list) {\n-\t\tstruct commit_list *temp = list;\n-\t\ttemp->item->object.flags &= ~mark;\n-\t\tlist = temp->next;\n-\t\tfree(temp);\n-\t}\n-}\n-\n-static int ref_newer(const unsigned char *new_sha1,\n-\t\t     const unsigned char *old_sha1)\n-{\n-\tstruct object *o;\n-\tstruct commit *old, *new;\n-\tstruct commit_list *list, *used;\n-\tint found = 0;\n-\n-\t/* Both new and old must be commit-ish and new is descendant of\n-\t * old.  Otherwise we require --force.\n-\t */\n-\to = deref_tag(parse_object(old_sha1), NULL, 0);\n-\tif (!o || o->type != OBJ_COMMIT)\n-\t\treturn 0;\n-\told = (struct commit *) o;\n-\n-\to = deref_tag(parse_object(new_sha1), NULL, 0);\n-\tif (!o || o->type != OBJ_COMMIT)\n-\t\treturn 0;\n-\tnew = (struct commit *) o;\n-\n-\tif (parse_commit(new) < 0)\n-\t\treturn 0;\n-\n-\tused = list = NULL;\n-\tcommit_list_insert(new, &list);\n-\twhile (list) {\n-\t\tnew = pop_most_recent_commit(&list, TMP_MARK);\n-\t\tcommit_list_insert(new, &used);\n-\t\tif (new == old) {\n-\t\t\tfound = 1;\n-\t\t\tbreak;\n-\t\t}\n-\t}\n-\tunmark_and_free(list, TMP_MARK);\n-\tunmark_and_free(used, TMP_MARK);\n-\treturn found;\n-}\n-\n static void add_remote_info_ref(struct remote_ls_ctx *ls)\n {\n \tstruct strbuf *buf = (struct strbuf *)ls->userData;\ndiff --git a/remote.c b/remote.c\nindex 2c010a1..5cb443f 100644\n--- a/remote.c\n+++ b/remote.c\n@@ -5,6 +5,7 @@\n #include \"diff.h\"\n #include \"revision.h\"\n #include \"dir.h\"\n+#include \"tag.h\"\n \n static struct refspec s_tag_refspec = {\n \t0,\n@@ -1271,6 +1272,54 @@ int resolve_remote_symref(struct ref *ref, struct ref *list)\n \treturn 1;\n }\n \n+static void unmark_and_free(struct commit_list *list, unsigned int mark)\n+{\n+\twhile (list) {\n+\t\tstruct commit_list *temp = list;\n+\t\ttemp->item->object.flags &= ~mark;\n+\t\tlist = temp->next;\n+\t\tfree(temp);\n+\t}\n+}\n+\n+int ref_newer(const unsigned char *new_sha1, const unsigned char *old_sha1)\n+{\n+\tstruct object *o;\n+\tstruct commit *old, *new;\n+\tstruct commit_list *list, *used;\n+\tint found = 0;\n+\n+\t/* Both new and old must be commit-ish and new is descendant of\n+\t * old.  Otherwise we require --force.\n+\t */\n+\to = deref_tag(parse_object(old_sha1), NULL, 0);\n+\tif (!o || o->type != OBJ_COMMIT)\n+\t\treturn 0;\n+\told = (struct commit *) o;\n+\n+\to = deref_tag(parse_object(new_sha1), NULL, 0);\n+\tif (!o || o->type != OBJ_COMMIT)\n+\t\treturn 0;\n+\tnew = (struct commit *) o;\n+\n+\tif (parse_commit(new) < 0)\n+\t\treturn 0;\n+\n+\tused = list = NULL;\n+\tcommit_list_insert(new, &list);\n+\twhile (list) {\n+\t\tnew = pop_most_recent_commit(&list, 1);\n+\t\tcommit_list_insert(new, &used);\n+\t\tif (new == old) {\n+\t\t\tfound = 1;\n+\t\t\tbreak;\n+\t\t}\n+\t}\n+\tunmark_and_free(list, 1);\n+\tunmark_and_free(used, 1);\n+\treturn found;\n+}\n+\n /*\n  * Return true if there is anything to report, otherwise false.\n  */\ndiff --git a/remote.h b/remote.h\nindex 41b7ac2..e14d041 100644\n--- a/remote.h\n+++ b/remote.h\n@@ -76,6 +76,7 @@ int check_ref_type(const struct ref *ref, int flags);\n void free_refs(struct ref *ref);\n \n int resolve_remote_symref(struct ref *ref, struct ref *list);\n+int ref_newer(const unsigned char *new_sha1, const unsigned char *old_sha1);\n \n /*\n  * Removes and frees any duplicate refs in the map.\n-- \n1.6.2.rc1.223.gfed32\n"},{"id":"105865","messageId":"75e083170cea799499bf66792a1c3950b29d6021.1235368324.git.jaysoffian@gmail.com","threadId":"17965","inReplyTo":"cover.1235368324.git.jaysoffian@gmail.com","subject":"[PATCH 10/13] remote.c: make match_refs() copy src ref before assigning to peer_ref","fromName":"Jay Soffian","fromEmail":"jaysoffian@gmail.com","sentAt":"2009-02-23T06:28:58Z","receivedAt":"2009-02-23T06:28:58Z","isPatch":true,"sender":{"key":"jaysoffian@gmail.com","avatar":"https://avatars.githubusercontent.com/u/155970?v=4"},"body":"In some instances, match_refs() was setting the peer_ref field in the\ndst ref list such that it pointed to a ref in the src list, instead of\nto a copy. This would cause a double-free when both the src and dst ref\nlists were freed, as free_refs() frees the peer_ref. A double-free would\nalso occur if the same branch was pushed to two different destinations\nsuch as:\n\n  push = refs/heads/master:refs/heads/backup\n  push = refs/heads/master:refs/heads/master\n\nThis patch corrects the problem by copying the ref when it has been\nplucked from the src list.\n\nSigned-off-by: Jay Soffian <jaysoffian@gmail.com>\n---\n remote.c |    7 +++++--\n 1 files changed, 5 insertions(+), 2 deletions(-)\n\ndiff --git a/remote.c b/remote.c\nindex 5cb443f..ab387f2 100644\n--- a/remote.c\n+++ b/remote.c\n@@ -930,6 +930,7 @@ static int match_explicit(struct ref *src, struct ref *dst,\n \t\t\t  struct refspec *rs)\n {\n \tstruct ref *matched_src, *matched_dst;\n+\tint copy_src;\n \n \tconst char *dst_value = rs->dst;\n \tchar *dst_guess;\n@@ -940,6 +941,7 @@ static int match_explicit(struct ref *src, struct ref *dst,\n \tmatched_src = matched_dst = NULL;\n \tswitch (count_refspec_match(rs->src, src, &matched_src)) {\n \tcase 1:\n+\t\tcopy_src = 1;\n \t\tbreak;\n \tcase 0:\n \t\t/* The source could be in the get_sha1() format\n@@ -949,6 +951,7 @@ static int match_explicit(struct ref *src, struct ref *dst,\n \t\tmatched_src = try_explicit_object_name(rs->src);\n \t\tif (!matched_src)\n \t\t\treturn error(\"src refspec %s does not match any.\", rs->src);\n+\t\tcopy_src = 0;\n \t\tbreak;\n \tdefault:\n \t\treturn error(\"src refspec %s matches more than one.\", rs->src);\n@@ -994,7 +997,7 @@ static int match_explicit(struct ref *src, struct ref *dst,\n \t\treturn error(\"dst ref %s receives from more than one src.\",\n \t\t      matched_dst->name);\n \telse {\n-\t\tmatched_dst->peer_ref = matched_src;\n+\t\tmatched_dst->peer_ref = copy_src ? copy_ref(matched_src) : matched_src;\n \t\tmatched_dst->force = rs->force;\n \t}\n \treturn 0;\n@@ -1102,7 +1105,7 @@ int match_refs(struct ref *src, struct ref *dst, struct ref ***dst_tail,\n \t\t\tdst_peer = make_linked_ref(dst_name, dst_tail);\n \t\t\thashcpy(dst_peer->new_sha1, src->new_sha1);\n \t\t}\n-\t\tdst_peer->peer_ref = src;\n+\t\tdst_peer->peer_ref = copy_ref(src);\n \t\tdst_peer->force = pat->force;\n \tfree_name:\n \t\tfree(dst_name);\n-- \n1.6.2.rc1.223.gfed32\n"},{"id":"105864","messageId":"6cbc71876488bd7e14db40560459c0e1b8ae7b37.1235368324.git.jaysoffian@gmail.com","threadId":"17965","inReplyTo":"cover.1235368324.git.jaysoffian@gmail.com","subject":"[PATCH 11/13] remote.c: don't short-circuit match_refs() when error in match_explicit_refs()","fromName":"Jay Soffian","fromEmail":"jaysoffian@gmail.com","sentAt":"2009-02-23T06:28:59Z","receivedAt":"2009-02-23T06:28:59Z","isPatch":true,"sender":{"key":"jaysoffian@gmail.com","avatar":"https://avatars.githubusercontent.com/u/155970?v=4"},"body":"match_refs() returns non-zero if there is an error in\nmatch_explicit_refs(), without handling any remaining pattern ref specs.\n\nIts existing callers exit upon receiving non-zero, so a partial result\nis of no consequence to them; however it is about to have a new caller\nthat is interested in the complete result even if there are errors in\nmatch_explicit_refs().\n\nSigned-off-by: Jay Soffian <jaysoffian@gmail.com>\n---\n remote.c |    6 ++++--\n 1 files changed, 4 insertions(+), 2 deletions(-)\n\ndiff --git a/remote.c b/remote.c\nindex ab387f2..5c14343 100644\n--- a/remote.c\n+++ b/remote.c\n@@ -1046,6 +1046,7 @@ int match_refs(struct ref *src, struct ref *dst, struct ref ***dst_tail,\n \tstruct refspec *rs;\n \tint send_all = flags & MATCH_REFS_ALL;\n \tint send_mirror = flags & MATCH_REFS_MIRROR;\n+\tint errs;\n \tstatic const char *default_refspec[] = { \":\", 0 };\n \n \tif (!nr_refspec) {\n@@ -1053,8 +1054,7 @@ int match_refs(struct ref *src, struct ref *dst, struct ref ***dst_tail,\n \t\trefspec = default_refspec;\n \t}\n \trs = parse_push_refspec(nr_refspec, (const char **) refspec);\n-\tif (match_explicit_refs(src, dst, dst_tail, rs, nr_refspec))\n-\t\treturn -1;\n+\terrs = match_explicit_refs(src, dst, dst_tail, rs, nr_refspec);\n \n \t/* pick the remainder */\n \tfor ( ; src; src = src->next) {\n@@ -1110,6 +1110,8 @@ int match_refs(struct ref *src, struct ref *dst, struct ref ***dst_tail,\n \tfree_name:\n \t\tfree(dst_name);\n \t}\n+\tif (errs)\n+\t\treturn -1;\n \treturn 0;\n }\n \n-- \n1.6.2.rc1.223.gfed32\n"},{"id":"105860","messageId":"885507eaf920f6b60727db7e712da3560a7fd4c5.1235368324.git.jaysoffian@gmail.com","threadId":"17965","inReplyTo":"cover.1235368324.git.jaysoffian@gmail.com","subject":"[PATCH 12/13] remote.c: refactor get_remote_ref_states()","fromName":"Jay Soffian","fromEmail":"jaysoffian@gmail.com","sentAt":"2009-02-23T06:29:00Z","receivedAt":"2009-02-23T06:29:00Z","isPatch":true,"sender":{"key":"jaysoffian@gmail.com","avatar":"https://avatars.githubusercontent.com/u/155970?v=4"},"body":"get_remote_ref_states() has three callers, but each is interested in\nslightly different information. Give it a bit-field flag so that callers\ncan specify which pieces of information they need.\n\nSigned-off-by: Jay Soffian <jaysoffian@gmail.com>\n---\n builtin-remote.c |   23 +++++++++++++++--------\n 1 files changed, 15 insertions(+), 8 deletions(-)\n\ndiff --git a/builtin-remote.c b/builtin-remote.c\nindex 4975a0e..327667a 100644\n--- a/builtin-remote.c\n+++ b/builtin-remote.c\n@@ -19,6 +19,9 @@ static const char * const builtin_remote_usage[] = {\n \tNULL\n };\n \n+#define GET_REF_STATES (1<<0)\n+#define GET_HEAD_NAMES (1<<1)\n+\n static int verbose;\n \n static int show_all(void);\n@@ -685,14 +688,15 @@ static int get_remote_ref_states(const char *name,\n \t\t\tstates->remote->url[0] : NULL);\n \t\tremote_refs = transport_get_remote_refs(transport);\n \t\ttransport_disconnect(transport);\n-\t\tget_head_names(remote_refs, name, states);\n-\t\tget_ref_states(remote_refs, states);\n+\t\tstates->queried = 1;\n+\t\tif (query & GET_REF_STATES)\n+\t\t\tget_ref_states(remote_refs, states);\n+\t\tif (query & GET_HEAD_NAMES)\n+\t\t\tget_head_names(remote_refs, name, states);\n \t} else {\n \t\tfor_each_ref(append_ref_to_tracked_list, states);\n \t\tsort_string_list(&states->tracked);\n \t}\n-\tstates->queried = query;\n-\n \treturn 0;\n }\n \n@@ -796,7 +800,7 @@ int show_local_info_item(struct string_list_item *item, void *cb_data)\n \n static int show(int argc, const char **argv)\n {\n-\tint no_query = 0, result = 0;\n+\tint no_query = 0, result = 0, query_flag = 0;\n \tstruct option options[] = {\n \t\tOPT_GROUP(\"show specific options\"),\n \t\tOPT_BOOLEAN('n', NULL, &no_query, \"do not query remotes\"),\n@@ -811,6 +815,9 @@ static int show(int argc, const char **argv)\n \tif (argc < 1)\n \t\treturn show_all();\n \n+\tif (!no_query)\n+\t\tquery_flag = (GET_REF_STATES | GET_HEAD_NAMES);\n+\n \tmemset(&states, 0, sizeof(states));\n \tmemset(&info, 0, sizeof(info));\n \tinfo.states = &states;\n@@ -818,7 +825,7 @@ static int show(int argc, const char **argv)\n \tfor (; argc; argc--, argv++) {\n \t\tint i;\n \n-\t\tget_remote_ref_states(*argv, &states, !no_query);\n+\t\tget_remote_ref_states(*argv, &states, query_flag);\n \n \t\tprintf(\"* remote %s\\n  URL: %s\\n\", *argv,\n \t\t\tstates.remote->url_nr > 0 ?\n@@ -902,7 +909,7 @@ static int set_head(int argc, const char **argv)\n \t} else if (opt_a && !opt_d && argc == 1) {\n \t\tstruct ref_states states;\n \t\tmemset(&states, 0, sizeof(states));\n-\t\tget_remote_ref_states(argv[0], &states, 1);\n+\t\tget_remote_ref_states(argv[0], &states, GET_HEAD_NAMES);\n \t\tif (!states.heads.nr)\n \t\t\tresult |= error(\"Cannot determine remote HEAD\");\n \t\telse if (states.heads.nr > 1) {\n@@ -962,7 +969,7 @@ static int prune(int argc, const char **argv)\n \tfor (; argc; argc--, argv++) {\n \t\tint i;\n \n-\t\tget_remote_ref_states(*argv, &states, 1);\n+\t\tget_remote_ref_states(*argv, &states, GET_REF_STATES);\n \n \t\tif (states.stale.nr) {\n \t\t\tprintf(\"Pruning %s\\n\", *argv);\n-- \n1.6.2.rc1.223.gfed32\n"},{"id":"105863","messageId":"1100286055de1ac271e8e5c060405fd358dab601.1235368324.git.jaysoffian@gmail.com","threadId":"17965","inReplyTo":"cover.1235368324.git.jaysoffian@gmail.com","subject":"[PATCH 13/13] remote: new show output style for push refspecs","fromName":"Jay Soffian","fromEmail":"jaysoffian@gmail.com","sentAt":"2009-02-23T06:29:01Z","receivedAt":"2009-02-23T06:29:01Z","isPatch":true,"sender":{"key":"jaysoffian@gmail.com","avatar":"https://avatars.githubusercontent.com/u/155970?v=4"},"body":"The existing output of \"git remote show <remote>\" with respect to push\nref specs is basically just to show the raw refspec. This patch teaches\nthe command to interpret the refspecs and show how each branch will be\npushed to the destination. The output gives the user an idea of what\n\"git push\" should do if it is run w/o any arguments.\n\nExample new output:\n\n1a. Typical output with no push refspec (i.e. matching branches only)\n\n$ git remote show origin\n* remote origin\n  [...]\n  Local refs configured for 'git push':\n    master pushes to master (up to date)\n    next   pushes to next   (local out of date)\n\n1b. Same as above, w/o querying the remote:\n\n$ git remote show origin -n\n* remote origin\n  [...]\n  Local ref configured for 'git push' (status not queried):\n    (matching) pushes to (matching)\n\n2a. With a forcing refspec (+), and a new topic\n    (something like push = refs/heads/*:refs/heads/*):\n\n$ git remote show origin\n* remote origin\n  [...]\n  Local refs configured for 'git push':\n    master     pushes to master    (fast forwardable)\n    new-topic  pushes to new-topic (create)\n    next       pushes to next      (local out of date)\n    pu         forces to pu        (up to date)\n\n2b. Same as above, w/o querying the remote\n\n$ git remote show origin -n\n* remote origin\n  [...]\n  Local refs configured for 'git push' (status not queried):\n    master     pushes to master\n    new-topic  pushes to new-topic\n    next       pushes to next\n    pu         forces to pu\n\n3. With a remote configured as a mirror:\n\n* remote backup\n  [...]\n  Local refs will be mirrored by 'git push'\n\nSigned-off-by: Jay Soffian <jaysoffian@gmail.com>\n---\nAfter spending quite a long time standing in the paint aisle looking\nat all the different colors, this is my favorite.\n\nYou might like a different color paint. For example, an obvious choice\nmight seem to be single character status fields a-la ls-files. But that\nwould sacrifice clarity (IMO) as the user then has to go lookup what the\nvalues mean in a man page, and in any case wouldn't be' consistent with\nthe rest of the new \"show\" output.\n\nAlso, \"forces to\" may sound a little funny, but I think it is obvious\nwhat it means and lines up more nicely than \"force pushes\" or any other\nchoice I considered.\n\nAnyway, I built this new shed, so I get to pick the color. (And\nhopefully no one blows it up w/a stick of dynamite) :-)\n\n builtin-remote.c  |  201 ++++++++++++++++++++++++++++++++++++++++++++++++----\n t/t5505-remote.sh |   57 +++++++++------\n 2 files changed, 219 insertions(+), 39 deletions(-)\n\ndiff --git a/builtin-remote.c b/builtin-remote.c\nindex 327667a..ac49219 100644\n--- a/builtin-remote.c\n+++ b/builtin-remote.c\n@@ -21,6 +21,7 @@ static const char * const builtin_remote_usage[] = {\n \n #define GET_REF_STATES (1<<0)\n #define GET_HEAD_NAMES (1<<1)\n+#define GET_PUSH_REF_STATES (1<<2)\n \n static int verbose;\n \n@@ -220,7 +221,7 @@ static void read_branches(void)\n \n struct ref_states {\n \tstruct remote *remote;\n-\tstruct string_list new, stale, tracked, heads;\n+\tstruct string_list new, stale, tracked, push, heads;\n \tint queried;\n };\n \n@@ -275,6 +276,112 @@ static int get_ref_states(const struct ref *remote_refs, struct ref_states *stat\n \treturn 0;\n }\n \n+struct push_info {\n+\tchar *dest;\n+\tint forced;\n+\tenum {\n+\t\tPUSH_STATUS_CREATE = 0,\n+\t\tPUSH_STATUS_DELETE,\n+\t\tPUSH_STATUS_UPTODATE,\n+\t\tPUSH_STATUS_FASTFORWARD,\n+\t\tPUSH_STATUS_OUTOFDATE,\n+\t\tPUSH_STATUS_NOTQUERIED,\n+\t} status;\n+};\n+\n+static int get_push_ref_states(const struct ref *remote_refs,\n+\tstruct ref_states *states)\n+{\n+\tstruct remote *remote = states->remote;\n+\tstruct ref *ref, *local_refs, *push_map, **push_tail;\n+\tif (remote->mirror)\n+\t\treturn 0;\n+\n+\tlocal_refs = get_local_heads();\n+\tref = push_map = copy_ref_list(remote_refs);\n+\twhile (ref->next)\n+\t\tref = ref->next;\n+\tpush_tail = &ref->next;\n+\n+\tmatch_refs(local_refs, push_map, &push_tail, remote->push_refspec_nr,\n+\t\t   remote->push_refspec, MATCH_REFS_NONE);\n+\n+\tstates->push.strdup_strings = 1;\n+\tfor (ref = push_map; ref; ref = ref->next) {\n+\t\tstruct string_list_item *item;\n+\t\tstruct push_info *info;\n+\n+\t\tif (!ref->peer_ref)\n+\t\t\tcontinue;\n+\t\thashcpy(ref->new_sha1, ref->peer_ref->new_sha1);\n+\n+\t\titem = string_list_append(abbrev_branch(ref->peer_ref->name),\n+\t\t\t\t\t  &states->push);\n+\t\titem->util = xcalloc(sizeof(struct push_info), 1);\n+\t\tinfo = item->util;\n+\t\tinfo->forced = ref->force;\n+\t\tinfo->dest = xstrdup(abbrev_branch(ref->name));\n+\n+\t\tif (is_null_sha1(ref->new_sha1)) {\n+\t\t\tinfo->status = PUSH_STATUS_DELETE;\n+\t\t} else if (!hashcmp(ref->old_sha1, ref->new_sha1))\n+\t\t\tinfo->status = PUSH_STATUS_UPTODATE;\n+\t\telse if (is_null_sha1(ref->old_sha1))\n+\t\t\tinfo->status = PUSH_STATUS_CREATE;\n+\t\telse if (has_sha1_file(ref->old_sha1) &&\n+\t\t\t ref_newer(ref->new_sha1, ref->old_sha1))\n+\t\t\tinfo->status = PUSH_STATUS_FASTFORWARD;\n+\t\telse\n+\t\t\tinfo->status = PUSH_STATUS_OUTOFDATE;\n+\t\t// ref->peer_ref = NULL; /* local ref which is freed below */\n+\t}\n+\tfree_refs(local_refs);\n+\tfree_refs(push_map);\n+\treturn 0;\n+}\n+\n+static int get_push_ref_states_noquery(struct ref_states *states)\n+{\n+\tint i;\n+\tstruct remote *remote = states->remote;\n+\tstruct string_list_item *item;\n+\tstruct push_info *info;\n+\n+\tif (remote->mirror)\n+\t\treturn 0;\n+\n+\tstates->push.strdup_strings = 1;\n+\tif (!remote->push_refspec_nr) {\n+\t\titem = string_list_append(\"(matching)\", &states->push);\n+\t\tinfo = item->util = xcalloc(sizeof(struct push_info), 1);\n+\t\tinfo->status = PUSH_STATUS_NOTQUERIED;\n+\t\tinfo->dest = xstrdup(item->string);\n+\t}\n+\tfor (i = 0; i < remote->push_refspec_nr; i++) {\n+\t\tstruct refspec *spec = remote->push + i;\n+\t\tchar buf[PATH_MAX];\n+\t\tif (spec->matching)\n+\t\t\titem = string_list_append(\"(matching)\", &states->push);\n+\t\telse if (spec->pattern) {\n+\t\t\tsnprintf(buf, (sizeof(buf)), \"%s*\", spec->src);\n+\t\t\titem = string_list_append(buf, &states->push);\n+\t\t\tsnprintf(buf, (sizeof(buf)), \"%s*\", spec->dst);\n+\t\t} else if (strlen(spec->src))\n+\t\t\titem = string_list_append(spec->src, &states->push);\n+\t\telse\n+\t\t\titem = string_list_append(\"(delete)\", &states->push);\n+\n+\t\tinfo = item->util = xcalloc(sizeof(struct push_info), 1);\n+\t\tinfo->forced = spec->force;\n+\t\tinfo->status = PUSH_STATUS_NOTQUERIED;\n+\t\tif (spec->pattern)\n+\t\t\tinfo->dest = xstrdup(buf);\n+\t\telse\n+\t\t\tinfo->dest = xstrdup(spec->dst ? spec->dst : item->string);\n+\t}\n+\treturn 0;\n+}\n+\n static int get_head_names(const struct ref *remote_refs,\n \tconst char *remote_name, struct ref_states *states)\n {\n@@ -645,12 +752,20 @@ static int rm(int argc, const char **argv)\n \treturn result;\n }\n \n+void clear_push_info(void *util, const char *string)\n+{\n+\tstruct push_info *info = util;\n+\tfree(info->dest);\n+\tfree(info);\n+}\n+\n static void free_remote_ref_states(struct ref_states *states)\n {\n \tstring_list_clear(&states->new, 0);\n \tstring_list_clear(&states->stale, 0);\n \tstring_list_clear(&states->tracked, 0);\n \tstring_list_clear(&states->heads, 0);\n+\tstring_list_clear_func(&states->push, clear_push_info);\n }\n \n static int append_ref_to_tracked_list(const char *refname,\n@@ -693,9 +808,12 @@ static int get_remote_ref_states(const char *name,\n \t\t\tget_ref_states(remote_refs, states);\n \t\tif (query & GET_HEAD_NAMES)\n \t\t\tget_head_names(remote_refs, name, states);\n+\t\tif (query & GET_PUSH_REF_STATES)\n+\t\t\tget_push_ref_states(remote_refs, states);\n \t} else {\n \t\tfor_each_ref(append_ref_to_tracked_list, states);\n \t\tsort_string_list(&states->tracked);\n+\t\tget_push_ref_states_noquery(states);\n \t}\n \treturn 0;\n }\n@@ -703,7 +821,7 @@ static int get_remote_ref_states(const char *name,\n struct show_info {\n \tstruct string_list *list;\n \tstruct ref_states *states;\n-\tint width;\n+\tint width, width2;\n \tint any_rebase;\n };\n \n@@ -798,6 +916,58 @@ int show_local_info_item(struct string_list_item *item, void *cb_data)\n \treturn 0;\n }\n \n+int add_push_to_show_info(struct string_list_item *push_item, void *cb_data)\n+{\n+\tstruct show_info *show_info = cb_data;\n+\tstruct push_info *push_info = push_item->util;\n+\tstruct string_list_item *item;\n+\tint n;\n+\tif ((n = strlen(push_item->string)) > show_info->width)\n+\t\tshow_info->width = n;\n+\tif ((n = strlen(push_info->dest)) > show_info->width2)\n+\t\tshow_info->width2 = n;\n+\titem = string_list_append(push_item->string, show_info->list);\n+\titem->util = push_item->util;\n+\treturn 0;\n+}\n+\n+int show_push_info_item(struct string_list_item *item, void *cb_data)\n+{\n+\tstruct show_info *show_info = cb_data;\n+\tstruct push_info *push_info = item->util;\n+\tchar *src = item->string, *status = NULL;\n+\n+\tswitch (push_info->status) {\n+\tcase PUSH_STATUS_CREATE:\n+\t\tstatus = \"create\";\n+\t\tbreak;\n+\tcase PUSH_STATUS_DELETE:\n+\t\tstatus = \"delete\";\n+\t\tsrc = \"(none)\";\n+\t\tbreak;\n+\tcase PUSH_STATUS_UPTODATE:\n+\t\tstatus = \"up to date\";\n+\t\tbreak;\n+\tcase PUSH_STATUS_FASTFORWARD:\n+\t\tstatus = \"fast forwardable\";\n+\t\tbreak;\n+\tcase PUSH_STATUS_OUTOFDATE:\n+\t\tstatus = \"local out of date\";\n+\t\tbreak;\n+\tcase PUSH_STATUS_NOTQUERIED:\n+\t\tbreak;\n+\t}\n+\tif (status)\n+\t\tprintf(\"    %-*s %s to %-*s (%s)\\n\", show_info->width, src,\n+\t\t\tpush_info->forced ? \"forces\" : \"pushes\",\n+\t\t\tshow_info->width2, push_info->dest, status);\n+\telse\n+\t\tprintf(\"    %-*s %s to %s\\n\", show_info->width, src,\n+\t\t\tpush_info->forced ? \"forces\" : \"pushes\",\n+\t\t\tpush_info->dest);\n+\treturn 0;\n+}\n+\n static int show(int argc, const char **argv)\n {\n \tint no_query = 0, result = 0, query_flag = 0;\n@@ -816,7 +986,7 @@ static int show(int argc, const char **argv)\n \t\treturn show_all();\n \n \tif (!no_query)\n-\t\tquery_flag = (GET_REF_STATES | GET_HEAD_NAMES);\n+\t\tquery_flag = (GET_REF_STATES | GET_HEAD_NAMES | GET_PUSH_REF_STATES);\n \n \tmemset(&states, 0, sizeof(states));\n \tmemset(&info, 0, sizeof(info));\n@@ -866,19 +1036,18 @@ static int show(int argc, const char **argv)\n \t\tstring_list_clear(info.list, 0);\n \n \t\t/* git push info */\n-\t\tif (states.remote->push_refspec_nr) {\n-\t\t\tprintf(\"  Local branch%s pushed with 'git push'\\n\",\n-\t\t\t\tstates.remote->push_refspec_nr > 1 ?\n-\t\t\t\t\t\"es\" : \"\");\n-\t\t\tfor (i = 0; i < states.remote->push_refspec_nr; i++) {\n-\t\t\t\tstruct refspec *spec = states.remote->push + i;\n-\t\t\t\tprintf(\"    %s%s%s%s\\n\",\n-\t\t\t\t       spec->force ? \"+\" : \"\",\n-\t\t\t\t       abbrev_branch(spec->src),\n-\t\t\t\t       spec->dst ? \":\" : \"\",\n-\t\t\t\t       spec->dst ? abbrev_branch(spec->dst) : \"\");\n-\t\t\t}\n-\t\t}\n+\t\tif (states.remote->mirror)\n+\t\t\tprintf(\"  Local refs will be mirrored by 'git push'\\n\");\n+\n+\t\tinfo.width = info.width2 = 0;\n+\t\tfor_each_string_list(add_push_to_show_info, &states.push, &info);\n+\t\tsort_string_list(info.list);\n+\t\tif (info.list->nr)\n+\t\t\tprintf(\"  Local ref%s configured for 'git push'%s:\\n\",\n+\t\t\t\tinfo.list->nr > 1 ? \"s\" : \"\",\n+\t\t\t\tno_query ? \" (status not queried)\" : \"\");\n+\t\tfor_each_string_list(show_push_info_item, info.list, &info);\n+\t\tstring_list_clear(info.list, 0);\n \n \t\tfree_remote_ref_states(&states);\n \t}\ndiff --git a/t/t5505-remote.sh b/t/t5505-remote.sh\nindex 6dd971e..95012e7 100755\n--- a/t/t5505-remote.sh\n+++ b/t/t5505-remote.sh\n@@ -141,42 +141,51 @@ cat > test/expect << EOF\n     master new (next fetch will store in remotes/origin)\n     side   tracked\n   Local branches configured for 'git pull':\n-    foo    rebases onto remote master\n-    master  merges with remote master\n-    oct     merges with remote topic-a\n-               and with remote topic-b\n-               and with remote topic-c\n-  Local branches pushed with 'git push'\n-    master:upstream\n-    +refs/tags/lastbackup\n+    ahead    merges with remote master\n+    master   merges with remote master\n+    octopus  merges with remote topic-a\n+                and with remote topic-b\n+                and with remote topic-c\n+    rebase  rebases onto remote master\n+  Local refs configured for 'git push':\n+    master pushes to master   (local out of date)\n+    master pushes to upstream (create)\n * remote two\n   URL: ../two\n   HEAD branch (remote HEAD is ambiguous, may be one of the following):\n     another\n     master\n+  Local refs configured for 'git push':\n+    ahead  forces to master  (fast forwardable)\n+    master pushes to another (up to date)\n EOF\n \n test_expect_success 'show' '\n \t(cd test &&\n-\t git config --add remote.origin.fetch \\\n-\t\trefs/heads/master:refs/heads/upstream &&\n+\t git config --add remote.origin.fetch refs/heads/master:refs/heads/upstream &&\n \t git fetch &&\n-\t git branch --track oct origin/master &&\n-\t git branch --track foo origin/master &&\n+\t git checkout -b ahead origin/master &&\n+\t echo 1 >> file &&\n+\t test_tick &&\n+\t git commit -m update file &&\n+\t git checkout master &&\n+\t git branch --track octopus origin/master &&\n+\t git branch --track rebase origin/master &&\n \t git branch -d -r origin/master &&\n \t git config --add remote.two.url ../two &&\n-\t git config branch.foo.rebase true &&\n-\t git config branch.oct.merge \"topic-a topic-b topic-c\" &&\n+\t git config branch.rebase.rebase true &&\n+\t git config branch.octopus.merge \"topic-a topic-b topic-c\" &&\n \t (cd ../one &&\n \t  echo 1 > file &&\n \t  test_tick &&\n \t  git commit -m update file) &&\n-\t git config remote.origin.push \\\n-\t\trefs/heads/master:refs/heads/upstream &&\n-\t git config --add remote.origin.push \\\n-\t\t+refs/tags/lastbackup &&\n+\t git config --add remote.origin.push : &&\n+\t git config --add remote.origin.push refs/heads/master:refs/heads/upstream &&\n+\t git config --add remote.origin.push +refs/tags/lastbackup &&\n+\t git config --add remote.two.push +refs/heads/ahead:refs/heads/master &&\n+\t git config --add remote.two.push refs/heads/master:refs/heads/another &&\n \t git remote show origin two > output &&\n-\t git branch -d foo oct &&\n+\t git branch -d rebase octopus &&\n \t test_cmp expect output)\n '\n \n@@ -187,11 +196,13 @@ cat > test/expect << EOF\n   Remote branches: (status not queried)\n     master\n     side\n-  Local branch configured for 'git pull':\n+  Local branches configured for 'git pull':\n+    ahead  merges with remote master\n     master merges with remote master\n-  Local branches pushed with 'git push'\n-    master:upstream\n-    +refs/tags/lastbackup\n+  Local refs configured for 'git push' (status not queried):\n+    (matching)           pushes to (matching)\n+    refs/heads/master    pushes to refs/heads/upstream\n+    refs/tags/lastbackup forces to refs/tags/lastbackup\n EOF\n \n test_expect_success 'show -n' '\n-- \n1.6.2.rc1.223.gfed32\n"},{"id":"105867","messageId":"20090223064510.GA24517@coredump.intra.peff.net","threadId":"17965","inReplyTo":"7f19e98ccc330d4094ffbb55ea06c35b91da9e55.1235368324.git.jaysoffian@gmail.com","subject":"Re: [PATCH 09/13] refactor duplicated ref_newer() to remote.c","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2009-02-23T06:45:10Z","receivedAt":"2009-02-23T06:45:10Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Mon, Feb 23, 2009 at 01:28:57AM -0500, Jay Soffian wrote:\n\n> ref_newer() appears to have been copied from builtin-send-pack.c to\n> http-push.c via cut and paste. This patch moves the function and its\n> helper unmark_and_free() to remote.c.\n> \n> Signed-off-by: Jay Soffian <jaysoffian@gmail.com>\n> ---\n> Hmm, I just noticed that the version in builtin-send-pack.c uses 1\n> whereas http-push.c uses TMP_MARK as the mark argument. I used the\n> version from builtin-send-pack.c. I don't know if this is signfificant.\n\nI think the TMP_MARK one is probably better. At the very least, the\nsend-pack one should be using SEEN instead of a bare '1'. But given that\nit is not part of the usual revision machinery, it seems like that was\nwhat TMP_MARK was designed for.\n\n-Peff\n"},{"id":"105868","messageId":"20090223064615.GB24517@coredump.intra.peff.net","threadId":"17965","inReplyTo":"904c2d8fe812fb5400d1b9946795c146de68eaca.1235368324.git.jaysoffian@gmail.com","subject":"Re: [PATCH 07/13] remote: new show output style","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2009-02-23T06:46:15Z","receivedAt":"2009-02-23T06:46:15Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Mon, Feb 23, 2009 at 01:28:55AM -0500, Jay Soffian wrote:\n\n> The existing output of \"git remote show <remote>\" is too verbose for the\n> information it provides. This patch teaches it to provide more\n> information in less space.\n>\n> Before the patch:\n> [...]\n> After this patch:\n> [...]\n\nWow. IMHO, the new one is _way_ easier to read.\n\n-Peff\n"},{"id":"105869","messageId":"20090223065048.GC24517@coredump.intra.peff.net","threadId":"17965","inReplyTo":"885507eaf920f6b60727db7e712da3560a7fd4c5.1235368324.git.jaysoffian@gmail.com","subject":"Re: [PATCH 12/13] remote.c: refactor get_remote_ref_states()","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2009-02-23T06:50:48Z","receivedAt":"2009-02-23T06:50:48Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Mon, Feb 23, 2009 at 01:29:00AM -0500, Jay Soffian wrote:\n\n> get_remote_ref_states() has three callers, but each is interested in\n> slightly different information. Give it a bit-field flag so that callers\n> can specify which pieces of information they need.\n\nHmph. I think this is probably an indication that\nget_remote_ref_states() should really be 3 functions:\n\n  common_stuff();\n  query_one();\n  query_two();\n\nand then callers can choose the subset they are interested in.\n\nWhich is really more or less equivalent; it just seems like extra\nobfuscation to have a single function with a bit-field.\n\n-Peff\n"},{"id":"105872","messageId":"20090223065934.GD24517@coredump.intra.peff.net","threadId":"17965","inReplyTo":"cover.1235368324.git.jaysoffian@gmail.com","subject":"Re: [PATCH 00/13] New output style for git remote show","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2009-02-23T06:59:34Z","receivedAt":"2009-02-23T06:59:34Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Mon, Feb 23, 2009 at 01:28:48AM -0500, Jay Soffian wrote:\n\n> Jay Soffian (13):\n>   remote: rename variable and eliminate redundant function call\n>   remote: remove unused code in get_ref_states\n>   remote: fix two inconsistencies in the output of \"show <remote>\"\n>   remote: make get_remote_ref_states() always populate states.tracked\n>   remote: name remote_refs consistently\n>   string-list: new for_each_string_list() function\n>   remote: new show output style\n>   refactor duplicated get_local_heads() to remote.c\n>   refactor duplicated ref_newer() to remote.c\n>   remote.c: make match_refs() copy src ref before assigning to peer_ref\n>   remote.c: don't short-circuit match_refs() when error in\n>     match_explicit_refs()\n>   remote.c: refactor get_remote_ref_states()\n>   remote: new show output style for push refspecs\n\nI gave these a quick read (but not any extensive apply+build+experiment\ncycle), and they all look good to me. I don't know when I'll have time\nto try breaking them, though. ;)\n\nThank you for splitting them. It made reading a lot more pleasant.\n\n-Peff\n"},{"id":"105876","messageId":"1235374171-92523-1-git-send-email-jaysoffian@gmail.com","threadId":"17965","inReplyTo":"20090223064510.GA24517@coredump.intra.peff.net","subject":"[PATCH v2 09/13] refactor duplicated ref_newer() to remote.c","fromName":"Jay Soffian","fromEmail":"jaysoffian@gmail.com","sentAt":"2009-02-23T07:29:31Z","receivedAt":"2009-02-23T07:29:31Z","isPatch":true,"sender":{"key":"jaysoffian@gmail.com","avatar":"https://avatars.githubusercontent.com/u/155970?v=4"},"body":"ref_newer() appears to have been copied from builtin-send-pack.c to\nhttp-push.c via cut and paste. This patch moves the function and its\nhelper unmark_and_free() to remote.c. There was a slight difference\nbetween the two implementations, one used TMP_MARK for the mark, the\nother used 1. Per Jeff King, I went with TMP_MARK as more correct.\n\nSigned-off-by: Jay Soffian <jaysoffian@gmail.com>\n---\nOn Mon, Feb 23, 2009 at 1:45 AM, Jeff King <peff@peff.net> wrote:\n \n> I think the TMP_MARK one is probably better. At the very least, the\n> send-pack one should be using SEEN instead of a bare '1'. But given that\n> it is not part of the usual revision machinery, it seems like that was\n> what TMP_MARK was designed for.\n\nOkay then. This replaces the previous in the series using TMP_MARK\ninstead, otherwise identical.\n\nj.\n\n builtin-send-pack.c |   49 -------------------------------------------------\n http-push.c         |   49 -------------------------------------------------\n remote.c            |   49 +++++++++++++++++++++++++++++++++++++++++++++++++\n remote.h            |    1 +\n 4 files changed, 50 insertions(+), 98 deletions(-)\n\ndiff --git a/builtin-send-pack.c b/builtin-send-pack.c\nindex 2fbfc29..186cecb 100644\n--- a/builtin-send-pack.c\n+++ b/builtin-send-pack.c\n@@ -84,55 +84,6 @@ static int pack_objects(int fd, struct ref *refs, struct extra_have_objects *ext\n \treturn 0;\n }\n \n-static void unmark_and_free(struct commit_list *list, unsigned int mark)\n-{\n-\twhile (list) {\n-\t\tstruct commit_list *temp = list;\n-\t\ttemp->item->object.flags &= ~mark;\n-\t\tlist = temp->next;\n-\t\tfree(temp);\n-\t}\n-}\n-\n-static int ref_newer(const unsigned char *new_sha1,\n-\t\t     const unsigned char *old_sha1)\n-{\n-\tstruct object *o;\n-\tstruct commit *old, *new;\n-\tstruct commit_list *list, *used;\n-\tint found = 0;\n-\n-\t/* Both new and old must be commit-ish and new is descendant of\n-\t * old.  Otherwise we require --force.\n-\t */\n-\to = deref_tag(parse_object(old_sha1), NULL, 0);\n-\tif (!o || o->type != OBJ_COMMIT)\n-\t\treturn 0;\n-\told = (struct commit *) o;\n-\n-\to = deref_tag(parse_object(new_sha1), NULL, 0);\n-\tif (!o || o->type != OBJ_COMMIT)\n-\t\treturn 0;\n-\tnew = (struct commit *) o;\n-\n-\tif (parse_commit(new) < 0)\n-\t\treturn 0;\n-\n-\tused = list = NULL;\n-\tcommit_list_insert(new, &list);\n-\twhile (list) {\n-\t\tnew = pop_most_recent_commit(&list, 1);\n-\t\tcommit_list_insert(new, &used);\n-\t\tif (new == old) {\n-\t\t\tfound = 1;\n-\t\t\tbreak;\n-\t\t}\n-\t}\n-\tunmark_and_free(list, 1);\n-\tunmark_and_free(used, 1);\n-\treturn found;\n-}\n-\n static struct ref *remote_refs, **remote_tail;\n \n static int receive_status(int in, struct ref *refs)\ndiff --git a/http-push.c b/http-push.c\nindex cfeed81..392533a 100644\n--- a/http-push.c\n+++ b/http-push.c\n@@ -1843,55 +1843,6 @@ static int is_zero_sha1(const unsigned char *sha1)\n \treturn 1;\n }\n \n-static void unmark_and_free(struct commit_list *list, unsigned int mark)\n-{\n-\twhile (list) {\n-\t\tstruct commit_list *temp = list;\n-\t\ttemp->item->object.flags &= ~mark;\n-\t\tlist = temp->next;\n-\t\tfree(temp);\n-\t}\n-}\n-\n-static int ref_newer(const unsigned char *new_sha1,\n-\t\t     const unsigned char *old_sha1)\n-{\n-\tstruct object *o;\n-\tstruct commit *old, *new;\n-\tstruct commit_list *list, *used;\n-\tint found = 0;\n-\n-\t/* Both new and old must be commit-ish and new is descendant of\n-\t * old.  Otherwise we require --force.\n-\t */\n-\to = deref_tag(parse_object(old_sha1), NULL, 0);\n-\tif (!o || o->type != OBJ_COMMIT)\n-\t\treturn 0;\n-\told = (struct commit *) o;\n-\n-\to = deref_tag(parse_object(new_sha1), NULL, 0);\n-\tif (!o || o->type != OBJ_COMMIT)\n-\t\treturn 0;\n-\tnew = (struct commit *) o;\n-\n-\tif (parse_commit(new) < 0)\n-\t\treturn 0;\n-\n-\tused = list = NULL;\n-\tcommit_list_insert(new, &list);\n-\twhile (list) {\n-\t\tnew = pop_most_recent_commit(&list, TMP_MARK);\n-\t\tcommit_list_insert(new, &used);\n-\t\tif (new == old) {\n-\t\t\tfound = 1;\n-\t\t\tbreak;\n-\t\t}\n-\t}\n-\tunmark_and_free(list, TMP_MARK);\n-\tunmark_and_free(used, TMP_MARK);\n-\treturn found;\n-}\n-\n static void add_remote_info_ref(struct remote_ls_ctx *ls)\n {\n \tstruct strbuf *buf = (struct strbuf *)ls->userData;\ndiff --git a/remote.c b/remote.c\nindex 2c010a1..d0053d5 100644\n--- a/remote.c\n+++ b/remote.c\n@@ -5,6 +5,7 @@\n #include \"diff.h\"\n #include \"revision.h\"\n #include \"dir.h\"\n+#include \"tag.h\"\n \n static struct refspec s_tag_refspec = {\n \t0,\n@@ -1271,6 +1272,54 @@ int resolve_remote_symref(struct ref *ref, struct ref *list)\n \treturn 1;\n }\n \n+static void unmark_and_free(struct commit_list *list, unsigned int mark)\n+{\n+\twhile (list) {\n+\t\tstruct commit_list *temp = list;\n+\t\ttemp->item->object.flags &= ~mark;\n+\t\tlist = temp->next;\n+\t\tfree(temp);\n+\t}\n+}\n+\n+int ref_newer(const unsigned char *new_sha1, const unsigned char *old_sha1)\n+{\n+\tstruct object *o;\n+\tstruct commit *old, *new;\n+\tstruct commit_list *list, *used;\n+\tint found = 0;\n+\n+\t/* Both new and old must be commit-ish and new is descendant of\n+\t * old.  Otherwise we require --force.\n+\t */\n+\to = deref_tag(parse_object(old_sha1), NULL, 0);\n+\tif (!o || o->type != OBJ_COMMIT)\n+\t\treturn 0;\n+\told = (struct commit *) o;\n+\n+\to = deref_tag(parse_object(new_sha1), NULL, 0);\n+\tif (!o || o->type != OBJ_COMMIT)\n+\t\treturn 0;\n+\tnew = (struct commit *) o;\n+\n+\tif (parse_commit(new) < 0)\n+\t\treturn 0;\n+\n+\tused = list = NULL;\n+\tcommit_list_insert(new, &list);\n+\twhile (list) {\n+\t\tnew = pop_most_recent_commit(&list, TMP_MARK);\n+\t\tcommit_list_insert(new, &used);\n+\t\tif (new == old) {\n+\t\t\tfound = 1;\n+\t\t\tbreak;\n+\t\t}\n+\t}\n+\tunmark_and_free(list, TMP_MARK);\n+\tunmark_and_free(used, TMP_MARK);\n+\treturn found;\n+}\n+\n /*\n  * Return true if there is anything to report, otherwise false.\n  */\ndiff --git a/remote.h b/remote.h\nindex 41b7ac2..e14d041 100644\n--- a/remote.h\n+++ b/remote.h\n@@ -76,6 +76,7 @@ int check_ref_type(const struct ref *ref, int flags);\n void free_refs(struct ref *ref);\n \n int resolve_remote_symref(struct ref *ref, struct ref *list);\n+int ref_newer(const unsigned char *new_sha1, const unsigned char *old_sha1);\n \n /*\n  * Removes and frees any duplicate refs in the map.\n-- \n1.6.2.rc1.223.gfed32\n"},{"id":"105879","messageId":"76718490902222355v7510d2f9p51ade61d1f257146@mail.gmail.com","threadId":"17965","inReplyTo":"20090223065048.GC24517@coredump.intra.peff.net","subject":"Re: [PATCH 12/13] remote.c: refactor get_remote_ref_states()","fromName":"Jay Soffian","fromEmail":"jaysoffian@gmail.com","sentAt":"2009-02-23T07:55:32Z","receivedAt":"2009-02-23T07:55:32Z","isPatch":true,"sender":{"key":"jaysoffian@gmail.com","avatar":"https://avatars.githubusercontent.com/u/155970?v=4"},"body":"On Mon, Feb 23, 2009 at 1:50 AM, Jeff King <peff@peff.net> wrote:\n> On Mon, Feb 23, 2009 at 01:29:00AM -0500, Jay Soffian wrote:\n>\n>> get_remote_ref_states() has three callers, but each is interested in\n>> slightly different information. Give it a bit-field flag so that callers\n>> can specify which pieces of information they need.\n>\n> Hmph. I think this is probably an indication that\n> get_remote_ref_states() should really be 3 functions:\n>\n>  common_stuff();\n>  query_one();\n>  query_two();\n>\n> and then callers can choose the subset they are interested in.\n>\n> Which is really more or less equivalent; it just seems like extra\n> obfuscation to have a single function with a bit-field.\n\nI see your hmph and raise you a hmph. :-)\n\nWell, I _had_ tried as you suggested first, and thought it yuckier. It\nwould actually be more like:\n\ncaller1() {\n  setup_for_get();\n  get_thing_one();\n}\n\ncaller2() {\n  setup_for_get();\n  get_thing_two();\n}\n\ncaller3() {\n  if (query) {\n     setup_for_get();\n     get_thing_one();\n     get_thing_two();\n     get_thing_three();\n} else {\n     get_thing_one_noquery()\n     get_thing_two_noquery();\n}\n\nAs opposed to:\n\ncaller1() {\n  get_things(ONE)\n}\n\ncaller2() {\n  get_things(TWO)\n}\n\ncaller3() {\n  things = 0;\n  if (query)\n     things = (ONE|TWO|THREE)\n  get_things(things)\n}\n\nI'm not sure why passing a flag saying what you want is obfuscating.\nAlso, I did find other places in git that do this sort of thing (e.g.,\nget_remote_heads).\n\n(Awaiting Junio's lucid reply explaining why my justification is bogus.) :-)\n\nj.\n"},{"id":"105880","messageId":"76718490902222356l339abf28n611297672cb28f37@mail.gmail.com","threadId":"17965","inReplyTo":"20090223065934.GD24517@coredump.intra.peff.net","subject":"Re: [PATCH 00/13] New output style for git remote show","fromName":"Jay Soffian","fromEmail":"jaysoffian@gmail.com","sentAt":"2009-02-23T07:56:51Z","receivedAt":"2009-02-23T07:56:51Z","isPatch":true,"sender":{"key":"jaysoffian@gmail.com","avatar":"https://avatars.githubusercontent.com/u/155970?v=4"},"body":"On Mon, Feb 23, 2009 at 1:59 AM, Jeff King <peff@peff.net> wrote:\n> I gave these a quick read (but not any extensive apply+build+experiment\n> cycle), and they all look good to me. I don't know when I'll have time\n> to try breaking them, though. ;)\n>\n> Thank you for splitting them. It made reading a lot more pleasant.\n\nThank you for the review. I humbly await your breakage attempts.\n\nj.\n"},{"id":"105883","messageId":"1235377892-96089-1-git-send-email-jaysoffian@gmail.com","threadId":"17965","inReplyTo":"76718490902222355v7510d2f9p51ade61d1f257146@mail.gmail.com","subject":"Re: [PATCH 12/13] remote.c: refactor get_remote_ref_states()","fromName":"Jay Soffian","fromEmail":"jaysoffian@gmail.com","sentAt":"2009-02-23T08:31:32Z","receivedAt":"2009-02-23T08:31:32Z","isPatch":true,"sender":{"key":"jaysoffian@gmail.com","avatar":"https://avatars.githubusercontent.com/u/155970?v=4"},"body":"---\nSo here's the inter-diff doing it the way you suggest. I'm surprised it\ndidn't add any LOC. If you really think this is better I'll re-do the\nend of the series to do it this way.\n\n builtin-remote.c |   81 ++++++++++++++++++++++++++---------------------------\n 1 files changed, 40 insertions(+), 41 deletions(-)\n\ndiff --git a/builtin-remote.c b/builtin-remote.c\nindex ac49219..5651b41 100644\n--- a/builtin-remote.c\n+++ b/builtin-remote.c\n@@ -19,10 +19,6 @@ static const char * const builtin_remote_usage[] = {\n \tNULL\n };\n \n-#define GET_REF_STATES (1<<0)\n-#define GET_HEAD_NAMES (1<<1)\n-#define GET_PUSH_REF_STATES (1<<2)\n-\n static int verbose;\n \n static int show_all(void);\n@@ -383,7 +379,7 @@ static int get_push_ref_states_noquery(struct ref_states *states)\n }\n \n static int get_head_names(const struct ref *remote_refs,\n-\tconst char *remote_name, struct ref_states *states)\n+\t\t\t  struct ref_states *states)\n {\n \tstruct ref *ref, *matches;\n \tstruct ref *fetch_map = NULL, **fetch_map_tail = &fetch_map;\n@@ -785,37 +781,15 @@ static int append_ref_to_tracked_list(const char *refname,\n \treturn 0;\n }\n \n-static int get_remote_ref_states(const char *name,\n-\t\t\t\t struct ref_states *states,\n-\t\t\t\t int query)\n+static const struct ref *get_remote_refs(struct ref_states *states)\n {\n \tstruct transport *transport;\n \tconst struct ref *remote_refs;\n-\n-\tstates->remote = remote_get(name);\n-\tif (!states->remote)\n-\t\treturn error(\"No such remote: %s\", name);\n-\n-\tread_branches();\n-\n-\tif (query) {\n-\t\ttransport = transport_get(NULL, states->remote->url_nr > 0 ?\n-\t\t\tstates->remote->url[0] : NULL);\n-\t\tremote_refs = transport_get_remote_refs(transport);\n-\t\ttransport_disconnect(transport);\n-\t\tstates->queried = 1;\n-\t\tif (query & GET_REF_STATES)\n-\t\t\tget_ref_states(remote_refs, states);\n-\t\tif (query & GET_HEAD_NAMES)\n-\t\t\tget_head_names(remote_refs, name, states);\n-\t\tif (query & GET_PUSH_REF_STATES)\n-\t\t\tget_push_ref_states(remote_refs, states);\n-\t} else {\n-\t\tfor_each_ref(append_ref_to_tracked_list, states);\n-\t\tsort_string_list(&states->tracked);\n-\t\tget_push_ref_states_noquery(states);\n-\t}\n-\treturn 0;\n+\ttransport = transport_get(NULL, states->remote->url_nr > 0 ?\n+\t\t\t\t  states->remote->url[0] : NULL);\n+\tremote_refs = transport_get_remote_refs(transport);\n+\ttransport_disconnect(transport);\n+\treturn remote_refs;\n }\n \n struct show_info {\n@@ -970,7 +944,7 @@ int show_push_info_item(struct string_list_item *item, void *cb_data)\n \n static int show(int argc, const char **argv)\n {\n-\tint no_query = 0, result = 0, query_flag = 0;\n+\tint no_query = 0, result = 0;\n \tstruct option options[] = {\n \t\tOPT_GROUP(\"show specific options\"),\n \t\tOPT_BOOLEAN('n', NULL, &no_query, \"do not query remotes\"),\n@@ -985,17 +959,31 @@ static int show(int argc, const char **argv)\n \tif (argc < 1)\n \t\treturn show_all();\n \n-\tif (!no_query)\n-\t\tquery_flag = (GET_REF_STATES | GET_HEAD_NAMES | GET_PUSH_REF_STATES);\n-\n+\tread_branches();\n \tmemset(&states, 0, sizeof(states));\n \tmemset(&info, 0, sizeof(info));\n+\tstates.queried = !no_query;\n \tinfo.states = &states;\n \tinfo.list = &info_list;\n+\n \tfor (; argc; argc--, argv++) {\n \t\tint i;\n \n-\t\tget_remote_ref_states(*argv, &states, query_flag);\n+\t\tif (!(states.remote = remote_get(*argv))) {\n+\t\t\terror(\"No such remote: %s\", *argv);\n+\t\t\tcontinue;\n+\t\t}\n+\t\tif (no_query) {\n+\t\t\tfor_each_ref(append_ref_to_tracked_list, &states);\n+\t\t\tsort_string_list(&states.tracked);\n+\t\t\tget_push_ref_states_noquery(&states);\n+\t\t} else {\n+\t\t\tconst struct ref *remote_refs;\n+\t\t\tremote_refs = get_remote_refs(&states);\n+\t\t\tget_ref_states(remote_refs, &states);\n+\t\t\tget_head_names(remote_refs, &states);\n+\t\t\tget_push_ref_states(remote_refs, &states);\n+\t\t}\n \n \t\tprintf(\"* remote %s\\n  URL: %s\\n\", *argv,\n \t\t\tstates.remote->url_nr > 0 ?\n@@ -1077,8 +1065,13 @@ static int set_head(int argc, const char **argv)\n \t\thead_name = xstrdup(argv[1]);\n \t} else if (opt_a && !opt_d && argc == 1) {\n \t\tstruct ref_states states;\n+\t\tconst struct ref *remote_refs;\n \t\tmemset(&states, 0, sizeof(states));\n-\t\tget_remote_ref_states(argv[0], &states, GET_HEAD_NAMES);\n+\t\tread_branches();\n+\t\tif (!(states.remote = remote_get(argv[0])))\n+\t\t\treturn error(\"No such remote: %s\", argv[0]);\n+\t\tremote_refs = get_remote_refs(&states);\n+\t\tget_head_names(remote_refs, &states);\n \t\tif (!states.heads.nr)\n \t\t\tresult |= error(\"Cannot determine remote HEAD\");\n \t\telse if (states.heads.nr > 1) {\n@@ -1134,11 +1127,17 @@ static int prune(int argc, const char **argv)\n \t\t\t? \" %s will become dangling!\\n\"\n \t\t\t: \" %s has become dangling!\\n\");\n \n+\tread_branches();\n \tmemset(&states, 0, sizeof(states));\n \tfor (; argc; argc--, argv++) {\n \t\tint i;\n-\n-\t\tget_remote_ref_states(*argv, &states, GET_REF_STATES);\n+\t\tconst struct ref *remote_refs;\n+\t\tif (!(states.remote = remote_get(*argv))) {\n+\t\t\terror(\"No such remote: %s\", *argv);\n+\t\t\tcontinue;\n+\t\t}\n+\t\tremote_refs = get_remote_refs(&states);\n+\t\tget_ref_states(remote_refs, &states);\n \n \t\tif (states.stale.nr) {\n \t\t\tprintf(\"Pruning %s\\n\", *argv);\n-- \n1.6.2.rc1.223.gfed32\n"},{"id":"105884","messageId":"49A263FB.7030308@viscovery.net","threadId":"17965","inReplyTo":"1235374171-92523-1-git-send-email-jaysoffian@gmail.com","subject":"Re: [PATCH v2 09/13] refactor duplicated ref_newer() to remote.c","fromName":"Johannes Sixt","fromEmail":"j.sixt@viscovery.net","sentAt":"2009-02-23T08:53:15Z","receivedAt":"2009-02-23T08:53:15Z","isPatch":true,"sender":{"key":"j6t@kdbg.org","avatar":"https://avatars.githubusercontent.com/u/14810926?v=4"},"body":"Jay Soffian schrieb:\n> diff --git a/remote.c b/remote.c\n> index 2c010a1..d0053d5 100644\n> --- a/remote.c\n> +++ b/remote.c\n> @@ -5,6 +5,7 @@\n>  #include \"diff.h\"\n>  #include \"revision.h\"\n>  #include \"dir.h\"\n> +#include \"tag.h\"\n\nYou are only moving code from http-push.c and builtin-send-pack.c to\nremote.c, but you have to add this '#include \"tag.h\"' here. How high are\nthe chances that you can remove the #include lines from http-push.c and\nbuiltin-send-pack.c?\n\n-- Hannes\n"},{"id":"105898","messageId":"76718490902230541k584e469bp5530b605bb700ef9@mail.gmail.com","threadId":"17965","inReplyTo":"49A263FB.7030308@viscovery.net","subject":"Re: [PATCH v2 09/13] refactor duplicated ref_newer() to remote.c","fromName":"Jay Soffian","fromEmail":"jaysoffian@gmail.com","sentAt":"2009-02-23T13:41:22Z","receivedAt":"2009-02-23T13:41:22Z","isPatch":true,"sender":{"key":"jaysoffian@gmail.com","avatar":"https://avatars.githubusercontent.com/u/155970?v=4"},"body":"On Mon, Feb 23, 2009 at 3:53 AM, Johannes Sixt <j.sixt@viscovery.net> wrote:\n> Jay Soffian schrieb:\n>> diff --git a/remote.c b/remote.c\n>> index 2c010a1..d0053d5 100644\n>> --- a/remote.c\n>> +++ b/remote.c\n>> @@ -5,6 +5,7 @@\n>>  #include \"diff.h\"\n>>  #include \"revision.h\"\n>>  #include \"dir.h\"\n>> +#include \"tag.h\"\n>\n> You are only moving code from http-push.c and builtin-send-pack.c to\n> remote.c, but you have to add this '#include \"tag.h\"' here. How high are\n> the chances that you can remove the #include lines from http-push.c and\n> builtin-send-pack.c?\n\n50/50 as it turns out. Junio, please squash this in if you don't mind:\n\ndiff --git a/builtin-send-pack.c b/builtin-send-pack.c\nindex 186cecb..9072905 100644\n--- a/builtin-send-pack.c\n+++ b/builtin-send-pack.c\n@@ -1,6 +1,5 @@\n #include \"cache.h\"\n #include \"commit.h\"\n-#include \"tag.h\"\n #include \"refs.h\"\n #include \"pkt-line.h\"\n #include \"run-command.h\"\n\n\nj.\n"},{"id":"105943","messageId":"49A32D36.3050104@xiplink.com","threadId":"17965","inReplyTo":"20090223064615.GB24517@coredump.intra.peff.net","subject":"Re: [PATCH 07/13] remote: new show output style","fromName":"Marc Branchaud","fromEmail":"marcnarc@xiplink.com","sentAt":"2009-02-23T23:11:50Z","receivedAt":"2009-02-23T23:11:50Z","isPatch":true,"sender":{"key":"marcnarc@xiplink.com","avatar":"https://avatars.githubusercontent.com/u/14980203?v=4"},"body":"Jeff King wrote:\n> \n> Wow. IMHO, the new one is _way_ easier to read.\n\nAgreed.  Great work, Jay!  Thanks!\n\n\t\tM.\n"},{"id":"105949","messageId":"20090224010556.GA3847@coredump.intra.peff.net","threadId":"17965","inReplyTo":"1235377892-96089-1-git-send-email-jaysoffian@gmail.com","subject":"Re: [PATCH 12/13] remote.c: refactor get_remote_ref_states()","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2009-02-24T01:05:56Z","receivedAt":"2009-02-24T01:05:56Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Mon, Feb 23, 2009 at 02:55:32AM -0500, Jay Soffian wrote:\n\n> I see your hmph and raise you a hmph. :-)\n> \n> Well, I _had_ tried as you suggested first, and thought it yuckier. It\n> would actually be more like:\n\nOK. My comment was along the lines of \"why didn't you think of doing it\nthis way first?\" but apparently you did. ;)\n\n> I'm not sure why passing a flag saying what you want is obfuscating.\n\nIt doesn't have to be. But from your description and my cursory look\nover the code, it seemed like get_remote_ref_states was really\nconflating several unrelated things. So breaking it apart would make\nsense for the same reason we have \"strlen\" and \"strchr\" as separate\nfunctions and not \"string_ops(s, WANT_STRLEN)\": the function is our\nbasic unit of reusable work.\n\nBut from your description:\n\n> caller1() {\n>   setup_for_get();\n>   get_thing_one();\n> }\n\nI didn't realize the commonality was actual setup; I thought it was \"do\na list of 5 things, but the first 2 are common, and then callers may\nwant to some mix of the other 3\".\n\nSo I think your original patch is fine.\n\n-Peff\n"},{"id":"105952","messageId":"7vvdr0pqhp.fsf@gitster.siamese.dyndns.org","threadId":"17965","inReplyTo":"2185ca69c518d60276ba1bc613b7699a6bca7c68.1235368324.git.jaysoffian@gmail.com","subject":"Re: [PATCH 04/13] remote: make get_remote_ref_states() always populate states.tracked","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2009-02-24T01:34:26Z","receivedAt":"2009-02-24T01:34:26Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Does this series _semantically_ depend on topics other than your other\n\"set HEAD\" topic that is still not in 'master'?\n\nI see you made it cleanly apply on top of 'pu', but frankly, I really hate\nto see a series based on 'pu' as a matter of principle and discipline.\n\nOther topics in 'pu' may not be ready for a long time, and you do not want\nthis series to be taken hostage to them.  Having to fork your topic off of\nmany other topics not even in 'next' means it would be more cumbersome for\nme to handle your series when any of the other topics that you base your\nwork on need to be discarded or replaced.\n\nIn other words, you make your series unworkable with if you introduce too\nmany dependencies.\n\nI've rebased it on top of Peff's jk/head-lookup topic (which in turn\ndepends on your js/remote-set-head topic), but I suspect that you would\nwant this series fork from and only depend on js/remote-set-head topic.\nIn any case, please check the result after I push the results out to make\nsure that I did not make any silly mistakes while rebasing the series.\n\nI also suspect that you would want to reroll the entire series anyway; see\nseparate comments on 10/13 and 11/13.\n\nThanks.\n"},{"id":"105953","messageId":"7vocwspqhc.fsf@gitster.siamese.dyndns.org","threadId":"17965","inReplyTo":"75e083170cea799499bf66792a1c3950b29d6021.1235368324.git.jaysoffian@gmail.com","subject":"Re: [PATCH 10/13] remote.c: make match_refs() copy src ref before assigning to peer_ref","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2009-02-24T01:34:39Z","receivedAt":"2009-02-24T01:34:39Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"If this issue was present before you started touching the affected code,\nit should come much earlier in the series than [10/13].  If on the other\nhand this was introduced by earlier one in the series, the patch that\nintroduced the bug should be corrected in place in the sequence without\nthis patch.\n"},{"id":"105954","messageId":"7vhc2kpqh3.fsf@gitster.siamese.dyndns.org","threadId":"17965","inReplyTo":"6cbc71876488bd7e14db40560459c0e1b8ae7b37.1235368324.git.jaysoffian@gmail.com","subject":"Re: [PATCH 11/13] remote.c: don't short-circuit match_refs() when error in match_explicit_refs()","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2009-02-24T01:34:48Z","receivedAt":"2009-02-24T01:34:48Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"The same comment as 10/13 applies here.\n"},{"id":"105962","messageId":"76718490902231906n620aac40x5c0663fd420c7f39@mail.gmail.com","threadId":"17965","inReplyTo":"7vocwspqhc.fsf@gitster.siamese.dyndns.org","subject":"Re: [PATCH 10/13] remote.c: make match_refs() copy src ref before assigning to peer_ref","fromName":"Jay Soffian","fromEmail":"jaysoffian@gmail.com","sentAt":"2009-02-24T03:06:42Z","receivedAt":"2009-02-24T03:06:42Z","isPatch":true,"sender":{"key":"jaysoffian@gmail.com","avatar":"https://avatars.githubusercontent.com/u/155970?v=4"},"body":"On Mon, Feb 23, 2009 at 8:34 PM, Junio C Hamano <gitster@pobox.com> wrote:\n> If this issue was present before you started touching the affected code,\n> it should come much earlier in the series than [10/13].  If on the other\n> hand this was introduced by earlier one in the series, the patch that\n> introduced the bug should be corrected in place in the sequence without\n> this patch.\n\nThis issue existed before, but the other callers of match_heads() only\ncall it once before the process terminates, and don't bother to free\nwhat it returns. So those callers didn't notice. This topic introduces\nthe first caller that calls match_heads() repeatedly, so it frees the\nreturned ref list after it has copied out what it needs.\n\nThe change is independent and can be moved anywhere in the series, or\neven introduced as a patch independent of the series itself. Which\nwould you prefer? (Actually, would you mind just applying it how you\nsee fit?)\n\nj.\n"},{"id":"105963","messageId":"76718490902231907y6e37d1b5ud1c276860ca6324e@mail.gmail.com","threadId":"17965","inReplyTo":"7vhc2kpqh3.fsf@gitster.siamese.dyndns.org","subject":"Re: [PATCH 11/13] remote.c: don't short-circuit match_refs() when error in match_explicit_refs()","fromName":"Jay Soffian","fromEmail":"jaysoffian@gmail.com","sentAt":"2009-02-24T03:07:36Z","receivedAt":"2009-02-24T03:07:36Z","isPatch":true,"sender":{"key":"jaysoffian@gmail.com","avatar":"https://avatars.githubusercontent.com/u/155970?v=4"},"body":"On Mon, Feb 23, 2009 at 8:34 PM, Junio C Hamano <gitster@pobox.com> wrote:\n> The same comment as 10/13 applies here.\n\nAs does the reply. :-)\n\nj.\n"},{"id":"105964","messageId":"76718490902231909n44b4ddebl1ce974090f90daff@mail.gmail.com","threadId":"17965","inReplyTo":"7vvdr0pqhp.fsf@gitster.siamese.dyndns.org","subject":"Re: [PATCH 04/13] remote: make get_remote_ref_states() always populate states.tracked","fromName":"Jay Soffian","fromEmail":"jaysoffian@gmail.com","sentAt":"2009-02-24T03:09:49Z","receivedAt":"2009-02-24T03:09:49Z","isPatch":true,"sender":{"key":"jaysoffian@gmail.com","avatar":"https://avatars.githubusercontent.com/u/155970?v=4"},"body":"On Mon, Feb 23, 2009 at 8:34 PM, Junio C Hamano <gitster@pobox.com> wrote:\n> Does this series _semantically_ depend on topics other than your other\n> \"set HEAD\" topic that is still not in 'master'?\n\nNo, but I wanted Jeff's changes. I have checked that I can apply the\n\"set HEAD\" series, then Jeff's changes, then this latest series all to\nnext w/o conflict.\n\nI've not tried it w/o Jeff's changes in the middle.\n\n> I see you made it cleanly apply on top of 'pu', but frankly, I really hate\n> to see a series based on 'pu' as a matter of principle and discipline.\n>\n> Other topics in 'pu' may not be ready for a long time, and you do not want\n> this series to be taken hostage to them.  Having to fork your topic off of\n> many other topics not even in 'next' means it would be more cumbersome for\n> me to handle your series when any of the other topics that you base your\n> work on need to be discarded or replaced.\n\nUnderstood. I thought this situation was a little different though due\nto Jeff's changes in the middle which really build on my set HEAD\ntopic.\n\n> In other words, you make your series unworkable with if you introduce too\n> many dependencies.\n>\n> I've rebased it on top of Peff's jk/head-lookup topic (which in turn\n> depends on your js/remote-set-head topic), but I suspect that you would\n> want this series fork from and only depend on js/remote-set-head topic.\n> In any case, please check the result after I push the results out to make\n> sure that I did not make any silly mistakes while rebasing the series.\n\nWill do, thanks.\n\n> I also suspect that you would want to reroll the entire series anyway; see\n> separate comments on 10/13 and 11/13.\n\nI've replied to those. Would you mind applying 10/13 and 11/13\nindependently of this series? This topic depends on them since\notherwise there will be double-frees, but they can go anywhere before\nthe topic.\n\nj.\n"},{"id":"105965","messageId":"76718490902231913x63ca33cp8dd08b63f337bc7f@mail.gmail.com","threadId":"17965","inReplyTo":"76718490902231909n44b4ddebl1ce974090f90daff@mail.gmail.com","subject":"Re: [PATCH 04/13] remote: make get_remote_ref_states() always populate states.tracked","fromName":"Jay Soffian","fromEmail":"jaysoffian@gmail.com","sentAt":"2009-02-24T03:13:53Z","receivedAt":"2009-02-24T03:13:53Z","isPatch":true,"sender":{"key":"jaysoffian@gmail.com","avatar":"https://avatars.githubusercontent.com/u/155970?v=4"},"body":"On Mon, Feb 23, 2009 at 10:09 PM, Jay Soffian <jaysoffian@gmail.com> wrote:\n> No, but I wanted Jeff's changes. I have checked that I can apply the\n> \"set HEAD\" series, then Jeff's changes, then this latest series all to\n> next w/o conflict.\n\nPut another way, IMO, the set HEAD series, Jeff's changes, and this\nseries might very well be a single topic.\n\n>> In other words, you make your series unworkable with if you introduce too\n>> many dependencies.\n\nFor future reference, should I build on top of master or next?\n\nj.\n"},{"id":"105966","messageId":"7vzlgcmsan.fsf@gitster.siamese.dyndns.org","threadId":"17965","inReplyTo":"76718490902231906n620aac40x5c0663fd420c7f39@mail.gmail.com","subject":"Re: [PATCH 10/13] remote.c: make match_refs() copy src ref before assigning to peer_ref","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2009-02-24T03:23:44Z","receivedAt":"2009-02-24T03:23:44Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Jay Soffian <jaysoffian@gmail.com> writes:\n\n> This issue existed before, but the other callers of match_heads() only\n> call it once before the process terminates, and don't bother to free\n> what it returns. So those callers didn't notice. This topic introduces\n> the first caller that calls match_heads() repeatedly, so it frees the\n> returned ref list after it has copied out what it needs.\n>\n> The change is independent and can be moved anywhere in the series, or\n> even introduced as a patch independent of the series itself.\n\nThanks for explanation.\n\nIf I am reading the above correctly, a sequence that does not have 10/13\nbefore the patch that makes match_heads() called repeatedly would break\nbisection, so it cannot be \"can be moved anywhere\".\n\nAnd it sounds like keeping this as a separate patch would make more\nsense.  Your proposed commit log message for the patch would contain the\nfirst paragraph I quoted above, I'd think.\n"},{"id":"105967","messageId":"1235448334-36310-1-git-send-email-jaysoffian@gmail.com","threadId":"17965","inReplyTo":"7vzlgcmsan.fsf@gitster.siamese.dyndns.org","subject":"[PATCH] remote.c: make match_refs() copy src ref before assigning to peer_ref","fromName":"Jay Soffian","fromEmail":"jaysoffian@gmail.com","sentAt":"2009-02-24T04:05:34Z","receivedAt":"2009-02-24T04:05:34Z","isPatch":true,"sender":{"key":"jaysoffian@gmail.com","avatar":"https://avatars.githubusercontent.com/u/155970?v=4"},"body":"In some instances, match_refs() sets the peer_ref field of refs in the\ndst list such that it points to a ref in the src list. Were a caller to\nfree both the src and dst lists, this would cause a double-free as\nfree_refs() frees the peer_ref.\n\nA double-free would also occur freeing just the dst list under the\nfollowing configuration:\n\n  push = refs/heads/master:refs/heads/backup\n  push = refs/heads/master:refs/heads/master\n\nSince such a configuration would cause two refs in the dst list to have\nthe same peer_ref.\n\nThis patch corrects the problem by copying the ref when it has been\nplucked from the src list.\n\nThis issue has gone undetected as the existing callers of match_heads()\ncall it only once and then terminate, w/o ever bothering to free the src\nor dst lists.\n\nSigned-off-by: Jay Soffian <jaysoffian@gmail.com>\n---\n remote.c |    7 +++++--\n 1 files changed, 5 insertions(+), 2 deletions(-)\n\ndiff --git a/remote.c b/remote.c\nindex d7079c6..98575be 100644\n--- a/remote.c\n+++ b/remote.c\n@@ -927,6 +927,7 @@ static int match_explicit(struct ref *src, struct ref *dst,\n \t\t\t  struct refspec *rs)\n {\n \tstruct ref *matched_src, *matched_dst;\n+\tint copy_src;\n \n \tconst char *dst_value = rs->dst;\n \tchar *dst_guess;\n@@ -937,6 +938,7 @@ static int match_explicit(struct ref *src, struct ref *dst,\n \tmatched_src = matched_dst = NULL;\n \tswitch (count_refspec_match(rs->src, src, &matched_src)) {\n \tcase 1:\n+\t\tcopy_src = 1;\n \t\tbreak;\n \tcase 0:\n \t\t/* The source could be in the get_sha1() format\n@@ -946,6 +948,7 @@ static int match_explicit(struct ref *src, struct ref *dst,\n \t\tmatched_src = try_explicit_object_name(rs->src);\n \t\tif (!matched_src)\n \t\t\treturn error(\"src refspec %s does not match any.\", rs->src);\n+\t\tcopy_src = 0;\n \t\tbreak;\n \tdefault:\n \t\treturn error(\"src refspec %s matches more than one.\", rs->src);\n@@ -991,7 +994,7 @@ static int match_explicit(struct ref *src, struct ref *dst,\n \t\treturn error(\"dst ref %s receives from more than one src.\",\n \t\t      matched_dst->name);\n \telse {\n-\t\tmatched_dst->peer_ref = matched_src;\n+\t\tmatched_dst->peer_ref = copy_src ? copy_ref(matched_src) : matched_src;\n \t\tmatched_dst->force = rs->force;\n \t}\n \treturn 0;\n@@ -1099,7 +1102,7 @@ int match_refs(struct ref *src, struct ref *dst, struct ref ***dst_tail,\n \t\t\tdst_peer = make_linked_ref(dst_name, dst_tail);\n \t\t\thashcpy(dst_peer->new_sha1, src->new_sha1);\n \t\t}\n-\t\tdst_peer->peer_ref = src;\n+\t\tdst_peer->peer_ref = copy_ref(src);\n \t\tdst_peer->force = pat->force;\n \tfree_name:\n \t\tfree(dst_name);\n-- \n1.6.2.rc1.291.g83eb\n"},{"id":"105982","messageId":"7vfxi4mk8n.fsf@gitster.siamese.dyndns.org","threadId":"17965","inReplyTo":"1235448334-36310-1-git-send-email-jaysoffian@gmail.com","subject":"Re: [PATCH] remote.c: make match_refs() copy src ref before assigning to peer_ref","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2009-02-24T06:17:44Z","receivedAt":"2009-02-24T06:17:44Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Jay Soffian <jaysoffian@gmail.com> writes:\n\n> This issue has gone undetected as the existing callers of match_heads()\n> call it only once and then terminate, w/o ever bothering to free the src\n> or dst lists.\n\nThanks.\n\nIt sounds more like existing function and usage was alright but your new\ncaller made it into an issue.\n\nSo I'd queue this as the first patch in the 13-patch series, dropping 10/13?\nWhat should happen to 11/13?\n"},{"id":"105988","messageId":"76718490902232253o4c7667d9h43f06d81794cef60@mail.gmail.com","threadId":"17965","inReplyTo":"7vfxi4mk8n.fsf@gitster.siamese.dyndns.org","subject":"Re: [PATCH] remote.c: make match_refs() copy src ref before assigning to peer_ref","fromName":"Jay Soffian","fromEmail":"jaysoffian@gmail.com","sentAt":"2009-02-24T06:53:48Z","receivedAt":"2009-02-24T06:53:48Z","isPatch":true,"sender":{"key":"jaysoffian@gmail.com","avatar":"https://avatars.githubusercontent.com/u/155970?v=4"},"body":"On Tue, Feb 24, 2009 at 1:17 AM, Junio C Hamano <gitster@pobox.com> wrote:\n> Jay Soffian <jaysoffian@gmail.com> writes:\n>\n>> This issue has gone undetected as the existing callers of match_heads()\n>> call it only once and then terminate, w/o ever bothering to free the src\n>> or dst lists.\n>\n> Thanks.\n>\n> It sounds more like existing function and usage was alright but your new\n> caller made it into an issue.\n\nWell, maybe. The existing function alters the passed in dst argument\n(a ref list) in two ways:\n\n1) It potentially adds new refs to the tail of the list.\n2) For the existing and new refs, it populates their peer_ref field.\nWhen it does this, it sometimes just points it at an existing ref in\nthe src list, but sometimes it allocates a new ref and points to that.\n\nSo there is no sane way to free the result. As there is no indication\nthat the caller shouldn't be able to free the src and dst lists after\nit is done, it was IMO a latent bug.\n\nInitially I tried to fix this by modifying free_refs() to make two\npasses over the list passed to it, once to mark each peer_ref, then a\nsecond time to clear only those peer_refs it had not already seen. I\ndid this because when I first saw the double free I was only freeing\nthe dst list. It took me a while to realize the cause was two refs in\nthe dst list having the same peer_ref.\n\nBut then I realized my caller needed to clear the src list as well,\nand saw that the problem was really in match_heads(), not in free'ing\nthe result.\n\n> So I'd queue this as the first patch in the 13-patch series, dropping 10/13?\n> What should happen to 11/13?\n\nI sent you a message off-list you may not have read yet. I'm\nre-rolling the entire js/remote-set-head for you off of the current\nmaster to get rid of any dependencies on pu, with jk/head-lookup on\nthe end of the series instead of in the middle. I needed to rebase off\nmaster since I have a dependency on cfa1ee6 which is now in master,\nbut wasn't when you spawned js/remote-set-head initially.\n\nj.\n"},{"id":"105993","messageId":"7vvdr0l358.fsf@gitster.siamese.dyndns.org","threadId":"17965","inReplyTo":"76718490902232253o4c7667d9h43f06d81794cef60@mail.gmail.com","subject":"Re: [PATCH] remote.c: make match_refs() copy src ref before assigning to peer_ref","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2009-02-24T07:12:19Z","receivedAt":"2009-02-24T07:12:19Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Jay Soffian <jaysoffian@gmail.com> writes:\n\n> So there is no sane way to free the result.\n\nYeah, I am not disagreeing that this is a good change to make the function\neasier to use.  There is no question about it.\n\nI just found your description a bit unfair to the original author of the\ncodepath who was probably fully aware of this.\n\n> I sent you a message off-list you may not have read yet.\n\nYes I have, but I was deep into tonight's integration cycle (I earlier\nasked you to check the rebased result when I push it out --- that is what\nI've been preparing).  I am almost done, and it will be pushed out\nshortly, but it won't have your re-roll.  That will be after 1.6.2-rc2.\n"}]}