### ⭐️ Set custom commit message
Set a custom commit message.
When we create a commit with a message `docs: Update some post`, a deployment commit will be generated with a message `docs: Update some post ${GITHUB_SHA}`.
```yaml
- name: Deploy
uses: peaceiris/actions-gh-pages@v4
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: ./public
commit_message: ${{ github.event.head_commit.message }}
```
To set a full custom commit message without a triggered commit hash,
use the `full_commit_message` option instead of the `commit_message` option.
```yaml
- name: Deploy
uses: peaceiris/actions-gh-pages@v4
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: ./public
full_commit_message: ${{ github.event.head_commit.message }}
```
### ⭐️ Create Git tag
Here is an example workflow.
```yaml
name: GitHub Pages
on:
push:
branches:
- main
tags:
- 'v*.*.*'
jobs:
deploy:
runs-on: ubuntu-22.04
permissions:
contents: write
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
steps:
- uses: actions/checkout@v3
- name: Some build
- name: Prepare tag
id: prepare_tag
if: startsWith(github.ref, 'refs/tags/')
run: |
echo "DEPLOY_TAG_NAME=deploy-${TAG_NAME}" >> "${GITHUB_OUTPUT}"
- name: Deploy
uses: peaceiris/actions-gh-pages@v4
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: ./public
tag_name: ${{ steps.prepare_tag.outputs.DEPLOY_TAG_NAME }}
tag_message: 'Deployment ${{ github.ref_name }}'
```
Commands on a local machine.
```console
$ # On a main branch
$ git tag -a "v1.2.3" -m "Release v1.2.3"
$ git push origin "v1.2.3"
$ # After deployment
$ git fetch origin
$ git tag
deploy-v1.2.3 # Tag on the gh-pages branch
v1.2.3 # Tag on the main branch
```
## Tips and FAQ
### ⭐️ Create SSH Deploy Key
Generate your deploy key with the following command.
```sh
ssh-keygen -t rsa -b 4096 -C "$(git config user.email)" -f gh-pages -N ""
```
You will get 2 files:
- `gh-pages.pub` is a public key
- `gh-pages` is a private key
Next, Go to **Repository Settings**
- Go to **Deploy Keys** and add your public key with the **Allow write access**
- Go to **Secrets** and add your private key as `ACTIONS_DEPLOY_KEY`
| Add your public key | Success |
|---|---|
|  |  |
| Add your private key | Success |
|---|---|
|  |  |
### ⭐️ First Deployment with `GITHUB_TOKEN`
The `GITHUB_TOKEN` has limitations for the first deployment so we have to select the GitHub Pages branch on the repository settings tab. After that, do the second deployment like the following pictures.
| First deployment failed | Go to the settings tab |
|---|---|
|  |  |
| Select branch | Deploying again and succeed |
|---|---|
|  |  |
If the action fails to push the commit or tag with the following error:
```txt
/usr/bin/git push origin gh-pages
remote: Write access to repository not granted.
fatal: unable to access 'https://github.com/username/repository.git/': The requested URL returned error: 403
Error: Action failed with "The process '/usr/bin/git' failed with exit code 128"
```
Please add the write permission to the [`permissions.contents` in a workflow/job](https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#permissions).
```yaml
permissions:
contents: write
```
Alternatively, you can [configure the default `GITHUB_TOKEN` permissions](https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/enabling-features-for-your-repository/managing-github-actions-settings-for-a-repository#configuring-the-default-github_token-permissions) by selecting read and write permissions.
### ⭐️ Use the latest and specific release
We recommend you to use the latest and specific release of this action for stable CI/CD.
It is useful to watch this repository (release only) to check the [latest release] of this action.
[latest release]: https://github.com/peaceiris/actions-gh-pages/releases
For continuous updating, we can use the GitHub native Dependabot.
Here is an example configuration of the bot. The config file is located in `.github/dependabot.yml`.
```yaml
version: 2
updates:
- package-ecosystem: "github-actions"
directory: "/"
schedule:
interval: "daily"
labels:
- "CI/CD"
commit-message:
prefix: ci
```
See the official documentation for more details about the Dependabot: [Keeping your dependencies updated automatically - GitHub Docs](https://docs.github.com/en/code-security/supply-chain-security/keeping-your-dependencies-updated-automatically)
### ⭐️ Schedule and Manual Deployment
For deploying regularly, we can set the `on.schedule` workflow trigger.
See [Scheduled events | Events that trigger workflows - GitHub Docs](https://docs.github.com/en/actions/learn-github-actions/events-that-trigger-workflows#scheduled-events)
For deploying manually, we can set the `on.workflow_dispatch` workflow trigger.
See [Manual events `workflow_dispatch` | Events that trigger workflows - GitHub Docs](https://docs.github.com/en/actions/learn-github-actions/events-that-trigger-workflows#manual-events)
```yaml
name: GitHub Pages
on:
push:
branches:
- main
schedule:
- cron: "22 22 * * *"
workflow_dispatch:
jobs:
deploy:
runs-on: ubuntu-22.04
permissions:
contents: write
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
steps:
...
```
### ⭐️ Release Strategy
cf. [support: execution from hashref disabled/broken vs GitHub Actions Security Best Practice? · Issue #712 · peaceiris/actions-gh-pages](https://github.com/peaceiris/actions-gh-pages/issues/712)
Our project builds and provides build assets only when creating a release. This is to prevent the user from executing this action with a specific branch (like main). For example, if we maintain build assets in the main branch and users use this action as follows, a major release including breaking changes will break the CI workflow of the users silently.
```yaml
- uses: peaceiris/actions-gh-pages@main # Bad example!
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: ./public
```
In this project, a major tag (e.g. v3) is guaranteed to contain no breaking changes. But, we recommend using a tag or a commit hash for the stability of your workflows.
```yaml
- uses: peaceiris/actions-gh-pages@v4.0.0 # tag: Better
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: ./public
```
```yaml
- uses: peaceiris/actions-gh-pages@373f7f263a76c20808c831209c920827a82a2847 # commit hash of v3.9.3: Best!
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: ./public
```
For verifying the release asset, we can use the following commands.
```sh
git clone https://github.com/peaceiris/actions-gh-pages.git
cd ./actions-gh-pages
git checkout v3.9.3
nvm install
nvm use
npm i -g npm
npm ci
npm run build
git diff ./lib/index.js # We will get zero exit code
```
## Examples
### ⭐️ Static Site Generators with Node.js
[hexo], [vuepress], [react-static], [gridsome], [create-react-app] and so on.
Please check where your output directory is before pushing your workflow.
e.g. `create-react-app` requires `publish_dir` to be set to `./build`
[hexo]: https://github.com/hexojs/hexo
[vuepress]: https://github.com/vuejs/vuepress
[react-static]: https://github.com/react-static/react-static
[gridsome]: https://github.com/gridsome/gridsome
[create-react-app]: https://github.com/facebook/create-react-app
Premise: Dependencies are managed by `package.json` and `package-lock.json`
```yaml
name: GitHub Pages
on:
push:
branches:
- main
pull_request:
jobs:
deploy:
runs-on: ubuntu-22.04
permissions:
contents: write
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
steps:
- uses: actions/checkout@v3
- name: Setup Node
uses: actions/setup-node@v3
with:
node-version: '14'
- name: Cache dependencies
uses: actions/cache@v3
with:
path: ~/.npm
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-node-
- run: npm ci
- run: npm run build
- name: Deploy
uses: peaceiris/actions-gh-pages@v4
if: github.ref == 'refs/heads/main'
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: ./public
```
### ⭐️ Gatsby
An example for [Gatsby] (Gatsby.js) project with [gatsby-starter-blog]
[Gatsby]: https://github.com/gatsbyjs/gatsby
[gatsby-starter-blog]: https://github.com/gatsbyjs/gatsby-starter-blog
```yaml
name: GitHub Pages
on:
push:
branches:
- main
pull_request:
jobs:
deploy:
runs-on: ubuntu-22.04
permissions:
contents: write
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
steps:
- uses: actions/checkout@v3
- name: Setup Node
uses: actions/setup-node@v3
with:
node-version: '14'
- name: Cache dependencies
uses: actions/cache@v3
with:
path: ~/.npm
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-node-
- run: npm ci
- run: npm run format
- run: npm run test
- run: npm run build
- name: Deploy
uses: peaceiris/actions-gh-pages@v4
if: github.ref == 'refs/heads/main'
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: ./public
```
### ⭐️ React and Next
An example for [Next.js] (React.js) project with [create-next-app]
[Next.js]: https://github.com/vercel/next.js
[create-next-app]: https://nextjs.org/docs
```yaml
name: GitHub Pages
on:
push:
branches:
- main
pull_request:
jobs:
deploy:
runs-on: ubuntu-22.04
permissions:
contents: write
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
steps:
- uses: actions/checkout@v3
- name: Setup Node
uses: actions/setup-node@v3
with:
node-version: '14'
- name: Get yarn cache
id: yarn-cache
run: echo "YARN_CACHE_DIR=$(yarn cache dir)" >> "${GITHUB_OUTPUT}"
- name: Cache dependencies
uses: actions/cache@v3
with:
path: ${{ steps.yarn-cache.outputs.YARN_CACHE_DIR }}
key: ${{ runner.os }}-yarn-${{ hashFiles('**/yarn.lock') }}
restore-keys: |
${{ runner.os }}-yarn-
- run: yarn install --frozen-lockfile
- run: yarn build
- run: yarn export
- name: Deploy
uses: peaceiris/actions-gh-pages@v4
if: github.ref == 'refs/heads/main'
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: ./out
```
### ⭐️ Vue and Nuxt
An example for [Nuxt.js] (Vue.js) project with [create-nuxt-app]
- cf. [Nuxt - GitHub Pages](https://nuxtjs.org/deployments/github-pages)
[Nuxt.js]: https://github.com/nuxt/nuxt.js
[create-nuxt-app]: https://github.com/nuxt/create-nuxt-app
```yaml
name: GitHub Pages
on:
push:
branches:
- main
pull_request:
jobs:
deploy:
runs-on: ubuntu-22.04
permissions:
contents: write
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
steps:
- uses: actions/checkout@v3
- name: Setup Node
uses: actions/setup-node@v3
with:
node-version: '14'
- name: Cache dependencies
uses: actions/cache@v3
with:
path: ~/.npm
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-node-
- run: npm ci
- run: npm test
- run: npm run generate
- name: deploy
uses: peaceiris/actions-gh-pages@v4
if: github.ref == 'refs/heads/main'
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: ./dist
```
### ⭐️ Docusaurus
An example workflow for [Docusaurus](https://docusaurus.io/).
`npx @docusaurus/init@next init website classic` is useful to create a new Docusaurus project.
```yaml
# .github/workflows/deploy.yml
name: GitHub Pages
on:
push:
branches:
- main
paths:
- '.github/workflows/deploy.yml'
- 'website/**'
pull_request:
jobs:
deploy:
runs-on: ubuntu-22.04
permissions:
contents: write
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
defaults:
run:
working-directory: website
steps:
- uses: actions/checkout@v3
- name: Setup Node
uses: actions/setup-node@v3
with:
node-version: '14'
- name: Get yarn cache
id: yarn-cache
run: echo "YARN_CACHE_DIR=$(yarn cache dir)" >> "${GITHUB_OUTPUT}"
- name: Cache dependencies
uses: actions/cache@v3
with:
path: ${{ steps.yarn-cache.outputs.YARN_CACHE_DIR }}
key: ${{ runner.os }}-website-${{ hashFiles('**/yarn.lock') }}
restore-keys: |
${{ runner.os }}-website-
- run: yarn install --frozen-lockfile
- run: yarn build
- name: Deploy
uses: peaceiris/actions-gh-pages@v4
if: github.ref == 'refs/heads/main'
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: ./website/build
```
### ⭐️ Static Site Generators with Python
[pelican], [MkDocs], [sphinx], and so on.
[pelican]: https://github.com/getpelican/pelican
[MkDocs]: https://github.com/mkdocs/mkdocs
[sphinx]: https://github.com/sphinx-doc/sphinx
Premise: Dependencies are managed by `requirements.txt`
```yaml
name: GitHub Pages
on:
push:
branches:
- main
pull_request:
jobs:
deploy:
runs-on: ubuntu-22.04
permissions:
contents: write
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
steps:
- uses: actions/checkout@v3
- name: Setup Python
uses: actions/setup-python@v3
with:
python-version: '3.8'
- name: Upgrade pip
run: |
# install pip=>20.1 to use "pip cache dir"
python3 -m pip install --upgrade pip
- name: Get pip cache dir
id: pip-cache
run: echo "dir=$(pip cache dir)" >> $GITHUB_OUTPUT
- name: Cache dependencies
uses: actions/cache@v3
with:
path: ${{ steps.pip-cache.outputs.dir }}
key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }}
restore-keys: |
${{ runner.os }}-pip-
- name: Install dependencies
run: python3 -m pip install -r ./requirements.txt
- run: mkdocs build
- name: Deploy
uses: peaceiris/actions-gh-pages@v4
if: github.ref == 'refs/heads/main'
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: ./site
```
### ⭐️ mdBook (Rust)
An example GitHub Actions workflow to deploy [rust-lang/mdBook] site to GitHub Pages.
[rust-lang/mdBook]: https://github.com/rust-lang/mdBook
- [peaceiris/actions-mdbook: GitHub Actions for mdBook (rust-lang/mdBook)](https://github.com/peaceiris/actions-mdbook)
```yaml
name: GitHub Pages
on:
push:
branches:
- main
pull_request:
jobs:
deploy:
runs-on: ubuntu-22.04
permissions:
contents: write
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
steps:
- uses: actions/checkout@v3
- name: Setup mdBook
uses: peaceiris/actions-mdbook@v1
with:
mdbook-version: '0.4.8'
# mdbook-version: 'latest'
- run: mdbook build
- name: Deploy
uses: peaceiris/actions-gh-pages@v4
if: github.ref == 'refs/heads/main'
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: ./book
```
Hint: you may want to publish your rustdocs. And use relative links to it from the md docs, and have them checked by `mdbook`.
Then, according to the [doc](https://rust-lang.github.io/mdBook/guide/creating.html#source-files), you may put `./target/doc/`
to your `./book/src` dir before you `mdbook build` and then it will end up in `./book/html/` and in your Github Pages.
### ⭐️ Flutter Web
An example workflow for [Flutter web project].
[Flutter web project]: https://flutter.dev/docs/get-started/web
```yaml
name: GitHub Pages
on:
push:
branches:
- main
pull_request:
jobs:
deploy:
runs-on: ubuntu-22.04
permissions:
contents: write
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
steps:
- uses: actions/checkout@v3
- name: Setup Flutter
run: |
git clone https://github.com/flutter/flutter.git --depth 1 -b beta _flutter
echo "${GITHUB_WORKSPACE}/_flutter/bin" >> ${GITHUB_PATH}
- name: Install
run: |
flutter config --enable-web
flutter pub get
- name: Build
run: flutter build web
- name: Deploy
uses: peaceiris/actions-gh-pages@v4
if: github.ref == 'refs/heads/main'
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: ./build/web
```
### ⭐️ Elm
An example workflow for [Elm].
[Elm]: https://elm-lang.org
```yaml
name: GitHub Pages
on:
push:
branches:
- main
pull_request:
jobs:
deploy:
runs-on: ubuntu-22.04
permissions:
contents: write
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
steps:
- uses: actions/checkout@v3
- name: Setup Node
uses: actions/setup-node@v3
with:
node-version: '14'
- name: Setup Elm
run: npm install elm --global
- name: Make
run: elm make --optimize src/Main.elm
- name: Move files
run: |
mkdir ./public
mv ./index.html ./public/
# If you have non-minimal setup with some assets and separate html/js files,
# provide --output=