Git内部:Git如何存储修订之间的微小差异?

Git内部:Git如何存储修订之间的微小差异?,git,Git,据我所知,一些VCS存储了版本之间的差异,因为有时候差异很小——源代码中的一行代码被更改,或者在后续版本中添加了注释。另一方面,Git为每个版本存储压缩的“快照” 如果只做了一个小的更改(大文本文件中的一行),Git如何处理这个问题?它是否存储两个几乎相同的副本?我认为这是对空间的低效利用 Git使用补丁或hunks。它计算2版本之间引入的差异并存储它 存储两个几乎相同的副本?我认为这是对空间的低效利用 Git扫描您的代码(启发式),并且只存储一次差异。如果git在多个文件中找到相同的代码,它将

据我所知,一些VCS存储了版本之间的差异,因为有时候差异很小——源代码中的一行代码被更改,或者在后续版本中添加了注释。另一方面,Git为每个版本存储压缩的“快照”


如果只做了一个小的更改(大文本文件中的一行),Git如何处理这个问题?它是否存储两个几乎相同的副本?我认为这是对空间的低效利用

Git使用补丁或
hunks
。它计算2版本之间引入的差异并存储它

存储两个几乎相同的副本?我认为这是对空间的低效利用

Git扫描您的代码(启发式),并且只存储一次差异。如果git在多个文件中找到相同的代码,它将为类似的代码生成
hunk
,并将指向它的指针存储在原始位置

让它变得简单-它比下面解释的要复杂得多,让它变得简单,这样你就可以更容易地理解它

扫描代码后,git搜索来自上一次提交的更改,如果发现更改,git将旧更改拆分为一个大块
如果您在文件的中间添加了代码,那么它将被拆分为3个大块(顶部=旧代码,中间-新代码,底部-旧代码),现在您将有3个大块。下次git扫描你的代码时,他将使用这3个大块头来搜索更改

例如:假设您有一组文件,每个文件的顶部都有许可协议,这在您的所有文件中都是相同的。
Git将扫描文件,第一个大块将作为补丁存储,Git将在所有其他文件上放置一个指向该大块的指针

这种方式git以一种非常有效的方式存储信息


如果您想查看it操作,请使用
git add-p
并选择
s
进行拆分


修补程序本身看起来像:


如上所述,hunk是一个与众不同的人,这里有一点关于这一点。
hunk
是一个与diff相关的术语,下面是git如何直观地显示它(补丁):

该格式以与上下文格式相同的两行标题开始,但原始文件前面有
--
,新文件前面有
++

下面是一个或多个变更块,其中包含文件中的行差异。
未更改的上下文行前面有空格字符,添加行前面有加号,删除行前面有减号


更多信息:


git存储实际提交文件的方式在存储库的整个生命周期中都会有所不同,但让我们从基础开始

当您将一个文件提交到存储库(即新文件)时,将生成该文件的完整副本。SHA1是根据其内容计算的,这是该文件的“对象id”

您可以在
.git\objects\SH\A1 hash

SH\A1散列
我用我的方式指示SHA1的前两个字符用作文件夹名,其余38个字符用作该目录中的文件名

然后修改该文件,将其添加到索引中,然后提交

这将再次存储为一个全新的文件,其索引方式与上述完全相同

这很容易测试,但请记住,无论何时进行更改1个文件的提交,都会得到3个git对象:

  • 文件的新版本
  • “树”对象,指示索引中每个文件的哪个版本用于此特定提交
  • 提交对象,存储对其父对象和树的引用
因此,git将文件存储为完整的快照。请注意,这些文件是压缩的,因此它们占用的空间不如此文件的两个完整副本,但它们占用的空间与此文件的两个完整压缩副本一样大

如果要添加的文件本身不适合压缩(想想jpg、png或zip文件),那么是的,这将占用大量空间

在某些时候,Git可能会决定打包您的存储库,在这里,Git可能会决定在这个打包文件中使用增量压缩(压缩并存储文件之间的差异)。然而,Git的其余部分没有看到这一点,因为这是Git内部底层文件访问之上的抽象。各种Git命令实现仍然会看到“未deltified”(如果有这样一个词)文件

现在,各种命令都会对您隐藏这一点,因为您使用的大多数git命令如果实现得好,就会对您(开发人员)隐藏所有底层的抽象和优化,而只关注您可能希望看到的内容

因此,如果您查看这些文件,一些命令将显示diff,其中底层文件不存储为diff,这仅仅是因为diff对您(开发人员)更有意义

如果改为使用卫浴命令,您将看到更多的水滴

如果您想了解所有这些在实践中是如何实现的,您只需要知道一个命令,即
git cat file-p SHA1

下面是一种测试方法:

  • 初始化新存储库
  • 添加一个文件并提交它
  • 执行
    git log
    并复制提交的SHA1
  • 执行commit的git cat file SHA1,您将看到如下内容:

    tree d7d68c5b2ecc58da225c953e35b0797a4805b844
    author Lasse Vågsæther Karlsen <lassevagsaether.karlsen@visma.com> 1491986419 +0200
    committer Lasse Vågsæther Karlsen <lassevagsaether.karlsen@visma.com> 1491986419 +0200
    
    First copy
    
    100644 blob 3b5d02884e6a17f20ed7938bf9e534f1bd0d195e    Temp.7z
    
    这告诉您索引包含一个文件(1行),文件名为
    Temp.7z
    ,并告诉您其SHA1 id。复制此id

  • 执行blob的
    git cat file-p SHA1,您将看到您添加的文件的内容
  • Git的存储模型既不神奇也不复杂