Jujutsu destroyed my Git workflow, and I'm not even mad!

I had everything and Jujutsu destroyed it. I had the perfect Git workflow with lazygit perfectly set up, aliases for the most used commands like gst for git status, gp for git push, and gloga for git log --oneline --decorate --graph --all. I used fixup commits and git absorb to automatically create them. I loved the feeling of a successful Git rebase and force push to my feature branch after discovering git rerere. It was all so comfy. Now with Jujutsu, none of that is useful anymore, and I’m not even mad!

What’s Jujutsu?

Jujutsu is a new version control system, mostly referred to as jj. You can use it like any other VCS to track changes in text files and collaborate with others. What sets jj apart is how you interact with it and the fact that it abstracts the storage engine from everything else. You can use Git as its backend and easily adopt it in existing codebases without requiring everyone to switch tools.

Say you’re juggling two features. In Git, you either commit half-baked work with a “WIP” message you’ll have to clean up later, or you stash and pray. And when you spot a typo three commits back? That’s git commit --fixup, then later git rebase -i --autosquash, carefully checking you didn’t mess up the order, resolving any conflicts, force pushing your branch. Rinse, repeat. In jj, your work-in-progress is already a commit, always. Switching to another feature is just jj edit other-feature. No stashing, no throwaway commits. Spot that typo three commits back? jj edit that commit, fix it, done. Every descendant rebases automatically.

In jj, there’s no staging area. No git add. Everything is always recorded automatically, and you can easily switch between working trees. No more need for git stash or git worktree gymnastics.

Messed up an operation? Don’t worry, jj undo will revert it. The entire operation history is tracked, so you can always go back. Like reflog, but better.

Learning jj

To be honest, at first, I wasn’t really impressed. I could see its potential but still didn’t believe the hype. Some operations felt unintuitive, or better, unfamiliar, which introduced some friction. It took me about a week of daily usage to get comfortable with it.

The moment it clicked was when I realized I could just be anywhere in my history. Need to check something three commits back? jj edit there, poke around, make a change if needed, and descendants rebase automatically. No detached HEAD warnings, no “you have unstaged changes” blocking you. The working copy is always a commit, so there’s nothing to lose.

The second realization: I stopped rebasing manually. In Git, I’d carefully orchestrate rebases, sometimes multiple times a day, especially when stacking changes. In jj, you just… work. Move commits around, and everything downstream adjusts. It sounds small until you notice you haven’t typed rebase in two weeks.

By the second week, I was all over it and navigating the repo felt like a breeze. Now Git feels kinda clunky.

I still reach for lazygit occasionally, mostly for exploring history, creating tags, or just poking around the repo. But the day-to-day work? Completely done in jj now.

What helped me most when switching over was this absolute lifesaver: the Git command table. It maps Git commands to their jj equivalents. Bookmark it.

Should you switch?

Here’s the catch: if you’re still getting comfortable with Git, I can’t recommend switching to jj just yet. Git is the industry standard. You’ll find it everywhere, and you’ll be expected to know your way around it. Learn Git first, then come back to jj when you’re ready.

For everyone else who’s been living in Git for years and is curious about something better? Give it a shot. The tutorial is solid, and there are plenty of YouTube videos walking through real workflows.

One genuine annoyance for tmux users: if you navigate panes with j/k, typing jj right after switching can misfire. The j gets eaten by tmux’s repeat window. I’m still hunting for a clean fix.

My config

Here’s what I’m running if you want a starting point:

 1#:schema https://jj-vcs.github.io/jj/latest/config-schema.json
 2[user]
 3name = "************"
 4email = "************"
 5
 6[ui]
 7editor = "nvim"
 8merge-editor = "bc"
 9paginate = "never"
10
11[aliases]
12tug = ["bookmark", "move", "--from", "heads(::@- & bookmarks())", "--to", "@-"]
13l = ["log", "--limit", "20"]
14la = ["log", "-r", "all()"]
15
16[merge-tools.bc]
17program = "bcomp"
18edit-args = ["$left", "$right", "-ro1", "-expandall"]
19merge-args = ["$left", "$right", "$base", "$output", "-automerge", "-reviewconflicts"]
20
21[merge-tools.mergiraf]
22program = "mergiraf"
23merge-args = ["merge", "$base", "$left", "$right", "-o", "$output", "-l", "$marker_length", "--fast"]
24merge-conflict-exit-codes = [1]

The tug alias is stolen from the community and makes bookmark management a breeze. Beyond Compare (bc) handles merges, and mergiraf is there for structured merge support.

That’s it. If you’re curious, the tutorial is solid, and Chris Krycho’s jj init essay captures the “aha” moments better than I could. Maybe you’ll let jj destroy your workflow too.