git/t/t3432-rebase-fast-forward.sh

115 lines
3.7 KiB
Bash
Raw Normal View History

#!/bin/sh
#
# Copyright (c) 2019 Denton Liu
#
test_description='ensure rebase fast-forwards commits when possible'
. ./test-lib.sh
test_expect_success setup '
test_commit A &&
test_commit B &&
test_commit C &&
test_commit D &&
git checkout -t -b side
'
test_rebase_same_head () {
status_n="$1" &&
shift &&
what_n="$1" &&
shift &&
cmp_n="$1" &&
shift &&
status_f="$1" &&
shift &&
what_f="$1" &&
shift &&
cmp_f="$1" &&
shift &&
test_rebase_same_head_ $status_n $what_n $cmp_n "" "$*" &&
test_rebase_same_head_ $status_f $what_f $cmp_f " --no-ff" "$*"
}
test_rebase_same_head_ () {
status="$1" &&
shift &&
what="$1" &&
shift &&
cmp="$1" &&
shift &&
flag="$1"
shift &&
test_expect_$status "git rebase$flag $* with $changes is $what with $cmp HEAD" "
oldhead=\$(git rev-parse HEAD) &&
test_when_finished 'git reset --hard \$oldhead' &&
git rebase$flag $* >stdout &&
if test $what = work
then
# Must check this case first, for 'is up to
# date, rebase forced[...]rewinding head' cases
test_i18ngrep 'rewinding head' stdout
elif test $what = noop
then
test_i18ngrep 'is up to date' stdout &&
test_i18ngrep ! 'rebase forced' stdout
elif test $what = noop-force
then
test_i18ngrep 'is up to date, rebase forced' stdout
fi &&
newhead=\$(git rev-parse HEAD) &&
if test $cmp = same
then
test_cmp_rev \$oldhead \$newhead
elif test $cmp = diff
then
! test_cmp_rev \$oldhead \$newhead
fi
"
}
changes='no changes'
test_rebase_same_head success work same success work same
test_rebase_same_head success noop same success noop-force same master
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 success noop same success noop-force same --onto master... master
test_rebase_same_head success noop same success noop-force same --no-fork-point
test_rebase_same_head success work same success work same --fork-point master
test_rebase_same_head failure noop 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 success work same success work same --fork-point --onto master... master
test_expect_success 'add work same to side' '
test_commit E
'
changes='our changes'
test_rebase_same_head success work same success work same
test_rebase_same_head success noop same success noop-force same master
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 success noop same success noop-force same --onto master... master
test_rebase_same_head success noop same success noop-force same --no-fork-point
test_rebase_same_head success work same success work same --fork-point 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 success work same success work same --fork-point --onto master... master
test_expect_success 'add work same to upstream' '
git checkout master &&
test_commit F &&
git checkout side
'
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
rebase: fast-forward --onto in more cases Before, when we had the following graph, A---B---C (master) \ D (side) running 'git rebase --onto master... master side' would result in D being always rebased, no matter what. However, the desired behavior is that rebase should notice that this is fast-forwardable and do that instead. Add detection to `can_fast_forward` so that this case can be detected and a fast-forward will be performed. First of all, rewrite the function to use gotos which simplifies the logic. Next, since the options.upstream && !oidcmp(&options.upstream->object.oid, &options.onto->object.oid) conditions were removed in `cmd_rebase`, we reintroduce a substitute in `can_fast_forward`. In particular, checking the merge bases of `upstream` and `head` fixes a failing case in t3416. The abbreviated graph for t3416 is as follows: F---G topic / A---B---C---D---E master and the failing command was git rebase --onto master...topic F topic Before, Git would see that there was one merge base (C), and the merge and onto were the same so it would incorrectly return 1, indicating that we could fast-forward. This would cause the rebased graph to be 'ABCFG' when we were expecting 'ABCG'. With the additional logic, we detect that upstream and head's merge base is F. Since onto isn't F, it means we're not rebasing the full set of commits from master..topic. Since we're excluding some commits, a fast-forward cannot be performed and so we correctly return 0. Add '-f' to test cases that failed as a result of this change because they were not expecting a fast-forward so that a rebase is forced. Helped-by: Phillip Wood <phillip.wood@dunelm.org.uk> Signed-off-by: Denton Liu <liu.denton@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2019-08-27 13:37:59 +08:00
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
rebase: fast-forward --onto in more cases Before, when we had the following graph, A---B---C (master) \ D (side) running 'git rebase --onto master... master side' would result in D being always rebased, no matter what. However, the desired behavior is that rebase should notice that this is fast-forwardable and do that instead. Add detection to `can_fast_forward` so that this case can be detected and a fast-forward will be performed. First of all, rewrite the function to use gotos which simplifies the logic. Next, since the options.upstream && !oidcmp(&options.upstream->object.oid, &options.onto->object.oid) conditions were removed in `cmd_rebase`, we reintroduce a substitute in `can_fast_forward`. In particular, checking the merge bases of `upstream` and `head` fixes a failing case in t3416. The abbreviated graph for t3416 is as follows: F---G topic / A---B---C---D---E master and the failing command was git rebase --onto master...topic F topic Before, Git would see that there was one merge base (C), and the merge and onto were the same so it would incorrectly return 1, indicating that we could fast-forward. This would cause the rebased graph to be 'ABCFG' when we were expecting 'ABCG'. With the additional logic, we detect that upstream and head's merge base is F. Since onto isn't F, it means we're not rebasing the full set of commits from master..topic. Since we're excluding some commits, a fast-forward cannot be performed and so we correctly return 0. Add '-f' to test cases that failed as a result of this change because they were not expecting a fast-forward so that a rebase is forced. Helped-by: Phillip Wood <phillip.wood@dunelm.org.uk> Signed-off-by: Denton Liu <liu.denton@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2019-08-27 13:37:59 +08:00
test_rebase_same_head success noop same success work diff --fork-point --onto master... master
test_done