By Zhang Liaoyuan (Yunyue)
Code programming is the starting point of the software development and delivery process, and code release is the end of this process. The code branching mode runs through the entire process from development to integration and then release. It is the closest partner of engineers. But how do we choose the most appropriate branch mode based on our own business characteristics and team size?
In this article, we will be addressing this issue by introducing the processes and characteristics of several mainstream Git branch modes, and providing selection suggestions.
The purpose of branches is to isolate one branch from another. However, additional branches add up to maintenance costs. We can define the following combinations from the development and release branches:
Imagine two different scenarios:
An appropriate branch mode can greatly improve the efficiency of software development, integration, and release. When each development team starts working, they must first determine the branching strategy. So, which branch mode would be the appropriate one? Before answering this question, let's first look at the common branch modes.
Common branch modes include trunk-based development (TBD), Git-Flow, Github-Flow, and Gitlab-Flow.
TBD means that all developers collaboratively work on one develop branch, that is, the master branch. In this mode, no additional long-lived develop branches are allowed, and only the master branch is used for development collaboration.
As no other develop branches that have been separated for a long time exist, code changes are continuously updated to the master branch, avoiding problems caused by code merging. Meanwhile, in this development mode, we recommend that you create a release branch from the master branch based on the cadence of releasing software versions. In TBD mode, all modifications are made on the master branch, including the correction of defects. After all the modifications are completed, they are cherry-picked to the release branch.
The characteristics of this case can be summarized into the following items:
In TBD mode, a team shares a develop branch and performs integration verification on the develop branch. Each code submission triggers integration verification. This requires that each batch of submitted code changes be quickly verified on the master branch to accommodate the next batch of code changes. Here, each batch of code changes must be based on the previous stable version. To ensure that the master branch is always available for code changes, the following requirements must be met:
Therefore, the TBD mode is a key driver of continuous integration. The TBD mode is conducive to continuous integration and helps build a stable and reliable baseline for the master branch. This baseline supports anytime release, implementing continuous delivery. However, the building of this baseline depend on the ability to quickly compile, check, and verify changes to the master branch based on the team's mature collaboration capabilities and engineering support. In addition, as release branches are involved, we must sort out the relationships among product versions, branches, and deployment scenarios to prevent release branch confusion, and to determine the defect correction strategies for each branch.
In TBD mode, each batch of submitted code changes must be small in scale and can be quickly verified to ensure releasability on the master branch. For some features in the development process, each change submission does not mean the completion of the entire features. To remove the impact of "semi-finished features" from the master branch, a feature toggle is often used. With the introduction of the feature toggle, frequent code changes are collected and verified first, but the relevant features are hidden by the feature toggle until they are fully ready.
However, the introduction of the feature toggle incurs cost, because the feature toggle is a configuration, which is essentially the same as a common macro definition, such as #if #else. From this sense, it produces a code branch. On the other hand, the use of the feature toggle makes your code vulnerable. Therefore, a good code design is required for the proper use of the feature toggle.
To address needs such as the feature switch in the development of a certain feature, and to suit scenarios where more and more teams work together to develop a feature, feature-oriented branch modes have emerged. Among the modes, Git-Flow is the most representative one.
Git-Flow provides a way of addressing the need for parallel development between different features. When you start developing a feature, create a feature branch from the master branch. Then, all the development work on the feature is done on this feature branch. After you complete the work on the feature, merge the feature branch back to the main code path for release.
Git-Flow has the following branches:
Each feature has its own develop branch, that is, the feature branch. When a developer needs to work on two features, the developer only needs to switch between the branches by running the "check out" command. This is to prevent the mutual interference between the development of the two features during the development process.
When you develop a feature, you need to verify it separately. After the feature is verified, merge it to an integration branch called develop branch to verify the entire software program. In this process, the develop branch is similar to the master branch most of the time. The develop branch always stores the most recent unreleased version. After the code on the develop branch is verified and can be released, you can create a release branch from the develop branch for release.
If a defect is found on the release branch during the release process, correct the defect on the release branch and synchronize the correction to the develop branch. After the version on the release branch is released, the finalized code is synchronized to the develop and master branches again. In this way, the master branch always keeps the baseline of the working version. Meanwhile, the develop branch keeps the latest version for development integration.
Git-Flow introduces a branch called hotfix, which is dedicated to correcting online defects. After the defects are corrected, they are collected to the develop branch and then synchronized to the master branch. In fact, we can consider hotfix as a special feature branch, but code changes submitted by it need to be synchronized to the master branch while being integrated to the develop branch.
Do you think Git-Flow is complicated? Then, let's see how it work by going through the feature development process.
The hotfix process is as follows:
The Git-Flow branch mode provides a relatively complete set of branches to cover most scenarios in the software development process. For a long time, developers take this mode as the standard Git branch mode, as its name implies in some sense. However, Git-Flow also has its problems. For example:
So, is there any branch mode that not only allows development tasks to be isolated from the mainline, but also is more lightweight than Git-Flow? In my opinion, the appropriate solution should be extremely simple in nature. Then, let's take a look at another branch mode called GitHub-Flow.
Unlike Git-Flow, GitHub-Flow involves no release branches. In the ideas of GitHub-Flow, once a version is ready to go, it can be deployed. Similarly, GitHub-Flow believes that hotfixes are identical to minor feature changes, and their processing methods should be similar.
GitHub-Flow has the following overall requirements:
Compared with Git-Flow, GitHub-Flow features greater simplicity. On the other hand, GitHub-Flow meets the need for continuous deployment. In GitHub-Flow, defects on the master branch can be quickly detected and the defective code can be quickly restored through mechanisms such as rollback. By merging everything into the master branch and deploying the master branch frequently, you can minimize the amount of unreleased code, which is also the best practice advocated by lean development and continuous delivery. Deployment was originally a tedious task, but implementing it frequently helps simplify this task to achieve continuous delivery.
Although GitHub-Flow simplifies the Git-Flow branch mode, it leaves us with unanswered questions about deployment, environment, and release. Therefore, we hope to provide more clues for these questions through GitLab-Flow.
Compared with GitHub-Flow, GitLab-Flow adopts a similar development mode except replacing pull requests with merge requests. Despite of this, the usage of the merge request is similar to that of the pull request, because both of them can be used a communication method for code review and feedback.
The biggest difference between GitHub-Flow and GitLab-Flow lies in their release modes. Unlike GitHub-Flow, GitLab-Flow introduces the production branch for the production environment and the pre-production branch for the pre-release environment (if any). In this way, the master branch hosts the code deployed in the integration environment, the pre-production branch hosts the code deployed in the pre-release environment, and the production branch hosts the latest code deployed in the production environment.
After a feature is developed, you must submit a merge request to merge the feature development code to the master branch and deploy the master branch to the integration environment for verification. After the verification is passed, you must submit a merge request to merge the master branch into the pre-production branch and deploy the pre-production branch to the pre-release environment for verification. After the verification is passed, you must submit a merge request to merge the code from the pre-production branch to the production branch.
As described in the preceding paragraph, based on the actual environment, the trunk release is merged downstream and deployed in sequence. In addition, GitLab-Flow supports different versions of the release branch. That is, different versions create different release branches from the master branch, and different release branches release code through the pre-production and production branches.
As you can see, GitLab-Flow does more than GitHub-Flow on the release side. While GitLab-Flow is strongly dependent on GitLab tools, GitLab-Flow can be seamlessly integrated with the Issue system in GitLab. In the working mode recommended by GitLab-Flow, each time a new feature branch is created, this request is actually initiated from an issue, that is, creating a mapping between the issue and the feature branch.
By classifying the preceding branch modes based on the number of development and release branches, we can determine the following modes:
|TBD||1. Few branches with simple practices
2. High efficiency
3. Few merge conflicts
4. Conducive to continuous deployment and delivery
5. Support for a single version per software
|1. Demanding for the team's collaboration maturity and integration discipline
2. Require outstanding integration verification infrastructure and methods
3. Require software design and implementation support for the separation of parallel development tasks
|Git-Flow||1. Support for parallel feature development
2. Complete rules with definite responsibilities of branches
3. Support for collaborative development within large and complex teams
4. Conducive to the distribution of traditional software
5. Support for multiple versions per software
|1. Many branches with complicated rules
2. Long branch lifecycle and frequent merge conflicts
3. Heavy maintenance workload for released versions
|Github-Flow||1. Support for parallel feature development
2. Clear and simple collaboration rules
3. Continuous integration and deployment
4. Conducive to continuous deployment and delivery
5. Easy integration with GitHub features
6. Support for a single version per software
|1. Demanding for the team's integration discipline
2. No branch management definition for integration and release
3. Require outstanding integration verification infrastructure and methods because no interruption is allowed during integration
4. Long develop branch lifecycles with potential merge conflict
|GitLab-Flow||1. Support for parallel feature development
2. Definite rule definitions for develop and release branches
3. Easy integration with GitHub features
4. Provide rolling validation and release for master, pre-production, and production branches, supporting continuous deployment and delivery
5. Offer the branch release method to support traditional software release
6. Support for a single version per complex software and multiple versions per software
|1. Long develop branch lifecycles with potential merge conflict
2. Support for the coupling between branches and the environment during release, for example, the coupling between the pre-production or production branch and the environment
3. Increased complexity and purposes due to introducing appropriate branch modes for multiple release modes
After we understand the common branch modes, we can choose appropriate practices based on our own business characteristics and team size. In other words, there is no perfect mode, but an appropriate mode.
Then, what must we consider when choosing the most suitable branch mode based on the characteristics of the team and project?
First of all, we must consider the version release cycle of the project. If the release cycle is long, Git-Flow is the best choice. Git-Flow can address issues such as new feature development, version release, and production system maintenance. If the release cycle is short, TBD and GitHub-Flow are both good choices. GitHub-flow features the integration of pull requests and code review. If your project is already using GitHub, GitHub-Flow is the best choice. GitHub-Flow and TBD are demanding for infrastructure such as continuous integration and automated testing. If relevant infrastructure is incomplete, we recommend that you do not use GitHub-Flow and TBD.
|Product type and its release method||Team size||Collaboration maturity||Applicable mainstream branch mode|
|Products that support continuous deployment and release, such as SaaS products||Middle||Moderate||GitHub-Flow and TBD|
|Products with a definite release window and a periodic version release cadence, such as iOS apps||Middle||Moderate||Git-Flow and GitLab-Flow with release branch|
|Products that are demanding for product quality and support continuous deployment and release, such as basic platform products||Middle||Moderate||GitLab-Flow|
|Products that are demanding for product quality and have a long maintenance cycle for released versions, such as 2B basic platform products||Large||Moderate||Git-Flow|
In addition, we recommend that you exercise the following practices from the perspective of the number of required release versions:
If you find that existing mainstream branch modes cannot meet your requirements, you can define your own branch modes. For example, if you have a team that adopts trunk development, you can define the spring, summer, fall, and winter branches. That is, use the "spring branch" in spring and the "summer branch" in summer. This branch mode has two benefits. First, it achieves trunk development and continuous release. Second, its name is very interesting and makes development work funny.
Alibaba Clouder - March 5, 2019
Apache Flink Community China - December 25, 2019
Alibaba Clouder - May 30, 2018
Alibaba Clouder - April 2, 2019
Hiteshjethva - March 5, 2021
Alibaba Clouder - March 5, 2019
Accelerate software development and delivery by integrating DevOps with the cloudLearn More
Help enterprises build high-quality, stable mobile appsLearn More
Alibaba Cloud (in partnership with Whale Cloud) helps telcos build an all-in-one telecommunication and digital lifestyle platform based on DingTalk.Learn More
More Posts by Alibaba Clouder