0
1

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の使い方

Last updated at Posted at 2025-11-09

複数プロジェクトのコード管理が楽になる!Git Submoduleの使い方🔗

「同じコードを3つのプロジェクトにコピペ...また修正漏れた!」

「プロジェクトごとにバージョンがバラバラで、どれが最新?」

「共通ライブラリの管理、もっと楽にならないかな...」

こんな悩み、ありませんか?

こんにちは、亀ちゃん🐰🐢です。
X (Twitter): @usagi_kamechan

複数のプロジェクトで同じコードを使っていると、修正のたびにあちこち更新しないといけなくて、本当に大変ですよね。

私も開発をしていて、コピペ地獄に苦しんだ経験があります。

でも、Git Submoduleを使ったら、この悩みがスッキリ解決しました!

🌟 この記事でわかること

  • Git Submoduleって何?どんな時に使うの?
  • 複数プロジェクトで共通コードを管理する方法
  • 実際の使い方(追加・クローン・更新)
  • チーム開発で気をつけること
  • よくあるトラブルと対処法

1. 私が困っていたこと

マイクロサービスを開発していた時のことです。

プロジェクトの構成はこんな感じでした:

【本番環境】                    【開発環境】
┌─────────┐                  ┌──────────────┐
│サービスA  │                  │ メインリポジトリ │
│(独立)    │                  │                │
└─────────┘                  │ ├─ サービスB   │
                              │ └─ サービスA ? │
┌─────────┐                  │    (どう管理?) │
│サービスB  │                  └──────────────┘
│(独立)    │
└─────────┘
  • サービスA:データを管理するWebアプリ(独立したリポジトリ)
  • サービスB:サービスAの機能を利用するアプリケーション(別リポジトリ)

本番環境では別々に動くけど、ローカルでの開発・動作確認では両方を一緒に動かす必要がありました。

何が困っていたか

開発時は両方のリポジトリを手動で管理しないといけない...

サービスAが更新されたら、サービスB側でも最新版を取り込みたいのに、いちいち手動でコピー。

チームメンバーの環境構築時、2つのリポジトリを説明するのが大変。

「リポジトリは分離したいけど、開発時は一緒に扱いたい...どうすれば?」

そう思っていた時、Git Submoduleに出会いました。

2. Git Submoduleって何?

Git Submoduleは、Gitリポジトリの中に別のGitリポジトリを含められる機能です。

イメージとしては、「入れ子構造」ですね。

【通常のリポジトリ】         【Submodule使用時】
┌────────────┐          ┌─────────────────┐
│ my-project │          │ my-project      │
│            │          │  (親リポジトリ)   │
│ ├─ src/   │          │                 │
│ ├─ docs/  │          │ ├─ src/         │
│ └─ ...    │          │ ├─ docs/        │
└────────────┘          │ └─ libs/        │
                        │     └─ common/  │← これがサブモジュール
                        │        (子リポジトリ)
                        └─────────────────┘
                               ↓
                        特定のコミットを参照
                        ┌───────────────┐
                        │ common-library│
                        │ (別リポジトリ) │
                        │               │
                        │ commit: abc123│
                        └───────────────┘

親リポジトリの中に、子リポジトリ(サブモジュール)を配置できます。

ポイントは「バージョンの固定」

重要なのは、親リポジトリは子リポジトリの特定のコミット(バージョン)を参照するということ。

つまり、「このプロジェクトは、あのライブラリのこのバージョンを使う」と明確に管理できるんです。

勝手に最新版に更新されることはありません。

自分で明示的に更新するまで、同じバージョンが使われ続けます。

これが、予期しない変更を防いでくれる大きなメリットです🌟

3. どんな時に使うの?活用例

Git Submoduleが活躍する場面をいくつか紹介します。

ケース1:複数プロジェクトで共通のライブラリを使う

3つのWebアプリで同じ認証ライブラリを使っている場合。

【従来の方法:コピペ地獄】
┌──────────┐  ┌──────────┐  ┌──────────┐
│ WebアプリA │  │ WebアプリB │  │ WebアプリC │
│ ├─ auth/ │  │ ├─ auth/ │  │ ├─ auth/ │
│ (コピー)  │  │ (コピー)  │  │ (コピー)  │
└──────────┘  └──────────┘  └──────────┘
   ❌ 修正が3箇所必要!バージョンがバラバラ!

【Submoduleを使う方法】
┌──────────┐  ┌──────────┐  ┌──────────┐
│ WebアプリA │  │ WebアプリB │  │ WebアプリC │
│ └─ auth/ │  │ └─ auth/ │  │ └─ auth/ │
└─────┬────┘  └─────┬────┘  └─────┬────┘
      └───────┬──────┴──────────────┘
              ↓ 全て参照
      ┌───────────────┐
      │ auth-library  │
      │ (共通リポジトリ)│
      └───────────────┘
   ✅ 修正は1箇所だけ!バージョン管理も明確!

