Is it possible to wrap an arbitrary series of operations such that when a single undo command is issued, all of the wrapped operations are undone at once, rather than requiring multiple undos to undo them?

For example, let's say I delete a line, move up two lines, delete another line, move up two more lines, and delete one more line. I'd like to be able to wrap those all those operations somehow so that when a single undo command is issued, all three deleted lines are restored to their proper locations.

Of course, this is just an example, and I'd like to be able to do that for any sequence of operations.

Update: I found an answer here involving with-undo-collapse which worked.

Update 2: The answer linked to above seems to be buggy, and while it does allow me to undo multiple operations in one undo, it sometimes undoes even more than what was wrapped in with-undo-collapse. I'm going to have to try to debug that code to figure out what's going wrong.

Update 3: The buggy code for with-undo-collapse and associated functions from the answer above is impenetrable to me, and I've failed at debugging it. As such, I'm forced to abandon it, as I'd rather have too-granular an undo rather than not-granular-enough. I'll now see if I can further explore Emacs' undo system on my own, using the links and tips provided elsewhere in this thread and maybe come up with my own, working solution.

Update 4: It looks like the simplest and the most bulletproof answer is to just wrap the block in evil-with-single-undo.

  • You probably want to look into adjusting the amalgamation business which is hard-coded to 20 inside simple.el -- see undo-auto-amalgamate. I actually like one undo per keystroke, so I disabled the amalgamation business. It is interest that you describe the current behavior as requiring multiple undos, since it is the exact opposite by default -- i.e., several keystrokes are undone in one fell swoop by default.
    – lawlist
    Commented Sep 12, 2017 at 11:06
  • In addition, there are certain commands that are taken into consideration when using the amalgamation business. You may wish to look into adding new commands that will be considered in that regard. To learn more, type M-x describe-function RET undo-auto-amalgamate RET to read the doc-string.
    – lawlist
    Commented Sep 12, 2017 at 11:35
  • @lawlist - It's not keystrokes that I wish to undo at once but elisp function calls. I have a function of my own that does a number of things, and after I call this function and try to undo it, only part of the things it does are undone. To undo everything it does I have to issue multiple undo commands. I'd like to have a single undo undo everything that function does. I tried putting (undo-auto-amalgamate) before everything my function does internally, but it didn't help.
    – izkon
    Commented Sep 12, 2017 at 13:15

2 Answers 2


You can use function undo-boundary to set your own Undo boundaries. But that just adds another boundary; it does not remove any existing boundaries.

You can use buffer-disable-undo to disable recording of undo information, and then reenable it again using buffer-enable-undo. But disabling drops all recorded undo info for the buffer.

You can also try modifying the undo information directly. It is in variable buffer-undo-list.

See the Elisp manual, nodes Undo and Maintaining Undo.

See also this related StackOverflow Q&A.

Actually, I think this question is a duplicate of this one. I've voted to close this one.

  • Thank you, but buffer-disable-undo followed by buffer-enable-undo did not work for me.
    – izkon
    Commented Sep 12, 2017 at 16:38
  • Did you check the message that (I think) this is a duplicate of?
    – Drew
    Commented Sep 12, 2017 at 17:09
  • I did, and it contained the solution, as I mentioned in the update to my original question above. Thank you.
    – izkon
    Commented Sep 12, 2017 at 18:16
  • Actually, the solution I refer to seems to be buggy (see my 2nd update to the original question above).
    – izkon
    Commented Sep 12, 2017 at 18:30
  • I can find nothing either. buffer-disable-undo eliminates the entire past undo list as well as preventing recording new entries. The question asks to be able to unwind to a previous checkpointed state, essentially amalgamating all undo entries into one. buffer-disable-undo does not do this.
    – jennykwan
    Commented Oct 15, 2018 at 15:40

You may be looking for C-hf atomic-change-group

atomic-change-group is a Lisp macro in ‘subr.el’.

(atomic-change-group &rest BODY)

Perform BODY as an atomic change group.
This means that if BODY exits abnormally,
all of its changes to the current buffer are undone.
This works regardless of whether undo is enabled in the buffer.

This mechanism is transparent to ordinary use of undo;
if undo is enabled in the buffer and BODY succeeds, the
user can undo the change normally.
  • Thank you, but atomic-change-group did not work for me.
    – izkon
    Commented Sep 12, 2017 at 16:39
  • Explaining how it did not work would be helpful for those coming after you. atomic-change-group does however many undo's necessary to return to the buffer state upon entering the block, in the case of an abend. That's not what the question is asking. If the block succeeds, atomic-change-group does not amalgamate the undo entries generated by the block so that a single undo entry undoes them all at once.
    – jennykwan
    Commented Oct 15, 2018 at 15:47

Not the answer you're looking for? Browse other questions tagged or ask your own question.