深度解析:用单分支顺序提交根治自治编码的 Git 状态问题)
人工智能AI Agent代码智能体Agent 编排CLIAI 应用【免费下载链接】gsd-2A powerful meta-prompting, context engineering and spec-driven development system that enables agents to work for long periods of time autonomously without losing track of the big picture项目地址https://gitcode.com/gh_mirrors/gs/gsd-2点击查看免费下载本文基于docs/dev/ADR-001-branchless-worktree-architecture.md系统拆解 gsd-2 早期为自治Auto编码会话设计的 Git 隔离架构从「每个里程碑一个工作树 树内切片分支」到「完全消灭切片分支、单分支顺序提交」的演进逻辑。你将掌握 GSD 工作树/分支模型的设计动机、.gsd/状态归属tracked vs gitignored的分类治理原则、合并管线与smartStage()等关键函数的简化路径以及该方案如何被后续 ADR-016 系列与 DB 权威DB-authoritative运行时模型取代的完整来龙去脉——这些知识对理解本仓库src/resources/extensions/gsd/下的工作树、合并与状态同步代码至关重要。背景GSD 如何用 Git 隔离自治编码会话GSDgsd-2使用 Git 作为自治编码会话期间的隔离机制。该 ADR 记录的当前架构在 M003、v2.13.0 中发布为每个里程碑创建一个工作树worktree并在每个工作树内部使用切片分支slice branch每个切片S01、S02、...在自己的分支gsd/M001/S01上工作切片完成时通过--no-ff合回里程碑分支milestone/M001里程碑完成时里程碑分支再 squash-merge 回main。这套架构是为了取代更早的「每切片一分支branch-per-slice」模型——后者引发了严重的.gsd/合并冲突。M003 解决了合并冲突却保留工作树内的切片分支继承了大量复杂逻辑并持续产生面向用户可见的失败。从源码看这一「每里程碑一个工作树」的模型至今仍是仓库的骨架src/resources/extensions/gsd/auto-worktree.ts拥有工作树的创建/进入/退出/合并生命周期src/resources/extensions/gsd/git-service.ts提供底层 Git 原语与暂存逻辑。五大问题切片分支模型为什么必须被推翻ADR-001 用五个层面的证据论证切片分支是「根因性的复杂度来源」。1. 规划产物不可见循环检测失败当research-slice或plan-slice分派时Agent 在切片分支上写入产物例如S02-RESEARCH.md。Agent 完成后handleAgentEnd会切回里程碑分支准备下一次分派——此时产物停留在切片分支上里程碑分支看不到它。verifyExpectedArtifact()当前实现于 auto-recovery.ts检查的是里程碑分支找不到文件就递增循环计数器并重试3 次重试后硬停止6 次生命周期分派后永久停止。结果就是烧掉预算、阻塞进度。这个问题在 auto-stop 架构文档中被记录为The Branch-Switching Problem分支切换问题。2..gsd/状态跨分支互相覆盖.gsd/是 gitignored 的.gitignore中的.gsd/规划产物roadmap、plans、summaries、decisions、requirements位于.gsd/milestones/但对 Git 不可见。当多个分支或工作树在同一个仓库上运行时它们共享磁盘上同一个.gsd/目录分支 A 的 M001 roadmap 会覆盖分支 B 的 M001 roadmap。GSD 读取到损坏的状态把错误的里程碑判为完成或陷入无限分派循环。该 ADR 还指出了代码库中的一个自相矛盾的 workaroundsmartStage()git-service.ts中的暂存逻辑尽管.gitignore声明忽略.gsd/仍会 force-addGSD_DURABLE_PATHSmilestones/、DECISIONS.md、PROJECT.md、REQUIREMENTS.md、QUEUE.md。这意味着.gsd/milestones/在某些分支上确实被部分跟踪而 gitignore 却声称相反——代码在与配置打架。源码佐证现状这一「代码与配置打架」的张力在后续演进中被形式化而非消除——git-service.ts 定义了RUNTIME_EXCLUSION_PATHS.gsd/activity/、.gsd/runtime/、.gsd/worktrees/、.gsd/gsd.db*、.gsd/STATE.md、.gsd/DISCUSSION-MANIFEST.json等其注释明确要求与 gitignore.ts 中的GSD_RUNTIME_PATTERNS保持同步两者互为 canonical 来源。这意味着暂存时只排除运行时路径而不是整体排除.gsd/。3. 合并/冲突代码复杂度切片分支模型需要一整套合并与冲突处理管线mergeSliceToMilestone()—— 98 行带withMergeHeal包装的--no-ff合并mergeSliceToMain()—— 189 行带冲突检测/分类/自动解决的 squash-mergegit-self-heal.ts—— 198 行3 个针对合并失败的恢复函数fix-merge分派单元 —— 专门用一个 LLM 会话来解决自动解决器搞不定的冲突smartStage()—— 49 行运行时暂存排除逻辑冲突分类 —— 80 行区分.gsd/冲突、运行时冲突与代码冲突总计约 582 行、分布在 3 个文件中的合并/分支/冲突代码外加fix-merge提示词模板与分派逻辑——而这些代码的存在仅仅是为了服务切片分支。4. 双隔离模式分支模式git-service.ts:mergeSliceToMain与工作树模式auto-worktree.ts:mergeSliceToMilestone是两套并行实现不同的合并策略、不同的冲突处理、不同的分支命名。两条路径都必须被维护和测试——共有 11 个测试文件覆盖合并/分支/工作树逻辑。5. Bug 历史v2.11.1因分支切换导致的解析缓存过期引发重复单元分派发布 URGENT 修复v2.13.1Windows 热修复mergeSliceToMilestone中的多行提交信息M003 之前15 个针对.gsd/合并冲突的独立 bug 修复持续的用户投诉循环检测失败与状态损坏决策彻底消灭切片分支ADR-001 的核心决策是Eliminate slice branches entirely.彻底消除切片分支。里程碑工作树内的所有工作都按顺序提交在同一条分支milestone/MID上。没有分支创建、没有分支切换、没有切片合并、没有工作树内冲突解决。同时把.gsd/规划产物纳入 Git 跟踪只忽略运行时/临时状态。目标架构main ──────────────────────────────────────────── main │ ↑ └─ worktree (milestone/M001) │ │ │ commit: feat(M001): context roadmap │ commit: feat(M001/S01): research │ commit: feat(M001/S01): plan │ commit: feat(M001/S01/T01): impl │ commit: feat(M001/S01/T02): impl │ commit: feat(M001/S01): summary UAT │ commit: feat(M001/S02): research │ commit: ... │ commit: feat(M001): milestone complete │ │ │ └──────────── squash merge ──────────────────┘使用的 Git 原语原语用途Worktrees工作树每个活动里程碑一个。文件系统级隔离。Commits提交每次动作的粒度化顺序历史。Squash merge每个里程碑在main上留下一个干净的单一提交。Branches分支只有main和milestone/MID。没有其他分支。不使用的 Git 原语原语原因切片分支切片是顺序执行的。分支只会增加复杂度没有任何回滚收益。--no-ff合并工作树内没有分支需要合并。分支切换从不发生。所有工作都在一条分支上。冲突解决工作树内没有合并就没有工作树内冲突。状态归属模型.gsd/从「整体忽略」到「分类治理」ADR-001 对.gsd/的归属做了关键切分纳入 Git 跟踪随分支流转.gsd/milestones/ — roadmaps, plans, summaries, research, contexts, task plans/summaries .gsd/PROJECT.md — project overview .gsd/DECISIONS.md — architectural decision register .gsd/REQUIREMENTS.md — requirements register .gsd/QUEUE.md — work queue保持 gitignored临时、运行时、基础设施.gsd/runtime/ — dispatch records, timeout tracking .gsd/activity/ — JSONL session dumps .gsd/worktrees/ — git worktree working directories .gsd/auto.lock — crash detection sentinel .gsd/metrics.json — token/cost accumulator .gsd/completed-units.json — dispatch idempotency tracker .gsd/STATE.md — rendered state projection .gsd/gsd.db — authoritative runtime database (local, gitignored) .gsd/DISCUSSION-MANIFEST.json — discussion phase tracking .gsd/milestones/**/*-CONTINUE.md — interrupted-work markers .gsd/milestones/**/continue.md — legacy continue markers.gitignore更新方案用显式的「仅运行时忽略」替代一刀切的.gsd/忽略# ── GSD: Runtime / Ephemeral ───────────────────────────────── .gsd/auto.lock .gsd/completed-units.json .gsd/STATE.md .gsd/metrics.json .gsd/gsd.db .gsd/activity/ .gsd/runtime/ .gsd/worktrees/ .gsd/DISCUSSION-MANIFEST.json .gsd/milestones/**/*-CONTINUE.md .gsd/milestones/**/continue.md规划产物milestones/、PROJECT.md、DECISIONS.md、REQUIREMENTS.md、QUEUE.md不在.gitignore中按常规方式被跟踪。现状对照本仓库根目录 .gitignore 至今仍保留# ── GSD project state (per-worktree, never committed) ── .gsd/以及.gsd/gsd.db的整体忽略——这正是该 ADR 的决策「未被采纳」的直接体现详见下文「取代与演进」。但GSD_RUNTIME_PATTERNS的精细化模式已在 gitignore.ts 落地为可编程的运行时路径清单。落地后的代码形态变化Consequences代码删除清单文件删除行数移除内容auto-worktree.ts~246mergeSliceToMilestone()、shouldUseWorktreeIsolation()、getMergeToMainMode()、切片合并守卫git-service.ts~250mergeSliceToMain()、冲突解决、合并后运行时剥离、ensureSliceBranch()、switchToMain()git-self-heal.ts~86abortAndReset()、withMergeHeal()合并专用恢复auto.ts~150合并分派守卫、fix-merge分派路径、分支模式路由worktree.ts~40getSliceBranchName()、ensureSliceBranch()、mergeSliceToMain()委托测试文件~11 个文件auto-worktree-merge.test.ts、auto-worktree-milestone-merge.test.ts及相关合并测试用例总计~770 行mergeMilestoneToMain()变成什么该函数被大幅简化流程变为六步自动提交工作树中的任何脏状态chdir回到 main 仓库根git checkout maingit merge --squash milestone/MID用里程碑摘要git commit移除工作树并删除分支不再有冲突分类、不再有运行时文件剥离、不再有.gsd/特殊处理。规划产物能干净合并是因为它们位于.gsd/milestones/M001/——在合并之前main上根本不存在这个目录。源码佐证现状mergeMilestoneToMain()至今仍存在于 auto-worktree.ts其实现保留了 ADR 规划的第一要素——「自动提交脏状态」并增加了并行模式守卫仅当 cwd 处于里程碑分支时才自动提交防止在集成分支上误提交他里程碑的脏文件污染main#2929随后还会先把工作树 DB 回灌到 main DB 再离开工作树上下文。测试可参考 auto-worktree-milestone-merge.test.ts 与 all-milestones-complete-merge.test.ts。smartStage()变成什么GSD_DURABLE_PATHS的 force-add 不再需要——规划产物不再被 gitignoregit add -A自然收录它们。函数缩减为git add -Agit reset HEAD -- runtime paths取消暂存运行时文件_runtimeFilesCleanedUp的一次性迁移逻辑也可以删除。源码对照当前 git-service.ts 的smartStage()已经演进为「用 pathspec 排除暂存」模式排除RUNTIME_EXCLUSION_PATHS而非整个.gsd/以避免大型未跟踪产物树导致git add -A挂起#1605并防止里程碑中途整体排除.gsd/造成后半段产物永不提交的静默失败#1326。它还包含并行工作者的里程碑锁GSD_MILESTONE_LOCK逻辑只暂存属于本里程碑的文件#1991。这验证了 ADR 判断——暂存逻辑的复杂度中心从「合并」转移到了「运行时路径排除与并行作用域」。handleAgentEnd()变成什么任一单元完成后使缓存失效autoCommitCurrentBranch()—— 在唯一的分支上提交verifyExpectedArtifact()—— 文件总是在当前分支上没有分支切换持久化完成键Path A fix原 937-953 行成为唯一路径分支不匹配不可能发生。fix-merge消亡fix-merge分派单元类型被彻底消除。工作树内没有任何会产生冲突的合并。唯一的合并是里程碑→mainsquash万一冲突罕见的并行里程碑边缘情况就在里程碑完成时做一次性解决——而不是进入分派循环。向后兼容shouldUseWorktreeIsolation()的三级偏好解析被单一行为取代始终使用工作树隔离。git.isolation: branch偏好被弃用。拥有既有gsd/M001/S01切片分支的项目仍可被状态推导state derivation读取但新工作不再创建切片分支。风险与缓解Risks1. 并行里程碑在 squash-merge 时的代码冲突如果两个里程碑修改同一源文件第二个 squash-merge 回main时会冲突。缓解squash-merge 前先git fetch origin main git rebase main。这是标准实践在单用户工作流中很少见。2. squash 后丢失逐切片 Git 历史squash 合并把main上所有提交折叠成一个。缓解提交信息带切片标签feat(M001/S01/T01):——可用git log --grep过滤里程碑分支可以保留不删除以备需要历史备选用merge --no-ff替代--squash以在main上保留历史3.git reset后 SQLite DB 失同步如果被跟踪的 markdown 通过git reset --hard回滚被 gitignored 的gsd.db不会回滚。当前 GSD 在运行时把数据库视为权威不会静默导入 markdown 投影。当数据库丢失或损坏、而 markdown 才是意图来源时操作者应使用显式的恢复/导入命令。4. 多工作树的磁盘占用每个工作树都会复制工作目录包括node_modules。缓解同一时间只保持一个活动里程碑单用户工作流完成后立即清理。备选方案分析Alternatives ConsideredA. 保留切片分支用即时迷你合并修复可见性research-slice或plan-slice后立即把切片分支合并回里程碑分支。这能修复循环检测 bug但保留全部合并复杂度。被拒新增一条合并路径而非移除根因仍需要冲突解决、自愈、分支切换。B. 保持.gsd/gitignored对手动工作树从 Git 历史引导状态当 GSD 在工作树中检测到空的.gsd/时用git show commit:.gsd/...从分支的 Git 历史重建状态。被拒这是恢复逻辑不是架构。不解决分支无关状态的根本问题Git 历史被重写时会失效。C. 分支作用域的.gsd/目录.gsd/branches/branch-name/milestones/...每个分支在.gsd/内的命名空间子目录中写入。被拒增加复杂度而非移除复杂度分支创建时需要重命名/移动目录且与标准 Git 工具不兼容git checkout不会重命名目录。验证三方模型压力测试与 Codex 异议该架构由三个独立模型压力测试过Gemini 2.5 Pro识别出 6 个攻击向量无一击穿核心模型。建议squash-merge 前预检 rebase已采纳、心跳锁已存在、启动时重建 DB已通过 M001/S02 importers 采纳。GPT-5.4 (Codex)通读全代码库后确认模型健全并指出smartStage()已经在 force-add 持久化路径印证了「跟踪产物」思路以及 PR #487 中的resolveMainWorktreeRoot在架构上是错误的已采纳——PR 将关闭。代码库分析确认.gsd/milestones/尽管被.gitignore声明忽略main上实际已被部分跟踪GSD_DURABLE_PATHS的存在本身就是代码层面对「规划产物应当被跟踪」的承认README 也已记录了正确的「仅运行时忽略」模式。Codex 异议与逐条回应异议 1「切片完成后、集成前崩溃——今天运行时能检测孤儿切片分支并合并它们。」回应无分支模型下没有可崩溃的集成步骤。切片工作直接提交在里程碑分支上重启时deriveState()按原样读取分支状态。孤儿分支恢复路径的存在仅仅是因为切片分支——移除分支就移除了它要恢复的故障模式。异议 2「两个终端并发编辑共享根文档PROJECT.md、DECISIONS.md。」回应有效的边缘情况。如果/gsd queue在main上编辑DECISIONS.md同时 auto 模式在工作树中编辑它squash-merge 时会有内容冲突。这是标准的 Git 内容冲突——与两个开发者编辑同一文件无异交给常规合并解决处理。既不是切片分支导致的也不能靠切片分支解决。异议 3「切片→里程碑合并提供了持续集成。移除它们会把冲突发现推迟到最后。」回应在单用户顺序工作流中工作树内没有东西需要集成——每个切片都构建在前一个之上。唯一冲突源是main分叉例如另一个里程碑先合并而切片→里程碑合并本来就抓不到这种冲突——它在工作树内合并不是对main合并。squash-merge 前的预检 rebase 能更直接地捕获它。异议 4「用另一个显式的切片边界原语替代切片分支而不是直接删除。」回应精神上接受。带规范标签的提交feat(M001/S01):、feat(M001/S01/T01):就是切片边界原语git log --grepM001/S01可隔离切片历史git revert可定位特定提交Git 标签gsd/M001/S01-complete可在需要时标记切片完成。边界原语是提交元数据而不是分支。行动清单回顾关闭 PR #487resolveMainWorktreeRoot——与该架构矛盾作为一个带阶段的 GSD 里程碑实施更新.gitignore并 force-add 既有规划产物移除切片分支的创建/切换/合并代码简化mergeMilestoneToMain()与smartStage()移除fix-merge分派单元移除分支模式隔离git.isolation: branch更新/删除 11 个测试文件更新 README 建议的 gitignore为既有切片分支项目提供迁移路径取代与演进ADR-001 的历史坐标阅读本 ADR 必须注意其状态栏Superseded2026-05-08 被取代。替代它的不是单一文档而是一个「三胞胎 一」的决策簇ADR-016-worktree-lifecycle-and-projection.md把工作树处理拆成「生命周期」与「状态投影」两个模块用WorktreeLifecycleenterMilestone/exitMilestone/restoreToProjectRoot等动词与WorktreeStateProjectionprojectRootToWorktree/projectWorktreeToRoot/finalizeProjectionForMerge接口收拢s.basePath变更与process.chdir纪律并把WorktreeResolver的 28 字段依赖接口退役ADR-016-worktree-safety-fail-closed.md工作树状态的 fail-closed 校验ADR-016-worktree-lifecycle-and-projection 的 phase-2 设计ADR-017-state-reconciliation-drift-driven.md漂移驱动的状态调和取代的核心原因是问题定义变了ADR-001 的原始动机.gsd/合并冲突、规划产物可见性被DB 权威运行时模型取代——项目根数据库.gsd/gsd.db成为权威markdown 文件成为投影projection跨分支状态互相覆盖不再是该 ADR 试图修复的故障模式。这一点在源码中有明确印记auto.ts 标注「DB status is the authoritative」、auto-recovery.ts 对execute-task/complete-slice以 DB 状态为权威同时 query-tools.ts 提供「flush SQLite WAL 后再git add .gsd/gsd.db」的工具说明gsd.db在部分路径下也会被提交。剩余的与工作树相关的关切生命周期归属、fail-closed 源码写入、漂移修复由ADR-014Auto Orchestration 深度模块、ADR-015运行时不变性模块、ADR-016 三件套与 ADR-017 分别收敛。同时里程碑工作树内的切片分支被保留了下来——ADR-016 的 carve-out 清单中仍可见mergeSliceToMain当前实现于 slice-cadence.ts由git.collapse_cadence: slice配置驱动#4765等合并原语说明「每切片即时合并回 main」的片节奏slice-cadence模式在现行版本中成为可选项。一句话概括这个演进ADR-001 的诊断切片分支是复杂度的源头和药方更简单的合并面、更清晰的.gsd/归属、用提交元数据做切片边界大部分被继承但它的主攻方向——把规划产物变成被跟踪的 Git 状态——被「SQLite 数据库权威 markdown 投影」的新模型取代后者成为当前仓库处理自治编码状态的根本范式。因此本文第一部分的历史分析§Decision 之前的全部内容保留作上下文参考而 §Decision 中的决策未被原样采纳。延伸阅读PRD-branchless-worktree-architecture.md该架构的产品需求文档补充动机与验收标准ADR-016-worktree-lifecycle-and-projection.md工作树生命周期与状态投影模块拆分直接继任者ADR-017-state-reconciliation-drift-driven.md漂移驱动的状态调和ADR-002-external-state-directory.md外部状态目录设计理解.gsd/归属争论的姊妹决策核心实现git-service.ts、auto-worktree.ts、gitignore.ts关键测试auto-worktree-milestone-merge.test.ts、gitignore-staging-2570.test.ts、git-service.test.ts其中对RUNTIME_EXCLUSION_PATHS的断言直接检验了「运行时路径永不入库」这一不变性赞分享人工智能AI Agent代码智能体Agent 编排CLIAI 应用【免费下载链接】gsd-2A powerful meta-prompting, context engineering and spec-driven development system that enables agents to work for long periods of time autonomously without losing track of the big picture项目地址https://gitcode.com/gh_mirrors/gs/gsd-2点击查看免费下载相关推荐GSD 无分支 Worktree 架构 PRD 全解析从 slice 分支模型到单分支顺序提交的演进设计GSD 无分支 Worktree 架构 PRD 全解析从 slice 分支模型到单分支顺序提交的演进设计 本文围绕 docs/dev/PRD branchle人工智能AI Agent代码智能体Agent 编排CLIAI 应用【亲测免费】 探索 Git 的无分支工作流git-branchless探索 Git 的无分支工作流git branchless 项目介绍 git branchless 是一个增强 Git 工作流的工具套件旨在使 Git 的使用开发工具CWLateralSlide手势冲突解决方案完美处理TableView侧滑删除问题CWLateralSlide手势冲突解决方案完美处理TableView侧滑删除问题 在iOS开发中实现侧滑抽屉功能时经常会遇到与TableView原生侧滑删上一篇AndroidLibs实操教程如何快速集成图片加载框架下一篇在 Vercel 上零配置部署 Create React App从项目初始化到 vercel dev 联调创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考