Git:“腐败的松散物体”


329

每当我从遥控器上拉出时,都会出现以下有关压缩的错误。当我运行手动压缩时,会得到相同的结果:

$ git gc
error: Could not read 3813783126d41a3200b35b6681357c213352ab31
fatal: bad tree object 3813783126d41a3200b35b6681357c213352ab31
error: failed to run repack

有谁知道该怎么办?

从猫文件我得到这个:

$ 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

有人可以帮我破译吗?


您是否尝试过查看后一个对象(45ba4ceb93bc812ef20a6630bb27e9e0b33a012a)?
Gintautas Miliauskas,2010年

4
谢谢...但是如何“看”一个物体?对git来说仍然很新:)
asgerhallas 2010年

2
不幸的是,“ git show”仅给我带来了“ git fsck”。
asgerhallas 2010年

4
Linus Torvalds撰写了以下有关此错误的有用文档,以及有关如何在文件存在的情况下如何手动重建Blob的信息:如何恢复损坏的Blob对象的一些技巧来重建Blob对象以修复损坏的存储库
UweKleine-König

2
您可以添加一些评论或编辑已接受的答案吗?我处于完全相同的情况,被接受的答案似乎没有包含足够的细节来“ Just Work TM”,而是迫使我自己去研究细节。
ripper234 '02

Answers:


57

看起来您有一个损坏的树对象。您将需要从其他人那里获得该对象。希望他们会有一个未损坏的版本。

如果您通过猜测应该存在哪些文件而无法从其他人那里找到有效的版本,则实际上可以对其进行重构。您可能想查看对象的日期和时间是否与其匹配。这些可能是相关的问题。您可以从那些对象推断出树对象的结构。

看看Scott Chacon关于git内部的Git屏幕录像。这将向您展示git的工作原理,以及如果您真的被卡住并且无法从其他人那里获得该对象,该如何进行这项侦探工作。


2
它可能存储在一个打包文件中。这是git通过存储增量压缩对象存储的方式。松散的对象是尚未打包的对象。Google提供打包文件,git索引文件,您应该可以根据需要深入研究。
亚当·迪米特鲁克

2
您能否在答案中提供指向Chacon的Git屏幕录像的链接?
Ehtesh Choudhury

1
git cat-file -t <SHA1>会告诉你类型。如果未损坏,则git cat-file <type> <SHA1>可以查看内容(我用过a blob,我想它也会向您显示其他类型的内容。)
Carl G

1
Linus的这篇文章也描述了恢复的过程blob。但是,当我遵循这些指令时,即使我已经成功运行了,它也git status做出了响应(可能是因为,按照他的指令,我已经将该目标文件移开了。返回它也给了我同样的错误。)fatal: unable to read <SHA1>git hash-object -w <file>corrupt loose object
Carl G

2
现在请用英语重复
Mehdi

359

我有同样的问题(不知道为什么)。

此修复程序需要访问存储库的未损坏的远程副本,并将使本地工作副本保持不变。

但这有一些缺点:

  • 您将丢失所有未推送的提交的记录,并且将不得不重新提交它们。
  • 您将失去任何藏匿处。

解决方法

从仓库上方的父目录中执行以下命令(将“ 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,,因为他们应该再等方面的工作。


11
这种方法对我有用。但是,我相信所有未推动的提交都丢失了。回购数据保持不变。
馄饨

30
是的,未推送的提交信息将丢失。但是在常见情况下(没有多个本地分支,它们中的当前未进行其他更改),所有最新的文件修改(即删除)仍在磁盘上,因此,您可以轻松地重复任何先前未进行的提交。由于我总是在任何提交顺序之后进行推送,因此我什至没有遇到这个麻烦。
立方生菜

7
简单明了。如果您不了解有关git的所有知识并且不想摆弄存储库,这是IMO,最有效的解决方案。
Oliboy50 2014年

4
我认为它将删除所有隐藏项,因为它们存储在.git子目录下。
安东尼·埃利奥特

4
如果项目中有子模块,则必须在检索.git文件夹之前将其初始化。
AdrieanKhisbe 2014年

241

最好的选择可能是简单地从远程仓库(例如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  

然后根据需要提交所有更改的文件。


12
恕我直言,这应该是公认的答案。比删除仓库和重新克隆要容易得多!:)尽管您确实丢失了任何分阶段提交的内容……
尼克

6
显然,如果损坏发生时您在master以外的其他分支中,请替换master为您的分支名称。
蒂莫西·佐恩

大多数情况下是按原样工作的,但是working当它损坏时我在另一个分支上,这些步骤没有给我除master以外的任何分支的本地副本(是的,我曾尝试用上面的master替换它,working但那不起作用)。最后使用完成上述步骤master,然后checkout -b working origin/working存储我的更改并在其中弹出存储。似乎奏效了-谢谢!
惊人的

1
我的存储库中有一个未损坏的子模块。此过程使存储库及其子模块处于诸如git statusyield的命令状态fatal: Not a git repository: submodules/my-sub/../../.git/modules/my-sub。从文件系统中删除子模块并重新启动该过程可恢复正常状态。最好先确保子模块中没有未推送的变更集是一个好主意……
Steven Baldasty

5
我这今天的表现并没有失去对文件提交的修改:)(GIT 2.17.1)
法比奥·迪亚斯

