はじめに
最近、git submodule を使っているリポジトリを触る機会がありました。
僕自身、言葉は知っていたものの「結局これって何をしているの?」が曖昧なままだったので、今回あらためて調べてみました。
git submodule とは
一言で言うと、別の Git リポジトリを、自分のリポジトリ内のサブディレクトリとして管理する仕組みです。
たとえば my-app の中で、共通ライブラリ shared-utils を使いたいとします。
このとき、コードをコピーして持ってくる代わりに、shared-utils リポジトリへの参照を持つのが submodule です。
my-app/
├── src/
├── shared-utils/ ← submodule
└── .gitmodules
submodule は常に最新を追いかけるわけではなく、特定のコミットハッシュを指定できます。つまり、親リポジトリ側でどの状態の submodule を使うかを明示的に指定できます。
おさえておきたいコマンド
submodule を追加する
git submodule add https://github.com/example/shared-utils.git shared-utils
実行すると、shared-utils/ が追加され、.gitmodules が作成(または更新)されます。
.gitmodules の中身はこんな感じ:
[submodule "shared-utils"]
path = shared-utils
url = https://github.com/example/shared-utils.git
clone 時に submodule も一緒に取得する
通常の git clone だけだと、submodule の中身が取得されないため、以下のオプションを追加する必要があります。
git clone --recurse-submodules https://github.com/example/my-app.git
すでに clone 済みのリポジトリで submodule を取得する
上記のオプションを指定せず clone してしまった場合は、以下のコマンドで取得できます。
git submodule update --init --recursive
ハマったポイント
submodule 側でコミットしても、親リポジトリに反映されない
submodule 内で変更して push しても、親リポジトリは古いコミットを指したままです。
親側で参照更新をコミットする必要があります。
cd shared-utils
git add <必要なファイル>
git commit -m "fix: something"
git push
cd ..
git add shared-utils
git commit -m "chore: update submodule reference"
git push
pull しただけでは submodule が更新されない
親リポジトリで git pull しても、submodule の中身は自動更新されないので、以下のようにする必要があります。
git pull && git submodule update --init --recursive
さいごに
今回調べてみて、submodule は別の Git リポジトリを、自分のリポジトリ内のサブディレクトリとして管理する仕組みということがわかりました。また、サブディレクトリに指定した Git リポジトリの特定のコミットを指定して管理できるのは、押さえておきたいポイントだなと思いました。