见过太多团队在两种极端之间摇摆:要么所有人往 main 直接推,要么搞出 develop / release / hotfix / feature 四层分支最后没人记得住规则。
小团队真正需要的只有三件事:主干随时可发布、每个改动可追溯、回滚成本低。
一、只留两条长期分支
main ──●────────●────────●──→ 随时可发布,受保护
╲ ╱ ╲ ╱
feature/* ●──●──● ●──●──● 短期分支,合并后删除
main:受保护分支,禁止直接 push,必须走 PR + 至少一个 approvefeature/xxx:从main切出,生命周期不超过 3 天
不需要 develop。持续交付的团队里,develop 只会让「已经完成但还没上线」的代码堆在那里,增加合并冲突。
二、功能分支怎么保持同步
分支活得越久,合并冲突越痛苦。规则是:每天至少同步一次 main。
git fetch origin
git rebase origin/main # 把自己的提交「挪」到最新 main 之上
rebase 的好处是历史是线性的,没有一堆「Merge branch 'main' into feature/xxx」的噪音提交。
如果 rebase 后需要强推(仅限自己的功能分支):
git push --force-with-lease
务必用 --force-with-lease 而不是 --force。前者会在远端有你不知道的新提交时拒绝推送,避免覆盖同事的工作。
⚠️ 铁律:永远不要 rebase 已经合并进
main或者多人共享的分支。共享分支用merge,私有分支用rebase。
三、合并到 main 用 squash
功能分支里可能有「修个 typo」「再试一次」「按评审意见改」这类提交。合进主干时压成一个:
# GitHub / GitLab 合并按钮选 "Squash and merge"
这样 main 上每个提交都是一个完整的、可回滚的功能单元:
a1b2c3d feat(post): 支持 Markdown 表格与任务列表
d4e5f6a fix(auth): 修正会话过期时间计算错误
9h8i7j6 perf(list): 列表查询改用覆盖索引
提交信息的规范(Conventional Commits):
<type>(<scope>): <描述>
type: feat | fix | docs | style | refactor | perf | test | chore
好处是能自动生成 changelog,也方便按类型筛选。
四、评审是流程的核心
PR 的合理大小:400 行以内。超过 800 行的 PR,评审质量会断崖式下降——没人会认真读完。
一个有效的 PR 描述模板:
## 做了什么
把首页文章列表查询从全表扫描改为覆盖索引。
## 为什么
线上 p95 从 40ms 涨到 820ms,见监控链接。
## 怎么验证
- [x] 本地跑通列表、搜索、分页
- [x] 新增 3 个查询单测
- [x] 压测对比:p95 820ms → 12ms
## 风险
需要执行 `0002_add_sort_at.sql` 迁移,回滚方案是删掉索引。
评审者的关注顺序应该是:正确性 → 边界条件 → 可读性 → 风格。不要在风格上花 80% 的评审时间,交给格式化工具。
五、常用的补救命令
改最后一次提交信息:
git commit --amend
把多个提交合成一个:
git rebase -i HEAD~3 # 把后两个的 pick 改成 squash
撤销已经推送的提交(安全做法):
git revert <sha> # 生成一个反向提交,历史完整保留
误把敏感文件提交了:
# 从历史里彻底删除(重写历史,需要全员重新拉取)
git filter-repo --path .env --invert-paths
# 然后立刻轮换所有泄露的密钥 —— 这一步不能省
找回被 reset 掉的提交:
git reflog # 找到 sha
git branch rescue <sha>
reflog 是最后的保险绳,几乎所有「提交丢了」都能救回来。
六、自动化守着底线
# .github/workflows/ci.yml
name: CI
on: [pull_request]
jobs:
check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with: { node-version: 20, cache: pnpm }
- run: pnpm install --frozen-lockfile
- run: pnpm run lint
- run: pnpm run typecheck
- run: pnpm test
CI 不绿不允许合并。把「能不能合」交给机器,把「该不该合」交给人。
一张规则速查表
| 场景 | 用什么 |
|---|---|
| 从 main 拉功能分支 | git switch -c feature/x main |
| 同步主干改动 | git rebase origin/main(私有分支) |
| 推送被 rebase 过的分支 | git push --force-with-lease |
| 合并到主干 | Squash merge |
| 共享分支同步 | git merge(不要 rebase) |
| 撤销线上提交 | git revert |
| 找回误删提交 | git reflog |
小结
分支策略的目标不是「看起来专业」,而是让这三件事变简单:看历史能懂、出问题能回滚、多人协作不互相踩。做到这三点,两条分支就够了。