You Automated Homebrew Updates. Did You Keep the Receipt?

Maybe you enabled brew autoupdate. Maybe you run brew update && brew upgrade yourself whenever the guilt becomes sufficiently loud.

Either way, here is the uncomfortable question: do you know what changed?

Not “is Homebrew current?” That part is easy. I mean which formulae and casks were installed before the update, which taps were active, which dependency tree you had, and which Git revision each tap pointed to.

I did not want another dashboard for that. I wanted a receipt.

That is what brew-snapshot creates.

Homebrew state should be a file, not a memory

Install it from my tap:

brew install AndrewDongminYoo/tap/brew-snapshot

Then take a snapshot:

brew-snapshot snapshot

The command first runs brew update and brew upgrade. It then writes the resulting state under ~/.local/share/brew-snapshot/:

  • Brewfile is the reinstall manifest used by brew bundle.
  • Brewfile.lock contains Homebrew's installed-package information as JSON.
  • Brewfile.deps records the installed dependency tree.
  • Brewfile.taps lists active taps.
  • Brewfile.refs records each available tap's Git commit.
  • last_snapshot_utc records when the snapshot completed.

Those files do not pretend that a package manager is a time machine (Homebrew would probably object anyway). They turn machine state into ordinary text and JSON that you can inspect, diff, and put under version control.

Let login do the boring part

The useful snapshot is the one that actually gets taken. Remembering to run a backup command is not much better than remembering every package by hand.

brew-snapshot setup

setup registers a user LaunchAgent that runs the snapshot command on login. There is also an explicit mode for casks whose auto-update flag would normally keep them out of a standard upgrade:

brew-snapshot snapshot --greedy

I kept this deliberately boring: no cloud account, no database, and no opaque sync format. The output is a directory you own.

Restoration is useful, but history is the real feature

On a new Mac, the obvious command is:

brew-snapshot restore

That installs from the saved Brewfile. It is useful after a migration, but it is not exact package-version reproduction. The project states that limit plainly: it does not pin every formula, and Homebrew may no longer serve the same versions later.

For version-sensitive software, the lock is evidence, not a guarantee. You may still need a versioned formula or brew extract.

The quieter benefit appears before disaster. When an update breaks a command, you can stop asking “what did I have yesterday?” and inspect the snapshot instead. The package list, dependency tree, tap set, and tap revisions give the investigation somewhere concrete to begin.

That was the missing piece for me. Automation kept the machine current, but it did not explain the machine. brew-snapshot gives the updates a paper trail.

If your Mac development environment has become too important to reconstruct from memory, install brew-snapshot and keep the receipt.