This is a guest blog post by Holger Just from Plan.io, the creators of Planio for Bitbucket Cloud.
It’s generally considered best practice to keep Git branches short-lived. But that approach won’t work for every team or every situation. I know this because it doesn’t work for my team.
You see, our Git workflows include many long-lived branches that we maintain in parallel, which is quite unorthodox. In fact, we deploy both a master branch as well as almost a hundred separate branches based on it into production, all at once.
As un-Git as that might sound, we’ve found that having multiple branches in production works quite well for our situation. Here’s why.
Forking and merging from open source projects
Planio is based on Redmine, an open-source project management tool written in Ruby on Rails. We have added some new features, integrations, and Planio-specific changes such as our integrated Git hosting service.
An international community of open source developers, mostly working on it in their own free time, maintain Redmine. While Planio’s developers are all part of the community, we are just “regular developers”, and we have only limited control over the open source project. Instead, we work with the community to bring any changes into Redmine’s code base using the same channels as everyone else: using the public issue tracker and providing patches.
Since the Redmine code base evolves over time to add new features and fix bugs, we have always faced the unique challenge of maintaining compatibility with this external codebase that we only have very limited control over. As a small team of software developers, we have a strong incentive to work with the Redmine community to integrate most of our own code changes back into Redmine and to regularly rebase our own version of the code on top of Redmine’s own code base, so we can benefit from the work of the community improving Redmine without having to laboriously port all changes manually.
At the same time, due to our Planio-specific additions to the code, we have to maintain a long-lived branch of the code which evolves in parallel to the upstream project. Almost all of our customers run on this master branch.
We also have enterprise clients who want specific modifications to Planio – e.g., an additional Redmine plugin or small changes to the user interface to fit their workflow. We create a branch for each enterprise account, make the necessary changes and deploy that branch for them.
We’ve followed this workflow for over six years now, and we still find it quite manageable. In our situation, we’re already maintaining a branch off an open source project. Therefore, it’s only one step more for us to maintain branches for our enterprise accounts. In addition, the changes we make there are usually quite small and modular – installing a plugin for example, so conflicts and integration issues are very seldom.
Working on almost a hundred long-lived branches
For most of the new development work we do, we use a traditional approach of having short-lived feature branches which we quickly merge into our Planio master branch and then generally provide as patches to the upstream Redmine project for integration, so both our customers as well as the Redmine community benefit from them.
For our enterprise customers with their own changes, we have to regularly synchronize our Planio master branch to their branches to ensure they get all new new features and bug fixes our basic customers get. As you can imagine, manually rebasing a hundred branches every few of days would get awfully boring, really quick.
The case for long-lived Git branches: manually rebasing a hundred branches every few days gets old fast.
Fortunately, due to Ruby’s flexibility we can keep changes on the enterprise branches mostly self-contained and easy to merge. New plugins can be added as a single Git submodule, and patches can often be added in separate files. This allows us to perform the regular rebases for each branch in a semi-automated fashion as part of our CI. Human developers only have to intervene in the rare case of a code conflict.
Where long-lived Git branches work best
Reflecting our our Git workflow, I think that having multiple long-lived branches in production can actually make sense in some cases. It worked for us because in our model we have multiple, closely related branches. Plus, we’re a small team and we control the changes to each branch, keeping those changes to a minimum.
That means we’ve been able to avoid the fear that long-lived branches raises: separate, incompatible, yet very similar, products emerging over time.
It’s a workflow that can make sense when you provide software you don’t fully control yourself (i.e., open source) to customers on a SaaS basis. You will always be working in a workflow involving at least two parallel branches: the external open source code and the internally-developed version you deploy for your customers.
For more on branching strategies and workflows, head to our Git tutorials site, Getting Git Right.
Did you find this post useful? Share it on your social network of choice so your fellow Git geeks can learn about use cases for long-lived branches, too!