t6046: testcases checking whether updates can be skipped in a merge

Add several tests checking whether updates can be skipped in a merge. Also add several similar testcases for where updates cannot be skipped in a merge to make sure that we skip if and only if we should. In particular: * Testcase 1a (particularly 1a-check-L) would have pointed out the problem Linus has been dealing with for year with his merges[1]. * Testcase 2a (particularly 2a-check-L) would have pointed out the problem with my directory-rename-series before it broke master[2]. * Testcases 3[ab] (particularly 3a-check-L) provide a simpler testcase than 12b of t6043 making that one easier to understand. * There are several complementary testcases to make sure we're not just fixing those particular issues while regressing in the opposite direction. * There are also a pair of tests for the special case when a merge results in a skippable update AND the user has dirty modifications to the path. [1] https://public-inbox.org/git/CA+55aFzLZ3UkG5svqZwSnhNk75=fXJRkvU1m_RHBG54NOoaZPA@mail.gmail.com/ [2] https://public-inbox.org/git/xmqqmuya43cs.fsf@gitster-ct.c.googlers.com/ Signed-off-by: Elijah Newren <newren@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Elijah Newren committed Apr 19, 2018 at 10:58 UTC c04ba51739a7771583e31966adb7c472980f3fc3
1 file changed +761
t/t6046-merge-skip-unneeded-updates.sh new
+761
@@ -0,0 +1,761 @@
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_failure '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_failure '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_failure '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 test_must_fail git merge -s recursive B^0 >out 2>err &&
370 +
371 + test_i18ngrep "CONFLICT (rename/add): Rename b->c" out &&
372 + test_i18ngrep ! "Skipped c" out &&
373 + test_must_be_empty err
374 +
375 + # FIXME: rename/add conflicts are horribly broken right now;
376 + # when I get back to my patch series fixing it and
377 + # rename/rename(2to1) conflicts to bring them in line with
378 + # how add/add conflicts behave, then checks like the below
379 + # could be added. But that patch series is waiting until
380 + # the rename-directory-detection series lands, which this
381 + # is part of. And in the mean time, I do not want to further
382 + # enforce broken behavior. So for now, the main test is the
383 + # one above that err is an empty file.
384 +
385 + #git ls-files -s >index_files &&
386 + #test_line_count = 2 index_files &&
387 +
388 + #git rev-parse >actual :2:c :3:c &&
389 + #git rev-parse >expect A:b A:c &&
390 + #test_cmp expect actual &&
391 +
392 + #git cat-file -p A:b >>merged &&
393 + #git cat-file -p A:c >>merge-me &&
394 + #>empty &&
395 + #test_must_fail git merge-file \
396 + # -L "Temporary merge branch 1" \
397 + # -L "" \
398 + # -L "Temporary merge branch 2" \
399 + # merged empty merge-me &&
400 + #sed -e "s/^\([<=>]\)/\1\1\1/" merged >merged-internal &&
401 +
402 + #git hash-object c >actual &&
403 + #git hash-object merged-internal >expect &&
404 + #test_cmp expect actual &&
405 +
406 + #test_path_is_missing b
407 + )
408 +'
409 +
410 +
411 +###########################################################################
412 +# SECTION 3: Cases involving directory renames
413 +#
414 +# NOTE:
415 +# Directory renames only apply when one side renames a directory, and the
416 +# other side adds or renames a path into that directory. Applying the
417 +# directory rename to that new path creates a new pathname that didn't
418 +# exist on either side of history. Thus, it is impossible for the
419 +# merge contents to already be at the right path, so all of these checks
420 +# exist just to make sure that updates are not skipped.
421 +###########################################################################
422 +
423 +# Testcase 3a, Change + rename into dir foo on A, dir rename foo->bar on B
424 +# Commit O: bq_1, foo/whatever
425 +# Commit A: foo/{bq_2, whatever}
426 +# Commit B: bq_1, bar/whatever
427 +# Expected: bar/{bq_2, whatever}
428 +
429 +test_expect_success '3a-setup: bq_1->foo/bq_2 on A, foo/->bar/ on B' '
430 + test_create_repo 3a &&
431 + (
432 + cd 3a &&
433 +
434 + mkdir foo &&
435 + test_seq 1 10 >bq &&
436 + test_write_lines a b c d e f g h i j k >foo/whatever &&
437 + git add bq foo/whatever &&
438 + test_tick &&
439 + git commit -m "O" &&
440 +
441 + git branch O &&
442 + git branch A &&
443 + git branch B &&
444 +
445 + git checkout A &&
446 + test_seq 1 11 >bq &&
447 + git add bq &&
448 + git mv bq foo/ &&
449 + test_tick &&
450 + git commit -m "A" &&
451 +
452 + git checkout B &&
453 + git mv foo/ bar/ &&
454 + test_tick &&
455 + git commit -m "B"
456 + )
457 +'
458 +
459 +test_expect_failure '3a-check-L: bq_1->foo/bq_2 on A, foo/->bar/ on B' '
460 + test_when_finished "git -C 3a reset --hard" &&
461 + test_when_finished "git -C 3a clean -fd" &&
462 + (
463 + cd 3a &&
464 +
465 + git checkout A^0 &&
466 +
467 + GIT_MERGE_VERBOSITY=3 git merge -s recursive B^0 >out 2>err &&
468 +
469 + test_i18ngrep ! "Skipped bar/bq" out &&
470 + test_must_be_empty err &&
471 +
472 + git ls-files -s >index_files &&
473 + test_line_count = 2 index_files &&
474 +
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 &&
478 +
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 &&
482 +
483 + test_must_fail git rev-parse HEAD:bq HEAD:foo/bq &&
484 + test_path_is_missing bq foo/bq foo/whatever
485 + )
486 +'
487 +
488 +test_expect_success '3a-check-R: bq_1->foo/bq_2 on A, foo/->bar/ on B' '
489 + test_when_finished "git -C 3a reset --hard" &&
490 + test_when_finished "git -C 3a clean -fd" &&
491 + (
492 + cd 3a &&
493 +
494 + git checkout B^0 &&
495 +
496 + GIT_MERGE_VERBOSITY=3 git merge -s recursive A^0 >out 2>err &&
497 +
498 + test_i18ngrep ! "Skipped bar/bq" out &&
499 + test_must_be_empty err &&
500 +
501 + git ls-files -s >index_files &&
502 + test_line_count = 2 index_files &&
503 +
504 + git rev-parse >actual HEAD:bar/bq HEAD:bar/whatever &&
505 + git rev-parse >expect A:foo/bq A:foo/whatever &&
506 + test_cmp expect actual &&
507 +
508 + git hash-object bar/bq bar/whatever >actual &&
509 + git rev-parse A:foo/bq A:foo/whatever >expect &&
510 + test_cmp expect actual &&
511 +
512 + test_must_fail git rev-parse HEAD:bq HEAD:foo/bq &&
513 + test_path_is_missing bq foo/bq foo/whatever
514 + )
515 +'
516 +
517 +# Testcase 3b, rename into dir foo on A, dir rename foo->bar + change on B
518 +# Commit O: bq_1, foo/whatever
519 +# Commit A: foo/{bq_1, whatever}
520 +# Commit B: bq_2, bar/whatever
521 +# Expected: bar/{bq_2, whatever}
522 +
523 +test_expect_success '3b-setup: bq_1->foo/bq_2 on A, foo/->bar/ on B' '
524 + test_create_repo 3b &&
525 + (
526 + cd 3b &&
527 +
528 + mkdir foo &&
529 + test_seq 1 10 >bq &&
530 + test_write_lines a b c d e f g h i j k >foo/whatever &&
531 + git add bq foo/whatever &&
532 + test_tick &&
533 + git commit -m "O" &&
534 +
535 + git branch O &&
536 + git branch A &&
537 + git branch B &&
538 +
539 + git checkout A &&
540 + git mv bq foo/ &&
541 + test_tick &&
542 + git commit -m "A" &&
543 +
544 + git checkout B &&
545 + test_seq 1 11 >bq &&
546 + git add bq &&
547 + git mv foo/ bar/ &&
548 + test_tick &&
549 + git commit -m "B"
550 + )
551 +'
552 +
553 +test_expect_success '3b-check-L: bq_1->foo/bq_2 on A, foo/->bar/ on B' '
554 + test_when_finished "git -C 3b reset --hard" &&
555 + test_when_finished "git -C 3b clean -fd" &&
556 + (
557 + cd 3b &&
558 +
559 + git checkout A^0 &&
560 +
561 + GIT_MERGE_VERBOSITY=3 git merge -s recursive B^0 >out 2>err &&
562 +
563 + test_i18ngrep ! "Skipped bar/bq" out &&
564 + test_must_be_empty err &&
565 +
566 + git ls-files -s >index_files &&
567 + test_line_count = 2 index_files &&
568 +
569 + git rev-parse >actual HEAD:bar/bq HEAD:bar/whatever &&
570 + git rev-parse >expect B:bq A:foo/whatever &&
571 + test_cmp expect actual &&
572 +
573 + git hash-object bar/bq bar/whatever >actual &&
574 + git rev-parse B:bq A:foo/whatever >expect &&
575 + test_cmp expect actual &&
576 +
577 + test_must_fail git rev-parse HEAD:bq HEAD:foo/bq &&
578 + test_path_is_missing bq foo/bq foo/whatever
579 + )
580 +'
581 +
582 +test_expect_failure '3b-check-R: bq_1->foo/bq_2 on A, foo/->bar/ on B' '
583 + test_when_finished "git -C 3b reset --hard" &&
584 + test_when_finished "git -C 3b clean -fd" &&
585 + (
586 + cd 3b &&
587 +
588 + git checkout B^0 &&
589 +
590 + GIT_MERGE_VERBOSITY=3 git merge -s recursive A^0 >out 2>err &&
591 +
592 + test_i18ngrep ! "Skipped bar/bq" out &&
593 + test_must_be_empty err &&
594 +
595 + git ls-files -s >index_files &&
596 + test_line_count = 2 index_files &&
597 +
598 + git rev-parse >actual HEAD:bar/bq HEAD:bar/whatever &&
599 + git rev-parse >expect B:bq A:foo/whatever &&
600 + test_cmp expect actual &&
601 +
602 + git hash-object bar/bq bar/whatever >actual &&
603 + git rev-parse B:bq A:foo/whatever >expect &&
604 + test_cmp expect actual &&
605 +
606 + test_must_fail git rev-parse HEAD:bq HEAD:foo/bq &&
607 + test_path_is_missing bq foo/bq foo/whatever
608 + )
609 +'
610 +
611 +###########################################################################
612 +# SECTION 4: Cases involving dirty changes
613 +###########################################################################
614 +
615 +# Testcase 4a, Changed on A, subset of changes on B, locally modified
616 +# Commit O: b_1
617 +# Commit A: b_2
618 +# Commit B: b_3
619 +# Working copy: b_4
620 +# Expected: b_2 for merge, b_4 in working copy
621 +
622 +test_expect_success '4a-setup: Change on A, change on B subset of A, dirty mods present' '
623 + test_create_repo 4a &&
624 + (
625 + cd 4a &&
626 +
627 + test_write_lines 1 2 3 4 5 6 7 8 9 10 >b &&
628 + git add b &&
629 + test_tick &&
630 + git commit -m "O" &&
631 +
632 + git branch O &&
633 + git branch A &&
634 + git branch B &&
635 +
636 + git checkout A &&
637 + test_write_lines 1 2 3 4 5 5.5 6 7 8 9 10 10.5 >b &&
638 + git add b &&
639 + test_tick &&
640 + git commit -m "A" &&
641 +
642 + git checkout B &&
643 + test_write_lines 1 2 3 4 5 5.5 6 7 8 9 10 >b &&
644 + git add b &&
645 + test_tick &&
646 + git commit -m "B"
647 + )
648 +'
649 +
650 +# NOTE: For as long as we continue using unpack_trees() without index_only
651 +# set to true, it will error out on a case like this claiming the the locally
652 +# modified file would be overwritten by the merge. Getting this testcase
653 +# correct requires doing the merge in-memory first, then realizing that no
654 +# updates to the file are necessary, and thus that we can just leave the path
655 +# alone.
656 +test_expect_failure '4a-check: Change on A, change on B subset of A, dirty mods present' '
657 + test_when_finished "git -C 4a reset --hard" &&
658 + test_when_finished "git -C 4a clean -fd" &&
659 + (
660 + cd 4a &&
661 +
662 + git checkout A^0 &&
663 + echo "File rewritten" >b &&
664 +
665 + test-tool chmtime =31337 b &&
666 + test-tool chmtime -v +0 b >expected-mtime &&
667 +
668 + GIT_MERGE_VERBOSITY=3 git merge -s recursive B^0 >out 2>err &&
669 +
670 + test_i18ngrep "Skipped b" out &&
671 + test_must_be_empty err &&
672 +
673 + test-tool chmtime -v +0 b >actual-mtime &&
674 + test_cmp expected-mtime actual-mtime &&
675 +
676 + git ls-files -s >index_files &&
677 + test_line_count = 1 index_files &&
678 +
679 + git rev-parse >actual :0:b &&
680 + git rev-parse >expect A:b &&
681 + test_cmp expect actual &&
682 +
683 + git hash-object b >actual &&
684 + echo "File rewritten" | git hash-object --stdin >expect &&
685 + test_cmp expect actual
686 + )
687 +'
688 +
689 +# Testcase 4b, Changed+renamed on A, subset of changes on B, locally modified
690 +# Commit O: b_1
691 +# Commit A: c_2
692 +# Commit B: b_3
693 +# Working copy: c_4
694 +# Expected: c_2
695 +
696 +test_expect_success '4b-setup: Rename+Mod(A)/Mod(B), change on B subset of A, dirty mods present' '
697 + test_create_repo 4b &&
698 + (
699 + cd 4b &&
700 +
701 + test_write_lines 1 2 3 4 5 6 7 8 9 10 >b &&
702 + git add b &&
703 + test_tick &&
704 + git commit -m "O" &&
705 +
706 + git branch O &&
707 + git branch A &&
708 + git branch B &&
709 +
710 + git checkout A &&
711 + test_write_lines 1 2 3 4 5 5.5 6 7 8 9 10 10.5 >b &&
712 + git add b &&
713 + git mv b c &&
714 + test_tick &&
715 + git commit -m "A" &&
716 +
717 + git checkout B &&
718 + test_write_lines 1 2 3 4 5 5.5 6 7 8 9 10 >b &&
719 + git add b &&
720 + test_tick &&
721 + git commit -m "B"
722 + )
723 +'
724 +
725 +test_expect_success '4b-check: Rename+Mod(A)/Mod(B), change on B subset of A, dirty mods present' '
726 + test_when_finished "git -C 4b reset --hard" &&
727 + test_when_finished "git -C 4b clean -fd" &&
728 + (
729 + cd 4b &&
730 +
731 + git checkout A^0 &&
732 + echo "File rewritten" >c &&
733 +
734 + test-tool chmtime =31337 c &&
735 + test-tool chmtime -v +0 c >expected-mtime &&
736 +
737 + GIT_MERGE_VERBOSITY=3 git merge -s recursive B^0 >out 2>err &&
738 +
739 + test_i18ngrep "Skipped c" out &&
740 + test_must_be_empty err &&
741 +
742 + test-tool chmtime -v +0 c >actual-mtime &&
743 + test_cmp expected-mtime actual-mtime &&
744 +
745 + git ls-files -s >index_files &&
746 + test_line_count = 1 index_files &&
747 +
748 + git rev-parse >actual :0:c &&
749 + git rev-parse >expect A:c &&
750 + test_cmp expect actual &&
751 +
752 + git hash-object c >actual &&
753 + echo "File rewritten" | git hash-object --stdin >expect &&
754 + test_cmp expect actual &&
755 +
756 + test_must_fail git rev-parse HEAD:b &&
757 + test_path_is_missing b
758 + )
759 +'
760 +
761 +test_done