Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/git/22.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
如何排除异常缓慢的git差异?_Git_Git Diff - Fatal编程技术网

如何排除异常缓慢的git差异?

如何排除异常缓慢的git差异?,git,git-diff,Git,Git Diff,我最近克隆了一个远程repo,其中一些git命令运行极其缓慢。例如,跑步 git diff --quiet …需要约40秒。(值得一提的是,回购协议是干净的。我使用的是git2.20.1版。) 在试图找出导致这种迟钝的原因时,我遇到了一些取消它的程序,尽管我不知道为什么 在这些过程中,我发现的最简单/最快的一个是:(从一个新克隆的回购实例开始)创建一个分支master,并将其签出。在此之后,如果我再次签出master,现在git diff--quiet会很快完成(低于50ms) 下面是一个交互

我最近克隆了一个远程repo,其中一些
git
命令运行极其缓慢。例如,跑步

git diff --quiet
…需要约40秒。(值得一提的是,回购协议是干净的。我使用的是
git
2.20.1版。)

在试图找出导致这种迟钝的原因时,我遇到了一些取消它的程序,尽管我不知道为什么

在这些过程中,我发现的最简单/最快的一个是:(从一个新克隆的回购实例开始)创建一个分支
master
,并将其签出。在此之后,如果我再次签出
master
,现在
git diff--quiet
会很快完成(低于50ms)

下面是一个交互示例,显示了各种操作的计时信息1:

正如我已经强调的,这只是“修复”回购协议的几种可能程序之一,它们对我来说都同样神秘。这只是我发现的最简单/最快的一个

上述计时顺序是非常可重复的(即,每次运行特定顺序时,我得到的计时大致相同,如图所示)

然而,它对看似微小的变化非常敏感。例如,如果我替换
git分支伏都教;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
无法修复回购协议,即使是暂时的;我试过了。)

我认为最终“修复”回购协议的是,
git
开始构建和缓存一些辅助数据结构,使其能够高效地执行某些操作。如果这个假设是正确的,那么我的问题可以重新表述为:什么是导致
git
构建这种辅助数据结构的最直接的方法


编辑:可能有助于说明上述情况的另外一点信息是,该回购协议包含一个超大(1GB)文件。(这解释了
git clone
步骤的慢度。我不知道这是否与
git diff--quiet
等的慢度有关,如果是,怎么做。)



1不用说,我将分支命名为
VOODOO
,以反映我对正在发生的事情的无知。

首先检查Git 2.27,甚至即将推出的2.28(2020年第3季度)是否存在问题

我会用它来衡量任何绩效。(as)

使用Git2.28(2020年第3季度),在具有太多stat不匹配路径的工作树中“
diff--quiet
”期间的内存使用量已经大大减少

它的补丁描述说明了一个用例,其中“
diff--quiet
”可能很慢:

参见(2020年6月1日)作者。
(于2020年6月18日合并)

:放弃统计不匹配对中的blob数据 报告人:Jan Christoph Uhde
签字人:杰夫·金

在对工作树执行树级差异时,我们可能会发现我们的索引统计信息是脏的,因此我们将文件对排队等待稍后检查。
如果实际内容没有改变,我们称之为统计不匹配;统计信息已经过时,但没有实际的差异

通常
diffcore\u std()
会通过
diffcore\u skip\u stat\u unmatch()
检测并删除这些相同的文件对

但是,当使用“
--quiet
”时,我们希望在看到任何更改时立即停止差异,因此我们会立即在
diff_change()
中检查统计不匹配

该检查可能要求我们实际将文件内容加载到一对
diff\u filespec

如果我们发现这一对不是统计数据不匹配,那就没什么大不了的;我们可能会在以后加载内容以生成补丁、进行重命名检测等,因此我们希望保留它。
但如果这是一个统计数据不匹配,那么我们将不再使用该数据;关键是我们要放弃这一对。但是,我们从未释放分配的
diff_filespec
数据

在大多数情况下,保存这些数据不是问题。我们不希望有太多的统计数据不匹配条目,因为我们使用的是
--quiet
,不管怎样,只要我们看到这样一个真正的变化,我们就会立即退出

