Skip to main content
jj-git

First-Class Conflict Handling

Step 9 of 12

First-Class Conflict Handling

jj treats conflicts as first-class objects—stored in commits, not blocking errors that halt your workflow.

Git's Conflict Model

In git, conflicts block everything:

git merge feature
# CONFLICT: file.js

# Can't commit until resolved
git status
# both modified: file.js

# Must resolve before continuing
vim file.js
git add file.js
git commit

jj's Conflict Model

In jj, conflicts live in commits. You can continue working, view them, and resolve when ready.

jj new @ feature
# Conflict recorded in @

# Can still work
jj status
# Shows conflicts

# Can commit @ with conflicts
jj describe -m "Merge with conflicts"
jj new

# Resolve later
jj resolve

Viewing Conflicts

jj
jj status
Command comparison: git commands on the left, jj commands on the right
gitjj
git statusjj status

Resolving Conflicts

jj
vim app.js
jj resolve app.js
jj resolve app.js
Command comparison: git commands on the left, jj commands on the right
gitjj
vim app.jsvim app.js
git add app.jsjj resolve app.js
git commitjj resolve app.js

Continuing with Conflicts

In jj, you can commit with conflicts and resolve later:

# Merge creates conflict
jj new @ feature

# Commit the conflict state
jj describe -m "Merged with conflicts in app.js"
jj new

# Continue working on other files
vim other.js
jj describe -m "Work on other file"
jj new

# Come back to resolve later
jj edit --change <commit-with-conflict>
jj resolve
NOTE:

This is powerful for complex merges—resolve conflicts in batches, not all at once.

Conflict Materialization

When you have conflicts, jj shows them in files:

# jj creates conflict markers
$ cat app.js
<<<<<<< Left
const x = 1;
=======
const x = 2;
>>>>>>> Right

But the conflict is also stored in commit metadata:

$ jj show @
Conflict in app.js:
  Left: abc (our change)
  Right: def (their change)
  Base: 123 (original)

Multiple Conflicts

jj
jj new @ feature
jj resolve file1
jj resolve
jj describe -m "Partial merge"
jj new
Command comparison: git commands on the left, jj commands on the right
gitjj
git merge featurejj new @ feature

Abandoning Merges

jj
jj abandon @
jj op undo
Command comparison: git commands on the left, jj commands on the right
gitjj
git merge --abortjj abandon @

Rebase Conflicts

Even with jj's automatic rebasing, conflicts can occur:

jj rebase -d main@origin
# Conflict in app.js

# Resolve and continue
jj resolve app.js
jj rebase --continue

But since jj auto-rebases descendants, you only resolve once:

jj
jj rebase -d @-
jj resolve
Command comparison: git commands on the left, jj commands on the right
gitjj
git rebase -i HEAD~5jj rebase -d @-
git add .jj resolve
git rebase --continue

Conflict Resolution Tools

jj
jj resolve --list
jj resolve file.js
Command comparison: git commands on the left, jj commands on the right
gitjj
git mergetooljj resolve --list

Visualizing Conflicts

# See which files have conflicts
jj status

# Show conflict details
jj show @

# Show just conflicts
jj diff --conflict

Try It Yourself

$
$

Key Takeaways

  • Conflicts are stored in commits, not blocking errors
  • jj resolve marks conflicts as resolved
  • Can commit with conflicts and resolve later
  • jj resolve --list shows all conflicts
  • Auto-rebasing means resolve conflicts once
  • jj op undo to abandon problematic merges

Next Steps

Finally, let's look at advanced workflows and tips for jj power users.