Skip to content

feat(git): friendly checkout error messages with stash & switch recovery#1785

Open
Marve10s wants to merge 16 commits intopingdotgg:mainfrom
Marve10s:feat/checkout-dirty-worktree-error-handling
Open

feat(git): friendly checkout error messages with stash & switch recovery#1785
Marve10s wants to merge 16 commits intopingdotgg:mainfrom
Marve10s:feat/checkout-dirty-worktree-error-handling

Conversation

@Marve10s
Copy link
Copy Markdown
Contributor

@Marve10s Marve10s commented Apr 6, 2026

Summary

  • When git checkout fails because the working tree has uncommitted changes, the app now shows a friendly "Uncommitted changes block checkout" error toast listing the conflicting files — instead of dumping a raw GitCommandError stack trace with internal file paths
  • The error toast includes a "Stash & Switch" action button that stashes changes, checks out the target branch, and attempts to pop the stash on the new branch
  • If the stash cannot be applied cleanly (e.g. the target branch doesn't have the same files), the server resets the merge state, cleans up orphaned untracked files, and keeps the stash entry safe. The UI shows a warning toast with a "Discard stash" button (with confirmation dialog) to drop the stash
  • Both "Your local changes would be overwritten" and "untracked working tree files would be overwritten" git error variants are now detected and handled with the same friendly UX
  • The "you need to resolve your current index" error (which previously showed a raw stack trace) now shows a clear "Unresolved conflicts in the repository" message
  • Toast layout restructured: copy and action buttons now render below the description instead of floating inline with the title. Copy button extended to warning-type toasts
  • Adds GitCheckoutDirtyWorktreeError tagged error, stashAndCheckout and stashDrop WS methods end-to-end (contracts → server → client)

Note

Medium Risk
Changes git branch checkout error handling and adds new stash-based recovery commands end-to-end (contracts/RPC/server/client), which could affect branch switching flows and stash state on failure paths.

Overview
Improves branch switching UX by returning a structured GitCheckoutDirtyWorktreeError (including conflicting file list) when checkoutBranch fails due to dirty or untracked-overwrite worktree state, instead of only generic GitCommandError.

Adds new git operations stashAndCheckout and stashDrop in GitCore with defensive cleanup for failed stash pop, and wires them through contracts + WS RPC (gitStashAndCheckout, gitStashDrop) to the web client.

Updates the branch selector to detect dirty-worktree and unresolved-index errors, show friendlier toasts with a "Stash & Switch" action (and optional "Discard stash" flow on stash-pop conflicts), and tweaks toast layout so action/copy controls render under the description (including copy for warning toasts).

Reviewed by Cursor Bugbot for commit 23cb962. Bugbot is set up for automated code reviews on this repo. Configure here.

Note

Add stash & switch recovery flow with friendly checkout error messages

  • Adds stashAndCheckout and stashDrop operations to GitCore and exposes them as WebSocket RPC endpoints (gitStashAndCheckout, gitStashDrop).
  • checkoutBranch now returns a typed GitCheckoutDirtyWorktreeError (including conflicting files and target branch) instead of a generic error when local or untracked changes block a checkout.
  • In the branch selector UI, checkout errors now show actionable toasts: a 'Stash & Switch' option triggers stashAndCheckout, and on stash conflict a 'Discard stash' option triggers stashDrop.
  • Toast layout is updated to place action and copy buttons in a footer row below the description, and copy buttons now appear on warning toasts as well.
  • Behavioral Change: createBranch with checkout now emits a GitCommandError (not GitCheckoutDirtyWorktreeError) on dirty worktree failures to preserve operation-specific messaging.

Macroscope summarized 23cb962.

@github-actions github-actions bot added size:L 100-499 changed lines (additions + deletions). vouch:unvouched PR author is not yet trusted in the VOUCHED list. labels Apr 6, 2026
@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Apr 6, 2026

Important

Review skipped

Auto reviews are disabled on this repository. Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: Repository UI

Review profile: CHILL

Plan: Pro

Run ID: 0ce38ac8-5fd4-4067-9000-0d84608d52f9

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Comment thread apps/server/src/git/Layers/GitCore.ts
Comment thread apps/web/src/components/BranchToolbarBranchSelector.tsx Outdated
Comment thread apps/web/src/components/BranchToolbarBranchSelector.tsx Outdated
Comment thread apps/web/src/components/BranchToolbarBranchSelector.tsx Outdated
@Marve10s Marve10s force-pushed the feat/checkout-dirty-worktree-error-handling branch 2 times, most recently from 0ed6af8 to 6709644 Compare April 6, 2026 17:38
@macroscopeapp
Copy link
Copy Markdown
Contributor

macroscopeapp bot commented Apr 6, 2026

Approvability

Verdict: Needs human review

This PR introduces a new user-facing feature for git checkout error recovery with stash & switch functionality. It adds new RPC endpoints, new error types, and new UI flows (actionable toasts with 'Stash & Switch' button). The scope and new user-facing behavior warrant human review.

You can customize Macroscope's approvability policy. Learn more.

@Marve10s Marve10s force-pushed the feat/checkout-dirty-worktree-error-handling branch 2 times, most recently from ebe2610 to 0ff3bdc Compare April 6, 2026 17:47
Comment thread apps/web/src/components/BranchToolbarBranchSelector.tsx
Comment thread apps/web/src/components/BranchToolbarBranchSelector.tsx Outdated
@Marve10s Marve10s force-pushed the feat/checkout-dirty-worktree-error-handling branch 2 times, most recently from 0252c65 to 042a9d9 Compare April 6, 2026 18:12
@Marve10s
Copy link
Copy Markdown
Contributor Author

Marve10s commented Apr 6, 2026

Before :
before-1-dirty-checkout-raw-error
before-2-untracked-raw-error

After :
after-1-friendly-error-with-stash-button
after-2-stash-conflict-warning-with-discard
If users tried to discard stash - shows a modal with approval.

Replace raw GitCommandError stack traces with structured, user-friendly
error handling when branch checkout fails due to uncommitted changes.
@Marve10s Marve10s force-pushed the feat/checkout-dirty-worktree-error-handling branch from 042a9d9 to c3cac0a Compare April 6, 2026 18:17
Comment thread apps/server/src/git/Layers/GitCore.test.ts
Comment thread packages/contracts/src/git.ts
Comment thread apps/server/src/git/Layers/GitCore.ts Outdated
Comment thread apps/web/src/components/BranchToolbarBranchSelector.tsx
@sashaduke
Copy link
Copy Markdown

+1, I have an error of a different kind that spills out so much i cant even close the toast so im gonna make a similar PR but this is useful

Resolve merge conflicts:
- BranchToolbarBranchSelector.tsx: adapt imports to LocalApi/EnvironmentApi split
- ipc.ts: move stashAndCheckout/stashDrop to EnvironmentApi.git (not LocalApi)
- wsNativeApi.ts: accept upstream deletion (replaced by localApi.ts + environmentApi.ts)
Comment thread apps/web/src/components/BranchToolbarBranchSelector.tsx
@github-actions github-actions bot added size:XL 500-999 changed lines (additions + deletions). and removed size:L 100-499 changed lines (additions + deletions). labels Apr 9, 2026
Comment thread apps/web/src/components/BranchToolbarBranchSelector.tsx
Comment thread apps/server/src/git/Layers/GitCore.ts
Comment thread apps/web/src/components/BranchToolbarBranchSelector.tsx
- Add stashAndCheckout/stashDrop to EnvironmentApi bindings and RPC wiring
- Replace useOptimistic with useState to work without useTransition
- Wrap toast actions in runBranchAction for concurrency safety
- Pass environmentId through checkout error context for query invalidation
- Add missing Cause import for GitCore stash error handling
- Use --include-untracked in stash cleanup to capture all remnants
@Marve10s Marve10s force-pushed the feat/checkout-dirty-worktree-error-handling branch from 3662ac5 to e3db0ea Compare April 9, 2026 15:08
Comment thread apps/web/src/components/BranchToolbarBranchSelector.tsx
Resolve merge conflicts:
- GitCore.ts service: combine Context import with new Scope type import
- ws.ts: take upstream's refactored replayEvents handler, add new
  gitStashAndCheckout and gitStashDrop method registrations
- BranchToolbarBranchSelector.tsx: combine PR imports (EnvironmentApi,
  QueryClient, invalidateGitQueries, readLocalApi) with upstream's new
  imports (scopeProjectRef, scopeThreadRef, ThreadId, DraftId, etc.)
Comment thread apps/web/src/components/BranchToolbarBranchSelector.tsx
Comment thread apps/server/src/ws.ts
Comment thread apps/server/src/git/Layers/GitCore.ts
…tent dirty worktree errors

- Add refreshGitStatus(input.cwd) to the gitStashDrop WS handler so
  clients see updated stash state after a drop, matching all other
  git mutation handlers.
- Detect when stashAndCheckout fails because ignored files still
  conflict (stash -u doesn't capture .gitignore'd files) and show
  an actionable error instead of a confusing dirty-worktree message.
Comment thread apps/web/src/components/BranchToolbarBranchSelector.tsx
…-worktree-error-handling

# Conflicts:
#	apps/server/src/git/Layers/GitCore.test.ts
#	apps/server/src/git/Layers/GitCore.ts
Comment thread apps/web/src/components/BranchToolbarBranchSelector.tsx
Comment thread apps/web/src/components/BranchToolbarBranchSelector.tsx
Copy link
Copy Markdown
Contributor

@cursor cursor bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cursor Bugbot has reviewed your changes and found 1 potential issue.

Fix All in Cursor

❌ Bugbot Autofix is OFF. To automatically fix reported issues with cloud agents, enable autofix in the Cursor dashboard.

Reviewed by Cursor Bugbot for commit 019345b. Configure here.

Comment thread apps/server/src/git/Services/GitCore.ts Outdated
Comment thread apps/server/src/git/Layers/GitCore.ts
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:XL 500-999 changed lines (additions + deletions). vouch:unvouched PR author is not yet trusted in the VOUCHED list.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants