Merge, Rebase, or Both: Branch Integration Strategies and Options for Git Environments
Merging is a common practice for developers using version control systems. Whether branches are created for testing, bug fixes, or other reasons, merging integrates changes to another location, such as the mainline. To be more specific, merging takes the contents of a single source branch and integrates them with a single target branch. In this process, only the target branch is changed while the source branch history is retained unchanged. With Git, however, there is the second option of rebasing, which is another way to integrate changes from one branch to another. Rebase accumulates a series of changes into a single “patch” and then integrates that patch onto the target branch. Unlike merging, however, rebasing flattens history because it transfers the work done from one branch onto another, destroying the source history in the process.
Always Rebase or Always Merge?
That significant difference has divided the Git community between merging and rebasing, some believing you should always rebase and others believing you should always merge. The “always rebase” camp points to the following benefits of rebasing in that it:
- Eliminates complicated history
- Avoids merge commit “noise,” which can be significant in busy repos with busy branches
- Cleans intermediary commits by squashing them all into a single commit, which can be helpful for DevOps teams that expect every commit to build and test successfully
In contrast, the “always merge” camp points to the benefits of merging in that it:
- Is simpler and more familiar, especially to developers familiar with systems other than Git
- Preserves complete history and proper chronological ordering in all cases
- Avoids the perils of rebasing shared history
An example will help clarify that last point. Consider the case of an experimental feature branch. After doing some work you might ask a colleague to take a look (e.g., via a pull request). If you later decide to rebase that shared branch after you’ve both collaborated, your colleague will soon face the painful process of reconciling what they have in their repo with yours. In short, rebasing any shared branch is painful for others, which is a “hidden” problem from which merge doesn’t suffer.
Recommendations: Consider Individuals, Teams, and Branching Strategies
Like so many other things in life, the answer to the question of whether to merge or rebase is “it depends.” At Perforce, we believe neither the “always merge” nor “always rebase” extreme is necessary for most organizations. In most cases there is room for both. Here are some things to think about:
- Rebasing privately affects only the individual (prior to work being pushed)
- Rebasing publicly affects others
- Rebase simplicity and elegance end where teams begin
- Team policies are essential and supersede individual preferences; you can’t allow friction that saps productivity to satisfy merely personal preferences
- History is a first-order work product and often an essential component for other teams, regulatory compliance, supportability, and more
For individuals, we think rebasing makes a lot of sense. The beauty of Git is the ability to branch for every unit of work, again and again as often as you like. Also, you can and should commit often when working locally (individually), which rebasing will allow you to clean up prior to review. When working with others, however, we recommend sticking with merge to avoid contention.
Thus, teams need to consider several questions when setting merge vs. rebase policies. Consider your team's level of rebase competence along with the overall Git competence across your organization. Determine the degree to which you value the simplicity of rebasing as compared to the traceability and history of merging, especially in the context of your products and industry.
Finally, whatever decisions are made about merging and rebasing should be considered in the context of a clear branching strategy. A successful branching strategy will be designed around the organization of your teams and how their work is to be organized in parallel, the point being to let each work at its own pace unimpeded by others to optimize productivity.
For example, you could have a development branch with individuals’ or feature team branches below, keeping each developer/team isolated. Work can then be delivered only when it makes sense. This makes it possible to isolate units of work more reliably from the main branch, which is isolated from QA, which is isolated from pre-production, and so forth. In short, your branching strategy should reflect the shape, roles, and goals of your organization.
Git and Perforce
Perforce Git Fusion allows developers to use Git the way they want to, with no changes needed. It also adds additional functionality and capabilities, and brings important enterprise features, including access control at the repo level, better compliance, and more granular security. Perforce with Git Fusion is a unifying solution that handles large and/or large numbers of Git repos and provides that single source of truth that is so important in development work.