threads / bug / 64593

bug: `git pull --rebase` breaks in the presence of pushurls

Subject: bug: `git pull --rebase` breaks in the presence of pushurls

## tl;dr

13 messages between Dec 7, 2025 and Dec 11, 2025.

replies: 12people: 4as markdown or json

Kartik Agaram· Dec 7, 2025, 21:55 UTC · lore
What did you do before the bug happened? (Steps to reproduce your issue)
1. Create a bare hub repo.
  mkdir hub
  cd hub
  git init --bare
  cd ..
2. Create a bare mirror of the hub.
  git clone --bare hub mirror
3. Create a working directory A and set its pushurls to hub and mirror.
  git clone hub A
  cd A
  git remote set-url --add --push origin `dirname $PWD`/hub
  git remote set-url --add --push origin `dirname $PWD`/mirror
4. Create commit 1 and push it to both.
  echo a > a
  git add .
  git commit -m 'commit 1'
  git push
5. Create a second working directory B without pushurls.
  cd ..
  git clone hub B
  cd B
6. Create commit 2 in working directory B and push it to hub.
  echo b > b
  git add .
  git commit -m 'commit 2'
  git push
7. Create commit 3 in working directory A and try unsuccessfully to push it.
  cd ../A
  echo c > c
  git add .
  git commit -m 'commit 3'
  git push
This throws an error when pushing to hub, but successfully pushes to mirror.
8. Try to fix the problem:
  git pull --rebase
This completes successfully.
What did you expect to happen? (Expected behavior)
git log in working directory A should show all 3 commits
What happened instead? (Actual behavior)
git log shows commits 1 and 2 (created in B).
What's different between what you expected and what actually happened?
Commit 3 which was locally created is lost after the `git pull --rebase`.
Anything else you want to add:
I first encountered it in git 2.51.0. Also found to be present on HEAD of https://github.com/git/git
Problem exists independent of ~/.gitconfig.
[System Info]
git version:
git version 2.52.0.199.gbdc5341ff6
cpu: x86_64
built from commit: bdc5341ff65278a3cc80b2e8a02a2f02aa1fac06
sizeof-long: 8
sizeof-size_t: 8
shell-path: /bin/sh
rust: disabled
libcurl: 8.16.0
OpenSSL: OpenSSL 3.5.3 16 Sep 2025
zlib: 1.3.1
SHA-1: SHA1_DC
SHA-256: SHA256_BLK
default-ref-format: files
default-hash: sha1
uname: Linux 6.12.48-1-MANJARO #1 SMP PREEMPT_DYNAMIC Fri, 19 Sep 2025 16:11:04 +0000 x86_64
compiler info: gnuc: 15.2
libc info: glibc: 2.42
$SHELL (typically, interactive shell): /usr/bin/zsh
[Enabled Hooks]
Phillip Wood· Dec 8, 2025, 14:30 UTC · re: Kartik Agaram · lore

Re: bug: `git pull --rebase` breaks in the presence of pushurls

Hi Kartik
On 07/12/2025 21:55, Kartik Agaram wrote:
Thanks for the easy reproducer
Show 7 quoted lines
> 7. Create commit 3 in working directory A and try unsuccessfully to push it.
> 
>    cd ../A
>    echo c > c
>    git add .
>    git commit -m 'commit 3'
>    git push> > This throws an error when pushing to hub, but successfully pushes to 
mirror.
"git push" updates refs/remotes/origin/master when pushing to "mirror".
> 8. Try to fix the problem:
> 
>    git pull --rebase

"git pull" tries to find the fork point between origin/master and master which is the tip of master because "git push" just updated origin/master to point to the same commit as master.

Unfortunately I'm not sure there is an easy way to fix this. For now I'd recommend doing

	git fetch && git rebase --no-fork-point

instead of running "git pull --rebase". We should perhaps add a "--no-fork-point" option to "git pull" as this isn't the first time that the fork-point has caused problems [1]. There was a patch to do that at [2] but it was lacking tests.

Thanks
Phillip

[1] https://lore.kernel.org/git/6bebcee9-1315-4ec3-a49b-d767f0f67bf7@gmail.com/ [2] https://lore.kernel.org/git/06beff46-cdaf-91c8-e6a3-6557694af618@gmail.com/

Phillip Wood· Dec 8, 2025, 16:04 UTC · re: Phillip Wood · lore

Re: bug: `git pull --rebase` breaks in the presence of pushurls

On 08/12/2025 14:30, Phillip Wood wrote:
> 
> Unfortunately I'm not sure there is an easy way to fix this.

Maybe we should skip the fork-point calculation if remote.<branch>.pushurl or remote.pushDefault are set?

