最近看到同事们在折腾新电脑环境,刚好趁着周末老设备磁盘空间告急(剩余不到 100G),顺手做了一次完整的 macOS 迁移与开发环境重建。

为了节约大家的时间,我尝试把整个过程整理成一套可复用、可迁移、可重建的初始化方案。希望能够让后续任何一台新 Mac,都可以在较短时间内恢复为完整开发环境,而不依赖记忆或零散操作。

写在前面

之前也零零碎碎写过一些 macOS 和开发环境配置,但都比较分散,缺乏统一结构。

这一次的目标是把 macOS 从“可用状态”提升为“开发机状态”,并建立一条完整的标准化路径,包括:基础系统、CLI 工具链、语言环境、SSH / GPG、包管理器、常用开发工具。

你可以当它是“安装软件清单”,但其实本质上应该是:一套简单的开发机环境的工程化重建方法论。

一台开发机,本质上是一组可控工具链的组合,而不应该是“手工配置的结果”。

设计原则

整个初始化过程遵循三个核心原则:

  • 可重建(Rebuildable):所有步骤都可以从零执行
  • 可迁移(Portable):环境可以跨机器复用
  • 可验证(Verifiable):每一步都有明确验证方式

多语言运行时环境统一(Go / Python / Node / Bun)

本文中涉及了四类工作中常见语言的环境配置。之所以大篇幅展开,是因为开发机真正进入“生产力层”的关键一步是:多语言运行时的版本管理与隔离。

这一层要解决的问题是:

  • 不同项目依赖不同 Node / Python / Go 版本冲突
  • PATH 污染导致命令覆盖
  • 全局依赖不可控
  • 环境在机器之间无法复现

因此,核心目标也非常明确:

每一种语言都必须具备“可切换、可回滚、可复现”的能力

当这一部分完成后,开发环境就可以变成一个“可切换系统”:

  • 每个项目拥有自己的 runtime
  • 不同版本不会互相污染
  • 环境随时可以重建
  • 本地开发与 CI/CD 保持一致

好了,接下来的所有步骤,都按照“从零恢复一台开发机”的顺序执行。

系统初始化和开发基础

macOS 初始化的第一步,是把系统变成“可开发状态”。

我们需要完成 Xcode CLI 工具的初始化:

xcode-select --install
sudo xcodebuild -license accept

当初始化完毕后,gitclang / gccmake / ld 这些后续所有工具链的基础就完备了。

HomeBrew

Homebrew 是 macOS 上最核心的开源包管理工具之一(项目地址Homebrew/brew),基于 BSD-2-Clause 协议。在HomeBrew 官网,我们能够找到它的安装命令:

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

如果网络较慢,可以考虑使用镜像源(比如:HomeBrew 阿里源HomeBrew 清华源),或者设置当前环境对一次性代理:

export https_proxy=http://127.0.0.1:1234

执行后,可以看到完整的安装流程日志:

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

==> Checking for `sudo` access (which may request your password)...
Password:
==> This script will install:
/opt/homebrew/bin/brew
/opt/homebrew/share/doc/homebrew
...
...
/opt/homebrew
/etc/paths.d/homebrew
==> The following new directories will be created:
/opt/homebrew/bin
/opt/homebrew/etc
...
...
/opt/homebrew/Caskroom
/opt/homebrew/Frameworks
==> The Xcode Command Line Tools will be installed.

Press RETURN/ENTER to continue or any other key to abort:
==> /usr/bin/sudo /usr/bin/install -d -o root -g wheel -m 0755 /opt/homebrew
==> /usr/bin/sudo /bin/mkdir -p /opt/homebrew/bin /opt/homebrew/etc /opt/homebrew/include /opt/homebrew/lib /opt/homebrew/sbin /opt/homebrew/share /opt/homebrew/var /opt/homebrew/opt /opt/homebrew/share/zsh /opt/homebrew/share/zsh/site-functions /opt/homebrew/var/homebrew /opt/homebrew/var/homebrew/linked /opt/homebrew/Cellar /opt/homebrew/Caskroom /opt/homebrew/Frameworks
...
...
==> Searching online for the Command Line Tools
==> /usr/bin/sudo /usr/bin/touch /tmp/.com.apple.dt.CommandLineTools.installondemand.in-progress
==> Installing Command Line Tools for Xcode 26.5-26.5
==> /usr/bin/sudo /usr/sbin/softwareupdate -i Command\ Line\ Tools\ for\ Xcode\ 26.5-26.5
Software Update Tool

Finding available software

