【入門】Git worktreeとは?並行開発を超効率化する使い方


【入門】Git worktreeとは?並行開発を超効率化する使い方

Gitを使った開発に慣れてくると、「もっと効率的に複数の作業を進めたい」「現在のブランチを中断せずに、別のブランチのコードを確認したい」といった要望が出てくることがあります。そんな時、git worktreeコマンドが強力な味方となります。

この記事では、Gitの基本的な操作(コミット、ブランチ、マージなど)は理解している方を対象に、git worktreeとは何か、そのメリット・デメリット、そして並行開発を劇的に効率化するための具体的な使い方を、約5000語のボリュームで徹底的に解説します。

さあ、git worktreeをマスターして、あなたの開発ワークフローを次のレベルへ引き上げましょう!

1. はじめに:並行開発における悩み

ソフトウェア開発では、同時に複数のタスクに取り組むことが日常茶飯事です。例えば、

  • 新しい機能(Feature A)を開発中に、別の新しい機能(Feature B)のプロトタイプも試したい。
  • メインの開発(Feature A)を進めながら、急に報告されたバグの修正も行いたい。
  • 開発中のコード(Feature A)とは別のブランチにある、過去のバージョンのコードを参照したい。
  • 同僚が作成したプルリクエストのコードをローカルで確認・テストしたい。

これらの状況に、あなたはどのように対応しているでしょうか? 多くのGitユーザーは、主にブランチの切り替えgit checkoutまたはgit switch)を使って対応していることと思います。

しかし、ブランチを切り替える際には、いくつかの面倒なステップが必要です。

  1. 現在のブランチでの変更を、すべてコミットするかスタッシュする。未コミットの変更があると、ブランチを切り替えられないことが多いためです。
  2. git checkout <別のブランチ> または git switch <別のブランチ> を実行する。
  3. Gitが作業ディレクトリの内容を、切り替え先のブランチの状態に書き換えるのを待つ。
  4. もしスタッシュを使っていた場合は、切り替え先のブランチでスタッシュを適用する(必要な場合)。

このプロセスには、いくつかの課題があります。

  • コンテキストスイッチのコスト: ブランチを切り替えるたびに、作業ディレクトリの状態が完全に変わります。これにより、IDEの設定、ビルドキャッシュ、依存関係のインストール状態などがリセットされたり、再構築が必要になったりすることがあります。これが時間的なロスにつながります。
  • 作業の中断: 現在の作業中の変更をすべて片付けなければならないため、気軽に他のブランチに「ちょっとだけ見に行く」「ちょっとだけ試す」ということがしづらいです。
  • コードの同時参照の困難さ: 別のブランチのコードを参照したい場合、一度ブランチを切り替えるか、別の場所にリポジトリをクローンしてくる必要があります。これは非常に手間がかかります。
  • 真の並行作業の難しさ: 同時に複数のブランチで異なるタスクを進めることは、事実上不可能です。一方のタスクを作業中に、もう一方のタスクに関連するアイデアが浮かんだとしても、すぐにそちらに移ってコードを書く、といったことができません。

これらの課題を解決し、並行開発を驚くほどスムーズにするのが、git worktreeコマンドです。

2. git worktreeとは?基本的な概念

git worktreeを理解するための鍵は、「作業ツリー(Worktree)」という概念です。

Gitリポジトリは、通常、一つの作業ディレクトリ(ワーキングツリー、または作業ツリー)と、Gitの履歴データなどが格納されている.gitディレクトリ(リポジトリ本体)で構成されています。

  • .gitディレクトリ: コミットオブジェクト、ツリーオブジェクト、ブロブオブジェクト、参照(ブランチ、タグなど)、ログ、設定ファイルなど、リポジトリのすべての履歴とメタデータがここに保存されています。
  • 作業ディレクトリ(ワーキングツリー、または作業ツリー): .gitディレクトリの隣にあるディレクトリで、特定のコミットの内容がファイルとして展開され、あなたが実際にコードを編集する場所です。

通常、一つのリポジトリに対して、この作業ディレクトリは一つだけです。そして、git checkoutgit switchコマンドは、この単一の作業ディレクトリの内容を、指定されたブランチやコミットの状態に切り替えます。

git worktreeコマンドを使うと、一つのGitリポジトリに対して、追加の作業ディレクトリを作成することができます。これが「追加の作業ツリー」です。

イメージとしては、元のリポジトリ(.gitディレクトリ)を親として、そこから枝分かれした複数の作業ディレクトリを持つようなものです。

my-project/ <-- リポジトリのルートディレクトリ
├── .git/ <-- リポジトリ本体 (全ブランチ・全履歴)
├── README.md
└── src/ <-- メインの作業ツリー
└── main.c

git worktree add ../feature-a feature-a を実行

“`
my-project/ <– リポジトリのルートディレクトリ
├── .git/ <– リポジトリ本体
├── README.md <– メインの作業ツリーのファイル
└── src/ <– メインの作業ツリーのファイル

../feature-a/ <– 追加の作業ツリー (feature-a ブランチ)
└── my-project/ <– (慣習的にリポジトリ名と同じサブディレクトリに入れることが多い)
├── .git <– このディレクトリは .git ではなく、親の .git/worktrees/… への参照ファイル
├── README.md <– feature-a ブランチのファイル
└── src/ <– feature-a ブランチのファイル
“`

