Published: Mon 28 September 2015
By Ben Sturmfels
In Technology .
tags: coding emacs lisp work
I love that Emacs notices merge conflicts in Bazaar versioned files,
highlighting the differences in green and pink. It's a small thing, but I really
miss this automation for when working with Git — I have to manually type M-x
smerge-mode
.
The feature works by looking for conflict files and markers whenever you open a Bazaar versioned file:
;;; Copied from Emacs 24.3.1: vc/vc-bzr.el.gz:472
( defun vc-bzr-find-file-hook ()
( when ( and buffer-file-name
;; FIXME: We should check that "bzr status" says "conflict".
( file-exists-p ( concat buffer-file-name ".BASE" ))
( file-exists-p ( concat buffer-file-name ".OTHER" ))
( file-exists-p ( concat buffer-file-name ".THIS" ))
;; If "bzr status" says there's a conflict but there are no
;; conflict markers, it's not clear what we should do.
( save-excursion
( goto-char ( point-min ))
( re-search-forward "^<<<<<<< " nil t )))
;; TODO: the merge algorithm used in `bzr merge' is nicely configurable,
;; but the one in `bzr pull' isn't, so it would be good to provide an
;; elisp function to remerge from the .BASE/OTHER/THIS files.
( smerge-start-session )
( add-hook 'after-save-hook 'vc-bzr-resolve-when-done nil t )
( message "There are unresolved conflicts in this file" )))
The above looks a little complicated, but the important part is the line
(smerge-start-session)
. This starts smerge-mode
to highlight merge
conflicts.
Let's do something similar with Git by defining a function
vc-git-find-file-hook
:
( defun vc-git-find-file-hook ()
( when ( save-excursion
( goto-char ( point-min ))
( re-search-forward "^<<<<<<< " nil t ))
( smerge-start-session )))
Emacs vc-mode
has a standard interface for version control systems, so simply
defining this function is all we need to do. Emacs will look for and run the
function if it exists (it doesn't by default).
Similar to the Bazaar version, this function looks for conflict marker text in the file, and starts smerge-mode
if it finds any. The Git version is shorter because Git deals with conflicts differently, and also because I haven't hit any edge cases… yet.