所以我最近发现了工具git cat-file
,我一直在玩它。我知道git使用blob来存储实际内容。但是为什么每次我改变文件时都会创建一个新的blob,即与编辑现有的blob,或者创建一个新的blob并删除旧的blob相反?
EG
git add
所以包含我的中间阶段变化的blob的目的,即包含“hello”的blob abc123并不明显。
在提交方面,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
从“”直接转到“hello world”,我甚至无法在没有挖掘git blob的情况下取回我的中间变化abc123。
但是为什么每当我git添加一个文件的更改时,它似乎创建一个新的blob,即与编辑现有的blob,或者创建一个新的blob并删除旧的blob相反?
没有blob可以改变。这与关于提交的规则相同:不能更改任何提交。
原因是每个Git对象-bbb和提交的哈希ID是四种类型的内部Git对象中的两种 - 只是作为该对象存储的内容的加密校验和。在文件(“blob”)的情况下,实际内容是五个ASCII字符hello.txt
,b
,l
,o
,space,然后blob的大小十进制并且还存储在ASCII中,然后是ASCII NUL字节,以及然后存储数据。例如,b
存储为Python可能代表的hello
。
(您可以使用SHA1哈希或使用b"blob 5\0hello"
计算此哈希:
git hash-object
要么:
$ echo -n hello | git hash-object --stdin
b6fc4c620b67d95f953a5c1c1230aaab5db5a1b0
所以任何带有哈希ID $ python3
[snip]
>>> import hashlib
>>> hashlib.sha1(b"blob 5\0hello").hexdigest()
'b6fc4c620b67d95f953a5c1c1230aaab5db5a1b0'
的blob都必须是文件b6fc4c620b67d95f953a5c1c1230aaab5db5a1b0
,或者 - 如果不是 - 你不能在这个Git存储库中存储包含hello
(没有换行符)的文件。找到一个文件(一个邪恶的双胞胎,阻止存储其他文件)的doppelgänger是非常重要的:请参阅hello
了解详情。
因此,当您How does the newly found SHA-1 collision affect Git?文件时,Git会创建一个新的blob,或者重新使用现有的blob,具体取决于该文件的数据是否已作为存储库中的blob存在。如果你然后git add
,Git永久保存内容,与新的提交对象相关联。如果你从未提交过那个blob,也没有其他提交或其他实体引用它,Git最终会通过垃圾收集过程使blob过期(参见git commit
)。
(请注意,这些Git对象也是zlib放气,并且是所有四种Git对象类型的倒数第二个存储形式。但是,经过一段时间后,现有对象可能被打包到一个包文件中,在那里它们对其他对象进行增量压缩包装文件是最终的存储形式。包装对象可以在必要时解压缩,但在正常操作中,Git只是在扩展增量压缩的同时从包文件中动态提取解压缩的对象数据。)
(为了完整起见,另外两个Git对象类型是树和带注释的标记。树对象存储文件名,从名称到blob哈希ID的映射,以及文件的可执行位。提交对象通过哈希ID引用到表示快照的树。带注释的标记对象是一种特殊情况数据结构,它包含另一个Git对象的哈希ID以及数据有效负载;在此数据有效负载中,您可以存储GPG签名或其他一些数字签名,以及您喜欢的任何其他内容。然后,您可以将轻量级标记指向带注释的标记对象,以获取带注释的标记。)
git gc
确实创建了blob,因为索引(或临时区域,它有许多名称......)的目的是准备快照,这将构成下一次提交。
此外,您谈论编辑或删除blob,但这将违背该工具的原则,因为快照必须始终可重复,并且它引用的所有blob都不会被触及。在某种程度上,你永远不会修改任何东西,你只需添加更多的东西和关系。
回答你的最后一点,不,你不能“甚至”回到你认为不值得储蓄的状态。