Every repository that adopts release-tools works this way. People only make decisions: start a release, move it to its next stage, label fixes for backporting, and approve the changelog. The release bot does the rest.
| Branch | Purpose | Lifetime |
|---|---|---|
main |
Where all work lands, through squash-merged pull requests. Always releasable. Alphas are tagged here. | Permanent |
release/X.Y |
Created at the feature freeze of release X.Y: its betas, release candidates, X.Y.0 and patch releases. Only receives bug fixes backported from main. |
Until the next minor or major release is final; then it is unsupported |
release-pr/X.Y, changelog/vX.Y.Z, backport branches |
The bot's branches for its PRs | Managed by the bot |
Work branches (e.g. fix/login-timeout) |
One change, one pull request | Deleted after merging |
Patches go to the newest final release. While the next release is in beta or release candidates, fixes are backported to both; older releases get no fixes, and users upgrade.
-
Branch off
mainand targetmain, bug fixes included. Only the bot opens PRs against release branches. -
PRs are squash-merged, so the PR title and description become the commit. The title becomes the changelog entry, so write it for users:
type: description, with an optional scope (fix(io): …), an optional gitmoji after the colon (fix(io): 🐛 …, stripped from the changelog), and!after the type for a breaking change (feat!: remove the old solver API).Type Use for In the changelog featnew functionality Features fixbug fixes Fixes deprecatemarking something as deprecated Deprecations, with the migration notes perfperformance improvements Performance docsdocumentation only Documentation refactor,test,build,ci,chore,stylechanges users don't notice no (unless breaking) -
Breaking changes and deprecations need a
## Migrationsection in the PR description saying what users have to change, with a before/after example as code blocks. It is copied into the changelog under the entry, which lists breaking changes first. -
The PR checks enforce the title format and the Migration section, and re-run when the title or description is edited.
-
A bug fix that should also reach the current release gets the
backportlabel, before or after merging: see Patch releases. Features are never backported.
Semantic versioning, MAJOR.MINOR.PATCH. Patch releases only fix
bugs and never break anything. Before 1.0, a minor release may break existing code; from
1.0 on, only a major release may. Tags carry a v prefix (v0.5.0, v0.5.0rc1).
A release started from the Release workflow (X.Y.0, including 0.Y.0 and 1.0.0) can
have pre-releases, spelled as in PEP 440:
| Stage | Tag | On | Pre-1.0 | 1.0 and later |
|---|---|---|---|---|
| Alpha: features still landing (optional) | vX.Y.0aN |
main |
v0.5.0a1 |
v1.3.0a1, v2.0.0a1 |
| Beta: feature freeze, fixes only (optional) | vX.Y.0bN |
release/X.Y |
v0.5.0b1 |
v1.3.0b1 |
| Release candidate (at least one) | vX.Y.0rcN |
release/X.Y |
v0.5.0rc1 |
v1.3.0rc1 |
| Final | vX.Y.0 |
release/X.Y |
v0.5.0 |
v1.3.0 |
| Patch | vX.Y.Z |
release/X.Y |
v0.5.1 |
v1.3.1 |
Patch releases (X.Y.Z with Z > 0) never have alphas, betas or release candidates,
before or after 1.0: merging their release PR ships them directly.
Public functionality is deprecated before it is removed: it keeps working and emits a
DeprecationWarning naming the replacement and the earliest version that removes it, for
at least one minor release (from 1.0 on, until the next major release). The removal is
then a breaking change with migration notes. Names starting with _ and anything
documented as experimental are exempt.