return a && b && hashcmp(a, b) == 0;
}
+enum rename_type {
+ RENAME_NORMAL = 0,
+ RENAME_DELETE,
+ RENAME_ONE_FILE_TO_TWO
+};
+
+struct rename_df_conflict_info {
+ enum rename_type rename_type;
+ struct diff_filepair *pair1;
+ struct diff_filepair *pair2;
+ const char *branch1;
+ const char *branch2;
+ struct stage_data *dst_entry1;
+ struct stage_data *dst_entry2;
+};
+
/*
* Since we want to write the index eventually, we cannot reuse the index
* for these (temporary) data.
unsigned mode;
unsigned char sha[20];
} stages[4];
+ struct rename_df_conflict_info *rename_df_conflict_info;
unsigned processed:1;
};
+static inline void setup_rename_df_conflict_info(enum rename_type rename_type,
+ struct diff_filepair *pair1,
+ struct diff_filepair *pair2,
+ const char *branch1,
+ const char *branch2,
+ struct stage_data *dst_entry1,
+ struct stage_data *dst_entry2)
+{
+ struct rename_df_conflict_info *ci = xcalloc(1, sizeof(struct rename_df_conflict_info));
+ ci->rename_type = rename_type;
+ ci->pair1 = pair1;
+ ci->branch1 = branch1;
+ ci->branch2 = branch2;
+
+ ci->dst_entry1 = dst_entry1;
+ dst_entry1->rename_df_conflict_info = ci;
+ dst_entry1->processed = 0;
+
+ assert(!pair2 == !dst_entry2);
+ if (dst_entry2) {
+ ci->dst_entry2 = dst_entry2;
+ ci->pair2 = pair2;
+ dst_entry2->rename_df_conflict_info = ci;
+ dst_entry2->processed = 0;
+ }
+}
+
static int show(struct merge_options *o, int v)
{
return (!o->call_depth && o->verbosity >= v) || o->verbosity >= 5;
opts.fn = threeway_merge;
opts.src_index = &the_index;
opts.dst_index = &the_index;
- set_porcelain_error_msgs(opts.msgs, "merge");
+ setup_unpack_trees_porcelain(&opts, "merge");
init_tree_desc_from_tree(t+0, common);
init_tree_desc_from_tree(t+1, head);
return renames;
}
-static int update_stages(const char *path, struct diff_filespec *o,
+static int update_stages_options(const char *path, struct diff_filespec *o,
struct diff_filespec *a, struct diff_filespec *b,
- int clear)
+ int clear, int options)
{
- int options = ADD_CACHE_OK_TO_ADD | ADD_CACHE_OK_TO_REPLACE;
if (clear)
if (remove_file_from_cache(path))
return -1;
return 0;
}
+static int update_stages(const char *path, struct diff_filespec *o,
+ struct diff_filespec *a, struct diff_filespec *b,
+ int clear)
+{
+ int options = ADD_CACHE_OK_TO_ADD | ADD_CACHE_OK_TO_REPLACE;
+ return update_stages_options(path, o, a, b, clear, options);
+}
+
+static int update_stages_and_entry(const char *path,
+ struct stage_data *entry,
+ struct diff_filespec *o,
+ struct diff_filespec *a,
+ struct diff_filespec *b,
+ int clear)
+{
+ int options;
+
+ entry->processed = 0;
+ entry->stages[1].mode = o->mode;
+ entry->stages[2].mode = a->mode;
+ entry->stages[3].mode = b->mode;
+ hashcpy(entry->stages[1].sha, o->sha1);
+ hashcpy(entry->stages[2].sha, a->sha1);
+ hashcpy(entry->stages[3].sha, b->sha1);
+ options = ADD_CACHE_OK_TO_ADD | ADD_CACHE_SKIP_DFCHECK;
+ return update_stages_options(path, o, a, b, clear, options);
+}
+
static int remove_file(struct merge_options *o, int clean,
const char *path, int no_wd)
{
return result;
}
-static void conflict_rename_rename(struct merge_options *o,
- struct rename *ren1,
- const char *branch1,
- struct rename *ren2,
- const char *branch2)
+static void conflict_rename_delete(struct merge_options *o,
+ struct diff_filepair *pair,
+ const char *rename_branch,
+ const char *other_branch)
+{
+ char *dest_name = pair->two->path;
+
+ output(o, 1, "CONFLICT (rename/delete): Rename %s->%s in %s "
+ "and deleted in %s",
+ pair->one->path, pair->two->path, rename_branch,
+ other_branch);
+ if (!o->call_depth)
+ update_stages(dest_name, NULL,
+ rename_branch == o->branch1 ? pair->two : NULL,
+ rename_branch == o->branch1 ? NULL : pair->two,
+ 1);
+ update_file(o, 0, pair->two->sha1, pair->two->mode, dest_name);
+}
+
+static void conflict_rename_rename_1to2(struct merge_options *o,
+ struct diff_filepair *pair1,
+ const char *branch1,
+ struct diff_filepair *pair2,
+ const char *branch2)
{
+ /* One file was renamed in both branches, but to different names. */
char *del[2];
int delp = 0;
- const char *ren1_dst = ren1->pair->two->path;
- const char *ren2_dst = ren2->pair->two->path;
+ const char *ren1_dst = pair1->two->path;
+ const char *ren2_dst = pair2->two->path;
const char *dst_name1 = ren1_dst;
const char *dst_name2 = ren2_dst;
if (string_list_has_string(&o->current_directory_set, ren1_dst)) {
/*
* Uncomment to leave the conflicting names in the resulting tree
*
- * update_file(o, 0, ren1->pair->two->sha1, ren1->pair->two->mode, dst_name1);
- * update_file(o, 0, ren2->pair->two->sha1, ren2->pair->two->mode, dst_name2);
+ * update_file(o, 0, pair1->two->sha1, pair1->two->mode, dst_name1);
+ * update_file(o, 0, pair2->two->sha1, pair2->two->mode, dst_name2);
*/
} else {
- update_stages(dst_name1, NULL, ren1->pair->two, NULL, 1);
- update_stages(dst_name2, NULL, NULL, ren2->pair->two, 1);
+ update_stages(ren1_dst, NULL, pair1->two, NULL, 1);
+ update_stages(ren2_dst, NULL, NULL, pair2->two, 1);
+
+ update_file(o, 0, pair1->two->sha1, pair1->two->mode, dst_name1);
+ update_file(o, 0, pair2->two->sha1, pair2->two->mode, dst_name2);
}
while (delp--)
free(del[delp]);
}
-static void conflict_rename_dir(struct merge_options *o,
- struct rename *ren1,
- const char *branch1)
-{
- char *new_path = unique_path(o, ren1->pair->two->path, branch1);
- output(o, 1, "Renaming %s to %s instead", ren1->pair->one->path, new_path);
- remove_file(o, 0, ren1->pair->two->path, 0);
- update_file(o, 0, ren1->pair->two->sha1, ren1->pair->two->mode, new_path);
- free(new_path);
-}
-
-static void conflict_rename_rename_2(struct merge_options *o,
- struct rename *ren1,
- const char *branch1,
- struct rename *ren2,
- const char *branch2)
+static void conflict_rename_rename_2to1(struct merge_options *o,
+ struct rename *ren1,
+ const char *branch1,
+ struct rename *ren2,
+ const char *branch2)
{
+ /* Two files were renamed to the same thing. */
char *new_path1 = unique_path(o, ren1->pair->two->path, branch1);
char *new_path2 = unique_path(o, ren2->pair->two->path, branch2);
output(o, 1, "Renaming %s to %s and %s to %s instead",
ren2->dst_entry->processed = 1;
ren2->processed = 1;
if (strcmp(ren1_dst, ren2_dst) != 0) {
- clean_merge = 0;
- output(o, 1, "CONFLICT (rename/rename): "
- "Rename \"%s\"->\"%s\" in branch \"%s\" "
- "rename \"%s\"->\"%s\" in \"%s\"%s",
- src, ren1_dst, branch1,
- src, ren2_dst, branch2,
- o->call_depth ? " (left unresolved)": "");
- if (o->call_depth) {
- remove_file_from_cache(src);
- update_file(o, 0, ren1->pair->one->sha1,
- ren1->pair->one->mode, src);
- }
- conflict_rename_rename(o, ren1, branch1, ren2, branch2);
+ setup_rename_df_conflict_info(RENAME_ONE_FILE_TO_TWO,
+ ren1->pair,
+ ren2->pair,
+ branch1,
+ branch2,
+ ren1->dst_entry,
+ ren2->dst_entry);
+ remove_file(o, 0, ren1_dst, 0);
+ /* ren2_dst not in head, so no need to delete */
} else {
- struct merge_file_info mfi;
remove_file(o, 1, ren1_src, 1);
- mfi = merge_file(o,
- ren1->pair->one,
- ren1->pair->two,
- ren2->pair->two,
- branch1,
- branch2);
- if (mfi.merge || !mfi.clean)
- output(o, 1, "Renaming %s->%s", src, ren1_dst);
-
- if (mfi.merge)
- output(o, 2, "Auto-merging %s", ren1_dst);
-
- if (!mfi.clean) {
- output(o, 1, "CONFLICT (content): merge conflict in %s",
- ren1_dst);
- clean_merge = 0;
-
- if (!o->call_depth)
- update_stages(ren1_dst,
- ren1->pair->one,
- ren1->pair->two,
- ren2->pair->two,
- 1 /* clear */);
- }
- update_file(o, mfi.clean, mfi.sha, mfi.mode, ren1_dst);
+ update_stages_and_entry(ren1_dst,
+ ren1->dst_entry,
+ ren1->pair->one,
+ ren1->pair->two,
+ ren2->pair->two,
+ 1 /* clear */);
}
} else {
/* Renamed in 1, maybe changed in 2 */
struct string_list_item *item;
/* we only use sha1 and mode of these */
struct diff_filespec src_other, dst_other;
- int try_merge, stage = a_renames == renames1 ? 3: 2;
+ int try_merge;
- remove_file(o, 1, ren1_src, o->call_depth || stage == 3);
+ /*
+ * unpack_trees loads entries from common-commit
+ * into stage 1, from head-commit into stage 2, and
+ * from merge-commit into stage 3. We keep track
+ * of which side corresponds to the rename.
+ */
+ int renamed_stage = a_renames == renames1 ? 2 : 3;
+ int other_stage = a_renames == renames1 ? 3 : 2;
- hashcpy(src_other.sha1, ren1->src_entry->stages[stage].sha);
- src_other.mode = ren1->src_entry->stages[stage].mode;
- hashcpy(dst_other.sha1, ren1->dst_entry->stages[stage].sha);
- dst_other.mode = ren1->dst_entry->stages[stage].mode;
+ remove_file(o, 1, ren1_src, o->call_depth || renamed_stage == 2);
+ hashcpy(src_other.sha1, ren1->src_entry->stages[other_stage].sha);
+ src_other.mode = ren1->src_entry->stages[other_stage].mode;
+ hashcpy(dst_other.sha1, ren1->dst_entry->stages[other_stage].sha);
+ dst_other.mode = ren1->dst_entry->stages[other_stage].mode;
try_merge = 0;
- if (string_list_has_string(&o->current_directory_set, ren1_dst)) {
- clean_merge = 0;
- output(o, 1, "CONFLICT (rename/directory): Rename %s->%s in %s "
- " directory %s added in %s",
- ren1_src, ren1_dst, branch1,
- ren1_dst, branch2);
- conflict_rename_dir(o, ren1, branch1);
- } else if (sha_eq(src_other.sha1, null_sha1)) {
- clean_merge = 0;
- output(o, 1, "CONFLICT (rename/delete): Rename %s->%s in %s "
- "and deleted in %s",
- ren1_src, ren1_dst, branch1,
- branch2);
- update_file(o, 0, ren1->pair->two->sha1, ren1->pair->two->mode, ren1_dst);
- if (!o->call_depth)
- update_stages(ren1_dst, NULL,
- branch1 == o->branch1 ?
- ren1->pair->two : NULL,
- branch1 == o->branch1 ?
- NULL : ren1->pair->two, 1);
+ if (sha_eq(src_other.sha1, null_sha1)) {
+ if (string_list_has_string(&o->current_directory_set, ren1_dst)) {
+ ren1->dst_entry->processed = 0;
+ setup_rename_df_conflict_info(RENAME_DELETE,
+ ren1->pair,
+ NULL,
+ branch1,
+ branch2,
+ ren1->dst_entry,
+ NULL);
+ remove_file(o, 0, ren1_dst, 0);
+ } else {
+ clean_merge = 0;
+ conflict_rename_delete(o, ren1->pair, branch1, branch2);
+ }
+ } else if ((dst_other.mode == ren1->pair->two->mode) &&
+ sha_eq(dst_other.sha1, ren1->pair->two->sha1)) {
+ /* Added file on the other side
+ identical to the file being
+ renamed: clean merge */
+ update_file(o, 1, ren1->pair->two->sha1, ren1->pair->two->mode, ren1_dst);
} else if (!sha_eq(dst_other.sha1, null_sha1)) {
const char *new_path;
clean_merge = 0;
mfi.sha,
mfi.mode,
ren1_dst);
+ try_merge = 0;
} else {
new_path = unique_path(o, ren1_dst, branch2);
output(o, 1, "Adding as %s instead", new_path);
"Rename %s->%s in %s",
ren1_src, ren1_dst, branch1,
ren2->pair->one->path, ren2->pair->two->path, branch2);
- conflict_rename_rename_2(o, ren1, branch1, ren2, branch2);
+ conflict_rename_rename_2to1(o, ren1, branch1, ren2, branch2);
} else
try_merge = 1;
if (try_merge) {
struct diff_filespec *one, *a, *b;
- struct merge_file_info mfi;
src_other.path = (char *)ren1_src;
one = ren1->pair->one;
b = ren1->pair->two;
a = &src_other;
}
- mfi = merge_file(o, one, a, b,
- o->branch1, o->branch2);
-
- if (mfi.clean &&
- sha_eq(mfi.sha, ren1->pair->two->sha1) &&
- mfi.mode == ren1->pair->two->mode) {
- /*
- * This message is part of
- * t6022 test. If you change
- * it update the test too.
- */
- output(o, 3, "Skipped %s (merged same as existing)", ren1_dst);
-
- /* There may be higher stage entries left
- * in the index (e.g. due to a D/F
- * conflict) that need to be resolved.
- */
- if (!ren1->dst_entry->stages[2].mode !=
- !ren1->dst_entry->stages[3].mode)
- ren1->dst_entry->processed = 0;
- } else {
- if (mfi.merge || !mfi.clean)
- output(o, 1, "Renaming %s => %s", ren1_src, ren1_dst);
- if (mfi.merge)
- output(o, 2, "Auto-merging %s", ren1_dst);
- if (!mfi.clean) {
- output(o, 1, "CONFLICT (rename/modify): Merge conflict in %s",
- ren1_dst);
- clean_merge = 0;
-
- if (!o->call_depth)
- update_stages(ren1_dst,
- one, a, b, 1);
- }
- update_file(o, mfi.clean, mfi.sha, mfi.mode, ren1_dst);
+ update_stages_and_entry(ren1_dst, ren1->dst_entry, one, a, b, 1);
+ if (string_list_has_string(&o->current_directory_set, ren1_dst)) {
+ setup_rename_df_conflict_info(RENAME_NORMAL,
+ ren1->pair,
+ NULL,
+ branch1,
+ NULL,
+ ren1->dst_entry,
+ NULL);
+ remove_file(o, 0, ren1_dst, 0);
}
}
}
return ret;
}
+static void handle_delete_modify(struct merge_options *o,
+ const char *path,
+ unsigned char *a_sha, int a_mode,
+ unsigned char *b_sha, int b_mode)
+{
+ if (!a_sha) {
+ output(o, 1, "CONFLICT (delete/modify): %s deleted in %s "
+ "and modified in %s. Version %s of %s left in tree.",
+ path, o->branch1,
+ o->branch2, o->branch2, path);
+ update_file(o, 0, b_sha, b_mode, path);
+ } else {
+ output(o, 1, "CONFLICT (delete/modify): %s deleted in %s "
+ "and modified in %s. Version %s of %s left in tree.",
+ path, o->branch2,
+ o->branch1, o->branch1, path);
+ update_file(o, 0, a_sha, a_mode, path);
+ }
+}
+
+
+static int merge_content(struct merge_options *o,
+ const char *path,
+ unsigned char *o_sha, int o_mode,
+ unsigned char *a_sha, int a_mode,
+ unsigned char *b_sha, int b_mode,
+ const char *df_rename_conflict_branch)
+{
+ const char *reason = "content";
+ struct merge_file_info mfi;
+ struct diff_filespec one, a, b;
+
+ if (!o_sha) {
+ reason = "add/add";
+ o_sha = (unsigned char *)null_sha1;
+ }
+ one.path = a.path = b.path = (char *)path;
+ hashcpy(one.sha1, o_sha);
+ one.mode = o_mode;
+ hashcpy(a.sha1, a_sha);
+ a.mode = a_mode;
+ hashcpy(b.sha1, b_sha);
+ b.mode = b_mode;
+
+ mfi = merge_file(o, &one, &a, &b, o->branch1, o->branch2);
+ if (mfi.clean && sha_eq(mfi.sha, a_sha) && mfi.mode == a.mode)
+ output(o, 3, "Skipped %s (merged same as existing)", path);
+ else
+ output(o, 2, "Auto-merging %s", path);
+
+ if (!mfi.clean) {
+ if (S_ISGITLINK(mfi.mode))
+ reason = "submodule";
+ output(o, 1, "CONFLICT (%s): Merge conflict in %s",
+ reason, path);
+ }
+
+ update_file(o, mfi.clean, mfi.sha, mfi.mode, path);
+ return mfi.clean;
+
+}
+
/* Per entry merge function */
static int process_entry(struct merge_options *o,
const char *path, struct stage_data *entry)
unsigned char *a_sha = stage_sha(entry->stages[2].sha, a_mode);
unsigned char *b_sha = stage_sha(entry->stages[3].sha, b_mode);
+ if (entry->rename_df_conflict_info)
+ return 1; /* Such cases are handled elsewhere. */
+
entry->processed = 1;
if (o_sha && (!a_sha || !b_sha)) {
/* Case A: Deleted in one */
} else {
/* Deleted in one and changed in the other */
clean_merge = 0;
- if (!a_sha) {
- output(o, 1, "CONFLICT (delete/modify): %s deleted in %s "
- "and modified in %s. Version %s of %s left in tree.",
- path, o->branch1,
- o->branch2, o->branch2, path);
- update_file(o, 0, b_sha, b_mode, path);
- } else {
- output(o, 1, "CONFLICT (delete/modify): %s deleted in %s "
- "and modified in %s. Version %s of %s left in tree.",
- path, o->branch2,
- o->branch1, o->branch1, path);
- update_file(o, 0, a_sha, a_mode, path);
- }
+ handle_delete_modify(o, path,
+ a_sha, a_mode, b_sha, b_mode);
}
} else if ((!o_sha && a_sha && !b_sha) ||
} else if (a_sha && b_sha) {
/* Case C: Added in both (check for same permissions) and */
/* case D: Modified in both, but differently. */
- const char *reason = "content";
- struct merge_file_info mfi;
- struct diff_filespec one, a, b;
-
- if (!o_sha) {
- reason = "add/add";
- o_sha = (unsigned char *)null_sha1;
- }
- output(o, 2, "Auto-merging %s", path);
- one.path = a.path = b.path = (char *)path;
- hashcpy(one.sha1, o_sha);
- one.mode = o_mode;
- hashcpy(a.sha1, a_sha);
- a.mode = a_mode;
- hashcpy(b.sha1, b_sha);
- b.mode = b_mode;
-
- mfi = merge_file(o, &one, &a, &b,
- o->branch1, o->branch2);
-
- clean_merge = mfi.clean;
- if (!mfi.clean) {
- if (S_ISGITLINK(mfi.mode))
- reason = "submodule";
- output(o, 1, "CONFLICT (%s): Merge conflict in %s",
- reason, path);
- }
- update_file(o, mfi.clean, mfi.sha, mfi.mode, path);
+ clean_merge = merge_content(o, path,
+ o_sha, o_mode, a_sha, a_mode, b_sha, b_mode,
+ NULL);
} else if (!o_sha && !a_sha && !b_sha) {
/*
* this entry was deleted altogether. a_mode == 0 means
}
/*
- * 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.
+ * Per entry merge function for D/F (and/or rename) conflicts. In the
+ * cases we can cleanly resolve D/F conflicts, process_entry() can
+ * clean out all the files below the directory for us. All D/F
+ * conflict cases must be handled here at the end to make sure any
+ * directories that can be cleaned out, are.
+ *
+ * Some rename conflicts may also be handled here that don't necessarily
+ * involve D/F conflicts, since the code to handle them is generic enough
+ * to handle those rename conflicts with or without D/F conflicts also
+ * being involved.
*/
static int process_df_entry(struct merge_options *o,
- const char *path, struct stage_data *entry)
+ const char *path, struct stage_data *entry)
{
int clean_merge = 1;
unsigned o_mode = entry->stages[1].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 (entry->rename_df_conflict_info) {
+ struct rename_df_conflict_info *conflict_info = entry->rename_df_conflict_info;
+ char *src;
+ switch (conflict_info->rename_type) {
+ case RENAME_NORMAL:
+ clean_merge = merge_content(o, path,
+ o_sha, o_mode, a_sha, a_mode, b_sha, b_mode,
+ conflict_info->branch1);
+ break;
+ case RENAME_DELETE:
+ clean_merge = 0;
+ conflict_rename_delete(o, conflict_info->pair1,
+ conflict_info->branch1,
+ conflict_info->branch2);
+ break;
+ case RENAME_ONE_FILE_TO_TWO:
+ src = conflict_info->pair1->one->path;
+ clean_merge = 0;
+ output(o, 1, "CONFLICT (rename/rename): "
+ "Rename \"%s\"->\"%s\" in branch \"%s\" "
+ "rename \"%s\"->\"%s\" in \"%s\"%s",
+ src, conflict_info->pair1->two->path, conflict_info->branch1,
+ src, conflict_info->pair2->two->path, conflict_info->branch2,
+ o->call_depth ? " (left unresolved)" : "");
+ if (o->call_depth) {
+ remove_file_from_cache(src);
+ update_file(o, 0, conflict_info->pair1->one->sha1,
+ conflict_info->pair1->one->mode, src);
+ }
+ conflict_rename_rename_1to2(o, conflict_info->pair1,
+ conflict_info->branch1,
+ conflict_info->pair2,
+ conflict_info->branch2);
+ conflict_info->dst_entry2->processed = 1;
+ break;
+ default:
+ entry->processed = 0;
+ break;
+ }
+ } else if (!o_sha && !!a_sha != !!b_sha) {
+ /* directory -> (directory, file) */
+ const char *add_branch;
+ const char *other_branch;
+ unsigned mode;
+ const unsigned char *sha;
+ const char *conf;
- 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);
+ 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);
+ }
} else {
- output(o, 2, "Adding %s", path);
- update_file(o, 1, sha, mode, path);
+ entry->processed = 0;
+ return 1; /* not handled; assume clean until processed */
}
return clean_merge;
}
-void set_porcelain_error_msgs(const char **msgs, const char *cmd)
-{
- const char *msg;
- char *tmp;
- const char *cmd2 = strcmp(cmd, "checkout") ? cmd : "switch branches";
- if (advice_commit_before_merge)
- msg = "Your local changes to the following files would be overwritten by %s:\n%%s"
- "Please, commit your changes or stash them before you can %s.";
- else
- msg = "Your local changes to the following files would be overwritten by %s:\n%%s";
- tmp = xmalloc(strlen(msg) + strlen(cmd) + strlen(cmd2) - 2);
- sprintf(tmp, msg, cmd, cmd2);
- msgs[ERROR_WOULD_OVERWRITE] = tmp;
- msgs[ERROR_NOT_UPTODATE_FILE] = tmp;
-
- msgs[ERROR_NOT_UPTODATE_DIR] =
- "Updating the following directories would lose untracked files in it:\n%s";
-
- if (advice_commit_before_merge)
- msg = "The following untracked working tree files would be %s by %s:\n%%s"
- "Please move or remove them before you can %s.";
- else
- msg = "The following untracked working tree files would be %s by %s:\n%%s";
- tmp = xmalloc(strlen(msg) + strlen(cmd) + strlen("removed") + strlen(cmd2) - 4);
- sprintf(tmp, msg, "removed", cmd, cmd2);
- msgs[ERROR_WOULD_LOSE_UNTRACKED_REMOVED] = tmp;
- tmp = xmalloc(strlen(msg) + strlen(cmd) + strlen("overwritten") + strlen(cmd2) - 4);
- sprintf(tmp, msg, "overwritten", cmd, cmd2);
- msgs[ERROR_WOULD_LOSE_UNTRACKED_OVERWRITTEN] = tmp;
-
- /*
- * Special case: ERROR_BIND_OVERLAP refers to a pair of paths, we
- * cannot easily display it as a list.
- */
- msgs[ERROR_BIND_OVERLAP] = "Entry '%s' overlaps with '%s'. Cannot bind.";
-
- msgs[ERROR_SPARSE_NOT_UPTODATE_FILE] =
- "Cannot update sparse checkout: the following entries are not up-to-date:\n%s";
- msgs[ERROR_WOULD_LOSE_ORPHANED_OVERWRITTEN] =
- "The following Working tree files would be overwritten by sparse checkout update:\n%s";
- msgs[ERROR_WOULD_LOSE_ORPHANED_REMOVED] =
- "The following Working tree files would be removed by sparse checkout update:\n%s";
-}
-
int merge_trees(struct merge_options *o,
struct tree *head,
struct tree *merge,
&& !process_df_entry(o, path, e))
clean = 0;
}
+ for (i = 0; i < entries->nr; i++) {
+ struct stage_data *e = entries->items[i].util;
+ if (!e->processed)
+ die("Unprocessed path??? %s",
+ entries->items[i].string);
+ }
string_list_clear(re_merge, 0);
string_list_clear(re_head, 0);