Source control management tools have advanced to support larger, more complex projects and enable hundreds of developers to contribute to a single product. Even with these advancements, merge conflicts are bound to happen when you have people collaborating on a shared codebase.
Luckily, you can reduce the number and complexity of these conflicts by developing branching strategies for your projects. Below, you can find the branching strategies that have high levels of adoption in 2024.
A branching strategy is your team’s approach to where you write code, through what process that code is merged with existing code, and how code is ultimately deployed to production. Whether you have a team of five hundred developers or five, collaborating on a shared codebase can be tricky and you’ll want to give serious thought to what branching strategy will work best for your project. This is how you’ll avoid time consuming merge conflict resolution or regression bug fixing in the future.
Branching strategies In Git summarizes the benefits of branching like this:
There are many branching strategies. Choosing the right one depends on the size of your team, the complexity and organization of your codebase, the type of version control system you use, your release cadence, and your team’s preferred collaboration style.
At a high level there are three main branching strategies: trunk-based development, release branching, and feature branching. Within these there are variations — too many to cover in one post. For a deeper dive into branching strategies I suggest Martin Fowler’s Patterns for Managing Source Code Branches.
Trunk-based development is where all developers work off a single branch — the trunk or the “main” branch — and check in small changes frequently so that the trunk is kept up-to-date and production ready.
Trunk-based development is a key concept in continuous integration and continuous delivery (CI/CD) and the regular check-ins happening multiple times a day ensure the code can be released on demand.
To ensure developers can check in frequently without running into conflicts and delays, they must communicate with each other often and work must be broken down into small tasks. It also helps to have well defined team processes for file check out and locking, as well as pair programming and code reviews, to ensure code being checked in does not introduce regressions or bugs.
Release branching takes a similar approach to trunk-based development by requiring frequent, usually daily, merges with the trunk but adds in an additional branch per release. This is to allow development to continue in parallel to testing and bug fixes needed to prepare a release for deployment to production.
When enough changes exist in the trunk to warrant a release, the trunk is copied into a release branch. Testers get to work on the new release branch and developers continue working on new features for the next release on the trunk. If bugs are found in the release branch they are fixed in the release branch and backported to the trunk.
Once the quality bar is met, changes in the release branch stop and it is released to production. The release branch is kept and follows a numbered naming convention (version 1, v2.0, etc.) that allows the team to track and maintain all the releases. If bugs fixed in the future in the trunk are applicable to previously released versions the fixes are merged with those release branches and deployed to production in subsequent update releases (version 1.1, v2.0.1, etc.).
Feature branching is where a developer makes a branch for the feature they are working on which allows them to work over a longer period of time without interfering with the main branch. Once the feature is complete, the developer merges their changes back into the main branch and the feature branch is deleted.
Feature branching allows multiple developers to work on different features in a shared codebase without locking each other out of files or destabilizing the main branch. Of course, overlapping changes could lead to issues if another developer changes code that you’re relying on, so it’s important to pull from main on a regular basis to re-sync your feature branch to the latest changes.
Feature branching is one of the key benefits of Git-based version control. The widespread adoption of Git has led to additional feature branching strategies specifically for developers using Git. The two most common are GitHub Flow and Git Flow.
In GitHub Flow there are two branches: the master and the feature. Feature branches are used to make changes, such as adding or refining features, code refactoring, fixes, experiments, etc. Once done, they are merged back into the master branch. Then those changes are deployed to production directly from the master branch. Ideally feature branches are small and merged back into main frequently. Because the master branch is always release-ready, they are then quickly deployed to production.
Git Flow combines multiple branching strategies to support more complicated development and deployment needs. Git Flow uses the following branches:
Feature branches are merged with the develop branch when the feature is complete and then deleted.
The release branch is created from the develop branch, often when enough features have merged into the develop branch to warrant a release. Once the release branch is fully tested and all bugs are fixed the release branch is merged back to the develop branch and also merged with the master branch and released to production.
The hotfix branch is usually reserved for fixing high priority production bugs. When there isn’t time to send code through all the branches in the regular development cycle, a hotfix branch is created from the master branch. The bug is fixed and tested and then the hotfix branch is merged back into the master branch — where it can be quickly deployed to production — and into the develop branch before being deleted.
For a more detailed walkthrough of Github Flow and Git Flow, including visualizations of these branching strategies, check out Git Flow vs Github Flow on GeeksforGeeks.