個人的に作っているツールでsubmoduleを使っているわけですが、
結構面倒なんですよねこのgitのsubmoduleという機能。
何かやるたびにググって・・・を繰り返しているので、
自分の理解を整理する意味でもちょっとまとめてみたいと思います。
それでもきっと翌日にはまたググるんだろうけど。
まずは親プロジェクトをclone
main1というプロジェクトで、その中にサブモジュール(sub)を利用するシーンを想定。
git clone https://github.com/myrepo/main1.git
次にcloneしてきたmain1ディレクトリに入ってsubmoduleをclone
git submodule add https://github.com/myrepo/sub.git
この状態で、 git status
を叩くと
On branch master
Your branch is up-to-date with 'origin/master'.
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)
new file: .gitmodules
new file: sub
と言った感じで、追加したsubというサブモジュールと、サブモジュールを管理するドットファイル、.gitmodulesが追加されている。
.gitmodulesって?
このgitmodulesをmain1に置いておくことで、別の環境や、別の人がこのmain1をcloneした際に、
gitmodulesファイルの中身をgitが勝手に読み込んでくれて別プロジェクトのソースをサブモジュールとしてcloneしてくれるという寸法。
中身はこんな感じになってる。
[submodule "sub"]
path = sub
url = https://github.com/myrepo/sub.git
とりあえずこの状態でmain1をpush
git add .
git commit -m "commit"
git push origin maseter
これでgithubのほうをみると、
これは「subというディレクトリはこちら(@ c1eb8af)を参照しています」ということ。
この@ c1eb8af
はなんなのかというと、
subというプロジェクトのコミットIDのことを差している。
submoduleはコミットIDを参照する
これがsubmoduleを理解するために非常に大事なポイントでして、
同時に理解を難しくしている所以のひとつでもあります。
コミットIDを参照していることで何が起こるかというと、
今この状態のまま、
別の人がsubというプロジェクトに対して更新を行ったとします。
その後、このmain1というプロジェクトの中で、git pullをしても、先程別の人がコミットした内容は取ってこれないということ。
じゃあどうすればいいのかというと、
main1直下ではなく、
main1/sub
に移動してこの配下でgit pull をします。
(main1直下で、 git submodule foreach git pull origin master
でもOK。こっちのほうがスタンダード?)
すると至って普通の形で別の人が更新した内容をローカルに持ってくることができます。
ここで問題が発生する
main1/sub配下に入ってpullしてきたわけですが、
pullすることでsub配下のmasterブランチが参照しているコミット番号が変わります。
ところが親プロジェクトのmain1ではまだpullしてくる前のコミット番号を参照しています。
つまりmain1の中でgit statusを叩くと、差分があると言われます。(コミット番号に差分がある)
これはアカン状態です。
とはいっても別に難しいことはする必要はなく普通に、
git add .
git commit -m 'さぶもじゅーる更新'
git push origin maseter
のフローを踏んであげればOKです。
こうすることでリモートが持つmain1プロジェクト配下のsubというディレクトリが参照するコミット番号がsubプロジェクトのmasterのコミット番号を参照することになります。
使ってみた感想
最初はかなり躓いたりしてかなり悲しかったのですが一つ一つsubmoduleの性質を紐解いていけば普通に使えるものでした。
僕の場合、趣味でbotを作っているのですが、
それぞれ、
- line
- slack
といて、それぞれが共通で使うライブラリをサブモジュールとしてcloneさせています。
そんな感じです。