macOS Homebrew 重装与国内镜像配置手册

本文记录一次在 Apple Silicon Mac 上重装 Homebrew 的完整流程,适用于以下情况:

  • 打开终端时 Homebrew 报 Ruby 栈错误,例如 Version value must be a string; got a NilClass
  • /opt/homebrew 中的 Homebrew 本体过旧,无法识别新版本 macOS
  • 想保留旧包清单,重新安装干净的 Homebrew
  • 想把 Homebrew 配成国内较快的镜像源

本文以 Apple Silicon 默认路径 /opt/homebrew 为例。如果你的 Mac 是 Intel 芯片,默认路径通常是 /usr/local,不要直接照搬路径。

0. 本次修复后的目标状态

重装完成后,目标状态如下:

lua 复制代码
brew --version
brew update
brew config

都应该正常执行,不再出现 Ruby NilClass 栈错误。

国内镜像配置采用中科大 USTC:

arduino 复制代码
export HOMEBREW_API_DOMAIN=https://mirrors.ustc.edu.cn/homebrew-bottles/api
export HOMEBREW_BOTTLE_DOMAIN=https://mirrors.ustc.edu.cn/homebrew-bottles
export HOMEBREW_BREW_GIT_REMOTE=https://mirrors.ustc.edu.cn/brew.git

注意:不要设置 HOMEBREW_CORE_GIT_REMOTE 到 USTC。新版 Homebrew 主要使用 API 元数据,中科大当前不再提供 homebrew-core.git 镜像,设置错误的 core Git remote 反而容易把环境搞坏。

1. 先确认环境

查看 macOS 版本、CPU 架构和 Homebrew 路径:

bash 复制代码
/usr/bin/sw_vers -productVersion
/usr/bin/uname -m
/usr/bin/which brew
/opt/homebrew/bin/brew --version
/opt/homebrew/bin/brew config

Apple Silicon 正常应看到:

bash 复制代码
arm64
/opt/homebrew/bin/brew

如果 brew --version 就报错,先继续往下做备份和重装。

2. 如果打开终端就报错,先临时关闭启动调用

很多终端启动报错是因为 ~/.zprofile 中有这行:

bash 复制代码
eval "$(/opt/homebrew/bin/brew shellenv)"

或者旧写法:

bash 复制代码
eval $(/opt/homebrew/bin/brew shellenv)

brew 本体坏掉时,每次打开 zsh 都会触发错误。先备份配置文件:

bash 复制代码
cp ~/.zprofile ~/.zprofile.bak.$(date +%Y%m%d-%H%M%S)

然后打开编辑:

bash 复制代码
nano ~/.zprofile

brew shellenv 那一行临时注释掉:

shell 复制代码
# eval "$(/opt/homebrew/bin/brew shellenv)"

保存后,新开一个终端验证不再自动报错。

重装完成后再恢复这一行。

3. 如果使用 Clash,确认代理端口

如果网络需要 Clash/Clash Verge/Mihomo,先找本机代理监听端口:

bash 复制代码
/usr/sbin/lsof -nP -iTCP -sTCP:LISTEN | grep -E 'clash|mihomo|789'

本次机器使用的是 Clash Verge 的 mixed-port:

makefile 复制代码
127.0.0.1:7897

后续命令中如果你的端口不同,把 7897 换成自己的端口。

设置本次终端会话的代理变量:

arduino 复制代码
export HTTP_PROXY=http://127.0.0.1:7897
export HTTPS_PROXY=http://127.0.0.1:7897
export ALL_PROXY=socks5://127.0.0.1:7897

可以测试 GitHub 和 USTC 是否可达:

bash 复制代码
curl -I -x http://127.0.0.1:7897 https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh
git -c http.proxy=http://127.0.0.1:7897 ls-remote --symref https://github.com/Homebrew/brew.git HEAD
git -c http.proxy= ls-remote --symref https://mirrors.ustc.edu.cn/brew.git HEAD

如果直连 USTC 很快,git -c http.proxy= 可以绕开代理。

4. 导出旧 Homebrew 包清单

创建备份目录:

perl 复制代码
STAMP=$(date +%Y%m%d-%H%M%S)
BACKUP="$HOME/Documents/work/homebrew-reinstall-backup-$STAMP"
mkdir -p "$BACKUP"

如果旧 brew 还能启动,导出包清单:

