Skip to main content
zerv is designed to run next to semantic-release, not instead of it. Split the work by branch:
  • semantic-release owns main. It reads conventional commits, decides the release version, writes the changelog, tags, and publishes.
  • zerv owns every other branch. Pull requests, feature branches, develop, release branches, dirty working trees: each Git state gets a SemVer on the spot, computed from tags, distance, branch, and dirtiness alone.
Release tools answer what version is this release? CI builds artifacts on every push, and those builds need versions long before a release exists. zerv answers what version is this exact Git state?
  • Every commit versioned - a version for any commit on any branch, including uncommitted changes. No build is ever unversioned.
  • Branch-based pre-releases - zerv flow maps branch patterns to pre-release types (develop and beta/* → beta, release/* → rc, everything else → alpha), so artifact names carry where they came from.
  • One payload, every format - generate ZERV RON once, then convert to SemVer, PEP440, CalVer, docker tags, v-prefixed major tags. Anything expressible as a schema or Tera template.

Both tools in one repository

zerv’s own repository runs both in its CD pipeline (cd.yml): semantic-release publishes the release, then zerv versions the same commit for artifact naming. The zerv-flow demonstration repo shows the full split. On pull requests, zerv runs alone: it versions the PR head, tags a pre-release, and feeds semver, PEP440, and docker tags to the deploy jobs. On main, semantic-release publishes and zerv versions the release build. See coexisting with semantic-release for the workflow wiring.

The core trade-off

zerv deliberately does not read commit messages or automate releases. It computes versions from VCS state (tags, distance, branch, dirtiness) and gets out of the way. That makes it:
  • Deterministic - the same Git state always yields the same version, regardless of commit message style.
  • Complementary - it runs alongside release automation instead of competing with it. See coexisting with semantic-release.
  • Language-agnostic - one Rust binary versions your Docker images, Python packages, Rust crates, and deployment manifests identically.

Same state, every format

One ZERV RON payload converts to whatever each pipeline stage needs:

When to reach for something else

  • You want commit-message parsing, changelogs, and publishing in one tool: use semantic-release, or run both.
  • You only need a version inside a Python package build: setuptools-scm already lives in that ecosystem.
  • You need a zero-install answer on a bare machine: git describe is always there, as long as its v1.0.0-5-gabc1234 shape is acceptable.