ライブラリをサブモジュールにすれば、各プロジェクトから同じコードを参照できます。

バグ修正したら、ライブラリ側を更新して、各プロジェクトで最新版を取り込むだけ。

コピペ不要です!

ケース2:外部ライブラリのバージョンを固定したい

オープンソースのライブラリを使っているけど、パッケージマネージャーで管理できない場合。

特定のコミットを固定して使いたい時に便利です。

ケース3:チーム開発でルールやドキュメントを共有

複数のプロジェクトで同じコーディング規約やドキュメントを共有したい。

サブモジュールにすれば、一箇所で管理して、全プロジェクトで同期できます。

ケース4:マイクロサービスのローカル開発

私のケースのように、本番では別々に動くサービスを、開発時は一緒に扱いたい場合。

サブモジュールとして含めることで、環境構築がスムーズになります。

4. 実際に使ってみよう!基本の3ステップ

ここからは、実際の使い方を見ていきましょう。

難しそうに見えるかもしれませんが、基本は3つのステップだけです。

【Git Submoduleの基本フロー】

 ステップ1           ステップ2              ステップ3
┌─────────┐      ┌──────────┐       ┌──────────┐
│サブモジュール│      │クローン時に │       │サブモジュール│
│を追加     │ ───→ │一緒に取得  │ ───→ │を更新     │
└─────────┘      └──────────┘       └──────────┘
     ↓                  ↓                   ↓
 git submodule     git clone          git submodule
    add            --recursive         update --remote

ステップ1: サブモジュールを追加する

既存のリポジトリにサブモジュールを追加するには、このコマンドを使います:

git submodule add <サブモジュールのリポジトリURL> <配置先のパス>

例えば、libs/commonというディレクトリに共通ライブラリを追加する場合:

git submodule add https://github.com/yourteam/common-library.git libs/common

このコマンドを実行すると、何が起こるのか?

【実行前】                    【実行後】
my-project/                  my-project/
├─ src/                      ├─ src/
├─ docs/                     ├─ docs/
└─ README.md                 ├─ libs/
                             │   └─ common/  ← 新しく追加!
                             ├─ .gitmodules  ← 設定ファイル
                             └─ README.md

.gitmodules の中身:
[submodule "libs/common"]
    path = libs/common
    url = https://github.com/yourteam/common-library.git
  1. 指定したパスにサブモジュールがクローンされます
  2. .gitmodulesというファイルが作成されます(サブモジュールの設定を保存)
  3. サブモジュールの情報が.git/configにも追加されます

.gitmodulesファイルは、チームメンバーと共有されます。

このファイルのおかげで、他のメンバーも同じサブモジュールを使えるようになります。

ステップ2: サブモジュール付きのリポジトリをクローンする

サブモジュールを含むリポジトリをクローンする方法は2つあります。

方法1: 最初から全部取得する

git clone --recursive <リポジトリのURL>

--recursiveオプションを付けると、サブモジュールも一緒にクローンされます。

一番簡単な方法です!

方法2: 後からサブモジュールを取得する

すでにクローンしてしまった場合は、このコマンドで取得できます:

git submodule update --init --recursive

--init:サブモジュールを初期化
--recursive:サブモジュールの中にさらにサブモジュールがある場合も全て取得

このコマンド、よく使うので覚えておくと便利です🔥

ステップ3: サブモジュールを更新する

サブモジュールの最新版を取り込みたい場合の方法です。

パターンA: サブモジュールの最新版に更新する

git submodule update --remote

このコマンドで、サブモジュールが最新のコミットにアップデートされます。

更新後は、親リポジトリでもコミットが必要です:

git add .
git commit -m "Update submodule to latest version"
git push

パターンB: サブモジュール内で直接変更する

サブモジュールの中で修正したい場合もあります。

その時はこんな流れです:

# サブモジュールのディレクトリに移動
cd libs/common

# ブランチをチェックアウト(重要!)
git checkout main

# 変更を加える
# ...

# サブモジュール内でコミット&プッシュ
git add .
git commit -m "Fix bug in common library"
git push

# 親リポジトリに戻る
cd ../..

# 親リポジトリでもサブモジュールの参照を更新
git add libs/common
git commit -m "Update submodule reference"
git push

ここで重要なのは、コミットが2箇所で必要ということ。

【サブモジュール変更時のコミットフロー】

Step 1: サブモジュール内で作業
┌─────────────────┐
│ libs/common/    │
│ (サブモジュール) │
│                 │
│ ✏️ コード修正    │
│ ✅ git commit   │← ① サブモジュール側でコミット
│ ⬆️ git push     │
└─────────────────┘