bash 复制代码
/opt/homebrew/bin/brew list --formula > "$BACKUP/formulae.txt" || true
/opt/homebrew/bin/brew list --cask > "$BACKUP/casks.txt" || true
/opt/homebrew/bin/brew leaves > "$BACKUP/leaves.txt" || true
/opt/homebrew/bin/brew bundle dump --force --file="$BACKUP/Brewfile" || true

说明:

  • formulae.txt:所有 formula,包括依赖
  • leaves.txt:你主动安装的顶层 formula,更适合用于恢复
  • casks.txt:图形应用
  • Brewfile:Homebrew Bundle 恢复文件

如果之前临时备份过 tap,Brewfile 里可能出现类似下面的行:

arduino 复制代码
tap "homebrew/cask.bak-brewfix-20260713", "https://github.com/Homebrew/homebrew-cask.git"
tap "homebrew/core.bak-brewfix-20260713", "https://github.com/Homebrew/homebrew-core.git"

这些是临时备份目录,不应该用于恢复,后续执行 brew bundle 前要删掉。

5. 确认没有残留 brew 或 Git 更新进程

perl 复制代码
ps -axo pid,ppid,stat,etime,command | grep -E '(/opt/homebrew/bin/brew|Homebrew|git .*homebrew|fetch-pack|index-pack)' | grep -v grep

如果没有输出,说明没有明显残留进程。

如果有正在运行的 brew update 或 Git fetch,先等它结束;确认卡死后再手动终止对应 PID。

6. 备份旧 /opt/homebrew 内容,不直接删除

确认 /opt/homebrew 存在且当前用户可写:

bash 复制代码
ls -ld /opt/homebrew
df -P /opt/homebrew "$HOME/Documents/work"

如果 /opt/homebrew 和备份目录在同一个 APFS 数据卷上,移动会很快,基本是目录改名,不是复制 3G 文件。

移动旧 Homebrew 内容到备份目录:

bash 复制代码
mkdir -p "$BACKUP/old-prefix"
find /opt/homebrew -mindepth 1 -maxdepth 1 -exec mv {} "$BACKUP/old-prefix/" ;
chmod 775 /opt/homebrew

确认现在 /opt/homebrew 是空目录:

bash 复制代码
ls -la /opt/homebrew
du -sh "$BACKUP"

这一步的关键点:不要直接 rm -rf /opt/homebrew。先移动备份,出问题还能恢复。

7. 安装新的 Homebrew 本体

方案 A:官方交互安装脚本

如果你愿意输入管理员密码,可以用官方脚本:

bash 复制代码
/bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"

如果需要 Clash 代理:

ini 复制代码
HTTPS_PROXY=http://127.0.0.1:7897 \
HTTP_PROXY=http://127.0.0.1:7897 \
ALL_PROXY=socks5://127.0.0.1:7897 \
/bin/bash -c "$(curl -fsSL -x http://127.0.0.1:7897 https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)"

注意:官方脚本在 macOS 上通常会检查 sudo 权限。

方案 B:手动克隆 Homebrew 本体

这是本次实际采用的方式。适合 /opt/homebrew 已经存在、为空、且当前用户可写的情况。

使用 GitHub:

bash 复制代码
git -c http.proxy=http://127.0.0.1:7897 \
  -c http.version=HTTP/1.1 \
  clone https://github.com/Homebrew/brew /opt/homebrew

如果 USTC 直连更快,也可以直接克隆中科大镜像:

ini 复制代码
git -c http.proxy= \
  -c http.version=HTTP/1.1 \
  clone https://mirrors.ustc.edu.cn/brew.git /opt/homebrew

如果 /opt/homebrew 不存在,可以先创建并授权:

bash 复制代码
sudo mkdir -p /opt/homebrew
sudo chown -R "$(whoami)":admin /opt/homebrew
chmod 775 /opt/homebrew

8. 初始化并验证新版 brew

bash 复制代码
/opt/homebrew/bin/brew --version
/opt/homebrew/bin/brew shellenv
eval "$(/opt/homebrew/bin/brew shellenv)"

让 Homebrew 初始化 Portable Ruby 和基础配置:

ini 复制代码
HTTPS_PROXY=http://127.0.0.1:7897 \
HTTP_PROXY=http://127.0.0.1:7897 \
ALL_PROXY=socks5://127.0.0.1:7897 \
/opt/homebrew/bin/brew config

