Some days ago I briefly wrote about my willingness to give Emacs built-in VC system a try for real. For real means that it’s easy to praise the beauties of vc-git when working on personal projects such as this blog, but is VC actually worth it on bigger projects where different people commit and push regularly, rebasing is a habit, and merge conflicts are unavoidable necessities?

A warning first. This article is not intended as a VC tutorial. It aims to be an example of how I use it or, to phrase it better, how I started to use it. As Mickey Petersen suggests in the “Exploring Emacs” section of his great Mastering Emacs book, if you want to know more about VC there is plenty of information right within our favourite text editor. Furthermore, Protesilaos Stavrou has a couple of nice videos on VC you might want to check out: Introduction to VC and Workflow with VC for Git.

Now, let’s break down a common workflow of mine:

  • A new ticket is assigned to me
  • I create a new branch for this ticket, starting from the master one
  • I code my thing
  • I commit and push my code
  • I file a new merge request ready to be reviewed
  • The review may require changes to my code
  • I may need to rebase my changes onto master because other developers have merged their branches before me
  • Merge conflicts may arise and need to be fixed
  • I push my updated code ready to be reviewed again
  • If everything’s fine I merge my changes, otherwise back to my edit/rebase/merge process until it’s properly done
  • Meanwhile, it may happen that I need to stash my changes and quickly fix a higher priority bug

This more or less happens on a daily basis, so the interaction with Git (the only VCS I have used in the last ten years) must be smooth. On the other hand, Git-wise the above workflow is not that complicated. For instance, I rarely use features such as cherry-picking or bisecting.

On the surface, the main difference between Magit and VC is transient. Magit transient menus make all the operations I described above1 a breeze. From checking out a branch to interactive rebasing, Magit requires few key strokes to accommodate my needs. The blatant truth is that Magit wraps everything I want from Git and much more in a user interface that just works.

VC, however, is not tightly coupled to Git, so it does not cover all of its many options. And yet I was able to manage my work projects with VC alternatives to Magit commands.

Operation VC Magit
Project status project-vc-dir magit-status
Pull vc-update magit-pull
New branch vc-retrieve-tag magit-branch
Commit vc-next-action magit-commit
Rebase shell-command + git rebase master magit-rebase
Push vc-push magit-push
Stash mu-vc-git-stash magit-stash
Log vc-print-root-log magit-log

VC has its own vc-git-stash, vc-git-stash-pop, and vc-git-stash-delete commands, but instead of calling them via M-x I devised mu-vc-git-stash and bound it to z in vc-dir-mode-map:

(defun mu-vc-git-stash (pop-or-delete)
  "Create, pop, or delete Git stashes.
With no POP-OR-DELETE call `vc-git-stash'. With one prefix
argument call `vc-git-stash-pop'. With two prefix arguments call
`vc-git-stash-delete'."
  (interactive "P" vc-dir-mode)
  (cond ((= (prefix-numeric-value pop-or-delete) 4)
         (call-interactively #'vc-git-stash-pop))
        ((= (prefix-numeric-value pop-or-delete) 16)
         (call-interactively #'vc-git-stash-delete))
        (t (call-interactively #'vc-git-stash))))

As you can see, C-u z issues vc-git-stash-pop while C-u C-u z runs vc-git-stash-delete.

One thing that Magit really shines at for me is interactive rebasing (r i ). I haven’t had the opportunity so far to check how I can handle this with VC. I guess a combination of shell-command and something I have yet to discover would do, probably.

Anyway, I’ll keep using VC in the next days and report back if I manage to adapt more of my Git workflows to it. I suspect Magit will outshine the humbler Emacs built-in eventually, but who knows. Reading on the emacs-devel mailing list that some wild Emacs developers prefer VC to Magit seems to confirm that the world is still full of surprises.


  1. Well, only the ones related to Git of course. ↩︎