173

在我的笔记本上运行VM时,电池耗尽,出现此错误;

错误:目标文件.git / objects / ce / theRef为空错误:目标文件.git / objects / ce / theRef为空致命:松散的对象theRef(存储在.git / objects / ce / theRef中)已损坏

我设法只用2条命令就使仓库再次工作,而又没有丢失我的工作(修改的文件/未提交的更改)

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

之后,我运行了一个git status,该回购就很好了,并且有了我的更改(等待提交,现在就执行。)。

git版本1.9.1

请记住备份所有您记得的更改,以防万一此解决方案无法正常工作,并且需要一种更彻底的方法。


10
find .git/objects/ -size 0 -exec rm -f {} \;为我工作;)
Lazaro Fernandes Lima Suleiman

遇到相同的问题,运行命令,在Mint VM上对我来说效果很好。
路德维格·赖达尔2015年

也可以完美地工作而无需执行任何其他操作。
Halsafar

1
不在VM上,这对我有用了很多次。IDK为什么这在我当前的项目中经常发生,但这每次都可以解决。
James L.

7
git symbolic-ref HEAD refs/heads/master.删除空对象后,可能需要运行。
斯蒂芬

43

写提交消息时,我的计算机崩溃了。重新启动后,工作树就如我离开时一样,并且能够成功提交更改。

然而,当我试图运行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认为应该在中some/file.whatever存储哈希值版本.git/object/xx/12345,而修复该错误主要是要弄清楚“松散对象”应该代表哪个文件。

细节

可能的选择似乎是

  1. 删除空文件
  2. 使文件进入Git可接受的状态

方法1:删除目标文件

我尝试的第一件事就是移动目标文件

mv .git/objects/xx/12345 ..

那没有用-git开始抱怨链接断开。进入方法2。

方法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

13

尝试

git stash

这对我有用。它隐藏了您所有尚未解决的问题。


奇怪的!?! 今天早上遇到了这个错误。昨天已提交,因此未提交的邮件没有更改。做了以下内容: git stash ...致命的:无法创建'/home/<user>/.git/index.lock':输入/输出错误 touch .git/a 触摸:不能碰'的.git / A':输入/输出错误 sudo touch /home/guest/.git/a NO ERROR git stash 否本地更改以保存 git status ...
无须

1
@ go2null我有点迟了,但是输入/输出错误通常意味着硬盘问题。尽管我确定您现在已经知道了。
arleslie

“无法保存当前索引状态”
弗拉基米尔·布拉西尔

9

一个垃圾收集固定我的问题:

git gc --aggressive --prune=now

需要一段时间才能完成,但是每个松散的对象和/或损坏的索引均已修复。


这是很好的解决方案。为我工作。我的系统意外关闭。但是,这一命令使我免于克隆和所有繁重的工作。感谢Jago。
Mukesh Kumar

“无法运行reflog”
弗拉基米尔·巴西

5

只需git prune为我解决此问题


这对我有用,似乎是最简单的解决方案。不知道为什么这个答案没有得到更多的选票。git pull我猜唯一的缺点是下一个要比平常花费更长的时间,因为它正在替换一些已删除的对象或其他东西。
Steev

1
原因可能是git prune根本无法解决问题。
user3072843

4

我只是遇到了这种情况-我的机器在写入Git存储库时崩溃了,并且损坏了。我将其修复如下。

我首先查看我没有推送到远程仓库的提交数量,因此:

gitk &

如果您不使用此工具,它将非常方便-据我所知,它在所有操作系统上都可用。这表明我的遥控器缺少两次提交。因此,我点击了表示最新的远程提交的标签(通常是/remotes/origin/master)以获取哈希(哈希为40个字符长,但是为了简洁起见,我在这里使用了10个字符-通常无论如何都可以使用)。

