diff options
Diffstat (limited to 'builtin/merge.c')
-rw-r--r-- | builtin/merge.c | 123 |
1 files changed, 63 insertions, 60 deletions
diff --git a/builtin/merge.c b/builtin/merge.c index 29988e54c5..d127d2225f 100644 --- a/builtin/merge.c +++ b/builtin/merge.c @@ -37,6 +37,7 @@ #include "packfile.h" #include "tag.h" #include "alias.h" +#include "branch.h" #include "commit-reach.h" #include "wt-status.h" @@ -61,6 +62,7 @@ static int show_diffstat = 1, shortlog_len = -1, squash; static int option_commit = -1; static int option_edit = -1; static int allow_trivial = 1, have_message, verify_signatures; +static int check_trust_level = 1; static int overwrite_ignore = 1; static struct strbuf merge_msg = STRBUF_INIT; static struct strategy **use_strategies; @@ -73,13 +75,14 @@ static int option_renormalize; static int verbosity; static int allow_rerere_auto; static int abort_current_merge; +static int quit_current_merge; static int continue_current_merge; static int allow_unrelated_histories; static int show_progress = -1; static int default_to_upstream = 1; static int signoff; static const char *sign_commit; -static int verify_msg = 1; +static int no_verify; static struct strategy all_strategy[] = { { "recursive", DEFAULT_TWOHEAD | NO_TRIVIAL }, @@ -274,6 +277,8 @@ static struct option builtin_merge_options[] = { OPT__VERBOSITY(&verbosity), OPT_BOOL(0, "abort", &abort_current_merge, N_("abort the current in-progress merge")), + OPT_BOOL(0, "quit", &quit_current_merge, + N_("--abort but leave index and working tree alone")), OPT_BOOL(0, "continue", &continue_current_merge, N_("continue the current in-progress merge")), OPT_BOOL(0, "allow-unrelated-histories", &allow_unrelated_histories, @@ -283,18 +288,10 @@ static struct option builtin_merge_options[] = { N_("GPG sign commit"), PARSE_OPT_OPTARG, NULL, (intptr_t) "" }, OPT_BOOL(0, "overwrite-ignore", &overwrite_ignore, N_("update ignored files (default)")), OPT_BOOL(0, "signoff", &signoff, N_("add Signed-off-by:")), - OPT_BOOL(0, "verify", &verify_msg, N_("verify commit-msg hook")), + OPT_BOOL(0, "no-verify", &no_verify, N_("bypass pre-merge-commit and commit-msg hooks")), OPT_END() }; -/* Cleans up metadata that is uninteresting after a succeeded merge. */ -static void drop_save(void) -{ - unlink(git_path_merge_head(the_repository)); - unlink(git_path_merge_msg(the_repository)); - unlink(git_path_merge_mode(the_repository)); -} - static int save_state(struct object_id *stash) { int len; @@ -388,7 +385,7 @@ static void finish_up_to_date(const char *msg) { if (verbosity >= 0) printf("%s%s\n", squash ? _(" (nothing to squash)") : "", msg); - drop_save(); + remove_merge_branch_state(the_repository); } static void squash_message(struct commit *commit, struct commit_list *remoteheads) @@ -635,6 +632,8 @@ static int git_merge_config(const char *k, const char *v, void *cb) } else if (!strcmp(k, "commit.gpgsign")) { sign_commit = git_config_bool(k, v) ? "" : NULL; return 0; + } else if (!strcmp(k, "gpg.mintrustlevel")) { + check_trust_level = 0; } status = fmt_merge_msg_config(k, v, cb); @@ -692,16 +691,13 @@ static int try_merge_strategy(const char *strategy, struct commit_list *common, struct commit_list *remoteheads, struct commit *head) { - struct lock_file lock = LOCK_INIT; const char *head_arg = "HEAD"; - hold_locked_index(&lock, LOCK_DIE_ON_ERROR); - refresh_cache(REFRESH_QUIET); - if (write_locked_index(&the_index, &lock, - COMMIT_LOCK | SKIP_IF_UNCHANGED)) + if (refresh_and_write_cache(REFRESH_QUIET, SKIP_IF_UNCHANGED, 0) < 0) return error(_("Unable to write index.")); if (!strcmp(strategy, "recursive") || !strcmp(strategy, "subtree")) { + struct lock_file lock = LOCK_INIT; int clean, x; struct commit *result; struct commit_list *reversed = NULL; @@ -820,6 +816,18 @@ static void write_merge_heads(struct commit_list *); 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 (find_hook("pre-merge-commit")) + discard_cache(); + read_cache_from(index_file); strbuf_addbuf(&msg, &merge_msg); if (squash) BUG("the control must not reach here under --squash"); @@ -846,7 +854,7 @@ static void prepare_to_commit(struct commit_list *remoteheads) abort_commit(remoteheads, NULL); } - if (verify_msg && run_commit_hook(0 < option_edit, get_index_file(), + if (!no_verify && run_commit_hook(0 < option_edit, get_index_file(), "commit-msg", git_path_merge_msg(the_repository), NULL)) abort_commit(remoteheads, NULL); @@ -864,12 +872,8 @@ static int merge_trivial(struct commit *head, struct commit_list *remoteheads) { struct object_id result_tree, result_commit; struct commit_list *parents, **pptr = &parents; - struct lock_file lock = LOCK_INIT; - hold_locked_index(&lock, LOCK_DIE_ON_ERROR); - refresh_cache(REFRESH_QUIET); - if (write_locked_index(&the_index, &lock, - COMMIT_LOCK | SKIP_IF_UNCHANGED)) + if (refresh_and_write_cache(REFRESH_QUIET, SKIP_IF_UNCHANGED, 0) < 0) return error(_("Unable to write index.")); write_tree_trivial(&result_tree); @@ -881,7 +885,7 @@ static int merge_trivial(struct commit *head, struct commit_list *remoteheads) &result_commit, NULL, sign_commit)) die(_("failed to write commit object")); finish(head, remoteheads, &result_commit, "In-index merge"); - drop_save(); + remove_merge_branch_state(the_repository); return 0; } @@ -896,6 +900,7 @@ static int finish_automerge(struct commit *head, struct strbuf buf = STRBUF_INIT; struct object_id result_commit; + write_tree_trivial(result_tree); free_commit_list(common); parents = remoteheads; if (!head_subsumed || fast_forward == FF_NO) @@ -907,7 +912,7 @@ static int finish_automerge(struct commit *head, strbuf_addf(&buf, "Merge made by the '%s' strategy.", wt_strategy); finish(head, remoteheads, &result_commit, buf.buf); strbuf_release(&buf); - drop_save(); + remove_merge_branch_state(the_repository); return 0; } @@ -1289,6 +1294,16 @@ int cmd_merge(int argc, const char **argv, const char *prefix) goto done; } + if (quit_current_merge) { + if (orig_argc != 2) + usage_msg_opt(_("--quit expects no arguments"), + builtin_merge_usage, + builtin_merge_options); + + remove_merge_branch_state(the_repository); + goto done; + } + if (continue_current_merge) { int nargc = 1; const char *nargv[] = {"commit", NULL}; @@ -1385,7 +1400,8 @@ int cmd_merge(int argc, const char **argv, const char *prefix) die(_("Can merge only exactly one commit into empty head")); if (verify_signatures) - verify_merge_signature(remoteheads->item, verbosity); + verify_merge_signature(remoteheads->item, verbosity, + check_trust_level); remote_head_oid = &remoteheads->item->object.oid; read_empty(remote_head_oid, 0); @@ -1408,7 +1424,8 @@ int cmd_merge(int argc, const char **argv, const char *prefix) if (verify_signatures) { for (p = remoteheads; p; p = p->next) { - verify_merge_signature(p->item, verbosity); + verify_merge_signature(p->item, verbosity, + check_trust_level); } } @@ -1505,7 +1522,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix) } finish(head_commit, remoteheads, &commit->object.oid, msg.buf); - drop_save(); + remove_merge_branch_state(the_repository); goto done; } else if (!remoteheads->next && common->next) ; @@ -1580,8 +1597,8 @@ int cmd_merge(int argc, const char **argv, const char *prefix) save_state(&stash)) oidclr(&stash); - for (i = 0; i < use_strategies_nr; i++) { - int ret; + for (i = 0; !merge_was_ok && i < use_strategies_nr; i++) { + int ret, cnt; if (i) { printf(_("Rewinding the tree to pristine...\n")); restore_state(&head_commit->object.oid, &stash); @@ -1598,40 +1615,26 @@ int cmd_merge(int argc, const char **argv, const char *prefix) ret = try_merge_strategy(use_strategies[i]->name, common, remoteheads, head_commit); - if (!option_commit && !ret) { - merge_was_ok = 1; - /* - * This is necessary here just to avoid writing - * the tree, but later we will *not* exit with - * status code 1 because merge_was_ok is set. - */ - ret = 1; - } - - if (ret) { - /* - * The backend exits with 1 when conflicts are - * left to be resolved, with 2 when it does not - * handle the given merge at all. - */ - if (ret == 1) { - int cnt = evaluate_result(); - - if (best_cnt <= 0 || cnt <= best_cnt) { - best_strategy = use_strategies[i]->name; - best_cnt = cnt; + /* + * The backend exits with 1 when conflicts are + * left to be resolved, with 2 when it does not + * handle the given merge at all. + */ + if (ret < 2) { + if (!ret) { + if (option_commit) { + /* Automerge succeeded. */ + automerge_was_ok = 1; + break; } + merge_was_ok = 1; + } + cnt = evaluate_result(); + if (best_cnt <= 0 || cnt <= best_cnt) { + best_strategy = use_strategies[i]->name; + best_cnt = cnt; } - if (merge_was_ok) - break; - else - continue; } - - /* Automerge succeeded. */ - write_tree_trivial(&result_tree); - automerge_was_ok = 1; - break; } /* |