如果 git 的功能来自文件的快照,为什么 .git/ 不会随着时间的推移而变得很大?

  • 本文关键字:git 时间 文件 功能 快照 如果 git
  • 更新时间 :
  • 英文 :


我一直在读git书。在这本书中,我了解到 git 的功能是通过拍摄你处理的文件的快照来实现的,而不是像其他 VCS 那样的增量。这有一些很好的好处。

然而,这让我想知道:随着时间的推移,包含这些快照的 .git/文件夹不应该太大吗?有些存储库有 10,000+ 次或更多提交,包含数百个文件。为什么 git 的大小不会爆炸?

这里的诀窍是这个声明:

git 通过拍摄您处理的文件的快照来发挥作用,而不是像其他 VCS 那样使用增量

既是真的,也是假的!

Git 的主对象数据库(键值存储(存储四种对象类型。 我们不需要在这里详细介绍;我们可以注意到,文件(或者更准确地说,文件的内容(存储在Blob对象中。然后,提交对象(间接(引用 blob 对象,因此,如果你有一些名为bigfile.txt的文件内容并将其存储在 1000 个不同的提交中,则所有这些提交中只有一个对象,重复使用 1000 次。 (事实上,如果您将其重命名为hugefile.txt而不更改其内容,则新提交将继续重用原始对象 — 名称单独存储在对象中。

这一切都很好,但随着时间的推移,大多数项目中的大多数文件确实会累积更改。 其他 VCS 将不使用存储每个文件的全新副本,而是使用增量编码来避免单独存储每个文件的每个版本。 如果 blob 对象是一个完整的、完整的(尽管是 zlib 压缩的(文件,你的问题可以归结为:单独 blob 对象的累积不会使对象数据库的增长速度比使用增量压缩的 VCS 快得多吗?

答案是会的,但 Git确实使用了增量压缩。 它只是在对象数据库级别以下执行此操作。 对象在逻辑上是独立的。 你给 Git 一些对象的密钥(哈希 ID(,然后你得到整个对象。 但只有所谓的松散对象被存储为一个简单的 zlib 放气文件。

正如乔纳森·布林克(Jonathan Brink(所指出的,git gc清理未使用的对象。 这对保留的对象没有帮助,例如旧版本的hugefile.txt或其他对象。 但是git gc- 只要 Git 认为它可能合适,Git 就会自动运行 - 不仅仅是修剪未引用的对象。 它还运行git repack,以构建或重新构建包文件

包文件存储多个对象,在包文件中,对象被增量压缩。 Git 对将进入单个包文件的所有对象的集合进行毛孔处理,对于所有N个对象,选取其中的一些集合B用作增量基础。 这些对象只是 zlib-放气。 其余的N-B对象被编码为增量,针对基数或使用这些碱基的早期增量编码对象。 因此,给定存储在包文件中的对象的键,Git 可以找到存储的对象或增量,如果存储的是增量,Git 也可以找到底层对象,一直到增量基础,从而提取完整的对象。

因此,Git确实使用增量编码,但仅在包文件中使用。 它也不是基于文件而是基于对象,所以(至少在理论上(如果你有巨大的树,或者提交消息中的长文本,它们也可以相互压缩。

即使这还不是故事的全部:对于通过网络传输,Git 将构建所谓的瘦包。 常规包装和薄包装之间的主要区别与这些增量底座有关。 给定常规包文件和哈希 ID,Git 始终可以从该文件中检索完整的对象。 但是,对于精简包,允许 Git 使用不在该包文件中的对象(只要将精简包传输到的另一个 Git 声称它具有这些对象(。 接收方需要在接收时"修复"精简包,但这允许git fetchgit push发送增量而不是完整的快照。

最新更新