RAKSUL TechBlog

RAKSULグループのエンジニアが技術トピックを発信するブログです

git worktree × claude code で並列開発を実践する

git worktree × AI コーディングアシスタントで並列開発を実践する

PRを小さく保ちながら複数機能を同時に進める方法

はじめに

こんにちは。ノバセルの戸辺です。

この記事は

の 7 日目です。

Claude Code や Cline などの AI コーディングアシスタントを使った開発の並列化は、すでに多くのエンジニアが実践しています。AI に作業を任せている間に別の作業を進める、複数の Terminal で同時に異なる機能を開発する、といったワークフローは一般的になりつつあります。

Anthropic 公式の Claude Code: Best practices for agentic coding でも、セクション 6「Uplevel with multi-Claude workflows」で git worktree を使った並列開発が推奨されています。

Using git worktrees enables you to run multiple Claude sessions simultaneously on different parts of your project, each focused on its own independent task. For instance, you might have one Claude refactoring your authentication system while another builds a completely unrelated data visualization component.

git worktree の基本的な使い方を解説するチュートリアルは多くありますが、実際の開発現場でどのように運用するのか、PR をどう管理するのか、依存関係のある機能をどう進めるのか、といった実践的なノウハウはあまり共有されていません。

この記事では、git worktree と AI コーディングアシスタントを組み合わせた並列開発のワークフローを、実際のプロジェクトでの運用経験をもとに解説します。この記事を読めば、worktree を使った並列開発を実践レベルで始められることを目指しています。

このワークフローが解決する問題

PR が大きくなりすぎる

機能開発を進めていると、気づけば PR が数千行の差分になっていることがあります。大きな PR には以下の問題があります。

  • レビュアーの負担が大きい
  • レビューに時間がかかり、マージまでの時間が長くなる
  • バグが混入しても発見が難しい
  • コンフリクトが発生しやすい

レビュー待ちでブロックされる

PR を出した後、レビュー待ちの間に何もできなくなることがあります。特に依存関係のある機能を開発している場合、前の PR がマージされるまで次に進めないという状況に陥りがちです。

解決策:小さな PR の依存チェーン + 複数 worktree での並行作業

これらの問題を解決するために、以下のアプローチを取ります。

  1. 機能を小さな単位に分割して依存チェーンを作る:1つの機能を複数の小さな PR に分割し、それぞれを依存関係として連結する
  2. 複数の worktree で異なる機能を並行開発する:独立した機能は別々の worktree で同時に進める
  3. AI コーディングアシスタントに作業を任せながら並列化する:各 Terminal で AI が作業している間に、別の作業を進める

全体像:どんな開発環境になるか

このワークフローを実践すると、開発環境は以下のようになります。

4 つの Terminal と GitHub Web UI

  • Terminal を 4 つ並列配置
    • 3 つは並行開発用(それぞれ異なる worktree / 機能)
    • 1 つはシェルコマンド実行用(worktree 一覧確認、git 操作など)
  • GitHub Web UI でレビュー
    • PR の確認・レビューはブラウザで
    • Editor は基本的に開かない

Editor を開かない理由や、tmux を使わない理由については後述します。

git worktree とは

基本概念

git worktree は、1 つのリポジトリに対して複数の作業ディレクトリ(working tree)を持つ機能です。通常、git リポジトリは 1 つの作業ディレクトリしか持てませんが、worktree を使うと複数のブランチを同時にチェックアウトした状態で作業できます。

$ ls -la | grep novasell-one
drwxr-xr-x  22 j.tobe  staff   704 12  1 11:36 novasell-one
drwxr-xr-x  22 j.tobe  staff   704 12  1 23:52 novasell-one-auth
drwxr-xr-x  24 j.tobe  staff   768 12  1 23:18 novasell-one-proposal
drwxr-xr-x  22 j.tobe  staff   704 12  1 23:42 novasell-one-send-email

このように、novasell-one(メインのリポジトリ)に加えて、novasell-one-authnovasell-one-proposalnovasell-one-send-email という 3 つの worktree が存在しています。それぞれが独立したディレクトリとして存在し、異なるブランチをチェックアウトした状態になっています。

基本コマンド

# worktree の作成(既存ブランチをチェックアウト)
git worktree add ../novasell-one-auth feature/auth/setup

# worktree の作成(新規ブランチを作成しながら)
git worktree add -b feature/auth/setup ../novasell-one-auth main

# worktree の一覧表示
git worktree list

# worktree の削除
git worktree remove ../novasell-one-auth

