# 04 · Git 工作流与 PR/Review 标准
> **目标**:定义代码如何从本地安全进入 `main`,并触发 CI/CD。课堂第一项功能必须完整演示本文件第 2 节。
---
## 1. 分支模型:GitHub Flow
```text
main 受保护,永远可部署
├─ feature/<issue>-<desc> 新功能
├─ fix/<issue>-<desc> 普通缺陷
├─ docs/<issue>-<desc> 文档
└─ chore/<issue>-<desc> 杂务/依赖/配置
```
- 只有一条长期分支:`main`。
- 日常开发必须从 `main` 开短分支,不能直接 push `main`。
- feature 分支寿命建议 ≤ 2-3 天。
- 分支命名:`<类型>/<issue号>-<英文短描述>`,例如 `feature/1-hello-api`。
---
## 2. 课堂必演示:从分支到 CD 的完整命令
> 这段是学生必须亲手跑通的一条链。不要省略 PR,不要直接 push main。
```bash
# 1. 确认在 main,并更新主干
git switch main
git pull
# 2. 从 main 开功能分支
git switch -c feature/1-first-feature
# 3. 写代码 + 写测试后,本地自检
ruff format --check .
ruff check .
pytest
# 4. 提交
git status
git add .
git commit -m "feat: add first feature"
# 5. 推送 feature 分支
git push -u origin feature/1-first-feature
# 6. 创建 PR(AI 做到这里为止)
gh pr create --base main --head feature/1-first-feature --title "feat: add first feature" --body "closes #1"
# 7. 查看 CI(AI 汇报 CI 状态后停下,等人类审核)
gh run list --limit 5
gh run watch
# 8. ★ 合并由人类执行 ★ —— 人工 Review 通过后,由人在网页点 "Merge",或人工运行:
# gh pr merge <PR号> --merge # 默认保留分支,不加 --delete-branch
# AI 不得自行合并未获批准的 PR。
# 9. 合并 main 后会触发 CD,查看部署流水线
gh run list --limit 5
```
> 如果课堂暂时没有开启分支保护,也要按这个流程演示 PR。分支保护是“强制执行”,PR 流程是“正确习惯”。
> **合并是人类的动作,不是 AI 的动作。** AI 在第 6/7 步发起 PR、汇报 CI 后必须停下;
> **只有人工 Review 通过,由人合并**,才触发 CD。AI 绝不替人按下 Merge。
> **默认保留分支**(不加 `--delete-branch`),除非人类明确要求删除已合并分支。
> **PR 必须用你本人 GitHub 账号发起**(`gh auth login` 登录的就是你本人),不要借他人账号代提。
> **⚠️ 建仓后第一件事:配置 Secrets,否则 CD 必失败。**
> 新仓库创建后(CD 第一次跑之前)立刻去
> `GitHub → Settings → Secrets and variables → Actions → New repository secret`
> 配好 `SSH_PRIVATE_KEY` / `SSH_HOST` / `SSH_USER`(详见 `05-cicd-standards.md` 第 5 节)。
> 没有数据库等部署目标时可只配 SSH 三件套。配置时机:**在合并到 main 触发 CD 之前**。
---
## 3. 认证不要混
| 动作 | 认证方式 | 说明 |
|---|---|---|
| `git push` / `git clone` | SSH 公钥或 HTTPS 凭证 | 负责搬代码 |
| `gh pr create` / `gh run list` | GitHub CLI 登录 | 负责调 GitHub API |
| CD SSH 到服务器 | GitHub Secrets 里的部署私钥 | 由 Actions runner 自动使用 |
如果 SSH 22 端口卡住,可使用 GitHub SSH 443:
```bash
ssh -T -p 443 git@ssh.github.com
git remote set-url origin ssh://git@ssh.github.com:443/<账号>/<仓库>.git
git push
```
---
## 4. 提交信息规范
采用 Conventional Commits:
| 前缀 | 含义 |
|---|---|
| `feat:` | 新功能 |
| `fix:` | 修 bug |
| `docs:` | 文档 |
| `test:` | 测试 |
| `refactor:` | 重构 |
| `ci:` | CI/CD |
| `build:` | 构建/依赖 |
| `chore:` | 杂务 |
一个 commit 只做一件事。
---
## 5. PR 通过三道闸
| 闸 | 内容 | 不通过怎么办 |
|---|---|---|
| 机器闸 | CI 全绿 | 修代码/测试/配置 |
| 人工闸 | 至少 1 人 Review | 修改并回复评论 |
| 策略闸 | 无冲突、分支保护通过 | 同步 main / 解冲突 |
PR 描述必须写:
```text
## What
这个 PR 做了什么
## Why
为什么需要
## Test
- [ ] 本地检查通过
- [ ] CI 通过
closes #<issue号>
```
---
## 6. 冲突处理
```bash
git switch main
git pull
git switch <你的分支>
git rebase main
# 如果有冲突:手动修改文件,删掉 <<<<<<< ======= >>>>>>> 标记
git add <冲突文件>
git rebase --continue
# rebase 后推送
git push --force-with-lease
```
冲突处理后必须重新跑测试。