Git: “损坏的松散对象”

508
每当我从远程拉取时,都会出现关于压缩的以下错误。当我运行手动压缩时,也会出现相同的错误。
$ git gc
error: Could not read 3813783126d41a3200b35b6681357c213352ab31
fatal: bad tree object 3813783126d41a3200b35b6681357c213352ab31
error: failed to run repack

我需要知道,关于这个问题应该怎么处理?

从cat-file命令中,我得到了以下内容:

$ git cat-file -t 3813783126d41a3200b35b6681357c213352ab31
error: unable to find 3813783126d41a3200b35b6681357c213352ab31
fatal: git cat-file 3813783126d41a3200b35b6681357c213352ab31: bad file

我从 git fsck 中得到了以下信息(不确定是否与此相关):

$ git fsck
error: inflate: data stream error (invalid distance too far back)
error: corrupt loose object '45ba4ceb93bc812ef20a6630bb27e9e0b33a012a'
fatal: loose object 45ba4ceb93bc812ef20a6630bb27e9e0b33a012a (stored in .git/objects/45/ba4ceb93bc812ef20a6630bb27e9e0b33a012a) is corrupted

有人能帮我解密这个吗?


5
谢谢...但是如何"看"一个对象呢?我对Git还很新 :) - asgerhallas
2
“git show” 给我的信息和 “git fsck” 已经给的一样,很遗憾没有更多的信息。 - asgerhallas
6
Linus Torvalds写了一份有关此错误的有用文档,以及如何手动重建blob对象的方法(如果您拥有文件):如何恢复损坏的blob对象 一些技巧来重建blob对象以修复损坏的存储库 - Uwe Kleine-König
2
你能否添加一些注释或编辑已接受的答案?我处于完全相同的情况下,已接受的答案似乎没有足够的细节来“Just Work TM”,而是会迫使我自己深入了解细节。 - ripper234
相关链接:https://dev59.com/PnRA5IYBdhLWcg3w2x2W - Vadzim
显示剩余3条评论
34个回答

526

我也曾经遇到过这个问题(不知道为什么)。

此修复方法需要访问未损坏的远程仓库副本,并将保留您的本地工作副本。

但它也有一些缺点:

  • 你将失去未推送的任何提交记录,并且必须重新提交它们。
  • 你将失去任何暂存的更改。

修复方法

从您的仓库上级目录执行以下命令(将“foo”替换为您的项目文件夹名称):

  1. 备份损坏的目录:
    cp -R foo foo-backup
  2. 将远程仓库克隆到一个新目录中:
    git clone git@www.mydomain.de:foo foo-newclone
  3. 删除损坏的 .git 子目录:
    rm -rf foo/.git
  4. 将新克隆的 .git 子目录移动到 foo 目录下:
    mv foo-newclone/.git foo
  5. 删除其余的临时克隆:
    rm -rf foo-newclone

在 Windows 上,你需要使用以下命令:

  • copy 代替 cp -R
  • rmdir /S 代替 rm -rf
  • move 代替 mv

现在,foo 恢复了它的原始 .git 子目录,但所有本地更改仍然存在。git statuscommitpullpush 等也可以正常工作。


13
这个方法对我起作用了,但我认为所有未推送的提交都丢失了。仓库数据没有受到影响。 - wonton
38
是的,未推送的提交信息将会丢失。但在普通情况下(没有除当前分支以外具有未推送更改的多个本地分支),所有最近的文件修改(包括删除)仍然保存在磁盘上,因此可以轻松地重复任何以前未推送的提交。由于我总是在一系列提交之后进行推送,所以我甚至没有遇到过这种问题。 - cubic lettuce
10
简单明了直接。在我看来,如果您不完全理解 Git,也不想折腾自己的代码库,这是最有效的解决方案。 - Oliboy50
4
我认为这将删除所有藏匿文件,因为它们被存储在.git子目录下。 - Anthony Elliott
5
如果项目中有子模块,需要在获取.git文件夹之前先初始化它们。 - AdrieanKhisbe
显示剩余13条评论

429

你最好的选择可能是从远程仓库(例如GitHub或其他)重新克隆。不幸的是,你将失去任何未推送的提交和储藏的更改,但是你的工作副本应该保持不变。

首先备份本地文件的副本,然后从你的工作树顶级目录执行以下操作:

rm -fr .git
git init
git remote add origin [your-git-remote-url]
git fetch
git reset --mixed origin/master
git branch --set-upstream-to=origin/master master

然后根据需要提交任何更改过的文件。


19
个人认为,这应该是被接受的答案。比删除存储库并重新克隆要简单得多! :) 虽然你会失去任何暂存的提交... - Nick
10
显然,如果在发生损坏时您所在的分支与主分支不同,请将 master 替换为您的分支名称。 - Timothy Zorn
1
我的代码库中有一个子模块没有损坏。这个过程使得代码库和它的子模块处于一种状态,例如 git status 命令会返回 fatal: Not a git repository: submodules/my-sub/../../.git/modules/my-sub。从文件系统中删除子模块并重新启动该过程可以恢复正常。可能首先确保子模块中没有未推送的变更集是一个好主意... - Steven Baldasty
8
我今天做了这件事,没有丢失文件中未提交的更改 :) (git 2.17.1) - Fábio Dias
2
如果您看到此消息,可能需要将“master”分支更改为“main”分支。 - CrowRish
显示剩余11条评论

351

在我的笔记本上使用虚拟机时,电池耗尽后出现以下错误:

error: object file .git/objects/ce/theRef is empty error: object file .git/objects/ce/theRef is empty fatal: loose object theRef (stored in .git/objects/ce/theRef) is corrupt

我只用了2个命令就成功地恢复了代码库,并且没有丢失我的工作(修改过的文件/未提交的更改)。

find .git/objects/ -size 0 -exec rm -f {} \;
git fetch origin

之后我运行了git status,仓库没有问题,并且有我的更改(等待被提交,现在就提交吧…)。

git版本1.9.1

记得备份所有你记得的更改,以防这个解决方案不起作用并需要更彻底的方法。


16
在删除空对象后,您可能需要运行 git symbolic-ref HEAD refs/heads/master - Stephan
谢谢!这简直像魔法一样!它节省了我的时间。 - undefined

69

看起来你的树对象已经损坏了,你需要从别人那里获取该对象,希望他们会有未损坏的版本。

如果找不到有效的版本,你实际上可以通过猜测应该存在哪些文件来重建它。您可能需要查看对象的日期和时间是否匹配。这些可能是相关联的 blob 对象。你可以从这些对象推断出树对象的结构。

请参阅Scott Chacon的Git Screencasts,了解 Git 内部工作原理以及在真正卡住并且无法从别人那里获取该对象时如何进行这项侦探工作。


2
它可以存储在包文件中。这是git通过存储增量来压缩对象存储的方式。松散对象是尚未打包的对象。在git中,可以搜索包文件、索引文件,您应该能够深入了解所需内容。 - Adam Dymitruk
2
你能在回答中提供一个链接,指向 Chacon 的 Git 屏幕录像吗? - Ehtesh Choudhury
1
git cat-file -t <SHA1> 命令可以告诉你对象的类型。如果没有损坏,你可以使用 git cat-file <type> <SHA1> 命令查看内容(我用它来查看 blob 的内容,我猜它也可以显示其他类型的内容)。 - Carl G
1
此外,Linus的这篇文章描述了恢复“blob”的过程。然而,当我按照这些说明操作时,“git status”响应“fatal: unable to read <SHA1>”,尽管我已经成功运行了“git hash-object -w <file>”(可能是因为,根据他的说明,我已经将该对象文件移开了。将其返回只给了我相同的“corrupt loose object”错误)。 - Carl G
3
现在请用英语重复。 - Mehdi
显示剩余5条评论

55

我在写提交信息时,电脑崩溃了。重启后,工作树和我离开时一样,并且我成功地提交了更改。

但是,当我尝试运行git status时,我得到了以下结果:

