I See a Future in Jj
Posted3 months agoActive2 months ago
steveklabnik.comTechstoryHigh profile
calmmixed
Debate
60/100
Version Control SystemsJjGit
Key topics
Version Control Systems
Jj
Git
Steve Klabnik joins ERSC (East River Source Control) and writes about his enthusiasm for jj, a new version control system, sparking a discussion about its merits and potential adoption.
Snapshot generated from the HN discussion
Discussion Activity
Very active discussionFirst comment
32m
Peak period
137
Day 1
Avg / period
40
Comment distribution160 data points
Loading chart...
Based on 160 loaded comments
Key moments
- 01Story posted
Oct 22, 2025 at 1:21 PM EDT
3 months ago
Step 01 - 02First comment
Oct 22, 2025 at 1:54 PM EDT
32m after posting
Step 02 - 03Peak activity
137 comments in Day 1
Hottest window of the conversation
Step 03 - 04Latest activity
Nov 3, 2025 at 2:38 PM EST
2 months ago
Step 04
Generating AI Summary...
Analyzing up to 500 comments to identify key contributors and discussion patterns
ID: 45672280Type: storyLast synced: 11/20/2025, 8:18:36 PM
Want the full context?
Jump to the original sources
Read the primary article or dive into the live Hacker News thread when you're ready.
Jj is a VCS, it was not at all clear (to me) until I got further and I was very confused as to why we were talking so much about source control (I thought Jj was a language since the article started by talking about Rust/Go).
Apparently Jj can work on/with git repos making it easier to adopt incrementally which is neat and the main point of this post is that the author is leaving Oxide to go work for a new company trying to to create the GitHub of Jj (my understanding at least).
I hope this helps someone else who might be confused like I was.
I tried to help fix this in https://github.com/steveklabnik/steveklabnik.com/pull/125/fi..., thanks again!
1. A good vscode extension (there's two so-so ones that I'm not sure are being updated) 2. LLM knowledge. I ask gpt-5 about doing something in jj the other day, it didn't even recognize it at first. When I reminded it it was a vcs it hallucinated half the commands. I ended up figuring it out myself from the docs
For LLMs, yeah this is hard for any new project. I use Claude Code, and it does a decent job with jj, it only tries to do git stuff sometimes. I haven't asked ChatGPT about it though, I'll have to experiment with it myself.
Just get the thing you need now, there's no promise the grass is getting any greener, nor that you're any better off waiting. Maybe the LLM won't learn for 6 months. Or 12 months. Or maybe the AI company will run out of money, or jack up their prices to where you're not using it anymore, or whatever.
Using VC commands an LLM generates for you sounds like a pretty terrible idea anyway. What if they delete your data? Why not spend 5 minutes searching for information written by a human?
+ any good tool will not let you run destructive commands without confirmation unless it's with some force flag and I have enough computer knowledge to not use force flags blindly.
+ "information written by a human" can be unreliable too.
Give it time. Once JJ resources enter the dragnet of future model datasets, LLMs will get better at regurgitating it.
I've extensively used CVS and Subversion in the past. I touched Mercurial and Bazaar when I ran into a project that used it. I remember in the CVS days, SVN was exciting to me, because CVS was such a pain to use, in almost every way. In the SVN days, git was exciting to me, because SVN still had quite a few pain points that poked me during daily use. Again, yes, git had and has rough edges, but nothing that would make me excited about a new VCS, I don't think.
Maybe I'm just getting old, and new tools don't excite me as much anymore. Learning a new tool means spending time doing something that isn't actually building, so my eventual use of the new tool needs to save me enough time (or at least frustration, messily converted into time units) to balance that out. And I need to factor in the risk that the new tool won't actually work out for me, or that it won't end up being adopted enough to matter. So I think I'll wait on jj, and see what happens. If it ends up becoming a Big Deal, I'll learn it.
The goal of this post wasn't really to convince anyone on why they may want to give jj a shot, more of just a post about how I think about technologies I may want to spend my limited time on this planet working on, and announce that I'm making a move.
I don't think that you're being unreasonably negative. I think it's crucial for technologies to understand that your position is basically the default one, and that you need to offer a real compelling reason to choose a new tool. For some people, jj has enough of that already to bother with choosing, but I think the real power is in things that aren't widely available yet. Hence the need to go build some stuff. It's early days! Not even 1.0 yet. It's very natural that most people do not care at this stage.
What I mean by simpler is, there's fewer features, which makes things easier to pick up, because these features fit together in a way that's more coherent than git's. By more powerful, I mean jj lets me regularly do things that are possible, but annoying and/or difficult in git.
I loved git. I was never the kind of person who thought its CLI was bad. But then, when I found jj, I realized why people thought that.
Makes sense. Developers I know have been wanting that.
https://www.gameoftrees.org/
It does this by adding an new operation on top of the operation log[1], so you don't lose repository states by moving up + down the op log. There's a corresponding `jj redo` as well.
0: https://jj-vcs.github.io/jj/latest/cli-reference/#jj-undo
1: https://jj-vcs.github.io/jj/latest/operation-log/
The biggest issue for me is it requires active change management (or feels like it). In git I do `git checkout foo` then I start editing. If I want to see what may changes are since foo then `git diff` tells me. With jj though, `jj edit foo` is the to git, state of the repo ALL changes to foo. So any new edits are invisible. So, instead of `jj edit` I have to do `jj edit` `jj new`, then later squash those into foo
I know there are similar cases in git but I guess I'm just used to git so I wasn't using those cases.
that said, I'm mostly enjoying jj. Though quite often i get a conflict I don't understand. Today I got 2 and it told me choose A or B. I did `jj diff -r A -r B` and it said no diffs. If no diffs aren't there no conflicts? I'm sure someone gets it but it was annoying to just have to pick one to abandon
You can as of v0.33.0[0]. Previous behaviour was that `jj undo; jj undo` would leave you where you started (it undid the undo).
> The biggest issue for me is it requires active change management (or feels like it). In git I do `git checkout foo` then I start editing. If I want to see what may changes are since foo then `git diff` tells me. With jj though, `jj edit foo` is the to git, state of the repo ALL changes to foo. So any new edits are invisible. So, instead of `jj edit` I have to do `jj edit` `jj new`, then later squash those into foo
I'm not 100% clear on what you mean here, but a few things that might help:
1. In jj you don't "checkout" a branch, you edit a specific commit. That commit might be pointed to by a bookmark but it doesn't have to be. A jj bookmark is roughly equivalent to what git calls a branch. Note that a git branch, and a jj bookmark are just pointers to a commit, as illustrated here[1]).
2. If you want to resume work on a branch/bookmark instead of `git checkout BRANCHNAME` you'd do `jj new BRANCHNAME` which puts a new commit on top of the commit and sets it as a working copy.
3. Bookmarks don't auto advance like they do in git. So adding new commits on top of a "branch" will leave the bookmark where it is until you `jj bookmark set/move` it. So you could squash commits down into the "foo" bookmark, but you could also move "foo" to point to subsequent commits.
4. Not sure what you mean by edits being invisible, but if it's seeing a diff from main to the tip of your branch (with a change id of ex. XYZ) it would be `jj diff -f main -t XYZ`.
0: https://github.com/jj-vcs/jj/blob/main/CHANGELOG.md#0330---2...
1: https://social.jvns.ca/@b0rk/111709462585184810
The core of their complaint is that if you use `jj edit` it's not obvious how to get a diff of what you did. The answer, of course, is that you can use `jj evolog -p`.
For what it's worth, this changed in v0.33.0:
> jj undo is now sequential: invoking it multiple times in sequence repeatedly undoes actions in the operation log.
(release notes: https://github.com/jj-vcs/jj/releases/tag/v0.33.0)
I’m not sure what happened in your conflict situation either, that does sound frustrating. EDIT: Oh, I wonder if it was this: https://jj-vcs.github.io/jj/latest/technical/concurrency/ specifically, that I bet the repo was being modified concurrently, and so you ended up with a divergent change.
The auto-commit behavior was one of my biggest concerns when starting, but it turns out that when combined with other things, I'm a huge fan now, for example.
This is one thing that I constantly find myself wishing was in git but inevitably resign myself to knowing "thats just not how git works."
Some of it is also what a "branch" means to different people can mean different things: https://jvns.ca/blog/2023/11/23/branches-intuition-reality/
But yeah, as others have said, not really possible in a general way, sadly.
- the working copy has a bookmark pointing to it
- there's some ancestor with a bookmark
- there's a single linear path between the two with no other bookmarks in between
Here's an example that represents a branch containing 3 commits named "bookmark-05ff" branched off of "bookmark-6825".
In this case, the following log would get you the commit pointed to by "bookmark-6825": I'm using the builtin_log_redacted output template. Normally you'd have actual bookmark names, descriptions, user, etc.Also note this bakes in a lot of assumptions and is brittle. As many others have said, it’s not generalizable.
You could probably attach metadata to commits indicating the branch name at time of creation, but there's probably a lot of weird edge cases to handle.
You might have a specific workflow such that you can actually answer your question, but it won’t generally apply to all repos.
Since a branch is really just a label for a specific commit, which may be at the end of a chain of successive parent commits, a branch isn’t really a first class structure, but a derived one.
You can get the fork point of a branch, which is a common ancestor commit shared by another branch, but that fork point is a commit and may not have a branch label. That commit can have any number of other branches going off of it: how would you decide which one is the parent vs just another sibling?
My assumption after looking at jj is that it is not as complicated as git yet. Give it time. It’s also not even as simple as git for many tasks, based on their own docs: https://jj-vcs.github.io/jj/latest/git-command-table/
If you have another machine on main without any outstanding changes and you want to pull the latest changes that is probably also two steps (git fetch + new?)
That said, I've been liking jj quite a bit for more mature / collaborative projects. It has been a learning experience. (don't enjoy updating bookmarks for PR branches though; jj encourages rewriting history which is not my favorite choice for code review branches; I often work in repos that squash-on-merge).
For updating bookmarks I've found like half a dozen variants of `tug` alias the community has come to using which is just a slight improvement (bit daunting to newcomer to pick 'best' one and not fan setting up aliases on all my working devices).
It would be nice if jj was better than git for the fundamental workflows like this out of the box overall.
https://github.com/jj-vcs/jj/blob/c70f9b5b3fff08a86fb11afc57...
Having said what I said, I do find new tools to be interesting, and I do hope jj ends up being successful. I'm always happy to be surprised by something that fixes problems that I didn't consciously know I had, or that adds new features or work modes that make my life easier in ways that never would have occurred to me in the first place. I was a pretty early git adopter, and it works great for me, but I'm sure a decent chunk of that is because I understand how it works under the hood, even if it often doesn't present a great UX.
And even if jj doesn't eventually surpass git's popularity, it's great to have other options, and avoid monocultures.
For me, the turning point was realizing that jj actually eased some of the frustrations I had with our rebase workflow at work. It took a while for it to click, but now I wouldn’t want to go back
In my day to day, its basically "git pull --rebase repo branch", plus some interactive rebate to squash commits, and it's not particularly frustrating, so I'm curious what you're doing that we're not.
rerere only helps so much with conflict resolution but with jj I think it is as painless as it could be.
A problem I run into when working with other people is that code reviews take forever and I need to build on top of them. Code gets merged while it's being reviewed, and it becomes a burden to keep rebasing your stack of PRs. It's also difficult to do things like designing each PR against the main branch, but testing all 3 of them together. (Sometimes you want to write the docs / take screenshots as though all your features are merged as-is.) jj makes all this trivial. You tell it what you want and it does it without involving an index or working copy or interrupting you to resolve conflicts.
I've found that it really makes me less annoyed when working with other people. I don't know why it takes people longer to review code (or to even open the review request) than it takes me to write things. But it does, and jj is what keeps me sane.
To be fair, I also use it on personal projects because sometimes you have 3 things you want to try at once and they're not related to each other. Upstream isn't going to change without your understanding, but it's still mechanically something to maintain the rebases on those 3 branches. jj just makes this burden go away.
Having said that, I don't know why a "jjhub" is needed. Github seems fine. jj's just a UI for git.
I have a workflow where I have my main and a bunch of branches that are children of other branches. So: main, branch_a, branch_a_1, branch_a_2, branch_a_1_x, etc. Probably not a good workflow, but that's what I do.
I keep editing old commits in my branches to have clean, atomic commits, which fucks up my branch structure and I need to cascade-rebase everything manually.
Do I understand correctly that jj does it automatically?
I don't open a PR for each commit, and we use squash commits at work which makes it harder to have this workflow but it still works fine for me.
I rebase only the leaf PR, and I have update-ref enabled to update the branch refs of all other branches in the stack. It works well. The only manual process is that I have to manually force push each branch afterwards.
Lastly, I use the `-x "cargo fmt" -x "cargo clippy"` feature when rebasing (which is missing in jj) to make sure the stack stays in a good state
jj does this for performance reasons. They don't want to perform a full checkout for every rebase action. This is simply something I disagree with
It's true that `jj fix` can be faster by not touching the working copy, but we also want a `jj run` command for the linter feature (https://github.com/jj-vcs/jj/issues/1869). It's just not done yet.
When you make a change to a pr in response to review feedback, do you just jj edit it in, and end up with a force push on GitHub? After which the review comment might get detached from the code or even hidden.
That's definitely something that could be better for me. (That said, there are other projects making it better too.)
The workflow still functions, it just requires me to manually update bookmarks.
I personally feel like your employer's policy is unusual for PR branches. Other people force pushing? Bad. Force-pushing to `main`? Bad. But force pushing to your own branch when you can delete it and re-create it? Just a waste of your time for no real reason. I wonder what the justification is.
Correct.
It makes sense to me because it leaves a linear history of git commits in response to comments on a PR which makes code review easier. We squash and rebase at the end.
> Just a waste of your time for no real reason. I wonder what the justification is.
We used to be on Gerrit, which I found better for code review as I could stack a bunch of minute changes together. I probably had 50-100% more productivity on Gerrit before my team made the switch.
Unfortunately, the industry standard is GitHub PRs. My team wasted a ton of time onboarding people to Gerrit and even after onboarding, less than 5% of people understood stacked changes enough to use them effectively.
Since force pushing/rebasing messes up GitHub PRs it was banned.
If you have suggestions for alternative code review workflows on GitHub I'm happy to hear them, but ideally they could be incremental.
Patch-based workflows in general (where you heavily use git rebase -i to curate a smaller set of "perfect" commits for anything you'd PR, rather than just piling new commits onto every PR) don't work well with the GitHub approach, which heavily favors merging stuff through the web interface (making merge or squash commits along the way).
You can make it work of course, but GitHub tends to behave in weird ways when it comes to how it's interface works with patch-based workflows. Perhaps a better estimate would be to see how it compares to a forge like Phorge or Sourcehut.
(The mention of the GitHub SVP being interested in stacked diffs sounds good in that regard. I'm also keeping an eye on Tangled and, now, on ERSC.)
You can have real branches! Many of them! You don't have to manually merge them! It's decentralized, you can have multiple origins, it lets you work offline! The list goes on and on.
There were many compelling reasons to switch to Git. But for all the articles about jj out there, I've never read any compelling reason to switch to jj. "It easier", "the commands are somewhat more ergonomic"... that's all?
Hot take, but I personally hate git and almost always rely on a GUI tool or IDE integration to interact with it.
Same happened e.g. with nodejs getting deno and bun around, which allowed to break nodejs' inertia on many problems that the others have solved.
I've been exploring JJ mainly for its slightly different approach to change tracking (~every change gets tracked, at least initially, rather than just commits).
Stacked PRs also look interesting but I haven't had an occasion to try them out yet.
FWIW, I still tried out jj and found it a joy to use. I use it all the time now. Most of the time, it not only gets out of your way, but rolls out the red carpet. I'm saying that as someone who knows their way around the git command line. t's like replacing your trusty old remote control with a new one where the buttons are well labeled, ergonomically placed, that lets you do entirely new useful things, and it has a universal back button that just works.
Maybe jj is an especially good fit for my way of working, but I do think that it is a real, actual improvement for everyone.
And it's super easy to pick up anytime. So yeah, I think you're doing it right! Sit back and let it come your way. From what I can see, there's a pretty good chance that it will.
But. I think it's incredibly useful for organizations to have patterns for how they use git. There can be huge variance! And there's so many people who don't feel comfortable doing interactive rebases (of their feature branches), or other serious monkeying with history.
(I also think jj's flows are incredibly good about avoiding accidental loss of work in a way that git can be extremely dangerous at.)
I think there's a ton of value to having more of a pattern than the free-form jamming that git gives us. The real value I see in jj is that it's more than the toolbox of things git gives one: it's something more learnable, teachable, and directed than git. And it seems to do it pretty well, with style, and less monkey business. I'm still super greenhorn at jj, and honestly lacking the need for it, but I'm excited to see it come along. Especially since it is compatible with so many other VCS.
It’s very liberating in some ways, in others it’s simply no worse than git. You can do everything you can do with git, but some of those things don’t require multiple steps or n repeats of the same action. jj rebase + commitable conflicts + jj undo = freedom and peace of mind.
Not really? From someone's post here a year ago:
> The real innovation of a lot of these alternative DVCS systems is that they free the state of the source from being dependent on the history that got you there. Such that applying patches A & B in that order is the same as applying B' & A' -- it results in the same tree. Git, on the other hand, hashes the actual list of changes to the state identifier, which is why rebasing results in a different git hash id.
Anybody who's wrestled with reordering/rebasing git history or has done git archaology is able to understand this benefit.
From Pijul's site:
> Pijul is the first distributed version control system to be based on a sound mathematical theory of changes
After years of grudgingly tolerating using a deployed prototype for a VCS, yes, I want the mathematically sound alternative.
All that being said, I do wish you the best, because truly, I am tired of git and JJ does seems like an improvement.
Most of my wrestling is with merge conflicts and a consistent tree doesn't help with that.
In a very real way, git won, and the inertia behind git is higher than it was for any VCS tool before it, and so just being better isn’t going to be enough, you’ll also need to interoperat.
Who upvotes this?
So the article is more like “Here’s why I started using Rust. If you thought I made a good choice then, well, I’m making a similar choice in case you want to join me.” Seems people find that compelling.
Just like Rust’s success was not inevitable, neither is jj’s. But I think it might work out.
You could also consider this a disclosure of sorts, I post a lot on this forum about jj (and Rust), and so knowing that I now have a financial incentive is important context to some people.
https://ersc.io/
- Everything locally stored in the repo: PRs, comments, issues, discussions, boards, ... - CLI first - Offline first (+ syncing) - A website for hosting/presentation
I was expecting when I make a commit, I would have the facility to specify what issues it addressed and it would close them for me automatically. It seemed there is so much opportunity there to "close the loop" when the issue tracker, etc and integrated in your VCS, but it wasn't taken.
If I may make a suggestion here: Allowing PRs to be stacked, i.e. allowing commits to be reviewed individually, like in Sapling, would be FANTASTIC.
EDIT: See also the link in this comment: https://news.ycombinator.com/item?id=45675335
I guess you benefit from some of the good parts only with the Google internal Piper backend, at the moment. So I’m curious about the ideas and plans you have at ERSC.
But what I’m also really yearning for is having a distributed asynchronous/offline-first code review flow built right in. The distributed nature of git somehow got lost with PRs or MRs in GitHub & Co.
Demo: run `git cat-file -p HEAD` in any jj repository that you've made a change to.
> do I get any benefit from the change id if I push to GitHub for PR review?
As of right now? Not really. The details are more complicated, but basically, if your project doesn't like the behavior of github when it comes to comments + editing commits, and wants you to tack on new commits instead, we can't change that behavior. However, https://github.com/LucioFranco/jj-spr can, in some situations, give you some of this experience. If your project is okay with editing commits, then it can help you locally, sure.
However. In an interesting turn of developments, GitHub's new SVP just tweeted that he's likes jj and is interested in adding stacked diffs to github. I don't know how this squares with their "no new features for 18 months" thing, but we'll see!
> But what I’m also really yearning for is having a distributed asynchronous/offline-first code review flow built right in.
It's not code review, it's issue tracking, but I've been using https://github.com/steveyegge/beads this week, and I think it might be the first "put your issues in your repo" system I actually enjoy. It says it's built for AI stuff, but like, you don't have to use AI with it.
I don't mean to imply that Google is fickle, but anything besides Google's perforce fork is deprecated every few years. We used to have a proper git wrapper, then mercurial+extensions, now jj is supposed to replace the mercurial thing, all in 7-ish years?
The git wrapper was never fully supported and had some rough edges (I think it was only ever a 20% project, and also its, like, really old). And the customized mercurial has been around for more than 7 years, I think close to a decade (the client I'm using right now is turning 7, and it wasn't my first one).
Yet another reason is that the .git directory is considered a documented API and several other tools and libraries depend on it (e.g. JGit and libgit2). So any new features for Google would need to be made to those tools too if we wanted things built on them to work.
We also consider Mercurial to have better UX.
I'm going back starting on monday, so I'm curious to try out jj.
In the past 10 years it's all been github and gitlab, and their code review tools are so painful, specifically w.r.t. tracking discussions across revisions. I never felt excited to try out jj because I was afraid it would that situation even worse.
But yeah, it's been a lot. Frankly even harder to keep track of from the outside!
I'll venture that jj is there to stay, however. If not at Google, then in general. It's just too much of a quantum leap. I think I've finally identified what about it sits so right with me: a change's identity is preserved through its revisions. In bare git, after a rebase or an amend, you get a wholly different commit that just happens to have a similar content.
Mind you, I'll also venture that jj will remain based on git as its storage backend, despite its stated goal otherwise. Git's internals are just too good at what they do to make it worthwhile to replace them.
168 more comments available on Hacker News