git fsck --full 只检查目录

  • 本文关键字:fsck --full git git
  • 更新时间 :
  • 英文 :


我正在从我的树莓派提供裸露的git存储库。我的目标是每晚运行git fsck --full,以便及早发现文件系统问题。我希望 fsck 同时检查"对象目录"和"对象",并查看输出,例如

pi@raspi2:/media/usb/git/dw.git $ git fsck --full
Checking object directories: 100% (256/256), done.
Checking objects: 100% (14538/14538), done.

对于我的一个存储库,未检查任何对象:

pi@raspi2:/media/usb/git/ts-ch.git.borken $ git --version
git version 2.11.0
pi@raspi2:/media/usb/git/ts-ch.git.borken $ git fsck --full
Checking object directories: 100% (256/256), done.
pi@raspi2:/media/usb/git/ts-ch.git.borken $ 

我修改了/objects 下的一个文件(一个 322kB 的.pdf文件)并再次运行 fsck。它显示的消息与以前相同,并且没有错误。

cd objects/86/
chmod u+w f3e6e674431ab3006cbb56fddecbdb4a7724b4 
echo "foosel" >> f3e6e674431ab3006cbb56fddecbdb4a7724b4 
chmod u-w f3e6e674431ab3006cbb56fddecbdb4a7724b4 

所有存储库都是相同的,它们是裸的,并且没有特殊的配置:

pi@raspi2:/media/usb/git/ts-ch.git $ git config --list
core.repositoryformatversion=0
core.filemode=true
core.bare=true

我错过了什么吗?为什么没有检测到此修改的对象?它的SHA1肯定不应该再匹配了。感谢您的任何提示!

关于腐败问题

是的,你错过了一些东西。 也就是说,您也没有以 Git 关注的方式损坏文件。 存储在磁盘上的对象通常以对象类型开头,然后是空格,然后是大小(使用 ASCII 数字),然后是 NUL。 大小说明了对象的大小,这就是 Git 最终读取的全部内容。 因此,像这样将数据固定到最后实际上不会损坏对象。 如果您将文件的内容替换为其他内容,那么您会看到问题。

作为参考,对象格式详细信息在 Git 用户手册中:

对象存储格式

所有对象都有一个静态确定的"类型",用于标识 对象(即如何使用它,以及它如何引用其他对象)。那里 目前有四种不同的对象类型:"blob"、"树"、"提交"和"标记"。

无论对象类型如何,所有对象都具有以下特征:它们 都用 zlib 放气,并且有一个标题,不仅指定了他们的 类型,但还提供有关对象中数据的大小信息。它 值得注意的是,用于命名对象的 SHA-1 哈希是 原始数据加上此标头,因此sha1sum文件与对象不匹配 文件的名称。

因此,始终可以测试对象的一般一致性 与对象的内容或类型无关:所有对象都可以 通过验证 (a) 其哈希与文件内容匹配以及 (b) 对象成功膨胀为形成序列的字节流 的<ascii type without space> + <space> + <ascii decimal size> + <byte> + <binary object data>.

结构化对象可以进一步具有其结构和连接性 已验证的其他对象。这通常是通过git fsck程序完成的,该程序 生成所有对象的完整依赖关系图,并验证其内部 一致性(除了通过验证其表面一致性 哈希)。

但是,有一个有趣的交互使我认为git fsck应该更加努力地工作并注意文件何时在最后有垃圾。 如果尝试在该存储库上运行git gc,最终会看到如下错误:

:: git gc
Counting objects: 9, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (3/3), done.
error: garbage at end of loose object '45b983be36b73c0788dc9cbcb76cbb80fc7bb057'
fatal: loose object 45b983be36b73c0788dc9cbcb76cbb80fc7bb057 (stored in .git/objects/45/b983be36b73c0788dc9cbcb76cbb80fc7bb057) is corrupt
error: failed to run repack

似乎如果git gc实际上无法运行,那么git fsck应该抓住问题。

关于为什么看不到"检查对象">

这个问题实际上非常简单:没有要检查的打包对象。 那些住在.git/objects/pack. 如果您没有任何这些文件,则不会看到"检查对象"位。

我仍然不明白为什么 git 拒绝报告它正在检查此存储库中的对象,

我将不将其带到git列表中,因为我认为git fsck应该足够彻底地检查事情,以便所有操作都应该起作用

