Gitで外部リポジトリを管理する方法として、git submoduleとgit subtreeがあります。どちらも外部プロジェクトを組み込む手段ですが、それぞれ特徴が異なり、適した使い道があります。本記事では、両者の違いを比較し、どのような場面で使い分けるべきかをまとめます。
基本的な概念
Git Submodule
外部リポジトリへの**参照(ポインタ)**を保持する仕組みです。メインリポジトリには特定のコミットハッシュのみが記録され、実際のコードは別のリポジトリとして管理されます。
Git Subtree
外部リポジトリの内容をコピーして統合する仕組みです。外部プロジェクトのコードがメインリポジトリの一部として完全に含まれます。
詳細比較
1. リポジトリ構造
Submodule
# .gitmodules ファイルに参照が記録される
[submodule "libs/external-lib"]
path = libs/external-lib
url = https://github.com/example/external-lib.git
Subtree
# 通常のディレクトリとしてコミット履歴に含まれる
# 特別な設定ファイルは不要
2. 基本操作の比較
| 操作 | Submodule | Subtree |
|---|---|---|
| 追加 | git submodule add <url> <path> |
git subtree add --prefix=<path> <url> <branch> |
| クローン |
git clone --recursive または git submodule update --init
|
git clone のみでOK |
| 更新 | git submodule update --remote |
git subtree pull --prefix=<path> <url> <branch> |
| 変更のプッシュ | submodule内で別途push | git subtree push --prefix=<path> <url> <branch> |
3. メリット・デメリット
Git Submodule
メリット
- 📌 外部リポジトリとの関係が明確
- 💾 メインリポジトリのサイズが小さい
- 🔄 外部プロジェクトを独立して更新しやすい
- 🔐 外部リポジトリへのアクセス権限を細かく管理できる
デメリット
- ⚠️ 初期セットアップが複雑(
--recursiveオプションなど) - 😰 チーム開発で同期忘れが発生しやすい
- 🔧 submodule内での変更管理が煩雑
- 📚 学習コストが高い
Git Subtree
メリット
- ✨ クローン後すぐに全てのコードが利用可能
- 🎯 通常のGit操作と同じように扱える
- 👥 チームメンバーがsubtreeを意識する必要がない
- 🔍 履歴が一つのリポジトリに統合される
デメリット
- 📦 リポジトリサイズが大きくなる
- 🌳 履歴が複雑になる可能性
- 🔄 外部リポジトリとの同期がやや面倒
- ⏱️ 大規模プロジェクトでは操作に時間がかかる
実践的な使い分け指針
Git Submodule が適している場面
1. 複数のプロジェクトで共有するライブラリ
# 社内共通ライブラリを複数のプロジェクトで使用
my-project/
├── src/
└── libs/
├── common-utils/ (submodule)
└── api-client/ (submodule)
理由: 各プロジェクトが独立してライブラリのバージョンを管理でき、ライブラリ自体への貢献も容易。
2. サードパーティの依存関係
# OSSライブラリを特定バージョンで固定
web-app/
└── vendor/
├── bootstrap/ (submodule)
└── jquery/ (submodule)
理由: 依存関係のバージョンを明示的に管理し、独立してアップデート可能。
3. マイクロサービスアーキテクチャ
# 複数のサービスを統合管理
infrastructure/
├── service-a/ (submodule)
├── service-b/ (submodule)
└── service-c/ (submodule)
理由: 各サービスが独立したリポジトリを持ち、個別に開発・デプロイできる。
Git Subtree が適している場面
1. プロジェクトにライブラリを完全に組み込む
# フォークしてカスタマイズしたライブラリ
my-app/
└── src/
└── customized-lib/ (subtree)
理由: チーム全員が特別な操作なしで即座に使え、カスタマイズも容易。
2. プラグインやテーマの管理
# WordPressのテーマ開発
wordpress-site/
└── wp-content/
└── themes/
└── custom-theme/ (subtree)
理由: デプロイ時に追加の手順が不要で、全ての内容が含まれる。
3. モノレポへの段階的移行
# 複数リポジトリを一つに統合
monorepo/
├── frontend/ (subtree)
├── backend/ (subtree)
└── shared/ (subtree)
理由: 履歴を保持したまま統合でき、将来的に完全なモノレポに移行しやすい。
実践的なコード例
Submodule の使用例
# 1. submoduleの追加
git submodule add https://github.com/example/library.git libs/library
# 2. リポジトリのクローン(新規メンバー)
git clone --recursive https://github.com/your/project.git
# 既存クローンにsubmoduleを初期化
git submodule update --init --recursive
# 3. submoduleの更新
cd libs/library
git pull origin main
cd ../..
git add libs/library
git commit -m "Update library submodule"
# 4. 全てのsubmoduleを最新に更新
git submodule update --remote --merge
Subtree の使用例
# 1. subtreeの追加
git subtree add --prefix=libs/library \
https://github.com/example/library.git main --squash
# 2. subtreeの更新(リモートの変更を取り込む)
git subtree pull --prefix=libs/library \
https://github.com/example/library.git main --squash
# 3. 変更を元のリポジトリにプッシュバック
git subtree push --prefix=libs/library \
https://github.com/example/library.git main
# 4. リモートを登録して簡略化
git remote add library-remote https://github.com/example/library.git
git subtree pull --prefix=libs/library library-remote main --squash
チーム開発での推奨事項
Submodule を使う場合
- 明確なドキュメント化
# README.md
## セットアップ手順
git clone --recursive <repository-url>
# または
git clone <repository-url>
git submodule update --init --recursive
- Git Hooks の活用
# .git/hooks/post-checkout
#!/bin/sh
git submodule update --init --recursive
- CI/CD での設定
# .github/workflows/ci.yml
- name: Checkout with submodules
uses: actions/checkout@v3
with:
submodules: recursive
Subtree を使う場合
- 更新用スクリプトの作成
#!/bin/bash
# update-subtrees.sh
git subtree pull --prefix=libs/lib1 lib1-remote main --squash
git subtree pull --prefix=libs/lib2 lib2-remote main --squash
- リモートの登録を推奨
# セットアップスクリプトに記載
git remote add lib1-remote https://github.com/example/lib1.git
git remote add lib2-remote https://github.com/example/lib2.git
決定フローチャート
外部リポジトリを統合したい
↓
┌─────┴─────┐
│チーム全員が│
│Git中級者? │
└─────┬─────┘
Yes │ No
│ └→ Subtree
↓
┌─────────────┐
│独立性が重要?│
└─────┬───────┘
Yes │ No
│ └→ Subtree
↓
┌──────────────┐
│複数箇所で共有?│
└──────┬───────┘
Yes │ No
│ └→ Subtree
↓
Submodule
まとめ
Submodule を選ぶべき状況
- ✅ 外部リポジトリとの独立性を保ちたい
- ✅ チームがGitに習熟している
- ✅ 複数のプロジェクトで同じリポジトリを共有
- ✅ 外部リポジトリへの貢献を頻繁に行う
Subtree を選ぶべき状況
- ✅ シンプルさを優先したい
- ✅ チームメンバーのGitスキルレベルが様々
- ✅ 外部コードを完全に統合したい
- ✅ クローン後すぐに全機能を使えることが重要
実務での傾向
- 大企業・大規模プロジェクト: Submodule(明確な境界線と責任範囲)
- スタートアップ・小規模チーム: Subtree(簡潔さと迅速性)
- OSSプロジェクト: Submodule(貢献のしやすさ)
- デプロイパッケージ: Subtree(自己完結性)
どちらを選ぶにしても、チーム内でルールを明確にし、ドキュメント化することが成功の鍵です。プロジェクトの特性とチームの状況に応じて、最適な方法を選択しましょう。