RELATED: SDLC, ALM, & SDLC, Versioning, Artifacting
From the merge hell of SVN and the early days of Git to the refined tactics we enjoy today, there have been many developments in branching strategies, but only a few remain relevant. This document covers these strategies as well as their adoption considerations.
The first three strategies are the most commonly used, with the fourth highlighting a critical anti-pattern, and the last being used for Linux kernel development; and some other large projects. Skip learning about the last two for now, but know that they exist.
| Strategy | Year | Description | Best For |
|---|---|---|---|
| Git Flow | 2010 | main, develop, & release-* are long-lived.feature & hotfix are terminal. |
Maintaining multiple versions of a product. Specifically noted as unsuitable for CD. |
| Github Flow | 2011 | main is the only long-lived branch.feature & hotfix are terminal.There are no release branches.*Originated: main is always deployable. |
Webapps, components, etc., where true CICD is the objective. |
| Trunk Based Development | ~2013 | main is the only long-lived branch.All other branches are terminal. There are no release branches.Practice matures beyond deploying from commit hashes, with asset-driven delivery being mandated. See Artifacting for more. New work is deployed frequently behind feature toggles, further decoupling feature releases from software versions. |
Environments where extreme delivery cadence is desirable, and which are "oops-tolerant". TBD may be used without feature flags, and sees tremendous success with products where every build is potentially releasable, and transit a mature SDLC. This would include pre-prod envs which develop the confidence in the product progressively until it qualifies for production. |
| GitLab Flow | 2014 | main is staging...{ENV} branches are used for deploying to each workload environment.feature & hotfix are terminal. |
Nothing. This was quickly outmoded. |
| Benevolent Dictator | 2005 | Every contributor maintains their own repository. Contributors > Lieutenants > Dictator |
Massive open-source projects. |
The two major anti-patterns to be aware of are building/deploying from:
- a commit hash
- an {ENV} branch
Heroku was never good, but it solved some problems at the time and gained significant adoption. Unfortunately this means that the practice was socialized to the degree that we still see these patterns today. Fortunately, between the laws of physics and their bit-flips (single-event upset), and the fact that the software supply chain is dynamic from moment-to-moment, artifacting is the only viable approach to software delivery.
See the Versioning and Artifacting primers for more.
[!WARNING] BONUS ANTI-PATTERN Abusing the concept of an "always deployable"
mainbranch to qualify deploying from commit hashes is a common tactic from those who don't understand modern CICD tactics.
Note specifically that this phrase was outmoded by "potentially releasable" (artifacts).
Use Trunk Based Development (TBD) wherever possible.
It's simple to understand; simple to operate; simple to automate; and simple to qualify.
Important
The objective of Trunk Based Development (TBD) is true Continuous Integration and Continuous Delivery of potentially releasable assets. The delivery of the asset is the demarcation of responsibility between the branching strategy and the quality tactics for the product. Delivered assets must meet quality standards in at least one test/preprod environment before being promoted to production.
See the SDLC, ALM, & SDLC primer for more.
Diagram: Trunk Based Development with usage, and tooling notations.
Unfortunately there are scenarios where the use of more complicated strategies cannot be avoided.
Strategy: Trunk Based Development, or TBD /w Release Branches
Ideally your product's release posture is agile, benefitting from CICD, or as close as it can get with mobile applications, in which case TBD is fine.
One particular mobile application architecture worth noting is Micro-Frontends. For these applications, the skeleton/framework for the application is published to the mobile app store, with it consuming "micro-frontends" -- web components which can be consumed as usual, and which can be managed independently of the mobile app stores. The only special consideration here being that instead of one monolithic application, you now benefit from being able to discretely iterate and manage each component.
There are scenarios where multiple versions of mobile applications must be maintained, in which case TBD with release branches is a suitable strategy.
Tip
The release process for major app stores is awful to the point that there's a market for 3rd party products that ease the pain. RUNWAY is one example.
See RUNWAY's article Choosing the right branching strategy for mobile development for more on this topic.
Strategy: Github Flow; TBD with release branches, and without feature flags.
If software is designed to be run only with internet connectivity then feature flags may be used. Ensure that the software handles flag caching for a reasonable period.
Strategy: Github Flow; TBD with release branches, and without feature flags.
Firmware is installed, instantiates, runs, and turns down. It doesn't get easier than this.
Firmware is for hardware, and hw will have many revisions. Some of these revisions will require major refactoring of the firmware, which is one qualifier for a major version bump. This is a single example of a scenario that would qualify for maintaining a permanent release branch.
Tip
This may not apply for fleet hardware.
Strategy: TBD as needed.
Components vary in size, complexity, and vertical. Some will require long term support for older versions, while others may be able to operate under relentless CICD. Only the business context can inform this posture.
Strategy: TBD as needed.
When customers (internal/external) may not be agile enough to migrate to a new major-version of a service in a short timeframe, maintaining a release branch for the last major version is advisable. This allows customers the continued use of the service during the turndown period for the old version without delaying product releases for the latest major release. Additionally, critical fixes and patching may be applied as needed.
Strategy: TBD as needed.
Unfortunately few monolith projects which are architected well. Beware of monolith
[!TIP] Reminder A monolith is software architecture where every component is closely coupled.
Strategy: TBD as needed.
[!TIP] Reminder A monorepo is the organization of more than one related product or component per repository.
⚠️ Git and Github were designed to handle a single-product-pre-repo.
"Github is not good at monorepo" - Scott Chacon (Co-founder of Github)
Important
Do not attempt to estimate developing a monorepo posture if this is new material for the team.
Execute a tech spike to clarify and validate all opinions before committing to an estimate.
If access control is required for any of the components, at the very least setup CODEOWNERS. If access to the code itself must be governed, such as for intellectual property, or security concerns, then these must be placed in separate repos as necessary.
DO NOT force everything to be in a single repository.
Monorepo's do not function well with Github, Jira, etc., as these (and many other) products were designed to facilitate a single-product-per-repository. This can easily be understood by examining the facts that: Github cannot tag multiple releases with the same version; and Jira requires plugins to handle versioning multiple components within a single project.
A simple ("simple") method of enacting a Monorepo on Github is to simply include the name of the component as a prefix to it's version number. IE: foo-9.0.210. Complications may/will arise with tooling designed to handle only semver compliant versions.
As far as tooling goes, it will be dependent upon your language. Start by checking out monorepo.tools.
Strategy: In-house/custom.
[!TIP] Reminder A Uni/Monster-repo is a single repository for the entire organization.
Important
There are many reasons that these organizations couldn't use Git/Github, with issue of being unable to affect access control within a repository among the most obvious.
Google and Facebook are infamous for not using Git, instead using Piper and CitC, and Sapling (previously Mercurial), respectively.
If you believe that your organization requires a unirepo posture, begin by understanding the many tradeoffs involved with deviating from industry standards, as well as the related CAPEX/OPEX concerns.