一行命令,把一台空 macOS 装成趁手的开发机。
36node/dotfiles 是一套面向 macOS 开发者的环境初始化方案。从全新系统到一台
「装着趁手工具、终端美观、Finder 干净、各种语言版本管理就绪、敏感凭据自动跨机同步」
的开发机,一条命令搞定,反复执行不出错。
不同于市面常见 dotfiles,本仓库优先选用 2024–2026 年仍在快速迭代的现代化轻量栈, 而不是十年来惯性沿用的老组合。
适合:
- 频繁换 Mac、或团队/新人 onboarding 想要一致开发环境
- 国内(或国内出海)开发者 —— 默认就装阿里云 CLI、飞书、微信
- 想读得懂自己装了什么的人 —— 核心就是一个
install.sh加几个lib/函数,全是带注释的 bash
- 模块化 ——
packages/下每个目录是一个独立 package,主脚本自动遍历,互不依赖 - 幂等 —— 所有写入走
append/link_file,反复跑不会副作用堆叠 - 现代化 —— 见下方"技术栈",全部 2026 年仍活跃维护的项目
- 可读 —— 主
install.sh从上往下顺序执行、注释比代码多,每个 package 自带 README,没有黑魔法 - 跨机同步敏感凭据 ——
.env/~/.ssh通过 vault + 软链方案自动同步,默认走 iCloud Drive,可换 Dropbox / Syncthing / 任意目录 - macOS 系统调优 —— Finder / Dock / 键盘 / 截图路径等开箱即用,每条注释完整
| 角色 | 选用 | 旧时代做法 |
|---|---|---|
| 终端 | ghostty | iTerm2 / Terminal.app |
| Shell 插件管理 | antidote | oh-my-zsh |
| Prompt | starship (tokyo-night) | powerlevel10k |
| Node 版本管理 | fnm | nvm |
| Node 包管理 | corepack (pnpm / yarn) | 全局 npm install |
| Python | pyenv + 3.14 | system python |
| 编辑器 | LazyVim (neovim) | 自配 .vimrc |
| 字体 | JetBrains Mono Nerd Font | — |
| 容器/编排 | docker + kubernetes-cli + kubectx + helm + k9s | — |
| 国内云 | aliyun-cli | — |
| 通用 CLI | 见下方「命令行工具速查」 | — |
下面是仓库里装的主要 CLI 工具,按主题分组,每个工具都附了官方仓库/文档链接。
完整清单以根目录 Brewfile 和各 packages/<name>/Brewfile 为准(见「软件清单:Brewfile」)。
| 工具 | 功能 |
|---|---|
| yazi | TUI 文件管理器,原生预览图片/视频/PDF(依赖 ffmpeg/imagemagick/poppler/sevenzip) |
| eza | ls 替代:彩色 + git 状态 + tree 模式 |
| fd | find 替代:更快、默认忽略 .git 和 .gitignore |
| zoxide | cd 替代:按访问历史智能跳转,输入 z foo 直达;zi 走 fzf 交互式选 |
| tree | 经典目录树 |
| 工具 | 功能 |
|---|---|
ripgrep (rg) |
grep 替代,超快 |
| fzf | 模糊查找器,被 zoxide / yazi / zsh 历史搜索等多处依赖 |
| bat | cat 替代:语法高亮 + 行号 + git diff |
| jless | TUI JSON viewer,搭配 jq 用:jq 处理、jless 浏览 |
| glow | 终端里渲染 markdown,看 README 不用切到 IDE |
| 工具 | 功能 |
|---|---|
bottom (btm) |
top / htop 替代,跨平台 Rust 实现 |
| mactop | macOS 专用,显示 Apple Silicon CPU/GPU 频率 + 能耗 |
| procs | ps 替代,彩色更易读 |
| dust | du 替代,树形可视化谁占硬盘 |
| duf | df 替代,彩色磁盘容量表 |
| 工具 | 功能 |
|---|---|
| git | 当然是 git |
| gh | GitHub 官方 CLI(gh pr、gh issue 等) |
| lazygit | Git TUI,键盘流操作 |
| delta | git diff 美化 pager(install.sh 已自动注册到 ~/.gitconfig) |
| git-lfs | Git 大文件存储 |
| actionlint | GitHub Actions workflow 静态检查 |
| 工具 | 功能 |
|---|---|
| kubectl | k8s 官方 CLI(包名 kubernetes-cli) |
| kubectx / kubens | 快速切换 context / namespace |
| kubecolor | 给 kubectl 输出着色 |
| helm | k8s 包管理器(PATH 上是 helm@3;helm 4 装着但不链接) |
| k9s | k8s TUI 管理工具 |
| k3sup | 一键部署 k3s 到任何机器 |
| docker / docker-compose | docker CLI 和 compose 插件(CLI-only,跟 OrbStack 共存时会有 PATH 优先级冲突,详见 packages/DevOps/Brewfile 注释) |
| lazydocker | Docker TUI,lazygit 同作者 |
| skopeo | 不拉镜像直接查看 / 复制远端镜像 |
| 工具 | 功能 |
|---|---|
| libpq | psql 等 Postgres 客户端(keg-only,Brewfile 里强制链接进 PATH) |
| redis | Redis 服务端与 redis-cli |
| mosquitto | MQTT broker,附带 mosquitto_pub / mosquitto_sub |
| 工具 | 功能 |
|---|---|
| autossh | SSH 隧道断线自动重连,配合 ~/.ssh/config 的 LocalForward 用 |
| xh | curl / httpie 替代,语法极简 |
| wget | 经典下载器 |
| iperf3 | 网络带宽测试 |
| telnet | 测端口连通性 |
| ngrok | 内网穿透(cask) |
| 工具 | 功能 |
|---|---|
| jq | JSON 流处理(标杆工具) |
| yq | jq 的 YAML 版,也能处理 JSON / XML |
| sd | sed 替代,语法直观 |
| tokei | 代码行数统计 |
| 工具 | 功能 |
|---|---|
| ffmpeg | 音视频处理,yazi 视频预览也用它 |
| imagemagick | 图片格式转换,yazi 图片预览也用它 |
| poppler | PDF 处理(提供 pdftotext / pdftoppm),yazi PDF 预览依赖 |
| librsvg | 提供 rsvg-convert,SVG 转 PNG / PDF |
sevenzip (7zz) |
7z 压缩格式,yazi 压缩档预览依赖 |
| 工具 | 功能 |
|---|---|
| tmux | 终端复用 |
| antidote | zsh 插件管理器(替代 oh-my-zsh) |
| starship | 跨 shell 的 prompt |
| direnv | 进入目录自动加载 .envrc,per-project 环境变量(首次 direnv allow 授权) |
| gum | 写交互式 shell 脚本的 UI 组件库 |
| 工具 | 功能 |
|---|---|
| claude-code | Anthropic 的终端 AI 编码助手(cask 分发,但本质是 CLI) |
| codex | OpenAI 的终端 coding agent(cask 分发,本质 CLI) |
| antigravity-cli | Google Antigravity 终端 agent(gemini-cli 的官方替代,cask) |
| 工具 | 功能 |
|---|---|
| aliyun-cli | 阿里云 CLI |
| gcloud-cli | Google Cloud CLI(cask) |
| ansible | 配置管理与自动化 |
| 工具 | 功能 |
|---|---|
| cmake / ninja | C/C++ 构建 |
| emscripten | C/C++ 编译到 WebAssembly |
| dfu-util | USB DFU 固件烧录 |
| 工具 | 功能 |
|---|---|
| go | Go 编译器(直接装稳定版,需要多版本切换可改用 goenv) |
| neovim | 现代 vim,搭配 LazyVim starter 一起装 |
| ruby | macOS 自带 ruby 太老,brew 装新版(CocoaPods、mas 等工具链需要) |
| biome | JS / TS 格式化 + lint(packages/node) |
| xcodegen | 用 YAML 生成 .xcodeproj(packages/xcode) |
| 工具 | 功能 |
|---|---|
| fnm | Node 版本管理(nvm 替代,Rust 实现) |
| pyenv | Python 版本管理 |
| mas | Mac App Store CLI(Brewfile 里的 mas 条目靠它安装) |
仓库装的 macOS 桌面应用(完整清单见各 Brewfile):
| 工具 | 功能 |
|---|---|
| ghostty | 现代终端模拟器,GPU 加速 |
| VS Code / Zed | 编辑器 |
| Figma | 设计 |
| GitHub Desktop | GitHub 图形客户端 |
| Postman | API 测试 |
| Google Chrome | 浏览器 |
| OrbStack | Docker Desktop 的轻量替代,启动快、省内存、原生 Apple Silicon;同时能跑 Linux VM |
| Redis Insight | Redis GUI(packages/DevOps) |
| ChatGPT / Claude / 豆包 | AI 桌面应用(ChatGPT 同时也是 Codex 桌面版) |
| Open Design | 本地优先的 AI 设计工具 |
| Clash Verge Rev | 代理客户端 |
| balenaEtcher | 烧录系统镜像到 U 盘 / SD 卡 |
| KeyClu | 长按 Cmd 显示当前 app 的快捷键 |
| Mos | 鼠标滚动平滑、反向 |
| MonitorControl | 用键盘控制外接显示器亮度 / 音量(macOS 自身不支持非 Apple 屏) |
| 飞书 / 微信 / 钉钉 / QQ / 腾讯会议 / 网易邮箱大师 | 国内通讯与办公 |
| Nerd Fonts(JetBrains Mono / Fira)+ Noto CJK | 终端字体与中文字体(packages/terminal) |
| Xcode / TestFlight / Developer | iOS / macOS 开发,经 App Store(mas)安装(packages/xcode,十几 GB,不需要就在 install.conf 里去掉) |
| ZeroTier | 虚拟局域网,免开 VPN 跨机直连(packages/zerotier,shell 里用 zero start/stop/restart/info) |
Brewfile.extra 里的可选项(默认询问后才装,可通过 install.conf 自动跳过/强装):
| 工具 | 功能 |
|---|---|
| Cursor | AI 代码编辑器 |
| cmux | 基于 Ghostty 的终端,竖排标签 |
| IINA | macOS 原生视频播放器 |
| Paper | 自动壁纸 |
| QQ 音乐 / 腾讯视频 | 影音 |
| Dropbox | 云盘 |
| Speedtest | 网速测试(App Store,需要先登录) |
# 1. clone 仓库
git clone git@github.com:36node/dotfiles.git ~/.dotfiles
cd ~/.dotfiles
# 2. 准备 .env(首次新建可从模板开始;多机用户参见下文「跨机同步:vault 设计」)
cp .env.example .env
# 3.(可选)想换 vault 后端就 export,不写默认走 iCloud Drive
# export DOTFILES_VAULT="$HOME/Dropbox/.dotfiles"
# 4. 一键安装(需要 sudo 密码)
./install.sh
# 也可以只装单个 package(跳过系统引导和根 Brewfile),例如:
./install.sh codexinstall.sh 跑完会做:
- 安装 Xcode Command Line Tools 和 Homebrew
- 按根目录
Brewfile装基础软件(git、gh、VS Code、Chrome、飞书等) - 遍历
packages/,逐个先装该 package 的Brewfile,再执行它的install.sh(做配置) - 询问是否安装
Brewfile.extra(你的个人选装清单) - 把根
source.zsh注入~/.zshrc
可重复执行,已装的会跳过。
./install.sh # 完整安装(按 install.conf;缺失则装全部 + 询问 extra)
./install.sh <package> # 仅装单个 package(它的 Brewfile + install.sh),跳过系统引导和根 Brewfile
./install.sh -o|-b|-s # 软链目标已被其他文件占用时统一覆盖 / 备份 / 跳过,不再逐个询问(可与 <package> 组合)
./install.sh -h # 帮助
./bundle.sh check # 清单里有、本机没装的
./bundle.sh unlisted # 本机装了、但不在任何 Brewfile 里的(只列出,不卸载)
./bundle.sh install # 补装缺失的软件(不升级,不跑 package 的 install.sh)每台机器想装的子集可能不同(开发机要 go / nvim,演示机只要 terminal / claude)。
通过仓库根 install.conf 控制,不进 git,每台机一份:
cp install.conf.example install.conf
# 编辑:按需注释/取消注释 PACKAGES 里的条目;设置 INSTALL_EXTRA=true|false语义:
| 文件 / 字段 | 行为 |
|---|---|
install.conf 不存在 |
装全部 packages + 询问 extra(保持原行为) |
PACKAGES=(a b) |
只装 a 和 b 两个 package |
PACKAGES=() |
装零个(显式空数组) |
未定义 PACKAGES |
装全部 packages |
INSTALL_EXTRA=true |
不询问直接装 Brewfile.extra |
INSTALL_EXTRA=false |
不询问直接跳过 Brewfile.extra |
INSTALL_EXTRA= (空/未设) |
交互式询问 |
install.conf 影响 ./install.sh(完整模式)和 ./bundle.sh check|install。./install.sh <package>
单装时不读此文件、不询问 extra、不装根 Brewfile,仅处理指定 package 的 Brewfile 和 install.sh。
所有软件都写在 Homebrew Bundle 的 Brewfile 里,
formula、cask、App Store 应用(mas)都在同一份清单:
| 文件 | 内容 | 什么时候装 |
|---|---|---|
Brewfile |
基础软件 | ./install.sh 完整安装时总会装 |
packages/<name>/Brewfile |
该 package 的软件 | 随 install.conf 的 PACKAGES 选择 |
Brewfile.extra |
选装软件 | 由 INSTALL_EXTRA 控制,默认询问 |
安装时一律 --no-upgrade:已装的跳过、不升级,升级请自己 brew upgrade。
几台机器之间保持一致:
- 在任一台机器上新装了软件 → 写进对应的 Brewfile 并提交
- 其他机器
git pull后跑./bundle.sh check看缺什么,./bundle.sh install补装 - 时不时跑
./bundle.sh unlisted,看看有没有手动装了却没写进清单的软件
注意:
- 第三方 tap 的软件要写
trusted: true(Homebrew 7 起第三方 tap 需显式信任),例如packages/nvim/Brewfile里的macism mas条目需要先登录 App Store;没登录时安装会失败,登录后重跑即可- 用官网安装包手动装过的应用,写进 Brewfile 后
brew bundle会自动接管(adopt):保留本机那份, 登记为 brew 管理。会自动更新的 App(多数桌面应用都是)直接接管;其余的只有版本一致才接管, 不一致会报「existing App is different」,这时删掉手动装的那份,或brew install --cask --force <cask>覆盖安装 helm和helm@3都提供bin/helm,keg-only 的软件要不要进 PATH 都在 Brewfile 里用link:写明, 否则brew bundle会按默认值改动现有链接(见packages/DevOps/Brewfile)
.
├── install.sh # 入口:xcode → brew → 根 Brewfile → packages → Brewfile.extra
│ # 支持 `./install.sh <package>` 单装某个 package
├── install.conf.example # 本机 PACKAGES / INSTALL_EXTRA 配置模板(拷出 install.conf 编辑)
├── source.zsh # shell 启动时自动加载所有 packages/*/source.zsh
├── Brewfile # 基础软件清单(brew bundle)
├── Brewfile.extra # 个人选装软件(默认询问后安装)
├── bundle.sh # 对比本机和 Brewfile:check / unlisted / install
├── .env / .env.example # 环境变量(详见 ".env 跨机同步")
├── lib/ # 通用辅助函数
│ ├── echo.sh # 彩色输出 message/success/warn/error
│ ├── append.sh # 幂等地追加行到文件
│ ├── link.sh # 软链 + 备份/覆盖/跳过
│ ├── brew.sh # brew_bundle / selected_brewfiles
│ ├── env.sh # load_env:解析 .env / .env.local(install.sh 与 source.zsh 共用)
│ └── vault.sh # 跨机同步辅助(默认 iCloud Drive,可换其他后端)
└── packages/
├── terminal/ # ghostty + zsh + antidote + starship + 字体
├── claude/ # claude code CLI(Anthropic 终端 AI 编码助手)
├── codex/ # codex CLI(OpenAI),config.toml 真身走 vault
├── node/ # fnm + node + corepack(pnpm/yarn)
├── python/ # pyenv + python
├── go/ # go
├── nvim/ # neovim + LazyVim starter
├── DevOps/ # k8s / docker / 阿里云 / ansible / helm
├── osx/ # macOS 系统设置(Finder/Dock/键盘 等)
├── xcode/ # Xcode / TestFlight / Developer(App Store)+ xcodegen
└── zerotier/ # ZeroTier 客户端 + `zero` 启停命令
每个 package 有可选的:
Brewfile—— 该 package 的软件清单,主脚本先用brew bundle装它install.sh—— 装完软件后执行,做配置(软链、写~/.zshrc等)source.zsh—— shell 启动时根source.zsh自动加载README.md—— 单 package 的细节说明
.env(敏感凭据)、~/.ssh(私钥/config/known_hosts)和 ~/.codex/config.toml
(会被 codex 回写本机路径/项目名)不进 git,但需要在多台 Mac
间保持一致。本仓库通过 "vault 目录" + 正向软链实现:
$DOTFILES_VAULT
│
├─ .env ──── symlink ──→ ~/.dotfiles/.env
├─ .ssh/ ──── symlink ──→ ~/.ssh
└─ .codex/config.toml ── symlink ──→ ~/.codex/config.toml
vault 是什么 —— 一个跨机器自动同步的目录。仓库不绑定任何具体后端,你想用什么都行:
| 后端 | 设置方法 |
|---|---|
| iCloud Drive(默认) | 不用动 |
| Dropbox | export DOTFILES_VAULT="$HOME/Dropbox/.dotfiles" |
| Syncthing | export DOTFILES_VAULT="$HOME/Sync/.dotfiles" |
| OneDrive | export DOTFILES_VAULT="$HOME/OneDrive/.dotfiles" |
| Google Drive | export DOTFILES_VAULT="$HOME/GoogleDrive/.dotfiles" |
| 纯本地(不同步) | export DOTFILES_VAULT="$HOME/.dotfiles-vault" |
把 export 写到 ~/.zprofile 或 ~/.zshenv 里,每次 ./install.sh 都自动生效;
不 export 时使用默认值(iCloud Drive)。
不要把
DOTFILES_VAULT写到.env/.env.local里。.env本身就放在 vault 里,install.sh是先做 vault sync、再加载.env, 写在那里读不到(鸡生蛋蛋生鸡)。所以必须从 shell 启动文件提前 export 进环境。
如果不打算换后端,用前先把 iCloud 配置好:
- 登录 iCloud —— 系统设置 → Apple ID → 登录,并打开 iCloud Drive
- 给
.dotfiles目录设置「保留下载」(详见下一节,这一步必做)
默认 vault 路径:
~/Library/Mobile Documents/com~apple~CloudDocs/.dotfiles/
install.sh 会调用 vault_sync_file .env 和 vault_sync_home .ssh,自动处理四种状态:
| 场景 | 行为 |
|---|---|
| 本地有实体、vault 还没有 | mv 本地实体到 vault,再建软链(首次迁移) |
| 本地没有、vault 有(新机器) | 直接建软链回本地 |
| 软链已正确 | 跳过(幂等) |
| vault 不可用 | warn 后跳过,安装流程不中断 |
macOS 默认开启 iCloud Drive → 优化 Mac 存储:磁盘紧张或文件长期不访问时,
系统会把本地副本卸载到云端,本地只剩 metadata(APFS 上叫 dataless 文件)。
对一般文件没问题,APFS 会在你访问时自动从云端拉回。
但对 ~/.ssh 这种关键场景是个雷:
ssh进程因为 macOS TCC 沙盒,没有权限触发 iCloud 拉回- 一旦
~/.ssh/known_hosts或私钥被 evict 成 dataless,git push/ssh server/scp都会突然报Operation not permitted,原因极其隐蔽
解决办法(用其他 vault 后端就不用管这一节):
打开 Finder → 进入 iCloud Drive → 显示隐藏文件(
Cmd + Shift + .)→ 找到.dotfiles文件夹 → 右键 → 「保留下载」
这样 vault 目录里的 .env、.ssh 和 .codex 会被钉在本地,不会再被 iCloud evict 到云端。
只影响这一个目录,其他 iCloud Drive 文件该优化还是优化,不动你全局的「优化 Mac 存储」设置。
install.sh 在每次跑时也会主动 cat 一遍 vault 文件触发 materialize(当下能恢复),
但那只是临时补救,不能阻止系统下次再 evict。所以上面的 Finder 设置必须做一次。
.env 跨机器一致 —— 但有些值你只想这台机器用(比如机器名、本机独有的 dev token)。
这种情况用 .env.local,本机覆盖、不进 git、不进 vault。
加载顺序:
.env ← 共享(vault 同步、所有 Mac 一份)
.env.local ← 本机覆盖(不同步,每台机器各写各的)
install.sh 和 source.zsh 都会先加载 .env、再加载 .env.local,
后者覆盖前者的同名变量。这跟 dotenv / Next.js / Vite 的协议一致。
典型用法 —— 让每台 Mac 有独特的 hostname:
# .env 里(共享)
COMPUTER_NAME=zzs-mac # 默认值
# 这台 Mac 的 .env.local 里
COMPUTER_NAME=zzs-mbp16 # 本机覆盖
# 另一台 Mac 的 .env.local 里
COMPUTER_NAME=zzs-mini.env.local 已加入 .gitignore,且不被 vault_sync_file 同步,安全。
不写 .env.local 的话就走 .env 的默认值,行为不变。
fix_ssh_permissions 在每次 install.sh 末尾兜底重置权限:dir 700、私钥 600、公钥 644。
这是因为某些后端(特别是 iCloud Drive)同步会破坏 Unix 权限位,sshd 严格检查权限会拒绝使用密钥。
跨机器场景:
- 主力 Mac 有完整
~/.ssh→ 跑./install.sh→ 实体迁移到 vault,本地变软链 - 新 Mac vault 同步完成后跑
./install.sh→ 本地~/.ssh直接软链到 vault 真身 - 加/删 SSH key:任意一台 Mac 编辑(实际写入 vault),其他 Mac 自动同步
私钥放在任何云盘 vault 里,等于把密钥交给云服务商的服务器。 iCloud Drive、Dropbox、OneDrive、Google Drive 都不是默认端到端加密 (iCloud Advanced Data Protection 在中国大陆账号不可用;Dropbox/Drive 类似)。
这意味着:
- 服务商员工(或被服务商服务器入侵者)理论上能读到你的私钥
- 国内 Apple ID 数据由「云上贵州」托管,受国内法律约束
- 任何登录同账号的设备都能拿到所有 SSH key
如果你的 SSH key 用于访问 生产服务器、公司内网、关键基础设施, 强烈建议改用 1Password SSH agent 等专用方案,或者把
DOTFILES_VAULT指向纯本地目录、用其他端到端加密通道传输。 个人项目、低风险场景下,本方案可接受。机器特定的高敏感凭据 适合放
.env.local,因为它不会被 vault 同步上传。
packages/osx/install.sh会修改 macOS 系统偏好(Finder、Dock、键盘、截图路径等)。如果不希望改系统,跳过此 package 或阅读后注释。- 安装末尾会
killallFinder / Dock / SystemUIServer 等让设置生效,期间 UI 会闪一下。 - 用默认的 iCloud Drive vault 时,先把 iCloud 登录、启用,并按上文给
.dotfiles目录设置「保留下载」;否则.env会留在仓库目录里 —— 注意别git add .把它带进 git 历史。 - 用其他 vault 后端时,确认
$DOTFILES_VAULT指向的目录已存在且可写(cloud client 已登录、本地能 ls 进去)。
欢迎 issue / PR。开始之前请先阅读:
本项目采用 MIT License,可自由使用、修改、商用、再分发。
