2

我一直在阅读 J. Loeliger 和 M. McCullough 的“使用 Git 进行版本控制”,我发现以下分别对 git 的内部结构和打包文件进行了解释:

“Git 的内部数据库有效地存储每个文件的每个版本 - 而不是它们的差异 - 因为文件从一个修订版到下一个修订版。因为 Git 使用文件完整内容的哈希作为该文件的名称,它必须对每个完整副本进行操作文件。它不能将其工作或其对象存储条目仅基于文件的部分内容,也不能基于该文件的两个修订版本之间的差异。

“为了创建一个打包文件,Git 首先找到内容非常相似的文件并存储其中一个的完整内容。然后它计算相似文件之间的差异或增量,并仅存储差异。”

现在它们对我来说似乎是矛盾的,第一段是错误的,因为 Git 确实存储了 blob 的增量(增量本身就是 blob)。那么为什么作者会决定这样解释呢?或者有人可以弥合这两段之间的差距吗?在我看来,Git 在没有完整快照的情况下可以很好地处理打包文件。我有一个来自 git-scm.com的例子。

4

1 回答 1

2

这两段讨论的是系统的不同层。

Git 基于对象数据库,其中唯一的对象是提交、树、blob 和标签。这些是用户可以使用的对象,它们都不代表这样的变化:补丁和差异都是按需生成的。

Git确实使用 delta-encoding 将对象打包在一起进行存储,但这本质上是存储系统和有线协议的实现细节,而不是 Git 工作原理的基本模型的一部分。Git 完全有可能在不为存储进行增量编码的情况下工作(这正是它开始的方式),或者使用不兼容的编码来存储对象的不同实现。值得注意的是,delta 的存储方式通常与您实际看到的差异部分的变化没有相似之处 - 例如,delta 仅基于对象的字节序列,而不是行。这些增量都被抽象出来了,你必须进行一些黑客攻击才能看到它们。

所以作者试图说明的一点是,Git 的基本操作模式都是基于完整的文件,并且诸如此类的操作git log -p实际上是动态计算差异,而不是简单地显示存储的内容。他们诚实地指出,磁盘存储可能涉及存储增量,但这是一个低级概念。

包文件的规则包括任何一个包文件必须是自包含的:也就是说,如果一个对象作为增量存储在包文件中,则基础对象也必须存储在包文件中。在一定限度内,增量可以链接在一起:但您始终可以从包文件中获取对象,而无需超出该文件。当 Git 在内部需要包中的对象时,将应用 deltas 来生成它,它通常根本不会对 deltified 表示进行操作。(AFAIK 唯一的例外是当将对象放入另一个包中时,增量可能会按原样复制)

于 2013-06-14T23:34:01.437 回答