GitSubmoduleの基本的な使い方

## git submoduleとは
git submoduleとは、Gitリポジトリ内に別のGitリポジトリをサブモジュールとして含めることができる機能です。サブモジュールを使うことで、複数のプロジェクトを同時に管理することができます。
例えば、あるプロジェクト内で他のプロジェクトを依存関係として管理する場合などに使用されます。

---

## 基本的な使い方
### サブモジュールの追加

```sh
$ git submodule add [サブモジュールのリポジトリURL]
```

---

### サブモジュールの初期化
```sh
$ git submodule init
```

```sh
# ハッシュコミットの前に「-」がついている場合はサブモジュールを取得できていない
$ git submodule
-[ハッシュコミット] submodule1
$ git submodule update --init
# もしくは
$ git submodule init
$ git submodule update
Cloning into '/Users/Project/submodule1'...
Submodule path 'submodule1': checked out 'ハッシュコミット'
# 取得すると「-」がとれる
$ git submodule
 [ハッシュコミット] submodule1 (heads/main)
```

:::note warn
mainブランチの最新状態を自動追従されるものではありません。
特定のリビジョンを参照するものです。
:::

![submodule-commit.drawio.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2348159/bc54e17d-0ab0-5cd7-cb03-5425df3351d4.png)

---

### サブモジュールを含んだリポジトリのクローン
```sh
$ git clone --recursive [サブモジュールを含んだリポジトリのURL]
```

---

### サブモジュールの更新

```sh
$ git submodule update
```

:::note warn
メインプロジェクトでチェックアウトしてもサブモジュールのリビジョンが自動で切り替わってくれないので上記のコマンドが必要になります。
:::

:::note info
`git config --global submodule.recurse true`で自動的にモブモジュールを更新することも可能
:::

![submodule-update.drawio.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2348159/156c7711-5cf3-7b22-b548-e1fcc677a16e.png)

---

#### mainブランチの最新リビジョンをチェックアウトする
```sh
$ git submodule update --remote
# 特定のサブモジュールのみチェックアウトする場合
$ git submodule update --remote [サブモジュール名]
# サブモジュールディレクトリ配下で以下のコマンド実行時と同じ
$ git fetch
$ git merge origin/master
# 最新リビジョンにチェックアウト後に元のリビジョン(親プロジェクトが保持しているリビジョン)に戻りたい場合
$ git submodule update
```

![udpate--remote.drawio.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2348159/866ae3f4-c718-4ecb-f2a1-b4af0e884e91.png)

---

### submodule変更後最新のリビジョンを取り込む
```sh
$ git submodule update --remote --merge
```
:::note info
--rebase オプションもあります
:::

:::note warn
サブモジュール内に変更を加える場合は、ブランチを切って作業してください。
--merge/--rebaseオプションを忘れると変更が上書きされてしまいます。
:::

---

### メインプロジェクトにpushする
まず、サブモジュールに変更を加えます。
```sh
$ cd submodule1
$ git checkout -b feature
$ touch new.txt
$ git add new.txt
$ git commit -m 'add new.txt'
$ git push
```

サブモジュールに加えたのでサブモジュールのリビジョンは更新されています。
そのため、メインプロジェクトにもサブモジュールのリビジョン変更をpushする必要があります。

```sh
$ cd ../
# サブモジュールに更新が入ると「+」がつく
$ git submodule
+[コミットハッシュ] submodule1 (コミットハッシュ)
$ git add submodule1
$ git commit -m 'update submodule1'
$ git push
```

---

#### (サブモジュールをpushしていない場合)pushさせない

--recurse-submodules=checkでサブモジュールのコミットがpushされていない場合、メインプロジェクトのpush時にエラーが表示されます。
```sh
$ git push --recurse-submodules=check
The following submodule paths contain changes that can
not be found on any remote:
  submodule1

Please try

	git push --recurse-submodules=on-demand

or cd to the path and use

	git push

to push them to a remote.

fatal: Aborting.
```

---

#### (サブモジュールをpushしていない場合)自動でPushする
`git push --recurse-submodules=on-demand`でpushし忘れのサブモジュールもまとめてpushすることが可能です。

```sh
$ git push --recurse-submodules=on-demand
```

---

### 追従ブランチの変更
```sh
$ git config -f .gitmodules submodule.submodule1.branch feature
$ cat .gitmodules 
[submodule "submodule1"]
	path = submodule1
	url = https://github.com/example/submodule1.git
	branch = feature
```

---

### .gitmodulesの変更を.git/configに反映させる
```sh
$ git submodule sync
```

---