<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Worktree on recca0120 技術筆記</title><link>https://recca0120.github.io/tags/worktree/</link><description>Recent content in Worktree on recca0120 技術筆記</description><generator>Hugo -- gohugo.io</generator><language>zh-hant-tw</language><lastBuildDate>Tue, 14 Apr 2026 22:00:00 +0800</lastBuildDate><atom:link href="https://recca0120.github.io/tags/worktree/index.xml" rel="self" type="application/rss+xml"/><item><title>git worktree：一個 repo 同時開多份工作目錄，也是 AI agent 並行開發的關鍵</title><link>https://recca0120.github.io/2026/04/14/git-worktree-parallel-work/</link><pubDate>Tue, 14 Apr 2026 22:00:00 +0800</pubDate><guid>https://recca0120.github.io/2026/04/14/git-worktree-parallel-work/</guid><description>&lt;img src="https://recca0120.github.io/" alt="Featured image of post git worktree：一個 repo 同時開多份工作目錄，也是 AI agent 並行開發的關鍵" /&gt;&lt;p&gt;手邊 feature 改到一半，PM 說 production 壞了要 hotfix。你的反射動作可能是 &lt;code&gt;git stash&lt;/code&gt;、切 master、修、回來 &lt;code&gt;stash pop&lt;/code&gt;——然後 dev server 重啟、IDE 重索引、未追蹤的 build 產物通通被 stash 吃掉。&lt;/p&gt;
&lt;p&gt;這種情境 git worktree 解得漂亮：&lt;strong&gt;同一個 repo 同時 checkout 多個分支到不同資料夾&lt;/strong&gt;，每個資料夾有自己的 HEAD、index、未追蹤檔案，但共用同一份物件庫。feature 留在原地不動，hotfix 在隔壁資料夾搞定。&lt;/p&gt;
&lt;h2 id="跟-stash多份-clone-比起來"&gt;&lt;a href="#%e8%b7%9f-stash%e5%a4%9a%e4%bb%bd-clone-%e6%af%94%e8%b5%b7%e4%be%86" class="header-anchor"&gt;&lt;/a&gt;跟 stash、多份 clone 比起來
&lt;/h2&gt;&lt;table&gt;
 &lt;thead&gt;
 &lt;tr&gt;
 &lt;th&gt;方案&lt;/th&gt;
 &lt;th&gt;切換成本&lt;/th&gt;
 &lt;th&gt;磁碟&lt;/th&gt;
 &lt;th&gt;物件同步&lt;/th&gt;
 &lt;/tr&gt;
 &lt;/thead&gt;
 &lt;tbody&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;git stash&lt;/code&gt; + 切分支&lt;/td&gt;
 &lt;td&gt;高（dev server 重啟、IDE 重索引）&lt;/td&gt;
 &lt;td&gt;省&lt;/td&gt;
 &lt;td&gt;同一個 repo&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;多份 clone&lt;/td&gt;
 &lt;td&gt;低&lt;/td&gt;
 &lt;td&gt;浪費（大 repo 幾 GB）&lt;/td&gt;
 &lt;td&gt;要分別 fetch&lt;/td&gt;
 &lt;/tr&gt;
 &lt;tr&gt;
 &lt;td&gt;&lt;code&gt;git worktree&lt;/code&gt;&lt;/td&gt;
 &lt;td&gt;低&lt;/td&gt;
 &lt;td&gt;省（物件共用）&lt;/td&gt;
 &lt;td&gt;單一 fetch 全部生效&lt;/td&gt;
 &lt;/tr&gt;
 &lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;worktree 是兩者的綜合體:檔案系統隔離、物件庫統一。&lt;/p&gt;
