I don't understand the workflow that makes JJ more useful than git. I dont think I've even had the idea of having multiple worktrees going at once. What is the use case? The author mentions being blocked by CI flow. Don't you have CI running on gitlab or github? just commit and push the branch and run CI. The author mentions stashing the changes, but like.. if you're running against CI, isn't it in a state that is commitworthy? I don't see how creating a worktree in a new folder and opening a new editor is more convenient than creating a branch at a certain commit.
I can understand if you need to run a CI or unit tests locally. Is that it?
I am not attacking JJ, I genuinely can't understand its value in my current workflow.
"When is jj useful" is a different question from "when are workspaces/git worktrees useful"
I find jj overall most useful for separating the concept of a machine-level commit history that saves every change from a human-readable commit history . jj has really nice tools for cleaning up your commits for review while still retaining all the mechanical changes in case you need to get more granular. (Of course, there are many other tools to do this, like magit – I just find jj to work best with my brain.)
Workspaces/worktrees are best when you have long-running tasks where the state of the disk is important. Local "CI" is a good example – kick off a long test run on one workspace while starting a new task in another. Another example these days is stuff with Agentic LLMs, e.g. I might create one workspace and ask Claude Code to do a deep investigation of why our AWS costs went up.
1. Stacked PRs. I like to be kind to my reviewers by asking them to review small, logically-contained pull requests. This means I often stack up chains of PRs, where C depends on B depends on A, and A is being reviewed. If I receive feedback on A, jj enables me to incorporate that change within A, and flows those changes down into my dependent branches. I can then merge and close out A, whole continuing to work on B and C. Achieving this in raw git is labour intensive and error prone.
2. Easily fix up commits. I like to work with atomic commits, and sometimes I realize that I've made a typo in a comment, or a small error, or missed a test case. Jj makes it really trivial to timewalk back to the commit in question, fix it and resume where I left off.
3. Decompose a big PR into multiple PRs. This is the flip side of point 1: I can take my own big PR and rearrange and partition the commits into A, B and C so that they can easily be reviewed.
In general, jj seems to encourage and reward you for being disciplined with your commits by enabling you to be more flexible in how you stage, review and ship your code.
On the flip side, if you're the kind of person who is used to typing `git commit --all --message "xxx"` you might not get as much value from jj until that changes.
You push branch A, then switch to branch B and start working on that. CI failed on branch A, so you stash branch B and switch back to branch A to fix it.
thanks, that makes sense. I don't see how a worktree is more convenient in that case.
Maybe from the kind of work I do? either CI is failing because of something really simple, or something really complicated that means getting a product setup and producing debug messages. If it's a critical fix on branch A, then I'm not working on branch B. I'm testing branch A locally while CI does its thing
Worktrees are useful particularly because they look like entirely separate projects to your IDEs or other project tooling. They are more useful on larger projects with lots of daily commits. If you just use branches then whenever you switch, in the worst case, your IDE has to blow away caches and reconstruct the project layout or build the project fresh. On large projects this takes significant time. But switching your IDE to a different project, there are now two project and build caches to switch between.
I wrote a very popular tutorial for jj, and I didn't use workspaces until a few weeks ago. They're useful for the same reasons git worktrees are: most recently, people use them for doing work with multiple AI agents in parallel, but historically, I've seen people use them for things like "this project's build takes 30 minutes so I want to work on something else while I wait for that".
> I don't see how creating a worktree in a new folder and opening a new editor is more convenient than creating a branch at a certain commit.
Worktrees are about being able to work on multiple branches at the same time, fundamentally. When you want to be doing something on one branch and something else on another branch simultaneously.
That does mean it's, IMHO, a fairly niche feature.
I keep my agent workflows distinct; we have (for historic reasons) a lot of non-git controlled context that differs between branches, and moving all that around on checkouts is untenable. I use this tool:
I've used multiple worktrees with plain git; it's not a unique jj feature anyway. It's handy for working on multiple things at the same time with somewhat less cognitive overhead to switch back and forth.
For what it's worth, I have been using jj as my primary git client for two years at this point, and have only use workspaces to see how they work, and then never touched them again.
There is a lot more to jj that makes it nicer than git, but it's mostly a bunch of small things that jj does nicer, that cumulatively add up to a significantly nicer experience.
I found worktrees unnecessarily painful in Git with little advantage over just having two copies of the repo.
Your far better off just having a clone of your primary repo, and have your primary repo as a local remote. Both can have a remote for GitHub and a separate remote for each other.
Genuinely curious, what did you find painful about it? A while back I found it annoying that I'd get errors when cleaning out my branches because they were checked out in a worktree I'd forgotten about, but git now highlights branches checked out in worktrees and has done so for a while.
In git you can have only one worktree per branch. For example, if you have a worktree on main you cannot have another one on main.
I personally find this annoying. I usually like to keep one pristine and always current working copy of main (and develop if applicable) around for search and other analysis tasks[1]. Worktrees would be ideal and efficient but due to the mentioned restriction I have to either waste space for a separate clone or do some ugly workarounds to keep the worktree on the branch while not keeping it on the branch.
jujutsu workspace are much nicer in that regard.
[1] I know there are tons of ways search and analyze in git but over the years I found a pristine working copy to be the most versatile solution.
You probably know this, but for others that don't: local git clones will share storage space with hardlinks for the objects in .git. The wasted space wouldn't be a doubling, it would be the work tree twice plus the (small) non-hardlinked bits under .git. No idea how LFS interacts with this, but it can be worth knowing about this mechanism.
Also, if you end up relying on it for space reasons, worth knowing that cloning from a file:// url switches the hardlink mechanism off so you end up with a full duplicate again.
This restriction of git worktrees is annoying but I just learned one simple rule to follow:
Never check out the main development branch (main/master/develop/etc) in other worktrees (non "main worktree", using git-worktree nomenclature)). Use other name with "wt-" prefix for it. Like in:
And to be honest, after being disciplined to always do that, I very rarely get error message saying that the branch I want to check out is already checked out in other worktree. Before that, I regularly had a situation when I checked out main branch on second worktree to see the current state of the repo (because my main worktree had a work in progress stuff) and after some time when I finished work on main branch, I tried to check out main branch on my main worktree and got the error. Because I totally forgot that I checked it out some time ago in the other worktree.
> In git you can have only one worktree per branch. For example, if you have a worktree on main you cannot have another one on main.
You can detach the worktree from the repo, and checkout multiple branches at the same time to different locations. Not sure if this also allows checking out the same branch to multiple locations at the same time. You can also have a swallow clone, so you don't have to waste space for the full repos history. So at the end you still have to waste space for each worktree, but this isn't something jujutsu can avoid either, or can it?
That sounds like a nice improvement, just like many other aspects of jj!
Tools should adapt to us and not the other way around, but if you are stuck with git, there's a slightly different workflow that supports your use case: detached head. Whenever I check out branches that I don't intend on committing to directly, I checkout e.g. origin/main. This can be checked out in many worktrees. I actually find it more ergonomic and did this before using worktrees: there are no extra steps in keeping a local main pointer up to date.
The detached head is what I meant with keeping it on the branch while not keeping it on the branch.
The complication comes from trying to stay current. With a regular worktree I could just pull, but now I have to remember the branch, fetch all and reset hard to the remembered branch.
This is kind of unfortunate in this case as it breaks some tooling since the extra trees are not collocated with git, like editor inline history/blame or agents that know to look in git history to fix their mistakes
I think the biggest benefits of colocation are, in rough approximation of the order I encounter them:
1) Various read-only editor features, like diff gutters, work as they usually do. Our editor support still just isn't there yet, I'm afraid.
2) Various automation that tends to rely on things like running `git` -- again, often read-only -- still work. That means you don't have to go and do a bunch of bullshit or write a patch your coworker has to review in order to make your ./run-all-tests.sh scripts work locally, or whatever.
3) Sometimes you can do some kind of nice things like run `git fetch $SOME_URL` and then `git checkout FETCH_HEAD` and it works and jj handles it fine. But I find this rare; I sometimes use this to checkout GitHub PRs locally though. This could be replaced 99% for me by having a `jj github` command or something.
The last one is very marginal, admittedly. Claude I haven't had a problem with; it tends to use jj quite easily with a little instruction.
To be technical, it's more that it can read and write the on-disk Git format directly, like many other tools can.
I think the easiest way to conceptualize it is to think of Git and jj as being broken down into three broad "layers": data storage, algorithms, user interface. Jujutsu uses the same data storage format as Git -- but each of them have their own algorithms and user interface built atop that storage.
You can still use git worktrees in a colocated repository. jj workspaces are a different, but similar capability that provide some extra features, at the cost of some others.
jj may use git as (one of) its backing stores, and its collocation offers some compatibility at the cost of important tradeoffs, but it isn’t intended to be a git frontend.
I'm glad they found a workflow that works for them, but
> but for some reason I cannot proceed on it while eg the CI is running, but I also don’t want to leave the commit and close my code editor etc. It would be simple to just stash everything and later pop the stash, but it still feels disruptive.
I have been using jj as my git client for 2 years now (wow), and I have never considered this to be disruptive. I just immediately switch to a new commit where I want to go, rather than making a new workspace to work in. Maybe it's a difference in the editor that I use (GNU Emacs) that makes this more natural?
Build cache, packages and a few of other things get messed up when switching branches - if you need to do a "quick bug-fix and get back into the main thing" worktrees are really nice.
I see. The projects I have been working on in the last few years don't take very long to compile, so build cache has not been a very big factor for me. I could see it being more important for projects that take a long time to build though.
if you don't do much in terms of accumulating open buffer/window sets, editor open at the specific line you were working on etc, then you'll feel it less.
or things like just keeping the terminal history consistent with a change if you look at things like compile command outputs etc.
It's not really usable to me as the workspace folder doesn't have .git in it, even though original repo is collocated and hence the git tools don't work there.
I am forced to use git work trees with separate collocated JJ repo each.
Some company tooling / git oneliners from internet / and probably most relevant for me is git plugins for neovim / some personal scripts I would have rewrite to work both in .git and .jj repos
I want a variant of this where I make a worktree that has no ability to push anywhere including its parent. Instead the parent worktree pulls from it automatically. That way I can run some sandboxed workflow that might arbitrarily corrupt the work tree, possibly overwriting everything in it and symlinked from it, without losing data.
Then you'll probably want a clone; which will cost in more space. Just remember to remove the remotes.
You could always use an overlayFS with the main (non-worktree) repo as the lowerdir (and then remove the remotes in the overlayFS), but that relies on you not trying to keep working on the git repo at the same time.
Same. Never used worktrees before, but mapping a worktrees to tickets I’m assigned to for Claude to work on is really great.
Heck with the ai, I even have it spin up a dev and test db for that worktree in a docker container. Each has their own so they don’t conflict on that front either. And I won’t lie, I didn’t write those scripts. The models did it all and can make adjustments when I find different work patterns that I like.
This is all to the point of me wondering why I never did this for myself in the past. With the number of times I’m doing multiple parts of a codebase and the annoyance of committing, stashing, checking out different branch and not being able to go more quickly between when blockers are resolved.
I consider git the best software ever written. I used to work with some other SVCs, and I cannot thinking on leaving git now. Somehow, I feel it like a limitation for my mind.
I'm following this Jujutsu project, I'm genuinely curious to see what it can bring to the SVC scene.
How so? I worked with Git all my professional life and I can't deny its efficacy. However, I would not call it un-improvable given all types of corner case issues I have had with it over the years.
Maybe "best ever" is too bold, but both proven efficacy and mainstream popularity for over 15 years, without being a bulky thing everybody just accept (like vscode), I don't see many other software examples.
Anyway, sorry for triggering you with the first bold statement! I actually wanted to emphasize the curiosity over jj.
>Anyway, sorry for triggering you with the first bold statement! I actually wanted to emphasize the curiosity over jj.
People does not have to be triggered to ask follow up questions. Its ok to even ask a challenging question as a response of a statement, without being an indication of their mood.
Having worked with cvs and svn, git has been an absolute blast.
That said, the first thing I do now in a repo is jj init --colocate. The fact alone that there is an operation log in jj, so you can easily revert your last command, or go back to any point you want, is mind blowing coming from git and having experienced frantically digging through the reflog.
But that aside, the way to work with branches ahem bookmarks, commits, conflicts, just makes so much sense in a world where simultaneous feature branches are a thing.
My journey was CVS->SVN->darcs->Hg->git. I can thoroughly recommend at least playing around with the others to see what you're missing. Darcs in particular I remember as having a much nicer model than either git or mercurial, but it had a horrible corner case behaviour. Pijul is supposed to fix that, but I haven't tried it yet.
That's interesting. I consider git the worst software ever written!
I speak specifically of the UI. Obviously the underlying system works. Yet it's totally within reason that the UI has wasted trillions of money and many person years in lost productivity.
Napkin math. It's easy to waste 30 minutes figuring out what the heck is going on after a command didn't work, or explaining what a detached head is to a newbie, or any number of completely avoidable issues were the UI better.
Consider the 26.9 million developers in North America[1]. How does one estimate the average salary across NA? Some in SV make 3x that. Elsewhere, it's conceivable that people make considerably less. Let's just say 100k. That's 100,000÷52÷40=48/hr or 24 per half hour. Anyone with git, I think it's safe to say, has had at least one stupid issue that took 30 minutes because of the UI. That's 26.9×24=645,600,000 monies.
In my experience and what I've seen of anyone who'a used git, 30 minutes is a gross underestimate. And people use git outside of NA. It's easily trillions in waste.
Re Worktree/Spaces alternative: Why not just open up a new editor window ?
> I usually use it when I’ve got one task I’m working on, but for some reason I cannot proceed on it while eg the CI is running, but I also don’t want to leave the commit and close my code editor etc. It would be simple to just stash everything and later pop the stash, but it still feels disruptive.
The author doesn't mention this as an improvement to git, just showcases that an equivalent feature exists in jj. This is useful to me, a jj noob that was not aware it's possible.
there isn't any. it's just possible in jj, which does not have feature parity with git and probably doesn't aim to have it anytime soon, if ever (not a contributor, so please don't quote me)
It depends on what you mean by "feature parity." jj has some features git doesn't, and git has some features jj doesn't. That's likely to be the case into the future, for sure.
There's also like, some features of git aren't features in jj, but that doesn't mean you can't do that stuff with jj, it just works differently. The index or stashes, for example. In a literal sense, that's not parity, but in a logical sense, it is.
I can understand if you need to run a CI or unit tests locally. Is that it?
I am not attacking JJ, I genuinely can't understand its value in my current workflow.
reply