diff --git a/docs/UPDATE.md b/docs/UPDATE.md new file mode 100644 index 00000000000..d1499c6ad81 --- /dev/null +++ b/docs/UPDATE.md @@ -0,0 +1,273 @@ +# NotionNext 版本更新指南 + +本指南帮助您安全地将博客更新到上游最新版本,同时保留所有个性化配置。 + +按照以下流程操作,您可以: +- ✅ 获取 NotionNext 的最新功能和修复 +- ✅ 保留您的个人配置(头像、标题、域名等) +- ✅ 安全处理可能的代码冲突 + +> ⚠️ 本指南适用于 Vercel 部署场景,其他平台未测试。 + +## 分支管理策略 + +本策略参考 [NotionNext 官方升级教程](https://docs.tangly1024.com/article/how-to-update-notionnext) 中的建议,使用双分支管理模式。 + +### 分支说明 + +| 分支 | 用途 | 更新策略 | 部署状态 | +|------|------|----------|----------| +| `main` | 同步上游原始代码 | 快进合并 | 不部署 | +| `deploy` | 生产环境代码 | 合并 main + 保留个性化 | Vercel 自动部署 | +| `feature/*` | 功能开发 | 基于 deploy 创建 | 不部署 | + +### 架构示意 + +``` +GitHub Fork Repository +├── main (同步 tangly1024/NotionNext) +├── deploy (生产分支 → Vercel) +└── feature/* (开发分支) +``` + +## 前置准备 + +### 1. 配置 Vercel 生产分支(重要) + +在 Vercel 中将生产分支设置为 `deploy`: + +1. 登录 [Vercel Dashboard](https://vercel.com) +2. 进入你的 NotionNext 项目 +3. 点击 **Settings** → **Git** +4. 找到 **Production Branch** 设置 +5. 将默认的 `main` 改为 `deploy` +6. 保存设置 + +> 💡 这样配置后,只有 `deploy` 分支的更新会触发生产环境部署,`main` 分支仅用于同步上游。 + +### 2. 配置上游仓库(仅首次) + +```bash +# 添加上游仓库 +git remote add upstream https://github.com/tangly1024/NotionNext.git + +# 验证配置 +git remote -v +``` + +预期输出: +``` +origin https://github.com/[你的用户名]/NotionNext.git (fetch) +origin https://github.com/[你的用户名]/NotionNext.git (push) +upstream https://github.com/tangly1024/NotionNext.git (fetch) +upstream https://github.com/tangly1024/NotionNext.git (push) +``` + +> ⚠️ 如果没有看到 upstream 行,说明上游仓库未成功添加 + +### 3. 识别个性化文件 + +更新前先了解你的个性化修改: + +```bash +# 查看个性化修改文件列表 +git diff --name-only main..deploy +``` + +常见个性化文件: +- `blog.config.js` - 博客配置 +- `public/avatar.png` - 头像 +- `public/favicon.ico` - 网站图标 +- `pages/_app.js` - 全局脚本 +- `.env.local` - 环境变量 + +## 标准更新流程 + +### 步骤 1:同步 main 分支 + +```bash +# 1.1 切换到 main 分支 +git checkout main + +# 1.2 拉取本地最新(防止多设备不同步) +git pull origin main + +# 1.3 获取上游更新 +git fetch upstream + +# 1.4 合并上游代码 +git merge upstream/main + +# 1.5 推送到自己的仓库 +git push origin main +``` + +### 步骤 2:更新 deploy 分支 + +```bash +# 2.1 切换到 deploy 分支 +git checkout deploy + +# 2.2 【重要】同步远程 deploy 分支 +git pull origin deploy + +# 2.3 合并 main 分支的更新 +git merge main +``` + +### 步骤 3:处理冲突 + +如果出现冲突,根据文件类型处理: + +| 文件类型 | 处理策略 | Git 命令 | +|----------|----------|----------| +| `yarn.lock` | 接受上游版本 | `git checkout --theirs yarn.lock` | +| `blog.config.js` | 手动合并 | 保留个人配置,添加新配置项 | +| `public/avatar.png` | 保留本地版本 | `git checkout --ours public/avatar.png` | +| `public/favicon.*` | 保留本地版本 | `git checkout --ours public/favicon.*` | + +处理完成后: + +```bash +# 添加已解决的文件 +git add . + +# 提交合并 +git commit -m "merge: 同步上游更新 + +- 保留个性化配置 +- 解决冲突文件: [文件列表]" +``` + +### 步骤 4:更新依赖并测试 + +```bash +# 4.1 清理并重新安装依赖 +rm -rf node_modules +yarn install + +# 4.2 本地测试 +yarn dev +# 访问 http://localhost:3000 确认正常 + +# 4.3 构建测试 +yarn build + +# 4.4 推送到远程 +git push origin deploy +``` + +## 自动化脚本 + +项目提供了自动化更新脚本 `scripts/update.sh`,功能包括: + +- 前置条件检查 +- 自动备份配置文件 +- 分支同步与合并 +- 安全冲突处理 +- 依赖更新 + +### 使用方法 + +```bash +# 赋予执行权限(首次) +chmod +x scripts/update.sh + +# 执行更新 +./scripts/update.sh +``` + +脚本会引导你完成整个更新流程,遇到需要手动处理的情况会给出明确提示。 + +## 回滚操作 + +### 方法一:Git 回滚 + +```bash +# 查看提交历史 +git log --oneline -10 + +# 回滚到指定版本 +git reset --hard [commit-hash] + +# 强制推送(谨慎使用) +git push origin deploy --force-with-lease +``` + +### 方法二:从 Vercel 恢复 + +如果误操作覆盖了代码,可以从 Vercel 的部署历史中恢复: + +1. 登录 Vercel Dashboard +2. 进入项目 → Deployments +3. 找到正常的历史部署,点击右侧三个点 +4. 选择 "View Source" 查看当时的源代码 +5. 点击右上角可跳转到 GitHub 对应版本 + +## 故障排查 + +### Vercel 部署失败 + +**问题**:推送后 Vercel 构建失败 + +**解决方案**: + +1. 检查 Vercel 构建日志定位具体错误 +2. 如果是依赖问题: + ```bash + rm -rf node_modules yarn.lock + yarn install + git add yarn.lock + git commit -m "fix: 重新生成 yarn.lock" + git push + ``` +3. 如果是环境变量问题:检查 Vercel Dashboard → Settings → Environment Variables + +### 大量文件冲突 + +**问题**:合并时出现大量冲突,难以处理 + +**解决方案**: + +```bash +# 中止当前合并 +git merge --abort + +# 查看上游最近的提交 +git log upstream/main --oneline -20 + +# 分步合并(先合并较早的提交) +git merge [earlier-commit] +# 解决冲突后继续合并下一个 +``` + +### 本地与远程不同步 + +**问题**:推送时提示 rejected + +**解决方案**: + +```bash +# 先拉取远程更新 +git pull origin deploy --rebase + +# 解决可能的冲突后推送 +git push origin deploy +``` + +## 注意事项 + +1. **更新频率**:建议每 1-2 周检查一次更新,重要安全更新应立即处理 +2. **备份重要文件**:更新前备份 `blog.config.js` 和其他个性化配置 +3. **测试验证**:更新后务必在本地测试,确认功能正常再部署 +4. **记录修改**:建议维护一份个性化修改清单,便于后续更新 + +## 相关资源 + +- [NotionNext 官方仓库](https://github.com/tangly1024/NotionNext) +- [NotionNext 文档](https://docs.tangly1024.com/) +- [Vercel 文档](https://vercel.com/docs) + +--- + +*文档版本:0.1.0 | 最后更新:2025-08-19* \ No newline at end of file diff --git a/scripts/update.sh b/scripts/update.sh new file mode 100755 index 00000000000..cda9d05e9e8 --- /dev/null +++ b/scripts/update.sh @@ -0,0 +1,345 @@ +#!/bin/bash + +# NotionNext 更新脚本 +# 功能: 从上游仓库同步更新到本地 deploy 分支 +# 适用: Vercel 部署场景 + +set -e # 遇到错误立即退出 + +# 颜色定义 +RED='\033[0;31m' +GREEN='\033[0;32m' +YELLOW='\033[1;33m' +BLUE='\033[0;34m' +NC='\033[0m' # No Color + +# 打印函数 +print_info() { + echo -e "${BLUE}[INFO]${NC} $1" +} + +print_success() { + echo -e "${GREEN}[SUCCESS]${NC} $1" +} + +print_warning() { + echo -e "${YELLOW}[WARNING]${NC} $1" +} + +print_error() { + echo -e "${RED}[ERROR]${NC} $1" +} + +# 检查前置条件 +check_prerequisites() { + print_info "检查前置条件..." + + # 检查是否在git仓库中 + if ! git rev-parse --git-dir > /dev/null 2>&1; then + print_error "当前目录不是git仓库" + exit 1 + fi + + # 检查是否有未提交的更改 + if ! git diff-index --quiet HEAD --; then + print_warning "检测到未提交的更改" + echo "请选择操作:" + echo "1) 暂存更改并继续" + echo "2) 退出脚本" + read -p "请输入选项 (1/2): " choice + + if [ "$choice" = "1" ]; then + git stash push -m "auto-update-stash-$(date +%Y%m%d-%H%M%S)" + print_success "更改已暂存" + STASHED=true + else + print_info "更新已取消" + exit 0 + fi + fi + + # 检查upstream远程仓库是否存在 + if ! git remote | grep -q "^upstream$"; then + print_warning "未找到upstream远程仓库,正在添加..." + git remote add upstream https://github.com/tangly1024/NotionNext.git + print_success "upstream远程仓库已添加" + fi + + print_success "前置条件检查通过" +} + +# 备份重要配置文件 +backup_configs() { + print_info "备份重要配置文件..." + + BACKUP_DIR="backup/$(date +%Y%m%d-%H%M%S)" + mkdir -p "$BACKUP_DIR" + + # 备份文件列表 + FILES_TO_BACKUP=( + "blog.config.js" + "public/avatar.png" + "public/favicon.ico" + "public/favicon.svg" + "public/ads.txt" + "pages/_app.js" + ".env.local" + ) + + for file in "${FILES_TO_BACKUP[@]}"; do + if [ -f "$file" ]; then + cp "$file" "$BACKUP_DIR/" 2>/dev/null || true + print_info "已备份: $file" + fi + done + + print_success "配置文件备份完成: $BACKUP_DIR" +} + +# 更新main分支 +update_main_branch() { + print_info "更新 main 分支..." + + # 记录当前分支 + CURRENT_BRANCH=$(git branch --show-current) + + # 切换到main分支 + git checkout main + + # 同步远程 main 分支 + print_info "同步远程 main 分支..." + git pull origin main || { + print_warning "远程同步失败,可能是首次推送" + } + + # 获取上游最新代码 + print_info "获取上游最新代码..." + git fetch upstream + + # 合并上游更新 + print_info "合并上游更新..." + git merge upstream/main --no-edit + + # 推送到origin + print_info "推送到远程仓库..." + git push origin main + + print_success "main 分支更新完成" +} + +# 合并到deploy分支 +merge_to_deploy() { + print_info "切换到 deploy 分支..." + git checkout deploy + + print_info "同步远程 deploy 分支..." + git pull origin deploy || { + print_warning "远程同步失败,可能是首次推送或有冲突" + print_info "尝试继续执行..." + } + + # 获取版本号信息(优先使用 tag,否则使用 commit) + OLD_VERSION=$(git describe --tags --always HEAD 2>/dev/null) + NEW_VERSION=$(git describe --tags --always main 2>/dev/null) + + print_info "开始合并 main 分支的更新..." + + # 构建提交信息 + if [ "$OLD_VERSION" != "$NEW_VERSION" ]; then + MERGE_MSG="merge: 同步上游更新 ($OLD_VERSION → $NEW_VERSION) + +- 合并最新功能和修复 +- 保留个性化配置" + else + MERGE_MSG="merge: 同步上游更新 + +- 合并最新功能和修复 +- 保留个性化配置" + fi + + # 尝试自动合并 + if git merge main -m "$MERGE_MSG" 2>/dev/null; then + print_success "合并成功,无冲突" + return 0 + else + print_warning "检测到合并冲突,需要手动解决" + return 1 + fi +} + +# 处理冲突 +handle_conflicts() { + print_info "分析冲突文件..." + + # 获取冲突文件列表 + CONFLICTS=$(git diff --name-only --diff-filter=U) + + if [ -z "$CONFLICTS" ]; then + print_success "没有冲突文件" + return 0 + fi + + echo "冲突文件列表:" + echo "$CONFLICTS" + echo "" + + # 安全地处理部分文件 + for file in $CONFLICTS; do + case "$file" in + "yarn.lock"|"package-lock.json") + print_info "接受上游版本: $file" + git checkout --theirs "$file" + git add "$file" + ;; + "public/avatar.png"|"public/favicon.ico"|"public/favicon.svg"|"public/ads.txt") + print_info "保留个人版本: $file" + git checkout --ours "$file" + git add "$file" + ;; + "blog.config.js") + print_warning "需要手动合并: $file" + print_info "请保留您的个人配置,同时合并新增的配置项" + ;; + *) + print_warning "需要手动检查: $file" + ;; + esac + done + + # 检查是否还有未解决的冲突 + REMAINING_CONFLICTS=$(git diff --name-only --diff-filter=U) + + if [ -n "$REMAINING_CONFLICTS" ]; then + print_warning "以下文件需要手动解决冲突:" + echo "$REMAINING_CONFLICTS" + echo "" + echo "请手动解决冲突后执行:" + echo " git add ." + echo " git commit" + echo " git push origin deploy" + return 1 + else + print_success "安全冲突已解决" + + # 获取版本号信息(优先使用 tag,否则使用 commit) + OLD_VERSION=$(git describe --tags --always HEAD~1 2>/dev/null) + NEW_VERSION=$(git describe --tags --always HEAD 2>/dev/null) + + if [ "$OLD_VERSION" != "$NEW_VERSION" ]; then + COMMIT_MSG="merge: 同步上游更新 ($OLD_VERSION → $NEW_VERSION) + +- 同步最新功能和修复 +- 保留个性化配置 +- 解决了依赖文件和静态资源的冲突" + else + COMMIT_MSG="merge: 同步上游更新 + +- 同步最新功能和修复 +- 保留个性化配置 +- 解决了依赖文件和静态资源的冲突" + fi + + git commit -m "$COMMIT_MSG" + return 0 + fi +} + +# 更新依赖 +update_dependencies() { + print_info "更新项目依赖..." + + # 清理旧的依赖 + if [ -d "node_modules" ]; then + print_info "清理旧的 node_modules..." + rm -rf node_modules + fi + + # 重新安装依赖 + print_info "使用 yarn 安装依赖..." + yarn install + + print_success "依赖更新完成" +} + +# 运行测试 +run_tests() { + print_info "运行测试..." + + # 检查是否有测试脚本 + if yarn run | grep -q "test"; then + yarn test || { + print_warning "测试失败,但继续执行" + } + else + print_info "未找到测试脚本,跳过测试" + fi + + # 尝试本地构建 + print_info "尝试本地构建..." + if yarn run | grep -q "build"; then + yarn build || { + print_error "构建失败!请检查错误信息" + return 1 + } + print_success "本地构建成功" + fi + + return 0 +} + +# 完成更新 +finish_update() { + print_info "推送更新到远程仓库..." + git push origin deploy + + # 恢复暂存的更改 + if [ "$STASHED" = true ]; then + print_info "恢复暂存的更改..." + git stash pop || { + print_warning "无法自动恢复暂存,请手动执行: git stash pop" + } + fi +} + +# 主函数 +main() { + echo "=======================================" + echo " NotionNext 更新脚本" + echo "=======================================" + echo "" + + # 执行更新流程 + check_prerequisites + backup_configs + update_main_branch + + if merge_to_deploy; then + update_dependencies + + if run_tests; then + finish_update + + print_success "🎉 更新完成!" + echo "" + echo "下一步操作:" + echo "1. 访问 http://localhost:3000 测试本地环境" + echo "2. 检查 Vercel 部署状态" + echo "3. 如有问题,可查看备份: backup/" + else + print_error "测试或构建失败,请检查问题后重试" + exit 1 + fi + else + if handle_conflicts; then + update_dependencies + finish_update + print_success "🎉 更新完成(自动解决了冲突)" + else + print_warning "请手动解决剩余的冲突" + exit 1 + fi + fi +} + +# 执行主函数 +main \ No newline at end of file