Nov 04

Time Machine automatically deletes old backups when it’s getting full, but if you also use the backup disk for other purposes, you might want to clear some space manually.

There is a built-in command line utility that comes with macOS which you can use for this – tmutil.

Specifically, the sub-command you want is tmutil delete, here is an extract from the man page:

     delete [-d backup_mount_point -t timestamp] [-p path]
             Deletes the backups with the specified timestamp from the backup volume mounted at the specified
             mountpoint. The -t option followed by a timestamp can be used multiple times to specify multiple backups
             to delete. For HFS backup disks, a specific path to delete can also be specified using the -p option.
             This verb can delete items from backups that were not made by, or are not claimed by, the current
             machine. Requires root and Full Disk Access privileges.

You can list existing backups with tmutil listbackups but the path that’s printed is not the path you need to provide to tmutil delete. In fact, you actually need to provide the -d and -t flags, not -p.

To find the backup mount point, you can use tmutil destinationinfo. Here is an example output:

~ $ tmutil destinationinfo                                                                                     
====================================================
Name          : Time Machine
Kind          : Local
Mount Point   : /Volumes/Time Machine
ID            : F0CBBC01-DEAD-CA1F-BEEF-0000AAAABBBB

So in this case, the value for the -d flag is "/Volumes/Time Machine".

You can extract this with awk or another utility, for example:

~ $ tmutil destinationinfo | awk -F ' : ' '/Mount Point/{print $2}'                                            
/Volumes/Time Machine

As for the -t (timestamp) flag, this is obvious from the tmutil listbackups output, but you can even specify -t in the listbackups sub-command which prints only the value needed in the correct format.

For example:

~ $ tmutil listbackups -t
2022-02-05-094839
2022-02-12-091416
2022-02-19-093000
2022-02-26-092448
...

Bringing it all together

Now we know what values to pass to tmutil delete, the final command might look like this:

sudo tmutil delete -d "/Volumes/Time Machine" -t 2022-02-05-094839

But we can go one better than this… Say you want to delete all the backups from Jan-Mar in 2023, you can use this one-liner:

tmutil listbackups -t | \
egrep '2023-0[123]' | \
xargs -L 1 sudo tmutil delete \
-d "$(tmutil destinationinfo | awk -F ' : ' '/Mount Point/{print $2}')" -t

Of course you could filter in other ways, e.g. head -n 20 to delete the oldest 20 backups (careful though, this will delete the most recent as well if there are only 20 or fewer in total).

Tagged with:
Dec 23

I recently purchased a new Mac mini to replace my home computer – a 2009 iMac. It was well overdue as Apple listed it as obsolete 4 years ago.

Unfortunately, it only comes with 256GB SSD storage as standard and Apple charges £200 extra for 512GB and £400 extra for 1TB. Very pricey! So in an attempt to save some money, I thought I would use an external drive for additional space.

It wasn’t long before I settled on the idea of getting an NVMe SSD with an enclosure. This was recommended by The Verge and seemed to offer the best price point and flexibility.

For the SSD itself, I went through several sites such as Tom’s Hardware looking for a recommendation and eventually settled on the ADATA XPG SX8200 Pro. This offered a good price/performance ratio (at least in the UK).

Now came the more tricky part – which enclose to use. Originally, I was expecting to get a Thunderbolt enclosure, but it turns out they are prohibitively expensive – especially for my use-case. It didn’t make sense to spend more on the caddy than the SSD!

After trawling Amazon for a while I picked up a FIDECO M.2 NVME External SSD Enclosure. It looked very promising – 4.3 out of 5 starts with 782 ratings.

However, as soon as it arrived – the fun started. While I did manage to connect and initialise the disk, immediately after starting a file transfer it detached itself from the OS. I tried disconnecting and reconnecting it, but it showed up uninitialised as a 97.86TB disk.

I thought I’d try formatting it again, but I ended up with the following error:

Unable to write to the last block of the device. : (-69760)

This makes sense, given how big it thought the disk is (over 90TB), and how big it actually is (1TB).

At this point, I started researching enclosures and looking around to if others had similar problems. It turns out NVMe enclosures are notoriously flakey and there are many forums threads discussing the topic.

What I found is, for all the off-brand enclosures, there are three actual chips that power them:

  1. JMS583
  2. RTL9210(B)
  3. ASM2362

Without knowing ahead of time, it seems the enclosure I first bought contained a RTL9210B. This does not have a lot of complaints, but it certainly didn’t work for me. I even tried upgrading the firmware to no avail.

So with that in mind, I scoured Amazon for a new enclosure with a different chipset. Specifically an ASM2362 as the JMicron chip has lots of negative comments.

A few days later (no, I don’t have Prime) my Kafuty USB3.1 to M.2 NVME External Hard Drive Enclosure arrived and I swapped over the SSD.

