{"thread":{"id":"10271","subject":"[PATCH 1/6] push, send-pack: fix test if remote branch exists for colon-less refspec","startedAt":"2007-10-14T08:54:39Z","lastAt":"2007-10-14T21:37:21Z","messageCount":12,"participants":["Steffen Prohaska","Johannes Schindelin"],"isPatch":true,"patchVersion":1,"patchTotal":6},"messages":[{"id":"55679","messageId":"11923520851713-git-send-email-prohaska@zib.de","threadId":"10271","inReplyTo":null,"subject":"change push's refspec behavior to match rev-parse","fromName":"Steffen Prohaska","fromEmail":"prohaska@zib.de","sentAt":"2007-10-14T08:54:39Z","receivedAt":"2007-10-14T08:54:39Z","isPatch":false,"sender":{"key":"prohaska@zib.de","avatar":"https://avatars.githubusercontent.com/u/217580?v=4"},"body":"This patch series addresses recent complaints about the behavior of push/send-pack\nwhen expanding short refspecs. The overall idea is to change push's handling of\nrefspecs to match the behavior of rev-parse.\n\n\nThe old way of matching short refspecs in push is often unexpected as\ndiscussed in [1]. Now \"git push <ref>\" resolves ref the same way as rev-parse.\n\n[1] http://marc.info/?l=git&m=119224567631084&w=2\n\n\nA related question is how to push only the current branch [2]. Now\n\"git push HEAD\" is supported to push the current head if a matching remote\nref exists.\n\n[2] http://marc.info/?l=git&m=119089831513994&w=2\n\nA summary of the patch series follows below.\n\n    Steffen\n\n builtin-rev-parse.c   |   27 ++++++++++++-------\n cache.h               |    2 +\n remote.c              |   23 ++++++++++------\n sha1_name.c           |   51 ++++++++++++++++++++++++++++--------\n t/t5516-fetch-push.sh |   68 ++++++++++++++++++++++++++++++++++++++++++++++--\n 5 files changed, 138 insertions(+), 33 deletions(-)\n\n [PATCH 1/6] push, send-pack: fix test if remote branch exists for colon-less refspec\n\n\tThis is a bug fix that should go to maint. All following patches modifying\n        the push test script require this.\n\n [PATCH 2/6] add get_sha1_with_real_ref() returning full name of ref on demand\n\n\tIs required by 3/6 and 4/6\n\n [PATCH 3/6] rev-parse: teach \"git rev-parse --symbolic\" to print the full ref name\n\n\tA bit off-topic. It demonstrates the use of get_sha1_with_real_ref.\n\n [PATCH 4/6] push, send-pack: support pushing HEAD to real ref name\n\n\tRequires 1/6.\n\n [PATCH 5/6] add ref_cmp_full_short() comparing full ref name with a short name\n [PATCH 6/6] push, send-pack: use same rules as git-rev-parse to resolve refspecs\n\n\tRequires 1/6.\n\n\tNote, an updated documentation is not yet included. I like to first wait for\n\tcomments.\n"},{"id":"55676","messageId":"1192352085653-git-send-email-prohaska@zib.de","threadId":"10271","inReplyTo":"11923520851713-git-send-email-prohaska@zib.de","subject":"[PATCH 1/6] push, send-pack: fix test if remote branch exists for colon-less refspec","fromName":"Steffen Prohaska","fromEmail":"prohaska@zib.de","sentAt":"2007-10-14T08:54:40Z","receivedAt":"2007-10-14T08:54:40Z","isPatch":true,"sender":{"key":"prohaska@zib.de","avatar":"https://avatars.githubusercontent.com/u/217580?v=4"},"body":"A push must fail if the remote ref does not yet exist and the refspec\ndoes not start with refs/. Remote refs must explicitly be created with\ntheir full name.\n\nThis commit adds some tests and fixes the existence check in send-pack.\n\nSigned-off-by: Steffen Prohaska <prohaska@zib.de>\n---\n remote.c              |    4 ++--\n t/t5516-fetch-push.sh |   34 ++++++++++++++++++++++++++++++++--\n 2 files changed, 34 insertions(+), 4 deletions(-)\n\ndiff --git a/remote.c b/remote.c\nindex bb774d0..36071b2 100644\n--- a/remote.c\n+++ b/remote.c\n@@ -511,12 +511,12 @@ 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\tif (!memcmp(rs->dst ? rs->dst : rs->src , \"refs/\", 5))\n \t\t\tmatched_dst = make_linked_ref(dst_value, 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 \"\n-\t\t\t      \"not start with refs/.\", dst_value);\n+\t\t\t      \"not start with refs/.\", rs->dst ? rs->dst : rs->src);\n \t\tbreak;\n \tdefault:\n \t\tmatched_dst = NULL;\ndiff --git a/t/t5516-fetch-push.sh b/t/t5516-fetch-push.sh\nindex ca46aaf..8629cf2 100755\n--- a/t/t5516-fetch-push.sh\n+++ b/t/t5516-fetch-push.sh\n@@ -126,6 +126,36 @@ test_expect_success 'push with wildcard' '\n \t)\n '\n \n+test_expect_success 'push nonexisting (1)' '\n+\n+\tmk_test &&\n+\tif git push testrepo master\n+\tthen\n+\t\techo \"Oops, should have failed\"\n+\t\tfalse\n+\tfi\n+\n+'\n+\n+test_expect_success 'push nonexisting (2)' '\n+\n+\tmk_test &&\n+\tif git push testrepo heads/master\n+\tthen\n+\t\techo \"Oops, should have failed\"\n+\t\tfalse\n+\tfi\n+\n+'\n+\n+test_expect_success 'push nonexisting (3)' '\n+\n+\tmk_test &&\n+\tgit push testrepo refs/heads/master &&\n+\tcheck_push_result $the_commit heads/master\n+\n+'\n+\n test_expect_success 'push with matching heads' '\n \n \tmk_test heads/master &&\n@@ -225,7 +255,7 @@ test_expect_success 'push with colon-less refspec (3)' '\n \t\tgit tag -d frotz\n \tfi &&\n \tgit branch -f frotz master &&\n-\tgit push testrepo frotz &&\n+\tgit push testrepo refs/heads/frotz &&\n \tcheck_push_result $the_commit heads/frotz &&\n \ttest 1 = $( cd testrepo && git show-ref | wc -l )\n '\n@@ -238,7 +268,7 @@ test_expect_success 'push with colon-less refspec (4)' '\n \t\tgit branch -D frotz\n \tfi &&\n \tgit tag -f frotz &&\n-\tgit push testrepo frotz &&\n+\tgit push testrepo refs/tags/frotz &&\n \tcheck_push_result $the_commit tags/frotz &&\n \ttest 1 = $( cd testrepo && git show-ref | wc -l )\n \n-- \n1.5.3.4.224.gc6b84\n"},{"id":"55678","messageId":"11923520852991-git-send-email-prohaska@zib.de","threadId":"10271","inReplyTo":"1192352085653-git-send-email-prohaska@zib.de","subject":"[PATCH 2/6] add get_sha1_with_real_ref() returning full name of ref on demand","fromName":"Steffen Prohaska","fromEmail":"prohaska@zib.de","sentAt":"2007-10-14T08:54:41Z","receivedAt":"2007-10-14T08:54:41Z","isPatch":true,"sender":{"key":"prohaska@zib.de","avatar":"https://avatars.githubusercontent.com/u/217580?v=4"},"body":"Deep inside get_sha1() the name of the requested ref is matched\naccording to the rules documented in git-rev-parse. This patch\nintroduces a function that returns the full name of the matched\nref to the outside.\n\nFor example 'master' is typically returned as 'refs/heads/master'.\n\nThe new function can be used by \"git rev-parse\" to print the full\nname of the matched ref and can be used by \"git send-pack\" to expand\na local ref to its full name.\n\nSigned-off-by: Steffen Prohaska <prohaska@zib.de>\n---\n cache.h     |    1 +\n sha1_name.c |   38 +++++++++++++++++++++++++++-----------\n 2 files changed, 28 insertions(+), 11 deletions(-)\n\ndiff --git a/cache.h b/cache.h\nindex e0abcd6..f98d57a 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -401,6 +401,7 @@ static inline unsigned int hexval(unsigned char c)\n \n extern int get_sha1(const char *str, unsigned char *sha1);\n extern int get_sha1_with_mode(const char *str, unsigned char *sha1, unsigned *mode);\n+extern int get_sha1_with_real_ref(const char *str, unsigned char *sha1, char **real_ref);\n extern int get_sha1_hex(const char *hex, unsigned char *sha1);\n extern char *sha1_to_hex(const unsigned char *sha1);\t/* static buffer result! */\n extern int read_ref(const char *filename, unsigned char *sha1);\ndiff --git a/sha1_name.c b/sha1_name.c\nindex 2d727d5..b820909 100644\n--- a/sha1_name.c\n+++ b/sha1_name.c\n@@ -306,7 +306,7 @@ int dwim_log(const char *str, int len, unsigned char *sha1, char **log)\n \treturn logs_found;\n }\n \n-static int get_sha1_basic(const char *str, int len, unsigned char *sha1)\n+static int get_sha1_basic(const char *str, int len, unsigned char *sha1, char **real_ref_out)\n {\n \tstatic const char *warning = \"warning: refname '%.*s' is ambiguous.\\n\";\n \tchar *real_ref = NULL;\n@@ -378,17 +378,21 @@ static int get_sha1_basic(const char *str, int len, unsigned char *sha1)\n \t\t}\n \t}\n \n-\tfree(real_ref);\n+\tif (real_ref_out) {\n+\t\t*real_ref_out = real_ref;\n+\t} else {\n+\t\tfree(real_ref);\n+\t}\n \treturn 0;\n }\n \n-static int get_sha1_1(const char *name, int len, unsigned char *sha1);\n+static int get_sha1_1(const char *name, int len, unsigned char *sha1, char **real_ref);\n \n static int get_parent(const char *name, int len,\n \t\t      unsigned char *result, int idx)\n {\n \tunsigned char sha1[20];\n-\tint ret = get_sha1_1(name, len, sha1);\n+\tint ret = get_sha1_1(name, len, sha1, /*real_ref=*/ 0);\n \tstruct commit *commit;\n \tstruct commit_list *p;\n \n@@ -418,7 +422,7 @@ static int get_nth_ancestor(const char *name, int len,\n \t\t\t    unsigned char *result, int generation)\n {\n \tunsigned char sha1[20];\n-\tint ret = get_sha1_1(name, len, sha1);\n+\tint ret = get_sha1_1(name, len, sha1, /*real_ref=*/ 0);\n \tif (ret)\n \t\treturn ret;\n \n@@ -471,7 +475,7 @@ static int peel_onion(const char *name, int len, unsigned char *sha1)\n \telse\n \t\treturn -1;\n \n-\tif (get_sha1_1(name, sp - name - 2, outer))\n+\tif (get_sha1_1(name, sp - name - 2, outer, /*real_ref=*/ 0))\n \t\treturn -1;\n \n \to = parse_object(outer);\n@@ -531,7 +535,7 @@ static int get_describe_name(const char *name, int len, unsigned char *sha1)\n \treturn -1;\n }\n \n-static int get_sha1_1(const char *name, int len, unsigned char *sha1)\n+static int get_sha1_1(const char *name, int len, unsigned char *sha1, char **real_ref)\n {\n \tint ret, has_suffix;\n \tconst char *cp;\n@@ -569,7 +573,7 @@ static int get_sha1_1(const char *name, int len, unsigned char *sha1)\n \tif (!ret)\n \t\treturn 0;\n \n-\tret = get_sha1_basic(name, len, sha1);\n+\tret = get_sha1_basic(name, len, sha1, real_ref);\n \tif (!ret)\n \t\treturn 0;\n \n@@ -651,14 +655,14 @@ int get_sha1(const char *name, unsigned char *sha1)\n \treturn get_sha1_with_mode(name, sha1, &unused);\n }\n \n-int get_sha1_with_mode(const char *name, unsigned char *sha1, unsigned *mode)\n+int get_sha1_with_mode_real_ref(const char *name, unsigned char *sha1, unsigned *mode, char** real_ref)\n {\n \tint ret, bracket_depth;\n \tint namelen = strlen(name);\n \tconst char *cp;\n \n \t*mode = S_IFINVALID;\n-\tret = get_sha1_1(name, namelen, sha1);\n+\tret = get_sha1_1(name, namelen, sha1, real_ref);\n \tif (!ret)\n \t\treturn ret;\n \t/* sha1:path --> object name of path in ent sha1\n@@ -709,9 +713,21 @@ int get_sha1_with_mode(const char *name, unsigned char *sha1, unsigned *mode)\n \t}\n \tif (*cp == ':') {\n \t\tunsigned char tree_sha1[20];\n-\t\tif (!get_sha1_1(name, cp-name, tree_sha1))\n+\t\tif (!get_sha1_1(name, cp-name, tree_sha1, real_ref))\n \t\t\treturn get_tree_entry(tree_sha1, cp+1, sha1,\n \t\t\t\t\t      mode);\n \t}\n \treturn ret;\n }\n+\n+int get_sha1_with_mode(const char *name, unsigned char *sha1, unsigned *mode)\n+{\n+\treturn get_sha1_with_mode_real_ref(name, sha1, mode, 0);\n+}\n+\n+int get_sha1_with_real_ref(const char *name, unsigned char *sha1, char **real_ref)\n+{\n+\tunsigned unused;\n+\treturn get_sha1_with_mode_real_ref(name, sha1, &unused, real_ref);\n+}\n+\n-- \n1.5.3.4.224.gc6b84\n"},{"id":"55677","messageId":"11923520853189-git-send-email-prohaska@zib.de","threadId":"10271","inReplyTo":"11923520852991-git-send-email-prohaska@zib.de","subject":"[PATCH 3/6] rev-parse: teach \"git rev-parse --symbolic\" to print the full ref name","fromName":"Steffen Prohaska","fromEmail":"prohaska@zib.de","sentAt":"2007-10-14T08:54:42Z","receivedAt":"2007-10-14T08:54:42Z","isPatch":true,"sender":{"key":"prohaska@zib.de","avatar":"https://avatars.githubusercontent.com/u/217580?v=4"},"body":"\"git rev-parse --symbolic\" used to return the ref name as it was\nspecified on the command line. This is changed to returning the\nfull matched ref name, i.e. \"git rev-parse --symbolic master\"\nnow typically returns \"refs/heads/master\".\n\nNote, this changes output of an established command. It might\nbreak existing setups. I checked that it does not break scripts\nin git.git.\n\nSigned-off-by: Steffen Prohaska <prohaska@zib.de>\n---\n builtin-rev-parse.c |   27 +++++++++++++++++----------\n 1 files changed, 17 insertions(+), 10 deletions(-)\n\ndiff --git a/builtin-rev-parse.c b/builtin-rev-parse.c\nindex 8d78b69..e64abeb 100644\n--- a/builtin-rev-parse.c\n+++ b/builtin-rev-parse.c\n@@ -93,7 +93,7 @@ static void show(const char *arg)\n }\n \n /* Output a revision, only if filter allows it */\n-static void show_rev(int type, const unsigned char *sha1, const char *name)\n+static void show_rev(int type, const unsigned char *sha1, const char *name, const char* real_name)\n {\n \tif (!(filter & DO_REVS))\n \t\treturn;\n@@ -102,7 +102,9 @@ static void show_rev(int type, const unsigned char *sha1, const char *name)\n \n \tif (type != show_type)\n \t\tputchar('^');\n-\tif (symbolic && name)\n+\tif (symbolic && real_name)\n+\t\tshow(real_name);\n+\telse if (symbolic && name)\n \t\tshow(name);\n \telse if (abbrev)\n \t\tshow(find_unique_abbrev(sha1, abbrev));\n@@ -131,7 +133,7 @@ static void show_default(void)\n \n \t\tdef = NULL;\n \t\tif (!get_sha1(s, sha1)) {\n-\t\t\tshow_rev(NORMAL, sha1, s);\n+\t\t\tshow_rev(NORMAL, sha1, s, 0);\n \t\t\treturn;\n \t\t}\n \t}\n@@ -139,7 +141,7 @@ static void show_default(void)\n \n static int show_reference(const char *refname, const unsigned char *sha1, int flag, void *cb_data)\n {\n-\tshow_rev(NORMAL, sha1, refname);\n+\tshow_rev(NORMAL, sha1, refname, 0);\n \treturn 0;\n }\n \n@@ -187,8 +189,8 @@ static int try_difference(const char *arg)\n \tif (dotdot == arg)\n \t\tthis = \"HEAD\";\n \tif (!get_sha1(this, sha1) && !get_sha1(next, end)) {\n-\t\tshow_rev(NORMAL, end, next);\n-\t\tshow_rev(symmetric ? NORMAL : REVERSED, sha1, this);\n+\t\tshow_rev(NORMAL, end, next, 0);\n+\t\tshow_rev(symmetric ? NORMAL : REVERSED, sha1, this, 0);\n \t\tif (symmetric) {\n \t\t\tstruct commit_list *exclude;\n \t\t\tstruct commit *a, *b;\n@@ -198,7 +200,7 @@ static int try_difference(const char *arg)\n \t\t\twhile (exclude) {\n \t\t\t\tstruct commit_list *n = exclude->next;\n \t\t\t\tshow_rev(REVERSED,\n-\t\t\t\t\t exclude->item->object.sha1,NULL);\n+\t\t\t\t\t exclude->item->object.sha1, NULL, 0);\n \t\t\t\tfree(exclude);\n \t\t\t\texclude = n;\n \t\t\t}\n@@ -213,6 +215,7 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)\n {\n \tint i, as_is = 0, verify = 0;\n \tunsigned char sha1[20];\n+\tchar* real_name = 0;\n \n \tgit_config(git_default_config);\n \n@@ -393,12 +396,16 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)\n \t\t/* Not a flag argument */\n \t\tif (try_difference(arg))\n \t\t\tcontinue;\n-\t\tif (!get_sha1(arg, sha1)) {\n-\t\t\tshow_rev(NORMAL, sha1, arg);\n+\t\tif (!get_sha1_with_real_ref(arg, sha1, &real_name)) {\n+\t\t\tshow_rev(NORMAL, sha1, arg, real_name);\n+\t\t\tif(real_name) {\n+\t\t\t\tfree(real_name);\n+\t\t\t\treal_name = 0;\n+\t\t\t}\n \t\t\tcontinue;\n \t\t}\n \t\tif (*arg == '^' && !get_sha1(arg+1, sha1)) {\n-\t\t\tshow_rev(REVERSED, sha1, arg+1);\n+\t\t\tshow_rev(REVERSED, sha1, arg+1, 0);\n \t\t\tcontinue;\n \t\t}\n \t\tas_is = 1;\n-- \n1.5.3.4.224.gc6b84\n"},{"id":"55680","messageId":"11923520851656-git-send-email-prohaska@zib.de","threadId":"10271","inReplyTo":"11923520853189-git-send-email-prohaska@zib.de","subject":"[PATCH 4/6] push, send-pack: support pushing HEAD to real ref name","fromName":"Steffen Prohaska","fromEmail":"prohaska@zib.de","sentAt":"2007-10-14T08:54:43Z","receivedAt":"2007-10-14T08:54:43Z","isPatch":true,"sender":{"key":"prohaska@zib.de","avatar":"https://avatars.githubusercontent.com/u/217580?v=4"},"body":"This teaches \"push <remote> HEAD\" to resolve HEAD on the local\nside to its real ref name, e.g. refs/heads/master, and then\nuse the real ref name on the remote side to search a matching\nremote ref.\n\nSigned-off-by: Steffen Prohaska <prohaska@zib.de>\n---\n remote.c              |   18 +++++++++++++-----\n t/t5516-fetch-push.sh |   22 ++++++++++++++++++++++\n 2 files changed, 35 insertions(+), 5 deletions(-)\n\ndiff --git a/remote.c b/remote.c\nindex 36071b2..58bc019 100644\n--- a/remote.c\n+++ b/remote.c\n@@ -439,6 +439,8 @@ static struct ref *try_explicit_object_name(const char *name)\n \tunsigned char sha1[20];\n \tstruct ref *ref;\n \tint len;\n+\tchar *real_name = 0;\n+\tconst char *best_name;\n \n \tif (!*name) {\n \t\tref = alloc_ref(20);\n@@ -446,12 +448,17 @@ static struct ref *try_explicit_object_name(const char *name)\n \t\thashclr(ref->new_sha1);\n \t\treturn ref;\n \t}\n-\tif (get_sha1(name, sha1))\n+\tif (get_sha1_with_real_ref(name, sha1, &real_name))\n \t\treturn NULL;\n-\tlen = strlen(name) + 1;\n+\tbest_name = real_name ? real_name : name;\n+\tlen = strlen(best_name) + 1;\n \tref = alloc_ref(len);\n-\tmemcpy(ref->name, name, len);\n+\tmemcpy(ref->name, best_name, len);\n \thashcpy(ref->new_sha1, sha1);\n+\n+\tif (real_name) {\n+\t\tfree(real_name);\n+\t}\n \treturn ref;\n }\n \n@@ -475,6 +482,7 @@ static int match_explicit(struct ref *src, struct ref *dst,\n \tstruct ref *matched_src, *matched_dst;\n \n \tconst char *dst_value = rs->dst;\n+\tconst char * const orig_dst_value = rs->dst ? rs->dst : rs->src;\n \n \tif (rs->pattern)\n \t\treturn errs;\n@@ -511,12 +519,12 @@ static int match_explicit(struct ref *src, struct ref *dst,\n \tcase 1:\n \t\tbreak;\n \tcase 0:\n-\t\tif (!memcmp(rs->dst ? rs->dst : rs->src , \"refs/\", 5))\n+\t\tif (!memcmp(orig_dst_value , \"refs/\", 5))\n \t\t\tmatched_dst = make_linked_ref(dst_value, 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 \"\n-\t\t\t      \"not start with refs/.\", rs->dst ? rs->dst : rs->src);\n+\t\t\t      \"not start with refs/.\", orig_dst_value);\n \t\tbreak;\n \tdefault:\n \t\tmatched_dst = NULL;\ndiff --git a/t/t5516-fetch-push.sh b/t/t5516-fetch-push.sh\nindex 8629cf2..97a032e 100755\n--- a/t/t5516-fetch-push.sh\n+++ b/t/t5516-fetch-push.sh\n@@ -274,4 +274,26 @@ test_expect_success 'push with colon-less refspec (4)' '\n \n '\n \n+test_expect_success 'push with HEAD' '\n+\n+\tmk_test heads/master &&\n+\tgit push testrepo HEAD &&\n+\tcheck_push_result $the_commit heads/master\n+\n+'\n+\n+test_expect_success 'push with HEAD not existing at remote' '\n+\n+\tmk_test heads/master &&\n+\tgit checkout -b local master &&\n+\tif git push testrepo HEAD\n+\tthen\n+\t\techo \"Oops, should have failed\"\n+\t\tfalse\n+\telse\n+\t\tcheck_push_result $the_first_commit heads/master\n+\tfi\n+\n+'\n+\n test_done\n-- \n1.5.3.4.224.gc6b84\n"},{"id":"55681","messageId":"11923520853014-git-send-email-prohaska@zib.de","threadId":"10271","inReplyTo":"11923520851656-git-send-email-prohaska@zib.de","subject":"[PATCH 5/6] add ref_cmp_full_short() comparing full ref name with a short name","fromName":"Steffen Prohaska","fromEmail":"prohaska@zib.de","sentAt":"2007-10-14T08:54:44Z","receivedAt":"2007-10-14T08:54:44Z","isPatch":true,"sender":{"key":"prohaska@zib.de","avatar":"https://avatars.githubusercontent.com/u/217580?v=4"},"body":"ref_cmp_full_short(full_name, short_name) expands short_name according\nto the rules documented in git-rev-parse and compares the expanded\nname with full_name. It reports a match by returning 0.\n\nThis function makes the rules for resolving refs to sha1s available\nfor string comparison. Before this change, the rules were buried in\nget_sha1*() and dwim_ref().\n\nref_cmp_full_short() will be used for matching refspecs in git-send-pack.\n\nSigned-off-by: Steffen Prohaska <prohaska@zib.de>\n---\n cache.h     |    1 +\n sha1_name.c |   13 +++++++++++++\n 2 files changed, 14 insertions(+), 0 deletions(-)\n\ndiff --git a/cache.h b/cache.h\nindex f98d57a..59345b5 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -406,6 +406,7 @@ extern int get_sha1_hex(const char *hex, unsigned char *sha1);\n extern char *sha1_to_hex(const unsigned char *sha1);\t/* static buffer result! */\n extern int read_ref(const char *filename, unsigned char *sha1);\n extern const char *resolve_ref(const char *path, unsigned char *sha1, int, int *);\n+extern int ref_cmp_full_short(const char *full_name, const char* short_name);\n extern int dwim_ref(const char *str, int len, unsigned char *sha1, char **ref);\n extern int dwim_log(const char *str, int len, unsigned char *sha1, char **ref);\n \ndiff --git a/sha1_name.c b/sha1_name.c\nindex b820909..ae235be 100644\n--- a/sha1_name.c\n+++ b/sha1_name.c\n@@ -249,6 +249,19 @@ static const char *ref_fmt[] = {\n \tNULL\n };\n \n+int ref_cmp_full_short(const char* full_name, const char* short_name)\n+{\n+\tconst char **p;\n+    const int short_name_len = strlen(short_name);\n+\n+\tfor (p = ref_fmt; *p; p++) {\n+\t\tif (strcmp(full_name, mkpath(*p, short_name_len, short_name)) == 0) {\n+            return 0;\n+        }\n+    }\n+    return -1;\n+}\n+\n int dwim_ref(const char *str, int len, unsigned char *sha1, char **ref)\n {\n \tconst char **p, *r;\n-- \n1.5.3.4.224.gc6b84\n"},{"id":"55682","messageId":"11923520862307-git-send-email-prohaska@zib.de","threadId":"10271","inReplyTo":"11923520853014-git-send-email-prohaska@zib.de","subject":"[PATCH 6/6] push, send-pack: use same rules as git-rev-parse to resolve refspecs","fromName":"Steffen Prohaska","fromEmail":"prohaska@zib.de","sentAt":"2007-10-14T08:54:45Z","receivedAt":"2007-10-14T08:54:45Z","isPatch":true,"sender":{"key":"prohaska@zib.de","avatar":"https://avatars.githubusercontent.com/u/217580?v=4"},"body":"This commit changes the rules for resolving refspecs to match the\nrules for resolving refs in rev-parse. git-rev-parse uses clear rules\nto resolve a short ref to its full name, which are well documented.\nThe rules for resolving refspecs documented in git-send-pack were\nless strict and harder to understand. This commit replaces them by\nthe rules of git-rev-parse.\n\nThe unified rules are easier to understand and better resolve ambiguous\ncases. You can now push from a repository containing several branches\nending on the same short name.\n\nNote, this breaks existing setups. For example \"master\" will no longer\nresolve to \"origin/master\".\n\nTODO: this patch does not yet include a modified documentation of\ngit-send-pack. I prefer to wait for some comments first.\n\nSigned-off-by: Steffen Prohaska <prohaska@zib.de>\n---\n remote.c              |    5 +----\n t/t5516-fetch-push.sh |   12 +++++++++++-\n 2 files changed, 12 insertions(+), 5 deletions(-)\n\ndiff --git a/remote.c b/remote.c\nindex 58bc019..09cb611 100644\n--- a/remote.c\n+++ b/remote.c\n@@ -383,10 +383,7 @@ static int count_refspec_match(const char *pattern,\n \t\tchar *name = refs->name;\n \t\tint namelen = strlen(name);\n \n-\t\tif (namelen < patlen ||\n-\t\t    memcmp(name + namelen - patlen, pattern, patlen))\n-\t\t\tcontinue;\n-\t\tif (namelen != patlen && name[namelen - patlen - 1] != '/')\n+\t\tif (ref_cmp_full_short(name, pattern))\n \t\t\tcontinue;\n \n \t\t/* A match is \"weak\" if it is with refs outside\ndiff --git a/t/t5516-fetch-push.sh b/t/t5516-fetch-push.sh\nindex 97a032e..2664060 100755\n--- a/t/t5516-fetch-push.sh\n+++ b/t/t5516-fetch-push.sh\n@@ -175,11 +175,21 @@ test_expect_success 'push with no ambiguity (1)' '\n test_expect_success 'push with no ambiguity (2)' '\n \n \tmk_test remotes/origin/master &&\n-\tgit push testrepo master:master &&\n+\tgit push testrepo master:origin/master &&\n \tcheck_push_result $the_commit remotes/origin/master\n \n '\n \n+test_expect_success 'push with colon-less refspec, no ambiguity' '\n+\n+\tmk_test heads/master heads/t/master &&\n+\tgit branch -f t/master master &&\n+\tgit push testrepo master &&\n+\tcheck_push_result $the_commit heads/master &&\n+\tcheck_push_result $the_first_commit heads/t/master\n+\n+'\n+\n test_expect_success 'push with weak ambiguity (1)' '\n \n \tmk_test heads/master remotes/origin/master &&\n-- \n1.5.3.4.224.gc6b84\n"},{"id":"55683","messageId":"1192352681389-git-send-email-prohaska@zib.de","threadId":"10271","inReplyTo":"1192352085653-git-send-email-prohaska@zib.de","subject":"[PATCH 1/6 v2] push, send-pack: fix test if remote branch exists for colon-less refspec","fromName":"Steffen Prohaska","fromEmail":"prohaska@zib.de","sentAt":"2007-10-14T09:04:41Z","receivedAt":"2007-10-14T09:04:41Z","isPatch":true,"sender":{"key":"prohaska@zib.de","avatar":"https://avatars.githubusercontent.com/u/217580?v=4"},"body":"A push must fail if the remote ref does not yet exist and the refspec\ndoes not start with refs/. Remote refs must explicitly be created with\ntheir full name.\n\nThis commit adds some tests and fixes the existence check in send-pack.\n\nSigned-off-by: Steffen Prohaska <prohaska@zib.de>\n---\n remote.c              |    5 +++--\n t/t5516-fetch-push.sh |   34 ++++++++++++++++++++++++++++++++--\n 2 files changed, 35 insertions(+), 4 deletions(-)\n\ndiff --git a/remote.c b/remote.c\nindex bb774d0..f26f0e0 100644\n--- a/remote.c\n+++ b/remote.c\n@@ -475,6 +475,7 @@ static int match_explicit(struct ref *src, struct ref *dst,\n \tstruct ref *matched_src, *matched_dst;\n \n \tconst char *dst_value = rs->dst;\n+\tconst char * const orig_dst_value = rs->dst ? rs->dst : rs->src;\n \n \tif (rs->pattern)\n \t\treturn errs;\n@@ -511,12 +512,12 @@ 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\tif (!memcmp(orig_dst_value , \"refs/\", 5))\n \t\t\tmatched_dst = make_linked_ref(dst_value, 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 \"\n-\t\t\t      \"not start with refs/.\", dst_value);\n+\t\t\t      \"not start with refs/.\", orig_dst_value);\n \t\tbreak;\n \tdefault:\n \t\tmatched_dst = NULL;\ndiff --git a/t/t5516-fetch-push.sh b/t/t5516-fetch-push.sh\nindex ca46aaf..8629cf2 100755\n--- a/t/t5516-fetch-push.sh\n+++ b/t/t5516-fetch-push.sh\n@@ -126,6 +126,36 @@ test_expect_success 'push with wildcard' '\n \t)\n '\n \n+test_expect_success 'push nonexisting (1)' '\n+\n+\tmk_test &&\n+\tif git push testrepo master\n+\tthen\n+\t\techo \"Oops, should have failed\"\n+\t\tfalse\n+\tfi\n+\n+'\n+\n+test_expect_success 'push nonexisting (2)' '\n+\n+\tmk_test &&\n+\tif git push testrepo heads/master\n+\tthen\n+\t\techo \"Oops, should have failed\"\n+\t\tfalse\n+\tfi\n+\n+'\n+\n+test_expect_success 'push nonexisting (3)' '\n+\n+\tmk_test &&\n+\tgit push testrepo refs/heads/master &&\n+\tcheck_push_result $the_commit heads/master\n+\n+'\n+\n test_expect_success 'push with matching heads' '\n \n \tmk_test heads/master &&\n@@ -225,7 +255,7 @@ test_expect_success 'push with colon-less refspec (3)' '\n \t\tgit tag -d frotz\n \tfi &&\n \tgit branch -f frotz master &&\n-\tgit push testrepo frotz &&\n+\tgit push testrepo refs/heads/frotz &&\n \tcheck_push_result $the_commit heads/frotz &&\n \ttest 1 = $( cd testrepo && git show-ref | wc -l )\n '\n@@ -238,7 +268,7 @@ test_expect_success 'push with colon-less refspec (4)' '\n \t\tgit branch -D frotz\n \tfi &&\n \tgit tag -f frotz &&\n-\tgit push testrepo frotz &&\n+\tgit push testrepo refs/tags/frotz &&\n \tcheck_push_result $the_commit tags/frotz &&\n \ttest 1 = $( cd testrepo && git show-ref | wc -l )\n \n-- \n1.5.3.4.224.gc6b84\n"},{"id":"55684","messageId":"3CEDD64B-8E6F-4D95-BEDA-BE7CA2898705@zib.de","threadId":"10271","inReplyTo":"11923520851713-git-send-email-prohaska@zib.de","subject":"Re: change push's refspec behavior to match rev-parse","fromName":"Steffen Prohaska","fromEmail":"prohaska@zib.de","sentAt":"2007-10-14T09:04:55Z","receivedAt":"2007-10-14T09:04:55Z","isPatch":false,"sender":{"key":"prohaska@zib.de","avatar":"https://avatars.githubusercontent.com/u/217580?v=4"},"body":"\nOn Oct 14, 2007, at 10:54 AM, Steffen Prohaska wrote:\n\n>\n>\n>  [PATCH 1/6] push, send-pack: fix test if remote branch exists for  \n> colon-less refspec\n>\n> \tThis is a bug fix that should go to maint. All following patches  \n> modifying\n>         the push test script require this.\n>\n>  [PATCH 4/6] push, send-pack: support pushing HEAD to real ref name\n>\n> \tRequires 1/6.\n\nThese two patches got mixed. I'll send updated versions in a minute.\n\nSorry for the noise,\n\tSteffen\n"},{"id":"55685","messageId":"1192352730108-git-send-email-prohaska@zib.de","threadId":"10271","inReplyTo":"11923520851656-git-send-email-prohaska@zib.de","subject":"[PATCH 4/6 v2] push, send-pack: support pushing HEAD to real ref name","fromName":"Steffen Prohaska","fromEmail":"prohaska@zib.de","sentAt":"2007-10-14T09:05:30Z","receivedAt":"2007-10-14T09:05:30Z","isPatch":true,"sender":{"key":"prohaska@zib.de","avatar":"https://avatars.githubusercontent.com/u/217580?v=4"},"body":"This teaches \"push <remote> HEAD\" to resolve HEAD on the local\nside to its real ref name, e.g. refs/heads/master, and then\nuse the real ref name on the remote side to search a matching\nremote ref.\n\nSigned-off-by: Steffen Prohaska <prohaska@zib.de>\n---\n remote.c              |   13 ++++++++++---\n t/t5516-fetch-push.sh |   22 ++++++++++++++++++++++\n 2 files changed, 32 insertions(+), 3 deletions(-)\n\ndiff --git a/remote.c b/remote.c\nindex f26f0e0..58bc019 100644\n--- a/remote.c\n+++ b/remote.c\n@@ -439,6 +439,8 @@ static struct ref *try_explicit_object_name(const char *name)\n \tunsigned char sha1[20];\n \tstruct ref *ref;\n \tint len;\n+\tchar *real_name = 0;\n+\tconst char *best_name;\n \n \tif (!*name) {\n \t\tref = alloc_ref(20);\n@@ -446,12 +448,17 @@ static struct ref *try_explicit_object_name(const char *name)\n \t\thashclr(ref->new_sha1);\n \t\treturn ref;\n \t}\n-\tif (get_sha1(name, sha1))\n+\tif (get_sha1_with_real_ref(name, sha1, &real_name))\n \t\treturn NULL;\n-\tlen = strlen(name) + 1;\n+\tbest_name = real_name ? real_name : name;\n+\tlen = strlen(best_name) + 1;\n \tref = alloc_ref(len);\n-\tmemcpy(ref->name, name, len);\n+\tmemcpy(ref->name, best_name, len);\n \thashcpy(ref->new_sha1, sha1);\n+\n+\tif (real_name) {\n+\t\tfree(real_name);\n+\t}\n \treturn ref;\n }\n \ndiff --git a/t/t5516-fetch-push.sh b/t/t5516-fetch-push.sh\nindex 8629cf2..97a032e 100755\n--- a/t/t5516-fetch-push.sh\n+++ b/t/t5516-fetch-push.sh\n@@ -274,4 +274,26 @@ test_expect_success 'push with colon-less refspec (4)' '\n \n '\n \n+test_expect_success 'push with HEAD' '\n+\n+\tmk_test heads/master &&\n+\tgit push testrepo HEAD &&\n+\tcheck_push_result $the_commit heads/master\n+\n+'\n+\n+test_expect_success 'push with HEAD not existing at remote' '\n+\n+\tmk_test heads/master &&\n+\tgit checkout -b local master &&\n+\tif git push testrepo HEAD\n+\tthen\n+\t\techo \"Oops, should have failed\"\n+\t\tfalse\n+\telse\n+\t\tcheck_push_result $the_first_commit heads/master\n+\tfi\n+\n+'\n+\n test_done\n-- \n1.5.3.4.224.gc6b84\n"},{"id":"55745","messageId":"Pine.LNX.4.64.0710141819490.25221@racer.site","threadId":"10271","inReplyTo":"11923520852991-git-send-email-prohaska@zib.de","subject":"Re: [PATCH 2/6] add get_sha1_with_real_ref() returning full name of ref on demand","fromName":"Johannes Schindelin","fromEmail":"johannes.schindelin@gmx.de","sentAt":"2007-10-14T17:21:09Z","receivedAt":"2007-10-14T17:21:09Z","isPatch":true,"sender":{"key":"johannes.schindelin@gmx.de","avatar":"https://avatars.githubusercontent.com/u/127790?v=4"},"body":"Hi,\n\nOn Sun, 14 Oct 2007, Steffen Prohaska wrote:\n\n> Deep inside get_sha1() the name of the requested ref is matched\n> according to the rules documented in git-rev-parse. This patch\n> introduces a function that returns the full name of the matched\n> ref to the outside.\n> \n> For example 'master' is typically returned as 'refs/heads/master'.\n> \n> The new function can be used by \"git rev-parse\" to print the full\n> name of the matched ref and can be used by \"git send-pack\" to expand\n> a local ref to its full name.\n\nI have not really studies your patch, but from your description it sounds \nas if dwim_ref() does what you want.\n\nCiao,\nDscho\n"},{"id":"55777","messageId":"5F1A8BAA-108D-4D55-9AEE-7ECDFA3DEB03@zib.de","threadId":"10271","inReplyTo":"Pine.LNX.4.64.0710141819490.25221@racer.site","subject":"Re: [PATCH 2/6] add get_sha1_with_real_ref() returning full name of ref on demand","fromName":"Steffen Prohaska","fromEmail":"prohaska@zib.de","sentAt":"2007-10-14T21:37:21Z","receivedAt":"2007-10-14T21:37:21Z","isPatch":true,"sender":{"key":"prohaska@zib.de","avatar":"https://avatars.githubusercontent.com/u/217580?v=4"},"body":"\nOn Oct 14, 2007, at 7:21 PM, Johannes Schindelin wrote:\n\n> Hi,\n>\n> On Sun, 14 Oct 2007, Steffen Prohaska wrote:\n>\n>> Deep inside get_sha1() the name of the requested ref is matched\n>> according to the rules documented in git-rev-parse. This patch\n>> introduces a function that returns the full name of the matched\n>> ref to the outside.\n>>\n>> For example 'master' is typically returned as 'refs/heads/master'.\n>>\n>> The new function can be used by \"git rev-parse\" to print the full\n>> name of the matched ref and can be used by \"git send-pack\" to expand\n>> a local ref to its full name.\n>\n> I have not really studies your patch, but from your description it  \n> sounds\n> as if dwim_ref() does what you want.\n\nWithout my patch get_sha1_with_mode() calls get_sha1_1() calls  \nget_sha1_basic()\ncalls dwim_ref(). I didn't analyze in detail what the *sha1*  \nfunctions add\nto what dwim_ref() provides.\n\nThe patch passes the information from dwim_ref() up the callstack.  \nMaybe this\nis not needed and I could directly call dwim_ref(). But I don't know.\n\n\tSteffen\n"}]}