<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom"><title>simonh.uk - software</title><link href="https://simonh.uk/" rel="alternate"></link><link href="https://simonh.uk/feeds/software.atom.xml" rel="self"></link><id>https://simonh.uk/</id><updated>2026-05-30T00:00:00+01:00</updated><subtitle>Simon Harrison :: Burton on Trent :: UK</subtitle><entry><title>First Sourceforge Project - hgweb Templates</title><link href="https://simonh.uk/2026/05/30/first-sourceforge-project-hgweb-templates/" rel="alternate"></link><published>2026-05-30T00:00:00+01:00</published><updated>2026-05-30T00:00:00+01:00</updated><author><name>Simon Harrison</name></author><id>tag:simonh.uk,2026-05-30:/2026/05/30/first-sourceforge-project-hgweb-templates/</id><summary type="html">	&lt;p&gt;Let&amp;#8217;s improve hgweb on Sourceforge&lt;/p&gt;</summary><content type="html">	&lt;p&gt;&lt;img alt="Sourceforge logo" src="/img/logo/sourceforge.svg" title="Sourceforge logo" /&gt;&lt;/p&gt;

	&lt;p&gt;I&amp;#8217;ve just created a repo on Sourceforge called &lt;a href="https://sourceforge.net/projects/hgweb-templates/"&gt;hgweb-templates&lt;/a&gt;&lt;/p&gt;

	&lt;p&gt;Why? And more importantly, why Sourceforge? Well, I chose SF as they have out of the box support for Mercurial. Plus they&amp;#8217;ve been around forever. The reason for the repository is that there are few changes / improvements I&amp;#8217;d like to make. My current preferred template is gitweb, so I&amp;#8217;ve started with that.&lt;/p&gt;

	&lt;p&gt;The first issue has been bugging me for a while. I have about 30 repo&amp;#8217;s on one of my servers. The index page has links to &lt;span class="caps"&gt;RSS&lt;/span&gt; / Atom feeds which probably makes sense on a public server, but on a private one, used only by me &amp;#8212; no sense at all. What I wanted instead was a link to the repository files. Using the gitweb template required clicking on the repo name, then clicking on the files menu icon. Sure, not the end of the world, but annoying when there was a place on the index page that was being wasted. &lt;/p&gt;

	&lt;p&gt;To my surprise, this first task was completed in about ten minutes! &lt;/p&gt;

	&lt;p class="hand"&gt;Gitweb before&lt;/p&gt;

	&lt;p&gt;&lt;img alt="Screenshot of original gitweb" src="/img/2026-05-30/gitweb-old.webp" title="Screenshot of original gitweb" /&gt;&lt;/p&gt;

	&lt;p class="hand"&gt;Gitweb after&lt;/p&gt;

	&lt;p&gt;&lt;img alt="Screenshot of gitweb-mod" src="/img/2026-05-30/gitweb-new.webp" title="Screenshot of gitweb-mod" /&gt;&lt;/p&gt;

	&lt;p&gt;Feel free to have a poke about the repo and if you have any useful customisations, please let me know.&lt;/p&gt;</content><category term="software"></category><category term="VCS"></category><category term="Mercurial"></category><category term="Sourcforge"></category></entry><entry><title>Getting Started with Mercurial (HG)</title><link href="https://simonh.uk/2026/05/25/getting-started-with-mercurial-hg/" rel="alternate"></link><published>2026-05-25T00:00:00+01:00</published><updated>2026-05-28T00:00:00+01:00</updated><author><name>Simon Harrison</name></author><id>tag:simonh.uk,2026-05-25:/2026/05/25/getting-started-with-mercurial-hg/</id><summary type="html">	&lt;p&gt;Git? Sorry never heard of it.&lt;/p&gt;</summary><content type="html">	&lt;p&gt;&lt;img alt="Mercurial logo" src="/img/logo/mercurial.svg" title="Mercurial logo" /&gt;&lt;/p&gt;

	&lt;p&gt;&lt;a href="https://www.mercurial-scm.org/"&gt;Mercurial&lt;/a&gt; doesn&amp;#8217;t get a lot of love nowadays, but as I&amp;#8217;ve been using it pretty much every day for about eight or nine years, I thought it might be time to remind The Internet that it still, very much is, a thing. One of the reasons I decided to write this post was this 2025 graph from &lt;a href="https://rhodecode.com/blog/156/version-control-systems-popularity-in-2025"&gt;rhodecode&lt;/a&gt; summarising developers preferred &lt;span class="caps"&gt;VCS&lt;/span&gt;&lt;/p&gt;

	&lt;p&gt;&lt;img alt="VCS market share 2025" src="/img/2026-05-25/vcs_chart.webp" title="VCS market share 2025" /&gt;&lt;/p&gt;

	&lt;p&gt;Sadly, there are nearly four times as many people using &lt;em&gt;nothing&lt;/em&gt; as those using Mercurial! I&amp;#8217;m not going to judge, or berate those people as I was one of them some years ago. I&amp;#8217;ll probably write about that in another post. But if &lt;strong&gt;one&lt;/strong&gt; person reads this post and at least tries Mercurial, I&amp;#8217;ll be happy&amp;#8230;&lt;/p&gt;

	&lt;p class="info"&gt;In this post, I&amp;#8217;m using a throwaway, demo project and I&amp;#8217;d advise anyone reading to do the same, until you&amp;#8217;re comfortable with Mercurial concepts and commands. I&amp;#8217;m also very lazy so if a command has a short option, I&amp;#8217;ll be using that in the examples below.&lt;/p&gt;

	&lt;h2&gt;Installation&lt;/h2&gt;

	&lt;p&gt;See &lt;a href="https://www.mercurial-scm.org/install"&gt;here&lt;/a&gt;&lt;/p&gt;

	&lt;h1&gt;hg help&lt;/h1&gt;

	&lt;p&gt;The most important command. &lt;/p&gt;

&lt;pre&gt;&lt;code&gt;Mercurial Distributed SCM

list of commands:

Repository creation:

 clone         make a copy of an existing repository
 init          create a new repository in the given directory
 qclone        clone main and patch repository at same time

Remote repository management:

 incoming      show new changesets found in source
 outgoing      show changesets not found in the destination
 paths         show aliases for remote repositories
 pull          pull changes from the specified source
 push          push changes to the specified destination
 serve         start stand-alone webserver

Change creation:

 absorb        incorporate corrections into the stack of draft changesets
 commit        commit the specified files or all outstanding changes
:&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;Just run &lt;code&gt;hg help &amp;lt;command&amp;gt;&lt;/code&gt; replacing &lt;code&gt;&amp;lt;command&amp;gt;&lt;/code&gt; with an actual command. For example &lt;code&gt;hg help init&lt;/code&gt; if you&amp;#8217;ve forgotten what init does. The documentation is very good, I&amp;#8217;ve found. &lt;/p&gt;

	&lt;h2&gt;hg status&lt;/h2&gt;

	&lt;p&gt;I&amp;#8217;ve already added a few files for the purposes of this demo. We&amp;#8217;ll run &lt;code&gt;hg st&lt;/code&gt; to see what needs to be done.&lt;/p&gt;

	&lt;p&gt;You can run &lt;code&gt;hg st&lt;/code&gt; to see the &lt;code&gt;status&lt;/code&gt; of your reposistory&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;[simon@computer 09:45:37] ~/tmp/hg-demo
$ hg st
abort: no repository found in &amp;#39;/home/simon/tmp/hg-demo&amp;#39; (.hg not found)&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;In this case, Mercurial helpfully tells us that we don&amp;#8217;t have a repository in this directory (yet). Let&amp;#8217;s create one&lt;/p&gt;

	&lt;h2&gt;hg init&lt;/h2&gt;

&lt;pre&gt;&lt;code&gt;[simon@computer 10:00:23] ~/tmp/hg-demo
$ hg init&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;If we forget that we&amp;#8217;ve created a repo and try to create one again, Mercurial won&amp;#8217;t allow that&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;[simon@computer 10:01:10] default ~/tmp/hg-demo
$ hg init
abort: repository . already exists&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;We&amp;#8217;ll run &lt;code&gt;hg st&lt;/code&gt; again to see where we are&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;[simon@computer 10:01:08] default ~/tmp/hg-demo
$ hg st
? bottle-sqlite-master/.gitignore
? bottle-sqlite-master/.travis.yml
? bottle-sqlite-master/LICENSE
? bottle-sqlite-master/README.rst
? bottle-sqlite-master/bottle_sqlite.py
? bottle-sqlite-master/setup.py
? bottle-sqlite-master/test.py
? bottle-sqlite-master/tox.ini&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;The &lt;code&gt;?&lt;/code&gt; simply means that the listed files / directories are currently unknown to Mercurial. We need to add them first&lt;/p&gt;

	&lt;h2&gt;hg add&lt;/h2&gt;

	&lt;p&gt;We can either add them individually, or add them all as a batch. I&amp;#8217;m lazy so I&amp;#8217;ll let Mercurial figure it out&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ hg add
adding bottle-sqlite-master/.gitignore
adding bottle-sqlite-master/.travis.yml
adding bottle-sqlite-master/LICENSE
adding bottle-sqlite-master/README.rst
adding bottle-sqlite-master/bottle_sqlite.py
adding bottle-sqlite-master/setup.py
adding bottle-sqlite-master/test.py
adding bottle-sqlite-master/tox.ini&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;Running &lt;code&gt;hg st&lt;/code&gt; again lets us know that the files have been added, but not committed (or checked in, as I prefer) to our repo&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;[simon@computer 10:04:53] default ~/tmp/hg-demo
$ hg st
A bottle-sqlite-master/.gitignore
A bottle-sqlite-master/.travis.yml
A bottle-sqlite-master/LICENSE
A bottle-sqlite-master/README.rst
A bottle-sqlite-master/bottle_sqlite.py
A bottle-sqlite-master/setup.py
A bottle-sqlite-master/test.py
A bottle-sqlite-master/tox.ini&lt;/code&gt;&lt;/pre&gt;

	&lt;h2&gt;hg ci&lt;/h2&gt;

	&lt;p&gt;Running &lt;code&gt;hg ci&lt;/code&gt; will open up our default editor and let us write a commit message&lt;/p&gt;

&lt;pre&gt;&lt;code&gt; GNU nano 9.0          /tmp/hg-editor-rw5uklht.commit.hg.txt *          I      

Add bottle-sqlite files                                                         

HG: Enter commit message.  Lines beginning with &amp;#39;HG:&amp;#39; are removed.              
HG: Leave message empty to abort commit.                                        
HG: --                                                                          
HG: user: Simon Harrison &amp;lt;simon@simonh.uk&amp;gt;                              
HG: branch &amp;#39;default&amp;#39;                                                            
HG: added bottle-sqlite-master/.gitignore                                       
HG: added bottle-sqlite-master/.travis.yml                                      
HG: added bottle-sqlite-master/LICENSE                                          
HG: added bottle-sqlite-master/README.rst                                       
HG: added bottle-sqlite-master/bottle_sqlite.py                                 
HG: added bottle-sqlite-master/setup.py                                         
HG: added bottle-sqlite-master/test.py                                          
HG: added bottle-sqlite-master/tox.ini  &lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;If we run &lt;code&gt;hg ci&lt;/code&gt; again when nothing has changed we get &lt;/p&gt;

&lt;pre&gt;&lt;code&gt;[simon@computer 10:19:55] default ~/tmp/hg-demo
$ hg ci
nothing changed&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;We can avoid the editor by passing &lt;code&gt;-m&lt;/code&gt; to Mercurial&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;[simon@computer 10:19:55] default ~/tmp/hg-demo
$ hg ci -m &amp;quot;I changed something, somewhere&amp;quot;&lt;/code&gt;&lt;/pre&gt;

	&lt;h2&gt;hg log&lt;/h2&gt;

	&lt;p&gt;At any time, we can see what chages we&amp;#8217;ve committed to our repo&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;[simon@computer 10:07:45] default ~/tmp/hg-demo
$ hg log 
changeset:   0:3f082894d145
tag:         tip
user:        Simon Harrison &amp;lt;simon@simonh.uk&amp;gt;
date:        Mon May 25 10:07:32 2026 +0100
summary:     Add bottle-sqlite files&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;As you can see, I&amp;#8217;ve got one changeset. They say it&amp;#8217;s always good to have a &lt;span class="caps"&gt;README&lt;/span&gt;, so let&amp;#8217;s add one of them&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;[simon@computer 10:22:46] default ~/tmp/hg-demo
$ hg st
? README&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;We&amp;#8217;ll add our new file specifically this time&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;[simon@computer 10:26:03] default ~/tmp/hg-demo
$ hg add README 
[simon@computer 10:26:51] default ~/tmp/hg-demo
$ hg st
A README&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;And check it in with a short log message&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;[simon@computer 10:28:07] default ~/tmp/hg-demo
$ hg ci -m &amp;quot;Add README&amp;quot;&lt;/code&gt;&lt;/pre&gt;

	&lt;h2&gt;hg log -p&lt;/h2&gt;

	&lt;p&gt;If we want to know what the actual changes were in a commit, we can pass the &lt;code&gt;-p&lt;/code&gt; for &lt;em&gt;patch&lt;/em&gt;&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;[simon@computer 10:28:31] default ~/tmp/hg-demo
$ hg log -p -r tip
changeset:   1:f45ecf76aaf0
tag:         tip
user:        Simon Harrison &amp;lt;simon@simonh.uk&amp;gt;
date:        Mon May 25 10:28:17 2026 +0100
summary:     Add README

diff -r 3f082894d145 -r f45ecf76aaf0 README
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/README    Mon May 25 10:28:17 2026 +0100
@@ -0,0 +1,1 @@
+This is just a test repo for a blog post.&lt;/code&gt;&lt;/pre&gt;

	&lt;h2&gt;hg clean&lt;/h2&gt;

	&lt;p&gt;What if you&amp;#8217;ve added a file (or files) to your working directory, but realise you don&amp;#8217;t want them in there, actually? Look at this. A random Perl script is in our project! &lt;/p&gt;

&lt;pre&gt;&lt;code&gt;[simon@computer 10:43:24] default ~/tmp/hg-demo
$ hg st
? first.pl&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;How did that get in here? Of course, we could just delete it using the shell or a file manager, but Mercurial has a useful command &lt;code&gt;clean&lt;/code&gt; to get rid of such things&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;[simon@computer 10:43:31] default ~/tmp/hg-demo
$ hg clean
permanently delete 1 unknown files? (yN) y
[simon@computer 10:43:53] default ~/tmp/hg-demo&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;Let&amp;#8217;s check it really has gone&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ ll
total 20K
drwxrwxr-x 4 simon simon 4.0K 2026-05-25 10:43 .
drwxrwxrwx 8 simon simon 4.0K 2026-05-25 09:58 ..
drwxrwxr-x 2 simon simon 4.0K 2020-10-03 16:27 bottle-sqlite-master
drwxrwxr-x 5 simon simon 4.0K 2026-05-25 10:56 .hg
-rw-rw-r-- 1 simon simon   42 2026-05-25 10:21 README&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;This can come in very useful. I quite often &lt;code&gt;pip install&lt;/code&gt; to a folder in my working directory. Except this time, I forget to install to &lt;code&gt;lib/pip&lt;/code&gt; &lt;/p&gt;

&lt;pre&gt;&lt;code&gt;[simon@computer 11:04:00] default ~/tmp/hg-demo
$ pip3 install -t . openpyxl
Collecting openpyxl
  Using cached openpyxl-3.1.5-py2.py3-none-any.whl.metadata (2.5 kB)
Collecting et-xmlfile (from openpyxl)
  Using cached et_xmlfile-2.0.0-py3-none-any.whl.metadata (2.7 kB)
Using cached openpyxl-3.1.5-py2.py3-none-any.whl (250 kB)
Using cached et_xmlfile-2.0.0-py3-none-any.whl (18 kB)
Installing collected packages: et-xmlfile, openpyxl
Successfully installed et-xmlfile-2.0.0 openpyxl-3.1.5&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;Running &lt;code&gt;hg st&lt;/code&gt; shows that I made a boo boo.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;? et_xmlfile-2.0.0.dist-info/AUTHORS.txt
? et_xmlfile-2.0.0.dist-info/INSTALLER
? et_xmlfile-2.0.0.dist-info/LICENCE.python
? et_xmlfile-2.0.0.dist-info/LICENCE.rst
? et_xmlfile-2.0.0.dist-info/METADATA
? et_xmlfile-2.0.0.dist-info/RECORD
? et_xmlfile-2.0.0.dist-info/WHEEL
? et_xmlfile-2.0.0.dist-info/top_level.txt
? et_xmlfile/__init__.py
? et_xmlfile/__pycache__/__init__.cpython-312.pyc
? et_xmlfile/__pycache__/incremental_tree.cpython-312.pyc
? et_xmlfile/__pycache__/xmlfile.cpython-312.pyc
? et_xmlfile/incremental_tree.py
? et_xmlfile/xmlfile.py
? openpyxl-3.1.5.dist-info/INSTALLER
? openpyxl-3.1.5.dist-info/LICENCE.rst
? openpyxl-3.1.5.dist-info/METADATA
? openpyxl-3.1.5.dist-info/RECORD
? openpyxl-3.1.5.dist-info/REQUESTED
? openpyxl-3.1.5.dist-info/WHEEL
? openpyxl-3.1.5.dist-info/top_level.txt
? openpyxl/__init__.py
? openpyxl/__pycache__/__init__.cpython-312.pyc
:&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;But no matter, now we know about &lt;code&gt;hg clean&lt;/code&gt;&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;[simon@computer 11:07:19] default ~/tmp/hg-demo
$ hg clean
permanently delete 401 unknown files? (yN) y
[simon@computer 11:07:28] default ~/tmp/hg-demo&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;And everything is back as it should be&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ ll
total 20K
drwxrwxr-x 4 simon simon 4.0K 2026-05-25 11:07 .
drwxrwxrwx 8 simon simon 4.0K 2026-05-25 09:58 ..
drwxrwxr-x 2 simon simon 4.0K 2020-10-03 16:27 bottle-sqlite-master
drwxrwxr-x 5 simon simon 4.0K 2026-05-25 11:07 .hg
-rw-rw-r-- 1 simon simon   42 2026-05-25 10:21 README&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;Running &lt;code&gt;hg log&lt;/code&gt; again shows that our repo has not been effected in any way&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;[simon@computer 11:07:31] default ~/tmp/hg-demo
$ hg log
changeset:   1:f45ecf76aaf0
tag:         tip
user:        Simon Harrison &amp;lt;simon@simonh.uk&amp;gt;
date:        Mon May 25 10:28:17 2026 +0100
summary:     Add README

changeset:   0:3f082894d145
user:        Simon Harrison &amp;lt;simon@simonh.uk&amp;gt;
date:        Mon May 25 10:07:32 2026 +0100
summary:     Add bottle-sqlite files&lt;/code&gt;&lt;/pre&gt;

	&lt;h2&gt;hg absorb&lt;/h2&gt;

	&lt;p&gt;At this point, I&amp;#8217;d like to introduce you to a Mercurial extension called &amp;#8220;absorb&amp;#8221;. I started using it only a few months ago, but let me tell you &amp;#8211; it&amp;#8217;s amazing!&lt;sup class="footnote" id="fnrev750a140db119431ab570a6dd02e8776c-1"&gt;&lt;a href="#fn750a140db119431ab570a6dd02e8776c-1"&gt;1&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;

	&lt;p&gt;Very often, particularly when working on a new project, you&amp;#8217;ll be making &lt;em&gt;lots&lt;/em&gt; of changes to the same files, trying to get them working correctly. And therefore, you&amp;#8217;ll be making lots of commits which just really add noise to your log. You might have:&lt;/p&gt;

	&lt;ul&gt;
		&lt;li&gt;add section to &lt;span class="caps"&gt;README&lt;/span&gt;&lt;/li&gt;
		&lt;li&gt;add another section to &lt;span class="caps"&gt;README&lt;/span&gt;&lt;/li&gt;
		&lt;li&gt;add yet another section to &lt;span class="caps"&gt;README&lt;/span&gt;&lt;/li&gt;
		&lt;li&gt;fix typo in &lt;span class="caps"&gt;README&lt;/span&gt;&lt;/li&gt;
		&lt;li&gt;etc.&lt;/li&gt;
	&lt;/ul&gt;

	&lt;p&gt;We&amp;#8217;ve already got at least four commits that aren&amp;#8217;t very informative. Absorb will insert new commits into old commits thereby giving you a nice clean log, with only one commit. In the example below, I&amp;#8217;ve made a note to myself to mention the absorb extension. I then instruct Mercurial to commit into the exising log entry &lt;/p&gt;

&lt;pre&gt;&lt;code&gt;[simon@computer 11:17:02] default ~/tmp/hg-demo
$ hg st
M README
[simon@computer 11:17:04] default ~/tmp/hg-demo
$ hg absorb
showing changes for README
        @@ -1,0 +1,3 @@
f45ecf7 +
f45ecf7 +Note: remember to write about hg absorb
f45ecf7 +

1 changesets affected
f45ecf7 Add README
apply changes (y/N)?  y
saved backup bundle to /home/simon/tmp/hg-demo/.hg/strip-backup/f45ecf76aaf0-07614989-absorb.hg
1 of 1 chunk(s) applied&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;Now I don&amp;#8217;t normally use the word &amp;#8220;neat&amp;#8221;, but I&amp;#8217;ve got to say, that&amp;#8217;s neat.&lt;/p&gt;

	&lt;h2&gt;hg export&lt;/h2&gt;

	&lt;p&gt;The &amp;#8220;export&amp;#8221; command will show the patch information for a changeset. Not specifying one will show the latest changeset called &lt;code&gt;tip&lt;/code&gt; &lt;/p&gt;

&lt;pre&gt;&lt;code&gt;[simon@computer 11:22:09] default ~/tmp/hg-demo
$ hg export
# HG changeset patch
# User Simon Harrison &amp;lt;simon@simonh.uk&amp;gt;
# Date 1779701297 -3600
#      Mon May 25 10:28:17 2026 +0100
# Node ID 9ac81759eac4cb041cb910172a50754d47a539d9
# Parent  3f082894d145de9bea6d87745be40831683d659d
Add README

diff -r 3f082894d145 -r 9ac81759eac4 README
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/README    Mon May 25 10:28:17 2026 +0100
@@ -0,0 +1,4 @@
+This is just a test repo for a blog post.
+
+Note: remember to write about hg absorb
+&lt;/code&gt;&lt;/pre&gt;

	&lt;h2&gt;~/.hgrc&lt;/h2&gt;

	&lt;p&gt;Mercurial will check to see if you have a &lt;code&gt;.hgrc&lt;/code&gt; file in your home directory. Mine is below. The only thing you need to know about right now is the &lt;code&gt;[extensions]&lt;/code&gt; section with:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;absorb = &lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;Which will enable the absorb extension&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;[simon@computer 11:22:14] default ~/tmp/hg-demo
$ cat ~/.hgrc
# $Id: .hgrc,v 1.2 2024/09/30 14:59:53 simon Exp simon $

# example user config (see &amp;#39;hg help config&amp;#39; for more info)

[ui]
# name and email, e.g.
# username = Jane Doe &amp;lt;jdoe@example.com&amp;gt;
username = Simon Harrison &amp;lt;web@simonh.uk&amp;gt;
editor = nano -/
# We recommend enabling tweakdefaults to get slight improvements to
# the UI over time. Make sure to set HGPLAIN in the environment when
# writing scripts!
tweakdefaults = True
merge=internal:merge

# uncomment to disable command output pagination
# (see &amp;#39;hg help pager&amp;#39; for details)
# paginate = never

[extensions]
convert = 
patchbomb = 
absorb = 
mq = 

[alias]
slog = log --stat -r
br = branch
bs = co stable
bd = co default
md = merge default
ms = merge stable
glog = log -G
ds = diff -r stable:default
dd = diff -r default:stable

[diff]
nobinary = True
git = False&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;Let&amp;#8217;s add openpyxl to our project (and in the right place)&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;[simon@computer 12:28:15] default ~/tmp/hg-demo
$ pip3 install -t lib/pip openpyxl
Collecting openpyxl
  Using cached openpyxl-3.1.5-py2.py3-none-any.whl.metadata (2.5 kB)
Collecting et-xmlfile (from openpyxl)
  Using cached et_xmlfile-2.0.0-py3-none-any.whl.metadata (2.7 kB)
Using cached openpyxl-3.1.5-py2.py3-none-any.whl (250 kB)
Using cached et_xmlfile-2.0.0-py3-none-any.whl (18 kB)
Installing collected packages: et-xmlfile, openpyxl
Successfully installed et-xmlfile-2.0.0 openpyxl-3.1.5&lt;/code&gt;&lt;/pre&gt;

	&lt;h2&gt;hg checkout&lt;/h2&gt;

	&lt;p&gt;At any time, we can jump around our changesets or revisions. This is called updating or checking out (as I prefer) a revision. Let&amp;#8217;s go back to the very beginning of our repo&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;[simon@computer 12:32:34] default ~/tmp/hg-demo
$ hg co -r0
0 files updated, 0 files merged, 402 files removed, 0 files unresolved&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;Mercurial has thrown away everything our working directory that didn&amp;#8217;t exist at revision 0. &lt;/p&gt;

	&lt;p&gt;Sometimes we want to give a name to a commit, mainly so we can refer to it easily and / or checkout that revision. We do that with tags.&lt;/p&gt;

	&lt;h2&gt;hg tag&lt;/h2&gt;

&lt;pre&gt;&lt;code&gt;[simon@computer 12:40:47] default ~/tmp/hg-demo
$ hg tag -r0 &amp;#39;zero&amp;#39;&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;This has two effects. One, it creates the named tag we specifed, and two, it creates a commit&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;[simon@computer 12:43:19] default ~/tmp/hg-demo
$ hg log 
changeset:   3:612f6977a3b8
tag:         tip
user:        Simon Harrison &amp;lt;simon@simonh.uk&amp;gt;
date:        Mon May 25 12:41:55 2026 +0100
summary:     Added tag zero for changeset 3f082894d145

changeset:   2:c74897799d7f
user:        Simon Harrison &amp;lt;simon@simonh.uk&amp;gt;
date:        Mon May 25 12:30:41 2026 +0100
summary:     Add openpyxl to lib/pip

changeset:   1:9ac81759eac4
user:        Simon Harrison &amp;lt;simon@simonh.uk&amp;gt;
date:        Mon May 25 10:28:17 2026 +0100
summary:     Add README

changeset:   0:3f082894d145
tag:         zero
user:        Simon Harrison &amp;lt;simon@simonh.uk&amp;gt;
date:        Mon May 25 10:07:32 2026 +0100
summary:     Add bottle-sqlite files&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;Let&amp;#8217;s have a look at the commit&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;[simon@computer 12:45:09] default ~/tmp/hg-demo
$ hg exp
# HG changeset patch
# User Simon Harrison &amp;lt;simon@simonh.uk&amp;gt;
# Date 1779709315 -3600
#      Mon May 25 12:41:55 2026 +0100
# Node ID 612f6977a3b82405ec0c78c4e0d7087340061450
# Parent  c74897799d7f5b33da8d3d65f9f1a665edfbdbee
Added tag zero for changeset 3f082894d145

diff -r c74897799d7f -r 612f6977a3b8 .hgtags
--- /dev/null   Thu Jan 01 00:00:00 1970 +0000
+++ b/.hgtags   Mon May 25 12:41:55 2026 +0100
@@ -0,0 +1,1 @@
+3f082894d145de9bea6d87745be40831683d659d zero&lt;/code&gt;&lt;/pre&gt;

	&lt;h2&gt;hg identify&lt;/h2&gt;

	&lt;p&gt;If we insist on bouncing around our changesets, it would be useful to quickly find out where we are. &amp;#8220;Identify&amp;#8221; or &amp;#8220;id&amp;#8221; is what we&amp;#8217;ll need to run&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;[simon@computer 12:52:55] default ~/tmp/hg-demo
$ hg id
612f6977a3b8 tip
[simon@computer 12:52:58] default ~/tmp/hg-demo
$ hg co zero
0 files updated, 0 files merged, 403 files removed, 0 files unresolved
[simon@computer 12:53:13] default ~/tmp/hg-demo
$ hg id
3f082894d145 zero&lt;/code&gt;&lt;/pre&gt;

	&lt;h2&gt;hg log -G&lt;/h2&gt;

	&lt;p&gt;We can also use &lt;code&gt;hg log -G&lt;/code&gt; to see where we are. The @ is where we currenly are&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;[simon@computer 13:11:55] default ~/tmp/hg-demo
$ hg log -G
o  changeset:   3:612f6977a3b8
|  tag:         tip
|  user:        Simon Harrison &amp;lt;simon@simonh.uk&amp;gt;
|  date:        Mon May 25 12:41:55 2026 +0100
|  summary:     Added tag zero for changeset 3f082894d145
|
o  changeset:   2:c74897799d7f
|  user:        Simon Harrison &amp;lt;simon@simonh.uk&amp;gt;
|  date:        Mon May 25 12:30:41 2026 +0100
|  summary:     Add openpyxl to lib/pip
|
o  changeset:   1:9ac81759eac4
|  user:        Simon Harrison &amp;lt;simon@simonh.uk&amp;gt;
|  date:        Mon May 25 10:28:17 2026 +0100
|  summary:     Add README
|
@  changeset:   0:3f082894d145
   tag:         zero
   user:        Simon Harrison &amp;lt;simon@simonh.uk&amp;gt;
   date:        Mon May 25 10:07:32 2026 +0100
   summary:     Add bottle-sqlite files&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;That&amp;#8217;s pretty helpful. Let&amp;#8217;s &lt;code&gt;update&lt;/code&gt; to our latest change&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;[simon@computer 13:11:57] default ~/tmp/hg-demo
$ hg co
403 files updated, 0 files merged, 0 files removed, 0 files unresolved
[simon@computer 13:13:51] default ~/tmp/hg-demo
$ hg log -G
@  changeset:   3:612f6977a3b8
|  tag:         tip
|  user:        Simon Harrison &amp;lt;simon@simonh.uk&amp;gt;
|  date:        Mon May 25 12:41:55 2026 +0100
|  summary:     Added tag zero for changeset 3f082894d145
|
o  changeset:   2:c74897799d7f
|  user:        Simon Harrison &amp;lt;simon@simonh.uk&amp;gt;
|  date:        Mon May 25 12:30:41 2026 +0100
|  summary:     Add openpyxl to lib/pip
|
o  changeset:   1:9ac81759eac4
|  user:        Simon Harrison &amp;lt;simon@simonh.uk&amp;gt;
|  date:        Mon May 25 10:28:17 2026 +0100
|  summary:     Add README
|
o  changeset:   0:3f082894d145
   tag:         zero
   user:        Simon Harrison &amp;lt;simon@simonh.uk&amp;gt;
   date:        Mon May 25 10:07:32 2026 +0100
   summary:     Add bottle-sqlite files&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;&lt;code&gt;hg id&lt;/code&gt; should agree with &lt;code&gt;hg log -G&lt;/code&gt;&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;[simon@computer 13:14:26] default ~/tmp/hg-demo
$ hg id
612f6977a3b8 tip&lt;/code&gt;&lt;/pre&gt;

	&lt;h2&gt;hg diff&lt;/h2&gt;

	&lt;p&gt;When we make changes to files already tracked by Mercurial, we can easily see what&amp;#8217;s changed by running &lt;code&gt;hg diff&lt;/code&gt;&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;[simon@computer 13:20:20] default ~/tmp/hg-demo
$ hg di
diff -r 612f6977a3b8 README
--- a/README    Mon May 25 12:41:55 2026 +0100
+++ b/README    Mon May 25 13:20:22 2026 +0100
@@ -1,4 +1,3 @@
 This is just a test repo for a blog post.

-Note: remember to write about hg absorb
-
+Remember to mention about hg diff&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;As you can see I&amp;#8217;ve replaced a line in &lt;span class="caps"&gt;README&lt;/span&gt;. Let&amp;#8217;s &lt;code&gt;absorb&lt;/code&gt; it.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;[simon@computer 13:22:09] default ~/tmp/hg-demo
$ hg absorb
showing changes for README
        @@ -2,2 +2,1 @@
9ac8175 -Note: remember to write about hg absorb
9ac8175 -
9ac8175 +Remember to mention about hg diff

1 changesets affected
9ac8175 Add README
apply changes (y/N)?  y
saved backup bundle to /home/simon/tmp/hg-demo/.hg/strip-backup/9ac81759eac4-5291bbfc-absorb.hg
1 of 1 chunk(s) applied&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;Can you see why I like &lt;code&gt;absorb&lt;/code&gt; so much now???&lt;/p&gt;

	&lt;h2&gt;hg backout&lt;/h2&gt;

	&lt;p&gt;Sometimes, you made a commit and you want to &amp;#8220;undo&amp;#8221; it. You wish you hadn&amp;#8217;t made the changes at all. &lt;code&gt;hg backout&lt;/code&gt; is like &lt;code&gt;ctrl-z&lt;/code&gt; for your repo. Maybe not, as you can backout any commits throughout the history of your repo. &lt;/p&gt;

	&lt;p&gt;I&amp;#8217;ve made a small change to the &lt;span class="caps"&gt;README&lt;/span&gt; and I&amp;#8217;ll check then commit it&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;[simon@computer 13:49:19] default ~/tmp/hg-demo
$ hg di
diff -r 5245de0c1b13 README
--- a/README    Mon May 25 12:41:55 2026 +0100
+++ b/README    Mon May 25 13:49:21 2026 +0100
@@ -1,3 +1,5 @@
 This is just a test repo for a blog post.

 Remember to mention about hg diff
+
+Today is very hot. Very hot indeed.&lt;/code&gt;&lt;/pre&gt;

