TAKASHI YAMASHINA software engineer

git submoduleの使い方と使い分け

git submoduleは、Gitリポジトリの中に別のGitリポジトリを含めるための仕組みです。外部ライブラリを特定のバージョンで管理したい場合に使いますが、運用が複雑になるため、多くの場合はパッケージマネージャーの利用を推奨します。

submoduleの基本操作

submoduleを追加する

bash
# submoduleを追加
git submodule add https://github.com/user/repo.git path/to/submodule

# 例:libsディレクトリにライブラリを追加
git submodule add https://github.com/example/library.git libs/library

# コミット
git commit -m "Add library as submodule"

submoduleを含むリポジトリをクローンする

bash
# 方法1:クローン後にsubmoduleを初期化
git clone https://github.com/user/main-repo.git
cd main-repo
git submodule init
git submodule update

# 方法2:クローン時に同時にsubmoduleも取得(推奨)
git clone --recurse-submodules https://github.com/user/main-repo.git

submoduleを更新する

bash
# submoduleを最新版に更新
cd path/to/submodule
git pull origin main

# 親リポジトリに戻って変更をコミット
cd ../..
git add path/to/submodule
git commit -m "Update submodule to latest version"

# または、すべてのsubmoduleを一度に更新
git submodule update --remote

submoduleを削除する

bash
# submoduleの登録を解除
git submodule deinit path/to/submodule

# submoduleのディレクトリを削除
git rm path/to/submodule

# コミット
git commit -m "Remove submodule"

実践的な使い方

特定のブランチを追跡する

bash
# submoduleの設定を変更
git config -f .gitmodules submodule.path/to/submodule.branch develop

# submoduleを指定ブランチの最新に更新
git submodule update --remote

submoduleの状態を確認する

bash
# submoduleの一覧と状態を表示
git submodule status

# submoduleの詳細情報を表示
git submodule summary

チーム全員がsubmoduleを更新する

bash
# pullと同時にsubmoduleも更新
git pull --recurse-submodules

# または、pull後に手動で更新
git pull
git submodule update --init --recursive

使ったほうがいい場合

1. 外部ライブラリの特定バージョンを固定したい

bash
# 例:プロジェクトで使うライブラリのバージョンを厳密に管理
git submodule add https://github.com/company/internal-library.git libs/internal

2. 複数のリポジトリを一元管理したい

bash
# モノレポ的な構成
main-project/
├── backend/      # submodule
├── frontend/     # submodule
└── shared/       # submodule

3. ドキュメントや設定ファイルを共有したい

bash
# 複数のプロジェクトで共通の設定を使う
git submodule add https://github.com/company/shared-configs.git config

使わないほうがいい場合

1. パッケージマネージャーが使える場合

bash
# ❌ 避ける:submoduleでライブラリ管理
git submodule add https://github.com/lodash/lodash.git libs/lodash

# ✅ 推奨:パッケージマネージャーを使う
npm install lodash

理由

2. 頻繁に更新が必要な依存関係

bash
# submoduleは更新が煩雑
cd path/to/submodule
git pull
cd ../..
git add path/to/submodule
git commit -m "Update"

理由

3. 初心者が多いプロジェクト

理由

4. CI/CDで複雑な設定が必要になる

bash
# CIでsubmoduleを扱う場合の設定が必要
git clone --recurse-submodules https://github.com/user/repo.git

理由

submoduleの問題点

1. 操作が煩雑

通常のgit clonegit pullでは不十分で、常に--recurse-submodulesオプションを付ける必要があります。

bash
# 忘れがち
git clone https://github.com/user/repo.git
# → submoduleが空のまま

# 正しい
git clone --recurse-submodules https://github.com/user/repo.git

2. 状態の不整合が起きやすい

bash
# 開発者Aがsubmoduleを更新
cd submodule
git pull
cd ..
git add submodule
git commit -m "Update submodule"
git push

# 開発者Bがpullしただけの場合
git pull  # submoduleは古いまま
# → ビルドエラーやバグの原因に

3. ブランチ切り替えが複雑

bash
# ブランチを切り替えた後、submoduleも切り替える必要がある
git checkout feature-branch
git submodule update --init --recursive

4. detached HEAD状態になりやすい

submoduleは特定のコミットを指すため、デフォルトでdetached HEAD状態になります。

bash
# submodule内で作業する場合は注意
cd path/to/submodule
git status  # "HEAD detached at abc1234"

# ブランチをチェックアウトする必要がある
git checkout main

代替手段

1. パッケージマネージャーを使う

bash
# Node.js
npm install package-name

# Python
pip install package-name

# Go
go get github.com/user/package

2. monorepo構成を使う

bash
# Turborepo, Nx, Lernaなど
project/
├── packages/
   ├── app-a/
   ├── app-b/
   └── shared/
└── package.json

3. Git worktreeを使う

bash
# 同じリポジトリの別ブランチを別ディレクトリで作業
git worktree add ../feature-branch feature-branch

4. ベンダリング(依存関係をコピー)

bash
# Go言語の例
go mod vendor

# Node.jsの例(非推奨だが可能)
cp -r node_modules/package ./vendor/

submoduleを使う際のベストプラクティス

1. ドキュメントに記載する

README.md markdown
## クローン方法

このリポジトリはsubmoduleを含むため、以下のコマンドでクローンしてください:

git clone --recurse-submodules https://github.com/user/repo.git

2. Makefileやスクリプトで自動化

setup:
	git submodule update --init --recursive

update:
	git submodule update --remote
	git add .
	git commit -m "Update submodules"

3. CIの設定を明示

.github/workflows/ci.yml yaml
- name: Checkout
  uses: actions/checkout@v3
  with:
    submodules: recursive

4. チーム内で運用ルールを決める

よくあるトラブルと解決方法

submoduleが空のディレクトリになっている

bash
# 解決方法
git submodule update --init --recursive

submoduleの変更が反映されない

bash
# submodule内の変更を確認
cd path/to/submodule
git status

# 親リポジトリで変更をコミット
cd ../..
git add path/to/submodule
git commit -m "Update submodule reference"

submoduleを削除したのに残っている

bash
# 完全に削除する手順
git submodule deinit -f path/to/submodule
git rm -f path/to/submodule
rm -rf .git/modules/path/to/submodule
git commit -m "Remove submodule completely"