Brew Install Missing Formulas

5 minute read Published

How to recover deleted Homebrew formulas following a brew upgrade.

Okay so I was trying to upgrade to the latest version of Hugo today on macOS and didn’t have the time nor the patience to read man brew again.

tldr brew didn’t show how to install a specific version of a formula so I did what any reasonable person would do and read Jake Trent’s downgrading post so I knew how to go back after an upgrade.

Then I ran a brew upgrade hugo to get the latest Hugo version…

docs master* ❯ brew upgrade hugo
==> Upgrading 1 outdated package:
hugo 0.44 -> 0.54.0
==> Upgrading hugo
==> Downloading https://homebrew.bintray.com/bottles/hugo-0.54.0.mojave.bottle.tar.gz
######################################################################## 100.0%
==> Pouring hugo-0.54.0.mojave.bottle.tar.gz
==> Caveats
Bash completion has been installed to:
  /usr/local/etc/bash_completion.d
==> Summary
🍺  /usr/local/Cellar/hugo/0.54.0: 31 files, 38.0MB
Removing: /usr/local/Cellar/hugo/0.40.1... (32 files, 28.2MB)
Removing: /usr/local/Cellar/hugo/0.40.2... (32 files, 28.2MB)
Removing: /usr/local/Cellar/hugo/0.42.1... (32 files, 28.3MB)
Removing: /usr/local/Cellar/hugo/0.44... (32 files, 54.6MB)
Removing: /usr/local/Cellar/hugo/0.46... (32 files, 54.9MB)
Removing: /usr/local/Cellar/hugo/0.53... (31 files, 37.9MB)

…and watched with doe-shaped eyes as Homebrew indiscriminately removed all the prior Hugo versions I’d installed. I couldn’t believe it.

Could they be in in the trash I alias to rm? Nope, not there…

Okay, so I’ll just reinstall 0.44. That’s all I need anyway right now. So clearly this will be as simple as brew install hugo@0.44 right?

WRONG!

I was met with errors:

images master* ❯ brew install hugo@0.44
Updating Homebrew...
==> Auto-updated Homebrew!
Updated 1 tap (homebrew/cask).
No changes to formulae.

Error: No available formula with the name "hugo@0.44"
==> Searching for a previously deleted formula (in the last month)...
Error: No previously deleted formula found.
==> Searching for similarly named formulae...
Error: No similarly named formulae found.
==> Searching taps...
==> Searching taps on GitHub...
Error: No formulae found in taps.

What, no beer this time? I felt like someone at GitHub was laughing at me. But I know never to attribute to malice that which can be explained by…

Anyway, so I opened an enhancement on Homebrew repository. There weren’t many open issues so surely this must be kind of regression which could be dovetailed into a useful feature. Right?

WRONG!

My issue was shredded apart by the lead maintainer. His quoted replies to each of my sentences felt like a curmudgeon writing teacher grading a poorly written essay. The issue was closed right then and there. But what greased me was that guy never even responded to my idea. It’s as if his emotions blinded him and he never saw the forest through the trees. Lack of gumption I guess.

Or maybe that’s what people who work for GitHub act like I thought to myself? The fleeting memory of subservience to a boss man told me otherwise. This dude was straight up unpleasant so I candidly let him know about it.

Now where were we… Oh yes, trying to downgrade to an older version of Hugo!

Installing Missing Brew Formulas

Okay, let’s get back to work doing something fruitful. After reading over several related questions on SO dating back as far as 8 years I finally see why dude got salty. This issue affects almost everyone at some point.

Based on several SO answers old brew formulas can install from HTTP. I saw people sharing URLs to gists and I downvoted every one of them. Then I cloned the homebrew-core repository using Git Desktop:

Then chose Open in Terminal from the Repository pull-down menu and ran a git log to find the commit sha of the version of Hugo I was looking for:

homebrew-core master ❯ git log Formula/hugo.rb
3f14077758 - hugo 0.46 (6 months ago) 
790b350335 - hugo: update 0.45.1 bottle. (7 months ago) 
50788e9d4f - hugo 0.45.1 (7 months ago) 
94fe208747 - hugo: update 0.45 bottle. (7 months ago) 
390320b60c - hugo 0.45 (7 months ago) 
2f62e91d58 - hugo: update 0.44 bottle. (7 months ago) 
2aedd26426 - hugo 0.44 (7 months ago) 
6412ad0f88 - hugo: update 0.43_1 bottle. (7 months ago) 
c49f3560dd - hugo: build extended version (7 months ago) 
8cafd8a34a - hugo: update 0.43 bottle. (7 months ago) 
4f872f0795 - hugo 0.43 (7 months ago) 
b8ad6a5124 - hugo: update 0.42.2 bottle. (7 months ago) 
546a6e4182 - hugo 0.42.2 (7 months ago) 

Bingo! Then I checked the diff just to make sure what was in it:

homebrew-core master ❯ git diff 2aedd26426~1 2aedd26426
diff --git a/Formula/hugo.rb b/Formula/hugo.rb
index 757a9936b6..27769053ed 100644
--- a/Formula/hugo.rb
+++ b/Formula/hugo.rb
@@ -1,9 +1,8 @@
 class Hugo < Formula
   desc "Configurable static site generator"
   homepage "https://gohugo.io/"
-  url "https://github.com/gohugoio/hugo/archive/v0.43.tar.gz"
-  sha256 "6a263844847b9676a38b7a687fda77f47e7cc39cdff7a9c1234a7afeec7baddb"
-  revision 1
+  url "https://github.com/gohugoio/hugo/archive/v0.44.tar.gz"
+  sha256 "63e6ae4be7e7b23ab5551842182b49be9a9a07a82d217c1a7a2815b49976129d"
   head "https://github.com/gohugoio/hugo.git"

And the paranoiac in me had to make sure I was looking at the right repo:

homebrew-core master ❯ git config --get remote.origin.url
https://github.com/Homebrew/homebrew-core.git
homebrew-core master ❯

Okay, looks good. Now to cobble together an install script:

FORMULA=hugo && \
COMMIT=2aedd26426 && \
RAW_PATH=https://raw.githubusercontent.com/Homebrew/homebrew-core && \
brew unlink ${FORMULA} && \
brew install ${RAW_PATH}/${COMMIT}/Formula/${FORMULA}.rb

(Variable expansion not strictly necessary.)

And that’s it. A repurposable shell script to recover formulae deleted during a brew upgrade. To use it simply replace hugo with the formula you wish to recover and swap 2aedd26426 with the commit sha the version was introduced to homebrew-core and you’re off to the races.

If you’re looking for a more robust approach you can run brew extract as mentioned by the Homebrew maintainer. But ain’t nobody got time for that.