この記事は サイトに関係ないコミットでのビルドを止める:Vercel ignoreCommandで前回デプロイとの差分を見る からの転載です。
この記事で分かること
-
ignoreCommandの差分の起点をHEAD^ではなくVERCEL_GIT_PREVIOUS_SHAにする理由 - 判定に迷ったときビルドする側に倒す理由
- この方法を採用すべき場面と、避けるべき場面
背景: こういう課題があった
ドキュメントやAIエージェントの設定だけを直したコミットでも、Vercelでは毎回ビルドが走ります。依存のインストールから next build まで一周しても、出力は1ピクセルも変わりません。そこで vercel.json の ignoreCommand で、ビルドに関係ないパスだけの変更ならビルドを止めたい、という話です。
前提は、VercelのGit連携でデプロイしていることです。
選択肢の検討
ignoreCommand のコマンドは、Root Directoryで実行され、Vercelは終了コードだけを見ます。exit 0 ならビルド中止(Canceled)、exit 1以上ならビルドです。シェルの常識と逆なので注意が必要です。
| アプローチ | メリット | デメリット |
|---|---|---|
| ダッシュボードの「Only build if there are changes in a folder」 | 設定が簡単 | 設定がリポジトリに残らず、レビューできない。アプリが1フォルダに収まる前提 |
HEAD^ を起点に除外を足す(公式の例の延長) |
1行で済む | 1回のpushが複数commitだと、途中の変更を見落とす |
VERCEL_GIT_PREVIOUS_SHA を起点にする(採用) |
止めた分の差分が次の判定に積み上がる | 初回デプロイと浅いcloneの扱いを自分で決める |
なぜこのアプローチを選んだか
HEAD^ 起点の何が問題かというと、アプリを変えたcommitの上にドキュメントだけのcommitを重ねてpushしたとき、最後の1 commitだけを見て止めてしまう点です。アプリの変更が反映されないのに、デプロイは「正常にCanceled」に見えます。
VERCEL_GIT_PREVIOUS_SHA は、そのプロジェクトとブランチで最後に成功したデプロイのshaです。Canceledは成功したデプロイではないので、起点は「最後に実際にビルドしたcommit」に留まります。
判断基準は、失敗したときの損の非対称性です。
- 余分にビルドする: 失うのはビルド1回分
- 誤って止める: アプリの変更が黙って本番に反映されない
そこで、止まる出口は1つだけにし、前回のshaが空、git diff の失敗(浅いcloneで前回のshaが無い場合など)、除外パス外の差分、のどれもビルドに流します。
実装例
{
"$schema": "https://openapi.vercel.sh/vercel.json",
"ignoreCommand": "[ -n \"$VERCEL_GIT_PREVIOUS_SHA\" ] && git diff --quiet \"$VERCEL_GIT_PREVIOUS_SHA\" HEAD -- . ':(exclude).claude' ':(exclude).github' ':(exclude)docs' ':(exclude)__tests__' ':(exclude)*.md'"
}
- 先頭の
[ -n ... ]で、初回デプロイ(前回のshaが空)を明示的にビルドへ倒す - 除外は長い書き方
:(exclude)で揃える。短い':!__tests__'は、_がマジック記号と読まれてfatal: Unimplemented pathspec magic '_'(exit 128)になり、エラーなのにビルドされるだけで気づきにくい - 除外するのは「ビルドが読まないパス」だけ。
vercel.json、package.json、lockfileは外さない -
*.mdはサブディレクトリの.mdもまたぐので、先にgit ls-files '*.md'で確認する
pushの前に、同じ文字列を手元で動かして終了コードを確認できます。
cmd=$(node -p 'require("./vercel.json").ignoreCommand')
VERCEL_GIT_PREVIOUS_SHA=$(git rev-parse HEAD~1) sh -c "$cmd"; echo "exit=$?"
VERCEL_GIT_PREVIOUS_SHA= sh -c "$cmd"; echo "exit=$?"
まとめ: どういう場面で使うべきか
AIエージェントの設定やドキュメントなど、出力に入らないコミットが多いプロジェクトで有効です。止める条件を狭く、それ以外は全部ビルドに流す形にしておけば、判定が壊れても失うのはビルド1回分で済みます。
一方、CMSの更新をデプロイフックの再ビルドで反映しているプロジェクトには向きません。commitが変わらず差分が無いので、再ビルドが止まってしまいます。また、省けるのはビルド時間で、止めたデプロイも1日のデプロイ数の上限には数えられます。
さらに深掘りしたい方へ
この記事では ignoreCommand の判定方針とその理由を解説しました。
サイトに関係ないコミットでのビルドを止める:Vercel ignoreCommandで前回デプロイとの差分を見る ではさらに:
- 除外してよいパスの判断表と、デプロイ後に効いているか確かめる手順
- 環境変数を変えた再デプロイやmonorepoのRoot Directoryなど、止まらない・止まりすぎる状況の対処表
- 検証用リポジトリで sh・bash・zsh・dash を試した終了コードの一覧