diff options
Diffstat (limited to 'builtin/rebase.c')
| -rw-r--r-- | builtin/rebase.c | 144 |
1 files changed, 76 insertions, 68 deletions
diff --git a/builtin/rebase.c b/builtin/rebase.c index 4084a6abb8..e3a8e74cfc 100644 --- a/builtin/rebase.c +++ b/builtin/rebase.c @@ -4,7 +4,6 @@ * Copyright (c) 2018 Pratik Karki */ -#define USE_THE_INDEX_VARIABLE #include "builtin.h" #include "abspath.h" #include "environment.h" @@ -58,7 +57,7 @@ enum empty_type { EMPTY_UNSPECIFIED = -1, EMPTY_DROP, EMPTY_KEEP, - EMPTY_ASK + EMPTY_STOP }; enum action { @@ -84,7 +83,7 @@ static const char *action_names[] = { struct rebase_options { enum rebase_type type; enum empty_type empty; - const char *default_backend; + char *default_backend; const char *state_dir; struct commit *upstream; const char *upstream_name; @@ -136,7 +135,7 @@ struct rebase_options { .type = REBASE_UNSPECIFIED, \ .empty = EMPTY_UNSPECIFIED, \ .keep_empty = 1, \ - .default_backend = "merge", \ + .default_backend = xstrdup("merge"), \ .flags = REBASE_NO_QUIET, \ .git_am_opts = STRVEC_INIT, \ .exec = STRING_LIST_INIT_NODUP, \ @@ -145,7 +144,6 @@ struct rebase_options { .reapply_cherry_picks = -1, \ .allow_empty_message = 1, \ .autosquash = -1, \ - .config_autosquash = -1, \ .rebase_merges = -1, \ .config_rebase_merges = -1, \ .update_refs = -1, \ @@ -153,6 +151,19 @@ struct rebase_options { .strategy_opts = STRING_LIST_INIT_NODUP,\ } +static void rebase_options_release(struct rebase_options *opts) +{ + free(opts->default_backend); + free(opts->reflog_action); + free(opts->head_name); + strvec_clear(&opts->git_am_opts); + free(opts->gpg_sign_opt); + string_list_clear(&opts->exec, 0); + free(opts->strategy); + string_list_clear(&opts->strategy_opts, 0); + strbuf_release(&opts->git_format_patch_opt); +} + static struct replay_opts get_replay_opts(const struct rebase_options *opts) { struct replay_opts replay = REPLAY_OPTS_INIT; @@ -195,7 +206,7 @@ static struct replay_opts get_replay_opts(const struct rebase_options *opts) return replay; } -static int edit_todo_file(unsigned flags) +static int edit_todo_file(unsigned flags, struct replay_opts *opts) { const char *todo_file = rebase_path_todo(); struct todo_list todo_list = TODO_LIST_INIT, @@ -205,8 +216,9 @@ static int edit_todo_file(unsigned flags) if (strbuf_read_file(&todo_list.buf, todo_file, 0) < 0) return error_errno(_("could not read '%s'."), todo_file); - strbuf_stripspace(&todo_list.buf, comment_line_char); - res = edit_todo_list(the_repository, &todo_list, &new_todo, NULL, NULL, flags); + strbuf_stripspace(&todo_list.buf, comment_line_str); + res = edit_todo_list(the_repository, opts, &todo_list, &new_todo, + NULL, NULL, flags); if (!res && todo_list_write_to_file(the_repository, &new_todo, todo_file, NULL, NULL, -1, flags & ~(TODO_LIST_SHORTEN_IDS))) res = error_errno(_("could not write '%s'"), todo_file); @@ -253,7 +265,7 @@ static int init_basic_state(struct replay_opts *opts, const char *head_name, if (!is_directory(merge_dir()) && mkdir_in_gitdir(merge_dir())) return error_errno(_("could not create temporary %s"), merge_dir()); - delete_reflog("REBASE_HEAD"); + refs_delete_reflog(get_main_ref_store(the_repository), "REBASE_HEAD"); interactive = fopen(path_interactive(), "w"); if (!interactive) @@ -296,9 +308,9 @@ static int do_interactive_rebase(struct rebase_options *opts, unsigned flags) if (ret) error(_("could not generate todo list")); else { - discard_index(&the_index); - if (todo_list_parse_insn_buffer(the_repository, todo_list.buf.buf, - &todo_list)) + discard_index(the_repository->index); + if (todo_list_parse_insn_buffer(the_repository, &replay, + todo_list.buf.buf, &todo_list)) BUG("unusable todo list"); ret = complete_action(the_repository, &replay, flags, @@ -353,9 +365,13 @@ static int run_sequencer_rebase(struct rebase_options *opts) replay_opts_release(&replay_opts); break; } - case ACTION_EDIT_TODO: - ret = edit_todo_file(flags); + case ACTION_EDIT_TODO: { + struct replay_opts replay_opts = get_replay_opts(opts); + + ret = edit_todo_file(flags, &replay_opts); + replay_opts_release(&replay_opts); break; + } case ACTION_SHOW_CURRENT_PATCH: { struct child_process cmd = CHILD_PROCESS_INIT; @@ -515,8 +531,10 @@ static int finish_rebase(struct rebase_options *opts) struct strbuf dir = STRBUF_INIT; int ret = 0; - delete_ref(NULL, "REBASE_HEAD", NULL, REF_NO_DEREF); - unlink(git_path_auto_merge(the_repository)); + refs_delete_ref(get_main_ref_store(the_repository), NULL, + "REBASE_HEAD", NULL, REF_NO_DEREF); + refs_delete_ref(get_main_ref_store(the_repository), NULL, + "AUTO_MERGE", NULL, REF_NO_DEREF); apply_autostash(state_dir_path("autostash", opts)); /* * We ignore errors in 'git maintenance run --auto', since the @@ -568,13 +586,6 @@ static int move_to_original_branch(struct rebase_options *opts) return ret; } -static const char *resolvemsg = -N_("Resolve all conflicts manually, mark them as resolved with\n" -"\"git add/rm <conflicted_files>\", then run \"git rebase --continue\".\n" -"You can instead skip this commit: run \"git rebase --skip\".\n" -"To abort and get back to the state before \"git rebase\", run " -"\"git rebase --abort\"."); - static int run_am(struct rebase_options *opts) { struct child_process am = CHILD_PROCESS_INIT; @@ -588,7 +599,7 @@ static int run_am(struct rebase_options *opts) opts->reflog_action); if (opts->action == ACTION_CONTINUE) { strvec_push(&am.args, "--resolved"); - strvec_pushf(&am.args, "--resolvemsg=%s", resolvemsg); + strvec_pushf(&am.args, "--resolvemsg=%s", rebase_resolvemsg); if (opts->gpg_sign_opt) strvec_push(&am.args, opts->gpg_sign_opt); status = run_command(&am); @@ -599,7 +610,7 @@ static int run_am(struct rebase_options *opts) } if (opts->action == ACTION_SKIP) { strvec_push(&am.args, "--skip"); - strvec_pushf(&am.args, "--resolvemsg=%s", resolvemsg); + strvec_pushf(&am.args, "--resolvemsg=%s", rebase_resolvemsg); status = run_command(&am); if (status) return status; @@ -618,7 +629,7 @@ static int run_am(struct rebase_options *opts) status = error_errno(_("could not open '%s' for writing"), rebased_patches); free(rebased_patches); - strvec_clear(&am.args); + child_process_clear(&am); return status; } @@ -646,7 +657,7 @@ static int run_am(struct rebase_options *opts) struct reset_head_opts ropts = { 0 }; unlink(rebased_patches); free(rebased_patches); - strvec_clear(&am.args); + child_process_clear(&am); ropts.oid = &opts->orig_head->object.oid; ropts.branch = opts->head_name; @@ -667,13 +678,13 @@ static int run_am(struct rebase_options *opts) status = error_errno(_("could not open '%s' for reading"), rebased_patches); free(rebased_patches); - strvec_clear(&am.args); + child_process_clear(&am); return status; } strvec_pushv(&am.args, opts->git_am_opts.v); strvec_push(&am.args, "--rebasing"); - strvec_pushf(&am.args, "--resolvemsg=%s", resolvemsg); + strvec_pushf(&am.args, "--resolvemsg=%s", rebase_resolvemsg); strvec_push(&am.args, "--patch-format=mboxrd"); if (opts->allow_rerere_autoupdate == RERERE_AUTOUPDATE) strvec_push(&am.args, "--rerere-autoupdate"); @@ -701,11 +712,8 @@ static int run_specific_rebase(struct rebase_options *opts) if (opts->type == REBASE_MERGE) { /* Run sequencer-based rebase */ - setenv("GIT_CHERRY_PICK_HELP", resolvemsg, 1); - if (!(opts->flags & REBASE_INTERACTIVE_EXPLICIT)) { + if (!(opts->flags & REBASE_INTERACTIVE_EXPLICIT)) setenv("GIT_SEQUENCE_EDITOR", ":", 1); - opts->autosquash = 0; - } if (opts->gpg_sign_opt) { /* remove the leading "-S" */ char *tmp = xstrdup(opts->gpg_sign_opt + 2); @@ -806,6 +814,7 @@ static int rebase_config(const char *var, const char *value, } if (!strcmp(var, "rebase.backend")) { + FREE_AND_NULL(opts->default_backend); return git_config_string(&opts->default_backend, var, value); } @@ -870,7 +879,8 @@ static int can_fast_forward(struct commit *onto, struct commit *upstream, if (!upstream) goto done; - merge_bases = repo_get_merge_bases(the_repository, upstream, head); + if (repo_get_merge_bases(the_repository, upstream, head, &merge_bases) < 0) + exit(128); if (!merge_bases || merge_bases->next) goto done; @@ -889,8 +899,9 @@ static void fill_branch_base(struct rebase_options *options, { struct commit_list *merge_bases = NULL; - merge_bases = repo_get_merge_bases(the_repository, options->onto, - options->orig_head); + if (repo_get_merge_bases(the_repository, options->onto, + options->orig_head, &merge_bases) < 0) + exit(128); if (!merge_bases || merge_bases->next) oidcpy(branch_base, null_oid()); else @@ -954,10 +965,14 @@ static enum empty_type parse_empty_value(const char *value) return EMPTY_DROP; else if (!strcasecmp(value, "keep")) return EMPTY_KEEP; - else if (!strcasecmp(value, "ask")) - return EMPTY_ASK; + else if (!strcasecmp(value, "stop")) + return EMPTY_STOP; + else if (!strcasecmp(value, "ask")) { + warning(_("--empty=ask is deprecated; use '--empty=stop' instead.")); + return EMPTY_STOP; + } - die(_("unrecognized empty type '%s'; valid values are \"drop\", \"keep\", and \"ask\"."), value); + die(_("unrecognized empty type '%s'; valid values are \"drop\", \"keep\", and \"stop\"."), value); } static int parse_opt_keep_empty(const struct option *opt, const char *arg, @@ -1051,6 +1066,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix) { struct rebase_options options = REBASE_OPTIONS_INIT; const char *branch_name; + const char *strategy_opt = NULL; int ret, flags, total_argc, in_progress = 0; int keep_base = 0; int ok_to_skip_pre_rebase = 0; @@ -1136,7 +1152,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix) "instead of ignoring them"), 1, PARSE_OPT_HIDDEN), OPT_RERERE_AUTOUPDATE(&options.allow_rerere_autoupdate), - OPT_CALLBACK_F(0, "empty", &options, "(drop|keep|ask)", + OPT_CALLBACK_F(0, "empty", &options, "(drop|keep|stop)", N_("how to handle commits that become empty"), PARSE_OPT_NONEG, parse_opt_empty), OPT_CALLBACK_F('k', "keep-empty", &options, NULL, @@ -1165,7 +1181,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix) PARSE_OPT_OPTARG, parse_opt_rebase_merges), OPT_BOOL(0, "fork-point", &options.fork_point, N_("use 'merge-base --fork-point' to refine upstream")), - OPT_STRING('s', "strategy", &options.strategy, + OPT_STRING('s', "strategy", &strategy_opt, N_("strategy"), N_("use the given merge strategy")), OPT_STRING_LIST('X', "strategy-option", &options.strategy_opts, N_("option"), @@ -1257,7 +1273,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix) die(_("options '%s' and '%s' cannot be used together"), "--root", "--fork-point"); if (options.action != ACTION_NONE && !in_progress) - die(_("No rebase in progress?")); + die(_("no rebase in progress")); if (options.action == ACTION_EDIT_TODO && !is_merge(&options)) die(_("The --edit-todo action can only be used during " @@ -1396,7 +1412,6 @@ int cmd_rebase(int argc, const char **argv, const char *prefix) if ((options.flags & REBASE_INTERACTIVE_EXPLICIT) || (options.action != ACTION_NONE) || (options.exec.nr > 0) || - (options.autosquash == -1 && options.config_autosquash == 1) || options.autosquash == 1) { allow_preemptive_ff = 0; } @@ -1475,13 +1490,12 @@ int cmd_rebase(int argc, const char **argv, const char *prefix) } } - if (options.strategy_opts.nr && !options.strategy) - options.strategy = "ort"; - - if (options.strategy) { - options.strategy = xstrdup(options.strategy); + if (strategy_opt) + options.strategy = xstrdup(strategy_opt); + else if (options.strategy_opts.nr && !options.strategy) + options.strategy = xstrdup("ort"); + if (options.strategy) imply_merge(&options, "--strategy"); - } if (options.root && !options.onto_name) imply_merge(&options, "--root without --onto"); @@ -1499,8 +1513,6 @@ int cmd_rebase(int argc, const char **argv, const char *prefix) if (is_merge(&options)) die(_("apply options and merge options " "cannot be used together")); - else if (options.autosquash == -1 && options.config_autosquash == 1) - die(_("apply options are incompatible with rebase.autoSquash. Consider adding --no-autosquash")); else if (options.rebase_merges == -1 && options.config_rebase_merges == 1) die(_("apply options are incompatible with rebase.rebaseMerges. Consider adding --no-rebase-merges")); else if (options.update_refs == -1 && options.config_update_refs == 1) @@ -1520,10 +1532,13 @@ int cmd_rebase(int argc, const char **argv, const char *prefix) options.rebase_merges = (options.rebase_merges >= 0) ? options.rebase_merges : ((options.config_rebase_merges >= 0) ? options.config_rebase_merges : 0); - if (options.autosquash == 1) + if (options.autosquash == 1) { imply_merge(&options, "--autosquash"); - options.autosquash = (options.autosquash >= 0) ? options.autosquash : - ((options.config_autosquash >= 0) ? options.config_autosquash : 0); + } else if (options.autosquash == -1) { + options.autosquash = + options.config_autosquash && + (options.flags & REBASE_INTERACTIVE_EXPLICIT); + } if (options.type == REBASE_UNSPECIFIED) { if (!strcmp(options.default_backend, "merge")) @@ -1553,7 +1568,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix) if (options.empty == EMPTY_UNSPECIFIED) { if (options.flags & REBASE_INTERACTIVE_EXPLICIT) - options.empty = EMPTY_ASK; + options.empty = EMPTY_STOP; else if (options.exec.nr > 0) options.empty = EMPTY_KEEP; else @@ -1628,7 +1643,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix) /* Is it a local branch? */ strbuf_reset(&buf); strbuf_addf(&buf, "refs/heads/%s", branch_name); - if (!read_ref(buf.buf, &branch_oid)) { + if (!refs_read_ref(get_main_ref_store(the_repository), buf.buf, &branch_oid)) { die_if_checked_out(buf.buf, 1); options.head_name = xstrdup(buf.buf); options.orig_head = @@ -1645,8 +1660,8 @@ int cmd_rebase(int argc, const char **argv, const char *prefix) } else if (argc == 0) { /* Do not need to switch branches, we are already on it. */ options.head_name = - xstrdup_or_null(resolve_ref_unsafe("HEAD", 0, NULL, - &flags)); + xstrdup_or_null(refs_resolve_ref_unsafe(get_main_ref_store(the_repository), "HEAD", 0, NULL, + &flags)); if (!options.head_name) die(_("No such ref: %s"), "HEAD"); if (flags & REF_ISSYMREF) { @@ -1740,7 +1755,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix) if (!(options.flags & REBASE_NO_QUIET)) ; /* be quiet */ else if (!strcmp(branch_name, "HEAD") && - resolve_ref_unsafe("HEAD", 0, NULL, &flag)) + refs_resolve_ref_unsafe(get_main_ref_store(the_repository), "HEAD", 0, NULL, &flag)) puts(_("HEAD is up to date.")); else printf(_("Current branch %s is up to date.\n"), @@ -1750,7 +1765,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix) } else if (!(options.flags & REBASE_NO_QUIET)) ; /* be quiet */ else if (!strcmp(branch_name, "HEAD") && - resolve_ref_unsafe("HEAD", 0, NULL, &flag)) + refs_resolve_ref_unsafe(get_main_ref_store(the_repository), "HEAD", 0, NULL, &flag)) puts(_("HEAD is up to date, rebase forced.")); else printf(_("Current branch %s is up to date, rebase " @@ -1837,14 +1852,7 @@ run_rebase: cleanup: strbuf_release(&buf); strbuf_release(&revisions); - free(options.reflog_action); - free(options.head_name); - strvec_clear(&options.git_am_opts); - free(options.gpg_sign_opt); - string_list_clear(&options.exec, 0); - free(options.strategy); - string_list_clear(&options.strategy_opts, 0); - strbuf_release(&options.git_format_patch_opt); + rebase_options_release(&options); free(squash_onto_name); free(keep_base_onto_name); return !!ret; |
