@ -1072,6 +1072,7 @@ static int process_entry(struct merge_options *o,
unsigned char *a_sha = stage_sha(entry->stages[2].sha, a_mode);
unsigned char *a_sha = stage_sha(entry->stages[2].sha, a_mode);
unsigned char *b_sha = stage_sha(entry->stages[3].sha, b_mode);
unsigned char *b_sha = stage_sha(entry->stages[3].sha, b_mode);
entry->processed = 1;
if (o_sha && (!a_sha || !b_sha)) {
if (o_sha && (!a_sha || !b_sha)) {
/* Case A: Deleted in one */
/* Case A: Deleted in one */
if ((!a_sha && !b_sha) ||
if ((!a_sha && !b_sha) ||
@ -1104,33 +1105,28 @@ static int process_entry(struct merge_options *o,
} else if ((!o_sha && a_sha && !b_sha) ||
} else if ((!o_sha && a_sha && !b_sha) ||
(!o_sha && !a_sha && b_sha)) {
(!o_sha && !a_sha && b_sha)) {
/* Case B: Added in one. */
/* Case B: Added in one. */
const char *add_branch;
const char *other_branch;
unsigned mode;
unsigned mode;
const unsigned char *sha;
const unsigned char *sha;
const char *conf;
if (a_sha) {
if (a_sha) {
add_branch = o->branch1;
other_branch = o->branch2;
mode = a_mode;
mode = a_mode;
sha = a_sha;
sha = a_sha;
conf = "file/directory";
} else {
} else {
add_branch = o->branch2;
other_branch = o->branch1;
mode = b_mode;
mode = b_mode;
sha = b_sha;
sha = b_sha;
conf = "directory/file";
}
}
if (string_list_has_string(&o->current_directory_set, path)) {
if (string_list_has_string(&o->current_directory_set, path)) {
const char *new_path = unique_path(o, path, add_branch);
/* Handle D->F conflicts after all subfiles */
clean_merge = 0;
entry->processed = 0;
output(o, 1, "CONFLICT (%s): There is a directory with name %s in %s. "
/* But get any file out of the way now, so conflicted
"Adding %s as %s",
* entries below the directory of the same name can
conf, path, other_branch, path, new_path);
* be put in the working directory.
remove_file(o, 0, path, 0);
*/
update_file(o, 0, sha, mode, new_path);
if (a_sha)
output(o, 2, "Removing %s", path);
/* do not touch working file if it did not exist */
remove_file(o, 0, path, !a_sha);
return 1; /* Assume clean till processed */
} else {
} else {
output(o, 2, "Adding %s", path);
output(o, 2, "Adding %s", path);
update_file(o, 1, sha, mode, path);
update_file(o, 1, sha, mode, path);
@ -1178,6 +1174,64 @@ static int process_entry(struct merge_options *o,
return clean_merge;
return clean_merge;
}
}
/*
* Per entry merge function for D/F conflicts, to be called only after
* all files below dir have been processed. We do this because in the
* cases we can cleanly resolve D/F conflicts, process_entry() can clean
* out all the files below the directory for us.
*/
static int process_df_entry(struct merge_options *o,
const char *path, struct stage_data *entry)
{
int clean_merge = 1;
unsigned o_mode = entry->stages[1].mode;
unsigned a_mode = entry->stages[2].mode;
unsigned b_mode = entry->stages[3].mode;
unsigned char *o_sha = stage_sha(entry->stages[1].sha, o_mode);
unsigned char *a_sha = stage_sha(entry->stages[2].sha, a_mode);
unsigned char *b_sha = stage_sha(entry->stages[3].sha, b_mode);
const char *add_branch;
const char *other_branch;
unsigned mode;
const unsigned char *sha;
const char *conf;
struct stat st;
/* We currently only handle D->F cases */
assert((!o_sha && a_sha && !b_sha) ||
(!o_sha && !a_sha && b_sha));
entry->processed = 1;
if (a_sha) {
add_branch = o->branch1;
other_branch = o->branch2;
mode = a_mode;
sha = a_sha;
conf = "file/directory";
} else {
add_branch = o->branch2;
other_branch = o->branch1;
mode = b_mode;
sha = b_sha;
conf = "directory/file";
}
if (lstat(path, &st) == 0 && S_ISDIR(st.st_mode)) {
const char *new_path = unique_path(o, path, add_branch);
clean_merge = 0;
output(o, 1, "CONFLICT (%s): There is a directory with name %s in %s. "
"Adding %s as %s",
conf, path, other_branch, path, new_path);
remove_file(o, 0, path, 0);
update_file(o, 0, sha, mode, new_path);
} else {
output(o, 2, "Adding %s", path);
update_file(o, 1, sha, mode, path);
}
return clean_merge;
}
struct unpack_trees_error_msgs get_porcelain_error_msgs(void)
struct unpack_trees_error_msgs get_porcelain_error_msgs(void)
{
{
struct unpack_trees_error_msgs msgs = {
struct unpack_trees_error_msgs msgs = {
@ -1249,6 +1303,13 @@ int merge_trees(struct merge_options *o,
&& !process_entry(o, path, e))
&& !process_entry(o, path, e))
clean = 0;
clean = 0;
}
}
for (i = 0; i < entries->nr; i++) {
const char *path = entries->items[i].string;
struct stage_data *e = entries->items[i].util;
if (!e->processed
&& !process_df_entry(o, path, e))
clean = 0;
}
string_list_clear(re_merge, 0);
string_list_clear(re_merge, 0);
string_list_clear(re_head, 0);
string_list_clear(re_head, 0);