Decision-making in development is rarely as significant as choosing a branching strategy. A well-known fact is that since the creation of Git in 2005 by Linus Torvalds for managing Linux kernel development, this tool has evolved from a simple version control mechanism to the foundation of modern DevOps practices. It is Git branching that has allowed developers worldwide to organize parallel work on large-scale projects, providing exceptional flexibility and control over every line of code.
The choice of branching strategy affects release timelines and determines how the team will respond to production environment errors, implement new features, and manage multiple product versions simultaneously. Nowadays, the discussion of GitFlow, GitHub Flow, and Trunk-Based Development is not just a technical consideration but a strategic choice that can determine the future of a project.
GitFlow is a branching model proposed by Vincent Driessen in 2010. The model is oriented toward projects with release cycles and supports multiple repository versions.
Work with this model begins by creating a develop
branch from the master
branch.
git init
git checkout -b develop
The develop
branch will contain the code relevant to the current release. Direct commits to main
or develop
are not allowed; all updates are made through merging. For each feature or task, the developer will create a new branch with the prefix feature
from develop
.
git checkout develop
git checkout -b feature/email_verification
After the functionality in the feature/email_verification
branch has been developed and tested, it is merged into develop
.
git checkout develop
git merge --no-ff feature/email_verification
The --no-ff
flag allows you to preserve the commit history, including branch history, even if the develop
branch's history has not changed.
Currently, the branch history looks like this: the development on the feature/email_verification
and feature/sms_verification
branches has been completed, and the branches have been merged into develop
. The feature/guest_no_verification
branch is still in progress and will not be included in the current release.
According to the GitFlow model, you should send features from the current release to a release branch — these are branches with the release
prefix, created from the develop
branch.
git checkout develop
git checkout -b release/1.0.0
Release branches are necessary to finalize the release features. Adding new features to this branch is prohibited, but you can fix bugs, document code, or modify configurations. Once the release/1.0.0
branch is ready and tested, it can be merged into main
, which always stores the latest production code.
git checkout master
git merge --no-ff release/1.0.0
While colleagues were preparing the release, the developer finished working on feature/guest_no_verification
and then merged it into develop
. Currently, the develop
branch does not contain new changes from the release branch, nor does master
. This is a common situation in the GitFlow model, as feature branches can live quite long and transition from release to release.
Therefore, the release/1.0.0
branch should also be merged into develop
.
git checkout develop
git merge --no-ff release/1.0.0
Now, the develop
branch includes the same changes.
Development continues, but a bug is discovered in production — a simple typo in a form that you'd rather not send through the long release cycle. For quick fixes in GitFlow, hotfix branches are used. These branches, prefixed with hotfix
, contain minor fixes, are created from the production master branch, and are merged into both master
and develop
when ready.
git checkout master
git checkout -b hotfix/release_1.0.0_textform_fix
...
git checkout master
git merge --no-ff hotfix/release_1.0.0_textform_fix
git checkout develop
git merge --no-ff hotfix/release_1.0.0_textform_fix
master
/main
: Contains tested, stable code that is ready for production deployment.
develop
: The main branch for development, that contains current but not yet release-ready code.
feature
: Branches used for developing new features, which are later merged into develop
.
release
: Branches used for preparing new releases, created from develop
and later merged into both master
and develop
.
hotfix
: Branches for quickly fixing issues in production versions, merged into both master
and develop
.
Clear version control structure.
Multiple parallel releases support.
Easy navigation through project history.
Requires setting up branch rules and CI/CD.
Long-lived features. The develop
branch often advances ahead, potentially leading to conflicts during merging.
GitHub Flow is a simpler and more flexible model designed for projects where the principle of Continuous Integration prevails. The model involves creating a new Git branch for each new task, continuous testing upon merging, and constant/frequent releases without a set release cycle.
All production code is stored in the master
branch. For each new feature, the developer creates a separate branch from master
. One of the unwritten rules of this model is to name branches so that they describe the main task of the feature. Adding the feature
prefix (similar to the GitFlow model) is not necessary.
git init
git checkout -b account_verification_by_email
Upon completion of the work, a PR — pull request
(Merge Request in GitLab) is created, a request to merge branches. This is a key feature of the model, where before merging, the system creates a code review request using Git tools, and after that, automated tests can be run, which must pass before the merge into master
.
Image source: docs.github.com
Image source: theserverside.com
main
/master
: The single branch that contains stable code ready for deployment to production.
Simplicity and clarity of the process.
Fast development and release cycles.
Ideal for CI/CD.
Not suitable for projects with complex release cycles.
Can be risky for very large projects with many dependencies.
Trunk-Based Development (TBD) is an approach where developers merge changes directly into the main branch (trunk
/main
/master
), minimizing the number of parallel branches. This ensures high development speed and fewer merge conflicts.
This approach describes not just working with Git but the entire development process — it should be iterative, with very short iterations for each feature. This means that when adding code to the trunk
branch, the feature may not yet be complete and might be implemented as interfaces or placeholders.
git init
git checkout -b account_verification_by_email_interface
With each subsequent iteration, the feature is fleshed out and will never break the build. The trunk
branch always contains stable, ready-to-release code, so you should conduct tests before merging into the trunk
branch. After successful tests, merge.
git checkout master
git merge --no-ff account_verification_by_email_interface
Now you can deploy the code to production. This means that with this approach, you don't need to be tied to release cycles, similar to GitHub Flow, but the difference lies in the fact that in Trunk-Based Development, work is done directly in the main branch, with a minimum of long-term feature branches. This provides constant product updates and the ability to quickly respond to changes without significant delays. When the feature is fully implemented, a tag can be added to the branch before merging, indicating to other developers that the feature is complete:
git checkout account_verification_by_email_complete
git tag complete
The graph of branches and commits might look like this.
To manage risks and ensure control over new features that may not be fully ready for use by all users, Trunk-Based Development actively uses feature flags. Feature flags allow developers to enable or disable functionality without requiring new deployments. This way, you can control access to new features, conduct A/B testing, and gradually roll out and collect feedback from users in real-world operating conditions.
Feature flag management can be handled through various platforms:
LaunchDarkly: A market leader in feature flag management, offering powerful tools for deployment, testing, and real-time feature analysis.
Split.io: A service that, in addition to managing flags, provides extensive capabilities for experimentation and A/B testing.
ConfigCat: A simpler and more accessible tool, suitable for small and medium-sized projects, that offers basic feature flag management and deployment capabilities.
trunk
/main
/master
: The central branch of the project where all changes are committed.
Simplifies the development process, reducing management overhead.
Speeds up the development cycle through frequent commits to the main branch.
Easy implementation of continuous CI/CD.
High demands on developer discipline and the quality of automated tests.
Risk of introducing unstable code into the main branch.
Additional time may be needed for stabilization before release.
The table below compares the branching models based on several basic parameters:
Criterion |
GitFlow |
GitHub Flow |
Trunk-Based Development (TBD) |
Team Size |
Better for large teams |
Works well for teams of any size |
Ideal for medium and large teams |
Release Cycles |
Long, with pre-releases (staging) |
Short, releases can be frequent and fast |
Very short, continuous releases |
Feature Complexity |
Supports complex features requiring long development |
Better for simple or medium complexity features |
Suitable for simple and streamlined features |
Feature Dependencies |
Manage dependencies through different branches |
Features should be relatively independent |
Features should be independent or use feature flags for managing dependencies |
Team Experience |
Suitable for teams of any experience level, but requires good process documentation within the team |
Simple management, suitable for teams of any experience level |
Requires CI/CD discipline and comfort with continuous integration |
For small teams (around five people) and startups, GitHub Flow is often the best choice, as it is simple to implement and supports high development speed with minimal overhead on branch management.
For medium and large teams, GitFlow or Trunk-Based Development may be preferable, depending on how critical managing multiple releases and code stability are. GitFlow is well-suited for companies with clear release cycles and the need to support multiple versions of a product simultaneously.
Trunk-Based Development may be ideal for organizations that prioritize rapid delivery and innovation, as this approach accelerates CI/CD processes.
If none of the well-known options fits, you can always develop something of your own using elements from different approaches. The key is that the development culture within the team defines the way of working with the Git system.