Skip to main content
Skip to content

在拉取请求中叠加 AI 生成的代码

创建一组可快速审查的小型、相互依赖的拉取请求。

大型拉取请求难以审查并造成瓶颈,尤其是在 AI 帮助短时间内生成大量代码时。 随着拉取请求大小的增加,评审质量也会下降。 审阅者可能会忽略结果、错过问题,或者拖延并将拉取请求搁置,直到拉取请求变得过时并产生合并冲突。

堆叠式拉取请求使大型代码更改便于审查。

堆栈是同一存储库中的一系列拉取请求,每个拉取请求都面向其下方的拉取请求的分支,形成位于单个分支(通常是主分支)上的有序链。 获取一组较小的拉取请求,而不是一个大型拉取请求。 由于每个拉取请求都有自己的重点差异,因此团队成员可以独立评审和批准每个层。

本教程逐步讲解如何将堆叠拉取请求与代理配合使用,以在可单独审阅的层中构建功能。 对于我们的示例,我们将考虑如何将用户身份验证添加到应用。 我们将使用 GitHub Copilot CLI 以及 gh-stack 代理技能。

先决条件

若要将 gh-stack 技能与代理配合使用,首先需要安装 GitHub CLI 以及 gh-stack CLI 扩展。 需要具备以下条件:

  • GitHub CLI (gh) 2.90.0 或更高版本,以及 Git 2.20 或更高版本。
    • 使用gh auth login对GitHub CLI进行身份验证。
  • 可以推送到的 GitHub 存储库。
  • 已安装并已登录的 GitHub Copilot CLI

在GitHub CLI中,安装gh-stack扩展和技能。

gh extension install github/gh-stack
gh skill install github/gh-stack

注意

在本教程中,如果你希望自己运行 stack 命令,而不是让 Copilot 这样做,则需要使用 GitHub CLI。

1. 在生成代码之前设计技术栈

一个好的技术栈就像建房子,从坚实的地基开始,搭建墙体框架,安装电线,然后完成石膏板安装。 每一层都依赖于下面一层。 最后,审阅者应该能够从下往上阅读拉取请求,并理解该功能是如何逐步成形的。

  • 将功能拆分为层。 每个层都应该是一个连贯的更改,可以单独审查。
    • 保持每个层都足够小,这样拉取请求可以快速审阅。 如果某个层需要较长的描述才能评审,它可能太大了。
    • 自行决定边界,或与 Copilot 一起制定计划。 无论哪种方式,堆栈的形态都由你决定。
  • 按依赖项对层进行排序。 基础性更改位于底部。 任何依赖于它们的内容都会上升。 对于身份验证,可能是:
    • 第 1 层:数据模型和迁移
    • 第 2 层:CRUD 终结点
    • 第 3 层:JWT 中间件和守卫
    • 第 4 层:集成和单元测试

示例提示

  • Propose a layered approach to add user authentication to this app. Order the layers by dependency, keeping each layer independently reviewable.
  • Review my planned layers and flag any that are too large or that depend on a branch above them.

2. 首先构建底层

使用基础创建堆栈。 上述所有内容都取决于正确获取此层。

  • 通知 Copilot 你将生成堆叠式拉取请求,并要求它基于计划生成第一层。 智能体使用 gh-stack 技能创建堆栈的第一个分支。
  • 如果希望自己创建堆栈,请直接使用 gh stack init 创建,并使用前缀来保持分支名称整洁,例如 gh stack init BRANCH-NAME-1。
  • 在继续操作之前,请查看生成的更改。 底层的错误会传播到其上方的每一个分支,因此请在继续操作之前先对底层进行检查。

示例提示

  • Start the pr-stack and build only the first layer: the user data model and migration.
  • Conduct a review of the generated code and confirm this branch contains only the data model and migration, and nothing that belongs in a later layer.

3. 将每个新代码层叠放在上面

建立基础后,一次构建一层该功能的其余部分。

  • 要求 Copilot 添加下一层并结合下方各层的上下文来实现它。 代理程序会将分支添加到分支栈顶部,并在其中提交工作。
  • 如果要自行添加分支,请使用 gh stack add BRANCH-NAME-NEXT。
  • 如果层开始增长太大,请考虑它是否偏离了计划,或者你实际上需要两个层而不是一个层。
  • 在操作过程中为每个层创建新分支,因此每个分支都保持为干净、独立的 diff。
  • 准备好创建拉取请求时,请让 Copilot 提交你的堆栈,或者如果要自行执行此操作,请使用 gh stack submit。
  • 让每个拉取请求保持独立。 重点标题和对层的简洁、有意义的描述通常足够。

示例提示

  • Add the next layer in a new branch on top: the CRUD endpoints that use the user model from the branch below.
  • This branch is getting large. Suggest how it could be split into two independently reviewable layers.

4. 在请求评审之前自行查看拉取请求

每个层都很小,使自我审查也更容易。 在让队友参与之前,先逐一检查每个分支。 审阅者应收到你已信任的更改。

  • 在每个分支上运行测试、linters 和代码扫描。 在请求评审之前,请 Copilot 帮助你根据标准检查每一层。
  • 有关全面审查 AI 生成的更改的方法,请参阅 查看 AI 生成的代码。

5. 从底部开始请求堆栈评审

生成层后,审阅者会看到较小的差异,而不是一大段代码。

  • 如果这些依赖项是紧密集成的,请要求从堆栈底部开始进行评审,以便可以在后续评审之前将更改向上集成到整个堆栈中。
  • 如果需要不同层的不同人员进行评审,审阅者可以并行工作。 一个人可以查看数据模型,而另一个人则查看终结点,并且两者都无需通读整个功能内容。

6. 根据反馈进行迭代

审阅反馈会分别落在各个图层上,而不是整个对象。 堆栈允许你将正确的层固定在原位,并将更改向上传递。

  • 要求 Copilot 修改被审阅者标记的层。 代理将移动到右侧分支,进行更改,并将其提交到该分支。 然后,它会将上面的层重新变基,以便它们包含该修复。
  • 将每个修改保留在它所属的层中。 在错误的分支上所做的更改可能会造成混乱,并在更高层引发错误。
  • 进行修复时,要求 Copilot 对上述分支进行变基,并同步这些更改。
  • 如果要自行在堆栈中移动,请使用 gh stack down、gh stack up 或 gh stack checkout BRANCH-NAME 在分支间导航。 然后,提交更改并运行 gh stack rebase --upstack 以将更改沿堆栈向上传递。

示例提示

  • A reviewer flagged that the auth service doesn't handle expired tokens. Fix that on BRANCH-NAME and test the changes.
  • I've rebased the layers above onto this fix. Check that the branch with endpoints still works with the change and flag anything that needs updating.

7. 从底层合并

叠堆按顺序合并,从基于主分支的层开始。 一次性合并层或逐个合并层,GitHub 会自动将下一层的目标重新设为指向 main。

  • 从下到上逐个合并堆栈,或者从堆栈中的任意位置开始合并,你所合并的拉取请求下方的所有分支都将从下到上合并。
  • 每个层相对于其父级的差异保持完全不变,只有基础发生变化,因此可以轻松一次合并一层,而不会影响正在进行的工作或评审。
  • 使用自动合并或合并队列,以便每个分支在批准后立即合并,并且其检查通过。 无需一次性等待整个堆栈。

一旦顶层合并,整个功能就已落地。 每个改动以小而有意识的变更形式进行审查,会比作为一个大型拉取请求(PR)更有效。

延伸阅读