Git推送错误 "无法锁定引用" "引用已经存在"

8

完整的错误信息如下:

远程:错误:无法锁定引用 'refs/heads/fix/add_overlay':引用已经存在

我正在使用SourceTree,但我认为这并不重要。我一直在尝试推送,但我一直收到此错误消息,我该如何解决?


这个回答解决了你的问题吗?git push: refs/heads/my/subbranch exists, cannot create - HFinch
5个回答

5
TL;DR:尝试移除他们的分支fix,即他们的refs/heads/fix,我怀疑它挡住了路。(确保他们不介意你移除它!)
错误信息非常奇怪。如果引用refs/heads/fix/add_overlay存在,那就不是问题!Git应该能够锁定它,如果它不能,它无法锁定的原因不是“因为它存在”。
我怀疑这可能是一个误导性的错误消息:可能是引用refs/heads/fix——而不是refs/heads/fix/add_overlay——存在,所以无法创建一个目录refs/heads/fix/来保存子参考refs/heads/fix/add_overlay,因为现有的引用refs/heads/fix挡住了路。
您可以通过检查现有的引用集(使用git ls-remote或者在git fetch -p之后,查看基于他们的分支名称的远程跟踪名称集合)来确定是否为此情况。如果是这种情况,您应该说服他们——无论他们是谁——重命名或删除他们的分支fix,这样您就可以让他们创建一个名为fix/的目录,其中包含诸如fix/add_overlay之类的分支名称。

4
你在这里的评论中将 Fix 的拼写大写了。服务器上是否存在大小写敏感的 fixFix,并且可能存在大小写折叠问题? - torek
啊哈!当我推送时,我能够将远程分支文件夹名称指定为“Fix”,而不是“fix”,然后推送成功了。 - Mike6679
1
是的,我完全同意,不确定我的团队中谁使用了大写字母……我总是使用小写字母来命名文件夹。 - Mike6679
这个问题的一个很好的解决方案,@torek,就是避免使用Windows和Mac ;-) - NeilG
我也一样,@Mike6679,我不知道我的团队中有谁使用混合的kebab、snake和camel case命名方式,这些命名方式根本没有描述内容,但是无论是谁,都有很多人;-) grrr - NeilG
显示剩余6条评论

2

要消除这个错误,导航到您的项目目录并运行git remote,然后通过运行git remote rm origin删除origin。创建一个新的存储库,[假设您使用GitHub]通过运行git remote add origin https://github.com/your_user_name/your_repository_name.git,并将更改推送到远程服务器git push -u origin master。这应该可以解决问题。


1

1
另一个可能的原因是分支的“区分大小写”问题。
这个问题可以在Windows平台上使用git bash重复出现,具体步骤如下: (可能导致本地仓库的工作丢失,请不要对您的工作副本进行操作)
1. 从远程仓库拉取一个名为“abc”的分支。 2. 切换到该分支“abc”。 3. 尝试推送到远程仓库,此时不会出现错误。 4. 切换到分支“Abc”,首字母大写。 5. 再次尝试推送。 6. 出现错误提示“无法锁定引用”、“引用已经存在”。
解决方法如下:
1. 在拼写错误的分支“Abc”上提交您的工作。 2. 记下提交的ID。在切换到其他分支之前,您必须获取该提交。否则,您可能永远无法再次获取它。 3. 备份您的本地仓库文件夹,以确保不会丢失工作。 4. 切换到正确的分支“abc”。 5. 将该提交合并到正确的分支中,使用命令git merge <commit id>。 6. 继续推送到远程仓库。
注意:
一旦你切换到正确的分支"abc",在"Abc"中所做的更改将被恢复。
即使你之后切换回"Abc",你也无法在git日志中找到"commit id",也无法获取"Abc"中的更改文件。
如果你手头有commit id,你仍然可以checkout该commit id来获取那些更改的文件。

0
这是对于这个问题的回答,同时也希望能够解决一系列类似的问题,这些问题通常都涉及到 Git 错误信息中的共同元素,可能会有一些变化。以下是我作为示例使用的完整错误信息(已匿名化),但如果您的情况略有不同,请继续阅读。这个答案仍然可能会有所帮助。

更新失败:引用已存在,无法创建:

$ 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'

示例问题和答案:

这个问题往往会反复出现,带有一定的变化,从而吸引了各种各样的回答,通常都是“我尝试了这个方法,它有效”,这又会引起评论,如“对我无效,但这个方法有效”。有许多类似的问题和答案,并不一定是一致的,也不太具有解释性:

我想尝试深入一些,揭示git内部更多的问题。通常在使用Git时,我并不想知道太多。解释通常是违反直觉的,由于缺乏基础背景而导致箭头指向错误的图表不够有用。这次我希望能让某些潜在的概念更加清晰,这可以帮助解决问题,并使将来的情况更容易记住和应用。

在.git中存储引用:

我试图保持简短,但请记住:

Git将所有本地数据和记录保存在本地repo的.git目录中。 当您创建名为feature/the-branch的(本地)分支时,Git会:
  1. 创建目录.git/refs/heads/feature/(如果不存在)
  2. 创建文件.git/refs/heads/feature/the-branch(这只是最初的Git实现决定的方式)
