Git замедляет Emacs до смерти - как это исправить?
Открытие файла (либо путем ввода Ctrl-x f
, AKA Find File
), либо путем ввода f
в этом файле в режиме Dired
), в рабочих каталогах, имеющих подкаталог .git
, очень медленно работает.
Даже самый простой файл (50 строк с комментариями) может занять до 8 секунд.
Тот же файл в другом каталоге, который не управляется Git, сразу открывается в jiffy.
Почему это происходит и как я могу исправить этот без отключения vc-mode? (поскольку одной из основных причин, по которым я использую Emacs, является его M-x ediff-revision
)
ОБНОВЛЕНИЕ 1:. Благодаря ответу @sanityinc ниже я запустил профилирование ELP, и это то, что я получил (для очень маленького файла 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: виновник обнаружен!, который, по существу, предполагает начало 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
Это вызывает 2 вопроса:
- Что в комбинации 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
Вы можете сказать разницу?:)
Git в Emacs теперь быстрее, но он все еще намного медленнее CVS под Emacs. Поэтому я понятия не имею, почему git называется "Система управления быстрой версией". Это может быть лучше CVS, но быстрее?
Ответы
Ответ 1
Есть встроенный профайлер под названием ELP. Вы можете попробовать что-то вроде M-x elp-instrument-package
, ввести "vc", а затем попробовать найти файл. Затем M-x elp-results
покажет вам отчет о профиле.
(Обратите внимание, что если время вместо этого тратится на функции, не связанные с vc, этот метод не отображает его, но вы можете создавать дополнительные пакеты, если хотите.)
Ответ 2
Вы можете попробовать profile открыть файл, чтобы точно видеть, что занимает так много времени.
Ответ 3
Вы можете отключить vc-mode, установив vc-handled-backends
в nil
в .emacs
.
Ответ 4
У меня была та же проблема с использованием окон git 2.10 из mingw emacs 25.1.1.
Для проверки выполните следующее:
(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