commit-hygiene commit-hygiene

这个技能是关于如何保持代码提交的原子性、合理控制PR的大小,以及在Git历史中保持清晰的提交记录。它提供了何时提交的指导,以及如何拆分大型更改以保持PR的可管理性和可审查性。

DevOps 0 次安装 0 次浏览 更新于 3/5/2026

name: commit-hygiene description: Atomic commits, PR size limits, commit thresholds, stacked PRs

Commit Hygiene Skill

Load with: base.md

Purpose: Keep commits atomic, PRs reviewable, and git history clean. Advise when it’s time to commit before changes become too large.


Core Philosophy

┌─────────────────────────────────────────────────────────────────┐
│  原子提交                                                  │
│  ─────────────────────────────────────────────────────────  │
│  每次提交一个逻辑更改。                                  │
│  每个提交应该是自包含且可部署的。            │
│  如果你需要用“和”来描述它,请拆分它。                     │
├─────────────────────────────────────────────────────────────────┤
│  小PR赢                                                   │
│  ─────────────────────────────────────────────────────────  │
│  < 400行更改 = 在 < 1小时内审查                      │
│  > 1000行 = 可能被草率批准或放弃               │
│  更小的PR = 更快的审查,更少的错误,更容易的回滚        │
├─────────────────────────────────────────────────────────────────┤
│  早提交,常提交                                      │
│  ─────────────────────────────────────────────────────────────  │
│  工作代码?提交它。                                        │
│  测试通过?提交它。                                        │
│  不要等到“完成” - 在每个稳定点提交。           │
└─────────────────────────────────────────────────────────────────┘

Commit Size Thresholds

Warning Thresholds (Time to Commit!)

Metric Yellow Zone Red Zone Action
Files changed 5-10 files > 10 files 立即提交
Lines added 150-300 lines > 300 lines 立即提交
Lines deleted 100-200 lines > 200 lines 立即提交
Total changes 250-400 lines > 400 lines 立即提交
Time since last commit 30-60 min > 60 min 考虑提交

Ideal Commit Size

┌─────────────────────────────────────────────────────────────────┐
│  理想提交                                                    │
│  ─────────────────────────────────────────────────────────────  │
│  文件:1-5                                                      │
│  行数:50-200总更改                                     │
│  范围:单一逻辑工作单元                              │
│  消息:描述一件事情                                    │
└─────────────────────────────────────────────────────────────────┘

Check Current State (Run Frequently)

Quick Status Check

# 查看更改(暂存+未暂存)
git status --short

# 计算文件和行数更改
git diff --stat
git diff --cached --stat  # 仅暂存

# 获取总数
git diff --shortstat
# 示例输出:8文件更改,245插入(+),32删除(-)

Detailed Change Analysis

# 全部差异摘要及文件名
git diff --stat HEAD

# 仅数字
git diff --numstat HEAD | awk '{add+=$1; del+=$2} END {print "+"add" -"del" total:"add+del}'

# 文件更改计数
git status --porcelain | wc -l

Pre-Commit Check Script

#!/bin/bash
# scripts/check-commit-size.sh

# 阈值
MAX_FILES=10
MAX_LINES=400
WARN_FILES=5
WARN_LINES=200

# 获取统计数据
FILES=$(git status --porcelain | wc -l | tr -d ' ')
STATS=$(git diff --shortstat HEAD 2>/dev/null)
INSERTIONS=$(echo "$STATS" | grep -oE '[0-9]+ insertion' | grep -oE '[0-9]+' || echo 0)
DELETIONS=$(echo "$STATS" | grep -oE '[0-9]+ deletion' | grep -oE '[0-9]+' || echo 0)
TOTAL=$((INSERTIONS + DELETIONS))

echo "📊 当前更改:$FILES文件,+$INSERTIONS -$DELETIONS ($TOTAL总行数)"

# 检查阈值
if [ "$FILES" -gt "$MAX_FILES" ] || [ "$TOTAL" -gt "$MAX_LINES" ]; then
    echo "🔴 红色区域:立即提交!更改过大。"
    echo "  考虑拆分为多个提交。"
    exit 1
elif [ "$FILES" -gt "$WARN_FILES" ] || [ "$TOTAL" -gt "$WARN_LINES" ]; then
    echo "🟡 警告:更改越来越大。尽快提交。"
    exit 0
else
    echo "🟢 良好:更改在健康限制内。"
    exit 0
fi

When to Commit

Commit Triggers (Any One = Commit)

Trigger Example
Test passes 测试刚刚变绿 → 提交
Feature complete 完成一个功能 → 提交
Refactor done 跨文件重命名变量 → 提交
Bug fixed 修复问题 → 提交
Before switching context 即将处理其他事情 → 提交
Clean compile 代码编译/检查干净 → 提交
Threshold hit > 5文件或> 200行 → 提交

