Skip to content

Commit 23366d2

Browse files
newrengitster
authored andcommitted
merge-ort: handle directory/file conflicts that remain
When a directory/file conflict remains, we can leave the directory where it is, but need to move the information about the file to a different pathname. After moving the file to a different pathname, we allow subsequent process_entry() logic to handle any additional details that might be relevant. This depends on a new helper function, unique_path(), that dies with an unimplemented error currently but will be implemented in a subsequent commit. Signed-off-by: Elijah Newren <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 0ccfa4e commit 23366d2

File tree

1 file changed

+84
-2
lines changed

1 file changed

+84
-2
lines changed

merge-ort.c

Lines changed: 84 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -343,6 +343,13 @@ static void path_msg(struct merge_options *opt,
343343
strbuf_addch(sb, '\n');
344344
}
345345

346+
static char *unique_path(struct strmap *existing_paths,
347+
const char *path,
348+
const char *branch)
349+
{
350+
die("Not yet implemented.");
351+
}
352+
346353
/*** Function Grouping: functions related to collect_merge_info() ***/
347354

348355
static void setup_path_info(struct merge_options *opt,
@@ -962,6 +969,8 @@ static void process_entry(struct merge_options *opt,
962969
struct conflict_info *ci,
963970
struct directory_versions *dir_metadata)
964971
{
972+
int df_file_index = 0;
973+
965974
VERIFY_CI(ci);
966975
assert(ci->filemask >= 0 && ci->filemask <= 7);
967976
/* ci->match_mask == 7 was handled in collect_merge_info_callback() */
@@ -998,13 +1007,86 @@ static void process_entry(struct merge_options *opt,
9981007
oidcpy(&ci->stages[i].oid, &null_oid);
9991008
}
10001009
} else if (ci->df_conflict && ci->merged.result.mode != 0) {
1001-
die("Not yet implemented.");
1010+
/*
1011+
* This started out as a D/F conflict, and the entries in
1012+
* the competing directory were not removed by the merge as
1013+
* evidenced by write_completed_directory() writing a value
1014+
* to ci->merged.result.mode.
1015+
*/
1016+
struct conflict_info *new_ci;
1017+
const char *branch;
1018+
const char *old_path = path;
1019+
int i;
1020+
1021+
assert(ci->merged.result.mode == S_IFDIR);
1022+
1023+
/*
1024+
* If filemask is 1, we can just ignore the file as having
1025+
* been deleted on both sides. We do not want to overwrite
1026+
* ci->merged.result, since it stores the tree for all the
1027+
* files under it.
1028+
*/
1029+
if (ci->filemask == 1) {
1030+
ci->filemask = 0;
1031+
return;
1032+
}
1033+
1034+
/*
1035+
* This file still exists on at least one side, and we want
1036+
* the directory to remain here, so we need to move this
1037+
* path to some new location.
1038+
*/
1039+
new_ci = xcalloc(1, sizeof(*new_ci));
1040+
/* We don't really want new_ci->merged.result copied, but it'll
1041+
* be overwritten below so it doesn't matter. We also don't
1042+
* want any directory mode/oid values copied, but we'll zero
1043+
* those out immediately. We do want the rest of ci copied.
1044+
*/
1045+
memcpy(new_ci, ci, sizeof(*ci));
1046+
new_ci->match_mask = (new_ci->match_mask & ~new_ci->dirmask);
1047+
new_ci->dirmask = 0;
1048+
for (i = MERGE_BASE; i <= MERGE_SIDE2; i++) {
1049+
if (new_ci->filemask & (1 << i))
1050+
continue;
1051+
/* zero out any entries related to directories */
1052+
new_ci->stages[i].mode = 0;
1053+
oidcpy(&new_ci->stages[i].oid, &null_oid);
1054+
}
1055+
1056+
/*
1057+
* Find out which side this file came from; note that we
1058+
* cannot just use ci->filemask, because renames could cause
1059+
* the filemask to go back to 7. So we use dirmask, then
1060+
* pick the opposite side's index.
1061+
*/
1062+
df_file_index = (ci->dirmask & (1 << 1)) ? 2 : 1;
1063+
branch = (df_file_index == 1) ? opt->branch1 : opt->branch2;
1064+
path = unique_path(&opt->priv->paths, path, branch);
1065+
strmap_put(&opt->priv->paths, path, new_ci);
1066+
1067+
path_msg(opt, path, 0,
1068+
_("CONFLICT (file/directory): directory in the way "
1069+
"of %s from %s; moving it to %s instead."),
1070+
old_path, branch, path);
1071+
1072+
/*
1073+
* Zero out the filemask for the old ci. At this point, ci
1074+
* was just an entry for a directory, so we don't need to
1075+
* do anything more with it.
1076+
*/
1077+
ci->filemask = 0;
1078+
1079+
/*
1080+
* Now note that we're working on the new entry (path was
1081+
* updated above.
1082+
*/
1083+
ci = new_ci;
10021084
}
10031085

10041086
/*
10051087
* NOTE: Below there is a long switch-like if-elseif-elseif... block
10061088
* which the code goes through even for the df_conflict cases
1007-
* above. Well, it will once we don't die-not-implemented above.
1089+
* above.
10081090
*/
10091091
if (ci->match_mask) {
10101092
ci->merged.clean = 1;

0 commit comments

Comments
 (0)