]> git.ipfire.org Git - thirdparty/git.git/blob - t/t6426-merge-skip-unneeded-updates.sh
Merge branch 'en/strmap'
[thirdparty/git.git] / t / t6426-merge-skip-unneeded-updates.sh
1 #!/bin/sh
2
3 test_description="merge cases"
4
5 # The setup for all of them, pictorially, is:
6 #
7 # A
8 # o
9 # / \
10 # O o ?
11 # \ /
12 # o
13 # B
14 #
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.
18 #
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.)
24
25 . ./test-lib.sh
26 . "$TEST_DIRECTORY"/lib-merge.sh
27
28
29 ###########################################################################
30 # SECTION 1: Cases involving no renames (one side has subset of changes of
31 # the other side)
32 ###########################################################################
33
34 # Testcase 1a, Changes on A, subset of changes on B
35 # Commit O: b_1
36 # Commit A: b_2
37 # Commit B: b_3
38 # Expected: b_2
39
40 test_setup_1a () {
41 test_create_repo 1a_$1 &&
42 (
43 cd 1a_$1 &&
44
45 test_write_lines 1 2 3 4 5 6 7 8 9 10 >b &&
46 git add b &&
47 test_tick &&
48 git commit -m "O" &&
49
50 git branch O &&
51 git branch A &&
52 git branch B &&
53
54 git checkout A &&
55 test_write_lines 1 2 3 4 5 5.5 6 7 8 9 10 10.5 >b &&
56 git add b &&
57 test_tick &&
58 git commit -m "A" &&
59
60 git checkout B &&
61 test_write_lines 1 2 3 4 5 5.5 6 7 8 9 10 >b &&
62 git add b &&
63 test_tick &&
64 git commit -m "B"
65 )
66 }
67
68 test_expect_success '1a-L: Modify(A)/Modify(B), change on B subset of A' '
69 test_setup_1a L &&
70 (
71 cd 1a_L &&
72
73 git checkout A^0 &&
74
75 test-tool chmtime --get -3600 b >old-mtime &&
76
77 GIT_MERGE_VERBOSITY=3 git merge -s recursive B^0 >out 2>err &&
78
79 test_must_be_empty err &&
80
81 # Make sure b was NOT updated
82 test-tool chmtime --get b >new-mtime &&
83 test_cmp old-mtime new-mtime &&
84
85 git ls-files -s >index_files &&
86 test_line_count = 1 index_files &&
87
88 git rev-parse >actual HEAD:b &&
89 git rev-parse >expect A:b &&
90 test_cmp expect actual &&
91
92 git hash-object b >actual &&
93 git rev-parse A:b >expect &&
94 test_cmp expect actual
95 )
96 '
97
98 test_expect_success '1a-R: Modify(A)/Modify(B), change on B subset of A' '
99 test_setup_1a R &&
100 (
101 cd 1a_R &&
102
103 git checkout B^0 &&
104
105 test-tool chmtime --get -3600 b >old-mtime &&
106 GIT_MERGE_VERBOSITY=3 git merge -s recursive A^0 >out 2>err &&
107
108 # Make sure b WAS updated
109 test-tool chmtime --get b >new-mtime &&
110 test $(cat old-mtime) -lt $(cat new-mtime) &&
111
112 test_must_be_empty err &&
113
114 git ls-files -s >index_files &&
115 test_line_count = 1 index_files &&
116
117 git rev-parse >actual HEAD:b &&
118 git rev-parse >expect A:b &&
119 test_cmp expect actual &&
120
121 git hash-object b >actual &&
122 git rev-parse A:b >expect &&
123 test_cmp expect actual
124 )
125 '
126
127
128 ###########################################################################
129 # SECTION 2: Cases involving basic renames
130 ###########################################################################
131
132 # Testcase 2a, Changes on A, rename on B
133 # Commit O: b_1
134 # Commit A: b_2
135 # Commit B: c_1
136 # Expected: c_2
137
138 test_setup_2a () {
139 test_create_repo 2a_$1 &&
140 (
141 cd 2a_$1 &&
142
143 test_seq 1 10 >b &&
144 git add b &&
145 test_tick &&
146 git commit -m "O" &&
147
148 git branch O &&
149 git branch A &&
150 git branch B &&
151
152 git checkout A &&
153 test_seq 1 11 >b &&
154 git add b &&
155 test_tick &&
156 git commit -m "A" &&
157
158 git checkout B &&
159 git mv b c &&
160 test_tick &&
161 git commit -m "B"
162 )
163 }
164
165 test_expect_success '2a-L: Modify/rename, merge into modify side' '
166 test_setup_2a L &&
167 (
168 cd 2a_L &&
169
170 git checkout A^0 &&
171
172 test_path_is_missing c &&
173 GIT_MERGE_VERBOSITY=3 git merge -s recursive B^0 >out 2>err &&
174
175 test_path_is_file c &&
176
177 git ls-files -s >index_files &&
178 test_line_count = 1 index_files &&
179
180 git rev-parse >actual HEAD:c &&
181 git rev-parse >expect A:b &&
182 test_cmp expect actual &&
183
184 git hash-object c >actual &&
185 git rev-parse A:b >expect &&
186 test_cmp expect actual &&
187
188 test_must_fail git rev-parse HEAD:b &&
189 test_path_is_missing b
190 )
191 '
192
193 test_expect_success '2a-R: Modify/rename, merge into rename side' '
194 test_setup_2a R &&
195 (
196 cd 2a_R &&
197
198 git checkout B^0 &&
199
200 test-tool chmtime --get -3600 c >old-mtime &&
201 GIT_MERGE_VERBOSITY=3 git merge -s recursive A^0 >out 2>err &&
202
203 # Make sure c WAS updated
204 test-tool chmtime --get c >new-mtime &&
205 test $(cat old-mtime) -lt $(cat new-mtime) &&
206
207 test_must_be_empty err &&
208
209 git ls-files -s >index_files &&
210 test_line_count = 1 index_files &&
211
212 git rev-parse >actual HEAD:c &&
213 git rev-parse >expect A:b &&
214 test_cmp expect actual &&
215
216 git hash-object c >actual &&
217 git rev-parse A:b >expect &&
218 test_cmp expect actual &&
219
220 test_must_fail git rev-parse HEAD:b &&
221 test_path_is_missing b
222 )
223 '
224
225 # Testcase 2b, Changed and renamed on A, subset of changes on B
226 # Commit O: b_1
227 # Commit A: c_2
228 # Commit B: b_3
229 # Expected: c_2
230
231 test_setup_2b () {
232 test_create_repo 2b_$1 &&
233 (
234 cd 2b_$1 &&
235
236 test_write_lines 1 2 3 4 5 6 7 8 9 10 >b &&
237 git add b &&
238 test_tick &&
239 git commit -m "O" &&
240
241 git branch O &&
242 git branch A &&
243 git branch B &&
244
245 git checkout A &&
246 test_write_lines 1 2 3 4 5 5.5 6 7 8 9 10 10.5 >b &&
247 git add b &&
248 git mv b c &&
249 test_tick &&
250 git commit -m "A" &&
251
252 git checkout B &&
253 test_write_lines 1 2 3 4 5 5.5 6 7 8 9 10 >b &&
254 git add b &&
255 test_tick &&
256 git commit -m "B"
257 )
258 }
259
260 test_expect_success '2b-L: Rename+Mod(A)/Mod(B), B mods subset of A' '
261 test_setup_2b L &&
262 (
263 cd 2b_L &&
264
265 git checkout A^0 &&
266
267 test-tool chmtime --get -3600 c >old-mtime &&
268 GIT_MERGE_VERBOSITY=3 git merge -s recursive B^0 >out 2>err &&
269
270 test_must_be_empty err &&
271
272 # Make sure c WAS updated
273 test-tool chmtime --get c >new-mtime &&
274 test_cmp old-mtime new-mtime &&
275
276 git ls-files -s >index_files &&
277 test_line_count = 1 index_files &&
278
279 git rev-parse >actual HEAD:c &&
280 git rev-parse >expect A:c &&
281 test_cmp expect actual &&
282
283 git hash-object c >actual &&
284 git rev-parse A:c >expect &&
285 test_cmp expect actual &&
286
287 test_must_fail git rev-parse HEAD:b &&
288 test_path_is_missing b
289 )
290 '
291
292 test_expect_success '2b-R: Rename+Mod(A)/Mod(B), B mods subset of A' '
293 test_setup_2b R &&
294 (
295 cd 2b_R &&
296
297 git checkout B^0 &&
298
299 test_path_is_missing c &&
300 GIT_MERGE_VERBOSITY=3 git merge -s recursive A^0 >out 2>err &&
301
302 # Make sure c now present (and thus was updated)
303 test_path_is_file c &&
304
305 test_must_be_empty err &&
306
307 git ls-files -s >index_files &&
308 test_line_count = 1 index_files &&
309
310 git rev-parse >actual HEAD:c &&
311 git rev-parse >expect A:c &&
312 test_cmp expect actual &&
313
314 git hash-object c >actual &&
315 git rev-parse A:c >expect &&
316 test_cmp expect actual &&
317
318 test_must_fail git rev-parse HEAD:b &&
319 test_path_is_missing b
320 )
321 '
322
323 # Testcase 2c, Changes on A, rename on B
324 # Commit O: b_1
325 # Commit A: b_2, c_3
326 # Commit B: c_1
327 # Expected: rename/add conflict c_2 vs c_3
328 #
329 # NOTE: Since A modified b_1->b_2, and B renamed b_1->c_1, the threeway
330 # merge of those files should result in c_2. We then should have a
331 # rename/add conflict between c_2 and c_3. However, if we note in
332 # merge_content() that A had the right contents (b_2 has same
333 # contents as c_2, just at a different name), and that A had the
334 # right path present (c_3 existed) and thus decides that it can
335 # skip the update, then we're in trouble. This test verifies we do
336 # not make that particular mistake.
337
338 test_setup_2c () {
339 test_create_repo 2c &&
340 (
341 cd 2c &&
342
343 test_seq 1 10 >b &&
344 git add b &&
345 test_tick &&
346 git commit -m "O" &&
347
348 git branch O &&
349 git branch A &&
350 git branch B &&
351
352 git checkout A &&
353 test_seq 1 11 >b &&
354 echo whatever >c &&
355 git add b c &&
356 test_tick &&
357 git commit -m "A" &&
358
359 git checkout B &&
360 git mv b c &&
361 test_tick &&
362 git commit -m "B"
363 )
364 }
365
366 test_expect_success '2c: Modify b & add c VS rename b->c' '
367 test_setup_2c &&
368 (
369 cd 2c &&
370
371 git checkout A^0 &&
372
373 test-tool chmtime --get -3600 c >old-mtime &&
374 GIT_MERGE_VERBOSITY=3 &&
375 export GIT_MERGE_VERBOSITY &&
376 test_must_fail git merge -s recursive B^0 >out 2>err &&
377
378 test_i18ngrep "CONFLICT (.*/add):" out &&
379 test_must_be_empty err &&
380
381 # Make sure c WAS updated
382 test-tool chmtime --get c >new-mtime &&
383 test $(cat old-mtime) -lt $(cat new-mtime)
384
385 # FIXME: rename/add conflicts are horribly broken right now;
386 # when I get back to my patch series fixing it and
387 # rename/rename(2to1) conflicts to bring them in line with
388 # how add/add conflicts behave, then checks like the below
389 # could be added. But that patch series is waiting until
390 # the rename-directory-detection series lands, which this
391 # is part of. And in the mean time, I do not want to further
392 # enforce broken behavior. So for now, the main test is the
393 # one above that err is an empty file.
394
395 #git ls-files -s >index_files &&
396 #test_line_count = 2 index_files &&
397
398 #git rev-parse >actual :2:c :3:c &&
399 #git rev-parse >expect A:b A:c &&
400 #test_cmp expect actual &&
401
402 #git cat-file -p A:b >>merged &&
403 #git cat-file -p A:c >>merge-me &&
404 #>empty &&
405 #test_must_fail git merge-file \
406 # -L "Temporary merge branch 1" \
407 # -L "" \
408 # -L "Temporary merge branch 2" \
409 # merged empty merge-me &&
410 #sed -e "s/^\([<=>]\)/\1\1\1/" merged >merged-internal &&
411
412 #git hash-object c >actual &&
413 #git hash-object merged-internal >expect &&
414 #test_cmp expect actual &&
415
416 #test_path_is_missing b
417 )
418 '
419
420
421 ###########################################################################
422 # SECTION 3: Cases involving directory renames
423 #
424 # NOTE:
425 # Directory renames only apply when one side renames a directory, and the
426 # other side adds or renames a path into that directory. Applying the
427 # directory rename to that new path creates a new pathname that didn't
428 # exist on either side of history. Thus, it is impossible for the
429 # merge contents to already be at the right path, so all of these checks
430 # exist just to make sure that updates are not skipped.
431 ###########################################################################
432
433 # Testcase 3a, Change + rename into dir foo on A, dir rename foo->bar on B
434 # Commit O: bq_1, foo/whatever
435 # Commit A: foo/{bq_2, whatever}
436 # Commit B: bq_1, bar/whatever
437 # Expected: bar/{bq_2, whatever}
438
439 test_setup_3a () {
440 test_create_repo 3a_$1 &&
441 (
442 cd 3a_$1 &&
443
444 mkdir foo &&
445 test_seq 1 10 >bq &&
446 test_write_lines a b c d e f g h i j k >foo/whatever &&
447 git add bq foo/whatever &&
448 test_tick &&
449 git commit -m "O" &&
450
451 git branch O &&
452 git branch A &&
453 git branch B &&
454
455 git checkout A &&
456 test_seq 1 11 >bq &&
457 git add bq &&
458 git mv bq foo/ &&
459 test_tick &&
460 git commit -m "A" &&
461
462 git checkout B &&
463 git mv foo/ bar/ &&
464 test_tick &&
465 git commit -m "B"
466 )
467 }
468
469 test_expect_success '3a-L: bq_1->foo/bq_2 on A, foo/->bar/ on B' '
470 test_setup_3a L &&
471 (
472 cd 3a_L &&
473
474 git checkout A^0 &&
475
476 test_path_is_missing bar/bq &&
477 GIT_MERGE_VERBOSITY=3 git -c merge.directoryRenames=true merge -s recursive B^0 >out 2>err &&
478
479 test_must_be_empty err &&
480
481 test_path_is_file bar/bq &&
482
483 git ls-files -s >index_files &&
484 test_line_count = 2 index_files &&
485
486 git rev-parse >actual HEAD:bar/bq HEAD:bar/whatever &&
487 git rev-parse >expect A:foo/bq A:foo/whatever &&
488 test_cmp expect actual &&
489
490 git hash-object bar/bq bar/whatever >actual &&
491 git rev-parse A:foo/bq A:foo/whatever >expect &&
492 test_cmp expect actual &&
493
494 test_must_fail git rev-parse HEAD:bq HEAD:foo/bq &&
495 test_path_is_missing bq foo/bq foo/whatever
496 )
497 '
498
499 test_expect_success '3a-R: bq_1->foo/bq_2 on A, foo/->bar/ on B' '
500 test_setup_3a R &&
501 (
502 cd 3a_R &&
503
504 git checkout B^0 &&
505
506 test_path_is_missing bar/bq &&
507 GIT_MERGE_VERBOSITY=3 git -c merge.directoryRenames=true merge -s recursive A^0 >out 2>err &&
508
509 test_must_be_empty err &&
510
511 test_path_is_file bar/bq &&
512
513 git ls-files -s >index_files &&
514 test_line_count = 2 index_files &&
515
516 git rev-parse >actual HEAD:bar/bq HEAD:bar/whatever &&
517 git rev-parse >expect A:foo/bq A:foo/whatever &&
518 test_cmp expect actual &&
519
520 git hash-object bar/bq bar/whatever >actual &&
521 git rev-parse A:foo/bq A:foo/whatever >expect &&
522 test_cmp expect actual &&
523
524 test_must_fail git rev-parse HEAD:bq HEAD:foo/bq &&
525 test_path_is_missing bq foo/bq foo/whatever
526 )
527 '
528
529 # Testcase 3b, rename into dir foo on A, dir rename foo->bar + change on B
530 # Commit O: bq_1, foo/whatever
531 # Commit A: foo/{bq_1, whatever}
532 # Commit B: bq_2, bar/whatever
533 # Expected: bar/{bq_2, whatever}
534
535 test_setup_3b () {
536 test_create_repo 3b_$1 &&
537 (
538 cd 3b_$1 &&
539
540 mkdir foo &&
541 test_seq 1 10 >bq &&
542 test_write_lines a b c d e f g h i j k >foo/whatever &&
543 git add bq foo/whatever &&
544 test_tick &&
545 git commit -m "O" &&
546
547 git branch O &&
548 git branch A &&
549 git branch B &&
550
551 git checkout A &&
552 git mv bq foo/ &&
553 test_tick &&
554 git commit -m "A" &&
555
556 git checkout B &&
557 test_seq 1 11 >bq &&
558 git add bq &&
559 git mv foo/ bar/ &&
560 test_tick &&
561 git commit -m "B"
562 )
563 }
564
565 test_expect_success '3b-L: bq_1->foo/bq_2 on A, foo/->bar/ on B' '
566 test_setup_3b L &&
567 (
568 cd 3b_L &&
569
570 git checkout A^0 &&
571
572 test_path_is_missing bar/bq &&
573 GIT_MERGE_VERBOSITY=3 git -c merge.directoryRenames=true merge -s recursive B^0 >out 2>err &&
574
575 test_must_be_empty err &&
576
577 test_path_is_file bar/bq &&
578
579 git ls-files -s >index_files &&
580 test_line_count = 2 index_files &&
581
582 git rev-parse >actual HEAD:bar/bq HEAD:bar/whatever &&
583 git rev-parse >expect B:bq A:foo/whatever &&
584 test_cmp expect actual &&
585
586 git hash-object bar/bq bar/whatever >actual &&
587 git rev-parse B:bq A:foo/whatever >expect &&
588 test_cmp expect actual &&
589
590 test_must_fail git rev-parse HEAD:bq HEAD:foo/bq &&
591 test_path_is_missing bq foo/bq foo/whatever
592 )
593 '
594
595 test_expect_success '3b-R: bq_1->foo/bq_2 on A, foo/->bar/ on B' '
596 test_setup_3b R &&
597 (
598 cd 3b_R &&
599
600 git checkout B^0 &&
601
602 test_path_is_missing bar/bq &&
603 GIT_MERGE_VERBOSITY=3 git -c merge.directoryRenames=true merge -s recursive A^0 >out 2>err &&
604
605 test_must_be_empty err &&
606
607 test_path_is_file bar/bq &&
608
609 git ls-files -s >index_files &&
610 test_line_count = 2 index_files &&
611
612 git rev-parse >actual HEAD:bar/bq HEAD:bar/whatever &&
613 git rev-parse >expect B:bq A:foo/whatever &&
614 test_cmp expect actual &&
615
616 git hash-object bar/bq bar/whatever >actual &&
617 git rev-parse B:bq A:foo/whatever >expect &&
618 test_cmp expect actual &&
619
620 test_must_fail git rev-parse HEAD:bq HEAD:foo/bq &&
621 test_path_is_missing bq foo/bq foo/whatever
622 )
623 '
624
625 ###########################################################################
626 # SECTION 4: Cases involving dirty changes
627 ###########################################################################
628
629 # Testcase 4a, Changed on A, subset of changes on B, locally modified
630 # Commit O: b_1
631 # Commit A: b_2
632 # Commit B: b_3
633 # Working copy: b_4
634 # Expected: b_2 for merge, b_4 in working copy
635
636 test_setup_4a () {
637 test_create_repo 4a &&
638 (
639 cd 4a &&
640
641 test_write_lines 1 2 3 4 5 6 7 8 9 10 >b &&
642 git add b &&
643 test_tick &&
644 git commit -m "O" &&
645
646 git branch O &&
647 git branch A &&
648 git branch B &&
649
650 git checkout A &&
651 test_write_lines 1 2 3 4 5 5.5 6 7 8 9 10 10.5 >b &&
652 git add b &&
653 test_tick &&
654 git commit -m "A" &&
655
656 git checkout B &&
657 test_write_lines 1 2 3 4 5 5.5 6 7 8 9 10 >b &&
658 git add b &&
659 test_tick &&
660 git commit -m "B"
661 )
662 }
663
664 # NOTE: For as long as we continue using unpack_trees() without index_only
665 # set to true, it will error out on a case like this claiming that the locally
666 # modified file would be overwritten by the merge. Getting this testcase
667 # correct requires doing the merge in-memory first, then realizing that no
668 # updates to the file are necessary, and thus that we can just leave the path
669 # alone.
670 test_expect_merge_algorithm failure success '4a: Change on A, change on B subset of A, dirty mods present' '
671 test_setup_4a &&
672 (
673 cd 4a &&
674
675 git checkout A^0 &&
676 echo "File rewritten" >b &&
677
678 test-tool chmtime --get -3600 b >old-mtime &&
679
680 GIT_MERGE_VERBOSITY=3 git merge -s recursive B^0 >out 2>err &&
681
682 test_must_be_empty err &&
683
684 # Make sure b was NOT updated
685 test-tool chmtime --get b >new-mtime &&
686 test_cmp old-mtime new-mtime &&
687
688 git ls-files -s >index_files &&
689 test_line_count = 1 index_files &&
690
691 git rev-parse >actual :0:b &&
692 git rev-parse >expect A:b &&
693 test_cmp expect actual &&
694
695 git hash-object b >actual &&
696 echo "File rewritten" | git hash-object --stdin >expect &&
697 test_cmp expect actual
698 )
699 '
700
701 # Testcase 4b, Changed+renamed on A, subset of changes on B, locally modified
702 # Commit O: b_1
703 # Commit A: c_2
704 # Commit B: b_3
705 # Working copy: c_4
706 # Expected: c_2
707
708 test_setup_4b () {
709 test_create_repo 4b &&
710 (
711 cd 4b &&
712
713 test_write_lines 1 2 3 4 5 6 7 8 9 10 >b &&
714 git add b &&
715 test_tick &&
716 git commit -m "O" &&
717
718 git branch O &&
719 git branch A &&
720 git branch B &&
721
722 git checkout A &&
723 test_write_lines 1 2 3 4 5 5.5 6 7 8 9 10 10.5 >b &&
724 git add b &&
725 git mv b c &&
726 test_tick &&
727 git commit -m "A" &&
728
729 git checkout B &&
730 test_write_lines 1 2 3 4 5 5.5 6 7 8 9 10 >b &&
731 git add b &&
732 test_tick &&
733 git commit -m "B"
734 )
735 }
736
737 test_expect_success '4b: Rename+Mod(A)/Mod(B), change on B subset of A, dirty mods present' '
738 test_setup_4b &&
739 (
740 cd 4b &&
741
742 git checkout A^0 &&
743 echo "File rewritten" >c &&
744
745 test-tool chmtime --get -3600 c >old-mtime &&
746
747 GIT_MERGE_VERBOSITY=3 git merge -s recursive B^0 >out 2>err &&
748
749 test_must_be_empty err &&
750
751 # Make sure c was NOT updated
752 test-tool chmtime --get c >new-mtime &&
753 test_cmp old-mtime new-mtime &&
754
755 git ls-files -s >index_files &&
756 test_line_count = 1 index_files &&
757
758 git rev-parse >actual :0:c &&
759 git rev-parse >expect A:c &&
760 test_cmp expect actual &&
761
762 git hash-object c >actual &&
763 echo "File rewritten" | git hash-object --stdin >expect &&
764 test_cmp expect actual &&
765
766 test_must_fail git rev-parse HEAD:b &&
767 test_path_is_missing b
768 )
769 '
770
771 test_done