複数ブランチ作業の救世主!Git Worktreeのメリットと活用事例

はい、承知いたしました。Git Worktreeのメリットと活用事例に焦点を当て、約5000語の詳細な記事を執筆します。記事の内容を直接表示します。


複数ブランチ作業の救世主!Git Worktreeのメリットと活用事例

序章:エンジニアを悩ませる「割り込み作業」と「複数タスク」

ソフトウェア開発の現場では、一つのタスクに集中して取り組める時間は限られています。特に、ある機能の開発中に緊急度の高いバグ修正依頼が入ったり、別のチームからの簡単な技術調査やレビュー依頼が舞い込んだりすることは日常茶飯事です。また、長期的な大型改修を進めながら、並行して短期的な機能改善も行わなければならないといった状況も頻繁に発生します。

このような状況で、多くのエンジニアが直面するのが「ブランチの切り替え」に関する悩みです。Gitを使って開発を進める上で、ブランチは非常に重要な概念であり、機能開発やバグ修正といった各タスクは通常、独立したブランチ上で進行します。しかし、タスクが切り替わるたびにブランチを切り替える作業は、思った以上に手間と時間を要します。

例えば、feature/Aブランチで開発を進めている最中に、bugfix/Bブランチでのバグ修正依頼が入ったとします。

  1. feature/Aブランチでの未コミットの変更をどうするか? git stashで一時保存するか、あるいは中途半端な状態でも一旦コミットしてしまうか。
  2. bugfix/Bブランチにgit checkoutで切り替える。
  3. バグ修正作業を行う。
  4. 修正が完了したらコミットし、リモートにプッシュするなど、必要な作業を行う。
  5. 元のfeature/Aブランチに戻るためにgit checkout feature/Aを実行する。
  6. もしgit stashを使っていた場合は、git stash applyなどで変更を元に戻す。

この一連の作業は、たとえ数分で終わる簡単な作業であっても、思考の中断や作業状態のリロード(IDEやターミナルのウィンドウを切り替える、コンパイルし直すなど)を伴い、開発効率を著しく低下させます。特に、大規模なプロジェクトや、コンパイル・ビルドに時間がかかるプロジェクトでは、ブランチ切り替えに伴う待ち時間が無視できません。さらに、git checkoutはワーキングツリーとインデックスを対象ブランチの状態に完全に一致させる操作であるため、大量のファイルが変更される場合や、大きなバイナリファイルが含まれる場合には、その処理自体にも時間がかかります。

また、git stashは便利な機能ですが、複数の変更をスタッシュしたり、特定のスタッシュだけを適用したりする際には、管理が煩雑になりがちです。「このスタッシュは何の変更だったっけ?」と迷うことも少なくありません。未コミットの変更がある状態でうっかりブランチを切り替えようとして、「Your local changes would be overwritten by checkout…」といったエラーメッセージに遭遇し、作業がブロックされるといった経験は、多くのGitユーザーにあるのではないでしょうか。

このような、複数のブランチ間を頻繁に行き来する必要がある開発ワークフローにおいて、従来のcheckoutstashに依存した手法は、開発者の集中力を削ぎ、生産性を低下させる大きな要因となっていました。

ここに救世主として登場するのが、GitのWorktree機能です。

Git Worktreeとは何か?基本的な概念

Git Worktreeは、一つのGitリポジトリに対して、複数の「作業ツリー(working tree)」を作成できる機能です。

通常、一つのGitリポジトリは、.gitという隠しディレクトリと、それ以外のワーキングツリー(作業ディレクトリ)で構成されています。ワーキングツリーには、リポジトリで管理されているファイル群の特定の時点(通常は現在のブランチのHEADが指すコミット)の状態が展開されています。そして、このワーキングツリーに対してファイル編集を行い、その変更をインデックス(ステージングエリア)に登録し、コミットするというサイクルで開発を進めます。

Git Worktree機能を使うと、このワーキングツリーをメインの作業ディレクトリとは別に、別のディレクトリに複数作成することができます。そして、それぞれの追加された作業ツリーは、メインリポジトリとは異なるブランチをチェックアウトすることができます。

例えるなら、

  • 従来のGit: 一つの机(リポジトリ)の上で、資料Aを見ながら作業している。資料Bについて考えたいときは、資料Aを脇にどけて(stash)、資料Bを取り出してくる(checkout)。
  • Git Worktree: 一つの本棚(リポジトリ)に資料が全て保管されている。机が複数あり、机Aでは資料Aを開いて作業し、机Bでは資料Bを開いて作業できる。机Aと机Bは完全に独立しており、必要に応じて机間を移動するだけ。

このように、Git Worktreeを使用すると、物理的に異なる複数のディレクトリで、同じリポジトリ内の異なるブランチを同時に開いて作業できるようになります。各Worktreeは完全に独立した作業環境を提供するため、それぞれのディレクトリで個別のターミナルを開き、個別のIDEでコードを編集し、個別のビルドやテストを実行することができます。

Git Worktreeが登場するまでの課題(なぜWorktreeが必要だったか)

