Git使Emacs变得非常缓慢 - 如何解决?

37

通过在Dired模式下输入f或者键入Ctrl-x f(也称为查找文件),打开一个文件会在拥有.git子目录的工作目录中极其缓慢。

即使是最简单的文件(50行大部分都是注释),也可能需要多达8秒才能打开。

相同的文件,在没有被Git管理的不同目录中,可以立即快速打开。

为什么会出现这种情况,我该如何修复它而无需禁用vc-mode?(因为我使用Emacs的主要原因之一是它的M-x ediff-revision

更新1:感谢@sanityinc的回答,我运行了ELP Profiling并收到了以下结果(69行代码,其中59行均为纯注释):

Function Name                       Call Count   Elapsed Time  Average Time
-------------                       ----------   ------------  ------------
vc-call-backend                      11          23.023        2.093
vc-find-file-hook                    1           8.757         8.757
vc-mode-line                         1           7.812         7.812
vc-default-mode-line-string          1           7.345         7.345
vc-state-refresh                     1           6.921         6.921
vc-state                             1           6.921         6.921
vc-default-state-heuristic           1           6.921         6.921
vc-registered                        1           0.945         0.945
vc-backend                           1           0.945         0.945
vc-git-registered                    1           0.912         0.912
vc-working-revision                  1           0.4240000000  0.4240000000
vc-find-root                         4           0.0990000000  0.0247500000
vconcat                              623         0.0220000000  3.53...e-005
vc-bzr-registered                    1           0.016         0.016
vc-check-master-templates            2           0.014         0.007
vc-default-registered                2           0.014         0.007
vc-rcs-registered                    1           0.008         0.008
vc-sccs-registered                   1           0.006         0.006
vc-svn-registered                    1           0.002         0.002
vc-cvs-registered                    1           0.001         0.001
vc-sccs-search-project-dir           1           0.0           0.0
vc-kill-buffer-hook                  6           0.0           0.0
vc-find-backend-function             11          0.0           0.0
vc-default-find-file-hook            1           0.0           0.0
vc-possible-master                   6           0.0           0.0
vc-file-clearprops                   1           0.0           0.0
vc-file-setprop                      3           0.0           0.0
vc-file-getprop                      5           0.0           0.0
vc-make-backend-sym                  15          0.0           0.0

这是很棒的信息,但我不是一位Emacs/elisp专家,所以我该从哪里开始呢?

更新2:在将这个问题搁置一段时间后,我发现了这篇很棒的博客文章:Cygwin slow start up: the culprit discovered!。文章建议在后台启动bash完成。我很快实施了它并重新运行了ELP分析测试:

vc-call-backend                      11          14.489        1.317
vc-find-file-hook                    1           5.488         5.488
vc-mode-line                         1           5.118         5.118
vc-default-mode-line-string          1           4.719         4.719
vc-state-refresh                     1           4.282         4.282
vc-state                             1           4.282         4.282
vc-default-state-heuristic           1           4.282         4.282
vc-working-revision                  1           0.437         0.437
vc-registered                        1           0.37          0.37
vc-backend                           1           0.37          0.37
vc-git-registered                    1           0.34          0.34
vc-find-root                         4           0.088         0.022
vc-bzr-registered                    1           0.015         0.015
vc-check-master-templates            2           0.013         0.0065 
vc-default-registered                2           0.013         0.0065 
vc-rcs-registered                    1           0.007         0.007
vc-sccs-registered                   1           0.006         0.006
vc-cvs-registered                    1           0.001         0.001
vconcat                              623         0.001         1.60...e-006
vc-svn-registered                    1           0.001         0.001
vc-sccs-search-project-dir           1           0.0           0.0
vc-kill-buffer-hook                  6           0.0           0.0
vc-find-backend-function             11          0.0           0.0
vc-default-find-file-hook            1           0.0           0.0
vc-possible-master                   6           0.0           0.0
vc-file-clearprops                   1           0.0           0.0
vc-file-setprop                      3           0.0           0.0
vc-file-getprop                      5           0.0           0.0
vc-make-backend-sym                  15          0.0           0.0

看到 vc-call-backend 的执行时间从23秒降到14秒确实很不错,但这仍然是不可接受的(查找一个CVS控制的文件只需要不到一秒钟!)。

更新3:无法解决这个谜团,我试着升级到最新的cygwin(1.7.9-1),但没有帮助。

所以,我决定尝试将沙盒(包括其.git子目录)从Samba共享移动到本地存储(C:\Users\WinWin\Documents)。然后重新运行ELP性能测试:

vc-call-backend                           11          2.082         0.1892727272
vc-find-file-hook                         1           0.897         0.897
vc-git--call                              7           0.8929999999  0.1275714285
vc-git-mode-line-string                   1           0.78          0.78
vc-mode-line                              1           0.78          0.78
vc-default-mode-line-string               1           0.655         0.655
vc-git--out-ok                            5           0.6519999999  0.1304
vc-git-state                              1           0.53          0.53
vc-state-refresh                          1           0.53          0.53
vc-state                                  1           0.53          0.53
vc-default-state-heuristic                1           0.53          0.53
vc-git-working-revision                   2           0.25          0.125
vc-git-registered                         2           0.2239999999  0.1119999999
vc-git--run-command-string                1           0.18          0.18
vc-working-revision                       1           0.125         0.125
vc-registered                             1           0.1169999999  0.1169999999
vc-backend                                2           0.1169999999  0.0584999999
vc-git--empty-db-p                        1           0.11          0.11
vc-find-root                              3           0.003         0.001
vc-git-root                               2           0.002         0.001
vc-check-master-templates                 2           0.001         0.0005
vc-sccs-registered                        1           0.001         0.001
vc-default-registered                     2           0.001         0.0005
vc-bzr-registered                         1           0.001         0.001
vc-rcs-registered                         1           0.0           0.0
vc-sccs-search-project-dir                1           0.0           0.0
vc-kill-buffer-hook                       5           0.0           0.0
vc-default-find-file-hook                 1           0.0           0.0
vc-possible-master                        6           0.0           0.0
vc-cvs-registered                         1           0.0           0.0
vc-file-clearprops                        1           0.0           0.0
vc-file-setprop                           3           0.0           0.0
vc-file-getprop                           5           0.0           0.0
vc-svn-registered                         1           0.0           0.0
vc-make-backend-sym                       2           0.0           0.0

哇!这将vc-call-backend的时间从14秒降至2秒。虽然这很不错,但并不太好,因为使用Emacs/CVS,我能够在同一Samba共享文件中以不到35毫秒的速度访问文件:

vc-call-backend                           5           0.031         0.0062
vc-find-file-hook                         1           0.031         0.031
vc-registered                             1           0.031         0.031
vc-backend                                1           0.031         0.031
vc-rcs-registered                         1           0.016         0.016
vc-check-master-templates                 1           0.016         0.016
vc-default-registered                     1           0.016         0.016
vc-insert-file                            1           0.015         0.015
vc-cvs-get-entries                        1           0.015         0.015
vc-cvs-registered                         1           0.015         0.015
vc-cvs-state-heuristic                    1           0.0           0.0
vc-cvs-parse-sticky-tag                   1           0.0           0.0
vc-kill-buffer-hook                       1           0.0           0.0
vc-find-backend-function                  1           0.0           0.0
vc-cvs-parse-entry                        1           0.0           0.0
vc-mode-line                              1           0.0           0.0
vc-default-find-file-hook                 1           0.0           0.0
vc-possible-master                        3           0.0           0.0
vc-cvs-mode-line-string                   1           0.0           0.0
vc-default-mode-line-string               1           0.0           0.0
vc-state-refresh                          1           0.0           0.0
vc-working-revision                       1           0.0           0.0
vc-state                                  1           0.0           0.0
vc-file-clearprops                        1           0.0           0.0
vc-file-setprop                           5           0.0           0.0
vc-file-getprop                           7           0.0           0.0
vc-make-backend-sym                       2           0.0           0.0

这引发了两个问题:

  1. 是什么让git+cygwin在网络速度上如此敏感?
  2. 如何让git的响应时间降至少于50毫秒?毕竟,它被称为“快速版本控制系统”。

使用msysgit 1.7.8时的更新:

vc-call-backend                      11          0.626         0.0569090909
vc-find-file-hook                    1           0.281         0.281
vc-mode-line                         1           0.2189999999  0.2189999999
vc-default-mode-line-string          1           0.1879999999  0.1879999999
vc-state-refresh                     1           0.157         0.157
vc-state                             1           0.157         0.157
vc-default-state-heuristic           1           0.157         0.157
vc-registered                        1           0.062         0.062
vc-backend                           1           0.062         0.062
vc-git-registered                    1           0.062         0.062
vc-working-revision                  1           0.0310000000  0.0310000000
vc-rcs-registered                    1           0.0           0.0
vc-sccs-search-project-dir           1           0.0           0.0
vc-kill-buffer-hook                  6           0.0           0.0
vc-find-backend-function             11          0.0           0.0
vc-default-find-file-hook            1           0.0           0.0
vc-possible-master                   6           0.0           0.0
vc-check-master-templates            2           0.0           0.0
vc-cvs-registered                    1           0.0           0.0
vc-sccs-registered                   1           0.0           0.0
vc-file-clearprops                   1           0.0           0.0
vconcat                              623         0.0           0.0
vc-default-registered                2           0.0           0.0
vc-file-setprop                      3           0.0           0.0
vc-find-root                         4           0.0           0.0
vc-file-getprop                      5           0.0           0.0
vc-bzr-registered                    1           0.0           0.0
vc-svn-registered                    1           0.0           0.0
vc-make-backend-sym                  15          0.0           0.0

你能分辨出区别吗? :)

