git.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH 1/2] builtin/rebase.c: Emit warning when rebasing without a forkpoint
@ 2023-08-19 20:34 Wesley Schwengle
  2023-08-19 20:34 ` Wesley Schwengle
                   ` (2 more replies)
  0 siblings, 3 replies; 23+ messages in thread
From: Wesley Schwengle @ 2023-08-19 20:34 UTC (permalink / raw)
  To: git

A couple of years ago I submitted d1e894c6d7 (Document `rebase.forkpoint` in
rebase man page, 2021-09-16) and during that discussion there was some talk
about the behaviour of `git rebase'[1]. During that time I found that the
documentation update was suffice. I wouldn't say it kept me awake at night but
I do think that `git rebase' with or without an upstream supplied should behave
the same in regards to forkpoints. This patch series addresses this behaviour
change. It introduces a warning so users will have to set `rebase.forkpoint' in
their configuration. In the future we can remove the warning and opt to pick
`--no-fork-point' as a default value for `git rebase'.

There is one point where I'm a little confused, the `test_cmp' function in the
testsuite doesn't like the output that is captured from STDERR, it seems that
there is a difference in regards to whitespace. My workaround is to use
`diff -wq`. I don't know if this is an accepted solution.

Another point of interest is that `git rebase' outputs `Successfully rebased
and updated refs/heads/foo.' on STDERR and when everything is up to date it
outputs `Current branch foo is up to date.' on STDOUT. I was a little confused
by this. Especially since the output on STDOUT can be compared with `test_cmp'.

[1] https://lore.kernel.org/git/xmqqmtocrxwq.fsf@gitster.g/



^ permalink raw reply	[flat|nested] 23+ messages in thread

* [PATCH 1/2] builtin/rebase.c: Emit warning when rebasing without a forkpoint
  2023-08-19 20:34 [PATCH 1/2] builtin/rebase.c: Emit warning when rebasing without a forkpoint Wesley Schwengle
@ 2023-08-19 20:34 ` Wesley Schwengle
  2023-08-31 20:57   ` Junio C Hamano
  2023-09-01 13:19   ` [PATCH 1/2] builtin/rebase.c: Emit warning when rebasing without a forkpoint Phillip Wood
  2023-08-19 20:34 ` [PATCH 2/2] git-rebase.txt: Add deprecation notice to the --fork-point options Wesley Schwengle
  2023-08-31 14:44 ` [PATCH 1/2] builtin/rebase.c: Emit warning when rebasing without a forkpoint Wesley Schwengle
  2 siblings, 2 replies; 23+ messages in thread
From: Wesley Schwengle @ 2023-08-19 20:34 UTC (permalink / raw)
  To: git

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@opperschaap.net>
---
 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


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH 2/2] git-rebase.txt: Add deprecation notice to the --fork-point options
  2023-08-19 20:34 [PATCH 1/2] builtin/rebase.c: Emit warning when rebasing without a forkpoint Wesley Schwengle
  2023-08-19 20:34 ` Wesley Schwengle
@ 2023-08-19 20:34 ` Wesley Schwengle
  2023-08-31 14:44 ` [PATCH 1/2] builtin/rebase.c: Emit warning when rebasing without a forkpoint Wesley Schwengle
  2 siblings, 0 replies; 23+ messages in thread
From: Wesley Schwengle @ 2023-08-19 20:34 UTC (permalink / raw)
  To: git

Signed-off-by: Wesley Schwengle <wesleys@opperschaap.net>
---
 Documentation/git-rebase.txt | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/Documentation/git-rebase.txt b/Documentation/git-rebase.txt
index e7b39ad244..e47b58bec2 100644
--- a/Documentation/git-rebase.txt
+++ b/Documentation/git-rebase.txt
@@ -462,7 +462,9 @@ ends up being empty, the `<upstream>` will be used as a fallback.
 +
 If `<upstream>` or `--keep-base` is given on the command line, then
 the default is `--no-fork-point`, otherwise the default is
-`--fork-point`. See also `rebase.forkpoint` in linkgit:git-config[1].
+`--fork-point`. See also `rebase.forkpoint` in linkgit:git-config[1]. This
+behaviour will be changed in an upcoming release of git. It is advised that you
+set `rebase.forkpoint` in your config or supply the command line switches.
 +
 If your branch was based on `<upstream>` but `<upstream>` was rewound and
 your branch contains commits which were dropped, this option can be used
-- 
2.42.0.rc2.7.gf9972720e9.dirty


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* Re: [PATCH 1/2] builtin/rebase.c: Emit warning when rebasing without a forkpoint
  2023-08-19 20:34 [PATCH 1/2] builtin/rebase.c: Emit warning when rebasing without a forkpoint Wesley Schwengle
  2023-08-19 20:34 ` Wesley Schwengle
  2023-08-19 20:34 ` [PATCH 2/2] git-rebase.txt: Add deprecation notice to the --fork-point options Wesley Schwengle
@ 2023-08-31 14:44 ` Wesley Schwengle
  2 siblings, 0 replies; 23+ messages in thread
From: Wesley Schwengle @ 2023-08-31 14:44 UTC (permalink / raw)
  To: git

> [snip]

I submitted this earlier this month. I think it wasn't noticed because of the
release of v4.24.0. If someone could have a look at this, that would be
appreciated. 

Cheers,
Wesley

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH 1/2] builtin/rebase.c: Emit warning when rebasing without a forkpoint
  2023-08-19 20:34 ` Wesley Schwengle