Thanks
Phillip
Kartik Agaram· Dec 8, 2025, 16:43 UTC · re: Phillip Wood · lore

Re: bug: `git pull --rebase` breaks in the presence of pushurls

> [for the successful pushurl] "git push" updated origin/master to point to the same commit as master.
Thank you, this is very helpful to help me understand what happened.
Junio C Hamano· Dec 8, 2025, 22:24 UTC · re: Phillip Wood · lore

Re: bug: `git pull --rebase` breaks in the presence of pushurls

Phillip Wood <phillip.wood123@gmail.com> writes:
Show 16 quoted lines
> "git push" updates refs/remotes/origin/master when pushing to "mirror".
>
>> 8. Try to fix the problem:
>> 
>>    git pull --rebase
>
> "git pull" tries to find the fork point between origin/master and master 
> which is the tip of master because "git push" just updated origin/master 
> to point to the same commit as master.
>
> Unfortunately I'm not sure there is an easy way to fix this. For now I'd 
> recommend doing
>
> 	git fetch && git rebase --no-fork-point
>
> instead of running "git pull --rebase".

Yeah, it is an integral part of "fetch" to update the remote-tracking branches, so this is harder to fix.

It may be possible to stop doing the fork-point computation in the "git rebase" phase, and instead do it _before_ we run "git fetch", to figure out what part of our history needs to be transplanted on top of the upstream, run "git fetch" (to let the tracking branches updated), and then run "git rebase", telling it exactly what range should be transplanted onto which commit to update the branch currently checked out. That would be a much larger change.

Kartik Agaram· Dec 9, 2025, 01:48 UTC · re: Junio C Hamano · lore

Re: bug: `git pull --rebase` breaks in the presence of pushurls

Should `git push` perhaps only update refs/remotes/origin/master if push to all pushurls succeeds (with the same result)? It seems like that would fix this issue. Does it not work in other scenarios?
Phillip Wood· Dec 9, 2025, 16:03 UTC · re: Kartik Agaram · lore

Re: bug: `git pull --rebase` breaks in the presence of pushurls

On 09/12/2025 01:48, Kartik Agaram wrote:
> Should `git push` perhaps only update refs/remotes/origin/master if push to all pushurls succeeds (with the same result)? It seems like that would fix this issue. Does it not work in other scenarios?

While that would help in your example, I don't think that helps in general as there is no guarantee that any of the push urls refer to the same server as the pull url. If you set a single push url that pushes to mirror in your example then "git pull --rebase" still drops the local commit. I'm a bit confused by remote.pushDefault as if I set that to a url rather than a remote then it does not update any remote tracking refs. I had assumed it would behave the same as remote.<remote>.pushurl.

Thanks
Phillip
Phillip Wood· Dec 10, 2025, 14:25 UTC · re: Junio C Hamano · lore

Re: bug: `git pull --rebase` breaks in the presence of pushurls

On 08/12/2025 22:24, Junio C Hamano wrote:
Show 29 quoted lines
> Phillip Wood <phillip.wood123@gmail.com> writes:
> 
>> "git push" updates refs/remotes/origin/master when pushing to "mirror".
>>
>>> 8. Try to fix the problem:
>>>
>>>     git pull --rebase
>>
>> "git pull" tries to find the fork point between origin/master and master
>> which is the tip of master because "git push" just updated origin/master
>> to point to the same commit as master.
>>
>> Unfortunately I'm not sure there is an easy way to fix this. For now I'd
>> recommend doing
>>
>> 	git fetch && git rebase --no-fork-point
>>
>> instead of running "git pull --rebase".
> 
> Yeah, it is an integral part of "fetch" to update the
> remote-tracking branches, so this is harder to fix.
> 
> It may be possible to stop doing the fork-point computation in the
> "git rebase" phase, and instead do it _before_ we run "git fetch",
> to figure out what part of our history needs to be transplanted on
> top of the upstream, run "git fetch" (to let the tracking branches
> updated), and then run "git rebase", telling it exactly what range
> should be transplanted onto which commit to update the branch
> currently checked out.  That would be a much larger change.

"git pull" already runs "git merge-base --fork-point" before it runs "git fetch". The problematic reflog entry comes from a previous push which pushes to a different server due to remote.<remote>.pushurl. Because we've just successfully pushed the local branch the fork point calculation thinks the remote tracking branch matches the local branch and so excludes all the local commits when we rebase but we didn't push it to the same server that we're fetching from. I wonder if we should disable the fork point calculation when there is a pushurl set.

Thanks
Phillip
Junio C Hamano· Dec 11, 2025, 03:21 UTC · re: Phillip Wood · lore

Re: bug: `git pull --rebase` breaks in the presence of pushurls

