@ttfake92-lab/macos-migration

>

View in AI SkillSafe app
5 scan findings
0 downloads
0 stars
0 demos
SKILL.md
namemacos-migration
description>

macOS 系统迁移助手

两阶段设计:旧系统采集 → 新系统还原。中间通过一个 JSON 清单文件衔接。

前置要求(务必先做)

在旧系统上先做一次 Time Machine 全量备份。 这是整个迁移的安全网——新系统上 任何一步出问题,都能从这份全量备份里捞回来。还原阶段也直接从 Time Machine 挂载点 读取数据。

没有 Time Machine 全量备份,就不要开始迁移。

运行模式检测

判断「采集还是还原」只看一个信号:清单文件在不在

ls ~/migration-manifest.json 2>/dev/null
条件 模式
无清单文件 采集模式(在旧系统上,生成清单)
有清单文件 还原模式(在新系统上,读清单还原)

Time Machine 只是还原阶段的数据来源,不参与模式判断。 用户也可以直接指定:「采集」「备份」「还原」「迁移」。


第零步:Homebrew 检查(两种模式都必须)

which brew && brew --version || echo "NOT_INSTALLED"
  • 已安装 → 继续

  • 未安装 → 引导用户在终端手动执行安装命令。这一步需要输入管理员密码(sudo), 无法静默完成:

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

    装完后按提示把 brew 加入 PATH(Apple Silicon:eval "$(/opt/homebrew/bin/brew shellenv)"), 再继续。


模式 A:旧系统采集

在旧系统上运行,扫描所有软件、配置、开发环境,生成 ~/migration-manifest.json

A1. Homebrew 软件包

brew list --formula
brew list --cask
brew tap

A2. 系统 Applications

ls /Applications/
ls ~/Applications/ 2>/dev/null

与 Homebrew cask 列表对比,标记哪些是 Homebrew 装的、哪些是手动/App Store 装的。

A3. Mac App Store 应用

mas list 2>/dev/null || echo "mas not installed"

如果 mas 未安装,提示用户是否要安装(brew install mas)。

A4. npm 全局包

npm ls -g --depth=0 2>/dev/null

A5. uv 工具

uv tool list 2>/dev/null

A6. pip/pipx 包

pip list 2>/dev/null
pipx list 2>/dev/null

A7. Go 全局工具

ls ~/go/bin/ 2>/dev/null

A8. 配置文件扫描

扫描 home 目录下的 dotfiles 和配置目录:

ls -la ~/

重点采集:

  • Shell:.zshrc, .zshenv, .zprofile, .bashrc, .bash_profile
  • Git:.gitconfig, .gitignore_global
  • SSH:.ssh/
  • 编辑器:.claude/, .codex/, .config/, .cursor/, .zed/
  • 容器:.docker/, .kube/
  • 包管理器:.npm/, .nvm/, .bun/, .cargo/, .rustup/
  • 其他应用配置:.SwitchHosts/, .ollama/, .syncthing/

敏感数据先问后采.ssh/(私钥)、dotfiles 里可能含 token、.aws/.kube/、 钥匙串等都是密钥级信息。采集这些之前先问用户是否纳入

  • 用户同意 → 正常采集,并明确提醒:「清单和备份里含私钥/凭据,传输、存放、 通过网盘或聊天工具发送时注意不要外泄。」
  • 用户拒绝 → 跳过这些项,在清单里记入 "skipped_sensitive": [...],让用户日后 自行手动迁移(差异报告里也会再列一次)。

A9. LaunchAgents(自启动服务)

ls ~/Library/LaunchAgents/

A10. 用户项目目录

列出 home 目录下非 dotfile 的顶层目录:

