]> git.ipfire.org Git - thirdparty/git.git/commitdiff
Merge branch 'ps/do-not-trust-commit-graph-blindly-for-existence'
authorJunio C Hamano <gitster@pobox.com>
Wed, 8 Nov 2023 02:03:59 +0000 (11:03 +0900)
committerJunio C Hamano <gitster@pobox.com>
Wed, 8 Nov 2023 02:03:59 +0000 (11:03 +0900)
The codepath to traverse the commit-graph learned to notice that a
commit is missing (e.g., corrupt repository lost an object), even
though it knows something about the commit (like its parents) from
what is in commit-graph.

* ps/do-not-trust-commit-graph-blindly-for-existence:
  commit: detect commits that exist in commit-graph but not in the ODB
  commit-graph: introduce envvar to disable commit existence checks

1  2 
Documentation/git.txt
commit-graph.c
commit-graph.h
t/t5318-commit-graph.sh

Simple merge
diff --cc commit-graph.c
Simple merge
diff --cc commit-graph.h
Simple merge
index 6505ff595a389afa7d79fe31305d214046c376f2,2c62b91ef96ba620e74d446d2c1f054da28ee866..134239d40f05fb15ef14712ee426b2fb581c827d
@@@ -822,77 -815,52 +822,125 @@@ test_expect_success 'overflow during ge
        )
  '
  
 +corrupt_chunk () {
 +      graph=full/.git/objects/info/commit-graph &&
 +      test_when_finished "rm -rf $graph" &&
 +      git -C full commit-graph write --reachable &&
 +      corrupt_chunk_file $graph "$@"
 +}
 +
 +check_corrupt_chunk () {
 +      corrupt_chunk "$@" &&
 +      git -C full -c core.commitGraph=false log >expect.out &&
 +      git -C full -c core.commitGraph=true log >out 2>err &&
 +      test_cmp expect.out out
 +}
 +
 +test_expect_success 'reader notices too-small oid fanout chunk' '
 +      # make it big enough that the graph file is plausible,
 +      # otherwise we hit an earlier check
 +      check_corrupt_chunk OIDF clear $(printf "000000%02x" $(test_seq 250)) &&
 +      cat >expect.err <<-\EOF &&
 +      error: commit-graph oid fanout chunk is wrong size
 +      error: commit-graph is missing the OID Fanout chunk
 +      EOF
 +      test_cmp expect.err err
 +'
 +
 +test_expect_success 'reader notices fanout/lookup table mismatch' '
 +      check_corrupt_chunk OIDF 1020 "FFFFFFFF" &&
 +      cat >expect.err <<-\EOF &&
 +      error: commit-graph oid table and fanout disagree on size
 +      EOF
 +      test_cmp expect.err err
 +'
 +
 +test_expect_success 'reader notices out-of-bounds fanout' '
 +      # Rather than try to corrupt a specific hash, we will just
 +      # wreck them all. But we cannot just set them all to 0xFFFFFFFF or
 +      # similar, as they are used for hi/lo starts in a binary search (so if
 +      # they are identical, that indicates that the search should abort
 +      # immediately). Instead, we will give them high values that differ by
 +      # 2^24, ensuring that any that are used would cause an out-of-bounds
 +      # read.
 +      check_corrupt_chunk OIDF 0 $(printf "%02x000000" $(test_seq 0 254)) &&
 +      cat >expect.err <<-\EOF &&
 +      error: commit-graph fanout values out of order
 +      EOF
 +      test_cmp expect.err err
 +'
 +
 +test_expect_success 'reader notices too-small commit data chunk' '
 +      check_corrupt_chunk CDAT clear 00000000 &&
 +      cat >expect.err <<-\EOF &&
 +      error: commit-graph commit data chunk is wrong size
 +      error: commit-graph is missing the Commit Data chunk
 +      EOF
 +      test_cmp expect.err err
 +'
 +
 +test_expect_success 'reader notices out-of-bounds extra edge' '
 +      check_corrupt_chunk EDGE clear &&
 +      cat >expect.err <<-\EOF &&
 +      error: commit-graph extra-edges pointer out of bounds
 +      EOF
 +      test_cmp expect.err err
 +'
 +
 +test_expect_success 'reader notices too-small generations chunk' '
 +      check_corrupt_chunk GDA2 clear 00000000 &&
 +      cat >expect.err <<-\EOF &&
 +      error: commit-graph generations chunk is wrong size
 +      EOF
 +      test_cmp expect.err err
 +'
 +
+ test_expect_success 'stale commit cannot be parsed when given directly' '
+       test_when_finished "rm -rf repo" &&
+       git init repo &&
+       (
+               cd repo &&
+               test_commit A &&
+               test_commit B &&
+               git commit-graph write --reachable &&
+               oid=$(git rev-parse B) &&
+               rm .git/objects/"$(test_oid_to_path "$oid")" &&
+               # Verify that it is possible to read the commit from the
+               # commit graph when not being paranoid, ...
+               GIT_COMMIT_GRAPH_PARANOIA=false git rev-list B &&
+               # ... but parsing the commit when double checking that
+               # it actually exists in the object database should fail.
+               test_must_fail git rev-list -1 B
+       )
+ '
+ test_expect_success 'stale commit cannot be parsed when traversing graph' '
+       test_when_finished "rm -rf repo" &&
+       git init repo &&
+       (
+               cd repo &&
+               test_commit A &&
+               test_commit B &&
+               test_commit C &&
+               git commit-graph write --reachable &&
+               # Corrupt the repository by deleting the intermediate commit
+               # object. Commands should notice that this object is absent and
+               # thus that the repository is corrupt even if the commit graph
+               # exists.
+               oid=$(git rev-parse B) &&
+               rm .git/objects/"$(test_oid_to_path "$oid")" &&
+               # Again, we should be able to parse the commit when not
+               # being paranoid about commit graph staleness...
+               GIT_COMMIT_GRAPH_PARANOIA=false git rev-parse HEAD~2 &&
+               # ... but fail when we are paranoid.
+               test_must_fail git rev-parse HEAD~2 2>error &&
+               grep "error: commit $oid exists in commit-graph but not in the object database" error
+       )
+ '
  test_done