关于 git-workflow
面向处理 Git 和 GitHub 变更的 Agent 工作流技能,强调专注分支、可恢复历史、发布检查和明确的授权边界。
主要功能
- 01从远程默认分支创建专注分支
- 02通过合并更新;不变基或强推
- 03拉取请求压缩合并并使用明确主题
- 04提交和推送前运行发布检查
- 05新工作前检查默认分支 CI 状态
适用场景
- 01从干净且最新的基线开始仓库工作
- 02在不改写历史的情况下更新拉取请求
- 03发布到 GitHub 前检查内容
安装
复制下面的命令,在终端中运行。
npx skills add https:/ / github.com/ frostney/ known-good-route --skill git-workflow安装后在 Claude Code 中输入/git-workflow确认已加载。
包含的文件
除 SKILL.md 外,安装时一起下载的参考资料和脚本。
references/github-stacks.mdscripts/publication_guard.pystack_push_guard.pytests/test_publication_guard.pytest_stack_push_guard.py详细介绍
Git 工作流
将每项更改都放在一个全新且范围明确的分支上,并确保其历史记录便于审查和恢复:合并而不是重写,绝不丢失本地工作,并将每个拉取请求作为一个带有明确主题的 squash 提交合入。Git 请求仅授权执行该操作所需的仓库和 GitHub 状态。
用户对这些默认设置中的某一项作出的明确指示,仅替换当前工作流的对应默认设置。在用户更改之前,后续轮次中都应保留该设置;新的仓库或操作需要单独确定范围。
开始或恢复工作
- 从远程默认分支解析基准分支;绝不硬编码
main。 - 将远程默认分支同步作为新工作的自动预检;不要请求许可来执行安全的干净更新。
- 在本地默认分支上开始新工作时,先检查状态,再获取或编辑。如果工作区干净,则自动获取并将其快进到已获取的远程默认分支最新提交。遇到仅存在于本地的提交、分叉或非快进更新时,立即停止。
- 如果本地默认分支的工作区有未提交更改,则在获取、更新或编辑之前停止,并询问用户选择:丢弃当前状态,或保留当前状态并基于最新远程默认分支创建一个范围明确的分支或工作区。未经用户答复,不得作出任一选择,也不得暂存、提交或丢弃任何内容。
- 在任何其他新选定或复用的分支或工作区中首次编辑之前,要求工作区干净,并获取远程默认分支。发现有未提交更改时,停止并报告相关文件;绝不自动暂存、提交或丢弃这些更改。
- 自动将每个新的范围明确的本地分支和工作区创建在刚获取的远程默认分支的确切最新提交上。不要将范围明确的分支配置为跟踪远程默认分支;仅在推送该范围明确的分支时设置其上游分支。
- 进入现有的范围明确的分支或工作区时,在编辑前获取其远程基准分支;仅在满足下方更新、提交和推送中的保持最新规则时才将其合并。
- 开始新工作之前,先通过默认分支健康检查门槛。
更新、提交和推送
-
合并远程基准分支以更新分支。绝不要变基。远程基准分支是开放 PR 的目标分支:如果目标是远程默认分支,则为远程默认分支;如果目标是命名基准分支,则按 create-pr 第 1 步中的定义确定,例如用于回移植的发布分支。绝不要将远程默认分支合并到目标为命名基准分支的 PR 所在分支。没有开放 PR 时,远程基准分支就是远程默认分支。
-
PR 分支以及准备提交 PR 的专用分支,无需始终与基准分支保持同步。仅在以下情况下将远程基准分支合并到该分支:
- 该分支与基准分支存在冲突;
- 仓库通过规则集或分支保护设置要求分支保持同步(此时 GitHub 会将 PR 的
mergeStateStatus报告为BEHIND); - 修复 Stale 或 Red 状态需要基准分支上的提交,例如需要包含它要修复的提交;或
- 用户提出要求。
仅仅落后于基准分支并不是合并理由,编辑或推送也不是:每次合并基准分支都会重新启动 PR 检查,包括任何完整 CI 运行。
-
原生堆栈中的某一层应通过堆栈引用进行更新。若开放 PR 的目标是任何其他非默认分支,则该 PR 没有远程基准分支:停止操作,不要合并或推送,并报告该目标分支,而不是自行选择一个。随后用户可以指定基准分支,或让 PR 重新堆叠。
-
在获准更新 PR 期间,解决那些预期行为已由所选更改和当前基准分支确定的冲突。保留双方所需的行为,使用项目工具重新生成生成文件,并验证结果。如果解决冲突需要在尚未解决的重要事项上作出选择,则暂停。在新工作预检期间,应在实现前报告冲突。
-
绝不要修改现有提交。每次修正都要创建一个新提交。
-
绝不要强制推送。如果普通推送因历史分叉而被拒绝,则停止。
-
仅暂存相关文件,并排除机密信息或无关的本地工作。
-
每次向 GitHub 仓库提交、推送或写入 PR 之前,都要运行发布防护检查。
-
使用简洁、符合 Conventional Commits 规范且采用祈使语气的提交主题。每个提交标题都必须说明可观察到的影响,而不只是变更的机制。
-
除非用户明确要求,否则让钩子正常运行。
发布检查
使用 Python 3.11 或更高版本,通过此已安装技能的实际安装路径运行 scripts/publication_guard.py,例如 python3 /path/to/git-workflow/scripts/publication_guard.py。它需要 gh 已登录 GitHub。当接收内容的仓库为公开仓库时,它会重写其中的私有 GitHub 引用和本机路径。
- 每次提交前,将提交消息写入文件,运行
staged --message-file FILE,并使用git commit -F FILE提交。 - 每次推送前(包括
gh stack push、gh stack submit和gh stack link),运行outgoing --base BASE。BASE 为REMOTE/DEFAULT;对于堆栈层,BASE 为其下方的分支。如果要推送到非当前分支推送远程的其他远程,请添加--remote NAME。通过上述提交步骤提交它暂存的内容,然后推送。 - 每次写入拉取请求标题或正文前,将标题和正文写入文件,并运行
pr --repo OWNER/REPO --title-file FILE --body-file FILE,其中OWNER/REPO是创建拉取请求的仓库。然后根据这些文件创建或编辑拉取请求。这适用于gh pr create、gh pr edit、gh api .../pulls --input FILE(根据已检查的文件构建其 JSON),以及gh stack submit和gh stack link创建的标题和正文;之后需使用gh pr edit对其进行校正。
根据其结果采取相应操作:
- 退出码为 0,且输出
is not public; nothing checked或nothing to rewrite: 继续。 - 退出码为 0,且出现
rewrote ...行:已暂存的文件以及你传入的文件现在都包含重写后的文本;这些文件中未暂存的编辑也会应用同样的重写。继续,并报告每一条rewrote和placeholder行。 - 出现
warning: commit ... pushing publishes that commit unchanged:历史记录永远不会被重写。推送时向用户报告所列的提交和文件。 - 出现
warning: PATH was not checked:检查程序无法将该文件作为文本读取。发布前,亲自检查其中是否包含私有仓库名称和本机路径,并报告检查结果。 - 出现与
.github/publication-guard.json或保留模式有关的warning::报告该警告;对于无法读取的内容,检查程序使用了默认保留列表。 - 退出码为 2:Git 或 GitHub 无法回答检查程序所依赖的问题,或者参数有误;未进行任何更改。修复错误指出的原因并重新运行。绝不要在未成功运行(退出码为 0)的情况下发布。
- 其他任何退出码:检查程序运行失败。停止操作,不要发布,并报告其输出。
在同一阶段,还要根据仓库的约束指南检查要发布的内容。当前的
约束指南台账必须涵盖这些内容:发布前,审查自记录该台账以来所做的任何更改。检查即将写入的提交消息、标题或正文是否符合台账中标记为 for publication 的每一行,例如仓库的提交、拉取请求描述和写作规则;修复所有违反规则的内容,并记录每一行的检查结果。
默认分支健康状况
拉取请求自身的检查用于保护默认分支;默认分支自身的运行则报告已合并内容的情况。在开始新工作前确认默认分支的健康状况,并在每次合并前立即重新检查,使用项目要求在默认分支提交上运行的 CI,例如其推送 CI,而不是集成部署。对于每个必需的工作流,列出其最近的默认分支运行,例如使用 gh run list --workflow WORKFLOW --branch DEFAULT --limit 50 --json databaseId,headSha,event,status,conclusion,createdAt。增加 --limit,直到列表中出现成功或失败(failure、timed_out 或 startup_failure)的运行,或已列出该工作流的全部历史记录。推送运行和覆盖率采样器触发的运行都计入。决定所依据的提交,是 git log --first-parent origin/DEFAULT 中最新的、具有成功或失败运行的提交,不论该运行由哪种事件触发。列出该提交的所有运行(gh run list --workflow WORKFLOW --commit SHA --json databaseId,event,status,conclusion,attempt,updatedAt);其中最新一次尝试最晚完成的运行即为决定性运行。已取消、已被取代和已跳过的运行均不产生结果。
- **绿色:**每个决定性运行均成功,或项目不要求在默认分支提交上运行 CI,且没有后续提交的运行被取消或取代。可以开始工作和合并。后续提交中仍在排队或进行中的运行不会阻止两者,合并也可能取代或取消这些运行。切勿让并行交付轮流进行,也不要持有共享的合并令牌来维持运行。
- **过时:**每个决定性运行均成功,但后续提交的某个运行被取消或取代,通常是因为工作流在每次推送时都会取消进行中的运行(使用带有
cancel-in-progress的concurrency组),因此已完成的运行不再覆盖所有已合入的提交。没有任何成功或失败运行的必需工作流也属于过时状态。合并不会因此暂停:每个拉取请求自身的必需检查,以及其声明规则要求的任何完整 CI 运行,仍是合并门槛,只有已完成但失败的运行才会阻止合并。覆盖率采样器会弥补这一缺口,除非仓库声明了过时界限。 - **红色:**决定性运行失败。停止合并:首先必须让分支恢复绿色,只有修复工作可以开始或合并。即使修复已合入,在该运行重新运行成功,或该工作流针对相同或更新的提交运行成功之前,状态仍为红色。找出失败的任务及其原因;如果采样器运行失败,问题来源在其新覆盖的提交中,使用
git log --first-parent PREVIOUS-DECIDING-SHA..SAMPLER-SHA查看。如果是偶发故障,且项目允许,则重新运行失败的任务即可消除故障。否则,查找修复的负责人:一个未关闭的拉取请求、一个议题或另一个会话。如果无人负责,且当前请求授权合并,就通过/deliver将修复作为独立工作项交付并优先合入。否则,报告失败的任务、原因及所需修复。修复合入后,等待其运行,可使用delivery-wait的workflow-terminal等待方式;不要合并任何会取代或取消该运行的内容。独立的本地调查可以继续;除此之外,不得开始开发或合并任何内容。
默认情况下,红色规则严格执行。只有个人或项目可以明确放宽此规则,例如允许无关的纯文档更改合入。
覆盖采样器
在 Stale 状态下,为每个必需工作流保持一个正在运行的任务,且该任务不会被任何合并取消。无论有多少合并落地,覆盖范围都会按一个任务的运行时长推进,最多额外增加一个工作流运行时长。
- 当该工作流没有此类排队或正在运行的任务时,在当前最新提交上、其取消组之外触发一个任务,例如使用
gh workflow run WORKFLOW --ref DEFAULT,并记录其运行 ID 和提交。继续合并;绝不要等待它。 - 每次交付都复用正在运行的任务;不会为自身启动任务。触发后查看任务列表时,如果发现同一工作流有更早的采样任务正在运行,就取消刚刚触发的任务。
- 它和其他任务一样决定状态:当它成功且其提交是已有结果的最新提交时,该提交及其之前的所有内容都已覆盖。当它失败并作出决定时,分支为 Red。
- 只有当工作流具有
workflow_dispatch触发器,且其concurrency组将手动触发与推送分开时,触发的任务才能避开取消组。若分组键仅基于工作流和引用,则在默认分支上触发的任务会与下一次推送进入同一组,并被取消。如果工作流不允许在该组之外运行任务,应将此情况报告为项目缺口,并说明修复方法,例如将github.event_name加入分组键,并仅在推送时取消正在运行的任务;同时继续在 PR 门禁下合并。
声明的陈旧度上限
仓库可以在根目录 ORCHESTRATION.md 的监控策略中声明默认分支陈旧度上限:限制未覆盖提交数(git rev-list --count --first-parent DECIDING-SHA..origin/DEFAULT)、决定状态的提交的时间,或两者兼有限制。若未声明,则没有上限,只有采样器。无论由何种原因导致决定状态的运行落后于最新提交,声明的上限都适用。格式错误或与更高权威指令相矛盾的设置,均视为已超限;应报告此情况。必需工作流若没有成功或失败的运行,即视为已超限。
超过上限后,暂停合并,直到某个已完成的运行将差距缩小到上限以内。等待满足条件的运行,使用 delivery-wait 的 workflow-terminal 等待方式:如果采样任务完成后的差距在上限以内,则等待该采样任务;否则等待最新提交自身的运行,该运行在暂停合并期间不会被取消。仅当最新提交没有排队或正在运行的任务时,才在其上触发采样任务。每次交付都等待同一个任务。任务完成后,其结果决定状态,同时合并期间就绪的所有内容。
合并
- 一旦拉取请求针对其确切的头部提交满足 就绪契约,就立即合并;该契约包括仓库声明的完整 CI 规则所要求的任何完整 CI 运行。绝不要等待先前合并触发的基础分支运行,除非默认分支健康状态为 Red,或超过声明的陈旧度上限。
- 每次合并前,重新检查 默认分支健康状态。
- 使用 squash 合并拉取请求,然后删除源分支。
- 由于采用 squash 合并,拉取请求的标题会成为基础分支上的提交主题:分支自身的提交主题不会保留。为标题撰写符合 Conventional Commit 规范的提交主题,说明此次整体变更带来的可观察影响。根据净效果选择类型,而不是根据其中数量最多的提交选择。如果项目根据提交历史生成变更日志或版本号递增,不符合规范的标题仍会顺利合并,但随后会悄然从中缺失。
- squash 合并后,同步本地基础分支,并删除已合并的本地分支。
原生 GitHub 堆栈
当用户选择堆栈、工作存在实际依赖链,或已确认的大型问题被有意拆分为累积式、可独立审查的层时,使用官方的 gh stack 工作流。不要将无关工作堆叠在一起。每一层都必须有一个明确的目标、范围受限的差异、各自的验证,以及明确列出的需求子集。
在创建、同步、推送、提交、审查或合并堆栈之前,请阅读 references/github-stacks.md。该参考文档是上述仅合并、不强制推送默认规则的唯一例外:只有在干净且已确认的原生堆栈上执行经过验证的 gh stack 命令时,才允许变基和使用 --force-with-lease。仍禁止使用原始的 git rebase、git push --force 和手动执行 git push --force-with-lease。