[BUG] Desktop Code tab git polling still leaves orphaned .git/index.lock on large repos
Summary
The Claude Desktop app (Code tab) polls git in the background for every open session. On a large repository this still leaves an orphaned .git/index.lock from time to time. Any later git add, git commit or index update then fails until someone removes the lock by hand. This is the same family as #37198, #11005, #47721 and #50269. Those issues are closed or locked, so I am filing a fresh report with captured evidence, as the bot comment asks.
Environment
- Claude Desktop 2.26454.2 (Code tab), macOS 26.6.2
- git 2.50.1 (Apple) and 2.49.0 (Homebrew)
- Repository: about 159k tracked files on an external exFAT volume. Several Code sessions are open on the same repository at once.
- Repo config already tuned for size:
feature.manyFiles=true,index.version=4,core.untrackedCache=true,core.preloadIndex=true
Evidence
We ran a detached watcher that records every process touching the repository's git directory. It captured 9 orphaned locks over about 24 hours.
- We traced and fixed the sources inside our own scripts. Every one was a porcelain git command that a Python
subprocess.run(timeout=...)killed with SIGKILL. - Afterwards, one more orphan lock appeared at 11:04:35 local time. The only git processes that had started in the 30 seconds before it belonged to the desktop app.
- Two of them were children of
Claude Helper(the app's NodeService). Both started at 11:04:31, 4 seconds before the lock appeared. - Their command lines began with
git -c core.quotepath=false … -c diff.ignoreSubmodules=…, which is consistent with the sidebar'sgit diff --numstat/git statuspolling. - No other git writer was running.
Local experiments with git 2.49 on clean repositories gave these results:
git diff(porcelain, against the worktree or HEAD) refreshes and writes the index (refresh_index_quietly) even withGIT_OPTIONAL_LOCKS=0.git statusdoes honourGIT_OPTIONAL_LOCKS=0.git diff-index,git diff-filesandgit diff --cachednever write the index.- git removes its
index.lockon SIGTERM but not on SIGKILL. A poller that kills a slow git process with SIGKILL therefore leaves the lock behind. - On a large repository a single refresh can hold the lock for 10–60 s, so a poll that times out is likely to hit this.
Expected
Background polling should never be able to leave .git/index.lock behind, and it should not compete with the user's own index writes.
Suggestions
- Run every read-only poll with
--no-optional-locks(orGIT_OPTIONAL_LOCKS=0). - Use plumbing instead of porcelain
git difffor change counts, because porcelain diff refreshes the index anyway. For example,git diff-index --numstat HEADalso skips stat-only changes. - On timeout, send SIGTERM to the git process group, allow a short grace period, and only then SIGKILL. Never SIGKILL git first.
- Add a per-project setting to turn off or slow down git polling for large repositories, as #50269 requested.
Thanks!
This issue has 1 comment on GitHub. Read the full discussion on GitHub ↗