Back in 2010, Vincent Driessen wrote “A successful Git branching model”. It provided a great model to develop applications in an organized repository and following semantic versioning concepts, so the teams were able to plan releases, implement features and hotfixes knowing and reflecting the changes on the GIT repository consistently.
At Swapps, we highly relied on this method for several years, and we quickly discovered that this method works mainly when we are working on a project with planned releases and a dedicated team. In our case, we work on different projects at the same time, some of them are on the development stage and others are in maintenance mode. This approach is explained in a previous article: “Be less agile to be more agile”.
The Git Flow weaknesses
- Too many branches.
- Developers forget to update the release branches.
- Develop branch is not always updated with master.
- Name convention can be confusing: Feature vs hotfix.
There are articles saying that “Git Flow can be harmful” and they propose a simpler alternative. I understand the reasons and I also like simplicity, but at what price? If an approach makes a project messy, then we may need to reconsider it.
The risk of oversimplification
Gitlab and Github have provided simplified alternatives where they propose to completely eliminate release and hotfix branches to only have a master branch and feature branches all the time. That works fine for projects with no parallel work and very specific and isolated features, but in real life it’s very common to be working on related issues (for example, an Agile sprint) and you need an intermediate branch (the next release branch or the former develop one) to test everything together before it’s deployed.
To resolve that, they remove the equivalence of master and production and manually setting tags or just deploy manually (Github Flow) or even worse, creating an additional branch for production (Gitlab Flow).
I don’t know what you think, but I think it’s not worth to lose automation or add a branch for something that is already resolved and standardized.
In another article, we will show how we automated deployment and tags creation based on our Git flow.
A new Git Flow
We have proposed a simpler approach where we keep the advantages of the original Git Flow, the repository remains structured, the workflow is a little simplified and we automate whatever is repetitive.
The key is to have the possibility to have a simpler approach like the one proposed by Github, but still have the option of having releases with several features when required.
Master is still the king
Master means production, and it’s the branch connected directly to the environment where the live application resides, so we have our continuous integration workflow configured to deploy automatically on any change to master.
You are allowed to create features or hotfix branches based on master and then create pull requests to master, so that’s deployed automatically.
Versions are important because they group the history of the development in terms of releases, so you have in your repository how and when the code was deployed. Do you see why it’s important to tie releases and deployments?
By following SEM versioning, we always start by a defined minor version, e.g. 0.1,1.0. So depending if we are creating a pull request from a feature to master or from a release branch to master, we must define the right version to use:
- Feature to master: patch.
- Release to master: minor or major version.
For the following examples, we will assume that we start our project with the version 0.1.0
The simplest approach: maintenance mode
This is especially useful for projects on maintenance mode. Just create all your feature branches based on master and you will be creating patches to your application.
- We work on feature1, feature2, feature3 for our project.
- Feature1 will produce version 0.1.1
- Feature2 will produce version 0.1.2
- Feature3 will produce version 0.1.3
Under a traditional context, we would have called those features as hotfixes, but let’s keep it simple in the naming convention for now.
Long term releases with a set of features
It’s used when you plan to implement a set of features, so you create a release branch based on master and all your features will be based on the specific release.
When it’s time to release all the features, you will create a pull request from the release branch to master.
- The current version in production is 0.1.0
- We have planned to work on feature1, feature2 and feature3 that will be released in 1 week.
- The version of the next release will be 0.2.
- We create a new branch release/0.2 based on master.
- Feature1 is merged to release/0.2 with no version.
- Feature2 is merged to release/0.2 with no version.
- Feature2 is merged to release/0.2 with no version.
- Pull request from release/0.2 to master.
- release/0.2 is merged to master producing new version 0.2.
Working on hotfixes while we are in the middle of a release development
As you could see in the previous examples, we manage the features of a release on a separate branch release/x.x, while the hotfixes are managed through patches and merged directly to master. It means that we can work on hotfixes while we are working on a release branch with no problem.
Be careful: Keep updated the release branch!
This is one of the disadvantages of the Git Flow approach. We are humans and forget things like updating the release branch with the most recent changes on master. If you don’t want to have problems, you need to find a way to keep the release branch always up to date.
We have provided an alternative to the standard Git flow that pretends to get the best of both worlds – robust and simple, and explained why the approaches provided by Github and Gitlab don’t fit our needs. As always, you are free to use whatever approach works better for you. The most important thing is that you and your team understand the workflow and you keep consistency so any other future repository viewer can understand.