Magit で Git Worktree を使う
Working with Git Worktrees in Magit (emacsredux.com)
要約
この記事では、Gitのworktree機能と、それをEmacsのMagitエディタでどのように活用するかを解説しています。worktreeは、同じリポジトリに対して複数の作業ディレクトリを持つことを可能にし、AIコーディングエージェントの利用や、ブランチ間の切り替えに伴うビルド状態の差異による手間を省くのに役立ちます。Magitはworktreeをシームレスにサポートしており、特別な学習なしに各worktreeで独立した操作が可能です。
全文翻訳
Magit で Git Worktrees を使う
正直に言うと、最近まで Git worktrees が存在することを知りませんでした。それらは10年間 Git に搭載されていた[1]にもかかわらず、一度も必要としませんでした。フィーチャーブランチで十分だったのです。ブランチを作成し、作業を行い、マージし、削除して、また最初から始めます。
worktrees を知るきっかけとなったのは、何と AI コーディングエージェントでした。Claude Code のようなツールは、タスクごとに worktree を作成するため、複数のエージェント(または同じエージェントの複数のセッション)が互いに、あるいはあなたに干渉することなく、同時に同じリポジトリで作業できます。突然、私のプロジェクトディレクトリは cider-this や cider-that のような兄弟ディレクトリでいっぱいになり、実際に何が起こっているのか理解する必要があると思いました。
Worktrees vs ブランチ
ブランチはコミットへの移動可能なポインタに過ぎず、作成は基本的に無料です。しかし、リポジトリは単一のワーキングディレクトリしか持たないため、2つのブランチで作業するには、そのディレクトリを前後に切り替える必要があります。おなじみの手順です。半端な作業をスタッシュ(またはコミット)し、別のブランチをチェックアウトし、作業を行い、最初のブランチを再度チェックアウトし、アンスタッシュします。これは機能しますが、退屈であり、2つのブランチがプロジェクトを異なるビルド状態にする場合、切り替えごとに世界の半分を再コンパイルする必要が生じ、さらに悪化します。
worktree は、同じリポジトリにアタッチされた追加のワーキングディレクトリを提供します。
$ git worktree add ../cider-smart-targeting -b smart-form-targeting
これで ~/projects/cider-smart-targeting はそのブランチの完全なチェックアウトとなり、メインのチェックアウトは元の場所にそのまま残ります。オブジェクトデータベース、refs、スタッシュ、リモートはすべて共有されます。worktree はクローンではないため、1つでフェッチすればすべてでフェッチされ、作成はほぼ瞬時です。各 worktree は独自の HEAD とインデックスを持ち、Git は1つの単純なルールを強制します。それは、1つのブランチは一度に1つの worktree でしかチェックアウトできないということです。
いつ使う価値があるのでしょうか?同時に2つのことを行う必要があるときです。一方のブランチで長時間テストを実行しながらもう一方のブランチで作業する、半端な作業を邪魔せずに PR をレビューする、あるいは最近皆が話題にしている理由である AI エージェントが孤立した状態で作業を行う場合です。その代償は非常にわずかです。ワーキングファイルはディスク上に複数存在し、Git で追跡されないもの(依存関係、ビルドキャッシュ、node_modules など)は、各 worktree で再設定する必要があります。
もしブランチがあなたにとって制限になったことがないなら、それはそれで構いません。私も10年以上そうでした。worktrees は、ワークフローが変わるまで必要性を感じない機能の1つです。
Jujutsu については?
作業コピーの話が出たついでに、現在バージョン管理で最も興味深いのは Jujutsu (jj) です。これは Git 互換の VCS で、worktrees が解決する問題をほとんど不要にします。jj では、ワーキングコピーはコミットであり、作業中に自動的にスナップショットが取られます。ステージングエリアもスタッシュもありません。なぜなら、失われたり邪魔になったりする可能性のある未コミットの状態がないからです。コンテキストの切り替えは常に安全です。また、並列ワーキングディレクトリ(jj workspace)の適切なサポートと、事実上すべてを元に戻せる操作ログも備えています。最後の点は、AI エージェントの群衆がこれに興味を持っている理由の一部でもあります。
既存の Git リポジトリの上に jj を使用できます(これをコロケーションリポジトリと呼びます)。同僚や Magit は、通常の Git リポジトリとして認識し続けます。私はまだ観察者ですが、これは明らかに注目すべきプロジェクトです。
Emacs の世界に戻りましょう。Magit は長年 worktree サポートを備えており、Z の下に隠されています。
| キー | コマンド |
|---|---|
Z b | magit-worktree-checkout |
Z c | magit-worktree-branch |
Z g | magit-worktree-status |
Z m | magit-worktree-move |
Z k | magit-worktree-delete |
最も良い点は、他に学ぶべきことがないことです。各 worktree は独自の Magit ステータスバッファを持ち、すべての Magit コマンドは現在のバッファが属する worktree に対して操作されます。Z g は必要な唯一の切り替えメカニズムであり、それすらも別のステータスバッファを訪問するためのショートカットに過ぎません。
私の(明らかに最近の)経験からの実用的なヒントをいくつか紹介します。
- デフォルトでは、ステータスバッファは worktree を一覧表示しません。これを修正するには、以下のようにします。
(magit-add-section-hook 'magit-status-sections-hook
#'magit-insert-worktrees
nil t)
これで、すべてのステータスバッファがリポジトリのすべての worktree を表示し、いずれかの上に RET を押すとそこにジャンプできます。
-
worktree は、メインのチェックアウトの 兄弟 として、ネストするのではなく、説明的な名前(
ciderの隣のcider-smart-targeting)で作成します。ネストはgrep、find、その他の多くのツールを混乱させます。 -
Magit のブランチ選択は、別の worktree でチェックアウトされているブランチに worktree のパスを付記し、再度チェックアウトすることを拒否します(これは Git のルールであり、Magit が意地悪をしているわけではありません)。ブランチが「チェックアウトできない」理由を不思議に思ったことがあるなら、それが原因であることがほとんどです。
-
各 worktree は、
project.el(または Projectile)にとって独自のプロジェクトであるため、プロジェクトの切り替え、プロジェクトごとのバッファ、検索などが自然に機能します。 -
Git で追跡されていないものは何も一緒に運ばれません。依存関係は worktree ごとに一度インストールする必要があり、ビルドキャッシュは空の状態から開始する必要があります。Elisp ではコストはかかりませんが、大規模な JVM または JS プロジェクトでは、このアプローチ全体の主な欠点です。
-
worktree が不要になったら、
Z k(またはコマンドラインでgit worktree remove)で削除します。手動でディレクトリを削除した場合、git worktree pruneで残ったブックキーピングをクリーンアップします。
締めくくり
最近、エージェントとのワークフローは通常次のようになります。エージェントが worktree で作業を行い、私は Magit でそこで変更を確認します(しばしば、別のタスクが2番目の worktree で実行されている間)、そしてブランチがマージされると worktree は削除されます。おそらく、いつか worktrees の他の用途を見つけるでしょう。どうなるか見てみましょう。
あなたは Git worktrees を使用していますか?そして、私と同じような回り道でそれらを発見しましたか?コメントでぜひ聞かせてください!
今日はここまでです。並列でコーディングを続けてください!
- これらは 2015 年 7 月にリリースされた Git 2.5 で導入されました。↩