🌱 Pezin
A tool that handles versioning with care — it can be used manually or integrated as a pre-commit hook to automate version bumps and changelog generation based on conventional commits.
Features
- 🔄 Automatic version bumping based on conventional commits
- 🌍 Universal language support - Python, Node.js, C/C++, Rust, PHP, Go, Java, .NET, and any custom patterns
- 📁 Multi-file version management - Update multiple version files simultaneously
- 🎨 Advanced pattern system - Component-level version control with rich template formatting
- 📝 Automated changelog generation with comparison links
- 🎣 Git pre-commit hook integration with reliable amend detection
- ⚡ CLI tool for manual version management
- 🏷️ Pre-release version support (alpha, beta, rc)
- 🔧 Flexible version formats - Support any prefix/suffix pattern (v1.2.3, 1.2.3v, release-1.2.3)
Quick Start
Installation
Install from PyPI:
pip install pezin
Or install the latest development version:
pip install git+https://github.com/tatus9/pezin.git
Setup Git Hook
Add to your .pre-commit-config.yaml:
repos:
- repo: https://github.com/tatus9/pezin
rev: v0.8.2 # Use the latest version
hooks:
- id: pezin-prepare
- id: pezin-post
Install the hooks:
pip install pre-commit pezin
pre-commit install --hook-type prepare-commit-msg --hook-type post-commit
Both hooks are required: pezin-prepare detects amends/rebases and
cooperates with the data-loss guard; pezin-post performs the bump,
changelog write and tagging.
Direct git hooks (without the pre-commit framework)
pezin install-hooks # also: pezin hooks-status / pezin uninstall-hooks
Since v0.9.0 the generated hooks are pinned to the interpreter that
ran pezin install-hooks, so they work from pipx/uv/virtualenv installs
without the venv on PATH. If the hook ever cannot import pezin it warns
and lets the commit through instead of blocking it — re-run
pezin install-hooks from the right environment to fix. Upgrading from
≤ 0.8.2? Re-run pezin install-hooks once to refresh the shebangs.
Start Using
Just commit with conventional commit format:
git commit -m "feat: add user authentication" # 1.0.0 → 1.1.0
git commit -m "fix: resolve login bug" # 1.1.0 → 1.1.1
git commit -m "feat!: redesign API" # 1.1.1 → 2.0.0
Your version files will be automatically updated!
Changelog Automation
Since v0.8.0 the post-commit hook also writes CHANGELOG.md on every
bump. It adds a new dated [<version>] section listing the triggering
commit under the matching category (Features, Bug Fixes, …) and creates
the file with a Keep-a-Changelog header if missing. Since v0.9.0 the
file follows Keep-a-Changelog ordering: ## [Unreleased] stays directly
below the header, entries accumulated under it are promoted into the new
version section, and your existing header text is preserved. No config
required — it's on by default.
Opt out or customise via [tool.pezin.changelog]:
[tool.pezin.changelog]
enabled = true # set false to skip the write
path = "CHANGELOG.md" # relative to the repo or service root
unreleased_label = "Unreleased"
If CHANGELOG.md does not exist, pezin creates it with a
Keep-a-Changelog header before writing the new section. A failure while
writing the changelog is logged as a warning and the version bump still
lands — the changelog is best-effort, never blocking.
In monorepo mode each service can override the same keys in that
service's [[tool.pezin.services]] entry; per-service entries are
resolved relative to that service's root:
[[tool.pezin.services]]
name = "api"
version_files = [{ path = "api/package.json", file_type = "json" }]
[tool.pezin.services.changelog]
path = "api/CHANGELOG.md"
Upgrading from < 0.8.0
Projects upgrading from versions before 0.8.0 will see CHANGELOG.md
edited automatically on the first conventional commit after upgrade.
If you maintain the changelog by hand, set enabled = false to keep
the previous behaviour.
Unstaged Changes and the pre-commit Data-Loss Guard
Under the pre-commit framework, any unstaged changes are "parked" in a
patch file while hooks run, then re-applied afterwards. If a hook rewrites
one of those files, the re-apply can fail and the unstaged work disappears
from the worktree (it survives only in ~/.cache/pre-commit/patch*).
Since v0.8.1 pezin guards against this:
- Skips the bump when pre-commit has parked unstaged changes to a file
pezin would rewrite (version files or
CHANGELOG.md). The hook prints a message explaining the skip; stash or commit those changes, then commit again or runpezin bumpto bump manually. - Atomic rollback: if pezin's own write/amend path fails halfway, the
worktree, index and
HEADare restored to their pre-hook state - no half-applied bumps, no leftover files.
Unstaged changes to other files never block the bump; the parked patch restores cleanly around it.
The guard relies on
pezin-prepare(installed above) marking the start of each commit. Without it — e.g. onlypezin-postinstalled — the guard falls back to a 60-second recency window, and a parked patch older than that (slow hook environments being built, slow sibling hooks) can slip past it. Install both hooks.
If you were hit by this bug before v0.8.1, your "lost" work is still in the
patch file pre-commit logged (~/.cache/pre-commit/pre-commit.log names
it). Recover with:
git apply --exclude=<conflicting-file> --whitespace=nowarn <patch-file>
Note for local-repo consumers (
repo: <path>, rev: HEADor a branch): pre-commit keys hook environments on therevstring, so a moved HEAD does not refresh them -pre-commit install-hooksalone keeps running the old code. Pin the rev to a released tag (edit it manually or runpre-commit autoupdate); the changed rev forces the environment rebuild. Verify withpre-commit run pezin-post --all-files -vafter upgrading.
Conventional Commits
| Type | Version Bump | Example |
|---|---|---|
feat: |
Minor (1.0.0 → 1.1.0) | feat: add user dashboard |
fix: |
Patch (1.0.0 → 1.0.1) | fix: resolve login issue |
feat!: |
Major (1.0.0 → 2.0.0) | feat!: redesign API |
docs:, chore:, etc. |
No bump | docs: update readme |
Special tokens:
[skip-bump]- Skip version bump[force-major]- Force major bump[pre-release=beta]- Add pre-release label
CLI Usage
# Check versions
pezin -v # Shows current project + pezin versions
pezin version # Same as above
# Manual version bumping
pezin minor # Bump minor version
pezin patch --dry-run # Preview changes
pezin major --pre-release rc # Pre-release version
# Custom configuration
pezin patch --config package.json
pezin minor --skip-changelog
# Multi-language project example
# Updates pyproject.toml, package.json, version.h simultaneously
git commit -m "feat: add multi-platform support"
Python API
from pezin import Version, ConventionalCommit, ChangelogManager
# Parse and bump version
version = Version.parse("1.2.3")
new_version = version.bump("minor")
print(str(new_version)) # "1.3.0"
# Parse commit message
commit = ConventionalCommit.parse(
"feat(api)!: add new endpoint\n\nBREAKING CHANGE: new auth"
)
print(commit.breaking) # True
# Update changelog
config = ChangelogConfig(repo_url="https://github.com/tatus9/pezin.git")
manager = ChangelogManager(config)
manager.update_changelog(
Path("CHANGELOG.md"),
str(new_version),
[commit]
)
Conventional Commits Guide
Pezin follows the Conventional Commits specification:
Basic Format
<type>[optional scope]: <description>
[optional body]
[optional footer(s)]
Version Bump Rules
feat: Minor version bump (1.0.0 → 1.1.0) - New featuresfix: Patch version bump (1.0.0 → 1.0.1) - Bug fixes!orBREAKING CHANGE: Major version bump (1.0.0 → 2.0.0) - Breaking changes
Other Commit Types (no version bump)
docs: Documentation changesstyle: Code style/formatting changesrefactor: Code refactoring without functional changesperf: Performance improvementstest: Adding or updating testschore: Maintenance tasks, dependency updatesci: CI/CD configuration changesbuild: Build system changes
Special Footer Tokens
Control version bumping behavior with footer tokens:
# Skip version bump entirely
git commit -m "feat: new feature
[skip-bump]"
# Force specific bump type
git commit -m "docs: update readme
[force-patch]"
# Add pre-release label
git commit -m "feat: beta feature
[pre-release=beta]"
Available tokens:
[skip-bump]: Skip version bump[force-major]: Force major bump (1.0.0 → 2.0.0)[force-minor]: Force minor bump (1.0.0 → 1.1.0)[force-patch]: Force patch bump (1.0.0 → 1.0.1)[pre-release=label]: Add pre-release label (alpha, beta, rc)
Documentation
- 📖 Quick Start Guide - Get started in minutes
- 📖 Installation Guide - Detailed setup instructions
- 🌍 Multi-Language Support - Python, Node.js, C++, Rust, and more
- 🎨 Advanced Patterns - Custom version formats and templates
- 📋 Conventional Commits - Complete commit format guide
- ⚙️ Configuration - Customize Pezin behavior
- 💻 CLI Usage - Manual version management
- 🐍 Python API - Programmatic usage
- 🔧 Troubleshooting - Common issues and solutions
Examples
- 🌍 Multi-Language Examples - Complete project setups
Contributing
We welcome contributions!
License
MIT License - feel free to use this project for any purpose.
Release files for pezin 0.9.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | |
|---|---|---|---|
| pezin-0.9.0.tar.gz | 53.5 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| pezin-0.9.0-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 112.8 kB
Release files / pezin-0.9.0.tar.gz
| Download URL | pezin-0.9.0.tar.gz |
|---|---|
| Size | 53.5 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
7a2bf2f90539e1ffc0dec763c7f9a6496ce59064da0dd361fee19298bb9ecaa1
|
|
BLAKE2b-256 checksum How to use checksums |
2eea37ecdd6e099d23907e3742029eeb2cfce73f24223bb29c3c6e902bebeb62
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 5, 2026.
Transparency logRelease files / pezin-0.9.0-py3-none-any.whl
| Download URL | pezin-0.9.0-py3-none-any.whl |
|---|---|
| Size | 59.3 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
57298f073b0ec3aa9733d62dd7dc6513838e073392e41cd0d6ff7c324c07a76f
|
|
BLAKE2b-256 checksum How to use checksums |
4bbe4d23a5d407cf6b33935097f0d2aa6b69f38238aa1d4259d755485d96c120
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Sep 5, 2026.
Transparency log