据我所知,Git中的每个提交都是整个存储库的“快照”,这意味着,至少每个文件都必须被读取。我的存储库是9.2 GB,提交只需要几分之一秒。不知道它是如何发生的那么快。
答案 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 5b15eb3,commit 16110c9,commit a09c130,commit e2017c4,commit ba41112,commit 3da4b60,commit c2bc6e6,{{3} },commit 8d84097,commit c523035,commit 1771be9,commit 135a712,commit 6c622f9,commit 144354b,commit 118bd57,commit 5c84b33, commit 3cbc6ed的commit d4f4d60,commit 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 | | | | | | | +-----------------------+
- 让
X0
为graph-{hash0}.graph
中的提交次数,X1
是graph-{hash1}.graph
中的提交次数,并且- X2是
graph-{hash2}.graph
中的提交数。如果提交出现在
i
的位置graph-{hash2}.graph
中,则我们将其解释为位置(X0 + X1 + i)
的提交,并将其用作其“图形位置”。 br />graph-{hash2}.graph
中的提交使用这些位置来指代其父母,这些父母可能在graph-{hash1}.graph
或graph-{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/
文件的修改时间早于给定的到期时间窗口。
该窗口默认为零,但可以使用命令行参数或配置设置进行更改。