このように、git worktree addコマンドを使うと、指定したパスに新しいディレクトリを作成し、その中に元のリポジトリの特定のブランチやコミット時点でのファイル群を展開します。そして、その新しいディレクトリは、元のリポジトリの.gitディレクトリと関連付けられます。

重要なポイントは以下の通りです。

  • リポジトリ本体は一つ: .gitディレクトリは一つです。追加の作業ツリー内に存在する.gitファイルは、実は元の.gitディレクトリ内にある特定のディレクトリ(.git/worktrees/<作業ツリー名>)への参照を含むテキストファイルです。
  • 独立した作業環境: 各作業ツリーは、完全に独立した作業ディレクトリとして機能します。それぞれの作業ツリーで、異なるブランチをチェックアウトしたり、ファイルを編集したり、コミットを作成したりできます。
  • ブランチの排他利用: 同じブランチを複数の作業ツリーで同時にチェックアウトすることはできません。 あるブランチがすでにどこかの作業ツリーでチェックアウトされている場合、別の作業ツリーでそのブランチをチェックアウトしようとするとエラーになります。これは、同じブランチに対して複数の場所で同時に変更を加えて混乱するのを防ぐためです。(ただし、特定のコミット(デタッチドHEAD)であれば複数の作業ツリーで参照可能です。)

git worktreeを使うことで、あなたは複数の異なるディレクトリを開き、それぞれで異なるブランチの作業を同時に進めることができるようになります。これは、まるで一つのリポジトリに対して、複数の「窓」を開いて作業しているような感覚です。

3. git worktreeを使うメリット

git worktreeを活用することで、前述の並行開発における課題が劇的に改善されます。主なメリットを見ていきましょう。

3.1. 高速なブランチ切り替えとコンテキストスイッチの排除

これがgit worktreeの最大のメリットの一つです。

従来のgit switchでは、ブランチを切り替えるたびにGitは現在の作業ディレクトリの内容をすべて破棄し、新しいブランチのファイル群をディスクから読み込み直して展開します。さらに、未コミットの変更がある場合は、その前にスタッシュ/コミットが必要でした。

git worktreeを使えば、あなたは単に別の作業ツリーのディレクトリに移動するだけで、瞬時に異なるブランチの作業環境にアクセスできます。ファイルシステムの切り替えが発生するだけで、Gitが作業ディレクトリの内容を丸ごと書き換える処理は不要です。スタッシュやコミットも不要です。

例えば、mainブランチで作業中に、急ぎでbugfixブランチに切り替えて修正したい場合、

  • 従来:

    1. mainでの変更をスタッシュ/コミット
    2. git switch bugfix
    3. 修正作業
    4. git add, git commit, git push
    5. git switch main
    6. スタッシュを適用(必要な場合)
    7. mainでの作業を再開
  • git worktree使用:

    1. (最初に一度だけ)git worktree add ../bugfix bugfixbugfixブランチ用の作業ツリーを作成しておく
    2. cd ../bugfix/my-project (またはIDEで別のウィンドウを開く)
    3. 修正作業
    4. git add, git commit, git push
    5. cd ../my-project (元のディレクトリに戻るか、IDEの別のウィンドウに戻る)
    6. mainでの作業を中断することなく、すぐに再開できる

このように、現在の作業状態を一切変更することなく、別の作業ツリー(別のブランチ)へ瞬時に移動できます。これは、特に大きなプロジェクトや、ビルドプロセスに時間のかかるプロジェクトで、コンテキストスイッチのコストを大幅に削減します。IDEやツールの状態も、それぞれの作業ツリーディレクトリに対して独立して保持されるため、再読み込みやキャッシュクリアの手間も省けます。

3.2. 真の並行作業の実現

それぞれの作業ツリーが独立した環境であるため、同時に複数のタスクを進めることができます。

  • 一つの作業ツリーでFeature Aの開発コードを書きながら、別の作業ツリーでFeature Bのアイデアを試すコードを書く。
  • 一つの作業ツリーで本命のバグ修正を行いながら、別の作業ツリーでそのバグの再現環境を構築・検証する。
  • 一つの作業ツリーで開発中のコードをビルド・テスト実行させながら、別の作業ツリーで次のタスクのコードを書き始める。

これは、一つの頭で複数のことを考えるのではなく、それぞれのタスクに集中できる独立した「机」が複数与えられるようなものです。

3.3. コード参照や比較の容易さ

別のブランチや過去のバージョンのコードを参照したい場合がよくあります。

  • mainブランチの最新コードを見ながら、開発中のフィーチャーブランチのコードと比較したい。
  • 過去のタグが打たれた時点のコードがどうなっていたか確認したい。
  • バグが発生した特定のコミット時点のコードを調べて、原因を探りたい。

