dsh-checkout-guard:写入前先确认你操作的是哪个工作副本

前言

智能体操作多个 git 仓库时,最贵的错误不是写错了代码,而是在误读的状态下把 git 命令跑对了。一个落后远端的 checkout、一份本机另存的同名 clone、被并发进程挪走的 HEAD,都不会让 git 报错——它只是按你的描述执行,然后你事后才发现改动不见了、推送被拒、提交压在了别人的半成品上。

这类问题的共同点是:出错之前,其实有一个能回答”我现在到底在哪个仓库、哪个分支、相对远端什么位置”的时刻。dsh-checkout-guard 就是在那个时刻介入。

这是什么

一个 DSH 插件,由 YaoleWu 维护(插件目录页的开发者字段,package.json 里的 author 仍写着 LeslieWylie,仓库已迁移到 YaoleWu/dsh-checkout-guard 名下)。它读取一个 git 工作副本,在编辑、提交、推送之前告诉你:分支身份、与远端的分叉/落后程度、这个数据的陈旧度、下一个提交会署哪个邮箱、暂存区里已有什么、以及本机是否还有同仓库的另一份 clone 已经跑在你前面。

只读,默认不联网,从不占用 index 锁。

核心功能

插件提供两个工具。

checkout_guard 对单个工作副本做一次深度检查,输出结构化结果,字段包括:

  • branch:当前分支、是否 detached、upstream、是否 linked worktree
  • sync:ahead / behind、fetchAgeSeconds、本次是否真的联网取过
  • remote:归一化后的 host/owner/repo、host、是否公开 forge
  • identity:下一个提交的邮箱、这个邮箱来自哪份配置、仓库是否有本地覆盖
  • workingTree:staged / unstaged / untracked 与 clean
  • duplicateCheckouts:本机同仓库的其他 checkout,各自的路径与领先情况
  • blockers / warnings / verdict / safeToWrite

调用方只需要看一个字段:safeToWrite。blockers 是继续下去会丢失或错置工作的状态,warnings 是值得知道但不必然是错的情况。

checkout_guard_scan 对某个根目录下的所有工作副本各返回一行同样的摘要,外加两个分组结果:

  • needsAttention:落后、分叉、detached、或没有 upstream 的那些 checkout
  • duplicateRemotes:按远端分组的路径,同仓库有几份 clone 一眼可见

典型用法是先跑 checkout_guard_scan 找到值得细看的副本,再把路径逐个交给 checkout_guard。

安装与启用

需要 Node 22.19+ 或 24+,运行期唯一依赖是 git 在 PATH 上。

npm install dsh-checkout-guard

然后在 profile 的 cordis.yml 追加:

- id: checkout-guard
  name: 'dsh-checkout-guard'

如果要限定插件的搜索范围,加上 config.roots:

- id: checkout-guard
  name: 'dsh-checkout-guard'
  config:
    roots:
      - /Users/you/projects

roots 限定插件会看的一切范围,不设时默认为你的 home 目录。当前版本为 0.1.0,许可证 MIT,peerDependencies 要求 @deepseek-ai/cordis ^4.0.1 与 @deepseek-ai/dsh-tools ^0.1.0-rc.6。

典型用法

对单个副本做断言式检查。传入 expectBranch 时,实际分支与预期不符直接记为 blocker:

{ "path": "/abs/path/to/repo", "expectBranch": "main" }

返回示例(节选):

{
  "branch":   { "current": "main", "detached": false, "upstream": "origin/main", "linkedWorktree": false },
  "sync":     { "ahead": 1, "behind": 1, "fetchAgeSeconds": 255600, "fetchedNow": false },
  "remote":   { "normalized": "github.com/acme/widget", "host": "github.com", "publicForge": true },
  "identity": { "email": "you@example.com", "source": "global", "repositoryOverride": false },
  "blockers": [
    "diverged from origin/main by 1 commit(s) (and 1 ahead); ... a push will be rejected",
    "another checkout of the same remote is ahead of this one: /elsewhere/widget ..."
  ],
  "verdict": "blocked",
  "safeToWrite": false
}

checkout_guard 可用参数:

参数 作用
path(必填) 工作副本的绝对路径,或其内部任意子目录
fetch 先联系远端让 ahead/behind 反映当下。唯一联网的选项,默认 false
expectBranch 你认为自己在哪个分支,不符即 blocker
expectIdentity 你期望的提交署名邮箱,不符即 blocker
remote 对比哪个远端,默认 origin
staleAfterHours 远端 ref 多久算陈旧,默认 24
findDuplicates / duplicateRoots / maxDepth / maxRepos 控制重复 clone 的搜索范围

expectBranch 和 expectIdentity 是把报告变成断言的开关。不传,插件只描述;传了,插件会拒绝。

把断言关闭、只看静默扫描结果的场景:

{ "roots": ["/abs/path/to/projects"], "maxDepth": 3 }

安全性质与适用场景

插件的安全约束与其问题域一致——它假设此刻可能还有另一个 agent 在同一个 checkout 里:

  • 不对任何仓库写入。唯一可能修改东西的命令是 git fetch --dry-run,仅在 fetch: true 时执行,且只动 FETCH_HEAD。
  • 每次调用都带 GIT_OPTIONAL_LOCKS=0,避免 git status 骗取 .git/index.lock 而卡住并发进程。
  • GIT_TERMINAL_PROMPT=0、空 GIT_ASKPASS,对私有远端 fetch 快速失败,不会停在无人可见的凭据提示上。
  • URL 归一化时先剥掉内嵌凭据,凭据无法进入结果对象或日志。
  • 路径白名单两侧都做 realpath,放在允许目录里的软链接读不到外面。

适合谁:在 DSH 里同时操作多个仓库的智能体与开发者。它刻意不做三件事:不告诉你远端是否已归档(那需要 forge API,插件不发带认证的 HTTP 请求,remote.normalized 给你 host/owner/repo 自己去查);不修任何东西(不 pull、不 rebase、不 stash、不 checkout,”落后”和”分叉”的正确恢复方式不同,这个选择不该由守卫替你做);不评判身份(只报告署名来自哪份配置,传了 expectIdentity 就严格按你给的值比对,从不猜测邮箱”应该”是什么)。

插件以当前 dsh 进程的权限运行,安装前应检查源码与许可证(本插件为 MIT)。

结尾

dsh-checkout-guard 做的事很小:在你下一个写操作之前回答一次”我到底在哪儿”。它不会替你修仓库,也无法阻止你在拿到 safeToWrite: false 之后继续,但至少让那个误读的状态在日志里留下一条明确记录,而不是事后在推送失败里才被发现。

  • 目录页:https://www.skillhub.cn/plugins/YaoleWu/dsh-checkout-guard
  • GitHub:https://github.com/YaoleWu/dsh-checkout-guard

DSH 理念是”一切皆插件”,社区目录是独立站点,与 DeepSeek / 幻方无官方从属关系。

羽毛球分组比赛记分
小程序二维码

欢迎使用《羽毛球分组比赛记分》微信小程序

小夜