summaryrefslogtreecommitdiff
path: root/merge-recursive.c
diff options
context:
space:
mode:
Diffstat (limited to 'merge-recursive.c')
-rw-r--r--merge-recursive.c142
1 files changed, 74 insertions, 68 deletions
diff --git a/merge-recursive.c b/merge-recursive.c
index cb53b01c19..656e769b44 100644
--- a/merge-recursive.c
+++ b/merge-recursive.c
@@ -136,16 +136,10 @@ static void output_commit_title(struct merge_options *o, struct commit *commit)
if (parse_commit(commit) != 0)
printf("(bad commit)\n");
else {
- const char *s;
- int len;
- for (s = commit->buffer; *s; s++)
- if (*s == '\n' && s[1] == '\n') {
- s += 2;
- break;
- }
- for (len = 0; s[len] && '\n' != s[len]; len++)
- ; /* do nothing */
- printf("%.*s\n", len, s);
+ const char *title;
+ int len = find_commit_subject(commit->buffer, &title);
+ if (len)
+ printf("%.*s\n", len, title);
}
}
}
@@ -185,7 +179,7 @@ static int git_merge_trees(int index_only,
opts.fn = threeway_merge;
opts.src_index = &the_index;
opts.dst_index = &the_index;
- opts.msgs = get_porcelain_error_msgs();
+ set_porcelain_error_msgs(opts.msgs, "merge");
init_tree_desc_from_tree(t+0, common);
init_tree_desc_from_tree(t+1, head);
@@ -238,9 +232,9 @@ static int save_files_dirs(const unsigned char *sha1,
newpath[baselen + len] = '\0';
if (S_ISDIR(mode))
- string_list_insert(newpath, &o->current_directory_set);
+ string_list_insert(&o->current_directory_set, newpath);
else
- string_list_insert(newpath, &o->current_file_set);
+ string_list_insert(&o->current_file_set, newpath);
free(newpath);
return (S_ISDIR(mode) ? READ_TREE_RECURSIVE : 0);
@@ -271,7 +265,7 @@ static struct stage_data *insert_stage_data(const char *path,
e->stages[2].sha, &e->stages[2].mode);
get_tree_entry(b->object.sha1, path,
e->stages[3].sha, &e->stages[3].mode);
- item = string_list_insert(path, entries);
+ item = string_list_insert(entries, path);
item->util = e;
return e;
}
@@ -294,9 +288,9 @@ static struct string_list *get_unmerged(void)
if (!ce_stage(ce))
continue;
- item = string_list_lookup(ce->name, unmerged);
+ item = string_list_lookup(unmerged, ce->name);
if (!item) {
- item = string_list_insert(ce->name, unmerged);
+ item = string_list_insert(unmerged, ce->name);
item->util = xcalloc(1, sizeof(struct stage_data));
}
e = item->util;
@@ -356,20 +350,20 @@ static struct string_list *get_renames(struct merge_options *o,
re = xmalloc(sizeof(*re));
re->processed = 0;
re->pair = pair;
- item = string_list_lookup(re->pair->one->path, entries);
+ item = string_list_lookup(entries, re->pair->one->path);
if (!item)
re->src_entry = insert_stage_data(re->pair->one->path,
o_tree, a_tree, b_tree, entries);
else
re->src_entry = item->util;
- item = string_list_lookup(re->pair->two->path, entries);
+ item = string_list_lookup(entries, re->pair->two->path);
if (!item)
re->dst_entry = insert_stage_data(re->pair->two->path,
o_tree, a_tree, b_tree, entries);
else
re->dst_entry = item->util;
- item = string_list_insert(pair->one->path, renames);
+ item = string_list_insert(renames, pair->one->path);
item->util = re;
}
opts.output_format = DIFF_FORMAT_NO_OUTPUT;
@@ -409,7 +403,7 @@ static int remove_file(struct merge_options *o, int clean,
return -1;
}
if (update_working_directory) {
- if (remove_path(path) && errno != ENOENT)
+ if (remove_path(path))
return -1;
}
return 0;
@@ -432,7 +426,7 @@ static char *unique_path(struct merge_options *o, const char *path, const char *
lstat(newpath, &st) == 0)
sprintf(p, "_%d", suffix++);
- string_list_insert(newpath, &o->current_file_set);
+ string_list_insert(&o->current_file_set, newpath);
return newpath;
}
@@ -599,23 +593,6 @@ struct merge_file_info
merge:1;
};
-static void fill_mm(const unsigned char *sha1, mmfile_t *mm)
-{
- unsigned long size;
- enum object_type type;
-
- if (!hashcmp(sha1, null_sha1)) {
- mm->ptr = xstrdup("");
- mm->size = 0;
- return;
- }
-
- mm->ptr = read_sha1_file(sha1, &type, &size);
- if (!mm->ptr || type != OBJ_BLOB)
- die("unable to read blob object %s", sha1_to_hex(sha1));
- mm->size = size;
-}
-
static int merge_3way(struct merge_options *o,
mmbuffer_t *result_buf,
struct diff_filespec *one,
@@ -625,7 +602,7 @@ static int merge_3way(struct merge_options *o,
const char *branch2)
{
mmfile_t orig, src1, src2;
- char *name1, *name2;
+ char *base_name, *name1, *name2;
int merge_status;
int favor;
@@ -645,19 +622,24 @@ static int merge_3way(struct merge_options *o,
}
}
- if (strcmp(a->path, b->path)) {
+ if (strcmp(a->path, b->path) ||
+ (o->ancestor != NULL && strcmp(a->path, one->path) != 0)) {
+ base_name = o->ancestor == NULL ? NULL :
+ xstrdup(mkpath("%s:%s", o->ancestor, one->path));
name1 = xstrdup(mkpath("%s:%s", branch1, a->path));
name2 = xstrdup(mkpath("%s:%s", branch2, b->path));
} else {
+ base_name = o->ancestor == NULL ? NULL :
+ xstrdup(mkpath("%s", o->ancestor));
name1 = xstrdup(mkpath("%s", branch1));
name2 = xstrdup(mkpath("%s", branch2));
}
- fill_mm(one->sha1, &orig);
- fill_mm(a->sha1, &src1);
- fill_mm(b->sha1, &src2);
+ read_mmblob(&orig, one->sha1);
+ read_mmblob(&src1, a->sha1);
+ read_mmblob(&src2, b->sha1);
- merge_status = ll_merge(result_buf, a->path, &orig,
+ merge_status = ll_merge(result_buf, a->path, &orig, base_name,
&src1, name1, &src2, name2,
(!!o->call_depth) | (favor << 1));
@@ -818,17 +800,18 @@ static int process_renames(struct merge_options *o,
struct string_list *b_renames)
{
int clean_merge = 1, i, j;
- struct string_list a_by_dst = {NULL, 0, 0, 0}, b_by_dst = {NULL, 0, 0, 0};
+ struct string_list a_by_dst = STRING_LIST_INIT_NODUP;
+ struct string_list b_by_dst = STRING_LIST_INIT_NODUP;
const struct rename *sre;
for (i = 0; i < a_renames->nr; i++) {
sre = a_renames->items[i].util;
- string_list_insert(sre->pair->two->path, &a_by_dst)->util
+ string_list_insert(&a_by_dst, sre->pair->two->path)->util
= sre->dst_entry;
}
for (i = 0; i < b_renames->nr; i++) {
sre = b_renames->items[i].util;
- string_list_insert(sre->pair->two->path, &b_by_dst)->util
+ string_list_insert(&b_by_dst, sre->pair->two->path)->util
= sre->dst_entry;
}
@@ -1000,7 +983,7 @@ static int process_renames(struct merge_options *o,
output(o, 1, "Adding as %s instead", new_path);
update_file(o, 0, dst_other.sha1, dst_other.mode, new_path);
}
- } else if ((item = string_list_lookup(ren1_dst, renames2Dst))) {
+ } else if ((item = string_list_lookup(renames2Dst, ren1_dst))) {
ren2 = item->util;
clean_merge = 0;
ren2->processed = 1;
@@ -1190,26 +1173,48 @@ static int process_entry(struct merge_options *o,
return clean_merge;
}
-struct unpack_trees_error_msgs get_porcelain_error_msgs(void)
+void set_porcelain_error_msgs(const char **msgs, const char *cmd)
{
- struct unpack_trees_error_msgs msgs = {
- /* would_overwrite */
- "Your local changes to '%s' would be overwritten by merge. Aborting.",
- /* not_uptodate_file */
- "Your local changes to '%s' would be overwritten by merge. Aborting.",
- /* not_uptodate_dir */
- "Updating '%s' would lose untracked files in it. Aborting.",
- /* would_lose_untracked */
- "Untracked working tree file '%s' would be %s by merge. Aborting",
- /* bind_overlap -- will not happen here */
- NULL,
- };
- if (advice_commit_before_merge) {
- msgs.would_overwrite = msgs.not_uptodate_file =
- "Your local changes to '%s' would be overwritten by merge. Aborting.\n"
- "Please, commit your changes or stash them before you can merge.";
- }
- return msgs;
+ 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,
@@ -1226,7 +1231,7 @@ int merge_trees(struct merge_options *o,
}
if (sha_eq(common->object.sha1, merge->object.sha1)) {
- output(o, 0, "Already uptodate!");
+ output(o, 0, "Already up-to-date!");
*result = head;
return 1;
}
@@ -1359,6 +1364,7 @@ int merge_recursive(struct merge_options *o,
if (!o->call_depth)
read_cache();
+ o->ancestor = "merged common ancestors";
clean = merge_trees(o, h1->tree, h2->tree, merged_common_ancestors->tree,
&mrtree);