1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

git worktree のポート整備をSkillで自動化した

1
Last updated at Posted at 2026-05-17

はじめに

個人で以下の Web アプリを運営しています。

関連記事

Next.js + Go + PostgreSQL のモノレポ構成です。

このアプリの開発で git worktree をよく使うのですが、ローカル環境でのポートの競合に悩まされていました。その問題をシェルスクリプト + Claude Code Skill で解決しました。

同じような悩みを抱えている方の助けになると幸いです。

git worktreeとは?

git worktree は1つのリポジトリから複数のブランチを 別々のディレクトリにチェックアウトできる機能 です。普通の git checkout での切り替えと違って、各ブランチが独立したディレクトリ・独立した node_modules・独立した起動状態を持てます。

個人開発で次のような状況が増えてきたので使い始めました。

  • 複数の機能を 並行で進めたい (Claude Code を別セッションで並行起動するときに特に便利)
  • ブランチ切り替えのたびに stash・依存再インストールをしたくない

ぶつかった問題

git worktree は便利なのですが、開発でフロントエンド (npm run dev) と バックエンド・DB (Docker) を同時に起動するので、worktree を増やすと

  • フロントエンド / バックエンドの ポートが衝突
  • フロントが叩く API URL が worktree ごとに違う
  • CORS の許可ドメインも増える
  • 作業終了後の片付け (worktree削除・ブランチ削除・サーバー停止) も毎回手動

という問題がありました。

要するに、worktree を作るたびに環境変数とポートの調整が地味に面倒でした。

解決方法

設計のポイント(2つのモードに分ける)

作業内容に応じて2モードを使い分けることにしました。

モード A : フロントエンドのみ変更

フロントエンドだけ触る作業のときは worktree 内でDocker を立ち上げず、main のバックエンドを共有するようにしました。

[Worktree Frontend (3100台)]
    ↓
[Main Backend (8080)]  ← main で起動済みのものを共有
    ↓
[Main DB (5432)]

Docker をまったく起動しなくて済むので、worktree の立ち上げが軽くて早いです。

モード B: バックエンド・DBも変更

バックエンドの変更が伴う時は worktree 内で Docker も起動するようにしました。

[Worktree Frontend (3100台)]
    ↓
[Worktree Backend (8100台)]  ← worktree専用に Docker 起動
    ↓
[Worktree DB (5500台)]       ← worktree専用に Docker 起動

バックエンドのコード変更だけでなく DBのスキーマ変更も worktree で安全に試せる ように、Backend と DB をまとめて worktree 内に起動します。
main のデータベースに影響を与えないので、マイグレーションの検証もこちらで行えます。

全体構成

  • シェルスクリプト (setup-worktree.sh)の作成
    • ポート割り当て
    • 環境ファイルの自動生成
  • Skillsで以下を1コマンド化
    • worktreeを作成
    • 起動(上記スクリプトでポート割り当て)
    • 片付け
    • モードA/Bの分岐も Skill 側に押し込める

シェルスクリプト

worktree 名のハッシュからポートを決定的に割り当て、衝突したら次のスロットにずらします。
Frontend / Backend / DB の3つ分のポートを worktree ごとに用意します。

シェルスクリプトの内容
scripts/setup-worktree.sh
set -euo pipefail

# 実行場所の確認 (worktree のルートで実行されているか)
if [ ! -f "docker-compose.yml" ]; then
  echo "Error: docker-compose.yml が見つかりません。" >&2
  exit 1
fi

CURRENT_DIR="$(pwd)"
WORKTREE_NAME="$(basename "$CURRENT_DIR")"

# main repo の場所を特定 (worktree の git common dir の親)
GIT_COMMON_DIR="$(git rev-parse --git-common-dir 2>/dev/null || echo "")"
if [ -z "$GIT_COMMON_DIR" ]; then
  echo "Error: git リポジトリではありません。" >&2
  exit 1
fi
MAIN_REPO="$(cd "$GIT_COMMON_DIR/.." && pwd)"

if [ "$CURRENT_DIR" = "$MAIN_REPO" ]; then
  echo "Error: このスクリプトは worktree 用です。" >&2
  exit 1
fi

