<?xml version="1.0" encoding="UTF-8"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="en">
    <title>ertius.org</title>
    <subtitle>rob weir&#39;s site</subtitle>
    <link rel="self" type="application/atom+xml" href="https://ertius.org/all.xml"/>
    <link rel="alternate" type="text/html" href="https://ertius.org/"/>
    <generator uri="https://www.getzola.org/">Zola</generator>
    <updated>2026-09-21T00:00:00+00:00</updated>
    <id>https://ertius.org/all.xml</id>
    <entry xml:lang="en">
        <title>Run Commands At Exact Git Refs</title>
        <published>2026-09-21T00:00:00+00:00</published>
        <updated>2026-09-21T00:00:00+00:00</updated>
        
        <author>
          <name>rweir@ertius.org (Rob Weir)</name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://ertius.org/til/2026-09-21/"/><id>https://ertius.org/til/2026-09-21/</id>
        <content type="html" xml:base="https://ertius.org/til/2026-09-21/">&lt;p&gt;It is often very handy to be working on multiple things in a single
repository, and while &lt;code&gt;magit&lt;/code&gt; makes &lt;em&gt;unpicking&lt;/em&gt; local changes into
coherent commits easy, &lt;em&gt;testing&lt;/em&gt; those commits is kind of annoying.  My
primary use case for this was for testing changes in an Ansible tree -
often I have a lot of things in flight, but it&#39;s pretty important to
ensure that a commit is coherent.  Specifically: &lt;em&gt;the change refers to
a new file and the new file itself needs to end up in the same
commit&lt;/em&gt;.  Just running tests or &lt;code&gt;ansible-playbook --check --diff&lt;/code&gt;
doesn&#39;t help in that case, because all the files are in the tree, but
what you care about is whether they&#39;ll be committed together.&lt;/p&gt;
&lt;p&gt;So I wrote a little script, the gist of which is this:&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-5 z-d-i&quot;&gt;#!&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-5 z-d-i&quot;&gt;/usr/bin/env bash&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-1 z-d-18&quot;&gt;set&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-12&quot;&gt; -&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-12&quot;&gt;euo&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-9&quot;&gt; pipefail&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-d-3&quot;&gt;main_repo&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-4&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-d-7&quot;&gt;$(&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-16&quot;&gt;git&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-9&quot;&gt; rev-parse&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-12&quot;&gt; -&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-12&quot;&gt;-show-toplevel&lt;/span&gt;&lt;span class=&quot;z-d-7&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-d-3&quot;&gt;rel_dir&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-4&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-d-7&quot;&gt;$(&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-16&quot;&gt;git&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-9&quot;&gt; rev-parse&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-12&quot;&gt; -&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-12&quot;&gt;-show-prefix&lt;/span&gt;&lt;span class=&quot;z-d-7&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-d-3&quot;&gt;cache&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-4&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-7&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-d-3&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;z-d-3&quot;&gt;HOME&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-9&quot;&gt;/.cache/run-at-worktrees&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-7&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-d-3&quot;&gt;mode_index&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-4&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-9&quot;&gt;0&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-d-3&quot;&gt;commit&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-4&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-9&quot;&gt;H&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-9&quot;&gt;E&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-9&quot;&gt;A&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-9&quot;&gt;D&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-9 z-d-17&quot;&gt;while&lt;/span&gt;&lt;span class=&quot;z-d-18&quot;&gt; [[&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-3&quot;&gt; $&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-3&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-17&quot;&gt; -gt&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-12&quot;&gt; 0&lt;/span&gt;&lt;span class=&quot;z-d-18&quot;&gt; ]]&lt;/span&gt;&lt;span class=&quot;z-d-7&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-17&quot;&gt; do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-9 z-d-17&quot;&gt;  case&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-7&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-3&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-3&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-7&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-17&quot;&gt; in&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-3 z-d-18&quot;&gt;    -&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-18&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-18&quot;&gt;i&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-18&quot;&gt;n&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-18&quot;&gt;d&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-18&quot;&gt;e&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-18&quot;&gt;x&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-4&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;z-d-3&quot;&gt;   mode_index&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-4&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-9&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;z-d-7&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-18&quot;&gt; shift&lt;/span&gt;&lt;span class=&quot;z-d-7&quot;&gt; ;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-3 z-d-18&quot;&gt;    -&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-18&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-4&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-18&quot;&gt;        shift&lt;/span&gt;&lt;span class=&quot;z-d-7&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-17&quot;&gt; break&lt;/span&gt;&lt;span class=&quot;z-d-7&quot;&gt; ;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-3 z-d-18&quot;&gt;    -&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-7&quot;&gt;*&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-4&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-18&quot;&gt;        echo&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-7&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-9&quot;&gt;run-at: unknown flag: &lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-3&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-3&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-7&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-4&quot;&gt; &amp;gt;&amp;amp;2&lt;/span&gt;&lt;span class=&quot;z-d-7&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-18&quot;&gt; exit&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-12&quot;&gt; 2&lt;/span&gt;&lt;span class=&quot;z-d-7&quot;&gt; ;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-9 z-d-4&quot;&gt;    *)&lt;/span&gt;&lt;span class=&quot;z-d-3&quot;&gt;         commit&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-4&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-7&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-3&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-3&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-7&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-d-7&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-18&quot;&gt; shift&lt;/span&gt;&lt;span class=&quot;z-d-7&quot;&gt; ;;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-9 z-d-17&quot;&gt;  esac&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-9 z-d-17&quot;&gt;done&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-9 z-d-17&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;z-d-18&quot;&gt; [[&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-3&quot;&gt; $&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-3&quot;&gt;#&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-17&quot;&gt; -eq&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-12&quot;&gt; 0&lt;/span&gt;&lt;span class=&quot;z-d-18&quot;&gt; ]]&lt;/span&gt;&lt;span class=&quot;z-d-7&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-17&quot;&gt; then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-1 z-d-18&quot;&gt;  echo&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-7&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-9&quot;&gt;run-at: missing command&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-7&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-4&quot;&gt; &amp;gt;&amp;amp;2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-1 z-d-18&quot;&gt;  exit&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-12&quot;&gt; 2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-9 z-d-17&quot;&gt;fi&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-9 z-d-17&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;z-d-7&quot;&gt; ((&lt;/span&gt;&lt;span class=&quot;z-d-3&quot;&gt; mode_index&lt;/span&gt;&lt;span class=&quot;z-d-7&quot;&gt; ))&lt;/span&gt;&lt;span class=&quot;z-d-7&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-17&quot;&gt; then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-d-3&quot;&gt;  tree&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-4&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-d-7&quot;&gt;$(&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-16&quot;&gt;git&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-12&quot;&gt; -&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-12&quot;&gt;C&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-7&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span class=&quot;z-d-3&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;z-d-3&quot;&gt;main_repo&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-7&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-9&quot;&gt; write-tree&lt;/span&gt;&lt;span class=&quot;z-d-7&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-d-3&quot;&gt;  sha&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-4&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-d-7&quot;&gt;$(&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-d-3&quot;&gt;    GIT_AUTHOR_DATE&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-4&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-7&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-9&quot;&gt;@0 +0000&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-7&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&quot;z-d-3&quot;&gt; GIT_COMMITTER_DATE&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-4&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-7&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-9&quot;&gt;@0 +0000&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-7&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-16&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-3 z-d-9&quot;&gt;    GIT_AUTHOR_NAME=run-at&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-9&quot;&gt; GIT_AUTHOR_EMAIL=at@localhost&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-3 z-d-9&quot;&gt;    GIT_COMMITTER_NAME=run-at&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-9&quot;&gt; GIT_COMMITTER_EMAIL=at@localhost&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-3 z-d-9&quot;&gt;    git&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-12&quot;&gt; -&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-12&quot;&gt;C&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-7&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span class=&quot;z-d-3&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;z-d-3&quot;&gt;main_repo&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-7&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-9&quot;&gt; commit-tree&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-7&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span class=&quot;z-d-3&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;z-d-3&quot;&gt;tree&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-7&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-12&quot;&gt; -&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-12&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-9&quot;&gt; HEAD&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-1 z-d-12&quot;&gt;      -&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-12&quot;&gt;m&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-7&quot;&gt; &amp;#39;&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-9&quot;&gt;run-at index snapshot&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-7&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-d-7&quot;&gt;  )&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-d-3&quot;&gt;  label&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-4&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-7&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-9&quot;&gt;index snapshot on top of &lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-7&quot;&gt;$(&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-16&quot;&gt;git&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-12&quot;&gt; -&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-12&quot;&gt;C&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-7&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span class=&quot;z-d-3&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;z-d-3&quot;&gt;main_repo&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-7&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-9&quot;&gt; rev-parse&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-12&quot;&gt; -&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-12&quot;&gt;-short&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-9&quot;&gt; HEAD&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-7&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-7&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-9 z-d-17&quot;&gt;else&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-d-3&quot;&gt;  sha&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-4&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-d-7&quot;&gt;$(&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-16&quot;&gt;git&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-12&quot;&gt; -&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-12&quot;&gt;C&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-7&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span class=&quot;z-d-3&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;z-d-3&quot;&gt;main_repo&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-7&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-9&quot;&gt; rev-parse&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-12&quot;&gt; -&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-12&quot;&gt;-verify&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-7&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span class=&quot;z-d-3&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;z-d-3&quot;&gt;commit&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-9&quot;&gt;^{commit}&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-7&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-d-7&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-d-3&quot;&gt;  label&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-4&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-d-7&quot;&gt;$(&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-16&quot;&gt;git&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-12&quot;&gt; -&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-12&quot;&gt;C&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-7&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span class=&quot;z-d-3&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;z-d-3&quot;&gt;main_repo&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-7&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-9&quot;&gt; log&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-12&quot;&gt; -&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-12&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-12&quot;&gt; -&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-12&quot;&gt;-format=&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-7&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-9&quot;&gt;%h %s&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-7&quot;&gt;&amp;#39;&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-7&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span class=&quot;z-d-3&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;z-d-3&quot;&gt;sha&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-7&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-d-7&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-9 z-d-17&quot;&gt;fi&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-d-3&quot;&gt;wt&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-4&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-7&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-d-3&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;z-d-3&quot;&gt;cache&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-9&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-7&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-7&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;z-d-3&quot;&gt;sha&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-4&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;z-d-3&quot;&gt;0&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-4&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;z-d-3&quot;&gt;12&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-7&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-7&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-16&quot;&gt;mkdir&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-12&quot;&gt; -&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-12&quot;&gt;p&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-7&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span class=&quot;z-d-3&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;z-d-3&quot;&gt;cache&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-7&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-9 z-d-17&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;z-d-18&quot;&gt; [[&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-17&quot;&gt; !&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-17&quot;&gt; -d&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-7&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span class=&quot;z-d-3&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;z-d-3&quot;&gt;wt&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-7&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-d-18&quot;&gt; ]]&lt;/span&gt;&lt;span class=&quot;z-d-7&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-17&quot;&gt; then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-16&quot;&gt;  git&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-12&quot;&gt; -&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-12&quot;&gt;C&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-7&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span class=&quot;z-d-3&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;z-d-3&quot;&gt;main_repo&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-7&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-9&quot;&gt; worktree&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-9&quot;&gt; add&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-12&quot;&gt; -&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-12&quot;&gt;-detach&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-7&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span class=&quot;z-d-3&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;z-d-3&quot;&gt;wt&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-7&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-7&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span class=&quot;z-d-3&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;z-d-3&quot;&gt;sha&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-7&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-4&quot;&gt; &amp;gt;&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-9&quot;&gt;/dev/null&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-9 z-d-17&quot;&gt;fi&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-1 z-d-18&quot;&gt;echo&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-7&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-9&quot;&gt;→ run-at: &lt;/span&gt;&lt;span class=&quot;z-d-3&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;z-d-3&quot;&gt;wt&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-7&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-4&quot;&gt; &amp;gt;&amp;amp;2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-1 z-d-18&quot;&gt;echo&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-7&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-9&quot;&gt;  rev:  &lt;/span&gt;&lt;span class=&quot;z-d-3&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;z-d-3&quot;&gt;sha&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-7&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-4&quot;&gt; &amp;gt;&amp;amp;2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-1 z-d-18&quot;&gt;echo&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-7&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-9&quot;&gt;  desc: &lt;/span&gt;&lt;span class=&quot;z-d-3&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;z-d-3&quot;&gt;label&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-7&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-4&quot;&gt; &amp;gt;&amp;amp;2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-d-3&quot;&gt;target_dir&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-4&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-7&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-d-3&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;z-d-3&quot;&gt;wt&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-7&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-9 z-d-17&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;z-d-18&quot;&gt; [[&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-17&quot;&gt; -n&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-7&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span class=&quot;z-d-3&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;z-d-3&quot;&gt;rel_dir&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-7&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-d-18&quot;&gt; ]]&lt;/span&gt;&lt;span class=&quot;z-d-7&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-17&quot;&gt; then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-d-3&quot;&gt;  target_dir&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-4&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-7&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-d-3&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;z-d-3&quot;&gt;wt&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-9&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-7&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-7&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;z-d-3&quot;&gt;rel_dir&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-4&quot;&gt;%&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-4&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-7&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-7&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-9 z-d-17&quot;&gt;fi&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-9 z-d-17&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;z-d-18&quot;&gt; [[&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-17&quot;&gt; !&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-17&quot;&gt; -d&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-7&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span class=&quot;z-d-3&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;z-d-3&quot;&gt;target_dir&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-7&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-d-18&quot;&gt; ]]&lt;/span&gt;&lt;span class=&quot;z-d-7&quot;&gt;;&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-17&quot;&gt; then&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-1 z-d-18&quot;&gt;  echo&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-7&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-9&quot;&gt;run-at: target directory does not exist in selected revision: &lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-7&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-7&quot;&gt;{&lt;/span&gt;&lt;span class=&quot;z-d-3&quot;&gt;rel_dir&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-4&quot;&gt;:-&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-9&quot;&gt;.&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-7&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-7&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-4&quot;&gt; &amp;gt;&amp;amp;2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-1 z-d-18&quot;&gt;  exit&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-12&quot;&gt; 1&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-9 z-d-17&quot;&gt;fi&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-1 z-d-18&quot;&gt;cd&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-7&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span class=&quot;z-d-3&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;z-d-3&quot;&gt;target_dir&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-7&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-1 z-d-18&quot;&gt;exec&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-7&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-3&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-3&quot;&gt;@&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-7&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;(the real version does some Ansible-specific stuff like symlinking the &lt;code&gt;venv&lt;/code&gt;).&lt;/p&gt;
&lt;p&gt;It&#39;s a lot of lines to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Get a git commit id (or, if you pass &lt;code&gt;--index&lt;/code&gt;, create a temporary
commit from the staging area).  Either &lt;em&gt;must go&lt;/em&gt; before the &lt;code&gt;--&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Make a worktree in &lt;code&gt;~/.cache/run-at-worktrees&lt;/code&gt;, with the name based
on the commit.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;cd&lt;/code&gt; to the same relative directory (e.g. if I&#39;m in
&lt;code&gt;~/src/linux/drivers&lt;/code&gt;, ensure I end up in &lt;code&gt;./drivers&lt;/code&gt; in the worktree)&lt;/li&gt;
&lt;li&gt;Exec the provided command.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Setting the commit metadata - &lt;code&gt;GIT_AUTHOR_*&lt;/code&gt; and &lt;code&gt;GIT_COMMITTER_*&lt;/code&gt; -
to static values means the temporary commit&#39;s hash depends only on the
current commit + contents of the index, so we will reuse any previous
worktree that shared the same content (and &lt;code&gt;HEAD&lt;/code&gt;).  &lt;code&gt;commit-tree&lt;/code&gt;
ignores any configured &lt;code&gt;gpg&lt;/code&gt;/&lt;code&gt;ssh&lt;/code&gt; signing requirement, so it doesn&#39;t
require any creds and the commit id doesn&#39;t depend on keys or
timestamps.&lt;/p&gt;
&lt;p&gt;This is one of those things that in the past I might have considered
too slow to do, but on a 5-year-old Mac, running it on the Linux
kernel:&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;shellsession&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-d-7&quot;&gt;❯&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-17&quot;&gt; time&lt;/span&gt;&lt;span&gt; run-at -- pwd&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-1&quot;&gt;Preparing worktree (detached HEAD 9ecfb2f7287a)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-1&quot;&gt;Updating files: 100% (94643/94643), done.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-1&quot;&gt;→ run-at: /Users/rob/.cache/run-at-worktrees/9ecfb2f7287a&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-1&quot;&gt;  rev:  9ecfb2f7287a967b418ba69f10d45ead0d360593&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-1&quot;&gt;  desc: 9ecfb2f7287a Merge tag &amp;#39;trace-ring-buffer-v7.2&amp;#39; of git://git.kernel.org/pub/scm/linux/kernel/git/trace/linux-trace&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-1&quot;&gt;/Users/rob/.cache/run-at-worktrees/9ecfb2f7287a&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-1&quot;&gt;user=3.21s system=6.72s cpu=94% total=10.523&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Since the worktree is named after the commit it&#39;s pointing at,
subsequent runs are ~instant:&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;shellsession&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-d-7&quot;&gt;❯&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-17&quot;&gt; time&lt;/span&gt;&lt;span&gt; run-at -- pwd&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-1&quot;&gt;→ run-at: /Users/rob/.cache/run-at-worktrees/9ecfb2f7287a&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-1&quot;&gt;  rev:  9ecfb2f7287a967b418ba69f10d45ead0d360593&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-1&quot;&gt;  desc: 9ecfb2f7287a Merge tag &amp;#39;trace-ring-buffer-v7.2&amp;#39; of git://git.kernel.org/pub/scm/linux/kernel/git/trace/linux-trace&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-1&quot;&gt;/Users/rob/.cache/run-at-worktrees/9ecfb2f7287a&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-1&quot;&gt;user=0.02s system=0.03s cpu=76% total=0.066&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;My code bases are much, much smaller than &lt;code&gt;linux.git&lt;/code&gt;, so that&#39;s plenty
fast enough for me for running tests or &lt;code&gt;uv run ansible-playbook --check --diff ...&lt;/code&gt;.  It is not fully hermetic, and any changes or
junk left in the worktree persist between runs, but it&#39;s turned
out to be very handy.&lt;/p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Trying To Make A Binary Cask With Homebrew</title>
        <published>2026-09-20T00:00:00+00:00</published>
        <updated>2026-09-20T00:00:00+00:00</updated>
        
        <author>
          <name>rweir@ertius.org (Rob Weir)</name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://ertius.org/til/2026-09-20/"/><id>https://ertius.org/til/2026-09-20/</id>
        <content type="html" xml:base="https://ertius.org/til/2026-09-20/">&lt;p&gt;&lt;code&gt;homebrew&lt;/code&gt; is kinda weird compared to Debian and &lt;code&gt;apt&lt;/code&gt;, but it is quite thorough and means I can keep almost all my software on macOS up-to-date with just &lt;code&gt;brew upgrade&lt;/code&gt;.  For the things it didn&#39;t have, though, I&#39;d usually just install from source to &lt;code&gt;~/.local/bin&lt;/code&gt; and then leave it un-upgraded forever, which is not ideal.  I thought I&#39;d actually do it a bit more properly today, and, well, at least the &quot;copy these binary files&quot; part is not very complicated.&lt;/p&gt;
