2026年5月23日

2026年5月23日

GitフックでWP-CLIやコードチェックを自動実行する方法(pre-commit・post-merge・post-receive)

Git フックを使うと、コミットの直前に PHP の構文チェックやコーディング規約チェックを走らせたり、プル後やサーバーへのプッシュ後に WP-CLI のコマンドを自動で実行したりできます。この記事では、WordPress のテーマ・プラグイン開発でよく使う pre-commit、post-merge、サーバー側の post-receive の3つについて、そのまま使えるスクリプト例と、チームで共有する方法、つまずきやすい点を説明します。

Gitフックの基本

Git フックは、コミットやマージなどの操作の前後に Git が自動で実行するスクリプトです。リポジトリの .git/hooks/ に、決まった名前(pre-commit など)で実行権限付きのファイルを置くと有効になります。

押さえておきたい性質は次のとおりです。

  • pre- で始まるフックは、スクリプトが0以外の終了コードを返すと操作が中止される。チェックに失敗したらコミットさせない、という使い方ができる
  • post- で始まるフックは操作の後に動くもので、失敗しても操作自体は取り消されない
  • .git/hooks/ の中身はリポジトリにコミットされない。そのため、何もしなければフックは自分の手元でしか動かない

最後の点はチーム開発で問題になるため、後半で共有方法を説明します。

pre-commit:コミット前に PHP をチェックする

まずは、コミットしようとしている PHP ファイルだけを対象に php -l(構文チェック)を実行するフックです。構文エラーのあるファイルが本番に出ると画面が真っ白になる事故につながるため、最初に入れておく価値があります。

#!/bin/sh
# .git/hooks/pre-commit

# ステージされた(追加・変更された)PHPファイルだけを対象にする
FILES=$(git diff --cached --name-only --diff-filter=ACM -- '*.php')
[ -z "$FILES" ] && exit 0

STATUS=0
for f in $FILES; do
  php -l "$f" > /dev/null || STATUS=1
done

if [ $STATUS -ne 0 ]; then
  echo "PHPの構文エラーがあるためコミットを中止しました。"
  exit 1
fi

保存したら実行権限を付けます。

chmod +x .git/hooks/pre-commit

ポイントは git diff --cached でステージ済みのファイルだけに絞っていることです。リポジトリ全体をチェックすると、コミットのたびに時間がかかり、使われなくなっていきます。このスクリプトはファイル名に空白が含まれないことを前提にしているので、空白入りのファイル名を扱う場合は書き方を調整してください。

WordPress コーディング規約(PHPCS)を追加する

構文チェックに加えて、PHP_CodeSniffer と WordPress Coding Standards(WPCS)で規約チェックを行うこともできます。Composer で開発用に入れておくと、チーム全員が同じバージョンを使えます。

composer require --dev wp-coding-standards/wpcs
# 導入された規約の一覧に WordPress 系が含まれるか確認
vendor/bin/phpcs -i

Composer のプラグイン許可を求められた場合は、内容を確認したうえで許可します。導入後は、先ほどのフックの末尾に次のような処理を足します。

# pre-commit の続き(ステージされたPHPファイルだけを規約チェック)
vendor/bin/phpcs --standard=WordPress $FILES
if [ $? -ne 0 ]; then
  echo "コーディング規約の違反があります。vendor/bin/phpcbf で自動修正できるものもあります。"
  exit 1
fi

既存のテーマに後から入れると大量の違反が出ることがあります。その場合は、プロジェクト直下に phpcs.xml.dist を置いて対象ディレクトリや除外ルールを決めてから運用を始めると、無理なく導入できます。

post-merge:プル後に WP-CLI を実行する

git pull でマージが起きた後に動く post-merge フックでは、ローカル開発環境を最新の状態に合わせる処理を自動化できます。たとえば composer.lock が変わっていたら依存関係を入れ直し、WordPress のキャッシュを消す、といった処理です。

#!/bin/sh
# .git/hooks/post-merge

# 直前のマージで composer.lock が変わったか
if git diff --name-only HEAD@{1} HEAD | grep -q '^composer.lock$'; then
  echo "composer.lock が更新されたため composer install を実行します"
  composer install --no-interaction
fi

# WordPress がインストール済みのときだけ WP-CLI を実行
if wp core is-installed > /dev/null 2>&1; then
  wp cache flush
fi

wp core is-installed は、WordPress がインストールされていない環境では0以外を返すので、フックが不要なエラーを出さないためのガードとして使えます。WordPress のディレクトリとリポジトリの位置が異なる場合は、wp --path=/path/to/wordpress cache flush のように --path を指定します。