# worktree名のSHA1ハッシュ先頭4桁(hex)から 1〜50 のスロット番号を計算
# Frontend port: 3100〜3149, Backend port: 8100〜8149, DB port: 5500〜5549
HASH_HEX="$(printf '%s' "$WORKTREE_NAME" | shasum | cut -c1-4)"
SLOT=$(( 16#${HASH_HEX} % 50 + 1 ))

# ポート衝突を検出して自動で次のスロットへ
MAX_TRIES=50
TRIES=0
while [ $TRIES -lt $MAX_TRIES ]; do
  FRONTEND_PORT=$((3100 + SLOT - 1))
  BACKEND_PORT=$((8100 + SLOT - 1))
  DB_PORT=$((5500 + SLOT - 1))
  if ! lsof -iTCP:$FRONTEND_PORT -sTCP:LISTEN >/dev/null 2>&1 \
     && ! lsof -iTCP:$BACKEND_PORT -sTCP:LISTEN >/dev/null 2>&1 \
     && ! lsof -iTCP:$DB_PORT -sTCP:LISTEN >/dev/null 2>&1; then
    break
  fi
  SLOT=$(( SLOT % 50 + 1 ))
  TRIES=$((TRIES + 1))
done

if [ $TRIES -ge $MAX_TRIES ]; then
  echo "Error: 空きポートが見つかりません" >&2
  exit 1
fi

write_if_absent() {
  local path="$1"
  local content="$2"
  if [ -f "$path" ]; then
    echo "  skip: $path (既に存在)"
  else
    printf '%s' "$content" > "$path"
    echo "  生成: $path"
  fi
}

echo ""
echo "Worktree:      $WORKTREE_NAME"
echo "Frontend port: $FRONTEND_PORT"
echo "Backend port:  $BACKEND_PORT"
echo "DB port:       $DB_PORT"
echo ""

# 1. Compose 用の .env (worktree ルート)
#    Backend と DB は worktree 内で起動するため、Docker内部ネットワークで接続
write_if_absent "$CURRENT_DIR/.env" "\
BACKEND_PORT=$BACKEND_PORT
DB_PORT=$DB_PORT
DATABASE_URL=postgres://user:password@db:5432/hotaruika_db?sslmode=disable
"

# 2. Next.js 用の .env.local
#    デフォルトは Main backend (8080) を共有 (Mode A)
write_if_absent "$CURRENT_DIR/frontend/.env.local" "\
PORT=$FRONTEND_PORT
NEXT_PUBLIC_API_URL=http://localhost:8080
# Mode B (Worktree backend を使う) 場合は上をコメントアウトし、以下を有効化
# NEXT_PUBLIC_API_URL=http://localhost:$BACKEND_PORT
"

# 3. backend/.env を main からコピー (Mode B で worktree backend 起動時に必要)
if [ -f "$CURRENT_DIR/backend/.env" ]; then
  echo "  skip: backend/.env"
elif [ -f "$MAIN_REPO/backend/.env" ]; then
  cp "$MAIN_REPO/backend/.env" "$CURRENT_DIR/backend/.env"
  echo "  コピー: backend/.env (main から)"
fi

cat <<EOF

セットアップ完了。

  cd frontend && npm install              # 初回のみ
  PORT=$FRONTEND_PORT npm run dev

  → http://localhost:$FRONTEND_PORT
EOF

Skill

シェルスクリプトだけだとまだ毎回 git worktree addbash scripts/setup-worktree.shnpm installPORT=xxxx npm run dev を叩く必要があります。
これを Claude CodeSkill で1コマンド化しました。

Skillsの内容
.claude/skills/worktree-new/SKILL.md
---
name: worktree-new
description: 新規ワークツリーを作成して開発環境を起動する。ブランチ作成、setup-worktree.sh実行、依存インストール、devサーバー起動までを自動化。Use when user wants to start work in a new worktree, create a worktree for a feature, or begin parallel development.
allowed-tools: Bash, Read, Grep, Glob, AskUserQuestion
---

# Worktree New スキル

## Instructions

このスキルは新規ワークツリーを作成し、開発をすぐ始められる状態にする。

### 実行フロー

#### 1. 事前確認

main に居ること、未コミット変更がないことを確認:

```bash
git branch --show-current
git status
```

main 以外なら AskUserQuestion で確認、未コミット変更があれば中止。

#### 2. トピック名の確認

**AskUserQuestion** でユーザーに確認 (kebab-case)。
ブランチ名は `worktree-<topic>` 形式になる。

#### 3. モード選択

**AskUserQuestion** で確認:

```
[A] フロントエンドのみ (Main backend/DB を共有・推奨)
[B] バックエンド・DBも変更 (worktree専用 backend + DB を起動)
```

#### 4. ワークツリー作成

```bash
git worktree add .claude/worktrees/<topic> -b worktree-<topic> main
cd .claude/worktrees/<topic>
```

#### 5. セットアップ実行

```bash
bash scripts/setup-worktree.sh
```

出力から Frontend port / Backend port / DB port を抽出する。

#### 6. 依存パッケージのインストール (初回のみ)

```bash
cd frontend
[ -d node_modules ] || npm install
```

#### 7. (モードB のみ) .env.local 書き換え

```bash
sed -i.tmp "s|^NEXT_PUBLIC_API_URL=http://localhost:8080|NEXT_PUBLIC_API_URL=http://localhost:<backend-port>|" .env.local
rm .env.local.tmp
```

#### 8. (モードB のみ) Backend と DB を起動

```bash
docker compose up backend db
```

#### 9. Dev サーバー起動 (バックグラウンド)

```bash
PORT=<frontend-port> npm run dev
```

#### 10. 結果報告

```
✅ ワークツリー作成完了

  Path:     .claude/worktrees/<topic>
  Branch:   worktree-<topic>
  Mode:     A or B
  Frontend: http://localhost:<frontend-port>
  Backend:  Main共有 (8080) or Worktree (<backend-port>)
  DB:       Main共有 (5432) or Worktree (<db-port>)
```

### 安全規則

- main 以外のブランチでの実行は必ず確認
- 既存の同名ブランチ・worktreeとの衝突は中止
- npm install / docker / npm run dev の失敗時はそこで停止

Claude Code が SKILL.md の指示通りに、bash コマンドを実行したり、ユーザーにモードを聞いたり、結果をパースしたりしながら、自動でセットアップを進めてくれます。

マージ後の片付けも Skill 化しました。

Skillsの内容
.claude/skills/worktree-cleanup/SKILL.md
---
name: worktree-cleanup
description: 作業完了後のワークツリー片付け。devサーバー停止、Docker停止、worktree削除、ブランチ削除までを自動化。Use when user wants to clean up after PR merge, remove a worktree, or finish work on a worktree.
allowed-tools: Bash, Read, Grep, Glob, AskUserQuestion
---

# Worktree Cleanup スキル

## Instructions

このスキルはマージ後のワークツリー片付けを自動化する。

### 実行フロー

#### 1. 現在地と対象 worktree の特定

```bash
pwd
git worktree list
```

worktree 内なら対象自動判定、main なら複数候補から AskUserQuestion で選択。

#### 2. 未コミット変更チェック

```bash
git status --porcelain
```

ある場合は AskUserQuestion で破棄 or 中止を確認。

#### 3. マージ済みチェック

```bash
git branch --merged main | grep "worktree-<topic>"
```

マージされていない場合は AskUserQuestion で確認。

#### 4. 動作中の dev サーバーを停止

このセッションで起動した npm run dev を **TaskStop** で停止。

#### 5. Worktree backend / DB Docker の停止 (起動していれば)

```bash
docker ps --filter "name=<worktree-name>-" --format "{{.Names}}"
```

起動していれば worktree ルートで:

```bash
docker compose down
```

(backend と db のコンテナがまとめて停止・削除される)

#### 6. main へ移動・最新化

```bash
cd <main-repo-path>
git checkout main
git pull origin main
```

#### 7. Worktree 削除

```bash
git worktree remove .claude/worktrees/<topic>
```

#### 8. ローカルブランチ削除

```bash
git branch -d worktree-<topic>   # マージ済みなら -d
git branch -D worktree-<topic>   # 未マージで確認済みなら -D
```

#### 9. リモート追跡参照の prune

```bash
git fetch --prune
```

### 安全規則

- 未コミット変更がある場合は必ず確認
- 未マージブランチは確認なしに削除しない
- Docker停止前に該当ワークツリーのコンテナか確認 (他worktreeを誤って停止しない)
- main ブランチ自体は絶対に削除しない

効果

worktree作成

$ /worktree-new
> Topic: add-terms-page
> Mode: [A] フロントのみ
... (Claude が自動で全部実行)
> ✅ http://localhost:3115 で起動しました

このようにスラッシュコマンド1つで完結します。
ポート番号も Claude が出力から自動抽出して PORT=xxxx npm run dev まで起動してくれます。
worktree 作成〜開発開始までが 約1分 に短縮されました。

片付け

$ /worktree-cleanup
... (サーバー停止・Docker停止・worktree削除・ブランチ削除・main最新化)
> ✅ 完了

まとめ

ポート競合と環境変数の管理を、シェルスクリプトと Skills で複数ステップを自動化することができました。

今後もっとAIを工夫して活用していきたいです。

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?