mcpField
G
git-workflow-and-versioning

git-workflow-and-versioning

github.com/addyosmani开发111.5k61.4k 次安装2 周前更新
代码仓库

关于 git-workflow-and-versioning

面向团队和编码 Agent 的 Git 工作流与版本管理技能,介绍从开发到发布如何保持变更小而易审查。内容涵盖提交规范、分支、worktree、语义化版本、标签和变更日志。

主要功能

  1. 01原子提交与描述性消息
  2. 02短期功能分支
  3. 03使用 Git worktree 并行工作
  4. 04提交前检查与变更摘要
  5. 05语义化版本、标签与变更日志

适用场景

  1. 01组织渐进式代码变更
  2. 02在独立分支并行运行 Agent 工作
  3. 03审查和回退范围明确的变更
  4. 04准备可复现且有记录的发布

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/addyosmani/agent-skills --skill git-workflow-and-versioning

安装后在 Claude Code 中输入/git-workflow-and-versioning确认已加载。

详细介绍

Git 工作流与版本控制

概述

Git 是你的安全网。把提交视为保存点,把分支视为沙盒,把历史记录视为文档。AI Agent 正在高速生成代码,有纪律的版本控制机制能让变更易于管理、审查和撤销。

适用时机

始终适用。每项代码变更都通过 git 进行。

核心原则

主干开发(推荐)

始终确保 main 可部署。在短期功能分支上开展工作,并在 1-3 天内合并回主干。长期存在的开发分支是隐性成本——它们会产生分歧、引发合并冲突并延迟集成。DORA 的研究一再表明,主干开发与高绩效工程团队相关。

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

这是推荐的默认做法。采用 gitflow 或长期分支的团队,可以根据自己的分支模型调整这些原则(原子提交、小规模变更、描述性提交消息)——提交纪律比具体的分支策略更重要。

  • 开发分支会带来成本。 分支每多存在一天,合并风险就会增加。
  • 发布分支可以接受。 当你需要稳定某个版本,同时 main 继续推进时,可以使用发布分支。
  • 功能标志优于长期分支。 与其将未完成的工作留在分支上数周,不如使用标志控制后再部署。
1. 尽早提交,频繁提交

每个成功的增量都应有自己的提交。不要积累大量尚未提交的变更。

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

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

提交就是保存点。如果下一项变更导致问题,你可以立即恢复到最近一个已知正常的状态。

2. 原子提交

每次提交只做一件逻辑上的事:

# 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. 使用描述性提交消息

提交消息应说明 为什么,而不只是 做了什么:

# 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>

类型:

  • feat — 新功能
  • fix — 修复错误
  • refactor — 既不修复错误也不添加功能的代码变更
  • test — 添加或更新测试
  • docs — 仅涉及文档
  • chore — 工具、依赖项、配置
4. 将不同关注点分开

不要将格式调整与行为变更合并。不要将重构与功能开发合并。每种类型的变更都应单独提交——最好也单独提交 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"

将重构与功能开发分开。 重构变更和功能变更是两种不同的变更,应分别提交。这样每项变更都更容易审查、撤销,也更容易在历史记录中理解。小型清理(如重命名变量)可根据审查者的判断纳入功能提交。

5. 控制变更规模

每次提交/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

分支策略

功能分支
main (always deployable)
  │
  ├── feature/task-creation    ← One feature per branch
  ├── feature/user-settings    ← Parallel work
  └── fix/duplicate-tasks      ← Bug fixes
  • 从 main(或团队的默认分支)创建分支
  • 保持分支生命周期短暂(在 1-3 天内合并)——长期分支是隐性成本
  • 合并后删除分支
  • 对于未完成的功能,优先使用功能标志,而不是长期分支
分支命名
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 同时运行多个分支:

# 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 即可——不会丢失任何内容
  • 变更在明确合并之前彼此隔离

保存点模式

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 可以让你回到上一个成功状态。

变更摘要

每次修改后,都应提供结构化摘要。这有助于简化审核、记录范围约束,并揭示意外变更:

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

这种做法能及早发现错误假设,并为审核者清晰梳理变更内容。“DIDN'T TOUCH”部分尤其重要——它表明你严守范围,没有擅自进行额外改造。

提交前检查

每次提交前:

# 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 钩子自动执行这些检查:

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

处理生成文件

  • 仅在项目需要时提交生成文件(例如,package-lock.json、Prisma 迁移)
  • 不要提交构建输出(dist/、.next/)、环境文件(.env)或 IDE 配置( .vscode/settings.json,除非需要共享)
  • 添加 .gitignore 文件,涵盖:node_modules/、dist/、.env、.env.local、*.pem

使用 Git 调试

