Git Push Error "cannot lock ref" "reference already exists"
Asked Answered
T

5

8

The full error is:

remote: error: cannot lock ref 'refs/heads/fix/add_overlay': reference already exists

I'm using SourceTree, but that should not matter I don't think. I keep trying to push and I keep getting this error, how can I resolve it?

Towards answered 7/12, 2017 at 21:1 Comment(1)
Does this answer your question? git push: refs/heads/my/subbranch exists, cannot createErickson
R
5

TL;DR: try removing their branch fix, i.e., their refs/heads/fix, which I suspect is in the way. (Be sure they don't care if you remove it!)


The error message is very odd. If the reference refs/heads/fix/add_overlay exists, that's not a problem! Git should be able to lock it, and if it can't, the reason it can't is not "because it exists".

I suspect that this may be a misleading error message: it may be that the reference refs/heads/fixnot refs/heads/fix/add_overlay—exists, so it's impossible to create a directory refs/heads/fix/ in which to hold the sub-reference refs/heads/fix/add_overlay because the existing reference refs/heads/fix is in the way.

You can tell whether this is the case by examining the set of references that exist (by using git ls-remote, or after a git fetch -p, by looking at your own set of remote-tracking names that are based on their branch names). And, if it is the case, you should convince them—whoever they are—to rename or remove their branch fix so that you can have them create a directory named fix/ containing branch names like fix/add_overlay.

Rosannarosanne answered 8/12, 2017 at 1:2 Comment(11)
I have pushed to this branch ( refs/heads/Fix/add_overlay ) before so now it does exist as a remote branch...but why would it be locked?Towards
I'm going to have the admin reboot our git server because I agree this issue and error message is very oddTowards
You spelled Fix in uppercase in your comment here. Is it possible there is a case sensitive fix vs Fix and some sort of case folding issue on the server?Rosannarosanne
reboot did not fix it eitherTowards
torek, you are right... in my remotes I see a 'fix' folder and a ''Fix" folder. Locally, my branch is under ''fix" and the remote version of my branch is under "Fix" ....how that happened, I have no idea. Is there way when pushing to specify the remote branch?Towards
ah ha! when pushing I was able to specify the remote branch folder name as "Fix" and not "fix" and then push succeeded.Towards
It's generally a bad idea to have branch names that differ only in case (upper vs lower), including directory names. Linux and Unix systems tend to be case-sensitive, so a/b and A/b and a/B and A/B name four different files; Windows and Mac file systems tend to do case-folding and you cannot store all four of those. This makes life miserable. The solution is to avoid the situation entirely. :-)Rosannarosanne
yep, absolutely I agree, not sure who in my team used upper case...I always use lower case for folders.Towards
I ran into this exact problem and you explained it perfectly for me. Thank youScotopia
One great solution to this problem, @torek, is to avoid using Windows and Mac ;-)Audient
Same here, @Mike6679, I don't know who in my team uses mixed kebab, snake and camel case names that don't describe the content in any way whatsoever, but whoever it is, there are a lot of them ;-) grrrAudient
M
2

To remove that error, navigate to your project directory and run git remote and then remove the origin by running git remote rm origin.Create a new repository, [assuming you use GitHub] by running git remote add origin https://github.com/your_user_name/your_repository_name.git, and push the changes to the remote server,git push -u origin master.This should work.

Mandy answered 8/7, 2020 at 11:40 Comment(1)
this worked for me. my issue was i hadn't updated an Overleaf-linked repository in a while and there were substantial conflicting changes, and following these steps removed the generic Reference already exists error Overleaf was throwing.Paleolithic
B
1

This error can occur when attempting to push to a folder with the same name as an existing branch.

https://mcmap.net/q/12211/-git-push-refs-heads-my-subbranch-exists-cannot-create

Bledsoe answered 27/9, 2018 at 13:45 Comment(0)
L
1

Another possible cause is about "Case Sensitive" of branch.

