Skip to content

Instantly share code, notes, and snippets.

@meain
Created November 20, 2025 08:43
Show Gist options
  • Select an option

  • Save meain/5a844ecb169b8a3d8398ffcf0d33eeef to your computer and use it in GitHub Desktop.

Select an option

Save meain/5a844ecb169b8a3d8398ffcf0d33eeef to your computer and use it in GitHub Desktop.

Intro to Jujitsu (jj)

A modern VCS for a civilized age jj-vcs/jj

width:200px align:right


Most of you know and likely hate using git


I've always loved git


I store everything in git

Including notes, tasks, medications, journals and more...


I've blogged about it

About git, git internals, and how to use git more effectively...

width:500px


I have given talks about it

width:500px

infracloudio/infranaut-meetup#133


But I don't use git anymore ๐Ÿ˜„

I've never found git to be hard, but the CLI feels arcane.


Quick survey

  • How many of you can confidently do git rebase?
  • How many of you know about git rerere?
  • How many of you use more than 3 stashes?

What is Jujitsu?

A Git-compatible VCS that rethinks the version control interface

  • Works alongside your existing .git folder
  • Same underlying storage, better UX
  • Easy to try, easy to migrate back

Let's learn jj


Getting started

# Start a new repo or convert existing
jj git init --colocate .

# Or clone an existing one
jj git clone <repo-url>

.jj and .git co-exist happily in the same repo


The fundamental difference

Git's model: You create commits explicitly

JJ's model: Every change is automatically a commit You organize and refine later


[DEMO] Your first jj commands

jj status    # See what's changed
jj log       # View commit history

# Make some changes to a file

jj log       # Notice: changes are already committed!
jj show      # See what changed
jj describe  # Add a description anytime

No more "forgot to commit"

JJ automatically tracks your working copy as a commit

Focus on writing code, not remembering to save


Working without branches

jj new   # Start new work (no branch needed)

# Make changes

jj new   # Start another piece of work

Create branches (bookmarks) only when you're ready to push


[DEMO] Basic workflow

# Make changes
jj describe -m "Add feature X"

# Create a bookmark for pushing
jj bookmark create feature-x

# Push to remote
jj git push

The real power of jj

Operations that are painful in git become trivial


Rebase from anywhere

You don't need to checkout a branch to rebase it

# Rebase any commit onto any other commit
jj rebase -s <source> -d <destination>

No "detached HEAD" confusion


Split commits easily

jj split

Interactively split any commit (even old ones) into multiple commits


Edit any commit

jj edit <commit>

Make changes to any commit in your history, not just the latest


[DEMO] Real-world workflow

Let's see how these features work together...

mkdir demodir && cd demodir
jj git init --colocate . # initialize the repository
echo 'apple' > fruit.txt
echo 'carrot' > vegetable.txt

  1. Split the changes (jj split)
  2. Describe revisions (jj describe)
  3. Parallelize revisions (jj parallelize q::u)
  4. Create a merge commit (jj new)
  5. Make additional changes in one file
  6. Absorb the changes (jj absorb)
  7. Undo that change (jj undo)
  8. Rebase manually onto other branch (jj rebase)
  9. Name both branches (jj branch)
  10. Linearize it (jj rebase)

No more stash!

Instead of stashing:

jj new   # Start new work on parent commit

Your previous work stays as a commit, perfectly preserved


Conflicts can wait

JJ tracks conflicts in commits

You can:

  • Rebase through conflicts
  • Resolve them whenever you're ready

jj absorb

Automatically figure out which commit each change belongs to

# Make fixes to multiple commits
jj absorb

JJ absorbs changes into the right commits based on context


Powerful revision selectors

"stack(r)" = "r | ancestors(descendants(immutable_heads()..r), 2)"
"mine" = "remote_bookmarks() & (mine() | committer('[email protected]'))"
'closest_bookmark(to)' = 'heads(::to & bookmarks())'
'unpushed(x)' = '::x & ~reachable(::x, remote_bookmarks())'

Build complex queries to select exactly the commits you want


Built-in undo for everything

jj op log              # View all operations
jj undo                # Undo last operation
jj op restore <id>     # Restore to any point

Every operation is recorded and reversible


Safety net: Use git anytime

If you ever get stuck or unsure:

git status
git log
git checkout main

Your .git folder is always there and always in sync


Evolution log

See how a commit has changed over time:

jj evolog <commit>

Perfect for understanding what happened during complex rebases


Why switch to jj?

Work naturally: Focus on code first, organize commits later

Powerful operations: Rebase, split, and modify any commit from anywhere

Safety first: Everything is undoable, conflicts can wait

Zero risk: Co-exists with git, migrate back anytime


When should you use jj?

  • Complex rebasing workflows
  • Feature development with lots of iteration
  • Teams that value clean history

Resources

Documentation: https://martinvonz.github.io/jj/ GitHub: https://github.com/jj-vcs/jj Tutorial: https://steveklabnik.github.io/jujutsu-tutorial/

Join the Discord community for help and discussion!


Key takeaways

  • JJ rethinks the version control interface, not the storage
  • Automatic commits free you to focus on code
  • Complex operations become simple
  • Everything is undoable
  • Works alongside git, try it risk-free

[DEMO] Configuration

Let's look at useful configurations...


[DEMO] Real repository

Let's look at how this works in an actual project...


Thank you! Questions?

Seriously, ask me questions.

Give it a try: jj git init --colocate .

Abin Simon (meain)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment