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