Skip to content

bundle: add a pin: true Brewfile option - #24454

Merged
MikeMcQuaid merged 1 commit into
Homebrew:mainfrom
zhuoqun-chen:bundle-pinned
Nov 4, 2026
Merged

MikeMcQuaid merged 1 commit into
Homebrew:mainfrom
zhuoqun-chen:bundle-pinned

Conversation

@zhuoqun-chen

@zhuoqun-chen zhuoqun-chen commented Nov 3, 2026 •

Copy link
Copy Markdown
Contributor

  • Have you followed our Contributing guidelines?
  • Have you checked for other open Pull Requests for the same change?
  • Have you explained what your changes do? Performance claims (e.g. "this is faster") must include brew benchmark results.
  • Have you explained why you'd like these changes included, not just what they do?
  • For bug fixes, have you given step-by-step brew commands to reproduce the bug?
  • Have you written new tests (excluding integration tests)? Here's an example.
  • Have you successfully run brew lgtm (style, typechecking and tests) locally?

  • I did not use AI/LLM to create this PR, or I disclosed the tool/model below and reviewed its output; I did not attribute commits to AI and will answer maintainer questions and review comments myself without AI/LLM.

AI/LLM disclosure: the code, tests and docs in this PR were drafted with Claude Code (model Claude Fable 5.1) from the behaviour discussed in Homebrew/discussions#6951, and reworked the same way after the first review. brew lgtm was run locally, and the option was exercised end to end on a Mac (below). I review the diff myself and answer review comments myself.


What

A per-entry pin: true option for brew and cask lines in a Brewfile:

cask "google-chrome", pin: true
brew "node@20", pin: true
  • brew bundle install installs the package if it is missing and then runs brew pin on it. An installed, unpinned package is pinned without being upgraded (progress verb Pinning); a package that is already pinned is skipped. A pinned entry is never upgraded by brew bundle, and brew upgrade skips it as it skips any pinned package.
  • brew bundle dump writes pin: true for pinned formulae and casks, so a dumped Brewfile reproduces the pins on another machine.

Undoing it is brew unpin, as with any pin; brew bundle check treats the option like greedy: (it only sees the pin once it exists). Pinned casks with auto_updates true can still update themselves outside Homebrew, as brew pin already warns.

Why

Since 6.0.9, brew upgrade and brew bundle upgrade an auto_updates true cask whenever the version in the tap is confirmed newer than the installed app bundle. For a browser kept on its own update channel that is unwanted, and the only opt-out, HOMEBREW_NO_UPGRADE_AUTO_UPDATES_CASKS, is global. brew pin is the per-package answer for both brew upgrade and brew bundle, but it is machine-local state that a Brewfile shared across machines could not declare. In Homebrew/discussions#6951 (https://github.com/orgs/Homebrew/discussions/6951#discussioncomment-17882821) I asked whether a per-cask toggle exists for brew bundle and @p-linnane answered "No, there isn't. Happy to review a PR adding this if you'd like." This is that PR.

How

  • bundle/cask.rb: upgrading? is false for a pinned entry; preinstall! lets an installed, unpinned cask through; install! then only runs brew pin --cask; dump emits pin: true.
  • bundle/brew.rb: the same for formulae (@pin, pin_change_state! with brew pin --formula, install_verb, dump).
  • docs/Brew-Bundle-and-Brewfile.md: one example in the advanced Brewfile listing.
  • Specs: pin instead of upgrade, skip when pinned, install then pin, and dump, for both types.

Verified on a Mac with cask "microsoft-edge", pin: true in a scratch Brewfile: brew bundle install printed Pinning microsoft-edge and left the installed version alone, a second run skipped it, brew bundle dump wrote cask "microsoft-edge", pin: true, and brew unpin --cask microsoft-edge restored the box.

@MikeMcQuaid
MikeMcQuaid marked this pull request as ready for review November 3, 2026 08:57

@MikeMcQuaid MikeMcQuaid left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good idea, implementation needs some work:

  • CI is failing
  • Please address any CodeRabbit comments when they come in
  • Let's use pin: true rather than pinned: true
  • Ensure brew bundle dump works correctly
  • Try to slim the code here; it feels pretty complex for what should be simple

@coderabbitai

coderabbitai Bot commented Nov 3, 2026 •

Copy link
Copy Markdown
Contributor

Review in Change Stack →

Summary

Summary by CodeRabbit

  • New Features
    • Brewfiles can use pin: true for formulae and casks. Missing packages are installed and pinned; installed packages are pinned without being upgraded.
    • Brew Bundle dumps include the pinned state of formulae and casks.
  • Bug Fixes
    • Pin-only actions skip unnecessary upgrade and post-install steps.
  • Documentation
    • Added guidance and an example for managing pinned casks, including automatic updates.

Brew Bundle formula and cask entries now support pin: true. Installation applies pins when needed, and installed pinned entries are not upgraded. Dump output records pinned state. Tests and documentation cover these changes.

Changes: Brewfile package pinning

