Photo by Rob Wingate on Unsplash
So I was pulling down some changes from a remote branch late one night, totally routine stuff, and Git just throws this at me:
error: cannot lock ref 'refs/remotes/origin/feature/my-branch':
'refs/remotes/origin/feature' exists; cannot create 'refs/remotes/origin/feature/my-branch'
I stared at it for a solid minute. The branch existed on remote, my internet was fine, nothing was obviously broken. But Git absolutely refused to update. If you've hit the "git cannot lock ref" error, you know exactly that sinking feeling — it's not a scary error, but it's weirdly cryptic the first few times you see it.
Here's what's actually going on and how to fix it without losing your mind.
Why This Error Happens
Git stores remote-tracking refs as files in your local .git/refs/remotes/ directory. The "cannot lock ref" error almost always comes down to a namespace conflict — basically, Git is trying to create a file at a path where a file or directory already exists with a conflicting name.
Think about it this way. Say someone on your team had a branch called feature (just that, no slash). Git stored it as a file at .git/refs/remotes/origin/feature. Now that branch got deleted on remote and replaced with a new one called feature/my-branch. Git now needs to create a directory named feature to store that new ref — but there's already a file sitting there with that exact name. Filesystem conflict. Git can't sort that out on its own, so it throws the lock error.
It also occasionally happens because of stale lock files left behind from a crashed Git operation — you'll see something like Unable to create '.git/refs/remotes/origin/feature.lock'. That's a slightly different flavor of the same general problem.
Alright so let's fix it.
Fix 1: Prune Your Remote-Tracking Refs
This is the first thing I always try, and honestly it solves it about 70% of the time. Remote-tracking refs can go stale when branches get deleted on the remote but your local Git doesn't know yet. Pruning cleans all that up:
git fetch --prune origin
Or if you want to do a full fetch and prune in one shot:
git remote prune origin
What this does is remove any local remote-tracking branches that no longer exist on the remote. That stale refs/remotes/origin/feature file that's blocking the new branch? Gone. After running this, try your fetch or pull again and there's a good chance it just works.
Side note — you can actually set Git to prune automatically on every fetch so you never deal with this again. Just run:
git config --global fetch.prune true
I've had this set for years and it's saved me from this exact headache more times than I can count.
Fix 2: Manually Delete the Conflicting Ref File
If pruning doesn't cut it — maybe the conflict is with a branch that still exists on remote but the local ref is corrupted or mismatched — you'll need to go in and delete the problem file yourself.
First, find it. The error message actually tells you exactly what the conflicting ref path is. Based on our example error above, the problem is at refs/remotes/origin/feature. So navigate into your repo and remove it:
# On Mac/Linux
rm .git/refs/remotes/origin/feature
# On Windows (PowerShell)
Remove-Item .git\refs\remotes\origin\feature
Now here's where it gets tricky — sometimes the ref isn't stored as a loose file in .git/refs/. Git also packs refs into a single file called .git/packed-refs for efficiency. Open that file in any text editor and look for a line referencing your conflicting branch. It'll look something like this:
a1b2c3d4e5f6... refs/remotes/origin/feature
Just delete that line, save the file, and try your fetch again. Not glamorous, but it works.
Fix 3: Delete the Stale Lock File Directly
If your error message mentions a .lock file specifically — like Git crashed mid-operation and left one behind — that's the easiest fix of all:
# Find any leftover lock files
find .git -name "*.lock"
# Remove them (make sure no Git operation is actively running first!)
find .git -name "*.lock" -delete
One word of caution here: only do this when you're sure no other Git process is actively running on the repo. If you delete a lock file while Git is mid-operation, you can end up with a corrupted state. But if you got the error during a pull that clearly failed and nothing is running, you're fine to clean them up.
Fallback: Nuke and Re-Clone (Last Resort)
In my experience, the three methods above cover 99% of cases. But occasionally — especially on repos with really messy history or after some kind of network interruption during a fetch — the ref database just gets into a state that's hard to untangle manually.
If nothing else is working and you're spending more than 20 minutes on this, honestly just re-clone:
cd ..
git clone repo-fresh
cd repo-fresh
Make sure you've pushed any local commits or stashed any uncommitted work before you do this, obviously. But a fresh clone has a clean ref database and the problem evaporates instantly. Sometimes the pragmatic move beats the clever one.
Quick Recap
The cannot lock ref error is almost always a stale or conflicting entry in your local Git ref store. Start with git fetch --prune origin, and if that doesn't work, track down the specific conflicting file in .git/refs/remotes/ or .git/packed-refs and remove it manually. Set fetch.prune true globally while you're at it — future you will appreciate it.
Hope this saves you the 45 minutes of Stack Overflow scrolling I went through the first time I hit this one.
Related: How to Fix Git Error: Cannot Lock Ref (And Why It Keeps Happening)
๋๊ธ
๋๊ธ ์ฐ๊ธฐ