Editing history without holding my breath

Part 7 of 9.

The three moves this lesson covers - start new work, edit existing work, start new work from a point in the past - map onto things I already did constantly in Git. The difference is how much I used to brace for them.

jj new closing out the current working copy and opening an empty one is unremarkable, basically git commit with the staging step removed. The one that changed how I work is jj edit <change-id>. Fixing something two commits back used to mean git rebase -i, picking edit on the right line, making the fix, git rebase --continue, and hoping nothing downstream conflicted along the way. With jj, jj edit just moves the working copy onto that commit. Any file I touch amends it directly. Descendants get rebased automatically the next time jj needs to show me the graph. No detached-HEAD state, no multi-step rebase to abandon halfway through if I change my mind - jj undo covers that.

Starting new work from a past commit instead of @ was the one that felt most unfamiliar coming from Git, mostly because Git makes the equivalent (checking out an old commit, then branching from it) feel like a special, slightly risky operation. In jj it’s just jj new <old-change-id>, and the log immediately shows a fork - two real heads sharing an ancestor, neither privileged over the other. Nothing forces me to decide right away whether that second line of work becomes a bookmark, gets merged back, or gets abandoned. That deferred-decision property is what I didn’t expect to value as much as I do: the moment “let me just quickly check this from main instead” comes up mid-task, it’s a single command instead of a stash-and-switch dance.