Skip to content

Commit ff3ba7d

Browse files
tamirdgitster
authored andcommitted
commit-reach: die on contains walk errors
Without generation numbers, repo_is_descendant_of() can return -1 when it cannot read commit ancestry. commit_contains() exposes that result through a Boolean interface, so ref-filter treats it as true. This can include a ref for --contains or exclude it for --no-contains without failing the command. Die when repo_is_descendant_of() reports an error. The memoized walk already dies when it cannot parse a commit, so callers of the non-memoized path no longer turn a failed walk into a match. Reported-by: Jeff King <peff@peff.net> Signed-off-by: Tamir Duberstein <tamird@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
1 parent ca96eee commit ff3ba7d

2 files changed

Lines changed: 29 additions & 1 deletion

File tree

commit-reach.c

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -854,10 +854,16 @@ static enum contains_result contains_tag_algo(struct commit *candidate,
854854
int commit_contains(struct ref_filter *filter, struct commit *commit,
855855
struct commit_list *list, struct contains_cache *cache)
856856
{
857+
int result;
858+
857859
if (filter->with_commit_tag_algo ||
858860
generation_numbers_enabled(the_repository))
859861
return contains_tag_algo(commit, list, cache) == CONTAINS_YES;
860-
return repo_is_descendant_of(the_repository, commit, list);
862+
863+
result = repo_is_descendant_of(the_repository, commit, list);
864+
if (result < 0)
865+
die(_("failed to check reachability"));
866+
return result;
861867
}
862868

863869
int can_all_from_reach_with_flag(struct object_array *from,

t/t6301-for-each-ref-errors.sh

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,28 @@ test_expect_success 'Missing objects are reported correctly' '
5252
test_must_be_empty brief-err
5353
'
5454

55+
test_expect_success 'missing ancestors are reported by contains filters' '
56+
test_when_finished "git update-ref -d refs/heads/missing-parent" &&
57+
{
58+
echo "tree $(git rev-parse HEAD^{tree})" &&
59+
echo "parent $MISSING" &&
60+
git cat-file commit HEAD |
61+
sed -n -e "/^author /p" -e "/^committer /p" &&
62+
echo &&
63+
echo "missing parent"
64+
} >commit &&
65+
broken=$(git hash-object -t commit -w commit) &&
66+
git update-ref refs/heads/missing-parent "$broken" &&
67+
for option in --contains --no-contains
68+
do
69+
test_must_fail git for-each-ref "$option=HEAD" \
70+
refs/heads/missing-parent >out 2>err &&
71+
test_must_be_empty out &&
72+
test_grep "parse commit $MISSING" err ||
73+
return 1
74+
done
75+
'
76+
5577
test_expect_success 'ahead-behind requires an argument' '
5678
test_must_fail git for-each-ref \
5779
--format="%(ahead-behind)" 2>err &&

0 commit comments

Comments
 (0)