Skip to main content
DevOps Insightsguides & answers

Git · troubleshooting

error: cannot lock ref

Git could not update a branch or remote-tracking ref, so the fetch, pull or commit stopped part-way. Usually a remote branch such as feature was replaced by one such as feature/x, two remote branches differ only in letter case on a Mac or Windows disk, or a crashed Git left a .lock file.

Reproduced on Git 2.50.1, . Where the text says “reproduced”, the behaviour was run on that version, not taken from documentation.

First published

New to this? Read what is actually happening first, then come back to the steps.

On this page · 9 sections

Before you start

  • A terminal in the repository, and the exact ref named in the message.

Run this first

step 1 of 1
git fetch --prune --verbose

Look for unable to update local ref, and the names involved

Shows each ref the fetch updates, prunes or fails on.

Work out which cause you have

A few questions to narrow the list. Every answer ends in a command that confirms or rules the cause out — this cannot see your cluster, so nothing here is a certainty until you have checked.

Narrow it down

0 answered · nothing is sent anywhere

What follows the ref name in the message?

Cause space

4 of 4 still possible

  • A remote branch became a folder of the same name (feature to feature/x)Common
  • Two remote branches differ only in letter caseCommon
  • A .lock file left by a crashed or still-running GitOccasional
  • Two Git processes updated the same ref at onceRare

Nothing ruled out yet. Answer the question above and the branches your answer eliminates will strike through here.

Or diagnose it manually

In this order. The first command usually contains the whole answer.

  1. Step 1

    git fetch --prune --verbose

    Shows each ref the fetch updates, prunes or fails on.

    Look for unable to update local ref, and the names involved

Every cause, and how to fix it

Ordered by how often each one turns out to be the answer.

A remote branch became a folder of the same name (feature to feature/x)

Common

Your clone still has origin/feature as a file, so it cannot create origin/feature/x inside a folder of that name.

Confirm

git fetch 2>&1 | grep -E 'exists; cannot create'

Two ref names where one is a prefix of the other

Fix

  • Prune the stale remote-tracking branch as you fetch: git fetch --prune (or git remote prune origin, then git fetch).
git fetch --prune

Reproduced on Git 2.43.0 and 2.50.1.

Two remote branches differ only in letter case

Common

Someone on Linux pushed both Release and release. On a case-insensitive disk (the default on macOS and Windows) your clone stores both in one file, so one of them silently points at the wrong commit and later fetches fail with is at ... but expected ....

Confirm

git ls-remote --heads origin | awk '{print tolower($2)}' | sort | uniq -d

Any output: branch names that collide when case is ignored

Fix

  • Fix it on the remote: rename or delete one of the two branches (whoever owns them decides which).
  • Then, in each clone, run git fetch --prune. The prune also removes the surviving branch, because it shared one file with its twin, so run git fetch once more to bring it back.

A .lock file left by a crashed or still-running Git

Occasional

Git writes BRANCH.lock while updating a ref. If Git crashed, or an IDE is still running a Git command, the lock remains.

Confirm

find .git -name '*.lock'; pgrep -lx git

A .lock file with no Git process running

Fix

  • Close editors and IDEs using the repository, confirm no git process remains, then delete the .lock file named in the message.

Two Git processes updated the same ref at once

Rare

is at ... but expected ... also appears when another fetch, an IDE's background fetch, or a CI step changed the ref between reading and writing it. Retrying usually works.

Confirm

git fetch

The error does not come back

Fix

  • Run the command again, and turn off background fetching in tools that run in the same clone if it recurs.

Understanding it properly

Skip this if you are mid-incident — the working part of the page is above. Worth reading afterwards, because understanding the mechanism is what stops the next one.

In plain terms

Git stores each branch as a small file named after it. Two situations break that: a branch called feature and another called feature/x would need feature to be both a file and a folder, and on Mac and Windows disks Release and release are the same file.

Words used on this page

Ref
A name pointing at a commit: branches (refs/heads/...), remote-tracking branches (refs/remotes/origin/...) and tags.
Remote-tracking branch
Your clone's copy of a branch on the remote, such as origin/main, updated by git fetch.
Prune
Deleting remote-tracking branches whose branch no longer exists on the remote: git fetch --prune.
What is actually happening

Reproduced with Git 2.43.0 on Ubuntu: when the remote deleted branch feature and created feature/x, git fetch printed error: cannot lock ref 'refs/remotes/origin/feature/x': 'refs/remotes/origin/feature' exists; cannot create 'refs/remotes/origin/feature/x'. Git 2.50.1 printed the same without the cannot lock ref prefix, and suggested git remote prune origin. git fetch --prune fixed it.

On macOS, with remote branches Release and release, origin/Release silently pointed at release's commit, because both names map to one file on a case-insensitive disk. The next fetch failed with cannot lock ref 'refs/remotes/origin/Release': is at b031510... but expected b35dd10.... On Linux both branches coexisted without complaint, which is why the people who created them often never see the error.

A leftover .git/refs/heads/main.lock made git commit fail with cannot lock ref 'HEAD': Unable to create '.../main.lock': File exists. and a note that another Git process may be running.

How to tell this is your problem
WhereWhat you see
git fetch or pull, Git 2.50error: 'refs/remotes/origin/A' exists; cannot create 'refs/remotes/origin/A/B'
git fetch or pull, older Giterror: cannot lock ref 'refs/remotes/origin/A/B': 'refs/remotes/origin/A' exists; cannot create 'refs/remotes/origin/A/B'
git fetch, Mac or Windowserror: cannot lock ref 'refs/remotes/origin/NAME': is at SHA but expected SHA
Any command that updates a branchfatal: cannot lock ref 'HEAD': Unable to create '.../refs/heads/BRANCH.lock': File exists.

How to know it is actually fixed

  • git fetch completes with no errors, and git rev-parse origin/BRANCH matches git ls-remote origin BRANCH.

Stopping it happening again

  • Set fetch.prune to true: git config --global fetch.prune true.
  • Agree on lowercase branch names, and block names that differ only in case in your Git host's branch rules where it supports that.

Security considerations

  • Before deleting a .lock file, make sure no Git process (including an editor or IDE) is still running in the repository; removing a live lock can corrupt the update it protects.

Sources

Behaviour described here is drawn from official documentation. Where a figure could not be confirmed on an official page it is attributed in the text rather than stated as canonical.

Did this get you to an answer?

No text box on purpose — please do not paste production logs anywhere

Something wrong or out of date? Report it