Git! [remote rejected] master -> master(锁定失败)

Git ! [remote rejected] master -> master (failed to lock)

我无法推送到我的 git 存储库。 git clonegit pull 工作正常,但 git push 不工作。

我检查了其他答案,例如 here 尝试了几种方法,例如 git push origin master --force。但错误仍然存​​在。

这是屏幕截图。

其他详情:

$ git show-ref refs/remotes/origin/master
8a205a0741f85fa309031a45f3613bf95a99148f refs/remotes/origin/master

$ git rev-parse --symbolic-full-name master
refs/heads/master

$ git rev-parse master
35ae39a241cd6bbfe7a9092f72b08279159e0056

$ git show-ref master
35ae39a241cd6bbfe7a9092f72b08279159e0056 refs/heads/master
8a205a0741f85fa309031a45f3613bf95a99148f refs/remotes/origin/master

请帮助我摆脱这个错误。

更新

$ git ls-remote
From https://xxx.git
8a205a0741f85fa309031a45f3613bf95a99148f        HEAD
8a205a0741f85fa309031a45f3613bf95a99148f        refs/heads/master
58feda6564bd52b9cce53da9862343aefd704202        refs/heads/new-0505
f24cd00e2f587689cdb92671769817c271bf0759        refs/heads/telestop
2a1afdf637a9108471eeddc755d49b74ef51e567        refs/meta/gitblit/reflog
8a205a0741f85fa309031a45f3613bf95a99148f        refs/remotes/origin/master

首先检查什么 git ls-remote returns.

目标是确保没有:

  • 远程分支名为 master/xxx ()
  • 名为 Master 的远程分支(大小写不同:还要检查您的本地 .git/refs/heads 是否存在相同问题)

这种失败有多种可能的原因。根据 ,这原来是服务器上挥之不去的 master.lock 文件。手动删除它就足够了。

因为失败的原因可能不止一个,所以仅提供这一个具体答案并不是那么有用。但是,我们可以在这里概述一般过程,以及可能出错的地方。

请记住,分支和标签名称是 refsreferences 的特定形式。每个人只持有一个哈希 ID。标签名称通常包含标签 object 的哈希 ID(它构成带注释的标签)或提交对象的哈希 ID,并且一旦创建,就永远不会更改。但是,分支名称标识提交链中的一个提交,并且该提交被视为属于该分支的最后一个提交。 (可能有后续提交,但它们不包含在该分支中。请注意,由分支名称 标识的提交可以 包含在 other 中但是分支。)其结果是随着分支的增长,这些值 有规律地变化 。因此必须更新 配对。

这些名称-值对可能应该保存在某种事务数据库中,但不是。 Git 目前(从今天的 2.26.2 版本开始的所有版本,并且可能会持续相当长的一段时间)将所有这些引用存储在两个位置中的一个或两个位置:一个名为 [=11= 的平面文件],或存储在文件系统中的单个文件,例如 refs/heads/master。要查找名称,Git 首先检查单个文件是否存在。如果是这样,该文件将具有正确的值。如果不存在,Git 检查该名称是否存在于 packed-refs 文件中,如果存在,则使用那里的值。如果两次搜索都失败,则该名称不存在。

为了确保任何 update 是原子的——当一个 Git 命令正在更新它时,没有其他 Git 命令可以更新它——Git 使用仔细的顺序创建 .lock 文件。例如,要更新 refs/heads/master,Git 首先创建 refs/heads/master.lock1 主机 OS 必须(并且确实)提供 "create file, but fail if it already exists"为此操作。

这里可能会出错。例如,假设目录(或文件夹,如果您更喜欢该术语)refs/heads/ 拒绝处理 git push 进程的用户 ID 的创建新文件权限。在这种情况下,创建 master.lock 将失败并出现 "permission denied" 类错误。

在您的特定情况下,master.lock 文件已经存在。通常,此类文件会被创建、写入,然后被删除或重命名。但是,如果出现电源故障、系统崩溃或其他 Git 程序突然终止的情况,系统 不会 处于良好状态。特别是 .lock 文件继续存在。

对于电源故障或系统崩溃,可以在系统启动期间进入并删除挥之不去的.lock文件。实际上,这在大多数服务器上并不常见,无需费心——人们可以像您一样手动修复他们的 Git 服务器。 Git 程序通常 也不应该 被 OS 突然杀死,但是一些系统使用 "out of memory killers" (OOM-killers)会导致这种情况有时会出现问题。


1创建了适当的 .lock 文件后,Git 将继续将新值写入锁定文件,然后使用原子重命名将 master.lock 文件更改为名为 master 的文件的操作,删除任何先前的文件。释放锁并存储新值,所有这些都以这样的方式进行,即任何需要该值的 other Git 命令都会看到新值。

Git 在更新其索引文件时使用相同的技术来创建 index.lock,但是由于索引条目永远不会从一个 Git 转移到另一个 Git,这里的任何失败都是始终纯粹是本地的,而不是 git push 期间。这个技巧还有一个特点,就是一个"transaction"可以通过简单的删除锁文件变成"rolled back",而不是将锁文件重命名为主文件名。

使用数据库时请记住术语 ACID:原子性、一致性、隔离性、持久性。 .lock 文件技术提供原子性,如果 OS 做出正确的保证,一致性和持久性。但是,隔离 属性 完全缺失:我们无法自行更新一个数据库字段。这就是 为什么 Git 为每个引用使用单独的文件(除了,也就是说,当它不使用时,通过 packed-refs 文件,因此实际上读取-only:只有一个 Git 程序,git pack-refs,曾经更新过它,使用它自己更复杂的锁定)。

在处理非常大的索引时,缺乏隔离也会很痛苦。为此,Git 可以使用 "split index" 模式,其中一些条目(最近未更改的条目)在第二个文件中,只有 "actively changing" 条目在主 .git/index 文件。

(使用真实数据库可以解决所有这些问题以及其他多个问题,但真实数据库很复杂。)