merge-ort: add implementation of rename/delete conflicts
Implement rename/delete conflicts, i.e. one side renames a file and the other deletes the file. This code replaces the following from merge-recurisve.c: * the code relevant to RENAME_DELETE in process_renames() * the RENAME_DELETE case of process_entry() * handle_rename_delete() Also, there is some shared code from merge-recursive.c for multiple different rename cases which we will no longer need for this case (or other rename cases): * handle_change_delete() * setup_rename_conflict_info() The consolidation of five separate codepaths into one is made possible by a change in design: process_renames() tweaks the conflict_info entries within opt->priv->paths such that process_entry() can then handle all the non-rename conflict types (directory/file, modify/delete, etc.) orthogonally. This means we're much less likely to miss special implementation of some kind of combination of conflict types (see commits brought in by66c62eaec6
("Merge branch 'en/merge-tests'", 2020-11-18), especially commitef52778708
("merge tests: expect improved directory/file conflict handling in ort", 2020-10-26) for more details). That, together with letting worktree/index updating be handled orthogonally in the merge_switch_to_result() function, dramatically simplifies the code for various special rename cases. To be fair, there is a _slight_ tweak to process_entry() here, because rename/delete cases will also trigger the modify/delete codepath. However, we only want a modify/delete message to be printed for a rename/delete conflict if there is a content change in the renamed file in addition to the rename. So process_renames() and process_entry() aren't quite fully orthogonal, but they are pretty close. Signed-off-by: Elijah Newren <newren@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
parent
53e88a0353
commit
2e91ddd24e
48
merge-ort.c
48
merge-ort.c
@ -657,6 +657,7 @@ static int process_renames(struct merge_options *opt,
|
||||
unsigned int old_sidemask;
|
||||
int target_index, other_source_index;
|
||||
int source_deleted, collision, type_changed;
|
||||
const char *rename_branch = NULL, *delete_branch = NULL;
|
||||
|
||||
old_ent = strmap_get_entry(&opt->priv->paths, pair->one->path);
|
||||
oldpath = old_ent->key;
|
||||
@ -779,6 +780,15 @@ static int process_renames(struct merge_options *opt,
|
||||
/* special handling so later blocks can handle this */
|
||||
die("Not yet implemented");
|
||||
}
|
||||
if (source_deleted) {
|
||||
if (target_index == 1) {
|
||||
rename_branch = opt->branch1;
|
||||
delete_branch = opt->branch2;
|
||||
} else {
|
||||
rename_branch = opt->branch2;
|
||||
delete_branch = opt->branch1;
|
||||
}
|
||||
}
|
||||
|
||||
assert(source_deleted || oldinfo->filemask & old_sidemask);
|
||||
|
||||
@ -790,13 +800,26 @@ static int process_renames(struct merge_options *opt,
|
||||
/* rename/add/delete or rename/rename(2to1)/delete */
|
||||
die("Not yet implemented");
|
||||
} else {
|
||||
/* a few different cases... */
|
||||
/*
|
||||
* a few different cases...start by copying the
|
||||
* existing stage(s) from oldinfo over the newinfo
|
||||
* and update the pathname(s).
|
||||
*/
|
||||
memcpy(&newinfo->stages[0], &oldinfo->stages[0],
|
||||
sizeof(newinfo->stages[0]));
|
||||
newinfo->filemask |= (1 << MERGE_BASE);
|
||||
newinfo->pathnames[0] = oldpath;
|
||||
if (type_changed) {
|
||||
/* rename vs. typechange */
|
||||
die("Not yet implemented");
|
||||
} else if (source_deleted) {
|
||||
/* rename/delete */
|
||||
die("Not yet implemented");
|
||||
newinfo->path_conflict = 1;
|
||||
path_msg(opt, newpath, 0,
|
||||
_("CONFLICT (rename/delete): %s renamed"
|
||||
" to %s in %s, but deleted in %s."),
|
||||
oldpath, newpath,
|
||||
rename_branch, delete_branch);
|
||||
} else {
|
||||
/* normal rename */
|
||||
die("Not yet implemented");
|
||||
@ -1332,12 +1355,21 @@ static void process_entry(struct merge_options *opt,
|
||||
modify_branch = (side == 1) ? opt->branch1 : opt->branch2;
|
||||
delete_branch = (side == 1) ? opt->branch2 : opt->branch1;
|
||||
|
||||
path_msg(opt, path, 0,
|
||||
_("CONFLICT (modify/delete): %s deleted in %s "
|
||||
"and modified in %s. Version %s of %s left "
|
||||
"in tree."),
|
||||
path, delete_branch, modify_branch,
|
||||
modify_branch, path);
|
||||
if (ci->path_conflict &&
|
||||
oideq(&ci->stages[0].oid, &ci->stages[side].oid)) {
|
||||
/*
|
||||
* This came from a rename/delete; no action to take,
|
||||
* but avoid printing "modify/delete" conflict notice
|
||||
* since the contents were not modified.
|
||||
*/
|
||||
} else {
|
||||
path_msg(opt, path, 0,
|
||||
_("CONFLICT (modify/delete): %s deleted in %s "
|
||||
"and modified in %s. Version %s of %s left "
|
||||
"in tree."),
|
||||
path, delete_branch, modify_branch,
|
||||
modify_branch, path);
|
||||
}
|
||||
} else if (ci->filemask == 2 || ci->filemask == 4) {
|
||||
/* Added on one side */
|
||||
int side = (ci->filemask == 4) ? 2 : 1;
|
||||
|
Loading…
Reference in New Issue
Block a user