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

26 KiB
Raw Permalink Blame History

語義化提交

將大型變更拆分為有意義的最小單位,並按顺序使用語義化提交消息進行提交。不依賴外部工具,仅使用 git 標準命令。

使用方法

/semantic-commit [選項]

選項

  • --dry-run : 不實際提交,仅顯示建議的提交拆分
  • --lang <語言> : 強制指定提交消息語言 (en, zh-tw)
  • --max-commits <數> : 指定最大提交數 (默認: 10)

基本示例

# 分析當前變更並按邏輯單位提交
/semantic-commit

# 仅確認拆分方案 (不實際提交)
/semantic-commit --dry-run

# 用英語生成提交消息
/semantic-commit --lang en

# 用繁体字中文生成提交消息
/semantic-commit --lang zh-tw

# 最多拆分為 5 個提交
/semantic-commit --max-commits 5

工作流程

  1. 變更分析: 通過 git diff HEAD 獲取所有變更
  2. 文件分類: 將變更的文件邏輯分組
  3. 提交建議: 為各組生成語義化提交消息
  4. 顺序執行: 用戶確認後,按顺序提交各組

變更拆分的核心功能

"大型變更"的檢測

以下條件被檢測為大型變更:

  1. 變更文件數: 5 個以上文件的變更
  2. 變更行數: 100 行以上的變更
  3. 多功能: 跨越 2 個以上功能區域的變更
  4. 混合模式: feat + fix + docs 混合
# 變更規模分析
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. 按功能邊界拆分
# 從目錄結構識別功能單位
git diff HEAD --name-only | cut -d'/' -f1-2 | sort | uniq
# → src/auth, src/api, components/ui 等
2. 按變更類型分離
# 新文件 vs 現有文件修改
git diff HEAD --name-status | grep '^A' # 新文件
git diff HEAD --name-status | grep '^M' # 修改文件
git diff HEAD --name-status | grep '^D' # 刪除文件
3. 依賴關系分析
# 檢測導入關系的變更
git diff HEAD | grep -E '^[+-].*import|^[+-].*require' | \
cut -d' ' -f2- | sort | uniq

文件單位的詳细分析

# 獲取變更文件列表
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 個文件以下
    • 高關聯性文件分組

輸出示例

$ /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 模式

$ /semantic-commit --dry-run

變更分析中... (DRY RUN)
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━

[顯示提交拆分建議]

  DRY RUN 模式: 不會實際執行提交
💡 要執行請去掉 --dry-run 選項重新運行

智能分析功能

1. 項目結構理解

  • package.json, Cargo.toml, pom.xml 等判斷項目類型
  • 從文件夹結構推測功能單位

2. 變更模式識別

# 檢測 Bug 修復模式
- "fix", "bug", "error" 等關鍵詞
- 異常處理的添加
- 條件分支的修改

# 檢測新功能模式
- 新文件創建
- 新方法添加
- API 端點添加

3. 依賴關系分析

  • 導入語句的變更
  • 類型定義的添加/修改
  • 與配置文件的關聯性

技術實現

使用 Git 標準命令的顺序提交實現

1. 預處理: 保存當前狀態
# 如有未暂存的變更則先重置
git reset HEAD
git status --porcelain > /tmp/original_state.txt

# 確認工作分支
CURRENT_BRANCH=$(git branch --show-current)
echo "工作分支: $CURRENT_BRANCH"
2. 按組顺序執行提交
# 讀取拆分計劃
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. 錯誤處理和回滾
# 預提交钩子失败時的處理
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. 完成後的驗證
# 確認所有變更都已提交
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. 抑制自動推送
# 注意: 不執行自動推送
echo "📝 注意: 不會自動推送"
echo "如需推送請執行以下命令:"
echo "  git push origin $CURRENT_BRANCH"

拆分算法的詳细說明

步骤 1: 初始分析
# 獲取所有變更文件並分類
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: 基于功能邊界的初始分組
# 基于目錄的分組
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: 變更內容相似性分析
# 分析各文件的變更類型
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: 基于依賴關系的調整
# 分析導入關系
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: 提交大小優化
# 調整組別大小
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: 最終分組確定
# 驗證拆分結果
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 規範

基本格式

<type>[optional scope]: <description>

[optional body]

[optional footer(s)]

標準類型

必需類型:

  • feat: 新功能 (用戶可見的功能添加)
  • fix: Bug 修復

可選類型:

  • build: 構建系統或外部依賴的變更
  • chore: 其他變更 (不影響發布)
  • ci: CI 配置文件和腳本的變更
  • docs: 仅文檔變更
  • style: 不影響代碼含義的變更 (空白、格式、分号等)
  • refactor: 既不修復 Bug 也不添加功能的代碼變更
  • perf: 性能改進
  • test: 添加或更正測試

作用域 (可選)

表示變更的影響範圍:

feat(api): 添加用戶認證端點
fix(ui): 解決按钮對齐問題
docs(readme): 更新安裝說明

Breaking Change

有 API 破坏性變更時:

