{
    "archive_path": "archive/1760332083.525186",
    "base_url": "www.stavros.io/posts/switch-to-jujutsu-already-a-tutorial",
    "basename": "",
    "bookmarked_date": "2025-10-13 05:08",
    "canonical": {
        "archive_org_path": "https://web.archive.org/web/www.stavros.io/posts/switch-to-jujutsu-already-a-tutorial",
        "dom_path": "output.html",
        "favicon_path": "favicon.ico",
        "git_path": "git/",
        "google_favicon_path": "https://www.google.com/s2/favicons?domain=www.stavros.io",
        "headers_path": "headers.json",
        "htmltotext_path": "htmltotext.txt",
        "index_path": "index.html",
        "media_path": "media/",
        "mercury_path": "mercury/content.html",
        "pdf_path": "output.pdf",
        "readability_path": "readability/content.html",
        "screenshot_path": "screenshot.png",
        "singlefile_path": "singlefile.html",
        "warc_path": "warc/",
        "wget_path": null
    },
    "domain": "www.stavros.io",
    "downloaded_at": "2025-10-13T05:08:04.891221+00:00",
    "downloaded_datestr": "2025-10-13 05:08",
    "extension": "",
    "hash": "57AYTW7S6NCJK648VEHS",
    "history": {
        "archive_org": [
            {
                "cmd": [
                    "/usr/bin/curl",
                    "--silent",
                    "--location",
                    "--compressed",
                    "--proxy",
                    "socks5://tor-socks-proxy:9150",
                    "--head",
                    "--max-time",
                    "60",
                    "--user-agent",
                    "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36 ArchiveBox/{VERSION} (+https://github.com/ArchiveBox/ArchiveBox/)",
                    "https://web.archive.org/save/https://www.stavros.io/posts/switch-to-jujutsu-already-a-tutorial/"
                ],
                "cmd_version": "8.10.1",
                "end_ts": "2025-10-13T05:08:53.872888+00:00",
                "index_texts": null,
                "output": "ArchiveError: Failed to find \"content-location\" URL header in Archive.org response.",
                "pwd": "/data/archive/1760332083.525186",
                "schema": "ArchiveResult",
                "start_ts": "2025-10-13T05:08:52.350818+00:00",
                "status": "failed"
            }
        ],
        "dom": [
            {
                "cmd": [
                    "/usr/bin/chromium-browser",
                    "--proxy-server=socks5://tor-socks-proxy:9150",
                    "--disable-features=DarkMode",
                    "--run-all-compositor-stages-before-draw",
                    "--hide-scrollbars",
                    "--autoplay-policy=no-user-gesture-required",
                    "--no-first-run",
                    "--use-fake-ui-for-media-stream",
                    "--use-fake-device-for-media-stream",
                    "--simulate-outdated-no-au='Tue, 31 Dec 2099 23:59:59 GMT'",
                    "--headless=new",
                    "--no-sandbox",
                    "--no-zygote",
                    "--disable-dev-shm-usage",
                    "--disable-software-rasterizer",
                    "--disable-sync",
                    "--window-size=1440,2000",
                    "--user-agent=Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36 ArchiveBox/{VERSION} (+https://github.com/ArchiveBox/ArchiveBox/)",
                    "--user-data-dir=/data/personas/Default/chrome_profile",
                    "--profile-directory=Default",
                    "--dump-dom",
                    "https://www.stavros.io/posts/switch-to-jujutsu-already-a-tutorial/"
                ],
                "cmd_version": "131.0.6778",
                "end_ts": "2025-10-13T05:08:20.722312+00:00",
                "index_texts": null,
                "output": "output.html",
                "pwd": "/data/archive/1760332083.525186",
                "schema": "ArchiveResult",
                "start_ts": "2025-10-13T05:08:13.156959+00:00",
                "status": "succeeded"
            }
        ],
        "favicon": [
            {
                "cmd": [
                    "/usr/bin/curl",
                    "--silent",
                    "--location",
                    "--compressed",
                    "--proxy",
                    "socks5://tor-socks-proxy:9150",
                    "--max-time",
                    "60",
                    "--output",
                    "favicon.ico",
                    "--user-agent",
                    "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36 ArchiveBox/{VERSION} (+https://github.com/ArchiveBox/ArchiveBox/)",
                    "https://www.google.com/s2/favicons?domain=www.stavros.io"
                ],
                "cmd_version": "8.10.1",
                "end_ts": "2025-10-13T05:08:08.866113+00:00",
                "index_texts": null,
                "output": "favicon.ico",
                "pwd": "/data/archive/1760332083.525186",
                "schema": "ArchiveResult",
                "start_ts": "2025-10-13T05:08:05.475735+00:00",
                "status": "succeeded"
            }
        ],
        "git": [],
        "headers": [
            {
                "cmd": [
                    "/usr/bin/curl",
                    "--silent",
                    "--location",
                    "--compressed",
                    "--proxy",
                    "socks5://tor-socks-proxy:9150",
                    "--head",
                    "--max-time",
                    "60",
                    "--user-agent",
                    "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36 ArchiveBox/{VERSION} (+https://github.com/ArchiveBox/ArchiveBox/)",
                    "https://www.stavros.io/posts/switch-to-jujutsu-already-a-tutorial/"
                ],
                "cmd_version": "8.10.1",
                "end_ts": "2025-10-13T05:08:09.170030+00:00",
                "index_texts": null,
                "output": "headers.json",
                "pwd": "/data/archive/1760332083.525186",
                "schema": "ArchiveResult",
                "start_ts": "2025-10-13T05:08:08.898985+00:00",
                "status": "succeeded"
            }
        ],
        "htmltotext": [
            {
                "cmd": [
                    "(internal) archivebox.extractors.htmltotext",
                    "./{singlefile,dom}.html"
                ],
                "cmd_version": "0.8.5rc51",
                "end_ts": "2025-10-13T05:08:42.707649+00:00",
                "index_texts": [
                    "Switch to Jujutsu already: a tutorial - Stavros' Stuff (https://www.stavros.io/posts/switch-to-jujutsu-already-a-tutorial/) (/static/images/favicons/apple-touch-icon.png?h=9b5552c9) (/static/images/favicons/favicon.ico?h=13b2c550) (/static/images/favicons/favicon-16x16.png?h=f3e1d4cf) (/static/images/favicons/favicon-32x32.png?h=d0029085) (/static/images/favicons/manifest.json?h=facfed0f) (/static/images/favicons/safari-pinned-tab.svg?h=7e72655d) (https://cdnjs.cloudflare.com/ajax/libs/lite-youtube-embed/0.3.3/lite-yt-embed.min.css) (Stavros' Stuff full posts feed) (/feed/short/) (/static/gen/main.css?h=1a007094)    (Search the site \u2026) (Search)    (/) (Stavros' Stuff) Stavros' Stuff  On programming and other things.  Tutorials (/tutorials/icecast/) How to create an internet radio station  (/tutorials/email/) How to delete emails on a POP3 server  (/tutorials/how-to-encode-your-movies/) How to encode your movies  (/tutorials/online-security/) How to keep yourself secure online  (/tutorials/how-to-run-opera-off-a-usb-thumb-drive/) How to run Opera off a USB thumb drive  (/tutorials/bittorrent/) How to use BitTorrent to send files  (/tutorials/networking-essentials/) Networking essentials  (/tutorials/secure-tunneling/) Secure Tunneling  (/tutorials/python/) Tutorial - Learn Python in 10 minutes    Downloads (/downloads/) Downloads  (/scripting/) Various scripts    Various (/projects/) My projects  (/notes/) Unstructured notes  (/freelance-python-developer/) Freelance Python developer  (https://github.com/skorokithakis/) My GitHub  (http://resume.stavros.io/) My r\u00e9sum\u00e9  (/about/) About me  (/archives/) Post archives     (#) Navigate to... (https://www.stavros.io/posts/switch-to-jujutsu-already-a-tutorial/#) Tutorials (https://www.stavros.io/tutorials/icecast/) \u2013\u00a0How to create an internet radio station (https://www.stavros.io/tutorials/email/) \u2013\u00a0How to delete emails on a POP3 server (https://www.stavros.io/tutorials/how-to-encode-your-movies/) \u2013\u00a0How to encode your movies (https://www.stavros.io/tutorials/online-security/) \u2013\u00a0How to keep yourself secure online (https://www.stavros.io/tutorials/how-to-run-opera-off-a-usb-thumb-drive/) \u2013\u00a0How to run Opera off a USB thumb drive (https://www.stavros.io/tutorials/bittorrent/) \u2013\u00a0How to use BitTorrent to send files (https://www.stavros.io/tutorials/networking-essentials/) \u2013\u00a0Networking essentials (https://www.stavros.io/tutorials/secure-tunneling/) \u2013\u00a0Secure Tunneling (https://www.stavros.io/tutorials/python/) \u2013\u00a0Tutorial - Learn Python in 10 minutes (https://www.stavros.io/posts/switch-to-jujutsu-already-a-tutorial/#) Downloads (https://www.stavros.io/downloads/) \u2013\u00a0Downloads (https://www.stavros.io/scripting/) \u2013\u00a0Various scripts (https://www.stavros.io/posts/switch-to-jujutsu-already-a-tutorial/#) Various (https://www.stavros.io/projects/) \u2013\u00a0My projects (https://www.stavros.io/notes/) \u2013\u00a0Unstructured notes (https://www.stavros.io/freelance-python-developer/) \u2013\u00a0Freelance Python developer (https://github.com/skorokithakis/) \u2013\u00a0My GitHub (http://resume.stavros.io/) \u2013\u00a0My r\u00e9sum\u00e9 (https://www.stavros.io/about/) \u2013\u00a0About me (https://www.stavros.io/archives/) \u2013\u00a0Post archives          (/posts/switch-to-jujutsu-already-a-tutorial/) (Permalink to \"Switch to Jujutsu already: a tutorial\") Switch to Jujutsu already: a tutorial  Conceived on Oct 10, 2025     If you don't like Jujutsu, you're wrong As all developers, I\u2019ve been using git since the dawn of time, since its commands were an inscrutable jumble of ill-fitting incantations, and it has remained this way until today.\nNeedless to say, I just don\u2019t get git.\nI never got it, even though I\u2019ve read a bunch of stuff on how it represents things internally.\nI\u2019ve been using it for years knowing what a few commands do, and whenever it gets into a weird state because I fat-fingered something, I have my trusty alias, fuckgit , that deletes the .git directory, clones the repo again into a temp folder, and moves the .git directory from that into my directory, and I\u2019ve managed to eke out a living for my family this way. Over the past few years, I\u2019ve been seeing people rave about (https://github.com/jj-vcs/jj) Jujutsu , and I always wanted to try it, but it never seemed worth the trouble, even though I hate git.\nI idly read a few tutorials, trying to understand how it works, but in the end I decided it wasn\u2019t for me. One day I randomly decided to try again, but this time I asked Claude how to do with Jujutsu whatever operation I wanted to do with git.\nThat\u2019s when the mental model of jj clicked for me, and I finally understood everything, including how git works .\nI never thought a VCS would spark joy in me, but here we are, and I figured maybe I can write something that will make jj click for you as well. It also doesn\u2019t hurt that Jujutsu is completely interoperable with git (and thus with providers like GitHub), and I can have all the power of Jujutsu locally on my git repos, without anyone knowing I\u2019m not actually using git. The problem The problem I had with the other tutorials, without realizing it, was thatthere was a fundamental tension between two basic things:\nThe best way to explain jj to someone who knows git is to use all the git terms they already know (because that makes it easy for them), but also to tell them to think about the git terms they know differently (because otherwise they\u2019ll form the wrong mental model).\nYou can\u2019t really explain something by saying \u201ca jj commit is like a git commit, except where it\u2019s not\u201d, so I\u2019ll try to do things a bit differently. This will be a short post (or, at least, not as long as other jj tutorials), I\u2019ll explain the high-level mental model you should have, and then give a FAQ for how to do various git things with jj. Warnings Just a disclaimer before we start, this is going to be far from an exhaustive reference. I\u2019m not an expert in either git or Jujutsu , but I know enough to hopefully make jj click for you enough to learn the rest on your own, so don\u2019t be too annoyed if I omit something. Also, you\u2019re going to read here some things about the way Jujutsu likes doing things that will offend you to your very core, and your first reaction will be \u201cmadness, this cannot possibly work\u201d.\nWhen you think this, I want you to relax, it\u2019s fine, it does work, it just means I haven\u2019t managed to make the whole thing click together for you yet.\nJust read on. I\u2019m not going to show you any Jujutsu commands here.\nI might refer to them by name, but I want you to understand the mental model enough to go look stuff up on your own, Jujutsu only has, like, three commands you\u2019re going to use for everything anyway (yes, you can do everything you do with git with them). (By the way, if you\u2019re going to be trying things out while reading this post, definitely get (https://terminaltrove.com/jjui/) jjui , it lets you visually work with the repository in a way that makes everything much easier to understand.) The high-level mental model you should have First of all, all the basic git things you\u2019re already familiar with are there in jj:\nCommits, branches, operations on those, all those things carry over, with some small differences. The main difference is in the general way the two work, jj simplifies git\u2019s model a lot by getting rid of some inconsistencies, and makes it much easier to understand what\u2019s going on \u201cunder the hood\u201d, because the \u201cunder the hood\u201d is now so much smaller and simpler, that it can just be over the hood. git The mental model that you probably have with git is something like an assembly line.\nYou take a bunch of components, you form them into a widget, you put the widget into a box, you write \u201cGeneral bug fixes\u201d onto the box, seal it, and send it off, never to be seen again by anyone. That\u2019s what git thinks of as a commit.\nYou have some work that is The Thing You\u2019re Working On Now, and then at some point that\u2019s kind of done, you select which pieces of that work you want to immortalize, and you commit them, freezing them in time forever from then on.\n(I know you can edit commits, but this is largely git\u2019s mental model, commits are immutable). Jujutsu Jujutsu, in contrast, is more like playing with Play-Doh.\nYou take a lump, cut it into two, shape one piece into something, give it a name, change your mind, give it another name, take a bit of the second piece and stick it on the first piece, and generally go back and forth all around your play area, making changes. Jujutsu wants you to be able to go back to an old commit, change it (gasp!), go to another branch (three commits back from that HEAD), change that commit too, move whole branches of your tree to other parts of it, whatever you want.\nYour worktree in Jujutsu is a free-for-all where you can rearrange things as you like. Madness, this cannot possibly work Yes yes, nobody wants their commits changing from under them, that\u2019s why Jujutsu doesn\u2019t let you easily change commits that have been pushed to a remote, you can relax now. However, if you spend a moment thinking about what I said above, you\u2019ll probably realize that a few things need to be different from git for this to work (and they are): Commits have to be mutable. Indeed, Jujutsu commits are mutable (until you push them).\nRight now you\u2019re thinking of commits as something that can\u2019t change, but this is one of the things you need to accept.\nYou can (and will) go back to a previous commit (that you haven\u2019t yet pushed) to fix a bug in it that you just hit, and it\u2019s as simple as checking out (jj calls it edit ing) that commit and making the change. You don\u2019t have to commit again! Jujutsu does whatever it needs to do under the hood when you run the jj command, to you it just looks like your edits are automatically persisted in the commit, in real time. To clarify, Jujutsu doesn\u2019t create new commits while this goes on, you just see one \u201copen\u201d commit that you keep making changes to your code in. If I can just go into a commit and edit it and jj auto-saves, there must not be a staging area. Indeed, there is no staging area like git has.\ngit splits code to either be in the repo (in a commit), or outside it (staged/unstaged). Jujutsu doesn\u2019t have that, you are always in a commit .\nThis is important: In git, you\u2019re outside a commit until you create one.\nIn Jujutsu, you are always inside a commit .\nNothing is ever outside a commit, \u201coutside a commit\u201d isn\u2019t a thing in Jujutsu. Even the very commit command in Jujutsu is an alias that adds a message to the commit you\u2019re on, and then creates a new (empty) one that you\u2019ll now be working on.\nEven when you create a new repo, you start in a commit. This is the most important difference between jj and git , and the one thing you should think a bit about, as it enables many really interesting workflows. Always being in a commit means that yes, you will have commits that are half-finished work.\nMaybe lots of them!\nI usually indicate this in the commit message, to remind myself. So commits might not have a commit message? You are impressively perceptive for a hypothetical straw man in whose mouth I\u2019m putting words.\nExactly, commits might not have a commit message.\nThey start out blank, and you can add a commit message at any point, whenever you have an idea of what that commit will do.\nIt might be when you start working on it, it might be half-way through, or it might be at the end.\nPersonally, I usually add the message at the end, but that\u2019s just preference. So there\u2019s no stashing either? Yes, since everything is always in a commit, there\u2019s nothing to stash. In git, if you have some uncommitted changes and want to check out an old commit, you need to stash them first.\nIn Jujutsu, since all your changes are automatically persisted in a commit at all times, you can have some new changes (which, if this were git, would be uncommitted), you can check out (or edit ) an older commit, then come back to your new changes in the latest commit, and they\u2019ll all be there. But then branches need to be lightweight. If you\u2019re going to be jumping around the tree all the time, making commits and branches, they can\u2019t require names.\nJujutsu lets you create branches by just creating a commit, you don\u2019t need to name the branch.\nIn Jujutsu (and in git!), branches are simply two or more commits with the same parent, it\u2019s just that git artificially makes you think of branches as special, because it makes you name them. In Jujutsu, creating a branch is as simple as checking out the commit you want to branch from, and creating a new commit on top of it.\nThis is one thing Jujutsu simplifies over git.\nIn git, branches are a fairly heavy thing, you have to name them, you have the mental model of \u201cbeing\u201d on the branch, and your workflow is centered around them.\nIn Jujutsu, you just\u2026 add a new commit, and if that commit has siblings, well, that\u2019s now a branch. Conflicts I haven\u2019t talked about conflicts much, because, unlike git, in practice they haven\u2019t really been anything special.\nJujutsu doesn\u2019t stop the world at all, it doesn\u2019t even particularly complain, it just marks a commit as conflicted, but you can continue working on other places in the worktree and then later come back at your leisure and fix that commit\u2019s conflicts! Whereas in git you have to quit what you\u2019re doing and fix the conflicts right now , jj is more \u201cby the way, when you have some time, let me know what this commit should look like*.\nThe changes also cascade to all subsequent commits, which is fantastic.\nYou only fix conflicts once, and jj takes care of the rest. Snapshots Under the hood, jj automatically and transparently commits whatever you\u2019re working on when you invoke the jj command (it can also be configured to do it on its own whenever a file in the repo changes).\nThis is safe, as these intermediate changes won\u2019t be pushed anywhere, but this means that you get snapshots for free! . If you\u2019ve ever had Claude get to a working solution, but then trip over itself and mess it up, jj can help, you can use the oplog to go back to the way your repo looked a few minutes ago, even if you didn\u2019t explicitly commit anything! Even using the status or log command to look at stuff will take a snapshot of your repo, allowing you to return to it if something goes wrong.\nNo more losing unstaged changes, ever! This has saved my ass a few times already. Questions and answers By now you probably have lots of questions, I\u2019ll try to answer some of them here.\nIf you have more questions, just send them to me and I\u2019ll add them here, along with the answer. How do I branch off main? You don\u2019t really branch off main, in that you usually won\u2019t need to create two commits off main, you\u2019ll only create one. git  (git-branch.png)   This is how git thinks of branches. You create a branch, and you're now in a special branch bit.  In git, we branch off of main, and now our mental model is that \u201cwe\u2019re in that branch\u201d.\nIn reality, if you look at the graph on the right, it\u2019s all still just a line, we\u2019ve just made a mental \u201cbend\u201d in the graph to tell ourselves that we\u2019re on a branch. As far as the graph is concerned, though, nothing special really actually happened, we just added more commits.\nThe only real difference is that \u201cmain\u201d stops at the third commit, whereas \u201cmy branch\u201d stops at the sixth commit.\nOther than that, the entire history is just one line. Jujutsu  (jj-branch.png)   This is how jj thinks of branches. The two graphs are equivalent, but you aren't anywhere special, `main` is just farther back.  Jujutsu, on the other hand, doesn\u2019t care what you think.\nIt only cares what parents, children, and siblings commits have. There are two reasons you might want to branch: History legitimately diverges into multiple directions, or You want to communicate to other people (or to yourself) that this part of the history is different (e.g. it contains some feature).\nThis is also the case when you want to create a new branch so you can open a PR for it.  To Jujutsu, this repo\u2019s history is a straight line, so there is no actual \u201cbranching\u201d. The only reason to have branches here is communication, so Jujutsu asks you to label the commits that you want on the branches yourself.\nYou can see these tags on the example on the right, and it\u2019s the same as the git example above.\nThere are still three commits in main , and three more in my branch . Jujutsu calls these labels \u201cbookmarks\u201d, and they correspond to whatever git uses to tag branches.\nBookmarks are what you\u2019ll tag your commits with to tell git what your branches are.  (legit-branch.png)   Here, the graph has actually branched, because `main` has one extra commit.  Continuing the earlier example, if we create a second commit off main, even if that\u2019s a merge commit (a commit with two parents) that\u2019s when the tree actually diverges.\nIn the graph on the right, the commit where we branched off now is a parent to two commits, and history is no longer linear.\nThis isn\u2019t special, it\u2019s just how things are, but this is what\u2019s actually a real \u201cbranch\u201d to Jujutsu. The way that git does things, ie creating a branch without history actually diverging, is just for us humans and our communication needs. Jujutsu doesn\u2019t require you to name its branches.\nYou can happily work without any branch names at all, and you can easily see what branch is for what from the commit descriptions.\nYou can name them, if you prefer, but you don\u2019t have to . This sounds a bit alien right now, but it\u2019s actually a really nice way to work. I\u2019m worried I\u2019ve lost you here, but it doesn\u2019t matter.\nYou\u2019ll understand all of this easily when you play around with the tree a bit in jjui. How do I add a commit message? You can add a commit message at any time to the current, using the describe command.\nYou can do this at any time, you can even go back to other commits and amend their messages (again with the describe command). How do I choose which of my changes to commit? You don\u2019t!\nEverything is already in a commit!\nWhat you do is you interactively select some of the changes in the current commit (whether this commit is blank/new or an old commit, it doesn\u2019t matter), and you split that commit into two. Jujutsu can also do this automatically!\nIf you have a commit with a bunch of small changes to various files, jj can absorb these changes into the closest ancestor commit where each thing changed.\nThis is pretty magical, as you can add a few one-liner bugfixes here and there, and jj will just automatically include them in the commits where those lines were touched. How do I check out a commit? Without getting too much into specifics, you just edit the commit you want.\nThis checks it out and you can make changes to it, however keep in mind that, if the commit was previously pushed to a remote, jj will give you a warning that you shouldn\u2019t change commits you\u2019ve pushed. jjui will make navigation around the repo really easy, so use it for checking out commits as well. How do I cherry-pick a commit onto another branch? You just\u2026 move it. In jjui, go to the commit you want to move, press r (for rebase ), go to the commit you want to move it after, press enter, and that\u2019s it. How do I reset soft/hard? There isn\u2019t really a soft reset, as there isn\u2019t a staging area for your changes to be reset in.\nSimply check out (edit ) the commit you want to edit, that\u2019s a soft reset in Jujutsu. For a hard reset (ie to throw away a commit), you abandon that commit.\njjui will, again, make it much easier to do this. What if I make a mistake? No matter what you do, you can undo it.\nNot just changes, but any jj operation, you can undo rebases, pulls, anything. You can also use the oplog (again, jjui makes this really easy) to go back to how the whole repo looked at any point in time.\nDon\u2019t be afraid to try things, with jj it\u2019s really easy to undo any mistake. How do I amend a commit? Simply edit it and make the changes you want. How do I move unstaged changes from one branch to another? There are no unstaged changes in jj.\nAll changes are in a commit, if you want to move the changes in your current commit to another branch, simply move your current commit to the target branch by rebasing.\nI can never remember what \u201crebase X onto Y\u201d does, so just move the commit with your changes to be a child of your branch\u2019s tip (again, use jjui for this). How do I open a PR on GitHub? To do that, you need to push a new branch.\nGo to the commit you want to push, then probably create a new one on top of that (I tend to create a new commit when I\u2019m done with an old one, just so I\u2019m remember I\u2019m done, but this is personal preference).\nThen, bookmark that commit with the branch name you want to give your PR, and push the commit along with the bookmark. That\u2019s all, now you can open the PR. Here, jj exposes the low-level operations much more than git:\nYou need to move the bookmark on your own to the commit you want to push (git does that automatically for you), and you need to push the bookmark manually as well.\nThis is very helpful for understanding how things work under the hood, but usually you\u2019ll set a jj alias to do this in one step. Personally, I have an alias (which I\u2019ll include below) to find the bookmark name, move it to the latest commit, and push. My aliases Here\u2019s my alias config:  [aliases] init  =  [\"git\", \"init\", \"--colocate\"] ps  =  [\"util\", \"exec\", \"--\", \"bash\", \"-c\", \"\"\" set -e # Check if current commit has both description and changes has_description = $(jj log -r @ --no-graph --color never -T 'description' | grep -q . && echo \"yes\" || echo \"no\") # Use 'empty' template keyword to check if commit has changes has_changes = $(jj log -r @ --no-graph --color never -T 'empty' | grep -q \"false\" && echo \"yes\" || echo \"no\") if [ \"$has_description\"  =  \"yes\" ] && [ \"$has_changes\" = \"yes\" ] ; then  echo \"Current commit has description and changes, creating new commit...\"  jj new fi # Get the bookmark from the parent commit directly bookmark = $(jj log -r 'ancestors(@) & bookmarks()' -n 1 --no-graph --color never -T 'bookmarks' | sed 's/\\\\*$//' | tr -d ' ') if [ -z \"$bookmark\" ]; then  echo \"No bookmark found on parent commit\"  exit 1 fi echo \"Moving bookmark '$bookmark' to parent commit and pushing...\" jj bookmark set \"$bookmark\" -r @- jj git fetch jj git push --bookmark \"$bookmark\" --allow-new \"\"\"] cma  =  [\"commit\", \"-m\"]   This means I can jj init to add jj to a git repo, and jj cma \"message\" to describe the current commit and create a new one on top of it (that\u2019s what commit does under the hood). jj ps is a convenience alias that: Looks backward in history Finds the last bookmark there (if this were git, this would be my branch name) Checks if the current commit has changes in it If it does, it creates a new commit Moves the bookmark to the parent commit (the one I was on before I ran the command) Fetches changes from upstream (to update my tree) Pushes the changes to the remote  I use this a lot! Epilogue Jujutsu doesn\u2019t do anything that git can\u2019t do, but it removes so much friction that you\u2019ll actually end up doing things all the time that git could do, but that were so fiddly with git that you never actually did them. Creating a branch for a minute just to try an idea out even though you\u2019re in the middle of some changes, going back to a previous commit to add a line you forgot, moving commits around the tree, all of these things are so easy that they\u2019re now actually your everyday workflow . With git, I never used to switch branches in the middle of work, because I was too worried that stashing multiple things onto the stack would eat my work.\nI\u2019d never go back to a previous commit and amend it, because here be dragons.\nI was extremely afraid of rebasing because I always got one conflict per commit and had to unconflict the same thing fifty times. Jujutsu gives you the confidence and understanding to do all of these things, and if you fuck something up (which I haven\u2019t yet, miraculously!) the oplog is right there to fix everything to how it was 30 seconds ago. I hope this tutorial made sense, but I\u2019m worried it didn\u2019t.\nPlease contact me on (https://x.com/intent/user?screen_name=Stavros) Twitter or (https://bsky.app/profile/stavros.io) Bluesky , or email me directly, if you have feedback or corrections.      Subscribe to my mailing list Did you like what you just read and want to be notified when I post more? Subscribe\n        to my mailing list to get an email whenever I post. (Email) ()  (Subscribe)    (https://twitter.com/intent/tweet?text=Switch%20to%20Jujutsu%20already%3A%20a%20tutorial&url=https%3A//www.stavros.io/posts/switch-to-jujutsu-already-a-tutorial/&via=stavros) (Tweet this)  Tweet   (https://www.facebook.com/sharer/sharer.php?u=https%3A//www.stavros.io/posts/switch-to-jujutsu-already-a-tutorial/) (Share on Facebook)  Share   (https://www.linkedin.com/cws/share?url=https%3A//www.stavros.io/posts/switch-to-jujutsu-already-a-tutorial/) (Share on LinkedIn)  Share   (http://reddit.com/submit?url=https%3A//www.stavros.io/posts/switch-to-jujutsu-already-a-tutorial/&title=Switch%20to%20Jujutsu%20already%3A%20a%20tutorial) (Share on reddit)  Share      Stavros A simple man  Greek. Amateur F1 driver. Technology enthusiast. Single parent. Liar.  Founder of (http://www.stochastic.io) Stochastic Technologies , a\n                            software development agency, and creator of various products which you can\n                            find in the (http://resume.stavros.io) r\u00e9sum\u00e9 .   Connect with me (mailto:hi@stavros.io?subject=Your article: Switch to Jujutsu already: a tutorial) (Email me)   (/feed/short/) (RSS feed)   (https://mastodon.social/@stavros) (Mastodon)    (https://twitter.com/Stavros) (Twitter)   (https://github.com/skorokithakis/) (Github)   (https://gitlab.com/stavros/) (Gitlab)   (https://portfolio.stavros.io/) (Photography portfolio)      This site is part of the webring:  (https://en.wikipedia.org/wiki/Webring) (What's this?) ? (https://webring.stavros.io) Tech makers  (https://webring.stavros.io/prev)  Previous (https://webring.stavros.io/random) \ud83d\ude0e Random (https://webring.stavros.io/next) Next     Recent Posts (/posts/switch-to-jujutsu-already-a-tutorial/) (Switch to Jujutsu already: a tutorial) Switch to Jujutsu already: a tutorial  (/posts/really-small-led-panel/) (I made a really small LED panel) I made a really small LED panel  (/posts/making-a-trmnl-device/) (I couldn't wait for a TRMNL device, so I made my own) I couldn't wait for a TRMNL device, so I made my own  (/posts/why-is-everything-so-scalable/) (Why is everything so scalable?) Why is everything so scalable?  (/posts/making-the-strofara/) (Making the Strofara) Making the Strofara  (/posts/saving-ssh-passphrases-on-kde/) (Saving SSH passphrases on KDE) Saving SSH passphrases on KDE  (/posts/the-ux-people/) (The UX people) The UX people  (/posts/spam-spammers-back/) (Spam spammers back) Spam spammers back  (/posts/use-your-wii-balance-board-as-a-scale-again/) (Use your Wii Balance Board as a scale (again)) Use your Wii Balance Board as a scale (again)  (/posts/clearing-up-some-passkeys-misconceptions/) (Clearing up some misconceptions about passkeys) Clearing up some misconceptions about passkeys        Made with \u2665 in Greece       ()  ()                 "
                ],
                "output": "htmltotext.txt",
                "pwd": "/data/archive/1760332083.525186",
                "schema": "ArchiveResult",
                "start_ts": "2025-10-13T05:08:42.583993+00:00",
                "status": "succeeded"
            }
        ],
        "media": [
            {
                "cmd": [
                    "/usr/local/bin/yt-dlp",
                    "--restrict-filenames",
                    "--trim-filenames",
                    "128",
                    "--write-description",
                    "--write-info-json",
                    "--write-annotations",
                    "--write-thumbnail",
                    "--no-call-home",
                    "--write-sub",
                    "--write-auto-subs",
                    "--convert-subs=srt",
                    "--yes-playlist",
                    "--continue",
                    "--no-abort-on-error",
                    "--ignore-errors",
                    "--geo-bypass",
                    "--add-metadata",
                    "--format=(bv*+ba/b)[filesize<=750m][filesize_approx<=?750m]/(bv*+ba/b)",
                    "--skip-download",
                    "--cache-dir=/data/yt-dlp-cache/",
                    "--cookies=/data/yt-dlp-cache/cookies.txt",
                    "--proxy=socks5://tor-socks-proxy:9150",
                    "--no-playlist",
                    "https://www.stavros.io/posts/switch-to-jujutsu-already-a-tutorial/"
                ],
                "cmd_version": "2024.10.7",
                "end_ts": "2025-10-13T05:08:52.241714+00:00",
                "index_texts": [],
                "output": "media/",
                "pwd": "/data/archive/1760332083.525186",
                "schema": "ArchiveResult",
                "start_ts": "2025-10-13T05:08:44.561836+00:00",
                "status": "succeeded"
            }
        ],
        "mercury": [
            {
                "cmd": [
                    "/home/archivebox/.npm/bin/postlight-parser",
                    "https://www.stavros.io/posts/switch-to-jujutsu-already-a-tutorial/"
                ],
                "cmd_version": "2.2.3",
                "end_ts": "2025-10-13T05:08:42.421907+00:00",
                "index_texts": null,
                "output": "mercury/",
                "pwd": "/data/archive/1760332083.525186",
                "schema": "ArchiveResult",
                "start_ts": "2025-10-13T05:08:35.502280+00:00",
                "status": "succeeded"
            }
        ],
        "pdf": [],
        "readability": [
            {
                "cmd": [
                    "/home/archivebox/.npm/bin/readability-extractor",
                    "/tmp/tmp290cjvf3",
                    "https://www.stavros.io/posts/switch-to-jujutsu-already-a-tutorial/"
                ],
                "cmd_version": "0.0.11",
                "end_ts": "2025-10-13T05:08:26.271334+00:00",
                "index_texts": [
                    "If you don't like Jujutsu, you're wrongAs all developers, I\u2019ve been using git since the dawn of time, since its commands were an inscrutable jumble of ill-fitting incantations, and it has remained this way until today.\nNeedless to say, I just don\u2019t get git.\nI never got it, even though I\u2019ve read a bunch of stuff on how it represents things internally.\nI\u2019ve been using it for years knowing what a few commands do, and whenever it gets into a weird state because I fat-fingered something, I have my trusty alias, fuckgit, that deletes the .git directory, clones the repo again into a temp folder, and moves the .git directory from that into my directory, and I\u2019ve managed to eke out a living for my family this way.\nOver the past few years, I\u2019ve been seeing people rave about Jujutsu, and I always wanted to try it, but it never seemed worth the trouble, even though I hate git.\nI idly read a few tutorials, trying to understand how it works, but in the end I decided it wasn\u2019t for me.\nOne day I randomly decided to try again, but this time I asked Claude how to do with Jujutsu whatever operation I wanted to do with git.\nThat\u2019s when the mental model of jj clicked for me, and I finally understood everything, including how git works.\nI never thought a VCS would spark joy in me, but here we are, and I figured maybe I can write something that will make jj click for you as well.\nIt also doesn\u2019t hurt that Jujutsu is completely interoperable with git (and thus with providers like GitHub), and I can have all the power of Jujutsu locally on my git repos, without anyone knowing I\u2019m not actually using git.\nThe problem\nThe problem I had with the other tutorials, without realizing it, was that there was a fundamental tension between two basic things:\nThe best way to explain jj to someone who knows git is to use all the git terms they already know (because that makes it easy for them), but also to tell them to think about the git terms they know differently (because otherwise they\u2019ll form the wrong mental model).\nYou can\u2019t really explain something by saying \u201ca jj commit is like a git commit, except where it\u2019s not\u201d, so I\u2019ll try to do things a bit differently.\nThis will be a short post (or, at least, not as long as other jj tutorials), I\u2019ll explain the high-level mental model you should have, and then give a FAQ for how to do various git things with jj.\nWarnings\nJust a disclaimer before we start, this is going to be far from an exhaustive reference.\nI\u2019m not an expert in either git or Jujutsu, but I know enough to hopefully make jj click for you enough to learn the rest on your own, so don\u2019t be too annoyed if I omit something.\nAlso, you\u2019re going to read here some things about the way Jujutsu likes doing things that will offend you to your very core, and your first reaction will be \u201cmadness, this cannot possibly work\u201d.\nWhen you think this, I want you to relax, it\u2019s fine, it does work, it just means I haven\u2019t managed to make the whole thing click together for you yet.\nJust read on.\nI\u2019m not going to show you any Jujutsu commands here.\nI might refer to them by name, but I want you to understand the mental model enough to go look stuff up on your own, Jujutsu only has, like, three commands you\u2019re going to use for everything anyway (yes, you can do everything you do with git with them).\n(By the way, if you\u2019re going to be trying things out while reading this post, definitely get jjui, it lets you visually work with the repository in a way that makes everything much easier to understand.)\nThe high-level mental model you should have\nFirst of all, all the basic git things you\u2019re already familiar with are there in jj:\nCommits, branches, operations on those, all those things carry over, with some small differences.\nThe main difference is in the general way the two work, jj simplifies git\u2019s model a lot by getting rid of some inconsistencies, and makes it much easier to understand what\u2019s going on \u201cunder the hood\u201d, because the \u201cunder the hood\u201d is now so much smaller and simpler, that it can just be over the hood.\ngit\nThe mental model that you probably have with git is something like an assembly line.\nYou take a bunch of components, you form them into a widget, you put the widget into a box, you write \u201cGeneral bug fixes\u201d onto the box, seal it, and send it off, never to be seen again by anyone.\nThat\u2019s what git thinks of as a commit.\nYou have some work that is The Thing You\u2019re Working On Now, and then at some point that\u2019s kind of done, you select which pieces of that work you want to immortalize, and you commit them, freezing them in time forever from then on.\n(I know you can edit commits, but this is largely git\u2019s mental model, commits are immutable).\nJujutsu\nJujutsu, in contrast, is more like playing with Play-Doh.\nYou take a lump, cut it into two, shape one piece into something, give it a name, change your mind, give it another name, take a bit of the second piece and stick it on the first piece, and generally go back and forth all around your play area, making changes.\nJujutsu wants you to be able to go back to an old commit, change it (gasp!), go to another branch (three commits back from that HEAD), change that commit too, move whole branches of your tree to other parts of it, whatever you want.\nYour worktree in Jujutsu is a free-for-all where you can rearrange things as you like.\nMadness, this cannot possibly work\nYes yes, nobody wants their commits changing from under them, that\u2019s why Jujutsu doesn\u2019t let you easily change commits that have been pushed to a remote, you can relax now.\nHowever, if you spend a moment thinking about what I said above, you\u2019ll probably realize that a few things need to be different from git for this to work (and they are):\nCommits have to be mutable.\nIndeed, Jujutsu commits are mutable (until you push them).\nRight now you\u2019re thinking of commits as something that can\u2019t change, but this is one of the things you need to accept.\nYou can (and will) go back to a previous commit (that you haven\u2019t yet pushed) to fix a bug in it that you just hit, and it\u2019s as simple as checking out (jj calls it editing) that commit and making the change.\nYou don\u2019t have to commit again!\nJujutsu does whatever it needs to do under the hood when you run the jj command, to you it just looks like your edits are automatically persisted in the commit, in real time.\nTo clarify, Jujutsu doesn\u2019t create new commits while this goes on, you just see one \u201copen\u201d commit that you keep making changes to your code in.\nIf I can just go into a commit and edit it and jj auto-saves, there must not be a staging area.\nIndeed, there is no staging area like git has.\ngit splits code to either be in the repo (in a commit), or outside it (staged/unstaged).\nJujutsu doesn\u2019t have that, you are always in a commit.\nThis is important: In git, you\u2019re outside a commit until you create one.\nIn Jujutsu, you are always inside a commit.\nNothing is ever outside a commit, \u201coutside a commit\u201d isn\u2019t a thing in Jujutsu.\nEven the very commit command in Jujutsu is an alias that adds a message to the commit you\u2019re on, and then creates a new (empty) one that you\u2019ll now be working on.\nEven when you create a new repo, you start in a commit.\nThis is the most important difference between jj and git, and the one thing you should think a bit about, as it enables many really interesting workflows.\nAlways being in a commit means that yes, you will have commits that are half-finished work.\nMaybe lots of them!\nI usually indicate this in the commit message, to remind myself.\nSo commits might not have a commit message?\nYou are impressively perceptive for a hypothetical straw man in whose mouth I\u2019m putting words.\nExactly, commits might not have a commit message.\nThey start out blank, and you can add a commit message at any point, whenever you have an idea of what that commit will do.\nIt might be when you start working on it, it might be half-way through, or it might be at the end.\nPersonally, I usually add the message at the end, but that\u2019s just preference.\nSo there\u2019s no stashing either?\nYes, since everything is always in a commit, there\u2019s nothing to stash.\nIn git, if you have some uncommitted changes and want to check out an old commit, you need to stash them first.\nIn Jujutsu, since all your changes are automatically persisted in a commit at all times, you can have some new changes (which, if this were git, would be uncommitted), you can check out (or edit) an older commit, then come back to your new changes in the latest commit, and they\u2019ll all be there.\nBut then branches need to be lightweight.\nIf you\u2019re going to be jumping around the tree all the time, making commits and branches, they can\u2019t require names.\nJujutsu lets you create branches by just creating a commit, you don\u2019t need to name the branch.\nIn Jujutsu (and in git!), branches are simply two or more commits with the same parent, it\u2019s just that git artificially makes you think of branches as special, because it makes you name them.\nIn Jujutsu, creating a branch is as simple as checking out the commit you want to branch from, and creating a new commit on top of it.\nThis is one thing Jujutsu simplifies over git.\nIn git, branches are a fairly heavy thing, you have to name them, you have the mental model of \u201cbeing\u201d on the branch, and your workflow is centered around them.\nIn Jujutsu, you just\u2026 add a new commit, and if that commit has siblings, well, that\u2019s now a branch.\nConflicts\nI haven\u2019t talked about conflicts much, because, unlike git, in practice they haven\u2019t really been anything special.\nJujutsu doesn\u2019t stop the world at all, it doesn\u2019t even particularly complain, it just marks a commit as conflicted, but you can continue working on other places in the worktree and then later come back at your leisure and fix that commit\u2019s conflicts!\nWhereas in git you have to quit what you\u2019re doing and fix the conflicts right now, jj is more \u201cby the way, when you have some time, let me know what this commit should look like*.\nThe changes also cascade to all subsequent commits, which is fantastic.\nYou only fix conflicts once, and jj takes care of the rest.\nSnapshots\nUnder the hood, jj automatically and transparently commits whatever you\u2019re working on when you invoke the jj command (it can also be configured to do it on its own whenever a file in the repo changes).\nThis is safe, as these intermediate changes won\u2019t be pushed anywhere, but this means that you get snapshots for free!.\nIf you\u2019ve ever had Claude get to a working solution, but then trip over itself and mess it up, jj can help, you can use the oplog to go back to the way your repo looked a few minutes ago, even if you didn\u2019t explicitly commit anything!\nEven using the status or log command to look at stuff will take a snapshot of your repo, allowing you to return to it if something goes wrong.\nNo more losing unstaged changes, ever!\nThis has saved my ass a few times already.\nQuestions and answers\nBy now you probably have lots of questions, I\u2019ll try to answer some of them here.\nIf you have more questions, just send them to me and I\u2019ll add them here, along with the answer.\nHow do I branch off main?\nYou don\u2019t really branch off main, in that you usually won\u2019t need to create two commits off main, you\u2019ll only create one.\ngit\nThis is how git thinks of branches. You create a branch, and you're now in a special branch bit.In git, we branch off of main, and now our mental model is that \u201cwe\u2019re in that branch\u201d.\nIn reality, if you look at the graph on the right, it\u2019s all still just a line, we\u2019ve just made a mental \u201cbend\u201d in the graph to tell ourselves that we\u2019re on a branch.\nAs far as the graph is concerned, though, nothing special really actually happened, we just added more commits.\nThe only real difference is that \u201cmain\u201d stops at the third commit, whereas \u201cmy branch\u201d stops at the sixth commit.\nOther than that, the entire history is just one line.\nJujutsu\nThis is how jj thinks of branches. The two graphs are equivalent, but you aren't anywhere special, `main` is just farther back.Jujutsu, on the other hand, doesn\u2019t care what you think.\nIt only cares what parents, children, and siblings commits have.\nThere are two reasons you might want to branch:\n\nHistory legitimately diverges into multiple directions, or\nYou want to communicate to other people (or to yourself) that this part of the history is different (e.g. it contains some feature).\nThis is also the case when you want to create a new branch so you can open a PR for it.\n\nTo Jujutsu, this repo\u2019s history is a straight line, so there is no actual \u201cbranching\u201d. The only reason to have branches here is communication, so Jujutsu asks you to label the commits that you want on the branches yourself.\nYou can see these tags on the example on the right, and it\u2019s the same as the git example above.\nThere are still three commits in main, and three more in my branch.\nJujutsu calls these labels \u201cbookmarks\u201d, and they correspond to whatever git uses to tag branches.\nBookmarks are what you\u2019ll tag your commits with to tell git what your branches are.\nHere, the graph has actually branched, because `main` has one extra commit.Continuing the earlier example, if we create a second commit off main, even if that\u2019s a merge commit (a commit with two parents) that\u2019s when the tree actually diverges.\nIn the graph on the right, the commit where we branched off now is a parent to two commits, and history is no longer linear.\nThis isn\u2019t special, it\u2019s just how things are, but this is what\u2019s actually a real \u201cbranch\u201d to Jujutsu.\nThe way that git does things, ie creating a branch without history actually diverging, is just for us humans and our communication needs.\nJujutsu doesn\u2019t require you to name its branches.\nYou can happily work without any branch names at all, and you can easily see what branch is for what from the commit descriptions.\nYou can name them, if you prefer, but you don\u2019t have to.\nThis sounds a bit alien right now, but it\u2019s actually a really nice way to work.\nI\u2019m worried I\u2019ve lost you here, but it doesn\u2019t matter.\nYou\u2019ll understand all of this easily when you play around with the tree a bit in jjui.\nHow do I add a commit message?\nYou can add a commit message at any time to the current, using the describe command.\nYou can do this at any time, you can even go back to other commits and amend their messages (again with the describe command).\nHow do I choose which of my changes to commit?\nYou don\u2019t!\nEverything is already in a commit!\nWhat you do is you interactively select some of the changes in the current commit (whether this commit is blank/new or an old commit, it doesn\u2019t matter), and you split that commit into two.\nJujutsu can also do this automatically!\nIf you have a commit with a bunch of small changes to various files, jj can absorb these changes into the closest ancestor commit where each thing changed.\nThis is pretty magical, as you can add a few one-liner bugfixes here and there, and jj will just automatically include them in the commits where those lines were touched.\nHow do I check out a commit?\nWithout getting too much into specifics, you just edit the commit you want.\nThis checks it out and you can make changes to it, however keep in mind that, if the commit was previously pushed to a remote, jj will give you a warning that you shouldn\u2019t change commits you\u2019ve pushed.\njjui will make navigation around the repo really easy, so use it for checking out commits as well.\nHow do I cherry-pick a commit onto another branch?\nYou just\u2026 move it. In jjui, go to the commit you want to move, press r (for rebase), go to the commit you want to move it after, press enter, and that\u2019s it.\nHow do I reset soft/hard?\nThere isn\u2019t really a soft reset, as there isn\u2019t a staging area for your changes to be reset in.\nSimply check out (edit) the commit you want to edit, that\u2019s a soft reset in Jujutsu.\nFor a hard reset (ie to throw away a commit), you abandon that commit.\njjui will, again, make it much easier to do this.\nWhat if I make a mistake?\nNo matter what you do, you can undo it.\nNot just changes, but any jj operation, you can undo rebases, pulls, anything.\nYou can also use the oplog (again, jjui makes this really easy) to go back to how the whole repo looked at any point in time.\nDon\u2019t be afraid to try things, with jj it\u2019s really easy to undo any mistake.\nHow do I amend a commit?\nSimply edit it and make the changes you want.\nHow do I move unstaged changes from one branch to another?\nThere are no unstaged changes in jj.\nAll changes are in a commit, if you want to move the changes in your current commit to another branch, simply move your current commit to the target branch by rebasing.\nI can never remember what \u201crebase X onto Y\u201d does, so just move the commit with your changes to be a child of your branch\u2019s tip (again, use jjui for this).\nHow do I open a PR on GitHub?\nTo do that, you need to push a new branch.\nGo to the commit you want to push, then probably create a new one on top of that (I tend to create a new commit when I\u2019m done with an old one, just so I\u2019m remember I\u2019m done, but this is personal preference).\nThen, bookmark that commit with the branch name you want to give your PR, and push the commit along with the bookmark.\nThat\u2019s all, now you can open the PR.\nHere, jj exposes the low-level operations much more than git:\nYou need to move the bookmark on your own to the commit you want to push (git does that automatically for you), and you need to push the bookmark manually as well.\nThis is very helpful for understanding how things work under the hood, but usually you\u2019ll set a jj alias to do this in one step.\nPersonally, I have an alias (which I\u2019ll include below) to find the bookmark name, move it to the latest commit, and push.\nMy aliases\nHere\u2019s my alias config:\n[aliases]\ninit = [\"git\", \"init\", \"--colocate\"]\nps = [\"util\", \"exec\", \"--\", \"bash\", \"-c\", \"\"\"\nset -e\n\n# Check if current commit has both description and changes\nhas_description=$(jj log -r @ --no-graph --color never -T 'description' | grep -q . && echo \"yes\" || echo \"no\")\n# Use 'empty' template keyword to check if commit has changes\nhas_changes=$(jj log -r @ --no-graph --color never -T 'empty' | grep -q \"false\" && echo \"yes\" || echo \"no\")\n\nif [ \"$has_description\" = \"yes\" ] && [ \"$has_changes\" = \"yes\" ]; then\n    echo \"Current commit has description and changes, creating new commit...\"\n    jj new\nfi\n\n# Get the bookmark from the parent commit directly\nbookmark=$(jj log -r 'ancestors(@) & bookmarks()' -n 1 --no-graph --color never -T 'bookmarks' | sed 's/\\\\*$//' | tr -d ' ')\n\nif [ -z \"$bookmark\" ]; then\n    echo \"No bookmark found on parent commit\"\n    exit 1\nfi\n\necho \"Moving bookmark '$bookmark' to parent commit and pushing...\"\njj bookmark set \"$bookmark\" -r @-\njj git fetch\njj git push --bookmark \"$bookmark\" --allow-new\n\"\"\"]\ncma = [\"commit\", \"-m\"]\n\nThis means I can jj init to add jj to a git repo, and jj cma \"message\" to describe the current commit and create a new one on top of it (that\u2019s what commit does under the hood).\njj ps is a convenience alias that:\n\nLooks backward in history\nFinds the last bookmark there (if this were git, this would be my branch name)\nChecks if the current commit has changes in it\nIf it does, it creates a new commit\nMoves the bookmark to the parent commit (the one I was on before I ran the command)\nFetches changes from upstream (to update my tree)\nPushes the changes to the remote\n\nI use this a lot!\nEpilogue\nJujutsu doesn\u2019t do anything that git can\u2019t do, but it removes so much friction that you\u2019ll actually end up doing things all the time that git could do, but that were so fiddly with git that you never actually did them.\nCreating a branch for a minute just to try an idea out even though you\u2019re in the middle of some changes, going back to a previous commit to add a line you forgot, moving commits around the tree, all of these things are so easy that they\u2019re now actually your everyday workflow.\nWith git, I never used to switch branches in the middle of work, because I was too worried that stashing multiple things onto the stack would eat my work.\nI\u2019d never go back to a previous commit and amend it, because here be dragons.\nI was extremely afraid of rebasing because I always got one conflict per commit and had to unconflict the same thing fifty times.\nJujutsu gives you the confidence and understanding to do all of these things, and if you fuck something up (which I haven\u2019t yet, miraculously!) the oplog is right there to fix everything to how it was 30 seconds ago.\nI hope this tutorial made sense, but I\u2019m worried it didn\u2019t.\nPlease contact me on Twitter or Bluesky, or email me directly, if you have feedback or corrections."
                ],
                "output": "readability/",
                "pwd": "/data/archive/1760332083.525186",
                "schema": "ArchiveResult",
                "start_ts": "2025-10-13T05:08:23.815083+00:00",
                "status": "succeeded"
            }
        ],
        "screenshot": [],
        "singlefile": [],
        "title": [
            {
                "cmd": [
                    "/usr/bin/curl",
                    "--silent",
                    "--location",
                    "--compressed",
                    "--proxy",
                    "socks5://tor-socks-proxy:9150",
                    "--max-time",
                    "60",
                    "--user-agent",
                    "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/128.0.0.0 Safari/537.36 ArchiveBox/{VERSION} (+https://github.com/ArchiveBox/ArchiveBox/)",
                    "https://www.stavros.io/posts/switch-to-jujutsu-already-a-tutorial/"
                ],
                "cmd_version": "8.10.1",
                "end_ts": "2025-10-13T05:08:20.777338+00:00",
                "index_texts": null,
                "output": "Switch to Jujutsu already: a tutorial - Stavros' Stuff",
                "pwd": "/data/archive/1760332083.525186",
                "schema": "ArchiveResult",
                "start_ts": "2025-10-13T05:08:20.750041+00:00",
                "status": "succeeded"
            }
        ],
        "wget": []
    },
    "icons": null,
    "is_archived": true,
    "is_static": false,
    "latest": {
        "archive_org": "ArchiveError: Failed to find \"content-location\" URL header in Archive.org response.",
        "dom": "output.html",
        "favicon": "favicon.ico",
        "git": null,
        "media": "media/",
        "pdf": null,
        "screenshot": null,
        "singlefile": null,
        "title": "Switch to Jujutsu already: a tutorial - Stavros' Stuff",
        "warc": null,
        "wget": null
    },
    "link_dir": "/data/archive/1760332083.525186",
    "newest_archive_date": "2025-10-13T05:08:52.350818+00:00",
    "num_failures": 1,
    "num_outputs": 8,
    "oldest_archive_date": "2025-10-13T05:08:05.475735+00:00",
    "path": "/posts/switch-to-jujutsu-already-a-tutorial/",
    "schema": "Link",
    "scheme": "https",
    "snapshot_abid": "snp_01K7DZFWB700A08DA101NPST7T",
    "snapshot_id": "6e1a4ca6-38aa-4c08-9415-1055eb6ce8fa",
    "sources": [
        "/data/sources/1760332082-import.txt"
    ],
    "tags": null,
    "tags_str": "",
    "timestamp": "1760332083.525186",
    "title": "Switch to Jujutsu already: a tutorial - Stavros' Stuff",
    "url": "https://www.stavros.io/posts/switch-to-jujutsu-already-a-tutorial/"
}