TL;DR: choose either git-flow or github-flow or gitlab-flow, forking, trunk based or ‘simple’ flow? They all have pro’s and con’s.
One decision a development team always faces is: ‘how do we interact with version control?’
Nowadays git is of course the default choice for a version control system.
Warning: skipping the git diagrams here, there’s enough of those on the internet.
About development workflow
Workflow actually involves both developers and automated machines. With this scope, a lot of choices can and should be made.
Branches contain code – the recipe to a deployable artifact – but there’s more to it than that.
The serving chef and other circumstances always contribute to the bits eventually written to a binary. The binary result is what needs checking before going into production, these checks are often called the ‘gates’.
For brevity we refer to whatever the ‘main line’ is as develop (since we’re ‘developing’ stuff).
For some reason many teams are opting to apply ‘git-flow’, by Vincent Driessen. This way of working is fine. It is especially suited to distributed teams and distinct software releases. It emphasizes the source code as the product, different branches tell the state of the code.
At our team we did not think git-flow would be the appropriate choice. The main reason is that for every release to production the following needs to happen (minimum), after having created and later reviewed a feature branch:
- merge to develop
- init git-flow (should be only once, but repeated clone actions do happen)
- start release (create release branch)
- somehow ‘know’ the release is just perfect (without changing the version)
- change version to release (in pom.xml since we’re using maven, push changes)
- finish release (merge to master and develop, and push these changes and push tags)
- do actual silly deploy to production things (not part of git-flow)
The same goes for hotfixes using a hotfix branch.
- These are a lot of steps! Repetitive work. To make it worse it involves manually changing things, as the ‘normal’ flow.
- Manual steps keep going wrong, forgetting to push tags, forgetting to merge to all branches, etc.
- Another pain point is that this flow requires keeping develop and master open for pushes, instead of only using (checked) pull requests (PR).
There are other options:
We decided to design a custom workflow to fit our needs. As simple as possible while still delivering quickly and in a reproducible way.
This way of working is more in line with trunk based development.
Principles for our work flow
- prevent repetitive, error-prone work
- a binary artifact is built –just once– from any develop version and will go to production
- no pushes to anything other than a personal feature branch
- merges are only done using reviewed PR’s (and permissions and checks managed)
- master always consists of production proven code (the recipe to the binary)
- a read-only git history (tags are too easily changed afterwards, flexible, by design)
- after release to production: automatic merge to master
- a hotfix (branched from master) build artifact goes to production (like develop)
- a PR from hotfix to develop to keep sync
- short lived feature branches
- before release to production there needs to be an automated check (gate) that no commits are missing from master due to hotfixing
- feature toggles and branch by abstraction are needed to be able to go to production at any time
- there are manual gates (waiting steps) in pipeline code, an alternative to branching
- Hotfixes have become a real exception since the regular flow will actually be quick enough to do fixes straight on the mainline and just release a new version.
So why the name cow-flow? No particular reason really, it just seemed like a recognizable friendly name for the users. The same goes for git work flow, pick what you like!
Good luck customizing your own git flow!