| Date: | 2026-05-07 09:46 |
|---|---|
| category: | Tech |
| tags: | macos, homebrew, productivity |
| summary: | Automated upgrade scripts are great until a critical tool breaks. Learn how to pin specific packages and use filtered commands to keep your environment stable without losing your "lazy" workflow. |
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.
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>- 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 -vlogic 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
pinfeature 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.
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.