这里是:

14c0fcc9b3

然后,我单击以下提交(即遥控器没有的第一个提交),并在那里获取哈希值:

04d44c3298

然后,我将两者都用于为此提交制作补丁:

git diff 14c0fcc9b3 04d44c3298 > 1.patch

然后,我同样对其他丢失的提交进行了处理,即,我使用了之前提交的哈希和提交本身的哈希:

git diff 04d44c3298 fc1d4b0df7 > 2.patch

然后,我移到一个新目录,从远程克隆了仓库:

git clone git@github.com:username/repo.git

然后,我将补丁文件移到新文件夹中,然后应用它们并使用其确切的提交消息(可以从git log或从gitk窗口粘贴)来提交它们:

patch -p1 < 1.patch
git commit

patch -p1 < 2.patch
git commit

这为我恢复了一切(请注意,对于大量的提交,可能有一种更快的方法)。但是,我很想看看损坏的回购协议中的树是否可以修复,答案是可以修复。使用上面提供的已修复的存储库,在损坏的文件夹中运行以下命令:

git fsck 

您将获得如下内容:

error: object file .git/objects/ca/539ed815fefdbbbfae6e8d0c0b3dbbe093390d is empty
error: unable to find ca539ed815fefdbbbfae6e8d0c0b3dbbe093390d
error: sha1 mismatch ca539ed815fefdbbbfae6e8d0c0b3dbbe093390d

要进行修复,我将在损坏的文件夹中进行此操作:

rm .git/objects/ca/539ed815fefdbbbfae6e8d0c0b3dbbe093390d
cp ../good-repo/.git/objects/ca/539ed815fefdbbbfae6e8d0c0b3dbbe093390d .git/objects/ca/539ed815fefdbbbfae6e8d0c0b3dbbe093390d

即删除损坏的文件,并用一个好的文件替换它。您可能必须执行几次。最终,您将可以毫无错误地运行fsck。您可能在报告中有“悬挂提交”和“悬挂blob”行,这是您在此文件夹中进行了重新设置和修改的结果,并且可以。垃圾收集器将在适当的时候将其删除。

因此(至少就我而言),损坏的树并不意味着会丢失未推送的提交。


3

我也收到了损坏的松散对象错误。

./objects/x/x

我通过进入损坏对象的目录成功修复了该问题。我看到分配给该对象的用户不是我的git用户。我不知道它是怎么发生的,但是我chown git:git在该文件上运行了一个文件,然后又重新工作了。

这可能是某些人的问题的潜在解决方法,但并非全部都是必要的。


2

我的(windows)机器决定自行重启后,出现此错误。幸运的是,我的远程仓库是最新的,所以我刚刚做了一个新的git-clone。



2

我在这里遵循了许多其他步骤。Linus关于如何查看git树/对象并查找缺少的内容的描述特别有用。git-git恢复损坏的blob

但是最后,对我而言,我的磁盘对象松散/损坏是由部分磁盘故障引起的,并且该文档不太容易恢复/覆盖这些对象。

最后,我移开了冲突objects/<ha>/<hash>,并使用git unpack-objects了合理更新的克隆中的打包文件。它能够还原丢失的树对象。

仍然给我留下了许多悬空的斑点,这可能是解压缩以前存档的内容的副作用,并在此处的其他问题中得到解决。


2

回答@ user1055643缺少最后一步:

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

--set-upstream-是有效的参数吗?我不这么认为!
Sharif Mamun 2014年

2
git的分支(--set-上游到= <上游> | -u <上游>)[<BRANCHNAME>]
的ErtugrulAltınboğa

如果.git从克隆的项目中删除并复制,则回购将起作用,但不会保留任何本地分支,也不会保留任何存储。
弗拉基米尔·武卡纳克(Fladimir Vukanac)

1

我们在这里有这种情况。碰巧问题是损坏的文件的所有权是root而不是我们的普通用户。这是由某人执行“ sudo su-”后在服务器上进行的提交引起的。

首先,使用以下命令识别损坏的文件:

$> git fsck --full

您应该收到这样的答案:

fatal: loose object 11b25a9d10b4144711bf616590e171a76a35c1f9 (stored in .git/objects/11/b25a9d10b4144711bf616590e171a76a35c1f9) is corrupt

进入损坏文件所在的文件夹,然后执行以下操作:

$> ls -la

