打包文件背后的机制

时间:2013-06-14 23:02:44

标签: git data-structures internals

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

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

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

现在他们似乎与我相矛盾,第一段是错误的,因为Git确实存储了blob的delta(delta本身就是blob)。那么作者为什么决定这样解释呢?或者有人能弥合这两段之间的差距?在我看来,没有完整的快照,Git对打包文件很好。我有一个来自git-scm.com的例子here

1 个答案:

答案 0 :(得分:2)

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

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

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

所以作者试图提出的观点是,Git的基本操作模式都是基于完整的文件,而git log -p这样的操作实际上是在动态计算差异,而不仅仅是显示什么被储存了。他们诚实地指出磁盘存储可能涉及存储增量,但这些是低级概念。

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