mcpField
G
git-commit

git-commit

github.com/chann开发051 次安装2 天前更新
代码仓库

关于 git-commit

用于将工作区变更整理为 Conventional Commits,或改写近期不符合规范的提交标题。它将创建提交、推送和重写历史分为不同流程,并设置相应的安全检查。

主要功能

  1. 01按逻辑单元整理变更
  2. 02使用 Conventional Commits 格式
  3. 03工作区干净时检查是否需改写
  4. 04检查敏感文件并展示提交计划
  5. 05通过安全检查后推送或重写历史

适用场景

  1. 01将不同变更分开提交
  2. 02规范近期提交标题
  3. 03以非强制方式推送提交
  4. 04变更前检查文件和提交信息

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/chann/skills --skill git-commit

安装后在 Claude Code 中输入/git-commit确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

agents/
openai.yaml
evals/
evals.json
scripts/
rewrite_msg.py

详细介绍

Git 提交技能

概述

将工作树中的更改归并为 Conventional Commits 1.0.0 单元(每个逻辑单元对应一个提交),或就地重写近期不符合规范的提交主题。

核心原则: 根据用户意图选择正确的工作流——创建新提交还是重写历史;除非用户明确同意(例如使用 /git-commit-rewrite 的 force 关键字),否则绝不使用破坏性标志绕过安全措施。

开始时声明: “我正在使用 git-commit 技能来 <提交 / 推送 / 重写> 这些更改。”

命令

命令技能操作作用对象
/git-commitgit-commit将工作树中的更改归并为 Conventional Commits未提交的更改(已暂存 + 未暂存)
/git-commit-pushgit-commit-push同上,然后执行 git push(不使用 --force)未提交的更改 + 远程仓库
/git-commit-rewritegit-commit-rewrite重写近期不符合规范的提交主题现有本地历史

选择正确的命令

开始任何操作前先检查:

git status --short        # Are there working-tree changes?
git log --oneline -10     # Are recent messages already Conventional?
情况命令
工作树有更改,历史记录正常/git-commit
工作树有更改 + 想要推送/git-commit-push
工作树干净,近期历史记录杂乱(“Added X”“WIP”“Fixed bug”)/git-commit-rewrite
两者兼有:工作树有未提交更改,且历史记录杂乱先提交(/git-commit),然后单独执行 /git-commit-rewrite

自动路由: 如果用户直接运行 /git-commit,但工作树干净,则检查近期历史记录。如果近期提交不符合规范,告知用户并询问:“没有可提交的工作更改。近期历史记录中有 N 个不符合规范的主题——你想使用 /git-commit-rewrite 重写它们吗?”

Conventional Commits 格式

<type>[optional scope][!]: <description>

[optional body]

[optional footer(s)]

允许的类型

类型含义
feat新功能(MINOR semver 版本提升)
fix修复错误(PATCH semver 版本提升)
docs仅限文档更改
style格式 / 空白字符;不更改逻辑
refactor既不修复错误也不添加功能的代码更改
perf性能改进
test添加或修复测试
build构建系统或外部依赖项
ciCI 配置文件和脚本
chore其他不修改 src 或测试的更改
revert撤销先前的提交

破坏性更改——在类型 / 作用域后添加 !(例如 feat(api)!: drop v1 endpoints),和 / 或包含 BREAKING CHANGE: ... 页脚。

主题规则

  • 使用祈使语气:“add”,而不是“added” / “adds”
  • 描述的首词使用小写
  • 末尾不加句号
  • 主题行尽量控制在 ≤72 个字符
  • 作用域可选,但当其能明确限定模块 / 区域时,建议使用

示例

feat(parser): add ability to parse arrays
fix(ui): correct button alignment
docs: update README with usage instructions
refactor(auth): extract token validation
chore: update dependencies
feat!: send email on registration

BREAKING CHANGE: email service is now required at boot

工作流:/git-commit(默认)

步骤 1:检查工作树
git status --short
git diff
git diff --cached

