把一个巨大的 AI 生成 PR 拆成可评审的堆叠

回想你最近交付的一个大型功能:你把它塞进一个巨大的拉取请求(PR),还是拆成范围更小的多个 PR?多年来,开发者总在两种选择中权衡:要么让一个 PR 越长越大,最终难以评审;要么把它拆成一串小 PR,但必须手动照看、同步,并在底层引入改动后不断解决冲突。

两种方式各有代价:一种难评审,另一种难维护。当天的选择往往只是看哪一种更不痛苦。

再加上编码智能体。它们产出很快。原文援引 Gartner 的预测,到2028年,智能体将在软件开发生命周期的各阶段带来50%的生产率提升。不过,智能体无法替你决定如何组织 PR,它们反而让这项决策更必要。

下面通过一个例子,演示如何使用堆叠 PR 简化评审。

观看原文完整视频演示

具体案例:为购物助手添加产品搜索

假设你发出提示,让智能体为购物助手添加产品搜索,然后离开几分钟,再回来评审、调整并批准。但看看通常会落进这一个 PR 的内容:

  • 新的数据模型和种子数据。
  • API 路由及输入验证。
  • 客户端接线、UI,以及空结果、回退和错误状态。

所有这些,以及更多改动,都在一个超过1000行的巨大 diff 中。

官方动图:PR 改动从0行增长到1500多行

智能体主要从传统代码编写方式中训练而来,因此这也是它们默认的交付方式。让我们把这个过程走一遍。

现有 Web 应用的起点是:

  • 一个从随机句子生成器获取回复的模拟 AI 助手。
  • 产品数据不一致,硬编码并分散在各组件里。
  • 没有目录模块、API、数据层,什么都没有。
官方截图:尚无产品搜索功能的网站初始状态
原文官方演示1。

为实现该功能创建一个 issue,典型流程是创建功能分支,交给一个编码智能体,或多个自定义智能体,得到整套实现及更新后的测试的初稿。然后你阅读代码——也许读了——还需手动验证功能、作必要修改、推送并创建 PR。PR 附带一份冗长却肤浅的 AI 生成描述,你确认 CI 通过、自查 diff,再请求评审。

评审者:改了1721行!描述也没什么帮助。我晚点再看。

随后是熟悉的问题:

  • 巨大的 PR 难以评审,于是一直搁着。
  • 评审者丢失上下文,反馈质量下降。
  • 合并更慢。

功能落地前,由此展开一个手动、混乱、耗时而且易冲突的过程;最后往往在评审不足的情况下合并。

GitHub 堆叠拉取请求

堆叠 PR 提供另一种交付结构,原则很简单:拆分。不再追求用一个 PR 完整解决 issue,而是把功能拆成逻辑层,识别到达最终目标的依赖链。你和智能体可以用原生方式,把原本会成为一个巨型 PR 的工作拆成一串小、专注、能够独立评审的层。

难评审的大 PR 变成多个逻辑有序的小 PR:每个聚焦一种关注点,小到评审者可以掌握全部内容,并自然承接前一个已经评审的 PR 的必要上下文。

下面开始实现。

堆叠结构

首先设置堆叠基底。这很关键,因为堆叠管理全过程中的 CI 检查和合并规则,都会依据基底进行评估。

再找出最核心的基础工作,把它放在靠近基底的位置,即堆叠底部;依赖它的工作依次放在上层。

层/分支 交付内容 依赖
L1(feat/catalog-data) 带类型的产品目录、种子数据、验证和数据访问模块 main(堆叠基底)
L2(feat/search-api) 经过验证的 /api/products/search 端点 feat/catalog-data
L3(feat/chat-grounding) 聊天调用API,用真实产品数据回答 feat/search-api
L4(feat/grounded-ui) 产品引用卡片及状态处理 feat/chat-grounding

数据、API、接线、用户体验的独立关注点由此变得清楚,可以分别分配给不同评审者:数据负责人评审数据,UI 负责人评审体验。

GitHub 原生的堆叠 PR 支持可以从 PR 界面启动,也通过 gh stack CLI 延伸到终端。

原文官方演示2。

安装堆叠 PR CLI 扩展

运行:

gh extension install github/gh-stack

过去做到这里就可以开始工作。但现在有智能体与你协作,需要让它们学会如何创建和管理堆叠。gh-stack skills 教授的正是这些能力:

gh skill install github/gh-stack

或者使用:

npx skills add github/gh-stack
原文官方演示3。

针对本例功能,工作流中的自定义智能体各有明确工作范围,并严格限定改动范围,以得到小而单一职责的 PR。