@ 2023-08-31 20:57   ` Junio C Hamano
  2023-08-31 21:52     ` Junio C Hamano
  2023-09-01 13:19   ` [PATCH 1/2] builtin/rebase.c: Emit warning when rebasing without a forkpoint Phillip Wood
  1 sibling, 1 reply; 23+ messages in thread
From: Junio C Hamano @ 2023-08-31 20:57 UTC (permalink / raw)
  To: Wesley Schwengle; +Cc: git

Wesley Schwengle <wesleys@opperschaap.net> writes:

> 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.

I actually think it is a reasonable, if a bit too clever (for my
taste at least), default for those who do not want to type the
"--fork-point" option from the command line and still want to use
that option when they are pulling from or rebasing on the source
they usually interact with, while still allowing them to be precise
when they do want to specify exactly what commit they want to base
it on.

And the way how you tell if they are using the "usual" source is to
see if they used the lazy "git rebase" (without arguments) form.  So
I do not think it is particularly a bad design to allow "git rebase
master" and "git rebase" to behave differently.  The latter may use
the "fork point computed using 'master' branch" (when the current
branch is configured to rebuild on top of 'master') while the former
may use "exactly the commit pointed at by the 'master' branch".

> 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.

Surely, but you would lose commits if you don't know these things
and explicitly gave the --fork-point option the same way.  So I am
not sure if switching of the default is warranted.

> -			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"

The message "Rebasing without specifying a forkpoint" reads as if
you are encouraging the use of forkpoint mode (which you are not, I
know), but then what the message advertises as a future default
stops not make sense.  "If we hate the forkpoint mode so much to
disable it by default, why so we discourage running the command
without specifying it?" would be the confused message the users will
read from it.

Your "git config" example command lines are not correct, are they?
There should be no '=' assignment operator.

I am also afraid that this is giving a way too broad an advice.

What you want to discourage is to rebase without specifying what to
rebase on and without saying if you want or you do not want the
forkpoint behaviour, which will opt the user into the more dangerous
forkpoint behaviour.  The above makes it sound as if we will
discourage even the more precise "git rebase <newbase>" form, but I
do not think it is the case.  We would and should not trigger the
folk-point behaviour if there is an explicit <upstream> and the user
does not say "--fork-point" from the command line.

Here is my attempt to rewrite the above:

    When 'git rebase' is run without specifying <upstream> on the
    command line, the current default is to use the fork-point
    heuristics, but 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.

Note that the parsing of "rebase.forkpoint" is a bit peculiar in
that 

 - By leaving it unspecified, the .fork_point = -1 in
   REBASE_OPTIONS_INIT takes effect (which is unsurprising);

 - By setting it to false, .fork_point becomes 0; but

 - If you set the configuration variable to true, .fork_point
   becomes -1, not 1.

And this is very much deliberate if I understand it correctly [*1*].
By the time we get to this part of the code (i.e. .fork_point is
-1), the user may already have rebase.forkpoint set to true.  IOW,
setting it to 'true' is not a valid way to squelch this message.

I am not commenting on the tests, as the above code probably needs
to be corrected first so that folks who want to squelch the message
and want the "forkpoint behaviour by default when rebuilding on the
usual upstream" behaviour can do so by setting the variable to true.

And that obviously need to be tested, too.

Thanks.


[References]

*1* https://lore.kernel.org/git/xmqqturbdxi2.fsf@gitster.c.googlers.com/

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH 1/2] builtin/rebase.c: Emit warning when rebasing without a forkpoint
  2023-08-31 20:57   ` Junio C Hamano
@ 2023-08-31 21:52     ` Junio C Hamano
  2023-09-01 13:33       ` Phillip Wood
  2023-09-02 22:16       ` [PATCH v2] " Wesley Schwengle
  0 siblings, 2 replies; 23+ messages in thread
From: Junio C Hamano @ 2023-08-31 21:52 UTC (permalink / raw)
  To: Wesley Schwengle; +Cc: git

Junio C Hamano <gitster@pobox.com> writes:

> I am not commenting on the tests, as the above code probably needs
> to be corrected first so that folks who want to squelch the message
> and want the "forkpoint behaviour by default when rebuilding on the
> usual upstream" behaviour can do so by setting the variable to true.
>
> And that obviously need to be tested, too.

Another worrysome thing about rebase.forkpoint is that it will be
inevitable for folks to start complaining that it does not work the
way other configuration variables do.  Setting the variable to
'true' is not the same as passing '--fork-point=true' from the
command line.

I actually think it would be a lot larger behaviour change with a
huge potential to be received as a regression if we start making the
variable to mean the same thing as passing '--fork-point=true'.
People may like the current "if you are rebuilding your branch on
its usual upstream, pay attention to the rebase and rewind of the
upstream itself, but if you are giving an explicit upstream from the
command line, the tool does not second guess you with the fork-point
heuristics" behaviour and prefer to set it to true.  We would be
breaking them big time if suddenly the rebase.forkpoint=true they
set previously starts triggering the fork-point heuristics when they
run "git rebase upstream".  So that needs to be kept in mind when/if
we fix the "setting the variable, even to 'true', will squelch the
warning".


^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH 1/2] builtin/rebase.c: Emit warning when rebasing without a forkpoint
  2023-08-19 20:34 ` Wesley Schwengle
  2023-08-31 20:57   ` Junio C Hamano
@ 2023-09-01 13:19   ` Phillip Wood
  2023-09-01 17:13     ` Wesley
  1 sibling, 1 reply; 23+ messages in thread
From: Phillip Wood @ 2023-09-01 13:19 UTC (permalink / raw)
  To: Wesley Schwengle, git; +Cc: Junio C Hamano

Hi Wesley

On 19/08/2023 21:34, Wesley Schwengle wrote:
> 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

Here "git merge" fast-forwards I think, if instead it created a merge 
commit there would be no problem as the tip of branch "foo" would not 
end up in master's reflog.

>      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'

For a reproduction recipe I think "git log --oneline" would suffice.

>      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

Thanks for the detailed reproduction recipe, I think it would be helpful 
to summarize what's happening in the commit message, especially as it 
seems to depend on "git merge" fast-forwarding. Do you often merge a 
branch into it's upstream and then reset the upstream branch?

I tend to agree with Junio that the current default is pretty 
reasonable. Looking through the links from the cover letter it seems 
that the current behavior came from a desire for

	git fetch && git rebase

to behave like

	git pull --rebase

I think the commit message for any change to the default should address 
why that is undesirable. Also we should consider what problems may arise 
from not defaulting to --fork-point when rebasing on an upstream branch 
that has itself been rebased or rewound.

Best Wishes

Phillip

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH 1/2] builtin/rebase.c: Emit warning when rebasing without a forkpoint
  2023-08-31 21:52     ` Junio C Hamano