It immediately showed up in Finder but I thought I’d reinitialise it anyway. Some file transfers and speed-tests later, all was still good ?

TLDR; On my M1 Mac mini, RTL9210B was a complete failure and ASM2362 is stable.

Tagged with:
Feb 18

I have been maintaining my own SVN server for many years, but in order to share code and make use of managed services, it was time to migrate some of my repositories to Git.

There are many tutorials for svn-git migration, here’s a customised script which works for me: migrate-svn-to-git.sh. Note, it requires an authors.txt file – there any plenty of adequate resources out there for how to create one.

There is nothing specific about this script for Google Source Repos, that is just my choice for private code so it can make use of Google Cloud Build and gcr.io.

#!/usr/bin/env bash

svnUri="$1"
gitUri="$2"

if [[ -z "${svnUri}" || -z "${gitUri}" ]]
; then
echo "[ERROR] Usage migrate-svn-to-git.sh <svn_uri> <git_uri>" 1>&2
exit 1
fi

if [[
! -f authors.txt ]]; then
echo "[ERROR] authors.txt is missing" 1>&2
exit 1
fi

echo "[INFO] Cloning from SVN: ${svnUri}"
git svn --authors-file=authors.txt clone -s ${svnUri} --prefix svn/ migration
cd migration

echo "[INFO] Creating Git tags"
for
t in $(git for-each-ref --format='%(refname:short)' refs/remotes/svn/tags); do git tag $(echo ${t} | sed 's^svn/tags/^^') ${t} && git branch -D -r ${t}; done
echo "[INFO] Creating Git branches"
for
b in $(git for-each-ref --format='%(refname:short)' refs/remotes/svn | grep -v trunk); do git branch $(echo ${b} | sed 's^svn/^^') refs/remotes/${b} && git branch -D -r ${b}; done

echo "[INFO] Creating .gitignore file"
git svn show-ignore > .gitignore
git add .gitignore
git commit -m "Added .gitignore"

echo "[INFO] Pushing to Git: ${gitUri}"
git remote add google ${gitUri}
git push --force google --tags
git push --force google --all

cd -

echo "[INFO] Removing migration directory"
rm -rf migration

Once you have created the Git repo, you need to switch your working copy of a project from SVN to Git. Here’s a script: switch-svn-to-git.sh

#!/usr/bin/env bash

gitUri="$1"

if [[ -z "${gitUri}" ]]
; then
echo "[ERROR] Usage switch-svn-to-git.sh <git_uri>" 1>&2
exit 1
fi

if [[
! -d .svn ]]; then
echo "[ERROR] Not a SVN project" 1>&2
exit 1
fi

echo "[INFO] Finding current branch"
svnBranch=$(svn info | grep '^URL:' | egrep -o '(tags|branches)/[^/]+|trunk' | egrep -o '[^/]+$')
echo "[DEBUG] ${svnBranch}"

echo "[INFO] Cleaning SVN directory"
rm -rf .svn

echo "[INFO] Initialising Git from: ${gitUri}"
git init
git remote add origin ${gitUri}
git fetch

echo "[INFO] Saving working copy"
git show origin/master:.gitignore > .gitignore
git checkout -b tmp
git add .
git commit -m "local changes"

echo "[INFO] Checking out branch"
gitBranch="master"
if [[ $
{svnBranch} != "trunk" ]]; then
gitBranch="${svnBranch}"
fi
git checkout ${gitBranch}

echo "[INFO] Merging working copy"
git merge --allow-unrelated-histories -X theirs --squash tmp
git branch --delete --force tmp

echo "[INFO] Deleting IntelliJ reference to SVN (if exists)"
test -f .idea/vcs.xml && rm .idea/vcs.xml

echo "[INFO] Done - you may want to set your name / email with: git config user.email <email>"
Mar 23

Ever wanted to hide an individual file in Mac OS X Finder without prefixing it with a dot? Here’s how (you’ll need the Apple developer tools installed):
[code lang=”bash”]/Developer/Tools/SetFile -a V «filename»[/code]
…and to show it again:

[code lang=”bash”]/Developer/Tools/SetFile -a v «filename»[/code]

If you want the Finder to show all hidden files, use this command:

[code lang=”bash”]defaults write com.apple.finder AppleShowAllFiles -bool true[/code]

…and to hide them again:

[code lang=”bash”]defaults write com.apple.finder AppleShowAllFiles -bool false[/code]

You’ll need to relaunch the Finder after this. I can think of three ways:

  1. [code lang=”bash”]killall Finder[/code]
  2. The “Force Quit Applications” dialogue box
  3. Click and hold “Finder” in the Dock while also holding ‘option’.
preload preload preload