Version numbers and immutable tags
This page is for engineers who choose version numbers or push tags for Exponential or any of its packages. Two rules apply to every package of the project, and both are easy to break by habit.
Contents
- Rule 1: the last position keeps counting
- Rule 2: a published tag never changes
- Choosing the next number
- The sorting trap
- How Composer sees it
Rule 1: the last position keeps counting
After x.y.9 comes x.y.10, never x.(y+1).0. The Velocity history shows 0.0.4.9 followed by 0.0.4.10. There is
no "running out" of digits: the last position is an integer. Moving a higher position is a separate decision about
what the release means, never a consequence of reaching nine (Source control and releases).
Rule 2: a published tag never changes
A tag, and the GitHub release made from it, is immutable once pushed:
- never delete, move, re-point or re-cut a pushed tag, not even to fix a typo or add a forgotten file;
- never replace the assets of a published release;
- a bad release is followed by the next version, whose notes say what was wrong.
Why. Composer and Packagist read a tag once and cache the version they found. A moved tag gives two different packages under one version number: installations that resolved it earlier keep the old contents, new ones get the new contents, and nobody can tell from the outside which they have.
Choosing the next number
Always from what is already published, never from memory or from the working tree:
git fetch --tags
git tag -l 'v*' --sort=version:refname | tail -5
gh release list --limit 10Compare both lists: a tag can exist without a release, and a release can exist for a tag the local clone has not fetched.
The sorting trap
By name, v0.0.4.10 sorts before v0.0.4.8:
git tag -l 'v0.0.4.*' | tail -1 # wrong: a name sort
git tag -l 'v0.0.4.*' --sort=version:refname # right
git tag -l 'v0.0.4.*' | sort -V | tail -1 # rightAny script that picks "the newest tag" must sort by version.
How Composer sees it
Composer and Packagist compare each position numerically, so 0.0.4.10 is newer than 0.0.4.9. A tilde constraint
floats the last position: ~0.0.4.9 means >=0.0.4.9 <0.0.5.0, which already accepts 0.0.4.10. The root
composer.json, for example, requires se7enxweb/exponential-velocity at ~0.0.4.57. Repinning to a higher minimum
is for clarity, and must wait until the version is on Packagist (Dependency management with Composer).
Related pages
- Release engineering
- Tags are permanent
- Choosing the next version
- Free documentation: this page is free to copy, translate and improve under the GNU FDL 1.3.
Become an Exponential Partner
Partners share their information, provide funding, contribute back and develop the products with us, and that is how Exponential grows. A partner website and dashboard are planned for mid-2027: please become a partner today to speed up our growth rate and land new features faster.