You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Pull() rebase conflict raises GitPullConflictException saying "mid-merge"; caller can't tell the repository is actually mid-rebase #242
GitPullBuilder.CreateException (GitIntegration/Builders/GitPullBuilder.cs:288-299) turns any failed pull whose stdout contains CONFLICT into a GitPullConflictException. Its own remarks (lines 280-285) say this covers both merge and rebase conflicts. The exception's documentation (GitIntegration/Execution/GitExceptions.cs:282-297) says "The repository is now mid-merge" and that git exits 128. Neither the exception nor the result says which operation actually stopped.
I reproduced this with git 2.43 using pull --rebase --progress and diverging commits that touch the same line. The result was:
The exit code is 1, not 128.
stdout is Auto-merging f / CONFLICT (content): Merge conflict in f.
The repository is left with .git/rebase-merge and REBASE_HEAD, and there is noMERGE_HEAD.
status --porcelain=v2 --branch reports # branch.head (detached) plus a u UU entry.
git merge --abort, which the "mid-merge" wording points the caller to, fails with fatal: There is no merge to abort (MERGE_HEAD missing) (exit 128).
Why it matters
This happens with .Rebase(). It also happens with a plain Pull() on any machine where pull.rebase=true is configured, because Pull() sets no reconciliation mode unless Merge() or Rebase() is called. In that case the caller may not even know a rebase was attempted. Recovery code written from the docs runs merge --abort, which fails and leaves the repository on a detached HEAD in the middle of a rebase.
Suggested fix / acceptance criteria
GitPullConflictException says which operation stopped, for example through a GitPullConflictKind { Merge, Rebase } property. The kind can be found by checking for REBASE_HEAD / rebase-merge after the failure. Checking the vector for --rebase alone misses the pull.rebase config case.
The exception remarks no longer claim "mid-merge" unconditionally or "exits 128"
An integration test in GitRemoteSyncTests covers a Rebase() conflict and asserts the kind
Another test covers a plain Pull() with pull.rebase=true set in the throwaway repository and asserts the kind
Priority: High. Recovery code written from the documentation runs merge --abort, which fails and leaves the repository on a detached HEAD in the middle of a rebase. A plain Pull() hits this on any machine with pull.rebase=true, so the caller may not know a rebase happened. The documented exit code (128) is also wrong (git exits 1).
Area / suggested assignment: GitIntegration pull builder and exceptions (GitPullBuilder.CreateException, GitPullConflictException).
Next step: Detect REBASE_HEAD or rebase-merge after the failure and expose a GitPullConflictKind. Fix the remarks, and add the Rebase() and pull.rebase=true integration tests.
Activity
matt-edmondson commentedon Oct 18, 2026
Triage
merge --abort, which fails and leaves the repository on a detached HEAD in the middle of a rebase. A plainPull()hits this on any machine withpull.rebase=true, so the caller may not know a rebase happened. The documented exit code (128) is also wrong (git exits 1).GitPullBuilder.CreateException,GitPullConflictException).REBASE_HEADorrebase-mergeafter the failure and expose aGitPullConflictKind. Fix the remarks, and add theRebase()andpull.rebase=trueintegration tests.Generated by Claude Code