然而,在一些极端情况下,这会产生很大的影响:

  • 我们通常会将工作树映射为一对中的一半。
    而且,由于操作系统可能会限制地图的总数,因此我们可以在大型存储库中与之相冲突。例如:

     $ cd linux
    $ git ls-files | wc -l
    67959
    $ sysctl vm.max_map_count
    vm.max_map_count = 65530
    $ git ls-files | xargs touch ;# everything is stat-dirty!
    $ git diff --quiet
    fatal: mmap failed: Cannot allocate memory
    
  • 有这么多文件是静态脏的应该是不寻常的,但如果您只是运行了类似“
    sed-i
    ”或类似的脚本,这是可能的

    此修补程序之后,上述程序将正确退出,代码为0

  • 即使未达到mmap限制,该对的一半索引也将从对象数据库拉入堆内存。
    再次在
    linux.git
    的克隆中运行:

    $ git ls-files | head -n 10000 | xargs touch
    $ git diff --quiet
    
  • 此修补程序之前的堆峰值为145MB,之后的堆峰值为94MB

    此修补程序通过释放我们在“
    --quiet
    ”stat unmatch check in
    diff\u changes
    期间拾取的所有
    diff\u filespec
    数据来解决此问题 以后没有人会需要这些数据,所以保留这些数据毫无意义。
    有几件事需要注意:

    • 我们可以完全跳过排队,这在理论上可以节省一点工作。但是没有什么可以保存的,因为我们需要一个
      diff\u文件对
      来馈送到
      diff\u filespec\u check\u stat\u unmatch()

      由于我们缓存了
      stat unmatch
      检查的结果,因此稍后调用
      diffcore\u skip\u sta
      
      $ git ls-files | head -n 10000 | xargs touch
      $ git diff --quiet
      
      Test                                                                     v2.29.0-rc1       this tree
      -----------------------------------------------------------------------------------------------------------------
      7519.2: status (fsmonitor=.git/hooks/fsmonitor-watchman)                 1.46(0.82+0.64)   1.47(0.83+0.62) +0.7%
      7519.3: status -uno (fsmonitor=.git/hooks/fsmonitor-watchman)            0.16(0.12+0.04)   0.17(0.12+0.05) +6.3%
      7519.4: status -uall (fsmonitor=.git/hooks/fsmonitor-watchman)           1.36(0.73+0.62)   1.37(0.76+0.60) +0.7%
      7519.5: diff (fsmonitor=.git/hooks/fsmonitor-watchman)                   0.85(0.22+0.63)   0.14(0.10+0.05) -83.5%
      7519.6: diff -- 0_files (fsmonitor=.git/hooks/fsmonitor-watchman)        0.12(0.08+0.05)   0.13(0.11+0.02) +8.3%
      7519.7: diff -- 10_files (fsmonitor=.git/hooks/fsmonitor-watchman)       0.12(0.08+0.04)   0.13(0.09+0.04) +8.3%
      7519.8: diff -- 100_files (fsmonitor=.git/hooks/fsmonitor-watchman)      0.12(0.07+0.05)   0.13(0.07+0.06) +8.3%
      7519.9: diff -- 1000_files (fsmonitor=.git/hooks/fsmonitor-watchman)     0.12(0.09+0.04)   0.13(0.08+0.05) +8.3%
      7519.10: diff -- 10000_files (fsmonitor=.git/hooks/fsmonitor-watchman)   0.14(0.09+0.05)   0.13(0.10+0.03) -7.1%
      7519.12: status (fsmonitor=)                                             1.67(0.93+1.49)   1.67(0.99+1.42) +0.0%
      7519.13: status -uno (fsmonitor=)                                        0.37(0.30+0.82)   0.37(0.33+0.79) +0.0%
      7519.14: status -uall (fsmonitor=)                                       1.58(0.97+1.35)   1.57(0.86+1.45) -0.6%
      7519.15: diff (fsmonitor=)                                               0.34(0.28+0.83)   0.34(0.27+0.83) +0.0%
      7519.16: diff -- 0_files (fsmonitor=)                                    0.09(0.06+0.04)   0.09(0.08+0.02) +0.0%
      7519.17: diff -- 10_files (fsmonitor=)                                   0.09(0.07+0.03)   0.09(0.06+0.05) +0.0%
      7519.18: diff -- 100_files (fsmonitor=)                                  0.09(0.06+0.04)   0.09(0.06+0.04) +0.0%
      7519.19: diff -- 1000_files (fsmonitor=)                                 0.09(0.06+0.04)   0.09(0.05+0.05) +0.0%
      7519.20: diff -- 10000_files (fsmonitor=)                                0.10(0.08+0.04)   0.10(0.06+0.05) +0.0%
      
      (gdb) bt  [simplified]