ls -d ~/*/ 2>/dev/null

排除系统目录(Library, Applications, Public 等),记录用户自建的项目/数据目录。

A11. Shell 环境

# 当前 shell 版本
zsh --version
# Homebrew 路径 / 版本管理器(nvm、fnm 等)配置
grep -iE 'brew|nvm|fnm' ~/.zshrc

A12. 其他易漏项

迁移时最容易漏、丢了又很烦的几类:

# 编辑器扩展
code --list-extensions 2>/dev/null
cursor --list-extensions 2>/dev/null

# 自购/自装字体
ls ~/Library/Fonts/ 2>/dev/null

# 定时任务
crontab -l 2>/dev/null

# 手动装到非 Homebrew 路径的命令行工具
ls /usr/local/bin/ 2>/dev/null
ls /opt/ 2>/dev/null

系统偏好(defaults)量大且与机型强相关,不自动采集;如用户在意,在还原差异 报告里提醒手动核对(键盘、触控板、Dock、快捷键等)。

A13. 生成清单文件

将以上所有信息写入 ~/migration-manifest.json

{
  "version": 1,
  "captured_at": "2026-06-28T16:00:00+08:00",
  "source_macos": "15.5",
  "source_hostname": "old-macbook",

  "homebrew": {
    "taps": ["user/repo", "..."],
    "formulas": ["git", "node@22", "..."],
    "casks": ["1password", "docker-desktop", "..."]
  },

  "applications": {
    "homebrew_casks": ["claude", "firefox", "..."],
    "app_store": [{"id": 123456, "name": "App Name"}],
    "manual": ["Final Cut Pro.app", "..."]
  },

  "package_managers": {
    "npm_global": ["@anthropic-ai/claude-code", "..."],
    "uv_tools": ["nano-pdf", "..."],
    "pip_packages": ["package1", "..."],
    "go_binaries": ["tool1", "..."]
  },

  "configs": {
    "dotfiles": [".zshrc", ".gitconfig", ".ssh", "..."],
    "config_dirs": [".claude", ".codex", ".config", ".docker", "..."],
    "app_support_keys": ["Syncthing", "obs-studio", "..."]
  },

  "editor_extensions": {
    "vscode": ["ms-python.python", "..."],
    "cursor": ["..."]
  },

  "fonts": ["MyFont.otf", "..."],
  "crontab": "<crontab -l 原文,无则空>",
  "manual_bins": ["/usr/local/bin/foo", "/opt/bar", "..."],

  "launch_agents": ["com.github.syncthing.plist", "..."],

  "user_dirs": ["Projects", "Sites", "..."],

  "shell": {
    "shell": "zsh",
    "brew_in_path": true,
    "nvm_installed": true,
    "custom_env_vars": {}
  },

  "skipped_sensitive": []
}

A14. 采集完成

输出清单摘要,提示用户:

✅ 采集完成!清单已保存到 ~/migration-manifest.json

采集内容:
- Homebrew: X taps, Y formulas, Z casks
- 应用: X 个 Homebrew, Y 个 App Store, Z 个手动安装
- npm 全局包: X 个
- 配置文件: X 个 dotfiles, Y 个配置目录
- 编辑器扩展: X 个 / 字体: Y 个 / 定时任务: 有/无
- 自启动服务: X 个
- 用户目录: X 个
- 跳过的敏感项: X 个(用户选择不采集)

⚠️ 若采集了 .ssh / dotfiles 中的凭据,清单与备份含私钥,传输存放注意不要外泄。

下一步:确认已有 Time Machine 全量备份,将 migration-manifest.json 复制到新系统,
再次运行此 skill。

模式 B:新系统还原

在新系统上运行,读取 migration-manifest.json 并逐步还原。

B0. 获取清单

ls ~/migration-manifest.json

如果不存在:

找不到 migration-manifest.json。

请将旧系统上采集的清单文件复制到新系统的 home 目录:
  scp old-mac:~/migration-manifest.json ~/migration-manifest.json

或者手动指定路径。

B1. Homebrew 软件安装

前提:第零步已确认 Homebrew 装好(需用户手动输密码安装)。装好之后这一步才能跑。

读取清单中的 homebrew 字段。

# 添加 taps(逐个)
brew tap <user>/<repo>

# 信任第三方 taps
brew trust <user>/<repo>

# 安装 formulas(批量,失败不回滚整批)
brew install <formula1> <formula2> ...

# 安装 casks(逐个,避免回滚)
for cask in <cask1> <cask2> ...; do
  brew install --cask "$cask" 2>&1 | tail -3
done

没装上的(需 sudo、网络失败等)先记下,最后在 B7 差异报告统一列给用户。

B2. 其他包管理器

读取清单中的 package_managers 字段。

# npm
npm install -g <pkg1> <pkg2> ...

# uv
uv tool install <pkg1> <pkg2> ...

# pip(如果需要)
pip install <pkg1> <pkg2> ...

# go binaries
go install <pkg1>@latest <pkg2>@latest ...

B3. 配置文件恢复

读取清单中的 configs 字段。

有两种数据来源,优先级:

  1. Time Machine 直接复制(如果有挂载)
  2. 用户手动提供(如果清单是从别的方式获取的)
TM="<Time Machine 用户目录路径>"
LOCAL="/Users/<username>"

# dotfiles
rsync -av --ignore-existing "$TM/.zshrc" "$LOCAL/"
rsync -av --ignore-existing "$TM/.gitconfig" "$LOCAL/"
rsync -av --ignore-existing "$TM/.ssh/" "$LOCAL/.ssh/"

# 配置目录
for dir in .claude .codex .config .docker .SwitchHosts ...; do
  rsync -av --ignore-existing "$TM/$dir/" "$LOCAL/$dir/"
done

恢复 .ssh/ 后确认权限:chmod 700 ~/.ssh && chmod 600 ~/.ssh/id_*。 如无 Time Machine,提示用户提供配置文件的来源路径。

B4. Library 关键子目录

从 Time Machine 恢复(如果有):

子目录 命令 说明
Preferences cp -rn 应用偏好设置
Keychains cp -rn 钥匙串
Containers cp -rn 沙盒应用数据
Group Containers cp -rn 共享容器
Mail cp -rn 邮件数据
Safari cp -rn 书签/历史

rsync 在 Time Machine APFS 快照上会报 io_read_flush 错误,Library 用 cp -rn

B5. LaunchAgents(自启动服务)

读取清单中的 launch_agents 字段。

逐个检查并创建对应的 plist 文件,然后 launchctl load

B6. 其他易漏项还原

对应采集阶段的 A12:

# 编辑器扩展(逐个装)
for ext in <清单 editor_extensions.vscode>; do code --install-extension "$ext"; done

# 字体
rsync -av --ignore-existing "$TM/Library/Fonts/" "$LOCAL/Library/Fonts/"

# 定时任务:先看新机器有没有现成的,再决定是否合并写入,避免覆盖
crontab -l 2>/dev/null

/usr/local/bin/opt 里的手动安装工具无法自动还原,列入 B7 差异报告提醒用户。

B7. 未安装项目处理

对比清单和实际安装结果,输出差异:

## 还原差异报告

### ❌ 安装失败(需手动处理)
- docker-desktop: 需要 sudo → 手动执行 `brew install --cask docker-desktop`
- tailscale-app: 需要 sudo → 手动执行 `brew install --cask tailscale-app`
- android-platform-tools: 网络问题 → 稍后重试

### ⚠️ 清单中有但无 Homebrew cask
- Final Cut Pro: App Store 应用
- DaVinci Resolve Studio: 手动下载 → blackmagicdesign.com

### ℹ️ App Store 应用(需手动安装或用 mas)
- GarageBand
- Infuse

### 🔧 需手动核对(非软件)
- 系统偏好 defaults:键盘 / 触控板 / Dock / 快捷键
- /usr/local/bin、/opt 手动工具:<manual_bins 列表>
- 拒绝采集的敏感项:<skipped_sensitive 列表>

踩坑记录

1. brew bundle 一个失败全部回滚

问题brew bundle --file=Brewfile 中任何一个 cask 下载失败,整批已安装的包全部回滚。

解决:不用 brew bundle。taps 逐个添加,formulas 批量安装,casks 逐个安装。

2. 第三方 taps 未信任

问题:Homebrew 6+ 要求显式信任第三方 taps,否则报 Refusing to load cask from untrusted tap

解决brew trust <user>/<repo>

3. rsync 在 Time Machine APFS 快照上报错

问题rsync -av --ignore-existing 复制 Library 子目录时报 io_read_flush 错误。

解决:Library 子目录改用 cp -rn

4. cp -rn 的 "Operation not permitted"

问题:macOS SIP/TCC 保护的文件无法直接复制(系统 Preferences、Mail 数据库等)。

影响:不影响使用。系统或应用在首次启动时自动重建。

5. cp -rn 的 "Not a directory" 错误

问题:Containers 中系统容器使用符号链接指向标准目录。

影响:不影响使用。用户应用的容器数据已正确复制。

6. 需要 sudo 的 casks

问题docker-desktoptailscale-appadobe-creative-cloud 安装时需要 sudo。

解决:记录在差异报告中,让用户手动执行。

7. node 版本冲突

问题brew install node@22brew link 失败。

解决brew link --overwrite node@22

8. Homebrew 检测不到非 Homebrew 安装的软件

问题:旧系统上通过 DMG/PKG/App Store 安装的软件,Homebrew 无法感知。

解决:采集阶段扫描 /Applications/ 并与 brew list --cask 对比,标记出手动安装的应用,还原时单独处理。

原则

  1. 先有 Time Machine 全量备份再开始:这是出错时唯一的兜底,也是还原的数据来源
  2. Homebrew 由用户手动安装:需要输密码(sudo),引导用户在终端执行,装好再继续
  3. 两阶段分离:采集和还原是独立的步骤,通过 JSON 文件衔接
  4. 敏感数据先问后采:私钥/凭据采不采由用户决定;采了就提醒外泄风险
  5. 绝不覆盖已有文件:所有 rsync/cp 都带 --ignore-existing-n
  6. 先小后大:按目录大小排序复制,方便快速验证
  7. 先做计划再动手:还原前输出清单摘要,让用户确认
  8. 记录差异:还原后输出差异报告,列出需要手动处理的项目
  9. 逐个安装 casks:避免 brew bundle 的回滚问题
  10. 验证每一步:安装后 brew list 确认,复制后 du -sh 验证大小
  11. 跳过缓存:Library/Application Support 中的缓存数据不恢复

Embed badges

Add these to your README to show the skill's verification status.

SkillSafe verified badge
Verified badge
[![SkillSafe verified badge](https://api.skillsafe.ai/v1/badge/@ttfake92-lab/macos-migration/verified)](https://skillsafe.ai/skill/@ttfake92-lab/macos-migration/)
Installs badge
Installs badge
[![Installs badge](https://api.skillsafe.ai/v1/badge/@ttfake92-lab/macos-migration/installs)](https://skillsafe.ai/skill/@ttfake92-lab/macos-migration/)
Scan badge
Scan badge
[![Scan badge](https://api.skillsafe.ai/v1/badge/@ttfake92-lab/macos-migration/scan)](https://skillsafe.ai/skill/@ttfake92-lab/macos-migration/)
Eval pass rate badge
Eval pass rate
[![Eval pass rate badge](https://api.skillsafe.ai/v1/badge/@ttfake92-lab/macos-migration/eval)](https://skillsafe.ai/skill/@ttfake92-lab/macos-migration/)