X-Git-Url: https://git.tokkee.org/?a=blobdiff_plain;f=merge-recursive.c;h=c96e1a734cb0c258cd4adb4f00e247abdf804640;hb=723024d696a47556baac77700e47fef288691f37;hp=87a27e0379c87efc8f04a4cf826f1bc7da242d34;hpb=c388761c153bc3e874e75f69ff77430164c038c4;p=git.git diff --git a/merge-recursive.c b/merge-recursive.c index 87a27e037..c96e1a734 100644 --- a/merge-recursive.c +++ b/merge-recursive.c @@ -67,27 +67,75 @@ struct stage_data unsigned processed:1; }; +struct output_buffer +{ + struct output_buffer *next; + char *str; +}; + static struct path_list current_file_set = {NULL, 0, 0, 1}; static struct path_list current_directory_set = {NULL, 0, 0, 1}; -static int output_indent = 0; +static int call_depth = 0; +static int verbosity = 2; +static int buffer_output = 1; +static int do_progress = 1; +static unsigned last_percent; +static unsigned merged_cnt; +static unsigned total_cnt; +static volatile sig_atomic_t progress_update; +static struct output_buffer *output_list, *output_end; + +static int show (int v) +{ + return (!call_depth && verbosity >= v) || verbosity >= 5; +} -static void output(const char *fmt, ...) +static void output(int v, const char *fmt, ...) { va_list args; - int i; - for (i = output_indent; i--;) - fputs(" ", stdout); va_start(args, fmt); - vfprintf(stdout, fmt, args); + if (buffer_output && show(v)) { + struct output_buffer *b = xmalloc(sizeof(*b)); + nfvasprintf(&b->str, fmt, args); + b->next = NULL; + if (output_end) + output_end->next = b; + else + output_list = b; + output_end = b; + } else if (show(v)) { + int i; + for (i = call_depth; i--;) + fputs(" ", stdout); + vfprintf(stdout, fmt, args); + fputc('\n', stdout); + } va_end(args); - fputc('\n', stdout); +} + +static void flush_output() +{ + struct output_buffer *b, *n; + for (b = output_list; b; b = n) { + int i; + for (i = call_depth; i--;) + fputs(" ", stdout); + fputs(b->str, stdout); + fputc('\n', stdout); + n = b->next; + free(b->str); + free(b); + } + output_list = NULL; + output_end = NULL; } static void output_commit_title(struct commit *commit) { int i; - for (i = output_indent; i--;) + flush_output(); + for (i = call_depth; i--;) fputs(" ", stdout); if (commit->util) printf("virtual %s\n", (char *)commit->util); @@ -110,33 +158,37 @@ static void output_commit_title(struct commit *commit) } } -static const char *current_index_file = NULL; -static const char *original_index_file; -static const char *temporary_index_file; -static int cache_dirty = 0; +static void progress_interval(int signum) +{ + progress_update = 1; +} -static int flush_cache(void) +static void setup_progress_signal(void) { - /* flush temporary index */ - struct lock_file *lock = xcalloc(1, sizeof(struct lock_file)); - int fd = hold_lock_file_for_update(lock, current_index_file, 1); - if (write_cache(fd, active_cache, active_nr) || - close(fd) || commit_lock_file(lock)) - die ("unable to write %s", current_index_file); - discard_cache(); - cache_dirty = 0; - return 0; + struct sigaction sa; + struct itimerval v; + + memset(&sa, 0, sizeof(sa)); + sa.sa_handler = progress_interval; + sigemptyset(&sa.sa_mask); + sa.sa_flags = SA_RESTART; + sigaction(SIGALRM, &sa, NULL); + + v.it_interval.tv_sec = 1; + v.it_interval.tv_usec = 0; + v.it_value = v.it_interval; + setitimer(ITIMER_REAL, &v, NULL); } -static void setup_index(int temp) +static void display_progress() { - current_index_file = temp ? temporary_index_file: original_index_file; - if (cache_dirty) { - discard_cache(); - cache_dirty = 0; + unsigned percent = total_cnt ? merged_cnt * 100 / total_cnt : 0; + if (progress_update || percent != last_percent) { + fprintf(stderr, "%4u%% (%u/%u) done\r", + percent, merged_cnt, total_cnt); + progress_update = 0; + last_percent = percent; } - unlink(temporary_index_file); - discard_cache(); } static struct cache_entry *make_cache_entry(unsigned int mode, @@ -167,9 +219,6 @@ static int add_cacheinfo(unsigned int mode, const unsigned char *sha1, const char *path, int stage, int refresh, int options) { struct cache_entry *ce; - if (!cache_dirty) - read_cache_from(current_index_file); - cache_dirty++; ce = make_cache_entry(mode, sha1 ? sha1 : null_sha1, path, stage, refresh); if (!ce) return error("cache_addinfo failed: %s", strerror(cache_errno)); @@ -187,26 +236,6 @@ static int add_cacheinfo(unsigned int mode, const unsigned char *sha1, */ static int index_only = 0; -static int git_read_tree(struct tree *tree) -{ - int rc; - struct object_list *trees = NULL; - struct unpack_trees_options opts; - - if (cache_dirty) - die("read-tree with dirty cache"); - - memset(&opts, 0, sizeof(opts)); - object_list_append(&tree->object, &trees); - rc = unpack_trees(trees, &opts); - cache_tree_free(&active_cache_tree); - - if (rc == 0) - cache_dirty = 1; - - return rc; -} - static int git_merge_trees(int index_only, struct tree *common, struct tree *head, @@ -216,11 +245,6 @@ static int git_merge_trees(int index_only, struct object_list *trees = NULL; struct unpack_trees_options opts; - if (!cache_dirty) { - read_cache_from(current_index_file); - cache_dirty = 1; - } - memset(&opts, 0, sizeof(opts)); if (index_only) opts.index_only = 1; @@ -236,39 +260,37 @@ static int git_merge_trees(int index_only, rc = unpack_trees(trees, &opts); cache_tree_free(&active_cache_tree); - - cache_dirty = 1; - return rc; } +static int unmerged_index(void) +{ + int i; + for (i = 0; i < active_nr; i++) { + struct cache_entry *ce = active_cache[i]; + if (ce_stage(ce)) + return 1; + } + return 0; +} + static struct tree *git_write_tree(void) { struct tree *result = NULL; - if (cache_dirty) { - unsigned i; - for (i = 0; i < active_nr; i++) { - struct cache_entry *ce = active_cache[i]; - if (ce_stage(ce)) - return NULL; - } - } else - read_cache_from(current_index_file); + if (unmerged_index()) + return NULL; if (!active_cache_tree) active_cache_tree = cache_tree(); if (!cache_tree_fully_valid(active_cache_tree) && - cache_tree_update(active_cache_tree, - active_cache, active_nr, 0, 0) < 0) + cache_tree_update(active_cache_tree, + active_cache, active_nr, 0, 0) < 0) die("error building trees"); result = lookup_tree(active_cache_tree->sha1); - flush_cache(); - cache_dirty = 0; - return result; } @@ -331,14 +353,14 @@ static struct path_list *get_unmerged(void) int i; unmerged->strdup_paths = 1; - if (!cache_dirty) { - read_cache_from(current_index_file); - cache_dirty++; - } - for (i = 0; i < active_nr; i++) { + total_cnt += active_nr; + + for (i = 0; i < active_nr; i++, merged_cnt++) { struct path_list_item *item; struct stage_data *e; struct cache_entry *ce = active_cache[i]; + if (do_progress) + display_progress(); if (!ce_stage(ce)) continue; @@ -364,7 +386,7 @@ struct rename }; /* - * Get information of all renames which occured between 'o_tree' and + * Get information of all renames which occurred between 'o_tree' and * 'tree'. We need the three trees in the merge ('o_tree', 'a_tree' and * 'b_tree') to be able to associate the correct cache entries with * the rename information. 'tree' is always equal to either a_tree or b_tree. @@ -469,9 +491,6 @@ static int remove_file(int clean, const char *path, int no_wd) int update_working_directory = !index_only && !no_wd; if (update_cache) { - if (!cache_dirty) - read_cache_from(current_index_file); - cache_dirty++; if (remove_file_from_cache(path)) return -1; } @@ -541,17 +560,17 @@ static void update_file_flags(const unsigned char *sha, update_wd = 0; if (update_wd) { - char type[20]; + enum object_type type; void *buf; unsigned long size; - buf = read_sha1_file(sha, type, &size); + buf = read_sha1_file(sha, &type, &size); if (!buf) die("cannot read object %s '%s'", sha1_to_hex(sha), path); - if (strcmp(type, blob_type) != 0) + if (type != OBJ_BLOB) die("blob expected for %s '%s'", sha1_to_hex(sha), path); - if (S_ISREG(mode)) { + if (S_ISREG(mode) || (!has_symlinks && S_ISLNK(mode))) { int fd; if (mkdir_p(path, 0777)) die("failed to create path %s: %s", path, strerror(errno)); @@ -570,8 +589,9 @@ static void update_file_flags(const unsigned char *sha, memcpy(lnk, buf, size); lnk[size] = '\0'; mkdir_p(path, 0777); - unlink(lnk); + unlink(path); symlink(lnk, path); + free(lnk); } else die("do not know what to do with %06o %s '%s'", mode, sha1_to_hex(sha), path); @@ -601,7 +621,7 @@ struct merge_file_info static void fill_mm(const unsigned char *sha1, mmfile_t *mm) { unsigned long size; - char type[20]; + enum object_type type; if (!hashcmp(sha1, null_sha1)) { mm->ptr = xstrdup(""); @@ -609,8 +629,8 @@ static void fill_mm(const unsigned char *sha1, mmfile_t *mm) return; } - mm->ptr = read_sha1_file(sha1, type, &size); - if (!mm->ptr || strcmp(type, blob_type)) + 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; } @@ -705,13 +725,13 @@ static void conflict_rename_rename(struct rename *ren1, const char *dst_name2 = ren2_dst; if (path_list_has_path(¤t_directory_set, ren1_dst)) { dst_name1 = del[delp++] = unique_path(ren1_dst, branch1); - output("%s is a directory in %s adding as %s instead", + output(1, "%s is a directory in %s added as %s instead", ren1_dst, branch2, dst_name1); remove_file(0, ren1_dst, 0); } if (path_list_has_path(¤t_directory_set, ren2_dst)) { dst_name2 = del[delp++] = unique_path(ren2_dst, branch2); - output("%s is a directory in %s adding as %s instead", + output(1, "%s is a directory in %s added as %s instead", ren2_dst, branch1, dst_name2); remove_file(0, ren2_dst, 0); } @@ -725,7 +745,7 @@ static void conflict_rename_dir(struct rename *ren1, const char *branch1) { char *new_path = unique_path(ren1->pair->two->path, branch1); - output("Renaming %s to %s instead", ren1->pair->one->path, new_path); + output(1, "Renamed %s to %s instead", ren1->pair->one->path, new_path); remove_file(0, ren1->pair->two->path, 0); update_file(0, ren1->pair->two->sha1, ren1->pair->two->mode, new_path); free(new_path); @@ -738,7 +758,7 @@ static void conflict_rename_rename_2(struct rename *ren1, { char *new_path1 = unique_path(ren1->pair->two->path, branch1); char *new_path2 = unique_path(ren2->pair->two->path, branch2); - output("Renaming %s to %s and %s to %s instead", + output(1, "Renamed %s to %s and %s to %s instead", ren1->pair->one->path, new_path1, ren2->pair->one->path, new_path2); remove_file(0, ren1->pair->two->path, 0); @@ -831,7 +851,7 @@ static int process_renames(struct path_list *a_renames, ren2->processed = 1; if (strcmp(ren1_dst, ren2_dst) != 0) { clean_merge = 0; - output("CONFLICT (rename/rename): " + output(1, "CONFLICT (rename/rename): " "Rename %s->%s in branch %s " "rename %s->%s in %s", src, ren1_dst, branch1, @@ -846,13 +866,13 @@ static int process_renames(struct path_list *a_renames, branch1, branch2); if (mfi.merge || !mfi.clean) - output("Renaming %s->%s", src, ren1_dst); + output(1, "Renamed %s->%s", src, ren1_dst); if (mfi.merge) - output("Auto-merging %s", ren1_dst); + output(2, "Auto-merged %s", ren1_dst); if (!mfi.clean) { - output("CONFLICT (content): merge conflict in %s", + output(1, "CONFLICT (content): merge conflict in %s", ren1_dst); clean_merge = 0; @@ -872,7 +892,7 @@ static int process_renames(struct path_list *a_renames, struct diff_filespec src_other, dst_other; int try_merge, stage = a_renames == renames1 ? 3: 2; - remove_file(1, ren1_src, index_only); + remove_file(1, ren1_src, index_only || stage == 3); hashcpy(src_other.sha1, ren1->src_entry->stages[stage].sha); src_other.mode = ren1->src_entry->stages[stage].mode; @@ -883,14 +903,14 @@ static int process_renames(struct path_list *a_renames, if (path_list_has_path(¤t_directory_set, ren1_dst)) { clean_merge = 0; - output("CONFLICT (rename/directory): Rename %s->%s in %s " + output(1, "CONFLICT (rename/directory): Renamed %s->%s in %s " " directory %s added in %s", ren1_src, ren1_dst, branch1, ren1_dst, branch2); conflict_rename_dir(ren1, branch1); } else if (sha_eq(src_other.sha1, null_sha1)) { clean_merge = 0; - output("CONFLICT (rename/delete): Rename %s->%s in %s " + output(1, "CONFLICT (rename/delete): Renamed %s->%s in %s " "and deleted in %s", ren1_src, ren1_dst, branch1, branch2); @@ -899,19 +919,19 @@ static int process_renames(struct path_list *a_renames, const char *new_path; clean_merge = 0; try_merge = 1; - output("CONFLICT (rename/add): Rename %s->%s in %s. " + output(1, "CONFLICT (rename/add): Renamed %s->%s in %s. " "%s added in %s", ren1_src, ren1_dst, branch1, ren1_dst, branch2); new_path = unique_path(ren1_dst, branch2); - output("Adding as %s instead", new_path); + output(1, "Added as %s instead", new_path); update_file(0, dst_other.sha1, dst_other.mode, new_path); } else if ((item = path_list_lookup(ren1_dst, renames2Dst))) { ren2 = item->util; clean_merge = 0; ren2->processed = 1; - output("CONFLICT (rename/rename): Rename %s->%s in %s. " - "Rename %s->%s in %s", + output(1, "CONFLICT (rename/rename): Renamed %s->%s in %s. " + "Renamed %s->%s in %s", ren1_src, ren1_dst, branch1, ren2->pair->one->path, ren2->pair->two->path, branch2); conflict_rename_rename_2(ren1, branch1, ren2, branch2); @@ -935,11 +955,11 @@ static int process_renames(struct path_list *a_renames, a_branch, b_branch); if (mfi.merge || !mfi.clean) - output("Renaming %s => %s", ren1_src, ren1_dst); + output(1, "Renamed %s => %s", ren1_src, ren1_dst); if (mfi.merge) - output("Auto-merging %s", ren1_dst); + output(2, "Auto-merged %s", ren1_dst); if (!mfi.clean) { - output("CONFLICT (rename/modify): Merge conflict in %s", + output(1, "CONFLICT (rename/modify): Merge conflict in %s", ren1_dst); clean_merge = 0; @@ -954,8 +974,6 @@ static int process_renames(struct path_list *a_renames, path_list_clear(&a_by_dst, 0); path_list_clear(&b_by_dst, 0); - if (cache_dirty) - flush_cache(); return clean_merge; } @@ -989,20 +1007,20 @@ static int process_entry(const char *path, struct stage_data *entry, /* Deleted in both or deleted in one and * unchanged in the other */ if (a_sha) - output("Removing %s", path); + output(2, "Removed %s", path); /* do not touch working file if it did not exist */ remove_file(1, path, !a_sha); } else { /* Deleted in one and changed in the other */ clean_merge = 0; if (!a_sha) { - output("CONFLICT (delete/modify): %s deleted in %s " + output(1, "CONFLICT (delete/modify): %s deleted in %s " "and modified in %s. Version %s of %s left in tree.", path, branch1, branch2, branch2, path); update_file(0, b_sha, b_mode, path); } else { - output("CONFLICT (delete/modify): %s deleted in %s " + output(1, "CONFLICT (delete/modify): %s deleted in %s " "and modified in %s. Version %s of %s left in tree.", path, branch2, branch1, branch1, path); @@ -1035,13 +1053,13 @@ static int process_entry(const char *path, struct stage_data *entry, if (path_list_has_path(¤t_directory_set, path)) { const char *new_path = unique_path(path, add_branch); clean_merge = 0; - output("CONFLICT (%s): There is a directory with name %s in %s. " - "Adding %s as %s", + output(1, "CONFLICT (%s): There is a directory with name %s in %s. " + "Added %s as %s", conf, path, other_branch, path, new_path); remove_file(0, path, 0); update_file(0, sha, mode, new_path); } else { - output("Adding %s", path); + output(2, "Added %s", path); update_file(1, sha, mode, path); } } else if (a_sha && b_sha) { @@ -1055,7 +1073,7 @@ static int process_entry(const char *path, struct stage_data *entry, reason = "add/add"; o_sha = (unsigned char *)null_sha1; } - output("Auto-merging %s", path); + output(2, "Auto-merged %s", path); o.path = a.path = b.path = (char *)path; hashcpy(o.sha1, o_sha); o.mode = o_mode; @@ -1071,7 +1089,7 @@ static int process_entry(const char *path, struct stage_data *entry, update_file(1, mfi.sha, mfi.mode, path); else { clean_merge = 0; - output("CONFLICT (%s): Merge conflict in %s", + output(1, "CONFLICT (%s): Merge conflict in %s", reason, path); if (index_only) @@ -1083,9 +1101,6 @@ static int process_entry(const char *path, struct stage_data *entry, } else die("Fatal merge failure, shouldn't happen."); - if (cache_dirty) - flush_cache(); - return clean_merge; } @@ -1098,7 +1113,7 @@ static int merge_trees(struct tree *head, { int code, clean; if (sha_eq(common->object.sha1, merge->object.sha1)) { - output("Already uptodate!"); + output(0, "Already uptodate!"); *result = head; return 1; } @@ -1110,9 +1125,7 @@ static int merge_trees(struct tree *head, sha1_to_hex(head->object.sha1), sha1_to_hex(merge->object.sha1)); - *result = git_write_tree(); - - if (!*result) { + if (unmerged_index()) { struct path_list *entries, *re_head, *re_merge; int i; path_list_clear(¤t_file_set, 1); @@ -1125,30 +1138,27 @@ static int merge_trees(struct tree *head, re_merge = get_renames(merge, common, head, merge, entries); clean = process_renames(re_head, re_merge, branch1, branch2); - for (i = 0; i < entries->nr; i++) { + total_cnt += entries->nr; + for (i = 0; i < entries->nr; i++, merged_cnt++) { const char *path = entries->items[i].path; struct stage_data *e = entries->items[i].util; - if (e->processed) - continue; - if (!process_entry(path, e, branch1, branch2)) + if (!e->processed + && !process_entry(path, e, branch1, branch2)) clean = 0; + if (do_progress) + display_progress(); } path_list_clear(re_merge, 0); path_list_clear(re_head, 0); path_list_clear(entries, 1); - if (clean || index_only) - *result = git_write_tree(); - else - *result = NULL; - } else { - clean = 1; - printf("merging of trees %s and %s resulted in %s\n", - sha1_to_hex(head->object.sha1), - sha1_to_hex(merge->object.sha1), - sha1_to_hex((*result)->object.sha1)); } + else + clean = 1; + + if (index_only) + *result = git_write_tree(); return clean; } @@ -1166,33 +1176,36 @@ static struct commit_list *reverse_commit_list(struct commit_list *list) /* * Merge the commits h1 and h2, return the resulting virtual - * commit object and a flag indicating the cleaness of the merge. + * commit object and a flag indicating the cleanness of the merge. */ static int merge(struct commit *h1, struct commit *h2, const char *branch1, const char *branch2, - int call_depth /* =0 */, - struct commit *ancestor /* =None */, + struct commit_list *ca, struct commit **result) { - struct commit_list *ca = NULL, *iter; + struct commit_list *iter; struct commit *merged_common_ancestors; struct tree *mrtree; int clean; - output("Merging:"); - output_commit_title(h1); - output_commit_title(h2); + if (show(4)) { + output(4, "Merging:"); + output_commit_title(h1); + output_commit_title(h2); + } - if (ancestor) - commit_list_insert(ancestor, &ca); - else - ca = reverse_commit_list(get_merge_bases(h1, h2, 1)); + if (!ca) { + ca = get_merge_bases(h1, h2, 1); + ca = reverse_commit_list(ca); + } - output("found %u common ancestor(s):", commit_list_count(ca)); - for (iter = ca; iter; iter = iter->next) - output_commit_title(iter->item); + if (show(5)) { + output(5, "found %u common ancestor(s):", commit_list_count(ca)); + for (iter = ca; iter; iter = iter->next) + output_commit_title(iter->item); + } merged_common_ancestors = pop_commit(&ca); if (merged_common_ancestors == NULL) { @@ -1201,50 +1214,56 @@ static int merge(struct commit *h1, tree->object.parsed = 1; tree->object.type = OBJ_TREE; - write_sha1_file(NULL, 0, tree_type, tree->object.sha1); + pretend_sha1_file(NULL, 0, OBJ_TREE, tree->object.sha1); merged_common_ancestors = make_virtual_commit(tree, "ancestor"); } for (iter = ca; iter; iter = iter->next) { - output_indent = call_depth + 1; + call_depth++; /* * When the merge fails, the result contains files * with conflict markers. The cleanness flag is - * ignored, it was never acutally used, as result of - * merge_trees has always overwritten it: the commited + * ignored, it was never actually used, as result of + * merge_trees has always overwritten it: the committed * "conflicts" were already resolved. */ + discard_cache(); merge(merged_common_ancestors, iter->item, "Temporary merge branch 1", "Temporary merge branch 2", - call_depth + 1, NULL, &merged_common_ancestors); - output_indent = call_depth; + call_depth--; if (!merged_common_ancestors) die("merge returned no commit"); } - if (call_depth == 0) { - setup_index(0 /* $GIT_DIR/index */); + discard_cache(); + if (!call_depth) { + read_cache(); index_only = 0; - } else { - setup_index(1 /* temporary index */); - git_read_tree(h1->tree); + } else index_only = 1; - } clean = merge_trees(h1->tree, h2->tree, merged_common_ancestors->tree, branch1, branch2, &mrtree); - if (!ancestor && (clean || index_only)) { + if (index_only) { *result = make_virtual_commit(mrtree, "merged tree"); commit_list_insert(h1, &(*result)->parents); commit_list_insert(h2, &(*result)->parents->next); - } else - *result = NULL; - + } + if (!call_depth && do_progress) { + /* Make sure we end at 100% */ + if (!total_cnt) + total_cnt = 1; + merged_cnt = total_cnt; + progress_update = 1; + display_progress(); + fputc('\n', stderr); + } + flush_output(); return clean; } @@ -1278,21 +1297,29 @@ static struct commit *get_ref(const char *ref) return (struct commit *)object; } +static int merge_config(const char *var, const char *value) +{ + if (!strcasecmp(var, "merge.verbosity")) { + verbosity = git_config_int(var, value); + return 0; + } + return git_default_config(var, value); +} + int main(int argc, char *argv[]) { - static const char *bases[2]; + static const char *bases[20]; static unsigned bases_count = 0; int i, clean; const char *branch1, *branch2; struct commit *result, *h1, *h2; + struct commit_list *ca = NULL; + struct lock_file *lock = xcalloc(1, sizeof(struct lock_file)); + int index_fd; - git_config(git_default_config); /* core.filemode */ - original_index_file = getenv(INDEX_ENVIRONMENT); - - if (!original_index_file) - original_index_file = xstrdup(git_path("index")); - - temporary_index_file = xstrdup(git_path("mrg-rcrsv-tmp-idx")); + git_config(merge_config); + if (getenv("GIT_MERGE_VERBOSITY")) + verbosity = strtol(getenv("GIT_MERGE_VERBOSITY"), NULL, 10); if (argc < 4) die("Usage: %s ... -- ...\n", argv[0]); @@ -1305,6 +1332,12 @@ int main(int argc, char *argv[]) } if (argc - i != 3) /* "--" "" "" */ die("Not handling anything other than two heads merge."); + if (verbosity >= 5) { + buffer_output = 0; + do_progress = 0; + } + else + do_progress = isatty(1); branch1 = argv[++i]; branch2 = argv[++i]; @@ -1314,20 +1347,24 @@ int main(int argc, char *argv[]) branch1 = better_branch_name(branch1); branch2 = better_branch_name(branch2); - printf("Merging %s with %s\n", branch1, branch2); - if (bases_count == 1) { - struct commit *ancestor = get_ref(bases[0]); - clean = merge(h1, h2, branch1, branch2, 0, ancestor, &result); - } else - clean = merge(h1, h2, branch1, branch2, 0, NULL, &result); + if (do_progress) + setup_progress_signal(); + if (show(3)) + printf("Merging %s with %s\n", branch1, branch2); - if (cache_dirty) - flush_cache(); + index_fd = hold_lock_file_for_update(lock, get_index_file(), 1); + + for (i = 0; i < bases_count; i++) { + struct commit *ancestor = get_ref(bases[i]); + ca = commit_list_insert(ancestor, &ca); + } + clean = merge(h1, h2, branch1, branch2, ca, &result); + + if (active_cache_changed && + (write_cache(index_fd, active_cache, active_nr) || + close(index_fd) || commit_lock_file(lock))) + die ("unable to write %s", get_index_file()); return clean ? 0: 1; } - -/* -vim: sw=8 noet -*/