What is merge complexity?
Typically, git will perform a 3-way merge when merging changes. For pipelines, this usually means comparing:
Most recent commit on the promotion branch
Most recent commit on the environment branch
The last ancestor commit that is shared to those two commits
In the example below, develop is being merged into main and the shared ancestor would be commit #1, with hash 752d352
. This is referred to as the 'base' commit of the merge.
In reality, commit histories are usually more complex than this and there are several scenarios that can cause git to identify multiple base commits rather than just one.
Multiple merge base example
Multiple merge base example
This section describes a scenario that causes multiple merge bases. Feel free to skip this explanation if you don't need the detail though.
In this scenario we have 2 long-lived environment branches, main
and develop
and 3 feature branches. We ignore aspects of the pipelines branching model that would make this even more complex within Gearset (I.e. promotion branches and back propagation PRs)
feature1
andfeature2
are created frommain
a single change is committed to each of the feature branches.
feature1
is merged intodevelop
and thenmain
feature2
is merged intodevelop
feature3
is now created frommain
a change is committed to
feature3
feature2
is merged intofeature3
to leave us on commit #7 -56eab2de
If we try to merge
feature3
in todevelop
then the shared ancestor is16e7560
onmain
. However, there are two different paths to get to our current commit at56eab2de
. These two paths mean that we have 2 merge bases that now need to be reconciled. The corresponding commits for these paths are:a84b77d
frommain
c5eb2ee
fromfeature2
If you want to investigate this for yourself then you can view the list of merge bases between the two branches by running
git merge-base --all feature3 develop
Why does this matter?
When there are multiple merge bases, our Semantic merge algorithm will need to run for each combination of possible bases in turn. Essentially multiplying the time taken to merge by the number of merge bases.
Semantic merge is highly optimised. However, in situations involving hundreds of merge bases it can easily become a significant portion of the time spent validating or deploying changes.
With Gearset's semantic merge algorithm, merges with 1 merge base take under 6 seconds on average. In comparison, merges with 50 or more merge bases take around 26 minutes on average!
In pipelines, we use the semantic merge algorithm as part of every validation run, as well as for many deployment runs. Every time a PR is created, or a source branch in a PR is updated, a validation is triggered. Every time an environment is updated it can trigger validations in the PRs that are open against that environment.
If all of these actions are taking 26+ minutes then it can quickly become very difficult to push changes through the pipeline with the velocity required by stakeholders.
It's worth noting that Azure DevOps will show a similar message 'Warning: Multiple merge bases detected' in this situation for similar reasons.
How do I fix it?
This problem can have two slightly different high-level causes:
The branch for the static environment is out of sync with the main branch
In this case, all PRs targeting the environment will show this warning.
This can be resolved by creating a sync PR using the sync icon. (see this article for more details on sync PRs)
This will merge your main branch into the environment branch. Any new feature branches created after this should now use this as the base commit when merging.
However, existing feature branches will still show the warning as they were branched from main before the sync commit was created and therefore cannot use it as a common ancestor.
The feature branch commit history is introducing additional merge bases
In this case, only some PRs will show this warning and the warning will probably persist as the feature is promoted to subsequent environments.
This will usually be caused by adding complexity to the commit history of the feature (or promotion) branch. E.g.
Creating a feature branch from a branch other than the branch at the end of your pipeline (e.g. Main/Master).
Merging another branch directly into the feature or promotion branch.
In general, it is best to avoid getting in to this state by ensuring your team know not to perform the actions listed above.
One way to resolve this scenario after it's happened is to create a new feature branch from your main branch and then squash merge the problematic feature branch into it.
⚠️ Bear in mind that this will squash all the changes in the old branch into a single commit, so you lose some of the detail in the commit history.
Note that as a rule, squash merging is not compatible with Pipelines. In this case though, it can be used as a workaround:
We have a pipeline with 3 long-lived static environment branches
staging
,uat
andmain
. We have a feature branch,my-feature
, which is showing the 'high merge base count' warning message.Create a new branch from
main
, we'll call this branchmy-feature-squashed
for this example.Use your VCS (GitHub, ADO, etc) to create a pull request merging
my-feature
intomy-feature-squash
Once any conflicts are resolved and any other issues addressed, merge the PR in the VCS using a squash merge. Note that this setting could be disabled so you may first need to update repository settings to temporarily allow it.
You can now create a new feature against your dev sandbox within Gearset and choose
my-feature-squashed
as the feature branch.The change can now be promoted through your pipeline within Gearset as normal.