Where you see how to interpret the conflict markers and you see how a conflict resolution automatically propagates.
Resolving A Conflict by Editing It
The most straightforward and natural way to solve a conflict is by
editing the affected files.
In this case, it's a matter of editing the merge Change zo:
@ l empty
× zm My parent is conflicted
× zo Merge conflict <- Resolve the conflict here
├─╮
│ ○ nz merge-b
○ │ m merge-a
├─╯
○ vr Base of merge-a and merge-b
│
~
Notice: you've surely obtained a different Change ID. For convenience,
let's call it nz+, meaning the nz's direct child.
Did I Tell You Not To Edit Changes?
If you are tempted to run jj edit zo, please, don't! Remember my
heartfelt plea in Don't Edit. Do jj new zo instead. Remember that any change you perform in zo is
automatically propagated. This way, you can review your resolution
before finalizing it and easily undo any mistake.
So, do yourself a favor and create a Buffer Change:
jj new zo
This is what you get:
@ k empty <- Your Buffer Change
│ × zm My parent is conflicted
├─╯
× zo empty Merge conflict <- The Change to fix
├─╮
│ ○ nz merge-b
○ │ m merge-a
├─╯
○ vr Base of merge-a and merge-b
│
~
Of course, even this Buffer Change will be conflicted. That's exactly the point: you want to resolve the conflict from there, so it must inherit it.
So, here's the idiomatic workflow for attacking conflicts:
- Run
jj newtargeting the conflicted Change. - When you've solved the conflict,
jj squash, as per the mini-workflow. - If you want to start over,
jj restore.
This is exactly the mini-workflow you saw in Don't Edit.
Resolving The Conflict
Edit the conflicted file file.txt. You will see this content:
Donec neque quam, dignissim in, mollis nec, sagittis eu, wisi.
Phasellus neque orci, porta a, aliquet quis, semper a, massa.
Etiam vel neque nec dui dignissim bibendum.
Nunc porta vulputate tellus.
Nunc eleifend leo vitae magna.
Sed id ligula quis est convallis tempor.
<<<<<<< conflict 1 of 1
%%%%%%% diff from: vrzponzu b12f7845 "Base of merge-a and merge-b"
\\\\\\\ to: mvxxwqoo e1acf668
-We will create a conflict here.
+We will create a conflict here: merge-a added this text.
+++++++ nzsunxwp 0004a47a
We will create a conflict here: merge-b added this text.
>>>>>>> conflict 1 of 1 ends
Nullam rutrum.
Curabitur vulputate vestibulum lorem.
Nullam eu ante vel est convallis dignissim.
Sed bibendum.
Aliquam posuere.
Let's learn how to read the conflict:
<<<<<<< conflict 1 of 1
%%%%%%% diff from: vrzponzu b12f7845 "Base of merge-a and merge-b"
\\\\\\\ to: mvxxwqoo e1acf668
-We will create a conflict here.
+We will create a conflict here: merge-a added this text.
+++++++ nzsunxwp 0004a47a
We will create a conflict here: merge-b added this text.
>>>>>>> conflict 1 of 1 ends
Interpreting Conflicts
The first and the last lines are obviously the conflict, with the total number of conflicts:
<<<<<<< conflict 1 of 1
>>>>>>> conflict 1 of 1 ends
All the lines above and below those boundaries are fine: both parents
agree on them.
Between those 2 markers, you will find 2 elements:
- How the 1st Change wanted to change the common Base.
- The content of the 2nd Change.
Look:
%%%%%%% diff from: vrzponzu b12f7845 "Base of merge-a and merge-b"
\\\\\\\ to: mvxxwqoo e1acf668
-We will create a conflict here.
+We will create a conflict here: merge-a added this text.
Read it as:
%%%%%%% diff from: v "Base of merge-a and merge-b" <- from the common Base
\\\\\\\ to: mvxxwqoo e1acf668 <- the first Change merge-a
-We will create a conflict here. <- wants to apply this diff.
+We will create a conflict here: merge-a added this text.
Of course, - means deleting a line, + means replacing the line
with some other content.
Resolving The Conflict
Here's a possible resolution:
Sed id ligula quis est convallis tempor.
We will create a conflict here: merge-a added this text, merge-b added this text.
Nullam rutrum.
*Very* interestingly, if you run jj st, you will see this message:
Hint: Conflict in parent commit has been resolved in working copy
Cool! That's how Jujutsu tells you:
Hey, pal! If you squash back this change, you fix the conflict.
Let's do that
jj squash
Perfect, it's all clear!
What about the Buffer Change? No worries, it's an empty, messageless
Change. It will be automatically abandoned once you move away; it was
a temporary working area from the start.
Conflict Resolutions Propagate
Look how beautiful:
@ l empty
○ zm My parent is conflicted
○ zo Merge conflict
├─╮
│ ○ nz merge-b
○ │ m merge-a
├─╯
○ vr Base of merge-a and merge-b
│
~
Not only is zo clear: the conflict resolution propagated to zm and
to @ too.
How cool is that?
Resolutions All The Way Down
That's a general rule. If you build on top of a conflict:
× j <- also in conflict
× i <- also in conflict
× h <- also in conflict
× g <- also in conflict
× f <- also in conflict
× e <- also in conflict
× d <- conflict
○ c
○ b
○ a
The moment you fix the conflict somewhere, the resolution will be
propagated. Say you fixed the conflict in f, you'd get:
○ j
○ i
○ h
○ g
○ f <- resolved here
× e <- conflict
× d <- conflict
○ c
○ b
○ a
Of course, ideally you'd fix the conflict where it originated. In this
case, since you already have a resolution in f you can
jj squash it to d:
○ j
○ i
○ h
○ g
○ f
○ e
○ d
○ c
○ b
○ a
I hope you got the idea.
Ready to see some more challenging cases?