t6429: testcases for remembering renames

We will soon be adding an optimization that caches (in memory only, never written to disk) upstream renames during a sequence of merges such as occurs during a cherry-pick or rebase operation. Add several tests meant to stress such an implementation to ensure it does the right thing, and include a test whose outcome we will later change due to this optimization as well. Signed-off-by: Elijah Newren <newren@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Elijah Newren committed May 20, 2021 at 06:09 UTC a22099f552d5e67dc71c2bd92c4b711387e9695f
2 files changed +700 -6
Documentation/technical/remembering-renames.txt
+8 -6
@@ -214,12 +214,14 @@ in-memory cache of renames and thus doesn't need to be considered further.
214 In the special case that E->A does rename the file but also renames it to
215 newfile, then there is no conflict from the renaming and the merge can
216 succeed. In this special case, the rename is not valid to cache because
217 -the second merge will find A:newfile in the MERGE_BASE. So a
218 -rename/rename(1to1) needs to be specially handled by pruning renames from
219 -the cache and decrementing the dir_rename_counts in the current and leading
220 -directories associated with those renames. Or, since these are really
221 -rare, one could just take the easy way out and disable the remembering
222 -renames optimization when a rename/rename(1to1) happens.
217 +the second merge will find A:newfile in the MERGE_BASE (see also the new
218 +testcases in t6429 with "rename same file identically" in their
219 +description). So a rename/rename(1to1) needs to be specially handled by
220 +pruning renames from the cache and decrementing the dir_rename_counts in
221 +the current and leading directories associated with those renames. Or,
222 +since these are really rare, one could just take the easy way out and
223 +disable the remembering renames optimization when a rename/rename(1to1)
224 +happens.
225
226 The previous paragraph handled the cases for E->A renaming oldfile, let's
227 continue assuming that oldfile is not renamed in A.
t/t6429-merge-sequence-rename-caching.sh new
+692
@@ -0,0 +1,692 @@
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 'test-tool fast-rebase' instead of either
15 +# cherry-pick or rebase. sequencer.c is only superficially
16 +# integrated with merge-ort; it calls merge_switch_to_result()
17 +# after EACH merge, which updates the index and working copy AND
18 +# throws away the cached results (because merge_switch_to_result()
19 +# is only supposed to be called at the end of the sequence).
20 +# Integrating them more deeply is a big task, so for now the tests
21 +# use 'test-tool fast-rebase'.
22 +#
23 +
24 +
25 +#
26 +# In the following simple testcase:
27 +# Base: numbers_1, values_1
28 +# Upstream: numbers_2, values_2
29 +# Topic_1: sequence_3
30 +# Topic_2: scruples_3
31 +# or, in english, rename numbers -> sequence in the first commit, and rename
32 +# values -> scruples in the second commit.
33 +#
34 +# This shouldn't be a challenge, it's just verifying that cached renames isn't
35 +# preventing us from finding new renames.
36 +#
37 +test_expect_success 'caching renames does not preclude finding new ones' '
38 + test_create_repo caching-renames-and-new-renames &&
39 + (
40 + cd caching-renames-and-new-renames &&
41 +
42 + test_seq 2 10 >numbers &&
43 + test_seq 2 10 >values &&
44 + git add numbers values &&
45 + git commit -m orig &&
46 +
47 + git branch upstream &&
48 + git branch topic &&
49 +
50 + git switch upstream &&
51 + test_seq 1 10 >numbers &&
52 + test_seq 1 10 >values &&
53 + git add numbers values &&
54 + git commit -m "Tweaked both files" &&
55 +
56 + git switch topic &&
57 +
58 + test_seq 2 12 >numbers &&
59 + git add numbers &&
60 + git mv numbers sequence &&
61 + git commit -m A &&
62 +
63 + test_seq 2 12 >values &&
64 + git add values &&
65 + git mv values scruples &&
66 + git commit -m B &&
67 +
68 + #
69 + # Actual testing
70 + #
71 +
72 + git switch upstream &&
73 +
74 + test-tool fast-rebase --onto HEAD upstream~1 topic &&
75 + #git cherry-pick upstream~1..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 +# Rename detection (diffcore_rename_extended()) will run twice here; it is
105 +# not needed on the topic side of history for either of the two commits
106 +# being merged, but it is needed on the upstream side of history for each
107 +# commit being picked.
108 +test_expect_success 'cherry-pick both a commit and its immediate revert' '
109 + test_create_repo 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 + test_might_fail test-tool fast-rebase --onto HEAD upstream~1 topic &&
144 + #git cherry-pick upstream~1..topic &&
145 +
146 + grep region_enter.*diffcore_rename trace.output >calls &&
147 + test_line_count = 2 calls
148 + )
149 +'
150 +
151 +#
152 +# In the following testcase:
153 +# Base: sequence_1
154 +# Upstream: rename sequence_1 -> values_2
155 +# Topic_1: rename sequence_1 -> values_3
156 +# Topic_2: add unrelated sequence_4
157 +# or, in english, both sides rename sequence -> values, and then the second
158 +# commit on the topic branch adds an unrelated file called sequence.
159 +#
160 +# This testcase presents no problems for git traditionally, but having both
161 +# sides do the same rename in effect "uses it up" and if it remains cached,
162 +# could cause a spurious rename/add conflict.
163 +#
164 +test_expect_success 'rename same file identically, then reintroduce it' '
165 + test_create_repo rename-rename-1to1-then-add-old-filename &&
166 + (
167 + cd rename-rename-1to1-then-add-old-filename &&
168 +
169 + test_seq 3 8 >sequence &&
170 + git add sequence &&
171 + git commit -m orig &&
172 +
173 + git branch upstream &&
174 + git branch topic &&
175 +
176 + git switch upstream &&
177 + test_seq 1 8 >sequence &&
178 + git add sequence &&
179 + git mv sequence values &&
180 + git commit -m "Renamed (and modified) sequence -> values" &&
181 +
182 + git switch topic &&
183 +
184 + test_seq 3 10 >sequence &&
185 + git add sequence &&
186 + git mv sequence values &&
187 + git commit -m A &&
188 +
189 + test_write_lines A B C D E F G H I J >sequence &&
190 + git add sequence &&
191 + git commit -m B &&
192 +
193 + #
194 + # Actual testing
195 + #
196 +
197 + git switch upstream &&
198 +
199 + GIT_TRACE2_PERF="$(pwd)/trace.output" &&
200 + export GIT_TRACE2_PERF &&
201 +
202 + test-tool fast-rebase --onto HEAD upstream~1 topic &&
203 + #git cherry-pick upstream~1..topic &&
204 +
205 + git ls-files >tracked &&
206 + test_line_count = 2 tracked &&
207 + test_path_is_file values &&
208 + test_path_is_file sequence &&
209 +
210 + grep region_enter.*diffcore_rename trace.output >calls &&
211 + test_line_count = 2 calls
212 + )
213 +'
214 +
215 +#
216 +# In the following testcase:
217 +# Base: olddir/{valuesZ_1, valuesY_1, valuesX_1}
218 +# Upstream: rename olddir/valuesZ_1 -> dirA/valuesZ_2
219 +# rename olddir/valuesY_1 -> dirA/valuesY_2
220 +# rename olddir/valuesX_1 -> dirB/valuesX_2
221 +# Topic_1: rename olddir/valuesZ_1 -> dirA/valuesZ_3
222 +# rename olddir/valuesY_1 -> dirA/valuesY_3
223 +# Topic_2: add olddir/newfile
224 +# Expected Pick1: dirA/{valuesZ, valuesY}, dirB/valuesX
225 +# Expected Pick2: dirA/{valuesZ, valuesY}, dirB/{valuesX, newfile}
226 +#
227 +# This testcase presents no problems for git traditionally, but having both
228 +# sides do the same renames in effect "use it up" but if the renames remain
229 +# cached, the directory rename could put newfile in the wrong directory.
230 +#
231 +test_expect_success 'rename same file identically, then add file to old dir' '
232 + test_create_repo rename-rename-1to1-then-add-file-to-old-dir &&
233 + (
234 + cd rename-rename-1to1-then-add-file-to-old-dir &&
235 +
236 + mkdir olddir/ &&
237 + test_seq 3 8 >olddir/valuesZ &&
238 + test_seq 3 8 >olddir/valuesY &&
239 + test_seq 3 8 >olddir/valuesX &&
240 + git add olddir &&
241 + git commit -m orig &&
242 +
243 + git branch upstream &&
244 + git branch topic &&
245 +
246 + git switch upstream &&
247 + test_seq 1 8 >olddir/valuesZ &&
248 + test_seq 1 8 >olddir/valuesY &&
249 + test_seq 1 8 >olddir/valuesX &&
250 + git add olddir &&
251 + mkdir dirA &&
252 + git mv olddir/valuesZ olddir/valuesY dirA &&
253 + git mv olddir/ dirB/ &&
254 + git commit -m "Renamed (and modified) values*" &&
255 +
256 + git switch topic &&
257 +
258 + test_seq 3 10 >olddir/valuesZ &&
259 + test_seq 3 10 >olddir/valuesY &&
260 + git add olddir &&
261 + mkdir dirA &&
262 + git mv olddir/valuesZ olddir/valuesY dirA &&
263 + git commit -m A &&
264 +
265 + >olddir/newfile &&
266 + git add olddir/newfile &&
267 + git commit -m B &&
268 +
269 + #
270 + # Actual testing
271 + #
272 +
273 + git switch upstream &&
274 + git config merge.directoryRenames true &&
275 +
276 + GIT_TRACE2_PERF="$(pwd)/trace.output" &&
277 + export GIT_TRACE2_PERF &&
278 +
279 + test-tool fast-rebase --onto HEAD upstream~1 topic &&
280 + #git cherry-pick upstream~1..topic &&
281 +
282 + git ls-files >tracked &&
283 + test_line_count = 4 tracked &&
284 + test_path_is_file dirA/valuesZ &&
285 + test_path_is_file dirA/valuesY &&
286 + test_path_is_file dirB/valuesX &&
287 + test_path_is_file dirB/newfile &&
288 +
289 + grep region_enter.*diffcore_rename trace.output >calls &&
290 + test_line_count = 3 calls
291 + )
292 +'
293 +
294 +#
295 +# In the following testcase, upstream renames a directory, and the topic branch
296 +# first adds a file to the directory, then later renames the directory
297 +# differently:
298 +# Base: olddir/a
299 +# olddir/b
300 +# Upstream: rename olddir/ -> newdir/
301 +# Topic_1: add olddir/newfile
302 +# Topic_2: rename olddir/ -> otherdir/
303 +#
304 +# Here we are just concerned that cached renames might prevent us from seeing
305 +# the rename conflict, and we want to ensure that we do get a conflict.
306 +#
307 +# While at it, also test that we do rename detection three times. We have to
308 +# detect renames on the upstream side of history once for each merge, plus
309 +# Topic_2 has renames.
310 +#
311 +test_expect_success 'cached dir rename does not prevent noticing later conflict' '
312 + test_create_repo dir-rename-cache-not-occluding-later-conflict &&
313 + (
314 + cd dir-rename-cache-not-occluding-later-conflict &&
315 +
316 + mkdir olddir &&
317 + test_seq 3 10 >olddir/a &&
318 + test_seq 3 10 >olddir/b &&
319 + git add olddir &&
320 + git commit -m orig &&
321 +
322 + git branch upstream &&
323 + git branch topic &&
324 +
325 + git switch upstream &&
326 + test_seq 3 10 >olddir/a &&
327 + test_seq 3 10 >olddir/b &&
328 + git add olddir &&
329 + git mv olddir newdir &&
330 + git commit -m "Dir renamed" &&
331 +
332 + git switch topic &&
333 +
334 + >olddir/newfile &&
335 + git add olddir/newfile &&
336 + git commit -m A &&
337 +
338 + test_seq 1 8 >olddir/a &&
339 + test_seq 1 8 >olddir/b &&
340 + git add olddir &&
341 + git mv olddir otherdir &&
342 + git commit -m B &&
343 +
344 + #
345 + # Actual testing
346 + #
347 +
348 + git switch upstream &&
349 + git config merge.directoryRenames true &&
350 +
351 + GIT_TRACE2_PERF="$(pwd)/trace.output" &&
352 + export GIT_TRACE2_PERF &&
353 +
354 + test_must_fail test-tool fast-rebase --onto HEAD upstream~1 topic >output &&
355 + #git cherry-pick upstream..topic &&
356 +
357 + grep CONFLICT..rename/rename output &&
358 +
359 + grep region_enter.*diffcore_rename trace.output >calls &&
360 + test_line_count = 3 calls
361 + )
362 +'
363 +
364 +# Helper for the next two tests
365 +test_setup_upstream_rename () {
366 + test_create_repo $1 &&
367 + (
368 + cd $1 &&
369 +
370 + test_seq 3 8 >somefile &&
371 + test_seq 3 8 >relevant-rename &&
372 + git add somefile relevant-rename &&
373 + mkdir olddir &&
374 + test_write_lines a b c d e f g >olddir/a &&
375 + test_write_lines z y x w v u t >olddir/b &&
376 + git add olddir &&
377 + git commit -m orig &&
378 +
379 + git branch upstream &&
380 + git branch topic &&
381 +
382 + git switch upstream &&
383 + test_seq 1 8 >somefile &&
384 + test_seq 1 8 >relevant-rename &&
385 + git add somefile relevant-rename &&
386 + git mv relevant-rename renamed &&
387 + echo h >>olddir/a &&
388 + echo s >>olddir/b &&
389 + git add olddir &&
390 + git mv olddir newdir &&
391 + git commit -m "Dir renamed"
392 + )
393 +}
394 +
395 +#
396 +# In the following testcase, upstream renames a file in the toplevel directory
397 +# as well as its only directory:
398 +# Base: relevant-rename_1
399 +# somefile
400 +# olddir/a
401 +# olddir/b
402 +# Upstream: rename relevant-rename_1 -> renamed_2
403 +# rename olddir/ -> newdir/
404 +# Topic_1: relevant-rename_3
405 +# Topic_2: olddir/newfile_1
406 +# Topic_3: olddir/newfile_2
407 +#
408 +# In this testcase, since the first commit being picked only modifies a
409 +# file in the toplevel directory, the directory rename is irrelevant for
410 +# that first merge. However, we need to notice the directory rename for
411 +# the merge that picks the second commit, and we don't want the third
412 +# commit to mess up its location either. We want to make sure that
413 +# olddir/newfile doesn't exist in the result and that newdir/newfile does.
414 +#
415 +# We also expect rename detection to occur three times. Although it is
416 +# typically needed two times per commit, there are no deleted files on the
417 +# topic side of history, so we only need to detect renames on the upstream
418 +# side for each of the 3 commits we need to pick.
419 +#
420 +test_expect_success 'dir rename unneeded, then add new file to old dir' '
421 + test_setup_upstream_rename dir-rename-unneeded-until-new-file &&
422 + (
423 + cd dir-rename-unneeded-until-new-file &&
424 +
425 + git switch topic &&
426 +
427 + test_seq 3 10 >relevant-rename &&
428 + git add relevant-rename &&
429 + git commit -m A &&
430 +
431 + echo foo >olddir/newfile &&
432 + git add olddir/newfile &&
433 + git commit -m B &&
434 +
435 + echo bar >>olddir/newfile &&
436 + git add olddir/newfile &&
437 + git commit -m C &&
438 +
439 + #
440 + # Actual testing
441 + #
442 +
443 + git switch upstream &&
444 + git config merge.directoryRenames true &&
445 +
446 + GIT_TRACE2_PERF="$(pwd)/trace.output" &&
447 + export GIT_TRACE2_PERF &&
448 +
449 + test-tool fast-rebase --onto HEAD upstream~1 topic &&
450 + #git cherry-pick upstream..topic &&
451 +
452 + grep region_enter.*diffcore_rename trace.output >calls &&
453 + test_line_count = 3 calls &&
454 +
455 + git ls-files >tracked &&
456 + test_line_count = 5 tracked &&
457 + test_path_is_missing olddir/newfile &&
458 + test_path_is_file newdir/newfile
459 + )
460 +'
461 +
462 +#
463 +# The following testcase is *very* similar to the last one, but instead of
464 +# adding a new olddir/newfile, it renames somefile -> olddir/newfile:
465 +# Base: relevant-rename_1
466 +# somefile_1
467 +# olddir/a
468 +# olddir/b
469 +# Upstream: rename relevant-rename_1 -> renamed_2
470 +# rename olddir/ -> newdir/
471 +# Topic_1: relevant-rename_3
472 +# Topic_2: rename somefile -> olddir/newfile_2
473 +# Topic_3: modify olddir/newfile_3
474 +#
475 +# In this testcase, since the first commit being picked only modifies a
476 +# file in the toplevel directory, the directory rename is irrelevant for
477 +# that first merge. However, we need to notice the directory rename for
478 +# the merge that picks the second commit, and we don't want the third
479 +# commit to mess up its location either. We want to make sure that
480 +# neither somefile or olddir/newfile exists in the result and that
481 +# newdir/newfile does.
482 +#
483 +# This testcase needs one more call to rename detection than the last
484 +# testcase, because of the somefile -> olddir/newfile rename in Topic_2.
485 +test_expect_success 'dir rename unneeded, then rename existing file into old dir' '
486 + test_setup_upstream_rename dir-rename-unneeded-until-file-moved-inside &&
487 + (
488 + cd dir-rename-unneeded-until-file-moved-inside &&
489 +
490 + git switch topic &&
491 +
492 + test_seq 3 10 >relevant-rename &&
493 + git add relevant-rename &&
494 + git commit -m A &&
495 +
496 + test_seq 1 10 >somefile &&
497 + git add somefile &&
498 + git mv somefile olddir/newfile &&
499 + git commit -m B &&
500 +
501 + test_seq 1 12 >olddir/newfile &&
502 + git add olddir/newfile &&
503 + git commit -m C &&
504 +
505 + #
506 + # Actual testing
507 + #
508 +
509 + git switch upstream &&
510 + git config merge.directoryRenames true &&
511 +
512 + GIT_TRACE2_PERF="$(pwd)/trace.output" &&
513 + export GIT_TRACE2_PERF &&
514 +
515 + test-tool fast-rebase --onto HEAD upstream~1 topic &&
516 + #git cherry-pick upstream..topic &&
517 +
518 + grep region_enter.*diffcore_rename trace.output >calls &&
519 + test_line_count = 4 calls &&
520 +
521 + test_path_is_missing somefile &&
522 + test_path_is_missing olddir/newfile &&
523 + test_path_is_file newdir/newfile &&
524 + git ls-files >tracked &&
525 + test_line_count = 4 tracked
526 + )
527 +'
528 +
529 +# Helper for the next two tests
530 +test_setup_topic_rename () {
531 + test_create_repo $1 &&
532 + (
533 + cd $1 &&
534 +
535 + test_seq 3 8 >somefile &&
536 + mkdir olddir &&
537 + test_seq 3 8 >olddir/a &&
538 + echo b >olddir/b &&
539 + git add olddir somefile &&
540 + git commit -m orig &&
541 +
542 + git branch upstream &&
543 + git branch topic &&
544 +
545 + git switch topic &&
546 + test_seq 1 8 >somefile &&
547 + test_seq 1 8 >olddir/a &&
548 + git add somefile olddir/a &&
549 + git mv olddir newdir &&
550 + git commit -m "Dir renamed" &&
551 +
552 + test_seq 1 10 >somefile &&
553 + git add somefile &&
554 + mkdir olddir &&
555 + >olddir/unrelated-file &&
556 + git add olddir &&
557 + git commit -m "Unrelated file in recreated old dir"
558 + )
559 +}
560 +
561 +#
562 +# In the following testcase, the first commit on the topic branch renames
563 +# a directory, while the second recreates the old directory and places a
564 +# file into it:
565 +# Base: somefile
566 +# olddir/a
567 +# olddir/b
568 +# Upstream: olddir/newfile
569 +# Topic_1: somefile_2
570 +# rename olddir/ -> newdir/
571 +# Topic_2: olddir/unrelated-file
572 +#
573 +# Note that the first pick should merge:
574 +# Base: somefile
575 +# olddir/{a,b}
576 +# Upstream: olddir/newfile
577 +# Topic_1: rename olddir/ -> newdir/
578 +# For which the expected result (assuming merge.directoryRenames=true) is
579 +# clearly:
580 +# Result: somefile
581 +# newdir/{a, b, newfile}
582 +#
583 +# While the second pick does the following three-way merge:
584 +# Base (Topic_1): somefile
585 +# newdir/{a,b}
586 +# Upstream (Result from 1): same files as base, but adds newdir/newfile
587 +# Topic_2: same files as base, but adds olddir/unrelated-file
588 +#
589 +# The second merge is pretty trivial; upstream adds newdir/newfile, and
590 +# topic_2 adds olddir/unrelated-file. We're just testing that we don't
591 +# accidentally cache directory renames somehow and rename
592 +# olddir/unrelated-file to newdir/unrelated-file.
593 +#
594 +# This testcase should only need one call to diffcore_rename_extended().
595 +test_expect_success 'caching renames only on upstream side, part 1' '
596 + test_setup_topic_rename cache-renames-only-upstream-add-file &&
597 + (
598 + cd cache-renames-only-upstream-add-file &&
599 +
600 + git switch upstream &&
601 +
602 + >olddir/newfile &&
603 + git add olddir/newfile &&
604 + git commit -m "Add newfile" &&
605 +
606 + #
607 + # Actual testing
608 + #
609 +
610 + git switch upstream &&
611 +
612 + git config merge.directoryRenames true &&
613 +
614 + GIT_TRACE2_PERF="$(pwd)/trace.output" &&
615 + export GIT_TRACE2_PERF &&
616 +
617 + test-tool fast-rebase --onto HEAD upstream~1 topic &&
618 + #git cherry-pick upstream..topic &&
619 +
620 + grep region_enter.*diffcore_rename trace.output >calls &&
621 + test_line_count = 1 calls &&
622 +
623 + git ls-files >tracked &&
624 + test_line_count = 5 tracked &&
625 + test_path_is_missing newdir/unrelated-file &&
626 + test_path_is_file olddir/unrelated-file &&
627 + test_path_is_file newdir/newfile &&
628 + test_path_is_file newdir/b &&
629 + test_path_is_file newdir/a &&
630 + test_path_is_file somefile
631 + )
632 +'
633 +
634 +#
635 +# The following testcase is *very* similar to the last one, but instead of
636 +# adding a new olddir/newfile, it renames somefile -> olddir/newfile:
637 +# Base: somefile
638 +# olddir/a
639 +# olddir/b
640 +# Upstream: somefile_1 -> olddir/newfile
641 +# Topic_1: rename olddir/ -> newdir/
642 +# somefile_2
643 +# Topic_2: olddir/unrelated-file
644 +# somefile_3
645 +#
646 +# Much like the previous test, this case is actually trivial and we are just
647 +# making sure there isn't some spurious directory rename caching going on
648 +# for the wrong side of history.
649 +#
650 +#
651 +# This testcase should only need three calls to diffcore_rename_extended(),
652 +# because there are no renames on the topic side of history for picking
653 +# Topic_2.
654 +#
655 +test_expect_success 'caching renames only on upstream side, part 2' '
656 + test_setup_topic_rename cache-renames-only-upstream-rename-file &&
657 + (
658 + cd cache-renames-only-upstream-rename-file &&
659 +
660 + git switch upstream &&
661 +
662 + git mv somefile olddir/newfile &&
663 + git commit -m "Add newfile" &&
664 +
665 + #
666 + # Actual testing
667 + #
668 +
669 + git switch upstream &&
670 +
671 + git config merge.directoryRenames true &&
672 +
673 + GIT_TRACE2_PERF="$(pwd)/trace.output" &&
674 + export GIT_TRACE2_PERF &&
675 +
676 + test-tool fast-rebase --onto HEAD upstream~1 topic &&
677 + #git cherry-pick upstream..topic &&
678 +
679 + grep region_enter.*diffcore_rename trace.output >calls &&
680 + test_line_count = 3 calls &&
681 +
682 + git ls-files >tracked &&
683 + test_line_count = 4 tracked &&
684 + test_path_is_missing newdir/unrelated-file &&
685 + test_path_is_file olddir/unrelated-file &&
686 + test_path_is_file newdir/newfile &&
687 + test_path_is_file newdir/b &&
688 + test_path_is_file newdir/a
689 + )
690 +'
691 +
692 +test_done