devAlice
← Mac

Brewfile 管理 — 用 `brew bundle` 将 Mac 开发环境代码化

一种将 Mac 配置锁定到单个文件的 Brewfile 模式。dump → cleanup → install,完整循环,换机一步到位。

每次配置新 Mac 都要逐行敲 brew install,效率极低。brew bundle 让一个 Brewfile 将 brew 公式、cask、VS Code 扩展,甚至 App Store 应用打包成可复现的配置。掌握这一模式后,换机和团队成员入职的时间能缩减数个半小时。

我认为 Brewfile 的价值不只是自动化安装,而是把开发环境变成可审计的代码。以前环境存在于脑子里和操作历史里;如今通过 brew bundle,环境变成了 Git 可以追踪的文件,因为那个文件才是环境的单一真实来源。

本指南适用于 macOS 14+ / Homebrew 4.x,是 Mac 初始配置 之后的将环境冻结为代码步骤。

TL;DR

  1. brew bundle dump --describe 将当前状态快照到 Brewfile
  2. 手动编辑(删除重复项和测试包)→ 提交到 Git
  3. 在新 Mac 上:brew bundle install --file=./Brewfile → 完成
  4. 定期 brew bundle cleanup 删除不在 Brewfile 中的内容

前提条件

  • Homebrew 4.x 已安装 — 参见 Mac 初始配置
  • (可选)GitHub 仓库或 Gist(用于存储 Brewfile)
  • (可选)mas-cli — 如需打包 Mac App Store 应用,运行 brew install mas

下载示例 Brewfile

devAlice 推荐的基础配置 — 下载后根据你的环境修改。

Brewfile
# 1. 下载
curl -fsSL https://devalice.jaceclub.com/assets/mac/brewfile-management/Brewfile.example -o Brewfile
 
# 2. 验证 SHA-256
shasum -a 256 Brewfile
# 期望值:2b54214d29391d15666fe5e15768aa2e6e6eabea8b3c772989d6e1216a816c5f
 
# 3. 检查(查看包含哪些包;根据你的环境编辑)
less Brewfile
 
# 4. 应用
brew bundle install --file=./Brewfile

1. Brewfile 语法基础 — 5 分钟

底层是 Ruby DSL,但实际上只需要掌握五个关键词。

# Brewfile
 
# tap — 额外的仓库
tap "homebrew/bundle"
tap "homebrew/services"
 
# brew — 公式(CLI 工具)
brew "git"
brew "gh"
brew "mise"
 
# 支持可选参数
brew "postgresql@16", restart_service: :changed
brew "redis",         start_service: true
 
# cask — GUI 应用
cask "visual-studio-code"
cask "rectangle"
 
# Mac App Store(需要 mas-cli)
mas "Xcode", id: 497799835
 
# VS Code 扩展(与 mas 类似语法)
vscode "dbaeumer.vscode-eslint"
vscode "esbenp.prettier-vscode"

注释 + 分区

# ─── CLI ──────────────────────────────────────
brew "git"
brew "gh"
 
# ─── GUI ──────────────────────────────────────
cask "visual-studio-code"

分区分隔符对后续维护大有裨益——提交后 diff 一目了然。


2. 从当前状态生成 Brewfile — dump — 3 分钟

如果你已经有一台配置完善的机器,可以一次性快照。

# 在当前目录创建 Brewfile(--force 覆盖已有文件)
brew bundle dump --force --describe
 
# --describe 为每行添加 # 注释 — 可读性提升

示例输出:

# ./Brewfile(自动生成)
tap "homebrew/services"
brew "git"
# Distributed revision control system
brew "gh"
# GitHub command-line tool
brew "jq"
# Lightweight and flexible command-line JSON processor
brew "mise"
# Polyglot runtime manager (asdf rust clone)
cask "visual-studio-code"
# Open-source code editor

手动整理 dump 结果

