1. やったこと
元の作業ツリーに未コミットの差分が積まれた状態で、ExploreSceneやsession.tsの大規模な分割リファクタを進める必要がありました。その場でmainをいじると差分が混ざるので、git worktreeで/tmp/dunque-mainに別ツリーを切り、そこにcodex CLIを向けて作業させました1。
自分は元のツリーで別のことを進めます。codexがmain上でコミットを積み、自分が手元の差分を整理する。並列で動かせば時間を節約できると思っていました2。
実際、作業速度は上がりました。codexは小さいコミットを連続して積み、typecheckとtestも別ツリーで完結していました。問題は終わらせ方にありました。
2. worktreeを消すタイミングで詰まった
codexの作業が終わったタイミングでgit worktree removeを走らせました3。
worktreeでの作業が完了したあと、元の場所へ差分を戻す段になってstash popが競合しました。
手順はこうです。
元のツリーでgit stash push -u、git merge main、git stash pop。
競合したのはsession.tsとExploreScene.tsで、どちらもcodexが大きく分割・再構成したファイルでした。
stashが保存しているのは「古い構造に対する差分」です。main側の構造が大きく変わっていると、その差分を戻す先がなくなります。stash popが競合するのは当然でした4。
解消の方針はシンプルで、Updated upstream(新しい構造)をベースにして、Stashed changesから本当に必要な差分だけ拾います5。
旧実装をそのまま復元しようとすると分割が壊れるので、それは避けます。
3. 何が良くて何がコストだったか
良かったのは、元のツリーを汚さずにリファクタを進められたことと、codexがmain上でコミットを積んでいる間に自分も別の作業を進められたことです。git checkoutで切り替えながら作業する方法に比べると、ミスの余地が減ります。
コストとして残るのは、「元の未コミット差分を新しいmainに載せ直す」という統合作業です。
これはworktreeを使っても消えません。物理的に分離できても、同じファイルに対する変更を最終的にどうマージするかは人間が判断しなければいけません6。
4. 次回やるとしたら
worktreeで大きな作業に入る前に、元の未コミット差分が大きければstashではなくWIPコミットとして退避しておきます。
stashは「一時的な退避」に見えますが、大規模なリファクタを挟むと戻しにくい。ブランチとして残しておく方が、後でdiffを確認しながら取り込みやすいです7。
終了処理の順序は先に決めます。
codexの作業が終わったら、まず終了スクリプトを走らせて成功を確認し、それからworktreeを削除する。
並列で動かすこと自体は有効でした。
詰まったのは終わらせ方の設計を後回しにしていたからで、次は開始前に「どう片付けるか」まで決めてから動かします。
- git worktreeはGit 2.5(2015年)で正式公開された機能で、1つのリポジトリから複数の作業ディレクトリを作り、それぞれで別のブランチを同時に操作できます。
git checkoutによる切り替えと違い、ファイルシステム上に独立したディレクトリが並ぶため、ブランチ切り替え事故がなくなります。 – 徹底解説:git worktree の使い方 - Anthropic公式ドキュメントでも、git worktreeによる並列セッション運用は「the single biggest productivity unlock(単一最大の生産性向上)」と位置づけられています。長時間タスクの場合、1つのworktreeでAIが作業している間に別のworktreeで開発を続行できる点が主なメリットとして挙げられています。 – 一般的なワークフロー – Claude Code Docs
- worktreeの削除には必ず
git worktree remove <パス>を使います。rm -rfでディレクトリを直接消すと、.git/worktrees/以下の管理情報が残ったままになり、リポジトリの整合性が壊れる可能性があります。残ってしまった場合はgit worktree pruneで不要なエントリを掃除できます。 – git worktreeを使ってみる git stash popでコンフリクトが起きてもstashは削除されずに残ります(git stash applyと同じ挙動になります)。そのためgit stash listで確認すれば、退避した内容は取り戻せます。焦ってgit reset --hardをかける前に、まずstashの中身を確認するとよいです。 – git stash popがconflictしたとき- コンフリクトが起きたファイルには
<<<<<<< Updated upstream(現在のコミット側)、=======(区切り)、>>>>>>> Stashed changes(stashの内容)という3つのマーカーが入ります。大規模リファクタ後はUpdated upstreamが正しい新構造なので、これを残してStashed changesから必要な箇所だけ手動で取り込みます。 – git stash popでコンフリクトした時の解決方法 - worktreeを使って並列でAIエージェントと人間が作業する場合でも、「同じファイルに対して別々の変更を加えた」という状況は最後に必ず統合コストとして現れます。worktreeはファイルシステム上の物理分離には強いですが、意味的な変更の衝突を解消する仕組みは持っていません。 – Git Worktrees: The Secret Weapon for Running Multiple AI Coding Agents in Parallel
git stash popの代わりにgit stash applyを使うと、適用後もstashのエントリが削除されずに残ります。コンフリクトが起きて解消しながら適用したい場合はapplyの方が安全で、必要な差分を取り込んだ後に手動でgit stash dropする運用が確実です。 – 変更を一時的に退避しよう!git stashを使いこなす5つのステップ