{"thread":{"id":"48389","subject":"[PATCH 0/9] get_short_oid UI improvements","startedAt":"2018-04-30T22:07:48Z","lastAt":"2018-05-11T06:55:43Z","messageCount":99,"participants":["Ævar Arnfjörð Bjarmason","Stefan Beller","Eric Sunshine","brian m. carlson","Derrick Stolee","Junio C Hamano","Jacob Keller","Jeff King","Duy Nguyen","Nguyễn Thái Ngọc Duy","Martin Ågren","Luke Diamand"],"isPatch":true,"patchVersion":1,"patchTotal":9},"messages":[{"id":"346197","messageId":"20180430220734.30133-1-avarab@gmail.com","threadId":"48389","inReplyTo":null,"subject":"[PATCH 0/9] get_short_oid UI improvements","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2018-04-30T22:07:25Z","receivedAt":"2018-04-30T22:07:48Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"I started out just wanting to do 04/09 so I'd get prettier output, but\nthen noticed that ^{tag}, ^{commit}< ^{blob} and ^{tree} didn't behave\nas expected with the disambiguation output, and that core.disambiguate\nhad never been documented.\n\nÆvar Arnfjörð Bjarmason (9):\n  sha1-name.c: remove stray newline\n  sha1-array.h: align function arguments\n  sha1-name.c: move around the collect_ambiguous() function\n  get_short_oid: sort ambiguous objects by type, then SHA-1\n  get_short_oid: learn to disambiguate by ^{tag}\n  get_short_oid: learn to disambiguate by ^{blob}\n  get_short_oid / peel_onion: ^{tree} should mean tree, not treeish\n  get_short_oid / peel_onion: ^{tree} should mean commit, not commitish\n  config doc: document core.disambiguate\n\n Documentation/config.txt            | 14 ++++++\n cache.h                             |  5 ++-\n sha1-array.c                        | 15 +++++++\n sha1-array.h                        |  7 ++-\n sha1-name.c                         | 69 ++++++++++++++++++++++++-----\n t/t1512-rev-parse-disambiguation.sh | 32 ++++++++++---\n 6 files changed, 120 insertions(+), 22 deletions(-)\n\n-- \n2.17.0.290.gded63e768a\n\n"},{"id":"346198","messageId":"20180430220734.30133-2-avarab@gmail.com","threadId":"48389","inReplyTo":"20180430220734.30133-1-avarab@gmail.com","subject":"[PATCH 1/9] sha1-name.c: remove stray newline","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2018-04-30T22:07:26Z","receivedAt":"2018-04-30T22:07:53Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"This stray newline was accidentally introduced in\nd2b7d9c7ed (\"sha1_name: convert disambiguate_hint_fn to take\nobject_id\", 2017-03-26).\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n sha1-name.c | 1 -\n 1 file changed, 1 deletion(-)\n\ndiff --git a/sha1-name.c b/sha1-name.c\nindex 5b93bf8da3..cd3b133aae 100644\n--- a/sha1-name.c\n+++ b/sha1-name.c\n@@ -346,7 +346,6 @@ static int show_ambiguous_object(const struct object_id *oid, void *data)\n \tstruct strbuf desc = STRBUF_INIT;\n \tint type;\n \n-\n \tif (ds->fn && !ds->fn(oid, ds->cb_data))\n \t\treturn 0;\n \n-- \n2.17.0.290.gded63e768a\n\n"},{"id":"346199","messageId":"20180430220734.30133-3-avarab@gmail.com","threadId":"48389","inReplyTo":"20180430220734.30133-1-avarab@gmail.com","subject":"[PATCH 2/9] sha1-array.h: align function arguments","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2018-04-30T22:07:27Z","receivedAt":"2018-04-30T22:07:56Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"The arguments weren't lined up with the opening parenthesis. Fixes up\ncode added in cff38a5e11 (\"receive-pack: eliminate duplicate .have\nrefs\", 2011-05-19).\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n sha1-array.h | 4 ++--\n 1 file changed, 2 insertions(+), 2 deletions(-)\n\ndiff --git a/sha1-array.h b/sha1-array.h\nindex 04b0756334..1e1d24b009 100644\n--- a/sha1-array.h\n+++ b/sha1-array.h\n@@ -17,7 +17,7 @@ void oid_array_clear(struct oid_array *array);\n typedef int (*for_each_oid_fn)(const struct object_id *oid,\n \t\t\t       void *data);\n int oid_array_for_each_unique(struct oid_array *array,\n-\t\t\t       for_each_oid_fn fn,\n-\t\t\t       void *data);\n+\t\t\t      for_each_oid_fn fn,\n+\t\t\t      void *data);\n \n #endif /* SHA1_ARRAY_H */\n-- \n2.17.0.290.gded63e768a\n\n"},{"id":"346200","messageId":"20180430220734.30133-4-avarab@gmail.com","threadId":"48389","inReplyTo":"20180430220734.30133-1-avarab@gmail.com","subject":"[PATCH 3/9] sha1-name.c: move around the collect_ambiguous() function","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2018-04-30T22:07:28Z","receivedAt":"2018-04-30T22:07:58Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"A subsequent change will make use of this static function in the\nget_short_oid() function, which is defined above where the\ncollect_ambiguous() function is now, which would result in a\ncompilation error due to a forward declaration.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n sha1-name.c | 12 ++++++------\n 1 file changed, 6 insertions(+), 6 deletions(-)\n\ndiff --git a/sha1-name.c b/sha1-name.c\nindex cd3b133aae..9d7bbd3e96 100644\n--- a/sha1-name.c\n+++ b/sha1-name.c\n@@ -372,6 +372,12 @@ static int show_ambiguous_object(const struct object_id *oid, void *data)\n \treturn 0;\n }\n \n+static int collect_ambiguous(const struct object_id *oid, void *data)\n+{\n+\toid_array_append(data, oid);\n+\treturn 0;\n+}\n+\n static int get_short_oid(const char *name, int len, struct object_id *oid,\n \t\t\t  unsigned flags)\n {\n@@ -421,12 +427,6 @@ static int get_short_oid(const char *name, int len, struct object_id *oid,\n \treturn status;\n }\n \n-static int collect_ambiguous(const struct object_id *oid, void *data)\n-{\n-\toid_array_append(data, oid);\n-\treturn 0;\n-}\n-\n int for_each_abbrev(const char *prefix, each_abbrev_fn fn, void *cb_data)\n {\n \tstruct oid_array collect = OID_ARRAY_INIT;\n-- \n2.17.0.290.gded63e768a\n\n"},{"id":"346201","messageId":"20180430220734.30133-5-avarab@gmail.com","threadId":"48389","inReplyTo":"20180430220734.30133-1-avarab@gmail.com","subject":"[PATCH 4/9] get_short_oid: sort ambiguous objects by type, then SHA-1","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2018-04-30T22:07:29Z","receivedAt":"2018-04-30T22:08:02Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Change the output emitted when an ambiguous object is encountered so\nthat we show tags first, then commits, followed by trees, and finally\nblobs. Within each type we show objects in hashcmp(). Before this\nchange the objects were only ordered by hashcmp().\n\nThe reason for doing this is that the output looks better as a result,\ne.g. the v2.17.0 tag before this change on \"git show e8f2\" would\ndisplay:\n\n    hint: The candidates are:\n    hint:   e8f2093055 tree\n    hint:   e8f21caf94 commit 2013-06-24 - bash prompt: print unique detached HEAD abbreviated object name\n    hint:   e8f21d02f7 blob\n    hint:   e8f21d577c blob\n    hint:   e8f25a3a50 tree\n    hint:   e8f26250fa commit 2017-02-03 - Merge pull request #996 from jeffhostetler/jeffhostetler/register_rename_src\n    hint:   e8f2650052 tag v2.17.0\n    hint:   e8f2867228 blob\n    hint:   e8f28d537c tree\n    hint:   e8f2a35526 blob\n    hint:   e8f2bc0c06 commit 2015-05-10 - Documentation: note behavior for multiple remote.url entries\n    hint:   e8f2cf6ec0 tree\n\nNow we'll instead show:\n\n    hint:   e8f2650052 tag v2.17.0\n    hint:   e8f21caf94 commit 2013-06-24 - bash prompt: print unique detached HEAD abbreviated object name\n    hint:   e8f26250fa commit 2017-02-03 - Merge pull request #996 from jeffhostetler/jeffhostetler/register_rename_src\n    hint:   e8f2bc0c06 commit 2015-05-10 - Documentation: note behavior for multiple remote.url entries\n    hint:   e8f2093055 tree\n    hint:   e8f25a3a50 tree\n    hint:   e8f28d537c tree\n    hint:   e8f2cf6ec0 tree\n    hint:   e8f21d02f7 blob\n    hint:   e8f21d577c blob\n    hint:   e8f2867228 blob\n    hint:   e8f2a35526 blob\n\nSince we show the commit data in the output that's nicely aligned once\nwe sort by object type. The decision to show tags before commits is\npretty arbitrary, but it's much less likely that we'll display a tag,\nso if there is one it makes sense to show it first.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n sha1-array.c | 15 +++++++++++++++\n sha1-array.h |  3 +++\n sha1-name.c  | 37 ++++++++++++++++++++++++++++++++++++-\n 3 files changed, 54 insertions(+), 1 deletion(-)\n\ndiff --git a/sha1-array.c b/sha1-array.c\nindex 838b3bf847..48bd9e9230 100644\n--- a/sha1-array.c\n+++ b/sha1-array.c\n@@ -41,6 +41,21 @@ void oid_array_clear(struct oid_array *array)\n \tarray->sorted = 0;\n }\n \n+\n+int oid_array_for_each(struct oid_array *array,\n+\t\t       for_each_oid_fn fn,\n+\t\t       void *data)\n+{\n+\tint i;\n+\n+\tfor (i = 0; i < array->nr; i++) {\n+\t\tint ret = fn(array->oid + i, data);\n+\t\tif (ret)\n+\t\t\treturn ret;\n+\t}\n+\treturn 0;\n+}\n+\n int oid_array_for_each_unique(struct oid_array *array,\n \t\t\t\tfor_each_oid_fn fn,\n \t\t\t\tvoid *data)\ndiff --git a/sha1-array.h b/sha1-array.h\nindex 1e1d24b009..232bf95017 100644\n--- a/sha1-array.h\n+++ b/sha1-array.h\n@@ -16,6 +16,9 @@ void oid_array_clear(struct oid_array *array);\n \n typedef int (*for_each_oid_fn)(const struct object_id *oid,\n \t\t\t       void *data);\n+int oid_array_for_each(struct oid_array *array,\n+\t\t       for_each_oid_fn fn,\n+\t\t       void *data);\n int oid_array_for_each_unique(struct oid_array *array,\n \t\t\t      for_each_oid_fn fn,\n \t\t\t      void *data);\ndiff --git a/sha1-name.c b/sha1-name.c\nindex 9d7bbd3e96..46d8b1afa6 100644\n--- a/sha1-name.c\n+++ b/sha1-name.c\n@@ -378,6 +378,34 @@ static int collect_ambiguous(const struct object_id *oid, void *data)\n \treturn 0;\n }\n \n+static int sort_ambiguous(const void *a, const void *b)\n+{\n+\tint a_type = oid_object_info(a, NULL);\n+\tint b_type = oid_object_info(b, NULL);\n+\tint a_type_sort;\n+\tint b_type_sort;\n+\n+\t/*\n+\t * Sorts by hash within the same object type, just as\n+\t * oid_array_for_each_unique() would do.\n+\t */\n+\tif (a_type == b_type)\n+\t\treturn oidcmp(a, b);\n+\n+\t/*\n+\t * Between object types show tags, then commits, and finally\n+\t * trees and blobs.\n+\t *\n+\t * The object_type enum is commit, tree, blob, tag, but we\n+\t * want tag, commit, tree blob. Cleverly (perhaps too\n+\t * cleverly) do that with modulus, since the enum assigns 1 to\n+\t * commit, so tag becomes 0.\n+\t */\n+\ta_type_sort = a_type % 4;\n+\tb_type_sort = b_type % 4;\n+\treturn a_type_sort > b_type_sort ? 1 : -1;\n+}\n+\n static int get_short_oid(const char *name, int len, struct object_id *oid,\n \t\t\t  unsigned flags)\n {\n@@ -409,6 +437,8 @@ static int get_short_oid(const char *name, int len, struct object_id *oid,\n \tstatus = finish_object_disambiguation(&ds, oid);\n \n \tif (!quietly && (status == SHORT_NAME_AMBIGUOUS)) {\n+\t\tstruct oid_array collect = OID_ARRAY_INIT;\n+\n \t\terror(_(\"short SHA1 %s is ambiguous\"), ds.hex_pfx);\n \n \t\t/*\n@@ -421,7 +451,12 @@ static int get_short_oid(const char *name, int len, struct object_id *oid,\n \t\t\tds.fn = NULL;\n \n \t\tadvise(_(\"The candidates are:\"));\n-\t\tfor_each_abbrev(ds.hex_pfx, show_ambiguous_object, &ds);\n+\t\tfor_each_abbrev(ds.hex_pfx, collect_ambiguous, &collect);\n+\t\tQSORT(collect.oid, collect.nr, sort_ambiguous);\n+\n+\t\tif (oid_array_for_each(&collect, show_ambiguous_object, &ds))\n+\t\t\tBUG(\"show_ambiguous_object shouldn't return non-zero\");\n+\t\toid_array_clear(&collect);\n \t}\n \n \treturn status;\n-- \n2.17.0.290.gded63e768a\n\n"},{"id":"346202","messageId":"20180430220734.30133-7-avarab@gmail.com","threadId":"48389","inReplyTo":"20180430220734.30133-1-avarab@gmail.com","subject":"[PATCH 6/9] get_short_oid: learn to disambiguate by ^{blob}","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2018-04-30T22:07:31Z","receivedAt":"2018-04-30T22:08:06Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"The disambiguation logic had all the pieces necessary to only print\nout those blobs that were ambiguous, but they hadn't been connected.\n\nThe initial logic was added in daba53aeaf (\"sha1_name.c: add support\nfor disambiguating other types\", 2012-07-02), and when the flags were\npropagated in 8a10fea49b (\"get_sha1: propagate flags to child\nfunctions\", 2016-09-26) GET_OID_BLOB wasn't added to lookup_flags.\n\nBefore this change requests for blobs were simply ignored:\n\n    $ git rev-parse e8f2^{blob}\n    error: short SHA1 e8f2 is ambiguous\n    hint: The candidates are:\n    hint:   e8f2650052 tag v2.17.0\n    hint:   e8f21caf94 commit 2013-06-24 - bash prompt: print unique detached HEAD abbreviated object name\n    hint:   e8f26250fa commit 2017-02-03 - Merge pull request #996 from jeffhostetler/jeffhostetler/register_rename_src\n    hint:   e8f2bc0c06 commit 2015-05-10 - Documentation: note behavior for multiple remote.url entries\n    hint:   e8f2093055 tree\n    hint:   e8f25a3a50 tree\n    hint:   e8f28d537c tree\n    hint:   e8f2cf6ec0 tree\n    hint:   e8f21d02f7 blob\n    hint:   e8f21d577c blob\n    hint:   e8f2867228 blob\n    hint:   e8f2a35526 blob\n    e8f2^{blob}\n    [...]\n\nBut now we'll do the right thing and only print the blobs:\n\n    $ git rev-parse e8f2^{blob}\n    error: short SHA1 e8f2 is ambiguous\n    hint: The candidates are:\n    hint:   e8f21d02f7 blob\n    hint:   e8f21d577c blob\n    hint:   e8f2867228 blob\n    hint:   e8f2a35526 blob\n    e8f2^{blob}\n    [...]\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n sha1-name.c                         | 2 ++\n t/t1512-rev-parse-disambiguation.sh | 6 +++++-\n 2 files changed, 7 insertions(+), 1 deletion(-)\n\ndiff --git a/sha1-name.c b/sha1-name.c\nindex 68d5f65362..023f9471a8 100644\n--- a/sha1-name.c\n+++ b/sha1-name.c\n@@ -971,6 +971,8 @@ static int peel_onion(const char *name, int len, struct object_id *oid,\n \t\tlookup_flags |= GET_OID_TAG;\n \telse if (expected_type == OBJ_TREE)\n \t\tlookup_flags |= GET_OID_TREEISH;\n+\telse if (expected_type == OBJ_BLOB)\n+\t\tlookup_flags |= GET_OID_BLOB;\n \n \tif (get_oid_1(name, sp - name - 2, &outer, lookup_flags))\n \t\treturn -1;\ndiff --git a/t/t1512-rev-parse-disambiguation.sh b/t/t1512-rev-parse-disambiguation.sh\nindex c7ceda2f21..08ae73e2a5 100755\n--- a/t/t1512-rev-parse-disambiguation.sh\n+++ b/t/t1512-rev-parse-disambiguation.sh\n@@ -337,7 +337,11 @@ test_expect_success C_LOCALE_OUTPUT 'ambiguity hints respect type' '\n \ttest_line_count = 7 hints &&\n \tgit rev-parse 000000000^{tag} >stdout &&\n \ttest_line_count = 1 stdout &&\n-\tgrep -q ^0000000000f8f stdout\n+\tgrep -q ^0000000000f8f stdout &&\n+\ttest_must_fail git rev-parse 000000000^{blob} 2>stderr &&\n+\tgrep ^hint: stderr >hints &&\n+\t# 5 blobs plus intro line &&\n+\ttest_line_count = 6 hints\n '\n \n test_expect_success C_LOCALE_OUTPUT 'failed type-selector still shows hint' '\n-- \n2.17.0.290.gded63e768a\n\n"},{"id":"346203","messageId":"20180430220734.30133-8-avarab@gmail.com","threadId":"48389","inReplyTo":"20180430220734.30133-1-avarab@gmail.com","subject":"[PATCH 7/9] get_short_oid / peel_onion: ^{tree} should mean tree, not treeish","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2018-04-30T22:07:32Z","receivedAt":"2018-04-30T22:08:08Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"After the recent series of patches ^{tag} and ^{blob} now work to get\njust the tags and blobs, but ^{tree} will still list any\ntree-ish (commits, tags and trees).\n\nThe previous behavior was added in ed1ca6025f (\"peel_onion:\ndisambiguate to favor tree-ish when we know we want a tree-ish\",\n2013-03-31). I may have missed some special-case but this makes more\nsense to me.\n\nNow \"$sha1:\" can be used as before to mean treeish\n\n    $ git rev-parse e8f2:\n    error: short SHA1 e8f2 is ambiguous\n    hint: The candidates are:\n    hint:   e8f2650052 tag v2.17.0\n    hint:   e8f21caf94 commit 2013-06-24 - bash prompt: print unique detached HEAD abbreviated object name\n    hint:   e8f26250fa commit 2017-02-03 - Merge pull request #996 from jeffhostetler/jeffhostetler/register_rename_src\n    hint:   e8f2bc0c06 commit 2015-05-10 - Documentation: note behavior for multiple remote.url entries\n    hint:   e8f2093055 tree\n    hint:   e8f25a3a50 tree\n    hint:   e8f28d537c tree\n    hint:   e8f2cf6ec0 tree\n    [...]\n\nBut ^{tree} shows just the trees, but would previously be equivalent\nto the above:\n\n    $ git rev-parse e8f2^{tree}\n    error: short SHA1 e8f2 is ambiguous\n    hint: The candidates are:\n    hint:   e8f2093055 tree\n    hint:   e8f25a3a50 tree\n    hint:   e8f28d537c tree\n    hint:   e8f2cf6ec0 tree\n    [...]\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n sha1-name.c                         |  2 +-\n t/t1512-rev-parse-disambiguation.sh | 18 ++++++++++++++----\n 2 files changed, 15 insertions(+), 5 deletions(-)\n\ndiff --git a/sha1-name.c b/sha1-name.c\nindex 023f9471a8..b61c0558d9 100644\n--- a/sha1-name.c\n+++ b/sha1-name.c\n@@ -970,7 +970,7 @@ static int peel_onion(const char *name, int len, struct object_id *oid,\n \telse if (expected_type == OBJ_TAG)\n \t\tlookup_flags |= GET_OID_TAG;\n \telse if (expected_type == OBJ_TREE)\n-\t\tlookup_flags |= GET_OID_TREEISH;\n+\t\tlookup_flags |= GET_OID_TREE;\n \telse if (expected_type == OBJ_BLOB)\n \t\tlookup_flags |= GET_OID_BLOB;\n \ndiff --git a/t/t1512-rev-parse-disambiguation.sh b/t/t1512-rev-parse-disambiguation.sh\nindex 08ae73e2a5..2acf564714 100755\n--- a/t/t1512-rev-parse-disambiguation.sh\n+++ b/t/t1512-rev-parse-disambiguation.sh\n@@ -159,9 +159,13 @@ test_expect_failure 'two semi-ambiguous commit-ish' '\n \tgit log 0000000000...\n '\n \n-test_expect_failure 'three semi-ambiguous tree-ish' '\n+test_expect_success '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+\ttest_must_fail git rev-parse --verify 0000000000: &&\n+\n+\t# For ^{tree} we can disambiguate because HEAD and v1.0.0 will\n+\t# be excluded.\n \tgit rev-parse --verify 0000000000^{tree}\n '\n \n@@ -267,8 +271,12 @@ test_expect_success 'ambiguous commit-ish' '\n # There are three objects with this prefix: a blob, a tree, and a tag. We know\n # the blob will not pass as a treeish, but the tree and tag should (and thus\n # cause an error).\n-test_expect_success 'ambiguous tags peel to treeish' '\n-\ttest_must_fail git rev-parse 0000000000f^{tree}\n+test_expect_success 'ambiguous tags peel to treeish or tree' '\n+\ttest_must_fail git rev-parse 0000000000f: &&\n+\tgit rev-parse 0000000000f^{tree} >stdout &&\n+\ttest_line_count = 1 stdout &&\n+\tgrep -q ^0000000000fd8bcc56 stdout\n+\n '\n \n test_expect_success 'rev-parse --disambiguate' '\n@@ -365,7 +373,9 @@ test_expect_success 'core.disambiguate config can prefer types' '\n test_expect_success 'core.disambiguate does not override context' '\n \t# treeish ambiguous between tag and tree\n \ttest_must_fail \\\n-\t\tgit -c core.disambiguate=committish rev-parse $sha1^{tree}\n+\t\tgit -c core.disambiguate=committish rev-parse $sha1: &&\n+\t# tree not ambiguous between tag and tree\n+\tgit -c core.disambiguate=committish rev-parse $sha1^{tree}\n '\n \n test_done\n-- \n2.17.0.290.gded63e768a\n\n"},{"id":"346204","messageId":"20180430220734.30133-6-avarab@gmail.com","threadId":"48389","inReplyTo":"20180430220734.30133-1-avarab@gmail.com","subject":"[PATCH 5/9] get_short_oid: learn to disambiguate by ^{tag}","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2018-04-30T22:07:30Z","receivedAt":"2018-04-30T22:08:11Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Add support for ^{tag} to the disambiguation logic. Before this ^{tag}\nwould simply be ignored:\n\n    $ git rev-parse e8f2^{tag}\n    error: short SHA1 e8f2 is ambiguous\n    hint: The candidates are:\n    hint:   e8f2650052 tag v2.17.0\n    hint:   e8f21caf94 commit 2013-06-24 - bash prompt: print unique detached HEAD abbreviated object name\n    hint:   e8f26250fa commit 2017-02-03 - Merge pull request #996 from jeffhostetler/jeffhostetler/register_rename_src\n    hint:   e8f2bc0c06 commit 2015-05-10 - Documentation: note behavior for multiple remote.url entries\n    hint:   e8f2093055 tree\n    hint:   e8f25a3a50 tree\n    hint:   e8f28d537c tree\n    hint:   e8f2cf6ec0 tree\n    hint:   e8f21d02f7 blob\n    hint:   e8f21d577c blob\n    hint:   e8f2867228 blob\n    hint:   e8f2a35526 blob\n    e8f2^{tag}\n\nNow the logic added in ed1ca6025f (\"peel_onion: disambiguate to favor\ntree-ish when we know we want a tree-ish\", 2013-03-31) has been\nextended to support it.\n\n    $ git rev-parse e8f2^{tag}\n    e8f2650052f3ff646023725e388ea1112b020e79\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n cache.h                             |  5 +++--\n sha1-name.c                         | 13 ++++++++++++-\n t/t1512-rev-parse-disambiguation.sh |  5 ++++-\n 3 files changed, 19 insertions(+), 4 deletions(-)\n\ndiff --git a/cache.h b/cache.h\nindex 77b7acebb6..3f6a292ba6 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -1322,8 +1322,9 @@ struct object_context {\n #define GET_OID_TREE             010\n #define GET_OID_TREEISH          020\n #define GET_OID_BLOB             040\n-#define GET_OID_FOLLOW_SYMLINKS 0100\n-#define GET_OID_RECORD_PATH     0200\n+#define GET_OID_TAG             0100\n+#define GET_OID_FOLLOW_SYMLINKS 0200\n+#define GET_OID_RECORD_PATH     0400\n #define GET_OID_ONLY_TO_DIE    04000\n \n #define GET_OID_DISAMBIGUATORS \\\ndiff --git a/sha1-name.c b/sha1-name.c\nindex 46d8b1afa6..68d5f65362 100644\n--- a/sha1-name.c\n+++ b/sha1-name.c\n@@ -221,6 +221,12 @@ static int finish_object_disambiguation(struct disambiguate_state *ds,\n \treturn 0;\n }\n \n+static int disambiguate_tag_only(const struct object_id *oid, void *cb_data_unused)\n+{\n+\tint kind = oid_object_info(oid, NULL);\n+\treturn kind == OBJ_TAG;\n+}\n+\n static int disambiguate_commit_only(const struct object_id *oid, void *cb_data_unused)\n {\n \tint kind = oid_object_info(oid, NULL);\n@@ -288,7 +294,8 @@ int set_disambiguate_hint_config(const char *var, const char *value)\n \t\t{ \"committish\", disambiguate_committish_only },\n \t\t{ \"tree\", disambiguate_tree_only },\n \t\t{ \"treeish\", disambiguate_treeish_only },\n-\t\t{ \"blob\", disambiguate_blob_only }\n+\t\t{ \"blob\", disambiguate_blob_only },\n+\t\t{ \"tag\", disambiguate_tag_only }\n \t};\n \tint i;\n \n@@ -429,6 +436,8 @@ static int get_short_oid(const char *name, int len, struct object_id *oid,\n \t\tds.fn = disambiguate_treeish_only;\n \telse if (flags & GET_OID_BLOB)\n \t\tds.fn = disambiguate_blob_only;\n+\telse if (flags & GET_OID_TAG)\n+\t\tds.fn = disambiguate_tag_only;\n \telse\n \t\tds.fn = default_disambiguate_hint;\n \n@@ -958,6 +967,8 @@ static int peel_onion(const char *name, int len, struct object_id *oid,\n \tlookup_flags &= ~GET_OID_DISAMBIGUATORS;\n \tif (expected_type == OBJ_COMMIT)\n \t\tlookup_flags |= GET_OID_COMMITTISH;\n+\telse if (expected_type == OBJ_TAG)\n+\t\tlookup_flags |= GET_OID_TAG;\n \telse if (expected_type == OBJ_TREE)\n \t\tlookup_flags |= GET_OID_TREEISH;\n \ndiff --git a/t/t1512-rev-parse-disambiguation.sh b/t/t1512-rev-parse-disambiguation.sh\nindex 711704ba5a..c7ceda2f21 100755\n--- a/t/t1512-rev-parse-disambiguation.sh\n+++ b/t/t1512-rev-parse-disambiguation.sh\n@@ -334,7 +334,10 @@ test_expect_success C_LOCALE_OUTPUT 'ambiguity hints respect type' '\n \ttest_must_fail git rev-parse 000000000^{commit} 2>stderr &&\n \tgrep ^hint: stderr >hints &&\n \t# 5 commits, 1 tag (which is a commitish), plus intro line\n-\ttest_line_count = 7 hints\n+\ttest_line_count = 7 hints &&\n+\tgit rev-parse 000000000^{tag} >stdout &&\n+\ttest_line_count = 1 stdout &&\n+\tgrep -q ^0000000000f8f stdout\n '\n \n test_expect_success C_LOCALE_OUTPUT 'failed type-selector still shows hint' '\n-- \n2.17.0.290.gded63e768a\n\n"},{"id":"346205","messageId":"20180430220734.30133-10-avarab@gmail.com","threadId":"48389","inReplyTo":"20180430220734.30133-1-avarab@gmail.com","subject":"[PATCH 9/9] config doc: document core.disambiguate","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2018-04-30T22:07:34Z","receivedAt":"2018-04-30T22:08:15Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"The core.disambiguate variable was added in\n5b33cb1fd7 (\"get_short_sha1: make default disambiguation\nconfigurable\", 2016-09-27) but never documented.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n Documentation/config.txt | 14 ++++++++++++++\n 1 file changed, 14 insertions(+)\n\ndiff --git a/Documentation/config.txt b/Documentation/config.txt\nindex 2659153cb3..6fee67c12d 100644\n--- a/Documentation/config.txt\n+++ b/Documentation/config.txt\n@@ -910,6 +910,20 @@ core.abbrev::\n \tabbreviated object names to stay unique for some time.\n \tThe minimum length is 4.\n \n+core.disambiguate::\n+\tIf Git is given a SHA-1 that's ambigous it'll suggest what\n+\tobjects you might mean. By default it'll print out all\n+\tpotential objects with that prefix regardless of their\n+\ttype. This setting, along with the `^{<type>}` peel syntax\n+\t(see linkgit:gitrevisions[7]), allows for narrowing that down.\n+\n++\n+Is set to `none` by default, can also be `commit` (peel syntax:\n+`$sha1^{commit}`), `commitish` (commits and tags), `tree` (peel:\n+`$sha1^{tree}`), `treeish` (everything except blobs), `blob` (peel:\n+`$sha1^{blob}`) or `tag` (peel: `$sha1^{tag}`). The peel syntax will\n+override any config value.\n+\n add.ignoreErrors::\n add.ignore-errors (deprecated)::\n \tTells 'git add' to continue adding files when some files cannot be\n-- \n2.17.0.290.gded63e768a\n\n"},{"id":"346206","messageId":"20180430220734.30133-9-avarab@gmail.com","threadId":"48389","inReplyTo":"20180430220734.30133-1-avarab@gmail.com","subject":"[PATCH 8/9] get_short_oid / peel_onion: ^{tree} should mean commit, not commitish","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2018-04-30T22:07:33Z","receivedAt":"2018-04-30T22:08:16Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Continue the untangling of peel disambiguation syntax. Before this\ne8f2^{commit} would show the v2.17.0 tag, but now it'll just show\nambiguous commits:\n\n    $ git rev-parse e8f2^{commit}\n    error: short SHA1 e8f2 is ambiguous\n    hint: The candidates are:\n    hint:   e8f21caf94 commit 2013-06-24 - bash prompt: print unique detached HEAD abbreviated object name\n    hint:   e8f26250fa commit 2017-02-03 - Merge pull request #996 from jeffhostetler/jeffhostetler/register_rename_src\n    hint:   e8f2bc0c06 commit 2015-05-10 - Documentation: note behavior for multiple remote.url entries\n    [...]\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n sha1-name.c                         | 2 +-\n t/t1512-rev-parse-disambiguation.sh | 7 ++++---\n 2 files changed, 5 insertions(+), 4 deletions(-)\n\ndiff --git a/sha1-name.c b/sha1-name.c\nindex b61c0558d9..1d2a74a29c 100644\n--- a/sha1-name.c\n+++ b/sha1-name.c\n@@ -966,7 +966,7 @@ static int peel_onion(const char *name, int len, struct object_id *oid,\n \n \tlookup_flags &= ~GET_OID_DISAMBIGUATORS;\n \tif (expected_type == OBJ_COMMIT)\n-\t\tlookup_flags |= GET_OID_COMMITTISH;\n+\t\tlookup_flags |= GET_OID_COMMIT;\n \telse if (expected_type == OBJ_TAG)\n \t\tlookup_flags |= GET_OID_TAG;\n \telse if (expected_type == OBJ_TREE)\ndiff --git a/t/t1512-rev-parse-disambiguation.sh b/t/t1512-rev-parse-disambiguation.sh\nindex 2acf564714..b3ef236db8 100755\n--- a/t/t1512-rev-parse-disambiguation.sh\n+++ b/t/t1512-rev-parse-disambiguation.sh\n@@ -341,8 +341,8 @@ test_expect_success C_LOCALE_OUTPUT 'ambiguity hints' '\n test_expect_success C_LOCALE_OUTPUT 'ambiguity hints respect type' '\n \ttest_must_fail git rev-parse 000000000^{commit} 2>stderr &&\n \tgrep ^hint: stderr >hints &&\n-\t# 5 commits, 1 tag (which is a commitish), plus intro line\n-\ttest_line_count = 7 hints &&\n+\t# 5 commits plus intro line\n+\ttest_line_count = 6 hints &&\n \tgit rev-parse 000000000^{tag} >stdout &&\n \ttest_line_count = 1 stdout &&\n \tgrep -q ^0000000000f8f stdout &&\n@@ -366,7 +366,8 @@ test_expect_success 'core.disambiguate config can prefer types' '\n \t# ambiguous between tree and tag\n \tsha1=0000000000f &&\n \ttest_must_fail git rev-parse $sha1 &&\n-\tgit rev-parse $sha1^{commit} &&\n+\t# there is no commit so ^{commit} comes up empty\n+\ttest_must_fail git rev-parse $sha1^{commit} &&\n \tgit -c core.disambiguate=committish rev-parse $sha1\n '\n \n-- \n2.17.0.290.gded63e768a\n\n"},{"id":"346211","messageId":"CAGZ79kY=-LAvA3i8QvS3Q1VniE2M-=vFxuXX3=zmPx9vXUaRgQ@mail.gmail.com","threadId":"48389","inReplyTo":"20180430220734.30133-1-avarab@gmail.com","subject":"Re: [PATCH 0/9] get_short_oid UI improvements","fromName":"Stefan Beller","fromEmail":"sbeller@google.com","sentAt":"2018-04-30T22:34:23Z","receivedAt":"2018-04-30T22:34:28Z","isPatch":true,"sender":{"key":"stefanbeller@gmail.com","avatar":"https://avatars.githubusercontent.com/u/455868?v=4"},"body":"On Mon, Apr 30, 2018 at 3:07 PM, Ævar Arnfjörð Bjarmason\n<avarab@gmail.com> wrote:\n> I started out just wanting to do 04/09 so I'd get prettier output, but\n> then noticed that ^{tag}, ^{commit}< ^{blob} and ^{tree} didn't behave\n> as expected with the disambiguation output, and that core.disambiguate\n> had never been documented.\n>\n\nThis whole series, including the comment in which you wonder\nif the code is overly smart, is\n\nReviewed-by: Stefan Beller <sbeller@google.com>\n"},{"id":"346213","messageId":"CAPig+cSxdLe=dg2MUNBAZ94z4bXZYfrP1w43R_4Fr0XKVe5jdQ@mail.gmail.com","threadId":"48389","inReplyTo":"20180430220734.30133-9-avarab@gmail.com","subject":"Re: [PATCH 8/9] get_short_oid / peel_onion: ^{tree} should mean commit, not commitish","fromName":"Eric Sunshine","fromEmail":"sunshine@sunshineco.com","sentAt":"2018-04-30T23:22:36Z","receivedAt":"2018-04-30T23:22:41Z","isPatch":true,"sender":{"key":"sunshine@sunshineco.com","avatar":"https://avatars.githubusercontent.com/u/163641?v=4"},"body":"On Mon, Apr 30, 2018 at 6:07 PM, Ævar Arnfjörð Bjarmason\n<avarab@gmail.com> wrote:\n> get_short_oid / peel_onion: ^{tree} should mean commit, not commitish\n\ns/tree/commit/\n\n> Continue the untangling of peel disambiguation syntax. Before this\n> e8f2^{commit} would show the v2.17.0 tag, but now it'll just show\n> ambiguous commits:\n>\n>     $ git rev-parse e8f2^{commit}\n>     error: short SHA1 e8f2 is ambiguous\n>     hint: The candidates are:\n>     hint:   e8f21caf94 commit 2013-06-24 - bash prompt: print unique detached HEAD abbreviated object name\n>     hint:   e8f26250fa commit 2017-02-03 - Merge pull request #996 from jeffhostetler/jeffhostetler/register_rename_src\n>     hint:   e8f2bc0c06 commit 2015-05-10 - Documentation: note behavior for multiple remote.url entries\n>     [...]\n>\n> Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n"},{"id":"346217","messageId":"20180501011351.GD13217@genre.crustytoothpaste.net","threadId":"48389","inReplyTo":"20180430220734.30133-8-avarab@gmail.com","subject":"Re: [PATCH 7/9] get_short_oid / peel_onion: ^{tree} should mean tree, not treeish","fromName":"brian m. carlson","fromEmail":"sandals@crustytoothpaste.net","sentAt":"2018-05-01T01:13:51Z","receivedAt":"2018-05-01T01:14:02Z","isPatch":true,"sender":{"key":"sandals@crustytoothpaste.net","avatar":"https://avatars.githubusercontent.com/u/497054?v=4"},"body":"On Mon, Apr 30, 2018 at 10:07:32PM +0000, Ævar Arnfjörð Bjarmason wrote:\n> diff --git a/sha1-name.c b/sha1-name.c\n> index 023f9471a8..b61c0558d9 100644\n> --- a/sha1-name.c\n> +++ b/sha1-name.c\n> @@ -970,7 +970,7 @@ static int peel_onion(const char *name, int len, struct object_id *oid,\n>  \telse if (expected_type == OBJ_TAG)\n>  \t\tlookup_flags |= GET_OID_TAG;\n>  \telse if (expected_type == OBJ_TREE)\n> -\t\tlookup_flags |= GET_OID_TREEISH;\n> +\t\tlookup_flags |= GET_OID_TREE;\n>  \telse if (expected_type == OBJ_BLOB)\n>  \t\tlookup_flags |= GET_OID_BLOB;\n>  \n\nI was concerned at first that this might lead to some sort of wrong\nbehavior when we do something like \"git rev-parse v2.17.0^{tree}\", but\nlooking at the code I've mostly convinced myself that that should still\nwork.\n-- \nbrian m. carlson: Houston, Texas, US\nOpenPGP: https://keybase.io/bk2204\n"},{"id":"346218","messageId":"20180501012701.GE13217@genre.crustytoothpaste.net","threadId":"48389","inReplyTo":"20180430220734.30133-1-avarab@gmail.com","subject":"Re: [PATCH 0/9] get_short_oid UI improvements","fromName":"brian m. carlson","fromEmail":"sandals@crustytoothpaste.net","sentAt":"2018-05-01T01:27:01Z","receivedAt":"2018-05-01T01:27:10Z","isPatch":true,"sender":{"key":"sandals@crustytoothpaste.net","avatar":"https://avatars.githubusercontent.com/u/497054?v=4"},"body":"On Mon, Apr 30, 2018 at 10:07:25PM +0000, Ævar Arnfjörð Bjarmason wrote:\n> I started out just wanting to do 04/09 so I'd get prettier output, but\n> then noticed that ^{tag}, ^{commit}< ^{blob} and ^{tree} didn't behave\n> as expected with the disambiguation output, and that core.disambiguate\n> had never been documented.\n> \n> Ævar Arnfjörð Bjarmason (9):\n>   sha1-name.c: remove stray newline\n>   sha1-array.h: align function arguments\n>   sha1-name.c: move around the collect_ambiguous() function\n>   get_short_oid: sort ambiguous objects by type, then SHA-1\n>   get_short_oid: learn to disambiguate by ^{tag}\n>   get_short_oid: learn to disambiguate by ^{blob}\n>   get_short_oid / peel_onion: ^{tree} should mean tree, not treeish\n>   get_short_oid / peel_onion: ^{tree} should mean commit, not commitish\n>   config doc: document core.disambiguate\n\nAs mentioned, I'm a bit unsure that patches 7 and 8 are entirely\ncorrect.  I've mostly convinced myself that they are after looking at\npeel_onion, but I'm still harboring lingering doubts for some reason.\n\nThe rest of the series looked fine to me.  Thanks for cleaning up my\nstray newline.\n-- \nbrian m. carlson: Houston, Texas, US\nOpenPGP: https://keybase.io/bk2204\n"},{"id":"346235","messageId":"5f8b1ec1-258d-1acc-133e-a7c248b4083e@gmail.com","threadId":"48389","inReplyTo":"20180430220734.30133-5-avarab@gmail.com","subject":"Re: [PATCH 4/9] get_short_oid: sort ambiguous objects by type, then SHA-1","fromName":"Derrick Stolee","fromEmail":"stolee@gmail.com","sentAt":"2018-05-01T11:11:07Z","receivedAt":"2018-05-01T11:11:23Z","isPatch":true,"sender":{"key":"stolee@gmail.com","avatar":"https://avatars.githubusercontent.com/u/570044?v=4"},"body":"On 4/30/2018 6:07 PM, Ævar Arnfjörð Bjarmason wrote:\n> Change the output emitted when an ambiguous object is encountered so\n> that we show tags first, then commits, followed by trees, and finally\n> blobs. Within each type we show objects in hashcmp(). Before this\n> change the objects were only ordered by hashcmp().\n>\n> The reason for doing this is that the output looks better as a result,\n> e.g. the v2.17.0 tag before this change on \"git show e8f2\" would\n> display:\n>\n>      hint: The candidates are:\n>      hint:   e8f2093055 tree\n>      hint:   e8f21caf94 commit 2013-06-24 - bash prompt: print unique detached HEAD abbreviated object name\n>      hint:   e8f21d02f7 blob\n>      hint:   e8f21d577c blob\n>      hint:   e8f25a3a50 tree\n>      hint:   e8f26250fa commit 2017-02-03 - Merge pull request #996 from jeffhostetler/jeffhostetler/register_rename_src\n>      hint:   e8f2650052 tag v2.17.0\n>      hint:   e8f2867228 blob\n>      hint:   e8f28d537c tree\n>      hint:   e8f2a35526 blob\n>      hint:   e8f2bc0c06 commit 2015-05-10 - Documentation: note behavior for multiple remote.url entries\n>      hint:   e8f2cf6ec0 tree\n>\n> Now we'll instead show:\n>\n>      hint:   e8f2650052 tag v2.17.0\n>      hint:   e8f21caf94 commit 2013-06-24 - bash prompt: print unique detached HEAD abbreviated object name\n>      hint:   e8f26250fa commit 2017-02-03 - Merge pull request #996 from jeffhostetler/jeffhostetler/register_rename_src\n>      hint:   e8f2bc0c06 commit 2015-05-10 - Documentation: note behavior for multiple remote.url entries\n>      hint:   e8f2093055 tree\n>      hint:   e8f25a3a50 tree\n>      hint:   e8f28d537c tree\n>      hint:   e8f2cf6ec0 tree\n>      hint:   e8f21d02f7 blob\n>      hint:   e8f21d577c blob\n>      hint:   e8f2867228 blob\n>      hint:   e8f2a35526 blob\n>\n> Since we show the commit data in the output that's nicely aligned once\n> we sort by object type. The decision to show tags before commits is\n> pretty arbitrary, but it's much less likely that we'll display a tag,\n> so if there is one it makes sense to show it first.\n\nHere's a non-arbitrary reason: the object types are ordered \ntopologically (ignoring self-references):\n\ntag -> commit, tree, blob\ncommit -> tree\ntree -> blob\n\n> Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n> ---\n>   sha1-array.c | 15 +++++++++++++++\n>   sha1-array.h |  3 +++\n>   sha1-name.c  | 37 ++++++++++++++++++++++++++++++++++++-\n>   3 files changed, 54 insertions(+), 1 deletion(-)\n>\n> diff --git a/sha1-array.c b/sha1-array.c\n> index 838b3bf847..48bd9e9230 100644\n> --- a/sha1-array.c\n> +++ b/sha1-array.c\n> @@ -41,6 +41,21 @@ void oid_array_clear(struct oid_array *array)\n>   \tarray->sorted = 0;\n>   }\n>   \n> +\n> +int oid_array_for_each(struct oid_array *array,\n> +\t\t       for_each_oid_fn fn,\n> +\t\t       void *data)\n> +{\n> +\tint i;\n> +\n> +\tfor (i = 0; i < array->nr; i++) {\n> +\t\tint ret = fn(array->oid + i, data);\n> +\t\tif (ret)\n> +\t\t\treturn ret;\n> +\t}\n> +\treturn 0;\n> +}\n> +\n>   int oid_array_for_each_unique(struct oid_array *array,\n>   \t\t\t\tfor_each_oid_fn fn,\n>   \t\t\t\tvoid *data)\n> diff --git a/sha1-array.h b/sha1-array.h\n> index 1e1d24b009..232bf95017 100644\n> --- a/sha1-array.h\n> +++ b/sha1-array.h\n> @@ -16,6 +16,9 @@ void oid_array_clear(struct oid_array *array);\n>   \n>   typedef int (*for_each_oid_fn)(const struct object_id *oid,\n>   \t\t\t       void *data);\n> +int oid_array_for_each(struct oid_array *array,\n> +\t\t       for_each_oid_fn fn,\n> +\t\t       void *data);\n>   int oid_array_for_each_unique(struct oid_array *array,\n>   \t\t\t      for_each_oid_fn fn,\n>   \t\t\t      void *data);\n> diff --git a/sha1-name.c b/sha1-name.c\n> index 9d7bbd3e96..46d8b1afa6 100644\n> --- a/sha1-name.c\n> +++ b/sha1-name.c\n> @@ -378,6 +378,34 @@ static int collect_ambiguous(const struct object_id *oid, void *data)\n>   \treturn 0;\n>   }\n>   \n> +static int sort_ambiguous(const void *a, const void *b)\n> +{\n> +\tint a_type = oid_object_info(a, NULL);\n> +\tint b_type = oid_object_info(b, NULL);\n> +\tint a_type_sort;\n> +\tint b_type_sort;\n> +\n> +\t/*\n> +\t * Sorts by hash within the same object type, just as\n> +\t * oid_array_for_each_unique() would do.\n> +\t */\n> +\tif (a_type == b_type)\n> +\t\treturn oidcmp(a, b);\n> +\n> +\t/*\n> +\t * Between object types show tags, then commits, and finally\n> +\t * trees and blobs.\n> +\t *\n> +\t * The object_type enum is commit, tree, blob, tag, but we\n> +\t * want tag, commit, tree blob. Cleverly (perhaps too\n> +\t * cleverly) do that with modulus, since the enum assigns 1 to\n> +\t * commit, so tag becomes 0.\n> +\t */\n\nI appreciate this comment. Clever things should be marked as such.\n\n> +\ta_type_sort = a_type % 4;\n> +\tb_type_sort = b_type % 4;\n> +\treturn a_type_sort > b_type_sort ? 1 : -1;\n> +}\n> +\n>   static int get_short_oid(const char *name, int len, struct object_id *oid,\n>   \t\t\t  unsigned flags)\n>   {\n> @@ -409,6 +437,8 @@ static int get_short_oid(const char *name, int len, struct object_id *oid,\n>   \tstatus = finish_object_disambiguation(&ds, oid);\n>   \n>   \tif (!quietly && (status == SHORT_NAME_AMBIGUOUS)) {\n> +\t\tstruct oid_array collect = OID_ARRAY_INIT;\n> +\n>   \t\terror(_(\"short SHA1 %s is ambiguous\"), ds.hex_pfx);\n>   \n>   \t\t/*\n> @@ -421,7 +451,12 @@ static int get_short_oid(const char *name, int len, struct object_id *oid,\n>   \t\t\tds.fn = NULL;\n>   \n>   \t\tadvise(_(\"The candidates are:\"));\n> -\t\tfor_each_abbrev(ds.hex_pfx, show_ambiguous_object, &ds);\n> +\t\tfor_each_abbrev(ds.hex_pfx, collect_ambiguous, &collect);\n> +\t\tQSORT(collect.oid, collect.nr, sort_ambiguous);\n\nI was wondering how the old code sorted by SHA even when the ambiguous \nobjects were loaded from different sources (multiple pack-files, loose \nobjects). Turns out that for_each_abbrev() does its own sort after \ncollecting the SHAs and then calls the given function pointer only once \nper distinct object. This avoids multiple instances of the same object, \nwhich may appear multiple times across pack-files.\n\nI only ask because now we are doing two sorts. I wonder if it would be \nmore elegant to provide your sorting algorithm to for_each_abbrev() and \nlet it call show_ambiguous_object as before.\n\nAnother question is if we should use this sort generally for all calls \nto for_each_abbrev(). The only other case I see is in builtin/revparse.c.\n\n> +\n> +\t\tif (oid_array_for_each(&collect, show_ambiguous_object, &ds))\n> +\t\t\tBUG(\"show_ambiguous_object shouldn't return non-zero\");\n> +\t\toid_array_clear(&collect);\n>   \t}\n>   \n>   \treturn status;\n\n"},{"id":"346236","messageId":"49980177-b389-1ef2-e579-cd7f2f4b91f0@gmail.com","threadId":"48389","inReplyTo":"20180430220734.30133-1-avarab@gmail.com","subject":"Re: [PATCH 0/9] get_short_oid UI improvements","fromName":"Derrick Stolee","fromEmail":"stolee@gmail.com","sentAt":"2018-05-01T11:16:13Z","receivedAt":"2018-05-01T11:16:19Z","isPatch":true,"sender":{"key":"stolee@gmail.com","avatar":"https://avatars.githubusercontent.com/u/570044?v=4"},"body":"On 4/30/2018 6:07 PM, Ævar Arnfjörð Bjarmason wrote:\n> I started out just wanting to do 04/09 so I'd get prettier output, but\n> then noticed that ^{tag}, ^{commit}< ^{blob} and ^{tree} didn't behave\n> as expected with the disambiguation output, and that core.disambiguate\n> had never been documented.\n>\n> Ævar Arnfjörð Bjarmason (9):\n>    sha1-name.c: remove stray newline\n>    sha1-array.h: align function arguments\n>    sha1-name.c: move around the collect_ambiguous() function\n>    get_short_oid: sort ambiguous objects by type, then SHA-1\n>    get_short_oid: learn to disambiguate by ^{tag}\n>    get_short_oid: learn to disambiguate by ^{blob}\n>    get_short_oid / peel_onion: ^{tree} should mean tree, not treeish\n>    get_short_oid / peel_onion: ^{tree} should mean commit, not commitish\n>    config doc: document core.disambiguate\n>\n>   Documentation/config.txt            | 14 ++++++\n>   cache.h                             |  5 ++-\n>   sha1-array.c                        | 15 +++++++\n>   sha1-array.h                        |  7 ++-\n>   sha1-name.c                         | 69 ++++++++++++++++++++++++-----\n>   t/t1512-rev-parse-disambiguation.sh | 32 ++++++++++---\n>   6 files changed, 120 insertions(+), 22 deletions(-)\n>\n\nThis is a good series. Please take a look at my suggestion in Patch 4/9, \nbut feel free to keep this series as written.\n\nReviewed-by: Derrick Stolee <dstolee@microsoft.com>\n"},{"id":"346240","messageId":"87a7tjzkdm.fsf@evledraar.gmail.com","threadId":"48389","inReplyTo":"5f8b1ec1-258d-1acc-133e-a7c248b4083e@gmail.com","subject":"Re: [PATCH 4/9] get_short_oid: sort ambiguous objects by type, then SHA-1","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2018-05-01T11:27:17Z","receivedAt":"2018-05-01T11:27:23Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"\nOn Tue, May 01 2018, Derrick Stolee wrote:\n\n> On 4/30/2018 6:07 PM, Ævar Arnfjörð Bjarmason wrote:\n>> Since we show the commit data in the output that's nicely aligned once\n>> we sort by object type. The decision to show tags before commits is\n>> pretty arbitrary, but it's much less likely that we'll display a tag,\n>> so if there is one it makes sense to show it first.\n>\n> Here's a non-arbitrary reason: the object types are ordered\n> topologically (ignoring self-references):\n>\n> tag -> commit, tree, blob\n> commit -> tree\n> tree -> blob\n\nThanks. I'll add a patch with that comment to v2.\n\n>> @@ -421,7 +451,12 @@ static int get_short_oid(const char *name, int len, struct object_id *oid,\n>>   \t\t\tds.fn = NULL;\n>>     \t\tadvise(_(\"The candidates are:\"));\n>> -\t\tfor_each_abbrev(ds.hex_pfx, show_ambiguous_object, &ds);\n>> +\t\tfor_each_abbrev(ds.hex_pfx, collect_ambiguous, &collect);\n>> +\t\tQSORT(collect.oid, collect.nr, sort_ambiguous);\n>\n> I was wondering how the old code sorted by SHA even when the ambiguous\n> objects were loaded from different sources (multiple pack-files, loose\n> objects). Turns out that for_each_abbrev() does its own sort after\n> collecting the SHAs and then calls the given function pointer only\n> once per distinct object. This avoids multiple instances of the same\n> object, which may appear multiple times across pack-files.\n>\n> I only ask because now we are doing two sorts. I wonder if it would be\n> more elegant to provide your sorting algorithm to for_each_abbrev()\n> and let it call show_ambiguous_object as before.\n>\n> Another question is if we should use this sort generally for all calls\n> to for_each_abbrev(). The only other case I see is in\n> builtin/revparse.c.\n\nWhen preparing v2 I realized how confusing this was, so I'd added this\nto the commit message of my WIP re-roll which should explain this:\n\n    A note on the implementation: I started out with something much\n    simpler which just replaced oid_array_sort() in sha1-array.c with a\n    custom sort function before calling oid_array_for_each_unique(). But\n    then dumbly noticed that it doesn't work because the output function\n    was tangled up with the code added in fad6b9e590 (\"for_each_abbrev:\n    drop duplicate objects\", 2016-09-26) to ensure we don't display\n    duplicate objects.\n    \n    That's why we're doing two passes here, first we need to sort the list\n    and de-duplicate the objects, then sort them in our custom order, and\n    finally output them without re-sorting them. I suppose we could also\n    make oid_array_for_each_unique() maintain a hashmap of emitted\n    objects, but that would increase its memory profile and wouldn't be\n    worth the complexity for this one-off use-case,\n    oid_array_for_each_unique() is used in many other places.\n"},{"id":"346251","messageId":"20180501120651.15886-1-avarab@gmail.com","threadId":"48389","inReplyTo":"20180430220734.30133-1-avarab@gmail.com","subject":"[PATCH v2 00/12] get_short_oid UI improvements","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2018-05-01T12:06:39Z","receivedAt":"2018-05-01T12:07:20Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"A v2 addressing feedback so far. Comments inline per-patch.\n\nÆvar Arnfjörð Bjarmason (12):\n  sha1-name.c: remove stray newline\n  sha1-array.h: align function arguments\n\nNo changes.\n\n  git-p4: change \"commitish\" typo to \"committish\"\n\nNew, I fixed my own \"commitish\" elsewhere, fixing it here in this\nunrelated area while I'm at it.\n\n  cache.h: add comment explaining the order in object_type\n\nNew: Derrick Stolee pointed out why the object type enum used later is\nordered that way, explain that with a comment.\n\n  sha1-name.c: move around the collect_ambiguous() function\n\nTrivial grammar correction in commit message:\n    -    collect_ambiguous() function is now, which would result in a\n    +    collect_ambiguous() function is now. Without this we'd then have a\n\n  get_short_oid: sort ambiguous objects by type, then SHA-1\n\n* Grammar fixes in commit message\n* Add docs to api-oid-array.txt documenting the new oid_array_for_each()\n* Document in the commit message why we sort twice\n* Note inline in sha1-array.c why oid_array_for_each() doesn't sort\n  with a pointer to the API docs.\n* Add test to assert that we sort objects in the order we expect, and\n  that they're hash sorted within the object types.\n\n  get_short_oid: learn to disambiguate by ^{tag}\n  get_short_oid: learn to disambiguate by ^{blob}\n\nNo changes.\n\n  get_short_oid / peel_onion: ^{tree} should be tree, not treeish\n\ns/mean/be/ in subject line (to avoid wrapping in E-Mail).\n\n  get_short_oid / peel_onion: ^{commit} should be commit, not committish\n\nRewrite commit message, now assumes less context from the rest of the\nseries & is easier to read stand-alone.\n\n  config doc: document core.disambiguate\n\nChange commitish to committish, and note the `$sha1:` peel syntax.\n\n  get_short_oid: document & warn if we ignore the type selector\n\nNew: Explain why we ignore e.g. $sha1^{blob} if there's no blobs with\nthe $sha1 prefix.\n\n Documentation/config.txt                  | 17 +++++\n Documentation/technical/api-oid-array.txt | 17 +++--\n cache.h                                   | 13 +++-\n git-p4.py                                 |  6 +-\n sha1-array.c                              | 17 +++++\n sha1-array.h                              |  7 +-\n sha1-name.c                               | 80 +++++++++++++++++++----\n t/t1512-rev-parse-disambiguation.sh       | 58 +++++++++++++---\n 8 files changed, 182 insertions(+), 33 deletions(-)\n\n-- \n2.17.0.290.gded63e768a\n\n"},{"id":"346252","messageId":"20180501120651.15886-2-avarab@gmail.com","threadId":"48389","inReplyTo":"20180501120651.15886-1-avarab@gmail.com","subject":"[PATCH v2 01/12] sha1-name.c: remove stray newline","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2018-05-01T12:06:40Z","receivedAt":"2018-05-01T12:07:26Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"This stray newline was accidentally introduced in\nd2b7d9c7ed (\"sha1_name: convert disambiguate_hint_fn to take\nobject_id\", 2017-03-26).\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n sha1-name.c | 1 -\n 1 file changed, 1 deletion(-)\n\ndiff --git a/sha1-name.c b/sha1-name.c\nindex 5b93bf8da3..cd3b133aae 100644\n--- a/sha1-name.c\n+++ b/sha1-name.c\n@@ -346,7 +346,6 @@ static int show_ambiguous_object(const struct object_id *oid, void *data)\n \tstruct strbuf desc = STRBUF_INIT;\n \tint type;\n \n-\n \tif (ds->fn && !ds->fn(oid, ds->cb_data))\n \t\treturn 0;\n \n-- \n2.17.0.290.gded63e768a\n\n"},{"id":"346253","messageId":"20180501120651.15886-3-avarab@gmail.com","threadId":"48389","inReplyTo":"20180501120651.15886-1-avarab@gmail.com","subject":"[PATCH v2 02/12] sha1-array.h: align function arguments","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2018-05-01T12:06:41Z","receivedAt":"2018-05-01T12:07:28Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"The arguments weren't lined up with the opening parenthesis. Fixes up\ncode added in cff38a5e11 (\"receive-pack: eliminate duplicate .have\nrefs\", 2011-05-19).\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n sha1-array.h | 4 ++--\n 1 file changed, 2 insertions(+), 2 deletions(-)\n\ndiff --git a/sha1-array.h b/sha1-array.h\nindex 04b0756334..1e1d24b009 100644\n--- a/sha1-array.h\n+++ b/sha1-array.h\n@@ -17,7 +17,7 @@ void oid_array_clear(struct oid_array *array);\n typedef int (*for_each_oid_fn)(const struct object_id *oid,\n \t\t\t       void *data);\n int oid_array_for_each_unique(struct oid_array *array,\n-\t\t\t       for_each_oid_fn fn,\n-\t\t\t       void *data);\n+\t\t\t      for_each_oid_fn fn,\n+\t\t\t      void *data);\n \n #endif /* SHA1_ARRAY_H */\n-- \n2.17.0.290.gded63e768a\n\n"},{"id":"346254","messageId":"20180501120651.15886-4-avarab@gmail.com","threadId":"48389","inReplyTo":"20180501120651.15886-1-avarab@gmail.com","subject":"[PATCH v2 03/12] git-p4: change \"commitish\" typo to \"committish\"","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2018-05-01T12:06:42Z","receivedAt":"2018-05-01T12:07:32Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"This was the only occurrence of \"commitish\" in the tree, but as the\nlog will reveal we've had others in the past. Fixes up code added in\n00ad6e3182 (\"git-p4: work with a detached head\", 2015-11-21).\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n git-p4.py | 6 +++---\n 1 file changed, 3 insertions(+), 3 deletions(-)\n\ndiff --git a/git-p4.py b/git-p4.py\nindex 7bb9cadc69..1afa87cd9d 100755\n--- a/git-p4.py\n+++ b/git-p4.py\n@@ -2099,11 +2099,11 @@ class P4Submit(Command, P4UserMap):\n \n         commits = []\n         if self.master:\n-            commitish = self.master\n+            committish = self.master\n         else:\n-            commitish = 'HEAD'\n+            committish = 'HEAD'\n \n-        for line in read_pipe_lines([\"git\", \"rev-list\", \"--no-merges\", \"%s..%s\" % (self.origin, commitish)]):\n+        for line in read_pipe_lines([\"git\", \"rev-list\", \"--no-merges\", \"%s..%s\" % (self.origin, committish)]):\n             commits.append(line.strip())\n         commits.reverse()\n \n-- \n2.17.0.290.gded63e768a\n\n"},{"id":"346255","messageId":"20180501120651.15886-5-avarab@gmail.com","threadId":"48389","inReplyTo":"20180501120651.15886-1-avarab@gmail.com","subject":"[PATCH v2 04/12] cache.h: add comment explaining the order in object_type","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2018-05-01T12:06:43Z","receivedAt":"2018-05-01T12:07:35Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"The order in the enum might seem arbitrary, and isn't explained by\n72518e9c26 (\"more lightweight revalidation while reusing deflated\nstream in packing\", 2006-09-03) which added it, but Derrick Stolee\nsuggested that it's ordered topologically in\n5f8b1ec1-258d-1acc-133e-a7c248b4083e@gmail.com. Makes sense to me, add\nthat as a comment.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n cache.h | 8 ++++++++\n 1 file changed, 8 insertions(+)\n\ndiff --git a/cache.h b/cache.h\nindex 77b7acebb6..354903c3ea 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -376,6 +376,14 @@ extern void free_name_hash(struct index_state *istate);\n enum object_type {\n \tOBJ_BAD = -1,\n \tOBJ_NONE = 0,\n+\t/*\n+\t * Why have our our \"real\" object types in this order? They're\n+\t * ordered topologically:\n+\t *\n+\t * tag(4)    -> commit(1), tree(2), blob(3)\n+\t * commit(1) -> tree(2)\n+\t * tree(2)   -> blob(3)\n+\t */\n \tOBJ_COMMIT = 1,\n \tOBJ_TREE = 2,\n \tOBJ_BLOB = 3,\n-- \n2.17.0.290.gded63e768a\n\n"},{"id":"346256","messageId":"20180501120651.15886-6-avarab@gmail.com","threadId":"48389","inReplyTo":"20180501120651.15886-1-avarab@gmail.com","subject":"[PATCH v2 05/12] sha1-name.c: move around the collect_ambiguous() function","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2018-05-01T12:06:44Z","receivedAt":"2018-05-01T12:07:38Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"A subsequent change will make use of this static function in the\nget_short_oid() function, which is defined above where the\ncollect_ambiguous() function is now. Without this we'd then have a\ncompilation error due to a forward declaration.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n sha1-name.c | 12 ++++++------\n 1 file changed, 6 insertions(+), 6 deletions(-)\n\ndiff --git a/sha1-name.c b/sha1-name.c\nindex cd3b133aae..9d7bbd3e96 100644\n--- a/sha1-name.c\n+++ b/sha1-name.c\n@@ -372,6 +372,12 @@ static int show_ambiguous_object(const struct object_id *oid, void *data)\n \treturn 0;\n }\n \n+static int collect_ambiguous(const struct object_id *oid, void *data)\n+{\n+\toid_array_append(data, oid);\n+\treturn 0;\n+}\n+\n static int get_short_oid(const char *name, int len, struct object_id *oid,\n \t\t\t  unsigned flags)\n {\n@@ -421,12 +427,6 @@ static int get_short_oid(const char *name, int len, struct object_id *oid,\n \treturn status;\n }\n \n-static int collect_ambiguous(const struct object_id *oid, void *data)\n-{\n-\toid_array_append(data, oid);\n-\treturn 0;\n-}\n-\n int for_each_abbrev(const char *prefix, each_abbrev_fn fn, void *cb_data)\n {\n \tstruct oid_array collect = OID_ARRAY_INIT;\n-- \n2.17.0.290.gded63e768a\n\n"},{"id":"346257","messageId":"20180501120651.15886-8-avarab@gmail.com","threadId":"48389","inReplyTo":"20180501120651.15886-1-avarab@gmail.com","subject":"[PATCH v2 07/12] get_short_oid: learn to disambiguate by ^{tag}","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2018-05-01T12:06:46Z","receivedAt":"2018-05-01T12:07:40Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Add support for ^{tag} to the disambiguation logic. Before this ^{tag}\nwould simply be ignored:\n\n    $ git rev-parse e8f2^{tag}\n    error: short SHA1 e8f2 is ambiguous\n    hint: The candidates are:\n    hint:   e8f2650052 tag v2.17.0\n    hint:   e8f21caf94 commit 2013-06-24 - bash prompt: print unique detached HEAD abbreviated object name\n    hint:   e8f26250fa commit 2017-02-03 - Merge pull request #996 from jeffhostetler/jeffhostetler/register_rename_src\n    hint:   e8f2bc0c06 commit 2015-05-10 - Documentation: note behavior for multiple remote.url entries\n    hint:   e8f2093055 tree\n    hint:   e8f25a3a50 tree\n    hint:   e8f28d537c tree\n    hint:   e8f2cf6ec0 tree\n    hint:   e8f21d02f7 blob\n    hint:   e8f21d577c blob\n    hint:   e8f2867228 blob\n    hint:   e8f2a35526 blob\n    e8f2^{tag}\n\nNow the logic added in ed1ca6025f (\"peel_onion: disambiguate to favor\ntree-ish when we know we want a tree-ish\", 2013-03-31) has been\nextended to support it.\n\n    $ git rev-parse e8f2^{tag}\n    e8f2650052f3ff646023725e388ea1112b020e79\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n cache.h                             |  5 +++--\n sha1-name.c                         | 13 ++++++++++++-\n t/t1512-rev-parse-disambiguation.sh |  5 ++++-\n 3 files changed, 19 insertions(+), 4 deletions(-)\n\ndiff --git a/cache.h b/cache.h\nindex 354903c3ea..a141995cc7 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -1330,8 +1330,9 @@ struct object_context {\n #define GET_OID_TREE             010\n #define GET_OID_TREEISH          020\n #define GET_OID_BLOB             040\n-#define GET_OID_FOLLOW_SYMLINKS 0100\n-#define GET_OID_RECORD_PATH     0200\n+#define GET_OID_TAG             0100\n+#define GET_OID_FOLLOW_SYMLINKS 0200\n+#define GET_OID_RECORD_PATH     0400\n #define GET_OID_ONLY_TO_DIE    04000\n \n #define GET_OID_DISAMBIGUATORS \\\ndiff --git a/sha1-name.c b/sha1-name.c\nindex 46d8b1afa6..68d5f65362 100644\n--- a/sha1-name.c\n+++ b/sha1-name.c\n@@ -221,6 +221,12 @@ static int finish_object_disambiguation(struct disambiguate_state *ds,\n \treturn 0;\n }\n \n+static int disambiguate_tag_only(const struct object_id *oid, void *cb_data_unused)\n+{\n+\tint kind = oid_object_info(oid, NULL);\n+\treturn kind == OBJ_TAG;\n+}\n+\n static int disambiguate_commit_only(const struct object_id *oid, void *cb_data_unused)\n {\n \tint kind = oid_object_info(oid, NULL);\n@@ -288,7 +294,8 @@ int set_disambiguate_hint_config(const char *var, const char *value)\n \t\t{ \"committish\", disambiguate_committish_only },\n \t\t{ \"tree\", disambiguate_tree_only },\n \t\t{ \"treeish\", disambiguate_treeish_only },\n-\t\t{ \"blob\", disambiguate_blob_only }\n+\t\t{ \"blob\", disambiguate_blob_only },\n+\t\t{ \"tag\", disambiguate_tag_only }\n \t};\n \tint i;\n \n@@ -429,6 +436,8 @@ static int get_short_oid(const char *name, int len, struct object_id *oid,\n \t\tds.fn = disambiguate_treeish_only;\n \telse if (flags & GET_OID_BLOB)\n \t\tds.fn = disambiguate_blob_only;\n+\telse if (flags & GET_OID_TAG)\n+\t\tds.fn = disambiguate_tag_only;\n \telse\n \t\tds.fn = default_disambiguate_hint;\n \n@@ -958,6 +967,8 @@ static int peel_onion(const char *name, int len, struct object_id *oid,\n \tlookup_flags &= ~GET_OID_DISAMBIGUATORS;\n \tif (expected_type == OBJ_COMMIT)\n \t\tlookup_flags |= GET_OID_COMMITTISH;\n+\telse if (expected_type == OBJ_TAG)\n+\t\tlookup_flags |= GET_OID_TAG;\n \telse if (expected_type == OBJ_TREE)\n \t\tlookup_flags |= GET_OID_TREEISH;\n \ndiff --git a/t/t1512-rev-parse-disambiguation.sh b/t/t1512-rev-parse-disambiguation.sh\nindex 2701462041..74e7d9c178 100755\n--- a/t/t1512-rev-parse-disambiguation.sh\n+++ b/t/t1512-rev-parse-disambiguation.sh\n@@ -334,7 +334,10 @@ test_expect_success C_LOCALE_OUTPUT 'ambiguity hints respect type' '\n \ttest_must_fail git rev-parse 000000000^{commit} 2>stderr &&\n \tgrep ^hint: stderr >hints &&\n \t# 5 commits, 1 tag (which is a commitish), plus intro line\n-\ttest_line_count = 7 hints\n+\ttest_line_count = 7 hints &&\n+\tgit rev-parse 000000000^{tag} >stdout &&\n+\ttest_line_count = 1 stdout &&\n+\tgrep -q ^0000000000f8f stdout\n '\n \n test_expect_success C_LOCALE_OUTPUT 'failed type-selector still shows hint' '\n-- \n2.17.0.290.gded63e768a\n\n"},{"id":"346258","messageId":"20180501120651.15886-7-avarab@gmail.com","threadId":"48389","inReplyTo":"20180501120651.15886-1-avarab@gmail.com","subject":"[PATCH v2 06/12] get_short_oid: sort ambiguous objects by type, then SHA-1","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2018-05-01T12:06:45Z","receivedAt":"2018-05-01T12:07:42Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Change the output emitted when an ambiguous object is encountered so\nthat we show tags first, then commits, followed by trees, and finally\nblobs. Within each type we show objects in hashcmp() order. Before\nthis change the objects were only ordered by hashcmp().\n\nThe reason for doing this is that the output looks better as a result,\ne.g. the v2.17.0 tag before this change on \"git show e8f2\" would\ndisplay:\n\n    hint: The candidates are:\n    hint:   e8f2093055 tree\n    hint:   e8f21caf94 commit 2013-06-24 - bash prompt: print unique detached HEAD abbreviated object name\n    hint:   e8f21d02f7 blob\n    hint:   e8f21d577c blob\n    hint:   e8f25a3a50 tree\n    hint:   e8f26250fa commit 2017-02-03 - Merge pull request #996 from jeffhostetler/jeffhostetler/register_rename_src\n    hint:   e8f2650052 tag v2.17.0\n    hint:   e8f2867228 blob\n    hint:   e8f28d537c tree\n    hint:   e8f2a35526 blob\n    hint:   e8f2bc0c06 commit 2015-05-10 - Documentation: note behavior for multiple remote.url entries\n    hint:   e8f2cf6ec0 tree\n\nNow we'll instead show:\n\n    hint:   e8f2650052 tag v2.17.0\n    hint:   e8f21caf94 commit 2013-06-24 - bash prompt: print unique detached HEAD abbreviated object name\n    hint:   e8f26250fa commit 2017-02-03 - Merge pull request #996 from jeffhostetler/jeffhostetler/register_rename_src\n    hint:   e8f2bc0c06 commit 2015-05-10 - Documentation: note behavior for multiple remote.url entries\n    hint:   e8f2093055 tree\n    hint:   e8f25a3a50 tree\n    hint:   e8f28d537c tree\n    hint:   e8f2cf6ec0 tree\n    hint:   e8f21d02f7 blob\n    hint:   e8f21d577c blob\n    hint:   e8f2867228 blob\n    hint:   e8f2a35526 blob\n\nSince we show the commit data in the output that's nicely aligned once\nwe sort by object type. The decision to show tags before commits is\npretty arbitrary. I don't want to order by object_type since there\ntags come last after blobs, which doesn't make sense if we want to\nshow the most important things first.\n\nI could display them after commits, but it's much less likely that\nwe'll display a tag, so if there is one it makes sense to show it\nprominently at the top.\n\nA note on the implementation: I started out with something much\nsimpler which just replaced oid_array_sort() in sha1-array.c with a\ncustom sort function before calling oid_array_for_each_unique(). But\nthen dumbly noticed that it doesn't work because the output function\nwas tangled up with the code added in fad6b9e590 (\"for_each_abbrev:\ndrop duplicate objects\", 2016-09-26) to ensure we don't display\nduplicate objects.\n\nThat's why we're doing two passes here, first we need to sort the list\nand de-duplicate the objects, then sort them in our custom order, and\nfinally output them without re-sorting them. I suppose we could also\nmake oid_array_for_each_unique() maintain a hashmap of emitted\nobjects, but that would increase its memory profile and wouldn't be\nworth the complexity for this one-off use-case,\noid_array_for_each_unique() is used in many other places.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n Documentation/technical/api-oid-array.txt | 17 +++++++----\n sha1-array.c                              | 17 +++++++++++\n sha1-array.h                              |  3 ++\n sha1-name.c                               | 37 ++++++++++++++++++++++-\n t/t1512-rev-parse-disambiguation.sh       | 21 +++++++++++++\n 5 files changed, 88 insertions(+), 7 deletions(-)\n\ndiff --git a/Documentation/technical/api-oid-array.txt b/Documentation/technical/api-oid-array.txt\nindex b0c11f868d..94b529722c 100644\n--- a/Documentation/technical/api-oid-array.txt\n+++ b/Documentation/technical/api-oid-array.txt\n@@ -35,13 +35,18 @@ Functions\n \tFree all memory associated with the array and return it to the\n \tinitial, empty state.\n \n+`oid_array_for_each`::\n+\tIterate over each element of the list, executing the callback\n+\tfunction for each one. Does not sort the list, so any custom\n+\thash order is retained. If the callback returns a non-zero\n+\tvalue, the iteration ends immediately and the callback's\n+\treturn is propagated; otherwise, 0 is returned.\n+\n `oid_array_for_each_unique`::\n-\tEfficiently iterate over each unique element of the list,\n-\texecuting the callback function for each one. If the array is\n-\tnot sorted, this function has the side effect of sorting it. If\n-\tthe callback returns a non-zero value, the iteration ends\n-\timmediately and the callback's return is propagated; otherwise,\n-\t0 is returned.\n+\tIterate over each unique element of the list in sort order ,\n+\tbut otherwise behaves like `oid_array_for_each`. If the array\n+\tis not sorted, this function has the side effect of sorting\n+\tit.\n \n Examples\n --------\ndiff --git a/sha1-array.c b/sha1-array.c\nindex 838b3bf847..5b2793615b 100644\n--- a/sha1-array.c\n+++ b/sha1-array.c\n@@ -41,6 +41,23 @@ void oid_array_clear(struct oid_array *array)\n \tarray->sorted = 0;\n }\n \n+\n+int oid_array_for_each(struct oid_array *array,\n+\t\t       for_each_oid_fn fn,\n+\t\t       void *data)\n+{\n+\tint i;\n+\n+\t/* No oid_array_sort() here! See the api-oid-array.txt docs! */\n+\n+\tfor (i = 0; i < array->nr; i++) {\n+\t\tint ret = fn(array->oid + i, data);\n+\t\tif (ret)\n+\t\t\treturn ret;\n+\t}\n+\treturn 0;\n+}\n+\n int oid_array_for_each_unique(struct oid_array *array,\n \t\t\t\tfor_each_oid_fn fn,\n \t\t\t\tvoid *data)\ndiff --git a/sha1-array.h b/sha1-array.h\nindex 1e1d24b009..232bf95017 100644\n--- a/sha1-array.h\n+++ b/sha1-array.h\n@@ -16,6 +16,9 @@ void oid_array_clear(struct oid_array *array);\n \n typedef int (*for_each_oid_fn)(const struct object_id *oid,\n \t\t\t       void *data);\n+int oid_array_for_each(struct oid_array *array,\n+\t\t       for_each_oid_fn fn,\n+\t\t       void *data);\n int oid_array_for_each_unique(struct oid_array *array,\n \t\t\t      for_each_oid_fn fn,\n \t\t\t      void *data);\ndiff --git a/sha1-name.c b/sha1-name.c\nindex 9d7bbd3e96..46d8b1afa6 100644\n--- a/sha1-name.c\n+++ b/sha1-name.c\n@@ -378,6 +378,34 @@ static int collect_ambiguous(const struct object_id *oid, void *data)\n \treturn 0;\n }\n \n+static int sort_ambiguous(const void *a, const void *b)\n+{\n+\tint a_type = oid_object_info(a, NULL);\n+\tint b_type = oid_object_info(b, NULL);\n+\tint a_type_sort;\n+\tint b_type_sort;\n+\n+\t/*\n+\t * Sorts by hash within the same object type, just as\n+\t * oid_array_for_each_unique() would do.\n+\t */\n+\tif (a_type == b_type)\n+\t\treturn oidcmp(a, b);\n+\n+\t/*\n+\t * Between object types show tags, then commits, and finally\n+\t * trees and blobs.\n+\t *\n+\t * The object_type enum is commit, tree, blob, tag, but we\n+\t * want tag, commit, tree blob. Cleverly (perhaps too\n+\t * cleverly) do that with modulus, since the enum assigns 1 to\n+\t * commit, so tag becomes 0.\n+\t */\n+\ta_type_sort = a_type % 4;\n+\tb_type_sort = b_type % 4;\n+\treturn a_type_sort > b_type_sort ? 1 : -1;\n+}\n+\n static int get_short_oid(const char *name, int len, struct object_id *oid,\n \t\t\t  unsigned flags)\n {\n@@ -409,6 +437,8 @@ static int get_short_oid(const char *name, int len, struct object_id *oid,\n \tstatus = finish_object_disambiguation(&ds, oid);\n \n \tif (!quietly && (status == SHORT_NAME_AMBIGUOUS)) {\n+\t\tstruct oid_array collect = OID_ARRAY_INIT;\n+\n \t\terror(_(\"short SHA1 %s is ambiguous\"), ds.hex_pfx);\n \n \t\t/*\n@@ -421,7 +451,12 @@ static int get_short_oid(const char *name, int len, struct object_id *oid,\n \t\t\tds.fn = NULL;\n \n \t\tadvise(_(\"The candidates are:\"));\n-\t\tfor_each_abbrev(ds.hex_pfx, show_ambiguous_object, &ds);\n+\t\tfor_each_abbrev(ds.hex_pfx, collect_ambiguous, &collect);\n+\t\tQSORT(collect.oid, collect.nr, sort_ambiguous);\n+\n+\t\tif (oid_array_for_each(&collect, show_ambiguous_object, &ds))\n+\t\t\tBUG(\"show_ambiguous_object shouldn't return non-zero\");\n+\t\toid_array_clear(&collect);\n \t}\n \n \treturn status;\ndiff --git a/t/t1512-rev-parse-disambiguation.sh b/t/t1512-rev-parse-disambiguation.sh\nindex 711704ba5a..2701462041 100755\n--- a/t/t1512-rev-parse-disambiguation.sh\n+++ b/t/t1512-rev-parse-disambiguation.sh\n@@ -361,4 +361,25 @@ test_expect_success 'core.disambiguate does not override context' '\n \t\tgit -c core.disambiguate=committish rev-parse $sha1^{tree}\n '\n \n+test_expect_success C_LOCALE_OUTPUT 'ambiguous commits are printed by type first, then hash order' '\n+\ttest_must_fail git rev-parse 0000 2>stderr &&\n+\tgrep ^hint: stderr >hints &&\n+\tgrep 0000 hints >objects &&\n+\tcat >expected <<-\\EOF &&\n+\ttag\n+\tcommit\n+\ttree\n+\tblob\n+\tEOF\n+\tawk \"{print \\$3}\" <objects >objects.types &&\n+\tuniq <objects.types >objects.types.uniq &&\n+\ttest_cmp expected objects.types.uniq &&\n+\tfor type in tag commit tree blob\n+\tdo\n+\t\tgrep $type objects >$type.objects &&\n+\t\tsort $type.objects >$type.objects.sorted &&\n+\t\ttest_cmp $type.objects.sorted $type.objects\n+\tdone\n+'\n+\n test_done\n-- \n2.17.0.290.gded63e768a\n\n"},{"id":"346259","messageId":"20180501120651.15886-10-avarab@gmail.com","threadId":"48389","inReplyTo":"20180501120651.15886-1-avarab@gmail.com","subject":"[PATCH v2 09/12] get_short_oid / peel_onion: ^{tree} should be tree, not treeish","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2018-05-01T12:06:48Z","receivedAt":"2018-05-01T12:07:45Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"After the recent series of patches ^{tag} and ^{blob} now work to get\njust the tags and blobs, but ^{tree} will still list any\ntree-ish (commits, tags and trees).\n\nThe previous behavior was added in ed1ca6025f (\"peel_onion:\ndisambiguate to favor tree-ish when we know we want a tree-ish\",\n2013-03-31). I may have missed some special-case but this makes more\nsense to me.\n\nNow \"$sha1:\" can be used as before to mean treeish\n\n    $ git rev-parse e8f2:\n    error: short SHA1 e8f2 is ambiguous\n    hint: The candidates are:\n    hint:   e8f2650052 tag v2.17.0\n    hint:   e8f21caf94 commit 2013-06-24 - bash prompt: print unique detached HEAD abbreviated object name\n    hint:   e8f26250fa commit 2017-02-03 - Merge pull request #996 from jeffhostetler/jeffhostetler/register_rename_src\n    hint:   e8f2bc0c06 commit 2015-05-10 - Documentation: note behavior for multiple remote.url entries\n    hint:   e8f2093055 tree\n    hint:   e8f25a3a50 tree\n    hint:   e8f28d537c tree\n    hint:   e8f2cf6ec0 tree\n    [...]\n\nBut ^{tree} shows just the trees, but would previously be equivalent\nto the above:\n\n    $ git rev-parse e8f2^{tree}\n    error: short SHA1 e8f2 is ambiguous\n    hint: The candidates are:\n    hint:   e8f2093055 tree\n    hint:   e8f25a3a50 tree\n    hint:   e8f28d537c tree\n    hint:   e8f2cf6ec0 tree\n    [...]\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n sha1-name.c                         |  2 +-\n t/t1512-rev-parse-disambiguation.sh | 18 ++++++++++++++----\n 2 files changed, 15 insertions(+), 5 deletions(-)\n\ndiff --git a/sha1-name.c b/sha1-name.c\nindex 023f9471a8..b61c0558d9 100644\n--- a/sha1-name.c\n+++ b/sha1-name.c\n@@ -970,7 +970,7 @@ static int peel_onion(const char *name, int len, struct object_id *oid,\n \telse if (expected_type == OBJ_TAG)\n \t\tlookup_flags |= GET_OID_TAG;\n \telse if (expected_type == OBJ_TREE)\n-\t\tlookup_flags |= GET_OID_TREEISH;\n+\t\tlookup_flags |= GET_OID_TREE;\n \telse if (expected_type == OBJ_BLOB)\n \t\tlookup_flags |= GET_OID_BLOB;\n \ndiff --git a/t/t1512-rev-parse-disambiguation.sh b/t/t1512-rev-parse-disambiguation.sh\nindex 9ce9cc3bc3..81076449a2 100755\n--- a/t/t1512-rev-parse-disambiguation.sh\n+++ b/t/t1512-rev-parse-disambiguation.sh\n@@ -159,9 +159,13 @@ test_expect_failure 'two semi-ambiguous commit-ish' '\n \tgit log 0000000000...\n '\n \n-test_expect_failure 'three semi-ambiguous tree-ish' '\n+test_expect_success '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+\ttest_must_fail git rev-parse --verify 0000000000: &&\n+\n+\t# For ^{tree} we can disambiguate because HEAD and v1.0.0 will\n+\t# be excluded.\n \tgit rev-parse --verify 0000000000^{tree}\n '\n \n@@ -267,8 +271,12 @@ test_expect_success 'ambiguous commit-ish' '\n # There are three objects with this prefix: a blob, a tree, and a tag. We know\n # the blob will not pass as a treeish, but the tree and tag should (and thus\n # cause an error).\n-test_expect_success 'ambiguous tags peel to treeish' '\n-\ttest_must_fail git rev-parse 0000000000f^{tree}\n+test_expect_success 'ambiguous tags peel to treeish or tree' '\n+\ttest_must_fail git rev-parse 0000000000f: &&\n+\tgit rev-parse 0000000000f^{tree} >stdout &&\n+\ttest_line_count = 1 stdout &&\n+\tgrep -q ^0000000000fd8bcc56 stdout\n+\n '\n \n test_expect_success 'rev-parse --disambiguate' '\n@@ -365,7 +373,9 @@ test_expect_success 'core.disambiguate config can prefer types' '\n test_expect_success 'core.disambiguate does not override context' '\n \t# treeish ambiguous between tag and tree\n \ttest_must_fail \\\n-\t\tgit -c core.disambiguate=committish rev-parse $sha1^{tree}\n+\t\tgit -c core.disambiguate=committish rev-parse $sha1: &&\n+\t# tree not ambiguous between tag and tree\n+\tgit -c core.disambiguate=committish rev-parse $sha1^{tree}\n '\n \n test_expect_success C_LOCALE_OUTPUT 'ambiguous commits are printed by type first, then hash order' '\n-- \n2.17.0.290.gded63e768a\n\n"},{"id":"346260","messageId":"20180501120651.15886-11-avarab@gmail.com","threadId":"48389","inReplyTo":"20180501120651.15886-1-avarab@gmail.com","subject":"[PATCH v2 10/12] get_short_oid / peel_onion: ^{commit} should be commit, not committish","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2018-05-01T12:06:49Z","receivedAt":"2018-05-01T12:07:48Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Change the ^{commit} syntax to mean just commits instead of committish\nfor the purpose of disambiguation. Before this e8f2^{commit} would\nshow the v2.17.0 tag as a disambiguation candidate, but now it'll just\nshow ambiguous commits:\n\n    $ git rev-parse e8f2^{commit}\n    error: short SHA1 e8f2 is ambiguous\n    hint: The candidates are:\n    hint:   e8f21caf94 commit 2013-06-24 - bash prompt: print unique detached HEAD abbreviated object name\n    hint:   e8f26250fa commit 2017-02-03 - Merge pull request #996 from jeffhostetler/jeffhostetler/register_rename_src\n    hint:   e8f2bc0c06 commit 2015-05-10 - Documentation: note behavior for multiple remote.url entries\n    [...]\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n sha1-name.c                         | 2 +-\n t/t1512-rev-parse-disambiguation.sh | 7 ++++---\n 2 files changed, 5 insertions(+), 4 deletions(-)\n\ndiff --git a/sha1-name.c b/sha1-name.c\nindex b61c0558d9..1d2a74a29c 100644\n--- a/sha1-name.c\n+++ b/sha1-name.c\n@@ -966,7 +966,7 @@ static int peel_onion(const char *name, int len, struct object_id *oid,\n \n \tlookup_flags &= ~GET_OID_DISAMBIGUATORS;\n \tif (expected_type == OBJ_COMMIT)\n-\t\tlookup_flags |= GET_OID_COMMITTISH;\n+\t\tlookup_flags |= GET_OID_COMMIT;\n \telse if (expected_type == OBJ_TAG)\n \t\tlookup_flags |= GET_OID_TAG;\n \telse if (expected_type == OBJ_TREE)\ndiff --git a/t/t1512-rev-parse-disambiguation.sh b/t/t1512-rev-parse-disambiguation.sh\nindex 81076449a2..b17973a266 100755\n--- a/t/t1512-rev-parse-disambiguation.sh\n+++ b/t/t1512-rev-parse-disambiguation.sh\n@@ -341,8 +341,8 @@ test_expect_success C_LOCALE_OUTPUT 'ambiguity hints' '\n test_expect_success C_LOCALE_OUTPUT 'ambiguity hints respect type' '\n \ttest_must_fail git rev-parse 000000000^{commit} 2>stderr &&\n \tgrep ^hint: stderr >hints &&\n-\t# 5 commits, 1 tag (which is a commitish), plus intro line\n-\ttest_line_count = 7 hints &&\n+\t# 5 commits plus intro line\n+\ttest_line_count = 6 hints &&\n \tgit rev-parse 000000000^{tag} >stdout &&\n \ttest_line_count = 1 stdout &&\n \tgrep -q ^0000000000f8f stdout &&\n@@ -366,7 +366,8 @@ test_expect_success 'core.disambiguate config can prefer types' '\n \t# ambiguous between tree and tag\n \tsha1=0000000000f &&\n \ttest_must_fail git rev-parse $sha1 &&\n-\tgit rev-parse $sha1^{commit} &&\n+\t# there is no commit so ^{commit} comes up empty\n+\ttest_must_fail git rev-parse $sha1^{commit} &&\n \tgit -c core.disambiguate=committish rev-parse $sha1\n '\n \n-- \n2.17.0.290.gded63e768a\n\n"},{"id":"346261","messageId":"20180501120651.15886-13-avarab@gmail.com","threadId":"48389","inReplyTo":"20180501120651.15886-1-avarab@gmail.com","subject":"[PATCH v2 12/12] get_short_oid: document & warn if we ignore the type selector","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2018-05-01T12:06:51Z","receivedAt":"2018-05-01T12:07:50Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"The SHA1 prefix 06fa currently matches no blobs in git.git. When\ndisambiguating short SHA1s we've been quietly ignoring the user's type\nselector as a fallback mechanism, this was intentionally added in\n1ffa26c461 (\"get_short_sha1: list ambiguous objects on error\",\n2016-09-26).\n\nI think that behavior makes sense, it's not very useful to just show\nnothing because a preference has been expressed via core.disambiguate,\nbut it's bad that we're quietly doing this. The user might thing that\nwe just didn't understand what e.g 06fa^{blob} meant.\n\nNow we'll instead print a warning if no objects of the requested type\nwere found:\n\n    $ git rev-parse 06fa^{blob}\n    error: short SHA1 06fa is ambiguous\n    hint: The candidates are:\n    [... no blobs listed ...]\n    warning: Your hint (via core.disambiguate or peel syntax) was ignored, we fell\n    back to showing all object types since no object of the requested type\n    matched the provide short SHA1 06fa\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n Documentation/config.txt            |  4 ++++\n sha1-name.c                         | 11 ++++++++++-\n t/t1512-rev-parse-disambiguation.sh |  5 ++++-\n 3 files changed, 18 insertions(+), 2 deletions(-)\n\ndiff --git a/Documentation/config.txt b/Documentation/config.txt\nindex 14a3d57e77..e14f2c0492 100644\n--- a/Documentation/config.txt\n+++ b/Documentation/config.txt\n@@ -922,6 +922,10 @@ Is set to `none` by default to show all object types. Can also be\n tags), `tree` (peel: `$sha1^{tree}`), `treeish` (everything except\n blobs, peel syntax: `$sha1:`), `blob` (peel: `$sha1^{blob}`) or `tag`\n (peel: `$sha1^{tag}`). The peel syntax will override any config value.\n++\n+If no objects of the selected type exist the disambiguation will fall\n+back to `none` and print a warning indicating no objects of the\n+selected type could be found for that prefix.\n \n add.ignoreErrors::\n add.ignore-errors (deprecated)::\ndiff --git a/sha1-name.c b/sha1-name.c\nindex 1d2a74a29c..9789764a38 100644\n--- a/sha1-name.c\n+++ b/sha1-name.c\n@@ -447,6 +447,7 @@ static int get_short_oid(const char *name, int len, struct object_id *oid,\n \n \tif (!quietly && (status == SHORT_NAME_AMBIGUOUS)) {\n \t\tstruct oid_array collect = OID_ARRAY_INIT;\n+\t\tint ignored_hint = 0;\n \n \t\terror(_(\"short SHA1 %s is ambiguous\"), ds.hex_pfx);\n \n@@ -456,8 +457,10 @@ static int get_short_oid(const char *name, int len, struct object_id *oid,\n \t\t * that case, we still want to show them, so disable the hint\n \t\t * function entirely.\n \t\t */\n-\t\tif (!ds.ambiguous)\n+\t\tif (!ds.ambiguous) {\n \t\t\tds.fn = NULL;\n+\t\t\tignored_hint = 1;\n+\t\t}\n \n \t\tadvise(_(\"The candidates are:\"));\n \t\tfor_each_abbrev(ds.hex_pfx, collect_ambiguous, &collect);\n@@ -466,6 +469,12 @@ static int get_short_oid(const char *name, int len, struct object_id *oid,\n \t\tif (oid_array_for_each(&collect, show_ambiguous_object, &ds))\n \t\t\tBUG(\"show_ambiguous_object shouldn't return non-zero\");\n \t\toid_array_clear(&collect);\n+\n+\t\tif (ignored_hint) {\n+\t\t\twarning(_(\"Your hint (via core.disambiguate or peel syntax) was ignored, we fell\\n\"\n+\t\t\t\t  \"back to showing all object types since no object of the requested type\\n\"\n+\t\t\t\t  \"matched the provide short SHA1 %s\"), ds.hex_pfx);\n+\t\t}\n \t}\n \n \treturn status;\ndiff --git a/t/t1512-rev-parse-disambiguation.sh b/t/t1512-rev-parse-disambiguation.sh\nindex b17973a266..940f323ee9 100755\n--- a/t/t1512-rev-parse-disambiguation.sh\n+++ b/t/t1512-rev-parse-disambiguation.sh\n@@ -359,7 +359,10 @@ test_expect_success C_LOCALE_OUTPUT 'failed type-selector still shows hint' '\n \techo 872 | git hash-object --stdin -w &&\n \ttest_must_fail git rev-parse ee3d^{commit} 2>stderr &&\n \tgrep ^hint: stderr >hints &&\n-\ttest_line_count = 3 hints\n+\ttest_line_count = 3 hints &&\n+\tgrep ^warning stderr >warnings &&\n+\tgrep -q \"Your hint.*was ignored\" warnings &&\n+\tgrep -q \"the provide short SHA1 ee3d\" stderr\n '\n \n test_expect_success 'core.disambiguate config can prefer types' '\n-- \n2.17.0.290.gded63e768a\n\n"},{"id":"346262","messageId":"20180501120651.15886-12-avarab@gmail.com","threadId":"48389","inReplyTo":"20180501120651.15886-1-avarab@gmail.com","subject":"[PATCH v2 11/12] config doc: document core.disambiguate","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2018-05-01T12:06:50Z","receivedAt":"2018-05-01T12:07:54Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"The core.disambiguate variable was added in\n5b33cb1fd7 (\"get_short_sha1: make default disambiguation\nconfigurable\", 2016-09-27) but never documented.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n Documentation/config.txt | 13 +++++++++++++\n 1 file changed, 13 insertions(+)\n\ndiff --git a/Documentation/config.txt b/Documentation/config.txt\nindex 2659153cb3..14a3d57e77 100644\n--- a/Documentation/config.txt\n+++ b/Documentation/config.txt\n@@ -910,6 +910,19 @@ core.abbrev::\n \tabbreviated object names to stay unique for some time.\n \tThe minimum length is 4.\n \n+core.disambiguate::\n+\tIf Git is given a SHA-1 that's ambigous it'll suggest what\n+\tobjects you might mean. By default it'll print out all\n+\tpotential objects with that prefix regardless of their\n+\ttype. This setting, along with the `^{<type>}` peel syntax\n+\t(see linkgit:gitrevisions[7]), allows for narrowing that down.\n++\n+Is set to `none` by default to show all object types. Can also be\n+`commit` (peel syntax: `$sha1^{commit}`), `committish` (commits and\n+tags), `tree` (peel: `$sha1^{tree}`), `treeish` (everything except\n+blobs, peel syntax: `$sha1:`), `blob` (peel: `$sha1^{blob}`) or `tag`\n+(peel: `$sha1^{tag}`). The peel syntax will override any config value.\n+\n add.ignoreErrors::\n add.ignore-errors (deprecated)::\n \tTells 'git add' to continue adding files when some files cannot be\n-- \n2.17.0.290.gded63e768a\n\n"},{"id":"346263","messageId":"20180501120651.15886-9-avarab@gmail.com","threadId":"48389","inReplyTo":"20180501120651.15886-1-avarab@gmail.com","subject":"[PATCH v2 08/12] get_short_oid: learn to disambiguate by ^{blob}","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2018-05-01T12:06:47Z","receivedAt":"2018-05-01T12:07:58Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"The disambiguation logic had all the pieces necessary to only print\nout those blobs that were ambiguous, but they hadn't been connected.\n\nThe initial logic was added in daba53aeaf (\"sha1_name.c: add support\nfor disambiguating other types\", 2012-07-02), and when the flags were\npropagated in 8a10fea49b (\"get_sha1: propagate flags to child\nfunctions\", 2016-09-26) GET_OID_BLOB wasn't added to lookup_flags.\n\nBefore this change requests for blobs were simply ignored:\n\n    $ git rev-parse e8f2^{blob}\n    error: short SHA1 e8f2 is ambiguous\n    hint: The candidates are:\n    hint:   e8f2650052 tag v2.17.0\n    hint:   e8f21caf94 commit 2013-06-24 - bash prompt: print unique detached HEAD abbreviated object name\n    hint:   e8f26250fa commit 2017-02-03 - Merge pull request #996 from jeffhostetler/jeffhostetler/register_rename_src\n    hint:   e8f2bc0c06 commit 2015-05-10 - Documentation: note behavior for multiple remote.url entries\n    hint:   e8f2093055 tree\n    hint:   e8f25a3a50 tree\n    hint:   e8f28d537c tree\n    hint:   e8f2cf6ec0 tree\n    hint:   e8f21d02f7 blob\n    hint:   e8f21d577c blob\n    hint:   e8f2867228 blob\n    hint:   e8f2a35526 blob\n    e8f2^{blob}\n    [...]\n\nBut now we'll do the right thing and only print the blobs:\n\n    $ git rev-parse e8f2^{blob}\n    error: short SHA1 e8f2 is ambiguous\n    hint: The candidates are:\n    hint:   e8f21d02f7 blob\n    hint:   e8f21d577c blob\n    hint:   e8f2867228 blob\n    hint:   e8f2a35526 blob\n    e8f2^{blob}\n    [...]\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n sha1-name.c                         | 2 ++\n t/t1512-rev-parse-disambiguation.sh | 6 +++++-\n 2 files changed, 7 insertions(+), 1 deletion(-)\n\ndiff --git a/sha1-name.c b/sha1-name.c\nindex 68d5f65362..023f9471a8 100644\n--- a/sha1-name.c\n+++ b/sha1-name.c\n@@ -971,6 +971,8 @@ static int peel_onion(const char *name, int len, struct object_id *oid,\n \t\tlookup_flags |= GET_OID_TAG;\n \telse if (expected_type == OBJ_TREE)\n \t\tlookup_flags |= GET_OID_TREEISH;\n+\telse if (expected_type == OBJ_BLOB)\n+\t\tlookup_flags |= GET_OID_BLOB;\n \n \tif (get_oid_1(name, sp - name - 2, &outer, lookup_flags))\n \t\treturn -1;\ndiff --git a/t/t1512-rev-parse-disambiguation.sh b/t/t1512-rev-parse-disambiguation.sh\nindex 74e7d9c178..9ce9cc3bc3 100755\n--- a/t/t1512-rev-parse-disambiguation.sh\n+++ b/t/t1512-rev-parse-disambiguation.sh\n@@ -337,7 +337,11 @@ test_expect_success C_LOCALE_OUTPUT 'ambiguity hints respect type' '\n \ttest_line_count = 7 hints &&\n \tgit rev-parse 000000000^{tag} >stdout &&\n \ttest_line_count = 1 stdout &&\n-\tgrep -q ^0000000000f8f stdout\n+\tgrep -q ^0000000000f8f stdout &&\n+\ttest_must_fail git rev-parse 000000000^{blob} 2>stderr &&\n+\tgrep ^hint: stderr >hints &&\n+\t# 5 blobs plus intro line &&\n+\ttest_line_count = 6 hints\n '\n \n test_expect_success C_LOCALE_OUTPUT 'failed type-selector still shows hint' '\n-- \n2.17.0.290.gded63e768a\n\n"},{"id":"346268","messageId":"348f193f-47bb-112f-6ef5-571749bb01e2@gmail.com","threadId":"48389","inReplyTo":"87a7tjzkdm.fsf@evledraar.gmail.com","subject":"Re: [PATCH 4/9] get_short_oid: sort ambiguous objects by type, then SHA-1","fromName":"Derrick Stolee","fromEmail":"stolee@gmail.com","sentAt":"2018-05-01T12:26:47Z","receivedAt":"2018-05-01T12:26:52Z","isPatch":true,"sender":{"key":"stolee@gmail.com","avatar":"https://avatars.githubusercontent.com/u/570044?v=4"},"body":"On 5/1/2018 7:27 AM, Ævar Arnfjörð Bjarmason wrote:\n> On Tue, May 01 2018, Derrick Stolee wrote:\n>\n>> On 4/30/2018 6:07 PM, Ævar Arnfjörð Bjarmason wrote:\n>>> Since we show the commit data in the output that's nicely aligned once\n>>> we sort by object type. The decision to show tags before commits is\n>>> pretty arbitrary, but it's much less likely that we'll display a tag,\n>>> so if there is one it makes sense to show it first.\n>> Here's a non-arbitrary reason: the object types are ordered\n>> topologically (ignoring self-references):\n>>\n>> tag -> commit, tree, blob\n>> commit -> tree\n>> tree -> blob\n> Thanks. I'll add a patch with that comment to v2.\n>\n>>> @@ -421,7 +451,12 @@ static int get_short_oid(const char *name, int len, struct object_id *oid,\n>>>    \t\t\tds.fn = NULL;\n>>>      \t\tadvise(_(\"The candidates are:\"));\n>>> -\t\tfor_each_abbrev(ds.hex_pfx, show_ambiguous_object, &ds);\n>>> +\t\tfor_each_abbrev(ds.hex_pfx, collect_ambiguous, &collect);\n>>> +\t\tQSORT(collect.oid, collect.nr, sort_ambiguous);\n>> I was wondering how the old code sorted by SHA even when the ambiguous\n>> objects were loaded from different sources (multiple pack-files, loose\n>> objects). Turns out that for_each_abbrev() does its own sort after\n>> collecting the SHAs and then calls the given function pointer only\n>> once per distinct object. This avoids multiple instances of the same\n>> object, which may appear multiple times across pack-files.\n>>\n>> I only ask because now we are doing two sorts. I wonder if it would be\n>> more elegant to provide your sorting algorithm to for_each_abbrev()\n>> and let it call show_ambiguous_object as before.\n>>\n>> Another question is if we should use this sort generally for all calls\n>> to for_each_abbrev(). The only other case I see is in\n>> builtin/revparse.c.\n> When preparing v2 I realized how confusing this was, so I'd added this\n> to the commit message of my WIP re-roll which should explain this:\n>\n>      A note on the implementation: I started out with something much\n>      simpler which just replaced oid_array_sort() in sha1-array.c with a\n>      custom sort function before calling oid_array_for_each_unique(). But\n>      then dumbly noticed that it doesn't work because the output function\n>      was tangled up with the code added in fad6b9e590 (\"for_each_abbrev:\n>      drop duplicate objects\", 2016-09-26) to ensure we don't display\n>      duplicate objects.\n>      \n>      That's why we're doing two passes here, first we need to sort the list\n>      and de-duplicate the objects, then sort them in our custom order, and\n>      finally output them without re-sorting them. I suppose we could also\n>      make oid_array_for_each_unique() maintain a hashmap of emitted\n>      objects, but that would increase its memory profile and wouldn't be\n>      worth the complexity for this one-off use-case,\n>      oid_array_for_each_unique() is used in many other places.\n\nHow would sorting in our custom order before de-duplicating fail the \nde-duplication? We will still pair identical OIDs as consecutive \nelements and oid_array_for_each_unique only cares about consecutive \nelements having distinct OIDs, not lex-ordered OIDs.\n\nPerhaps the noise is because we rely on oid_array_sort() to mark the \narray as sorted inside oid_array_for_each_unique(), but that could be \nremedied by calling our QSORT() inside for_each_abbrev() and marking the \narray as sorted before calling oid_array_for_each_unique().\n\n(Again, my comments are not meant to block this series.)\n\nThanks,\n-Stolee\n"},{"id":"346269","messageId":"878t93zh60.fsf@evledraar.gmail.com","threadId":"48389","inReplyTo":"348f193f-47bb-112f-6ef5-571749bb01e2@gmail.com","subject":"Re: [PATCH 4/9] get_short_oid: sort ambiguous objects by type, then SHA-1","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2018-05-01T12:36:39Z","receivedAt":"2018-05-01T12:36:46Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"\nOn Tue, May 01 2018, Derrick Stolee wrote:\n\n> On 5/1/2018 7:27 AM, Ævar Arnfjörð Bjarmason wrote:\n>> On Tue, May 01 2018, Derrick Stolee wrote:\n>>\n>>> On 4/30/2018 6:07 PM, Ævar Arnfjörð Bjarmason wrote:\n>>>> Since we show the commit data in the output that's nicely aligned once\n>>>> we sort by object type. The decision to show tags before commits is\n>>>> pretty arbitrary, but it's much less likely that we'll display a tag,\n>>>> so if there is one it makes sense to show it first.\n>>> Here's a non-arbitrary reason: the object types are ordered\n>>> topologically (ignoring self-references):\n>>>\n>>> tag -> commit, tree, blob\n>>> commit -> tree\n>>> tree -> blob\n>> Thanks. I'll add a patch with that comment to v2.\n>>\n>>>> @@ -421,7 +451,12 @@ static int get_short_oid(const char *name, int len, struct object_id *oid,\n>>>>    \t\t\tds.fn = NULL;\n>>>>      \t\tadvise(_(\"The candidates are:\"));\n>>>> -\t\tfor_each_abbrev(ds.hex_pfx, show_ambiguous_object, &ds);\n>>>> +\t\tfor_each_abbrev(ds.hex_pfx, collect_ambiguous, &collect);\n>>>> +\t\tQSORT(collect.oid, collect.nr, sort_ambiguous);\n>>> I was wondering how the old code sorted by SHA even when the ambiguous\n>>> objects were loaded from different sources (multiple pack-files, loose\n>>> objects). Turns out that for_each_abbrev() does its own sort after\n>>> collecting the SHAs and then calls the given function pointer only\n>>> once per distinct object. This avoids multiple instances of the same\n>>> object, which may appear multiple times across pack-files.\n>>>\n>>> I only ask because now we are doing two sorts. I wonder if it would be\n>>> more elegant to provide your sorting algorithm to for_each_abbrev()\n>>> and let it call show_ambiguous_object as before.\n>>>\n>>> Another question is if we should use this sort generally for all calls\n>>> to for_each_abbrev(). The only other case I see is in\n>>> builtin/revparse.c.\n>> When preparing v2 I realized how confusing this was, so I'd added this\n>> to the commit message of my WIP re-roll which should explain this:\n>>\n>>      A note on the implementation: I started out with something much\n>>      simpler which just replaced oid_array_sort() in sha1-array.c with a\n>>      custom sort function before calling oid_array_for_each_unique(). But\n>>      then dumbly noticed that it doesn't work because the output function\n>>      was tangled up with the code added in fad6b9e590 (\"for_each_abbrev:\n>>      drop duplicate objects\", 2016-09-26) to ensure we don't display\n>>      duplicate objects.\n>>           That's why we're doing two passes here, first we need to\n>> sort the list\n>>      and de-duplicate the objects, then sort them in our custom order, and\n>>      finally output them without re-sorting them. I suppose we could also\n>>      make oid_array_for_each_unique() maintain a hashmap of emitted\n>>      objects, but that would increase its memory profile and wouldn't be\n>>      worth the complexity for this one-off use-case,\n>>      oid_array_for_each_unique() is used in many other places.\n>\n> How would sorting in our custom order before de-duplicating fail the\n> de-duplication? We will still pair identical OIDs as consecutive\n> elements and oid_array_for_each_unique only cares about consecutive\n> elements having distinct OIDs, not lex-ordered OIDs.\n\nBecause there's no de-duplication without the array first being sorted\nin oidcmp() order, which oid_array_for_each_unique() checks for and\nre-sorts if !array->sorted. I.e. its de-duplication is just a state\nmachine where it won't call the callback if the currently processed\nelement has the same SHA1 as the last one.\n\n> Perhaps the noise is because we rely on oid_array_sort() to mark the\n> array as sorted inside oid_array_for_each_unique(), but that could be\n> remedied by calling our QSORT() inside for_each_abbrev() and marking\n> the array as sorted before calling oid_array_for_each_unique().\n\nAs noted above this won't work, because the function inherently relies\non the array being sorted to be able to de-duplicate. Doing this will\nyield duplicate entries.\n"},{"id":"346285","messageId":"20180501130318.58251-1-dstolee@microsoft.com","threadId":"48389","inReplyTo":"20180501120651.15886-1-avarab@gmail.com","subject":"[PATCH v2 06/11] get_short_oid: sort ambiguous objects by type, then SHA-1","fromName":"Derrick Stolee","fromEmail":"dstolee@microsoft.com","sentAt":"2018-05-01T13:03:28Z","receivedAt":"2018-05-01T13:03:35Z","isPatch":true,"sender":{"key":"stolee@gmail.com","avatar":"https://avatars.githubusercontent.com/u/570044?v=4"},"body":"From: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n\nHere is what I mean by sorting during for_each_abbrev(). This seems to work for\nme, so I don't know what the issue is with this one-pass approach.\n\nThanks,\n-Stolee\n\n-- >8 --\n\nChange the output emitted when an ambiguous object is encountered so\nthat we show tags first, then commits, followed by trees, and finally\nblobs. Within each type we show objects in hashcmp() order. Before\nthis change the objects were only ordered by hashcmp().\n\nThe reason for doing this is that the output looks better as a result,\ne.g. the v2.17.0 tag before this change on \"git show e8f2\" would\ndisplay:\n\n    hint: The candidates are:\n    hint:   e8f2093055 tree\n    hint:   e8f21caf94 commit 2013-06-24 - bash prompt: print unique detached HEAD abbreviated object name\n    hint:   e8f21d02f7 blob\n    hint:   e8f21d577c blob\n    hint:   e8f25a3a50 tree\n    hint:   e8f26250fa commit 2017-02-03 - Merge pull request #996 from jeffhostetler/jeffhostetler/register_rename_src\n    hint:   e8f2650052 tag v2.17.0\n    hint:   e8f2867228 blob\n    hint:   e8f28d537c tree\n    hint:   e8f2a35526 blob\n    hint:   e8f2bc0c06 commit 2015-05-10 - Documentation: note behavior for multiple remote.url entries\n    hint:   e8f2cf6ec0 tree\n\nNow we'll instead show:\n\n    hint:   e8f2650052 tag v2.17.0\n    hint:   e8f21caf94 commit 2013-06-24 - bash prompt: print unique detached HEAD abbreviated object name\n    hint:   e8f26250fa commit 2017-02-03 - Merge pull request #996 from jeffhostetler/jeffhostetler/register_rename_src\n    hint:   e8f2bc0c06 commit 2015-05-10 - Documentation: note behavior for multiple remote.url entries\n    hint:   e8f2093055 tree\n    hint:   e8f25a3a50 tree\n    hint:   e8f28d537c tree\n    hint:   e8f2cf6ec0 tree\n    hint:   e8f21d02f7 blob\n    hint:   e8f21d577c blob\n    hint:   e8f2867228 blob\n    hint:   e8f2a35526 blob\n\nSince we show the commit data in the output that's nicely aligned once\nwe sort by object type. The decision to show tags before commits is\npretty arbitrary. I don't want to order by object_type since there\ntags come last after blobs, which doesn't make sense if we want to\nshow the most important things first.\n\nI could display them after commits, but it's much less likely that\nwe'll display a tag, so if there is one it makes sense to show it\nprominently at the top.\n\nSigned-off-by: Ã†var ArnfjÃ¶rÃ° Bjarmason <avarab@gmail.com>\nSigned-off-by: Derrick Stolee <dstolee@microsoft.com>\n---\n sha1-name.c                         | 31 +++++++++++++++++++++++++++++\n t/t1512-rev-parse-disambiguation.sh | 21 +++++++++++++++++++\n 2 files changed, 52 insertions(+)\n\ndiff --git a/sha1-name.c b/sha1-name.c\nindex 5deebab56d..0336630c64 100644\n--- a/sha1-name.c\n+++ b/sha1-name.c\n@@ -385,6 +385,34 @@ static int collect_ambiguous(const struct object_id *oid, void *data)\n \treturn 0;\n }\n \n+static int sort_ambiguous(const void *a, const void *b)\n+{\n+\tint a_type = oid_object_info(a, NULL);\n+\tint b_type = oid_object_info(b, NULL);\n+\tint a_type_sort;\n+\tint b_type_sort;\n+\n+\t/*\n+\t * Sorts by hash within the same object type, just as\n+\t * oid_array_for_each_unique() would do.\n+\t */\n+\tif (a_type == b_type)\n+\t\treturn oidcmp(a, b);\n+\n+\t/*\n+\t * Between object types show tags, then commits, and finally\n+\t * trees and blobs.\n+\t *\n+\t * The object_type enum is commit, tree, blob, tag, but we\n+\t * want tag, commit, tree blob. Cleverly (perhaps too\n+\t * cleverly) do that with modulus, since the enum assigns 1 to\n+\t * commit, so tag becomes 0.\n+\t */\n+\ta_type_sort = a_type % 4;\n+\tb_type_sort = b_type % 4;\n+\treturn a_type_sort > b_type_sort ? 1 : -1;\n+}\n+\n static int get_short_oid(const char *name, int len, struct object_id *oid,\n \t\t\t  unsigned flags)\n {\n@@ -451,6 +479,9 @@ int for_each_abbrev(const char *prefix, each_abbrev_fn fn, void *cb_data)\n \tfind_short_object_filename(&ds);\n \tfind_short_packed_object(&ds);\n \n+\tQSORT(collect.oid, collect.nr, sort_ambiguous);\n+\tcollect.sorted = 1;\n+\n \tret = oid_array_for_each_unique(&collect, fn, cb_data);\n \toid_array_clear(&collect);\n \treturn ret;\ndiff --git a/t/t1512-rev-parse-disambiguation.sh b/t/t1512-rev-parse-disambiguation.sh\nindex c7ceda2f21..74e7d9c178 100755\n--- a/t/t1512-rev-parse-disambiguation.sh\n+++ b/t/t1512-rev-parse-disambiguation.sh\n@@ -364,4 +364,25 @@ test_expect_success 'core.disambiguate does not override context' '\n \t\tgit -c core.disambiguate=committish rev-parse $sha1^{tree}\n '\n \n+test_expect_success C_LOCALE_OUTPUT 'ambiguous commits are printed by type first, then hash order' '\n+\ttest_must_fail git rev-parse 0000 2>stderr &&\n+\tgrep ^hint: stderr >hints &&\n+\tgrep 0000 hints >objects &&\n+\tcat >expected <<-\\EOF &&\n+\ttag\n+\tcommit\n+\ttree\n+\tblob\n+\tEOF\n+\tawk \"{print \\$3}\" <objects >objects.types &&\n+\tuniq <objects.types >objects.types.uniq &&\n+\ttest_cmp expected objects.types.uniq &&\n+\tfor type in tag commit tree blob\n+\tdo\n+\t\tgrep $type objects >$type.objects &&\n+\t\tsort $type.objects >$type.objects.sorted &&\n+\t\ttest_cmp $type.objects.sorted $type.objects\n+\tdone\n+'\n+\n test_done\n-- \n2.17.0.39.g685157f7fb\n\n"},{"id":"346286","messageId":"9245fe83-a3f7-c978-b260-4097ce5a99f5@gmail.com","threadId":"48389","inReplyTo":"878t93zh60.fsf@evledraar.gmail.com","subject":"Re: [PATCH 4/9] get_short_oid: sort ambiguous objects by type, then SHA-1","fromName":"Derrick Stolee","fromEmail":"stolee@gmail.com","sentAt":"2018-05-01T13:05:15Z","receivedAt":"2018-05-01T13:05:20Z","isPatch":true,"sender":{"key":"stolee@gmail.com","avatar":"https://avatars.githubusercontent.com/u/570044?v=4"},"body":"On 5/1/2018 8:36 AM, Ævar Arnfjörð Bjarmason wrote:\n> On Tue, May 01 2018, Derrick Stolee wrote:\n>\n>> How would sorting in our custom order before de-duplicating fail the\n>> de-duplication? We will still pair identical OIDs as consecutive\n>> elements and oid_array_for_each_unique only cares about consecutive\n>> elements having distinct OIDs, not lex-ordered OIDs.\n> Because there's no de-duplication without the array first being sorted\n> in oidcmp() order, which oid_array_for_each_unique() checks for and\n> re-sorts if !array->sorted. I.e. its de-duplication is just a state\n> machine where it won't call the callback if the currently processed\n> element has the same SHA1 as the last one.\n>\n>> Perhaps the noise is because we rely on oid_array_sort() to mark the\n>> array as sorted inside oid_array_for_each_unique(), but that could be\n>> remedied by calling our QSORT() inside for_each_abbrev() and marking\n>> the array as sorted before calling oid_array_for_each_unique().\n> As noted above this won't work, because the function inherently relies\n> on the array being sorted to be able to de-duplicate. Doing this will\n> yield duplicate entries.\n\nI'm confused as to why my suggestion doesn't work, so I made it \nconcrete. I sent an alternate commit 6/12 to your v2 series [1].\n\nThanks,\n-Stolee\n\n[1] \nhttps://public-inbox.org/git/20180501130318.58251-1-dstolee@microsoft.com/T/#u\n"},{"id":"346287","messageId":"876047ze9v.fsf@evledraar.gmail.com","threadId":"48389","inReplyTo":"20180501130318.58251-1-dstolee@microsoft.com","subject":"Re: [PATCH v2 06/11] get_short_oid: sort ambiguous objects by type, then SHA-1","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2018-05-01T13:39:08Z","receivedAt":"2018-05-01T13:39:17Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"\nOn Tue, May 01 2018, Derrick Stolee wrote:\n\n> From: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n>\n> Here is what I mean by sorting during for_each_abbrev(). This seems to work for\n> me, so I don't know what the issue is with this one-pass approach.\n> [...]\n> +static int sort_ambiguous(const void *a, const void *b)\n> +{\n> +\tint a_type = oid_object_info(a, NULL);\n> +\tint b_type = oid_object_info(b, NULL);\n> +\tint a_type_sort;\n> +\tint b_type_sort;\n> +\n> +\t/*\n> +\t * Sorts by hash within the same object type, just as\n> +\t * oid_array_for_each_unique() would do.\n> +\t */\n> +\tif (a_type == b_type)\n> +\t\treturn oidcmp(a, b);\n> +\n> +\t/*\n> +\t * Between object types show tags, then commits, and finally\n> +\t * trees and blobs.\n> +\t *\n> +\t * The object_type enum is commit, tree, blob, tag, but we\n> +\t * want tag, commit, tree blob. Cleverly (perhaps too\n> +\t * cleverly) do that with modulus, since the enum assigns 1 to\n> +\t * commit, so tag becomes 0.\n> +\t */\n> +\ta_type_sort = a_type % 4;\n> +\tb_type_sort = b_type % 4;\n> +\treturn a_type_sort > b_type_sort ? 1 : -1;\n> +}\n> +\n>  static int get_short_oid(const char *name, int len, struct object_id *oid,\n>  \t\t\t  unsigned flags)\n>  {\n> @@ -451,6 +479,9 @@ int for_each_abbrev(const char *prefix, each_abbrev_fn fn, void *cb_data)\n>  \tfind_short_object_filename(&ds);\n>  \tfind_short_packed_object(&ds);\n>\n> +\tQSORT(collect.oid, collect.nr, sort_ambiguous);\n> +\tcollect.sorted = 1;\n> +\n\nYes this works. You're right. I wasn't trying to intentionally omit\nstuff in my recent 878t93zh60.fsf@evledraar.gmail.com, I'd just written\nthis code some days ago and forgotten why I did what I was doing (and\nthis is hard to test for), but it's all coming back to me now.\n\nThe actual requirement for oid_array_for_each_unique() working properly\nis that you've got to feed it in hash order, but my new sort_ambiguous()\nstill does that (barring any SHA-1 collisions, at which point we have\nbigger problems), so two passes aren't needed. So yes, this apporoach\nworks and is one-pass.\n\nBut that's just an implementation detail of the current sort method,\nwhen I wrote this I was initially playing with other sort orders,\ne.g. sorting SHAs regardless of type by the mtime of the file I found\nthem in. With this approach I'd start printing duplicates if I changed\nthe internals of sort_ambiguous() like that.\n\nBut I think it's extremely implausible that we'll start sorting things\nlike that, so I'll just take this method of doing it and add some\ncomment saying we must hashcmp() the entries in our own sort function\nfor the de-duplication to work, I don't see us ever changing that.\n"},{"id":"346288","messageId":"40868abd-6d2f-3f05-e099-6f0d06cc0683@gmail.com","threadId":"48389","inReplyTo":"876047ze9v.fsf@evledraar.gmail.com","subject":"Re: [PATCH v2 06/11] get_short_oid: sort ambiguous objects by type, then SHA-1","fromName":"Derrick Stolee","fromEmail":"stolee@gmail.com","sentAt":"2018-05-01T13:44:52Z","receivedAt":"2018-05-01T13:45:00Z","isPatch":true,"sender":{"key":"stolee@gmail.com","avatar":"https://avatars.githubusercontent.com/u/570044?v=4"},"body":"\n\nOn 5/1/2018 9:39 AM, Ævar Arnfjörð Bjarmason wrote:\n> On Tue, May 01 2018, Derrick Stolee wrote:\n>\n>> From: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n>>\n>> Here is what I mean by sorting during for_each_abbrev(). This seems to work for\n>> me, so I don't know what the issue is with this one-pass approach.\n>> [...]\n>> +static int sort_ambiguous(const void *a, const void *b)\n>> +{\n>> +\tint a_type = oid_object_info(a, NULL);\n>> +\tint b_type = oid_object_info(b, NULL);\n>> +\tint a_type_sort;\n>> +\tint b_type_sort;\n>> +\n>> +\t/*\n>> +\t * Sorts by hash within the same object type, just as\n>> +\t * oid_array_for_each_unique() would do.\n>> +\t */\n>> +\tif (a_type == b_type)\n>> +\t\treturn oidcmp(a, b);\n>> +\n>> +\t/*\n>> +\t * Between object types show tags, then commits, and finally\n>> +\t * trees and blobs.\n>> +\t *\n>> +\t * The object_type enum is commit, tree, blob, tag, but we\n>> +\t * want tag, commit, tree blob. Cleverly (perhaps too\n>> +\t * cleverly) do that with modulus, since the enum assigns 1 to\n>> +\t * commit, so tag becomes 0.\n>> +\t */\n>> +\ta_type_sort = a_type % 4;\n>> +\tb_type_sort = b_type % 4;\n>> +\treturn a_type_sort > b_type_sort ? 1 : -1;\n>> +}\n>> +\n>>   static int get_short_oid(const char *name, int len, struct object_id *oid,\n>>   \t\t\t  unsigned flags)\n>>   {\n>> @@ -451,6 +479,9 @@ int for_each_abbrev(const char *prefix, each_abbrev_fn fn, void *cb_data)\n>>   \tfind_short_object_filename(&ds);\n>>   \tfind_short_packed_object(&ds);\n>>\n>> +\tQSORT(collect.oid, collect.nr, sort_ambiguous);\n>> +\tcollect.sorted = 1;\n>> +\n> Yes this works. You're right. I wasn't trying to intentionally omit\n> stuff in my recent 878t93zh60.fsf@evledraar.gmail.com, I'd just written\n> this code some days ago and forgotten why I did what I was doing (and\n> this is hard to test for), but it's all coming back to me now.\n>\n> The actual requirement for oid_array_for_each_unique() working properly\n> is that you've got to feed it in hash order,\n\nTo work properly, duplicate entries must be consecutive. Since duplicate \nentries have the same type, our sort satisfies this condition.\n\n> but my new sort_ambiguous()\n> still does that (barring any SHA-1 collisions, at which point we have\n> bigger problems), so two passes aren't needed. So yes, this apporoach\n> works and is one-pass.\n>\n> But that's just an implementation detail of the current sort method,\n> when I wrote this I was initially playing with other sort orders,\n> e.g. sorting SHAs regardless of type by the mtime of the file I found\n> them in. With this approach I'd start printing duplicates if I changed\n> the internals of sort_ambiguous() like that.\n\nThat makes sense.\n\n> But I think it's extremely implausible that we'll start sorting things\n> like that, so I'll just take this method of doing it and add some\n> comment saying we must hashcmp() the entries in our own sort function\n> for the de-duplication to work, I don't see us ever changing that.\n\nSounds good.\n\nThanks,\n-Stolee\n"},{"id":"346290","messageId":"874ljrzctc.fsf@evledraar.gmail.com","threadId":"48389","inReplyTo":"40868abd-6d2f-3f05-e099-6f0d06cc0683@gmail.com","subject":"Re: [PATCH v2 06/11] get_short_oid: sort ambiguous objects by type, then SHA-1","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2018-05-01T14:10:39Z","receivedAt":"2018-05-01T14:10:48Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"\nOn Tue, May 01 2018, Derrick Stolee wrote:\n\n> On 5/1/2018 9:39 AM, Ævar Arnfjörð Bjarmason wrote:\n>> On Tue, May 01 2018, Derrick Stolee wrote:\n>>\n>>> From: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n>>>\n>>> Here is what I mean by sorting during for_each_abbrev(). This seems to work for\n>>> me, so I don't know what the issue is with this one-pass approach.\n>>> [...]\n>>> +static int sort_ambiguous(const void *a, const void *b)\n>>> +{\n>>> +\tint a_type = oid_object_info(a, NULL);\n>>> +\tint b_type = oid_object_info(b, NULL);\n>>> +\tint a_type_sort;\n>>> +\tint b_type_sort;\n>>> +\n>>> +\t/*\n>>> +\t * Sorts by hash within the same object type, just as\n>>> +\t * oid_array_for_each_unique() would do.\n>>> +\t */\n>>> +\tif (a_type == b_type)\n>>> +\t\treturn oidcmp(a, b);\n>>> +\n>>> +\t/*\n>>> +\t * Between object types show tags, then commits, and finally\n>>> +\t * trees and blobs.\n>>> +\t *\n>>> +\t * The object_type enum is commit, tree, blob, tag, but we\n>>> +\t * want tag, commit, tree blob. Cleverly (perhaps too\n>>> +\t * cleverly) do that with modulus, since the enum assigns 1 to\n>>> +\t * commit, so tag becomes 0.\n>>> +\t */\n>>> +\ta_type_sort = a_type % 4;\n>>> +\tb_type_sort = b_type % 4;\n>>> +\treturn a_type_sort > b_type_sort ? 1 : -1;\n>>> +}\n>>> +\n>>>   static int get_short_oid(const char *name, int len, struct object_id *oid,\n>>>   \t\t\t  unsigned flags)\n>>>   {\n>>> @@ -451,6 +479,9 @@ int for_each_abbrev(const char *prefix, each_abbrev_fn fn, void *cb_data)\n>>>   \tfind_short_object_filename(&ds);\n>>>   \tfind_short_packed_object(&ds);\n>>>\n>>> +\tQSORT(collect.oid, collect.nr, sort_ambiguous);\n>>> +\tcollect.sorted = 1;\n>>> +\n>> Yes this works. You're right. I wasn't trying to intentionally omit\n>> stuff in my recent 878t93zh60.fsf@evledraar.gmail.com, I'd just written\n>> this code some days ago and forgotten why I did what I was doing (and\n>> this is hard to test for), but it's all coming back to me now.\n>>\n>> The actual requirement for oid_array_for_each_unique() working properly\n>> is that you've got to feed it in hash order,\n>\n> To work properly, duplicate entries must be consecutive. Since\n> duplicate entries have the same type, our sort satisfies this\n> condition.\n>\n>> but my new sort_ambiguous()\n>> still does that (barring any SHA-1 collisions, at which point we have\n>> bigger problems), so two passes aren't needed. So yes, this apporoach\n>> works and is one-pass.\n>>\n>> But that's just an implementation detail of the current sort method,\n>> when I wrote this I was initially playing with other sort orders,\n>> e.g. sorting SHAs regardless of type by the mtime of the file I found\n>> them in. With this approach I'd start printing duplicates if I changed\n>> the internals of sort_ambiguous() like that.\n>\n> That makes sense.\n>\n>> But I think it's extremely implausible that we'll start sorting things\n>> like that, so I'll just take this method of doing it and add some\n>> comment saying we must hashcmp() the entries in our own sort function\n>> for the de-duplication to work, I don't see us ever changing that.\n>\n> Sounds good.\n\nActually I'm having second thoughts about that and thinking I might keep\nmy original approach (with a better explanation).\n\nA few more lines of code seems worthwhile in order to not break the\nassumptions a documented API is making, no matter how briefly, so I set\nabout documenting this case and supporting it, since\ne.g. oid_array_lookup() will completely fail with the hack of setting\nthe .sorted member, and came up with this:\n\ndiff --git a/Documentation/technical/api-oid-array.txt b/Documentation/technical/api-oid-array.txt\nindex b0c11f868d..ff87260220 100644\n--- a/Documentation/technical/api-oid-array.txt\n+++ b/Documentation/technical/api-oid-array.txt\n@@ -16,6 +16,20 @@ Data Structures\n \tthe actual data. The `nr` member contains the number of items in\n \tthe set.  The `alloc` and `sorted` members are used internally,\n \tand should not be needed by API callers.\n++\n+Both the `oid_array_lookup` and `oid_array_for_each_unique` functions\n+rely on the array being sorted. For the former it's an absolute\n+requirenment that the internal `oid_array_sort` function has been\n+called on it, bu for the latter it's enough that the elements are\n+ordered in such a way as to guarantee that identical object IDs are\n+adjacent in the array.\n++\n+This is useful e.g. to print output where commits, tags etc. are\n+grouped together (barring a hash collision they won't have the same\n+object ID), in such cases the `custom_sorted` member can be set to `1`\n+before calling `oid_array_for_each_unique`, and it'll skip its own\n+sorting. Once it's been set calling e.g. `oid_array_lookup` without it\n+being cleared again will cause an internal panic, so use it carefully.\n\n Functions\n ---------\ndiff --git a/sha1-array.c b/sha1-array.c\nindex 466a926aa3..cbae07ff78 100644\n--- a/sha1-array.c\n+++ b/sha1-array.c\n@@ -18,6 +18,7 @@ static void oid_array_sort(struct oid_array *array)\n {\n \tQSORT(array->oid, array->nr, void_hashcmp);\n \tarray->sorted = 1;\n+\tarray->custom_sorted = 0;\n }\n\n static const unsigned char *sha1_access(size_t index, void *table)\n@@ -28,6 +29,13 @@ static const unsigned char *sha1_access(size_t index, void *table)\n\n int oid_array_lookup(struct oid_array *array, const struct object_id *oid)\n {\n+\tif (array->custom_sorted)\n+\t\t/*\n+\t\t * We could also just clear custom_sorted here, but if\n+\t\t * the caller is custom sorting and then calling this\n+\t\t * that's likely something they'd like to know about.\n+\t\t */\n+\t\tBUG(\"PANIC: Cannot lookup OIDs in arrays with a custom sort!\");\n \tif (!array->sorted)\n \t\toid_array_sort(array);\n \treturn sha1_pos(oid->hash, array->oid, array->nr, sha1_access);\n@@ -39,6 +47,7 @@ void oid_array_clear(struct oid_array *array)\n \tarray->nr = 0;\n \tarray->alloc = 0;\n \tarray->sorted = 0;\n+\tarray->custom_sorted = 0;\n }\n\n int oid_array_for_each_unique(struct oid_array *array,\n@@ -47,7 +56,7 @@ int oid_array_for_each_unique(struct oid_array *array,\n {\n \tint i;\n\n-\tif (!array->sorted)\n+\tif (!array->sorted && !array->custom_sorted)\n \t\toid_array_sort(array);\n\n \tfor (i = 0; i < array->nr; i++) {\ndiff --git a/sha1-array.h b/sha1-array.h\nindex 1e1d24b009..bfa77ba1e4 100644\n--- a/sha1-array.h\n+++ b/sha1-array.h\n@@ -6,6 +6,7 @@ struct oid_array {\n \tint nr;\n \tint alloc;\n \tint sorted;\n+\tint custom_sorted;\n };\n\n #define OID_ARRAY_INIT { NULL, 0, 0, 0 }\ndiff --git a/sha1-name.c b/sha1-name.c\nindex b81e07adbb..d190800db0 100644\n--- a/sha1-name.c\n+++ b/sha1-name.c\n@@ -490,9 +490,11 @@ int for_each_abbrev(const char *prefix, each_abbrev_fn fn, void *cb_data)\n \tfind_short_packed_object(&ds);\n\n \tQSORT(collect.oid, collect.nr, sort_ambiguous);\n-\tcollect.sorted = 1;\n\n+\tcollect.custom_sorted = 1;\n \tret = oid_array_for_each_unique(&collect, fn, cb_data);\n+\tcollect.custom_sorted = 0;\n+\n \toid_array_clear(&collect);\n \treturn ret;\n }\n\nSo maybe I should just stop worrying and YOLO it, it just seems wrong to\nleave such a fragile setup in place where we set .sorted=1 and some\nfuture refactoring reasonably tries to call oid_array_lookup() on it and\nsilently fails.\n\nWhat do you think?\n"},{"id":"346291","messageId":"00b64485-44ef-709c-2f9d-56e790ca3a5e@gmail.com","threadId":"48389","inReplyTo":"874ljrzctc.fsf@evledraar.gmail.com","subject":"Re: [PATCH v2 06/11] get_short_oid: sort ambiguous objects by type, then SHA-1","fromName":"Derrick Stolee","fromEmail":"stolee@gmail.com","sentAt":"2018-05-01T14:15:23Z","receivedAt":"2018-05-01T14:15:30Z","isPatch":true,"sender":{"key":"stolee@gmail.com","avatar":"https://avatars.githubusercontent.com/u/570044?v=4"},"body":"On 5/1/2018 10:10 AM, Ævar Arnfjörð Bjarmason wrote:\n> Actually I'm having second thoughts about that and thinking I might keep\n> my original approach (with a better explanation).\n>\n> A few more lines of code seems worthwhile in order to not break the\n> assumptions a documented API is making, no matter how briefly, so I set\n> about documenting this case and supporting it, since\n> e.g. oid_array_lookup() will completely fail with the hack of setting\n> the .sorted member, and came up with this:\n>\n> diff --git a/Documentation/technical/api-oid-array.txt b/Documentation/technical/api-oid-array.txt\n> index b0c11f868d..ff87260220 100644\n> --- a/Documentation/technical/api-oid-array.txt\n> +++ b/Documentation/technical/api-oid-array.txt\n> @@ -16,6 +16,20 @@ Data Structures\n>   \tthe actual data. The `nr` member contains the number of items in\n>   \tthe set.  The `alloc` and `sorted` members are used internally,\n>   \tand should not be needed by API callers.\n> ++\n> +Both the `oid_array_lookup` and `oid_array_for_each_unique` functions\n> +rely on the array being sorted. For the former it's an absolute\n> +requirenment that the internal `oid_array_sort` function has been\n> +called on it, bu for the latter it's enough that the elements are\n> +ordered in such a way as to guarantee that identical object IDs are\n> +adjacent in the array.\n\ns/bu/but/\n\n> ++\n> +This is useful e.g. to print output where commits, tags etc. are\n> +grouped together (barring a hash collision they won't have the same\n> +object ID), in such cases the `custom_sorted` member can be set to `1`\n> +before calling `oid_array_for_each_unique`, and it'll skip its own\n> +sorting. Once it's been set calling e.g. `oid_array_lookup` without it\n> +being cleared again will cause an internal panic, so use it carefully.\n>\n>   Functions\n>   ---------\n> diff --git a/sha1-array.c b/sha1-array.c\n> index 466a926aa3..cbae07ff78 100644\n> --- a/sha1-array.c\n> +++ b/sha1-array.c\n> @@ -18,6 +18,7 @@ static void oid_array_sort(struct oid_array *array)\n>   {\n>   \tQSORT(array->oid, array->nr, void_hashcmp);\n>   \tarray->sorted = 1;\n> +\tarray->custom_sorted = 0;\n>   }\n>\n>   static const unsigned char *sha1_access(size_t index, void *table)\n> @@ -28,6 +29,13 @@ static const unsigned char *sha1_access(size_t index, void *table)\n>\n>   int oid_array_lookup(struct oid_array *array, const struct object_id *oid)\n>   {\n> +\tif (array->custom_sorted)\n> +\t\t/*\n> +\t\t * We could also just clear custom_sorted here, but if\n> +\t\t * the caller is custom sorting and then calling this\n> +\t\t * that's likely something they'd like to know about.\n> +\t\t */\n> +\t\tBUG(\"PANIC: Cannot lookup OIDs in arrays with a custom sort!\");\n\nProbably don't need the \"PANIC: \" here.\n\n>   \tif (!array->sorted)\n>   \t\toid_array_sort(array);\n>   \treturn sha1_pos(oid->hash, array->oid, array->nr, sha1_access);\n> @@ -39,6 +47,7 @@ void oid_array_clear(struct oid_array *array)\n>   \tarray->nr = 0;\n>   \tarray->alloc = 0;\n>   \tarray->sorted = 0;\n> +\tarray->custom_sorted = 0;\n>   }\n>\n>   int oid_array_for_each_unique(struct oid_array *array,\n> @@ -47,7 +56,7 @@ int oid_array_for_each_unique(struct oid_array *array,\n>   {\n>   \tint i;\n>\n> -\tif (!array->sorted)\n> +\tif (!array->sorted && !array->custom_sorted)\n>   \t\toid_array_sort(array);\n>\n>   \tfor (i = 0; i < array->nr; i++) {\n> diff --git a/sha1-array.h b/sha1-array.h\n> index 1e1d24b009..bfa77ba1e4 100644\n> --- a/sha1-array.h\n> +++ b/sha1-array.h\n> @@ -6,6 +6,7 @@ struct oid_array {\n>   \tint nr;\n>   \tint alloc;\n>   \tint sorted;\n> +\tint custom_sorted;\n>   };\n>\n>   #define OID_ARRAY_INIT { NULL, 0, 0, 0 }\n> diff --git a/sha1-name.c b/sha1-name.c\n> index b81e07adbb..d190800db0 100644\n> --- a/sha1-name.c\n> +++ b/sha1-name.c\n> @@ -490,9 +490,11 @@ int for_each_abbrev(const char *prefix, each_abbrev_fn fn, void *cb_data)\n>   \tfind_short_packed_object(&ds);\n>\n>   \tQSORT(collect.oid, collect.nr, sort_ambiguous);\n> -\tcollect.sorted = 1;\n>\n> +\tcollect.custom_sorted = 1;\n>   \tret = oid_array_for_each_unique(&collect, fn, cb_data);\n> +\tcollect.custom_sorted = 0;\n> +\n>   \toid_array_clear(&collect);\n>   \treturn ret;\n>   }\n>\n> So maybe I should just stop worrying and YOLO it, it just seems wrong to\n> leave such a fragile setup in place where we set .sorted=1 and some\n> future refactoring reasonably tries to call oid_array_lookup() on it and\n> silently fails.\n>\n> What do you think?\nI think this extra custom_sort check is worth keeping the API stable to \nfuture changes.\n\nThanks,\n-Stolee\n"},{"id":"346307","messageId":"20180501184016.15061-1-avarab@gmail.com","threadId":"48389","inReplyTo":"20180501120651.15886-1-avarab@gmail.com","subject":"[PATCH v3 00/12] get_short_oid UI improvements","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2018-05-01T18:40:04Z","receivedAt":"2018-05-01T18:40:36Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Comments inline:\n\nÆvar Arnfjörð Bjarmason (12):\n  sha1-name.c: remove stray newline\n\nNo changes.\n\n  sha1-array.h: align function arguments\n\nMention the correct commit to blame for disalignment in the commit\nmessage, and also fix it in the *.c file.\n\n  git-p4: change \"commitish\" typo to \"committish\"\n\nNo changes.\n\n  cache.h: add comment explaining the order in object_type\n\nTrivial commit message rewording.\n\n  sha1-name.c: move around the collect_ambiguous() function\n\nNo changes.\n\n  get_short_oid: sort ambiguous objects by type, then SHA-1\n\nThe biggest change in v3 is the no change at all to the code, but a\nlengthy explanation of why I didn't go for Derrick's simpler\nimplementation. Maybe I'm wrong about that, but I felt uneasy\noffloading undocumented (or if I documented it, it would only be for\nthis one edge-case) magic on the oid_array API. Instead I'm just\nmaking this patch a bit more complex.\n\n  get_short_oid: learn to disambiguate by ^{tag}\n  get_short_oid: learn to disambiguate by ^{blob}\n  get_short_oid / peel_onion: ^{tree} should be tree, not treeish\n  get_short_oid / peel_onion: ^{commit} should be commit, not committish\n  config doc: document core.disambiguate\n  get_short_oid: document & warn if we ignore the type selector\n\nNo changes except one trivial commit message formatting fix.\n\n Documentation/config.txt                  | 17 +++++\n Documentation/technical/api-oid-array.txt | 17 +++--\n cache.h                                   | 13 +++-\n git-p4.py                                 |  6 +-\n sha1-array.c                              | 21 +++++-\n sha1-array.h                              |  7 +-\n sha1-name.c                               | 80 +++++++++++++++++++----\n t/t1512-rev-parse-disambiguation.sh       | 58 +++++++++++++---\n 8 files changed, 184 insertions(+), 35 deletions(-)\n\n-- \n2.17.0.290.gded63e768a\n\n"},{"id":"346308","messageId":"20180501184016.15061-2-avarab@gmail.com","threadId":"48389","inReplyTo":"20180501184016.15061-1-avarab@gmail.com","subject":"[PATCH v3 01/12] sha1-name.c: remove stray newline","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2018-05-01T18:40:05Z","receivedAt":"2018-05-01T18:40:40Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"This stray newline was accidentally introduced in\nd2b7d9c7ed (\"sha1_name: convert disambiguate_hint_fn to take\nobject_id\", 2017-03-26).\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n sha1-name.c | 1 -\n 1 file changed, 1 deletion(-)\n\ndiff --git a/sha1-name.c b/sha1-name.c\nindex 5b93bf8da3..cd3b133aae 100644\n--- a/sha1-name.c\n+++ b/sha1-name.c\n@@ -346,7 +346,6 @@ static int show_ambiguous_object(const struct object_id *oid, void *data)\n \tstruct strbuf desc = STRBUF_INIT;\n \tint type;\n \n-\n \tif (ds->fn && !ds->fn(oid, ds->cb_data))\n \t\treturn 0;\n \n-- \n2.17.0.290.gded63e768a\n\n"},{"id":"346309","messageId":"20180501184016.15061-3-avarab@gmail.com","threadId":"48389","inReplyTo":"20180501184016.15061-1-avarab@gmail.com","subject":"[PATCH v3 02/12] sha1-array.h: align function arguments","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2018-05-01T18:40:06Z","receivedAt":"2018-05-01T18:40:42Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"The arguments weren't lined up with the opening parenthesis. Fixes up\ncode added in aae0caf19e (\"sha1-array.h: align function arguments\",\n2018-04-30).\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n sha1-array.c | 4 ++--\n sha1-array.h | 4 ++--\n 2 files changed, 4 insertions(+), 4 deletions(-)\n\ndiff --git a/sha1-array.c b/sha1-array.c\nindex 838b3bf847..466a926aa3 100644\n--- a/sha1-array.c\n+++ b/sha1-array.c\n@@ -42,8 +42,8 @@ void oid_array_clear(struct oid_array *array)\n }\n \n int oid_array_for_each_unique(struct oid_array *array,\n-\t\t\t\tfor_each_oid_fn fn,\n-\t\t\t\tvoid *data)\n+\t\t\t      for_each_oid_fn fn,\n+\t\t\t      void *data)\n {\n \tint i;\n \ndiff --git a/sha1-array.h b/sha1-array.h\nindex 04b0756334..1e1d24b009 100644\n--- a/sha1-array.h\n+++ b/sha1-array.h\n@@ -17,7 +17,7 @@ void oid_array_clear(struct oid_array *array);\n typedef int (*for_each_oid_fn)(const struct object_id *oid,\n \t\t\t       void *data);\n int oid_array_for_each_unique(struct oid_array *array,\n-\t\t\t       for_each_oid_fn fn,\n-\t\t\t       void *data);\n+\t\t\t      for_each_oid_fn fn,\n+\t\t\t      void *data);\n \n #endif /* SHA1_ARRAY_H */\n-- \n2.17.0.290.gded63e768a\n\n"},{"id":"346310","messageId":"20180501184016.15061-5-avarab@gmail.com","threadId":"48389","inReplyTo":"20180501184016.15061-1-avarab@gmail.com","subject":"[PATCH v3 04/12] cache.h: add comment explaining the order in object_type","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2018-05-01T18:40:08Z","receivedAt":"2018-05-01T18:40:46Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"The order in the enum might seem arbitrary, and isn't explained by\n72518e9c26 (\"more lightweight revalidation while reusing deflated\nstream in packing\", 2006-09-03) which added it.\n\nDerrick Stolee suggested that it's ordered topologically in\n5f8b1ec1-258d-1acc-133e-a7c248b4083e@gmail.com. Makes sense to me, add\nthat as a comment.\n\nHelped-by: Derrick Stolee <dstolee@microsoft.com>\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n cache.h | 8 ++++++++\n 1 file changed, 8 insertions(+)\n\ndiff --git a/cache.h b/cache.h\nindex 77b7acebb6..354903c3ea 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -376,6 +376,14 @@ extern void free_name_hash(struct index_state *istate);\n enum object_type {\n \tOBJ_BAD = -1,\n \tOBJ_NONE = 0,\n+\t/*\n+\t * Why have our our \"real\" object types in this order? They're\n+\t * ordered topologically:\n+\t *\n+\t * tag(4)    -> commit(1), tree(2), blob(3)\n+\t * commit(1) -> tree(2)\n+\t * tree(2)   -> blob(3)\n+\t */\n \tOBJ_COMMIT = 1,\n \tOBJ_TREE = 2,\n \tOBJ_BLOB = 3,\n-- \n2.17.0.290.gded63e768a\n\n"},{"id":"346311","messageId":"20180501184016.15061-4-avarab@gmail.com","threadId":"48389","inReplyTo":"20180501184016.15061-1-avarab@gmail.com","subject":"[PATCH v3 03/12] git-p4: change \"commitish\" typo to \"committish\"","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2018-05-01T18:40:07Z","receivedAt":"2018-05-01T18:40:49Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"This was the only occurrence of \"commitish\" in the tree, but as the\nlog will reveal we've had others in the past. Fixes up code added in\n00ad6e3182 (\"git-p4: work with a detached head\", 2015-11-21).\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n git-p4.py | 6 +++---\n 1 file changed, 3 insertions(+), 3 deletions(-)\n\ndiff --git a/git-p4.py b/git-p4.py\nindex 7bb9cadc69..1afa87cd9d 100755\n--- a/git-p4.py\n+++ b/git-p4.py\n@@ -2099,11 +2099,11 @@ class P4Submit(Command, P4UserMap):\n \n         commits = []\n         if self.master:\n-            commitish = self.master\n+            committish = self.master\n         else:\n-            commitish = 'HEAD'\n+            committish = 'HEAD'\n \n-        for line in read_pipe_lines([\"git\", \"rev-list\", \"--no-merges\", \"%s..%s\" % (self.origin, commitish)]):\n+        for line in read_pipe_lines([\"git\", \"rev-list\", \"--no-merges\", \"%s..%s\" % (self.origin, committish)]):\n             commits.append(line.strip())\n         commits.reverse()\n \n-- \n2.17.0.290.gded63e768a\n\n"},{"id":"346312","messageId":"20180501184016.15061-6-avarab@gmail.com","threadId":"48389","inReplyTo":"20180501184016.15061-1-avarab@gmail.com","subject":"[PATCH v3 05/12] sha1-name.c: move around the collect_ambiguous() function","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2018-05-01T18:40:09Z","receivedAt":"2018-05-01T18:40:52Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"A subsequent change will make use of this static function in the\nget_short_oid() function, which is defined above where the\ncollect_ambiguous() function is now. Without this we'd then have a\ncompilation error due to a forward declaration.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n sha1-name.c | 12 ++++++------\n 1 file changed, 6 insertions(+), 6 deletions(-)\n\ndiff --git a/sha1-name.c b/sha1-name.c\nindex cd3b133aae..9d7bbd3e96 100644\n--- a/sha1-name.c\n+++ b/sha1-name.c\n@@ -372,6 +372,12 @@ static int show_ambiguous_object(const struct object_id *oid, void *data)\n \treturn 0;\n }\n \n+static int collect_ambiguous(const struct object_id *oid, void *data)\n+{\n+\toid_array_append(data, oid);\n+\treturn 0;\n+}\n+\n static int get_short_oid(const char *name, int len, struct object_id *oid,\n \t\t\t  unsigned flags)\n {\n@@ -421,12 +427,6 @@ static int get_short_oid(const char *name, int len, struct object_id *oid,\n \treturn status;\n }\n \n-static int collect_ambiguous(const struct object_id *oid, void *data)\n-{\n-\toid_array_append(data, oid);\n-\treturn 0;\n-}\n-\n int for_each_abbrev(const char *prefix, each_abbrev_fn fn, void *cb_data)\n {\n \tstruct oid_array collect = OID_ARRAY_INIT;\n-- \n2.17.0.290.gded63e768a\n\n"},{"id":"346313","messageId":"20180501184016.15061-9-avarab@gmail.com","threadId":"48389","inReplyTo":"20180501184016.15061-1-avarab@gmail.com","subject":"[PATCH v3 08/12] get_short_oid: learn to disambiguate by ^{blob}","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2018-05-01T18:40:12Z","receivedAt":"2018-05-01T18:40:56Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"The disambiguation logic had all the pieces necessary to only print\nout those blobs that were ambiguous, but they hadn't been connected.\n\nThe initial logic was added in daba53aeaf (\"sha1_name.c: add support\nfor disambiguating other types\", 2012-07-02), and when the flags were\npropagated in 8a10fea49b (\"get_sha1: propagate flags to child\nfunctions\", 2016-09-26) GET_OID_BLOB wasn't added to lookup_flags.\n\nBefore this change requests for blobs were simply ignored:\n\n    $ git rev-parse e8f2^{blob}\n    error: short SHA1 e8f2 is ambiguous\n    hint: The candidates are:\n    hint:   e8f2650052 tag v2.17.0\n    hint:   e8f21caf94 commit 2013-06-24 - bash prompt: print unique detached HEAD abbreviated object name\n    hint:   e8f26250fa commit 2017-02-03 - Merge pull request #996 from jeffhostetler/jeffhostetler/register_rename_src\n    hint:   e8f2bc0c06 commit 2015-05-10 - Documentation: note behavior for multiple remote.url entries\n    hint:   e8f2093055 tree\n    hint:   e8f25a3a50 tree\n    hint:   e8f28d537c tree\n    hint:   e8f2cf6ec0 tree\n    hint:   e8f21d02f7 blob\n    hint:   e8f21d577c blob\n    hint:   e8f2867228 blob\n    hint:   e8f2a35526 blob\n    e8f2^{blob}\n    [...]\n\nBut now we'll do the right thing and only print the blobs:\n\n    $ git rev-parse e8f2^{blob}\n    error: short SHA1 e8f2 is ambiguous\n    hint: The candidates are:\n    hint:   e8f21d02f7 blob\n    hint:   e8f21d577c blob\n    hint:   e8f2867228 blob\n    hint:   e8f2a35526 blob\n    e8f2^{blob}\n    [...]\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n sha1-name.c                         | 2 ++\n t/t1512-rev-parse-disambiguation.sh | 6 +++++-\n 2 files changed, 7 insertions(+), 1 deletion(-)\n\ndiff --git a/sha1-name.c b/sha1-name.c\nindex 68d5f65362..023f9471a8 100644\n--- a/sha1-name.c\n+++ b/sha1-name.c\n@@ -971,6 +971,8 @@ static int peel_onion(const char *name, int len, struct object_id *oid,\n \t\tlookup_flags |= GET_OID_TAG;\n \telse if (expected_type == OBJ_TREE)\n \t\tlookup_flags |= GET_OID_TREEISH;\n+\telse if (expected_type == OBJ_BLOB)\n+\t\tlookup_flags |= GET_OID_BLOB;\n \n \tif (get_oid_1(name, sp - name - 2, &outer, lookup_flags))\n \t\treturn -1;\ndiff --git a/t/t1512-rev-parse-disambiguation.sh b/t/t1512-rev-parse-disambiguation.sh\nindex 74e7d9c178..9ce9cc3bc3 100755\n--- a/t/t1512-rev-parse-disambiguation.sh\n+++ b/t/t1512-rev-parse-disambiguation.sh\n@@ -337,7 +337,11 @@ test_expect_success C_LOCALE_OUTPUT 'ambiguity hints respect type' '\n \ttest_line_count = 7 hints &&\n \tgit rev-parse 000000000^{tag} >stdout &&\n \ttest_line_count = 1 stdout &&\n-\tgrep -q ^0000000000f8f stdout\n+\tgrep -q ^0000000000f8f stdout &&\n+\ttest_must_fail git rev-parse 000000000^{blob} 2>stderr &&\n+\tgrep ^hint: stderr >hints &&\n+\t# 5 blobs plus intro line &&\n+\ttest_line_count = 6 hints\n '\n \n test_expect_success C_LOCALE_OUTPUT 'failed type-selector still shows hint' '\n-- \n2.17.0.290.gded63e768a\n\n"},{"id":"346314","messageId":"20180501184016.15061-10-avarab@gmail.com","threadId":"48389","inReplyTo":"20180501184016.15061-1-avarab@gmail.com","subject":"[PATCH v3 09/12] get_short_oid / peel_onion: ^{tree} should be tree, not treeish","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2018-05-01T18:40:13Z","receivedAt":"2018-05-01T18:40:58Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"After the recent series of patches ^{tag} and ^{blob} now work to get\njust the tags and blobs, but ^{tree} will still list any\ntree-ish (commits, tags and trees).\n\nThe previous behavior was added in ed1ca6025f (\"peel_onion:\ndisambiguate to favor tree-ish when we know we want a tree-ish\",\n2013-03-31). I may have missed some special-case but this makes more\nsense to me.\n\nNow \"$sha1:\" can be used as before to mean treeish:\n\n    $ git rev-parse e8f2:\n    error: short SHA1 e8f2 is ambiguous\n    hint: The candidates are:\n    hint:   e8f2650052 tag v2.17.0\n    hint:   e8f21caf94 commit 2013-06-24 - bash prompt: print unique detached HEAD abbreviated object name\n    hint:   e8f26250fa commit 2017-02-03 - Merge pull request #996 from jeffhostetler/jeffhostetler/register_rename_src\n    hint:   e8f2bc0c06 commit 2015-05-10 - Documentation: note behavior for multiple remote.url entries\n    hint:   e8f2093055 tree\n    hint:   e8f25a3a50 tree\n    hint:   e8f28d537c tree\n    hint:   e8f2cf6ec0 tree\n    [...]\n\nBut ^{tree} shows just the trees, but would previously be equivalent\nto the above:\n\n    $ git rev-parse e8f2^{tree}\n    error: short SHA1 e8f2 is ambiguous\n    hint: The candidates are:\n    hint:   e8f2093055 tree\n    hint:   e8f25a3a50 tree\n    hint:   e8f28d537c tree\n    hint:   e8f2cf6ec0 tree\n    [...]\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n sha1-name.c                         |  2 +-\n t/t1512-rev-parse-disambiguation.sh | 18 ++++++++++++++----\n 2 files changed, 15 insertions(+), 5 deletions(-)\n\ndiff --git a/sha1-name.c b/sha1-name.c\nindex 023f9471a8..b61c0558d9 100644\n--- a/sha1-name.c\n+++ b/sha1-name.c\n@@ -970,7 +970,7 @@ static int peel_onion(const char *name, int len, struct object_id *oid,\n \telse if (expected_type == OBJ_TAG)\n \t\tlookup_flags |= GET_OID_TAG;\n \telse if (expected_type == OBJ_TREE)\n-\t\tlookup_flags |= GET_OID_TREEISH;\n+\t\tlookup_flags |= GET_OID_TREE;\n \telse if (expected_type == OBJ_BLOB)\n \t\tlookup_flags |= GET_OID_BLOB;\n \ndiff --git a/t/t1512-rev-parse-disambiguation.sh b/t/t1512-rev-parse-disambiguation.sh\nindex 9ce9cc3bc3..81076449a2 100755\n--- a/t/t1512-rev-parse-disambiguation.sh\n+++ b/t/t1512-rev-parse-disambiguation.sh\n@@ -159,9 +159,13 @@ test_expect_failure 'two semi-ambiguous commit-ish' '\n \tgit log 0000000000...\n '\n \n-test_expect_failure 'three semi-ambiguous tree-ish' '\n+test_expect_success '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+\ttest_must_fail git rev-parse --verify 0000000000: &&\n+\n+\t# For ^{tree} we can disambiguate because HEAD and v1.0.0 will\n+\t# be excluded.\n \tgit rev-parse --verify 0000000000^{tree}\n '\n \n@@ -267,8 +271,12 @@ test_expect_success 'ambiguous commit-ish' '\n # There are three objects with this prefix: a blob, a tree, and a tag. We know\n # the blob will not pass as a treeish, but the tree and tag should (and thus\n # cause an error).\n-test_expect_success 'ambiguous tags peel to treeish' '\n-\ttest_must_fail git rev-parse 0000000000f^{tree}\n+test_expect_success 'ambiguous tags peel to treeish or tree' '\n+\ttest_must_fail git rev-parse 0000000000f: &&\n+\tgit rev-parse 0000000000f^{tree} >stdout &&\n+\ttest_line_count = 1 stdout &&\n+\tgrep -q ^0000000000fd8bcc56 stdout\n+\n '\n \n test_expect_success 'rev-parse --disambiguate' '\n@@ -365,7 +373,9 @@ test_expect_success 'core.disambiguate config can prefer types' '\n test_expect_success 'core.disambiguate does not override context' '\n \t# treeish ambiguous between tag and tree\n \ttest_must_fail \\\n-\t\tgit -c core.disambiguate=committish rev-parse $sha1^{tree}\n+\t\tgit -c core.disambiguate=committish rev-parse $sha1: &&\n+\t# tree not ambiguous between tag and tree\n+\tgit -c core.disambiguate=committish rev-parse $sha1^{tree}\n '\n \n test_expect_success C_LOCALE_OUTPUT 'ambiguous commits are printed by type first, then hash order' '\n-- \n2.17.0.290.gded63e768a\n\n"},{"id":"346315","messageId":"20180501184016.15061-11-avarab@gmail.com","threadId":"48389","inReplyTo":"20180501184016.15061-1-avarab@gmail.com","subject":"[PATCH v3 10/12] get_short_oid / peel_onion: ^{commit} should be commit, not committish","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2018-05-01T18:40:14Z","receivedAt":"2018-05-01T18:41:01Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Change the ^{commit} syntax to mean just commits instead of committish\nfor the purpose of disambiguation. Before this e8f2^{commit} would\nshow the v2.17.0 tag as a disambiguation candidate, but now it'll just\nshow ambiguous commits:\n\n    $ git rev-parse e8f2^{commit}\n    error: short SHA1 e8f2 is ambiguous\n    hint: The candidates are:\n    hint:   e8f21caf94 commit 2013-06-24 - bash prompt: print unique detached HEAD abbreviated object name\n    hint:   e8f26250fa commit 2017-02-03 - Merge pull request #996 from jeffhostetler/jeffhostetler/register_rename_src\n    hint:   e8f2bc0c06 commit 2015-05-10 - Documentation: note behavior for multiple remote.url entries\n    [...]\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n sha1-name.c                         | 2 +-\n t/t1512-rev-parse-disambiguation.sh | 7 ++++---\n 2 files changed, 5 insertions(+), 4 deletions(-)\n\ndiff --git a/sha1-name.c b/sha1-name.c\nindex b61c0558d9..1d2a74a29c 100644\n--- a/sha1-name.c\n+++ b/sha1-name.c\n@@ -966,7 +966,7 @@ static int peel_onion(const char *name, int len, struct object_id *oid,\n \n \tlookup_flags &= ~GET_OID_DISAMBIGUATORS;\n \tif (expected_type == OBJ_COMMIT)\n-\t\tlookup_flags |= GET_OID_COMMITTISH;\n+\t\tlookup_flags |= GET_OID_COMMIT;\n \telse if (expected_type == OBJ_TAG)\n \t\tlookup_flags |= GET_OID_TAG;\n \telse if (expected_type == OBJ_TREE)\ndiff --git a/t/t1512-rev-parse-disambiguation.sh b/t/t1512-rev-parse-disambiguation.sh\nindex 81076449a2..b17973a266 100755\n--- a/t/t1512-rev-parse-disambiguation.sh\n+++ b/t/t1512-rev-parse-disambiguation.sh\n@@ -341,8 +341,8 @@ test_expect_success C_LOCALE_OUTPUT 'ambiguity hints' '\n test_expect_success C_LOCALE_OUTPUT 'ambiguity hints respect type' '\n \ttest_must_fail git rev-parse 000000000^{commit} 2>stderr &&\n \tgrep ^hint: stderr >hints &&\n-\t# 5 commits, 1 tag (which is a commitish), plus intro line\n-\ttest_line_count = 7 hints &&\n+\t# 5 commits plus intro line\n+\ttest_line_count = 6 hints &&\n \tgit rev-parse 000000000^{tag} >stdout &&\n \ttest_line_count = 1 stdout &&\n \tgrep -q ^0000000000f8f stdout &&\n@@ -366,7 +366,8 @@ test_expect_success 'core.disambiguate config can prefer types' '\n \t# ambiguous between tree and tag\n \tsha1=0000000000f &&\n \ttest_must_fail git rev-parse $sha1 &&\n-\tgit rev-parse $sha1^{commit} &&\n+\t# there is no commit so ^{commit} comes up empty\n+\ttest_must_fail git rev-parse $sha1^{commit} &&\n \tgit -c core.disambiguate=committish rev-parse $sha1\n '\n \n-- \n2.17.0.290.gded63e768a\n\n"},{"id":"346316","messageId":"20180501184016.15061-12-avarab@gmail.com","threadId":"48389","inReplyTo":"20180501184016.15061-1-avarab@gmail.com","subject":"[PATCH v3 11/12] config doc: document core.disambiguate","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2018-05-01T18:40:15Z","receivedAt":"2018-05-01T18:41:16Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"The core.disambiguate variable was added in\n5b33cb1fd7 (\"get_short_sha1: make default disambiguation\nconfigurable\", 2016-09-27) but never documented.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n Documentation/config.txt | 13 +++++++++++++\n 1 file changed, 13 insertions(+)\n\ndiff --git a/Documentation/config.txt b/Documentation/config.txt\nindex 2659153cb3..14a3d57e77 100644\n--- a/Documentation/config.txt\n+++ b/Documentation/config.txt\n@@ -910,6 +910,19 @@ core.abbrev::\n \tabbreviated object names to stay unique for some time.\n \tThe minimum length is 4.\n \n+core.disambiguate::\n+\tIf Git is given a SHA-1 that's ambigous it'll suggest what\n+\tobjects you might mean. By default it'll print out all\n+\tpotential objects with that prefix regardless of their\n+\ttype. This setting, along with the `^{<type>}` peel syntax\n+\t(see linkgit:gitrevisions[7]), allows for narrowing that down.\n++\n+Is set to `none` by default to show all object types. Can also be\n+`commit` (peel syntax: `$sha1^{commit}`), `committish` (commits and\n+tags), `tree` (peel: `$sha1^{tree}`), `treeish` (everything except\n+blobs, peel syntax: `$sha1:`), `blob` (peel: `$sha1^{blob}`) or `tag`\n+(peel: `$sha1^{tag}`). The peel syntax will override any config value.\n+\n add.ignoreErrors::\n add.ignore-errors (deprecated)::\n \tTells 'git add' to continue adding files when some files cannot be\n-- \n2.17.0.290.gded63e768a\n\n"},{"id":"346317","messageId":"20180501184016.15061-13-avarab@gmail.com","threadId":"48389","inReplyTo":"20180501184016.15061-1-avarab@gmail.com","subject":"[PATCH v3 12/12] get_short_oid: document & warn if we ignore the type selector","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2018-05-01T18:40:16Z","receivedAt":"2018-05-01T18:41:30Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"The SHA1 prefix 06fa currently matches no blobs in git.git. When\ndisambiguating short SHA1s we've been quietly ignoring the user's type\nselector as a fallback mechanism, this was intentionally added in\n1ffa26c461 (\"get_short_sha1: list ambiguous objects on error\",\n2016-09-26).\n\nI think that behavior makes sense, it's not very useful to just show\nnothing because a preference has been expressed via core.disambiguate,\nbut it's bad that we're quietly doing this. The user might thing that\nwe just didn't understand what e.g 06fa^{blob} meant.\n\nNow we'll instead print a warning if no objects of the requested type\nwere found:\n\n    $ git rev-parse 06fa^{blob}\n    error: short SHA1 06fa is ambiguous\n    hint: The candidates are:\n    [... no blobs listed ...]\n    warning: Your hint (via core.disambiguate or peel syntax) was ignored, we fell\n    back to showing all object types since no object of the requested type\n    matched the provide short SHA1 06fa\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n Documentation/config.txt            |  4 ++++\n sha1-name.c                         | 11 ++++++++++-\n t/t1512-rev-parse-disambiguation.sh |  5 ++++-\n 3 files changed, 18 insertions(+), 2 deletions(-)\n\ndiff --git a/Documentation/config.txt b/Documentation/config.txt\nindex 14a3d57e77..e14f2c0492 100644\n--- a/Documentation/config.txt\n+++ b/Documentation/config.txt\n@@ -922,6 +922,10 @@ Is set to `none` by default to show all object types. Can also be\n tags), `tree` (peel: `$sha1^{tree}`), `treeish` (everything except\n blobs, peel syntax: `$sha1:`), `blob` (peel: `$sha1^{blob}`) or `tag`\n (peel: `$sha1^{tag}`). The peel syntax will override any config value.\n++\n+If no objects of the selected type exist the disambiguation will fall\n+back to `none` and print a warning indicating no objects of the\n+selected type could be found for that prefix.\n \n add.ignoreErrors::\n add.ignore-errors (deprecated)::\ndiff --git a/sha1-name.c b/sha1-name.c\nindex 1d2a74a29c..9789764a38 100644\n--- a/sha1-name.c\n+++ b/sha1-name.c\n@@ -447,6 +447,7 @@ static int get_short_oid(const char *name, int len, struct object_id *oid,\n \n \tif (!quietly && (status == SHORT_NAME_AMBIGUOUS)) {\n \t\tstruct oid_array collect = OID_ARRAY_INIT;\n+\t\tint ignored_hint = 0;\n \n \t\terror(_(\"short SHA1 %s is ambiguous\"), ds.hex_pfx);\n \n@@ -456,8 +457,10 @@ static int get_short_oid(const char *name, int len, struct object_id *oid,\n \t\t * that case, we still want to show them, so disable the hint\n \t\t * function entirely.\n \t\t */\n-\t\tif (!ds.ambiguous)\n+\t\tif (!ds.ambiguous) {\n \t\t\tds.fn = NULL;\n+\t\t\tignored_hint = 1;\n+\t\t}\n \n \t\tadvise(_(\"The candidates are:\"));\n \t\tfor_each_abbrev(ds.hex_pfx, collect_ambiguous, &collect);\n@@ -466,6 +469,12 @@ static int get_short_oid(const char *name, int len, struct object_id *oid,\n \t\tif (oid_array_for_each(&collect, show_ambiguous_object, &ds))\n \t\t\tBUG(\"show_ambiguous_object shouldn't return non-zero\");\n \t\toid_array_clear(&collect);\n+\n+\t\tif (ignored_hint) {\n+\t\t\twarning(_(\"Your hint (via core.disambiguate or peel syntax) was ignored, we fell\\n\"\n+\t\t\t\t  \"back to showing all object types since no object of the requested type\\n\"\n+\t\t\t\t  \"matched the provide short SHA1 %s\"), ds.hex_pfx);\n+\t\t}\n \t}\n \n \treturn status;\ndiff --git a/t/t1512-rev-parse-disambiguation.sh b/t/t1512-rev-parse-disambiguation.sh\nindex b17973a266..940f323ee9 100755\n--- a/t/t1512-rev-parse-disambiguation.sh\n+++ b/t/t1512-rev-parse-disambiguation.sh\n@@ -359,7 +359,10 @@ test_expect_success C_LOCALE_OUTPUT 'failed type-selector still shows hint' '\n \techo 872 | git hash-object --stdin -w &&\n \ttest_must_fail git rev-parse ee3d^{commit} 2>stderr &&\n \tgrep ^hint: stderr >hints &&\n-\ttest_line_count = 3 hints\n+\ttest_line_count = 3 hints &&\n+\tgrep ^warning stderr >warnings &&\n+\tgrep -q \"Your hint.*was ignored\" warnings &&\n+\tgrep -q \"the provide short SHA1 ee3d\" stderr\n '\n \n test_expect_success 'core.disambiguate config can prefer types' '\n-- \n2.17.0.290.gded63e768a\n\n"},{"id":"346319","messageId":"20180501184016.15061-7-avarab@gmail.com","threadId":"48389","inReplyTo":"20180501184016.15061-1-avarab@gmail.com","subject":"[PATCH v3 06/12] get_short_oid: sort ambiguous objects by type, then SHA-1","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2018-05-01T18:40:10Z","receivedAt":"2018-05-01T18:41:43Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Change the output emitted when an ambiguous object is encountered so\nthat we show tags first, then commits, followed by trees, and finally\nblobs. Within each type we show objects in hashcmp() order. Before\nthis change the objects were only ordered by hashcmp().\n\nThe reason for doing this is that the output looks better as a result,\ne.g. the v2.17.0 tag before this change on \"git show e8f2\" would\ndisplay:\n\n    hint: The candidates are:\n    hint:   e8f2093055 tree\n    hint:   e8f21caf94 commit 2013-06-24 - bash prompt: print unique detached HEAD abbreviated object name\n    hint:   e8f21d02f7 blob\n    hint:   e8f21d577c blob\n    hint:   e8f25a3a50 tree\n    hint:   e8f26250fa commit 2017-02-03 - Merge pull request #996 from jeffhostetler/jeffhostetler/register_rename_src\n    hint:   e8f2650052 tag v2.17.0\n    hint:   e8f2867228 blob\n    hint:   e8f28d537c tree\n    hint:   e8f2a35526 blob\n    hint:   e8f2bc0c06 commit 2015-05-10 - Documentation: note behavior for multiple remote.url entries\n    hint:   e8f2cf6ec0 tree\n\nNow we'll instead show:\n\n    hint:   e8f2650052 tag v2.17.0\n    hint:   e8f21caf94 commit 2013-06-24 - bash prompt: print unique detached HEAD abbreviated object name\n    hint:   e8f26250fa commit 2017-02-03 - Merge pull request #996 from jeffhostetler/jeffhostetler/register_rename_src\n    hint:   e8f2bc0c06 commit 2015-05-10 - Documentation: note behavior for multiple remote.url entries\n    hint:   e8f2093055 tree\n    hint:   e8f25a3a50 tree\n    hint:   e8f28d537c tree\n    hint:   e8f2cf6ec0 tree\n    hint:   e8f21d02f7 blob\n    hint:   e8f21d577c blob\n    hint:   e8f2867228 blob\n    hint:   e8f2a35526 blob\n\nSince we show the commit data in the output that's nicely aligned once\nwe sort by object type. The decision to show tags before commits is\npretty arbitrary. I don't want to order by object_type since there\ntags come last after blobs, which doesn't make sense if we want to\nshow the most important things first.\n\nI could display them after commits, but it's much less likely that\nwe'll display a tag, so if there is one it makes sense to show it\nprominently at the top.\n\nA note on the implementation: Derrick rightly pointed out[1] that\nwe're bending over backwards here in get_short_oid() to first\nde-duplicate the list, and then emit it, but could simply do it in one\nstep.\n\nThe reason for that is that oid_array_for_each_unique() doesn't\nactually require that the array be sorted by oid_array_sort(), it just\nneeds to be sorted in some order that guarantees that all objects with\nthe same ID are adjacent to one another, which (barring a hash\ncollision, which'll be someone else's problem) the sort_ambiguous()\nfunction does.\n\nI agree that would be simpler for this code, and had forgotten why I\ninitially wrote it like this[2]. But on further reflection I think\nit's better to do more work here just so we're not underhandedly using\nthe oid-array API where we lie about the list being sorted. That would\nbreak any subsequent use of oid_array_lookup() in subtle ways.\n\nI could get around that by hacking the API itself to support this\nuse-case and documenting it, which I did as a WIP patch in [3], but I\nthink it's too much code smell just for this one call site. It's\nsimpler for the API to just introduce a oid_array_for_each() function\nto eagerly spew out the list without sorting or de-duplication, and\nthen do the de-duplication and sorting in two passes.\n\n1. https://public-inbox.org/git/20180501130318.58251-1-dstolee@microsoft.com/\n2. https://public-inbox.org/git/876047ze9v.fsf@evledraar.gmail.com/\n3. https://public-inbox.org/git/874ljrzctc.fsf@evledraar.gmail.com/\n\nHelped-by: Derrick Stolee <dstolee@microsoft.com>\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n Documentation/technical/api-oid-array.txt | 17 +++++++----\n sha1-array.c                              | 17 +++++++++++\n sha1-array.h                              |  3 ++\n sha1-name.c                               | 37 ++++++++++++++++++++++-\n t/t1512-rev-parse-disambiguation.sh       | 21 +++++++++++++\n 5 files changed, 88 insertions(+), 7 deletions(-)\n\ndiff --git a/Documentation/technical/api-oid-array.txt b/Documentation/technical/api-oid-array.txt\nindex b0c11f868d..94b529722c 100644\n--- a/Documentation/technical/api-oid-array.txt\n+++ b/Documentation/technical/api-oid-array.txt\n@@ -35,13 +35,18 @@ Functions\n \tFree all memory associated with the array and return it to the\n \tinitial, empty state.\n \n+`oid_array_for_each`::\n+\tIterate over each element of the list, executing the callback\n+\tfunction for each one. Does not sort the list, so any custom\n+\thash order is retained. If the callback returns a non-zero\n+\tvalue, the iteration ends immediately and the callback's\n+\treturn is propagated; otherwise, 0 is returned.\n+\n `oid_array_for_each_unique`::\n-\tEfficiently iterate over each unique element of the list,\n-\texecuting the callback function for each one. If the array is\n-\tnot sorted, this function has the side effect of sorting it. If\n-\tthe callback returns a non-zero value, the iteration ends\n-\timmediately and the callback's return is propagated; otherwise,\n-\t0 is returned.\n+\tIterate over each unique element of the list in sort order ,\n+\tbut otherwise behaves like `oid_array_for_each`. If the array\n+\tis not sorted, this function has the side effect of sorting\n+\tit.\n \n Examples\n --------\ndiff --git a/sha1-array.c b/sha1-array.c\nindex 466a926aa3..265941fbf4 100644\n--- a/sha1-array.c\n+++ b/sha1-array.c\n@@ -41,6 +41,23 @@ void oid_array_clear(struct oid_array *array)\n \tarray->sorted = 0;\n }\n \n+\n+int oid_array_for_each(struct oid_array *array,\n+\t\t       for_each_oid_fn fn,\n+\t\t       void *data)\n+{\n+\tint i;\n+\n+\t/* No oid_array_sort() here! See the api-oid-array.txt docs! */\n+\n+\tfor (i = 0; i < array->nr; i++) {\n+\t\tint ret = fn(array->oid + i, data);\n+\t\tif (ret)\n+\t\t\treturn ret;\n+\t}\n+\treturn 0;\n+}\n+\n int oid_array_for_each_unique(struct oid_array *array,\n \t\t\t      for_each_oid_fn fn,\n \t\t\t      void *data)\ndiff --git a/sha1-array.h b/sha1-array.h\nindex 1e1d24b009..232bf95017 100644\n--- a/sha1-array.h\n+++ b/sha1-array.h\n@@ -16,6 +16,9 @@ void oid_array_clear(struct oid_array *array);\n \n typedef int (*for_each_oid_fn)(const struct object_id *oid,\n \t\t\t       void *data);\n+int oid_array_for_each(struct oid_array *array,\n+\t\t       for_each_oid_fn fn,\n+\t\t       void *data);\n int oid_array_for_each_unique(struct oid_array *array,\n \t\t\t      for_each_oid_fn fn,\n \t\t\t      void *data);\ndiff --git a/sha1-name.c b/sha1-name.c\nindex 9d7bbd3e96..46d8b1afa6 100644\n--- a/sha1-name.c\n+++ b/sha1-name.c\n@@ -378,6 +378,34 @@ static int collect_ambiguous(const struct object_id *oid, void *data)\n \treturn 0;\n }\n \n+static int sort_ambiguous(const void *a, const void *b)\n+{\n+\tint a_type = oid_object_info(a, NULL);\n+\tint b_type = oid_object_info(b, NULL);\n+\tint a_type_sort;\n+\tint b_type_sort;\n+\n+\t/*\n+\t * Sorts by hash within the same object type, just as\n+\t * oid_array_for_each_unique() would do.\n+\t */\n+\tif (a_type == b_type)\n+\t\treturn oidcmp(a, b);\n+\n+\t/*\n+\t * Between object types show tags, then commits, and finally\n+\t * trees and blobs.\n+\t *\n+\t * The object_type enum is commit, tree, blob, tag, but we\n+\t * want tag, commit, tree blob. Cleverly (perhaps too\n+\t * cleverly) do that with modulus, since the enum assigns 1 to\n+\t * commit, so tag becomes 0.\n+\t */\n+\ta_type_sort = a_type % 4;\n+\tb_type_sort = b_type % 4;\n+\treturn a_type_sort > b_type_sort ? 1 : -1;\n+}\n+\n static int get_short_oid(const char *name, int len, struct object_id *oid,\n \t\t\t  unsigned flags)\n {\n@@ -409,6 +437,8 @@ static int get_short_oid(const char *name, int len, struct object_id *oid,\n \tstatus = finish_object_disambiguation(&ds, oid);\n \n \tif (!quietly && (status == SHORT_NAME_AMBIGUOUS)) {\n+\t\tstruct oid_array collect = OID_ARRAY_INIT;\n+\n \t\terror(_(\"short SHA1 %s is ambiguous\"), ds.hex_pfx);\n \n \t\t/*\n@@ -421,7 +451,12 @@ static int get_short_oid(const char *name, int len, struct object_id *oid,\n \t\t\tds.fn = NULL;\n \n \t\tadvise(_(\"The candidates are:\"));\n-\t\tfor_each_abbrev(ds.hex_pfx, show_ambiguous_object, &ds);\n+\t\tfor_each_abbrev(ds.hex_pfx, collect_ambiguous, &collect);\n+\t\tQSORT(collect.oid, collect.nr, sort_ambiguous);\n+\n+\t\tif (oid_array_for_each(&collect, show_ambiguous_object, &ds))\n+\t\t\tBUG(\"show_ambiguous_object shouldn't return non-zero\");\n+\t\toid_array_clear(&collect);\n \t}\n \n \treturn status;\ndiff --git a/t/t1512-rev-parse-disambiguation.sh b/t/t1512-rev-parse-disambiguation.sh\nindex 711704ba5a..2701462041 100755\n--- a/t/t1512-rev-parse-disambiguation.sh\n+++ b/t/t1512-rev-parse-disambiguation.sh\n@@ -361,4 +361,25 @@ test_expect_success 'core.disambiguate does not override context' '\n \t\tgit -c core.disambiguate=committish rev-parse $sha1^{tree}\n '\n \n+test_expect_success C_LOCALE_OUTPUT 'ambiguous commits are printed by type first, then hash order' '\n+\ttest_must_fail git rev-parse 0000 2>stderr &&\n+\tgrep ^hint: stderr >hints &&\n+\tgrep 0000 hints >objects &&\n+\tcat >expected <<-\\EOF &&\n+\ttag\n+\tcommit\n+\ttree\n+\tblob\n+\tEOF\n+\tawk \"{print \\$3}\" <objects >objects.types &&\n+\tuniq <objects.types >objects.types.uniq &&\n+\ttest_cmp expected objects.types.uniq &&\n+\tfor type in tag commit tree blob\n+\tdo\n+\t\tgrep $type objects >$type.objects &&\n+\t\tsort $type.objects >$type.objects.sorted &&\n+\t\ttest_cmp $type.objects.sorted $type.objects\n+\tdone\n+'\n+\n test_done\n-- \n2.17.0.290.gded63e768a\n\n"},{"id":"346320","messageId":"20180501184016.15061-8-avarab@gmail.com","threadId":"48389","inReplyTo":"20180501184016.15061-1-avarab@gmail.com","subject":"[PATCH v3 07/12] get_short_oid: learn to disambiguate by ^{tag}","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2018-05-01T18:40:11Z","receivedAt":"2018-05-01T18:41:46Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Add support for ^{tag} to the disambiguation logic. Before this ^{tag}\nwould simply be ignored:\n\n    $ git rev-parse e8f2^{tag}\n    error: short SHA1 e8f2 is ambiguous\n    hint: The candidates are:\n    hint:   e8f2650052 tag v2.17.0\n    hint:   e8f21caf94 commit 2013-06-24 - bash prompt: print unique detached HEAD abbreviated object name\n    hint:   e8f26250fa commit 2017-02-03 - Merge pull request #996 from jeffhostetler/jeffhostetler/register_rename_src\n    hint:   e8f2bc0c06 commit 2015-05-10 - Documentation: note behavior for multiple remote.url entries\n    hint:   e8f2093055 tree\n    hint:   e8f25a3a50 tree\n    hint:   e8f28d537c tree\n    hint:   e8f2cf6ec0 tree\n    hint:   e8f21d02f7 blob\n    hint:   e8f21d577c blob\n    hint:   e8f2867228 blob\n    hint:   e8f2a35526 blob\n    e8f2^{tag}\n\nNow the logic added in ed1ca6025f (\"peel_onion: disambiguate to favor\ntree-ish when we know we want a tree-ish\", 2013-03-31) has been\nextended to support it.\n\n    $ git rev-parse e8f2^{tag}\n    e8f2650052f3ff646023725e388ea1112b020e79\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n cache.h                             |  5 +++--\n sha1-name.c                         | 13 ++++++++++++-\n t/t1512-rev-parse-disambiguation.sh |  5 ++++-\n 3 files changed, 19 insertions(+), 4 deletions(-)\n\ndiff --git a/cache.h b/cache.h\nindex 354903c3ea..a141995cc7 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -1330,8 +1330,9 @@ struct object_context {\n #define GET_OID_TREE             010\n #define GET_OID_TREEISH          020\n #define GET_OID_BLOB             040\n-#define GET_OID_FOLLOW_SYMLINKS 0100\n-#define GET_OID_RECORD_PATH     0200\n+#define GET_OID_TAG             0100\n+#define GET_OID_FOLLOW_SYMLINKS 0200\n+#define GET_OID_RECORD_PATH     0400\n #define GET_OID_ONLY_TO_DIE    04000\n \n #define GET_OID_DISAMBIGUATORS \\\ndiff --git a/sha1-name.c b/sha1-name.c\nindex 46d8b1afa6..68d5f65362 100644\n--- a/sha1-name.c\n+++ b/sha1-name.c\n@@ -221,6 +221,12 @@ static int finish_object_disambiguation(struct disambiguate_state *ds,\n \treturn 0;\n }\n \n+static int disambiguate_tag_only(const struct object_id *oid, void *cb_data_unused)\n+{\n+\tint kind = oid_object_info(oid, NULL);\n+\treturn kind == OBJ_TAG;\n+}\n+\n static int disambiguate_commit_only(const struct object_id *oid, void *cb_data_unused)\n {\n \tint kind = oid_object_info(oid, NULL);\n@@ -288,7 +294,8 @@ int set_disambiguate_hint_config(const char *var, const char *value)\n \t\t{ \"committish\", disambiguate_committish_only },\n \t\t{ \"tree\", disambiguate_tree_only },\n \t\t{ \"treeish\", disambiguate_treeish_only },\n-\t\t{ \"blob\", disambiguate_blob_only }\n+\t\t{ \"blob\", disambiguate_blob_only },\n+\t\t{ \"tag\", disambiguate_tag_only }\n \t};\n \tint i;\n \n@@ -429,6 +436,8 @@ static int get_short_oid(const char *name, int len, struct object_id *oid,\n \t\tds.fn = disambiguate_treeish_only;\n \telse if (flags & GET_OID_BLOB)\n \t\tds.fn = disambiguate_blob_only;\n+\telse if (flags & GET_OID_TAG)\n+\t\tds.fn = disambiguate_tag_only;\n \telse\n \t\tds.fn = default_disambiguate_hint;\n \n@@ -958,6 +967,8 @@ static int peel_onion(const char *name, int len, struct object_id *oid,\n \tlookup_flags &= ~GET_OID_DISAMBIGUATORS;\n \tif (expected_type == OBJ_COMMIT)\n \t\tlookup_flags |= GET_OID_COMMITTISH;\n+\telse if (expected_type == OBJ_TAG)\n+\t\tlookup_flags |= GET_OID_TAG;\n \telse if (expected_type == OBJ_TREE)\n \t\tlookup_flags |= GET_OID_TREEISH;\n \ndiff --git a/t/t1512-rev-parse-disambiguation.sh b/t/t1512-rev-parse-disambiguation.sh\nindex 2701462041..74e7d9c178 100755\n--- a/t/t1512-rev-parse-disambiguation.sh\n+++ b/t/t1512-rev-parse-disambiguation.sh\n@@ -334,7 +334,10 @@ test_expect_success C_LOCALE_OUTPUT 'ambiguity hints respect type' '\n \ttest_must_fail git rev-parse 000000000^{commit} 2>stderr &&\n \tgrep ^hint: stderr >hints &&\n \t# 5 commits, 1 tag (which is a commitish), plus intro line\n-\ttest_line_count = 7 hints\n+\ttest_line_count = 7 hints &&\n+\tgit rev-parse 000000000^{tag} >stdout &&\n+\ttest_line_count = 1 stdout &&\n+\tgrep -q ^0000000000f8f stdout\n '\n \n test_expect_success C_LOCALE_OUTPUT 'failed type-selector still shows hint' '\n-- \n2.17.0.290.gded63e768a\n\n"},{"id":"346448","messageId":"f35aeda5-8f41-f457-736e-393e95f530ec@gmail.com","threadId":"48389","inReplyTo":"20180501184016.15061-1-avarab@gmail.com","subject":"Re: [PATCH v3 00/12] get_short_oid UI improvements","fromName":"Derrick Stolee","fromEmail":"stolee@gmail.com","sentAt":"2018-05-02T12:42:38Z","receivedAt":"2018-05-02T12:42:44Z","isPatch":true,"sender":{"key":"stolee@gmail.com","avatar":"https://avatars.githubusercontent.com/u/570044?v=4"},"body":"On 5/1/2018 2:40 PM, Ævar Arnfjörð Bjarmason wrote:\n> The biggest change in v3 is the no change at all to the code, but a\n> lengthy explanation of why I didn't go for Derrick's simpler\n> implementation. Maybe I'm wrong about that, but I felt uneasy\n> offloading undocumented (or if I documented it, it would only be for\n> this one edge-case) magic on the oid_array API. Instead I'm just\n> making this patch a bit more complex.\n\nI think that's fair. Thanks for going along with me on the thought \nexperiment.\n\n-Stolee\n"},{"id":"346451","messageId":"385be5ef-7d0d-7e5d-4373-4d85c1a36a0d@gmail.com","threadId":"48389","inReplyTo":"f35aeda5-8f41-f457-736e-393e95f530ec@gmail.com","subject":"Re: [PATCH v3 00/12] get_short_oid UI improvements","fromName":"Derrick Stolee","fromEmail":"stolee@gmail.com","sentAt":"2018-05-02T13:45:22Z","receivedAt":"2018-05-02T13:45:27Z","isPatch":true,"sender":{"key":"stolee@gmail.com","avatar":"https://avatars.githubusercontent.com/u/570044?v=4"},"body":"On 5/2/2018 8:42 AM, Derrick Stolee wrote:\n> On 5/1/2018 2:40 PM, Ævar Arnfjörð Bjarmason wrote:\n>> The biggest change in v3 is the no change at all to the code, but a\n>> lengthy explanation of why I didn't go for Derrick's simpler\n>> implementation. Maybe I'm wrong about that, but I felt uneasy\n>> offloading undocumented (or if I documented it, it would only be for\n>> this one edge-case) magic on the oid_array API. Instead I'm just\n>> making this patch a bit more complex.\n>\n> I think that's fair. Thanks for going along with me on the thought \n> experiment.\n\nAlso, v3 looks good to me.\n\nReviewed-by: Derrick Stolee <dstolee@microsoft.com>\n\n"},{"id":"346499","messageId":"xmqq8t91uy4y.fsf@gitster-ct.c.googlers.com","threadId":"48389","inReplyTo":"20180501184016.15061-5-avarab@gmail.com","subject":"Re: [PATCH v3 04/12] cache.h: add comment explaining the order in object_type","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2018-05-03T05:05:49Z","receivedAt":"2018-05-03T05:05:59Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Ævar Arnfjörð Bjarmason  <avarab@gmail.com> writes:\n\n> The order in the enum might seem arbitrary, and isn't explained by\n> 72518e9c26 (\"more lightweight revalidation while reusing deflated\n> stream in packing\", 2006-09-03) which added it.\n>\n> Derrick Stolee suggested that it's ordered topologically in\n> that as a comment.\n> 5f8b1ec1-258d-1acc-133e-a7c248b4083e@gmail.com. Makes sense to me, add\n\nWhen referring to a message-id, please do not omit surrounding <>,\nwhich is part of the message-id string.  That's like writing your\ne-mail address as avarab gmail.com without at sign.\n\n>  enum object_type {\n>  \tOBJ_BAD = -1,\n>  \tOBJ_NONE = 0,\n> +\t/*\n> +\t * Why have our our \"real\" object types in this order? They're\n> +\t * ordered topologically:\n> +\t *\n> +\t * tag(4)    -> commit(1), tree(2), blob(3)\n> +\t * commit(1) -> tree(2)\n> +\t * tree(2)   -> blob(3)\n> +\t */\n\nI am not sure if the above makes sense at all in explaining tag.\nWith all others, type with smaller type id can refer to another type\nthat is with equal or larger type id (tree can refer to another\ntree).  If tag had the smallest ID among all, it would have made\nsense, though.\n\nBefore anybody confused raises noise, a gitlink records a commit in\na tree, which may seem to contradict the rule even more, but it\nmerely records a commit, without \"referring\" to it in the same sense\nas other reference that require connectivity.\n\n>  \tOBJ_COMMIT = 1,\n>  \tOBJ_TREE = 2,\n>  \tOBJ_BLOB = 3,\n"},{"id":"346500","messageId":"xmqq4ljpuxsw.fsf@gitster-ct.c.googlers.com","threadId":"48389","inReplyTo":"20180501184016.15061-7-avarab@gmail.com","subject":"Re: [PATCH v3 06/12] get_short_oid: sort ambiguous objects by type, then SHA-1","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2018-05-03T05:13:03Z","receivedAt":"2018-05-03T05:13:09Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Ævar Arnfjörð Bjarmason  <avarab@gmail.com> writes:\n\n> +\t/*\n> +\t * Between object types show tags, then commits, and finally\n> +\t * trees and blobs.\n> +\t *\n> +\t * The object_type enum is commit, tree, blob, tag, but we\n> +\t * want tag, commit, tree blob. Cleverly (perhaps too\n\nThe missing comma between \"tree blob\"  on the second line made me\nread this comment twice, which made me notice the lack of \"and\"\nbefore \"tag\" on the previous line.\n\nAssignment is \"commit, tree, blob, and then tag\" but we want \"tag,\ncommit, tree and then blob\", perhaps?\n"},{"id":"346502","messageId":"xmqqzi1htij7.fsf@gitster-ct.c.googlers.com","threadId":"48389","inReplyTo":"20180501184016.15061-10-avarab@gmail.com","subject":"Re: [PATCH v3 09/12] get_short_oid / peel_onion: ^{tree} should be tree, not treeish","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2018-05-03T05:28:12Z","receivedAt":"2018-05-03T05:28:18Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Ævar Arnfjörð Bjarmason  <avarab@gmail.com> writes:\n\n> But ^{tree} shows just the trees, but would previously be equivalent\n> to the above:\n>\n>     $ git rev-parse e8f2^{tree}\n>     error: short SHA1 e8f2 is ambiguous\n>     hint: The candidates are:\n>     hint:   e8f2093055 tree\n>     hint:   e8f25a3a50 tree\n>     hint:   e8f28d537c tree\n>     hint:   e8f2cf6ec0 tree\n>     [...]\n\nWhen a user says \"git $cmd e8f2^{tree}\", the user is telling Git\nthat s/he knows e8f2 *is* a tree-ish, but for whatever reason $cmd\nwants a tree and does not accept an arbitrary tree-ish---that is the\nwhole piont of appending ^{tree} as a suffix.  A useful hint in such\na case would be \"oh, you said e8f2 is a tree-ish, but there are more\nthan one tree-ish, so let me show them to you to help you decide\nwhich one among them is the one you meant\".  When $cmd is rev-parse,\nI would even say that the user is saying \"I know e8f2 is a tree-ish,\nand I know it not a tree--it merely is a tree-ish.  I want the tree\nthat e8f2 thing points at\".\n\nLimiting that hint to show only real trees does not make any sense\nto me.  I do not think we care _too_ deeply, because most of the\ntime, command line location that expects a tree-ish can be given a\ntree-ish, so there is not much reason to use ^{tree} suffix these\ndays.  But in a case where it _does_ matter, I think this change\nmakes the \"hint\" almost useless.\n\nOr am I misleading what you wanted to achieve with this patch?\n"},{"id":"346503","messageId":"CA+P7+xraqcnvg274_zaJO5Je1sJDfmEL=-orFZ4hL1Sg26Cd9Q@mail.gmail.com","threadId":"48389","inReplyTo":"385be5ef-7d0d-7e5d-4373-4d85c1a36a0d@gmail.com","subject":"Re: [PATCH v3 00/12] get_short_oid UI improvements","fromName":"Jacob Keller","fromEmail":"jacob.keller@gmail.com","sentAt":"2018-05-03T06:43:16Z","receivedAt":"2018-05-03T06:43:49Z","isPatch":true,"sender":{"key":"jacob.keller@gmail.com","avatar":"https://avatars.githubusercontent.com/u/874719?v=4"},"body":"On Wed, May 2, 2018 at 6:45 AM, Derrick Stolee <stolee@gmail.com> wrote:\n> On 5/2/2018 8:42 AM, Derrick Stolee wrote:\n>>\n>> On 5/1/2018 2:40 PM, Ævar Arnfjörð Bjarmason wrote:\n>>>\n>>> The biggest change in v3 is the no change at all to the code, but a\n>>> lengthy explanation of why I didn't go for Derrick's simpler\n>>> implementation. Maybe I'm wrong about that, but I felt uneasy\n>>> offloading undocumented (or if I documented it, it would only be for\n>>> this one edge-case) magic on the oid_array API. Instead I'm just\n>>> making this patch a bit more complex.\n>>\n>>\n>> I think that's fair. Thanks for going along with me on the thought\n>> experiment.\n>\n>\n> Also, v3 looks good to me.\n>\n> Reviewed-by: Derrick Stolee <dstolee@microsoft.com>\n>\n\nI also reviewed this, and it looks good to me as well.\n\nThanks,\nJake\n"},{"id":"346505","messageId":"87wowlxko8.fsf@evledraar.gmail.com","threadId":"48389","inReplyTo":"xmqqzi1htij7.fsf@gitster-ct.c.googlers.com","subject":"Re: [PATCH v3 09/12] get_short_oid / peel_onion: ^{tree} should be tree, not treeish","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2018-05-03T07:28:23Z","receivedAt":"2018-05-03T07:28:30Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"\nOn Thu, May 03 2018, Junio C Hamano wrote:\n\n> Ævar Arnfjörð Bjarmason  <avarab@gmail.com> writes:\n>\n>> But ^{tree} shows just the trees, but would previously be equivalent\n>> to the above:\n>>\n>>     $ git rev-parse e8f2^{tree}\n>>     error: short SHA1 e8f2 is ambiguous\n>>     hint: The candidates are:\n>>     hint:   e8f2093055 tree\n>>     hint:   e8f25a3a50 tree\n>>     hint:   e8f28d537c tree\n>>     hint:   e8f2cf6ec0 tree\n>>     [...]\n>\n> When a user says \"git $cmd e8f2^{tree}\", the user is telling Git\n> that s/he knows e8f2 *is* a tree-ish, but for whatever reason $cmd\n> wants a tree and does not accept an arbitrary tree-ish---that is the\n> whole piont of appending ^{tree} as a suffix.  A useful hint in such\n> a case would be \"oh, you said e8f2 is a tree-ish, but there are more\n> than one tree-ish, so let me show them to you to help you decide\n> which one among them is the one you meant\".  When $cmd is rev-parse,\n> I would even say that the user is saying \"I know e8f2 is a tree-ish,\n> and I know it not a tree--it merely is a tree-ish.  I want the tree\n> that e8f2 thing points at\".\n>\n> Limiting that hint to show only real trees does not make any sense\n> to me.  I do not think we care _too_ deeply, because most of the\n> time, command line location that expects a tree-ish can be given a\n> tree-ish, so there is not much reason to use ^{tree} suffix these\n> days.  But in a case where it _does_ matter, I think this change\n> makes the \"hint\" almost useless.\n>\n> Or am I misleading what you wanted to achieve with this patch?\n\nThe reason I'm doing this is because I found it confusing that I can't\ndo:\n\n    for t in tag commit tree blob; do ./git --exec-path=$PWD rev-parse 7452^{$t}; done\n\nAnd get, respectively, only the SHAs that match the respective type, but\ncurrently (with released git) you can do:\n\n    for t in tag commit committish treeish tree blob; do git -c core.disambiguate=$t rev-parse 7452; done\n\nAnd while =tag doesn't work the others do (inluding =blob), so\ncore.disambiguate=tree gives you just trees, but ^{tree} gives you\ntreeish.\n\nWhy should ^{tree} be giving me ^{treeish} but =tree be giving me trees,\nand =treeish be synonymous with ^{tree}?\n\nThere's no other cases I know of where the ^{<type>} peel syntax won't\ngive you *only* the <type> you asked for. See peel_onion() ->\npeel_to_type() and how get_oid_1() will short-circuit if it has an\nanswer, and then finally fall back to this get_short_oid() codepath.\n\nLooking at the code & git log maybe it'll do that internally, but when\nyou peel a tag or commit ^{tree} will only ever find one thing, unlike\nthis disambiguation case where we can match multiple things.\n\nSo:\n\n1) Am I missing some subtlety or am I correct that there was no way to\nget git to return more than one SHA-1 for ^{commit} or ^{tree} before\nthis disambiguation feature was added?\n\n2) I think the behavior I've implemented is consistent with how the peel\nsyntax has been documented in revisions.txt:\n\n    '<rev>{caret}{<type>}', e.g. 'v0.99.8{caret}\\{commit\\}'::\n      A suffix '{caret}' followed by an object type name enclosed in\n      brace pair means dereference the object at '<rev>' recursively until\n      an object of type '<type>' is found or the object cannot be\n      dereferenced anymore (in which case, barf).\n      For example, if '<rev>' is a commit-ish, '<rev>{caret}\\{commit\\}'\n      describes the corresponding commit object.\n      Similarly, if '<rev>' is a tree-ish, '<rev>{caret}\\{tree\\}'\n      describes the corresponding tree object.\n      '<rev>{caret}0'\n      is a short-hand for '<rev>{caret}\\{commit\\}'.\n\nNote \"until an object of type '<type>' is found\". I.e. my mental model\nof this has been that yes you can *start* the search at a different\nobject (e.g. tag -> tree), but it'll only ever return the tree. The\ndisambiguation implementation has been inconsistent with this as\ndocumented, because it hasn't been drilling don to an object of '<type>'\ngiven a request like $short^{<type>}, but rather returning something\nmatching $short because it could be a container for <type>.\n\nAnyway, I'm not saying I'm right. This is the first time I really look\nat sha1-name.c in any detail. But the above describes the thought\nprocess behind this patch.\n"},{"id":"346611","messageId":"xmqqvac4tb64.fsf@gitster-ct.c.googlers.com","threadId":"48389","inReplyTo":"87wowlxko8.fsf@evledraar.gmail.com","subject":"Re: [PATCH v3 09/12] get_short_oid / peel_onion: ^{tree} should be tree, not treeish","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2018-05-04T02:19:31Z","receivedAt":"2018-05-04T02:19:37Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Ævar Arnfjörð Bjarmason <avarab@gmail.com> writes:\n\n> The reason I'm doing this is because I found it confusing that I can't\n> do:\n>\n>     for t in tag commit tree blob; do ./git --exec-path=$PWD rev-parse 7452^{$t}; done\n>\n> And get, respectively, only the SHAs that match the respective type, but\n> currently (with released git) you can do:\n>\n>     for t in tag commit committish treeish tree blob; do git -c core.disambiguate=$t rev-parse 7452; done\n\nExactly.  The former asks \"I (think I) know 7452 can be used to name\nan object of type $t, with peeling if necessary--give me the underlying\nobject of type $t\".  In short, the fact that you can write \"$X^{$t}\"\nsays that $X is a $t-ish (otherwise $X cannot be used as a stand-in\nfor an object of type $t) and that you fully expect that $X can merely\nbe of type $t-ish and not exactly $t (otherwise you wouldn't be\nmaking sure to coerce $X into $t with ^{$t} notation).\n\nIn *THAT* context, disambiguation help that lists objects whose name\nbegins with \"7452\" you gave, hoping that it is a unique enough\nprefix when it wasn't in reality, *MUST* give $t-ish; restricting it\nto $t makes the help mostly useless.\n\n> 1) Am I missing some subtlety or am I correct that there was no way to\n> get git to return more than one SHA-1 for ^{commit} or ^{tree} before\n> this disambiguation feature was added?\n\nThere is no such feature either before or after the disambiguation\nhelp.  I am not saying there shouldn't exist such a feature.  I am\nsaying that breaking the existing feature and making it useless is\nnot the way to add such a feature.\n"},{"id":"346641","messageId":"87lgczyfq6.fsf@evledraar.gmail.com","threadId":"48389","inReplyTo":"xmqqvac4tb64.fsf@gitster-ct.c.googlers.com","subject":"Re: [PATCH v3 09/12] get_short_oid / peel_onion: ^{tree} should be tree, not treeish","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2018-05-04T08:42:09Z","receivedAt":"2018-05-04T08:42:16Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"\nOn Fri, May 04 2018, Junio C Hamano wrote:\n\n> Ævar Arnfjörð Bjarmason <avarab@gmail.com> writes:\n>\n>> The reason I'm doing this is because I found it confusing that I can't\n>> do:\n>>\n>>     for t in tag commit tree blob; do ./git --exec-path=$PWD rev-parse 7452^{$t}; done\n>>\n>> And get, respectively, only the SHAs that match the respective type, but\n>> currently (with released git) you can do:\n>>\n>>     for t in tag commit committish treeish tree blob; do git -c core.disambiguate=$t rev-parse 7452; done\n>\n> Exactly.  The former asks \"I (think I) know 7452 can be used to name\n> an object of type $t, with peeling if necessary--give me the underlying\n> object of type $t\".\n\nRight, and I'm with you so far, this makes sense to me for all existing\nuses of the peel syntax, otherwise v2.17.0^{tree} wouldn't be the same\nas rev-parse v2.17.0^{tree}^{tree}...\n\n> In short, the fact that you can write \"$X^{$t}\"\n> says that $X is a $t-ish (otherwise $X cannot be used as a stand-in\n> for an object of type $t) and that you fully expect that $X can merely\n> be of type $t-ish and not exactly $t (otherwise you wouldn't be\n> making sure to coerce $X into $t with ^{$t} notation).\n>\n> In *THAT* context, disambiguation help that lists objects whose name\n> begins with \"7452\" you gave, hoping that it is a unique enough\n> prefix when it wasn't in reality, *MUST* give $t-ish; restricting it\n> to $t makes the help mostly useless.\n>\n>> 1) Am I missing some subtlety or am I correct that there was no way to\n>> get git to return more than one SHA-1 for ^{commit} or ^{tree} before\n>> this disambiguation feature was added?\n>\n> There is no such feature either before or after the disambiguation\n> help.  I am not saying there shouldn't exist such a feature.  I am\n> saying that breaking the existing feature and making it useless is\n> not the way to add such a feature.\n\nI still don't get how what you're proposing is going to be consistent,\nbut let's fully enumerate the output of 7452 with my patch to take that\ncase-by-case[1]:\n\n    ^{tag}:\n    7452b4b5786778d5d87f5c90a94fab8936502e20\n    ^{commit}:\n    hint:   74521eee4c commit 2007-12-01 - git-gui: install-sh from automake does not like -m755\n    hint:   745224e04a commit 2014-06-18 - refs.c: SSE2 optimizations for check_refname_component\n    ^{tree}:\n    hint:   7452336aa3 tree\n    hint:   74524f384d tree\n    hint:   7452813bcd tree\n    hint:   7452b1a701 tree\n    hint:   7452b73c42 tree\n    hint:   7452ca1557 tree\n    ^{blob}:\n    hint:   7452001351 blob\n    hint:   745254665d blob\n    hint:   7452a572c1 blob\n    hint:   7452b9fd21 blob\n    hint:   7452db13c8 blob\n    hint:   7452fce0da blob\n\nAnd[2]:\n\n    core.disambiguate=tag:\n    [same as ^{tag]\n    core.disambiguate=commit:\n    [same as ^{commit}]\n    core.disambiguate=committish:\n    hint:   7452b4b578 tag v2.1.0\n    hint:   74521eee4c commit 2007-12-01 - git-gui: install-sh from automake does not like -m755\n    hint:   745224e04a commit 2014-06-18 - refs.c: SSE2 optimizations for check_refname_component\n    core.disambiguate=tree:\n    [same as ^{tree}]\n    core.disambiguate=treeish (same as $sha1:)\n    hint:   7452b4b578 tag v2.1.0\n    hint:   74521eee4c commit 2007-12-01 - git-gui: install-sh from automake does not like -m755\n    hint:   745224e04a commit 2014-06-18 - refs.c: SSE2 optimizations for check_refname_component\n    hint:   7452336aa3 tree\n    hint:   74524f384d tree\n    hint:   7452813bcd tree\n    hint:   7452b1a701 tree\n    hint:   7452b73c42 tree\n    hint:   7452ca1557 tree\n    core.disambiguate=blob:\n    [same as ^{blob}]\n\nSo from my understanding of what you're saying you'd like to list tag,\ncommits and trees given $sha1^{tree}, because they're all types that can\nbe used to reach a tree.\n\nI don't think that's very useful, yes it would \"break\" existing\ndisambiguations, but this is such an obscure (and purely manual)\nuse-case than I think that's fine.\n\nBecause I think to the extent anyone's going to use this it's because\nthey know they have e.g. a short blob, commit etc. SHA-1 they're not\ngoing to use it because they have some short $SHA they know is a tree,\nand then want all SHA-1s of that *and* random tag & commit objects that\nhappen to have the same object prefix just because tags and commits can\nalso point to trees.\n\nHow does that make any sense? The entire reason for using the normal\npeel syntax is because you e.g. have v2.17.0 and want to get to the\n^{tree} or the ^{commit} tht v2.17.0 directly points to. That's entirely\northogonal to what the disambiguation is doing. There with your proposed\nsemantics you're peeling 7452 as 7452^{tree} because (IMO) you're\nlooking for trees, just to get some entirely unrelated commits and tags.\n\nBut *leaving that aside*, i.e. I don't see why the use-case would make\nsense. What I *don't* get is why, if you think that, you only want to\napply that rule to ^{tree}. I.e. wouldn't it then be consistent to say:\n\n    # a)\n    ^{tag}    = tag\n    ^{commit} = tag, commit\n    ^{tree}   = tag, commit, tree\n    ^{blob}   = tag, blob (blobish)\n\nWhereas my patch now does:\n\n    # b)\n    ^{tag}    = tag\n    ^{commit} = commit\n    ^{tree}   = tree\n    ^{blob}   = blob\n\nBut from what you seem to be proposing (or maybe you just didn't have a\nchance to critique the ^{blob} and ^{commit} patches):\n\n    # c)\n    ^{tag}    = tag\n    ^{commit} = commit\n    ^{tree}   = tag, tree, commit\n    ^{blob}   = blob\n\n1. for type in tag commit tree blob; do echo \"^{$type}:\" && ./git --exec-path=$PWD rev-parse 7452^{$type} 2>&1|grep -E -e ^hint -e '^[0-9a-f]{40}$' |grep -v are:; done\n2. for cfg in tag commit committish tree treeish blob; do echo \"core.disambiguate=$cfg:\" && ./git --exec-path=$PWD -c core.disambiguate=$cfg rev-parse 7452 2>&1|grep -E -e ^hint -e '^[0-9a-f]{40}$' |grep -v are:; done\n"},{"id":"346842","messageId":"xmqq6040qf8x.fsf@gitster-ct.c.googlers.com","threadId":"48389","inReplyTo":"87lgczyfq6.fsf@evledraar.gmail.com","subject":"Re: [PATCH v3 09/12] get_short_oid / peel_onion: ^{tree} should be tree, not treeish","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2018-05-07T04:08:46Z","receivedAt":"2018-05-07T04:08:52Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Ævar Arnfjörð Bjarmason <avarab@gmail.com> writes:\n\n> Right, and I'm with you so far, this makes sense to me for all existing\n> uses of the peel syntax, otherwise v2.17.0^{tree} wouldn't be the same\n> as rev-parse v2.17.0^{tree}^{tree}...\n\nMore importantly, you could spell v2.17.0 part of the above with a\nshort hexadecimal string.  And that string should be naming some\ntree-ish, the most important thing being that it is *NOT* required\nto be a tree (and practically, it is likely that the user has a\ntree-ish that is *NOT* a tree).\n\nI guess I have a reaction to the title\n\n    \"get_short_oid/peel_onion: ^{tree} should be tree\"\n\n\"X^{tree}\" should *RESULT* in a tree, but it should *REQUIRE* X to\nbe a tree-ish.  It is unclear \"should be tree\" is about the former\nand I read (perhaps mis-read) it as saying \"it should require X to\nbe a tree\"---that statement is utterly incorrect as we agreed above.\n\n> case-by-case[1]:\n>\n>     ^{tag}:\n>     7452b4b5786778d5d87f5c90a94fab8936502e20\n\nI take it as \"git rev-parse 7452^{tag}\" output (similarly ^{$type}\nfor the rest)?  That probably is desirable, as blobs, trees and\ncommits cannot be peeled down to a tag.\n\n>     ^{commit}:\n>     hint:   74521eee4c commit 2007-12-01 - git-gui: install-sh from automake does not like -m755\n>     hint:   745224e04a commit 2014-06-18 - refs.c: SSE2 optimizations for check_refname_component\n\nIf 7452 points at a commit, that tag itself should also be given as\na possible object the user may have meant in the \"hint\" thing.  I\nagree it is a good idea to exclude trees and blobs from the hint,\nfor the same reason why I think it makes sense to exclude blobs,\ntrees and commits from hints for a X in \"X^{tag}\" above.\n\n>     ^{tree}:\n>     hint:   7452336aa3 tree\n>     hint:   74524f384d tree\n>     hint:   7452813bcd tree\n>     hint:   7452b1a701 tree\n>     hint:   7452b73c42 tree\n>     hint:   7452ca1557 tree\n\nAgain, if there is a commit or a tag (that points at a commit or a\ntree) whose name begins with 7452, it should be included in the hint\nabove.  Not having blobs in the hint of course makes sense, as a\nblob cannot be X in \"X^{tree}\".\n\n> And[2]:\n>\n>     core.disambiguate=tag:\n>     [same as ^{tag]\n>     core.disambiguate=commit:\n>     [same as ^{commit}]\n\nWhen core.disambiguate tells us to \"interprete hexadecimal literals\nto name commit objects only\", giving only commits in hints: section\nmakes sense, because we are explicitly saying that \"when I say 7452,\nI do not mean any tag whose name begins with 7452\", so \"sorry, your\nrequest is not explicit enough---there are two commits and a tag\nthat begin with that prefix\" is not helpful---it should stop at \"you\nmay have meant one of these two commits\" and not mention any tag.\n"},{"id":"346986","messageId":"20180508143408.GA30183@sigill.intra.peff.net","threadId":"48389","inReplyTo":"xmqq6040qf8x.fsf@gitster-ct.c.googlers.com","subject":"Re: [PATCH v3 09/12] get_short_oid / peel_onion: ^{tree} should be tree, not treeish","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2018-05-08T14:34:09Z","receivedAt":"2018-05-08T14:34:14Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Mon, May 07, 2018 at 01:08:46PM +0900, Junio C Hamano wrote:\n\n> Ævar Arnfjörð Bjarmason <avarab@gmail.com> writes:\n> \n> > Right, and I'm with you so far, this makes sense to me for all existing\n> > uses of the peel syntax, otherwise v2.17.0^{tree} wouldn't be the same\n> > as rev-parse v2.17.0^{tree}^{tree}...\n> \n> More importantly, you could spell v2.17.0 part of the above with a\n> short hexadecimal string.  And that string should be naming some\n> tree-ish, the most important thing being that it is *NOT* required\n> to be a tree (and practically, it is likely that the user has a\n> tree-ish that is *NOT* a tree).\n> \n> I guess I have a reaction to the title\n> \n>     \"get_short_oid/peel_onion: ^{tree} should be tree\"\n> \n> \"X^{tree}\" should *RESULT* in a tree, but it should *REQUIRE* X to\n> be a tree-ish.  It is unclear \"should be tree\" is about the former\n> and I read (perhaps mis-read) it as saying \"it should require X to\n> be a tree\"---that statement is utterly incorrect as we agreed above.\n\nFWIW, I had the same feeling as you when reading this, that this commit\n(and the one after) are doing the wrong thing. And these paragraphs sum\nit up. The \"^{tree}\" is about asking us to peel to a tree, not about\nresolving X in the first place. We can use it as a _hint_ when resolving\nX, but the correct hint is \"something that can be peeled to a tree\", not\n\"is definitely a tree\".\n\n-Peff\n"},{"id":"346987","messageId":"20180508144128.GB30183@sigill.intra.peff.net","threadId":"48389","inReplyTo":"20180501184016.15061-12-avarab@gmail.com","subject":"Re: [PATCH v3 11/12] config doc: document core.disambiguate","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2018-05-08T14:41:28Z","receivedAt":"2018-05-08T14:41:33Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Tue, May 01, 2018 at 06:40:15PM +0000, Ævar Arnfjörð Bjarmason wrote:\n\n> The core.disambiguate variable was added in\n> 5b33cb1fd7 (\"get_short_sha1: make default disambiguation\n> configurable\", 2016-09-27) but never documented.\n\nThanks, this seems reasonable. It was originally added as a tool to let\npeople experiment with different defaults, and I never really expected\nit to be something normal people would set. But I'm not sure if anybody\nreally did much experimentation (I still suspect that setting it to\n\"commit\" or \"committish\" would make most people happy).\n\n> diff --git a/Documentation/config.txt b/Documentation/config.txt\n> index 2659153cb3..14a3d57e77 100644\n> --- a/Documentation/config.txt\n> +++ b/Documentation/config.txt\n> @@ -910,6 +910,19 @@ core.abbrev::\n>  \tabbreviated object names to stay unique for some time.\n>  \tThe minimum length is 4.\n>  \n> +core.disambiguate::\n> +\tIf Git is given a SHA-1 that's ambigous it'll suggest what\n> +\tobjects you might mean. By default it'll print out all\n> +\tpotential objects with that prefix regardless of their\n> +\ttype. This setting, along with the `^{<type>}` peel syntax\n> +\t(see linkgit:gitrevisions[7]), allows for narrowing that down.\n\nThis isn't just about what we print, but also about excluding objects\nfrom consideration that don't match.\n\n> +Is set to `none` by default to show all object types. Can also be\n> +`commit` (peel syntax: `$sha1^{commit}`), `committish` (commits and\n> +tags), `tree` (peel: `$sha1^{tree}`), `treeish` (everything except\n> +blobs, peel syntax: `$sha1:`), `blob` (peel: `$sha1^{blob}`) or `tag`\n> +(peel: `$sha1^{tag}`). The peel syntax will override any config value.\n\nThese peel references would need updating pending the discussion over\nthe earlier patches.\n\nI suspect there are other things besides peel syntax which may override\nthis. It's really just the fallback when the caller does not give the\nlookup machinery any other context. Certainly the peel specifiers are\none way to get syntax, but I think there are others. Grepping for\nGET_OID_, I see that the revision dot syntax infers committish context,\nas does anything that passes REVARG_COMMITTISH (so git-log, for\nexample).\n\n-Peff\n"},{"id":"346988","messageId":"20180508144443.GC30183@sigill.intra.peff.net","threadId":"48389","inReplyTo":"20180501184016.15061-7-avarab@gmail.com","subject":"Re: [PATCH v3 06/12] get_short_oid: sort ambiguous objects by type, then SHA-1","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2018-05-08T14:44:43Z","receivedAt":"2018-05-08T14:44:47Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Tue, May 01, 2018 at 06:40:10PM +0000, Ævar Arnfjörð Bjarmason wrote:\n\n> Change the output emitted when an ambiguous object is encountered so\n> that we show tags first, then commits, followed by trees, and finally\n> blobs. Within each type we show objects in hashcmp() order. Before\n> this change the objects were only ordered by hashcmp().\n> \n> The reason for doing this is that the output looks better as a result,\n> e.g. the v2.17.0 tag before this change on \"git show e8f2\" would\n> display:\n\nFWIW, I agree that this gives a big improvement to readability.\n\n-Peff\n"},{"id":"346991","messageId":"CACsJy8AkfNfupdr1MqZSaxNCbPwBVzxXNMMqPvwif0NtuCxDaA@mail.gmail.com","threadId":"48389","inReplyTo":"20180501184016.15061-5-avarab@gmail.com","subject":"Re: [PATCH v3 04/12] cache.h: add comment explaining the order in object_type","fromName":"Duy Nguyen","fromEmail":"pclouds@gmail.com","sentAt":"2018-05-08T15:35:08Z","receivedAt":"2018-05-08T15:35:45Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Tue, May 1, 2018 at 8:40 PM, Ævar Arnfjörð Bjarmason\n<avarab@gmail.com> wrote:\n> The order in the enum might seem arbitrary, and isn't explained by\n> 72518e9c26 (\"more lightweight revalidation while reusing deflated\n> stream in packing\", 2006-09-03) which added it.\n>\n> Derrick Stolee suggested that it's ordered topologically in\n> 5f8b1ec1-258d-1acc-133e-a7c248b4083e@gmail.com. Makes sense to me, add\n> that as a comment.\n>\n> Helped-by: Derrick Stolee <dstolee@microsoft.com>\n> Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n> ---\n>  cache.h | 8 ++++++++\n>  1 file changed, 8 insertions(+)\n>\n> diff --git a/cache.h b/cache.h\n> index 77b7acebb6..354903c3ea 100644\n> --- a/cache.h\n> +++ b/cache.h\n> @@ -376,6 +376,14 @@ extern void free_name_hash(struct index_state *istate);\n>  enum object_type {\n>         OBJ_BAD = -1,\n>         OBJ_NONE = 0,\n> +       /*\n> +        * Why have our our \"real\" object types in this order? They're\n> +        * ordered topologically:\n> +        *\n> +        * tag(4)    -> commit(1), tree(2), blob(3)\n> +        * commit(1) -> tree(2)\n> +        * tree(2)   -> blob(3)\n> +        */\n\nI think it's more important that these constants are part of the pack\nfile format. Even if it follows some order now, when a new object type\ncomes, you cannot just reorder to keep things look nice because then\nyou break pack file access.\n\nI'm afraid this comment suggests that these numbers are just about\norder, which is very wrong.\n\n>         OBJ_COMMIT = 1,\n>         OBJ_TREE = 2,\n>         OBJ_BLOB = 3,\n-- \nDuy\n"},{"id":"346992","messageId":"20180508155627.19245-1-pclouds@gmail.com","threadId":"48389","inReplyTo":"CACsJy8AkfNfupdr1MqZSaxNCbPwBVzxXNMMqPvwif0NtuCxDaA@mail.gmail.com","subject":"[PATCH] pack-format.txt: more details on pack file format","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2018-05-08T15:56:27Z","receivedAt":"2018-05-08T15:56:46Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"The current document mentions OBJ_* constants without their actual\nvalues. A git developer would know these are from cache.h but that's\nnot very friendly to a person who wants to read this file to implement\na pack file parser.\n\nSimilarly, the deltified representation is not documented at all (the\n\"document\" is basically patch-delta.c). Translate that C code in\nEnglish.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n I noticed that these object type values are not documented in\n pack-format.txt so here's my attempt to improve it.\n\n While at there, I also add some text about this obscure delta format.\n We occasionally have questions about this on the mailing list if I\n remember correctly.\n\n Documentation/technical/pack-format.txt | 41 +++++++++++++++++++++++++\n 1 file changed, 41 insertions(+)\n\ndiff --git a/Documentation/technical/pack-format.txt b/Documentation/technical/pack-format.txt\nindex 8e5bf60be3..2c7d5c0e74 100644\n--- a/Documentation/technical/pack-format.txt\n+++ b/Documentation/technical/pack-format.txt\n@@ -36,6 +36,47 @@ Git pack format\n \n   - The trailer records 20-byte SHA-1 checksum of all of the above.\n \n+Valid object types are:\n+\n+- OBJ_COMMIT (1)\n+- OBJ_TREE (2)\n+- OBJ_BLOB (3)\n+- OBJ_TAG (4)\n+- OBJ_OFS_DELTA (6)\n+- OBJ_REF_DELTA (7)\n+\n+Type 5 is reserved for future expansion.\n+\n+Deltified representation is a sequence of one byte command optionally\n+followed by more data for the command. The following commands are\n+recognized:\n+\n+- If bit 7 is set, the remaining bits in the command byte specifies\n+  how to extract copy offset and size to copy. The following must be\n+  evaluated in this exact order:\n+  - If bit 0 is set, the following byte contains bits 0-7 of the copy\n+    offset (this also resets all other bits in the copy offset to\n+    zero).\n+  - If bit 1 is set, the following byte contains bits 8-15 of the copy\n+    offset.\n+  - If bit 2 is set, the following byte contains bits 16-23 of the\n+    copy offset.\n+  - If bit 3 is set, the following byte contains bits 24-31 of the\n+    copy offset.\n+  - If bit 4 is set, the following byte contains bits 0-7 of the copy\n+    size (this also resets all other bits in the copy size to zero_.\n+  - If bit 5 is set, the following byte contains bits 8-15 of the copy\n+    size.\n+  - If bit 6 is set, the following byte contains bits 16-23 of the\n+    copy size.\n+\n+  Copy size zero means 0x10000 bytes. The data from source object at\n+  the given copy offset is copied back to the destination buffer.\n+\n+- If bit 7 is not set, it is the copy size in bytes. The following\n+  bytes are copied to destination buffer\n+- Command byte zero is reserved for future expansion.\n+\n == Original (version 1) pack-*.idx files have the following format:\n \n   - The header consists of 256 4-byte network byte order\n-- \n2.17.0.705.g3525833791\n\n"},{"id":"346997","messageId":"CAGZ79kZiwX-QFnkTfRHby38GYBDwj-0Dyv3_PWPXtnWr+112CA@mail.gmail.com","threadId":"48389","inReplyTo":"20180508155627.19245-1-pclouds@gmail.com","subject":"Re: [PATCH] pack-format.txt: more details on pack file format","fromName":"Stefan Beller","fromEmail":"sbeller@google.com","sentAt":"2018-05-08T17:23:56Z","receivedAt":"2018-05-08T17:24:04Z","isPatch":true,"sender":{"key":"stefanbeller@gmail.com","avatar":"https://avatars.githubusercontent.com/u/455868?v=4"},"body":"On Tue, May 8, 2018 at 8:56 AM, Nguyễn Thái Ngọc Duy <pclouds@gmail.com> wrote:\n> The current document mentions OBJ_* constants without their actual\n> values. A git developer would know these are from cache.h but that's\n> not very friendly to a person who wants to read this file to implement\n> a pack file parser.\n>\n> Similarly, the deltified representation is not documented at all (the\n> \"document\" is basically patch-delta.c). Translate that C code in\n> English.\n>\n> Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n> ---\n>  I noticed that these object type values are not documented in\n>  pack-format.txt so here's my attempt to improve it.\n\nThanks for sending this patch!\n\n>\n>  While at there, I also add some text about this obscure delta format.\n>  We occasionally have questions about this on the mailing list if I\n>  remember correctly.\n\nLet me see if I can understand it, as I am not well versed in the\ndelta format, so ideally I would understand it from the patch here?\n\n>\n>  Documentation/technical/pack-format.txt | 41 +++++++++++++++++++++++++\n>  1 file changed, 41 insertions(+)\n>\n> diff --git a/Documentation/technical/pack-format.txt b/Documentation/technical/pack-format.txt\n> index 8e5bf60be3..2c7d5c0e74 100644\n> --- a/Documentation/technical/pack-format.txt\n> +++ b/Documentation/technical/pack-format.txt\n> @@ -36,6 +36,47 @@ Git pack format\n>\n>    - The trailer records 20-byte SHA-1 checksum of all of the above.\n>\n> +Valid object types are:\n> +\n> +- OBJ_COMMIT (1)\n> +- OBJ_TREE (2)\n> +- OBJ_BLOB (3)\n> +- OBJ_TAG (4)\n> +- OBJ_OFS_DELTA (6)\n> +- OBJ_REF_DELTA (7)\n> +\n> +Type 5 is reserved for future expansion.\n\nand type 0 as well, but that is not spelled out?\n\n> +Deltified representation\n\nDoes this refer to OFS delta as well as REF deltas?\n\n> is a sequence of one byte command optionally\n> +followed by more data for the command. The following commands are\n> +recognized:\n\nSo a Deltified representation of an object is a 6 or 7 in the 3 bit type\nand then the length. Then a command is shown how to construct\nthe object based on other objects. Can there be more commands?\n\n> +- If bit 7 is set, the remaining bits in the command byte specifies\n> +  how to extract copy offset and size to copy. The following must be\n> +  evaluated in this exact order:\n\nSo there are 2 modes, and the high bit indicates which mode is used.\nYou start describing the more complicated mode first,\nmaybe give names to both of them? \"direct copy\" (below) and\n\"compressed copy with offset\" ?\n\n\n> +  - If bit 0 is set, the following byte contains bits 0-7 of the copy\n> +    offset (this also resets all other bits in the copy offset to\n> +    zero).\n> +  - If bit 1 is set, the following byte contains bits 8-15 of the copy\n> +    offset.\n> +  - If bit 2 is set, the following byte contains bits 16-23 of the\n> +    copy offset.\n> +  - If bit 3 is set, the following byte contains bits 24-31 of the\n> +    copy offset.\n\nI assume these bits are exclusive, i.e. if bit 3 is set, bits 0-2 are not\nallowed to be set. What happens if they are set, do we care?\n\nIf bit 3 is set, then the following byte contains 24-31 of the copy offset,\nwhere is the rest? Do I wait for another command byte with\nbits 2,1,0 to learn about the body offsets, or do they follow the\nfollowing byte? Something like:\n\n  \"If bit 3 is set, then the next 4 bytes are the copy offset,\n  in network byte order\"\n\n\n> +  - If bit 4 is set, the following byte contains bits 0-7 of the copy\n> +    size (this also resets all other bits in the copy size to zero_.\n> +  - If bit 5 is set, the following byte contains bits 8-15 of the copy\n> +    size.\n> +  - If bit 6 is set, the following byte contains bits 16-23 of the\n> +    copy size.\n\nbits 4-7 seem to be another group of mutually exclusive bits.\nThe same question as above:\nIf bit 6 is set, where are bits 0-15 of the copy size?\n\n> +\n> +  Copy size zero means 0x10000 bytes.\n\nThis is an interesting caveat. So we can only copy 1-0x10000 bytes,\nand cannot express to copy 0 bytes?\n\n> The data from source object at\n> +  the given copy offset is copied back to the destination buffer.\n> +\n> +- If bit 7 is not set, it is the copy size in bytes. The following\n> +  bytes are copied to destination buffer\n> +- Command byte zero is reserved for future expansion.\n\nThanks,\nStefan\n"},{"id":"347003","messageId":"87bmdqxb2s.fsf@evledraar.gmail.com","threadId":"48389","inReplyTo":"20180508155627.19245-1-pclouds@gmail.com","subject":"Re: [PATCH] pack-format.txt: more details on pack file format","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2018-05-08T18:21:31Z","receivedAt":"2018-05-08T18:21:41Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"\nOn Tue, May 08 2018, Nguyễn Thái Ngọc Duy wrote:\n\n> The current document mentions OBJ_* constants without their actual\n> values. A git developer would know these are from cache.h but that's\n> not very friendly to a person who wants to read this file to implement\n> a pack file parser.\n>\n> Similarly, the deltified representation is not documented at all (the\n> \"document\" is basically patch-delta.c). Translate that C code in\n> English.\n\nThanks, will drop my version from v4, although a comment for the enum in\ncache.h pointing the reader to these docs would be very useful.\n"},{"id":"347004","messageId":"CACsJy8A10qixJ7YtJKJejp1t49aBZFDn7CjSTiaq8GeVHuxiOQ@mail.gmail.com","threadId":"48389","inReplyTo":"CAGZ79kZiwX-QFnkTfRHby38GYBDwj-0Dyv3_PWPXtnWr+112CA@mail.gmail.com","subject":"Re: [PATCH] pack-format.txt: more details on pack file format","fromName":"Duy Nguyen","fromEmail":"pclouds@gmail.com","sentAt":"2018-05-08T18:22:09Z","receivedAt":"2018-05-08T18:22:45Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Tue, May 8, 2018 at 7:23 PM, Stefan Beller <sbeller@google.com> wrote:\n>>  While at there, I also add some text about this obscure delta format.\n>>  We occasionally have questions about this on the mailing list if I\n>>  remember correctly.\n>\n> Let me see if I can understand it, as I am not well versed in the\n> delta format, so ideally I would understand it from the patch here?\n\nWell yes. I don't expect my first version to be that easy to\nunderstand. This is where you come in to help ;-)\n\n>> +Valid object types are:\n>> +\n>> +- OBJ_COMMIT (1)\n>> +- OBJ_TREE (2)\n>> +- OBJ_BLOB (3)\n>> +- OBJ_TAG (4)\n>> +- OBJ_OFS_DELTA (6)\n>> +- OBJ_REF_DELTA (7)\n>> +\n>> +Type 5 is reserved for future expansion.\n>\n> and type 0 as well, but that is not spelled out?\n\ntype 0 is invalid. I think in some encoding it's not even possible to\nencode zero. Anyway yes it should be spelled out.\n\n>\n>> +Deltified representation\n>\n> Does this refer to OFS delta as well as REF deltas?\n\nYes. Both OFS and REF deltas have the same \"body\" which is what this\npart is about. The differences between OFS and REF deltas are not\ndescribed (in fact I don't think we describe what OFS and REF deltas\nare at all).\n\n>> is a sequence of one byte command optionally\n>> +followed by more data for the command. The following commands are\n>> +recognized:\n>\n> So a Deltified representation of an object is a 6 or 7 in the 3 bit type\n> and then the length. Then a command is shown how to construct\n> the object based on other objects. Can there be more commands?\n>\n>> +- If bit 7 is set, the remaining bits in the command byte specifies\n>> +  how to extract copy offset and size to copy. The following must be\n>> +  evaluated in this exact order:\n>\n> So there are 2 modes, and the high bit indicates which mode is used.\n> You start describing the more complicated mode first,\n> maybe give names to both of them? \"direct copy\" (below) and\n> \"compressed copy with offset\" ?\n\nI started to update this more because even this text is hard to get\neven to me. So let's get the background first.\n\nWe have a source object somewhere (the object name comes from ofs/ref\ndelta's header), basically we have the whole content. This delta\nthingy tells us how to use that source object to create a new (target)\nobject.\n\nThe delta is actually a sequence of instructions (of variable length).\nOne is for copying from the source object. The other copies from the\ndelta itself (e.g. this is new data in the target which is not\navailable anywhere in the source object to copy from). The last bit of\nthe first byte determines what instruction type it is.\n\n\n>> +  - If bit 0 is set, the following byte contains bits 0-7 of the copy\n>> +    offset (this also resets all other bits in the copy offset to\n>> +    zero).\n>> +  - If bit 1 is set, the following byte contains bits 8-15 of the copy\n>> +    offset.\n>> +  - If bit 2 is set, the following byte contains bits 16-23 of the\n>> +    copy offset.\n>> +  - If bit 3 is set, the following byte contains bits 24-31 of the\n>> +    copy offset.\n>\n> I assume these bits are exclusive, i.e. if bit 3 is set, bits 0-2 are not\n> allowed to be set. What happens if they are set, do we care?\n>\n> If bit 3 is set, then the following byte contains 24-31 of the copy offset,\n> where is the rest? Do I wait for another command byte with\n> bits 2,1,0 to learn about the body offsets, or do they follow the\n> following byte? Something like:\n>\n>   \"If bit 3 is set, then the next 4 bytes are the copy offset,\n>   in network byte order\"\n\nMy first attempt at \"translating to English\" is like a constructing C\nfrom assembly: it's horrible.\n\nThe instruction looks like this\n\n        bit      0        1        2        3       4      5      6\n  +----------+--------+--------+--------+--------+------+------+------+\n  | 1xxxxxxx | offset | offset | offset | offset | size | size | size |\n  +----------+--------+--------+--------+--------+------+------+------+\n\nHere you can see it in its full form, each box represents a byte. The\nfirst byte has bit 7 set as mentioned. We can see here that offsets\n(where to copy from in the source object) takes 4 bytes and size (how\nmany bytes to copy) takes 3. Offset size size is in LSB order.\n\nThe \"xxxxxxx\" part lets us shrink this down. If the offset can fit in\n16 bits, there's no reason to waste the last two bytes describing\nzero. Each 'x' marks whether the corresponding byte is present. The\nbit number is in the first row. So if you have offset 255 and size 1,\nthe instruction is three bytes 10010001b, 255, 1. The octets on \"bit\ncolumn\" 1, 2, 3, 5 and 6 are missing because the corresponding bit in\nthe first bit is not set.\n\n>> +  - If bit 4 is set, the following byte contains bits 0-7 of the copy\n>> +    size (this also resets all other bits in the copy size to zero_.\n>> +  - If bit 5 is set, the following byte contains bits 8-15 of the copy\n>> +    size.\n>> +  - If bit 6 is set, the following byte contains bits 16-23 of the\n>> +    copy size.\n>\n> bits 4-7 seem to be another group of mutually exclusive bits.\n> The same question as above:\n> If bit 6 is set, where are bits 0-15 of the copy size?\n\nI think this is a corner case in this format. I think Nico meant to\nspecify consecutive bytes: if size is 2 bytes then you have to specify\n_both_ of them even if the first byte could be zero and omitted.\n\nThe implementation detail is, if bit 6 is set but bit 4 is not, then\nthe size value is pretty much random. It's only when bit 4 is set that\nwe first clear out \"size\" and start adding bits to it.\n\n>\n>> +\n>> +  Copy size zero means 0x10000 bytes.\n>\n> This is an interesting caveat. So we can only copy 1-0x10000 bytes,\n> and cannot express to copy 0 bytes?\n\nYes. There's no point to copy nothing. And it saves space to not\nspecify \"size\" at all. I think this is meant to copy a very large part\nfrom the source, so you just continue to copy a series of 0x10000\nchunks.\n\n>\n>> The data from source object at\n>> +  the given copy offset is copied back to the destination buffer.\n>> +\n>> +- If bit 7 is not set, it is the copy size in bytes. The following\n>> +  bytes are copied to destination buffer\n>> +- Command byte zero is reserved for future expansion.\n>\n> Thanks,\n> Stefan\n\n\n\n-- \nDuy\n"},{"id":"347006","messageId":"CACsJy8AYjsLxvwCMXZ1PGu7iG=Vu5Dc7da-L-EmY+fBg_A4X8w@mail.gmail.com","threadId":"48389","inReplyTo":"87bmdqxb2s.fsf@evledraar.gmail.com","subject":"Re: [PATCH] pack-format.txt: more details on pack file format","fromName":"Duy Nguyen","fromEmail":"pclouds@gmail.com","sentAt":"2018-05-08T18:24:58Z","receivedAt":"2018-05-08T18:26:01Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Tue, May 8, 2018 at 8:21 PM, Ævar Arnfjörð Bjarmason\n<avarab@gmail.com> wrote:\n>\n> On Tue, May 08 2018, Nguyễn Thái Ngọc Duy wrote:\n>\n>> The current document mentions OBJ_* constants without their actual\n>> values. A git developer would know these are from cache.h but that's\n>> not very friendly to a person who wants to read this file to implement\n>> a pack file parser.\n>>\n>> Similarly, the deltified representation is not documented at all (the\n>> \"document\" is basically patch-delta.c). Translate that C code in\n>> English.\n>\n> Thanks, will drop my version from v4, although a comment for the enum in\n> cache.h pointing the reader to these docs would be very useful.\n\nTrue. I will add some together with the pack-format.txt update.\n-- \nDuy\n"},{"id":"347011","messageId":"87a7tax9m1.fsf@evledraar.gmail.com","threadId":"48389","inReplyTo":"20180508143408.GA30183@sigill.intra.peff.net","subject":"Re: [PATCH v3 09/12] get_short_oid / peel_onion: ^{tree} should be tree, not treeish","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2018-05-08T18:53:10Z","receivedAt":"2018-05-08T18:53:17Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"\nOn Tue, May 08 2018, Jeff King wrote:\n\n> On Mon, May 07, 2018 at 01:08:46PM +0900, Junio C Hamano wrote:\n>\n>> Ævar Arnfjörð Bjarmason <avarab@gmail.com> writes:\n>>\n>> > Right, and I'm with you so far, this makes sense to me for all existing\n>> > uses of the peel syntax, otherwise v2.17.0^{tree} wouldn't be the same\n>> > as rev-parse v2.17.0^{tree}^{tree}...\n>>\n>> More importantly, you could spell v2.17.0 part of the above with a\n>> short hexadecimal string.  And that string should be naming some\n>> tree-ish, the most important thing being that it is *NOT* required\n>> to be a tree (and practically, it is likely that the user has a\n>> tree-ish that is *NOT* a tree).\n>>\n>> I guess I have a reaction to the title\n>>\n>>     \"get_short_oid/peel_onion: ^{tree} should be tree\"\n>>\n>> \"X^{tree}\" should *RESULT* in a tree, but it should *REQUIRE* X to\n>> be a tree-ish.  It is unclear \"should be tree\" is about the former\n>> and I read (perhaps mis-read) it as saying \"it should require X to\n>> be a tree\"---that statement is utterly incorrect as we agreed above.\n>\n> FWIW, I had the same feeling as you when reading this, that this commit\n> (and the one after) are doing the wrong thing. And these paragraphs sum\n> it up. The \"^{tree}\" is about asking us to peel to a tree, not about\n> resolving X in the first place. We can use it as a _hint_ when resolving\n> X, but the correct hint is \"something that can be peeled to a tree\", not\n> \"is definitely a tree\".\n\nMaybe I'm just being dense, but I still don't get from this & Junio's\nE-Mails what the general rule should be.\n\nI think a response to the part after \"leaving that aside\" of my upthread\nE-Mail\n(https://public-inbox.org/git/87lgczyfq6.fsf@evledraar.gmail.com/) would\nhelp me out.\n\nNot to belabor the point, but here's a patch I came up with to\nrevisions.txt that's a WIP version of something that would describe the\nworldview after this v3:\n\n    diff --git a/Documentation/revisions.txt b/Documentation/revisions.txt\n    index dfcc49c72c..0bf68f4ad2 100644\n    --- a/Documentation/revisions.txt\n    +++ b/Documentation/revisions.txt\n    @@ -143,29 +143,52 @@ thing no matter the case.\n       '<rev>{caret}1{caret}1{caret}1'.  See below for an illustration of\n       the usage of this form.\n\n     '<rev>{caret}{<type>}', e.g. 'v0.99.8{caret}\\{commit\\}'::\n       A suffix '{caret}' followed by an object type name enclosed in\n       brace pair means dereference the object at '<rev>' recursively until\n       an object of type '<type>' is found or the object cannot be\n    -  dereferenced anymore (in which case, barf).\n    +  dereferenced anymore (in which case either return that object type, or barf).\n       For example, if '<rev>' is a commit-ish, '<rev>{caret}\\{commit\\}'\n       describes the corresponding commit object.\n       Similarly, if '<rev>' is a tree-ish, '<rev>{caret}\\{tree\\}'\n       describes the corresponding tree object.\n       '<rev>{caret}0'\n       is a short-hand for '<rev>{caret}\\{commit\\}'.\n     +\n     'rev{caret}\\{object\\}' can be used to make sure 'rev' names an\n     object that exists, without requiring 'rev' to be a tag, and\n     without dereferencing 'rev'; because a tag is already an object,\n     it does not have to be dereferenced even once to get to an object.\n     +\n     'rev{caret}\\{tag\\}' can be used to ensure that 'rev' identifies an\n     existing tag object.\n    ++\n    +Object types that don't have a 1=1 mapping to other object types\n    +cannot be dereferenced with the peel syntax, and will return an\n    +error. E.g. '<treeid>{caret}{commit}' or '<treeid>{caret}{tree}' is\n    +allowed because a tag can only point to one commit, and a commit can\n    +only point to one tree. But '<treeid>{caret}{blob}' will always\n    +produce an error since trees in general don't 1=1 map to blobs, even\n    +though the specific '<treeid>' in question might only contain one\n    +blob. Note that '<tagid>{caret}{blob}' is not an error if '<tagid>' is\n    +a tag that points directly to a blob, since that again becomes\n    +unambiguous.\n    ++\n    +'<rev>{caret}{<type>}' takes on a different meaning when '<rev>' is a\n    +SHA-1 that's ambiguous within the object store. In that case we don't\n    +have a 1=1 mapping anymore. E.g. e8f2 in git.git can refer to multiple\n    +objects of all the different object types. In that case\n    +{caret}{<type>} should always be an error to be consistent with the\n    +logic above, but that wouldn't be useful to anybody. Instead it'll\n    +fall back to being selector syntax for the given object types,\n    +e.g. e8f2{caret}{tag} will (as of writing this) return the v2.17.0\n    +tag, and {caret}{commit}, {caret}{tree} and {caret}{blob} will return\n    +commit, tree and blob objects, respectively.\n    +\n    [...]\n\nMy understanding of what you two are saying is that somehow the peel\nsemantics should be preserved when we take this beyond the 1=1 mapping\ncase, but I don't see how if we run with that how we wouldn't need to\nintroduce the concept of blobish for consistency as I noted upthread.\n\nSo it would be very useful to me if you or someone who understands the\nbehavior you & Junio seem to want could write a version of the patch I\nhave above where the last paragraph is different, and describes the\ndesired semantics, because I still don't get it. Why would we 1=many\npeel commits to trees as a special case, but not 1=many do the same for\ntrees & blobs?\n"},{"id":"347012","messageId":"CAGZ79ka2rEptsZKS+U-3ZNf4+R8b98f0E+ECdpndhb=JXLNLdQ@mail.gmail.com","threadId":"48389","inReplyTo":"CACsJy8A10qixJ7YtJKJejp1t49aBZFDn7CjSTiaq8GeVHuxiOQ@mail.gmail.com","subject":"Re: [PATCH] pack-format.txt: more details on pack file format","fromName":"Stefan Beller","fromEmail":"sbeller@google.com","sentAt":"2018-05-08T18:58:20Z","receivedAt":"2018-05-08T18:58:24Z","isPatch":true,"sender":{"key":"stefanbeller@gmail.com","avatar":"https://avatars.githubusercontent.com/u/455868?v=4"},"body":">>> +Deltified representation\n>>\n>> Does this refer to OFS delta as well as REF deltas?\n>\n> Yes. Both OFS and REF deltas have the same \"body\" which is what this\n> part is about. The differences between OFS and REF deltas are not\n> described (in fact I don't think we describe what OFS and REF deltas\n> are at all).\n\nMaybe we should?\n\n>\n>>> is a sequence of one byte command optionally\n>>> +followed by more data for the command. The following commands are\n>>> +recognized:\n>>\n>> So a Deltified representation of an object is a 6 or 7 in the 3 bit type\n>> and then the length. Then a command is shown how to construct\n>> the object based on other objects. Can there be more commands?\n>>\n>>> +- If bit 7 is set, the remaining bits in the command byte specifies\n>>> +  how to extract copy offset and size to copy. The following must be\n>>> +  evaluated in this exact order:\n>>\n>> So there are 2 modes, and the high bit indicates which mode is used.\n>> You start describing the more complicated mode first,\n>> maybe give names to both of them? \"direct copy\" (below) and\n>> \"compressed copy with offset\" ?\n>\n> I started to update this more because even this text is hard to get\n> even to me. So let's get the background first.\n>\n> We have a source object somewhere (the object name comes from ofs/ref\n> delta's header), basically we have the whole content. This delta\n> thingy tells us how to use that source object to create a new (target)\n> object.\n>\n> The delta is actually a sequence of instructions (of variable length).\n\nThe previous paragraph and this sentence are great for my understanding.\nthanks! (Maybe keep it in a similar form around?)\n\n> One is for copying from the source object.\n\nok that makes sense. I can think of it as a \"HTTP range request\", just\noptimized for packfiles and the source is inside the same pack.\nSo it would say \"Goto object <sha1> and copy bytes 13-168 here\"\n\n> The other copies from the\n> delta itself\n\nitself means the same object here, that we are describing here?\nor does it mean other deltas?\n\n> (e.g. this is new data in the target which is not\n> available anywhere in the source object to copy from).\n\n\n\n\n>\n> The instruction looks like this\n>\n>         bit      0        1        2        3       4      5      6\n>   +----------+--------+--------+--------+--------+------+------+------+\n>   | 1xxxxxxx | offset | offset | offset | offset | size | size | size |\n>   +----------+--------+--------+--------+--------+------+------+------+\n>\n> Here you can see it in its full form, each box represents a byte. The\n> first byte has bit 7 set as mentioned. We can see here that offsets\n> (where to copy from in the source object) takes 4 bytes and size (how\n> many bytes to copy) takes 3. Offset size size is in LSB order.\n>\n> The \"xxxxxxx\" part lets us shrink this down.\n\n.. by indicating how much prefix we can skip and assume it be all zero(?)\n\n> If the offset can fit in\n> 16 bits, there's no reason to waste the last two bytes describing\n> zero. Each 'x' marks whether the corresponding byte is present.\n\nSo for a full instruction (as above), we'd have to\n\n1 1111 111 <4 bytes offset> <3 bytes size>\n\nfor smaller instructions we have\n\n1 1100 100 <2 bytes offset> <1 byte size>\nand here the offset is in range 0..64k and\nthe size is 1-255 or 0x10000 ?\n\n\nModes to skip bytes in between are not allowed, e.g.\n1 1101 101 < 3 bytes of offsets> <2 bytes of size>\nand the missing bytes would be assumed to be 0?\n\n> The\n> bit number is in the first row. So if you have offset 255 and size 1,\n> the instruction is three bytes 10010001b, 255,\n\nOh it is the other way round, the size will be just one byte,\nindicating we can have a range of 1-255 or 0x10000 and an\noffset of 0..255.\n\n>\n> I think this is a corner case in this format. I think Nico meant to\n> specify consecutive bytes: if size is 2 bytes then you have to specify\n> _both_ of them even if the first byte could be zero and omitted.\n\nSo it is not a mutually exclusive group, but a sequence (similar as in\ngit-bisect), where we start with 0 and end with exactly one edge\nin between (sort of, we can also start with 1, then we have to have\nall 1s)\n\n> The implementation detail is, if bit 6 is set but bit 4 is not, then\n> the size value is pretty much random. It's only when bit 4 is set that\n> we first clear out \"size\" and start adding bits to it.\n\nThat sounds similar to what I spelled out above.\n\nThanks for taking on the documentation here.\nThe box with numbers really helped me!\n\nStefan\n"},{"id":"347056","messageId":"20180509075632.GA3327@sigill.intra.peff.net","threadId":"48389","inReplyTo":"87a7tax9m1.fsf@evledraar.gmail.com","subject":"Re: [PATCH v3 09/12] get_short_oid / peel_onion: ^{tree} should be tree, not treeish","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2018-05-09T07:56:32Z","receivedAt":"2018-05-09T07:56:37Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Tue, May 08, 2018 at 08:53:10PM +0200, Ævar Arnfjörð Bjarmason wrote:\n\n> >> \"X^{tree}\" should *RESULT* in a tree, but it should *REQUIRE* X to\n> >> be a tree-ish.  It is unclear \"should be tree\" is about the former\n> >> and I read (perhaps mis-read) it as saying \"it should require X to\n> >> be a tree\"---that statement is utterly incorrect as we agreed above.\n> >\n> > FWIW, I had the same feeling as you when reading this, that this commit\n> > (and the one after) are doing the wrong thing. And these paragraphs sum\n> > it up. The \"^{tree}\" is about asking us to peel to a tree, not about\n> > resolving X in the first place. We can use it as a _hint_ when resolving\n> > X, but the correct hint is \"something that can be peeled to a tree\", not\n> > \"is definitely a tree\".\n> \n> Maybe I'm just being dense, but I still don't get from this & Junio's\n> E-Mails what the general rule should be.\n\nLet me try to lay out my thinking a bit more clearly, and then I'll try\nto respond to the points you laid out below.\n\nBefore we had any disambiguation code, resolving X^{tree} really was two\nindependent steps: resolve X, and then peel it to a tree. When we added\nthe disambiguation code, the goal was to provide a hint to the first\nstep in such a way that we could never eliminate any resolutions that\nthe user _might_ have meant. But it's OK to take a situation where every\ncase but one would result in an error, and assume the user meant that\ncase. Sort of a \"do no harm\" rule.\n\nBy disambiguating with just a tree and not a tree-ish, that hint is now\neliminating possibilities that would have worked in the second step,\nwhich violates the rule.\n\nDoes thinking about it that way make more sense?\n\n> I think a response to the part after \"leaving that aside\" of my upthread\n> E-Mail\n> (https://public-inbox.org/git/87lgczyfq6.fsf@evledraar.gmail.com/) would\n> help me out.\n\nI'll quote that bit here:\n\n> But *leaving that aside*, i.e. I don't see why the use-case would make\n> sense. What I *don't* get is why, if you think that, you only want to\n> apply that rule to ^{tree}. I.e. wouldn't it then be consistent to say:\n> \n>     # a)\n>     ^{tag}    = tag\n>     ^{commit} = tag, commit\n>     ^{tree}   = tag, commit, tree\n>     ^{blob}   = tag, blob (blobish)\n\nYes, that makes sense to me conceptually, and would follow the rule I\ngave above. And I think that's what we do now, with the exception that\nthere is no blobish disambiguation. Presumably nobody ever bothered\nbecause probably because tagged blobs are pretty rare (and obviously\nthough trees point to blobs, you cannot disambiguate that way since\nthere's no one-to-one correspondence).\n\nSo I doubt anybody really cares in practice, but I agree that it would\nimprove consistency to write a patch to introduce GET_OID_BLOBISH and\nhave \"^{blob}\" parsing use it.  And possibly add \"blobish\" to\ncore.disambiguate (or is it \"blobbish\"?), though that's almost certainly\nsomething nobody would ever use.\n\n> My understanding of what you two are saying is that somehow the peel\n> semantics should be preserved when we take this beyond the 1=1 mapping\n> case, but I don't see how if we run with that how we wouldn't need to\n> introduce the concept of blobish for consistency as I noted upthread.\n\nYeah, I think the lack of blobish is a bug, just one that nobody has\never really cared about.\n\n> So it would be very useful to me if you or someone who understands the\n> behavior you & Junio seem to want could write a version of the patch I\n> have above where the last paragraph is different, and describes the\n> desired semantics, because I still don't get it. Why would we 1=many\n> peel commits to trees as a special case, but not 1=many do the same for\n> trees & blobs?\n\nI'm not sure I understand the mention of trees in the final sentence.\nAFAICT tree disambiguation is consistent with the peeling rules.\n\n-Peff\n"},{"id":"347061","messageId":"878t8txfyf.fsf@evledraar.gmail.com","threadId":"48389","inReplyTo":"20180509075632.GA3327@sigill.intra.peff.net","subject":"Re: [PATCH v3 09/12] get_short_oid / peel_onion: ^{tree} should be tree, not treeish","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2018-05-09T10:48:24Z","receivedAt":"2018-05-09T10:48:32Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"\nOn Wed, May 09 2018, Jeff King wrote:\n\n> On Tue, May 08, 2018 at 08:53:10PM +0200, Ævar Arnfjörð Bjarmason wrote:\n>\n>> >> \"X^{tree}\" should *RESULT* in a tree, but it should *REQUIRE* X to\n>> >> be a tree-ish.  It is unclear \"should be tree\" is about the former\n>> >> and I read (perhaps mis-read) it as saying \"it should require X to\n>> >> be a tree\"---that statement is utterly incorrect as we agreed above.\n>> >\n>> > FWIW, I had the same feeling as you when reading this, that this commit\n>> > (and the one after) are doing the wrong thing. And these paragraphs sum\n>> > it up. The \"^{tree}\" is about asking us to peel to a tree, not about\n>> > resolving X in the first place. We can use it as a _hint_ when resolving\n>> > X, but the correct hint is \"something that can be peeled to a tree\", not\n>> > \"is definitely a tree\".\n>>\n>> Maybe I'm just being dense, but I still don't get from this & Junio's\n>> E-Mails what the general rule should be.\n>\n> Let me try to lay out my thinking a bit more clearly, and then I'll try\n> to respond to the points you laid out below.\n>\n> Before we had any disambiguation code, resolving X^{tree} really was two\n> independent steps: resolve X, and then peel it to a tree. When we added\n> the disambiguation code, the goal was to provide a hint to the first\n> step in such a way that we could never eliminate any resolutions that\n> the user _might_ have meant. But it's OK to take a situation where every\n> case but one would result in an error, and assume the user meant that\n> case. Sort of a \"do no harm\" rule.\n>\n> By disambiguating with just a tree and not a tree-ish, that hint is now\n> eliminating possibilities that would have worked in the second step,\n> which violates the rule.\n>\n> Does thinking about it that way make more sense?\n\nOkey, so to rephrase that to make sure I understand it. It would be\ndocumented as something like this:\n\n    When the short SHA-1 X is ambiguous X^{<type>} doesn't mean do the\n    peel itself in X any way, rather it means list all those objects\n    matching X where a subsequent X^{<type>} wouldn't be an error.\n\n    I.e. X^{commit} will list tags and commits, since both can be peeled\n    to reveal a commit, X^{tree} will similarly list tags, commits and\n    trees, and X^{blob} will list tags and blobs[1], and X^{tag} will\n    only list tags.\n\n    But core.disambiguate=[tag|commit|tree|blob] is not at all like\n    ^{[tag|commit|tree|blob]} and is unlike the peel syntax only going\n    to list the objects of the respective type. The config synonym for\n    the peel syntax is committish, treeish, and the nonexistent blobish.\n\n>> I think a response to the part after \"leaving that aside\" of my upthread\n>> E-Mail\n>> (https://public-inbox.org/git/87lgczyfq6.fsf@evledraar.gmail.com/) would\n>> help me out.\n>\n> I'll quote that bit here:\n>\n>> But *leaving that aside*, i.e. I don't see why the use-case would make\n>> sense. What I *don't* get is why, if you think that, you only want to\n>> apply that rule to ^{tree}. I.e. wouldn't it then be consistent to say:\n>>\n>>     # a)\n>>     ^{tag}    = tag\n>>     ^{commit} = tag, commit\n>>     ^{tree}   = tag, commit, tree\n>>     ^{blob}   = tag, blob (blobish)\n>\n> Yes, that makes sense to me conceptually, and would follow the rule I\n> gave above. And I think that's what we do now, with the exception that\n> there is no blobish disambiguation. Presumably nobody ever bothered\n> because probably because tagged blobs are pretty rare (and obviously\n> though trees point to blobs, you cannot disambiguate that way since\n> there's no one-to-one correspondence).\n>\n> So I doubt anybody really cares in practice, but I agree that it would\n> improve consistency to write a patch to introduce GET_OID_BLOBISH and\n> have \"^{blob}\" parsing use it.  And possibly add \"blobish\" to\n> core.disambiguate (or is it \"blobbish\"?), though that's almost certainly\n> something nobody would ever use.\n\nYeah, I'll introduce it for consistency. To clarify I wasn't trying to\nmake some argument on the basis that we didn't have it, but I was\nconfused because I couldn't see how the general rule would apply to\n^{tree} and not ^{blob}.\n\n>> My understanding of what you two are saying is that somehow the peel\n>> semantics should be preserved when we take this beyond the 1=1 mapping\n>> case, but I don't see how if we run with that how we wouldn't need to\n>> introduce the concept of blobish for consistency as I noted upthread.\n>\n> Yeah, I think the lack of blobish is a bug, just one that nobody has\n> ever really cared about.\n>\n>> So it would be very useful to me if you or someone who understands the\n>> behavior you & Junio seem to want could write a version of the patch I\n>> have above where the last paragraph is different, and describes the\n>> desired semantics, because I still don't get it. Why would we 1=many\n>> peel commits to trees as a special case, but not 1=many do the same for\n>> trees & blobs?\n>\n> I'm not sure I understand the mention of trees in the final sentence.\n> AFAICT tree disambiguation is consistent with the peeling rules.\n\nYeah nevermind that, I was imagining some semantics where because we\ndropped the 1=1 mapping ^{tree} would list blobs, but in the worldview\nyou describe above (if I got it right) that doesn't make sense.\n\n1. Not currently, but I should amend my ^{blob} patch to work like that.\n"},{"id":"347169","messageId":"xmqqa7t8kuo0.fsf@gitster-ct.c.googlers.com","threadId":"48389","inReplyTo":"878t8txfyf.fsf@evledraar.gmail.com","subject":"Re: [PATCH v3 09/12] get_short_oid / peel_onion: ^{tree} should be tree, not treeish","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2018-05-10T04:21:19Z","receivedAt":"2018-05-10T04:21:25Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Ævar Arnfjörð Bjarmason <avarab@gmail.com> writes:\n\n>> Before we had any disambiguation code, resolving X^{tree} really was two\n>> independent steps: resolve X, and then peel it to a tree. When we added\n>> the disambiguation code, the goal was to provide a hint to the first\n>> step in such a way that we could never eliminate any resolutions that\n>> the user _might_ have meant. But it's OK to take a situation where every\n>> case but one would result in an error, and assume the user meant that\n>> case. Sort of a \"do no harm\" rule.\n>>\n>> By disambiguating with just a tree and not a tree-ish, that hint is now\n>> eliminating possibilities that would have worked in the second step,\n>> which violates the rule.\n>>\n>> Does thinking about it that way make more sense?\n>\n> Okey, so to rephrase that to make sure I understand it. It would be\n> documented as something like this:\n>\n>     When the short SHA-1 X is ambiguous X^{<type>} doesn't mean do the\n>     peel itself in X any way, rather it means list all those objects\n>     matching X where a subsequent X^{<type>} wouldn't be an error.\n\nWith the understanding that this paragraph is written primarily for\nyour own enlightenment, I wouldn't complain too much, but if you\nmeant this to become part of end-user documentation, I have a strong\nissue with the verb \"list\" used here.\n\nX^{<type>} never means to \"list\" anything (FWIW just X does not mean\nto \"list\" anything, either).  It just means that the user wants to\nspecify a single object whose object name is X^{<type>}, i.e. the\nuser expects that X names a single object, that can be peeled to\n<type>.\n\nNow, it is an error when (1) X does not specify a single object in\nthe first place, or (2) the single object cannot be peeled to <type>.\n\nWhen diagnosing such an error, we would give hints.  The hint would\nshow possible objects that the user could have meant with X.  The\n^{<type>} suffix given to it may be used to limit the hints to\nsubset of the objects that the user could have meant with X;\ne.g. when there is an object of each of type blob, tree, commit, and\ntag, whose name begins with 7777, the short and ambiguous prefix\n7777 could mean any of these four objects, but when given with\nsuffix, e.g. 7777^{tree}, it makes useless for the hint to include\nthe blob object, as it can never peel down to a tree object.\n\nIf the tag whose name begins with 7777 in this example points\ndirectly to a blob, excluding that tag from the hint would make the\nhint more useful.  I do not offhand know what the code does right\nnow.  I wouldn't call it a bug if such a tag is included in the\nhint, but if a change stops such a tag from getting included, I\nwould call such a change an improvement.\n\n>     I.e. X^{commit} will list tags and commits, since both can be peeled\n>     to reveal a commit, X^{tree} will similarly list tags, commits and\n>     trees, and X^{blob} will list tags and blobs[1], and X^{tag} will\n>     only list tags.\n\nModulo the use of \"list\", which I have trouble is as it makes it\nsound as if listing something is the purpose of the notation, I\nthink we are on the same page up to this point\n\nI think the best way to explain core.disambiguate to readers is to\nmake them rethink what I meant with \"the user expects that X names a\nsingle object\" in the early part of the above response.\n\nWithout constraint, Git understood that the user used 7777 to name\nany one of the objects of all four types.  With core.disambiguate,\nthe user can tell Git \"when I give potentially ambiguous object name\nwith a short prefix, assume that only a commit or a tag whose name\nbegins with the prefix is what I expected the short prefix to name\nuniquely\", so Git understood that the user wanted to name either a\ncommit or a tag.  It would still trigger an error as it does not\nuniquely name an object (for which an attempt to apply the ^{tree}\npeeling would further be made).\n\n"},{"id":"347183","messageId":"20180510065009.GB31779@sigill.intra.peff.net","threadId":"48389","inReplyTo":"xmqqa7t8kuo0.fsf@gitster-ct.c.googlers.com","subject":"Re: [PATCH v3 09/12] get_short_oid / peel_onion: ^{tree} should be tree, not treeish","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2018-05-10T06:50:09Z","receivedAt":"2018-05-10T06:50:14Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Thu, May 10, 2018 at 01:21:19PM +0900, Junio C Hamano wrote:\n\n> When diagnosing such an error, we would give hints.  The hint would\n> show possible objects that the user could have meant with X.  The\n> ^{<type>} suffix given to it may be used to limit the hints to\n> subset of the objects that the user could have meant with X;\n> e.g. when there is an object of each of type blob, tree, commit, and\n> tag, whose name begins with 7777, the short and ambiguous prefix\n> 7777 could mean any of these four objects, but when given with\n> suffix, e.g. 7777^{tree}, it makes useless for the hint to include\n> the blob object, as it can never peel down to a tree object.\n> \n> If the tag whose name begins with 7777 in this example points\n> directly to a blob, excluding that tag from the hint would make the\n> hint more useful.  I do not offhand know what the code does right\n> now.  I wouldn't call it a bug if such a tag is included in the\n> hint, but if a change stops such a tag from getting included, I\n> would call such a change an improvement.\n\nI actually wondered this while writing an earlier response, and so I\nhappen to know: when we are looking for a treeish, the disambiguator\nwill actually peel a candidate tag and only accept one that peels to a\ntree or commit. So we would omit the tag-to-blob entirely from\nconsideration (both as a candidate for ambiguity, and in the hint list).\n\n-Peff\n"},{"id":"347213","messageId":"20180510124303.6020-1-avarab@gmail.com","threadId":"48389","inReplyTo":"20180501184016.15061-10-avarab@gmail.com","subject":"[PATCH v4 0/6] get_short_oid UI improvements","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2018-05-10T12:42:57Z","receivedAt":"2018-05-10T12:43:21Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"This is like v3 except all the patches to the peel syntax & docs have\nbeen dropped, which were controversial.\n\nI think it's worthwhile to re-work that, but I don't have time for\nthat now, so I'm submitting this. Maybe I'll have time in the future\nto re-work the rest, but then I can base it on top of this.\n\nÆvar Arnfjörð Bjarmason (6):\n  sha1-name.c: remove stray newline\n  sha1-array.h: align function arguments\n  git-p4: change \"commitish\" typo to \"committish\"\n  sha1-name.c: move around the collect_ambiguous() function\n  get_short_oid: sort ambiguous objects by type, then SHA-1\n  get_short_oid: document & warn if we ignore the type selector\n\n Documentation/technical/api-oid-array.txt | 17 ++++---\n git-p4.py                                 |  6 +--\n sha1-array.c                              | 21 +++++++-\n sha1-array.h                              |  7 ++-\n sha1-name.c                               | 61 +++++++++++++++++++----\n t/t1512-rev-parse-disambiguation.sh       | 26 +++++++++-\n 6 files changed, 115 insertions(+), 23 deletions(-)\n\n-- \n2.17.0.410.g4ac3413cc8\n\n"},{"id":"347214","messageId":"20180510124303.6020-2-avarab@gmail.com","threadId":"48389","inReplyTo":"20180510124303.6020-1-avarab@gmail.com","subject":"[PATCH v4 1/6] sha1-name.c: remove stray newline","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2018-05-10T12:42:58Z","receivedAt":"2018-05-10T12:43:25Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"This stray newline was accidentally introduced in\nd2b7d9c7ed (\"sha1_name: convert disambiguate_hint_fn to take\nobject_id\", 2017-03-26).\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n sha1-name.c | 1 -\n 1 file changed, 1 deletion(-)\n\ndiff --git a/sha1-name.c b/sha1-name.c\nindex 5b93bf8da3..cd3b133aae 100644\n--- a/sha1-name.c\n+++ b/sha1-name.c\n@@ -346,7 +346,6 @@ static int show_ambiguous_object(const struct object_id *oid, void *data)\n \tstruct strbuf desc = STRBUF_INIT;\n \tint type;\n \n-\n \tif (ds->fn && !ds->fn(oid, ds->cb_data))\n \t\treturn 0;\n \n-- \n2.17.0.410.g4ac3413cc8\n\n"},{"id":"347215","messageId":"20180510124303.6020-3-avarab@gmail.com","threadId":"48389","inReplyTo":"20180510124303.6020-1-avarab@gmail.com","subject":"[PATCH v4 2/6] sha1-array.h: align function arguments","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2018-05-10T12:42:59Z","receivedAt":"2018-05-10T12:43:26Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"The arguments weren't lined up with the opening parenthesis. Fixes up\ncode added in aae0caf19e (\"sha1-array.h: align function arguments\",\n2018-04-30).\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n sha1-array.c | 4 ++--\n sha1-array.h | 4 ++--\n 2 files changed, 4 insertions(+), 4 deletions(-)\n\ndiff --git a/sha1-array.c b/sha1-array.c\nindex 838b3bf847..466a926aa3 100644\n--- a/sha1-array.c\n+++ b/sha1-array.c\n@@ -42,8 +42,8 @@ void oid_array_clear(struct oid_array *array)\n }\n \n int oid_array_for_each_unique(struct oid_array *array,\n-\t\t\t\tfor_each_oid_fn fn,\n-\t\t\t\tvoid *data)\n+\t\t\t      for_each_oid_fn fn,\n+\t\t\t      void *data)\n {\n \tint i;\n \ndiff --git a/sha1-array.h b/sha1-array.h\nindex 04b0756334..1e1d24b009 100644\n--- a/sha1-array.h\n+++ b/sha1-array.h\n@@ -17,7 +17,7 @@ void oid_array_clear(struct oid_array *array);\n typedef int (*for_each_oid_fn)(const struct object_id *oid,\n \t\t\t       void *data);\n int oid_array_for_each_unique(struct oid_array *array,\n-\t\t\t       for_each_oid_fn fn,\n-\t\t\t       void *data);\n+\t\t\t      for_each_oid_fn fn,\n+\t\t\t      void *data);\n \n #endif /* SHA1_ARRAY_H */\n-- \n2.17.0.410.g4ac3413cc8\n\n"},{"id":"347216","messageId":"20180510124303.6020-4-avarab@gmail.com","threadId":"48389","inReplyTo":"20180510124303.6020-1-avarab@gmail.com","subject":"[PATCH v4 3/6] git-p4: change \"commitish\" typo to \"committish\"","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2018-05-10T12:43:00Z","receivedAt":"2018-05-10T12:43:30Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"This was the only occurrence of \"commitish\" in the tree, but as the\nlog will reveal we've had others in the past. Fixes up code added in\n00ad6e3182 (\"git-p4: work with a detached head\", 2015-11-21).\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n git-p4.py | 6 +++---\n 1 file changed, 3 insertions(+), 3 deletions(-)\n\ndiff --git a/git-p4.py b/git-p4.py\nindex 7bb9cadc69..1afa87cd9d 100755\n--- a/git-p4.py\n+++ b/git-p4.py\n@@ -2099,11 +2099,11 @@ class P4Submit(Command, P4UserMap):\n \n         commits = []\n         if self.master:\n-            commitish = self.master\n+            committish = self.master\n         else:\n-            commitish = 'HEAD'\n+            committish = 'HEAD'\n \n-        for line in read_pipe_lines([\"git\", \"rev-list\", \"--no-merges\", \"%s..%s\" % (self.origin, commitish)]):\n+        for line in read_pipe_lines([\"git\", \"rev-list\", \"--no-merges\", \"%s..%s\" % (self.origin, committish)]):\n             commits.append(line.strip())\n         commits.reverse()\n \n-- \n2.17.0.410.g4ac3413cc8\n\n"},{"id":"347217","messageId":"20180510124303.6020-5-avarab@gmail.com","threadId":"48389","inReplyTo":"20180510124303.6020-1-avarab@gmail.com","subject":"[PATCH v4 4/6] sha1-name.c: move around the collect_ambiguous() function","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2018-05-10T12:43:01Z","receivedAt":"2018-05-10T12:43:34Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"A subsequent change will make use of this static function in the\nget_short_oid() function, which is defined above where the\ncollect_ambiguous() function is now. Without this we'd then have a\ncompilation error due to a forward declaration.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n sha1-name.c | 12 ++++++------\n 1 file changed, 6 insertions(+), 6 deletions(-)\n\ndiff --git a/sha1-name.c b/sha1-name.c\nindex cd3b133aae..9d7bbd3e96 100644\n--- a/sha1-name.c\n+++ b/sha1-name.c\n@@ -372,6 +372,12 @@ static int show_ambiguous_object(const struct object_id *oid, void *data)\n \treturn 0;\n }\n \n+static int collect_ambiguous(const struct object_id *oid, void *data)\n+{\n+\toid_array_append(data, oid);\n+\treturn 0;\n+}\n+\n static int get_short_oid(const char *name, int len, struct object_id *oid,\n \t\t\t  unsigned flags)\n {\n@@ -421,12 +427,6 @@ static int get_short_oid(const char *name, int len, struct object_id *oid,\n \treturn status;\n }\n \n-static int collect_ambiguous(const struct object_id *oid, void *data)\n-{\n-\toid_array_append(data, oid);\n-\treturn 0;\n-}\n-\n int for_each_abbrev(const char *prefix, each_abbrev_fn fn, void *cb_data)\n {\n \tstruct oid_array collect = OID_ARRAY_INIT;\n-- \n2.17.0.410.g4ac3413cc8\n\n"},{"id":"347218","messageId":"20180510124303.6020-6-avarab@gmail.com","threadId":"48389","inReplyTo":"20180510124303.6020-1-avarab@gmail.com","subject":"[PATCH v4 5/6] get_short_oid: sort ambiguous objects by type, then SHA-1","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2018-05-10T12:43:02Z","receivedAt":"2018-05-10T12:43:35Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"Change the output emitted when an ambiguous object is encountered so\nthat we show tags first, then commits, followed by trees, and finally\nblobs. Within each type we show objects in hashcmp() order. Before\nthis change the objects were only ordered by hashcmp().\n\nThe reason for doing this is that the output looks better as a result,\ne.g. the v2.17.0 tag before this change on \"git show e8f2\" would\ndisplay:\n\n    hint: The candidates are:\n    hint:   e8f2093055 tree\n    hint:   e8f21caf94 commit 2013-06-24 - bash prompt: print unique detached HEAD abbreviated object name\n    hint:   e8f21d02f7 blob\n    hint:   e8f21d577c blob\n    hint:   e8f25a3a50 tree\n    hint:   e8f26250fa commit 2017-02-03 - Merge pull request #996 from jeffhostetler/jeffhostetler/register_rename_src\n    hint:   e8f2650052 tag v2.17.0\n    hint:   e8f2867228 blob\n    hint:   e8f28d537c tree\n    hint:   e8f2a35526 blob\n    hint:   e8f2bc0c06 commit 2015-05-10 - Documentation: note behavior for multiple remote.url entries\n    hint:   e8f2cf6ec0 tree\n\nNow we'll instead show:\n\n    hint:   e8f2650052 tag v2.17.0\n    hint:   e8f21caf94 commit 2013-06-24 - bash prompt: print unique detached HEAD abbreviated object name\n    hint:   e8f26250fa commit 2017-02-03 - Merge pull request #996 from jeffhostetler/jeffhostetler/register_rename_src\n    hint:   e8f2bc0c06 commit 2015-05-10 - Documentation: note behavior for multiple remote.url entries\n    hint:   e8f2093055 tree\n    hint:   e8f25a3a50 tree\n    hint:   e8f28d537c tree\n    hint:   e8f2cf6ec0 tree\n    hint:   e8f21d02f7 blob\n    hint:   e8f21d577c blob\n    hint:   e8f2867228 blob\n    hint:   e8f2a35526 blob\n\nSince we show the commit data in the output that's nicely aligned once\nwe sort by object type. The decision to show tags before commits is\npretty arbitrary. I don't want to order by object_type since there\ntags come last after blobs, which doesn't make sense if we want to\nshow the most important things first.\n\nI could display them after commits, but it's much less likely that\nwe'll display a tag, so if there is one it makes sense to show it\nprominently at the top.\n\nA note on the implementation: Derrick rightly pointed out[1] that\nwe're bending over backwards here in get_short_oid() to first\nde-duplicate the list, and then emit it, but could simply do it in one\nstep.\n\nThe reason for that is that oid_array_for_each_unique() doesn't\nactually require that the array be sorted by oid_array_sort(), it just\nneeds to be sorted in some order that guarantees that all objects with\nthe same ID are adjacent to one another, which (barring a hash\ncollision, which'll be someone else's problem) the sort_ambiguous()\nfunction does.\n\nI agree that would be simpler for this code, and had forgotten why I\ninitially wrote it like this[2]. But on further reflection I think\nit's better to do more work here just so we're not underhandedly using\nthe oid-array API where we lie about the list being sorted. That would\nbreak any subsequent use of oid_array_lookup() in subtle ways.\n\nI could get around that by hacking the API itself to support this\nuse-case and documenting it, which I did as a WIP patch in [3], but I\nthink it's too much code smell just for this one call site. It's\nsimpler for the API to just introduce a oid_array_for_each() function\nto eagerly spew out the list without sorting or de-duplication, and\nthen do the de-duplication and sorting in two passes.\n\n1. https://public-inbox.org/git/20180501130318.58251-1-dstolee@microsoft.com/\n2. https://public-inbox.org/git/876047ze9v.fsf@evledraar.gmail.com/\n3. https://public-inbox.org/git/874ljrzctc.fsf@evledraar.gmail.com/\n\nHelped-by: Derrick Stolee <dstolee@microsoft.com>\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n Documentation/technical/api-oid-array.txt | 17 +++++++----\n sha1-array.c                              | 17 +++++++++++\n sha1-array.h                              |  3 ++\n sha1-name.c                               | 37 ++++++++++++++++++++++-\n t/t1512-rev-parse-disambiguation.sh       | 21 +++++++++++++\n 5 files changed, 88 insertions(+), 7 deletions(-)\n\ndiff --git a/Documentation/technical/api-oid-array.txt b/Documentation/technical/api-oid-array.txt\nindex b0c11f868d..94b529722c 100644\n--- a/Documentation/technical/api-oid-array.txt\n+++ b/Documentation/technical/api-oid-array.txt\n@@ -35,13 +35,18 @@ Functions\n \tFree all memory associated with the array and return it to the\n \tinitial, empty state.\n \n+`oid_array_for_each`::\n+\tIterate over each element of the list, executing the callback\n+\tfunction for each one. Does not sort the list, so any custom\n+\thash order is retained. If the callback returns a non-zero\n+\tvalue, the iteration ends immediately and the callback's\n+\treturn is propagated; otherwise, 0 is returned.\n+\n `oid_array_for_each_unique`::\n-\tEfficiently iterate over each unique element of the list,\n-\texecuting the callback function for each one. If the array is\n-\tnot sorted, this function has the side effect of sorting it. If\n-\tthe callback returns a non-zero value, the iteration ends\n-\timmediately and the callback's return is propagated; otherwise,\n-\t0 is returned.\n+\tIterate over each unique element of the list in sort order ,\n+\tbut otherwise behaves like `oid_array_for_each`. If the array\n+\tis not sorted, this function has the side effect of sorting\n+\tit.\n \n Examples\n --------\ndiff --git a/sha1-array.c b/sha1-array.c\nindex 466a926aa3..265941fbf4 100644\n--- a/sha1-array.c\n+++ b/sha1-array.c\n@@ -41,6 +41,23 @@ void oid_array_clear(struct oid_array *array)\n \tarray->sorted = 0;\n }\n \n+\n+int oid_array_for_each(struct oid_array *array,\n+\t\t       for_each_oid_fn fn,\n+\t\t       void *data)\n+{\n+\tint i;\n+\n+\t/* No oid_array_sort() here! See the api-oid-array.txt docs! */\n+\n+\tfor (i = 0; i < array->nr; i++) {\n+\t\tint ret = fn(array->oid + i, data);\n+\t\tif (ret)\n+\t\t\treturn ret;\n+\t}\n+\treturn 0;\n+}\n+\n int oid_array_for_each_unique(struct oid_array *array,\n \t\t\t      for_each_oid_fn fn,\n \t\t\t      void *data)\ndiff --git a/sha1-array.h b/sha1-array.h\nindex 1e1d24b009..232bf95017 100644\n--- a/sha1-array.h\n+++ b/sha1-array.h\n@@ -16,6 +16,9 @@ void oid_array_clear(struct oid_array *array);\n \n typedef int (*for_each_oid_fn)(const struct object_id *oid,\n \t\t\t       void *data);\n+int oid_array_for_each(struct oid_array *array,\n+\t\t       for_each_oid_fn fn,\n+\t\t       void *data);\n int oid_array_for_each_unique(struct oid_array *array,\n \t\t\t      for_each_oid_fn fn,\n \t\t\t      void *data);\ndiff --git a/sha1-name.c b/sha1-name.c\nindex 9d7bbd3e96..46d8b1afa6 100644\n--- a/sha1-name.c\n+++ b/sha1-name.c\n@@ -378,6 +378,34 @@ static int collect_ambiguous(const struct object_id *oid, void *data)\n \treturn 0;\n }\n \n+static int sort_ambiguous(const void *a, const void *b)\n+{\n+\tint a_type = oid_object_info(a, NULL);\n+\tint b_type = oid_object_info(b, NULL);\n+\tint a_type_sort;\n+\tint b_type_sort;\n+\n+\t/*\n+\t * Sorts by hash within the same object type, just as\n+\t * oid_array_for_each_unique() would do.\n+\t */\n+\tif (a_type == b_type)\n+\t\treturn oidcmp(a, b);\n+\n+\t/*\n+\t * Between object types show tags, then commits, and finally\n+\t * trees and blobs.\n+\t *\n+\t * The object_type enum is commit, tree, blob, tag, but we\n+\t * want tag, commit, tree blob. Cleverly (perhaps too\n+\t * cleverly) do that with modulus, since the enum assigns 1 to\n+\t * commit, so tag becomes 0.\n+\t */\n+\ta_type_sort = a_type % 4;\n+\tb_type_sort = b_type % 4;\n+\treturn a_type_sort > b_type_sort ? 1 : -1;\n+}\n+\n static int get_short_oid(const char *name, int len, struct object_id *oid,\n \t\t\t  unsigned flags)\n {\n@@ -409,6 +437,8 @@ static int get_short_oid(const char *name, int len, struct object_id *oid,\n \tstatus = finish_object_disambiguation(&ds, oid);\n \n \tif (!quietly && (status == SHORT_NAME_AMBIGUOUS)) {\n+\t\tstruct oid_array collect = OID_ARRAY_INIT;\n+\n \t\terror(_(\"short SHA1 %s is ambiguous\"), ds.hex_pfx);\n \n \t\t/*\n@@ -421,7 +451,12 @@ static int get_short_oid(const char *name, int len, struct object_id *oid,\n \t\t\tds.fn = NULL;\n \n \t\tadvise(_(\"The candidates are:\"));\n-\t\tfor_each_abbrev(ds.hex_pfx, show_ambiguous_object, &ds);\n+\t\tfor_each_abbrev(ds.hex_pfx, collect_ambiguous, &collect);\n+\t\tQSORT(collect.oid, collect.nr, sort_ambiguous);\n+\n+\t\tif (oid_array_for_each(&collect, show_ambiguous_object, &ds))\n+\t\t\tBUG(\"show_ambiguous_object shouldn't return non-zero\");\n+\t\toid_array_clear(&collect);\n \t}\n \n \treturn status;\ndiff --git a/t/t1512-rev-parse-disambiguation.sh b/t/t1512-rev-parse-disambiguation.sh\nindex 711704ba5a..2701462041 100755\n--- a/t/t1512-rev-parse-disambiguation.sh\n+++ b/t/t1512-rev-parse-disambiguation.sh\n@@ -361,4 +361,25 @@ test_expect_success 'core.disambiguate does not override context' '\n \t\tgit -c core.disambiguate=committish rev-parse $sha1^{tree}\n '\n \n+test_expect_success C_LOCALE_OUTPUT 'ambiguous commits are printed by type first, then hash order' '\n+\ttest_must_fail git rev-parse 0000 2>stderr &&\n+\tgrep ^hint: stderr >hints &&\n+\tgrep 0000 hints >objects &&\n+\tcat >expected <<-\\EOF &&\n+\ttag\n+\tcommit\n+\ttree\n+\tblob\n+\tEOF\n+\tawk \"{print \\$3}\" <objects >objects.types &&\n+\tuniq <objects.types >objects.types.uniq &&\n+\ttest_cmp expected objects.types.uniq &&\n+\tfor type in tag commit tree blob\n+\tdo\n+\t\tgrep $type objects >$type.objects &&\n+\t\tsort $type.objects >$type.objects.sorted &&\n+\t\ttest_cmp $type.objects.sorted $type.objects\n+\tdone\n+'\n+\n test_done\n-- \n2.17.0.410.g4ac3413cc8\n\n"},{"id":"347219","messageId":"20180510124303.6020-7-avarab@gmail.com","threadId":"48389","inReplyTo":"20180510124303.6020-1-avarab@gmail.com","subject":"[PATCH v4 6/6] get_short_oid: document & warn if we ignore the type selector","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2018-05-10T12:43:03Z","receivedAt":"2018-05-10T12:43:40Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"The SHA1 prefix 06fa currently matches no blobs in git.git. When\ndisambiguating short SHA1s we've been quietly ignoring the user's type\nselector as a fallback mechanism, this was intentionally added in\n1ffa26c461 (\"get_short_sha1: list ambiguous objects on error\",\n2016-09-26).\n\nI think that behavior makes sense, it's not very useful to just show\nnothing because a preference has been expressed via core.disambiguate,\nbut it's bad that we're quietly doing this. The user might thing that\nwe just didn't understand what e.g 06fa^{blob} meant.\n\nNow we'll instead print a warning if no objects of the requested type\nwere found:\n\n    $ git rev-parse 06fa^{blob}\n    error: short SHA1 06fa is ambiguous\n    hint: The candidates are:\n    [... no blobs listed ...]\n    warning: Your hint (via core.disambiguate or peel syntax) was ignored, we fell\n    back to showing all object types since no object of the requested type\n    matched the provide short SHA1 06fa\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n sha1-name.c                         | 11 ++++++++++-\n t/t1512-rev-parse-disambiguation.sh |  5 ++++-\n 2 files changed, 14 insertions(+), 2 deletions(-)\n\ndiff --git a/sha1-name.c b/sha1-name.c\nindex 46d8b1afa6..df33cc2dba 100644\n--- a/sha1-name.c\n+++ b/sha1-name.c\n@@ -438,6 +438,7 @@ static int get_short_oid(const char *name, int len, struct object_id *oid,\n \n \tif (!quietly && (status == SHORT_NAME_AMBIGUOUS)) {\n \t\tstruct oid_array collect = OID_ARRAY_INIT;\n+\t\tint ignored_hint = 0;\n \n \t\terror(_(\"short SHA1 %s is ambiguous\"), ds.hex_pfx);\n \n@@ -447,8 +448,10 @@ static int get_short_oid(const char *name, int len, struct object_id *oid,\n \t\t * that case, we still want to show them, so disable the hint\n \t\t * function entirely.\n \t\t */\n-\t\tif (!ds.ambiguous)\n+\t\tif (!ds.ambiguous) {\n \t\t\tds.fn = NULL;\n+\t\t\tignored_hint = 1;\n+\t\t}\n \n \t\tadvise(_(\"The candidates are:\"));\n \t\tfor_each_abbrev(ds.hex_pfx, collect_ambiguous, &collect);\n@@ -457,6 +460,12 @@ static int get_short_oid(const char *name, int len, struct object_id *oid,\n \t\tif (oid_array_for_each(&collect, show_ambiguous_object, &ds))\n \t\t\tBUG(\"show_ambiguous_object shouldn't return non-zero\");\n \t\toid_array_clear(&collect);\n+\n+\t\tif (ignored_hint) {\n+\t\t\twarning(_(\"Your hint (via core.disambiguate or peel syntax) was ignored, we fell\\n\"\n+\t\t\t\t  \"back to showing all object types since no object of the requested type\\n\"\n+\t\t\t\t  \"matched the provide short SHA1 %s\"), ds.hex_pfx);\n+\t\t}\n \t}\n \n \treturn status;\ndiff --git a/t/t1512-rev-parse-disambiguation.sh b/t/t1512-rev-parse-disambiguation.sh\nindex 2701462041..1f06c1e61f 100755\n--- a/t/t1512-rev-parse-disambiguation.sh\n+++ b/t/t1512-rev-parse-disambiguation.sh\n@@ -344,7 +344,10 @@ test_expect_success C_LOCALE_OUTPUT 'failed type-selector still shows hint' '\n \techo 872 | git hash-object --stdin -w &&\n \ttest_must_fail git rev-parse ee3d^{commit} 2>stderr &&\n \tgrep ^hint: stderr >hints &&\n-\ttest_line_count = 3 hints\n+\ttest_line_count = 3 hints &&\n+\tgrep ^warning stderr >warnings &&\n+\tgrep -q \"Your hint.*was ignored\" warnings &&\n+\tgrep -q \"the provide short SHA1 ee3d\" stderr\n '\n \n test_expect_success 'core.disambiguate config can prefer types' '\n-- \n2.17.0.410.g4ac3413cc8\n\n"},{"id":"347221","messageId":"CAN0heSoykVHTxD6s_QVUW_hMfTHG05yP-hVxnV6qsAO-eKJJ0A@mail.gmail.com","threadId":"48389","inReplyTo":"20180510124303.6020-7-avarab@gmail.com","subject":"Re: [PATCH v4 6/6] get_short_oid: document & warn if we ignore the type selector","fromName":"Martin Ågren","fromEmail":"martin.agren@gmail.com","sentAt":"2018-05-10T13:15:03Z","receivedAt":"2018-05-10T13:15:09Z","isPatch":true,"sender":{"key":"martin.agren@gmail.com","avatar":null},"body":"On 10 May 2018 at 14:43, Ævar Arnfjörð Bjarmason <avarab@gmail.com> wrote:\n> The SHA1 prefix 06fa currently matches no blobs in git.git. When\n> disambiguating short SHA1s we've been quietly ignoring the user's type\n> selector as a fallback mechanism, this was intentionally added in\n> 1ffa26c461 (\"get_short_sha1: list ambiguous objects on error\",\n> 2016-09-26).\n>\n> I think that behavior makes sense, it's not very useful to just show\n> nothing because a preference has been expressed via core.disambiguate,\n> but it's bad that we're quietly doing this. The user might thing that\n> we just didn't understand what e.g 06fa^{blob} meant.\n>\n> Now we'll instead print a warning if no objects of the requested type\n> were found:\n>\n>     $ git rev-parse 06fa^{blob}\n>     error: short SHA1 06fa is ambiguous\n>     hint: The candidates are:\n>     [... no blobs listed ...]\n>     warning: Your hint (via core.disambiguate or peel syntax) was ignored, we fell\n>     back to showing all object types since no object of the requested type\n>     matched the provide short SHA1 06fa\n\ns/ignored, we/ignored. We/? IMHO, it would read easier.\n\ns/provide short/provided short/\n\nAlso: s/SHA1/object id/? That said, you add the warning. The error\nmessage is already there and you are simply following its \"SHA1\".\n\nMartin\n"},{"id":"347247","messageId":"CAE5ih7-MKQoB27MKd0jJ91O+uKm8e2X5h8OcEaaGJAoYdWL5XQ@mail.gmail.com","threadId":"48389","inReplyTo":"20180510124303.6020-4-avarab@gmail.com","subject":"Re: [PATCH v4 3/6] git-p4: change \"commitish\" typo to \"committish\"","fromName":"Luke Diamand","fromEmail":"luke@diamand.org","sentAt":"2018-05-10T15:00:14Z","receivedAt":"2018-05-10T15:00:18Z","isPatch":true,"sender":{"key":"luke@diamand.org","avatar":"https://avatars.githubusercontent.com/u/5330967?v=4"},"body":"On 10 May 2018 at 13:43, Ævar Arnfjörð Bjarmason <avarab@gmail.com> wrote:\n> This was the only occurrence of \"commitish\" in the tree, but as the\n> log will reveal we've had others in the past. Fixes up code added in\n> 00ad6e3182 (\"git-p4: work with a detached head\", 2015-11-21).\n>\n> Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n\nLooks good to me!\n\nThanks,\nLuke\n\n\n> ---\n>  git-p4.py | 6 +++---\n>  1 file changed, 3 insertions(+), 3 deletions(-)\n>\n> diff --git a/git-p4.py b/git-p4.py\n> index 7bb9cadc69..1afa87cd9d 100755\n> --- a/git-p4.py\n> +++ b/git-p4.py\n> @@ -2099,11 +2099,11 @@ class P4Submit(Command, P4UserMap):\n>\n>          commits = []\n>          if self.master:\n> -            commitish = self.master\n> +            committish = self.master\n>          else:\n> -            commitish = 'HEAD'\n> +            committish = 'HEAD'\n>\n> -        for line in read_pipe_lines([\"git\", \"rev-list\", \"--no-merges\", \"%s..%s\" % (self.origin, commitish)]):\n> +        for line in read_pipe_lines([\"git\", \"rev-list\", \"--no-merges\", \"%s..%s\" % (self.origin, committish)]):\n>              commits.append(line.strip())\n>          commits.reverse()\n>\n> --\n> 2.17.0.410.g4ac3413cc8\n>\n"},{"id":"347248","messageId":"20180510150615.GA6462@sigill.intra.peff.net","threadId":"48389","inReplyTo":"20180510124303.6020-3-avarab@gmail.com","subject":"Re: [PATCH v4 2/6] sha1-array.h: align function arguments","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2018-05-10T15:06:15Z","receivedAt":"2018-05-10T15:06:27Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Thu, May 10, 2018 at 12:42:59PM +0000, Ævar Arnfjörð Bjarmason wrote:\n\n> The arguments weren't lined up with the opening parenthesis. Fixes up\n> code added in aae0caf19e (\"sha1-array.h: align function arguments\",\n> 2018-04-30).\n\nI think that's this patch. :)\n\nPresumably you meant 910650d2f8 (Rename sha1_array to oid_array,\n2017-03-31)?\n\n-Peff\n"},{"id":"347249","messageId":"20180510150939.25399-1-pclouds@gmail.com","threadId":"48389","inReplyTo":"20180508155627.19245-1-pclouds@gmail.com","subject":"[PATCH v2] pack-format.txt: more details on pack file format","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2018-05-10T15:09:39Z","receivedAt":"2018-05-10T15:09:48Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"The current document mentions OBJ_* constants without their actual\nvalues. A git developer would know these are from cache.h but that's\nnot very friendly to a person who wants to read this file to implement\na pack file parser.\n\nSimilarly, the deltified representation is not documented at all (the\n\"document\" is basically patch-delta.c). Translate that C code to\nEnglish with a bit more about what ofs-delta and ref-delta mean.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n This is a much better description than v1. I hope.\n\n Documentation/technical/pack-format.txt | 78 +++++++++++++++++++++++++\n cache.h                                 |  5 ++\n 2 files changed, 83 insertions(+)\n\ndiff --git a/Documentation/technical/pack-format.txt b/Documentation/technical/pack-format.txt\nindex 8e5bf60be3..d20bf592aa 100644\n--- a/Documentation/technical/pack-format.txt\n+++ b/Documentation/technical/pack-format.txt\n@@ -36,6 +36,84 @@ Git pack format\n \n   - The trailer records 20-byte SHA-1 checksum of all of the above.\n \n+=== Object types\n+\n+Valid object types are:\n+\n+- OBJ_COMMIT (1)\n+- OBJ_TREE (2)\n+- OBJ_BLOB (3)\n+- OBJ_TAG (4)\n+- OBJ_OFS_DELTA (6)\n+- OBJ_REF_DELTA (7)\n+\n+Type 5 is reserved for future expansion. Type 0 is invalid.\n+\n+=== Deltified representation\n+\n+Conceptually there are only four object types: commit, tree, tag and\n+blob. However to save space, an object could be stored as a \"delta\" of\n+another \"base\" object. These representations are assigned new types\n+ofs-delta and ref-delta, which is only valid in a pack file.\n+\n+Both ofs-delta and ref-delta store the \"delta\" against another\n+object. The difference between them is, ref-delta directly encodes\n+20-byte base object name. If the base object is in the same pack,\n+ofs-delta encodes the offset of the base object in the pack instead.\n+\n+The delta data is a sequence of instructions to reconstruct an object\n+from the base object. Each instruction appends more and more data to\n+the target object until it's complete. There are two supported\n+instructions so far: one for copy a byte range from the source object\n+and one for inserting new data embedded in the instruction itself.\n+\n+Each instruction has variable length. Instruction type is determined\n+by the seventh bit of the first octet. The following diagrams follow\n+the convention in RFC 1951 (Deflate compressed data format).\n+\n+  +----------+---------+---------+---------+---------+-------+-------+-------+\n+  | 1xxxxxxx | offset1 | offset2 | offset3 | offset4 | size1 | size2 | size3 |\n+  +----------+---------+---------+---------+---------+-------+-------+-------+\n+\n+This is the instruction format to copy a byte range from the source\n+object. It encodes the offset to copy from any the number of bytes to\n+copy. Offset and size are in little-endian order.\n+\n+All offset and size bytes are optional. This is to reduce the\n+instruction size when encoding small offsets or sizes. The first seven\n+bits in the first octet determines which of the next seven octets is\n+present. If bit zero is set, offset1 is present. If bit one is set\n+offset2 is present and so on.\n+\n+Note that a more compact instruction does not change offset and size\n+encoding. For example, if only offset2 is omitted like below, offset3\n+still contains bits 16-23. It does not become offset2 and contains\n+bits 8-15 even if it's right next to offset1.\n+\n+  +----------+---------+---------+\n+  | 10000101 | offset1 | offset3 |\n+  +----------+---------+---------+\n+\n+In its most compact form, this instruction only takes up one byte\n+(0x80) with both offset and size omitted, which will have default\n+values zero. There is another exception: size zero is automatically\n+converted to 0x10000.\n+\n+  +----------+============+\n+  | 0xxxxxxx |    data    |\n+  +----------+============+\n+\n+This is the instruction to construct target object without the base\n+object. The following data is appended to the target object. The first\n+seven bits of the first octet determines the size of data in\n+bytes. The size must be non-zero.\n+\n+  +----------+============\n+  | 00000000 |\n+  +----------+============\n+\n+This is the instruction reserved for future expansion.\n+\n == Original (version 1) pack-*.idx files have the following format:\n \n   - The header consists of 256 4-byte network byte order\ndiff --git a/cache.h b/cache.h\nindex 77b7acebb6..ad549e258e 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -373,6 +373,11 @@ extern void free_name_hash(struct index_state *istate);\n #define read_blob_data_from_cache(path, sz) read_blob_data_from_index(&the_index, (path), (sz))\n #endif\n \n+/*\n+ * Values in this enum (except those outside the 3 bit range) are part\n+ * of pack file format. See Documentation/technical/pack-format.txt\n+ * for more information.\n+ */\n enum object_type {\n \tOBJ_BAD = -1,\n \tOBJ_NONE = 0,\n-- \n2.17.0.705.g3525833791\n\n"},{"id":"347250","messageId":"20180510152221.GB6462@sigill.intra.peff.net","threadId":"48389","inReplyTo":"20180510124303.6020-6-avarab@gmail.com","subject":"Re: [PATCH v4 5/6] get_short_oid: sort ambiguous objects by type, then SHA-1","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2018-05-10T15:22:21Z","receivedAt":"2018-05-10T15:22:27Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Thu, May 10, 2018 at 12:43:02PM +0000, Ævar Arnfjörð Bjarmason wrote:\n\n> Now we'll instead show:\n> \n>     hint:   e8f2650052 tag v2.17.0\n>     hint:   e8f21caf94 commit 2013-06-24 - bash prompt: print unique detached HEAD abbreviated object name\n>     hint:   e8f26250fa commit 2017-02-03 - Merge pull request #996 from jeffhostetler/jeffhostetler/register_rename_src\n>     hint:   e8f2bc0c06 commit 2015-05-10 - Documentation: note behavior for multiple remote.url entries\n>     hint:   e8f2093055 tree\n>     hint:   e8f25a3a50 tree\n>     hint:   e8f28d537c tree\n>     hint:   e8f2cf6ec0 tree\n>     hint:   e8f21d02f7 blob\n>     hint:   e8f21d577c blob\n>     hint:   e8f2867228 blob\n>     hint:   e8f2a35526 blob\n\nI said already that I like the output, but this time I'll actually read\nthe code. ;)\n\nIt all looks good to me, with the exception of a few documentation nits\nI'll mention below.\n\n> A note on the implementation: Derrick rightly pointed out[1] that\n> we're bending over backwards here in get_short_oid() to first\n> de-duplicate the list, and then emit it, but could simply do it in one\n> step.\n> \n> The reason for that is that oid_array_for_each_unique() doesn't\n> actually require that the array be sorted by oid_array_sort(), it just\n> needs to be sorted in some order that guarantees that all objects with\n> the same ID are adjacent to one another, which (barring a hash\n> collision, which'll be someone else's problem) the sort_ambiguous()\n> function does.\n\nIf we were to go this route, I think it would make sense to add a\nsorting function pointer to \"struct oid_array\". I'm OK with punting on\nit for now, though.\n\n> diff --git a/Documentation/technical/api-oid-array.txt b/Documentation/technical/api-oid-array.txt\n> index b0c11f868d..94b529722c 100644\n> --- a/Documentation/technical/api-oid-array.txt\n> +++ b/Documentation/technical/api-oid-array.txt\n> @@ -35,13 +35,18 @@ Functions\n>  \tFree all memory associated with the array and return it to the\n>  \tinitial, empty state.\n>  \n> +`oid_array_for_each`::\n> +\tIterate over each element of the list, executing the callback\n> +\tfunction for each one. Does not sort the list, so any custom\n> +\thash order is retained. If the callback returns a non-zero\n> +\tvalue, the iteration ends immediately and the callback's\n> +\treturn is propagated; otherwise, 0 is returned.\n> +\n>  `oid_array_for_each_unique`::\n> -\tEfficiently iterate over each unique element of the list,\n> -\texecuting the callback function for each one. If the array is\n> -\tnot sorted, this function has the side effect of sorting it. If\n> -\tthe callback returns a non-zero value, the iteration ends\n> -\timmediately and the callback's return is propagated; otherwise,\n> -\t0 is returned.\n> +\tIterate over each unique element of the list in sort order ,\n> +\tbut otherwise behaves like `oid_array_for_each`. If the array\n> +\tis not sorted, this function has the side effect of sorting\n> +\tit.\n\nExtra space in \"sort order ,\".\n\nI'd probably say \"sorted order\", but that might be a matter of\npreference.\n\nAlso, your parallel verb tenses don't agree. ;) It should be \"Iterate\n... but otherwise behave\", not \"behaves\".\n\n> +\t/*\n> +\t * Between object types show tags, then commits, and finally\n> +\t * trees and blobs.\n> +\t *\n> +\t * The object_type enum is commit, tree, blob, tag, but we\n> +\t * want tag, commit, tree blob. Cleverly (perhaps too\n> +\t * cleverly) do that with modulus, since the enum assigns 1 to\n> +\t * commit, so tag becomes 0.\n> +\t */\n> +\ta_type_sort = a_type % 4;\n> +\tb_type_sort = b_type % 4;\n> +\treturn a_type_sort > b_type_sort ? 1 : -1;\n\nThis is amusingly clever, and should be very efficient. I'm glad there's\na comment at least, though.\n\n-Peff\n"},{"id":"347252","messageId":"20180510160322.GC6462@sigill.intra.peff.net","threadId":"48389","inReplyTo":"20180510124303.6020-7-avarab@gmail.com","subject":"Re: [PATCH v4 6/6] get_short_oid: document & warn if we ignore the type selector","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2018-05-10T16:03:22Z","receivedAt":"2018-05-10T16:03:36Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Thu, May 10, 2018 at 12:43:03PM +0000, Ævar Arnfjörð Bjarmason wrote:\n\n> The SHA1 prefix 06fa currently matches no blobs in git.git. When\n> disambiguating short SHA1s we've been quietly ignoring the user's type\n> selector as a fallback mechanism, this was intentionally added in\n> 1ffa26c461 (\"get_short_sha1: list ambiguous objects on error\",\n> 2016-09-26).\n> \n> I think that behavior makes sense, it's not very useful to just show\n> nothing because a preference has been expressed via core.disambiguate,\n> but it's bad that we're quietly doing this. The user might thing that\n> we just didn't understand what e.g 06fa^{blob} meant.\n\nI had to read this through a few times to figure out what problem you\nwere solving. Possibly because you lead with 06fa, which is really just\nan example (and also, I have an 06fa blob in my clone ;) ).\n\nMaybe:\n\n  If the short-sha1 disambiguation code is told to use a particular hint\n  (e.g., treeish or blob) but no objects with that short-sha1 match that\n  hint, we end up ignoring the hint. This can result in either:\n\n    1. We choose the non-matching object if there is only one. This will\n       typically result in an error later up the stack (since whatever\n       gave us the hint is expecting a particular type).\n\n    2. We list all objects with that short-sha1, including those with\n       non-matching types.\n\n  This second case can be confusing to the user, who might think that we\n  didn't apply the hint properly (especially if the hint came from\n  them). For example, in git.git there is no blob with the prefix 06fa.\n  So the user may see:\n\n    $ git rev-parse 06fa^{blob}\n    hint: The candidates are:\n    hint:   06fa2b7c2b tag v2.1.4\n    hint:   06faf6ba64 tree\n    06fa^{blob}\n    fatal: ambiguous argument '06fa^{blob}': unknown revision or path not in the working tree.\n\n  Let's help them out by issuing a warning whenever the hint is ignored.\n\nSo that at least explains it in a way that makes sense to me. But now\nthat I've propped up my strawman, let me take a few swings...\n\nYour patch just covers case 2, I think. And for the error case, that's\nprobably OK:\n\n  $ git rev-parse 06faf^{blob}\n  error: 06faf^{blob}: expected blob type, but the object dereferences to tree type\n  06faf^{blob}\n  error: 06faf^{blob}: expected blob type, but the object dereferences to tree type\n  fatal: ambiguous argument '06faf^{blob}': unknown revision or path not in the working tree.\n\n(though there is a separate bug in showing the error twice).\n\nBut some cases _don't_ issue an error. For example, try this:\n\n  $ git log ..06faf\n\nwhich returns an empty output! We return the single matching tree, even\nthough the \"..\" triggers the commit hint. The revision machinery just\nqueues the tree, and then later when we see we're not doing an --objects\ntraversal, it just gets ignored. (That's a separate issue, but it shows\nthat the hints are just that: hints. The code that runs after does not\nnecessarily require a matching type).\n\nAnd that example shows another issue, which is that the user does not\nnecessarily feed us the hint explicitly. We're using a committish hint\nthere, but I'm not sure if mentioning that would confuse the user or\nnot. Certainly this warning:\n\n>     warning: Your hint (via core.disambiguate or peel syntax) was ignored, we fell\n>     back to showing all object types since no object of the requested type\n>     matched the provide short SHA1 06fa\n\nis not accurate, because the hint came from neither of those places. ;)\n\nSo all that said together, I kind of wonder if we should consider\nissuing the warning earlier, doing so for all cases, and being a bit\nless chatty. Like:\n\n  $ git rev-parse 06fa^{blob}\n  warning: short object id 06fa did not match any objects of type 'blob'\n\nIf that were followed by any of:\n\n  1. error: short SHA1 06fa is ambiguous, then a bunch of non-blobs\n\n  2. error: expected blob but I got a tree\n\n  3. the command proceeds and silently ignores the matched object\n\nI think it would be helpful. We'd need to add in an extra mapping of\nGET_OID_* back to a human-readable string, but I think that should be\npretty easy.\n\nAnd finally, your 06fa example for me shows behavior that's either\nbuggy, or I'm just confused. I get:\n\n  $ git rev-parse 06fa^{blob}\n  error: short SHA1 06fa is ambiguous\n  hint: The candidates are:\n  hint:   06fa2b7c2b tag v2.1.4\n  hint:   06faa52353 commit 2005-10-18 - 2005-10-18 midnight\n  hint:   06fac427af blob\n  hint:   06faf6ba64 tree\n\n(That 06fac blob comes Junio's refs/notes/amlog). Shouldn't the blob\ndisambiguator show me just that object?\n\n-Peff\n"},{"id":"347253","messageId":"20180510160407.GD6462@sigill.intra.peff.net","threadId":"48389","inReplyTo":"20180510124303.6020-1-avarab@gmail.com","subject":"Re: [PATCH v4 0/6] get_short_oid UI improvements","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2018-05-10T16:04:07Z","receivedAt":"2018-05-10T16:04:25Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Thu, May 10, 2018 at 12:42:57PM +0000, Ævar Arnfjörð Bjarmason wrote:\n\n> This is like v3 except all the patches to the peel syntax & docs have\n> been dropped, which were controversial.\n> \n> I think it's worthwhile to re-work that, but I don't have time for\n> that now, so I'm submitting this. Maybe I'll have time in the future\n> to re-work the rest, but then I can base it on top of this.\n\nI'm not quite on-board with the final patch, but with the exception of a\nfew nits I sent already, the first 5 look good to me.\n\n-Peff\n"},{"id":"347254","messageId":"20180510160959.GA10199@sigill.intra.peff.net","threadId":"48389","inReplyTo":"20180510160322.GC6462@sigill.intra.peff.net","subject":"Re: [PATCH v4 6/6] get_short_oid: document & warn if we ignore the type selector","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2018-05-10T16:10:00Z","receivedAt":"2018-05-10T16:10:05Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Thu, May 10, 2018 at 12:03:22PM -0400, Jeff King wrote:\n\n> But some cases _don't_ issue an error. For example, try this:\n> \n>   $ git log ..06faf\n> \n> which returns an empty output! We return the single matching tree, even\n> though the \"..\" triggers the commit hint. The revision machinery just\n> queues the tree, and then later when we see we're not doing an --objects\n> traversal, it just gets ignored. (That's a separate issue, but it shows\n> that the hints are just that: hints. The code that runs after does not\n> necessarily require a matching type).\n\nI actually have a patch that generates a warning for this case (below).\nI've been running with it for about a year, but it annoyingly produces\nwarnings for \"git log --all\":\n\n  $ git log --all\n  warning: ignoring blob object in traversal: refs/tags/junio-gpg-pub\n\nI guess ideally it would distinguish between items added explicitly and\nthose added by a wildcard (or perhaps the wildcard adder should be more\ncareful about adding useless objects).\n\n---\ndiff --git a/revision.c b/revision.c\nindex 1cff11833e..816d6b75ee 100644\n--- a/revision.c\n+++ b/revision.c\n@@ -215,6 +215,16 @@ void add_pending_oid(struct rev_info *revs, const char *name,\n \tadd_pending_object(revs, object, name);\n }\n \n+static void warn_ignored_object(struct object *object, const char *name)\n+{\n+\tif (object->flags & UNINTERESTING)\n+\t\treturn;\n+\n+\twarning(_(\"ignoring %s object in traversal: %s\"),\n+\t\ttype_name(object->type),\n+\t\t(name && *name) ? name : oid_to_hex(&object->oid));\n+}\n+\n static struct commit *handle_commit(struct rev_info *revs,\n \t\t\t\t    struct object_array_entry *entry)\n {\n@@ -272,8 +282,10 @@ static struct commit *handle_commit(struct rev_info *revs,\n \t */\n \tif (object->type == OBJ_TREE) {\n \t\tstruct tree *tree = (struct tree *)object;\n-\t\tif (!revs->tree_objects)\n+\t\tif (!revs->tree_objects) {\n+\t\t\twarn_ignored_object(object, name);\n \t\t\treturn NULL;\n+\t\t}\n \t\tif (flags & UNINTERESTING) {\n \t\t\tmark_tree_contents_uninteresting(tree);\n \t\t\treturn NULL;\n@@ -286,8 +298,10 @@ static struct commit *handle_commit(struct rev_info *revs,\n \t * Blob object? You know the drill by now..\n \t */\n \tif (object->type == OBJ_BLOB) {\n-\t\tif (!revs->blob_objects)\n+\t\tif (!revs->blob_objects) {\n+\t\t\twarn_ignored_object(object, name);\n \t\t\treturn NULL;\n+\t\t}\n \t\tif (flags & UNINTERESTING)\n \t\t\treturn NULL;\n \t\tadd_pending_object_with_path(revs, object, name, mode, path);\n"},{"id":"347255","messageId":"20180510161532.GB10199@sigill.intra.peff.net","threadId":"48389","inReplyTo":"20180510160322.GC6462@sigill.intra.peff.net","subject":"Re: [PATCH v4 6/6] get_short_oid: document & warn if we ignore the type selector","fromName":"Jeff King","fromEmail":"peff@peff.net","sentAt":"2018-05-10T16:15:33Z","receivedAt":"2018-05-10T16:15:41Z","isPatch":true,"sender":{"key":"peff@peff.net","avatar":"https://avatars.githubusercontent.com/u/45925?v=4"},"body":"On Thu, May 10, 2018 at 12:03:22PM -0400, Jeff King wrote:\n\n> And finally, your 06fa example for me shows behavior that's either\n> buggy, or I'm just confused. I get:\n> \n>   $ git rev-parse 06fa^{blob}\n>   error: short SHA1 06fa is ambiguous\n>   hint: The candidates are:\n>   hint:   06fa2b7c2b tag v2.1.4\n>   hint:   06faa52353 commit 2005-10-18 - 2005-10-18 midnight\n>   hint:   06fac427af blob\n>   hint:   06faf6ba64 tree\n> \n> (That 06fac blob comes Junio's refs/notes/amlog). Shouldn't the blob\n> disambiguator show me just that object?\n\nAh, I see. No, \"^{blob}\" does not actually pass the blob disambiguator.\nWe only handle committish and treeish right now, and this iteration of\nthe series omits the function to fix that.\n\nSo I think the principle of this commit is sound without that patch, but\nyour example is not a good one anymore. :)\n\n-Peff\n"},{"id":"347258","messageId":"CAGZ79kYYFBE+39aeHX22w3ARmujFcgE8YDUQpp6Hps264r0wfQ@mail.gmail.com","threadId":"48389","inReplyTo":"20180510150939.25399-1-pclouds@gmail.com","subject":"Re: [PATCH v2] pack-format.txt: more details on pack file format","fromName":"Stefan Beller","fromEmail":"sbeller@google.com","sentAt":"2018-05-10T17:06:37Z","receivedAt":"2018-05-10T17:06:42Z","isPatch":true,"sender":{"key":"stefanbeller@gmail.com","avatar":"https://avatars.githubusercontent.com/u/455868?v=4"},"body":"On Thu, May 10, 2018 at 8:09 AM, Nguyễn Thái Ngọc Duy <pclouds@gmail.com> wrote:\n> The current document mentions OBJ_* constants without their actual\n> values. A git developer would know these are from cache.h but that's\n> not very friendly to a person who wants to read this file to implement\n> a pack file parser.\n>\n> Similarly, the deltified representation is not documented at all (the\n> \"document\" is basically patch-delta.c). Translate that C code to\n> English with a bit more about what ofs-delta and ref-delta mean.\n>\n> Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n> ---\n>  This is a much better description than v1. I hope.\n>\n>  Documentation/technical/pack-format.txt | 78 +++++++++++++++++++++++++\n>  cache.h                                 |  5 ++\n>  2 files changed, 83 insertions(+)\n>\n> diff --git a/Documentation/technical/pack-format.txt b/Documentation/technical/pack-format.txt\n> index 8e5bf60be3..d20bf592aa 100644\n> --- a/Documentation/technical/pack-format.txt\n> +++ b/Documentation/technical/pack-format.txt\n> @@ -36,6 +36,84 @@ Git pack format\n>\n>    - The trailer records 20-byte SHA-1 checksum of all of the above.\n>\n> +=== Object types\n> +\n> +Valid object types are:\n> +\n> +- OBJ_COMMIT (1)\n> +- OBJ_TREE (2)\n> +- OBJ_BLOB (3)\n> +- OBJ_TAG (4)\n> +- OBJ_OFS_DELTA (6)\n> +- OBJ_REF_DELTA (7)\n> +\n> +Type 5 is reserved for future expansion. Type 0 is invalid.\n> +\n> +=== Deltified representation\n> +\n> +Conceptually there are only four object types: commit, tree, tag and\n> +blob. However to save space, an object could be stored as a \"delta\" of\n> +another \"base\" object. These representations are assigned new types\n> +ofs-delta and ref-delta, which is only valid in a pack file.\n\n...only valid...\n\nas opposed to loose objects or as opposed to referencing cross-packs?\nI would think the former, not the latter.\n\n> +Both ofs-delta and ref-delta store the \"delta\" against another\n> +object. The difference between them is, ref-delta directly encodes\n> +20-byte base object name. If the base object is in the same pack,\n> +ofs-delta encodes the offset of the base object in the pack instead.\n\nReading this paragraph clears up the question from before.\nThe ref delta is a delta to another \"reference by hash id (sha1)\".\nWhat abbreviation is OFS? OFfSet ?\n\n> +The delta data is a sequence of instructions to reconstruct an object\n> +from the base object.\n\nAs said before the base object is of type 1..4, we do not \"delta-on-delta\"\nyet, but to construct the object we have to create the base object first,\nwhich itself can be represented as a deltified object leading to a delta\nchain.\n\n>     Each instruction appends more and more data to\n> +the target object until it's complete. There are two supported\n> +instructions so far: one for copy a byte range from the source object\n> +and one for inserting new data embedded in the instruction itself.\n\nok. So there are 2 types of instructions, \"copy from (offset, size)\" and\n\"new data follows\".\n\nThe next paragraphs seem to describe the copy instruction, maybe\nadd a sub-headline here?\n\n> +Each instruction has variable length. Instruction type is determined\n> +by the seventh bit of the first octet. The following diagrams follow\n> +the convention in RFC 1951 (Deflate compressed data format).\n> +\n> +  +----------+---------+---------+---------+---------+-------+-------+-------+\n> +  | 1xxxxxxx | offset1 | offset2 | offset3 | offset4 | size1 | size2 | size3 |\n> +  +----------+---------+---------+---------+---------+-------+-------+-------+\n> +\n> +This is the instruction format to copy a byte range from the source\n> +object. It encodes the offset to copy from any the number of bytes to\n> +copy. Offset and size are in little-endian order.\n> +\n> +All offset and size bytes are optional. This is to reduce the\n> +instruction size when encoding small offsets or sizes. The first seven\n> +bits in the first octet determines which of the next seven octets is\n> +present. If bit zero is set, offset1 is present. If bit one is set\n> +offset2 is present and so on.\n> +\n> +Note that a more compact instruction does not change offset and size\n> +encoding. For example, if only offset2 is omitted like below, offset3\n> +still contains bits 16-23. It does not become offset2 and contains\n> +bits 8-15 even if it's right next to offset1.\n> +\n> +  +----------+---------+---------+\n> +  | 10000101 | offset1 | offset3 |\n> +  +----------+---------+---------+\n\nIt reads very fluently to here.\n\n> +In its most compact form, this instruction only takes up one byte\n> +(0x80) with both offset and size omitted, which will have default\n> +values zero. There is another exception: size zero is automatically\n> +converted to 0x10000.\n\nThis \"another exception\" sounds a bit tacked on, but is still understandable.\nI would imagine that the size of 0 is used frequently to copy large blocks\nand coincidentally it is represented using the lowest number of bytes\nfor size. Cute!\n\nBefore the next diagram we could have a sub-headline, indicating\nthat the other instruction \"new data follows\" will now be described.\n\n> +  +----------+============+\n> +  | 0xxxxxxx |    data    |\n> +  +----------+============+\n> +\n> +This is the instruction to construct target object without the base\n> +object. The following data is appended to the target object. The first\n> +seven bits of the first octet determines the size of data in\n> +bytes. The size must be non-zero.\n\nThis command sounds very easy.\nHowever we can have at most 127 bytes of new data, so if someone\nadds a larger part of new code, we'd have many \"insert new data\"\ninstructions, all at the max of 127, such that the overhead for instruction\nbytes is 1/127 = 0.7 %. Sounds efficient.\n\n> +  +----------+============\n> +  | 00000000 |\n> +  +----------+============\n> +\n> +This is the instruction reserved for future expansion.\n\nThanks for pointing this out.\n\n\n>\n> +/*\n> + * Values in this enum (except those outside the 3 bit range) are part\n> + * of pack file format. See Documentation/technical/pack-format.txt\n> + * for more information.\n> + */\n\nMakes sense.\n\nI really like this patch very much. Thanks for writing it.\nMy annotations are just to add the cherry onto the cake,\nthe current form is\nReviewed-by: Stefan Beller <sbeller@google.com>\n\nThanks!\n"},{"id":"347328","messageId":"xmqqvabuhouc.fsf@gitster-ct.c.googlers.com","threadId":"48389","inReplyTo":"20180510150615.GA6462@sigill.intra.peff.net","subject":"Re: [PATCH v4 2/6] sha1-array.h: align function arguments","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2018-05-11T03:07:39Z","receivedAt":"2018-05-11T03:07:45Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Jeff King <peff@peff.net> writes:\n\n> On Thu, May 10, 2018 at 12:42:59PM +0000, Ævar Arnfjörð Bjarmason wrote:\n>\n>> The arguments weren't lined up with the opening parenthesis. Fixes up\n>> code added in aae0caf19e (\"sha1-array.h: align function arguments\",\n>> 2018-04-30).\n>\n> I think that's this patch. :)\n>\n> Presumably you meant 910650d2f8 (Rename sha1_array to oid_array,\n> 2017-03-31)?\n\nSharp eyes.  I couldn't quite tell from a cursory read of the blame\noutput, until I realized that the original before that culprit were\naligned and the renaming was what made them out of alignment.\n\nBut then \"fixes up code added in\" is not quite right, either.  It is\nwhat the commit should have touched but didn't ;-)\n\nThanks.\n"},{"id":"347329","messageId":"xmqqr2mihors.fsf@gitster-ct.c.googlers.com","threadId":"48389","inReplyTo":"xmqqvabuhouc.fsf@gitster-ct.c.googlers.com","subject":"Re: [PATCH v4 2/6] sha1-array.h: align function arguments","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2018-05-11T03:09:11Z","receivedAt":"2018-05-11T03:09:17Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Junio C Hamano <gitster@pobox.com> writes:\n\n> Jeff King <peff@peff.net> writes:\n>\n>> On Thu, May 10, 2018 at 12:42:59PM +0000, Ævar Arnfjörð Bjarmason wrote:\n>>\n>>> The arguments weren't lined up with the opening parenthesis. Fixes up\n>>> code added in aae0caf19e (\"sha1-array.h: align function arguments\",\n>>> 2018-04-30).\n> ...\n> But then \"fixes up code added in\" is not quite right, either.  It is\n> what the commit should have touched but didn't ;-)\n\nFWIW, I ended up with this description.\n\n    The arguments weren't lined up with the opening parenthesis, after\n    910650d2 (\"Rename sha1_array to oid_array\", 2017-03-31) renamed the\n    function.\n    \n"},{"id":"347332","messageId":"xmqqefiihmot.fsf@gitster-ct.c.googlers.com","threadId":"48389","inReplyTo":"20180510150939.25399-1-pclouds@gmail.com","subject":"Re: [PATCH v2] pack-format.txt: more details on pack file format","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2018-05-11T03:54:10Z","receivedAt":"2018-05-11T03:54:16Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Nguyễn Thái Ngọc Duy  <pclouds@gmail.com> writes:\n\n> +Both ofs-delta and ref-delta store the \"delta\" against another\n> +object. The difference between them is, ref-delta directly encodes\n> +20-byte base object name. If the base object is in the same pack,\n> +ofs-delta encodes the offset of the base object in the pack instead.\n\nThose of us who know how delta works would understand it, but \"delta\nagainst another object\" followed by a mention of \"base object\" may\nnot necessarily click to readers that \"another object\" and \"base\nobject\" refer to the same concept.\n\n\t... store the 'delta' to be applied to another object\n\t(called 'base object') to reconstruct the object.\n\nperhaps?\n\n> ...\n> +  +----------+---------+---------+---------+---------+-------+-------+-------+\n> +  | 1xxxxxxx | offset1 | offset2 | offset3 | offset4 | size1 | size2 | size3 |\n> +  +----------+---------+---------+---------+---------+-------+-------+-------+\n> +\n> +This is the instruction format to copy a byte range from the source\n> +object. It encodes the offset to copy from any the number of bytes to\n> +copy. Offset and size are in little-endian order.\n\n\"any the number\"???  Ah, s/any/and/ that is.\n\nOther than that, looks good to me.\n\nThanks.\n"},{"id":"347334","messageId":"xmqq36yyhhyp.fsf@gitster-ct.c.googlers.com","threadId":"48389","inReplyTo":"20180510124303.6020-6-avarab@gmail.com","subject":"Re: [PATCH v4 5/6] get_short_oid: sort ambiguous objects by type, then SHA-1","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2018-05-11T05:36:14Z","receivedAt":"2018-05-11T05:36:24Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Ævar Arnfjörð Bjarmason  <avarab@gmail.com> writes:\n\n> diff --git a/sha1-name.c b/sha1-name.c\n> index 9d7bbd3e96..46d8b1afa6 100644\n> --- a/sha1-name.c\n> +++ b/sha1-name.c\n> @@ -409,6 +437,8 @@ static int get_short_oid(const char *name, int len, struct object_id *oid,\n>  \tstatus = finish_object_disambiguation(&ds, oid);\n>  \n>  \tif (!quietly && (status == SHORT_NAME_AMBIGUOUS)) {\n> +\t\tstruct oid_array collect = OID_ARRAY_INIT;\n> +\n>  \t\terror(_(\"short SHA1 %s is ambiguous\"), ds.hex_pfx);\n>  \n>  \t\t/*\n> @@ -421,7 +451,12 @@ static int get_short_oid(const char *name, int len, struct object_id *oid,\n>  \t\t\tds.fn = NULL;\n>  \n>  \t\tadvise(_(\"The candidates are:\"));\n> -\t\tfor_each_abbrev(ds.hex_pfx, show_ambiguous_object, &ds);\n\nSo we used to let for_each_abbrev() to enumerate these object names\nthat share the prefix in the object name order and fed\nshow_ambiguous_object() to show them, which was the cause of the\noutput that is not grouped by type.  Now you collect them into\nanother oid_array and sort by type, relying on the fact to that the\nfor_each_abbrev() in the \"collect\" phase already does the de-duping.\n\nSounds good.\n\n> +\t\tfor_each_abbrev(ds.hex_pfx, collect_ambiguous, &collect);\n> +\t\tQSORT(collect.oid, collect.nr, sort_ambiguous);\n> +\n> +\t\tif (oid_array_for_each(&collect, show_ambiguous_object, &ds))\n> +\t\t\tBUG(\"show_ambiguous_object shouldn't return non-zero\");\n> +\t\toid_array_clear(&collect);\n>  \t}\n\n\n> diff --git a/t/t1512-rev-parse-disambiguation.sh b/t/t1512-rev-parse-disambiguation.sh\n> index 711704ba5a..2701462041 100755\n> --- a/t/t1512-rev-parse-disambiguation.sh\n> +++ b/t/t1512-rev-parse-disambiguation.sh\n> @@ -361,4 +361,25 @@ test_expect_success 'core.disambiguate does not override context' '\n>  \t\tgit -c core.disambiguate=committish rev-parse $sha1^{tree}\n>  '\n>  \n> +test_expect_success C_LOCALE_OUTPUT 'ambiguous commits are printed by type first, then hash order' '\n> +\ttest_must_fail git rev-parse 0000 2>stderr &&\n> +\tgrep ^hint: stderr >hints &&\n> +\tgrep 0000 hints >objects &&\n> +\tcat >expected <<-\\EOF &&\n> +\ttag\n> +\tcommit\n> +\ttree\n> +\tblob\n> +\tEOF\n> +\tawk \"{print \\$3}\" <objects >objects.types &&\n> +\tuniq <objects.types >objects.types.uniq &&\n\nEww, that is somewhat tricky (but correct) use of \"uniq\", which\nPOSIX not just mandates adjacent duplicates to be removed, but also\nforbids from removing duplicates that are not adjacent from each\nother.  So the objects in the \"hints\" file are not grouped by type,\nwe will fail to see these four lines.\n\n> +\ttest_cmp expected objects.types.uniq &&\n> +\tfor type in tag commit tree blob\n> +\tdo\n> +\t\tgrep $type objects >$type.objects &&\n> +\t\tsort $type.objects >$type.objects.sorted &&\n> +\t\ttest_cmp $type.objects.sorted $type.objects\n\nWe not only want to see objects grouped by type (and types shown in\na desired order), but within the same type we want them ordered by\nobject name.\n\nOK.\n\n> +\tdone\n> +'\n> +\n>  test_done\n"},{"id":"347339","messageId":"CACsJy8Btz_yYzdMds5SsJ+roSHj4RgiN4eCuPOh0+fod3e2mpw@mail.gmail.com","threadId":"48389","inReplyTo":"CAGZ79kYYFBE+39aeHX22w3ARmujFcgE8YDUQpp6Hps264r0wfQ@mail.gmail.com","subject":"Re: [PATCH v2] pack-format.txt: more details on pack file format","fromName":"Duy Nguyen","fromEmail":"pclouds@gmail.com","sentAt":"2018-05-11T06:41:08Z","receivedAt":"2018-05-11T06:41:42Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Thu, May 10, 2018 at 7:06 PM, Stefan Beller <sbeller@google.com> wrote:\n>> +=== Deltified representation\n>> +\n>> +Conceptually there are only four object types: commit, tree, tag and\n>> +blob. However to save space, an object could be stored as a \"delta\" of\n>> +another \"base\" object. These representations are assigned new types\n>> +ofs-delta and ref-delta, which is only valid in a pack file.\n>\n> ...only valid...\n>\n> as opposed to loose objects or as opposed to referencing cross-packs?\n> I would think the former, not the latter.\n\nYeah. This is pretty much an implementation detail of a pack. The\n\"real\" type is always blob/commit/tree/tag. But you only see this when\nyou dig deep down in pack-related code.\n\n>> +Both ofs-delta and ref-delta store the \"delta\" against another\n>> +object. The difference between them is, ref-delta directly encodes\n>> +20-byte base object name. If the base object is in the same pack,\n>> +ofs-delta encodes the offset of the base object in the pack instead.\n>\n> Reading this paragraph clears up the question from before.\n> The ref delta is a delta to another \"reference by hash id (sha1)\".\n> What abbreviation is OFS? OFfSet ?\n\nI guess so. I never bothered to track down the source for that.\n\n>> +The delta data is a sequence of instructions to reconstruct an object\n>> +from the base object.\n>\n> As said before the base object is of type 1..4, we do not \"delta-on-delta\"\n> yet, but to construct the object we have to create the base object first,\n> which itself can be represented as a deltified object leading to a delta\n> chain.\n\nYeah that's the delta chain concept. I'll just make a note here about\nbase object potentially being a delta object as well.\n-- \nDuy\n"},{"id":"347340","messageId":"20180511065523.7001-1-pclouds@gmail.com","threadId":"48389","inReplyTo":"20180510150939.25399-1-pclouds@gmail.com","subject":"[PATCH v3] pack-format.txt: more details on pack file format","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2018-05-11T06:55:23Z","receivedAt":"2018-05-11T06:55:43Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"The current document mentions OBJ_* constants without their actual\nvalues. A git developer would know these are from cache.h but that's\nnot very friendly to a person who wants to read this file to implement\na pack file parser.\n\nSimilarly, the deltified representation is not documented at all (the\n\"document\" is basically patch-delta.c). Translate that C code to\nEnglish with a bit more about what ofs-delta and ref-delta mean.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n Diff from v2\n\n    diff --git a/Documentation/technical/pack-format.txt b/Documentation/technical/pack-format.txt\n    index 00351cb822..70a99fd142 100644\n    --- a/Documentation/technical/pack-format.txt\n    +++ b/Documentation/technical/pack-format.txt\n    @@ -56,27 +56,37 @@ blob. However to save space, an object could be stored as a \"delta\" of\n     another \"base\" object. These representations are assigned new types\n     ofs-delta and ref-delta, which is only valid in a pack file.\n     \n    -Both ofs-delta and ref-delta store the \"delta\" against another\n    -object. The difference between them is, ref-delta directly encodes\n    -20-byte base object name. If the base object is in the same pack,\n    -ofs-delta encodes the offset of the base object in the pack instead.\n    +Both ofs-delta and ref-delta store the \"delta\" to be applied to\n    +another object (called 'base object') to reconstruct the object. The\n    +difference between them is, ref-delta directly encodes 20-byte base\n    +object name. If the base object is in the same pack, ofs-delta encodes\n    +the offset of the base object in the pack instead.\n    +\n    +The base object could also be deltified if it's in the same pack.\n    +Ref-delta can also refer to an object outside the pack (i.e. the\n    +so-called \"thin pack\"). When stored on disk however, the pack should\n    +be self contained to avoid cyclic dependency.\n     \n     The delta data is a sequence of instructions to reconstruct an object\n    -from the base object. Each instruction appends more and more data to\n    -the target object until it's complete. There are two supported\n    -instructions so far: one for copy a byte range from the source object\n    -and one for inserting new data embedded in the instruction itself.\n    +from the base object. If the base object is deltified, it must be\n    +converted to canonical form first. Each instruction appends more and\n    +more data to the target object until it's complete. There are two\n    +supported instructions so far: one for copy a byte range from the\n    +source object and one for inserting new data embedded in the\n    +instruction itself.\n     \n     Each instruction has variable length. Instruction type is determined\n     by the seventh bit of the first octet. The following diagrams follow\n     the convention in RFC 1951 (Deflate compressed data format).\n     \n    +==== Instruction to copy from base object\n    +\n       +----------+---------+---------+---------+---------+-------+-------+-------+\n       | 1xxxxxxx | offset1 | offset2 | offset3 | offset4 | size1 | size2 | size3 |\n       +----------+---------+---------+---------+---------+-------+-------+-------+\n     \n     This is the instruction format to copy a byte range from the source\n    -object. It encodes the offset to copy from any the number of bytes to\n    +object. It encodes the offset to copy from and the number of bytes to\n     copy. Offset and size are in little-endian order.\n     \n     All offset and size bytes are optional. This is to reduce the\n    @@ -99,6 +109,8 @@ In its most compact form, this instruction only takes up one byte\n     values zero. There is another exception: size zero is automatically\n     converted to 0x10000.\n     \n    +==== Instruction to add new data\n    +\n       +----------+============+\n       | 0xxxxxxx |    data    |\n       +----------+============+\n    @@ -108,6 +120,8 @@ object. The following data is appended to the target object. The first\n     seven bits of the first octet determines the size of data in\n     bytes. The size must be non-zero.\n     \n    +==== Reserved instruction\n    +\n       +----------+============\n       | 00000000 |\n       +----------+============\n\n Documentation/technical/pack-format.txt | 92 +++++++++++++++++++++++++\n cache.h                                 |  5 ++\n 2 files changed, 97 insertions(+)\n\ndiff --git a/Documentation/technical/pack-format.txt b/Documentation/technical/pack-format.txt\nindex 8e5bf60be3..70a99fd142 100644\n--- a/Documentation/technical/pack-format.txt\n+++ b/Documentation/technical/pack-format.txt\n@@ -36,6 +36,98 @@ Git pack format\n \n   - The trailer records 20-byte SHA-1 checksum of all of the above.\n \n+=== Object types\n+\n+Valid object types are:\n+\n+- OBJ_COMMIT (1)\n+- OBJ_TREE (2)\n+- OBJ_BLOB (3)\n+- OBJ_TAG (4)\n+- OBJ_OFS_DELTA (6)\n+- OBJ_REF_DELTA (7)\n+\n+Type 5 is reserved for future expansion. Type 0 is invalid.\n+\n+=== Deltified representation\n+\n+Conceptually there are only four object types: commit, tree, tag and\n+blob. However to save space, an object could be stored as a \"delta\" of\n+another \"base\" object. These representations are assigned new types\n+ofs-delta and ref-delta, which is only valid in a pack file.\n+\n+Both ofs-delta and ref-delta store the \"delta\" to be applied to\n+another object (called 'base object') to reconstruct the object. The\n+difference between them is, ref-delta directly encodes 20-byte base\n+object name. If the base object is in the same pack, ofs-delta encodes\n+the offset of the base object in the pack instead.\n+\n+The base object could also be deltified if it's in the same pack.\n+Ref-delta can also refer to an object outside the pack (i.e. the\n+so-called \"thin pack\"). When stored on disk however, the pack should\n+be self contained to avoid cyclic dependency.\n+\n+The delta data is a sequence of instructions to reconstruct an object\n+from the base object. If the base object is deltified, it must be\n+converted to canonical form first. Each instruction appends more and\n+more data to the target object until it's complete. There are two\n+supported instructions so far: one for copy a byte range from the\n+source object and one for inserting new data embedded in the\n+instruction itself.\n+\n+Each instruction has variable length. Instruction type is determined\n+by the seventh bit of the first octet. The following diagrams follow\n+the convention in RFC 1951 (Deflate compressed data format).\n+\n+==== Instruction to copy from base object\n+\n+  +----------+---------+---------+---------+---------+-------+-------+-------+\n+  | 1xxxxxxx | offset1 | offset2 | offset3 | offset4 | size1 | size2 | size3 |\n+  +----------+---------+---------+---------+---------+-------+-------+-------+\n+\n+This is the instruction format to copy a byte range from the source\n+object. It encodes the offset to copy from and the number of bytes to\n+copy. Offset and size are in little-endian order.\n+\n+All offset and size bytes are optional. This is to reduce the\n+instruction size when encoding small offsets or sizes. The first seven\n+bits in the first octet determines which of the next seven octets is\n+present. If bit zero is set, offset1 is present. If bit one is set\n+offset2 is present and so on.\n+\n+Note that a more compact instruction does not change offset and size\n+encoding. For example, if only offset2 is omitted like below, offset3\n+still contains bits 16-23. It does not become offset2 and contains\n+bits 8-15 even if it's right next to offset1.\n+\n+  +----------+---------+---------+\n+  | 10000101 | offset1 | offset3 |\n+  +----------+---------+---------+\n+\n+In its most compact form, this instruction only takes up one byte\n+(0x80) with both offset and size omitted, which will have default\n+values zero. There is another exception: size zero is automatically\n+converted to 0x10000.\n+\n+==== Instruction to add new data\n+\n+  +----------+============+\n+  | 0xxxxxxx |    data    |\n+  +----------+============+\n+\n+This is the instruction to construct target object without the base\n+object. The following data is appended to the target object. The first\n+seven bits of the first octet determines the size of data in\n+bytes. The size must be non-zero.\n+\n+==== Reserved instruction\n+\n+  +----------+============\n+  | 00000000 |\n+  +----------+============\n+\n+This is the instruction reserved for future expansion.\n+\n == Original (version 1) pack-*.idx files have the following format:\n \n   - The header consists of 256 4-byte network byte order\ndiff --git a/cache.h b/cache.h\nindex 77b7acebb6..ad549e258e 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -373,6 +373,11 @@ extern void free_name_hash(struct index_state *istate);\n #define read_blob_data_from_cache(path, sz) read_blob_data_from_index(&the_index, (path), (sz))\n #endif\n \n+/*\n+ * Values in this enum (except those outside the 3 bit range) are part\n+ * of pack file format. See Documentation/technical/pack-format.txt\n+ * for more information.\n+ */\n enum object_type {\n \tOBJ_BAD = -1,\n \tOBJ_NONE = 0,\n-- \n2.17.0.705.g3525833791\n\n"}]}