&lt;pre&gt;&lt;code&gt;[simon@computer 13:52:59] default ~/tmp/hg-demo
$ hg ci -m &amp;quot;Small change to README&amp;quot;&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;But then, I realise that people probably don&amp;#8217;t care that it&amp;#8217;s hot today. What was I thinking?!&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;[simon@computer 13:53:46] default ~/tmp/hg-demo
$ hg backout -r4
reverting README
changeset 5:8da10bffb88e backs out changeset 4:fb966da0722c&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;And of course, running &lt;code&gt;hg log&lt;/code&gt; records what we did&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;changeset:   5:8da10bffb88e
tag:         tip
user:        Simon Harrison &amp;lt;simon@simonh.uk&amp;gt;
date:        Mon May 25 13:55:16 2026 +0100
summary:     Backed out changeset fb966da0722c

changeset:   4:fb966da0722c
user:        Simon Harrison &amp;lt;simon@simonh.uk&amp;gt;
date:        Mon May 25 13:52:53 2026 +0100
summary:     Small change to the README

changeset:   3:5245de0c1b13
user:        Simon Harrison &amp;lt;simon@simonh.uk&amp;gt;
date:        Mon May 25 12:41:55 2026 +0100
summary:     Added tag zero for changeset 3f082894d145

changeset:   2:80ba0b02fc09
user:        Simon Harrison &amp;lt;simon@simonh.uk&amp;gt;
date:        Mon May 25 12:30:41 2026 +0100
summary:     Add openpyxl to lib/pip

changeset:   1:59aa4d653c3f
user:        Simon Harrison &amp;lt;simon@simonh.uk&amp;gt;
:

If we really don&amp;#39;t want to keep a change, we have another command called&lt;/code&gt;&lt;/pre&gt;

	&lt;h2&gt;hg strip&lt;/h2&gt;

	&lt;p class="warn"&gt; &lt;span class="caps"&gt;USE&lt;/span&gt; &lt;span class="caps"&gt;WITH&lt;/span&gt; &lt;span class="caps"&gt;CAUTION&lt;/span&gt;.&lt;/p&gt;

	&lt;p&gt;Perhaps this would be better named as &amp;#8220;obliterate&amp;#8221; as that&amp;#8217;s what it does. Strip will remove everything after a particular commit. Let&amp;#8217;s say you have ten commits. if you run &lt;code&gt;hg strip -r5&lt;/code&gt; then everything from r5 onwards is deleted! In the example below, I&amp;#8217;ve chosen to strip the latest commit and as you see, -r4 is no more.  &lt;/p&gt;

&lt;pre&gt;&lt;code&gt;[simon@computer 13:41:38] default ~/tmp/hg-demo
$ hg strip -r4
saved backup bundle to /home/simon/tmp/hg-demo/.hg/strip-backup/2804913c9e0d-63a65735-backup.hg
[simon@computer 13:41:49] default ~/tmp/hg-demo
$ hg log
changeset:   3:5245de0c1b13
tag:         tip
user:        Simon Harrison &amp;lt;simon@simonh.uk&amp;gt;
date:        Mon May 25 12:41:55 2026 +0100
summary:     Added tag zero for changeset 3f082894d145

changeset:   2:80ba0b02fc09
user:        Simon Harrison &amp;lt;simon@simonh.uk&amp;gt;
date:        Mon May 25 12:30:41 2026 +0100
summary:     Add openpyxl to lib/pip

changeset:   1:59aa4d653c3f
user:        Simon Harrison &amp;lt;simon@simonh.uk&amp;gt;
date:        Mon May 25 10:28:17 2026 +0100
summary:     Add README

changeset:   0:3f082894d145
tag:         zero
user:        Simon Harrison &amp;lt;simon@simonh.uk&amp;gt;
date:        Mon May 25 10:07:32 2026 +0100
summary:     Add bottle-sqlite files&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;You&amp;#8217;ll notice that Mercurial informed us that a backup bundle (whatever that is) has been saved and gives us the path. Thus we can undo our strip!&lt;/p&gt;

	&lt;p&gt;We&amp;#8217;ll strip right back to our r0 revision&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;[simon@computer 13:59:24] default ~/tmp/hg-demo