新 dump 会捕获当前所有已安装的内容,通常包含不少冗余。整理清单:

  1. 不再使用的测试包 → 删除
  2. 语言运行时 → 如果用 mise 管理,就删掉(如 nodepython@3.x
  3. 工作与个人 → 拆分为 Brewfile.work / Brewfile.personal
  4. 添加分区注释

现在投入 10 分钟,未来省下一个小时的配置时间。


3. 在另一台机器上应用 — install — 10-30 分钟

在包含 Brewfile 的目录中,在新机器上(或清理后):

brew bundle install --file=./Brewfile
 
# 或使用绝对路径
brew bundle install --file=$HOME/dotfiles/Brewfile
 
# 已安装的项目会跳过(幂等)

首次运行以 cask 下载为主(每个约 50-200MB)。预计需要 10-30 分钟。

逐步查看 — --verbose

brew bundle install --file=./Brewfile --verbose

只显示失败 — --quiet

brew bundle install --file=./Brewfile --quiet

4. 删除不在 Brewfile 中的包 — cleanup — 5 分钟

要让 Brewfile 成为唯一真实来源,删除未列出的所有内容。

# 演习 — 查看将会删除什么
brew bundle cleanup --file=./Brewfile
 
# 实际删除 — 谨慎操作
brew bundle cleanup --file=./Brewfile --force

⚠️ --force 会立即卸载。只在 Brewfile 完全整理好之后运行;否则可能需要重新安装。


5. 拆分策略 — 工作 / 个人 / 实验

单一的 Brewfile 最终会变得臃肿。按场景拆分。

~/dotfiles/
├── Brewfile           # 通用(CLI 必需品)
├── Brewfile.work      # 仅工作(Slack、Zoom...)
├── Brewfile.personal  # 个人(游戏启动器...)
└── Brewfile.optional  # 偶尔使用

一起应用

cd ~/dotfiles
brew bundle install --file=./Brewfile
brew bundle install --file=./Brewfile.work
brew bundle install --file=./Brewfile.personal

或通过 Makefile/shell 脚本

# ~/dotfiles/bundle.sh
#!/usr/bin/env bash
set -euo pipefail
cd "$(dirname "$0")"
for f in Brewfile Brewfile.work Brewfile.personal; do
  [ -f "$f" ] && brew bundle install --file="./$f"
done
echo "✓ 所有 Brewfile 已应用"

6. Git 版本控制 — 3 分钟

Brewfile 是任何 dotfiles 仓库的核心文件。

cd ~/dotfiles
git init
git add Brewfile Brewfile.*
git commit -m "feat: initial Brewfile baseline"
git remote add origin git@github.com:<user>/dotfiles.git
git push -u origin main

之后添加/删除包时:

brew bundle dump --force --describe   # 刷新
git diff Brewfile                     # 查看变更
git commit -am "feat: add postgresql + redis"
git push

在新机器上:

git clone git@github.com:<user>/dotfiles.git ~/dotfiles
cd ~/dotfiles
brew bundle install --file=./Brewfile

7. 自动化 — brew services + macOS LaunchAgent

每天自动 dump 一次,防止 brew 状态漂移。

~/Library/LaunchAgents/dev.local.brewdump.plist

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
  <key>Label</key><string>dev.local.brewdump</string>
  <key>ProgramArguments</key>
  <array>
    <string>/bin/bash</string>
    <string>-lc</string>
    <string>cd $HOME/dotfiles && /opt/homebrew/bin/brew bundle dump --force --describe</string>
  </array>
  <key>StartCalendarInterval</key>
  <dict><key>Hour</key><integer>22</integer><key>Minute</key><integer>0</integer></dict>
</dict>
</plist>
launchctl load ~/Library/LaunchAgents/dev.local.brewdump.plist

每天 22:00 自动 dump。每天早上 git diff 查看隔夜变化。


8. 故障排除

cleanup 时提示「Error: Cask 'X' is not installed」

该 cask 已在其他地方删除。重新运行 brew bundle cleanup --force 使状态重新一致。

Dump 捕获了太多意外的包

旧的传递依赖显示为顶级包。整理方法:

brew autoremove   # 删除仅作为依赖项使用的叶包
brew bundle dump --force --describe  # 重新 dump

App Store 应用未出现在 dump 中

mas-cli 未安装。运行 brew install mas 后重新 dump。

某些 cask 在安装时 SHA-256 校验失败

Homebrew 更新 cask 定义后可能发生。运行 brew update 后重试。


下一步

参考资料

更新日志

  • 2026-05-12 — 初始版本(devAlice M2 种子扩展)