submoduleを導入する
以下のとおりサブモジュールを追加すると
$ git submodule add -b master https://github.com/nyandora/sub-module
以下の変更がステージングに登録される。
-
.gitmodules
ファイルが追加 or 変更される。- 追加:サブモジュールの導入は初の場合
- 変更:他にサブモジュールがあったり、既存のサブモジュールを全て削除した場合
-
sub-module
というファイルが追加される(ディレクトリではない。以下にnew file
とあることから、ファイルであると分かる)。sub-moduleリポジトリのどのコミットを参照しているか、という情報を持つ。シンボリックリンク的なもの。
$ git status
On branch master
Your branch is up to date with 'origin/master'.
Changes to be committed:
(use "git restore --staged <file>..." to unstage)
new file: .gitmodules
new file: sub-module
sub-module
はファイルであり、sub-module
リポジトリのどのコミットを参照しているか、という情報を持つ。シンボリックリンクのようなもの。ただ、ファイルシステム上ではディレクトリとして扱われる(ややこしい)。
sub-module
ファイルが参照するコミットIDは、以下コマンドで分かる。
$ git submodule
6a6e6214f9a8033d64c6958d3777268f4eb376f2 sub-module (heads/master)
親リポジトリは、sub-moduleリポジトリの6a6e621
のコミットを参照している、ということが分かる。
.gitmodules
、sub-module
はまだステージングにあり、これらをcommit, pushして、親リポジトリのリモートリポジトリに反映する。
親リポジトリに入ったサブモジュール設定を、他の人が取り込む
この状態で、親リポジトリを新規にcloneする。
その後、以下のとおりsub-module
の参照先コミットIDを確認する。
$ git submodule
-6a6e6214f9a8033d64c6958d3777268f4eb376f2 ./
先頭に-
が付いているのは、sub-moduleリポジトリのソースコードをまだローカルに持ってきていない、ということ。
以下のように、sub-moduleリポジトリのソースコードを取得する。
$ git submodule update --init
Submodule 'sub-module' (https://github.com/nyandora/sub-module.git) registered for path './'
Cloning into '略'...
Submodule path './': checked out '6a6e6214f9a8033d64c6958d3777268f4eb376f2'
その後、以下のとおりsub-module
の参照先コミットIDを確認すると、-
が無くなっており、ローカルに実際に6a6e621
のソースコードを持って来れたということが分かる。
$ git submodule
6a6e6214f9a8033d64c6958d3777268f4eb376f2 sub-module (heads/master)
サブモジュール側に入った変更を、親リポジトリ側に反映する
まずは、以下のとおりsub-module
の参照先コミットIDを確認しておく。
$ git submodule
6a6e6214f9a8033d64c6958d3777268f4eb376f2 sub-module (heads/master)
sub-module
のリポジトリに何かしら変更を加え、commit, pushする。
その後、親リポジトリ側で以下コマンドで、sub-module
側の変更を取り込んだかと思いきや・・
$ git submodule update --recursive
実際は以下の通りとなり、参照先のコミットIDが変わらない。ローカルのファイルシステムにも、最新のソースコードが取得されない。
$ git submodule
6a6e6214f9a8033d64c6958d3777268f4eb376f2 sub-module (heads/master)
sub-module
側のmasterブランチに追従するには、以下のようにすべき。つまり、--remote
オプションが必要。sub-module
のmasterブランチが指す最新のコミットIDの内容が、ローカルに取得される。
$ git submodule update --remote --recursive
〜省略〜
From https://github.com/nyandora/sub-module
6a6e621..cecfa10 master -> origin/master
Submodule path 'sub-module': checked out 'cecfa106b59ee4b2ce8dffbe7c513617b80c70f7'
以下のとおり、確かに参照先のコミットIDが変わっている。
$ git submodule
+cecfa106b59ee4b2ce8dffbe7c513617b80c70f7 sub-module (remotes/origin/HEAD)
+
は、以下が不一致であるという意味。
- ローカルリポジトリ上の最新コミットの
sub-module
ファイルが指すコミットID(多くの場合、古いコミットID) - 作業ツリーの
sub-module
ファイルが指すコミットID(多くの場合、新しいコミットID。実際にローカルに取得されているソースコードのコミットID)
両者の差分は、以下で分かる。
$ git diff
diff --git a/sub-module b/sub-module
index 6a6e621..cecfa10 160000
--- a/sub-module
+++ b/sub-module
@@ -1 +1 @@
-Subproject commit 6a6e6214f9a8033d64c6958d3777268f4eb376f2
+Subproject commit cecfa106b59ee4b2ce8dffbe7c513617b80c70f7
先ほどのとおりgit submodule update --remote --recursive
を実行すると、以下のように、作業ツリーでsub-module
が変更されている。
$ git status
On branch master
Your branch is up to date with 'origin/master'.
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git restore <file>..." to discard changes in working directory)
modified: sub-module (new commits)
no changes added to commit (use "git add" and/or "git commit -a")
この変更をadd, commit, pushすると、サブモジュール側に入った変更が、親リポジトリ(リモートリポジトリ)に反映される。(最新のcecfa10
に切り替わっている)
このように、親リポジトリ側では、サブモジュール側のどのコミットIDを参照するか、ということを明示的に示す必要がある。
依存先ライブラリが新しくなったら、依存元のリポジトリでバージョンを上げてJARを取得し直すのと同じような感じ。
サブモジュール側に共通処理を入れることが多いと思うが、共通処理を変更したら、それを利用する側のリポジトリ側で今回のような対応を入れる必要がある。要注意。