Sync with 'maint'
[alt-git.git] / t / t6426-merge-skip-unneeded-updates.sh
blob62f0180325352b627ea25fc71ec0ffdb4e8e5bb7
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_PASSES_SANITIZE_LEAK=true
26 . ./test-lib.sh
27 . "$TEST_DIRECTORY"/lib-merge.sh
30 ###########################################################################
31 # SECTION 1: Cases involving no renames (one side has subset of changes of
32 # the other side)
33 ###########################################################################
35 # Testcase 1a, Changes on A, subset of changes on B
36 # Commit O: b_1
37 # Commit A: b_2
38 # Commit B: b_3
39 # Expected: b_2
41 test_setup_1a () {
42 git init 1a_$1 &&
44 cd 1a_$1 &&
46 test_write_lines 1 2 3 4 5 6 7 8 9 10 >b &&
47 git add b &&
48 test_tick &&
49 git commit -m "O" &&
51 git branch O &&
52 git branch A &&
53 git branch B &&
55 git checkout A &&
56 test_write_lines 1 2 3 4 5 5.5 6 7 8 9 10 10.5 >b &&
57 git add b &&
58 test_tick &&
59 git commit -m "A" &&
61 git checkout B &&
62 test_write_lines 1 2 3 4 5 5.5 6 7 8 9 10 >b &&
63 git add b &&
64 test_tick &&
65 git commit -m "B"
69 test_expect_success '1a-L: Modify(A)/Modify(B), change on B subset of A' '
70 test_setup_1a L &&
72 cd 1a_L &&
74 git checkout A^0 &&
76 test-tool chmtime --get -3600 b >old-mtime &&
78 GIT_MERGE_VERBOSITY=3 git merge -s recursive B^0 >out 2>err &&
80 test_must_be_empty err &&
82 # Make sure b was NOT updated
83 test-tool chmtime --get b >new-mtime &&
84 test_cmp old-mtime new-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-R: Modify(A)/Modify(B), change on B subset of A' '
100 test_setup_1a R &&
102 cd 1a_R &&
104 git checkout B^0 &&
106 test-tool chmtime --get -3600 b >old-mtime &&
107 GIT_MERGE_VERBOSITY=3 git merge -s recursive A^0 >out 2>err &&
109 # Make sure b WAS updated
110 test-tool chmtime --get b >new-mtime &&
111 test $(cat old-mtime) -lt $(cat new-mtime) &&
113 test_must_be_empty err &&
115 git ls-files -s >index_files &&
116 test_line_count = 1 index_files &&
118 git rev-parse >actual HEAD:b &&
119 git rev-parse >expect A:b &&
120 test_cmp expect actual &&
122 git hash-object b >actual &&
123 git rev-parse A:b >expect &&
124 test_cmp expect actual
129 ###########################################################################
130 # SECTION 2: Cases involving basic renames
131 ###########################################################################
133 # Testcase 2a, Changes on A, rename on B
134 # Commit O: b_1
135 # Commit A: b_2
136 # Commit B: c_1
137 # Expected: c_2
139 test_setup_2a () {
140 git init 2a_$1 &&
142 cd 2a_$1 &&
144 test_seq 1 10 >b &&
145 git add b &&
146 test_tick &&
147 git commit -m "O" &&
149 git branch O &&
150 git branch A &&
151 git branch B &&
153 git checkout A &&
154 test_seq 1 11 >b &&
155 git add b &&
156 test_tick &&
157 git commit -m "A" &&
159 git checkout B &&
160 git mv b c &&
161 test_tick &&
162 git commit -m "B"
166 test_expect_success '2a-L: Modify/rename, merge into modify side' '
167 test_setup_2a L &&
169 cd 2a_L &&
171 git checkout A^0 &&
173 test_path_is_missing c &&
174 GIT_MERGE_VERBOSITY=3 git merge -s recursive B^0 >out 2>err &&
176 test_path_is_file c &&
178 git ls-files -s >index_files &&
179 test_line_count = 1 index_files &&
181 git rev-parse >actual HEAD:c &&
182 git rev-parse >expect A:b &&
183 test_cmp expect actual &&
185 git hash-object c >actual &&
186 git rev-parse A:b >expect &&
187 test_cmp expect actual &&
189 test_must_fail git rev-parse HEAD:b &&
190 test_path_is_missing b
194 test_expect_success '2a-R: Modify/rename, merge into rename side' '
195 test_setup_2a R &&
197 cd 2a_R &&
199 git checkout B^0 &&
201 test-tool chmtime --get -3600 c >old-mtime &&
202 GIT_MERGE_VERBOSITY=3 git merge -s recursive A^0 >out 2>err &&
204 # Make sure c WAS updated
205 test-tool chmtime --get c >new-mtime &&
206 test $(cat old-mtime) -lt $(cat new-mtime) &&
208 test_must_be_empty err &&
210 git ls-files -s >index_files &&
211 test_line_count = 1 index_files &&
213 git rev-parse >actual HEAD:c &&
214 git rev-parse >expect A:b &&
215 test_cmp expect actual &&
217 git hash-object c >actual &&
218 git rev-parse A:b >expect &&
219 test_cmp expect actual &&
221 test_must_fail git rev-parse HEAD:b &&
222 test_path_is_missing b
226 # Testcase 2b, Changed and renamed on A, subset of changes on B
227 # Commit O: b_1
228 # Commit A: c_2
229 # Commit B: b_3
230 # Expected: c_2
232 test_setup_2b () {
233 git init 2b_$1 &&
235 cd 2b_$1 &&
237 test_write_lines 1 2 3 4 5 6 7 8 9 10 >b &&
238 git add b &&
239 test_tick &&
240 git commit -m "O" &&
242 git branch O &&
243 git branch A &&
244 git branch B &&
246 git checkout A &&
247 test_write_lines 1 2 3 4 5 5.5 6 7 8 9 10 10.5 >b &&
248 git add b &&
249 git mv b c &&
250 test_tick &&
251 git commit -m "A" &&
253 git checkout B &&
254 test_write_lines 1 2 3 4 5 5.5 6 7 8 9 10 >b &&
255 git add b &&
256 test_tick &&
257 git commit -m "B"
261 test_expect_success '2b-L: Rename+Mod(A)/Mod(B), B mods subset of A' '
262 test_setup_2b L &&
264 cd 2b_L &&
266 git checkout A^0 &&
268 test-tool chmtime --get -3600 c >old-mtime &&
269 GIT_MERGE_VERBOSITY=3 git merge -s recursive B^0 >out 2>err &&
271 test_must_be_empty err &&
273 # Make sure c WAS updated
274 test-tool chmtime --get c >new-mtime &&
275 test_cmp old-mtime new-mtime &&
277 git ls-files -s >index_files &&
278 test_line_count = 1 index_files &&
280 git rev-parse >actual HEAD:c &&
281 git rev-parse >expect A:c &&
282 test_cmp expect actual &&
284 git hash-object c >actual &&
285 git rev-parse A:c >expect &&
286 test_cmp expect actual &&
288 test_must_fail git rev-parse HEAD:b &&
289 test_path_is_missing b
293 test_expect_success '2b-R: Rename+Mod(A)/Mod(B), B mods subset of A' '
294 test_setup_2b R &&
296 cd 2b_R &&
298 git checkout B^0 &&
300 test_path_is_missing c &&
301 GIT_MERGE_VERBOSITY=3 git merge -s recursive A^0 >out 2>err &&
303 # Make sure c now present (and thus was updated)
304 test_path_is_file c &&
306 test_must_be_empty err &&
308 git ls-files -s >index_files &&
309 test_line_count = 1 index_files &&
311 git rev-parse >actual HEAD:c &&
312 git rev-parse >expect A:c &&
313 test_cmp expect actual &&
315 git hash-object c >actual &&
316 git rev-parse A:c >expect &&
317 test_cmp expect actual &&
319 test_must_fail git rev-parse HEAD:b &&
320 test_path_is_missing b
324 # Testcase 2c, Changes on A, rename on B
325 # Commit O: b_1
326 # Commit A: b_2, c_3
327 # Commit B: c_1
328 # Expected: rename/add conflict c_2 vs c_3
330 # NOTE: Since A modified b_1->b_2, and B renamed b_1->c_1, the threeway
331 # merge of those files should result in c_2. We then should have a
332 # rename/add conflict between c_2 and c_3. However, if we note in
333 # merge_content() that A had the right contents (b_2 has same
334 # contents as c_2, just at a different name), and that A had the
335 # right path present (c_3 existed) and thus decides that it can
336 # skip the update, then we're in trouble. This test verifies we do
337 # not make that particular mistake.
339 test_setup_2c () {
340 git init 2c &&
342 cd 2c &&
344 test_seq 1 10 >b &&
345 git add b &&
346 test_tick &&
347 git commit -m "O" &&
349 git branch O &&
350 git branch A &&
351 git branch B &&
353 git checkout A &&
354 test_seq 1 11 >b &&
355 echo whatever >c &&
356 git add b c &&
357 test_tick &&
358 git commit -m "A" &&
360 git checkout B &&
361 git mv b c &&
362 test_tick &&
363 git commit -m "B"
367 test_expect_success '2c: Modify b & add c VS rename b->c' '
368 test_setup_2c &&
370 cd 2c &&
372 git checkout A^0 &&
374 test-tool chmtime --get -3600 c >old-mtime &&
375 GIT_MERGE_VERBOSITY=3 &&
376 export GIT_MERGE_VERBOSITY &&
377 test_must_fail git merge -s recursive B^0 >out 2>err &&
379 test_grep "CONFLICT (.*/add):" out &&
380 test_must_be_empty err &&
382 git ls-files -s >index_files &&
383 test_line_count = 2 index_files &&
385 # Ensure b was removed
386 test_path_is_missing b &&
388 # Make sure c WAS updated...
389 test-tool chmtime --get c >new-mtime &&
390 test $(cat old-mtime) -lt $(cat new-mtime) &&
392 # ...and has correct index entries and working tree contents
393 git rev-parse >actual :2:c :3:c &&
394 git rev-parse >expect A:c A:b &&
395 test_cmp expect actual &&
397 git cat-file -p A:b >>merge-me &&
398 git cat-file -p A:c >>merged &&
399 >empty &&
400 test_must_fail git merge-file \
401 -L "HEAD" \
402 -L "" \
403 -L "B^0" \
404 merged empty merge-me &&
405 test_cmp merged c
410 ###########################################################################
411 # SECTION 3: Cases involving directory renames
413 # NOTE:
414 # Directory renames only apply when one side renames a directory, and the
415 # other side adds or renames a path into that directory. Applying the
416 # directory rename to that new path creates a new pathname that didn't
417 # exist on either side of history. Thus, it is impossible for the
418 # merge contents to already be at the right path, so all of these checks
419 # exist just to make sure that updates are not skipped.
420 ###########################################################################
422 # Testcase 3a, Change + rename into dir foo on A, dir rename foo->bar on B
423 # Commit O: bq_1, foo/whatever
424 # Commit A: foo/{bq_2, whatever}
425 # Commit B: bq_1, bar/whatever
426 # Expected: bar/{bq_2, whatever}
428 test_setup_3a () {
429 git init 3a_$1 &&
431 cd 3a_$1 &&
433 mkdir foo &&
434 test_seq 1 10 >bq &&
435 test_write_lines a b c d e f g h i j k >foo/whatever &&
436 git add bq foo/whatever &&
437 test_tick &&
438 git commit -m "O" &&
440 git branch O &&
441 git branch A &&
442 git branch B &&
444 git checkout A &&
445 test_seq 1 11 >bq &&
446 git add bq &&
447 git mv bq foo/ &&
448 test_tick &&
449 git commit -m "A" &&
451 git checkout B &&
452 git mv foo/ bar/ &&
453 test_tick &&
454 git commit -m "B"
458 test_expect_success '3a-L: bq_1->foo/bq_2 on A, foo/->bar/ on B' '
459 test_setup_3a L &&
461 cd 3a_L &&
463 git checkout A^0 &&
465 test_path_is_missing bar/bq &&
466 GIT_MERGE_VERBOSITY=3 git -c merge.directoryRenames=true merge -s recursive B^0 >out 2>err &&
468 test_must_be_empty err &&
470 test_path_is_file bar/bq &&
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 &&
485 test_path_is_missing foo/bq &&
486 test_path_is_missing foo/whatever
490 test_expect_success '3a-R: bq_1->foo/bq_2 on A, foo/->bar/ on B' '
491 test_setup_3a R &&
493 cd 3a_R &&
495 git checkout B^0 &&
497 test_path_is_missing bar/bq &&
498 GIT_MERGE_VERBOSITY=3 git -c merge.directoryRenames=true merge -s recursive A^0 >out 2>err &&
500 test_must_be_empty err &&
502 test_path_is_file bar/bq &&
504 git ls-files -s >index_files &&
505 test_line_count = 2 index_files &&
507 git rev-parse >actual HEAD:bar/bq HEAD:bar/whatever &&
508 git rev-parse >expect A:foo/bq A:foo/whatever &&
509 test_cmp expect actual &&
511 git hash-object bar/bq bar/whatever >actual &&
512 git rev-parse A:foo/bq A:foo/whatever >expect &&
513 test_cmp expect actual &&
515 test_must_fail git rev-parse HEAD:bq HEAD:foo/bq &&
516 test_path_is_missing bq &&
517 test_path_is_missing foo/bq &&
518 test_path_is_missing foo/whatever
522 # Testcase 3b, rename into dir foo on A, dir rename foo->bar + change on B
523 # Commit O: bq_1, foo/whatever
524 # Commit A: foo/{bq_1, whatever}
525 # Commit B: bq_2, bar/whatever
526 # Expected: bar/{bq_2, whatever}
528 test_setup_3b () {
529 git init 3b_$1 &&
531 cd 3b_$1 &&
533 mkdir foo &&
534 test_seq 1 10 >bq &&
535 test_write_lines a b c d e f g h i j k >foo/whatever &&
536 git add bq foo/whatever &&
537 test_tick &&
538 git commit -m "O" &&
540 git branch O &&
541 git branch A &&
542 git branch B &&
544 git checkout A &&
545 git mv bq foo/ &&
546 test_tick &&
547 git commit -m "A" &&
549 git checkout B &&
550 test_seq 1 11 >bq &&
551 git add bq &&
552 git mv foo/ bar/ &&
553 test_tick &&
554 git commit -m "B"
558 test_expect_success '3b-L: bq_1->foo/bq_2 on A, foo/->bar/ on B' '
559 test_setup_3b L &&
561 cd 3b_L &&
563 git checkout A^0 &&
565 test_path_is_missing bar/bq &&
566 GIT_MERGE_VERBOSITY=3 git -c merge.directoryRenames=true merge -s recursive B^0 >out 2>err &&
568 test_must_be_empty err &&
570 test_path_is_file bar/bq &&
572 git ls-files -s >index_files &&
573 test_line_count = 2 index_files &&
575 git rev-parse >actual HEAD:bar/bq HEAD:bar/whatever &&
576 git rev-parse >expect B:bq A:foo/whatever &&
577 test_cmp expect actual &&
579 git hash-object bar/bq bar/whatever >actual &&
580 git rev-parse B:bq A:foo/whatever >expect &&
581 test_cmp expect actual &&
583 test_must_fail git rev-parse HEAD:bq HEAD:foo/bq &&
584 test_path_is_missing bq &&
585 test_path_is_missing foo/bq &&
586 test_path_is_missing foo/whatever
590 test_expect_success '3b-R: bq_1->foo/bq_2 on A, foo/->bar/ on B' '
591 test_setup_3b R &&
593 cd 3b_R &&
595 git checkout B^0 &&
597 test_path_is_missing bar/bq &&
598 GIT_MERGE_VERBOSITY=3 git -c merge.directoryRenames=true merge -s recursive A^0 >out 2>err &&
600 test_must_be_empty err &&
602 test_path_is_file bar/bq &&
604 git ls-files -s >index_files &&
605 test_line_count = 2 index_files &&
607 git rev-parse >actual HEAD:bar/bq HEAD:bar/whatever &&
608 git rev-parse >expect B:bq A:foo/whatever &&
609 test_cmp expect actual &&
611 git hash-object bar/bq bar/whatever >actual &&
612 git rev-parse B:bq A:foo/whatever >expect &&
613 test_cmp expect actual &&
615 test_must_fail git rev-parse HEAD:bq HEAD:foo/bq &&
616 test_path_is_missing bq &&
617 test_path_is_missing foo/bq &&
618 test_path_is_missing foo/whatever
622 ###########################################################################
623 # SECTION 4: Cases involving dirty changes
624 ###########################################################################
626 # Testcase 4a, Changed on A, subset of changes on B, locally modified
627 # Commit O: b_1
628 # Commit A: b_2
629 # Commit B: b_3
630 # Working copy: b_4
631 # Expected: b_2 for merge, b_4 in working copy
633 test_setup_4a () {
634 git init 4a &&
636 cd 4a &&
638 test_write_lines 1 2 3 4 5 6 7 8 9 10 >b &&
639 git add b &&
640 test_tick &&
641 git commit -m "O" &&
643 git branch O &&
644 git branch A &&
645 git branch B &&
647 git checkout A &&
648 test_write_lines 1 2 3 4 5 5.5 6 7 8 9 10 10.5 >b &&
649 git add b &&
650 test_tick &&
651 git commit -m "A" &&
653 git checkout B &&
654 test_write_lines 1 2 3 4 5 5.5 6 7 8 9 10 >b &&
655 git add b &&
656 test_tick &&
657 git commit -m "B"
661 # NOTE: For as long as we continue using unpack_trees() without index_only
662 # set to true, it will error out on a case like this claiming that the locally
663 # modified file would be overwritten by the merge. Getting this testcase
664 # correct requires doing the merge in-memory first, then realizing that no
665 # updates to the file are necessary, and thus that we can just leave the path
666 # alone.
667 test_expect_merge_algorithm failure success '4a: Change on A, change on B subset of A, dirty mods present' '
668 test_setup_4a &&
670 cd 4a &&
672 git checkout A^0 &&
673 echo "File rewritten" >b &&
675 test-tool chmtime --get -3600 b >old-mtime &&
677 GIT_MERGE_VERBOSITY=3 git merge -s recursive B^0 >out 2>err &&
679 test_must_be_empty err &&
681 # Make sure b was NOT updated
682 test-tool chmtime --get b >new-mtime &&
683 test_cmp old-mtime new-mtime &&
685 git ls-files -s >index_files &&
686 test_line_count = 1 index_files &&
688 git rev-parse >actual :0:b &&
689 git rev-parse >expect A:b &&
690 test_cmp expect actual &&
692 git hash-object b >actual &&
693 echo "File rewritten" | git hash-object --stdin >expect &&
694 test_cmp expect actual
698 # Testcase 4b, Changed+renamed on A, subset of changes on B, locally modified
699 # Commit O: b_1
700 # Commit A: c_2
701 # Commit B: b_3
702 # Working copy: c_4
703 # Expected: c_2
705 test_setup_4b () {
706 git init 4b &&
708 cd 4b &&
710 test_write_lines 1 2 3 4 5 6 7 8 9 10 >b &&
711 git add b &&
712 test_tick &&
713 git commit -m "O" &&
715 git branch O &&
716 git branch A &&
717 git branch B &&
719 git checkout A &&
720 test_write_lines 1 2 3 4 5 5.5 6 7 8 9 10 10.5 >b &&
721 git add b &&
722 git mv b c &&
723 test_tick &&
724 git commit -m "A" &&
726 git checkout B &&
727 test_write_lines 1 2 3 4 5 5.5 6 7 8 9 10 >b &&
728 git add b &&
729 test_tick &&
730 git commit -m "B"
734 test_expect_success '4b: Rename+Mod(A)/Mod(B), change on B subset of A, dirty mods present' '
735 test_setup_4b &&
737 cd 4b &&
739 git checkout A^0 &&
740 echo "File rewritten" >c &&
742 test-tool chmtime --get -3600 c >old-mtime &&
744 GIT_MERGE_VERBOSITY=3 git merge -s recursive B^0 >out 2>err &&
746 test_must_be_empty err &&
748 # Make sure c was NOT updated
749 test-tool chmtime --get c >new-mtime &&
750 test_cmp old-mtime new-mtime &&
752 git ls-files -s >index_files &&
753 test_line_count = 1 index_files &&
755 git rev-parse >actual :0:c &&
756 git rev-parse >expect A:c &&
757 test_cmp expect actual &&
759 git hash-object c >actual &&
760 echo "File rewritten" | git hash-object --stdin >expect &&
761 test_cmp expect actual &&
763 test_must_fail git rev-parse HEAD:b &&
764 test_path_is_missing b
768 test_done