bump-version — a utility to automate:
- versioning in accordance with the Semantic Versioning specification
- generation of a changelog (Changelog)
- validation of commit messages against the Conventional Commits specification
- creation of a version file that can be imported into your program’s code at build time. This makes it possible, for example, to automatically keep the program version displayed by
--versionor in a GUI up to date - generation of Git commits related to a release, for example:
chore(release): 1.0.0 - automatic addition of Git tags to commits related to a release
The utility currently only works with Git.
- Versioning
- Supported platforms
- Installation and build
- How to use the utility
- How the utility determines release type
- Files generated by the utility
- Frequently asked questions (FAQ)
- Contributors
The bump-version utility versions itself. This is a dogfooding practice that lets you verify correct behavior and demonstrate the utility on a real project.
The utility is written in Go and compiles anywhere there is a Go compiler.
After building, the build/ directory contains the expected files:
linux-amd64/bump-version— Linux (x86_64)macos-amd64/bump-version— macOS (x86_64)macos-arm64/bump-version— macOS (ARM64)windows-amd64/bump-version.exe— Microsoft Windows (x86_64)
- Install the latest Go compiler from the official site https://go.dev/dl.
- Change to the project root directory from the command line.
- Run:
cd scripts && go run . build && cd ..After that, compiled artifacts for supported platforms will appear in the build/ directory.
The utility is statically built and has no runtime dependencies, so installation is simple:
- Copy the compiled binary to any directory available in PATH (for example
/usr/local/bin/on Unix-like systems orC:\Program Files\bump-version\on Windows). - If necessary, add the directory with the binary to your PATH environment variable.
- The repository must use Git.
IMPORTANT: Push releases with
git push --follow-tagsso the release commit and the annotated release tag travel together; those tags are what the utility uses to determine the current version. WhenshouldPushToOriginis enabled the utility pushes for you, otherwise it prints the exact next steps. - Make atomic commits (one logical change per commit).
- Follow Semantic Versioning for releases.
- Write commit messages following Conventional Commits.
The bump-version repository can serve as an example/reference for all these points.
An atomic commit contains a single logical change. It should:
- Address one task: fix a bug, add one small feature, change one config file, etc.
- Have a meaningful header in Conventional Commits format (kind[scope]: short verb) that reflects the change.
- Not mix different kinds of changes: for example, do not include formatting, bug fix, and feature in one commit. Semantically different changes should be split into separate commits (e.g.,
style: format files+fix(scope): correct null pointer).
Why this matters:
- bump-version analyzes history based on commit kinds (feat/fix/BREAKING CHANGE). If a commit contains multiple semantic types, the utility may misidentify the release type or put changes into the wrong CHANGELOG section.
- Atomic commits simplify review, rollback, and debugging (easier to find the problematic change via
git bisect). - When automatically generating a CHANGELOG, each commit lands in the correct section (Features, Bug Fixes, etc.), making the log clear and useful.
Practical recommendations:
- Make small, frequent commits.
- If working on a big task — break it into steps and commit iteratively.
- Use interactive staging/patch tools (
git add -p) to separate logically different changes. - If needed, add more details in the commit body; keep the header short and Conventional Commit–compliant.
Useful Git tools:
- Visual Studio Code — has an integrated diff viewer that allows staging hunks (https://code.visualstudio.com, https://github.com/VSCodium/vscodium).
- LazyGit — a convenient ncurses terminal client (https://github.com/jesseduffield/lazygit).
- diffview.nvim plugin for NeoVim, similar to VS Code’s diff viewer (https://github.com/sindrets/diffview.nvim).
- vim-fugitive plugin for vanilla Vim (https://github.com/tpope/vim-fugitive).
- Magit plugin for GNU Emacs (https://github.com/magit/magit).
- Gitk — a GUI viewer for Git (https://git-scm.com/docs/gitk).
For full details read the specification: https://semver.org/lang
Quick summary and practical rules for bump-version:
-
Version format: MAJOR.MINOR.PATCH (e.g., 2.4.1).
- MAJOR — incompatible API changes.
- MINOR — added functionality in a backwards-compatible manner.
- PATCH — backwards-compatible bug fixes.
-
Rules for bumping based on commit history (how bump-version applies them):
- MAJOR — bump when a
BREAKING CHANGEentry is found in the commit body/footer or if there is an exclamation mark after the commit type (e.g.,feat!: ...orfix!: ...). - MINOR — bump if there are no breaking changes but at least one
featcommit. - PATCH — bump if there are no breaking changes or feat commits but there are
fixorperfcommits. - No change — if there are no feat/fix/perf/BREAKING CHANGE commits (the utility prints
nothing to releaseand exits without making changes).
- MAJOR — bump when a
-
Additional notes:
- Commits like
refactor,docs,chore, etc. do not bump the version by default, but every commit that passes validation lands in the changelog under its own section (Features, Bug Fixes, Performance, Refactoring, Documentation, Tests, Build, Continuous Integration, Styling, Chores; anything else falls back to Chores). TheallowedCommitKindssetting gates validation, not changelog content. - BREAKING CHANGE counts even if declared in the commit body (for example, after a blank line) and should be explicit — describing the change and why it is incompatible.
- The
vprefix in Git tags (e.g.,v1.2.3) is optional and is configurable via the"versionTagFormat"field in the config file. The semantic versioning itself is unaffected by the prefix.
- Commits like
-
Examples:
- History: one
feat: add exportand severalfix:→ minor release (x.Y+1.0). - History:
refactor: restructure internalsanddocs:→ no version change by default. - History:
feat!: change API signatureor presence ofBREAKING CHANGE:→ major release (X+1.0.0).
- History: one
Following these rules and atomic commits ensures correct operation of bump-version and a useful, readable changelog.
For full details read the specification: https://www.conventionalcommits.org/en/v1.0.0
In short:
Commit header format:
commit_kind(scope): commit_title
commit_body
Scope and body are optional.
Scope is encouraged — it indicates which module or area the commit affects.
The header must start with an imperative present-tense verb, without a trailing period, starting with a lowercase letter. Scope is an abstract module name or unique source file name.
Brief explanation of commit kinds:
-
feat — new features that change program functionality. Example:
feat: add user authentication -
fix — bug fixes. Example:
fix: resolve crash on login -
docs — documentation changes. Example:
docs: add installation instructions to README.md -
style — formatting, style fixes not affecting logic. Example:
style: format code -
refactor — code changes that neither add features nor fix bugs. Example:
refactor: simplify user service logic -
perf — changes that improve performance. Example:
perf: optimize image loading -
test — adding or changing tests. Example:
test: add unit tests for user model -
build — changes to build system or external dependencies. Example:
build: update Makefile configuration -
ci — changes to CI configuration. Example:
ci: add linting step to CI pipeline -
chore — housekeeping tasks not affecting product source code. Example:
chore: update dependencies -
revert — revert previous changes. Example:
revert: revert "feat: add user authentication" Refs: 532a023, 22aeae8The
Refsattribute is necessary for this utility to determine which commits are reverted. -
BREAKING CHANGE — description of incompatible changes (may be in commit body or as a separate header). Example:
BREAKING CHANGE: The API endpoint has changed from /api/v1/users to /api/v2/users.
- Simple release generating all necessary files:
bump-versionThis command performs auto-detection from commits, prints the release plan, asks for confirmation, updates the version file, updates the Changelog, creates a release commit, and adds an annotated Git tag.
- Show the changelog for this release without writing it to the Changelog file:
bump-version preview-changelog- Add a Git hook to validate commit messages before each commit:
bump-version add-hookHooks may interfere with squashing and frequent rebases, so the hook is not installed by default. To just validate commits since the last release use bump-version lint. Also, if ignoreInvalidCommits is not set to true in the config file, the utility will fail on invalid commits.
- Remove the Git hook that validates commit messages before each commit:
bump-version remove-hook- Validate commits since the last release (no release), listing commits that do not match Conventional Commits:
bump-version lint- Validate all commits in history (no release), listing commits that do not match Conventional Commits:
bump-version lint-all- Validate the provided commit message:
bump-version lint-commit "fix: resolve crash on login"- Show the current version of your program and exit:
bump-version my-version- Show the next version of your program and exit (no changes applied):
bump-version next-version- Show help:
bump-version help- Show utility version:
bump-version version- Use a different config file:
bump-version command -config other-bump-version-config.cfg- Add a config file
bump-version.cfgto the project root:
bump-version init-config- Cancel a recent version bump (removes the release commit and tag, restores the version files):
bump-version cancel- Print the release plan and the changelog without changing anything:
bump-version -dry-run- Force the release type instead of deriving it from commits:
bump-version -type major- The
-forceoption suppresses the prompts like "Are you sure you want to overwrite this file?" and the release confirmation (required for non-interactive releases):
bump-version -force init-configBefore touching anything the utility prints the release plan and may refuse to continue:
- Confirmation prompt —
Release 1.2.3? [y/N]defaults to no; pass-forceto skip it (required in scripts and CI). - Staged changes — releases are refused while changes are staged; commit or reset them first.
- Dirty working tree — releases are refused when the working tree has uncommitted changes.
- Existing tag — releases are refused when the target tag already exists.
- Dry run —
-dry-runprints the plan and the changelog, then exits without modifying files, commits or tags. - Credential stripping — when the remote URL embeds credentials (
https://user:token@host/...), they are stripped before they can reach the changelog compare links.
The config file must be at the project root named bump-version.cfg.
If not found, default configuration is used.
The -config option points the utility to another config file.
Default configuration:
Config file fields:
version— configuration file version.versionFilenames— comma-separated names of the version files.changeLogFilename— name of the ChangeLog file.ignoreInvalidCommits— ignore invalid commits (do not fail on them).versionTagFormat— Git tag format for releases. Substitution{version}is replaced with the semantic version X.Y.Z.allowedCommitKinds— comma-separated list of allowed commit kinds.bumpVersionCommit— version bump commit message format (defaultchore(release): {version}).shouldPushToOrigin— push the release commit and tag on version bump withgit push --follow-tags(defaultfalse).
Each field present in the configuration file overrides the default.
bump-version scans commits since the last release and determines the required version bump based on Conventional Commit types:
- If there is at least one commit with
BREAKING CHANGEor an exclamation mark after the commit kind — bump MAJOR. - Else if there are
featcommits — bump MINOR. - Else if there are
fixorperfcommits — bump PATCH. - If there are no relevant commits — the version does not change (the utility warns
nothing to releaseand exits successfully without making changes).
The type can be forced with the -type option, which also allows releasing when the derived type would be "no change":
bump-version -type patchA forced type still requires at least one commit since the last tag.
# Changelog
## [2.76.0](https://github.com/acme/app/compare/v2.75.0...v2.76.0) (2026-06-06)
### Features
* **KauSection:** add Smoke icon indicator and the ability to search sensors with smoke state [8bf8850](https://github.com/acme/app/commit/8bf88509d2a1c0b3e5f7a9c1d2b4e6f801234567)
* **KauSection:** use proportional font for hex sensor state, also shade zero nibbles in gray [0f99f89](https://github.com/acme/app/commit/0f99f89d4b2c1a3e5f7d9b0c2a4e6f8012345678)
* avoid rendering of AppConsole when it is hidden (its state is preserved though) [b3f62f9](https://github.com/acme/app/commit/b3f62f9a1b2c3d4e5f6a7b8c9d0e1f201234567)
* make searching of items by empty queries faster [ea58508](https://github.com/acme/app/commit/ea58508c1d2e3f4a5b6c7d8e9f0a1b201234567)
### Bug Fixes
* **Settings:** ensure current theme hover re-renders as soon as chosen theme changes [72e32f9](https://github.com/acme/app/commit/72e32f9a1b2c3d4e5f6a7b8c9d0e1f201234567)
### Performance
* optimize image loading [3ab91c2](https://github.com/acme/app/commit/3ab91c2d3e4f5a6b7c8d9e0f1a2b3c401234567)Without a remote configured the compare and commit links are omitted and a single warning is printed.
CHANGELOG.md— automatically generated changelog grouped by versions and change kinds with commit hashes.- Version file (e.g.,
VERSION) — contains a single line with the current version. - A Git commit with the release message (by default
chore(release): X.Y.Z). - An annotated Git tag with the release name (e.g.,
vX.Y.Z) whose message isRelease X.Y.Z.
When shouldPushToOrigin is enabled the release commit and tag are pushed with git push --follow-tags; otherwise the utility prints the exact git push command to run next.
-
Question: What happens if there are no commits matching Conventional Commits?
- Answer: The utility prints an error or a warning about ignored commits. You will need to run an interactive rebase (
git rebase -i) to fix the commits.
- Answer: The utility prints an error or a warning about ignored commits. You will need to run an interactive rebase (
-
Question: I bumped the new version too early. What should I do?
- Answer: Run the
bump-version cancelcommand.
- Answer: Run the
-
Question: Why was my release refused?
- Answer: The utility refuses to release over staged changes (commit or reset them first), over an uncommitted working tree, or when the target tag already exists.
bump-version -dry-runshows what a release would do without changing anything.
- Answer: The utility refuses to release over staged changes (commit or reset them first), over an uncommitted working tree, or when the target tag already exists.
-
Question: How do I release from a script or CI without a prompt?
- Answer: Pass
-force. Without it the utility asksRelease X.Y.Z? [y/N]and defaults to no. Combine with-typeto pin the version bump and with-dry-runto preview.
- Answer: Pass
-
Question: Why does the output contain ANSI escape sequences (or none at all)?
- Answer: Colors are used only on POSIX terminals: output redirected to a file or pipe stays plain,
NO_COLOR(any non-empty value) andTERM=dumbdisable colors, andCLICOLOR_FORCE=1forces colors even into pipes (handy in CI). Windows output stays plain unless forced.
- Answer: Colors are used only on POSIX terminals: output redirected to a file or pipe stays plain,
- Daniil Stepanov [email protected]