致命:您当前的分支似乎已断开(可能是由于拉操作中断)



问题:

  1. 不小心修改了git,并将其推送到第一台计算机的usb密钥
  2. 从usb密钥拉到第二台计算机
  3. 第二个计算机存储库现在已损坏
  4. 将git拉到第一台计算机会导致合并冲突;对这是否也是一个腐败的状态感到困惑(如果修正案是腐败的)

症状:

大多数命令:

fatal: your current branch appears to be broken

.git/refs/heads/master:

$ cat .git/refs/heads/master

.git/refs/heads/master的文件目录:

'x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00x00'

$ git status
new file: ...
new file: ... [for every file in the repository; expected since on a corrupted branch]

我不确定我是否愿意责怪git——修正,因为它看起来有点温和;也许发生了其他事情。

如何修复?:

修复这一问题是否像从最近一次提交的.git/logs/refs/heads/master中获取哈希并手动将其插入.git/refs/hheads/master中一样简单?如果

如果是,我是否应该销毁违规的提交(这样以后就不会损坏东西,比如git-repack之类的)?

当我尝试less .git/logs/refs/heads/master并从表单的最后一行提取[edit:type错]第一个哈希时…

...
[hash for HEAD~2] [hash for HEAD~1] [authorname] ...
[hash for HEAD~1] [hash for HEAD] [authorname] ...
^^^^^^^^^^^^^^^^^   (corrupted)
EOF

然后粘贴到.git/refs/heads/master文件中,我现在被。。。

$ git fsck
error: inflate: data stream error (unknown compression method)
error: unable to unpack header of .git/objects/8f/1da374ffac3711f8cdde57379f90cb03bbb9ea
error: 8f1da374ffac3711f8cdde57379f90cb03bbb9ea: object corrupt or missing: .git/objects/8f/1da374ffac3711f8cdde57379f90cb03bbb9ea
error: inflate: data stream error (unknown compression method)
error: unable to unpack header of .git/objects/ac/2fcd052804fb7adac465220da5bcb04d008fc7
error: ac2fcd052804fb7adac465220da5bcb04d008fc7: object corrupt or missing: .git/objects/ac/2fcd052804fb7adac465220da5bcb04d008fc7
Checking object directories: 100% (256/256), done.
Checking objects: 100% (1147/1147), done.
error: inflate: data stream error (unknown compression method)
error: unable to unpack 8f1da374ffac3711f8cdde57379f90cb03bbb9ea header
error: inflate: data stream error (unknown compression method)
error: unable to unpack 8f1da374ffac3711f8cdde57379f90cb03bbb9ea header
fatal: loose object 8f1da374ffac3711f8cdde57379f90cb03bbb9ea (stored in .git/objects/8f/1da374ffac3711f8cdde57379f90cb03bbb9ea) is corrupt

我可以尝试销毁松散的对象,但我不确定它是否是指向(例如树)必须销毁的更腐败对象的指针。如果我知道推荐,我当然可以尝试销毁这个对象(或者可以尝试在备份上rm它);我应该试试吗?

此外,我该如何修复USB密钥和其他来自此混乱的回购?谢谢

