When commit d1e894c6d7 (Document `rebase.forkpoint` in rebase man page, 2021-09-16) was submitted there was a discussion on if the forkpoint behaviour of `git rebase' was sane. In my experience this wasn't sane. Git rebase doesn't work if you don't have an upstream branch configured (or something that says `merge = refs/heads/master' in the git config). The behaviour of `git rebase' was that if you supply an upstream on the command line that it behaves as if `--no-forkpoint' was supplied and if you don't supply an upstream, it behaves as if `--forkpoint' was supplied. This can result in a loss of commits if you don't know that and if you don't know about `git reflog' or have other copies of your changes. This can be seen with the following reproduction path: mkdir reproduction cd reproduction git init . echo "commit a" > file.txt git add file.txt git commit -m "First commit" file.txt echo "commit b" >> file.txt git commit -m "Second commit" file.txt git switch -c foo echo "commit c" >> file.txt" git commit -m "Third commit" file.txt git branch --set-upstream-to=master git status On branch foo Your branch is ahead of 'master' by 1 commit. git switch master git merge foo git reset --hard HEAD^ git switch foo Switched to branch 'foo' Your branch is ahead of 'master' by 1 commit. git log --format='%C(yellow)%h%Creset %Cgreen%s%Creset' 5f427e3 Third commit 03ad791 Second commit 411e6d4 First commit git rebase git status On branch foo Your branch is up to date with 'master'. git log --format='%C(yellow)%h%Creset %Cgreen%s%Creset' 03ad791 Second commit 411e6d4 First commit This patch adds a warning where it will indicate that `rebase.forkpoint' must be set in the git configuration and/or that you can supply a `--forkpoint' or `--no-forkpoint' command line option to your `git rebase' invocation. Signed-off-by: Wesley Schwengle <wesleys@xxxxxxxxxxxxxxx> --- builtin/rebase.c | 15 ++++++++++- t/t3431-rebase-fork-point.sh | 50 ++++++++++++++++++++++++++++++++++++ 2 files changed, 64 insertions(+), 1 deletion(-) diff --git a/builtin/rebase.c b/builtin/rebase.c index 50cb85751f..41dd9b6256 100644 --- a/builtin/rebase.c +++ b/builtin/rebase.c @@ -1604,8 +1604,21 @@ int cmd_rebase(int argc, const char **argv, const char *prefix) NULL); if (!options.upstream_name) error_on_missing_default_upstream(); - if (options.fork_point < 0) + if (options.fork_point < 0) { + warning(_( + "Rebasing without specifying a forkpoint is discouraged. You can squelch\n" + "this message by running one of the following commands something before your\n" + "next rebase:\n" + "\n" + " git config rebase.forkpoint = false # This will become the new default\n" + " git config rebase.forkpoint = true # This is the old default\n" + "\n" + "You can replace \"git config\" with \"git config --global\" to set a default\n" + "preference for all repositories. You can also pass --no-fork-point, --fork-point\n" + "on the command line to override the configured default per invocation.\n" + )); options.fork_point = 1; + } } else { options.upstream_name = argv[0]; argc--; diff --git a/t/t3431-rebase-fork-point.sh b/t/t3431-rebase-fork-point.sh index 4bfc779bb8..a583ca6228 100755 --- a/t/t3431-rebase-fork-point.sh +++ b/t/t3431-rebase-fork-point.sh @@ -113,4 +113,54 @@ test_expect_success 'rebase.forkPoint set to true and --root given' ' git rebase --root ' +# The use of the diff -qw is because there is some kind of whitespace character +# magic going on which probably has to do with the tabs. It only occurs when we +# check STDERR +test_expect_success 'rebase without forkpoint' ' + git init rebase-forkpoint && + cd rebase-forkpoint && + git status >/tmp/foo && + echo "commit a" > file.txt && + git add file.txt && + git commit -m "First commit" file.txt && + echo "commit b" >> file.txt && + git commit -m "Second commit" file.txt && + git switch -c foo && + echo "commit c" >> file.txt && + git commit -m "Third commit" file.txt && + git branch --set-upstream-to=main && + git switch main && + git merge foo && + git reset --hard HEAD^ && + git switch foo && + commit=$(git log -n1 --format="%h") && + git rebase >out 2>err && + test_must_be_empty out && + cat <<-\OEF > expect && + warning: Rebasing without specifying a forkpoint is discouraged. You can squelch + this message by running one of the following commands something before your + next rebase: + + git config rebase.forkpoint = false # This will become the new default + git config rebase.forkpoint = true # This is the old default + + You can replace "git config" with "git config --global" to set a default + preference for all repositories. You can also pass --no-fork-point, --fork-point + on the command line to override the configured default per invocation. + + Successfully rebased and updated refs/heads/foo. + OEF + diff -qw expect err && + git reset --hard $commit && + git rebase --fork-point >out 2>err && + test_must_be_empty out && + echo "Successfully rebased and updated refs/heads/foo." > expect && + diff -qw expect err && + git reset --hard $commit && + git rebase --no-fork-point >out 2>err && + test_must_be_empty err && + echo "Current branch foo is up to date." > expect && + test_cmp out expect +' + test_done -- 2.42.0.rc2.7.gf9972720e9.dirty