On this page
Release orchestration commands covering the full release lifecycle.
#rlsbl release
Release orchestration commands covering the full release lifecycle. Provides 11 subcommands: run, resume, init, retry, edit, undo, deprecate, yank, scrub, backfill, reconcile.
#release run
Bump version, validate the JSONL changelog, run tests and lint, commit, tag, push, and create a GitHub Release. Reads the bump type (patch, minor, major, or infra) and target selection from .rlsbl/releases/unreleased.toml, which can be scaffolded with rlsbl release init. Supports dry-run preview, --approve-consequential to skip the confirmation prompt in non-interactive contexts, and --allow-dirty to skip the clean working tree check.
Effect: mutating · consequential (prompts before running; --approve-consequential skips)
#Flags
| Name | Short | Type | Presence | Env | Description |
|---|---|---|---|---|---|
--push-timeout | int | optional | Timeout in seconds for each git push. Overrides the push_timeout config key; when omitted, push_timeout applies, else the shipped default. | ||
--ci-timeout | int | optional | Timeout in seconds for the release CI gate (the wait for CI to conclude on the pushed release candidate). Overrides the ci_timeout config key; when omitted, ci_timeout applies, else the shipped default. | ||
--check-timeout | int | optional | Timeout in seconds for each preflight check subprocess (tests, lint, external checks). Overrides the check_timeout config key; when omitted, check_timeout applies, else the shipped default. | ||
--hook-timeout | int | optional | Timeout in seconds for each release hook. Overrides the hook_timeout config key; when omitted, hook_timeout applies, else no timeout. | ||
--watch, --no-watch | bool | required | After release, automatically watch CI runs to completion (--no-watch to skip) | ||
--allow-dirty, --no-allow-dirty | bool | required | Skip the clean working tree check and allow releasing with uncommitted changes | ||
--releasable | str | optional | Which releasable to release. Required when running at a monorepo workspace root, where the directory names the whole workspace rather than one releasable; rejected anywhere else, since the directory already names it. |
#release resume
Resume a previously failed release from where it left off. Reads the in-progress state file (.rlsbl/releases/in-progress.json, or .rlsbl-monorepo/releasables/
Effect: mutating · consequential (prompts before running; --approve-consequential skips)
#Flags
| Name | Short | Type | Presence | Env | Description |
|---|---|---|---|---|---|
--push-timeout | int | optional | Timeout in seconds for each git push. Overrides the push_timeout config key; when omitted, push_timeout applies, else the shipped default. | ||
--ci-timeout | int | optional | Timeout in seconds for the release CI gate (the wait for CI to conclude on the pushed release candidate). Overrides the ci_timeout config key; when omitted, ci_timeout applies, else the shipped default. | ||
--check-timeout | int | optional | Timeout in seconds for each preflight check subprocess (tests, lint, external checks). Overrides the check_timeout config key; when omitted, check_timeout applies, else the shipped default. | ||
--hook-timeout | int | optional | Timeout in seconds for each release hook. Overrides the hook_timeout config key; when omitted, hook_timeout applies, else no timeout. | ||
--watch, --no-watch | bool | required | After release, automatically watch CI runs to completion (--no-watch to skip) |
#release init
Scaffold a .rlsbl/releases/unreleased.toml file by auto-detecting project targets. The generated file contains a default bump type (patch), an include list of all detected targets, and per-target configuration sections for Flutter targets.
Effect: mutating
Dry run: not supported — the command scaffolds a file whose point is that you edit it before releasing; printing that file instead of writing it leaves nothing to edit
#release retry
Dispatch CI/CD workflows for a completed release via gh workflow run. Reads the dispatch list and ref from .rlsbl/releases/retry.toml, which is auto-scaffolded with sensible defaults if missing. Verifies the GitHub Release exists before dispatching. Each workflow in the dispatch list is triggered against the configured ref (defaults to the release tag).
Effect: mutating · consequential (prompts before running; --approve-consequential skips)
#Flags
| Name | Short | Type | Presence | Env | Description |
|---|---|---|---|---|---|
--watch, --no-watch | bool | required | After retry, automatically watch CI runs to completion (--no-watch to skip) |
#release edit
Sync the GitHub Release notes for a given version with the corresponding CHANGELOG.md entry. Defaults to the current version if none is specified. Use --dry-run to preview changes without updating GitHub.
Effect: mutating
#Arguments
| Name | Type | Presence | Description |
|---|---|---|---|
version | str | optional | Version whose GitHub Release notes to sync (defaults to current version) |
#release undo
Revert a release. Without --version, reverts the latest release (deletes GitHub Release, removes git tag, reverts version bump commit). With --version, reverts a non-latest release if it is provably unpublished (probes registries for evidence, deletes GitHub Release + tag only, un-finalizes changelog).
Effect: mutating · consequential (prompts before running; --approve-consequential skips)
#Flags
| Name | Short | Type | Presence | Env | Description |
|---|---|---|---|---|---|
--target | str | optional | Target a specific registry for version detection (auto-detected if omitted) | ||
--version | str | optional | Version to undo (for non-latest releases that are provably unpublished) |
#release deprecate
Mark a past release as deprecated. Sets the GitHub Release pre-release flag and prepends a deprecation notice to the release notes. Use --reason to explain why and --use to suggest a replacement version.
Effect: mutating · consequential (prompts before running; --approve-consequential skips)
#Flags
| Name | Short | Type | Presence | Env | Description |
|---|---|---|---|---|---|
--reason | str | optional | Human-readable explanation of why this version is being deprecated | ||
--use | str | optional | Suggest this version as a replacement in the deprecation notice |
#Arguments
| Name | Type | Presence | Description |
|---|---|---|---|
version | str | required | Semver string of the release to deprecate, with or without v prefix (e.g. 0.9.1) |
#release yank
Remove a published version from package registries. Probes each configured target's registry to determine publication status, then executes registry-specific removal: npm deprecate, Go retract, or PyPI manual checklist. Also marks the GitHub Release as pre-release with a yank notice.
Effect: mutating · consequential (prompts before running; --approve-consequential skips)
#Flags
| Name | Short | Type | Presence | Env | Description |
|---|---|---|---|---|---|
--reason | str | optional | Human-readable explanation of why this version is being yanked | ||
--use | str | optional | Suggest this version as a replacement in the yank notice |
#Arguments
| Name | Type | Presence | Description |
|---|---|---|---|
version | str | required | Semver string of the release to yank, with or without v prefix (e.g. 0.9.1) |
#release scrub
Scrub sensitive content from git history and update release metadata to match the rewritten commits. Supports 3 modes: match (--pattern), file (--file), or recipe (--recipe). After rewriting, remaps commit hashes in JSONL changelog files, regenerates CHANGELOG.md, force-pushes, re-points the tags, and rewrites each tag's GitHub Release document in place. A Release is never deleted, so a failure mid-step leaves the previous document standing rather than a tag with no Release at all.
Effect: mutating · consequential (prompts before running; --approve-consequential skips)
#Flags
| Name | Short | Type | Presence | Env | Description |
|---|---|---|---|---|---|
mode | choice | required | Selection (not typed as a flag). Elect exactly one of --pattern, --file, --recipe. Which scrub mode to run: match a regex, rewrite one file, or execute a recipe TOML. Exactly one must be elected, and the elected one decides which further flags exist. | ||
--pattern | str | required | Elects mode = pattern. Match mode: rewrite every occurrence of a regular expression throughout the repository's history, in every file of every commit the chosen range covers Its value: regular expression matched against file contents in every commit of the chosen range; each match is replaced by --replace, or by same-length random ASCII under --mangle | ||
--replace | str | optional | Only with --pattern. literal text to substitute for each match (mutually exclusive with --mangle) | ||
--mangle | bool | optional | Only with --pattern. replace matched content with random ASCII of the same length (mutually exclusive with --replace) | ||
--file | str | required | Elects mode = file. File mode: rewrite one file throughout the repository's history, replacing every past version of it with the copy on disk now Its value: repository-relative path of the file to rewrite throughout history; every commit's version of it is replaced with its current on-disk content, or removed from that commit if the file is absent on disk (requires --from-commit) | ||
--recipe | str | required | Elects mode = recipe. Recipe mode: execute a scrub recipe TOML via safegit scrub run Its value: path to a scrub recipe TOML file; per-operation pattern/replace/mangle live inside the recipe | ||
commit-range | choice | required | Selection (not typed as a flag). Elect exactly one of --from-commit, --entire-history. Which commits the rewrite covers: everything descended from one commit, or the entire history from the initial commit onward. Exactly one must be elected. | ||
--from-commit | str | required | Elects commit-range = from-commit. Rewrite the commits descended from one named commit onward, leaving every commit before it exactly as it is Its value: SHA of the earliest commit to rewrite; every commit descended from it is rewritten too, and every commit before it keeps its current hash | ||
--entire-history | required | Elects commit-range = entire-history. Rewrite every commit in the repository from the initial commit onward (match and recipe modes only; file mode requires --from-commit) | |||
--reason | str | required | Why this content is being scrubbed. Recorded in the rewrite commit message and in the scrub archive, so it is the audit trail for an irreversible history rewrite. |
#release backfill
Bring this repository's release archives into the three-fate model from its real history: record each version's release commit from the tag (or the historical spelling its archive names in shipped_as, or its version-bump commit), complete an archive whose required fields are missing or unanswered (a present but empty bump or description is unanswered), materialize an archive for a released version that never got one, and adopt a version tag no store records as the release it is evidence of. A reconstructed description comes from the first source that yields one -- an operator-reviewed --overrides file, the version's GitHub Release body, its CHANGELOG.md section, the commit subjects in its tag range -- and the archive names the source it came from. Every tag the repository cannot account for is listed first and refuses the whole apply; --dry-run prints the plan and writes nothing.
Effect: mutating · consequential (prompts before running; --approve-consequential skips)
#Flags
| Name | Short | Type | Presence | Env | Description |
|---|---|---|---|---|---|
--overrides | str | optional | Path to a TOML file of reviewed descriptions, one [versions."X.Y.Z"] table per version with a description and an optional context. Applied before any derivation. A version the file names that this repository does not have is a hard error. | ||
--auto-commit, --no-auto-commit | bool | optional | Commit the written archives with the Autogenerated trailer (the handler commits when neither --auto-commit nor --no-auto-commit is passed) |
#release reconcile
Reconcile this project's published release metadata with what its own records say it released: push the refs origin is missing, re-point the ones a recorded rewrite moved, and create the GitHub Releases that are absent. Merges four explanation sources -- safegit's rewrite journal, the release record's release commits, the transition records, and the committed scrub archives -- into one preview whose verdicts are materialize, already-correct, re-point-with-lease, refuse-foreign, or refuse-identity-mismatch. Fail-closed: one ref origin holds that no record explains aborts the whole reconcile, and nothing anywhere is repaired. Consent is file-driven: --plan writes the plan, --apply performs it.
Effect: mutating · consequential (prompts before running; --approve-consequential skips)
#Flags
| Name | Short | Type | Presence | Env | Description |
|---|---|---|---|---|---|
mode | choice | required | Selection (not typed as a flag). Elect exactly one of --plan, --apply. Which half of the reconcile to run: write the plan, or perform it. Exactly one must be elected. | ||
--plan | required | Elects mode = plan. Observe origin and write the reconcile plan as reconcile-plan.toml beside the release records being reconciled (.rlsbl/releases/ in a standalone repository, the releasable's own releases/ in a workspace). Writes nothing to origin. | |||
--apply | required | Elects mode = apply. Perform the reconcile-plan.toml beside the release records being reconciled, after re-observing origin and refusing if it moved since the plan was written. | |||
--push-timeout | int | optional | Timeout in seconds for each ref push. Overrides the push_timeout config key; when omitted, push_timeout applies, else the shipped default. | ||
--releasable | str | optional | Which releasable to reconcile. Required when running at a monorepo workspace root, where the directory names the whole workspace rather than one releasable; rejected anywhere else, since the directory already names it. |