Dynamic versioning CLI tool
Project description
zerv
Automatic versioning for every commit - Generate semantic versions from any commit across all branches, or dirty working directory, with seamless pre-release handling and flexible format support for any CI/CD workflow.
Table of Contents
Quick Start
Smart Version Detection: zerv flow automatically generates meaningful SemVer versions from any Git state - no manual configuration required for common workflows.
# Install (Python via uv)
uv tool install zerv-version
# Try automated versioning (current branch determines output)
zerv flow
# → 1.0.0 (on main branch with tag v1.0.0)
# → 1.0.1-rc.1.post.3 (on release branch with pre-release tag)
# → 1.0.1-beta.1.post.3+develop.3.gf297dd0 (on develop branch)
# → 1.0.1-alpha.59394.post.1+feature.new.auth.1.g4e9af24 (on feature branch)
# → 1.0.1-alpha.17015.post.1.dev.1764382150+feature.dirty.work.1.g54c499a (on dirty feature branch)
- Multiple Format Generation: Transform a single ZERV_RON output into various formats (see
.github/workflows/shared-zerv-versioning.ymlfor example implementation)
# (on dirty feature branch)
ZERV_RON=$(zerv flow --output-format zerv)
# semver
echo $ZERV_RON | zerv version --source stdin --output-format semver
# → 1.0.1-alpha.17015.post.1.dev.1764382150+feature.dirty.work.1.g54c499a
# pep440
echo $ZERV_RON | zerv version --source stdin --output-format pep440
# → 1.0.0a17015.post1.dev1764382150+feature.dirty.work.1.g54c499a
# docker_tag
echo $ZERV_RON | zerv version --source stdin --output-template "{{ semver_obj.docker }}"
# → 1.0.1-alpha.17015.post.1.dev.1764382150-feature.dirty.work.1.g54c499a
# v_semver
echo $ZERV_RON | zerv version --source stdin --output-prefix v --output-format semver
# → v1.0.1-alpha.17015.post.1.dev.1764382150+feature.dirty.work.1.g54c499a
# v_major (schema-based approach)
echo $ZERV_RON | \
zerv version --source stdin \
--schema-ron '(core:[var(Major)], extra_core:[], build:[])' \
--output-prefix v --output-format pep440
# → v1
# v_major_minor (schema-based approach)
echo $ZERV_RON | \
zerv version --source stdin \
--schema-ron '(core:[var(Major), var(Minor)], extra_core:[], build:[])' \
--output-prefix v --output-format pep440
# → v1.0
# v_major_custom (custom template-based approach)
echo $ZERV_RON | zerv version --source stdin --output-template "v{{ major | default(value=\"0\") }}"
# → v1
# v_major_minor_custom (custom template-based approach)
echo $ZERV_RON | zerv version --source stdin --output-template "v{{ major | default(value=\"0\") }}{{ prefix_if(value=minor, prefix=\".\") }}"
# → v1.0
Key Features
- zerv version: Flexible, configurable version generation with full control
- zerv flow: Opinionated, automated pre-release management based on Git branches
- Smart Schema System: Auto-detects clean releases, pre-releases, and build context
- Multiple Formats: SemVer, PEP440 (Python), CalVer, custom schemas
- CI/CD Integration: Complements semantic release with branch-based pre-releases and full override control
Usage Examples
zerv flow: Automated branch-based versions
Purpose: Intelligent pre-release management that automatically generates meaningful versions from any Git state without manual decisions.
Core Principles
- Semantic state capture - Extract semantic meaning from ANY Git state (any branch, any commit, uncommitted changes)
- Multi-format output - Transform semantic meaning into various version formats with customizable format support
- Seamless semantic release integration - Work with semantic release tools while providing fully automated pre-release versioning
- Build traceability - Include sufficient context to trace versions back to exact Git states
Version Format Explained
Full Example: 1.0.1-alpha.12345.post.3.dev.1729924622+feature.auth.1.f4a8b9c
Structure: <BASE>-<PRE_RELEASE>.<POST>[.<DEV>][+BUILD_CONTEXT]
1.0.1- Base version (semantic meaning from tags)alpha.12345- Pre-release type and branch identificationpost.3- Commits since reference point[.dev.timestamp]- Optional dev timestamp for uncommitted changes[+BUILD_CONTEXT]- Optional build context for traceability
Key Point: The core version <BASE>-<PRE_RELEASE>.<POST>[.<DEV>] contains all semantic meaning needed to understand Git state. The build context [+BUILD_CONTEXT] is optional and provides additional verbose information for easier interpretation and traceability.
Version Variations:
- Tagged release:
1.0.1 - Tagged pre-release:
2.0.1-rc.1.post.2 - Branch from Tagged release:
1.0.1-alpha.54321.post.1+feature.login.1.f4a8b9c - Branch from Tagged pre-release:
2.0.1-alpha.98765.post.3+fix.auth.bug.1.c9d8e7f - Uncommitted changes:
2.0.1-alpha.98765.post.4.dev.1729924622+fix.auth.bug.1.c9d8e7f
Pre-release Resolution Strategy
Default behavior: All branches start as alpha.<hash-id> (hash-based identification)
Configurable branch patterns: Users can configure specific branches to use custom pre-release types (alpha, beta, rc) with optional numbers:
- Example:
feature/user-authbranch →beta.12345(label only, uses hash-based number) - Example:
developbranch →beta.1(label and custom number for stable branches) - Any branch can be mapped to any pre-release type (alpha, beta, rc) with hash-based or custom numbers
Branch name resolution: Extract pre-release information from branch name patterns:
-
Example:
release/1/feature-auth-fix→rc.1(extracts number from branch pattern) -
Simplified GitFlow-inspired naming conventions
-
Note: Branch names are conventions, not strict requirements - Zerv provides flexible pattern matching and user configuration.
Clean branches: main, master → No pre-release (clean releases)
Post-release resolution logic:
- Configurable post representation with two options:
- Tag Distance: Count commits from last tag
- Commit Distance: Count commits from branch creation point
- Default: Tag Distance (most common use case)
post.0: Exactly on reference point (no commits since)post.N: N commits since reference point- Consistent across all branch types (alpha, beta, rc, etc.)
Examples:
Tag Distance (release branches):
main: v1.0.0 (tag)
└── release/1 (created) → create tag v1.0.1-rc.1.post.1
└── 1 commit → 1.0.1-rc.1.post.1.dev.1729924622 (same post, dev timestamp)
└── 2 commits → 1.0.1-rc.1.post.1.dev.1729924623 (same post, dev timestamp)
└── create tag → 1.0.1-rc.1.post.2 (new tag increments post)
└── more commits → 1.0.1-rc.1.post.2.dev.1729924624 (new post, dev timestamp)
Commit Distance (develop branch):
main: v1.0.0 (tag)
└── develop (created from v1.0.0) → commit 1.0.1-beta.1.post.1 (1 commits since branch creation)
└── 5 commits later → 1.0.1-beta.1.post.6 (6 commits since branch creation)
└── 1 more commit → 1.0.1-beta.1.post.7 (7 commits since branch creation)
Workflow Examples
This section demonstrates how Zerv Flow works across different branching strategies and Git scenarios.
Note: To keep diagrams clean and readable, build context is omitted from version strings in the examples. Dirty state (.dev.timestamp) is shown in diagrams when applicable.
Example: A commit appears as 1.0.1-alpha.12345.post.3.dev.1729924622 in the diagrams. With build context enabled: 1.0.1-alpha.12345.post.3.dev.1729924622+feature.user-auth.3.a1b2c3d
Trunk-Based Development
Purpose: Complex trunk-based workflow with parallel features, nested branches, and synchronization scenarios.
Scenario: Development from v1.0.0 with parallel feature branches, synchronization, and nested development.
---
config:
logLevel: 'debug'
theme: 'base'
---
gitGraph
%% Step 1: Initial commit on main with v1.0.0 tag
commit id: "1.0.0"
%% Step 2: Create parallel feature branches feature-1 and feature-2 from main
branch feature-1 order: 2
branch feature-2 order: 3
%% Step 3: feature-2: Start development with dirty state
checkout feature-2
commit type:REVERSE id: "1.0.1-alpha.68031.post.0.dev.{timestamp}" tag: "uncommitted"
%% Step 4: feature-2: Create first commit
commit id: "1.0.1-alpha.68031.post.1"
%% Step 5: feature-1: Create commits (parallel development)
checkout feature-1
commit id: "1.0.1-alpha.42954.post.1"
commit id: "1.0.1-alpha.42954.post.2"
%% Step 6: feature-1: Merge to main and release v1.0.1
checkout main
merge feature-1 id: "1.0.1" tag: "feature-1 released"
%% Step 7: feature-2: Sync with main to get feature-1 changes
checkout feature-2
merge main id: "1.0.2-alpha.68031.post.2"
%% Step 8: feature-2: Create additional commit
commit id: "1.0.2-alpha.68031.post.3"
%% Step 9: feature-3: Branch from feature-2 for sub-feature development
branch feature-3 order: 4
checkout feature-3
commit id: "1.0.2-alpha.14698.post.4"
%% Step 10: feature-3: Continue development with dirty state
commit type:REVERSE id: "1.0.2-alpha.14698.post.4.dev.{timestamp}" tag: "uncommitted"
%% Step 11: feature-3: Continue development with commits
commit id: "1.0.2-alpha.14698.post.5"
commit id: "1.0.2-alpha.14698.post.6"
%% Step 12: feature-2: Merge feature-3 back to continue development
checkout feature-2
merge feature-3 id: "1.0.2-alpha.68031.post.6" tag: "feature-3 merged"
%% Step 13: feature-2: Final development before release
commit id: "1.0.2-alpha.68031.post.7"
%% Step 14: Final release: feature-2 merges to main and releases v1.1.0
checkout main
merge feature-2 id: "1.1.0" tag: "feature-2 released"
Key behaviors demonstrated:
- Parallel development:
feature-1andfeature-2get unique hash IDs (42954,68031) - Version progression: Base version updates when syncing (
1.0.1→1.0.2) - Dirty state: Uncommitted changes show
.dev.timestampsuffix - Nested branches:
feature-3branches fromfeature-2with independent versioning - Clean releases: Main branch maintains semantic versions on merges
GitFlow Branching Strategy
Purpose: GitFlow methodology with proper pre-release type mapping and merge patterns.
Scenario: Main branch with v1.0.0, develop branch integration, feature development, hotfix emergency flow, and release preparation.
---
config:
logLevel: 'debug'
theme: 'base'
---
gitGraph
%% Step 1: Initial state: main and develop branches
commit id: "1.0.0"
%% Step 2: Create develop branch with initial development commit
branch develop order: 3
checkout develop
commit id: "1.0.1-beta.1.post.1"
%% Step 3: Feature development from develop branch
branch feature/auth order: 4
checkout feature/auth
commit id: "1.0.1-alpha.92409.post.2"
commit id: "1.0.1-alpha.92409.post.3"
checkout develop
%% Step 4: Merge feature/auth back to develop
merge feature/auth id: "1.0.1-beta.1.post.3" tag: "feature merged"
%% Step 5: Hotfix emergency flow from main
checkout main
branch hotfix/critical order: 1
checkout hotfix/critical
commit id: "1.0.1-alpha.11477.post.1"
checkout main
%% Step 6: Merge hotfix to main and release v1.0.1
merge hotfix/critical id: "1.0.1" tag: "hotfix released"
%% Step 7: Sync develop with main changes and continue development
checkout develop
merge main id: "1.0.2-beta.1.post.4" tag: "sync main"
%% Step 8: Continue development on develop branch
commit id: "1.0.2-beta.1.post.5"
%% Step 9: Release branch preparation
branch release/1 order: 2
checkout release/1
commit id: "1.0.2-rc.1.post.1"
commit id: "1.0.2-rc.1.post.2"
commit type:REVERSE id: "1.0.2-rc.1.post.3.dev.{timestamp}" tag: "uncommitted"
commit id: "1.0.2-rc.1.post.3"
checkout main
%% Step 10: Final release: merge release/1 to main
merge release/1 id: "1.1.0" tag: "release 1.1.0"
%% Step 11: Sync develop with release and prepare for next cycle
checkout develop
merge main id: "1.1.1-beta.1.post.1" tag: "sync release"
Key behaviors demonstrated:
- Beta pre-releases: Develop branch uses
betafor integration builds - Alpha pre-releases: Feature branches use
alphawith hash-based identification - RC pre-releases: Release branches use
rcfor release candidates - Clean releases: Main branch maintains clean versions without pre-release suffixes
- Hotfix flow: Emergency fixes from main with proper version propagation
- Branch synchronization: Develop branch syncs with main releases
Complex Release Management
Purpose: Complex release branch scenarios including branch abandonment and cascading release preparation.
Scenario: Main branch with v1.0.0, release branch preparation with critical issues leading to abandonment, and selective branch creation for successful release.
---
config:
logLevel: 'debug'
theme: 'base'
---
gitGraph
%% Step 1: Initial state: main branch with v1.0.0 tag
commit id: "1.0.0" tag: "v1.0.0"
%% Step 2: Create release/1 from main for next release preparation
branch release/1 order: 2
checkout release/1
commit id: "1.0.1-rc.1.post.1"
commit id: "1.0.1-rc.1.post.2"
%% Step 3: Create release/2 from the second commit of release/1 (before issues)
%% release/1 at this point: 1.0.1-rc.1.post.2, so release/2 continues from there
checkout release/1
branch release/2 order: 1
checkout release/2
commit id: "1.0.1-rc.2.post.3"
%% Step 4: Go back to release/1 and add the problematic third commit (issues found)
checkout release/1
commit id: "1.0.1-rc.1.post.3" tag: "issues found"
%% Step 5: release/2 completes preparation successfully
checkout release/2
commit id: "1.0.1-rc.2.post.4"
%% Step 6: Merge release/2 to main and release v1.1.0
checkout main
merge release/2 id: "1.1.0" tag: "v1.1.0"
Version progression details:
- release/1:
1.0.1-rc.1.post.1→1.0.1-rc.1.post.2→1.0.1-rc.1.post.3(abandoned) - release/2: Created from
release/1's second commit (1.0.1-rc.1.post.2), continues as1.0.1-rc.2.post.3→1.0.1-rc.2.post.4 - Main: Clean progression
1.0.0→1.1.0(only from successfulrelease/2merge)
Key behaviors demonstrated:
- Branch isolation: Each release branch maintains independent versioning regardless of parent/child relationships
- Selective branching: Zerv Flow correctly handles branches created from specific historical commits
- Abandonment handling: Unmerged branches don't affect final release versions on main
- Cascade management: Complex branching scenarios where releases feed into other releases are handled transparently
- Clean main branch: Main only receives versions from successfully merged releases, maintaining clean semantic versioning
Schema Variants: 10+ Standard Schema Presets
Purpose: Complete control over version generation with 20+ schema presets and extensive customization options.
Schema Selection Examples:
zerv flow --schema standard-base
# → 1.0.1 (test case 1)
zerv flow --schema standard-base-context
# → 1.0.1+branch.name.g4e9af24 (test case 2)
zerv flow --schema standard-base-prerelease
# → 1.0.1-alpha.10192 (test case 3)
zerv flow --schema standard-base-prerelease-context
# → 1.0.1-alpha.10192+branch.name.1.g4e9af24 (test case 4)
zerv flow --schema standard-base-prerelease-post
# → 1.0.1-alpha.10192.post.1 (test case 5)
zerv flow --schema standard-base-prerelease-post-context
# → 1.0.1-alpha.10192.post.1+branch.name.1.g4e9af24 (test case 6)
zerv flow --schema standard-base-prerelease-post-dev
# → 1.0.1-alpha.10192.post.1.dev.1764382150 (test case 7)
zerv flow --schema standard-base-prerelease-post-dev-context
# → 1.0.1-alpha.10192.post.1.dev.1764382150+branch.name.1.g4e9af24 (test case 8)
zerv flow --schema standard
# → 1.0.0 (clean main - test case 9)
# → 1.0.1-rc.1 (release branch - test case 10)
# → 1.0.1-alpha.10192.post.1+branch.name.1.g4e9af24 (feature branch - test case 11)
# → 1.0.1-alpha.10192.post.1.dev.1764382150+branch.name.1.g4e9af24 (dirty feature branch - test case 12)
zerv flow --schema standard-no-context
# → 1.0.0 (clean main - test case 13)
# → 1.0.1-rc.1 (release branch - test case 14)
# → 1.0.1-alpha.10192.post.1 (feature branch - test case 15)
# → 1.0.1-alpha.10192.post.1.dev.1764382150 (dirty feature branch - test case 16)
zerv flow --schema standard-context
# → 1.0.0+main.g4e9af24 (clean main - test case 17)
# → 1.0.1-rc.1+release.1.do.something.g4e9af24 (release branch - test case 18)
# → 1.0.1-alpha.10192.post.1+branch.name.1.g4e9af24 (feature branch - test case 19)
# → 1.0.1-alpha.10192.post.1.dev.1764382150+branch.name.1.g4e9af24 (dirty feature branch - test case 20)
Branch Rules: Configurable Pattern Matching
Purpose: Map branch names to pre-release labels, numbers, and post modes for automated version generation.
Default GitFlow Rules:
[
(pattern: "develop", pre_release_label: beta, pre_release_num: 1, post_mode: commit),
(pattern: "release/*", pre_release_label: rc, post_mode: tag)
]
Pattern Matching:
- Exact:
"develop"matches only"develop" - Wildcard:
"release/*"matches"release/1","release/42","release/1/feature", etc. - Number extraction:
- With numbers:
release/1→rc.1,release/1/feature→rc.1 - Without numbers:
release/feature→rc.<hash-id>(fallback to hash-based identification)
- With numbers:
- Other branches:
*,feature/*,hotfix/*,bugfix/*, etc. →alpha.<hash-id>(fallback to hash-based identification)
Examples:
# Default GitFlow behavior
zerv flow
# → 1.0.1-rc.1.post.1+release.1.do.something.1.g3a2b1c4 (release/1/do-something branch - test case 1)
# → 1.0.1-beta.1.post.1+develop.1.g8f7e6d5 (develop branch - test case 2)
# → 1.0.1-alpha.10192.post.1+branch.name.1.g9d8c7b6 (feature branch - test case 3)
# → 1.0.1-rc.48993.post.1+release.do.something.1.g5e4f3a2 (release/do-something branch - test case 4)
# Custom branch rules
zerv flow --branch-rules '[
(pattern: "staging", pre_release_label: rc, pre_release_num: 1, post_mode: commit),
(pattern: "qa/*", pre_release_label: beta, post_mode: tag)
]'
# → 1.0.1-rc.1.post.1+staging.1.g2c3d4e5 (staging branch - test case 5)
# → 1.0.1-beta.123.post.1+qa.123.1.g7b8c9d0 (qa branch - test case 6)
# → 1.0.1-alpha.20460.post.1+feature.new.feature.1.g1d2e3f4 (feature branch - test case 7)
Configuration:
pattern: Branch name (exact) or wildcard (/*)pre_release_label:alpha,beta, orrcpre_release_num: Explicit number (exact) or extracted (wildcard)post_mode:commit(count commits) ortag(count tags)
Override Controls: Complete Version Customization
Override Options: VCS, version components, and pre-release controls
# VCS Overrides
zerv flow --tag-version "v2.1.0-beta.1" # Override tag version
# → 2.1.0
zerv flow --distance 42 # Override distance from tag
# → 1.0.1-alpha.60124.post.42+feature.test.42.g8f4e3a2
zerv flow --dirty # Force dirty=true
# → 1.0.1-alpha.18373.dev.1729927845+feature.dirty.ga1b2c3d
zerv flow --no-dirty # Force dirty=false
# → 1.0.0+feature.clean.g4d5e6f7
zerv flow --clean # Force clean state (distance=0, dirty=false)
# → 1.0.0+feature.clean.force.g8a9b0c1
zerv flow --bumped-branch "release/42" # Override branch name
# → 1.0.1-rc.42.post.1+release.42.1.g2c3d4e5
zerv flow --bumped-commit-hash "a1b2c3d" # Override commit hash
# → 1.0.1-alpha.48498.post.1+feature.hash.1.a1b2c3d
zerv flow --bumped-timestamp 1729924622 # Override timestamp
# → 1.0.1-alpha.18321.dev.1764598322+feature.timestamp.g7f8e9a0
# Version Component Overrides
zerv flow --major 2 # Override major
# → 2.0.0
zerv flow --minor 5 # Override minor
# → 1.5.0
zerv flow --patch 3 # Override patch
# → 1.0.3
zerv flow --epoch 1 # Override epoch
# → 1.0.0-epoch.1
zerv flow --post 7 # Override post
# → 1.0.1-alpha.15355.post.8+feature.post.1.g6b7c8d9 (post affects build context)
# Pre-release Controls
zerv flow --pre-release-label rc # Set pre-release type
# → 1.0.1-rc.10180.post.1+feature.pr.label.1.g3d4e5f6
zerv flow --pre-release-num 3 # Set pre-release number
# → 1.0.1-alpha.3.post.1+feature.pr.num.1.g9a0b1c2
zerv flow --post-mode commit # Set distance calculation method
# → 1.0.1-alpha.17003.post.1+feature.post.mode.1.g1d2e3f4
Usage Examples:
# VCS overrides
zerv flow --tag-version "v2.0.0" --distance 5 --bumped-branch "release/candidate"
# → 2.0.1-rc.71808.post.1+release.candidate.5.gb2c3d4e
# Version component overrides
zerv flow --major 2 --minor 5 --patch 3
# → 2.5.3
# Mixed overrides: VCS + version components
zerv flow --distance 3 --major 2 --minor 1
# → 2.1.1-alpha.60124.post.3+feature.test.3.g8f4e3a2
# Clean release with overrides
zerv flow --clean --major 2 --minor 0 --patch 0
# → 2.0.0+feature.clean.force.g8a9b0c1
# Complex multi-override scenario
zerv flow --tag-version "v1.5.0-rc.1" --bumped-commit-hash "f4a8b9c" --major 1 --minor 6
# → 1.6.0-alpha.11178.post.2+dev.branch.2.f4a8b9c
zerv version: Manual control with 4 main capability areas
Purpose: Complete manual control over version generation with flexible schema variants and granular customization options.
Note: Unlike zerv flow, zerv version generates versions as-is without opinionated auto-bumping logic. It does not automatically increment post-counts based on commits or tags, nor does it derive pre-release labels and numbers from branch patterns. This is general-purpose version generation without opinionated logic.
Schema Variants: 20+ presets (standard, calver families) and custom RON schemas
Purpose: Choose from 20+ predefined version schemas or create custom RON-based schemas for complete format control.
Schema Selection Examples:
zerv version --schema standard-base
# → 1.0.0 (test case 1)
zerv version --schema standard-base-context
# → 1.0.0+branch.name.1.g4e9af24 (test case 2)
zerv version --schema standard-base-prerelease
# → 1.0.0-alpha.1 (test case 3)
zerv version --schema standard-base-prerelease-post-dev-context
# → 1.0.0-alpha.1.post.5.dev.123+branch.name.1.g4e9af24 (test case 4)
zerv version --schema calver-base-prerelease-post-dev-context
# → 2025.12.4-0.alpha.1.post.5.dev.123+branch.name.1.g4e9af24 (test case 5)
# Custom RON Schemas
zerv version --schema-ron '(core:[var(Major), var(Minor), var(Patch)], extra_core:[], build:[])'
# → 1.0.0 (test case 6)
zerv version --schema-ron '(core:[var(Major), var(Minor), var(Patch)], extra_core:[], build:[str("build.id")])'
# → 1.0.0+build.id (test case 7)
zerv version --schema-ron '(
core: [var(Major), var(Minor), var(Patch)],
extra_core: [var(PreRelease), var(Post), var(Dev)],
build: [var(BumpedBranch), var(Distance), var(BumpedCommitHashShort)]
)'
# → 1.0.0-alpha.1.post.5.dev.123+branch.name.1.g4e9af24 (test case 8, equivalent to standard-base-prerelease-post-dev-context)
zerv version --schema-ron '(
core: [var(ts("YYYY")), var(ts("MM")), var(ts("DD"))],
extra_core: [var(PreRelease), var(Post), var(Dev)],
build: [var(BumpedBranch), var(Distance), var(BumpedCommitHashShort)]
)'
# → 2025.12.4-0.alpha.1.post.5.dev.123+branch.name.1.g{hex:7} (test case 9, equivalent to calver-base-prerelease-post-dev-context)
Schema Architecture: All schemas resolve to the internal ZervSchema struct with three required components:
core: Primary version components (e.g.,[Major, Minor, Patch]for SemVer)extra_core: Additional version components (e.g., pre-release, post-release, dev)build: Build metadata components (e.g., commit hash, branch name, build info)
Schema Resolution: Preset schemas (standard-base, calver-*, etc.) are predefined ZervSchema objects that adapt based on repository state. RON schemas are parsed from text into the same ZervSchema structure, providing identical functionality with custom definitions.
Examples:
- Test case 8: RON schema equivalent to
standard-base-prerelease-post-dev-context(test case 4) - Test case 9: RON schema equivalent to
calver-base-prerelease-post-dev-context(test case 5), demonstrating date formatting withvar(ts("YYYY"))
VCS Overrides: Override tag version, distance, dirty state, branch, commit data
Purpose: Override any VCS (Version Control System) detected values for complete control over version components.
zerv version --tag-version "v2.1.0-beta.1"
# → 2.1.0-beta.1+branch.name.1.g4e9af24 (test case 1)
zerv version --distance 42
# → 1.0.0-alpha.1.post.5.dev.123+branch.name.42.g8f4e3a2 (test case 2)
zerv version --dirty
# → 1.0.0-alpha.1.post.5.dev.123+branch.name.1.g4e9af24 (test case 3)
zerv version --bumped-branch "release/42"
# → 1.0.0-alpha.1.post.5.dev.123+release.42.1.g4e9af24 (test case 4)
Version Bumping: Field-based bumps (major/minor/patch) and schema-based bumps
Purpose: Increment version components using field-based or schema-based strategies.
zerv version --bump-major
# → 2.0.0 (test case 1)
zerv version --bump-minor
# → 1.1.0 (test case 2)
zerv version --bump-patch
# → 1.0.1 (test case 3)
zerv version --bump-major --bump-minor
# → 2.1.0 (test case 4)
zerv version --bump-core 0
# → 2.0.0 (test case 5, schema-based bump targeting core component index 0/major)
zerv version --bump-major --bump-minor --bump-patch
# → 2.1.1 (test case 6)
zerv version --bump-major 2
# → 3.0.0 (test case 7)
Component Overrides: Fine-grained control over individual version components
Purpose: Override specific version components while preserving all other detected values for precise version control.
Override Categories: Individual components, pre-release controls, and custom variables
# Version component overrides (major, minor, patch)
zerv version --major 2 --minor 5
# → 2.5.0+branch.name.1.g{hex:7} (test case 1)
# Pre-release component overrides (label and number)
zerv version --schema standard-base-prerelease-post-context --pre-release-label rc --pre-release-num 3
# → 1.0.0-rc.3+branch.name.1.g{hex:7} (test case 2)
# Additional component overrides (epoch, post, dev)
zerv version --schema standard-base-prerelease-post-dev-context --epoch 1 --post 7 --dev 456
# → 1.0.0-epoch.1.post.7.dev.456+branch.name.1.g{hex:7} (test case 3)
# Custom variables in schema-ron (requires schema-ron)
zerv version --schema-ron '(
core: [var(Major), var(Minor), var(Patch)],
extra_core: [],
build: [var(custom("build_id")), var(custom("environment"))]
)' --custom '{"build_id": "prod-123", "environment": "staging"}'
# → 1.0.0+prod.123.staging (test case 4)
Version Check: Validate version strings for different formats
Purpose: Validate that version strings conform to specific format requirements with support for multiple version standards.
# Check complex SemVer format validation
zerv check --format semver 1.0.0-rc.1.something.complex+something.complex
# → Version: 1.0.0-rc.1.something.complex+something.complex
# ✓ Valid SemVer format (test case 1)
# Check PEP440 format validation with build metadata
zerv check --format pep440 1.0.0a2.post5.dev3+something.complex
# → Version: 1.0.0a2.post5.dev3+something.complex
# ✓ Valid PEP440 format (test case 2)
# Check PEP440 format validation with normalization
zerv check --format pep440 1.0.0-alpha.2.post.5.dev.3+something.complex
# → Version: 1.0.0-alpha.2.post.5.dev.3+something.complex
# ✓ Valid PEP440 format (normalized: 1.0.0a2.post5.dev3+something.complex) (test case 3)
# Invalid version handling (fails with exit code 1)
zerv check --format semver invalid
# → Error: Invalid version: invalid - Invalid SemVer format (test case 4)
# Auto-detect and validate multiple formats
zerv check 2.1.0-beta.1
# → Version: 2.1.0-beta.1
# ✓ Valid PEP440 format (normalized: 2.1.0b1)
# ✓ Valid SemVer format (test case 5)
Input/Output & Piping: Shared capabilities for both commands
Purpose: Flexible input handling and output formatting with pipeline support for both zerv version and zerv flow commands.
# Source options - Use Git VCS or stdin for version data
zerv flow --source git
# → 1.0.1-alpha.10192.post.1.dev.1764382150+branch.name.1.g4e9af24 (VCS auto-detection)
# (test case 1)
# zerv RON format - Internal/debugging output and intermediate representation
# Used as stdin input for zerv version and zerv flow commands
zerv flow --output-format zerv
# → (
# schema: (
# core: [var(Major), var(Minor), var(Patch)],
# extra_core: [var(Epoch), var(PreRelease), ...],
# build: [var(BumpedBranch), var(Distance), ...]
# ),
# vars: (
# major: Some(1), minor: Some(0), patch: Some(1),
# pre_release: Some((label: Alpha, number: Some(123))),
# bumped_branch: Some("feature-branch"),
# bumped_commit_hash: Some("gabc123def"),
# ...
# )
# )
# (test case 2)
# Pipeline chaining - Multiple transformations
# Note: Upstream command must output --output-format zerv for stdin piping to work
zerv flow --source git --output-format zerv | zerv version --source stdin --major 4 --output-format semver
# → 4.0.1-alpha.10192.post.1.dev.1764382150+branch.name.1.g4e9af24
# (test case 3)
zerv flow --output-format pep440
# 1.0.1a10192.post1.dev1764382150+branch.name.1.g4e9af24
# (test case 4)
zerv flow --output-format semver
# 1.0.1-alpha.10192.post.1.dev.1764902466+branch.name.1.g4e9af24
# (test case 5)
zerv flow --output-prefix v --output-format semver
# v1.0.1-alpha.10192.post.1.dev.1764902466+branch.name.1.g4e9af24
# (test case 6)
zerv flow --output-template "app:{{ major }}.{{ minor }}.{{ patch }}"
# app:1.0.1
# (test case 7)
zerv flow --output-template "{{ semver_obj.docker }}"
# 1.0.1-alpha.10192.post.1.dev.1764902466-branch.name.1.g4e9af24
# (test case 8)
zerv flow --output-template "{{ semver_obj.base_part }}++{{ semver_obj.pre_release_part }}++{{ semver_obj.build_part }}"
# 1.0.1++alpha.10192.post.1.dev.1764902466++branch.name.1.g4e9af24
# (test case 9)
# Comprehensive template examples
zerv flow --output-template "Build: {{ major }}.{{ minor }}.{{ patch }}-{{ pre_release.label | default(value='release') }}{% if pre_release.number %}{{ pre_release.number }}{% endif %} ({{ bumped_branch }}@{{ bumped_commit_hash_short }})"
# → Build: 1.0.1-alpha59394 (feature.new.auth@g4e9af24)
# (test case 10)
zerv flow --output-template "Version: {{ semver_obj.docker }}, Branch: {{ bumped_branch | upper }}, Clean: {% if dirty %}No{% else %}Yes{% endif %}"
# → Version: 1.0.1-alpha.59394.post.1.dev.1764382150-branch.name.1.g54c499a, Branch: DIRTY.FEATURE.WORK, Clean: No
# (test case 11)
zerv flow --output-template "{% if distance %}{{ distance }} commits since {% if last_timestamp %}{{ format_timestamp(value=last_timestamp, format='%Y-%m-%d') }}{% else %}beginning{% endif %}{% else %}Exact tag{% endif %}"
# → 1 commits since 2025-12-05
# (test case 12)
zerv flow --output-template "App-{{ major }}{{ minor }}{{ patch }}{% if pre_release %}-{{ pre_release.label }}{% endif %}{% if dirty %}-SNAPSHOT{% endif %}-{{ hash(value=bumped_branch, length=4) }}"
# → App-101-alpha-SNAPSHOT-a1b2
# (test case 13)
zerv flow --output-template "PEP440: {{ pep440 }}"
# → PEP440: 1.0.1a10192.post1.dev1764909598+branch.name.1.g4e9af24
# (test case 14)
zerv flow --output-template "Release: v{{ major }}.{{ minor }}.{{ patch }}, Pre: {{ pre_release.label_code | default(value='release') }}, Hash: {{ bumped_commit_hash_short }}"
# → Release: v1.0.1, Pre: a, Hash: g4e9af24
# (test case 15)
- Smart Source Detection: Auto-detects input source (stdin if piped, git otherwise)
# Implicit source detection (auto: git if no stdin, stdin if piped)
zerv version
# Explicit git source
zerv version --source git
# Pipe between commands (implicit stdin detection)
zerv version --output-format zerv | zerv version
# Pipe between commands (explicit stdin source)
zerv version --output-format zerv | zerv version --source stdin
# No VCS - use overrides only
zerv version --source none --tag-version 1.2.3 --distance 5
Template System: Advanced custom formatting
Purpose: Complete control over version output using Tera templating with extensive variables, functions, and logical operations.
Note: Zerv uses the Tera templating engine, which provides powerful template features including conditionals, loops, filters, and custom functions.
Available Template Variables
Core Version Fields:
major,minor,patch- Version numbersepoch- Epoch version (optional)post,dev- Post-release and dev identifiers
Pre-release Context:
pre_release.label- Pre-release type ("alpha", "beta", "rc")pre_release.number- Pre-release numberpre_release.label_code- Short code ("a", "b", "rc")pre_release.label_pep440- PEP440 format ("a", "b", "rc")
VCS/Metadata Fields:
distance- Commits from reference pointdirty- Working directory dirty statebumped_branch- Branch namebumped_commit_hash- Full commit hashbumped_commit_hash_short- Short commit hashbumped_timestamp- Commit timestamplast_commit_hash- Last tag commit hashlast_commit_hash_short- Short last tag commit hashlast_timestamp- Last tag timestamp
Parsed Version Objects:
semver_obj.base_part- "1.2.3"semver_obj.pre_release_part- "alpha.1.post.3.dev.5"semver_obj.build_part- "build.456"semver_obj.docker- "1.2.3-alpha.1-build.456"pep440_obj.base_part- "1.2.3"pep440_obj.pre_release_part- "a1.post3.dev5"pep440_obj.build_part- "build.456"
Formatted Versions:
semver- Full SemVer stringpep440- Full PEP440 stringcurrent_timestamp- Current Unix timestamp
Custom Template Functions
String Manipulation:
sanitize(value=variable, preset='dotted')- Sanitize with presets: "semver", "pep440", "uint"sanitize(value=variable, separator='-', lowercase=true, max_length=10)- Custom sanitizationprefix(value=variable, length=10)- Extract first N charactersprefix_if(value=variable, prefix="+")- Add prefix only if value not empty
Hashing & Formatting:
hash(value=variable, length=7)- Generate hex hashhash_int(value=variable, length=7, allow_leading_zero=false)- Numeric hashformat_timestamp(value=timestamp, format="%Y-%m-%d")- Format timestamp "2023-12-30"format_timestamp(value=timestamp, format="compact_date")- "20231230"
zerv check: Validate version formats
Validate version strings against specific format requirements.
zerv check "1.2.3-rc.2"
# Version: 1.2.3-rc.2
# ✓ Valid PEP440 format (normalized: 1.2.3rc2)
# ✓ Valid SemVer format
zerv render: Format conversion
Parse and render version strings with format conversion, templates, and custom prefixes.
# Convert SemVer to PEP440
zerv render "1.2.3-alpha.1" --output-format pep440
# 1.2.3a1
# Convert PEP440 to SemVer
zerv render "1.2.3b2" --input-format pep440 --output-format semver
# 1.2.3-beta.2
# Auto-detect input format
zerv render "1.2.3a1" --output-format semver
# 1.2.3-alpha.1
Templates:
# Custom format
zerv render "1.2.3" --template "v{{major}}.{{minor}}"
# v1.2
# With pre-release
zerv render "2.0.0-beta.2" --template "{{major}}.{{minor}}.{{patch}}-{{pre_release.label}}"
# 2.0.0-beta
Prefixes:
zerv render "1.2.3" --output-prefix "v"
# v1.2.3
Python API
Zerv can be used as a Python library for version generation in Python scripts.
import zerv
zerv.version()
# "1.2.3-alpha.1"
Installation
# Python (uv - global CLI tool) - Recommended
uv tool install zerv-version
# Python (pip)
pip install zerv-version
# Python (uv - add to project)
uv add zerv-version
# Rust (cargo)
cargo install zerv
# Installation script (latest version)
curl -sSL https://raw.githubusercontent.com/wislertt/zerv/main/scripts/install.sh | bash
# Installation script (specific version)
curl -sSL https://raw.githubusercontent.com/wislertt/zerv/main/scripts/install.sh | bash -s vX.X.X
# Pre-built binaries
# Download from: https://github.com/wislertt/zerv/releases
Uninstall
# Rust/cargo
cargo uninstall zerv
# Python (pip)
pip uninstall zerv-version
# Python (uv tool)
uv tool uninstall zerv-version
# Manual binary
rm ~/.local/bin/zerv
Links
- Comprehensive Documentation: docs/llms.md - Complete reference for all Zerv capabilities
- CLI Help:
zerv --help,zerv flow --help,zerv version --help- Detailed command-line reference
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distributions
Built Distributions
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file zerv_version-0.8.11-py3-none-win_arm64.whl.
File metadata
- Download URL: zerv_version-0.8.11-py3-none-win_arm64.whl
- Upload date:
- Size: 2.3 MB
- Tags: Python 3, Windows ARM64
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.10.12 {"installer":{"name":"uv","version":"0.10.12","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":null,"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
5bab479f170adb54e0bb6954a34dd524179d4d6e134f631d919c37ebfbe3e617
|
|
| MD5 |
578a33cbf5fe360b1a39c629cc2c756a
|
|
| BLAKE2b-256 |
a77571e3cfe2701b240611cec126e612c860a13993267e8c9dd11048c476f9c2
|
File details
Details for the file zerv_version-0.8.11-py3-none-win_amd64.whl.
File metadata
- Download URL: zerv_version-0.8.11-py3-none-win_amd64.whl
- Upload date:
- Size: 2.5 MB
- Tags: Python 3, Windows x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.10.12 {"installer":{"name":"uv","version":"0.10.12","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":null,"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
6e4bc5e1a401ec0f25624d578d1cbd1413c7b8abbd3b6d67e474d265d2f2d8ab
|
|
| MD5 |
c72940bcfc8f329992948cbc86608cc4
|
|
| BLAKE2b-256 |
6f630f6ab4dc53c918b34441266bae7202978430eed8a1fbe02057f9b0245d5b
|
File details
Details for the file zerv_version-0.8.11-py3-none-manylinux_2_39_x86_64.whl.
File metadata
- Download URL: zerv_version-0.8.11-py3-none-manylinux_2_39_x86_64.whl
- Upload date:
- Size: 2.7 MB
- Tags: Python 3, manylinux: glibc 2.39+ x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.10.12 {"installer":{"name":"uv","version":"0.10.12","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
4a448946ea89c3894a0c0b0103023154c96f44b6c69e569a2570bb1c54e8d4f9
|
|
| MD5 |
21e452834ee2434a375a45a6f3edeeea
|
|
| BLAKE2b-256 |
8912eeca073bdca92d084b0b2044a952b12f5410e7edb61cdd3ce2a45c248142
|
File details
Details for the file zerv_version-0.8.11-py3-none-manylinux_2_39_aarch64.whl.
File metadata
- Download URL: zerv_version-0.8.11-py3-none-manylinux_2_39_aarch64.whl
- Upload date:
- Size: 2.5 MB
- Tags: Python 3, manylinux: glibc 2.39+ ARM64
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.10.12 {"installer":{"name":"uv","version":"0.10.12","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
468f27a521af312c49519033d41a4241dd724e9fbee9625727add70b45175e84
|
|
| MD5 |
a0be7324207af78ca5c3fdd998ee2eff
|
|
| BLAKE2b-256 |
ca159004022e2a567b526086230673554d680f84520a82c0fdd35271a729df3b
|
File details
Details for the file zerv_version-0.8.11-py3-none-macosx_11_0_arm64.whl.
File metadata
- Download URL: zerv_version-0.8.11-py3-none-macosx_11_0_arm64.whl
- Upload date:
- Size: 2.4 MB
- Tags: Python 3, macOS 11.0+ ARM64
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.10.12 {"installer":{"name":"uv","version":"0.10.12","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
7f6cdbb082f737831fe211a8fac016e044ff8b60a16a101f54ea3104e5f19e43
|
|
| MD5 |
8003b7899e6ecbc9193b5e0e0ad11c84
|
|
| BLAKE2b-256 |
a5aaa5f599465ee84577791b8ee7adb94e0be1d48bcfef3ad21f81402d6718ad
|
File details
Details for the file zerv_version-0.8.11-py3-none-macosx_10_12_x86_64.whl.
File metadata
- Download URL: zerv_version-0.8.11-py3-none-macosx_10_12_x86_64.whl
- Upload date:
- Size: 2.5 MB
- Tags: Python 3, macOS 10.12+ x86-64
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.10.12 {"installer":{"name":"uv","version":"0.10.12","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
e93fc3f517eb5b1cb965fe60279bb996b1ff5c24e91b591ef2b974595ffedffb
|
|
| MD5 |
e9733a00ab4f71e1736336cf5000d249
|
|
| BLAKE2b-256 |
587ab9a4246f1d3555a4f99b4f202dac4d5ed5aaa999d9a994de5b13acc7f721
|