这可能与 Git 2.12(2017 年第 1 季度)附带的这两组补丁有关:在树莓派上重新编译 git 2.12 现在可能会产生更好的结果。

请参阅下文:建议使用 Git 2.20(2018 年第 4 季度)。

"git fsck"现在更仔细地检查松动的物体。

请参阅Jeff King(peff
提交cce044d,提交c68b489,提交f6371f9,提交118e6ce,提交771e7d5,提交0b20f1a(2017年1月13日)。(由Junio C Hamano --gitster-- in commit 42ace93, 31 Jan 2017

)和:

"git fsck --connectivity-check"根本不起作用。

请参阅提交 a2b2285、提交 97ca7ca(2017 年 1 月 26 日)、提交 c20d4d7(2017 年 1 月 24 日)、提交 c2d17b3、提交 c3271a0、提交 c6c7b16、提交 b4584e4、提交 1ada11e(2017 年 1 月 16 日)和提交 3e3f8bd(2017 年 1 月 17 日)(peff)。
(由Junio C Hamano --gitster-- 在提交 4ba6197 中合并,2017 年 1 月 31 日)


2018 年 11 月更新:上面推荐的 Git 2.12 实际上引入了回归,这使得"git fsck"在处理截断的松散对象时陷入无限循环。

请参阅Jeff King(peff)的提交98f425b,提交ccdc481,提交5632baf(2018年10月30日)。
(由Junio C Hamano -gitster- 合并于提交879a8d4,2018年11月13日)

check_stream_sha1():处理输入下溢

此提交修复了 fscing 大时的无限循环 截断的松散对象。

check_stream_sha1()函数采用mmap松散的对象缓冲区,一次流式传输 4k 的输出,检查其 sha1。
当我们输出足够的字节(我们从对象标头知道大小)或zlib告诉我们除Z_OKZ_BUF_ERROR之外的任何内容时,循环就会退出。

后者是意料之中的,因为zlib我们的 4k 缓冲区中可能会耗尽空间,这就是它告诉我们处理输出并再次循环的方式。

Z_BUF_ERROR还涉及另一种情况:zlib无法取得进展,因为它需要更多的投入

这不应该发生在这个循环中,因为尽管我们正在流式传输输出,但我们在mmap'd 缓冲区中提供了整个放气的输入。但是由于我们不检查这种情况,如果我们确实看到一个 截断的对象,认为zlib要求更多的输出空间。


Git 2.22(2019 年第 2 季度)改进了"git fsck --connectivity-only",它确实省略了将任何引用中无法访问的对象筛选为无法访问和悬空所需的计算。
现在,当请求悬空对象时,这将启用(默认情况下会这样做,但可以使用"--no-dangling"选项覆盖)。

请参阅提交 8d8c2a5,提交 df805ed (05 Mar 2019) by Jeff King (peff)。
(由Junio C Hamano --gitster-- 合并于 提交 ea32776,2019 年 3 月 20 日)

fsck:始终为无法访问的对象计算 USED 标志

--connectivity-only选项避免打开每个对象,而是 只需用标志标记可访问的对象,并将其与集合进行比较 所有对象。3e3f8bd 中更详细地讨论了此策略 (fsck: 为--connectivity-check准备虚拟对象 , 2017-01-17).

这意味着我们将每个无法触及的对象报告为悬空。
而在完整的 fsck 中,我们实际上会打开并解析每个无法访问的对象,用 USED 标志标记它们的子对象,以表示"这是另一个对象提到的"。
因此,我们只能将对象图的不可到达段的尖端报告为悬空。

您可以通过一个微不足道的例子看到这种差异:

tree=$(git hash-object -t tree -w /dev/null)
one=$(echo one | git commit-tree $tree)
two=$(echo two | git commit-tree -p $one $tree)

运行git fsck将仅将$two报告为悬空,但对于--connectivity-only,两个提交(和树)都会被报告。同样,使用--lost-found将写入所有三个对象。

我们可以--connectivity-only通过采取 单独传递无法访问的对象,解析它们并标记 它们称为"已使用"的对象。这仍然避免解析任何斑点, 尽管我们确实支付了访问任何无法访问的提交和树的费用 (可能会或可能不会明显,具体取决于您有多少)。

最新更新