The change model¶
The change is the concept at the center of TOVIO, and it is the one that most repays understanding. Get this and the rest of the system clicks into place: why there's no staging area, why rebasing is safe, why lanes are landing targets, why stacks just work.
This page is about why the model is shaped this way. For the commands, see Get started.
Two identities for two different things¶
Git gives a commit one identity — its hash — and uses it for two jobs at once: this exact snapshot of bytes, and this unit of work in my history. That conflation is the root of rebase anxiety. The moment you amend or rebase, the hash changes, and "the thing you were working on" appears to vanish and be replaced by a stranger. CI loses track of it. A teammate's review comment points at a commit that no longer exists. You force-push and hope.
TOVIO splits the two jobs into two identities:
| What it names | When it changes | |
|---|---|---|
Change ID (chg:xkqm7y) |
The unit of work | Never — survives amend, rebase, split, absorb |
Commit ID (blake3:…) |
The exact snapshot | Whenever the content changes — like a Git hash |
A change points at its current commit. Rewriting history produces new commits but keeps the change's identity.
Mental model
A change is a Git branch and its commits as one named unit of work — with a permanent name that history edits can't disturb. The commit is the snapshot; the change is the story.
Why the Change ID is random, not content-derived¶
A Change ID is a random 128-bit value, drawn from a secure random source at the moment work begins,
rendered as chg: plus Crockford base32. It is deliberately not derived from content — and that is
the whole point. If identity were a hash of content, it would change the instant you amended a typo,
which is exactly the property we are trying to eliminate. Identity has to be stable under rewriting,
so it cannot be a function of the thing being rewritten.
The trade-off is that
random IDs aren't chronologically sortable. That's fine: ordering comes from the commit DAG and the
Hybrid Logical Clock, never from the ID. The two namespaces — chg: for
changes, blake3: for commits — are kept visibly distinct so a value is never ambiguous about which
kind of thing it names. Like Git short hashes, tools accept any unambiguous prefix.
On Git import
When you import a Git repository, each imported commit is assigned a fresh Change ID, and the original Git hash is preserved as metadata. Your history keeps its provenance and gains stable identity.
No staging area: the working copy is the change¶
There is no index and no tovio add. The working copy is continuously snapshotted into the current
change. On each command boundary (and optionally on a filesystem watcher event), TOVIO hashes only the
paths that changed and reuses unchanged subtrees, so the snapshot is fast and atomic.
tovio commit doesn't "stage then commit" — it finalizes the current change and starts a new one.
Granularity that you'd have reached for staging to get, you recover with explicit operations instead:
tovio commit --amend— fold more edits into the current change; the Change ID is unchanged.tovio change split— divide one change into a landable sub-change and a work-in-progress remainder.tovio change absorb— push fixup edits down into the changes that originally introduced those lines.
Because there is always a tracked snapshot, undo and crash recovery are trivial: there is never a moment where your work exists only in the editor.
Lanes are destinations; changes are workspaces¶
In Git you live on a branch. In TOVIO you live in a change, and a lane is a landing target —
a name for "the integrated state of finished work." You don't sit on main; you land changes onto it.
This is what makes TOVIO trunk-based by idiom. Because the change is your workspace, you land
changes continuously onto a small set of protected lanes rather than maintaining long-lived feature
branches. Long-lived develop / staging / release lanes are still supported, but they carry
the same integration debt they do in Git: the more a lane diverges, the more its eventual land costs.
Stacking: branching off a branch, without the pain¶
Because a change knows its parent — and a change's parent can be another change — you can stack changes:
main
└─ chg:aaa "add CGM client" ← base of the stack
└─ chg:bbb "wire CGM into sync" ← builds on aaa
└─ chg:ccc "CGM UI panel" ← builds on bbb
You work on all three at once, switching between them with no stashing. When the base is ready, you
tovio land my-lane --into main. Here is the part that dissolves the usual stacked-PR misery:
The land cascade
Landing the base of a stack automatically re-bases the changes above it onto the new lane
state — and their Change IDs do not change. chg:bbb and chg:ccc are still chg:bbb and
chg:ccc; they're just rebased. Reviews, CI runs, and references that point at them stay valid.
This is stacked development without the fragility: no manual rebase chain, no force-push storm, no re-pointing a tower of pull requests by hand.
History rewriting is a normal, safe operation¶
commit --amend, rebase, change split, change absorb — these are everyday, unremarkable
operations in TOVIO, because the thing that made them scary in Git is gone. They produce new commits, but
they keep Change IDs, and the operation log records every step so tovio undo can
reverse any of them. The interface even says so out loud: a rebase reports that the Change IDs are
unchanged, and a land that "your work kept its identity."
✓ Rebased chg:xkqm7y onto main (4 change(s) reparented, Change IDs unchanged) - undo with `tovio undo`
That single line is the cure for force-push anxiety. You are never one keystroke from losing track of your work.
Where to go next¶
- How this maps onto your Git habits: Coming from Git.
- What happens when two changes touch the same lines: Conflicts as data.
- How the local op-log makes supported mutations reversible: Fearlessness.
Last reviewed September 9, 2026
Suggest an improvement to this page Not for security reports — see disclosure