# Summarize Changes

> 总结当前代码更改，生成结构化的 commit message 或变更摘要；变更结束后直接调用时结合对话上下文精准提炼改动目标

- Skill: `ghost-him/summarize-changes` (Agent Skill, multi-file: 2 files)
- Install (CLI): `npx skillmds@latest add ghost-him/summarize-changes`
- Raw SKILL.md: https://api.skillmd.com/api/skills/ghost-him/summarize-changes/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Research & Search
- Author: ghost-him (https://skillmd.com/u/ghost-him)
- Updated: 2026-09-17
- Page: https://skillmd.com/skills/ghost-him/summarize-changes

---


# summarize-changes — 代码更改总结

分析当前 Git 工作区的变更（diff），结合当前对话上下文（如适用），理解修改了什么、为什么修改，生成简洁的 commit message。

## 触发方式

```
/summarize-changes [--staged]
```

- 不带参数：从 `git diff`（工作区 + 暂存区所有未提交变更）获取内容。
- `--staged`：只总结暂存区变更，从 `git diff --cached` 获取内容。

## 使用场景

1. **变更结束后直接调用**（推荐）：在同一对话中刚完成一项改动后调用。对话历史包含改动的目标、背景与决策过程，是 commit 标题与背景最可靠的来源，可避免仅凭 diff 猜测目标时被改动量分布误导。
2. **独立总结现有变更**：对话与本次改动无关（如新开会话总结工作区遗留变更）。仅从 diff 分析。

## 执行流程

0. **安全检查**（仅默认模式，`--staged` 模式跳过）：
   - 运行 `.omp/skills/summarize-changes/check-changes.sh` 获取工作区全貌：
     - 退出码 0（无未暂存/未跟踪文件）：展示输出后直接进入步骤 0.5。
     - 退出码 1（存在未暂存或未跟踪文件）：展示输出，通过 `ask` 询问是否继续/切换 `--staged`/中止。

0.5. **提取会话上下文**（仅场景 1）：
   - 回顾当前对话，确认是否包含本次改动的开发过程（原始需求、方案讨论、决策、范围说明、验证过程）。若不包含 → 按场景 2 处理，跳过本步骤。（若改动早期讨论已超出上下文窗口，可用 `history://` 读取本会话完整记录。）
   - 依次提取：
     - **改动目标**：用户最初要解决什么问题 → commit header 与 Why 的来源。
     - **决策与取舍**：为什么选当前方案、讨论中否掉/放弃的备选 → What & Impact 的来源。
     - **范围边界**：用户明确声明包含/排除的内容，用于识别 diff 中的附带改动。
     - **验证过程**：冒烟测试、测试结果等，作为影响描述的佐证。
   - **目标判定以对话为准**：commit 标题描述对话确立的目标，而非 diff 中改动量最大的领域。某领域虽改动量大但与对话目标无关，属于附带改动，仅在 body 中概括为次要要点。
   - 若对话包含多个独立任务且当前 diff 混有多个任务的内容，按任务分组提炼，必要时 `ask` 用户确认本次 commit 范围。

1. **收集变更信息**：运行 `git diff HEAD --stat` 和 `git diff HEAD`（或 `--cached` 对应版本）获取变更内容。

2. **容量检测**：stat 中变更文件 > 15 个时，禁止逐一文件详解，改为按**变更目的**分组概括。

3. **单文件上下文限制**：单个文件变更块上下文 > 200 行或变更行数 > 500 行时，禁止 Read 完整文件，仅基于 diff 片段分析。

4. **理解改动**：
   - 场景 1 先核对 diff 与步骤 0.5 的目标是否一致：
     - 目标内容在 diff 中缺失（改动未完成或 diff 属于其他任务）→ 提示用户「diff 与对话目标不符」。
     - diff 包含对话之外的大块改动 → `ask` 用户是否纳入本次 commit，或单独归类描述。
     - 对话讨论过但未落地的方案，**不写入** commit。
   - 阅读 diff，理解改了什么、为什么改。**不需逐一罗列每处修改**，同类变更合并为一条概括描述。
   - **输出篇幅与变更规模成正比**：小改动（≤5 文件、≤100 行 diff net）的 body 控制在 5–10 行内；中型 ≤15 行。body 不设逐行 70 字符限制，精简优先。
   - 关注**问题根因**和**高阶解决方案**，而非逐行翻译 diff。

5. **分析根因**（仅修复类变更）：从 diff 反推发生了什么错误。

6. **生成 commit message**：

   ```
   <type>(<scope>): <一句用户视角的话，描述提交后的最终效果>

   **🤔 背景与动机 (Why)**
   2–4 个要点，描述问题或痛点。

   **✨ 解决方案与影响 (What & Impact)**
   2–4 个要点，描述高阶解决方案和核心影响。
   ```

   - **场景 1：header 与 Why 直接来自步骤 0.5 的对话目标**，What & Impact 结合对话决策与 diff 验证结果；场景 2 按原规则从 diff 推断。
   - **header ≤100 字符**（commitlint `header-max-length`），且不含标点结尾。
   - **body 每行 ≤100 字符**（commitlint `body-max-line-length`）。
   - **subject 首词避用大写拉丁字母**：commitlint `subject-case` 禁止 sentence-case / start-case / pascal-case / upper-case，以全大写缩写（`SDK`、`API`、`IPC`、`CLI`）或首字母大写的英文单词开头都会违规；中文或小写开头（如 `sdk crates 版本解耦`）则通过。规避方法：缩写改小写（`sdk`），或改用中文/其他措辞开头。
   - 使用中文 body，**不含**双引号 `"`。
   - **每节要点 ≤4 个**，用抽象概括代替逐项枚举（不列函数名、文件数、测试数）。
   - **禁止在 body 中嵌入超过 50 字符的代码/路径/符号引用**。必须用自然语言描述行为，而非复现代码符号：
     - ❌ `在 validate_settings() 之前调用 component.apply_settings(component.get_default_settings())`
     - ✅ `在注册时预置 schema 默认值，使校验前已持有符合约束的初始状态`
     - ❌ `src-tauri/src/core/config/manager.rs:54-64`
     - ✅ 只描述「在哪层做了什么」即可，不列具体行号
   - **Scope 规则**：基于对 diff 的理解，用能代表本次改动所属领域的短名称作 scope（如 `translator`、`config`、`i18n`）。目录结构仅作参考，不作机械判定：
     - 改动可归入单一领域（功能、子系统、配置域或横切工作如 i18n/性能）→ 用领域名，即使文件散落在多个目录（如后端、前端与语言资源共同完成同一功能）。

6.4. **scope 大小写**：scope 须为小写/中划线/驼峰/帕斯卡命名，避免大写缩写开头（如 `SDK` 会触发 `scope-case` 违规），示例 `workspace`、`api`、`i18n` 均合规。

6.5. **commitlint 校验**：将生成的 commit message 送入仓库的 commitlint 检测——与 `.husky/commit-msg` 钩子同一规则源，覆盖 `subject-case`、`type-case`、`scope-case`、`header-max-length`、`body-max-line-length` 等全部规则（不再依赖自写脚本）：
   - 命令（在仓库根目录执行）：`printf '%s\n' '<commit message>' | bun x --no -- commitlint`，多行消息可用 heredoc 传入，空行须保留。
   - 退出码 0 → 合规，进入步骤 7；退出码 1 → 按报错规则修正（超长压缩措辞、subject/type/scope 大小写调整），**重新生成** commit message 后再次校验，直至通过。
   - commitlint 按字符统计长度（对宽字符与英文一致计数），header 与 body 上限均为 100。
   - 若本地无 bun 或 commitlint 不可用，回退为行长度检查（header ≤100、body ≤100）。

7. **输出结果**：展示给用户，不执行 `git commit`。



## 输出示例

```
fix(core): 在注册时预置 schema 默认值避免零值与约束冲突

**🤔 背景与动机 (Why)**
- 组件注册先于持久化配置加载，校验时读取的是 struct 零值而非 schema 默认值。
- min_items(1) 等约束下的空数组等零值导致「当前配置值无效」错误。

**✨ 解决方案与影响 (What & Impact)**
- 注册流程中先应用 schema 默认值作为初始状态，再执行校验。
- 持久化配置随后加载覆盖，不影响用户已保存的值。
```

## 注意事项

- 专注**总结变更**，不继续扩展新改动。
- **同类变更合并描述**，不逐行罗列 diff 细节。
- 涉及依赖版本变更时在 body 里注明原因。
- **场景 1 目标判定以对话为准**：diff 的改动量分布只影响 body 的详略与附带改动归类，不改变标题指向的目标。
- 对话中讨论过但未实施的方案（备选、被否决策）不写入 commit，只描述实际落地内容。

