adopt native GitHub stack workflow
This commit is contained in:
@@ -2,25 +2,31 @@
|
||||
|
||||
[English](responding-to-pr-review-on-a-stack.md) | 中文
|
||||
|
||||
评审意见可能同时针对一条依赖堆叠(`A ← B ← C …`)中的多个 PR(Pull Request)。本指南说明如何在不破坏堆叠的前提下解决这些意见。它依赖的两个不变式是根 [AGENTS.md](../../AGENTS.md) § Conventions 中的常设指令:只用 merge commit,以及永远不改写已推送的分支。
|
||||
评审意见可能同时针对一条依赖堆叠(`A ← B ← C …`)中的多个 PR(Pull Request)。请通过 GitHub 官方的堆叠 PR 功能保持这条链的关联。本指南负责评审修复的归属与传播;[dsh-merging-stacked-prs](../../.agents/skills/dsh-merging-stacked-prs/SKILL.md) skill(技能)负责检查关联关系和落地。
|
||||
|
||||
## 基本规则
|
||||
|
||||
1. **每个 PR 分支一个 worktree。** 每个 PR 的修复在该 PR 自己的 worktree 中进行;并行修复绝不共享同一个 checkout。
|
||||
2. **通过将父分支向下合并来更新子分支**(在子分支中执行 `git merge <parent-branch>`,产生一个新的 merge commit)。绝不对已推送的分支做 rebase/amend/force-push:改写会使分支与父 PR 及 GitHub 记录的内容产生分歧,破坏堆叠合并图,并抹去评审修复历史。
|
||||
3. **修复落在引入问题的那个 PR 上,然后向下流动。** 当 PR `B` 上的评论指向 `B` 引入的代码时,在 `B` 上修复,再将 `B` 合并到 `C`——即使 `C` 也包含该文件。把修复发起在下游会导致 `B` 带着未修复的代码交付,并对 `B` 的评审者隐藏修复。
|
||||
4. **每个评审修复是一个独立 commit,绝不 amend。** "修复评审发现"的 commit 记录了评审捕获的内容。只有你自己尚未推送、尚未评审的工作才可以 amend。
|
||||
2. **GitHub 的 stack 对象是权威依据。** base 分支确定预期的依赖顺序,`PullRequest.stack` 和 `stackEntry.position` 则证明 GitHub 已识别该堆叠。未经检查这些字段,不得仅凭分支链吻合就将其视为官方堆叠。
|
||||
3. **修复落在引入问题的那个 PR 上,然后沿堆叠向上流动。** 当 PR `B` 上的评论指向 `B` 引入的代码时,在 `B` 上修复,再将 `B` 的变更传播到 `C`,即使 `C` 也包含该文件。把修复发起在下游会导致 `B` 带着未修复的代码交付,并对 `B` 的评审者隐藏修复。
|
||||
4. **每项评审修复都保留为独立 commit。** 后续 rebase 可能改变其 OID,但不得通过 amend 把已经评审的修复从分支历史中抹去。只有你自己尚未推送且尚未评审的工作才可以 amend。
|
||||
5. **明确选择 merge-forward 或 rebase。** 评审后允许采用这两种历史更新方式。改写历史的推送必须受 lease 保护;如果远端 head 在此期间前移,操作必须中止,不得将其覆盖。禁止直接使用 `--force`。
|
||||
|
||||
## 沿堆叠解决评审意见
|
||||
|
||||
1. 在行动之前先就事论事地审视每条评论:对照代码验证其论断——评审者指出了正确的症状,但仍可能误诊原因。
|
||||
2. 将每个被接受的发现映射到其发起 PR,在那里修复,然后按顺序沿链向下合并。
|
||||
3. 委派的修复需要信任但验证:子 agent(智能体)的报告描述的是意图,不一定是实际落地的内容。请亲自在实际代码树上重新运行门禁;对于回归守卫,要证明它在未修复的代码上**失败**(引入回归、观察变红、再还原)——两种情况都通过的守卫什么也守不住。子 agent 将问题重新定性为「已处理」时,这是一个需要亲自深入的信号。
|
||||
4. 在评审线程中回复(`gh api repos/{owner}/{repo}/pulls/{pr}/comments/{id}/replies`),而非发顶层评论;说明修复内容及承载修复的 commit。
|
||||
5. 合并堆叠之前,检查依赖方:删除一个 PR 的 base 分支会自动关闭依赖它的 PR。用 `gh pr list --state open --base <branch> --json number --jq length` 检查每个分支(非零 = 有打开的依赖方),当子 PR 仍以该分支为 base 时,合并时不带 `--delete-branch`。完整的落地流程见 [dsh-merging-stacked-prs](../../.agents/skills/dsh-merging-stacked-prs/SKILL.md) skill(技能)。
|
||||
2. 将每个被接受的发现映射到其发起 PR,并在那里修复。
|
||||
3. 将修复后的层按顺序传播到每个受影响的子 PR:
|
||||
- **Merge-forward:** 将修复后的父分支合并到其子分支,验证子分支,然后继续沿堆叠向上传播。依照[增量更新 base 的决策](../../.agents/notes/implemented/process/2026-07-26-incremental-pr-base-retargeting.md),保留每个正在处理的检查点。
|
||||
- **原生级联 rebase:** 使用 `gh stack rebase`,验证所有已改写的层,然后通过 `gh stack push` 发布;也可以使用 `gh stack sync`,该命令可能先发布,因此必须按照 [dsh-pre-push-checks](../../.agents/skills/dsh-pre-push-checks/SKILL.md) 在同步后立即验证。
|
||||
4. 委派的修复需要信任但验证:子 agent(智能体)的报告描述的是意图,不一定是实际落地的内容。请亲自在实际代码树上重新运行门禁;对于回归守卫,要证明它在未修复的代码上**失败**(引入回归、观察变红、再还原)——两种情况都通过的守卫什么也守不住。子 agent 将问题重新定性为「已处理」时,这是一个需要亲自深入的信号。
|
||||
5. 在评审线程中回复(`gh api repos/{owner}/{repo}/pulls/{pr}/comments/{id}/replies`),而非发顶层评论;说明修复内容及当前承载修复的 commit 或 head。
|
||||
6. 每次改写推送后,都要重新读取未解决线程、批准状态、可合并性和检查结果。经 force-push 改写的 commit OID 或已过时的内联锚点,都不足以证明该发现当前仍处于已解决状态。
|
||||
7. 仅可通过官方堆叠流程落地。如果这些 PR 尚未关联,落地 skill 会自动关联作者相同的链;如果作者不同,则先询问用户;如果原生堆叠支持不可用,则硬性停止流程。
|
||||
|
||||
## 验证
|
||||
|
||||
- 每个已修复的 PR 显示一个新 commit(PR 时间线中没有 force-push 图标)。
|
||||
- 每个子 PR 相对其父 PR 的 diff 仍然只包含自身的变更。
|
||||
- 门禁在堆叠中的每个 PR 上都通过,而不仅仅是顶部。
|
||||
- 每个已修复 PR 的当前 diff 都在引入问题的那一层包含预期修正。
|
||||
- GraphQL 报告的官方堆叠只有一个且顺序符合预期;每个子 PR 相对于父 PR 的 diff 只显示该子 PR 自身的变更。
|
||||
- 每次改写推送后,均重新审计了未解决线程、批准状态、可合并性和检查结果。
|
||||
- 相关门禁在堆叠中的每个受影响 PR 上都通过,而不仅仅是顶部。
|
||||
|
||||
Reference in New Issue
Block a user