기술 · 실용 가이드
Git의 “cannot lock ref”? 삭제 전에 오류 접미사를 분류하세요
“is at… but expected”, “exists; cannot create”, “unable to resolve”는 서로 다른 실패입니다. 정확한 ref와 OID를 보존하고 경쟁 writer를 멈춘 뒤 증명된 분기만 복구하세요.

“Cannot lock ref”는 오류 접두사일 뿐 하나의 진단이 아닙니다. 나머지 문장이 expected old OID 경쟁, 계층 이름 충돌, 깨진 ref 또는 lock 생성 실패를 알려 줍니다.
무엇도 삭제하기 전에 전체 줄과 현재 ref 값을 저장하세요. background fetcher나 CI writer를 멈추고 접미사를 분류한 뒤 새로운 작업을 보존하는 좁은 수정만 수행합니다.
정확한 ref, 접미사, OID 보존
전체 오류, command, repository path와 “remote:” 접두사 여부를 저장합니다. git rev-parse --git-common-dir, git version, git status --short --branch, 전체 ref 이름도 기록합니다.
전체 ref에 git show-ref --verify를 사용하고 git for-each-ref로 주변 namespace를 봅니다. 변경 전에 현재 OID와 remote 광고 값을 보존하세요.
“is at A but expected B”를 경쟁으로 처리
이는 compare-and-swap 보호입니다. Git은 B를 기대했지만 A를 다시 읽었습니다. background fetch, IDE Git, 겹친 CI를 멈추고 누가 ref를 바꿨는지 확인합니다.
A가 유효하면 fresh fetch나 push를 한 번만 다시 실행합니다. B를 강제로 되돌리거나 ref를 삭제하면 보호된 새 작업을 잃을 수 있습니다.
namespace와 대소문자 충돌 해결
“X exists; cannot create X/Y”에서는 local과 remote ref를 모두 나열합니다. file 기반 저장에서 foo는 foo/bar를 막습니다. owner와 이름을 합의하고 OID를 보존한 뒤 변경합니다.
Windows 등에서는 case-insensitive 비교도 합니다. clean clone은 충돌 확인용이지 remote branch를 몰래 rename하는 허가가 아닙니다.
active lock과 broken ref 분리
“unable to resolve reference”는 Git command로 전체 ref를 검사합니다. packed, loose, symbolic, reftable일 수 있습니다. git fsck --full을 실행하고 packed-refs를 직접 편집하지 마세요.
.lock이 있으면 Git process, hook, IDE, backup, server task 소유가 아님을 증명합니다. 중단된 작업의 orphan lock만 stale-lock 분기입니다.
좁은 복구 검증과 원인 종료
local ref 수정이 증명되면 expected old OID와 git update-ref를 우선합니다. namespace 충돌은 합의된 rename/delete 후 fetch, race는 fresh retry 한 번입니다.
git show-ref, git fsck --full, fetch나 push 한 번, remote OID 비교로 끝내고 concurrent writer, 계층 이름, case folding, 중단 lock, 권한, broken ref를 기록합니다.