Downloading Command Line Tools for Xcode 26.5
Downloaded Command Line Tools for Xcode 26.5
Installing Command Line Tools for Xcode 26.5
Done with Command Line Tools for Xcode 26.5
Done.
==> /usr/bin/sudo /usr/bin/xcode-select --switch /Library/Developer/CommandLineTools
==> /usr/bin/sudo /bin/rm -f /tmp/.com.apple.dt.CommandLineTools.installondemand.in-progress
==> Downloading and installing Homebrew...
remote: Enumerating objects: 341218, done.
remote: Counting objects: 100% (718/718), done.
remote: Compressing objects: 100% (358/358), done.
remote: Total 341218 (delta 531), reused 404 (delta 360), pack-reused 340500 (from 6)
remote: Enumerating objects: 55, done.
remote: Counting objects: 100% (33/33), done.
remote: Total 55 (delta 33), reused 33 (delta 33), pack-reused 22 (from 1)
==> /usr/bin/sudo /bin/mkdir -p /etc/paths.d
==> /usr/bin/sudo tee /etc/paths.d/homebrew
/opt/homebrew/bin
==> /usr/bin/sudo /usr/sbin/chown root:wheel /etc/paths.d/homebrew
==> /usr/bin/sudo /bin/chmod a+r /etc/paths.d/homebrew
==> Updating Homebrew...
==> Downloading https://ghcr.io/v2/homebrew/core/portable-ruby/blobs/sha256:4ba8d535df01e4bf97e6661c3815796fd77364ea2552606e891659133a76f0e1
################################################################################################################# 100.0%
==> Pouring portable-ruby-4.0.5_1.arm64_big_sur.bottle.tar.gz
==> Installation successful!

==> Homebrew has enabled anonymous aggregate formulae and cask analytics.
Read the analytics documentation (and how to opt-out) here:
  https://docs.brew.sh/Analytics
No analytics data has been sent yet (nor will any be during this install run).

==> Homebrew is run entirely by unpaid volunteers. Please consider donating:
  https://github.com/Homebrew/brew#donations

==> Next steps:
- Run these commands in your terminal to add Homebrew to your PATH:
    echo >> /Users/soulteary/.zprofile
    echo 'eval "$(/opt/homebrew/bin/brew shellenv zsh)"' >> /Users/soulteary/.zprofile
    eval "$(/opt/homebrew/bin/brew shellenv zsh)"
- Run brew help to get started
- Further documentation:
    https://docs.brew.sh

安装过程说明

执行安装后,会经历几个关键步骤:

首先是“权限检查”:

==> Checking for `sudo` access

Homebrew 会确认当前用户是否具备 sudo 权限。

然后是“目录初始化”,(Apple Silicon 默认安装路径是 /opt/homebrew,其他设备是 /usr/local):

/opt/homebrew/bin
/opt/homebrew/etc
/opt/homebrew/Cellar

接着是,“Xcode CLI 自动安装”:

Installing Command Line Tools for Xcode

Xcode CLI 提供了gitclangmakeld 等关键命令。

最后是 “Homebrew 核心下载”:

Downloading and installing Homebrew...

完成后,Homebrew 本体就可以开始初始化了。

核心环境变量配置

完成安装之后,我们执行下面的命令,就能够完成 brew 命令在系统中的注册了。

echo >> $HOME/.zprofile
echo 'eval "$(/opt/homebrew/bin/brew shellenv zsh)"' >> $HOME/.zprofile
eval "$(/opt/homebrew/bin/brew shellenv zsh)"

上面命令执行完毕,执行 brew 就能够看到它的“用法提示信息”了:

# brew

Example usage:
  brew search TEXT|/REGEX/
  brew info [FORMULA|CASK...]
  brew install FORMULA|CASK...
  brew update
  brew upgrade [FORMULA|CASK...]
  brew uninstall FORMULA|CASK...
  brew list [FORMULA|CASK...]

Troubleshooting:
  brew config
  brew doctor
  brew install --verbose --debug FORMULA|CASK

Contributing:
  brew create URL [--no-fetch]
  brew edit [FORMULA|CASK...]

Further help:
  brew commands
  brew help [COMMAND]
  man brew
  https://docs.brew.sh

如果输出了类似上面的 help 信息,则安装成功。

Oh My Zsh

Zsh 已经是 macOS 默认 shell,而 Oh My Zsh 是最流行的增强框架。这十年里,虽然有很多 Shell 方案,但如果说在开源软件中找一个最简单、用户量可能最多的方案,莫过于 ohmyzsh/ohmyzsh 了。

安装命令也一样很简单,一行命令:

sh -c "$(curl -fsSL https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh)"

命令执行后,等待命令执行完毕:

# sh -c "$(curl -fsSL https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh)"

Cloning Oh My Zsh...
remote: Enumerating objects: 1534, done.
remote: Counting objects: 100% (1534/1534), done.
remote: Compressing objects: 100% (1446/1446), done.
remote: Total 1534 (delta 85), reused 1411 (delta 58), pack-reused 0 (from 0)
Receiving objects: 100% (1534/1534), 3.33 MiB | 7.16 MiB/s, done.
Resolving deltas: 100% (85/85), done.
From https://github.com/ohmyzsh/ohmyzsh
 * [new branch]      copilot/fix-broken-theme-jonathan   -> origin/copilot/fix-broken-theme-jonathan
 * [new branch]      master                              -> origin/master
 * [new branch]      rr-13813-introduce-cooldown-feature -> origin/rr-13813-introduce-cooldown-feature
branch 'master' set up to track 'origin/master'.
Switched to a new branch 'master'
/Users/soulteary

