基本原理

创建一个 Hugo 博客需要一些源文件,然后使用 hugo 命令将这些源文件编译为静态 html 文件,实际发布的博客是这些静态 html 文件

期望实现的效果是,我们在本地只需要维护这些源文件,然后在 github 中保存一份源文件,同时每当我们推送更新时,在 github 端完成 hugo 的编译过程

这样的好处时,我们无需在本地完成 hugo 编译过程,只管博客内容编辑即可,并且在机器迁移时,只需要同步这些源文件即可,可以减少同步文件的数量

为了外界能够访问到,hugo 编译的文件一定是保存在一个 public 仓库中的,根据源文件存储的仓库类型可以分为两种实现方式:

  1. 源文件 和 hugo 编译后文件保存在同一个 public 仓库中
  2. 源文件保存在一个 private 仓库中,hugo 编译后的文件保存在一个 public 仓库中

仓库设置

假设 源文件 存储在 private repository A,由 A 使用 hugo 进行编译,并且将编译后的文件推送到 public repository B

在 A 中除了增加 action 之外,还需要在 setting 中设置一个 key,具体类型和方法在 action 实现中都有说明

对于 B 来说,由于 A 推送过来的内容已经是可以直接展示的静态文件了,所以 B 直接在 setting 中设置一个 pages,选择展示 gh-pages 分支即可,实际上似乎当我们设置分支名称是 gh-pages 时,它就会自动开启 github pages,只需要稍微等一小会就可以看到效果了

action 实现

在实际实现时,难点实际就是如何使用 github action 完成 hugo 的编译

方式 1 和 方式 2 的区别只是在于,在 hugo 编译完成后,将需要发布的文件 push 到哪里

其实下面使用的 actions/checkout@v3, peaceiris/actions-hugo@v2, peaceiris/actions-gh-pages@v3 可以看为一种封装好的工具,比如说最后一步的文件推送,我们自己写 git 命令也一样可以实现,不过这些工具对命令进行了封装,更加易用

方式1 workflow 实现

需要注意的是,由于方式 1 只涉及到访问当前仓库,所以不需要额外权限。其中的github_token无需我们手动配置,工具会自行生成。

name: GitHub Pages

on:
  push:
    branches:
      - main  # Set a branch name to trigger deployment
  pull_request:

jobs:
  deploy:
    runs-on: ubuntu-latest
    permissions:
      contents: write
    steps:
      - uses: actions/checkout@v3
        with:
          submodules: true  # Fetch Hugo themes (true OR recursive)
          fetch-depth: 0    # Fetch all history for .GitInfo and .Lastmod

      - name: Setup Hugo
        uses: peaceiris/actions-hugo@v2
        with:
          hugo-version: 'latest'
          extended: true

      - name: Build
        run: hugo --minify

      - name: Deploy
        uses: peaceiris/actions-gh-pages@v3
        with:
          github_token: ${{ secrets.GITHUB_TOKEN }}
          publish_dir: ./public

方式 2 workflow 实现

peaceiris/actions-gh-pages@v3 文档 - 如何将内容推送到外部仓库

与方式 1 不同的是,此时涉及到访问外部仓库,因此需要额外权限,所需要使用的 key 就发生了变化,按理说,此时使用 deploy_keypersonal_token 均可,但是实测只能使用 personal_token

name: GitHub Pages

on:
  push:
    branches:
      - main  # Set a branch name to trigger deployment
  pull_request:

jobs:
  deploy:
    runs-on: ubuntu-latest
    permissions:
      contents: write
    steps:
      - name: Get blog source files from github to machine
        uses: actions/checkout@v3
        with:
          submodules: true  # Fetch Hugo themes (true OR recursive)
          fetch-depth: 0    # Fetch all history for .GitInfo and .Lastmod

      - name: Setup Hugo
        uses: peaceiris/actions-hugo@v2
        with:
          hugo-version: 'latest'
          extended: true

      - name: Build
        run: hugo --minify

      - name: Deploy
        uses: peaceiris/actions-gh-pages@v3
        with:
          personal_token: ${{ secrets.PERSONAL_TOKEN }}
          external_repository: gaohongy/blog-test
          publish_branch: gh-pages  # default: gh-pages
          publish_dir: ./public

这里要理解publish_branch 和 publish_dir,前者是要把文件推送到 gaohony/blog-test仓库的gh-pages分支下,后者的意思是把 hugo 编译结果中的 public 文件夹推送到gh-pages分支下

这样我们只需要向当前private仓库推送文件,actions 就可以首先完成 hugo 编译,然后把生成的文件推送到一个public仓库下

本地内容在不同仓库间迁移

假设之前的本地代码对应远程仓库A,现在期望切换到远程仓库B

只需要 git remote set-url origin <B address> 然后正常提交即可,这样操作 git log 还能够保留(因为这些内容都是存储在 .github 文件夹下的文件当中的)