如果没有更改 → 告知用户,执行自动路由检查(见上文),然后停止。

第 2 步:将更改分组为逻辑单元

阅读每个修改文件的差异,并按意图分组。每组对应 一个 Conventional Commit。忽略现有暂存状态——从头合并并重新分组已暂存和未暂存的更改。

分组规则:

  • 将 feat 与 fix 分开——绝不合并
  • 将 docs 与代码更改分开(除非文档是同一项更改中的文档字符串)
  • 新功能或修复的测试可以与对应提交合并;无关测试则可以单独提交
  • 将 build / ci / 依赖更新与功能工作分开
  • 将 refactor 与 feat 分开
  • 无关模块中的修复 → 按模块拆分提交
  • 功能文件中的琐碎空白更改可以合并到功能提交中

不要拆分过细(与功能一并提交一行无关紧要的清理也可以),也不要合并过度(feat 和 fix 必须分开)。

机密信息检查——标记以下任一情况,默认排除,除非用户明确确认:.env*、credentials.*、*_rsa、*.pem、*.key、*.p12、路径中包含单词 secret 的文件。不要仅因 .env.example 与 .env* 匹配而将其标记;它是公开模板。其他所有机密路径规则仍然适用,包括敏感的父目录或其他匹配的文件名模式。提醒用户仍被怀疑含有机密信息的文件;这些文件不应提交。

第 3 步:展示提交计划

创建任何提交之前,先打印计划并让用户提出异议:

Plan: 3 commits

1. feat(auth): add OAuth login flow
   - src/auth/oauth.ts
   - src/auth/index.ts

2. fix(api): handle null response in user fetch
   - src/api/users.ts

3. docs: update README with auth setup
   - README.md
第 4 步:逐个创建提交

按计划顺序处理每个单元:

git add path/one path/two   # explicit paths only
git commit -m "$(cat <<'EOF'
type(scope): description

optional body explaining the why
EOF
)"

规则:

  • 绝不使用 git add . 或 git add -A——始终指定明确的路径
  • 绝不使用 --no-verify、--no-gpg-sign、--amend(除非用户明确要求)
  • 绝不添加表情符号或 Co-Authored-By: Claude,除非用户要求
  • 多行消息使用 HEREDOC,确保引号处理正确
  • 每次提交后运行 git status --short,确认只有预期文件已提交

如果预提交钩子失败:不要使用 --no-verify 重试。调查并修复根本问题(或报告问题),然后创建新的提交。

第 5 步:最终摘要
git log --oneline -<N>

(其中 N 为已创建的提交数),并将其展示给用户。

示例
User: 변경사항 의미 단위로 커밋해줘

git status --short →
 M src/auth/oauth.ts
 M src/auth/index.ts
 M src/api/users.ts
 M README.md
?? src/api/.env

→ Detect .env (secret) — exclude, warn
→ Group:
   1. feat(auth): add OAuth login flow  (oauth.ts, auth/index.ts)
   2. fix(api): handle null response in user fetch  (users.ts)
   3. docs: update README with auth setup  (README.md)
→ Show plan, wait for confirmation
→ For each: git add <paths> && git commit -m "..."
→ git log --oneline -3

工作流:/git-commit-push

运行上述默认工作流。每次提交成功后:

git push

如果当前分支未配置上游分支:

git push -u origin "$(git branch --show-current)"

绝不使用 --force 或 --force-with-lease。如果推送被拒绝(非快进),请停止并报告——不要自动解决。如果推送因任何原因失败,请说明错误并让用户决定。

示例
User: /git-commit-push

(Same workflow as default, then:)
→ git push
   error: failed to push some refs (non-fast-forward)
→ STOP. Report:
   "Push rejected: branch is behind origin. Run `git pull --rebase`
    first, then re-push manually. I will not auto-resolve."

工作流:/git-commit-rewrite

重写近期历史中不符合 Conventional Commit 规范的提交消息。此操作具有破坏性——会更改提交 SHA。默认策略会拒绝修改任何已存在于远程上的提交。

