Emacs has an excellent undo system, once you get the hang of it. But as with all things Emacs, it could be better!

(use-package undo-tree
  :ensure t
  :pin elpa
  :diminish undo-tree-mode
  ("C-z" . undo)
  ("M-z" . undo-tree-redo)
  ("C-M-z" . undo-tree-visualize)
  (setq undo-tree-visualizer-diff t))

Let's see how the undo tree looks for this buffer:


As you can see, I've performed several undo and redo operations at this point, and can navigate through them. If I choose any node in the undo tree, I will be presented with an explanatory diff telling me what that node's change represents in a small window.