Skip to content

Release workflow

Verso calculates one exact file plan, then records progress through explicit local stages and one remote transaction. The persisted plan makes an interrupted release inspectable and recoverable without recomputing its intended output.

Before any write

Verso loads one release-group config, discovers its members, verifies that their versions are consistent, resolves one target version, and calculates every file's actual before and after content. A full release also calculates the changelog, commit message, tag, hooks, and atomic push. A bump plan contains only version-file changes and version hooks.

Shell
verso --version 2.0.0 --dry-runverso bump minor --dry-run

Dry-run renders that exact plan, including full-file before/after diffs, without writing files, running hooks, creating a transaction journal, or executing mutating Git commands.

Add --group core when working with a named release group.

For execution, Verso checks the worktree policy and planned paths, rejects an existing target tag, and takes a repository transaction lock. Only one Verso transaction may be active per Git repository.

Persisted stages

After the first file-change confirmation, Verso stores the plan and progress under Git metadata and uses atomic file replacement. The release stages are:

text
planned  -> before_version -> apply exact files -> files-applied -> after_version  -> before_commit -> git add/commit -> committed -> after_commit  -> before_tag -> annotated tag -> tagged -> after_tag  -> before_push -> git push --atomic -> pushed -> after_push  -> clear transaction

verso bump follows only planned -> files-applied, runs before_version and after_version, then clears the transaction. It does not change the changelog, stage files, create a commit or tag, or push.

The release confirmations before files, commit, tag, and push default to yes. A target that is not greater than the current version has an earlier confirmation that defaults to no. --yes accepts all of them.

Status, resume, and abort

Shell
verso status [--json]verso resume [--retry-hook | --skip-hook]verso abort [--force]

status is read-only. It reports the operation, release group, stage, version pair, changed-file count, interrupted hook, and whether abort is still allowed.

resume first reconciles the journal with the exact file contents, HEAD, and tag. It skips completed hooks and confirmations, then continues from the recorded stage. A hook that was active when the process stopped has an unknown outcome: inspect its side effects, then explicitly use --retry-hook or --skip-hook.

If another mutating release or bump is started while a transaction is active, Verso shows its group, version pair, and stage, then prompts to resume or abort it. Recovery completes that invocation; it does not continue into the newly requested release.

abort is conservative. It compare-and-deletes only the exact tag object Verso created, soft-resets only the expected release commit, unstages only planned paths, and restores a file only when it still matches the plan's after content. It refuses an unexpected HEAD, moved tag, or later file edit rather than overwriting unrelated work. Once the release commit exists, abort also checks the pinned remote and refuses an unowned target tag or a branch that already contains the release commit.

Resume keeps using the push URL, commit, and tag persisted when the transaction started, even if local HEAD advances after push begins.

Failure and cancellation behavior

Expected file, hook, commit, and tag failures before push trigger a best-effort local abort. Release hook failures are checked against the pinned remote first; if that remote cannot be inspected, Verso preserves the journal instead of assuming the hook did not publish. A crash, user cancellation at a later confirmation, or an ambiguous state preserves the journal so the user can choose resume or abort while push has not started. A push failure preserves the journal for resume only.

Stopping pointPersisted state and next action
Before initial file confirmationNo transaction and no file change
Files applied / before commitFiles remain unstaged; resume commits or abort restores them
Commit created / before tagExpected release commit remains; resume tags or abort soft-resets and restores
Tag created / before pushLocal commit and tag remain; resume pushes or abort removes the expected local work
Atomic push failedLocal commit, tag, and journal remain; fix or inspect the remote, then resume
Push succeeded / after_push failedLocal and remote refs remain; only resume is allowed

Cleanup never uses a hard reset. Restore, unstage, reset, tag-delete, journal, or remote-verification errors are reported instead of being hidden.

Hooks and CI handoff

Hooks are arbitrary project shell commands. Dry-run prints their names and commands but executes none. Pass secrets through the environment rather than storing them in config, keep hooks retry-safe, and prefer CI for destructive or credentialed publication. after_push is a follow-up boundary: it can be resumed, but it cannot undo remote refs. After an interrupted hook, confirm that its old process has stopped before retrying, skipping, or aborting the transaction.

Registry publication, GitHub Releases, binary builds, and deployment remain the responsibility of tag-triggered CI.

Before enabling automation, capture both checks in the target repository:

Shell
verso doctor --jsonverso --version <next-version> --dry-run --json

Add --group <NAME> to both commands when automating a named release group.

Atomic push details

Show the exact refs pushed by Verso

Verso resolves the current branch's configured remote and merge ref, then pushes only these two refs:

text
<release-commit-oid>:refs/heads/<upstream-branch><tag-object-oid>:refs/tags/<release-tag>

The command uses git push --atomic; unrelated local tags are not included. The remote must support atomic pushes, so it accepts both refs or neither.

Copyright © 2026 白熱.