3

所以我最近发现了这个工具git cat-file,我一直在玩它。我知道 git 使用 blob 来存储实际内容。但是为什么每次我git add更改文件时似乎都会创建一个新的blob,即与编辑现有的blob,或者创建一个新的blob并删除旧的blob相反?

例如

touch hello.txt
// change hello.txt to contains 'hello'
git add hello.txt // creates a blob abc123 containing: 'hello'  

// change hello.txt to 'hello world'
git add hello.txt // creates a blob cba321 containing: 'hello world'  

git commit // creates a commit with tree pointing at blob cba321

因此,包含我的中间阶段性更改的 blob 即包含“hello”的 blob abc123 的目的并不明显。

在提交方面,hello.txt从“”直接变为“hello world”,如果不挖掘 git blob,我什至无法取回我的中间更改 abc123。

4

2 回答 2

2

但是为什么每次我对文件添加更改时似乎都会创建一个新的blob,即与编辑现有的blob,或者创建一个新的blob并删除旧的blob相反?

无法更改任何 blob。这与关于提交的规则相同:永远不能更改任何提交。

原因是每个 Git 对象的哈希 ID(blob 和提交是四种内部 Git 对象中的两种)只是作为该对象存储的内容的加密校验和。在文件(“blob”)的情况下,实际内容是五个 ASCII 字符b, l, o, b, space,然后是十进制并存储在 ASCII 中的 blob 的大小,然后是一个 ASCII NUL 字节,然后是存储的数据。例如hello存储为 Python 可能表示为b"blob 5\0hello".

(您可以使用 SHA1 哈希计算此哈希,或使用git hash-object

$ echo -n hello | git hash-object --stdin
b6fc4c620b67d95f953a5c1c1230aaab5db5a1b0

或者:

$ python3
[snip]
>>> import hashlib
>>> hashlib.sha1(b"blob 5\0hello").hexdigest()
'b6fc4c620b67d95f953a5c1c1230aaab5db5a1b0'

因此,任何具有哈希 ID 的 blobb6fc4c620b67d95f953a5c1c1230aaab5db5a1b0都必然是文件hello,或者——如果不是——你不能hello在这个 Git 存储库中存储包含(没有换行符)的文件。为某个文件(一个阻止存储其他文件的邪恶双胞胎)找到一个分身并非易事:请参阅新发现的 SHA-1 冲突如何影响 Git?详情。

因此,当您git add创建一个文件时,Git 会创建一个新的 blob,或重新使用现有的 blob,具体取决于该文件的数据是否已作为存储库中的 blob 存在。如果您这样做git commit,Git 会永久保存与新提交对象关联的内容。如果您从未提交该 blob ,并且也没有其他提交或其他实体引用它,Git 最终会通过其垃圾收集过程使该 blob 过期(请参阅 参考资料git gc)。

(请注意,这些 Git 对象也是 zlib 压缩的,并且是所有四种 Git 对象类型的倒数第二个存储形式。但是,一段时间后,现有对象可能会打包到一个打包文件中,在那里它们与其他对象进行增量压缩在被 zlib-deflate 之前。pack 文件是最终的存储形式。如果需要,可以将打包的对象解包,尽管在正常操作中 Git 只是在扩展 delta 压缩的同时从 pack 文件中即时提取解压缩的对象数据。)

(为了完整起见,其他两种 Git 对象类型是和带注释的标签。树对象存储文件,从名称到 blob 哈希 ID 的映射,以及文件的可执行位。提交对象通过哈希 ID 指向表示快照的树。带注释的标记对象是一种特殊情况的数据结构,其中包含另一个 Git 对象的哈希 ID 以及数据负载;在此数据负载中,您可以存储 GPG 签名或其他一些数字签名,以及任何你喜欢的东西。然后你可以将一个轻量级标签指向带注释的标签对象,以获得带注释的标签。)

于 2019-03-29T22:13:12.197 回答
1

git add确实会创建 blob,因为索引(或暂存区,它有很多名称......)的目的是准备构成下一次提交的快照。

此外,您谈论的是编辑或删除 blob,但这与该工具的原则背道而驰,因为快照必须始终如一地重现,并且它引用的所有 blob 都保持不变。在某种程度上,你永远不会修改任何东西,你只是添加更多的东西和关系。

为了回答你的最后一点,不,你不能“甚至”回到认为不值得保存的状态。

于 2019-03-29T20:18:26.163 回答