9
8

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 SubmoduleとGit Subtreeの比較と使い分け

9
Posted at

Gitで外部リポジトリを管理する方法として、git submodulegit 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 を使う場合

  1. 明確なドキュメント化
# README.md
## セットアップ手順
git clone --recursive <repository-url>
# または
git clone <repository-url>
git submodule update --init --recursive
  1. Git Hooks の活用
# .git/hooks/post-checkout
#!/bin/sh
git submodule update --init --recursive
  1. CI/CD での設定
# .github/workflows/ci.yml
- name: Checkout with submodules
  uses: actions/checkout@v3
  with:
    submodules: recursive

Subtree を使う場合

  1. 更新用スクリプトの作成
#!/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
  1. リモートの登録を推奨
# セットアップスクリプトに記載
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(自己完結性)

どちらを選ぶにしても、チーム内でルールを明確にし、ドキュメント化することが成功の鍵です。プロジェクトの特性とチームの状況に応じて、最適な方法を選択しましょう。

参考リンク

9
8
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
9
8

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?