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

Goal

You conclude that the Git Index was a Good Thing®.
So, you learn a micro-workflow that builds on top of the same idea and will save you a lot of headaches.

Don't Edit

In the chapter Committing you read that:

By editing the file system, you are directly editing the commit.
We will soon see how this is somewhat dangerous.

In hindsight, I was a bit dramatic. After all, Jujutsu, like Git, never deletes information, so there's nothing really dangerous.
But why let accuracy spoil good drama? So, let me reformulate the idea as follows:

Directly performing open-heart surgery on a Change with jj edit is dramatically more perilous than working from a distance, on a new Change on top of it.

Terrified? Good. (Really, you have no reason to be, but good).

What's Wrong With Editing?

jj edit is ruthless: you edit the filesystem and each and every change is unconditionally committed to the Current Change. Even worse: if you are editing a Change deep in the history tree, this will also recursively propagate the changes to all the descendants, with an automated rebase.

The problem is that not every change is intentional:

  • Building the project can create artifact files. Jujutsu might track them before you get the chance to add them to .gitignore.
  • We all have fat fingers, and we all make mistakes. Combine "mistakes" with "automatically and recursively propagated" and have a recipe for disaster.
  • Editors and tools might create stray files. jj edit won't care: it will commit and rebase anyway.

A good rule of thumb, with Jujutsu just as with Git, is:

Always review the changes before making them part of a commit.

That's why the Git Index exists. jj edit is often just too rushed.

The solution is pretty easy: whenever you are tempted to run jj edit X, run jj new X instead. Rather than starting open-heart surgery on X (sirens blaring!), jj new prepares a safe working area for you to work in peace (elevator music...).

Mini-workflow

Here's a little recipe. If you want to edit X:

  1. jj new X
  2. Make your edits.
  3. When you are done, review your work with jj diff and squash it back with jj squash.
  4. If you want to start over, jj restore.

jj diff will show you the changes you made.
jj restore will revert only your changes, leaving the original target Change intact.

See This In Practice

Again using our sample repository. Say you want to edit v:

○  zx           Click alternates Xs and Os main
○  v            Click sets a X                    <-- What you want to edit
○  s            Square has state
│ ○  kt         empty Hover effect to board squares
│ ○  rv         empty Changes to both CSS and app.js
│ ○  q          Add the CSS file css
│ ○  rt         Link to CSS
├─╯
│ ○  o          Play instructions manual
│ ○  kx         Play manual
├─╯
○  n            Square is interactive
~

Instead of jj edit v, go with $ jj new v:

@  l            empty                             <-- Your Current Change
│ ○  zx         Click alternates Xs and Os main
├─╯
○  v            Click sets a X                    <-- What you want to edit
○  s            Square has state
│ ○  kt         empty Hover effect to board squares
│ ○  rv         empty Changes to both CSS and app.js
│ ○  q          Add the CSS file css
│ ○  rt         Link to CSS
├─╯
│ ○  o          Play instructions manual
│ ○  kx         Play manual
├─╯
○  n            Square is interactive
~

Notice where you landed:

  • on an empty, messageless Change
  • on top of the Change you want to edit.

Let me call that empty Change the Buffer Change.

If you squint, you could think of that Buffer Change as a Git Index-like structure. Only, it's an ordinary Change, like all the other ones, so it's persistent and operable with the ordinary commands.

Isn't That The Same As jj edit?

Definitely no.
If you did jj edit v directly:

  • jj diff would display your changes plus all the changes originally in v, mixed together. Reviewing your work would be less convenient.
  • Similarly, jj restore would revert your changes plus all the changes originally in v, basically reverting everything to v's parent s: definitely, not what you want.

The Joy Of Not Having Special Cases

The fact this Buffer Change is an ordinary Change has a couple of interesting consequences.

There's No Need for jj stash

You need to drop everything and switch to something else:

  • With Git, before running git checkout, you need to git stash push or you will lose your work.

  • With Jujutsu? Fear no more: go safe with jj new somewhere else: your Buffer Change won't be lost.

Since you are working with ordinary Changes, there's no separate stash mechanism to learn: suspended work lives alongside all other Changes and never gets lost. The git stash machinery collapses into the Jujutsu primitives you already know.

Multiple Indexes

Have you ever thought you can have multiple indexes? Say that while you are editing v (from a distance) you come up with another possible approach to complete your work. No problem: run another jj new v and you'll end up with a second, independent Index-like Change. Eventually, you will jj abandon one and jj squash the other. Or maybe you want to mix them? Your choice.