Skip to content

Commit a16e8ef

Browse files
newrengitster
authored andcommitted
merge-ort: fix merge.directoryRenames=false
There are two issues here. First, when merge.directoryRenames is set to false, there are a few code paths that should be turned off. I missed one; collect_renames() was still doing some directory rename detection logic unconditionally. It ended up not having much effect because get_provisional_directory_renames() was skipped earlier and not setting up renames->dir_renames, but the code should still be skipped. Second, the larger issue is that sometimes we get a cached_pair rename from a previous commit being replayed mapping A->B, but in a subsequent commit but collect_merge_info() doesn't even recurse into the directory containing B because there are no source pairings for that rename that are relevant; we can merge that commit fine without knowing the rename. But since the cached renames are added to the normal renames, when we go to process it and find that B is not part of opt->priv->paths, we hit the assertion error process_renames: Assertion `newinfo && ~newinfo->merged.clean` failed. I think we could fix this at the beginning of detect_regular_renames() by pruning from cached_pairs any entry whose destination isn't in opt->priv->paths, but it's suboptimal in that we'd kind of like the cached_pair to be restored afterwards so that it can help the subsequent commit, but more importantly since it sits at the intersection of the caching renames optimization and the relevant renames optimization, and the trivial directory resolution optimization, and I don't currently have Documentation/technical/remembering-renames.txt fully paged in, I'm not sure if that's a full solution or a bandaid for the current testcase. However, since the remembering renames optimization was the weakest of the set, and the optimization is far less important when directory rename detection is off (as that implies far fewer potential renames), let's just use a bigger hammer to ensure this special case is fixed: turn off the rename caching. We do the same thing already when we encounter rename/rename(1to1) cases (as per `git grep -3 disabling.the.optimization`, though it uses a slightly different triggering mechanism since it's trying to affect the next time that merge_check_renames_reusable() is called), and I think it makes sense to do the same here. Signed-off-by: Elijah Newren <[email protected]> Reviewed-by: Taylor Blau <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent a9185cc commit a16e8ef

File tree

2 files changed

+30
-3
lines changed

2 files changed

+30
-3
lines changed

merge-ort.c

Lines changed: 29 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3404,6 +3404,11 @@ static int collect_renames(struct merge_options *opt,
34043404
pool_diff_free_filepair(&opt->priv->pool, p);
34053405
continue;
34063406
}
3407+
if (opt->detect_directory_renames == MERGE_DIRECTORY_RENAMES_NONE &&
3408+
p->status == 'R' && 1) {
3409+
possibly_cache_new_pair(renames, p, side_index, NULL);
3410+
goto skip_directory_renames;
3411+
}
34073412

34083413
new_path = check_for_directory_rename(opt, p->two->path,
34093414
side_index,
@@ -3421,6 +3426,7 @@ static int collect_renames(struct merge_options *opt,
34213426
if (new_path)
34223427
apply_directory_rename_modifications(opt, p, new_path);
34233428

3429+
skip_directory_renames:
34243430
/*
34253431
* p->score comes back from diffcore_rename_extended() with
34263432
* the similarity of the renamed file. The similarity is
@@ -5025,7 +5031,8 @@ static void merge_start(struct merge_options *opt, struct merge_result *result)
50255031
trace2_region_leave("merge", "allocate/init", opt->repo);
50265032
}
50275033

5028-
static void merge_check_renames_reusable(struct merge_result *result,
5034+
static void merge_check_renames_reusable(struct merge_options *opt,
5035+
struct merge_result *result,
50295036
struct tree *merge_base,
50305037
struct tree *side1,
50315038
struct tree *side2)
@@ -5050,6 +5057,26 @@ static void merge_check_renames_reusable(struct merge_result *result,
50505057
return;
50515058
}
50525059

5060+
/*
5061+
* Avoid using cached renames when directory rename detection is
5062+
* turned off. Cached renames are far less important in that case,
5063+
* and they lead to testcases with an interesting intersection of
5064+
* effects from relevant renames optimization, trivial directory
5065+
* resolution optimization, and cached renames all converging when
5066+
* the target of a cached rename is in a directory that
5067+
* collect_merge_info() does not recurse into. To avoid such
5068+
* problems, simply disable cached renames for this case (similar
5069+
* to the rename/rename(1to1) case; see the "disabling the
5070+
* optimization" comment near that case).
5071+
*
5072+
* This could be revisited in the future; see the commit message
5073+
* where this comment was added for some possible pointers.
5074+
*/
5075+
if (opt->detect_directory_renames == MERGE_DIRECTORY_RENAMES_NONE) {
5076+
renames->cached_pairs_valid_side = 0; /* neither side valid */
5077+
return;
5078+
}
5079+
50535080
/*
50545081
* Handle other cases; note that merge_trees[0..2] will only
50555082
* be NULL if opti is, or if all three were manually set to
@@ -5258,7 +5285,7 @@ void merge_incore_nonrecursive(struct merge_options *opt,
52585285

52595286
trace2_region_enter("merge", "merge_start", opt->repo);
52605287
assert(opt->ancestor != NULL);
5261-
merge_check_renames_reusable(result, merge_base, side1, side2);
5288+
merge_check_renames_reusable(opt, result, merge_base, side1, side2);
52625289
merge_start(opt, result);
52635290
/*
52645291
* Record the trees used in this merge, so if there's a next merge in

t/t3650-replay-basics.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -195,7 +195,7 @@ test_expect_success 'using replay on bare repo to rebase multiple divergent bran
195195
done
196196
'
197197

198-
test_expect_failure 'merge.directoryRenames=false' '
198+
test_expect_success 'merge.directoryRenames=false' '
199199
# create a test case that stress-tests the rename caching
200200
git switch -c rename-onto &&
201201

0 commit comments

Comments
 (0)