Branch Organisation for regular releases

- 3 mins read

A client recently reorganised the way they use their VCS, switching from separate development and main branches to a single-branch model. This made me think on how I would organise my branches in git if I was starting a project from scratch.

To set the sage, my clients are mostly small enterprises where a single team is responsible for the complete software stack. They do not practice continuous deployment, but have clear cut releases at more or less regular intervals.

Single main branch

In the spirit of trunk based development, there should only be a single long-lived branch (called main or whatever seems appropriate) as the source of truth. In my experience, having multiple long lived branches causes a mess of separate incompatible code spaces.

Feature branch development

Any development is based on tickets, describing a single new feature or bug-fix. This causes a branch to be created off main where all the coding is done. Once a feature or fix is completed this branch is merged back into main and the feature branch is deleted immediately.

Ideally the code in mainwill always produce a fully-operational copy of the software and such is deployed to whatever development environment the team is using. In case any bigger features have been split into sub-features that make only sense when released together, feature flags can be used to disable these code paths. As a corollary it is always possible to cut a release from the current code in main.

Releases

When a set of features is to be released, a new minor release is cut by tagging the current state of main. (In a semver sense, major releases happen only rarely, but are treated just like minor releases).

In some cases critical bugs will be discovered where the fix cannot be delayed until the next minor release. In this case a release branch is forked from the release tag and any desired bug fixes are cherry-picked from main. A patch release is cut by tagging the current state of the release branch.

Side notes

Semantic Versioning

This system makes it straight forward to follow semantic versioning: any release cut off a release branch is a patch release, any release cut off mainis a minor release. As noted, true major releases are fairly uncommon in this model.

Merge vs rebase

The hierarchy of branches (with mainas the only source of truth) also makes it clear when to rebase as opposed to merge: feature branches are always merged back into main while changes from main are incorporated into feature branches by rebasing.

Release branches are a special case with bug fixes being cherry picked from main. In special cases where it seems not possible to fix a release bug from main (e.g. because the affected code has diverged to much from the release) it is also possible to fork a bug fix branch directly from the release branch. In this case special care has to be taken to make sure that the fix is also implemented in the main code base. A dedicated test case for this given bug is almost a must here.

None of this is new or original but it makes a nice summary for (self-) reference.