@@ -49,6 +49,62 @@ test_expect_success 'setup' '
4949 git tag -a -m "$x-$i" tag-$x-$i commit-$x-$i || return 1
5050 done
5151 done &&
52+
53+ # Build a small side topology to exercise the (PARENT1|PARENT2) ->
54+ # (PARENT1|PARENT2|STALE) transition in paint_down_to_common(); the
55+ # 10x10 grid above does not exercise it because no merge-base candidate
56+ # there is a descendant of another, so STALE never reaches a
57+ # still-pending candidate.
58+ #
59+ # ps-X
60+ # /|\
61+ # / | \
62+ # ps-Z ps-B ps-W
63+ # | / \ |
64+ # | / \ |
65+ # |/ \|
66+ # ps-T1 ps-T2
67+ #
68+ # where ps-T1=merge(ps-Z,ps-B), ps-T2=merge(ps-W,ps-B), so
69+ # merge-base(ps-T1,ps-T2) = ps-B. During the walk, ps-X transitions
70+ # to (PARENT1|PARENT2) via ps-Z and ps-W before ps-B is dequeued;
71+ # then the STALE-walk from ps-B transitions ps-X to
72+ # (PARENT1|PARENT2|STALE).
73+ git checkout --orphan ps-orphan &&
74+ test_commit ps-X &&
75+ git checkout -b ps-B-br ps-X && test_commit ps-B &&
76+ git checkout -b ps-Z-br ps-X && test_commit ps-Z &&
77+ git checkout -b ps-W-br ps-X && test_commit ps-W &&
78+ git checkout -b ps-T1 ps-Z &&
79+ git merge --no-ff -m ps-T1 ps-B &&
80+ git checkout -b ps-T2 ps-W &&
81+ git merge --no-ff -m ps-T2 ps-B &&
82+
83+ # Build a side topology that lives entirely outside the half
84+ # commit-graph and has non-monotonic commit dates, to exercise the
85+ # INFINITY-gate in paint_down_to_common. With both tips outside
86+ # the graph, generation is INFINITY and the queue falls back to
87+ # commit-date order, which here is non-monotonic.
88+ #
89+ # pi-X (date 500, PARENT1 tip) --> pi-P, pi-D
90+ # pi-D (date 480) --> pi-C
91+ # pi-C (date 200) --> pi-B
92+ # pi-B (date 100, PARENT2 tip) --> pi-P
93+ # pi-P (date 450, root)
94+ #
95+ # merge-base(pi-X, pi-B) = pi-B (it is an ancestor of pi-X and is
96+ # itself one of the queried tips).
97+ git checkout --orphan pi-orphan &&
98+ test_commit --date "@450 +0000" pi-P &&
99+ test_commit --date "@100 +0000" pi-B &&
100+ test_commit --date "@200 +0000" pi-C &&
101+ test_commit --date "@480 +0000" pi-D &&
102+ GIT_AUTHOR_DATE="@500 +0000" GIT_COMMITTER_DATE="@500 +0000" \
103+ git commit-tree -p pi-D -p pi-P -m pi-X pi-D^{tree} >pi-X-oid &&
104+ pi_x="$(cat pi-X-oid)" &&
105+ git branch -f pi-X-br "$pi_x" &&
106+ git tag pi-X "$pi_x" &&
107+
52108 git commit-graph write --reachable &&
53109 mv .git/objects/info/commit-graph commit-graph-full &&
54110 chmod u+w commit-graph-full &&
@@ -146,6 +202,16 @@ test_expect_success 'in_merge_bases_many:miss-heuristic' '
146202 test_all_modes in_merge_bases_many
147203'
148204
205+ test_expect_success ' in_merge_bases_many:self' '
206+ cat >input <<-\EOF &&
207+ A:commit-6-8
208+ X:commit-5-9
209+ X:commit-6-8
210+ EOF
211+ echo "in_merge_bases_many(A,X):1" >expect &&
212+ test_all_modes in_merge_bases_many
213+ '
214+
149215test_expect_success ' is_descendant_of:hit' '
150216 cat >input <<-\EOF &&
151217 A:commit-5-7
@@ -183,6 +249,51 @@ test_expect_success 'get_merge_bases_many' '
183249 test_all_modes get_merge_bases_many
184250'
185251
252+ test_expect_success ' get_merge_bases_many:duplicate-twos' '
253+ cat >input <<-\EOF &&
254+ A:commit-5-7
255+ X:commit-4-8
256+ X:commit-4-8
257+ X:commit-6-6
258+ X:commit-6-6
259+ X:commit-8-3
260+ EOF
261+ {
262+ echo "get_merge_bases_many(A,X):" &&
263+ git rev-parse commit-5-6 \
264+ commit-4-7 | sort
265+ } >expect &&
266+ test_all_modes get_merge_bases_many
267+ '
268+
269+ test_expect_success ' get_merge_bases_many:pending-stale' '
270+ # Exercises the (PARENT1|PARENT2) -> (...|STALE) transition path in
271+ # paint_down_to_common(). See the topology comment in the setup test.
272+ cat >input <<-\EOF &&
273+ A:ps-T1
274+ X:ps-T2
275+ EOF
276+ {
277+ echo "get_merge_bases_many(A,X):" &&
278+ git rev-parse ps-B
279+ } >expect &&
280+ test_all_modes get_merge_bases_many
281+ '
282+
283+ test_expect_success ' get_merge_bases_many:infinity-both-sides' '
284+ # Exercises the push-time INFINITY-gate in paint_down_to_common(). See
285+ # the pi-* topology comment in the setup test.
286+ cat >input <<-\EOF &&
287+ A:pi-X
288+ X:pi-B
289+ EOF
290+ {
291+ echo "get_merge_bases_many(A,X):" &&
292+ git rev-parse pi-B
293+ } >expect &&
294+ test_all_modes get_merge_bases_many
295+ '
296+
186297test_expect_success ' reduce_heads' '
187298 cat >input <<-\EOF &&
188299 X:commit-1-10
0 commit comments