I came across this rather strongly opinionated blog post – GitFlow considered harmful, and I have to say that I mostly agree with it.
In our company, we use a similar approach to the Anti-gitflow, but with even more simplicity. This is one particular thing I like so much about git is that each person, team, or company can pick the workflow that suits them best.
Just to give you a little bit of context, we have a rather small development team (under 10 people), but we do a large number of projects. All our projects are web-based, varying from small and simple websites (static HTML), through more complex WordPress sites (multilingual, e-commerce, etc), to business applications like CRMs. Each project is done by several developers at a time and can later on be passed on to other developers, often much later (another iteration after several month). Each developer is working on a number of projects at a time. And we do very fast-paced development, often deploying multiple versions per day. Given the nature of the projects and the development pace, we don’t ever really rollback. Rollback is just another step (version) forward. And we don’t have long and complex roadmaps in terms of which features will be released in which version. It’s more of a constant review of what’s pending, what needs which resources, and what we can do right now. (It’s far from ideal project management, but it somehow works for us. If you think you can do better, send me your CV or LinkedIn profile, and we’ll talk.)
In our case, we do the following:
- We have one eternal branch, and we call it master.
- The master branch is always stable and deployable. Even though we don’t really deploy it directly.
- Nobody is allowed to commit directly to the master branch. Initially it was just an agreed convention, but because people make mistakes, we now have this rule enforced with the technology. Both BitBucket and GitHub support protected branches. BitBucket, in my opinion, does it much better.
- All new features, fixes, and improvements are developed in separate “feature” branches. Most of these are branched off the master. For large chunks of work, we can create a feature branch, and then introduce incremental changes to it via sub-feature branches, branched off the feature one. This allows for easier code reviews – looking at a smaller set of changes, rather than a giant branch when it’s ready to be merged.
- We do code review on everything. The strongly suggested rule is that at least two other developers review the code before it is merged. But sometimes, this is ignored, because either the changes are small and insignificant (CSS tweaks or content typos), or we are really in a hurry (we’ll review the changes later). But whatever the case is, nobody is allowed to merge their own pull requests. That is set in stone. This guarantees that at least one other person looked at the changes before they were merged in.
- We tag new versions only on the master branch.
- We use semantic versioning for our tags.
- We don’t deploy branches. We deploy tags. This helps with preventing untested/unexpected changes sneaking in between the review of the branch and the deployment.
The above process suits us pretty well.
Hi Leonid,
Thanks for sharing your team git work-flow. I have some question from your work-flow. You said that the master branch is always stable, then what if the feature branch is already done? Will it merge to master branch or on another branch like develop or something?
Thanks
Hi. Usually yes, feature branch will get merged into master after code review and automated tests. Once done, integration tests will run as well. Then a new tag is done on master branch, which can include either a single or multiple features.
Hi,
Thanks for the answer, I found your method is simple yet very useful and wanted to adopt it. However, I have another question, what if on the future your older tag need to be patched. How usually you / your team handle this kind of thing?
Thanks
Hi,
glad you find this flow useful. :)
Tags are very specific versions (pointers to commits). So if we have a version ‘v1.5.3’ and a bug was found which we need to fix, we create a new feature branch, apply the fix, test/review/etc, then merge into master and now we can create a new tag – ‘v1.5.4’. So you basically always move forward.
An exception to the above would be if you support multiple major versions. For example, you have v1 and v2. Since your master branch is now on the v2, with, let’s say, the latest version being v2.0.9, this means you cannot fix the previous version’s bug on master. What we do is the following:
So, now your master branch is still the latest v2 codebase. But you also have a v1-fixes branch, which is like a master branch for the previous major version. The same can be done for more versions/scenarios.
For our team specifically, it’s a very rare case. We control most of our code and client projects, etc. So we usually just move forward and the moment we release a new major version, that’s the one that is being used for everything. This means that we can survive with only master branch as being stable.