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 `--fork-point' or `--no-fork-point' command line option to your `git rebase' invocation. 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). You would than need to use `git rebase <upstream>' to rebase. If you configure an upstream it would seem logical to be able to run `git rebase' without arguments. However doing so would trigger a different kind of behavior. `git rebase <upstream>' behaves as if `--no-fork-point' was supplied and without it behaves as if `--fork-point' was supplied. This behavior can result in a loss of commits and can surprise users. The following reproduction path exposes this behavior: git init reproduction cd reproduction 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 --oneline 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 --oneline 03ad791 Second commit 411e6d4 First commit Signed-off-by: Wesley Schwengle <wesleys@xxxxxxxxxxxxxxx> --- builtin/rebase.c | 16 +++++++++- t/t3431-rebase-fork-point.sh | 62 ++++++++++++++++++++++++++++++++++++ 2 files changed, 77 insertions(+), 1 deletion(-) diff --git a/builtin/rebase.c b/builtin/rebase.c index 2108001600..ee7db9ba0c 100644 --- a/builtin/rebase.c +++ b/builtin/rebase.c @@ -1608,8 +1608,22 @@ 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(_( + "When \"git rebase\" is run without specifying <upstream> on the\n" + "command line, the current default is to use the fork-point\n" + "heuristics. This is expected to change in a future version\n" + "of Git, and you will have to explicitly give \"--fork-point\" from\n" + "the command line if you keep using the fork-point mode. You can\n" + "run \"git config rebase.forkpoint false\" to adopt the new default\n" + "in advance and that will also squelch the message.\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..908867ae0f 100755 --- a/t/t3431-rebase-fork-point.sh +++ b/t/t3431-rebase-fork-point.sh @@ -113,4 +113,66 @@ 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 rebase.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: When "git rebase" is run without specifying <upstream> on the + command line, the current default is to use the fork-point + heuristics. This is expected to change in a future version + of Git, and you will have to explicitly give "--fork-point" from + the command line if you keep using the fork-point mode. You can + run "git config rebase.forkpoint false" to adopt the new default + in advance and that will also squelch the message. + + 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 && + git config --add rebase.forkpoint true && + git rebase >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 config --replace-all rebase.forkpoint false && + git rebase >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.103.g5622fd1409.dirty