正常时应该看到:

yaml 复制代码
HOMEBREW_PREFIX: /opt/homebrew
macOS: 15.x-arm64
Homebrew Ruby: ...

再执行:

ini 复制代码
HTTPS_PROXY=http://127.0.0.1:7897 \
HTTP_PROXY=http://127.0.0.1:7897 \
ALL_PROXY=socks5://127.0.0.1:7897 \
/opt/homebrew/bin/brew update

正常输出类似:

vbnet 复制代码
Already up-to-date.

9. 恢复 shell 启动配置并设置 USTC 镜像

编辑 ~/.zprofile

bash 复制代码
nano ~/.zprofile

加入或替换为下面几行:

bash 复制代码
export HOMEBREW_API_DOMAIN=https://mirrors.ustc.edu.cn/homebrew-bottles/api #ckbrew
export HOMEBREW_BOTTLE_DOMAIN=https://mirrors.ustc.edu.cn/homebrew-bottles #ckbrew
export HOMEBREW_BREW_GIT_REMOTE=https://mirrors.ustc.edu.cn/brew.git #ckbrew
eval "$(/opt/homebrew/bin/brew shellenv)" #ckbrew

同时把 brew 本体 Git remote 改到 USTC:

arduino 复制代码
git -C /opt/homebrew remote set-url origin https://mirrors.ustc.edu.cn/brew.git

验证新登录 shell 是否生效:

dart 复制代码
zsh -l -c 'echo HOMEBREW_API_DOMAIN=$HOMEBREW_API_DOMAIN; echo HOMEBREW_BOTTLE_DOMAIN=$HOMEBREW_BOTTLE_DOMAIN; echo HOMEBREW_BREW_GIT_REMOTE=$HOMEBREW_BREW_GIT_REMOTE; brew config'
git -C /opt/homebrew remote -v
zsh -l -c 'brew update'

期望看到:

ini 复制代码
HOMEBREW_API_DOMAIN=https://mirrors.ustc.edu.cn/homebrew-bottles/api
HOMEBREW_BOTTLE_DOMAIN=https://mirrors.ustc.edu.cn/homebrew-bottles
HOMEBREW_BREW_GIT_REMOTE=https://mirrors.ustc.edu.cn/brew.git
ORIGIN: https://mirrors.ustc.edu.cn/brew.git
Already up-to-date.

10. 恢复旧包

优先使用 leaves.txt 恢复顶层包:

bash 复制代码
[ -s "$BACKUP/leaves.txt" ] && xargs brew install < "$BACKUP/leaves.txt"

恢复 cask:

bash 复制代码
[ -s "$BACKUP/casks.txt" ] && xargs brew install --cask < "$BACKUP/casks.txt"

如果你更信任 Brewfile,先检查并删除临时 .bak-brewfix tap,再执行:

bash 复制代码
sed -n '1,160p' "$BACKUP/Brewfile"
brew bundle --file="$BACKUP/Brewfile"

本次旧环境中顶层包是:

复制代码
helm
nginx
pcre
telnet
zlib

因此本次恢复命令是:

复制代码
brew install helm nginx pcre telnet zlib

安装过程中可能看到:

  • pcre 已弃用:这是警告,不影响安装;长期可以迁移到 pcre2
  • zlib 是 keg-only:macOS 自带 zlib,因此 Homebrew 不会把它默认链接到 PATH
  • nginx 默认端口是 8080:无需 sudo 即可运行

11. 最终验证

bash 复制代码
zsh -l -c 'brew --version && brew list --formula'
zsh -l -c 'brew update'
brew info wget
brew doctor
command -v brew
command -v helm
command -v nginx
command -v telnet
helm version --short
nginx -v

brew doctor 可能返回非零状态,但只要是 warning,不代表 Homebrew 重装失败。

