kdwarn

Codeberg Mastodon Feeds

jujutsu

November 10, 2024

daybook, vcs | permalink

EDIT, 2025-12-25: I've gone back to straight git. I think jj will probably be a passing fad that will never have the full functionality as git, nor the documentation/support/community.

This is probably going to be something of an evergreen post, updated as necessary. Unless I forget it exists.

I heard about jujutsu sometime within the last year. I have to admit my initial thought was something along the lines of "why make something else when there's git?" but then I saw that Steve Klabnik (co-author of the Rust book) is writing a tutorial on it. So, as I said on Mastodon, I guess I'm going to have to check it out. (EDIT, 2025-07-23: "Jujustsu for busy devs" is a good intro.)

And so I've been using it on personal projects for the last couple weeks and I quite like it.

Anyway, I wanted to note some things I'm getting used to/figuring out.

Workflow:

  • I'm mostly using the "edit" workflow Steve describes, but not quite as he describes it.
  • The happy path: When I'm done with some set of changes, I'll update the description if necessary. I'm finding that writing the description before doing any work is helpful in thinking about it before doing it, so that's why I say "if necessary". But half the time it is, and if so it's done with jj describe (to open an editor to write the subject and optionally body of the message) or with jj describe -m <message> to write it on the command line. Push to remote, possibly. Then run jj new to start a new revision. I don't often use the -m <message> option with jj new, as I'm just trying to finish up the one I've been working on and leave things in a fresh state, but you can do that. (There's also one command that will replace describe and then new: jj commit, or jj ci for short.)
  • Aw fuck I forgot something:
    • if I've already started a new revision with jj new, just make whatever changes are necessary and then run jj squash. This will push the changes in the working copy into the previous revision, and the working copy will be empty. If you already added a description, an editor will pop up allow you to edit the commit, very much like in rebasing in git.
    • if not, run jj new and then jj squash. If you just run jj squash without starting a new revision, you'll be pushing all your changes both now and what you previously did into the the revision before the one you're attempting to add to.
    • if you already pushed to a remote, you can do it again, just specify the revision: jj git push -r <rev> --remote <remote-name>. There's no need (or option) for --force. Just push it.
    • it's also easy to do this with only some of the changes. I'll add that later.

Pushing to remote: If finished with a revision and want to push it somewhere, don't start a new one (because you can just work on the working copy without having to specify a revision). Update the bookmark with jj bookmark set main to move the main bookmark/branch to the working copy. Then do jj git push --remote <remote-name> to push it there. Then a new revision, to start further work, can be started with jj new.

Various things:

  • @ is the working copy and @- is used for the revision before the working copy. You can pass in the revision on most commands - -r <rev>. So -r @- is the one before the working. I'm not sure how far out it goes, but tacking on additional - will go one further.
  • jj show will show commit description (the full one, not just the subject like jj log does) and revision changes. Handy as jj show @- to see previous one from working copy.
  • jj undo is pretty great. I fucked up some things and it made them go away.
  • jj abandon is both useful and good naming. Wrote some code that's actually not worth saving? jj abandon.
  • to use jujutsu out of the gate with a new Rust project (rather than "colocate" it with git), pass --vcs=none to cargo new and then run jj git init in the project's directory.
  • the "builtin_log_compact_full_description" template is the one that feels most like what I expect from git log. So I've added an alias for it, to "v", which means it can be called with jj v. The new part of my ~/.config/jj/config.toml file looks like this:
    [aliases]
    v = ["log", "-T", "builtin_log_compact_full_description"] # v for verbose
    
  • Start a branch awhile ago and then just kind of forget about it? And then you're like 30 commits from where you diverged but you want to pick up the old branch again? I'd have to probably read several blog posts and forum threads for git, but for jujutsu it took me just jj help and a couple minutes to figure out that the answer is just jj rebase -r [revision] -d @ and everything seems ... like I wanted it to be? (-b or -s may be a better choice than -r. jj help rebase provides clear explanation and graphs to make the decision easy.)