summaryrefslogtreecommitdiff
path: root/merge-ort.c
diff options
context:
space:
mode:
authorElijah Newren <newren@gmail.com>2020-12-15 18:28:03 (GMT)
committerJunio C Hamano <gitster@pobox.com>2020-12-16 01:18:32 (GMT)
commit2e91ddd24e7240460fd2a9aee1962345ed858b6b (patch)
tree21444b6eebe728c3004916edd16fe1891aae11f4 /merge-ort.c
parent53e88a03539db70a7e990489784400b0b2916fa9 (diff)
downloadgit-2e91ddd24e7240460fd2a9aee1962345ed858b6b.zip
git-2e91ddd24e7240460fd2a9aee1962345ed858b6b.tar.gz
git-2e91ddd24e7240460fd2a9aee1962345ed858b6b.tar.bz2
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 66c62eaec6 ("Merge branch 'en/merge-tests'", 2020-11-18), especially commit ef52778708 ("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>
Diffstat (limited to 'merge-ort.c')
-rw-r--r--merge-ort.c48
1 files changed, 40 insertions, 8 deletions
diff --git a/merge-ort.c b/merge-ort.c
index 19477cf..a10c3f5 100644
--- a/merge-ort.c
+++ b/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;