jujutsu 0.44.0
49 points by olex
49 points by olex
I made two attempts now at trying to work with an existing git repo using jj and I haven't got the hang of it.
I'm even unable to articulate what issues I have, probably something related to the cognitive load of having two separate types of hashes ...
But my workflow of: make changes, interactively add them to the index then commit, push, feels like it does not work with jj, even though it's pretty simple. :(
Is there a "how to do X with jj" kind of documentation anywhere?
make changes, interactively add them to the index then commit, push
Based on the "interactively add" bit, I think you may be looking for jj split to separate different changes from one working state, to push one through, and continue working on the rest. It is actually pretty much the workflow I tend to have.
jj doesn't have a staging index "by default", but you can use an extra commit for the same purpose. Let's say you start off with something like this:
@ wtnrrk [] (no description set)
◆ wvnouv main [] initial commit
There is no staging index yet. wv (main) is a stable commit and wt is the working copy commit (in Git, that would be the worktree). To create a staging index, just make a new commit with jj new. This is optional, but to illustrate that @- is supposed to be the staging index, let's add a commit message with jj describe @- --message "staging index":
@ rkqswu [] (no description set)
○ wtnrrk [] staging index
◆ wvnouv main [] initial commit
Now, wt is the "staging index" and rk (@) is the working copy. You can now "stage" files, hunks and lines interactively with jj squash --interactive. Once you're happy with the state of the staging index, just change its commit message with jj describe (and possibly create a new "staging index" commit for your next chunk of work).
I've casually followed jj dev, but haven't tried it yet. This comment clarifies how my work style might translate to jj much better.
I generally am thinking in terms of staging changes that I want to insert (somewhere) into a stack of related commits that I am trying to keep separated for review.
If I want to take the working diff I made to a specific file and combine it with a commit that is linearly a few spots back, is there a easy normal flow for this in JJ?
I would like to see more of how to do X with jj as well, since I am still not using it well outside of single person projects.
So far I've found: https://maddie.wtf/posts/2025-07-21-jujutsu-for-busy-devs#entry-1
There’s also the Git command table from Jujutsu’s official docs.
That page is very concise and doesn’t go into the details of workflows to replace Git’s change→stage→commit workflow. In Jujutsu’s official docs, Comparison with Git > The index has one short paragraph about that. Others in this thread have already given or linked to more detailed explanations of alternative workflows.
I wish you can figure out what your issues are! :)
For your workflow I'd suggest: start with jj new BASE-BRANCH, make changes, jj split -i (select what you want in the first commit, then name it; whatever you didn't select gets in the second, unnamed commit); then whenever you want to push, set a bookmark for the tip of the branch, track it and push it. I think bookmarks feel a bit weird when compared to git branches, but my rule of thumb has been: bookmarks are for pushing, so I only need to mess with bookmarks when I'm about to push.
I seldom need to use git hashes, I mostly use jj hashes. I've created a shell alias to help me pick a hash (using fzf) when I need, but these days I'm mostly using jjui.
Treat the working copy revision like an index that automatically stashes and unstashes on rebase, and replace git add -p/-i with jj split -i. That's my advice, as a former heavy git add -p user.
Because there is no concept of staging and you're always working in a commit, you are just splitting up your top commit into commits you want to push and not push. jj commit -i sounds like what you need. It allows you to select changes from the current revision (your working copy), and anything not selected is placed in a new commit on top. Your bookmark will be left in place, so you'll need to advance it to the parent of your working copy before pushing.
Jj docs have some fairly atomic comparisons for git operations as well as a guide for working with git. As an alternative, you might like the squash workflow^1.
I have never been the most advanced git or jj user and have got by basically ignoring the git hashes, which are mostly not for you and shift under your feet while you work with jj. I've found jjui (an unofficial TUI) to be quite useful for visualising and clarifying the types of operations I want to do. Also, the FAQ is very much worth reading, it even talks about the git add -p workflow.
[1] I think this tutorial isn't quite up to date with current jj. Named branches are now bookmarks, and there's jj bookmark advance and other useful commands.
Going through this tutorial made the whole thing click for me: https://steveklabnik.github.io/jujutsu-tutorial/
cognitive load of having two separate types of hashes
that's interesting - ever since I've started using jj I don't look at git commit hashes at all (except during code review, but that' browser-based flow for me)
My workflow's pretty basic. I have one main branch and I keep adding to it:
Make changes.
jj diff: review changes.
jj commit -m "message" <file1> <file2> ...: commit changes (optionally specifying files if I don't want to commit them all at once).
To interact with a remote git repo:
-1. jj git fetch: fetch changes from upstream.
jj new main: start a new change on top of main....
jj bookmark set main -r @-: set the last change to main.
jj git push: push changes upstream.
I'm sure my workflow could be improved but my main need is to not have git screw up my repo in a way that I cannot repair it.
By the way any jj experts can tell me if I can simply skip the main bookmark stuff? I feel like compared to git push and git pull I'm doing extra work for the same thing? I feel that I should be able to just work off it rather than having to continually setting the main bookmark.
as you noted - there are some stuff that can be optimized!
trunk() instead of explicit bookmark name was a blessing for me (I've got one repo over decade old with master, but my brain was already rewired o main)jj bookmark advance (or its shortcut jj b a (oh shoot, it's JoJo reference?!)) may do exactly what you want (maybe with one or two lines of config)I have the same model with git, and what helped me to learn jj was to begin every workstream with 'jj new'.
If you do that, you can interactively squash to the parent, which is similar mental model to adding to the index.
Over time I've noticed that when beginning a workstream, I usually do "jj new foo" to start a new commit off foo, since on jj I typically keep independent changes as siblings rather than ancestors. I then might "jj new foo bar" to work off both changes. This flexibility results in me not needing staging as much.
There are times I end up with too many changes in a commit, and I need to do stage-likes, and I feel like in git it would be easier, but on balance, having more flexibility parallel changes is a net win for me.
https://steveklabnik.github.io/jujutsu-tutorial/real-world-workflows/the-squash-workflow.html is the closest relevant doc that I know, but note that you can mix and match "workflows". It's all just moving changes ultimately.
For pushing to git, I always do "jj bookmark advance && jj git push". This feels a bit awkward, and maybe there's a better way, but it works for me mostly.
I also struggle with the two different types of hashes. In practice I think I just pick either, and it seems to work?
I still use git on jj repos for things like git log and git blame. I haven't seen a need to learn the jj equivalents.
Not related to this particular release, but I recently bit the bullet and moved from a multiple-workspace git situation on a big mono to just using jujutsu. While I am probably only scraping the surface of the tool, I am feeling quite liberated by being able to do the following:
I still find some of the flags a little unintuitive, but I am forcing myself to just use them instead of aliasing everything. I am quite pleased.
jj rungained a--ignore-changesflag to avoid editing any revisions even if the command modifies the working copy.
This is great. I was experimenting with bodging hidpi support into the macos version of vintage story and ended up with an alias to build and launch arbitrary revisions.
--ignore-changes is exactly what I wanted to run against ephemeral workspaces without risk of persisting accidental modifications.
(I gave up btw and decided I should just start playing the damn game).
aliases.b = ["util", "exec", "--", "bash", "-c", """
set -euo pipefail
jj run -r "$1" --root -- sh -c 'dotnet build --no-restore --property:WarningLevel=0 decompiled/VintagestoryLib.csproj && cp decompiled/bin/Debug/net10.0/VintagestoryLib.dll "/Applications/Vintage Story.app/VintagestoryLib.dll" && pkill Vintagestory; sleep 0.1 && open "/Applications/Vintage Story.app"'
""", ""]
(This is the alias as currently in my repo config. It needs updating and probably some cleaning up too).
(I gave up btw and decided I should just start playing the damn game)
But have you considered that the current nutrition system is kinda underwhelming and you should make a mod inspired by how Valheim does food, and also add a stamina system while you're at it?
I've been using jj now for 6 months. I am a big fan of it in some ways, and not in others. The best part by far is how safe it feels. You can do some crazy rebase and mess everything up, squash commits by accident, whatever, and its all recoverable. The part I haven't got the hang of at all is branches. In my head, branches are deliberate streams of work, but jj's bookmarks and "anonymous branches" feel a bit weird to me. jj seems to encourage just making changes and figuring it out later, but I guess I always liked the very minor ceremony of making a branch and naming the thing I'm about to do.
I always liked the very minor ceremony of making a branch and naming the thing I'm about to do
Personally I make a new change with jj new and name that with what I think I’m about to do, then squash things into it as I go. Sometimes even constructing a few empty changes as sort of TODOs when there a few steps I’m planning to take, in case I go away and come back and need a reminder.
but I guess I always liked the very minor ceremony of making a branch and naming the thing I'm about to do.
You should still feel free to name your commits, even as you initially make them and they are empty. The new command allows describing (-m) for this purpose.
The lack of a branch shouldn’t make anything anonymous.
This is a great step; supporting tags directly will let me drop one of the last two things I return to the git CLI for, and I'm guessing some of my fetch issues with locking are about to disappear to, thanks to https://github.com/jj-vcs/jj/issues/7530
I hope eventually we will have a post about a new jj version where the first and most active top comment won't be a conversation about how someone has found themselves unable to use it.
Is there a timeline for a non-git backend for jj, or is that not really a concern at this point?
there are some plans!
https://ersc.io/blog/ersc-availability#user-content-fnref-1
(yeah, it's just a footnote)