fix(tooling): merge 驱动不再绑定到「上一个装过依赖的 worktree」,并补上悬空判红的断言 (#4868) - #4908
Merged
xuyushun441-sys merged 1 commit intoAug 3, 2026
Merged
Conversation
`setup-git-hooks.mjs` 把绝对路径 `${REPO_ROOT}/scripts/git-merge-regen.mjs` 写进
`.git/config`。linked worktree 共用同一份 config,于是每次 `pnpm install` 都把全容器
的驱动改指向刚装完的那个 worktree;而 AGENTS.md 要求收尾时 `git worktree remove`
—— 遵守这条纪律恰恰就是触发缺陷的动作。该 worktree 一删,所有 agent 凡碰到
`merge=os-regen` 映射文件的 merge 全部 MODULE_NOT_FOUND。路径已漂过四个 worktree。
改为 `node "$(git rev-parse --show-toplevel)/scripts/git-merge-regen.mjs" %O %A %B %P`:
git 把 merge 驱动交给 shell 执行,命令替换在每次调用时、在正在被合并的那个工作树里
求值 —— 既不绑定任何具体 worktree,又仍能解析到当前工作树根(绝对路径当初正是为了
后者)。既有 clone 下次 `pnpm install` 自愈。
自检此前照不出这个缺陷:每条既有 `--self-test` 检查都自建临时仓库、注册自己的驱动,
所以真实 config 悬空时它们全绿。新增 `registeredDriverResolves()` 读**实时** config,
在脚本不存在、指向本工作树以外(缺陷咬人前一步)、或与注册值漂移时判红。注册方与
校验方现在共读 `regen-artifacts.mjs` 的同一份 `GIT_SETTINGS` 声明。
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_018iARDqtrhQgz6fVHDeDkbQ
|
The latest updates on your projects. Learn more about Vercel for GitHub. 1 Skipped Deployment
|
xuyushun441-sys
marked this pull request as ready for review
August 3, 2026 15:36
xuyushun441-sys
enabled auto-merge
August 3, 2026 15:36
xuyushun441-sys
deleted the
claude/issue-4868-merge-driver-worktree-independent
branch
August 3, 2026 15:40
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes #4868
缺陷:遵守收尾纪律,就是触发缺陷的动作
scripts/setup-git-hooks.mjs把绝对路径写进merge.os-regen.driver。linked worktree 共用同一份/home/user/objectstack/.git/config,于是每次有人pnpm install,全容器的驱动就被改指向那个人的 worktree。关键的一环不是花絮:AGENTS.md 要求任务收尾时
git worktree remove。所以「按规矩收尾」正是让驱动悬空的那个动作 —— 这就是它为什么必然反复发生,而不是偶发。本单实施期间实测路径漂过四轮(-4796→-4793→-4843→-4890),其中-4843→-4890是我开工到建 worktree 这几分钟内、被另一个并行 agent 的 install 改掉的。驱动一坏,所有 agent 凡碰到
.gitattributes里merge=os-regen映射的文件(spec-changes.json、authorable-surface.json、content/docs/references/**等)的 merge 全部 MODULE_NOT_FOUND。比议题描述的更糟一点:实测驱动崩溃后,git 把该路径留成
UU,里面是 ours、且零冲突标记:也就是说一次条件反射式的
git add -A就会静默吞掉 incoming 那一侧 —— 正是 #4616 那类「无冲突标记地静默吞掉别人的删除」。为什么不能简单改回相对路径
原第 40 行的注释说明绝对路径是刻意的:躲开「相对路径解析到错的根」。所以解法必须同时满足两个约束:
新值:
git 把 merge 驱动命令整条交给 shell,所以命令替换在每次调用时、在正在被合并的那个工作树里求值 —— 两个约束同时满足。既有 clone 下次
pnpm install自愈。议题建议的
!形式是错的 —— 实测,没有照抄议题建议
!node "$(git rev-parse --show-toplevel)"/scripts/...。在 linked worktree 里实测(git 2.43):!前缀是 alias / credential-helper 的语法;merge 驱动的值本来就直接交给 shell,所以!node是在找一个真名叫!node的程序。失败方式还是静默降级成文本合并 —— 比现状更隐蔽。已去掉!。占位符必须保持不加引号 —— 也是实测
顺手「改进」引用会引入新缺陷。git 自己已经对
%P做了 shell 引用:即自己加引号会把字面引号塞进 pathname。已在代码注释里记下这个坑。
其余验证:
$(git rev-parse --show-toplevel)形式在 linked worktree 里、从工作树根和子目录发起的 merge 都正确解析到该 worktree 根。自检本身是反面教材,所以新增断言读实时 config
pnpm check:merge-driver的每一条既有检查都自建临时仓库、注册自己的驱动,所以它和真实调用路径不是同一条。开工时的实测 —— 此时真实 config 指向已删除的-4843:全绿。 这就是它能漂四轮没人发现的原因。
新增
registeredDriverResolves()读实时 config,三种判红方式:判红 1 —— 脚本不存在(悬空,即本单的现场)
判红 2 —— 指向本工作树以外(缺陷咬人前一步)
这条是我加的、议题没提的:worktree 还在、脚本还能解析,但驱动已经绑在别人的 worktree 上 —— 对刚 install 的那个人是绿的,对其他所有人已经是坏的。等到它被删才报,已经晚了。
判红 3 —— 与注册值漂移
实拍(我的
pnpm install用旧代码写进 config 之后):制造悬空态用的是进程级的
GIT_CONFIG_COUNT/GIT_CONFIG_KEY_0注入,没有改共享的.git/config—— 并行 agent 的 merge 不受影响。(判红 1 里既有的endToEnd也跟着红了,那是该注入方式会漏进它自建的临时仓库所致,不是真实场景的行为;判红 2 干净地只有新断言红。)修好后:
真实合并路径验证(比 self-test 更重要 —— self-test 已经证明过它会骗人)
在本 worktree 里构造两侧都改
packages/spec/spec-changes.json的真实合并,不带任何-c覆盖,驱动完全由共享.git/config解析:驱动被正确调用、pending marker 落盘、零冲突。同一场景在悬空值下则是本 PR 开头那段 MODULE_NOT_FOUND。
declared = enforced
注册方(
setup-git-hooks.mjs)与校验方(git-merge-regen.mjs --self-test)此前各写各的;现在共读regen-artifacts.mjs里同一份GIT_SETTINGS声明,少一处可漂移的副本。改动范围
scripts/setup-git-hooks.mjs、scripts/regen-artifacts.mjs、scripts/git-merge-regen.mjs,加一个空 frontmatter changeset(tooling 改动,不发版)。未改根package.json,未改.github/workflows/,未碰content/docs/releases/。pnpm check:merge-driver绿;三个改动脚本 ESLint 干净(exit 0);setup-git-hooks.mjs重复运行仍然静默(幂等)。Generated by Claude Code