Git如何快速创建提交?

时间:2016-08-17 22:56:56

标签: git version-control

据我所知,Git中的每个提交都是整个存储库的“快照”,这意味着,至少每个文件都必须被读取。我的存储库是9.2 GB,提交只需要几分之一秒。不知道它是如何发生的那么快。

3 个答案:

答案 0 :(得分:4)

  

至少,每个文件都必须被阅读

相反,这是可能发生的最

运行git commit来提交暂存的更改通常很快,因为实际上暂存更改完成了大部分工作。创建提交只需将索引(也称为“临时区域”)转换为非常轻量级的提交对象,其中包含有关提交的元数据,以及一些包含存储库结构的树对象。

但是,当您在特定文件上运行git add时,文件中的所有数据都会添加到git的数据库中。然后将有关该文件的数据存储在暂存区域中,以便在运行git commit时,有关该文件的所有信息都已存在于索引中。因此,最昂贵的部分是通过运行git add摊销的。

另一个微妙的事情是索引包含有关所有存储库中文件的信息 - 并且它维护有关工作目录的信息,例如它上次检查文件及其文件的时间戳尺寸。因此,即使您运行类似git add .的内容来暂存所有已更改的文件,也只需要stat该文件以确定它是否已更改,如果没有,则可以忽略它。

显然,查看工作目录中的所有文件有点贵,但很多比添加甚至未更改文件的完整快照更便宜。

因此,即使git在每次提交时都存储了存储库的快照,它实际上只需要为更改的文件存储新数据,它可以存储指向旧的,未更改的文件内容的指针。

答案 1 :(得分:0)

据我所知,到目前为止...想象一下,你在master分支中有很多提交,而另一个分支也有很多提交。因此,如果VCS不支持带哈希等的git概念,只是存储文件的差异然后你想分支。然后,其他VCS要么还原共享提交的所有更改,要么应用其他分支的所有更改,或者必须逐个比较所有文件。在我看来,git的哈希算法似乎是更好的方法,即使git必须做很多迭代/搜索我猜。 Idk如果我是对的,我今天就开始阅读有关git的内容。随意downvote / upvote和评论:D我认为这是一个只有少数人真正有部门知识的话题

答案 2 :(得分:0)

注意;如果您的存储库中包含大量提交,例如“ largest Git repo on the planet”,其中包含超过250000个提交,则添加新的提交实际上可能

这就是为什么Git 2.23(2019年第三季度)引入提交图的原因。

请参见commit 5b15eb3commit 16110c9commit a09c130commit e2017c4commit ba41112commit 3da4b60commit c2bc6e6,{{3} },commit 8d84097commit c523035commit 1771be9commit 135a712commit 6c622f9commit 144354bcommit 118bd57commit 5c84b33commit 3cbc6edcommit d4f4d60commit 890345a(2019年6月18日)。
(由Derrick Stolee (derrickstolee)Junio C Hamano -- gitster --中合并,2019年7月19日)

  

commit-graph:文档提交图链

commit 92b1ea6现在具有:

  

提交图链

     

通常,回购以几乎恒定的速度增长(每天提交)。
  随着时间的流逝,通过提取操作添加的提交数量比   完整历史记录中的提交次数。

     

通过创建提交图的“链”,我们可以快速写入新的提交数据,而无需重写整个提交历史记录 –至少在大多数情况下都是如此。

     

文件布局

     

提交图链使用多个文件,并且我们使用固定的命名约定来组织这些文件。
  每个提交图文件都有一个名称$OBJDIR/info/commit-graphs/graph-{hash}.graph,其中{hash}是存储在该文件页脚中的十六进制值的哈希值(这是该哈希值之前文件内容的哈希值)。
  对于一串提交图形文件,$OBJDIR/info/commit-graphs/commit-graph-chain处的纯文本文件包含从“最低”到“最高”的哈希值。

     

例如,如果commit-graph-chain文件包含以下行:

    {hash0}
    {hash1}
    {hash2}
     

然后,提交图链如下图所示:

 +-----------------------+
 |  graph-{hash2}.graph  |
 +-----------------------+
      |
 +-----------------------+
 |                       |
 |  graph-{hash1}.graph  |
 |                       |
 +-----------------------+
      |
 +-----------------------+
 |                       |
 |                       |
 |                       |
 |  graph-{hash0}.graph  |
 |                       |
 |                       |
 |                       |
 +-----------------------+

     
      
  • X0graph-{hash0}.graph中的提交次数,
  •   
  • X1graph-{hash1}.graph中的提交次数,并且
  •   
  • X2是graph-{hash2}.graph中的提交数。
  •   
     

