← HOME - a blog about
xit RSS
██╗ ██╗██╗████████╗██╗ ██████╗ ██████╗
╚██╗██╔╝██║╚══██╔══╝██║ ██╔═══██╗██╔════╝
╚███╔╝ ██║ ██║ ██║ ██║ ██║██║ ███╗
██╔██╗ ██║ ██║ ██║ ██║ ██║██║ ██║
██╔╝ ██╗██║ ██║ ███████╗╚██████╔╝╚██████╔╝
╚═╝ ╚═╝╚═╝ ╚═╝ ╚══════╝ ╚═════╝ ╚═════╝
DEVLOG - PATCH-BASED MERGING IS NOW ENABLED BY DEFAULT -
December 17, 2025
Today I decided to finally
enable patch-based merging by
default in xit. I believe xit is the first version control
system to have this feature while still being fully
git-compatible, and it is (for now) xit's marquee feature.
As I said in the
documentation, patch-based merging is
more reliable and leads to fewer conflicts than the
three-way merge that git uses. The example I used in that
doc was combining merging and cherry-picking, which git
fumbles so regularly that our entire industry has built
processes around avoiding it. We have collectively gaslit
ourselves into thinking it is inherently a bad idea, when it
really is just a limitation of git.
In addition to the cherry-picking problem, there is
another kind of merge conflict that git produces and xit
avoids: adjacent line conflicts. If one branch edits a line,
and another branch edits the line directly above or below
it, git will produce a conflict. People often
wonder why
this is a conflict -- they're different lines!
Imagine starting with this file:
1
2
3
4
On the master branch, you make this change:
1
2 changed on master
3
4
Then on the foo branch, you make this change:
1
2
3 changed on foo
4
What happens when you try to merge foo into master? With
git, you get this:
1
⟨⟨⟨⟨⟨⟨⟨ HEAD
2 changed on master
3
=======
2
3 changed on foo
⟩⟩⟩⟩⟩⟩⟩ foo
4
With xit, you get this:
1
2 changed on master
3 changed on foo
4
Many people, including in the above-mentioned stack
overflow post, assume that this is an intentional safety
feature in git, but that is nonsense. If we added even a
single empty line between 2 and 3 in the example above, git
would've auto-resolved the conflict! Why is it more
dangerous to merge changes that are next to each other
compared to those that are separated by one line?
The reality is that merging can *always* lead to invalid
code, because the VCS doesn't have any semantic
understanding of your code. If you add a new call to
`hello()` on branch A, and you delete the `hello` function
on branch B, guess what happens when you merge B into A? In
both git and xit, it completes successfully but the code is
broken. This is unavoidable.
The behavior above has nothing to do with safety, but
rather is a limitation of the diff3 algorithm that git uses
during a merge. When looking for where to place a change, it
uses the content of the parent line (the one immediately
above it) to decide where it should go. If that line was
changed on the other branch, this technique breaks,
resulting in a conflict.
The core problem is that git just doesn't have enough
information. All it can see is a line number and the
content, after all. In contrast, xit assigns a
globally-unique id to every line, allowing it to know
without ambiguity where it should go. This also explains why
git can
sometimes auto-resolve a conflict by putting the
change in the wrong place! While not as common as adjacent
line conflicts, it's scary that it's even possible.
Currently, the main downside of patch-based merging is
that it can take a long time to initially generate patches,
because it must do so for every commit in the history of the
repo. You can always run `xit patch off` if you want to
disable it, in which case xit will use the three-way merge
just like git. There are plenty of optimizations coming to
make patch generation faster, but you'll always have that
escape hatch if you need it.