* `git rebase (--no-fork-point) --onto=<newbase> [<upstream> [<branch>]]` leaves HEAD detached and *HEAD not moved when <branch> is exactly `HEAD`
@ 2024-09-01 11:02 Han Jiang
2024-09-01 15:26 ` Phillip Wood
0 siblings, 1 reply; 6+ messages in thread
From: Han Jiang @ 2024-09-01 11:02 UTC (permalink / raw)
To: git
Thank you for filling out a Git bug report!
Please answer the following questions to help us understand your issue.
What did you do before the bug happened? (Steps to reproduce your issue)
cd '/'; cd '/'; rm --force --recursive -- './test_git'; mkdir "$_"; cd "$_";
mkdir --parents -- './server' './client';
git -C './server' init --bare './repo.git'
echo '1' >'./file'; git --git-dir='./server/repo.git' --work-tree='.'
add './file'; git --git-dir='./server/repo.git' --work-tree='.' commit
-m "$((++number))"
echo '2' >'./file'; git --git-dir='./server/repo.git' --work-tree='.'
add './file'; git --git-dir='./server/repo.git' --work-tree='.' commit
-m "$((++number))"
git -C './server/repo.git' log --graph --all --patch
git -C './client' clone '../server/repo.git' './repo'
branch_default_path="$(git -C './client/repo' symbolic-ref HEAD)"
branch_default_name="${branch_default_path#'refs/heads/'}"
echo '3' >'./client/repo/file'; git -C './client/repo' add './file';
git -C './client/repo' commit -m "$((++number))"
git -C './client/repo' log --graph --all --patch
git -C './server/repo.git' reset --soft HEAD~1
echo '4' >'./file'; git --git-dir='./server/repo.git' --work-tree='.'
add './file'; git --git-dir='./server/repo.git' --work-tree='.' commit
-m "$((++number))"
git -C './server/repo.git' log --graph --all --patch
git -C './client/repo' fetch --all
git -C './client/repo' log --graph --all --patch
git -C './client/repo' -c 'core.editor=cat' rebase
--onto=HEAD@{upstream} --interactive "$(git -C './client/repo'
merge-base --fork-point HEAD@{upstream} HEAD)" HEAD
git -C './client/repo' log --graph --all --patch
echo '5' >'./client/repo/file'; git -C './client/repo' add './file';
git -C './client/repo' -c 'core.editor=:' rebase --continue
git -C './client/repo' log --graph --all --patch
git -C './client/repo' checkout -B "$branch_default_name"
git -C './client/repo' log --graph --all --patch
What did you expect to happen? (Expected behavior)
HEAD points to GIT_DEFAULT_BRANCH and GIT_DEFAULT_BRANCH points to tip
of origin's GIT_DEFAULT_BRANCH when rebase completes.
What happened instead? (Actual behavior)
HEAD is detached and *HEAD is not moved when rebase completes, so `git
checkout -B` is needed.
What's different between what you expected and what actually happened?
Anything else you want to add:
Replacing `HEAD` with branch name (`"$(git -C './client/repo' branch
--show-current)"`) works around the problem.
cd '/'; cd '/'; rm --force --recursive -- './test_git'; mkdir "$_"; cd "$_";
mkdir --parents -- './server' './client';
git -C './server' init --bare './repo.git'
echo '1' >'./file'; git --git-dir='./server/repo.git' --work-tree='.'
add './file'; git --git-dir='./server/repo.git' --work-tree='.' commit
-m "$((++number))"
echo '2' >'./file'; git --git-dir='./server/repo.git' --work-tree='.'
add './file'; git --git-dir='./server/repo.git' --work-tree='.' commit
-m "$((++number))"
git -C './server/repo.git' log --graph --all --patch
git -C './client' clone '../server/repo.git' './repo'
echo '3' >'./client/repo/file'; git -C './client/repo' add './file';
git -C './client/repo' commit -m "$((++number))"
git -C './client/repo' log --graph --all --patch
git -C './server/repo.git' reset --soft HEAD~1
echo '4' >'./file'; git --git-dir='./server/repo.git' --work-tree='.'
add './file'; git --git-dir='./server/repo.git' --work-tree='.' commit
-m "$((++number))"
git -C './server/repo.git' log --graph --all --patch
git -C './client/repo' fetch --all
git -C './client/repo' log --graph --all --patch
git -C './client/repo' -c 'core.editor=cat' rebase
--onto=HEAD@{upstream} --interactive "$(git -C './client/repo'
merge-base --fork-point HEAD@{upstream} HEAD)" "$(git -C
'./client/repo' branch --show-current)"
git -C './client/repo' log --graph --all --patch
echo '5' >'./client/repo/file'; git -C './client/repo' add './file';
git -C './client/repo' -c 'core.editor=:' rebase --continue
git -C './client/repo' log --graph --all --patch
Please review the rest of the bug report below.
You can delete any lines you don't wish to share.
[System Info]
git version:
git version 2.46.0.windows.1
cpu: x86_64
built from commit: 2e6a859ffc0471f60f79c1256f766042b0d5d17d
sizeof-long: 4
sizeof-size_t: 8
shell-path: D:/git-sdk-64-build-installers/usr/bin/sh
feature: fsmonitor--daemon
libcurl: 8.9.0
OpenSSL: OpenSSL 3.2.2 4 Jun 2024
zlib: 1.3.1
uname: Windows 10.0 22631
compiler info: gnuc: 14.1
libc info: no libc information available
$SHELL (typically, interactive shell): C:\Program Files\Git\usr\bin\bash.exe
[Enabled Hooks]
not run from a git repository - no hooks to show
^ permalink raw reply [flat|nested] 6+ messages in thread* Re: `git rebase (--no-fork-point) --onto=<newbase> [<upstream> [<branch>]]` leaves HEAD detached and *HEAD not moved when <branch> is exactly `HEAD` 2024-09-01 11:02 `git rebase (--no-fork-point) --onto=<newbase> [<upstream> [<branch>]]` leaves HEAD detached and *HEAD not moved when <branch> is exactly `HEAD` Han Jiang @ 2024-09-01 15:26 ` Phillip Wood 2024-09-01 15:42 ` Junio C Hamano 0 siblings, 1 reply; 6+ messages in thread From: Phillip Wood @ 2024-09-01 15:26 UTC (permalink / raw) To: Han Jiang, git On 01/09/2024 12:02, Han Jiang wrote: > What did you do before the bug happened? (Steps to reproduce your issue) > git -C './client/repo' -c 'core.editor=cat' rebase > --onto=HEAD@{upstream} --interactive "$(git -C './client/repo' > merge-base --fork-point HEAD@{upstream} HEAD)" HEAD "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>". "<branch>" is expected to be a branch name, not a symbolic ref to the branch like "HEAD". > Replacing `HEAD` with branch name (`"$(git -C './client/repo' branch > --show-current)"`) works around the problem. This is working as expected. "git checkout HEAD" is a no-op so "git rebase <upstream> HEAD" is behaving differently to "git checkout HEAD && git rebase <upstream>". We could look at changing that but it would be a breaking change for anyone relying on the current behavior to detach HEAD before rebasing. Best Wishes Phillip ^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: `git rebase (--no-fork-point) --onto=<newbase> [<upstream> [<branch>]]` leaves HEAD detached and *HEAD not moved when <branch> is exactly `HEAD` 2024-09-01 15:26 ` Phillip Wood @ 2024-09-01 15:42 ` Junio C Hamano 2024-09-01 22:05 ` Han Jiang 2024-09-02 9:04 ` Phillip Wood 0 siblings, 2 replies; 6+ messages in thread From: Junio C Hamano @ 2024-09-01 15:42 UTC (permalink / raw) To: Phillip Wood; +Cc: Han Jiang, git Phillip Wood <phillip.wood123@gmail.com> 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. ^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: `git rebase (--no-fork-point) --onto=<newbase> [<upstream> [<branch>]]` leaves HEAD detached and *HEAD not moved when <branch> is exactly `HEAD` 2024-09-01 15:42 ` Junio C Hamano @ 2024-09-01 22:05 ` Han Jiang 2024-09-02 9:04 ` Phillip Wood 1 sibling, 0 replies; 6+ messages in thread From: Han Jiang @ 2024-09-01 22:05 UTC (permalink / raw) To: Junio C Hamano, Phillip Wood; +Cc: git @Phillip Wood @Junio C Hamano I finally got it. Thank you both for your explanation! On Mon, Sep 2, 2024 at 3:42 AM Junio C Hamano <gitster@pobox.com> wrote: > > Phillip Wood <phillip.wood123@gmail.com> 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. > ^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: `git rebase (--no-fork-point) --onto=<newbase> [<upstream> [<branch>]]` leaves HEAD detached and *HEAD not moved when <branch> is exactly `HEAD` 2024-09-01 15:42 ` Junio C Hamano 2024-09-01 22:05 ` Han Jiang @ 2024-09-02 9:04 ` Phillip Wood 2024-09-03 15:38 ` Junio C Hamano 1 sibling, 1 reply; 6+ messages in thread From: Phillip Wood @ 2024-09-02 9:04 UTC (permalink / raw) To: Junio C Hamano; +Cc: Han Jiang, git Hi Junio On 01/09/2024 16:42, Junio C Hamano wrote: > Phillip Wood <phillip.wood123@gmail.com> writes: > >> "<branch>" is expected to be a >> branch name, not a symbolic ref to the branch like "HEAD". > > I question the correctness of this, though. Yes as you explain below, it is a bit of an over simplification > 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.j It appears to have changed in 0cb06644a5 (rebase [--onto O] A B: omit needless checkout, 2008-03-15). That also changed the reflog messages written by "git rebase <upstream> <branch>" so that "git checkout @{n}" does not see the new branch being checked out. Best Wishes Phillip ^ permalink raw reply [flat|nested] 6+ messages in thread
* Re: `git rebase (--no-fork-point) --onto=<newbase> [<upstream> [<branch>]]` leaves HEAD detached and *HEAD not moved when <branch> is exactly `HEAD` 2024-09-02 9:04 ` Phillip Wood @ 2024-09-03 15:38 ` Junio C Hamano 0 siblings, 0 replies; 6+ messages in thread From: Junio C Hamano @ 2024-09-03 15:38 UTC (permalink / raw) To: Phillip Wood; +Cc: Han Jiang, git Phillip Wood <phillip.wood123@gmail.com> writes: >> 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.j > > It appears to have changed in 0cb06644a5 (rebase [--onto O] A B: omit > needless checkout, 2008-03-15). That also changed the reflog messages > written by "git rebase <upstream> <branch>" so that "git checkout > @{n}" does not see the new branch being checked out. Thanks for digging. Even if we now know that it was a regression in the early times of the current code, it is way too old to change it now. Unless we want to do so at a major version bump, but I do not know if this is big enough to worth writing a release note entry for. Users who do want to run a trial rebase of the current branch on a detached HEAD have all been already using HEAD^0 as the <branch> argument and they have been fine without complaints. Making it consistent in the opposite direction by changinging "git checkout HEAD" to detach HEAD is unthinkable. So what we have is fine, I would think. Thanks. ^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2024-09-03 15:38 UTC | newest] Thread overview: 6+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2024-09-01 11:02 `git rebase (--no-fork-point) --onto=<newbase> [<upstream> [<branch>]]` leaves HEAD detached and *HEAD not moved when <branch> is exactly `HEAD` Han Jiang 2024-09-01 15:26 ` Phillip Wood 2024-09-01 15:42 ` Junio C Hamano 2024-09-01 22:05 ` Han Jiang 2024-09-02 9:04 ` Phillip Wood 2024-09-03 15:38 ` Junio C Hamano
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).