[BUG] Claude Code should use --no-optional-locks for all internal git operations and document statusline git pitfalls

Resolved 💬 3 comments Opened Apr 14, 2026 by shannonriester Closed Apr 17, 2026

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-locks flag on all git commands
  • GIT_OPTIONAL_LOCKS=0 environment variable
  • Using git diff --quiet HEAD + git diff --cached --quiet instead of git 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

  1. Claude Code internal: Use --no-optional-locks for all background git operations (status polling, context gathering)
  2. Documentation: Add a warning to statusline documentation about git lock contention
  3. Default statusline: If Claude Code ships any default statusline with git commands, ensure they use --no-optional-locks
  4. 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

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"
  }
}

View original on GitHub ↗

This issue has 3 comments on GitHub. Read the full discussion on GitHub ↗