submoduleがあるリポジトリの管理について

# git submoduleとは

gitで管理しているリポジトリに別リポジトリを連携させる機能です。
このリポジトリのコードを動かすときに必要なリポジトリをクローンしてくださいを自動化できます。

しかし、システム開発途中で起こることとして、親のリポジトリ更新に合わせて、サブモジュール側にも変更が必要になるパターンです。
本来は、サブモジュールで読み込むリビジョンは安定版を使用して、その基盤の上に新規コードを作っていくのが良いとは思いますが、新規機能の追加などでそうも言っていられないことがあります。

なので、この記事ではサブモジュールに変更を加える際に利用するコマンドを説明します。

# ますは、テストリポジトリの作成

まず、`test_main`, `test_a`, `test_b` の３つテストリポジトリを立てて、`test_a`, `test_b` を`test_main`のsubmoduleに設定します。

```bash
./test_main
├── README.md
├── test_a    # submodule
│   └── README.md
└── test_b    # submodule
    └── README.md
```

`test_main` をクローンしてから、サブモジュールを作成するまでの手順は以下です。

```bash
$ git clone git@github.com:wakaba130/test_main.git
$ cd test_main/
$ git submodule add git@github.com:wakaba130/test_a.git
$ git submodule add git@github.com:wakaba130/test_b.git
$ ls
README.md  test_a  test_b
```

この状態でいったんコミットします。

```bash
$ git add .
$ git commit -m "add submodule"
[main ace8afe] add submodule
 3 files changed, 8 insertions(+)
 create mode 100644 .gitmodules
 create mode 160000 test_a
 create mode 160000 test_b

$ git push origin main
# もろもろの表示省略
To github.com:wakaba130/test_main.git
   b056e33..9e05be5  main -> main
```

※ コミットする時に以下のようにエラーが出た場合は、`Run`以下の2行のコマンドにより、
メールアドレスとユーザー名を設定してください。

```
*** Please tell me who you are.

Run

  git config --global user.email "you@example.com"
  git config --global user.name "Your Name"

to set your account's default identity.
Omit --global to set the identity only in this repository.

fatal: empty ident name (for <---@---.>) not allowed
```

ブラウザでgithubを確認して、以下のようになっていたらOK

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/104675/689917e1-b63d-9b72-728e-cef31100c57a.png)

# ここからが本題

では、このサブモジュールに加えた変更をコミットするにはどうするのかやっていきたいと思います。
まず、サブモジュールにpushすると現在のブランチに直接プッシュして変更してしまうため、サブモジュール側に新しいブランチを切って、そちらにコミットします。

```bash
# サブモジュールのチェックアウト
$ git submodule foreach git checkout -b develop
# test_mainのブランチのチェックアウト
$ git checkout -b develop
```

## コマンド解説

リポジトリ内にサブモジュール (submodule)が複数あり、各サブモジュールで同じコマンドを実行したい場合にforeachを使用します。

```
$ git submodule foreach <コマンド>
```

# 変更を加えた後のコミット＆プッシュ 

`test_a`と`test_b`のREADME.mdを以下のように変更しました。

```markdown:test_a/README.md
# test_a

developブランチに変更しました。
```

```markdown:test_b/README.md
# test_b

developブランチに変更しました。
```

変更した結果を`foreach`を使用してコミット＆プッシュします。

```bash
# サブモジュールに対するコミット&プッシュ
$ git submodule foreach git add -A
$ git submodule foreach git commit -m 'submodule commit'
$ git submodule foreach git push --set-upstream origin develop
# test_mainリポジトリに対するコミット＆プッシュ
$ git add -A
$ git commit -m "submodule commit"
$ git push origin develop
```

あとは、各サブモジュールでプッシュしたブランチをメインブランチにマージしたりする。

# submoduleの参照するコミットを変更する

サブモジュール側を変更しても、サブモジュールを参照している親側は自動で変更されません。
サブモジュールで紐づいているのは、コミットIDであり、ブランチではないからです。
そのため、変更後のコミットIDを参照するように変更する必要があります。

```bash
# サブモジュールのディレクトリに移動
$ cd test_b
# 必要なバージョンをチェックアウトする
$ git checkout <コミットID>

# 親側に移動
$ cd ../
# 親側でコミット
$ git add .
$ git commit -m "revision test_b" 
```

# submoduleを含んだクローン

サブモジュールを使用しているリポジトリをクローンする際には、`--recursive`オプションを付ける必要があります。

```bash
$ git clone --recursive git@github.com:wakaba130/test_main.git
```

`--recursive`を付け忘れた場合は、以下のコマンドでサブモジュールが読み込めます。

```bash
$ cd test_main
$ git submodule update --init
```

# まとめ

サブモジュール側に変更があった際に使用するコマンドをまとめました。
今後の業務などで他にも覚える必要のあるコマンドが出てきたら更新します。

# 参考

https://qiita.com/shizuma/items/2b2f873a0034839e47ce

https://qiita.com/sotarok/items/0d525e568a6088f6f6bb

https://qiita.com/shizen-shin/items/1406e50a95d5e4f15d0e

https://qiita.com/msh0x01/items/43ac9bf71781eea60c75

https://www.m3tech.blog/entry/git-submodule