UndoCommands

Undo changes in Emacs with ‘C-/’, ‘C-x u’ or `C-_’.

Quoting the EmacsManual,

Consecutive repetitions of ‘C-/’ (or its aliases) undo earlier and earlier changes in the current buffer. If all the recorded changes have already been undone, the undo command signals an error.
Any command other than an undo command breaks the sequence of undo commands. Starting from that moment, the entire sequence of undo commands that you have just performed are themselves placed into the undo record, as a single set of changes. Therefore, to re-apply changes you have undone, type ‘C-f’ or any other command that harmlessly breaks the sequence of undoing; then type ‘C-/’ to undo the undo command.
On the other hand, if you want to resume undoing, without redoing previous undo commands, use ‘M-x undo-only’. This is like ‘undo’, but will not redo changes you have just undone.

When there is an active region, SelectiveUndo is performed on the region.

By default, Emacs keeps only a few dozen undo entries. You can control how many it keeps by customizing option ‘undo-limit’.

Undo Command Bindings

Having once undone a change with ‘C-x u’ or `C-_’ or ‘C-/’, you can repeat the undo command by pressing ‘C-x z’, which is ‘repeat’. So the overall sequence of ‘C-x u C-x z z z z z’ undoes changes back through time, and may be easier to type than `C-_ C-_ …’.

Binding undo to ‘C-z’ makes it easier to use (and the command ‘suspend-frame’ is still available on ‘C-x C-z’).

(global-unset-key "\C-z")
(global-set-key "\C-z" 'advertised-undo)

Different Undo Commands

UndoFu

Is a thin-convenience wrapper, adding undo/redo functionality over emacs built-in undo.

The UndoFu package does this without intrusive hooks or undo history manipulation which can be error prone.

UndoTree

Some people have trouble with the lack of redo or a way to browse the undo tree. There is no built-in way to do these things (aside from mentally trying to keep track of a long string of changes including undos, which some people find very difficult). The UndoTree package solves this issue nicely.

Undo Everything

Here’s a command that will do all the possible undo actions available in the buffer. Use it by EvaluatingExpressions or adding it to your InitFile.

(defun undo-all ()
  "Undo all edits."
  (interactive)
  (when (listp pending-undo-list)
    (undo))
  (while (listp pending-undo-list)
    (undo-more 1))
  (message "Buffer was completely undone"))

See also RevertBuffer.

Tempory changes that are undone at once

Sometimes you want to change a buffer briefly, then change it back. Perhaps like momentary-string-display or PopupRuler where you don’t want the user’s undo list affected.

(defmacro temporary-invisible-change (&rest forms)
  "Executes FORMS with a temporary buffer-undo-list, undoing on return.
The changes you make within FORMS are undone before returning.
But more importantly, the buffer's buffer-undo-list is not affected.
This allows you to temporarily modify read-only buffers too."
  `(let* ((buffer-undo-list)
          (modified (buffer-modified-p))
          (inhibit-read-only t))
     (save-excursion
       (unwind-protect
           (progn ,@forms)
         (primitive-undo (length buffer-undo-list) buffer-undo-list)
         (set-buffer-modified-p modified)))
     nil))

You would use this either with some kind of delay or read-event so a user sees what happened, or for operations like inserting form feed characters in before printing but having them removed again without a trace afterwords.

    (temporary-invisible-change
     (insert "try this")
     (forward-line)
     (insert "try that")
     (read-key-sequence-vector "Any event:"))

CategoryUndo