我从我的覆盆子pi中提供裸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肯定不再匹配了。谢谢你的任何提示!
答案 0 :(得分:4)
是的,你错过了一些东西。也就是说,你没有以Git关注的方式破坏文件。存储在磁盘上的对象通常以对象类型开头,后跟空格,后跟大小(使用ASCII编号),后跟一个NUL。大小表明对象的大小,以及Git最终阅读的全部内容。因此,将数据添加到最终,就像实际上不会破坏对象一样。如果您用其他内容替换了文件的内容,那么您就会看到问题。
作为参考,对象格式详细信息位于Git User's Manual:
对象存储格式
所有对象都有静态确定的"类型"它标识的格式 对象(即如何使用它,以及它如何引用其他对象)。那里 目前有四种不同的对象类型:" blob"," tree"," commit"和" tag"。
无论对象类型如何,所有对象都具有以下特征:它们 都用zlib放气,并且有一个不仅指定它们的标题 type,但也提供有关对象中数据的大小信息。它的 值得注意的是,用于命名对象的SHA-1哈希是哈希值 原始数据加上此标头,因此
sha1sum
文件与对象不匹配 文件名。因此,始终可以测试对象的一般一致性 独立于对象的内容或类型:所有对象都可以 通过验证(a)它们的哈希值与文件的内容相匹配来验证 (b)对象成功膨胀为形成序列的字节流
<ascii type without space> + <space> + <ascii decimal size> + <byte\0> + <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
。如果您没有任何这些文件,那么您将无法看到&#34;正在检查对象&#34;位。
答案 1 :(得分:0)
我仍然不明白为什么git拒绝报告它正在检查此仓库中的对象,
我不打算把它拿出来,因为我认为git fsck应该彻底检查所有操作应该有效
这可能与Git 2.12(2017年第一季度)附带的那两套补丁有关:在你的覆盆子pi上重新编译git 2.12可能会产生更好的结果。
见下文:建议使用Git 2.20(Q8 2018)。
&#34;
git fsck
&#34;现在更仔细地检查松散的物体。
commit cce044d点击commit c68b489,commit f6371f9,commit 118e6ce,commit 771e7d5,commit 0b20f1a,Jeff King (peff
)(2017年1月13日) 。
(Junio C Hamano -- gitster
--于2017年1月31日commit 42ace93合并)
并且:
&#34;
git fsck --connectivity-check
&#34;根本没用。
请参阅commit a2b2285,commit 97ca7ca(2017年1月26日),commit c20d4d7(2017年1月24日),commit c2d17b3,commit c3271a0,commit c6c7b16, commit b4584e4,commit 1ada11e(2017年1月16日)和commit 3e3f8bd(2017年1月17日)Jeff King (peff
)。
(Junio C Hamano -- gitster
--于2017年1月31日commit 4ba6197合并)
2018年11月更新:上面推荐的Git 2.12实际上引入了回归,这使得&#34; git fsck
&#34;在处理截断的松散对象时陷入无限循环。
commit 98f425b见commit ccdc481,commit 5632baf,Jeff King (peff
)(2018年10月30日)。
(由Junio C Hamano -- gitster
--合并于commit 879a8d4,2018年11月13日)
check_stream_sha1()
:处理输入下溢此提交在fscking较大时修复了无限循环 截断的松散物体。
check_stream_sha1()
函数使用mmap
一个松散的对象缓冲区,一次输出4k输出,检查其sha1。
当我们输出足够的字节(我们知道对象标题的大小),或zlib
告诉我们除Z_OK
或Z_BUF_ERROR
之外的任何内容时,循环退出。后者是预期的,因为
zlib
可能会在我们的4k缓冲区中耗尽空间,这就是它告诉我们处理输出并再次循环的方式。但
Z_BUF_ERROR
也涵盖了另一种情况:zlib
无法前进,因为它需要更多输入。这应该永远不会发生在这个循环中,因为虽然我们要对输出进行流式传输,但我们在
mmap
缓冲区中提供了整个缩小的输入。但是既然我们不检查这种情况,如果我们确实看到了,我们就会无限循环 截断的对象,认为zlib
要求更多的输出空间。
Git 2.22(2019年第二季度)改进了#34; git fsck --connectivity-only
&#34;,它确实省略了将任何无法从任何refs到达的对象筛选到无法到达和悬空所需的计算。
现在,在请求悬空对象时启用此功能(默认情况下已完成,但可以使用&#34; --no-dangling
&#34;选项覆盖。)
commit 8d8c2a5见commit df805ed,Jeff King (peff
)(2019年3月5日)
(由Junio C Hamano -- gitster
--合并于commit ea32776,2019年3月20日)
fsck
:始终为无法到达的对象计算USED标志
--connectivity-only
选项可以避免打开每个对象,而是打开 只标记带有标志的可到达对象,并将其与集合进行比较 所有对象。在3e3f8bd中更详细地讨论了该策略 (fsck
:为--connectivity-check
,2017-01-17)准备虚拟对象。这意味着我们将每个无法访问的对象报告为悬空 在一个完整的fsck中,我们实际上已经打开并解析了每个无法访问的对象,用USED标志标记其子对象,意味着&#34;这是另一个对象提到的。#34; > 因此,我们只能将对象图中无法到达的段的尖端报告为悬空。
你可以通过一个简单的例子来看到这种差异:
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
只会报告$ 2悬空,但使用--connectivity-only
时,会报告两次提交(和树)。同样,使用--lost-found
会写出所有三个对象。我们可以让
--connectivity-only
像普通情况一样工作 单独传递无法访问的对象,解析它们并标记 他们称之为USED的对象。这仍然可以避免解析任何blob, 虽然我们支付访问任何无法访问的提交和树的成本 (可能会或可能不会明显,取决于你有多少)。