强制模式(force 关键字)

如果调用中包含独立的令牌 force 或 --force(不区分大小写)——例如 /git-commit-rewrite force、“force rewrite these commits”、“force로 다시 써줘”——则以强制模式运行。该关键字表示用户已明确预先同意执行破坏性的原地重写,因此跳过所有交互式检查并直接应用。(触发条件是英文令牌 force/--force;仅出现韩语词语 강제로 不会触发强制模式。)

  • 跳过安全检查 A 和 B(工作区有未提交更改 / HEAD 处于分离状态)——不要提前停止。Git 仍会执行自身规则:如果工作区确实有未提交更改,git filter-branch 会拒绝操作(“Cannot rewrite branches: You have unstaged changes”)。如果 Git 报错,原样显示错误——不要绕过。
  • 跳过第 2 步的已推送提交菜单——即使提交已存在于远程,也自动选择原地重写。不要提示用户。
  • 跳过第 5 步的等待——仍要展示旧消息 → 新消息的计划,以确保操作透明,然后立即应用,无需等待。
  • **推送:**重写后,如果有任何被重写的提交已存在于远程,则最后执行 git push --force(不带其他参数)。这是唯一允许使用裸 --force 的场景,而且仅限用户使用该关键字选择加入强制模式时。如果没有任何提交已推送到远程,则重写仅保留在本地——不要推送。
  • 清理步骤不变——保留 refs/original/ 备份引用并报告它(第 8 步)。

不包含 force 关键字时,遵循下方完整的谨慎工作流。

第 1 步:确定重写范围

默认基准:

upstream=$(git rev-parse --abbrev-ref --symbolic-full-name '@{u}' 2>/dev/null || true)
if [ -n "$upstream" ]; then
  base=$(git merge-base HEAD "$upstream")
elif git rev-parse --verify main >/dev/null 2>&1; then
  base=$(git merge-base HEAD main)
elif git rev-parse --verify master >/dev/null 2>&1; then
  base=$(git merge-base HEAD master)
else
  echo "Could not determine a base. Ask the user for an explicit range." >&2
  exit 1
fi

如果用户指定数量(例如“重写最近 5 个”),则改用 HEAD~5 作为基准。绝不要使用 --root。

第 2 步:安全检查

强制模式会跳过整个步骤(参见上方“强制模式”)——直接进入第 3 步。

原地重写前,必须通过以下三项检查:

检查 A — 工作区干净:

[ -z "$(git status --porcelain)" ]

失败 → 告知用户先提交或暂存更改,然后停止。

检查 B — HEAD 已关联到分支:

git symbolic-ref -q HEAD >/dev/null

失败 → 告知用户切换到某个分支,然后停止。

检查 C — 范围内没有提交已存在于远程:

for sha in $(git rev-list "$base..HEAD"); do
  if [ -n "$(git branch -r --contains "$sha")" ]; then
    pushed_commits+=("$sha")
  fi
done

如果 pushed_commits 非空:**不要默默拒绝操作。**向用户显示以下菜单:

Found N commits in <base>..HEAD whose subjects are non-Conformant.
M of them are already pushed to a remote:

  abc1234  origin/main  "Added User-Agent Parser"
  def5678  origin/main  "Fixed bug"
  ...

Rewriting published history breaks pulls for collaborators. Options:

  1. Cancel — keep history as-is
  2. Rewrite locally + force-push (destructive; coordinate with team first)
  3. Cherry-pick onto a NEW branch with rewritten messages (safe; original branch untouched)

Which option? (default: 1)
  • 选项 1 → 正常退出
  • 选项 2 → 继续前,要求用户明确输入类似“yes force push”的短语;重写后执行 git push --force-with-lease(绝不要使用 --force)
  • 选项 3 → 参见下方“基于分支的重写”
第 3 步:识别不符合规范的提交

对于 <base>..HEAD 中的每个提交,检查其主题行是否符合:

^(feat|fix|docs|style|refactor|perf|test|build|ci|chore|revert)(\([^)]+\))?!?: .+

跳过已符合规范的提交。跳过合并提交(使用 git rev-list --no-merges)。

第 4 步:生成新消息

对于每个不符合规范的提交:

  1. 检查:git show --stat <sha>;必要时查看差异内容
  2. 根据更改内容,从上方表格中选择一个 type
  3. 选择可选的 scope(模块 / 文件区域)——不确定时省略
  4. 编写新的主题行:使用祈使语气、小写、不超过 72 个字符、末尾不加句号
  5. **逐字保留原提交正文。**只重写主题行。如果原正文为空,则保持为空。

典型转换示例请参见下方“常见不符合规范模式的映射”部分。

第 5 步:展示旧消息 → 新消息的计划
Rewrite plan: 3 commits

abc1234  added login feature
       → feat(auth): add login feature

def5678  Fixed bug
       → fix(api): handle null response in user fetch

ghi9012  WIP
       → chore: work-in-progress checkpoint

等待用户明确确认后再应用。(强制模式会展示此计划,但不会等待——而是立即应用。)

第 6 步:应用重写(原地)

在 /tmp/cc-rewrite-map.tsv 中构建映射文件。每个不符合规范的提交占一行:

<full-40-char-sha>\t<new full message including preserved body>

新的完整消息为 <new subject>\n\n<original body>(如果没有正文,则仅为 <new subject>)。在 TSV 中,消息内的换行符以 \n 转义;rewrite_msg.py 会将其还原。

然后运行(使用脚本的绝对路径):

script="$HOME/.claude/skills/git-commit/scripts/rewrite_msg.py"
# Plugin install path may differ; resolve via:
#   script=$(find ~/.claude -name rewrite_msg.py -path '*git-commit*' | head -1)
FILTER_BRANCH_SQUELCH_WARNING=1 git filter-branch -f \
  --msg-filter "python3 '$script'" \
  "$base..HEAD"

脚本读取 $GIT_COMMIT,在 /tmp/cc-rewrite-map.tsv 中查找该提交,并输出新消息。不在映射文件中的提交将原样保留。

如果可以使用 git filter-repo(优先于已弃用的 filter-branch),请改用它。但随附的映射流程目前依赖 filter-branch;只有在用户安装了 filter-repo 并且更倾向于使用它时,才进行切换。

第 7 步:基于分支进行重写(第 2 步中的选项 3)

当提交已推送且用户选择选项 3 时,请改为执行以下操作,而不是原地重写:

# 1. Note current branch
src=$(git branch --show-current)

# 2. Create a fresh branch off the upstream/base
git checkout -b "${src}-cc" "$base"

# 3. Cherry-pick each commit, rewriting message as you go
for sha in $(git rev-list --reverse --no-merges "$base..$src"); do
  new_msg=$(lookup_in_map "$sha")   # from Step 4 plan; or compose interactively
  git cherry-pick "$sha"
  git commit --amend -m "$new_msg"  # only the cherry-pick we just made
done

# 4. Verify, then push the new branch
git log --oneline "$base..HEAD"
git push -u origin "${src}-cc"

原始分支不会受到影响。用户可以从 ${src}-cc 创建 PR,并在准备好后弃用原始分支。无需强制推送,不会造成破坏。

第 8 步:重写后的清理

原地重写后(第 6 步):

  • 运行 git log --oneline "$base..HEAD" 并显示结果。
  • 告知用户备份引用已保存在 refs/original/refs/heads/<branch>,并说明确认无误后如何将其删除:
    git update-ref -d refs/original/refs/heads/<branch>
    
    不要自动删除。
  • 删除临时文件:
    rm -f /tmp/cc-rewrite-map.tsv
    

基于分支重写后(第 7 步):

  • 告知用户如果改变主意,如何切换回去:
    git checkout <original-branch>
    git branch -D <branch>-cc
    
