It doesn't work like that. I should probably rewrite that "first class" part in the docs and use a real example (I wrote it originally), but basically it comes down to this:
When a commit is in a conflicted state, the fact it is conflicted is recorded inside the commit object.
Let's say I have a base B which is the main branch, three commits X Y Z that do 3 different things, and my set of changes that aren't committed, called "@".
B (main) ---> X ---> Y ---> Z ---> @
Now someone pushes to main, so the full graph now actually looks like this with the new main called B'
B ---> B' (main)
\
\---> X ---> Y ---> Z ---> @
Let's say that B' has a change that will cause a conflict in Y. What does that mean? It means that if we were to change the parent of X to B', then the state of Y would be invalid and thus
in conflict, because the changes are not compatible with the state of the system.
`jj rebase -d main -s X` will give you a graph just like this, with such a conflict:
B ---> B' ---> X ---> Y ---> Z ---> @
C C C
The marker 'C' means "This commit is conflicted." Note that
all descendants of a conflicted commit are conflicted too, unless they solve the conflict. (This sentence is phrased very carefully because I'm about to show you a magic trick.)
Okay... So now in my filesystem, I can go see the conflict and I resolve it. Maybe Y renamed a variable that B' got rid in file foo.c, or something.
So now I can solve this conflict. But how do I resolve it? This is too much of a topic to discuss in general but here is the magic trick:
- Solve the conflict in your working copy
- Move the conflict resolution into the first conflicted commit, Y
- The conflict resolution will be propagated to all descendants, just the same way the conflict itself was propagated.
Step 1: solve the conflict in your working copy. Now my history looks like this.
B ---> B' ---> X ---> Y ---> Z ---> @
C C
Note: @ is no longer conflicted! We solved the conflict there, so it is OK. Now how do we resolve the conflict in Y and Z?
Step 2: `jj squash --from @ --into Y --interactive` will move any changes you select in a diff editor and then move that diff into the other commit.
Now the graph looks like this:
B ---> B' ---> X ---> Y ---> Z ---> @
I moved the
resolution of the conflict into Y. And so the resolution of the conflict is propagated to Z.
Step 3: There is no step 3. You are done.
So the secret is that, Jujutsu tracks conflicts and the relationships between conflicts in the commit graph, just like commits. This is why they are "first class." Git basically doesn't do any of this. A commit with a conflict and a commit without one are indistinguishable in Git, unless you look at the actual diff and see rejected hunk markers. A conflicted hunk in a modified file in Git is no different than any other hunk.
This is already too long but as an addendum what I used to do is describe the conflict support as "git rebase --update-refs, combined with git rerere, on 1000x steroids." Except that's actually a shit way to describe this functionality, because only like 5 people on Planet Earth know about --update-refs or rerere. So you really need to experience it yourself or see a step-by-step, I'm afraid.