第 5 章 多 session 多工
一句話:一件事開一個 session、一張自己的桌子,做完把成果搬回主桌。
一個 Claude Code session 就是一段獨立的對話加一個工作目錄。把兩件不相干的事塞進同一個 session,會發生兩件壞事:
- 互相污染:前一件事的檔案、討論、決定全都留在對話裡(第 2 章講過的 context 成本),第二件事的品質跟著下滑。
- 互相排隊:第二件事要等第一件做完才能開始。
多 session 多工就是「一件事一個 session」,讓它們同時進行。難點不在開很多視窗,而在不要互相踩檔。
claude --worktree 解決踩檔:它用 git worktree 幫每個 session 開一份獨立的目錄影本與分支,各做各的,最後由你在主 checkout(你平常工作的那份目錄)把成果 merge 回來——這一章就在練這件事。走 Orca 路線的話,同一件事由它的 worktree 面板代勞:每個任務天生就是一個 worktree,本章正是 Orca 整個產品圍繞的工作模式。
原理:為什麼同一個目錄會互相蓋檔
Section titled “原理:為什麼同一個目錄會互相蓋檔”蓋檔不是 Claude 的 bug,是「兩個人看著同一份檔案」的必然結果。上圖的時間線:A 先寫入了加好 --json 的版本;但 B 手上拿的還是更早讀到的舊版,等 B 寫入時,就把 A 的成果整段蓋掉——B 不知道 A 改過,git 也只看到「檔案被改了」,分不出是誰的手筆。
worktree 的解法是讓兩個人根本不看同一份檔案。開兩個 worktree 之後,目錄長這樣:
claude-code-practice/ ← 主 checkout(main 分支)├── src/todo.py└── .claude/worktrees/ ├── a/ ← session A 的影本(worktree-a 分支) │ └── src/todo.py └── b/ ← session B 的影本(worktree-b 分支) └── src/todo.py三份 todo.py 各自獨立,A、B 怎麼寫都不會碰到彼此;每份影本各在自己的分支上 commit,最後由你回主 checkout 用 merge 把兩條分支的成果有紀錄地合起來——衝突了 git 會告訴你,而不是默默消失。(上圖的目錄是 CLI 路線的樣子;Orca 把 worktree 放在它自己管理的位置、分支名是任務名——目錄位置不同,隔離的原理完全一樣。)
情境 A:兩件互不相干的任務
Section titled “情境 A:兩件互不相干的任務”要加一個 CLI 選項、同時要補 README 的使用範例。兩件事碰的檔案完全不重疊,一個 session 做完再做另一個純粹是在排隊。開兩個 worktree session,各自派一件,時間直接砍半。
情境 B:一邊跑長任務、一邊改別的
Section titled “情境 B:一邊跑長任務、一邊改別的”一個 session 正在跑一個要十幾分鐘的重構或測試修復,你不想在旁邊乾等。開第二個 worktree session 處理另一件小事,長任務那邊不會被你的新提示詞打斷,也不會看到你正在改的檔。
情境 C:一個 session 看 log、一個改 code
Section titled “情境 C:一個 session 看 log、一個改 code”排查問題時,一個 session 專門讀 log、整理線索、給你結論;另一個 session 拿著結論改 code。兩邊的 context 各自乾淨:讀 log 的那個不會被程式碼的討論淹沒,改 code 的那個也不用背著幾萬 token 的 log。
情境 D:一個寫、一個審(Writer/Reviewer)
Section titled “情境 D:一個寫、一個審(Writer/Reviewer)”session A 實作一個功能;開 session B(乾淨的 context)請它審 A 的產出——B 沒看過 A 的實作過程,不會替那些決定護短,審起來更像另一位工程師。把 B 的回饋貼回 A 修。測試也能這樣玩:一個 session 寫測試、另一個 session 寫實作去通過它。這是第 2 章「對抗式審查」的 session 版,隔離更徹底。
反例:同一個 checkout 開兩個 session 改同一批檔
Section titled “反例:同一個 checkout 開兩個 session 改同一批檔”在同一個目錄開兩個 claude,各自要求改 src/todo.py。兩個 session 看到的是同一份檔案,A 剛寫進去的內容 B 下一秒就覆蓋掉,git status 也分不出誰改了什麼。這不是多工,是互相破壞(見「原理」的時間線)。真的要動同一批檔,就排隊,或先拆成不重疊的工作。
開一個 worktree session
Section titled “開一個 worktree session”claude --worktree <name>Claude Code 會在 repo 根目錄下建 .claude/worktrees/<name>/(一份獨立的工作目錄),並開一條新分支 worktree-<name>,然後在那個目錄裡啟動 session。-w 是同一件事的縮寫。
同名再開一次,會直接進既有的 worktree(自己先用 git worktree add .claude/worktrees/<name> -b worktree-<name> <起點> 開好的也算)。它預設從 origin/main(GitHub 上那份 main 在你電腦裡的複本)長出來,所以每個 worktree 的起點都是乾淨的——反過來說,只在本機 commit、還沒 push 的東西不會出現在新 worktree 裡。期末作業會碰到這件事,到時用 settings.json 的 worktree.baseRef 讓它改從本機 HEAD(=你目前所在的那個 commit,也就是本機 main 最新的一個)長。
Orca 是 worktree 原生的:按 repo 名旁的 +、輸入任務名,就是「開一個 worktree + 一個 agent」。它用 git worktree 建一份獨立目錄與一條分支(分支名預設就是你取的任務名),agent 下拉選 Claude Code 後,session 直接在那個目錄裡啟動。
把 worktree 的分頁拖到畫面右緣或下緣可以分割視窗——CLI 路線要開兩個終端機視窗的事,在 Orca 裡是同一個視窗並排的兩個 pane,每個 agent 的狀態點還會告訴你它是在等你(橘:權限或輸入)還是做完了(綠);執行中是轉圈。
❯ 只改 src/todo.py 與 tests/test_todo.py:list 加 --json… ⏺ Edit(src/todo.py) ⏺ Bash(python3 -m unittest) 已 commit:feat: list 加 --json 輸出
❯ 只改 README.md 加三個使用範例… ⏺ Edit(README.md) 等你核准:Bash(git commit …)
本章練習在 Orca 裡的樣子:側欄兩個 worktree,主畫面分割成兩個 pane 各跑一個 Claude Code。綠=完成;橘=在等你——像這裡的 b 在等 commit 的權限核准,別傻等,去點它。UI 文字以你裝到的版本為準。
一個 session 一件事
Section titled “一個 session 一件事”給每個 session 的提示詞要自足:做什麼、只准碰哪些檔、做完要 commit 還是不要。session 之間看不到彼此的對話,所以「不要動 README」這種邊界一定要寫進提示詞,不能靠它自己猜。
收斂:摘要+回主 checkout merge
Section titled “收斂:摘要+回主 checkout merge”每個 session 收尾時請它用一句話摘要做了什麼、commit 了哪些檔。然後你回主 checkout(不是任何一個 worktree)做 merge:
git merge --no-ff --no-edit worktree-agit merge --no-ff --no-edit worktree-b--no-ff 讓每個 session 的成果在 git log --graph 上各自成一個 merge 節點,事後看得出來哪批改動來自誰(ff=fast-forward:main 沒有新 commit 時,git 預設直接把指標挪到分支尾端、不留合併紀錄)。--no-edit=用 git 自動產生的合併訊息——沒加的話 git 會開編輯器(多半是 vim)要你確認訊息,不熟 vim 的人會卡在那個畫面。
worktree 的收與留
Section titled “worktree 的收與留”在 worktree session 打 /exit,如果裡面有還沒 merge 出去的東西(未 commit 的改動、或新的 commit),Claude Code 會問要 keep 還是 remove:
- keep:保留目錄與分支,之後
claude --worktree <同名>可以回來繼續。 - remove:刪掉目錄與分支,裡面沒 merge 出去的改動一起消失。
規則很簡單:已經 merge 回主 checkout 的選 remove;還沒的選 keep。
worktree 是 Orca 開的,所以 /exit 只是結束 Claude Code session,不會出現 keep/remove 的提問——目錄與分支都還在,之後隨時可以在同一個 worktree 再開 agent 繼續。
生命週期由你在側欄管理:右鍵刪除 worktree 會連目錄與分支一起刪(有確認對話),沒 merge 出去的改動也跟著消失。規則跟 CLI 一樣:已經 merge 回主 checkout 的可以刪;還沒的留著。
a,沒 merge 出去的改動一起消失。側欄右鍵 worktree → Delete=CLI 路線 /exit 選 remove 的對應動作:連目錄與分支一起刪,刪之前先確認 merge 回主 checkout 了沒。
實務案例:長流程與小修並行
Section titled “實務案例:長流程與小修並行”一個團隊的後端開發流程被寫成一條五站的 workflow(第 3 章實務案例那條:ROUTE → SPEC → BUILD → VERIFY → DONE),SPEC 站硬停等人確認才往下走。這種長流程一跑就是幾十分鐘,工程師的做法是:主 checkout 留給自己看 diff 與回答 SPEC 站的問題,另外開一個 --worktree session 處理不相干的小修——長流程不受打擾,小修也不用等。
進階選做:無頭模式的批次 fan-out
Section titled “進階選做:無頭模式的批次 fan-out”平行的極端形態是不開互動介面:claude -p "提示詞" 直接跑完就退出。大批的機械式改動(幾百個檔案的遷移、逐檔加型別)可以用迴圈發出去:
for f in $(cat files.txt); do claude -p "把 $f 從 Python 2 遷移到 Python 3,完成回 OK、失敗回 FAIL" \ --allowedTools "Edit,Bash(git commit *)"done--allowedTools 限住它能用的工具——無人看管時這很重要。訣竅是先拿兩三個檔試跑、照失敗情況改提示詞,再跑全部。細節見官方 headless 文件。
練習兩個 worktree 分工,第三個終端機收斂
-
起點:
第一次做就 clone;已經 clone 過、或要重做這一章,用第二段把前一次留下的 worktree、分支與 merge 結果清掉。已經在 repo 目錄裡的人不要再貼 clone 這段。
Terminal window git clone https://github.com/AngusLu0731/claude-code-practice.gitcd claude-code-practice已 clone/重跑(在 repo 根目錄執行;只動
a、b這兩個 worktree 與同名分支,不碰你另外開的 worktree;可以重複跑):Terminal window for n in a b; dogit worktree remove --force ".claude/worktrees/$n" 2>/dev/nullgit branch -D "worktree-$n" 2>/dev/nulldonegit merge --abort 2>/dev/nullgit checkout -f main && git reset --hard origin/maingit clean -fd && git worktree prune白話:這段=把 repo 恢復成剛 clone 完的乾淨狀態。它會丟掉未 commit 的改動與未追蹤檔(含你自己貼進
.claude/的檔案),但不會動被 gitignore 的.todo.json(只影響list顯示的項目,想清就rm -f .todo.json)與.claude/settings.local.json(存的是你核准過的權限,留著沒關係)。origin/main是 GitHub 上那份 main 在你電腦裡的複本,所以reset --hard origin/main=回到跟 GitHub 一模一樣。最後的git worktree prune是第 5 章才用得到的清理,現在跑了沒作用也無害。repo 已在首頁「共用步驟」用 Add Repo 加進 Orca。要重做這一章:先在側欄刪掉上次的
a、b兩個 worktree(會連分支一起刪),再開一個系統終端機到主 checkout(你 clone 的那個目錄)把 merge 結果清掉:Terminal window git merge --abort 2>/dev/nullgit checkout -f main && git reset --hard origin/maingit clean -fd && git worktree prune本章「收斂」與「清理」這幾步要在主 checkout 做,最單純的做法就是旁邊開著這個系統終端機備用。
-
信任資料夾:
第一次在這個目錄開
claude,接受信任對話後/exit。已經做過就跳過。--worktree要求主 checkout 先接受過信任;接受這一次,進 worktree 不會再問。Terminal window claude這一步不用做——worktree 第一次啟動 agent 時才會問信任,到步驟 3 再選 Yes 就好(收斂用的系統終端機只跑 git,不會碰到信任對話)。
-
session A:開 worktree
a。本章總共會用到三個終端機視窗(A、B 各跑一個claude,C 做收斂),都cd到 repo 根目錄,可以先開好。開一個終端機,在 repo 根目錄:
Terminal window claude --worktree a按 repo 名旁的 +,任務名取
a,起點用預設的 main,agent 選 Claude Code——它會自動啟動,第一次會問信任,選 Yes(Orca 建的分支名預設就是a)。開好後整段貼這個提示詞:
只改 src/todo.py 與 tests/test_todo.py:list 加 --json 輸出(印出 JSON 陣列,每筆含 text 與 done)並補測試,不要動 README,做完只 commit 不要 push -
session B:再開 worktree
b。再開一個終端機,
cd到同一個 repo:Terminal window claude --worktree b再按一次 +,任務名取
b,agent 一樣選 Claude Code。把b的分頁拖到畫面右緣,跟a並排——兩個 session 同時在眼前跑。開好後整段貼這個提示詞:
只改 README.md 加三個使用範例,不要動 src/ 與 tests/,做完只 commit 不要 push -
收斂(主 checkout):等 A、B 都回報「已 commit」再動手。A、B 在
git commit前可能停在「要不要允許」,兩個視窗都看一眼,別乾等。開第三個終端機,在 repo 根目錄(不是
.claude/worktrees/底下):Terminal window git merge --no-ff --no-edit worktree-a && git merge --no-ff --no-edit worktree-b && python3 -m unittest -v&&=前一個成功才跑下一個:第一個 merge 衝突時後面不會跑,直接看故障排除「merge 衝突」。用步驟 1 開好的系統終端機,在主 checkout 執行——Orca 建的分支名預設就是任務名
a、b(不確定就先git branch看一眼):Terminal window git merge --no-ff --no-edit a && git merge --no-ff --no-edit b && python3 -m unittest -vRepos▾ claude-code-practicea · Claude Codeb · Claude Codea、b 都綠了=已 commit❯ cd ~/claude-code-practice ❯ git merge --no-ff --no-edit a && git merge --no-ff --no-edit b Merge made by the 'ort' strategy. ❯ python3 -m unittest -v OK
示意圖 全章唯一離開 Orca 的一步:Orca 視窗留著(a、b 都綠了=已 commit),merge 在旁邊的系統終端機、你 clone 的主 checkout 目錄裡做。
-
收掉兩個 worktree:
回終端機 A、B 各打
/exit。它會問 keep/remove,選 remove——成果已經 merge 進main,刪掉是安全的。沒出現提問的話,自己收:git worktree remove .claude/worktrees/a && git branch -d worktree-a(b同理)。在 A、B 的終端機各打
/exit結束 session(不會問 keep/remove),然後在側欄刪掉a、b兩個 worktree——會連目錄與分支一起刪,成果已經 merge 進main,刪掉是安全的。 -
在主 checkout 確認乾淨:
Terminal window git worktree prune && git worktree list && git branch選 remove 時 Claude Code 已經連分支一起刪了,不用再
git branch -d。如果剛才選的是 keep,目錄與分支都還在,要自己收:git worktree remove .claude/worktrees/a && git branch -d worktree-a(b同理)。側欄刪除已經連目錄與分支一起收掉了,這段只是最後確認:
git worktree list應只剩主 checkout 一行,git branch沒有a、b。
❯ git merge --no-ff --no-edit worktree-a && git merge --no-ff --no-edit worktree-b && python3 -m unittest -v Merge made by the 'ort' strategy. …… Ran 32 tests in 3.412s OK (skipped=2) ❯ git log --oneline --graph * f3a2c19 Merge branch 'worktree-b' |\ | * 9d1e042 docs: README 加三個使用範例 * | 8c47b31 Merge branch 'worktree-a' ……
兩個 merge 節點+32 個測試 OK=這一章的完成證明。hash 與測試秒數每次不同。
- 步驟 5 的 merge 沒有衝突;
python3 -m unittest -v最後幾行通常是Ran 32 tests(或更多——main本來有 31 個,A 每補一個測試就加一)與OK (skipped=2)。那兩個跳過的是跟教材站原始碼比對用的測試:你只 clone 了練習 repo、沒有站台原始碼,跳過是正常結果,不是錯誤(機器沒裝 node 的話會再多跳兩個,skipped=4也正常)。 git log --oneline --graph最上面有兩個 merge 節點(CLI 路線是Merge branch 'worktree-a'、Merge branch 'worktree-b';Orca 路線分支名預設是任務名,會是Merge branch 'a'、Merge branch 'b'——結構相同,只有名字不同)。- 先
python3 src/todo.py add 測試再python3 src/todo.py list --json,印出含text與done的 JSON 陣列(空清單印什麼依 A 的實作,不一定是[])。 - 步驟 7 之後
git worktree list只剩主 checkout 一行,git branch沒有worktree-a、worktree-b(Orca 路線:沒有a、b)。
- merge 時畫面突然變成一堆
#、打字沒反應:git 開了 vim 要你確認合併訊息(指令少了--no-edit)。打:wq再 Enter 就好。 - merge 衝突:
git merge --abort,回那個 session 說「只改指定檔案,重做一次」,它多半是動到了不該動的檔。 - remove 顯示 locked:
git worktree unlock .claude/worktrees/<name>再 remove 一次。 - B 動了 src/:提示詞邊界沒寫清楚,這是本章要你學到的事——把「不要動 src/ 與 tests/」寫進去再來一次。
list --json印出用法說明、不是 JSON:A 加了函式,但沒把--json接進main()的分派(原本是command == "list" and not rest)。回 session A 說「list --json現在會印用法,請把旗標接進 main 的分派並補測試,做完只 commit」,主 checkout 再git merge --no-ff --no-edit worktree-a一次。- A 或 B 的 session 中途關掉、還沒 commit:再打一次
claude --worktree a(或b)會直接回到同一個 worktree,跟它說「繼續,做完只 commit 不要 push」。 - merge 做到一半失敗:
git merge --abort回到 merge 前的狀態;兩個 worktree 與分支都還在,修好再做一次步驟 5。 - 想整章重做:步驟 1 的「已 clone/重跑」那一段就是為此準備的,它只清
a、b與main上的練習結果。 - Orca:不確定收斂指令該在哪裡跑:收斂(步驟 5)與清理(步驟 1、7)都在主 checkout 做,最單純的做法是開一個系統終端機到你 clone 的目錄執行。
- Orca:merge 說找不到分支
a:Orca 建的分支名以它實際取的為準,先在主 checkoutgit branch看一眼,用看到的名字 merge。
自檢(勾選會存在你的瀏覽器)0/4
以 Claude Code 2.1.246(2026-08-26)為準