Subject: Re: `git rebase (--no-fork-point) --onto=<newbase> [<upstream> [<branch>]]` leaves HEAD detached and *HEAD not moved when <branch> is exactly `HEAD`

From: Junio C Hamano <[email-masked]>
Date: Sun, 01 Sep 2024 08:42:52 -0700

Phillip Wood <[email-masked]> writes:

> "git rebase <upstream> <branch>" is designed to switch to a different
> branch before rebasing it. If you do not want to switch branches you
> should use "git rebase <upstream>".

Correct.

> "<branch>" is expected to be a
> branch name, not a symbolic ref to the branch like "HEAD".

I question the correctness of this, though.  The "what to rebase"
argument can be any arbitrary commit-ish, and if it is a name of a
local branch, that branch is rebased.  If it is not, the HEAD is
detached and that detached HEAD state is rebased.  The latter is
handy when you are unsure if you want to really touch the branch.
i.e. "git rebase master topic^0"---this way you'd end up on a
detached HEAD that shows what would happen if you really rebased
"topic" branch, but if you do not like the result, you can just
discard the state by e.g., checking out some branch, and you do not
even contaminate the reflog of the "topic" branch with the record of
this failed exeriment.

I have a mild suspicion that the "rebase" command might have changed
its behaviour since the days back when it was implemented as a shell
script, when the "what to rebase" argument is HEAD, as the most
natural implementation to do this "optionally first switch to it
when the argument is given" in the scripted Porcelain is to actually
run "git checkout HEAD", which should be a somewhat noisy no-op.
Apparently today's "git rebase" does not work that way and seems to
detach HEAD instead and then rebases it.  As you said, that is the
behaviour most users are familiar with and it is probably too late
to change, even if (I didn't check) an ancient version of "rebase"
did not work that way and instead rebased the current branch.

Thanks.