跳转到内容

用 Brewfile 声明这台机器装了什么 ​

用了一年之后,brew list 会列出几十上百个包,其中一部分你已经忘了为什么装。Brewfile 把这份清单变成一个可以读、可以提交、可以在新机器上执行的文件。

brew bundle 是 Homebrew 的内置子命令,不需要额外 tap。Homebrew 官方文档:Brew Bundle 与 Brewfile

开始之前 ​

需要装好 Homebrew,见使用 Homebrew 管理工具。本文命令不会卸载任何东西,除非你明确执行 cleanup——那一节单独标注了风险。

导出当前状态 ​

sh
brew bundle dump --describe

dump 把当前已安装的内容记录成 Brewfile,写在当前目录。--describe 给每一项加上一行说明注释——这是这篇里最值得记住的参数,因为半年后你需要的正是这些说明。

当前目录已有 Brewfile 时命令会失败,这是保护机制。确认可以覆盖再加 --force。

打开生成的文件,会看到几类条目:

ruby
tap "homebrew/cask-fonts"
brew "ripgrep"
cask "iina"
mas "Klib", id: 1439578330
vscode "editorconfig.editorconfig"
  • tap 是额外的软件源。
  • brew 是命令行包(formula)。
  • cask 是图形界面应用。
  • mas 是 App Store 应用,需要另外装 mas 这个命令行工具,并且已在 App Store 登录。
  • vscode 是编辑器扩展。

Brewfile 按 Ruby 语法解析,所以可以写条件判断,但这会让文件难读。先保持它是一份平铺的清单。

核对与重建 ​

检查当前机器与清单是否一致:

sh
brew bundle check --verbose

check 只报告差异,不做任何改动。--verbose 让它列出具体缺哪些,而不是只给一个结论。

按清单安装:

sh
brew bundle install

已经装好的项目会被跳过,所以重复执行是安全的。这条命令也可以简写成 brew bundle。

cleanup 会卸载东西 ​

sh
brew bundle cleanup

不加参数时它只列出清单里没有、但机器上装了的包,不执行删除。确认列表无误后,才用 --force 真正卸载。

务必先看列表。刚从别的机器拿来一份 Brewfile 就直接 cleanup --force,会卸载掉这台机器上你需要但清单里没有的软件。卸载图形应用时,应用的配置和数据未必一并清除,相关说明见卸载应用。

它不锁定版本 ​

这是最容易误解的地方。Homebrew 是滚动更新的包管理器,brew bundle 没有也不会有 lock 文件的概念。同一份 Brewfile 今天和三个月后执行,装到的版本不同。

所以 Brewfile 回答的是「装了哪些软件」,不是「装了哪些版本」。需要锁定运行时版本,那是另一件事,用 mise 管理并把版本写进项目里的配置文件。

默认情况下 brew bundle install 会顺带升级已装的包。不希望它这样做时加 --no-upgrade。

检查结果 ​

在一个临时目录里 brew bundle dump --describe,打开文件确认:条目数量和你的实际安装大致相符,每行都有说明注释,没有出现你不认识的 tap。

然后执行 brew bundle check --verbose,应当报告没有缺失。如果报告缺少 mas 条目,说明你还没装 mas 工具或没在 App Store 登录——这属于预期行为,不是清单出错。

动手练习 ​

用一个可丢弃的目录完成一轮,不影响现有安装:

  1. mkdir -p /tmp/brewfile-test && cd /tmp/brewfile-test
  2. brew bundle dump --describe,通读生成的文件,标出三个你已经想不起用途的包。
  3. brew bundle check --verbose,确认结果是一致。
  4. 手工删掉文件里的一行,再执行一次 check,观察它如何报告差异。
  5. 不要在这个目录执行 cleanup --force。

成功标准是能解释第 4 步的输出,并且对第 2 步标出的三个包做出决定:查清用途还是卸载。清单的价值不在于文件本身,而在于它逼你面对那些忘了为什么装的东西。

返回开发环境