AI 寫好的檔案去哪了?Claude Code、Codex、Herdr、Cursor 的 Git Worktree 在哪裡
最近我同時用 Claude Code、Codex、Herdr 和 Cursor 處理同一個專案。為了避免幾個工具直接改到同一份檔案,我把任務分到不同的 Git worktree,有些由工具建立,有些是我手動建立。
回到原本專案後,我用 Cursor 檢查各個任務,卻只看得到自己手動用 git worktree add 建立的那一份。Claude Code 明明回報完成,它建立的 worktree 卻不在我原先以為的位置。Codex CLI 也留有修改紀錄,但後來確認它只會修改啟動時所在的 checkout,不會替我建立 worktree。
我一開始還以為某些任務沒有真的執行。跑過 git worktree list --porcelain 才發現,四個工具處理 worktree 的方式各自不同:有的藏在專案目錄,有的放在家目錄,Codex CLI 則不會替我建立 worktree。
我原本想把四個工具的 worktree 全部放進專案內的 .worktree,實際查過設定後才發現,光靠原生設定做不到。這篇把各工具能改和不能改的地方寫清楚,也記下散落在不同位置的修改該怎麼找回來。
Worktree 為什麼會讓檔案看起來消失
一般切換 Git 分支時,檔案仍在同一個目錄,只是內容換成另一個分支。Worktree 會替同一個 repository 建立另一份 checkout,每份 checkout 都有自己的檔案、HEAD 和 index,但共用 Git 歷史。
AI coding tool 很適合用這種方式隔離任務。一個 agent 改登入功能,另一個 agent 修首頁,兩邊不會直接覆蓋同一個工作目錄。代價是你在主 repo 開著 Cursor 時,看不到其他 worktree 裡尚未合併的檔案。
四個工具預設放在哪裡
Worktree 是 Git 的功能,存放位置則由工具決定。目前這四個工具的預設行為不同:
| 工具 | 預設位置 | 原生設定能否改位置 | 要注意的地方 |
|---|---|---|---|
| Claude Code | <repo>/.claude/worktrees/<name> | 不行 | 沒有 Worktree root 設定 |
| Codex CLI | 無;CLI 不會自行建立 worktree | 不行 | ~/.codex/config.toml 沒有 worktree 路徑設定 |
| Herdr | ~/.herdr/worktrees/<repo>/<branch-slug> | 可以 | 用 config.toml 修改單一全域 root |
| Cursor | ~/.cursor/worktrees/... | 不行 | .cursor/worktrees.json 只能設定建立後要執行的命令 |
原生設定能不能統一目錄
結論是不能。四個工具裡,只有 Herdr 提供直接修改 Worktree root 的設定。Claude Code、Codex CLI 和 Cursor 都沒有對應的原生設定。
下面只保留各工具原生設定能做到的範圍。
Claude Code
修改位置:專案設定檔是 {{ 專案目錄 }}/.claude/settings.json。
怎麼改:Claude Code 沒有可直接指定 Worktree root 的設定鍵,因此無法只修改 settings.json 達成。
備註:--worktree 會使用 .claude/worktrees/<name>,原生設定無法改成其他位置。
Codex CLI
修改位置:Codex CLI 的設定檔是 ~/.codex/config.toml。
怎麼改:config.toml 沒有 Worktree root 設定,Codex CLI 也不會自行建立 worktree,因此無法靠原生設定檔修改位置。
備註:若要在 worktree 裡使用 Codex CLI,必須先由 Git 建立,再用 codex -C "{{ Worktree 絕對路徑 }}" 開啟。這不屬於 Codex 的目錄設定。
Herdr
修改位置:macOS 和 Linux 使用 ~/.config/herdr/config.toml,Windows 使用 %APPDATA%\herdr\config.toml。
怎麼改:在設定檔加入:
[worktrees]
directory = "/Users/yourname/Worktrees/herdr"
備註:Herdr 仍會在這個 root 底下加上 repo 和 branch 目錄,實際路徑會是:
/Users/yourname/Worktrees/herdr/<repo>/<branch-slug>
上面的 /Users/yourname/Worktrees/herdr 是 macOS 範例,實際使用時要換成自己的絕對路徑。Herdr 不會把 {{ 專案目錄 }} 當成變數,也不會依目前開啟的專案自動變換。
Cursor
修改位置:Cursor 的專案設定檔是 .cursor/worktrees.json。
怎麼改:這個檔案沒有 Worktree root 設定,只能設定 worktree 建立後要執行的命令,因此無法靠原生設定檔修改位置。
備註:Cursor 原生建立的 worktree 仍放在 ~/.cursor/worktrees/...。若要使用其他位置,只能先由 Git 手動建立,再用 Cursor 開啟。
找不到檔案時,先問 Git
不管工具把 worktree 放在哪裡,最可靠的查詢入口仍是:
git worktree list --porcelain
輸出可能像這樣:
worktree /Users/me/project
HEAD 1234567
branch refs/heads/main
worktree /Users/me/project/.claude/worktrees/fix-header
HEAD 89abcde
branch refs/heads/worktree-fix-header
worktree /Users/me/project/.worktree/manual-check
HEAD fedcba9
detached
先記下每個 worktree 路徑,再從主 repo 逐一檢查:
WORKTREE_PATH="{{ Worktree 絕對路徑 }}"
# 顯示目前分支,以及已暫存、未暫存和未追蹤檔案的狀態
git -C "$WORKTREE_PATH" status --short --branch
# 列出最近 8 筆 commit,並標出 HEAD、分支和 tag
git -C "$WORKTREE_PATH" log --oneline --decorate -n 8
# 統計尚未暫存的已追蹤檔案修改了哪些檔案和行數
git -C "$WORKTREE_PATH" diff --stat
# 列出未追蹤且沒有被標準 ignore 規則排除的檔案
git -C "$WORKTREE_PATH" ls-files --others --exclude-standard
git -C 不必切換目前所在目錄,較不容易把後續命令跑錯地方。檢查後通常會遇到兩種情況:修改尚未 commit,或成果已經在另一個分支/detached HEAD。
修改還沒 Commit
先不要刪資料夾,也不要執行 git worktree prune。已追蹤檔案可以先輸出成 patch。加上 HEAD 後,已暫存和未暫存的修改都會包含在內:
git -C "$WORKTREE_PATH" diff HEAD --binary > /tmp/agent-worktree.patch
指定要接收成果的 checkout,確認裡面沒有會互相覆蓋的修改,再套用:
TARGET_PATH="{{ 目標 checkout 的絕對路徑 }}"
git -C "$TARGET_PATH" status --short
git -C "$TARGET_PATH" apply /tmp/agent-worktree.patch
git -C "$TARGET_PATH" diff --stat
新檔案不會出現在 git diff 產生的 patch 中,要另外列出:
git -C "$WORKTREE_PATH" ls-files --others --exclude-standard
檢查內容後逐個複製到 $TARGET_PATH。不要用 cp -R 把整個 worktree 蓋回去,裡面還可能有 .git 指向、建置產物和其他不相關檔案。
修改已經 Commit
如果 worktree 有正常分支,先確認分支和 commit:
git -C "$WORKTREE_PATH" branch --show-current
git -C "$WORKTREE_PATH" log --oneline --decorate -n 10
接著指定要接收成果的 checkout,在該目錄執行 merge:
TARGET_PATH="{{ 目標 checkout 的絕對路徑 }}"
git -C "$TARGET_PATH" status --short
git -C "$TARGET_PATH" merge <worktree-branch>
只需要其中一個 commit 時,改用:
git -C "$TARGET_PATH" cherry-pick <commit-hash>
如果某個 worktree 停在 detached HEAD,commit 還在,只是沒有分支名稱指向它。先替目前的 HEAD 建立救援分支:
git -C "$WORKTREE_PATH" branch recover/<task-name> HEAD
請把 <task-name> 換成這次任務的名稱,避免多次救援使用同一個分支名。接著從目標 checkout 檢查差異:
TARGET_PATH="{{ 目標 checkout 的絕對路徑 }}"
git -C "$TARGET_PATH" log --oneline recover/<task-name>
git -C "$TARGET_PATH" diff <target-branch>...recover/<task-name>
確認後再 merge 或 cherry-pick。先建立分支的用意是保住 commit,避免清理 worktree 後只剩一串難找的 hash。
最後才清理
成果已經合併、patch 已保存,且未追蹤檔案也檢查完成後,再移除 worktree:
git worktree remove "{{ Worktree 絕對路徑 }}"
如果資料夾被手動搬過,可先修復 metadata:
git worktree repair "{{ 搬移後的 Worktree 絕對路徑 }}"
只想預覽失效項目時使用:
git worktree prune --dry-run
還在檢查中的 worktree 可以先鎖住:
git worktree lock "{{ Worktree 絕對路徑 }}" \
--reason "等待人工檢查 AI 工作成果"
我現在遇到「AI 說做完了,主 repo 卻沒有檔案」時,會先跑 git worktree list --porcelain。看到實際路徑後,再判斷要存 patch、建立救援分支,或只是開錯資料夾。確認成果回到目標分支後,才清理 worktree。
留言