UndoTree

About

Emacs’s undo system allows you to recover any past state of a buffer. To do this, Emacs treats “undo” itself as just another editing action that can be undone. This can be confusing and difficult to use. If you make an edit while undoing multiple changes, you “break the undo chain”. To get back to where you were, you have to undo all the undos you just did, then undo all the changes you’d already undone before. Only then can you continue undoing from where you left off. If this sounds confusing, it’s because it is! Hence, a number of packages exist that replace it with the undo/redo system (see CategoryUndo).

Instead of treating undo/redo as a linear sequence of changes, undo-tree-mode treats undo history as a branching tree of changes, similar to the way Vim handles it. This makes it substantially easier to undo and redo any change, while preserving the entire history of past states. The undo-tree visualizer is particularly helpful in complex cases. An added side bonus is that undo history can in some cases be stored more efficiently, allowing more changes to accumulate before Emacs starts discarding history. Undo history can be saved persistently across sessions with Emacs 24.3 and later. It also sports various other nifty features: storing and restoring past buffer states in registers, a diff view of the changes that will be made by undoing, and probably more besides.

For more information, see the Commentary at the top of the undo-tree.el file. (http://www.dr-qubit.org/undo-tree/undo-tree.txt)

Downloading

The undo-tree package is available from GNU ELPA in recent Emacsen, and in el-get. You can install it with ‘M-x install-package undo-tree’. The latest “stable” version (version 0.8.1, released February 2021) can also be downloaded from:

If you want to live on the bleeding edge, the latest “development” version can be found in a git repository located at:

To enable it, add it to your LoadPath (if necessary), then add the following to your InitFile:

   (global-undo-tree-mode)

Customizing undo-tree

Here are a few options you may want to investigate:

See ‘M-x customize-group undo-tree’ for more options.

Contributing

Please send bug reports and suggestions to toby-undo-tree@dr-qubit.org (you can post them here as well if you like, of course). I don’t check this page regularly, so anything not emailed to me is likely to languish here unnoticed for some time.

If you have code you would like to contribute to undo-tree, either send a patch against the latest development version to toby-undo-tree@dr-qubit.org, or better still, use git, rebase your work against the latest git master, and let me know where to find your clone of the undo-tree repository so that I can pull your changes.

TobyCubitt

Screenshot

Showing the undo-tree visualizer, with some undo states stored in registers, and the visualizer’s diff view:

UndoTreeScreenshot

Playing nicely with linum

I use linum and I was experiencing glitches with line numbers when I tried to jump from one buffer state to another with undo tree. The line numbers may had become scrambled, missing or incorrect. I’ve solved the issue like this:

(defun undo-tree-visualizer-update-linum (&rest args)
    (linum-update undo-tree-visualizer-parent-buffer))
(advice-add 'undo-tree-visualize-undo :after #'undo-tree-visualizer-update-linum)
(advice-add 'undo-tree-visualize-redo :after #'undo-tree-visualizer-update-linum)
(advice-add 'undo-tree-visualize-undo-to-x :after #'undo-tree-visualizer-update-linum)
(advice-add 'undo-tree-visualize-redo-to-x :after #'undo-tree-visualizer-update-linum)
(advice-add 'undo-tree-visualizer-mouse-set :after #'undo-tree-visualizer-update-linum)
(advice-add 'undo-tree-visualizer-set :after #'undo-tree-visualizer-update-linum)

Wouldn’t it be nice to have something like “after buffer state changed” hook here? Dear author, if you’re reading this, please consider making use of hooks in the future release. Thanks.

What’s wrong with the standard `after-change-functions` hook? Doesn’t it work?

(BTW, if you want a timely response from the package author, I strongly recommend emailing him rather than writing something on EmacsWiki. I hear he doesn’t spend his time polling EmacsWiki just in case someone writes something about one of his packages. Or stackexchange. Or comments on github clones of his repos he doesn’t even know about. Or reddit. Or any other random web sites. I have this on fairly good authority 😊)

--TobyCubitt


CategoryUndo