{"thread":{"id":"17987","subject":"[PATCH 02/23] builtin-remote: move duplicated cleanup code its own function","startedAt":"2009-02-24T09:50:49Z","lastAt":"2009-02-24T09:51:11Z","messageCount":23,"participants":["Jay Soffian"],"isPatch":true,"patchVersion":1,"patchTotal":23},"messages":[{"id":"106017","messageId":"4c6211345999ae7b99da14b87283c3836169ab63.1235467368.git.jaysoffian@gmail.com","threadId":"17987","inReplyTo":"cover.1235467368.git.jaysoffian@gmail.com","subject":"[PATCH 01/23] builtin-clone: move locate_head() to remote.c so it can be re-used","fromName":"Jay Soffian","fromEmail":"jaysoffian@gmail.com","sentAt":"2009-02-24T09:50:49Z","receivedAt":"2009-02-24T09:50:49Z","isPatch":true,"sender":{"key":"jaysoffian@gmail.com","avatar":"https://avatars.githubusercontent.com/u/155970?v=4"},"body":"Move locate_head() to remote.c and rename it to guess_remote_head() to\nmore accurately reflect what it does. This is in preparation for being\nable to call it from builtin-remote.c\n\nSigned-off-by: Jay Soffian <jaysoffian@gmail.com>\n---\n builtin-clone.c |   41 +++--------------------------------------\n remote.c        |   37 +++++++++++++++++++++++++++++++++++++\n remote.h        |    9 +++++++++\n 3 files changed, 49 insertions(+), 38 deletions(-)\n\ndiff --git a/builtin-clone.c b/builtin-clone.c\nindex c338910..d179d1c 100644\n--- a/builtin-clone.c\n+++ b/builtin-clone.c\n@@ -20,6 +20,7 @@\n #include \"dir.h\"\n #include \"pack-refs.h\"\n #include \"sigchain.h\"\n+#include \"remote.h\"\n \n /*\n  * Overall FIXMEs:\n@@ -293,43 +294,6 @@ static void remove_junk_on_signal(int signo)\n \traise(signo);\n }\n \n-static const struct ref *locate_head(const struct ref *refs,\n-\t\t\t\t     const struct ref *mapped_refs,\n-\t\t\t\t     const struct ref **remote_head_p)\n-{\n-\tconst struct ref *remote_head = NULL;\n-\tconst struct ref *remote_master = NULL;\n-\tconst struct ref *r;\n-\tfor (r = refs; r; r = r->next)\n-\t\tif (!strcmp(r->name, \"HEAD\"))\n-\t\t\tremote_head = r;\n-\n-\tfor (r = mapped_refs; r; r = r->next)\n-\t\tif (!strcmp(r->name, \"refs/heads/master\"))\n-\t\t\tremote_master = r;\n-\n-\tif (remote_head_p)\n-\t\t*remote_head_p = remote_head;\n-\n-\t/* If there's no HEAD value at all, never mind. */\n-\tif (!remote_head)\n-\t\treturn NULL;\n-\n-\t/* If refs/heads/master could be right, it is. */\n-\tif (remote_master && !hashcmp(remote_master->old_sha1,\n-\t\t\t\t      remote_head->old_sha1))\n-\t\treturn remote_master;\n-\n-\t/* Look for another ref that points there */\n-\tfor (r = mapped_refs; r; r = r->next)\n-\t\tif (r != remote_head &&\n-\t\t    !hashcmp(r->old_sha1, remote_head->old_sha1))\n-\t\t\treturn r;\n-\n-\t/* Nothing is the same */\n-\treturn NULL;\n-}\n-\n static struct ref *write_remote_refs(const struct ref *refs,\n \t\tstruct refspec *refspec, const char *reflog)\n {\n@@ -545,7 +509,8 @@ int cmd_clone(int argc, const char **argv, const char *prefix)\n \n \t\tmapped_refs = write_remote_refs(refs, &refspec, reflog_msg.buf);\n \n-\t\thead_points_at = locate_head(refs, mapped_refs, &remote_head);\n+\t\thead_points_at = guess_remote_head(refs, mapped_refs,\n+\t\t\t\t\t\t   &remote_head);\n \t}\n \telse {\n \t\twarning(\"You appear to have cloned an empty repository.\");\ndiff --git a/remote.c b/remote.c\nindex d7079c6..447f091 100644\n--- a/remote.c\n+++ b/remote.c\n@@ -1376,3 +1376,40 @@ int format_tracking_info(struct branch *branch, struct strbuf *sb)\n \t\t\t    base, num_ours, num_theirs);\n \treturn 1;\n }\n+\n+const struct ref *guess_remote_head(const struct ref *refs,\n+\t\t\t\t    const struct ref *mapped_refs,\n+\t\t\t\t    const struct ref **remote_head_p)\n+{\n+\tconst struct ref *remote_head = NULL;\n+\tconst struct ref *remote_master = NULL;\n+\tconst struct ref *r;\n+\tfor (r = refs; r; r = r->next)\n+\t\tif (!strcmp(r->name, \"HEAD\"))\n+\t\t\tremote_head = r;\n+\n+\tfor (r = mapped_refs; r; r = r->next)\n+\t\tif (!strcmp(r->name, \"refs/heads/master\"))\n+\t\t\tremote_master = r;\n+\n+\tif (remote_head_p)\n+\t\t*remote_head_p = remote_head;\n+\n+\t/* If there's no HEAD value at all, never mind. */\n+\tif (!remote_head)\n+\t\treturn NULL;\n+\n+\t/* If refs/heads/master could be right, it is. */\n+\tif (remote_master && !hashcmp(remote_master->old_sha1,\n+\t\t\t\t      remote_head->old_sha1))\n+\t\treturn remote_master;\n+\n+\t/* Look for another ref that points there */\n+\tfor (r = mapped_refs; r; r = r->next)\n+\t\tif (r != remote_head &&\n+\t\t    !hashcmp(r->old_sha1, remote_head->old_sha1))\n+\t\t\treturn r;\n+\n+\t/* Nothing is the same */\n+\treturn NULL;\n+}\ndiff --git a/remote.h b/remote.h\nindex a46a5be..cabb14a 100644\n--- a/remote.h\n+++ b/remote.h\n@@ -137,4 +137,13 @@ enum match_refs_flags {\n int stat_tracking_info(struct branch *branch, int *num_ours, int *num_theirs);\n int format_tracking_info(struct branch *branch, struct strbuf *sb);\n \n+/*\n+ * Look in refs for HEAD. Then look for a matching SHA1 in mapped_refs,\n+ * first checking if refs/heads/master matches. Return NULL if nothing matches\n+ * or if there is no HEAD in refs. remote_head_p is assigned HEAD if not NULL.\n+ */\n+const struct ref *guess_remote_head(const struct ref *refs,\n+\t\t\t\t    const struct ref *mapped_refs,\n+\t\t\t\t    const struct ref **remote_head_p);\n+\n #endif\n-- \n1.6.2.rc1.291.g83eb\n"},{"id":"106015","messageId":"84dd248aa6381f1f0a533203fdb0614a90460635.1235467368.git.jaysoffian@gmail.com","threadId":"17987","inReplyTo":"cover.1235467368.git.jaysoffian@gmail.com","subject":"[PATCH 02/23] builtin-remote: move duplicated cleanup code its own function","fromName":"Jay Soffian","fromEmail":"jaysoffian@gmail.com","sentAt":"2009-02-24T09:50:50Z","receivedAt":"2009-02-24T09:50:50Z","isPatch":true,"sender":{"key":"jaysoffian@gmail.com","avatar":"https://avatars.githubusercontent.com/u/155970?v=4"},"body":"Moved some identical lines of code into their own function in\npreparation for adding additional functionality which will use this\nfunction as well.\n\nAlso removed a bogus NEEDSWORK comment per Daniel Barkalow:\n\n  Actually, the comment is wrong; \"remote\" comes from remote_get(),\n  which returns things from a cache in remote.c; there could be a\n  remote_put() to let the code know that the caller is done with the\n  object, but it wouldn't presently do anything.\n\nSigned-off-by: Jay Soffian <jaysoffian@gmail.com>\n---\n builtin-remote.c |   17 +++++++++--------\n 1 files changed, 9 insertions(+), 8 deletions(-)\n\ndiff --git a/builtin-remote.c b/builtin-remote.c\nindex ac69d37..b89a353 100644\n--- a/builtin-remote.c\n+++ b/builtin-remote.c\n@@ -632,6 +632,13 @@ static void show_list(const char *title, struct string_list *list,\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+\tstring_list_clear(&states->stale, 0);\n+\tstring_list_clear(&states->tracked, 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@@ -738,10 +745,7 @@ static int show(int argc, const char **argv)\n \t\t\t}\n \t\t}\n \n-\t\t/* NEEDSWORK: free remote */\n-\t\tstring_list_clear(&states.new, 0);\n-\t\tstring_list_clear(&states.stale, 0);\n-\t\tstring_list_clear(&states.tracked, 0);\n+\t\tfree_remote_ref_states(&states);\n \t}\n \n \treturn result;\n@@ -792,10 +796,7 @@ static int prune(int argc, const char **argv)\n \t\t\twarn_dangling_symref(dangling_msg, refname);\n \t\t}\n \n-\t\t/* NEEDSWORK: free remote */\n-\t\tstring_list_clear(&states.new, 0);\n-\t\tstring_list_clear(&states.stale, 0);\n-\t\tstring_list_clear(&states.tracked, 0);\n+\t\tfree_remote_ref_states(&states);\n \t}\n \n \treturn result;\n-- \n1.6.2.rc1.291.g83eb\n"},{"id":"106016","messageId":"41dd1de0e111b3f135a061848d1e92d9b7994623.1235467368.git.jaysoffian@gmail.com","threadId":"17987","inReplyTo":"cover.1235467368.git.jaysoffian@gmail.com","subject":"[PATCH 03/23] builtin-remote: teach show to display remote HEAD","fromName":"Jay Soffian","fromEmail":"jaysoffian@gmail.com","sentAt":"2009-02-24T09:50:51Z","receivedAt":"2009-02-24T09:50:51Z","isPatch":true,"sender":{"key":"jaysoffian@gmail.com","avatar":"https://avatars.githubusercontent.com/u/155970?v=4"},"body":"This is in preparation for teaching remote how to set\nrefs/remotes/<remote>/HEAD to match what HEAD is set to at <remote>, but\nis useful in its own right.\n\nSigned-off-by: Jay Soffian <jaysoffian@gmail.com>\n---\n builtin-remote.c  |   26 ++++++++++++++++++++++++++\n t/t5505-remote.sh |    3 ++-\n 2 files changed, 28 insertions(+), 1 deletions(-)\n\ndiff --git a/builtin-remote.c b/builtin-remote.c\nindex b89a353..465c87a 100644\n--- a/builtin-remote.c\n+++ b/builtin-remote.c\n@@ -212,6 +212,7 @@ static void read_branches(void)\n struct ref_states {\n \tstruct remote *remote;\n \tstruct string_list new, stale, tracked;\n+\tchar *head_name;\n };\n \n static int handle_one_branch(const char *refname,\n@@ -271,6 +272,26 @@ static int get_ref_states(const struct ref *ref, struct ref_states *states)\n \treturn 0;\n }\n \n+static char *get_head_name(const struct ref *refs)\n+{\n+\tconst struct ref *head_points_at;\n+\tstruct ref *mapped_refs = NULL;\n+\tstruct ref **tail = &mapped_refs;\n+\tstruct refspec refspec;\n+\n+\trefspec.force = 0;\n+\trefspec.pattern = 1;\n+\trefspec.src = refspec.dst = \"refs/heads/\";\n+\n+\tget_fetch_map(refs, &refspec, &tail, 0);\n+\n+\thead_points_at = guess_remote_head(refs, mapped_refs, NULL);\n+\tif (head_points_at)\n+\t\treturn xstrdup(abbrev_branch(head_points_at->name));\n+\n+\treturn NULL;\n+}\n+\n struct known_remote {\n \tstruct known_remote *next;\n \tstruct remote *remote;\n@@ -637,6 +658,7 @@ static void free_remote_ref_states(struct ref_states *states)\n \tstring_list_clear(&states->new, 0);\n \tstring_list_clear(&states->stale, 0);\n \tstring_list_clear(&states->tracked, 0);\n+\tfree(states->head_name);\n }\n \n static int get_remote_ref_states(const char *name,\n@@ -658,6 +680,7 @@ static int get_remote_ref_states(const char *name,\n \t\tref = transport_get_remote_refs(transport);\n \t\ttransport_disconnect(transport);\n \n+\t\tstates->head_name = get_head_name(ref);\n \t\tget_ref_states(ref, states);\n \t}\n \n@@ -702,6 +725,9 @@ static int show(int argc, const char **argv)\n \t\tprintf(\"* remote %s\\n  URL: %s\\n\", *argv,\n \t\t\tstates.remote->url_nr > 0 ?\n \t\t\t\tstates.remote->url[0] : \"(no URL)\");\n+\t\tif (!no_query)\n+\t\t\tprintf(\"  HEAD: %s\\n\", states.head_name ?\n+\t\t\t\tstates.head_name : \"(unknown)\");\n \n \t\tfor (i = 0; i < branch_list.nr; i++) {\n \t\t\tstruct string_list_item *branch = branch_list.items + i;\ndiff --git a/t/t5505-remote.sh b/t/t5505-remote.sh\nindex eb63718..826d0c3 100755\n--- a/t/t5505-remote.sh\n+++ b/t/t5505-remote.sh\n@@ -136,6 +136,7 @@ EOF\n cat > test/expect << EOF\n * remote origin\n   URL: $(pwd)/one\n+  HEAD: 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@@ -343,7 +344,7 @@ test_expect_success '\"remote show\" does not show symbolic refs' '\n \tgit clone one three &&\n \t(cd three &&\n \t git remote show origin > output &&\n-\t ! grep HEAD < output &&\n+\t ! grep \"^ *HEAD$\" < output &&\n \t ! grep -i stale < output)\n \n '\n-- \n1.6.2.rc1.291.g83eb\n"},{"id":"106019","messageId":"f712297e8a8df716fa9f75c8ce5ce0bb79380369.1235467368.git.jaysoffian@gmail.com","threadId":"17987","inReplyTo":"cover.1235467368.git.jaysoffian@gmail.com","subject":"[PATCH 04/23] builtin-remote: add set-head subcommand","fromName":"Jay Soffian","fromEmail":"jaysoffian@gmail.com","sentAt":"2009-02-24T09:50:52Z","receivedAt":"2009-02-24T09:50:52Z","isPatch":true,"sender":{"key":"jaysoffian@gmail.com","avatar":"https://avatars.githubusercontent.com/u/155970?v=4"},"body":"Provide a porcelain command for setting and deleting\n$GIT_DIR/remotes/<remote>/HEAD.\n\nWhile we're at it, document what $GIT_DIR/remotes/<remote>/HEAD is all\nabout.\n\nSigned-off-by: Jay Soffian <jaysoffian@gmail.com>\n---\n Documentation/git-remote.txt           |   28 ++++++++++++++++-\n builtin-remote.c                       |   51 ++++++++++++++++++++++++++++++++\n contrib/completion/git-completion.bash |    2 +-\n 3 files changed, 78 insertions(+), 3 deletions(-)\n\ndiff --git a/Documentation/git-remote.txt b/Documentation/git-remote.txt\nindex fad983e..c9c0e6f 100644\n--- a/Documentation/git-remote.txt\n+++ b/Documentation/git-remote.txt\n@@ -13,6 +13,7 @@ SYNOPSIS\n 'git remote add' [-t <branch>] [-m <master>] [-f] [--mirror] <name> <url>\n 'git remote rename' <old> <new>\n 'git remote rm' <name>\n+'git remote set-head' <name> [-a | -d | <branch>]\n 'git remote show' [-n] <name>\n 'git remote prune' [-n | --dry-run] <name>\n 'git remote update' [group]\n@@ -53,8 +54,7 @@ is created.  You can give more than one `-t <branch>` to track\n multiple branches without grabbing all branches.\n +\n With `-m <master>` option, `$GIT_DIR/remotes/<name>/HEAD` is set\n-up to point at remote's `<master>` branch instead of whatever\n-branch the `HEAD` at the remote repository actually points at.\n+up to point at remote's `<master>` branch. See also the set-head command.\n +\n In mirror mode, enabled with `\\--mirror`, the refs will not be stored\n in the 'refs/remotes/' namespace, but in 'refs/heads/'.  This option\n@@ -76,6 +76,30 @@ the configuration file format.\n Remove the remote named <name>. All remote tracking branches and\n configuration settings for the remote are removed.\n \n+'set-head'::\n+\n+Sets or deletes the default branch (`$GIT_DIR/remotes/<name>/HEAD`) for\n+the named remote. Having a default branch for a remote is not required,\n+but allows the name of the remote to be specified in lieu of a specific\n+branch. For example, if the default branch for `origin` is set to\n+`master`, then `origin` may be specified wherever you would normally\n+specify `origin/master`.\n++\n+With `-d`, `$GIT_DIR/remotes/<name>/HEAD` is deleted.\n++\n+With `-a`, the remote is queried to determine its `HEAD`, then\n+`$GIT_DIR/remotes/<name>/HEAD` is set to the same branch. e.g., if the remote\n+`HEAD` is pointed at `next`, \"`git remote set-head origin -a`\" will set\n+`$GIT_DIR/refs/remotes/origin/HEAD` to `refs/remotes/origin/next`. This will\n+only work if `refs/remotes/origin/next` already exists; if not it must be\n+fetched first.\n++\n+Use `<branch>` to set `$GIT_DIR/remotes/<name>/HEAD` explicitly. e.g., \"git\n+remote set-head origin master\" will set `$GIT_DIR/refs/remotes/origin/HEAD` to\n+`refs/remotes/origin/master`. This will only work if\n+`refs/remotes/origin/master` already exists; if not it must be fetched first.\n++\n+\n 'show'::\n \n Gives some information about the remote <name>.\ndiff --git a/builtin-remote.c b/builtin-remote.c\nindex 465c87a..fcb166b 100644\n--- a/builtin-remote.c\n+++ b/builtin-remote.c\n@@ -12,6 +12,7 @@ static const char * const builtin_remote_usage[] = {\n \t\"git remote add [-t <branch>] [-m <master>] [-f] [--mirror] <name> <url>\",\n \t\"git remote rename <old> <new>\",\n \t\"git remote rm <name>\",\n+\t\"git remote set-head <name> [-a | -d | <branch>]\",\n \t\"git remote show [-n] <name>\",\n \t\"git remote prune [-n | --dry-run] <name>\",\n \t\"git remote [-v | --verbose] update [group]\",\n@@ -777,6 +778,54 @@ static int show(int argc, const char **argv)\n \treturn result;\n }\n \n+static int set_head(int argc, const char **argv)\n+{\n+\tint opt_a = 0, opt_d = 0, result = 0;\n+\tstruct strbuf buf = STRBUF_INIT, buf2 = STRBUF_INIT;\n+\tchar *head_name = NULL;\n+\n+\tstruct option options[] = {\n+\t\tOPT_GROUP(\"set-head specific options\"),\n+\t\tOPT_BOOLEAN('a', \"auto\", &opt_a,\n+\t\t\t    \"set refs/remotes/<name>/HEAD according to remote\"),\n+\t\tOPT_BOOLEAN('d', \"delete\", &opt_d,\n+\t\t\t    \"delete refs/remotes/<name>/HEAD\"),\n+\t\tOPT_END()\n+\t};\n+\targc = parse_options(argc, argv, options, builtin_remote_usage, 0);\n+\tif (argc)\n+\t\tstrbuf_addf(&buf, \"refs/remotes/%s/HEAD\", argv[0]);\n+\n+\tif (!opt_a && !opt_d && argc == 2) {\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\tmemset(&states, 0, sizeof(states));\n+\t\tget_remote_ref_states(argv[0], &states, 1);\n+\t\thead_name = xstrdup(states.head_name);\n+\t\tfree_remote_ref_states(&states);\n+\t} else if (opt_d && !opt_a && argc == 1) {\n+\t\tif (delete_ref(buf.buf, NULL, REF_NODEREF))\n+\t\t\tresult |= error(\"Could not delete %s\", buf.buf);\n+\t} else\n+\t\tusage_with_options(builtin_remote_usage, options);\n+\n+\tif (head_name) {\n+\t\tunsigned char sha1[20];\n+\t\tstrbuf_addf(&buf2, \"refs/remotes/%s/%s\", argv[0], head_name);\n+\t\t/* make sure it's valid */\n+\t\tif (!resolve_ref(buf2.buf, sha1, 1, NULL))\n+\t\t\tresult |= error(\"Not a valid ref: %s\", buf2.buf);\n+\t\telse if (create_symref(buf.buf, buf2.buf, \"remote set-head\"))\n+\t\t\tresult |= error(\"Could not setup %s\", buf.buf);\n+\t\tfree(head_name);\n+\t}\n+\n+\tstrbuf_release(&buf);\n+\tstrbuf_release(&buf2);\n+\treturn result;\n+}\n+\n static int prune(int argc, const char **argv)\n {\n \tint dry_run = 0, result = 0;\n@@ -947,6 +996,8 @@ int cmd_remote(int argc, const char **argv, const char *prefix)\n \t\tresult = mv(argc, argv);\n \telse if (!strcmp(argv[0], \"rm\"))\n \t\tresult = rm(argc, argv);\n+\telse if (!strcmp(argv[0], \"set-head\"))\n+\t\tresult = set_head(argc, argv);\n \telse if (!strcmp(argv[0], \"show\"))\n \t\tresult = show(argc, argv);\n \telse if (!strcmp(argv[0], \"prune\"))\ndiff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash\nindex 0a3092f..15b938b 100755\n--- a/contrib/completion/git-completion.bash\n+++ b/contrib/completion/git-completion.bash\n@@ -1443,7 +1443,7 @@ _git_config ()\n \n _git_remote ()\n {\n-\tlocal subcommands=\"add rename rm show prune update\"\n+\tlocal subcommands=\"add rename rm show prune update set-head\"\n \tlocal subcommand=\"$(__git_find_subcommand \"$subcommands\")\"\n \tif [ -z \"$subcommand\" ]; then\n \t\t__gitcomp \"$subcommands\"\n-- \n1.6.2.rc1.291.g83eb\n"},{"id":"106022","messageId":"f72afb9f451172b8dd9f074143e64f4d5544b808.1235467368.git.jaysoffian@gmail.com","threadId":"17987","inReplyTo":"cover.1235467368.git.jaysoffian@gmail.com","subject":"[PATCH 05/23] builtin-remote: better handling of multiple remote HEADs","fromName":"Jay Soffian","fromEmail":"jaysoffian@gmail.com","sentAt":"2009-02-24T09:50:53Z","receivedAt":"2009-02-24T09:50:53Z","isPatch":true,"sender":{"key":"jaysoffian@gmail.com","avatar":"https://avatars.githubusercontent.com/u/155970?v=4"},"body":"It is not currently possible to determine the remote HEAD unambiguously\nwhen multiple remote branches share the same SHA1 as the remote HEAD.\n\nIn this situation, git remote set-head --auto should not try to guess\nwhich HEAD the user wants. This patch causes set-head to provide a\nuseful error instead:\n\n$ git remote set-head origin --auto\nerror: Multiple remote HEAD branches. Please choose one explicitly with:\n  git remote set-head origin another\n  git remote set-head origin master\n\nAlso, the output of git remote show now shows the multiple HEADs:\n\n$ git remote show origin\n* remote origin\n  URL: ...\n  HEAD branches:\n    another\n    master\n\nSigned-off-by: Jay Soffian <jaysoffian@gmail.com>\n---\n builtin-clone.c   |    2 +-\n builtin-remote.c  |   56 +++++++++++++++++++++++++++++++++++------------------\n remote.c          |   28 ++++++++++++++++++-------\n remote.h          |    6 ++++-\n t/t5505-remote.sh |   51 ++++++++++++++++++++++++++++++++++++++++++++++-\n 5 files changed, 112 insertions(+), 31 deletions(-)\n\ndiff --git a/builtin-clone.c b/builtin-clone.c\nindex d179d1c..d57818c 100644\n--- a/builtin-clone.c\n+++ b/builtin-clone.c\n@@ -510,7 +510,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix)\n \t\tmapped_refs = write_remote_refs(refs, &refspec, reflog_msg.buf);\n \n \t\thead_points_at = guess_remote_head(refs, mapped_refs,\n-\t\t\t\t\t\t   &remote_head);\n+\t\t\t\t\t\t   &remote_head, NULL);\n \t}\n \telse {\n \t\twarning(\"You appear to have cloned an empty repository.\");\ndiff --git a/builtin-remote.c b/builtin-remote.c\nindex fcb166b..608c0f3 100644\n--- a/builtin-remote.c\n+++ b/builtin-remote.c\n@@ -212,8 +212,7 @@ static void read_branches(void)\n \n struct ref_states {\n \tstruct remote *remote;\n-\tstruct string_list new, stale, tracked;\n-\tchar *head_name;\n+\tstruct string_list new, stale, tracked, heads;\n };\n \n static int handle_one_branch(const char *refname,\n@@ -273,24 +272,26 @@ static int get_ref_states(const struct ref *ref, struct ref_states *states)\n \treturn 0;\n }\n \n-static char *get_head_name(const struct ref *refs)\n+static int get_head_names(const struct ref *refs,\n+\tconst char *remote_name, struct ref_states *states)\n {\n-\tconst struct ref *head_points_at;\n-\tstruct ref *mapped_refs = NULL;\n-\tstruct ref **tail = &mapped_refs;\n+\tstruct ref *ref, *matches = NULL;\n+\tstruct ref *fetch_map = NULL, **fetch_map_tail = &fetch_map;\n \tstruct refspec refspec;\n \n \trefspec.force = 0;\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+\tguess_remote_head(refs, fetch_map, NULL, &matches);\n+\tfor(ref = matches; ref; ref = ref->next)\n+\t\tstring_list_append(abbrev_branch(ref->name), &states->heads);\n \n-\tget_fetch_map(refs, &refspec, &tail, 0);\n-\n-\thead_points_at = guess_remote_head(refs, mapped_refs, NULL);\n-\tif (head_points_at)\n-\t\treturn xstrdup(abbrev_branch(head_points_at->name));\n+\tfree_refs(fetch_map);\n+\tfree_refs(matches);\n \n-\treturn NULL;\n+\treturn 0;\n }\n \n struct known_remote {\n@@ -659,7 +660,7 @@ static void free_remote_ref_states(struct ref_states *states)\n \tstring_list_clear(&states->new, 0);\n \tstring_list_clear(&states->stale, 0);\n \tstring_list_clear(&states->tracked, 0);\n-\tfree(states->head_name);\n+\tstring_list_clear(&states->heads, 0);\n }\n \n static int get_remote_ref_states(const char *name,\n@@ -681,7 +682,7 @@ static int get_remote_ref_states(const char *name,\n \t\tref = transport_get_remote_refs(transport);\n \t\ttransport_disconnect(transport);\n \n-\t\tstates->head_name = get_head_name(ref);\n+\t\tget_head_names(ref, name, states);\n \t\tget_ref_states(ref, states);\n \t}\n \n@@ -726,9 +727,15 @@ static int show(int argc, const char **argv)\n \t\tprintf(\"* remote %s\\n  URL: %s\\n\", *argv,\n \t\t\tstates.remote->url_nr > 0 ?\n \t\t\t\tstates.remote->url[0] : \"(no URL)\");\n-\t\tif (!no_query)\n-\t\t\tprintf(\"  HEAD: %s\\n\", states.head_name ?\n-\t\t\t\tstates.head_name : \"(unknown)\");\n+\t\tif (no_query)\n+\t\t\tprintf(\"  HEAD branch: (not queried)\\n\");\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@@ -780,7 +787,7 @@ static int show(int argc, const char **argv)\n \n static int set_head(int argc, const char **argv)\n {\n-\tint opt_a = 0, opt_d = 0, result = 0;\n+\tint i, opt_a = 0, opt_d = 0, result = 0;\n \tstruct strbuf buf = STRBUF_INIT, buf2 = STRBUF_INIT;\n \tchar *head_name = NULL;\n \n@@ -802,7 +809,16 @@ static int set_head(int argc, const char **argv)\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\thead_name = xstrdup(states.head_name);\n+\t\tif (!states.heads.nr)\n+\t\t\tresult |= error(\"Cannot determine remote HEAD\");\n+\t\telse if (states.heads.nr > 1) {\n+\t\t\tresult |= error(\"Multiple remote HEAD branches. \"\n+\t\t\t\t\t\"Please choose one explicitly with:\");\n+\t\t\tfor (i = 0; i < states.heads.nr; i++)\n+\t\t\t\tfprintf(stderr, \"  git remote set-head %s %s\\n\",\n+\t\t\t\t\targv[0], states.heads.items[i].string);\n+\t\t} else\n+\t\t\thead_name = xstrdup(states.heads.items[0].string);\n \t\tfree_remote_ref_states(&states);\n \t} else if (opt_d && !opt_a && argc == 1) {\n \t\tif (delete_ref(buf.buf, NULL, REF_NODEREF))\n@@ -818,6 +834,8 @@ static int set_head(int argc, const char **argv)\n \t\t\tresult |= error(\"Not a valid ref: %s\", buf2.buf);\n \t\telse if (create_symref(buf.buf, buf2.buf, \"remote set-head\"))\n \t\t\tresult |= error(\"Could not setup %s\", buf.buf);\n+\t\tif (opt_a)\n+\t\t\tprintf(\"%s/HEAD set to %s\\n\", argv[0], head_name);\n \t\tfree(head_name);\n \t}\n \ndiff --git a/remote.c b/remote.c\nindex 447f091..6385a22 100644\n--- a/remote.c\n+++ b/remote.c\n@@ -1379,18 +1379,23 @@ int format_tracking_info(struct branch *branch, struct strbuf *sb)\n \n const struct ref *guess_remote_head(const struct ref *refs,\n \t\t\t\t    const struct ref *mapped_refs,\n-\t\t\t\t    const struct ref **remote_head_p)\n+\t\t\t\t    const struct ref **remote_head_p,\n+\t\t\t\t    struct ref **all_matches_p)\n {\n \tconst struct ref *remote_head = NULL;\n \tconst struct ref *remote_master = NULL;\n+\tconst struct ref *ret = NULL;\n \tconst struct ref *r;\n+\tstruct ref **tail = all_matches_p;\n+\n \tfor (r = refs; r; r = r->next)\n \t\tif (!strcmp(r->name, \"HEAD\"))\n \t\t\tremote_head = r;\n \n-\tfor (r = mapped_refs; r; r = r->next)\n-\t\tif (!strcmp(r->name, \"refs/heads/master\"))\n-\t\t\tremote_master = r;\n+\tif (!all_matches_p)\n+\t\tfor (r = mapped_refs; r; r = r->next)\n+\t\t\tif (!strcmp(r->name, \"refs/heads/master\"))\n+\t\t\t\tremote_master = r;\n \n \tif (remote_head_p)\n \t\t*remote_head_p = remote_head;\n@@ -1407,9 +1412,16 @@ const struct ref *guess_remote_head(const struct ref *refs,\n \t/* Look for another ref that points there */\n \tfor (r = mapped_refs; r; r = r->next)\n \t\tif (r != remote_head &&\n-\t\t    !hashcmp(r->old_sha1, remote_head->old_sha1))\n-\t\t\treturn r;\n+\t\t    !hashcmp(r->old_sha1, remote_head->old_sha1)) {\n+\t\t\tstruct ref *cpy;\n+\t\t\tif (!ret)\n+\t\t\t\tret = r;\n+\t\t\tif (!all_matches_p)\n+\t\t\t\tbreak;\n+\t\t\t*tail = cpy = copy_ref(r);\n+\t\t\tcpy->peer_ref = NULL;\n+\t\t\ttail = &cpy->next;\n+\t\t}\n \n-\t/* Nothing is the same */\n-\treturn NULL;\n+\treturn ret;\n }\ndiff --git a/remote.h b/remote.h\nindex cabb14a..8409d42 100644\n--- a/remote.h\n+++ b/remote.h\n@@ -141,9 +141,13 @@ int format_tracking_info(struct branch *branch, struct strbuf *sb);\n  * Look in refs for HEAD. Then look for a matching SHA1 in mapped_refs,\n  * first checking if refs/heads/master matches. Return NULL if nothing matches\n  * or if there is no HEAD in refs. remote_head_p is assigned HEAD if not NULL.\n+ * If all_matches_p is NULL, return after the first possible match. Otherwise\n+ * all_matches_p is set to a ref list of each branch head with the same SHA1 as\n+ * HEAD.\n  */\n const struct ref *guess_remote_head(const struct ref *refs,\n \t\t\t\t    const struct ref *mapped_refs,\n-\t\t\t\t    const struct ref **remote_head_p);\n+\t\t\t\t    const struct ref **remote_head_p,\n+\t\t\t\t    struct ref **all_matches_p);\n \n #endif\ndiff --git a/t/t5505-remote.sh b/t/t5505-remote.sh\nindex 826d0c3..9ea923b 100755\n--- a/t/t5505-remote.sh\n+++ b/t/t5505-remote.sh\n@@ -136,7 +136,7 @@ EOF\n cat > test/expect << EOF\n * remote origin\n   URL: $(pwd)/one\n-  HEAD: master\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@@ -147,6 +147,11 @@ cat > test/expect << EOF\n   Local branches pushed with 'git push'\n     master:upstream\n     +refs/tags/lastbackup\n+* remote two\n+  URL: ../two\n+  HEAD branches:\n+    another\n+    master\n EOF\n \n test_expect_success 'show' '\n@@ -155,6 +160,7 @@ test_expect_success 'show' '\n \t\trefs/heads/master:refs/heads/upstream &&\n \t git fetch &&\n \t git branch -d -r origin/master &&\n+\t git config --add remote.two.url ../two &&\n \t (cd ../one &&\n \t  echo 1 > file &&\n \t  test_tick &&\n@@ -163,13 +169,14 @@ test_expect_success 'show' '\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 remote show origin > output &&\n+\t git remote show origin two > output &&\n \t test_cmp expect output)\n '\n \n 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@@ -198,6 +205,46 @@ test_expect_success 'prune' '\n \t test_must_fail git rev-parse refs/remotes/origin/side)\n '\n \n+test_expect_success 'set-head --delete' '\n+\t(cd test &&\n+\t git symbolic-ref refs/remotes/origin/HEAD &&\n+\t git remote set-head --delete origin &&\n+\t test_must_fail git symbolic-ref refs/remotes/origin/HEAD)\n+'\n+\n+test_expect_success 'set-head --auto' '\n+\t(cd test &&\n+\t git remote set-head --auto origin &&\n+\t echo refs/remotes/origin/master >expect &&\n+\t git symbolic-ref refs/remotes/origin/HEAD >output &&\n+\t test_cmp expect output\n+\t)\n+'\n+\n+cat >test/expect <<EOF\n+error: Multiple remote HEAD branches. Please choose one explicitly with:\n+  git remote set-head two another\n+  git remote set-head two master\n+EOF\n+\n+test_expect_success 'set-head --auto fails w/multiple HEADs' '\n+\t(cd test &&\n+\t test_must_fail git remote set-head --auto two >output 2>&1 &&\n+\ttest_cmp expect output)\n+'\n+\n+cat >test/expect <<EOF\n+refs/remotes/origin/side2\n+EOF\n+\n+test_expect_success 'set-head explicit' '\n+\t(cd test &&\n+\t git remote set-head origin side2 &&\n+\t git symbolic-ref refs/remotes/origin/HEAD >output &&\n+\t git remote set-head origin master &&\n+\t test_cmp expect output)\n+'\n+\n cat > test/expect << EOF\n Pruning origin\n URL: $(pwd)/one\n-- \n1.6.2.rc1.291.g83eb\n"},{"id":"106023","messageId":"9bcec2dfd965836ae4a34385f4db7e7b42d313a5.1235467368.git.jaysoffian@gmail.com","threadId":"17987","inReplyTo":"cover.1235467368.git.jaysoffian@gmail.com","subject":"[PATCH 06/23] remote.c: make match_refs() copy src ref before assigning to peer_ref","fromName":"Jay Soffian","fromEmail":"jaysoffian@gmail.com","sentAt":"2009-02-24T09:50:54Z","receivedAt":"2009-02-24T09:50:54Z","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. This prevents\ncallers from freeing both the src and dst lists, as doing so would cause\na double-free since free_refs() frees the peer_ref.\n\nAs well, the following configuration causes two refs in the dst list to\nhave the same peer_ref, which can also lead to a double-free:\n\n  push = refs/heads/master:refs/heads/backup\n  push = refs/heads/master:refs/heads/master\n\nExisting callers of match_heads() call it only once and then terminate,\nw/o ever bothering to free the src or dst lists, so this is not\ncurrently a problem.\n\nThis patch modifies match_refs() to first copy any refs it plucks from\nthe src list before assigning them as a peer_ref, thus future-proofing\nthe function against callers who might wish to free the src and/or dst\nlists.\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 6385a22..64879ce 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":"106028","messageId":"502989f7aa7d2066089d9e31ee2d71578998175e.1235467368.git.jaysoffian@gmail.com","threadId":"17987","inReplyTo":"cover.1235467368.git.jaysoffian@gmail.com","subject":"[PATCH 07/23] remote.c: don't short-circuit match_refs() when error in match_explicit_refs()","fromName":"Jay Soffian","fromEmail":"jaysoffian@gmail.com","sentAt":"2009-02-24T09:50:55Z","receivedAt":"2009-02-24T09:50:55Z","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 64879ce..9f22aaf 100644\n--- a/remote.c\n+++ b/remote.c\n@@ -1043,6 +1043,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@@ -1050,8 +1051,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@@ -1107,6 +1107,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.291.g83eb\n"},{"id":"106025","messageId":"f6fd75cecc0eeeceaaf933da0fbc4b71d3f60962.1235467368.git.jaysoffian@gmail.com","threadId":"17987","inReplyTo":"cover.1235467368.git.jaysoffian@gmail.com","subject":"[PATCH 08/23] refactor duplicated get_local_heads() to remote.c","fromName":"Jay Soffian","fromEmail":"jaysoffian@gmail.com","sentAt":"2009-02-24T09:50:56Z","receivedAt":"2009-02-24T09:50: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 9f22aaf..8fd8d23 100644\n--- a/remote.c\n+++ b/remote.c\n@@ -1430,3 +1430,29 @@ const struct ref *guess_remote_head(const struct ref *refs,\n \n \treturn ret;\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 8409d42..6ff0cda 100644\n--- a/remote.h\n+++ b/remote.h\n@@ -150,4 +150,5 @@ const struct ref *guess_remote_head(const struct ref *refs,\n \t\t\t\t    const struct ref **remote_head_p,\n \t\t\t\t    struct ref **all_matches_p);\n \n+struct ref *get_local_heads(void);\n #endif\n-- \n1.6.2.rc1.291.g83eb\n"},{"id":"106020","messageId":"4d8bdf7e8275435b717f1eb13b5ba18dd37fe194.1235467368.git.jaysoffian@gmail.com","threadId":"17987","inReplyTo":"cover.1235467368.git.jaysoffian@gmail.com","subject":"[PATCH 09/23] refactor duplicated ref_newer() to remote.c","fromName":"Jay Soffian","fromEmail":"jaysoffian@gmail.com","sentAt":"2009-02-24T09:50:57Z","receivedAt":"2009-02-24T09:50: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. 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---\n builtin-send-pack.c |   50 --------------------------------------------------\n http-push.c         |   49 -------------------------------------------------\n remote.c            |   49 +++++++++++++++++++++++++++++++++++++++++++++++++\n remote.h            |    1 +\n 4 files changed, 50 insertions(+), 99 deletions(-)\n\ndiff --git a/builtin-send-pack.c b/builtin-send-pack.c\nindex 2fbfc29..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@@ -84,55 +83,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 8fd8d23..f07ecf4 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@@ -1274,6 +1275,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 6ff0cda..1f78a0a 100644\n--- a/remote.h\n+++ b/remote.h\n@@ -74,6 +74,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.291.g83eb\n"},{"id":"106026","messageId":"66b5906b903b73ab022cdfdb7038035311fa5548.1235467368.git.jaysoffian@gmail.com","threadId":"17987","inReplyTo":"cover.1235467368.git.jaysoffian@gmail.com","subject":"[PATCH 10/23] string-list: new for_each_string_list() function","fromName":"Jay Soffian","fromEmail":"jaysoffian@gmail.com","sentAt":"2009-02-24T09:50:58Z","receivedAt":"2009-02-24T09:50:58Z","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.291.g83eb\n"},{"id":"106030","messageId":"c2de944b2fc5315c2d0f88cb16ad8b17033329a7.1235467368.git.jaysoffian@gmail.com","threadId":"17987","inReplyTo":"cover.1235467368.git.jaysoffian@gmail.com","subject":"[PATCH 11/23] builtin-remote: rename variable and eliminate redundant function call","fromName":"Jay Soffian","fromEmail":"jaysoffian@gmail.com","sentAt":"2009-02-24T09:50:59Z","receivedAt":"2009-02-24T09:50:59Z","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 608c0f3..48d668e 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@@ -489,7 +488,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@@ -599,7 +598,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@@ -742,7 +741,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.291.g83eb\n"},{"id":"106021","messageId":"713e5cc2722a0eacd5b14146b01bb5d455870474.1235467368.git.jaysoffian@gmail.com","threadId":"17987","inReplyTo":"cover.1235467368.git.jaysoffian@gmail.com","subject":"[PATCH 12/23] builtin-remote: name remote_refs consistently","fromName":"Jay Soffian","fromEmail":"jaysoffian@gmail.com","sentAt":"2009-02-24T09:51:00Z","receivedAt":"2009-02-24T09:51:00Z","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 |   19 ++++++++++---------\n 1 files changed, 10 insertions(+), 9 deletions(-)\n\ndiff --git a/builtin-remote.c b/builtin-remote.c\nindex 48d668e..d5c808c 100644\n--- a/builtin-remote.c\n+++ b/builtin-remote.c\n@@ -238,13 +238,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@@ -271,7 +272,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 = NULL;\n@@ -282,8 +283,8 @@ 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-\tguess_remote_head(refs, fetch_map, NULL, &matches);\n+\tget_fetch_map(remote_refs, &refspec, &fetch_map_tail, 0);\n+\tguess_remote_head(remote_refs, fetch_map, NULL, &matches);\n \tfor(ref = matches; ref; ref = ref->next)\n \t\tstring_list_append(abbrev_branch(ref->name), &states->heads);\n \n@@ -667,7 +668,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@@ -678,11 +679,11 @@ 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}\n \n \treturn 0;\n-- \n1.6.2.rc1.291.g83eb\n"},{"id":"106035","messageId":"b968867b87671e478382b3ecd873fc82e5a4909d.1235467368.git.jaysoffian@gmail.com","threadId":"17987","inReplyTo":"cover.1235467368.git.jaysoffian@gmail.com","subject":"[PATCH 13/23] builtin-remote: remove unused code in get_ref_states","fromName":"Jay Soffian","fromEmail":"jaysoffian@gmail.com","sentAt":"2009-02-24T09:51:01Z","receivedAt":"2009-02-24T09:51:01Z","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 d5c808c..56d73c8 100644\n--- a/builtin-remote.c\n+++ b/builtin-remote.c\n@@ -251,18 +251,11 @@ static int get_ref_states(const struct ref *remote_refs, struct ref_states *stat\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.291.g83eb\n"},{"id":"106031","messageId":"adaab0f7a5ce8d9b5aee492052a0a9791230f551.1235467368.git.jaysoffian@gmail.com","threadId":"17987","inReplyTo":"cover.1235467368.git.jaysoffian@gmail.com","subject":"[PATCH 14/23] builtin-remote: fix two inconsistencies in the output of \"show <remote>\"","fromName":"Jay Soffian","fromEmail":"jaysoffian@gmail.com","sentAt":"2009-02-24T09:51:02Z","receivedAt":"2009-02-24T09:51:02Z","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 56d73c8..cb56565 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@@ -259,6 +257,8 @@ static int get_ref_states(const struct ref *remote_refs, struct ref_states *stat\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 9ea923b..56146eb 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.291.g83eb\n"},{"id":"106027","messageId":"1c2c1a61e4add51c8a7d748c72365af651aac94f.1235467368.git.jaysoffian@gmail.com","threadId":"17987","inReplyTo":"cover.1235467368.git.jaysoffian@gmail.com","subject":"[PATCH 15/23] builtin-remote: make get_remote_ref_states() always populate states.tracked","fromName":"Jay Soffian","fromEmail":"jaysoffian@gmail.com","sentAt":"2009-02-24T09:51:03Z","receivedAt":"2009-02-24T09:51:03Z","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 cb56565..5ef8163 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(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 \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.291.g83eb\n"},{"id":"106038","messageId":"29438718de2df87754786279cd138b0d1fe0ca0e.1235467368.git.jaysoffian@gmail.com","threadId":"17987","inReplyTo":"cover.1235467368.git.jaysoffian@gmail.com","subject":"[PATCH 16/23] builtin-remote: refactor get_remote_ref_states()","fromName":"Jay Soffian","fromEmail":"jaysoffian@gmail.com","sentAt":"2009-02-24T09:51:04Z","receivedAt":"2009-02-24T09:51:04Z","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 |   21 ++++++++++++++-------\n 1 files changed, 14 insertions(+), 7 deletions(-)\n\ndiff --git a/builtin-remote.c b/builtin-remote.c\nindex 5ef8163..a822bd5 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@@ -691,9 +694,10 @@ 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-\n-\t\tget_head_names(remote_refs, name, states);\n-\t\tget_ref_states(remote_refs, states);\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@@ -704,7 +708,7 @@ static int get_remote_ref_states(const char *name,\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@@ -717,11 +721,14 @@ 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 \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@@ -805,7 +812,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@@ -865,7 +872,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.291.g83eb\n"},{"id":"106036","messageId":"43310a608c096dc40c9d39712a2f36433b783368.1235467368.git.jaysoffian@gmail.com","threadId":"17987","inReplyTo":"cover.1235467368.git.jaysoffian@gmail.com","subject":"[PATCH 17/23] builtin-remote: new show output style","fromName":"Jay Soffian","fromEmail":"jaysoffian@gmail.com","sentAt":"2009-02-24T09:51:05Z","receivedAt":"2009-02-24T09:51:05Z","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---\n builtin-remote.c  |  190 ++++++++++++++++++++++++++++++++++++++++-------------\n t/t5505-remote.sh |   31 +++++----\n 2 files changed, 162 insertions(+), 59 deletions(-)\n\ndiff --git a/builtin-remote.c b/builtin-remote.c\nindex a822bd5..852f779 100644\n--- a/builtin-remote.c\n+++ b/builtin-remote.c\n@@ -149,6 +149,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@@ -165,10 +166,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@@ -177,6 +179,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@@ -187,9 +192,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@@ -200,7 +205,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@@ -215,6 +221,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@@ -637,20 +644,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@@ -694,6 +687,7 @@ 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\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@@ -702,6 +696,103 @@ 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+\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@@ -715,6 +806,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@@ -725,6 +818,9 @@ static int show(int argc, const char **argv)\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+\tinfo.list = &info_list;\n \tfor (; argc; argc--, argv++) {\n \t\tint i;\n \n@@ -738,37 +834,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}\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\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\tshow_list(\"  Tracked remote branch%s\", &states.tracked, \"\");\n-\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\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 56146eb..835adbd 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.291.g83eb\n"},{"id":"106034","messageId":"18216c16b6e745d1a0271e3f2a483fd262bfde53.1235467368.git.jaysoffian@gmail.com","threadId":"17987","inReplyTo":"cover.1235467368.git.jaysoffian@gmail.com","subject":"[PATCH 18/23] builtin-remote: new show output style for push refspecs","fromName":"Jay Soffian","fromEmail":"jaysoffian@gmail.com","sentAt":"2009-02-24T09:51:06Z","receivedAt":"2009-02-24T09:51:06Z","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---\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 852f779..80ab7af 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@@ -644,12 +751,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@@ -692,9 +807,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@@ -702,7 +820,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@@ -797,6 +915,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@@ -815,7 +985,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@@ -865,19 +1035,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 835adbd..5ec668d 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.291.g83eb\n"},{"id":"106033","messageId":"3149d7f0af526b2e0654c88b4aba6e47f2ffab7c.1235467368.git.jaysoffian@gmail.com","threadId":"17987","inReplyTo":"cover.1235467368.git.jaysoffian@gmail.com","subject":"[PATCH 19/23] test scripts: refactor start_httpd helper","fromName":"Jay Soffian","fromEmail":"jaysoffian@gmail.com","sentAt":"2009-02-24T09:51:07Z","receivedAt":"2009-02-24T09:51:07Z","isPatch":true,"sender":{"key":"jaysoffian@gmail.com","avatar":"https://avatars.githubusercontent.com/u/155970?v=4"},"body":"From: Jeff King <peff@peff.net>\n\nThere are some redirects and some error checking that need\nto be done by the caller; let's move both into the\nstart_httpd function so that all callers don't have to\nrepeat them (there is only one caller now, but another will\nfollow in this series).\n\nThis doesn't violate any assumptions that aren't already\nbeing made by lib-httpd, which is happy to say \"skipping\"\nand call test_done for a number of other cases.\n\nSigned-off-by: Jeff King <peff@peff.net>\nSigned-off-by: Jay Soffian <jaysoffian@gmail.com>\n---\n t/lib-httpd.sh       |    9 +++++++--\n t/t5540-http-push.sh |    8 +-------\n 2 files changed, 8 insertions(+), 9 deletions(-)\n\ndiff --git a/t/lib-httpd.sh b/t/lib-httpd.sh\nindex 3824020..88cfc51 100644\n--- a/t/lib-httpd.sh\n+++ b/t/lib-httpd.sh\n@@ -82,13 +82,18 @@ prepare_httpd() {\n }\n \n start_httpd() {\n-\tprepare_httpd\n+\tprepare_httpd >&3 2>&4\n \n \ttrap 'stop_httpd; die' EXIT\n \n \t\"$LIB_HTTPD_PATH\" -d \"$HTTPD_ROOT_PATH\" \\\n \t\t-f \"$TEST_PATH/apache.conf\" $HTTPD_PARA \\\n-\t\t-c \"Listen 127.0.0.1:$LIB_HTTPD_PORT\" -k start\n+\t\t-c \"Listen 127.0.0.1:$LIB_HTTPD_PORT\" -k start \\\n+\t\t>&3 2>&4\n+\tif ! test $? = 0; then\n+\t\tsay \"skipping test, web server setup failed\"\n+\t\ttest_done\n+\tfi\n }\n \n stop_httpd() {\ndiff --git a/t/t5540-http-push.sh b/t/t5540-http-push.sh\nindex 11b3432..57a4411 100755\n--- a/t/t5540-http-push.sh\n+++ b/t/t5540-http-push.sh\n@@ -20,13 +20,7 @@ then\n fi\n \n . \"$TEST_DIRECTORY\"/lib-httpd.sh\n-\n-if ! start_httpd >&3 2>&4\n-then\n-\tsay \"skipping test, web server setup failed\"\n-\ttest_done\n-\texit\n-fi\n+start_httpd\n \n test_expect_success 'setup remote repository' '\n \tcd \"$ROOT_PATH\" &&\n-- \n1.6.2.rc1.291.g83eb\n"},{"id":"106029","messageId":"0e92666b696fa7044bb44108015de6b9325ca57e.1235467368.git.jaysoffian@gmail.com","threadId":"17987","inReplyTo":"cover.1235467368.git.jaysoffian@gmail.com","subject":"[PATCH 20/23] add basic http clone/fetch tests","fromName":"Jay Soffian","fromEmail":"jaysoffian@gmail.com","sentAt":"2009-02-24T09:51:08Z","receivedAt":"2009-02-24T09:51:08Z","isPatch":true,"sender":{"key":"jaysoffian@gmail.com","avatar":"https://avatars.githubusercontent.com/u/155970?v=4"},"body":"From: Jeff King <peff@peff.net>\n\nThis was mostly being tested implicitly by the \"http push\"\ntests. But making a separate test script means that:\n\n  - we will run fetch tests even when http pushing support\n    is not built\n\n  - when there are failures on fetching, they are easier to\n    see and isolate, as they are not in the middle of push\n    tests\n\nThis script defaults to running the webserver on port 5550,\nand puts the original t5540 on port 5540, so that the two\ncan be run simultaneously without conflict (but both still\nrespect an externally set LIB_HTTPD_PORT).\n\nSigned-off-by: Jeff King <peff@peff.net>\nSigned-off-by: Jay Soffian <jaysoffian@gmail.com>\n---\n Makefile              |    1 +\n t/t5540-http-push.sh  |    1 +\n t/t5550-http-fetch.sh |   46 ++++++++++++++++++++++++++++++++++++++++++++++\n 3 files changed, 48 insertions(+), 0 deletions(-)\n create mode 100755 t/t5550-http-fetch.sh\n\ndiff --git a/Makefile b/Makefile\nindex b040a96..5e54c9c 100644\n--- a/Makefile\n+++ b/Makefile\n@@ -1363,6 +1363,7 @@ GIT-CFLAGS: .FORCE-GIT-CFLAGS\n GIT-BUILD-OPTIONS: .FORCE-GIT-BUILD-OPTIONS\n \t@echo SHELL_PATH=\\''$(subst ','\\'',$(SHELL_PATH_SQ))'\\' >$@\n \t@echo TAR=\\''$(subst ','\\'',$(subst ','\\'',$(TAR)))'\\' >>$@\n+\t@echo NO_CURL=\\''$(subst ','\\'',$(subst ','\\'',$(NO_CURL)))'\\' >>$@\n \n ### Detect Tck/Tk interpreter path changes\n ifndef NO_TCLTK\ndiff --git a/t/t5540-http-push.sh b/t/t5540-http-push.sh\nindex 57a4411..cefab45 100755\n--- a/t/t5540-http-push.sh\n+++ b/t/t5540-http-push.sh\n@@ -11,6 +11,7 @@ This test runs various sanity checks on http-push.'\n \n ROOT_PATH=\"$PWD\"\n LIB_HTTPD_DAV=t\n+LIB_HTTPD_PORT=${LIB_HTTPD_PORT-'5540'}\n \n if git http-push > /dev/null 2>&1 || [ $? -eq 128 ]\n then\ndiff --git a/t/t5550-http-fetch.sh b/t/t5550-http-fetch.sh\nnew file mode 100755\nindex 0000000..b6e6ec9\n--- /dev/null\n+++ b/t/t5550-http-fetch.sh\n@@ -0,0 +1,46 @@\n+#!/bin/sh\n+\n+test_description='test fetching over http'\n+. ./test-lib.sh\n+\n+if test -n \"$NO_CURL\"; then\n+\tsay 'skipping test, git built without http support'\n+\ttest_done\n+fi\n+\n+. \"$TEST_DIRECTORY\"/lib-httpd.sh\n+LIB_HTTPD_PORT=${LIB_HTTPD_PORT-'5550'}\n+start_httpd\n+\n+test_expect_success 'setup repository' '\n+\techo content >file &&\n+\tgit add file &&\n+\tgit commit -m one\n+'\n+\n+test_expect_success 'create http-accessible bare repository' '\n+\tmkdir \"$HTTPD_DOCUMENT_ROOT_PATH/repo.git\" &&\n+\t(cd \"$HTTPD_DOCUMENT_ROOT_PATH/repo.git\" &&\n+\t git --bare init &&\n+\t echo \"exec git update-server-info\" >hooks/post-update &&\n+\t chmod +x hooks/post-update\n+\t) &&\n+\tgit remote add public \"$HTTPD_DOCUMENT_ROOT_PATH/repo.git\" &&\n+\tgit push public master:master\n+'\n+\n+test_expect_success 'clone http repository' '\n+\tgit clone $HTTPD_URL/repo.git clone &&\n+\ttest_cmp file clone/file\n+'\n+\n+test_expect_success 'fetch changes via http' '\n+\techo content >>file &&\n+\tgit commit -a -m two &&\n+\tgit push public\n+\t(cd clone && git pull) &&\n+\ttest_cmp file clone/file\n+'\n+\n+stop_httpd\n+test_done\n-- \n1.6.2.rc1.291.g83eb\n"},{"id":"106037","messageId":"ca07244190a8ed3eba1ee19198e53dbb6ae09417.1235467368.git.jaysoffian@gmail.com","threadId":"17987","inReplyTo":"cover.1235467368.git.jaysoffian@gmail.com","subject":"[PATCH 21/23] refactor find_refs_by_name to accept const list","fromName":"Jay Soffian","fromEmail":"jaysoffian@gmail.com","sentAt":"2009-02-24T09:51:09Z","receivedAt":"2009-02-24T09:51:09Z","isPatch":true,"sender":{"key":"jaysoffian@gmail.com","avatar":"https://avatars.githubusercontent.com/u/155970?v=4"},"body":"From: Jeff King <peff@peff.net>\n\nSince it doesn't actually touch its argument, this makes\nsense.\n\nHowever, we still want to return a non-const version (which\nrequires a cast) so that this:\n\n  struct ref *a, *b;\n  a = find_ref_by_name(b);\n\nworks. Unfortunately, you can also silently strip the const\nfrom a variable:\n\n  struct ref *a;\n  const struct ref *b;\n  a = find_ref_by_name(b);\n\nThis is a classic C const problem because there is no way to\nsay \"return the type with the same constness that was passed\nto us\"; we provide the same semantics as standard library\nfunctions like strchr.\n\nSigned-off-by: Jeff King <peff@peff.net>\nSigned-off-by: Jay Soffian <jaysoffian@gmail.com>\n---\n cache.h |    2 +-\n refs.c  |    4 ++--\n 2 files changed, 3 insertions(+), 3 deletions(-)\n\ndiff --git a/cache.h b/cache.h\nindex 189151d..609380d 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -801,7 +801,7 @@ struct ref {\n #define REF_HEADS\t(1u << 1)\n #define REF_TAGS\t(1u << 2)\n \n-extern struct ref *find_ref_by_name(struct ref *list, const char *name);\n+extern struct ref *find_ref_by_name(const struct ref *list, const char *name);\n \n #define CONNECT_VERBOSE       (1u << 0)\n extern struct child_process *git_connect(int fd[2], const char *url, const char *prog, int flags);\ndiff --git a/refs.c b/refs.c\nindex 6eb5f53..b2a37e1 100644\n--- a/refs.c\n+++ b/refs.c\n@@ -1628,10 +1628,10 @@ int update_ref(const char *action, const char *refname,\n \treturn 0;\n }\n \n-struct ref *find_ref_by_name(struct ref *list, const char *name)\n+struct ref *find_ref_by_name(const struct ref *list, const char *name)\n {\n \tfor ( ; list; list = list->next)\n \t\tif (!strcmp(list->name, name))\n-\t\t\treturn list;\n+\t\t\treturn (struct ref *)list;\n \treturn NULL;\n }\n-- \n1.6.2.rc1.291.g83eb\n"},{"id":"106032","messageId":"9fcb7dbd8ec6fbed4701098a2fecc5728521dbc7.1235467368.git.jaysoffian@gmail.com","threadId":"17987","inReplyTo":"cover.1235467368.git.jaysoffian@gmail.com","subject":"[PATCH 22/23] remote: refactor guess_remote_head","fromName":"Jay Soffian","fromEmail":"jaysoffian@gmail.com","sentAt":"2009-02-24T09:51:10Z","receivedAt":"2009-02-24T09:51:10Z","isPatch":true,"sender":{"key":"jaysoffian@gmail.com","avatar":"https://avatars.githubusercontent.com/u/155970?v=4"},"body":"From: Jeff King <peff@peff.net>\n\nThis function had a lot of complications which made it hard\nto read and extend, and confusing to call (because of\noptional unused parameters). This patch attempts to address\nthat:\n\n  - we used to manually search through the ref lists; this\n    should be a one-line call to find_ref_by_name\n\n  - guess_remote_head used to do two things: find the HEAD\n    ref, and then find a matching ref. And only one of the\n    two callers actually cared about returning the HEAD ref.\n    Since it's a one-liner, just have the caller do it\n    themselves (and remember it or not as they wish).\n\n  - there were two ways of getting results out of the\n    function (a return value, and an \"all_matched\" out\n    parameter), but no caller cared about both. One of them\n    returned a pointer into the passed-in ref list and one\n    of them returned a newly allocated list (with the\n    peer_ref fields stripped). Let's be simple and\n    consistent: the return value is always a ref copy with\n    a valid peer_ref. If \"all\" is requested, all candidates\n    are returned. Otherwise, the best candidate is returned.\n\nSigned-off-by: Jeff King <peff@peff.net>\nSigned-off-by: Jay Soffian <jaysoffian@gmail.com>\n---\n builtin-clone.c  |    5 +--\n builtin-remote.c |    5 ++-\n remote.c         |   62 ++++++++++++++++++++++-------------------------------\n remote.h         |   17 ++++++--------\n 4 files changed, 38 insertions(+), 51 deletions(-)\n\ndiff --git a/builtin-clone.c b/builtin-clone.c\nindex d57818c..7130cab 100644\n--- a/builtin-clone.c\n+++ b/builtin-clone.c\n@@ -508,9 +508,8 @@ int cmd_clone(int argc, const char **argv, const char *prefix)\n \t\tclear_extra_refs();\n \n \t\tmapped_refs = write_remote_refs(refs, &refspec, reflog_msg.buf);\n-\n-\t\thead_points_at = guess_remote_head(refs, mapped_refs,\n-\t\t\t\t\t\t   &remote_head, NULL);\n+\t\tremote_head = find_ref_by_name(refs, \"HEAD\");\n+\t\thead_points_at = guess_remote_head(remote_head, mapped_refs, 0);\n \t}\n \telse {\n \t\twarning(\"You appear to have cloned an empty repository.\");\ndiff --git a/builtin-remote.c b/builtin-remote.c\nindex 80ab7af..d5a575f 100644\n--- a/builtin-remote.c\n+++ b/builtin-remote.c\n@@ -385,7 +385,7 @@ static int get_push_ref_states_noquery(struct ref_states *states)\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 = NULL;\n+\tstruct ref *ref, *matches;\n \tstruct ref *fetch_map = NULL, **fetch_map_tail = &fetch_map;\n \tstruct refspec refspec;\n \n@@ -394,7 +394,8 @@ static int get_head_names(const struct ref *remote_refs,\n \trefspec.src = refspec.dst = \"refs/heads/\";\n \tstates->heads.strdup_strings = 1;\n \tget_fetch_map(remote_refs, &refspec, &fetch_map_tail, 0);\n-\tguess_remote_head(remote_refs, fetch_map, NULL, &matches);\n+\tmatches = guess_remote_head(find_ref_by_name(remote_refs, \"HEAD\"),\n+\t\t\t\t\tfetch_map, 1);\n \tfor(ref = matches; ref; ref = ref->next)\n \t\tstring_list_append(abbrev_branch(ref->name), &states->heads);\n \ndiff --git a/remote.c b/remote.c\nindex f07ecf4..96d5c95 100644\n--- a/remote.c\n+++ b/remote.c\n@@ -1431,53 +1431,43 @@ int format_tracking_info(struct branch *branch, struct strbuf *sb)\n \treturn 1;\n }\n \n-const struct ref *guess_remote_head(const struct ref *refs,\n-\t\t\t\t    const struct ref *mapped_refs,\n-\t\t\t\t    const struct ref **remote_head_p,\n-\t\t\t\t    struct ref **all_matches_p)\n+struct ref *copy_ref_with_peer(const struct ref *src)\n {\n-\tconst struct ref *remote_head = NULL;\n-\tconst struct ref *remote_master = NULL;\n-\tconst struct ref *ret = NULL;\n-\tconst struct ref *r;\n-\tstruct ref **tail = all_matches_p;\n-\n-\tfor (r = refs; r; r = r->next)\n-\t\tif (!strcmp(r->name, \"HEAD\"))\n-\t\t\tremote_head = r;\n-\n-\tif (!all_matches_p)\n-\t\tfor (r = mapped_refs; r; r = r->next)\n-\t\t\tif (!strcmp(r->name, \"refs/heads/master\"))\n-\t\t\t\tremote_master = r;\n+\tstruct ref *dst = copy_ref(src);\n+\tdst->peer_ref = copy_ref(src->peer_ref);\n+\treturn dst;\n+}\n \n-\tif (remote_head_p)\n-\t\t*remote_head_p = remote_head;\n+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+\tconst struct ref *r;\n+\tstruct ref *list = NULL;\n+\tstruct ref **tail = &list;\n \n-\t/* If there's no HEAD value at all, never mind. */\n-\tif (!remote_head)\n+\tif (!head)\n \t\treturn NULL;\n \n \t/* If refs/heads/master could be right, it is. */\n-\tif (remote_master && !hashcmp(remote_master->old_sha1,\n-\t\t\t\t      remote_head->old_sha1))\n-\t\treturn remote_master;\n+\tif (!all) {\n+\t\tconst struct ref *m;\n+\t\tm = find_ref_by_name(refs, \"refs/heads/master\");\n+\t\tif (m && !hashcmp(m->old_sha1, head->old_sha1))\n+\t\t\treturn copy_ref_with_peer(m);\n+\t}\n \n \t/* Look for another ref that points there */\n-\tfor (r = mapped_refs; r; r = r->next)\n-\t\tif (r != remote_head &&\n-\t\t    !hashcmp(r->old_sha1, remote_head->old_sha1)) {\n-\t\t\tstruct ref *cpy;\n-\t\t\tif (!ret)\n-\t\t\t\tret = r;\n-\t\t\tif (!all_matches_p)\n+\tfor (r = refs; r; r = r->next) {\n+\t\tif (r != head && !hashcmp(r->old_sha1, head->old_sha1)) {\n+\t\t\t*tail = copy_ref_with_peer(r);\n+\t\t\ttail = &((*tail)->next);\n+\t\t\tif (!all)\n \t\t\t\tbreak;\n-\t\t\t*tail = cpy = copy_ref(r);\n-\t\t\tcpy->peer_ref = NULL;\n-\t\t\ttail = &cpy->next;\n \t\t}\n+\t}\n \n-\treturn ret;\n+\treturn list;\n }\n \n static int one_local_ref(const char *refname, const unsigned char *sha1, int flag, void *cb_data)\ndiff --git a/remote.h b/remote.h\nindex 1f78a0a..903712f 100644\n--- a/remote.h\n+++ b/remote.h\n@@ -139,17 +139,14 @@ int stat_tracking_info(struct branch *branch, int *num_ours, int *num_theirs);\n int format_tracking_info(struct branch *branch, struct strbuf *sb);\n \n /*\n- * Look in refs for HEAD. Then look for a matching SHA1 in mapped_refs,\n- * first checking if refs/heads/master matches. Return NULL if nothing matches\n- * or if there is no HEAD in refs. remote_head_p is assigned HEAD if not NULL.\n- * If all_matches_p is NULL, return after the first possible match. Otherwise\n- * all_matches_p is set to a ref list of each branch head with the same SHA1 as\n- * HEAD.\n+ * Find refs from a list which are likely to be pointed to by the given HEAD\n+ * ref. If 'all' is false, returns the most likely ref; otherwise, returns a\n+ * list of all candidate refs. If no match is found (or 'head' is NULL),\n+ * returns NULL. All returns are newly allocated and should be freed.\n  */\n-const struct ref *guess_remote_head(const struct ref *refs,\n-\t\t\t\t    const struct ref *mapped_refs,\n-\t\t\t\t    const struct ref **remote_head_p,\n-\t\t\t\t    struct ref **all_matches_p);\n+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.291.g83eb\n"},{"id":"106024","messageId":"c87a95887e5de0258fa4d32f3aac195768b39949.1235467368.git.jaysoffian@gmail.com","threadId":"17987","inReplyTo":"cover.1235467368.git.jaysoffian@gmail.com","subject":"[PATCH 23/23] remote: use exact HEAD lookup if it is available","fromName":"Jay Soffian","fromEmail":"jaysoffian@gmail.com","sentAt":"2009-02-24T09:51:11Z","receivedAt":"2009-02-24T09:51:11Z","isPatch":true,"sender":{"key":"jaysoffian@gmail.com","avatar":"https://avatars.githubusercontent.com/u/155970?v=4"},"body":"From: Jeff King <peff@peff.net>\n\nOur usual method for determining the ref pointed to by HEAD\nis to compare HEAD's sha1 to the sha1 of all refs, trying to\nfind a unique match.\n\nHowever, some transports actually get to look at HEAD\ndirectly; we should make use of that information when it is\navailable.  Currently, only http remotes support this\nfeature.\n\nSigned-off-by: Jeff King <peff@peff.net>\nSigned-off-by: Jay Soffian <jaysoffian@gmail.com>\n---\n remote.c              |   10 ++++++++++\n t/t5550-http-fetch.sh |   11 +++++++++++\n 2 files changed, 21 insertions(+), 0 deletions(-)\n\ndiff --git a/remote.c b/remote.c\nindex 96d5c95..682af74 100644\n--- a/remote.c\n+++ b/remote.c\n@@ -1449,6 +1449,16 @@ struct ref *guess_remote_head(const struct ref *head,\n \tif (!head)\n \t\treturn NULL;\n \n+\t/*\n+\t * Some transports support directly peeking at\n+\t * where HEAD points; if that is the case, then\n+\t * we don't have to guess.\n+\t */\n+\tif (head->symref) {\n+\t\tr = find_ref_by_name(refs, head->symref);\n+\t\treturn r ? copy_ref_with_peer(r) : NULL;\n+\t}\n+\n \t/* If refs/heads/master could be right, it is. */\n \tif (!all) {\n \t\tconst struct ref *m;\ndiff --git a/t/t5550-http-fetch.sh b/t/t5550-http-fetch.sh\nindex b6e6ec9..05b1b62 100755\n--- a/t/t5550-http-fetch.sh\n+++ b/t/t5550-http-fetch.sh\n@@ -42,5 +42,16 @@ test_expect_success 'fetch changes via http' '\n \ttest_cmp file clone/file\n '\n \n+test_expect_success 'http remote detects correct HEAD' '\n+\tgit push public master:other &&\n+\t(cd clone &&\n+\t git remote set-head origin -d &&\n+\t git remote set-head origin -a &&\n+\t git symbolic-ref refs/remotes/origin/HEAD > output &&\n+\t echo refs/remotes/origin/master > expect &&\n+\t test_cmp expect output\n+\t)\n+'\n+\n stop_httpd\n test_done\n-- \n1.6.2.rc1.291.g83eb\n"}]}