+
Skip to content

rebase: offer to reschedule failed exec commands automatically #90

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions Documentation/config/rebase.txt
Original file line number Diff line number Diff line change
Expand Up @@ -64,3 +64,8 @@ instead of:
-------------------------------------------
+
Defaults to false.

rebase.rescheduleFailedExec::
Automatically reschedule `exec` commands that failed. This only makes
sense in interactive mode (or when an `--exec` option was provided).
This is the same as specifying the `--reschedule-failed-exec` option.
11 changes: 11 additions & 0 deletions Documentation/git-rebase.txt
Original file line number Diff line number Diff line change
Expand Up @@ -462,6 +462,12 @@ without an explicit `--interactive`.
+
See also INCOMPATIBLE OPTIONS below.

-y <cmd>::
This is the same as passing `--reschedule-failed-exec` before
`-x <cmd>`, i.e. it appends the specified `exec` command and
turns on the mode where failed `exec` commands are automatically
rescheduled.

--root::
Rebase all commits reachable from <branch>, instead of
limiting them with an <upstream>. This allows you to rebase
Expand Down Expand Up @@ -501,6 +507,11 @@ See also INCOMPATIBLE OPTIONS below.
with care: the final stash application after a successful
rebase might result in non-trivial conflicts.

--reschedule-failed-exec::
--no-reschedule-failed-exec::
Automatically reschedule `exec` commands that failed. This only makes
sense in interactive mode (or when an `--exec` option was provided).

INCOMPATIBLE OPTIONS
--------------------

Expand Down
2 changes: 2 additions & 0 deletions builtin/rebase--interactive.c
Original file line number Diff line number Diff line change
Expand Up @@ -192,6 +192,8 @@ int cmd_rebase__interactive(int argc, const char **argv, const char *prefix)
OPT_STRING(0, "onto-name", &onto_name, N_("onto-name"), N_("onto name")),
OPT_STRING(0, "cmd", &cmd, N_("cmd"), N_("the command to run")),
OPT_RERERE_AUTOUPDATE(&opts.allow_rerere_auto),
OPT_BOOL(0, "reschedule-failed-exec", &opts.reschedule_failed_exec,
N_("automatically re-schedule any `exec` that fails")),
OPT_END()
};

Expand Down
42 changes: 41 additions & 1 deletion builtin/rebase.c
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ struct rebase_options {
int rebase_merges, rebase_cousins;
char *strategy, *strategy_opts;
struct strbuf git_format_patch_opt;
int reschedule_failed_exec;
};

static int is_interactive(struct rebase_options *opts)
Expand Down Expand Up @@ -415,6 +416,8 @@ static int run_specific_rebase(struct rebase_options *opts)
argv_array_push(&child.args, opts->gpg_sign_opt);
if (opts->signoff)
argv_array_push(&child.args, "--signoff");
if (opts->reschedule_failed_exec)
argv_array_push(&child.args, "--reschedule-failed-exec");

status = run_command(&child);
goto finished_rebase;
Expand Down Expand Up @@ -674,6 +677,11 @@ static int rebase_config(const char *var, const char *value, void *data)
return 0;
}

if (!strcmp(var, "rebase.reschedulefailedexec")) {
opts->reschedule_failed_exec = git_config_bool(var, value);
return 0;
}

return git_default_config(var, value, data);
}

Expand Down Expand Up @@ -746,6 +754,23 @@ static int parse_opt_interactive(const struct option *opt, const char *arg,
return 0;
}

struct opt_y {
struct string_list *list;
struct rebase_options *options;
};

static int parse_opt_y(const struct option *opt, const char *arg, int unset)
{
struct opt_y *o = opt->value;

if (unset || !arg)
return -1;

o->options->reschedule_failed_exec = 1;
string_list_append(o->list, arg);
return 0;
}

static void NORETURN error_on_missing_default_upstream(void)
{
struct branch *current_branch = branch_get(NULL);
Expand Down Expand Up @@ -826,6 +851,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
struct string_list strategy_options = STRING_LIST_INIT_NODUP;
struct object_id squash_onto;
char *squash_onto_name = NULL;
struct opt_y opt_y = { .list = &exec, .options = &options };
struct option builtin_rebase_options[] = {
OPT_STRING(0, "onto", &options.onto_name,
N_("revision"),
Expand Down Expand Up @@ -903,6 +929,9 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
OPT_STRING_LIST('x', "exec", &exec, N_("exec"),
N_("add exec lines after each commit of the "
"editable list")),
{ OPTION_CALLBACK, 'y', NULL, &opt_y, N_("<cmd>"),
N_("same as --reschedule-failed-exec -x <cmd>"),
PARSE_OPT_NONEG, parse_opt_y },
OPT_BOOL(0, "allow-empty-message",
&options.allow_empty_message,
N_("allow rebasing commits with empty messages")),
Expand All @@ -920,6 +949,9 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
"strategy")),
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,
N_("automatically re-schedule any `exec` that fails")),
OPT_END(),
};
int i;
Expand Down Expand Up @@ -1216,6 +1248,9 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
break;
}

