Skip to content

Commit 66d92fe

Browse files
committed
rebase -i: generate the script via rebase--helper
This is substantially faster, improving the speedup relative to the shell script version of the interactive rebase from 2x to 3x on Windows. Signed-off-by: Johannes Schindelin <[email protected]>
1 parent aa3dfaa commit 66d92fe

File tree

4 files changed

+76
-22
lines changed

4 files changed

+76
-22
lines changed

builtin/rebase--helper.c

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,15 +11,19 @@ static const char * const builtin_rebase_helper_usage[] = {
1111
int cmd_rebase__helper(int argc, const char **argv, const char *prefix)
1212
{
1313
struct replay_opts opts = REPLAY_OPTS_INIT;
14+
int keep_empty = 0;
1415
enum {
15-
CONTINUE = 1, ABORT
16+
CONTINUE = 1, ABORT, MAKE_SCRIPT
1617
} command = 0;
1718
struct option options[] = {
1819
OPT_BOOL(0, "ff", &opts.allow_ff, N_("allow fast-forward")),
20+
OPT_BOOL(0, "keep-empty", &keep_empty, N_("keep empty commits")),
1921
OPT_CMDMODE(0, "continue", &command, N_("continue rebase"),
2022
CONTINUE),
2123
OPT_CMDMODE(0, "abort", &command, N_("abort rebase"),
2224
ABORT),
25+
OPT_CMDMODE(0, "make-script", &command,
26+
N_("make rebase script"), MAKE_SCRIPT),
2327
OPT_END()
2428
};
2529

@@ -36,5 +40,7 @@ int cmd_rebase__helper(int argc, const char **argv, const char *prefix)
3640
return !!sequencer_continue(&opts);
3741
if (command == ABORT && argc == 1)
3842
return !!sequencer_remove_state(&opts);
43+
if (command == MAKE_SCRIPT && argc > 1)
44+
return !!sequencer_make_script(keep_empty, stdout, argc, argv);
3945
usage_with_options(builtin_rebase_helper_usage, options);
4046
}

git-rebase--interactive.sh

Lines changed: 23 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -775,6 +775,7 @@ collapse_todo_ids() {
775775
# each log message will be re-retrieved in order to normalize the
776776
# autosquash arrangement
777777
rearrange_squash () {
778+
format=$(git config --get rebase.instructionFormat)
778779
# extract fixup!/squash! lines and resolve any referenced sha1's
779780
while read -r pick sha1 message
780781
do
@@ -1203,26 +1204,27 @@ else
12031204
revisions=$onto...$orig_head
12041205
shortrevisions=$shorthead
12051206
fi
1206-
format=$(git config --get rebase.instructionFormat)
1207-
# the 'rev-list .. | sed' requires %m to parse; the instruction requires %H to parse
1208-
git rev-list $merges_option --format="%m%H ${format:-%s}" \
1209-
--reverse --left-right --topo-order \
1210-
$revisions ${restrict_revision+^$restrict_revision} | \
1211-
sed -n "s/^>//p" |
1212-
while read -r sha1 rest
1213-
do
1214-
1215-
if test -z "$keep_empty" && is_empty_commit $sha1 && ! is_merge_commit $sha1
1216-
then
1217-
comment_out="$comment_char "
1218-
else
1219-
comment_out=
1220-
fi
1207+
if test t != "$preserve_merges"
1208+
then
1209+
git rebase--helper --make-script ${keep_empty:+--keep-empty} \
1210+
$revisions ${restrict_revision+^$restrict_revision} > "$todo"
1211+
else
1212+
format=$(git config --get rebase.instructionFormat)
1213+
# the 'rev-list .. | sed' requires %m to parse; the instruction requires %H to parse
1214+
git rev-list $merges_option --format="%m%H ${format:-%s}" \
1215+
--reverse --left-right --topo-order \
1216+
$revisions ${restrict_revision+^$restrict_revision} | \
1217+
sed -n "s/^>//p" |
1218+
while read -r sha1 rest
1219+
do
1220+
1221+
if test -z "$keep_empty" && is_empty_commit $sha1 && ! is_merge_commit $sha1
1222+
then
1223+
comment_out="$comment_char "
1224+
else
1225+
comment_out=
1226+
fi
12211227

1222-
if test t != "$preserve_merges"
1223-
then
1224-
printf '%s\n' "${comment_out}pick $sha1 $rest" >>"$todo"
1225-
else
12261228
if test -z "$rebase_root"
12271229
then
12281230
preserve=t
@@ -1241,8 +1243,8 @@ do
12411243
touch "$rewritten"/$sha1
12421244
printf '%s\n' "${comment_out}pick $sha1 $rest" >>"$todo"
12431245
fi
1244-
fi
1245-
done
1246+
done
1247+
fi
12461248

12471249
# Watch for commits that been dropped by --cherry-pick
12481250
if test t = "$preserve_merges"

sequencer.c

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2340,3 +2340,47 @@ void append_signoff(struct strbuf *msgbuf, int ignore_footer, unsigned flag)
23402340

23412341
strbuf_release(&sob);
23422342
}
2343+
2344+
int sequencer_make_script(int keep_empty, FILE *out,
2345+
int argc, const char **argv)
2346+
{
2347+
char *format = "%s";
2348+
struct pretty_print_context pp = {0};
2349+
struct strbuf buf = STRBUF_INIT;
2350+
struct rev_info revs;
2351+
struct commit *commit;
2352+
2353+
init_revisions(&revs, NULL);
2354+
revs.verbose_header = 1;
2355+
revs.max_parents = 1;
2356+
revs.cherry_pick = 1;
2357+
revs.limited = 1;
2358+
revs.reverse = 1;
2359+
revs.right_only = 1;
2360+
revs.sort_order = REV_SORT_IN_GRAPH_ORDER;
2361+
revs.topo_order = 1;
2362+
2363+
revs.pretty_given = 1;
2364+
git_config_get_string("rebase.instructionFormat", &format);
2365+
get_commit_format(format, &revs);
2366+
pp.fmt = revs.commit_format;
2367+
pp.output_encoding = get_log_output_encoding();
2368+
2369+
if (setup_revisions(argc, argv, &revs, NULL) > 1)
2370+
return error("make_script: unhandled options");
2371+
2372+
if (prepare_revision_walk(&revs) < 0)
2373+
return error("make_script: error preparing revisions");
2374+
2375+
while ((commit = get_revision(&revs))) {
2376+
strbuf_reset(&buf);
2377+
if (!keep_empty && is_original_commit_empty(commit))
2378+
strbuf_addf(&buf, "%c ", comment_line_char);
2379+
strbuf_addf(&buf, "pick %s ", oid_to_hex(&commit->object.oid));
2380+
pretty_print_commit(&pp, commit, &buf);
2381+
strbuf_addch(&buf, '\n');
2382+
fputs(buf.buf, out);
2383+
}
2384+
strbuf_release(&buf);
2385+
return 0;
2386+
}

sequencer.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,8 @@ int sequencer_remove_state(struct replay_opts *opts);
5858
int sequencer_commit(const char *defmsg, struct replay_opts *opts,
5959
int allow_empty, int edit, int amend,
6060
int cleanup_commit_message);
61+
int sequencer_make_script(int keep_empty, FILE *out,
62+
int argc, const char **argv);
6163

6264
extern const char sign_off_header[];
6365

0 commit comments

Comments
 (0)