Commit Immediately If

  • ✅ 测试通过后变为红色
  • ✅ 即将进行“大更改”
  • ✅ 编码超过30分钟
  • ✅ 即将尝试一些有风险的操作
  • ✅ 当前状态是“工作”的

Don’t Wait For

  • ❌ “完美”的代码
  • ❌ 所有功能完成
  • ❌ 全部测试覆盖
  • ❌ 来自你自己的代码审查
  • ❌ 文档完成

Atomic Commit Patterns

Good Atomic Commits

✅ "Add email validation to signup form"
   - 3文件:validator.ts, signup.tsx, signup.test.ts
   - 120行更改
   - 单一目的:电子邮件验证

✅ "Fix null pointer in user lookup"
   - 2文件:userService.ts, userService.test.ts
   - 25行更改
   - 单一目的:修复一个bug

✅ "Refactor: Extract PaymentProcessor class"
   - 4文件:payment.ts → paymentProcessor.ts + 类型
   - 180行更改
   - 单一目的:重构

Bad Commits (Too Large)

❌ "Add authentication, fix bugs, update styles"
   - 25文件更改
   - 800行更改
   - 混合了多个目的

❌ "WIP"
   - 未知范围
   - 没有明确的目的
   - 难以审查/回滚

❌ "Updates"
   - 15文件更改
   - 混合了功能、修复和重构
   - 无法正确审查

Splitting Large Changes

Strategy 1: By Layer

不要一个提交包含:
  - API端点 + 数据库迁移 + 前端 + 测试

拆分为:
  1. "Add users table migration"
  2. "Add User model and repository"
  3. "Add GET /users endpoint"
  4. "Add UserList component"
  5. "Add integration tests for user flow"

Strategy 2: By Feature Slice

不要一个提交包含:
  - 用户的所有CRUD操作

拆分为:
  1. "Add create user functionality"
  2. "Add read user functionality"
  3. "Add update user functionality"
  4. "Add delete user functionality"

Strategy 3: Refactor First

不要:
  - 功能+重构混合

拆分为:
  1. "Refactor: Extract validation helpers"(无行为变化)
  2. "Add email validation using new helpers"(新功能)

Strategy 4: By Risk Level

不要一个提交包含:
  - 安全更改 + 风险更改一起

拆分为:
  1. "Update dependencies"(安全,隔离)
  2. "Migrate to new API version"(风险,分开)

PR Size Guidelines

Optimal PR Size

Metric Optimal Acceptable Too Large
Files 1-10 10-20 > 20
Lines changed 50-200 200-400 > 400
Commits 1-5 5-10 > 10
Review time < 30 min 30-60 min > 60 min

PR Size vs Defect Rate

┌─────────────────────────────────────────────────────────────────┐
│  研究发现 (Google, Microsoft研究)                  │
│  ─────────────────────────────────────────────────────────  │
│  PRs < 200行:15%缺陷率                               │
│  PRs 200-400行:23%缺陷率                             │
|  PRs > 400行:40%+缺陷率                              │
│                                                                 │
│  超过200-400行后审查质量急剧下降。              │
│  大PRs得到“LGTM”橡皮图章,而不是真正的审查。          │
└─────────────────────────────────────────────────────────────────┘

When PR is Too Large

# 创建PR前检查大小
git diff main --stat
git diff main --shortstat

# 如果太大,考虑:
# 1. 拆分为多个PR(堆叠PR)
# 2. 创建功能标志并逐步合并
# 3. 使用草稿PR进行早期反馈

Commit Message Format

Structure

<type>: <description> (50 chars max)

[optional body - wrap at 72 chars]

[optional footer]

Types

Type Use For
feat 新功能
fix Bug修复
refactor 代码更改,既不修复也不添加
test 添加/更新测试
docs 仅文档
style 格式化,无代码更改
chore 构建,配置,依赖

Examples

feat: Add email validation to signup form

fix: Prevent null pointer in user lookup

refactor: Extract PaymentProcessor class

test: Add integration tests for checkout flow

chore: Update dependencies to latest versions

Git Workflow Integration

Pre-Commit Hook for Size Check

#!/bin/bash
# .git/hooks/pre-commit

MAX_LINES=400
MAX_FILES=15

FILES=$(git diff --cached --name-only | wc -l | tr -d ' ')
STATS=$(git diff --cached --shortstat)
INSERTIONS=$(echo "$STATS" | grep -oE '[0-9]+ insertion' | grep -oE '[0-9]+' || echo 0)
DELETIONS=$(echo "$STATS" | grep -oE '[0-9]+ deletion' | grep -oE '[0-9]+' || echo 0)
TOTAL=$((INSERTIONS + DELETIONS))