This is repeatable (with git bash on windows platform ) by:- (may cause loss of work in local repository. don't play with your working copy)

  1. Pull a branch from origin, e.g. with name "abc"
  2. Checkout that branch "abc"
  3. Try to push origin. This show no error.
  4. Checkout branch "Abc", first letter capital.
  5. Try to push again.
  6. Get error "cannot lock ref" "reference already exists"

To fix:-

  1. Commit your work in the typo branch "Abc"
  2. Note the commit ID. You must get the commit before checkout to other branch. Otherwise you may never get that again.
  3. Backup your local repository folder, to ensure no loss of work.
  4. Checkout the correct branch "abc"
  5. merge that commit into the correct branch, by git merge <commit id>
  6. continue with push origin

Note:

  1. Once you have checkout the correct branch "abc", changes made in "Abc" were restored.
  2. Even if you checkout back into "Abc" afterwards, you cannot find the "commit id" from git log, and cannot get the changed files in "Abc".
  3. If you have the commit id in hand, you can still checkout that commit id to get back those changed files.
Lew answered 29/11, 2023 at 1:40 Comment(0)
A
0

This is an answer to this question, and, I hope, a range of similar questions, definitely with common elements in the Git error message, and possibly with some variations. This is the full error I'm using as an example (anonymised), but read on if your situation is a bit different. The answer may still help.

update failed: reference exists: cannot create:

$ git push
Enumerating objects: 9, done.
Counting objects: 100% (9/9), done.
Delta compression using up to 8 threads
Compressing objects: 100% (7/7), done.
Writing objects: 100% (7/7), 13.43 KiB | 2.69 MiB/s, done.
Total 7 (delta 3), reused 0 (delta 0), pack-reused 0
remote: Resolving deltas: 100% (3/3), completed with 2 local objects.
To https://github.com/theaccount/therepo.git
   92bc4d8..37c3af9  feature/the-branch -> feature/the-branch
error: update_ref failed for ref 'refs/remotes/origin/feature/the-branch': cannot lock ref 'refs/remotes/origin/feature/the-branch': 'refs/remotes/origin/feature' exists; cannot create 'refs/remotes/origin/feature/the-branch'

Example questions and answers:

This question tends to repeat with variations which tends to attract a variety of answers, often of the "I tried this and it worked" sort, which then attracts comments such as "didn't work for me but this did". There's a proliferation of similar questions and answers which are not necessarily aligned, and not very explanatory:

I want to try to go a bit deeper and reveal more of the problem inside git. Often with Git I don't want to know. Explanations are usually counter-intuitive, consisting of unhelpful diagrams of arrows pointing the wrong way with insufficient foundational context. This time I hope I can make something a bit clearer. I believe the addition of some underlying concepts can help when problem solving and make it easier to remember and apply in future situations.

Storing references in .git:

I'm trying to keep it short, but remember:

  • Git keeps all its local data and records in the .git directory of your local repo
  • When you create a (local) branch called feature/the-branch Git will
    1. Create the directory .git/refs/heads/feature/ (if it doesn't exist)
    2. Create the file .git/refs/heads/feature/the-branch (this is just the way the initial Git implementation decided to do it)
  • When you push your local branch to your upstream origin (probably labelled origin) Git creates the path .git/refs/remotes/origin/feature/the-branch including all those directories on the way (there can be multiple remotes)
  • Now if someone (it wasn't me, honest) had previously created a branch named feature (don't do that) then Git will have created a file .git/refs/heads/feature and when it's pushed it will also create another file .git/refs/remotes/origin/feature
  • Now you should see it's impossible to create the .git/refs/heads/feature/ directory and all branches named starting feature/ are blocked

(Using the rsync terminology of trailing slash to indicate a directory.)

All this content is in your local .git directory, in your local repo - even when it's to record something about the remote repo, such as .git/refs/remotes/origin/feature/the-branch.

Reference exists

Sometimes you can fix a problem just by cloning again from the remote, but that's cheating. And it takes time. And doing manual copying may introduce difficult to locate errors when you have content in your local that needs to be pushed to origin.

In this case we did have a branch called feature, which apart from being very uncomfortable every time you took a look at the repo, also prevented the creation of feature branches, that were required to work with other parts of the CI/CD toolchain.

For this (old) question (with no accepted answer) it looks very much like someone once-upon-a-time created a branch called fix (genius). If a whole genre of Git questions isn't an argument for thinking about your naming conventions then I don't know what is. I've always hated bad naming, but now I've got reasoning why I can be indignant about it.

So the error message here looks like it's saying refs/heads/fix/add_overlay already exists. TBH, it actually is saying that (thanks again, Git; good to see you're maintaining your reputation), but it seems likely that the reference that already exists is refs/heads/fix. That means there's a local file .git/refs/heads/fix, and Git cannot create .git/refs/head/fix/ like it needs to, because the path, or reference, already exists.

This situation can still remain even if you have deleted the offending (fix or in my case, feature) branch. Or you may have cleaned up the origin properly but still have the reference locally. A push can even seem to succeed even though it reports errors, and subsequent operations nevertheless fail.

Various errors

There do seem to be a range of problems and error messages that can eventuate from this, and presumably similar situations. Bearing in mind the need for a local reference path including the right directories and filename, the following messages all make a lot more sense in retrospect:

In my situation I had somehow managed to push to the branch already. It existed on the remote, but now, after another push inexplicably failed I could no longer connect. Git told me my upstream branch was "gone":

$ git branch -vv
  develop            f22092e [origin/develop] Update deploy.yml
* feature/the-branch 37c3af9 [origin/feature/the-branch: gone] Move old README.md into documentation
  main               7bd2f45 [origin/main] Delete Deploytonon-prod.yml
  release            3b90d28 [origin/release] Merge pull request #10 from theaccount/develop
On branch feature/the-branch
Your branch is based on 'origin/feature/the-branch', but the upstream is gone.
  (use "git branch --unset-upstream" to fixup)

I tried to reset the upstream connection but the problem was obviously still there:

$ git branch --unset-upstream
$ git branch --set-upstream-to=origin/feature/the-branch feature/the-branch
error: the requested upstream branch 'origin/feature/the-branch' does not exist

I tried to update from the origin to re-align (or something) but Git had put itself into a dead end:

$ git fetch
error: cannot lock ref 'refs/remotes/origin/feature/the-branch': 'refs/remotes/origin/feature' exists; cannot create 'refs/remotes/origin/feature/the-branch'
From https://github.com/theaccount/therepo
 ! [new branch]      feature/the-branch -> origin/feature/the-branch  (unable to update local ref)

Diagnostics

Before using the git one-liner that will fix all this, I just want to demonstrate a couple of views that were not top of my mind in my git repertoire.

git branch -vv does not show the bad reference, so it's invisible otherwise.

At the end of the day, you can $cd .git and start looking around: ls refs/heads. That might even be quickest. But to summarise the situation remotely and locally, the following two commands reveal the problem immediately.

$ git ls-remote
From https://github.com/theaccount/therepo.git
7bd2f45d5a7a137c1058c2074183ff0dc4c523b7        HEAD
f22092ebd8f9c243efaf770f941cddf0f9b916c5        refs/heads/develop
37c3af9fe595c427eb1ff1d194e742e5273633c1        refs/heads/feature/the-branch
5317d3f80b94ab721ee2c51b87b70e950241fe01        refs/heads/features/notification
7bd2f45d5a7a137c1058c2074183ff0dc4c523b7        refs/heads/main
3b90d28ef5e5b1d4ad45b17bfa98d10cc70cdef5        refs/heads/release
9b169e74da97174d4877e7359c1772287faf03bb        refs/pull/1/head
f22092ebd8f9c243efaf770f941cddf0f9b916c5        refs/pull/10/head
96a8240b0449dff6579629de6feede0d82120765        refs/pull/2/head
8d1e7d64f276b9927dfd1b664805b208a421c6c9        refs/pull/3/head
0d120fee6da456d2f953a4aaa57f577489f21501        refs/pull/4/head
4ab5cc4596f31b44f72e3a0d92c8143b0cf39b2c        refs/pull/5/head
84ad3d7d7856d44fd45592d083e284964c19f1ef        refs/pull/6/head
881bfa14baa0b2d15e013371415cb3bf912b2887        refs/pull/7/head
b89c797b4abe0676cfdbfcbb09ffb87897a06eef        refs/pull/8/head
d40fdb24faea617f35c045a73e1884952e9283bf        refs/pull/9/head
b345722255e495cdd8895e7d53357dd8a3de523c        refs/tags/v0.0.0
28f027de3f6e8c8f541f22eea4fa25eba3ce15ce        refs/tags/v0.0.0^{}
5317d3f80b94ab721ee2c51b87b70e950241fe01        refs/tags/v1.0.0

Looking at the origin there is no refs/heads/feature. That problem was cleared up by another dev, and that's not the blocker. The branch we're trying to access is listed there as refs/heads/feature/the-branch as it should be. We can even see why last year we had problems tagging v0.0.0, because there seems to be a key bounce crept into one of the tag names in refs/tags/v0.0.0^{}.

But what does the local Git think the remote branches are?

$ git branch -r
  origin/HEAD -> origin/main
  origin/develop
  origin/feature
  origin/features/notification
  origin/main
  origin/release

Locally, we can see that there is still a reference to the origin feature branch, even though it's been deleted from the remote itself (and never existed on the local (remember, I said it wasn't me!)). Starting a new repo (cloning again from scratch) would avoid this problem (now that origin/feature has been deleted) but as we said, it's arduous and error prone, you could even try rm origin/feature, but there's a proper way.

