Understanding zealous diff3 style in Git conflicts
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:
- Local Changes (HEAD): Changes that are present in the current branch.
- Base Changes (Ancestor): The common ancestor's version of this part of the file.
- 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.
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
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
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 defaultmerge
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.