Raw
1 #!/bin/sh
2
3 test_description="remember regular & dir renames in sequence of merges"
4
5 . ./test-lib.sh
6
7 #
8 # NOTE 1: this testfile tends to not only rename files, but modify on both
9 # sides; without modifying on both sides, optimizations can kick in
10 # which make rename detection irrelevant or trivial. We want to make
11 # sure that we are triggering rename caching rather than rename
12 # bypassing.
13 #
14 # NOTE 2: this testfile uses replay instead of either cherry-pick or rebase.
15 # sequencer.c is only superficially integrated with merge-ort; it
16 # calls merge_switch_to_result() after EACH merge, which updates the
17 # index and working copy AND throws away the cached results (because
18 # merge_switch_to_result() is only supposed to be called at the end
19 # of the sequence). Integrating them more deeply is a big task, so
20 # for now the tests use 'git replay'.
21 #
22
23
24 #
25 # In the following simple testcase:
26 # Base: numbers_1, values_1
27 # Upstream: numbers_2, values_2
28 # Topic_1: sequence_3
29 # Topic_2: scruples_3
30 # or, in english, rename numbers -> sequence in the first commit, and rename
31 # values -> scruples in the second commit.
32 #
33 # This shouldn't be a challenge, it's just verifying that cached renames isn't
34 # preventing us from finding new renames.
35 #
36 test_expect_success 'caching renames does not preclude finding new ones' '
37 git init caching-renames-and-new-renames &&
38 (
39 cd caching-renames-and-new-renames &&
40
41 test_seq 2 10 >numbers &&
42 test_seq 2 10 >values &&
43 git add numbers values &&
44 git commit -m orig &&
45
46 git branch upstream &&
47 git branch topic &&
48
49 git switch upstream &&
50 test_seq 1 10 >numbers &&
51 test_seq 1 10 >values &&
52 git add numbers values &&
53 git commit -m "Tweaked both files" &&
54
55 git switch topic &&
56
57 test_seq 2 12 >numbers &&
58 git add numbers &&
59 git mv numbers sequence &&
60 git commit -m A &&
61
62 test_seq 2 12 >values &&
63 git add values &&
64 git mv values scruples &&
65 git commit -m B &&
66
67 #
68 # Actual testing
69 #
70
71 git switch upstream &&
72
73 git replay --onto HEAD upstream~1..topic >out &&
74 git update-ref --stdin <out &&
75 git checkout topic &&
76
77 git ls-files >tracked-files &&
78 test_line_count = 2 tracked-files &&
79 test_seq 1 12 >expect &&
80 test_cmp expect sequence &&
81 test_cmp expect scruples
82 )
83 '
84
85 #
86 # In the following testcase:
87 # Base: numbers_1
88 # Upstream: rename numbers_1 -> sequence_2
89 # Topic_1: numbers_3
90 # Topic_2: numbers_1
91 # or, in english, the first commit on the topic branch modifies numbers by
92 # shrinking it (dramatically) and the second commit on topic reverts its
93 # parent.
94 #
95 # Can git apply both patches?
96 #
97 # Traditional cherry-pick/rebase will fail to apply the second commit, the
98 # one that reverted its parent, because despite detecting the rename from
99 # 'numbers' to 'sequence' for the first commit, it fails to detect that
100 # rename when picking the second commit. That's "reasonable" given the
101 # dramatic change in size of the file, but remembering the rename and
102 # reusing it is reasonable too.
103 #
104 # We do test here that we expect rename detection to only be run once total
105 # (the topic side of history doesn't need renames, and with caching we
106 # should be able to only run rename detection on the upstream side one
107 # time.)
108 test_expect_success 'cherry-pick both a commit and its immediate revert' '
109 git init pick-commit-and-its-immediate-revert &&
110 (
111 cd pick-commit-and-its-immediate-revert &&
112
113 test_seq 11 30 >numbers &&
114 git add numbers &&
115 git commit -m orig &&
116
117 git branch upstream &&
118 git branch topic &&
119
120 git switch upstream &&
121 test_seq 1 30 >numbers &&
122 git add numbers &&
123 git mv numbers sequence &&
124 git commit -m "Renamed (and modified) numbers -> sequence" &&
125
126 git switch topic &&
127
128 test_seq 11 13 >numbers &&
129 git add numbers &&
130 git commit -m A &&
131
132 git revert HEAD &&
133
134 #
135 # Actual testing
136 #
137
138 git switch upstream &&
139
140 GIT_TRACE2_PERF="$(pwd)/trace.output" &&
141 export GIT_TRACE2_PERF &&
142
143 git replay --onto HEAD upstream~1..topic >out &&
144 git update-ref --stdin <out &&
145 git checkout topic &&
146
147 grep region_enter.*diffcore_rename trace.output >calls &&
148 test_line_count = 1 calls
149 )
150 '
151
152 #
153 # In the following testcase:
154 # Base: sequence_1
155 # Upstream: rename sequence_1 -> values_2
156 # Topic_1: rename sequence_1 -> values_3
157 # Topic_2: add unrelated sequence_4
158 # or, in english, both sides rename sequence -> values, and then the second
159 # commit on the topic branch adds an unrelated file called sequence.
160 #
161 # This testcase presents no problems for git traditionally, but having both
162 # sides do the same rename in effect "uses it up" and if it remains cached,
163 # could cause a spurious rename/add conflict.
164 #
165 test_expect_success 'rename same file identically, then reintroduce it' '
166 git init rename-rename-1to1-then-add-old-filename &&
167 (
168 cd rename-rename-1to1-then-add-old-filename &&
169
170 test_seq 3 8 >sequence &&
171 git add sequence &&
172 git commit -m orig &&
173
174 git branch upstream &&
175 git branch topic &&
176
177 git switch upstream &&
178 test_seq 1 8 >sequence &&
179 git add sequence &&
180 git mv sequence values &&
181 git commit -m "Renamed (and modified) sequence -> values" &&
182
183 git switch topic &&
184
185 test_seq 3 10 >sequence &&
186 git add sequence &&
187 git mv sequence values &&
188 git commit -m A &&
189
190 test_write_lines A B C D E F G H I J >sequence &&
191 git add sequence &&
192 git commit -m B &&
193
194 #
195 # Actual testing
196 #
197
198 git switch upstream &&
199
200 GIT_TRACE2_PERF="$(pwd)/trace.output" &&
201 export GIT_TRACE2_PERF &&
202
203 git replay --onto HEAD upstream~1..topic >out &&
204 git update-ref --stdin <out &&
205 git checkout topic &&
206
207 git ls-files >tracked &&
208 test_line_count = 2 tracked &&
209 test_path_is_file values &&
210 test_path_is_file sequence &&
211
212 grep region_enter.*diffcore_rename trace.output >calls &&
213 test_line_count = 2 calls
214 )
215 '
216
217 #
218 # In the following testcase:
219 # Base: olddir/{valuesZ_1, valuesY_1, valuesX_1}
220 # Upstream: rename olddir/valuesZ_1 -> dirA/valuesZ_2
221 # rename olddir/valuesY_1 -> dirA/valuesY_2
222 # rename olddir/valuesX_1 -> dirB/valuesX_2
223 # Topic_1: rename olddir/valuesZ_1 -> dirA/valuesZ_3
224 # rename olddir/valuesY_1 -> dirA/valuesY_3
225 # Topic_2: add olddir/newfile
226 # Expected Pick1: dirA/{valuesZ, valuesY}, dirB/valuesX
227 # Expected Pick2: dirA/{valuesZ, valuesY}, dirB/{valuesX, newfile}
228 #
229 # This testcase presents no problems for git traditionally, but having both
230 # sides do the same renames in effect "use it up" but if the renames remain
231 # cached, the directory rename could put newfile in the wrong directory.
232 #
233 test_expect_success 'rename same file identically, then add file to old dir' '
234 git init rename-rename-1to1-then-add-file-to-old-dir &&
235 (
236 cd rename-rename-1to1-then-add-file-to-old-dir &&
237
238 mkdir olddir/ &&
239 test_seq 3 8 >olddir/valuesZ &&
240 test_seq 3 8 >olddir/valuesY &&
241 test_seq 3 8 >olddir/valuesX &&
242 git add olddir &&
243 git commit -m orig &&
244
245 git branch upstream &&
246 git branch topic &&
247
248 git switch upstream &&
249 test_seq 1 8 >olddir/valuesZ &&
250 test_seq 1 8 >olddir/valuesY &&
251 test_seq 1 8 >olddir/valuesX &&
252 git add olddir &&
253 mkdir dirA &&
254 git mv olddir/valuesZ olddir/valuesY dirA &&
255 git mv olddir/ dirB/ &&
256 git commit -m "Renamed (and modified) values*" &&
257
258 git switch topic &&
259
260 test_seq 3 10 >olddir/valuesZ &&
261 test_seq 3 10 >olddir/valuesY &&
262 git add olddir &&
263 mkdir dirA &&
264 git mv olddir/valuesZ olddir/valuesY dirA &&
265 git commit -m A &&
266
267 >olddir/newfile &&
268 git add olddir/newfile &&
269 git commit -m B &&
270
271 #
272 # Actual testing
273 #
274
275 git switch upstream &&
276 git config merge.directoryRenames true &&
277
278 GIT_TRACE2_PERF="$(pwd)/trace.output" &&
279 export GIT_TRACE2_PERF &&
280
281 git replay --onto HEAD upstream~1..topic >out &&
282 git update-ref --stdin <out &&
283 git checkout topic &&
284
285 git ls-files >tracked &&
286 test_line_count = 4 tracked &&
287 test_path_is_file dirA/valuesZ &&
288 test_path_is_file dirA/valuesY &&
289 test_path_is_file dirB/valuesX &&
290 test_path_is_file dirB/newfile &&
291
292 grep region_enter.*diffcore_rename trace.output >calls &&
293 test_line_count = 3 calls
294 )
295 '
296
297 #
298 # In the following testcase, upstream renames a directory, and the topic branch
299 # first adds a file to the directory, then later renames the directory
300 # differently:
301 # Base: olddir/a
302 # olddir/b
303 # Upstream: rename olddir/ -> newdir/
304 # Topic_1: add olddir/newfile
305 # Topic_2: rename olddir/ -> otherdir/
306 #
307 # Here we are just concerned that cached renames might prevent us from seeing
308 # the rename conflict, and we want to ensure that we do get a conflict.
309 #
310 # While at it, though, we do test that we only try to detect renames 2
311 # times and not three. (The first merge needs to detect renames on the
312 # upstream side. Traditionally, the second merge would need to detect
313 # renames on both sides of history, but our caching of upstream renames
314 # should avoid the need to re-detect upstream renames.)
315 #
316 test_expect_success 'cached dir rename does not prevent noticing later conflict' '
317 git init dir-rename-cache-not-occluding-later-conflict &&
318 (
319 cd dir-rename-cache-not-occluding-later-conflict &&
320
321 mkdir olddir &&
322 test_seq 3 10 >olddir/a &&
323 test_seq 3 10 >olddir/b &&
324 git add olddir &&
325 git commit -m orig &&
326
327 git branch upstream &&
328 git branch topic &&
329
330 git switch upstream &&
331 test_seq 3 10 >olddir/a &&
332 test_seq 3 10 >olddir/b &&
333 git add olddir &&
334 git mv olddir newdir &&
335 git commit -m "Dir renamed" &&
336
337 git switch topic &&
338
339 >olddir/newfile &&
340 git add olddir/newfile &&
341 git commit -m A &&
342
343 test_seq 1 8 >olddir/a &&
344 test_seq 1 8 >olddir/b &&
345 git add olddir &&
346 git mv olddir otherdir &&
347 git commit -m B &&
348
349 #
350 # Actual testing
351 #
352
353 git switch upstream &&
354 git config merge.directoryRenames true &&
355
356 GIT_TRACE2_PERF="$(pwd)/trace.output" &&
357 export GIT_TRACE2_PERF &&
358
359 test_must_fail git replay --onto HEAD upstream~1..topic >output &&
360
361 grep region_enter.*diffcore_rename trace.output >calls &&
362 test_line_count = 2 calls
363 )
364 '
365
366 # Helper for the next two tests
367 test_setup_upstream_rename () {
368 git init $1 &&
369 (
370 cd $1 &&
371
372 test_seq 3 8 >somefile &&
373 test_seq 3 8 >relevant-rename &&
374 git add somefile relevant-rename &&
375 mkdir olddir &&
376 test_write_lines a b c d e f g >olddir/a &&
377 test_write_lines z y x w v u t >olddir/b &&
378 git add olddir &&
379 git commit -m orig &&
380
381 git branch upstream &&
382 git branch topic &&
383
384 git switch upstream &&
385 test_seq 1 8 >somefile &&
386 test_seq 1 8 >relevant-rename &&
387 git add somefile relevant-rename &&
388 git mv relevant-rename renamed &&
389 echo h >>olddir/a &&
390 echo s >>olddir/b &&
391 git add olddir &&
392 git mv olddir newdir &&
393 git commit -m "Dir renamed"
394 )
395 }
396
397 #
398 # In the following testcase, upstream renames a file in the toplevel directory
399 # as well as its only directory:
400 # Base: relevant-rename_1
401 # somefile
402 # olddir/a
403 # olddir/b
404 # Upstream: rename relevant-rename_1 -> renamed_2
405 # rename olddir/ -> newdir/
406 # Topic_1: relevant-rename_3
407 # Topic_2: olddir/newfile_1
408 # Topic_3: olddir/newfile_2
409 #
410 # In this testcase, since the first commit being picked only modifies a
411 # file in the toplevel directory, the directory rename is irrelevant for
412 # that first merge. However, we need to notice the directory rename for
413 # the merge that picks the second commit, and we don't want the third
414 # commit to mess up its location either. We want to make sure that
415 # olddir/newfile doesn't exist in the result and that newdir/newfile does.
416 #
417 # We also test that we only do rename detection twice. We never need
418 # rename detection on the topic side of history, but we do need it twice on
419 # the upstream side of history. For the first topic commit, we only need
420 # the
421 # relevant-rename -> renamed
422 # rename, because olddir is unmodified by Topic_1. For Topic_2, however,
423 # the new file being added to olddir means files that were previously
424 # irrelevant for rename detection are now relevant, forcing us to repeat
425 # rename detection for the paths we don't already have cached. Topic_3 also
426 # tweaks olddir/newfile, but the renames in olddir/ will have been cached
427 # from the second rename detection run.
428 #
429 test_expect_success 'dir rename unneeded, then add new file to old dir' '
430 test_setup_upstream_rename dir-rename-unneeded-until-new-file &&
431 (
432 cd dir-rename-unneeded-until-new-file &&
433
434 git switch topic &&
435
436 test_seq 3 10 >relevant-rename &&
437 git add relevant-rename &&
438 git commit -m A &&
439
440 echo foo >olddir/newfile &&
441 git add olddir/newfile &&
442 git commit -m B &&
443
444 echo bar >>olddir/newfile &&
445 git add olddir/newfile &&
446 git commit -m C &&
447
448 #
449 # Actual testing
450 #
451
452 git switch upstream &&
453 git config merge.directoryRenames true &&
454
455 GIT_TRACE2_PERF="$(pwd)/trace.output" &&
456 export GIT_TRACE2_PERF &&
457
458 git replay --onto HEAD upstream~1..topic >out &&
459 git update-ref --stdin <out &&
460 git checkout topic &&
461
462 grep region_enter.*diffcore_rename trace.output >calls &&
463 test_line_count = 2 calls &&
464
465 git ls-files >tracked &&
466 test_line_count = 5 tracked &&
467 test_path_is_missing olddir/newfile &&
468 test_path_is_file newdir/newfile
469 )
470 '
471
472 #
473 # The following testcase is *very* similar to the last one, but instead of
474 # adding a new olddir/newfile, it renames somefile -> olddir/newfile:
475 # Base: relevant-rename_1
476 # somefile_1
477 # olddir/a
478 # olddir/b
479 # Upstream: rename relevant-rename_1 -> renamed_2
480 # rename olddir/ -> newdir/
481 # Topic_1: relevant-rename_3
482 # Topic_2: rename somefile -> olddir/newfile_2
483 # Topic_3: modify olddir/newfile_3
484 #
485 # In this testcase, since the first commit being picked only modifies a
486 # file in the toplevel directory, the directory rename is irrelevant for
487 # that first merge. However, we need to notice the directory rename for
488 # the merge that picks the second commit, and we don't want the third
489 # commit to mess up its location either. We want to make sure that
490 # neither somefile or olddir/newfile exists in the result and that
491 # newdir/newfile does.
492 #
493 # This testcase needs one more call to rename detection than the last
494 # testcase, because of the somefile -> olddir/newfile rename in Topic_2.
495 test_expect_success 'dir rename unneeded, then rename existing file into old dir' '
496 test_setup_upstream_rename dir-rename-unneeded-until-file-moved-inside &&
497 (
498 cd dir-rename-unneeded-until-file-moved-inside &&
499
500 git switch topic &&
501
502 test_seq 3 10 >relevant-rename &&
503 git add relevant-rename &&
504 git commit -m A &&
505
506 test_seq 1 10 >somefile &&
507 git add somefile &&
508 git mv somefile olddir/newfile &&
509 git commit -m B &&
510
511 test_seq 1 12 >olddir/newfile &&
512 git add olddir/newfile &&
513 git commit -m C &&
514
515 #
516 # Actual testing
517 #
518
519 git switch upstream &&
520 git config merge.directoryRenames true &&
521
522 GIT_TRACE2_PERF="$(pwd)/trace.output" &&
523 export GIT_TRACE2_PERF &&
524
525 git replay --onto HEAD upstream~1..topic >out &&
526 git update-ref --stdin <out &&
527 git checkout topic &&
528
529 grep region_enter.*diffcore_rename trace.output >calls &&
530 test_line_count = 3 calls &&
531
532 test_path_is_missing somefile &&
533 test_path_is_missing olddir/newfile &&
534 test_path_is_file newdir/newfile &&
535 git ls-files >tracked &&
536 test_line_count = 4 tracked
537 )
538 '
539
540 # Helper for the next two tests
541 test_setup_topic_rename () {
542 git init $1 &&
543 (
544 cd $1 &&
545
546 test_seq 3 8 >somefile &&
547 mkdir olddir &&
548 test_seq 3 8 >olddir/a &&
549 echo b >olddir/b &&
550 git add olddir somefile &&
551 git commit -m orig &&
552
553 git branch upstream &&
554 git branch topic &&
555
556 git switch topic &&
557 test_seq 1 8 >somefile &&
558 test_seq 1 8 >olddir/a &&
559 git add somefile olddir/a &&
560 git mv olddir newdir &&
561 git commit -m "Dir renamed" &&
562
563 test_seq 1 10 >somefile &&
564 git add somefile &&
565 mkdir olddir &&
566 >olddir/unrelated-file &&
567 git add olddir &&
568 git commit -m "Unrelated file in recreated old dir"
569 )
570 }
571
572 #
573 # In the following testcase, the first commit on the topic branch renames
574 # a directory, while the second recreates the old directory and places a
575 # file into it:
576 # Base: somefile
577 # olddir/a
578 # olddir/b
579 # Upstream: olddir/newfile
580 # Topic_1: somefile_2
581 # rename olddir/ -> newdir/
582 # Topic_2: olddir/unrelated-file
583 #
584 # Note that the first pick should merge:
585 # Base: somefile
586 # olddir/{a,b}
587 # Upstream: olddir/newfile
588 # Topic_1: rename olddir/ -> newdir/
589 # For which the expected result (assuming merge.directoryRenames=true) is
590 # clearly:
591 # Result: somefile
592 # newdir/{a, b, newfile}
593 #
594 # While the second pick does the following three-way merge:
595 # Base (Topic_1): somefile
596 # newdir/{a,b}
597 # Upstream (Result from 1): same files as base, but adds newdir/newfile
598 # Topic_2: same files as base, but adds olddir/unrelated-file
599 #
600 # The second merge is pretty trivial; upstream adds newdir/newfile, and
601 # topic_2 adds olddir/unrelated-file. We're just testing that we don't
602 # accidentally cache directory renames somehow and rename
603 # olddir/unrelated-file to newdir/unrelated-file.
604 #
605 # This testcase should only need one call to diffcore_rename_extended().
606 test_expect_success 'caching renames only on upstream side, part 1' '
607 test_setup_topic_rename cache-renames-only-upstream-add-file &&
608 (
609 cd cache-renames-only-upstream-add-file &&
610
611 git switch upstream &&
612
613 >olddir/newfile &&
614 git add olddir/newfile &&
615 git commit -m "Add newfile" &&
616
617 #
618 # Actual testing
619 #
620
621 git switch upstream &&
622
623 git config merge.directoryRenames true &&
624
625 GIT_TRACE2_PERF="$(pwd)/trace.output" &&
626 export GIT_TRACE2_PERF &&
627
628 git replay --onto HEAD upstream~1..topic >out &&
629 git update-ref --stdin <out &&
630 git checkout topic &&
631
632 grep region_enter.*diffcore_rename trace.output >calls &&
633 test_line_count = 1 calls &&
634
635 git ls-files >tracked &&
636 test_line_count = 5 tracked &&
637 test_path_is_missing newdir/unrelated-file &&
638 test_path_is_file olddir/unrelated-file &&
639 test_path_is_file newdir/newfile &&
640 test_path_is_file newdir/b &&
641 test_path_is_file newdir/a &&
642 test_path_is_file somefile
643 )
644 '
645
646 #
647 # The following testcase is *very* similar to the last one, but instead of
648 # adding a new olddir/newfile, it renames somefile -> olddir/newfile:
649 # Base: somefile
650 # olddir/a
651 # olddir/b
652 # Upstream: somefile_1 -> olddir/newfile
653 # Topic_1: rename olddir/ -> newdir/
654 # somefile_2
655 # Topic_2: olddir/unrelated-file
656 # somefile_3
657 #
658 # Much like the previous test, this case is actually trivial and we are just
659 # making sure there isn't some spurious directory rename caching going on
660 # for the wrong side of history.
661 #
662 #
663 # This testcase should only need two calls to diffcore_rename_extended(),
664 # both for the first merge, one for each side of history.
665 #
666 test_expect_success 'caching renames only on upstream side, part 2' '
667 test_setup_topic_rename cache-renames-only-upstream-rename-file &&
668 (
669 cd cache-renames-only-upstream-rename-file &&
670
671 git switch upstream &&
672
673 git mv somefile olddir/newfile &&
674 git commit -m "Add newfile" &&
675
676 #
677 # Actual testing
678 #
679
680 git switch upstream &&
681
682 git config merge.directoryRenames true &&
683
684 GIT_TRACE2_PERF="$(pwd)/trace.output" &&
685 export GIT_TRACE2_PERF &&
686
687 git replay --onto HEAD upstream~1..topic >out &&
688 git update-ref --stdin <out &&
689 git checkout topic &&
690
691 grep region_enter.*diffcore_rename trace.output >calls &&
692 test_line_count = 2 calls &&
693
694 git ls-files >tracked &&
695 test_line_count = 4 tracked &&
696 test_path_is_missing newdir/unrelated-file &&
697 test_path_is_file olddir/unrelated-file &&
698 test_path_is_file newdir/newfile &&
699 test_path_is_file newdir/b &&
700 test_path_is_file newdir/a
701 )
702 '
703
704 #
705 # The following testcase just creates two simple renames (slightly modified
706 # on both sides but without conflicting changes), and a directory full of
707 # files that are otherwise uninteresting. The setup is as follows:
708 #
709 # base: unrelated/<BUNCH OF FILES>
710 # numbers
711 # values
712 # upstream: modify: numbers
713 # modify: values
714 # topic: add: unrelated/foo
715 # modify: numbers
716 # modify: values
717 # rename: numbers -> sequence
718 # rename: values -> progression
719 #
720 # This is a trivial rename case, but we're curious what happens with a very
721 # low renameLimit interacting with the restart optimization trying to notice
722 # that unrelated/ looks like a trivial merge candidate.
723 #
724 test_expect_success 'avoid assuming we detected renames' '
725 git init redo-weirdness &&
726 (
727 cd redo-weirdness &&
728
729 mkdir unrelated &&
730 for i in $(test_seq 1 10)
731 do
732 >unrelated/$i || exit 1
733 done &&
734 test_seq 2 10 >numbers &&
735 test_seq 12 20 >values &&
736 git add numbers values unrelated/ &&
737 git commit -m orig &&
738
739 git branch upstream &&
740 git branch topic &&
741
742 git switch upstream &&
743 test_seq 1 10 >numbers &&
744 test_seq 11 20 >values &&
745 git add numbers &&
746 git commit -m "Some tweaks" &&
747
748 git switch topic &&
749
750 >unrelated/foo &&
751 test_seq 2 12 >numbers &&
752 test_seq 12 22 >values &&
753 git add numbers values unrelated/ &&
754 git mv numbers sequence &&
755 git mv values progression &&
756 git commit -m A &&
757
758 #
759 # Actual testing
760 #
761
762 git switch --detach topic^0 &&
763
764 test_must_fail git -c merge.renameLimit=1 rebase upstream &&
765
766 git ls-files -u >actual &&
767 test_line_count = 2 actual
768 )
769 '
770
771 #
772 # In the following testcase:
773 # Base: olddir/{valuesX_1, valuesY_1, valuesZ_1}
774 # other/content
775 # Upstream: rename olddir/valuesX_1 -> newdir/valuesX_2
776 # Topic_1: modify olddir/valuesX_1 -> olddir/valuesX_3
777 # Topic_2: modify olddir/valuesY,
778 # modify other/content
779 # Expected Pick1: olddir/{valuesY, valuesZ}, newdir/valuesX, other/content
780 # Expected Pick2: olddir/{valuesY, valuesZ}, newdir/valuesX, other/content
781 #
782 # This testcase presents no problems for git traditionally, but the fact that
783 # olddir/valuesX -> newdir/valuesX
784 # gets cached after the first pick presents a problem for the second commit to
785 # be replayed, because it appears to be an irrelevant rename, so the trivial
786 # directory resolution will resolve newdir/ without recursing into it, giving
787 # us no way to apply the cached rename to anything.
788 #
789 test_expect_success 'rename a file, use it on first pick, but irrelevant on second' '
790 git init rename_a_file_use_it_once_irrelevant_on_second &&
791 (
792 cd rename_a_file_use_it_once_irrelevant_on_second &&
793
794 mkdir olddir/ other/ &&
795 test_seq 3 8 >olddir/valuesX &&
796 test_seq 3 8 >olddir/valuesY &&
797 test_seq 3 8 >olddir/valuesZ &&
798 printf "%s\n" A B C D E F G >other/content &&
799 git add olddir other &&
800 git commit -m orig &&
801
802 git branch upstream &&
803 git branch topic &&
804
805 git switch upstream &&
806 test_seq 1 8 >olddir/valuesX &&
807 git add olddir &&
808 mkdir newdir &&
809 git mv olddir/valuesX newdir &&
810 git commit -m "Renamed (and modified) olddir/valuesX into newdir/" &&
811
812 git switch topic &&
813
814 test_seq 3 10 >olddir/valuesX &&
815 git add olddir &&
816 git commit -m A &&
817
818 test_seq 1 8 >olddir/valuesY &&
819 printf "%s\n" A B C D E F G H I >other/content &&
820 git add olddir/valuesY other &&
821 git commit -m B &&
822
823 #
824 # Actual testing; mostly we want to verify that we do not hit
825 # git: merge-ort.c:3032: process_renames: Assertion `newinfo && !newinfo->merged.clean` failed.
826 #
827
828 git switch upstream &&
829 git config merge.directoryRenames true &&
830
831 git replay --onto HEAD upstream~1..topic >out &&
832
833 #
834 # ...but we may as well check that the replay gave us a reasonable result
835 #
836
837 git update-ref --stdin <out &&
838 git checkout topic &&
839
840 git ls-files >tracked &&
841 test_line_count = 4 tracked &&
842 test_path_is_file newdir/valuesX &&
843 test_path_is_file olddir/valuesY &&
844 test_path_is_file olddir/valuesZ &&
845 test_path_is_file other/content
846 )
847 '
848
849 #
850 # In the following testcase:
851 # Base: subdir/file_1
852 # Upstream: file_1 (renamed from subdir/file)
853 # Topic_1: subdir/file_2 (modified subdir/file)
854 # Topic_2: subdir/file_2, file_2 (added another "file" with same contents)
855 # Topic_3: file_2 (deleted subdir/file)
856 #
857 #
858 # This testcase presents no problems for git traditionally, but the fact that
859 # subdir/file -> file
860 # gets cached after the first pick presents a problem for the third commit
861 # to be replayed, because file has contents file_2 on all three sides and
862 # is thus trivially resolved early. The point of renames is to allow us to
863 # three-way merge contents across multiple filenames, but if the target is
864 # already resolved, we risk throwing an assertion. Verify that the code
865 # correctly drops the irrelevant rename in order to avoid hitting that
866 # assertion.
867 #
868 test_expect_success 'cached rename does not assert on trivially clean target' '
869 git init cached-rename-trivially-clean-target &&
870 (
871 cd cached-rename-trivially-clean-target &&
872
873 mkdir subdir &&
874 printf "%s\n" 1 2 3 >subdir/file &&
875 git add subdir/file &&
876 git commit -m orig &&
877
878 git branch upstream &&
879 git branch topic &&
880
881 git switch upstream &&
882 git mv subdir/file file &&
883 git commit -m "rename subdir/file to file" &&
884
885 git switch topic &&
886
887 echo 4 >>subdir/file &&
888 git add subdir/file &&
889 git commit -m "modify subdir/file" &&
890
891 cp subdir/file file &&
892 git add file &&
893 git commit -m "copy subdir/file to file" &&
894
895 git rm subdir/file &&
896 git commit -m "delete subdir/file" &&
897
898 git switch upstream &&
899 git replay --onto HEAD upstream..topic &&
900 git checkout topic &&
901
902 git ls-files >tracked-files &&
903 test_line_count = 1 tracked-files &&
904 printf "%s\n" 1 2 3 4 >expect &&
905 test_cmp expect file
906 )
907 '
908
909 test_done