Software Engineering: A Modern Approach
1 Managing Branches with Git-flow, GitHub Flow, and TBD
In this article, we will present three strategies for working with branches in software projects. It’s an important and practical subject, as these strategies define the workflow that teams employ to implement new features or fix bugs, for instance.
1.1 Git-flow
Git-flow is a commonly used branch strategy proposed by Vincent Driessen in 2010 (link). Essentially, the strategy uses two permanent branches:
main
—also known asmaster
ortrunk
—is used to store code that is production-ready.develop
stores code with features that have been implemented, but haven’t undergone a final test, which is typically performed by a Quality Analyst (QA).
Moreover, Git-flow proposes three temporary branches:
- Feature branches
- Release branches
- Hotfix branches
These branches are described next. They can be created using Git’s commands (see some examples here) or by tools and plugins that provide macros to facilitate Git-flow use.
Feature Branches
These branches are created from develop
before
developers start a new feature implementation. Once the implementation
is finished, they are merged back into develop
and then
removed. Thus, feature branches often exist only in a developer’s local
repository.
Example: In the next figure, we present three
feature branches. The full circles represent commits
and
the empty circles are merges
. Notice how feature branches
derive from and return to develop
.
Release Branches
These branches also originate from develop
. They are
used to prepare a new release, which must be approved by the customers.
Once the customer gives the green light, the release branches are
integrated into main
since a new system version is ready
for deployment.
If changes occurred during the approval process, the release branch
should also be merged back into develop
.
Example: After implementing the three features from
the previous figure, the team leader decided to generate a release 1.0.
For this purpose, they created a release branch (see figure) which was
used to perform the last changes to attend the customer. After these
changes, the code was finally approved and deployed—i.e., integrated
into main
. Lastly, the changes made on the release branch
were also applied to develop
.
Hotfix Branches
These branches are used to fix a critical error detected in
production—that is, in code that’s in the main
branch.
Therefore, they spawn from main
, receive commits to fix the
critical bug, and are finally re-integrated into main
and
develop
.
Example: After releasing the new version, users
reported a critical bug. Thus, a branch was created to correct this
critical bug (see following figure), which derived from
main
. After the bug fix, the branch was re-integrated into
main
and a new release was generated with the tag 1.0.1.
Finally, the branch was also integrated into develop
.
Summary
Summarizing, the most common flow when using Git-flow is as follows:
Feature ⇒ develop ⇒ release ⇒ main
A feature is always implemented in a specific branch. Then, this
branch is merged into develop
, where the feature undergoes
integration tests. Periodically, a release branch is created to show a
new system version to customers. Once approved, this version is
integrated into main
and made available to all users.
Git-flow should primarily be used when there are manual tests and QA teams, as well as when customers need to approve and validate any new version of the code before it goes into production.
However, when using Git-flow, feature branches may take a long time
to be integrated into develop
, which may result in many
integration conflicts (merge hell). Moreover, if the
integration of release branches takes time, developers will have to wait
longer to receive feedback on the new features they’ve implemented.
1.2 GitHub Flow
GitHub Flow is a common branch model when using GitHub. It’s simpler than Git-flow as it only consists of the main branch and feature branches. It also provides support for code review before integration, through GitHub’s Pull Requests (PR) mechanism.
When using GitHub Flow, the main steps are as follows:
- A developer creates a branch in their local repository.
- Implements a feature or fixes a bug.
- Pushes the branch to GitHub.
- Goes to GitHub and opens a Pull Request (PR), i.e., a request for someone to review their implementation.
- A reviewer checks the new code and possibly merges the PR into
main
.
An example of a PR request is shown in the next figure, which was
extracted from GitHub’s documentation. In this figure, a PR is opened to
review the my-patch-1
branch. After the review is complete,
this branch will be integrated into main
.
In the appendix about git, we discuss and explain the concept of Pull Request better.
GitHub Flow is primarily used in systems with only one production version, as is typically the case with web systems. A disadvantage of the model is that PRs can take a long time to be reviewed.
Despite the name, the same flow can be used with other version control services, like GitLab.
1.3 Trunk-Based Development (TBD)
TBD is even simpler than GitHub Flow as it uses only one branch—the
main
branch, also known as master
or
trunk
.
In reality, even in TBD, developers may create feature branches, but these should have a limited duration, of at most two days, as suggested by Paul Hammant in his TBD book (and also in this post):
One key rule is the length of life of the branch before it gets merged and deleted. Simply put, the branch should only last a couple of days. Any longer than two days, and there is a risk of the branch becoming a long-lived feature branch (the antithesis of trunk-based development).
To use TBD, there should be a comprehensive suite of unit and
integration tests to avoid introducing bugs and regressions in the
main
branch. Moreover, by using TBD, it becomes easier to
adopt practices such as Continuous Integration (CI) and Continuous
Deployment (CD).
In Chapter 10 of the book, we provide a more detailed description of TBD and also explain the feature flags mechanism, which is used to prevent incomplete feature implementations from going into production.