我试图从这样的几个存储库中提取git日志:
git log --pretty=format:%H\t%ae\t%an\t%at\t%s --numstat
Run Code Online (Sandbox Code Playgroud)
对于较大的存储库(例如rails / rails),需要花费35秒钟以上的时间才能生成日志。
有没有办法改善这种性能?
TLDR;如GitMerge 2019中所述:
git config --global core.commitGraph true
git config --global gc.writeCommitGraph true
cd /path/to/repo
git commit-graph write
Run Code Online (Sandbox Code Playgroud)
实际上(请参阅最后),Git 2.24+(2019年第三季度)不需要前两个配置:true默认情况下它们是必需的。
Git 2.18(Q2 2018)将改善git log性能:
见提交902f5a2(2018年3月24日),由勒内Scharfe( )rscharfe。
参见Derrick Stolee()的commit 0aaf05b和commit 3d475f4(2018年3月22日)。
参见brian m。的commit 626fd98(2018年3月22日)。卡尔森()。(由Junio C Hamano合并--在commit 51f813c中,2018年4月10日)derrickstoleebk2204
gitster
sha1_name:bsearch_pack()用于缩写在针对单个packfile计算对象ID的缩写长度时,该方法
find_abbrev_len_for_pack()当前实现二进制搜索。
这是几种实现之一。
此实现的一个问题是它会忽略中的扇出表pack-index。翻译此二进制搜索以使用
bsearch_pack()正确使用扇出表的现有方法。由于使用了扇出表,因此缩写计算要比以前快一些。
对于Linux仓库的完整包装副本,改进了以下“ git log”命令:
* git log --oneline --parents --raw
Before: 59.2s
After: 56.9s
Rel %: -3.8%
* git log --oneline --parents
Before: 6.48s
After: 5.91s
Rel %: -8.9%
Run Code Online (Sandbox Code Playgroud)
相同的Git 2.18添加了一个commits图:将计算祖先遍历所需的信息预先计算并存储在一个单独的文件中,以优化图遍历。
见提交7547b95,提交3d5df01,提交049d51a,提交177722b,提交4f2542b,提交1b70dfd,提交2a2e32b(2018年4月10日),以及提交f237c8b,提交08fd81c,提交4ce58ee,提交ae30d7b,提交b84f767,提交cfe8321,提交f2af9f5(02 2018年4月)作者Derrick Stolee(derrickstolee)。
(由Junio C gitsterHamano合并--在commit b10edb2中,2018年5月8日)
commit:将提交图与提交解析集成教Git检查提交图文件,以在调用时提供结构提交的内容
parse_commit_gently()。
此实现满足结构提交上的所有后置条件,包括加载父级,根树和提交日期。如果
core.commitGraph为false,则不检查图形文件。在测试脚本t5318-commit-graph.sh中,
output-matching在只读图形操作上添加条件。通过从图中加载提交而不是解析提交缓冲区,我们节省了很多时间。
这是Linux存储库副本的一些性能结果,其中“ master”具有678,653个可到达的提交,而在“
origin/master'”之后则有59,929个提交。
| Command | Before | After | Rel % |
|----------------------------------|--------|--------|-------|
| log --oneline --topo-order -1000 | 8.31s | 0.94s | -88% |
| branch -vv | 1.02s | 0.14s | -86% |
| rev-list --all | 5.89s | 1.07s | -81% |
| rev-list --all --objects | 66.15s | 58.45s | -11% |
Run Code Online (Sandbox Code Playgroud)
要了解有关提交图的更多信息,请参见“ 如何git log --graph工作? ”。
相同的Git 2.18(2018年第二季度)添加了延迟加载树。
该代码已被教导使用存储在提交图文件中的重复信息来学习提交的树对象名称,以避免在有意义的情况下打开和解析提交对象。
见提交279ffad(2018年4月30日)由SZEDER伽柏(szeder)。
见提交7b8a21d,提交2e27bd7,提交5bb03de,提交891435d(2018年4月6日)由井架Stolee( )derrickstolee。
(由Junio C gitsterHamano合并--在commit c89b6e1中,2018年5月23日)
commit-graph:延迟加载树进行提交commit-graph文件提供对提交数据的快速访问,包括图中每个提交的根树的OID。在执行深层提交图遍历时,我们可能不需要为这些提交加载大多数树。
延迟为从图中加载的提交加载树对象,直到通过提出请求为止
get_commit_tree()。
不要为未在图中的提交而延迟加载树,因为这需要重复解析,并且在不需要树时的相对性能改进很小。在Linux系统信息库中,针对以下命令运行了性能测试:
Run Code Online (Sandbox Code Playgroud)git log --graph --oneline -1000 Before: 0.92s After: 0.66s Rel %: -28.3%
Git 2.21(2019年第一季度)增加了宽松的缓存。
见提交8be88db(2019年1月7日),并提交4cea1ce,提交d4e19e5,提交0000d65(2019年1月6日),由勒内Scharfe( )rscharfe。
(由Junio C gitsterHamano合并--在eb8638a号提交中,2019年1月18日)
object-store:oid_array每个子目录使用一个缓存松散对象缓存根据需要一次填充一个子目录。
它存储在中oid_array,必须在每次添加操作之后重新使用。
因此,当查询各种各样的对象时,部分填充的数组最多需要重新执行255次,这比排序一次要花费100多倍。
oid_array每个子目录使用一个。
这样可以确保只对条目进行一次排序。作为一个小小的奖励,它还避免了每个缓存查找的八个二进制搜索步骤。缓存用于日志占位符
%h,%t和的冲突检查%p,我们可以看到更改使它们在带有ca的存储库中加快了速度。每个子目录100个对象:Run Code Online (Sandbox Code Playgroud)$ git count-objects 26733 objects, 68808 kilobytes Test HEAD^ HEAD -------------------------------------------------------------------- 4205.1: log with %H 0.51(0.47+0.04) 0.51(0.49+0.02) +0.0% 4205.2: log with %h 0.84(0.82+0.02) 0.60(0.57+0.03) -28.6% 4205.3: log with %T 0.53(0.49+0.04) 0.52(0.48+0.03) -1.9% 4205.4: log with %t 0.84(0.80+0.04) 0.60(0.59+0.01) -28.6% 4205.5: log with %P 0.52(0.48+0.03) 0.51(0.50+0.01) -1.9% 4205.6: log with %p 0.85(0.78+0.06) 0.61(0.56+0.05) -28.2% 4205.7: log with %h-%h-%h 0.96(0.92+0.03) 0.69(0.64+0.04) -28.1%
Git 2.22(2019年4月)在使用从提交图文件读取的数据之前检查错误。
见提交93b4405,提交43d3561,提交7b8ce9c,提交67a530f,提交61df89c,提交2ac138d(2019年3月25日),并提交945944c,提交f6761fa(2019年2月21日)通过ÆvarArnfjörðBjarmason( )avar。
(由Junio C gitsterHamano合并--在commit a5e4be2中,2019年4月25日)
commit-graph写:如果现有图已损坏,请不要死当
commit-graph被写入我们最终调用parse_commit()。反过来,这将调用代码,以咨询commit-graph有关提交的现有信息,如果图形损坏,我们将死亡。因此,我们进入了以下状态:如果设置了失败的“
commit-graph verify”,则不能再加上“commit-graph write”core.commitGraph=true,需要手动删除图形才能继续进行,或者core.commitGraph需要将其设置为“ false”。更改
commit-graph write代码路径以使用新的parse_commit_no_graph()帮助程序,而不是parse_commit()避免这种情况。
后者将调用repo_parse_commit_internal(),use_commit_graph=1如177722b中所示(“commit:将提交图与提交解析”,2018-04-10,Git v2.18.0-rc0)。完全不使用旧图会稍微减慢新图的编写速度,但这是防止现有提交图中的错误扩散的明智方法。
在Git 2.24+(2019年第三季度)中,提交图默认处于活动状态:
请参阅Derrick Stolee()提交的commit aaf633c,commit c6cc4c5,commit ad0fb65,commit 31b1de6,commit b068d9a和commit 7211b9e(2019年8月13日)。(由Junio C Hamano合并--在commit f4f8dfe中,2019年9月9日)derrickstolee
gitster
commit-graph:默认情况下启用提交图自从引入以来,提交图功能在过去一年左右的时间里已经活跃了很多。
此功能是中型到大型仓库的关键性能增强,并且不会严重损害小型仓库。将
core.commitGraph和的默认值更改gc.writeCommitGraph为true,以便用户默认情况下受益于此功能。
仍然在Git 2.24(2019年第四季度)中,配置变量告诉“ git fetch”在完成后写入提交图。
参见Derrick Stolee()的commit 50f26bd(03 Sep 2019 )。(由Junio C Hamano合并--在5a53509号提交中,2019年9月30日)derrickstolee
gitster
fetch:添加fetch.writeCommitGraph配置设置
提交图功能现在默认情况下处于启用状态,默认情况下在'
git gc' 期间写入。
通常,只有当'git gc --auto'命令将gc.auto设置传递给实际工作时,Git才会写入提交图。这意味着提交图通常会落后于每天使用的提交。要保持最新的提交,请在'
git fetch'上添加一个步骤以在获取新对象后编写提交图。
该fetch.writeCommitGraph配置设置允许写拆分提交-图形,因此平均写入该文件的成本是非常小的。有时,提交图链会崩溃到单个级别,这对于非常大的回购来说可能很慢。如果
feature.experimental要启用其他功能,请将默认值调整为true 。
仍然使用Git 2.24(2019年第四季度),commit-graph功能更加强大。
请参阅Jeff King()的commit 6abada1和commit fbab552(2019年9月12日)。(通过合并JUNIOÇ滨野- -在提交098e8c6,2019年10月7日)peff
gitster
commit-graph:DIE_ON_LOAD检查实际加载时间Commit 43d3561(commit-graph编写:如果现有图形损坏,不要死,2019-03-25,Git v2.22.0-rc0)添加了一个仅在测试套件中使用的环境变量
$GIT_TEST_COMMIT_GRAPH_DIE_ON_LOAD。
但这将对这个变量的检查放在的最顶部prepare_commit_graph(),每次我们要使用提交图时都会调用该检查。
最重要的是,它出现在我们检查快速路径“我们是否已经尝试加载吗?”之前,这意味着我们最终要求getenv()每次使用提交图而不是仅仅在加载时调用。
getenv()被允许有意想不到的副作用,但这在这里应该不是问题;我们正在延迟加载图,因此很明显,至少有一次对该函数的调用将对其进行调用。但这是低效的。
getenv()通常必须在整个环境空间中进行线性搜索。我们可以记住该调用,但是将支票降低到实际加载步骤仍然更简单。这对于我们t5318的唯一用户来说很好,并且可以产生较小的实际速度:
[before] Benchmark #1: git -C linux rev-list HEAD >/dev/null
- 如果您使用的是 git 版本 2.29 或更高版本,您应该运行 `git commit-graph write --reachable --changed-paths`。这将预先计算文件路径,以便作用域为文件的“git log”命令也受益于此缓存。 (2认同)
我的第一个想法是改进 IO,但我使用 SSD 对 Rails 存储库进行了测试,得到了类似的结果:30 秒。
--numstat是什么让一切变慢,否则git-log即使格式化也可以在 1 秒内完成。进行 diff 的成本很高,因此如果您可以将其从流程中删除,将会极大地加快速度。也许事后才这样做。
否则,如果您使用 自己的搜索工具过滤日志条目git-log,这将减少需要进行比较的条目数量。例如,git log --grep=foo --numstat只需一秒钟。它们位于“Commit Limiting”下的文档中。这可以大大减少 git 必须格式化的条目数量。git-log修订范围、日期过滤器、作者过滤器、日志消息 grep...所有这些都可以在执行昂贵的操作时提高大型存储库的性能。
您是对的,确实需要 20 到 35 秒的时间来生成 56\'000 次提交的报告,生成 224\'000 行 (15MiB) 的输出。事实上,我认为这是相当不错的表现,但你不这么认为;好的。
\n\n由于您是使用不变格式从不变的数据库生成报告,因此只需执行一次。之后,您可以使用缓存的结果git log并跳过耗时的生成。例如:
git log --pretty=format:%H\\t%ae\\t%an\\t%at\\t%s --numstat > log-pretty.txt\nRun Code Online (Sandbox Code Playgroud)\n\n您可能想知道在整个报告中搜索感兴趣的数据需要多长时间。这是一个值得思考的问题:
\n\n$ tail -1 log-pretty.txt\n30 0 railties/test/webrick_dispatcher_test.rb\n$ time grep railties/test/webrick_dispatcher_test.rb log-pretty.txt \n\xe2\x80\xa6\n30 0 railties/test/webrick_dispatcher_test.rb\n\nreal 0m0.012s\n\xe2\x80\xa6\nRun Code Online (Sandbox Code Playgroud)\n\n还不错,“缓存”的引入将所需的时间从 35 秒以上减少到了十几毫秒。这几乎快了 3000 倍。
\n