[Bug]: Initialize Git gives no confirmation for ~30 s when the folder holds a lot of untracked data (change-totals diff times out)#25558

opened10d agobyKkaovilai

Before submitting

  • I searched existing issues and did not find a duplicate.
  • I included enough detail to reproduce or investigate the problem.

Area

apps/server (the button feedback part is in apps/web)

Steps to reproduce

  1. Make a folder that is not a git repository and holds a lot of untracked data. About 8 GB across 34 text files of 240 MB each reproduces it on an SSD. Each file must stay under git's 512 MB core.bigFileThreshold, otherwise git treats it as binary and skips counting its lines.
    sh
    1mkdir demo && cd demo
    2python3 -c 'l="x"*79+"\n"; open("seed.txt","w").write(l*3000000)'
    3for i in $(seq 1 34); do cp seed.txt part$i.txt; done && rm seed.txt
  2. Add the folder as a project (Add project → Local folder) and start a new thread in it. The thread details panel shows Initialize Git.
  3. Click Initialize Git.

Expected behavior

git init takes tens of milliseconds, so the thread should switch to its repository state (branch name, Commit, Changes) right away. At minimum the button should show a busy state until that happens.

Actual behavior

The UI does not confirm the init for about 30 seconds. After that the branch name, Commit and Changes controls become usable.

  • In the recording below, the button is replaced about a second after the click by dimmed, inert main / Commit / Changes +0 −0 rows, which stay that way for about 30 s.
  • In another run, the button stayed enabled and unchanged for more than 8 s after the click, with no pending or disabled state.
  • In neither run is there a spinner, a toast or any other sign that something is happening.

Server trace for the recorded run (ws.rpc.vcs.init returns almost immediately, then the status refresh blocks):

116:35:24.575 ws.rpc.vcs.init 45 ms Success
216:35:24.623 VcsStatusBroadcaster.refreshStatus 31903 ms Success (ends 16:35:56.525)
316:35:26.451 GitVcsDriver.readBranchChangeTotals 30023 ms Failure (git diff --numstat hit the 30 s default timeout)

The first status update after init is built by readLocalStatus, which also computes the "Changes" row totals through readBranchChangeTotals in apps/server/src/vcs/GitVcsDriverCore.ts. For a repository with no commits, that runs git diff --numstat against the empty tree with every untracked file added to a temporary index. Git reads each file to count lines. REVIEW_UNTRACKED_MAX_FILES limits the file count but not the total size. The call has no timeout of its own, so it waits for the 30 s default; the failure is then swallowed (Effect.orElseSucceed(() => undefined)), and only after that does the isRepo: true status reach the client.

The same totals are recomputed on every status refresh. In the traces of my regular install (a large, mostly untracked folder), each 30 s status poll hit the same 30 s timeout.

Impact

Minor bug or occasional failure

Version or commit

main @ 3f9448747b (dev server, vp run dev, isolated state)

Environment

macOS 26 (Darwin 25.6), T3 Code web client in the in-app Browser panel, git 2.53

Logs or stack traces

See the spans above.

Screenshots, recordings, or supporting files

Recording of the run above (about 40 s):

https://github.com/user-attachments/assets/e9cf5d48-8d9f-4a45-8ec3-a06ef6143419

Workaround

None in the app. A short wait, or restarting the server, brings the repository state up.

  • #21858 is the same readBranchChangeTotals step slow on a large diff. It was fixed in #21872 by dropping --minimal, which does not help here: the time goes to reading untracked files, not to diff minimization.
  • #7076 covers overlapping status refreshes multiplying git work.

I have a small fix ready (a short timeout on the totals diff, so the row falls back to the uncommitted totals, plus keeping the button busy until the status reports the new repository). I'll wait for triage before opening a PR.

Note

Responses generated with Claude (model: Claude Sonnet 5.5)