Step 2: 親リポジトリで参照を更新
┌─────────────────┐
│ my-project/     │
│ (親リポジトリ)   │
│                 │
│ libs/common     │← 参照先が変わった
│ (abc123→def456) │
│ ✅ git commit   │← ② 親リポジトリでコミット
│ ⬆️ git push     │
└─────────────────┘

⚠️ 両方のコミットが必要!片方だけだとチームメンバーが同期できません
  1. サブモジュール側でコミット
  2. 親リポジトリでサブモジュールの参照をコミット

最初はちょっと面倒に感じるかもしれませんが、これがバージョン管理の明確さにつながります。

5. チーム開発で気をつけること

チームでGit Submoduleを使う時の注意点をまとめます。

注意点1: コミットが2箇所必要

さっきも触れましたが、サブモジュールを変更したら:

  1. サブモジュール側でコミット&プッシュ
  2. 親リポジトリでサブモジュールの参照を更新してコミット&プッシュ

この2ステップが必要です。

片方だけだと、他のメンバーが同じ状態を再現できなくなってしまいます。

注意点2: チームメンバーへの情報共有

Git Submoduleは通常のGitより少し複雑です。

チームメンバー全員が理解している必要があります。

READMEに以下を書いておくと親切です:

  • クローン時は--recursiveオプションを使うこと
  • 更新時はgit submodule update --init --recursiveを実行すること
  • サブモジュールを変更する時の手順

注意点3: プルした後はサブモジュールも更新

他のメンバーがサブモジュールを更新したら、自分の環境でも取り込む必要があります:

【チームメンバーのワークフロー】

開発者A                      開発者B
┌──────────┐                ┌──────────┐
│サブモジュール│                │          │
│を更新     │                │          │
│⬆️ push   │                │          │
└─────┬────┘                │          │
      │                     │          │
      │ ① サブモジュール更新  │          │
      │                     │          │
      ↓                     │          │
┌──────────┐                │          │
│親リポジトリ│                │          │
│参照を更新  │                │          │
│⬆️ push   │                │          │
└─────┬────┘                │          │
      │                     │          │
      │ ② 親リポジトリ更新   │          │
      │                     ↓          │
      └────────────────→ ┌──────────┐ │
                         │git pull  │ │
                         └──────────┘ │
                                ↓     │
                         ┌──────────┐ │
                         │git       │ │← ⚠️ これを忘れずに!
                         │submodule │ │
                         │update    │ │
                         └──────────┘ │
git pull
git submodule update --init --recursive

この2つのコマンドをセットで実行する習慣をつけましょう。

便利なTips: エイリアスを設定する

毎回長いコマンドを打つのは大変なので、エイリアスを設定すると便利です:

# サブモジュール更新用のエイリアス
git config --global alias.sup 'submodule update --init --recursive'

これでgit supと打つだけで更新できます!

チーム運用を楽にする工夫

リサーチの中で見つけた良い方法として、pre-commitフックの活用があります。

サブモジュール側の変更をプッシュし忘れるミスを防ぐために、コミット前にチェックする仕組みを入れるんです。

自動化できることは自動化すると、ヒューマンエラーが減って安心です🌟

6. よくあるトラブルと対処法

初心者がハマりやすいポイントと、その解決方法をまとめます。

【トラブルシューティング早見表】

問題                          解決策
┌─────────────────┐      ┌──────────────────┐
│サブモジュールが   │      │git submodule     │
│空っぽ!         │ ───→ │update --init     │
│                 │      │--recursive       │
└─────────────────┘      └──────────────────┘

┌─────────────────┐      ┌──────────────────┐
│Detached HEAD    │      │cd libs/common    │
│って何?         │ ───→ │git checkout main │
└─────────────────┘      └──────────────────┘

┌─────────────────┐      ┌──────────────────┐
│更新が反映されない│      │親リポジトリで     │
│                 │ ───→ │git add & commit  │
│                 │      │を忘れずに!      │
└─────────────────┘      └──────────────────┘

┌─────────────────┐      ┌──────────────────┐
│マージコンフリクト│      │正しいコミットを   │
│が起きた         │ ───→ │チームで相談して  │
│                 │      │checkout          │
└─────────────────┘      └──────────────────┘

トラブル1: 「Detached HEAD状態」って何?

サブモジュールのディレクトリでgit statusを見ると、detached HEADと表示されることがあります。

これは、特定のコミットを直接参照している状態。

【Detached HEAD の状態】