层/分支 智能体
L1(feat/catalog-data) 数据建模智能体
L2(feat/search-api) 后端智能体
L3(feat/chat-grounding) 前端智能体
L4(feat/grounded-ui) 前端智能体

最后确认 CI 已存在。每个 PR 会依据堆叠基底进行评估,各层都运行这些检查。现在开始工作。

第一层:产品目录基础

如今许多智能体工作流会自动化地自主循环运行,但为了说明,这里按步骤介绍:

  1. 用适当提示调用数据建模智能体。
  2. 智能体用 gh init stack 初始化新堆叠,把 main 设为第一分支 feat/catalog-data 的基底。
  3. 检出分支,完成工作并运行验证。
  4. 全部检查通过就提交该层,否则继续迭代。
原文官方演示4。

第二层:产品搜索 API

流程类似:

  1. 用适当提示调用后端智能体。
  2. 智能体用 gh stack add 在第一层上增加 feat/search-api;基底是 feat/catalog-data,可以导入完成的数据访问模块。
  3. 检出分支,完成工作并运行验证。
  4. 开发者手动测试 API。
  5. API 能正常工作且全部检查通过,才提交本层,否则继续迭代。
原文官方演示5。

第三层:将聊天连接到 API

  1. 用适当提示调用前端智能体。
  2. 在第二层之上增加 feat/chat-grounding,基底是 feat/search-api。该分支具备数据访问模块和经过验证的 API。
  3. 检出分支,完成工作并运行 Playwright 浏览器测试。
  4. 全部检查通过则提交本层,否则继续迭代。
原文官方演示6。

第四层:有数据依据的 UI 与引用

第三层和第四层虽由同一个前端智能体编写,却刻意分开。UI 负责人不应被迫检查底层数据流,反之亦然。这个结构支持独立评审。

  1. 在第三层之上增加 feat/grounded-ui,基底是 feat/chat-grounding。
  2. 检出分支,完成工作并运行 Playwright 浏览器测试。
  3. 全部检查通过则提交,否则继续迭代。
原文官方演示7。

提交堆叠

四个本地堆叠分支准备好了。先用 gh stack push 推送到远程,再用 gh stack submit 在 GitHub 上创建相互关联的 PR。

原文官方演示8。

堆叠地图与每层 CI

切到 GitHub,四个 PR 已打开。每个 PR 顶部都有堆叠地图,允许单击切换到堆叠中的其他 PR。

原文官方演示9。

评审并更新堆叠

现在换到评审者视角。堆叠地图像指南针,帮助评审者在顶部和底部之间导航,最终成功合并。方向是:自上而下理解,自下而上评审。

  • 自上而下阅读以获得上下文:在开始评审时就知道最终目标,例如“我们要在聊天界面显示产品卡片”。
  • 自下而上评审:逐步建立预设检查点。理解前一层以后,后一层的实现才有意义。

无需像本例最初那样,一次评审1720多行的 PR;评审可以分成堆叠中小而自包含的目标。

作为参与循环的人类评审者,你从底部第一层开始,看到自动 Copilot Code Review(CCR)捕获了两个问题,并同意需要修复。

原文官方演示10。

底层收到了修改请求,开发者接下来:

  • 把反馈交给拥有第一层分支的数据建模智能体。
  • 应用建议,测试、提交并推送。
  • 修复落进 feat/catalog-data 后,考虑第二、第三、第四层如何随之变化。

由于 feat/catalog-data 在评审后单独推送,GitHub 标出“Some branches in this stack have diverged and must be rebased”(堆叠中的部分分支已分叉,必须变基),并显示“Unable to merge as a stack”(无法作为堆叠合并),阻止合并。

PR 页面会出现一键Rebase stack按钮。使用前要注意:网页变基在 GitHub 服务器上运行,会把提交者(committer)设为点击按钮的人,产生的提交没有签名。如果分支保护要求签名提交,这次点击就可能导致检查失败。

终端中的对应做法是运行 gh stack rebase,在本地使用自己的 Git 配置进行同样的级联变基、交互解决冲突,然后执行 gh stack push。

最后用 gh stack sync 同步堆叠,让本地与 GitHub 上的其他层赶上最新变化。

原文官方演示11。

这一整合流程先从 origin 拉取,然后将 feat/catalog-data 之上的各分支逐层变基到新提交,推送变基后的分支,并同步 GitHub PR 状态。改动由此向上传递,无需手动处理第二、第三、第四层。

回到 GitHub,所有检查重新运行并通过,堆叠地图恢复为从 main 到 feat/grounded-ui 的清晰、可合并直线。

原文官方演示12。

开始使用堆叠拉取请求

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容