従来の方法では、ブランチを切り替えるか、別のディレクトリにクローンするしかありませんでした。git worktreeを使えば、参照したいブランチやコミットを指定して作業ツリーを作成するだけで、独立したディレクトリにその時点のコードが展開されます。

あなたはIDEやエディタで、メインの作業ツリーのディレクトリと、参照用の作業ツリーのディレクトリを同時に開くことができます。これにより、ファイルを開き直したり、ブランチを切り替えたりする手間なく、コードを簡単に参照したり比較したりできます。これは、特にリファクタリングやバグ調査において非常に強力です。

3.4. テストや検証の効率化

特定のブランチやコミットのコードに対して、ビルド、テスト、実行などの検証を行いたい場合があります。

git worktreeを使えば、検証したい状態の作業ツリーを作成し、そこで検証プロセスを実行できます。その間、メインの作業ツリーでは開発を続けることができます。検証が終わったら、その作業ツリーは破棄すればよく、メインの作業に一切影響を与えません。

例えば、

  • プルリクエストのレビュー時に、そのPRのブランチを作業ツリーとして作成し、ローカルでビルド・テストを実行して動作を確認する。
  • 特定のコミットで発生したバグを再現するために、そのコミットを作業ツリーとして作成し、デバッグ実行する。

これにより、メインの開発フローを中断することなく、効率的に検証を進めることができます。

3.5. 実験的な開発や一時的な作業

ちょっとしたアイデアを試したい、既存のコードに影響を与えずに実験的な変更を加えてみたい、といった場面でもgit worktreeは役立ちます。

一時的な作業ツリーを作成し、そこで自由にコードを変更したり、新しいライブラリを試したりできます。気に入らなければ、その作業ツリーごと削除してしまえばよく、メインのコードベースはクリーンなままです。

これは、新しい技術のPoC(概念実証)や、大胆なリファクタリングの試行など、本流の開発とは切り離して行いたい作業に最適です。

4. git worktreeを使う上でのデメリット・注意点

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

4.1. ディスク容量の消費

追加の作業ツリーを作成すると、そのブランチやコミット時点でのファイル群が新しいディレクトリに展開されます。つまり、リポジトリのサイズに比例して、追加の作業ツリーの数だけディスク容量を消費します。

特に、大きなプロジェクトや、多数の作業ツリーを作成する場合は、注意が必要です。不要になった作業ツリーはこまめに削除するようにしましょう。

ただし、.gitディレクトリ自体は一つなので、すべての履歴データが作業ツリーごとに複製されるわけではありません。あくまで、ファイルシステム上のファイル群が展開されることで容量が増えます。

4.2. 混乱の可能性

複数の作業ツリーで作業していると、「今、どのディレクトリで作業しているか」「どのブランチ/コミットを見ているか」が混乱する可能性があります。

特に、複数のターミナルウィンドウやIDEウィンドウを開いている場合、それぞれのウィンドウが異なる作業ツリーを指している可能性があります。うっかり間違った作業ツリーでコミットしてしまったり、意図しないブランチで作業してしまったりするリスクがあります。

この問題への対策としては、

  • 作業ツリーのディレクトリ名を分かりやすくする(例:../my-project-feature-a, ../my-project-bugfix-123)。
  • ターミナルやIDEの設定で、現在のディレクトリやGitブランチが分かりやすく表示されるようにする。
  • 定期的にgit worktree listコマンドを実行して、現在の作業ツリーの状態を確認する。

などの方法があります。

4.3. IDE/ツールの対応状況

多くのモダンなIDEやGitクライアントツールはgit worktreeをある程度サポートしていますが、完全に統合されていない場合もあります。

例えば、IDEのGit操作機能(ブランチ切り替え、マージ、リベースなど)が、メインの作業ツリーを前提として設計されており、追加の作業ツリーでの操作で挙動が不安定になったり、意図しない操作になったりすることが稀にあります。

基本的には、各作業ツリーディレクトリ内で独立したGitコマンド(git add, git commit, git pushなど)を実行するのが最も確実で推奨される方法です。

4.4. .gitディレクトリの管理

追加の作業ツリーは、元のリポジトリの.git/worktreesディレクトリにエントリが追加される形で管理されます。作業ツリーを削除する際には、そのディレクトリを削除するだけでなく、Gitにその作業ツリーの管理を終了させる必要があります(git worktree removeまたはgit worktree prune)。

手動で作業ツリーのディレクトリを削除してしまっただけでは、.git/worktreesに不要なエントリが残ってしまい、Gitがその作業ツリーがまだ存在すると認識してしまうことがあります。これにより、後々問題が発生する可能性があります。

4.5. ブランチの排他利用

前述の通り、同じブランチを複数の作業ツリーで同時にチェックアウトすることはできません。

例えば、mainブランチがメインの作業ツリーでチェックアウトされている場合、別の作業ツリーでgit worktree add ../another-dir mainを実行しようとするとエラーになります。

これは仕様であり、意図しないコンフリクトを防ぐためのものです。もし同じブランチの状態を複数の場所で参照したい場合は、特定のコミットIDを指定して作業ツリーを作成するか、そのブランチから一時的な別のブランチを作成して作業ツリーを作成する必要があります。