Looking for an existing zsh config...
Using the Oh My Zsh template file and adding it to /Users/soulteary/.zshrc.

         __                                     __   
  ____  / /_     ____ ___  __  __   ____  _____/ /_  
 / __ \/ __ \   / __ `__ \/ / / /  /_  / / ___/ __ \ 
/ /_/ / / / /  / / / / / / /_/ /    / /_(__  ) / / / 
\____/_/ /_/  /_/ /_/ /_/\__, /    /___/____/_/ /_/  
                        /____/                       ....is now installed!


Before you scream Oh My Zsh! look over the `.zshrc` file to select plugins, themes, and options.

• Follow us on X: https://x.com/ohmyzsh
• Join our Discord community: https://discord.gg/ohmyzsh
• Get stickers, t-shirts, coffee mugs and more: https://commitgoods.com/collections/oh-my-zsh

执行后会自动完成:~/.oh-my-zsh 目录等创建,并创建~/.zshrc,确认将默认 shell 切换为 zsh,并初始化 git 插件支持。

安装自动补全插件

如果说有哪些插件是 Oh My Zsh 必备,体验提升最大的,自动补全绝对是之一。当我们完成本体的安装后,先执行命令,完成自动补全功能的的插件下载:

git clone https://github.com/zsh-users/zsh-autosuggestions ${ZSH_CUSTOM:-~/.oh-my-zsh/custom}/plugins/zsh-autosuggestions

等待命令执行完毕:

# git clone https://github.com/zsh-users/zsh-autosuggestions ${ZSH_CUSTOM:-~/.oh-my-zsh/custom}/plugins/zsh-autosuggestions

Cloning into '/Users/soulteary/.oh-my-zsh/custom/plugins/zsh-autosuggestions'...
remote: Enumerating objects: 2591, done.
remote: Counting objects: 100% (150/150), done.
remote: Compressing objects: 100% (64/64), done.
remote: Total 2591 (delta 124), reused 86 (delta 86), pack-reused 2441 (from 3)
Receiving objects: 100% (2591/2591), 596.14 KiB | 1.87 MiB/s, done.
Resolving deltas: 100% (1656/1656), done.

接着,我们编辑 .zshrc 配置,把自动补全功能激活。

末日配置中的内容是:

plugins=(git)

我们将它修改为下面的内容,然后保存文件。

plugins=(
git
zsh-autosuggestions
)

重新打开终端,上面的内容就都会生效了。

之后,我们在终端里输入命令的时,如果遇到了我们之前输入过的内容,便会提醒我们完整命令。

首先是,基于历史命令提示。当我们输入命令时会自动补全:

git c

会提示:

git commit

会出现基于历史记录的预测:

docker compose u

可能会直接提示:

docker compose up -d

这样子,重复输入的很多内容的成本就被一次次的输入命令的过程中被减少了。

GPG 与 RSA Key 的使用(Git 签名体系)

在开发过程中,我们通常使用 git 进行代码管理。为了确保提交内容的真实性与不可伪造性,可以使用 GPG 签名机制对 commit 和 tag 进行加密签名验证。

但其实,在现代开发环境中,身份体系通常是分裂的:

  • SSH:用于远程访问(Git / Server)
  • GPG:用于签名(Commit / Tag)
  • Git:只是调用外部工具

但如果不做统一设计,会出现三个问题:key 管理混乱、agent 多套冲突、commit / SSH 身份不一致。

整体签名体系结构

现代 Git + GPG 的签名流程如下:

# Git → GPG → gpg-agent → pinentry-mac

Git
 ├── commit/tag signing → GPG
 ├── SSH authentication → ssh-agent
 └── identity unification → gpg-agent (optional bridge)

这四个部分,分别负责:

  • Git:触发签名请求
  • GPG:执行签名/验证逻辑
  • gpg-agent:管理密钥与缓存
  • pinentry-mac:负责 macOS 图形化密码输入

在 macOS 环境中,我们可以使用 gpg-agent 作为主 agent,并托管 SSH。

安装 GPG 环境

使用我们刚刚安装好的 Homebrew,安装必要组件:

# gnupg:GPG 主程序
# pinentry-mac:macOS 图形密码输入器
brew install gnupg pinentry-mac

执行命令后,耐心等待:

# brew install gnupg pinentry-mac

✔︎ JSON API packages.arm64_tahoe.jws.json                                                     Downloaded   15.2MB/ 15.2MB
==> Would install 2 formulae:
gnupg pinentry-mac
==> Downloading https://ghcr.io/v2/homebrew/core/gnupg/manifests/2.5.20
################################################################################################################# 100.0%
==> Would install 17 dependencies for gnupg:
ca-certificates
gmp
libunistring
gettext
...
ou can now set this as your pinentry program like

~/.gnupg/gpg-agent.conf
    pinentry-program /opt/homebrew/bin/pinentry-mac
==> Summary
🍺  /opt/homebrew/Cellar/pinentry-mac/1.3.1.1: 20 files, 556KB
==> Running `brew cleanup pinentry-mac`...
==> Caveats
==> pinentry-mac
You can now set this as your pinentry program like

~/.gnupg/gpg-agent.conf
    pinentry-program /opt/homebrew/bin/pinentry-mac

安装完成后,Homebrew 会提示 pinentry 的使用方式,例如:

You can now set this as your pinentry program like

~/.gnupg/gpg-agent.conf
    pinentry-program /opt/homebrew/bin/pinentry-mac

我们有更好的方式。

初始化 GPG 配置

创建 GPG 配置目录并设置权限:

mkdir -p ~/.gnupg

写入 gpg-agent 配置:

cat <<EOF > ~/.gnupg/gpg-agent.conf
pinentry-program /opt/homebrew/bin/pinentry-mac
enable-ssh-support
EOF

设置文件和目录正确的权限:

find ~/.gnupg -type d -exec chmod 700 {} \;
find ~/.gnupg -type f -exec chmod 600 {} \;

配置 shell 环境(zsh)

接着,我们在 .zshrc 中添加配置:

# GPG
export GPG_TTY=$(tty)
# 让 pinentry 使用 macOS GUI,避免卡输入
export PINENTRY_USER_DATA="USE_TTY=1"
# 在 shell 中启动 agent
gpgconf --launch gpg-agent
# SSH 通过 gpg-agent 统一管理
export SSH_AUTH_SOCK=$(gpgconf --list-dirs agent-ssh-socket)

SSH Key 管理

当上面的信息完成后,我们可以使用 ssh-add 来添加我们的 RSA Key。(SSH Key 与 GPG Key 是两套体系,这里仅作为扩展说明)

ssh-add ~/.ssh/key-1
ssh-add ~/.ssh/key-2

使用 ssh-add -l 可以查看 Key 的加载情况:

ssh-add -l

根据我们添加的 Key 的实际情况,可能可以看到类似下面的内容:

3072 SHA256:123456+123456 key-1 (RSA)
2048 SHA256:234567/345678+1234/123 key-2 (RSA)

导入 GPG Key

导入已有 key:

gpg --import ~/mykey.asc

根据导入的 key 的情况,可能得到类似下面的结果:

gpg: /Users/soulteary/.gnupg/trustdb.gpg:建立了信任度数据库
gpg: 密钥 DBCDD8CBF440F8DE:公钥 “Su Yang <soulteary@gmail.com>” 已导入
gpg: 密钥 DBCDD8CBF440F8DE:私钥已导入
gpg: 处理的总数:1
gpg:               已导入:1
gpg:       读取的私钥:1
gpg:   导入的私钥:1

检查 GPG Key 状态

接下来,我们可以使用命令检查导入的 Key 的信息:

gpg --list-secret-keys --keyid-format LONG

输出示例:

/Users/soulteary/.gnupg/pubring.kbx
-----------------------------------
sec   rsa4096/DBCDD8CBF440F8DE 2023-10-11 [SC]
      CD85ED7465AFF2FFA2FFB686DBCDD8CBF440F8DE
uid                   [ 未知 ] Su Yang <soulteary@gmail.com>

sec 表示该 key 具备可用于签名的私钥,在使用的时候,我们通常使用 rsa4096/... 后面的短 key ID,而最下面的一长串 fingerprint 是这个 Key 的唯一标识 key。

导出公钥(用于 GitHub / Gitea 等平台)

我们也可以通过命令,查询公钥,将公钥内容绑定到想要使用的系统平台里:

gpg --armor --export DBCDD8CBF440F8DE

输出结果类似:

-BEGIN PGP PUBLIC KEY BLOCK-----

mQINBGUmIH0BEAC6/bQb7Tb8nvLJhmJSnFfeAPahLlYtN462q7ukvbUi8LShhEK4
G1qAnQDgNedfH4Jn77DNGpHaPFaEjNvtqP76q0/Q33iV9MV6dfZMMy2txIoKny3f
PQJwSidmRCC0Hl0ntKUqEyyTgbAirLYKZ132c5NCp+AEk9J/07Ig1igAOMoFaAxK
B2/
...
wKESEp25n0CiBrBMtDWgQVR3OO10X0oI5nuSM2gh1PxN7LFALyXu
IZd9qjg+wN9wD81x1bFCnTJbQ7dILi5ukJzf36X1Q6VqT8XTbEs3V/ZDWICCSfqJ
fpK6Q1kCbrUl++6kE4tTCca1amMvGTZFa6xpeBMKxgLncXBa9N/F8pppqX5PiLhX
8rs+DBsOTB0yKwYnquCYymW4Wjv5BPMYf35tm0s1OGNDRtZczQFjKX0gMVtz5+1+
9pzZ
=etbA
-----END PGP PUBLIC KEY BLOCK-----

配置 Git 使用 GPG 签名

想要使用 GPG 签名,我们首先要进行 Git 的基础设置:

git config --global user.name "Your Name"
git config --global user.email "you@example.com"

然后,开启签名功能:

git config --global commit.gpgsign true
git config --global tag.gpgsign true
git config --global gpg.program gpg
git config --global gpg.format openpgp

最后,设置签名 key:

# git config --global user.signingkey <KEYID>
git config --global user.signingkey DBCDD8CBF440F8DE

因为不同的GPG 版本下fingerprint(CD85ED7...)解析可能有差异,所以建议我们使用短 ID (DBCDD8CB...) 。

创建测试仓库验证签名

让我们来验证上面的配置是否正确:

# 创建一个测试目录,并切换工作目录
mkdir git-commit-test                                                         
cd git-commit-test 
# 初始化 git 仓库
git init
# 随便创建一个文件
touch abc
# 将刚刚的文件添加到待提交列表里
git add .    

然后,使用 git commit -S 进行带签名的记录提交:

git commit -S -m "test signed commit"

执行成功,输出示例:

[main (root-commit) 0070f81] test signed commit
 1 file changed, 0 insertions(+), 0 deletions(-)
 create mode 100644 abc

验证签名是否正确

提交完毕,可以使用 git log 来检查是否正确进行签名:

git log --show-signature -1

输出示例:

commit 0070f8104cf00f42fb86bf5bc9dbd935c147a494 (HEAD -> main)
gpg: 签名建立于 日  6月/14 17:31:40 2026 CST
gpg:               使用 RSA 密钥 CD85ED7465AFF2FFA2FFB686DBCDD8CBF440F8DE
gpg: 完好的签名,来自于 “Su Yang <soulteary@gmail.com>” [未知]
gpg: 警告:此密钥未被受信任签名认证!
gpg:       没有证据表明此签名属于其声称的所有者。
      CD85ED7465AFF2FFA2FFB686DBCDD8CBF440F8DE
Author: Su Yang <soulteary@gmail.com>
Date:   Sun Jun 14 17:31:40 2026 +0800

    test signed commit

从上面的日志中,我们可以看到签名是有效的:“完整的签名”,没有“篡改”提醒。信息中的警告是因为本机尚未建立对该 GPG key 的信任链,不是签名错误。

常见问题

这里将常见问题也进行总结,应该能够节约很多折腾的同学的时间。

最常见的问题是,因为gpg-agent 未正确加载,pinentry 可能不弹窗。解决方法是重新启动 agent 程序:

gpgconf --kill gpg-agent
gpgconf --launch gpg-agent

然后,可能出现的问题是:git 找不到 gpg。我们可以使用命令来定位程序:

which gpg

确保在 /opt/homebrew/bin/gpg 路径中有程序,或目录被加入到了可被 shell 检索到的环境变量中。

Go 环境(GVM)

我之前曾写过几篇相关的内容:《搭建可维护的 Golang 开发环境》、《M1 芯片 Mac 上更好的 Golang 使用方案》、《Golang 多版本管理》。

这几年用下来,个人体感,还是在 2022 年,我做过修正的 GVM 版本最好用。项目开源地址是:soulteary/gvm。Go 的配置和使用,我们有三个核心原则,不污染系统环境、每个版本独立安装,GO PROXY 单独设置。

安装很简单,也是一条命令:

curl -sSL https://github.com/soulteary/gvm/raw/master/binscripts/gvm-installer | bash

安装成功能够看到下面的日志:

Cloning from https://github.com/soulteary/gvm.git to /Users/soulteary/.gvm
No existing Go versions detected
Installed GVM v1.0.24

Please restart your terminal session or to get started right away run
 `source /Users/soulteary/.gvm/scripts/gvm`

我们在 ~/.zshrc 中添加下面的配置:

# Golang & GVM
export GOPROXY="https://goproxy.cn"
export GO_BINARY_BASE_URL=https://golang.google.cn/dl/
[[ -s "$HOME/.gvm/scripts/gvm" ]] && source "$HOME/.gvm/scripts/gvm"
export GOROOT_BOOTSTRAP=$GOROOT

然后重新打开终端,就能够在环境中使用 gvm 命令了:

# gvm

Usage: gvm [command]

Description:
  GVM is the Go Version Manager

Commands:
  version    - print the gvm version number
  get        - gets the latest code (for debugging)
  use        - select a go version to use (--default to set permanently)
  diff       - view changes to Go root
  help       - display this usage text
  implode    - completely remove gvm
  install    - install go versions
  uninstall  - uninstall go versions
  cross      - install go cross compilers
  linkthis   - link this directory into GOPATH
  list       - list installed go versions
  listall    - list available versions
  alias      - manage go version aliases
  pkgset     - manage go packages sets
  pkgenv     - edit the environment for a package set

安装和使用指定 Golang 版本

如果我们想使用 gvm 来安装最新版本的 go 程序,可以先通过 gvm listall 来获取官方所有发行版:

# gvm listall

gvm gos (available)

   go1
   go1.0.1
   go1.0.2
...
   go1.26.0
   go1.26.1
   go1.26.2
   go1.26.3
   go1.26.4
...

在列表中找到当前最新的版本,比如 go1.26.4,然后使用 gvm install 命令,搭配 -B 参数,快速下载官方预构建好的版本:

# gvm install go1.26.4 -B

Installing go1.26.4 from binary source

完成下载后,我们使用 gvm use 命令,配合 --default 参数,完成默认版本的设置:

gvm use go1.26.4 --default
Now using version go1.26.4

上面的命令执行完毕后,我们就可以正常使用 go 命令了,比如使用 go version 查看下我们安装的 go 运行时是否正确:

# go version

go version go1.26.4 darwin/arm64

Python 环境

Python 的使用,我们设置三个原则:

  1. 不使用系统 Python
  2. 不使用 pip global install
  3. 所有依赖必须在 env 中隔离

这里推荐使用 Miniforge,基于 BSD-3 协议的轻量 Conda 分发版。开源项目地址:conda-forge/miniforge

我们通过一条命令完成工具的下载:

curl -L -O "https://github.com/conda-forge/miniforge/releases/latest/download/Miniforge3-$(uname)-$(uname -m).sh"

安装文件不大,大概 50MB 左右:

% Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
  0     0    0     0    0     0      0      0 --:--:-- --:--:-- --:--:--     0
  0     0    0     0    0     0      0      0 --:--:--  0:00:01 --:--:--     0
100 50.9M  100 50.9M    0     0  10.4M      0  0:00:04  0:00:04 --:--:-- 17.0M

然后使用 bash 命令搭配 -b 参数完成安装:

bash Miniforge3-$(uname)-$(uname -m).sh -b

等待命令执行完毕:

# bash Miniforge3-$(uname)-$(uname -m).sh -b
PREFIX=/Users/soulteary/miniforge3
Unpacking bootstrapper...
Unpacking payload...
Extracting bzip2-1.0.8-hd037594_9.conda
Extracting c-ares-1.34.6-hc919400_0.conda
Extracting ca-certificates-2026.5.20-hbd8a1cb_0.conda
Extracting libcxx-22.1.6-h55c6f16_0.conda
Extracting libev-4.33-h93a5062_2.conda
Extracting libexpat-2.8.1-hf6b4638_0.conda
Extracting libffi-3.5.2-hcf2aa1b_0.conda
Extracting libiconv-1.18-h23cfdf5_2.conda
Extracting liblzma-5.8.3-h8088a28_0.conda
Extracting libmpdec-4.0.0-h84a0fba_1.conda
Extracting libzlib-1.3.2-h8088a28_2.conda
...
Installing base environment...

Transaction

  Prefix: /Users/soulteary/miniforge3

  Updating specs:

   - bzip2==1.0.8=hd037594_9
   - c-ares==1.34.6=hc919400_0
   - ca-certificates==2026.5.20=hbd8a1cb_0
   - libcxx==22.1.6=h55c6f16_0
   - libev==4.33=h93a5062_2
   - libexpat==2.8.1=hf6b4638_0
...
   - conda-package-handling==2.4.0=pyh7900ff3_2
   - conda==26.3.2=py313h8f79df9_1


  Package                         Version  Build               Channel         Size
─────────────────────────────────────────────────────────────────────────────────────
  Install:
─────────────────────────────────────────────────────────────────────────────────────

  + archspec                        0.2.5  pyhd8ed1ab_0        conda-forge         
  + backports.zstd                  1.5.0  py313h7208f8c_0     conda-forge         
  + boltons                        25.0.0  pyhd8ed1ab_0        conda-forge         
  + brotli-python                   1.2.0  py313hde1f3bb_1     conda-forge         
  + bzip2                           1.0.8  hd037594_9          conda-forge         
  + c-ares                         1.34.6  hc919400_0          conda-forge         
...
  + zstandard                      0.25.0  py313h9734d34_1     conda-forge         
  + zstd                            1.5.7  hbf9d68e_6          conda-forge         

  Summary:

  Install: 80 packages

  Total download: 0 B

─────────────────────────────────────────────────────────────────────────────────────



Transaction starting
Linking bzip2-1.0.8-hd037594_9
Linking c-ares-1.34.6-hc919400_0
Linking ca-certificates-2026.5.20-hbd8a1cb_0
...
Linking requests-2.34.2-pyhcf101f3_0
Linking conda-libmamba-solver-26.4.2-pyhd8ed1ab_0
Linking conda-package-handling-2.4.0-pyh7900ff3_2
Linking conda-26.3.2-py313h8f79df9_1

Transaction finished

在完成安装之后,我们将下面的配置添加到 ~/.zshrc 中:

# Python
[ -f "$HOME/miniforge3/etc/profile.d/conda.sh" ] && \. "$HOME/miniforge3/etc/profile.d/conda.sh"
export PATH="$HOME/miniforge3/bin:$PATH"

我们执行 ~/miniforge3/bin/conda init完成项目的第一次初始化:

# ~/miniforge3/bin/conda init

no change     /Users/soulteary/miniforge3/condabin/conda
no change     /Users/soulteary/miniforge3/bin/conda
no change     /Users/soulteary/miniforge3/bin/activate
no change     /Users/soulteary/miniforge3/bin/deactivate
no change     /Users/soulteary/miniforge3/etc/profile.d/conda.sh
no change     /Users/soulteary/miniforge3/etc/fish/conf.d/conda.fish
no change     /Users/soulteary/miniforge3/shell/condabin/Conda.psm1
no change     /Users/soulteary/miniforge3/shell/condabin/conda-hook.ps1
no change     /Users/soulteary/miniforge3/lib/python3.13/site-packages/xontrib/conda.xsh
no change     /Users/soulteary/miniforge3/etc/profile.d/conda.csh
modified      /Users/soulteary/.bash_profile

==> For changes to take effect, close and re-open your current shell. <==

重新打开终端后,我们就能够正常使用熟悉的 conda 命令啦。

# conda

usage: conda [-h] [-v] [--no-plugins] [-V] COMMAND ...

conda is a tool for managing and deploying applications, environments and packages.

options:
  -h, --help            Show this help message and exit.
  -v, --verbose         Can be used multiple times. Once for detailed output, twice for INFO logging, thrice for DEBUG
                        logging, four times for TRACE logging.
  --no-plugins          Disable all plugins that are not built into conda.
  -V, --version         Show the conda version number and exit.

commands:
  The following built-in and plugins subcommands are available.

  COMMAND
    activate            Activate a conda environment.
    check               Display a health report for your environment (alias for doctor).
    clean               Remove unused packages and caches.
    commands            List all available conda subcommands (including those from plugins). Generally only used by
                        tab-completion.
    compare             Compare packages between conda environments.
    config              Modify configuration values in .condarc.
    create              Create a new conda environment from a list of specified packages.
    deactivate          Deactivate the current active conda environment.
    doctor              Display a health report for your environment.
    env                 Create and manage conda environments.
    export              Export a given environment
    info                Display information about current conda install.
    init                Initialize conda for shell interaction.
    install             Install a list of packages into a specified conda environment.
    list                List installed packages in a conda environment.
    menuinst            A subcommand for installing and removing shortcuts via menuinst.
    notices             Retrieve latest channel notifications.
    package             Create low-level conda packages. (EXPERIMENTAL)
    remove (uninstall)  Remove a list of packages from a specified conda environment.
    rename              Rename an existing environment.
    repoquery           Advanced search for repodata.
    run                 Run an executable in a conda environment.
    search              Search for packages and display associated information using the MatchSpec format.
    update (upgrade)    Update conda packages to the latest compatible version.

验证和使用

过去有一些文章提到过 conda 命令的使用,如果你感兴趣可以翻阅:《在搭载 M1 及 M2 芯片 MacBook设备上玩 Stable Diffusion 模型》、《用让新海诚本人惊讶的 AI 模型制作属于你的动漫视频》、《向量数据库入坑指南:聊聊来自元宇宙大厂 Meta 的相似度检索技术 Faiss》。

Node.js 环境

我们使用开源项目 nvm 来管理 Node.js 版本:nvm-sh/nvm。过去的十年里,这个项目非常稳定,在许多互联网公司里也承担过各种 CI 构建过程中的顶梁柱的角色。

关于 Node.js 环境同样约定三个原则:

  1. 不使用系统环境中的 Node(包括 brew 安装的)
  2. 所有版本由 nvm 控制
  3. npm 全局安装仅用于 CLI 工具

同样是一句命令完成安装:

curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.5/install.sh | bash

耐心等待完成安装:

#curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.5/install.sh | bash

  % Total    % Received % Xferd  Average Speed   Time    Time     Time  Current
                                 Dload  Upload   Total   Spent    Left  Speed
100 17051  100 17051    0     0  25641      0 --:--:-- --:--:-- --:--:-- 25640
=> Downloading nvm from git to '/Users/soulteary/.nvm'
=> Cloning into '/Users/soulteary/.nvm'...
remote: Enumerating objects: 432, done.
remote: Counting objects: 100% (432/432), done.
remote: Compressing objects: 100% (359/359), done.
remote: Total 432 (delta 61), reused 192 (delta 45), pack-reused 0 (from 0)
Receiving objects: 100% (432/432), 418.80 KiB | 1.12 MiB/s, done.
Resolving deltas: 100% (61/61), done.
* (HEAD detached at FETCH_HEAD)
  master
=> Compressing and cleaning up git repository

=> Appending nvm source string to /Users/soulteary/.zshrc
=> Appending bash_completion source string to /Users/soulteary/.zshrc
=> Close and reopen your terminal to start using nvm or run the following to use it now:

export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"  # This loads nvm
[ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion"  # This loads nvm bash_completion

上面的日志提醒我们要在 ~/.zshrc 中添加配置信息,其实在执行完毕后,nvm 会帮助我们自动添加一部分内容:

# Node.js
export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"  # This loads nvm
[ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion"  # This loads nvm bash_completion

我们可以手动额外添加一句配置,让后续的使用更丝滑:

# 额外添加,加速下载
export NVM_NODEJS_ORG_MIRROR=https://mirrors.tuna.tsinghua.edu.cn/nodejs-release/

安装和使用

当我们完成 nvm 的安装后,可以使用 nvm ls-remote 命令,来获取所有的 Node 可用版本:

# nvm ls-remote

        v0.1.14
        v0.1.15
        v0.1.16
        v0.1.17
...
       v22.16.0   (Latest LTS: Jod)
...
        v24.1.0

这里我们以安装最新的 LTS 版本(列表中的 v22.6.0)为例。

使用 install 命令,搭配具体版本号:

# nvm install v22.16.0

Downloading and installing node v22.16.0...
Downloading https://mirrors.tuna.tsinghua.edu.cn/nodejs-release//v22.16.0/node-v22.16.0-darwin-arm64.tar.xz...
################################################################################################################# 100.0%
Computing checksum with sha256sum
Checksums matched!
Now using node v22.16.0 (npm v10.9.2)
Creating default alias: default -> v22.16.0 *

如果你只有一个版本,程序会自动帮助你将这个版本设置为全局默认版本。但当你如果下载了更多的版本,想进行版本切换的时候,需要牢记下面的两个命令:

# nvm use 22.16.0 

Now using node v22.16.0 (npm v10.9.2)

# nvm alias default 22.16.0

default -> 22.16.0 (-> v22.16.0)

想要切换全局版本,首先要使用 nvm use 切换具体版本,然后要使用 nvm alias default 来变更全局默认版本。

命令执行完毕后,我们可以检查 Node 版本是否符合预期:

# node -v

v22.16.0

Bun(更现代的 JS Runtime)

作为更现代的 JS Runtime,Bun 提供了四个主要能力:runtime、package manager、bundler、test runner。

我们还是可以通过一行命令,完成安装:

curl -fsSL https://bun.sh/install | bash

安装速度通常非常快:

######################################################################## 100.0%
bun was installed successfully to ~/.bun/bin/bun 

Added "~/.bun/bin" to $PATH in "~/.zshrc" 

To get started, run: 

  exec /bin/zsh 
  bun --help 

完成安装之后,我们同样在 ~/.zshrc 中添加配置:

# bun completions
[ -s "/Users/soulteary/.bun/_bun" ] && source "/Users/soulteary/.bun/_bun"

# bun
export BUN_INSTALL="$HOME/.bun"
export PATH="$BUN_INSTALL/bin:$PATH"

重新打开终端后,我们就可以使用 bun 命令啦:

# bun

Bun is a fast JavaScript runtime, package manager, bundler, and test runner. (1.3.14+0d9b296af)

Usage: bun <command> [...flags] [...args]

Commands:
  run       ./my-script.ts       Execute a file with Bun
            lint                 Run a package.json script
  test                           Run unit tests with Bun
  x         next                 Execute a package binary (CLI), installing if needed (bunx)
  repl                           Start a REPL session with Bun
  exec                           Run a shell script directly with Bun

  install                        Install dependencies for a package.json (bun i)
  add       @remix-run/dev       Add a dependency to package.json (bun a)
  remove    babel-core           Remove a dependency from package.json (bun rm)
  update    @evan/duckdb         Update outdated dependencies
  audit                          Check installed packages for vulnerabilities
  outdated                       Display latest versions of outdated dependencies
  link      [<package>]          Register or link a local npm package
  unlink                         Unregister a local npm package
  publish                        Publish a package to the npm registry
  patch <pkg>                    Prepare a package for patching
  pm <subcommand>                Additional package management utilities
  info      @zarfjs/zarf         Display package metadata from the registry
  why       zod                  Explain why a package is installed

  build     ./a.ts ./b.jsx       Bundle TypeScript & JavaScript into a single file

  init                           Start an empty Bun project from a built-in template
  create    elysia               Create a new project from a template (bun c)
  upgrade                        Upgrade to latest version of Bun.
  feedback  ./file1 ./file2      Provide feedback to the Bun team.

  <command> --help               Print help text for command.

Learn more about Bun:            https://bun.com/docs
Join our Discord community:      https://bun.com/discord

其他:macOS 开发机初始化的其他流程

当在完成系统工具链、Shell、安全体系以及多语言运行时之后,整个开发机其实已经具备了“可用状态”。

不过,通常一台新设备到手,为了使用起来更安心,我通常还会做下面的一些动作:

  1. 检查/更新系统版本,确认已经到最新版本。
  2. 登录合适的 Apple 账号,完成 iCloud 的必要信息同步。
  3. 可能设置一些鼠标、触摸板拖动、手势相关的配置,让每次操作都更省力。
  4. 把常用的 macOS 先都打开一遍,让 iCloud 能够完成必要的信息同步,而不是先使用,可能造成数据冲突。
  5. 过程中,可以移除掉不用的 Dock 栏软件,让常驻软件图标更顺手,以及为当前设备改个共享名称。
  6. 如果你需要更新和同步相册数据,这时可以打开图片软件,挂在后台进行持续更新。
  7. 当基础软件信息都同步完毕之后,我们可以开始从 Apple App Store 中下载常用的软件,这类软件通常叫做受限的 MAS 软件,对系统的影响和损害可能性是最低的,因为会被限制在 Apple 沙盒环境中。
  8. 接下来,我们需要完成 xcode 软件的下载,以及初始化好 git 软件(初始化 xcode 命令行 sudo xcodebuild -license)。
  9. 当上面的内容都就绪后,我们可以开始下载非 Mac 和App Store 之外的软件了,我通常会完成 Chrome 、Little Snitch、VSCode(Cursor)、Localsend 等软件等安装。
  10. 最后就是类似本文的配置,跨设备数据同步,包括微信记录同步等工作啦。

最后

希望看到这里的你的设备,目前的状况已经是一台“可重建的开发系统”啦。

—EOF