Repository navigation
Description
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
- 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.mkdir demo && cd demo python3 -c 'l="x"*79+"\n"; open("seed.txt","w").write(l*3000000)' for i in $(seq 1 34); do cp seed.txt part$i.txt; done && rm seed.txt
- Add the folder as a project (Add project → Local folder) and start a new thread in it. The thread details panel shows Initialize Git.
- 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 −0rows, 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):
16:35:24.575 ws.rpc.vcs.init 45 ms Success
16:35:24.623 VcsStatusBroadcaster.refreshStatus 31903 ms Success (ends 16:35:56.525)
16: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 @ 3f94487 (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):
c9579205-50b9-4791-ac75-41a9affb3407-414c6e10-e57c-43bc-8a52-129668c23813-mp4.mp4
Workaround
None in the app. A short wait, or restarting the server, brings the repository state up.
Related
- [Bug]: vcs.refreshStatus takes ~25s on branches with a large diff (--minimal in change-totals diff) #21858 is the same
readBranchChangeTotalsstep slow on a large diff. It was fixed in fix(server): avoid expensive diff minimization in status refreshes #21872 by dropping--minimal, which does not help here: the time goes to reading untracked files, not to diff minimization. - Overlapping VCS status refreshes multiply Git and network work #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)
Activity