5. git worktreeの基本的な使い方

ここからは、git worktreeコマンドの具体的な使い方を見ていきましょう。

5.1. 新しい作業ツリーを作成する: git worktree add

最も頻繁に使うコマンドです。新しい作業ツリーを作成し、指定したパスにチェックアウトします。

bash
git worktree add <path> [<commit-ish>]

  • <path>: 新しい作業ツリーを作成するディレクトリのパスを指定します。絶対パスでも相対パスでも構いません。既存のディレクトリを指定することはできません。 指定したディレクトリは自動的に作成されます。
  • <commit-ish>: 新しい作業ツリーでチェックアウトしたいブランチ名、タグ名、コミットIDなどを指定します。省略可能です。

例1: 新しいブランチを作成してチェックアウトする

これが最も一般的な使い方です。指定したパスに新しい作業ツリーを作成し、そこに新しいブランチを作成してチェックアウトします。新しいブランチ名は、特に指定しない場合、作成するディレクトリ名の最後の部分が使われます。

“`bash

現在、my-project ディレクトリにいるとする

sibling-feature という新しいディレクトリに、feature-a ブランチ用の作業ツリーを作成

git worktree add ../sibling-feature feature-a
“`

上記のコマンドを実行すると:

  1. 現在のディレクトリの親ディレクトリ(../)にsibling-featureという新しいディレクトリが作成されます。
  2. 元のリポジトリ(my-project)の現在のブランチから新しいブランチfeature-aが作成されます。
  3. sibling-featureディレクトリの中に、my-projectリポジトリのファイル群がfeature-aブランチの状態で展開されます。
  4. sibling-featureディレクトリは、元のmy-projectリポジトリに関連付けられます。

sibling-featureディレクトリに移動してgit statusを実行すると、On branch feature-a と表示されるはずです。

新しいブランチ名を明示的に指定したい場合は、-bオプションを使います。

“`bash

新しいブランチ名は feature-b としたい

git worktree add ../sibling-feature-b -b feature-b
“`

この場合も、sibling-feature-bディレクトリが作成され、そこに新しいブランチfeature-bが作成・チェックアウトされます。ブランチ名とディレクトリ名を必ずしも一致させる必要はありませんが、分かりやすさのために一致させることが多いです。

例2: 既存のブランチをチェックアウトする

既に存在するブランチを作業ツリーとして開きたい場合。ただし、そのブランチが他のどの作業ツリーでもチェックアウトされていないことが条件です。

“`bash

main ブランチ用の作業ツリーを main-worktree ディレクトリに作成

git worktree add ../main-worktree main
“`

このコマンドを実行すると、../main-worktreeディレクトリにmainブランチの状態が展開されます。

例3: 特定のコミットをチェックアウトする

特定のコミットの状態を作業ツリーとして参照したい場合。これは、バグ調査や過去のバージョンの確認に便利です。

“`bash

特定のコミットID (例: abcdef0) を参照する作業ツリーを old-state ディレクトリに作成

git worktree add ../old-state abcdef0
“`

この場合、../old-stateディレクトリは「デタッチドHEAD」状態になります。これは、特定のコミットを直接参照しており、ブランチのように変更履歴を追跡しない状態です。この作業ツリー内で行ったコミットは、どのブランチにも属さない「浮いた」コミットになるため、注意が必要です。通常は、一時的な参照や検証に使い、変更を加える場合は新しいブランチを作成してから行うのが良いでしょう。

パスの指定について:

<path>は、現在のリポジトリのルートディレクトリからの相対パスでも、絶対パスでも構いません。ただし、慣習として、元のリポジトリのディレクトリの隣に作成することが多いです。

“`bash

現在のディレクトリの親ディレクトリに作成

git worktree add ../feature-a feature-a

絶対パスで指定

git worktree add /path/to/your/worktrees/feature-a feature-a
“`

注意点: 指定したパスにディレクトリが既に存在する場合、git worktree addは失敗します。

5.2. 現在の作業ツリーを一覧表示する: git worktree list

現在、このリポジトリに関連付けられている全ての作業ツリーを確認できます。

bash
git worktree list

実行例:

/path/to/my-project abcdef0 [main] # メインの作業ツリー
/path/to/sibling-feature 1234567 [feature-a] # 追加の作業ツリー (feature-a ブランチ)
/path/to/old-state abcdef0 (detached HEAD) # 追加の作業ツリー (コミット abcdef0)

表示される情報:

  • パス: 作業ツリーのルートディレクトリのパス。
  • HEAD: その作業ツリーのHEADが指しているコミットのハッシュ。
  • ブランチ/タグ/detached HEAD: その作業ツリーがチェックアウトしているブランチ名、タグ名、またはdetached HEADの状態であるかどうかが表示されます。メインの作業ツリーは通常、どのブランチにいるかを示します。

このコマンドは、自分が今どの作業ツリーを持っているか、そしてそれぞれの作業ツリーがどのブランチ/コミットを参照しているかを把握するために非常に重要です。

5.3. 作業ツリーを削除する: git worktree removegit worktree prune

