After a short introduction to the git basics, we should talk about branching. If you work on your own, you’re free to name your branches any way you like - but if you try to develop software in a team, that’s a clear recipe for chaos.
To solve this issue, you’ll have to communicate among your team to specify a branching strategy which defines how to name your branches, how different branches are merged into another and usually also have a say in which version of your software gets deployed or delivered to your users.
There are a number of well-established schemes in circulation, each with their specific advantages and shortcomings. And of course you are free to improve and adapt these schemes to best fit your workflows - just take care to document your workflow so you can communicate your chosen strategy to new team members.
I’ll forgo creating fancy graphs for the different models and instead link to their respective documentation where you can look up any details.
Git Flow is - to the best of my knowledge the first widely publicized branching strategy. It was originally published in 2010 in a blog article by Vincent Driessen. It quickly became a kind of de-facto standard and there is a lot of tooling available - but as the author points out in an amendment to the original article, it’s not a panacea and possibly unsuited in many situations.
Roughly speaking, git flow starts work from a main branch called
From there, most work is done in feature branches (usually named
Once you are getting ready to release a new version of the software, one
creates a release branch. Bugfixes related to that release are made in
that branch and once the software is deemed ready to release, that release
branch is merged into both the
If you need to make hotfixes to the software running on production, you create
a hotfix branch which is merged into both
Every time something is merged into
master, one creates a version tag.
Git Flow is especially useful if:
- you need to maintain multiple versions of your software in the wild
- you have a (possibly) lengthy QA period which tests every feature (i.e. not only new features) and need to ensure the software isn’t evolving while it’s undergoing testing
This is where Github Flow
It’s a very simple branching strategy based on one tenet: everything in the
main branch is always ready to deploy. Just like in Git Flow, you start
feature branches off of that default branch, but QA of new features is done
by deploying these branches and checking the functionality of these specific
There is no explicit mention of versioning and since everything in
always deployable any bugfix is treated like another feature branch.
Contrary to Git Flow, Github Flow is especially useful if you’re running a SaaS-style application on your own servers: there is only one instance of your software and Github Flow enables you to focus on fast iteration and delivery of both features and bugfixes.
As lined out in the article explaining OneFlow, it is meant as a drop-in replacement for GitFlow and mostly tries to focus on the short-livedness of the non-main branches.
The concepts are the same (main, feature, release and hotfix branches, version tags) but there are also a couple of decisions to make, as there are multiple ways to finish a feature branch:
- rebase: all changes from a feature branch are rewritten before merge to produce a linear history. In my opinion the “clean” history graph doesn’t warrant the effort from rebasing, potentially loosing GPG signatures on the affected commits.
- merge -no-ff: a feature branch is merged into the main branch, ensuring that a merge commit is created even if fast-forwarding (linear history) would have been possible.
- rebase + merge -no-ff: a combination of the above. It’s supposed to negate any disadvantages of the first two, but my reservations regarding rebase still apply.
Originally, OneFlow was born out of a desire to achieve a clean, easily readable history, which is why the rebase-based approaches are still prevalent with OneFlow users.
There is also a variant of OneFlow which again uses separate
master branches after which - in my mind - the differences to GitFlow are
So of course that’s not all. In order to get a good impression of what kind of considerations go into choosing a proper workflow, let me also say a few words about GitLab Flow.
In GitLab Flow, you have so called environment branches. These are also oriented towards development of SaaS-style software where you have one codebase which is running in different environments like testing, staging and production. Each of these branches receives its own branch.
It also advocates to reduce merge commits by rebasing your changes. As mentioned previously, I’m not the biggest fan of rebasing, but it can be helpful if it’s being done manually by the original author(s) as a cleanup step before creating a merge request, as outlined by this blog article from Atlassian - you just have to be willing to invest that effort to get a “nicer” history.
It is my opinion that proper mastery of git can easily compensate for a few more merge requests.
Another thing that bothers me about GitLab Flow: environment branches are clashing with my concept of software, where you decide to release a given state and then run it in any environment you want to.
I already mentioned that I’m not bothered by merge commits and that I’m a fan of giving released versions of software a version tag. Automatic rebasing and/or squashing is a big no-go in my opinion because it looses a lot of information about the history. Especially if you’re used to writing good commit messages, potentially using Conventional Commits.
As such, OneFlow with merge -no-ff is my preferred approach of the ones listed here. For SaaS-style applications, Github Flow would be good, too, but you’ll have to ensure that it fits your remaining processes like QA and continuous delivery, too.