get_sha1: propagate flags to child functions

The get_sha1() function is actually implementation by many
sub-functions, but we do not always pass our flags around to
all of those functions. As a result, we may forget that our
caller asked us to resolve with GET_SHA1_QUIETLY and output
messages. The two triggerable cases are:

  1. Resolving treeish:path will resolve the "treeish"
     portion using GET_SHA1_TREEISH, dropping all other
     flags.

  2. The peel_onion() function did not take flags at all
     but recurses to get_sha1_1(), which does.

The solution for both is to bitwise-OR their new flags with
the existing ones (after dropping any mutually exclusive
disambiguation flags).

This bug can trigger with "git rev-parse --quiet", which
asks for quiet resolution. But it can also happen in a more
vanilla code path when we do a follow-up ONLY_TO_DIE
invocation of get_sha1(), and that's what the tests check.

Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
Jeff King
2016-09-26 07:59:41 -04:00
committed by Junio C Hamano
parent 7243ffdd78
commit 8a10fea49b
2 changed files with 25 additions and 7 deletions

View File

@ -681,12 +681,12 @@ struct object *peel_to_type(const char *name, int namelen,
} }
} }
static int peel_onion(const char *name, int len, unsigned char *sha1) static int peel_onion(const char *name, int len, unsigned char *sha1,
unsigned lookup_flags)
{ {
unsigned char outer[20]; unsigned char outer[20];
const char *sp; const char *sp;
unsigned int expected_type = 0; unsigned int expected_type = 0;
unsigned lookup_flags = 0;
struct object *o; struct object *o;
/* /*
@ -726,10 +726,11 @@ static int peel_onion(const char *name, int len, unsigned char *sha1)
else else
return -1; return -1;
lookup_flags &= ~GET_SHA1_DISAMBIGUATORS;
if (expected_type == OBJ_COMMIT) if (expected_type == OBJ_COMMIT)
lookup_flags = GET_SHA1_COMMITTISH; lookup_flags |= GET_SHA1_COMMITTISH;
else if (expected_type == OBJ_TREE) else if (expected_type == OBJ_TREE)
lookup_flags = GET_SHA1_TREEISH; lookup_flags |= GET_SHA1_TREEISH;
if (get_sha1_1(name, sp - name - 2, outer, lookup_flags)) if (get_sha1_1(name, sp - name - 2, outer, lookup_flags))
return -1; return -1;
@ -830,7 +831,7 @@ static int get_sha1_1(const char *name, int len, unsigned char *sha1, unsigned l
return get_nth_ancestor(name, len1, sha1, num); return get_nth_ancestor(name, len1, sha1, num);
} }
ret = peel_onion(name, len, sha1); ret = peel_onion(name, len, sha1, lookup_flags);
if (!ret) if (!ret)
return 0; return 0;
@ -1465,7 +1466,12 @@ static int get_sha1_with_context_1(const char *name,
if (*cp == ':') { if (*cp == ':') {
unsigned char tree_sha1[20]; unsigned char tree_sha1[20];
int len = cp - name; int len = cp - name;
if (!get_sha1_1(name, len, tree_sha1, GET_SHA1_TREEISH)) { unsigned sub_flags = flags;
sub_flags &= ~GET_SHA1_DISAMBIGUATORS;
sub_flags |= GET_SHA1_TREEISH;
if (!get_sha1_1(name, len, tree_sha1, sub_flags)) {
const char *filename = cp+1; const char *filename = cp+1;
char *new_filename = NULL; char *new_filename = NULL;

View File

@ -291,10 +291,22 @@ test_expect_success 'ambiguous short sha1 ref' '
grep "refname.*${REF}.*ambiguous" err grep "refname.*${REF}.*ambiguous" err
' '
test_expect_success C_LOCALE_OUTPUT 'ambiguity errors are not repeated' ' test_expect_success C_LOCALE_OUTPUT 'ambiguity errors are not repeated (raw)' '
test_must_fail git rev-parse 00000 2>stderr && test_must_fail git rev-parse 00000 2>stderr &&
grep "is ambiguous" stderr >errors && grep "is ambiguous" stderr >errors &&
test_line_count = 1 errors test_line_count = 1 errors
' '
test_expect_success C_LOCALE_OUTPUT 'ambiguity errors are not repeated (treeish)' '
test_must_fail git rev-parse 00000:foo 2>stderr &&
grep "is ambiguous" stderr >errors &&
test_line_count = 1 errors
'
test_expect_success C_LOCALE_OUTPUT 'ambiguity errors are not repeated (peel)' '
test_must_fail git rev-parse 00000^{commit} 2>stderr &&
grep "is ambiguous" stderr >errors &&
test_line_count = 1 errors
'
test_done test_done