处理Git“Could not read”错误的方法

59

我在我的git仓库中遇到了这个错误:

22:09:15 $ git status
# On branch master
error: Could not read 8124cc15c63be92d534e4cdfa33c38d54deee122
error: unable to read tree object HEAD
nothing to commit (working directory clean)

在谷歌搜索中,error: unable to read tree object HEAD似乎没有什么有用的结果,这个错误看起来非常罕见。我不确定该如何处理它。这可能是硬盘故障吗?

编辑: git fsck的输出如下:

broken link from  commit 607328dc80e4901a55b95c683d4fbf43e6df28bf
              to    tree 8124cc15c63be92d534e4cdfa33c38d54deee122
missing tree 8124cc15c63be92d534e4cdfa33c38d54deee122
dangling tree 56b5d4a5e429d251582ec927bca7ef1225510c41
dangling tree 0259d2d38b18b6136bb6070fb41faf3624453cc6

这听起来像是某种损坏。你尝试过 git fsck 吗? - 1800 INFORMATION
10个回答

33
在"链接已损坏"的消息中,您可以遵循GitFaq建议
备份所有状态,以便如果您更改了内容,则可以重新执行任何操作!
解压任何损坏的包文件
参见“man git-unpack-objects”,特别是“-r”标志。
还要注意,它只会解压尚不可用的对象,因此您需要将包文件移出其正常位置(否则git-unpack-objects将在包文件本身中查找所有在包文件中的对象,并且不会解压任何东西)
替换任何损坏和/或缺失的对象
这是具有挑战性的部分。
有时(希望经常!)您可以在其他副本的存储库中找到丢失的对象。
在其他情况下,您可能需要尝试以其他方式找到数据(例如,也许您签出的副本包含哈希后将成为缺失对象的文件内容?)
确保使用“git fsck --full”一切正常
重新打包所有内容以恢复有效状态

注意事项:

2016年7月更新(7年后),随着Git 2.10即将发布,现在您可以:

git fsck --name-objects

它帮助命名那些破损链接的来源。

查看 "如何修复从树到树的git错误破损链接?" 获取更多信息。


24

