Text editors use persistent structures for undo/redo:
class Editor:
versions: list of document states
current: int // current version index
function edit(operation)
// Discard future versions (can't redo after new edit)
versions := versions[0..current + 1]
newDoc := apply(operation, versions[current])
versions.append(newDoc)
current := current + 1
function undo()
if current > 0 then
current := current - 1
function redo()
if current < len(versions) - 1 then
current := current + 1
With persistent structures, "discard future versions" is optional. You can keep all branches.