这个脚本是干什么的?

tools/update.sh 是一个服务器端同步脚本,目标是:把服务器上的工作目录强制更新到远端 origin/gh-pages 的最新状态

使用场景

如果你除了 GitHub Pages,还有自己的服务器(比如用宝塔面板搭建的 VPS),想让服务器也提供博客访问,流程是:

  1. 本地写文章 → npm run publish → 推送到 GitHub gh-pages 分支
  2. 服务器定时或手动执行 update.sh → 拉取最新静态文件
  3. Nginx 指向该目录 → 用户访问你的服务器域名就能看到博客

如果你只用 GitHub Pages

这个脚本对你没用。GitHub Pages 会自动从 gh-pages 分支读取内容,你 deploy 之后就上线了,不需要再同步。


用法

服务器上的仓库目录执行:

bash tools/update.sh

或者配置 cron 定时任务:

# 每小时同步一次
0 * * * * cd /www/wwwroot/yuanweize.github.io && bash tools/update.sh >> /var/log/hexo-sync.log 2>&1

完整源码

#!/usr/bin/env bash

set -euo pipefail

REPO_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
cd "$REPO_DIR"

REMOTE="origin"
BRANCH="gh-pages"

git fetch "$REMOTE" "$BRANCH"
git checkout -q "$BRANCH" 2>/dev/null || git checkout -q -b "$BRANCH" "$REMOTE/$BRANCH"
git reset --hard "$REMOTE/$BRANCH"

# Optional: if running under BaoTa panel, fix ownership for web server user.
# Keep this best-effort to avoid breaking automation when chown needs sudo.
if [ -f "/etc/init.d/bt" ] && id -u www >/dev/null 2>&1; then
chown -R www "$REPO_DIR" >/dev/null 2>&1 || true
fi

逐行代码解析

第 1 行:Shebang

#!/usr/bin/env bash
  • 使用 env bash 而不是硬编码 /bin/bash,兼容性更好(不同系统 bash 路径可能不同)

第 3 行:严格模式

set -euo pipefail

三个选项的含义:

  • -e:任何命令返回非零退出码时立即终止脚本
  • -u:引用未定义变量时报错(防止拼写错误导致空变量)
  • -o pipefail:管道中任一命令失败则整个管道失败

这是 Bash 脚本的最佳实践,能尽早发现问题。

第 5-6 行:定位仓库根目录

REPO_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")/.." && pwd)"
cd "$REPO_DIR"
  • ${BASH_SOURCE[0]}:当前脚本的路径(比 $0 更可靠,支持 source 调用)
  • dirname:取目录部分(即 tools/
  • /..:上一级就是仓库根目录
  • cd ... && pwd:进入目录并输出绝对路径

好处:无论你从哪个目录执行脚本,它都能正确定位到仓库根目录。

第 8-9 行:定义远端和分支

REMOTE="origin"
BRANCH="gh-pages"

变量化便于修改和阅读。

第 11 行:只拉取目标分支

git fetch "$REMOTE" "$BRANCH"
  • 只拉取 gh-pages 分支,不拉其他分支(节省带宽和时间)
  • fetch 只更新远端引用,不修改工作区

第 12 行:切换到目标分支

git checkout -q "$BRANCH" 2>/dev/null || git checkout -q -b "$BRANCH" "$REMOTE/$BRANCH"

这是一个"先尝试后回退"的模式:

  • 先尝试 checkout gh-pages(本地已有该分支)
  • 如果失败(本地没有),则创建并跟踪远端分支

-q 是静默模式,2>/dev/null 抑制错误输出。

第 13 行:强制对齐

git reset --hard "$REMOTE/$BRANCH"

核心操作:把当前工作区强制重置到远端分支的最新状态。

  • 本地未提交的修改会被覆盖
  • 本地比远端多的提交会被丢弃

这正是我们要的效果:服务器只是"镜像",不应该有本地修改。

第 15-19 行:宝塔权限修复(可选)

if [ -f "/etc/init.d/bt" ] && id -u www >/dev/null 2>&1; then
chown -R www "$REPO_DIR" >/dev/null 2>&1 || true
fi

逻辑分解:

  • [ -f "/etc/init.d/bt" ]:检测是否是宝塔面板环境
  • id -u www:检测是否存在 www 用户(宝塔默认 Web 服务用户)
  • 如果都满足,尝试把目录所有权改为 www
  • || true:即使 chown 失败也不中断脚本(best-effort)

为什么需要:Nginx 以 www 用户运行,需要读取权限。如果你用 root 执行同步,文件权限可能不对。


注意事项

  1. 这是破坏性操作:本地修改会被覆盖,请确保服务器上的仓库只用于"镜像"
  2. 不清理未跟踪文件:如果远端删了某个文件,本地可能残留。如需清理:
    git clean -fd  # 删除未跟踪的文件和目录
  3. 首次使用前:确保服务器上已经 git clone 过仓库

与 hexo deploy 的关系

hexo deploy 做的事情:

  1. public/ 目录推送到 gh-pages 分支

update.sh 做的事情:

  1. 把 gh-pages 分支的内容拉到服务器

它们是互补的,不是替代关系。如果你只用 GitHub Pages,不需要 update.sh