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.
# Install
cargo install zerv
# 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)- 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
Purpose: Intelligent pre-release management that automatically generates meaningful versions from any Git state without manual decisions.
- 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
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
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)
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
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
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
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
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)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 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.g1d2e3f4Usage 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.f4a8b9cPurpose: 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.
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"))
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)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)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)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)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)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.
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
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"
cargo install zerv# Install latest version
curl -sSL https://raw.githubusercontent.com/wislertt/zerv/main/scripts/install.sh | bash
# Install specific version
curl -sSL https://raw.githubusercontent.com/wislertt/zerv/main/scripts/install.sh | bash -s v0.7.82
# Or using environment variable
curl -sSL https://raw.githubusercontent.com/wislertt/zerv/main/scripts/install.sh | ZERV_VERSION=v0.7.82 bashDownload pre-built binaries from GitHub Releases
For Quick Install and Manual Download:
rm ~/.local/bin/zerv- 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