別リポジトリを埋め込む- git submodule
別の Git リポジトリをサブモジュールとして自リポジトリに取り込みます。
概念図
構文
git submodule <command> [<args>]使用例
サブモジュールを追加
git submodule add https://github.com/user/lib.git libs/libサブモジュールごとクローン
git clone --recurse-submodules <url>クローン後にサブモジュールを初期化・取得
git submodule update --init --recursiveサブモジュールを最新にする
git submodule update --remoteサブモジュールとは
追加から更新までの流れ
サブモジュールを追加する
git submodule add <url> <path>で指定パスに子リポジトリを登録します。.gitmodulesファイルが自動作成され、親リポジトリに追跡されます。コミットして共有する
.gitmodulesとサブモジュールのパスをgit commitしてgit pushします。チームメンバーが取得する際は--recurse-submodules付きでクローンします。サブモジュールを最新にする
git submodule update --remoteで子リポジトリのデフォルトブランチの最新コミットを取得します。その後、親リポジトリ側で変更をコミットして、どの子コミットを使うかを固定します。
# 1. 追加
git submodule add https://github.com/user/lib.git libs/lib
git commit -m "Add lib submodule"
# 2. クローン側(初めて取得する人)
git clone --recurse-submodules <parent-url>
# すでにクローン済みなら
git submodule update --init --recursive
# 3. 最新に更新
git submodule update --remote libs/lib
git commit -am "Bump lib submodule"ハマりポイント
親リポジトリが指すのは「特定のコミット」
サブモジュールはブランチではなく**コミットハッシュ**で固定されます。子リポジトリで新しいコミットを作っても、親側で更新をコミットし直さない限り追従しません。これを知らないと「最新にしたはずなのに反映されない」と混乱します。
--recurse-submodulesの付け忘れ通常の
git cloneやgit pullではサブモジュールは更新されません。git config --global submodule.recurse trueを設定しておくと、pull 時に自動で再帰的に更新されて便利です。サブモジュールの削除は面倒
git submodule deinit <path>→git rm <path>→.git/modules/<path>の手動削除、と3段階必要です。単にgit rmしただけでは残骸が残ります。代替案も検討する
サブモジュールは運用コストが高いため、モノレポ化・パッケージマネージャー(npm, pnpm workspace, Go modules 等)・
git subtreeなどの代替も検討する価値があります。
