Skip to content

fix(web,server): picking the previous branch after an agent's checkout switches back - #30107

Open
Yuruzuu wants to merge 4 commits into
pingdotgg:mainfrom
Yuruzuu:fix/branch-switch-after-agent-checkout
Open

Yuruzuu wants to merge 4 commits into
pingdotgg:mainfrom
Yuruzuu:fix/branch-switch-after-agent-checkout

Conversation

@Yuruzuu

@Yuruzuu Yuruzuu commented Nov 3, 2026

Copy link
Copy Markdown
Contributor

Problem

When an agent runs git switch itself, picking the previously current branch in the branch picker (composer or thread details) did nothing. The thread recorded the old branch, but git stayed on the agent's branch. maria-rcks found this while verifying #28575 (comment), and it reproduces on main.

Change

The picker skips vcs.switchRef when a ref claims a worktreePath ("reuse that worktree"). That claim came from data that a provider's own checkout never invalidates:

  • listRefs serves a snapshot cached for 2 minutes, plus the current branch from a path cache kept for 10 minutes. Both still mapped the old branch to this checkout.
  • The web picker keeps its mounted ref list and doesn't refetch it before a selection.

Now:

  • listRefs reads this checkout's HEAD (git symbolic-ref, run in parallel with the snapshot read). If HEAD disagrees with the cache, it invalidates the snapshot and re-reads it. This adds one subprocess per listRefs call and nothing to status reads.
  • Before taking the reuse shortcut, the web picker confirms the claim with an uncached readRefs. If that read fails or misses the ref, it runs a real checkout, and Git refuses that if the branch is checked out in another worktree.

Mobile always calls switchRef, so it was not affected. No contract changes.

Scope and approval

This qualifies for the small, focused bug-fix exception in CONTRIBUTING.md. It makes the branch picker switch branches as asked, without adding a feature, changing defaults, or altering contracts.

Verification

  • New GitVcsDriverCore.test.ts case, "follows a checkout made outside the driver after refs were cached". It warms listRefs, switches with plain git, and checks the refs, switchRef back, and detached HEAD. It fails on main (the stale ref still has this worktreePath) and passes here.
  • vp run check:changed: format, lint, knip, and typecheck pass. All 234 GitVcsDriverCore.test.ts cases pass except "keeps generated worktree folders short…", which fails identically on main on macOS (/var vs /private/var).
  • Real web client: Chrome, dev server with Replay (dev), scratch repo with main and feature/agent. I opened the picker to warm it, ran git switch feature/agent in the workspace, then picked main.
Before (main) After (this branch)
picker before picker after
after selecting main, before after selecting main, after

On main, git stays on feature/agent. On this branch, git branch --show-current prints main after the selection.

Made with Claude Opus 5.5 via Claude Code in T3 Code.

🤖 Generated with Claude Code

…t switches back

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@github-actions github-actions Bot added vouch:unvouched PR author is not yet trusted in the VOUCHED list. size:M 30-99 changed lines (additions + deletions). labels Nov 3, 2026
@macroscopeapp

macroscopeapp Bot commented Nov 3, 2026

Copy link
Copy Markdown
Contributor

Approvability

Verdict: Needs Human Approval

Macroscope's review found this PR requires human approval — The change refreshes stale branch/worktree metadata after agent checkouts. An unresolved finding identifies overlapping selections that can leave the thread on the wrong worktree; selection ordering needs resolution before release.

Needs human approval because:

  • 1 blocking correctness issue found at or above your repo's Minimum Blocking Severity

Adjust the Minimum Blocking Severity for this repo — including turning it Off — in Settings. You can add or adjust custom eligibility rules. Learn more.

@coderabbitai

coderabbitai Bot commented Nov 3, 2026 •

Copy link
Copy Markdown
Contributor

Review in Change Stack →

No actionable comments were generated in the recent review.

Walkthrough

