Skip to content

Commit 9ae39fe

Browse files
newrengitster
authored andcommitted
merge-ort: avoid assuming all renames detected
In commit 8b09a90 ("merge-ort: restart merge with cached renames to reduce process entry cost", 2021-07-16), we noted that in the merge-ort steps of collect_merge_info() detect_and_process_renames() process_entries() that process_entries() was expensive, and we could often make it cheaper by changing this to collect_merge_info() detect_and_process_renames() <cache all the renames, and restart> collect_merge_info() detect_and_process_renames() process_entries() because the second collect_merge_info() would be cheaper (we could avoid traversing into some directories), the second detect_and_process_renames() would be free since we had already detected all renames, and then process_entries() has far fewer entries to handle. However, this was built on the assumption that the first detect_and_process_renames() actually detected all potential renames. If someone has merge.renameLimit set to some small value, that assumption is violated which manifests later with the following message: $ git -c merge.renameLimit=1 rebase upstream ... git: merge-ort.c:546: clear_or_reinit_internal_opts: Assertion `renames->cached_pairs_valid_side == 0' failed. Turn off this cache-renames-and-restart whenever we cannot detect all renames, and add a testcase that would have caught this problem. Reported-by: Taylor Blau <[email protected]> Signed-off-by: Elijah Newren <[email protected]> Tested-by: Taylor Blau <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 5fbd2fc commit 9ae39fe

File tree

2 files changed

+71
-0
lines changed

2 files changed

+71
-0
lines changed

merge-ort.c

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3031,6 +3031,10 @@ static int detect_and_process_renames(struct merge_options *opt,
30313031
trace2_region_enter("merge", "regular renames", opt->repo);
30323032
detection_run |= detect_regular_renames(opt, MERGE_SIDE1);
30333033
detection_run |= detect_regular_renames(opt, MERGE_SIDE2);
3034+
if (renames->needed_limit) {
3035+
renames->cached_pairs_valid_side = 0;
3036+
renames->redo_after_renames = 0;
3037+
}
30343038
if (renames->redo_after_renames && detection_run) {
30353039
int i, side;
30363040
struct diff_filepair *p;

t/t6429-merge-sequence-rename-caching.sh

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -697,4 +697,71 @@ test_expect_success 'caching renames only on upstream side, part 2' '
697697
)
698698
'
699699

700+
#
701+
# The following testcase just creates two simple renames (slightly modified
702+
# on both sides but without conflicting changes), and a directory full of
703+
# files that are otherwise uninteresting. The setup is as follows:
704+
#
705+
# base: unrelated/<BUNCH OF FILES>
706+
# numbers
707+
# values
708+
# upstream: modify: numbers
709+
# modify: values
710+
# topic: add: unrelated/foo
711+
# modify: numbers
712+
# modify: values
713+
# rename: numbers -> sequence
714+
# rename: values -> progression
715+
#
716+
# This is a trivial rename case, but we're curious what happens with a very
717+
# low renameLimit interacting with the restart optimization trying to notice
718+
# that unrelated/ looks like a trivial merge candidate.
719+
#
720+
test_expect_success 'avoid assuming we detected renames' '
721+
git init redo-weirdness &&
722+
(
723+
cd redo-weirdness &&
724+
725+
mkdir unrelated &&
726+
for i in $(test_seq 1 10)
727+
do
728+
>unrelated/$i
729+
done &&
730+
test_seq 2 10 >numbers &&
731+
test_seq 12 20 >values &&
732+
git add numbers values unrelated/ &&
733+
git commit -m orig &&
734+
735+
git branch upstream &&
736+
git branch topic &&
737+
738+
git switch upstream &&
739+
test_seq 1 10 >numbers &&
740+
test_seq 11 20 >values &&
741+
git add numbers &&
742+
git commit -m "Some tweaks" &&
743+
744+
git switch topic &&
745+
746+
>unrelated/foo &&
747+
test_seq 2 12 >numbers &&
748+
test_seq 12 22 >values &&
749+
git add numbers values unrelated/ &&
750+
git mv numbers sequence &&
751+
git mv values progression &&
752+
git commit -m A &&
753+
754+
#
755+
# Actual testing
756+
#
757+
758+
git switch --detach topic^0 &&
759+
760+
test_must_fail git -c merge.renameLimit=1 rebase upstream &&
761+
762+
git ls-files -u >actual &&
763+
! test_file_is_empty actual
764+
)
765+
'
766+
700767
test_done

0 commit comments

Comments
 (0)