Posted 23 September 2021
by Adam Wisher

Share this blog:

Read more in Data Management

Automatic Merge Conflict Resolving for git

This post describes how merge conflicts can be automatically resolved using maven POM files as an example. The example related to the dependencies section of Maven POM files depicted below:

Screenshot-2021-09-13-at-10.53.44.png

The highlighting indicates that dependency order is different. This reflects what IDEs do automatically and also interactive user manipulation. When feature branches are created dependencies may need to be updated or increased; they aren’t typically reversed or reverted to a lower or earlier version.

Lets look at what happens if we use git’s built-in diff3 based merge:



xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
4.0.0

groupId
git-merge-driver
7.0.4


<<<<<<< HEAD

com.deltaxml.merge
merge
7.1.0

=======
>>>>>>> v2

com.deltaxml.merge
flexlm
7.1.0


com.deltaxml.merge
<<<<<<< HEAD
deltaxml
10.3.0
=======
flexlm
7.0.6


com.deltaxml.merge
merge
7.0.6
>>>>>>> v2


Here’s my first attempt to use our XML Merge with rule processing:


4.0.0
groupId
git-merge-driver
7.0.4


com.deltaxml.merge
merge
7.1.0


com.deltaxml.merge
flexlm
7.1.0


com.deltaxml.merge
deltaxml
10.3.0
7.0.6


com.deltaxml.merge
merge
7.0.6



dev/git-merge

It’s easier to see the dependencies, but why are there two version children in one of them? I delved a little deeper… The above result was generated using our command line driver for concurrent3 using the default parameter settings. An important one here was element splitting. What was happening was there was a textGroup containing the version numbers (‘10.3.0’ and ‘7.0.6’) and that was the only content of the element. As there was a high proportion of change it was then split. The splitting resulted into logically two additions which were then rule processed and added.

Lets look at this without splitting, word-by-word or rule processing applied:



xmlns:deltaxml="https://www.deltaxignia.com/ns/well-formed-delta-v1"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
deltaxml:version-order="a, v1, v2"
deltaxml:content-type="merge-concurrent"
deltaxml:version="2.0"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
deltaxml:deltaV2="a!=v1!=v2">
4.0.0
groupId
git-merge-driver
7.0.4


com.deltaxml.merge
merge


7.0.4
7.1.0




com.deltaxml.merge


deltaxml
flexlm




10.0.0
7.1.0




com.deltaxml.merge


flexlm
deltaxml




7.0.4
10.3.0
7.0.6




com.deltaxml.merge
merge
7.0.6


Now we can see the artifacts are not aligning and this is because dependencies are an unordered set. We can fix this with orderless and in the current XML merge by keying, so for example:



com.deltaxml.merge
merge
7.0.4

...

With this we get our expected alignment. Here we’ve done rule processing and the second dependency had some non-conflicting changes, but we don’t see these after rule processing. However the three way version conflicts remain:



xmlns:deltaxml="https://www.deltaxignia.com/ns/well-formed-delta-v1"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
deltaxml:version-order="ancestor, mine, theirs"
deltaxml:content-type="merge-concurrent"
deltaxml:version="2.0"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
deltaxml:deltaV2="ancestor!=mine!=theirs">
4.0.0
groupId
git-merge-driver
7.0.4


com.deltaxml.merge
merge


7.0.4
7.1.0
7.0.6




com.deltaxml.merge
deltaxml
10.3.0


com.deltaxml.merge
flexlm


7.0.4
7.1.0
7.0.6




Now do we want my local branch or the remote or theirs in this case? I’d argue we want the highest version, irrespective of which branch its on; given that APIs are generally upwardly compatible it should hopefully work for all branches.

Luckily we can do this automatically in XSLT: here’s a POM dependency resolver:



xmlns:xs="http://www.w3.org/2001/XMLSchema"
xmlns:math="http://www.w3.org/2005/xpath-functions/math"
xmlns:deltaxml="https://www.deltaxignia.com/ns/well-formed-delta-v1"
xmlns:pom="http://maven.apache.org/POM/4.0.0"
exclude-result-prefixes="xs math"
version="3.0">








This will ‘auto-resolve’ the version conflicts (which are going to be three way by definition). One final thing to consider – should this filter fix up deltas as it goes, so for example the deltaV2 on the parent dependency element, or should it just do a simple local change and we then have a final process which checks for any unresolved conflicts and when none are found removes all deltaxml attributes including deltas, version-order and content-type?

Putting this all together

The existing git merge driver:  deltaxml/git-merge-driver  will need an input filter for orderless and keying and also the above output filter and possibly as discussed above a filter to tidy up delta attributes.

This necessitates changing the driver code and the API changes needed require the move from the ThreeWayMerge class to the ConcurrentMerge class.

Future

There are certainly possibilities to extend this further; dependencies in POMs was the first example that comes to mind, it wasn’t an exhaustive analysis of the POM syntax.

This post has concentrated on an example and use-case for automatic conflict resolution, a future post will look at interactive conflict resolution.

© 2000-2025 DeltaXML Ltd. registered in England and Wales (Company No. 2528681), trading as DeltaXignia. All rights reserved