&lt;h2 id=&quot;jargon&quot;&gt;Jargon&lt;a class=&quot;anchor&quot; href=&quot;#jargon&quot; aria-label=&quot;Anchor link for: jargon&quot;&gt;#&lt;/a&gt;
&lt;/h2&gt;
&lt;p&gt;First, some jargon, since I can never remember what anything is in &lt;code&gt;brew&lt;/code&gt;-land:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;A &lt;em&gt;formula&lt;/em&gt; is a package definition for installing open source software from source (or community-provided prebuilt binary &lt;em&gt;bottles&lt;/em&gt;) in the form of a Ruby file&lt;/li&gt;
&lt;li&gt;A &lt;em&gt;cask&lt;/em&gt; is a package definition for installing a &lt;em&gt;binary&lt;/em&gt;, often a proprietary GUI app, which will be a &lt;code&gt;.rb&lt;/code&gt; file in the &lt;code&gt;Casks/&lt;/code&gt; directory of a &lt;em&gt;tap&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;A &lt;em&gt;tap&lt;/em&gt; is a Homebrew &quot;repository&quot;, somewhere it can download &lt;em&gt;formulas&lt;/em&gt; and &lt;em&gt;casks&lt;/em&gt; from (usually public &lt;code&gt;git&lt;/code&gt; repositories)&lt;/li&gt;
&lt;/ul&gt;
&lt;h2 id=&quot;getting-started&quot;&gt;Getting Started&lt;a class=&quot;anchor&quot; href=&quot;#getting-started&quot; aria-label=&quot;Anchor link for: getting-started&quot;&gt;#&lt;/a&gt;
&lt;/h2&gt;
&lt;p&gt;I want to install &lt;code&gt;coop&lt;/code&gt;, from &lt;a rel=&quot;external&quot; href=&quot;https://github.com/trailofbits/coop&quot;&gt;trailofbits&lt;/a&gt;, a sandbox for running coding agents.  Since upstream already ship binaries, I thought I&#39;d try to use them, by creating a &lt;em&gt;cask&lt;/em&gt; that just downloaded them from GitHub and installed them.&lt;/p&gt;
&lt;p&gt;First I need a &lt;em&gt;tap&lt;/em&gt; to put it in.  The simplest way is to use GitHub, so let&#39;s do that:&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-16&quot;&gt;brew&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-9&quot;&gt; tap-new&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-9&quot;&gt; rweir/homebrew-tap&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;On &lt;code&gt;aarch64/macos&lt;/code&gt; at least, this creates a local git repository (owned by me) in &lt;code&gt;/opt/homebrew/Library/Taps/rweir/homebrew-tap&lt;/code&gt;.  Then create a matching repository on GitHub and push to it:&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-16&quot;&gt;gh&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-9&quot;&gt; repo&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-9&quot;&gt; create&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-7&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-9&quot;&gt;rweir/homebrew-tap&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-7&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-1 z-d-12&quot;&gt;    -&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-12&quot;&gt;-push&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-12&quot;&gt; -&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-12&quot;&gt;-public&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-1 z-d-12&quot;&gt;    -&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-12&quot;&gt;-source&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-7&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-7&quot;&gt;$(&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-16&quot;&gt;brew&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-12&quot;&gt; -&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-12&quot;&gt;-repository&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-7&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-9&quot;&gt;rweir/homebrew-tap&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-7&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-7&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-7&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now you have a personal &lt;code&gt;tap&lt;/code&gt;, which you and anyone else can tell their local &lt;code&gt;brew&lt;/code&gt; to use:&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-16&quot;&gt;brew&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-9&quot;&gt; tap&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-9&quot;&gt; rweir/tap&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;&lt;code&gt;brew&lt;/code&gt; implicitly strips the &lt;code&gt;homebrew-&lt;/code&gt; from the repository name, so GitHub repo name &lt;code&gt;rweir/homebrew-tap&lt;/code&gt; maps to &lt;code&gt;brew tap&lt;/code&gt; argument &lt;code&gt;rweir/tap&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;So, I ask &lt;code&gt;brew&lt;/code&gt; to create the basic cask file for me to fill in:&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-16&quot;&gt;brew&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-9&quot;&gt; create&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-12&quot;&gt; -&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-12&quot;&gt;-cask&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-3 z-d-9&quot;&gt;    https://github.com/trailofbits/coop/releases/download/v0.6.0/coop-v0.6.0-aarch64-apple-darwin.tar.gz&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-1 z-d-12&quot;&gt;    -&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-12&quot;&gt;-tap&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-9&quot;&gt; rweir/homebrew-tap&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-12&quot;&gt; \&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-1 z-d-12&quot;&gt;    -&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-12&quot;&gt;-set-name&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-9&quot;&gt; coop&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then &lt;a rel=&quot;external&quot; href=&quot;https://github.com/rweir/homebrew-tap/blob/main/Casks/coop.rb&quot;&gt;just draw the rest of the owl&lt;/a&gt;:&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;ruby&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;cask &lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-7&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-9&quot;&gt;coop&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-7&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-17&quot;&gt; do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  version &lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-7&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-9&quot;&gt;0.6.0&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-7&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  sha256 &lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-7&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-9&quot;&gt;2eb045bbbb24e25c995500f93146eea5ee866595f9042ad441cb930d7ada3ed6&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-7&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  depends_on &lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-12&quot;&gt;arch&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-7&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-7&quot;&gt; :&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-12&quot;&gt;arm64&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  depends_on &lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-7&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-12&quot;&gt;macos&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-5 z-d-i&quot;&gt;  #&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-5 z-d-i&quot;&gt; Where to download the binary from&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  url &lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-7&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-9&quot;&gt;https://github.com/trailofbits/coop/releases/download/v&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-7&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-9&quot;&gt;version&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-7&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-9&quot;&gt;/coop-v&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-7&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-9&quot;&gt;version&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-7&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-9&quot;&gt;-aarch64-apple-darwin.tar.gz&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-7&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  name &lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-7&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-9&quot;&gt;coop&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-7&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  desc &lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-7&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-9&quot;&gt;Isolated VM environment for running Claude Code and Codex&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-7&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  homepage &lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-7&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-9&quot;&gt;https://github.com/trailofbits/coop&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-7&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-5 z-d-i&quot;&gt;  #&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-5 z-d-i&quot;&gt; Use the templated `url` field above to find other versions&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  livecheck &lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-17&quot;&gt;do&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    url &lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-7&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-12&quot;&gt;url&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-5 z-d-16&quot;&gt;    regex&lt;/span&gt;&lt;span class=&quot;z-d-7&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-7&quot;&gt;/&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-18&quot;&gt;^v?&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-7&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-2 z-l-b z-d-12&quot;&gt;\d&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-18&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-7&quot;&gt;(&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-18&quot;&gt;?:&lt;/span&gt;&lt;span class=&quot;z-l-2 z-l-b z-d-12&quot;&gt;\.&lt;/span&gt;&lt;span class=&quot;z-l-2 z-l-b z-d-12&quot;&gt;\d&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-18&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-7&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-18&quot;&gt;+&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-7&quot;&gt;)&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-18&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-7&quot;&gt;/i&lt;/span&gt;&lt;span class=&quot;z-d-7&quot;&gt;)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-9 z-d-17&quot;&gt;  end&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-5 z-d-i&quot;&gt;  #&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-5 z-d-i&quot;&gt; binaries are in a subdirectory inside the tarball, `brew` will use&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-6 z-d-5 z-d-i&quot;&gt;  #&lt;/span&gt;&lt;span class=&quot;z-l-6 z-d-5 z-d-i&quot;&gt; the basename as the target&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  binary &lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-7&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-9&quot;&gt;coop-v&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-7&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-9&quot;&gt;version&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-7&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-9&quot;&gt;-aarch64-apple-darwin/coop&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-7&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;  binary &lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-7&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-9&quot;&gt;coop-v&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-7&quot;&gt;#{&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-9&quot;&gt;version&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-7&quot;&gt;}&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-9&quot;&gt;-aarch64-apple-darwin/coop-proxy&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-7&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-9 z-d-17&quot;&gt;end&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;keeping-it-up-to-date&quot;&gt;Keeping It Up To Date&lt;a class=&quot;anchor&quot; href=&quot;#keeping-it-up-to-date&quot; aria-label=&quot;Anchor link for: keeping-it-up-to-date&quot;&gt;#&lt;/a&gt;
&lt;/h2&gt;
&lt;p&gt;&lt;code&gt;brew&lt;/code&gt; includes tooling to check for upstream updates:&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;shellsession&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-d-7&quot;&gt;$&lt;/span&gt;&lt;span class=&quot;z-d-3&quot;&gt; HOMEBREW_NO_AUTO_UPDATE&lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-4&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-9&quot;&gt;1&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-16&quot;&gt; brew&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-9&quot;&gt; livecheck&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-12&quot;&gt; -&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-12&quot;&gt;-cask&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-9&quot;&gt; rweir/tap/coop&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-1&quot;&gt;coop: 0.6.0 ==&amp;gt; 0.6.0&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;When there&#39;s a new version, I can make and then merge a PR to update &lt;code&gt;version&lt;/code&gt; and &lt;code&gt;sha256&lt;/code&gt; in &lt;code&gt;coop.rb&lt;/code&gt; to make it available.&lt;/p&gt;
&lt;h2 id=&quot;installing&quot;&gt;Installing&lt;a class=&quot;anchor&quot; href=&quot;#installing&quot; aria-label=&quot;Anchor link for: installing&quot;&gt;#&lt;/a&gt;
&lt;/h2&gt;
&lt;p&gt;Great, now it can be easily installed:&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;shellscript&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-16&quot;&gt;brew&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-9&quot;&gt; install&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-12&quot;&gt; -&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-12&quot;&gt;-cask&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-9&quot;&gt; rweir/tap/coop&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;h2 id=&quot;testing&quot;&gt;Testing&lt;a class=&quot;anchor&quot; href=&quot;#testing&quot; aria-label=&quot;Anchor link for: testing&quot;&gt;#&lt;/a&gt;
&lt;/h2&gt;
&lt;p&gt;Cool!  Now let&#39;s run it:&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;shellsession&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-d-7&quot;&gt;$&lt;/span&gt;&lt;span&gt; coop setup&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-1&quot;&gt;zsh: killed     coop setup&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and the classic popup:&lt;/p&gt;
&lt;figure class=&quot;article-figure&quot;&gt;
  &lt;img src=&quot;https://ertius.org/til/2026-09-20/computer-says-no.png&quot; alt=&quot;macOS warning: Apple could not verify that coop is free of malware.&quot; width=&quot;526&quot; height=&quot;474&quot; style=&quot;width: 360px&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;&gt;
  &lt;figcaption&gt;Computer Says No&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;h2 id=&quot;whelp&quot;&gt;Whelp&lt;a class=&quot;anchor&quot; href=&quot;#whelp&quot; aria-label=&quot;Anchor link for: whelp&quot;&gt;#&lt;/a&gt;
