From: Ævar Arnfjörð Bjarmason <avarab@xxxxxxxxx> Here is what I mean by sorting during for_each_abbrev(). This seems to work for me, so I don't know what the issue is with this one-pass approach. Thanks, -Stolee -- >8 -- Change the output emitted when an ambiguous object is encountered so that we show tags first, then commits, followed by trees, and finally blobs. Within each type we show objects in hashcmp() order. Before this change the objects were only ordered by hashcmp(). The reason for doing this is that the output looks better as a result, e.g. the v2.17.0 tag before this change on "git show e8f2" would display: hint: The candidates are: hint: e8f2093055 tree hint: e8f21caf94 commit 2013-06-24 - bash prompt: print unique detached HEAD abbreviated object name hint: e8f21d02f7 blob hint: e8f21d577c blob hint: e8f25a3a50 tree hint: e8f26250fa commit 2017-02-03 - Merge pull request #996 from jeffhostetler/jeffhostetler/register_rename_src hint: e8f2650052 tag v2.17.0 hint: e8f2867228 blob hint: e8f28d537c tree hint: e8f2a35526 blob hint: e8f2bc0c06 commit 2015-05-10 - Documentation: note behavior for multiple remote.url entries hint: e8f2cf6ec0 tree Now we'll instead show: hint: e8f2650052 tag v2.17.0 hint: e8f21caf94 commit 2013-06-24 - bash prompt: print unique detached HEAD abbreviated object name hint: e8f26250fa commit 2017-02-03 - Merge pull request #996 from jeffhostetler/jeffhostetler/register_rename_src hint: e8f2bc0c06 commit 2015-05-10 - Documentation: note behavior for multiple remote.url entries hint: e8f2093055 tree hint: e8f25a3a50 tree hint: e8f28d537c tree hint: e8f2cf6ec0 tree hint: e8f21d02f7 blob hint: e8f21d577c blob hint: e8f2867228 blob hint: e8f2a35526 blob Since we show the commit data in the output that's nicely aligned once we sort by object type. The decision to show tags before commits is pretty arbitrary. I don't want to order by object_type since there tags come last after blobs, which doesn't make sense if we want to show the most important things first. I could display them after commits, but it's much less likely that we'll display a tag, so if there is one it makes sense to show it prominently at the top. Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@xxxxxxxxx> Signed-off-by: Derrick Stolee <dstolee@xxxxxxxxxxxxx> --- sha1-name.c | 31 +++++++++++++++++++++++++++++ t/t1512-rev-parse-disambiguation.sh | 21 +++++++++++++++++++ 2 files changed, 52 insertions(+) diff --git a/sha1-name.c b/sha1-name.c index 5deebab56d..0336630c64 100644 --- a/sha1-name.c +++ b/sha1-name.c @@ -385,6 +385,34 @@ static int collect_ambiguous(const struct object_id *oid, void *data) return 0; } +static int sort_ambiguous(const void *a, const void *b) +{ + int a_type = oid_object_info(a, NULL); + int b_type = oid_object_info(b, NULL); + int a_type_sort; + int b_type_sort; + + /* + * Sorts by hash within the same object type, just as + * oid_array_for_each_unique() would do. + */ + if (a_type == b_type) + return oidcmp(a, b); + + /* + * Between object types show tags, then commits, and finally + * trees and blobs. + * + * The object_type enum is commit, tree, blob, tag, but we + * want tag, commit, tree blob. Cleverly (perhaps too + * cleverly) do that with modulus, since the enum assigns 1 to + * commit, so tag becomes 0. + */ + a_type_sort = a_type % 4; + b_type_sort = b_type % 4; + return a_type_sort > b_type_sort ? 1 : -1; +} + static int get_short_oid(const char *name, int len, struct object_id *oid, unsigned flags) { @@ -451,6 +479,9 @@ int for_each_abbrev(const char *prefix, each_abbrev_fn fn, void *cb_data) find_short_object_filename(&ds); find_short_packed_object(&ds); + QSORT(collect.oid, collect.nr, sort_ambiguous); + collect.sorted = 1; + ret = oid_array_for_each_unique(&collect, fn, cb_data); oid_array_clear(&collect); return ret; diff --git a/t/t1512-rev-parse-disambiguation.sh b/t/t1512-rev-parse-disambiguation.sh index c7ceda2f21..74e7d9c178 100755 --- a/t/t1512-rev-parse-disambiguation.sh +++ b/t/t1512-rev-parse-disambiguation.sh @@ -364,4 +364,25 @@ test_expect_success 'core.disambiguate does not override context' ' git -c core.disambiguate=committish rev-parse $sha1^{tree} ' +test_expect_success C_LOCALE_OUTPUT 'ambiguous commits are printed by type first, then hash order' ' + test_must_fail git rev-parse 0000 2>stderr && + grep ^hint: stderr >hints && + grep 0000 hints >objects && + cat >expected <<-\EOF && + tag + commit + tree + blob + EOF + awk "{print \$3}" <objects >objects.types && + uniq <objects.types >objects.types.uniq && + test_cmp expected objects.types.uniq && + for type in tag commit tree blob + do + grep $type objects >$type.objects && + sort $type.objects >$type.objects.sorted && + test_cmp $type.objects.sorted $type.objects + done +' + test_done -- 2.17.0.39.g685157f7fb