特定のファイル変更を検知するGitフックで「mainをpullしたら動かなくなった」を手軽に防ぐ
はじめに
大人数で開発していると、mainブランチを取り込んだだけなのに開発環境が動かなくなり、原因を調べたら「環境変数に変更があって反映する必要があった」ということがよくあります。少なくとも自分は経験があります。
今回は、Gitフックを使ってこの問題をどのように解決したかを紹介します。
背景
私たちの開発チームはバックエンドエンジニアとフロントエンドエンジニアが共同で作業しています。頻繁に行われるコード変更やマージの中で、環境変数やデータベースの変更が原因で、予期せぬエラーが発生することが度々ありました。
例えば、以下のような問題が発生しました:
mainをpull後に突然ログインできなくなり、メンバーに相談しているSlackのスレッドです。皆が思いつく解決策を出し合い、最終的には「seedデータで作られるユーザーのパスワードが変わっていた」ことが原因でログインできなくなっていたことが判明しました。
協力し合う良いチームに見えるかもしれませんが、そもそも開発者が変更箇所を簡単に認知できていれば、この会話も不要だったはずです。
それでは、どのファイルに変更があったかを視覚的に認識できる仕組みを作ろう!ということで、サクッと作りました。
Gitフックのpost-mergeでスクリプトを作成
post-mergeとは
merge コマンドが正常に終了したときに実行されるGitフックです。詳細はGit公式ドキュメントを参照してください。
このフックを使って、git pull(git fetch + git merge)を実行した際に変更を検知するスクリプトを書けばいいのです。
検知したいファイル変更
変更時に作業が必要になるファイルを挙げていきます。
- 環境変数(.env)
- seedデータ
- マイグレーションファイル
- Gemfile
これらの変更を検知したときに、プロンプトに視覚的に分かりやすく知らせるスクリプトを書きます。通常、.gitディレクトリはGitHubなどで管理しないので、他の開発者でもすぐに導入できる状態を目指します。
作成したスクリプト
実際に動くとこのように表示されます。エラーを連想させる赤色にして、視覚的に分かりやすくなっています。
本体
今回は便宜上、scripts/hooksディレクトリに配置しました。
scripts/hooks/post-merge
#! /bin/bash
# 色の定義
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
RED='\033[0;31m'
NC='\033[0m' # No Color
# 区切り線の定義
SEPARATOR="========================================================================================"
# 環境変数の変更を検知
changed_files=$(git diff --name-only HEAD@{1})
if echo "$changed_files" | grep -q 'backend/.env.example'; then
echo -e "${SEPARATOR}"
echo -e "${RED}環境変数が変更されました。作業ディレクトリで${GREEN}.env.example${NC}${RED}を${NC}${GREEN}.env${NC}${RED}に反映してください${NC}"
echo -e "作業ディレクトリ: /backend"
echo -e "${SEPARATOR}"
fi
# seedデータの変更を検知
if echo "$changed_files" | grep -q 'backend/db/seeds'; then
echo -e "${SEPARATOR}"
echo -e "${RED}seedデータが変更されました。作業ディレクトリで${GREEN}make seed${NC}${RED}を実行してください${NC}"
echo -e "作業ディレクトリ: /backend"
echo -e "${SEPARATOR}"
fi
# マイグレーションファイルの変更を検知
if echo "$changed_files" | grep -q 'backend/db/schema.rb'; then
echo -e "${SEPARATOR}"
echo -e "${RED}マイグレーションファイルが変更されました。作業ディレクトリで${GREEN}make rp${NC}${RED}を実行してください${NC}"
echo -e "作業ディレクトリ: /backend"
echo -e "${SEPARATOR}"
fi
# Gemfile変更
if echo "$changed_files" | grep -q 'backend/Gemfile.lock'; then
echo -e "${SEPARATOR}"
echo -e "${RED}Gemfileファイルが変更されました。作業ディレクトリで${GREEN}make build${NC}${RED}を実行してください${NC}"
echo -e "作業ディレクトリ: /"
echo -e "${SEPARATOR}"
fi
やっていることは単純で、マージする前のHEADと差分を比較しているだけです。次はこのpost-mergeフックを反映するスクリプトです。
フックを反映するスクリプト
scripts/hooks/setup-hooks.sh
#!/bin/bash
# .git/hooksディレクトリが存在することを確認
mkdir -p .git/hooks
# post-mergeフックをコピー
cp ./scripts/hooks/post-merge .git/hooks/post-merge
# post-mergeフックに実行権限を付与
chmod +x .git/hooks/post-merge
echo "Git hooks have been set up successfully."
あとはメンバーにsh scripts/hooks/setup-hooks.sh
を実行してもらうだけで準備完了です。
終わりに
大人数で開発していると、どうしても共有漏れが発生してしまうことがあります。ただ、そこを頑張るのではなく、いかに仕組みでカバーできるかを考えるのがエンジニアの仕事だと思います。今後も改善活動を進めていきたいです!
ここまで読んでいただきありがとうございました!
Discussion