t6099, t6600: add side-exhaustion regression tests

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>
seen
Kristofer Karlsson 2026-07-11 13:27:39 +00:00 committed by Junio C Hamano
parent 6e1730e22b
commit 0789dc8f04
2 changed files with 83 additions and 0 deletions

View File

@ -788,6 +788,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',

View File

@ -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