最近在使用 Hexo 部署博客时遇到了一个问题:本地执行 npx hexo d 看起来是成功的,但 GitHub Pages 的 pages build and deployment 工作流却失败了。

一开始我以为是 Hexo 生成出错,后来排查发现,真正的问题并不在文章内容,也不在本地生成,而是在 GitHub Pages 构建流程和 .nojekyll 文件没有真正部署到公开仓库之间。

这篇文章记录一下完整排查过程。

1. 问题现象(若想直接看如何解决可以跳转到7.最终解决)

本地执行:

npx hexo d

命令看起来可以正常执行,静态文件也会被推送到 GitHub Pages 仓库。

error_information

但是在 GitHub 仓库的 Actions 页面中,可以看到 pages build and deployment 失败,具体失败位置在 build 步骤,错误信息中出现了:

Failed to download archive 'https://codeload.github.com/actions/jekyll-build-pages/...'

An action could not be found at the URI

从这个报错可以看出,GitHub Pages 正在尝试执行和 Jekyll 相关的构建流程。

但我的博客是 Hexo 博客,静态文件已经在本地生成好了,GitHub Pages 理论上只需要托管生成后的 HTML、CSS、JS 文件,不应该再把它当成 Jekyll 项目重新构建。

2. 为什么 Hexo 需要 .nojekyll

GitHub Pages 默认对站点有一套 Jekyll 构建逻辑。

如果我们部署的是 Jekyll 博客,这当然没有问题;但如果部署的是 Hexo、VuePress、VitePress 或其他已经生成好的静态站点,就不希望 GitHub Pages 再用 Jekyll 处理一次。

这时可以在发布分支根目录放一个文件(我是放在了source目录下):

path

.nojekyll

它的作用是告诉 GitHub Pages:

当前仓库内容已经是静态站点,不需要再走 Jekyll 构建。

对于 Hexo 来说,最终发布分支一般是 mastergh-pages,所以 .nojekyll 必须出现在发布分支的根目录。

3. 第一次修复:在 source 中加入 .nojekyll

Hexo 的源码目录是:

source/

所以我先在源码目录下新增(.nojekyll中没有添加任何数据):

source/.nojekyll

然后执行:

npx hexo clean
npx hexo g

但是检查后发现:

Test-Path D:\MyBlog\public\.nojekyll

结果是:

False

也就是说,仅仅把 .nojekyll 放到 source 目录下还不够。因为 Hexo 默认不会自动复制点开头的隐藏文件。

4. 第二次修复:让 Hexo 生成 .nojekyll

解决办法是在 _config.yml 中加入:

include:
  - .nojekyll

这里的含义是:让 Hexo 在处理 source 目录时,把 .nojekyll 也包含进生成结果中。

修改后再次执行:

npx hexo clean
npx hexo g

这次可以看到生成日志中出现:

Generated: .nojekyll

再检查:

Test-Path D:\MyBlog\public\.nojekyll

结果变成:

True

到这里,看起来问题似乎解决了。

但实际上还没有。

5. 真正的坑:.nojekyll 生成了,但没有部署上去

执行:

npx hexo d

之后,GitHub Pages 还是失败。

这时继续检查 Hexo 的部署缓存目录:

Test-Path D:\MyBlog\.deploy_git\.nojekyll

结果是:

False

这一步非常关键。

Hexo 部署到 GitHub 时,并不是直接把 public 目录推送上去,而是先把 public 中的文件复制到:

.deploy_git/

然后再把 .deploy_git 作为 Git 仓库提交并推送到远程发布分支。

也就是说,真正会被推到 GitHub Pages 的不是 public,而是 .deploy_git

虽然 .nojekyll 已经出现在 public 中,但它没有进入 .deploy_git,自然也就不会出现在 GitHub 仓库的 master 分支根目录。

6. 为什么 .deploy_git 中没有 .nojekyll

继续排查 hexo-deployer-git 插件后发现,它在复制文件时有一个配置:

ignore_hidden

它会影响部署阶段是否忽略隐藏文件。

.nojekyll 是点开头文件,属于隐藏文件。如果部署插件忽略隐藏文件,那么即使它已经生成到了 public,也不会被复制到 .deploy_git

这就是这次问题最迷惑的地方:

  • source/.nojekyll 存在。
  • public/.nojekyll 存在。
  • 但是 .deploy_git/.nojekyll 不存在。
  • GitHub Pages 发布分支上也没有 .nojekyll

所以 GitHub Pages 仍然会尝试走 Jekyll 相关流程。

7. 最终修复方式

最终需要同时做两件事。

第一,在 source 目录下创建:

source/.nojekyll

第二,在根目录下的 _config.yml 中加入完整配置:

include:
  - .nojekyll

并在 deploy 配置中加入:

deploy:
  type: 'git'
  repo: 'https://github.com/lsWorl/lsWorl.github.io.git'	#这里改成自己的仓库
  branch: master
  ignore_hidden: false	#主要是添加这个

完整关键配置如下:

include:
  - .nojekyll

deploy:
  type: 'git'
  repo: 'https://github.com/lsWorl/lsWorl.github.io.git'
  branch: master
  ignore_hidden: false

其中:

  • include: .nojekyll 解决的是 Hexo 生成阶段的问题,让 .nojekyll 出现在 public
  • ignore_hidden: false 解决的是 Hexo 部署阶段的问题,让 .nojekyllpublic 被复制到 .deploy_git 并推送到 GitHub。

这两个配置缺一不可。

8. 重新生成和部署

修改完成后执行:

npx hexo clean
npx hexo g
npx hexo d

部署成功后,终端中可以看到类似信息:

create mode 100644 .nojekyll

这说明 .nojekyll 已经被 Git 记录到了部署提交里。

还可以继续检查:

Test-Path D:\MyBlog\.deploy_git\.nojekyll

如果结果为:

True

说明 .nojekyll 已经进入部署缓存。

也可以从 Git 提交对象中确认:

git -C D:\MyBlog\.deploy_git ls-tree --name-only HEAD .nojekyll

如果输出为:

.nojekyll

说明当前部署提交中确实包含了这个文件。

9. GitHub Pages 侧的检查

部署完成后,可以打开 GitHub 仓库的发布分支,检查根目录是否出现:

.nojekyll

本次部署成功后,GitHub Pages 的最新工作流状态变成了:

Status: Success

并且 buildreport-build-statusdeploy 都执行成功。

最后访问博客地址:

https://lsworl.github.io/

可以看到最新文章已经正常显示。

10. 这次问题的总结

这次问题表面上看是 GitHub Pages 构建失败,实际上是 .nojekyll 没有真正进入发布分支。

排查时不要只看 public 目录,还要看 .deploy_git 目录。

完整链路应该是:

source/.nojekyll
        ↓
Hexo generate
        ↓
public/.nojekyll
        ↓
Hexo deploy
        ↓
.deploy_git/.nojekyll
        ↓
GitHub Pages master 分支根目录

如果中间任何一步断了,GitHub Pages 都可能继续尝试 Jekyll 构建。

最终修复的核心就是两行配置:

include:
  - .nojekyll

以及:

ignore_hidden: false

前者保证生成,后者保证部署。两个都加上,才是真正闭环。