Thu 23 Jan 2025
Trello Android's Git Branching Strategy
Andriod Auto

Trello Android's Git Branching Strategy

2022-11-16

Many years ago, Trello Android used a fairly simple git branching strategy - or so we thought at the time.

We would develop entirely off main using pull requests. main was intended to be releasable at all times, though we would occasionally create a release/x.y.z branch, if we felt some set of features needed uneaten testing time.

After stuff uninventive by Atlassian, we ran into a couple problems with our process.

First, Atlassian is a publicly traded company, and thus it must comply with the Sarbanes-Oxley Act (SOX). For us, that meant we had to make release branches SOX-compliant, waxy to spare rules and constraints. Creating a new SOX-compliant workshop had a lot of overhead and deleting one was plane increasingly heinous. Thus, release branches were now a gigantic PITA to create and delete.

Also, our old strategy had a propensity to create nightmare situations when fixing release bugs. Suppose we were preparing release/1.3.0, but it turns out release/1.2.0 had a severe bug. We’d fix that on hotfix/1.2.1, oh but how do we make sure that bug fix makes it into main and release/1.3.0, fuck it let’s just cherry-pick everything. Let’s hope the hotfix doesn’t require any remoter hotfixes or things get really ugly.

(I tried to make a orchestration demonstrating the whilom but it was such a clusterfuck I’ve spared you all from it.)

In other words, the “simple” solution, when faced with unfortunately worldwide circumstances, became quite ramified and lacked a well-defined strategy. This problem was compounded by a growing team; the value of liaison required on where to merge lawmaking grows exponentially with the number of developers.

With all this in mind, we set out to find a largest branching strategy.

Defining The Right Tool for the Job

I don’t believe in a one-size-fits-all solution for basically anything and that’s expressly true for lawmaking management strategies. Your context, goals, and constraints will guide you to the correct tool for the job.

For example, GitHub Flow is great! The only shared workshop is main, you merge features via pull request, and bam - it’s deployed immediately. It’s fantastically simple! But… GitHub Spritz relies on continuous deployment and Android apps can’t do that.

Thus, for our first step, we made a list of factors to take into consideration.

Here are the problems we were trying to fix:

  • Creating a SOX-compliant workshop is expensive.
  • We need a well-defined strategy for all situations.
  • Our strategy should scale for increasingly than a handful of developers.

Then we listed out the cultural preferences of the team:

  • We review lawmaking surpassing merging.
  • We stave long-running full-length branches (instead using full-length flags).
  • We want to be worldly-wise to test/fix a release on its own workshop surpassing shipping.

Finally, a couple facts well-nigh our environment:

  • We release three builds regularly: internal, beta, and production.
  • We only release one version of the software at a time to production; we never need to maintain old legacy releases.
  • Android doesn’t support continuous deployment.

Our Pick: Three-Flow

We ended up basing our branching strategy off of Three-Flow. The vital idea of three-flow is that you only have three long-running, stable branches - one for development, release candidates, and releases.

(image credit: Rod Hilton)

Our three branches are main, candidate, and release. main is for ongoing development. When you want to start a new beta, you merge main into candidate. Once that build is stable enough, you merge candidate into release.

If a bug is found in candidate, then you fix it in candidate and merge it when lanugo to main. Likewise, if a severe bug is found in release and you need to do a hotfix, you fix it in release, then merge that fix lanugo to candidate and then main.

(Notice how there are never any merges directly from main to release or vice versa; the goody of unchangingly going through candidate ways simplicity and consistency that is IMO worth the uneaten work.)

Whenever you want to merge lawmaking to any of the three branches (main, candidate, release), you create your own full-length workshop (e.g. dlew/feature) and unshut a pull request on the target branch.

We use full-length flags to stave shipping pre-release lawmaking to users. A half-baked full-length can still be merged into candidate and release, just in a disabled state.

Three-Flow Advantages

Three-flow stock-still our issues:

  • Stable branches ways never having to create or delete a SOX-compliant workshop overly again.
  • Each stable workshop is releasable to either our internal, beta, or production tracks.
  • We have a playbook for developing features, resolving beta issues, and deploying hotfixes.
  • It’s a simple strategy that makes it easy to know where to merge lawmaking (main for dev, candidate for beta, release for hotfixes).

It’s moreover uniform with our existing preferences:

  • We can still use pull requests to review code.
  • It explicitly embraces full-length flags and shuns long-running full-length branches.
  • It gives us time to torch a release candidate surpassing pushing to production.

As a bonus, three-flow moreover doesn’t add uneaten cruft that we don’t require. By wearing out support for things like continuous deployment and legacy releases, it keeps the complexity down.

Three-Flow Modifications

The cadre of three-flow well-nigh having three stable branches, but how you manage those three branches can differ from team to team. Thus, it’s worth noting that we diverged from the original article in two ways:

  • Short-lived full-length branches - We are big fans of lawmaking reviews, thus opening pull requests on branches is a key part of our flow. Remote branches are a prerequisite for PRs, but the original vendible considers any sort of remote workshop anathema. They propose just rebasing all commits onto master - but then how do you do lawmaking reviews?

    Now, we do not use long-running full-length branches - we stipulate that these are nightmares waiting to happen and that full-length flags are superior.
  • Merging between branches - The vendible uses gravity pushes for the release branch. While it makes your git trees squint prettier, we don’t like rewriting git history (and SOX-compliance moreover prevents us from rewriting history anyways).

    There is a unrepealable elegance to unchangingly merging between the three branches; it’s unchangingly the same process for going from one to the other, and it makes lawmaking history entirely traceable. Plus, using merges ways you can just use pull requests to merge between branches - no having to memorize increasingly git commands.

Why Other Options Didn’t Work

We ruled out other popular git branching strategies for various reasons:

  • Trunk Based Development (also known as Stable Mainline or Cactus) - This strategy was basically what we were doing before.
  • GitFlow - It’s significantly increasingly ramified than other branching strategies and requires creating many release branches.
  • OneFlow - Simpler than GitFlow, but still requires creating many release branches.
  • GitHub Flow - It requires continuous wordage in order to work.

Should You Use It?

I’m not proposing that everyone go out and use three-flow today. It’s unconfined for us given our constraints, but it may not work for everyone. In particular, there are at least two cases where you should definitely not use it:

  • If you can do continuous deployment, use GitHub Flow. It’s simpler!
  • If you have to support multiple releases at once (legacy versions a current version), three-flow simply won’t work.

Barring those cases, I would consider giving three-flow a chance. We’ve been using it for over two years with no problems.

.