第 5 章 多 session 多工
一句話:一件事開一個 session、一張自己的桌子,做完把成果搬回主桌。
一個 Claude Code session 就是一段獨立的對話加一個工作目錄。把兩件不相干的事塞進同一個 session,會發生兩件壞事:
- 互相污染:前一件事的檔案、討論、決定全都留在對話裡(第 2 章講過的 context 成本),第二件事的品質跟著下滑。
- 互相排隊:第二件事要等第一件做完才能開始。
多 session 多工就是「一件事一個 session」,讓它們同時進行。難點不在開很多視窗,而在不要互相踩檔。
claude --worktree 解決踩檔:它用 git worktree 幫每個 session 開一份獨立的目錄影本與分支,各做各的,最後由你在主 checkout(你平常工作的那份目錄)把成果 merge 回來——這一章就在練這件事。
原理:為什麼同一個目錄會互相蓋檔
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 會告訴你,而不是默默消失。
情境 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。它預設從 repo 的預設分支(通常是 main)長出來,所以每個 worktree 的起點都是乾淨的。
一個 session 一件事
Section titled “一個 session 一件事”給每個 session 的提示詞要自足:做什麼、只准碰哪些檔、做完要 commit 還是不要。session 之間看不到彼此的對話,所以「不要動 README」這種邊界一定要寫進提示詞,不能靠它自己猜。
收斂:摘要+回主 checkout merge
Section titled “收斂:摘要+回主 checkout merge”每個 session 收尾時請它用一句話摘要做了什麼、commit 了哪些檔。然後你回主 checkout(不是任何一個 worktree)做 merge:
git merge --no-ff worktree-agit merge --no-ff worktree-b--no-ff 讓每個 session 的成果在 git log --graph 上各自成一個 merge 節點,事後看得出來哪批改動來自誰。
/exit 時的 keep/remove
Section titled “/exit 時的 keep/remove”在 worktree session 打 /exit,如果裡面有改動,Claude Code 會問要 keep 還是 remove:
- keep:保留目錄與分支,之後
claude --worktree <同名>可以回來繼續。 - remove:刪掉目錄與分支,裡面沒 merge 出去的改動一起消失。
規則很簡單:已經 merge 回主 checkout 的選 remove;還沒的選 keep。
實務案例:長流程與小修並行
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 結果清掉。
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(存的是你核准過的權限,留著沒關係)。 -
信任資料夾:第一次在這個目錄開
claude,接受信任對話後/exit。已經做過就跳過。Terminal window claude -
終端機 A:開 worktree
a,整段貼這個提示詞。Terminal window claude --worktree a只改 src/todo.py 與 tests/test_todo.py:list 加 --json 輸出(印出 JSON 陣列,每筆含 text 與 done)並補測試,不要動 README,做完只 commit 不要 push -
終端機 B:再開一個終端機,
cd到同一個 repo,開 worktreeb,整段貼這個提示詞。Terminal window claude --worktree b只改 README.md 加三個使用範例,不要動 src/ 與 tests/,做完只 commit 不要 push -
終端機 C(主 checkout):等 A、B 都回報「已 commit」,再開第三個終端機,在 repo 根目錄(不是
.claude/worktrees/底下)收斂:Terminal window git merge --no-ff worktree-a && git merge --no-ff worktree-b && python3 -m unittest -v -
回終端機 A、B 各打
/exit。它會問 keep/remove,選 remove——成果已經 merge 進main,刪掉是安全的。 -
在主 checkout 確認乾淨——選 remove 時 Claude Code 已經連分支一起刪了,不用再
git branch -d:Terminal window git worktree prune && git worktree list && git branch如果剛才選的是 keep,目錄與分支都還在,要自己收:
git worktree remove .claude/worktrees/a && git branch -d worktree-a(b同理)。
❯ git merge --no-ff worktree-a && git merge --no-ff worktree-b && python3 -m unittest -v Merge made by the 'ort' strategy. …… Ran 17 tests in 0.312s OK ❯ git log --oneline --graph * f3a2c19 Merge branch 'worktree-b' |\ | * 9d1e042 docs: README 加三個使用範例 * | 8c47b31 Merge branch 'worktree-a' ……
兩個 merge 節點+17 個測試 OK=這一章的完成證明。hash 與測試秒數每次不同。
- 步驟 5 的 merge 沒有衝突;
python3 -m unittest -v最後幾行是Ran 17 tests(或更多——main本來有 16 個,A 每補一個測試就加一)與OK。看到OK (skipped=1)也算過:那是比對教材站原始碼的測試,單獨 clone 練習 repo 時會跳過。 git log --oneline --graph最上面有兩個 merge 節點(Merge branch 'worktree-a'、Merge branch 'worktree-b')。python3 src/todo.py list --json印出 JSON(空清單就是[])。- 步驟 7 之後
git worktree list只剩主 checkout一行,git branch沒有worktree-a、worktree-b。
- merge 衝突:
git merge --abort,回那個 session 說「只改指定檔案,重做一次」,它多半是動到了不該動的檔。 - remove 顯示 locked:
git worktree unlock .claude/worktrees/<name>再 remove 一次。 - B 動了 src/:提示詞邊界沒寫清楚,這是本章要你學到的事——把「不要動 src/ 與 tests/」寫進去再來一次。
- A 或 B 的 session 中途關掉、還沒 commit:再打一次
claude --worktree a(或b)會直接回到同一個 worktree,跟它說「繼續,做完只 commit 不要 push」。 - merge 做到一半失敗:
git merge --abort回到 merge 前的狀態;兩個 worktree 與分支都還在,修好再做一次步驟 5。 claude --worktree a說目錄已存在:那是前一次留下的。想接著做就直接進去;想從乾淨起點重做,先跑步驟 1 的「已 clone/重跑」那一段。- 想整章重做:步驟 1 的「已 clone/重跑」那一段就是為此準備的,它只清
a、b與main上的練習結果。
自檢(勾選會存在你的瀏覽器)0/4
以 Claude Code 2.1.246(2026-08-26)為準