Skip to content

Commit 5620e55

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 5378808 commit 5620e55

File tree

4 files changed

+75
-22
lines changed

4 files changed

+75
-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: 22 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1189,26 +1189,27 @@ else
11891189
revisions=$onto...$orig_head
11901190
shortrevisions=$shorthead
11911191
fi
1192-
format=$(git config --get rebase.instructionFormat)
1193-
# the 'rev-list .. | sed' requires %m to parse; the instruction requires %H to parse
1194-
git rev-list $merges_option --format="%m%H ${format:-%s}" \
1195-
--reverse --left-right --topo-order \
1196-
$revisions ${restrict_revision+^$restrict_revision} | \
1197-
sed -n "s/^>//p" |
1198-
while read -r sha1 rest
1199-
do
1200-
1201-
if test -z "$keep_empty" && is_empty_commit $sha1 && ! is_merge_commit $sha1
1202-
then
1203-
comment_out="$comment_char "
1204-
else
1205-
comment_out=
1206-
fi
1192+
if test t != "$preserve_merges"
1193+
then
1194+
git rebase--helper --make-script ${keep_empty:+--keep-empty} \
1195+
$revisions ${restrict_revision+^$restrict_revision} > "$todo"
1196+
else
1197+
format=$(git config --get rebase.instructionFormat)
1198+
# the 'rev-list .. | sed' requires %m to parse; the instruction requires %H to parse
1199+
git rev-list $merges_option --format="%m%H ${format:-%s}" \
1200+
--reverse --left-right --topo-order \
1201+
$revisions ${restrict_revision+^$restrict_revision} | \
1202+
sed -n "s/^>//p" |
1203+
while read -r sha1 rest
1204+
do
1205+
1206+
if test -z "$keep_empty" && is_empty_commit $sha1 && ! is_merge_commit $sha1
1207+
then
1208+
comment_out="$comment_char "
1209+
else
1210+
comment_out=
1211+
fi
12071212

1208-
if test t != "$preserve_merges"
1209-
then
1210-
printf '%s\n' "${comment_out}pick $sha1 $rest" >>"$todo"
1211-
else
12121213
if test -z "$rebase_root"
12131214
then
12141215
preserve=t
@@ -1227,8 +1228,8 @@ do
12271228
touch "$rewritten"/$sha1
12281229
printf '%s\n' "${comment_out}pick $sha1 $rest" >>"$todo"
12291230
fi
1230-
fi
1231-
done
1231+
done
1232+
fi
12321233

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

sequencer.c

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

21832183
strbuf_release(&sob);
21842184
}
2185+
2186+
int sequencer_make_script(int keep_empty, FILE *out,
2187+
int argc, const char **argv)
2188+
{
2189+
char *format = "%s";
2190+
struct pretty_print_context pp = {0};
2191+
struct strbuf buf = STRBUF_INIT;
2192+
struct rev_info revs;
2193+
struct commit *commit;
2194+
2195+
init_revisions(&revs, NULL);
2196+
revs.verbose_header = 1;
2197+
revs.max_parents = 1;
2198+
revs.cherry_pick = 1;
2199+
revs.limited = 1;
2200+
revs.reverse = 1;
2201+
revs.right_only = 1;
2202+
revs.sort_order = REV_SORT_IN_GRAPH_ORDER;
2203+
revs.topo_order = 1;
2204+
2205+
revs.pretty_given = 1;
2206+
git_config_get_string("rebase.instructionFormat", &format);
2207+
get_commit_format(format, &revs);
2208+
pp.fmt = revs.commit_format;
2209+
pp.output_encoding = get_log_output_encoding();
2210+
2211+
if (setup_revisions(argc, argv, &revs, NULL) > 1)
2212+
return error("make_script: unhandled options");
2213+
2214+
if (prepare_revision_walk(&revs) < 0)
2215+
return error("make_script: error preparing revisions");
2216+
2217+
while ((commit = get_revision(&revs))) {
2218+
strbuf_reset(&buf);
2219+
if (!keep_empty && is_original_commit_empty(commit))
2220+
strbuf_addf(&buf, "%c ", comment_line_char);
2221+
strbuf_addf(&buf, "pick %s ", oid_to_hex(&commit->object.oid));
2222+
pretty_print_commit(&pp, commit, &buf);
2223+
strbuf_addch(&buf, '\n');
2224+
fputs(buf.buf, out);
2225+
}
2226+
strbuf_release(&buf);
2227+
return 0;
2228+
}

sequencer.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,8 @@ int sequencer_remove_state(struct replay_opts *opts);
4646

4747
int sequencer_commit(const char *defmsg, struct replay_opts *opts,
4848
int allow_empty, int edit, int amend);
49+
int sequencer_make_script(int keep_empty, FILE *out,
50+
int argc, const char **argv);
4951

5052
extern const char sign_off_header[];
5153

0 commit comments

Comments
 (0)