Git Worktreeが導入される前、複数のブランチを同時に扱いたい場合、開発者はいくつかの選択肢しかありませんでした。

  1. git stashgit checkoutを駆使する:

    • 最も一般的な方法。前述の通り、未コミットの変更をスタッシュし、ブランチを切り替え、作業を行い、ブランチを戻し、スタッシュを適用するという手間がかかる。
    • スタッシュの管理が煩雑になりやすい。
    • ブランチ切り替え自体に時間がかかる場合がある。
    • 異なるブランチで動作確認が必要な場合、都度ビルドし直す必要がある。
  2. リポジトリ全体を複数クローンする:

    • 最も原始的な方法。同じリポジトリを複数のディレクトリにクローンし、それぞれのクローンで異なるブランチをチェックアウトする。
    • ローカルディスク容量を大量に消費する(リポジトリのサイズが大きければ、クローン数に比例して必要な容量が増える)。
    • 複数のクローン間でコミットやブランチ情報を共有するには、都度git fetchgit pullgit pushなどのリモート操作が必要になり、面倒。または、ローカルファイルシステム上のパスを指定してリモート登録するといったテクニックが必要になるが、これも設定が煩雑。
    • 全体的な管理が煩雑になりやすい(どのディレクトリがどのクローンで、どのブランチを見ているのかなど)。
  3. IDEやツールに依存した機能を使う:

    • 一部の高度なIDEは、複数のブランチの状態を同時に表示したり、切り替えをスムーズに行うための機能を提供している場合がある。
    • ただし、これはIDEの機能に依存するため、汎用性が低い。また、IDEの機能も内部的にはcheckoutなどのGitコマンドを実行していることが多く、基本的な課題(ファイルコピーの手間など)は解決しない場合がある。

これらの従来の選択肢には、いずれも利便性や効率性の面で課題がありました。Worktreeは、これらの課題、特に「迅速かつシームレスなブランチ間の切り替えと同時作業」を実現するために考案された機能と言えます。リポジトリ全体をクローンするよりもディスク容量の消費を抑えつつ(オブジェクトストアは共有されるため)、checkoutによる待ち時間やstashの煩雑さから解放されることを目指しています。

Git Worktreeの仕組み(内部構造)

Git Worktreeがどのように機能するかを理解するには、Gitリポジトリの内部構造を少し知る必要があります。

基本的なGitリポジトリは、以下の要素から構成されます。

  • オブジェクトストア (.git/objects): コミットオブジェクト、ツリーオブジェクト、ブロブオブジェクト(ファイルの内容)、タグオブジェクトといった、リポジトリ内のすべての履歴データが格納されます。これはリポジトリの中核であり、不変のデータが格納されています。
  • 参照 (.git/refs): ブランチやタグといった、特定のコミットを指す名前付きのポインタが格納されます(例: refs/heads/main, refs/tags/v1.0)。
  • HEAD (.git/HEAD): 現在チェックアウトされているブランチやコミットを指すポインタです。通常はブランチを指します(例: ref: refs/heads/feature/A)。
  • インデックス (.git/index): 次のコミットに含まれる予定のファイルと、その時点でのファイル内容(オブジェクトストア内のブロブへのポインタ)を記録したステージングエリアです。
  • コンフィグレーション (.git/config): リポジトリ固有の設定(リモートリポジトリ情報、ユーザー名など)が格納されます。
  • ワーキングツリー(Working Tree): .gitディレクトリ以外の、実際にファイルが展開されているディレクトリです。ここでファイルを編集します。

従来の単一ワーキングツリーの場合、これらの要素はすべて.gitディレクトリとその親ディレクトリ(ワーキングツリー)の中に閉じ込められています。

Git Worktreeを追加すると、この構造が少し変わります。

メインのリポジトリディレクトリ(例: ~/project)には、引き続きメインの.gitディレクトリが存在します。これはリポジトリの中核であり、オブジェクトストア(.git/objects)や.git/refsなど、共有されるべきデータが含まれています。

追加のWorktreeを作成するディレクトリ(例: ~/project_bugfix)には、完全な.gitディレクトリは作成されません。代わりに、そのディレクトリのルートに.gitという名前のファイルが作成されます。この.gitファイルは、実際のGitリポジトリデータが格納されているメインの.gitディレクトリへのパスを記録しています。

“`

~/project_bugfix/.git の内容例

gitdir: /home/user/project/.git/worktrees/project_bugfix
“`

そして、メインのリポジトリの.gitディレクトリ内には、worktreesという新しいディレクトリが作成されます。このworktreesディレクトリの中に、追加された各Worktreeに対応するサブディレクトリ(例: worktrees/project_bugfix)が作成されます。

各Worktreeに対応するサブディレクトリ(例: ~/project/.git/worktrees/project_bugfix)の中には、そのWorktree固有のデータが格納されます。これには以下が含まれます。

  • HEAD: そのWorktreeが現在チェックアウトしているブランチやコミットを指します。
  • index: そのWorktree固有のステージングエリアです。
  • logs/HEAD: そのWorktreeでのHEADの移動履歴(reflog)です。
  • config: そのWorktree固有の設定(ほとんどの場合、メインリポジトリの設定を継承しますが、必要に応じて上書きできます)。
  • commondir: メインリポジトリの.gitディレクトリへのパスを記録したファイル。