前述の claude code best practice でもこのように、main branch と worktree が同じ階層になるような構成がとられていますが、たまに worktree の紹介をしているもので、main branch の下に worktree ディレクトリを作っているものを目にします

しかしその方法だと .gitignore の管理が複雑になったり階層構造が一つずれた感覚になったりするなどの不便さがあり、worktree そのものが嫌になってしまうのでお勧めしません

並行開発しなくても worktree は便利

少し余談ですが、実は、並行開発をしない場合でも worktree は非常に便利です。

main の動作確認で stash が不要

従来のワークフローでは、feature ブランチで開発中に main の動作確認をしたい場合、以下のような手順が必要でした。

# 従来のワークフロー
git stash                    # 作業中の変更を退避
git checkout main            # main に切り替え
# ... 動作確認 ...
git checkout feature/xxx     # feature に戻る
git stash pop               # 変更を復元

worktree を使っていれば、単に main のディレクトリに cd するだけです。

# worktree を使ったワークフロー
cd ../novasell-one          # main のディレクトリに移動
# ... 動作確認 ...
cd ../novasell-one-auth     # 元の作業ディレクトリに戻る

他メンバーのレビュー対応も楽

他のメンバーの PR をレビューする際、ローカルで動作確認が必要なことがあります。従来は stash してからブランチを切り替える必要がありましたが、worktree があれば専用のディレクトリでチェックアウトするだけです。

このように、「とりあえず新しい機能開発は worktree で始める」というのが良い習慣になります。

ディレクトリ構成とブランチ命名規則

worktree の命名

worktree のディレクトリ名は、main のリポジトリ名をプレフィックスにして、機能名をサフィックスにします。

novasell-one/              # main(メインのリポジトリ)
novasell-one-auth/         # OAuth 認証機能
novasell-one-send-email/   # メール送信機能
novasell-one-proposal/     # 他の機能開発

このルールにより、ls や Tab 補完で関連するディレクトリがまとまって表示されます。

ブランチ命名規則

ブランチは以下の命名規則に従います。

[feature|fix|spec]/[feature-name]/xxx
  • feature: 機能開発全般(テスト実装、CDK 実装なども含む)
  • fix: バグフィックス(hotfix で出す想定のもの)
  • spec: 実装を含まず、仕様書や提案書を作成する

feature-name は worktree と紐づいた一連のタスクの名前、xxx はその中での具体的な作業内容を端的に表す名前です。

例:

feature/send-email/1-deps
feature/send-email/2-models
feature/auth/oauth-client
spec/proposal/requirements

なぜ命名規則が重要か

命名規則を決めていないと、以下のようにブランチが乱立して何がどの機能なのかわからなくなります。

命名規則なしで乱立した worktree と branch たち

このスクリーンショットでは、feature/frontend-oauth-authfeature/proposalimplement/proposal-generation-lambda-phase1 など、異なる命名パターンが混在しており、どれがどの機能に属するブランチなのかが一目でわかりません。

命名規則を統一することで、ブランチの整理と理解が容易になります。また、AI コーディングアシスタントにもこのルールを持たせておくと、ブランチ作成時に自動的に従ってくれます。

Step 1:OpenSpec で仕様を固める

実装を始める前に、何を作るかを明確にすることが重要です。ここでは OpenSpec を使って仕様を策定します。

OpenSpec は、AI コーディングアシスタントと人間が「何を作るか」について合意してから実装に入るためのワークフローを提供するツールです。

spec ブランチで仕様策定

# 仕様策定用の worktree を作成
git worktree add -b spec/send-email/requirements ../novasell-one-proposal main

cd ../novasell-one-proposal

AI コーディングアシスタントと /openspec:proposal コマンドなどを使って対話しながら、以下を明確にします。

  • 機能の要件
  • 技術的な設計
  • PR の分割粒度

特に PR の分割粒度をここで決めておくことが重要です。「どこまでを 1 つの PR にするか」を事前に合意しておくことで、実装がスムーズに進みます。

Step 2:依存チェーン PR の実践

なぜ細かく分けるか

1 つの機能を 1 つの大きな PR にまとめるのではなく、複数の小さな PR に分割し、依存関係を持たせます。

メリット: 1. 各 PR が小さくレビューしやすい:数百行程度の差分なら、レビュアーの負担が軽い 2. 依存関係が明確:何がどの順番でマージされるべきかが明確 3. 並列レビューが可能:1 つ目が approve される前に、後続の PR をドラフトで出しておける

実例:メール送信機能の 9 段階分割

