我们开源了一个 skill 防止你的硬盘被 code agent 的 worktree 吃光

我们又开源了一个 agent skill,叫 git-hygiene。它和之前那一对 design-review / build-phases 一样,住在 ArcBlock/agent-skills 的 agentloop 插件里,解决的是 agent coding 常态化之后的另一个具体问题:
并行跑的 agent 越多,散落的工作目录就越多;收工时真正怕的不是麻烦,是删错。
这几个月我自己机器上反复发生同一件事:一次多分支收工,一个仓库里能扫出几十个本地分支、十几个 worktree。大半是不同 agent 各自留下的。git-hygiene 就是专门处理这件事的,而且处理得比我自己动手更小心。
怎么装、怎么用
它们是 agent skill,不绑定某一个具体的 agent。Claude Code 和 Codex 都能用。
安装(和系列里其它 agentloop skill 同一条路):
npx add-skill arcblock/agentloop装完之后,直接用自然语言触发就行。默认收工:
切到 main / 拉最新 / 清理没用的 worktree 和 branch或更短一点:
收工清分支
git hygiene默认流程做四件事:回默认分支、pull --ff-only 对齐远端、把每条本地分支 / worktree 按证据强弱分类,再只删已经证明安全的那些。
想再往前走一步、对「看起来还在的分支」做产权调查,再说清楚一点:
这些保留下来的分支是不是该补 PR,仔细核对这一层更贵,不是默认动作,只在你明确要求时才跑。完整实现就是 skill 自己的 SKILL.md,可以直接读。
每个 agent 一份工作区,是刚需不是浪费
以前一个人写代码,一个仓库一个工作目录,分支切来切去,收工时自己心里有数哪些能删。agent coding 把这件事的规模改了。
我现在常态是好几个 agent 同时在跑:一个在实现某个 feature,一个在独立 review 它的 PR,一个在修另一处的 bug,互不干扰。要做到互不干扰,唯一办法是每个 agent 一份 worktree。worktree 是 git 自带的功能:同一个仓库可以开出好几份独立的工作目录,各自签出不同分支,谁也不会因为切换自己的分支,连带把另一个 agent 正在用的那份目录也带着切走。
这是对的架构,不是可以省的步骤。如果几个 agent 共享同一份工作目录,任何一个执行 git checkout,所有人看到的当前分支都会跟着变。这类事故我们真踩过。worktree 隔离解决的正是这个问题,代价是每个隔离出来的工作目录,都是一份独立的、完整的仓库拷贝。
硬盘是怎么被吃满的
问题出在收工之后。一个 agent 把 PR 合完,它的 worktree 该删了,但「该删」和「被删」之间没有天然的连接。没人天天盯着这件事,而且我自己也不敢随手删,因为不确定这个分支是不是真的已经合并了。犹豫的结果就是攒着。
攒着的代价是真实的磁盘空间。我在存储这件事上吃过亏不止一次:早年电脑程序、数据、介质全绑在一起,车库里那些软盘、backup 光盘和磁带,现在想读出来都成问题了 🤣。那次的教训是「东西放着没人管,代价会在很久以后才显现,显现的时候已经晚了」。这次是同一个模式换了个显现方式:不是几十年后读不出来,是几周内硬盘就写满了。
我的机器是 1T。这几个月被这些散落的 worktree 一点点占满,每一份都是一个大仓库的完整拷贝,依赖包、构建产物、测试夹具全带着。几十份叠起来,很快就有感觉。
手工清理最怕的不是麻烦,是删错
真正让我犹豫的不是「删这么多分支好麻烦」,是「这条分支我到底能不能删」。
git branch -d(小写,只删已确认合并的分支,删不掉就报错)对 squash 合并完全不管用。squash 会把一条分支上的好几个 commit 压成一个新 commit 再合进主分支:内容一样,对象却是新的,跟原来分支上那几个 commit 已经对不上号。我们绝大多数 PR 都是 squash 合并,而 git branch --merged 靠的正是这种逐个 commit 的比对,会把明明合并过的分支报告成「还没合并」。真信了这个报告去一条条查 PR 状态,比不清理还累。
反过来,如果图省事直接上大写的 git branch -D(强制删,不管有没有独有内容),风险是删掉还没推上去的真实工作。而这恰好是并行 agent 场景下最容易发生的事:某个 agent 才写到一半就被打断,分支还躺在本地,你分不清它是「这活儿已经交了」还是「这活儿还没干完」。
skill 怎么判断
skill 的核心不是「删」,是先证明能删。对每一条本地分支,它按证据强弱分四类,一条一条来:
- SAFE:分支 tip 已经是
main(或仓库默认分支)历史里的祖先,内容已经进去了,可删。 - SQUASH_CANDIDATE:不是祖先,但 GitHub 上对应 PR 是
MERGED。多半是 squash 合并,不能直接信,要再做内容比对,确认没有漏掉的改动,才能删。 - KEEP:既不是祖先,也证不了已在 default 上(或 worktree 还 dirty / locked)。原样保留,报告出来,交给人判断。
- DETACHED_TMP:
/tmp一类路径下、一看就是临时审查沙箱、没签出到任何分支上的工作目录,单独识别出来处理。
默认动作只做「删」这一件事里最有把握的那部分。有独有内容的分支一律留着,不猜、不赌。
主工作区若还有未提交改动,它会先停下来,不 checkout、不删。只做 pull --ff-only,有分叉就报告,不擅自 rebase 修。远程显示 gone 也不等于本地可删:远端没了,本地 tip 仍可能有未合入的提交。
更进一步:这条分支到底该不该补 PR
清理时还会冒出一个新问题。几个「看起来是正经任务」的分支从没走过 PR,按老逻辑只能一直保留着,越攒越多,谁也不会去处理。
所以 skill 加了一层:你明确要求时,对每条 KEEP 分支先去 GitHub 查真实身份。
- 是不是已经通过另一个分支合并了,只是这条本地分支自己没跟着更新
- 是不是原来的 PR 关掉了,内容被另一个 PR 取代了
- 是不是其实有一条活跃的 open PR,只是被自动化系统盯着,不需要你插手
- 真的从来没开过 PR,才进入补交流程
补交前还有一步不能跳:不能只看「有独有 commit」就认定是好东西。得去比对文件的真实内容。很多时候那些改动早就通过别的路径进了 main,只是这条分支自己没跟上。
这次实测下来,五条看起来都「正经」的分支里,只有一条是真缺失,补了一个 PR;其余四条,要么已经合并、要么被取代、要么已经有人在跟。这一层现在已经跟着 skill 一起在 agent-skills 里,装了 agentloop 就能用。
什么时候不适合
它不会替你 merge PR,不会 force-push,不会 git clean -fdx,也不会动还没提交的改动。分支状态本身模糊不清,既没有清楚的 PR 证据,内容比对也说不准,它会原样留着,把判断权交回给人,不会为了「清得干净」去赌一把。
它也不替代创建 worktree 的工具。git-worktree 一类 skill 管的是怎么开并行目录;git-hygiene 管的是收工时怎么安全收。两边各做一段。
适合的场景很具体:多 agent 并行一段时间之后、PR 合完之后、你想切回 main 把主工作区复位,又怕手一滑删掉还没推完的活。如果你只有一个工作目录、分支也只有两三条,直接自己 git branch -d 就够了,不必启动这套。
这是同一条路上的另一块
上一篇 讲的是:计划会漂,得用干净上下文一轮轮审,再分阶段做。这篇讲的是:并行工作区是对的架构,但收工判断也得变成可重复、可信任的东西,不能再靠一个人凭印象点头。
两件事看起来一个管「怎么做」,一个管「做完怎么收」,其实是同一个问题的两面:agent coding 把规模抬上去之后,原来靠人脑记的那部分,得沉淀成 skill。
git-hygiene 解决不了「要不要清理」这个决定。它解决的是:清理时怎么保证不删错东西。
GitHub: github.com/ArcBlock/agent-skills · skill 源码:plugins/agentloop/skills/git-hygiene
系列相关: