Skip to main content

git commit で Hugo ローカルサーバへの自動デプロイを実現する

Author
blackratel

このブログは 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

「コミットしてブラウザを見るだけ」という状態になると、記事を書くことだけに集中できる。シンプルだが、実運用にちょうどいい自動化だと思っている。