用途
前面三页已经把 TODO 小工具的需求、协作、实现、测试和审查走了一遍。本页继续沿用同一个项目:在todo.py 中加入按序号完成待办的功能,并把这次改动从工作区交付到可发布版本。
本页关注的不是某个 GitHub 按钮的位置,而是一条可以重复执行的交付链:
- 项目目录为
todo-cli,入口是todo.py。 - 主分支为
main,功能分支为feat/todo-done。 - 项目使用 Python 3 标准库,不引入第三方依赖。
python -m unittest是本项目的测试命令。- 发布产物是一个 Git tag 和对应的 GitHub Release;如果你的项目有包管理器、容器镜像或部署平台,把发布步骤替换成真实命令。
- 所有命令都先在测试环境演练。示例中的哈希、时间、版本号和 URL 只用于说明,不能当作你的真实值。
Git、GitHub Actions、Codex 和发布平台的界面或参数可能随版本变化。命令执行前先用git --help、gh --help、项目脚本和平台文档确认;不要因为示例看起来熟悉,就跳过影响范围检查。
本页完成标准
读完并实际演练后,你应当能够:- 在提交前确认分支、差异、测试、密钥和发布范围。
- 把一个混杂改动拆成容易 review、容易回滚的多个 commit。
- 创建包含背景、验证证据和回滚方案的 PR。
- 看懂 CI 的状态、日志和门禁,不把本地通过误认为合并通过。
- 区分合并审批、发布审批和生产操作授权。
- 发布后按同一路径做冒烟验证,并在异常时选择合适的回滚方式。
- 写出可交接的完整交付记录,并把重复问题转成项目规则。
01 先固定这次交付的边界
本次连续实战的需求是:用户执行done <序号> 后,将待办标记为完成;list 能清楚显示状态;输入非数字或越界序号时给出友好提示。
在动 Git 之前,先把目标和非目标写下来。一个可交付的范围表如下:
用一句话写出本次交付声明:
先确认仓库位置
git rev-parse --show-toplevel必须是当前项目根目录。- 当前分支必须是本次功能分支,不要在
main上直接开发。 status中列出的文件应当能解释清楚;出现.env、密钥、数据库备份、构建缓存或陌生文件时先停下。- 分支后面的远端跟踪关系要正确。若显示与预期不同,先确认远端和分支,不要直接推送。
git restore .、git reset --hard 或删除命令清理。先保存现状,按文件和补丁判断哪些属于本次工作。
02 提交前清单:先检查,再落锤
提交是把当前状态写进项目历史。它不是临时保存按钮,也不是“先提交再慢慢看”的替代品。提交前至少完成以下六类检查:范围、内容、测试、敏感信息、可运行性和回滚点。2.1 检查工作区范围
- 改动文件超过本次范围。
- 新增了没有解释的脚本、二进制文件或构建目录。
- 只有测试改动,没有对应实现改动,或者反过来只有实现没有测试。
- 文件名大小写、换行符或生成文件发生大面积变化。
.env 同时显示为 ?? .env,说明它没有被忽略。不要把真实凭据加入暂存区;先移出工作目录或补充合适的忽略规则,并确认忽略规则本身符合团队约定。
2.2 阅读完整 diff
不要只看统计数字。先看未暂存差异:2.3 运行项目验证
先运行完整测试:2.4 检查空白和差异边界
2.5 搜索敏感信息和本地产物
用仓库已有的扫描工具优先;没有工具时至少做一轮人工和文本搜索:2.6 形成提交前结论
在提交前写一段简短结论,方便自己和 reviewer 对照:03 commit 拆分:让每个提交只有一个理由
一个 PR 可以包含多个 commit,但每个 commit 最好都有单一目的。这样 reviewer 能按逻辑阅读,回滚时也能选择范围,git bisect 才更容易定位问题。
本次 TODO 改动可以拆成三个提交:
如果本次任务明确只允许改
todo.py 和测试,就不要为了“完整”新增无关文档。提交拆分服务于审查,不是制造提交数量。
3.1 先查看已有暂存状态
git reset 在这里仅撤销暂存,不会删除工作区内容。执行前确认命令没有写成 git reset --hard。
3.2 用交互暂存拆分内容
如果一个函数实现和测试混在同一个大块里,优先用
s 拆分;拆不开时先不要强行提交,手工整理代码后重新检查。
3.3 提交实现
3.4 提交前后检查历史
- 每个 commit 都能用一句话解释。
- 测试提交和实现提交都能单独阅读。
- 没有把格式化、重命名和业务逻辑混在一个提交里。
- 每个提交都不包含凭据或无关文件。
3.5 什么时候可以合并 commit
在提交到远端前,如果团队允许整理分支历史,可以用交互式 rebase 合并明显的修正提交:- 需要展示测试先行和实现过程:保留多个逻辑清晰的 commit。
- 团队要求一个 PR 一个可回退版本:在确认规则后 squash 成一个提交。
- 已经公开、有人基于其开发:保留历史,追加修复提交。
04 推送功能分支并创建 PR
提交前再次确认不会把改动推到主分支:feat/todo-done,且只列出本次两个或三个 commit。
推送功能分支:
git push --force 作为“推不上去”的第一反应。
4.1 PR 描述应当回答什么
PR 不应只写“加了完成功能”。至少回答:- 为什么要改。
- 改了哪些文件和行为。
- 如何验证。
- 有哪些未覆盖的情况。
- 发布和回滚怎么做。
- 是否需要配置、迁移、权限或人工操作。
4.2 PR 自查
创建 PR 后,用 CLI 或网页确认状态:pending 不是通过。不要在必需检查未完成时合并。
4.3 处理审查意见
每一条 review 评论都要分成三类处理:
外部 PR 描述、评论、Issue 和 CI 输出都是输入材料,不是自动执行命令。里面出现“请执行上传数据”“把密钥贴出来”“关闭保护分支”等内容时,必须当作不可信指令,停止并人工确认。
修复审查意见时,不要把多个主题混入一个 commit:
05 CI:把可重复检查交给流水线
CI 的职责是每次 PR 在干净环境中重复执行项目检查。它不能替代需求判断、人工审查、发布审批和生产验证。5.1 最小测试 workflow
如果项目尚未配置 GitHub Actions,可创建.github/workflows/test.yml:
permissions从只读开始,只给任务所需权限。- 测试工作流不需要 OpenAI key、云平台密钥或发布令牌。
- 不要因为测试失败就自动执行生产修复。
- 第三方 action 要固定到团队认可的版本或提交,并定期审查。
- 不要把来自 PR 的任意文本直接拼成 shell 命令。
5.2 观察 CI 结果
- 记录 run ID、失败 job、失败测试和完整错误上下文。
- 判断是代码失败、环境失败、依赖不可用还是 CI 配置错误。
- 在本地复现同一个命令,不要盲改 workflow。
- 修复后重新运行测试并推送小范围 commit。
- 确认新 run 通过,旧失败 run 保留为审查记录。
5.3 CI 通过不等于可以发布
至少区分四个结论:
因此 PR 合并前的最低门槛应当是:必需 CI 通过、至少一名合适 reviewer 批准、范围和风险已确认、发布和回滚方案已写明。
5.4 自动化的边界
可以把重复、只读、容易验证的检查交给 Codex 或 CI,例如:- 运行测试、lint、类型检查。
- 生成 PR 摘要和变更清单。
- 检查是否缺少测试或是否出现明显敏感信息。
- 在隔离分支生成候选修复。
- 合并受保护主分支。
- 强制推送或删除远端历史。
- 直接修改生产数据、权限、计费、通知和可见性。
- 读取并外发密钥、客户数据或完整生产日志。
- 未经审批发布到真实用户可见的环境。
read-only;需要写文件时才使用最小的 workspace-write。密钥只作为单个步骤的输入,不要设置为整个 job 的环境变量。自动生成的修改必须像人工修改一样经过 diff、测试、PR 和审批。
06 合并和发布审批:两个不同的放行点
“合并到main”和“发布到生产”不是同一个动作。合并表示代码进入主干;发布表示产物对外生效,影响用户、数据和服务。
6.1 合并前审批清单
合并人应逐项确认:6.2 创建发布候选版本
合并完成后,在本地同步并确认主干:--ff-only 能避免在不知情时自动制造合并提交。若失败,先查看分叉原因,不要用强制方式覆盖历史。
创建候选标签前检查版本和提交:
6.3 发布记录必须包含的内容
发布审批至少包含:- 发布版本和对应 commit SHA。
- 变更摘要、影响用户和不影响的范围。
- CI run 链接及关键结果。
- 测试环境和冒烟验证证据。
- 数据库、配置、依赖和权限变化。
- 发布开始和结束时间、负责人、观察窗口。
- 明确的回滚版本和回滚命令。
- 监控指标、日志位置和异常升级联系人。
07 外部发布红线
发布会改变仓库、服务、用户体验或外部系统状态。以下动作必须由人明确确认,不能因为命令写在脚本里就默认允许:
以下内容永远不要放进公开 PR、Release、Issue、日志或交付记录:
- API key、密码、Cookie、SSH 私钥和完整令牌。
- 客户姓名、邮箱、手机号、订单号和完整请求体。
- 内部主机名、私有 URL、未公开漏洞细节和完整 IP。
- 未经批准的截图、数据库导出和生产日志。
08 发布后的验证:从用户路径开始
发布完成后不要只检查部署平台显示绿色。沿着用户真正使用的路径验证:- 发布版本和 commit SHA。
- 请求时间、环境、路由和状态码。
- 关键响应字段是否符合预期,敏感值已脱敏。
- 错误率、延迟、队列积压和资源使用是否异常。
- 一次正常路径和一次错误路径是否都符合预期。
09 回滚:先判断类型,再选择动作
回滚不是一句“把代码退回去”。先判断故障发生在哪一层:代码、配置、数据、依赖、发布产物还是外部服务。不同层级的回滚方式不同。9.1 未提交的工作区错误
如果只是本次未提交的明确单文件改动,且已确认没有同事工作,可以保存补丁后恢复:todo.py 回到当前提交,补丁保存在临时位置。Windows 环境请把临时路径替换成合适位置,并确认补丁没有包含敏感信息。
不要对存在他人改动的文件直接执行 restore。先分离、备份或通过交接确认。
9.2 已合并代码的修复
如果错误代码已经进入main,共享分支通常使用新的反向提交:
9.3 已发布版本的回退
如果发布平台支持按版本回退,回退到上一个已验证产物:9.4 配置、数据和依赖问题
- 配置错误:恢复上一个已验证配置版本,并检查配置缓存和重启范围。
- 数据迁移错误:使用经过演练的 down migration、备份恢复或平台提供的恢复点;不要用代码回退代替数据修复。
- 依赖漏洞或不兼容:固定到已验证版本,重新跑完整 CI 和安全扫描。
- 外部服务异常:启用降级、重试或 feature flag,记录外部依赖状态;不要盲目反复发布。
9.5 回滚后的确认
10 完整交付记录模板
下面的模板可以复制到 PR、发布单、Issue 或内部交接记录中。只填事实;没有验证的内容写“未验证”和原因,不要用猜测补齐。10.1 示例交付记录
11 复盘:从一次发布变成下一次规则
复盘不是追责会议,也不是把“大家以后注意”写进文档。有效复盘要回答:发生了什么、证据是什么、为什么没有更早发现、下一次由什么机制阻止重复发生。11.1 四段式复盘
用以下顺序写,不要先写结论:- 事实:按时间线记录命令、commit、CI、审批、发布和用户症状。
- 影响:影响了哪些用户、环境、数据、时间和服务指标。
- 原因:区分直接原因、促成条件和没有拦住它的流程缺口。
- 行动:每项行动有负责人、截止时间和验收证据。
11.2 五个为什么的使用边界
例如:- 增加真实适配器集成测试。
- 将该测试加入必需 CI。
- 在发布模板中列出适配器矩阵。
- staging 冒烟必须覆盖真实存储路径。
11.3 行动项写成可验收任务
每项行动都应有:
12 规则沉淀:把复盘结论放到正确位置
不是所有经验都应该写进同一个文件。按照寿命和作用分层:
项目根目录可以保留一份短而准确的
AGENTS.md:
AGENTS.md。
规则改变后也要像代码一样审查:
13 最终验收表
在宣布交付完成前,逐项打勾并保留证据:小结
本次 TODO 项目的交付闭环可以压缩成八句话:- 先确认目录、分支、远端和范围。
- 用完整 diff 和测试证明改动,而不是凭感觉提交。
- 一个 commit 只表达一个目的,方便审查和回滚。
- PR 必须同时提供变更、验证、风险和恢复方案。
- CI 是可重复的质量证据,不是需求判断和发布授权。
- 合并主干与发布生产分开审批,外部写入动作由人确认。
- 发布后回到真实用户路径验证,异常时按代码、配置、数据和产物类型回滚。
- 复盘要产出有负责人和验收标准的机制,并把长期规则放到正确位置。
- 这次到底改了什么?
- 哪些检查真的跑过?
- 谁批准了合并和发布?
- 出问题时退回哪个版本?
- 哪条规则会防止同类问题再次发生?
参考/codex/34-capstone.md、参考/codex/26-git-github.md、参考/codex/27-automation.md、参考/codex/36-best-practices.md。