This article translated from http://nvie.com/posts/a-successful-git-branching-model/ (by Vincent Driessen)
-
In this article, I will show a development model that has been used in all projects (including projects at work and private projects) a year ago. The result is very successful. I have long wanted to write something for it, but it is not until now. This article will not detail any project, but will only involve branch policies and release management.
This article uses Git as a version control tool for all source code.
Why is it git?
To fully understand the advantages and disadvantages of git compared with other centralized version control systems, refer to this page. The debate in this regard is full of smoke. As a developer, I love git most of all these tools. Git does change the way people consider merging and splitting. In my previous classic CVS/subversion world, merging/branches are always considered a terrible thing ("be careful when merging conflicts, you will be disgusted "), therefore, you should do such a thing only occasionally.
But with git, this kind of thing becomes very simple. Branch and merge are even considered to be one of the core of your daily version control operations. For example, in the CVS/subversion book, branch and merge are often introduced in subsequent chapters (for advanced users), but in each git book, this content has been introduced in the first three chapters (basic ).
The advantage of simplicity and repeatability is that branch and merge are no longer terrible. Version control tools should have helped us easily perform branch and merge operations.
After a brief introduction to the tool, let's look at the development model. The model I introduced is essentially a set of steps, and each team member must follow these steps to form a software development process with reliable management.
Decentralized but still centralized
The core of the well-proven repository configuration we use in this branch model is a central "truth" repository. Note that only this repository is considered a central repository (because git is a DVCs [distributed version control system], there is no central repository at the technical level ). Then we use origin to refer to this repository, because most git users are familiar with this name.
Each developer performs push and pull operations on the origin. However, in addition to this centralized push-pull relationship, each developer can also change pull from other developers or groups. For example, two or more developers may develop a large feature together. Before working code with permanent push to the origin, they can perform some decentralized operations. In, Alice, Bob, Alice, David, Clair, and David are groups respectively.
Technically speaking, Alice only defines a git remote named Bob, pointing to Bob's repository, and vice versa.
Main Branch
The core of this development model is mainly inspired by the existing model. The central warehouse contains two main branches, which have unlimited service life:
Each git application should be familiar with the master branch on the origin. It exists in parallel with the master branch, which is another branch named develop.
We believe that the head source code on the origin/develop Branch reflects the latest changes submitted during the development process. Some people call it "Integration Branch ". This branch is an automated daily build code source.
When the source code on the develop branch reaches a stable state, the version can be released. All the changes on develop should be merged back to the master branch in some way and tagged with the release version number. We will discuss the operation details later.
Therefore, every time a change is merged into the master branch, this is a new product version release as defined. We tend to strictly abide by this specification, So theoretically, every time the master node commits, we can use a git hook script to automatically build and deploy software to the product environment server.
Supporting Branch
Next to master and develop, our development model uses multiple supporting branches to help team members achieve parallel development, track product features, prepare Product Version releases, and quickly fix product problems. Different from the main branches, these branches have limited service life and will eventually be deleted.
The branches we will use include the following types:
- Feature Branch)
- Release Branch)
- Hotfix Branch)
Each of these branches has a specific purpose, and each of them has strict requirements on the branches from which the branches are merged and returned. We will introduce them one by one later.
From a technical point of view, these branches are not "special" at all ". Branches are classified based on how they are used. From a technical perspective, they are common git branches.
Feature Branch
Possible branch Source: Develop
Must be merged back: Develop
Branch command Conventions: Any name except master, develop, release-*, or Hotfix -*
Feature branches (also known as topic branches) are used to develop new features for the next release. When developing a feature, it is often unknown which release version the feature will become part. The focus of the feature branch is that as long as the feature is still being developed, the Branch will always exist, but it will eventually be merged back to the develop Branch (add the feature to the release version ), or be discarded (if the test results are disappointing ).
Feature branches often exist only in the developer's repository, rather than in the origin.
Create a feature Branch
When developing new features, create feature branches from the develop branch.
$ Git checkout-B myfeature develop
Switch to a new branch "myfeature"
Features merged back to develop
The completed features should be merged back to the develop branch to add the features to the next release:
$Git checkout develop
Switch to branch 'develop'
$ Git merge-no-FF myfeature
Updating ea1b82a .. 05e9557
(Summary of changes)
$ Git branch-D myfeature
Deleted branch myfeature (was 05e9557 ).
$ Git push origin develop
The-no-FF mark in the above Code will make the merge always create a new commit object, even if the merge can be performed in fast-forward mode. In this way, you can avoid losing the historical information of the feature branch and clearly present a set of commit to form a feature. Compare the following figure:
In the 2nd images, you cannot see which commit objects constitute a feature from the GIT history at a Glance-you need to read the log to obtain this information. In this case, the entire revert feature (a set of COMMIT) will be more troublesome, and it will be much simpler if-no-diff is used.
Yes, this will cause some (empty) Commit objects, but it is more advantageous than the disadvantage.
Unfortunately, I couldn't find a way to make-no-diff the default git merge behavior parameter, but it should actually be done.
Release Branch
Possible branch Source: Develop
Must be merged back: Develop and master
Branch naming convention: release -*
The Production Branch provides support for preparing a new product version release. It allows you to check all the details at the last moment. In addition, it allows you to fix minor bugs and prepare metadata for version release (for example, version number, build date, and so on ). After the Production Branch does these tasks, the develop branch will be relatively clean and easy to accept features for the next major version.
The time for creating a production branch from the develop branch is usually when the develop Branch (similar to) reflects the desired status of the new version. At least, this is when all features planned for the version release have been merged back to the develop branch. In the future, features of other version release plans should not be merged. They must be merged after the current version branch is created.
When a Production Branch is created, a version number is obtained for the corresponding version release -- it cannot be earlier. Before that time, the develop branch reflected the "next version" related changes, but I don't know whether the "next version" will become 0.3 or 1.0, until the Production Branch is created. The version number is determined based on the project version number rule when the release branch is created.
Create a Production Branch
The Production Branch is created from the develop branch. For example, suppose 1.1.5 is the current product version and we are about to release the next version. The status of the develop branch is ready for "next version" release. We also decided that the next version is 1.2 (instead of 1.1.6 or 2.0 ). Therefore, we create a Production Branch and assign it a name that reflects the new version number:
$ Git checkout-B releases-1.2 Develop
Switched to a new branch "release-1.2"
$./Bump-version.sh 1.2
Files modified successfully. Version bumped to 1.2.
$ Git commit-a-m "bumped version number to 1.2"
[Release-1.2 74d9424] bumped version number to 1.2
1 files changed. 1 insertions (+). 1 deletions (-)
After you create a new branch and go to the branch, we set the version number. The bump-version.sh here is a fictitious shell script that modifies some local workspace files to reflect the new version number. (Of course, this can also be done manually-Here we only want to change some files) and then submit the new version number.
The new release branch may exist for a period of time until the version is explicitly delivered externally. During this period, some bugs may be fixed on the branch (rather than on the develop branch ). Adding new features to this branch is strictly forbidden. The new features must be merged into the develop branch and then wait for the next version to be released.
End a feature Branch
When the feature branch reaches a status that can be officially released, we need to perform some operations. First, merge the Production Branch to the master (Remember, we previously defined that each commit on the master branch corresponds to a new version ). Then, the commit on the master branch must be tagged to facilitate future search for historical versions. Finally, the changes on the Production Branch need to be merged back to develop, so that future versions can also contain related bug fixes.
The operations in the previous two steps in git:
$ Git checkout master
Switched to branch 'master'
$ Git merge-None-FF release-1.2
Merge made by recursive.
(Summary of changes)
$ Git tag-A 1.2
Now the version release is complete, and tags are provided for future access.
Reminder:You may also want to use-S or-u <key> to sign the tag.
In order to retain the changes on the Production Branch, we also need to merge the branches back to develop. In git:
$ Git checkout develop
Switched to branch 'develop'
$ Git merge-None-FF release-1.2
Merge made by recursive.
(Summary of changes)
This operation may cause a merge conflict (the possibility is large because we changed the version number ). If yes, repair and submit.
Now the work is actually completed. The last step is to delete the Production Branch because we no longer need it:
$ Git branch-D release-1.2
Deleted branch release-1.2 (was ff452fe ).
Hot patch Branch
Possible branch Source: Master
Must be merged back: Develop and master
Branch naming convention: hotfix -*
The hot patch branch is very similar to the Production Branch, and its purpose is to release a new product version, although it is not in the planned version release. When an unexpected problem is found in the product version, you need to understand the problem and use the hot patch branch. When Major bugs in the product version need to be solved immediately, we create a hot patch branch from the tag of the corresponding version.
The main function of using the hot Patching branch is that the team members on the develop branch can continue to work, while others can quickly fix product bugs on the hot Patching branch.
Create a hot patch Branch
The hot patch branch is created from the master branch. For example, assume that version 1.2 is currently in use. Due to a serious bug, the product has caused many problems. At the same time, the develop branch is still in an unstable state and cannot release a new version. In this case, we can create a hot patch branch and fix the problem on the branch:
$ Git checkout-B hotfix-1.2.1 master
Switched to a new branch hotfix-1.2.1 ″
$./Bump-version.sh 1.2.1
Files modified successfully, version bumped to 1.2.1.
$ Git commit-a-m "bumped version number to 1.2.1 ″
[Hotfix-1.2.1 41 e61bb] bumped version number to 1.2.1
1 files changed, 1 insertions (+), 1 deletions (-)
Don't forget to set a new version number after creating a hot patch!
Then, fix the bug and use one or more separate commit submissions.
$ Git commit-m "fixed severe production problem"
[Hotfix-1.2.1 abbe5d6] fixed severe production problem
5 files changed, 32 insertions (+), 17 deletions (-)
End a hot patch Branch
After the fix is completed, the hot patch branch needs to be merged back to the master, but it also needs to be merged back to the develop, so that the relevant repair code will be included in the next version at the same time. This is similar to the Production Branch.
First, update the master branch and add the label.
$ Git checkout master
Switched to branch 'master'
$ Git merge-no-FF hotfix-1.2.1
Merge made by recursive.
(Summary of changes)
$ Git tag-A 1.2.1
Reminder:You may also want to use-S or-u <key> to sign the tag.
Then, merge the fix code to develop:
$ Git checkout develop
Switched to branch 'develop'
$ Git merge-no-FF hotfix-1.2.1
Merge made by recursive.
(Summary of changes)
Here is an exception,If a production branch exists at this time, the changes to the hot patch branch should be merged into the production branch instead of the develop branch.. Merging hot patches into the Production Branch also means that when the Production Branch ends, the changes will eventually be merged into the develop. (If the development work on develop is in urgent need of hot Patching and cannot wait for the Production Branch to complete, you can also securely merge hot Patching into the develop branch .)
Finally, delete the temporary hot patch Branch:
$ Git branch-D hotfix-1.2.1
Deleted branch hotfix-1.2.1 (was abbe5d6 ).
Summary
Although there is nothing new in this branch model, the "Panorama" at the beginning of this article actually plays a very important role in our project. It helps build an elegant and easy-to-understand conceptual model so that team members can quickly establish and understand a common branch and release process.
I also provide a high-quality PDF version for this image. You can print it out and stick it on the wall for reference at any time.