diff options
Diffstat (limited to 'merge-recursive.c')
-rw-r--r-- | merge-recursive.c | 163 |
1 files changed, 114 insertions, 49 deletions
diff --git a/merge-recursive.c b/merge-recursive.c index f5df9b961b..206c103635 100644 --- a/merge-recursive.c +++ b/merge-recursive.c @@ -3,6 +3,7 @@ * Fredrik Kuivinen. * The thieves were Alex Riesen and Johannes Schindelin, in June/July 2006 */ +#include "advice.h" #include "cache.h" #include "cache-tree.h" #include "commit.h" @@ -20,15 +21,17 @@ #include "merge-recursive.h" #include "dir.h" -static struct tree *shift_tree_object(struct tree *one, struct tree *two) +static struct tree *shift_tree_object(struct tree *one, struct tree *two, + const char *subtree_shift) { unsigned char shifted[20]; - /* - * NEEDSWORK: this limits the recursion depth to hardcoded - * value '2' to avoid excessive overhead. - */ - shift_tree(one->object.sha1, two->object.sha1, shifted, 2); + if (!*subtree_shift) { + shift_tree(one->object.sha1, two->object.sha1, shifted, 0); + } else { + shift_tree_by(one->object.sha1, two->object.sha1, shifted, + subtree_shift); + } if (!hashcmp(two->object.sha1, shifted)) return two; return lookup_tree(shifted); @@ -38,7 +41,7 @@ static struct tree *shift_tree_object(struct tree *one, struct tree *two) * A virtual commit has (const char *)commit->util set to the name. */ -struct commit *make_virtual_commit(struct tree *tree, const char *comment) +static struct commit *make_virtual_commit(struct tree *tree, const char *comment) { struct commit *commit = xcalloc(1, sizeof(struct commit)); commit->tree = tree; @@ -86,6 +89,7 @@ static void flush_output(struct merge_options *o) } } +__attribute__((format (printf, 3, 4))) static void output(struct merge_options *o, int v, const char *fmt, ...) { int len; @@ -181,6 +185,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(); init_tree_desc_from_tree(t+0, common); init_tree_desc_from_tree(t+1, head); @@ -197,13 +202,14 @@ struct tree *write_tree_from_memory(struct merge_options *o) if (unmerged_cache()) { int i; - output(o, 0, "There are unmerged index entries:"); + fprintf(stderr, "BUG: There are unmerged index entries:\n"); for (i = 0; i < active_nr; i++) { struct cache_entry *ce = active_cache[i]; if (ce_stage(ce)) - output(o, 0, "%d %.*s", ce_stage(ce), ce_namelen(ce), ce->name); + fprintf(stderr, "BUG: %d %.*s", ce_stage(ce), + (int)ce_namelen(ce), ce->name); } - return NULL; + die("Bug in merge-recursive.c"); } if (!active_cache_tree) @@ -403,7 +409,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; @@ -438,7 +444,7 @@ static void flush_buffer(int fd, const char *buf, unsigned long size) /* Ignore epipe */ if (errno == EPIPE) break; - die("merge-recursive: %s", strerror(errno)); + die_errno("merge-recursive"); } else if (!ret) { die("merge-recursive: disk full?"); } @@ -554,7 +560,7 @@ static void update_file_flags(struct merge_options *o, mode = 0666; fd = open(path, O_WRONLY | O_TRUNC | O_CREAT, mode); if (fd < 0) - die("failed to open %s: %s", path, strerror(errno)); + die_errno("failed to open '%s'", path); flush_buffer(fd, buf, size); close(fd); } else if (S_ISLNK(mode)) { @@ -562,7 +568,7 @@ static void update_file_flags(struct merge_options *o, safe_create_leading_directories_const(path); unlink(path); if (symlink(lnk, path)) - die("failed to symlink %s: %s", path, strerror(errno)); + die_errno("failed to symlink '%s'", path); free(lnk); } else die("do not know what to do with %06o %s '%s'", @@ -593,23 +599,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, @@ -619,19 +608,46 @@ 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; + + if (o->call_depth) + favor = 0; + else { + switch (o->recursive_variant) { + case MERGE_RECURSIVE_OURS: + favor = XDL_MERGE_FAVOR_OURS; + break; + case MERGE_RECURSIVE_THEIRS: + favor = XDL_MERGE_FAVOR_THEIRS; + break; + default: + favor = 0; + break; + } + } - name1 = xstrdup(mkpath("%s:%s", branch1, a->path)); - name2 = xstrdup(mkpath("%s:%s", branch2, 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); + (!!o->call_depth) | (favor << 1)); free(name1); free(name2); @@ -947,9 +963,31 @@ static int process_renames(struct merge_options *o, "%s added in %s", ren1_src, ren1_dst, branch1, ren1_dst, branch2); - new_path = unique_path(o, ren1_dst, branch2); - output(o, 1, "Adding as %s instead", new_path); - update_file(o, 0, dst_other.sha1, dst_other.mode, new_path); + if (o->call_depth) { + struct merge_file_info mfi; + struct diff_filespec one, a, b; + + one.path = a.path = b.path = + (char *)ren1_dst; + hashcpy(one.sha1, null_sha1); + one.mode = 0; + hashcpy(a.sha1, ren1->pair->two->sha1); + a.mode = ren1->pair->two->mode; + hashcpy(b.sha1, dst_other.sha1); + b.mode = dst_other.mode; + mfi = merge_file(o, &one, &a, &b, + branch1, + branch2); + output(o, 1, "Adding merged %s", ren1_dst); + update_file(o, 0, + mfi.sha, + mfi.mode, + ren1_dst); + } else { + new_path = unique_path(o, ren1_dst, branch2); + 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))) { ren2 = item->util; clean_merge = 0; @@ -1140,6 +1178,28 @@ static int process_entry(struct merge_options *o, return clean_merge; } +struct unpack_trees_error_msgs get_porcelain_error_msgs(void) +{ + 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; +} + int merge_trees(struct merge_options *o, struct tree *head, struct tree *merge, @@ -1148,9 +1208,9 @@ int merge_trees(struct merge_options *o, { int code, clean; - if (o->subtree_merge) { - merge = shift_tree_object(head, merge); - common = shift_tree_object(head, common); + if (o->subtree_shift) { + merge = shift_tree_object(head, merge, o->subtree_shift); + common = shift_tree_object(head, common, o->subtree_shift); } if (sha_eq(common->object.sha1, merge->object.sha1)) { @@ -1161,10 +1221,14 @@ int merge_trees(struct merge_options *o, code = git_merge_trees(o->call_depth, common, head, merge); - if (code != 0) - die("merging of trees %s and %s failed", - sha1_to_hex(head->object.sha1), - sha1_to_hex(merge->object.sha1)); + if (code != 0) { + if (show(o, 4) || o->call_depth) + die("merging of trees %s and %s failed", + sha1_to_hex(head->object.sha1), + sha1_to_hex(merge->object.sha1)); + else + exit(128); + } if (unmerged_cache()) { struct string_list *entries, *re_head, *re_merge; @@ -1283,6 +1347,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); |