不要になった作業ツリーは削除しましょう。ディスク容量の節約と、管理の煩雑さを減らすためです。

git worktree remove <path>

指定したパスにある作業ツリーを削除します。

bash
git worktree remove ../sibling-feature

このコマンドを実行すると、Gitはその作業ツリーの管理を終了し、指定したディレクトリ(例: ../sibling-feature)ごと削除します。

注意点:

  • 削除しようとしている作業ツリーで、未コミットの変更がある場合は、デフォルトでは削除できません。安全のため、変更をコミットするかスタッシュするかしてください。
  • どうしても未コミットの変更がある状態で強制的に削除したい場合は、-fオプションを付けますが、変更が失われる可能性があるため非推奨です。 変更を失いたくない場合は、必ずコミットまたはスタッシュしてから削除してください。
  • 現在作業している作業ツリー自体をgit worktree remove .のように削除しようとすると、エラーになります。(自分で自分の足元を削除できない)

git worktree prune

このコマンドは、Gitのリポジトリ本体(.gitディレクトリ)に記録されている作業ツリーの情報のうち、対応するディレクトリが既に存在しないものをクリーンアップします。

例えば、エクスプローラーやrm -rfなどで手動で作業ツリーのディレクトリを削除してしまった場合、git worktree listにはその作業ツリーの情報が残ってしまいます。このような「孤立した」作業ツリーのエントリを削除するのがgit worktree pruneです。

bash
git worktree prune

通常、git worktree removeを使えばpruneは不要ですが、何らかの理由でディレクトリだけが削除されてしまった場合に役立ちます。定期的に実行しても問題ありません。

5.4. 作業ツリーの場所を移動する: git worktree move

作成済みの作業ツリーのディレクトリの場所を変更したい場合に使います。

bash
git worktree move <current_path> <new_path>

  • <current_path>: 移動したい作業ツリーの現在のディレクトリのパス。
  • <new_path>: 移動先の新しいディレクトリのパス。

“`bash

../sibling-feature ディレクトリにある作業ツリーを ../archive/feature-a に移動

git worktree move ../sibling-feature ../archive/feature-a
“`

このコマンドは、ファイルシステム上のディレクトリを移動し、同時にGitの内部情報(.git/worktrees/...内のファイル)を更新します。手動でディレクトリを移動してからGitの設定ファイルを修正するよりも、このコマンドを使う方が安全で確実です。

6. 具体的な使用例・応用例

git worktreeがどのように並行開発やワークフローを効率化するのか、具体的なシナリオで見てみましょう。

6.1. シナリオ1:Feature A と Feature B の同時開発

あなたは今、mainブランチから分岐したfeature-aブランチで新機能の開発を進めています。しかし、別の新しい機能であるFeature Bのアイデアも浮かび、並行してプロトタイプを試したいと考えています。

git worktreeなしの場合:

  1. feature-aブランチでの作業を一時中断。
  2. 未コミットの変更があればコミットまたはスタッシュ。
  3. git switch main (またはfeature-aから分岐する元のブランチ)。
  4. git switch -c feature-b で新しいfeature-bブランチを作成・チェックアウト。
  5. feature-bでの作業開始。
  6. feature-bでの作業を中断し、feature-aに戻りたい場合、再度コミット/スタッシュし、git switch feature-aを実行。
  7. これを繰り返す…

ブランチ切り替えの手間とコンテキストスイッチのコストが何度も発生します。

git worktreeありの場合:

  1. feature-aブランチで作業中(例: ~/projects/my-project)。
  2. feature-b用の作業ツリーを作成します。元のリポジトリ(my-project)のディレクトリに移動し、以下を実行します。
    bash
    # 現在のディレクトリが ~/projects/my-project であるとする
    # 親ディレクトリに feature-b ディレクトリを作成し、新しい feature-b ブランチをチェックアウト
    git worktree add ../my-project-feature-b -b feature-b
  3. これで、~/projects/my-project-feature-b という新しいディレクトリに、feature-bブランチがチェックアウトされた作業ツリーができました。
  4. あなたは、~/projects/my-project のディレクトリでfeature-aの開発を続けながら、別のターミナルウィンドウやIDEウィンドウで ~/projects/my-project-feature-b のディレクトリを開き、feature-bの開発を同時に進めることができます。
  5. それぞれのディレクトリで独立してgit add, git commit, git pushなどのコマンドを実行します。
  6. 両方のフィーチャーブランチの開発が完了したら、それぞれをmainブランチにマージするなどの通常のGitフローに進みます。
  7. feature-bの開発が完了したら、../my-project-feature-bディレクトリは不要になるので削除します。
    bash
    cd ~/projects/my-project # 元のリポジトリの作業ツリーに戻る
    git worktree remove ../my-project-feature-b

このように、git worktreeを使えば、現在の作業を中断することなく、別のタスクのための独立した環境を瞬時に用意し、並行して作業を進めることができます。

6.2. シナリオ2:過去のバージョンの参照・デバッグ

ユーザーから、「1ヶ月前のバージョンでは発生しなかったのに、最新バージョンでバグが発生した」と報告が入りました。あなたは、バグの原因を探るために、1ヶ月前のバージョンと現在のバージョンを比較したり、1ヶ月前のバージョンでバグが本当に発生しないか確認したりしたいと考えています。