feat!: 更改用戶 API 響應格式

BREAKING CHANGE: 用戶響應現在包含额外的元數據

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.jsoncommitlint 部分
# 確認配置文件示例
cat commitlint.config.mjs
cat .commitlintrc.json
grep -A 10 '"commitlint"' package.json
2. 自定義類型檢測

項目特有類型的示例:

// 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. 語言設置檢測
// 項目使用中文消息時
export default {
  rules: {
    "subject-case": [0], // 為支持中文而禁用
    "subject-max-length": [2, "always", 72], // 中文調整字符數限制
  },
};

自動分析流程

  1. 搜索配置文件

    find . -name "commitlint.config.*" -o -name ".commitlintrc.*" | head -1
    
  2. 分析現有提交

    git log --oneline -50 --pretty=format:"%s"
    
  3. 使用類型統計

    git log --oneline -100 --pretty=format:"%s" | \
    grep -oE '^[a-z]+(\([^)]+\))?' | \
    sort | uniq -c | sort -nr
    

項目規約示例

Angular 風格
feat(scope): 添加新功能
fix(scope): 修復 Bug
docs(scope): 更新文檔
Gitmoji 結合風格
✨ feat: 添加用戶注冊
🐛 fix: 解決登錄問題
📚 docs: 更新 API 文檔
中文項目
feat: 新增用戶注冊功能
fix: 修復登錄處理的 Bug
docs: 更新 API 文檔

語言判定

此命令完整的語言判定邏輯:

  1. 從 CommitLint 配置確認語言設置

    # subject-case 規則被禁用時判定為中文
    grep -E '"subject-case".*\[0\]|subject-case.*0' commitlint.config.*
    
  2. 通過 git log 分析自動判定

    # 分析最近 20 個提交的語言 (繁体字中文)
    git log --oneline -20 --pretty=format:"%s" | \
    grep -E '[一-龯]' | wc -l
    # 50% 以上是繁体字中文則使用繁体字中文模式
    
  3. 項目文件的語言設置

    # 確認 README.md 的語言 (繁体字中文)
    head -10 README.md | grep -E '[一-龯]' | wc -l
    
    # 確認 package.json 的 description(繁体字中文)
    grep -E '"description".*[一-龯]' package.json
    
  4. 變更文件內的注釋·字符串分析

    # 確認變更文件的注釋語言 (繁体字中文)
    git diff HEAD | grep -E '^[+-].*//.*[一-龯]' | wc -l
    

判定算法

# 語言判定分數計算 (繁体字中文)
ZH_TW_SCORE=0

# 1. CommitLint 配置 (+3 分)
if grep -q '"subject-case".*\[0\]' commitlint.config.* 2>/dev/null; then
  ZH_TW_SCORE=$((ZH_TW_SCORE + 3))
fi

# 2. git log 分析 (最大 +2 分)
ZH_TW_COMMITS=$(git log --oneline -20 --pretty=format:"%s" | \
  grep -cE '[一-龯]' 2>/dev/null || echo 0)
if [ $ZH_TW_COMMITS -gt 10 ]; then
  ZH_TW_SCORE=$((ZH_TW_SCORE + 2))
elif [ $ZH_TW_COMMITS -gt 5 ]; then
  ZH_TW_SCORE=$((ZH_TW_SCORE + 1))
fi

# 3. README.md 確認 (+1 分)
if head -5 README.md 2>/dev/null | grep -qE '[一-龯]'; then
  ZH_TW_SCORE=$((ZH_TW_SCORE + 1))
fi

# 4. 變更文件內容確認 (+1 分)
if git diff HEAD 2>/dev/null | grep -qE '^[+-].*[一-龯]'; then
  ZH_TW_SCORE=$((ZH_TW_SCORE + 1))
fi

# 判定: 3 分以上為繁体字中文模式
if [ $ZH_TW_SCORE -ge 3 ]; then
  LANGUAGE="zh-tw"
else
  LANGUAGE="en"
fi

設置文件自動加載

執行時的動作

命令執行時按以下顺序確認設置:

  1. 搜索 CommitLint 配置文件

    # 按以下顺序搜索,使用找到的第一個文件
    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. 分析現有提交歷史

    # 從最近的提交學習使用模式
    git log --oneline -100 --pretty=format:"%s" | \
    head -20
    

配置示例分析

標準 commitlint.config.mjs:

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"]],
  },
};

中文對應配置:

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"],
    ],
  },
};

包含自定義類型的配置:

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 分析的自動推測

    # 從最近 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 自動檢測:

# 從 packages/ 文件夹推測 scope
ls packages/ | head -10
# → api, ui, core, auth 等作為 scope 建議

框架特定規約:

// 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'
  ]]
}

企業·團隊特有規約:

// 中國企業常見模式
{
  '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 個巨大提交):

# 變更文件 (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 個提交):

# 提交 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(混合的問題提交):

# 變更文件 (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 個提交):

# 提交 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(跨功能的巨大提交):

# 變更文件 (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 個提交):

# 提交 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 模式
  • 以更小單位重新執行