$ hg strip -r0
0 files updated, 0 files merged, 9 files removed, 0 files unresolved
saved backup bundle to /home/simon/tmp/hg-demo/.hg/strip-backup/3f082894d145-8475fde9-backup.hg&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;And then &lt;code&gt;pull&lt;/code&gt; the bundle&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;[simon@computer 14:00:10] default ~/tmp/hg-demo
$ hg pull .hg/strip-backup/3f082894d145-8475fde9-backup.hg
pulling from .hg/strip-backup/3f082894d145-8475fde9-backup.hg
requesting all changes
adding changesets
adding manifests
adding file changes
added 18 changesets with 423 changes to 418 files (+1 heads)
new changesets 3f082894d145:24aaa8765ca4 (18 drafts)
(run &amp;#39;hg heads&amp;#39; to see heads, &amp;#39;hg merge&amp;#39; to merge)&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;Credit: This Stack Overflow &lt;a href="https://stackoverflow.com/questions/56148134/recovering-commits-lost-after-hg-strip"&gt;post&lt;/a&gt; for how to restore the bundle.&lt;/p&gt;

	&lt;h2&gt;hg files&lt;/h2&gt;

	&lt;p&gt;&lt;code&gt;hg files&lt;/code&gt; can be useful for a quick summary of which files were being tracked at a particular revision&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;[simon@computer 08:58:41] default ~/tmp/hg-demo
$ hg files -r0
bottle-sqlite-master/.gitignore
bottle-sqlite-master/.travis.yml
bottle-sqlite-master/LICENSE
bottle-sqlite-master/README.rst
bottle-sqlite-master/bottle_sqlite.py
bottle-sqlite-master/setup.py
bottle-sqlite-master/test.py
bottle-sqlite-master/tox.ini&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;If we have lots of files, we may just want a total&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;[simon@computer 09:02:27] default ~/tmp/hg-demo
$ hg files -r0 | wc -l
8&lt;/code&gt;&lt;/pre&gt;

&lt;pre&gt;&lt;code&gt;[simon@computer 09:03:21] default ~/tmp/hg-demo
$ hg files -r15 | wc -l
416&lt;/code&gt;&lt;/pre&gt;


	&lt;h2&gt;hg branch&lt;/h2&gt;

	&lt;p&gt;Branching let&amp;#8217;s you veer off from the default branch for various reasons. One might be to create a stable branch, which you merge bug fixes from your main / default branch. Another might be to work on some experimental feature (which may need to be scrapped). Either way, a branch separates your code into silo&amp;#8217;s which are effectively independent until merged back together. &lt;/p&gt;

	&lt;p&gt;In Mercurial, you create a new branch like so&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;[simon@computer 13:29:15] default ~/tmp/hg-demo
$ hg br &amp;quot;test-branch&amp;quot;
marked working directory as branch test-branch
(branches are permanent and global, did you want a bookmark?)&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;Once you&amp;#8217;ve done that, you&amp;#8217;ll need to commit for the branch to actually be created. I have created and committed the test-branch and added a &lt;span class="caps"&gt;HELLO&lt;/span&gt;_WORLD file&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;changeset:   8:148dfc191c11
branch:      test-branch
tag:         tip
user:        Simon Harrison &amp;lt;simon@simonh.uk&amp;gt;
date:        Mon May 25 14:23:57 2026 +0100
summary:     Add HELLO_WORLD to the test-branch

changeset:   7:e0d495cff8b9
branch:      test-branch
user:        Simon Harrison &amp;lt;simon@simonh.uk&amp;gt;
date:        Mon May 25 14:19:01 2026 +0100
summary:     Create test-branch

changeset:   6:a54d2f2f5c03
user:        Simon Harrison &amp;lt;simon@simonh.uk&amp;gt;
date:        Mon May 25 14:09:46 2026 +0100
summary:     Added the INSTALL file

changeset:   5:8da10bffb88e
user:        Simon Harrison &amp;lt;simon@simonh.uk&amp;gt;
date:        Mon May 25 13:55:16 2026 +0100
summary:     Backed out changeset fb966da0722c

:&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;Mercurial reports what branch we&amp;#8217;re on (if we are not on the default one). Now we can switch between branches using &lt;code&gt;update&lt;/code&gt;&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;[simon@computer 14:30:42] test-branch ~/tmp/hg-demo
$ hg co default
0 files updated, 0 files merged, 1 files removed, 0 files unresolved&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;Running &lt;code&gt;ll&lt;/code&gt; will show that the &lt;span class="caps"&gt;HELLO&lt;/span&gt;_WORLD file is invisible to the default branch as we created it in the test-branch&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;[simon@computer 14:30:47] default ~/tmp/hg-demo
$ ll
total 32K
drwxrwxr-x 5 simon simon 4.0K 2026-05-25 14:30 .
drwxrwxrwx 8 simon simon 4.0K 2026-05-25 14:11 ..
drwxrwxr-x 2 simon simon 4.0K 2020-10-03 16:27 bottle-sqlite-master
drwxrwxr-x 6 simon simon 4.0K 2026-05-25 14:30 .hg
-rw-rw-r-- 1 simon simon   46 2026-05-25 13:13 .hgtags
-rw-rw-r-- 1 simon simon   46 2026-05-25 14:09 INSTALL
drwxrwxr-x 3 simon simon 4.0K 2026-05-25 13:13 lib
-rw-rw-r-- 1 simon simon   77 2026-05-25 13:53 README&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;Updating to the test-branch brings &lt;span class="caps"&gt;HELLO&lt;/span&gt;_WORLD back&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;[simon@computer 14:32:10] default ~/tmp/hg-demo
$ hg co test-branch
1 files updated, 0 files merged, 0 files removed, 0 files unresolved
[simon@computer 14:32:34] test-branch ~/tmp/hg-demo
$ ll
total 36K
drwxrwxr-x 5 simon simon 4.0K 2026-05-25 14:32 .
drwxrwxrwx 8 simon simon 4.0K 2026-05-25 14:11 ..
drwxrwxr-x 2 simon simon 4.0K 2020-10-03 16:27 bottle-sqlite-master
-rw-rw-r-- 1 simon simon   14 2026-05-25 14:32 HELLO_wORLD
drwxrwxr-x 6 simon simon 4.0K 2026-05-25 14:32 .hg
-rw-rw-r-- 1 simon simon   46 2026-05-25 13:13 .hgtags
-rw-rw-r-- 1 simon simon   46 2026-05-25 14:09 INSTALL
drwxrwxr-x 3 simon simon 4.0K 2026-05-25 13:13 lib
-rw-rw-r-- 1 simon simon   77 2026-05-25 13:53 README&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;So if at this point, we&amp;#8217;re happy with our changes on test-branch, we can merge those changes back into the default branch. We&amp;#8217;ll switch to our default branch first, then do the merge&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;[simon@computer 14:35:24] test-branch ~/tmp/hg-demo
$ hg co default
0 files updated, 0 files merged, 1 files removed, 0 files unresolved&lt;/code&gt;&lt;/pre&gt;

&lt;pre&gt;&lt;code&gt;[simon@computer 14:35:30] default ~/tmp/hg-demo
$ hg merge test-branch 
1 files updated, 0 files merged, 0 files removed, 0 files unresolved
(branch merge, don&amp;#39;t forget to commit)&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;Mercurial helpfully reminds us that we need to commit. Running &lt;code&gt;hg st&lt;/code&gt; gives us the following slightly frightening message&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;[simon@computer 14:35:37] default ~/tmp/hg-demo
$ hg st
M HELLO_wORLD
# The repository is in an unfinished *merge* state.

# To continue:    hg commit
# To abort:       hg merge --abort&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;But it also tells us what we need to do. We&amp;#8217;ll commit our merge using the usual &lt;code&gt;hg ci&lt;/code&gt; and check the log&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;changeset:   9:252812a28287
tag:         tip
parent:      6:a54d2f2f5c03
parent:      8:148dfc191c11
user:        Simon Harrison &amp;lt;simon@simonh.uk&amp;gt;
date:        Mon May 25 14:38:42 2026 +0100
summary:     Merge test-branch

changeset:   8:148dfc191c11
branch:      test-branch
user:        Simon Harrison &amp;lt;simon@simonh.uk&amp;gt;
date:        Mon May 25 14:23:57 2026 +0100
summary:     Add HELLO_WORLD to the test-branch

changeset:   7:e0d495cff8b9
branch:      test-branch
user:        Simon Harrison &amp;lt;simon@simonh.uk&amp;gt;
date:        Mon May 25 14:19:01 2026 +0100
summary:     Create test-branch

changeset:   6:a54d2f2f5c03
user:        Simon Harrison &amp;lt;simon@simonh.uk&amp;gt;
date:        Mon May 25 14:09:46 2026 +0100
:&lt;/code&gt;&lt;/pre&gt;

	&lt;h2&gt;hg heads&lt;/h2&gt;

	&lt;p&gt;Here&amp;#8217;s a question. What happens if we update to r0 and then make a change? Will that change be lost for all time. Let&amp;#8217;s see. I&amp;#8217;ve updated to r0 and then added a file called &lt;span class="caps"&gt;ZERO&lt;/span&gt;.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;[simon@computer 19:53:41] default ~/tmp/hg-demo
$ hg co
0 files updated, 0 files merged, 0 files removed, 0 files unresolved
updated to &amp;quot;3aa355043ddc: Add ZERO file to -r0 (let&amp;#39;s see what happens)&amp;quot;
1 other heads for branch &amp;quot;default&amp;quot;&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;Interesting. Running &lt;code&gt;hg heads&lt;/code&gt; will list all heads. Heads, by the way are commits with no descendants. Revision 0 is a head and so is a new branch. Bookmarks also create heads (we&amp;#8217;ll come to them later).&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;[simon@computer 19:53:39] default ~/tmp/hg-demo
$ hg heads
changeset:   12:3aa355043ddc
tag:         tip
parent:      0:3f082894d145
user:        Simon Harrison &amp;lt;simon@simonh.uk&amp;gt;
date:        Mon May 25 19:51:08 2026 +0100
summary:     Add ZERO file to -r0 (let&amp;#39;s see what happens)

changeset:   11:09402552bba8
bookmark:    testing
user:        Simon Harrison &amp;lt;simon@simonh.uk&amp;gt;
date:        Mon May 25 19:29:46 2026 +0100
summary:     Add CHANGES file

changeset:   8:148dfc191c11
branch:      test-branch
user:        Simon Harrison &amp;lt;simon@simonh.uk&amp;gt;
date:        Mon May 25 14:23:57 2026 +0100
summary:     Add HELLO_WORLD to the test-branch&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;Let&amp;#8217;s see what the log says&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;changeset:   12:3aa355043ddc
tag:         tip
parent:      0:3f082894d145
user:        Simon Harrison &amp;lt;simon@simonh.uk&amp;gt;
date:        Mon May 25 19:51:08 2026 +0100
summary:     Add ZERO file to -r0 (let&amp;#39;s see what happens)

changeset:   11:09402552bba8
bookmark:    testing
user:        Simon Harrison &amp;lt;simon@simonh.uk&amp;gt;
date:        Mon May 25 19:29:46 2026 +0100
summary:     Add CHANGES file

changeset:   10:59e842e18dc4
user:        Simon Harrison &amp;lt;simon@simonh.uk&amp;gt;
date:        Mon May 25 19:19:21 2026 +0100
summary:     Add some stuff to hello world and readme

changeset:   9:252812a28287
parent:      6:a54d2f2f5c03
parent:      8:148dfc191c11
user:        Simon Harrison &amp;lt;simon@simonh.uk&amp;gt;
date:        Mon May 25 14:38:42 2026 +0100
summary:     Merge test-branch

changeset:   8:148dfc191c11
branch:      test-branch
user:        Simon Harrison &amp;lt;simon@simonh.uk&amp;gt;
date:        Mon May 25 14:23:57 2026 +0100
summary:     Add HELLO_WORLD to the test-branch

changeset:   7:e0d495cff8b9
branch:      test-branch
user:        Simon Harrison &amp;lt;simon@simonh.uk&amp;gt;
date:        Mon May 25 14:19:01 2026 +0100
summary:     Create test-branch
:&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;Listing the files in our working directory reveals a problem&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;[simon@computer 20:06:57] default ~/tmp/hg-demo
$ ll
total 20K
drwxrwxr-x 4 simon simon 4.0K 2026-05-25 20:06 .
drwxrwxrwx 8 simon simon 4.0K 2026-05-25 14:11 ..
drwxrwxr-x 2 simon simon 4.0K 2020-10-03 16:27 bottle-sqlite-master
drwxrwxr-x 8 simon simon 4.0K 2026-05-25 20:06 .hg
-rw-rw-r-- 1 simon simon   25 2026-05-25 20:05 ZERO&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;&lt;span class="caps"&gt;EEK&lt;/span&gt;! Where have our other files gone? &lt;span class="caps"&gt;README&lt;/span&gt;, &lt;span class="caps"&gt;INSTALL&lt;/span&gt;, &lt;span class="caps"&gt;CHANGES&lt;/span&gt;, &lt;span class="caps"&gt;HELLO&lt;/span&gt;_WORLD. Where are they?&lt;/p&gt;

	&lt;p&gt;Relax. All we need to do is merge r12 with r11. &lt;/p&gt;

&lt;pre&gt;&lt;code&gt;[simon@computer 20:05:34] default ~/tmp/hg-demo
$ hg co -r11
406 files updated, 0 files merged, 1 files removed, 0 files unresolved
[simon@computer 20:05:38] default ~/tmp/hg-demo
$ hg merge -r12
1 files updated, 0 files merged, 0 files removed, 0 files unresolved
(branch merge, don&amp;#39;t forget to commit)
[simon@computer 20:05:46] default ~/tmp/hg-demo
$ hg ci -m &amp;quot;Merge r12 into default&amp;quot;&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;And now everything is as it should be&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;[simon@computer 20:06:03] default ~/tmp/hg-demo
$ ll
total 44K
drwxrwxr-x 5 simon simon 4.0K 2026-05-25 20:05 .
drwxrwxrwx 8 simon simon 4.0K 2026-05-25 14:11 ..
drwxrwxr-x 2 simon simon 4.0K 2020-10-03 16:27 bottle-sqlite-master
-rw-rw-r-- 1 simon simon   27 2026-05-25 20:05 CHANGES
-rw-rw-r-- 1 simon simon   47 2026-05-25 20:05 HELLO_wORLD
drwxrwxr-x 8 simon simon 4.0K 2026-05-25 20:06 .hg
-rw-rw-r-- 1 simon simon   46 2026-05-25 20:05 .hgtags
-rw-rw-r-- 1 simon simon   46 2026-05-25 20:05 INSTALL
drwxrwxr-x 3 simon simon 4.0K 2026-05-25 20:05 lib
-rw-rw-r-- 1 simon simon   92 2026-05-25 20:05 README
-rw-rw-r-- 1 simon simon   25 2026-05-25 20:05 ZERO&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;I&amp;#8217;ll be honest. I used to find merging terrifying. But it needn&amp;#8217;t be. These &lt;span class="caps"&gt;DVCS&lt;/span&gt;&amp;#8217;s are very good at merging.&lt;/p&gt;

	&lt;h2&gt;hg bookmarks&lt;/h2&gt;

	&lt;p&gt;As an alternative to branches, Mercurial also offers bookmarks. Bookmarks are sort of like tags, except the bookmark moves along as you commit instead of pointing at one commit forever. Huh? You may be thinking. What&amp;#8217;s the point of that? &lt;/p&gt;

	&lt;p&gt;Well, remember how we had to merge r12 into r11? By using bookmarks, we don&amp;#8217;t have to remember or look up what revision needs to be merged with another revision. We can simply merge using the named bookmark. We could have done this.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;[simon@computer 20:35:26] default ~/tmp/hg-demo
$ hg book -r0 zero
$ hg co zero&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;Add some files, modify them, whatever.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;[simon@computer 20:35:26] default ~/tmp/hg-demo
$ hg co
$ hg merge zero&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;I don&amp;#8217;t use bookmarks a great deal, but lots of Mercurial people love them.&lt;/p&gt;

	&lt;h2&gt;hg shelve&lt;/h2&gt;

	&lt;p&gt;Sometimes, you&amp;#8217;ll be working on something and then all of a sudden, you need to be some place else in your repository. Perhaps to fix a bug, investigate something etc. hg shelve lets you put away all your uncommitted changes in a safe place, and then bring them back later.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;[simon@computer 15:14:08] default ~/tmp/hg-demo
$ hg di
diff -r 252812a28287 HELLO_wORLD
--- a/HELLO_wORLD       Mon May 25 14:38:42 2026 +0100
+++ b/HELLO_wORLD       Mon May 25 15:14:10 2026 +0100
@@ -1,2 +1,3 @@
 Hello world!
-
+I&amp;#39;ve added this line
+and this one
diff -r 252812a28287 README
--- a/README    Mon May 25 14:38:42 2026 +0100
+++ b/README    Mon May 25 15:14:10 2026 +0100
@@ -1,3 +1,5 @@
 This is just a test repo for a blog post.

 Remember to mention about hg diff
+
+Howdly doodly&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;I want to put those very important (unfinished) changes away as I&amp;#8217;m not ready to commit them yet. I mean, I could commit them, but the work is not finished. Let&amp;#8217;s shelve them instead&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;[simon@computer 15:18:07] default ~/tmp/hg-demo
$ hg shelve
shelved as default
2 files updated, 0 files merged, 0 files removed, 0 files unresolved
[simon@computer 15:18:09] default ~/tmp/hg-demo
$ hg st
[simon@computer 15:18:12] default ~/tmp/hg-demo
$ hg shelve -l
default         (8s ago)    changes to: Merge test-branch&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;We can see what we&amp;#8217;ve shelved easily&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;[simon@computer 15:20:29] default ~/tmp/hg-demo
$ hg shelve -l
default         (2m ago)    changes to: Merge test-branch&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;And when we&amp;#8217;re ready, we can get those changes back in our working directory&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;[simon@computer 15:20:32] default ~/tmp/hg-demo
$ hg unshelve
unshelving change &amp;#39;default&amp;#39;
[simon@computer 15:21:12] default ~/tmp/hg-demo
$ hg st
M HELLO_wORLD
M README&lt;/code&gt;&lt;/pre&gt;

	&lt;h2&gt;hg clone&lt;/h2&gt;

	&lt;p&gt;As responsible computer users, we realise we should arrange a backup of our hg-demo project. One option is to simply copy the repo from where it is to somewhere else. However, that&amp;#8217;s not recommended. Mercurial includes the &lt;code&gt;clone&lt;/code&gt; command which has quite a few advantages over a simple, manual copy. I&amp;#8217;ll clone my repo to a second hard drive, installed in my PC&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;[simon@computer 11:26:02] ~/tmp
$ hg clone hg-demo/ /media/simon/KINGSTON_1TB/repo-backup/hg-demo
updating to branch default
9 files updated, 0 files merged, 0 files removed, 0 files unresolved&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;If we have a look at the &lt;code&gt;.hg/hgrc&lt;/code&gt; in the cloned repository (the backup), we can see that Mercurial has made a note of where the source repository is&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;[simon@computer 11:39:28] default /media/simon/KINGSTON_1TB/repo-backup/hg-demo
$ cat .hg/hgrc
# example repository config (see &amp;#39;hg help config&amp;#39; for more info)
[paths]
default = /home/simon/tmp/hg-demo

# path aliases to other clones of this repo in URLs or filesystem paths
# (see &amp;#39;hg help config.paths&amp;#39; for more info)
#
# default:pushurl = ssh://jdoe@example.net/hg/jdoes-fork
# my-fork         = ssh://jdoe@example.net/hg/jdoes-fork
# my-clone        = /home/jdoe/jdoes-clone

[ui]
# name and email (local to this repository, optional), e.g.
# username = Jane Doe &amp;lt;jdoe@example.com&amp;gt;&lt;/code&gt;&lt;/pre&gt;

	&lt;h2&gt;hg pull / push&lt;/h2&gt;

	&lt;p&gt;Awesome. So now we can &lt;code&gt;pull&lt;/code&gt; changes from our backup repository, but it&amp;#8217;s easier for us to &lt;code&gt;push&lt;/code&gt; changes from our main repository to our backup. To do that we&amp;#8217;ll need to copy and then modifiy the &lt;code&gt;[paths]&lt;/code&gt; section in our backup &lt;code&gt;.hg/hgrc&lt;/code&gt; file&lt;/p&gt;

	&lt;p&gt;All we need right now is the following&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;[simon@computer 11:38:42] default ~/tmp/hg-demo
$ cat .hg/hgrc
[paths]
default = /media/simon/KINGSTON_1TB/repo-backup/hg-demo&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;And now we can backup as we go!&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;[simon@computer 11:43:50] default ~/tmp/hg-demo
$ hg push
pushing to /media/simon/KINGSTON_1TB/repo-backup/hg-demo
searching for changes
no changes found&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;We&amp;#8217;ll create a new file and &lt;code&gt;push&lt;/code&gt; it to our backup&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;[simon@computer 11:45:34] default ~/tmp/hg-demo
$ nano NEW_FILE
[simon@computer 11:45:51] default ~/tmp/hg-demo
$ hg st
? NEW_FILE
[simon@computer 11:45:52] default ~/tmp/hg-demo
$ hg add
adding NEW_FILE
[simon@computer 11:46:12] default ~/tmp/hg-demo
$ hg ci -m &amp;quot;Added a new file, that&amp;#39;s all&amp;quot;
[simon@computer 11:46:24] default ~/tmp/hg-demo
$ hg push
pushing to /media/simon/KINGSTON_1TB/repo-backup/hg-demo
searching for changes
adding changesets
adding manifests
adding file changes
added 1 changesets with 1 changes to 1 files
updating bookmark zero&lt;/code&gt;&lt;/pre&gt;

	&lt;h2&gt;hg serve&lt;/h2&gt;

	&lt;p&gt;As much as I love the command line, sometimes a task is easier using a graphical tool. From time to time I&amp;#8217;ve had need to dig through old revisions to retrieve some code that I thought I&amp;#8217;d never need again (but did)! Mercurial&amp;#8217;s built in web server can be very handy  &lt;/p&gt;

&lt;pre&gt;&lt;code&gt;[simon@computer 14:29:50] default ~/tmp/hg-demo
$ hg serve
listening at http://computer:8000/ (bound to *:8000)&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;And you&amp;#8217;ve now got a web interface to your repository.&lt;/p&gt;

	&lt;p class="hand"&gt;Log view&lt;/p&gt;

	&lt;p&gt;&lt;img alt="hg serve log view" src="/img/2026-05-25/hg_serve1.webp" title="hg serve log view" /&gt;&lt;/p&gt;

	&lt;p class="hand"&gt;Graph view&lt;/p&gt;

	&lt;p&gt;&lt;img alt="hg serve graphical log view" src="/img/2026-05-25/hg_serve2.webp" title="hg serve graphical log view" /&gt;&lt;/p&gt;


	&lt;h2&gt;To be Continued&amp;#8230;&lt;/h2&gt;

	&lt;p&gt;&lt;img alt="Please Standby" src="/img/standby2.webp" title="Please Standby" /&gt;&lt;/p&gt;

	&lt;h2 class="footnotes"&gt;Footnotes &lt;/h2&gt;

	&lt;p class="footnote" id="fn750a140db119431ab570a6dd02e8776c-1"&gt;&lt;sup&gt;1&lt;/sup&gt; &lt;a href="https://gregoryszorc.com/blog/2018/11/05/absorbing-commit-changes-in-mercurial-4.8/"&gt;Absorbing Commit Changes in Mercurial 4.8&lt;/a&gt;&lt;/p&gt;</content><category term="software"></category><category term="VCS"></category><category term="mercurial"></category></entry><entry><title>Real World Game of Trees (Got)</title><link href="https://simonh.uk/2026/05/19/real-world-game-of-trees-got/" rel="alternate"></link><published>2026-05-19T00:00:00+01:00</published><updated>2026-05-22T00:00:00+01:00</updated><author><name>Simon Harrison</name></author><id>tag:simonh.uk,2026-05-19:/2026/05/19/real-world-game-of-trees-got/</id><summary type="html">	&lt;p&gt;Centralized / distributed is the way&lt;/p&gt;</summary><content type="html">	&lt;p&gt;&lt;img alt="Got logo" src="/img/got.webp" title="Got logo" /&gt;&lt;/p&gt;

	&lt;p&gt;This is my third post on &lt;a href="https://gameoftrees.org/"&gt;Got&lt;/a&gt;. The first one was a &lt;a href="https://simonh.uk/2024/10/29/first-look-at-openbsd-game-of-trees-got/"&gt;First Look&lt;/a&gt;, followed by &lt;a href="https://simonh.uk/2024/10/29/first-look-at-openbsd-game-of-trees-got/"&gt;Trying Out&lt;/a&gt;, and you have probably guessed that this one is about using Got in real world projects.&lt;/p&gt;

	&lt;h2&gt;Why use Got?&lt;/h2&gt;

	&lt;p class="warn"&gt;I&amp;#8217;m probably going to repeat myself from previous posts, so apologies in advance. &lt;/p&gt;

	&lt;p&gt;Firstly, Git is ubiquitous. I think any programmer, even one working on their own like me, should be able to deal with Git repositories. The problem is,  I don&amp;#8217;t really like Git. I tried it back in ~2016 when it became obvious I need to use a &lt;span class="caps"&gt;VCS&lt;/span&gt;, but Git didn&amp;#8217;t click with me. I tried Fossil, Git, Mercurial, Darcs and Mercurial was the one I liked best. so, I&amp;#8217;ve continued to use it ever since. On the rare occasions when I&amp;#8217;ve been forced to use Git, it&amp;#8217;s got the job done, but at no point have I ever thought, &amp;#8220;the time is right to switch to Git.&amp;#8221; Never, sorry.&lt;/p&gt;

	&lt;p&gt;I came across Got whilst browsing salsa.debian.org. When I found out is was an OpenBSD project, I became more interested. Any self respecting geek knows that OpenBSD are one of the biggest projects to continue to use &lt;span class="caps"&gt;CVS&lt;/span&gt;. Well, their own rewrite of &lt;span class="caps"&gt;GNU&lt;/span&gt; &lt;span class="caps"&gt;CVS&lt;/span&gt;. But I think we all know that a distributed project like Linux, or a &lt;span class="caps"&gt;BSD&lt;/span&gt; would be better off using a distributed &lt;span class="caps"&gt;VCS&lt;/span&gt;. And I think we all also know, that over the last twenty years, the distributed &lt;span class="caps"&gt;VCS&lt;/span&gt;&amp;#8217;s have proven themselves. &lt;/p&gt;

	&lt;p&gt;So Got is an OpenBSD implementation of Git designed for their workflows. See &lt;a href="https://gameoftrees.org/goals.html"&gt;here&lt;/a&gt; for the project goals. The &amp;#8220;features&amp;#8221; that appealed most to me were&lt;/p&gt;

	&lt;blockquote&gt;
		&lt;p&gt;Strong built-in support for a centralized repository model&lt;/p&gt;
	&lt;/blockquote&gt;

	&lt;p&gt;and &lt;/p&gt;

	&lt;blockquote&gt;
		&lt;p&gt;Keep things easy for developers who don&amp;#8217;t need branches.&lt;/p&gt;
	&lt;/blockquote&gt;

	&lt;p&gt;The centralized repo model is something that clicks with me. With Got, you &lt;strong&gt;have&lt;/strong&gt; to have repo&amp;#8217;s and worktrees in different places:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;/home/simon/repo/got/all-my-repositories&lt;/code&gt;&lt;/pre&gt;

&lt;pre&gt;&lt;code&gt;/home/simon/repo/tree/all-my-working-directories&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;You cannot checkout a worktree into a repository. With this hybrid centralized/distributed model all your repositories can live in one directory, and your worktrees can be scattered all over your hard drive. As long as you checkin worktree changes, you can delete the worktree when you no longer need it. It is after all, just a worktree, not your repository!&lt;/p&gt;

	&lt;p&gt;The second goal of keeping things easy for people who don&amp;#8217;t need branches also appeals to me. When I&amp;#8217;m starting a new project, I don&amp;#8217;t branch &lt;em&gt;at all&lt;/em&gt;. Everything is done on the default branch. At the point where things seem stable, I&amp;#8217;ll sometimes create a stable branch and from that point follow the stable / main branching strategy as described by &lt;a href="https://stevelosh.com/blog/2010/05/mercurial-workflows-stable-default/"&gt;Steve Losh&lt;/a&gt;. I&amp;#8217;ve always thought that the idea of &amp;#8220;feature&amp;#8221; branches is unnecessary.&lt;/p&gt;

	&lt;p&gt;I look at it like this: you&amp;#8217;ve got some work to do, so get on with it and do it. No need to create a temporary branch as it&amp;#8217;s going to get merged back into the default branch anyway and then thrown away! If the work may take many iterations to get right, you can use the &lt;code&gt;stage -p&lt;/code&gt; command in Got to interactively prepare the changes that you&amp;#8217;re happy with. In Mercurial, I quite often use &lt;code&gt;hg ci -i&lt;/code&gt; which works in a similar way.  &lt;/p&gt;

	&lt;h2&gt;Project 1: Miscellaneous Scripts&lt;/h2&gt;

	&lt;p&gt;I wrote a post in 2023 about using &lt;a href="https://simonh.uk/2023/02/11/using-gnu-rcs-in-2023/"&gt;&lt;span class="caps"&gt;RCS&lt;/span&gt;&lt;/a&gt; for versioning one off, ad-hoc scripts. But I was starting to hit the limit of &lt;span class="caps"&gt;RCS&lt;/span&gt;&amp;#8217;s capablilities. Here are the problems I was having:&lt;/p&gt;

	&lt;p&gt;1. I have scripts all over the place that I need to somehow keep track of&lt;br /&gt;
2, Some scripts are used in multiple projects&lt;/p&gt;

	&lt;p&gt;Problem 1 means I need some other tool to keep track of all my &lt;span class="caps"&gt;RCS&lt;/span&gt; repositories. I&amp;#8217;d always resisted having a central repo for unrelated items (i.e. not a project), but now suspected it might be an obvious solution to my problem.&lt;/p&gt;

	&lt;p&gt;Problem 2 mainly relates to my bottle.py projects. I have written, or modified, a number of modules that are used in most projects. Up until now my stupid method was to simply remember which project had the latest updates and copy the module from there to the new project. Ugh! Not good. A better approach was clearly needed&amp;#8230;&lt;/p&gt;

	&lt;p&gt;So I thought this a perfect time to try out Got for something that actually mattered (to me). Normally, I&amp;#8217;d use Mercurial, my &lt;span class="caps"&gt;VCS&lt;/span&gt; of choice, but there a few reasons I&amp;#8217;m wanting to incorporate Got into my toolbox, as explained above.&lt;/p&gt;

	&lt;h2&gt;Project 2: Static Website&lt;/h2&gt;

	&lt;p&gt;For a project I&amp;#8217;m currenly working on, I wanted to create a simple static website. Another opportunity to get my hands wet (or wetter) with Got. &lt;/p&gt;

	&lt;p&gt;So, how did it go?&lt;/p&gt;

	&lt;h2&gt;The Scripts&lt;/h2&gt;

	&lt;p&gt;Very simple. I created:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;/home/simon/repo/simonh/simonh-scripts.got&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;Then cd&amp;#8217;ing into the new directory and running:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;got init .&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;Next I import the scripts from a temporary directory where I put them all together:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;got import ~/tmp/scripts&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;Finally:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;got co . ~/code/scripts&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;And that&amp;#8217;s it. Well nearly it. I&amp;#8217;ll set up a repo on one of my servers to act as a backup. In the repo edit got.conf&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;remote &amp;quot;simonh&amp;quot; {
  server myserver.com
  protocol ssh
  repository &amp;quot;/home/simon/repo/got/simonh-scripts.got&amp;quot;
}&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;Now (after creating the repo on the server) I can backup my repo with:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;got se simonh&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;Perfect! Repo created, worktree created, everything backed up. &lt;/p&gt;

	&lt;h2&gt;The website&lt;/h2&gt;

	&lt;p&gt;This one was slightly different as I&amp;#8217;m wanting two branches: main and stable. Plus, right now I have nothing to import. Let&amp;#8217;s get to work.&lt;/p&gt;

	&lt;p&gt;I&amp;#8217;ll create my (temporary) working directory:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;mkdir ~/tmp/new-website&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;Inside that directory, create whatever files I need to be able to put them on my web server. As it happens, I only need index.html right now. &lt;/p&gt;

	&lt;p&gt;Let&amp;#8217;s setup the local repo:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ mkdir ~/repo/web/new-website 
$ cd ~/repo/web/new-website
$ got init .
$ got im ~/tmp/new-website
$ got co . ~/web/new-website
$ rm -r ~/tmp/new-website&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;So I&amp;#8217;ve now created my index.html which is good enough to upload to the live web server. The great thing about having a stable and a main branch is that I can work on the main branch and only merge changes into stable when they&amp;#8217;re ready. &lt;/p&gt;

	&lt;h2&gt;A Pleasant Surprise&lt;/h2&gt;

	&lt;p&gt;At this point I have my index.html page that I want to put on the web server. I basically need to create a repo on the server and a worktree on the server. &lt;/p&gt;

	&lt;p&gt;The repo will live in a similar directory structure to my local machine:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;/home/simon/repo/web/new-website.got&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;and the worktree will be checked out to &lt;/p&gt;

&lt;pre&gt;&lt;code&gt;/var/www/new-website&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;The beautiful thing about this setup is that I can push changes from my local repo to my remote repo, then update the remote worktree (which was checked out from the stable branch)! Any half finished work is siloed in the &amp;#8220;main&amp;#8221; branch until integrated or merged into stable. When I add binary files (&lt;span class="caps"&gt;PNG&lt;/span&gt;&amp;#8217;s, &lt;span class="caps"&gt;JPG&lt;/span&gt;&amp;#8217;s, &lt;span class="caps"&gt;PDF&lt;/span&gt;&amp;#8217;s etc), they also get sent to my server and the worktree will be updated to include them as well.  &lt;/p&gt;

&lt;pre&gt;&lt;code&gt;simon@myserver:~ [ssh] $ cd /var/www/new-website/
simon@myserver:/var/www/new-website [ssh] $ sudo got br
stable
simon@myserver:/var/www/new-website [ssh] $ sudo got up
Already up-to-date&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;If you&amp;#8217;ve made changes but Got reports that you&amp;#8217;re already up-to-date, when you&amp;#8217;re not, you&amp;#8217;ll probably have to merge or integrate the changes from the main branch to the stable:&lt;sup class="footnote" id="fnrev88ecf3abcab74ed1bd5cc977e03c8803-1"&gt;&lt;a href="#fn88ecf3abcab74ed1bd5cc977e03c8803-1"&gt;1&lt;/a&gt;&lt;/sup&gt;&lt;/p&gt;

	&lt;p&gt;Just be careful that you haven&amp;#8217;t added anything to your stable branch that shouldn&amp;#8217;t be there. As you can see below, only &lt;code&gt;index.html&lt;/code&gt; was updated, &lt;code&gt;about.html&lt;/code&gt; and &lt;code&gt;contact.html&lt;/code&gt; exist in the main branch, but haven&amp;#8217;t been added to stable:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;simon@myserver:/var/www/new-website [ssh] $ sudo got br
stable
simon@myserver:/var/www/new-website [ssh] $ sudo got ig main
U  index.html
Integrated refs/heads/main into refs/heads/stable&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;The final precautionary measure is to add an .htaccess file to the .got directory in the server worktree to prevent browsing:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;simon@myserver:/var/www/new-website [ssh] $ cat .got/.htaccess 
Require all denied&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;Not that there&amp;#8217;s anything valuable there, just worth locking down anyway.&lt;/p&gt;

	&lt;h2&gt;Conclusion&lt;/h2&gt;

	&lt;p&gt;Both projects went well. I was a bit unclear when it comes to the differences between merging and integrating. It&amp;#8217;s only the last year or two since I&amp;#8217;ve been using anything more than the default / master / main branch. I even ended up checking the mailing list for an explanation of the Got integrate command (see &lt;a href="https://marc.gameoftrees.org/mail/1661526332.M193146P13612Q65.html"&gt;here&lt;/a&gt;):&lt;/p&gt;

	&lt;blockquote&gt;
		&lt;p&gt;&lt;em&gt;Have I got it right that it basically syncs the master branch with the&lt;br /&gt;
working branch? As in you checkout a new branch to, for example, add&lt;br /&gt;
a new feature or fix a bug and then want to sync the master with the changes?&lt;/em&gt;&lt;/p&gt;
	&lt;/blockquote&gt;

	&lt;blockquote&gt;
		&lt;p&gt;&lt;em&gt;Yes, that&amp;#8217;s precisely it.&lt;/em&gt;&lt;/p&gt;
	&lt;/blockquote&gt;

	&lt;p&gt;The Google AI bot states this:&lt;/p&gt;

	&lt;blockquote&gt;
		&lt;p&gt;&lt;em&gt;A merge is a general term for combining changes between branches, while a reintegrate (specifically in Apache Subversion) is a specialized final merge that takes all unique changes from a completed feature branch and safely applies them back to its parent branch.&lt;/em&gt;&lt;/p&gt;
	&lt;/blockquote&gt;

	&lt;p&gt;So it would appear that the main difference is not attempting to merge changes already applied. The keyword is &amp;#8220;unique&amp;#8221;. This will be very useful for syncing between main and stable branches I think.&lt;/p&gt;

	&lt;p&gt;I&amp;#8217;ll continue to use Mercurial as my main &lt;span class="caps"&gt;VCS&lt;/span&gt; for Python stuff, and &lt;span class="caps"&gt;RCS&lt;/span&gt; when I&amp;#8217;m working on a script until it&amp;#8217;s complete. Then I&amp;#8217;ll dump the script + the &lt;span class="caps"&gt;RCS&lt;/span&gt; folder into my Got repo.&lt;/p&gt;

	&lt;p&gt;Like the &lt;span class="caps"&gt;BSD&lt;/span&gt; people, there&amp;#8217;s no rush or pressure to change anything right now. I&amp;#8217;m very impressed with Got and I like it&amp;#8217;s lack of features and commands:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ got -h
usage: got [-hV] command [arg ...]
commands: init import clone fetch checkout update log diff blame tree status ref branch tag add remove patch revert commit send cherrypick backout rebase histedit integrate merge stage unstage cat info&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;Compare with the same command for Git:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ git -h
usage: git [-v | --version] [-h | --help] [-C &amp;lt;path&amp;gt;] [-c &amp;lt;name&amp;gt;=&amp;lt;value&amp;gt;]
           [--exec-path[=&amp;lt;path&amp;gt;]] [--html-path] [--man-path] [--info-path]
           [-p | --paginate | -P | --no-pager] [--no-replace-objects] [--no-lazy-fetch]
           [--no-optional-locks] [--no-advice] [--bare] [--git-dir=&amp;lt;path&amp;gt;]
           [--work-tree=&amp;lt;path&amp;gt;] [--namespace=&amp;lt;name&amp;gt;] [--config-env=&amp;lt;name&amp;gt;=&amp;lt;envvar&amp;gt;]
           &amp;lt;command&amp;gt; [&amp;lt;args&amp;gt;]

These are common Git commands used in various situations:

start a working area (see also: git help tutorial)
   clone      Clone a repository into a new directory
   init       Create an empty Git repository or reinitialise an existing one

work on the current change (see also: git help everyday)
   add        Add file contents to the index
   mv         Move or rename a file, a directory, or a symlink
   restore    Restore working tree files
   rm         Remove files from the working tree and from the index

examine the history and state (see also: git help revisions)
   bisect     Use binary search to find the commit that introduced a bug
   diff       Show changes between commits, commit and working tree, etc
   grep       Print lines matching a pattern
   log        Show commit logs
   show       Show various types of objects
   status     Show the working tree status

grow, mark and tweak your common history
   backfill   Download missing objects in a partial clone
   branch     List, create, or delete branches
   commit     Record changes to the repository
   history    EXPERIMENTAL: Rewrite history
   merge      Join two or more development histories together
   rebase     Reapply commits on top of another base tip
   reset      Set `HEAD` or the index to a known state
   switch     Switch branches
   tag        Create, list, delete or verify tags

collaborate (see also: git help workflows)
   fetch      Download objects and refs from another repository
   pull       Fetch from and integrate with another repository or a local branch
   push       Update remote refs along with associated objects

&amp;#39;git help -a&amp;#39; and &amp;#39;git help -g&amp;#39; list available subcommands and some
concept guides. See &amp;#39;git help &amp;lt;command&amp;gt;&amp;#39; or &amp;#39;git help &amp;lt;concept&amp;gt;&amp;#39;
to read about a specific subcommand or concept.
See &amp;#39;git help git&amp;#39; for an overview of the system.&lt;/code&gt;&lt;/pre&gt;


	&lt;blockquote&gt;
		&lt;p&gt;&lt;em&gt;“Perfection is achieved, not when there is nothing more to add, but when there is nothing left to take away.”&lt;/em&gt; ― Antoine de Saint-Exupéry&lt;/p&gt;
	&lt;/blockquote&gt;

	&lt;h2&gt;Afterword&lt;/h2&gt;

	&lt;p&gt;Oh, I nearly forgot. Actually I did forget and had to edit this post. Apparently, I made it into an OpenBSD &lt;a href="https://www.openbsd.org/papers/eurobsdcon2025-stsp-gothub.pdf"&gt;presentation&lt;/a&gt;:&lt;/p&gt;

	&lt;p&gt;&lt;img alt="OpenBSD presentation PDF" src="/img/2026-05-19/bsdcon2025.png" title="OpenBSD presentation PDF" /&gt;&lt;/p&gt;

	&lt;p&gt;How about that, eh? I think I was looking something up about Got and happened to open the &lt;span class="caps"&gt;PDF&lt;/span&gt; and on page 6, there I am! I told the other half and she was quietly impressed (I could tell).&lt;/p&gt;

	&lt;h2 class="footnotes"&gt;Footnotes&lt;/h2&gt;

	&lt;p class="footnote" id="fn88ecf3abcab74ed1bd5cc977e03c8803-1"&gt;&lt;sup&gt;1&lt;/sup&gt; Still trying to get my head around local branches and remote branches.&lt;/p&gt;</content><category term="software"></category><category term="VCS"></category><category term="Got"></category></entry><entry><title>Quick Review of Fizzy by Basecamp</title><link href="https://simonh.uk/2026/04/25/quick-review-of-fizzy-by-basecamp/" rel="alternate"></link><published>2026-04-25T00:00:00+01:00</published><updated>2026-04-26T00:00:00+01:00</updated><author><name>Simon Harrison</name></author><id>tag:simonh.uk,2026-04-25:/2026/04/25/quick-review-of-fizzy-by-basecamp/</id><summary type="html">	&lt;p&gt;What would you like to do? Or not do?&lt;/p&gt;</summary><content type="html">	&lt;p&gt;&lt;img alt="Kanban Board" src="/img/2026-04-25/kanban.webp" title="Kanban Board" /&gt;&lt;/p&gt;

	&lt;p&gt;For some years now, I&amp;#8217;ve had an itch; keeping track of things that need doing (or may need doing at some point). Along with &lt;em&gt;those&lt;/em&gt; things, there are also ideas that I may want turn in to something one day. You know what I&amp;#8217;m talking about. Now, I&amp;#8217;ve never been one of those todo obsessed people. My approach until now has been to either just-get-on-with-it-and-do-the-thing &amp;trade; or, keep a &lt;span class="caps"&gt;TODO&lt;/span&gt; text file in whatever software project folder I&amp;#8217;m working on. This second method works, but it&amp;#8217;s clunky and it&amp;#8217;s only real benefit over not recording the todo item at all, is that it&amp;#8217;s saved outside of my head. &lt;/p&gt;

	&lt;p&gt;But you can&amp;#8217;t really do anything with it. You can&amp;#8217;t easily mark it as done, move it to &amp;#8220;deal with it another time&amp;#8221;, &amp;#8220;more info needed&amp;#8221;, &amp;#8220;sorted for the moment, but needs improving&amp;#8221;. &lt;/p&gt;

	&lt;p&gt;So I&amp;#8217;ve been aware that I could do with something &lt;strong&gt;better&lt;/strong&gt;. Over the last year or so, I&amp;#8217;ve tried Dropbox Paper, Atlassian something, Jira maybe? A couple of command line task / todo programs. But none of them was what I was after. What am I after, you ask?&lt;/p&gt;

	&lt;h2&gt;The &lt;em&gt;Something&lt;/em&gt; Tracker&lt;/h2&gt;

	&lt;p&gt;There is &lt;em&gt;something&lt;/em&gt; you want to keep track of. It could be a bug, an idea, an improvement, an entire project, even a wish. We&amp;#8217;ll just call it an item for now, bearing in mind that each item may have sub-items.&lt;/p&gt;

	&lt;h2&gt;The &lt;em&gt;Item&lt;/em&gt; Tracker&lt;/h2&gt;

	&lt;p&gt;Ok, so that item needs a name, a category (from above), a priority would be nice, then I can just filter on the highest priority items. Being able to attach a label to an item would also be helpful. Let&amp;#8217;s say you&amp;#8217;re building a house, you could have labels for:
	&lt;ul&gt;
		&lt;li&gt;Front garden&lt;/li&gt;
		&lt;li&gt;Back garden&lt;/li&gt;
		&lt;li&gt;Upstairs&lt;/li&gt;
		&lt;li&gt;Downstairs&lt;/li&gt;
		&lt;li&gt;Electrical&lt;/li&gt;
		&lt;li&gt;Plumbing&lt;/li&gt;
	&lt;/ul&gt;&lt;/p&gt;

	&lt;p&gt;Now, you can filter on &lt;em&gt;things that need doing upstairs&lt;/em&gt; that are high priority. Or, &lt;em&gt;things that need doing upstairs&lt;/em&gt; but I&amp;#8217;ve been putting off for ages. You may then think, &amp;#8220;I know, I&amp;#8217;ll get someone else to do all that!&amp;#8221;  &lt;/p&gt;

	&lt;p&gt;I&amp;#8217;ll need to be able to mark each item as done, when it&amp;#8217;s done (obviously). But, what if an item is done, but I&amp;#8217;m not 100% happy with it. What do we call that? Partially done? Done, but revisit one day? Hmmm. We&amp;#8217;ll have to come back to that one. Now, I work alone (sigma male before it became popular), so other people are of no interest to me. But, if I was to go to the trouble of designing and writing my item tracker, I might be able to make a few quid off all that work, so I&amp;#8217;d make it multi-user. With that decided, I&amp;#8217;ll want to assign items to different people. And they should be able to move items around as they see fit. &lt;/p&gt;

	&lt;h2&gt;What was that Basecamp thing?&lt;/h2&gt;

	&lt;p&gt;I remembered that I watched a Youtube vid by Jason Fried, where he was demoing an issue tracker they were working on called &lt;a href="https://www.youtube.com/watch?v=CpZ4j_z_o_k"&gt;Fizzy&lt;/a&gt;&lt;/p&gt;

	&lt;p&gt;Today I thought I&amp;#8217;d have a look for it and it turns out it&amp;#8217;s open source and you can create a free account. Of course I had to give it a try&amp;#8230; &lt;/p&gt;

	&lt;p&gt;&lt;img alt="Fizzy homepage" src="/img/2026-04-25/fizzy_home.webp" title="Fizzy homepage" /&gt;&lt;/p&gt;

	&lt;p&gt;Looking at it from the lens of my requirements, how does it fare?&lt;/p&gt;

	&lt;h3&gt;Can I create tasks / todo&amp;#8217;s / somethings?&lt;/h3&gt;

	&lt;p&gt;Fizzy uses, or is inspired by, the Kanban system so the main unit that is tracked is called a card. Fair enough. So I&amp;#8217;m happy with that.&lt;/p&gt;

	&lt;h3&gt;Can you give a card a name?&lt;/h3&gt;

	&lt;p&gt;&lt;img alt="Creating a card" src="/img/2026-04-25/fizzy_create_card.webp" title="Creating a card" /&gt; &lt;/p&gt;

	&lt;p&gt;Yes. There&amp;#8217;d be little point in having everything called &lt;em&gt;untitled&lt;/em&gt; but Fizzy will name your unnamed card that if you can&amp;#8217;t be arsed with all the typing.&lt;/p&gt;

	&lt;p&gt;Let&amp;#8217;s create a card and call it:&lt;/p&gt;

	&lt;p&gt;&lt;img alt="Viewing a card" src="/img/2026-04-25/fizzy_view_card.webp" title="Viewing a card" /&gt; &lt;/p&gt;

	&lt;p&gt;How very meta of me!&lt;/p&gt;

	&lt;p&gt;Once you&amp;#8217;ve created a card, people can add comments, progress updates etc. Integral to the kanban system is moving a card through different stages until it eventually reaches &lt;strong&gt;done&lt;/strong&gt; (hopefully).&lt;/p&gt;

	&lt;h3&gt;Done, but revisit?&lt;/h3&gt;

	&lt;p&gt;Remember earlier I said that occasionally I have a task which is sorted, but not sorted &lt;em&gt;properly&lt;/em&gt;. At some point I&amp;#8217;m going to have to completely redo it. How does Fizzy deal with those sorts of issues? Easy, just add a new column:&lt;/p&gt;

	&lt;p&gt;&lt;img alt="Creating a new column" src="/img/2026-04-25/fizzy_revisit.webp" title="Creating a new column" /&gt; &lt;/p&gt;

	&lt;p&gt;And then, it appears on your board:&lt;/p&gt;

	&lt;p&gt;&lt;img alt="New column on board" src="/img/2026-04-25/fizzy_revisit2.webp" title="New column on board" /&gt; &lt;/p&gt;

	&lt;p&gt;That is pretty nice, eh?&lt;/p&gt;

	&lt;h3&gt;Yes, but what about projects???&lt;/h3&gt;

	&lt;p&gt;This one had me stumped for about 30 seconds. Then I realised: create a new board. Each board is a project. Again, it can&amp;#8217;t possibly get much easier than that. &lt;/p&gt;

	&lt;h3&gt;Yes, but what about priorities???&lt;/h3&gt;

	&lt;p&gt;I suppose you just create columns named &lt;em&gt;urgent&lt;/em&gt;, &lt;em&gt;high priority&lt;/em&gt; etc.&lt;/p&gt;

	&lt;h2&gt;Conclusion&lt;/h2&gt;

	&lt;p&gt;Ever since &lt;span class="caps"&gt;DHH&lt;/span&gt; announced rubyonrails back in the early 2000&amp;#8217;s, I&amp;#8217;ve periodically checked up on what Basecamp, or 37signals, are up to. I&amp;#8217;ve always liked their can-do, just go for it attitude.&lt;/p&gt;

	&lt;p&gt;It seems they&amp;#8217;ve sorted another problem in an elegant, simple to use way (and the help system is excellent). I&amp;#8217;ve only messed about for about half an hour, but I&amp;#8217;m going to stick with this one for a bit.&lt;/p&gt;

	&lt;h2&gt;Updates&lt;/h2&gt;

	&lt;p&gt;&lt;mark&gt;2026-04-26&lt;/mark&gt;&lt;/p&gt;

	&lt;p&gt;Apparently, they&amp;#8217;re back to 37signals now so the title is now incorrect. With that out of the way, I&amp;#8217;ve got to say:&lt;/p&gt;

	&lt;p&gt;&lt;img alt="Wow, this is good" src="/img/2026-04-25/wow.webp" title="Wow, this is good" /&gt; &lt;/p&gt;

	&lt;p&gt;Wow, this is good. I signed up for an account yesterday, and today I always have a Fizzy tab open in my browser while I&amp;#8217;m coding. It&amp;#8217;s just so &lt;em&gt;easy&lt;/em&gt; to use. Here&amp;#8217;s my new workflow thanks to Fizzy.&lt;/p&gt;

	&lt;p&gt;1. Write some code&lt;br /&gt;
2. Notice something that isn&amp;#8217;t quite right.&lt;br /&gt;
3. Add a card in Fizzy with a brief description&lt;br /&gt;
4. &lt;span class="caps"&gt;GOTO&lt;/span&gt; 1&lt;/p&gt;

	&lt;p&gt;At the moment, I&amp;#8217;ve got everything in the &amp;#8220;maybe&amp;#8221; column, which is just an ongoing dump of things I notice, or resurface while I&amp;#8217;m working. &lt;/p&gt;

	&lt;p&gt;&lt;img alt="Fizzy board" src="/img/2026-04-25/fizzy_board.webp" title="Fizzy board" /&gt; &lt;/p&gt;

	&lt;p&gt;I&amp;#8217;ve added comments to some cards, with further notes, or ideas that may be useful when I come back to it and try to decide what to do. &lt;/p&gt;

	&lt;p&gt;Having a tool like this for notes, bugs, ideas, todo&amp;#8217;s is now going to be as important as Mercurial for version control. Once I&amp;#8217;ve got the project I&amp;#8217;m working on now completed, I may think about having go at writing something similar myself. If that happens, I&amp;#8217;ll write about it here of course.&lt;/p&gt;

	&lt;p&gt;Great work, 37signals. &lt;/p&gt;</content><category term="software"></category><category term="software"></category><category term="todo"></category></entry><entry><title>Backing Up Retro Game Library using Rsync</title><link href="https://simonh.uk/2026/02/10/backing-up-retro-game-library-using-rsync/" rel="alternate"></link><published>2026-02-10T00:00:00+00:00</published><updated>2026-02-12T00:00:00+00:00</updated><author><name>Simon Harrison</name></author><id>tag:simonh.uk,2026-02-10:/2026/02/10/backing-up-retro-game-library-using-rsync/</id><summary type="html">	&lt;p&gt;No &lt;span class="caps"&gt;GUI&lt;/span&gt; needed&lt;/p&gt;</summary><content type="html">	&lt;p&gt;&lt;img alt="rsync logo" src="/img/2026-02-10/rsync.webp" title="rsync logo" /&gt;&lt;/p&gt;

	&lt;p&gt;In this post, I thought I&amp;#8217;d share my simple method for keeping my (mainly) retro games backed up on a &lt;span class="caps"&gt;USB&lt;/span&gt; hard drive. To start with, I was doing it all manually, but that soon grew tiresome so I decided to use the tried and trusted &lt;a href="https://linux.die.net/man/1/rsync"&gt;rsync&lt;/a&gt; to save time. Before I ran any commands on my proper game directory, I created a test folder to make sure everything worked as I wanted. Rsync is a program with lots of options, but here I&amp;#8217;m only using it for a simple backup from one tree to another. Let&amp;#8217;s get started!&lt;/p&gt;

	&lt;p&gt;If you&amp;#8217;re not familiar with rsync, it generally takes a source folder and a destination folder, preceded by whatever options you want to use. Below, I&amp;#8217;m using &lt;code&gt;-navi&lt;/code&gt; which means:&lt;/p&gt;

	&lt;p&gt;&lt;code&gt;-n&lt;/code&gt; &amp;#8211; run in test mode (dry run)&lt;br /&gt;
&lt;code&gt;-a&lt;/code&gt; &amp;#8211; run in archive mode (which includes lots of options to save typing)&lt;br /&gt;
&lt;code&gt;-v&lt;/code&gt; &amp;#8211; run in verbose mode to give us info&lt;br /&gt;
&lt;code&gt;-i&lt;/code&gt; &amp;#8211; itemize what files are going to be added, deleted etc.&lt;/p&gt;

	&lt;p&gt;As you can see from the output below, rsync when used with &lt;code&gt;-navi&lt;/code&gt; gives us a summary of everything that it&amp;#8217;s going to do.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;[simon@computer 14:38:24] ~/tmp
$ rsync -navi Games/ Games-backup
sending incremental file list
created directory Games-backup
cd+++++++++ ./
cd+++++++++ gb/
&amp;gt;f+++++++++ gb/A-mazing Tater (USA).gb
&amp;gt;f+++++++++ gb/Adventures of Lolo (Europe) (SGB Enhanced).gb
&amp;gt;f+++++++++ gb/Adventures of Star Saver, The (USA, Europe).gb
&amp;gt;f+++++++++ gb/Kirby&amp;#39;s Block Ball (USA, Europe) (SGB Enhanced).gb
&amp;gt;f+++++++++ gb/Kirby&amp;#39;s Dream Land (USA, Europe).gb
&amp;gt;f+++++++++ gb/Kirby&amp;#39;s Dream Land 2 (USA, Europe) (SGB Enhanced).gb
&amp;gt;f+++++++++ gb/Kirby&amp;#39;s Pinball Land (USA, Europe).gb
&amp;gt;f+++++++++ gb/Kirby&amp;#39;s Star Stacker (USA, Europe) (SGB Enhanced).gb
&amp;gt;f+++++++++ gb/Wario Blast Featuring Bomberman! (USA, Europe) (SGB Enhanced).gb
&amp;gt;f+++++++++ gb/Wario Land - Super Mario Land 3 (World).gb
&amp;gt;f+++++++++ gb/Wario Land 3 (World) (En,Ja).gbc
&amp;gt;f+++++++++ gb/Wario Land II (USA, Europe) (SGB Enhanced) (GB Compatible).gbc
&amp;gt;f+++++++++ gb/Yoshi (USA).gb
&amp;gt;f+++++++++ gb/Yoshi&amp;#39;s Cookie (USA, Europe).gb
cd+++++++++ gba/
&amp;gt;f+++++++++ gba/Celeste 2 (v1.0) (Aftermarket).gba
&amp;gt;f+++++++++ gba/Celeste Classic (World) (v1.2) (Aftermarket) (Unl).gba
cd+++++++++ gg/
&amp;gt;f+++++++++ gg/Castle of Illusion Starring Mickey Mouse (USA, Europe, Brazil) (En).sms
&amp;gt;f+++++++++ gg/Chase H.Q. (USA).sms
&amp;gt;f+++++++++ gg/Choplifter III (USA).gg
&amp;gt;f+++++++++ gg/Excellent Dizzy Collection, The (Europe).sms
&amp;gt;f+++++++++ gg/GG Aleste (Japan) (En).gg
&amp;gt;f+++++++++ gg/GG Aleste 3 (Japan) (En) (Aleste Collection).gg
&amp;gt;f+++++++++ gg/GG Aleste II (Japan) (En) (Aleste Collection).gg
&amp;gt;f+++++++++ gg/Galaga 2 (Europe).gg
&amp;gt;f+++++++++ gg/Sonic &amp;amp; Tails (Japan) (En).gg
&amp;gt;f+++++++++ gg/Sonic &amp;amp; Tails 2 (Japan) (En).gg
&amp;gt;f+++++++++ gg/Sonic The Hedgehog (World) (Rev A).gg
&amp;gt;f+++++++++ gg/Sonic The Hedgehog 2 (World).gg
&amp;gt;f+++++++++ gg/Streets of Rage (World).gg
&amp;gt;f+++++++++ gg/Streets of Rage 2 (World).gg
&amp;gt;f+++++++++ gg/Super Space Invaders (USA, Europe).gg
&amp;gt;f+++++++++ gg/Tails Adventure (World) (En,Ja).gg
&amp;gt;f+++++++++ gg/Terminator 2 - Judgment Day (World).gg
&amp;gt;f+++++++++ gg/Terminator, The (USA, Europe).gg
cd+++++++++ ngc/
&amp;gt;f+++++++++ ngc/Bust-A-Move Pocket (USA).ngc
&amp;gt;f+++++++++ ngc/Crush Roller (World) (En,Ja).ngc
&amp;gt;f+++++++++ ngc/Fantastic Night Dreams - Cotton (Europe).ngc
&amp;gt;f+++++++++ ngc/Fatal Fury F-Contact - Pocket Fighting Series (World) (En,Ja).ngc
&amp;gt;f+++++++++ ngc/King of Fighters R-2 - Pocket Fighting Series (World) (En,Ja).ngc
&amp;gt;f+++++++++ ngc/Last Blade, The - Beyond the Destiny (USA, Europe).ngc
&amp;gt;f+++++++++ ngc/Magical Drop Pocket (USA, Europe).ngc
&amp;gt;f+++++++++ ngc/Rockman - Battle &amp;amp; Fighters (Japan).ngc
&amp;gt;f+++++++++ ngc/SNK Gals&amp;#39; Fighters (USA, Europe).ngc
&amp;gt;f+++++++++ ngc/SNK vs. Capcom - Card Fighters&amp;#39; Clash - SNK Version (USA, Europe).ngc
&amp;gt;f+++++++++ ngc/SNK vs. Capcom - The Match of the Millennium (World) (En,Ja).ngc
&amp;gt;f+++++++++ ngc/Sonic The Hedgehog - Pocket Adventure (World) (En,Ja).ngc
cd+++++++++ pce/
&amp;gt;f+++++++++ pce/Bomberman &amp;#39;93 (USA).pce
&amp;gt;f+++++++++ pce/Bomberman (USA).pce
&amp;gt;f+++++++++ pce/Chase H.Q. (USA).pce
&amp;gt;f+++++++++ pce/Darius Alpha (Japan) (En) (SG Enhanced).pce
&amp;gt;f+++++++++ pce/Darius Plus (Japan) (En) (SG Enhanced).pce
&amp;gt;f+++++++++ pce/Final Soldier (Japan) (En).pce
&amp;gt;f+++++++++ pce/Galaga &amp;#39;88 (Japan) (En).pce
&amp;gt;f+++++++++ pce/Gradius (Japan) (En).pce
&amp;gt;f+++++++++ pce/ImageFight (Japan) (En).pce
&amp;gt;f+++++++++ pce/Pac-Land (USA).pce
&amp;gt;f+++++++++ pce/R-Type I (Japan) (En).pce
&amp;gt;f+++++++++ pce/R-Type II (Japan) (En) (V1.1).pce
&amp;gt;f+++++++++ pce/Raiden (USA).pce
&amp;gt;f+++++++++ pce/Salamander (Japan) (En).pce
&amp;gt;f+++++++++ pce/Soldier Blade (USA).pce
&amp;gt;f+++++++++ pce/Space Invaders - Fukkatsu no Hi (Japan).pce
&amp;gt;f+++++++++ pce/Super Star Soldier (USA).pce
&amp;gt;f+++++++++ pce/Turrican (USA).pce

sent 3,171 bytes  received 266 bytes  6,874.00 bytes/sec
total size is 54,620,304  speedup is 15,891.85 (DRY RUN)&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;Once we&amp;#8217;re happy that our command is going to do what we intend it to do, we can remove the &lt;code&gt;-n&lt;/code&gt; switch to make the initial backup:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;[simon@computer 14:38:40] ~/tmp
$ rsync -avi Games/ Games-backup
sending incremental file list
created directory Games-backup
cd+++++++++ ./
cd+++++++++ gb/
&amp;gt;f+++++++++ gb/A-mazing Tater (USA).gb
&amp;gt;f+++++++++ gb/Adventures of Lolo (Europe) (SGB Enhanced).gb
&amp;gt;f+++++++++ gb/Adventures of Star Saver, The (USA, Europe).gb
&amp;gt;f+++++++++ gb/Kirby&amp;#39;s Block Ball (USA, Europe) (SGB Enhanced).gb
&amp;gt;f+++++++++ gb/Kirby&amp;#39;s Dream Land (USA, Europe).gb
&amp;gt;f+++++++++ gb/Kirby&amp;#39;s Dream Land 2 (USA, Europe) (SGB Enhanced).gb
&amp;gt;f+++++++++ gb/Kirby&amp;#39;s Pinball Land (USA, Europe).gb
&amp;gt;f+++++++++ gb/Kirby&amp;#39;s Star Stacker (USA, Europe) (SGB Enhanced).gb
&amp;gt;f+++++++++ gb/Wario Blast Featuring Bomberman! (USA, Europe) (SGB Enhanced).gb
&amp;gt;f+++++++++ gb/Wario Land - Super Mario Land 3 (World).gb
&amp;gt;f+++++++++ gb/Wario Land 3 (World) (En,Ja).gbc
&amp;gt;f+++++++++ gb/Wario Land II (USA, Europe) (SGB Enhanced) (GB Compatible).gbc
&amp;gt;f+++++++++ gb/Yoshi (USA).gb
&amp;gt;f+++++++++ gb/Yoshi&amp;#39;s Cookie (USA, Europe).gb
cd+++++++++ gba/
&amp;gt;f+++++++++ gba/Celeste 2 (v1.0) (Aftermarket).gba
&amp;gt;f+++++++++ gba/Celeste Classic (World) (v1.2) (Aftermarket) (Unl).gba
cd+++++++++ gg/
&amp;gt;f+++++++++ gg/Castle of Illusion Starring Mickey Mouse (USA, Europe, Brazil) (En).sms
&amp;gt;f+++++++++ gg/Chase H.Q. (USA).sms
&amp;gt;f+++++++++ gg/Choplifter III (USA).gg
&amp;gt;f+++++++++ gg/Excellent Dizzy Collection, The (Europe).sms
&amp;gt;f+++++++++ gg/GG Aleste (Japan) (En).gg
&amp;gt;f+++++++++ gg/GG Aleste 3 (Japan) (En) (Aleste Collection).gg
&amp;gt;f+++++++++ gg/GG Aleste II (Japan) (En) (Aleste Collection).gg
&amp;gt;f+++++++++ gg/Galaga 2 (Europe).gg
&amp;gt;f+++++++++ gg/Sonic &amp;amp; Tails (Japan) (En).gg
&amp;gt;f+++++++++ gg/Sonic &amp;amp; Tails 2 (Japan) (En).gg
&amp;gt;f+++++++++ gg/Sonic The Hedgehog (World) (Rev A).gg
&amp;gt;f+++++++++ gg/Sonic The Hedgehog 2 (World).gg
&amp;gt;f+++++++++ gg/Streets of Rage (World).gg
&amp;gt;f+++++++++ gg/Streets of Rage 2 (World).gg
&amp;gt;f+++++++++ gg/Super Space Invaders (USA, Europe).gg
&amp;gt;f+++++++++ gg/Tails Adventure (World) (En,Ja).gg
&amp;gt;f+++++++++ gg/Terminator 2 - Judgment Day (World).gg
&amp;gt;f+++++++++ gg/Terminator, The (USA, Europe).gg
cd+++++++++ ngc/
&amp;gt;f+++++++++ ngc/Bust-A-Move Pocket (USA).ngc
&amp;gt;f+++++++++ ngc/Crush Roller (World) (En,Ja).ngc
&amp;gt;f+++++++++ ngc/Fantastic Night Dreams - Cotton (Europe).ngc
&amp;gt;f+++++++++ ngc/Fatal Fury F-Contact - Pocket Fighting Series (World) (En,Ja).ngc
&amp;gt;f+++++++++ ngc/King of Fighters R-2 - Pocket Fighting Series (World) (En,Ja).ngc
&amp;gt;f+++++++++ ngc/Last Blade, The - Beyond the Destiny (USA, Europe).ngc
&amp;gt;f+++++++++ ngc/Magical Drop Pocket (USA, Europe).ngc
&amp;gt;f+++++++++ ngc/Rockman - Battle &amp;amp; Fighters (Japan).ngc
&amp;gt;f+++++++++ ngc/SNK Gals&amp;#39; Fighters (USA, Europe).ngc
&amp;gt;f+++++++++ ngc/SNK vs. Capcom - Card Fighters&amp;#39; Clash - SNK Version (USA, Europe).ngc
&amp;gt;f+++++++++ ngc/SNK vs. Capcom - The Match of the Millennium (World) (En,Ja).ngc
&amp;gt;f+++++++++ ngc/Sonic The Hedgehog - Pocket Adventure (World) (En,Ja).ngc
cd+++++++++ pce/
&amp;gt;f+++++++++ pce/Bomberman &amp;#39;93 (USA).pce
&amp;gt;f+++++++++ pce/Bomberman (USA).pce
&amp;gt;f+++++++++ pce/Chase H.Q. (USA).pce
&amp;gt;f+++++++++ pce/Darius Alpha (Japan) (En) (SG Enhanced).pce
&amp;gt;f+++++++++ pce/Darius Plus (Japan) (En) (SG Enhanced).pce
&amp;gt;f+++++++++ pce/Final Soldier (Japan) (En).pce
&amp;gt;f+++++++++ pce/Galaga &amp;#39;88 (Japan) (En).pce
&amp;gt;f+++++++++ pce/Gradius (Japan) (En).pce
&amp;gt;f+++++++++ pce/ImageFight (Japan) (En).pce
&amp;gt;f+++++++++ pce/Pac-Land (USA).pce
&amp;gt;f+++++++++ pce/R-Type I (Japan) (En).pce
&amp;gt;f+++++++++ pce/R-Type II (Japan) (En) (V1.1).pce
&amp;gt;f+++++++++ pce/Raiden (USA).pce
&amp;gt;f+++++++++ pce/Salamander (Japan) (En).pce
&amp;gt;f+++++++++ pce/Soldier Blade (USA).pce
&amp;gt;f+++++++++ pce/Space Invaders - Fukkatsu no Hi (Japan).pce
&amp;gt;f+++++++++ pce/Super Star Soldier (USA).pce
&amp;gt;f+++++++++ pce/Turrican (USA).pce

sent 54,639,115 bytes  received 1,310 bytes  109,280,850.00 bytes/sec
total size is 54,620,304  speedup is 1.00&lt;/code&gt;&lt;/pre&gt;

	&lt;p class="info"&gt;Make sure to include the trailing slash after the source directory otherwise rsync will copy the &lt;code&gt;Games&lt;/code&gt; directory as well (which is not what we want):&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;[simon@computer 14:46:29] ~/tmp
$ rsync -navi Games Games-backup
sending incremental file list
cd+++++++++ Games/
cd+++++++++ Games/gb/
&amp;gt;f+++++++++ Games/gb/A-mazing Tater (USA).gb
&amp;gt;f+++++++++ Games/gb/Adventures of Lolo (Europe) (SGB Enhanced).gb
&amp;gt;f+++++++++ Games/gb/Adventures of Star Saver, The (USA, Europe).gb
&amp;gt;f+++++++++ Games/gb/Kirby&amp;#39;s Block Ball (USA, Europe) (SGB Enhanced).gb
&amp;gt;f+++++++++ Games/gb/Kirby&amp;#39;s Dream Land (USA, Europe).gb
&amp;gt;f+++++++++ Games/gb/Kirby&amp;#39;s Dream Land 2 (USA, Europe) (SGB Enhanced).gb
&amp;gt;f+++++++++ Games/gb/Kirby&amp;#39;s Pinball Land (USA, Europe).gb
&amp;gt;f+++++++++ Games/gb/Kirby&amp;#39;s Star Stacker (USA, Europe) (SGB Enhanced).gb
&amp;gt;f+++++++++ Games/gb/Wario Blast Featuring Bomberman! (USA, Europe) (SGB Enhanced).gb
&amp;gt;f+++++++++ Games/gb/Wario Land - Super Mario Land 3 (World).gb
&amp;gt;f+++++++++ Games/gb/Wario Land 3 (World) (En,Ja).gbc
&amp;gt;f+++++++++ Games/gb/Wario Land II (USA, Europe) (SGB Enhanced) (GB Compatible).gbc
&amp;gt;f+++++++++ Games/gb/Yoshi (USA).gb
&amp;gt;f+++++++++ Games/gb/Yoshi&amp;#39;s Cookie (USA, Europe).gb
cd+++++++++ Games/gba/
&amp;gt;f+++++++++ Games/gba/Celeste 2 (v1.0) (Aftermarket).gba
&amp;gt;f+++++++++ Games/gba/Celeste Classic (World) (v1.2) (Aftermarket) (Unl).gba
cd+++++++++ Games/gg/
&amp;gt;f+++++++++ Games/gg/Castle of Illusion Starring Mickey Mouse (USA, Europe, Brazil) (En).sms
&amp;gt;f+++++++++ Games/gg/Chase H.Q. (USA).sms
&amp;gt;f+++++++++ Games/gg/Choplifter III (USA).gg
&amp;gt;f+++++++++ Games/gg/Excellent Dizzy Collection, The (Europe).sms
&amp;gt;f+++++++++ Games/gg/GG Aleste (Japan) (En).gg
&amp;gt;f+++++++++ Games/gg/GG Aleste 3 (Japan) (En) (Aleste Collection).gg
&amp;gt;f+++++++++ Games/gg/GG Aleste II (Japan) (En) (Aleste Collection).gg
&amp;gt;f+++++++++ Games/gg/Galaga 2 (Europe).gg
&amp;gt;f+++++++++ Games/gg/Sonic &amp;amp; Tails (Japan) (En).gg
&amp;gt;f+++++++++ Games/gg/Sonic &amp;amp; Tails 2 (Japan) (En).gg
&amp;gt;f+++++++++ Games/gg/Sonic The Hedgehog (World) (Rev A).gg
&amp;gt;f+++++++++ Games/gg/Sonic The Hedgehog 2 (World).gg
&amp;gt;f+++++++++ Games/gg/Streets of Rage (World).gg
&amp;gt;f+++++++++ Games/gg/Streets of Rage 2 (World).gg
&amp;gt;f+++++++++ Games/gg/Super Space Invaders (USA, Europe).gg
&amp;gt;f+++++++++ Games/gg/Tails Adventure (World) (En,Ja).gg
&amp;gt;f+++++++++ Games/gg/Terminator 2 - Judgment Day (World).gg
&amp;gt;f+++++++++ Games/gg/Terminator, The (USA, Europe).gg
cd+++++++++ Games/ngc/
&amp;gt;f+++++++++ Games/ngc/Bust-A-Move Pocket (USA).ngc
&amp;gt;f+++++++++ Games/ngc/Crush Roller (World) (En,Ja).ngc
&amp;gt;f+++++++++ Games/ngc/Fantastic Night Dreams - Cotton (Europe).ngc
&amp;gt;f+++++++++ Games/ngc/Fatal Fury F-Contact - Pocket Fighting Series (World) (En,Ja).ngc
&amp;gt;f+++++++++ Games/ngc/King of Fighters R-2 - Pocket Fighting Series (World) (En,Ja).ngc
&amp;gt;f+++++++++ Games/ngc/Last Blade, The - Beyond the Destiny (USA, Europe).ngc
&amp;gt;f+++++++++ Games/ngc/Magical Drop Pocket (USA, Europe).ngc
&amp;gt;f+++++++++ Games/ngc/Rockman - Battle &amp;amp; Fighters (Japan).ngc
&amp;gt;f+++++++++ Games/ngc/SNK Gals&amp;#39; Fighters (USA, Europe).ngc
&amp;gt;f+++++++++ Games/ngc/SNK vs. Capcom - Card Fighters&amp;#39; Clash - SNK Version (USA, Europe).ngc
&amp;gt;f+++++++++ Games/ngc/SNK vs. Capcom - The Match of the Millennium (World) (En,Ja).ngc
&amp;gt;f+++++++++ Games/ngc/Sonic The Hedgehog - Pocket Adventure (World) (En,Ja).ngc
cd+++++++++ Games/pce/
&amp;gt;f+++++++++ Games/pce/Bomberman &amp;#39;93 (USA).pce
&amp;gt;f+++++++++ Games/pce/Bomberman (USA).pce
&amp;gt;f+++++++++ Games/pce/Chase H.Q. (USA).pce
&amp;gt;f+++++++++ Games/pce/Darius Alpha (Japan) (En) (SG Enhanced).pce
&amp;gt;f+++++++++ Games/pce/Darius Plus (Japan) (En) (SG Enhanced).pce
&amp;gt;f+++++++++ Games/pce/Final Soldier (Japan) (En).pce
&amp;gt;f+++++++++ Games/pce/Galaga &amp;#39;88 (Japan) (En).pce
&amp;gt;f+++++++++ Games/pce/Gradius (Japan) (En).pce
&amp;gt;f+++++++++ Games/pce/ImageFight (Japan) (En).pce
&amp;gt;f+++++++++ Games/pce/Pac-Land (USA).pce
&amp;gt;f+++++++++ Games/pce/R-Type I (Japan) (En).pce
&amp;gt;f+++++++++ Games/pce/R-Type II (Japan) (En) (V1.1).pce
&amp;gt;f+++++++++ Games/pce/Raiden (USA).pce
&amp;gt;f+++++++++ Games/pce/Salamander (Japan) (En).pce
&amp;gt;f+++++++++ Games/pce/Soldier Blade (USA).pce
&amp;gt;f+++++++++ Games/pce/Space Invaders - Fukkatsu no Hi (Japan).pce
&amp;gt;f+++++++++ Games/pce/Super Star Soldier (USA).pce
&amp;gt;f+++++++++ Games/pce/Turrican (USA).pce

sent 3,187 bytes  received 232 bytes  6,838.00 bytes/sec
total size is 54,620,304  speedup is 15,975.52 (DRY RUN)&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;Now that we&amp;#8217;ve run rsync and copied all our games to our backup folder, running the same command again should not produce any changes. Let&amp;#8217;s check:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;[simon@computer 14:55:15] ~/tmp
$ rsync -avi Games/ Games-backup
sending incremental file list

sent 2,957 bytes  received 17 bytes  5,948.00 bytes/sec
total size is 54,620,304  speedup is 18,365.94&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;rsync hasn&amp;#8217;t done anything by the looks of it, which is as we expect. Now, lets add a couple of new games to our source folder. We&amp;#8217;re in the mood for a bit of hockey so we&amp;#8217;ll add two games, one Gameboy game, one Game Gear one. Let&amp;#8217;s see if rsync spots them:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;[simon@computer 14:55:20] ~/tmp
$ rsync -navi Games/ Games-backup
sending incremental file list
.d..t...... gb/
&amp;gt;f+++++++++ gb/NHL Blades of Steel (USA).gbc
.d..t...... gg/
&amp;gt;f+++++++++ gg/NHL All-Star Hockey (USA).gg

sent 3,040 bytes  received 29 bytes  6,138.00 bytes/sec
total size is 56,193,168  speedup is 18,309.93 (DRY RUN)&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;It sure did! Let&amp;#8217;s have rsync add them to our backup directory:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;[simon@computer 15:00:19] ~/tmp
$ rsync -avi Games/ Games-backup
sending incremental file list
.d..t...... gb/
&amp;gt;f+++++++++ gb/NHL Blades of Steel (USA).gbc
.d..t...... gg/
&amp;gt;f+++++++++ gg/NHL All-Star Hockey (USA).gg

sent 1,576,360 bytes  received 69 bytes  3,152,858.00 bytes/sec
total size is 56,193,168  speedup is 35.65&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;I really like the &lt;code&gt;-i&lt;/code&gt; option, as we can see exactly what rsync has done. &lt;/p&gt;

	&lt;h2&gt;What about files I&amp;#8217;ve deleted?&lt;/h2&gt;

	&lt;p&gt;If you&amp;#8217;re trying to manage a backup directory manually, it can be a lot of work, keeping track of files and folders added, modified and deleted. rsync has a handy &lt;code&gt;--delete&lt;/code&gt; option which will delete files from the destination folder that aren&amp;#8217;t in the source folder. For our example use case in this post about managing our retro game library backups, we may have a rom that doesn&amp;#8217;t work. So we&amp;#8217;d like it gone from both folders. &lt;/p&gt;

	&lt;p&gt;We decide to get rid of a Wario game and a Turrican game. These have already been backed up, but the &lt;code&gt;--delete&lt;/code&gt; option tells rsync to delete anything that&amp;#8217;s in the destination folder, but not in the source folder. Let&amp;#8217;s run rsync in test mode:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;[simon@computer 15:16:04] ~/tmp
$ rsync -navi --delete Games/ Games-backup
sending incremental file list
*deleting   gb/Wario Blast Featuring Bomberman! (USA, Europe) (SGB Enhanced).gb
*deleting   pce/Turrican (USA).pce
.d..t...... gb/
.d..t...... pce/

sent 2,942 bytes  received 120 bytes  6,124.00 bytes/sec
total size is 55,668,880  speedup is 18,180.56 (DRY RUN)&lt;/code&gt;&lt;/pre&gt;

	&lt;h2&gt;What about file / directory renames?&lt;/h2&gt;

	&lt;p&gt;Let&amp;#8217;s say we decide to stop being so lazy and rename &lt;code&gt;gb&lt;/code&gt; to &lt;code&gt;Gameboy&lt;/code&gt;. Will rsync be smart enough to notice that and simply rename it for us at the backup? Or, will it assume this a brand new directory and copy all the same files again? Let&amp;#8217;s find out:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;[simon@computer 11:23:14] master ~/tmp
$ rsync -navi --delete Games/ Games-backup/
sending incremental file list
*deleting   gb/Yoshi&amp;#39;s Cookie (USA, Europe).gb
*deleting   gb/Yoshi (USA).gb
*deleting   gb/Wario Land II (USA, Europe) (SGB Enhanced) (GB Compatible).gbc
*deleting   gb/Wario Land 3 (World) (En,Ja).gbc
*deleting   gb/Wario Land - Super Mario Land 3 (World).gb
*deleting   gb/NHL Blades of Steel (USA).gbc
*deleting   gb/Kirby&amp;#39;s Star Stacker (USA, Europe) (SGB Enhanced).gb
*deleting   gb/Kirby&amp;#39;s Pinball Land (USA, Europe).gb
*deleting   gb/Kirby&amp;#39;s Dream Land 2 (USA, Europe) (SGB Enhanced).gb
*deleting   gb/Kirby&amp;#39;s Dream Land (USA, Europe).gb
*deleting   gb/Kirby&amp;#39;s Block Ball (USA, Europe) (SGB Enhanced).gb
*deleting   gb/Adventures of Star Saver, The (USA, Europe).gb
*deleting   gb/Adventures of Lolo (Europe) (SGB Enhanced).gb
*deleting   gb/A-mazing Tater (USA).gb
*deleting   gb/
.d..t...... ./
cd+++++++++ Gameboy/
&amp;gt;f+++++++++ Gameboy/A-mazing Tater (USA).gb
&amp;gt;f+++++++++ Gameboy/Adventures of Lolo (Europe) (SGB Enhanced).gb
&amp;gt;f+++++++++ Gameboy/Adventures of Star Saver, The (USA, Europe).gb
&amp;gt;f+++++++++ Gameboy/Kirby&amp;#39;s Block Ball (USA, Europe) (SGB Enhanced).gb
&amp;gt;f+++++++++ Gameboy/Kirby&amp;#39;s Dream Land (USA, Europe).gb
&amp;gt;f+++++++++ Gameboy/Kirby&amp;#39;s Dream Land 2 (USA, Europe) (SGB Enhanced).gb
&amp;gt;f+++++++++ Gameboy/Kirby&amp;#39;s Pinball Land (USA, Europe).gb
&amp;gt;f+++++++++ Gameboy/Kirby&amp;#39;s Star Stacker (USA, Europe) (SGB Enhanced).gb
&amp;gt;f+++++++++ Gameboy/NHL Blades of Steel (USA).gbc
&amp;gt;f+++++++++ Gameboy/Wario Land - Super Mario Land 3 (World).gb
&amp;gt;f+++++++++ Gameboy/Wario Land 3 (World) (En,Ja).gbc
&amp;gt;f+++++++++ Gameboy/Wario Land II (USA, Europe) (SGB Enhanced) (GB Compatible).gbc
&amp;gt;f+++++++++ Gameboy/Yoshi (USA).gb
&amp;gt;f+++++++++ Gameboy/Yoshi&amp;#39;s Cookie (USA, Europe).gb

sent 2,999 bytes  received 724 bytes  7,446.00 bytes/sec
total size is 55,668,880  speedup is 14,952.69 (DRY RUN)&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;As you see, rsync went with the second option. At the time of running this, I really wasn&amp;#8217;t sure what would happen. After doing a bit of research, it&amp;#8217;s because rsync doesn&amp;#8217;t keep any state between runs. Each time you run it, it simply compares the source and the destination and because we passed &lt;code&gt;--delete&lt;/code&gt; rsync simply sees a folder (and all it&amp;#8217;s contents) need deleting, and a new folder needs copying to the backup. &lt;/p&gt;

	&lt;p&gt;It&amp;#8217;s the same result if you rename a file or multiple files:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;[simon@computer 11:30:08] master ~/tmp
$ rsync -navi --delete Games/ Games-backup/
sending incremental file list
*deleting   Gameboy/Blades of Steel (USA).gbc
.d..t...... Gameboy/
&amp;gt;f+++++++++ Gameboy/NHL Blades of Steel (USA).gbc

sent 2,953 bytes  received 60 bytes  6,026.00 bytes/sec
total size is 55,668,880  speedup is 18,476.23 (DRY RUN)&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;With files only a few kilobytes in size, it&amp;#8217;s not really an issue. However, if you&amp;#8217;re backing up big files taking up gigabytes, this is going to be a problem. There are patches and workarounds, but I think you should take this into account up front and try to avoid renaming directories in particular! &lt;/p&gt;

	&lt;h2&gt;Conclusion&lt;/h2&gt;

	&lt;p&gt;So now, I&amp;#8217;m happy that the command:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;$ rsync -avi --delete Games/ Games-backup/&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;is going to backup anything newly added, and delete any games that I deliberately deleted. By the way, rsync also keeps track of modified files. So if you replace a game with another one shaing exactly the same name (but different contents), rsync will copy that one to your backup folder too.&lt;/p&gt;

	&lt;p&gt;I think rsync is the perfect program for managing a backup of your games / roms. You only have &lt;strong&gt;one&lt;/strong&gt; folder that you need to keep tidy and rsync will keep a perfect duplicate of that folder for you. &lt;/p&gt;

	&lt;p&gt;A lot of people (myself included) may have had some fear of using rsync for this sort of task but once you&amp;#8217;ve tried it on a test directory and dialled in your options, I don&amp;#8217;t tnink anything can beat it. &lt;/p&gt;</content><category term="software"></category><category term="retro"></category><category term="tips"></category><category term="linux"></category><category term="software"></category></entry><entry><title>Using Emacs as a Word Processor</title><link href="https://simonh.uk/2025/09/27/using-emacs-as-a-word-processor/" rel="alternate"></link><published>2025-09-27T00:00:00+01:00</published><updated>2025-09-27T00:00:00+01:00</updated><author><name>Simon Harrison</name></author><id>tag:simonh.uk,2025-09-27:/2025/09/27/using-emacs-as-a-word-processor/</id><summary type="html">	&lt;p&gt;Is there anything Emacs can&amp;#8217;t do?&lt;/p&gt;</summary><content type="html">	&lt;p&gt;&lt;img alt="Emacs enriched text mode" src="/img/2025-09-27/emacs-enriched-mode.webp" title="Emacs enriched text mode" /&gt;&lt;/p&gt;

	&lt;p&gt;Ever since &lt;a href="https://lock.cmpxchg8b.com/"&gt;Tavis Ormandy&lt;/a&gt; got Wordperfect 8 &lt;a href="https://github.com/taviso/wpunix"&gt;working&lt;/a&gt; on modern Linux it&amp;#8217;s been bugging me that we don&amp;#8217;t have many options for word processing in the terminal. &lt;/p&gt;

	&lt;p&gt;Thanks to his amazing work, we do now have an enterprise grade word processor running in our terminals. However, there are problems.&lt;/p&gt;

	&lt;h2&gt;Problems with Wordperfect 8&lt;/h2&gt;

	&lt;p&gt;&lt;img alt="WordPerfect 8 for Unix" src="/img/2025-09-27/wpunix.webp" title="WordPerfect 8 for Unix" /&gt;&lt;/p&gt;

	&lt;p&gt;The most glaring problems are that it&amp;#8217;s closed source, hasn&amp;#8217;t been updated in &lt;em&gt;27 years&lt;/em&gt;, and it&amp;#8217;s not exactly, &lt;em&gt;user friendly&lt;/em&gt;. The &lt;span class="caps"&gt;PDF&lt;/span&gt; manual is ~700 pages! There&amp;#8217;s also the file format problem. It&amp;#8217;s not a publicly documented format. You can certainly open a &lt;code&gt;.wp&lt;/code&gt; file in plenty of software:&lt;/p&gt;

	&lt;ul&gt;
		&lt;li&gt;Libre Office&lt;/li&gt;
		&lt;li&gt;Abiword&lt;/li&gt;
		&lt;li&gt;Google Docs&lt;/li&gt;
	&lt;/ul&gt;

	&lt;p&gt;will all open an old wordperfect document, thanks most likely to &lt;a href="https://libwpd.sourceforge.net/"&gt;libwpd&lt;/a&gt; but you&amp;#8217;ll only be able to &lt;em&gt;edit&lt;/em&gt; it in Wordperfect. Which raises the question, &lt;/p&gt;

	&lt;blockquote&gt;
		&lt;p&gt;&amp;#8220;will I be able to open / edit these documents in twenty years time?&amp;#8221;&lt;/p&gt;
	&lt;/blockquote&gt;

	&lt;p&gt;So, while wpunix is an interesting piece of software, it&amp;#8217;s probably &lt;strong&gt;not&lt;/strong&gt; the best idea to do all your writing with it. &lt;/p&gt;

	&lt;p&gt;So, as I&amp;#8217;m inclined to do, I set about seeing what other options I have for editing documents on the command line.&lt;/p&gt;

	&lt;h2&gt;&lt;span class="caps"&gt;JOE&lt;/span&gt; Editor (Jstar)&lt;/h2&gt;

	&lt;p&gt;&lt;img alt="Joe jstar mode" src="/img/2025-09-27/joe-editor.webp" title="Joe jstar mode" /&gt;&lt;/p&gt;

	&lt;p&gt;I was already familiar with &lt;a href="https://joe-editor.sourceforge.io/"&gt;&lt;span class="caps"&gt;JOE&lt;/span&gt;&lt;/a&gt; and vaguely remembered that it had a Wordstar emulation mode. I&amp;#8217;ve never used Wordstar, but know it&amp;#8217;s still considered  irreplaceable by some &lt;a href="https://sfwriter.com/wordstar.htm"&gt;notable users&lt;/a&gt;. So, I had a play with it but it&amp;#8217;s not quite what I&amp;#8217;m after. The only formatting that one could consider somewhat out of the ordinary with Jstar is being able to centre text. &lt;/p&gt;

	&lt;h2&gt;What Should a Word Processor Do?&lt;/h2&gt;

	&lt;p&gt;To my mind, at a minimum, a word processor should be able to:&lt;/p&gt;

	&lt;ul&gt;
		&lt;li&gt;bold, underline and italicize text&lt;/li&gt;
		&lt;li&gt;Centre, left and right align text&lt;/li&gt;
		&lt;li&gt;Justify text&lt;/li&gt;
		&lt;li&gt;Have various types of headings&lt;/li&gt;
	&lt;/ul&gt;

	&lt;p&gt;I was amazed that no such command line program seemed to exist. Yeah sure, we&amp;#8217;ve got loads of Markdown editors, but I don&amp;#8217;t consider Markdown to be anything related to word processing. I even thought about attempting to make my own format (how hard could it be?!). But luckily, I came across:&lt;/p&gt;

	&lt;h2&gt;&lt;span class="caps"&gt;RFC&lt;/span&gt; 1896 The text/enriched &lt;span class="caps"&gt;MIME&lt;/span&gt; Content-type&lt;/h2&gt;

	&lt;p&gt;For some reason, I always forget than &lt;em&gt;any&lt;/em&gt; computer problem was almost certainly solved years ago. And so it was for this problem. &lt;a href="https://www.rfc-editor.org/rfc/rfc1896.html"&gt;&lt;span class="caps"&gt;RFC&lt;/span&gt; 1896&lt;/a&gt; was suggested in 1996 to allow formatting of email messages. Unfortunately, it never caught on. Still, it exists and is a standard and Emacs has an enriched mode! See &lt;a href="https://www.gnu.org/software/emacs/manual/html_node/emacs/Enriched-Text.html"&gt;here&lt;/a&gt; for online documentation. Here&amp;#8217;s the &amp;#8220;source&amp;#8221; code for the screenshot at the top of this post:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;Content-Type: text/enriched
Text-Width: 70

&amp;lt;flushright&amp;gt;This is right aligned 

&amp;lt;/flushright&amp;gt;&amp;lt;center&amp;gt;

Here is some &amp;lt;bold&amp;gt;bold &amp;lt;/bold&amp;gt;text and here is some that is &amp;lt;italic&amp;gt;italic&amp;lt;/italic&amp;gt;.

&amp;lt;/center&amp;gt;&amp;lt;flushboth&amp;gt;

Enriched mode is a minor mode for editing formatted text files in a
WYSIWYG (What You See Is What You Get) fashion. When Enriched mode is
enabled, you can apply various formatting properties to the text in
the buffer, such as fonts and colors; upon saving the buffer, those
properties are saved together with the text, using the MIME
‘text/enriched’ file format.


Enriched mode is typically used with Text mode (see Text Mode). It is
not compatible with Font Lock mode, which is used by many major modes,
including most programming language modes, for syntax highlighting
(see Font Lock mode).  Unlike Enriched mode, Font Lock mode assigns
text properties automatically, based on the current buffer contents;
those properties are not saved to disk.

&amp;lt;/flushboth&amp;gt;&amp;lt;center&amp;gt;

&amp;lt;underline&amp;gt;Underlined Heading&amp;lt;/underline&amp;gt;

&amp;lt;/center&amp;gt;&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;The only thing that seems to be missing from enriched-mode is increasing the font size. There&amp;#8217;s a discussion on the mailing list that goes into detail:&lt;/p&gt;

	&lt;p&gt;&lt;a href="https://lists.gnu.org/archive/html/help-gnu-emacs/2025-06/msg00146.html"&gt;Making selected text larger in enriched mode&lt;/a&gt; &lt;/p&gt;

	&lt;p&gt;Apart from that, enriched-mode seems pretty much perfect for writing. &lt;/p&gt;

	&lt;h2&gt;Using Emacs Enriched Mode&lt;/h2&gt;

	&lt;p&gt;I won&amp;#8217;t go into great detail as the documentation link above explains everything, but here are my brief notes:&lt;/p&gt;

	&lt;p&gt;Type &lt;code&gt;M-x enriched-mode&lt;/code&gt; on a new file to activate the mode.&lt;sup class="footnote" id="fnrevbd637d5c3b58403fbdd2b79093be41ca-1"&gt;&lt;a href="#fnbd637d5c3b58403fbdd2b79093be41ca-1"&gt;1&lt;/a&gt;&lt;/sup&gt; Then, you only really &lt;em&gt;need&lt;/em&gt; to remember two shortcuts:&lt;/p&gt;

	&lt;p&gt;&lt;code&gt;Alt-o&lt;/code&gt; to bring up the &lt;em&gt;Options(?)&lt;/em&gt; menu and &lt;code&gt;Alt-j&lt;/code&gt; to bring up the &lt;em&gt;Justify&lt;/em&gt; menu.&lt;/p&gt;

	&lt;p&gt;Then, you can just press a single letter:&lt;/p&gt;

	&lt;p&gt;&lt;img alt="Emacs enriched mode options menu" src="/img/2025-09-27/alt-o.png" title="Emacs enriched mode options menu" /&gt;&lt;/p&gt;

	&lt;p&gt;&lt;code&gt;Alt-o&lt;/code&gt; &lt;code&gt;b&lt;/code&gt; to bold for example&lt;/p&gt;

	&lt;p&gt;&lt;img alt="Emacs enriched mode justification menu" src="/img/2025-09-27/alt-j.png" title="Emacs enriched mode justification menu" /&gt;&lt;/p&gt;

	&lt;p&gt;&lt;code&gt;Alt-j&lt;/code&gt; &lt;code&gt;b&lt;/code&gt; to justify &lt;/p&gt;

	&lt;h2&gt;Plain Text Benefits&lt;/h2&gt;

	&lt;p&gt;As enriched text is simply plain text with a bit of markup, it&amp;#8217;s easily versionable (&lt;span class="caps"&gt;RCS&lt;/span&gt;, Mercurial / Git et al.). You can write a script to convert your enriched text to another format etc. &lt;/p&gt;

	&lt;h2&gt;Conclusion&lt;/h2&gt;

	&lt;p&gt;As I wrote in &lt;a href="https://simonh.uk/2025/09/13/why-i-use-gnu-nano-as-my-default-editor/"&gt;Why I use &lt;span class="caps"&gt;GNU&lt;/span&gt; Nano&lt;/a&gt; post, I don&amp;#8217;t use Emacs as my text editor. But, I&amp;#8217;ll probably start using it as my word processor instead&amp;#8230;&lt;/p&gt;

	&lt;h2 class="footnotes"&gt;Footnotes&lt;/h2&gt;

	&lt;p class="footnote" id="fnbd637d5c3b58403fbdd2b79093be41ca-1"&gt;&lt;sup&gt;1&lt;/sup&gt; I&amp;#8217;m trying to find an easy way to start Emacs in enriched mode. Will update post if I find it!&lt;/p&gt;</content><category term="software"></category><category term="writing"></category><category term="emacs"></category><category term="gnu"></category></entry><entry><title>Microsoft Edit vs GNU Nano</title><link href="https://simonh.uk/2025/09/23/microsoft-edit-vs-gnu-nano/" rel="alternate"></link><published>2025-09-23T00:00:00+01:00</published><updated>2025-09-24T00:00:00+01:00</updated><author><name>Simon Harrison</name></author><id>tag:simonh.uk,2025-09-23:/2025/09/23/microsoft-edit-vs-gnu-nano/</id><summary type="html">	&lt;p&gt;An apple vs an orange&lt;/p&gt;</summary><content type="html">	&lt;p&gt;&lt;img alt="Edit v.1.2.0 running on Linux" src="/img/2025-09-23/edit_linux.webp" title="Edit v.1.2.0 running on Linux" /&gt;&lt;/p&gt;

	&lt;p&gt;I&amp;#8217;ve been seeing a few posts / videos claiming that Microsoft Edit is &lt;strong&gt;better&lt;/strong&gt; than &lt;span class="caps"&gt;GNU&lt;/span&gt; Nano. Sorry, it isn&amp;#8217;t. Furthermore, it hasn&amp;#8217;t been designed to be better than &lt;em&gt;anything&lt;/em&gt;! &lt;/p&gt;

	&lt;p&gt;Microsoft explained why they created Edit on their &lt;a href="https://devblogs.microsoft.com/commandline/edit-is-now-open-source/"&gt;Devblog&lt;/a&gt;:&lt;/p&gt;

	&lt;blockquote&gt;
		&lt;p&gt;&lt;em&gt;What motivated us to build Edit was the need for a default  CLI  text editor in 64-bit versions of Windows. 32-bit versions of Windows ship with the  MS-DOS editor , but 64-bit versions do not have a  CLI  editor installed inbox. From there, we narrowed down our options…&lt;/em&gt;&lt;/p&gt;
	&lt;/blockquote&gt;

	&lt;blockquote&gt;
		&lt;p&gt;&lt;em&gt;Many of you are probably familiar with the “How do I exit vim?” meme. While it is relatively simple to learn the magic exit incantation, it’s certainly not a coincidence that this often turns up as a stumbling block for new and old programmers.&lt;/em&gt;&lt;/p&gt;
	&lt;/blockquote&gt;

	&lt;blockquote&gt;
		&lt;p&gt;&lt;em&gt;Because we wanted to avoid this for a built-in default editor, we decided that we wanted a modeless editor for Windows (versus a modal editor where new users would have to remember different modes of operation and how to switch between them).&lt;/em&gt;&lt;/p&gt;
	&lt;/blockquote&gt;

	&lt;blockquote&gt;
		&lt;p&gt;&lt;em&gt;This unfortunately limited our choices to a list of editors that either had no first-party support for Windows or were too big to bundle them with every version of the OS. As a result, Edit was born.&lt;/em&gt;&lt;/p&gt;
	&lt;/blockquote&gt;

	&lt;p&gt;It should be noted that this &lt;em&gt;new&lt;/em&gt;, Rust written Edit, is a modern version of an old &lt;span class="caps"&gt;DOS&lt;/span&gt; program of the same name. Here&amp;#8217;s what that looked like:&lt;/p&gt;

	&lt;p&gt;&lt;img alt="DOS edit" src="/img/2025-09-23/edit_dos.webp" title="DOS edit" /&gt;&lt;/p&gt;

	&lt;p&gt;Edit is designed for very simple editing. Below is the &lt;em&gt;entire&lt;/em&gt; man page:&lt;/p&gt;

	&lt;p&gt;&lt;img alt="Manpage on Linux" src="/img/2025-09-23/edit_manpage.webp" title="Manpage on Linux" /&gt;&lt;/p&gt;

	&lt;p&gt;Nice and clear, and the program is learnable in approximately &lt;em&gt;5 minutes&lt;/em&gt;. In contrast, you&amp;#8217;ll probably need a couple of hours to fully learn and become productive with &lt;span class="caps"&gt;GNU&lt;/span&gt; Nano. They have different histories and purposes. Here is the first paragraph from the Nano &lt;span class="caps"&gt;README&lt;/span&gt;:&lt;/p&gt;

	&lt;p&gt;&lt;img alt="Nano history" src="/img/2025-09-23/nano_readme.webp" title="Nano history" /&gt;&lt;/p&gt;

	&lt;p&gt;Nano began life as a clone of Pico&lt;sup class="footnote" id="fnrev1c07585a4a1d4bbf9a56714b0d4ece8d-1"&gt;&lt;a href="#fn1c07585a4a1d4bbf9a56714b0d4ece8d-1"&gt;1&lt;/a&gt;&lt;/sup&gt;, then added features that users wished Pico had, whilst retaining its simple, easy to use nature. Edit is a re-implementation of &lt;span class="caps"&gt;DOS&lt;/span&gt; edit.com. The stated goal of Edit is&lt;/p&gt;

	&lt;blockquote&gt;
		&lt;p&gt;&lt;em&gt;&amp;#8230;to provide an accessible editor that even users largely unfamiliar with terminals can easily use.&lt;/em&gt;&lt;/p&gt;
	&lt;/blockquote&gt;

	&lt;p&gt;You can type characters, delete them, search and replace, and that&amp;#8217;s about it. Which is fine. Remember, this will ship with &lt;em&gt;Windows&lt;/em&gt;. Now I haven&amp;#8217;t used Windows at home since, maybe, 2006. MS Edit is not targeted at me, or anyone other than &lt;em&gt;their&lt;/em&gt; customers. It&amp;#8217;s there because they &lt;em&gt;should&lt;/em&gt; have a terminal text editor. It&amp;#8217;s not fancy or powerful but it will allow their customers to edit text files from the command line in a stress free way.&lt;/p&gt;

	&lt;p&gt;Personally, I like what they&amp;#8217;ve done. There&amp;#8217;s no configuration and no options to muck about with. You fire it up and do what you need to do. &lt;/p&gt;

	&lt;h2&gt;Conclusion&lt;/h2&gt;

	&lt;p&gt;I think Edit is a great bit of software. I like that Microsoft have released it as open source, and that they release Linux builds. I&amp;#8217;ve had a play with it and haven&amp;#8217;t felt the need to delete it. To my mind, it has already achieved it&amp;#8217;s stated goal. There&amp;#8217;s not really anything else that it needs at this point. I&amp;#8217;m sure Microsoft are fully aware that if they start adding new features, it becomes &lt;em&gt;harder&lt;/em&gt; to learn, &lt;em&gt;harder&lt;/em&gt; to use. &lt;span class="caps"&gt;GNU&lt;/span&gt; Nano doesn&amp;#8217;t have that contraint. It wants to be simple, but also useful. &lt;/p&gt;

	&lt;p&gt;Microsoft Edit is good but &lt;span class="caps"&gt;GNU&lt;/span&gt; Nano is better and always will be. &lt;/p&gt;

	&lt;h2 class="web"&gt;See Also&lt;/h2&gt;

	&lt;p&gt;&lt;a href="https://simonh.uk/2025/09/13/why-i-use-gnu-nano-as-my-default-editor/"&gt;Why I use &lt;span class="caps"&gt;GNU&lt;/span&gt; Nano as my Default Editor&lt;/a&gt;&lt;/p&gt;

	&lt;p&gt;&lt;a href="https://www.nano-editor.org/"&gt;&lt;span class="caps"&gt;GNU&lt;/span&gt; Nano Homepage&lt;/a&gt;&lt;/p&gt;

	&lt;p&gt;&lt;a href="https://github.com/microsoft/edit"&gt;Microsoft Edit Repository&lt;/a&gt;&lt;/p&gt;

	&lt;h2 class="footnotes"&gt;Footnotes&lt;/h2&gt;

	&lt;p class="footnote" id="fn1c07585a4a1d4bbf9a56714b0d4ece8d-1"&gt;&lt;sup&gt;1&lt;/sup&gt; Pico (pi)ne (co)mposer was the editor for the &lt;a href="https://en.wikipedia.org/wiki/Pine_%28email_client%29"&gt;&lt;span class="caps"&gt;PINE&lt;/span&gt;&lt;/a&gt; email program. Very popular in the 90&amp;#8217;s and kept alive in the fork &lt;a href="https://alpineapp.email/"&gt;Alpine&lt;/a&gt; which I use on my servers.&lt;/p&gt;</content><category term="software"></category><category term="linux"></category><category term="windows"></category><category term="gnu"></category></entry><entry><title>Why I use GNU Nano as my Default Editor</title><link href="https://simonh.uk/2025/09/13/why-i-use-gnu-nano-as-my-default-editor/" rel="alternate"></link><published>2025-09-13T00:00:00+01:00</published><updated>2025-09-14T00:00:00+01:00</updated><author><name>Simon Harrison</name></author><id>tag:simonh.uk,2025-09-13:/2025/09/13/why-i-use-gnu-nano-as-my-default-editor/</id><summary type="html">	&lt;p&gt;Nano isn&amp;#8217;t Pico (or &lt;span class="caps"&gt;TIP&lt;/span&gt;)&lt;/p&gt;</summary><content type="html">	&lt;p&gt;&lt;img alt="GNU Nano Logo" src="/img/logo/nano-logo.png" title="GNU Nano Logo" /&gt;&lt;/p&gt;

	&lt;h2&gt;The Backstory&lt;/h2&gt;

	&lt;p&gt;For many years, my default text editor has been &lt;a href="https://community.linuxmint.com/software/view/xed"&gt;xed&lt;/a&gt; as it comes with Linux Mint, my distro of choice for some years. I&amp;#8217;ve used xed for most of the &lt;a href="https://bottlepy.org/docs/dev/"&gt;bottle.py&lt;/a&gt; programs I&amp;#8217;ve written. I never really thought about it, just used it as it got the job done. I generally use Nano for editing files over &lt;span class="caps"&gt;SSH&lt;/span&gt; and have also used that for many years.&lt;/p&gt;

	&lt;p&gt;A few weeks ago, I was thinking about my workflow and wondered why I wasn&amp;#8217;t using a terminal based editor? Here&amp;#8217;s how I use bottle.py&lt;/p&gt;

	&lt;p&gt;1. Fire up &lt;a href="https://github.com/tmux/tmux/wiki"&gt;tmux&lt;/a&gt;&lt;br /&gt;
2. Run &amp;#8220;python3 name-of-program.py&amp;#8220;&lt;br /&gt;
3. Open another tmux window for &lt;a href="https://www.mercurial-scm.org/"&gt;Mercurial&lt;/a&gt; checkins&lt;/p&gt;

	&lt;p&gt;Here&amp;#8217;s a screenshot of my terminal whilst writing this post:&lt;/p&gt;

	&lt;p&gt;&lt;img alt="" src="/img/2025-09-13/terminal.webp" /&gt;&lt;/p&gt;

	&lt;p&gt;It started bothering me that I was faffing about having to use my mouse to navigate between the terminal and my text editor. So I decided to find a terminal (non &lt;span class="caps"&gt;GUI&lt;/span&gt;) editor that would suit me. &lt;/p&gt;

	&lt;h2&gt;My Editor Requirements&lt;/h2&gt;

	&lt;p&gt;I was well aware of the &lt;strong&gt;hundreds&lt;/strong&gt; of editors available for Linux, having had a play with most of them at one time or another:&lt;/p&gt;

	&lt;p&gt;Emacs, Vim, Jed, Vile, Jove, Joe, Nano, mg, etc&amp;#8230;.&lt;/p&gt;

	&lt;p&gt;So I had a think about what was vital and what would be nice-to-have features.&lt;/p&gt;

	&lt;h3&gt;Vital&lt;/h3&gt;

	&lt;ul&gt;
		&lt;li&gt;&lt;strong&gt;Multiple buffers&lt;/strong&gt; &amp;#8212; I usually have at least two source code files open at a time when I&amp;#8217;m coding.&lt;/li&gt;
	&lt;/ul&gt;

	&lt;ul&gt;
		&lt;li&gt;&lt;strong&gt;Good support for keyboard shortcuts&lt;/strong&gt; &amp;#8212; Of course, this is subjective. Emacs and Vim let you do anything, but I don&amp;#8217;t normally need that much power! However, most things that I may need to do on a daily basis should have a shortcut.&lt;/li&gt;
	&lt;/ul&gt;

	&lt;ul&gt;
		&lt;li&gt;&lt;strong&gt;Remapping of keys&lt;/strong&gt; &amp;#8212; I&amp;#8217;ve used &lt;a href="https://colemak.com/"&gt;Colemak&lt;/a&gt; since about 2008, so what might be great for &lt;span class="caps"&gt;QWERTY&lt;/span&gt;, may not be great for me.&lt;/li&gt;
	&lt;/ul&gt;

	&lt;ul&gt;
		&lt;li&gt;&lt;strong&gt;Quickly delete lines&lt;/strong&gt; &amp;#8212; One of the features I really liked with Vim is &lt;code&gt;dd&lt;/code&gt; to delete a line, followed by &lt;code&gt;.&lt;/code&gt; to delete subsequent lines.&lt;/li&gt;
	&lt;/ul&gt;

	&lt;h3&gt;Nice to Have&amp;#8217;s&lt;/h3&gt;

	&lt;ul&gt;
		&lt;li&gt;&lt;strong&gt;Sensible Defaults&lt;/strong&gt; &amp;#8212; This is one of the things I&amp;#8217;ve always liked about Nano. You can just start using it. Shortcuts are visible at the bottom of the window if you need them.&lt;/li&gt;
	&lt;/ul&gt;

	&lt;ul&gt;
		&lt;li&gt;&lt;strong&gt;Show a line at 80 columns&lt;/strong&gt; &amp;#8212; I don&amp;#8217;t like long lines of code.&lt;/li&gt;
	&lt;/ul&gt;

	&lt;ul&gt;
		&lt;li&gt;&lt;strong&gt;Quickly comment / uncomment code&lt;/strong&gt; &amp;#8212; I got very used to xed&amp;#8217;s &lt;code&gt;Ctrl-/&lt;/code&gt; for this purpose!&lt;/li&gt;
	&lt;/ul&gt;

	&lt;ul&gt;
		&lt;li&gt;&lt;strong&gt;Auto ident&lt;/strong&gt; &amp;#8212; I use Python more than any other language, so auto indenting is hard to live without.&lt;/li&gt;
	&lt;/ul&gt;

	&lt;ul&gt;
		&lt;li&gt;&lt;strong&gt;Syntax Highlighting&lt;/strong&gt; &amp;#8212; Not 100% critical, but is often useful for seeing what&amp;#8217;s what.&lt;/li&gt;
	&lt;/ul&gt;

	&lt;ul&gt;
		&lt;li&gt;&lt;strong&gt;Bookmarks&lt;/strong&gt; &amp;#8212; Very useful to be able to mark lines in files and jump between them.&lt;/li&gt;
	&lt;/ul&gt;

	&lt;ul&gt;
		&lt;li&gt;&lt;strong&gt;Scroll without moving cursor&lt;/strong&gt; &amp;#8212; I liked this feature I first saw in Vim. You move the screen but the cursor stays where it is&lt;/li&gt;
	&lt;/ul&gt;

	&lt;ul&gt;
		&lt;li&gt;&lt;strong&gt;Insert a newline above / below current line&lt;/strong&gt; &amp;#8212; Some editors have a shortcut that will insert a newline without having to go to the end of the line, press enter&lt;/li&gt;
	&lt;/ul&gt;

	&lt;h2&gt;Where I Looked Closer at Nano&lt;/h2&gt;

	&lt;p&gt;I won&amp;#8217;t lie, Nano came first to mind. I was already familiar with it and it seems to be installed everywhere I need it. But did it do what I needed (and would like it to do)?&lt;/p&gt;

	&lt;p&gt;Yes, it would (I found out after an hour or so)!&lt;/p&gt;

	&lt;p&gt;I discovered pretty quickly that version 8, released in 2024 had introduced &amp;#8220;modern bindings&amp;#8221;:&lt;/p&gt;

&lt;blockquote&gt;&lt;p&gt;&lt;em&gt;Command-line option  -- modernbindings (-/) makes ^Q quit, ^X cut, ^C copy, ^V paste, ^Z undo, ^Y redo, ^O open a file, ^W write a file, ^R replace, ^G find again, ^D find again backwards, ^A set the mark, ^T jump to a line, ^P show the position, and ^E execute.&lt;/em&gt;&lt;/p&gt;&lt;/blockquote&gt;

	&lt;p&gt;I look at that as a sensible default. The original shortcuts aren&amp;#8217;t terrible, but I like the &lt;span class="caps"&gt;CUA&lt;/span&gt; ones more. So I downloaded the latest tarball (8.6) and compiled it. I added &lt;code&gt;alias nano="nano -/"&lt;/code&gt; to my &lt;code&gt;.bashrc&lt;/code&gt; (and on all my servers). &lt;/p&gt;

	&lt;h2&gt;What I Needed / Wanted&lt;/h2&gt;

	&lt;p&gt;&amp;check; multiple buffers: &lt;code&gt;set multibuffer&lt;/code&gt;&lt;br /&gt;
&amp;check; comment / uncomment code: &lt;code&gt;Alt-3&lt;/code&gt;&lt;br /&gt;
&amp;check; show end of line: &lt;code&gt;set guidestripe 80&lt;/code&gt;&lt;br /&gt;
&amp;check; syntax highlighting: &lt;code&gt;include /usr/local/share/nano/*.nanorc&lt;/code&gt;&lt;br /&gt;
&amp;check; quickly delete lines:&lt;br /&gt;
&lt;code&gt;Alt-delete&lt;/code&gt; to delete entire line&lt;br /&gt;
&lt;code&gt;Alt-backspace&lt;/code&gt; to  delete words&lt;br /&gt;
&amp;check; bookmarks: &amp;#8220;anchors&amp;#8221; in Nano speak.&lt;br /&gt;
&lt;code&gt;Alt-Insert&lt;/code&gt; to set/unset.&lt;br /&gt;
&lt;code&gt;Alt-PgUp&lt;/code&gt; / &lt;code&gt;Alt-PgDn&lt;/code&gt; to cycle through them&lt;br /&gt;
&amp;check; move viewport up and down: &lt;code&gt;Alt--&lt;/code&gt; / &lt;code&gt;Alt-+&lt;/code&gt;&lt;br /&gt;
&amp;check; insert a newline above / below current line&lt;br /&gt;
&lt;code&gt;bind ^N "{home}{enter}{up}" main&lt;/code&gt; &lt;br /&gt;
&lt;code&gt;bind ^k "{end}{enter}" main&lt;/code&gt;&lt;/p&gt;

	&lt;h2&gt;My Tweaks&lt;/h2&gt;

	&lt;p&gt;Many, many years ago,&lt;sup class="footnote" id="fnrev5329114433a4497c9378f74fd279a861-1"&gt;&lt;a href="#fn5329114433a4497c9378f74fd279a861-1"&gt;1&lt;/a&gt;&lt;/sup&gt; I came across the idea of having the arrow keys accessible on the home row using either the &lt;code&gt;CTRL&lt;/code&gt; or &lt;code&gt;ALT&lt;/code&gt; keys. Similar to this keyboard:&lt;/p&gt;

	&lt;p&gt;&lt;img alt="" src="/img/2025-09-13/arrow_keys.png" /&gt;&lt;/p&gt;

	&lt;p&gt;As I was hoping to somewhat optimize my text editing, I figured I&amp;#8217;d try and get some often used keys where I wanted them.&lt;sup class="footnote" id="fnrev5329114433a4497c9378f74fd279a861-2"&gt;&lt;a href="#fn5329114433a4497c9378f74fd279a861-2"&gt;2&lt;/a&gt;&lt;/sup&gt; Using &lt;span class="caps"&gt;QWERTY&lt;/span&gt; notation, I now have:&lt;/p&gt;

	&lt;p&gt;&lt;code&gt;Alt-j&lt;/code&gt; &amp;#8212; Left&lt;br /&gt;
&lt;code&gt;Alt-k&lt;/code&gt; &amp;#8212; Down&lt;br /&gt;
&lt;code&gt;Alt-i&lt;/code&gt; &amp;#8212; Up&lt;br /&gt;
&lt;code&gt;Alt-l&lt;/code&gt; &amp;#8212; Right&lt;br /&gt;
&lt;code&gt;Alt-u&lt;/code&gt; &amp;#8212; Home&lt;br /&gt;
&lt;code&gt;Alt-o&lt;/code&gt; &amp;#8212; End&lt;br /&gt;
&lt;code&gt;Alt-h&lt;/code&gt; &amp;#8212; Delete&lt;br /&gt;
&lt;code&gt;Ctrl-k&lt;/code&gt; &amp;#8212; Page Down&lt;br /&gt;
&lt;code&gt;Ctrl-i&lt;/code&gt; &amp;#8212; Page Up&lt;/p&gt;

	&lt;p&gt;Very nice! I&amp;#8217;m already used to them after only a few days. If you&amp;#8217;re interested, below is my &lt;code&gt;.nanorc&lt;/code&gt;&lt;/p&gt;

	&lt;h2&gt;My .nanorc&lt;/h2&gt;

&lt;pre&gt;&lt;code&gt;# $Id: .nanorc,v 1.6 2025/09/15 13:29:21 simon Exp simon $

set multibuffer
set tabsize 4
set tabstospaces
set autoindent
set wordbounds
set quickblank
set trimblanks
set linenumbers
set smarthome
set mouse
set indicator
set guidestripe 80
set positionlog
set quickblank
set stateflags

set brackets &amp;quot;&amp;quot;&amp;#39;)&amp;gt;]}&amp;quot;
set matchbrackets &amp;quot;(&amp;lt;[{)&amp;gt;]}&amp;quot;

set keycolor cyan
set functioncolor cyan
set numbercolor yellow

bind M-5 cycle main

#=============================================
# Experimental: bring useful keys to home row
#=============================================

bind M-n left main
bind M-i right main
bind M-u up main
bind M-e down main
bind M-l home main
bind M-y end main
bind M-h delete main

bind ^u pageup main
bind ^e pagedown main

# newline above current line
bind ^n &amp;quot;{home}{enter}{up}&amp;quot; main

# newline below current line
bind ^k &amp;quot;{end}{enter}&amp;quot; main

include /usr/local/share/nano/*.nanorc
include &amp;quot;~/.nano/tpl.nanorc&amp;quot;&lt;/code&gt;&lt;/pre&gt;

	&lt;h2&gt;Why Not Just Use&amp;#8230;&lt;/h2&gt;

	&lt;p&gt;Of course, anyone who comes here may have their own, possibly strong, opinions about which text editor is &lt;em&gt;the one true editor&lt;/em&gt;. Fair enough, but I can&amp;#8217;t be bothered to spend weeks learning how to use a text editor. &lt;/p&gt;

	&lt;p&gt;I set out to find a &lt;span class="caps"&gt;TUI&lt;/span&gt; editor to do my work with and have found it with &lt;span class="caps"&gt;GNU&lt;/span&gt; Nano.&lt;/p&gt;

	&lt;p&gt;I&amp;#8217;ll quickly mention why some other, obvious editors didn&amp;#8217;t beat Nano for me.&lt;/p&gt;

	&lt;p&gt;1. Emacs&lt;/p&gt;

	&lt;p&gt;Sorry, but having to type &lt;code&gt;Ctrl-X Ctrl-C&lt;/code&gt; to exit isn&amp;#8217;t for me.&lt;/p&gt;

	&lt;p&gt;2. Vim&lt;/p&gt;

	&lt;p&gt;Philosophically, I like the idea of a modal editor. However, in practice, I&amp;#8217;ve always found Vim&amp;#8217;s learning curve not worth the time. If I wrote software for a living, instead of as a hobby, I might invest more time in learning it. Maybe&amp;#8230;&lt;/p&gt;

	&lt;p&gt;3. Micro&lt;/p&gt;

	&lt;p&gt;Micro does seem interesting. However, Nano with &lt;code&gt;--modern-bindings&lt;/code&gt; possibly makes it less interesting.&lt;/p&gt;

	&lt;h2&gt;Conclusion&lt;/h2&gt;

	&lt;p&gt;Like a lot of people, I&amp;#8217;ve been unaware of exactly what Nano is capable of. I&amp;#8217;ve been pressing pageup repeatedly to get to the top of the screen when I could have just pressed &lt;code&gt;Ctrl-home&lt;/code&gt; or &lt;code&gt;Ctrl-end&lt;/code&gt; to go to the beginning or end of the file. &lt;/p&gt;

	&lt;p&gt;Likewise, I never knew that &lt;code&gt;Alt-home&lt;/code&gt; and &lt;code&gt;Alt-end&lt;/code&gt; would take me to the first / last lines in the viewport.&lt;/p&gt;

	&lt;p&gt;Embarrassingly, I didn&amp;#8217;t know that Nano supported multiple buffers. So like a fool, I&amp;#8217;d edit one file on a server, close it, open another one, close that, open the first one again&amp;#8230;&lt;/p&gt;

	&lt;p&gt;Today I&amp;#8217;ve just found that Nano supports &lt;em&gt;soft wrapping&lt;/em&gt; using &lt;code&gt;Alt-s&lt;/code&gt; which has proven useful writing this post in Textile where unwanted newlines are inserted.&lt;/p&gt;

	&lt;p&gt;I think some people in the Linux world see Nano as our Windows Notepad. Not something to be used by serious people with serious things to do. I never thought that, but after reading the excellent documentation on the Nano website (and man / info pages) I&amp;#8217;m now aware of exactly what it can do.&lt;/p&gt;

	&lt;p&gt;I hope that you too, will have another look at this awesome little editor.&lt;/p&gt;

	&lt;p&gt;&lt;a href="https://www.nano-editor.org/"&gt;&lt;img align="center" alt="" src="/img/logo/withnano.png" /&gt;&lt;/a&gt;&lt;/p&gt;

	&lt;h2 class="footnotes"&gt;Footnotes&lt;/h2&gt;

	&lt;p class="footnote" id="fn5329114433a4497c9378f74fd279a861-1"&gt;&lt;sup&gt;1&lt;/sup&gt; I believe it was Ergoemacs that introduced me to this idea.&lt;/p&gt;

	&lt;p class="footnote" id="fn5329114433a4497c9378f74fd279a861-2"&gt;&lt;sup&gt;2&lt;/sup&gt; If you want to do this yourself, here are a couple of tips. You press control by moving your palm outwards and &lt;em&gt;not&lt;/em&gt; by stretching your pinky! Alt is pressed by moving your thumb outwards. It takes a bit of getting used to but is worth it, I think.&lt;/p&gt;</content><category term="software"></category><category term="software"></category><category term="linux"></category><category term="gnu"></category></entry><entry><title>Trying Out OpenBSD Game of Trees (Got)</title><link href="https://simonh.uk/2025/06/08/trying-out-openbsd-game-of-trees-got/" rel="alternate"></link><published>2025-06-08T00:00:00+01:00</published><updated>2026-05-15T00:00:00+01:00</updated><author><name>Simon Harrison</name></author><id>tag:simonh.uk,2025-06-08:/2025/06/08/trying-out-openbsd-game-of-trees-got/</id><summary type="html">	&lt;p&gt;Is less more?&lt;/p&gt;</summary><content type="html">	&lt;p&gt;&lt;a href="https://gameoftrees.org"&gt;&lt;img alt="Got Website" src="/img/2025-06-08/got.webp" title="Got Website" /&gt;&lt;/a&gt;&lt;/p&gt;

	&lt;h2&gt;Background &amp;amp; Motivations&lt;/h2&gt;

	&lt;p&gt;I&amp;#8217;ve been a Mercurial user since about 2017. It&amp;#8217;s always worked well for me, &lt;em&gt;but&lt;/em&gt; I&amp;#8217;ve found myself wondering over the last couple of years if another &lt;span class="caps"&gt;VCS&lt;/span&gt; might be a better fit for me. One reason is that I&amp;#8217;m not an advanced user, using only a fraction of what Mercurial has to offer. I don&amp;#8217;t collaborate with anyone else so I only need to record changes, push my code out to backup servers, revert (occasionally), email patches to my production servers etc. &lt;/p&gt;

	&lt;p&gt;So today, I decided to use Got to track changes on a real project and this post documents how it went. &lt;/p&gt;

	&lt;h2&gt;Installation&lt;/h2&gt;

	&lt;p&gt;&lt;mark&gt;Updated on 2026-05-15&lt;/mark&gt;&lt;/p&gt;

	&lt;h3&gt;Dependencies&lt;/h3&gt;

	&lt;p&gt;On Debian 13 (Trixie), you&amp;#8217;ll need to install the following packages:&lt;/p&gt;

	&lt;p&gt;&lt;code&gt;sudo apt install ncurses-dev pkg-config uuid-dev libbsd-dev libtls-dev&lt;/code&gt;&lt;/p&gt;

	&lt;p&gt;Next, We&amp;#8217;ll need to download and compile Got from &lt;a href="https://gameoftrees.org/releases/portable/"&gt;here&lt;/a&gt;. At the time of writing version 0.113 is the latest. Then, it&amp;#8217;s the usual:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;./configure
make
sudo make install&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;Which will install Got to &lt;code&gt;/usr/local&lt;/code&gt;&lt;/p&gt;

	&lt;p&gt;To check everything worked, run:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;simon@computer:~$ got -h
usage: got [-hV] command [arg ...]
commands: init import clone fetch checkout update log diff blame tree status ref branch tag add remove patch revert commit send cherrypick backout rebase histedit integrate merge stage unstage cat info&lt;/code&gt;&lt;/pre&gt;

	&lt;h2&gt;The Got Way&lt;/h2&gt;

	&lt;p&gt;One of the things I found most appealing about Got is that repositories and work trees &lt;strong&gt;have&lt;/strong&gt; to live in different locations. When you think about it, that makes complete sense. Most of us are used to having our repo&amp;#8217;s inside our working directory. Yes, it&amp;#8217;s convenient but I&amp;#8217;ve now come to the conclusion that it&amp;#8217;s not optimal. Your repo is one thing, your working directory is another thing. &lt;/p&gt;

	&lt;h2&gt;Creating the Repo and importing code&lt;/h2&gt;

	&lt;p&gt;As this project is a static web site, I dectided to create a separate directory for my repo:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;got init /home/simon/tmp/repo/first_project.got&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;There&amp;#8217;s no requirement to append &lt;code&gt;.got&lt;/code&gt; to the project, but it reminds me what I&amp;#8217;m using. &lt;/p&gt;

&lt;pre&gt;&lt;code&gt;simon@computer:~/tmp$ tree repo/first_project.got/&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;Let&amp;#8217;s have a look to see what Got has created for us:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;tree repo/first_project.got
repo/first_project.got/
├── config
├── description
├── HEAD
├── objects
│   └── pack
└── refs

4 directories, 3 files&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;Looks good. The next step may seem a bit clunky, but is what we need to do:&lt;/p&gt;

	&lt;ul&gt;
		&lt;li&gt;Import code into our repository&lt;/li&gt;
		&lt;li&gt;Check out the repository to a worktree&lt;/li&gt;
	&lt;/ul&gt;

	&lt;p&gt;Right now, our repo is empty. Let&amp;#8217;s do our first checkin:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;simon@computer:~/tmp$ got import -r repo/first_project.got/ first_project/
A  /home/simon/tmp/first_project/css/pico.min.css
A  /home/simon/tmp/first_project/css/tacit.min.css
A  /home/simon/tmp/first_project/fonts/Inter-Italic-VariableFont_opsz,wght.woff2
A  /home/simon/tmp/first_project/fonts/Inter-VariableFont_opsz,wght.woff2
A  /home/simon/tmp/first_project/software/visitors/index.html
A  /home/simon/tmp/first_project/banner.png
A  /home/simon/tmp/first_project/index.html
Created branch refs/heads/main with commit 95f800a6d501db76d7fe56978e6c396d0c3736bb&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;Now that our working directory&amp;#8217;s contents have been added to our repo, we can delete the working directory and check out a worktree:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;simon@computer:~/tmp$ rm -r first_project&lt;/code&gt;&lt;/pre&gt;

&lt;pre&gt;&lt;code&gt;simon@computer:~/tmp$ got co repo/first_project.got/ first_project
A  first_project/asus.png
A  first_project/css/pico.min.css
A  first_project/css/tacit.min.css
A  first_project/fonts/Inter-Italic-VariableFont_opsz,wght.woff2
A  first_project/fonts/Inter-VariableFont_opsz,wght.woff2
A  first_project/index.html
A  first_project/software/visitors/index.html
Checked out refs/heads/main: 95f800a6d501db76d7fe56978e6c396d0c3736bb
Now shut up and hack&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;Now, inside our worktree&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;simon@computer:~/tmp/first_project$ got log
-----------------------------------------------
commit 95f800a6d501db76d7fe56978e6c396d0c3736bb (main)
from: Simon Harrison &amp;lt;mail@simonh.uk&amp;gt;
date: Sun Jun  8 20:16:54 2025 UTC

 First checkin&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;Got uses a hidden directory to keep track of things &amp;#8212; &lt;code&gt;.got&lt;/code&gt;. Let&amp;#8217;s see what&amp;#8217;s in there:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;simon@computer:~/tmp/first_project$ ll
total 116K
drwxr-xr-x  6 simon simon 4.0K 2025-06-08 21:21 .
drwxrwxrwx 11 simon simon 4.0K 2025-06-08 21:21 ..
-rw-r--r--  1 simon simon  84K 2025-06-08 21:21 asus.png
drwxr-xr-x  2 simon simon 4.0K 2025-06-08 21:21 css
drwxr-xr-x  2 simon simon 4.0K 2025-06-08 21:21 fonts
drwxr-xr-x  2 simon simon 4.0K 2025-06-08 21:21 .got
-rw-r--r--  1 simon simon 4.6K 2025-06-08 21:21 index.html
drwxr-xr-x  3 simon simon 4.0K 2025-06-08 21:21 software
simon@computer:~/tmp/first_project$ tree .got
.got
├── base-commit
├── file-index
├── format
├── head-ref
├── lock
├── path-prefix
├── repository
└── uuid

1 directory, 8 files&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;Obviously, we&amp;#8217;ll leave all that alone as Got will update them as we check in changes. &lt;/p&gt;

	&lt;p&gt;So at this point, we&amp;#8217;re all setup to track changes to our code. The last thing I want to do right now is set up a backup that I can push to one of my servers.&lt;/p&gt;

	&lt;p&gt;We&amp;#8217;ll do that in our repo:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;simon@computer:~/tmp/first_project.got$ nano got.conf&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;And add the following, adjusting to fit your server&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;remote &amp;quot;simonh&amp;quot; {
  server myserver.com
  protocol ssh
  repository &amp;quot;/home/simon/repo/got/first_project.got&amp;quot;
}&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;For this to work, we need to create a Got repo on our server that matches the &lt;code&gt;repository&lt;/code&gt; value above.&lt;/p&gt;

	&lt;p&gt;With this done, we can &lt;code&gt;got send&lt;/code&gt; our changes. By the way, most commands have aliases:&lt;/p&gt;

	&lt;ul&gt;
		&lt;li&gt;&lt;code&gt;ci&lt;/code&gt; &amp;#8212; commit&lt;/li&gt;
		&lt;li&gt;&lt;code&gt;co&lt;/code&gt; &amp;#8212; checkout&lt;/li&gt;
		&lt;li&gt;&lt;code&gt;se&lt;/code&gt; &amp;#8212; send&lt;/li&gt;
		&lt;li&gt;&lt;code&gt;fe&lt;/code&gt; &amp;#8212; fetch&lt;/li&gt;
		&lt;li&gt;&lt;code&gt;pa&lt;/code&gt; &amp;#8212; patch&lt;/li&gt;
	&lt;/ul&gt;

	&lt;p&gt;Consult the excellent man pages for the full list. Let&amp;#8217;s send our changes to keep them safe:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;simon@computer:~/tmp/first_project$ got se simonh
Connecting to &amp;quot;simonh&amp;quot; ssh://myserver.com/home/simon/repo/got/first_project.got
2 commits colored; 3 objects found; 6 trees scanned
packing 1 reference; 3 objects; deltify: 100%; uploading pack:  2.7K 100%
Server has accepted refs/heads/main&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;Got also comes with Tog, a &lt;span class="caps"&gt;CLI&lt;/span&gt; repository browser:&lt;/p&gt;

	&lt;p&gt;&lt;img alt="Tog repository browser" src="/img/2025-06-08/tog.webp" title="Tog repository browser" /&gt;&lt;/p&gt;

	&lt;h2&gt;Creating &amp;amp; Listing Tags&lt;/h2&gt;

	&lt;p&gt;Tags are equivalent to Mercurial bookmarks &amp;#8212; a label for a commit. &lt;/p&gt;

&lt;pre&gt;&lt;code&gt;simon@computer:~/tmp/first_project$ got tag -l
-----------------------------------------------
tag 0.2 807e609a829c43a9f3f9c8d4c1214b4371fe4485
from: Simon Harrison &amp;lt;mail@simonh.uk&amp;gt;
date: Sun Jun  8 16:12:03 2025 UTC
object: commit 3aa38f1608aee14a1a90a7eae3928f83e4c14baa

 Second test of using tags

-----------------------------------------------
tag 0.1 c291af4175f48db379169437ac1a09e381a631f8
from: Simon Harrison &amp;lt;mail@simonh.uk&amp;gt;
date: Sun Jun  8 13:34:21 2025 UTC
object: commit 8e431b7a506992d02d5e39b283652bb5d3ae9d03

 Just testing out tags&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;Passing &lt;code&gt;-s&lt;/code&gt; gives us a &lt;em&gt;short&lt;/em&gt; one line summary:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;simon@computer:~/tmp/first_project$ got tag -ls
2025-06-08 commit:3aa38f1608 0.2: Second test of using tags
2025-06-08 commit:8e431b7a50 0.1: Just testing out tags&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;We can create a tag easily:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;simon@computer:~/tmp/first_project$ got tag &amp;#39;0.3&amp;#39;
Created tag d1d6792cb83866567525f66875b983faf7dcd4d7

simon@computer:~/tmp/first_project$ got tag -sl
2025-06-09 commit:f257381e43 0.3: Third version
2025-06-08 commit:3aa38f1608 0.2: Second test of using tags
2025-06-08 commit:8e431b7a50 0.1: Just testing out tags&lt;/code&gt;&lt;/pre&gt;

	&lt;h2&gt;Branching &amp;amp; Merging&lt;/h2&gt;

	&lt;p&gt;To be honest, I don&amp;#8217;t branch. If that changes I&amp;#8217;ll update this section.&lt;/p&gt;

	&lt;h2&gt;Conclusion&lt;/h2&gt;

	&lt;p&gt;Initial setup for basic tracking of changes should take no more than fifteen / twenty minutes. Once you&amp;#8217;ve done that, you&amp;#8217;ll have a nice, well-documented &lt;span class="caps"&gt;VCS&lt;/span&gt; that has a tight focus. I&amp;#8217;m going to continue using Got for this one project. I should point out that Got is not Git. Many features are not implemented (and may never be). However, it&amp;#8217;s perfectly usable right now and if you&amp;#8217;re looking for a &lt;em&gt;no frills&lt;/em&gt; &lt;span class="caps"&gt;VCS&lt;/span&gt;, Got may be just what you need.&lt;/p&gt;

	&lt;h2 class="web"&gt;See Also&lt;/h2&gt;

	&lt;p&gt;I wrote a post last year &lt;a href="https://simonh.uk/2024/10/29/first-look-at-openbsd-game-of-trees-got/"&gt;first look at Got&lt;/a&gt;  which may be of interest.&lt;/p&gt;</content><category term="software"></category><category term="VCS"></category><category term="Got"></category></entry><entry><title>First Look at OpenBSD Game of Trees (Got)</title><link href="https://simonh.uk/2024/10/29/first-look-at-openbsd-game-of-trees-got/" rel="alternate"></link><published>2024-10-29T00:00:00+00:00</published><updated>2024-10-29T00:00:00+00:00</updated><author><name>Simon Harrison</name></author><id>tag:simonh.uk,2024-10-29:/2024/10/29/first-look-at-openbsd-game-of-trees-got/</id><summary type="html">	&lt;p&gt;Git stripped back to the bare essentials&lt;/p&gt;</summary><content type="html">	&lt;h1&gt;Git, but simpler (to use, maybe&amp;#8230;)&lt;/h1&gt;

	&lt;p&gt;&lt;img alt="Game of trees logo" src="/img/2024-10-29/got.webp" title="Game of trees logo" /&gt;&lt;/p&gt;

	&lt;p&gt;I&amp;#8217;m a long time &lt;a href="https://www.mercurial-scm.org/"&gt;Mercurial&lt;/a&gt; user. Even so, I keep my eye on other &lt;span class="caps"&gt;VCS&lt;/span&gt;&amp;#8217;s to see what new ideas are developing. A few weeks ago, I came across &lt;a href="https://gameoftrees.org/"&gt;Got&lt;/a&gt;, a reimplementation / reimagining of &lt;a href="https:///git-scm.com"&gt;Git&lt;/a&gt; for use by the OpenBSD people, under a &lt;span class="caps"&gt;BSD&lt;/span&gt; compatible licence.&lt;/p&gt;

	&lt;p&gt;Got claims to take some of the best features from &lt;span class="caps"&gt;CVS&lt;/span&gt;, &lt;span class="caps"&gt;SVN&lt;/span&gt;, Git, Mercurial and Fossil. This I found very interesting. Here are the most noticeable differences I&amp;#8217;ve noticed (for a Git or Mercurial user).&lt;/p&gt;

	&lt;ul&gt;
		&lt;li&gt;Repositories must checked out to a worktree.&lt;/li&gt;
	&lt;/ul&gt;

	&lt;p&gt;Hg and Git users are used to having the repository &lt;em&gt;inside&lt;/em&gt; the worktree (working directory). Got treats a repository and a worktree as two completely different things. Or rather, Got treats the repository as one thing and you can have as many worktrees as you need. The benefit of this model is that you can have different branches checked out at the same time. You can checkout only a subset of the repository. This is also the same model that Fossil uses. When I tried using Fossil years ago, I intensely disliked this &amp;#8220;feature&amp;#8221;, but I&amp;#8217;m now starting to think it makes sense. &lt;/p&gt;

	&lt;ul&gt;
		&lt;li&gt;No built in help&lt;/li&gt;
	&lt;/ul&gt;

	&lt;p&gt;As always, OpenBSD prefers to have excellent man pages to document their software and answer any question you might have. &lt;/p&gt;

&lt;pre&gt;&lt;code&gt;simon@computer:~$ got help
got: unknown command &amp;#39;help&amp;#39;
commands: init import clone fetch checkout update log diff blame tree status ref branch tag add remove patch revert commit send cherrypick backout rebase histedit integrate merge stage unstage cat info&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;Whether that&amp;#8217;s planned to change, I&amp;#8217;m not sure. Probably not.&lt;/p&gt;

	&lt;ul&gt;
		&lt;li&gt;Some important features are currently missing&lt;/li&gt;
	&lt;/ul&gt;

	&lt;p&gt;Last time I checked, file renames weren&amp;#8217;t automatically handled. I believe this is planned to change. Little, quality of life features like &lt;code&gt;hg email&lt;/code&gt; will probably never be implemented. &lt;/p&gt;

	&lt;ul&gt;
		&lt;li&gt;There&amp;#8217;s a steeper learning curve&lt;/li&gt;
	&lt;/ul&gt;

	&lt;p&gt;You really do have to &lt;span class="caps"&gt;RTFM&lt;/span&gt; when it comes to Got. I got stuck on some basic stuff and asked on &lt;span class="caps"&gt;IRC&lt;/span&gt; for assistance. The lead developer, Stefan Sperling is actually a very helpful guy and got me going. Still, be prepared to read the entire man page!&lt;/p&gt;

	&lt;h1&gt;Features I&amp;#8217;d love to see&lt;/h1&gt;

	&lt;ul&gt;
		&lt;li&gt;hg shelve / Git stash&lt;/li&gt;
	&lt;/ul&gt;

	&lt;p&gt;Set aside changes and bring them back later. Very useful, (nearly) impossible to live with once you&amp;#8217;ve used it.&lt;/p&gt;

	&lt;ul&gt;
		&lt;li&gt;Easy emailing of patches&lt;/li&gt;
	&lt;/ul&gt;

	&lt;p&gt;I use &lt;code&gt;hg email -r tip&lt;/code&gt; &lt;em&gt;all the time&lt;/em&gt; when I&amp;#8217;m working on a project.&lt;/p&gt;

	&lt;ul&gt;
		&lt;li&gt;Local revision numbers&lt;/li&gt;
	&lt;/ul&gt;

	&lt;p&gt;Mercurial is (I think) the only current &lt;span class="caps"&gt;VCS&lt;/span&gt; that has local revision numbers. That feature is just &lt;em&gt;so handy&lt;/em&gt;. Much easier for humans to deal with &lt;code&gt;revision 17&lt;/code&gt; than &lt;code&gt;revision bf63491f5a5b&lt;/code&gt;&lt;/p&gt;

	&lt;h2&gt;Conclusion&lt;/h2&gt;

	&lt;p&gt;Got makes it clear on their website they aren&amp;#8217;t seeking to replace anything or to steal you away from your &lt;span class="caps"&gt;VCS&lt;/span&gt; of choice. In the &lt;span class="caps"&gt;FAQ&lt;/span&gt; they state:&lt;/p&gt;

	&lt;blockquote&gt;
		&lt;p&gt;If you are wondering why Got even exists, you can just ignore it.&lt;/p&gt;
	&lt;/blockquote&gt;

	&lt;p&gt;Quite right. There are &lt;strong&gt;far&lt;/strong&gt; too many people on the internet moaning that &lt;em&gt;their&lt;/em&gt; thing is the only thing that matters and if everyone would just use it everyone would be far happier as a result. Got isn&amp;#8217;t one of those projects. &lt;/p&gt;

	&lt;p&gt;It&amp;#8217;s written by, and for, the OpenBSD crew. There&amp;#8217;s a portable port for us Linux types. I&amp;#8217;ll be keeping an eye on this one in case it ends up as useful as &lt;a href="https://opensmtpd.org/"&gt;OpenSMTPD&lt;/a&gt;&lt;/p&gt;</content><category term="software"></category><category term="VCS"></category><category term="Got"></category></entry><entry><title>Using GNU RCS for Managing Configuration Files</title><link href="https://simonh.uk/2023/08/25/using-gnu-rcs-for-managing-configuration-files/" rel="alternate"></link><published>2023-08-25T00:00:00+01:00</published><updated>2026-05-22T00:00:00+01:00</updated><author><name>Simon Harrison</name></author><id>tag:simonh.uk,2023-08-25:/2023/08/25/using-gnu-rcs-for-managing-configuration-files/</id><summary type="html">	&lt;p&gt;Why didn&amp;#8217;t anyone tell me about this years ago?!&lt;/p&gt;</summary><content type="html">	&lt;p&gt;&lt;img alt="GNU Logo" src="/img/logo/gnu.webp" title="GNU Logo" /&gt;&lt;/p&gt;

	&lt;p&gt;As regular readers will know, I&amp;#8217;m a big fan of version control for software projects. You may also know that I&amp;#8217;ve recently started to use &lt;span class="caps"&gt;RCS&lt;/span&gt; for managing single files (shell/Python scripts, &lt;span class="caps"&gt;CGI&lt;/span&gt; scripts etc.). Tonight, I&amp;#8217;d like to present my &lt;strong&gt;simple&lt;/strong&gt; workflow for version controlling configuration files, also using &lt;span class="caps"&gt;RCS&lt;/span&gt;.&lt;/p&gt;

	&lt;h2&gt;The Problem&lt;/h2&gt;

	&lt;p&gt;We Linux users frequently have to create and edit config files. Here is a list of some of mine:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;.vimrc
.nanorc
/etc/smtpd.conf
/etc/aliases
/etc/hosts
/etc/apache2/*
/etc/apt/sources*
...&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;Up until recently, I&amp;#8217;d usually rename a config file to &lt;code&gt;&amp;lt;filename&amp;gt;.bak&lt;/code&gt; in case something went horribly wrong. Come to think of it, that&amp;#8217;s pretty much &lt;b&gt;always&lt;/b&gt; the advice you&amp;#8217;ll be given online. &lt;/p&gt;

	&lt;p&gt;Of course, there&amp;#8217;s a better, more robust way of keeping track of changes you&amp;#8217;ve made, with the ability to roll back to any previous revision. But, it does take a little bit of discipline!&lt;/p&gt;

	&lt;h2&gt;The Solution&lt;/h2&gt;

	&lt;p&gt;Let&amp;#8217;s say you need to edit your &lt;code&gt;.nanorc&lt;/code&gt; &lt;/p&gt;

&lt;pre&gt;&lt;code&gt;simon@computer:~$ mkdir RCS
mkdir: cannot create directory ‘RCS’: File exists&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;OK, good. I&amp;#8217;ve already got a repository setup in my home directory. Let&amp;#8217;s open it up and see what it contains:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;nano .nanorc
 GNU nano 6.2                         .nanorc                                  



















                                [ Read 0 lines ]
^G Help      ^O Write Out ^W Where Is  ^K Cut       ^T Execute   ^C Location
^X Exit      ^R Read File ^\ Replace   ^U Paste     ^J Justify   ^/ Go To Line&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;An empty file which means the file either didn&amp;#8217;t exist or was empty. Let&amp;#8217;s get to work. I&amp;#8217;ll add the settings I want, plus the &lt;span class="caps"&gt;RCS&lt;/span&gt; metadata so I can see the current version number and the date it was checked in:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;  GNU nano 6.2                         .nanorc                           I   S  
#=====================================================================
# $Revision$
# $Date$
# $Author$
#======================================================================

set autoindent
set tabsize 4
set tabstospaces
set softwrap









                               [ Read 10 lines ]
^G Help      ^O Write Out ^W Where Is  ^K Cut       ^T Execute   ^C Location
^X Exit      ^R Read File ^\ Replace   ^U Paste     ^J Justify   ^/ Go To Line&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;Now let&amp;#8217;s checkin the file&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;simon@computer:~$ ci -l .nanorc 
RCS/.nanorc,v  &amp;lt;--  .nanorc
enter description, terminated with single &amp;#39;.&amp;#39; or end of file:
NOTE: This is NOT the log message!
&amp;gt;&amp;gt; First checkin 
&amp;gt;&amp;gt; .
initial revision: 1.1
done
simon@computer:~$ &lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;Let&amp;#8217;s have a look at the file&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;simon@computer:~$ cat .nanorc 
#=====================================================================
# $Revision: 1.1 $
# $Date: 2023/08/25 19:11:01 $
# $Author: simon $
#======================================================================

set autoindent
set tabsize 4
set tabstospaces
set softwrap&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;So, three things are immediately evident:&lt;/p&gt;

	&lt;p&gt;1. The file is version controlled&lt;br /&gt;
2. I can see how many revisions have been made to the file&lt;br /&gt;
3. I can see the datetime of the last revision. Nice. &lt;/p&gt;

	&lt;p&gt;I read somewhere that it&amp;#8217;s a good idea to add the .nanorc files from the &lt;code&gt;/usr/share/nano/*&lt;/code&gt; directory to enable syntax highlighting for lots of filetypes. Let&amp;#8217;s add that to my &lt;code&gt;.nanorc&lt;/code&gt; file:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;  GNU nano 6.2                         .nanorc                           I   S  
#=====================================================================
# $Revision: 1.1 $
# $Date: 2023/08/25 19:11:01 $
# $Author: simon $
#======================================================================

set autoindent
set tabsize 4
set tabstospaces
set softwrap

include &amp;quot;/usr/share/nano/*.nanorc&amp;quot;







                               [ Read 13 lines ]
^G Help      ^O Write Out ^W Where Is  ^K Cut       ^T Execute   ^C Location
^X Exit      ^R Read File ^\ Replace   ^U Paste     ^J Justify   ^/ Go To Line&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;Now I&amp;#8217;ll checkin the change&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;simon@computer:~$ ci -l ./.nanorc 
./RCS/.nanorc,v  &amp;lt;--  ./.nanorc
new revision: 1.2; previous revision: 1.1
enter log message, terminated with single &amp;#39;.&amp;#39; or end of file:
&amp;gt;&amp;gt; Add all .nanorc files from /usr/share/nano/*
&amp;gt;&amp;gt; .
done
simon@computer:~$ &lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;If I accidently try and checkin an unchanged file, &lt;span class="caps"&gt;RCS&lt;/span&gt; will say:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;simon@computer:~$ ci -l ./.nanorc 
./RCS/.nanorc,v  &amp;lt;--  ./.nanorc
file is unchanged; reverting to previous revision 1.2
done&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;If you&amp;#8217;re ever unsure you can always run &lt;code&gt;rlog&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;simon@computer:~$ rlog ./.nanorc 

RCS file: ./RCS/.nanorc,v
Working file: ./.nanorc
head: 1.2
branch:
locks: strict
        simon: 1.2
access list:
symbolic names:
keyword substitution: kv
total revisions: 2;     selected revisions: 2
description:
First checkin
----------------------------
revision 1.2    locked by: simon;
date: 2023/08/25 19:20:20;  author: simon;  state: Exp;  lines: +6 -3
Add all .nanorc files from /usr/share/nano/*
----------------------------
revision 1.1
date: 2023/08/25 19:11:01;  author: simon;  state: Exp;
Initial revision
=============================================================================&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;Yep, 1.2 is the latest revision. Another option is to run &lt;code&gt;rcsdiff&lt;/code&gt;:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;simon@computer:~$ rcsdiff ./.nanorc 
===================================================================
RCS file: ./RCS/.nanorc,v
retrieving revision 1.2
diff -r1.2 ./.nanorc&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;No changes are shown (as no changes have been made). &lt;/p&gt;

	&lt;p&gt;What if we have changes? I&amp;#8217;ll add the setting to show line numbers (without checking the file in):&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;simon@computer:~$ rcsdiff -u ./.nanorc 
===================================================================
RCS file: ./RCS/.nanorc,v
retrieving revision 1.2
diff -u -r1.2 ./.nanorc
--- ./.nanorc   2023/08/25 19:20:20     1.2
+++ ./.nanorc   2023/08/25 19:29:15
@@ -8,6 +8,7 @@
 set tabsize 4
 set tabstospaces
 set softwrap
+set linenumbers

 include &amp;quot;/usr/share/nano/*.nanorc&amp;quot;&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;I&amp;#8217;ve now run &lt;code&gt;ci -l .nanorc&lt;/code&gt; but decide I don&amp;#8217;t really need to see to see line numbers. I want to go back to the revision before I added that line:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;simon@computer:~$ co -l -r1.2 ./.nanorc 
./RCS/.nanorc,v  --&amp;gt;  ./.nanorc
revision 1.2 (locked)
writable ./.nanorc exists; remove it? [ny](n): y
co: ./RCS/.nanorc,v: warning: You now have 2 locks.
done&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;Let&amp;#8217;s see the revision of the file now:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;simon@computer:~$ cat .nanorc 
#=====================================================================
# $Revision: 1.2 $
# $Date: 2023/08/25 19:20:20 $
# $Author: simon $
#======================================================================

set autoindent
set tabsize 4
set tabstospaces
set softwrap

include &amp;quot;/usr/share/nano/*.nanorc&amp;quot;&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;Ah good, we&amp;#8217;ve rolled back to where we were. And that&amp;#8217;s all there is to it. Here is the new workflow&lt;/p&gt;

	&lt;h3&gt;The New Workflow&lt;/h3&gt;

	&lt;p&gt;1. &lt;code&gt;mkdir RCS&lt;/code&gt; in the working directory&lt;br /&gt;
2. Add &lt;span class="caps"&gt;RCS&lt;/span&gt; metadata to the file if it doesn&amp;#8217;t exist&lt;br /&gt;
3. Make changes to the config file&lt;br /&gt;
4. Checkin the changes (&lt;code&gt;ci -l myfile.conf&lt;/code&gt;)&lt;br /&gt;
5. If you make a mistake or dislike a setting, &lt;code&gt;co -l -r1.?&lt;/code&gt;&lt;/p&gt;

	&lt;p&gt;Some nice features would be to automatically create the &lt;code&gt;RCS&lt;/code&gt; directory if it doesn&amp;#8217;t exist and to have all these &lt;code&gt;RCS&lt;/code&gt; directories backed up. That&amp;#8217;s for another post though&amp;#8230;&lt;/p&gt;

	&lt;p&gt;&lt;mark&gt;Update on 2026-05-22&lt;/mark&gt;&lt;/p&gt;

	&lt;p&gt;I&amp;#8217;ve set up some aliases in my &lt;code&gt;~/.bashrc&lt;/code&gt; to make working with &lt;span class="caps"&gt;RCS&lt;/span&gt; a bit easier:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;# GNU RCS aliases
alias rdiff=&amp;#39;rcs diff -u&amp;#39;
alias ci=&amp;#39;mkdir -p RCS; ci -u&amp;#39;
alias co=&amp;#39;co -l&amp;#39;&lt;/code&gt;&lt;/pre&gt;</content><category term="software"></category><category term="GNU"></category><category term="RCS"></category><category term="VCS"></category></entry><entry><title>Running bottle.py with systemd</title><link href="https://simonh.uk/2023/03/25/running-bottlepy-with-systemd/" rel="alternate"></link><published>2023-03-25T00:00:00+00:00</published><updated>2023-03-25T00:00:00+00:00</updated><author><name>Simon Harrison</name></author><id>tag:simonh.uk,2023-03-25:/2023/03/25/running-bottlepy-with-systemd/</id><summary type="html">	&lt;p&gt;systemd isn&amp;#8217;t so scary after all&lt;/p&gt;</summary><content type="html">	&lt;p&gt;&lt;img alt="Bottle.py Logo" src="/img/logo/bottle.svg" title="Bottle.py Logo" /&gt;&lt;/p&gt;

	&lt;p&gt;I have a number of &lt;a href="https://bottlepy.org/docs/dev/"&gt;bottle.py&lt;/a&gt; web services that I run on my servers. For the last few years, I&amp;#8217;ve been using &lt;a href="https://github.com/tmux/tmux/wiki"&gt;tmux&lt;/a&gt; to launch these services and then detaching them so they continue running after I logout of the &lt;span class="caps"&gt;SSH&lt;/span&gt; session. Recently, one of those servers had an issue causing the provider to require moving my &lt;span class="caps"&gt;VPS&lt;/span&gt; to another machine. So, when I went to use it, I got the &lt;code&gt;503 Service Unavailable&lt;/code&gt; message (that no one likes to see)!&lt;/p&gt;

	&lt;p&gt;Today, I finally got around to setting up &lt;a href="https://www.freedesktop.org/wiki/Software/systemd/"&gt;systemd&lt;/a&gt; service files for these services. It only took about an hour (including troubleshooting things not working). Below is the &lt;code&gt;shopping.service&lt;/code&gt; file (for a web based shopping list I wrote):&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;# Save this file in ~/.config/systemd/user/shopping.service
# then run:
# $ systemctl --user daemon-reload
# $ systemctl --user enable shopping.service
# Below will prevent the service stopping when we terminate the SSH session
# $ sudo loginctl enable-linger username

[Unit]
Description=Shopping List (bottle.py)
After=network.target

[Service]
Type=simple
WorkingDirectory=/home/simon/web/shopping
ExecStart=/usr/bin/python3 /home/simon/web/shopping/shopping.py
Restart=always

[Install]
WantedBy=default.target&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;Note: make sure to follow the comments. Otherwise, you&amp;#8217;ll also have problems. &lt;/p&gt;

	&lt;p&gt;Once you&amp;#8217;ve created and symlinked the file to &lt;code&gt;~/.config/systemd/user&lt;/code&gt;, you&amp;#8217;ll be able to check all is good as you can for any system process. &lt;/p&gt;

&lt;pre&gt;&lt;code&gt;simon@server:~/web/shopping [ssh] $ systemctl --user status shopping_list.service 
● shopping_list.service - Shopping List (bottle.py)
     Loaded: loaded (/home/simon/.config/systemd/user/shopping_list.service; enabled; vendor preset: enabled)
     Active: active (running) since Sat 2023-03-25 20:26:29 GMT; 9min ago
   Main PID: 32632 (python3)
      Tasks: 11 (limit: 1129)
     Memory: 100.3M
        CPU: 7.471s
     CGroup: /user.slice/user-1000.slice/user@1000.service/app.slice/shopping_list.service
             └─32632 /usr/bin/python3 /home/simon/web/shopping/run_sl2.py&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;I&amp;#8217;ll monitor this one service for a while, then I plan to use systemd service files for all my web services.&lt;/p&gt;</content><category term="software"></category><category term="python"></category><category term="linux"></category><category term="systemd"></category><category term="bottle.py"></category></entry><entry><title>Using GNU RCS in 2023</title><link href="https://simonh.uk/2023/02/11/using-gnu-rcs-in-2023/" rel="alternate"></link><published>2023-02-11T00:00:00+00:00</published><updated>2023-02-11T00:00:00+00:00</updated><author><name>Simon Harrison</name></author><id>tag:simonh.uk,2023-02-11:/2023/02/11/using-gnu-rcs-in-2023/</id><summary type="html">	&lt;p&gt;Version control for single files&lt;/p&gt;</summary><content type="html">	&lt;p&gt;&lt;img alt="GNU Logo" src="/img/logo/gnu.webp" title="GNU Logo" /&gt;&lt;/p&gt;

	&lt;h2&gt;Old School Version Control&lt;/h2&gt;

	&lt;p&gt;Since I started using &lt;a href="https://www.mercurial-scm.org/"&gt;Mercurial&lt;/a&gt; a few years back, I&amp;#8217;ve realised the value in having everything important under version control. The thing is, tools like Mercurial and Git don&amp;#8217;t seem to be quite the right tool when you&amp;#8217;re wanting to manage &lt;em&gt;single&lt;/em&gt; files. &lt;/p&gt;

	&lt;p&gt;Enter &lt;a href="https://www.gnu.org/software/rcs/"&gt;&lt;span class="caps"&gt;RCS&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;

	&lt;p&gt;&lt;span class="caps"&gt;RCS&lt;/span&gt; dates back to 1982, and was last updated in 2022 (still active). I believe that one of &lt;span class="caps"&gt;RCS&lt;/span&gt;&amp;#8217;s perceived weaknesses can actually be a strength: it was designed to work with single files. Using it is very easy. Let&amp;#8217;s get started!&lt;/p&gt;

	&lt;p&gt;The first thing I do is add some variables that &lt;span class="caps"&gt;RCS&lt;/span&gt; will populate for us. I&amp;#8217;ll add a bit of metadata to our fake program &lt;code&gt;my_program&lt;/code&gt;&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;# $Date$
# $Revision$
# $Author$&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;These will be replaced when we &amp;#8220;checkout&amp;#8221; our file from &lt;span class="caps"&gt;RCS&lt;/span&gt;. But first we need to &amp;#8220;checkin&amp;#8221; our initial revision. &lt;/p&gt;

&lt;pre&gt;&lt;code&gt;# $Date$
# $Revision$
# $Author$

This is the first version of my file. I&amp;#39;ve done a small amount of work that I want to save.&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;Let&amp;#8217;s check in our first version.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;simon@computer:~/tmp/my_script$ mkdir RCS&lt;/code&gt;&lt;/pre&gt;

&lt;pre&gt;&lt;code&gt;simon@computer:~/tmp/my_script$ ll
total 16K
drwxrwxr-x  3 simon simon 4.0K 2023-02-11 11:16 .
drwxrwxr-x 18 simon simon 4.0K 2023-02-11 11:09 ..
-rw-rw-r--  1 simon simon  128 2023-02-11 11:15 my_program
drwxrwxr-x  2 simon simon 4.0K 2023-02-11 11:16 RCS&lt;/code&gt;&lt;/pre&gt;

&lt;pre&gt;&lt;code&gt;simon@computer:~/tmp/my_script$ ci my_program 
RCS/my_program,v  &amp;lt;--  my_program
enter description, terminated with single &amp;#39;.&amp;#39; or end of file:
NOTE: This is NOT the log message!
&amp;gt;&amp;gt; Version 1 of my_program
&amp;gt;&amp;gt; .
initial revision: 1.1
done&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;So we&amp;#8217;ve performed our first commit. Let&amp;#8217;s see the state of our working directory&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;simon@computer:~/tmp/my_script$ tree
.
└── RCS
    └── my_program,v

1 directory, 1 file&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;As you can see, our original file has been destroyed! We now have one file in the &lt;span class="caps"&gt;RCS&lt;/span&gt; directory &lt;code&gt;my_program,v&lt;/code&gt;. That file is our &amp;#8220;versioned&amp;#8221; file. Let&amp;#8217;s take a look at it&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;simon@computer:~/tmp/my_script$ cat RCS/my_program,v 
head    1.1;
access;
symbols;
locks; strict;
comment @# @;


1.1
date    2023.02.11.11.16.25;    author simon;   state Exp;
branches;
next    ;


desc
@Version 1 of my_program
@


1.1
log
@Initial revision
@
text
@# $Date$
# $Revision$
# $Author$

This is the first version of my file. I&amp;#39;ve done a small amount of work that I want to save.


@
simon@computer:~/tmp/my_script$&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;As you can see, there&amp;#8217;s quite a bit of information in there, along with the text of &lt;code&gt;my_program&lt;/code&gt;&lt;/p&gt;

	&lt;p&gt;To retrieve our file and do some work, we need to check it out, with a lock, to prevent other people working on it at the same time as us (to avoid conflicts).&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;simon@computer:~/tmp/my_script$ co -l ./my_program 
./RCS/my_program,v  --&amp;gt;  ./my_program
revision 1.1 (locked)
done&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;Let&amp;#8217;s see our working directory state now&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;simon@computer:~/tmp/my_script$ tree
.
├── my_program
└── RCS
    └── my_program,v

1 directory, 2 files&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;Great, the file is back! Let&amp;#8217;s take a look at the contents&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;simon@computer:~/tmp/my_script$ cat my_program 
# $Date: 2023/02/11 11:16:25 $
# $Revision: 1.1 $
# $Author: simon $

This is the first version of my file. I&amp;#39;ve done a small amount of work that I want to save.&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;As I said earlier, the dollar variables have been expanded by &lt;span class="caps"&gt;RCS&lt;/span&gt;. Let&amp;#8217;s make another change and see what happens.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;# $Date: 2023/02/11 11:16:25 $
# $Revision: 1.1 $
# $Author: simon $

This is the first version of my file. I&amp;#39;ve done a small amount of work that I want to save.

I&amp;#39;ve simply added a blank newline and this line now.&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;Running &lt;code&gt;rcsdiff&lt;/code&gt; will show us unsaved changes. Use the &lt;code&gt;-u&lt;/code&gt; option to get unified diff output.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;simon@computer:~/tmp/my_script$ rcsdiff -u ./my_program 
===================================================================
RCS file: ./RCS/my_program,v
retrieving revision 1.1
diff -u -r1.1 ./my_program
--- ./my_program        2023/02/11 11:16:25     1.1
+++ ./my_program        2023/02/11 11:29:41
@@ -4,4 +4,6 @@

 This is the first version of my file. I&amp;#39;ve done a small amount of work that I want to save.

+I&amp;#39;ve simply added a blank newline and this line now.
+

simon@computer:~/tmp/my_script$ &lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;All looks good, so we&amp;#8217;ll commit our changes.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;simon@computer:~/tmp/my_script$ ci ./my_program 
./RCS/my_program,v  &amp;lt;--  ./my_program
new revision: 1.2; previous revision: 1.1
enter log message, terminated with single &amp;#39;.&amp;#39; or end of file:
&amp;gt;&amp;gt; Did a bit of work
&amp;gt;&amp;gt; .
done&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;Very easy and painless, eh? Once again, our file will have been destroyed so we need to check it out again to either work on it (with the &lt;code&gt;-l&lt;/code&gt; option to have a locked version of the file) or without a lock for a read only version.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;simon@computer:~/tmp/my_script$ co ./my_program 
./RCS/my_program,v  --&amp;gt;  ./my_program
revision 1.2
done
simon@computer:~/tmp/my_script$ cat my_program 
# $Date: 2023/02/11 11:31:42 $
# $Revision: 1.2 $
# $Author: simon $

This is the first version of my file. I&amp;#39;ve done a small amount of work that I want to save.

I&amp;#39;ve simply added a blank newline and this line now.&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;The date and revision have been updated and our most recent changes are there. Because we didn&amp;#8217;t lock our file, it&amp;#8217;s readonly. &lt;/p&gt;

&lt;pre&gt;&lt;code&gt;  GNU nano 6.2                       my_program                                 
# $Date: 2023/02/11 11:31:42 $
# $Revision: 1.2 $
# $Author: simon $

This is the first version of my file. I&amp;#39;ve done a small amount of work that I w&amp;gt;

I&amp;#39;ve simply added a blank newline and this line now.












                      [ File &amp;#39;my_program&amp;#39; is unwritable ]
^G Help      ^O Write Out ^W Where Is  ^K Cut       ^T Execute   ^C Location
^X Exit      ^R Read File ^\ Replace   ^U Paste     ^J Justify   ^/ Go To Line&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;&lt;span class="caps"&gt;GNU&lt;/span&gt; Nano tells us at the bottom that the file is unwritable. Fair enough. &lt;/p&gt;

	&lt;p&gt;We&amp;#8217;ll checkout an editable version now with &lt;code&gt;co -l&lt;/code&gt;&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;simon@computer:~/tmp/my_script$ co -l ./my_program 
./RCS/my_program,v  --&amp;gt;  ./my_program
revision 1.2 (locked)
done&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;If we want to view our changes &lt;code&gt;rlog&lt;/code&gt; will happily tell us&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;simon@computer:~/tmp/my_script$ rlog ./my_program 

RCS file: ./RCS/my_program,v
Working file: ./my_program
head: 1.2
branch:
locks: strict
        simon: 1.2
access list:
symbolic names:
keyword substitution: kv
total revisions: 2;     selected revisions: 2
description:
Version 1 of my_program
----------------------------
revision 1.2    locked by: simon;
date: 2023/02/11 11:31:42;  author: simon;  state: Exp;  lines: +5 -3
Did a bit of work
----------------------------
revision 1.1
date: 2023/02/11 11:16:25;  author: simon;  state: Exp;
Initial revision
=============================================================================&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;And that&amp;#8217;s really all there is to it (for my purposes anyway). Take a look at the excellent &lt;a href="https://www.gnu.org/software/rcs/manual/"&gt;manual&lt;/a&gt; for everything else you can do with &lt;span class="caps"&gt;RCS&lt;/span&gt;.&lt;/p&gt;

	&lt;p&gt;I&amp;#8217;m sure you can see the value of &lt;span class="caps"&gt;RCS&lt;/span&gt; for shell scripts, single Python files, etc. &lt;/p&gt;</content><category term="software"></category><category term="VCS"></category><category term="GNU"></category><category term="RCS"></category></entry><entry><title>Manage Invoices with GNU Recutils</title><link href="https://simonh.uk/2022/08/13/manage-invoices-with-gnu-recutils/" rel="alternate"></link><published>2022-08-13T00:00:00+01:00</published><updated>2022-08-13T00:00:00+01:00</updated><author><name>Simon Harrison</name></author><id>tag:simonh.uk,2022-08-13:/2022/08/13/manage-invoices-with-gnu-recutils/</id><summary type="html">	&lt;p&gt;unix plain text databases!&lt;/p&gt;</summary><content type="html">	&lt;p&gt;&lt;img alt="GNU Logo" src="/img/logo/gnu.webp" title="GNU Logo" /&gt;&lt;/p&gt;

	&lt;p&gt;I&amp;#8217;ve been running an &lt;span class="caps"&gt;NDT&lt;/span&gt; business since 2017. After a couple of years getting annoyed at writing my reports in Libreoffice Writer, I decided to write my own software to generate the reports for me. This has saved me an enormous amount of time. A couple of years ago, I started thinking about how I should handle my invoices. I don&amp;#8217;t generate a lot of invoices, but sometimes I&amp;#8217;d lose track of who&amp;#8217;d paid, who hadn&amp;#8217;t and realised I needed &lt;em&gt;something&lt;/em&gt; to keep track of them.&lt;/p&gt;

	&lt;p&gt;One option was just to simply add it to my existing system. But, I couldn&amp;#8217;t really be bothered. So I decided to have a simple spreadsheet. This worked ok, I simply added a new row to my &amp;#8220;invoice_log_2022.xlsx&amp;#8221; and then email myself the new version so I had some redundancy. But it bugged me a little as it seemed there should be an easier way to handle a few records. For example, I had to use some spreadsheet program just to add / view my invoices. &lt;/p&gt;

	&lt;p&gt;So, I thought I&amp;#8217;d see what other options I could find. Eventually, I came across &lt;a href="https://www.gnu.org/software/recutils/"&gt;&lt;span class="caps"&gt;GNU&lt;/span&gt; Recutils&lt;/a&gt;. Here is the description from their site:&lt;/p&gt;

	&lt;blockquote&gt;
		&lt;p&gt;&lt;span class="caps"&gt;GNU&lt;/span&gt; Recutils is a set of tools and libraries to access human-editable, plain text databases called recfiles. The data is stored as a sequence of records, each record containing an arbitrary number of named fields. The picture below shows a sample database containing information about &lt;span class="caps"&gt;GNU&lt;/span&gt; packages, along with the main features provided by Recutils.&lt;/p&gt;
	&lt;/blockquote&gt;

	&lt;p&gt;&lt;img alt="recutils screenshot" src="/img/2022-08-13/recutils.png" title="recutils screenshot" /&gt;&lt;/p&gt;

	&lt;p&gt;This seemed to be worth a look! I converted my spreadsheet to csv, then imported it into the recfile format. &lt;/p&gt;

&lt;pre&gt;&lt;code&gt;Invoice_No: N123456
Due_Date: 2022-07-31
Amount: £180.00
Customer: Some Customer
Description: MPI of fillet welds on fabricated assemblies
Amount_Paid: £180.00
Date_Paid: 2022-08-05

Invoice_No: N123457
Due_Date: 2022-07-31
Amount: £150.00
Customer: Another Customer
Description: DPI of condenser pipework
Amount_Paid: 
Date_Paid: &lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;The above shows two records. The first one has been paid, the second one has not. If I want to add a new invoice to the log, I simply copy the last record, edit the fields and save the file. It really doesn&amp;#8217;t get much easier than that. No need for anything more than a text editor. &lt;/p&gt;

	&lt;p&gt;I&amp;#8217;ve only been using recutils for a week and have just started scratching the surface of the tools that come with it, &lt;code&gt;recins&lt;/code&gt;, &lt;code&gt;recsel&lt;/code&gt;, &lt;code&gt;recdel&lt;/code&gt; etc. One thing I want to do is have a cron job that will email me any invoices that are overdue. &lt;/p&gt;

	&lt;h2&gt;Conclusion&lt;/h2&gt;

	&lt;p&gt;I really like Sqlite. I use it for loads of things, but sometimes even Sqlite is overkill. The next time you think about creating a new spreadsheet to save a few records, perhaps you&amp;#8217;ll try Recutils instead&amp;#8230;&lt;/p&gt;</content><category term="software"></category><category term="business"></category><category term="database"></category><category term="tips"></category><category term="gnu"></category></entry><entry><title>A Guide to Choosing, Starting and Finishing Software Projects</title><link href="https://simonh.uk/2021/12/18/a-guide-to-choosing-starting-and-finishing-software-projects/" rel="alternate"></link><published>2021-12-18T00:00:00+00:00</published><updated>2021-12-18T00:00:00+00:00</updated><author><name>Simon Harrison</name></author><id>tag:simonh.uk,2021-12-18:/2021/12/18/a-guide-to-choosing-starting-and-finishing-software-projects/</id><summary type="html">	&lt;p&gt;tldr: It needs to be useful and have an audience&lt;/p&gt;</summary><content type="html">	&lt;h1&gt;Intro&lt;/h1&gt;

	&lt;p&gt;I&amp;#8217;ve been a productive programmer for about four years now and believe I&amp;#8217;m in a position to offer some friendly advice to others who might be struggling. &lt;/p&gt;

	&lt;p&gt;I tried, and failed, to learn programming for many years. The turning point for me was a real world project for a company that I worked for. &lt;/p&gt;

	&lt;h2&gt;Step One&lt;/h2&gt;

	&lt;p&gt;&lt;ins&gt;Pick a real world project&lt;/ins&gt;&lt;/p&gt;

	&lt;p&gt;My first project was a system to record torque settings in a workshop. The way they had done it for many years, was for each technician to record the settings in a bound book. This would include &lt;/p&gt;

	&lt;ul&gt;
		&lt;li&gt;their clock number&lt;/li&gt;
		&lt;li&gt;the date&lt;/li&gt;
		&lt;li&gt;the job number&lt;/li&gt;
		&lt;li&gt;the torque value applied&lt;/li&gt;
		&lt;li&gt;the torque wrench used&lt;/li&gt;
		&lt;li&gt;the torque meter used&lt;/li&gt;
	&lt;/ul&gt;

	&lt;p&gt;And finally, they&amp;#8217;d stamp the last column instead of a signature (company policy) so if there was an issue, they could ascertain who&amp;#8217;d torqued a particular bolt.&lt;/p&gt;

	&lt;p&gt;The problems with this method, as I saw it, were:&lt;/p&gt;

	&lt;ul&gt;
		&lt;li&gt;someone had to regularly print out the new books (ME)!&lt;/li&gt;
		&lt;li&gt;finding a record was like finding a needle in a haystack&lt;/li&gt;
		&lt;li&gt;no backup &amp;#8211; if book is lost, all records gone&lt;/li&gt;
	&lt;/ul&gt;

	&lt;p&gt;Bear in mind, this company had about twenty of these books in daily use. Also, it was not uncommon to have to try to find a record (if an engine or transmission failed in service). &lt;/p&gt;

	&lt;p&gt;So, I offered to attempt to write a web based system, accessed using a couple of tablets the company already had. It took maybe a month or two of work in my spare time to have a prototype built. We tested it using one station, and when that proved to work better than the old way, we introduced the second tablet. &lt;/p&gt;

	&lt;p&gt;This was not a tech company and the supervisors were genuinely surprised and delighted that they could now search on any field:&lt;/p&gt;

	&lt;ul&gt;
		&lt;li&gt;all records for a particular job&lt;/li&gt;
		&lt;li&gt;all records for a particular technician&lt;/li&gt;
		&lt;li&gt;all records on a date or in a date range&lt;/li&gt;
	&lt;/ul&gt;

	&lt;p&gt;etc.&lt;/p&gt;

	&lt;p&gt;Unfortunately, their lazy, unskilled IT department didn&amp;#8217;t like me in their turf and started causing problems, so I decided to turn the program off. But, it was very successful and well liked by its users and management who were directly involved. &lt;/p&gt;

	&lt;h2&gt;Step Two&lt;/h2&gt;

	&lt;p&gt;&lt;ins&gt;Make it better than the old way&lt;/ins&gt;&lt;/p&gt;

	&lt;p&gt;Personally, I love writing software. Starting with nothing and ending up with something in use, better than how it was done previously. Every software project I&amp;#8217;ve written has been to replace something that could easily be improved, i.e. to replace a spreadsheet, a white board, or paper. &lt;/p&gt;

	&lt;p&gt;When you&amp;#8217;re starting out people can be nervous about change. So I always say to them:&lt;/p&gt;

	&lt;blockquote&gt;
		&lt;p&gt;&amp;#8220;If you don&amp;#8217;t like it, you can always go back to how you did it before.&amp;#8221;&lt;/p&gt;
	&lt;/blockquote&gt;

	&lt;p&gt;Knowing fine well that once they&amp;#8217;ve used my system, going back will be the last thing they want to do! But it&amp;#8217;s important to tell them, to reassure them that it&amp;#8217;s just a trial. That they are in control. People are weird like that. &lt;/p&gt;

	&lt;h2&gt;Step Three&lt;/h2&gt;

	&lt;p&gt;&lt;ins&gt;Launch as soon as you can&lt;/ins&gt;&lt;/p&gt;

	&lt;p&gt;Once you&amp;#8217;ve picked your real world project, get to work! As with all things, you&amp;#8217;ll get better and quicker and more confident as you write more code. You&amp;#8217;ll also get feedback from your users that you couldn&amp;#8217;t predict. The sooner you launch, the sooner your project improves. That&amp;#8217;s been my experience. &lt;/p&gt;

	&lt;h2&gt;Step Four&lt;/h2&gt;

	&lt;p&gt;&lt;ins&gt;Work as much as you can to improve it&lt;/ins&gt;&lt;/p&gt;

	&lt;p&gt;So your project is live, &lt;em&gt;real&lt;/em&gt; people are using it and benefiting from your skills. Over the next few weeks / months, try and make it better. Add new features that your users suggest (within reason). Make things simpler and easier for your users. I guarantee you that it will take months until you can officially say it&amp;#8217;s &amp;#8220;done.&amp;#8221; &lt;/p&gt;

	&lt;h2&gt;Summary and Conclusion&lt;/h2&gt;

	&lt;p&gt;So, lets recap&lt;/p&gt;

	&lt;p&gt;1. Pick a real world project&lt;br /&gt;
2. Make it better than the old way&lt;br /&gt;
3. Launch as soon as you can&lt;br /&gt;
4. Work as much as you can to improve it&lt;br /&gt;
5. &lt;span class="caps"&gt;GOTO&lt;/span&gt; step 1&lt;/p&gt;

	&lt;p&gt;And that&amp;#8217;s how I work. That&amp;#8217;s my system for writing software. Of course there&amp;#8217;s loads of other things that you should consider (version control, backups, security etc.) but for my first couple of projects, I didn&amp;#8217;t bother with version control software. I&amp;#8217;d struggle to go back to not using it now, but I muddled through. The other stuff you&amp;#8217;ll pick up as you need to. &lt;/p&gt;

	&lt;p&gt;In case you&amp;#8217;re interested, here is the before and after for the torque meter software project I mentioned above:&lt;/p&gt;

	&lt;p&gt;Before:&lt;/p&gt;

	&lt;p&gt;&lt;img alt="torque book" src="/img/2021-12-18/torque_book.jpg" title="torque book" /&gt;&lt;/p&gt;

	&lt;p&gt;After:&lt;/p&gt;

	&lt;p&gt;&lt;img alt="torque software" src="/img/2021-12-18/torque_software.jpg" title="torque software" /&gt;&lt;/p&gt;</content><category term="software"></category><category term="tips"></category><category term="programming"></category></entry><entry><title>Send SMS from Linux Computer via ADB</title><link href="https://simonh.uk/2021/11/14/send-sms-from-linux-computer-via-adb/" rel="alternate"></link><published>2021-11-14T00:00:00+00:00</published><updated>2021-11-14T00:00:00+00:00</updated><author><name>Simon Harrison</name></author><id>tag:simonh.uk,2021-11-14:/2021/11/14/send-sms-from-linux-computer-via-adb/</id><summary type="html">	&lt;p&gt;That&amp;#8217;s another itch, scratched.&lt;/p&gt;</summary><content type="html">	&lt;p&gt;Since I learnt how to send emails from my servers and desktop, I thought it would be useful to send &lt;span class="caps"&gt;SMS&lt;/span&gt; (Short Message Service) texts as well. No specific use cases yet, but I&amp;#8217;m sure one day it&amp;#8217;ll be needed&amp;#8230;&lt;/p&gt;

	&lt;p&gt;After looking into &lt;a href="http://smstools3.kekekasvi.com/"&gt;smstools&lt;/a&gt;, &lt;a href="https://wammu.eu/gammu/"&gt;Gammu&lt;/a&gt;, and loads of others, I was getting nowhere and ready to give up. But then, I remembered &lt;a href="https://developer.android.com/studio/command-line/adb"&gt;&lt;span class="caps"&gt;ADB&lt;/span&gt;&lt;/a&gt;.  Like most people, I&amp;#8217;ve got numerous Android phones knocking about, surely I could use an old Android phone + &lt;span class="caps"&gt;ADB&lt;/span&gt; to send an &lt;span class="caps"&gt;SMS&lt;/span&gt;. &lt;/p&gt;

	&lt;p&gt;I started off with my first Android phone, an &lt;a href="https://www.gsmarena.com/htc_desire-3077.php"&gt;&lt;span class="caps"&gt;HTC&lt;/span&gt; Desire&lt;/a&gt;. Even though this phone is now 11 years old, it still works perfectly and it&amp;#8217;d be nice to give it something to do!&lt;/p&gt;

	&lt;p&gt;&lt;ins&gt;Android 2 (Gingerbread)&lt;/ins&gt;&lt;/p&gt;

	&lt;p&gt;The first thing to notice is that we put the phone number in just as we&amp;#8217;d type in to to the phone. No +44XXXXXXXXX needed here. So let&amp;#8217;s start sending some &lt;span class="caps"&gt;SMS&lt;/span&gt; messages.&lt;/p&gt;

	&lt;p&gt;To send an sms with spaces, which is almost certainly required, we either escape each space character with a back slash, or far better, enclose the string in single quotes:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;simon@computer:~$ adb shell service call isms 5 s16 &amp;quot;07123456789&amp;quot; i32 0 i32 0 s16 &amp;quot;&amp;#39;Here is some text with spaces but not escaped.&amp;#39;&amp;quot;
Result: Parcel(00000000    &amp;#39;....&amp;#39;)
simon@computer:~$&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;I wondered if I could send the output of shell commands (yep):&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;simon@computer:~$ adb shell service call isms 5 s16 &amp;quot;07123456789&amp;quot; i32 0 i32 0 s16 &amp;quot;&amp;#39;$(uptime)&amp;#39;&amp;quot;&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;Here are some of the messages I received on my mobile. The last message was the uptime message above.&lt;/p&gt;

	&lt;p&gt;&lt;img alt="SMS received on phone" src="/img/2021-11-14/screenshot_sms.png" title="SMS received on phone" /&gt;&lt;/p&gt;

	&lt;p&gt;I also had a &lt;a href="https://www.gsmarena.com/nokia_5-8571.php"&gt;Nokia 5&lt;/a&gt; in a drawer. &lt;/p&gt;

	&lt;p&gt;&lt;ins&gt;Android 9&lt;/ins&gt;&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;simon@computer:~$ adb shell service call isms 7 i32 0 s16 &amp;quot;com.android.mms.service&amp;quot; s16 &amp;quot;+447123456789&amp;quot; s16 &amp;quot;null&amp;quot; s16 &amp;quot;Hello\ from\ your\ home\ computer.&amp;quot; s16 &amp;quot;null&amp;quot; s16 &amp;quot;null&amp;quot;&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;As you can see, the syntax is different depending on your Android version. I&amp;#8217;ve only just started scratching the surface with &lt;span class="caps"&gt;ADB&lt;/span&gt;, but there&amp;#8217;s lots of potential for all sorts of helpful notifications.&lt;/p&gt;

	&lt;p&gt;I&amp;#8217;ll probably write a new post once I&amp;#8217;ve done some more experimenting.&lt;/p&gt;</content><category term="software"></category><category term="android"></category><category term="sms"></category><category term="linux"></category><category term="tips"></category></entry><entry><title>On the Pros and Cons of Software Testing</title><link href="https://simonh.uk/2021/06/10/on-the-pros-and-cons-of-software-testing/" rel="alternate"></link><published>2021-06-10T00:00:00+01:00</published><updated>2021-06-10T00:00:00+01:00</updated><author><name>Simon Harrison</name></author><id>tag:simonh.uk,2021-06-10:/2021/06/10/on-the-pros-and-cons-of-software-testing/</id><summary type="html">	&lt;p&gt;I understand the concept, just wonder if it&amp;#8217;s worth the time&lt;/p&gt;</summary><content type="html">	&lt;p&gt;Over the years, I&amp;#8217;ve noticed that there are two types of coders&lt;/p&gt;

	&lt;ol&gt;
		&lt;li&gt;Those who don&amp;#8217;t really see testing as something worth their time&lt;/li&gt;
		&lt;li&gt;Those who test everything&lt;/li&gt;
	&lt;/ol&gt;

	&lt;p&gt;I fall into the first camp. There&amp;#8217;s probably a transtion from 1 to 2, but it seems to be an all or nothing type arrangement to me. You don&amp;#8217;t come across many coders who do &amp;#8220;some&amp;#8221; automated testing. &lt;/p&gt;

	&lt;p&gt;Now, of course, we all &lt;strong&gt;test&lt;/strong&gt; functionally. You&amp;#8217;ve just added a new feature to your untested code, so you run it and test it out. Try and break it. Often, it will break quite happily. You missed something obvious and then you fix the code, retest, and all looks good. &lt;/p&gt;

	&lt;p&gt;I run quite a lot of code like this. As do many others. I think, secretly, many coders know that test suites are a bit of a con. You may run 5000 tests and everything passes. &lt;/p&gt;

	&lt;p&gt;So, therefore the code is good?! Bug free? Not necessarily&amp;#8230;&lt;/p&gt;

	&lt;p&gt;I mean, think about it. You are going to test &lt;strong&gt;every&lt;/strong&gt; permutation of permissable inputs? Or outputs? &lt;/p&gt;

	&lt;p&gt;Nope (unless you&amp;#8217;re &lt;a href="https://sqlite.org/testing.html"&gt;sqlite&lt;/a&gt;). &lt;/p&gt;

	&lt;p&gt;For a lot of code, it doesn&amp;#8217;t really matter. &lt;/p&gt;

	&lt;ul&gt;
		&lt;li&gt;You run it&lt;/li&gt;
		&lt;li&gt;It works&lt;/li&gt;
		&lt;li&gt;Something breaks&lt;/li&gt;
		&lt;li&gt;You fix it&lt;/li&gt;
		&lt;li&gt;You run it&lt;/li&gt;
	&lt;/ul&gt;

	&lt;p&gt;That seems reasonable to me. And it&amp;#8217;s exactly the same process with an automated test suite except there&amp;#8217;s a write tests step. &lt;/p&gt;

	&lt;p&gt;Small time coders can get away with dealing with bugs as they come up. I&amp;#8217;ve had a few chewy moments, but if you coded intelligently / defensively in the first place, you&amp;#8217;ve built workarounds in to handle minor bugs. &lt;/p&gt;

	&lt;h2&gt;My Workflow&lt;/h2&gt;

	&lt;p&gt;When I start a new project, I initialize a Mercurial repository, bring in all the files I know I&amp;#8217;ll need right away, and then start coding. I work alone, by the way, so there&amp;#8217;s no corner of the code that I haven&amp;#8217;t touched. &lt;/p&gt;

	&lt;p&gt;I work on one feature at a time. Anything that feature might touch, I functionally test as I go.&lt;/p&gt;

	&lt;h2&gt;Example&lt;/h2&gt;

	&lt;p&gt;Last year, I wrote a web based shopping list for my partner and me to use instead of a paper list. We&amp;#8217;ve been using it every week since, and generally it works perfectly. &lt;/p&gt;

	&lt;p&gt;But, eventually a very annoying bug showed up. This cropped up after it running for about six months. What went wrong was she created a new list, and started to add items. And then she got a 500 error (Internal Server Error). &lt;/p&gt;

	&lt;p&gt;Now, I&amp;#8217;d set up my database so that each shopping list was indexed by date. So if she created a list today (2021-06-11) and then tried to create a new list on the same date, she&amp;#8217;d be prompted whether to add to the existing list or whether she wanted to delete the existing list. The reason being; my partner will create a new shopping list every Wednesday, add all the items she knows we need, then on the Thursday, one of us ticks off the items on our phones to remove them as we&amp;#8217;re putting items in to the trolley. &lt;/p&gt;

	&lt;p&gt;But on this day, she created a new list (a week after the old one), started to add items to the list and got the 500 error for nearly every item she tried to add! I was at home at the time, so &lt;span class="caps"&gt;SSH&lt;/span&gt;&amp;#8217;d into the server to have a look what was going on. The traceback pointed to an sqlite integrity error. &lt;/p&gt;

	&lt;p&gt;It turned out that instead of creating a new list, she was adding to the old list. Not her fault as I&amp;#8217;d coded it that creating a new list would close the old list, and make a new one. I checked all the relevant code, and everything looked good. &lt;/p&gt;

	&lt;p&gt;When I designed the software, one of the features I thought she&amp;#8217;d like, was being able to look at previous lists, and just click each item to add it to the new list. She generally gets a lot of items each week that are the same as every other week.&lt;/p&gt;

	&lt;p&gt;Here is a screenshot of the /lists page:&lt;/p&gt;

	&lt;p&gt;&lt;img alt="Shopping List Program" src="/img/2021-06-10/shopping_list.png" title="Shopping List Program" /&gt;&lt;/p&gt;

	&lt;p&gt;So from here she can click on the first date (or any date) and every item added on that date can be clicked and that will add it to the current list:&lt;/p&gt;

	&lt;p&gt;&lt;img alt="Shopping List Items" src="/img/2021-06-10/shopping_list2.png" title="Shopping List Items" /&gt;&lt;/p&gt;

	&lt;p&gt;If the item has already been added, it won&amp;#8217;t be added again. &lt;/p&gt;

	&lt;p&gt;It was on the /lists page that I realised that a new list hadn&amp;#8217;t been created. The solution was to delete the old list, and create a new one. &lt;/p&gt;

	&lt;h2&gt;Conclusion&lt;/h2&gt;

	&lt;p&gt;I never found the actual cause of the bug. I think it was possibly a caching issue on her phone. It has never showed up again. Even if I&amp;#8217;d written tests for everything I could think of, I wouldn&amp;#8217;t have considered the possibility that today&amp;#8217;s date would be anything other than: today&amp;#8217;s date!&lt;/p&gt;</content><category term="software"></category><category term="software"></category><category term="testing"></category></entry><entry><title>Why I still Use Windows XP</title><link href="https://simonh.uk/2021/05/21/why-i-still-use-windows-xp/" rel="alternate"></link><published>2021-05-21T00:00:00+01:00</published><updated>2021-05-21T00:00:00+01:00</updated><author><name>Simon Harrison</name></author><id>tag:simonh.uk,2021-05-21:/2021/05/21/why-i-still-use-windows-xp/</id><summary type="html">	&lt;p&gt;In a virtual machine, obviously!&lt;/p&gt;</summary><content type="html">	&lt;p&gt;&lt;img alt="Windows XP booting" src="/img/2021-05-21/xp-boot.jpg" title="Windows XP booting" /&gt;&lt;/p&gt;

	&lt;p&gt;Windows XP was on the first PC I owned, built by my brother in about 2001/2002. The computer had a 20GB hard disk, a 750Mhz processor, and served me well for many years. &lt;/p&gt;

	&lt;p&gt;To be honest, I always liked XP. I upgraded to Vista at some point, but that ran so badly, I switched to using Linux permanently in about 2008 or 2009. &lt;/p&gt;

	&lt;p&gt;Ever since I&amp;#8217;ve had computers powerful enough to run &lt;a href="https://www.virtualbox.org/"&gt;VirtualBox&lt;/a&gt;, I&amp;#8217;ve always had a Windows XP virtual machine. &lt;/p&gt;

	&lt;h2&gt;Why?&lt;/h2&gt;

	&lt;ul&gt;
		&lt;li&gt;Lightweight and fast&lt;/li&gt;
		&lt;li&gt;Good enough&lt;/li&gt;
		&lt;li&gt;Runs &lt;em&gt;most&lt;/em&gt; of the Windows software I might need&lt;/li&gt;
		&lt;li&gt;Stable&lt;/li&gt;
	&lt;/ul&gt;

	&lt;p&gt;I&amp;#8217;m not a Free Software &amp;#8220;fanatic&amp;#8221;. There&amp;#8217;s nothing as good as Adobe Acrobat XI that runs natively on Linux. Some people, myself included, consider Acrobat 11 &lt;strong&gt;far&lt;/strong&gt; better than Acrobat DC. Recent Adobe software is more about them, and less about their users. Photoshop CS 5.1 also runs on XP and does pretty much anything you might need to do to a photo (if you can&amp;#8217;t figure out how do it in &lt;span class="caps"&gt;GIMP&lt;/span&gt;). &lt;/p&gt;

	&lt;p&gt;Windows XP &lt;span class="caps"&gt;RAM&lt;/span&gt; Usage (Idling)&lt;/p&gt;

	&lt;p&gt;&lt;img alt="Windows XP Task Manager" src="/img/2021-05-21/xp-taskmanager.png" title="Windows XP Task Manager" /&gt;&lt;/p&gt;

	&lt;p&gt;Linux Mint 20.1 Cinnamon (Idling)&lt;/p&gt;

	&lt;p&gt;&lt;img alt="Linux Mint" src="/img/2021-05-21/xp-htop.png" title="Linux Mint" /&gt;&lt;/p&gt;

	&lt;p&gt;MX Linux 19.4 (Idling)&lt;/p&gt;

	&lt;p&gt;&lt;img alt="MX Linux" src="/img/2021-05-21/xp-htop-mx.png" title="MX Linux" /&gt;&lt;/p&gt;

	&lt;p&gt;Big difference between the three, aren&amp;#8217;t there?!&lt;/p&gt;

	&lt;h2&gt;Tips&lt;/h2&gt;

	&lt;p&gt;My XP instance has no internet access (why would it?). I only use it for occasional Acrobat, a bit of WordPerfect and some IronPython stuff. &lt;/p&gt;

	&lt;p&gt;If you want to do some scripting, IronPython 2.7.8 is the last version that runs on XP (to my knowledge). I tried 2.7.9 to 2.7.11 (latest) but no dice, probably due to the .net framework 4.0 being the last to run on XP.&lt;/p&gt;

	&lt;p&gt;Make sure you&amp;#8217;re running SP3, which was the last service pack released. &lt;/p&gt;</content><category term="software"></category><category term="windows"></category><category term="virtualization"></category></entry><entry><title>Getting Started with GnuPG (gpg)</title><link href="https://simonh.uk/2021/05/20/getting-started-with-gnupg-gpg/" rel="alternate"></link><published>2021-05-20T00:00:00+01:00</published><updated>2021-05-20T00:00:00+01:00</updated><author><name>Simon Harrison</name></author><id>tag:simonh.uk,2021-05-20:/2021/05/20/getting-started-with-gnupg-gpg/</id><summary type="html">	&lt;p&gt;Encryption, Signing, Compression all in one&lt;/p&gt;</summary><content type="html">	&lt;p&gt;&lt;img alt="GNU GPG Logo" src="/img/logo/gnu_gpg.svg" title="GNU GPG Logo" /&gt;&lt;/p&gt;

	&lt;p&gt;I&amp;#8217;ve been meaning to spend a bit of time looking at use cases for &lt;a href="https://gnupg.org/"&gt;gpg&lt;/a&gt;&lt;/p&gt;

	&lt;p&gt;I wasn&amp;#8217;t aware that you don&amp;#8217;t even need to set up any accounts. You can start using for symmetric encryption right out of the box. Symmetric encryption relies on a shared password / passphrase that is shared with recipients. &lt;/p&gt;

	&lt;p&gt;I&amp;#8217;m using a fairly fresh installation of &lt;a href="https://mxlinux.org/"&gt;mxlinux&lt;/a&gt; in Virtual Box. GnuPG is already installed as with pretty much any distro.&lt;/p&gt;

	&lt;p&gt;As you can see below, lots of options are available.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;simon@mx:~
$ gpg -h
gpg (GnuPG) 2.2.12
libgcrypt 1.8.4
Copyright (C) 2018 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later &amp;lt;https://gnu.org/licenses/gpl.html&amp;gt;
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.

Home: /home/simon/.gnupg
Supported algorithms:
Pubkey: RSA, ELG, DSA, ECDH, ECDSA, EDDSA
Cipher: IDEA, 3DES, CAST5, BLOWFISH, AES, AES192, AES256, TWOFISH,
        CAMELLIA128, CAMELLIA192, CAMELLIA256
Hash: SHA1, RIPEMD160, SHA256, SHA384, SHA512, SHA224
Compression: Uncompressed, ZIP, ZLIB, BZIP2

Syntax: gpg [options] [files]
Sign, check, encrypt or decrypt
Default operation depends on the input data

Commands:

 -s, --sign                  make a signature
     --clear-sign            make a clear text signature
 -b, --detach-sign           make a detached signature
 -e, --encrypt               encrypt data
 -c, --symmetric             encryption only with symmetric cipher
 -d, --decrypt               decrypt data (default)
     --verify                verify a signature
 -k, --list-keys             list keys
     --list-signatures       list keys and signatures
     --check-signatures      list and check key signatures
     --fingerprint           list keys and fingerprints
 -K, --list-secret-keys      list secret keys
     --generate-key          generate a new key pair
     --quick-generate-key    quickly generate a new key pair
     --quick-add-uid         quickly add a new user-id
     --quick-revoke-uid      quickly revoke a user-id
     --quick-set-expire      quickly set a new expiration date
     --full-generate-key     full featured key pair generation
     --generate-revocation   generate a revocation certificate
     --delete-keys           remove keys from the public keyring
     --delete-secret-keys    remove keys from the secret keyring
     --quick-sign-key        quickly sign a key
     --quick-lsign-key       quickly sign a key locally
     --sign-key              sign a key
     --lsign-key             sign a key locally
     --edit-key              sign or edit a key
     --change-passphrase     change a passphrase
     --export                export keys
     --send-keys             export keys to a keyserver
     --receive-keys          import keys from a keyserver
     --search-keys           search for keys on a keyserver
     --refresh-keys          update all keys from a keyserver
     --import                import/merge keys
     --card-status           print the card status
     --edit-card             change data on a card
     --change-pin            change a card&amp;#39;s PIN
     --update-trustdb        update the trust database
     --print-md              print message digests
     --server                run in server mode
     --tofu-policy VALUE     set the TOFU policy for a key

Options:

 -a, --armor                 create ascii armored output
 -r, --recipient USER-ID     encrypt for USER-ID
 -u, --local-user USER-ID    use USER-ID to sign or decrypt
 -z N                        set compress level to N (0 disables)
     --textmode              use canonical text mode
 -o, --output FILE           write output to FILE
 -v, --verbose               verbose
 -n, --dry-run               do not make any changes
 -i, --interactive           prompt before overwriting
     --openpgp               use strict OpenPGP behavior

(See the man page for a complete listing of all commands and options)

Examples:

 -se -r Bob [file]          sign and encrypt for user Bob
 --clear-sign [file]        make a clear text signature
 --detach-sign [file]       make a detached signature
 --list-keys [names]        show keys
 --fingerprint [names]      show fingerprints

Please report bugs to &amp;lt;https://bugs.gnupg.org&amp;gt;.&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;Now, we&amp;#8217;ll take a man page (uptime as it&amp;#8217;s nice and short) and save it to a file ready to encrypt and email to test encryption.&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;simon@mx:~
$ man uptime &amp;gt; uptime.txt&lt;/code&gt;&lt;/pre&gt;

&lt;pre&gt;&lt;code&gt;simon@mx:~
$ gpg --armor --symmetric uptime.txt&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;We could save some keystrokes by just typing &lt;code&gt;gpg -ac &amp;lt;filename&amp;gt;&lt;/code&gt;&lt;/p&gt;

	&lt;p&gt;You&amp;#8217;ll be prompted for a password (which you have to enter twice), I chose &lt;code&gt;simonh&lt;/code&gt;&lt;/p&gt;

	&lt;p&gt;As you can see, gpg also compresses the encrypted file (&lt;code&gt;uptime.txt.asc&lt;/code&gt;).&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;simon@mx:~
$ ll
total 300K
-rw-r--r--  1 simon simon  113 Apr 17 18:18 dead.letter
drwxr-xr-x  2 simon simon 4.0K Apr 15 19:17 Desktop
drwxr-xr-x  2 simon simon 4.0K Apr 15 19:25 Documents
drwxr-xr-x  2 simon simon 4.0K Apr 15 19:25 Downloads
drwx------  2 simon simon 4.0K Apr 16 15:36 mail
drwx------  5 simon simon 4.0K Apr 16 17:26 Maildir
-rw-------  1 simon simon  467 Apr 19 18:26 mbox
drwxr-xr-x  2 simon simon 4.0K Apr 15 19:25 Music
drwxr-xr-x  2 simon simon 4.0K Apr 15 19:25 Pictures
drwxr-xr-x  2 simon simon 4.0K Apr 15 19:25 Public
drwxr-xr-x  3 simon simon 4.0K Apr 17 17:53 src
drwxr-xr-x  2 simon simon 4.0K Apr 15 19:25 Templates
-rw-r--r--  1 simon simon 1.9K May 20 16:52 uptime.txt
-rw-r--r--  1 simon simon 1.4K May 20 16:52 uptime.txt.asc
drwxr-xr-x 12 simon simon 4.0K May  9 20:00 var
drwxr-xr-x  2 simon simon 4.0K Apr 15 19:25 Videos&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;Here is the (encrypted) contents of the uptime man page:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;simon@mx:~
$ cat uptime.txt.asc 
-----BEGIN PGP MESSAGE-----

jA0ECQMCfoUA3aASbz7/0ukBogSiu3yxpUM+FfoTaCkTBqmUxYagw7ifq8R6WT4o
Za/3rgH7X7UXWuis9q+GKssabXdnZelUlUewnz5P/iHGYBP0C0KhCTHZm8r5abDg
L8E0nsLEYkSu1bcdz07Rdky0S6Pc3uqvFOJLnGBz+TUgWdzHEXtijCxYya1oasyf
izZD+QRGFcsCjh5Ji9BBK92Dza9lRRgvLeZ3PE9IDQjgtHz2qLEDJq82CRMqqzC5
Gv9xfG+sryEgWxKXjfa0XfiC9+9P1hZC4buaKxX26GS697ks2UikZ4EzOi6lpuUC
uGCwi3CdpjnrKnkkPqCixAVKmq6t81MMD1m6fbHnOJSHyRBdk+V7qgPQAq+wDbHM
BnQW4FmX5rVMPBKEezaM/HMJYjBwRjOpeBoAUF4gx8nr9YGTVJygNYgdH8P19mqf
rdxcCFf7OADpZOrxVl1aaaBC5EmEGhUO4zJ47a11m+Tg+0QNddRQOnUZQ6T76glM
Q6TvkxR/wewL3yAIfFqAYACWWyIlMsKOWi4BT8d4MQMauvRC039lQtrNb4E/DfSw
ZD4o4N28f5IrS2Icri0qpqCyK/5bhbSReXpcjgbCF61ckG8H6S6kucAidir7DCJS
gfxbTBuD+FmhN2D+tzerUV0WiMeHMBnvF24ng0zRS0bCG20yj3Kb2n4tsz64FIfj
bcDfPxjwnTNiSZUcmE75ClL9V/4M/NBIu0d1j/okdaTkbLHtsITrOSPenunhvFZp
cMcnDrvfAo+EpT4NIBJ6xrCRq/wRSSW5/cMAp3BF9RpYpmNr1MLQsVx4ax28Yid6
A2r865gPDVVyFBnIvmaFUpmGf9sGg3J2AnjcBpSAXzWnvn7nXXs84At4ZqwgBkhp
FLGWYaPv8MajifGjbjewjMJqYN/Xq8bBw+9x6HCL/AJT4XYeNhYYzHwqUhLFVJeS
PWisaW0bKx2lUYyHEMBW/+KSeTna+UiSEsnbhD+ZBrr9OBnRgPAgNlZwOUZPOVAM
RPvSJdMVkzMVDeHK7tJEUEUMHYpg/3VtVD/EjkHCRrkWStLx4IhJp4UszhH4H3Da
B/yklhNpbejjYOPFT75O/LCBM+cvzdBhO2QucsisyA6WD9fPTzR5clPsndHJSdKW
Ai8lfH5wI0D4Ci4kl2NTCEtIE/StbV4DhZx/VXVu08jSu+xuSribBGimGsAPu/lx
473lFEgjEujaXG2OvUZNBEQwqcBMd8cvkHT+9VyF1M/f8g==
=WzQF
-----END PGP MESSAGE-----&lt;/code&gt;&lt;/pre&gt;


	&lt;p&gt;We&amp;#8217;ll email it to ourselves now, read the email and save the message in the body to &lt;code&gt;uptime&lt;/code&gt;&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;simon@computer:~$ gpg -d uptime &amp;gt; uptime-manual&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;Of course, you&amp;#8217;ll be prompted for the password &lt;code&gt;simonh&lt;/code&gt; and you get the original file back.&lt;/p&gt;

	&lt;p&gt;Here&amp;#8217;s the original, decrypted text&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;UPTIME(1)                                 User Commands                                 UPTIME(1)

NAME
       uptime - Tell how long the system has been running.

SYNOPSIS
       uptime [options]

DESCRIPTION
       uptime  gives a one line display of the following information.  The current time, how long
       the system has been running, how many users are currently logged on, and the  system  load
       averages for the past 1, 5, and 15 minutes.

       This is the same information contained in the header line displayed by w(1).

       System  load  averages is the average number of processes that are either in a runnable or
       uninterruptable state.  A process in a runnable state is either using the CPU  or  waiting
       to  use  the  CPU.   A process in uninterruptable state is waiting for some I/O access, eg
       waiting for disk.  The averages are taken over the three time  intervals.   Load  averages
       are not normalized for the number of CPUs in a system, so a load average of 1 means a sin‐
       gle CPU system is loaded all the time while on a 4 CPU system it means it was idle 75%  of
       the time.

OPTIONS
       -p, --pretty
              show uptime in pretty format

       -h, --help
              display this help text

       -s, --since
              system up since, in yyyy-mm-dd HH:MM:SS format

       -V, --version
              display version information and exit

FILES
       /var/run/utmp
              information about who is currently logged on

       /proc  process information

AUTHORS
       uptime was written by Larry Greenfield ⟨greenfie@gauss.rutgers.edu⟩ and Michael K. Johnson
       ⟨johnsonm@sunsite.unc.edu⟩

SEE ALSO
       ps(1), top(1), utmp(5), w(1)

REPORTING BUGS
       Please send bug reports to ⟨procps@freelists.org⟩

procps-ng                                 December 2012                                 UPTIME(1)&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;So, just using this simple method, you can take any file, encrypt it (you can change the cipher by the way), compress it and then send it to someone who knows the key. If you accidentally send the message to someone who wasn&amp;#8217;t expecting it, they&amp;#8217;ll have little clue what it&amp;#8217;s all about. &lt;/p&gt;

	&lt;p&gt;Awesome!&lt;/p&gt;</content><category term="software"></category><category term="gpg"></category><category term="gnu"></category><category term="web"></category></entry><entry><title>Using WordPerfect 6.2 in DOSBox (Part 1)</title><link href="https://simonh.uk/2021/05/17/using-wordperfect-62-in-dosbox-part-1/" rel="alternate"></link><published>2021-05-17T00:00:00+01:00</published><updated>2021-05-17T00:00:00+01:00</updated><author><name>Simon Harrison</name></author><id>tag:simonh.uk,2021-05-17:/2021/05/17/using-wordperfect-62-in-dosbox-part-1/</id><summary type="html">	&lt;p&gt;Some say it went downhill from here&lt;/p&gt;</summary><content type="html">	&lt;p&gt;&lt;img alt="Wordperfect Logo" src="/img/2021-05-17/wp.gif" title="Wordperfect Logo" /&gt;&lt;/p&gt;

	&lt;h2&gt;Why?&lt;/h2&gt;

	&lt;blockquote&gt;
		&lt;p&gt;WordPerfect for &lt;span class="caps"&gt;DOS&lt;/span&gt;, in the opinion of many knowledgeable users, is still the greatest program ever written. Some of its features have not been matched even by the latest Windows software, and its interface remains unequaled for efficiency and elegance. Its support for multiple font formats has not been equaled by any other program or operating system, and its support for multiple alphabets, languages, and symbol sets has only been equaled by twenty-first-century versions of Windows, Linux, and the Mac OS.&lt;/p&gt;
	&lt;/blockquote&gt;

	&lt;p&gt;&lt;a href="http://www.columbia.edu/~em36/wpdos/"&gt;www.columbia.edu/~em36/wpdos/&lt;/a&gt;&lt;br /&gt;
&lt;a href="http://www.dosdays.co.uk/topics/Software/wordperfect.php"&gt;www.dosdays.co.uk/topics/Software/wordperfect.php&lt;/a&gt;&lt;br /&gt;
&lt;a href="https://blog.cmpxchg8b.com/2020/09/finding-console-word-processor.html"&gt;blog.cmpxchg8b.com/2020/09/finding-console-word-processor.html&lt;/a&gt;&lt;br /&gt;
&lt;a href="http://www.studymore.org.uk/wp51.htm"&gt;www.studymore.org.uk/wp51.htm&lt;/a&gt;&lt;/p&gt;

	&lt;h2&gt;My Reasons&lt;/h2&gt;

	&lt;p&gt;I use &lt;span class="caps"&gt;GNU&lt;/span&gt;/Linux and the obvious choices are LibreOffice, Apache OpenOffice and Abiword. They&amp;#8217;re all fine and the first two can go toe to toe with MS Office any day of the week. &lt;/p&gt;

	&lt;p&gt;But sometimes, I think it&amp;#8217;s a bit overkill. And LibreOffice isn&amp;#8217;t exactly &lt;em&gt;fast&lt;/em&gt; to load up. This isn&amp;#8217;t the first time I&amp;#8217;ve installed WordPerfect, but as I&amp;#8217;ve got a bit of time on my hands, I thought I&amp;#8217;d dig a bit deeper.&lt;/p&gt;

	&lt;p&gt;And to my knowledge, Linux never really had a &lt;em&gt;great&lt;/em&gt; word processor (correct me if I&amp;#8217;m wrong).&lt;/p&gt;

	&lt;h2&gt;Add Colemak Keyboard Layout to Dosbox&lt;/h2&gt;

	&lt;p&gt;I&amp;#8217;m awkward so I use an alternative keyboard layout called &lt;a href="https://colemak.com/"&gt;Colemak&lt;/a&gt;. I&amp;#8217;ve been using it since 2008 so the first order of business was to get that set up correctly.&lt;/p&gt;

	&lt;p&gt;Copy this &lt;a href="https://gist.github.com/gonejack/0655029de3465cb78f3e"&gt;mapper&lt;/a&gt;&lt;/p&gt;

	&lt;p&gt;Save that as &lt;code&gt;colemak-0.74.map&lt;/code&gt; in you dosbox settings directory. &lt;/p&gt;

&lt;pre&gt;&lt;code&gt;simon@computer:~/.dosbox$ tree
.
├── colemak-0.74.map
├── dosbox-0.74-3.conf
└── dosbox-0.74.conf&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;Open &lt;code&gt;dosbox-0.74-3.conf&lt;/code&gt; and find the line beginning with &lt;code&gt;mapperfile&lt;/code&gt;&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;mapperfile=mapper-0.74-3.map&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;I usually just comment out the original value and add the new one below:&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;#mapperfile=mapper-0.74-3.map
mapperfile=colemak-0.74.map&lt;/code&gt;&lt;/pre&gt;

	&lt;h2&gt;Obtain the Software&lt;/h2&gt;

	&lt;p&gt;I searched for &amp;#8220;Corel WordPerfect Suite 6.2 for &lt;span class="caps"&gt;DOS&lt;/span&gt;&amp;#8221; and the filesize of the &lt;code&gt;.7z&lt;/code&gt; file should be about 49.1MB.&lt;/p&gt;

	&lt;p&gt;Open with wine (5.0) and follow the prompts. I opted to only install WordPerfect, not the full suite. &lt;/p&gt;

	&lt;p&gt;Here are a few screenshots of the install process. Notice the help tips &lt;/p&gt;

	&lt;p&gt;&lt;img alt="installation 1" src="/img/2021-05-17/wp-install1.png" title="installation 1" /&gt;&lt;/p&gt;

	&lt;p&gt;&lt;img alt="installation 2" src="/img/2021-05-17/wp-install2.png" title="installation 2" /&gt;&lt;/p&gt;

	&lt;p&gt;&lt;img alt="installation 3" src="/img/2021-05-17/wp-install3.png" title="installation 3" /&gt;&lt;/p&gt;

	&lt;p&gt;When it&amp;#8217;s finished installing you&amp;#8217;ll need to launch &lt;code&gt;WP.EXE&lt;/code&gt;&lt;/p&gt;

&lt;pre&gt;&lt;code&gt;simon@computer:~/.wine/drive_c/COREL/WP62$ ls
CVDASC.CVX   HRF6.FRS      TIBM.VRS     VMP.COM       WP_OS2.ICO
CVDTKT.CVX   INSTALL.EXE   T_LES1K.TUT  WP350M.ORS    WPSTAND.DR
CVDWP5X.CVX  LIBRARY.STY   T_LES1M.TUT  WP350.ORS     WPUS.ICR
CVDWP60.CVX  MACROS        T_LES2.TUT   WP480M.ORS    WP{WPC}.LCN
CVDWPG1.CVX  MCV.EXE       T_LES3.TUT   WP480.ORS     WP{WPC}.QKL
CVDWPG2.CVX  QFIGENUS.EXE  T_LES4.TUT   WP62.INS      WP{WPC}.SET
CV.EXE       README.ARS    T_LIB.TUT    WP62.PIF      WP_WP_US.BRS
EGA512.FRS   README.CV     T_LTRS.TUT   WP.COM        WP_WP_US.HLM
EGAITAL.FRS  README.FAX    VAPINUL.COM  WP_CV_US.DLG  WP_WP_US.HLP
EGASMC.FRS   README.MCV    VGA512.FRS   WP_CV_US.HLP  WP_WP_US.MRS
EGAUND.FRS   README.VRS    VGAITAL.FRS  WP.EXE        WP_WP_US.QRS
EGA.VRS      README.WP     VGASMC.FRS   WP.FIL        WP_WP_US.TRS
GRAPHICS     STANDARD.IRS  VGAUND.FRS   WPICONS.DLL   WP_WP_US.TUT
HRF12.FRS    TEMPLATE      VGA.VRS      WP.LRS&lt;/code&gt;&lt;/pre&gt;

	&lt;p&gt;Which will give you the following beautiful screen&lt;/p&gt;

	&lt;p&gt;&lt;img alt="wordperfect running" src="/img/2021-05-17/wp-dosbox1.png" title="wordperfect running" /&gt;&lt;/p&gt;

	&lt;p&gt;The first thing you&amp;#8217;ll want to do is choose &lt;code&gt;Help &amp;gt; Tutorial&lt;/code&gt; from the top menu.&lt;/p&gt;

	&lt;p&gt;&lt;img alt="help &amp;gt; tutorial" src="/img/2021-05-17/wp-dosbox2.png" title="help &amp;gt; tutorial" /&gt;&lt;/p&gt;

	&lt;p&gt;And spend about twenty minutes going through them. It&amp;#8217;s worth your time, I assure you.&lt;/p&gt;

	&lt;p&gt;&lt;img alt="help &amp;gt; tutorial" src="/img/2021-05-17/wp-dosbox3.png" title="help &amp;gt; tutorial" /&gt;&lt;/p&gt;

	&lt;p&gt;By the way, your mouse will be &lt;strong&gt;trapped&lt;/strong&gt; in the dosbox window. To free it hit &lt;code&gt;CTRL-F10&lt;/code&gt; (took me a while to discover that)!&lt;/p&gt;

	&lt;h2&gt;WordPerfect Tips&lt;/h2&gt;

	&lt;p&gt;&lt;a href="http://www.microcounsel.com/WPTIPS.HTM"&gt;www.microcounsel.com/WPTIPS.HTM&lt;/a&gt;&lt;br /&gt;
&lt;a href="https://www.youtube.com/watch?v=ML_GoEUhs4A"&gt;www.youtube.com/watch?v=ML_GoEUhs4A&lt;/a&gt;&lt;/p&gt;

	&lt;p&gt;And the first link at top of this page, has lots of great resources for getting help, manuals etc.&lt;/p&gt;</content><category term="software"></category><category term="software"></category><category term="dos"></category><category term="terminal"></category></entry><entry><title>Interesting UNIX, BSD, Linux programs and Packages</title><link href="https://simonh.uk/2021/04/19/interesting-unix-bsd-linux-programs-and-packages/" rel="alternate"></link><published>2021-04-19T00:00:00+01:00</published><updated>2021-04-19T00:00:00+01:00</updated><author><name>Simon Harrison</name></author><id>tag:simonh.uk,2021-04-19:/2021/04/19/interesting-unix-bsd-linux-programs-and-packages/</id><summary type="html">	&lt;p&gt;A Post-it&amp;#8482; note for *nix stuff.&lt;/p&gt;</summary><content type="html">	&lt;p&gt;&lt;img alt="Vintage Terminal" src="/img/2021-04-19/vt100.webp" title="Vintage Terminal" /&gt;&lt;/p&gt;

	&lt;h1&gt;Mail&lt;/h1&gt;

	&lt;p&gt;&lt;a href="https://mailutils.org/"&gt;Mailutils&lt;/a&gt;&lt;/p&gt;

	&lt;blockquote&gt;
		&lt;p&gt;Mailutils is a swiss army knife of electronic mail handling. It offers a rich set of utilities and daemons for processing e-mail.&lt;/p&gt;
	&lt;/blockquote&gt;

	&lt;p&gt;&lt;a href="https://github.com/leahneukirchen/mblaze"&gt;mblaze&lt;/a&gt;&lt;/p&gt;

	&lt;blockquote&gt;
		&lt;p&gt;The mblaze message system is a set of Unix utilities for processing and intseracting with mail messages which are stored in maildir folders.&lt;/p&gt;
	&lt;/blockquote&gt;


	&lt;p&gt;&lt;a href="https://github.com/nicm/fdm"&gt;fdm&lt;/a&gt;&lt;/p&gt;

	&lt;blockquote&gt;
		&lt;p&gt;fdm is a program designed to fetch mail from POP3 or &lt;span class="caps"&gt;IMAP&lt;/span&gt; servers, or receive local mail from stdin, and deliver it in various ways.&lt;/p&gt;
	&lt;/blockquote&gt;

	&lt;p&gt;&lt;a href="https://getmail6.org/"&gt;getmail6&lt;/a&gt;&lt;/p&gt;

	&lt;blockquote&gt;
		&lt;p&gt;Welcome to getmail 6, a mail retriever with support for POP3, POP3-over-&lt;span class="caps"&gt;SSL&lt;/span&gt;, IMAP4, IMAP4-over-&lt;span class="caps"&gt;SSL&lt;/span&gt;, and &lt;span class="caps"&gt;SDPS&lt;/span&gt; mail accounts. It supports normal single-user mail accounts and multidrop (domain) mailboxes. getmail is written in Python, and licensed under the &lt;span class="caps"&gt;GNU&lt;/span&gt; General Public License version 2.&lt;/p&gt;
	&lt;/blockquote&gt;

	&lt;p&gt;&lt;a href="http://pyropus.ca/software/getmail/"&gt;getmail&lt;/a&gt;&lt;/p&gt;

	&lt;blockquote&gt;
		&lt;p&gt;getmail is a mail retriever designed to allow you to get your mail from one or more mail accounts on various mail servers to your local machine for reading with a minimum of fuss. getmail is designed to be secure, flexible, reliable, and easy-to-use. getmail is designed to replace other mail retrievers such as fetchmail.&lt;/p&gt;
	&lt;/blockquote&gt;

	&lt;p&gt;&lt;a href="https://public-inbox.org/"&gt;public-inbox&lt;/a&gt;&lt;/p&gt;

	&lt;blockquote&gt;
		&lt;p&gt;public-inbox implements the sharing of an email inbox via git to&lt;br /&gt;
complement or replace traditional mailing lists.  Readers may&lt;br /&gt;
read via &lt;span class="caps"&gt;NNTP&lt;/span&gt;, &lt;span class="caps"&gt;IMAP&lt;/span&gt;, Atom feeds or &lt;span class="caps"&gt;HTML&lt;/span&gt; archives.&lt;/p&gt;
	&lt;/blockquote&gt;

	&lt;p&gt;&lt;a href="https://www.dbmail.org/"&gt;dbmail&lt;/a&gt;&lt;/p&gt;

	&lt;blockquote&gt;
		&lt;p&gt;Fast and scalable sql based email services&lt;br /&gt;
Storage of mail messages in a relational database&lt;br /&gt;
Frontends: IMAP4, POP3, ManageSieve, LMTP&lt;br /&gt;
Backends: MySQL, PostgreSQL, Oracle, and &lt;span class="caps"&gt;SQL&lt;/span&gt;ite&lt;/p&gt;
	&lt;/blockquote&gt;

	&lt;p&gt;&lt;a href="https://puszcza.gnu.org.ua/software/mailfromd/"&gt;Mailfromd&lt;/a&gt;&lt;/p&gt;

	&lt;blockquote&gt;
		&lt;p&gt;Mailfromd is a general-purpose mail filtering daemon for Sendmail, Postfix and MeTA1. It is able to filter both incoming and outgoing messages using criteria of arbitrary complexity, supplied by the administrator in the form of a script file. The daemon interfaces with the &lt;span class="caps"&gt;MTA&lt;/span&gt; using Milter or PMilter protocols.&lt;/p&gt;
	&lt;/blockquote&gt;

	&lt;p&gt;&lt;a href="http://www.ivarch.com/programs/qsf/"&gt;&lt;span class="caps"&gt;QSF&lt;/span&gt;&lt;/a&gt;&lt;/p&gt;

	&lt;blockquote&gt;
		&lt;p&gt;Quick Spam Filter (&lt;span class="caps"&gt;QSF&lt;/span&gt;) is an Open Source email classification filter, designed to be small, fast, and accurate, which works to classify incoming email as either spam or non-spam. To recognise spam, &lt;span class="caps"&gt;QSF&lt;/span&gt; strips the text out of the email (using &lt;span class="caps"&gt;MIME&lt;/span&gt; decoding and &lt;span class="caps"&gt;HTML&lt;/span&gt; stripping) and then splits it into tokens (words, word pairs, &lt;span class="caps"&gt;URL&lt;/span&gt;s, and so on). These tokens are then looked up in a database and analysed using the Bayesian technique to see whether the email should be classified as spam or not.&lt;/p&gt;
	&lt;/blockquote&gt;</content><category term="software"></category><category term="linux"></category><category term="debian"></category></entry><entry><title>Mercurial for the Lone Coder</title><link href="https://simonh.uk/2020/09/08/mercurial-for-the-lone-coder/" rel="alternate"></link><published>2020-09-08T00:00:00+01:00</published><updated>2020-09-08T00:00:00+01:00</updated><author><name>Simon Harrison</name></author><id>tag:simonh.uk,2020-09-08:/2020/09/08/mercurial-for-the-lone-coder/</id><summary type="html">	&lt;p&gt;Learn to Love Revision Control&lt;/p&gt;</summary><content type="html">	&lt;p&gt;&lt;img alt="Mercurial Logo" src="/img/logo/mercurial.svg" title="Mercurial Logo" /&gt;&lt;/p&gt;

	&lt;h2&gt;Background&lt;/h2&gt;

	&lt;p&gt;I&amp;#8217;ve been a (productive) programmer for about three years now.&lt;br /&gt;
My workflow has been the following:&lt;/p&gt;

	&lt;ol&gt;
		&lt;li&gt;set up a folder for the project&lt;/li&gt;
		&lt;li&gt;start working&lt;/li&gt;
		&lt;li&gt;create an archive of the folder with the current date each day and save that in multiple locations for backup&lt;/li&gt;
		&lt;li&gt;rename the folder to todays date&lt;/li&gt;
		&lt;li&gt;Back to step 2&lt;/li&gt;
	&lt;/ol&gt;

	&lt;p&gt;I was aware pretty much from day one that this wasn&amp;#8217;t the best setup, but it worked and I didn&amp;#8217;t have to worry about any tool clobbering my work and leaving me with &lt;a href="https://www.mail-archive.com/fossil-users%40lists.fossil-scm.org/msg04665.html"&gt;lost files&lt;/a&gt;&lt;/p&gt;

	&lt;p&gt;I remember that happening at the time, as Zed Shaw went from a massive fan of fossil, to, well, not a massive fan. &lt;/p&gt;

	&lt;p&gt;Over the years, I&amp;#8217;ve tried &lt;a href="https://fossil-scm.org/"&gt;Fossil&lt;/a&gt;, &lt;a href="https://git-scm.com/"&gt;Git&lt;/a&gt; and &lt;a href="https://www.mercurial-scm.org/"&gt;Mercurial&lt;/a&gt; (and probably others). &lt;/p&gt;

	&lt;p&gt;I always came to the conclusion that I&amp;#8217;d need to put in too much time to learn their intricacies to bother with them.&lt;/p&gt;

	&lt;p&gt;Anyway, last month I decided to revisit &lt;span class="caps"&gt;SCM&lt;/span&gt; again. As I&amp;#8217;d been using &lt;span class="caps"&gt;SQL&lt;/span&gt;ite a lot, I thought Fossil would be ideal as it&amp;#8217;s used as the &lt;span class="caps"&gt;SCM&lt;/span&gt; for &lt;span class="caps"&gt;SQL&lt;/span&gt;ite itself. &lt;/p&gt;

	&lt;h2&gt;My Thoughts about Fossil&lt;/h2&gt;

	&lt;p&gt;Fossil uses an sqlite database as the repository. One of it&amp;#8217;s best features is that it&amp;#8217;s an &lt;span class="caps"&gt;SCM&lt;/span&gt;, a wiki, a bug tracker, a forum, a website, and probably other stuff too.&lt;/p&gt;

	&lt;p&gt;What annoyed me very quickly though is the workflow:&lt;/p&gt;

	&lt;ul&gt;
		&lt;li&gt;Create a directory ~/fossil where you store your repositories&lt;/li&gt;
		&lt;li&gt;From that directory run &lt;code&gt;fossil new  project.fossil /path/to/where/actual/code/is&lt;/code&gt;&lt;/li&gt;
		&lt;li&gt;Then run &lt;code&gt;fossil open /path/to/where/actual/code/is&lt;/code&gt;&lt;/li&gt;
		&lt;li&gt;Get a warning from fossil that the directory is not empty and must use &lt;code&gt;--force&lt;/code&gt; to override&lt;/li&gt;
	&lt;/ul&gt;

	&lt;p&gt;I mean, come on! So, I ditched the idea of using fossil and thought I&amp;#8217;d see what Mercurial (hg) was like nowadays. &lt;/p&gt;

	&lt;p&gt;Here is the hg way:&lt;/p&gt;

	&lt;ul&gt;
		&lt;li&gt;Run &lt;code&gt;hg init&lt;/code&gt; in the directory you want to track&lt;/li&gt;
		&lt;li&gt;Run &lt;code&gt;hg add .&lt;/code&gt; to add everything&lt;/li&gt;
		&lt;li&gt;Make some changes, run &lt;code&gt;hg commit -m 'I changed some things'&lt;/code&gt;&lt;/li&gt;
		&lt;li&gt;Run &lt;code&gt;hg serve&lt;/code&gt; and have a web interface&lt;/li&gt;
	&lt;/ul&gt;

	&lt;p&gt;I recommend using &lt;code&gt;hg c 'Changed something else'&lt;/code&gt;&lt;/p&gt;

	&lt;p&gt;by adding the following to your &lt;code&gt;~/.hgrc&lt;/code&gt;&lt;/p&gt;

	&lt;p&gt;&lt;code&gt;[alias]&lt;/code&gt;&lt;br /&gt;
&lt;code&gt;c = commit -m&lt;/code&gt;&lt;/p&gt;


	&lt;p&gt;TO BE &lt;span class="caps"&gt;CONTINUED&lt;/span&gt;&amp;#8230;&lt;/p&gt;</content><category term="software"></category><category term="VCS"></category><category term="Mercurial"></category></entry><entry><title>My New Favourite Text Editor</title><link href="https://simonh.uk/2016/01/19/my-new-favourite-text-editor/" rel="alternate"></link><published>2016-01-19T00:00:00+00:00</published><updated>2016-01-19T00:00:00+00:00</updated><author><name>Simon Harrison</name></author><id>tag:simonh.uk,2016-01-19:/2016/01/19/my-new-favourite-text-editor/</id><summary type="html">&lt;p&gt;Notepad2-mod is great!&lt;/p&gt;</summary><content type="html">&lt;p&gt;&lt;em&gt;Note: This post is from an old Pelican blog I used to have at simonh.me, which I found on a backup drive on 2025-01-07. It's probably of no use, but reposted for posterity!&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Over the years, I've tried &lt;em&gt;lots&lt;/em&gt; of text editors. Vim, EMACS, Sublime Text,
Jedit, Nano, Notepad++ (and more). As I use Linux at home and Windows at work, I've been looking for a while, for one that I can use on either OS. &lt;/p&gt;
&lt;p&gt;As much as I love Linux (and I have &lt;strong&gt;no&lt;/strong&gt; desire to switch back to Windows after about six years), there is some software written for Windows that I think is fantastic. Foobar2000, imgburn (when I used to burn discs), Adobe Photoshop and namexif spring to mind. &lt;/p&gt;
&lt;p&gt;So, a few weeks ago I set about (again) finding a text editor that I could use just as well at work as I could at home. I had another go with Notepad++. It seemed to be trying to do a bit too much. The interface has too much going on. I needed something simpler. Plus there were some oddities running on Wine. I somehow stumbled upon Notepad2-mod &lt;a href="https://xhmikosr.github.io/notepad2-mod/"&gt;https://xhmikosr.github.io/notepad2-mod/&lt;/a&gt;. &lt;/p&gt;
&lt;p&gt;A text editor that wanted to be &lt;em&gt;slightly better&lt;/em&gt; than Notepad??? This doesn't sound good, I thought. But when I tried it, it seemed to be just what I was looking for. Syntax highlighting for Python and indentation guides are all I really need at the moment. Plus, it works great on Wine. &lt;/p&gt;
&lt;p&gt;It does very little for you, except what you &lt;strong&gt;need&lt;/strong&gt;. I class that as a
feature. I have the utmost respect for editors like Vim, but that it is pretty
much unusable "out of the box", without hunting around on the net for 
tips on how to set up your &lt;code&gt;.vimrc&lt;/code&gt; seems strange to me. &lt;/p&gt;
&lt;p&gt;If you haven't tried it, and are wanting to do some coding, rather than
learning the intricacies of a particular text editor, I urge you to give it
a go. &lt;/p&gt;</content><category term="software"></category><category term="coding"></category><category term="archived"></category></entry></feed>