---
name: cm
description: 分批分类按规范提交
disable-model-invocation: true
argument-hint: "[可选：限定文件或范围]"
---

把当前改动分批分类提交。

先看清全部改动：`git status --porcelain`（含未跟踪文件，`git diff` 看不到它们）+ `git diff`。顺手扫一眼有没有密钥、调试输出、误加的文件。

## 分组

- 合在一起是默认，拆需要给出理由。算数的理由只有两种：这两部分放同一个 commit 里会让人看不清改了什么，或者将来想回退其中一半会连累另一半；message 的 body 需要第二段讲另一件事。说不出这两个理由就不拆。
- 以下都不算理由：文件不同、目录不同、语言不同、改动类型不同（顺手改的一行文档不需要单独一个 docs commit）、改动行数多、跨了前后端。
- 一两行的清理（`.gitignore` 条目、空行、拼写、格式）不单独成 commit：并进这一批里最相关的组，没有相关的就并进最大的组，message 里不提。
- 每个 commit 必须能独立成立——单独看是完整的一件事，不是半截。一件事的所有必要部分放同一个 commit：改函数签名和它的调用点、新增配置项和读它的代码、改动和它对应的测试，不许分开提交攒数量。
- 先看 `git log` 里这个项目历史 commit 的粒度，按同样的粒度分，不套模板。
- 上下文里已有的任务列表只是线索，不是分组依据：任务里夹带的无关改动要拆出去，任务列表之外的零散改动要捡进来，以实际 `git diff` 为准。
- 一个文件里混了两件事，整个文件放进主要那边，在 message 里说明。不做文件内拆分。
- 分组必须是文件清单的一个划分：每个文件属于且只属于一个组，不重不漏。

## 提交操作

- `git add <路径…>` 逐组提交，全程不动工作区。禁 `git add -A`、`git commit -a`。
- 禁止用 `git stash` / `git reset` / `git checkout` 来回倒腾着切割改动——这条路会走到 `git reset --hard` 丢数据（claude-code issue #14293），主流 commit skill 里也没人这么做。
- 个人项目默认直接提交到当前分支；只有改动大或有风险、主分支受保护、或多人协作时，才先开分支。

## Message

- 格式和禁忌照我全局 `~/.claude/CLAUDE.md` 里的 commit 规范执行，这里不重复。
- 先只看这一组的 diff 写草稿，写完再想有没有 diff 看不出的 why 要补。不要从对话出发写。
- 每句话要同时满足两条：指向 diff 里某处改动，指不到的删；提供看 diff 得不到的 why，看 diff 就知道的删。
- diff 外的信息只能是关于最终代码的 why（设计取舍、约束）；对话过程、被否掉的中间版本、「为什么没有某东西」、会话待办的编号都不是。
- body 按方面分段，空行隔开，每段 2 到 4 行，行宽 72 列（中文约 36 字），断行落在标点处。段与段讲同一件事的不同方面；哪一段讲的是另一件事，就拆成两个 commit。
- 没有值得写的 why 就不写 body，单行 subject 完事，不要为了「像样」硬凑段落。版本号、顺带的清理这类看 diff 就知道的不写。
- 每组 `git add` 之后、commit 之前调 `/flow:vet`，把草稿原文当参数传给它。按它标出的句子删改；注释的问题改在文件里再重新 `git add`。再调一次，直到它回「vet 通过」。

## 收尾

- 提交前把分组方案 + 每条 message（都过了 vet 的）列给我看一眼。
- 全部提交完跑一次 `git status` 核对，剩余改动必须是事先说好不提交的那些。
- 未经我明确同意不要 push。

带参数时只提交指定的那部分，其余不动。
