Every time I see one of these nifty git tricks or workarounds I find myself wondering, “why not just use jj?”
You get a nicer, significantly simpler interface. You don’t need any tricks. You don’t have to google how to work yourself out of a bad state, ever. And you get near-perfect git compatibility (ie you can use jj on a shared git repo, doing all the same things, and your teammates won’t know the difference).
I’ve wondered if there is a psychological thing here: someone who spent time memorizing all the git nonsense may have some pride in that (which is earned, certainly), that introduces some mental friction in walking away???
I'm one of the git users you describe who are resistant to jj. jj sounds great, Steve Klabnik's endorsement is very convincing, and I would probably love it, but here's the issue: I've used git for 17 years and have internalized its idiosyncracies sufficiently to practically never run into problems, and help anyone on my team who does.
jj is harder to adopt for people with a thorough mental model of git, because it's harder to accept jj commands at face value. I know it's modifying my git tree, so I feel compelled to grok exactly what it's doing, but that's distracting and time consuming.
People like me should probably trial jj exclusively for two weeks, to shed that antijjotic resistance and form a more clear-headed opinion.
> jj is harder to adopt for people with a thorough mental model of git
No, it really isn’t. I have used git since shortly after it was first released and I’ve written a git implementation.
I switched to jj in one day. And the amount of git arcana I have to keep in working memory is now basically nil. My VCS now works in almost a 1:1 mapping with how my brain wants to interact with my repo rather than having to go through a translation layer.
If you understand what git commands are doing, what jj does is essentially trivial to add to your mental model.
I also get the benefit of being able to use workflows that I always want to use in git but which are an enormous pain in practice. And I get access to wildly powerful new workflows I didn’t even consider because they would be outlandish in git.
What I will say is this: there is certainly an adjustment period, and I also totally hear you about how learning internals can be time consuming.
I think you can get a lot of the way there with at least the core concept with something like this, if you'll indulge me:
With git, you build up stuff on your filesystem. You then select which bits go into a diff in your index, and then when you're done, you stamp out a commit.
With jj, you instead start by creating a commit. In this case, it's empty. Then, every time you run a jj command, it does a snapshot, and this produces a new commit. However, because we want to have a stable identifier for a commit, we introduce a new one: the change id. This is basically an alias for the latest commit snapshot that was made. Your git history is just made up of each of these latest commits for each change.
... does that make any sense? Obviously there's more to all of the features than this, but that's sort of the core way that the histories map to each other.
It's not a trick or workaround. It's a very straightforward use of a command flag on one of the most used git commands. It's even conceptually very simple, you're just rebasing a subset of commits of a branch onto a different parent. Anyone who has ever rebased already has a working mental model of this operation. Framing this issue where knowing a single flag on a command every git user uses every day to perform an operation they already broadly understand as some arcane knowledge and 'nonsense' is ridiculous.
> introduces some mental friction in walking away???
I don't think it's just mental friction. Suppose you've learned git well enough that everything you do in it is automatic and fast, and the things which aren't fast by default you've built aliases and tooling for over the years. Yes, starting from ground zero you might want something like jj, but at the current point in your life you're not starting from ground zero. Switching to jj means learning another tool to achieve similar outcomes on your workflows.
If jj took many weeks of relearning, I might be right there with you. But the overwhelming majority of people I’ve personally seen who try the switch convert within a day, are barely slowed down by day two, and are effectively fluent within three days to a week at most.
It really just depends. I was very comfortable with the git cli. It didn't take long to learn jj's, and I'm faster with it now than I ever was with git, simply because a lot of things are easier to do and take less commands.
I don't think it's pride, more that I don't see the problem that it solves for me. I don't find that git gets in my way at all, and I don't find it confusing. It's a pretty transparent tool that I use every day and hardly notice.
I don't mind other people using jj, but I simply don't feel a need to try it. There's nothing prideful about that, it's just pragmatism.
Pragmatic is using the best tool for the job. Certainly subjectively, and arguably objectively, jj is the better tool in many ways.
My advice is to try it. You should like it, if you're in the majority of folks to give it a sincere shot. If you don't like it, cool. But then my advice changes. jj is probably the future. Adapt or become one of those old-timers who froze their learning in time.
The most common reason is that the git user has no idea it exists. I am in this bucket alongside 99% of git users.
There are an assortment of other potential reasons:
- It is a new tool that hasn't been battle tested as much as git has, which can decrease confidence.
- Git has inertia. People have learned it, it takes less effort to add a new git skill to your repertoire than learn a new tool from scratch, even if the new tool is easy to pick up.
- Due to its novelty, the auxiliary tooling ecosystem for jj is smaller (does it have plugins for all the popular editors? Lots of people like those, git's are high quality)
- Git is good enough. It's not perfect, but its popularity means that its shortcomings have readily available fixes or tweaks from users. It simply isn't bad enough and there are bountiful resources on how to use it effectively.
I think a core reason (besides not knowing jj exists), is the framing that there is a choice that has to be made, or a switch that has to occur. It is, instead, additive. I have Sublime Merge (GUI git client) and jj both looking at my git repo all day. Zed's git stuff is watching it too.
jj is sort of a bag of git tricks for me that I use when needed. It's no different than some things being easier with the git CLI vs others being easier in Sublime. I'll be at a stage where my committing/branching/rearranging wants are something that jj nails perfectly, and I do those there. As far at the other tools are concerned, I just did a bunch of sophisticated git operations.
The "colocated with git" capability of jj is probably it's most amazing feature tbh, and is key to any sort of adoption.
1. It's very new; I haven't had time to learn it properly yet.
2. It's very new and tooling doesn't support it well, e.g. VSCode. There aren't many GUIs yet.
3. I tried it once co-locating with Git and you definitely can't use both at the same time, even if it can use a `.git` directory. It ended up in a huge mess.
I'm definitely in favour of better-than-Git alternatives but I don't think it's reasonable to expect everyone to switch to JJ right now. It isn't so much better that abandoning the de facto standard is obviously worth it yet. (In contrast to things like the iPhone, Rust, SSDs, etc.).
Also I really wish they would focus on some of the bigger pain points of Git. I can deal with rebasing and whatnot. Sometimes it's painful but it's usually not that bad.
What I can't deal with are submodules and LFS. Both are awful and fixing them properly requires fundamental changes to the VCS which aren't going to happen in Git. JJ has an opportunity to do that. Imagine if JJ could say "we have submodules but they aren't awful!" or "you can check in large files!". Those are the sort of huge advantages that would mean you can say "why not just use JJ".
Colocating is the default now, and you should be able to use both at the same time, though running git commands that mutate can confuse jj. Ideally you only use read-only git commands.
Both submodules and LFS are things that jj wants to address, but they take time.
Oh, there's another stgit user! ^5
Coming from darcs, I couldn't use git until stgit came along, and today, it's one of those few tools I can't imagine working without. Nothing else matches my way of code hacking.
So often, I watch people making a big mess with git, and I always recommend stgit to them, so they can post proper and reviewable branches for merging. But in all these years, I could never convince anybody.
It’s a bit like qwertz. Sure, it is not optimal, there are better alternatives available. But it is good enough, and it is universal. That trumps a 5% typing improvement on my own custom keyboard layout at the cost of not being able to use my coworkers keyboard.
Also, I dislike all of the alternate git frontends I tried, because they are opinionated in a way they clash with my workflow.
Moreover, I don’t think the git CLI is that bad. Once you learn some basic concepts, it makes a lot of sense and is pretty consistent.
Most problems people report stem from a refusal to learn the underlying structure and models. That is on them. And when using a different frontend, they don’t disappear either. They are just abstracted, to allow you to avoid learning them. But they are still there, and you will probably still need to know them at some point.
> Most problems people report stem from a refusal to learn the underlying structure and models.
It's very easy to fall into the trap of believing this: git's implementation fits together neatly enough that it feels like the best you could do. Like, yes it's complex, but surely that's just intrinsic complexity of the problem? (Also, I think we all sometimes feel like someone with a different view must just not know as much as us.)
But if you have used other version control systems (I'm thinking particularly Mercurial here) you realise that actually some of that complexity is just totally made up by git.
Jujutsu is not a Git frontend, it is an independent VCS that is compatible with Git. This is important because it has concepts and ideas of its own. It is used entirely independent of Git within Google.
i went from being a "jj cli power user" to relying on jjui for all of my complex rebase needs so quickly that i now have to read the man page to recall basic commands
This particular tip is basic. It just describes how to copy changes from one branch to another with one kind of rebase. But there's always someone who is learning git for the first time and may not even know how it's used.
Git is simple enough and has features and capabilities that jj does not have. Contrary to popular belief, git is not hard to use. I refuse to use any "simpler" system that is slower or less feature-rich than git. I don't even want to learn another commit graph model, because git's model is very good. About 95% of what people like yourself call "git nonsense" consists of useful features that many people would be annoyed to not have.
I believe that a large number of git or general VCS users have no idea about commit hygiene. They have not had to cherry-pick or edit commits, and have no idea what to do about conflicts. To people like that, git's features and methods will appear especially foreign.
I looked over jj specifically many moons ago and concluded it would annoy me and not function at my job. I forgot what the reasons were. One reason was most likely because I need submodules and worktrees to work. I just looked at its FAQ, and saw a bunch of nonsensical new terms as well. Nothing is more compatible with git than git itself, and I am very satisfied with how well git works for me.
submodules aren't native with jj, you use git commands to manage them, and it works fine. Eventually there'll be some sort of native support.
worktrees are called "workspaces" in jj, but are the same.
A lot of people find jj easier to have good commit hygiene with, and find it simpler and more powerful, not less. But that said, if you're happy with git, you should continue to use it.
There is also mental friction with learning an entirely new tool. `jj` is different enough from `git` that one can't transfer knowledge. Currently the documentation is not good enough to assuage that issue.
Frankly, this is a rather poor, uninformed excuse. Most people who try it grok the concepts in days. And they feel right at home in weeks. That's when you start hearing, "I'll never go back."
Wish i could remember my issues with jj. I tried it, i wanted to stick with it because i loved the fact that i could reorder commits while deferring the actual conflicts.. but something eventually prevented me from switching. Searching my slack history where i talked about this with a coworker who actually used jj:
1. I had quite a bit of trouble figuring out a workflow for branches. Since my companies unit of work is the branch, with specifically named branches, my `jj ls` was confusing as hell.
`jj st` might have helped a bit, but there were scenarios where creating an commit would abandon the branch... if i'm reading my post history correctly. My coworker who was more familiar explained my jj problems away with "definitely pre-release software", so at the time neither of us were aware of a workflow which considered branches more core.
Fwiw, I don't even remember when the jj workflow had branches come into play.. but i was not happy with the UX around branches.
2. iirc i didn't like how it auto stashed/committed things. I found random `dbg!` statements could slip in more easily and i had to be on guard about what is committed, since everything just auto pushed. My normal workflow has me purposefully stashing chunks when i'm satisfied with them, and i use that as the visual metric. That felt less solid with jj.
Please take this with a huge grain of salt, this is 10 month old memory i scavenged from slack history. Plus as my coworker was saying, jj was changing a lot.. so maybe my issues are less relevant now? Or just flat out wrong, but nonetheless i bounced off of jj despite wanting to stick with it.
"creating a commit would abandon the branch" is certainly something lost in translation. There are other reasons you may have not liked the UX, largely that if you create branches and then add a bunch of commits after it, the branch head doesn't automatically move by default. There is a config setting you can change if you prefer that, or the `jj tug` alias some people set up.
I more or less use the method described [here](https://steveklabnik.github.io/jujutsu-tutorial/advanced/sim...) for branches. One thing I do change is that I set the bookmark to an empty commit that serves as the head of each branch. When I am satisfied with a commit on head and want to move it to a branch I just `jj rebase -r @ -B branch`. When I want to create a new branch it's just `jj new -A main -B head` and `jj bookmark set branch_name -r @`
Half my team switched to JJ this year, and I do find stacking PRs to be much more pleasant now. We had previously tried out Graphite but it didn't really stick.
I wrote up a little way to use JJ's revsets to make it easy to push an entire stack of branches in one command:
The main issue I kept having when trying to do this with just git is then managing all the branch names to be attached to the right moved commits, so that my stack could be reviewable on github's open PRs.
Does jj help with that at all?
I've experimented a bit with git-town.com (OSS) and now everyone at $DAYJOB uses graphite.com (SaaS) which does that part very well.
It’s one of the core features that rebases, including branch names (bookmarks in jj) work ‘correctly’. You can rebase whole dags, including merges, with multiple named heads with just one jj rebase -b.
`--update-refs` flag helps a lot in vanilla git. That and `--autosquash` should probably be default flags to `git rebase`. I also don't entirely trust rebase without `-i` (`--interactive`), personally. I hear there is talk about shaking up the out-of-the-box default flags in git 3, and I think rebase should especially get new defaults.
I came into the comments specifically to ask if this flag existed. I feel bad that the author developed this whole flow just because they didn't know about this, but that's pretty common with git.
discoverability is a big problem, especially for CLI tools which can't afford to show small hints or "what's new" popups. I myself learned it from someone else, not docs.
update-refs works only in a narrow case when every branch starts form the tip of a previous. Your helper might still be useful if it properly "replants" whole tree keeping its structure.
Running a git command on one branch and multiple branches being affected is really unusual for me! This really does look like it is designed for just this problem, though. Simple overview: https://blog.hot-coffee.dev/en/blog/git_update_refs/
I've settled on a workflow that reverses the situation. I simply commit all my work to the main branch and cherry pick commits into temporary feature branches only when submitting PRs.
This way I only need to worry about maintaining a single consistent lineage of commits. I've been using this workflow for about a year now and find it to be much easier than juggling and rebasing feature branches.
Interesting, I'll be sure to check it out. It sounds pretty similar to the tool I built which lets you edit a "plan" in a text editor to assign commits to feature branches - the plan is saved so it can be amended continuously.
I usually just `git rebase origin/main -i` after the base branch has been merged there, and this means I need to explicitly drop the merged commits, but I can inspect what's happening.
Add `--update-refs` to your interactive rebase and it will give you an easy line to know how many commits to drop because it will add an `update-ref` line for the old branch. You can just easily delete everything up to and including that `update-ref` line and don't have to manually pull up a git log of the other branch to remember which commits already merged.
(Plus, of course, if you have multiple branches stacked, `--update-refs` makes it easier to update all of them if you start from the outermost branch.)
I'm a heavy user of git-spice: https://abhinav.github.io/git-spice (created by a former coworker) and can't really go back to a time without it. While still not nearly as good as Facebook's Phabricator, it's probably the best workflow for small, focused stacked PRs you can achieve in a Github / Gitlab based repository.
You get a nicer, significantly simpler interface. You don’t need any tricks. You don’t have to google how to work yourself out of a bad state, ever. And you get near-perfect git compatibility (ie you can use jj on a shared git repo, doing all the same things, and your teammates won’t know the difference).
I’ve wondered if there is a psychological thing here: someone who spent time memorizing all the git nonsense may have some pride in that (which is earned, certainly), that introduces some mental friction in walking away???
jj is harder to adopt for people with a thorough mental model of git, because it's harder to accept jj commands at face value. I know it's modifying my git tree, so I feel compelled to grok exactly what it's doing, but that's distracting and time consuming.
People like me should probably trial jj exclusively for two weeks, to shed that antijjotic resistance and form a more clear-headed opinion.
No, it really isn’t. I have used git since shortly after it was first released and I’ve written a git implementation.
I switched to jj in one day. And the amount of git arcana I have to keep in working memory is now basically nil. My VCS now works in almost a 1:1 mapping with how my brain wants to interact with my repo rather than having to go through a translation layer.
If you understand what git commands are doing, what jj does is essentially trivial to add to your mental model.
I also get the benefit of being able to use workflows that I always want to use in git but which are an enormous pain in practice. And I get access to wildly powerful new workflows I didn’t even consider because they would be outlandish in git.
What I will say is this: there is certainly an adjustment period, and I also totally hear you about how learning internals can be time consuming.
I think you can get a lot of the way there with at least the core concept with something like this, if you'll indulge me:
With git, you build up stuff on your filesystem. You then select which bits go into a diff in your index, and then when you're done, you stamp out a commit.
With jj, you instead start by creating a commit. In this case, it's empty. Then, every time you run a jj command, it does a snapshot, and this produces a new commit. However, because we want to have a stable identifier for a commit, we introduce a new one: the change id. This is basically an alias for the latest commit snapshot that was made. Your git history is just made up of each of these latest commits for each change.
... does that make any sense? Obviously there's more to all of the features than this, but that's sort of the core way that the histories map to each other.
I don't think it's just mental friction. Suppose you've learned git well enough that everything you do in it is automatic and fast, and the things which aren't fast by default you've built aliases and tooling for over the years. Yes, starting from ground zero you might want something like jj, but at the current point in your life you're not starting from ground zero. Switching to jj means learning another tool to achieve similar outcomes on your workflows.
I don't mind other people using jj, but I simply don't feel a need to try it. There's nothing prideful about that, it's just pragmatism.
My advice is to try it. You should like it, if you're in the majority of folks to give it a sincere shot. If you don't like it, cool. But then my advice changes. jj is probably the future. Adapt or become one of those old-timers who froze their learning in time.
The most common reason is that the git user has no idea it exists. I am in this bucket alongside 99% of git users.
There are an assortment of other potential reasons:
- It is a new tool that hasn't been battle tested as much as git has, which can decrease confidence.
- Git has inertia. People have learned it, it takes less effort to add a new git skill to your repertoire than learn a new tool from scratch, even if the new tool is easy to pick up.
- Due to its novelty, the auxiliary tooling ecosystem for jj is smaller (does it have plugins for all the popular editors? Lots of people like those, git's are high quality)
- Git is good enough. It's not perfect, but its popularity means that its shortcomings have readily available fixes or tweaks from users. It simply isn't bad enough and there are bountiful resources on how to use it effectively.
jj is sort of a bag of git tricks for me that I use when needed. It's no different than some things being easier with the git CLI vs others being easier in Sublime. I'll be at a stage where my committing/branching/rearranging wants are something that jj nails perfectly, and I do those there. As far at the other tools are concerned, I just did a bunch of sophisticated git operations.
The "colocated with git" capability of jj is probably it's most amazing feature tbh, and is key to any sort of adoption.
1. It's very new; I haven't had time to learn it properly yet.
2. It's very new and tooling doesn't support it well, e.g. VSCode. There aren't many GUIs yet.
3. I tried it once co-locating with Git and you definitely can't use both at the same time, even if it can use a `.git` directory. It ended up in a huge mess.
I'm definitely in favour of better-than-Git alternatives but I don't think it's reasonable to expect everyone to switch to JJ right now. It isn't so much better that abandoning the de facto standard is obviously worth it yet. (In contrast to things like the iPhone, Rust, SSDs, etc.).
Also I really wish they would focus on some of the bigger pain points of Git. I can deal with rebasing and whatnot. Sometimes it's painful but it's usually not that bad.
What I can't deal with are submodules and LFS. Both are awful and fixing them properly requires fundamental changes to the VCS which aren't going to happen in Git. JJ has an opportunity to do that. Imagine if JJ could say "we have submodules but they aren't awful!" or "you can check in large files!". Those are the sort of huge advantages that would mean you can say "why not just use JJ".
Both submodules and LFS are things that jj wants to address, but they take time.
Also, I dislike all of the alternate git frontends I tried, because they are opinionated in a way they clash with my workflow.
Moreover, I don’t think the git CLI is that bad. Once you learn some basic concepts, it makes a lot of sense and is pretty consistent.
Most problems people report stem from a refusal to learn the underlying structure and models. That is on them. And when using a different frontend, they don’t disappear either. They are just abstracted, to allow you to avoid learning them. But they are still there, and you will probably still need to know them at some point.
It's very easy to fall into the trap of believing this: git's implementation fits together neatly enough that it feels like the best you could do. Like, yes it's complex, but surely that's just intrinsic complexity of the problem? (Also, I think we all sometimes feel like someone with a different view must just not know as much as us.)
But if you have used other version control systems (I'm thinking particularly Mercurial here) you realise that actually some of that complexity is just totally made up by git.
I recognize that some folks are stuck with it, and yeah, in your case jj probably just doesn't make sense. Stay tuned though.
i went from being a "jj cli power user" to relying on jjui for all of my complex rebase needs so quickly that i now have to read the man page to recall basic commands
Git is simple enough and has features and capabilities that jj does not have. Contrary to popular belief, git is not hard to use. I refuse to use any "simpler" system that is slower or less feature-rich than git. I don't even want to learn another commit graph model, because git's model is very good. About 95% of what people like yourself call "git nonsense" consists of useful features that many people would be annoyed to not have.
I believe that a large number of git or general VCS users have no idea about commit hygiene. They have not had to cherry-pick or edit commits, and have no idea what to do about conflicts. To people like that, git's features and methods will appear especially foreign.
I looked over jj specifically many moons ago and concluded it would annoy me and not function at my job. I forgot what the reasons were. One reason was most likely because I need submodules and worktrees to work. I just looked at its FAQ, and saw a bunch of nonsensical new terms as well. Nothing is more compatible with git than git itself, and I am very satisfied with how well git works for me.
worktrees are called "workspaces" in jj, but are the same.
A lot of people find jj easier to have good commit hygiene with, and find it simpler and more powerful, not less. But that said, if you're happy with git, you should continue to use it.
I agree. That's why jj uses practically the same model. That's how Git can quite easily be used as a backend.
> I just looked at its FAQ, and saw a bunch of nonsensical new terms as well.
Like what? Perhaps we can improve it.
The jj CLI is very easy to grok, even for a seasoned git user. Maybe even especially so for a seasoned git user.
1. I had quite a bit of trouble figuring out a workflow for branches. Since my companies unit of work is the branch, with specifically named branches, my `jj ls` was confusing as hell.
`jj st` might have helped a bit, but there were scenarios where creating an commit would abandon the branch... if i'm reading my post history correctly. My coworker who was more familiar explained my jj problems away with "definitely pre-release software", so at the time neither of us were aware of a workflow which considered branches more core.
Fwiw, I don't even remember when the jj workflow had branches come into play.. but i was not happy with the UX around branches.
2. iirc i didn't like how it auto stashed/committed things. I found random `dbg!` statements could slip in more easily and i had to be on guard about what is committed, since everything just auto pushed. My normal workflow has me purposefully stashing chunks when i'm satisfied with them, and i use that as the visual metric. That felt less solid with jj.
Please take this with a huge grain of salt, this is 10 month old memory i scavenged from slack history. Plus as my coworker was saying, jj was changing a lot.. so maybe my issues are less relevant now? Or just flat out wrong, but nonetheless i bounced off of jj despite wanting to stick with it.
Auto-commit is still a thing, but you can regain the stuff you like with a workflow change, this is called the "squash workflow" and is very popular: https://steveklabnik.github.io/jujutsu-tutorial/real-world-w...
> You rebase feature-1 onto main:
feature2 moves as well. Basically, the behavior here is just the default.
It's not something I can just shift away from.
This makes it unusable for me.
Keeping these things in a private commit is one option.
Configuring auto-tracking to be off is another option.
https://github.com/jj-vcs/jj
https://www.stavros.io/posts/switch-to-jujutsu-already-a-tut...
Also found https://github.com/gitbutlerapp/gitbutler
I wrote up a little way to use JJ's revsets to make it easy to push an entire stack of branches in one command:
https://crabmusket.net/2025/jj-bough-a-useful-alias-for-stac...
Does jj help with that at all?
I've experimented a bit with git-town.com (OSS) and now everyone at $DAYJOB uses graphite.com (SaaS) which does that part very well.
I used to dutifully read release notes for every git release, but stopped at some point. Apparently that point was more than three years ago.
Deleted Comment
Running a git command on one branch and multiple branches being affected is really unusual for me! This really does look like it is designed for just this problem, though. Simple overview: https://blog.hot-coffee.dev/en/blog/git_update_refs/
https://andrewlock.net/working-with-stacked-branches-in-git-...
Another commenter posted this link which was a bit more succinct
https://blog.hot-coffee.dev/en/blog/git_update_refs/
There isn’t much to it though, you just go to the branch and run git rebase with the update refs flag.
This way I only need to worry about maintaining a single consistent lineage of commits. I've been using this workflow for about a year now and find it to be much easier than juggling and rebasing feature branches.
In case anyone's interested, I made a tool that automates this workflow. The worfklow and tool are described here: https://github.com/bjvanderweij/dflock/
https://blog.gitbutler.com/stacked-branches-with-gitbutler
(Plus, of course, if you have multiple branches stacked, `--update-refs` makes it easier to update all of them if you start from the outermost branch.)