Git SubmoduleでのやらかしとGit Submoduleとうまく付き合うために

この記事は[Ateam Hikkoshi Samurai Inc. & Ateam Connect Inc.（エイチーム引越し侍、エイチームコネクト） Advent Calendar 2019](https://qiita.com/advent-calendar/2019/hikkoshi) 4日目の記事です。

[本番環境でやらかしちゃった人 Advent Calendar 2019](https://qiita.com/advent-calendar/2019/yarakashi-production)が人気ですね。おはこんばんにちは。
👆このカレンダー程ではないですが、私もやらかした事があります。`Git Submodule`で。
今回はそれについて何が起こったのか、どう対策したのかと簡単に説明した後、
`Git Submodule`を使う上でよく使うコマンドについて説明します。

## はじめに
Gitについて学びたい方には以下をお勧めします。
https://git-scm.com/book/ja/v2
上記のSubmoduleについてのページは以下です。(おそらくこの記事よりも参考になるかと思います)
[7.11 Git のさまざまなツール - サブモジュール](https://git-scm.com/book/ja/v2/Git-%E3%81%AE%E3%81%95%E3%81%BE%E3%81%96%E3%81%BE%E3%81%AA%E3%83%84%E3%83%BC%E3%83%AB-%E3%82%B5%E3%83%96%E3%83%A2%E3%82%B8%E3%83%A5%E3%83%BC%E3%83%AB)

## 背景
弊社ではサービスによってリリースする方法として、Deployボタンをポチっと押す簡単なものから、複数の手順を踏んでリリースをするものまで複数あります。
また、リリースはエンジニアなら誰でもできるわけではなく、一部のメンバーのみができるような権限管理がされています。
`Git Submodule`のやらかしは、複数の手順を踏んでリリースするものでの出来事です。

### とあるチケットのリリース作業
いつものように開発フローを進みリリースができる状態となったプログラムのリリース作業を進めていました。
別の開発者が開発し、私がコードレビューし、私がリリースを行うタイプでした。
一通りの確認作業を実施し、本番環境へのリリースを完了しました。
リリースを完了した直後、エラー通知がひとつ、またひとつと届くのを確認しました。
リリースによる負荷でエラーが発生することもあるのでその時点ではそれ系かな？と思いつつエラー通知を確認しました。
そこには今まで見たことのないタイプのエラー通知が来ており、一目で
あ
あ!ヤバいやつだ!!とすぐに分かったので担当者と一緒にリリースしたものの切り戻し作業を実施しました。
5分程度で切り戻しが完了し、次は何が原因だったのかを確認する作業を始めました。

## 何が起こっていたのか
本来Submoduleが参照すべき先が過去に巻き戻ってしまっていた事が原因です。
(`Git Submodule`の仕組みを使った事がある方にとってはあるあるな事なのかもしれません)
リリースする手順の中にDiffの確認をする手順も含まれており、そこにSubmoduleのDiffも出ていたのですが、それを私が見逃してしまっていました。
そのDiffを見逃してしまった結果、本番環境で問題を発生させてしまう結果となったのです。

## 何が原因だったのか
まず、本件における責任はリリースを実施した私にあります。リリースをするという役割を持つ事はその結果起こりうることへの責務を負うことに繋がるからです。
原因としては以下があると考えました。

1. 開発者がSubmoduleの向き先変更をPushしたコミットへ含めてしまっていた
1. リリース手順の差分確認の際、Submoduleの向き先変更が含まれていることに気づくことができなかった

詳細は割愛しますが、この時は 2. についての対策を実施しました。

## 行った対策
今までの手順では、通常のコードの差分と同時にSubmoduleのDiffも確認していました。
それを、Submoduleの変更があった場合は、そのSubmoduleの向き先ががSubmodule自身のMasterと等しいかのチェックをリリース時の処理に追加しました。

## 改善されたフローと新たな課題
上記の対策を実施した結果、Submoduleが最新出ない場合は確認のダイアログが表示されるようになり、Submoduleの向き先を誤って変更してしまうという種類のミスは発生していません。
しかし、なにかのリリースでSubmoduleの向き先を更新するとそのSubmoduleを参照している別Projectもリリースする必要が出てきたため、リリースに時間がかかるようになってしまいました。ここは要改善点です。

## `Git Submodule`におけるケース別操作例
ここから`Git Submodule`についての説明と、主な対応方法について説明します。
はじめに、でも言及しましたが、[7.11 Git のさまざまなツール - サブモジュール](https://git-scm.com/book/ja/v2/Git-%E3%81%AE%E3%81%95%E3%81%BE%E3%81%96%E3%81%BE%E3%81%AA%E3%83%84%E3%83%BC%E3%83%AB-%E3%82%B5%E3%83%96%E3%83%A2%E3%82%B8%E3%83%A5%E3%83%BC%E3%83%AB)を読むこともお勧めします。
以下からは、私の理解を私がわかりやすいと思う言葉を使って説明していますので、一部正確ではない部分、または間違っている部分があるかもしれません。その点ご留意ください。

**Submodule**とは**ある Git リポジトリを別の Git リポジトリの共通モジュールとして扱うための仕組み**です。

## `Git Submodule`を使うことで何が嬉しいのか
サービスやプロジェクトを跨いで使用するような共通処理をSubmodule化することで一元管理ができるようになります。
便利な仕組みですが、その簡単さ故、人為的なミスも起こりやすいです。
以下に遭遇しうるパターンとその際に実施すべきコマンド例を上げます。

### 対象のプロジェクトで使用されているSubmoduleの確認方法

```sh
# 任意のプロジェクト直下
git submodule status
586857a3fa26c271eacb1e8a845fabef79b6fb2a sub/module1 (remotes/origin/HEAD)
da489da68e9f753d3d5c3da53eca68c9c0f559ab lib/common_submodule2 (remotes/origin/HEAD)
```
※リポジトリ直下の`.gitmodules`の中身を確認することでもSubmoduleの確認が可能です。

### Submoduleでdiffが出たとき
`git pull`や`git merge`で最新の更新を取り込んだ際に、`(master *)`の様に差分がでることがあります。

```sh
git diff
diff --git a/sub/module1 b/sub/module1
index 6a55aa29..8d4c117cb 160000
--- a/sub/module1/
+++ b/sub/module1/
@@ -1 +1 @@
-Subproject commit a8e3a94836ec75bb36539c29652fc844cbfa072d
+Subproject commit e5546365dffd2d5d34d0ab8f5923f61496007358
```

## `git submodule update` について
`git submodule update` は`git pull`などで最新の更新を取得した際などに、
自身の環境のSubmoduleが向いている向き先を取得した更新をもとに参照すべき向き先へ変更するコマンドです。
`git diff`でSubmoduleの変更が出た際は、多くの場合`git submodule update`で差分を解消することが必要です。

## Submoduleの変更をaddする場合
Submoduleの変更を`git add`して`git commit`する時とはどういう場合でしょうか。
それは、自身がそのSubmoduleを変更しその向き先へ合わせる場合、または別の開発で更新された向き先へ合わせるために更新する場合などです。
Submoduleの向き先の変更のaddとcommitについては、何らかの手段で制限をすることを推奨します。前述したように、あまりにも簡単に向き先を変更できるためです。
日々の開発において、Submoduleの向き先の変更に気づかずにcommitしてしまう、というミスが起こりえます。人間はミスをする生き物です。なのでミスをするという前提で考えましょう。

私がいるプロジェクトでは、Submoduleの変更をそのままcommitすることはできません。
Gitの仕組みの一つである`pre-commit`でSubmoduleの変更がcommitされようとしていたらRejectする仕組みを採用しています。

## 終わりに
私がなにかを学ぶ時、特にミスをしない方法を学ぶタイミングは大抵**そのミスを犯してしまった時**です。なぜそのミスが起こったのか、どう対策をしたのか、その結果そのミスの発生率はどうなったのか、を残すことで1人でも同じ轍を踏む人が少なくなればと思います。
また、本記事を読まれた方ならなんとなく分かるかもしれませんが、まだまだ課題や改善すべき点が本件以外にも多くあります。そのような課題を解決したい!俺が解決してやる!という気概のある方はぜひ👇下記をご参照ください。

# お知らせ
エイチームグループでは一緒に活躍してくれる優秀な人材を募集中です。
興味のある方はぜひとも[エイチームグループ採用ページ](http://www.a-tm.co.jp/recruit/)（[Webエンジニア詳細ページ](http://www.a-tm.co.jp/recruit/requirements/career/lifestylesupport-webengineer/)よりお問い合わせ下さい。
あるいは、[Qiita Jobs](https://jobs.qiita.com/)の[引越し侍Webエンジニアチーム](https://jobs.qiita.com/employers/a-hikkoshi/development_teams/173)、[自社サービスWebエンジニア／インフラからサービス改善まで！]()、[求む！引越し侍大規模リプレイスにおけるフロントエンドのリードエンジニア募集！](https://jobs.qiita.com/postings/317)の記事をみて、興味が出てきた方は是非Qiita Jobsのチャットでメッセージをください。

# 明日
明日は最近マネージャー業務が忙しくコードを書く時間がなかなか取れないと嘆いている[keki](https://qiita.com/keki)の記事です。
お楽しみに！