実用ガイド · 実用ガイド
Git worktreeを移動したら動かない?repair・prune・removeの前に双方向を確認
未コミットの作業を保全し、Gitが保存する2つのパスを記録する。移動した側に合うrepairを選び、クリーンアップや削除の前に両方向を検証する。

mainリポジトリやlinked worktreeを`git worktree move`以外で移動すると、Gitの2つのパス記録が一致しなくなることがある。「not a git repository」、`prunable`表示、ファイルは残るのに`git worktree list`に出ない状態などが起こり得る。
最初に`prune`、`remove --force`、`rm -rf`を実行したり、`.git`を手で編集したりしない。作業ディレクトリを保全して、リンクの両端を記録する。修復命令は短くても、正しい関係を直し、未コミットの作業が残ったことを確かめる必要がある。
対象はGit自身のworktree管理情報だ。デスクトップアプリ、IDE、タスク実行ツールやワークスペースのデータベースが、別のパスを保存することもある。Gitが正常でも、その別の登録情報は古いままの場合がある。
1. 証拠を保全する
クリーンアップジョブ、ガベージコレクション、IDEのワークスペース削除、`git worktree prune`を呼ぶスクリプトを止める。調査中にどちらのディレクトリも再移動しない。
未コミットや未追跡のファイルがある作業ディレクトリは、安全な場所に全体をコピーする。登録が壊れていても、フォルダーを捨ててよいという意味ではない。
Git命令がまだ動くworktreeから、次の出力を保存する。
```sh git --version git worktree list --porcelain git worktree prune --dry-run --verbose ```
dry runは診断だけに使う。新しい場所にファイルが残るworktreeの削除を提案したら止める。古い登録の証拠であり、pruneの許可ではない。
各ディレクトリの絶対パス、存在の有無、`git status --porcelain=v1`が動くかも記録する。動けば出力を保存し、失敗したら最初のエラーをそのまま残す。
認証情報、トークン入りのremote URL、非公開ファイルの内容をサポート報告に貼らない。
2. 双方向のリンクを記録する
linked worktreeの小さな`.git`ファイルは、mainの`.git/worktrees/`内の専用ディレクトリを指す。その中の`gitdir`記録がlinked作業ディレクトリへ戻る。したがってリンクには2つの方向がある。
worktreeごとに1行を作る。
| 項目 | 記録する内容 | | --- | --- | | Worktree名 | 秘密のプロジェクト名を避けた識別名 | | 現在のディレクトリ | 今存在するパス | | 一覧のディレクトリ | `git worktree list --porcelain`のパス | | linked側の`.git`対象 | `gitdir:`の対象を記録し、編集しない | | main側の`gitdir`対象 | `.git/worktrees/<id>/gitdir`の逆方向パス | | ブランチまたはdetached HEAD | porcelain一覧や保存済みHEAD | | 変更・未追跡の状態 | 正確な状態概要、または取得不能 | | prune dry run | 変更なし、または削除提案の原文 | | 第三者のパス | Git以外のIDEやワークスペース記録 | | 分類 | main移動、linked移動、両方、孤立、または不明 |
ディレクトリ名だけで登録を選ばない。似た名前のworktreeがあり得るので、管理ディレクトリ名を現在のパスの代わりにしない。
3. repairの前に移動を分類する
記録表から次の分岐を選ぶ。
main worktreeだけが移動した
linked側の`.git`がmainの旧位置を指し、linkedでのGit命令が失敗することがある。新しいmainには専用のworktree記録が残る。
新しいmain worktreeから実行する。
```sh git worktree repair ```
Git公式文書では、移動したmainとlinked worktreeの接続を戻すと説明されている。
linked worktreeを1つだけ移動した
linkedのポインターがmainに届くため、内部のGit命令が動く場合がある。一方、main側の`gitdir`は旧linkedパスを保持し、一覧がそこを`prunable`とすることがある。
移動後のlinked worktree内で実行する。
```sh git worktree repair ```
その後mainで、porcelain一覧が新しいパスを示すことを確認する。
複数のlinked worktreeを移動した
mainに到達できるworktreeから、移動後のlinkedパスをすべて指定する。
```sh git worktree repair /new/path/alpha /new/path/beta ```
診断中は絶対パスを使う。相対リンクの方針を意図的に採用し検証済みの場合だけ例外とする。
mainとlinkedの両方を移動した
新しいmainから各linked worktreeの新しいパスを指定する。
```sh git worktree repair /new/path/alpha /new/path/beta ```
両側を手動移動したとき、明示的に両方向を修復する分岐だ。
ディレクトリはあるが未登録
未登録は削除してよいという意味ではない。管理記録がなくても未コミット作業が残る可能性がある。保全してファイルを調べ、自動削除から外す。対応関係が不明なら`repair`は正しい管理記録を新たに推測できない。
捨ててよい残骸だと確認した場合でも、削除は調査後の別の判断であり、Gitの確認失敗から自動的に導かない。
4. 修復した関係を検証する
mainとすべてのlinkedから、同じ読み取り確認をもう一度行う。
```sh git worktree list --porcelain git worktree prune --dry-run --verbose git status --porcelain=v1 git rev-parse --path-format=absolute --git-dir git rev-parse --path-format=absolute --git-common-dir ```
次のすべてが成立した場合だけ修復を受け入れる。
1. 目的のworktreeがそれぞれ現在のパスに1回だけ現れる。 2. 生きているworktreeが`prunable`になっていない。 3. 各linkedが期待するcommon directoryを解決する。 4. ブランチやdetached HEADの対応が変わっていない。 5. 事前に記録した変更済み・未追跡ファイルが残る。 6. prune dry runが生きているworktreeの削除を提案しない。 7. IDEや別のワークスペースが正しいパスを開くか、別の未解決問題として明記されている。
1つでも失敗したら止める。証拠を保存し、forceオプションへ進まない。
5. repair・prune・remove・lockを分ける
`git worktree repair`は古い、または壊れた管理リンクを更新する。mainやlinkedの移動に使う通常の命令だ。
`git worktree prune`は作業ディレクトリがなくなったworktreeの管理情報を削除する。単に移動したディレクトリの最初の対処ではない。先にdry runを見る。
`git worktree remove`は不要になった登録済みworktreeを退役させる。Gitは通常、変更や未追跡ファイルのあるworktreeを拒否する。`--force`は保護を弱めるもので、修復策ではない。
`git worktree lock --reason "..."`は、着脱するドライブや一時的に未マウントになる共有領域のworktreeを自動pruneから守る。誤ったパスは修復しない。ロックされたworktreeの移動や削除には追加のforceが必要になる。
各命令の目的は異なる。Gitはmain worktreeやサブモジュールを含むlinked worktreeの`worktree move`を認めず、superprojectの複数チェックアウトも推奨していない。ここでの例はその制約を解決しない。証拠を残して構成を別途調べる。
6. 第三者のパス記録を別の層として扱う
ワークスペース製品がworktreeの絶対パスを独自DBに保存することがある。正式な`git worktree move`後にGitが新しいパスを示しても、製品は旧パスを開く場合がある。
まず前述の検証でGitが正常か確かめる。その後、製品の文書にあるパス変更、インポート、再作成の方法を調べる。アプリの古い記録に合わせてGitを再変更しない。
第三者の結果を別に記録する。
- Git正常、製品パスも更新。 - Git正常、製品にパス変更機能なし。 - Git正常、製品レコードの再作成が必要でアプリ状態が失われる可能性あり。 - Git異常、双方向記録表へ戻る。
この区別により、製品の制約をGit修復の失敗と取り違えない。
7. 使い捨てリポジトリで確認したこと
一時的なGit 2.51.1リポジトリにmainと1つのlinked worktreeを作り、linkedに未追跡ファイルを置いた。
両方のディレクトリを手動移動すると、mainの一覧は旧linkedパスを`prunable`とし、prune dry runは管理記録の削除を提案した。新しいlinkedでの`git status`は失敗した。新mainで`git worktree repair <new-linked-path>`を実行すると接続が戻り、未追跡ファイルも残った。
linkedのみの移動では内部のstatusが動く一方、main側のパスは古いままだった。新しいlinked内のrepairでmain一覧が更新された。mainのみの移動ではlinkedポインターが壊れ、新mainのrepairで戻った。
3つの使い捨てLinux環境でGit 2.51.1を実行した。各repair後に変更済み・未追跡ファイルのバイト、HEAD、ブランチの対応は変わらなかった。現行文書は2.56.0まで確認したが、その実行ファイルは試していない。全Git版、ネットワーク領域、サブモジュール、IDEやワークスペースDBの挙動を保証しない。
よくある質問
linkedの.gitを手で編集すべきか?
証拠として残し、まず`git worktree repair`を使う。一方向の編集ではmain側の逆方向記録が古いままになることがある。
新linkedでgit statusが動くのに一覧が旧パスなのはなぜ?
linkedの`.git`はmainに届いていても、main側の`gitdir`が旧linked位置を指す場合がある。一方向の修復に該当する。
prunableなら安全にpruneできるか?
対応するworktreeが本当になくなったか確認する。移動して残るディレクトリでも旧パスはprunableになる。
未登録ディレクトリをrepairで戻せるか?
Gitが対応関係を戻せる管理情報が残る場合に限る。worktreeに見えるだけでは有効な登録の証拠にならない。削除前に保全して調べる。
repairはIDEやワークスペース管理も更新するか?
必ずしも更新しない。GitはGitの管理情報だけを直す。他の製品の絶対パスは各製品が対応する更新や再作成の手順を使う。
