I noticed that git difftool
is very slow. An delay of about 1..2 seconds appears between each diff invocation.
To benchmark it I have written a custom difftool
command:
#!/bin/sh
echo $0 $1 $2
And configured Git to use this tool in my ~/.gitconfig
[diff]
tool = mydiff
[difftool "mydiff"]
prompt = false
cmd = "~/mydiff \"$LOCAL\" \"$REMOTE\""
I tested it on the Git sources:
$ 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
When I time a git difftool
with 259b5e6d33
, the result is ridiculously slow:
$ 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
By trying a simpler script it goes much faster:
$ 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
What did I miss?
Here the results I got
| Cygwin | Debian | Ubuntu | Method |
| ------ | ------ | ------ | -------- |
| 10.381 | 2.620 | 0.580 | difftool |
| 1.149 | 0.567 | 0.210 | custom |
For the Cygwin
results, I measured 2.8s spent in git-difftool
and 7.5s spent in git-difftool--helper
. The latter is 98 lines long. I don't understand why it is that slow.
Using some of the techniques found on the msysgit GitHub, I have narrowed this down a bit.
For each file in the diff, git-difftool--helper
re-runs the following internal commands:
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'
Notice that, in this particular case, it took roughly 4.5 seconds to execute these. This is a pretty consistent pattern throughout my log.
Note too that some of these are duplicate - git config difftool.bc.cmd
is called 4 times!
Now, possible remedies:
.gitconfig
file. Seriously. It's still noticeable, but now on the order of 2 seconds instead of 4.5..gitconfig
lives) are both excluded from realtime virus scanning.git difftool
should be slightly faster with Git 2.13 (Q2 2017)
See commit d12a8cf (14 Apr 2017) by Jeff Hostetler (jeffhostetler
).
(Merged by Junio C Hamano -- gitster
-- in commit 8868ba1, 24 Apr 2017)
unpack-trees
: avoid duplicate ODB lookups during checkout
(ODB: Object DataBase)
Teach
traverse_trees_recursive()
to not do redundant ODB lookups when both directories refer to the same OID.In operations such as
read-tree
andcheckout
, there will likely be many peer directories that have the same OID when the differences between the commits are relatively small.
In these cases we can avoid hitting the ODB multiple times for the same OID.This patch handles n=2 and n=3 cases and simply copies the data rather than repeating the fill_tree_descriptor().
================
On the Windows repo (500K trees, 3.1M files, 450MB index), this reduced the overall time by 0.75 seconds when cycling between 2 commits with a single file difference.
(avg) before: 22.699
(avg) after: 21.955
===============
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With