It's nice, I really like it! I'll probably switch to it as my main VCS eventually. But it doesn't feel that important to me. Even though my main work involves quite a lot of annoying rebases which is where JJ really seems to shine.
I dunno I guess it's just that a) I've really mastered git and have a deeply-rooted workflow in it and b) despite my project involving annoying rebases, version control still isn't very high on the list of problems I have.
So yeah I'm basically bullish on JJ as a technology but I think movement from Git is inevitably gonna be slow and steady.
What really kept you from staying with it? It does seem like if your workflow involves a lot of nasty rebases you'd reap dividends from something like jj. I was also someone who'd mastered git (hell, I've written a git implementation) so I get having its patterns deeply ingrained.
There's nothing keeping me from switching except the activation energy cost. Almost every aspect of working in my area (Linux kernel) is painful so I'm constantly investing in tooling and workflow stuff. So usually I just don't feel like investing EVEN MORE in the area of tooling that's probably least painful of all.
So yeah this is still basically a recommendation for people to try JJ!
I think all of those are using git and many Gerrit as well.
If your project is open source but still interacts with the main body of Google code in a significant way, you can still be in the monorepo and then mirror it to Git via Copybara (or you can work primarily in Git and then mirror to the monorepo via Copybara).
The most common case of that is libraries that get imported into server binaries. There's a whole section of the monorepo for open source code, with special rules and processes around it.
But a that has setup and friction costs so it's only worth it if you see a pretty significant upside.
For stuff that's pretty standalone there's no point. Classic cases are Chromium and Go. Then of course there's Google's various operating systems...
Is this one of the repos that uses Gerrit? Does JJ play well with Gerrit?
IIRC Gerrit was super picky about amending commits and I was worried JJ's laissez faire attitude about creating git commits on demand wouldn't jive well.
There was a PR for a `jj gerrit` command, but at this point, it's not super needed. Here's the main bug tracking this https://github.com/jj-vcs/jj/issues/4387
Beyond that, the jj, gerrit, and git butler folks are working together on standardizing the change ID concept so they all work well together without extra tooling. That's going to take a long time though. Think "store the change ID in the commit rather than as a trailer", that kind of thing.
JJ does create commits without you explicitly asking but you do still have direct and fine grained control over it. It's not magic it's just that it's occasionally implicit. And squashing and splitting is nice and easy.
I don't understand why anyone would say you have to use it. It does a very specific thing, namely finding the source of a regression between two commits. If you need it you'll know.
Does it work well with a classic merge workflow? I haven't worked that way (without rebasing) for a long time.
That's also useful for bisecting, as you can first find the feature that is buggy and then find the commit that introduced it.
I use the commit message to add ticket numbers to things to group commits.
I prefer to have everything in a single source of truth (git), so everything is in commits. Your tickets are my merge commits.
Was that 'may I ask'?
Not that often, but not seldom. Its useful if you have a bug, that isn't obvious where it comes from, but easily testable. Then you just write a test and let git figure out where it comes from. The test doesn't need to be automatable. I also used it for firmware that needs to be flashed and the bug effected in an LED blinking incorrectly. I still saved a lot of time.
Yes, can't type sometimes.
I see. Maybe it's just what kinda of code and/or how I write it, usually pretty clear which abstraction isn't doing its thing. From there, it's either clear what is the bug, or git blame will reveal what changed.
This has a much higher chance of succeeding if you maintain strict boundaries and isolation which isn't always possible.
It's a command that is needed rarely but there's no replacement for it in some situations.
It might be slightly more tedious but couldn't you just do the same thing manually and it would add just a couple minutes to the search and you would still save weeks? I like the ergonomics but only use it once every couple years.
Now that I switched to jj (colocated with a get repo, very useful), I went back to using the CLI again for jj and I don't miss the graphical tools.
I’ve tried jj on three occasions and I always get confused by something and just bounce. It hasn’t clicked for me.
I’ve only tried it solo hobby projects. For which git is perfectly tolerable.
I have many many many complaints about git. But jj doesn’t move the needle for me.
Reading this post I am extremely annoyed. Almost every single section is “but more on that later”. It’s still far more complicated than it needs to be.
I also really really really hate the jj log rendering. The colors are a sea of barf. Bolding the leading character that represent uniqueness is stupid and adds noise. The username being second is dumb, I almost never care about that. And the bright neon green (empty)(no description set) is such bad spew. Kinda nit picky, but blech.
Jujutsu suffers the same thing Git suffers. Every god damn blog post that tries to explain how simple it is just my eyes gloss over and think “this is too complex for me to care”.
You can fully change/customise it. Sounds like you just don't like the default.
Most people use the default for most of their tools. It’s why Google pays Apple over $20 billion per year to be the default search engine. Because defaults matter.
> I’ve only tried it solo hobby projects.
If I can surmise a bit, this is probably why it's never felt "worth it". I'm guessing that for a hobby project you don't really care that much about crafting small, easily-digestible PRs or keeping a clean history. `git commit -a` every now and then is good enough, and that's entirely reasonable.
For team projects, jj becomes a much bigger deal. I find it invaluable for splitting up a day's worth of work into small, parallel, easily-reviewable changes. While working on one feature I might run across a dozen other things that should be fixed, improved, or otherwise changed. Bundling them into one giant PR is bad practice and causes reviews to take much longer.
Carving those up into single-purpose PRs that can be reviewed in seconds and tested independently is super helpful on a project with multiple teammates. But that's not something that really matters or that most people care to take the time do to in personal projects. Hell, it's something a lot of people punt on a lot in git due to the extra burden of doing so.
If I used Git as part of a large team I’d perhaps spend more time with jj. But for solo projects it adds even more complexity to Git rather than reduce. So I don’t feel strongly inclined to spend that time.
Must be a preference thing. Showing me the unique characters is awesome. Git sucks after getting used to it.
I regularly jump around commit hashes. However 99.9% of the time a commit hash is printed I am not going to go to it. So it’s pure noise 99.9% of the time. And the absolute most it can save me when it isn’t noise is a few keystrokes. Not a good design imho.
I've used it and I like it but I couldn't find a good plugin for Neovim so I reverted back to my old more well-supported workflow.
The biggest killer was performance. jj operations took several seconds for me, whereas git is instantaneous no matter how big the project. Maybe this is fixed now.
But also honestly I felt like there was a bit more mental burden to using jj. When I switched back to git, it was like a weight off my shoulders. Maybe that's just due to the decade of constant use though.
Everything else is instant.
This sounds exactly like something a person evangelizing it would say.
What other tools do people do that for? Not many. I see the most similar language and behaviour with regards to uv, which similarly revolutionized/simplified python tooling.
Likewise mise, which makes it similarly frictionless to install and manage tooling and their versions across projects and system-wide.
The evangelizing for these things comes because these tools start to heal the trauma that came from immense friction. We want others to be similarly liberated.
For those who say "I don't feel friction/trauma with git, legacy Python tooling etc", I can only say that you're living in Plato's cave/the matrix/in a cult/with Stockholm syndrome and just don't know what you're missing out on.
To make a point? To prove that "they are right"? People do this constantly, tools, libraries, languages... All the time really.
Text editors, programming languages, shells, VCSs, nix/guix…
I also already use very good tooling for git, namely Magit. IMO Magit is a much better git frontend than Jujutsu. It guides you down the right path but doesn't take away any of the power of git at all. It's quite remarkable.
Maybe I should recommend jj to some of my colleagues, though. Trouble is I'm already on the hook for helping them with git, but I don't have the experience with jj.
This is kind of a poor take. By all means use what you prefer! But understanding git and knowing the "right" way to use it doesn't make jj obsolete.
I am (or was) a git expert. I’ve used it since pre-GitHub. I’ve written a git implementation. I know (or knew) the interface inside and out. I haven’t deleted and re-cloned a repo in as long as I can remember.
jj is still leagues better. Things I want to do and know how to do in git are dramatically faster and easier. They require less mental overhead. They’re less error prone. And I get superpowers with workflows that are super useful but wildly impractical in git.
This isn’t even really opinion at this point. Any task you can give me in git, I can with almost near certainty give you a shorter and more elegant alternative with jj that is an intuitive and obvious interaction with its core primitives.
A month ago our company split off a division. They needed to take a specific repo and sanitize out all of the parts that aren’t relevant to the new company, going back to the beginning of its commit history. You can do this with git. It wouldn’t be fun. I’d have to spend a lot of time reading the filter-branch manpage, and people have written countless wrappers of varying quality that try and make it a bit more ergonomic.
It took me like ten minutes to come up with:
declare -rA paths=(
…
)
# for every commit that touched a file
# we want to excise
for id in "$(
jj log \
--revisions '..' \
--no-graph \
--template 'change_id ++ "\n"' \
"${paths[@]}"
)"; do
# restore those paths’ contents from the
# the empty root commit; this happens
# entirely in-memory without having to check
# out each revision into the working copy to
# do file operations so it is FAST
jj restore \
--ignore-immutable \
--from 'root()' \
--to $id \
"${paths[@]}"
done
# remove any commits that are now empty
jj abandon \
--ignore-immutable \
--revisions 'empty() ~ root()'
Three dumb, simple commands that I already use every day: list some commits, copy file contents from one commit into another, and remove some commits from the tree.Not only was this more or less obvious to do, but it was exceedingly fast to perform on a pretty highly-trafficked repo due to not having to thrash around in the working directory with checkouts.
> Magit is a much better git frontend than Jujutsu. It guides you down the right path but doesn't take away any of the power of git at all.
jj is more powerful than git. It’s not simply a dumbed-down alternative. By having a more carefully chosen set of primitives that compose better, you gain a lot of abilities that are technically possible with git but never used in practice due to the complexity.
And you can still do all the normal git things too.
Why? They’re sharing what they prefer in response to someone claiming that everyone who tries the other thing comes to prefer that. They’re offering a reply in context and not in the slightest saying everyone should follow what they do.
> By all means use what you prefer!
That’s exactly what they’re doing.
> But understanding git and knowing the "right" way to use it doesn't make jj obsolete.
Which they haven’t claimed at all.
You seem to be objecting to an argument which hasn’t been made.
So I think I would revise my comment above and say I don't need jj because I've already got a toolkit that does a similar thing. I haven't raw dogged the git CLI in a decade.
However if I ever run into a problem like yours and my tools aren't cutting it I'll definitely keep jj in mind so thanks for showing me!
Reporting in. Doesn't mean I will end up with jj eventually, but so far I always went back to git after a while.
For me it is the staging area and the workflow it allows. Most people hate it and love jj because it does away with it. That is just not me. I don't see the staging area as a hack that was necessary to overcome some superfluous technical limitations but as a workflow tool.
Could I change my ways? Sure. jj just did not provide enough benefit for me so far to do it, but we will see. I am still open to give jj another try some day.
I use a staging area with jj! I would surmise most jj users do too. It's just a real, honest-to-god commit in the repo instead of a special snowflake.
# do some work
…
# prepare a new, empty commit if you don't already have one
jj new --no-edit --insert-before @
# move changes into it; repeat ad nauseam
jj squash --interactive
Since it's just a commit, all your tools work with it out of the box. And you don't need to stash changes when you jump around between branches.For me the staging area being a snowflake is the feature. It is a special temporary singleton commit if you will, but I can rely on its temporary and singleton nature. As that it should have a different interface from regular commits.
When I eventually figure it all out, I can tidy it all up into completely coherent, discrete, sequential commits that make it look like I knew exactly what I was doing from the start, then push to remote.
Conversely git staging around stashing was always an absolute, terrifying mystery to me. I could never remember what was stored where, and would consequently end up losing work, repeating work, and, most of all, just making massive commits that make no sense.
I was sold on jj from essentially the moment I found it, but I remain routinely amazed at how much more powerful (yet simple!) it is than I realized.
In my mind, in some sense, every commit can simultaneously be a stash, staging area, part of a branch and more. Because you can easily create endless branches on top of, beside, before, as merges of, etc.. any commit. And it all automatically rebases, conflicts often auto-resolve (or at least don't block you immediately).
I really don't know how to best describe it. But there's a reason that many people are quite literally evangelizing it in every post that comes up - who does this for git, or anything?
Just give it a try. And, even better, use it via jjui
You now you can give stashs a commit message?
It is just SO EASY to move, merge, split, rebase, squash etc commits, and even just individual lines and sections from within commits (via split).
And it's all even easier via jjui
I don't think there's anything any of us can really say to convince those of you who are constitutionally skeptical about it (or even allergic to it) why you should try it... If all of our fawning and evangelizing isn't enough to get you to at least give it a fair shake, then there isn't much else to be said.
It's also that I want my commit hashes to be stable (because I cross-reference them) and it sounds like they wouldn't in jj, because it is kind of rebase-y?
The only thing left for me to say to folks like you who think git is just fine (or even great) is that you're in Plato's Cave. https://en.m.wikipedia.org/wiki/Allegory_of_the_cave
You just don't know what you're missing out on. But if you give it a fair shake, you'll see the light quite quickly.
Take care!
Generally you use the id, not the hash.
And yes, everything you can do with jj you can also do with git. It’s just that most people don’t, because it’s much harder with git, involves rebases and changing hashes, and so on.
This gets even better with octopus merges (known in the jj community as "megamerges"): open up 5 branches at the same time, address minor tweaks in any number of them, and `jj absorb` the content into the right parent branch.
I have never tried git absorb across merges, no clue if that works.
Moreover, jj should be able (I haven't explicitly tried this) to autogenerate the conflict resolution in the `jj absorb` case, since it knows what the final post-merge state should be.
Because that's my workflow. I produce a few focused and semantically coherent commits that I'd like to apply to the codebase, where each keeps the codebase in a working state. I might be working on more than one thing at once, but I know which commit each set of changes should "live in."
An append-only log of commits is decidedly not something I want. Is jj amenable to this?
https://v5.chriskrycho.com/journal/jujutsu-megamerges-and-jj...
jj squash --into -r <revset>
Where <revset> is @-, a change id, or perhaps a bookmark name if you want to give a semantic name to your changes.On the other hand, tools like jj seem great for people who spend a lot of time refining and perfecting every commit so that their repo history is pristine. I’m not one of those people. My git hygiene is atrocious. I have git halitosis. But functionally, it’s fine. Everything is in the git history and is recoverable. That’s about all I care about.
Also, I don’t have the capacity to juggle a lot in my mind. If someone does, then sure, jj may facilitate that. But I don’t need such facilitation.
In Git, I need to keep in mind all the different things I'm working on and which branch goes where, or I wind up with a monster PR with a chain of commits that mix everything up enough that it's even more effort to pull the PR apart to be reviewable. Ask my colleagues how I know that :P.
With jj, I don't feel that I'm putting more effort into organising my changes -- quite the opposite -- not least because there's very little book-keeping involved in parking something that's in progress or coming back to it later. And when I come to ask for a review, I've got separate changes I can push as smaller PRs, and I can easily pull the right sets of changes out to make each one reviewable.
I think the biggest improvement is that if I just need to look at something else for a couple of minutes then come back, I can `jj new main` to switch and not bring my changes with me then I can `jj edit <oldref>` to get my working copy back into the state it was in before, with all my old changes.
I'm pretty sure none of my colleagues have started using it (although they're free to) but I can confidently say (because I've asked) that they've noticed the difference in my work and prefer the more focused changes.
How do you recover from accidentally deleting a branch that you never checked out? Assume it was deleted on known remotes also.
Lack of gitattributes support precludes git-crypt and git-lfs usage or anything that needs filters; line ending settings will get ignored, making Windows interop a little less smooth; etc.
Also note that auxillary tooling, such as git-annex and git-bug, becomes second class, i.e. no oplog integration and they might mess up your log with internal-use commits and heads.
This one got fixed just a few days ago! https://github.com/jj-vcs/jj/pull/6728
https://github.com/jj-vcs/jj/issues/53
(I am interested because I want to try, but need git-lfs, which needs gitattributes.)
Arguably a good thing - git's autocrlf setting causes way more issues than it solves. I highly recommend setting it to "input" (basically bans CRLF).
I hit this - I develop in Windows.
I still prefer jj and won't go back to pure git :-)
Git is definitely more powerful but causes more damage than good and wastes more time in most workplaces who are just looking for some simple version control and branching/merging features.
I don't have any productivity issues with git, like... at all. It's not like I spend an hour running git commands every day.
I can totally imagine that some people spend their day manipulating repos with git, and jj is better for them. But that's not my case, and git is already everywhere.
To me it sounds like telling me: "You HAVE TO move to bim, the better vim. It's very similar to vim, but different enough that you have to learn new stuff. But you will be infinitely more productive: when you start bim, you're already in edit mode, so you don't have to type i! And the auto-complete in Julia is objectively a lot better in bim!".
Sure, but typing "i" a few times more is really not a concern for me, and I don't use Julia. But if it's better for you, please enjoy bim!
This is where jj excels. Especially if you find yourself often doing large chunks of work between convenient checkpoints, but you still want to create commits as if this work was all done in tiny and discrete chunks. It's also very helpful if you're the kind of developer who makes lots of unrelated changes in a single coding session, and wants all those changes to be in parallel branches that can be reviewed and merged independently. I greatly prefer working with (and being) the kind of developer that puts out a large number of very tiny and easy to review PRs, eve. jj makes doing that a breeze.
There are lots of people for whom these things aren't important. I will be slightly judgmental and say I don't really enjoy working with them. They tend to write very large PRs that are difficult and time-consuming to review. And it's a frequent source of frustration for everyone when 95% of the work is uncontroversial but a merge is being held up because of legitimate concerns with an unrelated 5%. This is even worse when there's later work that builds upon it that can't happen until a merge (or that needs to be constantly rebased as the PR is improved).
As an example of another ‘unnecessary’ switch, Pip with venvs was also completely solving all my Python dependency problems. I just needed to copy paste a few lines from my README to create and populate the venv, and remember to run pip and Python from that venv. And run pip freeze after package installs or upgrades. No problem. But switching to uv was a huge life improvement. No more copy pasting (‘uv sync’ does everything and even that isn’t needed) nor remembering extra steps and everything is fast so I’m never waiting and forgetting what I was going to do.
I could’ve been GP talking about pip but still I would be missing out.
I still see people clinging to cvs because it works for them (netbsd why?), which I respect but don’t understand/believe.
Fish don’t know what water is.
So.. I’m gonna give jj a go and trust life will be better again.
Jj is to git what uv is to other python tooling.
Check out jjui as well, which makes jj even better. https://github.com/idursun/jjui
https://mise.jdx.dev is equally as revelatory as jj and uv
IMO this is all being driven by Rust. jj, mise, ripgrep, fd, bat, eza, delta… all of the best of breed tools these days seem to be coming out of that ecosystem.
Jujutsu finally made me understand git, after ten years of git use. It removes enough of the magic that I now know exactly what the commands do, and how the data model works.
Doesn't feel painful in git, but I'd like to see an example doing that with jj. Maybe I'll try.
A very, very large problem at five out of six companies I have worked at is casual code improvement and refactoring. Devs would say, "we will address that minor and unrelated thing in a separate PR" - one that never comes. At one company, a single PR could address unrelated fixes and it was encouraged to "take out the trash" on the code. Unrelated metrics added, logging improvement, or code simplified, or test robustness improved, etc. That company had vastly better code. Easier to read. Easier to maintain. Easier to observe. And easier to test.
That sort of workflow is ideal for making sure you've got a set of isolated commits each looking at a single subject so that when someone is reading through the history later they can quickly see where something was introduced or why, and jj is perfect for doing that because it makes crafting those commits so much easier.
It's very frustrating that what IMO is the inferior approach was producing better results in those teams!
When you are told to separate general code improvements to another PR, or worse, to not do them, and create a Jira task for them so they can be adequately prioritized, it just saps your will to do so. You just won't do any improvements that fall outside the scope of the feature, because even just thinking about the hoops you have to jump through to get work done is mentally draining.
Coincidentally jj makes this process much easier than it would be with git, it will very happily let you shift commits around between different branches, edit commits in place and cleanly rebase those edits onto subsequent commits, or split a messy commit into two commits that makes sense.
If people instead reviewed commit by commit until the PR HEAD, the code itself would tell a story, but best of all - the story would then be obvious!
I can see that.
From the other side of the PR though, it involves significantly _more_ work from a reviewer.
The "red tape" of separating commits and opening separate PRs should be removed by the team.
The effort of separating commits and opening separate PRs is minimal once you're comfortable with the tools.
I encourage colleagues to be comfortable with these workflows, because a reviewer's time is generally no less valuable than their's.
jujutsu also seems like a poor fit for large monorepos repos (particularly ones that use git hooks). The expense of certain git operations increases quadratically with the size of the repo. A repo doesn't need to be terribly large for `git status` to require 5-6 seconds. (God bless the man who added scalar and sparse checkout to git.)
The absolute last thing I want is a tool that's doing more with git -- creating commits, branches, checking things out, rebasing, or doing anything that requires a git-status check.
The best way of getting changes is through is simply sitting down and talking with the reviewer. Most of these small PRS, splitting things, creating elaborate stacking systems are just technology hacks around a social/process problem. I've seen people make more of a mess trying to split pr's up where they are so fine grained its silly and actually had dependencies on commits they didn't realise they had which reviewers then had to resolve. Literally anything to avoid talking and working with people. People are trying to turn a tightly collaborative process and turn it into isolated single work units with no collaboration that just need a rubber stamp.
As opposed to one 33-change PR? Yes, absolutely yes they do.
I probably don’t have time to review a giant PR like that. If I do, I feel guilty asking for fixed in one part when 31 of the changes are great. Why are we holding up all these improvements for one or two small concerns? We can merge and just fix those later. Except that never happens.
I probably have time to review eight one-liners. My other coworker has time for five. After lunch I can quickly check out another seven. Over the course of the day all 33 get reviewed and merged as time allows.
100% this.
With remote teams spread across time zones, mega-PRs become even more problematic.
One commit for a single line? I can't imagine developing software this way. Fixing bugs? Sure. Altering this or that in a well-established, mature codebase? Probably. For features, I don't see how it's possible.
note this is also true in software engineering.
Where the developers at that other company could “take out the trash” amidst one PR, jj makes it trivial to carve off each of those fixes into their own separate PR. It’s no more work than making them separate commits.
People don’t do this in git because it’s a hassle. So you either get cleanup that never comes because each branch needs to know in advance what work it’s going to do or you get omnibus PRs that do twenty different things.
There’s a better way, and it lets you have clean history and developers can fix things they run into along the way.
This is the one thing I always point to when I say "Mercurial is better" (and now, jj).
Why can't we have our cake and eat it? Mercurial lets you have lots of individual commits, but they're hidden, and you'll see only the squashed commit. Why do we have to lose all those individual commits to get that squashed commit? The answer: You don't need to.
Hmm what's the issue with the GitHub default of merging PRs, where there's a merge commit which individually pulls in the PR's commits? You can revert the merge PR as a whole, or the PR commits individually. E.g. with this[1] merge commit, you can `git revert 0a98f570 -m 1` (the merge commit) or `git revert b30950fc` (an individual commit from the PR).
[1] https://github.com/amelioro/ameliorate/commit/0a98f570f63ffd...
> This is where jj excels. Especially if you find yourself often doing large chunks of work between convenient checkpoints, but you still want to create commits as if this work was all done in tiny and discrete chunks.
This is exactly how I like to use git. Sounds like I should be recommending jj to colleagues who struggle with this approach.
It also makes it simple and easy to split B and A apart such that both their parents are `main` if they’re unrelated.
You can also go hog-wild. I was working on a big refactor recently. I made independent changes A, B, C, and D (each one to three commits). I then wanted to work on code that assumed all of these commits were available, so I made a merge commit E that combined them. I then made changes F that depended on that refactor, so was a child of E.
Managing this was simple. If I needed to make updates or tweaks to A-D, E and F were updated to incorporate them automatically. `jj absorb` even meant that doing these types of changes was almost zero work: I could make a bunch of changes and the tool would know in which parent commit they belonged.
None of this was merged in yet. When I was ready, PRs went out for A-D. When they each merged into `main`, E became a no-op and was discarded. F became its own PR. This is something I never would have done in git because having multiple threads of unmerged code is a colossal hassle.
It took me a few months to realize that I could use jj split to move specific files to a different commit. And then I'd sometimes squash them into related commits, rebase to move them around etc...
But I just discovered interactive split, which lets you move specific lines and sections from different files in a commit to a different commit. So I've been using that a lot more recently to organize the changes more thematically.
Ultimately I should try to become more diligent with adding a new commit any time I start doing something different - it's dead simple to do and even less friction to organize later - but I suppose that I'm not that inclined because the interactive split makes it so easy to do it all later that I just stay in the flow of my monster commits.
Everything is possible with jj.
just started making much more use of jj split to move split
EDIT: I love it.
Also, if you didn't discover yet, you can use the arrow keys to unfold the different files and sections. Then select what you need, split the rest to new commit.
As you know, even when just using the most basic functionality (new changes, merges, rebases) of jj, it's amazing. But then you just keep discovering other features and workflows - none of which require any incantations - that make it that much better. And I'm sure I'm still only scratching the surface of its possibilities.
And, as I keep saying everywhere, jjui just takes the whole experience to another level.
- Create multiple topic branches, one for each thing you're working on.
- Now you probably want to work on item A while having B and C all available, so make a single merge commit (jj new a b c) to build on top of.
- Create further commits on top of that, while you're working.
- When you're cleaning up (ideally often), use squash --to or rebase --after to move those commits back the branch they belong on. This does not invalidate the merge commit; you will, effectively, have multiple branches checked out at once.
EDIT: This is apparently called the 'megamerge workflow'.
- Will not rewrite an immutable commit, of course. (Though you can tell it to, and for my personal repositories I sometimes actually set immutable() = root().)
- Will not do anything to diffs if it's uncertain where they should go, either because that file wasn't edited in a previous mutable commit, or because it was edited in multiple sibling/cousin commits. The latter is likely to happen with mega-merges.
You can use --into to restrict the set of target commits, if you already know what feature branch you're updating.
But I'm still not disciplined enough to use it and other proper workflows consistently, especially when new features/topics spring up while working on another one. I just start working on it at the same time, and jj makes it simple to split it into its own commit and branch later.
What's your git workflow for a change that depends on two other in flight changes? (More generally, of course, this can occur in an arbitrary part of one's change graph - which is usually not too deep, but at least in my experience, occasionally is.)
Having good tooling for this unlocked workflows I didn't know I was missing, and switching back to git when leaving Google felt like losing a limb.
Git has worktrees for that. If a parallel change is done in a separate worktree, it can be built and tested independently, which, I guess, is important for kernel developers, who are the initial target audience for git.
I've never really struggled too hard to get git commits into different branches for review, but if you've put unrelated changes into the same working dir, you'll want `git add -p` to sort them out into multiple commits.
Note there are corresponding `-p` flags for things like git-restore and git-reset as well.
You’ve added a new feature. In doing that, you’ve also fixed four unrelated bugs, clarified the documentation for a method you needed to use, and rewritten another function to be more performant.
You could push this all as six commits on one branch. PR reviewers will now have to figure out what parts are related to what, or read each commit one-by-one. If someone wants changes to one of these commits, your entire branch is held up.
Or you could split these six different commits out to each be directly on `main` and make a PR for each of them. They can be tested in CI, reviewed, and merged in isolation.
The latter is far better. You can do it in git, but it’s not exactly fun. It is trivial in jj.
But it is great to know that it is trivial in jj. That's a reason to try :-).
Everything feeling like it’s a slightly uphill battle isn’t something you always notice until it’s suddenly gone.
No, I'd probably put them all as individual branches to be reviewed, assuming they're truly independent changes. As long as they don't actually conflict it's not very hard to do this in git.
But this is kind of what I mean when I say that git fits my needs, because I wouldn't come across 4 unrelated tasks like this in the course of implementing a single commit's worth of features, unless I was having the world's biggest attack of ADD.
And if these things did need to get done to properly implement the feature to our team's quality standards, it would be appropriate to be included in that feature's PR as well.
I'm sure it's a nice tool, especially for those who work in domains where it takes a long time to land your commits into the main branch of development, but a lot of this sounds like solutions to problems that we don't all have.
It is in fact a great tool, jj makes doing this even easier.
At least uv solved real problems I was having with Python package management, but for my own personal usage git is 99% aligned with what I need.
jj just makes all of the stuff I liked to do with git easier and faster, and lets me do some things you can’t do with git.
But you should use the tools you want to use.
> Now I am not one of those "the git CLI is too complex and git is too hard to learn" people, but I do acknowledge that puts me in the minority. But let's reframe that: if we can make something more powerful and easier? Sign me up!
That's nice.
I know of him better from his Rust work, but he explained himself well enough in his own comment that he probably doesn't need your assistance to reiterate a point he made very effectively on his own.
Also, he's not the only one who's used git since the early days.
They're useful, but they're not really what your parent is talking about, your parent is talking about a workflow where you realize you've want to break up your work after the fact, rather than setting out to do it that way from the start.
None of that sounds like a positive to me, so I’d rather appreciate some evangelism to enlighten me and correct my misjudgments/misunderstandings which I fully admit are likely. :-)
It's probably easiest to understand by just trying it. It can be used with regular Git repos.
There definitely are lots of big issues with Git though. I dunno how many jj solves but it doesn't seem unreasonable to suggest people move to a better system.
My point is just that I am yet to find a convincing example that would suggest that jj would improve my workflow. If people find it hard to stash a change, I don't tell them that they shouldn't get their shit together and not use jj. But I don't find it hard to stash a change, so why do I feel like jj evangelists try to convince me that something is wrong with me?
That just results in less friction, and in you doing things with it that you couldn't be bothered to before. Yes, I can switch branches in git by stashing my changes, and then I can try to figure out the five-levels-deep stash stack, but with jj I just switch between branches without finishing working on them, because it just works and is easy.
Yes, with git you can technically have five branches open at the same time, and stash work to switch between them to work on one thing or the other, but it's so hard and finicky that you end up never doing it in reality. Or, you can say "I never need that", but is it that you never need it, or that your tools make it so hard that you just subconsciously never do it? For me, it was the latter, as now I'm switching between branches ALL THE TIME, just because it's easy.
The matrix or people happily in a cult would be similar analogies. Perhaps even Stockholm syndrome...
That kind of rhetoric makes me want to say "don't tell me I'm stupid if you are the one finding it hard to switch between git branches".
Git was fine. I used git for ages. I loved its underlying model, and I think it’s brilliant. But it has a lot of sharp edges and a lot of tasks that are painful or frustrating, and people either opt to restrict themselves to a tiny subset to avoid the pain or they carefully curate a workflow that mostly does the job over the course of years.
Suddenly within a week of trying a new tool you just… don’t carry any of that any more.
It’s like going from GOTOs to structured programming with encapsulated functions. People made many useful programs with GOTO. Some people were more principled than others, but we all got by. But it turns out that functions and loops are a way better mental model for control flow than GOTO. Nobody had to switch and there were plenty of holdouts. But eventually the benefits were impossible to ignore.
People like Dijkstra evangelized structured programming because they “saw the light”.
I think of jj as the ultimate refinement of git. It's not revolutionary, in the sense that there's no must-have feature, but it's a distinct evolutionary upgrade that's just way more pleasant than git.
It's telling that most hard-core git gurus are lukewarm on jj at first, but for everyone else, jj makes it way easier to do guru-level version control.
Just my $.02, anyway.
- jj undo, jj op restore, and jj --at-op to reset or view the repo at a previous state
- create multiple directories (workspaces) backed by a single repository at different commits
These are the only things I can think of off the top of my head that you can do with jj that you can't do with git.
This is `git worktree`.
They don't work with submodules but submodules are a disaster that should be avoided anyway so probably no big loss there.
What about `git reflog`?
FWIW, I cheated on a previous job for months by working 10% or so, then faking git commit data to spread it out across the week before sending a PR.
Thank you "git commit --amend --no-edit --date xxx"
Yeah - the other day I did a fetch, and then decided I didn't want to fetch. I simply ran "jj undo" to undo the fetch.
The git gurus responding how they can do X/Y/Z don't quite realize that git is still cumbersome enough that most people never bother to reach their level of proficiency.
Whereas jj is simpler, better-designed, and more powerful, so it's easier to start doing more advanced VC.
I also think everyone's underestimated how much universal undo enables exploration.
Once I started using jj, I realized how poor/annoying git's stash is. You don't need a concept called stash in jj. You have some work done and want to stash it? Just leave it alone as a leaf node (or split your commit into a leaf node). Then branch off the parent to work on whatever you want.
And with jj, my "stashed" node is version controlled in itself. I can make changes to it, undo it, all while still being stashed. (Maybe you can do this in git - I don't know).
Other niceties of jj:
Why do I need to come up with a commit message only when committing? Why couple the two? With jj, you can just decide to work on X, write your commit message "Adding cat photos to Easter Egg", and then work on the feature. Or you can just start working, and in the middle of it all, add the commit message, and continue working. You can change the commit message at any point.
Why do I need to fix merge conflicts immediately? Just the other day in jj, I made a change, which resulted in a merge conflict in several nodes. Whatever - I just branched off a clean node and worked on what I needed to. Only the following day did I go and fix the merge conflict.
Why can I only merge two branches? And why do I need to think of from/to when merging? A merge is basically creating a new node that is the child of multiple nodes. It's symmetric - there's no from/to. And you should be able to specify 10 parents if you want to.
Agreed. Having used SCCS, CVS, Subversion, VSS, Perforce, Clearcase, Accurev (the weirdest of the lot), Mercurial and Git, I'll move when the market decides what has critical mass and my job needs it.
jj feels a bit like learning a Dvorak keyboard and then being in an office of qwerty. Jobs want git, my colleagues know git, I'll be asked a question about... git. Using git has been the lowest version control churn in my brain for a decade, which is nice.
I am also the guy who gets asked with doing crazy git things when the need comes up. I have another post here where a tricky and slow filter-branch that our company needed to do on a repo was a simple and obvious three-liner in jj.
And outside of a few scenarios, they can use git, you can use jj, and everyone will be happy.
I push to my team's Git repo using jj all the time.
Wit the added bonus that "bim" won't remain popular enough to sustain its development for long, so "bim" users have to switch to the fork "bbim" in 2 years, that won't remain popular enough to sustain its development for long...
bat just is more useful even if you didn't have issues with cat
The author starts by saying that they actually have no issue with the git CLI, which is exactly my case.
I started trying jujutsu and until now, I can describe the feeling as an ergonomic keyboard: I am fine with any keyboard, really, it's not that some keyboards are "hard to use". Nobody would (should?) say "with a cheap keyboard, you can't type fast enough to be efficient, but with this ergonomic keyboard, you will be faster". But one may find that an ergonomic keyboard is more comfortable for them, or that it sounds a bit better or feel a bit better.
There is no real need to change keyboard if you like yours. It doesn't mean that it's impossible to find another keyboard that would be more pleasant to use.
JJ may be that (for me, but again I'm just starting): it seems equivalent to git CLI (as in, it's not a heavy GUI or a VScode plugin: it's really a CLI) and it feels like it may be more ergonomic.
And at the very least, it's fun to try.
As it is, I go with whatever our clients require of us, and that isn't jj.
This kind of industry work needs factory line mindset, there aren't special knobs for someone on the sidelines working on the software rolling carpet, which granted isn't for everyone.
> If I had an option, I would still be using something like Subversion or Mercurial.
> As it is, I go with whatever our clients require of us, and that isn't jj.
I share no desire to use jj in those words.
All I was saying is that if a client requires you to use git, you could use jj without them knowing/caring - unless your entire workstation is under tight control, in which case, again, it's not relevant to the discussion
do you know about git rerere?
if yes - try jj.
I believe your perception is flawed because the people who just try it and throw it away don't tend to talk about it because it's not popular enough to warrant even a twitter comment. This is the first time I got the impulse to share this but only because you claimed a rather silly 100% conversion rate.
But I don't think parent comment to mine was "outrageously combative", I just thought it was a bit silly to claim a 100% conversion rate.
Cognitive dissonance is a thing.
And there's nothing crippled about thr git repos.
Try jjui for a great TUI experience on top of jj.
That said, I struggle a bit with learning version control systems (that aren't git, like, I never really wrapped my head around svn or darcs or anything until they invented git). Seems like everybody just wants to write about the cool new commands they can run now instead of conveying how the data model works, or what mental model it wants to encourage. I had the same issue trying to get into pijul a while back, couldn't understand how to conceptualize the current state of a branch if I couldn't point at a commit in a tree and say "that's the branch, right there".
The data model is technically of revisions, which are stable across operations like rebases (which change the underlying git commit).
How to conceptualize a branch: as a bookmark of a specific commit.
Those who have tried it and
1) actually gave it a fair shake - and are now evangelize it, and
2) people who simply didn't give it a fair shake due to a) time restraints and b) just not having an open enough mind to genuinely try it out
And then those who haven't tried it but
1) have never heard of it, and
2) are unwilling to try it because they are stuck in their ways (I view these people as being in Plato's Cave, or the matrix, or a cult - even though us evangelizers obviously sound like we're in a cult). They're in an even sadder position than those who tried it half-heartedly.
All such sorts of people are on display in this thread. I hope us zealots have been able to convince (hopefully via education) at least a few to try it out.
And also to try jjui, which is incredible.
When it's our first time, the muscle damage can weight a lot to even be able to sit properly in front of the desk during the first couple of weeks.
1) use a git hook to generate Gerrit IDs for new commit. AFAIK, JJ doesn't support these.
2) we also use submodules, which must be handled using git commands.
So if I decide to use JJ, I'll have to use a mix of JJ and git..
This landed in a jj release a few months back. I assume it’s live in gerrit now too.
For sure git is hard to learn for beginners and there could be an alternative which is easier to pick up (maybe jj) but for those who know how git works internally and are proficient with it I don’t see it being worth the switch.
Oh, the number of times I do
git commit --fixup ...searches `git log` and pastes`... && \
git rebase -i --autosquash ...that same commit^...
I waste several half minutes several times per day in periods!Another time-consuming thing is context-switching from a feature branch with staged/unstaged changes. If you're good with worktrees, you can largely avoid this, but the way I work with worktrees, I instantiate them as subdirectories to my repo's parent, which clutters my directories unless I make space for this as I clone the repository, which I haven't got used to.
I deliberately avoid too complicated git workflow aliases because I hate being stuck without them.
I am definitely in the camp of "I'd switch to jj the moment I give myself time to try it."
In the meantime, running git commands does sometimes take more time than it needs to.
git rebase -i --rebase-merges --keep-base trunk
This lets me reorganize commits, edit commit messages, split work into new branches, etc… When I add --update-refs into the mix it lets me do what I read are the biggest workflow improvements from jj, except it’s just git.This article from Andrew Lock on stacked branches in git was a great inspiration for me, and where I learned about --update-refs:
https://andrewlock.net/working-with-stacked-branches-in-git-...
But I don’t see how that removes the usefulness of fixup commits, only that you can do them across stacked branches with ease.
But you’re saying I don’t need the particular hash of the parent, I can just rebase all the way back to main/trunk each time. That’s a good point!
I think I’m still saving time by fixup, it was the second hash lookup I wasn’t happy with.
I like to rebase my fixups immediately when possible so I don’t forget.
That’s where I made the comment about not actually running fixup. Instead of claiming to fix a SHA, I leave myself a note like “fix tests” so I can move it appropriately even if I get distracted for a few days
Every time jujutsu pops back up on HN I check to see if they've added it yet. Not yet! But they are slowly getting there:
Is it that I have to fall back to git for its changes? Or that I just shouldn’t use jj if I’m in a repo with lfs files?
serious question as somebody who has never even looked into what jujutsu offers - unless you're a solo dev with some free time, what exactly is the selling point here?
edit: i didnt realise that its just a layer on top of git so that basically answers my question, fair
I used it for a week and switched back to `git`. Most of its hallmark features are not something I use that often.
Most of the projects I do for money are on Github and Gitlab.
I got my hands on things like YT videos explaining, official docs, cheatsheets.
About 4 hours exploring, trying to use with some side projects.
I did the same decades ago from CVS/SVN to git (even tried Hg). At that time it was obvious the "revolution" + "evolution" effect. Also git provided some transition tools that were easier to use from my pov.
Now it's just "evolution".
I see the added power to work with different "branches" simultaneously, move commits in different order in a way that is easier to have some better management logic, etc.
This is basically compelling if you work on different facets on big monorepos.
But I want to work on one thing a time nowadays, do something reliable, instead several features simultaneously, even with AI assistance, so the gains are not that huge, yet.
Like you I ended up using git commands again naturally. Stopping using svn commands eons ago felt amazing.
I've been meaning to give it another shot, and probably will after this article
You will be hard-pressed to find someone who stuck with it for a week and decided to go back to git. You will not find a lot of people who say they switched but just stayed out of inertia. Of course both of these do happen—nothing is perfect—but they are by far the exception. From my own personal anecadata, I have seen a 100% conversion rate from everyone who gave it a serious try.
I encourage you to let today be the day that you decide to try it out. It is far less effort to make the switch than you probably think it is: I was productive the same day I switched and within a week I had no remaining situations where I needed to fall back to git commands. You will quickly be more productive and you will find yourself amazed at how you ever got by without it.