multi-repo-git-ops について
multi-repo-git-opsは、親リポジトリとGitサブモジュールで構成されたプロジェクト向けのスキルです。リポジトリの把握、サービスごとのブランチやコミット管理を案内し、該当する場合はBMADのストーリー運用にも対応します。
主な機能
- 01サブモジュールと追跡ブランチの検出
- 02変更対象リポジトリの特定
- 03複数サービス間のブランチ調整
- 04コミット・プッシュ・プルリクエストの案内
- 05BMADストーリーに沿ったGit操作
活用シーン
- 01複数サービスリポジトリでの作業開始
- 02複数サービスにまたがるBMADストーリーの実装
- 03サービス変更のレビューとマージ準備
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ bmad-labs/ skills --skill multi-repo-git-opsインストール後、Claude Code で/multi-repo-git-opsを入力して読み込まれたか確認します。
詳細
マルチリポジトリの Git 操作
このスキルは、Git サブモジュールを使用するマルチリポジトリシステムでの Git 操作を扱います。親リポジトリが複数のサービスリポジトリを統括します。各サービスリポジトリは、それぞれ独自のブランチ、履歴、CI/CD を持つ独立した Git リポジトリです。
この構造を理解することが重要です。ここでの Git 操作では、どのリポジトリに影響するかを判断し、それぞれで正しく操作する必要があります。
検出プロトコル
Git 操作を実行する前に、プロジェクトの構造を動的に検出してください。サービス名、ブランチの対応関係、ディレクトリ構成を決めつけず、必ず .gitmodules を読み取ってください。
手順 1:サブモジュールとそのパスを特定する
# List all submodules with their paths
git config -f .gitmodules --get-regexp '\.path$'
手順 2:各サブモジュールが追跡するブランチを特定する
# List all submodule branch mappings
git config -f .gitmodules --get-regexp '\.branch$'
# Get a specific service's default branch
git config -f .gitmodules submodule."{submodule-path}".branch
サブモジュールのブランチが .gitmodules に設定されていない場合は、リモートを確認してください。
cd {submodule-path}
git remote show origin | grep 'HEAD branch'
手順 3:プロジェクトの手法を検出する
- BMAD:
_bmad-output/implementation-artifacts/ディレクトリが存在するか確認します - BMAD が検出された場合は、BMAD 統合のセクションを適用します
手順 4:検出した情報をセッション中にキャッシュする
検出後、エージェントは以下を把握します。
- すべてのサブモジュール名とパス
- 各サブモジュールのデフォルトブランチ
- BMAD が使用されているかどうか
- サブモジュールのディレクトリ接頭辞(一般的には
services/)
セッション中の以降のすべての操作では、このキャッシュ済み情報を使用してください。
リポジトリ構成
一般的なマルチリポジトリプロジェクトは、次のような構成です。
{parent-repo}/ (parent repo — planning & orchestration only)
├── .gitmodules (submodule definitions with tracked branches)
├── services/ (submodule repos — directory name may vary)
│ ├── auth-service/ (branch: develop)
│ ├── booking-service/ (branch: dev)
│ ├── config-repo/ (branch: main)
│ └── ...
└── [project methodology dirs] (e.g., _bmad-output/ if using BMAD)
重要な原則:親リポジトリが追跡するのは、各サブモジュールのコードそのものではなく、コミットへのポインターです。サービスのコードを変更した場合は、サービスリポジトリでコミットしてから、親リポジトリのポインターを更新します。
ブランチの規約
サービスごとのデフォルトブランチ
サービスごとに追跡するデフォルトブランチが異なる場合があります。ブランチを作成する前に、必ず正しいブランチを確認してください。
# Get a service's default branch (always use this — never assume)
git config -f .gitmodules submodule."{submodule-path}".branch
同じプロジェクト内でも、サービスによって異なるデフォルトブランチ(例:develop、dev、main)を使用することがよくあります。信頼できる唯一の情報源は .gitmodules です。
フィーチャーブランチの命名
チケットベースの作業(JIRA/プロジェクトトラッカー)の場合:
{type}/{TICKET-ID}-{short-description}
例:feat/PROJ-1234-add-search-by-date、bugfix/PROJ-5678-fix-null-pointer
BMAD ストーリーの作業(ストーリーファイル名に基づく)の場合:
feat/{story-key}
ストーリーキーはストーリーファイル名から取得します。1-2-user-authentication.md という名前のストーリーファイル(エピック 1、ストーリー 2 を表す)の場合、ブランチ名は feat/1-2-user-authentication になります。
ブランチ種別の接頭辞:feat/、fix/、bugfix/、chore/、base/
BMAD 統合(該当する場合)
このセクションは、プロジェクトで BMAD の手法を使用している場合にのみ適用されます。_bmad-output/implementation-artifacts/ ディレクトリがあるか確認して検出してください。
BMAD では、ストーリーファイルとスプリントステータスの追跡によって作業を管理します。このセクションでは、Git 操作と BMAD のライフサイクルの対応について説明します。
ストーリーがサービスを参照する方法
BMAD のストーリーファイルは _bmad-output/implementation-artifacts/{story-key}.md にあります。ストーリーでは、影響を受けるサービスがいくつかの方法で記載されているため、以下をすべて確認してください。
- ストーリーのタイトルまたは本文にあるサービスのタグ:
[auth-service]、[scheduler-service] - Dev Notes セクション:「変更対象となるソースツリーのコンポーネント」をサービスのパスとともに記載
- Project Structure Notes:
services/{service-name}/src/...のようなパスを参照 - Tasks/Subtasks:個別のタスクで異なるサービスを参照する場合があります
ストーリーにサービスが明示的にタグ付けされていない場合は、Dev Notes と Tasks に記載されたファイルパスを確認し、どのサブモジュールディレクトリが関係するかを判断してください。
BMAD のステータスと Git 操作の対応
BMAD は _bmad-output/implementation-artifacts/sprint-status.yaml でストーリーのステータスを追跡します。ステータスの各遷移には、対応する Git 操作があります。
| ストーリーのステータス変更 | 必要な Git 操作 |
|---|---|
backlog → ready-for-dev | Git 操作なし(ストーリーファイルの作成のみ) |
ready-for-dev → in-progress | 影響を受けるサービスでフィーチャーブランチを作成 |
in-progress(作業中) | サービスのリポジトリで変更をコミット |
in-progress → review | すべてのサービスブランチをプッシュし、クリーンな状態であることを確認 |
review → in-progress(修正) | 同じブランチで作業を続け、修正をコミット |
review → done | PR をマージし、親のサブモジュールポインターを更新 |
BMAD ストーリーの開始(Git のセットアップ)
BMAD ストーリーの作業を始めるときは、次の Git 操作を行います。
ステップ 1:ストーリーを読み、サービスを特定する
# Story files follow pattern: {epic_num}-{story_num}-{slug}.md
# Example: _bmad-output/implementation-artifacts/1-2-user-authentication.md
ストーリーファイルを読みます。次の情報から、影響を受けるサービスを抽出します。
[auth-service]のようなサービスのタグ- Dev Notes 内のファイルパス(例:
services/{service-name}/src/...) - 特定のサービスを参照するタスクの説明
ステップ 2:ストーリーキーからブランチ名を決める
# Story file: 1-2-user-authentication.md → branch: feat/1-2-user-authentication
STORY_KEY="1-2-user-authentication" # from the story file name (without .md)
BRANCH_NAME="feat/${STORY_KEY}"
ステップ 3:影響を受けるすべてのサービスでブランチを作成する
# For each affected service (replace with actual discovered service names):
for SERVICE in auth-service scheduler-service; do
DEFAULT_BRANCH=$(git config -f .gitmodules submodule."services/$SERVICE".branch)
cd services/$SERVICE
git checkout $DEFAULT_BRANCH
git pull origin $DEFAULT_BRANCH
git checkout -b $BRANCH_NAME
git push -u origin $BRANCH_NAME
cd ../..
done
追跡しやすいように、影響を受けるすべてのサービスで同じブランチ名を使用します。これにより、システム全体でストーリーに関連するすべての変更を簡単に見つけられます。
ステップ 4:セットアップを確認する
# Confirm all affected services are on the correct branch
git submodule foreach --quiet 'BRANCH=$(git branch --show-current); echo "$(basename $(pwd)): $BRANCH"'
ストーリーの実装中
変更のコミット — 必ずサービスのディレクトリ内でコミットします。
cd services/{service-name}
git add {specific-files}
git commit -m "feat({scope}): add validation for booking dates
Story: {story-key}"
複数のサービスにまたがる作業 — 各サービスで個別にコミットします。
# Service A
cd services/auth-service
git add src/auth/jwt.service.ts src/auth/jwt.service.spec.ts
git commit -m "feat(auth): add JWT validation endpoint
Story: 1-2-user-authentication"
# Service B
cd ../bff-service
git add src/middleware/auth.middleware.ts
git commit -m "feat(middleware): add JWT auth middleware
Story: 1-2-user-authentication"
すべてのコミットは、以下のコミットメッセージ形式に従う必要があります。release-please が正しい変更履歴とバージョン更新を生成するために重要です。
ストーリーの完了(プッシュと PR)
ストーリーのレビュー準備ができたら、次の手順を実行します。
ステップ 1:影響を受ける各サービスで品質チェックを実行する
cd services/{service-name}
npm run lint
npm run format
npm run typecheck
npm test
ステップ 2:各サービスのフィーチャーブランチをプッシュする
# Push services first — always before parent
cd services/{service-name}
git push origin feat/{story-key}
ステップ 3:サービスごとに PR を作成する
サービスごとに個別の PR を作成します:feat/{story-key} → サービスのデフォルトブランチ。
PR のタイトル形式:feat({story-key}): {story title}
PR の本文ではストーリーを参照します:Story: {epic_num}.{story_num} - {title}
ステップ 4:PR のマージ後、親を更新する
# For each merged service:
cd services/{service-name}
git checkout {default-branch}
git pull origin {default-branch}
cd ../..
# Update parent pointers (use actual discovered service paths)
git add services/auth-service services/bff-service
git commit -m "chore: update submodule pointers after story {story-key}
Services updated:
- auth-service
- bff-service"
コミットメッセージ形式(release-please 互換)
プロジェクトで、バージョン管理と変更履歴の生成を自動化するために release-please を使用している場合は、release-please がバージョン更新を正しく判定し、意味のある変更履歴を生成できるよう、すべてのコミットメッセージが Conventional Commits の仕様に従う必要があります。
release-please を使用していない場合でも、多数のリポジトリにわたって整然とした解析可能な Git 履歴を作成できるため、複数リポジトリのシステムでは Conventional Commits が推奨形式です。
AI の共著者トレーラーは禁止
AI エージェントのコミットメッセージに Co-Authored-By トレーラーを絶対に追加しないでください。 つまり、次のような行を追加してはいけません。
Co-Authored-By: Claude <[email protected]>
Co-Authored-By: Claude Opus 4.6 (1M context) <[email protected]>
コミットメッセージには、以下で説明する Conventional Commit の構造のみを含めてください。コミットへの AI の帰属情報は変更履歴を汚し、Git 履歴にノイズを加えるだけで、何の価値もありません。このルールは、機能追加、修正、雑務、その他あらゆるコミットに適用されます。
構造
<type>(<scope>): <description>
[optional body]
[optional footer(s)]
ヘッダーのルール:
type— 必須(以下の type テーブルを参照)scope— 任意。影響を受けるコードのセクションを表す名詞を括弧内に記述しますdescription— 必須。:の直後に記述します- 命令形の現在形を使います。"added" や "adds" ではなく "add" とします
- 先頭の文字を大文字にしません
- 末尾にピリオドを付けません
- 約 100 文字以内に収めます
本文 — 任意。ヘッダーとの間に空行を入れます。「何を」「なぜ」を説明する自由形式のテキストです。
フッター — 任意。本文との間に空行を入れます。破壊的変更、ストーリーの参照、その他のメタデータに使用します。
コミットの種類とバージョンの更新
Release-please は、バージョン更新に対応する種類のコミット、つまりリリース対象となる単位を検出した場合にのみリリースを作成します。適切な種類を選ぶことが重要です。リリースされるバージョンと変更履歴に表示される内容が直接決まるためです。
リリース対象の種類(リリースをトリガーします)
| 種類 | SemVer の更新 | 使用する場面 |
|---|---|---|
feat | マイナー(0.x.0) | 新しい機能、エンドポイント、UI コンポーネント |
fix | パッチ(0.0.x) | 既存機能のバグ修正 |
deps | パッチ(0.0.x) | 依存関係の更新(package.json、ロックファイル) |
リリース対象外の種類(単独ではリリースをトリガーしません)
| 種類 | 使用する場面 |
|---|---|
refactor | 動作を変えないコードの再構成 |
perf | パフォーマンスの改善(特別なリファクタリング) |
test | テストの追加または修正 |
docs | ドキュメントのみの変更 |
style | コードスタイル(フォーマット、空白、セミコロン) |
chore | メンテナンスタスク(.gitignore、設定、ツール) |
build | ビルドシステム、依存関係、プロジェクトのバージョン |
ci | CI/CD パイプラインとワークフローの変更 |
前回のリリース以降、リリース対象外の種類のコミットしかない場合、リリース PR は作成されません。種類は意図的に選んでください。実際には feat: や fix: に当たる変更に chore: を使わないでください。
適切な種類の選び方
New capability or feature? → feat
Fixing a bug? → fix
Dependency update? → deps
Performance improvement? → perf
Code restructuring, no behavior Δ? → refactor
Documentation only? → docs
Tests only? → test
CI/CD or build changes? → ci / build
Everything else (configs, tooling)? → chore
破壊的変更(メジャー更新)
破壊的変更を含むコミットは、種類にかかわらずメジャーバージョンへの更新をトリガーします。形式は 2 種類あります。
オプション A — ヘッダーに ! を付ける:
feat(api)!: redesign authentication flow
BREAKING CHANGE: the /auth/login endpoint now requires OAuth2 tokens
instead of API keys. All existing integrations must migrate.
オプション B — フッターのみ:
refactor(database): migrate from MongoDB to PostgreSQL
BREAKING CHANGE: all database connection strings must be updated.
The MongoDB driver is no longer included.
フッターでは BREAKING CHANGE(スペース)と BREAKING-CHANGE(ハイフン)の両方が認識されます。
破壊的変更を示す場合は、! 形式を使う場合でも、移行への影響を説明する BREAKING CHANGE: フッターを必ず含めてください。利用者が変更すべき内容を把握するために読むのは、このフッターです。
スコープ
スコープは、影響を受けるコード領域を示します。変更履歴の整理に役立ち、モノレポ構成では変更を適切なパッケージに振り分けるためにも使われます。
適切なスコープ(コード領域を示すもの):
feat(auth): add JWT validation
fix(scheduler): correct cron expression parsing
refactor(booking): extract date utility
不適切なスコープ(アンチパターン):
fix(PROJ-1234): ... ← ticket IDs are not scopes
feat(john): ... ← people are not scopes
スコープにはドメイン名またはモジュール名(例:auth、booking、scheduler、middleware、config、migration)を使ってください。
ストーリーへの参照
BMAD を使用する場合、ストーリーキーはスコープではなく、コミットの本文またはフッターに含めてください。
feat(auth): add JWT validation endpoint
Implement token validation with RS256 signing.
Story: 1-2-user-authentication
Release-Please 専用フッター
| フッター | 用途 |
|---|---|
BREAKING CHANGE: <desc> | メジャーバージョンへの更新をトリガーします |
Release-As: x.x.x | 特定のバージョン番号を指定します |
Release-As の例 — 初回リリースや、複数のバージョンを連携して更新する場合に便利です。
chore: prepare v3.0.0 release
Release-As: 3.0.0
完全な例
シンプルな機能(マイナー更新):
feat(booking): add search by date range endpoint
詳細を含むバグ修正(パッチ更新):
fix(auth): resolve token refresh race condition
The refresh token was being invalidated before the new access token
was issued, causing a brief window where requests would fail.
Story: 2-3-auth-improvements
破壊的変更(メジャー更新):
feat(api)!: remove deprecated v1 booking endpoints
BREAKING CHANGE: all /api/v1/bookings/* endpoints are removed.
Consumers must migrate to /api/v2/bookings/* which uses the new
pagination format.
Story: 3-1-api-v2-migration
依存関係の更新(パッチ更新):
deps: upgrade @nestjs/core to v11.0.0
テストのみの変更(リリースなし):
test(scheduler): add unit tests for cron expression parser
雑務(リリースなし):
chore: update .gitignore to exclude coverage reports
親リポジトリのコミットメッセージ
親リポジトリでサブモジュールのポインターを更新する場合、親リポジトリ自体の機能変更ではないため、chore: を使ってください。
chore: update submodule pointers after story 1-2-user-authentication
Services updated:
- auth-service
- bff-service
一般的な操作のリファレンス
機能ブランチの作成(BMAD 以外)
BMAD ストーリーに紐づかないアドホックな作業の場合:
DEFAULT_BRANCH=$(git config -f .gitmodules submodule."{submodule-path}".branch)
cd {submodule-path}
git checkout $DEFAULT_BRANCH
git pull origin $DEFAULT_BRANCH
git checkout -b feat/{TICKET-ID}-{description}
git push -u origin feat/{TICKET-ID}-{description}
すべてのサブモジュールを同期
# Pull parent and update all submodule pointers
git pull origin main
git submodule update --recursive
# OR: Pull latest from each submodule's tracked branch
git submodule foreach 'git pull origin $(git config -f $toplevel/.gitmodules submodule.$name.branch)'
すべてのリポジトリのステータスを確認
# Quick status: show only services with changes or non-default branches
git submodule foreach --quiet \
'STATUS=$(git status --porcelain); BRANCH=$(git branch --show-current); DEFAULT=$(git config -f $toplevel/.gitmodules submodule.$name.branch); if [ -n "$STATUS" ] || [ "$BRANCH" != "$DEFAULT" ]; then echo "$(basename $(pwd)) [$BRANCH]: $([ -n "$STATUS" ] && echo "has changes" || echo "clean, non-default branch")"; fi'
サービスをデフォルトブランチに戻す
DEFAULT_BRANCH=$(git config -f .gitmodules submodule."{submodule-path}".branch)
cd {submodule-path}
git checkout $DEFAULT_BRANCH
git pull origin $DEFAULT_BRANCH
CI/CD の把握
マルチリポジトリシステムでは、プッシュ時に何が起きるかを理解することが重要です。一般的なブランチとデプロイ先の対応関係は次のとおりです。
| ブランチ | プッシュ時の一般的な影響 |
|---|---|
develop / dev | 開発環境に自動デプロイされる可能性があります — 必ず事前にユーザーに確認してください |
main | 安定版の参照先 — デプロイワークフローを利用できます |
test、stage、release | workflow_dispatch による手動デプロイ |
feat/*、base/* | CI が実行されます(lint、テスト、ビルド)が、デプロイは行われません |
実際のデプロイ動作は、プロジェクトの CI/CD 設定によって異なります。サブモジュールに共通の CI/CD ワークフローリポジトリが含まれているかを確認し、どのブランチがデプロイを開始するのかをユーザーに確認してください。
安全規則
以下の規則に従うことで、マルチリポジトリシステムでよくあるミスを防げます。
- 必ず親リポジトリより先にサービスリポジトリをプッシュしてください — 親リポジトリを先にプッシュすると、サブモジュールのポインターが壊れ、他の開発者のチェックアウトに支障が出ます
- 共有のデフォルトブランチ(
develop、dev、main)には絶対に強制プッシュしないでください — これらは共有ブランチです - デプロイを開始するブランチにプッシュする前に、必ずユーザーに確認してください
- フィーチャーブランチを作成する前に、サービスのデフォルトブランチを確認してください — サービスごとに異なり、誤ったベースからブランチを作成するとマージコンフリクトが発生します
- サービスリポジトリでは、
git add .やgit add -Aを絶対に使用しないでください — シークレットやビルド成果物のコミットを避けるため、必ず特定のファイルを追加してください - どのリポジトリでも、
.env、認証情報、シークレット、node_modulesを絶対にコミットしないでください - 複数サービスにまたがるストーリーでは、すべてのサービスで同じブランチ名を使用してください — これにより追跡が容易になります
- Git 操作によってストーリーの状態が変わった場合(ブランチ作成 →
in-progress、レビュー用にプッシュ →review)、sprint-status.yaml を更新してください — BMAD を使用している場合のみ - コミットメッセージに AI エージェントの
Co-Authored-Byトレーラーを絶対に追加しないでください — Claude、Copilot、その他の AI による帰属表示は避けてください。これらは変更履歴や Git 履歴を汚します。コミットメッセージには、Conventional Commits の形式(type、scope、description、body、破壊的変更/ストーリー参照用の footers)のみを含めてください - すべてのコミットメッセージは Conventional Commits 形式にしてください — release-please は自動バージョン管理と変更履歴の生成にこの形式を使用します。不正な形式のコミットメッセージは、リリースの漏れや誤ったバージョン更新につながる可能性があります