以下は、メール送信機能を 9 つの PR に分割した例です。

PR の依存チェーン

main
  ↑
  └─ feature/send-email/1-deps (Resend SDK + 例外)
      ↑
      └─ feature/send-email/2-models (データモデル)
          ↑
          └─ feature/send-email/3-api-client (API クライアント)
              ↑
              └─ feature/send-email/4-email-service (Email Service)
                  ↑
                  └─ feature/send-email/5-scheduler (Scheduler Service)
                      ↑
                      └─ feature/send-email/6-lambda (Lambda)
                          ↑
                          └─ feature/send-email/7-database (Database)
                              ↑
                              └─ feature/send-email/8-monitoring (CloudWatch)
                                  ↑
                                  └─ feature/send-email/9-tests-docs (テスト & ドキュメント)

各 PR の構成: - PR #1: mainfeature/send-email/1-deps - PR #2: feature/send-email/1-depsfeature/send-email/2-models - PR #3: feature/send-email/2-modelsfeature/send-email/3-api-client - ...

ポイントは、各 PR の merge 先(base)を前の PR のブランチに設定することです。これにより、依存関係が明確になり、GitHub 上でも依存の連鎖が可視化されます。

具体的な作り方

# 1. worktree の作成
git worktree add -b feature/send-email/1-deps ../novasell-one-send-email main
cd ../novasell-one-send-email

# 2. 最初の実装を行い、PR を作成
# ... AI コーディングアシスタントで実装 ...
git push -u origin feature/send-email/1-deps
gh pr create --base main --title "feat(email): Resend SDK と例外クラスの追加"

# 3. レビュー待ちの間に、次のブランチを派生
git checkout -b feature/send-email/2-models

# 4. 次の実装を行い、PR を作成(base を前のブランチに)
# ... AI コーディングアシスタントで実装 ...
git push -u origin feature/send-email/2-models
gh pr create --base feature/send-email/1-deps --title "feat(email): データモデルの追加"

# 5. 以降、同様に繰り返す

PR description に依存関係を明記

PR の description には、依存関係を明記しておきます。

## Summary

メール送信機能のためのユニットテストとドキュメントを追加します。

This is **PR #9 of 9** - Final PR in the Email Sending feature implementation.

## Dependencies

