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:
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.
Plan 9
(Update: 6/6/2026) In Plan 9, mgit is available as a Javascript command which can be run via QuickJS.
Code: https://gitlab.com/atamariya/qjs/-/blob/js/mgit.js
Notes:
- Some git features are only available in my fork of Plan 9 https://gitlab.com/atamariya/plan9front.git .
- Processes running git/fs are likely to have differing views of the repository. e.g. a child process switching branch will make the parent process see the worktree as dirty.
- In Plan 9 git, working with multiple remotes is not supported.
- git/query -c c1:c2 returns a list of files changed between the two commits c1 and c2. It uses file hash for comparison.
git/branch -n br
# New branch from commit
git/branch -n -b commit br
git/add file
# Remove file (both are equivalent)
git/add -r file
git/rm file
# Diff worktree against staging
git/diff
# List changed files
git/diff -n
# Diff staging against HEAD
git/diff -s
# List changed files
git/diff -ns
# Patch worktree (-r for reverse)
git/patch patch
# Patch staging (-r for reverse)
git/patch -s patch
# Commit to HEAD
git/commit -m 'commit message'
git/stash
# Stash list
git/stash -l
# Stash pop (apply recent stash to worktree and drop the same)
git/stash -p
# Stash apply
git/stash -a n
Gitlab
If you manage multiple repositories in Gitlab, it might be easier to set up SSH keys rather than manage per-project based access tokens.
Plan 9: Generate keypair and load private key in factotum.
cat key >/mnt/factotum/ctl
Register the public key with GitLab. Avatar → Edit profile → SSH Keys (left sidebar) → Add new key → paste the rsa2ssh output, give it a name and save.
If you already have a cloned repository, change the URL in .git/config as follows:
url = git@gitlab.com:username/yourproject.git
Lessons learnt
- 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.
- Performance bottleneck is not the number of files edited but the size of the repository (number of files in the repository).
- Stash saves the HEAD commit with the changes. This is used as the base for a three-way merge with the stash and the worktree.
Code (Work In Progress)
https://gitlab.com/atamariya/emacs/-/blob/mgit/lisp/vc/mgit.el
Patches for Magit
(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)))
(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
Post a Comment