hexo deploy 把站点推成空白?因为用管道看了部署日志
现象:部署"成功",站点消失
一次例行的内容更新,跑完 hexo g 和 hexo deploy,日志最后几行是熟悉的:
1 | INFO Deploy done: git |
刷新线上地址——404。换几个文章页,全是 404。首页偶尔返回 200 但是空白。
登录 GitHub 看部署仓库,最新 commit 是:
1 | Site updated: 2026-10-23 15:06:59 |
时间戳是最新的,看起来推成功了。但点进去看文件树——空的。没有 index.html,没有 posts/,只有一个 .git。
根因:工作区被清空,然后推了个空提交
hexo-deployer-git 的机制是:把 .deploy_git 当作一个独立的 git 工作区,每次部署时把 public/ 的内容同步进去,然后 commit + push。
关键点在于同步的方式:它不是增量覆盖,而是先清理工作区(相当于 git rm -r 全部内容 + 复制新文件),再提交。这个设计本身没问题——它保证删除的文章不会残留。
问题出在中断。
如果进程在「清空工作区」之后、「复制新文件」完成之前被杀,.deploy_git 就处于一个中间状态:文件全没了,但没有产生新的 commit。此时仓库里躺着的还是上一次的内容,看起来正常。
然后下一次(或者被中断的那次恢复后)执行 git add -A && git commit——如果此时工作区确实是空的,就会生成一个「删除所有文件」的提交,推上去。
线上就空了。
什么会杀掉它:管道
最容易被忽略的诱因是这一条命令:
1 | npx hexo deploy | grep -E "Deploy done" |
或者任何 | head、| tail 的变体。
管道的工作方式:grep 匹配到第一个结果后如果退出(grep -m1、或者 head -n5 读够行数就关闭 stdin),管道读端关闭,hexo 进程后续再往 stdout 写就会收到 SIGPIPE(信号 13),默认行为是终止进程。
hexo deploy 是个长流程:生成 → 复制到 .deploy_git → git add → git commit → git push → (如果配置了)其他部署插件。你只关心最后一行 Deploy done,于是 grep 前面的进度输出一出现就立即匹配退出,hexo 在复制文件的中途被杀。
你以为只是少看了几行日志,实际上是给了进程一刀。
这个问题在长时间部署里更容易触发——文件多、网络慢、push 耗时长,中途被杀的概率更高。
修复:日志重定向到文件
不要用管道看部署日志。重定向到文件,跑完再读:
1 | npx hexo deploy > .workbuddy/tmp/deploy.log 2>&1 |
同样地,任何可能长时间运行的构建命令都适用这条规则:先落盘,再看盘。
部署后的三项核验
日志会说谎。Deploy done: git 这行是在 git push 成功后打印的,但如果 push 的内容本身就是空的,它照样打印。
真正的判断要看仓库状态。三项都过才算部署成功:
1 | cd .deploy_git |
任何一项不对,就重跑 hexo deploy。
这三项检查值得写进部署脚本,作为硬性门槛而不是靠人肉记忆。
一个会掩盖真实错误的干扰项
部署日志末尾常见这个:
1 | 'firebase' is not recognized as an internal or external command |
如果 _config.yml 里配置了 hexo-deployer-firebase 但本机没装 firebase CLI,每次部署都会在最后报这个错,进程退出码是 2。
这会造成两种误判:
- 看到
FATAL和 exit code 2,以为整体失败——实际上 git 部分可能已经成功 - 反过来,因为「这个错误每次都出现、是已知问题」而忽略整个日志——那么真正的中断错误也被一起忽略了
处理方式是:明确知道哪些错误是可忽略的,然后只核验那三项客观指标。不要用「日志里有没有 ERROR」来判断成败,要用「仓库状态对不对」来判断。
如果不再用 firebase 部署,把 _config.yml 里对应的 deployer 删掉,让日志干净,比留着习惯性忽略更好。
恢复步骤
站点已经空了,怎么救:
- 确认
public/目录还在且完整——构建产物没丢,只是没推上去 - **重跑
npx hexo deploy**(不用hexo g,产物是好的) - 重跑三项核验
hexo-deployer-git 会把 public/ 重新复制进 .deploy_git 并提交,空的提交会被新的覆盖。线上约 1 分钟内恢复(GitHub Pages 的生效时间)。
如果 public/ 也丢了(比如 hexo clean 之后没重新生成),就 hexo g && hexo deploy 走完整流程。
收口
这件事的本质不是 hexo 的 bug,而是用管道消费长任务的输出这个习惯性操作。
三条规则:
- 构建/部署类命令,输出重定向到文件,不用管道
- 成败看仓库状态,不看日志关键词(新 commit + 工作区干净 + 关键文件存在)
- 已知的噪声错误要清掉,不要训练自己忽略日志
第 3 条容易被当成洁癖。但「习惯性忽略某类报错」和「错过真正的事故信号」之间,只隔一次判断。
同期的部署链路整理见 记录一次把文章、音乐、抖音日更压进 watchdog,域名迁移期间的部署问题见 Hexo 换域名后 canonical 和 sitemap 还指着旧域。