M8 並行工作:stash 與 worktree
- 用
git stash收起、取回、管理未提交的修改; - 用
git worktree同時在幾條分支上工作,並正確地收拾; - 解釋「同一條分支同一時間只能在一個 worktree」的原因;
- 按情況在 stash、分支、worktree 之間選擇。
1做到一半,要先處理別的事 Interrupted work
你正在改報告的兩節,還沒改完,也不想把半成品提交。這時導師要你立即修正另一處的錯誤。M4 說過,有未提交的修改時切換分支,Git 可能會拒絕;即使能切換,半成品也會跟着你到另一條分支,混進錯誤的 commit。
有三種做法:
- 先提交半成品(之後用 M6 的
reset --soft或 M7 的互動式 rebase 整理); - stash:把修改暫時收進抽屜,處理完再拿出來;
- worktree:不動現在這張書桌,另開一張書桌處理急事。
2stash:把半成品收進抽屜 Stashing
git stash # 收起:工作目錄和暫存區回到 HEAD 的樣子
git stash push -m "改到一半的第二節" # 收起時寫一句說明
git stash list # 列出抽屜裏的東西:stash@{0} 是最新的
git stash pop # 拿出最新一份,並從抽屜移除
git stash apply stash@{1} # 拿出指定的一份,但留在抽屜
git stash drop stash@{1} # 丟掉指定的一份
抽屜是一個堆疊:最後收進去的,最先被 pop 出來。拿出來時,Git 用三方合併把修改套回目前的檔案;如果期間同一處(或相鄰處)被改過,就會出現衝突標記 <<<<<<< Updated upstream … >>>>>>> Stashed changes,處理方法和 M5 相同,而那一份 stash 會保留在抽屜,直到你確認後 drop。
git stash 建立兩個特殊的 commit:一個記下暫存區(index on …),一個記下工作目錄(WIP on …,它的第二個 parent 就是前者),再由 refs/stash 指着。所以 stash 和分支一樣存在倉庫裏,所有 worktree 共用同一個抽屜。沙盒算出的 stash 編號與真實 Git 相同。
- 未追蹤的新檔案預設不會被收起。要連它們一起收,用
git stash -u。 - 抽屜會被遺忘。stash 沒有分支名,幾星期後你不會記得
stash@{3}是甚麼。收起時寫說明(-m);收起超過一天的工作,通常應該改為提交到一條分支。
3worktree:多開一張書桌 Worktrees
FAQ-001 的比喻:倉庫是一本書,分支是書籤,worktree 是一張攤開這本書的書桌。git worktree add 在磁碟上多建一個資料夾,裏面攤開另一條分支,而歷史仍然只有一份。
git worktree add ../app-feature feature # 為現有分支開一張書桌
git worktree add -b hotfix ../hotfix # 同時建立新分支 hotfix
git worktree list # 列出所有書桌
cd ../hotfix # 到那張書桌工作(就是普通的資料夾)
git worktree remove ../hotfix # 收拾書桌(分支本身保留)
git worktree prune # 清理已被手動刪除的書桌留下的記錄
一條分支,同一時間只能在一張書桌
如果兩張書桌都攤開 main,你在其中一張提交,main 會往前走;另一張書桌的檔案和暫存區卻還停在舊版本,它下一次提交就會悄悄蓋掉剛才的改動。所以 Git 直接禁止:
fatal: 'feature' is already used by worktree at '~/app-feature'
同樣地,被某張書桌攤開的分支也不能刪除。要在另一張書桌查看同一個版本,可以用 git worktree add --detach <路徑> main(detached HEAD,M4)。
.git/worktrees/ 裏的記錄仍在,那條分支也會一直被當作「使用中」。用 git worktree remove;如果已經刪了,執行 git worktree prune。另外,每張書桌都是一份完整的工作檔案,用完就收拾,免得佔用大量磁碟空間。
4沙盒:抽屜與書桌 Sandbox: stash and worktrees
5stash、分支、worktree 怎樣選 Choosing
| stash | 分支+提交 | worktree | |
|---|---|---|---|
| 本質 | 抽屜:暫存的修改(特殊 commit) | 書籤:歷史裏的一個位置 | 書桌:磁碟上的另一個資料夾 |
| 適合 | 幾分鐘到幾小時的打斷 | 任何要保留的工作 | 要同時進行、或要長時間並存的工作 |
| 同時看兩個版本 | 不行 | 不行(一個資料夾一次只展示一條分支) | 可以,兩個資料夾並排 |
| 成本 | 幾乎為零 | 幾乎為零 | 一份完整的工作檔案 |
| 風險 | 容易被遺忘 | 半成品混入歷史(可之後整理) | 忘記收拾、佔用磁碟 |
worktree 與 clone 有何不同?clone 是另一個完整的倉庫(另一份 .git),兩邊的 commit 要靠 push/pull 才能互通。worktree 共用同一份 .git:在任何一張書桌提交,其他書桌立即看得到,不必同步。
- 「開一個 worktree 就是複製了整個倉庫。」不是。歷史只有一份;複製的只是那條分支的工作檔案(FAQ-001)。
- 「stash 只存在我現在這個資料夾。」不是。
refs/stash在共用的.git裏,任何一張書桌都能git stash list、pop。 - 「
git worktree remove會刪掉分支。」不會。它只收拾書桌,分支和 commit 都保留。
6worktree 與 AI 協作 Worktrees and AI agents
讓幾個 AI agent(或幾位同學)同時修改同一個倉庫時,最常見的做法就是一個 agent 一張書桌:每個 agent 在自己的 worktree、自己的分支上工作,互不干擾;完成後各自開 PR,經審查合併回 main。例如 Claude 的桌面程式為每個工作階段自動開一個 worktree(資料夾在 .claude/worktrees/ 之下),這門課的教材就是這樣寫成的。worktree 的「一條分支一張書桌」規則,正好防止兩個 agent 同時改寫同一條分支。M13 會完整討論 AI 時代的協作規則。
7命令速查 Cheat sheet
| 命令 | 作用 |
|---|---|
git stash / git stash push -m "說明" | 收起未提交的修改 |
git stash -u | 連未追蹤的檔案一起收起 |
git stash list | 列出所有 stash |
git stash pop / apply | 取回最新一份(pop 會移除,apply 保留) |
git stash drop stash@{n} | 丟掉指定的一份 |
git worktree add <路徑> <分支> | 為現有分支開書桌 |
git worktree add -b <新分支> <路徑> | 建立新分支並開書桌 |
git worktree list | 列出所有書桌 |
git worktree remove <路徑> | 收拾書桌(有未提交修改時要 --force) |
git worktree prune | 清理被手動刪除的書桌的記錄 |
8小測 Quiz
本單元重點 Summary
- stash 是抽屜:暫時收起未提交的修改,是一個堆疊;它本身也是 commit,所有 worktree 共用。
- worktree 是書桌:同一份
.git,多個資料夾各自攤開一條分支,各有自己的 HEAD、工作目錄和暫存區。 - 同一條分支同一時間只能在一張書桌,以免互相覆蓋。
- 收拾書桌用
git worktree remove;手動刪了就prune。 - 短暫打斷用 stash,要保留的工作就提交,要同時進行的用 worktree。
延伸閱讀
- Pro Git 7.3 Stashing and Cleaning
- git worktree 官方文件、git stash 官方文件
- DataCamp, Git Worktree Tutorial(英文,含 hotfix 與 AI 並行開發的例子)
- FAQ-001:分支和 worktree 有甚麼分別?