在大型 monorepo(.git 目录 10GB)中,我观察到了以下行为。
# When outputing to a file, it is very fast:
time git log -2 > /tmp/X
real 0m0.076s
user 0m0.007s
sys 0m0.046s
# When outputting to the tty, it is more than 10x slower:
time git log -2
# ... Output omitted
real 0m0.830s
user 0m0.078s
sys 0m0.586s
以下是我的所有与日志相关的配置:
$ git config -l | grep log
log.mailmap=true
core.logallrefupdates=true
是什么导致了性能的差异,以及当 git log 输出到 tty 时如何获得相同的性能?
更多观察:
在较小的 repo 中,
git log -2
即使输出到 tty 也很快,因此问题似乎与大型 repo 有关。real 0m0.057s user 0m0.008s sys 0m0.022s
输出文件上的 Cat 速度很快,因此不仅仅是写入 stdout 很慢。
time cat /tmp/X real 0m0.015s user 0m0.001s sys 0m0.005s
expect
强制使用ttyunbuffer
也会减慢速度git log
:time unbuffer git log -2 > /tmp/X real 0m1.007s user 0m0.104s sys 0m0.669s
相比之下,
unbuffer
它本身的开销约为 240 毫秒:time unbuffer cat /tmp/X real 0m0.239s user 0m0.033s sys 0m0.111s
根据@LeGEC 的出色建议和一些进一步的实验,看起来造成差异的原因是装饰。
因此,我们得到以下结果:
git log
正如您在回答中所写,我认为您已经找到了导致速度缓慢的原因:当尝试打印每次提交的装饰时,本地存储库中的大量引用会导致速度变慢。检查一下哪些类型的引用占了这些引用的大部分。您可以比较以下数字:
如果您发现您有大量的远程分支:请尝试运行
git fetch --prune
以摆脱refs/remotes/origin/*
已被上游删除的远程引用(中的引用)。如果这 3 个数字加起来不等于中的总行数
packed-refs
,请检查哪些其他参考可以使计数更高。packed-refs
:它只是一个文本文件,每个引用一行,git for-each-ref
,例如:cut -d/ -f1-2
说“用作/
字段分隔符,仅保留前两个字段”,您可以缩小到最高数字,并通过提高第二个数字来获取更多详细信息-f1-x