git worktreeなしの場合:

  1. 現在の作業ブランチでの変更をコミットまたはスタッシュ。
  2. 1ヶ月前のバージョンに対応するタグやコミットID(例: v1.0.0 または abcdef0)にgit switch v1.0.0などで切り替える。
  3. その時点のコードでバグが再現しないかテストする。
  4. 必要に応じて、現在のブランチに戻り、再度コミット/スタッシュを処理し、コードを比較する。
  5. ブランチを何度も行ったり来たりする必要があり、手間がかかる上に、コードの比較もエディタの機能を使うなど工夫が必要です。

git worktreeありの場合:

  1. 現在の作業ブランチで作業中(例: ~/projects/my-project)。
  2. 1ヶ月前のバージョン(タグv1.0.0とする)を作業ツリーとして作成します。
    bash
    git worktree add ../my-project-v1.0.0 v1.0.0
  3. ~/projects/my-project-v1.0.0 という新しいディレクトリに、v1.0.0タグの時点でのファイル群が展開されました。これはdetached HEAD状態になります。
  4. あなたは、~/projects/my-project-v1.0.0ディレクトリで、1ヶ月前のバージョンのコードを使ってバグが再現しないかテストできます。同時に、~/projects/my-projectディレクトリでは最新バージョンのコードを見ることができます。
  5. IDEで両方のディレクトリを開けば、コードを簡単に参照したり、ファイル比較ツールを使って変更点を確認したりできます。
  6. バグの原因が特定できたら、../my-project-v1.0.0ディレクトリは不要になるので削除します。
    bash
    git worktree remove ../my-project-v1.0.0

git worktreeを使うことで、現在の開発作業を一切中断することなく、過去の任意の時点のコードベースを調査・検証できるため、デバッグ効率が格段に向上します。

6.3. シナリオ3:Pull Request のレビュー

同僚が新しい機能(feature-xブランチ)を開発し、レビューを依頼されました。あなたは、コードを読んだ上で、実際にローカル環境でビルドし、動作を確認してから承認したいと考えています。

git worktreeなしの場合:

  1. 現在の作業ブランチでの変更をコミットまたはスタッシュ。
  2. レビュー対象のブランチ(feature-x)をフェッチし、ローカルでチェックアウト。
    bash
    git fetch origin feature-x:feature-x
    git switch feature-x
  3. ローカルでビルド、テスト、動作確認を行う。
  4. レビューコメントを作成する。
  5. 元の作業ブランチに戻るために、再度コミット/スタッシュし、git switch <元のブランチ>を実行。
  6. 複数のPRをレビューする場合、これを繰り返す…

ここでも、作業の中断とブランチ切り替えの手間が発生します。

git worktreeありの場合:

  1. 現在の作業ブランチで作業中(例: ~/projects/my-project)。
  2. レビュー対象のブランチ(origin/feature-x)を作業ツリーとして作成します。
    bash
    # リモート追跡ブランチをローカルブランチとしてチェックアウトしつつ作業ツリーを作成
    git worktree add ../my-project-review-feature-x feature-x
    # または、ローカルブランチを作成せずに直接リモート追跡ブランチをチェックアウト (detached HEADになる)
    # git worktree add ../my-project-review-feature-x origin/feature-x
  3. ~/projects/my-project-review-feature-x という新しいディレクトリに、feature-xブランチのコードが展開されました。
  4. あなたは、この新しいディレクトリで、feature-xのコードをローカルでビルドし、テスト実行して動作を確認できます。メインの作業ツリーはそのままにしておけます。
  5. IDEで両方のディレクトリを開けば、あなたのコードとレビュー対象のコードを見比べながら作業できます。
  6. レビューが完了したら、../my-project-review-feature-xディレクトリは不要になるので削除します。
    bash
    git worktree remove ../my-project-review-feature-x

PRレビューの効率が大幅に向上し、レビューのために自分の開発作業を中断する必要がなくなります。複数のPRを並行してレビューすることも容易になります。

6.4. シナリオ4:実験的な修正の試行

現在の開発中のコードで、あるライブラリの新しいバージョンを試してみたい、あるいはコードの特定の部分を大きくリファクタリングしてみたい、といった実験を行いたいと考えています。ただし、この実験がうまくいく保証はなく、現在のメインの開発ラインに影響を与えたくありません。

git worktreeなしの場合:

  1. 現在の作業ブランチでの変更をコミットまたはスタッシュ。
  2. 新しいブランチを作成し、そこに切り替える。
  3. 実験的な修正を加える。
  4. 結果を確認する。
  5. もし失敗したら、そのブランチは破棄する。成功したら、その変更をどうにかして元のブランチに取り込む(チェリーピックなど)。

これもブランチ切り替えが必要で、元の作業に戻るのが面倒です。また、元のブランチに作業中の変更がある場合、それらを一時的にスタッシュする必要があり、コンテキストスイッチが発生します。

