The problem
Automating package updates is the dream for any developer who values their time. However, the "bleeding edge" can sometimes cut you. Recently, my preferred terminal, Tabby, broke following a series of macOS updates.
When a core tool in your workflow fails after an unattended upgrade, it halts productivity. While Homebrew allows you to "pin" standard formulae to prevent them from updating, there is currently no native "pin" or "hold" feature for Homebrew Casks. This means a blanket upgrade command will always try to pull the latest (and potentially broken) version of your GUI applications.
The (imperfect) solution
To keep using a specific version of a Cask while still upgrading everything else, you can use a filtered command. Instead of a blind global upgrade, you can list outdated casks and exclude the problematic one using grep.
For Tabby, the following command ensures everything else moves forward while the terminal remains untouched:
# Upgrade all casks except Tabby
brew upgrade --cask --greedy $(brew outdated --cask --greedy | grep -v "tabby")
For standard CLI tools (formulae), you should use the built-in pinning mechanism:
# Prevent a formula from being upgraded
brew pin <package_name>
Why this improves stability
- The "stay lazy" workflow
Most of us use a "one-liner" to keep our systems current. My personal "lazy" script handles Homebrew, Python tools, and specific app fixes in one go:
brew update || true; brew upgrade || true; brew upgrade --cask --greedy $(brew outdated --cask --greedy | grep -v "tabby") || true; brew cleanup -s || true; uv tool upgrade --all || true; xattr -cr /Applications/Chromium.app
- Targeted exclusion
- By adding the grep -v logic to the middle of the chain, you maintain the automation. You don't have to remember to skip Tabby manually; the script handles the logic for you.
- Granular control
- This approach bridges the gap between the robust pin feature available for formulae and the lack of such a feature for Casks. It ensures that known-stable versions of GUI apps stay put until you are ready to manually verify a fix.
The perfect solution that does not yet exist
If only the Homebrew maintainers would implement a native brew cask pin command. Having a unified way to freeze versions for both command-line tools and applications would eliminate the need for complex bash one-liners and custom grep filters.
Originally published as GitHub Gist #02ac4c3c2b2bd1dd0d896f9c8e13b9bd
Comments