       newText: change.newText
     })
 
-  changes
+  {
+    type: 'transaction',
+    changes,
+    markersBefore: transaction.markerSnapshotBefore
+    markersAfter: transaction.markerSnapshotAfter
+  }
+
+transactionFromSnapshot = ({changes, markersBefore, markersAfter}) ->
+  patch = new Patch
+  for {oldStart, oldEnd, oldText, newStart, newEnd, newText} in changes by -1
+    oldExtent = traversal(oldEnd, oldStart)
+    newExtent = traversal(newEnd, newStart)
+    patch.splice(oldStart, oldExtent, newExtent, oldText, newText)
+
+  # TODO: Return raw patch if there's no markersBefore && markersAfter
+  new Transaction(markersBefore, patch, markersAfter)

      layers[id] = snapshot
    layers

getCheckpointSnapshot = (checkpoint) ->
  {
    type: 'checkpoint',
    id: checkpoint.id,

    for entry in @undoStack by -1
      switch entry.constructor
        when Checkpoint
          undoStack.unshift(snapshotFromCheckpoint(entry))
        when Transaction
          undoStack.unshift(snapshotFromTransaction(entry))
          undoStackPatches.unshift(entry.patch)

      break if undoStack.length is maxEntries