つまり、追加されたWorktreeは、独自のHEAD、インデックス、ワーキングツリーを持ちますが、オブジェクトストア(.git/objects)や多くの設定データはメインリポジトリと共有しています。これにより、リポジトリ全体を複数クローンする場合に比べて、ディスク容量の消費を大幅に抑えることができます。ファイルの実体(ブロブオブジェクト)はメインの.git/objectsに一つだけ存在し、各Worktreeは必要に応じてそれを参照してワーキングツリーに展開します。

この仕組みにより、各Worktreeは互いに独立したブランチで作業できる環境を持ちながら、リポジトリの履歴データやオブジェクトは効率的に共有されるという理想的な状態が実現されています。

Git Worktreeの圧倒的なメリット

Git Worktreeを開発ワークフローに導入することで、従来の課題が解決され、さまざまなメリットを享受できます。

  1. 驚くほど高速なブランチ切り替え

    • 従来のgit checkout <branch>は、現在のワーキングツリーの状態を保存し、対象ブランチのコミットに対応するファイル群をディスクに展開し直すという、ファイル操作を伴う処理です。ファイルの数が多かったり、大きなファイルが含まれていたりすると、この処理には時間がかかります。
    • Worktreeを使用する場合、それぞれのWorktreeは独立したディレクトリに存在するため、ブランチを切り替えるのではなく、ディレクトリを移動するだけで済みます。例えば、cd ../project_bugfixのようにファイルシステム上のパスを移動するだけで、別のブランチの作業環境に瞬時に切り替えることができます。これは、まさに「机を移動する」感覚であり、Gitコマンドによる待ち時間がほとんどありません。
    • これにより、短い割り込み作業や、複数のタスク間を行き来する際のストレスが激減します。
  2. コンテキストスイッチのコスト削減

    • ブランチを切り替えるだけでなく、それに伴うコンテキストスイッチ(思考の切り替え、作業環境の再構築)も開発効率を大きく左右します。
    • Worktreeを使えば、~/projectディレクトリでメインの開発を行い、~/project_bugfixディレクトリでバグ修正を行うというように、それぞれ独立したディレクトリで作業できます。これにより、それぞれのWorktreeに対して個別のターミナルウィンドウやIDEインスタンスを開くことができます。
    • メインのWorktreeでは機能開発に関するファイルを開き、バグ修正用のWorktreeではバグに関連するファイルを開いておくことができます。それぞれのIDEは独立して動作するため、シンボリックリンクの解決、依存関係の解決、コンパイル状態なども各Worktreeの状態に合わせて維持されます。
    • ある作業中に別の作業に移る場合、単に別のターミナルウィンドウやIDEウィンドウに切り替えるだけでよく、元の作業状態(開いているファイル、ターミナルのコマンド履歴、IDEのビルド状態など)はそのまま保たれます。これは、checkoutstashでは得られない大きな利点であり、思考の中断を最小限に抑え、コンテキストスイッチに伴う認知的負荷を大幅に軽減します。
  3. 複数タスクの同時進行が容易に

    • 最も典型的なWorktreeの活用シーンです。機能Aの開発(feature/Aブランチ)を進めている最中に、緊急性の高い機能Bの開発(feature/Bブランチ)に着手する必要が生じたとします。
    • 従来のやり方では、feature/Aの作業を一旦中断し、stashして、feature/Bcheckoutして作業し、完了したら戻る、という流れになります。
    • Worktreeを使えば、~/projectディレクトリでfeature/Aブランチを開いたまま、git worktree add ../project_feature_B feature/Bを実行し、~/project_feature_Bディレクトリに移ってfeature/Bの開発を開始できます。両方の作業を完全に並行して進めることが可能です。必要に応じて、両方のディレクトリでそれぞれビルドやテストを実行することもできます。
  4. 実験的ブランチや調査用ブランチの管理が容易

    • 「ちょっとこのブランチのあのコミットの状態を確認したい」「大規模なリファクタリングを別のブランチで試してみたい」といった場合に、メインの開発ブランチを汚したり、現在の作業状態を退避させたりすることなく、独立したWorktreeを作成して作業できます。
    • 例えば、あるコミット時点のコードの状態を調査したい場合、git worktree add ../project_old_version <commit-hash>のようにコミットハッシュを指定してWorktreeを作成できます。そのWorktreeでは、指定したコミット時点のファイル群が展開されるため、簡単に過去のコードを調査したり、そこでデバッグを実行したりできます。
    • 新しい技術やライブラリを試す、大胆な設計変更を実験するなど、メインの開発ラインから完全に切り離して作業したい場合に非常に便利です。不要になったらディレクトリごと削除し、git worktree pruneを実行するだけで後片付けも簡単です。
  5. ディスク容量の効率的な利用(完全なクローンと比較して)

    • 前述の仕組みの通り、追加されたWorktreeはオブジェクトストアをメインリポジトリと共有するため、リポジトリ全体を何度もクローンするよりもディスク容量の消費を抑えることができます。特に、Git LFSなどで管理される大きなバイナリファイルが多いリポジトリでは、この差が顕著になります。
  6. レビュー作業の効率化

    • 他の開発者からのプルリクエストをレビューする際、提案されている変更をローカルで確認したい場合があります。その場合、通常はリモートブランチをフェッチし、新しいローカルブランチを作成してそのコミットをチェックアウトするという手順を踏みます。
    • Worktreeを使えば、現在作業中のブランチから離れることなく、git worktree add ../project_review <remote-branch-name>のようにして、レビューしたいブランチ専用のWorktreeを簡単に作成できます。そのWorktreeでコードを確認したり、動作テストを行ったりできます。レビューが終わったら、そのWorktreeディレクトリを削除するだけで済みます。

