背景

在使用 /commit skill 提交代码时,反复出现三类问题:漏网 commit、type 混用、body 为空。这篇笔记记录这三个现象的本质、涉及的 Git 机制,以及如何通过修改 skill 从根本上解决它们。


三个典型现象

现象 1:漏网 commit

清理日志后发现遗漏,分别开了两个新 commit,message 写着”漏网一条”。

  • 表象:git log 多出打补丁式的 commit,历史显得零碎
  • 本质:把”补漏”误当成”新目的”,违反了一个 commit = 一个完整意图的原则

现象 2:type 混用

一个 commit 用了 perf(video),但实际包含了清日志(chore)+ 性能优化(perf)+ 文档更新三件事。

  • 表象:type 和实际改动内容对不上,读历史时产生误导
  • 本质:type 是分类标签,混合目的时无法准确分类,只能选其一,其余被掩盖

现象 3:body 为空

docs 类 commit 没有写 body,只有 subject。

  • 表象:只知道”更新了文档”,不知道为什么更新、更新了什么结论
  • 本质:docs/chore/refactor 这类 commit,subject 天然只能描述操作,body 是传达”为什么”的唯一地方,缺失则信息丢失

涉及的 Git 机制

Conventional Commits 规范

格式:type(scope): subject + body

字段说明
type改动类别:feat / fix / perf / chore / docs / refactor / test / style
scope影响范围,单模块加,跨模块省略
subject描述效果而非操作,“修复卡顿”而非”删除日志”
body说明 why,让人不看代码也能理解

判断 subject 是否合格

把 subject 给 3 个月后的自己看:能不能不看代码就理解这次 commit 的意义?如果不能,重写。

git commit —amend

把当前工作区的改动并入上一个 commit,不产生新 commit。

git add <files>
git commit --amend --no-edit   # 保留原 message
git commit --amend             # 同时修改 message

适用场景:发现上一个 commit 有遗漏,立刻补上。 注意:会改写历史,已推送时需要 git push --force

git rebase -i(交互式 rebase)

对一段历史 commit 批量重写,每行一个操作:

操作含义
pick保留不变
reword保留改动,修改 message
fixup并入上一个 commit,丢弃 message(等同于事后 amend)
squash并入上一个 commit,保留 message

非交互式自动化:通过环境变量注入脚本,绕过编辑器,实现完全脚本化:

GIT_SEQUENCE_EDITOR=/tmp/seq.sh \
GIT_EDITOR=/tmp/msg.sh \
git rebase -i <base-commit>
  • GIT_SEQUENCE_EDITOR:控制 todo 文件(把 pick 改成 fixup/reword 等)
  • GIT_EDITOR:控制每次 reword 时的 message 输入(按第一行内容识别当前 commit,替换为预准备的新 message)

这次实际用法示例(seq editor 脚本核心逻辑):

for line in lines:
    if re.search(r'漏网关键词', line):
        line = re.sub(r'^pick', 'fixup', line)
    elif re.search(r'需要改message的关键词', line):
        line = re.sub(r'^pick', 'reword', line)

git push —force

rebase / amend 后本地和远程历史分叉,必须 force push 同步:

git push --force origin main

协作仓库慎用

force push 会覆盖远程历史,在多人协作仓库中可能覆盖他人工作。个人仓库可以直接用。


/commit skill 的工作原理

/commit 是 Claude Code 的一个 skill(位于 ~/.claude/skills/commit/SKILL.md),通过 /commit 命令触发。

Skill 的本质:向 Claude 注入一段「工作流程 + 约束规则」的上下文,让 Claude 在执行任务时遵循特定步骤,而不是随意发挥。

原有流程(7 步):

  1. 状态检查
  2. 安全检查(敏感文件、冲突标记)
  3. 代码审查(遗留日志、TODO)
  4. 生成符合 Conventional Commits 的 message
  5. 用户确认
  6. 执行提交
  7. 询问推送

为什么会出问题 → 为什么这样修复有效

问题根本原因修复方案为什么有效
漏网 commitskill 没有 amend 路径,发现遗漏只能新开 commitStep 1 检测今天的 commit → 主动询问是否补漏;Step 5 增加 amend 选项把”是否 amend”变成流程中的显式判断点,而非靠执行者自发想到
type 混用自检是内部”过一遍”,没有强制执行自检改为”逐条执行不能省略”,body 含 fix 类内容时强制标注 [fix] 或提示拆分弱约束变成强制步骤,从”可能检查”变成”必须检查”
body 为空”可选”太宽泛,没有区分何时必须写明确规则:docs/refactor/chore 必须写 body给出明确判断标准,消除模糊地带
subject 是操作描述没有在生成后检查描述类型自检第 1 条:含操作动词列举时重新生成生成和检查分离,增加验证步骤

关键设计原则

规则不够,需要流程兜底。

光在 skill 里写”描述效果而非操作”是不够的——Claude 生成时仍然可能写出操作描述。真正有效的做法是:在流程中加入显式的验证步骤,生成之后再过一遍检查清单,不合格就重新生成。

这个原则适用于所有 skill 的设计:

  • 约束条件 → 放进规则
  • 规则的执行 → 靠流程中的强制检查点保障
  • 用户决策 → 靠 AskUserQuestion 在关键节点收集确认