现在在Emacs下使用Git要快得多,但它仍然比在Emacs下使用CVS慢得多。所以我不知道为什么Git被称为“快速版本控制系统”。它可能比CVS更好,但更快吗?


1
关于存储库状态的更多信息将会很有用,例如:a)文件是否已在git中注册?b)是否存在其他未注册的文件?c)存储库中是否有待处理的大型修改文件? - sanityinc
1
@sanityinc 当在Emacs中打开该文件时,执行M-! git status需要5-6秒的时间。 - WinWin
1
而且据说在命令行上使用git会更快?你是通过Cygwin使用git吗? - sanityinc
2
Windows很奇怪。我的bash提示符在cygwin下需要几秒钟才能显示,我无法确定原因。我想你的git调用也是由于某种相关影响而变得异常缓慢。问题出在你的git二进制文件(或文件系统)上,而不是Emacs。顺便说一句,我在Windows Emacs和Windows(msys)Git上运行得很好。你为什么需要cygwin? - jrockway
@jrockway 我需要cygwin,因为我可以在Windows或Linux/UNIX上工作时拥有完全相同的环境。这是我长期以来一直在使用的方式,我不能放弃cygwin。我的许多生产力脚本都依赖于它。现在,如果你告诉我可以保留cygwin,但是摆脱它的git实现并改用msys,那就是另一回事了... +1 :) 另外,请参见我上面的更新。与CVS相比,Git肯定对vc-mode做了一些不好的事情。 - WinWin
显示剩余7条评论
4个回答

