本 Skill 用于在跨分支代码迁移前执行全面的预迁移审计。通过分析 git 历史、diff 内容和代码语义,自动识别迁移范围内的外部依赖,评估迁移风险,生成结构化审计报告。
适用于任何语言、任何框架、任何项目类型。
输出语言规则:所有报告和面向用户的输出均使用用户偏好的语言生成(根据对话上下文中的语言设置)。如未指定偏好,默认使用用户正在使用的语言。
git merge — 需要精确识别迁移范围适用场景:迁移一个边界清晰的完整目录/模块。
输入:
特点:
适用场景:迁移一个功能,代码分散在多个目录,由多个 commit 组成。
输入(以下任意组合):
特点:
适用场景:以模块路径为主,但需要额外追踪模块外的相关改动。
输入:
开始审计前,自动检测项目类型,以便后续步骤使用正确的依赖分析策略:
# 检测项目类型
ls -la # 查看根目录结构
# 通过特征文件判断项目类型:
# - build.gradle / settings.gradle → Android/Java/Kotlin (Gradle)
# - pom.xml → Java/Kotlin (Maven)
# - package.json → JavaScript/TypeScript (Node.js)
# - go.mod → Go
# - Cargo.toml → Rust
# - requirements.txt / setup.py / pyproject.toml → Python
# - Podfile / *.xcodeproj → iOS (Swift/ObjC)
# - CMakeLists.txt → C/C++
# - *.sln / *.csproj → C# (.NET)
# - mix.exs → Elixir
# - Gemfile → Ruby
同时检测项目的多渠道/多 flavor 结构:
# 检查 flavor/variant 结构(Android)
grep -r "productFlavors" --include="*.gradle" . | head -5
# 检查多环境配置(Node.js)
ls .env* 2>/dev/null
# 检查多 target(iOS)
grep -c "target" *.xcodeproj/project.pbxproj 2>/dev/null
记录项目类型和多渠道结构,后续步骤将据此调整分析策略。
与用户确认以下信息:
必填参数:
按模式确认:
| 模式 | 需确认的参数 |
|---|---|
| ------ | ------------- |
| A(模块路径) | 模块路径(支持多个,如 src/audio/、lib/player/) |
| B(功能) | commit 列表 / 关键词 / 时间范围+作者 / Issue ID |
| C(混合) | 模块路径 + 功能关键词 |
可选参数:
test/、docs/)# 获取两个分支的分叉点
git merge-base origin/<源分支> origin/<目标分支>
# 获取源分支上目标模块的所有 commit(排除 merge commit)
git log <起始commit>..origin/<源分支> --oneline --no-merges -- <模块路径1> <模块路径2> ...
按以下策略依次执行,合并去重:
策略 1:精确 commit 列表(如用户提供)
# 直接使用用户提供的 commit SHA
git log --oneline <sha1> <sha2> <sha3> ...
策略 2:关键词搜索(AI 自动扩展关键词变体)
# 用户原始关键词
git log <起始>..<源分支> --oneline --no-merges --grep="<关键词>"
# AI 自动扩展的关键词变体(中英文、缩写、相关概念)
git log <起始>..<源分支> --oneline --no-merges --grep="<变体1>"
git log <起始>..<源分支> --oneline --no-merges --grep="<变体2>"
# ... 合并去重
关键词扩展规则:
策略 3:时间范围 + 作者
git log <起始>..<源分支> --oneline --no-merges --author="<作者>" --since="<开始日期>" --until="<结束日期>"
策略 4:Issue/TAPD ID 搜索
git log <起始>..<源分支> --oneline --no-merges --grep="<issue-id>"
策略 5:文件路径反向追踪
# 从已找到的 commit 中提取涉及的文件
git diff-tree --no-commit-id -r --name-only <已知sha>
# 反向查找修改过这些文件的其他 commit
git log <起始>..<源分支> --oneline --no-merges -- <文件1> <文件2> ...
策略 6:代码引用链分析
# 从已知的核心类/函数出发,找到所有引用它们的文件
grep -rn "<核心类名>" --include="*.<扩展名>" . | grep -v build | grep -v node_modules
# 再找修改了这些引用文件的 commit
git log <起始>..<源分支> --oneline --no-merges -- <引用文件列表>
合并去重后,呈现给用户确认:
通过以下策略共找到 N 个相关 commit:
- 关键词搜索("audio"、"听书"、"tts"):找到 X 个
- 文件反向追踪:额外发现 Y 个
- 代码引用链:额外发现 Z 个
完整列表:
1. abc1234 - feat: 添加听书播放功能
2. def5678 - fix: 修复播放暂停问题
...
请确认是否有遗漏,如有补充请提供。
先执行模式 A 的路径扫描,再执行模式 B 的关键词搜索,合并去重。
对确定范围内的每个 commit,检查是否涉及"迁移范围外"的文件:
for sha in <commit列表>; do
# 获取该 commit 修改的所有文件
all_files=$(git diff-tree --no-commit-id -r --name-only "$sha")
# 过滤出不在迁移范围内的文件(外部文件)
external_files=$(echo "$all_files" | grep -v "^<模块路径模式>")
if [ -n "$external_files" ]; then
echo "=== $sha ==="
echo "$external_files"
fi
done
对于功能模式,"外部文件"的定义需要动态确定:
对每个涉及外部文件的 commit,执行 git show 查看 diff 内容,按以下通用标准分类:
| 判定标准 | 分类 | 说明 |
|---|---|---|
| --------- | ------ | ------ |
| 外部文件新增了被迁移代码引用的符号(类/函数/变量/类型) | 强依赖 | 迁移代码编译/运行依赖此变更 |
| 外部文件修改了被迁移代码调用的函数签名 | 强依赖 | 签名不匹配导致编译失败 |
| 外部文件引用了迁移范围内的符号 | 强依赖 | 外部代码集成了迁移功能 |
| 外部文件的变更与迁移代码无引用关系 | 弱依赖 | 同一 commit 中的无关改动 |
| 外部文件是构建配置文件 | 基础设施 | 模块注册/依赖声明 |
| 外部文件是测试文件 | 测试依赖 | 可选迁移 |
| 外部文件是资源文件(strings/drawable/layout 等) | 资源依赖 | 需检查是否重复定义 |
根据步骤 0 检测到的项目类型,使用对应的引用识别方法:
| 项目类型 | 引用识别方法 |
|---|---|
| --------- | ------------- |
| Java/Kotlin | import 语句、类继承、接口实现、方法调用、构造函数参数 |
| JavaScript/TypeScript | import/require 语句、export 声明 |
| Python | import/from...import 语句 |
| Go | import 语句、包引用 |
| C/C++ | #include 指令、函数声明/定义 |
| Rust | use/mod 语句、extern crate |
| Swift/ObjC | import/#import 语句 |
| Ruby | require/require_relative 语句 |
| C# | using 语句、命名空间引用 |
| 通用 | 代码中的文件名/路径字符串引用 |
对每个强依赖的外部文件,评估冲突风险:
# 获取两个分支间该文件的 diff 统计
git diff origin/<目标分支> origin/<源分支> --stat -- <文件>
# 获取文件总行数(评估文件复杂度)
wc -l <文件>
# 检查目标分支是否也修改了该文件(双向修改 = 高冲突概率)
git log <起始>..origin/<目标分支> --oneline --no-merges -- <文件>
# 检查文件行尾格式(CR/LF/CRLF)
file <文件>
风险等级判定:
审计过程中,额外检查以下通用常见陷阱:
file <路径> 检查是否有 "CR line terminators"(Windows/Mac 行尾混用)迁移模块后,必须检查模块中 import 的所有第三方库在目标分支的构建配置中是否有对应声明:
# 示例:Java/Kotlin 项目
grep -rh "^import " <模块路径> --include="*.java" --include="*.kt" | \
grep -v "<项目包名>" | grep -v "android\|java\|kotlin" | sort -u
# 对比 build.gradle / pom.xml 中的依赖声明
⚠️ 传递依赖链在不同分支可能不同 — 源分支通过传递依赖获得的库,在目标分支可能不存在。必须显式声明所有直接使用的依赖。
| 项目类型 | 检查项 |
|---|---|
| --------- | -------- |
| Gradle (Java/Android/Kotlin) | build.gradle 依赖声明、settings.gradle 模块注册、flavor 配置、本地 aar/jar 依赖、AGP library 模块限制(fileTree 不能包含 .aar) |
| Maven (Java) | pom.xml 依赖声明、模块结构、parent pom 版本 |
| npm/yarn (JS/TS) | package.json 依赖版本、lock 文件差异、workspace 配置 |
| Go | go.mod 依赖版本、replace 指令 |
| Cargo (Rust) | Cargo.toml 依赖版本、workspace members |
| pip (Python) | requirements.txt 版本、setup.py/pyproject.toml 配置 |
| CocoaPods (iOS) | Podfile 依赖、.xcodeproj 配置 |
| CMake (C/C++) | CMakeLists.txt targets 和 link libraries |
| .NET (C#) | .csproj 引用、NuGet 包版本 |
生成交互式 HTML 报告,保存到项目的 docs/ 目录下(不存在则创建)。
报告包含以下部分:
报告交互功能:
基于审计结果,提供分层迁移策略建议:
阶段 0:基础设施
- 构建配置文件(build.gradle / package.json / go.mod 等)
- 模块注册/声明
- 新增的依赖模块(如 model 层)
✅ 完成后立即编译验证
阶段 1:核心代码迁移
- 方案 A(整模块覆盖):直接用源分支的模块目录覆盖目标分支
- 覆盖前确认目标分支模块目录无独有代码
- 覆盖后检查传递依赖
- 方案 B(逐 commit cherry-pick):按时间顺序逐个 cherry-pick
✅ 完成后立即编译验证
阶段 2:低风险外部依赖
- 新增文件(直接复制)
- 纯追加变更(无冲突 cherry-pick)
- 目标分支未修改的文件
✅ 完成后立即编译验证
阶段 3:中风险外部依赖
- 逐 commit cherry-pick,手动解决小冲突
- 或手动合并差异
- 每次 cherry-pick 后执行检查清单
✅ 完成后立即编译验证
阶段 4:高风险外部依赖
- 手动处理
- 保留目标分支版本 + 手动补充必要变更
- 超大文件不要整体 cherry-pick
- CR 行尾文件需先转换格式再编辑
✅ 完成后立即编译验证
阶段 5:验证
- 编译验证
- 单元测试
- 功能测试
- 回归测试
docs/migration-audit-<时间戳>.html| 文件类型 | 建议策略 |
|---|---|
| --------- | --------- |
| 迁移范围内的内部文件(冲突) | 直接用源分支最终版本覆盖 |
| 外部文件冲突 | 手动解决,保留目标分支独有逻辑 |
| 超大文件(>5000 行) | 不要整体 cherry-pick,保留目标分支版本 + 手动补充 |
| 构建配置文件 | 手动合并,不要覆盖目标分支的配置 |
| 二进制文件 | 直接用源分支版本覆盖(无法合并) |
| 测试文件 | 可选迁移,优先级最低 |
| 资源文件(strings.xml 等) | cherry-pick 后检查是否有重复定义 |
| CR 行尾文件 | 先 tr '\r' '\n' 转换 → 编辑 → tr '\n' '\r' 转回 |
每次 cherry-pick 后,AI 必须提醒用户执行以下检查:
grep -rn "<<<<<<" --include="*.<扩展名>" .在报告中主动标注以下风险:
api(name:'xxx', ext:'aar')使用功能模式时,AI 必须:
当用户在迁移过程中遇到编译错误或运行时问题时,AI 应能:
用户:我需要把 feature/payment 分支的支付模块迁移到 main 分支,帮我做个审计
AI:好的,我来执行跨分支模块迁移审计。请确认以下信息:
feature/paymentmainsrc/modules/payment/)用户:我需要把 develop 分支的"用户认证重构"功能迁移到 release/v2.0
AI:好的,我来执行功能级别的迁移审计。这个功能可能跨多个目录、多个 commit,我需要先定位所有相关 commit。
请提供以下信息(越多越好):
我会通过多策略交叉验证尽可能完整地找到所有相关 commit,然后请你确认。
用户:迁移 src/audio/ 模块,但这个模块还依赖了一些公共组件的改动
AI:好的,我使用混合模式:
src/audio/ 路径下的所有 commit请确认源分支和目标分支名称?
用户:cherry-pick 后编译报错 "actual and formal argument lists differ in length"
AI:这是典型的接口签名差异问题。让我检查一下两个分支中该接口的签名差异...
(对比两个分支的接口定义,提供具体修复方案)
报告使用以下结构:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>跨分支迁移审计报告</title>
<!-- 内联 CSS:现代简洁设计,支持暗色/亮色模式 -->
<!-- 内联 JS:筛选、搜索、展开/折叠、导出 CSV -->
</head>
<body>
<!-- 0. 关键风险告警面板(置顶,红色背景) -->
<!-- 1. 报告头部:项目名、源分支、目标分支、生成时间 -->
<!-- 2. 概览统计卡片(commit 数、依赖数、风险分布、预估工作量) -->
<!-- 3. Commit 发现过程(功能模式) -->
<!-- 4. 风险矩阵表格(可筛选、可排序) -->
<!-- 5. Commit 详情列表(可展开 diff) -->
<!-- 6. 特殊情况警告面板 -->
<!-- 7. 迁移策略建议(分阶段) -->
<!-- 8. Cherry-pick 检查清单(可打印) -->
<!-- 9. 操作按钮(导出 CSV、导出 Markdown、打印) -->
</body>
</html>
报告样式要求:
共 1 个版本