Skip to main content
The release flow keeps production code on prod and release information on release-state. Deleting release-state does not delete production commits, version tags, GitHub Releases, or GHCR images. It does remove the automation’s record of which version and production SHA were last approved.

Branch shape

release-state starts with an orphan commit: it has its own history, independent of main and prod. Its entire tree contains exactly these three regular, non-executable files (Git mode 100644):
There are no subdirectories, application files, workflows, configuration files, symlinks, or generated JavaScript on this branch. The automation and release-please-config.json live on the code branches. Never restore release-state from a prod version tag or by copying a code branch: those commits contain the application tree, which fails metadata validation. Never merge release-state into main or prod.

Before the first release

The bridge creates these exact starting contents:
.release-please-manifest.json
CHANGELOG.md
release.json
This means no release has been approved. An open metadata PR is a proposal; its contents do not become approved state until it is merged into release-state.

After approval

For example, a first v1.0.0 approval has this manifest:
.release-please-manifest.json
Its release record has the following shape. The SHA and notes below are illustrative; recovery must use actual production SHAs and the exact approved notes.
release.json
Future records use an increasing version, such as 1.0.1, with previousTag: "v1.0.0" and previousSha set to the actual commit tagged v1.0.0. Both SHAs refer to application history, not metadata branch commits. A non-null record with no previous release must be version 1.0.0. CHANGELOG.md starts with # Changelog and accumulates Release Please entries, newest first. It includes the currently approved version. The complete notes contain the generated headings, dates, links, and commit references; retain those when recovering. The manifest and release record describe the last approved release, which may still be awaiting publication. Publication does not add a separate flag or metadata commit. To determine its status, check that the GitHub Release is published, not a prerelease, and its tag points to prodSha; its body must equal notes. GHCR uploads can finish later or require a separate retry.

Recover a deleted branch

First stop prod promotions and disable Stable release in the Actions workflow menu while restoring. This prevents a prod push from automatically recreating empty state. Leave application deployments, existing tags, releases, and images intact. After releases have shipped, do not recover by running plan against empty state. The bootstrap path assumes no previous release and will propose v1.0.0 again. Restore the last approved metadata, or reconstruct the last published state, before resuming automation.

Prefer the original metadata commit

The best recovery preserves all three files and their original history, including any approval whose publication failed. Find the former release-state tip in a local clone/reflog, a backup, or the merge_commit_sha of its most recently merged metadata PR. A version tag is not this commit: tags point to prod code. In a recovery clone, fetch and inspect the known metadata commit. Replace the placeholder with the full SHA:
Confirm that the tree contains only the three 100644 files, and that this is the most recent merged/approved state. A temporary automation PR head may contain an unapproved future release; do not restore it as approved state. If GitHub can no longer fetch the commit, use a clone or backup that still has it, or reconstruct published state below. If the remote branch is absent, recreate it at that commit with an empty expected-ref lease:
The empty lease requires the remote ref to be absent and refuses to replace an existing branch, including one recreated during recovery. Do not replace it with an unconditional force push. A ruleset may require an administrator’s narrowly scoped recovery exception to recreate the ref. Restore its normal protections immediately afterward. If automation has already recreated an empty branch, stop and inspect it; an administrator must review and restore the intended metadata ref under a temporary recovery exception.

Reconstruct from published releases

Use this only when the original metadata commit cannot be recovered. It reconstructs published state, not an approved-but-unpublished release. Check merged metadata PRs and failed publication runs first; preserve any outstanding approval separately rather than silently treating it as shipped. The recipe requires Git, GitHub CLI authenticated for read access, and Python 3. Use a new, empty recovery directory, keeping exported API data outside the metadata checkout:
Confirm that releases.json includes all published production releases and has not been edited. Save the following Python recipe as ../rebuild-state.py (outside the metadata checkout), then run python ../rebuild-state.py from metadata/:
This orders stable releases by semantic version, rather than assuming GitHub’s latest release or publication date identifies the correct boundary. The reconstructed changelog contains the published notes newest first; it may differ in spacing from the original generated file. Deleted releases, edited notes, or missing tags require recovery from an original metadata commit or backup instead of guessing the missing history. Review the three files and the selected latest/previous release against GitHub, then commit and inspect the metadata-only tree:
The push recreates an absent branch; it does not replace an existing one. Apply any narrowly scoped administrator recovery exception only for this operation, then restore the branch rules. Keep recovery scripts and API exports outside the branch.

If nothing has been released or approved

If no production release exists and no merged metadata PR has an outstanding approval, the empty bootstrap shape is sufficient. Re-enable Stable release and run plan from prod; it recreates the orphan branch and proposes the first releasable v1.0.0. Restore the branch rules before approving its PR.

Resume automation

  1. Restore the release-state ruleset: PR required, independent approval, stale approvals dismissed, deletion/force pushes blocked, and Validate release metadata required. Verify the metadata Actions event policy is still enabled.
  2. Re-enable Stable release. If the recovered approved record has not been published, run publish from prod to complete that specific approval. If it matches an existing published release, run plan from prod to calculate the next release from its recorded SHA.
  3. Inspect any old/open metadata PRs before merging. Close stale proposals based on the lost branch; let plan create/update the current proposal and ensure its metadata check passes. A restored pending release is not an invitation to approve a different open proposal.
  4. Verify existing version tags still point to their original prod commits. Retry missing stable image uploads using Stable Docker Images with the existing release tag. Resume normal main → prod promotions.
For future recovery, retain a backup of the release-state ref and its Git objects alongside repository backups. Published tags preserve application code, not this branch’s metadata history; GitHub Releases preserve published notes, but not an unpublished approval.