Files
gh-wasabeef-claude-code-coo…/commands/semantic-commit.md
2025-11-30 09:05:46 +08:00

1138 lines
27 KiB
Markdown
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
## 语义化提交
将大型变更拆分为有意义的最小单位,并按顺序使用语义化提交消息进行提交。不依赖外部工具,仅使用 git 标准命令。
### 使用方法
```bash
/semantic-commit [选项]
```
### 选项
- `--dry-run` : 不实际提交,仅显示建议的提交拆分
- `--lang <语言>` : 强制指定提交消息语言 (en, zh-cn)
- `--max-commits <数>` : 指定最大提交数 (默认: 10)
### 基本示例
```bash
# 分析当前变更并按逻辑单位提交
/semantic-commit
# 仅确认拆分方案 (不实际提交)
/semantic-commit --dry-run
# 用英语生成提交消息
/semantic-commit --lang en
# 用中文生成提交消息
/semantic-commit --lang zh-cn
# 最多拆分为 5 个提交
/semantic-commit --max-commits 5
```
### 工作流程
1. **变更分析**: 通过 `git diff HEAD` 获取所有变更
2. **文件分类**: 将变更的文件逻辑分组
3. **提交建议**: 为各组生成语义化提交消息
4. **顺序执行**: 用户确认后,按顺序提交各组
### 变更拆分的核心功能
#### "大型变更"的检测
以下条件被检测为大型变更:
1. **变更文件数**: 5 个以上文件的变更
2. **变更行数**: 100 行以上的变更
3. **多功能**: 跨越 2 个以上功能区域的变更
4. **混合模式**: feat + fix + docs 混合
```bash
# 变更规模分析
CHANGED_FILES=$(git diff HEAD --name-only | wc -l)
CHANGED_LINES=$(git diff HEAD --stat | tail -1 | grep -o '[0-9]\+ insertions\|[0-9]\+ deletions' | awk '{sum+=$1} END {print sum}')
if [ $CHANGED_FILES -ge 5 ] || [ $CHANGED_LINES -ge 100 ]; then
echo "检测到大型变更: 建议拆分"
fi
```
#### "有意义的最小单位"拆分策略
##### 1. 按功能边界拆分
```bash
# 从目录结构识别功能单位
git diff HEAD --name-only | cut -d'/' -f1-2 | sort | uniq
# → src/auth, src/api, components/ui 等
```
##### 2. 按变更类型分离
```bash
# 新文件 vs 现有文件修改
git diff HEAD --name-status | grep '^A' # 新文件
git diff HEAD --name-status | grep '^M' # 修改文件
git diff HEAD --name-status | grep '^D' # 删除文件
```
##### 3. 依赖关系分析
```bash
# 检测导入关系的变更
git diff HEAD | grep -E '^[+-].*import|^[+-].*require' | \
cut -d' ' -f2- | sort | uniq
```
#### 文件单位的详细分析
```bash
# 获取变更文件列表
git diff HEAD --name-only
# 分别分析各文件的变更内容
git diff HEAD -- <file>
# 判定文件的变更类型
git diff HEAD --name-status | while read status file; do
case $status in
A) echo "$file: 新建" ;;
M) echo "$file: 修改" ;;
D) echo "$file: 删除" ;;
R*) echo "$file: 重命名" ;;
esac
done
```
#### 逻辑分组的标准
1. **功能单位**: 相关功能的文件
- `src/auth/` 下的文件 → 认证功能
- `components/` 下的文件 → UI 组件
2. **变更类型**: 相同类型的变更
- 仅测试文件 → `test:`
- 仅文档 → `docs:`
- 仅配置文件 → `chore:`
3. **依赖关系**: 相互关联的文件
- 模型 + 迁移
- 组件 + 样式
4. **变更规模**: 保持适当的提交大小
- 每个提交 10 个文件以下
- 高关联性文件分组
### 输出示例
```bash
$ /semantic-commit
变更分析中...
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
检测到的变更:
• src/auth/login.ts (修改)
• src/auth/register.ts (新建)
• src/auth/types.ts (修改)
• tests/auth.test.ts (新建)
• docs/authentication.md (新建)
建议的提交拆分:
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
提交 1/3
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
消息: feat: 实现用户注册和登录系统
包含文件:
• src/auth/login.ts
• src/auth/register.ts
• src/auth/types.ts
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
提交 2/3
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
消息: test: 添加认证系统的全面测试
包含文件:
• tests/auth.test.ts
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
提交 3/3
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
消息: docs: 添加认证系统文档
包含文件:
• docs/authentication.md
是否按此拆分方案执行提交? (y/n/edit):
```
### 执行时的选项
- `y` : 按建议的拆分执行
- `n` : 取消
- `edit` : 逐个编辑提交消息
- `merge <编号 1> <编号 2>` : 合并指定的提交
- `split <编号>` : 进一步拆分指定的提交
### Dry Run 模式
```bash
$ /semantic-commit --dry-run
变更分析中... (DRY RUN)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
[显示提交拆分建议]
DRY RUN 模式: 不会实际执行提交
💡 要执行请去掉 --dry-run 选项重新运行
```
### 智能分析功能
#### 1. 项目结构理解
-`package.json`, `Cargo.toml`, `pom.xml` 等判断项目类型
- 从文件夹结构推测功能单位
#### 2. 变更模式识别
```bash
# 检测 Bug 修复模式
- "fix", "bug", "error" 等关键词
- 异常处理的添加
- 条件分支的修改
# 检测新功能模式
- 新文件创建
- 新方法添加
- API 端点添加
```
#### 3. 依赖关系分析
- 导入语句的变更
- 类型定义的添加/修改
- 与配置文件的关联性
### 技术实现
#### 使用 Git 标准命令的顺序提交实现
##### 1. 预处理: 保存当前状态
```bash
# 如有未暂存的变更则先重置
git reset HEAD
git status --porcelain > /tmp/original_state.txt
# 确认工作分支
CURRENT_BRANCH=$(git branch --show-current)
echo "工作分支: $CURRENT_BRANCH"
```
##### 2. 按组顺序执行提交
```bash
# 读取拆分计划
while IFS= read -r commit_plan; do
group_num=$(echo "$commit_plan" | cut -d':' -f1)
files=$(echo "$commit_plan" | cut -d':' -f2- | tr ' ' '\n')
echo "=== 执行提交 $group_num ==="
# 仅暂存相关文件
echo "$files" | while read file; do
if [ -f "$file" ]; then
git add "$file"
echo "暂存: $file"
fi
done
# 确认暂存状态
staged_files=$(git diff --staged --name-only)
if [ -z "$staged_files" ]; then
echo "警告: 没有暂存的文件"
continue
fi
# 生成提交消息 (LLM 分析)
commit_msg=$(generate_commit_message_for_staged_files)
# 用户确认
echo "建议的提交消息: $commit_msg"
echo "暂存的文件:"
echo "$staged_files"
read -p "执行此提交? (y/n): " confirm
if [ "$confirm" = "y" ]; then
# 执行提交
git commit -m "$commit_msg"
echo "✅ 提交 $group_num 完成"
else
# 取消暂存
git reset HEAD
echo "❌ 跳过提交 $group_num"
fi
done < /tmp/commit_plan.txt
```
##### 3. 错误处理和回滚
```bash
# 预提交钩子失败时的处理
commit_with_retry() {
local commit_msg="$1"
local max_retries=2
local retry_count=0
while [ $retry_count -lt $max_retries ]; do
if git commit -m "$commit_msg"; then
echo "✅ 提交成功"
return 0
else
echo "❌ 提交失败 (尝试 $((retry_count + 1))/$max_retries)"
# 合并预提交钩子的自动修正
if git diff --staged --quiet; then
echo "预提交钩子自动修正了变更"
git add -u
fi
retry_count=$((retry_count + 1))
fi
done
echo "❌ 提交失败。请手动确认。"
return 1
}
# 从中断恢复
resume_from_failure() {
echo "检测到中断的提交处理"
echo "当前暂存状态:"
git status --porcelain
read -p "继续处理? (y/n): " resume
if [ "$resume" = "y" ]; then
# 从最后的提交位置恢复
last_commit=$(git log --oneline -1 --pretty=format:"%s")
echo "最后的提交: $last_commit"
else
# 完全重置
git reset HEAD
echo "处理已重置"
fi
}
```
##### 4. 完成后的验证
```bash
# 确认所有变更都已提交
remaining_changes=$(git status --porcelain | wc -l)
if [ $remaining_changes -eq 0 ]; then
echo "✅ 所有变更都已提交"
else
echo "⚠️ 还有未提交的变更:"
git status --short
fi
# 显示提交历史
echo "创建的提交:"
git log --oneline -n 10 --graph
```
##### 5. 抑制自动推送
```bash
# 注意: 不执行自动推送
echo "📝 注意: 不会自动推送"
echo "如需推送请执行以下命令:"
echo " git push origin $CURRENT_BRANCH"
```
#### 拆分算法的详细说明
##### 步骤 1: 初始分析
```bash
# 获取所有变更文件并分类
git diff HEAD --name-status | while read status file; do
echo "$status:$file"
done > /tmp/changes.txt
# 按功能目录统计变更
git diff HEAD --name-only | cut -d'/' -f1-2 | sort | uniq -c
```
##### 步骤 2: 基于功能边界的初始分组
```bash
# 基于目录的分组
GROUPS=$(git diff HEAD --name-only | cut -d'/' -f1-2 | sort | uniq)
for group in $GROUPS; do
echo "=== 组别: $group ==="
git diff HEAD --name-only | grep "^$group" | head -10
done
```
##### 步骤 3: 变更内容相似性分析
```bash
# 分析各文件的变更类型
git diff HEAD --name-only | while read file; do
# 检测新函数/类的添加
NEW_FUNCTIONS=$(git diff HEAD -- "$file" | grep -c '^+.*function\|^+.*class\|^+.*def ')
# 检测 Bug 修复模式
BUG_FIXES=$(git diff HEAD -- "$file" | grep -c '^+.*fix\|^+.*bug\|^-.*error')
# 判断是否为测试文件
if [[ "$file" =~ test|spec ]]; then
echo "$file: TEST"
elif [ $NEW_FUNCTIONS -gt 0 ]; then
echo "$file: FEAT"
elif [ $BUG_FIXES -gt 0 ]; then
echo "$file: FIX"
else
echo "$file: REFACTOR"
fi
done
```
##### 步骤 4: 基于依赖关系的调整
```bash
# 分析导入关系
git diff HEAD | grep -E '^[+-].*import|^[+-].*from.*import' | \
while read line; do
echo "$line" | sed 's/^[+-]//' | awk '{print $2}'
done | sort | uniq > /tmp/imports.txt
# 相关文件的分组
git diff HEAD --name-only | while read file; do
basename=$(basename "$file" .js .ts .py)
related=$(git diff HEAD --name-only | grep "$basename" | grep -v "^$file$")
if [ -n "$related" ]; then
echo "相关文件组: $file <-> $related"
fi
done
```
##### 步骤 5: 提交大小优化
```bash
# 调整组别大小
MAX_FILES_PER_COMMIT=8
current_group=1
file_count=0
git diff HEAD --name-only | while read file; do
if [ $file_count -ge $MAX_FILES_PER_COMMIT ]; then
current_group=$((current_group + 1))
file_count=0
fi
echo "提交 $current_group: $file"
file_count=$((file_count + 1))
done
```
##### 步骤 6: 最终分组确定
```bash
# 验证拆分结果
for group in $(seq 1 $current_group); do
files=$(grep "提交 $group:" /tmp/commit_plan.txt | cut -d':' -f2-)
lines=$(echo "$files" | xargs git diff HEAD -- | wc -l)
echo "提交 $group: $(echo "$files" | wc -w) 个文件, $lines 行变更"
done
```
### Conventional Commits 规范
#### 基本格式
```text
<type>[optional scope]: <description>
[optional body]
[optional footer(s)]
```
#### 标准类型
**必需类型**:
- `feat`: 新功能 (用户可见的功能添加)
- `fix`: Bug 修复
**可选类型**:
- `build`: 构建系统或外部依赖的变更
- `chore`: 其他变更 (不影响发布)
- `ci`: CI 配置文件和脚本的变更
- `docs`: 仅文档变更
- `style`: 不影响代码含义的变更 (空白、格式、分号等)
- `refactor`: 既不修复 Bug 也不添加功能的代码变更
- `perf`: 性能改进
- `test`: 添加或修正测试
#### 作用域 (可选)
表示变更的影响范围:
```text
feat(api): 添加用户认证端点
fix(ui): 解决按钮对齐问题
docs(readme): 更新安装说明
```
#### Breaking Change
有 API 破坏性变更时:
```text
feat!: 更改用户 API 响应格式
BREAKING CHANGE: 用户响应现在包含额外的元数据
```
```text
feat(api)!: 更改认证流程
```
#### 项目规约的自动检测
**重要**: 如果存在项目特有的规约,优先使用。
##### 1. CommitLint 配置确认
自动检测以下文件的配置:
- `commitlint.config.js`
- `commitlint.config.mjs`
- `commitlint.config.cjs`
- `commitlint.config.ts`
- `.commitlintrc.js`
- `.commitlintrc.json`
- `.commitlintrc.yml`
- `.commitlintrc.yaml`
- `package.json``commitlint` 部分
```bash
# 确认配置文件示例
cat commitlint.config.mjs
cat .commitlintrc.json
grep -A 10 '"commitlint"' package.json
```
##### 2. 自定义类型检测
项目特有类型的示例:
```javascript
// commitlint.config.mjs
export default {
extends: ["@commitlint/config-conventional"],
rules: {
"type-enum": [
2,
"always",
[
"feat",
"fix",
"docs",
"style",
"refactor",
"test",
"chore",
"wip", // 进行中
"hotfix", // 紧急修复
"release", // 发布
"deps", // 依赖更新
"config", // 配置变更
],
],
},
};
```
##### 3. 语言设置检测
```javascript
// 项目使用中文消息时
export default {
rules: {
"subject-case": [0], // 为支持中文而禁用
"subject-max-length": [2, "always", 72], // 中文调整字符数限制
},
};
```
#### 自动分析流程
1. **搜索配置文件**
```bash
find . -name "commitlint.config.*" -o -name ".commitlintrc.*" | head -1
```
2. **分析现有提交**
```bash
git log --oneline -50 --pretty=format:"%s"
```
3. **使用类型统计**
```bash
git log --oneline -100 --pretty=format:"%s" | \
grep -oE '^[a-z]+(\([^)]+\))?' | \
sort | uniq -c | sort -nr
```
#### 项目规约示例
##### Angular 风格
```text
feat(scope): 添加新功能
fix(scope): 修复 Bug
docs(scope): 更新文档
```
##### Gitmoji 结合风格
```text
✨ feat: 添加用户注册
🐛 fix: 解决登录问题
📚 docs: 更新 API 文档
```
##### 中文项目
```text
feat: 新增用户注册功能
fix: 修复登录处理的 Bug
docs: 更新 API 文档
```
### 语言判定
此命令完整的语言判定逻辑:
1. **从 CommitLint 配置**确认语言设置
```bash
# subject-case 规则被禁用时判定为中文
grep -E '"subject-case".*\[0\]|subject-case.*0' commitlint.config.*
```
2. **通过 git log 分析**自动判定
```bash
# 分析最近 20 个提交的语言
git log --oneline -20 --pretty=format:"%s" | \
grep -E '[一-龥]|添加|修复|更新|删除|实现|优化|重构|测试|文档' | wc -l
# 50% 以上包含中文字符或中文技术词汇则使用中文模式
```
3. **项目文件**的语言设置
```bash
# 确认 README.md 的语言
head -10 README.md | grep -E '[一-龥]' | wc -l
# 确认 package.json 的 description
grep -E '"description".*[一-龥]' package.json
```
4. **变更文件内**的注释·字符串分析
```bash
# 确认变更文件的注释语言
git diff HEAD | grep -E '^[+-].*//.*[一-龥]|^[+-].*//.*添加|^[+-].*//.*修复|^[+-].*//.*更新' | wc -l
```
#### 判定算法
```bash
# 语言判定分数计算
CHINESE_SCORE=0
# 1. CommitLint 配置 (+3 分)
if grep -q '"subject-case".*\[0\]' commitlint.config.* 2>/dev/null; then
CHINESE_SCORE=$((CHINESE_SCORE + 3))
fi
# 2. git log 分析 (最大 +2 分)
CHINESE_COMMITS=$(git log --oneline -20 --pretty=format:"%s" | \
grep -cE '[一-龥]|添加|修复|更新|删除|实现|优化|重构|测试|文档' 2>/dev/null || echo 0)
if [ $CHINESE_COMMITS -gt 10 ]; then
CHINESE_SCORE=$((CHINESE_SCORE + 2))
elif [ $CHINESE_COMMITS -gt 5 ]; then
CHINESE_SCORE=$((CHINESE_SCORE + 1))
fi
# 3. README.md 确认 (+1 分)
if head -5 README.md 2>/dev/null | grep -qE '[一-龥]'; then
CHINESE_SCORE=$((CHINESE_SCORE + 1))
fi
# 4. 变更文件内容确认 (+1 分)
if git diff HEAD 2>/dev/null | grep -qE '^[+-].*[一-龥]|^[+-].*添加|^[+-].*修复|^[+-].*更新'; then
CHINESE_SCORE=$((CHINESE_SCORE + 1))
fi
# 判定: 3 分以上为中文模式
if [ $CHINESE_SCORE -ge 3 ]; then
LANGUAGE="zh"
else
LANGUAGE="en"
fi
```
### 设置文件自动加载
#### 执行时的动作
命令执行时按以下顺序确认设置:
1. **搜索 CommitLint 配置文件**
```bash
# 按以下顺序搜索,使用找到的第一个文件
commitlint.config.mjs
commitlint.config.js
commitlint.config.cjs
commitlint.config.ts
.commitlintrc.js
.commitlintrc.json
.commitlintrc.yml
.commitlintrc.yaml
package.json (commitlint 部分)
```
2. **解析配置内容**
- 提取可用类型列表
- 确认是否有作用域限制
- 获取消息长度限制
- 确认语言设置
3. **分析现有提交历史**
```bash
# 从最近的提交学习使用模式
git log --oneline -100 --pretty=format:"%s" | \
head -20
```
#### 配置示例分析
**标准 commitlint.config.mjs**:
```javascript
export default {
extends: ["@commitlint/config-conventional"],
rules: {
"type-enum": [
2,
"always",
["feat", "fix", "docs", "style", "refactor", "perf", "test", "chore"],
],
"scope-enum": [2, "always", ["api", "ui", "core", "auth", "db"]],
},
};
```
**中文对应配置**:
```javascript
export default {
extends: ["@commitlint/config-conventional"],
rules: {
"subject-case": [0], // 为中文禁用
"subject-max-length": [2, "always", 72],
"type-enum": [
2,
"always",
["feat", "fix", "docs", "style", "refactor", "test", "chore"],
],
},
};
```
**包含自定义类型的配置**:
```javascript
export default {
extends: ["@commitlint/config-conventional"],
rules: {
"type-enum": [
2,
"always",
[
"feat",
"fix",
"docs",
"style",
"refactor",
"test",
"chore",
"wip", // Work in Progress
"hotfix", // 紧急修复
"release", // 发布准备
"deps", // 依赖更新
"config", // 配置变更
],
],
},
};
```
#### 后备行为
找不到配置文件时:
1. **基于 git log 分析**的自动推测
```bash
# 从最近 100 个提交中提取类型
git log --oneline -100 --pretty=format:"%s" | \
grep -oE '^[a-z]+(\([^)]+\))?' | \
sort | uniq -c | sort -nr
```
2. **使用 Conventional Commits 标准**作为默认
```
feat, fix, docs, style, refactor, perf, test, chore, build, ci
```
3. **语言判定**
- 中文提交 50% 以上 → 中文模式
- 其他 → 英文模式
### 先决条件
- 在 Git 仓库内执行
- 存在未提交的变更
- 已暂存的变更会被重置
### 注意事项
- **无自动推送**: 提交后的 `git push` 需手动执行
- **不创建分支**: 在当前分支提交
- **建议备份**: 重要变更前使用 `git stash` 备份
### 项目规约的优先级
生成提交消息时的优先级:
1. **CommitLint 配置** (最优先)
- `commitlint.config.*` 文件的设置
- 自定义类型和作用域限制
- 消息长度和大小写限制
2. **现有提交历史** (第 2 优先)
- 实际使用的类型统计
- 消息语言 (中文/英文)
- 作用域使用模式
3. **项目类型** (第 3 优先)
- `package.json` → Node.js 项目
- `Cargo.toml` → Rust 项目
- `pom.xml` → Java 项目
4. **Conventional Commits 标准** (后备)
- 未找到配置时的标准行为
#### 规约检测实例
**Monorepo 的 scope 自动检测**:
```bash
# 从 packages/ 文件夹推测 scope
ls packages/ | head -10
# → api, ui, core, auth 等作为 scope 建议
```
**框架特定规约**:
```javascript
// Angular 项目情况
{
'scope-enum': [2, 'always', [
'animations', 'common', 'core', 'forms', 'http', 'platform-browser',
'platform-server', 'router', 'service-worker', 'upgrade'
]]
}
// React 项目情况
{
'scope-enum': [2, 'always', [
'components', 'hooks', 'utils', 'types', 'styles', 'api'
]]
}
```
**企业·团队特有规约**:
```javascript
// 中国企业常见模式
{
'type-enum': [2, 'always', [
'feat', 'fix', 'docs', 'style', 'refactor', 'test', 'chore',
'wip', // 进行中 (Pull Request 用)
'hotfix', // 紧急修复
'release' // 发布准备
]],
'subject-case': [0], // 中文对应
'subject-max-length': [2, 'always', 72] // 中文设置较长
}
```
### 最佳实践
1. **尊重项目规约**: 遵循现有的设置和模式
2. **小变更单位**: 1 个提交 = 1 个逻辑变更
3. **清晰的消息**: 明确说明变更内容
4. **重视关联性**: 将功能相关的文件分组
5. **分离测试**: 测试文件单独提交
6. **利用配置文件**: 引入 CommitLint 统一团队规约
### 实际拆分示例 (Before/After)
#### 示例 1: 大规模认证系统添加
**Before(1 个巨大提交):**
```bash
# 变更文件 (15 个文件850 行变更)
src/auth/login.js # 新建
src/auth/register.js # 新建
src/auth/password.js # 新建
src/auth/types.js # 新建
src/api/auth-routes.js # 新建
src/middleware/auth.js # 新建
src/database/migrations/001_users.sql # 新建
src/database/models/user.js # 新建
tests/auth/login.test.js # 新建
tests/auth/register.test.js # 新建
tests/api/auth-routes.test.js # 新建
docs/authentication.md # 新建
package.json # 依赖添加
README.md # 使用方法添加
.env.example # 环境变量示例添加
# 传统的问题提交
feat: 实现完整的用户认证系统包含登录、注册、密码重置、API 路由、数据库模型、测试和文档
```
**After(拆分为有意义的 5 个提交):**
```bash
# 提交 1: 数据库基础
feat(db): 添加用户模型和认证架构
包含文件:
- src/database/migrations/001_users.sql
- src/database/models/user.js
- src/auth/types.js
理由: 数据库结构是其他功能的基础,因此最先提交
# 提交 2: 认证逻辑
feat(auth): 实现核心认证功能
包含文件:
- src/auth/login.js
- src/auth/register.js
- src/auth/password.js
- src/middleware/auth.js
理由: 认证的核心业务逻辑批量提交
# 提交 3: API 端点
feat(api): 添加认证 API 路由
包含文件:
- src/api/auth-routes.js
理由: API 层依赖认证逻辑,因此后提交
# 提交 4: 全面测试
test(auth): 添加认证系统的全面测试
包含文件:
- tests/auth/login.test.js
- tests/auth/register.test.js
- tests/api/auth-routes.test.js
理由: 实现完成后批量添加测试
# 提交 5: 配置和文档
docs(auth): 添加认证文档和配置
包含文件:
- docs/authentication.md
- package.json
- README.md
- .env.example
理由: 文档和配置最后汇总提交
```
#### 示例 2: Bug 修复和重构混合
**Before(混合的问题提交):**
```bash
# 变更文件 (8 个文件320 行变更)
src/user/service.js # Bug 修复 + 重构
src/user/validator.js # 新建 (重构)
src/auth/middleware.js # Bug 修复
src/api/user-routes.js # Bug 修复 + 错误处理改进
tests/user.test.js # 测试添加
tests/auth.test.js # Bug 修复测试添加
docs/user-api.md # 文档更新
package.json # 依赖更新
# 问题提交
fix: 解决用户验证 Bug 并重构验证逻辑,改进错误处理
```
**After(按类型拆分为 3 个提交):**
```bash
# 提交 1: 紧急 Bug 修复
fix: 解决用户验证和认证 Bug
包含文件:
- src/user/service.js(仅 Bug 修复部分)
- src/auth/middleware.js
- tests/auth.test.js(仅 Bug 修复测试)
理由: 影响生产环境的 Bug 最优先修复
# 提交 2: 验证逻辑重构
refactor: 提取并改进用户验证逻辑
包含文件:
- src/user/service.js(重构部分)
- src/user/validator.js
- src/api/user-routes.js
- tests/user.test.js
理由: 结构改进按功能单位汇总提交
# 提交 3: 文档和依赖更新
chore: 更新文档和依赖
包含文件:
- docs/user-api.md
- package.json
理由: 开发环境整备最后汇总提交
```
#### 示例 3: 多功能并行开发
**Before(跨功能的巨大提交):**
```bash
# 变更文件 (12 个文件600 行变更)
src/user/profile.js # 新功能 A
src/user/avatar.js # 新功能 A
src/notification/email.js # 新功能 B
src/notification/sms.js # 新功能 B
src/api/profile-routes.js # 新功能 A 用 API
src/api/notification-routes.js # 新功能 B 用 API
src/dashboard/widgets.js # 新功能 C
src/dashboard/charts.js # 新功能 C
tests/profile.test.js # 新功能 A 用测试
tests/notification.test.js # 新功能 B 用测试
tests/dashboard.test.js # 新功能 C 用测试
package.json # 全功能依赖
# 问题提交
feat: 添加用户档案管理、通知系统和仪表板组件
```
**After(按功能拆分为 4 个提交):**
```bash
# 提交 1: 用户档案功能
feat(profile): 添加用户档案管理
包含文件:
- src/user/profile.js
- src/user/avatar.js
- src/api/profile-routes.js
- tests/profile.test.js
理由: 档案功能是独立的功能单位
# 提交 2: 通知系统
feat(notification): 实现邮件和短信通知
包含文件:
- src/notification/email.js
- src/notification/sms.js
- src/api/notification-routes.js
- tests/notification.test.js
理由: 通知功能是独立的功能单位
# 提交 3: 仪表板组件
feat(dashboard): 添加交互式组件和图表
包含文件:
- src/dashboard/widgets.js
- src/dashboard/charts.js
- tests/dashboard.test.js
理由: 仪表板功能是独立的功能单位
# 提交 4: 依赖和基础设施更新
chore: 为新功能更新依赖
包含文件:
- package.json
理由: 通用依赖更新最后汇总
```
### 拆分效果比较
| 项目 | Before(巨大提交) | After(适当拆分) |
| -------------- | ------------------- | ------------------- |
| **代码审查性** | ❌ 非常困难 | ✅ 各提交小巧易审查 |
| **Bug 追踪** | ❌ 问题位置难以确定 | ✅ 即时定位问题提交 |
| **回滚** | ❌ 必须整体回滚 | ✅ 精准回滚问题部分 |
| **并行开发** | ❌ 容易发生冲突 | ✅ 按功能合并容易 |
| **部署** | ❌ 功能批量部署 | ✅ 可逐步部署 |
### 故障排除
#### 提交失败时
- 确认预提交钩子
- 解决依赖关系
- 逐个文件重试
#### 拆分不当时
- 用 `--max-commits` 选项调整
- 使用手动 `edit` 模式
- 以更小单位重新执行