当您将本地分支推送到上游源(可能标记为origin)时,Git会创建路径.git/refs/remotes/origin/feature/the-branch,包括沿途的所有目录(可能有多个远程)。 现在,如果有人(不是我,诚实的)之前创建了一个名为feature的分支(不要这样做),那么Git将创建一个文件.git/refs/heads/feature,并且在推送时还会创建另一个文件.git/refs/remotes/origin/feature。 现在,您应该看到无法创建.git/refs/heads/feature/目录,并且以feature/开头的所有分支都被阻止了。

(使用rsync术语的尾随斜杠来指示目录。)

所有这些内容都在您的本地.git目录中,在您的本地repo中 - 即使它是为了记录有关远程repo的某些内容,例如.git/refs/remotes/origin/feature/the-branch

引用存在

有时,您可以通过再次从远程克隆来解决问题,但那是作弊。而且需要时间。当您在本地拥有需要推送到原点的内容时,进行手动复制可能会引入难以定位的错误。

在这种情况下,我们确实有一个名为feature的分支,除了每次查看repo时非常不舒服之外,还阻止了创建与CI / CD工具链的其他部分一起使用所需的feature分支。

对于这个(旧)问题(没有被接受的答案),看起来很像有人曾经创建了一个名为fix(天才)的分支。如果整个Git问题类型都不能让你考虑命名约定,那我不知道还有什么能让你考虑。我一直讨厌糟糕的命名,但现在我有理由对此感到愤慨。

所以这里的错误信息看起来像是在说refs/heads/fix/add_overlay已经存在。说实话,它确实是在说这个(再次感谢Git;很高兴看到你保持了你的声誉),但似乎已经存在的引用是refs/heads/fix。这意味着有一个本地文件.git/refs/heads/fix,而Git无法像需要的那样创建.git/refs/head/fix/,因为该路径或引用已经存在。

即使您已删除有问题的(fix或在我的情况下,feature)分支,此情况仍可能存在。或者您可能已经正确清理了源,但本地仍然有引用。即使推送报告错误,推送甚至似乎成功,随后的操作仍然会失败。

各种错误

似乎会出现一系列问题和错误消息,这些错误消息可能与类似的情况有关。请记住需要包括正确目录和文件名的本地引用路径,以下消息在回顾时都更加合理:

在我的情况下,我不知何故已经成功推送到该分支。它存在于远程,但是现在,在另一个推送莫名其妙地失败后,我无法再连接。Git告诉我我的上游分支已经“消失”:

$ 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)

我尝试重置上游连接,但问题显然仍然存在:

$ 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

我尝试从源更新以重新对齐(或其他操作),但Git已经陷入了死胡同:

$ 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)

诊断

在使用修复所有问题的 git 一行命令之前,我想展示一些我在 git 技能库中没有考虑到的视图。

git branch -vv 不显示错误引用,因此它是不可见的。

最终,你可以执行 $cd .git 并开始查看: ls refs/heads。这可能是最快的方法。但为了总结远程和本地的情况,以下两个命令立即揭示了问题。

$ 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

查看源代码,没有refs/heads/feature。这个问题已经被另一个开发人员解决了,这不是阻碍因素。我们正在尝试访问的分支在那里列出为refs/heads/feature/the-branch,正如它应该的那样。我们甚至可以看到为什么去年我们在标记v0.0.0时遇到了问题,因为在refs/tags/v0.0.0^{}中的一个标记名称中似乎存在一个键跳动。

但是本地Git认为远程分支是什么呢?

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

就本地而言,我们可以看到仍然有一个对于“origin”“特性”分支的引用,即使它已经从远程删除(并且在本地从未存在过(记住,我说不是我!))。重新开始一个新的repo(从头克隆)将避免这个问题(现在“origin/feature”已被删除),但正如我们所说,这是费力和容易出错的,你甚至可以尝试使用“rm origin/feature”,但还有更好的方法。

修剪孤儿引用

现在我们想要删除一些东西;像Git(或任何东西一样,但以某种方式,它在Git中总是更加复杂)一样,我们希望确保我们不会删除错东西。希望这背景介绍了更多信心。如果您仍然认为可能发生不可挽回的破坏性事件,您始终可以压缩repo并将其放在手边,以便在搞砸时再次尝试;但现在应该真的不需要这样做。

我们有我们的本地分支,并进行了更改以进行推送,但upstream显示错误,所以我们可以清理它:

$ git branch --unset-upstream

现在我们有了一个没有任何跟踪的本地分支:

$ 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

现在我们可以“修剪”已被删除的远程分支的“孤立”本地引用。这是元数据删除,不会删除任何真正的内容,因为Git只是一个对象存储库。
因此,我们使用fetchorigin获取分支信息,但我们添加了--prune选项,以使命令剥离与原始版本不对齐的本地引用。这将删除阻止的feature(文件)并创建到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

恢复远程跟踪

现在本地 Git 已经有了正确的引用,我们可以轻松地将本地分支的上游设置为源上的分支。名为 feature(或 OP 的 fix)的文件已被删除,并被同名目录所替代:

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

检查我们的分支状态,显示所有跟踪其远程的分支:

$ 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

现在你应该能够添加提交推送了。希望如此。

更多选项

正如我所说,我认为由于远程和源上的故障组合可能会出现一系列类似的问题。如果您的情况与fetch --prune不匹配,则请查看本答案开头的问题列表并研究可能涵盖相反情况的命令:

git remote prune origin

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接