non-builtin rebase: use non-builtin interactive backend

We recently converted both the `git rebase` and the `git rebase -i`
command from Unix shell scripts to builtins.

The former has a safety valve allowing to fall back to the scripted
`rebase`, just in case that there is a bug in the builtin `rebase`:
setting the config variable `rebase.useBuiltin` to `false` will
fall back to using the scripted version.

The latter did not have such a safety hatch.

Let's reinstate the scripted interactive rebase backend so that `rebase.useBuiltin=false` will not use the builtin interactive rebase,
just in case that an end user runs into a bug with the builtin version
and needs to get out of the fix really quickly.

This is necessary because Git for Windows wants to ship the builtin
rebase/interactive rebase earlier than core Git: Git for Windows
v2.19.0 will come with the option of a drastically faster (if a lot
less battle-tested) `git rebase`/`git rebase -i`.

As the file name `git-rebase--interactive` is already in use, let's
rename the scripted backend to `git-legacy-rebase--interactive`.

A couple of additional touch-ups are needed (such as teaching the
builtin `rebase--interactive`, which assumed the role of the
`rebase--helper`, to perform the two tricks to skip the unnecessary
picks and to generate a new todo list) to make things work again.

Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de>
This commit is contained in:
Johannes Schindelin
2018-08-24 15:07:41 +02:00
parent a725f493d3
commit 254dd5356e
7 changed files with 42 additions and 46 deletions

1
.gitignore vendored
View File

@@ -83,6 +83,7 @@
/git-interpret-trailers
/git-instaweb
/git-legacy-rebase
/git-legacy-rebase--interactive
/git-legacy-stash
/git-log
/git-ls-files

View File

@@ -639,6 +639,7 @@ SCRIPT_SH += git-request-pull.sh
SCRIPT_SH += git-submodule.sh
SCRIPT_SH += git-web--browse.sh
SCRIPT_LIB += git-legacy-rebase--interactive
SCRIPT_LIB += git-mergetool--lib
SCRIPT_LIB += git-parse-remote
SCRIPT_LIB += git-rebase--am

View File

@@ -143,7 +143,8 @@ int cmd_rebase__interactive(int argc, const char **argv, const char *prefix)
char *raw_strategies = NULL;
enum {
NONE = 0, CONTINUE, SKIP, EDIT_TODO, SHOW_CURRENT_PATCH,
SHORTEN_OIDS, EXPAND_OIDS, CHECK_TODO_LIST, REARRANGE_SQUASH, ADD_EXEC
SHORTEN_OIDS, EXPAND_OIDS, CHECK_TODO_LIST, REARRANGE_SQUASH, ADD_EXEC,
MAKE_SCRIPT, SKIP_UNNECESSARY_PICKS,
} command = 0;
struct option options[] = {
OPT_BOOL(0, "ff", &opts.allow_ff, N_("allow fast-forward")),
@@ -196,6 +197,10 @@ int cmd_rebase__interactive(int argc, const char **argv, const char *prefix)
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_CMDMODE(0, "make-script", &command,
N_("make rebase script"), MAKE_SCRIPT),
OPT_CMDMODE(0, "skip-unnecessary-picks", &command,
N_("skip unnecessary picks"), SKIP_UNNECESSARY_PICKS),
OPT_END()
};
@@ -267,6 +272,18 @@ int cmd_rebase__interactive(int argc, const char **argv, const char *prefix)
case ADD_EXEC:
ret = sequencer_add_exec_commands(the_repository, cmd);
break;
case MAKE_SCRIPT:
ret = sequencer_make_script(the_repository,
stdout, argc, argv, flags);
break;
case SKIP_UNNECESSARY_PICKS: {
struct object_id oid;
ret = skip_unnecessary_picks(the_repository, &oid);
if (!ret)
printf("%s\n", oid_to_hex(&oid));
break;
}
default:
BUG("invalid command '%d'", command);
}

View File

