Radish alpha
r
rad:z371PVmDHdjJucejRoRYJcDEvD5pp
Radicle website including documentation and guides
Radicle
Git
blog: Jujutsu + Radicle = ❤️
Fintan Halpenny committed 8 months ago
commit 9e985935c988be10d3de9464af5025fa8b051104
parent 38d6dd2
2 files changed +575 -0
added _posts/2025-08-14-jujutsu-with-radicle.md
@@ -0,0 +1,574 @@
+
---
+
title: "Jujutsu + Radicle = ❤️"
+
subtitle: "How I use Jujutsu in tandem with Radicle"
+
author: "fintohaps"
+
authorUrl: "https://app.radicle.xyz/nodes/seed.radicle.garden/users/did:key:z6MkireRatUThvd3qzfKht1S44wpm4FEWSSa4PRMTSQZ3voM"
+
layout: "blog"
+
---
+

+
Roughly a year ago at the first ever [Local First Conference], a friend and
+
previous colleague – [Alex Good] – told me about this tool called
+
`jj` ([Jujutsu][jj]). We did the usual thing and I sat down beside him as he
+
explained it to me. My brain did the usual thing and took in some of the
+
information but not enough of it, and so I didn't touch `jj` for quite some time
+
after that – but what's good enough for Alex Good is good enough for me.
+

+
After that, I feel like I saw a post about `jj` once every couple of months on
+
Hacker News – confirmation bias anyone? It was a constant talking point during
+
Git Merge 2024, and now it's a third Git tool that uses the concept of change
+
identifiers, so it's a talking point on the [Git mailing list][git-list-change-id-topic].
+

+
So, fast-forward a year or so, and I've been using `jj` for quite some time
+
while contributing to and maintaining the `heartwood` repository – the home of
+
the Radicle protocol – as well as some others. Did I have to convince my whole
+
team that `jj` should be used by all of us and we all switch to this new
+
workflow? No. The first piece of "magic" of `jj` is that it is essentially a
+
version control system that has a transparent layer on top of Git itself. A
+
change in `jj` will always point to a Git commit. The beauty of its
+
implementation is that the underlying commit can change as much as it wants,
+
while the `jj` change remains the same. This unlocks a lot of nice flows for
+
managing changes using `jj`.
+

+
So, you must be wondering by now, "How do I blend Radicle with `jj`?" Well,
+
let's dance between the three worlds of `jj`, Git, and Radicle, to see how they
+
have melted together to form a beautiful (_almost_) branch-less workflow.
+

+
### Radicle and Git
+

+
I won't spend too much time here, but if you don't know by now, Radicle works on
+
top of Git to allow people to use this ubiquitous tool, while we benefit from
+
its storage and protocol. When you start a Radicle repository, it's essentially
+
a Git repository where we use some special references and extension points of
+
Git to cryptographically secure your commits, and store all your
+
[social, collaborative artifacts][guide-user-cobs]. If you haven't yet, go
+
[download] Radicle and try it yourself using our [guides].
+