我刚遇到了一个类似的问题。当我的笔记本电脑在进行git pull时强制关机时,产生了数据损坏。我有一个远程备份仓库。首先,在.git/objects/??/*中出现了几个大小为零的对象文件。 在备份了仓库的cp -a之后,我执行了以下操作:

  • 删除零长度对象
  • 将远程仓库克隆到 ../fresh/ 仓库中
  • 在损坏的仓库中,我执行了以下命令:

    cat ../fresh/.git/objects/pack/pack-*.pack | git unpack-objects

这样可以填充对象数据库中缺失的对象。现在,该仓库似乎已经恢复正常。


奇怪,Git 抱怨我的一个包文件损坏了。我刚刚使用这个命令解压了那个损坏的包文件,在解压过程中没有抱怨任何损坏,现在 git fsck 又正常了! - thenickdude
这会输出二进制数据,例如 PACK^@^@^@^B^@^@^@,需要将其保存在某个地方吗? - glen
@ElanRuusamäe 真的吗?它不应该输出打包数据。你忘记了 | git unpack-objects 管道部分了吗? - Tilman Vogel

7

我曾经遇到过同样的问题。经过长时间的摸索,我发现这是由于更改了仓库的git文件权限所致。我已按照以下步骤解决了此问题:

$ cd .git
$ chmod 755 *

完成!


那在我的情况下就是原因,虽然你的建议本可以防止它发生,但现在问题已经出现了 - 我的存储库已经损坏了。我通过重命名项目、从其他地方重新克隆并通过从重命名的项目中复制文件来重新创建我失去的一些提交。我使用的是较旧的Ubuntu LTS版本,因此只有git 1.5.4.3。 - rjmunro

5

在我的Homebrew安装的Git存储库中,我遇到了类似的错误。与其逐个恢复所有缺失的对象,我发现更容易的方法是简单地删除.git目录,并通过重新从Homebrew's public repository克隆来创建它。以下是我的步骤:

  1. 检查你的Git仓库中有哪些信息是重新克隆无法获取的。对于我来说,它包括私有分支、存储和远程。
    • 将存储转换为真正的提交,方法是创建一个新分支,应用存储,并使用类似“[WIP]”这样的名称进行提交以显示它是一个存储。
    • 通过将其推送到自己的远程上,保存不在公共远程上的分支。这可以是GitHub上存储库的分叉,也可以是机器上不同位置的新Git存储库。
    • 如果你有多个远程,请保存git remote -v的输出,其中包含你的远程的名称和URL,以便稍后手动添加它们。
  2. 删除你的仓库的.git目录(或将其重命名为.git-broken并稍后删除)。在命令行中,使用rm -rf .git
  3. 使用git clone https://github.com/Homebrew/homebrew.git或其他URI重新克隆远程目录。
  4. 这将创建一个名为存储库的新子文件夹homebrew。你只需要从那里获取.git目录;你的本地文件已经没问题了。所以使用mv homebrew/.git .git,然后删除homebrew文件夹。
  5. 由于你从头重新创建了Git仓库,它应该没有任何错误。现在只需恢复第一步中保存的任何信息即可。
    • 如果你有其他远程,请使用git remote add <name> <url>再次添加它们。
    • 如果你将任何分支(或转换为分支的存储)备份到远程存储库,请从该存储库中将它们拉到本地存储库。
    • 如果你想要,可以通过使用git reset HEAD^回滚“[WIP]”提交并将工作目录再次保存到存储中git stash save <custom-message>,将存储分支转换回存储。
如果你运行 git fsck,应该看到没有错误:
$ git fsck
Checking object directories: 100% (256/256), done.
Checking objects: 100% (197135/197135), done.
Checking connectivity: 197162, done.
$

执行 git stash listgit branchgit remote -v 命令,输出结果应与之前相同。


1

我通过移除远程并重新添加解决了这个问题。

我使用了git fsck --name-objects命令,它显示出多个分支损坏。删除本地和远程的这些分支副本并没有解决问题。

然而,解决方法是:

git remote remove origin

然后:

git origin add origin <my-origin>

我这样做之后,一切都恢复正常了。


0
如果您没有未提交的更改,最简单的解决方案是删除本地分支: git branch -D [分支名称]
然后再次检出远程分支: git checkout -b [分支名称] origin/[分支名称]

0

我通过从远程服务器目录中删除Capistrano的'repo'文件夹来解决了这个错误。我尝试了许多其他建议的解决方法,发现问题并不在我的本地项目上。问题似乎出现在Capistrano执行从repo到远程的拉取时。对我来说,这可能是由于停止的部署留下了损坏的对象/对象引用。我的主机也刚刚进行了服务器迁移,也许在此过程中某些东西变得损坏了。


0
我通过在同一目录/项目文件夹中进行更改来修复了错误,然后尝试提交新更改,结果出现了错误消息“无效对象100644 e38e910ceb18b09f436f353c3a131bfe2caba130 for 'Book/alise_mathe/app/src/main/res/menu/drawermenu.xml'”。这个消息解决了问题,我只是通过将文件名更改为“drawer_menu.xml”来重构drawermenu.xml。添加更改,提交并推送即可。(Android Studio)
希望这能帮到你。

0
如果以上步骤都不起作用,而你有本地更改需要保留,并且远程存储库也需要保持完好,那么此重置脚本会奏效。
如果你还需要保留你的存储区,可以手动复制以下文件:
  • .git/objects
  • .git/refs/stash
  • .git/logs/refs/stash

0

对于任何缺失的引用或服务器未发送所有对象错误消息,我的通常解决方案如下:

当前存储库文件夹名为“original”

  1. 创建一个新文件夹 - 以下称为“new”

  2. 在“new”中运行git init

  3. original\\.git\config复制到new\\.git\config

    (这是一种快速/简便的方法,将所有远程添加到新的存储库中)

  4. 在“new”中运行git fetch --all --tags

(从服务器获取每个对象)

  1. 将文件夹new\\.git\objects移动到original\\.git
  2. 让操作系统合并文件夹,如果出现替换确认,请选择否(非常罕见)
  3. 在“original”中运行git gc (删除重复对象和您实际不需要的对象)
  4. 删除“new”

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