Jujutsu is a distributed version control system (think git alternative). I consider myself a git power user and it’s interesting to challenge myself and work with a system that promotes a bit different workflow.
The main difference in philosophy seems to be that jujutsu encourages “rewriting the history” and editing older revisions, with changes seamlessly propagated to the descendant commits. I saw it described as “always being in an interactive rebase, and it’s actually good!“. As someone who uses git rebase -i quite a lot - I was curious!
For the full sales pitch and tutorials I’d like to refer to the official docs or a tutorial by Steve Klabnik. Here you will find my notes on the pros, cons and “good to know” as I’m learning to work with jj.
Materials
Useful reference materials
- CLI reference: https://jj-vcs.github.io/jj/latest/cli-reference/
- revsets language reference: https://jj-vcs.github.io/jj/v0.13.0/revsets/
- tutorial by Steve Klabnik: https://steveklabnik.github.io/jujutsu-tutorial/introduction/introduction.html
Cheat sheet
Useful config
The jj config is stored in ~/.config/jj/config.toml. So far, I liked the following options:
# display full commit messages in `jj log` rather than the one-line titles
jj config set --user templates.log "builtin_log_compact_full_description"
# limit the log length when executing `jj`
jj config set --user ui.default-command '["log", "-n", "15"]'
# prevent secret or temporary commits from being pushed to remotes
[revset-aliases]
private = "description(regex:'^(wip:|local:|secret:|private:)')"
[git]
private-commits = "private"jj log by default displays the following set of revisions: present(@) | ancestors(immutable_heads().., 2) | present(trunk()). This can be changed with the setting revsets.log.
The good
jj operation logis impressive - all operations in the repository are recorded and can be reverted with a simplejj undo- all files in the repository are tracked by default. This increases the risk of accidentally committing secrets but much more often I made the mistake of forgetting to add the right files in git.
- jj coexists with git, making it possible to adopt it without converting the rest of your team
- it’s possible to configure a regex for identifying local-only commits (see config docs) and jj will protect you from pushing those to the remote
Complaints
Some of the difficulties and downsides I’ve encountered. Surely at least some of them will be resolved as tooling around jj matures, for example improving shell completion.
- the language for selecting revisions is quite verbose. That’s a win for readability (compared to git’s magical incantations) but quite a lot to type.
- I miss the
commit.verbosesetting from Git config which showed a preview of the whole diff when editing the commit messages. It made it easier to ensure I’m committing the right thing and writing an accurate message and. On the other hand, in jj it’s trivial to undo any operation withjj undoso I shouldn’t worry so much about making a mistake. - the diff capable of showing per -word difference is nice but I miss the
git.colorMovedsetting which would differentiate moved lines from truly deleted. - I’m yet to find a quick way to show a diff of all changes made on a given branch. In git that would be
git diff main...some-long-branch-name. Here the equivalent seems to bejj diff -f 'fork_point(main | some-long-branch-name)' -t some-long-branch-namewhich is quite a lot more to type. Perhaps I need to set up an alias that will make it easier to call this command.- This is exacerbated by fish shell completions not working while in the middle of a more complex expression. After
jj diff -f 'fork_point(main |tab completion will not help me withsome-long-branch-anme
- This is exacerbated by fish shell completions not working while in the middle of a more complex expression. After