On 05/12/2025 09:07 AM, Phillip Wood wrote:
On 06/05/2025 22:36, Mr Bill wrote:
Hi, I ran across this doing a pull --rebase using the current master
version of git
This happens on Slackware linux, using git HEAD, version 2.35.8, and
2.46.2
I have a clone of the ffmpeg video package, with a few custom commits
on top of it,
I periodically fetch and "pull --rebase" to update the underlying
ffmpeg code.
I tried this recently, and my custom commits disappeared.
I looked further with a small test, and it looks like this is happening:
The setup:
"base" repo with a few commits (A, B, C)
"clone_1" cloned from "base", with a few extra commits (F, G)
"clone_2" cloned from "clone_1"
Add a few more commits for base (D, E)
Then use "git remote set-url origin" to point "clone_2" to "base"
Then, in "clone_2" do "pull --rebase"; the F and G commits disappear.
After the url is updated the reflog for the upstream branch still has
an entry for "G". When "git pull --rebase" runs "git merge-base
--fork-point <upstream-branch> HEAD" it will return "G" and so that
commit will be excluded from the commits being rebased.
Thank you for your comments on this (Ben and Tuomas, also)
I've seen this situation when looking at this issue.
Running "git merge-base --fork-point..." returns different values for
the clone_1 and clone_2 branches:
* clone_1 points to commit "C"
* clone_2 points to commit "G"
... apparently because of the extra "G" entry for the upstream branch.
I was expecting running "git fetch" after the "git remote set-url..." would
update the upstream HEAD information to reflect the new upstream repo state.
(and "git fetch" happens as part of "git pull --rebase", so that's
covered, too)
In my case, I can use the "rebase --no-fork-point" style to keep my updates.
Thanks again!
- Bill
Running
git fetch && git rebase --no-fork-point
should keep the commits "F" and "G". Alternatively instead of updating
the url you could rename the "origin" remote and then add a new remote
called "origin" pointing to base. That way when you pull the reflog
for the upstream branch will not have entries from the previous
remote url.
Then, in "clone_1" do "pull --rebase"; the F and G commits are retained.
That's because "F" and "G" are not in the reflog of the upstream branch
in clone_1.
It's debatable whether "git pull --rebase" should use "--fork-point" by
default. On the one hand it is convenient when the history of the
upstream branch has been rewritten but on the other hand it leads to
unexpected surprises like this. The fact that there isn't a way to
disable it and it ignores the rebase.forkPoint config setting does not
help.
Best Wishes
Phillip
Something like this:
# commit trees:
#
# base: A---B---C (initial base repo with 3 commits)
# clone_1: A---B---C (clone_1 cloned from base at commit C)
# base: A---B---C---D---E (base added extra commits D and E)
# clone_1: A---B---C---F---G (clone_1 added extra commits F and G)
# clone_2: A---B---C---F---G (clone_2 cloned from clone_1 at commit G)
#
# *** now, change clone_2 to use base as the upstream url, and fetch
/ pull / rebase to get up to date ***
#
# * set clone_2 upstream to point to base repo
# * "pull --rebase" in clone_2 (should fetch from base repo and
rebase F and G after D and E)
#
# expected result: A---B---C---D---E---F---G
# actual result: A---B---C---D---E
# commits F and G are gone
#
# Doing "pull --rebase" in clone_1 gives the expected result:
# expected result: A---B---C---D---E---F---G
#
This looks like either stale state info after the "set-url" command,
or I'm doing something wrong.
I can repeatedly cause this to happen in my local ffmpeg devel area,
if that helps debug/test this.
... and answer questions, if any.
Thanks for the help!
Bill
P.S. here's the test script I used for this:
--------------------------------------------------------------------------
#!/bin/bash
set -o errexit
BASE_WORKING_DIR="rebase_bug.working"
# Clean up the test area
rm -rf "${BASE_WORKING_DIR:?}"
mkdir "${BASE_WORKING_DIR:?}"
cd "${BASE_WORKING_DIR:?}"
WORKING_DIR="${PWD}"
mkdir test_rebase_base.git
cd test_rebase_base.git
# create the base git repo, with commit A, B and C
git init
echo "Commit A" > testfileA
git add testfileA
git commit -m "Commit A"
echo "Commit B" > testfileB
git add testfileB
git commit -m "Commit B"
echo "Commit C" > testfileC
git add testfileC
git commit -m "Commit C"
cd ..
# Clone the base area into the clone_1 area
git clone test_rebase_base.git test_rebase_clone_1.git
cd test_rebase_base.git
# Add commit D and E to the base area
echo "Commit D" > testfileD
git add testfileD
git commit -m "Commit D"
echo "Commit E" > testfileE
git add testfileE
git commit -m "Commit E"
cd ..
cd test_rebase_clone_1.git
# Add commit F and G to the clone_1 area
echo "Commit F" > testfileF
git add testfileF
git commit -m "Commit F"
echo "Commit G" > testfileG
git add testfileG
git commit -m "Commit G"
cd ..
# clone from clone_1 into clone_2
git clone test_rebase_clone_1.git test_rebase_clone_2.git
cd test_rebase_clone_2.git
# change clone_2 to point to base
git remote set-url origin "${WORKING_DIR:?}/test_rebase_base.git"
# expecting this to pull in the "base" extra commits, and move
the local HEAD commit after it in sequence
git pull --rebase
cd ..
cd test_rebase_clone_1.git
# do the same pull --rebase in clone_1
git pull --rebase
cd ..
cd test_rebase_base.git
git log --oneline > "${WORKING_DIR:?}/test_rebase_base.oneline.log"
cd ..
cd test_rebase_clone_1.git
git log --oneline > "${WORKING_DIR:?}/test_rebase_clone_1.oneline.log"
cd ..
cd test_rebase_clone_2.git
git log --oneline > "${WORKING_DIR:?}/test_rebase_clone_2.oneline.log"
cd ..
# The test_rebase_clone_1.oneline.log and
test_rebase_clone_2.oneline.log should match, but they don't
echo "done"
--------------------------------------------------------------------------------------------------