The server detects when the current Git branch differs from cached branch data and reloads refs. The branch selector confirms listed refs with a fresh read before it reuses a worktree path.

Changes: Branch state refresh

Layer / File(s) Summary
Detect external checkout changes
apps/server/src/vcs/GitVcsDriverCore.ts, apps/server/src/vcs/GitVcsDriverCore.test.ts
listRefs reads HEAD and reloads the refs snapshot when the live branch differs from cached branch data. Tests cover external branch changes, detached HEAD, and cached snapshot reads.
Validate refs before worktree reuse
apps/web/src/components/BranchToolbar.logic.ts, apps/web/src/components/BranchToolbar.logic.test.ts, apps/web/src/components/BranchToolbarBranchSelector.tsx
The selector reads refs before reusing a listed worktree path. It uses a matching fresh ref when found, clears the worktree path after a failed or complete read without a match, and retains the listed path when the read is truncated. Selection closes the picker and requests composer focus before confirmation. A later selection supersedes an earlier confirmation still in progress.

Estimated code review effort: 3 (Moderate) | ~20 minutes

Change: Bug fix

Possibly related issues

  • pingdotgg/t3code#27437 — The changes refresh cached refs after external Git changes and confirm refs before worktree reuse. They may not cover every added or deleted ref.
  • pingdotgg/t3code#27336 — The changes check live checkout state before branch-picker worktree reuse, but do not change checkpoint attribution.
  • pingdotgg/t3code#17813 — The changes check live checkout state before worktree reuse, but do not reconcile cleanup with stored branch records.
  • pingdotgg/t3code#11078 — The changes address live Git state for branch-picker worktree claims, but do not update sidebar labels.

Suggested reviewers: juliusmarminge

Merge Risk: Low · up to 153f8

A message sent immediately after choosing a branch may start in the previous worktree. This bounded timing risk merits owner awareness.

Pre-merge checks: Passed 4
Check name Status Explanation
Title check Passed The title is a concise conventional-commit title that identifies the web and server fix for branch selection after an agent checkout.
Description check Passed The description includes the required Problem, Change, Scope and approval, and Verification sections. It explains the bug, implementation, approval exception, focused tests, known baseline failure, ma…
Linked Issues check Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check Passed Check skipped because no linked issues were found for this pull request.
Full details: Description check

Explanation

The description includes the required Problem, Change, Scope and approval, and Verification sections. It explains the bug, implementation, approval exception, focused tests, known baseline failure, manual UI verification, screenshots, and agent details.

Finishing Touches
Generate unit tests (beta)
  • Create a new PR
  • Autofix · Keep fixing CodeRabbit findings and required CI, and resolving merge conflicts

CodeRabbit Verify

  • Run CodeRabbit Verify to test the changes in this pull request.
Recent review info
Run configuration
Commits

Reviewing files that changed from the base of the PR and between 7fb8a04 and 153f872.

Files selected for processing: 3
  • apps/web/src/components/BranchToolbar.logic.test.ts
  • apps/web/src/components/BranchToolbar.logic.ts
  • apps/web/src/components/BranchToolbarBranchSelector.tsx

Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 6 remain after this review.

@coderabbitai coderabbitai Bot left a comment •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

  • Fix comments: Fix CodeRabbit comments on this PR

Comment thread apps/server/src/vcs/GitVcsDriverCore.ts Resolved
… cases

listRefs no longer matches a null worktree root against branches without a
worktree, which made every call reread refs when worktree metadata is missing.
The picker keeps its worktree claim when its confirming read was truncated.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

@coderabbitai coderabbitai Bot left a comment •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

  • Fix comments: Fix CodeRabbit comments on this PR

…ne page

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@github-actions github-actions Bot added size:L 100-499 changed lines (additions + deletions). and removed size:M 30-99 changed lines (additions + deletions). labels Nov 3, 2026
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

size:L 100-499 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.

1 participant