I often see people recommend the command pattern for implementing undo/redo in, say, a level editor. While it sure works, it’s a lot of code and a lot of work. Some ten years ago I came across an idea that I have used ever since, that is super easy to implement and has worked like a charm for all my projects so far.
Every level editor already has the functionality to serialize the level state (and save it to disk). It also has the ability to load a previously saved state, and the idea is to simply use those to implement undo/redo. I create a stack of memory buffers and serialize the entire level into that after each action is completed. Undo is implemented by walking one step up the stack and load that state. Redo is implemented in the same way by walking a step down the stack and load.
This obviously doesn’t work for something like photoshop unless you have terabytes of memory laying around, but in my experience the level information is usually relatively compact and serializes fast, since heavy objects like textures and models are only referenced. If you are worried about memory consumption, you can also just save each serialized state to a temporary folder on disk instead.
The one problem I came across with this approach is that editor specific state, like which object is selected might be forgotten after undo if you use pointers, but I have solved that by handling selection with object id’s rather than pointers.