修复从提交到提交的Git断开链接 [英] Repair git broken link from commit to commit

查看:10
本文介绍了修复从提交到提交的Git断开链接的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我遇到过git fsck调用返回几个断开的链接的情况。这是因为,对于该存储库,运行了rm命令并删除了几个写保护文件(错误)。该存储库也没有最近的备份(同样,出现了错误)。因为Git正在被使用,所以存储库并没有完全消失,但一些历史记录已经被篡改了。直到最近要重新同步到源时才注意到这一点,并且由于中断的历史记录,这一操作失败。

我希望修复此历史记录(如果可能),以便它可以与上游源合并。我认识到,我将无法恢复完整的历史记录,因为一些文件刚刚消失,但我希望尽可能多地保留这些文件,以便正常工作。

我查看了Linus的电子邮件,以及如何恢复损坏的Blob对象(MIT hosted copy),还查看了:

How to recover Git objects damaged by hard disk failure?

Repair corrupted Git repository

和许多其他链接一样,但我没有看到太多关于从提交到提交错误的断开链接的建议。请注意,我确实制作了此存储库的副本,因此我不会擦除任何内容。

git fsck的结果为

    $ git fsck
    broken link from commit <SHA1>
                  to commit <SHA2>
    broken link from   tree <SHA3>
                  to   blob <SHA4>
    ...
    dangling blob <SHA5>
    missing commit <SHA2>
    missing blob <SHA4>
    ...

当我通过git log查看GIT历史记录时,最终出现错误

error: Could not read <SHA2>
fatal: Failed to traverse parents of commit <SHA1>
它与上次备份的位置很接近,但不完全在那里,因此我没有重叠的覆盖范围。我想尝试反向遍历历史,认为我可以从最旧的提交日志移动到最新的提交日志

$ git log --reverse
error: Could not read <SHA2>
fatal: Failed to traverse parents of commit <SHA1>

所以我不能尝试在两端都绑定提交(除非有人知道如何这样做)。我尝试使用git repair,它似乎能够解决一些问题,但不是所有问题。从现在开始,它似乎也在破坏git log

$ git log
...
error: Could not read <SHA6>
fatal: Failed to traverse parents of commit <SHA7>

这在历史上发生的时间比这个问题早得多。有趣的是,这个提交确实存在于我最初未修复的存储库中。复制SHA文件可以让我跳过故障,但会突然出现另一个同样存在的故障。

它建议我运行git repair --force,但最终完全重新初始化了存储库,这也不是我真正想要的。

如何才能将此存储库还原到正常工作状态?

推荐答案

@leGEC为我整理这篇文章提供了最后几个部分,但我认为值得介绍我使用的全部方法。注意:我希望我能够做的很多事情都是针对我的情况的,但也有一些事情是可以概括的。

查看git fsck的结果时,我发现有几个悬而未决的提交。当我检查这些散列时,我发现了好的提交片段。因此,原始结构为

存储库
(a)->(b)->(c)->(d)->(e)->(f)->(g)->(h)->(i)->(j)

命令rm之后,

命令可能处于类似

的状态
(b)->(c) (e)->(f) (h)->(i)->(j)

如问题中所述,备份非常旧,格式为

(a)->(b)

但仅此而已。我们所能做的就是使用git replace来尝试解决这个问题。请注意git replace似乎是真正销毁存储库的优秀工具。我在我的原始存储库的副本上做了这件事,我很高兴这不是真正的交易!

我们将在新的(良好的)基础上构建我们的新存储库。我们首先从已有的备份中初始化一个新的存储库。

$ mkdir my/new/fixed/repository
$ cd my/new/fixed/repository
$ git init

现在,我们将从我们的备份(不包括损坏的存储库的全部空间)中解压现有结构。

$ git remote add origin /path/to/backup/repository
$ get remote fetch
$ get checkout --track my-broken-branch # This may not be necessary

为了避免破坏我们的存储库,我们制作了一个副本

$ cd /path/to/repository/root
$ mkdir repository-copy
$ cp -R /path/to/broken/repository /path/to/repository-copy
$ cd /path/to/repository-copy

