{"thread":{"id":"8526","subject":"[PATCH 1/5] remote.c: refactor match_explicit_refs()","startedAt":"2007-06-09T09:21:32Z","lastAt":"2007-06-10T06:59:17Z","messageCount":6,"participants":["Junio C Hamano"],"isPatch":true,"patchVersion":1,"patchTotal":5},"messages":[{"id":"44436","messageId":"11813808962261-git-send-email-gitster@pobox.com","threadId":"8526","inReplyTo":null,"subject":"[PATCH 1/5] remote.c: refactor match_explicit_refs()","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2007-06-09T09:21:32Z","receivedAt":"2007-06-09T09:21:32Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"This does not change functionality; just splits one block that\nis deeply nested and indented out of a huge loop into a separate\nfunction.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n remote.c |  159 +++++++++++++++++++++++++++++++++----------------------------\n 1 files changed, 86 insertions(+), 73 deletions(-)\n\ndiff --git a/remote.c b/remote.c\nindex 33c8e50..b53130f 100644\n--- a/remote.c\n+++ b/remote.c\n@@ -406,90 +406,98 @@ static struct ref *try_explicit_object_name(const char *name)\n \treturn ref;\n }\n \n-static int match_explicit_refs(struct ref *src, struct ref *dst,\n-\t\t\t       struct ref ***dst_tail, struct refspec *rs,\n-\t\t\t       int rs_nr)\n+static int match_explicit(struct ref *src, struct ref *dst,\n+\t\t\t  struct ref ***dst_tail,\n+\t\t\t  struct refspec *rs,\n+\t\t\t  int errs)\n {\n-\tint i, errs;\n-\tfor (i = errs = 0; i < rs_nr; i++) {\n-\t\tstruct ref *matched_src, *matched_dst;\n+\tstruct ref *matched_src, *matched_dst;\n \n-\t\tconst char *dst_value = rs[i].dst;\n+\tconst char *dst_value = rs->dst;\n \n-\t\tif (rs[i].pattern)\n-\t\t\tcontinue;\n+\tif (rs->pattern)\n+\t\treturn errs;\n \n-\t\tif (dst_value == NULL)\n-\t\t\tdst_value = rs[i].src;\n+\tif (dst_value == NULL)\n+\t\tdst_value = rs->src;\n \n-\t\tmatched_src = matched_dst = NULL;\n-\t\tswitch (count_refspec_match(rs[i].src, src, &matched_src)) {\n-\t\tcase 1:\n-\t\t\tbreak;\n-\t\tcase 0:\n-\t\t\t/* The source could be in the get_sha1() format\n-\t\t\t * not a reference name.  :refs/other is a\n-\t\t\t * way to delete 'other' ref at the remote end.\n-\t\t\t */\n-\t\t\tmatched_src = try_explicit_object_name(rs[i].src);\n-\t\t\tif (matched_src)\n-\t\t\t\tbreak;\n-\t\t\terrs = 1;\n-\t\t\terror(\"src refspec %s does not match any.\",\n-\t\t\t      rs[i].src);\n-\t\t\tbreak;\n-\t\tdefault:\n-\t\t\terrs = 1;\n-\t\t\terror(\"src refspec %s matches more than one.\",\n-\t\t\t      rs[i].src);\n-\t\t\tbreak;\n-\t\t}\n-\t\tswitch (count_refspec_match(dst_value, dst, &matched_dst)) {\n-\t\tcase 1:\n-\t\t\tbreak;\n-\t\tcase 0:\n-\t\t\tif (!memcmp(dst_value, \"refs/\", 5)) {\n-\t\t\t\tint len = strlen(dst_value) + 1;\n-\t\t\t\tmatched_dst = xcalloc(1, sizeof(*dst) + len);\n-\t\t\t\tmemcpy(matched_dst->name, dst_value, len);\n-\t\t\t\tlink_dst_tail(matched_dst, dst_tail);\n-\t\t\t}\n-\t\t\telse if (!strcmp(rs[i].src, dst_value) &&\n-\t\t\t\t matched_src) {\n-\t\t\t\t/* pushing \"master:master\" when\n-\t\t\t\t * remote does not have master yet.\n-\t\t\t\t */\n-\t\t\t\tint len = strlen(matched_src->name) + 1;\n-\t\t\t\tmatched_dst = xcalloc(1, sizeof(*dst) + len);\n-\t\t\t\tmemcpy(matched_dst->name, matched_src->name,\n-\t\t\t\t       len);\n-\t\t\t\tlink_dst_tail(matched_dst, dst_tail);\n-\t\t\t}\n-\t\t\telse {\n-\t\t\t\terrs = 1;\n-\t\t\t\terror(\"dst refspec %s does not match any \"\n-\t\t\t\t      \"existing ref on the remote and does \"\n-\t\t\t\t      \"not start with refs/.\", dst_value);\n-\t\t\t}\n-\t\t\tbreak;\n-\t\tdefault:\n-\t\t\terrs = 1;\n-\t\t\terror(\"dst refspec %s matches more than one.\",\n-\t\t\t      dst_value);\n+\tmatched_src = matched_dst = NULL;\n+\tswitch (count_refspec_match(rs->src, src, &matched_src)) {\n+\tcase 1:\n+\t\tbreak;\n+\tcase 0:\n+\t\t/* The source could be in the get_sha1() format\n+\t\t * not a reference name.  :refs/other is a\n+\t\t * way to delete 'other' ref at the remote end.\n+\t\t */\n+\t\tmatched_src = try_explicit_object_name(rs->src);\n+\t\tif (matched_src)\n \t\t\tbreak;\n+\t\terrs = 1;\n+\t\terror(\"src refspec %s does not match any.\",\n+\t\t      rs->src);\n+\t\tbreak;\n+\tdefault:\n+\t\terrs = 1;\n+\t\terror(\"src refspec %s matches more than one.\",\n+\t\t      rs->src);\n+\t\tbreak;\n+\t}\n+\tswitch (count_refspec_match(dst_value, dst, &matched_dst)) {\n+\tcase 1:\n+\t\tbreak;\n+\tcase 0:\n+\t\tif (!memcmp(dst_value, \"refs/\", 5)) {\n+\t\t\tint len = strlen(dst_value) + 1;\n+\t\t\tmatched_dst = xcalloc(1, sizeof(*dst) + len);\n+\t\t\tmemcpy(matched_dst->name, dst_value, len);\n+\t\t\tlink_dst_tail(matched_dst, dst_tail);\n \t\t}\n-\t\tif (errs)\n-\t\t\tcontinue;\n-\t\tif (matched_dst->peer_ref) {\n-\t\t\terrs = 1;\n-\t\t\terror(\"dst ref %s receives from more than one src.\",\n-\t\t\t      matched_dst->name);\n+\t\telse if (!strcmp(rs->src, dst_value) &&\n+\t\t\t matched_src) {\n+\t\t\t/* pushing \"master:master\" when\n+\t\t\t * remote does not have master yet.\n+\t\t\t */\n+\t\t\tint len = strlen(matched_src->name) + 1;\n+\t\t\tmatched_dst = xcalloc(1, sizeof(*dst) + len);\n+\t\t\tmemcpy(matched_dst->name, matched_src->name,\n+\t\t\t       len);\n+\t\t\tlink_dst_tail(matched_dst, dst_tail);\n \t\t}\n \t\telse {\n-\t\t\tmatched_dst->peer_ref = matched_src;\n-\t\t\tmatched_dst->force = rs[i].force;\n+\t\t\terrs = 1;\n+\t\t\terror(\"dst refspec %s does not match any \"\n+\t\t\t      \"existing ref on the remote and does \"\n+\t\t\t      \"not start with refs/.\", dst_value);\n \t\t}\n+\t\tbreak;\n+\tdefault:\n+\t\terrs = 1;\n+\t\terror(\"dst refspec %s matches more than one.\",\n+\t\t      dst_value);\n+\t\tbreak;\n+\t}\n+\tif (errs)\n+\t\treturn errs;\n+\tif (matched_dst->peer_ref) {\n+\t\terrs = 1;\n+\t\terror(\"dst ref %s receives from more than one src.\",\n+\t\t      matched_dst->name);\n \t}\n+\telse {\n+\t\tmatched_dst->peer_ref = matched_src;\n+\t\tmatched_dst->force = rs->force;\n+\t}\n+\treturn errs;\n+}\n+\n+static int match_explicit_refs(struct ref *src, struct ref *dst,\n+\t\t\t       struct ref ***dst_tail, struct refspec *rs,\n+\t\t\t       int rs_nr)\n+{\n+\tint i, errs;\n+\tfor (i = errs = 0; i < rs_nr; i++)\n+\t\terrs |= match_explicit(src, dst, dst_tail, &rs[i], errs);\n \treturn -errs;\n }\n \n@@ -513,6 +521,11 @@ static const struct refspec *check_pattern_match(const struct refspec *rs,\n \treturn NULL;\n }\n \n+/*\n+ * Note. This is used only by \"push\"; refspec matching rules for\n+ * push and fetch are subtly different, so do not try to reuse it\n+ * without thinking.\n+ */\n int match_refs(struct ref *src, struct ref *dst, struct ref ***dst_tail,\n \t       int nr_refspec, char **refspec, int all)\n {\n-- \n1.5.2.1.144.gabc40\n"},{"id":"44440","messageId":"11813808961403-git-send-email-gitster@pobox.com","threadId":"8526","inReplyTo":"11813808962261-git-send-email-gitster@pobox.com","subject":"[PATCH 2/5] remote.c: refactor creation of new dst ref","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2007-06-09T09:21:33Z","receivedAt":"2007-06-09T09:21:33Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"This refactors open-coded sequence to create a new \"struct ref\"\nand link it to the tail of dst list into a new function.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n remote.c |   35 +++++++++++++++++------------------\n 1 files changed, 17 insertions(+), 18 deletions(-)\n\ndiff --git a/remote.c b/remote.c\nindex b53130f..f469fb3 100644\n--- a/remote.c\n+++ b/remote.c\n@@ -406,6 +406,18 @@ static struct ref *try_explicit_object_name(const char *name)\n \treturn ref;\n }\n \n+static struct ref *make_dst(const char *name, struct ref ***dst_tail)\n+{\n+\tstruct ref *dst;\n+\tsize_t len;\n+\n+\tlen = strlen(name) + 1;\n+\tdst = xcalloc(1, sizeof(*dst) + len);\n+\tmemcpy(dst->name, name, len);\n+\tlink_dst_tail(dst, dst_tail);\n+\treturn dst;\n+}\n+\n static int match_explicit(struct ref *src, struct ref *dst,\n \t\t\t  struct ref ***dst_tail,\n \t\t\t  struct refspec *rs,\n@@ -447,23 +459,13 @@ static int match_explicit(struct ref *src, struct ref *dst,\n \tcase 1:\n \t\tbreak;\n \tcase 0:\n-\t\tif (!memcmp(dst_value, \"refs/\", 5)) {\n-\t\t\tint len = strlen(dst_value) + 1;\n-\t\t\tmatched_dst = xcalloc(1, sizeof(*dst) + len);\n-\t\t\tmemcpy(matched_dst->name, dst_value, len);\n-\t\t\tlink_dst_tail(matched_dst, dst_tail);\n-\t\t}\n-\t\telse if (!strcmp(rs->src, dst_value) &&\n-\t\t\t matched_src) {\n+\t\tif (!memcmp(dst_value, \"refs/\", 5))\n+\t\t\tmatched_dst = make_dst(dst_value, dst_tail);\n+\t\telse if (!strcmp(rs->src, dst_value) && matched_src)\n \t\t\t/* pushing \"master:master\" when\n \t\t\t * remote does not have master yet.\n \t\t\t */\n-\t\t\tint len = strlen(matched_src->name) + 1;\n-\t\t\tmatched_dst = xcalloc(1, sizeof(*dst) + len);\n-\t\t\tmemcpy(matched_dst->name, matched_src->name,\n-\t\t\t       len);\n-\t\t\tlink_dst_tail(matched_dst, dst_tail);\n-\t\t}\n+\t\t\tmatched_dst = make_dst(matched_src->name, dst_tail);\n \t\telse {\n \t\t\terrs = 1;\n \t\t\terror(\"dst refspec %s does not match any \"\n@@ -567,11 +569,8 @@ int match_refs(struct ref *src, struct ref *dst, struct ref ***dst_tail,\n \t\t\tgoto free_name;\n \t\tif (!dst_peer) {\n \t\t\t/* Create a new one and link it */\n-\t\t\tint len = strlen(dst_name) + 1;\n-\t\t\tdst_peer = xcalloc(1, sizeof(*dst_peer) + len);\n-\t\t\tmemcpy(dst_peer->name, dst_name, len);\n+\t\t\tdst_peer = make_dst(dst_name, dst_tail);\n \t\t\thashcpy(dst_peer->new_sha1, src->new_sha1);\n-\t\t\tlink_dst_tail(dst_peer, dst_tail);\n \t\t}\n \t\tdst_peer->peer_ref = src;\n \tfree_name:\n-- \n1.5.2.1.144.gabc40\n"},{"id":"44438","messageId":"11813808961996-git-send-email-gitster@pobox.com","threadId":"8526","inReplyTo":"11813808962261-git-send-email-gitster@pobox.com","subject":"[PATCH 3/5] remote.c: minor clean-up of match_explicit()","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2007-06-09T09:21:34Z","receivedAt":"2007-06-09T09:21:34Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"When checking what ref the source refspec matches, we have no\nbusiness setting the default for the destination, so move that\ncode lower.  Also simplify the result from the code block that\nmatches the source side by making it set matched_src only upon\nunambiguous match.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n remote.c |   23 ++++++++++++-----------\n 1 files changed, 12 insertions(+), 11 deletions(-)\n\ndiff --git a/remote.c b/remote.c\nindex f469fb3..30abdbb 100644\n--- a/remote.c\n+++ b/remote.c\n@@ -430,9 +430,6 @@ static int match_explicit(struct ref *src, struct ref *dst,\n \tif (rs->pattern)\n \t\treturn errs;\n \n-\tif (dst_value == NULL)\n-\t\tdst_value = rs->src;\n-\n \tmatched_src = matched_dst = NULL;\n \tswitch (count_refspec_match(rs->src, src, &matched_src)) {\n \tcase 1:\n@@ -445,16 +442,22 @@ 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\tbreak;\n-\t\terrs = 1;\n \t\terror(\"src refspec %s does not match any.\",\n \t\t      rs->src);\n \t\tbreak;\n \tdefault:\n-\t\terrs = 1;\n+\t\tmatched_src = NULL;\n \t\terror(\"src refspec %s matches more than one.\",\n \t\t      rs->src);\n \t\tbreak;\n \t}\n+\n+\tif (!matched_src)\n+\t\terrs = 1;\n+\n+\tif (dst_value == NULL)\n+\t\tdst_value = rs->src;\n+\n \tswitch (count_refspec_match(dst_value, dst, &matched_dst)) {\n \tcase 1:\n \t\tbreak;\n@@ -466,21 +469,19 @@ static int match_explicit(struct ref *src, struct ref *dst,\n \t\t\t * remote does not have master yet.\n \t\t\t */\n \t\t\tmatched_dst = make_dst(matched_src->name, dst_tail);\n-\t\telse {\n-\t\t\terrs = 1;\n+\t\telse\n \t\t\terror(\"dst refspec %s does not match any \"\n \t\t\t      \"existing ref on the remote and does \"\n \t\t\t      \"not start with refs/.\", dst_value);\n-\t\t}\n \t\tbreak;\n \tdefault:\n-\t\terrs = 1;\n+\t\tmatched_dst = NULL;\n \t\terror(\"dst refspec %s matches more than one.\",\n \t\t      dst_value);\n \t\tbreak;\n \t}\n-\tif (errs)\n-\t\treturn errs;\n+\tif (errs || matched_dst == NULL)\n+\t\treturn 1;\n \tif (matched_dst->peer_ref) {\n \t\terrs = 1;\n \t\terror(\"dst ref %s receives from more than one src.\",\n-- \n1.5.2.1.144.gabc40\n"},{"id":"44439","messageId":"11813808973622-git-send-email-gitster@pobox.com","threadId":"8526","inReplyTo":"11813808962261-git-send-email-gitster@pobox.com","subject":"[PATCH 4/5] remote.c: fix \"git push\" weak match disambiguation","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2007-06-09T09:21:35Z","receivedAt":"2007-06-09T09:21:35Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"When \"git push A:B\" is given, and A (or B) is not a full refname\nthat begins with refs/, we require an unambiguous match with an\nexisting ref.  For this purpose, a match with a local branch or\na tag (i.e. refs/heads/A and refs/tags/A) is called a \"strong\nmatch\", and any other match is called a \"weak match\".  A partial\nrefname is unambiguous when there is only one strong match with\nany number of weak matches, or when there is only one weak match\nand no other match.\n\nHowever, as reported by Sparse with Ramsay Jones recently,\ncount_refspec_match() function had a bug where a variable in an\ninner block masked a different variable of the same name, which\ncaused the weak matches to be ignored.\n\nThis fixes it, and adds tests for the fix.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n remote.c              |    1 -\n t/t5516-fetch-push.sh |  112 +++++++++++++++++++++++++++++++++++++++++++++++++\n 2 files changed, 112 insertions(+), 1 deletions(-)\n\ndiff --git a/remote.c b/remote.c\nindex 30abdbb..120df36 100644\n--- a/remote.c\n+++ b/remote.c\n@@ -333,7 +333,6 @@ static int count_refspec_match(const char *pattern,\n \tfor (weak_match = match = 0; refs; refs = refs->next) {\n \t\tchar *name = refs->name;\n \t\tint namelen = strlen(name);\n-\t\tint weak_match;\n \n \t\tif (namelen < patlen ||\n \t\t    memcmp(name + namelen - patlen, pattern, patlen))\ndiff --git a/t/t5516-fetch-push.sh b/t/t5516-fetch-push.sh\nindex dba018f..b3b57fa 100755\n--- a/t/t5516-fetch-push.sh\n+++ b/t/t5516-fetch-push.sh\n@@ -15,12 +15,58 @@ mk_empty () {\n \t)\n }\n \n+mk_test () {\n+\tmk_empty &&\n+\t(\n+\t\tfor ref in \"$@\"\n+\t\tdo\n+\t\t\tgit push testrepo $the_first_commit:refs/$ref || {\n+\t\t\t\techo \"Oops, push refs/$ref failure\"\n+\t\t\t\texit 1\n+\t\t\t}\n+\t\tdone &&\n+\t\tcd testrepo &&\n+\t\tfor ref in \"$@\"\n+\t\tdo\n+\t\t\tr=$(git show-ref -s --verify refs/$ref) &&\n+\t\t\ttest \"z$r\" = \"z$the_first_commit\" || {\n+\t\t\t\techo \"Oops, refs/$ref is wrong\"\n+\t\t\t\texit 1\n+\t\t\t}\n+\t\tdone &&\n+\t\tgit fsck --full\n+\t)\n+}\n+\n+check_push_result () {\n+\t(\n+\t\tcd testrepo &&\n+\t\tit=\"$1\" &&\n+\t\tshift\n+\t\tfor ref in \"$@\"\n+\t\tdo\n+\t\t\tr=$(git show-ref -s --verify refs/$ref) &&\n+\t\t\ttest \"z$r\" = \"z$it\" || {\n+\t\t\t\techo \"Oops, refs/$ref is wrong\"\n+\t\t\t\texit 1\n+\t\t\t}\n+\t\tdone &&\n+\t\tgit fsck --full\n+\t)\n+}\n+\n test_expect_success setup '\n \n \t: >path1 &&\n \tgit add path1 &&\n \ttest_tick &&\n \tgit commit -a -m repo &&\n+\tthe_first_commit=$(git show-ref -s --verify refs/heads/master) &&\n+\n+\t: >path2 &&\n+\tgit add path2 &&\n+\ttest_tick &&\n+\tgit commit -a -m second &&\n \tthe_commit=$(git show-ref -s --verify refs/heads/master)\n \n '\n@@ -79,4 +125,70 @@ test_expect_success 'push with wildcard' '\n \t)\n '\n \n+test_expect_success 'push with matching heads' '\n+\n+\tmk_test heads/master &&\n+\tgit push testrepo &&\n+\tcheck_push_result $the_commit heads/master\n+\n+'\n+\n+test_expect_success 'push with no ambiguity (1)' '\n+\n+\tmk_test heads/master &&\n+\tgit push testrepo master:master &&\n+\tcheck_push_result $the_commit heads/master\n+\n+'\n+\n+test_expect_success 'push with no ambiguity (2)' '\n+\n+\tmk_test remotes/origin/master &&\n+\tgit push testrepo master:master &&\n+\tcheck_push_result $the_commit remotes/origin/master\n+\n+'\n+\n+test_expect_success 'push with weak ambiguity (1)' '\n+\n+\tmk_test heads/master remotes/origin/master &&\n+\tgit push testrepo master:master &&\n+\tcheck_push_result $the_commit heads/master &&\n+\tcheck_push_result $the_first_commit remotes/origin/master\n+\n+'\n+\n+test_expect_success 'push with weak ambiguity (2)' '\n+\n+\tmk_test heads/master remotes/origin/master remotes/another/master &&\n+\tgit push testrepo master:master &&\n+\tcheck_push_result $the_commit heads/master &&\n+\tcheck_push_result $the_first_commit remotes/origin/master remotes/another/master\n+\n+'\n+\n+test_expect_success 'push with ambiguity (1)' '\n+\n+\tmk_test remotes/origin/master remotes/frotz/master &&\n+\tif git push testrepo master:master\n+\tthen\n+\t\techo \"Oops, should have failed\"\n+\t\tfalse\n+\telse\n+\t\tcheck_push_result $the_first_commit remotes/origin/master remotes/frotz/master\n+\tfi\n+'\n+\n+test_expect_success 'push with ambiguity (2)' '\n+\n+\tmk_test heads/frotz tags/frotz &&\n+\tif git push testrepo master:frotz\n+\tthen\n+\t\techo \"Oops, should have failed\"\n+\t\tfalse\n+\telse\n+\t\tcheck_push_result $the_first_commit heads/frotz tags/frotz\n+\tfi\n+'\n+\n test_done\n-- \n1.5.2.1.144.gabc40\n"},{"id":"44437","messageId":"11813808973041-git-send-email-gitster@pobox.com","threadId":"8526","inReplyTo":"11813808962261-git-send-email-gitster@pobox.com","subject":"[PATCH 5/5] remote.c: \"git-push frotz\" should update what matches at the source.","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2007-06-09T09:21:36Z","receivedAt":"2007-06-09T09:21:36Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Earlier, when the local repository has a branch \"frotz\" and the\nremote repository has a tag \"frotz\" (but not branch \"frotz\"),\n\"git-push frotz\" mistakenly updated the tag at the remote side.\nThis was because the partial refname matching code was applied\nindependently on both source and destination side.\n\nWith this fix, when a colon-less refspec is given to git-push,\nwe first match it with the refs in the source repository, and\nupdate the matching ref in the destination repository.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n remote.c              |    7 +-----\n t/t5516-fetch-push.sh |   52 +++++++++++++++++++++++++++++++++++++++++++++++++\n 2 files changed, 53 insertions(+), 6 deletions(-)\n\ndiff --git a/remote.c b/remote.c\nindex 120df36..754d513 100644\n--- a/remote.c\n+++ b/remote.c\n@@ -455,7 +455,7 @@ static int match_explicit(struct ref *src, struct ref *dst,\n \t\terrs = 1;\n \n \tif (dst_value == NULL)\n-\t\tdst_value = rs->src;\n+\t\tdst_value = matched_src->name;\n \n \tswitch (count_refspec_match(dst_value, dst, &matched_dst)) {\n \tcase 1:\n@@ -463,11 +463,6 @@ static int match_explicit(struct ref *src, struct ref *dst,\n \tcase 0:\n \t\tif (!memcmp(dst_value, \"refs/\", 5))\n \t\t\tmatched_dst = make_dst(dst_value, dst_tail);\n-\t\telse if (!strcmp(rs->src, dst_value) && matched_src)\n-\t\t\t/* pushing \"master:master\" when\n-\t\t\t * remote does not have master yet.\n-\t\t\t */\n-\t\t\tmatched_dst = make_dst(matched_src->name, dst_tail);\n \t\telse\n \t\t\terror(\"dst refspec %s does not match any \"\n \t\t\t      \"existing ref on the remote and does \"\ndiff --git a/t/t5516-fetch-push.sh b/t/t5516-fetch-push.sh\nindex b3b57fa..08d58e1 100755\n--- a/t/t5516-fetch-push.sh\n+++ b/t/t5516-fetch-push.sh\n@@ -189,6 +189,58 @@ test_expect_success 'push with ambiguity (2)' '\n \telse\n \t\tcheck_push_result $the_first_commit heads/frotz tags/frotz\n \tfi\n+\n+'\n+\n+test_expect_success 'push with colon-less refspec (1)' '\n+\n+\tmk_test heads/frotz tags/frotz &&\n+\tgit branch -f frotz master &&\n+\tgit push testrepo frotz &&\n+\tcheck_push_result $the_commit heads/frotz &&\n+\tcheck_push_result $the_first_commit tags/frotz\n+\n+'\n+\n+test_expect_success 'push with colon-less refspec (2)' '\n+\n+\tmk_test heads/frotz tags/frotz &&\n+\tif git show-ref --verify -q refs/heads/frotz\n+\tthen\n+\t\tgit branch -D frotz\n+\tfi &&\n+\tgit tag -f frotz &&\n+\tgit push testrepo frotz &&\n+\tcheck_push_result $the_commit tags/frotz &&\n+\tcheck_push_result $the_first_commit heads/frotz\n+\n+'\n+\n+test_expect_success 'push with colon-less refspec (3)' '\n+\n+\tmk_test &&\n+\tif git show-ref --verify -q refs/tags/frotz\n+\tthen\n+\t\tgit tag -d frotz\n+\tfi &&\n+\tgit branch -f frotz master &&\n+\tgit push testrepo frotz &&\n+\tcheck_push_result $the_commit heads/frotz &&\n+\ttest \"$( cd testrepo && git show-ref | wc -l )\" = 1\n+'\n+\n+test_expect_success 'push with colon-less refspec (4)' '\n+\n+\tmk_test &&\n+\tif git show-ref --verify -q refs/heads/frotz\n+\tthen\n+\t\tgit branch -D frotz\n+\tfi &&\n+\tgit tag -f frotz &&\n+\tgit push testrepo frotz &&\n+\tcheck_push_result $the_commit tags/frotz &&\n+\ttest \"$( cd testrepo && git show-ref | wc -l )\" = 1\n+\n '\n \n test_done\n-- \n1.5.2.1.144.gabc40\n"},{"id":"44529","messageId":"7vk5ucb8hm.fsf_-_@assigned-by-dhcp.cox.net","threadId":"8526","inReplyTo":"11813808973041-git-send-email-gitster@pobox.com","subject":"[PATCH 6/5] git-push: Update description of refspecs and add examples","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2007-06-10T06:59:17Z","receivedAt":"2007-06-10T06:59:17Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n\n * This is primarily to describe the semantics [Patch 5/5] fixes.\n\n Documentation/git-push.txt |   25 ++++++++++++++++++++++---\n 1 files changed, 22 insertions(+), 3 deletions(-)\n\ndiff --git a/Documentation/git-push.txt b/Documentation/git-push.txt\nindex 366c5db..665f6dc 100644\n--- a/Documentation/git-push.txt\n+++ b/Documentation/git-push.txt\n@@ -53,9 +53,8 @@ side are updated.\n +\n `tag <tag>` means the same as `refs/tags/<tag>:refs/tags/<tag>`.\n +\n-A parameter <ref> without a colon is equivalent to\n-<ref>`:`<ref>, hence updates <ref> in the destination from <ref>\n-in the source.\n+A parameter <ref> without a colon pushes the <ref> from the source\n+repository to the destination repository under the same name.\n +\n Pushing an empty <src> allows you to delete the <dst> ref from\n the remote repository.\n@@ -98,6 +97,26 @@ the remote repository.\n \n include::urls.txt[]\n \n+\n+Examples\n+--------\n+\n+git push origin master::\n+\tFind a ref that matches `master` in the source repository\n+\t(most likely, it would find `refs/heads/master`), and update\n+\tthe same ref (e.g. `refs/heads/master`) in `origin` repository\n+\twith it.\n+\n+git push origin :experimental::\n+\tFind a ref that matches `experimental` in the `origin` repository\n+\t(e.g. `refs/heads/experimental`), and delete it.\n+\n+git push origin master:satellite/master::\n+\tFind a ref that matches `master` in the source repository\n+\t(most likely, it would find `refs/heads/master`), and update\n+\tthe ref that matches `satellite/master` (most likely, it would\n+\tbe `refs/remotes/satellite/master`) in `origin` repository with it.\n+\n Author\n ------\n Written by Junio C Hamano <junkio@cox.net>, later rewritten in C\n-- \n1.5.2.1.938.gac3b4\n"}]}