Make Emacs faster than Vim in "git mergetool"
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
:
[mergetool.ediff]
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:
[Unit]
Description=Emacs text editor
Documentation=info:emacs man:emacs(1) https://gnu.org/software/emacs/
[Service]
Type=forking
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)"
Environment=SSH_AUTH_SOCK=%t/keyring/ssh
Restart=on-failure
[Install]
WantedBy=default.target
Step 2, set up in ~/.gitconfig
:
[mergetool.emacs]
cmd = ediff.sh "$LOCAL" "$REMOTE" "$BASE" "$MERGED"
[mergetool.emacsclient]
cmd = MYEMACSCLIENT=emacsclient ediff.sh "$LOCAL" "$REMOTE" "$BASE" "$MERGED"
Step 3, create ediff.sh
:
#!/bin/sh
[ -z "$MYEMACSCLIENT" ] && MYEMACSCLIENT="emacs"
# 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\")))"
else
$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\")))"
fi
Step 4, run git mergetool -t emacsclient
to resolve conflicts.
My init-ediff.el in emacs.d.