如果提交出现在i的位置graph-{hash2}.graph中,则我们将其解释为位置(X0 + X1 + i)的提交,并将其用作其“图形位置”。 br />   graph-{hash2}.graph中的提交使用这些位置来指代其父母,这些父母可能在graph-{hash1}.graphgraph-{hash0}.graph中。
  通过检查间隔j[0, X0)[X0, X0 + X1)中的约束,我们可以导航到位置[X0 + X1, X0 + X1 + X2)上的任意提交。


这意味着 documentation 具有新的write命令选项 --split

>
  

commit-graph:将--split选项添加到内置

     

在'--split'子命令中添加新的“ git commit-graph write”选项。
  该选项允许编写提交图链的可选行为。

     

当前行为将添加一个提示提交图,其中包含不在现有提交图或提交图链中的所有提交。
  以后的更改将允许合并链并过期文件。

     

添加一个新的测试脚本(git commit-grah)来证明这一点   行为。

然后t5324-split-commit-graph.sh添加:

  

使用--split选项,将提交图写入存储在<dir>/info/commit-graphs中的多个提交图文件链中。
  提交图中尚未包含的新提交将添加到新的“提示”文件中。
  如果满足以下合并条件,则此文件与现有文件合并   见过:

     
      
  • 如果未指定--size-multiple=<X>,则使X等于2。   提示文件将提交N次,而上一个提示文件将提交M次,   是X的{​​{1}}倍于N,而是将两个文件合并为一个文件。

  •   
  • 如果为M指定了--max-commits=<M>为正整数,并且新提示文件的提交超过M,则将新提示与上一个提示合并

  •   
     

最后,如果未指定M,则使--expire-time=<datetime>为当前时间。写入拆分提交图后,请删除所有修改时间早于datetime的未使用提交图。


这将有助于

  

datetime:允许交叉链接

     

在诸如fork网络之类的环境中,具有跨基础存储库和fork存储库的提交图链会很有帮助。
  分支通常是大型仓库中的一小部分数据,但有时分支要大得多。
  例如,same documentation的提交次数几乎是git-for-windows/git的两倍,因为它基于每次主要版本更新重新建立其提交。

git/git现在包括:

  

跨多个对象目录的链接

     

在具有备用项的存储库中,我们从本地对象目录中然后在每个备用项中查找commit-graph文件。
  存在的第一个文件定义了我们的链。
  在链文件中为每个commit-graph-chain查找graph-{hash}文件时,我们对主机目录采用相同的模式。

     

这允许在分支网络中的多个分支之间拆分提交图。
  典型的案例是大型的“基础”仓库,上面有许多较小的货叉。

     

随着基础仓库的发展,它可能会比分叉更频繁地更新和合并其提交图链。
  如果fork在基本存储库之后更新其提交图,则它应将提交图链“重新绑定”到基本存储库中的新链上。
  读取每个{hash}文件时,我们会跟踪包含该文件的对象目录。在写入新的提交图文件期间,我们检查源对象目录中是否有任何更改,并读取该源的graph-{hash}文件,并基于这些文件创建一个新文件。
  在此“父”操作期间,由于所有文件对新的基本文件均无效,因此我们必须折叠分叉中的所有级别。


这还涉及到到期提交图文件:

  

commit-graph-chain:到期提交图文件

     

当我们在提交图链中合并提交图文件时,我们应该清理不再使用的文件。

     

此更改为上下文引入了“ commit-graph”值,即   始终为零(目前)。
  然后,我们检查expiry_window文件夹中每个graph-{hash}.graph文件的修改时间,并取消链接早于$OBJDIR/info/commit-graphs的文件。

documentation现在引用:

  

删除图形{hash}文件

     

在写入新的提示文件后,某些expiry_window文件可能不再是链的一部分。最终从磁盘中删除这些文件很重要。
  延迟删除的主要原因是,另一个进程可以在重写之前graph-{hash}文件来读取文件,但是在删除commit-graph-chain文件后再查找文件。

     

要允许在未引用旧拆分提交图后保留一段时间,   当文件变为未引用状态时,我们将更新文件的修改时间。
  然后,我们在graph-{hash}目录中扫描$OBJDIR/info/commit-graphs/   文件的修改时间早于给定的到期时间窗口。
  该窗口默认为零,但可以使用命令行参数或配置设置进行更改。