AI 写的 commit message 为什么比你写的好?/commit 源码揭秘

一句话总结

  • /commit 全部源码只有 92 行,是 Claude Code 中最精简的命令之一
  • 它的类型是 prompt------不做任何本地逻辑,纯靠一段 prompt + 工具白名单让 LLM 自己搞定
  • 核心创新:用 !git diff HEAD`` 语法在 prompt 注入前预执行 shell 命令,让 LLM 拿到实时 diff 数据
  • 只白名单了 3 个工具:git addgit statusgit commit------极致最小权限
  • 有一套完整的 Git Safety Protocol:永远不 amend、不 skip hooks、不提交 .env

源码定位

bash 复制代码
src/commands/commit.ts              ← 命令全部逻辑(92行,3.5KB)
src/utils/promptShellExecution.ts   ← !`command` 预执行引擎
src/utils/attribution.ts           ← commit attribution 生成

命令类型prompt

go 复制代码
const command = {
  type: 'prompt',             // ← 纯 prompt 注入
  name: 'commit',
  description: 'Create a git commit',
  allowedTools: ALLOWED_TOOLS,  // ← 只允许 3 个工具
  progressMessage: 'creating commit',
  source: 'builtin',
} satisfies Command

/init 一样是 prompt 类型------但比 /init 更极致:整个命令的"智能"100% 来自 prompt 设计,没有任何条件分支或模式选择。


执行流程

scss 复制代码
用户输入 /commit
    ↓
getPromptForCommand() 被调用
    ↓
构造 prompt(含 !`command` 占位符)
    ↓
executeShellCommandsInPrompt() 预执行 shell 命令:
  !`git status`         → 替换为当前状态
  !`git diff HEAD`      → 替换为完整 diff
  !`git branch --show-current` → 替换为分支名
  !`git log --oneline -10`     → 替换为最近10条 commit
    ↓
完整 prompt 注入对话
    ↓
LLM 分析 diff,生成 commit message,调用 git add + git commit

核心源码解读

1. 完整 Prompt 全文(带注释)

这是 /commit 的核心------一段不到 40 行的 prompt 就搞定了 Conventional Commits:

sql 复制代码
function getPromptContent(): string {
  const { commit: commitAttribution } = getAttributionTexts()

  return `## Context

- Current git status: !`git status`
- Current git diff (staged and unstaged changes): !`git diff HEAD`
- Current branch: !`git branch --show-current`
- Recent commits: !`git log --oneline -10`

## Git Safety Protocol

- NEVER update the git config
- NEVER skip hooks (--no-verify, --no-gpg-sign, etc) unless the user explicitly requests it
- CRITICAL: ALWAYS create NEW commits. NEVER use git commit --amend, unless the user explicitly requests it
- Do not commit files that likely contain secrets (.env, credentials.json, etc). Warn the user if they specifically request to commit those files
- If there are no changes to commit, do not create an empty commit
- Never use git commands with the -i flag (like git rebase -i or git add -i) since they require interactive input

## Your task

Based on the above changes, create a single git commit:

1. Analyze all staged changes and draft a commit message:
   - Look at the recent commits above to follow this repository's commit message style
   - Summarize the nature of the changes (new feature, enhancement, bug fix, refactoring, test, docs, etc.)
   - Ensure the message accurately reflects the changes and their purpose
   - Draft a concise (1-2 sentences) commit message that focuses on the "why" rather than the "what"

2. Stage relevant files and create the commit using HEREDOC syntax:
\`\`\`
git commit -m "$(cat <<'EOF'
Commit message here.${commitAttribution ? `\n\n${commitAttribution}` : ''}
EOF
)"
\`\`\`

You have the capability to call multiple tools in a single response. Stage and create the commit using a single message. Do not use any other tools or do anything else.`
}

2. !command`` 预执行机制

这是 Claude Code 的一个通用基础设施------在 prompt 模板中嵌入 shell 命令,注入前先执行、替换为输出结果:

typescript 复制代码
// promptShellExecution.ts
// 支持两种语法:
// 代码块: ```! command ```
// 行内:   !`command`

