Branching Strategies are controversial. Why is that? Why can’t we just pick a strategy like Git Flow and call it the one true way to do branching? The answer is that software development is too complicated for a one size fits all approach. Factors that can impact how you do branching:
- Is your team remote?
- Do all contributors have the same level of repository access?
- Is the project an open source project?
- Are there multiple products being produced from this repository?
- Are you doing Agile development?
- Is there a comprehensive automated test suite?
- What tools are you using to manage source control?
- Does your project have core values regarding quality?
What I am going to propose in this post is a minimalist branching strategy designed to fit the NetNewsWire project.
NetNewsWire is a small, open source project. It has a small core team that is trusted with full repository access. It has additional developers that contribute via repository forks and pull requests. Everyone is remote. There are two main products produced, an iOS app and a macOS app. The two products share code that should be kept in the same repository. There isn’t a comprehensive automated test suite. It has a stated project goal of zero known bug releases. There is a desire to ensure that the release process doesn’t impede development. Source control is done in Git and dependency management is done using Git submodules.
The branching strategy I am going to recommend is an implementation of Three-Flow, a Trunk Based Development strategy. Do not read about Three-Flow right now. I’m going to give you an executive summary of Three-Flow and apply it to NetNewsWire. Besides the Three-Flow post has a lot of scary git commands and it specifically says it won’t work for a project like NetNewsWire. By itself it won’t, but it is a good foundation to start from.
(A lot of NetNewsWire development is done using Git forks and pull requests. This branching strategy accommodates that workflow, but I won’t be addressing it in this post. This post will focus on how development is managed for the developers with full repository access.)
Three-Flow uses 3 branches to facilitate development, stabilize a release, and manage production hotfixes. Development happens on Master and moves to a branch called Candidate when it is ready to be stabilized. Development continues on Master and bug fixes to the release candidate happen on Candidate. When the product is released, it is pushed to the Release branch. Hotfixes can happen on the Release branch. All bugs found and fixed are back merged to Candidate and then Master respectively.
All arrows going up are promotions (pushes) to the next environment. All arrows going down are back ports of bugfixes.
That is Three-Flow applied to NetNewsWire. It would be that simple, but we have two products we are going to deliver from the same repository. The iOS and the macOS variants of NetNewsWire. To stabilize and manage both variants, each will need to be given their own Candidate and Release branches.
Today (6/2/2019) we would need 2 branches, Master and macOS Candidate, in the main repository which will eventually grow to be 5 branches. There will also be a number of repository forks that NetNewWire developers will create to do bug fixes and implement new features (not shown here).
Each release should be tagged using Semantic Versioning. Candidates will continue to be tagged using the current convention which denotes the difference between developer, alpha and beta releases. Additionally, we will need to use a convention to avoid tag name collisions between iOS and macOS products. macOS will use even minor release numbers and iOS will use odd minor release numbers. (See the above diagram for examples.)
NetNewsWire uses Git submodules to manage project dependencies. All the submodules are under the same project umbrella as NetNewWire and there are no third party dependencies to manage. These submodules are mostly stable at this point. For simplicity sake, all development on the submodules will continue on their repository Master branch. These submodules won’t be managed as separate projects with separate releases/tags at this time.
There are 3 types of branches: Master, Candidate, and Release. All feature development happens on Master. Stabilization happens on Candidate. Hotfixes happen on Release. Each product gets its own Candidate and Release branches. All candidates and releases get tagged.
I feel this system is as simple as it can be, but not any simpler. The complexity built into this system buys us:
- The ability to release for 2 platforms
- Shared code stays in the same repository
- Time to stabilize releases
- Management of production releases
Feedback is welcome. We will be discussing this post in the NetNewsWire Slack on the #work channel.