【发布时间】:2019-12-22 16:51:23
【问题描述】:
我最近克隆了一个远程仓库,其中一些 git 命令运行非常缓慢。例如,运行
git diff --quiet
...大约需要 40 秒。 (对于它的价值,回购是干净的。我使用的是git 2.20.1 版。)
在试图找出导致这种迟缓的原因时,我遇到了一些取消它的程序,尽管我不知道为什么。
在这些过程中,我发现的最简单/最快的一个是:(从一个新克隆的 repo 实例开始)从master 创建一个分支,然后将其签出。在此之后,如果我再次检查 master,现在 git diff --quiet 会很快完成(不到 50 毫秒)。
下面是一个示例交互,显示了各种操作的时间信息1:
rm -rf ./"$REPONAME" # 0.174 s
git clone "$URL" # 54.118 s
cd ./"$REPONAME" # 0.007 s
git diff --quiet # 39.438 s
git branch VOODOO # 0.032 s
git checkout VOODOO # 31.247 s
git diff --quiet # 0.014 s
git checkout master # 0.034 s
git diff --quiet # 0.012 s
正如我已经强调的那样,这只是“修复”回购的几种可能程序之一,它们对我来说同样神秘。这只是我发现的最简单/最快的一个。
上述时序序列非常可重复(即,每次运行该特定序列时,我得到的时序大致相同)。
然而,它对看似微小的变化非常敏感。例如,如果我将git branch VOODOO; git checkout VOODOO 替换为git checkout -b VOODOO,随后的时序配置文件将发生根本性的变化:
rm -rf ./"$REPONAME" # 0.015 s
git clone "$URL" # 45.312 s
cd ./"$REPONAME" # 0.007 s
git diff --quiet # 46.145 s
git checkout -b VOODOO # 42.363 s
git diff --quiet # 41.180 s
git checkout master # 47.345 s
git diff --quiet # 0.018 s
我想弄清楚发生了什么。如何进一步解决问题?
是否有永久(“可提交”)方式来“修复”回购? (通过“修复”我的意思是:摆脱git diff --quiet、git checkout ... 等的长时间延迟)
(顺便说一句,git gc 不会修复 repo,即使是暂时的;我试过了。)
我认为最终“修复”回购的是git 开始构建并缓存一些辅助数据结构,使其能够执行某些操作有效率的。如果这个假设是正确的,那么我的问题可以改写为:导致git构建这种辅助数据结构的最直接的方法是什么?
编辑: 可以说明上述情况的另外一点信息是,此存储库包含一个异常大 (1GB) 的文件。 (这就解释了git clone这一步的慢,不知道是不是和git diff --quiet等的慢有关系,如果有,是怎么回事。)
1不用说,我已将分支命名为VOODOO,以反映我对正在发生的事情的无知。
【问题讨论】:
-
git clone似乎与其他长期操作处于同一水平。你对git clone也需要很长时间感到惊讶吗?当您查看它的进度指示器时,它大部分时间都花在了哪里? -
@j6t:确实,克隆速度非常慢。我对我的帖子进行了编辑,阐明了这一点。简而言之,克隆大部分时间都在“接收对象”阶段。
-
您是在命令行上键入示例命令,即命令之间有一些延迟,还是从脚本中调用它们以便它们立即运行?另外,如果您背靠背运行两个
git diff会发生什么?当第一个慢时,第二个是快还是慢? -
@j6t:我使用脚本来运行命令,以确保可重复性。如果我在原始序列中的每个
git diff --quiet命令之后立即添加第二个git diff --quiet命令,我发现每对的第二个git diff --quiet命令与(该对的)第一个命令所花费的时间大致相同。 -
这或多或少排除了需要扫描工作树数据的“racily clean index”情况。 (在这种情况下,第二个
git diff会很快。)我建议您收集更多数据。例如,如果您使用的是 Linux 或类似系统,请运行strace -f -tt -e file,clone,execve -o /tmp/git.strace git diff --quiet并检查/tmp/git.strace中的时间戳。也许它揭示了时间花在哪里。