18

I am forced to use Windows 10 for a project. Yes, I would rather use GNU/Linux. To keep my sanity, I've tried to regard Windows as a bootloader for Emacs :)

Unfortunately, Magit (one of my favorite parts of Emacs, which also makes up for the lack of a good command line on Windows) is unbearably slow. I have an SSD, 16 GB of RAM and a quad-core i7 but it takes eight seconds to execute magit-status on a small repository. Then, when I want to stage another change, it takes about 5 seconds per file.

Here's what I've tried:

  • $ git config --global core.preloadindex true
  • $ git config --global core.fscache true
  • $ git config --global gc.auto 256
  • Adding the entire project to the Windows Defender (my only AV) exclusion list
  • Setting the magit-git-executable to the regular msysgit one I downloaded (https://git-for-windows.github.io/). I checked and git status here takes < 1 second. I know that magit-status does way more, but this is too much.

Can anyone suggest ways to make this faster? I can't imagine anyone using Magit on Windows like this.

It was suggested that this question is a duplicate, but they asked:

I'm struggling to understand why Emacs have noticeably shorter startup time on Ubuntu than Windows. Anyone knows the answer?

I know at least some reasons why Emacs, Git, and Magit are slower on Windows. I am asking how do I optimize Magit to do fewer things, or cache results, or something, even if it's at the expense of functionality.

11
  • git-status takes <1 second? It should be essentially instantaneous. Is there any perceptible delay at all?
    – PythonNut
    Jan 11, 2016 at 16:32
  • Do you have the same issues running the equivalent git commands from the command line?
    – elethan
    Jan 11, 2016 at 16:50
  • I think magit's default choice for magit-git-executable will probably be a bit faster (the ones in cmd and bin are actually wrappers, if executable-find returns one of them magit will attempt to set magit-git-executable to the "real" git). 8 seconds for a small repository sounds like something else is wrong though, takes ~0.8s for magit's repo here (Windows 8).
    – npostavs
    Jan 11, 2016 at 16:52
  • Possible duplicate of Why does Emacs take longer to start on Windows than on Linux?
    – nanny
    Jan 11, 2016 at 17:24
  • 1
    Also, for a more accurate time, you could set magit-refresh-verbose to t.
    – nanny
    Jan 11, 2016 at 17:32

3 Answers 3

13

I have actually done rather a lot of research on this and fundamentally the problem is that git for windows sucks

This is the upstream bug: https://github.com/git-for-windows/git/issues/596 and it requires somebody to rewrite shell scripts in C so that there is no more command forking. For me, its the interactive rebase that is the real killer (I can kick off an interactive rebase, go make tea, come back, read some news, drink the tea, and then maybe it's finished. It's much worse than a lot of people think it is), but general status-like calls are also enough to interrupt the work stride.

An alternative might be to update jGit to support the commands that magit uses, and then run it in nailgun to reduce the JVM startup time, I started a thread to discuss this: http://dev.eclipse.org/mhonarc/lists/jgit-dev/msg03064.html

You might want to read https://stackoverflow.com/questions/4485059 for some potential speedups, but honestly you'll barely notice them.

Something you can do in magit is to follow the author's advice in setting up a minimal magit-status just for staging

;; WORKAROUND https://github.com/magit/magit/issues/2395
(define-derived-mode magit-staging-mode magit-status-mode "Magit staging"
  "Mode for showing staged and unstaged changes."
  :group 'magit-status)
(defun magit-staging-refresh-buffer ()
  (magit-insert-section (status)
    (magit-insert-untracked-files)
    (magit-insert-unstaged-changes)
    (magit-insert-staged-changes)))
(defun magit-staging ()
  (interactive)
  (magit-mode-setup #'magit-staging-mode))

so, do you know any experienced C or Java developers who'd be able to help with either of the solutions to fix git or jGit?

6
  • I'm not so sure the problem is shell scripts vs. C, because magit-status takes a really long time as well, and I don't think status uses many of the shell scripts.
    – nanny
    Jan 14, 2016 at 16:39
  • 1
    And thank you for that "minimal" magit-status code, it seem to help me a bit (it cuts my magit-refresh time down to 2-3 seconds).
    – nanny
    Jan 14, 2016 at 17:05
  • This is exactly what I want. Thanks!
    – Hut8
    Jan 14, 2016 at 17:16
  • 1
    yup, magit-staging takes a couple of seconds for me too. Enough to interrupt my thinking, but not enough to destroy my day.
    – fommil
    Jan 14, 2016 at 22:44
  • 2
    the reason why magit-status is slow is because it calls out to git maybe 10 or 20 times. Starting new processes on Windows is extremely slow compared to GNU platforms. The shell scripts are an extreme case of this (because pretty much every statement is a new process)
    – fommil
    Jan 14, 2016 at 22:45
2

Having recently looked at the a list of call-process calls from magit-status for another reason, it occured to me that some of them can be cached. With the following advice magit-status on Magit's repo goes from 1.9 to 1.3 seconds (my previous measurement of 0.8s mentioned in the comments was for a different (faster) computer). If you are already using magit-staging from the other answer it's probably not going to help much: I saw a reduction from 0.16 to 0.12 seconds (but that's barely larger than measurement noise).

WARNING: This doesn't take care of updating the cache, so things may go wrong (especially if you are fiddling with your git configuration).

(defvar-local magit-git--git-dir-cache nil)
(defvar-local magit-git--toplevel-cache nil)
(defvar-local magit-git--cdup-cache nil)

(defun memoize-rev-parse (fun &rest args)
  (pcase (car args)
    ("--git-dir"
     (unless magit-git--git-dir-cache
       (setq magit-git--git-dir-cache (apply fun args)))
     magit-git--git-dir-cache)
    ("--show-toplevel"
     (unless magit-git--toplevel-cache
       (setq magit-git--toplevel-cache (apply fun args)))
     magit-git--toplevel-cache)
    ("--show-cdup"
     (let ((cdup (assoc default-directory magit-git--cdup-cache)))
       (unless cdup
         (setq cdup (cons default-directory (apply fun args)))
         (push cdup magit-git--cdup-cache))
       (cdr cdup)))
    (_ (apply fun args))))

(advice-add 'magit-rev-parse-safe :around #'memoize-rev-parse)

(defvar-local magit-git--config-cache (make-hash-table :test 'equal))

(defun memoize-git-config (fun &rest keys)
  (let ((val (gethash keys magit-git--config-cache :nil)))
    (when (eq val :nil)
      (setq val (puthash keys (apply fun keys) magit-git--config-cache)))
    val))

(advice-add 'magit-get :around #'memoize-git-config)
(advice-add 'magit-get-boolean :around #'memoize-git-config)
2
  • why don't you just use the melpa.org/#/memoize package?
    – fommil
    Jan 15, 2016 at 10:18
  • 1
    @fommil: I needed to memoize rev-parse per buffer for some args. I couldn't see a way to do so after a cursory look at the memoize package. Also it says it can't handle memoizing nil.
    – npostavs
    Jan 15, 2016 at 15:00
2

Use Emacs on WSL.

I did an extensive use of magit when I worked on a Linux box.
But was kind of forced to use Windows 10.
I tried to use Magit though I couldn't stand how slow it was.
So I just switched to SublimeMerge for git use.
After one year using it, I haven't looked back.

But since I have tried native Emacs on Windows and Emacs on WSL...
Just made a test to check magit-status on same repo.
I manually started a stopwatch with a hotkey in Windows.
So there is a bit of time gap between when magit-status ends and when the watch stops.

In my case Emacs-on-WSL beats Emacs-on-Windows by ~2 secs vs ~6 secs.
Both tests made starting emacs with emacs -Q.

enter image description here

enter image description here

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.