Skip to content

Rewrite history safely

Rewriting history in TOVIO is not the high-wire act it is in Git. The single idea that removes the fear: a change keeps its stable Change ID through every rewrite. Amend, split, squash, absorb, reorder, rebase — the commit hashes change, but chg:a3f7b2 is still chg:a3f7b2. You (and your teammates, CI, and agents) can always point at the same unit of work no matter how its history is reshaped.

Every rewrite is one undo away

Each command on this page is op-logged and reversible with a single tovio undo. There is no force-push, no detached HEAD, no "diverged history," and no way to strand your work. Reshape freely; take it back if you don't like it. See Undo and redo recorded operations for the local retention and peer-observation boundaries.

Implemented and specification-only rewrite verbs

tovio commit --amend, tovio change split, tovio change absorb, and tovio rebase / tovio change rebase have landed and preserve Change IDs. The standalone tovio amend, tovio squash, and tovio reorder remain specification-only; those sections document intended behavior, not commands you can run today.

Why this is safe (the Change ID)

A Git rebase rewrites commit hashes, which is why it feels dangerous — references break, history "diverges," and recovery means spelunking the reflog. TOVIO separates two identities:

  • The Commit ID (blake3:…) is a content hash. It does change when content changes.
  • The Change ID (chg:…) is a stable name assigned when work began. It never changes.

So a rewrite produces new commits under the same change. References to the change stay valid. tovio change show chg:a3f7b2 always resolves to that change's current commit, before and after any rewrite. Affirming this is why every rewrite prints a line like "Change IDs unchanged" or "same Change IDs — your work kept its identity." For the full mental model behind Change IDs, see the concepts.

Amend — fold edits into the current change

The everyday rewrite. Add more edits, or fix the message, without starting a new change:

$ tovio commit --amend -m "Add Dexcom G7 sync handler (with retry)"
✓ amended  chg:a3f7b2…  blake3:07afd91f2c…
  2 file(s) · amended · undo with `tovio undo`

This folds the current working change into the last commit and preserves its Change ID; omit -m to keep the existing message (Commit your work).

No standalone tovio amend

The CLI specification also spells this tovio amend; that verb is not implemented. Use tovio commit --amend.

Split — divide one change into several

split recovers granularity after the fact — TOVIO has no staging index, so you don't pre-select what goes in a commit; you commit, then split if you want finer pieces. Divide by paths:

$ tovio change split chg:a3f7b2 --paths "src/**"
✓ Split chg:a3f7b2… into ready chg:phb97d… (1 path(s)) + remainder chg:a3f7b2… - undo with `tovio undo`

The matching files become a fresh ready sub-change that is landable on its own; the rest stays as the remainder, which keeps the original Change ID and stacks on top (parent → ready → remainder). The change must be a lane tip; omit the id to split the current change. --paths is repeatable.

This is also how you do a partial land: split the ready files into their own sub-change, then land just that one and keep the rest as work in progress. You never cherry-pick individual files out of a change.

Squash — combine a change into its parent

The CLI specification designs tovio squash <change-id> [--into <target>], where the surviving change keeps its ID.

Not yet available

tovio squash is not implemented. Today the nearest tools are tovio change absorb (fold fixups back into the changes that own them) and tovio commit --amend (fold working edits into the last commit).

Absorb — distribute fixups automatically

Made a handful of small fixes that really belong to earlier changes in your stack? absorb routes each file your current change touches into the single unlanded ancestor that last touched it, then re-stacks the rest:

$ tovio change absorb --dry-run    # preview the routing without rewriting anything
$ tovio change absorb
✓ Absorbed 1 file(s) into 1 change(s) (Change IDs unchanged); 0 kept in chg:a3f7b2… - undo with `tovio undo`
  → chg:phb97d… : src/integrations/cgm/dexcom.ts

No manual "fixup!" commits, no interactive rebase — TOVIO figures out where each edit belongs. It is conservative: a file that no ancestor (or several ancestors) touched stays in your change, and when nothing at all routes — every fixup was new code, or there is no unlanded stack forked off main — absorb declines with TVO-OP-016 rather than guessing.

Reorder — change the order of a stack

The CLI specification designs tovio reorder <change-id> --before <change-id>, preserving Change IDs across the reorder.

Not yet available

tovio reorder is not implemented.

Rebase — re-parent changes onto a new base

The top-level form reparents the current change and its stack onto another lane or change (default main):

$ tovio rebase --onto main
✓ Rebased chg:002… onto main (2 change(s) reparented, Change IDs unchanged) - undo with `tovio undo`

To name the change explicitly — or a linear range <start>..<tip> — use the change form:

$ tovio change rebase chg:002 --onto main

rebase is the explicit re-parenting form. In everyday work you rarely need it directly, because tovio land auto-rebases a stack for you when you land its base. Dependent lanes are re-derived through the same path-scoped descendant cascade. Where content can't auto-merge, conflicts are stored, not blocking — the summary reads N conflict(s) stored (resolve, then land) — see Resolve conflicts. Rebasing onto a protected lane is the exception: it refuses to leave unresolved conflicts there. A lane already based on the target reports nothing to rebase.

Where these sit in the CLI

commit --amend sits with commit in everyday use; split and absorb live under the everyday tovio change group; tovio rebase (and, once they ship, squash and reorder) sits one tier deeper in tovio help --advanced — kept out of the default tovio help index so the everyday surface stays small, but always runnable by name. They are documented here because they're the heart of fearless history editing.

A note for teammates and agents

Because the Change ID is stable, rewriting your history doesn't break anyone who's tracking your change. A teammate who pulled chg:a3f7b2 as a dependency keeps a valid reference after you amend it — TOVIO notifies them with an impact pointer and a rebase suggestion rather than leaving them with a dangling hash. That cross-developer flow lives in the collaboration guides.

Where to go next

Last reviewed September 9, 2026

Suggest an improvement to this page Not for security reports — see disclosure