arche / wiki / The Draft Model and History Editing

The Draft Model and History Editing

Understanding how Arche treats the working directory changes the way you think about almost every operation.

The Working Directory Is Always a Commit

In Git, there are three states: the working directory, the index (staging area), and committed history. In Arche, there are two: the working directory and history. The working directory is always a materialised view of the current draft commit. When you edit a file, you are implicitly editing the draft. When you run arche snap, you give the draft a message and finalise it, which creates a new empty draft pointing to the freshly-made commit as its parent.

This means "the current state of your work" is always a valid commit object in the store, even before you give it a name. You never lose work to an accidental git checkout because there is nothing analogous to the stash-or-lose decision Git sometimes forces on you.

Change IDs: Identity That Survives Rewrites

Every commit is assigned a change ID at creation, formatted as ch: followed by eight lowercase letters (e.g. ch:kptxoyvr). The change ID is stable across rewrites. If you amend a commit, rebase it onto a new parent, or squash it with a neighbour, the change ID stays the same. The content hash changes, but the identity doesn't.

This has concrete practical consequences. You can reference a commit by its change ID in scripts, in issue tracker links, in code review comments, and those references will remain valid after the inevitable rebase that cleans up the history. The oplog stores change IDs rather than hashes for exactly this reason.

Amending HEAD

To add more changes to the most recent commit, or to revise its message, just edit files and run:

arche snap --amend

This re-snapshots the working directory and replaces the HEAD commit with a new object that has the same change ID but a new content hash. An obsolescence marker linking the old hash to the new one is written as part of the same transaction. If there are any draft commits that descend from HEAD, Arche automatically rebases them onto the amended tip. Their change IDs are preserved, their content hashes change, and obsolescence markers chain accordingly.

The auto-rebase after amend is the mechanism that makes stacked changes work cleanly. You amend the bottom commit in your stack, and the rest of the stack updates silently.

Shelving Changes

When you need to set aside working-copy changes without creating a commit, use a shelf:

arche shelve [name]

This captures a snapshot of the current working copy, then reverts the working directory to HEAD. Shelves are stored in store.db, are not visible in arche log, and are never synced to remotes. The default shelf name is "default". Pass an explicit name to maintain multiple independent shelves.

To restore a shelf onto the working copy:

arche unshelve [name]

Unshelving does not delete the shelf. To remove it:

arche shelve drop my-wip

To list all shelves:

arche shelve list

Shelves serve the same role as Git stash. Because the draft model keeps the working directory as a first-class commit state, most situations where Git users reach for stash don't arise in Arche. Shelves are there for the cases that do: switching contexts mid-flight, setting aside an experiment, or carrying changes across a checkout without snapping them yet.

Splitting a Commit

If a commit contains logically unrelated changes, arche split opens the same hunk-selection TUI used by arche snap -i. The hunks you select go into a new first commit; the remaining hunks become a second commit directly on top of it. Both commits share the commit message of the original until you edit them. The original is marked obsolete.

arche split

Folding and Squashing

To fold a commit into its parent, discarding the commit boundary between them:

arche fold <commit>

The named commit and its parent are replaced by a single combined commit. The tree is taken from <commit> (the final state), the parents are taken from the original parent's parents, and the message combines both. Both the original commit and its parent are marked obsolete.

To collapse a range of commits into one, where the result has the tree of the last commit and the parents of the first:

arche squash ch:aaa..ch:bbb

Both fold and squash require --force-rewrite if any of the affected commits are public, because rewriting public history is a deliberately exceptional operation.

Rebasing

arche rebase <dest>

This replays the current commit lineage on top of <dest>. Each commit in the chain is replayed by computing the diff from its parent to itself, then applying that diff to the current tip of the rebase in progress. Each replayed commit gets the same change ID as its original, a new content hash, and an obsolescence marker linking the old hash to the new one.

If a diff can't be applied cleanly, Arche writes a conflict object at the conflicting path, records it in the replayed commit, and continues to the next step. The rebase runs to completion. Afterwards the working copy reflects the tip of the rebased chain, with conflict markers in any file that couldn't be merged automatically. Edit those files, run arche resolve <path> for each one, then arche snap.

Rebasing public commits requires --force-rewrite. Rewriting public history is understood to be a coordination event, not a routine operation.

The Operation Log

arche op log

Every mutation (init, snap, checkout, merge, rebase, undo) records a row in the operation log. Each row stores the complete ref state (HEAD and all bookmark targets) before and after the operation, plus a timestamp and any relevant metadata (the change ID being merged, the rebase destination, etc.).

This is different from arche log, which shows the commit DAG. The operation log is a chronological record of what you did, regardless of what the current DAG looks like.

arche undo --step 3

Restores HEAD and all bookmarks to their state three operations ago. This is atomic: either all refs are restored, or nothing changes. The undo itself is recorded in the operation log, so you can undo the undo.

Worktrees

When you need to work on two commits simultaneously, say reviewing an old branch while keeping your main working copy mid-flight, use a linked worktree:

arche worktree add ../arche-review -b old-feature

This creates a directory at ../arche-review checked out to the old-feature bookmark, sharing the same store.db as the main repository. It has its own HEAD file, its own working copy, but the same history. Snapping in one worktree is immediately visible to the other. There is no duplication of object storage.

To see all active worktrees:

arche worktree list

To remove a worktree registration (the files on disk are left untouched):

arche worktree remove arche-review