Git Worktreeの基本的な使い方

Git Worktreeの使い方は非常にシンプルです。

1. 新しいWorktreeを追加する

新しいWorktreeを作成し、新しいブランチを同時に作成してチェックアウトする場合:

bash
git worktree add <path/to/new/worktree> -b <new-branch-name>

例: 現在のmainブランチでの作業を続けながら、feature/Aという新しいブランチで作業を開始したい場合。~/projectがメインリポジトリの場所だとすると、~/project_feature_Aというディレクトリに新しいWorktreeを作成できます。

“`bash

現在のディレクトリは ~/project

git worktree add ../project_feature_A -b feature/A
“`

このコマンドを実行すると、以下の処理が行われます。

  • ../project_feature_Aというディレクトリが作成されます。
  • メインリポジトリの.gitディレクトリ内に、このWorktreeに関する情報が記録されます(例: ~/project/.git/worktrees/project_feature_A)。
  • feature/Aという新しいブランチが作成され、現在のHEAD(通常はmain)のコミットが指されます。
  • 新しく作成された../project_feature_Aディレクトリに、feature/AブランチのHEADが指すコミットの状態が展開されます。
  • ../project_feature_Aディレクトリには、メインリポジトリの.gitディレクトリを指す.gitファイルが作成されます。

既存のブランチをチェックアウトしたWorktreeを追加する場合:

bash
git worktree add <path/to/new/worktree> <existing-branch-name>

例: bugfix/Bという既存のブランチで緊急作業を行うためにWorktreeを作成する場合。

“`bash

現在のディレクトリは ~/project

git worktree add ../project_bugfix bugfix/B
“`

このコマンドを実行すると、../project_bugfixディレクトリが作成され、そこにbugfix/BブランチのHEADが指すコミットの状態が展開されます。

特定のコミットをチェックアウトしたWorktreeを追加する場合:

bash
git worktree add <path/to/new/worktree> <commit-hash>

例: 過去の特定のコミット(例: a1b2c3d4)の状態を確認したい場合。

“`bash

現在のディレクトリは ~/project

git worktree add ../project_history a1b2c3d4
“`

重要な注意点:

  • 追加したWorktreeのパスは、メインリポジトリのディレクトリの外部である必要があります。メインリポジトリのサブディレクトリ内にはWorktreeを作成できません。これは、GitがWorktreeを独立した作業環境として扱うためです。一般的な慣習としては、メインリポジトリと同じ階層か、あるいは専用のWorktree用ディレクトリを作成してその中に配置します。
  • 追加するWorktreeのディレクトリは、存在しない必要があります。コマンド実行時に自動的に作成されます。
  • デフォルトでは、追加されたWorktreeはそのWorktree専用のブランチを「借用」します。つまり、同じブランチを複数のWorktreeで同時にチェックアウトすることはできません(後述する注意点)。

2. Worktreeの一覧を表示する

現在アクティブなWorktreeの一覧を確認するには、メインリポジトリのディレクトリ(またはそのWorktreeのディレクトリ)で以下のコマンドを実行します。

bash
git worktree list

出力例:

/home/user/project a1b2c3d4 [main]
/home/user/project_feature_A 5f6e7d8c [feature/A]
/home/user/project_bugfix 9h0i1j2k [bugfix/B]

この出力は、Worktreeのパス、現在のHEADのコミットハッシュ、チェックアウトしているブランチ名を示しています。先頭のパスがメインリポジトリ(”main/bare”と表示されることもあります)です。

3. Worktreeを削除する

不要になったWorktreeを削除するには、そのWorktreeのディレクトリを削除し、GitにそのWorktreeの情報を取り除くように伝えます。

まず、削除したいWorktreeのディレクトリ(例: ../project_feature_A)から移動します。削除対象のWorktreeディレクトリ内にいる状態では削除できません。

次に、メインリポジトリのディレクトリに戻るか、別のWorktreeディレクトリから、以下のコマンドを実行します。

bash
git worktree remove <path/to/worktree/to/remove>

例: ../project_feature_Aを削除する場合。

“`bash

現在のディレクトリは ~/project または ~/project_bugfix など

git worktree remove ../project_feature_A
“`

このコマンドは、指定されたWorktreeディレクトリが存在し、かつそこで作業中のファイルがない(コミットされていない変更がない)場合に成功します。もし変更がある場合はエラーになります。強制的に削除したい場合は、-fオプションを付けます。

