“fatal: Unable to create ‘.git/index.lock’: File exists.” 的标准答案是 rm .git/index.lock。这篇在本机复现它,看哪些命令真的被挡、什么情况下是真有进程握着锁(不能删)、手工删了会发生什么,以及并发时撞锁的概率有多高。
$ touch .git/index.lock && ls -l .git/index.lock | awk '{print $5, $NF}'
0 .git/index.lock
$ git add b.txt (退出码 128)
fatal: Unable to create '<tmp>/repo/.git/index.lock': File exists.
Another git process seems to be running in this repository, or the lock file may be stale
逐个命令(只看是否因为 index.lock 失败):
git add b.txt 退出码 128 被 index.lock 挡住
git commit -m x --allow-empty 退出码 128 被 index.lock 挡住
git checkout -b newbr 退出码 0 不受影响
git switch -c newbr2 退出码 0 不受影响
git reset 退出码 128 被 index.lock 挡住
git stash -u 退出码 1 被 index.lock 挡住
git merge --ff-only HEAD 退出码 0 不受影响
git rm --cached a.txt 退出码 128 被 index.lock 挡住
git status 退出码 0 不受影响
git log --oneline 退出码 0 不受影响
git diff 退出码 0 不受影响
git branch 退出码 0 不受影响
git show HEAD --stat 退出码 0 不受影响
git tag t1 退出码 0 不受影响写暂存区的命令被挡,读操作和新建分支不受影响。
钩子运行到第 1 秒时 git commit(先 add 好):.git/index.lock 不存在
钩子运行到第 1 秒时 git commit -a:.git/index.lock 存在
钩子运行到第 1 秒时 git commit -m x a.txt(指定文件):.git/index.lock 存在
$ ls .git/index.lock && git add b.txt (退出码 128)
.git/index.lock
fatal: Unable to create '<tmp>/repo/.git/index.lock': File exists.
Another git process seems to be running in this repository, or the lock file may be stale
此时那个 git commit 还在运行:True
$ ls .git/index.lock 2>&1 | tail -1; git log --oneline | head -3
ls: .git/index.lock: No such file or directory
42711f0 x
2fd4b32 c1commit -a 或指定文件的 commit 在钩子运行期间握着锁;普通 commit 不握。
$ rm .git/index.lock && echo "已删除锁文件(commit 还在跑钩子)" && git add b.txt && git status --short
已删除锁文件(commit 还在跑钩子)
M a.txt
A b.txt
被删锁的那个 git commit(退出码 128):
fatal: repository has been updated, but unable to write
new index file. Check that disk is not full and quota is
not exceeded, and then "git restore --staged :/" to recover.
$ git log --oneline | head -3; git status --short
47315ae x
2fd4b32 c1
AM a.txt
A b.txt没有 git 进程时删掉就行;进程在跑时删锁会让它报 repository has been updated, but unable to write new index file,暂存区状态错乱。
.git/HEAD.lock 存在时 git commit -qam x --allow-empty(退出码 128):
fatal: cannot lock ref 'HEAD': Unable to create '<tmp>/repo/.git/HEAD.lock': File exists.
Another git process seems to be running in this repository, or the lock file may be stale
.git/refs/heads/main.lock 存在时 git commit -qm x --allow-empty(退出码 128):
fatal: cannot lock ref 'HEAD': Unable to create '<tmp>/repo/.git/refs/heads/main.lock': File exists.
Another git process seems to be running in this repository, or the lock file may be stale
.git/config.lock 存在时 git config user.name Bob(退出码 255):
error: could not lock config file .git/config: File exists
.git/packed-refs.lock 存在时 git pack-refs --all(退出码 128):
fatal: Unable to create '<tmp>/repo/.git/packed-refs.lock': File exists.
Another git process seems to be running in this repository, or the lock file may be stale
.git/shallow.lock 存在时 git fetch --depth 1 ../repo 2>&1 | head -1(退出码 0):
fatal: Unable to create '<tmp>/repo/.git/shallow.lock': File exists.HEAD.lock、config.lock、packed-refs.lock 的报错措辞各不相同,看路径删对应的。
两个并行进程各 add 100 个文件:失败 40 次 + 40 次,共 200 次里 80 次;最后真正进入暂存区的 f*.txt 文件 120 个(用时 1.49 s)
两个进程同时 add 一半会失败,锁不会等待,直接报错。