Git![远程拒绝] master -> master(无法锁定)

3
我无法将代码推送到我的git仓库。使用git clonegit pull正常,但是git push不行。
我查看了其他帖子,例如这里,尝试了一些方法,如使用git push origin master --force。但错误仍然存在。
以下是屏幕截图。 enter image description here 其他细节:
$ 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 push origin master:master吗?说实话,我无法解释原因 - 我查找了你的错误并尝试了很多普遍的建议,但导致这种错误的原因千差万别,据我所知,你没有遇到这些问题。唯一的共同点是Git对分支及其实际分支的信息存在某种问题。有时它尝试推送到大小写不正确的分支名称,有时它尝试推送到一个名为a/b的分支,但已经存在一个名为a的分支。或者本地git索引中可能只是存在一些垃圾信息。 - VLAZ
@VLAZ 谢谢您的指示。但是 git push origin master:master 的输出与 git push origin master 相同。 - Miron
“failed to lock” 是 Git 报告的错误,这个错误是由另一个Git中的锁定失败引起的,在这种情况下,至少不是由你可以从你的端解决的任何问题导致的。你需要让有服务器访问权限的人进去查看出了什么问题并在那里进行修复。 - torek
很有可能是权限问题,尽管具体情况部分取决于服务器运行的操作系统以及该操作系统的配置方式。Windows系统存在打开文件的问题;当您启用最严格的安全选项(SELinux)时,Linux系统会变得无法使用。 - torek
@torek没错。 我从存在master.lock文件的服务器检查了'ref/heads',在我删除该文件后,git push成功了。你能把你的评论作为答案发布,并解释可能出现锁文件的情况吗? - Miron
2个回答

2
这种失败有几个可能的原因。根据评论,这实际上是服务器上残留的master.lock文件。手动删除即可解决。
因为失败可能有多个原因,提供仅此一个特定答案并不是很有用。然而我们可以在这里概述一般流程以及可能出现的问题。
请记住,分支和标签名称是引用或参考的特定形式。每个名称只包含一个哈希ID。标签名称通常保存标签对象(制作注释标签)或提交对象的哈希ID,并且一旦创建就永远不会更改。但是,分支名称标识链中的一个提交,该提交被视为是该分支的最后一个提交。 (可能存在后续提交,但它们不包含在该分支中。请注意,由分支名称标识的提交可以包含在其他分支中。)这的结果是这些值会随着分支增长而经常更改。因此,名称值对必须更新。
这些名称-值对应该保存在某种事务性数据库中,但实际上并没有。Git目前(截至今天的2.26.2版本及以前的所有版本,以及未来相当长一段时间内)将所有这些引用存储在两个地方中的一个或两个位置:单个名为packed-refs的平面文件,或者存储在文件系统中的单独文件,例如refs/heads/master。要查找名称,Git首先检查单个文件是否存在。如果是,则该文件将具有正确的值。如果没有,则Git会检查名称是否存在于packed-refs文件中,如果存在,则使用那里的值。如果两个搜索都失败,则名称不存在。
为了确保任何更新是原子的——即在一个Git命令更新名称时,没有其他Git命令可以更新它——Git使用一系列谨慎的创建.lock文件的序列。例如,要更新refs/heads/master,Git首先创建refs/heads/master.lock1主机操作系统必须(并且确实)为此提供“创建文件,但如果它已经存在则失败”的操作。
事情可能出现问题。例如,假设目录(或文件夹,如果您更喜欢该术语)refs/heads/拒绝向处理git push进程的用户ID授予创建新文件的权限。在这种情况下,创建master.lock将失败,并出现“权限被拒绝”类型的错误。
在您的特定情况下,master.lock文件已经存在。通常,这些文件会被创建、写入,然后删除或重命名。但是,在Git程序意外终止的情况下,如断电、系统崩溃等,系统并不处于良好状态。特别是,.lock文件仍然存在。
对于断电或系统崩溃,可以在系统启动时进入并删除残留的.lock文件。但实际上,在大多数服务器上,这种情况并不常见,人们可以像您一样手动修复其Git服务器。Git程序通常也不应该被操作系统突然终止,但有些系统使用“内存杀手”(OOM-killers),有时会导致此类问题。
创建适当的.lock文件后,Git将继续将新值写入锁文件,然后使用原子重命名操作将master.lock文件更改为名为master的文件,删除任何先前的文件。这既释放了锁定,又以一种方式存储了新值,以便任何需要该值的其他 Git命令都将看到新值。
Git在更新其索引文件时使用相同的技术来创建index.lock,但由于索引条目从未从一个Git传输到另一个Git,因此任何故障都始终是纯粹的本地故障,而不是在git push期间发生的故障。此技术具有另一个特点,即“事务”可以通过简单地删除锁文件而不是将锁文件重命名为主名称来“回滚”。
在处理数据库时,请记住术语ACID:原子性、一致性、隔离性、持久性。.lock文件技术提供了原子性,并且如果操作系统提供了正确的保证,则提供了一致性和持久性。但是,隔离属性完全缺失:我们无法单独更新一个数据库字段。这就是为什么Git对每个引用使用单独的文件(除非通过packed-refs文件,它实际上是只读的:只有一个Git程序git pack-refs会使用其自己更复杂的锁定来更新它)。
缺乏隔离性在处理极大的索引时会非常痛苦。因此,Git 可以使用“分裂索引”模式,在这种模式下,一些条目(那些最近没有被更改的条目)存储在第二个文件中,只有“正在活跃更改”的条目才存储在主要的 .git/index 文件中。
(使用真正的数据库可以解决所有这些问题以及其他多个问题,但真正的数据库是复杂的。)

1

首先检查git ls-remote返回的内容。

目标是确保没有以下情况:

  • 名为master/xxx的远程分支(如此处所示
  • 名为Master的远程分支(大小写不同:还需检查本地.git/refs/heads是否存在同样的问题)

太好了,这也是我的研究结果。所以,我并没有离谱。如果OP使用的是一个新的git仓库,并且默认分支是master,那么我会感到惊讶。然而,我能找到的所有关于这个错误的信息都表明这不是这种情况。 - VLAZ

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