@ 2023-09-01 13:33       ` Phillip Wood
  2023-09-01 16:48         ` Junio C Hamano
  2023-09-02 22:16       ` [PATCH v2] " Wesley Schwengle
  1 sibling, 1 reply; 23+ messages in thread
From: Phillip Wood @ 2023-09-01 13:33 UTC (permalink / raw)
  To: Junio C Hamano, Wesley Schwengle; +Cc: git

On 31/08/2023 22:52, Junio C Hamano wrote:
> Junio C Hamano <gitster@pobox.com> writes:
> 
>> I am not commenting on the tests, as the above code probably needs
>> to be corrected first so that folks who want to squelch the message
>> and want the "forkpoint behaviour by default when rebuilding on the
>> usual upstream" behaviour can do so by setting the variable to true.
>>
>> And that obviously need to be tested, too.
> 
> Another worrysome thing about rebase.forkpoint is that it will be
> inevitable for folks to start complaining that it does not work the
> way other configuration variables do.  Setting the variable to
> 'true' is not the same as passing '--fork-point=true' from the
> command line.

It does seem strange, it looks like the variable was really added as a 
way to turn off the current default. If we do change the default to 
--no-fork-point when no upstream is given on the commandline then I 
think we should consider allowing "auto" for rebase.forkpoint with the 
some meaning as "true" and recommend that instead.

Best Wishes

Phillip

> I actually think it would be a lot larger behaviour change with a
> huge potential to be received as a regression if we start making the
> variable to mean the same thing as passing '--fork-point=true'.
> People may like the current "if you are rebuilding your branch on
> its usual upstream, pay attention to the rebase and rewind of the
> upstream itself, but if you are giving an explicit upstream from the
> command line, the tool does not second guess you with the fork-point
> heuristics" behaviour and prefer to set it to true.  We would be
> breaking them big time if suddenly the rebase.forkpoint=true they
> set previously starts triggering the fork-point heuristics when they
> run "git rebase upstream".  So that needs to be kept in mind when/if
> we fix the "setting the variable, even to 'true', will squelch the
> warning".
> 


^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH 1/2] builtin/rebase.c: Emit warning when rebasing without a forkpoint
  2023-09-01 13:33       ` Phillip Wood
@ 2023-09-01 16:48         ` Junio C Hamano
  0 siblings, 0 replies; 23+ messages in thread
From: Junio C Hamano @ 2023-09-01 16:48 UTC (permalink / raw)
  To: Phillip Wood; +Cc: Wesley Schwengle, git

Phillip Wood <phillip.wood123@gmail.com> writes:

> It does seem strange, it looks like the variable was really added as a
> way to turn off the current default. If we do change the default to
> --no-fork-point when no upstream is given on the commandline then I
> think we should consider allowing "auto" for rebase.forkpoint with the
> some meaning as "true" and recommend that instead.

Perhaps.  The current and existing users do not need to change
anything and 'true' should keep working fine, but given that we are
discouraging the use of fork-point heuristics, it is not clear if it
makes sense to entice new users with a new 'auto' synonym, so, I
dunno

Thanks.
.

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH 1/2] builtin/rebase.c: Emit warning when rebasing without a forkpoint
  2023-09-01 13:19   ` [PATCH 1/2] builtin/rebase.c: Emit warning when rebasing without a forkpoint Phillip Wood
@ 2023-09-01 17:13     ` Wesley
  2023-09-01 18:10       ` Junio C Hamano
  0 siblings, 1 reply; 23+ messages in thread
From: Wesley @ 2023-09-01 17:13 UTC (permalink / raw)
  To: phillip.wood; +Cc: Junio C Hamano, git


Hello Phillip,


On 9/1/23 09:19, Phillip Wood wrote:
> Hi Wesley
> 
> On 19/08/2023 21:34, Wesley Schwengle wrote:
>> 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
> 
> Here "git merge" fast-forwards I think, if instead it created a merge 
> commit there would be no problem as the tip of branch "foo" would not 
> end up in master's reflog.

If you do

git merge foo --no-ff
git reset --hard HEAD^
git switch foo
git rebase

You'll end up with just the commits that are in master. You'll lose all 
commits from foo.

>>      git log --format='%C(yellow)%h%Creset %Cgreen%s%Creset'
> 
> For a reproduction recipe I think "git log --oneline" would suffice.

Will update, thanks.

 >> [snip]
> 
> Thanks for the detailed reproduction recipe, I think it would be helpful 
> to summarize what's happening in the commit message, especially as it 
> seems to depend on "git merge" fast-forwarding. Do you often merge a 
> branch into it's upstream and then reset the upstream branch?

Tricky question. When I encountered this behavior I was working on an 
epic/topic branch that I had locally. And I made a commit that I thought 
should have been in another branch. I moved the commit to another branch 
and than later on rebased it.

I didn't reply to Juno yet, but he refers to the discussion about 
--fork-point and --root command line options. This discussion links to a 
blogpost [*1*] where the same behavior is experienced.

The quirk is this: --fork-point looks at the reflog and reflog is local. 
Meaning, having an remote upstream branch will make --fork-point a noop. 
Only where you have an upstream which is local and your reflog has seen 
dropped commits it does something. In all other cases (including 
supplying the upstream) it behaves as if --no-fork-point was set. If you 
do the same action in two different clones, you get a different result, 
depending on what is in your reflog. I find this very tricky behavior 
for a default. I've set it to false myself, to get a more consistent 
behavior.

I usually have a remote upstream (gitlab/github) and work with that, so 
the --fork-point behaviour isn't present because there is no reflog for 
that, so it behaves as --no-fork-point.

Cheers,
Wesley