bash
git worktree remove -f ../project_feature_A

-fオプションは、未コミットの変更や未プッシュのコミットがあっても強制的にWorktreeを削除しますが、そのWorktreeで行った作業は失われる可能性があるため、使用には注意が必要です。通常は、Worktree内で全ての変更をコミットまたはスタッシュし、ブランチをリモートにプッシュするなどしてから削除するのが安全です。

4. 使われていないWorktree情報を整理する

Worktreeディレクトリをファイルシステム上で直接削除してしまった場合など、Gitの内部情報と実際のディレクトリの状態が不整合になることがあります。このような場合に、GitのWorktreeリストから存在しないWorktreeの情報を削除し、整理するために以下のコマンドを使用します。

bash
git worktree prune

このコマンドは、指定されたパスにディレクトリが存在しないWorktreeの情報を削除します。定期的に実行することで、GitのWorktree管理情報をクリーンに保つことができます。

Git Worktreeの応用的な使い方・活用事例

Worktreeの基本的な使い方が分かったところで、具体的な活用事例を見ていきましょう。Worktreeはさまざまな開発シナリオで真価を発揮します。

活用事例 1:複数機能開発の同時進行

  • シナリオ: あなたは現在、新しい顧客管理システムの一機能(feature/crm-contactsブランチ)を開発中です。そこに、経営層から別の重要機能(feature/dashboard-widgetsブランチ)を今すぐ着手してほしいという依頼が入りました。
  • Worktreeなし: feature/crm-contactsでの作業を中断。未コミットの変更をスタッシュし、feature/dashboard-widgetsブランチに切り替え、新しい作業を開始。feature/dashboard-widgetsの作業中に、feature/crm-contactsについて何か確認したいことが発生したら、再びスタッシュ&チェックアウトでブランチを行き来する。非常に非効率。
  • Worktreeあり:
    1. 現在のディレクトリ(例: ~/project)でfeature/crm-contactsブランチでの作業を続けます。
    2. 新しいWorktreeを、feature/dashboard-widgetsブランチをチェックアウトして作成します:
      bash
      git worktree add ../project_dashboard feature/dashboard-widgets
    3. cd ../project_dashboardで新しいWorktreeディレクトリに移動し、別のターミナルウィンドウを開いてfeature/dashboard-widgetsの開発を開始します。
    4. ~/projectのターミナルではfeature/crm-contactsの開発を続け、~/project_dashboardのターミナルではfeature/dashboard-widgetsの開発を進めます。
    5. 両方の作業を独立して行えるため、コンテキストスイッチのコストが最小限に抑えられます。それぞれのWorktreeで個別のビルドやテストを実行できます。
    6. 必要に応じて、両方のディレクトリのウィンドウを切り替えながら作業を進めます。

活用事例 2:緊急バグ修正と並行した開発

  • シナリオ: あなたは安定版ブランチ(release/v1.0)をベースにした新機能開発(feature/awesome)を進めています。本番環境で深刻なバグが見つかり、すぐに修正版をリリースする必要が生じました。バグ修正は安定版ブランチに対して行い、その後、修正を新機能開発ブランチにもマージする必要があります。
  • Worktreeなし: feature/awesomeでの作業を中断。未コミットの変更をスタッシュし、release/v1.0ブランチに切り替え、バグ修正を行います。修正をコミット、タグ付け、リリース作業などを行います。その後、feature/awesomeに戻り、release/v1.0の修正をマージします。
  • Worktreeあり:
    1. ~/projectディレクトリでfeature/awesomeブランチでの作業を続けます。
    2. バグ修正用のWorktreeをrelease/v1.0ブランチをチェックアウトして作成します:
      bash
      git worktree add ../project_hotfix release/v1.0
    3. cd ../project_hotfixでバグ修正用Worktreeに移動し、バグ修正作業を開始します。
    4. バグ修正が完了したら、project_hotfixディレクトリでコミットし、リモートにプッシュします。必要に応じてタグ付けなども行います。
    5. バグ修正が完了し、release/v1.0にマージされたら、~/projectディレクトリに戻り、release/v1.0ブランチの最新の状態をfeature/awesomeブランチにマージします。
      bash
      # ~/project ディレクトリにて
      git fetch origin
      git merge origin/release/v1.0
    6. バグ修正用のWorktree(../project_hotfix)は不要になったら削除します。

活用事例 3:過去バージョンの調査・デバッグ

  • シナリオ: ユーザーから、以前のバージョン(例: 2ヶ月前のリリースに相当する特定のコミットa1b2c3d4)で発生するバグについて報告がありました。現在の開発中のコードでは再現せず、過去のコードを実際に動かして調査する必要があります。
  • Worktreeなし: 現在の作業をスタッシュし、対象のコミットをcheckoutします。過去のコードベースで必要な環境構築(ライブラリのインストール、設定ファイルの調整など)を行います。調査が終わったら、元のブランチに戻るために再びcheckoutし、スタッシュを適用します。過去のバージョンと現在のバージョンのコードを見比べる必要がある場合、非常に手間がかかります。
  • Worktreeあり:
    1. 現在のディレクトリ(例: ~/project)でメイン開発を続けます。
    2. 調査用のWorktreeを、対象のコミットをチェックアウトして作成します:
      bash
      git worktree add ../project_old_bug_investigation a1b2c3d4
    3. cd ../project_old_bug_investigationで調査用Worktreeに移動し、過去のコードベースを展開します。
    4. このWorktree内で必要な環境構築を行い、バグの再現やデバッグを行います。
    5. 別のターミナルウィンドウで現在のコード(~/project)を開き、過去のコードと現在のコードを簡単に見比べながら調査を進めることができます。
    6. 調査が完了したら、調査用Worktree(../project_old_bug_investigation)は削除します。

