Git 分支与部署指南¶
给所有开发者看。5 分钟读完,知道怎么安全开发和部署。
一句话原则¶
main分支永远可以安全部署。不要把半成品代码 merge 到 main。
我们的部署流程¶
graph LR
A[feature branch] -->|PR + review| B[main]
B -->|自动| C[test 环境<br/>us-west-2]
B -->|手动触发| D[pre 环境<br/>us-east-2]
B -->|手动触发<br/>需确认| E[prod 环境<br/>us-east-1]
style C fill:#d4edda
style D fill:#fff3cd
style E fill:#f8d7da
日常开发:三步走¶
1. 建分支¶
2. 每天同步 main¶
这一步防止冲突累积。每天做一次,冲突永远很小:
不 rebase(冲突累积):
main: ──A──B──C──D──E──
你的 branch: └──X──Y──Z── ← 基于 A,跟 main 差了 4 个 commit,冲突爆炸
每天 rebase(零冲突):
main: ──A──B──C──D──E──
你的 branch: └──X──Y──Z── ← 基于 E,始终最新,冲突为零
3. 提 PR¶
PR 必须:CI 通过 + CDK diff 无危险变更 + code review 通过。
怎么拆大 Feature¶
关键:每个 PR 独立 merge 后,不能让现有功能出问题。
❌ 错误:一个大 PR
──────────────────────────────────────────────────
PR #1: DynamoDB + SQS + Lambda + 全部逻辑 (2000 行)
merge 后半成品上线,出问题难回滚
✅ 正确:拆成 4 个安全的小 PR
──────────────────────────────────────────────────
PR #1: 加 DynamoDB table (200 行) → merge ✅ 空 table 不影响现有功能
↓
PR #2: 加 SQS queue + DLQ (200 行) → merge ✅ 空 queue 不影响现有功能
↓
PR #3: 加 Lambda (DRY_RUN=true) (400 行) → merge ✅ 存在但不工作
↓
PR #4: 启用 Lambda (DRY_RUN=false) (50 行) → merge ✅ feature 正式上线
怎么判断"能不能 merge"¶
| 场景 | 能 merge 吗 | 原因 |
|---|---|---|
| 加了 DynamoDB table,还没有代码读写它 | ✅ | 空 table 不影响任何功能 |
加了 Lambda,设了 DRY_RUN=true |
✅ | Lambda 存在但不工作 |
| 改了 Lambda handler 逻辑,只改了一半 | ❌ | 半成品逻辑会破坏正在处理的数据 |
| 改了 API 返回格式,调用方还没适配 | ❌ | 调用方会报错 |
改现有代码又没法拆? 用 feature flag:
// CDK 里先设 'false',merge 后走旧逻辑,不影响现有功能
// 等 feature 做完再改成 'true'
if (process.env.ENABLE_NEW_ANALYSIS === 'true') {
return newLogic(data);
} else {
return oldLogic(data); // 现有功能不受影响
}
大 Feature 用 Draft PR¶
当 feature 需要多天开发、无法一次性拆成小 PR 时,先开 Draft PR:
# 第一次 push 后立即开 Draft PR
gh pr create --draft --base main --title "feat: 描述"
# 每天继续开发 + push,review comments 在 PR 上积累
git push
# 全部做完后,转为 Ready for Review
gh pr ready <PR号>
为什么用 Draft PR 而不是做完再开?
| 做法 | 问题 |
|---|---|
| 做完再开 PR | 一次性 review 几千行,reviewer 痛苦,容易漏看 |
| 边做边开 Draft PR | reviewer 可以分批看,早期发现设计问题,避免返工 |
Draft PR 的好处: - GitHub 不允许 merge Draft PR,不会被误操作 - 保留完整 review 历史,不会因为 close/reopen 丢失上下文 - 队友能随时看到进度,提前提出意见 - CI 照常跑,随时知道 build 状态
紧急 Hotfix 流程¶
当 prod 出 bug 需要紧急修复时,按以下 5 步操作:
# ① 从 prod 当前版本切分支(不是从 main 切!main 上可能有新代码)
git tag --list 'prod-*' --sort=-creatordate | head -5 # 查看最近的 prod tag
git checkout -b hotfix/简短描述 prod-2026-03-04 # 从 tag 切
# ② 修 bug
git add 具体文件
git commit -m "fix: 简要描述"
git push -u origin hotfix/简短描述
# ③ 部署到 test 验证
gh workflow run deploy-test.yml -f ref=hotfix/简短描述
# ④ 验证通过后部署到 prod
gh workflow run deploy-prod.yml -f confirm=deploy-prod -f ref=hotfix/简短描述
# ⑤ 合回 main(不能忘!否则下次部署会覆盖 hotfix)
gh pr create --base main --head hotfix/简短描述 --title "fix: 合并 hotfix 回 main"
为什么从 tag 切而不是从 main 切? 因为 main 上可能有还没部署过的新代码。从 prod tag 切,保证 hotfix 分支和当前生产环境一致,不会带上任何半成品。
好习惯 vs 坏习惯¶
| ❌ 坏习惯 | ✅ 好习惯 | 为什么 |
|---|---|---|
| 半成品赶紧 merge,怕冲突 | 留在 branch 上,每天 rebase | main 永远干净,冲突不累积 |
| 一个大 PR,2000 行 | 拆成小 PR,每个独立安全 | 好 review,好回滚 |
| 一周不 rebase | 每天 git rebase origin/main |
冲突在小的时候就解决 |
| hotfix 从 main 切 | hotfix 从 prod tag 切 | 不会带上 main 上的新代码 |
| 部署完不打 tag | 每次 prod 部署自动打 tag | 永远知道 prod 跑的是哪个版本 |
用 --no-verify 跳 hooks |
修复 hook 报的错 | 不绕过类型检查和测试 |
| hotfix 忘了合回 main | 部署后立即创建 PR 合回 | 下次部署不会覆盖 hotfix |
速查:常用命令¶
| 我要做什么 | 命令 |
|---|---|
| 建 feature 分支 | git checkout -b feature/描述 |
| 每天同步 main | git fetch origin && git rebase origin/main |
| rebase 遇到冲突 | 解决冲突 → git add 文件 → git rebase --continue |
| rebase 搞乱了想撤回 | git rebase --abort |
| 提 PR | gh pr create --base main --title "feat: 描述" |
| 部署 test(指定分支) | gh workflow run deploy-test.yml -f ref=分支名 |
| 部署 prod | gh workflow run deploy-prod.yml -f confirm=deploy-prod |
| 部署 prod(指定分支) | gh workflow run deploy-prod.yml -f confirm=deploy-prod -f ref=分支名 |
| 查看 prod tag | git tag --list 'prod-*' --sort=-creatordate \| head -5 |
常见问题¶
Q:merge 和 rebase 什么时候用哪个?
简单记:同步自己的 branch 用 rebase,合并到 main 用 PR merge。
| 我要做什么 | 用什么 |
|---|---|
| 把 main 最新代码同步到我的 feature branch | git rebase origin/main |
| 把我的 feature branch 合并到 main | GitHub PR → 点 Merge |
Q:prod tag 从哪来?
每次成功部署 prod 后,CI 自动打 tag(格式 prod-YYYY-MM-DD)。手动打: