maehachi08 Anything Blog

2012年12月23日
git submodule addしたremote repositoryは最新コミットを自動追従しない(更新が必要)
git

あるrepository(以下、"repository A")で使うconfigファイルを全社用に纏めて管理しているrepository(以下、"repository Z")のコミットファイルを参照させるためにgit submoduleを使おうと思ったのですが、そもそもrepository Aから参照するrepository Zのコミット位置は常に最新を見るのか、それともgit submodule実行時にコミット位置なのか分からなかったので検証してみた。

検証に使用したrepositoryはそれぞれこうだ。


repository A : git@github.com:maehachi08/pachitani.git
repository Z : git@github.com:maehachi08/tools.git


## git submoduleでcloneしてみた
```bash
### まずはrepository Aをgit cloneしてくる
$ git clone git@github.com:maehachi08/pachitani.git
$ cd pachitani

### この段階でのrepository AのコミットIDを確認
$ git log | head -1
commit 478cefef9d96fd3d954c679d4a2897b55bdfff78

### ワーキングコピーディレクトリ下でrepository Zをgit submoduleしてくる
### repository URL指定の後ろにtoolsと引数を渡すことでdirectory名を指定
### コマンド結果を見てると実際はcloneして持ってきていることが分かる
$ git submodule add git@github.com:maehachi08/tools.git tools
Cloning into 'tools'...
remote: Counting objects: 26, done.
remote: Compressing objects: 100% (17/17), done.
remote: Total 26 (delta 1), reused 22 (delta 0)
Receiving objects: 100% (26/26), done.
Resolving deltas: 100% (1/1), done.

### git statusで見るとrepository Zをcloneしたdirectoryと
### .gitmodulesというドットファイルが作成されたことが分かる
$ git status
# On branch master
# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage)
#
#       new file:   .gitmodules
#       new file:   tools
#


### git diff --cachedでdiffを確認すると以下のことが分かりました
###  ① .gitmodulesにはsubmoduleの情報が3行
###  ② toolsファイルが新しく作成されている
###  ③ submoduleでcloneされたのは、コミット位置が「d7d8e99b41707229cbad2ba627735a549014e303」であること
$ git diff --cached
diff --git a/.gitmodules b/.gitmodules
new file mode 100644
index 0000000..6a26676
--- /dev/null
+++ b/.gitmodules
@@ -0,0 +1,3 @@
+[submodule "tools"]
+       path = tools
+       url = git@github.com:maehachi08/tools.git
diff --git a/tools b/tools
new file mode 160000
index 0000000..a8d812e
--- /dev/null
+++ b/tools
@@ -0,0 +1 @@
+Subproject commit a8d812e05d1bee9c6fd22364815991eb010eda17


### git submodule addしてきた状態で一度コミットする
$ git commit -m "toolsレポをsubmodule addしてみた" .gitmodules tools


### まぁ、当然コミット位置が進む
$ git log | head -1
commit 94ef7e4c42c67f40d83e02742562297b95b96d58

参照先となるrepository Zを更新してみた

試しに、repository ZにてREADME.mdを更新してコミットしてみます。

### まず、git submodule addしたもののコミット位置を確認
### @repository Aのsummodule
$ cd tools/
$ git log | head -1
commit a8d812e05d1bee9c6fd22364815991eb010eda17


### 2階層上がって、repository Aをgit clone
$ cd ../../
$ git clone git@github.com:maehachi08/tools.git
$ cd tools/


### working repositoryとしてcloneしてきたもののコミット位置を確認
### 当然ながら、git submodule addしたものとコミットIDは同じです
$ git log | head -1
commit a8d812e05d1bee9c6fd22364815991eb010eda17


### README.mdを更新
$ vim README.md
$ git add README.md
$ git commit -m "README.mdを更新しました" README.md


### 更新分をコミットしたのでコミットID確認
### もちろんさっきと違う
$ git log | head -1
commit 483cbaedd41e6cf631855b9c01bae8d77370c6b9


### github repositoryにpushする
$ git push origin master

git submodule addしたrepository Aのworking copyでrepository Zの更新を反映

repository Zをsubmoduleとしてcopyしたrepository Aではrepository Zの更新はどう見えるのか。
自動的に最新コミットを追従してくれるのか、それとも、手動でpullしてこないと駄目なのか。

### repository Aに移動
$ cd ../pachitani/


### repository A自体のコミットIDはgit submodule addした直後から変更なし
$ git log | head -1
commit 94ef7e4c42c67f40d83e02742562297b95b96d58


### repository Aのsubmodule addしたrepository Zのコミット位置は
### git submodule add段階のコミット位置から更新されていない
$ cd tools/
$ git log | head -1
commit a8d812e05d1bee9c6fd22364815991eb010eda17

以上の結果から、git submodule addしたsubmoduleレポジトリのコミット位置は、submodule addした段階のコミット位置のまま、更新を追従することはない

ことが分かりました。

submoduleの更新(最新コミットの追従)

まずはsubmoduleなディレクトリでgit pullして更新できるか試しました。結論言うとできたようです。

$ git pull
remote: Counting objects: 5, done.
remote: Compressing objects: 100% (2/2), done.
remote: Total 3 (delta 1), reused 3 (delta 1)
Unpacking objects: 100% (3/3), done.
From github.com:maehachi08/tools
   a8d812e..483cbae  master     -> origin/master
Updating a8d812e..483cbae
Fast-forward
 README.md | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)


### git logでコミット位置を確認したところ、最新コミットを追従したようです
$ git log | head -1
commit 483cbaedd41e6cf631855b9c01bae8d77370c6b9

次に、
git submodule foreach 'git pull origin master'で更新できる試します。結論言うと、これも出来ました。

### pushで最新コミット位置にしてしまったので、repository Zに再度更新をかけます
$ cd ../../tools/
$ echo "" >> README.md
$ git add README.md
$ git commit -m "test" README.md
$ git push origin mastet
$ git log | head -1
commit 6f20c66a5c839d637fb5439eeadab90eb539b588


### repository Aの中にあるsubmoduleのrepository Zのコミット位置
$ cd ../pachitani/tools/
$ git log | head -1
commit 483cbaedd41e6cf631855b9c01bae8d77370c6b9

### 更新かけてみる
### 注意なのは、pullとは違ってsubmoduleの親repositoryにて実行すること
$ cd ../
$ git submodule foreach 'git pull origin master'
Entering 'tools'
remote: Counting objects: 5, done.
remote: Compressing objects: 100% (2/2), done.
remote: Total 3 (delta 1), reused 3 (delta 1)
Unpacking objects: 100% (3/3), done.
From github.com:maehachi08/tools
 * branch            master     -> FETCH_HEAD
Updating 483cbae..6f20c66
Fast-forward
 README.md | 1 +
 1 file changed, 1 insertion(+)


### submoduleのrepository Zのコミット位置が最新を追従している
$ cd tools/
$ git log | head -1
commit 6f20c66a5c839d637fb5439eeadab90eb539b588

今までの整理

  • working repositoryにremote repositoryをサブディレクトリとして組み込むには、git submodule add
  • submoduleのmasterブランチの更新を自動追従しない
  • submoduleにmasterブランチの更新を反映するには以下2つの方法がある
    1. submoduleディレクトリ内でgit pull
    2. 親repositoryディレクトリ内でgit submodule foreach 'git pull origin master'