このブログは Hugo で構築している。記事作成時は Ansible でローカルの Hugo を更新してプレビューし、確認後に本番へアップロードするフローで運用している。
これまではコミット後に ansible-playbook コマンドを手動で実行していたが、コミットしたら自動で Hugo が更新されプレビューに集中できる環境を作りたかった。
この記事では、git の post-commit hook と Ansible を組み合わせた自動デプロイの仕組みを紹介する。
構成の概要 #
このブログは以下の構成で運用している。
| 役割 | 内容 |
|---|---|
| 記事管理 | git リポジトリの files/*.md |
| ローカルデプロイ | Ansible Playbook (ansible_connection=local) |
| プレビュー | ローカルの Hugo サーバ |
自動化の対象は「コミット → Ansible 実行」の部分だ。
なぜ git hook を選んだか #
git hook にした理由は以下の通りだ。
- コミット単位で管理できる — いつ・何を反映したか git 履歴に残る
- ロールバックが楽 —
git revertすれば記事を戻せる - 余計なプロセスを常駐させなくていい — デーモンが不要
実装 #
フックの配置 #
git のデフォルトフックディレクトリは .git/hooks/ だが、ここは git 管理外なので GitHub に push されない。別 PC でクローンしたときにフックが消えてしまう。
そこで .githooks/ というディレクトリをリポジトリのルートに作り、git にフックの参照先を変更させる。
mkdir -p .githooks
git config core.hooksPath .githooksこの設定で git は .git/hooks/ の代わりに .githooks/ を参照するようになる。.githooks/ はリポジトリに含まれるため、GitHub にも push できる。
post-commit スクリプト #
.githooks/post-commit に以下を配置する。
#!/bin/bash
# files/*.md の変更のみを対象にする
CHANGED=$(git diff HEAD~1 --name-only 2>/dev/null | grep -E '^files/.*\.md$')
[ -z "$CHANGED" ] && exit 0
echo "========================================"
echo " files/*.md の変更を検知しました"
echo "$CHANGED" | sed 's/^/ /'
echo "========================================"
echo " Ansible を実行します..."
cd "$(git rev-parse --show-toplevel)"
ansible-playbook -i inventory.ini play.yml
if [ $? -eq 0 ]; then
echo "========================================"
echo " デプロイ完了"
echo " プレビュー : ローカルで確認してください"
echo "========================================"
else
echo "[ERROR] Ansible が失敗しました"
exit 1
fi実行権限を付与してコミットする。
chmod +x .githooks/post-commit
git add .githooks/post-commit
git commit -m "add: post-commit hook"ポイント:files/*.md だけを対象にする
#
記事は files/*.md に配置するため、そのファイルが変更されたときだけ Ansible でデプロイするようにした。
日常の使い方 #
# 記事を書く
vim files/新記事.md
# コミットするだけで自動デプロイ
git add files/新記事.md
git commit -m "add: 新記事"
# → Ansible が自動実行される
# ローカルでプレビュー確認コンテンツを以前の状態に戻す #
記事の内容を過去の状態に戻したい場合は、git の履歴を使って対応できる。
特定ファイルを以前のバージョンに戻す #
# 変更履歴を確認して戻したいコミットのハッシュを調べる
git log --oneline files/記事名.md
# 指定コミット時点の内容に戻す
git checkout <コミットハッシュ> -- files/記事名.md
# コミットすると hook が発火して自動デプロイされる
git add files/記事名.md
git commit -m "revert: 記事名を以前の状態に戻す"直前のコミットを丸ごと取り消す #
# 直前のコミットを打ち消す新しいコミットを作成する
git revert HEAD
# こちらも files/*.md が含まれていれば hook が発火して自動デプロイされるgit revert は履歴を書き換えずに「取り消しコミット」を積む方法のため、安全に使える。
別 PC でクローンした場合 #
core.hooksPath はローカルの git 設定(.git/config)に書き込まれるため、クローンしても引き継がれない。新しい環境では以下を一度実行する必要がある。
git clone <リポジトリURL>
cd <リポジトリ名>
git config core.hooksPath .githooksまとめ #
| やること | コマンド |
|---|---|
| フック参照先の設定 | git config core.hooksPath .githooks |
| フックの有効化確認 | git config --get core.hooksPath |
| 手動でデプロイ | ansible-playbook -i inventory.ini play.yml |
「コミットしてブラウザを見るだけ」という状態になると、記事を書くことだけに集中できる。シンプルだが、実運用にちょうどいい自動化だと思っている。