(Japanese version is here)
Konnichiwa! My name is Kunio Namba, and I manage development and infrastructure at Kindril. Using open-source methods, I build, deploy, and continuously improve internal service management systems. Through practical use of git and GitHub, we encountered various issues. This article introduces our internal efforts to resolve these issues.
Issues with Git-Flow and Github Flow
When managing source code and releases using GitHub, two well-known methods are "git-flow" and "Github Flow." This section organizes the issues we faced with each method.
This article assumes knowledge of git-flow and Github flow and is aimed at those struggling with their operation or considering using these methods for source code and release management. For prerequisite knowledge, please refer to the following articles:
References
-
Introduction to git-flow:
-
Introduction to Github Flow:
-
Articles on similar issues and solutions:
Issues with Git-Flow
Development with git-flow centers around the develop branch. New features are created in feature branches and merged back into develop to improve the product's quality. For releases, a release branch is branched off from develop, adjusted for release, and then merged into the main branch.
This approach works well when the entire development is focused on a single release. However, managing multiple releases introduces the following issues:
Unwanted Changes in Releases
Feature development can branch off from develop at any time, and merges are unrestricted. This simplicity means that develop can contain features not yet decided for any release. For example, if the current version is 1.0, a feature intended for version 1.2 (1.2A) might be included in the latest develop.
When a new feature for version 1.1 (1.1B) is branched from develop, it includes changes intended for version 1.2. Merging the feature branch for 1.1B into the release branch for version 1.1 unintentionally includes feature 1.2A.
Unclear Branch Points
To avoid the above issue, branching must occur from a point in develop before the inclusion of features for version 1.2A. This complicates the previously simple feature branching process. Developers must determine which point in develop is "safe." This complexity is a specific point where git-flow operations become cumbersome.
Complexity in Controlling Feature Inclusion in Releases
Deciding which features to include in a release is often driven by business needs, separate from technical management. Given the state of merges in develop, controlling and retesting necessary items for a release requires rebase, cherry-pick, and other controls. This complexity undermines the overall simplicity.
Overall, as mentioned in reference , it results in a failure to adhere to the KISS principle (Keep It Simple Stupid).
Issues with Github Flow
While git-flow defines multiple branch purposes and controls for releases, it inherently becomes complex. As an alternative, Github Flow is simple, providing minimal rules while meeting needs.
However, in large teams, uncontrolled development does not work. In our global collaborative development, involving contributors from Japan, Asia, Australia, India, Eastern Europe, and the Americas, a level of organized rules similar to git-flow is necessary.
Consistency Checks Beyond Releases
Github Flow's policy of "release quickly, deploy, and fail fast" may work for simple products or web interfaces. However, comprehensive workflows to ensure overall consistency are desired. Reference also highlights the challenge of securing testing environments.
Solution
We implemented a method combining the best of both approaches, which we call git-github-flow. It is essentially a derivative of Github Flow but incorporates elements of git-flow, hence the term fusion. It is also similar to reference .
Objectives
In retrospect, our objectives were as follows:
- Continue using the important develop branch
- Manage releases properly like git-flow
- Especially manage releases
- Maintain the simplicity of Github Flow
Actual Definition
We made the following changes to git-flow, described in the workflow:
- Feature and release branches are branched from the latest main branch, not develop (change).
- Completed features are merged into develop (unchanged).
- Merges into develop are gated with "Pull Requests" for consistency (unchanged).
- Features are merged into release branches only after successful merges into develop (change).
- Once confirmed in the release branch, the release is gated with a "Pull Request" into main (unchanged).
- After releasing, the main branch is merged back into develop (change).
Flow Explanation
The overall flow, similar to git-flow, is illustrated below. The lines extending to both develop and release branches upon feature completion represent steps 3 and 4.
Even with simultaneous merges of features A and B for release 1.1.0 and feature C for release 1.2.0 into develop, confusion is avoided.
In step 4, after confirming successful Pull Request merges into develop (yellow commits on the left) and testing (dashed lines), features are merged into release branches (green commits on the right).
Whether a Pull Request is required for merging into release branches depends on the strictness of release management and whether the release manager manually merges.
Confirmation of Objectives
The following addresses our objectives:
To continue using the important develop branch, all feature branch changes are gathered in develop for consistency.
To manage releases properly like git-flow, we continue using release branches. Features are incorporated into release branches via Pull Requests or merges, avoiding unintended feature inclusion from develop.
To maintain the simplicity of Github Flow, we adopt the "branch from main, merge back into main" simplicity, avoiding direct reflection of develop into releases.
Our objectives are achieved.
Workflow Comparison
Comparing git-flow, Github Flow, and our git-github-flow:
Models | git-flow | Github Flow | git-github-flow |
---|---|---|---|
main branch | Official product releases | Official product releases | Official product releases |
develop branch | Used | Not specified | Used |
Feature branches | Used | Used | Used |
Release branches (including Hotfix branches) | Used | Not specified | Used |
Branch point for feature branches | develop | main | main |
Merge point for feature branches | develop | main | - develop - Release branches |
Pull Request necessity for develop branch | N/A (not assuming GitHub like collaboration tools.) | N/A (develop branch is not defined) | Required |
Implementation Results
Initially, we implemented the development flow within the project using git-flow. However, managing multiple version releases in a short period, with feature and version combinations and swaps, led to the aforementioned issues.
Using our defined method, combining the best of git-flow and Github Flow, resulted in a simple and understandable operation. Here, I will introduce additional implementation tips.
Implementation Tips
- We restricted direct pushes to the develop branch, requiring Pull Requests.
- We automated builds and deployments to test machines via Github Actions upon Pull Request requests to develop.
- For each new release, created a new branch from main at the time of tagging, made standard changes, and used it as the branching point for subsequent feature branches.
Conclusion
This article introduced a branch model combining the best of git-flow and Github Flow. While there may be opinions on various countermeasures such as code modularization, multi-develop branch, tagging methods, and use of scripting, this method aims to address the issues in a simple flow within a single repository, leveraging the benefits of git-flow and Github Flow.
When you wanted to introduce this model on other sites, please use the name "git-github-flow" and link to this site.