3 test_description
="merge cases"
5 # The setup for all of them, pictorially, is:
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.
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.)
28 ###########################################################################
29 # SECTION 1: Cases involving no renames (one side has subset of changes of
31 ###########################################################################
33 # Testcase 1a, Changes on A, subset of changes on B
40 test_create_repo
1a_
$1 &&
44 test_write_lines
1 2 3 4 5 6 7 8 9 10 >b
&&
54 test_write_lines
1 2 3 4 5 5.5 6 7 8 9 10 10.5 >b
&&
60 test_write_lines
1 2 3 4 5 5.5 6 7 8 9 10 >b
&&
67 test_expect_success
'1a-L: Modify(A)/Modify(B), change on B subset of A' '
74 test-tool chmtime =31337 b &&
75 test-tool chmtime -v +0 b >expected-mtime &&
77 GIT_MERGE_VERBOSITY=3 git merge -s recursive B^0 >out 2>err &&
79 test_i18ngrep "Skipped b" out &&
80 test_must_be_empty err &&
82 test-tool chmtime -v +0 b >actual-mtime &&
83 test_cmp expected-mtime actual-mtime &&
85 git ls-files -s >index_files &&
86 test_line_count = 1 index_files &&
88 git rev-parse >actual HEAD:b &&
89 git rev-parse >expect A:b &&
90 test_cmp expect actual &&
92 git hash-object b >actual &&
93 git rev-parse A:b >expect &&
94 test_cmp expect actual
98 test_expect_success
'1a-R: Modify(A)/Modify(B), change on B subset of A' '
105 GIT_MERGE_VERBOSITY=3 git merge -s recursive A^0 >out 2>err &&
107 test_i18ngrep "Auto-merging b" out &&
108 test_must_be_empty err &&
110 git ls-files -s >index_files &&
111 test_line_count = 1 index_files &&
113 git rev-parse >actual HEAD:b &&
114 git rev-parse >expect A:b &&
115 test_cmp expect actual &&
117 git hash-object b >actual &&
118 git rev-parse A:b >expect &&
119 test_cmp expect actual
124 ###########################################################################
125 # SECTION 2: Cases involving basic renames
126 ###########################################################################
128 # Testcase 2a, Changes on A, rename on B
135 test_create_repo
2a_
$1 &&
161 test_expect_success
'2a-L: Modify/rename, merge into modify side' '
168 GIT_MERGE_VERBOSITY=3 git merge -s recursive B^0 >out 2>err &&
170 test_i18ngrep ! "Skipped c" out &&
171 test_must_be_empty err &&
173 git ls-files -s >index_files &&
174 test_line_count = 1 index_files &&
176 git rev-parse >actual HEAD:c &&
177 git rev-parse >expect A:b &&
178 test_cmp expect actual &&
180 git hash-object c >actual &&
181 git rev-parse A:b >expect &&
182 test_cmp expect actual &&
184 test_must_fail git rev-parse HEAD:b &&
185 test_path_is_missing b
189 test_expect_success
'2a-R: Modify/rename, merge into rename side' '
196 GIT_MERGE_VERBOSITY=3 git merge -s recursive A^0 >out 2>err &&
198 test_i18ngrep ! "Skipped c" out &&
199 test_must_be_empty err &&
201 git ls-files -s >index_files &&
202 test_line_count = 1 index_files &&
204 git rev-parse >actual HEAD:c &&
205 git rev-parse >expect A:b &&
206 test_cmp expect actual &&
208 git hash-object c >actual &&
209 git rev-parse A:b >expect &&
210 test_cmp expect actual &&
212 test_must_fail git rev-parse HEAD:b &&
213 test_path_is_missing b
217 # Testcase 2b, Changed and renamed on A, subset of changes on B
224 test_create_repo
2b_
$1 &&
228 test_write_lines
1 2 3 4 5 6 7 8 9 10 >b
&&
238 test_write_lines
1 2 3 4 5 5.5 6 7 8 9 10 10.5 >b
&&
245 test_write_lines
1 2 3 4 5 5.5 6 7 8 9 10 >b
&&
252 test_expect_success
'2b-L: Rename+Mod(A)/Mod(B), B mods subset of A' '
259 test-tool chmtime =31337 c &&
260 test-tool chmtime -v +0 c >expected-mtime &&
262 GIT_MERGE_VERBOSITY=3 git merge -s recursive B^0 >out 2>err &&
264 test_i18ngrep "Skipped c" out &&
265 test_must_be_empty err &&
267 test-tool chmtime -v +0 c >actual-mtime &&
268 test_cmp expected-mtime actual-mtime &&
270 git ls-files -s >index_files &&
271 test_line_count = 1 index_files &&
273 git rev-parse >actual HEAD:c &&
274 git rev-parse >expect A:c &&
275 test_cmp expect actual &&
277 git hash-object c >actual &&
278 git rev-parse A:c >expect &&
279 test_cmp expect actual &&
281 test_must_fail git rev-parse HEAD:b &&
282 test_path_is_missing b
286 test_expect_success
'2b-R: Rename+Mod(A)/Mod(B), B mods subset of A' '
293 GIT_MERGE_VERBOSITY=3 git merge -s recursive A^0 >out 2>err &&
295 test_i18ngrep "Auto-merging c" out &&
296 test_must_be_empty err &&
298 git ls-files -s >index_files &&
299 test_line_count = 1 index_files &&
301 git rev-parse >actual HEAD:c &&
302 git rev-parse >expect A:c &&
303 test_cmp expect actual &&
305 git hash-object c >actual &&
306 git rev-parse A:c >expect &&
307 test_cmp expect actual &&
309 test_must_fail git rev-parse HEAD:b &&
310 test_path_is_missing b
314 # Testcase 2c, Changes on A, rename on B
318 # Expected: rename/add conflict c_2 vs c_3
320 # NOTE: Since A modified b_1->b_2, and B renamed b_1->c_1, the threeway
321 # merge of those files should result in c_2. We then should have a
322 # rename/add conflict between c_2 and c_3. However, if we note in
323 # merge_content() that A had the right contents (b_2 has same
324 # contents as c_2, just at a different name), and that A had the
325 # right path present (c_3 existed) and thus decides that it can
326 # skip the update, then we're in trouble. This test verifies we do
327 # not make that particular mistake.
330 test_create_repo
2c
&&
357 test_expect_success
'2c: Modify b & add c VS rename b->c' '
364 GIT_MERGE_VERBOSITY=3 &&
365 export GIT_MERGE_VERBOSITY &&
366 test_must_fail git merge -s recursive B^0 >out 2>err &&
368 test_i18ngrep "CONFLICT (rename/add): Rename b->c" out &&
369 test_i18ngrep ! "Skipped c" out &&
370 test_must_be_empty err
372 # FIXME: rename/add conflicts are horribly broken right now;
373 # when I get back to my patch series fixing it and
374 # rename/rename(2to1) conflicts to bring them in line with
375 # how add/add conflicts behave, then checks like the below
376 # could be added. But that patch series is waiting until
377 # the rename-directory-detection series lands, which this
378 # is part of. And in the mean time, I do not want to further
379 # enforce broken behavior. So for now, the main test is the
380 # one above that err is an empty file.
382 #git ls-files -s >index_files &&
383 #test_line_count = 2 index_files &&
385 #git rev-parse >actual :2:c :3:c &&
386 #git rev-parse >expect A:b A:c &&
387 #test_cmp expect actual &&
389 #git cat-file -p A:b >>merged &&
390 #git cat-file -p A:c >>merge-me &&
392 #test_must_fail git merge-file \
393 # -L "Temporary merge branch 1" \
395 # -L "Temporary merge branch 2" \
396 # merged empty merge-me &&
397 #sed -e "s/^\([<=>]\)/\1\1\1/" merged >merged-internal &&
399 #git hash-object c >actual &&
400 #git hash-object merged-internal >expect &&
401 #test_cmp expect actual &&
403 #test_path_is_missing b
408 ###########################################################################
409 # SECTION 3: Cases involving directory renames
412 # Directory renames only apply when one side renames a directory, and the
413 # other side adds or renames a path into that directory. Applying the
414 # directory rename to that new path creates a new pathname that didn't
415 # exist on either side of history. Thus, it is impossible for the
416 # merge contents to already be at the right path, so all of these checks
417 # exist just to make sure that updates are not skipped.
418 ###########################################################################
420 # Testcase 3a, Change + rename into dir foo on A, dir rename foo->bar on B
421 # Commit O: bq_1, foo/whatever
422 # Commit A: foo/{bq_2, whatever}
423 # Commit B: bq_1, bar/whatever
424 # Expected: bar/{bq_2, whatever}
427 test_create_repo
3a_
$1 &&
433 test_write_lines a b c d e f g h i j k
>foo
/whatever
&&
434 git add bq foo
/whatever
&&
456 test_expect_success
'3a-L: bq_1->foo/bq_2 on A, foo/->bar/ on B' '
463 GIT_MERGE_VERBOSITY=3 git -c merge.directoryRenames=true merge -s recursive B^0 >out 2>err &&
465 test_i18ngrep ! "Skipped bar/bq" out &&
466 test_must_be_empty err &&
468 git ls-files -s >index_files &&
469 test_line_count = 2 index_files &&
471 git rev-parse >actual HEAD:bar/bq HEAD:bar/whatever &&
472 git rev-parse >expect A:foo/bq A:foo/whatever &&
473 test_cmp expect actual &&
475 git hash-object bar/bq bar/whatever >actual &&
476 git rev-parse A:foo/bq A:foo/whatever >expect &&
477 test_cmp expect actual &&
479 test_must_fail git rev-parse HEAD:bq HEAD:foo/bq &&
480 test_path_is_missing bq foo/bq foo/whatever
484 test_expect_success
'3a-R: bq_1->foo/bq_2 on A, foo/->bar/ on B' '
491 GIT_MERGE_VERBOSITY=3 git -c merge.directoryRenames=true merge -s recursive A^0 >out 2>err &&
493 test_i18ngrep ! "Skipped bar/bq" out &&
494 test_must_be_empty err &&
496 git ls-files -s >index_files &&
497 test_line_count = 2 index_files &&
499 git rev-parse >actual HEAD:bar/bq HEAD:bar/whatever &&
500 git rev-parse >expect A:foo/bq A:foo/whatever &&
501 test_cmp expect actual &&
503 git hash-object bar/bq bar/whatever >actual &&
504 git rev-parse A:foo/bq A:foo/whatever >expect &&
505 test_cmp expect actual &&
507 test_must_fail git rev-parse HEAD:bq HEAD:foo/bq &&
508 test_path_is_missing bq foo/bq foo/whatever
512 # Testcase 3b, rename into dir foo on A, dir rename foo->bar + change on B
513 # Commit O: bq_1, foo/whatever
514 # Commit A: foo/{bq_1, whatever}
515 # Commit B: bq_2, bar/whatever
516 # Expected: bar/{bq_2, whatever}
519 test_create_repo
3b_
$1 &&
525 test_write_lines a b c d e f g h i j k
>foo
/whatever
&&
526 git add bq foo
/whatever
&&
548 test_expect_success
'3b-L: bq_1->foo/bq_2 on A, foo/->bar/ on B' '
555 GIT_MERGE_VERBOSITY=3 git -c merge.directoryRenames=true merge -s recursive B^0 >out 2>err &&
557 test_i18ngrep ! "Skipped bar/bq" out &&
558 test_must_be_empty err &&
560 git ls-files -s >index_files &&
561 test_line_count = 2 index_files &&
563 git rev-parse >actual HEAD:bar/bq HEAD:bar/whatever &&
564 git rev-parse >expect B:bq A:foo/whatever &&
565 test_cmp expect actual &&
567 git hash-object bar/bq bar/whatever >actual &&
568 git rev-parse B:bq A:foo/whatever >expect &&
569 test_cmp expect actual &&
571 test_must_fail git rev-parse HEAD:bq HEAD:foo/bq &&
572 test_path_is_missing bq foo/bq foo/whatever
576 test_expect_success
'3b-R: bq_1->foo/bq_2 on A, foo/->bar/ on B' '
583 GIT_MERGE_VERBOSITY=3 git -c merge.directoryRenames=true merge -s recursive A^0 >out 2>err &&
585 test_i18ngrep ! "Skipped bar/bq" out &&
586 test_must_be_empty err &&
588 git ls-files -s >index_files &&
589 test_line_count = 2 index_files &&
591 git rev-parse >actual HEAD:bar/bq HEAD:bar/whatever &&
592 git rev-parse >expect B:bq A:foo/whatever &&
593 test_cmp expect actual &&
595 git hash-object bar/bq bar/whatever >actual &&
596 git rev-parse B:bq A:foo/whatever >expect &&
597 test_cmp expect actual &&
599 test_must_fail git rev-parse HEAD:bq HEAD:foo/bq &&
600 test_path_is_missing bq foo/bq foo/whatever
604 ###########################################################################
605 # SECTION 4: Cases involving dirty changes
606 ###########################################################################
608 # Testcase 4a, Changed on A, subset of changes on B, locally modified
613 # Expected: b_2 for merge, b_4 in working copy
616 test_create_repo
4a
&&
620 test_write_lines
1 2 3 4 5 6 7 8 9 10 >b
&&
630 test_write_lines
1 2 3 4 5 5.5 6 7 8 9 10 10.5 >b
&&
636 test_write_lines
1 2 3 4 5 5.5 6 7 8 9 10 >b
&&
643 # NOTE: For as long as we continue using unpack_trees() without index_only
644 # set to true, it will error out on a case like this claiming the the locally
645 # modified file would be overwritten by the merge. Getting this testcase
646 # correct requires doing the merge in-memory first, then realizing that no
647 # updates to the file are necessary, and thus that we can just leave the path
649 test_expect_failure
'4a: Change on A, change on B subset of A, dirty mods present' '
655 echo "File rewritten" >b &&
657 test-tool chmtime =31337 b &&
658 test-tool chmtime -v +0 b >expected-mtime &&
660 GIT_MERGE_VERBOSITY=3 git merge -s recursive B^0 >out 2>err &&
662 test_i18ngrep "Skipped b" out &&
663 test_must_be_empty err &&
665 test-tool chmtime -v +0 b >actual-mtime &&
666 test_cmp expected-mtime actual-mtime &&
668 git ls-files -s >index_files &&
669 test_line_count = 1 index_files &&
671 git rev-parse >actual :0:b &&
672 git rev-parse >expect A:b &&
673 test_cmp expect actual &&
675 git hash-object b >actual &&
676 echo "File rewritten" | git hash-object --stdin >expect &&
677 test_cmp expect actual
681 # Testcase 4b, Changed+renamed on A, subset of changes on B, locally modified
689 test_create_repo
4b
&&
693 test_write_lines
1 2 3 4 5 6 7 8 9 10 >b
&&
703 test_write_lines
1 2 3 4 5 5.5 6 7 8 9 10 10.5 >b
&&
710 test_write_lines
1 2 3 4 5 5.5 6 7 8 9 10 >b
&&
717 test_expect_success
'4b: Rename+Mod(A)/Mod(B), change on B subset of A, dirty mods present' '
723 echo "File rewritten" >c &&
725 test-tool chmtime =31337 c &&
726 test-tool chmtime -v +0 c >expected-mtime &&
728 GIT_MERGE_VERBOSITY=3 git merge -s recursive B^0 >out 2>err &&
730 test_i18ngrep "Skipped c" out &&
731 test_must_be_empty err &&
733 test-tool chmtime -v +0 c >actual-mtime &&
734 test_cmp expected-mtime actual-mtime &&
736 git ls-files -s >index_files &&
737 test_line_count = 1 index_files &&
739 git rev-parse >actual :0:c &&
740 git rev-parse >expect A:c &&
741 test_cmp expect actual &&
743 git hash-object c >actual &&
744 echo "File rewritten" | git hash-object --stdin >expect &&
745 test_cmp expect actual &&
747 test_must_fail git rev-parse HEAD:b &&
748 test_path_is_missing b