diff options
-rw-r--r-- | builtin/rebase.c | 27 | ||||
-rwxr-xr-x | t/t3400-rebase.sh | 2 | ||||
-rwxr-xr-x | t/t3404-rebase-interactive.sh | 2 | ||||
-rwxr-xr-x | t/t3432-rebase-fast-forward.sh | 4 |
4 files changed, 23 insertions, 12 deletions
diff --git a/builtin/rebase.c b/builtin/rebase.c index 1ddad46126..1e1406c8ba 100644 --- a/builtin/rebase.c +++ b/builtin/rebase.c @@ -1260,8 +1260,8 @@ static int is_linear_history(struct commit *from, struct commit *to) return 1; } -static int can_fast_forward(struct commit *onto, struct object_id *head_oid, - struct object_id *merge_base) +static int can_fast_forward(struct commit *onto, struct commit *upstream, + struct object_id *head_oid, struct object_id *merge_base) { struct commit *head = lookup_commit(the_repository, head_oid); struct commit_list *merge_bases = NULL; @@ -1280,6 +1280,17 @@ static int can_fast_forward(struct commit *onto, struct object_id *head_oid, if (!oideq(merge_base, &onto->object.oid)) goto done; + if (!upstream) + goto done; + + free_commit_list(merge_bases); + merge_bases = get_merge_bases(upstream, head); + if (!merge_bases || merge_bases->next) + goto done; + + if (!oideq(&onto->object.oid, &merge_bases->item->object.oid)) + goto done; + res = 1; done: @@ -2027,13 +2038,13 @@ int cmd_rebase(int argc, const char **argv, const char *prefix) /* * Check if we are already based on onto with linear history, - * but this should be done only when upstream and onto are the same - * and if this is not an interactive rebase. + * in which case we could fast-forward without replacing the commits + * with new commits recreated by replaying their changes. This + * optimization must not be done if this is an interactive rebase. */ - if (can_fast_forward(options.onto, &options.orig_head, &merge_base) && - !is_interactive(&options) && !options.restrict_revision && - options.upstream && - !oidcmp(&options.upstream->object.oid, &options.onto->object.oid)) { + if (can_fast_forward(options.onto, options.upstream, &options.orig_head, + &merge_base) && + !is_interactive(&options) && !options.restrict_revision) { int flag; if (!(options.flags & REBASE_FORCE)) { diff --git a/t/t3400-rebase.sh b/t/t3400-rebase.sh index 80b23fd326..d7c724bea3 100755 --- a/t/t3400-rebase.sh +++ b/t/t3400-rebase.sh @@ -295,7 +295,7 @@ test_expect_success 'rebase --am and --show-current-patch' ' echo two >>init.t && git commit -a -m two && git tag two && - test_must_fail git rebase --onto init HEAD^ && + test_must_fail git rebase -f --onto init HEAD^ && GIT_TRACE=1 git rebase --show-current-patch >/dev/null 2>stderr && grep "show.*$(git rev-parse two)" stderr ) diff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh index 461dd539ff..3cc9052f10 100755 --- a/t/t3404-rebase-interactive.sh +++ b/t/t3404-rebase-interactive.sh @@ -1058,7 +1058,7 @@ test_expect_success C_LOCALE_OUTPUT 'rebase --edit-todo does not work on non-int git reset --hard && git checkout conflict-branch && set_fake_editor && - test_must_fail git rebase --onto HEAD~2 HEAD~ && + test_must_fail git rebase -f --onto HEAD~2 HEAD~ && test_must_fail git rebase --edit-todo && git rebase --abort ' diff --git a/t/t3432-rebase-fast-forward.sh b/t/t3432-rebase-fast-forward.sh index 58ecb33e08..35bc94142d 100755 --- a/t/t3432-rebase-fast-forward.sh +++ b/t/t3432-rebase-fast-forward.sh @@ -106,9 +106,9 @@ test_expect_success 'add work same to upstream' ' changes='our and their changes' test_rebase_same_head success noop same success noop-force diff --onto B B test_rebase_same_head success noop same success noop-force diff --onto B... B -test_rebase_same_head failure work same success work diff --onto master... master +test_rebase_same_head success noop same success work diff --onto master... master test_rebase_same_head failure work same success work diff --fork-point --onto B B test_rebase_same_head failure work same success work diff --fork-point --onto B... B -test_rebase_same_head failure work same success work diff --fork-point --onto master... master +test_rebase_same_head success noop same success work diff --fork-point --onto master... master test_done |