一句话总结
/commit全部源码只有 92 行,是 Claude Code 中最精简的命令之一- 它的类型是
prompt------不做任何本地逻辑,纯靠一段 prompt + 工具白名单让 LLM 自己搞定 - 核心创新:用
!git diff HEAD`` 语法在 prompt 注入前预执行 shell 命令,让 LLM 拿到实时 diff 数据 - 只白名单了 3 个工具:
git add、git status、git 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 更好的方法
- 保持 git log 风格一致------AI 会模仿你最近 10 条 commit 的风格
- 如果想要特定格式,在 CLAUDE.md 里写 commit 规范,AI 会参考
- 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。如有更新,以最新版本为准。