Fixing Git 'cannot lock ref' Errors: Handling Case-Sensitivity on macOS

intermediate🍎 macOS2026-05-02| macOS (APFS/HFS+ Filesystem), Git (any version)

Error Message

error: cannot lock ref 'refs/heads/feature/abc': 'refs/heads/feature/ABC' exists; cannot create 'refs/heads/feature/abc'
#git#filesystem#case-sensitivity#macos

The Problem Context

Imagine you’re deep in a coding session, everything is flowing, and you go to git fetch the latest changes. Instead of a clean update, Git stops you cold. It throws a frustrating error about "locking references." You check your branch names, and they look fine. Yet, Git refuses to cooperate.

This happens because of a fundamental mismatch between Git and macOS. While Linux treats 'File.txt' and 'file.txt' as two unique entities, macOS is case-insensitive but case-preserving. If a folder named 'Feature' already exists, you cannot create another one named 'feature' in that same directory. To your Mac, they are the same path.

The Exact Error

error: cannot lock ref 'refs/heads/feature/abc': 'refs/heads/feature/ABC' exists; cannot create 'refs/heads/feature/abc'

Why This Happens

Git isn't just a tool; it's a database that uses your filesystem to store data. By default, it saves local branches as individual files inside the .git/refs/heads/ directory. For a branch named feature/ABC, Git creates a folder named feature and a file named ABC inside it.

The conflict starts when a teammate pushes feature/abc (lowercase) to the server. When you try to pull it, Git attempts to write a new file named abc. Since macOS sees ABC and abc as the same file, Git gets caught in a loop. It sees a reference already exists but notices the data doesn't match, leading to the "cannot lock ref" failure.

How to Fix the Lock Conflict

1. Prune Stale Remote References

Often, the "old" version of the branch was already deleted or renamed on the server, but your local machine is still clinging to the ghost of that reference. You need to tell Git to synchronize its memory.

git remote prune origin

This command is a quick housekeeping tool. It removes any origin/ tracking branches that no longer exist on the remote. If feature/ABC was only a remote-tracking branch, this usually solves the problem instantly.

2. Delete the Local Conflict

If pruning doesn't help, the culprit is likely a branch living on your local disk. You need to find the specific name causing the collision.

git branch -a | grep -i "feature/abc"

If you see both feature/abc and feature/ABC, one has to go. Since your Mac can't distinguish between them, delete the version that doesn't match your team's naming convention.

# Force delete the conflicting local branch
git branch -D feature/ABC

3. Surgical Cleanup of the .git Folder

Sometimes the filesystem gets stuck so badly that standard Git commands fail to clear the debris. In these rare cases, you can manually remove the offending file. Handle this with care—you are touching Git’s internal organs.

  • Open your terminal in the project root.
  • Navigate to the hidden refs folder: cd .git/refs/heads/
  • Find the directory matching your prefix (e.g., feature).
  • Delete the file that matches the conflicting branch name.

Example command:

rm .git/refs/heads/feature/ABC

Once the file is gone, try fetching again: git fetch --prune.

4. The "Nuclear" Option: git pack-refs

If you have dozens of branches and the errors keep popping up, use pack-refs. This command compresses hundreds of small branch files into a single flat text file called packed-refs.

git pack-refs --all

Because the branches are now just lines in a text file rather than individual files on your disk, the macOS filesystem limitations no longer apply. It effectively bypasses the case-sensitivity issue entirely.

Verification

To make sure the fix stuck, pull the latest changes:

git pull origin main
git fetch --all

If the command finishes without complaints, you're back in business. Run git branch -a one last time to confirm that only the correctly cased version of the branch remains.

Lessons for the Future

  • Stick to Lowercase: Save yourself the headache. Agree as a team to use only lowercase letters for branch names (e.g., feature/fix-header instead of Feature/Fix-Header).
  • Prune by Default: Set Git to prune automatically by running git config --global fetch.prune true. This keeps your local environment clean without extra effort.
  • Environment Awareness: Your Mac is friendly and case-insensitive, but your Linux production servers are not. Always treat case differences as meaningful bugs.

Related Error Notes