The eleventh batch
[git/gitster.git] / t / t4301-merge-tree-write-tree.sh
blob37f1cd7364ce0d4eab374b6a40bb6125dd76f7af
1 #!/bin/sh
3 test_description='git merge-tree --write-tree'
5 TEST_PASSES_SANITIZE_LEAK=true
6 . ./test-lib.sh
8 # This test is ort-specific
9 if test "$GIT_TEST_MERGE_ALGORITHM" != "ort"
10 then
11 skip_all="GIT_TEST_MERGE_ALGORITHM != ort"
12 test_done
15 test_expect_success setup '
16 test_write_lines 1 2 3 4 5 >numbers &&
17 echo hello >greeting &&
18 echo foo >whatever &&
19 git add numbers greeting whatever &&
20 test_tick &&
21 git commit -m initial &&
23 git branch side1 &&
24 git branch side2 &&
25 git branch side3 &&
26 git branch side4 &&
28 git checkout side1 &&
29 test_write_lines 1 2 3 4 5 6 >numbers &&
30 echo hi >greeting &&
31 echo bar >whatever &&
32 git add numbers greeting whatever &&
33 test_tick &&
34 git commit -m modify-stuff &&
36 git checkout side2 &&
37 test_write_lines 0 1 2 3 4 5 >numbers &&
38 echo yo >greeting &&
39 git rm whatever &&
40 mkdir whatever &&
41 >whatever/empty &&
42 git add numbers greeting whatever/empty &&
43 test_tick &&
44 git commit -m other-modifications &&
46 git checkout side3 &&
47 git mv numbers sequence &&
48 test_tick &&
49 git commit -m rename-numbers &&
51 git checkout side4 &&
52 test_write_lines 0 1 2 3 4 5 >numbers &&
53 echo yo >greeting &&
54 git add numbers greeting &&
55 test_tick &&
56 git commit -m other-content-modifications &&
58 git switch --orphan unrelated &&
59 >something-else &&
60 git add something-else &&
61 test_tick &&
62 git commit -m first-commit
65 test_expect_success 'Clean merge' '
66 TREE_OID=$(git merge-tree --write-tree side1 side3) &&
67 q_to_tab <<-EOF >expect &&
68 100644 blob $(git rev-parse side1:greeting)Qgreeting
69 100644 blob $(git rev-parse side1:numbers)Qsequence
70 100644 blob $(git rev-parse side1:whatever)Qwhatever
71 EOF
73 git ls-tree $TREE_OID >actual &&
74 test_cmp expect actual
77 test_expect_success 'Content merge and a few conflicts' '
78 git checkout side1^0 &&
79 test_must_fail git merge side2 &&
80 expected_tree=$(git rev-parse AUTO_MERGE) &&
82 # We will redo the merge, while we are still in a conflicted state!
83 git ls-files -u >conflicted-file-info &&
84 test_when_finished "git reset --hard" &&
86 test_expect_code 1 git merge-tree --write-tree side1 side2 >RESULT &&
87 actual_tree=$(head -n 1 RESULT) &&
89 # Due to differences of e.g. "HEAD" vs "side1", the results will not
90 # exactly match. Dig into individual files.
92 # Numbers should have three-way merged cleanly
93 test_write_lines 0 1 2 3 4 5 6 >expect &&
94 git show ${actual_tree}:numbers >actual &&
95 test_cmp expect actual &&
97 # whatever and whatever~<branch> should have same HASHES
98 git rev-parse ${expected_tree}:whatever ${expected_tree}:whatever~HEAD >expect &&
99 git rev-parse ${actual_tree}:whatever ${actual_tree}:whatever~side1 >actual &&
100 test_cmp expect actual &&
102 # greeting should have a merge conflict
103 git show ${expected_tree}:greeting >tmp &&
104 sed -e s/HEAD/side1/ tmp >expect &&
105 git show ${actual_tree}:greeting >actual &&
106 test_cmp expect actual
109 test_expect_success 'Auto resolve conflicts by "ours" strategy option' '
110 git checkout side1^0 &&
112 # make sure merge conflict exists
113 test_must_fail git merge side4 &&
114 git merge --abort &&
116 git merge -X ours side4 &&
117 git rev-parse HEAD^{tree} >expected &&
119 git merge-tree -X ours side1 side4 >actual &&
121 test_cmp expected actual
124 test_expect_success 'Barf on misspelled option, with exit code other than 0 or 1' '
125 # Mis-spell with single "s" instead of double "s"
126 test_expect_code 129 git merge-tree --write-tree --mesages FOOBAR side1 side2 2>expect &&
128 grep "error: unknown option.*mesages" expect
131 test_expect_success 'Barf on too many arguments' '
132 test_expect_code 129 git merge-tree --write-tree side1 side2 invalid 2>expect &&
134 grep "^usage: git merge-tree" expect
137 anonymize_hash() {
138 sed -e "s/[0-9a-f]\{40,\}/HASH/g" "$@"
141 test_expect_success 'test conflict notices and such' '
142 test_expect_code 1 git merge-tree --write-tree --name-only side1 side2 >out &&
143 anonymize_hash out >actual &&
145 # Expected results:
146 # "greeting" should merge with conflicts
147 # "numbers" should merge cleanly
148 # "whatever" has *both* a modify/delete and a file/directory conflict
149 cat <<-EOF >expect &&
150 HASH
151 greeting
152 whatever~side1
154 Auto-merging greeting
155 CONFLICT (content): Merge conflict in greeting
156 Auto-merging numbers
157 CONFLICT (file/directory): directory in the way of whatever from side1; moving it to whatever~side1 instead.
158 CONFLICT (modify/delete): whatever~side1 deleted in side2 and modified in side1. Version side1 of whatever~side1 left in tree.
161 test_cmp expect actual
164 # directory rename + content conflict
165 # Commit O: foo, olddir/{a,b,c}
166 # Commit A: modify foo, newdir/{a,b,c}
167 # Commit B: modify foo differently & rename foo -> olddir/bar
168 # Expected: CONFLICT(content) for newdir/bar (not olddir/bar or foo)
170 test_expect_success 'directory rename + content conflict' '
171 # Setup
172 git init dir-rename-and-content &&
174 cd dir-rename-and-content &&
175 test_write_lines 1 2 3 4 5 >foo &&
176 mkdir olddir &&
177 for i in a b c; do echo $i >olddir/$i || exit 1; done &&
178 git add foo olddir &&
179 git commit -m "original" &&
181 git branch O &&
182 git branch A &&
183 git branch B &&
185 git checkout A &&
186 test_write_lines 1 2 3 4 5 6 >foo &&
187 git add foo &&
188 git mv olddir newdir &&
189 git commit -m "Modify foo, rename olddir to newdir" &&
191 git checkout B &&
192 test_write_lines 1 2 3 4 5 six >foo &&
193 git add foo &&
194 git mv foo olddir/bar &&
195 git commit -m "Modify foo & rename foo -> olddir/bar"
196 ) &&
197 # Testing
199 cd dir-rename-and-content &&
201 test_expect_code 1 \
202 git merge-tree -z A^0 B^0 >out &&
203 echo >>out &&
204 anonymize_hash out >actual &&
205 q_to_tab <<-\EOF | lf_to_nul >expect &&
206 HASH
207 100644 HASH 1Qnewdir/bar
208 100644 HASH 2Qnewdir/bar
209 100644 HASH 3Qnewdir/bar
212 q_to_nul <<-EOF >>expect &&
213 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.
214 Q1Qnewdir/barQAuto-mergingQAuto-merging newdir/bar
215 Q1Qnewdir/barQCONFLICT (contents)QCONFLICT (content): Merge conflict in newdir/bar
218 test_cmp expect actual
222 # rename/delete + modify/delete handling
223 # Commit O: foo
224 # Commit A: modify foo + rename to bar
225 # Commit B: delete foo
226 # Expected: CONFLICT(rename/delete) + CONFLICT(modify/delete)
228 test_expect_success 'rename/delete handling' '
229 # Setup
230 git init rename-delete &&
232 cd rename-delete &&
233 test_write_lines 1 2 3 4 5 >foo &&
234 git add foo &&
235 git commit -m "original" &&
237 git branch O &&
238 git branch A &&
239 git branch B &&
241 git checkout A &&
242 test_write_lines 1 2 3 4 5 6 >foo &&
243 git add foo &&
244 git mv foo bar &&
245 git commit -m "Modify foo, rename to bar" &&
247 git checkout B &&
248 git rm foo &&
249 git commit -m "remove foo"
250 ) &&
251 # Testing
253 cd rename-delete &&
255 test_expect_code 1 \
256 git merge-tree -z A^0 B^0 >out &&
257 echo >>out &&
258 anonymize_hash out >actual &&
259 q_to_tab <<-\EOF | lf_to_nul >expect &&
260 HASH
261 100644 HASH 1Qbar
262 100644 HASH 2Qbar
265 q_to_nul <<-EOF >>expect &&
266 Q2QbarQfooQCONFLICT (rename/delete)QCONFLICT (rename/delete): foo renamed to bar in A^0, but deleted in B^0.
267 Q1QbarQCONFLICT (modify/delete)QCONFLICT (modify/delete): bar deleted in B^0 and modified in A^0. Version A^0 of bar left in tree.
270 test_cmp expect actual
274 # rename/add handling
275 # Commit O: foo
276 # Commit A: modify foo, add different bar
277 # Commit B: modify & rename foo->bar
278 # Expected: CONFLICT(add/add) [via rename collide] for bar
280 test_expect_success 'rename/add handling' '
281 # Setup
282 git init rename-add &&
284 cd rename-add &&
285 test_write_lines original 1 2 3 4 5 >foo &&
286 git add foo &&
287 git commit -m "original" &&
289 git branch O &&
290 git branch A &&
291 git branch B &&
293 git checkout A &&
294 test_write_lines 1 2 3 4 5 >foo &&
295 echo "different file" >bar &&
296 git add foo bar &&
297 git commit -m "Modify foo, add bar" &&
299 git checkout B &&
300 test_write_lines original 1 2 3 4 5 6 >foo &&
301 git add foo &&
302 git mv foo bar &&
303 git commit -m "rename foo to bar"
304 ) &&
305 # Testing
307 cd rename-add &&
309 test_expect_code 1 \
310 git merge-tree -z A^0 B^0 >out &&
311 echo >>out &&
314 # First, check that the bar that appears at stage 3 does not
315 # correspond to an individual blob anywhere in history
317 hash=$(tr "\0" "\n" <out | head -n 3 | grep 3.bar | cut -f 2 -d " ") &&
318 git rev-list --objects --all >all_blobs &&
319 ! grep $hash all_blobs &&
322 # Second, check anonymized hash output against expectation
324 anonymize_hash out >actual &&
325 q_to_tab <<-\EOF | lf_to_nul >expect &&
326 HASH
327 100644 HASH 2Qbar
328 100644 HASH 3Qbar
331 q_to_nul <<-EOF >>expect &&
332 Q1QbarQAuto-mergingQAuto-merging bar
333 Q1QbarQCONFLICT (contents)QCONFLICT (add/add): Merge conflict in bar
334 Q1QfooQAuto-mergingQAuto-merging foo
337 test_cmp expect actual
341 # rename/add, where add is a mode conflict
342 # Commit O: foo
343 # Commit A: modify foo, add symlink bar
344 # Commit B: modify & rename foo->bar
345 # Expected: CONFLICT(distinct modes) for bar
347 test_expect_success SYMLINKS 'rename/add, where add is a mode conflict' '
348 # Setup
349 git init rename-add-symlink &&
351 cd rename-add-symlink &&
352 test_write_lines original 1 2 3 4 5 >foo &&
353 git add foo &&
354 git commit -m "original" &&
356 git branch O &&
357 git branch A &&
358 git branch B &&
360 git checkout A &&
361 test_write_lines 1 2 3 4 5 >foo &&
362 ln -s foo bar &&
363 git add foo bar &&
364 git commit -m "Modify foo, add symlink bar" &&
366 git checkout B &&
367 test_write_lines original 1 2 3 4 5 6 >foo &&
368 git add foo &&
369 git mv foo bar &&
370 git commit -m "rename foo to bar"
371 ) &&
372 # Testing
374 cd rename-add-symlink &&
376 test_expect_code 1 \
377 git merge-tree -z A^0 B^0 >out &&
378 echo >>out &&
381 # First, check that the bar that appears at stage 3 does not
382 # correspond to an individual blob anywhere in history
384 hash=$(tr "\0" "\n" <out | head -n 3 | grep 3.bar | cut -f 2 -d " ") &&
385 git rev-list --objects --all >all_blobs &&
386 ! grep $hash all_blobs &&
389 # Second, check anonymized hash output against expectation
391 anonymize_hash out >actual &&
392 q_to_tab <<-\EOF | lf_to_nul >expect &&
393 HASH
394 120000 HASH 2Qbar
395 100644 HASH 3Qbar~B^0
398 q_to_nul <<-EOF >>expect &&
399 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.
400 Q1QfooQAuto-mergingQAuto-merging foo
403 test_cmp expect actual
407 # rename/rename(1to2) + content conflict handling
408 # Commit O: foo
409 # Commit A: modify foo & rename to bar
410 # Commit B: modify foo & rename to baz
411 # Expected: CONFLICT(rename/rename)
413 test_expect_success 'rename/rename + content conflict' '
414 # Setup
415 git init rr-plus-content &&
417 cd rr-plus-content &&
418 test_write_lines 1 2 3 4 5 >foo &&
419 git add foo &&
420 git commit -m "original" &&
422 git branch O &&
423 git branch A &&
424 git branch B &&
426 git checkout A &&
427 test_write_lines 1 2 3 4 5 six >foo &&
428 git add foo &&
429 git mv foo bar &&
430 git commit -m "Modify foo + rename to bar" &&
432 git checkout B &&
433 test_write_lines 1 2 3 4 5 6 >foo &&
434 git add foo &&
435 git mv foo baz &&
436 git commit -m "Modify foo + rename to baz"
437 ) &&
438 # Testing
440 cd rr-plus-content &&
442 test_expect_code 1 \
443 git merge-tree -z A^0 B^0 >out &&
444 echo >>out &&
445 anonymize_hash out >actual &&
446 q_to_tab <<-\EOF | lf_to_nul >expect &&
447 HASH
448 100644 HASH 2Qbar
449 100644 HASH 3Qbaz
450 100644 HASH 1Qfoo
453 q_to_nul <<-EOF >>expect &&
454 Q1QfooQAuto-mergingQAuto-merging foo
455 Q3QfooQbarQbazQCONFLICT (rename/rename)QCONFLICT (rename/rename): foo renamed to bar in A^0 and to baz in B^0.
458 test_cmp expect actual
462 # rename/add/delete
463 # Commit O: foo
464 # Commit A: rm foo, add different bar
465 # Commit B: rename foo->bar
466 # Expected: CONFLICT (rename/delete), CONFLICT(add/add) [via rename collide]
467 # for bar
469 test_expect_success 'rename/add/delete conflict' '
470 # Setup
471 git init rad &&
473 cd rad &&
474 echo "original file" >foo &&
475 git add foo &&
476 git commit -m "original" &&
478 git branch O &&
479 git branch A &&
480 git branch B &&
482 git checkout A &&
483 git rm foo &&
484 echo "different file" >bar &&
485 git add bar &&
486 git commit -m "Remove foo, add bar" &&
488 git checkout B &&
489 git mv foo bar &&
490 git commit -m "rename foo to bar"
491 ) &&
492 # Testing
494 cd rad &&
496 test_expect_code 1 \
497 git merge-tree -z B^0 A^0 >out &&
498 echo >>out &&
499 anonymize_hash out >actual &&
501 q_to_tab <<-\EOF | lf_to_nul >expect &&
502 HASH
503 100644 HASH 2Qbar
504 100644 HASH 3Qbar
508 q_to_nul <<-EOF >>expect &&
509 2QbarQfooQCONFLICT (rename/delete)QCONFLICT (rename/delete): foo renamed to bar in B^0, but deleted in A^0.
510 Q1QbarQAuto-mergingQAuto-merging bar
511 Q1QbarQCONFLICT (contents)QCONFLICT (add/add): Merge conflict in bar
514 test_cmp expect actual
518 # rename/rename(2to1)/delete/delete
519 # Commit O: foo, bar
520 # Commit A: rename foo->baz, rm bar
521 # Commit B: rename bar->baz, rm foo
522 # Expected: 2x CONFLICT (rename/delete), CONFLICT (add/add) via colliding
523 # renames for baz
525 test_expect_success 'rename/rename(2to1)/delete/delete conflict' '
526 # Setup
527 git init rrdd &&
529 cd rrdd &&
530 echo foo >foo &&
531 echo bar >bar &&
532 git add foo bar &&
533 git commit -m O &&
535 git branch O &&
536 git branch A &&
537 git branch B &&
539 git checkout A &&
540 git mv foo baz &&
541 git rm bar &&
542 git commit -m "Rename foo, remove bar" &&
544 git checkout B &&
545 git mv bar baz &&
546 git rm foo &&
547 git commit -m "Rename bar, remove foo"
548 ) &&
549 # Testing
551 cd rrdd &&
553 test_expect_code 1 \
554 git merge-tree -z A^0 B^0 >out &&
555 echo >>out &&
556 anonymize_hash out >actual &&
558 q_to_tab <<-\EOF | lf_to_nul >expect &&
559 HASH
560 100644 HASH 2Qbaz
561 100644 HASH 3Qbaz
565 q_to_nul <<-EOF >>expect &&
566 2QbazQbarQCONFLICT (rename/delete)QCONFLICT (rename/delete): bar renamed to baz in B^0, but deleted in A^0.
567 Q2QbazQfooQCONFLICT (rename/delete)QCONFLICT (rename/delete): foo renamed to baz in A^0, but deleted in B^0.
568 Q1QbazQAuto-mergingQAuto-merging baz
569 Q1QbazQCONFLICT (contents)QCONFLICT (add/add): Merge conflict in baz
572 test_cmp expect actual
576 # mod6: chains of rename/rename(1to2) + add/add via colliding renames
577 # Commit O: one, three, five
578 # Commit A: one->two, three->four, five->six
579 # Commit B: one->six, three->two, five->four
580 # Expected: three CONFLICT(rename/rename) messages + three CONFLICT(add/add)
581 # messages; each path in two of the multi-way merged contents
582 # found in two, four, six
584 test_expect_success 'mod6: chains of rename/rename(1to2) and add/add via colliding renames' '
585 # Setup
586 git init mod6 &&
588 cd mod6 &&
589 test_seq 11 19 >one &&
590 test_seq 31 39 >three &&
591 test_seq 51 59 >five &&
592 git add . &&
593 test_tick &&
594 git commit -m "O" &&
596 git branch O &&
597 git branch A &&
598 git branch B &&
600 git checkout A &&
601 test_seq 10 19 >one &&
602 echo 40 >>three &&
603 git add one three &&
604 git mv one two &&
605 git mv three four &&
606 git mv five six &&
607 test_tick &&
608 git commit -m "A" &&
610 git checkout B &&
611 echo 20 >>one &&
612 echo forty >>three &&
613 echo 60 >>five &&
614 git add one three five &&
615 git mv one six &&
616 git mv three two &&
617 git mv five four &&
618 test_tick &&
619 git commit -m "B"
620 ) &&
621 # Testing
623 cd mod6 &&
625 test_expect_code 1 \
626 git merge-tree -z A^0 B^0 >out &&
627 echo >>out &&
630 # First, check that some of the hashes that appear as stage
631 # conflict entries do not appear as individual blobs anywhere
632 # in history.
634 hash1=$(tr "\0" "\n" <out | head | grep 2.four | cut -f 2 -d " ") &&
635 hash2=$(tr "\0" "\n" <out | head | grep 3.two | cut -f 2 -d " ") &&
636 git rev-list --objects --all >all_blobs &&
637 ! grep $hash1 all_blobs &&
638 ! grep $hash2 all_blobs &&
641 # Now compare anonymized hash output with expectation
643 anonymize_hash out >actual &&
644 q_to_tab <<-\EOF | lf_to_nul >expect &&
645 HASH
646 100644 HASH 1Qfive
647 100644 HASH 2Qfour
648 100644 HASH 3Qfour
649 100644 HASH 1Qone
650 100644 HASH 2Qsix
651 100644 HASH 3Qsix
652 100644 HASH 1Qthree
653 100644 HASH 2Qtwo
654 100644 HASH 3Qtwo
658 q_to_nul <<-EOF >>expect &&
659 3QfiveQsixQfourQCONFLICT (rename/rename)QCONFLICT (rename/rename): five renamed to six in A^0 and to four in B^0.
660 Q1QfourQAuto-mergingQAuto-merging four
661 Q1QfourQCONFLICT (contents)QCONFLICT (add/add): Merge conflict in four
662 Q1QoneQAuto-mergingQAuto-merging one
663 Q3QoneQtwoQsixQCONFLICT (rename/rename)QCONFLICT (rename/rename): one renamed to two in A^0 and to six in B^0.
664 Q1QsixQAuto-mergingQAuto-merging six
665 Q1QsixQCONFLICT (contents)QCONFLICT (add/add): Merge conflict in six
666 Q1QthreeQAuto-mergingQAuto-merging three
667 Q3QthreeQfourQtwoQCONFLICT (rename/rename)QCONFLICT (rename/rename): three renamed to four in A^0 and to two in B^0.
668 Q1QtwoQAuto-mergingQAuto-merging two
669 Q1QtwoQCONFLICT (contents)QCONFLICT (add/add): Merge conflict in two
672 test_cmp expect actual
676 # directory rename + rename/delete + modify/delete + directory/file conflict
677 # Commit O: foo, olddir/{a,b,c}
678 # Commit A: delete foo, rename olddir/ -> newdir/, add newdir/bar/file
679 # Commit B: modify foo & rename foo -> olddir/bar
680 # Expected: CONFLICT(content) for newdir/bar (not olddir/bar or foo)
682 test_expect_success 'directory rename + rename/delete + modify/delete + directory/file conflict' '
683 # Setup
684 git init 4-stacked-conflict &&
686 cd 4-stacked-conflict &&
687 test_write_lines 1 2 3 4 5 >foo &&
688 mkdir olddir &&
689 for i in a b c; do echo $i >olddir/$i || exit 1; done &&
690 git add foo olddir &&
691 git commit -m "original" &&
693 git branch O &&
694 git branch A &&
695 git branch B &&
697 git checkout A &&
698 git rm foo &&
699 git mv olddir newdir &&
700 mkdir newdir/bar &&
701 >newdir/bar/file &&
702 git add newdir/bar/file &&
703 git commit -m "rm foo, olddir/ -> newdir/, + newdir/bar/file" &&
705 git checkout B &&
706 test_write_lines 1 2 3 4 5 6 >foo &&
707 git add foo &&
708 git mv foo olddir/bar &&
709 git commit -m "Modify foo & rename foo -> olddir/bar"
710 ) &&
711 # Testing
713 cd 4-stacked-conflict &&
715 test_expect_code 1 \
716 git merge-tree -z A^0 B^0 >out &&
717 echo >>out &&
718 anonymize_hash out >actual &&
720 q_to_tab <<-\EOF | lf_to_nul >expect &&
721 HASH
722 100644 HASH 1Qnewdir/bar~B^0
723 100644 HASH 3Qnewdir/bar~B^0
726 q_to_nul <<-EOF >>expect &&
727 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.
728 Q2Qnewdir/barQfooQCONFLICT (rename/delete)QCONFLICT (rename/delete): foo renamed to newdir/bar in B^0, but deleted in A^0.
729 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.
730 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.
733 test_cmp expect actual
737 for opt in $(git merge-tree --git-completion-helper-all)
739 if test $opt = "--trivial-merge" || test $opt = "--write-tree"
740 then
741 continue
744 test_expect_success "usage: --trivial-merge is incompatible with $opt" '
745 test_expect_code 128 git merge-tree --trivial-merge $opt side1 side2 side3
747 done
749 test_expect_success 'Just the conflicted files without the messages' '
750 test_expect_code 1 git merge-tree --write-tree --no-messages --name-only side1 side2 >out &&
751 anonymize_hash out >actual &&
753 test_write_lines HASH greeting whatever~side1 >expect &&
755 test_cmp expect actual
758 test_expect_success 'Check conflicted oids and modes without messages' '
759 test_expect_code 1 git merge-tree --write-tree --no-messages side1 side2 >out &&
760 anonymize_hash out >actual &&
762 # Compare the basic output format
763 q_to_tab >expect <<-\EOF &&
764 HASH
765 100644 HASH 1Qgreeting
766 100644 HASH 2Qgreeting
767 100644 HASH 3Qgreeting
768 100644 HASH 1Qwhatever~side1
769 100644 HASH 2Qwhatever~side1
772 test_cmp expect actual &&
774 # Check the actual hashes against the `ls-files -u` output too
775 tail -n +2 out | sed -e s/side1/HEAD/ >actual &&
776 test_cmp conflicted-file-info actual
779 test_expect_success 'NUL terminated conflicted file "lines"' '
780 git checkout -b tweak1 side1 &&
781 test_write_lines zero 1 2 3 4 5 6 >numbers &&
782 git add numbers &&
783 git mv numbers "Αυτά μου φαίνονται κινέζικα" &&
784 git commit -m "Renamed numbers" &&
786 test_expect_code 1 git merge-tree --write-tree -z tweak1 side2 >out &&
787 echo >>out &&
788 anonymize_hash out >actual &&
790 # Expected results:
791 # "greeting" should merge with conflicts
792 # "whatever" has *both* a modify/delete and a file/directory conflict
793 # "Αυτά μου φαίνονται κινέζικα" should have a conflict
794 echo HASH | lf_to_nul >expect &&
796 q_to_tab <<-EOF | lf_to_nul >>expect &&
797 100644 HASH 1Qgreeting
798 100644 HASH 2Qgreeting
799 100644 HASH 3Qgreeting
800 100644 HASH 1Qwhatever~tweak1
801 100644 HASH 2Qwhatever~tweak1
802 100644 HASH 1QΑυτά μου φαίνονται κινέζικα
803 100644 HASH 2QΑυτά μου φαίνονται κινέζικα
804 100644 HASH 3QΑυτά μου φαίνονται κινέζικα
808 q_to_nul <<-EOF >>expect &&
809 1QgreetingQAuto-mergingQAuto-merging greeting
810 Q1QgreetingQCONFLICT (contents)QCONFLICT (content): Merge conflict in greeting
811 Q2Qwhatever~tweak1QwhateverQCONFLICT (file/directory)QCONFLICT (file/directory): directory in the way of whatever from tweak1; moving it to whatever~tweak1 instead.
812 Q1Qwhatever~tweak1QCONFLICT (modify/delete)QCONFLICT (modify/delete): whatever~tweak1 deleted in side2 and modified in tweak1. Version tweak1 of whatever~tweak1 left in tree.
813 Q1QΑυτά μου φαίνονται κινέζικαQAuto-mergingQAuto-merging Αυτά μου φαίνονται κινέζικα
814 Q1QΑυτά μου φαίνονται κινέζικαQCONFLICT (contents)QCONFLICT (content): Merge conflict in Αυτά μου φαίνονται κινέζικα
818 test_cmp expect actual
821 test_expect_success 'error out by default for unrelated histories' '
822 test_expect_code 128 git merge-tree --write-tree side1 unrelated 2>error &&
824 grep "refusing to merge unrelated histories" error
827 test_expect_success 'can override merge of unrelated histories' '
828 git merge-tree --write-tree --allow-unrelated-histories side1 unrelated >tree &&
829 TREE=$(cat tree) &&
831 git rev-parse side1:numbers side1:greeting side1:whatever unrelated:something-else >expect &&
832 git rev-parse $TREE:numbers $TREE:greeting $TREE:whatever $TREE:something-else >actual &&
834 test_cmp expect actual
837 test_expect_success SANITY 'merge-ort fails gracefully in a read-only repository' '
838 git init --bare read-only &&
839 git push read-only side1 side2 side3 &&
840 test_when_finished "chmod -R u+w read-only" &&
841 chmod -R a-w read-only &&
842 test_must_fail git -C read-only merge-tree side1 side3 &&
843 test_must_fail git -C read-only merge-tree side1 side2
846 test_expect_success '--stdin with both a successful and a conflicted merge' '
847 printf "side1 side3\nside1 side2" | git merge-tree --stdin >actual &&
849 git checkout side1^0 &&
850 git merge side3 &&
852 printf "1\0" >expect &&
853 git rev-parse HEAD^{tree} | lf_to_nul >>expect &&
854 printf "\0" >>expect &&
856 git checkout side1^0 &&
857 test_must_fail git merge side2 &&
858 sed s/HEAD/side1/ greeting >tmp &&
859 mv tmp greeting &&
860 git add -u &&
861 git mv whatever~HEAD whatever~side1 &&
863 printf "0\0" >>expect &&
864 git write-tree | lf_to_nul >>expect &&
866 cat <<-EOF | q_to_tab | lf_to_nul >>expect &&
867 100644 $(git rev-parse side1~1:greeting) 1Qgreeting
868 100644 $(git rev-parse side1:greeting) 2Qgreeting
869 100644 $(git rev-parse side2:greeting) 3Qgreeting
870 100644 $(git rev-parse side1~1:whatever) 1Qwhatever~side1
871 100644 $(git rev-parse side1:whatever) 2Qwhatever~side1
874 q_to_nul <<-EOF >>expect &&
875 Q1QgreetingQAuto-mergingQAuto-merging greeting
876 Q1QgreetingQCONFLICT (contents)QCONFLICT (content): Merge conflict in greeting
877 Q1QnumbersQAuto-mergingQAuto-merging numbers
878 Q2Qwhatever~side1QwhateverQCONFLICT (file/directory)QCONFLICT (file/directory): directory in the way of whatever from side1; moving it to whatever~side1 instead.
879 Q1Qwhatever~side1QCONFLICT (modify/delete)QCONFLICT (modify/delete): whatever~side1 deleted in side2 and modified in side1. Version side1 of whatever~side1 left in tree.
882 printf "\0\0" >>expect &&
884 test_cmp expect actual
888 test_expect_success '--merge-base is incompatible with --stdin' '
889 test_must_fail git merge-tree --merge-base=side1 --stdin 2>expect &&
891 grep "^fatal: .*merge-base.*stdin.* cannot be used together" expect
894 # specify merge-base as parent of branch2
895 # git merge-tree --write-tree --merge-base=c2 c1 c3
896 # Commit c1: add file1
897 # Commit c2: add file2 after c1
898 # Commit c3: add file3 after c2
899 # Expected: add file3, and file2 does NOT appear
901 test_expect_success 'specify merge-base as parent of branch2' '
902 # Setup
903 test_when_finished "rm -rf base-b2-p" &&
904 git init base-b2-p &&
905 test_commit -C base-b2-p c1 file1 &&
906 test_commit -C base-b2-p c2 file2 &&
907 test_commit -C base-b2-p c3 file3 &&
909 # Testing
910 TREE_OID=$(git -C base-b2-p merge-tree --write-tree --merge-base=c2 c1 c3) &&
912 q_to_tab <<-EOF >expect &&
913 100644 blob $(git -C base-b2-p rev-parse c1:file1)Qfile1
914 100644 blob $(git -C base-b2-p rev-parse c3:file3)Qfile3
917 git -C base-b2-p ls-tree $TREE_OID >actual &&
918 test_cmp expect actual
921 # Since the earlier tests have verified that individual merge-tree calls
922 # are doing the right thing, this test case is only used to verify that
923 # we can also trigger merges via --stdin, and that when we do we get
924 # the same answer as running a bunch of separate merges.
926 test_expect_success 'check the input format when --stdin is passed' '
927 test_when_finished "rm -rf repo" &&
928 git init repo &&
929 test_commit -C repo c1 &&
930 test_commit -C repo c2 &&
931 test_commit -C repo c3 &&
932 printf "c1 c3\nc2 -- c1 c3\nc2 c3" | git -C repo merge-tree --stdin >actual &&
934 printf "1\0" >expect &&
935 git -C repo merge-tree --write-tree -z c1 c3 >>expect &&
936 printf "\0" >>expect &&
938 printf "1\0" >>expect &&
939 git -C repo merge-tree --write-tree -z --merge-base=c2 c1 c3 >>expect &&
940 printf "\0" >>expect &&
942 printf "1\0" >>expect &&
943 git -C repo merge-tree --write-tree -z c2 c3 >>expect &&
944 printf "\0" >>expect &&
946 test_cmp expect actual
949 test_expect_success '--merge-base with tree OIDs' '
950 git merge-tree --merge-base=side1^ side1 side3 >with-commits &&
951 git merge-tree --merge-base=side1^^{tree} side1^{tree} side3^{tree} >with-trees &&
952 test_cmp with-commits with-trees
955 test_expect_success 'error out on missing tree objects' '
956 git init --bare missing-tree.git &&
957 git rev-list side3 >list &&
958 git rev-parse side3^: >>list &&
959 git pack-objects missing-tree.git/objects/pack/side3-tree-is-missing <list &&
960 side3=$(git rev-parse side3) &&
961 test_must_fail git --git-dir=missing-tree.git merge-tree $side3^ $side3 >actual 2>err &&
962 test_grep "Could not read $(git rev-parse $side3:)" err &&
963 test_must_be_empty actual
966 test_expect_success 'error out on missing blob objects' '
967 echo 1 | git hash-object -w --stdin >blob1 &&
968 echo 2 | git hash-object -w --stdin >blob2 &&
969 echo 3 | git hash-object -w --stdin >blob3 &&
970 printf "100644 blob $(cat blob1)\tblob\n" | git mktree >tree1 &&
971 printf "100644 blob $(cat blob2)\tblob\n" | git mktree >tree2 &&
972 printf "100644 blob $(cat blob3)\tblob\n" | git mktree >tree3 &&
973 git init --bare missing-blob.git &&
974 cat blob1 blob3 tree1 tree2 tree3 |
975 git pack-objects missing-blob.git/objects/pack/side1-whatever-is-missing &&
976 test_must_fail git --git-dir=missing-blob.git >actual 2>err \
977 merge-tree --merge-base=$(cat tree1) $(cat tree2) $(cat tree3) &&
978 test_grep "unable to read blob object $(cat blob2)" err &&
979 test_must_be_empty actual
982 test_expect_success 'error out on missing commits as well' '
983 git init --bare missing-commit.git &&
984 git rev-list --objects side1 side3 >list-including-initial &&
985 grep -v ^$(git rev-parse side1^) <list-including-initial >list &&
986 git pack-objects missing-commit.git/objects/pack/missing-initial <list &&
987 side1=$(git rev-parse side1) &&
988 side3=$(git rev-parse side3) &&
989 test_must_fail git --git-dir=missing-commit.git \
990 merge-tree --allow-unrelated-histories $side1 $side3 >actual &&
991 test_must_be_empty actual
994 test_done