大師篇 · 第 18 章
平行 session 與 Git Worktrees
到這一章,你已經會開一個 Claude、會用子代理、會排背景任務。現在把場面放大:達人不是「開一個 Claude 等它做完再開下一個」,而是同時開五個、甚至十幾個 Claude 各做各的。問題來了——它們都在同一個資料夾改檔,不是會互相覆蓋、撞成一團嗎?這章教你用 Git 的 worktree(工作樹)給每個分身一塊獨立的工作目錄,讓它們各寫各的、互不打架。我們從一個指令的 flag 開始,一路走到 Boris 同時跑十幾個分身的日常工作流,最後看一個誇張案例:十六個 Claude 合力寫出十萬行的 C 編譯器。
先講為什麼需要它。假設你想同時請 Claude 做三件事:改 A 功能、修 B 的 bug、把 C 重構。你開三個終端機分頁、各跑一個 Claude,聽起來很美好——但它們三個都在同一個資料夾裡讀檔、改檔。A 改到一半的檔案,B 讀進去就是改壞的半成品;C 一存檔,把 A 剛寫好的東西蓋掉。三個分身在同一張桌子上搶同一疊紙,結果就是一團亂。
Git 早就有現成的解法叫 (工作樹):同一個 Git 儲存庫,可以同時 checkout 出好幾份獨立的工作目錄,每份各在自己的分支上,改動互不干擾,但底層共用同一份版本歷史。Claude Code 把這件事包成一個 flag——你不用自己手動建 worktree、自己記哪個分身在哪個目錄,它幫你開好、跑完沒改動還會自動收掉。這章就是教你怎麼用這套機制,把「同時開很多個 Claude」從災難變成生產力。
本章含官方與需注意兩級資料
本章內容混用不同可信度的來源,正文會用 source-tag 徽章逐處標明分級。例如 官方 表示出自 Anthropic 官方文件;實驗性 表示前沿、尚未定型、斟酌採用。完整四級(官方/達人/社群/實驗性)見正文。
前面學過的接這裡
第 10 章的「多代理自動化」教過子代理與背景任務,那是「一個 Claude 派分身、或把任務丟到背景」。這章是更上一層的「很多個 Claude session 平行開」——重點不在派工,而在「怎麼讓它們同時改檔不互相覆蓋」。兩者可以疊著用:每個平行 session 底下,還可以各自再派自己的子代理。
18.1 一個 flag 開出隔離的平行 session
最基本的用法就一個 flag。啟動 Claude 時加上 --worktree(簡寫 -w)再給它一個名字,Claude 就會自動幫這個 session 開一塊獨立的工作目錄,而不是直接在你目前的資料夾動手。
建議執行:在一個 Git 儲存庫裡,用獨立 worktree 開一個 session
# 開一個叫 feature-x 的隔離 session
# Claude 會自動建 .claude/worktrees/feature-x/ 並切到 worktree-feature-x 分支
claude --worktree feature-x
這行做了什麼?它在 .claude/worktrees/feature-x/ 開一塊全新的工作目錄,並切到一個新分支 worktree-feature-x。這個 session 之後所有的讀檔、改檔,都發生在那塊獨立目錄裡——你原本的工作目錄一個字都不會被它碰到。你可以同時再開一個 claude --worktree fix-b、一個 claude --worktree refactor-c,三個各據一方,誰也蓋不到誰。連名字都懶得取也沒關係,claude --worktree 後面什麼都不加,Claude 會自己生一個像 bright-running-fox 這樣好記的隨機名字。官方
已經在對話裡了才想到這件事該隔離著做,不用整個重開一個終端機。直接跟 Claude 說一句「幫我開個 worktree 來處理這個」,它會自己呼叫內部的 EnterWorktree 工具,把接下來的工作切進一塊新的隔離目錄;如果你人已經在某個 worktree 裡、又想再跳去另一塊,一樣可以再叫它切換一次——原本那塊會維持原樣,不會被動到。官方
還有一招更快——直接從一個既有的 PR 分身出來:claude --worktree "#1234" 會去抓 origin 上編號 1234 那個 PR 的分支,建到 .claude/worktrees/pr-1234。想接手同事開的 PR、幫忙補幾個 commit 再推回去,這樣起手最快,不用自己先找分支名字。官方
預設情況下,新 worktree 是從遠端的主分支(origin/HEAD)長出來的,等於一塊乾淨的起點;只有這個專案根本沒設遠端、或抓取失敗時,它才會退回用你電腦上目前的 HEAD。但你常常會想反過來——「以我電腦上現在這份(還沒推上去的)進度為基礎」來開分身,例如要請一個子代理接手你手上做到一半的東西。這時候不能靠它自動退回,得自己明講:在專案的 .claude/settings.json 裡把 worktree.baseRef 設成 "head",之後每次開新 worktree 都會帶上你當下的進度(含未推送的 commit)。這個欄位只吃 "fresh" 或 "head" 兩個值,不接受任意的 git ref。官方
參考:把新 worktree 的起點固定成本機目前 HEAD(含未推送進度)
{
"worktree": {
"baseRef": "head"
}
}
另外,worktree 是獨立目錄,預設不會帶 .gitignore 掉的檔案(像 .env 這種環境設定);你可以用一個 .worktreeinclude 清單,明確指定「這些被忽略的檔案也幫我帶進每個 worktree」。
參考:用 .worktreeinclude 把 .env 帶進每個 worktree
# 專案根目錄放一個 .worktreeinclude,每行一個要帶進 worktree 的「被 gitignore 檔」
.env
.env.local
這份清單只認「同時符合清單裡的樣式、而且本身真的被 .gitignore 排除」的檔案——已經被 Git 追蹤的檔案不會被重複複製一次,不用擔心弄出兩份。要注意的是,這個機制只在你走 --worktree、子代理 worktree、或桌面版並行 session 這幾條官方路徑時才生效;18.5 會提到的非 Git 版控自訂 hook,.worktreeinclude 完全不會被處理,得自己在 hook 腳本裡動手複製。官方
18.2 收尾規則:自動清、鎖定,以及非互動模式的坑
開了這麼多獨立目錄,用完誰負責收?答案分三種情況,行為不太一樣,先搞懂才不會找不到東西、或反過來納悶「怎麼我的 worktree 憑空消失了」。官方
情況一:整段跑下來沒有任何改動
離開 session 時,Claude 會直接把這塊臨時 worktree 連同分支一起清掉,不留空殼。如果你當初有幫這個 session 取名字,它會改成先問你一句要不要保留,不是無條件默默刪掉。
情況二:有未 commit 的變更或未追蹤的新檔案
離開時會跳出提示,問你要保留還是移除;選移除的話連分支也會一併丟掉,記得先確認東西都存好、或已經 commit/push 出去再收。
情況三:非互動模式(claude -p --worktree ...)
腳本化執行沒有「離開時的互動提示」這個時機點,所以完全不會自動清。得自己記得跑 git worktree remove 收尾,不然孤兒 worktree 會一直堆在 .claude/worktrees/ 底下。
背景 session 與子代理(18.3 會講的 isolation: worktree)建立的 worktree,還多一層保護網:只要超過 cleanupPeriodDays(預設 30 天)都沒有未 commit、未追蹤、未推送的內容,就會被自動 sweep 掉。但要記住一個不對稱的地方——用 --worktree 手動開的 worktree,永遠不會被這個 sweep 清掉,這塊完全留給你自己判斷,系統不會替你做主。agent 執行期間,Claude 還會對它正在用的 worktree 跑一次 git worktree lock,避免背景清理程序跟它同時動手誤刪;想清掉一個被鎖住、或被 sweep 保留住不放的 worktree,直接加 --force 蓋過去就好:
參考:強制清掉被鎖住或保留住的 worktree
git worktree remove --force <worktree 路徑>
第一次在某個資料夾用 --worktree,得先手動跑過一次 claude
Claude Code 對每個資料夾都有一道「workspace trust(工作區信任)」確認關卡——第一次在裡面動手前,會跳出提示問你信不信任這批檔案。--worktree 需要吃到這個信任狀態,所以互動模式下,如果這個資料夾你連一次都還沒手動跑過 claude 通過信任確認,直接下 --worktree 會被擋下來、提示你先跑一次 claude。claude -p --worktree(非互動)則會跳過這道信任檢查直接執行,不會卡住。
版本較舊時,啟動失敗的訊息不太友善
如果 Claude 啟動時進不去 worktree 該在的目錄(例如自訂的 WorktreeCreate hook 印出的不是一個有效路徑,或那個目錄事後被刪掉了),較舊版本會讓整個 session 直接當掉;-p 非互動模式甚至會卡住大約 30 秒,最後才用「成功」的結束碼收尾,很容易讓你誤判成「有跑完但其實什麼也沒做」。這個行為在後續版本已經改成印出明確的錯誤訊息、用失敗的結束碼收尾,判讀清楚很多。worktree 相關的旗標名稱、預設清理天數這類細節版本演進很快,實際行為請以你目前 claude --version 對應的官方文件或 --help 為準。官方
18.3 讓子代理也各拿一塊 worktree:isolation 設定
上一節是「你手動開好幾個平行 session」。但如果是一個 Claude 自己派出一群子代理去平行工作,這群子代理同樣在同一個目錄,照樣會撞車。解法對稱:讓每個子代理也各自拿一塊臨時 worktree。
做法是在你自訂的子代理定義檔(subagent frontmatter)裡,加一行 isolation: worktree。設了之後,每個平行跑的子代理啟動時,Claude 會自動發給它一塊臨時 worktree,讓它在裡面獨立改檔;跑完沒留下變更的話,那塊 worktree 一樣會自動移除。
參考:在子代理定義裡開 worktree 隔離
# 某個自訂子代理的定義檔開頭(frontmatter)
---
name: refactor-worker
description: 平行重構某個模組
isolation: worktree # ← 關鍵這行:每個平行 instance 自動拿臨時 worktree
---
你甚至不一定要去改定義檔——你也可以直接在對話裡跟 Claude 說「請用 worktree 隔離跑你的這些子代理」,效果一樣。重點是觀念:只要有多個分身會同時寫檔,就讓它們各自有獨立工作目錄,這是貫穿整章的核心律。官方
這塊臨時 worktree 遵循的起點規則,跟 18.1 講的 --worktree 完全一樣——預設從 origin/HEAD 分出、受 worktree.baseRef 影響。它一樣不會自動裝依賴、不會自動複製被 gitignore 掉的檔案;18.5 會整理一份「worktree 不會幫你做的事」清單,派工前先看過一遍,會少踩很多次同一個坑。
18.4 不靠旗標:手動管理 worktree 的三個指令
--worktree 幫你把「開新目錄、切分支、事後清理」都包好了,但有時候你要更精準的控制——worktree 要放在哪個路徑、要接到哪個既有分支、要不要照你自己的資料夾命名慣例。這時候不靠 Claude 的 flag,直接用 Git 原生的三個指令自己管,反而更直覺。
參考:手動建立、查看、移除 worktree
# 開一個新分支的 worktree,放在專案外層的指定路徑
git worktree add ../project-feature-a -b feature-a
# 從一個既有分支開 worktree(不用 -b,因為分支已經存在)
git worktree add ../project-bugfix bugfix-123
# 進去之後才啟動 Claude
cd ../project-feature-a && claude
# 列出目前這個儲存庫所有的 worktree
git worktree list
# 用完了,移除
git worktree remove ../project-feature-a
手動開的 worktree,初始化這一步要自己補
不管是用 --worktree 還是手動 git worktree add 開出來的目錄,本質上都只是把 Git 追蹤的檔案重新 checkout 一份出來——node_modules、虛擬環境、build 產物這些「裝出來的」東西不會跟過去,因為它們本來就被 .gitignore 排除。每開一個新 worktree,第一件事永遠是照這個專案的規矩重新裝一次依賴(npm install、pnpm install、poetry install、dotnet restore 之類),Claude Code 不會幫你做這一步。忘了裝,Claude 一開工就會卡在「找不到套件」。
什麼時候該選手動、什麼時候該用 --worktree?想快速隔離一個臨時任務、懶得管路徑名字,用 --worktree 最順手;要接進某個既有的固定分支、要放在特定路徑給其他工具(例如 IDE 的多視窗)認得到,或本來就有一套自己的專案初始化腳本要跑,手動管理反而更好掌控。
18.5 worktree 不會幫你隔離的東西:常見地雷與排除法
下面整理幾個「文件沒特別強調、真的同時開好幾個分身才會撞到」的狀況,多半是社群和個別開發者實測回報的經驗。記住這一句就抓到這整節的重點:worktree 隔離的是檔案,不是執行環境。
| 地雷 | 典型症狀 | 排除法 |
|---|---|---|
| Port 衝突 | 兩個 worktree 各跑一次 npm run dev,第二個直接報 port 3000 已被佔用 |
每個 worktree 各自指定不同 PORT,或寫進該 worktree 自己的 .env.local |
| 共用資料庫撞車 | 一個分身跑 migration,另一個分身的 schema 瞬間對不上;兩邊同時灌測試資料互相覆蓋 | 依分支名稱切出各自獨立的資料庫(見本節最後的 hook 範例),或至少排開時間別同時動 DB |
| 共用設定檔合併衝突 | 多個 worktree 各自改了同一份「被 Git 追蹤」的設定檔,合回主分支時幾乎必衝突 | 常變動的設定改用環境變數(不進版控),減少多個分身都想動同一份檔案的機會 |
有兩個地雷份量比較重,值得展開講。第一個是硬碟空間:worktree 本身很省(共用同一份 .git 版本歷史),真正爆量的是每個 worktree 各自重裝一份 node_modules、各自留一份 build 產物。社群實測過一個約 2GB 大小的專案,只開兩個 worktree 就多吃掉將近 10GB 硬碟空間社群;也有人回報單一個下午光靠自動建立的 worktree,就吃掉 10GB 以上。如果你的套件管理器支援內容定址(content-addressable)的全域快取——像 pnpm 那樣套件只在硬碟上存一份、各專案用硬連結指過去——單一 worktree 的實際佔用會小非常多,被這個雷炸過的話值得認真考慮換過去。
.claude/ 底下的自訂設定,有時候不會完整帶進 worktree
曾有使用者回報(Claude Code 2.1.51、macOS):用 --worktree 開出來的目錄裡,.claude/ 資料夾只剩下 settings.local.json,自己寫的 skills/、agents/、rules/、甚至 settings.json 本身全部不見,worktree 裡的 session 因此用不到自訂子代理或規則。常見原因是這些檔案剛加進主專案、但還沒 commit——回顧前面反覆強調的規則:worktree 只會帶已經被 Git 追蹤的內容。先把 .claude/ 底下的自訂檔案 commit 掉,或用 18.1 的 .worktreeinclude 明確列出來,是目前看得到的兩條解法。這是社群回報、截稿時官方尚未回應的行為社群,遇到請先確認你當下版本是否還有這個狀況。
Windows 使用者另外注意一點:較舊版本移除 worktree 時,只把「頂層」的 NTFS junction/目錄 symlink 當成連結處理;如果 junction 巢狀藏在子目錄裡,移除 worktree 可能會連它指向的外部目錄內容一起被清掉。後續版本已經改成不論多深都當連結處理,不會誤刪外部內容——同樣建議照你目前版本的實際行為為準。官方
想知道進階解法:用 hook 自動幫每個 worktree 裝依賴、開獨立資料庫
前面那些「要自己記得做」的收尾工作,其實可以自動化。Claude Code 有一個 WorktreeCreate hook(第 8 章介紹過 hook 的基本概念,第 19 章會系統性展開),每次新 worktree 建好時自動觸發一段你寫的指令。最直接的用法是拿它自動裝依賴,不用每次手動敲:
{
"hooks": {
"WorktreeCreate": [
{
"hooks": [
{ "type": "command", "command": "bash -c 'npm install >&2'" }
]
}
]
}
}
指令習慣用 bash -c 包一層、把安裝過程的輸出導到 >&2(stderr)——這是官方範例的寫法,跟著做準沒錯,用意是不讓安裝過程的雜訊混進去。同一個 hook 也能拿來解共用資料庫撞車的問題:依分支名稱產生一個獨立的資料庫(例如 myapp_development_功能分支名),寫進該 worktree 自己的 .env.local,讓每個分身各用各的 DB;對應再寫一個 WorktreeRemove hook,在 worktree 收尾時把那個臨時資料庫 drop 掉。要注意 WorktreeRemove 只負責善後(記錄、清理),沒有「擋掉這次移除」的能力,它的結束碼不影響移除是否照跑,失敗頂多留在 debug log 裡讓你事後查。
如果你的專案不是用 Git 版控(例如 SVN、Perforce),worktree 隔離預設只認 Git,得完全靠自訂 WorktreeCreate/WorktreeRemove hook 取代預設邏輯。WorktreeCreate hook 有一條硬規定:必須把「建好的目錄路徑」印到 stdout,非 0 的結束碼視同建立失敗。官方文件給的示範大致是這樣:
# 讀 stdin 的 .name、跑 svn checkout、把目錄路徑印到 stdout 給 Claude 當工作目錄
{
"hooks": {
"WorktreeCreate": [
{
"hooks": [
{ "type": "command", "command": "bash -c 'NAME=$(jq -r .name); DIR=$HOME/.claude/worktrees/$NAME; svn checkout https://svn.example.com/repo/trunk $DIR >&2 && echo $DIR'" }
]
}
]
}
}
這條路線比較小眾——多數人的專案都是 Git,用不到。但團隊裡如果還有一角在用舊式版控系統,知道這條後路存在,至少不用因此放棄平行 session 的效率。官方
地雷踩到怕了?三條備用路
如果你的專案服務依賴多到「每個 worktree 都要整套環境重起一份」變成日常困擾,這裡再列三條社群摸索出來的替代路,給你參考——但預設還是先試 worktree,這三條是「備而不用」的選項,不是要你一開始就跳過。
第一條是圖形化總覽工具:第三方 TUI 工具 claude-squad(GitHub:smtg-ai/claude-squad,brew install claude-squad 裝完指令叫 cs)用 tmux 搭 git worktree,把多個 Claude Code(甚至 Codex、Gemini、Aider 等其他 agent)各自跑在獨立 worktree + tmux session 裡,給你一個總覽畫面看所有分身的狀態,還有背景自動接受模式跟合併前的 review 流程。想「一眼看清所有分身在幹嘛」又懶得自己刻 shell 腳本,這是現成的選擇。社群
第二條更激進:乾脆不用 worktree。trigger.dev 團隊踩了前面這些地雷踩到很煩之後,換成 GitButler 的「virtual branches(虛擬分支)」——多條分支同時套用在同一份工作目錄上,不再是「一個分支一個資料夾」,改用一個 gitbutler/workspace merge commit 代表目前所有套用中的分支。Claude 改用 GitButler 專屬的 but CLI(不是原生 git)操作,例如先 but status --json 拿到檔案與分支的 ID,再用 but commit fe -m "訊息" --changes g0,h0 把指定的檔案 commit 到指定的分支。好處是只有一份工作目錄,dev server、資料庫、測試環境都不用為每個分身重起一份;代價是要多學一套非標準的 git 工具鏈。這條路只適合服務依賴多到每個 worktree 都要整套起一份的大型專案,不是每個專案都值得為此換一套工具鏈。達人 · trigger.dev 團隊
第三條是換一整個終端機本身:cmux(GitHub:manaflow-ai/cmux,官網 cmux.com)不是疊在你原本終端機上的一層工具,它本身就是一款以 Ghostty 為底層打造的原生 macOS 終端機 App,設計目標就是讓多個 AI coding agent(Claude Code、Codex、Gemini CLI、Aider 等)同時並行——用垂直分頁組織每個分身、幫你留意「哪個分身在等你回應」的通知光環與桌面通知、內建可程式化的瀏覽器分頁,還支援 SSH 遠端 workspace 跟 session 還原。跟前面兩條路一樣是在解「多分身管理」這個問題,但性質不同——它不是包一層 tmux、也不是換一套 git 工具鏈,是連你打字的那個終端機視窗本身都換掉。要說清楚的是:危險指令攔截、prompt 編輯強化、用量顯示,這些都不是它的功能——能擋 rm/sudo 這類危險指令的是 Claude Code 自己原生的機制(deny 清單、PreToolUse hook、/permissions,第 3 章 3.4 節與第 24 章 24.3 節已經教過),換了終端機,這幾道防線不會跟著變。社群
裝起來不難,挑一種你順手的方式:
-
安裝
下載 .dmg,或用 Homebrew 一行裝完
想跟著官方的 Sparkle 自動更新走,就上 cmux.com 下載 .dmg,拖進「應用程式」資料夾;習慣用終端機管軟體,跑這兩行也一樣:
brew tap manaflow-ai/cmux brew install --cask cmux系統需求是 macOS 14.0 以上;目前不支援 Windows。
-
開工
開分頁,照平常的方式打
cc進 Claude每個分頁都是一個正常的 shell,你在
.zshrc裡設過的捷徑(例如alias cc='claude')照樣讀得到——cc從來不是內建指令,是你自己的 shell alias,照樣被讀進來而已。
用 cmux 前,這幾件事你該先知道
- 環境變數不會自動帶進來:這是一款 GUI App,不會像終端機那樣載入
.zshrc裡設的環境變數。舊版常用CLAUDE_CODE_NO_FLICKER=1這個環境變數解畫面閃爍,這裡完全沒用——要解閃爍問題,改在~/.claude/settings.json裡設"tui": "fullscreen"(Claude Code 2.1.110 以上才支援這個欄位)。 - 畫面預設會閃爍:底層是 Ghostty,跟同類終端機一樣有這個通病。上面提到的 Fullscreen 模式能解,但代價是會犧牲
Cmd+click開檔、Cmd+F搜尋這兩個功能,兩害相權,自己選。 - 不支援 AppleScript 視窗操作:如果你搭配外部編輯器(像下面提到的 CotEditor)、用
EDITOR='cot --wait'這種寫法,存檔後編輯器會想用 AppleScript 把呼叫它的視窗拉回前景——這一步在這裡會失敗、回傳非 0 的結束碼,Claude Code 因此會誤判成「編輯失敗」而不採用你剛編輯好的內容。解法是包一層 wrapper script,用2>/dev/null吃掉錯誤訊息、強制exit 0。 - 目前不支援 Windows:這是 macOS 專用 App,Windows 使用者這條路走不通。
裝好之後,如果想讓長 prompt 的編輯體驗更順手,可以參考侯智薰(雷蒙)在他的 Claude Code 學習資源站整理的 Starter Kit:外部編輯器那份設定包教你裝 CotEditor(Mac App Store 免費)、設好 EDITOR 環境變數,搭配 Ctrl+G 呼出編輯器寫長 prompt、Cmd+S 存檔就自動送回輸入框——這份設定包本身就點名了 cmux 的 AppleScript 限制,也附了跟上面同一種思路的 wrapper script 解法,可以直接對照著設定。同一個資源站另外兩份設定包,看到再挑就好:「安全三重奏」那份的第三層是權限模式,你在第 7 章 7.1 節已經學過 Claude Code 原生的三種權限模式與 Shift+Tab 切換,這層可以直接略過;「狀態列」那份的安裝方式是請 AI 直接改寫並覆蓋 settings.json 的 statusLine 欄位——如果你已經照第 8 章 8.7 節設過原生的 statusLine,套用前務必先檢查自己現有的設定內容,這份不會自動合併,會直接蓋掉你原本設好的東西。達人 · 侯智薰(雷蒙)
選配技巧:幫常用資料夾設個開啟捷徑
每次都要手動切換、找資料夾才能開進 cmux 覺得麻煩,可以到「系統設定 → 鍵盤 → 鍵盤快速鍵 → 服務 → 檔案與資料夾」,幫特定資料夾建一個開啟服務並綁個快捷鍵,之後在 Finder 選好資料夾按一下就能直接開進去。這是個人化的小撇步,順手就用,不用也完全不影響前面教的用法。
18.6 Writer/Reviewer 配對:審查者用全新 context 偏見更少
平行不只是「同時做更多事」,還能玩出一個很聰明的搭配:一個 session 負責寫、另一個全新的 session 負責審。為什麼要分兩個?因為寫的那個 Claude 滿腦子都是「我剛剛為什麼這樣寫」的脈絡,它對自己的程式碼有感情、有盲點;而一個全新 context、沒參與過撰寫的 Claude 來審查,沒有先入為主的包袱,更容易抓到問題。這跟人類團隊「作者自己看不出自己的錯字,換一個人一眼就看到」是同個道理。
Boris Cherny(Claude Code 核心開發者)的個人做法是:本地同時跑大約五個 checkout/worktree,分別開在編號又上了色的終端分頁裡(他用 Ghostty 終端機),靠 shell alias 快速跳轉——例如 za 跳第一個、zb 跳第二個、zc 跳第三個。他還會固定留一個專門的 analysis worktree,不拿來改 code,純粹用來跑 log 查詢、跑資料庫查詢這種「唯讀調查」工作。達人 · Boris Cherny
參考:給平行 session 設好記又好跳的 shell alias(範例)
# 放進你的 ~/.zshrc 或 ~/.bashrc,之後打 za / zb / zc 就能各跳一個 session 目錄
# 路徑與名稱請依你自己的專案調整,這只是示意
alias za='cd ~/work/proj-a && claude --worktree task-a'
alias zb='cd ~/work/proj-a && claude --worktree task-b'
alias zc='cd ~/work/proj-a && claude --worktree analysis'
上色分頁是「認得出哪個是哪個」的小撇步
同時開五個分身,最大的麻煩其實是「我現在在看哪一個?」。給每個終端分頁不同顏色、加上編號,掃一眼就分辨得出來,比硬記順序可靠太多。這是達人的個人偏好,不是非得這樣不可——但同時跑越多 session,這種視覺辨識就越值得做。
alias 不夠用了?升級成 shell 函式
簡單的 alias 只能開固定的 worktree。想要「不用先 cd 過去,就能對指定 worktree 下任意指令」,改寫成一個 shell 函式會更好用。incident.io 團隊的做法是包一個 w 函式,接受「專案、分支、要跑的指令」三個參數,例如 w myproject feat git status、w myproject feat claude,不用手動切目錄就能對任一個 worktree 下指令達人 · incident.io 團隊。另一種做法是像 dangerlanc 那樣寫一個 gw 函式,解析 git worktree list --porcelain 的輸出配 fzf 做互動式選單——打 gw 跳出清單讓你挑,或直接 gw feature-auth 跳到指定分支的 worktree達人 · dangerlanc。兩種都比死記一長串 cd 路徑實際,值得在分身開到四五個以上時換過去。
這種「寫一個、審一個」的配對還有變體:一個 session 專門寫測試、另一個 session 專門寫實作去通過那些測試。兩邊各據一塊 worktree,寫測試的那邊不會被實作的細節牽著走,反而更能站在「使用者該怎麼用」的角度設計測試。達人 · Boris Cherny
18.7 /batch:一次 fan-out 到數十、數百個 worktree 分身
前面是手動開三五個。再往上一個量級——當你要做的是「把整個 src/ 從一個框架遷移到另一個框架」這種大量重複、彼此獨立的工作時,可以用 /batch 一口氣 fan-out 到數十、甚至數百個子代理,每個各據一塊 worktree、各改一塊、各自開自己的 PR。
它的流程是:你下 /batch,Claude 會先訪談你——問清楚這次遷移的規則、範圍、要注意什麼,把需求對齊;對齊之後,它才把工作 fan 出去給一大群子代理平行處理。每個子代理在自己的 worktree 裡做完、自己跑測試、開自己的 PR,你最後逐一審 PR 就好。典型例子就是「把 src/ 底下所有元件從 Solid 遷移到 React」這種一檔一檔做、規則一致的大工程。
要讓這套跑得安全,關鍵還是那行 isolation: worktree(見 18.3)——agent 的 frontmatter 加上它,幾百個分身才不會在同一目錄互砸。官方達人 · Boris Cherny
「/batch 會自動套 worktree 隔離」這點請臨用前再確認
「/batch 會自動幫每個分身套上 worktree 隔離」這個說法,是從官方零碎資訊推論出來的、不是白紙黑字的明文保證。真要 fan-out 到幾十幾百個分身前,請先確認你的 agent 定義確實有設 isolation: worktree,別賭它自動幫你開——萬一沒開,幾百個分身擠同一目錄,後果不堪設想。
18.8 分身開多了找不回來?跨 worktree 接續對話
平行開到五個、十個之後,一定會遇到這個狀況:隔天回來,你記得「某個 worktree 裡有個 session 做到一半」,但想不起來是哪一個、叫什麼名字。附錄 A 提過 claude --resume 能接續舊對話,這裡要補的是它在跨 worktree 時的行為。
如果你記得 session 的名字,claude --resume <名字> 精準符合的話會直接接上——即使那個 session 其實活在另一塊 worktree 裡,不用先手動切過去;名字只記得個大概,模糊符合會打開一個挑選器,還幫你把搜尋字都先填好。挑選器裡預設只列「目前這個 worktree」的對話,按 Ctrl+W 能把範圍撐大到「整個儲存庫底下所有 worktree」,再按 Ctrl+A 撐到「這台機器上所有專案」——記不清是哪個專案的,一路按到底總找得到。官方
兩個終端機同時 resume 同一個 session,訊息會攪在一起
找到想接續的對話後,如果在另一個終端機分頁也對同一個 session 打了 --resume(沒加 --fork-session),兩邊各自輸入的內容會交錯寫進同一份逐字稿,很快就會把上下文搞得語無倫次。真的想從某個既有對話「分岔」出兩條各自獨立的路,用 --continue --fork-session,或直接在對話裡打 /branch 分岔後的名字,各自複製一份出來再平行,不要對同一個 session 開兩個視窗硬用。
另外兩個常用的接續指令一併記住:claude --continue 接續目前所在目錄最近一次的對話(不用打名字);claude --from-pr <PR 編號> 直接接回連結到某個 PR 的 session——18.7 提到 /batch 開出來的每個分身都會各開一個 PR,事後想回頭看某個分身當初怎麼做的,這條最快。
參考:腳本化查詢某個 session 目前跑到哪(適合寫進自動化流程)
# 不進互動介面,直接問某個 session「你剛剛改了什麼」,取出純文字結果
claude -p --resume <session-id> --output-format json "summarize what we changed" | jq -r '.result'
18.9 誇張案例:16 個 Claude 合寫 10 萬行 C 編譯器
把平行編排推到極致是什麼樣子?研究者 Nicholas Carlini 做過一個展示:用 16 個 Opus 同時跑,合力寫出一個約十萬行的 C 語言編譯器。這不是日常該模仿的用法,但從它萃取的幾個原則,正是「大規模平行」的精髓。
它的架構是這樣:16 個 Claude 跑在各自的 Docker 容器裡,共享同一個 Git 儲存庫。它們怎麼分工不撞車?用一個 current_tasks/ 目錄裡的 lock 檔(鎖檔)來搶工作——一個分身要做某項任務前,先去搶那個任務的鎖,搶到才做,沒搶到就換下一個。改完之後走「先拉取、合併、再推送」(sequential pull-merge-push)的順序回寫,遇到 merge 衝突,Claude 自己解。達人 · Nicholas Carlini
想知道細節:這個案例萃取出的三個原則(研究展示,非日常 pattern)
這是一次工程/研究展示,不是給一般人照抄的日常做法——但裡頭有三個原則很值得記住。原則一,用鎖檔做分散協調:不需要一個中央大腦指揮,每個分身自己去 current_tasks/ 搶鎖,搶到才做,這樣十六個分身不需要彼此溝通就不會做到同一件事。原則二,回寫走序列化的拉取-合併-推送:大家共用一個儲存庫,推送前先拉最新、合併、再推,避免覆蓋彼此。原則三,merge 衝突讓 Claude 自己解:衝突在大規模平行下必然發生,與其每次喊人來處理,不如讓分身自主處理掉。工作還分三段演進:早期各寫獨立的 failing test、中期分頭做不同的開源子專案、晚期拿 GCC 當「標準答案」隨機抽 kernel 檔來比對;另外配了幾個專家 agent 專門做去重、效能、文件、設計批判。
整個案例最核心的一句話是 Carlini 自己說的:「你是在為 Claude 寫一套測試 harness(測試骨架),不是為你自己寫。」——意思是,當你指揮這麼多分身時,你的工作重心已經不是「自己寫 code」,而是「設計一套能讓 Claude 自我驗證、自我糾錯的框架」。這正好呼應了第 15 章的驗證心法:規模越大,越要靠機械化的驗證閘門,而不是靠你一個一個盯。
這是研究展示,不是日常範本
十六個分身寫十萬行編譯器是一次性的工程/研究展示,不是一般使用者的標準操作流程。你該帶走的是上面三個原則(鎖檔協調、序列化回寫、衝突自解),而不是真的去開十六個容器。日常你頂多同時跑幾個,量級差很遠。
18.10 Boris 的日常:10~15 個分身一起跑長什麼樣
講完極端案例,回到比較接地氣的「達人日常」。據轉述,Boris 平常會同時跑 10 到 15 個平行 Claude session,每個各據一塊 Git worktree 避免 context 互撞。注意這個數字(10~15)跟 18.6 提到的「約 5 個」略有出入——這是不同時間、不同轉述來源的差異,你不用糾結確切數字,重點是「同時跑很多個」是常態,不是炫技。社群轉述
數字看看就好,先摸自己機器的上限
10~15 個是達人的設定,不是人人都該追的目標。有實測回報:一台 M1 Mac 搭 Claude Max 5x 訂閱,同時開 4 個平行 session 還算舒服;再往上加,多個 session 一起跑 build、跑測試很容易把機器資源榨乾,反而互相拖慢。多篇來源給的實務上限大概落在 2 到 5 個——超過這個量級,「切換與追蹤各分身進度」耗的心力,往往就蓋過平行帶來的時間收益了。社群
他的日常節奏大致是這樣,可以當你自己的範本:
-
規劃
每個 session 先 Plan,再 Execute,最後 Verify
每塊 worktree 裡的 session 都走「先規劃 → 再執行 → 最後驗證」的三段式。驗證不是看一眼就算,而是實際跑測試、跑 linter、跑 build,拿結果說話(這正是第 15 章驗證心法的日常實踐)。
-
顧 context
context 大約用到一半時就 /compact
同時跑這麼多個,每個的對話脈絡都會慢慢膨脹。他的習慣是 context 大約填到 50% 左右就主動下
/compact壓縮,把脈絡蒸餾成精華再繼續,避免它越跑越糊。 -
累積教訓
把每次學到的教訓寫進 tasks/lessons.md
遇到的坑、學到的規則,隨手寫進一個像
tasks/lessons.md的檔案。下次同樣的錯就不用再犯一遍——這跟第 14 章「把錯誤寫成規則」的 Error-to-CLAUDE.md 精神一脈相承。累積下來你會得到一個越用越聰明的工作流:分身各做各的、彼此不打架,犯過的錯被寫成規則不再重演,你從「自己動手寫」升級成「指揮一支會自我驗證的隊伍」。
-
合併收斂
合併回主分支前,先通讀一遍 diff
CI 全綠不代表可以直接合。合併前用
git diff main..agent/分支名稱通讀一次改了什麼,抓的是「CI 測不出來但人一看就懂」的問題——分身有沒有動到範圍外的檔案(scope creep)。有依賴關係的改動(例如先改 schema、再改對應的程式邏輯)要照相依順序一條一條合,不要一次全部合下去;多條分身要合併時,也建議一次合一條,方便出狀況時抓是哪一條的責任。累積下來你會得到一個越用越聰明的工作流:分身各做各的、彼此不打架,犯過的錯被寫成規則不再重演,合併時也不會因為貪快而讓一條壞分支污染主線。你從「自己動手寫」升級成「指揮一支會自我驗證、收尾也謹慎的隊伍」。
Claude 偶爾會把 git 操作的順序搞錯,直接明講順序更快
指揮這麼多分身收尾時,偶爾會遇到 Claude 想在還沒 push 之前就搶著開 PR 這種順序顛倒的狀況。與其讓它自己試錯,直接把順序講清楚——「先 push,再開 PR」——通常比等它自己摸索快得多。達人
這節是社群轉述,當參考不當教條
這套日常工作流是經由社群(Matthias Herbert 轉述)整理的達人實踐,不是 Anthropic 的官方規範。數字(10~15 個、50% compact)會因人、因專案而異,請當成「達人怎麼做」的參考起點,依你自己的機器與專案調整,別當成非遵守不可的硬規則。
18.11 小結
這一章把「同時開很多個 Claude」從一團亂變成一套方法。核心只有一句話:只要有多個分身會同時改檔,就給它們各自獨立的工作目錄。你學到的官方工具有——啟動時加 --worktree(-w)給單一 session 一塊隔離目錄(也能用 #PR 編號 直接接手既有 PR、或在對話裡臨時呼叫 EnterWorktree 切換)、用 .worktreeinclude 把 .env 帶進去、在子代理定義裡加 isolation: worktree 讓平行子代理各據一方、用 /batch 一次 fan-out 到幾十幾百個分身各開自己的 PR、還有 --resume 系列指令跨 worktree 找回舊對話。你也知道了它的邊界在哪——收尾規則分三種情況、非互動模式不會自動清;worktree 只隔離檔案不隔離執行環境,node_modules、port、資料庫都得自己顧,需要時可以用 WorktreeCreate hook 自動化這些收尾。
再往上,是 Writer/Reviewer 配對(讓全新 context 的審查者抓盲點,配合 shell 函式管理一堆分身)、以及達人同時跑五到十幾個 session 的日常節奏(Plan→Execute→Verify、半滿就 /compact、教訓寫進 lessons.md、合併前先通讀 diff)。真的被執行環境隔離的地雷卡住很多次,還有 claude-squad、GitButler 這類第三方路線可以參考。
要記住的分寸是:--worktree 和 isolation: worktree 是官方機制,可以放心用;但「同時跑幾個」「什麼時候 compact」這些數字是達人個人偏好與社群轉述,會因人而異;而 16 個分身寫編譯器那種規模是研究展示,你帶走它的三個原則(鎖檔協調、序列化回寫、衝突自解)就好,不必真的照做。下一章我們講 Hooks,把這些「軟性守則」變成程式自動執行的「鐵閘門」——18.5 已經先讓你摸過 WorktreeCreate 的味道了。
18.12 動手試試
找一個你本機的 Git 專案(最好是可以隨便玩、壞了不心疼的),照下面三步感受一下平行 worktree。
-
動手做
用 worktree 開兩個獨立 session
開兩個終端分頁,一個跑
claude --worktree try-a、另一個跑claude --worktree try-b。各自叫它改不同的檔案,然後去看.claude/worktrees/底下,確認真的開出了try-a和try-b兩塊獨立目錄。# 分頁一 claude --worktree try-a # 分頁二 claude --worktree try-b -
動手做
驗證它們互不干擾
在
try-a那個 session 改某個檔、存檔;切到try-b看同一個檔——它應該看不到 A 剛剛的改動(因為它們在不同分支、不同目錄)。這就是隔離生效的證據。預期會看到A 改的東西只存在 A 的 worktree/分支裡,B 的工作目錄完全不受影響。你也可以用
git worktree list看到 Git 確實列出了多塊工作樹。 -
動手做
試一次 Writer/Reviewer 配對
在
try-a叫 Claude 寫一個小功能;開一個全新的claude --worktree review,叫它去審try-a寫的那段 code、挑毛病。感受一下「全新 context 的審查者」是不是真的更容易抓到原作者沒注意到的問題。
玩完記得收乾淨
練習用的 worktree 不需要了,可以用 git worktree remove <路徑> 清掉,或讓沒有改動的那些自動被回收;被鎖住清不掉就加 --force(18.2)。剛上手別一次開太多,先從兩三個熟悉手感,再慢慢加——趁這幾個練習用的 worktree 還在,也可以順手看一眼 .claude/worktrees/ 底下各自佔了多少空間,對 18.5 講的硬碟地雷會更有感覺。