+
Note that if you're already familiar with `jj` this might not be that
+
interesting for you, and you can skip to [User Config](#user-config).
+

+
#### My `.git/config`
+

+
As a maintainer of a few repositories using Radicle, I naturally need to push to
+
and fetch from the repository in Radicle [storage][rip-storage]. This means
+
that I'll need a remote – this is set up for you when you run `rad init` or `rad
+
clone`. This looks like:
+

+
```ini
+
[remote "rad"]
+
	url = rad://z371PVmDHdjJucejRoRYJcDEvD5pp
+
	fetch = +refs/heads/*:refs/remotes/rad/*
+
	fetch = +refs/tags/*:refs/remotes/rad/tags/*
+
	pushurl = rad://z371PVmDHdjJucejRoRYJcDEvD5pp/z6MkireRatUThvd3qzfKht1S44wpm4FEWSSa4PRMTSQZ3voM
+
[branch "master"]
+
	remote = rad
+
	merge = refs/heads/master
+
```
+

+
The `rad://` URL tells `git` which [remote helper][git-remote-helpers] to use
+
by trying to find `git-remote-rad`. This will handle fetching/pushing from/to
+
the repository identified by `z371PVmDHdjJucejRoRYJcDEvD5pp`. The string
+
`z6MkireRatUThvd3qzfKht1S44wpm4FEWSSa4PRMTSQZ3voM` is my Node ID, and
+
identifies my machine
+
which makes sure that when I push, my references get stored under that
+
[namespace][rip-storage-namespace]. Then when have the usual upstream branch setup
+
for `master` for the `rad` remote – you may be familiar with this Git config entry
+
when you have your `origin` set up for another Git forge.
+

+
There's one last piece of the puzzle in config that is an alias for easily
+
creating a Radicle [patch][guide-user-patch].
+

+
```ini
+
[alias]
+
    patch = push rad HEAD:refs/patches
+
```
+

+
When you push to the special reference `refs/patches`, the remote helper will
+
catch this and create a new patch for you, and in this case it will use whatever
+
`HEAD` is for the head of the patch. Note that it will use whatever `rad/master`
+
is as the base of the patch – that is to say, whatever commits are between
+
`rad/master` and `HEAD` (including `HEAD`) are the commits being proposed by the
+
patch. So, whenever I'm ready to make a patch, I use `git patch` and my
+
`$EDITOR` pops open to make my well-crafted message describing what changes I'm
+
making.
+

+
#### `git fetch rad` and `git push rad`
+

+
This is going to be brief. All I do with `git` now is `git fetch rad` (or my
+
peer's remotes) to fetch any new work in Radicle storage. For pushing I will use
+
`git push rad` to create or update patches (coming up), update my version of
+
`master`, and, on the rare occasion, push a branch. That's it! No more `commit`,
+
no more `rebase`, no more `merge` – ok I still use `git log` – but that's pretty
+
much it. So how did I ditch all of these commands? Let's take a look `jj`.
+

+
### Jujutsu and Git
+

+
Let's see how I'm using `jj` by visiting several of its commands and seeing how
+
I can use them in different scenarios.
+

+
#### `jj new`
+

+
It's only natural to start off with `jj new`. This command creates a new change
+
in `jj`, as well as creating a new, empty commit for that change. Whenever I'm
+
going to make a new change that's based on the `master` branch, I run:
+

+
<pre class="wide">
+
$ jj new master@rad
+
Working copy  (@) now at: <span style="font-weight:bold;"></span><span style="font-weight:bold;filter: contrast(70%) brightness(190%);color:purple;">qx</span><span style="font-weight:bold;filter: contrast(70%) brightness(190%);color:dimgray;">uvyurn</span><span style="font-weight:bold;"> </span><span style="font-weight:bold;filter: contrast(70%) brightness(190%);color:blue;">8e</span><span style="font-weight:bold;filter: contrast(70%) brightness(190%);color:dimgray;">711a87</span><span style="font-weight:bold;"> </span><span style="font-weight:bold;filter: contrast(70%) brightness(190%);color:green;">(empty)</span><span style="font-weight:bold;"> </span><span style="font-weight:bold;filter: contrast(70%) brightness(190%);color:green;">(no description set)</span>
+
Parent commit (@-)      : <span style="font-weight:bold;"></span><span style="font-weight:bold;color:purple;">xsl</span><span style="filter: contrast(70%) brightness(190%);color:dimgray;">qmmsl</span> <span style="font-weight:bold;"></span><span style="font-weight:bold;color:blue;">62</span><span style="filter: contrast(70%) brightness(190%);color:dimgray;">cdaf6d</span> <span style="color:purple;">master@rad</span><span style="filter: contrast(70%) brightness(190%);color:dimgray;"> | </span>deployment: Vercel → Cloudflare Workers
+
Added 0 files, modified 0 files, removed 1 files
+
</pre>
+

+
You'll notice that `jj` spits out a Change ID and a Commit ID. You may also
+
notice that a prefix is highlighted – this is the unique prefix for the change
+
and the commit at this time! Which means that I can use `qx` or `8e` to refer to
+
this particular change or commit without any ambiguity; an amazing UX, if you
+
ask me.
+

+
At this point, I might know what I'm going to be working on so I use `jj
+
describe` to give this change a message.
+

+
<pre class="wide">
+
$ jj describe -m <span style="color:green;">"blog: Radicle and JJ"</span>
+
Working copy  (@) now at: <span style="font-weight:bold;"></span><span style="font-weight:bold;filter: contrast(70%) brightness(190%);color:purple;">qx</span><span style="font-weight:bold;filter: contrast(70%) brightness(190%);color:dimgray;">uvyurn</span><span style="font-weight:bold;"> </span><span style="font-weight:bold;filter: contrast(70%) brightness(190%);color:blue;">40</span><span style="font-weight:bold;filter: contrast(70%) brightness(190%);color:dimgray;">8133a5</span><span style="font-weight:bold;"> </span><span style="font-weight:bold;filter: contrast(70%) brightness(190%);color:green;">(empty)</span><span style="font-weight:bold;"> blog: Radicle and JJ</span>
+
Parent commit (@-)      : <span style="font-weight:bold;"></span><span style="font-weight:bold;color:purple;">xsl</span><span style="filter: contrast(70%) brightness(190%);color:dimgray;">qmmsl</span> <span style="font-weight:bold;"></span><span style="font-weight:bold;color:blue;">62</span><span style="filter: contrast(70%) brightness(190%);color:dimgray;">cdaf6d</span> <span style="color:purple;">master@rad</span><span style="filter: contrast(70%) brightness(190%);color:dimgray;"> | </span>deployment: Vercel → Cloudflare Workers
+
</pre>
+

+
I've now changed the description so that it no longer says `(no description
+
yet)`, and it now reads `blog: Radicle and JJ`.
+

+
So let's see what we have here:
+

+
<pre class="wide">
+
$ jj show qx
+
Commit ID: <span style="color:blue;">408133a5e54c80d2398be0c78cccabbd6063902d</span>
+
Change ID: <span style="color:purple;">qxuvyurnqsvupzlpzsvzzpqlmlqvoxwq</span>
+
Author   : <span style="color:olive;">Fintan Halpenny</span> &lt;<span style="color:olive;">fintan.halpenny@radicle.xyz</span>&gt; (<span style="color:teal;">2025-06-10 07:52:34</span>)
+
Committer: <span style="color:olive;">Fintan Halpenny</span> &lt;<span style="color:olive;">fintan.halpenny@radicle.xyz</span>&gt; (<span style="color:teal;">2025-06-10 07:52:34</span>)
+

+
    blog: Radicle and JJ
+
</pre>
+

+
We can see that it looks similar to a Git commit, which we can also inspect
+
using:
+

+
<pre class="wide">
+
$ git show 408133a5e54c80d2398be0c78cccabbd6063902d
+
<span style="color:olive;">commit 408133a5e54c80d2398be0c78cccabbd6063902d</span>
+
Author: Fintan Halpenny &lt;fintan.halpenny@radicle.xyz&gt;
+
Date:   2025-06-10 07:52:34 +0200
+

+
    blog: Radicle and JJ
+
</pre>
+

+
This leaves us in a position to do our usual changes within our working copy of
+
the Git repository.
+

+
At any point where I'm looking to separate changes, I can use `jj new` again,
+
specifying any change to make a new change after the given change:
+

+
<pre class="wide">
+
$ jj new qx
+
Working copy  (@) now at: <span style="font-weight:bold;"></span><span style="font-weight:bold;filter: contrast(70%) brightness(190%);color:purple;">w</span><span style="font-weight:bold;filter: contrast(70%) brightness(190%);color:dimgray;">msmovxx</span><span style="font-weight:bold;"> </span><span style="font-weight:bold;filter: contrast(70%) brightness(190%);color:blue;">c5</span><span style="font-weight:bold;filter: contrast(70%) brightness(190%);color:dimgray;">0301c1</span><span style="font-weight:bold;"> </span><span style="font-weight:bold;filter: contrast(70%) brightness(190%);color:green;">(empty)</span><span style="font-weight:bold;"> </span><span style="font-weight:bold;filter: contrast(70%) brightness(190%);color:green;">(no description set)</span>
+
Parent commit (@-)      : <span style="font-weight:bold;"></span><span style="font-weight:bold;color:purple;">qx</span><span style="filter: contrast(70%) brightness(190%);color:dimgray;">uvyurn</span> <span style="font-weight:bold;"></span><span style="font-weight:bold;color:blue;">40</span><span style="filter: contrast(70%) brightness(190%);color:dimgray;">8133a5</span> blog: Radicle and JJ
+
</pre>
+

+
<pre class="wide">
+
$ jj describe -m <span style="color:green;">"blog: Radicle an JJ - add body"</span>
+
Working copy  (@) now at: <span style="font-weight:bold;"></span><span style="font-weight:bold;filter: contrast(70%) brightness(190%);color:purple;">w</span><span style="font-weight:bold;filter: contrast(70%) brightness(190%);color:dimgray;">msmovxx</span><span style="font-weight:bold;"> </span><span style="font-weight:bold;filter: contrast(70%) brightness(190%);color:blue;">a3</span><span style="font-weight:bold;filter: contrast(70%) brightness(190%);color:dimgray;">d195ad</span><span style="font-weight:bold;"> </span><span style="font-weight:bold;filter: contrast(70%) brightness(190%);color:green;">(empty)</span><span style="font-weight:bold;"> blog: Radicle and JJ – add body</span>
+
Parent commit (@-)      : <span style="font-weight:bold;"></span><span style="font-weight:bold;color:purple;">qx</span><span style="filter: contrast(70%) brightness(190%);color:dimgray;">uvyurn</span> <span style="font-weight:bold;"></span><span style="font-weight:bold;color:blue;">40</span><span style="filter: contrast(70%) brightness(190%);color:dimgray;">8133a5</span> blog: Radicle and JJ
+
</pre>
+

+
If I ever think I'm about to make some changes before the change I'm on, then I
+
can use the `-B` option:
+

+
<pre class="wide">
+
$ jj new -B @
+
Rebased 1 descendant commits
+
Working copy  (@) now at: <span style="font-weight:bold;"></span><span style="font-weight:bold;filter: contrast(70%) brightness(190%);color:purple;">zv</span><span style="font-weight:bold;filter: contrast(70%) brightness(190%);color:dimgray;">rmpyox</span><span style="font-weight:bold;"> </span><span style="font-weight:bold;filter: contrast(70%) brightness(190%);color:blue;">f0</span><span style="font-weight:bold;filter: contrast(70%) brightness(190%);color:dimgray;">635336</span><span style="font-weight:bold;"> </span><span style="font-weight:bold;filter: contrast(70%) brightness(190%);color:green;">(empty)</span><span style="font-weight:bold;"> </span><span style="font-weight:bold;filter: contrast(70%) brightness(190%);color:green;">(no description set)</span>
+
Parent commit (@-)      : <span style="font-weight:bold;"></span><span style="font-weight:bold;color:purple;">xsl</span><span style="filter: contrast(70%) brightness(190%);color:dimgray;">qmmsl</span> <span style="font-weight:bold;"></span><span style="font-weight:bold;color:blue;">62</span><span style="filter: contrast(70%) brightness(190%);color:dimgray;">cdaf6d</span> <span style="color:purple;">master@rad</span><span style="filter: contrast(70%) brightness(190%);color:dimgray;"> | </span>deployment: Vercel → Cloudflare Workers
+
Added 0 files, modified 0 files, removed 1 files
+
</pre>
+

+
#### `jj edit`
+

+
At any point in time, I can also decide to go back to an old change and edit it,
+
specifying the change that I want to edit:
+

+
<pre class="wide">
+
$ jj edit qx
+
Working copy  (@) now at: <span style="font-weight:bold;"></span><span style="font-weight:bold;filter: contrast(70%) brightness(190%);color:purple;">qx</span><span style="font-weight:bold;filter: contrast(70%) brightness(190%);color:dimgray;">uvyurn</span><span style="font-weight:bold;"> </span><span style="font-weight:bold;filter: contrast(70%) brightness(190%);color:blue;">40</span><span style="font-weight:bold;filter: contrast(70%) brightness(190%);color:dimgray;">8133a5</span><span style="font-weight:bold;"> blog: Radicle and JJ</span>
+
Parent commit (@-)      : <span style="font-weight:bold;"></span><span style="font-weight:bold;color:purple;">xsl</span><span style="filter: contrast(70%) brightness(190%);color:dimgray;">qmmsl</span> <span style="font-weight:bold;"></span><span style="font-weight:bold;color:blue;">62</span><span style="filter: contrast(70%) brightness(190%);color:dimgray;">cdaf6d</span> <span style="color:purple;">master@rad</span><span style="filter: contrast(70%) brightness(190%);color:dimgray;"> | </span>deployment: Vercel → Cloudflare Workers
+
</pre>
+

+
You can now forget about all those `fixup!` commits you were making to add
+
changes into previous commits. No longer are you at the mercy of making a commit
+
that is ahead of some other changes and you need to reorder it using `git
+
rebase`. You taste that? It tastes like victory...
+

+
#### `jj squash`
+

+
Ok, so you've made some changes that are not related to the current change? This
+
happens, or at least it does to me – I'm not perfect, (un)fortunately. I can use
+
the power of `jj new`, whether after or before the current change, and combine
+
it with `jj squash`:
+

+
<pre class="wide">
+
$ jj squash -u --from w --to qx
+
Rebased 1 descendant commits
+
Working copy  (@) now at: <span style="font-weight:bold;"></span><span style="font-weight:bold;filter: contrast(70%) brightness(190%);color:purple;">qx</span><span style="font-weight:bold;filter: contrast(70%) brightness(190%);color:dimgray;">uvyurn</span><span style="font-weight:bold;"> </span><span style="font-weight:bold;filter: contrast(70%) brightness(190%);color:blue;">1e</span><span style="font-weight:bold;filter: contrast(70%) brightness(190%);color:dimgray;">2b0ccc</span><span style="font-weight:bold;"> </span><span style="font-weight:bold;filter: contrast(70%) brightness(190%);color:green;">(empty)</span><span style="font-weight:bold;"> blog: Radicle and JJ</span>
+
Parent commit (@-)      : <span style="font-weight:bold;"></span><span style="font-weight:bold;color:purple;">xsl</span><span style="filter: contrast(70%) brightness(190%);color:dimgray;">qmmsl</span> <span style="font-weight:bold;"></span><span style="font-weight:bold;color:blue;">62</span><span style="filter: contrast(70%) brightness(190%);color:dimgray;">cdaf6d</span> <span style="color:purple;">master@rad</span><span style="filter: contrast(70%) brightness(190%);color:dimgray;"> | </span>deployment: Vercel → Cloudflare Workers
+
</pre>
+

+
This says that I'm squashing the changes from the change identified by `r` into
+
the change `xn`, and I want to keep the description of `xn` and drop the
+
description of `r` (the `-u` option).
+

+
For extra points, `jj` even includes the beautiful `-i` option for _choosing_
+
which changes you're taking from the source change – via a TUI. I cannot
+
begin to describe how useful this is for moving around file changes and keeping
+
my history clean and linear.
+

+
#### `jj rebase`
+

+
The final piece of the puzzle, at least for my workflow, is `jj rebase`. I can
+
move around changes and put them on top of a destination change:
+

+
<pre class="wide">
+
$ jj rebase -d qx -r sm
+
Working copy  (@) now at: <span style="font-weight:bold;"></span><span style="font-weight:bold;filter: contrast(70%) brightness(190%);color:purple;">sm</span><span style="font-weight:bold;filter: contrast(70%) brightness(190%);color:dimgray;">vvuqzo</span><span style="font-weight:bold;"> </span><span style="font-weight:bold;filter: contrast(70%) brightness(190%);color:blue;">42</span><span style="font-weight:bold;filter: contrast(70%) brightness(190%);color:dimgray;">0180e8</span> blog: relevant blog material
+
Parent commit (@-)      : <span style="font-weight:bold;"></span><span style="font-weight:bold;color:purple;">qx</span><span style="filter: contrast(70%) brightness(190%);color:dimgray;">uvyurn</span> <span style="font-weight:bold;"></span><span style="font-weight:bold;color:blue;">1e</span><span style="filter: contrast(70%) brightness(190%);color:dimgray;">2b0ccc</span> blog: Radicle and JJ
+
Added 1 files, modified 0 files, removed 0 files
+
</pre>
+

+
This rebases the change `sm` onto the change `qx`. In fact, the `-r` can take a
+
set of changes (see [revsets][jj-revsets]) and graft them all on top of the
+
destination.
+

+
#### My `.jj/config`
+

+
The final part I'll touch on is my `jj` config, which can be split into the user
+
and repo config. Thanks to Bruno, who wrote a lot of this on Zulip, and I
+
cribbed it from him.
+

+
##### User Config
+

+
Here is my user config, and we'll discuss a couple of the entries, and I'll
+
leave the rest as homework.
+

+
```toml
+
[aliases]
+
dlog = ["log", "-r"]
+
l = ["log", "-r", "(trunk()..@):: | (trunk()..@)-"]
+
fresh = ["new", "trunk()"]
+
tug = [
+
    "bookmark",
+
    "move",
+
    "--from",
+
    "closest_bookmark(@)",
+
    "--to",
+
    "closest_pushable(@)",
+
]
+

+
[revset-aliases]
+
"closest_bookmark(to)" = "heads(::to & bookmarks())"
+
"closest_pushable(to)" = "heads(::to & mutable() & ~description(exact:\"\") & (~empty() | merges()))"
+
"desc(x)" = "description(x)"
+
"pending()" = ".. ~ ::tags() ~ ::remote_bookmarks() ~ @ ~ private()"
+
"private()" = "description(glob:'wip:*') | \
+
    description(glob:'private:*') | \
+
    description(glob:'WIP:*') | \
+
    description(glob:'PRIVATE:*') | \
+
    conflicts() | \
+
    (empty() ~ merges()) | \
+
    description('substring-i:\"DO NOT MAIL\"')"
+
```
+

+
- `fresh`: this allows me to have an alias for `jj new master@rad` and use `jj
+
  fresh`.
+
- `tug`: this allows me to tug the closest [bookmark][jj-bookmarks] to a change
+
  that can be pushed – we'll see an example of this later.
+

+
##### Repository Config
+

+
And here is my repository config, which we'll discuss a bit more in detail.
+

+
```toml
+
[revset-aliases]
+
"trunk()" = "master@rad"
+
"immutable_heads()" = "present(trunk()) | \
+
    tags() | \
+
    ( \
+
        untracked_remote_bookmarks() ~ \
+
        untracked_remote_bookmarks(remote='rad') ~ \
+
        untracked_remote_bookmarks(regex:'^patch(es)/',remote='rad') \
+
    )"
+

+
[git]
+
write-change-id-header = true
+
```
+

+
We want to change the `trunk()` alias from its default in `jj` so that it points
+
to `master@rad`, the default branch in this particular Radicle repository. The
+
`trunk()` revset is used in a few place, for example, we saw it above in
+
`fresh`, but it is also in the next revset alias.
+

+
Some changes in `jj` will be marked as [immutable][jj-immutables-heads]. `jj`
+
will prevent you from changing certain changes if they are marked as immutable,
+
and its default value for this can be very restrictive, so instead we change it
+
here. First we mark changes that are `present` in `trunk()` or `tags()` as
+
immutable. Then we have untracked remote bookmarks with the set difference
+
operator `~`. What are not marking as immutable are bookmarks that are in `rad`
+
or that `patch`/`patches`. That is, if the changes are ours or from patches,
+
then they're safe to edit. You might think, "Why are patches safe?"" Well, let's
+
finally get into Radicle and Jujutsu.
+

+
### Radicle and Jujutsu
+

+
So here we are, a lot of build up to get to the point where I can describe how I
+
can avoid using branches (as much as possible).
+

+
#### Contributing Patches
+

+
We will first dive into contributing a new patch using Radicle. As described in
+
[Jujutsu and Git](#jujutsu-and-git), I can start making a set of changes using
+
`jj new`, editing them just how I like using `jj edit`, and ordering them just
+
the way I want with `jj rebase` and `jj squash`. During this whole time, I'm in
+
that, initially scary, [detached HEAD state][detached-head]. Here it comes,
+
we're going to make a patch!
+

+
##### Creating a New Patch
+

+
```
+
git patch
+
```
+

+
That's it. Well, the `$EDITOR` opens and I write a title and a body describing
+
my wonderful changes, and when I'm done, the remote helper will create the patch
+
and announce it to the network.
+

+
<pre class="wide">
+
<span style="color:green;">✓</span> Patch <span style="color:teal;">e5f0a5a5adaa33c3b931235967e4930ece9bb617</span> opened
+
<span style="color:green;">✓</span> Synced with <span style="color:green;">8</span> node(s)
+

+
To rad://z3cyotNHuasWowQ2h4yF9c3tFFdvc/z6MkvZwzK64f3GuDcAs6dEcje89ddfHkBjS1v9Dkh7aCGq3C
+
 * [new reference]   HEAD -&gt; refs/patches
+
</pre>
+

+

+
##### Updating a Patch
+

+
Let's be honest though, my wonderful changes are rarely wonderful from the
+
get-go. They need some polishing, and my peers always have great suggestions
+
that I should integrate into the patch.
+

+
From here, I can find the patch using `rad patch`:
+

+
<pre class="wide">
+
$ rad patch
+
<span style="color:#2a2a2a;">╭</span><span style="color:#2a2a2a;">───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────</span><span style="color:#2a2a2a;">╮</span>
+
<span style="color:#2a2a2a;">│ </span>●  <span style="font-weight:bold;">ID</span>       <span style="font-weight:bold;">Title</span>                                                  <span style="font-weight:bold;">Author</span>                          <span style="font-weight:bold;">Reviews</span>    <span style="font-weight:bold;">Head</span>     <span style="font-weight:bold;">+</span>      <span style="font-weight:bold;">-</span>      <span style="font-weight:bold;">Updated</span>     <span style="color:#2a2a2a;"> │</span>
+
<span style="color:#2a2a2a;">├</span><span style="color:#2a2a2a;">───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────</span><span style="color:#2a2a2a;">┤</span>
+
<span style="color:#2a2a2a;">│ </span><span style="color:green;">●</span>  <span style="color:teal;">18a71ad</span>  radicle-cli: Warn when using old names of nodes        <span style="color:purple;">self</span>           <span style="font-style:italic;color:purple;">(you)</span>            - - - - -  <span style="color:blue;">552f4af</span>  <span style="color:green;">+146</span>   <span style="color:red;">-3</span>     <span style="font-style:italic;">4 days ago</span>  <span style="color:#2a2a2a;"> │</span>
+
<span style="color:#2a2a2a;">│ </span><span style="color:green;">●</span>  <span style="color:teal;">ed450c9</span>  node, profile, ssh: Make key location configurable     <span style="color:purple;">self</span>           <span style="font-style:italic;color:purple;">(you)</span>            - - - - -  <span style="color:blue;">d2f7b89</span>  <span style="color:green;">+376</span>   <span style="color:red;">-74</span>    <span style="font-style:italic;">1 month ago</span> <span style="color:#2a2a2a;"> │</span>
+
<span style="color:#2a2a2a;">│ </span><span style="color:green;">●</span>  <span style="color:teal;">12bc851</span>  node, cli: Refactor test environment                   <span style="color:purple;">self</span>           <span style="font-style:italic;color:purple;">(you)</span>            - - - - -  <span style="color:blue;">d059957</span>  <span style="color:green;">+826</span>   <span style="color:red;">-1214</span>  <span style="font-style:italic;">1 month ago</span> <span style="color:#2a2a2a;"> │</span>
+
<span style="color:#2a2a2a;">│ </span><span style="color:green;">●</span>  <span style="color:teal;">3219ef8</span>  Remove predefined bootstrap nodes                      <span style="color:purple;">istankovic</span>     <span style="color:purple;">z6MkmiJ…mkTV5sS</span>  - - - - -  <span style="color:blue;">7322e3a</span>  <span style="color:green;">+138</span>   <span style="color:red;">-108</span>   <span style="font-style:italic;">2 days ago</span>  <span style="color:#2a2a2a;"> │</span>
+
<span style="color:#2a2a2a;">│ </span><span style="color:green;">●</span>  <span style="color:teal;">058586b</span>  Suggest the git configured default branch during init  <span style="color:purple;">stemporus</span>      <span style="color:purple;">z6MkqLa…jr8xo5K</span>  - - - - -  <span style="color:blue;">6a1147f</span>  <span style="color:green;">+16</span>    <span style="color:red;">-8</span>     <span style="font-style:italic;">2 weeks ago</span> <span style="color:#2a2a2a;"> │</span>
+
<span style="color:#2a2a2a;">│ </span><span style="color:green;">●</span>  <span style="color:teal;">1015e51</span>  build: Rewrite tagging script                          <span style="color:purple;">fintohaps</span>      <span style="color:purple;">z6Mkire…SQZ3voM</span>  - - - - -  <span style="color:blue;">149de0b</span>  <span style="color:green;">+24</span>    <span style="color:red;">-12</span>    <span style="font-style:italic;">3 weeks ago</span> <span style="color:#2a2a2a;"> │</span>
+
<span style="color:#2a2a2a;">│ </span><span style="color:green;">●</span>  <span style="color:teal;">e85ff9a</span>  node: clean up `UploadError`                           <span style="color:purple;">fintohaps</span>      <span style="color:purple;">z6Mkire…SQZ3voM</span>  - - - - -  <span style="color:blue;">b408e44</span>  <span style="color:green;">+15</span>    <span style="color:red;">-13</span>    <span style="font-style:italic;">3 weeks ago</span> <span style="color:#2a2a2a;"> │</span>
+
<span style="color:#2a2a2a;">│ </span><span style="color:green;">●</span>  <span style="color:teal;">c54883e</span>  Canonical References                                   <span style="color:purple;">fintohaps</span>      <span style="color:purple;">z6Mkire…SQZ3voM</span>  - - - - -  <span style="color:blue;">34014a6</span>  <span style="color:green;">+4642</span>  <span style="color:red;">-1575</span>  <span style="font-style:italic;">1 month ago</span> <span style="color:#2a2a2a;"> │</span>
+
<span style="color:#2a2a2a;">│ </span><span style="color:green;">●</span>  <span style="color:teal;">e500399</span>  radicle: improve inline comments                       <span style="color:purple;">fintohaps</span>      <span style="color:purple;">z6Mkire…SQZ3voM</span>  - - - - -  <span style="color:blue;">e7cab63</span>  <span style="color:green;">+924</span>   <span style="color:red;">-244</span>   <span style="font-style:italic;">1 month ago</span> <span style="color:#2a2a2a;"> │</span>
+
<span style="color:#2a2a2a;">│ </span><span style="color:green;">●</span>  <span style="color:teal;">6080c3c</span>  Add issue instructions                                 <span style="color:purple;">yorgos-laptop</span>  <span style="color:purple;">z6MkrnX…CPFSFS3</span>  - - - - -  <span style="color:blue;">1877285</span>  <span style="color:green;">+32</span>    <span style="color:red;">-15</span>    <span style="font-style:italic;">1 month ago</span> <span style="color:#2a2a2a;"> │</span>
+
<span style="color:#2a2a2a;">│ </span><span style="color:green;">●</span>  <span style="color:teal;">40a8d72</span>  radicle: introduce COB stream                          <span style="color:purple;">fintohaps</span>      <span style="color:purple;">z6Mkire…SQZ3voM</span>  - - - - -  <span style="color:blue;">ec00acb</span>  <span style="color:green;">+1178</span>  <span style="color:red;">-9</span>     <span style="font-style:italic;">4 months ago</span><span style="color:#2a2a2a;"> │</span>
+
<span style="color:#2a2a2a;">│ </span><span style="color:green;">●</span>  <span style="color:teal;">8ab3f9c</span>  Add document on how to implement a new COB type        <span style="color:purple;">liw</span>            <span style="color:purple;">z6MkgEM…1b2w2FV</span>  - - - - -  <span style="color:blue;">5a3b095</span>  <span style="color:green;">+314</span>   <span style="color:red;">-0</span>     <span style="font-style:italic;">1 year ago</span>  <span style="color:#2a2a2a;"> │</span>
+
<span style="color:#2a2a2a;">╰</span><span style="color:#2a2a2a;">───────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────</span><span style="color:#2a2a2a;">╯</span>
+
</pre>
+

+
Let's say I received feedback on my `Canonical References` patch, I can use its
+
`ID`, the shortened version above, to inspect it:
+

+
<pre class="wide">
+
$ rad patch show c54883e
+
<span style="color:#2a2a2a;">╭</span><span style="color:#2a2a2a;">──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────</span><span style="color:#2a2a2a;">╮</span>
+
<span style="color:#2a2a2a;">│ </span><span style="color:teal;">Title</span>     <span style="font-weight:bold;">Canonical References</span>                                                                                                                  <span style="color:#2a2a2a;"> │</span>
+
<span style="color:#2a2a2a;">│ </span><span style="color:teal;">Patch</span>     c54883e5ffb1f8a99f432e3ac79c0b728cd0dab3                                                                                              <span style="color:#2a2a2a;"> │</span>
+
<span style="color:#2a2a2a;">│ </span><span style="color:teal;">Author</span>    <span style="color:purple;">fintohaps</span> <span style="color:purple;">z6Mkire…SQZ3voM</span>                                                                                                             <span style="color:#2a2a2a;"> │</span>
+
<span style="color:#2a2a2a;">│ </span><span style="color:teal;">Head</span>      <span style="color:blue;">34014a67b0ddc859d95e17ffc71c1ae61aff5758</span>                                                                                              <span style="color:#2a2a2a;"> │</span>
+
<span style="color:#2a2a2a;">│ </span><span style="color:teal;">Branches</span>  <span style="color:olive;">patch/c54883e, sync-goal</span>                                                                                                              <span style="color:#2a2a2a;"> │</span>
+
<span style="color:#2a2a2a;">│ </span><span style="color:teal;">Commits</span>   ahead <span style="color:green;">6</span>, behind <span style="color:red;">49</span>                                                                                                                    <span style="color:#2a2a2a;"> │</span>
+
<span style="color:#2a2a2a;">│ </span><span style="color:teal;">Status</span>    <span style="color:green;">open</span>                                                                                                                                  <span style="color:#2a2a2a;"> │</span>
+
<span style="color:#2a2a2a;">│ </span>                                                                                                                                                <span style="color:#2a2a2a;"> │</span>
+
<span style="color:#2a2a2a;">│ </span>See RIP-0004[^0] for the specification.                                                                                                         <span style="color:#2a2a2a;"> │</span>
+
<span style="color:#2a2a2a;">│ </span>                                                                                                                                                <span style="color:#2a2a2a;"> │</span>
+
<span style="color:#2a2a2a;">│ </span>This patch is an implementation of RIP-0004. It implements the rules mechanism                                                                  <span style="color:#2a2a2a;"> │</span>
+
<span style="color:#2a2a2a;">│ </span>within the `rules` module. This is interplays with the existing `canonical`                                                                     <span style="color:#2a2a2a;"> │</span>
+
<span style="color:#2a2a2a;">│ </span>mechanisms, already defined (but slightly refactored).                                                                                          <span style="color:#2a2a2a;"> │</span>
+
<span style="color:#2a2a2a;">│ </span>                                                                                                                                                <span style="color:#2a2a2a;"> │</span>
+
<span style="color:#2a2a2a;">│ </span>The `rules` are then used in pushing and fetching references. A test is added to                                                                <span style="color:#2a2a2a;"> │</span>
+
<span style="color:#2a2a2a;">│ </span>illustrate the canonical references in action via tags.                                                                                         <span style="color:#2a2a2a;"> │</span>
+
<span style="color:#2a2a2a;">│ </span>                                                                                                                                                <span style="color:#2a2a2a;"> │</span>
+
<span style="color:#2a2a2a;">│ </span>There were some incidental changes that were made to ensure the tags use case is                                                                <span style="color:#2a2a2a;"> │</span>
+
<span style="color:#2a2a2a;">│ </span>easy for users. The first change was to add a tags refspec to remotes in order                                                                  <span style="color:#2a2a2a;"> │</span>
+
<span style="color:#2a2a2a;">│ </span>to easily fetch tags from peers -- as well ensuring those tags do not pollute                                                                   <span style="color:#2a2a2a;"> │</span>
+
<span style="color:#2a2a2a;">│ </span>the `refs/tags` namespace in the working copy.                                                                                                  <span style="color:#2a2a2a;"> │</span>
+
<span style="color:#2a2a2a;">│ </span>                                                                                                                                                <span style="color:#2a2a2a;"> │</span>
+
<span style="color:#2a2a2a;">│ </span>This had a knock on change where there was a bug `libgit2` that didn't allow for                                                                <span style="color:#2a2a2a;"> │</span>
+
<span style="color:#2a2a2a;">│ </span>deleting `multivar` entries, which the new remote setup fell under. This was                                                                    <span style="color:#2a2a2a;"> │</span>
+
<span style="color:#2a2a2a;">│ </span>fixed and so we update to `git2-0.19`.                                                                                                          <span style="color:#2a2a2a;"> │</span>
+
<span style="color:#2a2a2a;">│ </span>                                                                                                                                                <span style="color:#2a2a2a;"> │</span>
+
<span style="color:#2a2a2a;">│ </span>As well this, the `rad id update` command would error if the payload identifier                                                                 <span style="color:#2a2a2a;"> │</span>
+
<span style="color:#2a2a2a;">│ </span>was not the project identifier. This would stop adding new payloads to extend                                                                   <span style="color:#2a2a2a;"> │</span>
+
<span style="color:#2a2a2a;">│ </span>the identity -- which was needed for introducing canonical references.                                                                          <span style="color:#2a2a2a;"> │</span>
+
<span style="color:#2a2a2a;">│ </span>                                                                                                                                                <span style="color:#2a2a2a;"> │</span>
+
<span style="color:#2a2a2a;">│ </span>[^0]:                                                                                                                                           <span style="color:#2a2a2a;"> │</span>
+
<span style="color:#2a2a2a;">│ </span>https://app.radicle.xyz/nodes/seed.radicle.garden/rad:z3trNYnLWS11cJWC6BbxDs5niGo82/patches/1d1ce874f7c39ecdcd8c318bbae46ffd02fe1ea8?tab=changes<span style="color:#2a2a2a;"> │</span>
+
<span style="color:#2a2a2a;">├</span><span style="color:#2a2a2a;">──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────</span><span style="color:#2a2a2a;">┤</span>
+
<span style="color:#2a2a2a;">│ </span><span style="color:blue;">34014a6</span> radicle: refactor rule matching                                                                                                         <span style="color:#2a2a2a;"> │</span>
+
<span style="color:#2a2a2a;">│ </span><span style="color:blue;">0e0b77e</span> radicle: add canonical refs to identity                                                                                                 <span style="color:#2a2a2a;"> │</span>
+
<span style="color:#2a2a2a;">│ </span><span style="color:blue;">bbe019c</span> radicle: canonical reference rules                                                                                                      <span style="color:#2a2a2a;"> │</span>
+
<span style="color:#2a2a2a;">│ </span><span style="color:blue;">b3ad6f2</span> radicle: refactor Canonical                                                                                                             <span style="color:#2a2a2a;"> │</span>
+
<span style="color:#2a2a2a;">│ </span><span style="color:blue;">04277b4</span> radicle: store threshold in Canonical                                                                                                   <span style="color:#2a2a2a;"> │</span>
+
<span style="color:#2a2a2a;">│ </span><span style="color:blue;">312c6a4</span> meta: relax radicle-git dependencies                                                                                                    <span style="color:#2a2a2a;"> │</span>
+
<span style="color:#2a2a2a;">├</span><span style="color:#2a2a2a;">──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────</span><span style="color:#2a2a2a;">┤</span>
+
<span style="color:#2a2a2a;">│ </span><span style="color:green;">●</span> opened by <span style="color:purple;">fintohaps</span> <span style="color:purple;">z6Mkire…SQZ3voM</span> <span style="color:blue;">(3e97837)</span> 10 months ago                                                                                   <span style="color:#2a2a2a;"> │</span>
+
<span style="color:#2a2a2a;">│ </span><span style="color:teal;">↑</span> updated to c1a2cc5787f44c0a835c1deae375be04c399dd7e <span style="color:blue;">(58e932c)</span> 9 months ago                                                                    <span style="color:#2a2a2a;"> │</span>
+
<span style="color:#2a2a2a;">│ </span><span style="color:teal;">↑</span> updated to c55494efc2e780cd6c91a1f90efdae8a3eb1c7ef <span style="color:blue;">(1b07774)</span> 8 months ago                                                                    <span style="color:#2a2a2a;"> │</span>
+
<span style="color:#2a2a2a;">│ </span><span style="color:teal;">↑</span> updated to 583e6b3366c36cc7e67910c29a66750397a60484 <span style="color:blue;">(fdd5277)</span> 7 months ago                                                                    <span style="color:#2a2a2a;"> │</span>
+
<span style="color:#2a2a2a;">│ </span><span style="color:teal;">↑</span> updated to d54ddef216909bdd3e54e33e4f82c45df79c00d3 <span style="color:blue;">(f24f9d8)</span> 7 months ago                                                                    <span style="color:#2a2a2a;"> │</span>
+
<span style="color:#2a2a2a;">│ </span><span style="color:teal;">↑</span> updated to ac48ae6e75d4eaa13daed657eed24dfeabb9be94 <span style="color:blue;">(7d8e461)</span> 7 months ago                                                                    <span style="color:#2a2a2a;"> │</span>
+
<span style="color:#2a2a2a;">│ </span><span style="color:teal;">↑</span> updated to 2b31e460db7451376dc3e346ee02b5fd597fa5c6 <span style="color:blue;">(040cfb7)</span> 7 months ago                                                                    <span style="color:#2a2a2a;"> │</span>
+
<span style="color:#2a2a2a;">│ </span><span style="color:teal;">↑</span> updated to e1c360a1311a0a215bed6eb42e4b0c8c5c44e611 <span style="color:blue;">(f0dec88)</span> 6 months ago                                                                    <span style="color:#2a2a2a;"> │</span>
+
<span style="color:#2a2a2a;">│ </span><span style="color:teal;">↑</span> updated to 492cfbafd31e4bac85ee73af519ddc6254b47f82 <span style="color:blue;">(f9cb27f)</span> 4 months ago                                                                    <span style="color:#2a2a2a;"> │</span>
+
<span style="color:#2a2a2a;">│ </span><span style="color:teal;">↑</span> updated to fbdf18d7683bdac7a76149777eed5cf9bbbf5bd5 <span style="color:blue;">(2a64755)</span> 4 months ago                                                                    <span style="color:#2a2a2a;"> │</span>
+
<span style="color:#2a2a2a;">│ </span><span style="color:teal;">↑</span> updated to 4baf32afd65f2c4b374d8f21fed6877aa804a003 <span style="color:blue;">(0cecae6)</span> 4 months ago                                                                    <span style="color:#2a2a2a;"> │</span>
+
<span style="color:#2a2a2a;">│ </span>  └─ ⋄ reviewed by <span style="color:purple;">self</span> <span style="font-style:italic;color:purple;">(you)</span> 1 month ago                                                                                                       <span style="color:#2a2a2a;"> │</span>
+
<span style="color:#2a2a2a;">│ </span><span style="color:teal;">↑</span> updated to d2ebc70caca54a8ba508d72862c1e1c79d718129 <span style="color:blue;">(4515d45)</span> 1 month ago                                                                     <span style="color:#2a2a2a;"> │</span>
+
<span style="color:#2a2a2a;">│ </span><span style="color:teal;">↑</span> updated to 13e9ba641c624db26b6bfe85870daf064f90e9ab <span style="color:blue;">(045e465)</span> 1 month ago                                                                     <span style="color:#2a2a2a;"> │</span>
+
<span style="color:#2a2a2a;">│ </span><span style="color:teal;">↑</span> updated to 47495c408ccf5eec49b61c7bdb339e5f2d695a30 <span style="color:blue;">(a6be355)</span> 1 month ago                                                                     <span style="color:#2a2a2a;"> │</span>
+
<span style="color:#2a2a2a;">│ </span><span style="color:teal;">↑</span> updated to e3bdb65d3adb94360dd3449744792f6ecb1f451f <span style="color:blue;">(8d08215)</span> 1 month ago                                                                     <span style="color:#2a2a2a;"> │</span>
+
<span style="color:#2a2a2a;">│ </span>  └─ ⋄ reviewed by <span style="color:purple;">erikli</span> <span style="color:purple;">z6MkgFq…FGAnBGz</span> 1 month ago                                                                                           <span style="color:#2a2a2a;"> │</span>
+
<span style="color:#2a2a2a;">│ </span><span style="color:teal;">↑</span> updated to 9f779028704b4c022cbe25c0e4a9bb46dc8463ba <span style="color:blue;">(49fcea7)</span> 1 month ago                                                                     <span style="color:#2a2a2a;"> │</span>
+
<span style="color:#2a2a2a;">│ </span><span style="color:teal;">↑</span> updated to 86ebfcaaf986edba5e77ede1be4d3c4ce33bd27c <span style="color:blue;">(2df7cd9)</span> 1 month ago                                                                     <span style="color:#2a2a2a;"> │</span>
+
<span style="color:#2a2a2a;">│ </span><span style="color:teal;">↑</span> updated to fa9bdff35d76903f72cf24f1cccca812ae26e98c <span style="color:blue;">(34014a6)</span> 1 month ago                                                                     <span style="color:#2a2a2a;"> │</span>
+
<span style="color:#2a2a2a;">╰</span><span style="color:#2a2a2a;">──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────</span><span style="color:#2a2a2a;">╯</span>
+
</pre>
+

+
You can see here how non-perfect my changes are, I'm being vulnerable here.
+

+
I can now grab the value `Head` in the above table, and use it in `jj`, by
+
running `jj new 34014a67b0ddc859d95e17ffc71c1ae61aff5758`. This will drop me
+
onto a new change after `34014a67b0ddc859d95e17ffc71c1ae61aff5758`, and then I
+
can use `jj log -r ::@` to see all the previous changes.
+

+
Again, I use the wonderful `jj edit` command, or perhaps I make new changes that
+
I then `jj squash` into the relevant changes – it all depends on the scope of
+
the change!
+

+
Once I'm done, I push `HEAD` to another special [refspec][git-refspec], using
+
the patch's full identifier:
+

+
```sh
+
git push rad HEAD:patches/c54883e5ffb1f8a99f432e3ac79c0b728cd0dab3 -f
+
```
+

+
We use `-f` if we are editing the changes since this will change the underlying
+
commits and `git` will reject this. Once again, this will open my `$EDITOR` and
+
I will add a message about the changes that were made in this update.
+

+
This creates a new "revision" for the patch, preserving the older revisions.
+
So essentially, patches in Radicle are append-only. This makes it safe for us to
+
make edits to changes, marking them as mutable – the Git history will be
+
preserved!
+

+
#### Maintaining Patches
+

+
From the maintaining perspective, the flow starts off similar to updating, where
+
I would look up the patch that I want to merge. If I made the patch, things are
+
a bit easier because the Git objects are easily accessible and I can do `jj new`
+
using the commit. If I attempt to do this with a patch that came from another
+
contributor, then I may run into this issue:
+

+
<pre class="wide">
+
$ jj new 7322e3ac61669ba6dbde16bb0f7d30edf1ee85ce
+
<span style="font-weight:bold;"></span><span style="font-weight:bold;color:red;">Error: </span><span style="font-weight:bold;">Revision `7322e3ac61669ba6dbde16bb0f7d30edf1ee85ce` doesn't exist</span>
+
</pre>
+

+
The way to do this instead, is to use the remote syntax and the special
+
`patches` reference:
+

+
<pre class="wide">
+
$ jj new patches/3219ef871dd44c7ef51693f4aeba4c2c5c0c5c7b@rad
+
Working copy  (@) now at: <span style="font-weight:bold;"></span><span style="font-weight:bold;filter: contrast(70%) brightness(190%);color:purple;">oo</span><span style="font-weight:bold;filter: contrast(70%) brightness(190%);color:dimgray;">xzsqoy</span><span style="font-weight:bold;"> </span><span style="font-weight:bold;filter: contrast(70%) brightness(190%);color:blue;">eb</span><span style="font-weight:bold;filter: contrast(70%) brightness(190%);color:dimgray;">9e0803</span><span style="font-weight:bold;"> </span><span style="font-weight:bold;filter: contrast(70%) brightness(190%);color:green;">(empty)</span><span style="font-weight:bold;"> </span><span style="font-weight:bold;filter: contrast(70%) brightness(190%);color:green;">(no description set)</span>
+
Parent commit (@-)      : <span style="font-weight:bold;"></span><span style="font-weight:bold;color:purple;">s</span><span style="filter: contrast(70%) brightness(190%);color:dimgray;">wpyssrk</span> <span style="font-weight:bold;"></span><span style="font-weight:bold;color:blue;">73</span><span style="filter: contrast(70%) brightness(190%);color:dimgray;">22e3ac</span> <span style="color:purple;">patches/3219ef871dd44c7ef51693f4aeba4c2c5c0c5c7b patches/3219ef871dd44c7ef51693f4aeba4c2c5c0c5c7b@rad</span><span style="filter: contrast(70%) brightness(190%);color:dimgray;"> | </span>node, cli: remove predefined bootstrap nodes
+
</pre>
+

+
At this point, I can also look at what commits are in the patch via `rad patch
+
show`, or by using `jj log -r ::@`. If they're already on top `master@rad`, then
+
to merge the patch I can simply `git push rad master` – and the remote helper
+
marks the patch as merged if the canonical reference of `master` is update (a
+
topic for another time).
+

+
If the patch isn't on top of `master@rad` then I can rebase the changes using
+
`jj rebase -d master@rad -r <base>::<head>` to get the series of changes on top
+
of our latest. It's then necessary to push a new revision to the patch so that
+
the patch can know it is being merged with the new commits – remember that I
+
rebased, so this changes the underlying commits.
+

+
We should update our `master` bookmark, and this is where the `tug` alias comes
+
in. When I run `jj tug`, it figures out that `master` is the closest bookmark
+
and pulls it up to the latest change that can be pushed. I can then push to
+
update the patch:
+

+
```sh
+
git push rad master:patches/3219ef871dd44c7ef51693f4aeba4c2c5c0c5c7b -f
+
```
+

+
Here I'm using `master` instead of `HEAD` – this gets around a little issue I've
+
been seeing for patches that I do not own, where the remote helper rejects the
+
push because it cannot resolve `HEAD` (a mystery left for another day).
+

+
Once the patch has been rebased, I can do the usual `git push rad master` to
+
update the canonical reference and have the patch marked as merged.
+

+
## Conclusion
+

+
And our adventure ends here. We dived into how Radicle works with Git, how
+
Jujutsu works Git, and how I use Jujutsu to have a branch-less flow in Radicle.
+
This is has been a dream to work with. This type of tooling feels like it
+
enables me a lot more when managing my changes and keeping a clean history. I
+
was *able* to do this with `git rebase`, but it felt like it got in the way more
+
than it enabled me – and I haven't even touched on how [conflicts][jj-conflicts]
+
are easy in Jujutsu!
+

+
There is plenty of room for improvements here, some things on my list are:
+
- Keeping track of Jujutsu change IDs in Radicle data, which is already being
+
  looked at!
+
- Not needing to use `rad patch show` to get metadata for managing patches, and
+
  perhaps even bookmarking patch identifiers automatically.
+

+
Come help in discussion on our [Zulip], and enjoy being Radicle 🌱👾
+

+
<!-- Other people and events. --->
+
[Alex Good]: https://patternist.xyz
+
[Local First Conference]: https://www.localfirstconf.com/
+
[detached-head]: https://wizardzines.com/comics/detached-head-state/
+

+
<!-- Jujutsu -->
+
[jj]: https://jj-vcs.github.io/jj/v0.30.0/
+
[jj-bookmarks]: https://jj-vcs.github.io/jj/v0.30.0/bookmarks
+
[jj-conflicts]: https://jj-vcs.github.io/jj/v0.30.0/conflicts
+
[jj-immutables-heads]: https://jj-vcs.github.io/jj/v0.30.0/config/#set-of-immutable-commits
+
[jj-revsets]: https://jj-vcs.github.io/jj/v0.30.0/revsets
+

+
<!-- Git -->
+
[git-list-change-id-topic]: https://lore.kernel.org/git/CAESOdVAspxUJKGAA58i0tvks4ZOfoGf1Aa5gPr0FXzdcywqUUw@mail.gmail.com/
+
[git-refspec]: https://git-scm.com/book/en/v2/Git-Internals-The-Refspec
+
[git-remote-helpers]: https://git-scm.com/docs/gitremote-helpers
+

+
<!-- Radicle -->
+
[Zulip]: https://radicle.zulipchat.com
+
[download]: https://radicle.xyz/download
+
[guide-user-cobs]: https://radicle.xyz/guides/user#2-collaborating-the-radicle-way
+
[guide-user-patch]: https://radicle.xyz/guides/user#working-with-patches
+
[guides]: https://radicle.xyz/guides
+
[rip-storage]: https://app.radicle.xyz/nodes/ash.radicle.garden/rad:z3trNYnLWS11cJWC6BbxDs5niGo82/tree/0003-storage-layout.md
+
[rip-storage-namespace]: https://app.radicle.xyz/nodes/ash.radicle.garden/rad:z3trNYnLWS11cJWC6BbxDs5niGo82/tree/0003-storage-layout.md#layout
modified index.md
@@ -132,6 +132,7 @@ updated, join our community on 💬 [Zulip][zulip], or <a href="{{ site.feed.pat

## Blog

+
- 14.08.2025 [Jujutsu + Radicle = ❤️](/2025/08/14/jj-with-radicle.html)
- 12.08.2025 [Canonical References](/2025/08/12/canonical-references.html) released. ✨
- 23.07.2025 [Using Radicle CI for Development](/2025/07/23/using-radicle-ci-for-development.html)
- 30.05.2025 [How we used Radicle with GitHub Actions](/2025/05/30/radicle-with-github-actions.html)