Skip to content

Commit

Permalink
rebase --keep-base: imply --reapply-cherry-picks
Browse files Browse the repository at this point in the history
As --keep-base does not rebase the branch it is confusing if it
removes commits that have been cherry-picked to the upstream branch.
As --reapply-cherry-picks is not supported by the "apply" backend this
commit ensures that cherry-picks are reapplied by forcing the upstream
commit to match the onto commit unless --no-reapply-cherry-picks is
given.

Reported-by: Philippe Blain <[email protected]>
Signed-off-by: Phillip Wood <[email protected]>
  • Loading branch information
phillipwood committed Sep 5, 2022
1 parent d8f4de2 commit 2cc3c82
Show file tree
Hide file tree
Showing 3 changed files with 52 additions and 11 deletions.
26 changes: 16 additions & 10 deletions Documentation/git-rebase.txt
Original file line number Diff line number Diff line change
Expand Up @@ -218,12 +218,14 @@ leave out at most one of A and B, in which case it defaults to HEAD.
merge base of `<upstream>` and `<branch>`. Running
`git rebase --keep-base <upstream> <branch>` is equivalent to
running
`git rebase --onto <upstream>...<branch> <upstream> <branch>`.
`git rebase --reapply-cherry-picks --onto <upstream>...<branch> <upstream> <branch>`.
+
This option is useful in the case where one is developing a feature on
top of an upstream branch. While the feature is being worked on, the
upstream branch may advance and it may not be the best idea to keep
rebasing on top of the upstream but to keep the base commit as-is.
rebasing on top of the upstream but to keep the base commit as-is. As
the base commit is unchanged this option implies `--reapply-cherry-picks`
to avoid losing commits.
+
Although both this option and `--fork-point` find the merge base between
`<upstream>` and `<branch>`, this option uses the merge base as the _starting
Expand Down Expand Up @@ -278,7 +280,8 @@ See also INCOMPATIBLE OPTIONS below.
Note that commits which start empty are kept (unless `--no-keep-empty`
is specified), and commits which are clean cherry-picks (as determined
by `git log --cherry-mark ...`) are detected and dropped as a
preliminary step (unless `--reapply-cherry-picks` is passed).
preliminary step (unless `--reapply-cherry-picks` or `--keep-base` is
passed).
+
See also INCOMPATIBLE OPTIONS below.

Expand Down Expand Up @@ -311,13 +314,16 @@ See also INCOMPATIBLE OPTIONS below.
upstream changes, the behavior towards them is controlled by
the `--empty` flag.)
+
By default (or if `--no-reapply-cherry-picks` is given), these commits
will be automatically dropped. Because this necessitates reading all
upstream commits, this can be expensive in repos with a large number
of upstream commits that need to be read. When using the 'merge'
backend, warnings will be issued for each dropped commit (unless
`--quiet` is given). Advice will also be issued unless
`advice.skippedCherryPicks` is set to false (see linkgit:git-config[1]).

In the absence of `--keep-base` (or if `--no-reapply-cherry-picks` is
given), these commits will be automatically dropped. Because this
necessitates reading all upstream commits, this can be expensive in
repos with a large number of upstream commits that need to be read.
When using the 'merge' backend, warnings will be issued for each
dropped commit (unless `--quiet` is given). Advice will also be issued
unless `advice.skippedCherryPicks` is set to false (see
linkgit:git-config[1]).

+
`--reapply-cherry-picks` allows rebase to forgo reading all upstream
commits, potentially improving performance.
Expand Down
16 changes: 15 additions & 1 deletion builtin/rebase.c
Original file line number Diff line number Diff line change
Expand Up @@ -1180,6 +1180,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
prepare_repo_settings(the_repository);
the_repository->settings.command_requires_full_index = 0;

options.reapply_cherry_picks = -1;
options.allow_empty_message = 1;
git_config(rebase_config, &options);
/* options.gpg_sign_opt will be either "-S" or NULL */
Expand Down Expand Up @@ -1239,6 +1240,12 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
if (options.root)
die(_("options '%s' and '%s' cannot be used together"), "--keep-base", "--root");
}
/*
* --keep-base defaults to --reapply-cherry-picks as it is confusing if
* commits disappear when using this option.
*/
if (options.reapply_cherry_picks < 0)
options.reapply_cherry_picks = keep_base;

if (options.root && options.fork_point > 0)
die(_("options '%s' and '%s' cannot be used together"), "--root", "--fork-point");
Expand Down Expand Up @@ -1415,7 +1422,11 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
if (options.empty != EMPTY_UNSPECIFIED)
imply_merge(&options, "--empty");

if (options.reapply_cherry_picks)
/*
* --keep-base implements --reapply-cherry-picks by altering upstream so
* it works with both backends.
*/
if (options.reapply_cherry_picks && !keep_base)
imply_merge(&options, "--reapply-cherry-picks");

if (gpg_sign)
Expand Down Expand Up @@ -1678,6 +1689,9 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
options.onto_name);
fill_branch_base(&options, &branch_base);
}
if (keep_base && options.reapply_cherry_picks)
options.upstream = options.onto;

if (options.fork_point > 0)
options.restrict_revision =
get_fork_point(options.upstream_name, options.orig_head);
Expand Down
21 changes: 21 additions & 0 deletions t/t3416-rebase-onto-threedots.sh
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,27 @@ test_expect_success 'rebase --keep-base requires a single merge base' '
grep "need exactly one merge base with branch" err
'

test_expect_success 'rebase --keep-base keeps cherry picks' '
git checkout -f -B main E &&
git cherry-pick F &&
(
set_fake_editor &&
EXPECT_COUNT=2 git rebase -i --keep-base HEAD G
) &&
test_cmp_rev HEAD G
'

test_expect_success 'rebase --keep-base --no-reapply-cherry-picks' '
git checkout -f -B main E &&
git cherry-pick F &&
(
set_fake_editor &&
EXPECT_COUNT=1 git rebase -i --keep-base \
--no-reapply-cherry-picks HEAD G
) &&
test_cmp_rev HEAD^ C
'

# This must be the last test in this file
test_expect_success '$EDITOR and friends are unchanged' '
test_editor_unchanged
Expand Down

0 comments on commit 2cc3c82

Please sign in to comment.