Sync with 2.44.1
[git/gitster.git] / t / t4301-merge-tree-write-tree.sh
blobeea19907b550c4a97a7ca7760f1be30bea7d8db0
1 #!/bin/sh
3 test_description='git merge-tree --write-tree'
5 . ./test-lib.sh
7 # This test is ort-specific
8 if test "$GIT_TEST_MERGE_ALGORITHM" != "ort"
9 then
10 skip_all="GIT_TEST_MERGE_ALGORITHM != ort"
11 test_done
14 test_expect_success setup '
15 test_write_lines 1 2 3 4 5 >numbers &&
16 echo hello >greeting &&
17 echo foo >whatever &&
18 git add numbers greeting whatever &&
19 test_tick &&
20 git commit -m initial &&
22 git branch side1 &&
23 git branch side2 &&
24 git branch side3 &&
25 git branch side4 &&
27 git checkout side1 &&
28 test_write_lines 1 2 3 4 5 6 >numbers &&
29 echo hi >greeting &&
30 echo bar >whatever &&
31 git add numbers greeting whatever &&
32 test_tick &&
33 git commit -m modify-stuff &&
35 git checkout side2 &&
36 test_write_lines 0 1 2 3 4 5 >numbers &&
37 echo yo >greeting &&
38 git rm whatever &&
39 mkdir whatever &&
40 >whatever/empty &&
41 git add numbers greeting whatever/empty &&
42 test_tick &&
43 git commit -m other-modifications &&
45 git checkout side3 &&
46 git mv numbers sequence &&
47 test_tick &&
48 git commit -m rename-numbers &&
50 git checkout side4 &&
51 test_write_lines 0 1 2 3 4 5 >numbers &&
52 echo yo >greeting &&
53 git add numbers greeting &&
54 test_tick &&
55 git commit -m other-content-modifications &&
57 git switch --orphan unrelated &&
58 >something-else &&
59 git add something-else &&
60 test_tick &&
61 git commit -m first-commit
64 test_expect_success 'Clean merge' '
65 TREE_OID=$(git merge-tree --write-tree side1 side3) &&
66 q_to_tab <<-EOF >expect &&
67 100644 blob $(git rev-parse side1:greeting)Qgreeting
68 100644 blob $(git rev-parse side1:numbers)Qsequence
69 100644 blob $(git rev-parse side1:whatever)Qwhatever
70 EOF
72 git ls-tree $TREE_OID >actual &&
73 test_cmp expect actual
76 test_expect_success 'Content merge and a few conflicts' '
77 git checkout side1^0 &&
78 test_must_fail git merge side2 &&
79 expected_tree=$(git rev-parse AUTO_MERGE) &&
81 # We will redo the merge, while we are still in a conflicted state!
82 git ls-files -u >conflicted-file-info &&
83 test_when_finished "git reset --hard" &&
85 test_expect_code 1 git merge-tree --write-tree side1 side2 >RESULT &&
86 actual_tree=$(head -n 1 RESULT) &&
88 # Due to differences of e.g. "HEAD" vs "side1", the results will not
89 # exactly match. Dig into individual files.
91 # Numbers should have three-way merged cleanly
92 test_write_lines 0 1 2 3 4 5 6 >expect &&
93 git show ${actual_tree}:numbers >actual &&
94 test_cmp expect actual &&
96 # whatever and whatever~<branch> should have same HASHES
97 git rev-parse ${expected_tree}:whatever ${expected_tree}:whatever~HEAD >expect &&
98 git rev-parse ${actual_tree}:whatever ${actual_tree}:whatever~side1 >actual &&
99 test_cmp expect actual &&
101 # greeting should have a merge conflict
102 git show ${expected_tree}:greeting >tmp &&
103 sed -e s/HEAD/side1/ tmp >expect &&
104 git show ${actual_tree}:greeting >actual &&
105 test_cmp expect actual
108 test_expect_success 'Auto resolve conflicts by "ours" strategy option' '
109 git checkout side1^0 &&
111 # make sure merge conflict exists
112 test_must_fail git merge side4 &&
113 git merge --abort &&
115 git merge -X ours side4 &&
116 git rev-parse HEAD^{tree} >expected &&
118 git merge-tree -X ours side1 side4 >actual &&
120 test_cmp expected actual
123 test_expect_success 'Barf on misspelled option, with exit code other than 0 or 1' '
124 # Mis-spell with single "s" instead of double "s"
125 test_expect_code 129 git merge-tree --write-tree --mesages FOOBAR side1 side2 2>expect &&
127 grep "error: unknown option.*mesages" expect
130 test_expect_success 'Barf on too many arguments' '
131 test_expect_code 129 git merge-tree --write-tree side1 side2 invalid 2>expect &&
133 grep "^usage: git merge-tree" expect
136 anonymize_hash() {
137 sed -e "s/[0-9a-f]\{40,\}/HASH/g" "$@"
140 test_expect_success 'test conflict notices and such' '
141 test_expect_code 1 git merge-tree --write-tree --name-only side1 side2 >out &&
142 anonymize_hash out >actual &&
144 # Expected results:
145 # "greeting" should merge with conflicts
146 # "numbers" should merge cleanly
147 # "whatever" has *both* a modify/delete and a file/directory conflict
148 cat <<-EOF >expect &&
149 HASH
150 greeting
151 whatever~side1
153 Auto-merging greeting
154 CONFLICT (content): Merge conflict in greeting
155 Auto-merging numbers
156 CONFLICT (file/directory): directory in the way of whatever from side1; moving it to whatever~side1 instead.
157 CONFLICT (modify/delete): whatever~side1 deleted in side2 and modified in side1. Version side1 of whatever~side1 left in tree.
160 test_cmp expect actual
163 # directory rename + content conflict
164 # Commit O: foo, olddir/{a,b,c}
165 # Commit A: modify foo, newdir/{a,b,c}
166 # Commit B: modify foo differently & rename foo -> olddir/bar
167 # Expected: CONFLICT(content) for newdir/bar (not olddir/bar or foo)
169 test_expect_success 'directory rename + content conflict' '
170 # Setup
171 git init dir-rename-and-content &&
173 cd dir-rename-and-content &&
174 test_write_lines 1 2 3 4 5 >foo &&
175 mkdir olddir &&
176 for i in a b c; do echo $i >olddir/$i || exit 1; done &&
177 git add foo olddir &&
178 git commit -m "original" &&
180 git branch O &&
181 git branch A &&
182 git branch B &&
184 git checkout A &&
185 test_write_lines 1 2 3 4 5 6 >foo &&
186 git add foo &&
187 git mv olddir newdir &&
188 git commit -m "Modify foo, rename olddir to newdir" &&
190 git checkout B &&
191 test_write_lines 1 2 3 4 5 six >foo &&
192 git add foo &&
193 git mv foo olddir/bar &&
194 git commit -m "Modify foo & rename foo -> olddir/bar"
195 ) &&
196 # Testing
198 cd dir-rename-and-content &&
200 test_expect_code 1 \
201 git merge-tree -z A^0 B^0 >out &&
202 echo >>out &&
203 anonymize_hash out >actual &&
204 q_to_tab <<-\EOF | lf_to_nul >expect &&
205 HASH
206 100644 HASH 1Qnewdir/bar
207 100644 HASH 2Qnewdir/bar
208 100644 HASH 3Qnewdir/bar
211 q_to_nul <<-EOF >>expect &&
212 Q2Qnewdir/barQolddir/barQCONFLICT (directory rename suggested)QCONFLICT (file location): foo renamed to olddir/bar in B^0, inside a directory that was renamed in A^0, suggesting it should perhaps be moved to newdir/bar.
213 Q1Qnewdir/barQAuto-mergingQAuto-merging newdir/bar
214 Q1Qnewdir/barQCONFLICT (contents)QCONFLICT (content): Merge conflict in newdir/bar
217 test_cmp expect actual
221 # rename/delete + modify/delete handling
222 # Commit O: foo
223 # Commit A: modify foo + rename to bar
224 # Commit B: delete foo
225 # Expected: CONFLICT(rename/delete) + CONFLICT(modify/delete)
227 test_expect_success 'rename/delete handling' '
228 # Setup
229 git init rename-delete &&
231 cd rename-delete &&
232 test_write_lines 1 2 3 4 5 >foo &&
233 git add foo &&
234 git commit -m "original" &&
236 git branch O &&
237 git branch A &&
238 git branch B &&
240 git checkout A &&
241 test_write_lines 1 2 3 4 5 6 >foo &&
242 git add foo &&
243 git mv foo bar &&
244 git commit -m "Modify foo, rename to bar" &&
246 git checkout B &&
247 git rm foo &&
248 git commit -m "remove foo"
249 ) &&
250 # Testing
252 cd rename-delete &&
254 test_expect_code 1 \
255 git merge-tree -z A^0 B^0 >out &&
256 echo >>out &&
257 anonymize_hash out >actual &&
258 q_to_tab <<-\EOF | lf_to_nul >expect &&
259 HASH
260 100644 HASH 1Qbar
261 100644 HASH 2Qbar
264 q_to_nul <<-EOF >>expect &&
265 Q2QbarQfooQCONFLICT (rename/delete)QCONFLICT (rename/delete): foo renamed to bar in A^0, but deleted in B^0.
266 Q1QbarQCONFLICT (modify/delete)QCONFLICT (modify/delete): bar deleted in B^0 and modified in A^0. Version A^0 of bar left in tree.
269 test_cmp expect actual
273 # rename/add handling
274 # Commit O: foo
275 # Commit A: modify foo, add different bar
276 # Commit B: modify & rename foo->bar
277 # Expected: CONFLICT(add/add) [via rename collide] for bar
279 test_expect_success 'rename/add handling' '
280 # Setup
281 git init rename-add &&
283 cd rename-add &&
284 test_write_lines original 1 2 3 4 5 >foo &&
285 git add foo &&
286 git commit -m "original" &&
288 git branch O &&
289 git branch A &&
290 git branch B &&
292 git checkout A &&
293 test_write_lines 1 2 3 4 5 >foo &&
294 echo "different file" >bar &&
295 git add foo bar &&
296 git commit -m "Modify foo, add bar" &&
298 git checkout B &&
299 test_write_lines original 1 2 3 4 5 6 >foo &&
300 git add foo &&
301 git mv foo bar &&
302 git commit -m "rename foo to bar"
303 ) &&
304 # Testing
306 cd rename-add &&
308 test_expect_code 1 \
309 git merge-tree -z A^0 B^0 >out &&
310 echo >>out &&
313 # First, check that the bar that appears at stage 3 does not
314 # correspond to an individual blob anywhere in history
316 hash=$(tr "\0" "\n" <out | head -n 3 | grep 3.bar | cut -f 2 -d " ") &&
317 git rev-list --objects --all >all_blobs &&
318 ! grep $hash all_blobs &&
321 # Second, check anonymized hash output against expectation
323 anonymize_hash out >actual &&
324 q_to_tab <<-\EOF | lf_to_nul >expect &&
325 HASH
326 100644 HASH 2Qbar
327 100644 HASH 3Qbar
330 q_to_nul <<-EOF >>expect &&
331 Q1QbarQAuto-mergingQAuto-merging bar
332 Q1QbarQCONFLICT (contents)QCONFLICT (add/add): Merge conflict in bar
333 Q1QfooQAuto-mergingQAuto-merging foo
336 test_cmp expect actual
340 # rename/add, where add is a mode conflict
341 # Commit O: foo
342 # Commit A: modify foo, add symlink bar
343 # Commit B: modify & rename foo->bar
344 # Expected: CONFLICT(distinct modes) for bar
346 test_expect_success SYMLINKS 'rename/add, where add is a mode conflict' '
347 # Setup
348 git init rename-add-symlink &&
350 cd rename-add-symlink &&
351 test_write_lines original 1 2 3 4 5 >foo &&
352 git add foo &&
353 git commit -m "original" &&
355 git branch O &&
356 git branch A &&
357 git branch B &&
359 git checkout A &&
360 test_write_lines 1 2 3 4 5 >foo &&
361 ln -s foo bar &&
362 git add foo bar &&
363 git commit -m "Modify foo, add symlink bar" &&
365 git checkout B &&
366 test_write_lines original 1 2 3 4 5 6 >foo &&
367 git add foo &&
368 git mv foo bar &&
369 git commit -m "rename foo to bar"
370 ) &&
371 # Testing
373 cd rename-add-symlink &&
375 test_expect_code 1 \
376 git merge-tree -z A^0 B^0 >out &&
377 echo >>out &&
380 # First, check that the bar that appears at stage 3 does not
381 # correspond to an individual blob anywhere in history
383 hash=$(tr "\0" "\n" <out | head -n 3 | grep 3.bar | cut -f 2 -d " ") &&
384 git rev-list --objects --all >all_blobs &&
385 ! grep $hash all_blobs &&
388 # Second, check anonymized hash output against expectation
390 anonymize_hash out >actual &&
391 q_to_tab <<-\EOF | lf_to_nul >expect &&
392 HASH
393 120000 HASH 2Qbar
394 100644 HASH 3Qbar~B^0
397 q_to_nul <<-EOF >>expect &&
398 Q2QbarQbar~B^0QCONFLICT (distinct modes)QCONFLICT (distinct types): bar had different types on each side; renamed one of them so each can be recorded somewhere.
399 Q1QfooQAuto-mergingQAuto-merging foo
402 test_cmp expect actual
406 # rename/rename(1to2) + content conflict handling
407 # Commit O: foo
408 # Commit A: modify foo & rename to bar
409 # Commit B: modify foo & rename to baz
410 # Expected: CONFLICT(rename/rename)
412 test_expect_success 'rename/rename + content conflict' '
413 # Setup
414 git init rr-plus-content &&
416 cd rr-plus-content &&
417 test_write_lines 1 2 3 4 5 >foo &&
418 git add foo &&
419 git commit -m "original" &&
421 git branch O &&
422 git branch A &&
423 git branch B &&
425 git checkout A &&
426 test_write_lines 1 2 3 4 5 six >foo &&
427 git add foo &&
428 git mv foo bar &&
429 git commit -m "Modify foo + rename to bar" &&
431 git checkout B &&
432 test_write_lines 1 2 3 4 5 6 >foo &&
433 git add foo &&
434 git mv foo baz &&
435 git commit -m "Modify foo + rename to baz"
436 ) &&
437 # Testing
439 cd rr-plus-content &&
441 test_expect_code 1 \
442 git merge-tree -z A^0 B^0 >out &&
443 echo >>out &&
444 anonymize_hash out >actual &&
445 q_to_tab <<-\EOF | lf_to_nul >expect &&
446 HASH
447 100644 HASH 2Qbar
448 100644 HASH 3Qbaz
449 100644 HASH 1Qfoo
452 q_to_nul <<-EOF >>expect &&
453 Q1QfooQAuto-mergingQAuto-merging foo
454 Q3QfooQbarQbazQCONFLICT (rename/rename)QCONFLICT (rename/rename): foo renamed to bar in A^0 and to baz in B^0.
457 test_cmp expect actual
461 # rename/add/delete
462 # Commit O: foo
463 # Commit A: rm foo, add different bar
464 # Commit B: rename foo->bar
465 # Expected: CONFLICT (rename/delete), CONFLICT(add/add) [via rename collide]
466 # for bar
468 test_expect_success 'rename/add/delete conflict' '
469 # Setup
470 git init rad &&
472 cd rad &&
473 echo "original file" >foo &&
474 git add foo &&
475 git commit -m "original" &&
477 git branch O &&
478 git branch A &&
479 git branch B &&
481 git checkout A &&
482 git rm foo &&
483 echo "different file" >bar &&
484 git add bar &&
485 git commit -m "Remove foo, add bar" &&
487 git checkout B &&
488 git mv foo bar &&
489 git commit -m "rename foo to bar"
490 ) &&
491 # Testing
493 cd rad &&
495 test_expect_code 1 \
496 git merge-tree -z B^0 A^0 >out &&
497 echo >>out &&
498 anonymize_hash out >actual &&
500 q_to_tab <<-\EOF | lf_to_nul >expect &&
501 HASH
502 100644 HASH 2Qbar
503 100644 HASH 3Qbar
507 q_to_nul <<-EOF >>expect &&
508 2QbarQfooQCONFLICT (rename/delete)QCONFLICT (rename/delete): foo renamed to bar in B^0, but deleted in A^0.
509 Q1QbarQAuto-mergingQAuto-merging bar
510 Q1QbarQCONFLICT (contents)QCONFLICT (add/add): Merge conflict in bar
513 test_cmp expect actual
517 # rename/rename(2to1)/delete/delete
518 # Commit O: foo, bar
519 # Commit A: rename foo->baz, rm bar
520 # Commit B: rename bar->baz, rm foo
521 # Expected: 2x CONFLICT (rename/delete), CONFLICT (add/add) via colliding
522 # renames for baz
524 test_expect_success 'rename/rename(2to1)/delete/delete conflict' '
525 # Setup
526 git init rrdd &&
528 cd rrdd &&
529 echo foo >foo &&
530 echo bar >bar &&
531 git add foo bar &&
532 git commit -m O &&
534 git branch O &&
535 git branch A &&
536 git branch B &&
538 git checkout A &&
539 git mv foo baz &&
540 git rm bar &&
541 git commit -m "Rename foo, remove bar" &&
543 git checkout B &&
544 git mv bar baz &&
545 git rm foo &&
546 git commit -m "Rename bar, remove foo"
547 ) &&
548 # Testing
550 cd rrdd &&
552 test_expect_code 1 \
553 git merge-tree -z A^0 B^0 >out &&
554 echo >>out &&
555 anonymize_hash out >actual &&
557 q_to_tab <<-\EOF | lf_to_nul >expect &&
558 HASH
559 100644 HASH 2Qbaz
560 100644 HASH 3Qbaz
564 q_to_nul <<-EOF >>expect &&
565 2QbazQbarQCONFLICT (rename/delete)QCONFLICT (rename/delete): bar renamed to baz in B^0, but deleted in A^0.
566 Q2QbazQfooQCONFLICT (rename/delete)QCONFLICT (rename/delete): foo renamed to baz in A^0, but deleted in B^0.
567 Q1QbazQAuto-mergingQAuto-merging baz
568 Q1QbazQCONFLICT (contents)QCONFLICT (add/add): Merge conflict in baz
571 test_cmp expect actual
575 # mod6: chains of rename/rename(1to2) + add/add via colliding renames
576 # Commit O: one, three, five
577 # Commit A: one->two, three->four, five->six
578 # Commit B: one->six, three->two, five->four
579 # Expected: three CONFLICT(rename/rename) messages + three CONFLICT(add/add)
580 # messages; each path in two of the multi-way merged contents
581 # found in two, four, six
583 test_expect_success 'mod6: chains of rename/rename(1to2) and add/add via colliding renames' '
584 # Setup
585 git init mod6 &&
587 cd mod6 &&
588 test_seq 11 19 >one &&
589 test_seq 31 39 >three &&
590 test_seq 51 59 >five &&
591 git add . &&
592 test_tick &&
593 git commit -m "O" &&
595 git branch O &&
596 git branch A &&
597 git branch B &&
599 git checkout A &&
600 test_seq 10 19 >one &&
601 echo 40 >>three &&
602 git add one three &&
603 git mv one two &&
604 git mv three four &&
605 git mv five six &&
606 test_tick &&
607 git commit -m "A" &&
609 git checkout B &&
610 echo 20 >>one &&
611 echo forty >>three &&
612 echo 60 >>five &&
613 git add one three five &&
614 git mv one six &&
615 git mv three two &&
616 git mv five four &&
617 test_tick &&
618 git commit -m "B"
619 ) &&
620 # Testing
622 cd mod6 &&
624 test_expect_code 1 \
625 git merge-tree -z A^0 B^0 >out &&
626 echo >>out &&
629 # First, check that some of the hashes that appear as stage
630 # conflict entries do not appear as individual blobs anywhere
631 # in history.
633 hash1=$(tr "\0" "\n" <out | head | grep 2.four | cut -f 2 -d " ") &&
634 hash2=$(tr "\0" "\n" <out | head | grep 3.two | cut -f 2 -d " ") &&
635 git rev-list --objects --all >all_blobs &&
636 ! grep $hash1 all_blobs &&
637 ! grep $hash2 all_blobs &&
640 # Now compare anonymized hash output with expectation
642 anonymize_hash out >actual &&
643 q_to_tab <<-\EOF | lf_to_nul >expect &&
644 HASH
645 100644 HASH 1Qfive
646 100644 HASH 2Qfour
647 100644 HASH 3Qfour
648 100644 HASH 1Qone
649 100644 HASH 2Qsix
650 100644 HASH 3Qsix
651 100644 HASH 1Qthree
652 100644 HASH 2Qtwo
653 100644 HASH 3Qtwo
657 q_to_nul <<-EOF >>expect &&
658 3QfiveQsixQfourQCONFLICT (rename/rename)QCONFLICT (rename/rename): five renamed to six in A^0 and to four in B^0.
659 Q1QfourQAuto-mergingQAuto-merging four
660 Q1QfourQCONFLICT (contents)QCONFLICT (add/add): Merge conflict in four
661 Q1QoneQAuto-mergingQAuto-merging one
662 Q3QoneQtwoQsixQCONFLICT (rename/rename)QCONFLICT (rename/rename): one renamed to two in A^0 and to six in B^0.
663 Q1QsixQAuto-mergingQAuto-merging six
664 Q1QsixQCONFLICT (contents)QCONFLICT (add/add): Merge conflict in six
665 Q1QthreeQAuto-mergingQAuto-merging three
666 Q3QthreeQfourQtwoQCONFLICT (rename/rename)QCONFLICT (rename/rename): three renamed to four in A^0 and to two in B^0.
667 Q1QtwoQAuto-mergingQAuto-merging two
668 Q1QtwoQCONFLICT (contents)QCONFLICT (add/add): Merge conflict in two
671 test_cmp expect actual
675 # directory rename + rename/delete + modify/delete + directory/file conflict
676 # Commit O: foo, olddir/{a,b,c}
677 # Commit A: delete foo, rename olddir/ -> newdir/, add newdir/bar/file
678 # Commit B: modify foo & rename foo -> olddir/bar
679 # Expected: CONFLICT(content) for newdir/bar (not olddir/bar or foo)
681 test_expect_success 'directory rename + rename/delete + modify/delete + directory/file conflict' '
682 # Setup
683 git init 4-stacked-conflict &&
685 cd 4-stacked-conflict &&
686 test_write_lines 1 2 3 4 5 >foo &&
687 mkdir olddir &&
688 for i in a b c; do echo $i >olddir/$i || exit 1; done &&
689 git add foo olddir &&
690 git commit -m "original" &&
692 git branch O &&
693 git branch A &&
694 git branch B &&
696 git checkout A &&
697 git rm foo &&
698 git mv olddir newdir &&
699 mkdir newdir/bar &&
700 >newdir/bar/file &&
701 git add newdir/bar/file &&
702 git commit -m "rm foo, olddir/ -> newdir/, + newdir/bar/file" &&
704 git checkout B &&
705 test_write_lines 1 2 3 4 5 6 >foo &&
706 git add foo &&
707 git mv foo olddir/bar &&
708 git commit -m "Modify foo & rename foo -> olddir/bar"
709 ) &&
710 # Testing
712 cd 4-stacked-conflict &&
714 test_expect_code 1 \
715 git merge-tree -z A^0 B^0 >out &&
716 echo >>out &&
717 anonymize_hash out >actual &&
719 q_to_tab <<-\EOF | lf_to_nul >expect &&
720 HASH
721 100644 HASH 1Qnewdir/bar~B^0
722 100644 HASH 3Qnewdir/bar~B^0
725 q_to_nul <<-EOF >>expect &&
726 Q2Qnewdir/barQolddir/barQCONFLICT (directory rename suggested)QCONFLICT (file location): foo renamed to olddir/bar in B^0, inside a directory that was renamed in A^0, suggesting it should perhaps be moved to newdir/bar.
727 Q2Qnewdir/barQfooQCONFLICT (rename/delete)QCONFLICT (rename/delete): foo renamed to newdir/bar in B^0, but deleted in A^0.
728 Q2Qnewdir/bar~B^0Qnewdir/barQCONFLICT (file/directory)QCONFLICT (file/directory): directory in the way of newdir/bar from B^0; moving it to newdir/bar~B^0 instead.
729 Q1Qnewdir/bar~B^0QCONFLICT (modify/delete)QCONFLICT (modify/delete): newdir/bar~B^0 deleted in A^0 and modified in B^0. Version B^0 of newdir/bar~B^0 left in tree.
732 test_cmp expect actual
736 for opt in $(git merge-tree --git-completion-helper-all)
738 if test $opt = "--trivial-merge" || test $opt = "--write-tree"
739 then
740 continue
743 test_expect_success "usage: --trivial-merge is incompatible with $opt" '
744 test_expect_code 128 git merge-tree --trivial-merge $opt side1 side2 side3
746 done
748 test_expect_success 'Just the conflicted files without the messages' '
749 test_expect_code 1 git merge-tree --write-tree --no-messages --name-only side1 side2 >out &&
750 anonymize_hash out >actual &&
752 test_write_lines HASH greeting whatever~side1 >expect &&
754 test_cmp expect actual
757 test_expect_success 'Check conflicted oids and modes without messages' '
758 test_expect_code 1 git merge-tree --write-tree --no-messages side1 side2 >out &&
759 anonymize_hash out >actual &&
761 # Compare the basic output format
762 q_to_tab >expect <<-\EOF &&
763 HASH
764 100644 HASH 1Qgreeting
765 100644 HASH 2Qgreeting
766 100644 HASH 3Qgreeting
767 100644 HASH 1Qwhatever~side1
768 100644 HASH 2Qwhatever~side1
771 test_cmp expect actual &&
773 # Check the actual hashes against the `ls-files -u` output too
774 tail -n +2 out | sed -e s/side1/HEAD/ >actual &&
775 test_cmp conflicted-file-info actual
778 test_expect_success 'NUL terminated conflicted file "lines"' '
779 git checkout -b tweak1 side1 &&
780 test_write_lines zero 1 2 3 4 5 6 >numbers &&
781 git add numbers &&
782 git mv numbers "Αυτά μου φαίνονται κινέζικα" &&
783 git commit -m "Renamed numbers" &&
785 test_expect_code 1 git merge-tree --write-tree -z tweak1 side2 >out &&
786 echo >>out &&
787 anonymize_hash out >actual &&
789 # Expected results:
790 # "greeting" should merge with conflicts
791 # "whatever" has *both* a modify/delete and a file/directory conflict
792 # "Αυτά μου φαίνονται κινέζικα" should have a conflict
793 echo HASH | lf_to_nul >expect &&
795 q_to_tab <<-EOF | lf_to_nul >>expect &&
796 100644 HASH 1Qgreeting
797 100644 HASH 2Qgreeting
798 100644 HASH 3Qgreeting
799 100644 HASH 1Qwhatever~tweak1
800 100644 HASH 2Qwhatever~tweak1
801 100644 HASH 1QΑυτά μου φαίνονται κινέζικα
802 100644 HASH 2QΑυτά μου φαίνονται κινέζικα
803 100644 HASH 3QΑυτά μου φαίνονται κινέζικα
807 q_to_nul <<-EOF >>expect &&
808 1QgreetingQAuto-mergingQAuto-merging greeting
809 Q1QgreetingQCONFLICT (contents)QCONFLICT (content): Merge conflict in greeting
810 Q2Qwhatever~tweak1QwhateverQCONFLICT (file/directory)QCONFLICT (file/directory): directory in the way of whatever from tweak1; moving it to whatever~tweak1 instead.
811 Q1Qwhatever~tweak1QCONFLICT (modify/delete)QCONFLICT (modify/delete): whatever~tweak1 deleted in side2 and modified in tweak1. Version tweak1 of whatever~tweak1 left in tree.
812 Q1QΑυτά μου φαίνονται κινέζικαQAuto-mergingQAuto-merging Αυτά μου φαίνονται κινέζικα
813 Q1QΑυτά μου φαίνονται κινέζικαQCONFLICT (contents)QCONFLICT (content): Merge conflict in Αυτά μου φαίνονται κινέζικα
817 test_cmp expect actual
820 test_expect_success 'error out by default for unrelated histories' '
821 test_expect_code 128 git merge-tree --write-tree side1 unrelated 2>error &&
823 grep "refusing to merge unrelated histories" error
826 test_expect_success 'can override merge of unrelated histories' '
827 git merge-tree --write-tree --allow-unrelated-histories side1 unrelated >tree &&
828 TREE=$(cat tree) &&
830 git rev-parse side1:numbers side1:greeting side1:whatever unrelated:something-else >expect &&
831 git rev-parse $TREE:numbers $TREE:greeting $TREE:whatever $TREE:something-else >actual &&
833 test_cmp expect actual
836 test_expect_success SANITY 'merge-ort fails gracefully in a read-only repository' '
837 git init --bare read-only &&
838 git push read-only side1 side2 side3 &&
839 test_when_finished "chmod -R u+w read-only" &&
840 chmod -R a-w read-only &&
841 test_must_fail git -C read-only merge-tree side1 side3 &&
842 test_must_fail git -C read-only merge-tree side1 side2
845 test_expect_success '--stdin with both a successful and a conflicted merge' '
846 printf "side1 side3\nside1 side2" | git merge-tree --stdin >actual &&
848 git checkout side1^0 &&
849 git merge side3 &&
851 printf "1\0" >expect &&
852 git rev-parse HEAD^{tree} | lf_to_nul >>expect &&
853 printf "\0" >>expect &&
855 git checkout side1^0 &&
856 test_must_fail git merge side2 &&
857 sed s/HEAD/side1/ greeting >tmp &&
858 mv tmp greeting &&
859 git add -u &&
860 git mv whatever~HEAD whatever~side1 &&
862 printf "0\0" >>expect &&
863 git write-tree | lf_to_nul >>expect &&
865 cat <<-EOF | q_to_tab | lf_to_nul >>expect &&
866 100644 $(git rev-parse side1~1:greeting) 1Qgreeting
867 100644 $(git rev-parse side1:greeting) 2Qgreeting
868 100644 $(git rev-parse side2:greeting) 3Qgreeting
869 100644 $(git rev-parse side1~1:whatever) 1Qwhatever~side1
870 100644 $(git rev-parse side1:whatever) 2Qwhatever~side1
873 q_to_nul <<-EOF >>expect &&
874 Q1QgreetingQAuto-mergingQAuto-merging greeting
875 Q1QgreetingQCONFLICT (contents)QCONFLICT (content): Merge conflict in greeting
876 Q1QnumbersQAuto-mergingQAuto-merging numbers
877 Q2Qwhatever~side1QwhateverQCONFLICT (file/directory)QCONFLICT (file/directory): directory in the way of whatever from side1; moving it to whatever~side1 instead.
878 Q1Qwhatever~side1QCONFLICT (modify/delete)QCONFLICT (modify/delete): whatever~side1 deleted in side2 and modified in side1. Version side1 of whatever~side1 left in tree.
881 printf "\0\0" >>expect &&
883 test_cmp expect actual
887 test_expect_success '--merge-base is incompatible with --stdin' '
888 test_must_fail git merge-tree --merge-base=side1 --stdin 2>expect &&
890 grep "^fatal: .*merge-base.*stdin.* cannot be used together" expect
893 # specify merge-base as parent of branch2
894 # git merge-tree --write-tree --merge-base=c2 c1 c3
895 # Commit c1: add file1
896 # Commit c2: add file2 after c1
897 # Commit c3: add file3 after c2
898 # Expected: add file3, and file2 does NOT appear
900 test_expect_success 'specify merge-base as parent of branch2' '
901 # Setup
902 test_when_finished "rm -rf base-b2-p" &&
903 git init base-b2-p &&
904 test_commit -C base-b2-p c1 file1 &&
905 test_commit -C base-b2-p c2 file2 &&
906 test_commit -C base-b2-p c3 file3 &&
908 # Testing
909 TREE_OID=$(git -C base-b2-p merge-tree --write-tree --merge-base=c2 c1 c3) &&
911 q_to_tab <<-EOF >expect &&
912 100644 blob $(git -C base-b2-p rev-parse c1:file1)Qfile1
913 100644 blob $(git -C base-b2-p rev-parse c3:file3)Qfile3
916 git -C base-b2-p ls-tree $TREE_OID >actual &&
917 test_cmp expect actual
920 # Since the earlier tests have verified that individual merge-tree calls
921 # are doing the right thing, this test case is only used to verify that
922 # we can also trigger merges via --stdin, and that when we do we get
923 # the same answer as running a bunch of separate merges.
925 test_expect_success 'check the input format when --stdin is passed' '
926 test_when_finished "rm -rf repo" &&
927 git init repo &&
928 test_commit -C repo c1 &&
929 test_commit -C repo c2 &&
930 test_commit -C repo c3 &&
931 printf "c1 c3\nc2 -- c1 c3\nc2 c3" | git -C repo merge-tree --stdin >actual &&
933 printf "1\0" >expect &&
934 git -C repo merge-tree --write-tree -z c1 c3 >>expect &&
935 printf "\0" >>expect &&
937 printf "1\0" >>expect &&
938 git -C repo merge-tree --write-tree -z --merge-base=c2 c1 c3 >>expect &&
939 printf "\0" >>expect &&
941 printf "1\0" >>expect &&
942 git -C repo merge-tree --write-tree -z c2 c3 >>expect &&
943 printf "\0" >>expect &&
945 test_cmp expect actual
948 test_expect_success '--merge-base with tree OIDs' '
949 git merge-tree --merge-base=side1^ side1 side3 >with-commits &&
950 git merge-tree --merge-base=side1^^{tree} side1^{tree} side3^{tree} >with-trees &&
951 test_cmp with-commits with-trees
954 test_expect_success 'error out on missing tree objects' '
955 git init --bare missing-tree.git &&
956 git rev-list side3 >list &&
957 git rev-parse side3^: >>list &&
958 git pack-objects missing-tree.git/objects/pack/side3-tree-is-missing <list &&
959 side3=$(git rev-parse side3) &&
960 test_must_fail git --git-dir=missing-tree.git merge-tree $side3^ $side3 >actual 2>err &&
961 test_grep "Could not read $(git rev-parse $side3:)" err &&
962 test_must_be_empty actual
965 test_expect_success 'error out on missing blob objects' '
966 echo 1 | git hash-object -w --stdin >blob1 &&
967 echo 2 | git hash-object -w --stdin >blob2 &&
968 echo 3 | git hash-object -w --stdin >blob3 &&
969 printf "100644 blob $(cat blob1)\tblob\n" | git mktree >tree1 &&
970 printf "100644 blob $(cat blob2)\tblob\n" | git mktree >tree2 &&
971 printf "100644 blob $(cat blob3)\tblob\n" | git mktree >tree3 &&
972 git init --bare missing-blob.git &&
973 cat blob1 blob3 tree1 tree2 tree3 |
974 git pack-objects missing-blob.git/objects/pack/side1-whatever-is-missing &&
975 test_must_fail git --git-dir=missing-blob.git >actual 2>err \
976 merge-tree --merge-base=$(cat tree1) $(cat tree2) $(cat tree3) &&
977 test_grep "unable to read blob object $(cat blob2)" err &&
978 test_must_be_empty actual
981 test_expect_success 'error out on missing commits as well' '
982 git init --bare missing-commit.git &&
983 git rev-list --objects side1 side3 >list-including-initial &&
984 grep -v ^$(git rev-parse side1^) <list-including-initial >list &&
985 git pack-objects missing-commit.git/objects/pack/missing-initial <list &&
986 side1=$(git rev-parse side1) &&
987 side3=$(git rev-parse side3) &&
988 test_must_fail git --git-dir=missing-commit.git \
989 merge-tree --allow-unrelated-histories $side1 $side3 >actual &&
990 test_must_be_empty actual
993 test_done