]> git.ipfire.org Git - thirdparty/git.git/blame - t/t4301-merge-tree-write-tree.sh
The third batch
[thirdparty/git.git] / t / t4301-merge-tree-write-tree.sh
CommitLineData
1f0c3a29
EN
1#!/bin/sh
2
3test_description='git merge-tree --write-tree'
4
5. ./test-lib.sh
6
7# This test is ort-specific
8if test "$GIT_TEST_MERGE_ALGORITHM" != "ort"
9then
10 skip_all="GIT_TEST_MERGE_ALGORITHM != ort"
11 test_done
12fi
13
14test_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 &&
21
22 git branch side1 &&
23 git branch side2 &&
24 git branch side3 &&
6a4c9e7b 25 git branch side4 &&
1f0c3a29
EN
26
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 &&
34
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 &&
44
45 git checkout side3 &&
46 git mv numbers sequence &&
47 test_tick &&
7976721d
EN
48 git commit -m rename-numbers &&
49
6a4c9e7b
TY
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 &&
56
7976721d
EN
57 git switch --orphan unrelated &&
58 >something-else &&
59 git add something-else &&
60 test_tick &&
61 git commit -m first-commit
1f0c3a29
EN
62'
63
64test_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
71
72 git ls-tree $TREE_OID >actual &&
73 test_cmp expect actual
74'
75
76test_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) &&
80
81 # We will redo the merge, while we are still in a conflicted state!
b520bc6c 82 git ls-files -u >conflicted-file-info &&
1f0c3a29
EN
83 test_when_finished "git reset --hard" &&
84
85 test_expect_code 1 git merge-tree --write-tree side1 side2 >RESULT &&
86 actual_tree=$(head -n 1 RESULT) &&
87
88 # Due to differences of e.g. "HEAD" vs "side1", the results will not
89 # exactly match. Dig into individual files.
90
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 &&
95
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 &&
100
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
106'
107
6a4c9e7b
TY
108test_expect_success 'Auto resolve conflicts by "ours" strategy option' '
109 git checkout side1^0 &&
110
111 # make sure merge conflict exists
112 test_must_fail git merge side4 &&
113 git merge --abort &&
114
115 git merge -X ours side4 &&
116 git rev-parse HEAD^{tree} >expected &&
117
118 git merge-tree -X ours side1 side4 >actual &&
119
120 test_cmp expected actual
121'
122
1f0c3a29
EN
123test_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 &&
126
127 grep "error: unknown option.*mesages" expect
128'
129
130test_expect_success 'Barf on too many arguments' '
131 test_expect_code 129 git merge-tree --write-tree side1 side2 invalid 2>expect &&
132
133 grep "^usage: git merge-tree" expect
134'
135
a1a78119
EN
136anonymize_hash() {
137 sed -e "s/[0-9a-f]\{40,\}/HASH/g" "$@"
138}
139
140test_expect_success 'test conflict notices and such' '
b520bc6c 141 test_expect_code 1 git merge-tree --write-tree --name-only side1 side2 >out &&
a1a78119
EN
142 anonymize_hash out >actual &&
143
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
7fa33388
EN
150 greeting
151 whatever~side1
a1a78119
EN
152
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.
158 EOF
159
160 test_cmp expect actual
161'
162
3c4dbf55
EN
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
b39a8418 167# Expected: CONFLICT(content) for newdir/bar (not olddir/bar or foo)
3c4dbf55
EN
168
169test_expect_success 'directory rename + content conflict' '
170 # Setup
171 git init dir-rename-and-content &&
172 (
173 cd dir-rename-and-content &&
174 test_write_lines 1 2 3 4 5 >foo &&
175 mkdir olddir &&
87ed9716 176 for i in a b c; do echo $i >olddir/$i || exit 1; done &&
3c4dbf55
EN
177 git add foo olddir &&
178 git commit -m "original" &&
179
180 git branch O &&
181 git branch A &&
182 git branch B &&
183
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" &&
189
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
197 (
198 cd dir-rename-and-content &&
199
200 test_expect_code 1 \
201 git merge-tree -z A^0 B^0 >out &&
3871bdb7 202 echo >>out &&
3c4dbf55
EN
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
209 EOF
210
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
215 Q
216 EOF
217 test_cmp expect actual
218 )
219'
220
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)
226
227test_expect_success 'rename/delete handling' '
228 # Setup
229 git init rename-delete &&
230 (
231 cd rename-delete &&
232 test_write_lines 1 2 3 4 5 >foo &&
233 git add foo &&
234 git commit -m "original" &&
235
236 git branch O &&
237 git branch A &&
238 git branch B &&
239
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" &&
245
246 git checkout B &&
247 git rm foo &&
248 git commit -m "remove foo"
249 ) &&
250 # Testing
251 (
252 cd rename-delete &&
253
254 test_expect_code 1 \
255 git merge-tree -z A^0 B^0 >out &&
3871bdb7 256 echo >>out &&
3c4dbf55
EN
257 anonymize_hash out >actual &&
258 q_to_tab <<-\EOF | lf_to_nul >expect &&
259 HASH
260 100644 HASH 1Qbar
261 100644 HASH 2Qbar
262 EOF
263
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.
267 Q
268 EOF
269 test_cmp expect actual
270 )
271'
272
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
278
279test_expect_success 'rename/add handling' '
280 # Setup
281 git init rename-add &&
282 (
283 cd rename-add &&
284 test_write_lines original 1 2 3 4 5 >foo &&
285 git add foo &&
286 git commit -m "original" &&
287
288 git branch O &&
289 git branch A &&
290 git branch B &&
291
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" &&
297
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
305 (
306 cd rename-add &&
307
308 test_expect_code 1 \
309 git merge-tree -z A^0 B^0 >out &&
3871bdb7 310 echo >>out &&
3c4dbf55
EN
311
312 #
313 # First, check that the bar that appears at stage 3 does not
314 # correspond to an individual blob anywhere in history
315 #
237ce762 316 hash=$(tr "\0" "\n" <out | head -n 3 | grep 3.bar | cut -f 2 -d " ") &&
3c4dbf55
EN
317 git rev-list --objects --all >all_blobs &&
318 ! grep $hash all_blobs &&
319
320 #
321 # Second, check anonymized hash output against expectation
322 #
323 anonymize_hash out >actual &&
324 q_to_tab <<-\EOF | lf_to_nul >expect &&
325 HASH
326 100644 HASH 2Qbar
327 100644 HASH 3Qbar
328 EOF
329
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
334 Q
335 EOF
336 test_cmp expect actual
337 )
338'
339
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
345
346test_expect_success SYMLINKS 'rename/add, where add is a mode conflict' '
347 # Setup
348 git init rename-add-symlink &&
349 (
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" &&
354
355 git branch O &&
356 git branch A &&
357 git branch B &&
358
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" &&
364
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
372 (
373 cd rename-add-symlink &&
374
375 test_expect_code 1 \
376 git merge-tree -z A^0 B^0 >out &&
3871bdb7 377 echo >>out &&
3c4dbf55
EN
378
379 #
380 # First, check that the bar that appears at stage 3 does not
381 # correspond to an individual blob anywhere in history
382 #
237ce762 383 hash=$(tr "\0" "\n" <out | head -n 3 | grep 3.bar | cut -f 2 -d " ") &&
3c4dbf55
EN
384 git rev-list --objects --all >all_blobs &&
385 ! grep $hash all_blobs &&
386
387 #
388 # Second, check anonymized hash output against expectation
389 #
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
395 EOF
396
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
400 Q
401 EOF
402 test_cmp expect actual
403 )
404'
405
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)
411
412test_expect_success 'rename/rename + content conflict' '
413 # Setup
414 git init rr-plus-content &&
415 (
416 cd rr-plus-content &&
417 test_write_lines 1 2 3 4 5 >foo &&
418 git add foo &&
419 git commit -m "original" &&
420
421 git branch O &&
422 git branch A &&
423 git branch B &&
424
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" &&
430
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
438 (
439 cd rr-plus-content &&
440
441 test_expect_code 1 \
442 git merge-tree -z A^0 B^0 >out &&
3871bdb7 443 echo >>out &&
3c4dbf55
EN
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
450 EOF
451
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.
455 Q
456 EOF
457 test_cmp expect actual
458 )
459'
460
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
467
468test_expect_success 'rename/add/delete conflict' '
469 # Setup
470 git init rad &&
471 (
472 cd rad &&
473 echo "original file" >foo &&
474 git add foo &&
475 git commit -m "original" &&
476
477 git branch O &&
478 git branch A &&
479 git branch B &&
480
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" &&
486
487 git checkout B &&
488 git mv foo bar &&
489 git commit -m "rename foo to bar"
490 ) &&
491 # Testing
492 (
493 cd rad &&
494
495 test_expect_code 1 \
496 git merge-tree -z B^0 A^0 >out &&
3871bdb7 497 echo >>out &&
3c4dbf55
EN
498 anonymize_hash out >actual &&
499
500 q_to_tab <<-\EOF | lf_to_nul >expect &&
501 HASH
502 100644 HASH 2Qbar
503 100644 HASH 3Qbar
504
505 EOF
506
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
511 Q
512 EOF
513 test_cmp expect actual
514 )
515'
516
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
523
524test_expect_success 'rename/rename(2to1)/delete/delete conflict' '
525 # Setup
526 git init rrdd &&
527 (
528 cd rrdd &&
529 echo foo >foo &&
530 echo bar >bar &&
531 git add foo bar &&
532 git commit -m O &&
533
534 git branch O &&
535 git branch A &&
536 git branch B &&
537
538 git checkout A &&
539 git mv foo baz &&
540 git rm bar &&
541 git commit -m "Rename foo, remove bar" &&
542
543 git checkout B &&
544 git mv bar baz &&
545 git rm foo &&
546 git commit -m "Rename bar, remove foo"
547 ) &&
548 # Testing
549 (
550 cd rrdd &&
551
552 test_expect_code 1 \
553 git merge-tree -z A^0 B^0 >out &&
3871bdb7 554 echo >>out &&
3c4dbf55
EN
555 anonymize_hash out >actual &&
556
557 q_to_tab <<-\EOF | lf_to_nul >expect &&
558 HASH
559 100644 HASH 2Qbaz
560 100644 HASH 3Qbaz
561
562 EOF
563
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
569 Q
570 EOF
571 test_cmp expect actual
572 )
573'
574
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
582
583test_expect_success 'mod6: chains of rename/rename(1to2) and add/add via colliding renames' '
584 # Setup
585 git init mod6 &&
586 (
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" &&
594
595 git branch O &&
596 git branch A &&
597 git branch B &&
598
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" &&
608
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
621 (
622 cd mod6 &&
623
624 test_expect_code 1 \
625 git merge-tree -z A^0 B^0 >out &&
3871bdb7 626 echo >>out &&
3c4dbf55
EN
627
628 #
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.
632 #
237ce762
BB
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 " ") &&
3c4dbf55
EN
635 git rev-list --objects --all >all_blobs &&
636 ! grep $hash1 all_blobs &&
637 ! grep $hash2 all_blobs &&
638
639 #
640 # Now compare anonymized hash output with expectation
641 #
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
654
655 EOF
656
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
669 Q
670 EOF
671 test_cmp expect actual
672 )
673'
674
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
b39a8418 679# Expected: CONFLICT(content) for newdir/bar (not olddir/bar or foo)
3c4dbf55
EN
680
681test_expect_success 'directory rename + rename/delete + modify/delete + directory/file conflict' '
682 # Setup
683 git init 4-stacked-conflict &&
684 (
685 cd 4-stacked-conflict &&
686 test_write_lines 1 2 3 4 5 >foo &&
687 mkdir olddir &&
87ed9716 688 for i in a b c; do echo $i >olddir/$i || exit 1; done &&
3c4dbf55
EN
689 git add foo olddir &&
690 git commit -m "original" &&
691
692 git branch O &&
693 git branch A &&
694 git branch B &&
695
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" &&
703
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
711 (
712 cd 4-stacked-conflict &&
713
714 test_expect_code 1 \
715 git merge-tree -z A^0 B^0 >out &&
3871bdb7 716 echo >>out &&
3c4dbf55
EN
717 anonymize_hash out >actual &&
718
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
723 EOF
724
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.
730 Q
731 EOF
732 test_cmp expect actual
733 )
734'
735
a1a78119
EN
736for opt in $(git merge-tree --git-completion-helper-all)
737do
738 if test $opt = "--trivial-merge" || test $opt = "--write-tree"
739 then
740 continue
741 fi
742
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
745 '
746done
747
7fa33388 748test_expect_success 'Just the conflicted files without the messages' '
b520bc6c 749 test_expect_code 1 git merge-tree --write-tree --no-messages --name-only side1 side2 >out &&
7fa33388
EN
750 anonymize_hash out >actual &&
751
752 test_write_lines HASH greeting whatever~side1 >expect &&
753
754 test_cmp expect actual
755'
756
b520bc6c
EN
757test_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 &&
760
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
769 EOF
770
771 test_cmp expect actual &&
772
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
776'
777
7c48b278
EN
778test_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" &&
784
785 test_expect_code 1 git merge-tree --write-tree -z tweak1 side2 >out &&
3871bdb7 786 echo >>out &&
7c48b278 787 anonymize_hash out >actual &&
7c48b278
EN
788
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 &&
794
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Αυτά μου φαίνονται κινέζικα
804
805 EOF
806
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 Αυτά μου φαίνονται κινέζικα
814 Q
815 EOF
816
817 test_cmp expect actual
818'
819
7976721d
EN
820test_expect_success 'error out by default for unrelated histories' '
821 test_expect_code 128 git merge-tree --write-tree side1 unrelated 2>error &&
822
823 grep "refusing to merge unrelated histories" error
824'
825
826test_expect_success 'can override merge of unrelated histories' '
827 git merge-tree --write-tree --allow-unrelated-histories side1 unrelated >tree &&
828 TREE=$(cat tree) &&
829
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 &&
832
833 test_cmp expect actual
834'
835
0b55d930
JS
836test_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
843'
844
ec1edbcb
EN
845test_expect_success '--stdin with both a successful and a conflicted merge' '
846 printf "side1 side3\nside1 side2" | git merge-tree --stdin >actual &&
847
848 git checkout side1^0 &&
849 git merge side3 &&
850
851 printf "1\0" >expect &&
852 git rev-parse HEAD^{tree} | lf_to_nul >>expect &&
853 printf "\0" >>expect &&
854
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 &&
861
862 printf "0\0" >>expect &&
863 git write-tree | lf_to_nul >>expect &&
864
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
871 EOF
872
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.
879 EOF
880
881 printf "\0\0" >>expect &&
882
883 test_cmp expect actual
884'
885
501e3bab
KZ
886
887test_expect_success '--merge-base is incompatible with --stdin' '
888 test_must_fail git merge-tree --merge-base=side1 --stdin 2>expect &&
889
7854bf49 890 grep "^fatal: .*merge-base.*stdin.* cannot be used together" expect
501e3bab
KZ
891'
892
66265a69
KZ
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
899
900test_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 &&
907
908 # Testing
909 TREE_OID=$(git -C base-b2-p merge-tree --write-tree --merge-base=c2 c1 c3) &&
910
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
914 EOF
915
916 git -C base-b2-p ls-tree $TREE_OID >actual &&
917 test_cmp expect actual
918'
919
501e3bab
KZ
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.
924
925test_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 &&
932
933 printf "1\0" >expect &&
934 git -C repo merge-tree --write-tree -z c1 c3 >>expect &&
935 printf "\0" >>expect &&
936
937 printf "1\0" >>expect &&
938 git -C repo merge-tree --write-tree -z --merge-base=c2 c1 c3 >>expect &&
939 printf "\0" >>expect &&
940
941 printf "1\0" >>expect &&
942 git -C repo merge-tree --write-tree -z c2 c3 >>expect &&
943 printf "\0" >>expect &&
944
945 test_cmp expect actual
946'
947
5f43cf5b
JS
948test_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
952'
953
d4bf1930
JS
954test_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
963'
964
98c6d16d
JS
965test_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
979'
980
76e2a099
JS
981test_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
991'
992
1f0c3a29 993test_done