
🎯 学 gstack 的版本队列仪表盘:不是凭记忆管理"哪些 PR 在排队、哪些已合入、哪些在部署中",而是自动扫描所有活跃分支和 open PR、检测 VERSION 碰撞、可视化合入队列——让发布管理从"心里有数"变成"屏幕上有数"。 ⏱️ 预计时间:20 分钟
[!quote]- 📖 原Skill精要 技能名称:landing-report 核心功能:只读版本队列仪表盘。显示当前被 open PR 占用的 VERSION 槽位、哪些并行 Conductor workspace 有接近完成的 WIP 工作、/ship 下次会选哪个槽位。零修改——纯快照视图,让发布管理从"心里有数"变成"屏幕上有数"。 所属体系:gstack 虚拟工程团队 协作关系:在 [[L6-25-发布上线管理|ship]] 之前使用,了解当前排队状态和可用版本号
§1 课程概览
landing-report 是 gstack 发布体系的"指挥中心仪表盘"——纯只读、零修改的快照视图。它从五个维度展示发布全景:活跃分支列表(PR 状态 + VERSION)、版本号队列(碰撞检测 + 间隙识别)、合入队列状态(CI + 审查 + 冲突)、部署追踪(最近部署的版本和健康状态)、阻塞项(CI 失败/冲突/审查陈旧/版本碰撞)。核心能力是 VERSION 碰撞检测——通过 gstack-next-version 扫描所有 open PR 的版本号,发现"两个 PR 抢占同一版本号"的冲突,防止"幽灵发布"(先合入的 PR 的 CHANGELOG 被后合入的悄然覆盖)。在多团队并行开发场景下(如 5 个团队同时开 PR),landing-report 提供合入顺序建议、封网风险评估、和明确的下一步行动推荐。
[!tip] 白话小课堂 假设你们团队有 5 个人同时开发 5 个功能,每个人开了一个 PR。你作为 Tech Lead,怎么知道"谁的 PR 先合、有没有版本号冲突、谁卡住了"?landing-report 就是一张"发布全景图"——一个命令看清所有 PR 的排队状态,谁该先合、谁和谁抢版本号、谁被 CI 卡住了,一目了然。
§2 Landing Report 解决什么问题?
多分支并行开发的"可见性黑洞"
当多个开发者并行工作时: → "我的 PR 在队列里排第几?" → "谁抢了我的版本号?" → "这个分支合了之后下一个合哪个?" → "有没有人的 PR 已经 merge 了但忘了删分支?" → "main 上最新的部署是哪个版本?"
没有 landing-report: → 靠 git log --oneline 手动查看 → 靠 Slack/微信群沟通"谁先合谁后合" → VERSION 冲突靠运气发现
有 landing-report: → 一个命令看清所有 PR 的合入状态 → VERSION 队列可视化 → 阻塞/冲突一目了然 → 部署状态追踪
💡 白话小课堂:假设你们团队有 5 个人同时开发 5 个功能,每个人开了一个 PR。
§3 Landing Report 的信息维度
五维信息展示
1. 活跃分支列表
→ 本地分支 + 远程分支 → 每个分支的 PR 状态(无 PR / OPEN / MERGED / CLOSED) → 每个分支的 VERSION(如有) → 分支的合入目标(base branch)
2. 版本号队列
→ 按 VERSION 排序的所有 open PR → 显示 VERSION 碰撞(两个 PR 声明了相同的版本号) → 显示 VERSION 间隙(1.7.0.0 → 1.9.0.0 中间缺了 1.8.0.0) → 下一个可用版本号
3. 合入队列状态
→ open PR 按创建时间排序 → 显示 CI 状态(passed / failing / pending) → 显示审查状态(reviewed / not reviewed / stale) → 显示 merge 冲突状态
4. 部署追踪
→ 最近部署的版本 → 部署时间 → 部署状态(healthy / degraded / failed) → 生产环境 URL 和验证结果
5. 阻塞项
→ CI 失败的 PR → 有 merge 冲突的 PR → 审查陈旧但想合入的 PR → VERSION 碰撞的 PR
§4 报告格式——一眼看懂发布全景
Landing Report 输出示例
═══════════════════════════════════════════════════════════ LANDING REPORT — shop-app Generated: 2026-05-03T16:00:00Z ═══════════════════════════════════════════════════════════
VERSION QUEUE (next: v1.7.0.0)
| VERSION | Branch | PR | Status |
|---|---|---|---|
| v1.7.0.0 | feat/checkout | #42 OPEN | ✓ CI ✓ Review |
| v1.8.0.0 | feat/inventory | #43 OPEN | ⚠ CI pending |
| v1.8.0.0 | fix/price-calc | #44 OPEN | ⚠ VERSION COLLISION |
| v1.9.0.0 | feat/recommend | — NO PR | needs /ship |
MERGE QUEUE (by creation time) #1 feat/checkout → v1.7.0.0 (READY TO LAND) #2 feat/inventory → v1.8.0.0 (WAITING CI)
BLOCKED ⚠ fix/price-calc: VERSION v1.8.0.0 collides with feat/inventory → Resolution: rename VERSION to v1.8.1.0 or coordinate merge order
DEPLOY HISTORY v1.6.0.0 → deployed 2026-05-03T09:00:00Z → HEALTHY v1.5.1.0 → deployed 2026-05-02T14:00:00Z → HEALTHY
RECOMMENDATION → Land #42 (feat/checkout) first → Resolve VERSION collision between #43 and #44 → Run /ship for feat/recommend
## 报告各部分的设计意图
→ VERSION QUEUE: 快速发现版本号冲突
→ MERGE QUEUE: 合入顺序一目了然
→ BLOCKED: 需要解决的问题突出显示
→ DEPLOY HISTORY: 最近的生产变更记录
→ RECOMMENDATION: 明确下一步行动
§5 VERSION 碰撞检测的核心算法
gstack-next-version 的工作原理
landing-report 调用 gstack-next-version 来检测版本碰撞:
算法
- 扫描目标分支(main)上所有 open PR 的 VERSION 文件
- 构建 VERSION 列表,按版本号排序
- 检测碰撞:两个 PR 声明了相同的版本号
- 检测间隙:版本号不连续(虽然允许但不推荐)
- 返回下一个可用版本号
VERSION 碰撞的严重性
→ 碰撞 = 两个 PR 想用同一个版本号 → 先合入的 PR 会成功 → 后合入的 PR 会覆盖 CHANGELOG 条目 → 第一个 PR 的发布记录丢失("幽灵发布") → 这是 CHANGELOG 完整性的最高优先级威胁
碰撞解决策略
→ 自动 bump 后合入的 PR 到下一个可用版本 → 或协调合入顺序(一个先合,另一个 rebase) → 或手动指定版本号(特殊情况下)
⚠️ 避坑指南: VERSION 碰撞最可怕的地方不是"两个 PR 用了同一个版本号"——冲突本身很容易发现。真正可怕的是"先合入的那个 PR 的 CHANGELOG 被后合入的悄然覆盖"。
§6 部署追踪——不只是"谁合了什么"
Deploy History 的来源
landing-report 从多个数据源聚合部署信息:
数据源
- gstack-review-log → 审查和合入记录
- land-and-deploy 的 deploy reports → 部署报告
- canary 报告 → 部署后健康验证
- git log main --oneline → 合入历史
- gh pr list --state merged → 已合入 PR 列表
展示信息
→ 版本号 + 部署时间 + 部署状态 → 如果部署失败 → 显示失败原因 + 回退记录 → 如果部署成功 → 显示健康状态 + canary 结果
部署状态分类
→ HEALTHY: canary 通过,生产正常 → DEGRADED: 有轻微问题但可接受 → FAILED: 部署失败(已回退或 skip) → REVERTED: 已回退到前一版本 → UNKNOWN: 未追踪(可能是手动部署)
§7 电商 Skill 案例:电商APP版本发布报告自动生成
🛒 实战案例:某电商平台5个开发团队并行在main分支上工作——支付团队(分期付款功能,v2.5.0.0)、物流团队(新物流商API集成,v2.5.0.0撞号)、营销团队(推荐算法优化,v2.6.0.0)、基础架构(Node.js升级v22,v2.7.0.0)、前端团队(商品详情页重构,v2.8.0.0)。同时5个PR open,版本号冲突、合入顺序不确定、部署状态不可见,导致发布混乱——“我的功能合了但怎么还没上线?”。
- Landing Report输出:自动扫描所有open PR和已合入但未部署的分支,生成完整发布视图——VERSION QUEUE显示5个团队的版本占用(v2.5.0.0被支付和物流同时占用→碰撞警告)、MERGE QUEUE建议合入顺序(#1 payment/install v2.5.0.0 READY→#2 logistics/carrier需先解决版本冲突升级到v2.6.0.0→#3 marketing/recomm v2.7.0.0需先完成review)、BLOCKED项(物流版本冲突/基础设施CI失败3个测试不通过/前端review提交3天未审查)。
- 部署追踪:DEPLOY HISTORY显示生产环境最新版本v2.4.1.0(2026-11-03部署,HEALTHY✓)、上一版本v2.4.0.0(2026-10-31部署,HEALTHY✓)。版本队列碰撞检测——gstack-next-version扫描发现v2.5.0.0冲突(支付和物流同时申请),建议物流升级到v2.6.0.0或等支付先合。
- 封网风险评估:双11封网倒计时5天。支付团队的v2.5.0.0(分期付款功能影响GMV)建议封网前优先合入,物流团队的v2.6.0.0和营销团队的v2.7.0.0视情况决定是否赶封网窗口,基础设施Node.js升级(v2.7.0.0)CI失败建议推迟到封网后以免引入不稳定因素,前端重构(v2.8.0.0)未完成审查建议标记为封网后发布。
- 积压检测:发现2个已合入但可能未部署的版本——v2.3.2.0(合并24小时仍未部署,状态UNKNOWN)和v2.3.1.0(合并72小时仍未部署,状态LOST)→自动标记为“幽灵发布”风险并提醒CTO。经查v2.3.1.0已部署但deploy report未归档(修复归档脚本后解决),v2.3.2.0确实未部署(工程师合了PR后忘记触发land-and-deploy)。
🔑 启示:多团队并行开发最大的风险不是代码冲突——是发布状态的“不可见性”。5个团队各自运行、各自合入、各自部署,没有人知道“谁合了什么、谁还没部署、谁的版本号被抢了”。Landing Report的价值是让不可见变得可见——版本碰撞可视化、合入顺序有数据支撑、幽灵发布被自动检测。
[!info] 参考来源 版本队列管理理念参考了 GitHub merge queue 功能和 Shopify 使用的 Shipit 部署协调系统。
§8 结构拆解
landing-report 结构模板
核心特征
- 管理对象: 多分支并行开发时的发布队列全景(PR 状态 + VERSION 占用 + 合入顺序 + 部署追踪)
- 核心原则: 纯只读快照——零修改,只展示,让"心里有数"变成"屏幕上有数"
- 关键设计: gstack-next-version 碰撞检测 + 五维信息展示(分支/版本队列/合入状态/部署追踪/阻塞项)+ 合入顺序推荐
通用结构
- 分支扫描层: 本地分支 + 远程分支 → PR 状态匹配(无 PR/OPEN/MERGED/CLOSED)→ VERSION 提取 → base branch 记录
- 版本队列层: gstack-next-version 扫描所有 open PR 的 VERSION → 碰撞检测 → 间隙识别 → 下一个可用版本号
- 合入状态层: CI 状态(passed/failing/pending)+ 审查状态(reviewed/not reviewed/stale)+ merge 冲突检测
- 部署追踪层: gstack-review-log + deploy reports + canary 报告 + git log + gh pr list → 部署状态分类(HEALTHY/DEGRADED/FAILED/REVERTED/UNKNOWN)
- 阻塞聚合层: CI 失败 + merge 冲突 + 审查陈旧 + VERSION 碰撞 → 分级展示 + 解决建议
- 推荐输出层: 合入顺序建议(业务优先级/依赖关系/风险递减)+ 封网风险评估 + 下一步行动
§9 掌握检验
Q1:landing-report 的五个信息维度中,VERSION QUEUE 的核心功能是什么?
- A) 显示所有已合入的 PR 的版本号历史
- B) 快速发现版本号冲突——两个 open PR 声明了相同的版本号,防止"幽灵发布"
- C) 自动为所有 open PR 分配版本号
- D) 显示生产环境中正在运行的版本号
Q2:landing-report 中,部署状态"DEGRADED"和"FAILED"的区别是什么?
- A) DEGRADED 表示 canary 未运行,FAILED 表示 canary 失败
- B) DEGRADED 表示有轻微问题但可接受(仍在运行),FAILED 表示部署失败(已回退或跳过)
- C) DEGRADED 表示只有前端有问题,FAILED 表示后端有问题
- D) 两者完全相同,只是措辞不同
Q3:VERSION 碰撞被称为"CHANGELOG 完整性的最高优先级威胁"。请详细解释"幽灵发布"的完整因果链:两个 PR 都声明 v1.7.0.0 → 第一个 PR 合入成功 → 第二个 PR 合入成功 → 为什么第一个 PR 的 CHANGELOG 条目会消失?为什么说"幽灵发布"比丢失代码还严重(从审计追溯和合规两个角度分析)?
Q4:合入队列默认按"先到先合"(PR 创建时间)排序。请列出至少三种应该改变这个默认顺序的合理场景,并说明每种场景下新的排序依据是什么。在"支付功能 PR(影响 GMV)vs 文档修正 PR(只改 README)"同时 ready 的情况下,合入顺序应该怎么排?为什么?
Q5:BLOCKED 区域中,"CI 失败"和"审查未完成"是否应该被视为同等优先级的阻塞?请将它们分为硬阻塞(必须解决才能合入)和软阻塞(建议解决但可跳过),并给出每种分类的理由。在什么特殊情况下,"审查未完成"可以从硬阻塞降为软阻塞?
Q6:封网期间(如双11前 5 天),landing-report 展示了"封网倒计时: 5 天"和"当前处于 FREEZE: 仅允许 [HOTFIX] PR"。假设你是一名 Tech Lead,看到报告中 5 个团队的 PR 中有 2 个 "READY TO LAND"、2 个 "BLOCKED"、1 个 "NEEDS REVIEW"——请基于这份 landing-report 做出合入决策:哪些 PR 应该在封网前合入?哪些应该推迟到封网后?决策依据是什么?如果你的决策和团队中某个 Tech Lead 的意见不一致(他认为他的 PR 应该优先),你用什么数据说服他?
§10 答案
点击查看答案
Q1:B —— VERSION QUEUE 的核心功能是快速发现版本号冲突。
Q2:B —— DEGRADED = canary 通过但有轻微问题(如偶尔的控制台 warning、性能略低于基线但在预算内),系统仍在运行;FAILED = 部署本身失败(CI 部署 job 失败、平台拒绝部署、或 canary 检测到 CRITICAL 问题),通常已回退或跳过。
Q3:完整因果链:PR A 声明 v1.7.0.0 → 合入 → CHANGELOG 中写入 v1.7.0.0 的条目 → PR B 也声明 v1.7.0.0 → 合入 → 如果 PR B 使用的 VERSION 文件和 CHANGELOG 是基于 main 旧状态的分支(没有 rebase 到 PR A 合入后的 main)→ PR B 的 VERSION 文件覆盖了 PR A bump 的版本号 → PR B 的 CHANGELOG 条目覆盖了 PR A 的条目(因为 PR B 的 CHANGELOG 中没有 PR A 的内容)→ PR A 的发布记录消失。"幽灵发布"比丢失代码更严重的原因:①审计追溯——6 个月后合规审计问"v1.7.0.0 是什么时候发布的?包含了什么变更?"——你无法回答,因为记录消失了。丢失代码可以通过 git reflog 恢复,但丢失的发布记录(人类可读的 CHANGELOG)无法从 git 历史中自动恢复——git log 只能告诉你 commit message,不能告诉你哪些 commit 属于同一个发布版本。②合规风险——如果 v1.7.0.0 包含了 GDPR 相关的修复,但你无法从 CHANGELOG 证明"这个修复确实在 v1.7.0.0 中发布了"→ 合规审计失败。
Q4:改变默认顺序的场景:①业务优先级——支付功能(影响 GMV)应优先于文档修正(只改 README),因为支付功能的延迟合入 = 直接收入损失;②依赖关系——PR B 依赖 PR A 的代码(B 从 A 的分支开出),A 必须先合入;③风险递减——小修改、低风险的 PR 先合入,大修改、高风险的后合入(降低 merge conflict 的复杂度)。支付 vs 文档场景:支付功能先合——因为这关系到"用户能不能付钱"。文档修正后合——即使 README 落后一个版本也不会影响生产系统。排序依据不是"谁先提的 PR"而是"哪个 PR 的延迟合入代价更高"——支付功能的延迟 = 每个小时的 GMV 损失,文档修正的延迟 = 零业务影响。
Q5:硬阻塞:CI 失败——代码不工作,合入后会导致生产问题;VERSION 碰撞——会导致 CHANGELOG 覆盖和"幽灵发布"。软阻塞:审查未完成——代码可能没问题只是还没人看,在紧急 hotfix 场景下可以跳过(但需要显式记录跳过审查的决策)。审查未完成降级条件:紧急 hotfix(P0 级别的生产故障)、超小 diff(< 10 行变更且不涉及安全/支付逻辑)、已有充分的自动化测试覆盖且全部通过。但降级不是默认行为——每次降级都需要显式决策和审计记录。
Q6:决策分析:①READY TO LAND 的 2 个 PR——如果它们通过了 CI + 审查,且不是大的 feature,建议在封网前合入(封网后 5 天内这些功能在生产上稳定运行、有时间发现问题)。②BLOCKED 的 2 个 PR——分析阻塞原因:如果阻塞是 CI 失败,赶在封网前修(因为封网后不能修);如果阻塞是审查未完成,取决于 PR 的业务重要性(支付相关必须审、文档相关可推迟)。③NEEDS REVIEW 的 PR——如果是大 feature,强烈建议推迟到封网后(因为封网期间不能改,如果这个 feature 有 bug 只能 hotfix——风险太高)。说服持不同意见的 Tech Lead:用 landing-report 的数据——"你的 PR 在阻塞列表中,阻塞原因是审查未完成。封网后你还有 3 天可以完成审查并合入。如果现在强行合入,封网期间如果出了问题,hotfix 的审批链是 CTO + 2 senior engineers——这比等 3 天再合的成本高得多。"
(5/6 通过)
延伸阅读
- 上一课:[[L6-29-发布文档同步|发布文档自动同步]] —— 确保每次发版文档自动跟上
- [[L6-25-发布上线管理|发布上线管理]] —— landing-report 在 /ship 之前使用,了解排队状态
- [[L6-28-代码冻结与解冻|代码冻结与解冻]] —— 封网期间 landing-report 展示 FREEZE 状态和封网倒计时

评论区
共 0 条评论