解説

JekyllとGitHub Pagesで、検証と本番公開を分ける

Jekyll製ブログで、ブランチやプルリクエストの検証とGitHub Pagesへの本番公開をどう分けていたかを、ブランチ構成からワークフロー、変更例まで解説します。

目次

このブログは以前、JekyllでMarkdownからサイトを生成し、GitHub Pagesで公開していました。最初は main に変更を入れてビルドし、その結果を公開すれば十分でした。

記事やレイアウトを作業ブランチで直すようになると、別の課題が出てきます。プルリクエストを出す前にサイトが壊れていないか確かめたい。でも、レビュー中の変更まで本番へ公開したくはありません。

必要だったのは、作業ブランチとプルリクエストでは検証だけを行い、レビューを経て main に入った変更だけを公開することです。

ソースと公開ファイルは別のブランチ

main にはMarkdown記事、設定、ワークフローなどのソースがあります。GitHub Pagesが配信するのは、Jekyllが生成したHTMLやCSS、画像などを置く gh-pages ブランチです。gh-pages は生成物の置き場であり、手作業で編集する場所ではありません。

作業ブランチ/プルリクエスト
          │ CIでビルド・言語ルートを検証
          ▼
       main(記事・設定・ワークフローのソース)
          │ 本番ビルドとルート検査
          ▼
 gh-pages(生成HTML・CSS・アセット) ──► GitHub Pages

CIとCDを分ける理由

CIが答えるのは「この変更を正しくビルドできるか」です。作業ブランチやプルリクエストでも実行できます。CDが答えるのは「検証済みの成果物で本番サイトを置き換えるか」です。公開の条件を main へのマージに絞れば、確認中の変更がそのまま訪問者に届くことはありません。

2つのワークフローと起動条件

当時はこの2つの流れに Validate blog と Automatic build という名前を付けていました。

作業branch / pull request(検証のみ)

  1. branchへのpush / PRを開く・更新任意のbranchで検証
  2. Validate blogJekyll build + 言語別route検査
  3. 検証結果gh-pagesには公開しない

mainへのmerge(公開条件)

  1. 自動ビルド本番 Jekyll ビルド + ルート確認
  2. 生成ファイルgh-pagesに公開
  3. GitHub Pages生成サイトを配信
検証と公開は別の経路です。緑のcheckが付いてもdeployは行われず、本番公開はmainへのmergeを境界とします。
  • Validate blog(.github/workflows/main.yml) — 任意のブランチへのpush、プルリクエスト、手動の workflow_dispatch で起動します。Jekyllをビルドして言語別ルートを検証し、デプロイはしません。
  • Automatic build(.github/workflows/pages-deploy.yml) — main へのpush(指定された変更だけのpushは除外)か、手動の workflow_dispatch で起動します。ジョブ条件により refs/heads/main 以外では公開しません。

Automatic build のpushトリガーでは、.gitignore、README.md、LICENSE、ARTICLE_PROGRESS.md の変更を無視します。そのため、これらだけを変更したpushでは検証は動いても本番デプロイは始まりません。手動実行を選んだ場合も、ブランチ条件は省略されず、main 以外ではジョブが動きません。

Validate blog:ブランチとPRを検証する

検証ワークフローはRuby 2.7をセットアップし、Bundlerのキャッシュを使って依存関係を用意します。その後、Jekyllでサイトをビルドし、生成された _site の言語別ルートを確認します。

bundle exec jekyll build
ruby tools/verify_language_routes.rb _site

このワークフローはpushの対象ブランチを限定しません。プルリクエストでも同じ検証を行い、GitHub Actionsから手動で起動することもできます。どの場合も目的は変更の確認であり、検証に成功しただけでは gh-pages も公開サイトも更新されません。

Automatic build:mainの変更を公開する

本番ワークフローもRuby 2.7とBundlerをセットアップし、bash tools/deploy.sh を実行します。このヘルパーは本番用のJekyllビルドと言語別ルート検査を行い、生成したサイトで gh-pages の内容を置き換えます。当時はその更新にforce pushを使っていました。gh-pages は毎回生成される出力なので、記事や設定の変更は main 側で行います。

つまり公開までの境界は明確です。作業ブランチやPRではビルド可否を確かめ、レビュー後に変更を main へ取り込むと、本番用の生成と公開が始まります。

韓国語記事の一文を直す例

韓国語の記事にある一文を修正する場合は、次の順に進めます。

  1. main から作業ブランチを作り、韓国語記事の該当箇所を編集してpushします。
  2. Validate blog の実行結果を確認します。Jekyllビルドと言語別ルート検査の両方が成功することを確かめます。
  3. main 向けのプルリクエストを開き、PR上の検証を通してレビューを受けます。
  4. PRを main にマージします。対象となる変更なら Automatic build が本番ビルドを行い、gh-pages を更新します。
  5. デプロイの成功を確認し、公開サイトで韓国語記事の該当ページを開いて修正文を確かめます。

これが「検証はこまめに、デプロイは意図をもって」の実際の流れです。検証を手動でやり直すなら Validate blog、ソース変更なしで本番サイトを再生成するなら Automatic build を main から手動実行します。

当時のJekyllサイトをローカルで確認する

当時のJekyll構成をローカルで確かめるには、依存関係をインストールして開発サーバーを起動していました。

bundle install
bundle exec jekyll serve

本番環境だけで起きる問題は、当時このコマンドでproductionビルドを再現していました。

JEKYLL_ENV=production bundle exec jekyll build

現在の構成について

2026年10月6日現在、このサイトの本番環境はJekyll/ChirpyからAstroの静的サイトへ移行しています。この記事は以前のJekyll構成を記録したものです。現在は main の変更をNode/Astroでビルドし、site-v2/dist を自動で gh-pages に公開してGitHub Pagesが配信します。実装は変わりましたが、変更を検証してから本番に公開する原則は今も同じです。