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