Merge branch 'ds/scalar-updates' into maint-2.42
[alt-git.git] / t / t4301-merge-tree-write-tree.sh
blob250f721795b5bd2ecba3090b7e181c50673540aa
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 &&
26 git checkout side1 &&
27 test_write_lines 1 2 3 4 5 6 >numbers &&
28 echo hi >greeting &&
29 echo bar >whatever &&
30 git add numbers greeting whatever &&
31 test_tick &&
32 git commit -m modify-stuff &&
34 git checkout side2 &&
35 test_write_lines 0 1 2 3 4 5 >numbers &&
36 echo yo >greeting &&
37 git rm whatever &&
38 mkdir whatever &&
39 >whatever/empty &&
40 git add numbers greeting whatever/empty &&
41 test_tick &&
42 git commit -m other-modifications &&
44 git checkout side3 &&
45 git mv numbers sequence &&
46 test_tick &&
47 git commit -m rename-numbers &&
49 git switch --orphan unrelated &&
50 >something-else &&
51 git add something-else &&
52 test_tick &&
53 git commit -m first-commit
56 test_expect_success 'Clean merge' '
57 TREE_OID=$(git merge-tree --write-tree side1 side3) &&
58 q_to_tab <<-EOF >expect &&
59 100644 blob $(git rev-parse side1:greeting)Qgreeting
60 100644 blob $(git rev-parse side1:numbers)Qsequence
61 100644 blob $(git rev-parse side1:whatever)Qwhatever
62 EOF
64 git ls-tree $TREE_OID >actual &&
65 test_cmp expect actual
68 test_expect_success 'Content merge and a few conflicts' '
69 git checkout side1^0 &&
70 test_must_fail git merge side2 &&
71 expected_tree=$(git rev-parse AUTO_MERGE) &&
73 # We will redo the merge, while we are still in a conflicted state!
74 git ls-files -u >conflicted-file-info &&
75 test_when_finished "git reset --hard" &&
77 test_expect_code 1 git merge-tree --write-tree side1 side2 >RESULT &&
78 actual_tree=$(head -n 1 RESULT) &&
80 # Due to differences of e.g. "HEAD" vs "side1", the results will not
81 # exactly match. Dig into individual files.
83 # Numbers should have three-way merged cleanly
84 test_write_lines 0 1 2 3 4 5 6 >expect &&
85 git show ${actual_tree}:numbers >actual &&
86 test_cmp expect actual &&
88 # whatever and whatever~<branch> should have same HASHES
89 git rev-parse ${expected_tree}:whatever ${expected_tree}:whatever~HEAD >expect &&
90 git rev-parse ${actual_tree}:whatever ${actual_tree}:whatever~side1 >actual &&
91 test_cmp expect actual &&
93 # greeting should have a merge conflict
94 git show ${expected_tree}:greeting >tmp &&
95 sed -e s/HEAD/side1/ tmp >expect &&
96 git show ${actual_tree}:greeting >actual &&
97 test_cmp expect actual
100 test_expect_success 'Barf on misspelled option, with exit code other than 0 or 1' '
101 # Mis-spell with single "s" instead of double "s"
102 test_expect_code 129 git merge-tree --write-tree --mesages FOOBAR side1 side2 2>expect &&
104 grep "error: unknown option.*mesages" expect
107 test_expect_success 'Barf on too many arguments' '
108 test_expect_code 129 git merge-tree --write-tree side1 side2 invalid 2>expect &&
110 grep "^usage: git merge-tree" expect
113 anonymize_hash() {
114 sed -e "s/[0-9a-f]\{40,\}/HASH/g" "$@"
117 test_expect_success 'test conflict notices and such' '
118 test_expect_code 1 git merge-tree --write-tree --name-only side1 side2 >out &&
119 anonymize_hash out >actual &&
121 # Expected results:
122 # "greeting" should merge with conflicts
123 # "numbers" should merge cleanly
124 # "whatever" has *both* a modify/delete and a file/directory conflict
125 cat <<-EOF >expect &&
126 HASH
127 greeting
128 whatever~side1
130 Auto-merging greeting
131 CONFLICT (content): Merge conflict in greeting
132 Auto-merging numbers
133 CONFLICT (file/directory): directory in the way of whatever from side1; moving it to whatever~side1 instead.
134 CONFLICT (modify/delete): whatever~side1 deleted in side2 and modified in side1. Version side1 of whatever~side1 left in tree.
137 test_cmp expect actual
140 # directory rename + content conflict
141 # Commit O: foo, olddir/{a,b,c}
142 # Commit A: modify foo, newdir/{a,b,c}
143 # Commit B: modify foo differently & rename foo -> olddir/bar
144 # Expected: CONFLICT(content) for newdir/bar (not olddir/bar or foo)
146 test_expect_success 'directory rename + content conflict' '
147 # Setup
148 git init dir-rename-and-content &&
150 cd dir-rename-and-content &&
151 test_write_lines 1 2 3 4 5 >foo &&
152 mkdir olddir &&
153 for i in a b c; do echo $i >olddir/$i || exit 1; done &&
154 git add foo olddir &&
155 git commit -m "original" &&
157 git branch O &&
158 git branch A &&
159 git branch B &&
161 git checkout A &&
162 test_write_lines 1 2 3 4 5 6 >foo &&
163 git add foo &&
164 git mv olddir newdir &&
165 git commit -m "Modify foo, rename olddir to newdir" &&
167 git checkout B &&
168 test_write_lines 1 2 3 4 5 six >foo &&
169 git add foo &&
170 git mv foo olddir/bar &&
171 git commit -m "Modify foo & rename foo -> olddir/bar"
172 ) &&
173 # Testing
175 cd dir-rename-and-content &&
177 test_expect_code 1 \
178 git merge-tree -z A^0 B^0 >out &&
179 echo >>out &&
180 anonymize_hash out >actual &&
181 q_to_tab <<-\EOF | lf_to_nul >expect &&
182 HASH
183 100644 HASH 1Qnewdir/bar
184 100644 HASH 2Qnewdir/bar
185 100644 HASH 3Qnewdir/bar
188 q_to_nul <<-EOF >>expect &&
189 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.
190 Q1Qnewdir/barQAuto-mergingQAuto-merging newdir/bar
191 Q1Qnewdir/barQCONFLICT (contents)QCONFLICT (content): Merge conflict in newdir/bar
194 test_cmp expect actual
198 # rename/delete + modify/delete handling
199 # Commit O: foo
200 # Commit A: modify foo + rename to bar
201 # Commit B: delete foo
202 # Expected: CONFLICT(rename/delete) + CONFLICT(modify/delete)
204 test_expect_success 'rename/delete handling' '
205 # Setup
206 git init rename-delete &&
208 cd rename-delete &&
209 test_write_lines 1 2 3 4 5 >foo &&
210 git add foo &&
211 git commit -m "original" &&
213 git branch O &&
214 git branch A &&
215 git branch B &&
217 git checkout A &&
218 test_write_lines 1 2 3 4 5 6 >foo &&
219 git add foo &&
220 git mv foo bar &&
221 git commit -m "Modify foo, rename to bar" &&
223 git checkout B &&
224 git rm foo &&
225 git commit -m "remove foo"
226 ) &&
227 # Testing
229 cd rename-delete &&
231 test_expect_code 1 \
232 git merge-tree -z A^0 B^0 >out &&
233 echo >>out &&
234 anonymize_hash out >actual &&
235 q_to_tab <<-\EOF | lf_to_nul >expect &&
236 HASH
237 100644 HASH 1Qbar
238 100644 HASH 2Qbar
241 q_to_nul <<-EOF >>expect &&
242 Q2QbarQfooQCONFLICT (rename/delete)QCONFLICT (rename/delete): foo renamed to bar in A^0, but deleted in B^0.
243 Q1QbarQCONFLICT (modify/delete)QCONFLICT (modify/delete): bar deleted in B^0 and modified in A^0. Version A^0 of bar left in tree.
246 test_cmp expect actual
250 # rename/add handling
251 # Commit O: foo
252 # Commit A: modify foo, add different bar
253 # Commit B: modify & rename foo->bar
254 # Expected: CONFLICT(add/add) [via rename collide] for bar
256 test_expect_success 'rename/add handling' '
257 # Setup
258 git init rename-add &&
260 cd rename-add &&
261 test_write_lines original 1 2 3 4 5 >foo &&
262 git add foo &&
263 git commit -m "original" &&
265 git branch O &&
266 git branch A &&
267 git branch B &&
269 git checkout A &&
270 test_write_lines 1 2 3 4 5 >foo &&
271 echo "different file" >bar &&
272 git add foo bar &&
273 git commit -m "Modify foo, add bar" &&
275 git checkout B &&
276 test_write_lines original 1 2 3 4 5 6 >foo &&
277 git add foo &&
278 git mv foo bar &&
279 git commit -m "rename foo to bar"
280 ) &&
281 # Testing
283 cd rename-add &&
285 test_expect_code 1 \
286 git merge-tree -z A^0 B^0 >out &&
287 echo >>out &&
290 # First, check that the bar that appears at stage 3 does not
291 # correspond to an individual blob anywhere in history
293 hash=$(cat out | tr "\0" "\n" | head -n 3 | grep 3.bar | cut -f 2 -d " ") &&
294 git rev-list --objects --all >all_blobs &&
295 ! grep $hash all_blobs &&
298 # Second, check anonymized hash output against expectation
300 anonymize_hash out >actual &&
301 q_to_tab <<-\EOF | lf_to_nul >expect &&
302 HASH
303 100644 HASH 2Qbar
304 100644 HASH 3Qbar
307 q_to_nul <<-EOF >>expect &&
308 Q1QbarQAuto-mergingQAuto-merging bar
309 Q1QbarQCONFLICT (contents)QCONFLICT (add/add): Merge conflict in bar
310 Q1QfooQAuto-mergingQAuto-merging foo
313 test_cmp expect actual
317 # rename/add, where add is a mode conflict
318 # Commit O: foo
319 # Commit A: modify foo, add symlink bar
320 # Commit B: modify & rename foo->bar
321 # Expected: CONFLICT(distinct modes) for bar
323 test_expect_success SYMLINKS 'rename/add, where add is a mode conflict' '
324 # Setup
325 git init rename-add-symlink &&
327 cd rename-add-symlink &&
328 test_write_lines original 1 2 3 4 5 >foo &&
329 git add foo &&
330 git commit -m "original" &&
332 git branch O &&
333 git branch A &&
334 git branch B &&
336 git checkout A &&
337 test_write_lines 1 2 3 4 5 >foo &&
338 ln -s foo bar &&
339 git add foo bar &&
340 git commit -m "Modify foo, add symlink bar" &&
342 git checkout B &&
343 test_write_lines original 1 2 3 4 5 6 >foo &&
344 git add foo &&
345 git mv foo bar &&
346 git commit -m "rename foo to bar"
347 ) &&
348 # Testing
350 cd rename-add-symlink &&
352 test_expect_code 1 \
353 git merge-tree -z A^0 B^0 >out &&
354 echo >>out &&
357 # First, check that the bar that appears at stage 3 does not
358 # correspond to an individual blob anywhere in history
360 hash=$(cat out | tr "\0" "\n" | head -n 3 | grep 3.bar | cut -f 2 -d " ") &&
361 git rev-list --objects --all >all_blobs &&
362 ! grep $hash all_blobs &&
365 # Second, check anonymized hash output against expectation
367 anonymize_hash out >actual &&
368 q_to_tab <<-\EOF | lf_to_nul >expect &&
369 HASH
370 120000 HASH 2Qbar
371 100644 HASH 3Qbar~B^0
374 q_to_nul <<-EOF >>expect &&
375 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.
376 Q1QfooQAuto-mergingQAuto-merging foo
379 test_cmp expect actual
383 # rename/rename(1to2) + content conflict handling
384 # Commit O: foo
385 # Commit A: modify foo & rename to bar
386 # Commit B: modify foo & rename to baz
387 # Expected: CONFLICT(rename/rename)
389 test_expect_success 'rename/rename + content conflict' '
390 # Setup
391 git init rr-plus-content &&
393 cd rr-plus-content &&
394 test_write_lines 1 2 3 4 5 >foo &&
395 git add foo &&
396 git commit -m "original" &&
398 git branch O &&
399 git branch A &&
400 git branch B &&
402 git checkout A &&
403 test_write_lines 1 2 3 4 5 six >foo &&
404 git add foo &&
405 git mv foo bar &&
406 git commit -m "Modify foo + rename to bar" &&
408 git checkout B &&
409 test_write_lines 1 2 3 4 5 6 >foo &&
410 git add foo &&
411 git mv foo baz &&
412 git commit -m "Modify foo + rename to baz"
413 ) &&
414 # Testing
416 cd rr-plus-content &&
418 test_expect_code 1 \
419 git merge-tree -z A^0 B^0 >out &&
420 echo >>out &&
421 anonymize_hash out >actual &&
422 q_to_tab <<-\EOF | lf_to_nul >expect &&
423 HASH
424 100644 HASH 2Qbar
425 100644 HASH 3Qbaz
426 100644 HASH 1Qfoo
429 q_to_nul <<-EOF >>expect &&
430 Q1QfooQAuto-mergingQAuto-merging foo
431 Q3QfooQbarQbazQCONFLICT (rename/rename)QCONFLICT (rename/rename): foo renamed to bar in A^0 and to baz in B^0.
434 test_cmp expect actual
438 # rename/add/delete
439 # Commit O: foo
440 # Commit A: rm foo, add different bar
441 # Commit B: rename foo->bar
442 # Expected: CONFLICT (rename/delete), CONFLICT(add/add) [via rename collide]
443 # for bar
445 test_expect_success 'rename/add/delete conflict' '
446 # Setup
447 git init rad &&
449 cd rad &&
450 echo "original file" >foo &&
451 git add foo &&
452 git commit -m "original" &&
454 git branch O &&
455 git branch A &&
456 git branch B &&
458 git checkout A &&
459 git rm foo &&
460 echo "different file" >bar &&
461 git add bar &&
462 git commit -m "Remove foo, add bar" &&
464 git checkout B &&
465 git mv foo bar &&
466 git commit -m "rename foo to bar"
467 ) &&
468 # Testing
470 cd rad &&
472 test_expect_code 1 \
473 git merge-tree -z B^0 A^0 >out &&
474 echo >>out &&
475 anonymize_hash out >actual &&
477 q_to_tab <<-\EOF | lf_to_nul >expect &&
478 HASH
479 100644 HASH 2Qbar
480 100644 HASH 3Qbar
484 q_to_nul <<-EOF >>expect &&
485 2QbarQfooQCONFLICT (rename/delete)QCONFLICT (rename/delete): foo renamed to bar in B^0, but deleted in A^0.
486 Q1QbarQAuto-mergingQAuto-merging bar
487 Q1QbarQCONFLICT (contents)QCONFLICT (add/add): Merge conflict in bar
490 test_cmp expect actual
494 # rename/rename(2to1)/delete/delete
495 # Commit O: foo, bar
496 # Commit A: rename foo->baz, rm bar
497 # Commit B: rename bar->baz, rm foo
498 # Expected: 2x CONFLICT (rename/delete), CONFLICT (add/add) via colliding
499 # renames for baz
501 test_expect_success 'rename/rename(2to1)/delete/delete conflict' '
502 # Setup
503 git init rrdd &&
505 cd rrdd &&
506 echo foo >foo &&
507 echo bar >bar &&
508 git add foo bar &&
509 git commit -m O &&
511 git branch O &&
512 git branch A &&
513 git branch B &&
515 git checkout A &&
516 git mv foo baz &&
517 git rm bar &&
518 git commit -m "Rename foo, remove bar" &&
520 git checkout B &&
521 git mv bar baz &&
522 git rm foo &&
523 git commit -m "Rename bar, remove foo"
524 ) &&
525 # Testing
527 cd rrdd &&
529 test_expect_code 1 \
530 git merge-tree -z A^0 B^0 >out &&
531 echo >>out &&
532 anonymize_hash out >actual &&
534 q_to_tab <<-\EOF | lf_to_nul >expect &&
535 HASH
536 100644 HASH 2Qbaz
537 100644 HASH 3Qbaz
541 q_to_nul <<-EOF >>expect &&
542 2QbazQbarQCONFLICT (rename/delete)QCONFLICT (rename/delete): bar renamed to baz in B^0, but deleted in A^0.
543 Q2QbazQfooQCONFLICT (rename/delete)QCONFLICT (rename/delete): foo renamed to baz in A^0, but deleted in B^0.
544 Q1QbazQAuto-mergingQAuto-merging baz
545 Q1QbazQCONFLICT (contents)QCONFLICT (add/add): Merge conflict in baz
548 test_cmp expect actual
552 # mod6: chains of rename/rename(1to2) + add/add via colliding renames
553 # Commit O: one, three, five
554 # Commit A: one->two, three->four, five->six
555 # Commit B: one->six, three->two, five->four
556 # Expected: three CONFLICT(rename/rename) messages + three CONFLICT(add/add)
557 # messages; each path in two of the multi-way merged contents
558 # found in two, four, six
560 test_expect_success 'mod6: chains of rename/rename(1to2) and add/add via colliding renames' '
561 # Setup
562 git init mod6 &&
564 cd mod6 &&
565 test_seq 11 19 >one &&
566 test_seq 31 39 >three &&
567 test_seq 51 59 >five &&
568 git add . &&
569 test_tick &&
570 git commit -m "O" &&
572 git branch O &&
573 git branch A &&
574 git branch B &&
576 git checkout A &&
577 test_seq 10 19 >one &&
578 echo 40 >>three &&
579 git add one three &&
580 git mv one two &&
581 git mv three four &&
582 git mv five six &&
583 test_tick &&
584 git commit -m "A" &&
586 git checkout B &&
587 echo 20 >>one &&
588 echo forty >>three &&
589 echo 60 >>five &&
590 git add one three five &&
591 git mv one six &&
592 git mv three two &&
593 git mv five four &&
594 test_tick &&
595 git commit -m "B"
596 ) &&
597 # Testing
599 cd mod6 &&
601 test_expect_code 1 \
602 git merge-tree -z A^0 B^0 >out &&
603 echo >>out &&
606 # First, check that some of the hashes that appear as stage
607 # conflict entries do not appear as individual blobs anywhere
608 # in history.
610 hash1=$(cat out | tr "\0" "\n" | head | grep 2.four | cut -f 2 -d " ") &&
611 hash2=$(cat out | tr "\0" "\n" | head | grep 3.two | cut -f 2 -d " ") &&
612 git rev-list --objects --all >all_blobs &&
613 ! grep $hash1 all_blobs &&
614 ! grep $hash2 all_blobs &&
617 # Now compare anonymized hash output with expectation
619 anonymize_hash out >actual &&
620 q_to_tab <<-\EOF | lf_to_nul >expect &&
621 HASH
622 100644 HASH 1Qfive
623 100644 HASH 2Qfour
624 100644 HASH 3Qfour
625 100644 HASH 1Qone
626 100644 HASH 2Qsix
627 100644 HASH 3Qsix
628 100644 HASH 1Qthree
629 100644 HASH 2Qtwo
630 100644 HASH 3Qtwo
634 q_to_nul <<-EOF >>expect &&
635 3QfiveQsixQfourQCONFLICT (rename/rename)QCONFLICT (rename/rename): five renamed to six in A^0 and to four in B^0.
636 Q1QfourQAuto-mergingQAuto-merging four
637 Q1QfourQCONFLICT (contents)QCONFLICT (add/add): Merge conflict in four
638 Q1QoneQAuto-mergingQAuto-merging one
639 Q3QoneQtwoQsixQCONFLICT (rename/rename)QCONFLICT (rename/rename): one renamed to two in A^0 and to six in B^0.
640 Q1QsixQAuto-mergingQAuto-merging six
641 Q1QsixQCONFLICT (contents)QCONFLICT (add/add): Merge conflict in six
642 Q1QthreeQAuto-mergingQAuto-merging three
643 Q3QthreeQfourQtwoQCONFLICT (rename/rename)QCONFLICT (rename/rename): three renamed to four in A^0 and to two in B^0.
644 Q1QtwoQAuto-mergingQAuto-merging two
645 Q1QtwoQCONFLICT (contents)QCONFLICT (add/add): Merge conflict in two
648 test_cmp expect actual
652 # directory rename + rename/delete + modify/delete + directory/file conflict
653 # Commit O: foo, olddir/{a,b,c}
654 # Commit A: delete foo, rename olddir/ -> newdir/, add newdir/bar/file
655 # Commit B: modify foo & rename foo -> olddir/bar
656 # Expected: CONFLICT(content) for newdir/bar (not olddir/bar or foo)
658 test_expect_success 'directory rename + rename/delete + modify/delete + directory/file conflict' '
659 # Setup
660 git init 4-stacked-conflict &&
662 cd 4-stacked-conflict &&
663 test_write_lines 1 2 3 4 5 >foo &&
664 mkdir olddir &&
665 for i in a b c; do echo $i >olddir/$i || exit 1; done &&
666 git add foo olddir &&
667 git commit -m "original" &&
669 git branch O &&
670 git branch A &&
671 git branch B &&
673 git checkout A &&
674 git rm foo &&
675 git mv olddir newdir &&
676 mkdir newdir/bar &&
677 >newdir/bar/file &&
678 git add newdir/bar/file &&
679 git commit -m "rm foo, olddir/ -> newdir/, + newdir/bar/file" &&
681 git checkout B &&
682 test_write_lines 1 2 3 4 5 6 >foo &&
683 git add foo &&
684 git mv foo olddir/bar &&
685 git commit -m "Modify foo & rename foo -> olddir/bar"
686 ) &&
687 # Testing
689 cd 4-stacked-conflict &&
691 test_expect_code 1 \
692 git merge-tree -z A^0 B^0 >out &&
693 echo >>out &&
694 anonymize_hash out >actual &&
696 q_to_tab <<-\EOF | lf_to_nul >expect &&
697 HASH
698 100644 HASH 1Qnewdir/bar~B^0
699 100644 HASH 3Qnewdir/bar~B^0
702 q_to_nul <<-EOF >>expect &&
703 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.
704 Q2Qnewdir/barQfooQCONFLICT (rename/delete)QCONFLICT (rename/delete): foo renamed to newdir/bar in B^0, but deleted in A^0.
705 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.
706 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.
709 test_cmp expect actual
713 for opt in $(git merge-tree --git-completion-helper-all)
715 if test $opt = "--trivial-merge" || test $opt = "--write-tree"
716 then
717 continue
720 test_expect_success "usage: --trivial-merge is incompatible with $opt" '
721 test_expect_code 128 git merge-tree --trivial-merge $opt side1 side2 side3
723 done
725 test_expect_success 'Just the conflicted files without the messages' '
726 test_expect_code 1 git merge-tree --write-tree --no-messages --name-only side1 side2 >out &&
727 anonymize_hash out >actual &&
729 test_write_lines HASH greeting whatever~side1 >expect &&
731 test_cmp expect actual
734 test_expect_success 'Check conflicted oids and modes without messages' '
735 test_expect_code 1 git merge-tree --write-tree --no-messages side1 side2 >out &&
736 anonymize_hash out >actual &&
738 # Compare the basic output format
739 q_to_tab >expect <<-\EOF &&
740 HASH
741 100644 HASH 1Qgreeting
742 100644 HASH 2Qgreeting
743 100644 HASH 3Qgreeting
744 100644 HASH 1Qwhatever~side1
745 100644 HASH 2Qwhatever~side1
748 test_cmp expect actual &&
750 # Check the actual hashes against the `ls-files -u` output too
751 tail -n +2 out | sed -e s/side1/HEAD/ >actual &&
752 test_cmp conflicted-file-info actual
755 test_expect_success 'NUL terminated conflicted file "lines"' '
756 git checkout -b tweak1 side1 &&
757 test_write_lines zero 1 2 3 4 5 6 >numbers &&
758 git add numbers &&
759 git mv numbers "Αυτά μου φαίνονται κινέζικα" &&
760 git commit -m "Renamed numbers" &&
762 test_expect_code 1 git merge-tree --write-tree -z tweak1 side2 >out &&
763 echo >>out &&
764 anonymize_hash out >actual &&
766 # Expected results:
767 # "greeting" should merge with conflicts
768 # "whatever" has *both* a modify/delete and a file/directory conflict
769 # "Αυτά μου φαίνονται κινέζικα" should have a conflict
770 echo HASH | lf_to_nul >expect &&
772 q_to_tab <<-EOF | lf_to_nul >>expect &&
773 100644 HASH 1Qgreeting
774 100644 HASH 2Qgreeting
775 100644 HASH 3Qgreeting
776 100644 HASH 1Qwhatever~tweak1
777 100644 HASH 2Qwhatever~tweak1
778 100644 HASH 1QΑυτά μου φαίνονται κινέζικα
779 100644 HASH 2QΑυτά μου φαίνονται κινέζικα
780 100644 HASH 3QΑυτά μου φαίνονται κινέζικα
784 q_to_nul <<-EOF >>expect &&
785 1QgreetingQAuto-mergingQAuto-merging greeting
786 Q1QgreetingQCONFLICT (contents)QCONFLICT (content): Merge conflict in greeting
787 Q2Qwhatever~tweak1QwhateverQCONFLICT (file/directory)QCONFLICT (file/directory): directory in the way of whatever from tweak1; moving it to whatever~tweak1 instead.
788 Q1Qwhatever~tweak1QCONFLICT (modify/delete)QCONFLICT (modify/delete): whatever~tweak1 deleted in side2 and modified in tweak1. Version tweak1 of whatever~tweak1 left in tree.
789 Q1QΑυτά μου φαίνονται κινέζικαQAuto-mergingQAuto-merging Αυτά μου φαίνονται κινέζικα
790 Q1QΑυτά μου φαίνονται κινέζικαQCONFLICT (contents)QCONFLICT (content): Merge conflict in Αυτά μου φαίνονται κινέζικα
794 test_cmp expect actual
797 test_expect_success 'error out by default for unrelated histories' '
798 test_expect_code 128 git merge-tree --write-tree side1 unrelated 2>error &&
800 grep "refusing to merge unrelated histories" error
803 test_expect_success 'can override merge of unrelated histories' '
804 git merge-tree --write-tree --allow-unrelated-histories side1 unrelated >tree &&
805 TREE=$(cat tree) &&
807 git rev-parse side1:numbers side1:greeting side1:whatever unrelated:something-else >expect &&
808 git rev-parse $TREE:numbers $TREE:greeting $TREE:whatever $TREE:something-else >actual &&
810 test_cmp expect actual
813 test_expect_success SANITY 'merge-ort fails gracefully in a read-only repository' '
814 git init --bare read-only &&
815 git push read-only side1 side2 side3 &&
816 test_when_finished "chmod -R u+w read-only" &&
817 chmod -R a-w read-only &&
818 test_must_fail git -C read-only merge-tree side1 side3 &&
819 test_must_fail git -C read-only merge-tree side1 side2
822 test_expect_success '--stdin with both a successful and a conflicted merge' '
823 printf "side1 side3\nside1 side2" | git merge-tree --stdin >actual &&
825 git checkout side1^0 &&
826 git merge side3 &&
828 printf "1\0" >expect &&
829 git rev-parse HEAD^{tree} | lf_to_nul >>expect &&
830 printf "\0" >>expect &&
832 git checkout side1^0 &&
833 test_must_fail git merge side2 &&
834 sed s/HEAD/side1/ greeting >tmp &&
835 mv tmp greeting &&
836 git add -u &&
837 git mv whatever~HEAD whatever~side1 &&
839 printf "0\0" >>expect &&
840 git write-tree | lf_to_nul >>expect &&
842 cat <<-EOF | q_to_tab | lf_to_nul >>expect &&
843 100644 $(git rev-parse side1~1:greeting) 1Qgreeting
844 100644 $(git rev-parse side1:greeting) 2Qgreeting
845 100644 $(git rev-parse side2:greeting) 3Qgreeting
846 100644 $(git rev-parse side1~1:whatever) 1Qwhatever~side1
847 100644 $(git rev-parse side1:whatever) 2Qwhatever~side1
850 q_to_nul <<-EOF >>expect &&
851 Q1QgreetingQAuto-mergingQAuto-merging greeting
852 Q1QgreetingQCONFLICT (contents)QCONFLICT (content): Merge conflict in greeting
853 Q1QnumbersQAuto-mergingQAuto-merging numbers
854 Q2Qwhatever~side1QwhateverQCONFLICT (file/directory)QCONFLICT (file/directory): directory in the way of whatever from side1; moving it to whatever~side1 instead.
855 Q1Qwhatever~side1QCONFLICT (modify/delete)QCONFLICT (modify/delete): whatever~side1 deleted in side2 and modified in side1. Version side1 of whatever~side1 left in tree.
858 printf "\0\0" >>expect &&
860 test_cmp expect actual
864 test_expect_success '--merge-base is incompatible with --stdin' '
865 test_must_fail git merge-tree --merge-base=side1 --stdin 2>expect &&
867 grep "^fatal: --merge-base is incompatible with --stdin" expect
870 # specify merge-base as parent of branch2
871 # git merge-tree --write-tree --merge-base=c2 c1 c3
872 # Commit c1: add file1
873 # Commit c2: add file2 after c1
874 # Commit c3: add file3 after c2
875 # Expected: add file3, and file2 does NOT appear
877 test_expect_success 'specify merge-base as parent of branch2' '
878 # Setup
879 test_when_finished "rm -rf base-b2-p" &&
880 git init base-b2-p &&
881 test_commit -C base-b2-p c1 file1 &&
882 test_commit -C base-b2-p c2 file2 &&
883 test_commit -C base-b2-p c3 file3 &&
885 # Testing
886 TREE_OID=$(git -C base-b2-p merge-tree --write-tree --merge-base=c2 c1 c3) &&
888 q_to_tab <<-EOF >expect &&
889 100644 blob $(git -C base-b2-p rev-parse c1:file1)Qfile1
890 100644 blob $(git -C base-b2-p rev-parse c3:file3)Qfile3
893 git -C base-b2-p ls-tree $TREE_OID >actual &&
894 test_cmp expect actual
897 # Since the earlier tests have verified that individual merge-tree calls
898 # are doing the right thing, this test case is only used to verify that
899 # we can also trigger merges via --stdin, and that when we do we get
900 # the same answer as running a bunch of separate merges.
902 test_expect_success 'check the input format when --stdin is passed' '
903 test_when_finished "rm -rf repo" &&
904 git init repo &&
905 test_commit -C repo c1 &&
906 test_commit -C repo c2 &&
907 test_commit -C repo c3 &&
908 printf "c1 c3\nc2 -- c1 c3\nc2 c3" | git -C repo merge-tree --stdin >actual &&
910 printf "1\0" >expect &&
911 git -C repo merge-tree --write-tree -z c1 c3 >>expect &&
912 printf "\0" >>expect &&
914 printf "1\0" >>expect &&
915 git -C repo merge-tree --write-tree -z --merge-base=c2 c1 c3 >>expect &&
916 printf "\0" >>expect &&
918 printf "1\0" >>expect &&
919 git -C repo merge-tree --write-tree -z c2 c3 >>expect &&
920 printf "\0" >>expect &&
922 test_cmp expect actual
925 test_done