Releases, revert, and concurrent change sets
Every publish is a numbered release, and reverting one drafts a change set that restores the state before it. Several change sets can hold the same entry, and the ones that lose the race rebase.
Releases
Every publish claims a sequential release number.
$ myna releases list
# TITLE PUBLISHED BY ITEMS STATE
12 Autumn pricing 2026-07-24T09:12:04Z Deploy agent 3 live
11 Fix launch post typo 2026-07-23T16:40:11Z Ana Duarte 1 reverted by #12
myna releases inspect takes a release number or the id of the change set that produced it, and the dashboard lists releases alongside change sets.
Revert
Taking a release back drafts a change set staging the inverse of every item.
$ myna releases revert 11
Created change set chs_01J9... — Revert release #11
OP RESOURCE RESTORES
update posts/launch rev_01J8...
It publishes nothing, so it needs content:write rather than content:publish, and it goes through validation, preview, approvals, and checks like anything written by hand.
Undoing a create unpublishes. Undoing an unpublish or a delete restores the revision that preceded it, copied forward into a new revision.
If a later release already changed one of those resources, the revert is refused and names every superseded resource. --force takes them back anyway.
A published revert is itself a release, so it can be reverted in turn.
Concurrent change sets
An entry can belong to several open change sets. Inside one, an edit builds on what that change set already proposes; a change set that has not touched the entry starts from what is published. With several in flight and no change set named, an edit is refused and lists the candidates.
Rebase
Whichever change set publishes first wins. The rest hold a stale base, and publish refuses it rather than merging.
$ myna changes rebase chs_01... --dry-run
posts/pricing — 2 field(s) replayed, 1 conflict(s)
FIELD MINE THEIRS
title Pricing and plans Plans and pricing
A rebase replays the change set's field-level edits on top of what is published now. Fields the other side did not touch are replayed. Fields where both sides reached the same value are not conflicts. The rest refuse the rebase until you pick a side with --take-mine or --take-theirs.
Granularity comes from the same comparison the diff uses. Nested groups descend, so seo.title and seo.description are independent. Arrays compare whole.
A rebase writes new revisions and moves the items, so approvals go stale and checks re-run.
The conflicts check
A new built-in check reports whether anything has moved under a change set, and whether catching up is mechanical or a decision. Stale bases moved out of the schema check into it.
Also
- The
change_set.publishedwebhook carriesreleaseNumber. - Publishing a revert emits
release.reverted.
Upgrading
$ npm install @myna-sh/[email protected]
Additive: nothing removed, minimum supported client unchanged. New capabilities are releases, releases.revert, change-sets.concurrent, and change-sets.rebase — see the management API reference.
Affects api · dashboard · sdk · cli · mcp · docs