Pruning orphan references

Now we want to delete something; and as always with Git (or anything, but somehow it's always more complicated with Git), we want to be sure we don't delete the wrong thing. Hopefully this background has introduced a lot more confidence. If you still judge there is a probability that something irrevocably destructive may happen, you can always zip the repo and keep it on one hand to try again if you mess up; but that should not really be necessary now.

We have our local branch, with changes to push, but upstream is showing an error, so we can just clean it up:

$ git branch --unset-upstream

Now we have our local branch without any tracking:

$ git branch -vv
  develop            f22092e [origin/develop] Update deploy.yml
* feature/the-branch 37c3af9 Move old README.md into documentation
  main               7bd2f45 [origin/main] Delete Deploytonon-prod.yml
  release            3b90d28 [origin/release] Merge pull request #10 from theaccount/develop

We can now "prune" the "orphan" local reference to the remote branch that's since been deleted. This is a meta data delete. It's not going to delete any real content, since Git is just an object store.

So we use a fetch to get the branch information from the origin, but we add the --prune option, to make the command strip out any references in our local that don't align with the origin. This removes the blocking feature (file) and creates the remote references to feature/the-branch:

$ git fetch --prune origin
From https://github.com/theaccount/therepo
 - [deleted]         (none)     -> origin/feature
 * [new branch]      feature/the-branch -> origin/feature/the-branch

Reinstate remote tracking

Now that the local Git has the right references we can easily set the upstream for our local branch to the branch on the origin. The file named feature (or fix for the OP) has been removed, and is replaced with a directory of the same name:

$ git branch -u origin/feature/the-branch
Branch 'feature/the-branch' set up to track remote branch 'feature/the-branch' from 'origin'.

Checking our branch status shows all branches tracking their remotes:

$ git branch -vv
  develop            f22092e [origin/develop] Update deploy.yml
* feature/the-branch 37c3af9 [origin/feature/the-branch] Move old README.md into documentation
  main               7bd2f45 [origin/main] Delete Deploytonon-prod.yml
  release            3b90d28 [origin/release] Merge pull request #10 from theaccount/develop

You should now be able to add, commit and push. Hopefully.

Further options

As I said, I think there are a range of similar issues that can occur due to combinations of faults on remote and origin. If your situation doesn't quite match the fetch --prune doesn't work, then follow up on the list of questions at the beginning of this answer and research this command that may cover inverse situations:

git remote prune origin
Audient answered 14/4, 2023 at 6:44 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.