Understanding zealous diff3 style in Git conflicts

7 min read
gitvcscli3 more...

When collaborating on code with others or merging branches in Git, conflicts are inevitable. A common tool to resolve these conflicts is built-in markers mechanism. Although merge style of conflict markers became the well-known industry standard, there is still room to improve the experience of using the version control system in this area. This article aims to explain what zdiff3 is and how it can be applied to conflict markers and highlight the algorithm significance.

Branching, merging and why conflicts even occur

In Git, development most of the times happens in branches. A branch in Git is essentially a movable pointer to one of the commits. The default branch in Git is usually called main, trunk or master - developers create new branches for features, bug fixes, or experiments. These branches allow developers to work on the code independently from the main line of development.

When the work on a branch is complete, it is merged back e.g. into the main branch (it does not have to be the default branch, often feature branches are merged into other feature branches). Git attempts to automatically merge the changes by combining the snapshots pointing to the specific branch pointers. If the changes in the two branches do not overlap, Git can usually merge them automatically.

In other cases Git will raise a conflict.

Common scenarios for merge conflicts

  • Editing the same line: Two branches have made different changes to the same line of a file.
  • One branch edits a file while another deletes it: One branch makes changes to a file, while another branch deletes that same file.
  • Concurrent file renaming: Two branches rename the same file differently or make changes to a file that one of the branches has renamed.

What is Git's zealous diff3 merge conflicts style?

The zdiff3 conflict marker is an option for a merge conflict markers in Git that provides way more context than default merge style at the same time being enhanced version of diff3. It shows the common ancestor's version in addition to the two conflicting changes, offering a three-way comparison - just like diff3.

Comparison of zdiff3 vs diff3

Unlike the diff3, zealous one tries to resolve as many conflicts as possible by itself. It is a bit more aggressive in its approach - which results in less manual work for the developer during the process.

Installation of new conflict style

Actually, the question "how to install zdiff3" is quite wrong - it is already built into the Git without any need for installation. The zdiff3 conflict markers are activated by setting the merge conflict style in the configuration via CLI:

git config --global merge.conflictstyle zdiff3

... or by setting it directly in the .gitconfig file:

...
[merge]
  conflictstyle = zdiff3
...

Structure of zdiff3 and diff3 conflict markers

A zdiff3 and diff3 conflict marker styles divide the conflicting area into three sections:

  1. Local Changes (HEAD): Changes that are present in the current branch.
  2. Base Changes (Ancestor): The common ancestor's version of this part of the file.
  3. Incoming Changes (MERGE_HEAD): Changes that are present in the branch being merged into the current one.

The sections are separated by different markers:

  • <<<<<<< HEAD marks the beginning of the local changes.
  • ||||||| merged common ancestors marks the beginning of the base changes.
  • ======= separates the local changes from the incoming changes.
  • >>>>>>> MERGE_HEAD marks the end of the incoming changes.

Understanding the difference between all mentioned conflict styles

Let's start from the default merge style of conflict markers. It is the most common and widely used style. It is simple and easy to understand. It shows only the local changes and the incoming changes, being a two-way comparison.


Reference drawing explaining how does the merge conflicts style look like

Frankly speaking - it is not enough to resolve the conflict in a complex scenario. It is not enough to understand the context of the changes and the evolution of the code. This is where diff3 and zdiff3 come into play.

Reference example of a diff3 style conflict


Reference drawing explaining how does the diff3 conflicts style look like

Unlike previous style and apart from the common ancestor section, the diff3 does not try to aggresively resolve the conflicts by itself, which is easy spottable on the embedded drawing. The developer gets full set of information it is up to him to decide which changes to keep and which to discard.

Reference example of a zdiff3 style conflict


Reference drawing explaining how does the zealous diff (aka zdiff3) conflicts style look like

And here comes the zdiff3 style. As the name says - it is zealous version of a diff3. The behavior can be summed up as an merge + diff3 - in this style both aggressive resolving and common ancestor features are present.

Personally I find it the most useful, straightforward and productive style of conflict markers. It is the most informative (but not overwhelming) information-wise, since changes that are the same between local and incoming are moved out of conflict markers leaving clean ground for analyzing the code.

Explore the differences in practice

If you want to play with the examples from the drawings, create a new directory and use the following commands to create a conflict and see how it looks in different styles:

git init \
  && git branch -m main \
  && echo -e "Foo\nHello" > file.txt \
  && git add file.txt \
  && git commit -m "a" \
  && git branch new-branch \
  && git switch new-branch \
  && echo -e "Bar\nFarwell" > file.txt \
  && git add file.txt \
  && git commit -m "b" \
  && git switch main \
  && echo -e "Bar\nHello" > file.txt \
  && git add file.txt \
  && git commit -m "c" \
  && git merge new-branch

Troubleshooting common zdiff3 and diff3 configuration issues

When setting up zdiff3 or diff3 conflict styles, you might encounter some issues. These problems are more common than you'd think - especially in enterprise environments or when working with different Git versions across machines. Let's address the most frequent ones.

The "unknown style 'zdiff3'" error

The most common issue developers face is Git throwing an error when trying to set zdiff3:

error: unknown style 'zdiff3' given for 'merge.conflictstyle'

This happens because zdiff3 was introduced in Git version 2.35.0 (released in January 2022). If you're running an older version, Git simply doesn't know what zdiff3 is.

First, check your Git version:

git --version

If it's older than 2.35.0, you have few options:

  • Upgrade Git (recommended): On macOS, Git usually comes with Xcode Command Line Tools. You can update it by updating Xcode tools with xcode-select --install. However, Apple's bundled Git often lags behind the latest version. For the newest Git version, you might need to install it separately via Homebrew: brew install git (this will install alongside the system version). On Ubuntu/Debian systems, you might need to add the official Git PPA first to get the latest version.

  • Fall back to diff3: While not as aggressive in conflict resolution, regular diff3 still provides the three-way comparison with the common ancestor - which is already miles better than the default merge style:

git config --global merge.conflictstyle diff3

Configuration not taking effect

Sometimes you set the configuration but conflicts still appear in merge style. This usually happens due to repository-specific settings overriding global ones. Git follows a hierarchy: global → local.

Check what's actually set:

# Check local repository config
git config merge.conflictstyle

# Check global config
git config --global merge.conflictstyle

# See all merge-related configs
git config --list | grep merge

If there's a local override, remove it:

git config --unset merge.conflictstyle

Conclusion

The zdiff3 conflict marker is a powerful tool for resolving merge conflicts in Git.

  • By providing a three-way comparison (outgoing, common ancestor, incoming), it offers developers additional context, helping them understand the evolution of changes and make informed decisions.

  • By being more aggressive in its approach to resolving conflicts, it can save developers time and effort by automatically resolving as many conflicts as possible. The more time you spend on the repetative manual work the more error-prone it gets. zdiff3 is a marvellous way to avoid it and minimize the hassle and frustration.

As collaboration and branch management are integral parts of modern software development, mastering tools like zdiff3 is essential for maintaining a smooth workflow.

Want to talk about the article? Tag or message me on