&lt;/h2&gt;
&lt;p&gt;I could not find a single page describing all this (&lt;strong&gt;edit&lt;/strong&gt;: &lt;em&gt;I just found a pretty good doc on the Homebrew site, actually:&lt;/em&gt; &lt;a rel=&quot;external&quot; href=&quot;https://docs.brew.sh/Homebrew-Security-and-Supply-Chain#casks-have-a-different-trust-model&quot;&gt;Casks have a different trust model&lt;/a&gt;), but what&#39;s going on seems to be:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;macOS on AArch64 won&#39;t run ARM64 code that doesn&#39;t have a signature, but even an &quot;ad-hoc&quot; one is fine (&lt;a rel=&quot;external&quot; href=&quot;https://support.apple.com/en-au/guide/security/secebb113be1/1/web/1#sec75fb361d2&quot;&gt;source&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;The linker &lt;em&gt;does&lt;/em&gt; &lt;a rel=&quot;external&quot; href=&quot;https://users.rust-lang.org/t/how-to-create-macos-bundles-for-apple-silicon-they-always-seem-broken/132678/2&quot;&gt;sign the binaries&lt;/a&gt; from &lt;code&gt;cargo build&lt;/code&gt; with an ad-hoc signature, so that&#39;s fine&lt;/li&gt;
&lt;li&gt;Homebrew Cask &lt;a rel=&quot;external&quot; href=&quot;https://github.com/Homebrew/brew/blob/edb70f031e4170c780799633a1226ff73e1077f4/Library/Homebrew/cask/quarantine.rb#L221&quot;&gt;marks downloaded binaries as downloaded&lt;/a&gt; by setting the &lt;code&gt;com.apple.quarantine&lt;/code&gt; xattr on them (and is quite reasonably &lt;a rel=&quot;external&quot; href=&quot;https://github.com/Homebrew/brew/issues/20755#issuecomment-3330984446&quot;&gt;removing support for not doing that&lt;/a&gt;)&lt;/li&gt;
&lt;li&gt;Trying to run a binary with the &lt;code&gt;quarantine&lt;/code&gt; xattr on it triggers Gatekeeper, which by default requires the binary to be both signed with an Apple Developer ID and then &lt;em&gt;also&lt;/em&gt; notarised by Apple.  Notarisation requires the binary be uploaded to Apple and pass some malware checks, and if it passes, Apple issues a notarisation ticket that Gatekeeper can verify.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;You can allow-list binaries, but it&#39;s being made increasingly difficult - Sequoia &lt;a rel=&quot;external&quot; href=&quot;https://developer.apple.com/news/?id=saqachfa&quot;&gt;removed the control-click&lt;/a&gt; workaround for this and the current workaround is a temporary button in Settings → Privacy &amp;amp; Security:&lt;/p&gt;
&lt;figure class=&quot;article-figure&quot;&gt;
  &lt;img src=&quot;https://ertius.org/til/2026-09-20/override.png&quot; alt=&quot;Settings dialog allowing binaries to be exempted from Gatekeeper so they can be run&quot; width=&quot;924&quot; height=&quot;183&quot; loading=&quot;lazy&quot; decoding=&quot;async&quot;&gt;
  &lt;figcaption&gt;Overriding it&lt;/figcaption&gt;
&lt;/figure&gt;
&lt;p&gt;So, that was something of a waste of time.  Options to make it work:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Get an Apple Developer account myself and have the binaries signed and notarised&lt;/li&gt;
&lt;li&gt;Add &lt;code&gt;xattr -d com.apple.quarantine&lt;/code&gt; to the cask and bypass all this&lt;/li&gt;
&lt;li&gt;Instead of a &lt;em&gt;cask&lt;/em&gt;, create a &lt;em&gt;formula&lt;/em&gt; that uses &lt;code&gt;bin.install&lt;/code&gt; to simply install the binaries rather than building them, avoiding Casks&#39;s provenance checks entirely and trusting upstream to not distribute malware, and ignoring the source entirely&lt;/li&gt;
&lt;li&gt;Document that one needs to go to Settings and click two buttons after install and every update&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;None of these are excellent, and the other-other option is: make a normal Homebrew formula instead, which downloads the source and builds it or uses &lt;a rel=&quot;external&quot; href=&quot;https://docs.brew.sh/Bottles&quot;&gt;prebuilt binary&lt;/a&gt; &lt;em&gt;bottles&lt;/em&gt;, which is what I&#39;ll do next.&lt;/p&gt;
&lt;p&gt;So, lesson learnt: &lt;em&gt;casks&lt;/em&gt; are only sensible for binaries where upstream has already interacted with Apple to have them signed and notarised.&lt;/p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Very Partial Git Commits</title>
        <published>2026-02-08T00:00:00+00:00</published>
        <updated>2026-02-08T00:00:00+00:00</updated>
        
        <author>
          <name>rweir@ertius.org (Rob Weir)</name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://ertius.org/til/2026-02-08/"/><id>/til/2026-02-08/</id>
        <content type="html" xml:base="https://ertius.org/til/2026-02-08/">&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https://magit.vc&quot;&gt;&lt;code&gt;magit&lt;/code&gt;&lt;/a&gt; is of course the best &lt;code&gt;git&lt;/code&gt; client there
is, in particular because of how easy it makes curating the
index/staging area.  You can select individual hunks and go down to
marking individual lines for staging, and so I often end up spending a
lot of time crafting a commit.  A downside of this is that most of the
time my index is in some very specific state and so if I want to
commit something else, e.g. a typo fix or a dependency or something
that&#39;s not super related to the current change, I can&#39;t easily do so -
I would need to &lt;code&gt;stash&lt;/code&gt; and &lt;code&gt;add&lt;/code&gt; and &lt;code&gt;commit&lt;/code&gt; and &lt;code&gt;unstash&lt;/code&gt;, and so I
basically never do.&lt;/p&gt;
&lt;p&gt;Turns out someone thought of this and added a great new&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-1-1&quot;&gt;&lt;a href=&quot;https://ertius.org/til/2026-02-08/#fn-1&quot;&gt;[1]&lt;/a&gt;&lt;/sup&gt; feature to
&lt;code&gt;git&lt;/code&gt; - &lt;code&gt;-o&lt;/code&gt; / &lt;code&gt;--only&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;$ git add some_file.txt &amp;amp;&amp;amp; git commit -o -m&amp;quot;add some_file.txt&amp;quot; some_file.txt&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;A should-not-have-been-surprising-to-me quirk is that it&#39;s filtering
the &lt;em&gt;index&lt;/em&gt; not the tree, and so you need to stage it first.&lt;/p&gt;
&lt;section class=&quot;footnotes&quot;&gt;
&lt;ol class=&quot;footnotes-list&quot;&gt;
&lt;li id=&quot;fn-1&quot;&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https://git.kernel.org/pub/scm/git/git.git/commit/?id=5a798fb57f&quot;&gt;added &lt;code&gt;2006-02-05 16:08:01 -0800&lt;/code&gt; to ... &lt;strong&gt;&lt;code&gt;git-commit.sh&lt;/code&gt;&lt;/strong&gt;&lt;/a&gt; &lt;a href=&quot;https://ertius.org/til/2026-02-08/#fr-1-1&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>I just want to mirror 10GB</title>
        <published>2026-02-05T00:00:00+00:00</published>
        <updated>2026-02-05T00:00:00+00:00</updated>
        
        <author>
          <name>rweir@ertius.org (Rob Weir)</name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://ertius.org/til/2026-02-05/"/><id>/til/2026-02-05/</id>
        <content type="html" xml:base="https://ertius.org/til/2026-02-05/">&lt;p&gt;I use a few third-party &lt;code&gt;apt&lt;/code&gt; repositories on my servers, which is
very convenient, but can also be slightly annoying:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;kanidm&lt;/code&gt; uses GitHub Pages, which still isn&#39;t available via IPv6 in
the year of our lord 2026&lt;/li&gt;
&lt;li&gt;&lt;code&gt;smallstep&lt;/code&gt; has some bizarre DNS load balancing config that is both
IPv4-only and has long &lt;code&gt;CNAME&lt;/code&gt; chains that make resolution
unreliable for me (which is possibly my fault!)&lt;/li&gt;
&lt;li&gt;&lt;code&gt;incus&lt;/code&gt; releases very frequently and removes older packages, and I
prefer to pin exact package versions for big complicated (but good!
very good!) things like Incus which makes it regularly be
uninstallable on a new host because the last release I pinned is
gone from their repo&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;So, it seemed like time to set up a local mirror of this small amount of data
that I would like to have reliably available.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;debmirror&lt;/code&gt; was the obvious first choice for me, but no variation of
&lt;code&gt;--ignore=&quot;binary-all&quot;&lt;/code&gt; that I could contrive would make it stop
trying to fetch the non-existent &lt;code&gt;binary-all&lt;/code&gt; arch:&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Feb 05 10:50:07 myhost systemd[1]: Starting debmirror@kanidm.service - Mirror third-party apt repository: kanidm...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Feb 05 10:50:07 myhost debmirror-sync.sh[462970]: === Syncing mirror: kanidm ===&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Feb 05 10:50:07 myhost debmirror-sync.sh[462970]: Host: kanidm.github.io&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Feb 05 10:50:07 myhost debmirror-sync.sh[462970]: Root: /kanidm_ppa&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Feb 05 10:50:07 myhost debmirror-sync.sh[462970]: Dists: bookworm,trixie&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Feb 05 10:50:07 myhost debmirror-sync.sh[462970]: Sections: stable&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Feb 05 10:50:07 myhost debmirror-sync.sh[462970]: Archs: amd64,arm64&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Feb 05 10:50:07 myhost debmirror-sync.sh[462970]: Destination: /srv/apt-mirror/kanidm&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Feb 05 10:50:07 myhost debmirror-sync.sh[462970]: Running: debmirror --method=https --host=kanidm.github.io --root=/kanidm_ppa --dist=bookworm,trixie --section=stable --arch=amd64,arm64 --keyring=/etc/apt/keyrings/thirdparty-mirror/kanidm_ppa.gpg --nosource --ignore-missing-release --ignore-small-errors --timeout=300 --rsync-extra=none --diff=none --progress /srv/apt-mirror/kanidm&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Feb 05 10:50:07 myhost debmirror-sync.sh[462972]: Warning: --rsync-extra is not configured to mirror the trace files.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Feb 05 10:50:07 myhost debmirror-sync.sh[462972]:          This configuration is not recommended.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Feb 05 10:50:07 myhost debmirror-sync.sh[462972]: Mirroring to /srv/apt-mirror/kanidm from https://anonymous@kanidm.github.io/kanidm_ppa/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Feb 05 10:50:07 myhost debmirror-sync.sh[462972]: Arches: amd64,arm64&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Feb 05 10:50:07 myhost debmirror-sync.sh[462972]: Dists: bookworm,trixie&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Feb 05 10:50:07 myhost debmirror-sync.sh[462972]: Sections: stable&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Feb 05 10:50:07 myhost debmirror-sync.sh[462972]: Pdiff mode: none&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Feb 05 10:50:07 myhost debmirror-sync.sh[462972]: Will clean up after mirroring.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Feb 05 10:50:07 myhost debmirror-sync.sh[462972]: Attempting to get lock ...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Feb 05 10:50:07 myhost debmirror-sync.sh[462972]: Getting meta files ...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Feb 05 10:50:07 myhost debmirror-sync.sh[462972]: [168B blob data]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Feb 05 10:50:07 myhost debmirror-sync.sh[462972]: ok&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Feb 05 10:50:07 myhost debmirror-sync.sh[462972]: [180B blob data]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Feb 05 10:50:07 myhost debmirror-sync.sh[462972]: ok&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Feb 05 10:50:08 myhost debmirror-sync.sh[462972]: [149B blob data]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Feb 05 10:50:08 myhost debmirror-sync.sh[462972]: ok&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Feb 05 10:50:08 myhost debmirror-sync.sh[462972]: [196B blob data]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Feb 05 10:50:08 myhost debmirror-sync.sh[462972]: ok&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Feb 05 10:50:08 myhost debmirror-sync.sh[462972]: [208B blob data]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Feb 05 10:50:08 myhost debmirror-sync.sh[462972]: ok&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Feb 05 10:50:08 myhost debmirror-sync.sh[462972]: [140B blob data]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Feb 05 10:50:08 myhost debmirror-sync.sh[462972]: ok&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Feb 05 10:50:08 myhost debmirror-sync.sh[462972]: Ignoring missing Release file for dists/bookworm/stable/binary-all/Packages.gz&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Feb 05 10:50:08 myhost debmirror-sync.sh[462972]: [235B blob data]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Feb 05 10:50:08 myhost debmirror-sync.sh[462972]: Download of dists/bookworm/stable/binary-all/Packages.gz failed: 404 Not Found&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Feb 05 10:50:08 myhost debmirror-sync.sh[462972]: Ignoring missing Release file for dists/trixie/stable/binary-all/Packages.gz&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Feb 05 10:50:08 myhost debmirror-sync.sh[462972]: [231B blob data]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Feb 05 10:50:08 myhost debmirror-sync.sh[462972]: Download of dists/trixie/stable/binary-all/Packages.gz failed: 404 Not Found&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Feb 05 10:50:08 myhost debmirror-sync.sh[462972]: Failed to download some Package, Sources or Release files!&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Feb 05 10:50:08 myhost debmirror-sync.sh[462972]: WARNING: releasing 1 pending lock...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Feb 05 10:50:08 myhost debmirror-sync.sh[462972]: Errors:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Feb 05 10:50:08 myhost debmirror-sync.sh[462972]:  Ignoring missing Release file for dists/bookworm/stable/binary-all/Packages.gz&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Feb 05 10:50:08 myhost debmirror-sync.sh[462972]:  Download of dists/bookworm/stable/binary-all/Packages.gz failed: 404 Not Found&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Feb 05 10:50:08 myhost debmirror-sync.sh[462972]:  Ignoring missing Release file for dists/trixie/stable/binary-all/Packages.gz&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Feb 05 10:50:08 myhost debmirror-sync.sh[462972]:  Download of dists/trixie/stable/binary-all/Packages.gz failed: 404 Not Found&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Feb 05 10:50:08 myhost debmirror-sync.sh[462970]: === Sync failed with exit code 2 ===&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;(I think it is &lt;a rel=&quot;external&quot; href=&quot;https://bugs.debian.org/944139&quot;&gt;this bug&lt;/a&gt;).&lt;/p&gt;
&lt;p&gt;&lt;code&gt;aptly&lt;/code&gt; looked nice for try #2, and claims to support exactly this -
mirroring third party repositories - but as far as I could tell it had
no support for &lt;em&gt;mirroring&lt;/em&gt; repository &lt;em&gt;signatures&lt;/em&gt;, making clients in
2026 quite unhappy:&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Error: The repository &amp;#39;https://somehost.example.org/thirdparty/kanidm trixie Release&amp;#39; is not signed.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Notice: Updating from such a repository can&amp;#39;t be done securely, and is therefore disabled by default.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I uh would really rather not have to set up my own secure remote
package signing system for my very basic mirror.&lt;/p&gt;
&lt;p&gt;Attempt #3 to just use &lt;code&gt;wget&lt;/code&gt; to spider files doesn&#39;t work since some
of the repositories are hosted on GitHub Pages, which doesn&#39;t do
normal directory indexes.&lt;/p&gt;
&lt;p&gt;Try #4 was &lt;code&gt;apt-mirror2&lt;/code&gt;, which is blessedly itself packaged in
Debian, and Just Works - it basically just takes some &lt;code&gt;sources.list&lt;/code&gt;
lines and some paths and does the thing:&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# apt-mirror2 config for kanidm&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;# Generated by Ansible&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;set base_path         /srv/apt-mirror&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;set mirror_path       /srv/apt-mirror/public&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;set skel_path         /srv/apt-mirror/.skel&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;set var_path          /srv/apt-mirror/.var&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;set nthreads          4&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;set gpg_verify        on&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;set etc_trusted_parts /srv/apt-mirror/.gnupg&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;deb [arch=amd64,arm64 signed-by=/srv/apt-mirror/.gnupg/kanidm_ppa.gpg] https://kanidm.github.io/kanidm_ppa bookworm stable&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;deb [arch=amd64,arm64 signed-by=/srv/apt-mirror/.gnupg/kanidm_ppa.gpg] https://kanidm.github.io/kanidm_ppa trixie stable&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;It is quite surprising that this is much much more fiddly than running
my own full-Debian mirror is - that was half an hour of fiddling with
&lt;a rel=&quot;external&quot; href=&quot;https://www.debian.org/mirror/ftpmirror&quot;&gt;&lt;code&gt;ftpsync&lt;/code&gt;&lt;/a&gt; and it was done.&lt;/p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Artisanal Filesystem Hacking With systemd</title>
        <published>2026-01-31T00:00:00+00:00</published>
        <updated>2026-01-31T00:00:00+00:00</updated>
        
        <author>
          <name>rweir@ertius.org (Rob Weir)</name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://ertius.org/til/2026-01-31/"/><id>/til/2026-01-31/</id>
        <content type="html" xml:base="https://ertius.org/til/2026-01-31/">&lt;p&gt;A service I started running some instances of a while ago is &lt;a rel=&quot;external&quot; href=&quot;https://atlas.ripe.net/&quot;&gt;RIPE
Atlas&lt;/a&gt;, a distributed dns/ping/traceroute
probing tool run by &lt;a rel=&quot;external&quot; href=&quot;https://www.ripe.net&quot;&gt;RIPE&lt;/a&gt;.  It is pretty easy
to deploy - they provide an &lt;code&gt;apt&lt;/code&gt; repository, that has a package in it
that installs an &lt;code&gt;apt&lt;/code&gt; config that gives you access to the packages.
Once it&#39;s installed, &lt;a rel=&quot;external&quot; href=&quot;https://github.com/RIPE-NCC/ripe-atlas-probe-doc/blob/master/manuals/Debian13-binary.en.md&quot;&gt;it produces an SSH public
key&lt;/a&gt;
that you paste into a web page and away it goes.&lt;/p&gt;
&lt;p&gt;It is however not super flexible to operate.  One thing I wanted to do
was configure it to use an external resolver instead of the local
&lt;code&gt;unbound&lt;/code&gt; instance I have that is full of weird config hax for my
internal network.  As far as I could tell there&#39;s no config option
anywhere for this and I really wanted to avoid editing any of the
files in the package.  Once again, &lt;code&gt;systemd&lt;/code&gt; saves the day - just put
the resolver config in &lt;code&gt;/etc/ripe-atlas/resolv.conf&lt;/code&gt; and a drop-in
file in &lt;code&gt;/etc/systemd/system/ripe-atlas.service.d/dns.conf&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;ini&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-8 z-d-7&quot;&gt;[&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-16&quot;&gt;Service&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-7&quot;&gt;]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-9 z-d-17&quot;&gt;BindReadOnlyPaths&lt;/span&gt;&lt;span class=&quot;z-d-7&quot;&gt;=&lt;/span&gt;&lt;span&gt;/etc/ripe-atlas/resolv.conf:/etc/resolv.conf&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;et voila.  Once again a thing I would probably not have bothered to do
in the pre-&lt;code&gt;systemd&lt;/code&gt; era - it is easy to add a &quot;mount --bind&quot; line to
a &lt;code&gt;sysvinit&lt;/code&gt; script but that would mean hacking a shell script from a
package (albeit a &lt;code&gt;conffile&lt;/code&gt;), which is annoying going forward
(telling &lt;code&gt;dpkg&lt;/code&gt; to leave it alone) and much more annoying to
automate - telling Ansible to insert a line into a text file in
roughly the right place is much more annoying than just dropping two
files on disk:&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;yaml&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-d-7&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-4&quot;&gt; n&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-4&quot;&gt;ame&lt;/span&gt;&lt;span class=&quot;z-d-7&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-9&quot;&gt; D&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-9&quot;&gt;eploy RIPE Atlas custom resolv.conf&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-2 z-d-4&quot;&gt;  a&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-4&quot;&gt;nsible.builtin.template&lt;/span&gt;&lt;span class=&quot;z-d-7&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-2 z-d-4&quot;&gt;    s&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-4&quot;&gt;rc&lt;/span&gt;&lt;span class=&quot;z-d-7&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-9&quot;&gt; r&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-9&quot;&gt;ipe-atlas-resolv.conf.j2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-2 z-d-4&quot;&gt;    d&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-4&quot;&gt;est&lt;/span&gt;&lt;span class=&quot;z-d-7&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-9&quot;&gt; /&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-9&quot;&gt;etc/ripe-atlas/resolv.conf&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-2 z-d-4&quot;&gt;    o&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-4&quot;&gt;wner&lt;/span&gt;&lt;span class=&quot;z-d-7&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-9&quot;&gt; r&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-9&quot;&gt;oot&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-2 z-d-4&quot;&gt;    g&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-4&quot;&gt;roup&lt;/span&gt;&lt;span class=&quot;z-d-7&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-9&quot;&gt; r&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-9&quot;&gt;oot&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-2 z-d-4&quot;&gt;    m&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-4&quot;&gt;ode&lt;/span&gt;&lt;span class=&quot;z-d-7&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-7&quot;&gt; &amp;#39;&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-9&quot;&gt;0644&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-7&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-2 z-d-4&quot;&gt;  n&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-4&quot;&gt;otify&lt;/span&gt;&lt;span class=&quot;z-d-7&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-d-7&quot;&gt;    -&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-7&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-9&quot;&gt;RIPE Atlas : restart service&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-7&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-d-7&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-4&quot;&gt; n&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-4&quot;&gt;ame&lt;/span&gt;&lt;span class=&quot;z-d-7&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-9&quot;&gt; C&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-9&quot;&gt;reate ripe-atlas service override directory&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-2 z-d-4&quot;&gt;  a&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-4&quot;&gt;nsible.builtin.file&lt;/span&gt;&lt;span class=&quot;z-d-7&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-2 z-d-4&quot;&gt;    p&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-4&quot;&gt;ath&lt;/span&gt;&lt;span class=&quot;z-d-7&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-9&quot;&gt; /&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-9&quot;&gt;etc/systemd/system/ripe-atlas.service.d&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-2 z-d-4&quot;&gt;    s&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-4&quot;&gt;tate&lt;/span&gt;&lt;span class=&quot;z-d-7&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-9&quot;&gt; d&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-9&quot;&gt;irectory&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-2 z-d-4&quot;&gt;    o&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-4&quot;&gt;wner&lt;/span&gt;&lt;span class=&quot;z-d-7&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-9&quot;&gt; r&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-9&quot;&gt;oot&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-2 z-d-4&quot;&gt;    g&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-4&quot;&gt;roup&lt;/span&gt;&lt;span class=&quot;z-d-7&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-9&quot;&gt; r&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-9&quot;&gt;oot&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-2 z-d-4&quot;&gt;    m&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-4&quot;&gt;ode&lt;/span&gt;&lt;span class=&quot;z-d-7&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-7&quot;&gt; &amp;#39;&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-9&quot;&gt;0755&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-7&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-d-7&quot;&gt;-&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-4&quot;&gt; n&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-4&quot;&gt;ame&lt;/span&gt;&lt;span class=&quot;z-d-7&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-9&quot;&gt; D&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-9&quot;&gt;eploy ripe-atlas DNS override&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-2 z-d-4&quot;&gt;  a&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-4&quot;&gt;nsible.builtin.template&lt;/span&gt;&lt;span class=&quot;z-d-7&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-2 z-d-4&quot;&gt;    s&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-4&quot;&gt;rc&lt;/span&gt;&lt;span class=&quot;z-d-7&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-9&quot;&gt; r&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-9&quot;&gt;ipe-atlas-dns.conf.j2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-2 z-d-4&quot;&gt;    d&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-4&quot;&gt;est&lt;/span&gt;&lt;span class=&quot;z-d-7&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-9&quot;&gt; /&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-9&quot;&gt;etc/systemd/system/ripe-atlas.service.d/dns.conf&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-2 z-d-4&quot;&gt;    o&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-4&quot;&gt;wner&lt;/span&gt;&lt;span class=&quot;z-d-7&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-9&quot;&gt; r&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-9&quot;&gt;oot&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-2 z-d-4&quot;&gt;    g&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-4&quot;&gt;roup&lt;/span&gt;&lt;span class=&quot;z-d-7&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-9&quot;&gt; r&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-9&quot;&gt;oot&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-2 z-d-4&quot;&gt;    m&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-4&quot;&gt;ode&lt;/span&gt;&lt;span class=&quot;z-d-7&quot;&gt;:&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-7&quot;&gt; &amp;#39;&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-9&quot;&gt;0644&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-7&quot;&gt;&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-2 z-d-4&quot;&gt;  n&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-4&quot;&gt;otify&lt;/span&gt;&lt;span class=&quot;z-d-7&quot;&gt;:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-d-7&quot;&gt;    -&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-7&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-9&quot;&gt;RIPE Atlas : daemon-reload&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-7&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-d-7&quot;&gt;    -&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-7&quot;&gt; &amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-9&quot;&gt;RIPE Atlas : restart service&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-7&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Which is actually quite verbose, but is extremely straight-forward and
depends on the &lt;code&gt;systemd&lt;/code&gt; configuration merge semantics rather than
luck at automatically hacking shell scripts.  I actually started
writing out an equivalent attempt using &lt;code&gt;ansible.builtin.lineinfile&lt;/code&gt;
to edit an init script to add a &lt;code&gt;mount --bind&lt;/code&gt; line after the header
(not correctly in the &lt;code&gt;start&lt;/code&gt; and torn down in &lt;code&gt;stop&lt;/code&gt; since that seems
way too hard), then remembered that in that world I&#39;d first need to
write enough &lt;code&gt;sh&lt;/code&gt; to put this service in a &lt;code&gt;chroot&lt;/code&gt; to begin with, so
that I could customise the &lt;code&gt;/etc/resolv.conf&lt;/code&gt; it saw.&lt;/p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Zola Asset Integrity</title>
        <published>2026-01-12T00:00:00+00:00</published>
        <updated>2026-01-12T00:00:00+00:00</updated>
        
        <author>
          <name>rweir@ertius.org (Rob Weir)</name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://ertius.org/til/2026-01-12/"/><id>/til/2026-01-12/</id>
        <content type="html" xml:base="https://ertius.org/til/2026-01-12/">&lt;p&gt;As a diligent Over Engineer, a while ago I added two things to how
Zola generates links to assets:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;code&gt;integrity&lt;/code&gt; attributes to CSS &lt;code&gt;&amp;lt;link&amp;gt;&lt;/code&gt;s, which means the browser
will reject CSS with the wrong hash&lt;/li&gt;
&lt;li&gt;&lt;code&gt;?h=0123456789abcdef&lt;/code&gt; faux-&lt;code&gt;GET&lt;/code&gt; params to the asset URLs
themselves, so that I can set long HTTP cache times on them&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;That looks like this in a Zola template:&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;html&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-d-3&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-4 z-d-b&quot;&gt;link&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-1 z-d-16&quot;&gt;    integrity&lt;/span&gt;&lt;span class=&quot;z-d-7&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-7&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-9&quot;&gt;sha384-{{ get_hash(path=&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-7&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-16&quot;&gt;css&lt;/span&gt;&lt;span class=&quot;z-l-7 z-l-i z-d-11&quot;&gt;/some.css&amp;quot;,&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-16&quot;&gt; sha_type&lt;/span&gt;&lt;span class=&quot;z-d-7&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-9&quot;&gt;384,&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-16&quot;&gt; base64&lt;/span&gt;&lt;span class=&quot;z-d-7&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-9&quot;&gt;true)&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-16&quot;&gt; |&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-16&quot;&gt; safe&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-16&quot;&gt; }}&lt;/span&gt;&lt;span class=&quot;z-l-7 z-l-i z-d-11&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-1 z-d-16&quot;&gt;    rel&lt;/span&gt;&lt;span class=&quot;z-d-7&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-7&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-9&quot;&gt;stylesheet&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-7&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-16&quot;&gt; href&lt;/span&gt;&lt;span class=&quot;z-d-7&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-7&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-9&quot;&gt;{{ get_url(cachebust=true, path=&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-7&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-16&quot;&gt;css&lt;/span&gt;&lt;span class=&quot;z-l-7 z-l-i z-d-11&quot;&gt;/some.css&amp;quot;)&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-16&quot;&gt; }}&lt;/span&gt;&lt;span class=&quot;z-l-7 z-l-i z-d-11&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-d-3&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;which produces output like this in the generated HTML:&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;html&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-d-3&quot;&gt;&amp;lt;&lt;/span&gt;&lt;span class=&quot;z-l-2 z-d-4 z-d-b&quot;&gt;link&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-1 z-d-16&quot;&gt;    integrity&lt;/span&gt;&lt;span class=&quot;z-d-7&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-7&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-9&quot;&gt;sha384-6d001da919b965dc3a4672b9d7ddce374d165452a2285f2753988842092ea6b9946645375cff3ede89a991c9698bfcea&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-7&quot;&gt;&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-1 z-d-16&quot;&gt;    rel&lt;/span&gt;&lt;span class=&quot;z-d-7&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-7&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-9&quot;&gt;stylesheet&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-7&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-1 z-d-16&quot;&gt; href&lt;/span&gt;&lt;span class=&quot;z-d-7&quot;&gt;=&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-7&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-9&quot;&gt;/css/some.css?h=0123456789abcdef&lt;/span&gt;&lt;span class=&quot;z-l-3 z-d-7&quot;&gt;&amp;quot;&lt;/span&gt;&lt;span class=&quot;z-d-3&quot;&gt;&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Thus letting the HTML assert what the assets loaded for it should look
like.  So, now, if a malicious TLA MITMs you or compromises the server
serving static assets, the browser will reject them (from the console
log):&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;[Error] Cannot load stylesheet http://127.0.0.1:1111/css/main.css?h=0123456789abcdef. Failed integrity metadata check. Content length: 7715, Expected content length:&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;7715, Expected metadata: sha384-6d001da919b965dc3a4672b9d7ddce374d165452a2285f2753988842092ea6b9946645375cff3ede89a991c9698bfcea&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;In other news, Zola has a &lt;code&gt;serve&lt;/code&gt;
&lt;a rel=&quot;external&quot; href=&quot;https://www.getzola.org/documentation/getting-started/cli-usage/#serve&quot;&gt;command&lt;/a&gt;
that runs a little dev server and reloads if any of the files change:&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;❯ mise run serve&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;[serve] $ zola serve --interface 0.0.0.0 --base-url / --port=${PORT:-1111} --drafts&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Building site...&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Checking all internal links with anchors.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&amp;gt; Successfully checked 0 internal link(s) with anchors.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;-&amp;gt; Creating 1 pages (0 orphan) and 0 sections&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Done in 7ms.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Web server is available at / (bound to 0.0.0.0:1111)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Listening for changes in /home/user/project/{config.toml,content,static,templates}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Press Ctrl+C to stop&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Change detected @ 2026-01-12 15:03:46&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;-&amp;gt; Static file changed /home/user/project/static/css/some.css&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Done in 2ms.&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;You can see at the bottom that it reloaded the CSS file that had changed.&lt;/p&gt;
&lt;p&gt;Unfortunately, &lt;a rel=&quot;external&quot; href=&quot;https://github.com/getzola/zola/issues/1817&quot;&gt;Zola doesn&#39;t tie these two features
together&lt;/a&gt; and if you use
integrity and edit the assets while &lt;code&gt;zola&lt;/code&gt; is running, then it will
start serving the new asset with the old HTML, and then the browser
will quite reasonably tell you to fuck off and stop loading the CSS.
Excitingly, browsers don&#39;t really show that this is happening anywhere
&lt;em&gt;except&lt;/em&gt; in the console log, and if you have multiple style sheets and
edited only one, the behaviour you will see is:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;everything is fine&lt;/li&gt;
&lt;li&gt;edit a CSS file&lt;/li&gt;
&lt;li&gt;reload page&lt;/li&gt;
&lt;li&gt;styles are all fucked up, and if you&#39;re like me, assume it&#39;s
because your edit was terrible&lt;/li&gt;
&lt;li&gt;think that&#39;s weird, let&#39;s blame caching or something&lt;/li&gt;
&lt;li&gt;restart zola&lt;/li&gt;
&lt;li&gt;everything is fine&lt;/li&gt;
&lt;li&gt;undo change to CSS file&lt;/li&gt;
&lt;li&gt;styles are all fucked up, and if you&#39;re like me, assume it&#39;s
because your edit was terrible&lt;/li&gt;
&lt;li&gt;etc&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;On the bug, user &lt;a rel=&quot;external&quot; href=&quot;https://github.com/legoktm&quot;&gt;legoktm&lt;/a&gt; provides a
&lt;a rel=&quot;external&quot; href=&quot;https://github.com/getzola/zola/issues/1817#issuecomment-2692552878&quot;&gt;pretty good
workaround&lt;/a&gt;,
that just removes the integrity attribute entirely when in local dev
serving mode:&lt;/p&gt;
&lt;p&gt;Firstly, add a new macro in &lt;code&gt;templates/macros.html&lt;/code&gt;:&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{% macro sri(path) -%}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{% if config.mode != &amp;quot;serve&amp;quot; -%}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;integrity=&amp;quot;sha384-{{ get_hash(path=path, sha_type=384, base64=true) | safe }}&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{%- endif %}&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{%- endmacro %}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Then at the top of &lt;code&gt;templates/base.html&lt;/code&gt; (or wherever your &lt;code&gt;&amp;lt;link&amp;gt;&lt;/code&gt; tags are done):&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;{% import &amp;quot;macros.html&amp;quot; as macros %}&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;and wherever you actually write out the &lt;code&gt;&amp;lt;link&amp;gt;&lt;/code&gt; in the templates, do this instead:&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;&amp;lt;link rel=&amp;quot;stylesheet&amp;quot; href=&amp;quot;{{ get_url(path=&amp;quot;static/some.css&amp;quot;, cachebust=true) }}&amp;quot;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;    {{macros::sri(path=&amp;quot;static/some.css&amp;quot;)}} /&amp;gt;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Git Spelunking</title>
        <published>2026-01-02T00:00:00+00:00</published>
        <updated>2026-01-02T00:00:00+00:00</updated>
        
        <author>
          <name>rweir@ertius.org (Rob Weir)</name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://ertius.org/til/2026-01-02/"/><id>/til/2026-01-02/</id>
        <content type="html" xml:base="https://ertius.org/til/2026-01-02/">&lt;p&gt;I wanted to find something in some commit, and while trying to
remember the right way to wrap around &lt;code&gt;git rev-list --all&lt;/code&gt;, I found
that &lt;code&gt;git&lt;/code&gt; grew an option to just do that: &lt;code&gt;git log -G&amp;lt;regexp&amp;gt; --branches --all&lt;/code&gt;&lt;sup class=&quot;footnote-reference&quot; id=&quot;fr-1-1&quot;&gt;&lt;a href=&quot;https://ertius.org/til/2026-01-02/#fn-1&quot;&gt;[1]&lt;/a&gt;&lt;/sup&gt;.&lt;/p&gt;
&lt;p&gt;And when was it added?  Let&#39;s find out:&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;❯ git log -G&amp;quot;-G&amp;quot; --pretty=format:&amp;quot;%h%x09%x09%ad%x09%s&amp;quot; --reverse -- Documentation/diff-options.txt&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;f506b8e8b5      2010-08-23 10:17:03 -0700   git log/diff: add -G&amp;lt;regexp&amp;gt; that greps in the patch text&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;5bc3f0b567      2013-05-31 17:42:15 +0530   diffcore-pickaxe doc: document -S and -G properly&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;9299f84921      2020-02-06 21:53:01 +0100   diff-options.txt: avoid &amp;quot;regex&amp;quot; overload in example&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;6b552e39c0      2024-11-18 22:05:50 +0000   doc: git-diff: apply format changes to diff-options&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;1f010d6bdf      2025-01-20 01:56:02 +0000   doc: use .adoc extension for AsciiDoc files&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;section class=&quot;footnotes&quot;&gt;
&lt;ol class=&quot;footnotes-list&quot;&gt;
&lt;li id=&quot;fn-1&quot;&gt;
&lt;p&gt;&lt;a rel=&quot;external&quot; href=&quot;https://stackoverflow.com/a/2928721&quot;&gt;https://stackoverflow.com/a/2928721&lt;/a&gt; &lt;a href=&quot;https://ertius.org/til/2026-01-02/#fr-1-1&quot;&gt;↩&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/section&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Java In The Browser In The Year 2025</title>
        <published>2025-12-01T00:00:00+00:00</published>
        <updated>2025-12-01T00:00:00+00:00</updated>
        
        <author>
          <name>rweir@ertius.org (Rob Weir)</name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://ertius.org/til/2025-12-01/"/><id>/til/2025-12-01/</id>
        <content type="html" xml:base="https://ertius.org/til/2025-12-01/">&lt;p&gt;Sometime one needs to use an ancient version of &lt;code&gt;java&lt;/code&gt;, but since
Oracle is in charge, obviously the official process is a nightmare.
Fortunately some excellent person &lt;a rel=&quot;external&quot; href=&quot;https://gist.github.com/wavezhang/ba8425f24a968ec9b2a8619d7c2d86a6?permalink_comment_id=5534373#gistcomment-5534373&quot;&gt;wrote a list of urls from other
companies who surely have permission to offer said binaries, all
available without logging in to
Oracle&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;This installs it to &lt;code&gt;/Library/Internet\ Plug-Ins/JavaAppletPlugin.plugin/Contents/Home/&lt;/code&gt;, however
OpenWebstart, since it&#39;s an app bundle or something, is unable to use
that, so:&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;shellsession&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-1&quot;&gt;sudo mkdir /opt/jre8&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-1&quot;&gt;cd /opt/jre8&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-1&quot;&gt;sudo cp -r &amp;quot;/Library/Internet\ Plug-Ins/JavaAppletPlugin.plugin/Contents/Home/&amp;quot; .&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Now you can point OpenWebstart at &lt;code&gt;/opt/jre8&lt;/code&gt;, but whatever GUI
toolkit it&#39;s using is quite terrible, so you must go to &lt;code&gt;/opt&lt;/code&gt;,
highlight &lt;code&gt;jre8&lt;/code&gt; and then click &quot;&lt;em&gt;Choose&lt;/em&gt;&quot;.&lt;/p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>ZFS micro incompatibilities</title>
        <published>2025-11-30T00:00:00+00:00</published>
        <updated>2025-11-30T00:00:00+00:00</updated>
        
        <author>
          <name>rweir@ertius.org (Rob Weir)</name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://ertius.org/til/2025-11-30/"/><id>/til/2025-11-30/</id>
        <content type="html" xml:base="https://ertius.org/til/2025-11-30/">&lt;p&gt;I&#39;ve been setting up ZFS replication between some servers, but between
one pair, every sync was failed with:&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Nov 30 11:07:11 sourcehost syncoid[890260]: Sending incremental tank/enc/var/spool@autosnap_2025-11-27_20:00:22_monthly ... autosnap_2025-11-30_11:00:39_hourly (~ 555 KB):&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Nov 30 11:07:12 sourcehost syncoid[890982]: warning: cannot send &amp;#39;tank/enc/var/spool@autosnap_2025-11-27_20:00:22_weekly&amp;#39;: Invalid argument&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Source machine (which was on the way to being upgraded to &lt;code&gt;trixie&lt;/code&gt; but
hadn&#39;t been rebooted yet):&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;plain&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;root@sourcehost:~# uname -a&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;Linux sourcehost 6.1.0-37-amd64 #1 SMP PREEMPT_DYNAMIC Debian 6.1.140-1 (2025-05-22) x86_64 GNU/Linux&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;root@sourcehost:~# zfs version&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;zfs-2.3.2-2&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span&gt;zfs-kmod-2.3.1-1~bpo12+1&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;I had assumed it was some incompatibility with the destination machine
and spent ages trying to track that down until I read the error more
carefully - cannot &lt;em&gt;send&lt;/em&gt;, ie the problem is with the &lt;code&gt;zfs&lt;/code&gt; tool on
&lt;em&gt;sourcehost&lt;/em&gt;, before it even talks to the destination.&lt;/p&gt;
&lt;p&gt;Eventually I found a
&lt;a rel=&quot;external&quot; href=&quot;https://github.com/openzfs/zfs/issues/17323&quot;&gt;reference&lt;/a&gt; to a bug in
&lt;code&gt;openzfs&lt;/code&gt; &lt;code&gt;2.3.1&lt;/code&gt; that broke the user-space API, and then &lt;code&gt;2.3.2&lt;/code&gt;
reverted the breakage, which broke compatibility with &lt;code&gt;2.3.1&lt;/code&gt; itself.
Going through PRs from between 2.3.1 and 2.3.2, it&#39;s
&lt;a rel=&quot;external&quot; href=&quot;https://github.com/openzfs/zfs/issues/17330&quot;&gt;this&lt;/a&gt;, and here&#39;s &lt;a rel=&quot;external&quot; href=&quot;https://github.com/openzfs/zfs/pull/17137&quot;&gt;the
explanation of the accidental ABI change
change&lt;/a&gt;&lt;/p&gt;
&lt;p&gt;A reboot in to the new kernel with the new, same-versioned &lt;code&gt;zfs&lt;/code&gt;
userspace and kernel module fixed it.&lt;/p&gt;
</content>
        
    </entry>
    <entry xml:lang="en">
        <title>Automounting ZFS encrypted filesystems</title>
        <published>2025-11-27T00:00:00+00:00</published>
        <updated>2025-11-27T00:00:00+00:00</updated>
        
        <author>
          <name>rweir@ertius.org (Rob Weir)</name>
        </author>
        
        <link rel="alternate" type="text/html" href="https://ertius.org/til/2025-11-27/"/><id>/til/2025-11-27/</id>
        <content type="html" xml:base="https://ertius.org/til/2025-11-27/">&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;shellsession&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-1&quot;&gt;zfs set keylocation=file:///etc/some-secret-path dataset/enrypted&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;And that&#39;s all that&#39;s needed - well, and a &lt;code&gt;systemctl daemon-reload&lt;/code&gt;
to actually generate the units.  Before that, you can see what
&lt;code&gt;zfs-mount-generator&lt;/code&gt; plans to do:&lt;/p&gt;
&lt;pre class=&quot;giallo z-l-code z-d-code&quot; &gt;&lt;code data-lang=&quot;shellsession&quot;&gt;&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-d-7&quot;&gt;$&lt;/span&gt;&lt;span&gt; mkdir /tmp/zfs-gen/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-d-7&quot;&gt;$&lt;/span&gt;&lt;span&gt; /usr/lib/systemd/system-generators/zfs-mount-generator /tmp/zfs-gen/&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-d-7&quot;&gt;$&lt;/span&gt;&lt;span&gt; cat /tmp/zfs-gen/zfs-load-key@dataset-enrypted.service&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-d-7&quot;&gt;#&lt;/span&gt;&lt;span&gt; Automatically generated by zfs-mount-generator&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-1&quot;&gt;[Unit]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-1&quot;&gt;Description=Load ZFS key for dataset/encrypted&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-1&quot;&gt;SourcePath=/etc/zfs/zfs-list.cache/dataset&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-1&quot;&gt;Documentation=man:zfs-mount-generator(8)&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-1&quot;&gt;DefaultDependencies=no&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-1&quot;&gt;Wants=&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-1&quot;&gt;After=&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-1&quot;&gt;RequiresMountsFor=&amp;#39;/etc/some-secret-path&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-1&quot;&gt;[Service]&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-1&quot;&gt;Type=oneshot&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-1&quot;&gt;RemainAfterExit=yes&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-d-7&quot;&gt;#&lt;/span&gt;&lt;span&gt; This avoids a dependency loop involving systemd-journald.socket &lt;/span&gt;&lt;span class=&quot;z-l-9 z-d-17&quot;&gt;if&lt;/span&gt;&lt;span class=&quot;z-l-8 z-d-16&quot;&gt; this&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-d-7&quot;&gt;#&lt;/span&gt;&lt;span&gt; dataset is a parent of the root filesystem.&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-1&quot;&gt;StandardOutput=null&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-1&quot;&gt;StandardError=null&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-1&quot;&gt;ExecStart=/bin/sh -euc &amp;#39;[ &amp;quot;$$(/usr/sbin/zfs get -H -o value keystatus &amp;quot;dataset/encrypted&amp;quot;)&amp;quot; = &amp;quot;unavailable&amp;quot; ] || exit 0;exec /usr/sbin/zfs load-key &amp;quot;dataset/encrypted&amp;quot;&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-1&quot;&gt;ExecStop=/bin/sh -euc &amp;#39;[ &amp;quot;$$(/usr/sbin/zfs get -H -o value keystatus &amp;quot;dataset/encrypted&amp;quot;)&amp;quot; = &amp;quot;available&amp;quot; ] || exit 0;exec /usr/sbin/zfs unload-key &amp;quot;dataset/encrypted&amp;quot;&amp;#39;&lt;/span&gt;&lt;/span&gt;
&lt;span class=&quot;giallo-l&quot;&gt;&lt;span class=&quot;z-l-1&quot;&gt;~&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;
&lt;p&gt;Which shows that it&#39;s just a service that loads the key at startup and
unloads the key on shutdown, exactly as you&#39;d want.  Note that it also
set a mount dependency on the location the key is stored, so that this
can be stored on another e.g. another encrypted filesystem that itself
needs to be unlocked.&lt;/p&gt;
&lt;p&gt;This all assumes you&#39;ve done the &lt;code&gt;zfs-zed&lt;/code&gt; dance to hook ZFS in to
&lt;code&gt;systemd&lt;/code&gt; to begin with; if not, the Debian manpage &lt;a rel=&quot;external&quot; href=&quot;https://manpages.debian.org/trixie/zfsutils-linux/zfs-mount-generator.8.en.html#EXAMPLES&quot;&gt;explains how to
do that
bit&lt;/a&gt;.&lt;/p&gt;
</content>
        
    </entry>
</feed>
