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 / 幻方無官方從屬關係。

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

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

小夜