# Git Workflow And Versioning

> 规范 git 工作流实践。适用于任何代码改动，也适用于提交、分支、冲突处理，或你需要在多个并行工作流之间组织代码时。

- Skill: `233i/git-workflow-and-versioning` (Agent Skill)
- Install (CLI): `npx skillmds@latest add 233i/git-workflow-and-versioning`
- Raw SKILL.md: https://api.skillmd.com/api/skills/233i/git-workflow-and-versioning/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Productivity
- Author: 233i (https://skillmd.com/u/233i)
- Updated: 2026-09-22
- Page: https://skillmd.com/skills/233i/git-workflow-and-versioning

---


# Git 工作流与版本管理

## 概览

Git 是你的安全网。把 commit 当作存档点，把 branch 当作沙箱，把历史当作文档。面对高速生成代码的 AI agent，严格的版本控制纪律，是让改动保持可管理、可评审、可回滚的关键机制。

## 何时使用

始终如此。每一项代码改动都应该经过 git。

## 核心原则

### 基于主干的开发（Trunk-Based Development，推荐）

让 `main` 始终保持可部署。使用 1-3 天内就回合并的短命 feature branch。长期存在的开发分支是一种隐性成本，它们会逐渐分叉、制造冲突，并推迟集成。DORA 的研究长期显示，trunk-based development 与高绩效工程团队显著相关。

```
main ──●──●──●──●──●──●──●──●──●──  (always deployable)
        ╲      ╱  ╲    ╱
         ●──●─╱    ●──╱    ← short-lived feature branches (1-3 days)
```

这是默认推荐做法。使用 gitflow 或长期分支的团队，也可以把这些原则迁移过去，例如原子提交、小改动、清晰描述。真正重要的是提交纪律，而不是某个固定分支模型。

- **开发分支本身就是成本。** 分支每多活一天，就多积累一天合并风险
- **发布分支可以接受。** 当你需要稳定某个版本，而 `main` 继续前进时
- **Feature flags 优于长期分支。** 相比在分支上挂几周，不如把未完成功能放在 flag 后面提前部署

### 1. 早点提交，经常提交

每个成功的增量都应该有独立 commit，不要堆出一大坨未提交改动。

```
Work pattern:
  Implement slice → Test → Verify → Commit → Next slice

Not this:
  Implement everything → Hope it works → Giant commit
```

Commit 就是存档点。下一个改动如果把东西弄坏了，你能立刻回到最后一个已知正确状态。

### 2. 原子提交

每个 commit 只做一件逻辑上的事：

```
# Good: Each commit is self-contained
git log --oneline
a1b2c3d Add task creation endpoint with validation
d4e5f6g Add task creation form component
h7i8j9k Connect form to API and add loading state
m1n2o3p Add task creation tests (unit + integration)

# Bad: Everything mixed together
git log --oneline
x1y2z3a Add task feature, fix sidebar, update deps, refactor utils
```

### 3. 描述性提交信息

Commit message 要解释 *why*，而不只是 *what*：

```
# Good: Explains intent
feat: add email validation to registration endpoint

Prevents invalid email formats from reaching the database.
Uses Zod schema validation at the route handler level,
consistent with existing validation patterns in auth.ts.

# Bad: Describes what's obvious from the diff
update auth.ts
```

**格式：**
```
<type>: <short description>

<optional body explaining why, not what>
```

**常见 type：**
- `feat`：新功能
- `fix`：bug 修复
- `refactor`：既不修 bug 也不加功能的代码改动
- `test`：补测或改测
- `docs`：纯文档改动
- `chore`：工具、依赖、配置

### 4. 把关注点分开

不要把格式化改动和行为改动混在一起，也不要把重构和功能混在一起。每一种类型的改动都应该是单独 commit，理想情况下也是单独 PR：

```
# Good: Separate concerns
git commit -m "refactor: extract validation logic to shared utility"
git commit -m "feat: add phone number validation to registration"

# Bad: Mixed concerns
git commit -m "refactor validation and add phone number field"
```

**重构和功能要分开。** 一个重构改动和一个功能改动，是两件事，应该分别提交。这样更易评审、更易回滚，历史也更容易读懂。极小的顺手清理，例如变量重命名，是否可并入功能提交，可由 reviewer 决定。

### 5. 控制改动规模

目标是每个 commit / PR 大约 100 行改动。超过约 1000 行就必须拆分。具体拆法见 `code-review-and-quality` 里的拆分策略。

```
~100 lines  → Easy to review, easy to revert
~300 lines  → Acceptable for a single logical change
~1000 lines → Split into smaller changes
```

## 分支策略

### 功能分支（Feature Branch）

```
main (always deployable)
  │
  ├── feature/task-creation    ← One feature per branch
  ├── feature/user-settings    ← Parallel work
  └── fix/duplicate-tasks      ← Bug fixes
```

- 从 `main` 或团队默认分支拉出
- 保持分支短命，1-3 天内合并
- 合并后删分支
- 对未完成功能优先用 feature flag，而不是长期挂分支

### 分支命名

```
feature/<short-description>   → feature/task-creation
fix/<short-description>       → fix/duplicate-tasks
chore/<short-description>     → chore/update-deps
refactor/<short-description>  → refactor/auth-module
```

## 使用工作树（Worktree）

做并行 AI agent 工作时，用 git worktree 同时挂多个分支：

```bash
# Create a worktree for a feature branch
git worktree add ../project-feature-a feature/task-creation
git worktree add ../project-feature-b feature/user-settings

# Each worktree is a separate directory with its own branch
# Agents can work in parallel without interfering
ls ../
  project/              ← main branch
  project-feature-a/    ← task-creation branch
  project-feature-b/    ← user-settings branch

# When done, merge and clean up
git worktree remove ../project-feature-a
```

好处：
- 多个 agent 可以并行处理不同功能
- 不需要来回切分支，每个目录自带一个分支
- 某个实验失败，直接删 worktree 就行
- 改动在明确合并前彼此隔离

## 保存点模式（Save Point）

```
Agent starts work
    │
    ├── Makes a change
    │   ├── Test passes? → Commit → Continue
    │   └── Test fails? → Revert to last commit → Investigate
    │
    ├── Makes another change
    │   ├── Test passes? → Commit → Continue
    │   └── Test fails? → Revert to last commit → Investigate
    │
    └── Feature complete → All commits form a clean history
```

这种模式保证你最多只会丢失一个增量的工作。如果 agent 开始跑偏，`git reset --hard HEAD` 能把你拉回上一个成功状态。

## 变更总结

每次修改之后，都给出结构化 summary。这样便于 review，也能证明你守住了范围边界，并帮助发现意外改动：

```
CHANGES MADE:
- src/routes/tasks.ts: Added validation middleware to POST endpoint
- src/lib/validation.ts: Added TaskCreateSchema using Zod

THINGS I DIDN'T TOUCH (intentionally):
- src/routes/auth.ts: Has similar validation gap but out of scope
- src/middleware/error.ts: Error format could be improved (separate task)

POTENTIAL CONCERNS:
- The Zod schema is strict — rejects extra fields. Confirm this is desired.
- Added zod as a dependency (72KB gzipped) — already in package.json
```

这种模式能尽早暴露错误假设，也能给 reviewer 一张清晰地图。尤其是 `DIDN'T TOUCH` 这一段，非常重要，它证明你没有顺手把任务变成大装修。

## 提交前卫生

每次 commit 前都做这些检查：

```bash
# 1. Check what you're about to commit
git diff --staged

# 2. Ensure no secrets
git diff --staged | grep -i "password\|secret\|api_key\|token"

# 3. Run tests
npm test

# 4. Run linting
npm run lint

# 5. Run type checking
npx tsc --noEmit
```

可以配 git hooks 自动化：

```json
// package.json (using lint-staged + husky)
{
  "lint-staged": {
    "*.{ts,tsx}": ["eslint --fix", "prettier --write"],
    "*.{json,md}": ["prettier --write"]
  }
}
```

## 如何处理生成文件

- **应提交生成文件**，如果项目明确需要它们，例如 `package-lock.json`、Prisma migrations
- **不要提交** 构建产物，例如 `dist/`、`.next/`，环境文件例如 `.env`，以及本地 IDE 配置，例如 `.vscode/settings.json`，除非明确要共享
- **项目必须有 `.gitignore`**，至少覆盖：`node_modules/`、`dist/`、`.env`、`.env.local`、`*.pem`

## 用 Git 做调试

```bash
# Find which commit introduced a bug
git bisect start
git bisect bad HEAD
git bisect good <known-good-commit>
# Git checkouts midpoints; run your test at each to narrow down

# View what changed recently
git log --oneline -20
git diff HEAD~5..HEAD -- src/

# Find who last changed a specific line
git blame src/services/task.ts

# Search commit messages for a keyword
git log --grep="validation" --oneline
```

## 常见自我安慰

| 自我安慰 | 现实 |
|---|---|
| “功能做完再一起提交” | 一个巨型提交几乎不可 review、不可调试、也不可安全回滚。每个切片都应该提交。 |
| “提交信息不重要” | 提交信息就是文档。未来的你和未来的 agent 都要靠它理解变更。 |
| “最后 squash 一下就行” | Squash 会抹掉开发过程的叙事。更好的做法，是从一开始就保持增量提交足够干净。 |
| “分支会增加负担” | 短命分支几乎没有负担，而且能避免冲突。真正麻烦的是长期分支。 |
| “这次大改先交上去，之后再拆” | 大改动更难 review、更危险、也更难回滚。应该在提交前拆，而不是提交后。 |
| “不需要 `.gitignore`” | 直到有一天你把带生产 secrets 的 `.env` 提交上去了。这个东西必须第一天就配好。 |

## 危险信号

- 大量未提交改动不断积累
- commit message 像 “fix”、“update”、“misc” 这种没有信息量的词
- 格式化改动和行为改动混在一起
- 项目里没有 `.gitignore`
- 把 `node_modules/`、`.env` 或构建产物提交进仓库
- 长期分支和 `main` 已严重分叉
- 对共享分支 force push

## 验证

对于每一个 commit，确认：

- [ ] 它只做一件逻辑上的事
- [ ] 提交信息说明了 why，并符合 type 约定
- [ ] 提交前测试通过
- [ ] diff 中没有 secrets
- [ ] 没有把纯格式化改动和行为改动混在一起
- [ ] `.gitignore` 覆盖了常见排除项

