{"thread":{"id":"30945","subject":"[PATCH v5 00/25] Extending the shelf-life of \"git describe\" output","startedAt":"2012-07-03T21:36:50Z","lastAt":"2012-07-03T21:37:15Z","messageCount":26,"participants":["Junio C Hamano"],"isPatch":true,"patchVersion":5,"patchTotal":25},"messages":[{"id":"194559","messageId":"1341351435-31011-1-git-send-email-gitster@pobox.com","threadId":"30945","inReplyTo":null,"subject":"[PATCH v5 00/25] Extending the shelf-life of \"git describe\" output","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2012-07-03T21:36:50Z","receivedAt":"2012-07-03T21:36:50Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"This is take 5.  The earlier rounds were $gmane/200165, 200387,\n200506 and 200869.\n\nExcept that the typo advise function is now called\n\"maybe_die_on_misspelt_object_name()\", per discussion with Matthieu,\nthe early part of the series up to \"restructure disambiguation\"\n(Patch #9) is the same as before.\n\nI thought the thinking behind the fix to a minor regression pointed\nout by Peff deserves to be kept as a separate commit, so it appears\nas such as Patch #10.\n\nPatches #20-#24 are new.  The test script added in Patch #13 includes\nthe tests for these new features, all start as \"expect-failure\", and\nthese flip them to \"expect-success\" as they implement them.\n\nThe last one #25 adds a new option to rev-parse to let you enumerate\nobjects that would match if you give too short an abbreviation.  It\nwould independently help the issue in \"blame\" output that did not\nattempt to make the commit object names unique, reported in\n$gmane/200839.\n\n\nJunio C Hamano (25):\n  sha1_name.c: indentation fix\n  sha1_name.c: hide get_sha1_with_context_1() ugliness\n  sha1_name.c: get rid of get_sha1_with_mode_1()\n  sha1_name.c: get rid of get_sha1_with_mode()\n  sha1_name.c: clarify what \"fake\" is for in find_short_object_filename()\n  sha1_name.c: rename \"now\" to \"current\"\n  sha1_name.c: refactor find_short_packed_object()\n  sha1_name.c: correct misnamed \"canonical\" and \"res\"\n  sha1_name.c: restructure disambiguation of short names\n  get_sha1(): fix error status regression\n  sha1_name.c: allow get_short_sha1() to take other flags\n  sha1_name.c: teach get_short_sha1() a commit-only option\n  sha1_name.c: get_describe_name() by definition groks only commits\n  sha1_name.c: get_sha1_1() takes lookup flags\n  sha1_name.c: many short names can only be committish\n  sha1_name.c: teach lookup context to get_sha1_with_context()\n  sha1_name.c: introduce get_sha1_committish()\n  revision.c: allow handle_revision_arg() to take other flags\n  revision.c: the \"log\" family, except for \"show\", takes committish\n  sha1_name.c: add support for disambiguating other types\n  apply: --build-fake-ancestor expects blobs\n  commit-tree: the command wants a tree and commits\n  reset: the command takes committish\n  rev-parse: A and B in \"rev-parse A..B\" refer to committish\n  rev-parse --disambiguate=<prefix>\n\n Documentation/git-rev-parse.txt     |   6 +\n builtin/apply.c                     |   2 +-\n builtin/cat-file.c                  |   2 +-\n builtin/commit-tree.c               |   8 +-\n builtin/log.c                       |   3 +\n builtin/pack-objects.c              |   2 +-\n builtin/reset.c                     |  10 +-\n builtin/rev-parse.c                 |  14 +-\n cache.h                             |  28 +-\n commit.c                            |   2 +-\n revision.c                          |  38 +--\n revision.h                          |   5 +-\n setup.c                             |   8 +-\n sha1_name.c                         | 494 ++++++++++++++++++++++++++----------\n t/t1512-rev-parse-disambiguation.sh | 263 +++++++++++++++++++\n 15 files changed, 713 insertions(+), 172 deletions(-)\n create mode 100755 t/t1512-rev-parse-disambiguation.sh\n\n-- \n1.7.11.1.229.g706c98f\n"},{"id":"194560","messageId":"1341351435-31011-2-git-send-email-gitster@pobox.com","threadId":"30945","inReplyTo":"1341351435-31011-1-git-send-email-gitster@pobox.com","subject":"[PATCH v5 01/25] sha1_name.c: indentation fix","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2012-07-03T21:36:51Z","receivedAt":"2012-07-03T21:36:51Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Signed-off-by: Junio C Hamano <gitster@pobox.com>\n---\n sha1_name.c | 4 ++--\n 1 file changed, 2 insertions(+), 2 deletions(-)\n\ndiff --git a/sha1_name.c b/sha1_name.c\nindex 03ffc2c..5b0c845 100644\n--- a/sha1_name.c\n+++ b/sha1_name.c\n@@ -103,10 +103,10 @@ static int find_short_packed_object(int len, const unsigned char *match, unsigne\n \t\t}\n \t\tif (first < num) {\n \t\t\tconst unsigned char *now, *next;\n-\t\t       now = nth_packed_object_sha1(p, first);\n+\t\t\tnow = nth_packed_object_sha1(p, first);\n \t\t\tif (match_sha(len, match, now)) {\n \t\t\t\tnext = nth_packed_object_sha1(p, first+1);\n-\t\t\t       if (!next|| !match_sha(len, match, next)) {\n+\t\t\t\tif (!next|| !match_sha(len, match, next)) {\n \t\t\t\t\t/* unique within this pack */\n \t\t\t\t\tif (!found) {\n \t\t\t\t\t\tfound_sha1 = now;\n-- \n1.7.11.1.229.g706c98f\n"},{"id":"194581","messageId":"1341351435-31011-3-git-send-email-gitster@pobox.com","threadId":"30945","inReplyTo":"1341351435-31011-1-git-send-email-gitster@pobox.com","subject":"[PATCH v5 02/25] sha1_name.c: hide get_sha1_with_context_1() ugliness","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2012-07-03T21:36:52Z","receivedAt":"2012-07-03T21:36:52Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"There is no outside caller that cares about the \"only-to-die\" ugliness.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n cache.h     |  6 +-----\n sha1_name.c | 31 ++++++++++++++++++-------------\n 2 files changed, 19 insertions(+), 18 deletions(-)\n\ndiff --git a/cache.h b/cache.h\nindex 10afd71..9ee470c 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -817,11 +817,7 @@ static inline int get_sha1_with_mode(const char *str, unsigned char *sha1, unsig\n {\n \treturn get_sha1_with_mode_1(str, sha1, mode, 0, NULL);\n }\n-extern int get_sha1_with_context_1(const char *name, unsigned char *sha1, struct object_context *orc, int only_to_die, const char *prefix);\n-static inline int get_sha1_with_context(const char *str, unsigned char *sha1, struct object_context *orc)\n-{\n-\treturn get_sha1_with_context_1(str, sha1, orc, 0, NULL);\n-}\n+extern int get_sha1_with_context(const char *str, unsigned char *sha1, struct object_context *orc);\n \n /*\n  * Try to read a SHA1 in hexadecimal format from the 40 characters\ndiff --git a/sha1_name.c b/sha1_name.c\nindex 5b0c845..10932bf 100644\n--- a/sha1_name.c\n+++ b/sha1_name.c\n@@ -992,16 +992,6 @@ static void diagnose_invalid_index_path(int stage,\n }\n \n \n-int get_sha1_with_mode_1(const char *name, unsigned char *sha1, unsigned *mode,\n-\t\t\t int only_to_die, const char *prefix)\n-{\n-\tstruct object_context oc;\n-\tint ret;\n-\tret = get_sha1_with_context_1(name, sha1, &oc, only_to_die, prefix);\n-\t*mode = oc.mode;\n-\treturn ret;\n-}\n-\n static char *resolve_relative_path(const char *rel)\n {\n \tif (prefixcmp(rel, \"./\") && prefixcmp(rel, \"../\"))\n@@ -1019,9 +1009,9 @@ static char *resolve_relative_path(const char *rel)\n \t\t\t   rel);\n }\n \n-int get_sha1_with_context_1(const char *name, unsigned char *sha1,\n-\t\t\t    struct object_context *oc,\n-\t\t\t    int only_to_die, const char *prefix)\n+static int get_sha1_with_context_1(const char *name, unsigned char *sha1,\n+\t\t\t\t   struct object_context *oc,\n+\t\t\t\t   int only_to_die, const char *prefix)\n {\n \tint ret, bracket_depth;\n \tint namelen = strlen(name);\n@@ -1134,3 +1124,18 @@ int get_sha1_with_context_1(const char *name, unsigned char *sha1,\n \t}\n \treturn ret;\n }\n+\n+int get_sha1_with_mode_1(const char *name, unsigned char *sha1, unsigned *mode,\n+\t\t\t int only_to_die, const char *prefix)\n+{\n+\tstruct object_context oc;\n+\tint ret;\n+\tret = get_sha1_with_context_1(name, sha1, &oc, only_to_die, prefix);\n+\t*mode = oc.mode;\n+\treturn ret;\n+}\n+\n+int get_sha1_with_context(const char *str, unsigned char *sha1, struct object_context *orc)\n+{\n+\treturn get_sha1_with_context_1(str, sha1, orc, 0, NULL);\n+}\n-- \n1.7.11.1.229.g706c98f\n"},{"id":"194562","messageId":"1341351435-31011-4-git-send-email-gitster@pobox.com","threadId":"30945","inReplyTo":"1341351435-31011-1-git-send-email-gitster@pobox.com","subject":"[PATCH v5 03/25] sha1_name.c: get rid of get_sha1_with_mode_1()","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2012-07-03T21:36:53Z","receivedAt":"2012-07-03T21:36:53Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"The only external caller is setup.c that tries to give a nicer error\nmessage when an object name is misspelt (e.g. \"HEAD:cashe.h\").\nRetire it and give the caller a dedicated and more intuitive API\nfunction maybe_die_on_misspelt_object_name().\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n cache.h     |  7 ++-----\n setup.c     |  8 ++------\n sha1_name.c | 20 ++++++++++++++++----\n 3 files changed, 20 insertions(+), 15 deletions(-)\n\ndiff --git a/cache.h b/cache.h\nindex 9ee470c..beafa5b 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -812,11 +812,8 @@ struct object_context {\n };\n \n extern int get_sha1(const char *str, unsigned char *sha1);\n-extern int get_sha1_with_mode_1(const char *str, unsigned char *sha1, unsigned *mode, int only_to_die, const char *prefix);\n-static inline int get_sha1_with_mode(const char *str, unsigned char *sha1, unsigned *mode)\n-{\n-\treturn get_sha1_with_mode_1(str, sha1, mode, 0, NULL);\n-}\n+extern int get_sha1_with_mode(const char *str, unsigned char *sha1, unsigned *mode);\n+extern void maybe_die_on_misspelt_object_name(const char *name, const char *prefix);\n extern int get_sha1_with_context(const char *str, unsigned char *sha1, struct object_context *orc);\n \n /*\ndiff --git a/setup.c b/setup.c\nindex 61c22e6..233bfbe 100644\n--- a/setup.c\n+++ b/setup.c\n@@ -55,18 +55,14 @@ int check_filename(const char *prefix, const char *arg)\n \n static void NORETURN die_verify_filename(const char *prefix, const char *arg)\n {\n-\tunsigned char sha1[20];\n-\tunsigned mode;\n-\n \t/*\n \t * Saying \"'(icase)foo' does not exist in the index\" when the\n \t * user gave us \":(icase)foo\" is just stupid.  A magic pathspec\n \t * begins with a colon and is followed by a non-alnum; do not\n-\t * let get_sha1_with_mode_1(only_to_die=1) to even trigger.\n+\t * let maybe_die_on_misspelt_object_name() even trigger.\n \t */\n \tif (!(arg[0] == ':' && !isalnum(arg[1])))\n-\t\t/* try a detailed diagnostic ... */\n-\t\tget_sha1_with_mode_1(arg, sha1, &mode, 1, prefix);\n+\t\tmaybe_die_on_misspelt_object_name(arg, prefix);\n \n \t/* ... or fall back the most general message. */\n \tdie(\"ambiguous argument '%s': unknown revision or path not in the working tree.\\n\"\ndiff --git a/sha1_name.c b/sha1_name.c\nindex 10932bf..df583c2 100644\n--- a/sha1_name.c\n+++ b/sha1_name.c\n@@ -1125,12 +1125,24 @@ static int get_sha1_with_context_1(const char *name, unsigned char *sha1,\n \treturn ret;\n }\n \n-int get_sha1_with_mode_1(const char *name, unsigned char *sha1, unsigned *mode,\n-\t\t\t int only_to_die, const char *prefix)\n+/*\n+ * Call this function when you know \"name\" given by the end user must\n+ * name an object but it doesn't; the function _may_ die with a better\n+ * diagnostic message than \"no such object 'name'\", e.g. \"Path 'doc' does not\n+ * exist in 'HEAD'\" when given \"HEAD:doc\", or it may return in which case\n+ * you have a chance to diagnose the error further.\n+ */\n+void maybe_die_on_misspelt_object_name(const char *name, const char *prefix)\n {\n \tstruct object_context oc;\n-\tint ret;\n-\tret = get_sha1_with_context_1(name, sha1, &oc, only_to_die, prefix);\n+\tunsigned char sha1[20];\n+\tget_sha1_with_context_1(name, sha1, &oc, 1, prefix);\n+}\n+\n+int get_sha1_with_mode(const char *str, unsigned char *sha1, unsigned *mode)\n+{\n+\tstruct object_context oc;\n+\tint ret = get_sha1_with_context_1(str, sha1, &oc, 0, NULL);\n \t*mode = oc.mode;\n \treturn ret;\n }\n-- \n1.7.11.1.229.g706c98f\n"},{"id":"194580","messageId":"1341351435-31011-5-git-send-email-gitster@pobox.com","threadId":"30945","inReplyTo":"1341351435-31011-1-git-send-email-gitster@pobox.com","subject":"[PATCH v5 04/25] sha1_name.c: get rid of get_sha1_with_mode()","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2012-07-03T21:36:54Z","receivedAt":"2012-07-03T21:36:54Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"There are only two callers, and they will benefit from being able to\npass disambiguation hints to underlying get_sha1_with_context() API\nonce it happens.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n cache.h     |  1 -\n revision.c  | 12 ++++++------\n sha1_name.c |  8 --------\n 3 files changed, 6 insertions(+), 15 deletions(-)\n\ndiff --git a/cache.h b/cache.h\nindex beafa5b..2aa9fb6 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -812,7 +812,6 @@ struct object_context {\n };\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 void maybe_die_on_misspelt_object_name(const char *name, const char *prefix);\n extern int get_sha1_with_context(const char *str, unsigned char *sha1, struct object_context *orc);\n \ndiff --git a/revision.c b/revision.c\nindex 064e351..86a14c8 100644\n--- a/revision.c\n+++ b/revision.c\n@@ -1097,7 +1097,7 @@ int handle_revision_arg(const char *arg_, struct rev_info *revs,\n \t\t\tint flags,\n \t\t\tint cant_be_filename)\n {\n-\tunsigned mode;\n+\tstruct object_context oc;\n \tchar *dotdot;\n \tstruct object *object;\n \tunsigned char sha1[20];\n@@ -1180,13 +1180,13 @@ int handle_revision_arg(const char *arg_, struct rev_info *revs,\n \t\tlocal_flags = UNINTERESTING;\n \t\targ++;\n \t}\n-\tif (get_sha1_with_mode(arg, sha1, &mode))\n+\tif (get_sha1_with_context(arg, sha1, &oc))\n \t\treturn revs->ignore_missing ? 0 : -1;\n \tif (!cant_be_filename)\n \t\tverify_non_filename(revs->prefix, arg);\n \tobject = get_reference(revs, arg, sha1, flags ^ local_flags);\n \tadd_rev_cmdline(revs, object, arg_, REV_CMD_REV, flags ^ local_flags);\n-\tadd_pending_object_with_mode(revs, object, arg, mode);\n+\tadd_pending_object_with_mode(revs, object, arg, oc.mode);\n \treturn 0;\n }\n \n@@ -1794,11 +1794,11 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, struct s\n \tif (revs->def && !revs->pending.nr && !got_rev_arg) {\n \t\tunsigned char sha1[20];\n \t\tstruct object *object;\n-\t\tunsigned mode;\n-\t\tif (get_sha1_with_mode(revs->def, sha1, &mode))\n+\t\tstruct object_context oc;\n+\t\tif (get_sha1_with_context(revs->def, sha1, &oc))\n \t\t\tdie(\"bad default revision '%s'\", revs->def);\n \t\tobject = get_reference(revs, revs->def, sha1, 0);\n-\t\tadd_pending_object_with_mode(revs, object, revs->def, mode);\n+\t\tadd_pending_object_with_mode(revs, object, revs->def, oc.mode);\n \t}\n \n \t/* Did the user ask for any diff output? Run the diff! */\ndiff --git a/sha1_name.c b/sha1_name.c\nindex df583c2..e63459b 100644\n--- a/sha1_name.c\n+++ b/sha1_name.c\n@@ -1139,14 +1139,6 @@ void maybe_die_on_misspelt_object_name(const char *name, const char *prefix)\n \tget_sha1_with_context_1(name, sha1, &oc, 1, prefix);\n }\n \n-int get_sha1_with_mode(const char *str, unsigned char *sha1, unsigned *mode)\n-{\n-\tstruct object_context oc;\n-\tint ret = get_sha1_with_context_1(str, sha1, &oc, 0, NULL);\n-\t*mode = oc.mode;\n-\treturn ret;\n-}\n-\n int get_sha1_with_context(const char *str, unsigned char *sha1, struct object_context *orc)\n {\n \treturn get_sha1_with_context_1(str, sha1, orc, 0, NULL);\n-- \n1.7.11.1.229.g706c98f\n"},{"id":"194561","messageId":"1341351435-31011-6-git-send-email-gitster@pobox.com","threadId":"30945","inReplyTo":"1341351435-31011-1-git-send-email-gitster@pobox.com","subject":"[PATCH v5 05/25] sha1_name.c: clarify what \"fake\" is for in find_short_object_filename()","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2012-07-03T21:36:55Z","receivedAt":"2012-07-03T21:36:55Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Signed-off-by: Junio C Hamano <gitster@pobox.com>\n---\n sha1_name.c | 7 +++++++\n 1 file changed, 7 insertions(+)\n\ndiff --git a/sha1_name.c b/sha1_name.c\nindex e63459b..9bb657d 100644\n--- a/sha1_name.c\n+++ b/sha1_name.c\n@@ -17,6 +17,13 @@ static int find_short_object_filename(int len, const char *name, unsigned char *\n \tstatic struct alternate_object_database *fakeent;\n \n \tif (!fakeent) {\n+\t\t/*\n+\t\t * Create a \"fake\" alternate object database that\n+\t\t * points to our own object database, to make it\n+\t\t * easier to get a temporary working space in\n+\t\t * alt->name/alt->base while iterating over the\n+\t\t * object databases including our own.\n+\t\t */\n \t\tconst char *objdir = get_object_directory();\n \t\tint objdir_len = strlen(objdir);\n \t\tint entlen = objdir_len + 43;\n-- \n1.7.11.1.229.g706c98f\n"},{"id":"194564","messageId":"1341351435-31011-7-git-send-email-gitster@pobox.com","threadId":"30945","inReplyTo":"1341351435-31011-1-git-send-email-gitster@pobox.com","subject":"[PATCH v5 06/25] sha1_name.c: rename \"now\" to \"current\"","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2012-07-03T21:36:56Z","receivedAt":"2012-07-03T21:36:56Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"This variable points at the element we are currently looking at, and\ndoes not have anything to do with the current time which the name\n\"now\" implies.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n sha1_name.c | 16 ++++++++--------\n 1 file changed, 8 insertions(+), 8 deletions(-)\n\ndiff --git a/sha1_name.c b/sha1_name.c\nindex 9bb657d..c5c4591 100644\n--- a/sha1_name.c\n+++ b/sha1_name.c\n@@ -93,11 +93,11 @@ static int find_short_packed_object(int len, const unsigned char *match, unsigne\n \t\tlast = num;\n \t\twhile (first < last) {\n \t\t\tuint32_t mid = (first + last) / 2;\n-\t\t\tconst unsigned char *now;\n+\t\t\tconst unsigned char *current;\n \t\t\tint cmp;\n \n-\t\t\tnow = nth_packed_object_sha1(p, mid);\n-\t\t\tcmp = hashcmp(match, now);\n+\t\t\tcurrent = nth_packed_object_sha1(p, mid);\n+\t\t\tcmp = hashcmp(match, current);\n \t\t\tif (!cmp) {\n \t\t\t\tfirst = mid;\n \t\t\t\tbreak;\n@@ -109,17 +109,17 @@ static int find_short_packed_object(int len, const unsigned char *match, unsigne\n \t\t\tlast = mid;\n \t\t}\n \t\tif (first < num) {\n-\t\t\tconst unsigned char *now, *next;\n-\t\t\tnow = nth_packed_object_sha1(p, first);\n-\t\t\tif (match_sha(len, match, now)) {\n+\t\t\tconst unsigned char *current, *next;\n+\t\t\tcurrent = nth_packed_object_sha1(p, first);\n+\t\t\tif (match_sha(len, match, current)) {\n \t\t\t\tnext = nth_packed_object_sha1(p, first+1);\n \t\t\t\tif (!next|| !match_sha(len, match, next)) {\n \t\t\t\t\t/* unique within this pack */\n \t\t\t\t\tif (!found) {\n-\t\t\t\t\t\tfound_sha1 = now;\n+\t\t\t\t\t\tfound_sha1 = current;\n \t\t\t\t\t\tfound++;\n \t\t\t\t\t}\n-\t\t\t\t\telse if (hashcmp(found_sha1, now)) {\n+\t\t\t\t\telse if (hashcmp(found_sha1, current)) {\n \t\t\t\t\t\tfound = 2;\n \t\t\t\t\t\tbreak;\n \t\t\t\t\t}\n-- \n1.7.11.1.229.g706c98f\n"},{"id":"194579","messageId":"1341351435-31011-8-git-send-email-gitster@pobox.com","threadId":"30945","inReplyTo":"1341351435-31011-1-git-send-email-gitster@pobox.com","subject":"[PATCH v5 07/25] sha1_name.c: refactor find_short_packed_object()","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2012-07-03T21:36:57Z","receivedAt":"2012-07-03T21:36:57Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Extract the logic to find object(s) that match a given prefix inside\na single pack into a separate helper function, and give it a bit more\ncomment.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n sha1_name.c | 103 +++++++++++++++++++++++++++++++++---------------------------\n 1 file changed, 56 insertions(+), 47 deletions(-)\n\ndiff --git a/sha1_name.c b/sha1_name.c\nindex c5c4591..7bef45f 100644\n--- a/sha1_name.c\n+++ b/sha1_name.c\n@@ -78,6 +78,59 @@ static int match_sha(unsigned len, const unsigned char *a, const unsigned char *\n \treturn 1;\n }\n \n+static int unique_in_pack(int len,\n+\t\t\t  const unsigned char *match,\n+\t\t\t  struct packed_git *p,\n+\t\t\t  const unsigned char **found_sha1,\n+\t\t\t  int seen_so_far)\n+{\n+\tuint32_t num, last, i, first = 0;\n+\tconst unsigned char *current = NULL;\n+\n+\topen_pack_index(p);\n+\tnum = p->num_objects;\n+\tlast = num;\n+\twhile (first < last) {\n+\t\tuint32_t mid = (first + last) / 2;\n+\t\tconst unsigned char *current;\n+\t\tint cmp;\n+\n+\t\tcurrent = nth_packed_object_sha1(p, mid);\n+\t\tcmp = hashcmp(match, current);\n+\t\tif (!cmp) {\n+\t\t\tfirst = mid;\n+\t\t\tbreak;\n+\t\t}\n+\t\tif (cmp > 0) {\n+\t\t\tfirst = mid+1;\n+\t\t\tcontinue;\n+\t\t}\n+\t\tlast = mid;\n+\t}\n+\n+\t/*\n+\t * At this point, \"first\" is the location of the lowest object\n+\t * with an object name that could match \"match\".  See if we have\n+\t * 0, 1 or more objects that actually match(es).\n+\t */\n+\tfor (i = first; i < num; i++) {\n+\t\tcurrent = nth_packed_object_sha1(p, first);\n+\t\tif (!match_sha(len, match, current))\n+\t\t\tbreak;\n+\n+\t\t/* current matches */\n+\t\tif (!seen_so_far) {\n+\t\t\t*found_sha1 = current;\n+\t\t\tseen_so_far++;\n+\t\t} else if (seen_so_far) {\n+\t\t\t/* is it the same as the one previously found elsewhere? */\n+\t\t\tif (hashcmp(*found_sha1, current))\n+\t\t\t\treturn 2; /* definitely not unique */\n+\t\t}\n+\t}\n+\treturn seen_so_far;\n+}\n+\n static int find_short_packed_object(int len, const unsigned char *match, unsigned char *sha1)\n {\n \tstruct packed_git *p;\n@@ -85,53 +138,9 @@ static int find_short_packed_object(int len, const unsigned char *match, unsigne\n \tint found = 0;\n \n \tprepare_packed_git();\n-\tfor (p = packed_git; p && found < 2; p = p->next) {\n-\t\tuint32_t num, last;\n-\t\tuint32_t first = 0;\n-\t\topen_pack_index(p);\n-\t\tnum = p->num_objects;\n-\t\tlast = num;\n-\t\twhile (first < last) {\n-\t\t\tuint32_t mid = (first + last) / 2;\n-\t\t\tconst unsigned char *current;\n-\t\t\tint cmp;\n-\n-\t\t\tcurrent = nth_packed_object_sha1(p, mid);\n-\t\t\tcmp = hashcmp(match, current);\n-\t\t\tif (!cmp) {\n-\t\t\t\tfirst = mid;\n-\t\t\t\tbreak;\n-\t\t\t}\n-\t\t\tif (cmp > 0) {\n-\t\t\t\tfirst = mid+1;\n-\t\t\t\tcontinue;\n-\t\t\t}\n-\t\t\tlast = mid;\n-\t\t}\n-\t\tif (first < num) {\n-\t\t\tconst unsigned char *current, *next;\n-\t\t\tcurrent = nth_packed_object_sha1(p, first);\n-\t\t\tif (match_sha(len, match, current)) {\n-\t\t\t\tnext = nth_packed_object_sha1(p, first+1);\n-\t\t\t\tif (!next|| !match_sha(len, match, next)) {\n-\t\t\t\t\t/* unique within this pack */\n-\t\t\t\t\tif (!found) {\n-\t\t\t\t\t\tfound_sha1 = current;\n-\t\t\t\t\t\tfound++;\n-\t\t\t\t\t}\n-\t\t\t\t\telse if (hashcmp(found_sha1, current)) {\n-\t\t\t\t\t\tfound = 2;\n-\t\t\t\t\t\tbreak;\n-\t\t\t\t\t}\n-\t\t\t\t}\n-\t\t\t\telse {\n-\t\t\t\t\t/* not even unique within this pack */\n-\t\t\t\t\tfound = 2;\n-\t\t\t\t\tbreak;\n-\t\t\t\t}\n-\t\t\t}\n-\t\t}\n-\t}\n+\tfor (p = packed_git; p && found < 2; p = p->next)\n+\t\tfound = unique_in_pack(len, match, p, &found_sha1, found);\n+\n \tif (found == 1)\n \t\thashcpy(sha1, found_sha1);\n \treturn found;\n-- \n1.7.11.1.229.g706c98f\n"},{"id":"194578","messageId":"1341351435-31011-9-git-send-email-gitster@pobox.com","threadId":"30945","inReplyTo":"1341351435-31011-1-git-send-email-gitster@pobox.com","subject":"[PATCH v5 08/25] sha1_name.c: correct misnamed \"canonical\" and \"res\"","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2012-07-03T21:36:58Z","receivedAt":"2012-07-03T21:36:58Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"These are hexadecimal and binary representation of the short object\nname given to the callchain as its input.  Rename them with _pfx\nsuffix to make it clear they are prefixes, and call them hex and bin\nrespectively.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n sha1_name.c | 44 ++++++++++++++++++++++----------------------\n 1 file changed, 22 insertions(+), 22 deletions(-)\n\ndiff --git a/sha1_name.c b/sha1_name.c\nindex 7bef45f..db8ac83 100644\n--- a/sha1_name.c\n+++ b/sha1_name.c\n@@ -9,7 +9,7 @@\n \n static int get_sha1_oneline(const char *, unsigned char *, struct commit_list *);\n \n-static int find_short_object_filename(int len, const char *name, unsigned char *sha1)\n+static int find_short_object_filename(int len, const char *hex_pfx, unsigned char *sha1)\n {\n \tstruct alternate_object_database *alt;\n \tchar hex[40];\n@@ -34,18 +34,18 @@ static int find_short_object_filename(int len, const char *name, unsigned char *\n \t}\n \tfakeent->next = alt_odb_list;\n \n-\tsprintf(hex, \"%.2s\", name);\n+\tsprintf(hex, \"%.2s\", hex_pfx);\n \tfor (alt = fakeent; alt && found < 2; alt = alt->next) {\n \t\tstruct dirent *de;\n \t\tDIR *dir;\n-\t\tsprintf(alt->name, \"%.2s/\", name);\n+\t\tsprintf(alt->name, \"%.2s/\", hex_pfx);\n \t\tdir = opendir(alt->base);\n \t\tif (!dir)\n \t\t\tcontinue;\n \t\twhile ((de = readdir(dir)) != NULL) {\n \t\t\tif (strlen(de->d_name) != 38)\n \t\t\t\tcontinue;\n-\t\t\tif (memcmp(de->d_name, name + 2, len - 2))\n+\t\t\tif (memcmp(de->d_name, hex_pfx + 2, len - 2))\n \t\t\t\tcontinue;\n \t\t\tif (!found) {\n \t\t\t\tmemcpy(hex + 2, de->d_name, 38);\n@@ -79,7 +79,7 @@ static int match_sha(unsigned len, const unsigned char *a, const unsigned char *\n }\n \n static int unique_in_pack(int len,\n-\t\t\t  const unsigned char *match,\n+\t\t\t  const unsigned char *bin_pfx,\n \t\t\t  struct packed_git *p,\n \t\t\t  const unsigned char **found_sha1,\n \t\t\t  int seen_so_far)\n@@ -96,7 +96,7 @@ static int unique_in_pack(int len,\n \t\tint cmp;\n \n \t\tcurrent = nth_packed_object_sha1(p, mid);\n-\t\tcmp = hashcmp(match, current);\n+\t\tcmp = hashcmp(bin_pfx, current);\n \t\tif (!cmp) {\n \t\t\tfirst = mid;\n \t\t\tbreak;\n@@ -110,12 +110,12 @@ static int unique_in_pack(int len,\n \n \t/*\n \t * At this point, \"first\" is the location of the lowest object\n-\t * with an object name that could match \"match\".  See if we have\n+\t * with an object name that could match \"bin_pfx\".  See if we have\n \t * 0, 1 or more objects that actually match(es).\n \t */\n \tfor (i = first; i < num; i++) {\n \t\tcurrent = nth_packed_object_sha1(p, first);\n-\t\tif (!match_sha(len, match, current))\n+\t\tif (!match_sha(len, bin_pfx, current))\n \t\t\tbreak;\n \n \t\t/* current matches */\n@@ -131,7 +131,7 @@ static int unique_in_pack(int len,\n \treturn seen_so_far;\n }\n \n-static int find_short_packed_object(int len, const unsigned char *match, unsigned char *sha1)\n+static int find_short_packed_object(int len, const unsigned char *bin_pfx, unsigned char *sha1)\n {\n \tstruct packed_git *p;\n \tconst unsigned char *found_sha1 = NULL;\n@@ -139,7 +139,7 @@ static int find_short_packed_object(int len, const unsigned char *match, unsigne\n \n \tprepare_packed_git();\n \tfor (p = packed_git; p && found < 2; p = p->next)\n-\t\tfound = unique_in_pack(len, match, p, &found_sha1, found);\n+\t\tfound = unique_in_pack(len, bin_pfx, p, &found_sha1, found);\n \n \tif (found == 1)\n \t\thashcpy(sha1, found_sha1);\n@@ -149,15 +149,15 @@ static int find_short_packed_object(int len, const unsigned char *match, unsigne\n #define SHORT_NAME_NOT_FOUND (-1)\n #define SHORT_NAME_AMBIGUOUS (-2)\n \n-static int find_unique_short_object(int len, char *canonical,\n-\t\t\t\t    unsigned char *res, unsigned char *sha1)\n+static int find_unique_short_object(int len, char *hex_pfx,\n+\t\t\t\t    unsigned char *bin_pfx, unsigned char *sha1)\n {\n \tint has_unpacked, has_packed;\n \tunsigned char unpacked_sha1[20], packed_sha1[20];\n \n \tprepare_alt_odb();\n-\thas_unpacked = find_short_object_filename(len, canonical, unpacked_sha1);\n-\thas_packed = find_short_packed_object(len, res, packed_sha1);\n+\thas_unpacked = find_short_object_filename(len, hex_pfx, unpacked_sha1);\n+\thas_packed = find_short_packed_object(len, bin_pfx, packed_sha1);\n \tif (!has_unpacked && !has_packed)\n \t\treturn SHORT_NAME_NOT_FOUND;\n \tif (1 < has_unpacked || 1 < has_packed)\n@@ -177,13 +177,13 @@ static int get_short_sha1(const char *name, int len, unsigned char *sha1,\n \t\t\t  int quietly)\n {\n \tint i, status;\n-\tchar canonical[40];\n-\tunsigned char res[20];\n+\tchar hex_pfx[40];\n+\tunsigned char bin_pfx[20];\n \n \tif (len < MINIMUM_ABBREV || len > 40)\n \t\treturn -1;\n-\thashclr(res);\n-\tmemset(canonical, 'x', 40);\n+\thashclr(bin_pfx);\n+\tmemset(hex_pfx, 'x', 40);\n \tfor (i = 0; i < len ;i++) {\n \t\tunsigned char c = name[i];\n \t\tunsigned char val;\n@@ -197,15 +197,15 @@ static int get_short_sha1(const char *name, int len, unsigned char *sha1,\n \t\t}\n \t\telse\n \t\t\treturn -1;\n-\t\tcanonical[i] = c;\n+\t\thex_pfx[i] = c;\n \t\tif (!(i & 1))\n \t\t\tval <<= 4;\n-\t\tres[i >> 1] |= val;\n+\t\tbin_pfx[i >> 1] |= val;\n \t}\n \n-\tstatus = find_unique_short_object(i, canonical, res, sha1);\n+\tstatus = find_unique_short_object(i, hex_pfx, bin_pfx, sha1);\n \tif (!quietly && (status == SHORT_NAME_AMBIGUOUS))\n-\t\treturn error(\"short SHA1 %.*s is ambiguous.\", len, canonical);\n+\t\treturn error(\"short SHA1 %.*s is ambiguous.\", len, hex_pfx);\n \treturn status;\n }\n \n-- \n1.7.11.1.229.g706c98f\n"},{"id":"194563","messageId":"1341351435-31011-10-git-send-email-gitster@pobox.com","threadId":"30945","inReplyTo":"1341351435-31011-1-git-send-email-gitster@pobox.com","subject":"[PATCH v5 09/25] sha1_name.c: restructure disambiguation of short names","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2012-07-03T21:36:59Z","receivedAt":"2012-07-03T21:36:59Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"We try to find zero, one or more matches from loose objects and\npacked objects independently and then decide if the given short\nobject name is unique across them.\n\nInstead, introduce a \"struct disambiguate_state\" that keeps track of\nwhat we have found so far, that can be one of:\n\n - We have seen one object that _could_ be what we are looking for;\n - We have also checked that object for additional constraints (if any),\n   and found that the object satisfies it;\n - We have also checked that object for additional constraints (if any),\n   and found that the object does not satisfy it; or\n - We have seen more than one objects that satisfy the constraints.\n\nand pass it to the enumeration functions for loose and packed\nobjects.  The disambiguation state can optionally take a callback\nfunction that takes a candidate object name and reports if the\nobject satisifies additional criteria (e.g. when the caller knows\nthat the short name must refer to a commit, this mechanism can be\nused to check the type of the given object).\n\nCompared to the earlier attempt, this round avoids the optional\ncheck if there is only one candidate that matches the short name in\nthe first place.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n sha1_name.c | 172 +++++++++++++++++++++++++++++++++++++++---------------------\n 1 file changed, 112 insertions(+), 60 deletions(-)\n\ndiff --git a/sha1_name.c b/sha1_name.c\nindex db8ac83..2e2dbb8 100644\n--- a/sha1_name.c\n+++ b/sha1_name.c\n@@ -9,11 +9,67 @@\n \n static int get_sha1_oneline(const char *, unsigned char *, struct commit_list *);\n \n-static int find_short_object_filename(int len, const char *hex_pfx, unsigned char *sha1)\n+typedef int (*disambiguate_hint_fn)(const unsigned char *, void *);\n+\n+struct disambiguate_state {\n+\tdisambiguate_hint_fn fn;\n+\tvoid *cb_data;\n+\tunsigned char candidate[20];\n+\tunsigned candidate_exists:1;\n+\tunsigned candidate_checked:1;\n+\tunsigned candidate_ok:1;\n+\tunsigned disambiguate_fn_used:1;\n+\tunsigned ambiguous:1;\n+};\n+\n+static void update_candidates(struct disambiguate_state *ds, const unsigned char *current)\n+{\n+\tif (!ds->candidate_exists) {\n+\t\t/* this is the first candidate */\n+\t\thashcpy(ds->candidate, current);\n+\t\tds->candidate_exists = 1;\n+\t\treturn;\n+\t} else if (!hashcmp(ds->candidate, current)) {\n+\t\t/* the same as what we already have seen */\n+\t\treturn;\n+\t}\n+\n+\tif (!ds->fn) {\n+\t\t/* cannot disambiguate between ds->candidate and current */\n+\t\tds->ambiguous = 1;\n+\t\treturn;\n+\t}\n+\n+\tif (!ds->candidate_checked) {\n+\t\tds->candidate_ok = ds->fn(ds->candidate, ds->cb_data);\n+\t\tds->disambiguate_fn_used = 1;\n+\t\tds->candidate_checked = 1;\n+\t}\n+\n+\tif (!ds->candidate_ok) {\n+\t\t/* discard the candidate; we know it does not satisify fn */\n+\t\thashcpy(ds->candidate, current);\n+\t\tds->candidate_checked = 0;\n+\t\treturn;\n+\t}\n+\n+\t/* if we reach this point, we know ds->candidate satisfies fn */\n+\tif (ds->fn(current, ds->cb_data)) {\n+\t\t/*\n+\t\t * if both current and candidate satisfy fn, we cannot\n+\t\t * disambiguate.\n+\t\t */\n+\t\tds->candidate_ok = 0;\n+\t\tds->ambiguous = 1;\n+\t}\n+\n+\t/* otherwise, current can be discarded and candidate is still good */\n+}\n+\n+static void find_short_object_filename(int len, const char *hex_pfx, struct disambiguate_state *ds)\n {\n \tstruct alternate_object_database *alt;\n \tchar hex[40];\n-\tint found = 0;\n \tstatic struct alternate_object_database *fakeent;\n \n \tif (!fakeent) {\n@@ -35,32 +91,27 @@ static int find_short_object_filename(int len, const char *hex_pfx, unsigned cha\n \tfakeent->next = alt_odb_list;\n \n \tsprintf(hex, \"%.2s\", hex_pfx);\n-\tfor (alt = fakeent; alt && found < 2; alt = alt->next) {\n+\tfor (alt = fakeent; alt && !ds->ambiguous; alt = alt->next) {\n \t\tstruct dirent *de;\n \t\tDIR *dir;\n \t\tsprintf(alt->name, \"%.2s/\", hex_pfx);\n \t\tdir = opendir(alt->base);\n \t\tif (!dir)\n \t\t\tcontinue;\n-\t\twhile ((de = readdir(dir)) != NULL) {\n+\n+\t\twhile (!ds->ambiguous && (de = readdir(dir)) != NULL) {\n+\t\t\tunsigned char sha1[20];\n+\n \t\t\tif (strlen(de->d_name) != 38)\n \t\t\t\tcontinue;\n \t\t\tif (memcmp(de->d_name, hex_pfx + 2, len - 2))\n \t\t\t\tcontinue;\n-\t\t\tif (!found) {\n-\t\t\t\tmemcpy(hex + 2, de->d_name, 38);\n-\t\t\t\tfound++;\n-\t\t\t}\n-\t\t\telse if (memcmp(hex + 2, de->d_name, 38)) {\n-\t\t\t\tfound = 2;\n-\t\t\t\tbreak;\n-\t\t\t}\n+\t\t\tmemcpy(hex + 2, de->d_name, 38);\n+\t\t\tif (!get_sha1_hex(hex, sha1))\n+\t\t\t\tupdate_candidates(ds, sha1);\n \t\t}\n \t\tclosedir(dir);\n \t}\n-\tif (found == 1)\n-\t\treturn get_sha1_hex(hex, sha1) == 0;\n-\treturn found;\n }\n \n static int match_sha(unsigned len, const unsigned char *a, const unsigned char *b)\n@@ -78,11 +129,10 @@ static int match_sha(unsigned len, const unsigned char *a, const unsigned char *\n \treturn 1;\n }\n \n-static int unique_in_pack(int len,\n+static void unique_in_pack(int len,\n \t\t\t  const unsigned char *bin_pfx,\n-\t\t\t  struct packed_git *p,\n-\t\t\t  const unsigned char **found_sha1,\n-\t\t\t  int seen_so_far)\n+\t\t\t   struct packed_git *p,\n+\t\t\t   struct disambiguate_state *ds)\n {\n \tuint32_t num, last, i, first = 0;\n \tconst unsigned char *current = NULL;\n@@ -113,63 +163,58 @@ static int unique_in_pack(int len,\n \t * with an object name that could match \"bin_pfx\".  See if we have\n \t * 0, 1 or more objects that actually match(es).\n \t */\n-\tfor (i = first; i < num; i++) {\n-\t\tcurrent = nth_packed_object_sha1(p, first);\n+\tfor (i = first; i < num && !ds->ambiguous; i++) {\n+\t\tcurrent = nth_packed_object_sha1(p, i);\n \t\tif (!match_sha(len, bin_pfx, current))\n \t\t\tbreak;\n-\n-\t\t/* current matches */\n-\t\tif (!seen_so_far) {\n-\t\t\t*found_sha1 = current;\n-\t\t\tseen_so_far++;\n-\t\t} else if (seen_so_far) {\n-\t\t\t/* is it the same as the one previously found elsewhere? */\n-\t\t\tif (hashcmp(*found_sha1, current))\n-\t\t\t\treturn 2; /* definitely not unique */\n-\t\t}\n+\t\tupdate_candidates(ds, current);\n \t}\n-\treturn seen_so_far;\n }\n \n-static int find_short_packed_object(int len, const unsigned char *bin_pfx, unsigned char *sha1)\n+static void find_short_packed_object(int len, const unsigned char *bin_pfx,\n+\t\t\t\t     struct disambiguate_state *ds)\n {\n \tstruct packed_git *p;\n-\tconst unsigned char *found_sha1 = NULL;\n-\tint found = 0;\n \n \tprepare_packed_git();\n-\tfor (p = packed_git; p && found < 2; p = p->next)\n-\t\tfound = unique_in_pack(len, bin_pfx, p, &found_sha1, found);\n-\n-\tif (found == 1)\n-\t\thashcpy(sha1, found_sha1);\n-\treturn found;\n+\tfor (p = packed_git; p && !ds->ambiguous; p = p->next)\n+\t\tunique_in_pack(len, bin_pfx, p, ds);\n }\n \n #define SHORT_NAME_NOT_FOUND (-1)\n #define SHORT_NAME_AMBIGUOUS (-2)\n \n-static int find_unique_short_object(int len, char *hex_pfx,\n-\t\t\t\t    unsigned char *bin_pfx, unsigned char *sha1)\n+static int finish_object_disambiguation(struct disambiguate_state *ds,\n+\t\t\t\t\tunsigned char *sha1)\n {\n-\tint has_unpacked, has_packed;\n-\tunsigned char unpacked_sha1[20], packed_sha1[20];\n+\tif (ds->ambiguous)\n+\t\treturn SHORT_NAME_AMBIGUOUS;\n \n-\tprepare_alt_odb();\n-\thas_unpacked = find_short_object_filename(len, hex_pfx, unpacked_sha1);\n-\thas_packed = find_short_packed_object(len, bin_pfx, packed_sha1);\n-\tif (!has_unpacked && !has_packed)\n+\tif (!ds->candidate_exists)\n \t\treturn SHORT_NAME_NOT_FOUND;\n-\tif (1 < has_unpacked || 1 < has_packed)\n-\t\treturn SHORT_NAME_AMBIGUOUS;\n-\tif (has_unpacked != has_packed) {\n-\t\thashcpy(sha1, (has_packed ? packed_sha1 : unpacked_sha1));\n-\t\treturn 0;\n-\t}\n-\t/* Both have unique ones -- do they match? */\n-\tif (hashcmp(packed_sha1, unpacked_sha1))\n-\t\treturn SHORT_NAME_AMBIGUOUS;\n-\thashcpy(sha1, packed_sha1);\n+\n+\tif (!ds->candidate_checked)\n+\t\t/*\n+\t\t * If this is the only candidate, there is no point\n+\t\t * calling the disambiguation hint callback.\n+\t\t *\n+\t\t * On the other hand, if the current candidate\n+\t\t * replaced an earlier candidate that did _not_ pass\n+\t\t * the disambiguation hint callback, then we do have\n+\t\t * more than one objects that match the short name\n+\t\t * given, so we should make sure this one matches;\n+\t\t * otherwise, if we discovered this one and the one\n+\t\t * that we previously discarded in the reverse order,\n+\t\t * we would end up showing different results in the\n+\t\t * same repository!\n+\t\t */\n+\t\tds->candidate_ok = (!ds->disambiguate_fn_used ||\n+\t\t\t\t    ds->fn(ds->candidate, ds->cb_data));\n+\n+\tif (!ds->candidate_ok)\n+\t\treturn SHORT_NAME_NOT_FOUND;\n+\n+\thashcpy(sha1, ds->candidate);\n \treturn 0;\n }\n \n@@ -179,6 +224,7 @@ static int get_short_sha1(const char *name, int len, unsigned char *sha1,\n \tint i, status;\n \tchar hex_pfx[40];\n \tunsigned char bin_pfx[20];\n+\tstruct disambiguate_state ds;\n \n \tif (len < MINIMUM_ABBREV || len > 40)\n \t\treturn -1;\n@@ -203,7 +249,13 @@ static int get_short_sha1(const char *name, int len, unsigned char *sha1,\n \t\tbin_pfx[i >> 1] |= val;\n \t}\n \n-\tstatus = find_unique_short_object(i, hex_pfx, bin_pfx, sha1);\n+\tprepare_alt_odb();\n+\n+\tmemset(&ds, 0, sizeof(ds));\n+\tfind_short_object_filename(len, hex_pfx, &ds);\n+\tfind_short_packed_object(len, bin_pfx, &ds);\n+\tstatus = finish_object_disambiguation(&ds, sha1);\n+\n \tif (!quietly && (status == SHORT_NAME_AMBIGUOUS))\n \t\treturn error(\"short SHA1 %.*s is ambiguous.\", len, hex_pfx);\n \treturn status;\n-- \n1.7.11.1.229.g706c98f\n"},{"id":"194575","messageId":"1341351435-31011-11-git-send-email-gitster@pobox.com","threadId":"30945","inReplyTo":"1341351435-31011-1-git-send-email-gitster@pobox.com","subject":"[PATCH v5 10/25] get_sha1(): fix error status regression","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2012-07-03T21:37:00Z","receivedAt":"2012-07-03T21:37:00Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"In finish_object_disambiguation(), if the candidate hasn't been\nchecked, there are two cases:\n\n - It is the first and only object that match the prefix; or\n - It replaced another object that matched the prefix but that\n   object did not satisfy ds->fn() callback.\n\nAnd the former case we set ds->candidate_ok to true without doing\nanything else, while for the latter we check the candidate, which\nmay set ds->candidate_ok to false.\n\nAt this point in the code, ds->candidate_ok can be false only if\nthis last-round check found that the candidate does not pass the\ncheck, because the state after update_candidates() returns cannot\nsatisfy\n\n    !ds->ambiguous && ds->candidate_exists && ds->candidate_checked\n\nand !ds->canidate_ok at the same time.\n\nHence, when we execute this \"return\", we know we have seen more than\none object that match the prefix (and none of them satisfied ds->fn),\nmeaning that we should say \"the short name is ambiguous\", not \"there\nis no object that matches the prefix\".\n\nNoticed by Jeff King.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n sha1_name.c | 2 +-\n 1 file changed, 1 insertion(+), 1 deletion(-)\n\ndiff --git a/sha1_name.c b/sha1_name.c\nindex 2e2dbb8..c824bdd 100644\n--- a/sha1_name.c\n+++ b/sha1_name.c\n@@ -212,7 +212,7 @@ static int finish_object_disambiguation(struct disambiguate_state *ds,\n \t\t\t\t    ds->fn(ds->candidate, ds->cb_data));\n \n \tif (!ds->candidate_ok)\n-\t\treturn SHORT_NAME_NOT_FOUND;\n+\t\treturn SHORT_NAME_AMBIGUOUS;\n \n \thashcpy(sha1, ds->candidate);\n \treturn 0;\n-- \n1.7.11.1.229.g706c98f\n"},{"id":"194576","messageId":"1341351435-31011-12-git-send-email-gitster@pobox.com","threadId":"30945","inReplyTo":"1341351435-31011-1-git-send-email-gitster@pobox.com","subject":"[PATCH v5 11/25] sha1_name.c: allow get_short_sha1() to take other flags","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2012-07-03T21:37:01Z","receivedAt":"2012-07-03T21:37:01Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Instead of a separate \"int quietly\" argument, make it take \"unsigned\nflags\" so that we can pass other options to it.\n\nThe bit assignment of this flag word is exposed in cache.h because\nthe mechanism will be exposed to callers of the higher layer in\nlater commits in this series.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n cache.h     | 2 ++\n sha1_name.c | 7 ++++---\n 2 files changed, 6 insertions(+), 3 deletions(-)\n\ndiff --git a/cache.h b/cache.h\nindex 2aa9fb6..1bafa45 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -811,6 +811,8 @@ struct object_context {\n \tunsigned mode;\n };\n \n+#define GET_SHA1_QUIETLY 01\n+\n extern int get_sha1(const char *str, unsigned char *sha1);\n extern void maybe_die_on_misspelt_object_name(const char *name, const char *prefix);\n extern int get_sha1_with_context(const char *str, unsigned char *sha1, struct object_context *orc);\ndiff --git a/sha1_name.c b/sha1_name.c\nindex c824bdd..793d80c 100644\n--- a/sha1_name.c\n+++ b/sha1_name.c\n@@ -219,12 +219,13 @@ static int finish_object_disambiguation(struct disambiguate_state *ds,\n }\n \n static int get_short_sha1(const char *name, int len, unsigned char *sha1,\n-\t\t\t  int quietly)\n+\t\t\t  unsigned flags)\n {\n \tint i, status;\n \tchar hex_pfx[40];\n \tunsigned char bin_pfx[20];\n \tstruct disambiguate_state ds;\n+\tint quietly = !!(flags & GET_SHA1_QUIETLY);\n \n \tif (len < MINIMUM_ABBREV || len > 40)\n \t\treturn -1;\n@@ -272,7 +273,7 @@ const char *find_unique_abbrev(const unsigned char *sha1, int len)\n \t\treturn hex;\n \twhile (len < 40) {\n \t\tunsigned char sha1_ret[20];\n-\t\tstatus = get_short_sha1(hex, len, sha1_ret, 1);\n+\t\tstatus = get_short_sha1(hex, len, sha1_ret, GET_SHA1_QUIETLY);\n \t\tif (exists\n \t\t    ? !status\n \t\t    : status == SHORT_NAME_NOT_FOUND) {\n@@ -603,7 +604,7 @@ static int get_describe_name(const char *name, int len, unsigned char *sha1)\n \t\t\tif (ch == 'g' && cp[-1] == '-') {\n \t\t\t\tcp++;\n \t\t\t\tlen -= cp - name;\n-\t\t\t\treturn get_short_sha1(cp, len, sha1, 1);\n+\t\t\t\treturn get_short_sha1(cp, len, sha1, GET_SHA1_QUIETLY);\n \t\t\t}\n \t\t}\n \t}\n-- \n1.7.11.1.229.g706c98f\n"},{"id":"194565","messageId":"1341351435-31011-13-git-send-email-gitster@pobox.com","threadId":"30945","inReplyTo":"1341351435-31011-1-git-send-email-gitster@pobox.com","subject":"[PATCH v5 12/25] sha1_name.c: teach get_short_sha1() a commit-only option","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2012-07-03T21:37:02Z","receivedAt":"2012-07-03T21:37:02Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"When the caller knows that the parameter is meant to name a commit,\ne.g. \"56789a\" in describe name \"v1.2.3-4-g56789a\", pass that as a\nhint so that lower level can use it to disambiguate objects when\nthere is only one commit whose name begins with 56789a even if there\nare objects of other types whose names share the same prefix.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n cache.h     | 1 +\n sha1_name.c | 9 +++++++++\n 2 files changed, 10 insertions(+)\n\ndiff --git a/cache.h b/cache.h\nindex 1bafa45..2d91dbd 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -812,6 +812,7 @@ struct object_context {\n };\n \n #define GET_SHA1_QUIETLY 01\n+#define GET_SHA1_COMMIT 02\n \n extern int get_sha1(const char *str, unsigned char *sha1);\n extern void maybe_die_on_misspelt_object_name(const char *name, const char *prefix);\ndiff --git a/sha1_name.c b/sha1_name.c\nindex 793d80c..174d3df 100644\n--- a/sha1_name.c\n+++ b/sha1_name.c\n@@ -218,6 +218,12 @@ static int finish_object_disambiguation(struct disambiguate_state *ds,\n \treturn 0;\n }\n \n+static int disambiguate_commit_only(const unsigned char *sha1, void *cb_data_unused)\n+{\n+\tint kind = sha1_object_info(sha1, NULL);\n+\treturn kind == OBJ_COMMIT;\n+}\n+\n static int get_short_sha1(const char *name, int len, unsigned char *sha1,\n \t\t\t  unsigned flags)\n {\n@@ -253,6 +259,9 @@ static int get_short_sha1(const char *name, int len, unsigned char *sha1,\n \tprepare_alt_odb();\n \n \tmemset(&ds, 0, sizeof(ds));\n+\tif (flags & GET_SHA1_COMMIT)\n+\t\tds.fn = disambiguate_commit_only;\n+\n \tfind_short_object_filename(len, hex_pfx, &ds);\n \tfind_short_packed_object(len, bin_pfx, &ds);\n \tstatus = finish_object_disambiguation(&ds, sha1);\n-- \n1.7.11.1.229.g706c98f\n"},{"id":"194577","messageId":"1341351435-31011-14-git-send-email-gitster@pobox.com","threadId":"30945","inReplyTo":"1341351435-31011-1-git-send-email-gitster@pobox.com","subject":"[PATCH v5 13/25] sha1_name.c: get_describe_name() by definition groks only commits","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2012-07-03T21:37:03Z","receivedAt":"2012-07-03T21:37:03Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Teach get_describe_name() to pass the disambiguation hint down the\ncallchain to get_short_sha1().\n\nAlso add tests to show various syntactic elements that we could take\nadvantage of the object type information to help disambiguration of\nabbreviated object names.  Many of them are marked as broken, and\nsome of them will be fixed in later patches in this series.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n sha1_name.c                         |   3 +-\n t/t1512-rev-parse-disambiguation.sh | 254 ++++++++++++++++++++++++++++++++++++\n 2 files changed, 256 insertions(+), 1 deletion(-)\n create mode 100755 t/t1512-rev-parse-disambiguation.sh\n\ndiff --git a/sha1_name.c b/sha1_name.c\nindex 174d3df..caef6e5 100644\n--- a/sha1_name.c\n+++ b/sha1_name.c\n@@ -603,6 +603,7 @@ static int peel_onion(const char *name, int len, unsigned char *sha1)\n static int get_describe_name(const char *name, int len, unsigned char *sha1)\n {\n \tconst char *cp;\n+\tunsigned flags = GET_SHA1_QUIETLY | GET_SHA1_COMMIT;\n \n \tfor (cp = name + len - 1; name + 2 <= cp; cp--) {\n \t\tchar ch = *cp;\n@@ -613,7 +614,7 @@ static int get_describe_name(const char *name, int len, unsigned char *sha1)\n \t\t\tif (ch == 'g' && cp[-1] == '-') {\n \t\t\t\tcp++;\n \t\t\t\tlen -= cp - name;\n-\t\t\t\treturn get_short_sha1(cp, len, sha1, GET_SHA1_QUIETLY);\n+\t\t\t\treturn get_short_sha1(cp, len, sha1, flags);\n \t\t\t}\n \t\t}\n \t}\ndiff --git a/t/t1512-rev-parse-disambiguation.sh b/t/t1512-rev-parse-disambiguation.sh\nnew file mode 100755\nindex 0000000..de45468\n--- /dev/null\n+++ b/t/t1512-rev-parse-disambiguation.sh\n@@ -0,0 +1,254 @@\n+#!/bin/sh\n+\n+test_description='object name disambiguation\n+\n+Create blobs, trees, commits and a tag that all share the same\n+prefix, and make sure \"git rev-parse\" can take advantage of\n+type information to disambiguate short object names that are\n+not necessarily unique.\n+\n+The final history used in the test has five commits, with the bottom\n+one tagged as v1.0.0.  They all have one regular file each.\n+\n+  +-------------------------------------------+\n+  |                                           |\n+  |           .-------cs60sb5----- d59np2z    |\n+  |          /                   /            |\n+  |  d8znjge0 ---a2dit76---b4crl15            |\n+  |                                           |\n+  +-------------------------------------------+\n+\n+'\n+\n+. ./test-lib.sh\n+\n+test_expect_success 'blob and tree' '\n+\t(\n+\t\tfor i in 0 1 2 3 4 5 6 7 8 9\n+\t\tdo\n+\t\t\techo $i\n+\t\tdone\n+\t\techo\n+\t\techo cbpkuqa\n+\t) >bz01t33 &&\n+\n+\t# create one blob 1102198254\n+\tgit add bz01t33 &&\n+\n+\t# create one tree 1102198206\n+\tgit write-tree\n+'\n+\n+test_expect_success 'warn ambiguity when no candidate matches type hint' '\n+\ttest_must_fail git rev-parse --verify 11021982^{commit} 2>actual &&\n+\tgrep \"short SHA1 11021982 is ambiguous\" actual\n+'\n+\n+test_expect_failure 'disambiguate tree-ish' '\n+\t# feed tree-ish in an unambiguous way\n+\tgit rev-parse --verify 1102198206:bz01t33 &&\n+\n+\t# ambiguous at the object name level, but there is only one\n+\t# such tree-ish (the other is a blob)\n+\tgit rev-parse --verify 11021982:bz01t33\n+'\n+\n+test_expect_failure 'disambiguate blob' '\n+\tsed -e \"s/|$//\" >patch <<-EOF &&\n+\tdiff --git a/frotz b/frotz\n+\tindex 11021982..11021982 100644\n+\t--- a/frotz\n+\t+++ b/frotz\n+\t@@ -10,3 +10,4 @@\n+\t 9\n+\t |\n+\t cbpkuqa\n+\t+aqukpbc\n+\tEOF\n+\t(\n+\t\tGIT_INDEX_FILE=frotz &&\n+\t\texport GIT_INDEX_FILE &&\n+\t\tgit apply --build-fake-ancestor frotz patch &&\n+\t\tgit cat-file blob :frotz >actual\n+\t) &&\n+\ttest_cmp bz01t33 actual\n+'\n+\n+test_expect_failure 'disambiguate tree' '\n+\tcommit=$(echo \"frotz\" | git commit-tree 11021982) &&\n+\ttest $(git rev-parse $commit^{tree}) = $(git rev-parse 1102198206)\n+'\n+\n+test_expect_success 'first commit' '\n+\t# create one commit 1102198268\n+\ttest_tick &&\n+\tgit commit -m d8znjge0\n+'\n+\n+test_expect_failure 'disambiguate commit-ish' '\n+\t# feed commit-ish in an unambiguous way\n+\tgit rev-parse --verify 1102198268^{commit} &&\n+\n+\t# ambiguous at the object name level, but there is only one\n+\t# such commit (the others are tree and blob)\n+\tgit rev-parse --verify 11021982^{commit} &&\n+\n+\t# likewise\n+\tgit rev-parse --verify 11021982^0\n+'\n+\n+test_expect_failure 'disambiguate commit' '\n+\tcommit=$(echo \"frotz\" | git commit-tree 11021982 -p 11021982) &&\n+\ttest $(git rev-parse $commit^) = $(git rev-parse 1102198268)\n+'\n+\n+test_expect_failure 'log name1..name2 takes only commit-ishes on both ends' '\n+\tgit log 11021982..11021982 &&\n+\tgit log ..11021982 &&\n+\tgit log 11021982.. &&\n+\tgit log 11021982...11021982 &&\n+\tgit log ...11021982 &&\n+\tgit log 11021982...\n+'\n+\n+test_expect_failure 'rev-parse name1..name2 takes only commit-ishes on both ends' '\n+\tgit rev-parse 11021982..11021982 &&\n+\tgit rev-parse ..11021982 &&\n+\tgit rev-parse 11021982..\n+'\n+\n+test_expect_failure 'git log takes only commit-ish' '\n+\tgit log 11021982\n+'\n+\n+test_expect_failure 'git reset takes only commit-ish' '\n+\tgit reset 11021982\n+'\n+\n+test_expect_success 'first tag' '\n+\t# create one tag 1102198256\n+\tgit tag -a -m d3g97ek v1.0.0\n+'\n+\n+test_expect_failure 'two semi-ambiguous commit-ish' '\n+\t# Once the parser becomes ultra-smart, it could notice that\n+\t# 110282 before ^{commit} name many different objects, but\n+\t# that only two (HEAD and v1.0.0 tag) can be peeled to commit,\n+\t# and that peeling them down to commit yield the same commit\n+\t# without ambiguity.\n+\tgit rev-parse --verify 110282^{commit} &&\n+\n+\t# likewise\n+\tgit log 11021982..11021982 &&\n+\tgit log ..11021982 &&\n+\tgit log 11021982.. &&\n+\tgit log 11021982...11021982 &&\n+\tgit log ...11021982 &&\n+\tgit log 11021982...\n+'\n+\n+test_expect_failure 'three semi-ambiguous tree-ish' '\n+\t# Likewise for tree-ish.  HEAD, v1.0.0 and HEAD^{tree} share\n+\t# the prefix but peeling them to tree yields the same thing\n+\tgit rev-parse --verify 110282^{tree}\n+'\n+\n+test_expect_success 'parse describe name' '\n+\t# feed an unambiguous describe name\n+\tgit rev-parse --verify v1.0.0-0-g1102198268 &&\n+\n+\t# ambiguous at the object name level, but there is only one\n+\t# such commit (others are blob, tree and tag)\n+\tgit rev-parse --verify v1.0.0-0-g11021982\n+'\n+\n+test_expect_success 'more history' '\n+\t# commit 110219822\n+\tgit mv bz01t33 b90au8x &&\n+\techo bdc8xi8 >>b90au8x &&\n+\tgit add b90au8x &&\n+\n+\ttest_tick &&\n+\tgit commit -m a2dit76 &&\n+\n+\t# commit 110219828\n+\tgit mv b90au8x djintr2 &&\n+\techo a2a49zt >>djintr2 &&\n+\tgit add djintr2 &&\n+\n+\ttest_tick &&\n+\tgit commit -m b4crl15 &&\n+\n+\t# commit 11021982d\n+\tgit checkout v1.0.0^0 &&\n+\tgit mv bz01t33 ddp2qt1 &&\n+\n+\tfor i in bdc8xi8 a2a49zt c0l9aeu\n+\tdo\n+\t\techo $i\n+\tdone >>ddp2qt1 &&\n+\tgit add ddp2qt1 &&\n+\n+\ttest_tick &&\n+\tgit commit -m cs60sb5 &&\n+\tside=$(git rev-parse HEAD) &&\n+\n+\t# commit 11021982a\n+\tgit checkout master &&\n+\n+\t# If you use recursive, merge will fail and you will need to\n+\t# clean up bz01t33 as well.  If you use resolve, merge will\n+\t# succeed.\n+\ttest_might_fail git merge --no-commit -s resolve $side &&\n+\tgit rm -f ddp2qt1 djintr2 &&\n+\ttest_might_fail git rm -f bz01t33 &&\n+\t(\n+\t\tgit cat-file blob $side:ddp2qt1\n+\t\techo d4o8f4f\n+\t) >c3q9963 &&\n+\tgit add c3q9963 &&\n+\n+\ttest_tick &&\n+\tgit commit -m d59np2z\n+\n+'\n+\n+test_expect_failure 'parse describe name taking advantage of generation' '\n+\t# ambiguous at the object name level, but there is only one\n+\t# such commit at generation 0\n+\tgit rev-parse --verify v1.0.0-0-g11021982 &&\n+\n+\t# likewise for generation 2 and 4\n+\tgit rev-parse --verify v1.0.0-2-g11021982 &&\n+\tgit rev-parse --verify v1.0.0-4-g11021982\n+'\n+\n+# Note: because rev-parse does not even try to disambiguate based on\n+# the generation number, this test currently succeeds for a wrong\n+# reason.  When it learns to use the generation number, the previous\n+# test should succeed, and also this test should fail because the\n+# describe name used in the test with generation number can name two\n+# commits.  Make sure that such a future enhancement does not randomly\n+# pick one.\n+test_expect_success 'parse describe name not ignoring ambiguity' '\n+\t# ambiguous at the object name level, and there are two such\n+\t# commits at generation 1\n+\ttest_must_fail git rev-parse --verify v1.0.0-1-g11021982\n+'\n+\n+test_expect_success 'ambiguous commit-ish' '\n+\t# Now there are many commits that begin with the\n+\t# common prefix, none of these should pick one at\n+\t# random.  They all should result in ambiguity errors.\n+\ttest_must_fail git rev-parse --verify 110282^{commit} &&\n+\n+\t# likewise\n+\ttest_must_fail git log 11021982..11021982 &&\n+\ttest_must_fail git log ..11021982 &&\n+\ttest_must_fail git log 11021982.. &&\n+\ttest_must_fail git log 11021982...11021982 &&\n+\ttest_must_fail git log ...11021982 &&\n+\ttest_must_fail git log 11021982...\n+'\n+\n+test_done\n-- \n1.7.11.1.229.g706c98f\n"},{"id":"194573","messageId":"1341351435-31011-15-git-send-email-gitster@pobox.com","threadId":"30945","inReplyTo":"1341351435-31011-1-git-send-email-gitster@pobox.com","subject":"[PATCH v5 14/25] sha1_name.c: get_sha1_1() takes lookup flags","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2012-07-03T21:37:04Z","receivedAt":"2012-07-03T21:37:04Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"This is to pass the disambiguation hints from the caller down the\ncallchain.  Nothing is changed in this step, as everybody just\npasses 0 in the flag.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n sha1_name.c | 16 ++++++++--------\n 1 file changed, 8 insertions(+), 8 deletions(-)\n\ndiff --git a/sha1_name.c b/sha1_name.c\nindex caef6e5..8feb9b5 100644\n--- a/sha1_name.c\n+++ b/sha1_name.c\n@@ -333,7 +333,7 @@ static inline int upstream_mark(const char *string, int len)\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, unsigned lookup_flags);\n \n static int get_sha1_basic(const char *str, int len, unsigned char *sha1)\n {\n@@ -370,7 +370,7 @@ static int get_sha1_basic(const char *str, int len, unsigned char *sha1)\n \t\tret = interpret_branch_name(str+at, &buf);\n \t\tif (ret > 0) {\n \t\t\t/* substitute this branch name and restart */\n-\t\t\treturn get_sha1_1(buf.buf, buf.len, sha1);\n+\t\t\treturn get_sha1_1(buf.buf, buf.len, sha1, 0);\n \t\t} else if (ret == 0) {\n \t\t\treturn -1;\n \t\t}\n@@ -440,7 +440,7 @@ 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, 0);\n \tstruct commit *commit;\n \tstruct commit_list *p;\n \n@@ -473,7 +473,7 @@ static int get_nth_ancestor(const char *name, int len,\n \tstruct commit *commit;\n \tint ret;\n \n-\tret = get_sha1_1(name, len, sha1);\n+\tret = get_sha1_1(name, len, sha1, 0);\n \tif (ret)\n \t\treturn ret;\n \tcommit = lookup_commit_reference(sha1);\n@@ -554,7 +554,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, 0))\n \t\treturn -1;\n \n \to = parse_object(outer);\n@@ -621,7 +621,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, unsigned lookup_flags)\n {\n \tint ret, has_suffix;\n \tconst char *cp;\n@@ -1098,7 +1098,7 @@ static int get_sha1_with_context_1(const char *name, unsigned char *sha1,\n \n \tmemset(oc, 0, sizeof(*oc));\n \toc->mode = S_IFINVALID;\n-\tret = get_sha1_1(name, namelen, sha1);\n+\tret = get_sha1_1(name, namelen, sha1, 0);\n \tif (!ret)\n \t\treturn ret;\n \t/* sha1:path --> object name of path in ent sha1\n@@ -1176,7 +1176,7 @@ static int get_sha1_with_context_1(const char *name, unsigned char *sha1,\n \t\t\tstrncpy(object_name, name, cp-name);\n \t\t\tobject_name[cp-name] = '\\0';\n \t\t}\n-\t\tif (!get_sha1_1(name, cp-name, tree_sha1)) {\n+\t\tif (!get_sha1_1(name, cp-name, tree_sha1, 0)) {\n \t\t\tconst char *filename = cp+1;\n \t\t\tchar *new_filename = NULL;\n \n-- \n1.7.11.1.229.g706c98f\n"},{"id":"194570","messageId":"1341351435-31011-16-git-send-email-gitster@pobox.com","threadId":"30945","inReplyTo":"1341351435-31011-1-git-send-email-gitster@pobox.com","subject":"[PATCH v5 15/25] sha1_name.c: many short names can only be committish","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2012-07-03T21:37:05Z","receivedAt":"2012-07-03T21:37:05Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"We know that the token \"$name\" that appear in \"$name^{commit}\",\n\"$name^4\", \"$name~4\" etc. can only name a committish (either a\ncommit or a tag that peels to a commit).  Teach get_short_sha1() to\ntake advantage of that knowledge when disambiguating an abbreviated\nSHA-1 given as an object name.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n cache.h                             |  1 +\n sha1_name.c                         | 32 ++++++++++++++++++++++++++++----\n t/t1512-rev-parse-disambiguation.sh |  2 +-\n 3 files changed, 30 insertions(+), 5 deletions(-)\n\ndiff --git a/cache.h b/cache.h\nindex 2d91dbd..1508fdb 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -813,6 +813,7 @@ struct object_context {\n \n #define GET_SHA1_QUIETLY 01\n #define GET_SHA1_COMMIT 02\n+#define GET_SHA1_COMMITTISH 04\n \n extern int get_sha1(const char *str, unsigned char *sha1);\n extern void maybe_die_on_misspelt_object_name(const char *name, const char *prefix);\ndiff --git a/sha1_name.c b/sha1_name.c\nindex 8feb9b5..215bb01 100644\n--- a/sha1_name.c\n+++ b/sha1_name.c\n@@ -224,6 +224,24 @@ static int disambiguate_commit_only(const unsigned char *sha1, void *cb_data_unu\n \treturn kind == OBJ_COMMIT;\n }\n \n+static int disambiguate_committish_only(const unsigned char *sha1, void *cb_data_unused)\n+{\n+\tstruct object *obj;\n+\tint kind;\n+\n+\tkind = sha1_object_info(sha1, NULL);\n+\tif (kind == OBJ_COMMIT)\n+\t\treturn 1;\n+\tif (kind != OBJ_TAG)\n+\t\treturn 0;\n+\n+\t/* We need to do this the hard way... */\n+\tobj = deref_tag(lookup_object(sha1), NULL, 0);\n+\tif (obj && obj->type == OBJ_COMMIT)\n+\t\treturn 1;\n+\treturn 0;\n+}\n+\n static int get_short_sha1(const char *name, int len, unsigned char *sha1,\n \t\t\t  unsigned flags)\n {\n@@ -261,6 +279,8 @@ static int get_short_sha1(const char *name, int len, unsigned char *sha1,\n \tmemset(&ds, 0, sizeof(ds));\n \tif (flags & GET_SHA1_COMMIT)\n \t\tds.fn = disambiguate_commit_only;\n+\telse if (flags & GET_SHA1_COMMITTISH)\n+\t\tds.fn = disambiguate_committish_only;\n \n \tfind_short_object_filename(len, hex_pfx, &ds);\n \tfind_short_packed_object(len, bin_pfx, &ds);\n@@ -440,7 +460,7 @@ 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, 0);\n+\tint ret = get_sha1_1(name, len, sha1, GET_SHA1_COMMITTISH);\n \tstruct commit *commit;\n \tstruct commit_list *p;\n \n@@ -473,7 +493,7 @@ static int get_nth_ancestor(const char *name, int len,\n \tstruct commit *commit;\n \tint ret;\n \n-\tret = get_sha1_1(name, len, sha1, 0);\n+\tret = get_sha1_1(name, len, sha1, GET_SHA1_COMMITTISH);\n \tif (ret)\n \t\treturn ret;\n \tcommit = lookup_commit_reference(sha1);\n@@ -519,6 +539,7 @@ static int peel_onion(const char *name, int len, unsigned char *sha1)\n \tunsigned char outer[20];\n \tconst char *sp;\n \tunsigned int expected_type = 0;\n+\tunsigned lookup_flags = 0;\n \tstruct object *o;\n \n \t/*\n@@ -554,7 +575,10 @@ 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, 0))\n+\tif (expected_type == OBJ_COMMIT)\n+\t\tlookup_flags = GET_SHA1_COMMITTISH;\n+\n+\tif (get_sha1_1(name, sp - name - 2, outer, lookup_flags))\n \t\treturn -1;\n \n \to = parse_object(outer);\n@@ -666,7 +690,7 @@ static int get_sha1_1(const char *name, int len, unsigned char *sha1, unsigned l\n \tif (!ret)\n \t\treturn 0;\n \n-\treturn get_short_sha1(name, len, sha1, 0);\n+\treturn get_short_sha1(name, len, sha1, lookup_flags);\n }\n \n /*\ndiff --git a/t/t1512-rev-parse-disambiguation.sh b/t/t1512-rev-parse-disambiguation.sh\nindex de45468..1a736b0 100755\n--- a/t/t1512-rev-parse-disambiguation.sh\n+++ b/t/t1512-rev-parse-disambiguation.sh\n@@ -85,7 +85,7 @@ test_expect_success 'first commit' '\n \tgit commit -m d8znjge0\n '\n \n-test_expect_failure 'disambiguate commit-ish' '\n+test_expect_success 'disambiguate commit-ish' '\n \t# feed commit-ish in an unambiguous way\n \tgit rev-parse --verify 1102198268^{commit} &&\n \n-- \n1.7.11.1.229.g706c98f\n"},{"id":"194571","messageId":"1341351435-31011-17-git-send-email-gitster@pobox.com","threadId":"30945","inReplyTo":"1341351435-31011-1-git-send-email-gitster@pobox.com","subject":"[PATCH v5 16/25] sha1_name.c: teach lookup context to get_sha1_with_context()","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2012-07-03T21:37:06Z","receivedAt":"2012-07-03T21:37:06Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"The function takes user input string and returns the object name\n(binary SHA-1) with mode bits and path when the object was looked\nup in a tree.\n\nAdditionally give hints to help disambiguation of abbreviated object\nnames when the caller knows what it is looking for.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/cat-file.c |  2 +-\n cache.h            |  3 ++-\n revision.c         |  4 ++--\n sha1_name.c        | 22 +++++++++++++---------\n 4 files changed, 18 insertions(+), 13 deletions(-)\n\ndiff --git a/builtin/cat-file.c b/builtin/cat-file.c\nindex 07bd984..c27268f 100644\n--- a/builtin/cat-file.c\n+++ b/builtin/cat-file.c\n@@ -90,7 +90,7 @@ static int cat_one_file(int opt, const char *exp_type, const char *obj_name)\n \tunsigned long size;\n \tstruct object_context obj_context;\n \n-\tif (get_sha1_with_context(obj_name, sha1, &obj_context))\n+\tif (get_sha1_with_context(obj_name, 0, sha1, &obj_context))\n \t\tdie(\"Not a valid object name %s\", obj_name);\n \n \tbuf = NULL;\ndiff --git a/cache.h b/cache.h\nindex 1508fdb..e1fa63b 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -814,10 +814,11 @@ struct object_context {\n #define GET_SHA1_QUIETLY 01\n #define GET_SHA1_COMMIT 02\n #define GET_SHA1_COMMITTISH 04\n+#define GET_SHA1_ONLY_TO_DIE 04000\n \n extern int get_sha1(const char *str, unsigned char *sha1);\n extern void maybe_die_on_misspelt_object_name(const char *name, const char *prefix);\n-extern int get_sha1_with_context(const char *str, unsigned char *sha1, struct object_context *orc);\n+extern int get_sha1_with_context(const char *str, unsigned flags, unsigned char *sha1, struct object_context *orc);\n \n /*\n  * Try to read a SHA1 in hexadecimal format from the 40 characters\ndiff --git a/revision.c b/revision.c\nindex 86a14c8..7444f2e 100644\n--- a/revision.c\n+++ b/revision.c\n@@ -1180,7 +1180,7 @@ int handle_revision_arg(const char *arg_, struct rev_info *revs,\n \t\tlocal_flags = UNINTERESTING;\n \t\targ++;\n \t}\n-\tif (get_sha1_with_context(arg, sha1, &oc))\n+\tif (get_sha1_with_context(arg, 0, sha1, &oc))\n \t\treturn revs->ignore_missing ? 0 : -1;\n \tif (!cant_be_filename)\n \t\tverify_non_filename(revs->prefix, arg);\n@@ -1795,7 +1795,7 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, struct s\n \t\tunsigned char sha1[20];\n \t\tstruct object *object;\n \t\tstruct object_context oc;\n-\t\tif (get_sha1_with_context(revs->def, sha1, &oc))\n+\t\tif (get_sha1_with_context(revs->def, 0, sha1, &oc))\n \t\t\tdie(\"bad default revision '%s'\", revs->def);\n \t\tobject = get_reference(revs, revs->def, sha1, 0);\n \t\tadd_pending_object_with_mode(revs, object, revs->def, oc.mode);\ndiff --git a/sha1_name.c b/sha1_name.c\nindex 215bb01..c045be8 100644\n--- a/sha1_name.c\n+++ b/sha1_name.c\n@@ -996,7 +996,7 @@ int strbuf_check_branch_ref(struct strbuf *sb, const char *name)\n int get_sha1(const char *name, unsigned char *sha1)\n {\n \tstruct object_context unused;\n-\treturn get_sha1_with_context(name, sha1, &unused);\n+\treturn get_sha1_with_context(name, 0, sha1, &unused);\n }\n \n /* Must be called only when object_name:filename doesn't exist. */\n@@ -1112,20 +1112,24 @@ static char *resolve_relative_path(const char *rel)\n \t\t\t   rel);\n }\n \n-static int get_sha1_with_context_1(const char *name, unsigned char *sha1,\n-\t\t\t\t   struct object_context *oc,\n-\t\t\t\t   int only_to_die, const char *prefix)\n+static int get_sha1_with_context_1(const char *name,\n+\t\t\t\t   unsigned flags,\n+\t\t\t\t   const char *prefix,\n+\t\t\t\t   unsigned char *sha1,\n+\t\t\t\t   struct object_context *oc)\n {\n \tint ret, bracket_depth;\n \tint namelen = strlen(name);\n \tconst char *cp;\n+\tint only_to_die = flags & GET_SHA1_ONLY_TO_DIE;\n \n \tmemset(oc, 0, sizeof(*oc));\n \toc->mode = S_IFINVALID;\n-\tret = get_sha1_1(name, namelen, sha1, 0);\n+\tret = get_sha1_1(name, namelen, sha1, flags);\n \tif (!ret)\n \t\treturn ret;\n-\t/* sha1:path --> object name of path in ent sha1\n+\t/*\n+\t * sha1:path --> object name of path in ent sha1\n \t * :path -> object name of absolute path in index\n \t * :./path -> object name of path relative to cwd in index\n \t * :[0-3]:path -> object name of path in index at stage\n@@ -1239,10 +1243,10 @@ void maybe_die_on_misspelt_object_name(const char *name, const char *prefix)\n {\n \tstruct object_context oc;\n \tunsigned char sha1[20];\n-\tget_sha1_with_context_1(name, sha1, &oc, 1, prefix);\n+\tget_sha1_with_context_1(name, GET_SHA1_ONLY_TO_DIE, prefix, sha1, &oc);\n }\n \n-int get_sha1_with_context(const char *str, unsigned char *sha1, struct object_context *orc)\n+int get_sha1_with_context(const char *str, unsigned flags, unsigned char *sha1, struct object_context *orc)\n {\n-\treturn get_sha1_with_context_1(str, sha1, orc, 0, NULL);\n+\treturn get_sha1_with_context_1(str, flags, NULL, sha1, orc);\n }\n-- \n1.7.11.1.229.g706c98f\n"},{"id":"194572","messageId":"1341351435-31011-18-git-send-email-gitster@pobox.com","threadId":"30945","inReplyTo":"1341351435-31011-1-git-send-email-gitster@pobox.com","subject":"[PATCH v5 17/25] sha1_name.c: introduce get_sha1_committish()","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2012-07-03T21:37:07Z","receivedAt":"2012-07-03T21:37:07Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Many callers know that the user meant to name a committish by\nsyntactical positions where the object name appears.  Calling this\nfunction allows the machinery to disambiguate shorter-than-unique\nabbreviated object names between committish and others.\n\nNote that this does NOT error out when the named object is not a\ncommittish. It is merely to give a hint to the disambiguation\nmachinery.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n cache.h                             |  1 +\n commit.c                            |  2 +-\n revision.c                          |  6 +++---\n sha1_name.c                         | 21 +++++++++++++++++++--\n t/t1512-rev-parse-disambiguation.sh |  2 +-\n 5 files changed, 25 insertions(+), 7 deletions(-)\n\ndiff --git a/cache.h b/cache.h\nindex e1fa63b..e947b48 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -817,6 +817,7 @@ struct object_context {\n #define GET_SHA1_ONLY_TO_DIE 04000\n \n extern int get_sha1(const char *str, unsigned char *sha1);\n+extern int get_sha1_committish(const char *str, unsigned char *sha1);\n extern void maybe_die_on_misspelt_object_name(const char *name, const char *prefix);\n extern int get_sha1_with_context(const char *str, unsigned flags, unsigned char *sha1, struct object_context *orc);\n \ndiff --git a/commit.c b/commit.c\nindex 35af498..8b84eff 100644\n--- a/commit.c\n+++ b/commit.c\n@@ -67,7 +67,7 @@ struct commit *lookup_commit_reference_by_name(const char *name)\n \tunsigned char sha1[20];\n \tstruct commit *commit;\n \n-\tif (get_sha1(name, sha1))\n+\tif (get_sha1_committish(name, sha1))\n \t\treturn NULL;\n \tcommit = lookup_commit_reference(sha1);\n \tif (!commit || parse_commit(commit))\ndiff --git a/revision.c b/revision.c\nindex 7444f2e..c3160f2 100644\n--- a/revision.c\n+++ b/revision.c\n@@ -979,7 +979,7 @@ static int add_parents_only(struct rev_info *revs, const char *arg_, int flags)\n \t\tflags ^= UNINTERESTING;\n \t\targ++;\n \t}\n-\tif (get_sha1(arg, sha1))\n+\tif (get_sha1_committish(arg, sha1))\n \t\treturn 0;\n \twhile (1) {\n \t\tit = get_reference(revs, arg, sha1, 0);\n@@ -1120,8 +1120,8 @@ int handle_revision_arg(const char *arg_, struct rev_info *revs,\n \t\t\tnext = \"HEAD\";\n \t\tif (dotdot == arg)\n \t\t\tthis = \"HEAD\";\n-\t\tif (!get_sha1(this, from_sha1) &&\n-\t\t    !get_sha1(next, sha1)) {\n+\t\tif (!get_sha1_committish(this, from_sha1) &&\n+\t\t    !get_sha1_committish(next, sha1)) {\n \t\t\tstruct commit *a, *b;\n \t\t\tstruct commit_list *exclude;\n \ndiff --git a/sha1_name.c b/sha1_name.c\nindex c045be8..9e13d60 100644\n--- a/sha1_name.c\n+++ b/sha1_name.c\n@@ -872,7 +872,7 @@ int get_sha1_mb(const char *name, unsigned char *sha1)\n \t\tstruct strbuf sb;\n \t\tstrbuf_init(&sb, dots - name);\n \t\tstrbuf_add(&sb, name, dots - name);\n-\t\tst = get_sha1(sb.buf, sha1_tmp);\n+\t\tst = get_sha1_committish(sb.buf, sha1_tmp);\n \t\tstrbuf_release(&sb);\n \t}\n \tif (st)\n@@ -881,7 +881,7 @@ int get_sha1_mb(const char *name, unsigned char *sha1)\n \tif (!one)\n \t\treturn -1;\n \n-\tif (get_sha1(dots[3] ? (dots + 3) : \"HEAD\", sha1_tmp))\n+\tif (get_sha1_committish(dots[3] ? (dots + 3) : \"HEAD\", sha1_tmp))\n \t\treturn -1;\n \ttwo = lookup_commit_reference_gently(sha1_tmp, 0);\n \tif (!two)\n@@ -999,6 +999,23 @@ int get_sha1(const char *name, unsigned char *sha1)\n \treturn get_sha1_with_context(name, 0, sha1, &unused);\n }\n \n+/*\n+ * Many callers know that the user meant to name a committish by\n+ * syntactical positions where the object name appears.  Calling this\n+ * function allows the machinery to disambiguate shorter-than-unique\n+ * abbreviated object names between committish and others.\n+ *\n+ * Note that this does NOT error out when the named object is not a\n+ * committish. It is merely to give a hint to the disambiguation\n+ * machinery.\n+ */\n+int get_sha1_committish(const char *name, unsigned char *sha1)\n+{\n+\tstruct object_context unused;\n+\treturn get_sha1_with_context(name, GET_SHA1_COMMITTISH,\n+\t\t\t\t     sha1, &unused);\n+}\n+\n /* Must be called only when object_name:filename doesn't exist. */\n static void diagnose_invalid_sha1_path(const char *prefix,\n \t\t\t\t       const char *filename,\ndiff --git a/t/t1512-rev-parse-disambiguation.sh b/t/t1512-rev-parse-disambiguation.sh\nindex 1a736b0..7c92451 100755\n--- a/t/t1512-rev-parse-disambiguation.sh\n+++ b/t/t1512-rev-parse-disambiguation.sh\n@@ -102,7 +102,7 @@ test_expect_failure 'disambiguate commit' '\n \ttest $(git rev-parse $commit^) = $(git rev-parse 1102198268)\n '\n \n-test_expect_failure 'log name1..name2 takes only commit-ishes on both ends' '\n+test_expect_success 'log name1..name2 takes only commit-ishes on both ends' '\n \tgit log 11021982..11021982 &&\n \tgit log ..11021982 &&\n \tgit log 11021982.. &&\n-- \n1.7.11.1.229.g706c98f\n"},{"id":"194566","messageId":"1341351435-31011-19-git-send-email-gitster@pobox.com","threadId":"30945","inReplyTo":"1341351435-31011-1-git-send-email-gitster@pobox.com","subject":"[PATCH v5 18/25] revision.c: allow handle_revision_arg() to take other flags","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2012-07-03T21:37:08Z","receivedAt":"2012-07-03T21:37:08Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"The existing \"cant_be_filename\" that tells the function that the\ncaller knows the arg is not a path (hence it does not have to be\nchecked for absense of the file whose name matches it) is made into\na bit in the flag word.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/pack-objects.c |  2 +-\n revision.c             | 13 +++++++------\n revision.h             |  3 ++-\n 3 files changed, 10 insertions(+), 8 deletions(-)\n\ndiff --git a/builtin/pack-objects.c b/builtin/pack-objects.c\nindex 0f2e7b8..48ccadd 100644\n--- a/builtin/pack-objects.c\n+++ b/builtin/pack-objects.c\n@@ -2290,7 +2290,7 @@ static void get_object_list(int ac, const char **av)\n \t\t\t}\n \t\t\tdie(\"not a rev '%s'\", line);\n \t\t}\n-\t\tif (handle_revision_arg(line, &revs, flags, 1))\n+\t\tif (handle_revision_arg(line, &revs, flags, REVARG_CANNOT_BE_FILENAME))\n \t\t\tdie(\"bad revision '%s'\", line);\n \t}\n \ndiff --git a/revision.c b/revision.c\nindex c3160f2..929497f 100644\n--- a/revision.c\n+++ b/revision.c\n@@ -1093,9 +1093,7 @@ static void prepare_show_merge(struct rev_info *revs)\n \trevs->limited = 1;\n }\n \n-int handle_revision_arg(const char *arg_, struct rev_info *revs,\n-\t\t\tint flags,\n-\t\t\tint cant_be_filename)\n+int handle_revision_arg(const char *arg_, struct rev_info *revs, int flags, unsigned revarg_opt)\n {\n \tstruct object_context oc;\n \tchar *dotdot;\n@@ -1103,6 +1101,7 @@ int handle_revision_arg(const char *arg_, struct rev_info *revs,\n \tunsigned char sha1[20];\n \tint local_flags;\n \tconst char *arg = arg_;\n+\tint cant_be_filename = revarg_opt & REVARG_CANNOT_BE_FILENAME;\n \n \tdotdot = strstr(arg, \"..\");\n \tif (dotdot) {\n@@ -1236,7 +1235,7 @@ static void read_revisions_from_stdin(struct rev_info *revs,\n \t\t\t}\n \t\t\tdie(\"options not supported in --stdin mode\");\n \t\t}\n-\t\tif (handle_revision_arg(sb.buf, revs, 0, 1))\n+\t\tif (handle_revision_arg(sb.buf, revs, 0, REVARG_CANNOT_BE_FILENAME))\n \t\t\tdie(\"bad revision '%s'\", sb.buf);\n \t}\n \tif (seen_dashdash)\n@@ -1684,7 +1683,7 @@ static int handle_revision_pseudo_opt(const char *submodule,\n  */\n int setup_revisions(int argc, const char **argv, struct rev_info *revs, struct setup_revision_opt *opt)\n {\n-\tint i, flags, left, seen_dashdash, read_from_stdin, got_rev_arg = 0;\n+\tint i, flags, left, seen_dashdash, read_from_stdin, got_rev_arg = 0, revarg_opt;\n \tstruct cmdline_pathspec prune_data;\n \tconst char *submodule = NULL;\n \n@@ -1708,6 +1707,7 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, struct s\n \n \t/* Second, deal with arguments and options */\n \tflags = 0;\n+\trevarg_opt = seen_dashdash ? REVARG_CANNOT_BE_FILENAME : 0;\n \tread_from_stdin = 0;\n \tfor (left = i = 1; i < argc; i++) {\n \t\tconst char *arg = argv[i];\n@@ -1743,7 +1743,8 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, struct s\n \t\t\tcontinue;\n \t\t}\n \n-\t\tif (handle_revision_arg(arg, revs, flags, seen_dashdash)) {\n+\n+\t\tif (handle_revision_arg(arg, revs, flags, revarg_opt)) {\n \t\t\tint j;\n \t\t\tif (seen_dashdash || *arg == '^')\n \t\t\t\tdie(\"bad revision '%s'\", arg);\ndiff --git a/revision.h b/revision.h\nindex b8e9223..8eceaec 100644\n--- a/revision.h\n+++ b/revision.h\n@@ -190,7 +190,8 @@ extern int setup_revisions(int argc, const char **argv, struct rev_info *revs, s\n extern void parse_revision_opt(struct rev_info *revs, struct parse_opt_ctx_t *ctx,\n \t\t\t\t const struct option *options,\n \t\t\t\t const char * const usagestr[]);\n-extern int handle_revision_arg(const char *arg, struct rev_info *revs,int flags,int cant_be_filename);\n+#define REVARG_CANNOT_BE_FILENAME 01\n+extern int handle_revision_arg(const char *arg, struct rev_info *revs, int flags, unsigned revarg_opt);\n \n extern int prepare_revision_walk(struct rev_info *revs);\n extern struct commit *get_revision(struct rev_info *revs);\n-- \n1.7.11.1.229.g706c98f\n"},{"id":"194574","messageId":"1341351435-31011-20-git-send-email-gitster@pobox.com","threadId":"30945","inReplyTo":"1341351435-31011-1-git-send-email-gitster@pobox.com","subject":"[PATCH v5 19/25] revision.c: the \"log\" family, except for \"show\", takes committish","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2012-07-03T21:37:09Z","receivedAt":"2012-07-03T21:37:09Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Add a field to setup_revision_opt structure and allow these callers\nto tell the setup_revisions command parsing machinery that short SHA1\nit encounters are meant to name committish.\n\nThis step does not go all the way to connect the setup_revisions()\nto sha1_name.c yet.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/log.c                       |  3 +++\n revision.c                          | 11 +++++++++--\n revision.h                          |  2 ++\n t/t1512-rev-parse-disambiguation.sh |  2 +-\n 4 files changed, 15 insertions(+), 3 deletions(-)\n\ndiff --git a/builtin/log.c b/builtin/log.c\nindex 7d1f6f8..9363f39 100644\n--- a/builtin/log.c\n+++ b/builtin/log.c\n@@ -363,6 +363,7 @@ int cmd_whatchanged(int argc, const char **argv, const char *prefix)\n \trev.simplify_history = 0;\n \tmemset(&opt, 0, sizeof(opt));\n \topt.def = \"HEAD\";\n+\topt.revarg_opt = REVARG_COMMITTISH;\n \tcmd_log_init(argc, argv, prefix, &rev, &opt);\n \tif (!rev.diffopt.output_format)\n \t\trev.diffopt.output_format = DIFF_FORMAT_RAW;\n@@ -543,6 +544,7 @@ int cmd_log(int argc, const char **argv, const char *prefix)\n \trev.always_show_header = 1;\n \tmemset(&opt, 0, sizeof(opt));\n \topt.def = \"HEAD\";\n+\topt.revarg_opt = REVARG_COMMITTISH;\n \tcmd_log_init(argc, argv, prefix, &rev, &opt);\n \treturn cmd_log_walk(&rev);\n }\n@@ -1144,6 +1146,7 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)\n \trev.subject_prefix = fmt_patch_subject_prefix;\n \tmemset(&s_r_opt, 0, sizeof(s_r_opt));\n \ts_r_opt.def = \"HEAD\";\n+\ts_r_opt.revarg_opt = REVARG_COMMITTISH;\n \n \tif (default_attach) {\n \t\trev.mime_boundary = default_attach;\ndiff --git a/revision.c b/revision.c\nindex 929497f..ec6f0c8 100644\n--- a/revision.c\n+++ b/revision.c\n@@ -1102,6 +1102,7 @@ int handle_revision_arg(const char *arg_, struct rev_info *revs, int flags, unsi\n \tint local_flags;\n \tconst char *arg = arg_;\n \tint cant_be_filename = revarg_opt & REVARG_CANNOT_BE_FILENAME;\n+\tunsigned get_sha1_flags = 0;\n \n \tdotdot = strstr(arg, \"..\");\n \tif (dotdot) {\n@@ -1179,7 +1180,11 @@ int handle_revision_arg(const char *arg_, struct rev_info *revs, int flags, unsi\n \t\tlocal_flags = UNINTERESTING;\n \t\targ++;\n \t}\n-\tif (get_sha1_with_context(arg, 0, sha1, &oc))\n+\n+\tif (revarg_opt & REVARG_COMMITTISH)\n+\t\tget_sha1_flags = GET_SHA1_COMMITTISH;\n+\n+\tif (get_sha1_with_context(arg, get_sha1_flags, sha1, &oc))\n \t\treturn revs->ignore_missing ? 0 : -1;\n \tif (!cant_be_filename)\n \t\tverify_non_filename(revs->prefix, arg);\n@@ -1707,7 +1712,9 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, struct s\n \n \t/* Second, deal with arguments and options */\n \tflags = 0;\n-\trevarg_opt = seen_dashdash ? REVARG_CANNOT_BE_FILENAME : 0;\n+\trevarg_opt = opt ? opt->revarg_opt : 0;\n+\tif (seen_dashdash)\n+\t\trevarg_opt |= REVARG_CANNOT_BE_FILENAME;\n \tread_from_stdin = 0;\n \tfor (left = i = 1; i < argc; i++) {\n \t\tconst char *arg = argv[i];\ndiff --git a/revision.h b/revision.h\nindex 8eceaec..402f10d 100644\n--- a/revision.h\n+++ b/revision.h\n@@ -183,6 +183,7 @@ struct setup_revision_opt {\n \tconst char *def;\n \tvoid (*tweak)(struct rev_info *, struct setup_revision_opt *);\n \tconst char *submodule;\n+\tunsigned revarg_opt;\n };\n \n extern void init_revisions(struct rev_info *revs, const char *prefix);\n@@ -191,6 +192,7 @@ extern void parse_revision_opt(struct rev_info *revs, struct parse_opt_ctx_t *ct\n \t\t\t\t const struct option *options,\n \t\t\t\t const char * const usagestr[]);\n #define REVARG_CANNOT_BE_FILENAME 01\n+#define REVARG_COMMITTISH 02\n extern int handle_revision_arg(const char *arg, struct rev_info *revs, int flags, unsigned revarg_opt);\n \n extern int prepare_revision_walk(struct rev_info *revs);\ndiff --git a/t/t1512-rev-parse-disambiguation.sh b/t/t1512-rev-parse-disambiguation.sh\nindex 7c92451..417b436 100755\n--- a/t/t1512-rev-parse-disambiguation.sh\n+++ b/t/t1512-rev-parse-disambiguation.sh\n@@ -117,7 +117,7 @@ test_expect_failure 'rev-parse name1..name2 takes only commit-ishes on both ends\n \tgit rev-parse 11021982..\n '\n \n-test_expect_failure 'git log takes only commit-ish' '\n+test_expect_success 'git log takes only commit-ish' '\n \tgit log 11021982\n '\n \n-- \n1.7.11.1.229.g706c98f\n"},{"id":"194568","messageId":"1341351435-31011-21-git-send-email-gitster@pobox.com","threadId":"30945","inReplyTo":"1341351435-31011-1-git-send-email-gitster@pobox.com","subject":"[PATCH v5 20/25] sha1_name.c: add support for disambiguating other types","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2012-07-03T21:37:10Z","receivedAt":"2012-07-03T21:37:10Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"This teaches the revision parser that in \"$name:$path\" (used for a\nblob object name), \"$name\" must be a tree-ish.\n\nThere are many more places where we know what types of objects are\ncalled for.  This patch adds support for \"commit\", \"treeish\", \"tree\",\nand \"blob\", which could be used in the following contexts:\n\n - \"git apply --build-fake-ancestor\" reads the \"index\" lines from\n   the patch; they must name blob objects (not even \"blob-ish\");\n\n - \"git commit-tree\" reads a tree object name (not \"tree-ish\"), and\n   zero or more commit object names (not \"committish\");\n\n - \"git reset $rev\" wants a committish; \"git reset $rev -- $path\"\n   wants a treeish.\n\nThey will come in later patches in the series.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n cache.h                             | 13 ++++++--\n sha1_name.c                         | 66 ++++++++++++++++++++++++++++++++++++-\n t/t1512-rev-parse-disambiguation.sh |  2 +-\n 3 files changed, 76 insertions(+), 5 deletions(-)\n\ndiff --git a/cache.h b/cache.h\nindex e947b48..c8d6406 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -811,13 +811,20 @@ struct object_context {\n \tunsigned mode;\n };\n \n-#define GET_SHA1_QUIETLY 01\n-#define GET_SHA1_COMMIT 02\n-#define GET_SHA1_COMMITTISH 04\n+#define GET_SHA1_QUIETLY        01\n+#define GET_SHA1_COMMIT         02\n+#define GET_SHA1_COMMITTISH     04\n+#define GET_SHA1_TREE          010\n+#define GET_SHA1_TREEISH       020\n+#define GET_SHA1_BLOB\t       040\n #define GET_SHA1_ONLY_TO_DIE 04000\n \n extern int get_sha1(const char *str, unsigned char *sha1);\n+extern int get_sha1_commit(const char *str, unsigned char *sha1);\n extern int get_sha1_committish(const char *str, unsigned char *sha1);\n+extern int get_sha1_tree(const char *str, unsigned char *sha1);\n+extern int get_sha1_treeish(const char *str, unsigned char *sha1);\n+extern int get_sha1_blob(const char *str, unsigned char *sha1);\n extern void maybe_die_on_misspelt_object_name(const char *name, const char *prefix);\n extern int get_sha1_with_context(const char *str, unsigned flags, unsigned char *sha1, struct object_context *orc);\n \ndiff --git a/sha1_name.c b/sha1_name.c\nindex 9e13d60..18fac92 100644\n--- a/sha1_name.c\n+++ b/sha1_name.c\n@@ -242,6 +242,36 @@ static int disambiguate_committish_only(const unsigned char *sha1, void *cb_data\n \treturn 0;\n }\n \n+static int disambiguate_tree_only(const unsigned char *sha1, void *cb_data_unused)\n+{\n+\tint kind = sha1_object_info(sha1, NULL);\n+\treturn kind == OBJ_TREE;\n+}\n+\n+static int disambiguate_treeish_only(const unsigned char *sha1, void *cb_data_unused)\n+{\n+\tstruct object *obj;\n+\tint kind;\n+\n+\tkind = sha1_object_info(sha1, NULL);\n+\tif (kind == OBJ_TREE || kind == OBJ_COMMIT)\n+\t\treturn 1;\n+\tif (kind != OBJ_TAG)\n+\t\treturn 0;\n+\n+\t/* We need to do this the hard way... */\n+\tobj = deref_tag(lookup_object(sha1), NULL, 0);\n+\tif (obj && (obj->type == OBJ_TREE || obj->type == OBJ_COMMIT))\n+\t\treturn 1;\n+\treturn 0;\n+}\n+\n+static int disambiguate_blob_only(const unsigned char *sha1, void *cb_data_unused)\n+{\n+\tint kind = sha1_object_info(sha1, NULL);\n+\treturn kind == OBJ_BLOB;\n+}\n+\n static int get_short_sha1(const char *name, int len, unsigned char *sha1,\n \t\t\t  unsigned flags)\n {\n@@ -281,6 +311,12 @@ static int get_short_sha1(const char *name, int len, unsigned char *sha1,\n \t\tds.fn = disambiguate_commit_only;\n \telse if (flags & GET_SHA1_COMMITTISH)\n \t\tds.fn = disambiguate_committish_only;\n+\telse if (flags & GET_SHA1_TREE)\n+\t\tds.fn = disambiguate_tree_only;\n+\telse if (flags & GET_SHA1_TREEISH)\n+\t\tds.fn = disambiguate_treeish_only;\n+\telse if (flags & GET_SHA1_BLOB)\n+\t\tds.fn = disambiguate_blob_only;\n \n \tfind_short_object_filename(len, hex_pfx, &ds);\n \tfind_short_packed_object(len, bin_pfx, &ds);\n@@ -1016,6 +1052,34 @@ int get_sha1_committish(const char *name, unsigned char *sha1)\n \t\t\t\t     sha1, &unused);\n }\n \n+int get_sha1_treeish(const char *name, unsigned char *sha1)\n+{\n+\tstruct object_context unused;\n+\treturn get_sha1_with_context(name, GET_SHA1_TREEISH,\n+\t\t\t\t     sha1, &unused);\n+}\n+\n+int get_sha1_commit(const char *name, unsigned char *sha1)\n+{\n+\tstruct object_context unused;\n+\treturn get_sha1_with_context(name, GET_SHA1_COMMIT,\n+\t\t\t\t     sha1, &unused);\n+}\n+\n+int get_sha1_tree(const char *name, unsigned char *sha1)\n+{\n+\tstruct object_context unused;\n+\treturn get_sha1_with_context(name, GET_SHA1_TREE,\n+\t\t\t\t     sha1, &unused);\n+}\n+\n+int get_sha1_blob(const char *name, unsigned char *sha1)\n+{\n+\tstruct object_context unused;\n+\treturn get_sha1_with_context(name, GET_SHA1_BLOB,\n+\t\t\t\t     sha1, &unused);\n+}\n+\n /* Must be called only when object_name:filename doesn't exist. */\n static void diagnose_invalid_sha1_path(const char *prefix,\n \t\t\t\t       const char *filename,\n@@ -1221,7 +1285,7 @@ static int get_sha1_with_context_1(const char *name,\n \t\t\tstrncpy(object_name, name, cp-name);\n \t\t\tobject_name[cp-name] = '\\0';\n \t\t}\n-\t\tif (!get_sha1_1(name, cp-name, tree_sha1, 0)) {\n+\t\tif (!get_sha1_1(name, cp-name, tree_sha1, GET_SHA1_TREEISH)) {\n \t\t\tconst char *filename = cp+1;\n \t\t\tchar *new_filename = NULL;\n \ndiff --git a/t/t1512-rev-parse-disambiguation.sh b/t/t1512-rev-parse-disambiguation.sh\nindex 417b436..4851a5f 100755\n--- a/t/t1512-rev-parse-disambiguation.sh\n+++ b/t/t1512-rev-parse-disambiguation.sh\n@@ -44,7 +44,7 @@ test_expect_success 'warn ambiguity when no candidate matches type hint' '\n \tgrep \"short SHA1 11021982 is ambiguous\" actual\n '\n \n-test_expect_failure 'disambiguate tree-ish' '\n+test_expect_success 'disambiguate tree-ish' '\n \t# feed tree-ish in an unambiguous way\n \tgit rev-parse --verify 1102198206:bz01t33 &&\n \n-- \n1.7.11.1.229.g706c98f\n"},{"id":"194569","messageId":"1341351435-31011-22-git-send-email-gitster@pobox.com","threadId":"30945","inReplyTo":"1341351435-31011-1-git-send-email-gitster@pobox.com","subject":"[PATCH v5 21/25] apply: --build-fake-ancestor expects blobs","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2012-07-03T21:37:11Z","receivedAt":"2012-07-03T21:37:11Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"The \"index\" line read from the patch to reconstruct a partial\npreimage tree records the object names of blob objects.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/apply.c                     | 2 +-\n t/t1512-rev-parse-disambiguation.sh | 2 +-\n 2 files changed, 2 insertions(+), 2 deletions(-)\n\ndiff --git a/builtin/apply.c b/builtin/apply.c\nindex c24dc54..8b2db1d 100644\n--- a/builtin/apply.c\n+++ b/builtin/apply.c\n@@ -3203,7 +3203,7 @@ static void build_fake_ancestor(struct patch *list, const char *filename)\n \t\tname = patch->old_name ? patch->old_name : patch->new_name;\n \t\tif (0 < patch->is_new)\n \t\t\tcontinue;\n-\t\telse if (get_sha1(patch->old_sha1_prefix, sha1))\n+\t\telse if (get_sha1_blob(patch->old_sha1_prefix, sha1))\n \t\t\t/* git diff has no index line for mode/type changes */\n \t\t\tif (!patch->lines_added && !patch->lines_deleted) {\n \t\t\t\tif (get_current_sha1(patch->old_name, sha1))\ndiff --git a/t/t1512-rev-parse-disambiguation.sh b/t/t1512-rev-parse-disambiguation.sh\nindex 4851a5f..87270c9 100755\n--- a/t/t1512-rev-parse-disambiguation.sh\n+++ b/t/t1512-rev-parse-disambiguation.sh\n@@ -53,7 +53,7 @@ test_expect_success 'disambiguate tree-ish' '\n \tgit rev-parse --verify 11021982:bz01t33\n '\n \n-test_expect_failure 'disambiguate blob' '\n+test_expect_success 'disambiguate blob' '\n \tsed -e \"s/|$//\" >patch <<-EOF &&\n \tdiff --git a/frotz b/frotz\n \tindex 11021982..11021982 100644\n-- \n1.7.11.1.229.g706c98f\n"},{"id":"194567","messageId":"1341351435-31011-23-git-send-email-gitster@pobox.com","threadId":"30945","inReplyTo":"1341351435-31011-1-git-send-email-gitster@pobox.com","subject":"[PATCH v5 22/25] commit-tree: the command wants a tree and commits","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2012-07-03T21:37:12Z","receivedAt":"2012-07-03T21:37:12Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Signed-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/commit-tree.c               | 8 ++++----\n t/t1512-rev-parse-disambiguation.sh | 4 ++--\n 2 files changed, 6 insertions(+), 6 deletions(-)\n\ndiff --git a/builtin/commit-tree.c b/builtin/commit-tree.c\nindex 164b655..cb982c5 100644\n--- a/builtin/commit-tree.c\n+++ b/builtin/commit-tree.c\n@@ -48,8 +48,8 @@ int cmd_commit_tree(int argc, const char **argv, const char *prefix)\n \tif (argc < 2 || !strcmp(argv[1], \"-h\"))\n \t\tusage(commit_tree_usage);\n \n-\tif (get_sha1(argv[1], tree_sha1))\n-\t\tdie(\"Not a valid object name %s\", argv[1]);\n+\tif (get_sha1_tree(argv[1], tree_sha1))\n+\t\tdie(\"Not a valid tree object name %s\", argv[1]);\n \n \tfor (i = 1; i < argc; i++) {\n \t\tconst char *arg = argv[i];\n@@ -57,7 +57,7 @@ int cmd_commit_tree(int argc, const char **argv, const char *prefix)\n \t\t\tunsigned char sha1[20];\n \t\t\tif (argc <= ++i)\n \t\t\t\tusage(commit_tree_usage);\n-\t\t\tif (get_sha1(argv[i], sha1))\n+\t\t\tif (get_sha1_commit(argv[i], sha1))\n \t\t\t\tdie(\"Not a valid object name %s\", argv[i]);\n \t\t\tassert_sha1_type(sha1, OBJ_COMMIT);\n \t\t\tnew_parent(lookup_commit(sha1), &parents);\n@@ -104,7 +104,7 @@ int cmd_commit_tree(int argc, const char **argv, const char *prefix)\n \t\t\tcontinue;\n \t\t}\n \n-\t\tif (get_sha1(arg, tree_sha1))\n+\t\tif (get_sha1_tree(arg, tree_sha1))\n \t\t\tdie(\"Not a valid object name %s\", arg);\n \t\tif (got_tree)\n \t\t\tdie(\"Cannot give more than one trees\");\ndiff --git a/t/t1512-rev-parse-disambiguation.sh b/t/t1512-rev-parse-disambiguation.sh\nindex 87270c9..dd42729 100755\n--- a/t/t1512-rev-parse-disambiguation.sh\n+++ b/t/t1512-rev-parse-disambiguation.sh\n@@ -74,7 +74,7 @@ test_expect_success 'disambiguate blob' '\n \ttest_cmp bz01t33 actual\n '\n \n-test_expect_failure 'disambiguate tree' '\n+test_expect_success 'disambiguate tree' '\n \tcommit=$(echo \"frotz\" | git commit-tree 11021982) &&\n \ttest $(git rev-parse $commit^{tree}) = $(git rev-parse 1102198206)\n '\n@@ -97,7 +97,7 @@ test_expect_success 'disambiguate commit-ish' '\n \tgit rev-parse --verify 11021982^0\n '\n \n-test_expect_failure 'disambiguate commit' '\n+test_expect_success 'disambiguate commit' '\n \tcommit=$(echo \"frotz\" | git commit-tree 11021982 -p 11021982) &&\n \ttest $(git rev-parse $commit^) = $(git rev-parse 1102198268)\n '\n-- \n1.7.11.1.229.g706c98f\n"},{"id":"194583","messageId":"1341351435-31011-24-git-send-email-gitster@pobox.com","threadId":"30945","inReplyTo":"1341351435-31011-1-git-send-email-gitster@pobox.com","subject":"[PATCH v5 23/25] reset: the command takes committish","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2012-07-03T21:37:13Z","receivedAt":"2012-07-03T21:37:13Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"This is not strictly correct, in that resetting selected index\nentries from corresponding paths out of a given tree without moving\nHEAD is a valid operation, and in such case a tree-ish would suffice.\n\nBut the existing code already requires a committish in the codepath,\nso let's be consistent with it for now.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/reset.c                     | 10 ++++++++--\n t/t1512-rev-parse-disambiguation.sh |  2 +-\n 2 files changed, 9 insertions(+), 3 deletions(-)\n\ndiff --git a/builtin/reset.c b/builtin/reset.c\nindex 8c2c1d5..392fb63 100644\n--- a/builtin/reset.c\n+++ b/builtin/reset.c\n@@ -276,7 +276,7 @@ int cmd_reset(int argc, const char **argv, const char *prefix)\n \t\t * Otherwise, argv[i] could be either <rev> or <paths> and\n \t\t * has to be unambiguous.\n \t\t */\n-\t\telse if (!get_sha1(argv[i], sha1)) {\n+\t\telse if (!get_sha1_committish(argv[i], sha1)) {\n \t\t\t/*\n \t\t\t * Ok, argv[i] looks like a rev; it should not\n \t\t\t * be a filename.\n@@ -289,9 +289,15 @@ int cmd_reset(int argc, const char **argv, const char *prefix)\n \t\t}\n \t}\n \n-\tif (get_sha1(rev, sha1))\n+\tif (get_sha1_committish(rev, sha1))\n \t\tdie(_(\"Failed to resolve '%s' as a valid ref.\"), rev);\n \n+\t/*\n+\t * NOTE: As \"git reset $treeish -- $path\" should be usable on\n+\t * any tree-ish, this is not strictly correct. We are not\n+\t * moving the HEAD to any commit; we are merely resetting the\n+\t * entries in the index to that of a treeish.\n+\t */\n \tcommit = lookup_commit_reference(sha1);\n \tif (!commit)\n \t\tdie(_(\"Could not parse object '%s'.\"), rev);\ndiff --git a/t/t1512-rev-parse-disambiguation.sh b/t/t1512-rev-parse-disambiguation.sh\nindex dd42729..c3b78b9 100755\n--- a/t/t1512-rev-parse-disambiguation.sh\n+++ b/t/t1512-rev-parse-disambiguation.sh\n@@ -121,7 +121,7 @@ test_expect_success 'git log takes only commit-ish' '\n \tgit log 11021982\n '\n \n-test_expect_failure 'git reset takes only commit-ish' '\n+test_expect_success 'git reset takes only commit-ish' '\n \tgit reset 11021982\n '\n \n-- \n1.7.11.1.229.g706c98f\n"},{"id":"194582","messageId":"1341351435-31011-25-git-send-email-gitster@pobox.com","threadId":"30945","inReplyTo":"1341351435-31011-1-git-send-email-gitster@pobox.com","subject":"[PATCH v5 24/25] rev-parse: A and B in \"rev-parse A..B\" refer to committish","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2012-07-03T21:37:14Z","receivedAt":"2012-07-03T21:37:14Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Signed-off-by: Junio C Hamano <gitster@pobox.com>\n---\n builtin/rev-parse.c                 | 4 ++--\n t/t1512-rev-parse-disambiguation.sh | 2 +-\n 2 files changed, 3 insertions(+), 3 deletions(-)\n\ndiff --git a/builtin/rev-parse.c b/builtin/rev-parse.c\nindex 98d1cbe..16b98b5 100644\n--- a/builtin/rev-parse.c\n+++ b/builtin/rev-parse.c\n@@ -238,7 +238,7 @@ static int try_difference(const char *arg)\n \t\tnext = \"HEAD\";\n \tif (dotdot == arg)\n \t\tthis = \"HEAD\";\n-\tif (!get_sha1(this, sha1) && !get_sha1(next, end)) {\n+\tif (!get_sha1_committish(this, sha1) && !get_sha1_committish(next, end)) {\n \t\tshow_rev(NORMAL, end, next);\n \t\tshow_rev(symmetric ? NORMAL : REVERSED, sha1, this);\n \t\tif (symmetric) {\n@@ -278,7 +278,7 @@ static int try_parent_shorthands(const char *arg)\n \t\treturn 0;\n \n \t*dotdot = 0;\n-\tif (get_sha1(arg, sha1))\n+\tif (get_sha1_committish(arg, sha1))\n \t\treturn 0;\n \n \tif (!parents_only)\ndiff --git a/t/t1512-rev-parse-disambiguation.sh b/t/t1512-rev-parse-disambiguation.sh\nindex c3b78b9..9acaf1d 100755\n--- a/t/t1512-rev-parse-disambiguation.sh\n+++ b/t/t1512-rev-parse-disambiguation.sh\n@@ -111,7 +111,7 @@ test_expect_success 'log name1..name2 takes only commit-ishes on both ends' '\n \tgit log 11021982...\n '\n \n-test_expect_failure 'rev-parse name1..name2 takes only commit-ishes on both ends' '\n+test_expect_success 'rev-parse name1..name2 takes only commit-ishes on both ends' '\n \tgit rev-parse 11021982..11021982 &&\n \tgit rev-parse ..11021982 &&\n \tgit rev-parse 11021982..\n-- \n1.7.11.1.229.g706c98f\n"},{"id":"194584","messageId":"1341351435-31011-26-git-send-email-gitster@pobox.com","threadId":"30945","inReplyTo":"1341351435-31011-1-git-send-email-gitster@pobox.com","subject":"[PATCH v5 25/25] rev-parse --disambiguate=<prefix>","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2012-07-03T21:37:15Z","receivedAt":"2012-07-03T21:37:15Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"The new option allows you to feed an ambiguous prefix and enumerate\nall the objects that share it as a prefix of their object names.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n---\n Documentation/git-rev-parse.txt     |  6 ++++\n builtin/rev-parse.c                 | 10 +++++++\n cache.h                             |  3 ++\n sha1_name.c                         | 59 +++++++++++++++++++++++++++++++------\n t/t1512-rev-parse-disambiguation.sh |  9 ++++++\n 5 files changed, 78 insertions(+), 9 deletions(-)\n\ndiff --git a/Documentation/git-rev-parse.txt b/Documentation/git-rev-parse.txt\nindex 8023dc0..8d90863 100644\n--- a/Documentation/git-rev-parse.txt\n+++ b/Documentation/git-rev-parse.txt\n@@ -101,6 +101,12 @@ OPTIONS\n \tThe option core.warnAmbiguousRefs is used to select the strict\n \tabbreviation mode.\n \n+--disambiguate=<prefix>::\n+\tShow every object whose name begins with the given prefix.\n+\tThe <prefix> must be at least 4 hexadecimal digits long to\n+\tavoid listing each and every object in the repository by\n+\tmistake.\n+\n --all::\n \tShow all refs found in `refs/`.\n \ndiff --git a/builtin/rev-parse.c b/builtin/rev-parse.c\nindex 16b98b5..d85b8a6 100644\n--- a/builtin/rev-parse.c\n+++ b/builtin/rev-parse.c\n@@ -195,6 +195,12 @@ static int anti_reference(const char *refname, const unsigned char *sha1, int fl\n \treturn 0;\n }\n \n+static int show_abbrev(const unsigned char *sha1, void *cb_data)\n+{\n+\tshow_rev(NORMAL, sha1, NULL);\n+\treturn 0;\n+}\n+\n static void show_datestring(const char *flag, const char *datestr)\n {\n \tstatic char buffer[100];\n@@ -589,6 +595,10 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix)\n \t\t\t\tfor_each_ref(show_reference, NULL);\n \t\t\t\tcontinue;\n \t\t\t}\n+\t\t\tif (!prefixcmp(arg, \"--disambiguate=\")) {\n+\t\t\t\tfor_each_abbrev(arg + 15, show_abbrev, NULL);\n+\t\t\t\tcontinue;\n+\t\t\t}\n \t\t\tif (!strcmp(arg, \"--bisect\")) {\n \t\t\t\tfor_each_ref_in(\"refs/bisect/bad\", show_reference, NULL);\n \t\t\t\tfor_each_ref_in(\"refs/bisect/good\", anti_reference, NULL);\ndiff --git a/cache.h b/cache.h\nindex c8d6406..6338878 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -828,6 +828,9 @@ extern int get_sha1_blob(const char *str, unsigned char *sha1);\n extern void maybe_die_on_misspelt_object_name(const char *name, const char *prefix);\n extern int get_sha1_with_context(const char *str, unsigned flags, unsigned char *sha1, struct object_context *orc);\n \n+typedef int each_abbrev_fn(const unsigned char *sha1, void *);\n+extern int for_each_abbrev(const char *prefix, each_abbrev_fn, void *);\n+\n /*\n  * Try to read a SHA1 in hexadecimal format from the 40 characters\n  * starting at hex.  Write the 20-byte result to sha1 in binary form.\ndiff --git a/sha1_name.c b/sha1_name.c\nindex 18fac92..8bc20c5 100644\n--- a/sha1_name.c\n+++ b/sha1_name.c\n@@ -20,10 +20,15 @@ struct disambiguate_state {\n \tunsigned candidate_ok:1;\n \tunsigned disambiguate_fn_used:1;\n \tunsigned ambiguous:1;\n+\tunsigned always_call_fn:1;\n };\n \n static void update_candidates(struct disambiguate_state *ds, const unsigned char *current)\n {\n+\tif (ds->always_call_fn) {\n+\t\tds->ambiguous = ds->fn(current, ds->cb_data) ? 1 : 0;\n+\t\treturn;\n+\t}\n \tif (!ds->candidate_exists) {\n \t\t/* this is the first candidate */\n \t\thashcpy(ds->candidate, current);\n@@ -272,17 +277,12 @@ static int disambiguate_blob_only(const unsigned char *sha1, void *cb_data_unuse\n \treturn kind == OBJ_BLOB;\n }\n \n-static int get_short_sha1(const char *name, int len, unsigned char *sha1,\n-\t\t\t  unsigned flags)\n+static int prepare_prefixes(const char *name, int len,\n+\t\t\t    unsigned char *bin_pfx,\n+\t\t\t    char *hex_pfx)\n {\n-\tint i, status;\n-\tchar hex_pfx[40];\n-\tunsigned char bin_pfx[20];\n-\tstruct disambiguate_state ds;\n-\tint quietly = !!(flags & GET_SHA1_QUIETLY);\n+\tint i;\n \n-\tif (len < MINIMUM_ABBREV || len > 40)\n-\t\treturn -1;\n \thashclr(bin_pfx);\n \tmemset(hex_pfx, 'x', 40);\n \tfor (i = 0; i < len ;i++) {\n@@ -303,6 +303,22 @@ static int get_short_sha1(const char *name, int len, unsigned char *sha1,\n \t\t\tval <<= 4;\n \t\tbin_pfx[i >> 1] |= val;\n \t}\n+\treturn 0;\n+}\n+\n+static int get_short_sha1(const char *name, int len, unsigned char *sha1,\n+\t\t\t  unsigned flags)\n+{\n+\tint status;\n+\tchar hex_pfx[40];\n+\tunsigned char bin_pfx[20];\n+\tstruct disambiguate_state ds;\n+\tint quietly = !!(flags & GET_SHA1_QUIETLY);\n+\n+\tif (len < MINIMUM_ABBREV || len > 40)\n+\t\treturn -1;\n+\tif (prepare_prefixes(name, len, bin_pfx, hex_pfx) < 0)\n+\t\treturn -1;\n \n \tprepare_alt_odb();\n \n@@ -327,6 +343,31 @@ static int get_short_sha1(const char *name, int len, unsigned char *sha1,\n \treturn status;\n }\n \n+\n+int for_each_abbrev(const char *prefix, each_abbrev_fn fn, void *cb_data)\n+{\n+\tchar hex_pfx[40];\n+\tunsigned char bin_pfx[20];\n+\tstruct disambiguate_state ds;\n+\tint len = strlen(prefix);\n+\n+\tif (len < MINIMUM_ABBREV || len > 40)\n+\t\treturn -1;\n+\tif (prepare_prefixes(prefix, len, bin_pfx, hex_pfx) < 0)\n+\t\treturn -1;\n+\n+\tprepare_alt_odb();\n+\n+\tmemset(&ds, 0, sizeof(ds));\n+\tds.always_call_fn = 1;\n+\tds.cb_data = cb_data;\n+\tds.fn = fn;\n+\n+\tfind_short_object_filename(len, hex_pfx, &ds);\n+\tfind_short_packed_object(len, bin_pfx, &ds);\n+\treturn ds.ambiguous;\n+}\n+\n const char *find_unique_abbrev(const unsigned char *sha1, int len)\n {\n \tint status, exists;\ndiff --git a/t/t1512-rev-parse-disambiguation.sh b/t/t1512-rev-parse-disambiguation.sh\nindex 9acaf1d..115eaa5 100755\n--- a/t/t1512-rev-parse-disambiguation.sh\n+++ b/t/t1512-rev-parse-disambiguation.sh\n@@ -251,4 +251,13 @@ test_expect_success 'ambiguous commit-ish' '\n \ttest_must_fail git log 11021982...\n '\n \n+test_expect_success 'rev-parse --disambiguate' '\n+\t# The test creates 16 objects that share the prefix and two\n+\t# commits created by commit-tree in earlier tests do not share\n+\t# the prefix.\n+\tgit rev-parse --disambiguate=11021982 >actual &&\n+\ttest \"$(wc -l <actual)\" = 16 &&\n+\ttest \"$(sed -e \"s/^\\(........\\).*/\\1/\" actual |\tsort -u)\" = 11021982\n+'\n+\n test_done\n-- \n1.7.11.1.229.g706c98f\n"}]}