You try to pull, fetch, or checkout a branch and Git throws:
error: cannot lock ref 'refs/heads/main': Unable to create lock file
Or the related variant:
fatal: Unable to create '/path/to/repo/.git/refs/heads/main.lock': File exists
Git uses lock files to prevent concurrent operations from corrupting refs. If a lock file is stuck, everything grinds to a halt.
What causes this
When Git updates a reference (branch pointer, tag, etc.), it creates a .lock file next to the ref file. This prevents two Git processes from writing to the same ref simultaneously. Once the operation completes, the lock file is removed.
The lock file gets stuck when:
- A previous Git operation crashed or was killed mid-write (Ctrl+C during a rebase, power loss, etc.)
- Another Git process is still running (a background fetch, a GUI client, an IDE’s Git integration)
- A filesystem issue prevents Git from deleting the lock file
- On networked filesystems (NFS, SMB), stale locks can persist after a client disconnects
Fix 1: Remove the stale lock file
If you’re sure no other Git process is running, delete the lock file:
rm -f .git/refs/heads/main.lock
If you’re not sure which lock file is the problem, find all of them:
find .git -name "*.lock" -type f
Then remove them:
find .git -name "*.lock" -type f -delete
Always verify no other Git process is running first:
ps aux | grep git
Fix 2: Run garbage collection
Sometimes the issue is caused by loose refs or packed-refs being in a bad state. Running GC cleans things up:
git gc --prune=now
If that also fails due to a lock, remove the lock first (Fix 1), then run GC.
Fix 3: Prune stale remote refs
If the error mentions a remote ref like refs/remotes/origin/main, the issue is with your local copy of remote tracking branches:
git remote prune origin
This removes local references to remote branches that no longer exist. If that fails due to a lock:
rm -f .git/refs/remotes/origin/main.lock
git remote prune origin
Fix 4: Re-pack references
Git stores refs in two ways: as individual files under .git/refs/ and packed into .git/packed-refs. Conflicts between these can cause lock issues:
git pack-refs --all
This consolidates all loose refs into the packed-refs file, which can resolve conflicts between the two storage formats.
Fix 5: Check for background Git processes
IDEs like VS Code, IntelliJ, and others run Git operations in the background. If you’re seeing lock errors frequently:
# Check for running Git processes
ps aux | grep git
# On macOS/Linux, check what's holding the lock
lsof .git/refs/heads/main.lock
Kill any stale Git processes, or temporarily disable your IDE’s Git integration to isolate the issue.
Related resources
How to prevent it
- Avoid killing Git operations with Ctrl+C — let them finish or use
git merge --abort/git rebase --abortto cancel cleanly - If you use a Git GUI alongside the terminal, be aware they may run concurrent operations
- On shared/networked filesystems, avoid having multiple machines operate on the same repo simultaneously
- Add a pre-commit hook or alias that checks for stale locks before operations