diff --git a/sha1_name.c b/sha1_name.c index f7e388490a..0513f148f1 100644 --- a/sha1_name.c +++ b/sha1_name.c @@ -318,6 +318,38 @@ static int init_object_disambiguation(const char *name, int len, return 0; } +static int show_ambiguous_object(const unsigned char *sha1, void *data) +{ + const struct disambiguate_state *ds = data; + struct strbuf desc = STRBUF_INIT; + int type; + + if (ds->fn && !ds->fn(sha1, ds->cb_data)) + return 0; + + type = sha1_object_info(sha1, NULL); + if (type == OBJ_COMMIT) { + struct commit *commit = lookup_commit(sha1); + if (commit) { + struct pretty_print_context pp = {0}; + pp.date_mode.type = DATE_SHORT; + format_commit_message(commit, " %ad - %s", &desc, &pp); + } + } else if (type == OBJ_TAG) { + struct tag *tag = lookup_tag(sha1); + if (!parse_tag(tag) && tag->tag) + strbuf_addf(&desc, " %s", tag->tag); + } + + advise(" %s %s%s", + find_unique_abbrev(sha1, DEFAULT_ABBREV), + typename(type) ? typename(type) : "unknown type", + desc.buf); + + strbuf_release(&desc); + return 0; +} + static int get_short_sha1(const char *name, int len, unsigned char *sha1, unsigned flags) { @@ -346,8 +378,22 @@ static int get_short_sha1(const char *name, int len, unsigned char *sha1, find_short_packed_object(&ds); status = finish_object_disambiguation(&ds, sha1); - if (!quietly && (status == SHORT_NAME_AMBIGUOUS)) - return error(_("short SHA1 %s is ambiguous"), ds.hex_pfx); + if (!quietly && (status == SHORT_NAME_AMBIGUOUS)) { + error(_("short SHA1 %s is ambiguous"), ds.hex_pfx); + + /* + * We may still have ambiguity if we simply saw a series of + * candidates that did not satisfy our hint function. In + * that case, we still want to show them, so disable the hint + * function entirely. + */ + if (!ds.ambiguous) + ds.fn = NULL; + + advise(_("The candidates are:")); + for_each_abbrev(ds.hex_pfx, show_ambiguous_object, &ds); + } + return status; } diff --git a/t/t1512-rev-parse-disambiguation.sh b/t/t1512-rev-parse-disambiguation.sh index 1d8f550996..c5447ef877 100755 --- a/t/t1512-rev-parse-disambiguation.sh +++ b/t/t1512-rev-parse-disambiguation.sh @@ -323,4 +323,28 @@ test_expect_success C_LOCALE_OUTPUT 'ambiguity errors are not repeated (peel)' ' test_line_count = 1 errors ' +test_expect_success C_LOCALE_OUTPUT 'ambiguity hints' ' + test_must_fail git rev-parse 000000000 2>stderr && + grep ^hint: stderr >hints && + # 16 candidates, plus one intro line + test_line_count = 17 hints +' + +test_expect_success C_LOCALE_OUTPUT 'ambiguity hints respect type' ' + test_must_fail git rev-parse 000000000^{commit} 2>stderr && + grep ^hint: stderr >hints && + # 5 commits, 1 tag (which is a commitish), plus intro line + test_line_count = 7 hints +' + +test_expect_success C_LOCALE_OUTPUT 'failed type-selector still shows hint' ' + # these two blobs share the same prefix "ee3d", but neither + # will pass for a commit + echo 851 | git hash-object --stdin -w && + echo 872 | git hash-object --stdin -w && + test_must_fail git rev-parse ee3d^{commit} 2>stderr && + grep ^hint: stderr >hints && + test_line_count = 3 hints +' + test_done