[1]: https://commaok.xyz/post/fork-point/
-- 
Wesley

Why not both?


^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH 1/2] builtin/rebase.c: Emit warning when rebasing without a forkpoint
  2023-09-01 17:13     ` Wesley
@ 2023-09-01 18:10       ` Junio C Hamano
  2023-09-02  1:35         ` Wesley
  0 siblings, 1 reply; 23+ messages in thread
From: Junio C Hamano @ 2023-09-01 18:10 UTC (permalink / raw)
  To: Wesley; +Cc: phillip.wood, git

Wesley <wesleys@opperschaap.net> writes:

> The quirk is this: --fork-point looks at the reflog and reflog is
> local. Meaning, having an remote upstream branch will make
> --fork-point a noop. Only where you have an upstream which is local
> and your reflog has seen dropped commits it does something.

Why do you lack reflog on your remote-tracking branches in the first
place?  

The fork-point heuristics, as far as I understand it, was invented
exactly to protect you from your upstream repository rewinding and
rebuilding the branch you have been building on top of.  The default
fetch refspec +refs/heads/*:refs/remotes/origin/* has the "force"
option "+" in front exactly because the fetching repository is
expected to keep the reflog for remote-tracking branches to help
recovering from such a rewind & rebuild.

Puzzled.  

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH 1/2] builtin/rebase.c: Emit warning when rebasing without a forkpoint
  2023-09-01 18:10       ` Junio C Hamano
@ 2023-09-02  1:35         ` Wesley
  2023-09-02 22:36           ` Junio C Hamano
  0 siblings, 1 reply; 23+ messages in thread
From: Wesley @ 2023-09-02  1:35 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: phillip.wood, git

On 9/1/23 14:10, Junio C Hamano wrote:
> Wesley <wesleys@opperschaap.net> writes:
> 
>> The quirk is this: --fork-point looks at the reflog and reflog is
>> local. Meaning, having an remote upstream branch will make
>> --fork-point a noop. Only where you have an upstream which is local
>> and your reflog has seen dropped commits it does something.
> 
> Why do you lack reflog on your remote-tracking branches in the first
> place?

I do not know? I tested with a bare repo and two clones. And I also 
tested it with just a remote upstream in another branch.

When in repo-1 I do the reset --hard HEAD^, and push the results, and 
pull them in in repo-2 the behavior doesn't replicate. The git reflog 
command doesn't show the reset.
However, if I delete the reflog entry for removal of the reset HEAD^, 
git rebase exposes the fork-point behavior.

