There are many ways to organize your branches with git. In this article I want to show you 4 ways of doing so. We will see what are the pros and cons and when they are most applicable. So let's start.
Ahhh Git-Flow. In theory so nice and then the hard realitiy hits. Git-Flow tries to be an universal branching strategy which covers a lot of scenarios. The main idea is you have a set of branches which have a specific responsibility:
- main/master - The current version in production. If you need the current production version you just check out this branch
- develop - The active development branch.
- feature - A feature branch is cut of from develop and once you are done it will go back to develop.
- release - The release branch is a gate keeper to production. Once you decide we're ready to release, you cut off from develop and can do some last bugfixes on that branch. No new features should be introduced here.
- hotfix - Hotfix branches are cut from main/master or release depending if you want to make a normal fix or a hotfix in production.
There is a well defined life-cycle in Git-Flow. You have an active development branch develop. If you want to implement a feature you branch off from develop and create your own feature branch. Once this is done you integrate that feature back to the develop branch. After a while you decide we want to go to production. Then you branch off from your current develop and create a new release branch. Here you can do further testing and only critical changes should be integrated for example via a hotfix branch. When that stage is complete you merge the release branch into main or master and tag the version. This version then gets shipped to production. So main/master is always a mirror of your current production environment. You can go back in time via the tags to see what was in production 5 weeks ago.
If you just see the picture you might be overwhelmed. To be honest I squeezed a lot of use cases in one picture, but those situations might arise. The typical use case if you work in big teams or have to align support cycles with other teams in your environment. A typical example would be a bank. They don't typically push out software in a weekly manner so everything has to be aligned. Also if you work in big teams Git-Flow scales quite well.
- Easy to align work even over multiple teams.
- Handling of multiple product versions.
- Every branch has a clear responsibility.
- We have a gate between active development branch and production.
- A complicated model with lots of branches. That also means you have to backmerge between some of those, which increases complexity and increases also the chance of merge conflicts.
- It can slow down the development process / release frequency because of all of those steps.
- It needs some majority of the team and willingness to stick to it.
The second one we want to have a look at is the GitHub-Flow. It is a simplification of the Git-Flow in the sense that we don't have any release branches. We have one active development branch (often main or master), which then gets shipped to production. Features or bug-fixes are done via relatively long living features branches. The idea is that main branch can always go to production in some fashion or another. Normally people tend to work with tags to indicate whether or not a specific commit is released to a customer.
The idea behind the GitHub-Flow is to foster an asynchronous workflow. That means we create something and have often times a review which results in feedback, which then should get integrated. The typical way open source projects work on GitHub (hence the name).
The GitHub-Flow is perfect for open-source projects even with a medium sized team. It fosters direct feedback loops and asynchronous working. For such projects also long-living feature branches are "normal" as people have less time to work on such stuff. But I wouldn't stop there: This workflow is well suited in a lot of scenarios with a small team where everything is under their control. If you have to maintain multiple active releases, this will most likely not be the branching strategy you want.
- Faster feedback cycles and short production cycles
- Perfect for asynchronous work in smaller teams
- Easier to understand than Git-Flow as it is "more agile"
- Once a feature branch is merged it is production ready. If not tested properly and backed by a strong CI/CD this can easier introduce bugs
- Branches tend to live longer
- Can become tricky for bigger teams (e.g. increased potential for merge conflicts)
- Supporting multiple release versions at a time is very difficult
Gitlab-Flow position itself somewhere in the middle of the Git-Flow and GitHub-Flow. In its core it is still like the GitHub-Flow but adds stages before you can go to production. So instead of saying
main == production Gitlab-Flow introduces here some branches which reflect your "real" staging environments.
- Can handle multiple release versions or even multiple stages
- Simpler than Git-Flow
- Does focus more on quality with a lean approach
- It can become very complex if you want to maintain multiple versions.
- More complex than GitHub-Flow
Trunk Based Development
Last but not least Trunk Based Development. You only have a single shared branch called trunk. The idea is to eliminate long-living branches completely (so we can avoid merge hell 😄). The design can vary a bit. There are two flavours depending on the team size. If the team is kind of small everyone is directly commited to the trunk. Once we are ready to ship, we create a release branch which reflects the state in production. If the team is bigger, normally you tend to create also smaller short-lived feature branches. At best you integrate even those feature branches as often as possible. The idea here is that you don't necessarily implement the whole feature but slices of it so you can merge frequently.
If you have a strong team which understands the requirements and implications of Trunk based development go for it. It is not really suitable for open source projects where people tend to have long-living feature branches due to the nature of how many open-source projects work.
- Foster perfectly DevOps / Unit testing best practices.
- Enhances collaboration.
- As we have almost no branches, less chance of merge conflicts.
- Allows quick releases
- You need kind of a senior team to pull this off. You have to know how to slice a feature so you can integrate regularly. Also it fosters autonomy, which can be overwhelming for juniors.
- A strong sense of CI/CD with useful testing is a must otherwise your trunk branch can become unstable.
As we can see all of the branching strategies have their pros and cons and it depends on your concrete situation what is "best". I hope I could give you a nice overview and a good foundation for your next project.