本次遇到的 doctor warning 包括:

  • Command Line Tools 有新版
  • pcre 已弃用
  • /usr/local/lib/libAliST.dylib 是非 Homebrew dylib
  • /usr/local/include/node/* 是非 Homebrew header

这些不影响 brew 启动、更新和安装包。

12. 回滚方法

如果新 Homebrew 安装失败,可以把新内容移动到备份目录,然后恢复旧内容。

假设备份目录是:

ini 复制代码
BACKUP="$HOME/Documents/work/homebrew-reinstall-backup-YYYYMMDD-HHMMSS"

回滚:

bash 复制代码
mkdir -p "$BACKUP/new-prefix-failed"
find /opt/homebrew -mindepth 1 -maxdepth 1 -exec mv {} "$BACKUP/new-prefix-failed/" ;
find "$BACKUP/old-prefix" -mindepth 1 -maxdepth 1 -exec mv {} /opt/homebrew/ ;

然后恢复之前的 ~/.zprofile 备份:

bash 复制代码
ls ~/.zprofile.bak.*
cp ~/.zprofile.bak.YYYYMMDD-HHMMSS ~/.zprofile

重新打开终端验证。

13. 清理备份

确认新 Homebrew 用几天都没问题后,再考虑删除旧备份:

bash 复制代码
du -sh "$BACKUP"

确认路径无误后再删除。建议不要当天立刻删除,至少保留一段时间。

14. 常见问题

14.1 为什么不直接 brew update 原地修?

如果旧 Homebrew 太老,可能无法识别 macOS 15+,启动阶段就报错,brew update 自己也跑不起来。可以尝试手动更新 Git 仓库,但如果旧 tap 或浅克隆状态复杂,重装更干净。

14.2 为什么不设置 HOMEBREW_CORE_GIT_REMOTE

新版 Homebrew 主要通过 API 获取 core/cask 元数据。中科大当前不再提供 homebrew-core.git,实际测试会返回 repository not found。设置错误的 core Git remote 没有收益,反而可能造成更新失败。

14.3 为什么官方安装脚本会失败?

官方脚本在 macOS 上通常会检查 sudo 权限。非交互环境里无法输入密码时,会看到类似:

csharp 复制代码
Need sudo access on macOS

此时如果 /opt/homebrew 已经存在且当前用户可写,可以改用手动克隆 Homebrew 本体的方式。

14.4 Clash 开着但命令还是连不上怎么办?

GUI 应用的系统代理不一定会自动进入终端环境。给命令显式加代理变量:

arduino 复制代码
export HTTP_PROXY=http://127.0.0.1:7897
export HTTPS_PROXY=http://127.0.0.1:7897
export ALL_PROXY=socks5://127.0.0.1:7897

或者在单条命令前临时加:

perl 复制代码
HTTPS_PROXY=http://127.0.0.1:7897 HTTP_PROXY=http://127.0.0.1:7897 ALL_PROXY=socks5://127.0.0.1:7897 brew update

14.5 如何确认当前镜像配置?

arduino 复制代码
brew config | grep HOMEBREW
git -C "$(brew --repository)" remote -v

应看到:

arduino 复制代码
HOMEBREW_API_DOMAIN: https://mirrors.ustc.edu.cn/homebrew-bottles/api
HOMEBREW_BOTTLE_DOMAIN: https://mirrors.ustc.edu.cn/homebrew-bottles
HOMEBREW_BREW_GIT_REMOTE: https://mirrors.ustc.edu.cn/brew.git
origin https://mirrors.ustc.edu.cn/brew.git

15. 参考链接

相关推荐
行者全栈架构师1 小时前
大模型批量生成代码的质量衰减:为什么 AI 越写越敷衍?根因分析与系统性解决方案
后端·架构·代码规范
乐观的Terry1 小时前
1、为什么要自己造发布系统
java·spring boot·后端·spring cloud·架构
用户EasyAdminBlazor1 小时前
EasyAdminBlazor 第十篇:数据导入导出——批量处理不再麻烦
前端·后端
ikoala2 小时前
Codex 小白入门:从安装到插件、MCP、Skills,一篇把配置讲明白
前端·javascript·后端
雪隐2 小时前
用Flutter做背单词APP-04一个人,2周,从零撸出一个背单词App
前端·人工智能·后端
web行路人3 小时前
Spring Boot 第四周:集成 Spring Security 与 JWT 鉴权实践
spring boot·后端·spring
用户298698530143 小时前
Python 实现 Excel 到 ODS、XPS、PostScript 及 PDF/A-1b 的格式转换
后端·python·excel
爱勇宝4 小时前
AI 时代,更稀缺的是「提出好问题」还是「判断好答案」?
前端·人工智能·后端
逝水无殇4 小时前
C# 正则表达式详解
开发语言·后端·正则表达式·c#