Meta git (mgit)

 


Meta git (mgit) is a wrapper around magit, which is a wrapper around git.

If the output looks familiar, it's because it's the output from command git status -v. For the discerning eye, it uses the font-lock defaults from diff mode (notice the highlight on ;;). diff-mode uses repeated diff commands to highlight the refinements. Use diff-mode or diff-refine-hunk if you must have the eye-candy.


Motivation

Magit is a handy tool for working with git repository in GNU Emacs. However, if you work with a large enough repository, you'll hit a performance road-block. Here's an attempt to deconstruct the problem and find a solution.

Magit provides an information rich dashboard for git status. However, this comes with multiple calls to git command. If you run M-x magit-toggle-verbose-refresh and then run magit-status, you'll see the following output:

Refreshing buffer ‘magit: src<anand>’...
  magit-insert-error-header                          2.031e-06
  magit-insert-diff-filter-header                    3.0799e-05
  magit-insert-head-branch-header                    0.004475604
  magit-insert-upstream-branch-header                0.005282276
  magit-insert-push-branch-header                    3.5114e-05
  magit-insert-tags-header                           0.008421254
  magit-insert-status-headers                        0.021357499 !
  magit-insert-merge-log                             0.001540241
  magit-insert-rebase-sequence                       0.000193708
  magit-insert-am-sequence                           0.000190186
  magit-insert-sequencer-sequence                    0.000405629
  magit-insert-bisect-output                         0.000159796
  magit-insert-bisect-rest                           4.9848e-05
  magit-insert-bisect-log                            7.4688e-05
  magit-insert-untracked-files                       4.554816041 !!
  magit-insert-unstaged-changes                      3.27816181 !!
  magit-insert-staged-changes                        0.033723897 !!
  magit-insert-stashes                               0.009674576
  magit-insert-unpushed-to-pushremote                4.0493e-05
  magit-insert-unpushed-to-upstream-or-recent        0.014408128 !
  magit-insert-unpulled-from-pushremote              3.31e-06
  magit-insert-unpulled-from-upstream                0.004328423
Refreshing buffer ‘magit: src<anand>’...done (13.270s) 
 

In comparison, the output from git status -v provides pertinent information (see screenshot) in around 3-4s.


Lessons learnt

  1. Most git commands are fast except the ones which operate on tree level information. However, magit operations seem slower because of the refresh problem - it needs to refresh the complete dashboard.
  2. Performance bottleneck is not the number of files edited but the size of the repository (number of files in the repository).
     

Code (Work In Progress)

https://gitlab.com/atamariya/emacs/-/blob/mgit/lisp/vc/mgit.el

Patches for Magit

You need to apply following patches to magit files:
 
modified magit-diff.el
@@ -2324,6  +2327,11 @@
       (when orig
         (setq orig (magit-decode-git-path orig)))
-      (setq file (magit-decode-git-path file))
-      (setq header (nreverse header))
-      ;; KLUDGE `git-log' ignores `--no-prefix' when `-L' is used.
-      (when (and (derived-mode-p 'magit-log-mode)
-                 (seq-some (lambda (arg) (string-prefix-p "-L" arg))
-                           magit-buffer-log-args))
+      (when file
+    (setq file (magit-decode-git-path file)))
+      ;; KLUDGE `git-diff' ignores `--no-prefix' for new files and renames at
+      ;; least.  And `git-log' ignores `--no-prefix' when `-L' is used.
+      (when (or (and file (string-prefix-p "b/" file))
+        (and orig (string-prefix-p "a/" orig))
+                (and (derived-mode-p 'magit-log-mode)
+                     (--first (string-prefix-p "-L" it)
+                              magit-buffer-log-args)))
+        (when file
+      (setq file (substring file 2))) 
@@ -2341,5  +2327,8 @@
 (defun magit-diff-insert-file-section
    (file orig status modes rename header &optional long-status)
   (magit-insert-section section
-    (file file (or (equal status "deleted")
-                   (derived-mode-p 'magit-status-mode)))
+    (file (or file orig)
+      (or (equal status "deleted")
+              (derived-mode-p 'magit-status-mode)))
     (insert (propertize (format "%-10s %s" status
-                                (if (or (not orig) (equal orig file))
-                                    file
-                                  (format "%s -> %s" orig file)))
+                                (if (and orig file)
+                    (if (equal orig file)
+                    file
+                                      (format "%s -> %s" orig file))
+                  (or orig file)))
                         'font-lock-face 'magit-diff-file-heading))
 
 

 

Comments

Popular posts from this blog

GNU Emacs as a Comic Book Reader

Tinylisp and Multi-threaded Emacs

Data Visualization with GNU Emacs