🌳

Claude Codeで複数リポジトリ開発するのが面倒すぎたので自動化した話

に公開

TL;DR

最近、Claude Codeで複数のリポジトリを同時に扱う機会が増えてきて、毎回手作業でセットアップするのがめっちゃ面倒だなぁと思いました。
そこで、Fish FunctionとGit Worktreeを組み合わせて、チケット単位で全リポジトリを平等に扱える開発環境を一発で構築できるようにしてみました!

はじめに

Claude Codeでマルチリポジトリ開発したいことありますよね〜。自分も趣味開発や仕事での開発とかで、複数のリポジトリを横断して作業することが増えてきました。

Claude Codeには--add-dirオプションがあって、メインのリポジトリに他のリポジトリも追加できるんですが…

cd <main-dir>
$ claude --add-dir <another-dir>

これ使ってみると、なんだか 主従関係が生まれちゃうのが気持ち悪い んですよね!

メインのリポジトリがあって、サブのリポジトリがある、みたいな感じで、Claude Codeもカレントディレクトリを重視してる感じがするし、追加ディレクトリの方は提案精度が落ちるような気がしちゃいます(※完全に個人の感想です)。

それに、複数リポジトリで同じ機能を開発するときって、

  1. リポジトリAでブランチ作成
  2. リポジトリBでブランチ作成
  3. リポジトリCでブランチ作成
  4. 各ディレクトリに移動してClaude Code起動...

みたいな手作業がめっちゃ発生するんですよね。毎回やるには面倒だし、ブランチ名間違えたりとかミスも起きがち...

そこで考えた解決策

というわけで、 チケット単位で独立したワークスペースを作って、全部のリポジトリを平等に扱えるようにしよう! と思いました。

ざっくりいうと、~/ws/<ticket>/ っていう専用フォルダを作って、そこに必要なリポジトリを全部同じ階層で並べちゃうという作戦です。

基本的なアイデア

~/ws/TICKET-123/
├── repo-a/          # repo-a/TICKET-123ブランチ
├── repo-b/          # repo-b/TICKET-123ブランチ
├── repo-c/          # repo-c/TICKET-123ブランチ
└── .claude/
    └── settings.json

こんな感じで、全部のリポジトリが同じ階層に並んでて、どれがメインでどれがサブとかない状態です。しかも、各リポジトリはgit worktreeで軽量展開するので、元のリポジトリに影響しないし、クローンコストもゼロ!

でも、この環境を手動で作るのは絶対面倒だし続かないので... Fish functionで自動化しちゃいました

作ったもの

こんなFish functionを書いてみました:

function claude_workspace
    # チケットIDを入力
    echo "Enter ticket ID:"
    read ticket_id

    if test -z "$ticket_id"
        echo "Ticket ID is required"
        return
    end

    # ワークスペースディレクトリを作成
    set -l ws_dir "$HOME/ws/$ticket_id"
    mkdir -p "$ws_dir"

    # 最初のrepoを選択(ghqでリポジトリ一覧を取得→fzyで対話的選択)
    set -l first_repo (ghq list | fzy -l 15)

    if test -z "$first_repo"
        return
    end

    set -l selected_repos $first_repo

    # 追加のrepoを選択するか確認(複数リポジトリに対応)
    while true
        echo "Selected repos: $selected_repos"

        echo "Add more repos? (y/n/q)"
        read -n 1 choice
        echo

        switch $choice
            case y Y
                set -l next_repo (ghq list | fzy -l 15)
                if test -n "$next_repo"
                    set selected_repos $selected_repos $next_repo
                end
            case n N
                break
            case q Q
                return
            case '*'
                echo "Invalid choice. Use y/n/q"
        end
    end

    # 各リポジトリでworktreeを作成
    for repo in $selected_repos
        # ghqでリポジトリの実際のパスを取得
        set -l src_path (ghq list -p | grep "$repo\$")

        # リモートから最新の状態を取得
        echo "Fetching $repo..."
        git -C "$src_path" fetch

        # main/masterブランチを自動判定
        set -l base_branch
        if git -C "$src_path" show-ref --verify --quiet refs/remotes/origin/main
            set base_branch "origin/main"
        else if git -C "$src_path" show-ref --verify --quiet refs/remotes/origin/master
            set base_branch "origin/master"
        else
            echo "Warning: No origin/main or origin/master found, using current branch"
            set base_branch (git -C "$src_path" rev-parse --abbrev-ref HEAD)
        end

        set -l new_branch "$ticket_id"

        # パス名を一階層化(github.com/user/repo → github-com-user-repo)
        set -l short_name (string replace -a "/" "-" "$repo" | string replace -a "." "-")

        echo "Creating worktree for $repo (branch: $new_branch from $base_branch) -> $short_name"
        git -C "$src_path" worktree add -b "$new_branch" "$ws_dir/$short_name" "$base_branch"
    end

    # ワークスペースに移動してClaude Codeを起動
    cd "$ws_dir"
    echo "Running: claude"
    claude
