git - 打包文件背后的机制

标签 git data-structures internals

我一直在阅读 J. Loeliger 和 M. McCullough 的《Version Control with Git》,我发现以下分别对 git 的内部结构和打包文件的解释:

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

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

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

最佳答案

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

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

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

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

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

关于git - 打包文件背后的机制,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/17118488/

相关文章:

Git:无法重定向/解析 'git fetch --dry-run' 命令的输出

git - 如何 git clean 手动创建的文件

c++ - 在 C++ 中实现链表,我哪里出错了?

python - Python中将数组转换为二维矩阵时出错

c - PsGetContextThread 返回 C0000005(ACCESS_VIOLATION)

c# - 64 位 Windows 可以分配超过 7FFF'FFFF'FFFF 的虚拟内存吗?

git - 使用 git 作为部署实用程序时的安全问题

git - 检索 Git 中特定提交中的文件路径

string - 用于查找包含所有查询词的最小子串的高效数据结构

c - pthreads 内部是否忙于等待?