GitHub Blog
精选
67AI 编辑部评分,满分 100

GitHub 如何用堆叠式 Pull Request 拆解 AI 生成的巨型代码

2026-08-05 00:47· 13分钟前· Julia Muiruri
跳到正文
精选理由

详细演示了用 GitHub 堆叠 PR 将 AI 生成的大 PR 拆分为逻辑层,配合 gh-stack CLI 和技能,提供可立即采用的审查优化方案。

AI 摘要

GitHub 介绍用堆叠式 Pull Request(stacked PR)解决 AI 编码智能体生成巨型代码难以审查的问题。通过将 1,000+ 行的大 diff 按数据、API、接线、UI 拆成 L1-L4 四个独立分层,每层可分配不同审查者。

正文 · AI 翻译

回想一下你最近发布的一个大功能。说实话,你是把它硬塞进一个巨大的 pull request 里,还是拆成了多个范围更小的 pull request?多年来,你一直默默地在两种选择之间纠结:要么看着一个 pull request 膨胀到审阅变成噩梦,要么把它拆成一串更小的 pull request,然后你得像保姆一样盯着它们,手动同步,每次下面引入改动时还要解开各种冲突。

两种选择都有取舍。一种难审阅,另一种难维护。你那天做的决定,倾向于选那个痛苦更少一点的选项。

现在再加上编码智能体。它们生产力极高,根据 Gartner 的预测,到 2028 年它们将在软件开发生命周期的每个阶段带来 50% 的生产力提升。但是,它们无法替你消除如何组织 pull request 的选择。它们反而放大了做出这个选择的必要性。

在这篇文章中,跟随一个示例,看看如何用堆叠式 pull request 来简化审阅。

深入来看:为购物助手添加商品搜索功能

假设你发出一个提示词,要求给购物助手添加商品搜索功能,然后走开,几分钟后——真的就是几分钟——你回来审阅、引导并批准。但仔细看看,那个单独的 pull request 里通常会落下些什么:

  • 一个新的数据模型及其种子数据
  • 一条 API 路由及其校验逻辑
  • 客户端接线、UI,以及空状态/兜底状态/错误状态

……所有这些,甚至更多,都堆在一个巨大的、超过 1000 行的 diff 里。

Animated gif showing the pull request size grow from 0 lines to over 1,500 lines.

对于很大程度上基于多年来代码传统写法训练出来的智能体来说,这种模式就是它们默认的交付方式。让我们把这个过程走一遍。

你想在一个现有的 Web 应用上添加商品搜索功能,你的初始状态是:

  • 一个模拟 AI 助手,其回复来自随机行生成器
  • 不一致的商品数据被硬编码并散落在各个组件中
  • 没有目录模块,没有 API,没有数据层——什么都没有
Screenshot of the starting state of the website without a product search.

一个 issue 被创建出来以实现该功能,典型的流程是创建一个功能分支,把它分配给一个编码智能体(或多个自定义智能体),拿到整个实现代码的第一版草稿以及更新后的测试……

视频封面视频 · 前往原文观看

……你阅读了代码(好吧,你大概只是扫了一眼代码)。然后,你仍然需要手动验证功能行为并进行必要的更新,推送并打开一个带有又长又浅的 AI 生成描述的拉取请求,确保 CI 检查通过,然后自查 diff 再请求审查者。你开始动手……

<reviewer's hat>

审查者:改了 1721 行!!这个描述没什么帮助。我晚点再看吧。

</reviewer's hat>

接下来发生的事情大家都很熟悉:

  • 这个庞大的拉取请求变得难以审查——于是它就……一直搁在那儿。
  • 审查者丢失了上下文,反馈质量也随之下降。
  • 合并变得更加缓慢。

这开启了一个手动、混乱、耗时的流程,在功能落地之前很容易产生冲突,而最终功能落地时也往往审查不足。

GitHub 堆叠式拉取请求

堆叠式拉取请求引入了一种不同且更好的交付结构。其原理很简单:分解。与其试图用一个拉取请求完整解决整个问题,不如将功能拆分成逻辑层次,并识别出达成目标所需的依赖链。这为你和你的智能体提供了一种原生的方式,将原本会落在一个巨型拉取请求中的工作,分解成一系列小而聚焦、可独立审查的层次。

