From: Junio C Hamano Date: Mon, 29 Jul 2019 19:38:20 +0000 (-0700) Subject: Merge branch 'pw/rebase-abort-clean-rewritten' into maint X-Git-Tag: v2.23.0-rc0~1^2~8 X-Git-Url: https://git.lorimer.id.au/gitweb.git/diff_plain/649cae69bc8cc99fd5a9e72f8a08ae301d0d5e16?hp=-c Merge branch 'pw/rebase-abort-clean-rewritten' into maint "git rebase --abort" used to leave refs/rewritten/ when concluding "git rebase -r", which has been corrected. * pw/rebase-abort-clean-rewritten: rebase --abort/--quit: cleanup refs/rewritten sequencer: return errors from sequencer_remove_state() rebase: warn if state directory cannot be removed rebase: fix a memory leak --- 649cae69bc8cc99fd5a9e72f8a08ae301d0d5e16 diff --combined builtin/rebase.c index b6892bc771,bb347203ba..3d6219d022 --- a/builtin/rebase.c +++ b/builtin/rebase.c @@@ -87,7 -87,6 +87,7 @@@ struct rebase_options char *strategy, *strategy_opts; struct strbuf git_format_patch_opt; int reschedule_failed_exec; + int use_legacy_rebase; }; #define REBASE_OPTIONS_INIT { \ @@@ -521,6 -520,29 +521,6 @@@ int cmd_rebase__interactive(int argc, c return !!run_rebase_interactive(&opts, command); } -static int use_builtin_rebase(void) -{ - struct child_process cp = CHILD_PROCESS_INIT; - struct strbuf out = STRBUF_INIT; - int ret, env = git_env_bool("GIT_TEST_REBASE_USE_BUILTIN", -1); - - if (env != -1) - return env; - - argv_array_pushl(&cp.args, - "config", "--bool", "rebase.usebuiltin", NULL); - cp.git_cmd = 1; - if (capture_command(&cp, &out, 6)) { - strbuf_release(&out); - return 1; - } - - strbuf_trim(&out); - ret = !strcmp("true", out.buf); - strbuf_release(&out); - return ret; -} - static int is_interactive(struct rebase_options *opts) { return opts->type == REBASE_INTERACTIVE || @@@ -738,6 -760,7 +738,7 @@@ static int finish_rebase(struct rebase_ { struct strbuf dir = STRBUF_INIT; const char *argv_gc_auto[] = { "gc", "--auto", NULL }; + int ret = 0; delete_ref(NULL, "REBASE_HEAD", NULL, REF_NO_DEREF); apply_autostash(opts); @@@ -747,11 -770,20 +748,20 @@@ * user should see them. */ run_command_v_opt(argv_gc_auto, RUN_GIT_CMD); - strbuf_addstr(&dir, opts->state_dir); - remove_dir_recursively(&dir, 0); - strbuf_release(&dir); + if (opts->type == REBASE_INTERACTIVE) { + struct replay_opts replay = REPLAY_OPTS_INIT; - return 0; + replay.action = REPLAY_INTERACTIVE_REBASE; + ret = sequencer_remove_state(&replay); + } else { + strbuf_addstr(&dir, opts->state_dir); + if (remove_dir_recursively(&dir, 0)) + ret = error(_("could not remove '%s'"), + opts->state_dir); + strbuf_release(&dir); + } + + return ret; } static struct commit *peel_committish(const char *name) @@@ -782,7 -814,6 +792,7 @@@ static void add_var(struct strbuf *buf #define RESET_HEAD_HARD (1<<1) #define RESET_HEAD_RUN_POST_CHECKOUT_HOOK (1<<2) #define RESET_HEAD_REFS_ONLY (1<<3) +#define RESET_ORIG_HEAD (1<<4) static int reset_head(struct object_id *oid, const char *action, const char *switch_to_branch, unsigned flags, @@@ -792,7 -823,6 +802,7 @@@ unsigned reset_hard = flags & RESET_HEAD_HARD; unsigned run_hook = flags & RESET_HEAD_RUN_POST_CHECKOUT_HOOK; unsigned refs_only = flags & RESET_HEAD_REFS_ONLY; + unsigned update_orig_head = flags & RESET_ORIG_HEAD; struct object_id head_oid; struct tree_desc desc[2] = { { NULL }, { NULL } }; struct lock_file lock = LOCK_INIT; @@@ -869,21 -899,18 +879,21 @@@ reset_head_refs strbuf_addf(&msg, "%s: ", reflog_action ? reflog_action : "rebase"); prefix_len = msg.len; - if (!get_oid("ORIG_HEAD", &oid_old_orig)) - old_orig = &oid_old_orig; - if (!get_oid("HEAD", &oid_orig)) { - orig = &oid_orig; - if (!reflog_orig_head) { - strbuf_addstr(&msg, "updating ORIG_HEAD"); - reflog_orig_head = msg.buf; - } - update_ref(reflog_orig_head, "ORIG_HEAD", orig, old_orig, 0, - UPDATE_REFS_MSG_ON_ERR); - } else if (old_orig) - delete_ref(NULL, "ORIG_HEAD", old_orig, 0); + if (update_orig_head) { + if (!get_oid("ORIG_HEAD", &oid_old_orig)) + old_orig = &oid_old_orig; + if (!get_oid("HEAD", &oid_orig)) { + orig = &oid_orig; + if (!reflog_orig_head) { + strbuf_addstr(&msg, "updating ORIG_HEAD"); + reflog_orig_head = msg.buf; + } + update_ref(reflog_orig_head, "ORIG_HEAD", orig, + old_orig, 0, UPDATE_REFS_MSG_ON_ERR); + } else if (old_orig) + delete_ref(NULL, "ORIG_HEAD", old_orig, 0); + } + if (!reflog_head) { strbuf_setlen(&msg, prefix_len); strbuf_addstr(&msg, "updating HEAD"); @@@ -894,7 -921,7 +904,7 @@@ detach_head ? REF_NO_DEREF : 0, UPDATE_REFS_MSG_ON_ERR); else { - ret = update_ref(reflog_orig_head, switch_to_branch, oid, + ret = update_ref(reflog_head, switch_to_branch, oid, NULL, 0, UPDATE_REFS_MSG_ON_ERR); if (!ret) ret = create_symref("HEAD", switch_to_branch, @@@ -1203,7 -1230,7 +1213,7 @@@ static int rebase_config(const char *va if (git_config_bool(var, value)) opts->flags |= REBASE_DIFFSTAT; else - opts->flags &= !REBASE_DIFFSTAT; + opts->flags &= ~REBASE_DIFFSTAT; return 0; } @@@ -1229,11 -1256,6 +1239,11 @@@ return 0; } + if (!strcmp(var, "rebase.usebuiltin")) { + opts->use_legacy_rebase = !git_config_bool(var, value); + return 0; + } + return git_default_config(var, value, data); } @@@ -1384,7 -1406,6 +1394,7 @@@ int cmd_rebase(int argc, const char **a struct string_list strategy_options = STRING_LIST_INIT_NODUP; struct object_id squash_onto; char *squash_onto_name = NULL; + int reschedule_failed_exec = -1; struct option builtin_rebase_options[] = { OPT_STRING(0, "onto", &options.onto_name, N_("revision"), @@@ -1443,8 -1464,8 +1453,8 @@@ PARSE_OPT_NOARG | PARSE_OPT_NONEG, parse_opt_interactive }, OPT_SET_INT('p', "preserve-merges", &options.type, - N_("try to recreate merges instead of ignoring " - "them"), REBASE_PRESERVE_MERGES), + N_("(DEPRECATED) try to recreate merges instead of " + "ignoring them"), REBASE_PRESERVE_MERGES), OPT_RERERE_AUTOUPDATE(&options.allow_rerere_autoupdate), OPT_BOOL('k', "keep-empty", &options.keep_empty, N_("preserve empty commits during rebase")), @@@ -1477,12 -1498,28 +1487,12 @@@ OPT_BOOL(0, "root", &options.root, N_("rebase all reachable commits up to the root(s)")), OPT_BOOL(0, "reschedule-failed-exec", - &options.reschedule_failed_exec, + &reschedule_failed_exec, N_("automatically re-schedule any `exec` that fails")), OPT_END(), }; int i; - /* - * NEEDSWORK: Once the builtin rebase has been tested enough - * and git-legacy-rebase.sh is retired to contrib/, this preamble - * can be removed. - */ - - if (!use_builtin_rebase()) { - const char *path = mkpath("%s/git-legacy-rebase", - git_exec_path()); - - if (sane_execvp(path, (char **)argv) < 0) - die_errno(_("could not exec %s"), path); - else - BUG("sane_execvp() returned???"); - } - if (argc == 2 && !strcmp(argv[1], "-h")) usage_with_options(builtin_rebase_usage, builtin_rebase_options); @@@ -1494,11 -1531,6 +1504,11 @@@ options.allow_empty_message = 1; git_config(rebase_config, &options); + if (options.use_legacy_rebase || + !git_env_bool("GIT_TEST_REBASE_USE_BUILTIN", -1)) + warning(_("the rebase.useBuiltin support has been removed!\n" + "See its entry in 'git help config' for details.")); + strbuf_reset(&buf); strbuf_addf(&buf, "%s/applying", apply_dir()); if(file_exists(buf.buf)) @@@ -1542,10 -1574,6 +1552,10 @@@ usage_with_options(builtin_rebase_usage, builtin_rebase_options); + if (options.type == REBASE_PRESERVE_MERGES) + warning(_("git rebase --preserve-merges is deprecated. " + "Use --rebase-merges instead.")); + if (action != ACTION_NONE && !in_progress) die(_("No rebase in progress?")); setenv(GIT_REFLOG_ACTION_ENVIRONMENT, "rebase", 0); @@@ -1627,15 -1655,23 +1637,23 @@@ die(_("could not move back to %s"), oid_to_hex(&options.orig_head)); remove_branch_state(the_repository); - ret = finish_rebase(&options); + ret = !!finish_rebase(&options); goto cleanup; } case ACTION_QUIT: { - strbuf_reset(&buf); - strbuf_addstr(&buf, options.state_dir); - ret = !!remove_dir_recursively(&buf, 0); - if (ret) - die(_("could not remove '%s'"), options.state_dir); + if (options.type == REBASE_INTERACTIVE) { + struct replay_opts replay = REPLAY_OPTS_INIT; + + replay.action = REPLAY_INTERACTIVE_REBASE; + ret = !!sequencer_remove_state(&replay); + } else { + strbuf_reset(&buf); + strbuf_addstr(&buf, options.state_dir); + ret = !!remove_dir_recursively(&buf, 0); + if (ret) + error(_("could not remove '%s'"), + options.state_dir); + } goto cleanup; } case ACTION_EDIT_TODO: @@@ -1784,11 -1820,8 +1802,11 @@@ break; } - if (options.reschedule_failed_exec && !is_interactive(&options)) - die(_("%s requires an interactive rebase"), "--reschedule-failed-exec"); + if (reschedule_failed_exec > 0 && !is_interactive(&options)) + die(_("--reschedule-failed-exec requires " + "--exec or --interactive")); + if (reschedule_failed_exec >= 0) + options.reschedule_failed_exec = reschedule_failed_exec; if (options.git_am_opts.argc) { /* all am options except -q are compatible only with --am */ @@@ -1924,7 -1957,8 +1942,7 @@@ branch_name = options.head_name; } else { - free(options.head_name); - options.head_name = NULL; + FREE_AND_NULL(options.head_name); branch_name = "HEAD"; } if (get_oid("HEAD", &options.orig_head)) @@@ -2113,8 -2147,7 +2131,8 @@@ strbuf_addf(&msg, "%s: checkout %s", getenv(GIT_REFLOG_ACTION_ENVIRONMENT), options.onto_name); if (reset_head(&options.onto->object.oid, "checkout", NULL, - RESET_HEAD_DETACH | RESET_HEAD_RUN_POST_CHECKOUT_HOOK, + RESET_HEAD_DETACH | RESET_ORIG_HEAD | + RESET_HEAD_RUN_POST_CHECKOUT_HOOK, NULL, msg.buf)) die(_("Could not detach HEAD")); strbuf_release(&msg); @@@ -2124,14 -2157,14 +2142,14 @@@ * we just fast-forwarded. */ strbuf_reset(&msg); - if (!oidcmp(&merge_base, &options.orig_head)) { + if (oideq(&merge_base, &options.orig_head)) { printf(_("Fast-forwarded %s to %s.\n"), branch_name, options.onto_name); strbuf_addf(&msg, "rebase finished: %s onto %s", options.head_name ? options.head_name : "detached HEAD", oid_to_hex(&options.onto->object.oid)); - reset_head(NULL, "Fast-forwarded", options.head_name, 0, - "HEAD", msg.buf); + reset_head(NULL, "Fast-forwarded", options.head_name, + RESET_HEAD_REFS_ONLY, "HEAD", msg.buf); strbuf_release(&msg); ret = !!finish_rebase(&options); goto cleanup; @@@ -2150,6 -2183,7 +2168,7 @@@ run_rebase ret = !!run_specific_rebase(&options, action); cleanup: + strbuf_release(&buf); strbuf_release(&revisions); free(options.head_name); free(options.gpg_sign_opt); diff --combined sequencer.c index 63b09cfceb,258e583156..1d206fd224 --- a/sequencer.c +++ b/sequencer.c @@@ -171,22 -171,17 +171,22 @@@ static int git_sequencer_config(const c if (status) return status; - if (!strcmp(s, "verbatim")) + if (!strcmp(s, "verbatim")) { opts->default_msg_cleanup = COMMIT_MSG_CLEANUP_NONE; - else if (!strcmp(s, "whitespace")) + opts->explicit_cleanup = 1; + } else if (!strcmp(s, "whitespace")) { opts->default_msg_cleanup = COMMIT_MSG_CLEANUP_SPACE; - else if (!strcmp(s, "strip")) + opts->explicit_cleanup = 1; + } else if (!strcmp(s, "strip")) { opts->default_msg_cleanup = COMMIT_MSG_CLEANUP_ALL; - else if (!strcmp(s, "scissors")) - opts->default_msg_cleanup = COMMIT_MSG_CLEANUP_SPACE; - else + opts->explicit_cleanup = 1; + } else if (!strcmp(s, "scissors")) { + opts->default_msg_cleanup = COMMIT_MSG_CLEANUP_SCISSORS; + opts->explicit_cleanup = 1; + } else { warning(_("invalid commit message cleanup mode '%s'"), s); + } free((char *)s); return status; @@@ -279,7 -274,7 +279,7 @@@ static const char *gpg_sign_opt_quoted( int sequencer_remove_state(struct replay_opts *opts) { struct strbuf buf = STRBUF_INIT; - int i; + int i, ret = 0; if (is_rebase_i(opts) && strbuf_read_file(&buf, rebase_path_refs_to_delete(), 0) > 0) { @@@ -288,8 -283,10 +288,10 @@@ char *eol = strchr(p, '\n'); if (eol) *eol = '\0'; - if (delete_ref("(rebase -i) cleanup", p, NULL, 0) < 0) + if (delete_ref("(rebase -i) cleanup", p, NULL, 0) < 0) { warning(_("could not delete '%s'"), p); + ret = -1; + } if (!eol) break; p = eol + 1; @@@ -305,10 -302,11 +307,11 @@@ strbuf_reset(&buf); strbuf_addstr(&buf, get_dir(opts)); - remove_dir_recursively(&buf, 0); + if (remove_dir_recursively(&buf, 0)) + ret = error(_("could not remove '%s'"), buf.buf); strbuf_release(&buf); - return 0; + return ret; } static const char *action_name(const struct replay_opts *opts) @@@ -515,54 -513,11 +518,54 @@@ static int fast_forward_to(struct repos return 0; } +enum commit_msg_cleanup_mode get_cleanup_mode(const char *cleanup_arg, + int use_editor) +{ + if (!cleanup_arg || !strcmp(cleanup_arg, "default")) + return use_editor ? COMMIT_MSG_CLEANUP_ALL : + COMMIT_MSG_CLEANUP_SPACE; + else if (!strcmp(cleanup_arg, "verbatim")) + return COMMIT_MSG_CLEANUP_NONE; + else if (!strcmp(cleanup_arg, "whitespace")) + return COMMIT_MSG_CLEANUP_SPACE; + else if (!strcmp(cleanup_arg, "strip")) + return COMMIT_MSG_CLEANUP_ALL; + else if (!strcmp(cleanup_arg, "scissors")) + return use_editor ? COMMIT_MSG_CLEANUP_SCISSORS : + COMMIT_MSG_CLEANUP_SPACE; + else + die(_("Invalid cleanup mode %s"), cleanup_arg); +} + +/* + * NB using int rather than enum cleanup_mode to stop clang's + * -Wtautological-constant-out-of-range-compare complaining that the comparison + * is always true. + */ +static const char *describe_cleanup_mode(int cleanup_mode) +{ + static const char *modes[] = { "whitespace", + "verbatim", + "scissors", + "strip" }; + + if (cleanup_mode < ARRAY_SIZE(modes)) + return modes[cleanup_mode]; + + BUG("invalid cleanup_mode provided (%d)", cleanup_mode); +} + void append_conflicts_hint(struct index_state *istate, - struct strbuf *msgbuf) + struct strbuf *msgbuf, enum commit_msg_cleanup_mode cleanup_mode) { int i; + if (cleanup_mode == COMMIT_MSG_CLEANUP_SCISSORS) { + strbuf_addch(msgbuf, '\n'); + wt_status_append_cut_line(msgbuf); + strbuf_addch(msgbuf, comment_line_char); + } + strbuf_addch(msgbuf, '\n'); strbuf_commented_addf(msgbuf, "Conflicts:\n"); for (i = 0; i < istate->cache_nr;) { @@@ -630,8 -585,7 +633,8 @@@ static int do_recursive_merge(struct re _(action_name(opts))); if (!clean) - append_conflicts_hint(r->index, msgbuf); + append_conflicts_hint(r->index, msgbuf, + opts->default_msg_cleanup); return !clean; } @@@ -950,6 -904,7 +953,6 @@@ static int run_git_commit(struct reposi unsigned int flags) { struct child_process cmd = CHILD_PROCESS_INIT; - const char *value; if ((flags & CREATE_ROOT_COMMIT) && !(flags & AMEND_MSG)) { struct strbuf msg = STRBUF_INIT, script = STRBUF_INIT; @@@ -1019,7 -974,7 +1022,7 @@@ argv_array_push(&cmd.args, "-e"); else if (!(flags & CLEANUP_MSG) && !opts->signoff && !opts->record_origin && - git_config_get_value("commit.cleanup", &value)) + !opts->explicit_cleanup) argv_array_push(&cmd.args, "--cleanup=verbatim"); if ((flags & ALLOW_EMPTY)) @@@ -1060,16 -1015,6 +1063,16 @@@ static int rest_is_empty(const struct s return 1; } +void cleanup_message(struct strbuf *msgbuf, + enum commit_msg_cleanup_mode cleanup_mode, int verbose) +{ + if (verbose || /* Truncate the message just before the diff, if any. */ + cleanup_mode == COMMIT_MSG_CLEANUP_SCISSORS) + strbuf_setlen(msgbuf, wt_status_locate_end(msgbuf->buf, msgbuf->len)); + if (cleanup_mode != COMMIT_MSG_CLEANUP_NONE) + strbuf_stripspace(msgbuf, cleanup_mode == COMMIT_MSG_CLEANUP_ALL); +} + /* * Find out if the message in the strbuf contains only whitespace and * Signed-off-by lines. @@@ -1440,13 -1385,8 +1443,13 @@@ static int try_to_commit(struct reposit msg = &commit_msg; } - cleanup = (flags & CLEANUP_MSG) ? COMMIT_MSG_CLEANUP_ALL : - opts->default_msg_cleanup; + if (flags & CLEANUP_MSG) + cleanup = COMMIT_MSG_CLEANUP_ALL; + else if ((opts->signoff || opts->record_origin) && + !opts->explicit_cleanup) + cleanup = COMMIT_MSG_CLEANUP_SPACE; + else + cleanup = opts->default_msg_cleanup; if (cleanup != COMMIT_MSG_CLEANUP_NONE) strbuf_stripspace(msg, cleanup == COMMIT_MSG_CLEANUP_ALL); @@@ -2161,48 -2101,12 +2164,48 @@@ static int parse_insn_line(struct repos item->arg_len = (int)(eol - bol); if (status < 0) - return -1; + return error(_("could not parse '%.*s'"), + (int)(end_of_object_name - bol), bol); item->commit = lookup_commit_reference(r, &commit_oid); return !item->commit; } +int sequencer_get_last_command(struct repository *r, enum replay_action *action) +{ + struct todo_item item; + char *eol; + const char *todo_file; + struct strbuf buf = STRBUF_INIT; + int ret = -1; + + todo_file = git_path_todo_file(); + if (strbuf_read_file(&buf, todo_file, 0) < 0) { + if (errno == ENOENT) + return -1; + else + return error_errno("unable to open '%s'", todo_file); + } + eol = strchrnul(buf.buf, '\n'); + if (buf.buf != eol && eol[-1] == '\r') + eol--; /* strip Carriage Return */ + if (parse_insn_line(r, &item, buf.buf, buf.buf, eol)) + goto fail; + if (item.command == TODO_PICK) + *action = REPLAY_PICK; + else if (item.command == TODO_REVERT) + *action = REPLAY_REVERT; + else + goto fail; + + ret = 0; + + fail: + strbuf_release(&buf); + + return ret; +} + int todo_list_parse_insn_buffer(struct repository *r, char *buf, struct todo_list *todo_list) { @@@ -2286,57 -2190,6 +2289,57 @@@ static ssize_t strbuf_read_file_or_whin return len; } +static int have_finished_the_last_pick(void) +{ + struct strbuf buf = STRBUF_INIT; + const char *eol; + const char *todo_path = git_path_todo_file(); + int ret = 0; + + if (strbuf_read_file(&buf, todo_path, 0) < 0) { + if (errno == ENOENT) { + return 0; + } else { + error_errno("unable to open '%s'", todo_path); + return 0; + } + } + /* If there is only one line then we are done */ + eol = strchr(buf.buf, '\n'); + if (!eol || !eol[1]) + ret = 1; + + strbuf_release(&buf); + + return ret; +} + +void sequencer_post_commit_cleanup(struct repository *r) +{ + struct replay_opts opts = REPLAY_OPTS_INIT; + int need_cleanup = 0; + + if (file_exists(git_path_cherry_pick_head(r))) { + unlink(git_path_cherry_pick_head(r)); + opts.action = REPLAY_PICK; + need_cleanup = 1; + } + + if (file_exists(git_path_revert_head(r))) { + unlink(git_path_revert_head(r)); + opts.action = REPLAY_REVERT; + need_cleanup = 1; + } + + if (!need_cleanup) + return; + + if (!have_finished_the_last_pick()) + return; + + sequencer_remove_state(&opts); +} + static int read_populate_todo(struct repository *r, struct todo_list *todo_list, struct replay_opts *opts) @@@ -2424,15 -2277,6 +2427,15 @@@ static int populate_opts_cb(const char opts->no_commit = git_config_bool_or_int(key, value, &error_flag); else if (!strcmp(key, "options.edit")) opts->edit = git_config_bool_or_int(key, value, &error_flag); + else if (!strcmp(key, "options.allow-empty")) + opts->allow_empty = + git_config_bool_or_int(key, value, &error_flag); + else if (!strcmp(key, "options.allow-empty-message")) + opts->allow_empty_message = + git_config_bool_or_int(key, value, &error_flag); + else if (!strcmp(key, "options.keep-redundant-commits")) + opts->keep_redundant_commits = + git_config_bool_or_int(key, value, &error_flag); else if (!strcmp(key, "options.signoff")) opts->signoff = git_config_bool_or_int(key, value, &error_flag); else if (!strcmp(key, "options.record-origin")) @@@ -2452,10 -2296,7 +2455,10 @@@ opts->allow_rerere_auto = git_config_bool_or_int(key, value, &error_flag) ? RERERE_AUTOUPDATE : RERERE_NOAUTOUPDATE; - else + else if (!strcmp(key, "options.default-msg-cleanup")) { + opts->explicit_cleanup = 1; + opts->default_msg_cleanup = get_cleanup_mode(value, 1); + } else return error(_("invalid key: %s"), key); if (!error_flag) @@@ -2830,59 -2671,36 +2833,59 @@@ static int save_opts(struct replay_opt int res = 0; if (opts->no_commit) - res |= git_config_set_in_file_gently(opts_file, "options.no-commit", "true"); + res |= git_config_set_in_file_gently(opts_file, + "options.no-commit", "true"); if (opts->edit) - res |= git_config_set_in_file_gently(opts_file, "options.edit", "true"); + res |= git_config_set_in_file_gently(opts_file, + "options.edit", "true"); + if (opts->allow_empty) + res |= git_config_set_in_file_gently(opts_file, + "options.allow-empty", "true"); + if (opts->allow_empty_message) + res |= git_config_set_in_file_gently(opts_file, + "options.allow-empty-message", "true"); + if (opts->keep_redundant_commits) + res |= git_config_set_in_file_gently(opts_file, + "options.keep-redundant-commits", "true"); if (opts->signoff) - res |= git_config_set_in_file_gently(opts_file, "options.signoff", "true"); + res |= git_config_set_in_file_gently(opts_file, + "options.signoff", "true"); if (opts->record_origin) - res |= git_config_set_in_file_gently(opts_file, "options.record-origin", "true"); + res |= git_config_set_in_file_gently(opts_file, + "options.record-origin", "true"); if (opts->allow_ff) - res |= git_config_set_in_file_gently(opts_file, "options.allow-ff", "true"); + res |= git_config_set_in_file_gently(opts_file, + "options.allow-ff", "true"); if (opts->mainline) { struct strbuf buf = STRBUF_INIT; strbuf_addf(&buf, "%d", opts->mainline); - res |= git_config_set_in_file_gently(opts_file, "options.mainline", buf.buf); + res |= git_config_set_in_file_gently(opts_file, + "options.mainline", buf.buf); strbuf_release(&buf); } if (opts->strategy) - res |= git_config_set_in_file_gently(opts_file, "options.strategy", opts->strategy); + res |= git_config_set_in_file_gently(opts_file, + "options.strategy", opts->strategy); if (opts->gpg_sign) - res |= git_config_set_in_file_gently(opts_file, "options.gpg-sign", opts->gpg_sign); + res |= git_config_set_in_file_gently(opts_file, + "options.gpg-sign", opts->gpg_sign); if (opts->xopts) { int i; for (i = 0; i < opts->xopts_nr; i++) res |= git_config_set_multivar_in_file_gently(opts_file, - "options.strategy-option", - opts->xopts[i], "^$", 0); + "options.strategy-option", + opts->xopts[i], "^$", 0); } if (opts->allow_rerere_auto) - res |= git_config_set_in_file_gently(opts_file, "options.allow-rerere-auto", - opts->allow_rerere_auto == RERERE_AUTOUPDATE ? - "true" : "false"); + res |= git_config_set_in_file_gently(opts_file, + "options.allow-rerere-auto", + opts->allow_rerere_auto == RERERE_AUTOUPDATE ? + "true" : "false"); + + if (opts->explicit_cleanup) + res |= git_config_set_in_file_gently(opts_file, + "options.default-msg-cleanup", + describe_cleanup_mode(opts->default_msg_cleanup)); return res; } @@@ -3731,11 -3549,8 +3734,11 @@@ static int pick_commits(struct reposito unlink(git_path_merge_head(the_repository)); delete_ref(NULL, "REBASE_HEAD", NULL, REF_NO_DEREF); - if (item->command == TODO_BREAK) + if (item->command == TODO_BREAK) { + if (!opts->verbose) + term_clear_line(); return stopped_at_head(r); + } } if (item->command <= TODO_SQUASH) { if (is_rebase_i(opts)) @@@ -3757,14 -3572,11 +3760,14 @@@ } if (item->command == TODO_EDIT) { struct commit *commit = item->commit; - if (!res) + if (!res) { + if (!opts->verbose) + term_clear_line(); fprintf(stderr, _("Stopped at %s... %.*s\n"), short_commit_name(commit), item->arg_len, arg); + } return error_with_patch(r, commit, arg, item->arg_len, opts, res, !res); } @@@ -3802,12 -3614,11 +3805,12 @@@ int saved = *end_of_arg; struct stat st; + if (!opts->verbose) + term_clear_line(); *end_of_arg = '\0'; res = do_exec(r, arg); *end_of_arg = saved; - /* Reread the todo file if it has changed. */ if (res) { if (opts->reschedule_failed_exec) reschedule = 1; @@@ -3815,7 -3626,6 +3818,7 @@@ res = error_errno(_("could not stat '%s'"), get_todo_path(opts)); else if (match_stat_data(&todo_list->stat, &st)) { + /* Reread the todo file if it has changed. */ todo_list_release(todo_list); if (read_populate_todo(r, todo_list, opts)) res = -1; /* message was printed */ @@@ -3962,13 -3772,10 +3965,13 @@@ cleanup_head_ref } apply_autostash(opts); - if (!opts->quiet) + if (!opts->quiet) { + if (!opts->verbose) + term_clear_line(); fprintf(stderr, "Successfully rebased and updated %s.\n", head_ref.buf); + } strbuf_release(&buf); strbuf_release(&head_ref); diff --combined t/t3430-rebase-merges.sh index 42ba5b9f09,e63576d334..f0814d5280 --- a/t/t3430-rebase-merges.sh +++ b/t/t3430-rebase-merges.sh @@@ -224,8 -224,24 +224,24 @@@ test_expect_success 'refs/rewritten/* i test_cmp_rev HEAD "$(cat wt/b)" ' + test_expect_success '--abort cleans up refs/rewritten' ' + git checkout -b abort-cleans-refs-rewritten H && + GIT_SEQUENCE_EDITOR="echo break >>" git rebase -ir @^ && + git rev-parse --verify refs/rewritten/onto && + git rebase --abort && + test_must_fail git rev-parse --verify refs/rewritten/onto + ' + + test_expect_success '--quit cleans up refs/rewritten' ' + git checkout -b quit-cleans-refs-rewritten H && + GIT_SEQUENCE_EDITOR="echo break >>" git rebase -ir @^ && + git rev-parse --verify refs/rewritten/onto && + git rebase --quit && + test_must_fail git rev-parse --verify refs/rewritten/onto + ' + test_expect_success 'post-rewrite hook and fixups work for merges' ' - git checkout -b post-rewrite && + git checkout -b post-rewrite H && test_commit same1 && git reset --hard HEAD^ && test_commit same2 && @@@ -271,7 -287,7 +287,7 @@@ test_expect_success 'root commits' EOF test_config sequence.editor \""$PWD"/replace-editor.sh\" && test_tick && - git rebase -i --force --root -r && + git rebase -i --force-rebase --root -r && test "Parsnip" = "$(git show -s --format=%an HEAD^)" && test $(git rev-parse second-root^0) != $(git rev-parse HEAD^) && test $(git rev-parse second-root:second-root.t) = \ @@@ -364,7 -380,7 +380,7 @@@ test_expect_success 'octopus merges' test_cmp_rev HEAD $before && test_tick && - git rebase -i --force -r HEAD^^ && + git rebase -i --force-rebase -r HEAD^^ && test "Hank" = "$(git show -s --format=%an HEAD)" && test "$before" != $(git rev-parse HEAD) && test_cmp_graph HEAD^^.. <<-\EOF