After Magit has run git
for side-effects, it also refreshes the
current Magit buffer and the respective status buffer. This is
necessary because otherwise outdated information might be displayed
without the user noticing. Magit buffers are updated by recreating
their content from scratch, which makes updating simpler and less
error-prone, but also more costly. Keeping it simple and just
re-creating everything from scratch is an old design decision and
departing from that will require major refactoring.
Meanwhile you can tell Magit to only automatically refresh the current Magit buffer, but not the status buffer. If you do that, then the status buffer is only refreshed automatically if it is the current buffer.
(setq magit-refresh-status-buffer nil)
You should also check whether any third-party packages have added
anything to magit-refresh-buffer-hook
, magit-pre-refresh-hook
, and
magit-post-refresh-hook
. If so, then check whether those additions
impact performance significantly.
Magit can be told to refresh buffers verbosely using M-x
magit-toggle-verbose-refresh
. Enabling this helps figuring out which
sections are bottlenecks. Each line printed to the *Messages*
buffer
contains a section name, the number of seconds it took to show this
section, and from 0 to 2 exclamation marks: the more exclamation marks
the slower the section is.
Magit also reverts buffers for visited files located inside the
current repository when the visited file changes on disk. That is
implemented on top of auto-revert-mode
from the built-in library
autorevert
. To figure out whether that impacts performance, check
whether performance is significantly worse, when many buffers exist
and/or when some buffers visit files using TRAMP. If so, then this
should help.
(setq auto-revert-buffer-list-filter 'magit-auto-revert-repository-buffer-p)
For alternative approaches see Automatic Reverting of File-Visiting Buffers.
If you have enabled any features that are disabled by default, then you should check whether they impact performance significantly. It’s likely that they were not enabled by default because it is known that they reduce performance at least in large repositories.
If performance is only slow inside certain unusually large
repositories, then you might want to disable certain features on a
per-repository or per-repository-class basis only. See
Per-Repository Configuration. For example it takes a long time to
determine the next and current tag in repository with exceptional
numbers of tags. It would therefore be a good idea to disable
magit-insert-tags-headers
, as explained at the mentioned node.
When showing logs, Magit limits the number of commits initially shown
in the hope that this avoids unnecessary work. When --graph
is
used, then this unfortunately does not have the desired effect for
large histories. Junio, Git’s maintainer, said on the Git mailing
list (https://www.spinics.net/lists/git/msg232230.html): "--graph
wants
to compute the whole history and the max-count only affects the output
phase after --graph
does its computation".
In other words, it’s not that Git is slow at outputting the differences, or that Magit is slow at parsing the output - the problem is that Git first goes outside and has a smoke.
We actually work around this issue by limiting the number of commits
not only by using -<N>
but by also using a range. But unfortunately
that’s not always possible.
When more than a few thousand commits are shown, then the use of
--graph
can slow things down.
Using --color --graph
is even slower. Magit uses code that is part of
Emacs to turn control characters into faces. That code is pretty slow
and this is quite noticeable when showing a log with many branches and
merges. For that reason --color
is not enabled by default anymore.
Consider leaving it at that.
If diffs are slow, then consider turning off some optional diff
features by setting all or some of the following variables to nil
:
magit-diff-highlight-indentation
, magit-diff-highlight-trailing
,
magit-diff-paint-whitespace
, magit-diff-highlight-hunk-body
, and
magit-diff-refine-hunk
.
When showing a commit instead of some arbitrary diff, then some
additional information is displayed. Calculating this information
can be quite expensive given certain circumstances. If looking at
a commit using magit-revision-mode
takes considerably more time than
looking at the same commit in magit-diff-mode
, then consider setting
magit-revision-insert-related-refs
to nil
.
When you are often confronted with diffs that contain deleted files,
then you might want to enable the --irreversible-delete
argument. If
you do that then diffs still show that a file was deleted but without
also showing the complete deleted content of the file. This argument
is not available by default, see (transient)Enabling and Disabling Suffixes. Once you have done that you should enable it and save that
setting, see (transient)Saving Values. You should do this in both
the diff (d
) and the diff refresh (D
) transient popups.
When refreshing the "references buffer" is slow, then that’s usually because several hundred refs are being displayed. The best way to address that is to display fewer refs, obviously.
If you are not, or only mildly, interested in seeing the list of tags, then start by not displaying them:
(remove-hook 'magit-refs-sections-hook 'magit-insert-tags)
Then you should also make sure that the listed remote branches
actually all exist. You can do so by pruning branches which no longer
exist using f-pa
.
When you initiate a commit, then Magit by default automatically shows a diff of the changes you are about to commit. For large commits this can take a long time, which is especially distracting when you are committing large amounts of generated data which you don’t actually intend to inspect before committing. This behavior can be turned off using:
(remove-hook 'server-switch-hook 'magit-commit-diff) (remove-hook 'with-editor-filter-visit-hook 'magit-commit-diff)
Then you can type C-c C-d
to show the diff when you actually want to
see it, but only then. Alternatively you can leave the hook alone and
just type C-g
in those cases when it takes too long to generate the
diff. If you do that, then you will end up with a broken diff buffer,
but doing it this way has the advantage that you usually get to see
the diff, which is useful because it increases the odds that you spot
potential issues.