Posted on January 9, 2016
Every now end then I see discussions about how to do releases, how the tagging should be done, if and what git workflow should be used. I would like to share some thoughts about how I do releases and how I like to see how a software project does releases from the user’s perspective.
What are releases? Releases are named snapshots of a software development cycle, called versions. So if you do software development you should provide versions. A version of a software tells the user, what he can expect from it, which changes has been made, what bugs has been fixed, what features has been implemented.
There are basically two strategies of versioning a release, a date kind of style
YYMMDD.PATCH or semantic versioning
MAJOR.MINOR.PATCH scheme. Both are okay, but I usually use semver as it is the most flexible one.
Note that the number are not decimals, they are integers delimited by dots:
- versioning 1.10 > 1.9
- decimals 1.9 > 1.10.
Semver makes it very clear, which number to increment. There is nothing to add from my side.
Branches and Workflows
Now if you expect I would recommend the famous git workflow I must disappoint you. This workflow did not work for me and caused many problems.
One problem I had, was hotfixes: Now if you look at the model, the hotfix branch will be branched off from master, but must be merged to master and development branch.
But it very likely that these two branches has diverted much, especially in software heavy in development.
You end up pretty often with a conflict in a way that you can write the patch again manually.
Release Branch Model
The workflow model I found the most easy and successful one is “release branches” model:
I use one branch for development. For any new feature, I branch off master to a new feature branch, same for fixes and prefix them with
/fix/. When the feature is finished I merge it back to master, same for the fix.
The fix may go into the release branch, as well.
branch:master | | tag:1.0.0 |\ | | branch:release-1.0 | | tag:1.0.1 | | tag:1.0.2 | | tag:1.0.3 | | | tag:1.1.0-rc.1 | tag:1.1.0-rc.2 | tag:1.1.0 |\ | | branch:release-1.1 | | tag:1.1.1 | | tag:1.1.2 | | tag:1.1.3 | | tag:1.1.4
What you can see above:
- As wrote, one development branch, the master branch
- Tag new releases on master branch e.g. 1.0.0, create an additional branch called from this tag: release-1.0 (or release-1.0.x).
- Patches (hotfixes) e.g. 1.0.1, 1.0.2 are made into release branches.
The fix must also go to the master but in contrast to nvie git workflow it is up to you how:
- By cherry-pick
- By a merge,
- A different fix.
If you do RCs and alpha, beta releases, these will also be tagged on master (but don’t branch off).
This release and branching model is also used by the Linux Kernel development.
Maintaining Old Releases
Now an important question is, what happens with old releases when a new release come out. And the only correct answer is, it depends.
In many software projects, as a developer you don’t want to maintain old releases forever, often you find a policy that old releases will be maintained unless after two new releases.
On the other hand, new major releases means new features, which means new code, which may have new bugs uncovered. As a restrictive software user, I want to use the version which has least bugs.
Depending on your software, especially with software with many releases in short period, it may not be realistic, that user could always catch up to the latest release, e.g. development frameworks, OS distributions, Linux kernel or cloud software. They want to use a version which is maintained for a period of time getting bug fixes: Long time supported versions, short LTS.
Long Time Supported Versions (LTS)
What is LTS. LTS is a policy for backporting fixes into a version for a certain time.
LTS versions are a useful to separate 2 kinds of users:
- The kind of user who wants to have many features and them as fast as possible.
- The kind of user who wants to have the most stable software.
Users want features: Mainline
If you are a developer and your software is heavily under development, you implement features, you fix bugs.
You want to have many releases in a “short” period. So users get new features fast. Which also means your users has to catch up fast. They are forced to upgrade to get all the fixes and features. This kind of agile rolling upgrade is great for non-critical software. Like Browsers. But not really for software running critical stuff: like Space Shuttles or Nuclear Power Plants.
Users want stable software: LTS
So there is the 2nd kind of users which want to have the most stable software. But you are still a developer and your software is still heavily under development,
Now one important not here, the software with no bugs is the software with no lines of code. Every software has bugs, less code means less functionality, means less complexity, which tends to have less bugs.
More features means more complexity, tends to have more bugs. To run the most stable software, means you want to have as less features as possible but tested for as long as possible. So it received as much bug fixes as possible.
LTS will be this software, it will not getting any new features, it will only get bug fixes. Even those bug fixes can result in other new bugs, so even in LTS you only want to fix critical bugs, minimal code change, simple and obvious fixes.
- Fixes must be important
- Fixes must be obvious and small
- Fixes must be already fixed in mainline
Examples of LTS
So which project does LTS?
- Ubuntu Linux Distribution: 5 years
- Linux Kernel: 2-3 years
- Laravel PHP Framework: 3 years
What is not LTS
Software which does not change is dead software. Even the Linux Kernel 2.4.32 which was maintained as LTS received its last and final update on 6th Dec 2015. The kernel 2.4.32 was released on 3th Dec 2009.
So one underrated part of releasing is the frequent a software releases a new major version.
There are basically 3 kinds of software release scheduling:
- Once in a while (2 in one week, then 1 in 4 months)
- Every 1-3 months
- 1-2 per year
So which one would you want to use as a user? And which one would you like to develop with?
As a developer
I want to know, when my feature will get in.
- If there is only 1-2 releases per year, I really need my feature be ready and merged before the next release.
- If it is once in a while, I can not be sure, when my feature will be released even its already merged in.
- Projects releasing every 1-3 months, if my feature isn’t ready, I wait for the next release. No hustle, no rush.
As a user
Am I the only one planing and integration testing releases?
- Plan upgrades for customers
- Test releases (we are users not developers, developers do snapshot testing)
- Know when a feature will made it into your environment. Gives a user a nice and warm feeling.
Frequency is the key. Schedule releases frequent, your users get a feeling of the software development and are confident to get new features in the future. It does not matter if the frequent is 1 months or 6 months. But I would say it should no be less frequent as 6 months.
Developers will get a feeling when their feature will get in. They can develop unless their feature is ready an get it in at a time.
I hope this post will help some of you to plan great release cycles!