git fsck --full仅检查目录

7

我正在使用树莓派提供裸的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肯定不再匹配。感谢任何提示!

2个回答

4

关于损坏问题

是的,您确实错过了一些东西。也就是说,您没有以Git关注的方式对文件进行破坏。通常存储在磁盘上的对象以对象类型开头,后跟空格,然后是大小(使用ASCII数字),后跟NUL。大小表示对象的大小,这就是Git最终读取的所有内容。因此,在末尾添加数据不会实际损坏对象。如果您用其他内容替换文件的内容,那么您将看到问题。

有关对象格式的详细信息可在Git用户手册中查看:

对象存储格式

所有对象都具有静态确定的“类型”,它标识了对象的格式(即它的使用方法以及它如何引用其他对象)。目前有四种不同的对象类型:“blob”,“tree”,“commit”和“tag”。

无论对象类型如何,所有对象都共享以下特性:它们都使用zlib压缩,并且具有标题,该标题不仅指定它们的类型,而且还提供有关对象中数据的大小信息。值得注意的是,用于命名对象的SHA-1哈希是原始数据加上此标题的哈希值,因此sha1sum file与文件的对象名称不匹配。

因此,无论对象的内容或类型如何,都可以始终测试对象的一般一致性:通过验证它们的哈希值是否与文件内容匹配以及对象是否成功解压缩为形成序列的字节流进行验证:<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中。如果您没有这些文件,则不会看到“检查对象”部分。

非常好的提示,谢谢!确实,如果我在文件中间交换一个字节,fsck --full会检测到一个error: sha1 mismatch 86f3e6e674431ab3006cbb56fddecbdb4a7724b4。所以我仍然不明白为什么git拒绝报告它正在检查此存储库中的对象,但从功能上讲,这似乎并不重要。 - dnswlt
我刚刚发布了一个更新,其中包含答案,但它确实很重要。:-( git gc 无法完成其任务。:-( 我将在 git 列表中提出此问题,因为我认为 git fsck 应该彻底检查所有操作,以便所有操作都能正常工作。 - John Szakmeister

0
我仍然不明白为什么git拒绝报告它正在检查此repo中的对象,
我将在git列表中提出这个问题,因为我认为git fsck应该彻底检查所有操作以确保其正常工作。
这可能与Git 2.12(2017年第一季度)带来的这两组补丁有关:现在在树莓派上重新编译git 2.12可能会产生更好的结果。
请参见下文:建议使用Git 2.20(2018年第四季度)。
“git fsck”现在更仔细地检查松散的对象。

请查看提交 cce044d, 提交 c68b489, 提交 f6371f9, 提交 118e6ce, 提交 771e7d5, 提交 0b20f1a (2017年1月13日) 由Jeff King (peff)提交。
(由Junio C Hamano -- gitster --合并于提交 42ace93, 2017年1月31日)

而且:

"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日) 由 Jeff King (peff) 提交。
(由 Junio C Hamano -- gitster -- 合并于 提交 4ba6197, 2017年1月31日)


2018年11月更新:上述推荐的Git 2.12实际上引入了一个回归,导致在处理截断的松散对象时"git fsck"进入无限循环。

请查看提交 98f425b, 提交 ccdc481, 提交 5632baf (2018年10月30日) 由Jeff King (peff)完成。
(由Junio C Hamano -- gitster --提交 879a8d4中合并,2018年11月13日)

check_stream_sha1(): 处理输入不足

此提交修复了在fsck大型截断松散对象时出现无限循环的问题。

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

后者是预期的,因为zlib可能会在我们的4k缓冲区中用完空间,这就是它告诉我们处理输出并再次循环的方式。

Z_BUF_ERROR也涵盖了另一种情况:即zlib由于需要更多的输入而无法取得进展。

在此循环中,这种情况永远不应发生,因为虽然我们正在流式传输输出,但我们在的缓冲区中有整个压缩的输入可用。但由于我们没有检查这种情况,如果我们看到一个截断的对象,我们将无限循环,认为zlib正在请求更多的输出空间。


Git 2.22(2019年第二季度)改进了“git fsck --connectivity-only”,该命令省略了必要的计算,以将不可从任何引用到达的对象筛选为不可达和悬空。
现在,在请求悬空对象时启用此功能(默认情况下执行此操作,但可以使用“--no-dangling”选项覆盖)。

查看提交8d8c2a5提交df805ed(2019年3月5日)由Jeff King (peff)
(由Junio C Hamano -- gitster --合并于提交ea32776,2019年3月20日)

fsck: always compute USED flags for unreachable objects

The --connectivity-only option avoids opening every object, and instead just marks reachable objects with a flag and compares this to the set of all objects. This strategy is discussed in more detail in 3e3f8bd (fsck: prepare dummy objects for --connectivity-check, 2017-01-17).

This means that we report every unreachable object as dangling.
Whereas in a full fsck, we'd have actually opened and parsed each of those unreachable objects, marking their child objects with the USED flag, to mean "this was mentioned by another object".
And thus we can report only the tip of an unreachable segment of the object graph as dangling.

You can see this difference with a trivial example:

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)

Running git fsck will report only $two as dangling, but with --connectivity-only, both commits (and the tree) are reported. Likewise, using --lost-found would write all three objects.

We can make --connectivity-only work like the normal case by taking a separate pass over the unreachable objects, parsing them and marking objects they refer to as USED. That still avoids parsing any blobs, though we do pay the cost to access any unreachable commits and trees (which may or may not be noticeable, depending on how many you have).


请参见Git 2.39(2022年第四季度)的https://github.com/git/git/commit/fdbfac60fd889d4e55244958ce7febd61cb53f9d。 - VonC

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