> The fork-point heuristics, as far as I understand it, was invented
> exactly to protect you from your upstream repository rewinding and
> rebuilding the branch you have been building on top of.  The default
> fetch refspec +refs/heads/*:refs/remotes/origin/* has the "force"
> option "+" in front exactly because the fetching repository is
> expected to keep the reflog for remote-tracking branches to help
> recovering from such a rewind & rebuild.

I haven't force pushed anything btw, maybe that could explain things?

Cheers,
Wesley

-- 
Wesley

Why not both?


^ permalink raw reply	[flat|nested] 23+ messages in thread

* [PATCH v2] Emit warning when rebasing without a forkpoint
  2023-08-31 21:52     ` Junio C Hamano
  2023-09-01 13:33       ` Phillip Wood
@ 2023-09-02 22:16       ` Wesley Schwengle
  2023-09-02 22:16         ` [PATCH v2 1/3] rebase.c: Make a distiction between rebase.forkpoint and --fork-point arguments Wesley Schwengle
                           ` (2 more replies)
  1 sibling, 3 replies; 23+ messages in thread
From: Wesley Schwengle @ 2023-09-02 22:16 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git

This is the second version of the patch series.

Patch 1: Be able to use rebase.forkpoint and --root
Patch 2: Adding the warning + tests
Patch 3: Update documenation

I think I have covered most of your concerns and feedback in this second
version.

On 8/31/23 16:57, Junio C Hamano wrote:
> Wesley Schwengle <wesleys@opperschaap.net> writes:
> 
> Here is my attempt to rewrite the above:
> 
>      When 'git rebase' is run without specifying <upstream> on the
>      command line, the current default is to use the fork-point
>      heuristics, but 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.

I agree. I'll change the text to your version.

> Note that the parsing of "rebase.forkpoint" is a bit peculiar in
> that
> 
>   - By leaving it unspecified, the .fork_point = -1 in
>     REBASE_OPTIONS_INIT takes effect (which is unsurprising);
> 
>   - By setting it to false, .fork_point becomes 0; but
> 
>   - If you set the configuration variable to true, .fork_point
>     becomes -1, not 1.

I changed this in patch 1.

> And this is very much deliberate if I understand it correctly [*1*].
> By the time we get to this part of the code (i.e. .fork_point is
> -1), the user may already have rebase.forkpoint set to true.  IOW,
> setting it to 'true' is not a valid way to squelch this message.

So this works now with patch 2.

> Another worrysome thing about rebase.forkpoint is that it will be
> inevitable for folks to start complaining that it does not work the
> way other configuration variables do.  Setting the variable to
> 'true' is not the same as passing '--fork-point=true' from the
> command line.

I think it is now with the current series.

> I actually think it would be a lot larger behaviour change with a
> huge potential to be received as a regression if we start making the
> variable to mean the same thing as passing '--fork-point=true'.
> People may like the current "if you are rebuilding your branch on
> its usual upstream, pay attention to the rebase and rewind of the
> upstream itself, but if you are giving an explicit upstream from the
> command line, the tool does not second guess you with the fork-point
> heuristics" behaviour and prefer to set it to true.  We would be
> breaking them big time if suddenly the rebase.forkpoint=true they
> set previously starts triggering the fork-point heuristics when they
> run "git rebase upstream".  So that needs to be kept in mind when/if
> we fix the "setting the variable, even to 'true', will squelch the
> warning".

I get what you are saying. My solution is to make the --fork-point or
--no-fork-point more explicit. People could use an alias for this?

It would mean a different approach to the problem and deprecating
rebase.forkpoint as a boolean value. It could become one of three values:
"true", "false" and "legacy". Where "legacy" can be "implicit" or "auto".
Although you had some ideas on "auto" already. I'm not sure on how I would call
it. "no-upstream"?

-- 
Wesley

Why not both?



^ permalink raw reply	[flat|nested] 23+ messages in thread

* [PATCH v2 1/3] rebase.c: Make a distiction between rebase.forkpoint and --fork-point arguments
  2023-09-02 22:16       ` [PATCH v2] " Wesley Schwengle
@ 2023-09-02 22:16         ` Wesley Schwengle
  2023-09-02 22:16         ` [PATCH v2 2/3] builtin/rebase.c: Emit warning when rebasing without a forkpoint Wesley Schwengle
  2023-09-02 22:16         ` [PATCH v2 3/3] git-rebase.txt: Add deprecation notice to the --fork-point options Wesley Schwengle
  2 siblings, 0 replies; 23+ messages in thread
From: Wesley Schwengle @ 2023-09-02 22:16 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git

When you call `git rebase --root' we are not interested in the
rebase.forkpoint configuration. The two options are not to be combined.

Because the implementation checks if the configured value for using a
forkpoint > 0 I've opted to give the configured forkpoint the value 2.
If the user supplies --fork-point on the command line this has a value
of 1. Now we can make a distinction between user input and the configured
value of rebase.forkpoint.

Signed-off-by: Wesley Schwengle <wesleys@opperschaap.net>
---
 builtin/rebase.c | 8 ++++++--
 1 file changed, 6 insertions(+), 2 deletions(-)

diff --git a/builtin/rebase.c b/builtin/rebase.c
index 50cb85751f..2108001600 100644
--- a/builtin/rebase.c
+++ b/builtin/rebase.c
@@ -824,7 +824,7 @@ static int rebase_config(const char *var, const char *value,
 	}
 
 	if (!strcmp(var, "rebase.forkpoint")) {
-		opts->fork_point = git_config_bool(var, value) ? -1 : 0;
+		opts->fork_point = git_config_bool(var, value) ? 2 : 0;
 		return 0;
 	}
 
@@ -1264,8 +1264,12 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
 		if (options.fork_point < 0)
 			options.fork_point = 0;
 	}
-	if (options.root && options.fork_point > 0)
+	if (options.root && options.fork_point == 1) {
 		die(_("options '%s' and '%s' cannot be used together"), "--root", "--fork-point");
+	} else if (options.root && options.fork_point > 1) {
+	    options.fork_point = 0;
+	}
+
 
 	if (options.action != ACTION_NONE && !in_progress)
 		die(_("No rebase in progress?"));
-- 
2.42.0.103.g5622fd1409.dirty


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH v2 2/3] builtin/rebase.c: Emit warning when rebasing without a forkpoint
  2023-09-02 22:16       ` [PATCH v2] " Wesley Schwengle
  2023-09-02 22:16         ` [PATCH v2 1/3] rebase.c: Make a distiction between rebase.forkpoint and --fork-point arguments Wesley Schwengle
@ 2023-09-02 22:16         ` Wesley Schwengle
  2023-09-02 23:37           ` Junio C Hamano
  2023-09-02 22:16         ` [PATCH v2 3/3] git-rebase.txt: Add deprecation notice to the --fork-point options Wesley Schwengle
  2 siblings, 1 reply; 23+ messages in thread
From: Wesley Schwengle @ 2023-09-02 22:16 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git

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@opperschaap.net>
---
 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


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH v2 3/3] git-rebase.txt: Add deprecation notice to the --fork-point options
  2023-09-02 22:16       ` [PATCH v2] " Wesley Schwengle
  2023-09-02 22:16         ` [PATCH v2 1/3] rebase.c: Make a distiction between rebase.forkpoint and --fork-point arguments Wesley Schwengle
  2023-09-02 22:16         ` [PATCH v2 2/3] builtin/rebase.c: Emit warning when rebasing without a forkpoint Wesley Schwengle
@ 2023-09-02 22:16         ` Wesley Schwengle
  2 siblings, 0 replies; 23+ messages in thread
From: Wesley Schwengle @ 2023-09-02 22:16 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git

Signed-off-by: Wesley Schwengle <wesleys@opperschaap.net>
---
 Documentation/git-rebase.txt | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/Documentation/git-rebase.txt b/Documentation/git-rebase.txt
index e7b39ad244..e47b58bec2 100644
--- a/Documentation/git-rebase.txt
+++ b/Documentation/git-rebase.txt
@@ -462,7 +462,9 @@ ends up being empty, the `<upstream>` will be used as a fallback.
 +
 If `<upstream>` or `--keep-base` is given on the command line, then
 the default is `--no-fork-point`, otherwise the default is
-`--fork-point`. See also `rebase.forkpoint` in linkgit:git-config[1].
+`--fork-point`. See also `rebase.forkpoint` in linkgit:git-config[1]. This
+behaviour will be changed in an upcoming release of git. It is advised that you
+set `rebase.forkpoint` in your config or supply the command line switches.
 +
 If your branch was based on `<upstream>` but `<upstream>` was rewound and
 your branch contains commits which were dropped, this option can be used
-- 
2.42.0.103.g5622fd1409.dirty


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* Re: [PATCH 1/2] builtin/rebase.c: Emit warning when rebasing without a forkpoint
  2023-09-02  1:35         ` Wesley
@ 2023-09-02 22:36           ` Junio C Hamano
  0 siblings, 0 replies; 23+ messages in thread
From: Junio C Hamano @ 2023-09-02 22:36 UTC (permalink / raw)
  To: Wesley; +Cc: phillip.wood, git

Wesley <wesleys@opperschaap.net> writes:

> On 9/1/23 14:10, Junio C Hamano wrote:
>> Wesley <wesleys@opperschaap.net> writes:
>> 
>>> The quirk is this: --fork-point looks at the reflog and reflog is
>>> local. Meaning, having an remote upstream branch will make
>>> --fork-point a noop. Only where you have an upstream which is local
>>> and your reflog has seen dropped commits it does something.
>> Why do you lack reflog on your remote-tracking branches in the first
>> place?
>
> I do not know? I tested with a bare repo and two clones. And I also
> tested it with just a remote upstream in another branch.

IIRC, a non-bare repository (i.e. with working tree) should get
core.logallrefupdates set to true by default, so all your refs, not
just local and remote-tracking branches, should have records.

> I haven't force pushed anything btw, maybe that could explain things?

If your "remote" is never force-pushed, then the movements of refs
at the remote (which you will observe whenever you fetch from it)
will always fast-forward, and the remote-tracking branches in your
local repository that keeps track of the movement will also record
the fast-forwarding movement in the reflog.  But then there is no
need for the fork-point heurisitics to trigger, and even if it
triggered the heuristics would not change the outcome, when rebasing
against such a remote branch, as their tip will always a decendant
of all commits that ever sat at the tip of that remote branch.


^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH v2 2/3] builtin/rebase.c: Emit warning when rebasing without a forkpoint
  2023-09-02 22:16         ` [PATCH v2 2/3] builtin/rebase.c: Emit warning when rebasing without a forkpoint Wesley Schwengle
@ 2023-09-02 23:37           ` Junio C Hamano
  2023-09-03  2:29             ` Wesley
  2023-09-03  4:50             ` Junio C Hamano
  0 siblings, 2 replies; 23+ messages in thread
From: Junio C Hamano @ 2023-09-02 23:37 UTC (permalink / raw)
  To: Wesley Schwengle; +Cc: git

Wesley Schwengle <wesleys@opperschaap.net> writes:

> Subject: Re: [PATCH v2 2/3] builtin/rebase.c: Emit warning when rebasing without a forkpoint

(applies to all three patches) downcase "Emit" after the <area>: prefix.

> 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.

I already said that the above is not true, so I will not repeat myself.

> Git rebase doesn't work if you don't have an upstream branch configured

"git rebase foo" works just fine, so this statement needs a lot of
tightening.

> (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.

No, what is causing the loss in this particular case is allowing to
use the fork-point heuristics.  If you do not want it, you can
either explicitly give --no-fork-point or <upstream> (or both if you
feel that you need to absolutely be clear).  Or you can set the
configuration to "false" to disable this "auto" behaviour.

> The following reproduction path exposes
> this behavior:

I actually do not think having this example in the proposed log
message adds more value than it distracts readers from the real
point of this change.

If you rewind to lose commits from the branch you are (re)building
against, and what was rewound and discarded was part of the work you
are building, whether it is on a local branch or on a remote branch
that contains what you have already pushed, they will be discarded,
it is by design, and it is a known deficiency with the fork-point
heuristics.  How the fork-point heuristics breaks down is rather
well known and it is pretty much orthogonal to the point of this
patch, which is to make it harder to trigger by folks who are not
familiar with "git rebase" and yet try to be lazy by not specifying
the <upstream> from the command line.

By the way, while I do agree with the need to make users _aware_ of
the "auto" behaviour [*1*], I am not yet convinced that there is a
need to change the default in the future.

	Side note: It allows those who originally advocated the
	fork-point heuristics to be extra lazy and allow fork-point
	heuristics to be used when they rebuild on top of what they
	usually rebuild on (and the "usually" part is signalled by
	using "git rebase" without saying what to build on from the
	command line).  The default allows them not to worry about
	the heuristics to kick in when they explicitly say on which
	exact commit they want to rebuild on.

And when we do not know if the default will change, the new warning
message will lose value.  Many of those who see the message are
already familiar with when the forkpoint heuristics will kick in,
and those who weren't familiar with will not know what the default
change is about, without consulting the documentation.

It might be better to extend the documentation instead, which will
not distract those who are using the tool just fine already.

> 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 &&

Style???

> +	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 &&

Why does this have to be orgiinal in such a strange way?  When
everybody else uses string "EOF" as the end-of-here-doc-marker, and
if there is no downside to use the same string here, we should just
use the same "EOF" to avoid distracting readers.

> +	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 &&

Why not "test_cmp expect actual" like everybody else?

> +...
> +	echo "Current branch foo is up to date." > expect &&
> +	test_cmp out expect
> +'
> +
>  test_done

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH v2 2/3] builtin/rebase.c: Emit warning when rebasing without a forkpoint
  2023-09-02 23:37           ` Junio C Hamano
@ 2023-09-03  2:29             ` Wesley
  2023-09-03  4:50             ` Junio C Hamano
  1 sibling, 0 replies; 23+ messages in thread
From: Wesley @ 2023-09-03  2:29 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git

On 9/2/23 19:37, Junio C Hamano wrote:
> Wesley Schwengle <wesleys@opperschaap.net> writes:

Thanks for the feedback. I won't continue the patch series because some 
of the feedback you've given below.

>> 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.
> 
> No, what is causing the loss in this particular case is allowing to
> use the fork-point heuristics.  If you do not want it, you can
> either explicitly give --no-fork-point or <upstream> (or both if you
> feel that you need to absolutely be clear).  Or you can set the
> configuration to "false" to disable this "auto" behaviour.

Isn't that what I'm saying? At least I'm trying to say what you are saying.

> By the way, while I do agree with the need to make users _aware_ of
> the "auto" behaviour [*1*], I am not yet convinced that there is a
> need to change the default in the future.

In that case, I'll abort this patch series. I don't agree with the `git 
rebase' in the lazy form and `git rebase <upstream>' acting differently, 
but I already have the rebase.forkpoint set to false to counter it.

> It might be better to extend the documentation instead, which will
> not distract those who are using the tool just fine already.

That is with the current viewpoints the best option I think.

>> +	diff -qw expect err &&
> 
> Why not "test_cmp expect actual" like everybody else?

As said in the initial patch series and the comment above the tests:

> There is one point where I'm a little confused, the `test_cmp' function in the
> testsuite doesn't like the output that is captured from STDERR, it seems that
> there is a difference in regards to whitespace. My workaround is to use
> `diff -wq`. I don't know if this is an accepted solution.

That's why.

Cheers,
Wesley

-- 
Wesley

Why not both?


^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH v2 2/3] builtin/rebase.c: Emit warning when rebasing without a forkpoint
  2023-09-02 23:37           ` Junio C Hamano
  2023-09-03  2:29             ` Wesley
@ 2023-09-03  4:50             ` Junio C Hamano
  2023-09-03 12:34               ` Wesley Schwengle
  2023-09-04 10:16               ` Phillip Wood
  1 sibling, 2 replies; 23+ messages in thread
From: Junio C Hamano @ 2023-09-03  4:50 UTC (permalink / raw)
  To: Wesley Schwengle; +Cc: git

Junio C Hamano <gitster@pobox.com> writes:

> If you rewind to lose commits from the branch you are (re)building
> against, and what was rewound and discarded was part of the work you
> are building, whether it is on a local branch or on a remote branch
> that contains what you have already pushed, they will be discarded,
> it is by design, and it is a known deficiency with the fork-point
> heuristics.  How the fork-point heuristics breaks down is rather
> well known ...

Another tangent, this time very closely related to this topic, is
that it may be worth warning when the fork-point heuristics chooses
the base commit that is different from the original upstream,
regardless of how we ended up using fork-point heuristics.

Experienced users may not be confused when the heuristics kicks in
and when it does not (e.g. because they configured, because they
used the "lazy" form, or because they gave "--fork-point" from the
command line explicitly), but they still may get surprising results
if a reflog entry chosen to be used as the base by the heuristics is
not what they expected to be used, and can lose their work that way.
Imagine that you pushed your work to the remote that is a shared
repository, and then continued building on top of it, while others
rewound the remote branch to eject your work, and your "git fetch"
updated the remote-tracking branch.  You'll be pretty much in the
same situation you had in your reproduction recipe that rewound your
own local branch that you used to build your derived work on and
would lose your work the same way, if you do not notice that the
remote branch has been rewound (and the fork-point heuristics chose
a "wrong" commit from the reflog of your remote-tracking branch.

Perhaps something along the lines of this (not even compile tested,
though)...  It might even be useful to show a shortlog between the
.restrict_revision and .upstream, which is the list of commits that
is potentially lost, but that might turn out to be excessively loud
and noisy in the workflow of those who do benefit from the
fork-point heuristics because their project rewinds branches too
often and too wildly for them to manually keep track of.  I dunno.


 builtin/rebase.c | 8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)

diff --git c/builtin/rebase.c w/builtin/rebase.c
index 50cb85751f..432a97e205 100644
--- c/builtin/rebase.c
+++ w/builtin/rebase.c
@@ -1721,9 +1721,15 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
 	if (keep_base && options.reapply_cherry_picks)
 		options.upstream = options.onto;
 
-	if (options.fork_point > 0)
+	if (options.fork_point > 0) {
 		options.restrict_revision =
 			get_fork_point(options.upstream_name, options.orig_head);
+		if (options.restrict_revision &&
+		    options.restrict_revision != options.upstream)
+			warning(_("fork-point heuristics using %s from the reflog of %s"),
+				oid_to_hex(&options.restrict_revision->object.oid),
+				options.upstream_name);
+	}
 
 	if (repo_read_index(the_repository) < 0)
 		die(_("could not read index"));


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* Re: [PATCH v2 2/3] builtin/rebase.c: Emit warning when rebasing without a forkpoint
  2023-09-03  4:50             ` Junio C Hamano
@ 2023-09-03 12:34               ` Wesley Schwengle
  2023-09-05 22:01                 ` Junio C Hamano
  2023-09-04 10:16               ` Phillip Wood
  1 sibling, 1 reply; 23+ messages in thread
From: Wesley Schwengle @ 2023-09-03 12:34 UTC (permalink / raw)
  To: Junio C Hamano; +Cc: git

On 9/3/23 00:50, Junio C Hamano wrote:
> Junio C Hamano <gitster@pobox.com> writes:
> 
>> If you rewind to lose commits from the branch you are (re)building
>> against, and what was rewound and discarded was part of the work you
>> are building, whether it is on a local branch or on a remote branch
>> that contains what you have already pushed, they will be discarded,
>> it is by design, and it is a known deficiency with the fork-point
>> heuristics.  How the fork-point heuristics breaks down is rather
>> well known ...
> 
> Another tangent, this time very closely related to this topic, is
> that it may be worth warning when the fork-point heuristics chooses
> the base commit that is different from the original upstream,
> regardless of how we ended up using fork-point heuristics.
> 
> [snip]
> 
> Perhaps something along the lines of this (not even compile tested,
> though)...  It might even be useful to show a shortlog between the
> .restrict_revision and .upstream, which is the list of commits that
> is potentially lost, but that might turn out to be excessively loud
> and noisy in the workflow of those who do benefit from the
> fork-point heuristics because their project rewinds branches too
> often and too wildly for them to manually keep track of.  I dunno.

I like the idea of the warning, but it could be loud indeed and you'll 
want to turn it off in that case.

-- 
Wesley

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH v2 2/3] builtin/rebase.c: Emit warning when rebasing without a forkpoint
  2023-09-03  4:50             ` Junio C Hamano
  2023-09-03 12:34               ` Wesley Schwengle
@ 2023-09-04 10:16               ` Phillip Wood
  1 sibling, 0 replies; 23+ messages in thread
From: Phillip Wood @ 2023-09-04 10:16 UTC (permalink / raw)
  To: Junio C Hamano, Wesley Schwengle; +Cc: git

On 03/09/2023 05:50, Junio C Hamano wrote:
> Junio C Hamano <gitster@pobox.com> writes:
> 
>> If you rewind to lose commits from the branch you are (re)building
>> against, and what was rewound and discarded was part of the work you
>> are building, whether it is on a local branch or on a remote branch
>> that contains what you have already pushed, they will be discarded,
>> it is by design, and it is a known deficiency with the fork-point
>> heuristics.  How the fork-point heuristics breaks down is rather
>> well known ...
> 
> Another tangent, this time very closely related to this topic, is
> that it may be worth warning when the fork-point heuristics chooses
> the base commit that is different from the original upstream,
> regardless of how we ended up using fork-point heuristics.

I think that is a good idea and would help to mitigate the surprise that 
some users have expressed when --fork-point kicks and they didn't know 
about it. I think we may want to compare "branch_base" which holds the 
merge-base of HEAD and upstream with "restrict_revision" to decide when 
to warn.

Best Wishes

Phillip

> Experienced users may not be confused when the heuristics kicks in
> and when it does not (e.g. because they configured, because they
> used the "lazy" form, or because they gave "--fork-point" from the
> command line explicitly), but they still may get surprising results
> if a reflog entry chosen to be used as the base by the heuristics is
> not what they expected to be used, and can lose their work that way.
> Imagine that you pushed your work to the remote that is a shared
> repository, and then continued building on top of it, while others
> rewound the remote branch to eject your work, and your "git fetch"
> updated the remote-tracking branch.  You'll be pretty much in the
> same situation you had in your reproduction recipe that rewound your
> own local branch that you used to build your derived work on and
> would lose your work the same way, if you do not notice that the
> remote branch has been rewound (and the fork-point heuristics chose
> a "wrong" commit from the reflog of your remote-tracking branch.
> 
> Perhaps something along the lines of this (not even compile tested,
> though)...  It might even be useful to show a shortlog between the
> .restrict_revision and .upstream, which is the list of commits that
> is potentially lost, but that might turn out to be excessively loud
> and noisy in the workflow of those who do benefit from the
> fork-point heuristics because their project rewinds branches too
> often and too wildly for them to manually keep track of.  I dunno.
> 
> 
>   builtin/rebase.c | 8 +++++++-
>   1 file changed, 7 insertions(+), 1 deletion(-)
> 
> diff --git c/builtin/rebase.c w/builtin/rebase.c
> index 50cb85751f..432a97e205 100644
> --- c/builtin/rebase.c
> +++ w/builtin/rebase.c
> @@ -1721,9 +1721,15 @@ int cmd_rebase(int argc, const char **argv, const char *prefix)
>   	if (keep_base && options.reapply_cherry_picks)
>   		options.upstream = options.onto;
>   
> -	if (options.fork_point > 0)
> +	if (options.fork_point > 0) {
>   		options.restrict_revision =
>   			get_fork_point(options.upstream_name, options.orig_head);
> +		if (options.restrict_revision &&
> +		    options.restrict_revision != options.upstream)
> +			warning(_("fork-point heuristics using %s from the reflog of %s"),
> +				oid_to_hex(&options.restrict_revision->object.oid),
> +				options.upstream_name);
> +	}
>   
>   	if (repo_read_index(the_repository) < 0)
>   		die(_("could not read index"));
> 


^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH v2 2/3] builtin/rebase.c: Emit warning when rebasing without a forkpoint
  2023-09-03 12:34               ` Wesley Schwengle
@ 2023-09-05 22:01                 ` Junio C Hamano
  0 siblings, 0 replies; 23+ messages in thread
From: Junio C Hamano @ 2023-09-05 22:01 UTC (permalink / raw)
  To: Wesley Schwengle; +Cc: git

Wesley Schwengle <wesleys@opperschaap.net> writes:

> I like the idea of the warning, but it could be loud indeed and you'll
> want to turn it off in that case.

I tend to think that a single-liner warning would not be too
intrusive (it might actually be too subtle to be noticed),
especially given that it is issued only when the fork-point does
move the target commit from what was given.

Giving a shortlog of what is lost in the history does sound like a
bit too loud, I am afraind, though.

^ permalink raw reply	[flat|nested] 23+ messages in thread

end of thread, other threads:[~2023-09-05 22:02 UTC | newest]

Thread overview: 23+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-08-19 20:34 [PATCH 1/2] builtin/rebase.c: Emit warning when rebasing without a forkpoint Wesley Schwengle
2023-08-19 20:34 ` Wesley Schwengle
2023-08-31 20:57   ` Junio C Hamano
2023-08-31 21:52     ` Junio C Hamano
2023-09-01 13:33       ` Phillip Wood
2023-09-01 16:48         ` Junio C Hamano
2023-09-02 22:16       ` [PATCH v2] " Wesley Schwengle
2023-09-02 22:16         ` [PATCH v2 1/3] rebase.c: Make a distiction between rebase.forkpoint and --fork-point arguments Wesley Schwengle
2023-09-02 22:16         ` [PATCH v2 2/3] builtin/rebase.c: Emit warning when rebasing without a forkpoint Wesley Schwengle
2023-09-02 23:37           ` Junio C Hamano
2023-09-03  2:29             ` Wesley
2023-09-03  4:50             ` Junio C Hamano
2023-09-03 12:34               ` Wesley Schwengle
2023-09-05 22:01                 ` Junio C Hamano
2023-09-04 10:16               ` Phillip Wood
2023-09-02 22:16         ` [PATCH v2 3/3] git-rebase.txt: Add deprecation notice to the --fork-point options Wesley Schwengle
2023-09-01 13:19   ` [PATCH 1/2] builtin/rebase.c: Emit warning when rebasing without a forkpoint Phillip Wood
2023-09-01 17:13     ` Wesley
2023-09-01 18:10       ` Junio C Hamano
2023-09-02  1:35         ` Wesley
2023-09-02 22:36           ` Junio C Hamano
2023-08-19 20:34 ` [PATCH 2/2] git-rebase.txt: Add deprecation notice to the --fork-point options Wesley Schwengle
2023-08-31 14:44 ` [PATCH 1/2] builtin/rebase.c: Emit warning when rebasing without a forkpoint Wesley Schwengle

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).