Layer / File(s) Summary
Formula pin state and install flow
Library/Homebrew/bundle/brew.rb, Library/Homebrew/test/bundle/brew_spec.rb
Formula entries record requested pinning, pin formulae when needed, and avoid upgrading installed formulae when pinning is requested. Dumps include pin: true for pinned formulae. Tests cover installation, pinning, and already-pinned formulae.
Cask pin state and install flow
Library/Homebrew/bundle/cask.rb, Library/Homebrew/test/bundle/cask_spec.rb, Library/Homebrew/test/bundle/dumper_spec.rb, docs/Brew-Bundle-and-Brewfile.md
Cask entries pin installed casks when requested and do not upgrade them in that case. Pin-only operations skip postinstall. Dumps include pin: true; tests and documentation cover the behaviour.
Merge Risk: Moderate · up to 55ffa

With pin: true, brew bundle check can report success when a package still needs pinning. The documented brew bundle check || brew bundle install pattern then skips the install and the pin is never applied. Fix the check paths before merging.

Pre-merge checks: Passed 4
Check name Status Explanation
Title check Passed The title "bundle: add a pin: true Brewfile option" matches the main change. The PR adds a per-entry pin: true option for brew and cask lines in a Brewfile, covering install, pin, upgrade skip…
Linked Issues check Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check Passed Check skipped because no linked issues were found for this pull request.
Description check Passed The description is specific and on-topic. It describes a per-entry pin: true option for brew and cask Brewfile lines, the install, dump and upgrade behaviour, the files touched (bundle/brew.rb…
Full details: Title check

Explanation

The title "bundle: add a pin: true Brewfile option" matches the main change. The PR adds a per-entry pin: true option for brew and cask lines in a Brewfile, covering install, pin, upgrade skip, and dump behaviour. The title is short, specific and free of noise. The PR objectives name the option pinned:, but the changeset implements pin: true, so the title agrees with the code.

Full details: Description check

Explanation

The description is specific and on-topic. It describes a per-entry pin: true option for brew and cask Brewfile lines, the install, dump and upgrade behaviour, the files touched (bundle/brew.rb, bundle/cask.rb, docs and specs), the motivation (auto_updates true casks, Homebrew/discussions#6951), and a manual verification on a Mac. It matches the changeset in the raw summary, so the check passes.

Tip

🎯 Customize your risk assessments

Guide how CodeRabbit assesses merge risk and security architecture risk. Highlight sensitive changes and explain your security boundaries using Merge Risk Instructions and Security Risk Instructions in your review settings. Security architecture risk assessments require the Advanced plan or above.

✅ Automatic approvals, with your rules

Let CodeRabbit approve pull requests once required threads are resolved, pre-merge checks pass, and your risk limits are met. Enable Automatic approvals in review settings, with overrides for teams or file paths.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

Share
Recent review info
Run configuration
  • Source mode: Auto
  • Repository: Unavailable
  • Branch: Unavailable
  • File: No configuration file from this repository applied
  • Commit: Unavailable
  • Layers: Organization UI
  • Review profile: CHILL
  • Plan: Advanced
  • Run ID: b992dd2f-4e9d-4320-b6ac-e28770e60881
Commits

Reviewing files that changed from the base of the PR and between 45c95c5 and 55ffa41.

Files selected for processing: 5
  • Library/Homebrew/bundle/brew.rb
  • Library/Homebrew/bundle/cask.rb
  • Library/Homebrew/test/bundle/brew_spec.rb
  • Library/Homebrew/test/bundle/cask_spec.rb
  • docs/Brew-Bundle-and-Brewfile.md

Included review availability: This review used your included allowance. Your plan provides up to 10 included reviews per hour; 9 remain after this review.

Since Homebrew 6.0.9 `brew upgrade` and `brew bundle` upgrade casks with
`auto_updates true` whenever the tap version is confirmed newer than the
installed one, and the only opt-out is the global
`HOMEBREW_NO_UPGRADE_AUTO_UPDATES_CASKS`. `brew pin` already keeps a
formula or cask out of both commands, but it is machine-local state that
a `Brewfile` could not declare (Homebrew/discussions#6951).

- `brew "foo", pin: true` and `cask "foo", pin: true` install the package
  when it is missing and then `brew pin` it. An installed, unpinned
  package is pinned without being upgraded; a pinned one is skipped.
- `brew bundle dump` writes `pin: true` for pinned formulae and casks.
@zhuoqun-chen zhuoqun-chen changed the title bundle: add a pinned: true Brewfile option bundle: add a pin: true Brewfile option Nov 3, 2026
Comment thread Library/Homebrew/bundle/brew.rb Resolved
Comment thread Library/Homebrew/bundle/cask.rb Resolved
@zhuoqun-chen

zhuoqun-chen commented Nov 4, 2026 •

Copy link
Copy Markdown
Contributor Author

Hi @MikeMcQuaid , all the requirements are addressed, the 2 CodeRabbit comments are manually resolved because I think making more commits breaks your "keep it simple" point. Similar to greedy option, here the logic is left simple for check and install.

@MikeMcQuaid MikeMcQuaid left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, this is more like it, nice work!

@MikeMcQuaid
MikeMcQuaid enabled auto-merge November 4, 2026 11:19
@MikeMcQuaid
MikeMcQuaid disabled auto-merge November 4, 2026 11:25
@MikeMcQuaid
MikeMcQuaid added this pull request to the merge queue Nov 4, 2026
Merged via the queue into Homebrew:main with commit 4d1e464 Nov 4, 2026
56 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

⌂ 换网址