On 26/04/17 12:59, Johannes Schindelin wrote: > The first step of an interactive rebase is to generate the so-called "todo > script", to be stored in the state directory as "git-rebase-todo" and to > be edited by the user. > > Originally, we adjusted the output of `git log <options>` using a simple > sed script. Over the course of the years, the code became more > complicated. We now use shell scripting to edit the output of `git log` > conditionally, depending whether to keep "empty" commits (i.e. commits > that do not change any files). > > On platforms where shell scripting is not native, this can be a serious > drag. And it opens the door for incompatibilities between platforms when > it comes to shell scripting or to Unix-y commands. > > Let's just re-implement the todo script generation in plain C, using the > revision machinery directly. > > This is substantially faster, improving the speed relative to the > shell script version of the interactive rebase from 2x to 3x on Windows. > > Note that the rearrange_squash() function in git-rebase--interactive > relied on the fact that we set the "format" variable to the config setting > rebase.instructionFormat. Relying on a side effect like this is no good, > hence we explicitly perform that assignment (possibly again) in > rearrange_squash(). > > Signed-off-by: Johannes Schindelin <johannes.schindelin@xxxxxx> > --- > builtin/rebase--helper.c | 8 +++++++- > git-rebase--interactive.sh | 44 +++++++++++++++++++++++--------------------- > sequencer.c | 45 +++++++++++++++++++++++++++++++++++++++++++++ > sequencer.h | 3 +++ > 4 files changed, 78 insertions(+), 22 deletions(-) > > diff --git a/sequencer.c b/sequencer.c > index 77afecaebf0..e858a976279 100644 > --- a/sequencer.c > +++ b/sequencer.c > @@ -2388,3 +2388,48 @@ void append_signoff(struct strbuf *msgbuf, int ignore_footer, unsigned flag) > > strbuf_release(&sob); > } > + > +int sequencer_make_script(int keep_empty, FILE *out, > + int argc, const char **argv) > +{ > + char *format = xstrdup("%s"); > + struct pretty_print_context pp = {0}; > + struct strbuf buf = STRBUF_INIT; > + struct rev_info revs; > + struct commit *commit; > + > + init_revisions(&revs, NULL); > + revs.verbose_header = 1; > + revs.max_parents = 1; > + revs.cherry_pick = 1; > + revs.limited = 1; > + revs.reverse = 1; > + revs.right_only = 1; > + revs.sort_order = REV_SORT_IN_GRAPH_ORDER; > + revs.topo_order = 1; > + > + revs.pretty_given = 1; > + git_config_get_string("rebase.instructionFormat", &format); Firstly thanks for all your work on speeding up rebase -i, it definitely feels faster. This changes the behaviour of git -c rebase.instructionFormat= rebase -i The shell version treats the rebase.instructionFormat being unset or set to the empty string as equivalent. This version generates a todo list with lines like 'pick <abbrev sha1>' rather than 'pick <abbrev sha1> <subject>' I only picked this up because I have a script that does 'git -c rebase.instructionFormat= rebase -i' with a custom sequence editor. I can easily add '%s' in the appropriate place but I thought I'd point it out in case other people are affected by the change. Please CC me in any replies as I'm not subscribed to this list Best Wishes Phillip > + get_commit_format(format, &revs); > + free(format); > + pp.fmt = revs.commit_format; > + pp.output_encoding = get_log_output_encoding(); > + > + if (setup_revisions(argc, argv, &revs, NULL) > 1) > + return error(_("make_script: unhandled options")); > + > + if (prepare_revision_walk(&revs) < 0) > + return error(_("make_script: error preparing revisions")); > + > + while ((commit = get_revision(&revs))) { > + strbuf_reset(&buf); > + if (!keep_empty && is_original_commit_empty(commit)) > + strbuf_addf(&buf, "%c ", comment_line_char); > + strbuf_addf(&buf, "pick %s ", oid_to_hex(&commit->object.oid)); > + pretty_print_commit(&pp, commit, &buf); > + strbuf_addch(&buf, '\n'); > + fputs(buf.buf, out); > + } > + strbuf_release(&buf); > + return 0; > +} > diff --git a/sequencer.h b/sequencer.h > index f885b68395f..83f2943b7a9 100644 > --- a/sequencer.h > +++ b/sequencer.h > @@ -45,6 +45,9 @@ int sequencer_continue(struct replay_opts *opts); > int sequencer_rollback(struct replay_opts *opts); > int sequencer_remove_state(struct replay_opts *opts); > > +int sequencer_make_script(int keep_empty, FILE *out, > + int argc, const char **argv); > + > extern const char sign_off_header[]; > > void append_signoff(struct strbuf *msgbuf, int ignore_footer, unsigned flag); >