error: object file .git/objects/xx/12345 is empty
fatal: loose object xx12345 (stored in .git/objects/xx/12345 is corrupt

与大部分其他答案不同,我并非试图恢复任何数据,我只是需要让Git不再抱怨空对象文件。

概述

“对象文件”是Git对你关心的真实文件的散列表示。Git认为应该在.git/object/xx/12345中存储some/file.whatever的散列版本,并且修复错误主要是找出这个“松散对象”应该代表哪个文件。

详细信息

可能的选择似乎是:

  1. 删除空文件
  2. 将文件转换为Git可接受的状态

方法1:删除对象文件

我尝试的第一件事就是移动对象文件。

mv .git/objects/xx/12345 ..

这个方法不起作用 - Git 报告一个链接损坏。我们尝试 Approach 2。

Approach 2: 修复文件

Linus Torvalds 写了一篇很棒的文章,介绍如何恢复一个对象文件,这解决了我的问题。关键步骤在此总结。

$> # Find out which file the blob object refers to
$> git fsck
broken link from    tree 2d9263c6d23595e7cb2a21e5ebbb53655278dff8
           to    blob xx12345
missing blob xx12345

$> git ls-tree 2d926
...
10064 blob xx12345    your_file.whatever

这告诉你空对象应该是一个哈希的哪个文件。现在你可以修复它。

$> git hash-object -w path/to/your_file.whatever

这样做后,我检查了 .git/objects/xx/12345,它不再为空,并且 Git 不再抱怨。


我曾经遇到一种情况,我的存储库没有任何远程备份或备份,并且损坏的对象被添加在初始提交附近,可能会破坏整个树。我有自己的方法尝试在不同的存储库中重新创建对象,但这个答案以更精细的方式实现了相同的结果。 - Estecka
1
对我来说不起作用。我得到了error: object file .git/objects/af/c1e62b3ff4f76d034551fa5c6131635a83434f is empty的错误,但这些文件确实丢失了,而且git fsck也没有列出任何损坏的链接。 - reinierpost
手动删除损坏的文件,然后执行 git pull 命令。这将解决问题。 - Iftikhar Ali Ansari
手动删除损坏的文件然后执行git pull无效。相反,它会抛出一个错误消息"无法读取<文件名>。 - spadelives
谢谢。我刚刚删除了空文件,现在它可以工作了。 - Amir Pourmand

19

一个垃圾回收解决了我的问题:

git gc --aggressive --prune=now

修复过程需要一定的时间,但每个松散的对象和/或损坏的索引都被修复了。


2
这是一个好的解决方案。对我很有效。我的系统意外关机了。然而,这个命令让我免于克隆和所有那些繁重的任务。谢谢Jago。 - Mukesh Kumar
12
"无法运行 reflog" - Vladimir Brasil
2
另一个问题中得知:仅使用git gc --prune=now是不够的,因为这些提交仍然在reflog中被引用。因此,清除reflog是必要的。 - Peter Mortensen

17

尝试

git stash

这对我有效。它将您尚未提交的所有更改暂存,并解决了问题。


1
今天早上遇到了一个奇怪的错误。昨天已经提交了,所以没有未提交的更改。我做了以下操作:git stash ... fatal: Unable to create '/home/<user>/.git/index.lock': Input/output error touch .git/a touch: cannot touch ‘.git/a’: Input/output error sudo touch /home/guest/.git/a NO ERROR git stash No local changes to save git status ... nothing to commit, working directory clean - go2null
2
@go2null 我有点晚了,但是输入/输出错误通常意味着硬盘问题。虽然我相信你现在已经解决了这个问题。 - arleslie
无法保存当前索引状态。 - Vladimir Brasil

9

对我来说,仅运行git prune就解决了这个问题。


这对我有用,而且似乎是最简单的解决方案。不确定为什么这个答案没有得到更多的票数。唯一的缺点是下一个git pull比平常要慢一些,我猜可能是因为它正在替换某些已删除的对象或其他内容。 - steev
6
可能的原因是 git prune 完全没有解决这个问题。 - user3072843

9

我的Linux Mint系统崩溃后,我按下电源按钮关闭了笔记本电脑,这就是为什么我的.git文件损坏的原因。

find .git/objects/ -empty -delete

之后,我遇到了错误:fatal: Bad object head。我刚刚重新初始化了我的git。

git init

从远程仓库获取

git fetch

检查您的git,请使用以下命令:

git status

现在它又可以工作了。我没有丢失我本地的更改,因此我可以提交而不需要重写代码。


谢谢,我本来以为会很困难才能找回我的工作,但实际上很简单。 - peterretief

7
我遇到过这种情况,当我的系统崩溃时。我做的是:
请注意,您的损坏提交已经丢失,但更改仍保留在那里。您可能需要在此过程结束时重新创建这些提交。
- 备份您的代码。 - 转到您的工作目录并删除 .git 文件夹。 - 现在在另一个位置克隆远程并复制其中的 .git 文件夹。 - 将其粘贴到您的工作目录中。 - 进行所需的提交。

1
这救了我的命。非常感谢你,朋友。但要注意,使用这些步骤后,您将获得新的更改。因此,请留意它们,然后进行提交和推送。 - Saurabh Ghewari

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