1

问题:

  1. 不小心做了一个 git --amend 并将其从第一台计算机推送到 USB 密钥
  2. 从 USB 密钥拉到第二台计算机
  3. 第二台计算机存储库现已损坏
  4. git pull 到第一台计算机导致合并冲突;对这是否也是损坏状态感到困惑(如果 --amend 已损坏)

症状:

大多数命令:

fatal: your current branch appears to be broken

.git/refs/heads/master:

$ cat .git/refs/heads/master

.git/refs/heads/master 的文件内容:

'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00'

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

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

怎么修?:

解决这个问题就像从 .git/logs/refs/heads/master 的最新良好提交中获取哈希并将其手动插入 .git/refs/heads/master 一样简单吗?我该怎么做,如果

如果是这样,我应该销毁有问题的提交(这样它就不会在以后破坏东西,比如 agit-repack或其他东西)?

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

...
[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 密钥和其他 repo?谢谢。

(对新手可能有用的参考资料,不太可能帮助有能力回答这个问题的人: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
4

2 回答 2

2

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

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

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

    在这里,损坏的文件包括.git/refs/heads/master. 该文件应包含 41 个字节,其中包含一个 40 个字节的文本表示,表示提交的哈希 ID,应被视为 branch 的尖端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 -p或暂存与提交版本工作树版本git reset -p不同的文件的第三个变体时,您可能会得到这个。在这种情况下,删除并重新创建索引(使用)将使重建该文件的最简单方法是重新运行or操作。rm .git/index; git resetgit add -pgit reset -p

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

    error: ac2fcd052804fb7adac465220da5bcb04d008fc7: invalid sha1 pointer in cache-tree
    

    这里cache-tree指的是索引中的东西,使用它的旧名称cache。但由于这是“缓存”,删除和重新创建索引可能会解决问题,这取决于其他事情。

  • 损坏的文件可能包括您的一些工作树文件。Git 无法帮助您解决这些问题:管理这些文件的是您计算机的其余部分。当您进行一些现有的提交时, Git会将文件的副本写入git checkout您的工作树,以便它们采用您可以查看和使用的形式,但在那之后,这一切都由您/您的计算机来管理。

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

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

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

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

    invalid reflog entry 8f1da374ffac3711f8cdde57379f90cb03bbb9ea
    

    和:

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

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

从所有这些中,我们可以得出结论——但这仍然是一个猜测——git commit --amend提交本身被破坏了,并且损坏的哈希 IDmaster应该是 text 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. remove-and-reset 将从您选择的提交中重建索引/缓存,方法是将其哈希 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或者可能只是在纸上,关于这个,然后回去重建你以后可以重建的东西,因为实例。

这种方法往往缓慢而痛苦。您使用的方法(尝试就地修复损坏的克隆)更快更容易,但可能会给您留下一些隐藏的问题(例如,丢失的提交,您只是不记得,这是您故意破坏的提交之后发生的,因为它被损坏了)。

于 2019-11-02T18:10:22.547 回答
0

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

  • 电脑1:
    • 在第一个 repo 上运行git fsck以冲突它没有损坏
    • 将 repo 文件夹复制到计算机 1 上的备份中
    • 在计算机 1 上提交任何东西(和/或如果只有你,可能会变基)
    • 推送到 USB 密钥(选项:git fsck事先在 USB 密钥上运行;不确定如何在裸仓库上运行,所以我将其克隆到临时仓库......)
  • 电脑2:
    • 将计算机 2 上损坏的 repo 文件夹复制到备份
    • git clone从 USB 密钥恢复 repo

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

于 2019-11-02T06:05:58.620 回答