git worktreeありの場合:

  1. 現在の作業ブランチで作業中(例: ~/projects/my-project)。
  2. 実験用の新しい作業ツリーを作成します。新しいブランチを作成してそこで作業するのが良いでしょう。
    bash
    git worktree add ../my-project-experiment -b experiment-try-new-lib
  3. ~/projects/my-project-experimentディレクトリに移動し、そこで自由に実験的な変更(ライブラリの更新、コードの書き換えなど)を加えます。コミットも自由に行えます。
  4. 実験の結果を確認します。
  5. 実験が成功し、その変更をメインの開発ラインに取り込みたい場合は、experiment-try-new-libブランチから元のブランチにマージするなどの通常のGit操作を行います。
  6. 実験が失敗し、その変更が不要になった場合は、../my-project-experimentディレクトリを削除します。
    bash
    cd ~/projects/my-project # 元のリポジトリの作業ツリーに戻る
    git worktree remove ../my-project-experiment

このように、git worktreeを使えば、メインの開発ラインから完全に切り離された環境で安全に実験を行うことができます。成功した場合の統合も、ブランチ操作で容易に行えます。

これらのシナリオからわかるように、git worktreeは、複数のタスクを同時に進めたい、他のブランチのコードを気軽に参照したい、特定のバージョンのコードを検証したい、といった様々な場面で、開発ワークフローを劇的に効率化する強力なツールです。

7. worktreeとブランチ戦略

git worktreeは、特定のブランチ戦略に依存するツールではなく、Gitのブランチモデルをより柔軟かつ効率的に利用するための補助ツールです。Git Flow、GitHub Flow、GitLab Flowなど、どのようなブランチ戦略を採用しているプロジェクトでも活用できます。

  • フィーチャーブランチ開発: 複数のフィーチャーブランチを並行して開発する際に、それぞれのフィーチャーブランチを作業ツリーとして作成し、同時に作業を進めることができます(シナリオ1)。
  • リリースブランチ管理: リリースブランチと開発ブランチ(developなど)を並行して管理する必要がある場合に、それぞれのブランチを作業ツリーとして開き、必要な修正やバックポート作業を効率的に行えます。
  • ホットフィックス: main(またはmaster)ブランチからホットフィックスブランチを作成し、それを別の作業ツリーで開いて緊急度の高い修正作業に迅速に取りかかることができます(シナリオ2のバグ修正応用)。

git worktree自体が新しいブランチ戦略を強いるものではありません。あなたのチームが採用している既存のブランチ戦略の中で、複数のブランチにまたがる作業が発生する際に、その作業をよりスムーズにするために利用する、という位置づけで捉えるのが適切です。

8. worktree利用時のヒントとベストプラクティス

git worktreeをより快適に、安全に使うためのいくつかのヒントとベストプラクティスを紹介します。

8.1. ディレクトリ命名規則を決める

複数の作業ツリーを作成する場合、それぞれのディレクトリ名を分かりやすくすることが非常に重要です。どのディレクトリがどのブランチ/コミットを参照しているのか、一目でわかるように命名規則を決めておきましょう。

例:

  • my-project-main (メインの作業ツリー、mainブランチ)
  • my-project-feat-a (feature-aブランチ)
  • my-project-bug-123 (bugfix/123ブランチ)
  • my-project-v1.0.0 (v1.0.0タグ/コミット)
  • my-project-review-pr-456 (プルリクエスト456のブランチ)

8.2. ターミナルやIDEの設定を活用する

現在作業している作業ツリーの場所や、チェックアウトしているブランチが常に表示されるように、ターミナルのプロンプトやIDEの設定を活用しましょう。これにより、誤った作業ツリーでコマンドを実行するリスクを減らせます。

多くのターミナルエミュレータやシェル(Bash, Zshなど)では、現在のGitブランチをプロンプトに表示するように設定できます。IDEも通常、ウィンドウのタイトルバーやステータスバーに現在のプロジェクトディレクトリとGitブランチを表示します。

8.3. 不要になった作業ツリーはこまめに削除する

前述の通り、作業ツリーはディスク容量を消費します。タスクが完了し、その作業ツリーが不要になったら、すぐにgit worktree removeコマンドで削除するように習慣づけましょう。

8.4. .gitignore の活用

追加の作業ツリー固有の一時ファイルや設定ファイルがある場合は、.gitignoreに適切に設定しておきましょう。

8.5. Dotfiles や環境設定の共有

複数の作業ツリーで作業する場合、エディタの設定、リンターの設定、ビルドツールの設定など、開発環境に関連するファイル(いわゆるdotfilesなど)を共有したい場合があります。これらをリポジトリ内に含めるか、外部からシンボリックリンクなどで参照させるかなど、チーム内で方針を決めておくと良いでしょう。

8.6. メインの作業ツリーは常に最新の状態に近く保つ

もし可能であれば、メインの作業ツリーはチームの主要な開発ライン(例: mainブランチ)の最新の状態に近く保っておくと、他の作業ツリーとの連携(例: mainからのリベース、他のブランチのマージなど)がスムーズに行えることが多いです。

9. よくある質問 (FAQ)

