I've poked at the source code but haven't found exactly what causes
the issue --- but if you do a 'git pull --rebase' or 'git rebase' onto
a tracking branch that has previously pointed to a commit that the
rebasing branch includes, the rebase will be a noop.
In practice I've hit this a few times lately when splitting a topic
branch into two branches after the fact.
Here is a short repro:
git init
touch file1
git add file1
git commit -a -m "first commit"
touch file2
git add file2
git commit -a -m "second commit"
touch file3
git add file3
git commit -a -m "third commit"
git checkout -b branch
git branch --set-upstream-to=master
git checkout master
git reset --hard 'HEAD^1'
touch file2.5
git add file2.5
git commit -a -m "second-and-a-half commit"
git --no-pager log --oneline --all --graph
#rm .git/logs/refs/heads/master
git checkout branch
git pull -v --rebase
git --no-pager log --oneline --all --graph
This outputs,
* 58432a7 (branch) third commit
| * 0e4f775 (HEAD -> master) second-and-a-half commit
|/
* 37b2e3f second commit
* 5e9f0b7 first commit
...
Successfully rebased and updated refs/heads/branch.
* 0e4f775 (HEAD -> branch, master) second-and-a-half commit
* 37b2e3f second commit
* 5e9f0b7 first commit
showing that "third commit" is lost. If you execute the "rm ..."
line, then the sequence works as expected, and the final state is,
Successfully rebased and updated refs/heads/branch.
* b636309 (HEAD -> branch) third commit
* 410a5dc (master) second-and-a-half commit
* 41981d0 second commit
* 286398d first commit
My best guess is that there's something odd happening in get_fork_point().
Cheers,
Andrew
Am 03.01.21 um 23:02 schrieb Andrew Oates:
I've poked at the source code but haven't found exactly what causes
the issue --- but if you do a 'git pull --rebase' or 'git rebase' onto
a tracking branch that has previously pointed to a commit that the
rebasing branch includes, the rebase will be a noop.
In practice I've hit this a few times lately when splitting a topic
branch into two branches after the fact.
Here is a short repro:
git init
touch file1
git add file1
git commit -a -m "first commit"
touch file2
git add file2
git commit -a -m "second commit"
touch file3
git add file3
git commit -a -m "third commit"
git checkout -b branch
git branch --set-upstream-to=master
git checkout master
git reset --hard 'HEAD^1'
touch file2.5
git add file2.5
git commit -a -m "second-and-a-half commit"
git --no-pager log --oneline --all --graph
#rm .git/logs/refs/heads/master
git checkout branch
git pull -v --rebase
git --no-pager log --oneline --all --graph
This outputs,
* 58432a7 (branch) third commit
| * 0e4f775 (HEAD -> master) second-and-a-half commit
|/
* 37b2e3f second commit
* 5e9f0b7 first commit
...
Successfully rebased and updated refs/heads/branch.
* 0e4f775 (HEAD -> branch, master) second-and-a-half commit
* 37b2e3f second commit
* 5e9f0b7 first commit
showing that "third commit" is lost. If you execute the "rm ..."
line, then the sequence works as expected, and the final state is,
Successfully rebased and updated refs/heads/branch.
* b636309 (HEAD -> branch) third commit
* 410a5dc (master) second-and-a-half commit
* 41981d0 second commit
* 286398d first commit
My best guess is that there's something odd happening in get_fork_point().
To me, the outcome looks reasonable:
By the time when the branch was created, it had no commits on top of
master. Then master was rewound and grew in a different direction, while
the branch didn't do anything. When you rebase it to its upstream, you
should expect that no commits are rebased.
-- Hannes
On Sun, Jan 3, 2021 at 5:33 PM Johannes Sixt [off-list ref] wrote:
Am 03.01.21 um 23:02 schrieb Andrew Oates:
quoted
I've poked at the source code but haven't found exactly what causes
the issue --- but if you do a 'git pull --rebase' or 'git rebase' onto
a tracking branch that has previously pointed to a commit that the
rebasing branch includes, the rebase will be a noop.
In practice I've hit this a few times lately when splitting a topic
branch into two branches after the fact.
Here is a short repro:
git init
touch file1
git add file1
git commit -a -m "first commit"
touch file2
git add file2
git commit -a -m "second commit"
touch file3
git add file3
git commit -a -m "third commit"
git checkout -b branch
git branch --set-upstream-to=master
git checkout master
git reset --hard 'HEAD^1'
touch file2.5
git add file2.5
git commit -a -m "second-and-a-half commit"
git --no-pager log --oneline --all --graph
#rm .git/logs/refs/heads/master
git checkout branch
git pull -v --rebase
git --no-pager log --oneline --all --graph
This outputs,
* 58432a7 (branch) third commit
| * 0e4f775 (HEAD -> master) second-and-a-half commit
|/
* 37b2e3f second commit
* 5e9f0b7 first commit
...
Successfully rebased and updated refs/heads/branch.
* 0e4f775 (HEAD -> branch, master) second-and-a-half commit
* 37b2e3f second commit
* 5e9f0b7 first commit
showing that "third commit" is lost. If you execute the "rm ..."
line, then the sequence works as expected, and the final state is,
Successfully rebased and updated refs/heads/branch.
* b636309 (HEAD -> branch) third commit
* 410a5dc (master) second-and-a-half commit
* 41981d0 second commit
* 286398d first commit
My best guess is that there's something odd happening in get_fork_point().
Yeah, I guess this is actually WAI, though the outcome was surprising
to me (git silently dropped my commits). Of course, after poking for
a while, as soon as I sent this I found some clear documentation for
the behavior :) Under the git rebase docs:
"If your branch was based on <upstream> but <upstream> was rewound and
your branch contains commits which were dropped, this option can be
used with --keep-base in order to drop those commits from your
branch."
In that case, maybe this is a UX suggestion rather than a bug report.
I experienced this via "git pull" rather than "git rebase", which I
generally consider a pretty safe thing to run --- but in this case,
git silently dropped my commits (which luckily I noticed).
Thoughts on how this would be less surprising to me as a user,
1) somehow make it just DTRT (though per the rebase --fork-point
docs, and your point, this may not be possible/desirable)
2) document these commits out when checking out the branch[1]
3) after a pull, log how many such commits were "dropped" for this reason
As it currently stands, the behavior is surprising --- the commits
that get rebased don't match either what is printed when checking out
the branch, or by the summary in the docs ("This is the same set of
commits that would be shown by git log <upstream>..HEAD"), and the
commits are dropped silently. The fact that the commits are somehow
tied to the old branch via the reflog breaks my mental model of branch
history not being semantically important, or the fact that "git pull"
in two repositories that are otherwise identical would have a
different outcome based on the individual history.
[1] it currently says something along the lines of "...and have X and
Y different commits each, respectively.
(use "git pull" to merge the remote branch into yours)", which I've
always assumed would mean that (barring stuff like duplicate commits),
I would end up with X+Y commits after pulling.
To me, the outcome looks reasonable:
By the time when the branch was created, it had no commits on top of
master. Then master was rewound and grew in a different direction, while
the branch didn't do anything. When you rebase it to its upstream, you
should expect that no commits are rebased.
FWIW in the cases where I've actually hit this, I had additional
commits on top of the new branch, so only the commits at the "bottom"
were dropped (which is much harder to notice). I think the difference
is whether you consider the dropped commits part of the original
branch (now discarded), or the new branch --- my mental model was the
latter, in part because I didn't realize that branch history was
actually semantically important.
-- Hannes