# Git Worktree で並行開発する方法：作業を混ぜない基本フロー

> Canonical: https://vxi.me/ja/posts/git-worktree-parallel-development/
> Locale: ja-jp
> Published: 2026-03-25
> Updated: 2026-03-25
> Markdown: https://vxi.me/ja/posts/git-worktree-parallel-development.md

複数機能を並行開発しようとすると、最初は「ブランチをいくつか作って、一つのリポジトリで `checkout` を切り替えればいい」と考えがちです。

短時間ならそれでも動きます。ただ、片方で新機能を作りながら別のバグを直し、さらにローカルサービスまで起動し始めると、どのコードを実行しているのか分からなくなりやすいです。

私は最終的に、メインのリポジトリは安定ブランチ用に残し、実際の開発は `git worktree` で機能ごとに独立ディレクトリを作る形に固定しました。

これなら一台のマシンで複数ブランチを同時に扱っても、ディレクトリ、プロセス、ビルド成果物が混ざりにくくなります。

## なぜブランチ切り替えではなく Worktree にしたのか

難しいのは「新しいブランチを作ること」ではありません。

本当に困るのは、次のようなズレです。

- 新機能を確認しているつもりでも、サービスは古いディレクトリから起動している
- 別ブランチのビルド成果物が残っている
- `git add .` で関係ない生成物までコミットする
- 本番障害対応と新機能開発が同じ作業ツリーで混ざる

`git worktree` は、ブランチごとに別の作業ディレクトリを持てます。

私にとって一番大きい利点は、ブランチ数ではなく**作業環境そのものを分離できること**です。

## 私が固定しているディレクトリ規約

長く使うなら、最初にルールを決めた方が楽です。

私の例では次のようにしています。

- メインリポジトリ：`/Users/kuangyongjie/charting_library`
- worktree のルート：`/Users/kuangyongjie/worktrees`
- ブランチ名：`codex/<feature-name>`
- メインブランチ：`master`

機能開発は例えば次の場所に置きます。

```text
/Users/kuangyongjie/worktrees/hotspot-ff
```

パスを見るだけで、メインリポジトリなのか機能ブランチなのか判断できるようにしておくのがポイントです。

## 作成手順

最初に worktree 用ディレクトリを準備します。

```bash
mkdir -p /Users/kuangyongjie/worktrees
```

次にメインリポジトリから、新しいブランチと worktree を同時に作ります。

```bash
REPO=/Users/kuangyongjie/charting_library
WT=/Users/kuangyongjie/worktrees/<feature-name>
BRANCH=codex/<feature-name>
BASE=master

# リモートが使えるなら master を更新
# git -C "$REPO" pull --rebase central "$BASE"

git -C "$REPO" worktree add "$WT" -b "$BRANCH" "$BASE"
cd "$WT"
git branch --show-current
```

正常なら、最後に次のようなブランチ名が出ます。

```text
codex/<feature-name>
```

ここから先、この機能の編集、ビルド、テストはすべて `"$WT"` 側で行います。

## 開発とテストは worktree 内だけで行う

このルールはかなり重要です。

例えばフロントエンドがサブディレクトリにあるなら、必ず対象 worktree に入ってからビルドします。

```bash
cd "$WT/trendradar-service/trendradar-web"
npm run build
# 本番向けビルド
# npm run build:multi-layer
```

私自身、「コードを変更したのに画面が変わらない」という問題に何度も当たりました。

原因がコードではなく、サービスが別ディレクトリから起動していたというケースです。

そのため、表示が変わらないときはフレームワークより先にプロセスの `cwd` を確認します。

```bash
lsof -nP -iTCP:<port> | sed -n '1,5p'
ps -p <pid> -o pid,ppid,command
lsof -p <pid> | rg "cwd"
```

最終的に `cwd` が次のような worktree パスを指していることを確認します。

```text
/Users/kuangyongjie/worktrees/<feature-name>/...
```

ここが違っていれば、そもそも対象ブランチをテストしていません。

## コミット時に git add . を避ける理由

並行開発では、私は意図的に保守的にコミットします。

worktree の中にキャッシュやローカル DB、スナップショット、OS の生成ファイルが残っていることがあるためです。

例えば次のようなものです。

- `__pycache__`
- `*.db`
- `snapshot_*`
- `.DS_Store`

そのため、基本は対象ファイルだけを追加します。

```bash
cd "$WT"
git add <file1> <file2> <file3>
git status --short
git commit -m "feat/fix: <summary>"
```

`git status --short` を一度見るだけでも、余計なファイルを混ぜる事故をかなり減らせます。

## マージはメインディレクトリだけで行う

機能が完成した後のマージは worktree 側ではなく、メインリポジトリ側で行います。

```bash
cd /Users/kuangyongjie/charting_library
git branch --show-current   # master であることを確認

# 必要なら先に更新
# git pull --rebase central master

git merge --no-ff codex/<feature-name>
```

重要なのは `--no-ff` 自体より、**今いるディレクトリとブランチを確認してからマージすること**です。

もし次のエラーが出たら、

```text
MERGE_HEAD exists
```

前回のマージが終わっていない可能性があります。

```bash
git merge --abort
```

で一度戻してから、改めて更新とマージを行います。

リモートへ push する場合は次のようにします。

```bash
cd /Users/kuangyongjie/charting_library
git push <remote> master
```

環境によってリモート名は `origin` とは限りません。私の環境では `central` を使うケースもあります。

## Fast-forward を使いたい場合

「機能ブランチを独立起動して確認し、問題なければ merge commit を作らず統合したい」なら fast-forward 前提でも構いません。

例えば次の流れです。

```bash
cd /Users/kuangyongjie/charting_library
git checkout master
git pull --rebase central master

git worktree add /Users/kuangyongjie/worktrees/hotspot-ff -b codex/hotspot-ff master
```

サービスも必ずその worktree から起動します。

```bash
cd /Users/kuangyongjie/worktrees/hotspot-ff/trendradar-service
./venv/bin/uvicorn app.main:app --host 127.0.0.1 --port 9544
```

別ターミナルから PID と `cwd` を確認します。

```bash
lsof -nP -iTCP:9544 -sTCP:LISTEN
ps -p <PID> -o pid,ppid,command
lsof -a -p <PID> -d cwd -Fn
```

「分岐ブランチでテストした」と思っていても、実際には別ディレクトリのプロセスを見ていた、という失敗はかなり起こりやすいです。

## 私が固定しているルール

長期運用するなら、最低限これだけは固定しておくと安定します。

- 1 機能につき 1 worktree
- 1 タスクや 1 会話を 1 worktree に対応させる
- 作業開始時に `git branch --show-current`
- コミット前に `git status --short`
- マージはメインディレクトリの `master` だけで行う

特別なテクニックではありませんが、並行開発を壊しにくくするのはこうした基本動作です。

## よくある問題

### ローカル画面が古いまま

まずコードを疑う前に、サービスプロセスの `cwd` が対象 worktree か確認します。

その上で、そのブランチ内でフロントエンドを再ビルドしたか確認します。

### fatal: 'origin' does not appear to be a git repository

多くの場合は Git 自体ではなく、リモート名の違いです。

```bash
git remote -v
```

で実際の名前を確認してから push します。

### MERGE_HEAD exists

前回のマージが途中です。

```bash
git merge --abort
```

で中断してから、改めて進めます。

### フロントエンドだけ変更した場合、バックエンド再起動は必要か

通常は不要です。静的アセットの再ビルドと配置が済んでいれば、キャッシュを更新するだけで反映されることも多いです。
