Using Git Conflict Style Diff3 to Easily Resolve Merge Conflicts

There is a git setting that is off by default, but when turned on, it makes resolving merge conflicts trivial. That setting is merge.conflictstyle = diff3. This setting is a merge conflict resolving superpower. Even if you had nothing to do with the changes in the two trees you are merging, with it on, you are able to infer the correct resolution.

To explain what it really does, I want to start by presenting a merge conflict of ECMAScript imports without this setting turned on:

<<<<<<< HEAD
import { documentService, userService, operationalTransformService } from './src/services'
=======
import { documentService, documentHistoryService } from './src/services'
import { sanitizeDocumentTitle } from './src/view-helpers'
import { formatRelative, differenceInMinutes } from 'date-fns'
>>>>>>> hotfix-abc

Now suppose you are a tech lead, who had nothing to do with the implementation of either of these branches, and you need to do this merge to run the tests against a hotfix before deploying. What do you do? Go back and read each patch to figure out what changes each one did? Scan the rest of the file for references to these imports? Do you run a linter a bunch of times to figure out which imports to keep and which to remove? What if it's not a set of imports but actual business logic that changed?

The problem is that you have no context without looking at the actual patches themselves to know what happened. Did hotfix-abc add documentHistoryService or did the branch you have checked out remove it?

What you really need is context of what this portion of the file looked like before each branch made their incompatible changes. This is what merge.conflictstyle = diff3 gives you. With each merge conflict, git will find the closest common ancestor to that piece of code and git will insert it between the two sides of your conflict like so:

<<<<<<< HEAD
import { documentService, userService, operationalTransformService } from './src/services'
||||||| f6e4a54
import { documentService, userService } from './src/services'
import { formatRelative } from 'date-fns'
=======
import { documentService, documentHistoryService } from './src/services'
import { sanitizeDocumentTitle } from './src/view-helpers'
import { formatRelative, differenceInMinutes } from 'date-fns'
>>>>>>> hotfix-abc

Instead of just the final results of the two changes you are merging, git gives you the information you need to easily figure out what happened in each branch. Even though you, the reader, had nothing to do with either change, you should still be able to deduce the following:

In HEAD:

And in hotfix-abc:

Given this information, you can find the correct conflict resolution:

import { documentService, documentHistoryService, operationalTransformService } from './src/services'
import { sanitizeDocumentTitle } from './src/view-helpers'
import { differenceInMinutes } from 'date-fns'