Skip to content

Branch switch times out after 10 seconds in large repos and leaves the working tree half-switched #22245

Description

@Daimonke

What happened

I switched branches with the branch picker in a large monorepo. The switch failed after about 10 seconds. The old branch was still checked out, but the working tree showed 3,918 deleted files, 2,241 modified files and 50 untracked files from the target branch.

It happened twice. The first time I didn't notice, and my next git pull --autostash stashed the broken tree and then conflicted when applying it back.

Diagnosis

switchRef runs git checkout with a fixed 10-second timeout:

// A stale ref must not turn into a path checkout that discards local edits.
yield* executeGitWithStableDiagnostics(
"GitVcsDriver.switchRef.checkout",
input.cwd,
[...checkoutArgs, "--"],
{
timeoutMs: 10_000,
fallbackErrorDetail: "git checkout failed",
},

In this repo, switching between the two branches rewrites about 6,000 files, some through Git LFS, so the checkout takes longer than 10 seconds. The timeout kills git after it has written part of the target branch's files, but before it updates the index and HEAD. Git can't roll back an interrupted checkout, so the working tree is left mixed and the UI shows only a generic failure.

Long-running commands such as push already pass timeoutMs: null (L2660). Checkout changes the working tree, so killing it partway does more damage than letting it finish. Running it without a timeout, or warning that the working tree may be partially updated when it fails, would avoid this.

Steps to reproduce

  1. Open a repo where switching between two branches rewrites enough files that git checkout takes more than 10 seconds (here about 6,000 files, with Git LFS).
  2. Switch to the other branch with the branch picker.
  3. After about 10 seconds the switch fails. git status shows thousands of changes and the old branch is still checked out.

Running the same git checkout <branch> in a terminal completes normally.

Version

0.1.1-nightly.20261019.3348

Environment

Windows desktop app, server in WSL2 (Ubuntu 24.04.4), git 2.43.0, git-lfs 3.4.1

Evidence

server.trace.ndjson:
GitVcsDriver.switchRef.checkout  durationMs=10025.5  2026-10-20 11:45:32
GitVcsDriver.switchRef.checkout  durationMs=10028.8  2026-10-20 12:06:23
GitCommandError: Git command failed in GitVcsDriver.switchRef.checkout (<repo>): Git command timed out.
cause: InterruptError: All fibers interrupted without error
    at runGitCommand

git status --short | cut -c1-2 | sort | uniq -c   (after the second failure)
   3918  D
   2241  M
     50 ??

Related issues

#15541 hits the fixed 5-minute git timeout during worktree creation. It's the same kind of problem, but a different code path and limit, so a fix there wouldn't cover branch switching.

Fix applied or workaround

Restored the old branch with git reset --hard HEAD and git clean -fd, then ran git checkout from a terminal, which completed.

Filed by

Claude Code (claude-opus-5-5) in a T3 Code thread

Activity

  1. juliusmarminge commented on Oct 21, 2026

    @juliusmarminge
    Member

    Reproduced on current main 70e5e384da using the web dev app with a Linux server. Switching from old to target through the branch picker in a disposable repository with a 15-second Git smudge filter failed after 10,008 ms. HEAD remained on old, while a tracked file contained target content. The same checkout in a terminal completed in 15.149 seconds. This reproduces the interrupted-checkout failure without the private monorepo; Windows/WSL2 and Git LFS remain unverified.

  2. mahmoodnizamani94-png commented on Nov 3, 2026

    @mahmoodnizamani94-png

    Hit this same 10-second timeout in GitVcsDriver.switchRef.checkout on v0.1.6 (latest stable release, not nightly; Linux x64, T3 Code Desktop 0.1.6 stable, git 2.56.0), filed with full details in #30368.

    One extra way this bites people is on a blobless partial clone (remote.origin.partialclonefilter=blob:none) when switching to an orphan/deployment branch that only holds binaries and none of the main source tree:

    1. git checkout unlinks all existing tracked files from the working directory right away (within ~20ms), then starts downloading the missing blobs for the target branch over the network.
    2. At 10 seconds (durationMs: 10014.5), GitVcsDriver.switchRef.checkout kills git checkout before it finishes fetching the blobs or updating HEAD.
    3. HEAD stays on the previous branch with the working tree completely wiped. If you then switch to main, git only writes out the few files that differ between the previous branch and main, leaving the rest of the repo deleted on disk.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    via-triageFiled through npx t3 triage

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions