Undoing and redoing are operations so common while editing files that we don’t think about them much. Most software however have a poor undo/redo system in which edits get lost all the time.
Emacs’ undos never loses edits and undo-tree brings a wonderful undo/redo system to it.
Undo systems
Linear systems: classic undo/redo
You have some file:
You make some edit:
You make another edit:
And another one:
You can undo:
You can undo some more:
You can also redo:
Now, you make some new edit. From this point on, some edits are lost:
You can still undo:
And you can redo your last undo, but you can’t access all previous states of the file:
Linear systems: Emacs
You have some file:
You make some edit:
You make another edit:
And another one:
The first undo adds a new point to the chain of edits, reversing the effects of the last edit:
More undoing keeps adding points to the chain:
There is no proper redo. Instead, you stop undoing, then start again to undo the undo:
You can make new edits
Nothing ever gets lost, but you might get headaches. For instance, to go back to the beginning, you have to do:
Nothing ever gets lost and it is a lot more sane to navigate the history.
To to back to the beginning, you only have to do:
Compare this with the insane Emacs default system:
And this is an exceedingly simple example only involving 5 different file states. I let you imagine how it quickly explodes in complexity in real life situations 🙂
Now, the default Emacs system has the huge benefit to never lose any edit. It is already a huge improvement over the default system on most software! The thing is that when we undo and redo changes, linear systems are not ideal. A tree structure that can be fully navigated is just a more sensible solution.
Undo-tree was initially developed for Vim, so Vim can also use an ideal undo/redo system.
Installing and customizing undo-tree
This is a personal affair.
The minimal configuration when using straight (to download the package) and use-package to load it and customize it, looks like this:
(use-package undo-tree :straight t)
My personal configuration looks like this:
(use-package undo-tree :straight t :init (global-undo-tree-mode 1) :bind (("C-l" . undo-tree-undo) ("C-r" . undo-tree-redo) ("s-t" . undo-tree-visualize) :map undo-tree-visualizer-mode-map;; go to selected undo state ("<return>" . undo-tree-visualizer-quit);; cancel (return to state before calling undo-tree-visualize) ("q" . undo-tree-visualizer-abort)))