1138 lines
26 KiB
Markdown
1138 lines
26 KiB
Markdown
## 語義化提交
|
||
|
||
將大型變更拆分為有意義的最小單位,並按顺序使用語義化提交消息進行提交。不依賴外部工具,仅使用 git 標準命令。
|
||
|
||
### 使用方法
|
||
|
||
```bash
|
||
/semantic-commit [選項]
|
||
```
|
||
|
||
### 選項
|
||
|
||
- `--dry-run` : 不實際提交,仅顯示建議的提交拆分
|
||
- `--lang <語言>` : 強制指定提交消息語言 (en, zh-tw)
|
||
- `--max-commits <數>` : 指定最大提交數 (默認: 10)
|
||
|
||
### 基本示例
|
||
|
||
```bash
|
||
# 分析當前變更並按邏輯單位提交
|
||
/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 混合
|
||
|
||
```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
|
||
# 語言判定分數計算 (繁体字中文)
|
||
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 配置文件**
|
||
|
||
```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` 模式
|
||
- 以更小單位重新執行
|