Skip to content

Commit 2e91ddd

Browse files
newrengitster
authored andcommitted
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 by 66c62ea ("Merge branch 'en/merge-tests'", 2020-11-18), especially commit ef52778 ("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 <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 53e88a0 commit 2e91ddd

File tree

1 file changed

+40
-8
lines changed

1 file changed

+40
-8
lines changed

merge-ort.c

Lines changed: 40 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -657,6 +657,7 @@ static int process_renames(struct merge_options *opt,
657657
unsigned int old_sidemask;
658658
int target_index, other_source_index;
659659
int source_deleted, collision, type_changed;
660+
const char *rename_branch = NULL, *delete_branch = NULL;
660661

661662
old_ent = strmap_get_entry(&opt->priv->paths, pair->one->path);
662663
oldpath = old_ent->key;
@@ -779,6 +780,15 @@ static int process_renames(struct merge_options *opt,
779780
/* special handling so later blocks can handle this */
780781
die("Not yet implemented");
781782
}
783+
if (source_deleted) {
784+
if (target_index == 1) {
785+
rename_branch = opt->branch1;
786+
delete_branch = opt->branch2;
787+
} else {
788+
rename_branch = opt->branch2;
789+
delete_branch = opt->branch1;
790+
}
791+
}
782792

783793
assert(source_deleted || oldinfo->filemask & old_sidemask);
784794

@@ -790,13 +800,26 @@ static int process_renames(struct merge_options *opt,
790800
/* rename/add/delete or rename/rename(2to1)/delete */
791801
die("Not yet implemented");
792802
} else {
793-
/* a few different cases... */
803+
/*
804+
* a few different cases...start by copying the
805+
* existing stage(s) from oldinfo over the newinfo
806+
* and update the pathname(s).
807+
*/
808+
memcpy(&newinfo->stages[0], &oldinfo->stages[0],
809+
sizeof(newinfo->stages[0]));
810+
newinfo->filemask |= (1 << MERGE_BASE);
811+
newinfo->pathnames[0] = oldpath;
794812
if (type_changed) {
795813
/* rename vs. typechange */
796814
die("Not yet implemented");
797815
} else if (source_deleted) {
798816
/* rename/delete */
799-
die("Not yet implemented");
817+
newinfo->path_conflict = 1;
818+
path_msg(opt, newpath, 0,
819+
_("CONFLICT (rename/delete): %s renamed"
820+
" to %s in %s, but deleted in %s."),
821+
oldpath, newpath,
822+
rename_branch, delete_branch);
800823
} else {
801824
/* normal rename */
802825
die("Not yet implemented");
@@ -1332,12 +1355,21 @@ static void process_entry(struct merge_options *opt,
13321355
modify_branch = (side == 1) ? opt->branch1 : opt->branch2;
13331356
delete_branch = (side == 1) ? opt->branch2 : opt->branch1;
13341357

1335-
path_msg(opt, path, 0,
1336-
_("CONFLICT (modify/delete): %s deleted in %s "
1337-
"and modified in %s. Version %s of %s left "
1338-
"in tree."),
1339-
path, delete_branch, modify_branch,
1340-
modify_branch, path);
1358+
if (ci->path_conflict &&
1359+
oideq(&ci->stages[0].oid, &ci->stages[side].oid)) {
1360+
/*
1361+
* This came from a rename/delete; no action to take,
1362+
* but avoid printing "modify/delete" conflict notice
1363+
* since the contents were not modified.
1364+
*/
1365+
} else {
1366+
path_msg(opt, path, 0,
1367+
_("CONFLICT (modify/delete): %s deleted in %s "
1368+
"and modified in %s. Version %s of %s left "
1369+
"in tree."),
1370+
path, delete_branch, modify_branch,
1371+
modify_branch, path);
1372+
}
13411373
} else if (ci->filemask == 2 || ci->filemask == 4) {
13421374
/* Added on one side */
13431375
int side = (ci->filemask == 4) ? 2 : 1;

0 commit comments

Comments
 (0)