An interactive git rebase

I recently happened upon an article by Julia Evans on what can go wrong when rebasing in Git. This made me realise that I should probably talk about my favourite, yet obscure, Git feature.

When using commit you can use --fixup <commitid> or --squash <commitid> to create a commit that can be automatically fixup’d or squashed on the next rebase with --autosquash. This is handy, but you need to know the commitid beforehand.

There is a type of refspec that can resolve a regular expression to the commitid of a matching commit: :/<RegExp>. This will find the ID of the most recent commit (not necessarily on your current branch) with message matching /<RegExp>/, and resolve to that.

It’s a killer feature with --fixup and --squash: in a pinch, you can create fixes to past commits that

  1. you only vaguely remember the message of, and
  2. Git can automatically move (autosquash) in the next interactive rebase.
Continue reading
Posted in tip.

At the time of this writing, this blog runs on a Bitnami WordPress image, but I have changed the configuration to run multiple sites (WP_ALLOW_MULTISITE and MULTISITE in the wp-config.php). I realised I had issues running scheduled events using DISABLE_WP_CRON when the ActivityPub plugin failed to send new posts to subscribers. This was confirmed by the site health dashboard, indicating that scheduled events were late.

As it turns out, when manually running the script with sudo -u daemon /opt/bitnami/php/bin/php /opt/bitnami/wordpress/wp-cron.php (with WP_DEBUG enabled) complains of an undeclared HTTP_HOST, and terminates quickly. As soon as I set that variable in the environment and reran the script, the warning was gone, and the script took longer to run. All my recent post also made it to the fediverse!

Continue reading

I’ve never had a personal Twitter account, mainly for fear of the time sink and doom-scrolling. I wanted to avoid both. I recently obtained an invite to BlueSky, which I took, out of curiosity. The next obvious thing to do was to open an account on the Fediverse, and use that (I had one on a self-hosted Nextcloud Social instance, but the server is now firewalled, so not quite social enough).

I quite like the liveliness and congeniality of the discussion there, and I was glad to find a few familiar faces, some that I have been following for decades before. It’s nice to receive everything in one place. Though it does revive my fears of time-sink.

This blog is now also a node in the fediverse, you can follow what I post here at When thinking more about how to make it useful, I also realised that I have a number of ongoing projects that I work on-and-off on. So far, I have been keeping progress notes, and writing a longer blog post in the end. With this integration with the Fediverse, I want to try something new, posting quick updates about progress, blockers and discoveries.

I’ll use the freshly minted µblog category, along with a tag per project, to classify those posts. They will not be displayed on the main page, but will pushed via the fediverse to willing followers. I’ll still write full articles in the end

GnuPG sometimes gets confused about which SmartCard a subkey is on, and refuses to use it from the currently-available card.

tl;dr: Here’s a quick script to fix the issue.

$ export SUBKEYID=...
$ KEYGRIP=$(gpg --with-keygrip -k ${SUBKEYID} | sed -n "/${SUBKEYID}/,/$/{s/ *Keygrip = //p}" )
$ rm -i ~/.gnupg/private-keys-v1.d/${KEYGRIP}.key
$ gpg --card-status  # recreate the stub from the daily-use key
Continue reading

When working on many feature branches, they tend to accumulate in the local Git clone. Even if they get deleted in upstream shared repos, they need to be cleared locally, too, otherwise they will stick around forever.

Here’s a quick one-liner to clean up every branch that is fully merged to main. It does make sure not to delete main and develop, though.

git branch -d $(git branch --merged main | grep -vE '(^\*|master|main|develop)')
Continue reading
Screenshot of a terminal showing oft-used commands

As idle musing, and a way to show off my mastery of shell pipelines, I was wondering what my most-used shell commands are. It’s an easy few commands to pipe.

history | sed 's/^ *//;s/ \+/ /g' | cut -d' ' -f 2 | sort | uniq -c | sort -n | tail -n 20

The outcome is rather expected. I feel validated (by my shell) in my own self-perception!

Continue reading

When migrating a database from MySQL to PostgreSQL, I bumped into a slight issue with timestamp formatting. PostgreSQL supports many date/time formats, but no native support to output ISO-8601 UTC time & date format (e.g., 2023-08-05T13:54:22Z), favouring consistency with RFC3339 instead.

ISO 8601 specifies the use of uppercase letter T to separate the date and time. PostgreSQL accepts that format on input, but on output it uses a space rather than T, as shown above. This is for readability and for consistency with RFC 3339 as well as some other database systems.

Fortunately, StackOverflow had a solution, including some notes about how to handle timestamps with timezones.

SELECT to_char(now() AT TIME ZONE 'Etc/Zulu', 'yyyy-mm-dd"T"hh24:mi:ss"Z"');
A few HomeAssistant cards showing SNMP monitoring of speed and quota of an upstring ISP.

I finally fell for the smart-home mania when I needed to read a few Zigbee climate sensors, and started using Home Assistant. There was no return from it, and I gradually grew the number of sensors and automations. This is all the easier thanks to a very active community site, offering many a recipe and troubleshooting advice. This is where I found a bandwidth monitor based on SNMP metrics that has been functional for a while.

My ISP, Internode (no longer the awesome service it used to be 10 years ago), has become increasingly flaky, silently dropping support for their Customer Tools API. This API was useful to track quota usage in a number of tools, including my own Munin plugin. Because of this, I unwittingly, and without warning, went beyond my monthly quota this month. I had to double my monthly bill to buy additional data blocks to tie me over.

It became obvious that I needed a new way to track my usage. What could be better than HomeAssistant, which was already ingesting SNMP data from the router? I posted my updated solution in the original thread, but thought that it might be worth duplicating here.

Continue reading
A diagram of a CloudFormation template creating a TLS-secured CloudFront distribution serving content from an S3 bucket.

As I mentioned in a previous post, I am migrating a number of static websites from Apache on bare metal to an object store and a CDN in the cloud. Namely, this is AWS S3 and CloudFront. To avoid too much manual grooming of pet yaks, I also went directly for Infrastructure-as-Code with CloudFormation, with the objective of creating a relatively simple reusable web+CDN template.

This is not a new topic, and a number of resources already exist around the web. I, for example, started with this one, which does a fairly decent job. There are, however, a number of fine details which I have found were tricky to get right, could lead into incompatibilities, and for which accurate documentation was hard to find (even ChatGPT failed to provide a correct answer, though this is not entirely surprising).

ChatGPT confidently states things that aren’t true.

The goal of this post is to call those out, and provide the CloudFormation template mentioned above for those looking for a base. The template will:

  1. create an S3 bucket for use as a website endpoint
  2. create a CloudFront distribution using that bucket as an Origin
  3. create a few DNS entries
  4. create a TLS certificate for the service


Continue reading