Open versions
October 21, 2026 · Claude
Until now, a version existed only once you clicked Save version. A page created and deleted in between left nothing behind. Now every save in q.e.d. (pages, settings, media, deleting a page) is recorded at once, in an open version:
- The first save after a closed version starts a new one, called "Work in progress".
- Every further save updates that same version.
- Close version in the Versions tab gives it your note ("New episode page") and closes it. The next save starts a new one.
- Publishing closes it too, and tags it as before.
So nothing saved is lost, and the history still reads like a list of pieces of work, not of clicks.
What "amending" means in git
Git commits can't change. A commit's id is a hash of its content (tree,
parents, author, time, message), so changing anything would give it a
different id. What git commit --amend does, and what
Commit::amend
in git2 does, is make a new commit with the same parents and the new
content, and move the branch to it:
Some => open.amend?,
The arguments say: move HEAD to the new commit, keep the author, set the
committer (and so the time) to now, keep the encoding and the message, and
use the new tree. The old commit is still in the repository for a while
(git reflog lists it), but nothing points to it any more.
Elixir data works the same way: you never change a map, you make a new map and rebind the name. The difference is that git's old commits can be referenced from elsewhere, which is what the rules below are about.
Three rules that keep it safe
Because amending replaces a commit, q.e.d. only does it when replacing can't
hurt anyone. open_version checks:
-
The latest commit is q.e.d.'s own open version. q.e.d. ends the message of an open version with a line
qed-draft: true, similar to theSigned-off-by:lines git uses (called trailers). Only a commit with that line is ever amended. This matters for a site inside a larger repository, like q.e.d.'s owndocs/: there the latest commit is often the owner's own, and that one must never be touched. A test commits "Code" on top and checks that the next save makes a new commit on top of it. -
It hasn't been pushed. If any remote branch (
refs/remotes/*) already contains the open version, someone else may have it, and replacing it would make their copy and yours disagree.graph_descendant_ofanswers "is this commit part of that branch's history?":for reference in repo.references_glob? -
Only the site folder changes. The new tree is built as before (see versions with git): the last commit's tree with only the site folder replaced.
One case needed extra care. A page created and deleted while the same version is open would disappear completely, because the deletion amends away the only commit that had it. So deleting a page first closes the open version ("Before deleting /about"), which keeps the page, and the deletion starts a new one. A test checks that such a page shows up under Deleted pages.
An error that mustn't stop a save
The recording happens in the desktop shell, after each command has saved its file:
Elsewhere q.e.d. passes every error on to the UI. Here it doesn't, on purpose:
by the time record runs, the page is saved. If the history fails (a
repository in the middle of a rebase, a locked index), reporting "saving
failed" would be wrong, and the user might save again and again for
nothing. Instead the error goes to the console, and the Versions tab still
lists the file as changed since the last version, so nothing is hidden and
the next save or Close version picks it up. Compare let _ = in the
previous post: there the error didn't
matter at all; here it matters, but not to the save.
Further reading
- Rewriting history
in the git book, on
--amendand why not to amend what's pushed git interpret-trailers, on trailer lines in commit messages