@matheusbsbs / matheus-bagliano / commits / 767a9c417e
Fork 0

rebase -i: stop checking out the tip of the branch to rebase

One of the first things done when using a sequencer-based rebase (ie. `rebase -i', `rebase -r', or `rebase -m') is to make a todo list. This requires knowledge of the commit range to rebase. To get the oid of the last commit of the range, the tip of the branch to rebase is checked out with prepare_branch_to_be_rebased(), then the oid of the head is read. After this, the tip of the branch is not even modified. The `am' backend, on the other hand, does not check out the branch. On big repositories, it's a performance penalty: with `rebase -i', the user may have to wait before editing the todo list while git is extracting the branch silently, and "quiet" rebases will be slower than `am'. Since we already have the oid of the tip of the branch in `opts->orig_head', it's useless to switch to this commit. This removes the call to prepare_branch_to_be_rebased() in do_interactive_rebase(), and adds a `orig_head' parameter to get_revision_ranges(). prepare_branch_to_be_rebased() is removed as it is no longer used. This introduces a visible change: as we do not switch on the tip of the branch to rebase, no reflog entry is created at the beginning of the rebase for it. Unscientific performance measurements, performed on linux.git, are as follow: Before this patch: $ time git rebase -m --onto v4.18 463fa44eec2fef50~ 463fa44eec2fef50 real 0m8,940s user 0m6,830s sys 0m2,121s After this patch: $ time git rebase -m --onto v4.18 463fa44eec2fef50~ 463fa44eec2fef50 real 0m1,834s user 0m0,916s sys 0m0,206s Reported-by: SZEDER Gábor <szeder.dev@gmail.com> Signed-off-by: Alban Gruin <alban.gruin@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Alban Gruin committed Jan 24, 2020 at 16:05 UTC 767a9c417eb2109dda71995c8fb8a884d3a35e6f
3 files changed +5 -30
builtin/rebase.c
+5 -13
@@ -241,21 +241,17 @@ static int edit_todo_file(unsigned flags)
241 }
242
243 static int get_revision_ranges(struct commit *upstream, struct commit *onto,
244 - const char **head_hash,
244 + struct object_id *orig_head, const char **head_hash,
245 char **revisions, char **shortrevisions)
246 {
247 struct commit *base_rev = upstream ? upstream : onto;
248 const char *shorthead;
249 - struct object_id orig_head;
250 -
251 - if (get_oid("HEAD", &orig_head))
252 - return error(_("no HEAD?"));
249
254 - *head_hash = find_unique_abbrev(&orig_head, GIT_MAX_HEXSZ);
250 + *head_hash = find_unique_abbrev(orig_head, GIT_MAX_HEXSZ);
251 *revisions = xstrfmt("%s...%s", oid_to_hex(&base_rev->object.oid),
252 *head_hash);
253
258 - shorthead = find_unique_abbrev(&orig_head, DEFAULT_ABBREV);
254 + shorthead = find_unique_abbrev(orig_head, DEFAULT_ABBREV);
255
256 if (upstream) {
257 const char *shortrev;
@@ -309,12 +305,8 @@ static int do_interactive_rebase(struct rebase_options *opts, unsigned flags)
305 struct replay_opts replay = get_replay_opts(opts);
306 struct string_list commands = STRING_LIST_INIT_DUP;
307
312 - if (prepare_branch_to_be_rebased(the_repository, &replay,
313 - opts->switch_to))
314 - return -1;
315 -
316 - if (get_revision_ranges(opts->upstream, opts->onto, &head_hash,
317 - &revisions, &shortrevisions))
308 + if (get_revision_ranges(opts->upstream, opts->onto, &opts->orig_head,
309 + &head_hash, &revisions, &shortrevisions))
310 return -1;
311
312 if (init_basic_state(&replay,
sequencer.c
-14
@@ -3740,20 +3740,6 @@ static int run_git_checkout(struct repository *r, struct replay_opts *opts,
3740 return ret;
3741 }
3742
3743 -int prepare_branch_to_be_rebased(struct repository *r, struct replay_opts *opts,
3744 - const char *commit)
3745 -{
3746 - const char *action;
3747 -
3748 - if (commit && *commit) {
3749 - action = reflog_message(opts, "start", "checkout %s", commit);
3750 - if (run_git_checkout(r, opts, commit, action))
3751 - return error(_("could not checkout %s"), commit);
3752 - }
3753 -
3754 - return 0;
3755 -}
3756 -
3743 static int checkout_onto(struct repository *r, struct replay_opts *opts,
3744 const char *onto_name, const struct object_id *onto,
3745 const char *orig_head)
sequencer.h
-3
@@ -184,9 +184,6 @@ void commit_post_rewrite(struct repository *r,
184 const struct commit *current_head,
185 const struct object_id *new_head);
186
187 -int prepare_branch_to_be_rebased(struct repository *r, struct replay_opts *opts,
188 - const char *commit);
189 -
187 #define SUMMARY_INITIAL_COMMIT (1 << 0)
188 #define SUMMARY_SHOW_AUTHOR_DATE (1 << 1)
189 void print_commit_summary(struct repository *repo,