加快git rev-list --topo-order 的另一种方法是使用 Git 2.20(2018 年第四季度)
参见commit 561b583、commit b454241、commit 5284fc5、commit f0d9cc4、commit d6b4071、commit 4b47a9a、commit aca4240(2018 年 11 月 1 日)Derrick Stolee (derrickstolee)。
(合并Junio C Hamano -- gitster --commit 62ca33e,2018 年 11 月 18 日)
revision.c: 基于生成的拓扑序算法
当前的--topo-order 算法要求在输出第一个值之前预先遍历所有可达的提交,对它们进行拓扑排序。
此补丁引入了一种新算法,该算法使用存储的代数以递增方式按拓扑顺序进行遍历,并在执行过程中输出提交。
这可以显着减少写入固定数量提交的计算时间,例如在使用“-n <N>”进行限制或填充寻呼机的第一页时。
在我的本地测试中,我以三种模式在 Linux 仓库上使用了以下 Git 命令:
-
HEAD~1 没有提交图,
-
HEAD~1 带有提交图,并且
- 带有提交图的 HEAD。
这允许比较我们从提交图解析提交获得的好处,然后再次比较我们通过限制我们遍历的提交集获得的好处。
Test: git rev-list --topo-order -100 HEAD
HEAD~1, no commit-graph: 6.80 s
HEAD~1, w/ commit-graph: 0.77 s
HEAD, w/ commit-graph: 0.02 s
查看commit b454241中的所有详细信息。
注意:如commit d6b4071中所述:
rev-list 命令对 Git 的功能至关重要。
以下是几种重要的 rev-list 操作类型:
-
基本:
git rev-list --topo-order HEAD
-
范围:
git rev-list --topo-order compare..HEAD
-
祖先:
git rev-list --topo-order --ancestry-path compare..HEAD
-
对称差:
git rev-list --topo-order compare...HEAD
尽管如此,请使用 Git 2.23(2019 年第三季度),因为 Git 2.20 的拓扑结构在用于范围时引入了回归。
见commit 1d8e31a、commit 1b4d882(2019 年 5 月 21 日)Derrick Stolee (derrickstolee)。
(由 Junio C Hamano -- gitster -- 合并于 commit bdc81d1,2019 年 6 月 17 日)
revision:保持 topo-walk 没有无趣的提交
在b454241(revision.c: generation-based topo-order algorithm, 2018-11-01, v2.20.0-rc0)中更新topo-order walk时,逻辑是对walk logic的巨大改写.
在那个巨大的变化中,我们不小心包含了
在expand_topo_walk() 中提交了无趣的提交。
这意味着像
这样的简单查询
git rev-list --topo-order HEAD~1..HEAD
将为从 HEAD 到达的所有提交扩展拓扑遍历,而不是
只有一次提交。
revision:使用生成 A..B --topo-order 查询
如果存在具有计算代数的提交图,则
'git rev-list --topo-order -n <N> <rev>' 查询将使用那些代
数字以减少在编写N 提交之前经过的提交次数。
b454241 中的一个警告(revision.c:基于生成的拓扑顺序
algorithm, 2018-11-01) 是为了不启用新的查询算法
修订范围为“A..B”。
该逻辑被放置为从“A”开始,并将这些提交标记为无趣,但在某些情况下,性能实际上比现有逻辑差。
这种性能下降的根本原因是生成
numbers 增加我们相对于
现有的按提交日期行走的启发式方法。
虽然代数实际上保证了算法是正确的,但现有的逻辑很少出错,而且增加的要求不值得付出代价。
在 Git 2.28(2020 年第三季度)中,“git log -L...”现在利用“此提交触及哪些路径?”存储在提交图系统中的信息。
见commit 002933f、commit 3cb9d2b、commit 48da94b、commit d554672(2020 年 5 月 11 日)SZEDER Gábor (szeder)。
请参阅 Derrick Stolee (derrickstolee) 的 commit f32dde8(2020 年 5 月 11 日)。
(由 Junio C Hamano -- gitster -- 合并于 commit c3a0282,2020 年 6 月 9 日)
签字人:SZEDER Gábor
签字人:Derrick Stolee
之前的补丁可以在历史遍历期间执行行级过滤,而不是在昂贵的预处理步骤中执行,但它仍然需要一些更简单的预处理步骤,尤其是拓扑排序。
然而,现在我们有存储代号的提交图,这使得以拓扑顺序递增地遍历历史成为可能,而无需准备 limit_list() 和 sort_in_topological_order() 步骤;参见b45424181e ("[revision.c](https://github.com/git/git/blob/002933f3fe2b016022ebbbbb359f6aeba58309a4/revision.c): 基于生成的拓扑顺序算法", 2018-11-01, Git v2.20.0-rc0 -- merge)。
这个补丁结合了两者,所以我们可以在历史遍历期间进行拓扑排序和行级过滤,甚至消除那些更简单的预处理步骤,从而进一步减少显示第一次提交修改给定行之前的延迟范围。
“revs->limited”标志在这方面起着核心作用,因为由于当前实现的限制,仅当此标志保持未设置时才启用基于代数的拓扑排序。
然而,自从12da1d1f6f 中引入该功能以来,行级日志始终在setup_revisions() 中设置此标志(“实现行历史搜索(git log -L)”,2013-03-28,Git v1 .8.4-rc0 -- merge)。
设置'limited'的原因尚不清楚,因为行级日志本身并不直接依赖它,也不影响limit_list()函数如何限制修订范围。
但是,有一个间接的依赖关系:行级日志需要拓扑排序,而“传统”sort_in_topological_order() 需要一个已经有限的提交列表,因为e6c3505b44(“确保我们之前生成了整个提交列表试图对其进行拓扑排序”,2005-07-06,Git v0.99 -- merge 列在 batch #0 中)。
基于代数的新拓扑排序不再需要有限的提交列表。
所以不要为行级日志设置'revs->limited',除非确实有必要,即:
- 用户明确要求重写父级,因为这仍然在
line_log_filter() 预处理步骤中完成(参见上一个补丁),这也需要 sort_in_topological_order() 和 turn limit_list()。
- 提交图文件不可用或尚不包含代号。
在这些情况下,我们不得不依靠sort_in_topological_order() 和limit_list()。
generation_numbers_enabled() 的现有条件已经确保在这些情况下设置了“limited”标志;此补丁只是确保行级日志在该条件之前设置“revs->topo_order”。
虽然在 git.git 中可以衡量显示第一次提交之前减少的延迟,但需要更大的存储库才能使其清晰可见。
在这两种情况下,都选择了行范围以下,因此它们的修改与起始修订相当接近,因此这种更改的效果最为明显。
# git.git
$ time git --no-pager log -L:read_alternate_refs:sha1-file.c -1 v2.23.0
Before:
real 0m0.107s
user 0m0.091s
sys 0m0.013s
After:
real 0m0.058s
user 0m0.050s
sys 0m0.005s
# linux.git
$ time git --no-pager log \
-L:build_restore_work_registers:arch/mips/mm/tlbex.c -1 v5.2
Before:
real 0m1.129s
user 0m1.061s
sys 0m0.069s
After:
real 0m0.096s
user 0m0.087s
sys 0m0.009s
Derrick Stolee 的附加测试:由于这个补丁提高了第一个结果的性能,我在 Linux 内核存储库上重复了上一个补丁的实验,在这里实时报告:
Command: git log -L 100,200:MAINTAINERS -n 1 >/dev/null
Before: 0.71 s
After: 0.05 s
现在,在报告第一个结果之前,我们已经删除了所有 ~910,000 次提交的完整拓扑顺序。剩下的性能改进是:
-
将父级重写逻辑更新为增量式,类似于“git log --graph”的行为方式。
-
使用changed-path Bloom 过滤器来减少在tree-diff 中查看路径是否更改所花费的时间。
在 Git 2.31(2021 年第一季度)中,拓扑行走代码路径被新的 trace2 统计信息覆盖。
见Derrick Stolee (derrickstolee)commit 90b666d(2020 年 12 月 30 日)。
(由 Junio C Hamano -- gitster -- 合并于 commit 02feca7,2021 年 1 月 15 日)
签字人:Derrick Stolee
自42e50e7 ("revision.c: add trace2 stats around Bloom filter usage", 2020-04-06, Git v2.27.0-rc0 -- @987654364 @ 列于batch #6)。
为使用代数限制行走大小的拓扑行走算法添加类似的跟踪。
此信息有助于调查和描述启发式方法和其他更改的好处。
打印的信息是 JSON 格式,可以很好地格式化如下:
{
unt_explort_walked":2603,
unt_indegree_walked":2603,
unt_topo_walked":473
}
这些值中的每一个都计算拓扑行走的三个“阶段”中的每一个访问的提交数量,如b454241(“revision.c:基于生成的拓扑顺序算法”,2018- 11-01,Git v2.20.0-rc0 -- merge)。
在 Git 2.32(2021 年第二季度)中,引入了一个新的配置变量,允许选择在提交图文件中使用哪个版本的世代号。
见commit 702110a,commit c7ef8fe(2021 年 2 月 25 日)Derrick Stolee (derrickstolee)。
(由 Junio C Hamano -- gitster -- 合并到 commit d20fa3c,2021 年 3 月 22 日)
签字人:Derrick Stolee
我们有两个既定的代号版本:1:拓扑级别 2:更正的提交日期
默认情况下启用更正的提交日期,但它们也会在 GDAT 和 GDOV 块中写入额外数据。
托管 Git 数据的服务可能希望更好地控制此功能何时推出,而不仅仅是更新 Git 二进制文件。
添加一个新的“commitGraph.generationVersion”配置选项,用于指定预期的代号版本。
如果该值小于 2,则永远不会从现有文件中写入或读取 GDAT 块。
git config 现在包含在其man page 中:
commitGraph.generationVersion
指定写入时使用的代号版本类型
或阅读提交图文件。
如果指定版本 1,则
不会写入或读取更正的提交日期。
默认为 2。