# 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

发布与版本管理

提交记录是你追踪变更的方式;版本则是使用者追踪变更的方式。一旦有其他人依赖你的代码——另一个团队、已发布的软件包、已部署的客户端——“main 分支上的最新版本”就不再足以回答“我运行的是什么版本,升级是否安全?”版本号和变更日志就是回答这个问题的契约。

语义化版本

对于有使用者的项目,使用 MAJOR.MINOR.PATCH 版本号,让数字传达含义:

  MAJOR  breaking change — consumers must change their code to upgrade
  MINOR  new functionality, backward-compatible — safe to upgrade
  PATCH  bug fix, backward-compatible — safe to upgrade

版本号是一种承诺,因此代码必须与之相符。一个改变了使用者所依赖行为的“补丁”版本,只是披着伪装的主版本变更(Hyrum 定律——参见 api-and-interface-design 技能)。如果不确定某项变更是否会破坏兼容性,就假定会;意外升级主版本的代价,远低于破坏使用者的代价。

为发布打标签,并以标签作为事实依据

发布是历史中的一个不可变节点,而不是不断变化的分支。为其打标签,以便随时重现:

git tag -a v1.4.0 -m "Release 1.4.0"
git push origin v1.4.0

从标签中获取版本号,而不是在多个分散文件中手动编辑,这样构建产物、标签和变更日志就永远不会相互矛盾。

编写面向读者的变更日志

变更日志不是 git log。它是经过整理、面向使用者的“改了什么,我是否需要关注?”的答案——按 Added / Changed / Fixed / Deprecated / Removed / Security 分类,最新内容放在最前面,每条都围绕用户影响来写,而不是内部实现细节。

## [1.4.0] - 2025-06-12
### Added
- Bulk task import via CSV
### Fixed
- Timezone drift in recurring task due dates
### Deprecated
- `GET /v1/tasks/all` — use the paginated `GET /v1/tasks` (removal in 2.0)

在实施变更的同一次改动中写好变更日志条目,此时影响还记忆犹新——不要等到发布时再从提交历史中还原。破坏性变更需要附带迁移说明和弃用期限(遵循 deprecation-and-migration 技能);实际发布工作属于 shipping-and-launch 技能的范畴——本节规定的是为其提供依据的版本管理契约。

常见借口

借口事实
“等功能做完再提交”一个巨大的提交难以审查、调试或回退。每完成一个部分就提交。
“提交说明不重要”提交说明是文档。未来的你(以及未来的 Agent)需要了解改了什么,以及为什么改。
“之后我会把它们全部压缩”压缩提交会抹去开发过程。最好从一开始就保持提交干净、循序渐进。
“分支会增加开销”短期分支不费成本,还能避免相互冲突的工作撞在一起。问题在于长期分支——应在 1-3 天内合并。
“之后我会拆分这个更改”大型更改更难审查,部署风险更高,也更难回退。应在提交审查前拆分,而不是之后。
“我不需要 .gitignore”直到包含生产环境密钥的 .env 被提交为止。立即设置它。
“这只是一个小修复,提升补丁版本就行”检查使用者能观察到什么。若行为变化影响了他们的使用,无论差异有多小,都属于重大更改。
“变更日志就是提交日志”提交记录是给你看的;变更日志是给使用者看的,应按影响筛选整理。根据原始提交记录生成变更日志,会掩盖重要内容。
“发布时再写变更日志”到那时只能凭记忆重构影响,而且会遗漏一半内容。应在更改时就写好条目。

危险信号

  • 未提交的大量更改不断累积
  • 提交说明写着“修复”“更新”“杂项”之类的内容
  • 格式更改与行为更改混在一起
  • 项目中没有 .gitignore
  • 提交了 node_modules/、.env 或构建产物
  • 长期分支与 main 差异显著
  • 对共享分支强制推送
  • 破坏性更改以次版本或补丁版本发布
  • 发布没有标签,或手动编辑的版本号与标签不一致
  • 面向用户的发布没有变更日志条目,或变更日志只是直接倾倒提交说明

验证

每次提交都要检查:

  • 提交只做一件符合逻辑的事
  • 提交说明解释原因,并遵循类型约定
  • 提交前测试通过
  • 差异中没有密钥
  • 没有混入仅涉及格式的更改
  • .gitignore 包含常见的排除项

每次发布都要检查(任何有使用者的发布):

  • 版本升级与更改相符:破坏性更改 → 主版本,新增功能 → 次版本,修复 → 补丁版本
  • 发布已打标签,且版本号从标签派生,而非手动编辑到与标签不一致
  • 变更日志包含经过筛选整理、易于阅读且按影响归类的本版本条目

评论

支持 Markdown