This patch series reimplements the expensive pre- and post-processing of the todo script in C. And it concludes the work I did to accelerate rebase -i. Changes since v2: - rearranged error_errno() calls to come before any subsequent free() and close() - now call close(fd) in case of error to avoid resource leaks - removed unused `format` variable holding the value of rebase.instructionFormat from rearrange_squash() - modified rearrange_squash() to make it easier to reason about subjects[i] taking custody of a strbuf's buffer (this should enable Coverity to see that there is no resource leak here) Johannes Schindelin (9): rebase -i: generate the script via rebase--helper rebase -i: remove useless indentation rebase -i: do not invent onelines when expanding/collapsing SHA-1s rebase -i: also expand/collapse the SHA-1s via the rebase--helper t3404: relax rebase.missingCommitsCheck tests rebase -i: check for missing commits in the rebase--helper rebase -i: skip unnecessary picks using the rebase--helper t3415: test fixup with wrapped oneline rebase -i: rearrange fixup/squash lines using the rebase--helper Documentation/git-rebase.txt | 16 +- builtin/rebase--helper.c | 29 ++- git-rebase--interactive.sh | 362 ++++------------------------ sequencer.c | 531 ++++++++++++++++++++++++++++++++++++++++++ sequencer.h | 8 + t/t3404-rebase-interactive.sh | 22 +- t/t3415-rebase-autosquash.sh | 16 +- 7 files changed, 641 insertions(+), 343 deletions(-) base-commit: e2cb6ab84c94f147f1259260961513b40c36108a Based-On: rebase--helper at https://github.com/dscho/git Fetch-Base-Via: git fetch https://github.com/dscho/git rebase--helper Published-As: https://github.com/dscho/git/releases/tag/rebase-i-extra-v3 Fetch-It-Via: git fetch https://github.com/dscho/git rebase-i-extra-v3 Interdiff vs v2: diff --git a/sequencer.c b/sequencer.c index 2b07fb9e0ce..7ac1792311e 100644 --- a/sequencer.c +++ b/sequencer.c @@ -2393,7 +2393,7 @@ void append_signoff(struct strbuf *msgbuf, int ignore_footer, unsigned flag) int sequencer_make_script(int keep_empty, FILE *out, int argc, const char **argv) { - char *format = "%s"; + char *format = xstrdup("%s"); struct pretty_print_context pp = {0}; struct strbuf buf = STRBUF_INIT; struct rev_info revs; @@ -2412,6 +2412,7 @@ int sequencer_make_script(int keep_empty, FILE *out, revs.pretty_given = 1; git_config_get_string("rebase.instructionFormat", &format); get_commit_format(format, &revs); + free(format); pp.fmt = revs.commit_format; pp.output_encoding = get_log_output_encoding(); @@ -2676,24 +2677,41 @@ int skip_unnecessary_picks(void) const char *done_path = rebase_path_done(); fd = open(done_path, O_CREAT | O_WRONLY | O_APPEND, 0666); + if (fd < 0) { + error_errno(_("could not open '%s' for writing"), + done_path); + todo_list_release(&todo_list); + return -1; + } if (write_in_full(fd, todo_list.buf.buf, offset) < 0) { + error_errno(_("could not write to '%s'"), done_path); todo_list_release(&todo_list); - return error_errno(_("could not write to '%s'"), - done_path); + close(fd); + return -1; } close(fd); fd = open(rebase_path_todo(), O_WRONLY, 0666); + if (fd < 0) { + error_errno(_("could not open '%s' for writing"), + rebase_path_todo()); + todo_list_release(&todo_list); + return -1; + } if (write_in_full(fd, todo_list.buf.buf + offset, todo_list.buf.len - offset) < 0) { + error_errno(_("could not write to '%s'"), + rebase_path_todo()); + close(fd); todo_list_release(&todo_list); - return error_errno(_("could not write to '%s'"), - rebase_path_todo()); + return -1; } if (ftruncate(fd, todo_list.buf.len - offset) < 0) { + error_errno(_("could not truncate '%s'"), + rebase_path_todo()); todo_list_release(&todo_list); - return error_errno(_("could not truncate '%s'"), - rebase_path_todo()); + close(fd); + return -1; } close(fd); @@ -2768,6 +2786,7 @@ int rearrange_squash(void) struct strbuf buf = STRBUF_INIT; struct todo_item *item = todo_list.items + i; const char *commit_buffer, *subject, *p; + size_t subject_len; int i2 = -1; struct subject2item_entry *entry; @@ -2788,7 +2807,7 @@ int rearrange_squash(void) commit_buffer = get_commit_buffer(item->commit, NULL); find_commit_subject(commit_buffer, &subject); format_subject(&buf, subject, " "); - subject = subjects[i] = buf.buf; + subject = subjects[i] = strbuf_detach(&buf, &subject_len); unuse_commit_buffer(item->commit, commit_buffer); if ((skip_prefix(subject, "fixup! ", &p) || skip_prefix(subject, "squash! ", &p))) { @@ -2835,19 +2854,16 @@ int rearrange_squash(void) tail[i2] = i; } else if (!hashmap_get_from_hash(&subject2item, strhash(subject), subject)) { - FLEX_ALLOC_MEM(entry, subject, buf.buf, buf.len); + FLEX_ALLOC_MEM(entry, subject, subject, subject_len); entry->i = i; hashmap_entry_init(entry, strhash(entry->subject)); hashmap_put(&subject2item, entry); } - strbuf_detach(&buf, NULL); } if (rearranged) { struct strbuf buf = STRBUF_INIT; - char *format = NULL; - git_config_get_string("rebase.instructionFormat", &format); for (i = 0; i < todo_list.nr; i++) { enum todo_command command = todo_list.items[i].command; int cur = i; -- 2.12.2.windows.2.406.gd14a8f8640f