活用事例 4:ドキュメント作成とコード開発の分離

  • シナリオ: あなたは新しいAPI機能を開発しており(feature/new-apiブランチ)、同時にそのAPIの技術ドキュメントも更新する必要があります。ドキュメントは別のブランチ(docs/api-updateブランチ)で管理されています。
  • Worktreeなし: コード開発中にドキュメントを更新したい場合、コードの作業を中断してドキュメントブランチに切り替え、ドキュメントを編集し、またコードブランチに戻るという手順が必要になります。
  • Worktreeあり:
    1. ~/projectディレクトリでfeature/new-apiブランチでのコード開発を続けます。
    2. ドキュメント更新用のWorktreeを、docs/api-updateブランチをチェックアウトして作成します:
      bash
      git worktree add ../project_docs docs/api-update
    3. cd ../project_docsでドキュメント用Worktreeに移動し、別のターミナルやエディタでドキュメント編集を開始します。
    4. コードとドキュメントの両方を同時に開いて作業できるため、効率的に進めることができます。コードの変更を反映してすぐにドキュメントを更新するといった作業がスムーズに行えます。

活用事例 5:プルリクエストのレビュー作業

  • シナリオ: チームメイトからプルリクエストが送られてきました。変更内容をローカルで確認し、動作テストを行いたいと考えています。
  • Worktreeなし: リモートブランチをフェッチし、それを元にローカルブランチを作成し、チェックアウトします。確認が終わったら、元のブランチに戻り、レビュー用に作成したローカルブランチを削除します。
  • Worktreeあり:
    1. 現在のディレクトリ(例: ~/project)でメイン開発を続けます。
    2. レビュー用のWorktreeを、対象のリモートブランチをチェックアウトして作成します:
      bash
      git worktree add ../project_review origin/feature/team-member-branch
    3. cd ../project_reviewでレビュー用Worktreeに移動し、提案されたコードを確認したり、ローカルでビルド・テストを実行したりします。
    4. レビューが完了したら、レビュー用Worktree(../project_review)は削除します。メイン開発ブランチの状態に一切影響を与えずにレビュー作業が完結します。

活用事例 6:CI/CDパイプラインでの活用(高度なケース)

  • シナリオ: 一つのリポジトリで、異なるバージョンのライブラリやフレームワークを使い分けながら、複数の製品やプロジェクトを管理している。CI/CDパイプラインで、各製品/プロジェクトに対応するブランチやタグを元に、独立したビルドやテストを実行したい。
  • Worktreeなし: CI環境でリポジトリを複数回クローンするか、都度ブランチを切り替えてビルド・テストを実行する必要がある。クローンは非効率、ブランチ切り替えはCIの並列実行を妨げる可能性がある。
  • Worktreeあり: CI環境で一度リポジトリをクローンし、そこから必要なブランチ/タグごとにWorktreeを作成して、各Worktree内で並列にビルド・テストを実行する。オブジェクトストアを共有するためクローンより効率的で、ブランチ切り替えのオーバーヘッドもないため並列化しやすい。ただし、CI/CDツールがWorktreeの概念を直接サポートしているわけではない場合、スクリプトでWorktreeを管理する必要がある。これは比較的上級者向けの活用法と言えます。

これらの事例からもわかるように、Worktreeは「現在の作業状態を維持したまま、別のブランチ/コミットの環境に瞬時にアクセスしたい」というあらゆるシナリオで強力なツールとなります。

Git Worktreeを使う上での注意点・デメリット

