Raw
1 #!/bin/sh
2
3 test_description='basic git replay tests'
4
5 GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
6 export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
7
8 . ./test-lib.sh
9
10 GIT_AUTHOR_NAME=author@name
11 GIT_AUTHOR_EMAIL=bogus@email@address
12 export GIT_AUTHOR_NAME GIT_AUTHOR_EMAIL
13
14 test_expect_success 'setup' '
15 test_commit A &&
16 test_commit B &&
17
18 git switch -c topic1 &&
19 test_commit C &&
20 git switch -c topic2 &&
21 test_commit D &&
22 test_commit E &&
23 git switch topic1 &&
24 test_commit F &&
25 git switch -c topic3 &&
26 test_commit G &&
27 test_commit H &&
28 git switch -c empty &&
29 git commit --allow-empty -m empty &&
30 git switch -c topic4 main &&
31 test_commit I &&
32 test_commit J &&
33
34 git switch -c next main &&
35 test_commit K &&
36 git merge -m "Merge topic1" topic1 &&
37 git merge -m "Merge topic2" topic2 &&
38 git merge -m "Merge topic3" topic3 &&
39 >evil &&
40 git add evil &&
41 git commit --amend &&
42 git merge -m "Merge topic4" topic4 &&
43
44 git switch main &&
45 test_commit L &&
46 test_commit M &&
47
48 git switch --detach topic4 &&
49 test_commit N &&
50 test_commit O &&
51 git switch -c topic-with-merge topic4 &&
52 test_merge P O --no-ff &&
53 git switch main &&
54
55 git switch --orphan unrelated &&
56 test_commit unrelated-root &&
57
58 git switch -c conflict B &&
59 test_commit C.conflict C.t conflict &&
60 git branch -D unrelated &&
61
62 git switch -c divergent-x main &&
63 test_commit X &&
64 git switch -c divergent-y main &&
65 test_commit Y &&
66 git switch divergent-x &&
67 test_merge Z divergent-y --no-ff
68 '
69
70 test_expect_success 'setup bare' '
71 git clone --bare . bare
72 '
73
74 test_expect_success 'argument to --advance must be a reference' '
75 echo "fatal: argument to --advance must be a reference" >expect &&
76 oid=$(git rev-parse main) &&
77 test_must_fail git replay --advance=$oid topic1..topic2 2>actual &&
78 test_cmp expect actual
79 '
80
81 test_expect_success '--onto with invalid commit-ish' '
82 printf "fatal: ${SQ}refs/not-valid${SQ} is not " >expect &&
83 printf "a valid commit-ish for --onto\n" >>expect &&
84 test_must_fail git replay --onto=refs/not-valid topic1..topic2 2>actual &&
85 test_cmp expect actual
86 '
87
88 test_expect_success 'exactly one of --onto, --advance, or --revert is required' '
89 echo "error: exactly one of --onto, --advance, or --revert is required" >expect &&
90 test_might_fail git replay -h >>expect &&
91 test_must_fail git replay topic1..topic2 2>actual &&
92 test_cmp expect actual
93 '
94
95 test_expect_success 'replay down to root onto another branch' '
96 git replay --ref-action=print --onto main topic2 >result &&
97
98 test_line_count = 1 result &&
99
100 git log --format=%s $(cut -f 3 -d " " result) >actual &&
101 test_write_lines E D C M L B A >expect &&
102 test_cmp expect actual
103 '
104
105 test_expect_success '--advance and --contained cannot be used together' '
106 test_must_fail git replay --advance=main --contained \
107 topic1..topic2 2>actual &&
108 test_grep "cannot be used together" actual
109 '
110
111 test_expect_success 'cannot advance target ... ordering would be ill-defined' '
112 echo "fatal: ${SQ}--advance${SQ} cannot be used with multiple revision ranges because the ordering would be ill-defined" >expect &&
113 test_must_fail git replay --advance=main main topic1 topic2 2>actual &&
114 test_cmp expect actual
115 '
116
117 test_expect_success 'replaying merge commits is not supported yet' '
118 echo "fatal: replaying merge commits is not supported yet!" >expect &&
119 test_must_fail git replay --advance=main main..topic-with-merge 2>actual &&
120 test_cmp expect actual
121 '
122
123 test_expect_success 'using replay to rebase two branches, one on top of other' '
124 git replay --ref-action=print --onto main topic1..topic2 >result &&
125
126 test_line_count = 1 result &&
127
128 git log --format=%s $(cut -f 3 -d " " result) >actual &&
129 test_write_lines E D M L B A >expect &&
130 test_cmp expect actual &&
131
132 printf "update refs/heads/topic2 " >expect &&
133 printf "%s " $(cut -f 3 -d " " result) >>expect &&
134 git rev-parse topic2 >>expect &&
135
136 test_cmp expect result
137 '
138
139 test_expect_success 'using replay on bare repo to rebase two branches, one on top of other' '
140 git -C bare replay --ref-action=print --onto main topic1..topic2 >result-bare &&
141 test_cmp expect result-bare
142 '
143
144 test_expect_success 'using replay to rebase with a conflict' '
145 test_expect_code 1 git replay --onto topic1 B..conflict
146 '
147
148 test_expect_success 'using replay on bare repo to rebase with a conflict' '
149 test_expect_code 1 git -C bare replay --onto topic1 B..conflict
150 '
151
152 test_expect_success 'using replay to perform basic cherry-pick' '
153 # The differences between this test and previous ones are:
154 # --advance vs --onto
155 # 2nd field of result is refs/heads/main vs. refs/heads/topic2
156 # 4th field of result is hash for main instead of hash for topic2
157
158 git replay --ref-action=print --advance main topic1..topic2 >result &&
159
160 test_line_count = 1 result &&
161
162 git log --format=%s $(cut -f 3 -d " " result) >actual &&
163 test_write_lines E D M L B A >expect &&
164 test_cmp expect actual &&
165
166 printf "update refs/heads/main " >expect &&
167 printf "%s " $(cut -f 3 -d " " result) >>expect &&
168 git rev-parse main >>expect &&
169
170 test_cmp expect result
171 '
172
173 test_expect_success 'using replay on bare repo to perform basic cherry-pick' '
174 git -C bare replay --ref-action=print --advance main topic1..topic2 >result-bare &&
175 test_cmp expect result-bare
176 '
177
178 test_expect_success 'commits that become empty are dropped' '
179 # Save original branches
180 git for-each-ref --format="update %(refname) %(objectname)" \
181 refs/heads/ >original-branches &&
182 test_when_finished "git update-ref --stdin <original-branches &&
183 rm original-branches" &&
184 # Cherry-pick tip of topic1 ("F"), from the middle of A..empty, to main
185 git replay --advance main topic1^! &&
186
187 # Replay all of A..empty onto main (which includes topic1 & thus F
188 # in the middle)
189 git replay --onto main --branches --ancestry-path=empty ^A \
190 >result &&
191 git log --format="%s%d" L..empty >actual &&
192 test_write_lines >expect \
193 "empty (empty)" "H (topic3)" G "C (topic1)" "F (main)" "M (tag: M)" &&
194 test_cmp expect actual
195 '
196
197 test_expect_success 'replay on bare repo fails with both --advance and --onto' '
198 test_must_fail git -C bare replay --advance main --onto main topic1..topic2 >result-bare
199 '
200
201 test_expect_success 'replay fails when both --advance and --onto are omitted' '
202 test_must_fail git replay topic1..topic2 >result
203 '
204
205 test_expect_success 'using replay to also rebase a contained branch' '
206 git replay --ref-action=print --contained --onto main main..topic3 >result &&
207
208 test_line_count = 2 result &&
209 cut -f 3 -d " " result >new-branch-tips &&
210
211 git log --format=%s $(head -n 1 new-branch-tips) >actual &&
212 test_write_lines F C M L B A >expect &&
213 test_cmp expect actual &&
214
215 git log --format=%s $(tail -n 1 new-branch-tips) >actual &&
216 test_write_lines H G F C M L B A >expect &&
217 test_cmp expect actual &&
218
219 printf "update refs/heads/topic1 " >expect &&
220 printf "%s " $(head -n 1 new-branch-tips) >>expect &&
221 git rev-parse topic1 >>expect &&
222 printf "update refs/heads/topic3 " >>expect &&
223 printf "%s " $(tail -n 1 new-branch-tips) >>expect &&
224 git rev-parse topic3 >>expect &&
225
226 test_cmp expect result
227 '
228
229 test_expect_success 'using replay on bare repo to also rebase a contained branch' '
230 git -C bare replay --ref-action=print --contained --onto main main..topic3 >result-bare &&
231 test_cmp expect result-bare
232 '
233
234 test_expect_success 'using replay to rebase multiple divergent branches' '
235 git replay --ref-action=print --onto main ^topic1 topic2 topic4 >result &&
236
237 test_line_count = 2 result &&
238 cut -f 3 -d " " result >new-branch-tips &&
239
240 git log --format=%s $(head -n 1 new-branch-tips) >actual &&
241 test_write_lines E D M L B A >expect &&
242 test_cmp expect actual &&
243
244 git log --format=%s $(tail -n 1 new-branch-tips) >actual &&
245 test_write_lines J I M L B A >expect &&
246 test_cmp expect actual &&
247
248 printf "update refs/heads/topic2 " >expect &&
249 printf "%s " $(head -n 1 new-branch-tips) >>expect &&
250 git rev-parse topic2 >>expect &&
251 printf "update refs/heads/topic4 " >>expect &&
252 printf "%s " $(tail -n 1 new-branch-tips) >>expect &&
253 git rev-parse topic4 >>expect &&
254
255 test_cmp expect result
256 '
257
258 test_expect_success 'using replay on bare repo to rebase multiple divergent branches, including contained ones' '
259 git -C bare replay --ref-action=print --contained --onto main ^main topic2 topic3 topic4 >result &&
260
261 test_line_count = 4 result &&
262 cut -f 3 -d " " result >new-branch-tips &&
263
264 >expect &&
265 for i in 2 1 3 4
266 do
267 printf "update refs/heads/topic$i " >>expect &&
268 printf "%s " $(grep topic$i result | cut -f 3 -d " ") >>expect &&
269 git -C bare rev-parse topic$i >>expect || return 1
270 done &&
271
272 test_cmp expect result &&
273
274 test_write_lines F C M L B A >expect1 &&
275 test_write_lines E D C M L B A >expect2 &&
276 test_write_lines H G F C M L B A >expect3 &&
277 test_write_lines J I M L B A >expect4 &&
278
279 for i in 1 2 3 4
280 do
281 git -C bare log --format=%s $(grep topic$i result | cut -f 3 -d " ") >actual &&
282 test_cmp expect$i actual || return 1
283 done
284 '
285
286 test_expect_success 'using replay to update detached HEAD' '
287 current_head=$(git branch --show-current) &&
288 test_when_finished git switch "$current_head" &&
289 git switch --detach &&
290 test_commit something &&
291 git replay --ref-action=print --onto HEAD~2 --ref-action=print HEAD~..HEAD >updates &&
292 test_grep "update HEAD " updates
293 '
294
295 test_expect_success 'merge.directoryRenames=false' '
296 # create a test case that stress-tests the rename caching
297 git switch -c rename-onto &&
298
299 mkdir -p to-rename &&
300 test_commit to-rename/move &&
301
302 mkdir -p renamed-directory &&
303 git mv to-rename/move* renamed-directory/ &&
304 test_tick &&
305 git commit -m renamed-directory &&
306
307 git switch -c rename-from HEAD^ &&
308 test_commit to-rename/add-a-file &&
309 echo modified >to-rename/add-a-file.t &&
310 test_tick &&
311 git commit -m modified to-rename/add-a-file.t &&
312
313 git -c merge.directoryRenames=false replay \
314 --onto rename-onto rename-onto..rename-from
315 '
316
317 test_expect_success 'default atomic behavior updates refs directly' '
318 # Use a separate branch to avoid contaminating topic2 for later tests
319 git branch test-atomic topic2 &&
320 test_when_finished "git branch -D test-atomic" &&
321
322 # Test default atomic behavior (no output, refs updated)
323 git replay --onto main topic1..test-atomic >output &&
324 test_must_be_empty output &&
325
326 # Verify ref was updated
327 git log --format=%s test-atomic >actual &&
328 test_write_lines E D M L B A >expect &&
329 test_cmp expect actual &&
330
331 # Verify reflog message includes SHA of onto commit
332 git reflog test-atomic -1 --format=%gs >reflog-msg &&
333 ONTO_SHA=$(git rev-parse main) &&
334 echo "replay --onto $ONTO_SHA" >expect-reflog &&
335 test_cmp expect-reflog reflog-msg
336 '
337
338 test_expect_success 'atomic behavior in bare repository' '
339 # Store original state for cleanup
340 START=$(git -C bare rev-parse topic2) &&
341 test_when_finished "git -C bare update-ref refs/heads/topic2 $START" &&
342
343 # Test atomic updates work in bare repo
344 git -C bare replay --onto main topic1..topic2 >output &&
345 test_must_be_empty output &&
346
347 # Verify ref was updated in bare repo
348 git -C bare log --format=%s topic2 >actual &&
349 test_write_lines E D M L B A >expect &&
350 test_cmp expect actual
351 '
352
353 test_expect_success 'reflog message for --advance mode' '
354 # Store original state
355 START=$(git rev-parse main) &&
356 test_when_finished "git update-ref refs/heads/main $START" &&
357
358 # Test --advance mode reflog message
359 git replay --advance main topic1..topic2 >output &&
360 test_must_be_empty output &&
361
362 # Verify reflog message includes --advance and branch name
363 git reflog main -1 --format=%gs >reflog-msg &&
364 echo "replay --advance main" >expect-reflog &&
365 test_cmp expect-reflog reflog-msg
366 '
367
368 test_expect_success 'replay.refAction=print config option' '
369 # Store original state
370 START=$(git rev-parse topic2) &&
371 test_when_finished "git branch -f topic2 $START" &&
372
373 # Test with config set to print
374 test_config replay.refAction print &&
375 git replay --onto main topic1..topic2 >output &&
376 test_line_count = 1 output &&
377 test_grep "^update refs/heads/topic2 " output
378 '
379
380 test_expect_success 'replay.refAction=update config option' '
381 # Store original state
382 START=$(git rev-parse topic2) &&
383 test_when_finished "git branch -f topic2 $START" &&
384
385 # Test with config set to update
386 test_config replay.refAction update &&
387 git replay --onto main topic1..topic2 >output &&
388 test_must_be_empty output &&
389
390 # Verify ref was updated
391 git log --format=%s topic2 >actual &&
392 test_write_lines E D M L B A >expect &&
393 test_cmp expect actual
394 '
395
396 test_expect_success 'command-line --ref-action overrides config' '
397 # Store original state
398 START=$(git rev-parse topic2) &&
399 test_when_finished "git branch -f topic2 $START" &&
400
401 # Set config to update but use --ref-action=print
402 test_config replay.refAction update &&
403 git replay --ref-action=print --onto main topic1..topic2 >output &&
404 test_line_count = 1 output &&
405 test_grep "^update refs/heads/topic2 " output
406 '
407
408 test_expect_success 'invalid replay.refAction value' '
409 test_config replay.refAction invalid &&
410 test_must_fail git replay --onto main topic1..topic2 2>error &&
411 test_grep "invalid.*replay.refAction.*value" error
412 '
413
414 test_expect_success 'argument to --revert must be a reference' '
415 echo "fatal: argument to --revert must be a reference" >expect &&
416 oid=$(git rev-parse main) &&
417 test_must_fail git replay --revert=$oid topic1..topic2 2>actual &&
418 test_cmp expect actual
419 '
420
421 test_expect_success 'cannot revert with multiple sources' '
422 echo "fatal: ${SQ}--revert${SQ} cannot be used with multiple revision ranges because the ordering would be ill-defined" >expect &&
423 test_must_fail git replay --revert main main topic1 topic2 2>actual &&
424 test_cmp expect actual
425 '
426
427 test_expect_success 'using replay --revert to revert commits' '
428 # Reuse existing topic4 branch (has commits I and J on top of main)
429 START=$(git rev-parse topic4) &&
430 test_when_finished "git branch -f topic4 $START" &&
431
432 # Revert commits I and J
433 git replay --revert topic4 topic4~2..topic4 &&
434
435 # Verify the revert commits were created (newest-first ordering
436 # means J is reverted first, then I on top)
437 git log --format=%s -4 topic4 >actual &&
438 cat >expect <<-\EOF &&
439 Revert "I"
440 Revert "J"
441 J
442 I
443 EOF
444 test_cmp expect actual &&
445
446 # Verify commit message format includes hash (tip is Revert "I")
447 test_commit_message topic4 <<-EOF &&
448 Revert "I"
449
450 This reverts commit $(git rev-parse I).
451 EOF
452
453 # Verify reflog message
454 git reflog topic4 -1 --format=%gs >reflog-msg &&
455 echo "replay --revert topic4" >expect-reflog &&
456 test_cmp expect-reflog reflog-msg
457 '
458
459 test_expect_success 'using replay --revert in bare repo' '
460 # Reuse existing topic4 in bare repo
461 START=$(git -C bare rev-parse topic4) &&
462 test_when_finished "git -C bare update-ref refs/heads/topic4 $START" &&
463
464 # Revert commit J in bare repo
465 git -C bare replay --revert topic4 topic4~1..topic4 &&
466
467 # Verify revert was created
468 git -C bare log -1 --format=%s topic4 >actual &&
469 echo "Revert \"J\"" >expect &&
470 test_cmp expect actual
471 '
472
473 test_expect_success 'revert of revert uses Reapply' '
474 # Use topic4 and first revert J, then revert the revert
475 START=$(git rev-parse topic4) &&
476 test_when_finished "git branch -f topic4 $START" &&
477
478 # First revert J
479 git replay --revert topic4 topic4~1..topic4 &&
480 REVERT_J=$(git rev-parse topic4) &&
481
482 # Now revert the revert - should become Reapply
483 git replay --revert topic4 topic4~1..topic4 &&
484
485 # Verify Reapply prefix and message format
486 test_commit_message topic4 <<-EOF
487 Reapply "J"
488
489 This reverts commit $REVERT_J.
490 EOF
491 '
492
493 test_expect_success 'git replay --revert with conflict' '
494 # conflict branch has C.conflict which conflicts with topic1s C
495 test_expect_code 1 git replay --revert conflict B..topic1
496 '
497
498 test_expect_success 'git replay --revert incompatible with --contained' '
499 test_must_fail git replay --revert topic4 --contained topic4~1..topic4 2>error &&
500 test_grep "cannot be used together" error
501 '
502
503 test_expect_success 'git replay --revert incompatible with --onto' '
504 test_must_fail git replay --revert topic4 --onto main topic4~1..topic4 2>error &&
505 test_grep "cannot be used together" error
506 '
507
508 test_expect_success 'git replay --revert incompatible with --advance' '
509 test_must_fail git replay --revert topic4 --advance main topic4~1..topic4 2>error &&
510 test_grep "cannot be used together" error
511 '
512
513 test_expect_success 'using --onto with --ref' '
514 git branch test-ref-onto topic2 &&
515 test_when_finished "git branch -D test-ref-onto" &&
516
517 git replay --ref-action=print --onto=main --ref=refs/heads/test-ref-onto topic1..topic2 >result &&
518
519 test_line_count = 1 result &&
520 test_grep "^update refs/heads/test-ref-onto " result &&
521
522 git log --format=%s $(cut -f 3 -d " " result) >actual &&
523 test_write_lines E D M L B A >expect &&
524 test_cmp expect actual
525 '
526
527 test_expect_success 'using --advance with --ref' '
528 git branch test-ref-advance main &&
529 git branch test-ref-target main &&
530 test_when_finished "git branch -D test-ref-advance test-ref-target" &&
531
532 git replay --ref-action=print --advance=test-ref-advance --ref=refs/heads/test-ref-target topic1..topic2 >result &&
533
534 test_line_count = 1 result &&
535 test_grep "^update refs/heads/test-ref-target " result
536 '
537
538 test_expect_success 'using --revert with --ref' '
539 git branch test-ref-revert topic4 &&
540 git branch test-ref-revert-target topic4 &&
541 test_when_finished "git branch -D test-ref-revert test-ref-revert-target" &&
542
543 git replay --ref-action=print --revert=test-ref-revert --ref=refs/heads/test-ref-revert-target topic4~1..topic4 >result &&
544
545 test_line_count = 1 result &&
546 test_grep "^update refs/heads/test-ref-revert-target " result
547 '
548
549 test_expect_success '--ref is incompatible with --contained' '
550 test_must_fail git replay --onto=main --ref=refs/heads/main --contained topic1..topic2 2>err &&
551 test_grep "cannot be used together" err
552 '
553
554 test_expect_success '--ref with nonexistent fully-qualified ref' '
555 test_when_finished "git update-ref -d refs/heads/new-branch" &&
556
557 git replay --onto=main --ref=refs/heads/new-branch topic1..topic2 &&
558
559 git log --format=%s -2 new-branch >actual &&
560 test_write_lines E D >expect &&
561 test_cmp expect actual
562 '
563
564 test_expect_success '--ref must be a valid refname' '
565 test_must_fail git replay --onto=main --ref="refs/heads/bad..ref" topic1..topic2 2>err &&
566 test_grep "is not a valid refname" err
567 '
568
569 test_expect_success '--ref requires fully qualified ref' '
570 test_must_fail git replay --onto=main --ref=main topic1..topic2 2>err &&
571 test_grep "is not a valid refname" err
572 '
573
574 test_expect_success '--onto with --ref rejects multiple revision ranges' '
575 test_must_fail git replay --onto=main --ref=refs/heads/topic2 ^topic1 topic2 topic4 2>err &&
576 test_grep "cannot be used with multiple revision ranges" err
577 '
578
579 test_expect_success 'replay to rebase merge commit with --linearize' '
580 git replay --ref-action=print --linearize \
581 --onto main I..topic-with-merge >result &&
582
583 test_line_count = 1 result &&
584
585 git log --format=%s $(cut -f 3 -d " " result) >actual &&
586 test_write_lines O N J M L B A >expect &&
587 test_cmp expect actual
588 '
589
590 test_expect_success 'replay to rebase merge commit with --linearize down to the root commit' '
591 git replay --ref-action=print --linearize \
592 --onto unrelated-root topic-with-merge >result &&
593
594 test_line_count = 1 result &&
595
596 git log --format=%s $(cut -f 3 -d " " result) >actual &&
597 test_write_lines O N J I B A unrelated-root >expect &&
598 test_cmp expect actual
599 '
600
601 test_expect_success 'replay to cherry-pick merge commit with --linearize' '
602 git replay --ref-action=print --linearize \
603 --advance main I..topic-with-merge >result &&
604
605 test_line_count = 1 result &&
606
607 git log --format=%s $(cut -f 3 -d " " result) >actual &&
608 test_write_lines O N J M L B A >expect &&
609 test_cmp expect actual &&
610
611 printf "update refs/heads/main " >expect &&
612 printf "%s " $(cut -f 3 -d " " result) >>expect &&
613 git rev-parse main >>expect &&
614 test_cmp expect result
615 '
616
617 test_expect_success 'replay --linearize produces the same patches' '
618 git replay --ref-action=print --linearize \
619 --onto main I..topic-with-merge >result &&
620
621 test_line_count = 1 result &&
622 tip=$(cut -f 3 -d " " result) &&
623
624 # range-diff does not care about the dropped merge,
625 # so the original commits (I..topic-with-merge)
626 # and the replayed chain (main..tip) must produce identical patches.
627 git range-diff I..topic-with-merge main..$tip >out &&
628 test_file_not_empty out &&
629 test_grep ! -v "=" out &&
630
631 git log --oneline main..$tip >out &&
632 test_line_count = 3 out
633 '
634
635 test_expect_success 'replay with --linearize rebase multiple divergent branches into a single line' '
636 git replay --ref-action=print --linearize \
637 --onto main ^B topic2 topic3 topic4 >result &&
638
639 test_line_count = 3 result &&
640 cut -f 3 -d " " result >new-branch-tips &&
641
642 >expect &&
643 for i in 2 3 4
644 do
645 printf "update refs/heads/topic$i " >>expect &&
646 printf "%s " $(grep topic$i result | cut -f 3 -d " ") >>expect &&
647 git rev-parse topic$i >>expect || return 1
648 done &&
649
650 test_cmp expect result &&
651
652 test_write_lines E D C M L B A >expect2 &&
653 test_write_lines H G F E D C M L B A >expect3 &&
654 test_write_lines J I H G F E D C M L B A >expect4 &&
655
656 for i in 2 3 4
657 do
658 git log --format=%s $(grep topic$i result | cut -f 3 -d " ") >actual &&
659 test_cmp expect$i actual || return 1
660 done
661 '
662
663 test_expect_success 'replay with --linearize of a divergent merge keeps both sides' '
664 git replay --ref-action=print --linearize \
665 --onto main main..divergent-x >result &&
666 test_line_count = 1 result &&
667 tip=$(cut -f 3 -d " " result) &&
668
669 # The merge Z is dropped, but both X and Y are linearized onto main;
670 # neither side is lost.
671 git log --format=%s main..$tip >actual &&
672 test_write_lines Y X >expect &&
673 test_cmp expect actual
674 '
675
676 test_expect_success '--linearize with --contained updates contained refs' '
677 git replay --ref-action=print --linearize --contained \
678 --onto main ^B topic-with-merge >result &&
679
680 test_line_count = 2 result &&
681
682 git log --format=%s $(head -n 1 result | cut -f 3 -d " ") >actual &&
683 test_write_lines J I M L B A >expect &&
684 test_cmp expect actual &&
685
686 git log --format=%s $(tail -n 1 result | cut -f 3 -d " ") >actual &&
687 test_write_lines O N J I M L B A >expect &&
688 test_cmp expect actual
689 '
690
691 test_expect_success 'replay --revert with --linearize reverts a range containing a merge' '
692 git replay --ref-action=print --revert=divergent-x --linearize \
693 main..divergent-x >result &&
694 test_line_count = 1 result &&
695 tip=$(cut -f 3 -d " " result) &&
696
697 git log --format=%s $tip >actual &&
698 test_write_lines \
699 "Revert \"X\"" "Revert \"Y\"" Z Y X M L B A >expect &&
700 test_cmp expect actual &&
701
702 test_must_fail git cat-file -e $tip:X.t &&
703 test_must_fail git cat-file -e $tip:Y.t
704 '
705
706 test_done