43

有一个名为ELP的内置分析器。您可以尝试像这样使用M-x elp-instrument-package,输入“vc”,然后尝试查找文件。之后,M-x elp-results会显示给您一个性能报告。

(请注意,如果时间花费在非vc相关函数中,此技术将无法显示它,但如果您愿意,可以进一步仪器化其他包。)


1
接受您的提示是接近解决这个谜团最有帮助的。我倾向于接受您的观察,即问题可能在我的 git 设置中而不是 Emacs 中。我将尝试在单独的线程中解决这个问题。再次感谢。 - WinWin

4
你可以尝试对文件进行性能分析,以确定哪些操作花费了大量时间。

感谢您让我了解Emacs本地分析器,并给予+1的支持。不幸的是,在底部它说:“目前仅支持Linux”,而我正在Windows 7下使用Emacs。 - WinWin

3

我曾经在使用mingw emacs 25.1.1时,遇到了与windows git 2.10相关的问题。

以下是测试所用命令:

(progn
  ;; make sure the buffer is not already open
  (elp-instrument-function 'find-file-other-window)
  (elp-instrument-function 'vc-git-registered)
  (elp-instrument-function 'vc-git-mode-line-string)
  (elp-instrument-function 'vc-git-find-file-hook)
  (find-file-other-window "my-file-in-a-git-repo")
  (elp-results)
  (elp-restore-all))

给出以下配置文件:
find-file-other-window   1           1.1076142     1.1076142
vc-git-mode-line-string  1           0.6396082     0.6396082
vc-git-find-file-hook    1           0.2652034     0.2652034
vc-git-registered        1           0.1872024     0.1872024

vc-git-mode-line-string函数需要一定的时间。它会在你窗口的模式行中显示类似于Git:mybranch的东西。我不太关心这个,也不想每次都等这么久,所以我覆盖了实现,只让它返回"Git"

(defun vc-git-mode-line-string (file)
  "Overwritten default vc-git-el implementation. Return a string
for `vc-mode-line' to put in the mode line for FILE."
  "Git")

vc-git-find-file-hook函数将在打开冲突文件时打开一个漂亮的冲突编辑模式。实现首先调用vc-git-conflicted-files,这需要一些时间,然后进行一个相当简单的检查,看是否有任何行以<<<<<<<开头。我只是交换了两者的顺序,现在在大多数情况下,该实现仅需约0.0秒。

(defun vc-git-find-file-hook ()
  "Overwritten default vc-git-el implementation. Activate
`smerge-mode' if there is a conflict."
  (when (and buffer-file-name
             ;; FIRST check whether this file looks like a conflicted file
             (save-excursion
               (goto-char (point-min))
               (re-search-forward "^<<<<<<< " nil 'noerror))
             ;; THEN ask git if it really is a conflict
             (vc-git-conflicted-files buffer-file-name))
    (vc-file-setprop buffer-file-name 'vc-state 'conflict)
    (smerge-start-session)
    (when vc-git-resolve-conflicts
      (add-hook 'after-save-hook 'vc-git-resolve-when-done nil 'local))
    (vc-message-unresolved-conflicts buffer-file-name)))

结果:

find-file-other-window   1           0.2838039     0.2838039
vc-git-registered        1           0.2682037     0.2682037
vc-git-find-file-hook    1           0.0           0.0
vc-git-mode-line-string  1           0.0           0.0

2
您可以通过在您的.emacs文件中将vc-handled-backends设置为nildisable vc-mode

@robert 和 @Alex Ott,我使用Emacs的主要原因之一是 ediff-revisions。难道没有更好的方法来加快速度吗?毕竟,Emacs不会对CVS版本控制下的文件做出那样的反应... - WinWin

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接