A GUIDE ABOUT
GitFlow for SemVer
A branching model that enables semantic versioning to integrate with continuous deployment
Developers should focus on solving problems by writing code. They don’t need to be concerned about how, why, or where their solutions are deployed. The ecosystem should take responsibility for the technical complexity.
Introduction
The GitFlow Workflow¹, published by Vincent Driessen, is a branching model that allows for multiple streams with strict boundaries between them. The core principles are fairly simple and intuitive.
One of the benefits of this model is that it works quite very well with SemVer² by allowing for patches, release preparation, and feature development.
It also provides a framework for seamless integration with a continuous deployment model.
Before reading this article you should familiarise yourself with the core concepts of SemVer² and determine whether it is applicable.
Target Audience
My opinion is that you should only consider this model if your application can be live in different states. In essence, it means that deployments are controlled by multiple environments.
Stop reading if
- your application has a single “live” state, and all clients are on the most stable version
- you are bored
Keep reading if
- your application has multiple “live” states, client A on v.1.0.1, client B on v.1.0.12, and client C on v.1.3.1
- you are bored
Overview
The flow is simple to understand, but challenging to explain as a single concept. Diving into a practical overview of each stream should hopefully provide more clarity.
Legend
develop
— latest unstable versionmaster
— latest stable versiontag
— a snapshot of the versionhotfix
— temporary branch to fix something on a versionrelease
— temporary branch to prepare a new versionfeature
— temporary branch to develop a new feature
Master versus develop
These two branches are long-lived and should always exist. They each represent a history of the project; in different states.
The master
branch represents the official release history. Each new release will be merged into master
. This branch is the latest official published state of the project.
The develop
branch serves as an integration point for features and contains a full history of the project. New release
branches should be created from the develop
branch. These release
branches would be used as temporary branches to prepare a new version
Tags are always merged into master
and master
should be merged into develop
.
Feature
Each feature
should live in its own branch, isolated until it is complete. When a feature
is complete it is merged into develop
, ready to be part of the next release
branch. The feature
branches should never interact with master
.
Feature scenario
A new feature is requested and the story reads…
As a user I would like to have a view of the amount of beers in my fridge so that I can manage my bar’s stock.
The developer creates a new feature
branch by branching off of the develop
branch.
git checkout develop
git pull origin develop
git checkout -b feature-beer-grid
The developer implements the solution in the feature-beer-grid
branch and sends it for testing. By doing a push to origin it can be picked up in pipelines and deployed to the staging environments.
git checkout feature-beer-grid
git commit -am "VA-125: Implemented the new beer grid in the backend"
git push origin feature-beer-grid
The solution is now tested and the developer gets notified that it failed QA. The developer returns to the feature-beer-grid
branch to resolve the problem. Once the issue has been resolved, the developer commits the changes and pushes the branch to origin for another round of testing.
git checkout feature-beer-grid
git commit -am "VA-125: Fixed bug with editing a beer record"
git push origin feature-beer-grid
Once the issue passes testing and is ready to become part of the next release phase the developer is responsible for merging the feature-beer-grid
branch into develop
.
git checkout develop
git pull origin develop
git merge --no-ff feature-beer-grid
git push origin develop
Hotfix
The hotfix
branches are reserved for patch production releases. These patches should be done with caution and the responsibility is on the developer and the testing team to ensure that there won't be a negative impact on the production environments.
This allows the development team to iterate on releases without interrupting the rest of the workflow or waiting for the next release cycle.
Hotfix scenario
An issue is reported to the support team and a bug is logged.
VA-124: Importing beer records from a CSV with semicolon delimiters does not work since version 1.0.0.
The developer assigned to this issue needs to attempt to resolve it in the appropriate minor version. The developer updates his local git repo with the latest tags in order to find the latest tag in the 1.0.X range from which the hotfix
branch should be created.
git fetch origin --tags
git tag -ln
git checkout 1.0.1
git checkout -b hotfix-1.0.1-VA-124
The developer implements the solution in the hotfix-1.0.1-VA-124
branch and sends it for testing. By doing a push to origin it will be picked up in pipelines and deployed to the staging environments.
git checkout hotfix-1.0.1-VA-124
git commit -am "VA-124: Found and resolved an issue with the import mechanism. The import mechanism will now dynamically determine the delimiter."
git push origin hotfix-1.0.1-VA-124
The issue passes the QA phase and is now ready to go straight into production. It is the developer’s responsibility to create a new tag
for this issue. Creating this tag
will publish the release and deploy it in the production environments. The developer also needs to merge this tag forward into master
.
git checkout hotfix-1.0.1-VA-124
git fetch origin --tags
git tag -ln
git tag -a 1.0.2 -m "Deployed as 1.0.2"# Update master and develop
git checkout master
git merge --no-ff 1.1.0
git push origin master
git checkout develop
git merge --no-ff master
git push origin develop
Release
The development team will continuously iterate on the develop
branch until it has acquired enough features for a new release (or a predetermined release date is approaching). A new release
branch is created to allow stabilisation in preparation for the new version.
Once the release
branch is created no new features should be introduced and the only changes in the form of bug fixes, minor improvements, documentation and other release-oriented tasks are allowed.
The development team works closely with the support team to iterate on issues in the release
branch and polish it until it is considered to be production ready.
Scenario
The development team is nearing a release cycle and committed releasing the new version 1.1 soon.
The developer should create a new release
branch from develop
and push it to origin to deploy it into the staging environments.
git checkout develop
git pull origin develop
git checkout -b release-1.1
The QA team finds an issue in the release and logs it as:
VA-126: Cannot edit a beer record in the new backend beer grid since version 1.1.X
The developer should now create a new branch off of the release-1.1
branch as release-1.1-VA-126
to solve the issue.
git checkout release-1.1
git pull origin release-1.1
git checkout -b release-1.1-VA-126# developer makes some changes and commits the solution
git commit -am "VA-126: Fixed javascript error"
git push origin release-1.1-VA-126
The support team tests the release-1.1-VA-126
branch in the staging environment and finally sign it off as flawless.
Now the developer merges the release-1.1-VA-126
branch back into the original release-1.1
preparation branch.
git checkout release-1.1
git pull origin release-1.1
git merge --no-ff release-1.1-VA-126
Once the development team has resolved all (or most of) the issues reported in the release-1.1
range and determines that it is production ready it can be tagged and bagged. The developer also needs to update the master
and develop
branches accordingly, to ensure that they are up to date with the latest changes.
git checkout release-1.1
git tag -a 1.1.0 -m "Deployed as 1.1.0"# Update master and develop
git checkout master
git merge --no-ff 1.1.0
git push origin master
git checkout develop
git merge --no-ff master
git push origin develop