问题
resolveGitPath(src/index.ts 附近 151-161 行)对相对路径的解析优先级是:会话 cwd 相对路径若存在,则优先于仓库根相对路径:
const sessionPath = requireAbsolute(join(cwd, raw))
if (await stat(sessionPath).then(() => true).catch(() => false)) return sessionPath
const root = await git.repoRoot(cwd, selected).catch(() => cwd)
return requireAbsolute(join(root, raw))
但 Git status/diff 行的路径是仓库根相对的。当会话 cwd 是仓库的子目录、且子目录下恰好存在同名相对路径时,存在性检查命中,解析结果指向子目录下的同名文件而不是状态行所指的是文件。
危害集中在前瞻性 destructive 的 git.discard
git.stage/git.unstage 不受影响(它们把原始相对路径直接交给 git -C root)
- 但
git.discard(src/index.ts 410 行)先 resolveGitPath 再 git checkout -- <绝对路径>:命中误解析时还原的是另一个文件,状态行所指文件的改动原封不动
具体场景:会话 cwd /repo/pkg,状态行 "README.md"(实际是 /repo/README.md 被修改),而 /repo/pkg/README.md 也存在 → 点 discard(确认后)还原的是 /repo/pkg/README.md;若后者也有未提交改动,这些改动被销毁,而用户以为处理的是状态行那一个文件。若 pkg 下副本无改动,git checkout -- 静默无操作,用户会误以为状态行改动已还原。
同一误解析也影响 fs.read/git.diff 对状态行的预览(展示的是子目录同名文件的内容/diff)。
注释表明「cwd 相对优先」是为嵌套会话的读取安全边界刻意设计的——这个意图合理,但它同时被用于构造破坏性 pathspec,两者冲突。
建议方向
- 对
git.discard(以及状态行驱动的 diff 预览)改为始终按仓库根解析,或
- 解析后校验该路径确被 git 跟踪(
git ls-files 命中)再执行 checkout,未命中时回退仓库根解析,或
- 至少在 discard 确认对话框里显示最终解析出的绝对路径,让用户确认的对象无歧义
问题
resolveGitPath(src/index.ts附近 151-161 行)对相对路径的解析优先级是:会话 cwd 相对路径若存在,则优先于仓库根相对路径:但 Git status/diff 行的路径是仓库根相对的。当会话 cwd 是仓库的子目录、且子目录下恰好存在同名相对路径时,存在性检查命中,解析结果指向子目录下的同名文件而不是状态行所指的是文件。
危害集中在前瞻性 destructive 的 git.discard
git.stage/git.unstage不受影响(它们把原始相对路径直接交给git -C root)git.discard(src/index.ts410 行)先resolveGitPath再git checkout -- <绝对路径>:命中误解析时还原的是另一个文件,状态行所指文件的改动原封不动具体场景:会话 cwd
/repo/pkg,状态行 "README.md"(实际是/repo/README.md被修改),而/repo/pkg/README.md也存在 → 点 discard(确认后)还原的是/repo/pkg/README.md;若后者也有未提交改动,这些改动被销毁,而用户以为处理的是状态行那一个文件。若 pkg 下副本无改动,git checkout --静默无操作,用户会误以为状态行改动已还原。同一误解析也影响
fs.read/git.diff对状态行的预览(展示的是子目录同名文件的内容/diff)。注释表明「cwd 相对优先」是为嵌套会话的读取安全边界刻意设计的——这个意图合理,但它同时被用于构造破坏性 pathspec,两者冲突。
建议方向
git.discard(以及状态行驱动的 diff 预览)改为始终按仓库根解析,或git ls-files命中)再执行 checkout,未命中时回退仓库根解析,或