This was informative, thanks Steve! The only problem I had was that the difference between changes and commits wasn't clarified enough in the beginning, and I got lost trying to distinguish between the two. I'm on chapter 4 and I'm still not sure what a change is and what a commit is.
From a tiny bit of previous jj experience, my mental model is "a commit is the snapshot, and a change is what happened between snapshots", but that might be wrong. It would be great if this could be clarified a bit more in the tutorial.
Changes are a stable ID for a single conceptual modification to the repo. They are backed by—at least right now—a regular git commit with a content hash.
As you iterate on one change, new underlying git commits are made to snapshot the latest state of the current change being edited. The change ID remains stable though the backing commit ID varies as the change’s contents are modified.
You can always revert a change back to a previous backing commit.
This has a few cool implications.
First, you never have uncommitted changes. You are always editing a “current” change with an ID that is regularly persisting your work (either every time you run a jj command or with a filesystem event monitor).
Second, you’re never “on” a named branch: you’re only ever “on” a change and named branches are just mutable pointers to change IDs. This is awesome for a long-lived linear bit of work that needs to be merged in piecemeal. In git you’d need multiple branches based on one another and nothing tracks the relationship between them. Updating earlier work is painful. With jj, it’s all just one linear branch with some changes having names. If you need to edit an earlier change or insert new ones, you just… do that.
They (and you, unless you go digging) only see the latest commit associated with each change.
The older ones are there in your local repo but they’re invisible unless you need to look through the “obsolete log” to find earlier iterations of changes. This is similar to (and built on, essentially) git’s reflog that holds on to commits that are no longer in active use.
There’s also an “operations log” that, instead of tracking history of individual changes, tracks history of the entire repo. So if you reorder or drop changes, you can always undo those operations.
Thanks for the feedback! I think these terms are used a bit loosely, even though I try to be precise about it.
Your mental model sounds decent. I think there’s a few ways to describe things. I like to think of changes as a stable ID for something I want to accomplish, and a commit as the intermediate steps that make up a change. You can kind of think of a change as a branch… but I think that’s stretching it.
OK, going through the tutorial again, I think the difference between commits and changes are definitely the thing to focus on. Before your comments, I felt like I was building on a small foundation, because I didn't understand how commits and changes relate, and didn't have a good mental model of them.
After your comments, the entire tutorial is more solid, but still I feel like I have gaps. My feedback would be to really focus on commits vs changes and define their relationships, what affects them, etc before you go into anything else.
Ahh, this really helps. I think you should definitely mention that a change consists of commits (unless it already is and I missed it). This helps because the two questions I had before were "if I change some text, will the change ID change too?" and "does a commit end a change?".
Clarifying early on what exactly a change ID is, when it changes, and what the relationship between changes and commits is would really help, I think.
From a tiny bit of previous jj experience, my mental model is "a commit is the snapshot, and a change is what happened between snapshots", but that might be wrong. It would be great if this could be clarified a bit more in the tutorial.