@@ -95,11 +95,11 @@ git_sequence_editor () {
}
expand_todo_ids() {
git rebase--helper --expand-ids
git rebase--interactive --expand-ids
}
collapse_todo_ids() {
git rebase--helper --shorten-ids
git rebase--interactive --shorten-ids
}
# Switch to the branch in $into and notify it in the reflog
@@ -131,12 +131,12 @@ get_missing_commit_check_level () {
initiate_action () {
case "$1" in
continue)
exec git rebase--helper ${force_rebase:+--no-ff} $allow_empty_message \
exec git rebase--interactive ${force_rebase:+--no-ff} $allow_empty_message \
--continue
;;
skip)
git rerere clear
exec git rebase--helper ${force_rebase:+--no-ff} $allow_empty_message \
exec git rebase--interactive ${force_rebase:+--no-ff} $allow_empty_message \
--continue
;;
edit-todo)
@@ -207,8 +207,8 @@ init_revisions_and_shortrevisions () {
complete_action() {
test -s "$todo" || echo noop >> "$todo"
test -z "$autosquash" || git rebase--helper --rearrange-squash || exit
test -n "$cmd" && git rebase--helper --add-exec-commands "$cmd"
test -z "$autosquash" || git rebase--interactive --rearrange-squash || exit
test -n "$cmd" && git rebase--interactive --add-exec-commands --cmd "$cmd"
todocount=$(git stripspace --strip-comments <"$todo" | wc -l)
todocount=${todocount##* }
@@ -243,7 +243,7 @@ EOF
has_action "$todo" ||
return 2
git rebase--helper --check-todo-list || {
git rebase--interactive --check-todo-list || {
ret=$?
checkout_onto
exit $ret
@@ -252,12 +252,12 @@ EOF
expand_todo_ids
test -n "$force_rebase" ||
onto="$(git rebase--helper --skip-unnecessary-picks)" ||
onto="$(git rebase--interactive --skip-unnecessary-picks)" ||
die "Could not skip unnecessary pick commands"
checkout_onto
require_clean_work_tree "rebase"
exec git rebase--helper ${force_rebase:+--no-ff} $allow_empty_message \
exec git rebase--interactive ${force_rebase:+--no-ff} $allow_empty_message \
--continue
}
@@ -273,7 +273,7 @@ git_rebase__interactive () {
init_revisions_and_shortrevisions
git rebase--helper --make-script ${keep_empty:+--keep-empty} \
git rebase--interactive --make-script ${keep_empty:+--keep-empty} \
${rebase_merges:+--rebase-merges} \
${rebase_cousins:+--rebase-cousins} \
$revisions ${restrict_revision+^$restrict_revision} >"$todo" ||

View File

@@ -141,38 +141,6 @@ finish_rebase () {
rm -rf "$state_dir"
}
run_interactive () {
GIT_CHERRY_PICK_HELP="$resolvemsg"
export GIT_CHERRY_PICK_HELP
test -n "$keep_empty" && keep_empty="--keep-empty"
test -n "$rebase_merges" && rebase_merges="--rebase-merges"
test -n "$rebase_cousins" && rebase_cousins="--rebase-cousins"
test -n "$autosquash" && autosquash="--autosquash"
test -n "$verbose" && verbose="--verbose"
test -n "$force_rebase" && force_rebase="--no-ff"
test -n "$restrict_revision" && \
restrict_revision="--restrict-revision=^$restrict_revision"
test -n "$upstream" && upstream="--upstream=$upstream"
test -n "$onto" && onto="--onto=$onto"
test -n "$squash_onto" && squash_onto="--squash-onto=$squash_onto"
test -n "$onto_name" && onto_name="--onto-name=$onto_name"
test -n "$head_name" && head_name="--head-name=$head_name"
test -n "$strategy" && strategy="--strategy=$strategy"
test -n "$strategy_opts" && strategy_opts="--strategy-opts=$strategy_opts"
test -n "$switch_to" && switch_to="--switch-to=$switch_to"
test -n "$cmd" && cmd="--cmd=$cmd"
test -n "$action" && action="--$action"
exec git rebase--interactive "$action" "$keep_empty" "$rebase_merges" "$rebase_cousins" \
"$upstream" "$onto" "$squash_onto" "$restrict_revision" \
"$allow_empty_message" "$autosquash" "$verbose" \
"$force_rebase" "$onto_name" "$head_name" "$strategy" \
"$strategy_opts" "$cmd" "$switch_to" \
"$allow_rerere_autoupdate" "$gpg_sign_opt" "$signoff" \
"$reschedule_failed_exec"
}
run_specific_rebase () {
if [ "$interactive_rebase" = implied ]; then
GIT_SEQUENCE_EDITOR=:
@@ -182,7 +150,9 @@ run_specific_rebase () {
if test -n "$interactive_rebase" -a -z "$preserve_merges"
then
run_interactive
. git-legacy-rebase--$type
git_rebase__$type
else
. git-rebase--$type
@@ -202,7 +172,12 @@ run_specific_rebase () {
then
apply_autostash &&
rm -rf "$state_dir" &&
die "Nothing to do"
if test -n "$interactive_rebase" -a -z "$preserve_merges"
then
die "error: nothing to do"
else
die "Nothing to do"
fi
fi
exit $ret
}

View File

@@ -4793,7 +4793,7 @@ static int rewrite_file(const char *path, const char *buf, size_t len)
}
/* skip picking commits whose parents are unchanged */
static int skip_unnecessary_picks(struct repository *r, struct object_id *output_oid)
int skip_unnecessary_picks(struct repository *r, struct object_id *output_oid)
{
const char *todo_file = rebase_path_todo();
struct strbuf buf = STRBUF_INIT;

View File

@@ -144,3 +144,5 @@ int read_author_script(const char *path, char **name, char **email, char **date,
void parse_strategy_opts(struct replay_opts *opts, char *raw_opts);
int write_basic_state(struct replay_opts *opts, const char *head_name,
const char *onto, const char *orig_head);
int skip_unnecessary_picks(struct repository *r, struct object_id *output_oid);