Hello and happy Monday!
Today I’ll be sharing my examinations into semantic versioning.
Most of my findings came from other informative blogs, so I’ll also include the links to these resources throughout this post.
What is Semantic Versioning?
I like this explanation from Red Hat the most:
The basic principle of semantic versioning is that an increment to a major, minor, or micro part of a version signals a particular degree of compatibility or incompatibility with previous versions of a package.
If we head on over to the Semantic Versioning 2.0.0 site we can gain more insight into it’s application.
Here’s a summary from their site:
Given a version number MAJOR.MINOR.PATCH, [we] increment the:
- MAJOR version when we make incompatible API changes,
- MINOR version when we add functionality in a backwards-compatible manner, and
- PATCH version when we make backwards-compatible bug fixes.
Additional labels for pre-release and build metadata are available as extensions to the MAJOR.MINOR.PATCH format.
Why Semantic Versioning?
These next two excerpts also comes from the Semantic Versioning site under the Introduction header.
In the world of software management there exists a dread[ed] place called “dependency hell.” The bigger your system grows and the more packages you integrate into your software, the more likely you are to find yourself, one day, in this pit of despair.
In systems with many dependencies, releasing new package versions can quickly become a nightmare. If the dependency specifications are too tight, you are in danger of version lock (the inability to upgrade a package without having to release new versions of every dependent package). If dependencies are specified too loosely, you will inevitably be bitten by version promiscuity (assuming compatibility with more future versions than is reasonable). Dependency hell is where you are when version lock and/or version promiscuity prevent you from easily and safely moving your project forward.
As a solution to this problem, I propose a simple set of rules and requirements that dictate how version numbers are assigned and incremented. These rules are based on but not necessarily limited to pre-existing widespread common practices in use in both closed and open-source software. For this system to work, you first need to declare a public API. This may consist of documentation or be enforced by the code itself. Regardless, it is important that this API be clear and precise. Once you identify your public API, you communicate changes to it with specific increments to your version number. Consider a version format of X.Y.Z (Major.Minor.Patch). Bug fixes not affecting the API increment the patch version, backwards compatible API additions/changes increment the minor version, and backwards incompatible API changes increment the major version.
Major, Minor and Patch Versions in Detail
Let’s say you are the maintainer of an open source library, an XML parser, with the version number “1.0.0”. And now you want to release a new version because you fixed some bugs.
For the bug-fix you:
- changed some method implementations,
- but you didn’t add new methods
- and the changes are backwards compatible
In that case the new release is just a patch. That means you would update the patch version in your version string. That would be “1.0.1“.
Now let’s say you want to add additional features to your software library. The current version “1.0.1” can read XML files from hard disk and now you want to add a new feature which allows to read XML files from the internet. For this new feature you are adding new methods and you extend the public API of your new library. That’s why you count up the minor version in your version number. So the next release looks like this “1.1.0″. And every time you count up the minor version you have to reset the patch version to 0.
During your work on this XML parser you learned a lot of new stuff and you decide to completely refactor the library to make it even more awesome! During the refactoring you change the public API on the library and the new version is not backwards compatible anymore. That’s why you release version “2.0.0″. It’s a major version! Every time you count up the major version number you have to reset the minor and patch version to 0.
People who rely on your XML parser can now immediately see that the new version will, very likely, lead to compilation errors and break their build. Seeing the version number they now know that they have to be careful with the update, they have to check the change logs and the migration path.
Semantic Versioning in the Real World
He shows some nice illustrations of how to version our initial development staged projects as well as some examples of using Git tags to version our repository. Check out his full post to get the full educational experience.
Here are a few illustrations from Jurgen’s post that demonstrates semantic versioning in the real world.
Some unofficial conventions
0.y.z (a major component of zero) is generally used for initial development
When your code is used in production, you should increase to version 1.0.0 (a major component of one or higher)
A real world example
v0.0.0 # New project v0.1.0 # Add some functionality v0.2.0 # Add other new functionality v0.2.1 # Fix bug v0.3.0 # Add some functionality v0.3.1 # Fix bug v0.3.2 # Fix bug v0.3.3 # Fix bug v0.3.4 # Fix bug v0.4.0 # Add some functionality v0.4.1 # Fix bug v0.4.2 # Fix bug v1.0.0 # Code is being used in production v1.1.0 # Add some functionality v1.2.0 # Add other new functionality v1.2.1 # Fix bug v2.0.0 # Implement changes that causes public API of code to become backwards incompatible ...
Semantic versioning with Git
Git uses the concept of tags to assign versions to your Git repository:
To view the available tags of your repository:
To add a tag to your repository:
git tag -a v0.2.4 -m 'my version 0.2.4'
To push tags to a remote repository e.g. to origin:
git push origin --tags
Semantic versioning appears to be just what I need to keep my application from becoming dragged into the clutches of dependency hell.
Finally, here is a list of some additional resources I used to educate myself on this topic:
- Git basics – Tagging
- A blog post entitled Semantic Versioning by: Seth Vargo
- Never A Wrong (Semantic) Version Again! [35 minute Youtube clip]
- Semantic Versioning with Continuous Deployment by: Mark Seemann
- RubyGems Guides on Semantic Versioning