rerere: add documentation for conflict normalization
[git.git] / t / t6046-merge-skip-unneeded-updates.sh
blobfcefffcaece290f4070aceb9ddf6b5579447f104
1 #!/bin/sh
3 test_description="merge cases"
5 # The setup for all of them, pictorially, is:
7 # A
8 # o
9 # / \
10 # O o ?
11 # \ /
12 # o
13 # B
15 # To help make it easier to follow the flow of tests, they have been
16 # divided into sections and each test will start with a quick explanation
17 # of what commits O, A, and B contain.
19 # Notation:
20 # z/{b,c} means files z/b and z/c both exist
21 # x/d_1 means file x/d exists with content d1. (Purpose of the
22 # underscore notation is to differentiate different
23 # files that might be renamed into each other's paths.)
25 . ./test-lib.sh
28 ###########################################################################
29 # SECTION 1: Cases involving no renames (one side has subset of changes of
30 # the other side)
31 ###########################################################################
33 # Testcase 1a, Changes on A, subset of changes on B
34 # Commit O: b_1
35 # Commit A: b_2
36 # Commit B: b_3
37 # Expected: b_2
39 test_expect_success '1a-setup: Modify(A)/Modify(B), change on B subset of A' '
40 test_create_repo 1a &&
42 cd 1a &&
44 test_write_lines 1 2 3 4 5 6 7 8 9 10 >b &&
45 git add b &&
46 test_tick &&
47 git commit -m "O" &&
49 git branch O &&
50 git branch A &&
51 git branch B &&
53 git checkout A &&
54 test_write_lines 1 2 3 4 5 5.5 6 7 8 9 10 10.5 >b &&
55 git add b &&
56 test_tick &&
57 git commit -m "A" &&
59 git checkout B &&
60 test_write_lines 1 2 3 4 5 5.5 6 7 8 9 10 >b &&
61 git add b &&
62 test_tick &&
63 git commit -m "B"
67 test_expect_success '1a-check-L: Modify(A)/Modify(B), change on B subset of A' '
68 test_when_finished "git -C 1a reset --hard" &&
69 test_when_finished "git -C 1a clean -fd" &&
71 cd 1a &&
73 git checkout A^0 &&
75 test-tool chmtime =31337 b &&
76 test-tool chmtime -v +0 b >expected-mtime &&
78 GIT_MERGE_VERBOSITY=3 git merge -s recursive B^0 >out 2>err &&
80 test_i18ngrep "Skipped b" out &&
81 test_must_be_empty err &&
83 test-tool chmtime -v +0 b >actual-mtime &&
84 test_cmp expected-mtime actual-mtime &&
86 git ls-files -s >index_files &&
87 test_line_count = 1 index_files &&
89 git rev-parse >actual HEAD:b &&
90 git rev-parse >expect A:b &&
91 test_cmp expect actual &&
93 git hash-object b >actual &&
94 git rev-parse A:b >expect &&
95 test_cmp expect actual
99 test_expect_success '1a-check-R: Modify(A)/Modify(B), change on B subset of A' '
100 test_when_finished "git -C 1a reset --hard" &&
101 test_when_finished "git -C 1a clean -fd" &&
103 cd 1a &&
105 git checkout B^0 &&
107 GIT_MERGE_VERBOSITY=3 git merge -s recursive A^0 >out 2>err &&
109 test_i18ngrep "Auto-merging b" out &&
110 test_must_be_empty err &&
112 git ls-files -s >index_files &&
113 test_line_count = 1 index_files &&
115 git rev-parse >actual HEAD:b &&
116 git rev-parse >expect A:b &&
117 test_cmp expect actual &&
119 git hash-object b >actual &&
120 git rev-parse A:b >expect &&
121 test_cmp expect actual
126 ###########################################################################
127 # SECTION 2: Cases involving basic renames
128 ###########################################################################
130 # Testcase 2a, Changes on A, rename on B
131 # Commit O: b_1
132 # Commit A: b_2
133 # Commit B: c_1
134 # Expected: c_2
136 test_expect_success '2a-setup: Modify(A)/rename(B)' '
137 test_create_repo 2a &&
139 cd 2a &&
141 test_seq 1 10 >b &&
142 git add b &&
143 test_tick &&
144 git commit -m "O" &&
146 git branch O &&
147 git branch A &&
148 git branch B &&
150 git checkout A &&
151 test_seq 1 11 >b &&
152 git add b &&
153 test_tick &&
154 git commit -m "A" &&
156 git checkout B &&
157 git mv b c &&
158 test_tick &&
159 git commit -m "B"
163 test_expect_success '2a-check-L: Modify/rename, merge into modify side' '
164 test_when_finished "git -C 2a reset --hard" &&
165 test_when_finished "git -C 2a clean -fd" &&
167 cd 2a &&
169 git checkout A^0 &&
171 GIT_MERGE_VERBOSITY=3 git merge -s recursive B^0 >out 2>err &&
173 test_i18ngrep ! "Skipped c" out &&
174 test_must_be_empty err &&
176 git ls-files -s >index_files &&
177 test_line_count = 1 index_files &&
179 git rev-parse >actual HEAD:c &&
180 git rev-parse >expect A:b &&
181 test_cmp expect actual &&
183 git hash-object c >actual &&
184 git rev-parse A:b >expect &&
185 test_cmp expect actual &&
187 test_must_fail git rev-parse HEAD:b &&
188 test_path_is_missing b
192 test_expect_success '2a-check-R: Modify/rename, merge into rename side' '
193 test_when_finished "git -C 2a reset --hard" &&
194 test_when_finished "git -C 2a clean -fd" &&
196 cd 2a &&
198 git checkout B^0 &&
200 GIT_MERGE_VERBOSITY=3 git merge -s recursive A^0 >out 2>err &&
202 test_i18ngrep ! "Skipped c" out &&
203 test_must_be_empty err &&
205 git ls-files -s >index_files &&
206 test_line_count = 1 index_files &&
208 git rev-parse >actual HEAD:c &&
209 git rev-parse >expect A:b &&
210 test_cmp expect actual &&
212 git hash-object c >actual &&
213 git rev-parse A:b >expect &&
214 test_cmp expect actual &&
216 test_must_fail git rev-parse HEAD:b &&
217 test_path_is_missing b
221 # Testcase 2b, Changed and renamed on A, subset of changes on B
222 # Commit O: b_1
223 # Commit A: c_2
224 # Commit B: b_3
225 # Expected: c_2
227 test_expect_success '2b-setup: Rename+Mod(A)/Mod(B), B mods subset of A' '
228 test_create_repo 2b &&
230 cd 2b &&
232 test_write_lines 1 2 3 4 5 6 7 8 9 10 >b &&
233 git add b &&
234 test_tick &&
235 git commit -m "O" &&
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 5.5 6 7 8 9 10 10.5 >b &&
243 git add b &&
244 git mv b c &&
245 test_tick &&
246 git commit -m "A" &&
248 git checkout B &&
249 test_write_lines 1 2 3 4 5 5.5 6 7 8 9 10 >b &&
250 git add b &&
251 test_tick &&
252 git commit -m "B"
256 test_expect_success '2b-check-L: Rename+Mod(A)/Mod(B), B mods subset of A' '
257 test_when_finished "git -C 2b reset --hard" &&
258 test_when_finished "git -C 2b clean -fd" &&
260 cd 2b &&
262 git checkout A^0 &&
264 test-tool chmtime =31337 c &&
265 test-tool chmtime -v +0 c >expected-mtime &&
267 GIT_MERGE_VERBOSITY=3 git merge -s recursive B^0 >out 2>err &&
269 test_i18ngrep "Skipped c" out &&
270 test_must_be_empty err &&
272 test-tool chmtime -v +0 c >actual-mtime &&
273 test_cmp expected-mtime actual-mtime &&
275 git ls-files -s >index_files &&
276 test_line_count = 1 index_files &&
278 git rev-parse >actual HEAD:c &&
279 git rev-parse >expect A:c &&
280 test_cmp expect actual &&
282 git hash-object c >actual &&
283 git rev-parse A:c >expect &&
284 test_cmp expect actual &&
286 test_must_fail git rev-parse HEAD:b &&
287 test_path_is_missing b
291 test_expect_success '2b-check-R: Rename+Mod(A)/Mod(B), B mods subset of A' '
292 test_when_finished "git -C 2b reset --hard" &&
293 test_when_finished "git -C 2b clean -fd" &&
295 cd 2b &&
297 git checkout B^0 &&
299 GIT_MERGE_VERBOSITY=3 git merge -s recursive A^0 >out 2>err &&
301 test_i18ngrep "Auto-merging c" out &&
302 test_must_be_empty err &&
304 git ls-files -s >index_files &&
305 test_line_count = 1 index_files &&
307 git rev-parse >actual HEAD:c &&
308 git rev-parse >expect A:c &&
309 test_cmp expect actual &&
311 git hash-object c >actual &&
312 git rev-parse A:c >expect &&
313 test_cmp expect actual &&
315 test_must_fail git rev-parse HEAD:b &&
316 test_path_is_missing b
320 # Testcase 2c, Changes on A, rename on B
321 # Commit O: b_1
322 # Commit A: b_2, c_3
323 # Commit B: c_1
324 # Expected: rename/add conflict c_2 vs c_3
326 # NOTE: Since A modified b_1->b_2, and B renamed b_1->c_1, the threeway
327 # merge of those files should result in c_2. We then should have a
328 # rename/add conflict between c_2 and c_3. However, if we note in
329 # merge_content() that A had the right contents (b_2 has same
330 # contents as c_2, just at a different name), and that A had the
331 # right path present (c_3 existed) and thus decides that it can
332 # skip the update, then we're in trouble. This test verifies we do
333 # not make that particular mistake.
335 test_expect_success '2c-setup: Modify b & add c VS rename b->c' '
336 test_create_repo 2c &&
338 cd 2c &&
340 test_seq 1 10 >b &&
341 git add b &&
342 test_tick &&
343 git commit -m "O" &&
345 git branch O &&
346 git branch A &&
347 git branch B &&
349 git checkout A &&
350 test_seq 1 11 >b &&
351 echo whatever >c &&
352 git add b c &&
353 test_tick &&
354 git commit -m "A" &&
356 git checkout B &&
357 git mv b c &&
358 test_tick &&
359 git commit -m "B"
363 test_expect_success '2c-check: Modify b & add c VS rename b->c' '
365 cd 2c &&
367 git checkout A^0 &&
369 GIT_MERGE_VERBOSITY=3 test_must_fail git merge -s recursive B^0 >out 2>err &&
371 test_i18ngrep "CONFLICT (rename/add): Rename b->c" out &&
372 test_i18ngrep ! "Skipped c" out &&
373 test_must_be_empty err
375 # FIXME: rename/add conflicts are horribly broken right now;
376 # when I get back to my patch series fixing it and
377 # rename/rename(2to1) conflicts to bring them in line with
378 # how add/add conflicts behave, then checks like the below
379 # could be added. But that patch series is waiting until
380 # the rename-directory-detection series lands, which this
381 # is part of. And in the mean time, I do not want to further
382 # enforce broken behavior. So for now, the main test is the
383 # one above that err is an empty file.
385 #git ls-files -s >index_files &&
386 #test_line_count = 2 index_files &&
388 #git rev-parse >actual :2:c :3:c &&
389 #git rev-parse >expect A:b A:c &&
390 #test_cmp expect actual &&
392 #git cat-file -p A:b >>merged &&
393 #git cat-file -p A:c >>merge-me &&
394 #>empty &&
395 #test_must_fail git merge-file \
396 # -L "Temporary merge branch 1" \
397 # -L "" \
398 # -L "Temporary merge branch 2" \
399 # merged empty merge-me &&
400 #sed -e "s/^\([<=>]\)/\1\1\1/" merged >merged-internal &&
402 #git hash-object c >actual &&
403 #git hash-object merged-internal >expect &&
404 #test_cmp expect actual &&
406 #test_path_is_missing b
411 ###########################################################################
412 # SECTION 3: Cases involving directory renames
414 # NOTE:
415 # Directory renames only apply when one side renames a directory, and the
416 # other side adds or renames a path into that directory. Applying the
417 # directory rename to that new path creates a new pathname that didn't
418 # exist on either side of history. Thus, it is impossible for the
419 # merge contents to already be at the right path, so all of these checks
420 # exist just to make sure that updates are not skipped.
421 ###########################################################################
423 # Testcase 3a, Change + rename into dir foo on A, dir rename foo->bar on B
424 # Commit O: bq_1, foo/whatever
425 # Commit A: foo/{bq_2, whatever}
426 # Commit B: bq_1, bar/whatever
427 # Expected: bar/{bq_2, whatever}
429 test_expect_success '3a-setup: bq_1->foo/bq_2 on A, foo/->bar/ on B' '
430 test_create_repo 3a &&
432 cd 3a &&
434 mkdir foo &&
435 test_seq 1 10 >bq &&
436 test_write_lines a b c d e f g h i j k >foo/whatever &&
437 git add bq foo/whatever &&
438 test_tick &&
439 git commit -m "O" &&
441 git branch O &&
442 git branch A &&
443 git branch B &&
445 git checkout A &&
446 test_seq 1 11 >bq &&
447 git add bq &&
448 git mv bq foo/ &&
449 test_tick &&
450 git commit -m "A" &&
452 git checkout B &&
453 git mv foo/ bar/ &&
454 test_tick &&
455 git commit -m "B"
459 test_expect_success '3a-check-L: bq_1->foo/bq_2 on A, foo/->bar/ on B' '
460 test_when_finished "git -C 3a reset --hard" &&
461 test_when_finished "git -C 3a clean -fd" &&
463 cd 3a &&
465 git checkout A^0 &&
467 GIT_MERGE_VERBOSITY=3 git merge -s recursive B^0 >out 2>err &&
469 test_i18ngrep ! "Skipped bar/bq" out &&
470 test_must_be_empty err &&
472 git ls-files -s >index_files &&
473 test_line_count = 2 index_files &&
475 git rev-parse >actual HEAD:bar/bq HEAD:bar/whatever &&
476 git rev-parse >expect A:foo/bq A:foo/whatever &&
477 test_cmp expect actual &&
479 git hash-object bar/bq bar/whatever >actual &&
480 git rev-parse A:foo/bq A:foo/whatever >expect &&
481 test_cmp expect actual &&
483 test_must_fail git rev-parse HEAD:bq HEAD:foo/bq &&
484 test_path_is_missing bq foo/bq foo/whatever
488 test_expect_success '3a-check-R: bq_1->foo/bq_2 on A, foo/->bar/ on B' '
489 test_when_finished "git -C 3a reset --hard" &&
490 test_when_finished "git -C 3a clean -fd" &&
492 cd 3a &&
494 git checkout B^0 &&
496 GIT_MERGE_VERBOSITY=3 git merge -s recursive A^0 >out 2>err &&
498 test_i18ngrep ! "Skipped bar/bq" out &&
499 test_must_be_empty err &&
501 git ls-files -s >index_files &&
502 test_line_count = 2 index_files &&
504 git rev-parse >actual HEAD:bar/bq HEAD:bar/whatever &&
505 git rev-parse >expect A:foo/bq A:foo/whatever &&
506 test_cmp expect actual &&
508 git hash-object bar/bq bar/whatever >actual &&
509 git rev-parse A:foo/bq A:foo/whatever >expect &&
510 test_cmp expect actual &&
512 test_must_fail git rev-parse HEAD:bq HEAD:foo/bq &&
513 test_path_is_missing bq foo/bq foo/whatever
517 # Testcase 3b, rename into dir foo on A, dir rename foo->bar + change on B
518 # Commit O: bq_1, foo/whatever
519 # Commit A: foo/{bq_1, whatever}
520 # Commit B: bq_2, bar/whatever
521 # Expected: bar/{bq_2, whatever}
523 test_expect_success '3b-setup: bq_1->foo/bq_2 on A, foo/->bar/ on B' '
524 test_create_repo 3b &&
526 cd 3b &&
528 mkdir foo &&
529 test_seq 1 10 >bq &&
530 test_write_lines a b c d e f g h i j k >foo/whatever &&
531 git add bq foo/whatever &&
532 test_tick &&
533 git commit -m "O" &&
535 git branch O &&
536 git branch A &&
537 git branch B &&
539 git checkout A &&
540 git mv bq foo/ &&
541 test_tick &&
542 git commit -m "A" &&
544 git checkout B &&
545 test_seq 1 11 >bq &&
546 git add bq &&
547 git mv foo/ bar/ &&
548 test_tick &&
549 git commit -m "B"
553 test_expect_success '3b-check-L: bq_1->foo/bq_2 on A, foo/->bar/ on B' '
554 test_when_finished "git -C 3b reset --hard" &&
555 test_when_finished "git -C 3b clean -fd" &&
557 cd 3b &&
559 git checkout A^0 &&
561 GIT_MERGE_VERBOSITY=3 git merge -s recursive B^0 >out 2>err &&
563 test_i18ngrep ! "Skipped bar/bq" out &&
564 test_must_be_empty err &&
566 git ls-files -s >index_files &&
567 test_line_count = 2 index_files &&
569 git rev-parse >actual HEAD:bar/bq HEAD:bar/whatever &&
570 git rev-parse >expect B:bq A:foo/whatever &&
571 test_cmp expect actual &&
573 git hash-object bar/bq bar/whatever >actual &&
574 git rev-parse B:bq A:foo/whatever >expect &&
575 test_cmp expect actual &&
577 test_must_fail git rev-parse HEAD:bq HEAD:foo/bq &&
578 test_path_is_missing bq foo/bq foo/whatever
582 test_expect_success '3b-check-R: bq_1->foo/bq_2 on A, foo/->bar/ on B' '
583 test_when_finished "git -C 3b reset --hard" &&
584 test_when_finished "git -C 3b clean -fd" &&
586 cd 3b &&
588 git checkout B^0 &&
590 GIT_MERGE_VERBOSITY=3 git merge -s recursive A^0 >out 2>err &&
592 test_i18ngrep ! "Skipped bar/bq" out &&
593 test_must_be_empty err &&
595 git ls-files -s >index_files &&
596 test_line_count = 2 index_files &&
598 git rev-parse >actual HEAD:bar/bq HEAD:bar/whatever &&
599 git rev-parse >expect B:bq A:foo/whatever &&
600 test_cmp expect actual &&
602 git hash-object bar/bq bar/whatever >actual &&
603 git rev-parse B:bq A:foo/whatever >expect &&
604 test_cmp expect actual &&
606 test_must_fail git rev-parse HEAD:bq HEAD:foo/bq &&
607 test_path_is_missing bq foo/bq foo/whatever
611 ###########################################################################
612 # SECTION 4: Cases involving dirty changes
613 ###########################################################################
615 # Testcase 4a, Changed on A, subset of changes on B, locally modified
616 # Commit O: b_1
617 # Commit A: b_2
618 # Commit B: b_3
619 # Working copy: b_4
620 # Expected: b_2 for merge, b_4 in working copy
622 test_expect_success '4a-setup: Change on A, change on B subset of A, dirty mods present' '
623 test_create_repo 4a &&
625 cd 4a &&
627 test_write_lines 1 2 3 4 5 6 7 8 9 10 >b &&
628 git add b &&
629 test_tick &&
630 git commit -m "O" &&
632 git branch O &&
633 git branch A &&
634 git branch B &&
636 git checkout A &&
637 test_write_lines 1 2 3 4 5 5.5 6 7 8 9 10 10.5 >b &&
638 git add b &&
639 test_tick &&
640 git commit -m "A" &&
642 git checkout B &&
643 test_write_lines 1 2 3 4 5 5.5 6 7 8 9 10 >b &&
644 git add b &&
645 test_tick &&
646 git commit -m "B"
650 # NOTE: For as long as we continue using unpack_trees() without index_only
651 # set to true, it will error out on a case like this claiming the the locally
652 # modified file would be overwritten by the merge. Getting this testcase
653 # correct requires doing the merge in-memory first, then realizing that no
654 # updates to the file are necessary, and thus that we can just leave the path
655 # alone.
656 test_expect_failure '4a-check: Change on A, change on B subset of A, dirty mods present' '
657 test_when_finished "git -C 4a reset --hard" &&
658 test_when_finished "git -C 4a clean -fd" &&
660 cd 4a &&
662 git checkout A^0 &&
663 echo "File rewritten" >b &&
665 test-tool chmtime =31337 b &&
666 test-tool chmtime -v +0 b >expected-mtime &&
668 GIT_MERGE_VERBOSITY=3 git merge -s recursive B^0 >out 2>err &&
670 test_i18ngrep "Skipped b" out &&
671 test_must_be_empty err &&
673 test-tool chmtime -v +0 b >actual-mtime &&
674 test_cmp expected-mtime actual-mtime &&
676 git ls-files -s >index_files &&
677 test_line_count = 1 index_files &&
679 git rev-parse >actual :0:b &&
680 git rev-parse >expect A:b &&
681 test_cmp expect actual &&
683 git hash-object b >actual &&
684 echo "File rewritten" | git hash-object --stdin >expect &&
685 test_cmp expect actual
689 # Testcase 4b, Changed+renamed on A, subset of changes on B, locally modified
690 # Commit O: b_1
691 # Commit A: c_2
692 # Commit B: b_3
693 # Working copy: c_4
694 # Expected: c_2
696 test_expect_success '4b-setup: Rename+Mod(A)/Mod(B), change on B subset of A, dirty mods present' '
697 test_create_repo 4b &&
699 cd 4b &&
701 test_write_lines 1 2 3 4 5 6 7 8 9 10 >b &&
702 git add b &&
703 test_tick &&
704 git commit -m "O" &&
706 git branch O &&
707 git branch A &&
708 git branch B &&
710 git checkout A &&
711 test_write_lines 1 2 3 4 5 5.5 6 7 8 9 10 10.5 >b &&
712 git add b &&
713 git mv b c &&
714 test_tick &&
715 git commit -m "A" &&
717 git checkout B &&
718 test_write_lines 1 2 3 4 5 5.5 6 7 8 9 10 >b &&
719 git add b &&
720 test_tick &&
721 git commit -m "B"
725 test_expect_success '4b-check: Rename+Mod(A)/Mod(B), change on B subset of A, dirty mods present' '
726 test_when_finished "git -C 4b reset --hard" &&
727 test_when_finished "git -C 4b clean -fd" &&
729 cd 4b &&
731 git checkout A^0 &&
732 echo "File rewritten" >c &&
734 test-tool chmtime =31337 c &&
735 test-tool chmtime -v +0 c >expected-mtime &&
737 GIT_MERGE_VERBOSITY=3 git merge -s recursive B^0 >out 2>err &&
739 test_i18ngrep "Skipped c" out &&
740 test_must_be_empty err &&
742 test-tool chmtime -v +0 c >actual-mtime &&
743 test_cmp expected-mtime actual-mtime &&
745 git ls-files -s >index_files &&
746 test_line_count = 1 index_files &&
748 git rev-parse >actual :0:c &&
749 git rev-parse >expect A:c &&
750 test_cmp expect actual &&
752 git hash-object c >actual &&
753 echo "File rewritten" | git hash-object --stdin >expect &&
754 test_cmp expect actual &&
756 test_must_fail git rev-parse HEAD:b &&
757 test_path_is_missing b
761 test_done