检查损坏文件的所有权。如果不同,请返回到您的仓库的根目录并执行以下操作:

$> sudo chown -R YOURCORRECTUSER:www-data .git/

希望能帮助到你!


1

对我而言,这是由于做一次电源时停电而发生的git push

消息看起来像这样:

$ git status
error: object file .git/objects/c2/38824eb3fb602edc2c49fccb535f9e53951c74 is empty
error: object file .git/objects/c2/38824eb3fb602edc2c49fccb535f9e53951c74 is empty
fatal: loose object c238824eb3fb602edc2c49fccb535f9e53951c74 (stored in .git/objects/c2/38824eb3fb602edc2c49fccb535f9e53951c74) is corrupt

我尝试过类似的操作,git fsck但无济于事。由于崩溃发生在期间git push,因此很明显是在客户端重写期间发生的,这是在服务器更新之后发生的。我环顾四周,发现c2388我的情况是一个提交对象,因为该对象由中的条目引用.git/refs。因此,我知道我可以通过c2388历史记录(通过Web界面或第二个克隆)找到历史记录。

在第二个克隆中,我做了一个操作git log -n 2 c2388以识别的前身c2388。然后我手动修改.git/refs/heads/master.git/refs/remotes/origin/master是的前身c2388代替c2388。然后我可以做一个git fetch。由于git fetch空对象上的冲突而失败了几次。我删除了每个空对象,直到git fetch成功。这就治愈了存储库。


1

我以这种方式解决了:我决定简单地将未损坏的目标文件从备份的克隆复制到我的原始存储库中。效果也一样。(顺便说一句:如果您无法通过名称在.git / objects /中找到该对象,则可能是为了节省空间而对其进行了打包)。


0

我在裸露的远程git仓库中遇到了同样的问题。经过大量的故障排除后,我发现我的一位同事进行了一次提交,其中.git / objects中的某些文件具有440(r--r -----)而不是444(r--r--r)的权限。 -)。在要求同事更改裸git存储库中的“ chmod 444 -R对象”权限后,问题已解决。


0

我只是有这样的问题。我的特殊问题是由系统崩溃导致的,该崩溃破坏了最近的提交(因此也破坏了master分支)。我没有推送,而是想重新提交该提交。在我的特定情况下,我能够这样处理:

  1. 备份以下内容.git/rsync -a .git/ git-bak/
  2. 选中.git/logs/HEAD,找到具有有效提交ID的最后一行。对我来说,这是第二次提交。很好,因为我仍然拥有该文件的工作目录版本,因此还有我想要的每个版本。
  3. 在该提交处创建一个分支: git branch temp <commit-id>
  4. 使用工作目录中的文件重新执行损坏的提交。
  5. git reset master temp 将master分支移至您在步骤2中所做的新提交。
  6. git checkout master并使用确认它看起来正确git log
  7. git branch -d temp
  8. git fsck --full,现在应该可以安全删除fsck发现的任何损坏的对象。
  9. 如果一切看起来不错,请尝试推动。如果可以的话

那对我有用。我怀疑这是一个合理的常见情况,因为最近的提交很有可能被破坏,但是如果您又丢失了一次提交,则仍可以使用这样的方法,并谨慎使用git cherrypick和reflog在中.git/logs/HEAD


0

遇到此问题时,我备份了最近的更改(因为我知道自己已更改),然后删除了.git / location中抱怨的文件。然后我做了一个git pull。不过请注意,这可能对您不起作用。


0

我的系统崩溃后,我遇到了这个问题。我所做的是:

(请注意,损坏的提交会丢失,但更改会保留。您可能必须在此过程结束时重新创建那些提交)

  • 备份您的代码。
  • 转到工作目录并删除.git文件夹。
  • 现在,将遥控器克隆到另一个位置,然后.git在其中复制文件夹。
  • 将其粘贴到您的工作目录中。
  • 根据需要提交。

-7

只需删除.git文件夹并再次添加即可。这个简单的解决方案为我工作。


3
这会破坏您的本地存储库...,可能会有不想要的副作用:)请编辑您的建议并添加该警告。
Felix'1

1
如果删除.git并从克隆的项目中进行复制,则回购将起作用,但是不会保留任何本地分支或存储物。另外,出于友好的建议,请完全删除您的答案,以停止接受不赞成票。
弗拉基米尔·武卡纳克(Fladimir Vukanac)

1
哇,纳利...谈论使用火箭筒做镊子的工作。
TuncayGöncüoğlu的
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.