科技 · 实用指南
Git 提示“cannot lock ref”?删除前先按报错后缀分类
“is at… but expected”“exists; cannot create”和“unable to resolve”不是同一种故障。先保留精确引用与 OID、停止竞争写入,再只修已证明的分支。

“Cannot lock ref”只是报错前缀,不是单一诊断。后半句才说明 Git 是输掉了预期旧 OID 的竞争、撞上层级命名冲突、读到损坏引用,还是无法创建锁。
删除任何内容前,先保存完整报错和当前引用值。随后停止后台抓取器或 CI 写入,按后缀分类,只做一次能保留更新工作的窄修复。
保留精确引用、报错后缀与 OID
复制完整报错、命令、仓库路径,并记录故障是本地发生还是带有“remote:”前缀。保存 git rev-parse --git-common-dir、git version、git status --short --branch 和报错中的完整引用。
对完整引用运行 git show-ref --verify,并用 git for-each-ref 查看相邻命名空间。修改前保存当前 OID 和远端公布值;预期旧 OID 不匹配可能说明另一写入者已经完成了有用更新。
把“is at A but expected B”当作竞争
这句话是比较并交换保护:Git 预期 B,却重新读到 A。先停止后台 fetch、IDE Git 集成和重叠 CI 作业,再确认谁改了引用,以及 A 是否与远端或已完成操作一致。
如果 A 有效,就只重新执行一次新的 fetch 或 push,让 Git 按当前状态计算。不要把 B 强制写回,也不要按通用配方删除引用,否则可能擦掉锁机制正在保护的更新。
有意识地处理命名空间与大小写冲突
遇到“X exists; cannot create X/Y”时,列出本地与远端的完整引用。文件型引用存储中,foo 会阻挡 foo/bar。与分支所有者决定要移动哪个名字,先保留目标 OID,再更新自动化和保护规则。
在 Windows 等大小写不敏感文件系统上,同时按字节和忽略大小写比较名称。干净克隆可验证存储冲突,但不能作为静默重命名远端分支的许可。
区分活动锁与损坏引用证据
遇到“unable to resolve reference”时,应通过 Git 命令检查完整引用,不要只查看 .git/refs 文件;引用可能是 packed、loose、symbolic 或保存在 reftable 中。运行 git fsck --full,把 packed-refs 只当证据,不要手工编辑。
看到 .lock 文件时,先证明没有 Git 进程、hook、IDE、备份或服务器任务持有它,并记录路径和时间。只有已停止操作遗留的孤儿锁才进入过期锁分支;权限、磁盘和损坏引用需各自处理。
验证一次窄修复并关闭根因
已证明需要修正本地引用时,优先使用带预期旧 OID 的 git update-ref。命名空间冲突按协定重命名或删除后再抓取;并发竞争则只需一次全新重试。
最后运行 git show-ref、git fsck --full 和一次 fetch 或 push,并对照远端 OID。记录根因是竞争写入、层级名称、大小写、被中断的锁、权限还是损坏引用,避免自动化重现。