示例:混乱的历史记录
User: 커밋 메시지 다시 써줘
       (User shares git log:)
       96b6be8  gnhf #43: Added User-Agent Parser ...
       eda73c5  gnhf #42: Added JSON Schema Generator ...
       e943794  gnhf #41: Added IPv4 Subnet Calculator ...
       0a7e01e  gnhf #40: Added Markdown TOC Generator ...

Step 1 (range):
   upstream = origin/gnhf/prd-chann-tools-2026-8f2964
   base = $(git merge-base HEAD origin/main)

Step 2 (safety):
   ✓ working tree clean
   ✓ HEAD attached
   ✗ all 4 commits exist on origin/<branch>
   → Show menu (Cancel / Force-push / New branch). User picks 3.

Step 3 (regex): all 4 fail the regex (start with "gnhf #N:")

Step 4 (mapping):
   "gnhf #43: Added User-Agent Parser..."   → feat(api-network): add user-agent parser
   "gnhf #42: Added JSON Schema Generator"  → feat(data-format): add JSON schema generator
   "gnhf #41: Added IPv4 Subnet Calculator" → feat(api-network): add IPv4 subnet calculator
   "gnhf #40: Added Markdown TOC Generator" → feat(text): add Markdown TOC generator

   Drop the "gnhf #N" prefix (ticket-tracker noise; belongs in the body or a footer).
   To preserve the ticket reference, add a footer:
       Refs: gnhf#43

Step 5: show old → new plan, wait for confirmation.

Step 7 (branch-based):
   git checkout -b feature-tools-cc origin/main
   for sha in (cherry-pick each, --amend with new message)
   git push -u origin feature-tools-cc

常见的不符合规范模式映射

在第 4 步生成新主题时,使用以下映射。

原始模式可能的 Conventional 改写
Added X / Add Xfeat: add X(或 feat(scope): add X)
Fixed X / Fix X / Bugfix: Xfix: <imperative>
Updated X(外观调整/依赖升级)chore: update X 或 build(deps): bump X
Updated X(实际重构)refactor: <imperative>
Cleanup / Clean up Xrefactor: <imperative> 或 chore: <imperative>
Renamed X to Yrefactor: rename X to Y
Removed X / Delete Xrefactor: remove X(如果有破坏性变更,则用 feat!:)
WIP / wip / tmpchore: work-in-progress checkpoint
Initial commitchore: initial commit
Merge branch 'X'跳过(已排除合并提交)
[TICKET-123] Added Xfeat: add X + 页脚 Refs: TICKET-123
proj #N: Added Xfeat(scope): add X + 页脚 Refs: proj#N
Tests for Xtest: add tests for X
Docs: <anything>docs: <imperative>
Refactor X(已接近祈使形式)refactor: <imperative form>

经验法则:

  • 过去时 → 祈使形式(“Added” → “add”,“Fixed” → “fix”)
  • 首字母大写 → 小写
  • 删除末尾句点
  • 将工单跟踪器前缀移至 Refs: 页脚(不要丢失关联信息)
  • 如果类型确实难以在 chore、refactor 和 style 之间判断,工具/配置相关的优先用 chore,代码结构变更用 refactor,只有空白/格式调整才用 style

快速参考

遇到问题时,请询问:

症状操作
没有未提交的更改 + 历史记录混乱建议使用 /git-commit-rewrite
有未提交的更改 + 历史记录混乱先提交,再使用 /git-commit-rewrite
已推送的历史记录 + 想要修复使用第 7 步(基于分支重写)
提交前钩子失败修复根本问题;绝不要使用 --no-verify
推送被拒绝(非快进)停止并显示错误;未经明确同意,绝不要使用 --force
git filter-branch 提示已弃用已设置 FILTER_BRANCH_SQUELCH_WARNING=1;忽略即可

常见错误

在一个提交中合并 feat 和 fix

  • 问题: feat(auth): add OAuth and fix null response 混合了不同类型
  • 修复: 拆分为两个提交,一个 feat,一个 fix

