Git 将 Emacs 减慢到死亡 - 如何解决这个问题?

Posted

技术标签:

【中文标题】Git 将 Emacs 减慢到死亡 - 如何解决这个问题?【英文标题】:Git slows down Emacs to Death - How to Fix this? 【发布时间】:2011-10-07 03:46:50 【问题描述】:

打开文件(通过键入Ctrl-x f,AKA Find File)或在Dired 模式下对该文件键入f),在具有.git 子目录的工作目录中速度非常慢。

即使是最简单的文件(50 行,主要是 cmets)也可能需要 8 秒才能打开。

同一文件,位于不受 Git 管理的不同目录中,会立即打开。

为什么会发生这种情况,我该如何在不禁用 vc-mode 的情况下解决这个问题? (因为我使用 Emacs 的主要原因之一是它的M-x ediff-revision

更新 1:感谢@sanityinc 在下面的回答,我运行了 ELP 分析,这就是我收到的(对于一个非常小的文件,69 行,其中 59 行是普通 cmets):

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 我可以在 不到 35 毫秒 内访问一个文件——在沙盒最初所在的同一个 Samba 共享上:

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

这提出了两个问题:

    git+cygwin 的组合使它如此敏感 网速? 我怎样才能让 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 更好,但更快?

【问题讨论】:

更多关于存储库状态的信息会很有用,例如a) 文件是否在 git 中注册? b) 还有其他未注册的文件吗? c) repo 中是否有文件有大量修改未决? @sanityinc (a) 是的,文件是用git注册的,比较新的文件,目前只有2次提交。 (b) 所有文件都已注册,除了一个“gitignored”子目录。 (c) repo 中的所有文件都已完全提交,没有待修改。附:它是一个四核 64 位机器,所以不应该为这件事情的缓慢找借口。 :) @sanityinc 在 Emacs 中打开该文件时,M-! git status 需要 5-6 秒 而且大概 git 在命令行上要快得多?你是通过 Cygwin 使用 git 吗? Windows 很奇怪。我的 bash 提示需要几秒钟才能在 cygwin 下显示,我无法确定。我想一些相关的影响是导致你的 git 调用永远需要。问题在于您的 git 二进制文件(或文件系统),而不是 Emacs。 FWIW,我在 Windows Emacs 和 Windows (msys) Git 上运气不错。为什么需要 cygwin? 【参考方案1】:

有一个名为 ELP 的内置分析器。您可以尝试类似M-x elp-instrument-package,输入“vc”,然后尝试查找文件。之后,M-x elp-results 将向您显示个人资料报告。

(请注意,如果时间花在与 vc 无关的函数上,此技术将不会显示,但您可以根据需要检测更多包。)

【讨论】:

接受您的提示是接近解开谜团最有帮助的方法。我倾向于接受您的观察,即问题可能出在我的 git 设置上,而不是 Emacs。我将尝试在一个单独的线程中解决这个问题。再次感谢。【参考方案2】:

你可以尝试profile打开你的文件,看看究竟是什么花费了这么多时间。

【讨论】:

感谢 +1 让我注意到 Emacs Native Profiler,因为我以前不知道它。不幸的是,它在底部显示“目前仅支持 Linux”,而我在 Windows 7 下使用 Emacs。【参考方案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

【讨论】:

【参考方案4】:

您可以通过在.emacs 中将vc-handled-backends 设置为nil 来disable vc-mode。

【讨论】:

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

以上是关于Git 将 Emacs 减慢到死亡 - 如何解决这个问题?的主要内容,如果未能解决你的问题,请参考以下文章

如何在 GNU Emacs 中逐行滚动?

我如何将像上/下控制之类的emacs添加到vscode?

GNU Emacs完全抛弃Bazaar,正在切换到Git

在 git 中切换分支时,如何让 Emacs 恢复所有未更改的缓冲区?

编写日志条目时防止GNU Emacs退出

如何在 Emacs 中使用 Magit 管理 Git 项目 | Linux 中国