2026-05-12 08:00:00
Over the past few weeks, I have been using jj! This is not the first time I have tried it, but it is the first time it has stuck.
For years, my git workflow has used "make a change, then git commit --amend --no-edit && git push --force-with-lease", while on a branch. This meant that my
changes would be up to date on the remote with very little latency. PRs would
rarely be more than a small number of commits, usually 1, and I would try to
keep them as small as possible.
Since working with agents, I have found myself switching branch much more
frequently. Because of this, I either have to git stash, or make some silly
little wip commit to stop my changes from stepping on each other.
Enter our new hero, jj! The model here is a bit different. I will not write a
huge manual because there are plenty of those, and they are better than anything
I would whack into my notes with little thought.
Suffice to say, the main thing that appeals to me is that my changes are always committed. Every edit automatically amends the most recent commit, and a push will overwrite the remote (or, in jj speak, move it "sideways").
Editing a change is easy, no checkout/rebase dance. It's as if someone took my preferred git workflow and built a tool around it. I am unsure why it took me so long to figure this out.
Just a braindump really. I will probably publish more notes as I learn more things.
When making a change, my workflow is
jj new main
<do some coding>
jj describe -m 'feat: something really cool'
jj git push -c @
Done. Merge PR, repeat.
In jj, we talk about changes more than commits. A change is a constantly evolving commit. And "@" refers to the current change
Before doing some work, you should start a change. All of the edits you are about to make will live here
jj new main
This makes your commit (change vs commit is real and confusing when you're new)
on top of main (the commit with the bookmark main). If you want to make a new
change that is the child of your current, just run jj new.
You're probably used to adding some changes to your staging area, then committing them with a message. Well with jj, your changes are already added. But your change probably does not have a description! (like a commit message)
jj describe -m 'hello i am a message'
You can also describe a change when you make it, with
jj new -m "hello i am a message"
If you're on a change, you're happy with it, and you want it on github so some agent can roast your (claude's) code?
Easy.
jj git push -c @
Aka "use git to push the current commit". It will automatically create a branch, push that to the remote. You can actually do this over and over again while making changes, and it will automatically translate the jj magic into a git amend and force push.
I am excited for jj to get its own protocol and host though.
If you want to jump back and edit an existing change? Easy
jj edit <change-id>
This is where things start to feel powerful me, and also where the existing mental model I try to tack this onto starts to break. There's no checkout, rebase, etc to fuck about with.
jj has changes AND commits. If we recall that it constantly evolves a commit, rather than having a staging area, then we can think of the change as the stable id, and the commit id as the one that changes with each edit
Pretty much anything you do in jj is stored in the op log. If you do a thing,
and it messes up? jj undo to the rescue.
jj is still piggybacking on top of git, mostly. They have made it easy to convert an existing repo, and also integrate with github
# Create a jj repo inside of a git repo
jj git init
# Fetch from the remote (github etc)
jj git fetch
# Push
jj git push
# Clone
jj git clone
There aren't any! Not in the way you are used to. jj uses "bookmarks", or, a
string that you can attach to a commit. When you push a change, it automatically
creates a bookmark for you - eg, push-refrefref
# bookmark the current change with a name
jj bookmark create <name>
# move a bookmark to a new commit
jj bookmark set <name> -r <commit>
# other things exist just use --help
The main frustration I have is that bookmarks do not move when I create a new change.
From the glossary
Unlike in Git, there is no concept of a "current bookmark"; bookmarks do not move when you create a new commit. Bookmarks do automatically follow the commit if it gets rewritten.
I'll write up something else about rebasing and editing and all the fun stuff later
Note: writing this in Vim has been super annoying, because I have jj bound to
<esc>.
2026-02-16 08:00:00

I was recently setting up a new k3s cluster for running Atuin. Since I wrote my last note on the subject, a few things have changed!
I definitely need to do a v2 of my post, but in the meantime I learned a bit about Spegel, an optional integrated registry included with k3s.
If server nodes are started with --embedded-registry, then they will setup +
run a Spegel registry. This means they host a local OCI registry on port 6443,
while connecting to a p2p network over port 5001.
In order for upstream registry mirroring to work, you must edit
/etc/rancher/k3s/registries.yaml
For example
mirrors:
docker.io:
registry.k8s.io:
enables mirroring of those two registries. This file is read at startup. You
can enable wildcard mirroring with "*":, quoted required.
The p2p routing works in a very similar way to BitTorrent - Spegel also uses a Kademlia DHT for resolving digests.
gif sourced from the spegel readme
2025-11-06 08:00:00
I moved to the US and bought a superduke yay
Here I am making some notes. I will likely also track torque specs, services, etc.
A collection of useful specs
| Spec | Value |
|---|---|
| Factory recommended rear pressure | 42 |
| Factory recommended front pressure | 36 |
| Ellie's preferred rear pressure | 36 |
| Ellie's preferred front pressure | 32 |
I'll note them down as I look them up
| Part | Torque (nm) |
|---|---|
| Rear wheel nut | 250 |
2025-01-03 08:00:00
Today I found myself needing to configure ingress-nginx. I needed to write a bit of nginx config to rewrite status codes for certain routes.
Something like
nginx.ingress.kubernetes.io/configuration-snippet: |-
location /metrics {
return 404;
}
I've done this many times in the past, but today I received the following error
Error: UPGRADE FAILED: cannot patch "xyz" with kind Ingress: admission webhook "validate.nginx.ingress.kubernetes.io" denied the request: annotation group ConfigurationSnippet contains risky annotation based on ingress configuration
I already had
allowSnippetAnnotations: true
set, so this was confusing!
It turns out, in a recent release (controller 1.12), annotations are flagged by risk. There's a table here
You now need to specify
annotations-risk-level: Critical
in the configmap. If you're using the helm chart, it can be added like so
controller:
config:
annotations-risk-level: Critical
Note that this change is a reaction to a security issue. This is mostly an issue if you're using a multi-tenant cluster.
Issues: https://github.com/kubernetes/ingress-nginx/issues/12618, https://github.com/kubernetes/kubernetes/issues/126811
2024-09-13 08:00:00
I've been working on a desktop app with Tauri, and had issues for a while with the "draggable" prop on some elements. Instead of them dragging as I expected, I'd just get a plus icon.
The fix was pretty easy
I added
app: {
window:[{
...snip,
"dragDropEnabled": false
}]
}
to my tauri.config.json.
This is mentioned in the Tauri docs: https://v2.tauri.app/reference/javascript/api/namespacewebview/#properties-1
2024-07-30 08:00:00
It's pretty common that I'll accidentally use the wrong email for a commit. I have a few emails that I like to use for different purposes, so getting it correct is important :)
This one is nice and easy!
git commit --amend --author="Example Name <[email protected]>"
git rebase -i on whatever base you wantedit, instead of pick
git commit --amend --author="Example Name <[email protected]>", then git rebase --continue
Filter the whole thing! Be careful though, filter-branch can break things if you're not careful
git filter-branch -f --commit-filter '
if [ "$GIT_AUTHOR_EMAIL" = "[email protected]" ];
then
GIT_AUTHOR_NAME="New Name";
GIT_AUTHOR_EMAIL="[email protected]";
git commit-tree "$@";
else
git commit-tree "$@";
fi' HEAD
I first mentioned git-filter-repo in split git repo, but it's useful here too. Preferable to filter-branch, but not included in the base git install.
Install with
curl "https://raw.githubusercontent.com/newren/git-filter-repo/main/git-filter-repo" -o ~/.local/bin/git-filter-path
Then do either of the following
If you setup your mailmap to map old -> new, you can run
git filter-repo --use-mailmap
Otherwise, the following works well
git filter-repo --email-callback '
return email if email != b"[email protected]" else b"[email protected]"
'