Hugo to GitHub Pages: A Brand New History Every Time
This guide outlines a robust and secure deployment process for a Hugo project to a GitHub Pages repository, ensuring that the commit history is effectively “reset” with each new deployment. This method is particularly useful for keeping sensitive information out of the public repository and maintaining a clean, obfuscated history.
Scenario Overview
The setup involves two distinct GitHub repositories and an automated workflow:
- Private Hugo Source Repository: This private repository (
github.com/username/hugo-source-repo
for example) holds all the Hugo project’s raw source code, including Markdown content, themes, and configuration. Keeping this private ensures sensitive data and work-in-progress remain confidential. - Public GitHub Pages Repository: This public repository serves the live website (e.g.,
github.com/username/username.github.io
for a user/organization page, orgithub.com/username/project-page
for a project page). Importantly, this repository will only contain the static HTML, CSS, JavaScript, and asset files generated by Hugo. - GitHub Actions for Automation: A dedicated GitHub Actions workflow, residing within the private source code repository, automates the deployment. This workflow will:
- Trigger automatically on pushes to a specified branch (like
main
). - Build the Hugo site, generating the
public
directory. - Take only the contents of this
public
directory. - Deploy these contents to the public GitHub Pages repository.
- Trigger automatically on pushes to a specified branch (like
- Clearing Commit History:This is achieved using the
peaceiris/actions-gh-pages
action with theforce_orphan: true
flag. This critical setting ensures that each new deployment creates a completely fresh, single commit that effectively replaces the entire history of the GitHub Pages branch. This prevents the accumulation of old commits and makes it difficult to trace past changes, enhancing privacy by design.
This approach efficiently avoids manual history editing and reduces the risk of accidentally exposing sensitive information, as the public repository only ever receives the final, compiled static assets with a completely new history upon each deployment.
Workflow:
[Local Hugo Source] --> (Push to main) --> [Private GitHub Repo]
|
v
[GitHub Actions Workflow]
|
(Build site using Hugo) |
(Use PAT & force_orphan) v
-----------------------------------------------------
| Only /public folder is deployed as new commit |
| Entire Git history in public repo is replaced |
-----------------------------------------------------
|
v
[Public GitHub Pages Repo]
|
v
[GitHub Pages Live Website]
Step-by-Step Deployment Guide
Part 1: Set Up GitHub Repositories
- Push local Hugo blog project to a private GitHub repository, e.g
my-hugo-blog
. - Create the Public GitHub Pages Repository:
- Create a new public repository on GitHub.
- Crucial Naming:
- For a User or Organization Page, the repository name must be exactly
username.github.io
(e.g.,johndoe.github.io
). GitHub will serve it from themain
branch. - For a Project Page, it can be named anything (e.g.,
my-hugo-project-page
). GitHub Pages will typically serve it from thegh-pages
branch.
- For a User or Organization Page, the repository name must be exactly
- Create this repository empty, without a README or
.gitignore
.
Part 2: Configure the Private Hugo Source Repository
Exclude
public/
in.gitignore
: In the root of the private Hugo source repository, ensure the.gitignore
file includespublic/
. This prevents generated static site files from being committed to the source code.# .gitignore /public/ /resources/_gen/ .hugo_build.lock .DS_Store
Generate a Personal Access Token (PAT): The GitHub Actions workflow needs permission to push to the public GitHub Pages repository.
- Go to GitHub’s Settings > Developer settings > Personal access tokens > Tokens (classic)**.
- Click Generate new token (classic).
- Give it a clear name (e.g.,
Hugo_Deploy_PAT
). - Grant it only the
repo
scope. This is essential for cross-repository pushes. - Copy the generated token immediately! It will not be shown again.
Add the PAT as a Repository Secret:
- In the private Hugo source repository (e.g.,
my-hugo-website-source
), navigate to Settings > Secrets and variables > Actions. - Click New repository secret.
- Name it
DEPLOY_TOKEN
. - Paste the copied PAT value into the
Secret
field. - Click Add secret.
- In the private Hugo source repository (e.g.,
Create the GitHub Actions Workflow File: Inside the private Hugo source repository, create this file at
.github/workflows/deploy.yml
.
name: hugo-deploy-CI
# Controls when the action will run.
on:
push:
branches:
- main # Change this to your source branch
workflow_dispatch:
jobs:
# docs:https://github.com/peaceiris/actions-gh-pages
deploy:
runs-on: ubuntu-latest
steps:
- name: Git checkout
uses: actions/checkout@v4
- name: Setup hugo
uses: peaceiris/actions-hugo@v2
with:
hugo-version: '0.81.0'
extended: true
- name: Build
run: hugo
- name: Deploy to GitHub Pages
uses: peaceiris/actions-gh-pages@v4
with: github_token: ${{ secrets.DEPLOY_TOKEN }} # Use the PAT from your repository secrets
publish_dir: ./public # The directory containing your built Hugo site
external_repository: username/username.github.io # IMPORTANT: Your PUBLIC GitHub Pages repo # For a project page, use: username/project-page
publish_branch: main # Use 'main' for User/Org Pages, 'gh-pages' for Project Pages
force_orphan: true
Key points for this workflow:
on: push: branches: - main
: Adjustmain
to the branch where Hugo source code changes are pushed.github_token: ${{ secrets.DEPLOY_TOKEN }}
: This securely uses the Personal Access Token.external_repository: username/username.github.io
: Crucially, this must be the exact name of the public GitHub Pages repository.publish_branch: main
: Ensure this matches the branch configured for GitHub Pages (usuallymain
for user/org pages,gh-pages
for project pages).force_orphan: true
: This is the setting that replaces the entire branch history with a single new commit on each deployment.
Part 3: Configure the Public GitHub Pages Repository
- Set Up GitHub Pages Source:
- Go to your public GitHub Pages repository on GitHub.
- Navigate to Settings > Pages.
- Under “Build and deployment”, select
Deploy from a branch
for “Source”. - For “Branch”, select the appropriate branch and folder:
main
and/ (root)
for User/Organization Pages.gh-pages
and/ (root)
for Project Pages.
- Click Save.
With these steps, every time changes are pushed to the designated deployment branch in the private source repository, GitHub Actions will automatically rebuild the Hugo site and deploy a fresh, clean version with a brand new history to the public GitHub Pages repository.