Top 5 tips on how to avoid Git merge conflicts

Viktor Reinok
4 min readApr 4, 2022

--

Would you like to reduce friction during development? Smoothen delivery pipeline by reducing manual interventions? Improve quality. Or just add another minor refinement into a sea of cumulative improvements? Addressing git merge conflict root causes would be a perfect place to start!

What this article is not about? It is not about how to solve merge conflicts. The article is about the optimizing design process, ergonomics of tooling, and applying mental frames that one could use to reduce the number of avoidable merge conflicts.

What is a merge conflict? Basically is it a situation when src ( source code) in branch A was changed at the same location as in a branch B that is being merged to branch A. Now, git is not smart enough to make the decision on how to merge the src at the particular location. Therefore the merge conflict requires manual intervention: A decision on which side A or B is the correct option.

  1. Use unified rules for import ordering in your team
    According to my experience, this is the number one reason for merge conflicts that could be avoided. Manny language stores resource import definitions on top of a file and most often different IDEs and different configurations result in a merge conflict.
    The solution would be to control code style by:
    a) IDE configuration or plugins
    - Eclipse code formatter
    b) Git commit hook that auto formats the src
  2. Avoid appending code at the end of files. Especially in frequently modifiable files.
    Some examples:
    a) Error code classifiers. Those get often modified and it is just foolish to count up the error codes. A better way would be to group the error codes by domain meaning.
    b) New private methods at the end of the src? Why not leave it as IDE does it by default. IntelliJ for example leaves the newly created method under the method from where the extraction was done. Today's tooling does not require too scrolling through src. Src is navigatable and well-indexed.
    c) Property files. Does it really make sense to add new properties at the bottom of the file? Not always. It does communicate the time those properties were added but so does git blame, right? So, why not group those rather by function, business domain, or type of property?
  3. Disable autoformatting of the whole file that is being edited.
    But what about leaving the area nicer after you left? Let's be honest it's all or nothing deal. Either agree on strict rules that all have to follow or there will be someone who will be applying some conflicting formatting. My recommendation is to only format the edited src.
    Some examples:
    a) Adding this keyword to the variables in Java. Not worth it. I have experienced a bug that was caused by missing this keyword only once in my career. That bug was discovered very early. So, in my opinion, weighing down the whole team thinking you are making things better by adding a huge amount of unnecessary changes to the whole file not worth it.
    b) Using different whitespace configurations. For example tabs vs spaces. Although it is rather more important less advanced tools for resolving the merge conflicts. Do not recall seeing such conflict marked by the IntelliJ IDEA merge tool.
  4. Synchronize the branches as often as possible
    Merge upstream branches to downstream branches often. Sure, it will not avoid the merge conflict but it will reduce the effort of solving merge conflicts exponentially. It is drastically more difficult if multiple workstreams by different authors who were doing different things intertwine. Merging an upstream branch into your branch frequently will reduce the chance of realization of the scenario mentioned above.
  5. Keep the changes small
    Less modification over a shorter period of time just reduces the probability of the same line of src being modified. Use the divide and conquer approach to slice the work and design your application in such a way that small increments would be easier to release.

Now, what if you started using those 5 tips? Merge conflicts will still happen, hopefully much less frequently. The study below will shine a light on why one would need to pay attention to the resolution of a merge conflict.

A 2019 study tells that src that [2]

We also found that code associated with a merge conflict is twice as likely to have a bug, and code associated with SEMANTIC merge conflicts are 26 times more likely to have a bug compared to code associated with other conflicts.

Being a bit naive, we can conclude that paying more attention to points 4 and 5, would also contribute to a better quality besides smoother workflow.

Misc:

Does it make sense? Git command to find what are the most modified files in your git repo:

git log --pretty=format: --name-only | sort | uniq -c | sort -rg | head -20

Some FYIs:

There are 6 merge conflict types:

  • SEMANTIC -Two conflicting semantic changes, where two different changes in the program logic overlap
  • DISJOINT -Semantically unrelated changes that overlap textually
  • DELETE -A conflict in which one of the branches deletes code modified on the other branch
  • FORMATTING -Conflicting changes due to formatting (whitespace changes) MSLoggerBase
  • COMMENTS - Conflicting changes are limited to comments only MSLoggerBase
  • OTHER -Not belonging to any of the above

The frequency of occurrence: SEMANTIC, FORMATTING, DISJOINT (60, 23, and 15 %)

References:

  1. https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/addressing-merge-conflicts/about-merge-conflicts
  2. The study https://www.ics.uci.edu/~iftekha/pdf/J4.pdf
  3. https://stackoverflow.com/questions/44359334/what-are-the-reasons-and-cases-that-cause-git-merge-conflicts
  4. https://codescene.com/
  5. https://www.youtube.com/watch?v=7FApEq8wum4

--

--