前言¶
智能體操作多個 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 worktreesync:ahead/behind、fetchAgeSeconds、本次是否真的聯網取過remote:歸一化後的host/owner/repo、host、是否公開 forgeidentity:下一個提交的郵箱、這個郵箱來自哪份配置、倉庫是否有本地覆蓋workingTree:staged/unstaged/untracked與cleanduplicateCheckouts:本機同倉庫的其他 checkout,各自的路徑與領先情況blockers/warnings/verdict/safeToWrite
調用方只需要看一個字段:safeToWrite。blockers 是繼續下去會丟失或錯置工作的狀態,warnings 是值得知道但不必然是錯的情況。
checkout_guard_scan 對某個根目錄下的所有工作副本各返回一行同樣的摘要,外加兩個分組結果:
needsAttention:落後、分叉、detached、或沒有 upstream 的那些 checkoutduplicateRemotes:按遠端分組的路徑,同倉庫有幾份 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 / 幻方無官方從屬關係。