Claude Code で git index.lock が消えない問題と原因の特定
Claude Code を使っていると git add や git commit が index.lock で失敗し続ける問題にハマった。初歩的だけど原因の特定に手間取ったので記録しておく。
症状
Claude Code のセッション中に git コマンドを実行すると、ほぼ毎回これが出る。
fatal: Unable to create '.git/index.lock': File exists.
rm -f .git/index.lock で消しても数秒で再作成される。
最初に疑ったもの(ハズレ)
Cursor(VS Code 系 IDE)の git.autorefresh や git.autofetch が定期的に git status を叩いているのでは、と推測した。設定を false に変更し、Cursor を再起動してみたが解消しなかった。
拡張機能(GitHub Pull Requests 等)も疑って無効化したが変わらず。
犯人の特定
lock ファイルを消した直後にプロセスを確認する方法で特定できた。
rm -f .git/index.lock
# 再作成されるのを待って
ps aux | grep git
出力。
ota2000 18331 /opt/homebrew/opt/git/libexec/git-core/git status --porcelain=2
このプロセスの親を辿ると、Claude Code の statusline.js だった。Claude Code はターミナル下部にブランチ名と変更状態を表示するために、git status --porcelain を定期的に実行している。この実行時に index.lock が作られ、他の git コマンドと競合していた。
解決
GIT_OPTIONAL_LOCKS=0 という環境変数を設定すると、git は read-only な操作(git status 等)で lock ファイルを作らなくなる。
~/.claude/statusline.js を修正して、git コマンド実行時にこの環境変数を渡すようにした。
// Before
execSync('git status --porcelain', { encoding: 'utf8' });
// After
const gitEnv = { ...process.env, GIT_OPTIONAL_LOCKS: '0' };
execSync('git status --porcelain', { encoding: 'utf8', env: gitEnv });
加えて ~/.claude/settings.json の env にも追加しておいた。
{
"env": {
"GIT_OPTIONAL_LOCKS": "0"
}
}
これで lock ファイルは再作成されなくなった。
振り返り
IDE を疑って設定を変えたり再起動したりで 30 分くらい無駄にした。最初から ps aux | grep git していれば一瞬だった。index.lock が消えないときはプロセスを見る。これに尽きる。
GIT_OPTIONAL_LOCKS=0 は read-only な git 操作の lock を抑制する公式の仕組みで、git のドキュメントにも記載がある。statusline のようなバックグラウンドで git status を叩く仕組みには最初から入れておくべきだろう。