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.schinde...@gmx.de>
> ---
>  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);
> 

Reply via email to