if (options.reschedule_failed_exec && !is_interactive(&options))
die(_("--reschedule-failed-exec requires an interactive rebase"));

if (options.git_am_opts.argc) {
/* all am options except -q are compatible only with --am */
for (i = options.git_am_opts.argc - 1; i >= 0; i--)
Expand All @@ -1241,7 +1276,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
options.flags |= REBASE_FORCE;
}

if (options.type == REBASE_PRESERVE_MERGES)
if (options.type == REBASE_PRESERVE_MERGES) {
/*
* Note: incompatibility with --signoff handled in signoff block above
* Note: incompatibility with --interactive is just a strong warning;
Expand All @@ -1251,6 +1286,11 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
die(_("error: cannot combine '--preserve-merges' with "
"'--rebase-merges'"));

if (options.reschedule_failed_exec)
die(_("error: cannot combine '--preserve-merges' with "
"'--reschedule-failed-exec'"));
}

if (options.rebase_merges) {
if (strategy_options.nr)
die(_("error: cannot combine '--rebase-merges' with "
Expand Down
27 changes: 26 additions & 1 deletion git-legacy-rebase.sh
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ f,force-rebase! cherry-pick all commits, even if unchanged
m,merge! use merging strategies to rebase
i,interactive! let the user edit the list of commits to rebase
x,exec=! add exec lines after each commit of the editable list
y=! same as --reschedule-failed-exec -x
k,keep-empty preserve empty commits during rebase
allow-empty-message allow rebasing commits with empty messages
stat! display a diffstat of what changed upstream
Expand All @@ -48,6 +49,7 @@ skip! skip current patch and continue
edit-todo! edit the todo list during an interactive rebase
quit! abort but keep HEAD where it is
show-current-patch! show the patch file being applied or merged
reschedule-failed-exec automatically reschedule failed exec commands
"
. git-sh-setup
set_reflog_action rebase
Expand Down Expand Up @@ -92,11 +94,14 @@ autosquash=
keep_empty=
allow_empty_message=--allow-empty-message
signoff=
reschedule_failed_exec=
test "$(git config --bool rebase.autosquash)" = "true" && autosquash=t
case "$(git config --bool commit.gpgsign)" in
true) gpg_sign_opt=-S ;;
*) gpg_sign_opt= ;;
esac
test "$(git config --bool rebase.reschedulefailedexec)" = "true" &&
reschedule_failed_exec=--reschedule-failed-exec
. git-rebase--common

read_basic_state () {
Expand Down Expand Up @@ -126,6 +131,8 @@ read_basic_state () {
signoff="$(cat "$state_dir"/signoff)"
force_rebase=t
}
test -f "$state_dir"/reschedule-failed-exec &&
reschedule_failed_exec=t
}

finish_rebase () {
Expand Down Expand Up @@ -163,7 +170,8 @@ run_interactive () {
"$allow_empty_message" "$autosquash" "$verbose" \
"$force_rebase" "$onto_name" "$head_name" "$strategy" \
"$strategy_opts" "$cmd" "$switch_to" \
"$allow_rerere_autoupdate" "$gpg_sign_opt" "$signoff"
"$allow_rerere_autoupdate" "$gpg_sign_opt" "$signoff" \
"$reschedule_failed_exec"
}

run_specific_rebase () {
Expand Down Expand Up @@ -255,6 +263,11 @@ do
cmd="${cmd}exec ${1#--exec=}${LF}"
test -z "$interactive_rebase" && interactive_rebase=implied
;;
-y*)
reschedule_failed_exec=--reschedule-failed-exec
cmd="${cmd}exec ${1#-y}${LF}"
test -z "$interactive_rebase" && interactive_rebase=implied
;;
--interactive)
interactive_rebase=explicit
;;
Expand Down Expand Up @@ -378,6 +391,12 @@ do
--gpg-sign=*)
gpg_sign_opt="-S${1#--gpg-sign=}"
;;
--reschedule-failed-exec)
reschedule_failed_exec=--reschedule-failed-exec
;;
--no-reschedule-failed-exec)
reschedule_failed_exec=
;;
--)
shift
break
Expand Down Expand Up @@ -534,8 +553,14 @@ then
# git-rebase.txt caveats with "unless you know what you are doing"
test -n "$rebase_merges" &&
die "$(gettext "error: cannot combine '--preserve-merges' with '--rebase-merges'")"

test -z "$reschedule_failed_exec" ||
die "$(gettext "error: cannot combine '--preserve-merges' with '--reschedule-failed-exec'")"
fi

test -z "$reschedule_failed_exec" || test -n "$interactive_rebase" ||
die "$(gettext "error: --reschedule-failed-exec requires an interactive rebase")"

if test -n "$rebase_merges"
then
test -n "$strategy_opts" &&
Expand Down
1 change: 1 addition & 0 deletions git-rebase--common.sh
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ write_basic_state () {
"$state_dir"/allow_rerere_autoupdate
test -n "$gpg_sign_opt" && echo "$gpg_sign_opt" > "$state_dir"/gpg_sign_opt
test -n "$signoff" && echo "$signoff" >"$state_dir"/signoff
test -n "$reschedule_failed_exec" && : > "$state_dir"/reschedule-failed-exec
}

apply_autostash () {
Expand Down
13 changes: 10 additions & 3 deletions sequencer.c
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,7 @@ static GIT_PATH_FUNC(rebase_path_strategy, "rebase-merge/strategy")
static GIT_PATH_FUNC(rebase_path_strategy_opts, "rebase-merge/strategy_opts")
static GIT_PATH_FUNC(rebase_path_allow_rerere_autoupdate, "rebase-merge/allow_rerere_autoupdate")
static GIT_PATH_FUNC(rebase_path_quiet, "rebase-merge/quiet")
static GIT_PATH_FUNC(rebase_path_reschedule_failed_exec, "rebase-merge/reschedule-failed-exec")

static int git_sequencer_config(const char *k, const char *v, void *cb)
{
Expand Down Expand Up @@ -2362,6 +2363,9 @@ static int read_populate_opts(struct replay_opts *opts)
opts->signoff = 1;
}

if (file_exists(rebase_path_reschedule_failed_exec()))
opts->reschedule_failed_exec = 1;

read_strategy_opts(opts, &buf);
strbuf_release(&buf);

Expand Down Expand Up @@ -2443,6 +2447,8 @@ int write_basic_state(struct replay_opts *opts, const char *head_name,
write_file(rebase_path_gpg_sign_opt(), "-S%s\n", opts->gpg_sign);
if (opts->signoff)
write_file(rebase_path_signoff(), "--signoff\n");
if (opts->reschedule_failed_exec)
write_file(rebase_path_reschedule_failed_exec(), "%s", "");

return 0;
}
Expand Down Expand Up @@ -3586,9 +3592,10 @@ static int pick_commits(struct todo_list *todo_list, struct replay_opts *opts)
*end_of_arg = saved;

/* Reread the todo file if it has changed. */
if (res)
; /* fall through */
else if (stat(get_todo_path(opts), &st))
if (res) {
if (opts->reschedule_failed_exec)
reschedule = 1;
} else if (stat(get_todo_path(opts), &st))
res = error_errno(_("could not stat '%s'"),
get_todo_path(opts));
else if (match_stat_data(&todo_list->stat, &st)) {
Expand Down
1 change: 1 addition & 0 deletions sequencer.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ struct replay_opts {
int allow_empty_message;
int keep_redundant_commits;
int verbose;
int reschedule_failed_exec;

int mainline;

Expand Down
14 changes: 14 additions & 0 deletions t/t3418-rebase-continue.sh
Original file line number Diff line number Diff line change
Expand Up @@ -254,4 +254,18 @@ test_expect_success 'the todo command "break" works' '
test_path_is_file execed
'

test_expect_success '--reschedule-failed-exec' '
test_when_finished "git rebase --abort" &&
test_must_fail git rebase -x false --reschedule-failed-exec HEAD^ &&
grep "^exec false" .git/rebase-merge/git-rebase-todo &&
git rebase --abort &&
test_must_fail git -c rebase.rescheduleFailedExec=true \
rebase -x false HEAD^ 2>err &&
grep "^exec false" .git/rebase-merge/git-rebase-todo &&
test_i18ngrep "has been rescheduled" err &&
git rebase --abort &&
test_must_fail git rebase -y false HEAD^ 2>err &&
test_i18ngrep "has been rescheduled" err
'

test_done
点击 这是indexloc提供的php浏览器服务,不要输入任何密码和下载