Watch at Ease看見世界,讀懂生活。

科技 · 實用指南

Git 顯示「cannot lock ref」?刪除前先依錯誤後綴分類

「is at… but expected」、「exists; cannot create」和「unable to resolve」是不同故障。先保留精確引用與 OID、停止競爭寫入,再只修已證明的分支。

原創插畫:區分預期舊 OID 競爭、引用命名空間衝突,以及引用損壞或作用中鎖定。
原創插畫:變更引用前先依完整錯誤後綴分類。 Watch at Ease

「Cannot lock ref」只是錯誤前綴,不是單一診斷。後半句才說明 Git 是失去預期舊 OID 的競爭、遇到階層名稱衝突、讀到損壞引用,還是無法建立鎖定。

刪除任何東西前,先保存完整錯誤和目前引用值。接著停止背景抓取器或 CI 寫入,依後綴分類,只做一次能保留較新工作的窄修復。

保留精確引用、後綴與 OID

複製完整錯誤、命令、repository 路徑,並記錄是本地故障或帶「remote:」前綴。保存 git rev-parse --git-common-dir、git version、git status --short --branch 與完整引用。

對完整引用執行 git show-ref --verify,並用 git for-each-ref 檢視相鄰命名空間。變更前保存目前 OID 與遠端值;不匹配可能是另一寫入者已完成有效更新。

把「is at A but expected B」當作競爭

這是 compare-and-swap 保護:Git 預期 B,重新讀到 A。先停止背景 fetch、IDE Git 整合與重疊 CI,再確認誰改了引用及 A 是否有效。

如果 A 有效,只重新執行一次新的 fetch 或 push。不要強制寫回 B 或刪除引用,否則可能抹掉鎖定正在保護的更新。

刻意處理命名空間與大小寫衝突

遇到「X exists; cannot create X/Y」時列出本地與遠端完整引用。檔案型儲存中 foo 會阻擋 foo/bar。與所有者決定名稱並先保存 OID。

在 Windows 等不分大小寫系統上,同時比較原始名稱與忽略大小寫的名稱。乾淨 clone 可確認衝突,但不是靜默改遠端名稱的許可。

區分作用中鎖定與損壞引用

遇到「unable to resolve reference」時以 Git 命令檢查完整引用;它可能是 packed、loose、symbolic 或 reftable。執行 git fsck --full,不要手改 packed-refs。

若有 .lock,先證明沒有 Git process、hook、IDE、備份或伺服器工作持有它。只有停止操作留下的孤兒鎖定才是 stale lock;權限、磁碟與損壞引用要分開修。

驗證窄修復並關閉根因

已證明要修本地引用時,優先用帶 expected old OID 的 git update-ref。命名衝突依協議 rename 或 delete 後再 fetch;競爭則做一次 fresh retry。

最後執行 git show-ref、git fsck --full 與一次 fetch 或 push,對照遠端 OID,並記錄並行寫入、階層名稱、大小寫、中斷鎖定、權限或損壞引用。

原創插畫:顯示 Git 引用鎖定故障的觀察、隔離、修復與驗證。
原創插畫:保留 OID、隔離寫入者、只做一次窄修復再驗證。 Watch at Ease