end

使ってみた感想

これが めっちゃ便利 なんです!

使い方は超シンプルで、claude_workspaceって打つだけ。チケットIDを聞かれて、fzyでリポジトリを選択していくだけです。

$ claude_workspace
# チケットID: FEATURE-456
# fzyでリポジトリ選択: repo-a, repo-b, repo-c

すると、こんな環境が自動で作られちゃいます:

~/ws/FEATURE-456/
├── github-com-myorg-repo-a/    # FEATURE-456 ブランチ
├── github-com-myorg-repo-b/    # FEATURE-456 ブランチ
├── github-com-myorg-repo-c/    # FEATURE-456 ブランチ
└── .claude/
    └── settings.json

全部のリポジトリが同じ階層に並んでて、同じ名前のブランチが自動で作られて、Claude Codeも自動で起動してくれます。もう 主従関係とか考える必要なし

自動化する前 vs した後

自動化前(毎回これやってた...):

mkdir ~/work/feature-x
cd ~/repo-a && git switch -c feature-x && git worktree add ~/work/feature-x/repo-a
cd ~/repo-b && git switch -c feature-x && git worktree add ~/work/feature-x/repo-b
cd ~/work/feature-x
claude --add-dir repo-b

自動化後:

claude_workspace
# チケットID入力 → リポジトリ選択 → 完了!
# 自分はこれを Ctrl + <key> でキーバインドにしちゃってます!

もう 比較にならないぐらい楽 ですw

嬉しいポイント

1. 完全平等な関係

全部のリポジトリが同じ階層にあるので、どれがメインでどれがサブかを気にしなくていいんです。Claude Codeも全部のリポジトリを同じように扱ってくれるので、横断的な変更とかも一気にお願いできちゃいます。

2. 軽量で効率的

Git Worktreeを使ってるので、元のリポジトリには影響しないし、.gitオブジェクトは共有されてるからディスク容量も無駄になりません。並行してPR作業とかもできるし、最高です!

3. どんなツールでも使える

これって「mkdirしてフォルダ入れてるだけ」なので、Claude Code以外のコーディングCLIでも使えちゃいます。汎用性高い〜

ちょっと困ったところ

とはいえ、使ってみて困ったこともあります...

問題1: CLAUDE.mdの作り直し

一時的なワークスペースで /init 実行するのって結構重い処理なんですよね。なので、各リポジトリで事前に /init でCLAUDE.mdを作っておく必要があります。ちょっと手間...

問題2: 複数Gitでのコミット指示

「コミットしておいて」だけだと、どのリポジトリにコミットするか分からないので、「repo-aとrepo-cにそれぞれコミットして」みたいに明示的に指示する必要があります。まあ、慣れの問題かな〜

まとめ

Fish FunctionとGit Worktreeを組み合わせることで、Claude Codeでの複数リポジトリ開発がめっちゃラクになりました!

良くなったポイント:

  • 完全対称アーキテクチャ: 主従関係なし!全部平等!
  • 軽量な並行開発環境: 元のコードに影響なし、効率的!
  • 統一的開発体験: Claude Codeで一貫してアクセス可能!

マイクロサービス開発でも、モノレポ運用でも、プライベートリポジトリ+OSSのハイブリッドな場合でも、複数リポジトリが関わる色んなシナリオで活用できると思います。

最初の設定はちょっと面倒かもしれませんが、一度設定しちゃえば、その後の開発作業が格段にラクになります!

興味のある方はぜひ試してみてください〜
もし「こうした方がいいんじゃない?」とかアイデアがあれば教えてください!改善点とかもお待ちしてます!


この記事がお役に立ちましたら、いいねやコメントいただけると嬉しいです!
X(@zawawahoge)でも発信しているので、ぜひ繋がっていきましょう!

参考文献

Discussion