通常のブランチ上               Detached HEAD状態
┌─────────────┐              ┌─────────────┐
│   main      │← HEAD        │   main      │
│     ↓       │              │             │
│ ○─○─○─●    │              │ ○─○─○─○    │
│  コミット    │              │       ↑     │
└─────────────┘              │      HEAD   │← ブランチではなく
                             │             │  コミットを直接参照
                             └─────────────┘

✅ ブランチで作業できる        ⚠️ ここで変更すると危険!

ブランチではなく、コミット単体を見ている状態です。

解決策:作業前にブランチをチェックアウトする

cd libs/common
git checkout main

これで通常のブランチ上で作業できます。

トラブル2: サブモジュールが空っぽになってる!

リポジトリをクローンしたのに、サブモジュールのディレクトリが空。

これは、--recursiveオプションなしでクローンした時によく起こります。

解決策:サブモジュールを初期化・更新する

git submodule update --init --recursive

これで中身が取得されます。

トラブル3: 更新したのに反映されない

サブモジュールを更新したはずなのに、チームメンバーの環境で反映されない。

原因は、親リポジトリでサブモジュールの参照を更新していないことがほとんど。

解決策:親リポジトリでもコミットする

git add <サブモジュールのパス>
git commit -m "Update submodule reference"
git push

サブモジュール側のプッシュだけでなく、親側のコミット&プッシュも忘れずに!

トラブル4: マージコンフリクトが起きた

複数人がサブモジュールの参照を変更すると、マージコンフリクトが発生することがあります。

解決策:適切なコミットを選んで解決

cd <サブモジュールのパス>
git checkout <正しいコミットハッシュ>
cd ..
git add <サブモジュールのパス>
git commit

どちらのバージョンを採用するか、チームで相談して決めましょう。

7. まとめ - やってみた感想

Git Submoduleを使う前は、「難しそう...」と思っていました。

でも、実際に使ってみたら、思ったよりシンプルでした。

最初の一歩は確かにちょっと複雑です。

コミットが2箇所必要とか、detached HEADとか、慣れないうちは戸惑います。

でも、コピペ地獄から解放されたメリットは本当に大きかったです。

使ってみて良かったこと

【Git Submoduleのメリット・デメリット】

✅ メリット                    ⚠️ デメリット
┌─────────────────┐      ┌─────────────────┐
│複数プロジェクトで  │      │初心者には少し    │
│コードを一元管理   │      │学習コストがある  │
├─────────────────┤      ├─────────────────┤
│バグ修正が        │      │コミットが2箇所   │
│一箇所で済む      │      │必要で手間       │
├─────────────────┤      ├─────────────────┤
│バージョン管理が   │      │チーム全体の     │
│明確で安全       │      │理解が必要       │
├─────────────────┤      ├─────────────────┤
│環境構築が        │      │忘れやすい       │
│スムーズ         │      │更新コマンド     │
└─────────────────┘      └─────────────────┘
  • 複数プロジェクトで同じコードを管理するのが楽になった
  • バグ修正が一箇所で済むようになった
  • チームメンバーの環境構築がスムーズになった
  • バージョン管理が明確になって、予期しない変更が減った

最初の一歩を踏み出すなら

いきなり本番のプロジェクトで使うのではなく、まずは個人プロジェクトで試してみるのがおすすめです。

小さく始めて、慣れてきたらチーム開発に導入する。

そんな流れがいいと思います。

代替手段も検討しよう

Git Submoduleが万能というわけではありません。

プログラミング言語のパッケージマネージャー(npm、pip、など)が使える場合は、そちらの方が簡単です。

また、Git Subtreeという別の方法もあります。

プロジェクトの性質に合わせて、最適な方法を選びましょう。

最後に

複数のプロジェクトでコードを共有する必要があるなら、Git Submoduleは試してみる価値があります。

最初はちょっと戸惑うかもしれませんが、慣れれば強力なツールです。

ぜひ使ってみてください!🔥


📌 コマンド早見表

よく使うコマンドをまとめました。困った時の参考にどうぞ!

┌─────────────────────────────────────────────────┐
│           Git Submodule コマンド早見表           │
└─────────────────────────────────────────────────┘

【追加】
git submodule add <URL> <path>
  サブモジュールを新規追加

【クローン】
git clone --recursive <URL>
  サブモジュール含めてクローン

【初期化・取得】
git submodule update --init --recursive
  サブモジュールを初期化して取得
  ※既にクローン済みの場合

【更新】
git submodule update --remote
  サブモジュールを最新版に更新

【確認】
git submodule status
  サブモジュールの状態を確認

【プル後の同期】
git pull && git submodule update --init --recursive
  親リポジトリとサブモジュールを両方更新
  ※セットで実行!

【エイリアス設定(便利!)】
git config --global alias.sup 'submodule update --init --recursive'
  → git sup で更新できるようになる
0
1
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
0
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?