[BUG] Claude Code should use --no-optional-locks for all internal git operations and document statusline git pitfalls
Problem
Stale .git/index.lock files continue to block git operations for Claude Code users. The original issue #11005 was auto-closed despite active discussion and no official fix.
This affects daily workflow — when the lock file appears, all git operations (commit, stash, rebase, checkout) fail until the user manually removes it.
Root Causes
1. Statusline scripts using git status --porcelain
The most common cause. Many statusline scripts (including official examples and community tools like claude-powerline) use git status --porcelain to show dirty state. This command acquires an index lock, and when it races with Claude Code's own git operations (or the user's), stale locks are created.
Fix: Claude Code's statusline documentation should explicitly warn against using git status and recommend either:
--no-optional-locksflag on all git commandsGIT_OPTIONAL_LOCKS=0environment variable- Using
git diff --quiet HEAD+git diff --cached --quietinstead ofgit status --porcelain
2. Claude Code's internal git polling
Claude Code runs frequent background git commands for context. These should all use --no-optional-locks to avoid competing with user operations and statusline scripts.
Verified Fix
Replacing git status --porcelain with git --no-optional-locks diff --quiet HEAD in my statusline script completely eliminates the issue. Stress tested with 30 concurrent invocations — zero lock files created.
Environment
- macOS Darwin 25.4.0
- Claude Code (latest)
- Git 2.x
- Large monorepo (~100k files)
Requested Changes
- Claude Code internal: Use
--no-optional-locksfor all background git operations (status polling, context gathering) - Documentation: Add a warning to statusline documentation about git lock contention
- Default statusline: If Claude Code ships any default statusline with git commands, ensure they use
--no-optional-locks - Defensive cleanup: Consider auto-cleaning stale 0-byte lock files that are older than 30 seconds with no holding process (check via
lsof)
Related Issues
- #11005 (auto-closed, locked — 40+ affected users)
- #28546 (Windows variant)
- #28823 (lint-staged race condition variant)
- #10078 (zombie git processes)
- Cursor forum threads: https://forum.cursor.com/t/git-lock-file-issue-in-cursor/149747
Workaround
For anyone hitting this now, replace git status --porcelain in your statusline with:
# Instead of: git status --porcelain
# Use:
if ! git --no-optional-locks diff --quiet HEAD 2>/dev/null || \
! git --no-optional-locks diff --cached --quiet 2>/dev/null; then
git_dirty="*"
fi
Or prefix your entire statusline command with GIT_OPTIONAL_LOCKS=0:
{
"statusLine": {
"type": "command",
"command": "GIT_OPTIONAL_LOCKS=0 ~/.claude/statusline.sh"
}
}This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