Q1: 同じブランチを複数の作業ツリーでチェックアウトできますか?

いいえ、できません。 Gitの仕様により、特定のブランチは同時に一つの作業ツリーでしかチェックアウトできません。これは、同じブランチに対して複数の場所で同時に変更が加えられることによる混乱やコンフリクトを防ぐためです。

もし同じブランチの状態を複数の場所で参照したい場合は、特定のコミットIDを指定してデタッチドHEADの作業ツリーを作成するか、そのブランチから一時的な別のブランチを作成して作業ツリーを作る方法があります。

Q2: git clonegit worktree add の違いは何ですか?

git clone は、リモートリポジトリの完全なコピーを新しく作成します。これには、すべての履歴(.gitディレクトリ)と、デフォルトブランチ(通常はmain/master)のファイル群が含まれます。新しく作成されたディレクトリは、それ自体が独立したGitリポジトリとして機能します。

git worktree add は、既存のローカルリポジトリに対して、追加の作業ディレクトリを作成するものです。リポジトリ本体(.gitディレクトリ)は元の場所の一つだけです。追加の作業ツリー内の.gitファイルは、元のリポジトリの内部にある管理情報への参照です。

つまり、git cloneは完全に独立したリポジトリを作成するのに対し、git worktree addは一つのリポジトリに複数の作業場所を持たせる機能です。worktreeは、同じリポジトリ内で複数のブランチ/コミットを同時に扱いたい場合に効率的です。

Q3: 作業ツリーを削除すると、ブランチも削除されますか?

いいえ、削除されません。 git worktree remove <path>コマンドは、あくまで作業ツリーのディレクトリとその関連付けを削除するものです。その作業ツリーでチェックアウトしていたブランチ自体は、リポジトリ本体(.gitディレクトリ)に残ります。

ブランチを削除したい場合は、別途git branch -d <branch_name>コマンドを実行する必要があります。

Q4: 作業ツリー内で git add, git commit, git push は通常通り使えますか?

はい、使えます。 各作業ツリーは独立した作業環境として機能します。それぞれの作業ツリーのディレクトリに移動して、通常のGitコマンド(git status, git add, git commit, git pull, git push, git merge, git rebaseなど)をブランチ操作含めて実行できます。

例えば、feature-aブランチを作業ツリーとして開いているディレクトリでgit commitを実行すると、そのコミットはfeature-aブランチに追加されます。git pushすれば、リモートのfeature-aブランチに反映されます。

Q5: .git ディレクトリはどうなりますか?

メインの作業ツリーのルートディレクトリには、通常の.gitディレクトリがあります。追加の作業ツリーのルートディレクトリにも.gitという名前のファイルまたはディレクトリが存在しますが、これは実際のGitリポジトリ本体ではなく、元のリポジトリ内の特定のディレクトリ(.git/worktrees/<作業ツリーID>)への参照を含むファイルです。

Gitは、この参照をたどって、すべての作業ツリーが共有するリポジトリ本体のデータにアクセスします。追加の作業ツリーに関連するメタデータ(どのブランチがチェックアウトされているかなど)は、元のリポジトリの.git/worktrees/<作業ツリーID> ディレクトリに保存されます。

Q6: WindowsとmacOS/Linuxでの違いはありますか?

コマンドの基本的な使い方や概念に違いはありません。ただし、パスの区切り文字(Windowsは\、macOS/Linuxは/)や、ファイルシステムの大文字小文字の区別などのOS固有の特性には注意が必要です。

git worktree add ../feature-a feature-aのように相対パスを使う場合、実行しているターミナルのカレントディレクトリと、追加したい作業ツリーの場所の関係を正しく指定する必要があります。絶対パスを使う場合は、OSのパス形式に従ってください。

10. まとめ

この記事では、Gitのworktreeコマンドについて、その基本的な概念から、並行開発を効率化するためのメリット、注意点、そして具体的な使い方や応用例、さらには利用上のヒントやよくある質問まで、詳細に解説しました。

git worktreeは、一つのGitリポジトリに対して複数の独立した作業ディレクトリを関連付けることで、ブランチ切り替えの手間やコンテキストスイッチのコストを排除し、複数のタスクを同時に効率的に進めることを可能にする強力なツールです。

  • Feature開発とバグ修正の並行作業
  • 過去のバージョンや他のブランチのコード参照
  • Pull Requestのローカル検証
  • 実験的な変更の試行

など、様々なシナリオであなたの開発体験を向上させることができます。

もちろん、追加のディスク容量が必要になったり、複数の作業ツリーを管理することによる混乱の可能性といったデメリットもありますが、適切なディレクトリ命名規則やツール設定、そして不要になった作業ツリーのこまめな削除といったベストプラクティスを守ることで、これらのデメリットは最小限に抑えることができます。

Gitを使った開発で「もっと効率を上げたい」「ブランチ切り替えが面倒だ」と感じている方は、ぜひ今日からgit worktreeをあなたのワークフローに取り入れてみてください。きっと、その便利さに驚くはずです。

さあ、git worktree addコマンドを試して、並行開発の新しい扉を開きましょう!


コメントする

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

上部へスクロール