if [ "$TOTAL" -gt "$MAX_LINES" ]; then
    echo "❌ 提交太大:$TOTAL行(最大:$MAX_LINES)"
    echo "   考虑拆分为更小的提交。"
    echo "   使用 'git add -p' 进行部分暂存。"
    exit 1
fi

if [ "$FILES" -gt "$MAX_FILES" ]; then
    echo "❌ 文件太多:$FILES(最大:$MAX_FILES)"
    echo "   考虑拆分为更小的提交。"
    exit 1
fi

echo "✅ 提交大小OK:$FILES文件,$TOTAL行"

Partial Staging (Split Large Changes)

# 交互式地暂存特定块
git add -p

# 暂存特定文件
git add path/to/specific/file.ts

# 预览暂存
git add -N file.ts  # 意图添加
git diff            # 查看将添加的内容
git add file.ts     # 实际添加

Unstage If Too Large

# 取消暂存所有内容
git reset HEAD

# 取消暂存特定文件
git reset HEAD path/to/file.ts

# 仅暂存本次提交所需的内容
git add -p

Claude Integration

Periodic Check During Development

Claude应在每次重大更改后运行此检查:

# 快速状态
git diff --shortstat HEAD

Claude建议提交的阈值:

条件 Claude操作
> 5文件更改 建议:“考虑提交当前更改”
> 200行更改 建议:“更改越来越大,建议提交”
> 10文件或> 400行 警告:“⚠️现在提交,以免更改变得难以管理”
测试刚刚通过 建议:“好的检查点 - 提交这些通过的测试”
重构完成 建议:“重构完成 - 在添加功能前提交”

Claude提交提醒消息

📊 状态:7文件更改,+180 -45(225总数)
💡 接近提交阈值。考虑提交当前工作。

---

📊 状态:12文件更改,+320 -80(400总数)
⚠️ 更改大!现在提交以保持PR可审查。
  建议提交:"feat: Add user authentication flow"

---

📊 状态:3文件更改,+85 -10(95总数)
✅ 测试通过。提交的好时机!
  建议提交:"fix: Validate email format on signup"

Stacked PRs (For Large Features)

当一个功能确实很大时,使用堆叠PR:

┌─────────────────────────────────────────────────────────────────┐
│  堆叠PR模式                                             │
│  ─────────────────────────────────────────────────────────────  │
│                                                                 │
│  main ─────────────────────────────────────────────────────────│
│    └── PR #1: 数据库模式(200行)← 首先审查       │
│         └── PR #2: API端点(250行)← 第二次审查   │
│              └── PR #3: 前端(300行)← 第三次审查    │
│                                                                 │
│  每个PR都可以独立审查。                           │
│  合并顺序:#1 → #2 → #3                                   │
└─────────────────────────────────────────────────────────────────┘

创建堆叠PR

# 创建基础分支
git checkout -b feature/auth-schema
# ... 做更改 ...
git commit -m "feat: Add users table schema"
git push -u origin feature/auth-schema
gh pr create --base main --title "feat: Add users table schema"

# 从第一个创建下一个分支
git checkout -b feature/auth-api
# ... 做更改 ...
git commit -m "feat: Add authentication API endpoints"
git push -u origin feature/auth-api
gh pr create --base feature/auth-schema --title "feat: Add auth API endpoints"

# 以此类推...

Checklist

提交前

  • [ ] 更改是为了一个逻辑目的
  • [ ] 测试通过(如适用)
  • [ ] 代码检查/类型检查通过
  • [ ] < 10文件更改
  • [ ] < 400行总数
  • [ ] 提交消息描述一件事情

创建PR前

  • [ ] 总行数 < 400(理想 < 200)
  • [ ] 所有提交都是原子的
  • [ ] 没有"WIP"或"fixup"提交
  • [ ] PR标题描述更改
  • [ ] 描述解释原因,而不仅仅是什么

红旗(停下来拆分)

  • ❌ 提交消息需要"和"
  • ❌ 一个提交中 > 10文件
  • ❌ 一个提交中 > 400行
  • ❌ 混合了功能、修复和重构
  • ❌ “我稍后再清理这个”

快速参考

阈值

文件:  ≤ 5 = 🟢  |  6-10 = 🟡  |  > 10 = 🔴
行数:  ≤ 200 = 🟢  |  201-400 = 🟡  |  > 400 = 🔴
时间:   ≤ 30分钟 = 🟢  |  30-60分钟 = 🟡  |  > 60分钟 = 🔴

命令

# 快速状态
git diff --shortstat HEAD

# 详细文件列表
git diff --stat HEAD

# 部分暂存
git add -p

# PR前检查
git diff main --shortstat

立即提交如果

  • ✅ 测试刚刚通过
  • ✅ > 200行更改
  • ✅ > 5文件更改
  • ✅ 即将切换任务
  • ✅ 当前状态是"工作"的