diff options
Diffstat (limited to 'builtin/merge.c')
| -rw-r--r-- | builtin/merge.c | 130 |
1 files changed, 85 insertions, 45 deletions
diff --git a/builtin/merge.c b/builtin/merge.c index 74e53cf20a..5900b81729 100644 --- a/builtin/merge.c +++ b/builtin/merge.c @@ -313,8 +313,16 @@ static int save_state(struct object_id *stash) int len; struct child_process cp = CHILD_PROCESS_INIT; struct strbuf buffer = STRBUF_INIT; + struct lock_file lock_file = LOCK_INIT; + int fd; int rc = -1; + fd = repo_hold_locked_index(the_repository, &lock_file, 0); + refresh_cache(REFRESH_QUIET); + if (0 <= fd) + repo_update_index_if_able(the_repository, &lock_file); + rollback_lock_file(&lock_file); + strvec_pushl(&cp.args, "stash", "create", NULL); cp.out = -1; cp.git_cmd = 1; @@ -375,24 +383,26 @@ static void reset_hard(const struct object_id *oid, int verbose) static void restore_state(const struct object_id *head, const struct object_id *stash) { - struct strbuf sb = STRBUF_INIT; - const char *args[] = { "stash", "apply", NULL, NULL }; - - if (is_null_oid(stash)) - return; + struct strvec args = STRVEC_INIT; reset_hard(head, 1); - args[2] = oid_to_hex(stash); + if (is_null_oid(stash)) + goto refresh_cache; + + strvec_pushl(&args, "stash", "apply", "--index", "--quiet", NULL); + strvec_push(&args, oid_to_hex(stash)); /* * It is OK to ignore error here, for example when there was * nothing to restore. */ - run_command_v_opt(args, RUN_GIT_CMD); + run_command_v_opt(args.v, RUN_GIT_CMD); + strvec_clear(&args); - strbuf_release(&sb); - refresh_cache(REFRESH_QUIET); +refresh_cache: + if (discard_cache() < 0 || read_cache() < 0) + die(_("could not read index")); } /* This is called when no merge was necessary. */ @@ -443,6 +453,7 @@ static void squash_message(struct commit *commit, struct commit_list *remotehead } write_file_buf(git_path_squash_msg(the_repository), out.buf, out.len); strbuf_release(&out); + release_revisions(&rev); } static void finish(struct commit *head_commit, @@ -490,9 +501,10 @@ static void finish(struct commit *head_commit, } /* Run a post-merge hook */ - run_hook_le(NULL, "post-merge", squash ? "1" : "0", NULL); + run_hooks_l("post-merge", squash ? "1" : "0", NULL); - apply_autostash(git_path_merge_autostash(the_repository)); + if (new_head) + apply_autostash(git_path_merge_autostash(the_repository)); strbuf_release(&reflog_message); } @@ -501,7 +513,6 @@ static void merge_name(const char *remote, struct strbuf *msg) { struct commit *remote_head; struct object_id branch_head; - struct strbuf buf = STRBUF_INIT; struct strbuf bname = STRBUF_INIT; struct merge_remote_desc *desc; const char *ptr; @@ -589,7 +600,6 @@ static void merge_name(const char *remote, struct strbuf *msg) oid_to_hex(&remote_head->object.oid), remote); cleanup: free(found_ref); - strbuf_release(&buf); strbuf_release(&bname); } @@ -757,8 +767,10 @@ static int try_merge_strategy(const char *strategy, struct commit_list *common, else clean = merge_recursive(&o, head, remoteheads->item, reversed, &result); - if (clean < 0) - exit(128); + if (clean < 0) { + rollback_lock_file(&lock); + return 2; + } if (write_locked_index(&the_index, &lock, COMMIT_LOCK | SKIP_IF_UNCHANGED)) die(_("unable to write %s"), get_index_file()); @@ -845,15 +857,20 @@ static void prepare_to_commit(struct commit_list *remoteheads) struct strbuf msg = STRBUF_INIT; const char *index_file = get_index_file(); - if (!no_verify && run_commit_hook(0 < option_edit, index_file, "pre-merge-commit", NULL)) - abort_commit(remoteheads, NULL); - /* - * Re-read the index as pre-merge-commit hook could have updated it, - * and write it out as a tree. We must do this before we invoke - * the editor and after we invoke run_status above. - */ - if (hook_exists("pre-merge-commit")) - discard_cache(); + if (!no_verify) { + int invoked_hook; + + if (run_commit_hook(0 < option_edit, index_file, &invoked_hook, + "pre-merge-commit", NULL)) + abort_commit(remoteheads, NULL); + /* + * Re-read the index as pre-merge-commit hook could have updated it, + * and write it out as a tree. We must do this before we invoke + * the editor and after we invoke run_status above. + */ + if (invoked_hook) + discard_cache(); + } read_cache_from(index_file); strbuf_addbuf(&msg, &merge_msg); if (squash) @@ -875,7 +892,8 @@ static void prepare_to_commit(struct commit_list *remoteheads) append_signoff(&msg, ignore_non_trailer(msg.buf, msg.len), 0); write_merge_heads(remoteheads); write_file_buf(git_path_merge_msg(the_repository), msg.buf, msg.len); - if (run_commit_hook(0 < option_edit, get_index_file(), "prepare-commit-msg", + if (run_commit_hook(0 < option_edit, get_index_file(), NULL, + "prepare-commit-msg", git_path_merge_msg(the_repository), "merge", NULL)) abort_commit(remoteheads, NULL); if (0 < option_edit) { @@ -884,7 +902,7 @@ static void prepare_to_commit(struct commit_list *remoteheads) } if (!no_verify && run_commit_hook(0 < option_edit, get_index_file(), - "commit-msg", + NULL, "commit-msg", git_path_merge_msg(the_repository), NULL)) abort_commit(remoteheads, NULL); @@ -992,6 +1010,7 @@ static int evaluate_result(void) */ cnt += count_unmerged_entries(); + release_revisions(&rev); return cnt; } @@ -1273,7 +1292,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix) int best_cnt = -1, merge_was_ok = 0, automerge_was_ok = 0; struct commit_list *common = NULL; const char *best_strategy = NULL, *wt_strategy = NULL; - struct commit_list *remoteheads, *p; + struct commit_list *remoteheads = NULL, *p; void *branch_to_free; int orig_argc = argc; @@ -1568,8 +1587,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix) if (autostash) create_autostash(the_repository, - git_path_merge_autostash(the_repository), - "merge"); + git_path_merge_autostash(the_repository)); if (checkout_fast_forward(the_repository, &head_commit->object.oid, &commit->object.oid, @@ -1596,6 +1614,21 @@ int cmd_merge(int argc, const char **argv, const char *prefix) */ refresh_cache(REFRESH_QUIET); if (allow_trivial && fast_forward != FF_ONLY) { + /* + * Must first ensure that index matches HEAD before + * attempting a trivial merge. + */ + struct tree *head_tree = get_commit_tree(head_commit); + struct strbuf sb = STRBUF_INIT; + + if (repo_index_has_changes(the_repository, head_tree, + &sb)) { + error(_("Your local changes to the following files would be overwritten by merge:\n %s"), + sb.buf); + strbuf_release(&sb); + return 2; + } + /* See if it is really trivial. */ git_committer_info(IDENT_STRICT); printf(_("Trying really trivial in-index merge...\n")); @@ -1640,8 +1673,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix) if (autostash) create_autostash(the_repository, - git_path_merge_autostash(the_repository), - "merge"); + git_path_merge_autostash(the_repository)); /* We are going to make a new commit. */ git_committer_info(IDENT_STRICT); @@ -1653,15 +1685,15 @@ int cmd_merge(int argc, const char **argv, const char *prefix) * tree in the index -- this means that the index must be in * sync with the head commit. The strategies are responsible * to ensure this. + * + * Stash away the local changes so that we can try more than one + * and/or recover from merge strategies bailing while leaving the + * index and working tree polluted. */ - if (use_strategies_nr == 1 || - /* - * Stash away the local changes so that we can try more than one. - */ - save_state(&stash)) + if (save_state(&stash)) oidclr(&stash); - for (i = 0; !merge_was_ok && i < use_strategies_nr; i++) { + for (i = 0; i < use_strategies_nr; i++) { int ret, cnt; if (i) { printf(_("Rewinding the tree to pristine...\n")); @@ -1676,7 +1708,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix) */ wt_strategy = use_strategies[i]->name; - ret = try_merge_strategy(use_strategies[i]->name, + ret = try_merge_strategy(wt_strategy, common, remoteheads, head_commit); /* @@ -1686,16 +1718,17 @@ int cmd_merge(int argc, const char **argv, const char *prefix) */ if (ret < 2) { if (!ret) { - if (option_commit) { - /* Automerge succeeded. */ - automerge_was_ok = 1; - break; - } + /* + * This strategy worked; no point in trying + * another. + */ merge_was_ok = 1; + best_strategy = wt_strategy; + break; } cnt = (use_strategies_nr > 1) ? evaluate_result() : 0; if (best_cnt <= 0 || cnt <= best_cnt) { - best_strategy = use_strategies[i]->name; + best_strategy = wt_strategy; best_cnt = cnt; } } @@ -1705,7 +1738,8 @@ int cmd_merge(int argc, const char **argv, const char *prefix) * If we have a resulting tree, that means the strategy module * auto resolved the merge cleanly. */ - if (automerge_was_ok) { + if (merge_was_ok && option_commit) { + automerge_was_ok = 1; ret = finish_automerge(head_commit, head_subsumed, common, remoteheads, &result_tree, wt_strategy); @@ -1750,8 +1784,14 @@ int cmd_merge(int argc, const char **argv, const char *prefix) "stopped before committing as requested\n")); else ret = suggest_conflicts(); + if (autostash) + printf(_("When finished, apply stashed changes with `git stash pop`\n")); done: + if (!automerge_was_ok) { + free_commit_list(common); + free_commit_list(remoteheads); + } strbuf_release(&buf); free(branch_to_free); return ret; |
