概述:本教程带你从零构建一个「变更影响分析」Skill,让 Claude Code 在你提交代码改动时,自动解析
git diff、反向追踪符号引用、定位需要回归的测试,并产出带 Mermaid 依赖图的风险报告。适合掌握基础 Skill 写法、想进阶学习「脚本 Skill + 渐进式披露」分层架构的开发者。
~/.claude/skills/ 或项目 .claude/skills/ 下创建目录origin/main)rg(ripgrep)、git、awk、jq(多数发行版自带或可一键装)改一行函数签名,到底会波及哪些文件?靠人脑记忆依赖关系在大型代码库里几乎不可能。每次 PR review 都要回答三个问题:改了什么、影响了什么、要补哪些测试。「变更影响分析」(Change Impact Analysis,社区俗称 Blast Radius)就是用静态追踪的方式,把改动的「爆炸半径」量化出来。
把这套流程固化成一个 Skill,Claude Code 就能在你输入「评估这次改动的影响」时自动跑完整链路,而不是每次都从头口述一遍分析方法。
Claude Code 的 Skill 采用渐进式披露(Progressive Disclosure)设计——上下文按需加载,避免一次性把所有细节塞进模型窗口。一个进阶 Skill 通常分三层:
flowchart TB
A["① metadata 层<br/>name + description<br/>常驻系统提示词"] --> B{模型判断<br/>是否触发?}
B -->|是| C["② SKILL.md 正文<br/>触发后加载<br/>核心流程与约束"]
C --> D{需要执行脚本<br/>或查阅规则?}
D -->|是| E["③ 资源层<br/>scripts/ 与 references/<br/>按需读取"]
B -->|否| F["不加载,零成本"]
E --> G["返回结构化结果"]
D -->|否| G
设计目录结构如下:
change-impact-analysis/
├── SKILL.md # 主指令:触发场景 + 工作流程
├── scripts/
│ ├── extract-changes.sh # 从 diff 提取变更的导出符号
│ ├── trace-references.sh # 反向追踪符号在仓库中的引用
│ ├── find-affected-tests.sh # 定位需要回归的测试文件
│ └── score-risk.sh # 计算风险评分
└── references/
├── destructive-patterns.md # 破坏性变更判定规则
└── report-template.md # 输出报告模板
关键点:SKILL.md 保持精简(控制在 200 行内),把判定规则、报告长模板等「重内容」下沉到 references/,让模型在真正需要时才去读——这就是渐进式披露省 token 的核心。
创建 .claude/skills/change-impact-analysis/SKILL.md:
---
name: change-impact-analysis
description: 评估一次代码改动的"爆炸半径"。当用户提交/比较改动、做 PR review、
问"这次改动会影响什么"、"哪些测试要回归"、"这个改动安不安全"时使用。
解析 git diff,反向追踪符号引用,定位受影响测试,输出带 Mermaid 依赖图的风险报告。
allowed-tools: Bash(git diff:*), Bash(git log:*), Bash(git show:*), Bash(bash:*.sh),
Bash(rg:*), Read, Grep, Glob
---
# 变更影响分析
当被触发时,按以下流程评估当前仓库相对基线分支的改动影响。
## 输入
- 基线分支:默认 `origin/main`。用户指定其他分支则用其指定值。
- 可选:用户给定的具体 commit 范围(如 `HEAD~3..HEAD`)。
## 执行流程
1. **提取变更实体**
运行 `bash scripts/extract-changes.sh <base>`,得到被删除/修改的导出符号
(函数、类、export 常量)。重点关注符号定义行的删除——这是破坏性变更的高危信号。
2. **反向追踪引用**
把上一步的符号写入临时文件,运行 `bash scripts/trace-references.sh <symbols.txt> <root>`
找出引用这些符号的所有文件,剔除定义文件自身。
3. **定位受影响测试**
运行 `bash scripts/find-affected-tests.sh`,匹配受影响文件对应的测试
(约定 `foo.ts` → `foo.test.ts` / `foo.spec.ts` / `test_foo.py`)。
4. **判定破坏性变更**
读 `references/destructive-patterns.md`,逐条核对当前 diff 是否命中:
导出符号被删除、函数签名改变、返回类型收窄、公开常量值变更等。
5. **计算风险评分**
运行 `bash scripts/score-risk.sh <affected> <tests> <breaking(0|1)>`。
6. **产出报告**
严格按 `references/report-template.md` 的结构输出,含一张 Mermaid 影响图。
## 约束
- 只读分析,绝不修改任何源文件或测试文件。
- 若 diff 为空,直接回报"无改动",不要编造影响。
- 报告中每个受影响文件必须给出被引用的符号名作为依据,禁止空泛列举。
几个写法要点值得展开:
description 是「触发条件」而非「功能简介」。 它常驻在系统提示词里,决定模型何时主动调用本 Skill。写「当用户问 X、做 Y 时使用」比写「这是一个分析工具」触发率高得多。这是新手最常踩的坑。
allowed-tools 用白名单收窄边界。 这里只放开只读的 git 命令和脚本执行,把 Edit/Write 排除在外——影响分析天然是只读操作,白名单从机制上杜绝了「分析着分析着把代码改了」的越权风险。
把繁重的、确定性的工作交给 awk/rg/git,模型只负责调度与解读——这是「脚本 Skill」模式,比让模型逐文件 Read 再推理稳定得多。
scripts/extract-changes.sh —— 从 diff 提取变更的导出符号:
#!/usr/bin/env bash
# extract-changes.sh: 从 diff 提取被删除/修改的导出符号
# 用法: bash extract-changes.sh [base=origin/main]
set -euo pipefail
BASE="${1:-origin/main}"
ROOT="$(git rev-parse --show-toplevel)"
git diff "${BASE}...HEAD" --unified=0 --diff-filter=d |
awk '
/^\+\+\+ / { next } # skip file headers
/^[-+]/ && !/^[-+][-+][-+]/ { # only real +/- diff lines
line = $0
# match exported / defined symbols across JS/TS/Python/Go-ish
if (line ~ /(export[[:space:]]+(async[[:space:]]+)?function|export[[:space:]]+(default[[:space:]]+)?(const|class)|function[[:space:]]+|def[[:space:]]+|func[[:space:]]+|class[[:space:]]+)/) {
# strip the leading +/-, collapse spaces
sub(/^[-+]/, "", line); gsub(/[[:space:]]+/, " ", line)
print line
}
}
'
scripts/trace-references.sh —— 反向追踪符号引用:
#!/usr/bin/env bash
# trace-references.sh: 对符号列表反向追踪引用文件
# 用法: bash trace-references.sh <symbols_file> [root=.]
set -euo pipefail
SYMS="$1"; ROOT="${2:-.}"
[ -f "$SYMS" ] || { echo "symbols file not found" >&2; exit 1; }
while IFS= read -r raw; do
# extract the identifier after the keyword (function|def|const|class ...)
sym="$(printf '%s' "$raw" | grep -oE '[A-Za-z_][A-Za-z0-9_]*' | sed -n '2p')"
[ -z "$sym" ] && sym="$(printf '%s' "$raw" | grep -oE '[A-Za-z_][A-Za-z0-9_]*' | head -1)"
[ -z "$sym" ] && continue
# whole-word match, list files only
rg -l --no-ignore-vcs -w "$sym" "$ROOT" 2>/dev/null || true
done < "$SYMS" | sort -u
scripts/find-affected-tests.sh —— 定位对应测试:
#!/usr/bin/env bash
# find-affected-tests.sh: 受影响文件 → 对应测试文件
# 用法: bash find-affected-tests.sh <affected_files_file>
set -euo pipefail
IN="$1"
while IFS= read -r f; do
[ -z "$f" ] && continue
base="${f%.*}"; ext="${f##*.}"
# 常见测试命名约定
for pat in "${base}.test.${ext}" "${base}.spec.${ext}" \
"$(dirname "$f")/__tests__/$(basename "${base}").test.${ext}" \
"tests/test_$(basename "${base}").py"; do
[ -f "$pat" ] && echo "$pat"
done
done < "$IN" | sort -u
scripts/score-risk.sh —— 风险评分:
#!/usr/bin/env bash
# score-risk.sh: 受影响数 * 3 + 受影响测试 * 2 + 破坏性 * 20
set -euo pipefail
AFFECTED="${1:-0}"; TESTS="${2:-0}"; BREAKING="${3:-0}"
echo $(( AFFECTED * 3 + TESTS * 2 + BREAKING * 20 ))
预期结果:四个脚本都接受标准输入输出,可独立测试。例如在一个改动了 utils/format.ts 导出函数的仓库里:
$ bash scripts/extract-changes.sh origin/main
export function formatPrice(amount: number, currency: string)
$ bash scripts/extract-changes.sh origin/main > /tmp/syms.txt
$ bash scripts/trace-references.sh /tmp/syms.txt .
src/cart/summary.ts
src/invoice/print.ts
$ bash scripts/score-risk.sh 2 1 0
8
常见问题
awk 正则只覆盖常见关键字,团队若有私有命名规范,在正则里补 keyword 即可,不要让模型去猜。trace-references.sh 误报? rg -w 全词匹配已能过滤大量误报;对动态调用(字符串拼接方法名)静态分析本就无能为力,报告中需如实标注「无法静态追踪」。find-affected-tests.sh 的 for pat 列表里加你们项目的约定路径。references/destructive-patterns.md —— 破坏性变更判定清单(只在与破坏性判定相关时才加载):
# 破坏性变更(Breaking Change)判定清单
命中以下任一条,即视为破坏性变更(`breaking=1`):
1. **导出符号被删除**:`export function/const/class` 从 diff 中消失。
2. **函数签名改变**:参数数量减少、参数顺序变化、必填参数新增。
3. **返回类型收窄**:`string | undefined` → `string`,或 `any` → 具体类型。
4. **公开常量值变更**:`export const MAX = 100` 变为其他值。
5. **HTTP 接口契约变更**:路由路径、状态码、请求/响应字段移除。
以下不算破坏性:新增导出、内部实现重构、新增可选参数、放宽类型。
references/report-template.md —— 报告模板(控制输出一致性):
# 变更影响分析报告
**基线**:<base> → **HEAD** **风险评分**:<score>(破坏性:<yes/no>)
## 改动概览
- 变更文件 N 个,删除 X 行 / 新增 Y 行
- 变更的导出符号:`sym1`, `sym2`
## 影响范围(爆炸半径)
| 文件 | 引用的符号 | 路径 |
|------|-----------|------|
| src/a.ts | sym1 | import/调用 |
## 需要回归的测试
- a.test.ts
## 影响关系图
```mermaid
graph LR
A["utils/format.ts<br/>(改)"] --> B["cart/summary.ts"]
A --> C["invoice/print.ts"]
(一句话结论 + 是否建议人工 review 重点模块)
## 第五步:实战演练——分析一次真实的破坏性改动
准备一个最小仓库模拟场景:
```bash
mkdir demo-cia && cd demo-cia && git init -q
npm init -y >/dev/null 2>&1
# 初始版本:一个导出函数
cat > utils/format.ts <<'EOF'
export function formatPrice(amount: number, currency = 'USD') {
return `${currency} ${amount.toFixed(2)}`;
}
EOF
# 两处调用
cat > cart/summary.ts <<'EOF'
import { formatPrice } from '../utils/format';
export const line = (a: number) => formatPrice(a);
EOF
cat > invoice/print.ts <<'EOF'
import { formatPrice } from '../utils/format';
export const bill = (a: number) => formatPrice(a, 'EUR');
EOF
git add -A && git commit -qm "init" && git branch -M main
# 现在做一个破坏性改动:删掉默认参数,改成必填
cat > utils/format.ts <<'EOF'
export function formatPrice(amount: number, currency: string) {
return `${currency} ${amount.toFixed(2)}`;
}
EOF
git add -A && git commit -qm "breaking: currency now required"
在 Claude Code 里把 Skill 放好后,直接对话触发:
帮我评估这次改动的影响。
模型会自动按流程执行,最终产出类似报告:
# 变更影响分析报告
基线:origin/main → HEAD 风险评分:22(破坏性:是)
## 改动概览
- 变更文件 1 个,删除 1 行 / 新增 1 行
- 变更的导出符号:formatPrice
## 影响范围
| 文件 | 引用符号 |
|------|---------|
| cart/summary.ts | formatPrice(无第二实参,将编译失败)|
| invoice/print.ts | formatPrice(已传 'EUR',安全)|
## 需要回归的测试
- 暂无对应测试文件(建议补 utils/format 的单测)
## 影响关系图
graph LR
A["utils/format.ts (改)"] --> B["cart/summary.ts ⚠"]
A --> C["invoice/print.ts ✓"]
## 结论
破坏性变更:formatPrice 第二参数从有默认值变为必填。
cart/summary.ts 未传 currency,构建会直接失败,必须先修。
注意模型不是机械跑脚本——它在第 4 步对照 destructive-patterns.md 判定出「必填参数新增」属于破坏性,并在解读阶段点出 summary.ts 因缺参会编译失败这一语义级结论。脚本负责确定性检索,模型负责语义判断,二者分工。
让 Skill 自动触发而非手动喊。 把 description 里的触发词覆盖到「PR review」「提交前检查」「这个改动安全吗」等高频说法,命中率会显著上升。可在团队约定里把「提 PR 前先做影响分析」写进 CLAUDE.md,配合自动触发形成肌肉记忆。
用 context: fork 隔离重型分析。 若分析过程会产生大量中间输出污染主上下文,可在 frontmatter 加 context: fork,让本次 Skill 执行在独立上下文里跑完再回传结论。
缓存基线 diff。 大仓库 git diff origin/main...HEAD 较慢,可在脚本里加 git rev-parse HEAD 做缓存键,避免重复全量 diff。
接 hook 做自动门禁。 用 PreToolUse hook 在执行 git commit/git push 前自动触发本 Skill,当风险评分超阈值时阻断提交——把分析从「事后报告」升级为「事前护栏」。
| 维度 | 评估 |
|---|---|
| 适合人群 | 中级及以上前端/后端工程师,有 PR review 经验 |
| 训练营类型 | 工程效能、AI 辅助研发、代码质量训练营 |
| 预计教学时长 | 讲解 45 分钟 + 动手实操 90 分钟 |
| 难度 | ★★★☆☆(脚本调试是主要耗时点) |
| 复用价值 | 高——可原样迁入任何 Git 仓库即用 |
name/description/allowed-tools/context 等字段的逐项权威说明[!tip] 51学通信知识星球 星主:爱卫生(微信:gprshome201101)——公众号「51学通信」创办者,19 年通信行业运维与讲师经验,著有《GPRS网络信令实例详解》《EPC原理与实践》《5G核心网原理与实践》三本纸质书(各大电商平台有售)。 星球定位:深耕 5G 核心网、IMS、NFV/AI、云原生等 ICT 领域,主打运维岗位与信令分析。 当前规模:5200 篇主题 / 990 个回答,198 元/年。 加入福利:加入星球后请加爱卫生微信,拉您进知识星球年度陪伴与答疑群——不限量回复您的各种问题,另有群内分享。 AI 加持:51学通信知识星球已作为 skill 接入 WorkBuddy,使用 deepseek-4-flash 在海量星球帖子中精准找贴、找视频、找 FAQ 和案例,做总结、找文档和 PPT 等场景全覆盖。
