Our Git Branching Model (for most projects)

Over the years, we have tried and tested many different approaches to git branching. Some of them work, others failed miserably. Through all of this experience, we have developed an approach which seems to work well for us.

We have adapted Git-Flow to suit our needs and business model

To give context, we are obviously a software development agency with numerous clients, and many different projects going on at the same time. Some projects are one-offs that last for a few months. Other projects are ongoing and span over the course of several years.

Thus, we have found it necessary to develop a streamlined approach to our git branching that gives us the utility that we need from the git repository tools, but also does not get in the way of our progress. In other words, it allows us to develop software at a faster pace with less friction and more output. This is something that our clients have come to love about us- and a contributor to the fact that the majority of our clients stay with us for years.

In this one, as compared with the Vincent Driessen’s original Git Flow you’ll notice that the biggest step we removed is the develop branch. While this does come with certain downsides, we have found the improved flow to be a huge upside.

How to use the model in 6 Rules

Rule 1: Only ever deploy the master branch on the production server.

I mean, that should be pretty obvious, but unless you like seeing major bugs and unfinished code deployed to production, follow this rule exactly!

The master branch should contain well-refined, well-tested and working code, based on the most recent completed release.

Rule 2: Create your release branch from master directly after deploying the release.

After merging the fully-tested release and it passes all the UAT checks on staging server, and the whole team feels happy with it, it’s time to deploy to production.

It is at that time when we will tag master the latest version number and immediately delete all other branches.

Why do we delete everything? Because it’s not accepted code and we don’t want it lingering around getting dusty, and running the risk of someone thinking it is a good idea to pick it up and merge it later. That can cause all sorts of problems.

Once the other branches are deleted, we can now create the next release branch. Use this naming convention: release/number.

In the model diagram above, we use the same release number as the sprint name. In this case, MR (Major Release) + Year + Ordinal, or MR21.1, meaning the 1st release in 2021.

Rule 3: Never merge master into release or release into lower branches.

Put another way, only merge up, never down.

Rule 4: Merge hotfixes to master and release branches at the same time.

Rules 3 and 4 go together.

By doing this we will keep the integrity of the code at a high level. Master will always have the most stable code, and hotfixes make it even more stable. Therefore by merging the hotfix to the release branch at the same moment, we will ensure that the release branch gets the most stable copies of the code.

What happens in the event there is a merge conflict from merging the hotfix?

This happens from time to time, but should happen infrequently IF you are using S.O.L.I.D. principles and good technical planning. This alone helps us avoid the vast majority of issues. That said, it will still occur, and you need to know what to do about it.

First, take a screenshot of the relevant conflicts and the affected code- and add that to the hotfix ticket as a record.

Almost 100% of the time, I resolve the conflict in favor of the hotfix’s code. It is the most stable on production, so therefore your release should be including it, and only it, as the winner. Then, we find the developer and ticket number related to the conflict in question, and ask them to update their code around the hotfix. By following the next rule, the developer will receive the hotfix, and then they will have the opportunity to correct their code.

Rule 5: Keep feature branches short-lived and REBASE OFTEN!

Feature branches use the same name, but should not be thought of in the same way as a ‘software feature.’ Feature branches should be a smaller part of a larger plan. Therefore, if they don’t live very long, they contain less risk of negatively affecting the larger scope and other developers’ work.

A general rule of thumb is: If your branch needs to live longer than a day or two, it’s too big and should be broken up into several, incremental branches. For example, you could start with a branch that runs the database queries that set up the supporting structure. Then, in your next branch you could set up the scaffolding of the feature, but not actually dev out all the features themselves.

Obviously, a different approach is needed when you’re in pre-release of an application/site, and you might have more intensive branches and actually need to have longer-lived branches, but especially once the app has gone live, and if you have multiple hands touching the codebase, short-lived branches are the best way to keep everything straight.