Phillip Wood <phillip.wood123@gmail.com> writes:
> "git pull" already runs "git merge-base --fork-point" before it runs 
> "git fetch". The problematic reflog entry comes from a previous push 
> which pushes to a different server due to remote.<remote>.pushurl. 

Ah, of course. fork-point heuristics with a repository you yourself push into would not make all that sense, since you are in control when and what to push there in the first place :/.

Show 5 quoted lines
> Because we've just successfully pushed the local branch the fork point 
> calculation thinks the remote tracking branch matches the local branch 
> and so excludes all the local commits when we rebase but we didn't push 
> it to the same server that we're fetching from. I wonder if we should 
> disable the fork point calculation when there is a pushurl set.
Tempting thought.  Or educate users with diagnoses and advise()?
K Jayatheerth· Dec 11, 2025, 05:35 UTC · re: Junio C Hamano · lore

Re: bug: `git pull --rebase` breaks in the presence of pushurls

I’m trying to make sure I fully understand where the fork-point behavior is coming from. I'm assuming get_rebase_fork_point() and get_rebase_newbase_and_upstream() are responsible.

And when we talk about the “fork-point heuristic” here, we mean the logic that uses the reflog of the upstream branch to detect whether the user has previously rebased or reset, and uses that information to choose a different merge-base than the raw merge-base HEAD upstream, correct?

Just checking that I’m following correctly before thinking about possible approaches.

Phillip Wood· Dec 11, 2025, 15:54 UTC · re: K Jayatheerth · lore

Re: bug: `git pull --rebase` breaks in the presence of pushurls

On 11/12/2025 05:35, K Jayatheerth wrote:
Show 8 quoted lines
> I’m trying to make sure I fully understand where the fork-point behavior is coming from.
> I'm assuming get_rebase_fork_point() and get_rebase_newbase_and_upstream() are responsible.
> 
> And when we talk about the “fork-point heuristic” here,
> we mean the logic that uses the reflog of the upstream branch
> to detect whether the user has previously rebased or reset,
> and uses that information to choose a
> different merge-base than the raw merge-base HEAD upstream, correct?

Almost, it uses the reflog of the upstream branch to find the most recent entry that is a descendant of the local branch. It then uses that commit to limit the range of commits that get rebased in case the upstream branch has been reset or rewritten. There is a diagram in the documentation [1] which might help.

Thanks
Phillip
[1] https://git-scm.com/docs/git-merge-base#_discussion_on_fork_point_mode
> Just checking that I’m following correctly
> before thinking about possible approaches.
Phillip Wood· Dec 11, 2025, 19:39 UTC · re: Phillip Wood · lore

Re: bug: `git pull --rebase` breaks in the presence of pushurls

On 11/12/2025 15:54, Phillip Wood wrote:
> On 11/12/2025 05:35, K Jayatheerth wrote:
> Almost, it uses the reflog of the upstream branch to find the most 
> recent entry that is a descendant of the local branch.

Sorry that should say "is an ancestor of the local branch", it is trying to find the upstream reflog entry that the local branch is descended from.

Show 14 quoted lines
> It then uses that 
> commit to limit the range of commits that get rebased in case the 
> upstream branch has been reset or rewritten. There is a diagram in the 
> documentation [1] which might help.
> 
> Thanks
> 
> Phillip
> 
> [1] https://git-scm.com/docs/git-merge-base#_discussion_on_fork_point_mode
> 
>> Just checking that I’m following correctly
>> before thinking about possible approaches.
> 
Phillip Wood· Dec 11, 2025, 15:56 UTC · re: Junio C Hamano · lore

Re: bug: `git pull --rebase` breaks in the presence of pushurls

On 11/12/2025 03:21, Junio C Hamano wrote:
Show 17 quoted lines
> Phillip Wood <phillip.wood123@gmail.com> writes:
> 
>> "git pull" already runs "git merge-base --fork-point" before it runs
>> "git fetch". The problematic reflog entry comes from a previous push
>> which pushes to a different server due to remote.<remote>.pushurl.
> 
> Ah, of course.  fork-point heuristics with a repository you yourself
> push into would not make all that sense, since you are in control
> when and what to push there in the first place :/.
> 
>> Because we've just successfully pushed the local branch the fork point
>> calculation thinks the remote tracking branch matches the local branch
>> and so excludes all the local commits when we rebase but we didn't push
>> it to the same server that we're fetching from. I wonder if we should
>> disable the fork point calculation when there is a pushurl set.
> 
> Tempting thought.  Or educate users with diagnoses and advise()?

If we do that we'll also need to provide a way for the user to skip using the fork point when pulling. At the moment I think there is way for the user to turn it off.

Thanks
Phillip

← back to recent threads