{"thread":{"id":"64593","subject":"bug: `git pull --rebase` breaks in the presence of pushurls","startedAt":"2025-12-07T21:55:54Z","lastAt":"2025-12-11T19:39:15Z","messageCount":13,"participants":["Kartik Agaram","Phillip Wood","Junio C Hamano","K Jayatheerth"],"isPatch":false,"patchVersion":null,"patchTotal":null},"messages":[{"id":"531802","messageId":"896e4e13-5d2f-4c5c-ac32-2927dbff91a0@app.fastmail.com","threadId":"64593","inReplyTo":null,"subject":"bug: `git pull --rebase` breaks in the presence of pushurls","fromName":"Kartik Agaram","fromEmail":"ak@akkartik.com","sentAt":"2025-12-07T21:55:33Z","receivedAt":"2025-12-07T21:55:54Z","isPatch":false,"sender":{"key":"ak@akkartik.com","avatar":"https://gravatar.com/avatar/bfa044e06852c348b2777d9a9a558c179429443f5d7b65d97291ae787b8ccc52?d=mp&s=160"},"body":"What did you do before the bug happened? (Steps to reproduce your issue)\n\n1. Create a bare hub repo.\n\n  mkdir hub\n  cd hub\n  git init --bare\n  cd ..\n\n2. Create a bare mirror of the hub.\n\n  git clone --bare hub mirror\n\n3. Create a working directory A and set its pushurls to hub and mirror.\n\n  git clone hub A\n  cd A\n  git remote set-url --add --push origin `dirname $PWD`/hub\n  git remote set-url --add --push origin `dirname $PWD`/mirror\n\n4. Create commit 1 and push it to both.\n\n  echo a > a\n  git add .\n  git commit -m 'commit 1'\n  git push\n\n5. Create a second working directory B without pushurls.\n\n  cd ..\n  git clone hub B\n  cd B\n\n6. Create commit 2 in working directory B and push it to hub.\n\n  echo b > b\n  git add .\n  git commit -m 'commit 2'\n  git push\n\n7. Create commit 3 in working directory A and try unsuccessfully to push it.\n\n  cd ../A\n  echo c > c\n  git add .\n  git commit -m 'commit 3'\n  git push\n\nThis throws an error when pushing to hub, but successfully pushes to mirror.\n\n8. Try to fix the problem:\n\n  git pull --rebase\n\nThis completes successfully.\n\nWhat did you expect to happen? (Expected behavior)\n\ngit log in working directory A should show all 3 commits\n\nWhat happened instead? (Actual behavior)\n\ngit log shows commits 1 and 2 (created in B).\n\nWhat's different between what you expected and what actually happened?\n\nCommit 3 which was locally created is lost after the `git pull --rebase`.\n\nAnything else you want to add:\n\nI first encountered it in git 2.51.0. Also found to be present on HEAD of https://github.com/git/git\n\nProblem exists independent of ~/.gitconfig.\n\n[System Info]\ngit version:\ngit version 2.52.0.199.gbdc5341ff6\ncpu: x86_64\nbuilt from commit: bdc5341ff65278a3cc80b2e8a02a2f02aa1fac06\nsizeof-long: 8\nsizeof-size_t: 8\nshell-path: /bin/sh\nrust: disabled\nlibcurl: 8.16.0\nOpenSSL: OpenSSL 3.5.3 16 Sep 2025\nzlib: 1.3.1\nSHA-1: SHA1_DC\nSHA-256: SHA256_BLK\ndefault-ref-format: files\ndefault-hash: sha1\nuname: Linux 6.12.48-1-MANJARO #1 SMP PREEMPT_DYNAMIC Fri, 19 Sep 2025 16:11:04 +0000 x86_64\ncompiler info: gnuc: 15.2\nlibc info: glibc: 2.42\n$SHELL (typically, interactive shell): /usr/bin/zsh\n\n\n[Enabled Hooks]\n"},{"id":"531834","messageId":"04cc0cc0-155e-422e-b723-b1115c918087@gmail.com","threadId":"64593","inReplyTo":"896e4e13-5d2f-4c5c-ac32-2927dbff91a0@app.fastmail.com","subject":"Re: bug: `git pull --rebase` breaks in the presence of pushurls","fromName":"Phillip Wood","fromEmail":"phillip.wood123@gmail.com","sentAt":"2025-12-08T14:30:44Z","receivedAt":"2025-12-08T14:30:48Z","isPatch":false,"sender":{"key":"phillip.wood@dunelm.org.uk","avatar":null},"body":"Hi Kartik\n\n\nOn 07/12/2025 21:55, Kartik Agaram wrote:\n\nThanks for the easy reproducer\n\n> 7. Create commit 3 in working directory A and try unsuccessfully to push it.\n> \n>    cd ../A\n>    echo c > c\n>    git add .\n>    git commit -m 'commit 3'\n>    git push> > This throws an error when pushing to hub, but successfully pushes to \nmirror.\n\n\"git push\" updates refs/remotes/origin/master when pushing to \"mirror\".\n\n> 8. Try to fix the problem:\n> \n>    git pull --rebase\n\n\"git pull\" tries to find the fork point between origin/master and master \nwhich is the tip of master because \"git push\" just updated origin/master \nto point to the same commit as master.\n\nUnfortunately I'm not sure there is an easy way to fix this. For now I'd \nrecommend doing\n\n\tgit fetch && git rebase --no-fork-point\n\ninstead of running \"git pull --rebase\". We should perhaps add a \n\"--no-fork-point\" option to \"git pull\" as this isn't the first time that \nthe fork-point has caused problems [1]. There was a patch to do that at \n[2] but it was lacking tests.\n\nThanks\n\nPhillip\n\n[1] \nhttps://lore.kernel.org/git/6bebcee9-1315-4ec3-a49b-d767f0f67bf7@gmail.com/\n[2] \nhttps://lore.kernel.org/git/06beff46-cdaf-91c8-e6a3-6557694af618@gmail.com/\n"},{"id":"531839","messageId":"b52e18c8-7533-4359-bb23-60cf25ca1694@gmail.com","threadId":"64593","inReplyTo":"04cc0cc0-155e-422e-b723-b1115c918087@gmail.com","subject":"Re: bug: `git pull --rebase` breaks in the presence of pushurls","fromName":"Phillip Wood","fromEmail":"phillip.wood123@gmail.com","sentAt":"2025-12-08T16:04:13Z","receivedAt":"2025-12-08T16:04:17Z","isPatch":false,"sender":{"key":"phillip.wood@dunelm.org.uk","avatar":null},"body":"On 08/12/2025 14:30, Phillip Wood wrote:\n> \n> Unfortunately I'm not sure there is an easy way to fix this.\n\nMaybe we should skip the fork-point calculation if \nremote.<branch>.pushurl or remote.pushDefault are set?\n\nThanks\n\nPhillip\n\n"},{"id":"531841","messageId":"b13b59e2-8119-4015-bfce-26a07cddfdbe@app.fastmail.com","threadId":"64593","inReplyTo":"04cc0cc0-155e-422e-b723-b1115c918087@gmail.com","subject":"Re: bug: `git pull --rebase` breaks in the presence of pushurls","fromName":"Kartik Agaram","fromEmail":"ak@akkartik.com","sentAt":"2025-12-08T16:43:24Z","receivedAt":"2025-12-08T16:43:46Z","isPatch":false,"sender":{"key":"ak@akkartik.com","avatar":"https://gravatar.com/avatar/bfa044e06852c348b2777d9a9a558c179429443f5d7b65d97291ae787b8ccc52?d=mp&s=160"},"body":"> [for the successful pushurl] \"git push\" updated origin/master to point to the same commit as master.\n\nThank you, this is very helpful to help me understand what happened.\n"},{"id":"531861","messageId":"xmqqa4zsliim.fsf@gitster.g","threadId":"64593","inReplyTo":"04cc0cc0-155e-422e-b723-b1115c918087@gmail.com","subject":"Re: bug: `git pull --rebase` breaks in the presence of pushurls","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2025-12-08T22:24:01Z","receivedAt":"2025-12-08T22:24:04Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Phillip Wood <phillip.wood123@gmail.com> writes:\n\n> \"git push\" updates refs/remotes/origin/master when pushing to \"mirror\".\n>\n>> 8. Try to fix the problem:\n>> \n>>    git pull --rebase\n>\n> \"git pull\" tries to find the fork point between origin/master and master \n> which is the tip of master because \"git push\" just updated origin/master \n> to point to the same commit as master.\n>\n> Unfortunately I'm not sure there is an easy way to fix this. For now I'd \n> recommend doing\n>\n> \tgit fetch && git rebase --no-fork-point\n>\n> instead of running \"git pull --rebase\".\n\nYeah, it is an integral part of \"fetch\" to update the\nremote-tracking branches, so this is harder to fix.\n\nIt may be possible to stop doing the fork-point computation in the\n\"git rebase\" phase, and instead do it _before_ we run \"git fetch\",\nto figure out what part of our history needs to be transplanted on\ntop of the upstream, run \"git fetch\" (to let the tracking branches\nupdated), and then run \"git rebase\", telling it exactly what range\nshould be transplanted onto which commit to update the branch\ncurrently checked out.  That would be a much larger change.\n\n"},{"id":"531868","messageId":"67bcbcce-96cd-4bf9-826b-e52b3e09a5d5@app.fastmail.com","threadId":"64593","inReplyTo":"xmqqa4zsliim.fsf@gitster.g","subject":"Re: bug: `git pull --rebase` breaks in the presence of pushurls","fromName":"Kartik Agaram","fromEmail":"ak@akkartik.com","sentAt":"2025-12-09T01:48:38Z","receivedAt":"2025-12-09T01:48:58Z","isPatch":false,"sender":{"key":"ak@akkartik.com","avatar":"https://gravatar.com/avatar/bfa044e06852c348b2777d9a9a558c179429443f5d7b65d97291ae787b8ccc52?d=mp&s=160"},"body":"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?\n"},{"id":"531899","messageId":"e4ac43f7-f42d-4353-959b-7ab91890b7ea@gmail.com","threadId":"64593","inReplyTo":"67bcbcce-96cd-4bf9-826b-e52b3e09a5d5@app.fastmail.com","subject":"Re: bug: `git pull --rebase` breaks in the presence of pushurls","fromName":"Phillip Wood","fromEmail":"phillip.wood123@gmail.com","sentAt":"2025-12-09T16:03:21Z","receivedAt":"2025-12-09T16:03:27Z","isPatch":false,"sender":{"key":"phillip.wood@dunelm.org.uk","avatar":null},"body":"On 09/12/2025 01:48, Kartik Agaram wrote:\n> 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?\n\nWhile that would help in your example, I don't think that helps in \ngeneral as there is no guarantee that any of the push urls refer to the \nsame server as the pull url. If you set a single push url that pushes to \nmirror in your example then \"git pull --rebase\" still drops the local \ncommit. I'm a bit confused by remote.pushDefault as if I set that to a \nurl rather than a remote then it does not update any remote tracking \nrefs. I had assumed it would behave the same as remote.<remote>.pushurl.\n\nThanks\n\nPhillip\n\n\n"},{"id":"531976","messageId":"61f61218-1945-4efe-961a-e6cb4ac8c6a9@gmail.com","threadId":"64593","inReplyTo":"xmqqa4zsliim.fsf@gitster.g","subject":"Re: bug: `git pull --rebase` breaks in the presence of pushurls","fromName":"Phillip Wood","fromEmail":"phillip.wood123@gmail.com","sentAt":"2025-12-10T14:25:32Z","receivedAt":"2025-12-10T14:25:39Z","isPatch":false,"sender":{"key":"phillip.wood@dunelm.org.uk","avatar":null},"body":"\n\nOn 08/12/2025 22:24, Junio C Hamano wrote:\n> Phillip Wood <phillip.wood123@gmail.com> writes:\n> \n>> \"git push\" updates refs/remotes/origin/master when pushing to \"mirror\".\n>>\n>>> 8. Try to fix the problem:\n>>>\n>>>     git pull --rebase\n>>\n>> \"git pull\" tries to find the fork point between origin/master and master\n>> which is the tip of master because \"git push\" just updated origin/master\n>> to point to the same commit as master.\n>>\n>> Unfortunately I'm not sure there is an easy way to fix this. For now I'd\n>> recommend doing\n>>\n>> \tgit fetch && git rebase --no-fork-point\n>>\n>> instead of running \"git pull --rebase\".\n> \n> Yeah, it is an integral part of \"fetch\" to update the\n> remote-tracking branches, so this is harder to fix.\n> \n> It may be possible to stop doing the fork-point computation in the\n> \"git rebase\" phase, and instead do it _before_ we run \"git fetch\",\n> to figure out what part of our history needs to be transplanted on\n> top of the upstream, run \"git fetch\" (to let the tracking branches\n> updated), and then run \"git rebase\", telling it exactly what range\n> should be transplanted onto which commit to update the branch\n> currently checked out.  That would be a much larger change.\n\n\"git pull\" already runs \"git merge-base --fork-point\" before it runs \n\"git fetch\". The problematic reflog entry comes from a previous push \nwhich pushes to a different server due to remote.<remote>.pushurl. \nBecause we've just successfully pushed the local branch the fork point \ncalculation thinks the remote tracking branch matches the local branch \nand so excludes all the local commits when we rebase but we didn't push \nit to the same server that we're fetching from. I wonder if we should \ndisable the fork point calculation when there is a pushurl set.\n\nThanks\n\nPhillip\n\n"},{"id":"532012","messageId":"xmqqpl8lg0u3.fsf@gitster.g","threadId":"64593","inReplyTo":"61f61218-1945-4efe-961a-e6cb4ac8c6a9@gmail.com","subject":"Re: bug: `git pull --rebase` breaks in the presence of pushurls","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2025-12-11T03:21:40Z","receivedAt":"2025-12-11T03:21:42Z","isPatch":false,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Phillip Wood <phillip.wood123@gmail.com> writes:\n\n> \"git pull\" already runs \"git merge-base --fork-point\" before it runs \n> \"git fetch\". The problematic reflog entry comes from a previous push \n> which pushes to a different server due to remote.<remote>.pushurl. \n\nAh, of course.  fork-point heuristics with a repository you yourself\npush into would not make all that sense, since you are in control\nwhen and what to push there in the first place :/.\n\n> Because we've just successfully pushed the local branch the fork point \n> calculation thinks the remote tracking branch matches the local branch \n> and so excludes all the local commits when we rebase but we didn't push \n> it to the same server that we're fetching from. I wonder if we should \n> disable the fork point calculation when there is a pushurl set.\n\nTempting thought.  Or educate users with diagnoses and advise()?\n\n"},{"id":"532018","messageId":"20251211053504.8758-1-jayatheerthkulkarni2005@gmail.com","threadId":"64593","inReplyTo":"xmqqpl8lg0u3.fsf@gitster.g","subject":"Re: bug: `git pull --rebase` breaks in the presence of pushurls","fromName":"K Jayatheerth","fromEmail":"jayatheerthkulkarni2005@gmail.com","sentAt":"2025-12-11T05:35:03Z","receivedAt":"2025-12-11T05:35:39Z","isPatch":false,"sender":{"key":"jayatheerthkulkarni2005@gmail.com","avatar":"https://avatars.githubusercontent.com/u/148841023?v=4"},"body":"I’m trying to make sure I fully understand where the fork-point behavior is coming from.\nI'm assuming get_rebase_fork_point() and get_rebase_newbase_and_upstream() are responsible.\n\nAnd when we talk about the “fork-point heuristic” here,\nwe mean the logic that uses the reflog of the upstream branch\nto detect whether the user has previously rebased or reset,\nand uses that information to choose a\ndifferent merge-base than the raw merge-base HEAD upstream, correct?\n\nJust checking that I’m following correctly\nbefore thinking about possible approaches.\n"},{"id":"532048","messageId":"3a6f39cf-b35e-461f-84a7-85e6e7376d21@gmail.com","threadId":"64593","inReplyTo":"20251211053504.8758-1-jayatheerthkulkarni2005@gmail.com","subject":"Re: bug: `git pull --rebase` breaks in the presence of pushurls","fromName":"Phillip Wood","fromEmail":"phillip.wood123@gmail.com","sentAt":"2025-12-11T15:54:33Z","receivedAt":"2025-12-11T15:54:39Z","isPatch":false,"sender":{"key":"phillip.wood@dunelm.org.uk","avatar":null},"body":"On 11/12/2025 05:35, K Jayatheerth wrote:\n> I’m trying to make sure I fully understand where the fork-point behavior is coming from.\n> I'm assuming get_rebase_fork_point() and get_rebase_newbase_and_upstream() are responsible.\n> \n> And when we talk about the “fork-point heuristic” here,\n> we mean the logic that uses the reflog of the upstream branch\n> to detect whether the user has previously rebased or reset,\n> and uses that information to choose a\n> different merge-base than the raw merge-base HEAD upstream, correct?\n\nAlmost, it uses the reflog of the upstream branch to find the most \nrecent entry that is a descendant of the local branch. It then uses that \ncommit to limit the range of commits that get rebased in case the \nupstream branch has been reset or rewritten. There is a diagram in the \ndocumentation [1] which might help.\n\nThanks\n\nPhillip\n\n[1] https://git-scm.com/docs/git-merge-base#_discussion_on_fork_point_mode\n\n> Just checking that I’m following correctly\n> before thinking about possible approaches.\n\n"},{"id":"532049","messageId":"177a25f0-7292-4ee7-8a02-9c90a5979313@gmail.com","threadId":"64593","inReplyTo":"xmqqpl8lg0u3.fsf@gitster.g","subject":"Re: bug: `git pull --rebase` breaks in the presence of pushurls","fromName":"Phillip Wood","fromEmail":"phillip.wood123@gmail.com","sentAt":"2025-12-11T15:56:17Z","receivedAt":"2025-12-11T15:56:22Z","isPatch":false,"sender":{"key":"phillip.wood@dunelm.org.uk","avatar":null},"body":"On 11/12/2025 03:21, Junio C Hamano wrote:\n> Phillip Wood <phillip.wood123@gmail.com> writes:\n> \n>> \"git pull\" already runs \"git merge-base --fork-point\" before it runs\n>> \"git fetch\". The problematic reflog entry comes from a previous push\n>> which pushes to a different server due to remote.<remote>.pushurl.\n> \n> Ah, of course.  fork-point heuristics with a repository you yourself\n> push into would not make all that sense, since you are in control\n> when and what to push there in the first place :/.\n> \n>> Because we've just successfully pushed the local branch the fork point\n>> calculation thinks the remote tracking branch matches the local branch\n>> and so excludes all the local commits when we rebase but we didn't push\n>> it to the same server that we're fetching from. I wonder if we should\n>> disable the fork point calculation when there is a pushurl set.\n> \n> Tempting thought.  Or educate users with diagnoses and advise()?\n\nIf we do that we'll also need to provide a way for the user to skip \nusing the fork point when pulling. At the moment I think there is way \nfor the user to turn it off.\n\nThanks\n\nPhillip\n"},{"id":"532053","messageId":"fd5f7f9a-8c2c-4222-9b16-309e9a6c587b@gmail.com","threadId":"64593","inReplyTo":"3a6f39cf-b35e-461f-84a7-85e6e7376d21@gmail.com","subject":"Re: bug: `git pull --rebase` breaks in the presence of pushurls","fromName":"Phillip Wood","fromEmail":"phillip.wood123@gmail.com","sentAt":"2025-12-11T19:39:08Z","receivedAt":"2025-12-11T19:39:15Z","isPatch":false,"sender":{"key":"phillip.wood@dunelm.org.uk","avatar":null},"body":"On 11/12/2025 15:54, Phillip Wood wrote:\n> On 11/12/2025 05:35, K Jayatheerth wrote:\n> Almost, it uses the reflog of the upstream branch to find the most \n> recent entry that is a descendant of the local branch.\n\nSorry that should say \"is an ancestor of the local branch\", it is trying \nto find the upstream reflog entry that the local branch is descended from.\n\n> It then uses that \n> commit to limit the range of commits that get rebased in case the \n> upstream branch has been reset or rewritten. There is a diagram in the \n> documentation [1] which might help.\n> \n> Thanks\n> \n> Phillip\n> \n> [1] https://git-scm.com/docs/git-merge-base#_discussion_on_fork_point_mode\n> \n>> Just checking that I’m following correctly\n>> before thinking about possible approaches.\n> \n\n"}]}