Worktreeは非常に便利な機能ですが、いくつかの注意点やデメリットも存在します。これらを理解した上で利用することが重要です。

  1. ディスク容量の消費(ゼロではない)

    • オブジェクトストアは共有されるため、リポジトリ全体をクローンするよりは効率的ですが、Worktreeごとにワーキングツリーのファイル(コード、ビルド成果物など)とGit管理情報(HEAD, index, reflogsなど)がディスク上に必要になります。
    • 特に、コンパイル済みのバイナリやライブラリなど、ワーキングツリーで生成されるファイルが大きいプロジェクトの場合、Worktreeの数に比例してディスク容量を消費します。
    • たくさんのWorktreeを作成・放置すると、知らず知らずのうちにディスク容量を圧迫する可能性があるため、不要になったWorktreeはこまめに削除することが推奨されます。
  2. ターミナル管理やIDE管理の煩雑化

    • 複数のWorktreeで作業するということは、複数のターミナルウィンドウやIDEウィンドウ(あるいはタブ)を開いて作業することが多くなる、ということです。
    • どのウィンドウがどのWorktree(=どのブランチ)で作業しているのか、意識して管理する必要があります。ウィンドウタイトルなどをWorktreeのパスやブランチ名でカスタマイズするなどの工夫が役立ちます。
    • エディタやIDEの設定ファイル(.vscode, .ideaなど)は通常リポジトリに含まれるため、Worktreeごとに異なる設定が適用される可能性があります。
  3. 一部のGit操作の制限

    • チェックアウト中のブランチの削除: あるWorktreeがチェックアウトしているブランチを、別のWorktreeから削除しようとするとエラーになります。Gitは、アクティブに使用されているブランチを誤って削除しないように保護しています。
    • 同じブランチの複数Worktreeでのチェックアウト: 基本的に、同じブランチを複数のWorktreeで同時にチェックアウトすることはできません。各Worktreeは、そのWorktree専用にそのブランチを「借用」するようなイメージです。もし同じブランチを複数箇所で開きたい場合は、一度ブランチ名を変更した上でWorktreeを追加するなどの回避策が必要になることがあります(ただし、そのような状況自体がWorktreeの本来の意図から外れることが多いかもしれません)。
    • リベースなどインタラクティブな操作: 自分が作業しているWorktree以外のWorktreeでチェックアウトされているブランチに対して、複雑なGit操作(例: git rebase -i)を行う際には、意図しない挙動を引き起こす可能性や、Gitが制限をかける場合があります。操作を行う際は、そのWorktreeのディレクトリに移動して行うのが安全です。
    • Worktree内のブランチ名変更/削除: Worktree内で現在チェックアウトしているブランチ名を変更したり削除したりしようとすると、制限がかかる場合があります。そのWorktreeのブランチ操作は、原則としてそのWorktree内で行うべきです。
  4. .gitディレクトリ(ファイル)とworktreesディレクトリの管理

    • 追加されたWorktreeディレクトリのルートには.gitというファイルが作成されるという仕組みを理解していないと、混乱する可能性があります。
    • メインリポジトリを移動したり削除したりすると、それに関連付けられた全てのWorktreeが機能しなくなります。Worktreeを削除せずにメインリポジトリを移動した場合、Worktree内の.gitファイルが指すパスが不正になるため、git worktree pruneで手動で情報を削除する必要があります。
  5. パスに関する考慮事項

    • Worktreeを作成する際のパスは、メインリポジトリのディレクトリの外部でなければなりません。これはGitの制約です。
    • 絶対パスでWorktreeを作成した場合、メインリポジトリを移動してもWorktreeは機能しますが、相対パスで作成した場合、メインリポジトリを移動すると.gitファイル内のパスが不正になり機能しなくなることがあります。

これらの注意点を踏まえると、Git Worktreeは、あくまで「ローカルでの開発効率を向上させるためのツール」として捉えるのが適切です。リモートリポジトリとの連携や、チームメンバーとの共有といった場面では、従来のブランチ操作(フェッチ、プル、プッシュ、マージ、リベースなど)の知識が依然として重要です。Worktreeは、これらの操作を行う前の、ローカルでのファイル編集やコミット作業を並行して行う部分に特化した機能と言えます。

Git Worktreeに関するよくある質問(Q&A)

Q1: メインリポジトリのディレクトリを削除したらどうなりますか?

A1: メインリポジトリのディレクトリにはオブジェクトストアなど、Worktreeが共有する重要なデータが格納されています。これを削除すると、それに紐づく全てのWorktreeは正常に動作しなくなります。Worktreeディレクトリ内の.gitファイルが参照するメインリポジトリが存在しなくなるためです。メインリポジトリを削除する前に、関連する全てのWorktreeをgit worktree removeコマンドで削除することが推奨されます。

Q2: Worktreeの中でgit stashは使えますか?

A2: はい、使えます。各Worktreeは独立したインデックスとワーキングツリーを持つため、そのWorktree内での変更をgit stashで一時保存し、後でgit stash applyなどで元に戻すといった操作は通常通り行えます。スタッシュの情報も、そのWorktreeに関連付けられて管理されます。

Q3: 同じブランチを複数のWorktreeでチェックアウトできますか?

A3: いいえ、デフォルトではできません。git worktree addでブランチ名を指定してWorktreeを作成すると、そのブランチは「借用」され、他のWorktreeやメインリポジトリではチェックアウトできなくなります。これは、同じブランチを複数の場所で同時に変更してしまうことによる混乱を防ぐためのGitの設計です。もしどうしても同じコミットの内容を複数箇所で開きたい場合は、一方のWorktreeではブランチ名ではなくコミットハッシュをチェックアウトするか、あるいはダミーのブランチ名を一時的に作成してそれをチェックアウトするといった回避策が考えられますが、通常は避けるべきです。

Q4: Worktree内でコミットやプッシュなどの操作はできますか?

A4: はい、できます。各Worktreeは独立したワーキングツリーとインデックスを持つため、通常通りファイルの編集、git addgit commitgit pushなどの操作を行えます。これらの操作は、そのWorktreeがチェックアウトしているブランチに対して行われます。

