Still using GitFlow? What about a simpler alternative?
July 18, 2017
GitFlow is a branching model created by Vincent Driessen on 2010 (original article). Since it was published, many companies had tested and implemented it, which allows us to have many reviews about how well (or not) it works. After some discussions within our team, we decided to not go with GitFlow, but use a simpler model instead, together with a tightly defined workflow. Some of the discussed reasons of why not go with GitFlow are the same written on this blog post.
The Feature Branch Model
Compared to GitFlow, it is easier to implement and does not require any plugins to be properly used. The step-by-step of this model would be:
Create a branch from the master (feature-x), which is where the feature will be developed:
git checkout -b feature-x
Push the branch to the remote:
git push -u origin feature-x. With the branch in the remote repo, a pull request should be opened with it (How to open it in GitHub). A pull request is where all modifications are available to other members and they will be able to review it
Fix the reviewed code and wait for approval. If a new release on the master generates a conflict, a best practice would be to rebase it (instead of merging)
(optional) If a rebase is needed: checkout to master
git checkout master, pull the changes
git pull, go back to the feature branch
git checkout feature-x, do the rebase
git rebase masterand then sync the rebased branch
git push --force-with-lease. A good tutorial about merging x rebasing is available on this Atlassian article.
If there are no conflicts and it was approved ⇒ squash + merge
Why Squash + Merge instead of just Merge?
The squash and merge is made up of two processes: the squash, which compact all commits in one big commit/patch, and then the merge itself. After squashing + merging, you will have only one commit in the target branch (usually master) containing all your modifications. This enables two things:
It is easier to move this feature, as the whole patch/feature will be on one commit hash
The target branch will be cleaner, less messy and more readable — without those 67 commits you have made to finish the feature.
There are more information about about why devs prefers squash and merge, instead of only merging, on this article.
Managing release versions with git tags
In the feature branch model, a merge is considered a new version release. To track each release version, tags can be used. These will be used as reference to choose which version should be deployed at the servers.
To manage these tags/release, a good practice is the usage of *semantic versioning:*
Given a version number MAJOR.MINOR.PATCH, increment the:
- MAJOR version when you make incompatible API changes,
- MINOR version when you add functionality in a backwards-compatible manner, and
- PATCH version when you make backwards-compatible bug fixes.
Checkout to the master branch:
git checkout master
Pull changes from the remote
Get the most recent tag using
git describe --abbrev=0(let’s say it returns v0.1.0)
Create a tag using
git tag -a <version>⇒
git tag -a v0.2.0
Push the modifications and the tag:
git push origin v0.2.0 --follow-tags
In many PaaS, such as AWS Beanstalk or Heroku, a remote repository is set-up where, when changes are pushed (eg. git push heroku master), a deploy is triggered using the latest commits on master. In these cases, a simple push force using the release tag will deploy the desired version:
git push -f <deploy/env-remote> v0.2.0:master. Easy, eh?
NOTE: At Chaordic New Offers Team, a grunt script was developed where we publish which tag should be deployed:
What happens if a hot-fix is needed?
At some point, an issue will be raised and the production version will need a hot-fix ASAP. A feature branch can’t just be opened to develop a fix, as the master will probably be ahead of the production version. In this case, the fix needs to be done directly on the production version:
Checkout to the production version tag
git checkout v0.10.0
Create a new branch from this tag
git checkout -b hotfix-v0.10.1-weirdbehavior
Create the fix and commit it
Create a tag for this new release
git tag -a v0.10.1(notice the SEMVER pattern)
Push the branch and tag to remote
git push -u origin hotfix-v0.10.1-weirdbehavior --follow-tags
Deploy the tag
v0.10.1to the production environment
A push request should be opened, as the fix should be applied at the master afterwards
If more patches are needed, this process can be repeated on the same version, incrementing only the patch version.
What about applying it to other environments?
This patch probably should be applied to other environments as well, which can be done through git cherry-pick
Checkout to the environment version tag
git checkout v0.13.0
Create a new branch for the patch
git checkout -b hotfix-v0.13.1
git cherry-pick v0.10.1or a
git cherry-pick <commit-hash>to apply the desired commit
git tag -a v0.13.1and
git push origin v0.13.1(push just the tag)
What if I want to get a modification from master and sent to one of the environments?
It is very similar to the above one: a
git cherry-pick should be done using a commit hash from the master as, after squash + merge a push request, a new commit is generated with all changes (big patch of commits condensed in one).
Just keep in mind…
The gap between the environments versions should be as short as possible. Otherwise, some issues may appear:
If the production is on
v0.1.10, the latest release is
v0.10, but the version
v0.3will be deployed: the team members will have to check if some of the production patches are still required and then apply them, one by one.
If some feature was only finished on
v0.10.0, and it is required for the roll-out, but the
v0.7.0is still not well tested: the release should be hold until the
v0.7.0has been tested
Usually, these version gaps occur when the producing capacity is higher than the testing capacity (developers x testers ratio).
The model is still being tested but, until now, it has been working well. The only faced drawbacks were the ones pointed on the session above.
Personal Blog by Bruno Luiz Silva (contact me)
A collection of random software engineering thoughts