&lt;h2 id="核心指令"&gt;&lt;a href="#%e6%a0%b8%e5%bf%83%e6%8c%87%e4%bb%a4" class="header-anchor"&gt;&lt;/a&gt;核心指令
&lt;/h2&gt;&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt; 1
&lt;/span&gt;&lt;span class="lnt"&gt; 2
&lt;/span&gt;&lt;span class="lnt"&gt; 3
&lt;/span&gt;&lt;span class="lnt"&gt; 4
&lt;/span&gt;&lt;span class="lnt"&gt; 5
&lt;/span&gt;&lt;span class="lnt"&gt; 6
&lt;/span&gt;&lt;span class="lnt"&gt; 7
&lt;/span&gt;&lt;span class="lnt"&gt; 8
&lt;/span&gt;&lt;span class="lnt"&gt; 9
&lt;/span&gt;&lt;span class="lnt"&gt;10
&lt;/span&gt;&lt;span class="lnt"&gt;11
&lt;/span&gt;&lt;span class="lnt"&gt;12
&lt;/span&gt;&lt;span class="lnt"&gt;13
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 新增 worktree——用路徑的最後一段當新分支名&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git worktree add ../hotfix &lt;span class="c1"&gt;# 從 HEAD 開 hotfix 分支&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git worktree add ../review pr-123 &lt;span class="c1"&gt;# checkout 現有分支&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git worktree add -b feat-x ../feat-x main &lt;span class="c1"&gt;# 從 main 開 feat-x&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git worktree add -d ../throwaway &lt;span class="c1"&gt;# detached HEAD、不開分支&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git worktree list &lt;span class="c1"&gt;# --porcelain 方便 script 解析&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git worktree remove ../hotfix &lt;span class="c1"&gt;# 乾淨才能 remove；髒的加 -f&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git worktree prune &lt;span class="c1"&gt;# 清掉手動刪掉資料夾後的殘留 metadata&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git worktree lock ../usb-drive --reason &lt;span class="s2"&gt;&amp;#34;removable drive&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git worktree unlock ../usb-drive
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git worktree move ../old ../new &lt;span class="c1"&gt;# 有 submodule 的 worktree 不能 move&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git worktree repair &lt;span class="c1"&gt;# 主 repo 搬家後修復連結&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;&lt;strong&gt;取個短 alias 用起來更順&lt;/strong&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git config --global alias.wta &lt;span class="s1"&gt;&amp;#39;worktree add&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git config --global alias.wtl &lt;span class="s1"&gt;&amp;#39;worktree list&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git config --global alias.wtr &lt;span class="s1"&gt;&amp;#39;worktree remove&amp;#39;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;h2 id="常見實戰場景"&gt;&lt;a href="#%e5%b8%b8%e8%a6%8b%e5%af%a6%e6%88%b0%e5%a0%b4%e6%99%af" class="header-anchor"&gt;&lt;/a&gt;常見實戰場景
&lt;/h2&gt;&lt;p&gt;&lt;strong&gt;1. Hotfix 不打斷 feature&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git worktree add ../hotfix-prod origin/main
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; ../hotfix-prod
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 修 bug、commit、push、開 PR&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; ../myrepo
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git worktree remove ../hotfix-prod
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;feature 的 dev server 沒停過,node_modules 沒動過,IDE 也沒重掃。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;2. 長跑測試 + 繼續寫&lt;/strong&gt;&lt;/p&gt;
&lt;p&gt;&lt;code&gt;pytest&lt;/code&gt; / &lt;code&gt;cargo test&lt;/code&gt; 跑 10 分鐘,開一個 worktree 讓它慢慢跑,你在主 worktree 繼續改下一個 commit。兩邊互不干擾。&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git worktree add ../ci-run branch-a
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; ../ci-run &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; pytest --slow &lt;span class="p"&gt;&amp;amp;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; - &lt;span class="c1"&gt;# 回主 worktree 繼續寫&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;&lt;strong&gt;3. Code review 不污染當下狀態&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git worktree add ../review-456 pr-456-branch
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; ../review-456
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 跑起來、翻程式、下 comment&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;cd&lt;/span&gt; - &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; git worktree remove ../review-456
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;&lt;strong&gt;4. 多個 AI agent 平行跑&lt;/strong&gt;(2025 最被低估的用法)&lt;/p&gt;
&lt;p&gt;Claude Code / Cursor / Aider 這類 AI 工具一次只能有一個在同個資料夾工作,檔案會互相蓋。一個分支一個 worktree,就能&lt;strong&gt;三個 agent 同時跑三個 feature&lt;/strong&gt;,不互相踩腳、各自 dev server port、各自 node_modules:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git worktree add ../agent-a -b feat-a
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git worktree add ../agent-b -b feat-b
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git worktree add ../agent-c -b feat-c
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="c1"&gt;# 三個 terminal pane / 三個 tmux window 各跑一個 claude&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;Claude Code 的 Agent tool 甚至內建 &lt;code&gt;isolation: &amp;quot;worktree&amp;quot;&lt;/code&gt; 選項,sub-agent 自動開 worktree 跑,改完 merge 回來。&lt;/p&gt;
&lt;h2 id="目錄佈局的三種流派"&gt;&lt;a href="#%e7%9b%ae%e9%8c%84%e4%bd%88%e5%b1%80%e7%9a%84%e4%b8%89%e7%a8%ae%e6%b5%81%e6%b4%be" class="header-anchor"&gt;&lt;/a&gt;目錄佈局的三種流派
&lt;/h2&gt;&lt;p&gt;&lt;strong&gt;兄弟資料夾(最簡單)&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;~/code/myrepo
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;~/code/myrepo-hotfix
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;~/code/myrepo-review-123
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;編輯器「一個資料夾一個專案」模式最順。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;.worktrees/&lt;/code&gt; 子目錄&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;myrepo/
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;├── src/
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;└── .worktrees/
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; ├── feat-x/
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; └── hotfix/
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;集中管理,記得加到 global gitignore。缺點是某些工具(ESLint、tsc)會遞迴掃進去。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Bare repo 模式(多分支平行開發首選)&lt;/strong&gt;&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;mkdir myproj &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;cd&lt;/span&gt; myproj
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git clone --bare git@github.com:org/repo.git .bare
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="nb"&gt;echo&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;gitdir: ./.bare&amp;#34;&lt;/span&gt; &amp;gt; .git
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git worktree add main
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;git worktree add feat-x
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;結果:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;span class="lnt"&gt;4
&lt;/span&gt;&lt;span class="lnt"&gt;5
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-fallback" data-lang="fallback"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;myproj/
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;├── .bare/ # 真正的物件庫
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;├── .git # 檔案,內容指向 .bare
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;├── main/ # main 分支的 checkout
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;└── feat-x/ # feat-x 分支的 checkout
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;沒有「主 working copy」,每個分支都是一個 worktree,&lt;code&gt;cd&lt;/code&gt; 就是切換分支。跟 tmux / AI agent 搭起來超乾淨。&lt;/p&gt;
&lt;h2 id="踩過的雷"&gt;&lt;a href="#%e8%b8%a9%e9%81%8e%e7%9a%84%e9%9b%b7" class="header-anchor"&gt;&lt;/a&gt;踩過的雷
&lt;/h2&gt;&lt;p&gt;&lt;strong&gt;&lt;code&gt;.git&lt;/code&gt; 在 linked worktree 是檔案不是資料夾&lt;/strong&gt;。內容是 &lt;code&gt;gitdir: /path/to/main/.git/worktrees/&amp;lt;name&amp;gt;&lt;/code&gt;。直接讀 &lt;code&gt;.git/&lt;/code&gt; 當資料夾的工具會炸。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;同一個分支不能在兩個 worktree checkout&lt;/strong&gt;。預設擋下以防 index 漂移。硬要可以 &lt;code&gt;--force&lt;/code&gt; 或用 detached HEAD。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Submodule 是痛點&lt;/strong&gt;。&lt;code&gt;worktree move&lt;/code&gt; 會拒絕,&lt;code&gt;remove&lt;/code&gt; 要 &lt;code&gt;--force&lt;/code&gt;。&lt;code&gt;.git/modules/&lt;/code&gt; 是共用的,不同 worktree 切不同 submodule commit 會互相覆蓋。大量用 submodule 的專案要小心。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;node_modules&lt;/code&gt;、&lt;code&gt;venv&lt;/code&gt;、&lt;code&gt;target/&lt;/code&gt; 各自一份&lt;/strong&gt;。磁碟吃重。幾個省法:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;pnpm 有 content-addressable store,多個 worktree 重裝也幾乎不佔空間&lt;/li&gt;
&lt;li&gt;Rust 設 &lt;code&gt;CARGO_TARGET_DIR=~/.cache/cargo-target&lt;/code&gt; 讓所有 worktree 共用&lt;/li&gt;
&lt;li&gt;uv、poetry 的 cache 也能跨 worktree 共用&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;&lt;strong&gt;&lt;code&gt;.env&lt;/code&gt; 不會複製&lt;/strong&gt;。用 direnv 的 &lt;code&gt;.envrc&lt;/code&gt; 放進去,進入資料夾自動載入。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;hooks 是共用的&lt;/strong&gt;(&lt;code&gt;.git/hooks/&lt;/code&gt; 在 common dir)。hook script 如果用相對路徑假設在 repo root,換 worktree 會壞。寫 hook 一律用 &lt;code&gt;git rev-parse --show-toplevel&lt;/code&gt; 取當下 worktree 的根。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;IDE 索引各自跑&lt;/strong&gt;。VS Code / JetBrains 在每個 worktree 都建一份索引,CPU 跟磁碟會重複吃。這是結構限制沒得避。&lt;/p&gt;
&lt;h2 id="編輯器整合"&gt;&lt;a href="#%e7%b7%a8%e8%bc%af%e5%99%a8%e6%95%b4%e5%90%88" class="header-anchor"&gt;&lt;/a&gt;編輯器整合
&lt;/h2&gt;&lt;p&gt;&lt;strong&gt;VS Code&lt;/strong&gt;:用 multi-root workspace(&lt;code&gt;File → Add Folder to Workspace&lt;/code&gt;)一次開多個 worktree,或乾脆每個開一個視窗。2024 年後 &lt;code&gt;GitHub.vscode-pull-request-github&lt;/code&gt; 直接把 PR checkout 做成 worktree。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;JetBrains&lt;/strong&gt;:Git tool window 有原生 worktree UI 從 2023.2 開始能 GUI 操作。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;fzf 快速切換&lt;/strong&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;div class="chroma"&gt;
&lt;table class="lntable"&gt;&lt;tr&gt;&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code&gt;&lt;span class="lnt"&gt;1
&lt;/span&gt;&lt;span class="lnt"&gt;2
&lt;/span&gt;&lt;span class="lnt"&gt;3
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;
&lt;td class="lntd"&gt;
&lt;pre tabindex="0" class="chroma"&gt;&lt;code class="language-bash" data-lang="bash"&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;wtcd&lt;span class="o"&gt;()&lt;/span&gt; &lt;span class="o"&gt;{&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt; &lt;span class="nb"&gt;cd&lt;/span&gt; &lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;&lt;span class="k"&gt;$(&lt;/span&gt;git worktree list --porcelain &lt;span class="p"&gt;|&lt;/span&gt; awk &lt;span class="s1"&gt;&amp;#39;/^worktree /{print $2}&amp;#39;&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; fzf&lt;span class="k"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;&amp;#34;&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;span class="line"&gt;&lt;span class="cl"&gt;&lt;span class="o"&gt;}&lt;/span&gt;
&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;
&lt;/div&gt;
&lt;/div&gt;&lt;p&gt;敲 &lt;code&gt;wtcd&lt;/code&gt; 跳 fzf 選單,fuzzy 搜 worktree 路徑,enter 直接 &lt;code&gt;cd&lt;/code&gt; 過去。&lt;/p&gt;
&lt;h2 id="20242026-的新功能"&gt;&lt;a href="#20242026-%e7%9a%84%e6%96%b0%e5%8a%9f%e8%83%bd" class="header-anchor"&gt;&lt;/a&gt;2024–2026 的新功能
&lt;/h2&gt;&lt;p&gt;&lt;strong&gt;Git 2.44(2024/2)&lt;/strong&gt;:&lt;code&gt;git worktree add --orphan&lt;/code&gt; — 開一個 unborn branch 的 worktree,做 &lt;code&gt;gh-pages&lt;/code&gt; 那種分開 deploy 分支很順。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Git 2.46(2024/7)&lt;/strong&gt;:&lt;code&gt;worktree.useRelativePaths&lt;/code&gt; config 跟 &lt;code&gt;--relative-paths&lt;/code&gt; flag — worktree 內部連結改成相對路徑。好處是主 repo 搬家、或整個資料夾同步到 Dropbox / iCloud / docker volume,worktree 不會爛。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Git 2.48(2025/1)&lt;/strong&gt;:&lt;code&gt;git worktree repair&lt;/code&gt; 會自動修絕對/相對路徑不一致的狀況。&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;Git 2.50(2025 年中)&lt;/strong&gt;:relative paths 跟 porcelain 輸出穩定化。&lt;/p&gt;
&lt;p&gt;生態系:2025 年「AI agent 一分支一 worktree」模式變主流,&lt;code&gt;git-town&lt;/code&gt;、&lt;code&gt;ghq&lt;/code&gt;、&lt;code&gt;gh&lt;/code&gt; CLI 都陸續加 first-class worktree 支援。&lt;/p&gt;
&lt;h2 id="上手建議"&gt;&lt;a href="#%e4%b8%8a%e6%89%8b%e5%bb%ba%e8%ad%b0" class="header-anchor"&gt;&lt;/a&gt;上手建議
&lt;/h2&gt;&lt;ol&gt;
&lt;li&gt;先在隨便一個 repo 跑 &lt;code&gt;git worktree add ../test-wt -b test-branch&lt;/code&gt;,進去亂改&lt;/li&gt;
&lt;li&gt;回到主 worktree,觀察 &lt;code&gt;git branch&lt;/code&gt; 看到但 &lt;code&gt;git status&lt;/code&gt; 不受影響&lt;/li&gt;
&lt;li&gt;&lt;code&gt;git worktree remove ../test-wt&lt;/code&gt; 刪掉,檢查主 worktree 完全沒動&lt;/li&gt;
&lt;li&gt;加上 &lt;code&gt;wta&lt;/code&gt; / &lt;code&gt;wtl&lt;/code&gt; / &lt;code&gt;wtr&lt;/code&gt; alias,肌肉記憶養起來&lt;/li&gt;
&lt;li&gt;下次 hotfix 時用 worktree 代替 stash,感受一下不用切分支的爽度&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;對用 AI coding agent 的人來說,worktree 不是加分項——是必備。一個 repo 一次只能跑一個 agent 這個限制,worktree 直接拿掉。&lt;/p&gt;
&lt;h2 id="參考資源"&gt;&lt;a href="#%e5%8f%83%e8%80%83%e8%b3%87%e6%ba%90" class="header-anchor"&gt;&lt;/a&gt;參考資源
&lt;/h2&gt;&lt;ul&gt;
&lt;li&gt;&lt;a class="link" href="https://git-scm.com/docs/git-worktree" target="_blank" rel="noopener"
 &gt;git-worktree 官方文件&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://github.com/git/git/blob/master/Documentation/RelNotes/2.46.0.txt" target="_blank" rel="noopener"
 &gt;Git 2.46 release notes — worktree.useRelativePaths&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://code.claude.com/docs/en/agent-sdk" target="_blank" rel="noopener"
 &gt;Claude Code Agent tool — isolation: worktree&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a class="link" href="https://www.git-town.com/" target="_blank" rel="noopener"
 &gt;git-town — high-level git workflow wrapper&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</description></item></channel></rss>