使用过去时的主题

  • 问题: “added login flow”、“fixed bug”
  • 修复: 使用祈使语气——“add login flow”、“handle null response”

使用 git add . 暂存所有内容

  • 问题: 意外暂存机密或无关更改
  • 修复: 每组更改都始终使用 git add <explicit-paths>

使用 --no-verify 绕过钩子

  • 问题: 掩盖真实问题;提交在本地“能用”,但在 CI 中失败
  • 修复: 调查钩子失败的原因;修复根本原因;创建新的提交

默默拒绝改写已推送的历史

  • 问题: 只说“我不能”,不提供后续方案
  • 修复: 在步骤 2 中提供 3 个选项(取消 / 强制推送 / 基于分支)

改写时丢弃工单引用

  • 问题: “gnhf #43: Added X” → “feat: add X” 会丢失 gnhf#43 关联
  • 修复: 将工单移到 Refs: gnhf#43 页脚;不要丢失它

改写合并提交

  • 问题: 对合并提交使用 Filter-branch 会扰乱父提交关联
  • 修复: 始终使用 git rev-list --no-merges

危险信号

绝不:

  • 使用 git add . 或 git add -A(使用明确指定的路径)
  • 未经用户明确同意使用 --no-verify、--no-gpg-sign、--amend
  • 使用 --force 推送——除非处于 /git-commit-rewrite 强制模式(force 关键字即为明确同意);其他情况下,只有在获得明确同意后才使用 --force-with-lease
  • 未经用户明确例外授权,提交疑似 .env* 文件(精确文件名为 .env.example 的文件除外)、credentials.*、*_rsa、*.pem、*.key 或 *.p12
  • 在一个提交中合并 feat 和 fix
  • 未先展示 3 个选项就改写已推送的提交——强制模式除外,其中 force 关键字即为预先同意
  • 使用 git filter-branch --root
  • 改写时丢弃工单引用(将它们移至 Refs: 页脚)

始终:

  • 创建提交前展示提交计划
  • 每次提交后运行 git status --short 以进行验证
  • 改写时逐字保留原始提交正文
  • 列出要改写的提交时使用 --no-merges
  • 询问已推送提交时,默认选择“取消”
  • 遵循仓库现有的范围命名惯例(先运行 git log -20 --oneline)

行为说明

遵循仓库现有风格。 先检查 git log -20 --oneline。如果仓库使用 Conventional Commits,就遵循其范围命名惯例。如果现有提交信息风格混杂,则默认使用小写描述和简洁范围。

对话说明与提交信息的语言。 对话更新使用用户提示词的语言。提交信息使用 git log 中占主导地位的语言(无法确定时用英语)。

谨慎使用范围。 范围必须对应实际存在的模块或区域。如果不确定,就省略范围,不要凭空编造。

不要在正文中过度解释。 正文应补充主题无法表达的背景(原因、棘手的权衡、相关问题)。如果主题已能清楚说明,就不要写正文。

拒绝操作,不要绕过检查。 如果安全检查失败(未经同意的已推送提交、工作区不干净、HEAD 分离、疑似机密),请报告并停止。不要使用破坏性标志绕过检查。例外: /git-commit-rewrite 强制模式,用户通过 force 关键字明确选择启用(参见强制模式)。

信任用户明确授权的例外。 “强制推送”、“我知道它已推送,还是要改写”、“这次把 .env 包含进去” → 可以继续,但先用一行说明风险。对于 /git-commit-rewrite,force 关键字是这种授权的正式形式(参见强制模式)。

集成

配合使用:

  • code-review — 提交前运行 /code-review,作为最终质量检查
  • git-merge-to-main / git-merge-to-dev — 提交后集成分支
  • 任何插件提交钩子(commitlint、husky)——修复违规,不要使用 --no-verify

调用方式: 仅由用户手动调用。绝不在其他技能的工作流中自动运行。

评论

支持 Markdown