]> git.ipfire.org Git - thirdparty/git.git/commitdiff
t6099, t6600: add side-exhaustion regression tests
authorKristofer Karlsson <krka@spotify.com>
Wed, 24 Jun 2026 12:14:09 +0000 (12:14 +0000)
committerJunio C Hamano <gitster@pobox.com>
Wed, 24 Jun 2026 16:58:50 +0000 (09:58 -0700)
Add t6099 to test the case where multiple merge-base candidates exist
and one is an ancestor of another. This exercises the side-exhaustion
optimization in paint_down_to_common together with the
remove_redundant safety net in get_merge_bases_many_0.

Add a mixed finite/INFINITY test to t6600 where one tip is outside
the commit-graph (INFINITY generation) and the other is inside.
This exercises the region transition: the walk starts in the
INFINITY region where side-exhaustion is disabled, then crosses
into the finite region where it can fire.

Signed-off-by: Kristofer Karlsson <krka@spotify.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
t/meson.build
t/t6099-merge-base-side-exhaustion.sh [new file with mode: 0755]
t/t6600-test-reach.sh

index 3219264fe7d4973ff96436b5c5ea2f6a9b9468a1..ee6ebdffb9284024238e2dddbebc39bd17d1780a 100644 (file)
@@ -786,6 +786,7 @@ integration_tests = [
   't6041-bisect-submodule.sh',
   't6050-replace.sh',
   't6060-merge-index.sh',
+  't6099-merge-base-side-exhaustion.sh',
   't6100-rev-list-in-order.sh',
   't6101-rev-parse-parents.sh',
   't6102-rev-list-unexpected-objects.sh',
diff --git a/t/t6099-merge-base-side-exhaustion.sh b/t/t6099-merge-base-side-exhaustion.sh
new file mode 100755 (executable)
index 0000000..4f1e0d5
--- /dev/null
@@ -0,0 +1,82 @@
+#!/bin/sh
+
+test_description='merge-base with ancestor among merge-base candidates
+
+Test that merge-base --all correctly handles cases where
+multiple merge-base candidates exist and one is an ancestor
+of another. The side-exhaustion optimization in
+paint_down_to_common may exit before STALE propagation
+removes the ancestor, but remove_redundant catches it.
+
+Graph shape (parents are below children):
+
+   A ----------- X
+   |\           /|
+   | B---------/ |
+   | |           |
+   e2 \         f2
+   |   |         |
+   e1 d1        f1
+    \  |        /
+     \ |       /
+      \|      /
+       C
+
+A and X are the two tips.
+B and C are both reachable from A and X.
+B reaches C through d1.
+Only B should appear in merge-base --all output.
+'
+
+GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
+export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
+
+TEST_PASSES_SANITIZE_LEAK=true
+. ./test-lib.sh
+
+test_expect_success 'setup ancestor merge-base candidate' '
+       test_commit C &&
+
+       git checkout -b d-chain HEAD &&
+       test_commit d1 &&
+       test_commit B &&
+
+       git checkout -b e-path C &&
+       test_commit e1 &&
+       test_commit e2 &&
+
+       git checkout -b f-path C &&
+       test_commit f1 &&
+       test_commit f2 &&
+
+       git checkout -b branch-A e-path &&
+       test_merge A B &&
+
+       git checkout -b branch-X f-path &&
+       test_merge X B &&
+
+       git commit-graph write --reachable
+'
+
+test_expect_success 'merge-base --all excludes ancestor candidate' '
+       git rev-parse B >expected &&
+       git merge-base --all A X >actual &&
+       test_cmp expected actual
+'
+
+test_expect_success 'merge-base (single) finds shallowest' '
+       git rev-parse B >expected &&
+       git merge-base A X >actual &&
+       test_cmp expected actual
+'
+
+# Without commit-graph: generation numbers are INFINITY,
+# side-exhaustion optimization does not fire.
+test_expect_success 'merge-base --all without commit-graph' '
+       rm -f .git/objects/info/commit-graph &&
+       git rev-parse B >expected &&
+       git merge-base --all A X >actual &&
+       test_cmp expected actual
+'
+
+test_done
index c2e091aad11a6dbbb2c7411ebbf3cb4beedf50e7..4b771b4c58748a7751419dbea44eda6e3666a9f4 100755 (executable)
@@ -294,6 +294,31 @@ test_expect_success 'get_merge_bases_many:infinity-both-sides' '
        test_all_modes get_merge_bases_many
 '
 
+test_expect_success 'setup mixed finite/INFINITY topology' '
+       # Create a commit outside all saved commit-graph files so it always
+       # has INFINITY generation, while its parent (ps-X) is in the graph
+       # with a finite generation. Use the ps-* orphan topology so we do
+       # not pollute the grid-based rev-list tests.
+       git checkout ps-X &&
+       test_env GIT_TEST_COMMIT_GRAPH= test_commit pm-INF
+'
+
+test_expect_success 'get_merge_bases_many:mixed-finite-infinity' '
+       # One tip (pm-INF) is outside the commit-graph with INFINITY
+       # generation; the other (ps-B) is in the graph with finite
+       # generation. The walk starts in the INFINITY region and crosses
+       # into the finite region where side-exhaustion can fire.
+       cat >input <<-\EOF &&
+       A:pm-INF
+       X:ps-B
+       EOF
+       {
+               echo "get_merge_bases_many(A,X):" &&
+               git rev-parse ps-X
+       } >expect &&
+       test_all_modes get_merge_bases_many
+'
+
 test_expect_success 'reduce_heads' '
        cat >input <<-\EOF &&
        X:commit-1-10