Release Process
fVDB uses a simplified OneFlow branching model with short-lived release branches.
Branching Model
main is the single long-lived default branch. It always contains the latest
development code. Release branches (release/vX.Y) are created for
stabilization. At release time, an adopt branch (adopt/vX.Y) reconciles
the version in pyproject.toml and merges the release work back into main,
keeping the release branch available for future hotfix releases. Hotfix
releases (PATCH > 0) reuse the same release branch but do not create an
adopt branch – hotfix changes are assumed to already be on main (via
cherry-pick) or to be specific to that minor release.
main: ──A──B──C──D──────────G──H── ...
\ / \
release/v0.4: E──F──T─────/─────P──Q──U
\ /
adopt/v0.4: V─┘
(v0.4.0) (v0.4.1)
A, B: normal development on
mainB: burndown begins;
release/v0.4branches offC:
mainversion bumped to next.dev0D: new feature merged to
main(not included in the release)E, F: bug fixes or pre-burndown PRs merged to the release branch
T: release tag
v0.4.0created on the release branchV: adopt branch created from
T; version set to matchmainG: merge commit bringing release fixes back into
mainviaadopt/v0.4H: development continues
P: version bumped to
0.4.1on the release branch (start-release.sh 0.4.1)Q: cherry-picked fix
U: release tag
v0.4.1created on the release branch
Branch Naming
Purpose |
Pattern |
Example |
|---|---|---|
Release |
|
|
Adopt (minor releases only) |
|
|
Version Management
The version in pyproject.toml is the single source of truth.
Branch |
Version |
Example |
|---|---|---|
|
|
|
|
|
|
|
|
|
|
|
|
The .dev0 suffix on main is a PEP 440
pre-release marker that signals unreleased development code. It does not affect
nightly builds, which override the version entirely.
Timeline
A typical release takes about one week:
Phase |
Duration |
What happens |
|---|---|---|
Burndown start |
Day 0 |
Create release branch, bump |
Burndown |
~4-6 days |
Stabilize: fix bugs on the release branch, continue features on |
Code freeze |
1-3 days |
Only critical fixes on the release branch (admin merge only) |
Release day |
Day ~7 |
Tag, create adopt branch + PR, create GitHub Release |
Procedures
Starting a Release (Burndown)
Run from a clean, up-to-date checkout of main:
./devtools/start-release.sh 0.4.0
This will:
Create
release/v0.4from currentmainSet the version to
0.4.0on the release branch (bothpyproject.tomlandfvdb_core_stable_versionindocs/conf.py)Bump
mainto0.5.0.dev0Push both branches to
upstreamOpen a draft PR from
release/v0.4intomain(tracks burndown; will be closed byfinish-release.shand replaced by an adopt PR)
Use --remote origin to push to a different remote.
Use --dry-run to preview without making changes.
During Burndown
Once the release branch exists, PR targeting rules change:
New PRs opened during burndown target
mainby default and will ship in the following release. If a PR is needed in the current release, it must target the release branch directly and requires maintainer approval.PRs opened before burndown that have not yet merged should be triaged during burndown planning. Decide whether each open PR is needed in the current release and retarget it to the release branch if so. After merging, if the change is also needed immediately on
main, cherry-pick the squash-merged commit from the release branch back ontomain:git checkout main git cherry-pick <commit-sha>
This may cause a minor conflict when the adopt branch is merged back into
main, but the content will be nearly identical and easy to resolve.New features continue targeting
mainas usual.
Code Freeze
Tighten branch protection on release/v0.4:
No new PRs to the release branch except approved critical fixes
Require admin approval for merges
This is a manual GitHub settings change, not automated by the scripts.
Finishing a Release
On release day:
./devtools/finish-release.sh 0.4.0
This will:
Verify the publish workflow passed on the release branch
Tag
v0.4.0on the HEAD ofrelease/v0.4Push the tag
Create
adopt/v0.4fromrelease/v0.4with a commit that sets the version inpyproject.tomlto matchmain(e.g.0.5.0.dev0)Push
adopt/v0.4Close the draft release PR
Open a new PR from
adopt/v0.4intomainCreate a GitHub Release (triggers the publish workflow)
Trigger the
sync-doc-version.ymlworkflow to create a PR updatingdocs/conf.pyto the new release version
After the script finishes, merge the adopt PR once CI passes. Use a
merge commit (not squash) to preserve the release branch history on main.
The release/v0.4 branch is left untouched at version 0.4.0, available
as the base for future hotfix releases.
Creating the GitHub Release triggers Read the Docs to build versioned
documentation for the new tag automatically. The /en/stable/ alias updates
to point to the highest semver tag. No separate documentation deployment
step is needed.
Optionally, merge the doc version sync PR created by
sync-doc-version.yml. This updates fvdb_core_stable_version in
docs/conf.py on main, which affects install command examples shown on
the /en/latest/ docs build. This is not urgent since versioned docs are
built directly from the tag.
Use --remote origin to target a different remote.
Use --dry-run to preview without making changes.
Hotfix Releases
The same scripts handle hotfix releases. Pass a version with PATCH > 0
(e.g. 0.4.1) to enter hotfix mode. Hotfix releases do not create an
adopt branch or PR to merge changes back into main – the fixes should
already be on main (the commits for the hotfix should have been cherry-picked from main) or be specific to the minor version.
Start the hotfix:
./devtools/start-release.sh 0.4.1
This verifies that
release/v0.4is at thev0.4.0tag, bumps the version to0.4.1, and leaves you on the release branch ready to apply fixes. For successive hotfixes (e.g.0.4.2), the script verifies the branch is at the previous hotfix tag (v0.4.1).Cherry-pick or apply fixes:
git cherry-pick <commit-sha>
Push the release branch to trigger the publish workflow:
git push upstream release/v0.4
Wait for CI, then finish the hotfix:
./devtools/finish-release.sh 0.4.1
This tags
v0.4.1, creates a GitHub Release, and triggers thesync-doc-version.ymlworkflow to updatedocs/conf.py.Optionally merge the doc version sync PR once CI passes. This updates install examples on
/en/latest/but is not required for the versioned tag docs, which RTD builds automatically.
GitHub Branch Protection
Recommended settings for release/v* branches during burndown:
Require pull request reviews before merging
Require status checks to pass
Require signed commits
During code freeze, additionally:
Restrict who can push (admin only)
Require approval from a code owner
Script Reference
Script |
Purpose |
|---|---|
|
Create release branch (or prepare hotfix), bump versions, open PR |
|
Tag release, create adopt branch + PR (minor only), create GitHub Release |
|
End-to-end tests for the release scripts (including hotfix) |
All scripts support --help, --dry-run, and --remote <name> flags.
Using with Other Repositories
The scripts live in fvdb-core but work with any repository that has a
version = "..." line in pyproject.toml. They detect the target repository
from the current working directory (git rev-parse --show-toplevel).
To release fvdb-reality-capture, run the scripts from inside that repo:
cd /path/to/fvdb-reality-capture
/path/to/fvdb-core/devtools/start-release.sh 0.4.0
Automated Release Validation
Both fvdb-core and fvdb-reality-capture have publish.yml workflows that
auto-trigger on pushes to release/v* branches. This provides continuous
validation during the burndown period.
What Happens Automatically
When code is pushed to a release branch (e.g. release/v0.4):
fvdb-core:
publish.ymlbuilds wheels for all Python/Torch/CUDA combinations in the matrix, uploads them to the S3 staging index (simple-staging), and runs GPU validation (smoke test + unit tests) on each variant.fvdb-reality-capture:
publish.ymlbuilds a pure-Python wheel, uploads it to S3 staging, then runs GPU validation that installs fvdb-core from S3 staging to test the two packages together.
S3 Staging Index
Release candidate wheels are published to the staging index at:
https://fvdb-packages.s3.us-east-2.amazonaws.com/simple-staging/
This allows manual testing before the final release. Staging wheels older than 30 days are automatically pruned.
Cross-Repository Lockstep Releases
fvdb-core and fvdb-reality-capture are released in lockstep. The procedure is:
Start burndown in fvdb-core first:
cd /path/to/fvdb-core ./devtools/start-release.sh 0.4.0
Wait for the push to trigger the publish workflow and confirm wheels appear in S3 staging.
Start burndown in fvdb-reality-capture:
cd /path/to/fvdb-reality-capture /path/to/fvdb-core/devtools/start-release.sh 0.4.0
The fvdb-reality-capture validation will install fvdb-core from S3 staging, verifying cross-package compatibility.
Finish fvdb-core first, then fvdb-reality-capture:
cd /path/to/fvdb-core ./devtools/finish-release.sh 0.4.0 cd /path/to/fvdb-reality-capture /path/to/fvdb-core/devtools/finish-release.sh 0.4.0
After each
finish-release.shrun, merge the resultingadopt/v*PR on GitHub, deleting theadopt/v*branch once CI passes. We keep the correspondingrelease/vX.Ybranch for any future hotfix releases (PATCH > 0), reusing the same release branch rather than creating separate hotfix branches.Optionally merge the doc version sync PRs created by
sync-doc-version.yml. This updates install examples on/en/latest/but is not required since Read the Docs builds versioned docs from each tag directly.
finish-release.sh checks that the latest publish.yml run on the release
branch succeeded before proceeding. If the workflow failed or hasn’t run, it
prompts for confirmation.
Workflow Dispatch
Both workflows also support manual triggering via workflow_dispatch with
options to select the publish target (s3, testpypi, none) and whether
to run GPU validation.
Versioned Documentation (Read the Docs)
Documentation is hosted on Read the Docs with automatic version management:
Tag builds: When a GitHub Release is created, RTD’s automation rules detect the new semver tag and build versioned docs for it (e.g.
/en/v0.4.2/). The/en/stable/alias automatically points to the highest semver tag.Latest: The
/en/latest/build tracks themainbranch and is rebuilt on every push.Version switcher: RTD provides a built-in flyout menu on every page for switching between versions.
The sync-doc-version.yml workflow keeps fvdb_core_stable_version in
docs/conf.py in sync with the latest GitHub Release. This variable drives
install command examples shown in the documentation. The workflow runs:
Nightly (cron schedule) as a safety net
On demand via
workflow_dispatch, triggered automatically byfinish-release.shafter creating a GitHub Release
When the doc version is out of date, the workflow creates (or updates) a PR
on the auto/sync-doc-version branch using devtools/update-doc-versions.sh.
Merging this PR triggers an RTD rebuild of /en/latest/ to pick up the
updated install examples.