# 08 M2 Git 与 CI 工作流规划 - 执行人:Git Workflow Master - 日期:2026-09-07 - 范围:第二迭代(M2 宠物健康档案)开工前的三仓状态核查、分支/提交策略、CI 扩展与防泄漏规划。**本报告只核查与规划,未改动任何代码、工作流或 mkdocs.yml。** --- ## 1. 三仓当前状态核查(2026-09-07 实测) | 仓库 | 分支 | 相对 origin | 工作区 | stash | 最新提交 CI 状态 | | --- | --- | --- | --- | --- | --- | | patbond-api | dev | 同步(fetch 后确认) | 干净 | 无 | **success**(`0d81c38`,CI / backend-test,run 6) | | patbond-flutter | dev | 同步 | 干净 | 无 | **success**(`3f8388e`,CI / flutter-gates,run 11) | | patbond-doc | main | 同步 | 干净 | 无 | **success**(`5537f92`,CI / docs-build) | CI 状态经 Gitea commit status API 逐仓核实,非转述。 **未提交内容清单:无。** 第一迭代「三仓改动长期未 commit」的教训在收官阶段已彻底闭环——包括上次报告中留给用户自决的 patbond-flutter README.md 也已入库。唯一例外是本报告文件本身(写入 patbond-doc 后为未跟踪状态),按第 3 节波次规则随下一波提交。 两处非阻塞的历史遗留(可选清理,**待拍板**): - patbond-api 本地 `master` 分支(`ff876bc`)的上游 `origin/master` 已在远端删除(`branch -vv` 显示「丢失」)。本地分支可删:`git branch -D master`(确认无独有提交后执行;`ff876bc` 是初始 README 提交,早已被 dev 包含的话可安全删除,删前用 `git merge-base --is-ancestor ff876bc dev` 核实)。 - patbond-flutter 本地 `main`(`030b11f`)与远端 `origin/main` 均落后于 dev。dev 是事实集成分支,main 处于闲置态。M2 不动它;若未来引入「main = 可发布」语义(见 2.3),届时再统一处理。 ## 2. M2 分支与提交策略 ### 2.1 现状评估 第一迭代的 trunk-based 小步直推 dev(doc 直推 main)配合本地门禁运转良好:历史线性、无合并冲突、每个提交自带验收证据。但当时 CI 尚未上线,「门禁不绿不提交」全靠自觉;现在三仓 CI 已在 push 时执行同一套门禁,且**三个 ci.yml 均已配置 `pull_request:` 触发器**——PR 合入前门禁是零成本就绪的,只差用不用。 ### 2.2 推荐方案(**待拍板**):trunk-based 为主 + 高风险改动走 PR 两人 + AI 辅助的协作模式下,日常改动走 PR 的评审收益低、流程开销高,不推荐全面切换。推荐分层: - **日常改动**(单波次内可完成、不动 schema、不动跨仓契约):**继续小步直推 dev**(doc 直推 main)。CI 在 push 后兜底,红了立即修——两人团队里一个红提交的传播面可控。 - **高风险改动强制走短命分支 + Gitea PR**,合入前 CI 必须绿。触发条件(满足其一): 1. 新增/变更 Flyway 迁移(M2 的宠物健康档案必然新增 `V3__*.sql`,首当其冲); 2. 跨仓契约变更(openapi.yaml 的破坏性修改); 3. 依赖升级、大规模重构; 4. 两人同时改同一仓库的并行期。 - 分支命名沿用规范:`feat/<主题>`、`fix/<主题>`(如 `feat/pet-health-schema`),合入后即删,不留长期分叉。 - 个人分支整理历史用 `git push --force-with-lease`;共享分支(dev/main)依旧禁止 force push、禁止改写已推送历史。 选择理由:这是对现行 `git-workflow.md` 第 9 行「何时开 feature 分支」条款的最小延伸——把「破坏性风险」具体化为可判定的清单,并利用已就绪的 PR 触发器让 CI 在合入前把关,而不是引入一套全新流程。 **配套(可选,待拍板)**:在 Gitea 仓库设置中为 dev/main 开启分支保护,勾选「合并前需状态检查通过」并选中 CI 上下文。两人团队可以不开(靠约定),开了则规则由平台强制执行,AI 辅助开发场景下多一道机械防线。 ### 2.3 暂不引入的东西 - 不引入 Git Flow / develop-release 双轨——没有版本化发布压力,dev 单集成分支足够。 - 不引入 main 发布分支语义——等 M3 有部署目标后再议。 ## 3. M2 提交节奏规范 ### 3.1 波次即提交(第一迭代教训的制度化) - **每个波次收尾时,三仓凡有改动必须 commit 并 push,push 后确认 CI 绿,才算波次闭环。** 波次报告中记录各仓提交哈希与 CI 结论(沿用第一迭代收官报告的做法)。 - 波次中途允许多次小提交(鼓励),但不允许波次结束时仍有未提交改动过夜。 - AI 会话结束前,执行者对三仓各跑一次 `git status`,把结果写进波次报告——「工作区干净」要有出处。 ### 3.2 提交信息:沿用现行约定,不引入新格式 `git-workflow.md` 已固化的「`feat/fix/refactor/docs/test/chore` 前缀 + 中文主题 + 正文验收证据 + ADR 引用」在第一迭代全程执行良好(近 20 个提交无一例外),**M2 原样沿用,不引入英文 conventional commits 或 scope 括号语法**——现行格式已具备 conventional commits 的全部实用价值(可 grep、可归类、可回溯),改格式只会割裂历史。 M2 补充一条:涉及契约的提交,正文注明对应的 openapi.yaml 版本或 doc 仓提交哈希(见 3.3)。 ### 3.3 契约先行时的三仓提交顺序 M2 采用契约先行,顺序固定为: 1. **patbond-doc 先行**:`docs/api/openapi.yaml` 的契约变更单独成提交(`docs: 宠物健康档案 API 契约(M2 波次 N)`),push 且 docs-build 绿。契约提交不与其他文档改动混杂,保证可独立引用与回退。 2. **patbond-api 跟进**:实现 + 测试成一或多个提交,正文引用 doc 仓契约提交哈希,push 且 backend-test 绿。 3. **patbond-flutter 收尾**:对接实现,正文同样引用契约哈希,push 且 flutter-gates 绿。 契约中途返工时,doc 仓允许在同波次内追加修订提交(契约未被下游消费前不算破坏性变更);一旦 api/flutter 已按某版契约合入,再改即视为破坏性修改,走 2.2 的 PR 通道。 ## 4. CI 扩展规划 ### 4.1 现状修正:任务假设的两问已被第一迭代末的事实回答 核查发现三仓 CI 均已上线且全绿,任务中「flutter 是否接入 CI」「doc 是否加 --strict 门禁」不再是开放问题: - **patbond-flutter CI 已上线并验证可行**(run 11 success)。零外部 action 约束下 Flutter SDK 进容器的方案已在 `ci.yml` 中落地:从 flutter-io.cn 镜像 curl 下载 Flutter 3.44.6 的 tar.xz,解压到挂载的 `gitea_toolcache` 卷(runner `container.options` 配置 `-v gitea_toolcache:/opt/hostedtoolcache`),首跑下载约 900MB,后续 run 复用缓存秒级就绪;pub 走 pub.flutter-io.cn。门禁为 format/analyze/test 三命令,与本地一致。 - **patbond-doc 的 `mkdocs build --strict` 门禁已上线**(apt 装 mkdocs,规避 PEP 668;docs-build success)。 - patbond-api CI 全绿(82 测试,约 3m18s),Testcontainers 经 docker.sock 挂载正常工作。 ### 4.2 M2 的 CI 增量(按优先级,均为规划,实施时再改文件) 1. **无必做项。** 三条流水线覆盖了全部本地门禁,M2 开工不被 CI 阻塞。 2. 可选——**Flutter 版本升级流程注明**:toolcache 以 `flutter-3.44.6` 目录名区分版本,升级 SDK 时改 ci.yml 中 `FLUTTER_VERSION` 即自动触发新版本下载,旧目录需手动清理卷(写入 ci-runner-setup.md 的常见问题即可,M2 内低优先)。 3. 可选——**api CI 增加 M2 迁移的守护**:`./mvnw clean test` 已覆盖 Flyway 迁移执行(Testcontainers 起真库跑迁移),无需新增步骤;只需坚持「已推送迁移不可变」规则。 4. 明确**不做**:flutter `build apk` 冒烟(耗时大、M2 无发布需求)、覆盖率门槛(先积累基线再谈阈值)。 ## 5. 敏感信息防泄漏(轻量方案规划,待拍板后实施) 现状:三仓 `.git/hooks` 均只有样例,无任何自动检查;卫生完全靠 `git-workflow.md` 约定 + 提交前人工核对。api 仓敏感配置已按 `*.sample` 模式管理(真实 `application.yml` 在 gitignore 中)。AI 辅助开发下,机械防线值得补上。零外部 action 约束下推荐两层,均为纯 shell + grep,无任何外部依赖: ### 5.1 第一层:入库的共享 pre-commit 脚本(推荐先做) - 各仓新增 `scripts/hooks/pre-commit`(入库,可评审、可演进),检查 `git diff --cached` 的暂存内容: - **文件名黑名单**:拦截 `application.yml`(非 .sample)、`.env`、`*.pem`、`*.p12`、`*.jks`、`key.properties` 等入暂存区; - **内容模式**:对暂存 diff 的新增行 grep 常见凭据特征——`BEGIN (RSA |EC )?PRIVATE KEY`、`password:`/`secret:` 后跟非占位值(排除 `changeme`、`your-*`、`` 等样例值)、长 base64/hex token 形态; - 命中即拒绝提交并打印命中行号(不打印命中内容全文,避免终端留痕)。 - 启用方式为一次性 `git config core.hooksPath scripts/hooks`(每仓每机各执行一次,写入各仓 README)。hook 可被 `--no-verify` 绕过——这是特性不是缺陷:误报时有出口,且第二层兜底。 ### 5.2 第二层:CI 侧兜底 grep(各仓 ci.yml 加一个 step) - checkout 后加一个纯 shell step,对整棵工作树跑同一套文件名/内容模式检查(复用 5.1 的脚本,保证两层规则同源),命中则 fail。零外部 action,新增耗时秒级。 - 与 pre-commit 的分工:hook 拦「即将提交的」,CI 拦「已经提交的」(含 `--no-verify` 绕过和历史遗漏的新暴露)。CI 只查工作树而不扫全历史——扫历史属一次性审计,若做一次即可,不进流水线。 ### 5.3 不推荐 - gitleaks/trufflehog 等外部工具:与零外部依赖约束冲突(需拉二进制或镜像),且对本项目的敏感面(一个 application.yml + 未来的第三方 key)而言是牛刀。 - 提交后自动改写历史清除泄漏:一旦真泄漏,正确动作是**立即轮换凭据**,再考虑历史清理——写入规范备忘即可。 ## 6. 待拍板事项汇总 | # | 事项 | 推荐 | 见 | | --- | --- | --- | --- | | 1 | M2 分支策略:trunk-based 为主 + 高风险改动(Flyway 迁移/契约破坏性变更/依赖升级/并行期)强制短命分支 + PR | 采纳 | 2.2 | | 2 | Gitea dev/main 分支保护 + 状态检查强制 | 可选,倾向开启 | 2.2 | | 3 | 提交信息格式沿用现行中文约定,不切换英文 conventional commits | 沿用 | 3.2 | | 4 | 契约先行三仓提交顺序:doc → api → flutter,契约提交独立成提交并被下游引用 | 采纳 | 3.3 | | 5 | 防泄漏两层方案(共享 pre-commit 脚本 + CI 兜底 grep) | 采纳,M2 第一波实施 | 5 | | 6 | patbond-api 本地孤儿 `master` 分支清理 | 顺手做 | 1 | 采纳后需要落实的文件改动(本报告未执行):各仓 `scripts/hooks/pre-commit` 与 ci.yml 的兜底 step、`git-workflow.md` 增补 2.2/3.1/3.3 条款、本报告挂入 mkdocs 导航。