那个难以审查的大型拉取请求,变成了一叠更小、逻辑有序的拉取请求,每个都只关注单一问题,小到审查者能轻松装进脑子里,并且有足够的上下文自然地从先前已审查的拉取请求中流动过来。

让我们来实现它。

堆叠结构

让我们看看分解问题并排列分层堆叠时所涉及的步骤。

首先,也是重要的一点,设置堆叠基线。这一点很关键,因为在整个堆叠管理生命周期中,CI 检查和合并规则都是针对堆叠基线来评估的。

然后,识别核心的基础工作单元,把它放在靠近基线(堆叠最底层)的位置,再把依赖它的工作分层堆叠在上面。

堆叠层(L#)/分支要交付的内容依赖
L1(feat/catalog-data)一个带种子数据、校验逻辑和数据访问模块的类型化目录main(堆叠基线)
L2(feat/search-api)经过校验的 /api/products/search 端点feat/catalog-data
L3(feat/chat-grounding)Chat 调用 API,并从真实产品数据中获取答案feat/search-api
L4(feat/grounded-ui)产品引用卡片 + 状态feat/chat-grounding

现在各个独立关注点已经清晰:数据、API、接线、用户体验,从而可以为每一层分配不同的评审人员。数据由数据负责人评审,用户体验由 UI 负责人评审。

GitHub 对堆叠式拉取请求的原生支持可以从拉取请求界面直接启动,并通过 gh stack CLI 无缝扩展到终端。

安装堆叠式拉取请求 CLI 扩展

运行以下命令:

gh extension install github/gh-stack
视频封面视频 · 前往原文观看

在远古时代,你就能直接开始干活了。但今天不行。现在有智能体在你身边协同工作。这些智能体需要学习堆叠式拉取请求的工作原理,以及如何代表你创建和管理它们。gh-stack 技能就是教它们这些的。

gh skill install github/gh-stack

或者,如果你更倾向于:

npx skills add github/gh-stack
视频封面视频 · 前往原文观看

对于上述示例中的特定功能,你的开发工作流拥有自定义智能体,每个智能体都有明确的工作流,并遵循严格的范围纪律,以实现小而单一职责的拉取请求目标。

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

设置的最后一步是确认 CI 已存在。如前所述,每个拉取请求都将针对堆叠基线进行评估,这些检查将对每一层运行。

现在,工作开始了。

第一层:数据目录基础

如今大多数智能体工作流都是自动化的,并在循环中自主执行,但为了便于说明,我们将逐步介绍每个步骤。

此时,所有智能体都已熟悉堆叠式拉取请求的工作原理,因此这一阶段的典型工作流是:

  1. 用适当的提示词调用数据建模智能体
  2. 智能体初始化一个新的堆叠,并设置第一个分支——feat/catalog-data,以 main 作为其基线,使用 gh init stack
  3. 检出分支、进行工作并运行验证
  4. (所有检查均通过)?提交该层 : 迭代
视频封面视频 · 前往原文观看

给未来评审者的备注:类型是否正确?数据是否经过验证?查询辅助函数是否安全?句号。

第二层:产品搜索 API

遵循类似流程:

  1. 用适当的提示词调用后端智能体
  2. 智能体在第一层基础 `feat/catalog-data` 之上添加下一层 `feat/search-api`,通过 `gh stack add` 导入已完成的数据访问模块。
  3. 检出代码,运行验证,一切正常。
  4. 开发者手动测试 API。
  5. (API 正常 && 所有检查通过)?提交该层:迭代。
视频封面视频 · 前往原文观看

给未来的审查者备注:输入是否经过验证?响应契约是否稳定?错误/空状态是在这里处理还是推给下游?完毕。

第三层:将聊天功能接入 API

在下一层中,你需要:

  1. 用合适的提示词调用 Frontend 智能体
  2. 智能体在第二层基础之上添加下一层 `feat/chat-grounding`。其基础分支为 `feat/search-api`,该分支将同时包含数据访问模块和已验证的 API。
  3. 检出代码,运行验证,并用 Playwright 运行浏览器测试。
  4. (所有检查通过)?提交该层:迭代。
视频封面视频 · 前往原文观看

给未来的审查者备注:每个回答是否都能追溯到真实的 API 响应?当 API 失败或返回空结果时会发生什么?完毕。

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

你会注意到第三层和第四层虽然作者相同(都是 Frontend 智能体),但分层方式截然不同。这是有意为之。UI 的负责人不应该需要检查底层数据流,反之亦然,这种结构正好保证了这种独立性。

于是,Frontend 智能体:

  1. 在第三层基础之上添加下一层 `feat/grounded-ui`,其基础分支为 `feat/chat-grounding`。
  2. 检出代码,运行验证,并用 Playwright 运行浏览器测试。
  3. (所有检查通过)?提交该层:迭代。
视频封面视频 · 前往原文观看

给未来的审查者备注:每条引用是否都能链接回真实产品?加载、空状态和错误状态是否都已覆盖?完毕。

提交整个栈

四个本地堆叠分支已就绪。下一步是用 `gh stack push` 将它们推送到远程,然后用 `gh stack submit` 在 GitHub 上创建相互关联的拉取请求。

视频封面视频 · 前往原文观看

栈映射图与每一层的 CI

切换到 GitHub 界面,四个拉取请求都已打开,在每个请求的顶部你都能看到栈映射图,这是一个在栈内各拉取请求之间一键导航的系统。

视频封面视频 · 前往原文观看

审查与更新栈

是时候换个角色,从审查者的视角来看待堆叠式拉取请求的流程了。

<reviewer’s hat on>

栈映射(stack map)是评审者手中的指南针——在栈顶与栈底之间提供导航,指引变更走向成功合并。其移动方向是明确的:自上而下阅读,自下而上评审。

  • 自上而下阅读,是为了获取上下文。这样你在评审过程一开始就能看到最终目标,从而确定方向。“哦,原来我们是想在聊天界面上展示产品卡片。”
  • 自下而上评审,是为了在既定检查点上逐层推进。只有理解了前一层,后一层的实现才有意义。

你不再需要像我们示例中那样,一次性评审一个超过 1,720 行的巨型 pull request,而是可以将评审分散到栈中一个个小而完整的独立目标上。

视频封面视频 · 前往原文观看

作为被指定的人工介入评审者,你进入后先看第一层,也就是栈底的那个 pull request,发现自动化的 Copilot Code Review(CCR)捕获了两个问题,而你也同意这两个问题应当修复。

<developer's hat back on>

变更请求发生在栈底,于是你:

  • 将反馈交给第一层的作者——负责该分支的数据建模智能体
  • 建议被采纳、测试、提交并推送
  • 一旦修复落地到 feat/catalog-data 分支,自然而然的下一个问题是:这对第二层、第三层和第四层意味着什么?

由于 feat/catalog-data 分支在评审之后被插队推送,GitHub 会明确标记:“此栈中的部分分支已分叉,必须进行变基(rebase)”,并同时显示“无法作为栈合并”的标记,从而阻止合并。

视频封面视频 · 前往原文观看

回到 GitHub 的 pull request 界面上,会出现一个一键式的 Rebase stack 按钮。在使用该按钮之前,有一点值得注意。通过该按钮触发基于 Web 的变基操作会在 GitHub 的服务器上执行,这意味着它会将提交者重置为点击按钮的那个人,生成的提交不会被签名,如果分支保护要求签名提交,那么这一键点击就会悄悄出问题。

更安全的等效做法是在终端中执行 `gh stack rebase`,在本地完成同样的级联变基,同时交互式解决冲突,但这次使用的是你自己的 Git 配置,然后再执行 `gh stack push`。

最后,你需要在整个栈中向上传播变更。栈的其余部分——无论是本地还是 GitHub 上——现在都需要跟上,而最简便的方式莫过于一条同步命令:`gh stack sync`。

这一站式流程从拉取远端更新开始,将 `feat/catalog-data` 之上每一层分支的变基操作级联应用到新提交上,推送变基后的分支,并从 GitHub 同步拉取请求状态。这样一来,变更会逐层向上传递,无需任何人手动触碰第二、第三或第四层。

回到 GitHub 上,所有检查都会重新运行并通过,栈图也会恢复成一条从 `main` 到 `feat/grounded-ui` 的干净、可合并的直线。

视频封面视频 · 前往原文观看

开始使用堆叠式拉取请求 >

GitHub 如何用堆叠式 Pull Request 拆解 AI 生成的巨型代码

GitHub Blog·2026-08-05 00:47·13分钟前·Julia Muiruri
阅读原文· github.blog(在新标签页打开)
精选理由

详细演示了用 GitHub 堆叠 PR 将 AI 生成的大 PR 拆分为逻辑层,配合 gh-stack CLI 和技能,提供可立即采用的审查优化方案。

AI 摘要

GitHub 介绍用堆叠式 Pull Request(stacked PR)解决 AI 编码智能体生成巨型代码难以审查的问题。通过将 1,000+ 行的大 diff 按数据、API、接线、UI 拆成 L1-L4 四个独立分层,每层可分配不同审查者。

正文 · AI 翻译

回想一下你最近发布的一个大功能。说实话,你是把它硬塞进一个巨大的 pull request 里,还是拆成了多个范围更小的 pull request?多年来,你一直默默地在两种选择之间纠结:要么看着一个 pull request 膨胀到审阅变成噩梦,要么把它拆成一串更小的 pull request,然后你得像保姆一样盯着它们,手动同步,每次下面引入改动时还要解开各种冲突。

两种选择都有取舍。一种难审阅,另一种难维护。你那天做的决定,倾向于选那个痛苦更少一点的选项。

现在再加上编码智能体。它们生产力极高,根据 Gartner 的预测,到 2028 年它们将在软件开发生命周期的每个阶段带来 50% 的生产力提升。但是,它们无法替你消除如何组织 pull request 的选择。它们反而放大了做出这个选择的必要性。

在这篇文章中,跟随一个示例,看看如何用堆叠式 pull request 来简化审阅。

深入来看:为购物助手添加商品搜索功能

假设你发出一个提示词,要求给购物助手添加商品搜索功能,然后走开,几分钟后——真的就是几分钟——你回来审阅、引导并批准。但仔细看看,那个单独的 pull request 里通常会落下些什么:

  • 一个新的数据模型及其种子数据
  • 一条 API 路由及其校验逻辑
  • 客户端接线、UI,以及空状态/兜底状态/错误状态

……所有这些,甚至更多,都堆在一个巨大的、超过 1000 行的 diff 里。

Animated gif showing the pull request size grow from 0 lines to over 1,500 lines.

对于很大程度上基于多年来代码传统写法训练出来的智能体来说,这种模式就是它们默认的交付方式。让我们把这个过程走一遍。

你想在一个现有的 Web 应用上添加商品搜索功能,你的初始状态是:

  • 一个模拟 AI 助手,其回复来自随机行生成器
  • 不一致的商品数据被硬编码并散落在各个组件中
  • 没有目录模块,没有 API,没有数据层——什么都没有
Screenshot of the starting state of the website without a product search.

一个 issue 被创建出来以实现该功能,典型的流程是创建一个功能分支,把它分配给一个编码智能体(或多个自定义智能体),拿到整个实现代码的第一版草稿以及更新后的测试……

视频封面视频 · 前往原文观看

……你阅读了代码(好吧,你大概只是扫了一眼代码)。然后,你仍然需要手动验证功能行为并进行必要的更新,推送并打开一个带有又长又浅的 AI 生成描述的拉取请求,确保 CI 检查通过,然后自查 diff 再请求审查者。你开始动手……

<reviewer's hat>

审查者:改了 1721 行!!这个描述没什么帮助。我晚点再看吧。

</reviewer's hat>

接下来发生的事情大家都很熟悉:

  • 这个庞大的拉取请求变得难以审查——于是它就……一直搁在那儿。
  • 审查者丢失了上下文,反馈质量也随之下降。
  • 合并变得更加缓慢。

这开启了一个手动、混乱、耗时的流程,在功能落地之前很容易产生冲突,而最终功能落地时也往往审查不足。

GitHub 堆叠式拉取请求

堆叠式拉取请求引入了一种不同且更好的交付结构。其原理很简单:分解。与其试图用一个拉取请求完整解决整个问题,不如将功能拆分成逻辑层次,并识别出达成目标所需的依赖链。这为你和你的智能体提供了一种原生的方式,将原本会落在一个巨型拉取请求中的工作,分解成一系列小而聚焦、可独立审查的层次。

那个难以审查的大型拉取请求,变成了一叠更小、逻辑有序的拉取请求,每个都只关注单一问题,小到审查者能轻松装进脑子里,并且有足够的上下文自然地从先前已审查的拉取请求中流动过来。

让我们来实现它。

堆叠结构

让我们看看分解问题并排列分层堆叠时所涉及的步骤。

首先,也是重要的一点,设置堆叠基线。这一点很关键,因为在整个堆叠管理生命周期中,CI 检查和合并规则都是针对堆叠基线来评估的。

然后,识别核心的基础工作单元,把它放在靠近基线(堆叠最底层)的位置,再把依赖它的工作分层堆叠在上面。

堆叠层(L#)/分支要交付的内容依赖
L1(feat/catalog-data)一个带种子数据、校验逻辑和数据访问模块的类型化目录main(堆叠基线)
L2(feat/search-api)经过校验的 /api/products/search 端点feat/catalog-data
L3(feat/chat-grounding)Chat 调用 API,并从真实产品数据中获取答案feat/search-api
L4(feat/grounded-ui)产品引用卡片 + 状态feat/chat-grounding

现在各个独立关注点已经清晰:数据、API、接线、用户体验,从而可以为每一层分配不同的评审人员。数据由数据负责人评审,用户体验由 UI 负责人评审。

GitHub 对堆叠式拉取请求的原生支持可以从拉取请求界面直接启动,并通过 gh stack CLI 无缝扩展到终端。

安装堆叠式拉取请求 CLI 扩展

运行以下命令:

gh extension install github/gh-stack
视频封面视频 · 前往原文观看

在远古时代,你就能直接开始干活了。但今天不行。现在有智能体在你身边协同工作。这些智能体需要学习堆叠式拉取请求的工作原理,以及如何代表你创建和管理它们。gh-stack 技能就是教它们这些的。

gh skill install github/gh-stack

或者,如果你更倾向于:

npx skills add github/gh-stack
视频封面视频 · 前往原文观看

对于上述示例中的特定功能,你的开发工作流拥有自定义智能体,每个智能体都有明确的工作流,并遵循严格的范围纪律,以实现小而单一职责的拉取请求目标。

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

设置的最后一步是确认 CI 已存在。如前所述,每个拉取请求都将针对堆叠基线进行评估,这些检查将对每一层运行。

现在,工作开始了。

第一层:数据目录基础

如今大多数智能体工作流都是自动化的,并在循环中自主执行,但为了便于说明,我们将逐步介绍每个步骤。

此时,所有智能体都已熟悉堆叠式拉取请求的工作原理,因此这一阶段的典型工作流是:

  1. 用适当的提示词调用数据建模智能体
  2. 智能体初始化一个新的堆叠,并设置第一个分支——feat/catalog-data,以 main 作为其基线,使用 gh init stack
  3. 检出分支、进行工作并运行验证
  4. (所有检查均通过)?提交该层 : 迭代
视频封面视频 · 前往原文观看

给未来评审者的备注:类型是否正确?数据是否经过验证?查询辅助函数是否安全?句号。

第二层:产品搜索 API

遵循类似流程:

  1. 用适当的提示词调用后端智能体
  2. 智能体在第一层基础 `feat/catalog-data` 之上添加下一层 `feat/search-api`,通过 `gh stack add` 导入已完成的数据访问模块。
  3. 检出代码,运行验证,一切正常。
  4. 开发者手动测试 API。
  5. (API 正常 && 所有检查通过)?提交该层:迭代。
视频封面视频 · 前往原文观看

给未来的审查者备注:输入是否经过验证?响应契约是否稳定?错误/空状态是在这里处理还是推给下游?完毕。

第三层:将聊天功能接入 API

在下一层中,你需要:

  1. 用合适的提示词调用 Frontend 智能体
  2. 智能体在第二层基础之上添加下一层 `feat/chat-grounding`。其基础分支为 `feat/search-api`,该分支将同时包含数据访问模块和已验证的 API。
  3. 检出代码,运行验证,并用 Playwright 运行浏览器测试。
  4. (所有检查通过)?提交该层:迭代。
视频封面视频 · 前往原文观看

给未来的审查者备注:每个回答是否都能追溯到真实的 API 响应?当 API 失败或返回空结果时会发生什么?完毕。

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

你会注意到第三层和第四层虽然作者相同(都是 Frontend 智能体),但分层方式截然不同。这是有意为之。UI 的负责人不应该需要检查底层数据流,反之亦然,这种结构正好保证了这种独立性。

于是,Frontend 智能体:

  1. 在第三层基础之上添加下一层 `feat/grounded-ui`,其基础分支为 `feat/chat-grounding`。
  2. 检出代码,运行验证,并用 Playwright 运行浏览器测试。
  3. (所有检查通过)?提交该层:迭代。
视频封面视频 · 前往原文观看

给未来的审查者备注:每条引用是否都能链接回真实产品?加载、空状态和错误状态是否都已覆盖?完毕。

提交整个栈

四个本地堆叠分支已就绪。下一步是用 `gh stack push` 将它们推送到远程,然后用 `gh stack submit` 在 GitHub 上创建相互关联的拉取请求。

视频封面视频 · 前往原文观看

栈映射图与每一层的 CI

切换到 GitHub 界面,四个拉取请求都已打开,在每个请求的顶部你都能看到栈映射图,这是一个在栈内各拉取请求之间一键导航的系统。

视频封面视频 · 前往原文观看

审查与更新栈

是时候换个角色,从审查者的视角来看待堆叠式拉取请求的流程了。

<reviewer’s hat on>

栈映射(stack map)是评审者手中的指南针——在栈顶与栈底之间提供导航,指引变更走向成功合并。其移动方向是明确的:自上而下阅读,自下而上评审。

  • 自上而下阅读,是为了获取上下文。这样你在评审过程一开始就能看到最终目标,从而确定方向。“哦,原来我们是想在聊天界面上展示产品卡片。”
  • 自下而上评审,是为了在既定检查点上逐层推进。只有理解了前一层,后一层的实现才有意义。

你不再需要像我们示例中那样,一次性评审一个超过 1,720 行的巨型 pull request,而是可以将评审分散到栈中一个个小而完整的独立目标上。

视频封面视频 · 前往原文观看

作为被指定的人工介入评审者,你进入后先看第一层,也就是栈底的那个 pull request,发现自动化的 Copilot Code Review(CCR)捕获了两个问题,而你也同意这两个问题应当修复。

<developer's hat back on>

变更请求发生在栈底,于是你:

  • 将反馈交给第一层的作者——负责该分支的数据建模智能体
  • 建议被采纳、测试、提交并推送
  • 一旦修复落地到 feat/catalog-data 分支,自然而然的下一个问题是:这对第二层、第三层和第四层意味着什么?

由于 feat/catalog-data 分支在评审之后被插队推送,GitHub 会明确标记:“此栈中的部分分支已分叉,必须进行变基(rebase)”,并同时显示“无法作为栈合并”的标记,从而阻止合并。

视频封面视频 · 前往原文观看

回到 GitHub 的 pull request 界面上,会出现一个一键式的 Rebase stack 按钮。在使用该按钮之前,有一点值得注意。通过该按钮触发基于 Web 的变基操作会在 GitHub 的服务器上执行,这意味着它会将提交者重置为点击按钮的那个人,生成的提交不会被签名,如果分支保护要求签名提交,那么这一键点击就会悄悄出问题。

更安全的等效做法是在终端中执行 `gh stack rebase`,在本地完成同样的级联变基,同时交互式解决冲突,但这次使用的是你自己的 Git 配置,然后再执行 `gh stack push`。

最后,你需要在整个栈中向上传播变更。栈的其余部分——无论是本地还是 GitHub 上——现在都需要跟上,而最简便的方式莫过于一条同步命令:`gh stack sync`。

这一站式流程从拉取远端更新开始,将 `feat/catalog-data` 之上每一层分支的变基操作级联应用到新提交上,推送变基后的分支,并从 GitHub 同步拉取请求状态。这样一来,变更会逐层向上传递,无需任何人手动触碰第二、第三或第四层。

回到 GitHub 上,所有检查都会重新运行并通过,栈图也会恢复成一条从 `main` 到 `feat/grounded-ui` 的干净、可合并的直线。

视频封面视频 · 前往原文观看

开始使用堆叠式拉取请求 >

阅读原文github.blog(在新标签页打开)