(对新手来说可能有用的参考资料,不太可能帮助有能力回答这个问题的人:https://aboullaite.me/deep-dive-into-git-git-refs/)(类似的致命问题:您当前的分支似乎被破坏了——没有说明错误的原因;许多事情可能会导致这个错误)


编辑:

我为上面列出的每个对象都做了rm .git/objects/...,现在我有了。。。

$ git fsck
Checking object directories: 100% (256/256), done.
Checking objects: 100% (1147/1147), done.
error: refs/remotes/origin/HEAD: invalid sha1 pointer 0000000000000000000000000000000000000000
error: refs/remotes/origin/master: invalid sha1 pointer 0000000000000000000000000000000000000000
error: HEAD: invalid reflog entry 8f1da374ffac3711f8cdde57379f90cb03bbb9ea
error: refs/heads/master: invalid reflog entry 8f1da374ffac3711f8cdde57379f90cb03bbb9ea
error: bad ref for .git/logs/refs/remotes/origin/HEAD
error: bad ref for .git/logs/refs/remotes/origin/master
error: ac2fcd052804fb7adac465220da5bcb04d008fc7: invalid sha1 pointer in cache-tree
broken link from    tree b0d598ef5427d59ed31eb1b315c761fc89af40b7
to    tree ac2fcd052804fb7adac465220da5bcb04d008fc7
dangling blob f4e39c36cc8df3f9f324c0ccca4ed6a7a3ffe6ac
dangling tree 068716abcf815b4eaf8f0fe74c3020bf6251bba0
dangling blob fb4cfe7c94e8b4d800fdb4935806577b2b99fd94
dangling blob 35cf2ca2ed03811c14f1598c50daacfab9032b8f
missing tree ac2fcd052804fb7adac465220da5bcb04d008fc7
dangling blob d056e38af637cf0de76dac5689a8c5e735d75793
dangling blob 3b3903cc7b4eb035e9c4508024acc3f81c015741
dangling blob b09c3cc95935a327ecf7fad8374f14c4e320f67e

问题的根源很可能是在操作系统将写入USB密钥之前或期间删除了USB密钥。这留下了许多损坏的文件。

由于任何原因不当关闭计算机而损坏的文件——拔出USB密钥是其中之一,但操作系统崩溃、电源故障、计算机着火等也是其中之一——往往会导致最近写入的文件损坏。刚刚安静地放置的文件往往是完整的。这里有很多注意事项,但这个一般原则适用于这里。

  • 如果更新分支,包含分支信息的文件可能会损坏。

    此处,损坏的文件包括.git/refs/heads/master。该文件应包含41个字节,其中包括提交的散列ID的40字节文本表示,该散列ID应被视为分支master的顶端,后跟ASCII换行符没有定义的方法来猜测哪个提交是正确的提示提交,这就是为什么Git在一些文件中存储了"master*的提示提交的哈希ID是多少"问题的答案。

    (在某些情况下,.git/packed-refs中可能有一个有效的答案,但通常情况下,如果.git/refs/heads/master存在,它应该包含正确的答案。正确的答案会随着时间的推移而变化,通过创建新的提交、运行git reset、运行git branch -f等等。)

  • 损坏的文件可能包括.git/index,它包含Git的索引暂存区。这两个术语在Git中的含义相同,对于同一个文件,还有第三个现在很少使用的术语,缓存。除了在使用索引处理冲突合并时,索引文件中的内容大多非常容易重新计算:Git使用它来加快速度,即作为缓存,因此是第三个很少使用的术语。

    如果(大多数情况下)缓存中没有无法重新计算的内容,您可以简单地删除.git/index,然后运行git reset来重新计算它。这将使所有"新文件…"消息消失,唯一丢失的是您是否进行了一些特定的更新。

    这个词经常出现在这里,因为索引包含您打算在下一次提交中放入的所有blob对象("文件")的哈希ID。如果你做了一些不寻常的事情,比如创建一个新的唯一版本的文件,并将其放入索引,然后从其他地方将其删除,那么在任何地方都可能很难找到该唯一版本文件的哈希ID。当使用git add -pgit reset -p暂存与提交版本工作树版本都不同的文件的第三个变体时,可以获得此信息。在这种情况下,删除并重新创建索引(使用rm .git/index; git reset)将使重建该文件的最简单方法是重新运行git add -pgit reset -p操作。

    在您的情况下,似乎有可能索引被完全删除,导致Git声称每个文件都是新的。这与运行rm .git/index时得到的结果相同,所以您还不如运行git reset。然而,由于这条消息,这里肯定还有其他事情在发生:

    error: ac2fcd052804fb7adac465220da5bcb04d008fc7: invalid sha1 pointer in cache-tree
    

    这里的cache-tree是指索引中的内容,使用其旧名称cache。但由于这是"缓存",删除并重新创建索引可能会解决问题,具体取决于其他因素。

  • 损坏的文件可能包括您的一些工作树文件。Git无法帮助你:管理这些文件的是你电脑的其他部分。当你git checkout一些现有的提交时,Git会将文件的副本写入到你的工作树中,这样它们就成了你可以看到和使用的形式,但在那之后,一切都由你/你的计算机来管理。

  • 损坏的文件可能包括Git的一些内部对象。在你的情况下,这显然确实发生了:

    error: unable to unpack header of .git/objects/8f/1da374ffac3711f8cdde57379f90cb03bbb9ea
    error: 8f1da374ffac3711f8cdde57379f90cb03bbb9ea: object corrupt or missing: .git/objects/8f/1da374ffac3711f8cdde57379f90cb03bbb9ea
    

    这意味着对象8f1da374ffac3711f8cdde57379f90cb03bbb9ea已损坏。如果没有进一步的信息,就不可能判断这个对象是什么类型,更不用说其中有什么数据以及它们是否有价值了。

  • 损坏的文件可能包括存储在.git/logs/中的各种reflog。在这种情况下,您得到:

    invalid reflog entry 8f1da374ffac3711f8cdde57379f90cb03bbb9ea
    

    和:

    error: refs/heads/master: invalid reflog entry 8f1da374ffac3711f8cdde57379f90cb03bbb9ea
    

    使用相同的数字。这是我们刚才看到的损坏的对象哈希ID。由于分支名称是指向提交对象所必需的,因此我们现在可以猜测8f1da374ffac3711f8cdde57379f90cb03bbb9ea在被损坏之前是一个提交对象。它可能是最近创建的提交,例如git commit --amend所做的提交。

从所有这些中,我们可以得出结论——但这仍然是一种猜测——git commit --amend提交本身已经损坏,并且master中损坏的哈希ID应该是文本8f1da374ffac3711f8cdde57379f90cb03bbb9ea。索引可能已损坏或完全删除,但通常只需删除它并重建其缓存方面就足够安全了,因此您可以再次删除它(如果必要),然后在获得合理的"当前提交"后从当前提交中重建它。你的一些reflog可能会被损坏,但无论如何,reflog都是辅助数据:它们中的任何东西对Git自己的操作都不是关键的,所以损坏的可以被截断。最大的问题是损坏的.git/objects/文件。

如果您愿意丢失该提交,则可以简单地删除损坏的对象并将有效的哈希ID放入.git/refs/heads/master中。当你这么做的时候,你的fsck仍然抱怨:

error: ac2fcd052804fb7adac465220da5bcb04d008fc7: invalid sha1 pointer in cache-tree
broken link from    tree b0d598ef5427d59ed31eb1b315c761fc89af40b7
to    tree ac2fcd052804fb7adac465220da5bcb04d008fc7

现在,第一行仍然指向从.git/index读取的内容。移除和重置将通过将所选提交的哈希ID写入.git/refs/heads/master来重建索引/缓存如果树对象ac2fcd052804fb7adac465220da5bcb04d008fc7未在存储库中的其他位置使用,则可能会留下一个完整的存储库。

如果没有,那么只有两种方法可以使这个特定的Git存储库自我一致:

  1. 删除直接或间接引用该树对象的所有提交及其所有子体(如果有的话)。

  2. 获取或重建丢失的对象。如果它在其他Git存储库中,也就是这个存储库的克隆中,那么获取它的方法很简单。在拥有它的存储库中运行git cat-file -p ac2fcd052804fb7adac465220da5bcb04d008fc7。结果是树的文本表示。使用git hash-object -t tree -w在USB密钥存储库中创建对象,使其现在存在。

请注意,此获取或重建方法适用于任何损坏或丢失的对象:哈希ID在每个克隆中都是全局唯一的,因此,如果您可以在其他克隆中找到对象,则可以从其他克隆复制对象

结论

我该如何修复USB密钥和其他回购?

最清晰的方法是使用其他克隆。查找同一存储库的未损坏的克隆。制作该克隆的克隆,作为新的"修复的克隆"结果。在这个新的克隆中,从损坏的存储库中添加新的对象——新的标记、树、Blob和提交——它们本身没有损坏。(您可以使用cp或使用git cat-file -p <hash> | git hash-object -t <type> --stdin直接复制它们。)这样,您只能中读取损坏的克隆。

当你击中一个损坏的物体时,尽可能多地恢复有用的数据,然后继续前进

结果将始终是一个良好有效的克隆,具有尽可能多的恢复数据您将确切地知道您恢复了什么和丢失了什么。你甚至可以有一些文件丢失的提交(因为它们的内部blob对象被不可恢复地损坏):你可以在某个地方保存一个注释,也许使用git notes,也许只是在纸上,然后回去重建你可以重建的东西,例如。

这种方法往往是缓慢和痛苦的。您使用的方法——尝试在适当的位置修复损坏的克隆——更快、更容易,但可能会给您留下一些隐藏的问题(例如,丢失的提交,您只是不记得了,它是在之后出现的,因为它被损坏了,您故意将其删除)。

Git 2.40(2023年第1季度)在类似的场景(中断拉取)中应该更健壮。

首先,不要忘记激活core.fsync=reference,正如我在这里提到的(Git 2.36+)

Git 2.40修复了忘记将输出刷新到磁盘的fsync$GIT_DIR/packed-refs文件的序列。

参见Patrick Steinhardt提交的ce54672(2022年12月20日)(pks-t)
(由Junio C Hamano合并——gitster——于2023年1月2日提交3ed91c5)

refs:通过未正确将打包的引用同步到磁盘来修复损坏

签字人:Patrick Steinhardt

在GitLab,我们最近收到一份报告,其中一个存储库在节点硬崩溃后留下了损坏的packed-refs文件,尽管设置了core.fsync=reference
如果我们正确地将原子重命名为,理论上就不应该发生这种情况

  1. 将数据写入临时文件
  2. 将临时文件同步到磁盘
  3. 将临时文件重命名到位

因此,如果我们在写入packed-refs文件的过程中崩溃,我们应该只能看到文件的旧状态或新状态。

当我们在写packed-refs文件时跳舞时,确实有一个问题:我们使用FILE *流来写临时文件,但在将其同步到磁盘之前不要刷新它。

因此,任何仍在缓冲的数据都将无法同步,机器崩溃可能会导致损坏。

通过在fsync之前刷新文件流来修复此错误。

[暂时回答自己的问题,但我想接受一个实际有效的答案]

  • 计算机1:
    • 在第一个repo上运行git fsck以冲突它没有损坏
    • 将repo文件夹复制到计算机1上的备份
    • 在计算机1上提交任何内容(和/或如果只有您,则可能重新基准)
    • push-to-usb密钥(选项:事先在usb密钥上运行git fsck;不确定如何在裸repo上运行,所以我将其克隆到临时repo…)
  • 计算机2:
    • 将计算机2上损坏的repo文件夹复制到备份
    • git clone从usb密钥恢复repo

这显然不是一个答案,但目前有效("足够好"),但解决这一问题的正确方法可能会使社区受益。

最新更新