const INLINE_PATTERN = /(?<=^|\s)!`([^`]+)`/gm

export async function executeShellCommandsInPrompt(
  text: string,
  context: ToolUseContext,
  slashCommandName: string,
): Promise<string> {
  // 找到所有 !`...` 模式,执行命令,替换为输出
}

这意味着 LLM 看到的不是 !git diff HEAD``,而是实际的 diff 内容。 prompt 模板在注入前就已经被"渲染"过了。

3. 最小权限白名单

arduino 复制代码
const ALLOWED_TOOLS = [
  'Bash(git add:*)',      // 只能 git add
  'Bash(git status:*)',   // 只能 git status
  'Bash(git commit:*)',   // 只能 git commit
]

LLM 只能执行这 3 类命令。不能 git push、不能 git rebase、不能 rm -rf。这是 Claude Code 安全模型的核心------每个 prompt 类型命令都可以声明 allowedTools,运行时强制执行。

权限注入逻辑

javascript 复制代码
async getPromptForCommand(_args, context) {
  const promptContent = getPromptContent()
  const finalContent = await executeShellCommandsInPrompt(promptContent, {
    ...context,
    getAppState() {
      const appState = context.getAppState()
      return {
        ...appState,
        toolPermissionContext: {
          ...appState.toolPermissionContext,
          alwaysAllowRules: {
            ...appState.toolPermissionContext.alwaysAllowRules,
            command: ALLOWED_TOOLS,  // ← 临时注入白名单
          },
        },
      }
    },
  }, '/commit')

  return [{ type: 'text', text: finalContent }]
}

它不是修改全局权限,而是在执行上下文中临时覆盖------命令结束后权限恢复原状。

4. Git Safety Protocol 设计

6 条安全规则,每条都对应一个真实的 incident:

规则 防什么
NEVER update git config 防 AI 改 user.name/email
NEVER skip hooks 防绕过 lint/format 检查
NEVER use --amend 防覆盖别人的 commit
不提交 .env/credentials 防泄露密钥
不创建空 commit 防无意义操作
不用 -i flag 交互式命令会卡死

5. commit message 风格学习

kotlin 复制代码
- Look at the recent commits above to follow this repository's commit message style

这一行是关键------!git log --oneline -10`` 预执行后,LLM 能看到最近 10 条 commit 的风格。如果你的项目用 feat: 前缀,AI 就会跟着用;如果你的项目用全小写无前缀,AI 也会适配。

不是硬编码 Conventional Commits,而是"看样学样"。

6. HEREDOC 语法的必要性

bash 复制代码
git commit -m "$(cat <<'EOF'
Commit message here.
EOF
)"

为什么不直接 git commit -m "message"?因为 commit message 可能包含引号、换行符、特殊字符。HEREDOC 是 shell 中处理多行含特殊字符文本的标准方式------避免转义地狱。


横向对比:/commit vs 手写 vs 其他 AI 工具

维度 手写 GitHub Copilot Claude Code /commit
上下文 只看 staged diff 只看 staged diff diff + status + branch + 最近10条commit
风格 取决于心情 固定模板 学习仓库已有风格
安全 取决于人 无特殊处理 6条安全规则
归因 可选 attribution
代码量 N/A 未知 92行

设计亮点:三个可迁移的 Pattern

1. Prompt Template + Shell Pre-execution

!command`` 语法让 prompt 模板具有了"运行时数据注入"能力。你不需要在代码层面解析 git diff 再拼接 prompt------直接在模板里写 shell 命令,框架自动处理。

可迁移:如果你在做 AI 工具,任何需要"先获取数据再让 LLM 分析"的场景,都可以用这种模板预执行模式。

2. 上下文学习 > 规则硬编码

不说"你必须用 Conventional Commits",而是给 LLM 看 git log 让它自己学。这比硬编码格式规则更灵活------适用于任何项目。

可迁移:Few-shot learning 的变体。与其写一堆规则,不如给 LLM 看几个实例。

3. 最小工具权限原则

每个命令只开放它需要的最小工具集。/commit 不能 git push、不能 git rebase------即使 LLM "想"这么做,权限层面也会拦住。

可迁移:设计 AI Agent 时,给每个 action 定义最小权限边界,不给 LLM 全局 admin 权限。


实战建议

使用技巧

bash 复制代码
# 直接用------它会自动 stage 所有变更
/commit

# 先手动 stage 部分文件,再 /commit(只提交 staged 的)
git add src/feature.ts
/commit

让 commit message 更好的方法

  1. 保持 git log 风格一致------AI 会模仿你最近 10 条 commit 的风格
  2. 如果想要特定格式,在 CLAUDE.md 里写 commit 规范,AI 会参考
  3. attribution 默认开启 ------commit message 末尾会加 Co-authored-by: Claude

注意事项

  • /commit 会提交所有变更 (staged + unstaged),除非你先手动 git add 特定文件
  • 不会自动 push------需要你自己 git push 或用 /commit-push-pr
  • 如果没有任何变更,会安全地什么都不做

下篇预告

第 4 篇:Anthropic 的 AI 代码审查到底检查了什么?/review prompt 全文曝光

/review 分两条路:本地审查(prompt 驱动)和远程 Ultrareview(云端多 Agent 并行找 bug)。我们会完整展示审查 prompt 的维度设计,以及 Ultrareview 背后的 Bughunter 架构。


本文基于 Claude Code CLI 源码(TypeScript,反编译自 source map)分析。源码路径:src/commands/commit.ts。如有更新,以最新版本为准。

相关推荐
码哥字节3 小时前
Claude Code 准确率从 41% 升到 89%,这个 CLAUDE.md 只做了一件事
agent·ai编程·claude
关山3 小时前
ClaudeCode 使用指北
claude
凌奕20 小时前
让你的 AI 编程助手「偷懒」:50k Star 的 Ponytail,让 Agent 少写一半代码
chatgpt·agent·claude
码哥字节1 天前
Skill 仓库本周炸榜,但 90% 工程师没分清这三个体系的本质区别
agent·claude
冬奇Lab2 天前
每日一个开源项目(第138篇):OpenMontage - 把 AI 编程助手变成完整的视频制作团队
人工智能·开源·claude
程序员辉哥2 天前
Skill精通系列之GStack-最会做决策的虚拟团队
openai·ai编程·claude
浩风祭月2 天前
Cursor + Claude Code实战:从需求分析到测试提交的完整流程
ai编程·claude·cursor
乘风gg2 天前
还在养虾吗?虾王已诞生:微信龙虾 ClawBot
前端·ai编程·claude