post-merge では、データベースを書き換えるコマンド(wp search-replace やインポートなど)を自動で走らせるのは避けたほうが安全です。プルのたびに意図せずデータが変わると、原因の切り分けが難しくなります。

post-receive:サーバー側でデプロイ処理を行う

サーバー上にベアリポジトリを置き、そこへ git push したら公開ディレクトリに反映する、という構成では post-receive フックを使います。このフックはプッシュを受け取ったサーバー側で動きます。

#!/bin/sh
# /home/deploy/site.git/hooks/post-receive

TARGET=/var/www/example.com
REPO=/home/deploy/site.git
BRANCH=main

while read oldrev newrev ref; do
  if [ "$ref" = "refs/heads/$BRANCH" ]; then
    # 反映前にデータベースを書き出す
    mkdir -p /home/deploy/backups
    wp db export /home/deploy/backups/pre-deploy-$(date +%Y%m%d%H%M%S).sql --path="$TARGET"

    # 作業ツリーを最新に
    git --work-tree="$TARGET" --git-dir="$REPO" checkout -f "$BRANCH"

    # データベースの更新が必要な場合に適用し、キャッシュを消す
    wp core update-db --path="$TARGET"
    wp cache flush --path="$TARGET"
  fi
done

post-receive は標準入力から「古いコミット・新しいコミット・ブランチ名」を1行ずつ受け取るので、対象ブランチへのプッシュのときだけ処理するようにしています。

この方式は手軽ですが、注意点があります。

  • ファイルを上書きしている間はサイトが中途半端な状態になる。アクセスの多いサイトでは、リリースごとにディレクトリを分けてシンボリックリンクを切り替える方式のほうが向いている
  • checkout -f はサーバー上で直接編集された変更を上書きする。本番で直接ファイルを編集しない運用にそろえる
  • wp-config.php や wp-content/uploads はリポジトリに含めず、サーバー側だけで管理する
  • フックの実行ユーザーとWebサーバーの実行ユーザーが違うと、ファイルの所有者や権限がずれる

まずはステージング環境で同じ構成を作り、プッシュから反映、バックアップの取得までが期待どおりに動くことを確認してから本番に適用してください。

フックをチームで共有する

.git/hooks/ はコミットされないため、チームで同じフックを使うには工夫が必要です。Git 標準の方法は、リポジトリ内のディレクトリをフックの置き場所として指定する core.hooksPath です。この設定は Git 2.9 で追加されたもので、現在一般的に使われている Git であれば利用できます(2026年10月現在)。手元のバージョンは git --version で確認できます。

# リポジトリに .githooks/ を作ってフックを置き、コミットしておく
mkdir -p .githooks
cp .git/hooks/pre-commit .githooks/pre-commit
chmod +x .githooks/pre-commit

# 各メンバーが一度だけ実行する
git config core.hooksPath .githooks

この設定自体は各自のローカル設定なので、README に手順を書くか、Composer の scripts に登録して composer install 時に実行されるようにしておくと漏れを防げます。Node.js を併用しているプロジェクトでは、Husky のようなフック管理ツールを使う方法もあります。

なお、フックは git commit --no-verify で飛ばせます。フックはあくまで手元での早期発見のための仕組みなので、同じチェックを CI(GitHub Actions など)でも実行し、そちらを最終的な関門にするのが一般的です。

フックを運用するときのコツ

  • 実行時間を短く保つ。数秒を超えるとメンバーが --no-verify を使い始める。重いテストは CI に任せる
  • 失敗したときは、何が原因でどう直せばよいかをメッセージで示す
  • フックの中でファイルを書き換えて自動で git add する処理は、意図しない変更がコミットに混ざりやすいので慎重に扱う
  • Windows の Git Bash でも動くよう、#!/bin/sh で書き、改行コードは LF にする

まとめ

  • pre-commit では、ステージ済みの PHP ファイルに php -l と phpcs --standard=WordPress を実行し、失敗したらコミットを止める
  • post-merge では、composer.lock の変更検知や wp cache flush などローカル環境の追従を自動化する。DB を書き換える処理は入れない
  • post-receive でのデプロイは手軽だが、反映中の不整合や権限のずれに注意し、事前に wp db export を取る
  • フックはコミットされないので、core.hooksPath で共有し、同じチェックを CI でも実行する

お気軽にご相談ください

お見積りへ お問い合わせへ
▲