From: Michael Haggerty Date: Tue, 2 Jun 2015 15:57:26 +0000 (+0200) Subject: for-each-ref: report broken references correctly X-Git-Tag: v2.4.8~5^2~2 X-Git-Url: https://git.lorimer.id.au/gitweb.git/diff_plain/8afc493d115e35092be8de3a441317f175928ab5 for-each-ref: report broken references correctly If there is a loose reference file with invalid contents, "git for-each-ref" incorrectly reports the problem as being a missing object with name NULL_SHA1: $ echo '12345678' >.git/refs/heads/nonsense $ git for-each-ref fatal: missing object 0000000000000000000000000000000000000000 for refs/heads/nonsense With an explicit "--format" string, it can even report that the reference validly points at NULL_SHA1: $ git for-each-ref --format='%(objectname) %(refname)' 0000000000000000000000000000000000000000 refs/heads/nonsense $ echo $? 0 This has been broken since b7dd2d2 for-each-ref: Do not lookup objects when they will not be used (2009-05-27) , which changed for-each-ref from using for_each_ref() to using git_for_each_rawref() in order to avoid looking up the referred-to objects unnecessarily. (When "git for-each-ref" is given a "--format" string that doesn't include information about the pointed-to object, it does not look up the object at all, which makes it considerably faster. Iterating with DO_FOR_EACH_INCLUDE_BROKEN is essential to this optimization because otherwise for_each_ref() would itself need to check whether the object exists as part of its brokenness test.) But for_each_rawref() includes broken references in the iteration, and "git for-each-ref" doesn't itself reject references with REF_ISBROKEN. The result is that broken references are processed *as if* they had the value NULL_SHA1, which is the value stored in entries for broken references. Change "git for-each-ref" to emit warnings for references that are REF_ISBROKEN but to otherwise skip them. Signed-off-by: Michael Haggerty Signed-off-by: Junio C Hamano --- diff --git a/builtin/for-each-ref.c b/builtin/for-each-ref.c index 008513c2f1..4a15f568f1 100644 --- a/builtin/for-each-ref.c +++ b/builtin/for-each-ref.c @@ -851,6 +851,11 @@ static int grab_single_ref(const char *refname, const unsigned char *sha1, int f return 0; } + if (flag & REF_ISBROKEN) { + warning("ignoring broken ref %s", refname); + return 0; + } + if (*cb->grab_pattern) { const char **pattern; int namelen = strlen(refname); diff --git a/t/t6301-for-each-ref-errors.sh b/t/t6301-for-each-ref-errors.sh index cf25244c26..72d2397e12 100755 --- a/t/t6301-for-each-ref-errors.sh +++ b/t/t6301-for-each-ref-errors.sh @@ -14,7 +14,7 @@ test_expect_success setup ' git for-each-ref --format="%(objectname) %(refname)" >brief-list ' -test_expect_failure 'Broken refs are reported correctly' ' +test_expect_success 'Broken refs are reported correctly' ' r=refs/heads/bogus && : >.git/$r && test_when_finished "rm -f .git/$r" &&