Q5: WorktreeはGitのバージョン管理に影響しますか?

A5: 直接的な影響はありません。Worktreeはあくまでローカルでの作業環境を複数作る機能であり、リポジトリのコミット履歴やブランチ構造そのものに影響を与えるものではありません。リモートリポジトリへのプッシュやプルは、各Worktreeから独立して行われます。

Q6: Worktreeはチームでの利用に向いていますか?

A6: Worktreeは基本的にローカルでの開発効率を向上させるためのツールです。作成したWorktreeはローカル環境に依存するため、他のチームメンバーとWorktreeの状態を共有することはできません。チームメンバーはそれぞれ自身のローカル環境でWorktreeを作成して利用することになります。Worktreeの使用ルールや慣習をチーム内で共有しておくと、よりスムーズに連携できるかもしれません。

Q7: Worktreeの管理をもっと簡単にできますか?

A7: 一部のGitクライアントGUIツールや、Git Worktreeをラップしたコマンドラインツール(例: gitaなど)が存在し、Worktreeの作成、一覧表示、削除などをより直感的に行える機能を提供している場合があります。これらのツールを利用することで、ターミナルでのコマンド入力を減らし、管理を効率化できる可能性があります。

Git Worktreeを使い始めるためのステップ

Git Worktreeのメリットを理解し、実際に使ってみたくなった方もいるでしょう。使い始めるのは非常に簡単です。

  1. Gitのバージョンを確認: Git WorktreeはGitバージョン2.5で導入された機能です。それ以降のバージョンであれば利用可能です。git --versionコマンドで確認してみてください。もし古すぎる場合は、Gitをアップデートしてください。
  2. 簡単な実験から始める: まずは、現在作業中のリポジトリとは別の、小さめのリポジトリや、あるいは全く新しいテスト用のリポジトリで試してみるのがおすすめです。
  3. Worktreeを作成してみる: 現在のブランチ(例: main)から新しい実験用ブランチ(例: experiment)を作成し、それをチェックアウトしたWorktreeを作成してみましょう。
    bash
    # メインリポジトリのディレクトリにて
    git branch experiment
    git worktree add ../test_worktree experiment

    ../test_worktreeは、メインリポジトリの親ディレクトリに新しく作るディレクトリの名前です)
  4. 新しいWorktreeに移動し、作業してみる:
    bash
    cd ../test_worktree
    # ここでファイルの編集、git status, git add, git commit などを試す
  5. メインリポジトリに戻り、状態を確認する:
    bash
    cd ../[メインリポジトリのディレクトリ名]
    git worktree list

    新しいWorktreeがリストに表示されるはずです。
  6. 不要になったWorktreeを削除する:
    bash
    git worktree remove ../test_worktree
    git worktree prune # 必要に応じて

    この一連の流れを試すことで、Worktreeの挙動を理解し、自分のワークフローにどう組み込めるかイメージしやすくなります。

最初は一つの追加Worktreeから始め、慣れてきたら複数のWorktreeを使い分けるようにすると良いでしょう。日常的に発生する「割り込み作業」や「別のブランチの確認」といった場面で積極的にWorktreeを活用することで、そのメリットを実感できるはずです。

まとめ:Worktreeで変わる開発ワークフロー

Git Worktreeは、単一のリポジトリから複数の独立した作業環境(Worktree)を作成することを可能にする強力な機能です。従来のgit checkoutgit stashに依存したブランチ切り替えの非効率性や、リポジトリ全体をクローンすることによるディスク容量の無駄といった課題を解決します。

Worktreeの最大のメリットは、高速なブランチ間移動と、それに伴うコンテキストスイッチの大幅な削減です。各Worktreeが独立したディレクトリと作業状態を持つため、複数のタスク(機能開発、バグ修正、調査、レビューなど)を完全に並行して進めることが容易になります。ディレクトリを移動するだけで瞬時に作業環境を切り替えられる感覚は、一度体験すると手放せなくなるでしょう。

もちろん、ディスク容量の消費や、複数のWorktreeの管理、一部のGit操作の制約といった注意点も存在します。しかし、これらのデメリットは、Worktreeがもたらす生産性向上とストレス軽減というメリットに比べれば、多くの開発者にとって取るに足らないものである場合が多いでしょう。

Git Worktreeは、特に以下のような開発者やチームにとって、開発ワークフローを劇的に改善する可能性を秘めています。

  • 頻繁に割り込み作業が発生する
  • 複数の異なるタスクを並行して進める必要がある
  • 大規模なコードベースで、ブランチ切り替えに時間がかかる
  • 過去のコードや実験的なコードを気軽に触りたい

Git Worktreeを上手に活用することで、あなたの開発プロセスはよりスムーズになり、集中力を持続させやすくなるはずです。これは、コードを書く時間だけでなく、問題を解決し、新しいアイデアを形にするための「考える時間」を確保するためにも非常に重要です。

ぜひ今日からGit Worktreeを試してみてください。あなたの開発ワークフローの「救世主」となるかもしれません。


コメントする

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

上部へスクロール