Make Emacs faster than Vim in "git mergetool"

  |   Source

My article Emacs is the best merge tool for Git explains how to combine git mergetool with ediff-mode in Emacs.

Harrison McCullough suggested the work flow can be faster if emacs is replaced with emacsclient.

I did some research and found a perfect solution. It's even faster than Vim.

Initial solution

Please note emacsclient is only use for resolving conflicts.

Step 1, start emacs server by running emacs -Q --daemon --eval "(setq startup-now t)" -l "/home/my-username/.emacs.d/init.el" --eval "(progn (require 'server) (server-start))" in shell.

Step 2, insert below code into ~/.emacs.d/init.el (see the comment why this advice is required):

(defadvice server-save-buffers-kill-terminal (after server-save-buffers-kill-terminal-after-hack activate)
  ;; kill all buffers, so new ediff panel is re-created and `ediff-startup-hook-setup' is called again
  ;; besides, remove the buffers whose binding files are alredy merged in `buffer-list'
  (mapc 'kill-buffer (buffer-list)))

Step 3, insert below code into ~/.gitconfig:

cmd = emacsclient -nw --eval \"(progn (setq ediff-quit-hook 'kill-emacs) (if (file-readable-p \\\"$BASE\\\") (ediff-merge-files-with-ancestor \\\"$LOCAL\\\" \\\"$REMOTE\\\" \\\"$BASE\\\" nil \\\"$MERGED\\\") (ediff-merge-files \\\"$LOCAL\\\" \\\"$REMOTE\\\" nil \\\"$MERGED\\\")))\"

My real world solution

It's similar to initial solution. But some scripts are created for automation.

Step 1, read Using Emacs as a Server in the manual and create ~/.config/systemd/user/emacs.service for Systemd:

Description=Emacs text editor
Documentation=info:emacs man:emacs(1)

ExecStart=emacs -Q --daemon --eval "(setq startup-now t)" -l "/home/my-username/.emacs.d/init.el" --eval "(progn (require 'server) (server-start))" 
ExecStop=emacsclient --eval "(kill-emacs)"


Step 2, set up in ~/.gitconfig:

    cmd = "$LOCAL" "$REMOTE" "$BASE" "$MERGED"
    cmd = MYEMACSCLIENT=emacsclient "$LOCAL" "$REMOTE" "$BASE" "$MERGED"

Step 3, create

# emacsclient won't work in git mergetool
# $1=$LOCAL $2=$REMOTE $3=$BASE $4=$MERGED
if [ "$MYEMACSCLIENT" = "emacs" ]; then
    $MYEMACSCLIENT -nw -Q --eval "(setq startup-now t)" -l "$HOME/.emacs.d/init.el" --eval "(progn (setq ediff-quit-hook 'kill-emacs) (if (file-readable-p \"$3\") (ediff-merge-files-with-ancestor \"$1\" \"$2\" \"$3\" nil \"$4\") (ediff-merge-files \"$1\" \"$2\" nil \"$4\")))"
    $MYEMACSCLIENT -nw --eval "(progn (setq ediff-quit-hook 'kill-emacs) (if (file-readable-p \"$3\") (ediff-merge-files-with-ancestor \"$1\" \"$2\" \"$3\" nil \"$4\") (ediff-merge-files \"$1\" \"$2\" nil \"$4\")))"

Step 4, run git mergetool -t emacsclient to resolve conflicts.

My init-ediff.el in emacs.d.

Comments powered by Disqus