Skip to content

Instantly share code, notes, and snippets.

@AlexAtkinson
Last active January 31, 2026 07:17
Show Gist options
  • Select an option

  • Save AlexAtkinson/7db2eb20b0edd93a550f90bcac2c2c0f to your computer and use it in GitHub Desktop.

Select an option

Save AlexAtkinson/7db2eb20b0edd93a550f90bcac2c2c0f to your computer and use it in GitHub Desktop.
An actionable overview of branching strategies.

Git Branching Strategies

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.

Branching Strategies

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 Anti-Patterns

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" main branch 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).

The Gold Standard

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.

JIRA Epics Workflow with Labels
Diagram: Trunk Based Development with usage, and tooling notations.

Unfortunately there are scenarios where the use of more complicated strategies cannot be avoided.

Use Cases

Mobile Application Development

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.

Installable Applications

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.

Firmware

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.

Components

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.

Microservices

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.

Monolith

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.

Monorepo

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.

Uni/Monster-repo

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.
⚠️ Knowledge & skill relating to contribution of code, CI, and other aspects of the SDLC under this model are generally not portable.

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment