Multiple Tool Versions via Homebrew

Recently, I started using Hugo with an older project. After I pulled the code and ran hugo, it failed. It turned out it was not yet compatible with the latest version that got automatically installed via Homebrew.

Well, no big deal, Homebrew allows for installing older versions of formulae. So I got it working.

Shortly after that, I started another new project (this blog, BTW). Guess what happened? It broke again, this time because the installed version of hugo was too old and not compatible with the configured theme.

Well, that is a bit of a problem, but there is hope:

Installing an old Version

The nice thing is that Homebrew entirely relies on files from a public repository on GitHub. The bad thing is that all default formulae come from this repository, and we have to inspect the commit history to find the desired version of a tool. This is a task that is most likely going to overwhelm the GitHub UI at some point.

Get the Last Versions from Homebrew

Hence, we only need to find the respective commit for what we want to install. For that, we can use either Homebrew itself or Git commands.

Using Homebrew

$ brew log --oneline hugo

This will output the last commits for the formula. However, the installation of Homebrew relies on a shallow clone of the corresponding Git repository, which means there is only partial data available, i.e., the desired version we want to install might not be included in the result anymore.

If we are lucky, and the version is included in the output, we can proceed with the next step: Find the Formula. Otherwise, we have to use Git to access the full history.

Using Git

  • We don’t need any actual files.
  • We don’t need an actual checkout.
  • We’re only interested in the master branch.

The following command gives us exactly that:

$ git clone \
--filter=blob:none \
--no-checkout \
--single-branch \
--branch master \
https://github.com/Homebrew/homebrew-core.git

Although we did not check out any branch, we still received more than 260 MB of commit history data. Obviously, we would like to avoid that, if possible.

After cloning the repository (history information), we can check the logs for commits related to the tool and version we are interested in, hugo and version 0.41 in this example:

$ git log --oneline | grep hugo | grep -F 0.41
  1. Get the commit history in one-line format
  2. Filter all commits related to hugo
  3. Filter all commits related to version 0.41 (using a fixed string, otherwise the . had to be escaped.

This returns the following result:

b1e187384b hugo: update 0.41 bottle. 824a875022 hugo 0.41

We are only interested in the most recent commit for the version.

Find the Formula

$ git diff-tree --no-commit-id --name-only -r b1e187384b Formula/hugo.rb

Usually, this result should not be a big surprise since all formulae are located in the Formula directory and the information about a formula also cover this:

$ brew info hugo
hugo: stable 0.69.0 (bottled), HEAD Configurable static site generator https://gohugo.io/ From: https://github.com/Homebrew/homebrew-core/blob/master/Formula/hugo.rb

Install from File Path via Homebrew

$ brew install https://raw.githubusercontent.com/Homebrew/homebrew-core/824a875022/Formula/hugo.rb

Bringing it all together with ${FORMULA} and ${VERSION} representing what we want to install, we can use the following snippet to install a formula based on the Git commit history:

Prevent old Version from Upgrades

This can be undone with the below command:

Install latest Version

By unlinking the previously installed version, we simulate the state without the tool being installed:

Now, it will not be possible to use the command:

$ hugo version
zsh: command not found: hugo

Install new Version

$ brew update
$ brew install hugo

If we run the version command again, we will get the expected output:

$ hugo version
Hugo Static Site Generator v0.69.0/extended darwin/amd64 BuildDate: unknown

Switch between Installed Versions

Check available Versions

$ brew list --versions hugo

Switch to another Version

That’s all!

Internally, Homebrew is updating symlinks to point to the respective version we are specifying in the switch command.

Originally published at https://4ndrs.xyz on April 12, 2020.

Photo Enthusiast, Cyclist, Scandinavia Traveller, Hockey Fan, and Book Lover in personal life. IT Architect/Developer and Scrum Master in professional life.

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store