首先,让我们尝试使用以前的存储库来修复我们所能修复的内容:

git remote add backup /path/to/backup/repository
git unpack-objects < /path/to/backup/repository/.git/objects/pack/pack-*.pack

好的,让我们看看损坏是什么:

$ git fsck
broken link from  commit <SHA1>
              to  commit <SHA2>
broken link from    tree <SHA3>
              to    blob <SHA4>
...
dangling commit <SHA5>
...
missing commit <SHA2>
...
missing blob <SHA4>
...
dangling commit <SHA6>
...

令人感兴趣的是悬挂提交,因为它们很可能是我们想要尝试缝合在一起的小子分支。请注意,这些提交并不总是按时间顺序进行的。对我来说,顺序恰好是(从最旧到最新)<SHA5>-<SHA6>,但您可能会有自己的结要解开。您可以通过运行

来检查提交日期/时间
$ git show -s <SHAX>

此时需要注意的一点是,如果您在损坏的存储库副本中,然后运行命令git log,您将能够遍历存储库,直到遇到错误:

error: Could not read <SHA2>
fatal: Failed to traverse parents of commit <SHA1>

因此,我们需要将的父对象替换为实际有效的提交。这种模式被称为嫁接,但由于新的(Er)最佳实践git replace,进行纯嫁接不再被认为是最佳实践(How do git grafts and replace differ? (Are grafts now deprecated?))。

所以我现在将

$ git replace --graft <SHA1> <SHA6>
$ git fsck
broken link from  commit <SHA1>
              to  commit <SHA2>
broken link from    tree <SHA3>
              to    blob <SHA4>
...
broken link from  commit <SHA7>
              to  commit <SHA8>

因此出现了新的中断提交。如果我使用调查提交,我发现前一个提交在剩余悬空提交时间之前结束。所以我要把这两者嫁接在一起。注意,如果您有很多人在这个存储库上工作,这样做可能不安全,但在这种情况下,我相信这是可以的。

$ git replace --graft <SHA7> <SHA5>
$ git fsck
broken link from  commit <SHA1>
              to  commit <SHA2>
broken link from    tree <SHA3>
              to    blob <SHA4>
...
broken link from  commit <SHA7>
              to  commit <SHA8>

没有新的悬空提交,在我的情况下,能够连接到我的备份存储库。在其他情况下,我认为这并不总是正确的。如果是这样的话,您最终可以将远程存储库的头部移植为剩余的错误提交链接。

现在我们必须处理丢失的斑点。您可以尝试按照Linus的方法修复它们,或者,如果您愿意接受丢失的历史记录,您可以再次使用git替换将它们从历史记录中删除。一般方法是

$ git ls-tree <SHA3>
...
100644 blob <SHA4>  my-magic-file
...
$ git log --raw --all --full-history -- subdirectory/my-magic-file | grep -B 20 -A 20 "<SHA4>" # May just need to use first few values from SHA4
# commit information after missing blob
# commit information for missing blob
# commit information before missing blob
$ git replace --graft <commit-after-missing-blob> <commit-before-missing-blob>

重复此操作,直到git rev-list --objects my/branch运行完成。

现在,您需要删除无关提交。幸运的是,已经开发了一种新的工具来完成这项工作:git-filter-repo。此工具将提交我们的嫁接并重构历史记录。

$ git filter-repo --force
$ git fsck
Checking object directories: 100%...
Checking objects: 100%...

现在让我们看看我们是否可以成功地从损坏的分支中获取存储库。

$ cd /path/to/my/new/fixed/repository
$ git fetch broken my/branch
...
From /path/to/my/broken/repository
 * branch            my/branch        -> FETCH_HEAD
 * [new branch]      my/branch        -> broken/my/branch

而且,因为我们与遥控器有共同的历史记录,所以我们现在可以与以前断开的分支合并

$ git merge broken/my/branch

并且历史记录再次干净。

这篇关于修复从提交到提交的Git断开链接的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