Skip to content

Commit ce5238a

Browse files
phillipwoodgitster
authored andcommitted
rebase --keep-base: imply --reapply-cherry-picks
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]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent d42c9ff commit ce5238a

File tree

3 files changed

+52
-11
lines changed

3 files changed

+52
-11
lines changed

Documentation/git-rebase.txt

Lines changed: 16 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -218,12 +218,14 @@ leave out at most one of A and B, in which case it defaults to HEAD.
218218
merge base of `<upstream>` and `<branch>`. Running
219219
`git rebase --keep-base <upstream> <branch>` is equivalent to
220220
running
221-
`git rebase --onto <upstream>...<branch> <upstream> <branch>`.
221+
`git rebase --reapply-cherry-picks --onto <upstream>...<branch> <upstream> <branch>`.
222222
+
223223
This option is useful in the case where one is developing a feature on
224224
top of an upstream branch. While the feature is being worked on, the
225225
upstream branch may advance and it may not be the best idea to keep
226-
rebasing on top of the upstream but to keep the base commit as-is.
226+
rebasing on top of the upstream but to keep the base commit as-is. As
227+
the base commit is unchanged this option implies `--reapply-cherry-picks`
228+
to avoid losing commits.
227229
+
228230
Although both this option and `--fork-point` find the merge base between
229231
`<upstream>` and `<branch>`, this option uses the merge base as the _starting
@@ -278,7 +280,8 @@ See also INCOMPATIBLE OPTIONS below.
278280
Note that commits which start empty are kept (unless `--no-keep-empty`
279281
is specified), and commits which are clean cherry-picks (as determined
280282
by `git log --cherry-mark ...`) are detected and dropped as a
281-
preliminary step (unless `--reapply-cherry-picks` is passed).
283+
preliminary step (unless `--reapply-cherry-picks` or `--keep-base` is
284+
passed).
282285
+
283286
See also INCOMPATIBLE OPTIONS below.
284287

@@ -311,13 +314,16 @@ See also INCOMPATIBLE OPTIONS below.
311314
upstream changes, the behavior towards them is controlled by
312315
the `--empty` flag.)
313316
+
314-
By default (or if `--no-reapply-cherry-picks` is given), these commits
315-
will be automatically dropped. Because this necessitates reading all
316-
upstream commits, this can be expensive in repos with a large number
317-
of upstream commits that need to be read. When using the 'merge'
318-
backend, warnings will be issued for each dropped commit (unless
319-
`--quiet` is given). Advice will also be issued unless
320-
`advice.skippedCherryPicks` is set to false (see linkgit:git-config[1]).
317+
318+
In the absence of `--keep-base` (or if `--no-reapply-cherry-picks` is
319+
given), these commits will be automatically dropped. Because this
320+
necessitates reading all upstream commits, this can be expensive in
321+
repositories with a large number of upstream commits that need to be
322+
read. When using the 'merge' backend, warnings will be issued for each
323+
dropped commit (unless `--quiet` is given). Advice will also be issued
324+
unless `advice.skippedCherryPicks` is set to false (see
325+
linkgit:git-config[1]).
326+
321327
+
322328
`--reapply-cherry-picks` allows rebase to forgo reading all upstream
323329
commits, potentially improving performance.

builtin/rebase.c

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1171,6 +1171,7 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
11711171
prepare_repo_settings(the_repository);
11721172
the_repository->settings.command_requires_full_index = 0;
11731173

1174+
options.reapply_cherry_picks = -1;
11741175
options.allow_empty_message = 1;
11751176
git_config(rebase_config, &options);
11761177
/* options.gpg_sign_opt will be either "-S" or NULL */
@@ -1230,6 +1231,12 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
12301231
if (options.root)
12311232
die(_("options '%s' and '%s' cannot be used together"), "--keep-base", "--root");
12321233
}
1234+
/*
1235+
* --keep-base defaults to --reapply-cherry-picks to avoid losing
1236+
* commits when using this option.
1237+
*/
1238+
if (options.reapply_cherry_picks < 0)
1239+
options.reapply_cherry_picks = keep_base;
12331240

12341241
if (options.root && options.fork_point > 0)
12351242
die(_("options '%s' and '%s' cannot be used together"), "--root", "--fork-point");
@@ -1406,7 +1413,11 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
14061413
if (options.empty != EMPTY_UNSPECIFIED)
14071414
imply_merge(&options, "--empty");
14081415

1409-
if (options.reapply_cherry_picks)
1416+
/*
1417+
* --keep-base implements --reapply-cherry-picks by altering upstream so
1418+
* it works with both backends.
1419+
*/
1420+
if (options.reapply_cherry_picks && !keep_base)
14101421
imply_merge(&options, "--reapply-cherry-picks");
14111422

14121423
if (gpg_sign)
@@ -1672,6 +1683,9 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
16721683
fill_branch_base(&options, &branch_base);
16731684
}
16741685

1686+
if (keep_base && options.reapply_cherry_picks)
1687+
options.upstream = options.onto;
1688+
16751689
if (options.fork_point > 0)
16761690
options.restrict_revision =
16771691
get_fork_point(options.upstream_name, options.orig_head);

t/t3416-rebase-onto-threedots.sh

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,27 @@ test_expect_success 'rebase --keep-base requires a single merge base' '
199199
grep "need exactly one merge base with branch" err
200200
'
201201

202+
test_expect_success 'rebase --keep-base keeps cherry picks' '
203+
git checkout -f -B main E &&
204+
git cherry-pick F &&
205+
(
206+
set_fake_editor &&
207+
EXPECT_COUNT=2 git rebase -i --keep-base HEAD G
208+
) &&
209+
test_cmp_rev HEAD G
210+
'
211+
212+
test_expect_success 'rebase --keep-base --no-reapply-cherry-picks' '
213+
git checkout -f -B main E &&
214+
git cherry-pick F &&
215+
(
216+
set_fake_editor &&
217+
EXPECT_COUNT=1 git rebase -i --keep-base \
218+
--no-reapply-cherry-picks HEAD G
219+
) &&
220+
test_cmp_rev HEAD^ C
221+
'
222+
202223
# This must be the last test in this file
203224
test_expect_success '$EDITOR and friends are unchanged' '
204225
test_editor_unchanged

0 commit comments

Comments
 (0)