Git difftool在Cygwin/MinGW中的速度慢得可笑

Git difftool在Cygwin/MinGW中的速度慢得可笑,git,cygwin,mingw,benchmarking,git-difftool,Git,Cygwin,Mingw,Benchmarking,Git Difftool,我注意到,gitdifftool非常慢。每次diff调用之间会出现大约1..2秒的延迟 为了对其进行基准测试,我编写了一个自定义的difftool命令: #!/bin/sh echo $0 $1 $2 并将Git配置为在my~/.gitconfig [diff] tool = mydiff [difftool "mydiff"] prompt = false cmd = "~/mydiff \"$LOCAL\" \"$REMOTE\"" 我在Git源代码上测试了它:

我注意到,
gitdifftool
非常慢。每次diff调用之间会出现大约1..2秒的延迟

为了对其进行基准测试,我编写了一个自定义的
difftool
命令:

#!/bin/sh
echo $0 $1 $2
并将Git配置为在my
~/.gitconfig

[diff]
    tool = mydiff
[difftool "mydiff"]
    prompt = false
    cmd = "~/mydiff \"$LOCAL\" \"$REMOTE\""
我在Git源代码上测试了它:

$ git clone https://github.com/git/git.git
$ cd git
$ git rev-parse HEAD
1bc8feaa7cc752fe3b902ccf83ae9332e40921db
$ git diff head~10 --stat --name-only | wc -l
23
当我用
259b5e6d33
计时一个
git difftool
时,结果慢得可笑:

$ time git difftool 259b5
mydiff /dev/null Documentation/RelNotes/2.6.3.txt
...
mydiff /tmp/mY2T6l_upload-pack.c upload-pack.c

real    0m10.381s
user    0m1.997s
sys     0m6.667s
通过尝试更简单的脚本,速度会快得多:

$ time git diff --name-only --stat 259b5 | xargs -n1 -I{} sh -c 'git show 259b5:{} > {}.tmp && ~/mydiff {} {}.tmp'
mydiff Documentation/RelNotes/2.6.3.txt Documentation/RelNotes/2.6.3.txt.tmp
mydiff upload-pack.c upload-pack.c.tmp

real    0m1.149s
user    0m0.472s
sys     0m0.821s
我错过了什么

这是我得到的结果

| Cygwin | Debian | Ubuntu | Method   |
| ------ | ------ | ------ | -------- |
| 10.381 |  2.620 | 0.580  | difftool |
|  1.149 |  0.567 | 0.210  | custom   |

对于
Cygwin
结果,我测量了在
git difftool
中花费的2.8秒和在
git difftool--helper
中花费的7.5秒。后者有98行。我不明白为什么这么慢

使用找到的一些技术,我已经缩小了范围

对于diff中的每个文件,
git difftool--helper
重新运行以下内部命令:

12:44:46.941239 git.c:351               trace: built-in: git 'config' 'diff.tool'
12:44:47.359239 git.c:351               trace: built-in: git 'config' 'difftool.bc.cmd'
12:44:47.933239 git.c:351               trace: built-in: git 'config' '--bool' 'mergetool.prompt'
12:44:48.797239 git.c:351               trace: built-in: git 'config' '--bool' 'difftool.prompt'
12:44:49.696239 git.c:351               trace: built-in: git 'config' 'difftool.bc.cmd'
12:44:50.135239 git.c:351               trace: built-in: git 'config' 'difftool.bc.path'
12:44:50.422239 git.c:351               trace: built-in: git 'config' 'mergetool.bc.path'
12:44:51.060239 git.c:351               trace: built-in: git 'config' 'difftool.bc.cmd'
12:44:51.452239 git.c:351               trace: built-in: git 'config' 'difftool.bc.cmd'
请注意,在这个特定的例子中,执行这些操作大约需要4.5秒。在我的日志中,这是一个非常一致的模式

还要注意,其中一些是重复的-
git config difftool.bc.cmd
被调用了4次

