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