Depends on: All previous PRs (PR #1-8) [feat(cdk): AWS CDK環境セットアップ #1-8]

これにより、レビュアーが依存関係を把握しやすくなり、マージ順序を間違えるリスクも減ります。

Step 3:複数 worktree で並行開発

独立した機能を同時に進める

OAuth 認証機能とメール送信機能のように、依存関係のない機能は完全に並列で開発できます。

# Terminal 1: OAuth 認証機能
cd ~/src/github.com/example/novasell-one-auth
claude  # AI コーディングアシスタントを起動

# Terminal 2: メール送信機能
cd ~/src/github.com/example/novasell-one-send-email
claude  # AI コーディングアシスタントを起動

# Terminal 3: 仕様策定
cd ~/src/github.com/example/novasell-one-proposal
claude  # AI コーディングアシスタントを起動

# Terminal 4: シェルコマンド用
cd ~/src/github.com/example/novasell-one
# git 操作、worktree 一覧確認など

各 Terminal で AI コーディングアシスタントが作業している間に、別の Terminal で指示を出したり、シェル用の Terminal でコマンドを実行したりできます。

依存チェーン PR のマージフロー

依存チェーンを作った後、実際にどのようにマージしていくかを説明します。

親ブランチがマージされると merge 先が自動で切り替わる

GitHub では、ある PR の base ブランチ(merge 先)が main にマージされると、その PR の base は自動的に main に切り替わります。

例えば、以下の状態を考えます。

- PR #1: main ← feature/send-email/1-deps
- PR #2: feature/send-email/1-deps ← feature/send-email/2-models

PR #1 がマージされると、PR #2 の base は自動的に main に変更されます。

- PR #1: (マージ済み)
- PR #2: main ← feature/send-email/2-models

この仕組みを利用して、親から順にレビュー・マージしていくと、結果的にすべての PR が順次 main にマージされていきます。

マージ後のブランチ更新フロー

親ブランチが main にマージされた後、子ブランチでは以下の作業を行います。

# 1. main を最新化
git fetch origin
git checkout main
git pull origin main

# 2. 子ブランチに移動して main をマージ
git checkout feature/send-email/2-models
git merge main

# 3. コンフリクトがあれば解消
# ... コンフリクト解消 ...
git add .
git commit

# 4. プッシュして PR を更新
git push origin feature/send-email/2-models

これを各 PR について順番に行っていくことで、依存チェーン全体が main に統合されていきます。

なぜ Editor を開かないか

このワークフローでは、基本的に Editor(VS Code、Cursor など)を開きません。理由は以下の通りです。

細かいところを自分で直したくなる誘惑を断つ

Editor を開くと、「ここは自分で直した方が早い」という誘惑に駆られます。しかし、AI コーディングアシスタントに任せることで、自分は別の作業に集中できます。

AI の性能向上で人間の編集がボトルネックになる

AI コーディングアシスタントの性能は日々向上しています。近い将来、人間が Editor で編集する速度がボトルネックになることが予想されます。今から Editor を使わないワークフローに慣れておくことで、AI の進化を最大限に活用で切るのではないかと考えています。仮にこの予測を外したとしても、Editor ありのスタイルにはすぐに戻れると思いますし、ここに張ってもリスクは小さいと考えています。

画面占有の問題

複数の Terminal を並べて並行開発する場合、これを Editor 込みでやろうとすると画面を大きく占有します。Terminal 4 つ + GitHub Web UI という構成の方が、画面を効率的に使えます。

例外:Markdown プレビューなど

とはいえ、Markdown のプレビューを見たい場合など、Editor が便利な場面もあります。そのような場合は軽量で起動が速い Zed を使っています。あくまで「見る」ためのツールであり、「編集する」ためには使いません。

その場合も、claude code から離れずその console のなかで

!zed [開きたいファイルパスまたはフォルダのパス]

とかで開いています。ほんの少し無駄な token を消費してしまいますがそのくらいはご愛嬌です。

コードレビューも CLI / GitHub Web UI

コードレビューも Editor 上では行いません。CLI(gh pr viewgh pr diff など)や GitHub Web UI で行います。

なぜ tmux を使わないか

あと、結局 tmux も使っていません。

Terminal を複数使うなら tmux を使うべきでは?という疑問があるかもしれません。しかし、このワークフローでは tmux を使っていません。

スクロール問題

tmux はデフォルトでスクロールが直感的ではありません。当然設定で解決可能ですが(set -g mouse on など)、設定・学習コストが増えるだけです。

Terminal 複数起動にデメリットがない

OS のTerminal アプリ(macOS の Terminal.app や iTerm2 など)で複数ウィンドウを開くことに、特にデメリットはありません。Mission Control や Alt+Tab で簡単に切り替えられます。

長い出力にはネイティブスクロールが快適

AI コーディングアシスタントは長い出力をすることが多いです。ネイティブ Terminal のスクロールの方が快適にログを追えます。

物理的分離の視認性

4K モニタや複数モニタが一般的な現在、「1 画面に詰め込む」より「物理的に分ける」方が視認性が高いです。各 Terminal が独立したウィンドウになっていることで、どの作業がどこで行われているかが直感的にわかります。

サーバルームに赴いて、オンサイト保守で CUI と睨めっこするとか、リモートに用意した開発サーバに ssh ではいるとかそういう時でなければ tmux は不要かもしれません。

私の場合、個人の開発環境が自宅サーバ上にあるので、それをリモートで扱うときはもちろん便利に tmux を活用しています。

運用 Tips

シェル用 Terminal を 1 つ確保

並行開発用の Terminal とは別に、シェルコマンド実行用の Terminal を 1 つ確保しておくと便利です。

  • git worktree list で worktree の一覧確認
  • ls -la | grep <repo-name> でディレクトリ確認
  • その他の git 操作

worktree の整理タイミング

PR がマージされたら、対応する worktree は削除します。

git worktree remove ../novasell-one-send-email

放置すると worktree が増えすぎて管理が大変になるので、定期的に整理しましょう。

まとめ

この記事では、git worktree と AI コーディングアシスタントを組み合わせた並列開発のワークフローを解説しました。

ポイントをまとめると:

  1. 並行開発しなくても worktree は便利:stash 不要で main の確認やレビュー対応ができる
  2. 依存チェーン PR で小さく保つ:機能を細かく分割し、依存関係を明確にする
  3. 複数 Terminal × 複数 worktree で並列化:AI に作業を任せながら別の作業を進める
  4. 命名規則を統一する:worktree 名、ブランチ名のルールを決めて管理を楽にする

まずは「新しい機能開発は worktree で始める」ことから試してみてください。stash から解放されるだけでも、開発体験が大きく向上するはずです。