Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Resurrecting And Branching

Important

You play with undoing operations, start new development lines by inserting Changes mid-branch, and edit messages deep in the history tree. It’s easier than it sounds!

Warning

Changed your mind? Want to resurrect the license commit?

Tip

Yes! Undoing is always jj undo:

jj undo
Undid operation: 3a6c93cd543e (2026-06-10 15:48:34) abandon commit c25416325e097a36d0cc1216fb4938e0c44b28a8
@  o    empty A dummy React.js application
○  t    A license
○  x    Initial commit
◆  z    empty

Back to life!

Adding Changes In Arbitrary Positions

jj new adds a Change on top of the Current Change. But you can insert Changes anywhere. Select where using -r (the same option used with abandon):

jj new -r x -m "One here"
@  k    empty One here                        <-- this one
│ ○  o  empty A dummy React.js application
│ ○  t  A license
├─╯
○  x    Initial commit
◆  z    empty

This started a new branch line, which you can grow with more jj new commands.

Want to insert a Change right before o (between o and t)? Use --before (or -B):

new --before o -m "One there"
○  o    empty A dummy React.js application
@  zv   empty One there                       <-- this one
○  t    A license
│ ○  k  empty One here
├─╯
○  x    Initial commit
◆  zz   empty

Everything Is Dual

Symmetrically, there’s also --after (or -A).

Warning

Insert a commit right after zz.

Tip

jj new -A zz -m "Initial commit is no more"
~
○  x    Initial commit
@  m    empty Initial commit is no more
◆  zz   empty

In summary, starting from:

o-o-R-o-o

This is what you get with the 3 different options:

jj new -r R

o-o-R-o-o
     \
      X
jj new --after R

o-o-R-X-o-o
jj new --before R

o-o-X-R-o-o

These moves are perfectly possible in Git, but cumbersome because you must handle the underlying mechanics. So, it’s unlikely you have performed them often.

The Ubiquitous -r Option

x’s message is Initial commit:

○  x    Initial commit                     <-- this one
@  m    empty Initial commit is no more
◆  zz   empty

Having inserted a Change before it, the description is now misleading. Mildly infuriating! How to amend it?

You’ll love this about Jujutsu: once you learn a grammar element, you can use it everywhere it makes sense. -r can be used with jj new to position a Change, with log to define what to display, with jj desc to target a message…

Warning

How to fix x’s description?

Tip

jj desc -r x -m "Hello, world"
○  x    Hello, world
@  m    empty Initial commit is no more
◆  zz   empty

Fixed. Good job.

What’s The Point of Creating Empty Commits?

Who would ever create empty commits, though? Notice:

  • You can jj edit them later and add actual content.
  • Committing before coding is idiomatic in Jujutsu workflows.
  • Editing isn’t the only way to populate Changes. You’ll soon move edits and files from a distance, and empty commits act as useful placeholders.

Cleaning up

Here’s a Chapter closing exercise. Move to o:

jj edit o

Get rid of the dummy commits you just created:

  • k: One here
  • zv: One there
  • m: Initial commit is no more

Warning

How would you do that?

Tip

Combine abandon and -r:

jj abandon -r k -r zv -r m
@  o    empty A dummy React.js application
○  t    A license
○  x    Hello, world
◆  z    empty

Congrats if you got it!

Many commands operate on single or multiple Changes, contiguous or sparse. These are equivalent:

  • jj abandon -r k -r zv -r m
  • jj abandon k zv m
  • jj abandon -r 'k | zv | m'

jj abandon k zv m works because when there is no ambiguity, revsets can be passed as positional arguments.

The last example uses the | operator from the Revset Language, a powerful yet simple syntax for selecting Change sets. Read more in A Glimpse of the Revset Language.

Where To Go From Here?

Admittedly, these exercises were a bit contrived. Make them your own, and we will soon apply them to genuinely useful cases.

In the meantime, be proud! You just executed manipulations that are far from trivial in raw Git.