The following is a proto-type implementation of an approximation of what you want. It exploits the fact that new branches in the undo-tree are added at the left-hand side of the current node.
The key-sequence C-M-_ is bound to undo-tree-walk
which walks the right-upper part of the undo tree starting at the current node.
The behavior differs from what you want if the active branch of some sub-tree on the right-hand side of the current node is not the left-most branch in that sub-tree.
You can get in such a state by non-trival undo/redo-sequences.
Just try it for yourself to see whether that is sufficient for your application.
(defvar-local undo-tree-walk
"Possible values:
nil: not in undo/redo-chain
undo: traversing undo tree upwards
redo: traversing undo tree downwards
")
(setq undo-tree-walk nil)
(defun undo-tree-walk ()
"Walk the right-upper part of the undo-tree starting at the current node."
(interactive)
(set-transient-map undo-tree-walk-map t #'undo-tree-walk-off)
(let ((num-branches (undo-tree-num-branches)))
(cond
((= num-branches 0) ; arrived at leaf
(setq undo-tree-walk 'undo))
((> num-branches 1) ;
(let ((branch (undo-tree-node-branch (undo-tree-current buffer-undo-tree))))
(setf (undo-tree-node-branch (undo-tree-current buffer-undo-tree))
(if (>= (1+ branch) (undo-tree-num-branches))
(progn
(setq undo-tree-walk 'undo)
(1- (undo-tree-num-branches)))
(setq undo-tree-walk 'redo)
(1+ branch))))
;; no state change for (= num-branches 1)
)
))
(case undo-tree-walk
(undo
(undo-tree-undo-1))
(redo
(undo-tree-redo-1))
(t
(setq undo-tree-walk 'undo)
(undo-tree-undo-1)))
(let ((curbuf (current-buffer)))
(undo-tree-visualize)
(switch-to-buffer-other-window curbuf)))
(defun undo-tree-walk-off ()
"Switch `undo-tree-walk' off."
(setq undo-tree-walk nil))
(defvar undo-tree-walk-map
(make-sparse-keymap)
"Keymap active while `undo-tree-walk'.")
(define-key undo-tree-walk-map (kbd "C-M-_") #'undo-tree-walk)
(global-set-key (kbd "C-M-_") #'undo-tree-walk)
Note, that I added undo-tree-visualize
to the end of undo-tree-walk
to display the consequences of walking the undo-tree with undo-tree-walk
.
Feel free to modify the code to your likings.
Note also, that I had to choose this most simple approximation of a solution for your problem because of time-restrictions.