概念 study · 研习 #server, devops, automation 2026-08-02

站点自动部署:Git Hook 流水线

本文记录将 Wiki 的部署流程从"本地构建 + 手动上传"升级为"git push 自动上线"的完整过程,以及过程中踩过的坑。

前置:服务器已就绪 → 从零购买并配置云服务器;站点迁移背景 → 博客与 Wiki 私有化迁移

背景:手动部署的痛点

静态站点的发布流程原本是:

本地构建(node scripts/build.mjs --public)
  → scp dist 到服务器
  → SSH 替换 /var/www/wiki

每次写新文章都要重复这四个步骤,且容易忘记或出错。目标是:本地写完文章,git push 一条命令,服务器自动构建并上线

方案:bare 仓库 + post-receive 钩子

Git 的 post-receive 钩子在服务器收到 push 后自动执行,是纯静态站最轻量的自动部署方案:

本地 wiki 仓库 ──git push──▶ 服务器 bare 仓库 (wiki-deploy.git)
                                    │  post-receive 钩子
                                    ▼
                checkout → npm ci → 构建 → 复制 dist → /var/www/wiki

实现细节

服务器侧

  1. 安装 node/npm(apt install nodejs npm,v18.19.1)
  2. 创建 bare 仓库:git init --bare ~/wiki-deploy.git
  3. 编写 post-receive 钩子(~/wiki-deploy.git/hooks/post-receive):
#!/bin/bash
set -e
WORK="$HOME/wiki-deploy-work"
TARGET="/var/www/wiki"
cd "$WORK" 2>/dev/null || { git clone "$HOME/wiki-deploy.git" "$WORK"; cd "$WORK"; }
unset GIT_DIR
git pull --ff-only origin master 2>/dev/null || true
npm ci --silent 2>/dev/null || npm install --silent
WIKI_PUBLIC=1 node scripts/build.mjs
sudo rm -rf "$TARGET"
sudo mkdir -p "$TARGET"
sudo cp -r dist/* "$TARGET/"
echo "WIKI AUTO-DEPLOY OK"

本地侧

git remote add origin ops@139.199.70.119:wiki-deploy.git
git push origin master

踩过的坑

1. 内嵌 git 仓库不会被外层仓库跟踪

study-wiki/ 自身是一个 git 仓库(Obsidian 初始化过)——外层仓库只会把它当作 submodule 引用(mode 160000),内容不会进入仓库,push 到服务器后无法构建。

解决:移走 study-wiki/.git(备份为 .git-study-wiki.bak,并加入 .gitignore),让内容并入外层仓库。

2. 硬编码目录清单导致 ENOENT

--public 模式下服务器只 clone 到 study-wiki(work-wiki 在 .gitignore 里不推送)——但构建脚本有三处硬编码 ['study-wiki', 'work-wiki'] 的遍历(图片收集、文件索引),在服务器上读取不存在的 work-wiki 目录直接崩溃(ENOENT)。

解决:全部接入 --public/WIKI_PUBLIC 判断。

3. 命令行参数在 git hook 环境下不可靠

最初用 node scripts/build.mjs --public 传参,但在 post-receive 钩子环境下 process.argv 的解析行为异常(手动 SSH 测试正常、钩子里失效)。

解决:改用环境变量 WIKI_PUBLIC=1 作为主开关,--public 保留为本地便捷用法(双保险):

const IS_PUBLIC = process.argv.includes('--public') || process.env.WIKI_PUBLIC === '1'

使用方式

以后写知识库文章:

# 1. 在 study-wiki/ 下写 markdown(可用 [[双链]] 关联其他文章)
# 2. 提交并推送
git add -A
git commit -m "新文章:xxx"
git push origin master   # 1-2 秒后线上自动更新

安全边界work-wiki/ 在 .gitignore 中——永远不会被 push 到公开仓库,私有内容只留在本地。

扩展:博客同样接入

VitePress 博客用完全相同的模式接入自动部署:

# 服务器:blog-deploy.git + post-receive 钩子
npm ci --silent 2>/dev/null || npm install --silent
npm run build --silent          # vitepress build
sudo cp -r .vitepress/dist/* /var/www/blog/
# 本地推送
cd blog && git push origin master

首次 push 时服务器自动安装 vitepress 依赖(约 30s-1min),之后增量构建(约 10s)。

总结

现在博客与知识库都已实现"写文章 → git push → 自动上线":

模块 仓库 构建 目标
博客 blog-deploy.git npm run build(VitePress) /var/www/blog
知识库 wiki-deploy.git WIKI_PUBLIC=1 node scripts/build.mjs /var/www/wiki

相关:从零购买并配置云服务器 · 博客与 Wiki 私有化迁移