现在,可能的补救措施:

  • 通过将所有与diff相关的部分移动到
    .gitconfig
    文件的顶部,我将这些命令的执行时间缩短了一半。认真地它仍然很明显,但是现在已经从4.5秒改为2秒
  • 确保程序文件下的Git文件夹和用户配置文件(其中
    .gitconfig
    lives)都被排除在实时病毒扫描之外
  • 基本上,Git需要更高效地解析和获取配置值。理想情况下,它将缓存这些,而不是在循环中每次都从配置中重新请求(并重新分配…)。甚至可能在整个命令执行过程中进行缓存

git difftool
使用git 2.13(2017年第二季度)应该会稍微快一点
参见(2017年4月14日)作者。
(于2017年4月24日被合并)

解包树
:在签出期间避免重复的ODB查找 (ODB:对象数据库)

教导
遍历树\u recursive()
在两个目录引用同一个OID时不要进行冗余ODB查找

在诸如
读取树
签出
等操作中,当提交之间的差异相对较小时,可能会有许多具有相同OID的对等目录。
在这些情况下,我们可以避免对同一OID多次命中ODB

此修补程序处理n=2和n=3种情况,并简单地复制数据,而不是重复填充树描述符()

在Windows repo(500K树,3.1M文件,450MB索引)上,当在两次提交之间以单个文件差异循环时,总时间减少了0.75秒


经过一些调查,我有证据表明,糟糕的性能与来自不同域的用户拥有的文件有关。具体而言,我得出以下结论:

  • 我在一个拥有多个域和数千名用户的公司环境中工作
  • 由于组织的变化,每个用户可能仅在过渡阶段被保存在两个域中,即他或她的主域和第二个域。当通过Windows GUI更改对象所有权时,每个用户都会出现两次,并且必须转到扩展用户选择以识别分配给特定域的用户
  • 启用acl的cygwin将“其他域”文件用户显示为“+”。主域自身仅为“”。没有acl的Cygwin在这两种情况下仅显示“”。这可能会让人相当困惑,因为cygwin识别的文件权限和所有权表示写入权限,而用户实际上没有写入权限
  • 属于“其他域”self的文件可由我的“此域”self写入,因此域分配在很大程度上是透明的
  • 我们版本控制系统中的一个大型源代码树(在git repo中也有镜像)有数千个文件属于“其他域自己”。这似乎导致文件操作缓慢。将所有权更改为“主域自身”解决了git和其他文件访问的速度问题
我必须假设为其他域中的用户获取文件权限很慢,并且由于某些原因没有缓存(它总是同一个用户)

下面文章的其余部分是我最初发布的内容。我让它继续


对我来说(在一家拥有多个地理分布的Windows域的大公司工作),罪魁祸首是cygwin Windows默认值。考虑域中所有已知用户的这个请求:

$ time (mkpasswd -D | wc -l)
45183

real    27m55,340s
user    0m1,637s
sys     0m0,123s
修复(1)(2)是一个简单的问题,即使用
noacl
安装NTFS文件系统,即我的
/etc/fstab
包含行

none / cygdrive binary,posix=0,user,noacl 0 0
(同时消除恼人的
cygdrive
前缀)

我忍不住想象cygwin/msys(在那里有相同的行为,除了Windows git安装默认装载
noacl
,可能是因为这个原因)对它接触的每个文件执行域服务器查询,并且不缓存结果

2015年前后,cygwin 2.4或2.5引入了这一变化。从

为了适应标准的Windows ACL,所有者和ACL中所有其他用户的POSIX权限是使用Windows AuthZ API计算的。在某些情况下,这可能会显著降低POSIX权限的计算速度(我强调)

noacl
选项将启动BeyondCompare(或回显字符串)的时间从25秒减少到1秒。完全无法理解为什么同一个文件上的一个简单的
git diff
即使使用acl也非常快,因为我会nai
$ time (mkpasswd -D | wc -l)
45183

real    27m55,340s
user    0m1,637s
sys     0m0,123s
none / cygdrive binary,posix=0,user,noacl 0 0