Why does GitHub submodule merge conflict detection work differently to gits?

Viewed 41

I write this as one who fully understands the complexities of submodules and their limitations, so please don't use your answer to give me a lecture about this being the fate I deserve for using submodules. I do know that if they are used the wrong way, they can create all manner of nasty nightmares. However, the way I am using them is not one of those ways - developers are barely aware of their existence and almost all the management of them is performed in strucutred way by automated CI/CD processes.

I am using a pure git superproject and its submodules as a configuration tracking mechanism for a collection of submodules. Each tag in the superproject represents a configuration of submodules that can be deployed into an environment. There is one branch per environment which tracks what is actually deployed in an environment. There is a master branch that tracks the master branches of the all the submodules. Other branches are used to track feature or fix branches of the same name in the submodules. All the accounting is done automatically by the CI/CD system so that developers barely need to be aware of the existence of submodules, let alone how to wrangle with them.

The normal release process is to tag the master branch and merge that tag into an environment branch. Typically, this will update the environment branch with the state of the master branch and thus make the environment branch tree-same and submodule-same as the tag.

In case a hotfix is required, we create a branch from the same tag as was last pushed into the environment to be hotfixed, create branches of the submodules with the same name and at the same commit as the tag, and update the submodules as required to implement the hot fix, which ultimately updates the superproject branch of the same name. We then tag that hotfix branch with a tag, merge that tag into the environment branch and the hotfix is then deployed to the related environment by the CI/CD processes.

This potentially creates a non-trivial divergence between the hotfix branch and master which might cause a merge conflict on a future normal deployment so we do an 'ours' strategy merge of the hotfix tag back into master which doesn't change the master tree, but does enough with the history to keep git happy (we also, of course, merge the hotfix branches from the submodules into the master branches so that we can sleep in bed at night and not feel bad about lying about whether superproject merge was legit or not).

All of this works pretty well, and there are almost never any merge conflicts that aren't caused by a failure to do that last step.

Today I was working through the hotfix process with the intention of delivering a single hotfix tag to 3 environment branches. This seemed straightforward, but strangely it didn't work.

If I test it locally, the merge into each of the 3 environment branches works, but when I create a tag delivery branch (identical to the hotfix tag) to do the same in GitHub, GitHub reports a merge conflict between 2 of the environment branches and the tag delivery branch, but not between the 3rd environment branch.

For reference I have included screen captures of gitk force-{environment} ^{hotfix} which shows the divergence of the environment away from the hotfix tag/branch (there is always going to be at least one merge commit which diverges).

THe intended merge is equivalent to:

git checkout force-{environment} &&
git merge {hotfix}

failing environment branch (force-exosphere):

failing environment branch

working environment branch (force-quartz):

working environment branch

The curious thing is that the force-{environment} branch that is failing is the most trivial one (force-exosphere) - the more complicated branch (force-quartz) actually passes GitHub's merge conflict detection logic. There is another branch (force-emerald, not shown) which looks and behaves like force-exosphere. All 3 branches merge without conflict if the merge is done natively with git, outside of GitHub.

My question is: what is it about GitHub's merge conflict detection logic that is causing GitHub to report the existence of merge conflict on a submodule when git itself does not?

0 Answers
Related