tools(sync-upstream): 上游同步脚本
Some checks failed
continuous-integration/drone/push Build is passing
CI / test (push) Has been cancelled
CI / frontend (push) Has been cancelled
CI / golangci-lint (push) Has been cancelled
Security Scan / backend-security (push) Has been cancelled
Security Scan / frontend-security (push) Has been cancelled

只刷新 gitea/ora_main 镜像(默认)或 --try-merge 在临时分支启动合并。
永远不直接动 main,最后一步合并由人工 ff-only。包含冲突预检 + 完整
next-steps 引导。
This commit is contained in:
mini
2026-05-03 00:51:55 +08:00
parent c3fd4a5c0f
commit 808b9dd8ad

191
tools/sync-upstream.sh Executable file
View File

@@ -0,0 +1,191 @@
#!/usr/bin/env bash
# tools/sync-upstream.sh
#
# 同步上游 (Wei-Shaw/sub2api) 最新代码到我们 Gitea fork 的工作流脚本。
#
# 设计目标:
# 1. 在 Gitea 上维护一个纯净的上游镜像分支(默认 ora_main永远 = upstream/main HEAD
# 2. 永远不直接合并到 main —— 创建临时分支让人工 review/preview 后手动合并
# 3. 合并前打印冲突预检,让人提前知道改动范围
#
# 使用方式:
# ./tools/sync-upstream.sh # 仅刷新 gitea/ora_main 镜像
# ./tools/sync-upstream.sh --try-merge # 刷新 + 创建临时分支并启动合并(停在 --no-commit
#
# --try-merge 模式的完整步骤:
# 1. fetch upstream + force-with-lease 推到 gitea/ora_main
# 2. 预检:列出预计会冲突的文件
# 3. 从最新的 main 切出临时分支 merge/upstream-YYYY-MM-DD-HHMM
# 4. 在临时分支启动 git merge --no-commit --no-ff upstream/main停在合并状态
# 5. 打印 next-steps 引导后续 typecheck/build/preview/commit/main 合并
#
# 自定义环境变量(可覆盖默认):
# UPSTREAM_REMOTE 远程名(默认 upstream应指向 GitHub Wei-Shaw/sub2api
# GITEA_REMOTE 远程名(默认 gitea自建
# MIRROR_BRANCH 镜像分支名(默认 ora_main
#
# 安全注意:
# - 强制推送只发生在镜像分支上force-with-lease比 force 安全),不会动 main
# - 主分支 main 完全由人工接手最后一步 git merge --ff-only + git push
set -euo pipefail
UPSTREAM_REMOTE="${UPSTREAM_REMOTE:-upstream}"
GITEA_REMOTE="${GITEA_REMOTE:-gitea}"
MIRROR_BRANCH="${MIRROR_BRANCH:-ora_main}"
TEMP_BRANCH_PREFIX="merge/upstream-"
# ------------------------------------------------------------------
# 前置检查
# ------------------------------------------------------------------
if ! git rev-parse --git-dir >/dev/null 2>&1; then
echo "Error: 当前目录不是 git 仓库" >&2
exit 1
fi
if ! git remote get-url "$UPSTREAM_REMOTE" >/dev/null 2>&1; then
echo "Error: remote '$UPSTREAM_REMOTE' 未配置" >&2
echo " 添加方式: git remote add $UPSTREAM_REMOTE https://github.com/Wei-Shaw/sub2api.git" >&2
exit 1
fi
if ! git remote get-url "$GITEA_REMOTE" >/dev/null 2>&1; then
echo "Error: remote '$GITEA_REMOTE' 未配置" >&2
exit 1
fi
# ------------------------------------------------------------------
# 1. 拉最新 upstream
# ------------------------------------------------------------------
echo "[1/3] Fetching $UPSTREAM_REMOTE/main..."
git fetch "$UPSTREAM_REMOTE" main --tags
# ------------------------------------------------------------------
# 2. 刷新 Gitea 镜像分支
# ------------------------------------------------------------------
UPSTREAM_HEAD=$(git rev-parse --short "$UPSTREAM_REMOTE/main")
echo "[2/3] Refreshing $GITEA_REMOTE/$MIRROR_BRANCH to $UPSTREAM_REMOTE/main ($UPSTREAM_HEAD)..."
# force-with-lease远端如果在我们 fetch 之后被别人改过会拒绝推送(比 --force 安全)
git push --force-with-lease "$GITEA_REMOTE" \
"refs/remotes/$UPSTREAM_REMOTE/main:refs/heads/$MIRROR_BRANCH"
# ------------------------------------------------------------------
# 3. 状态报告
# ------------------------------------------------------------------
BASE=$(git merge-base main "$UPSTREAM_REMOTE/main")
NEW_COMMITS=$(git rev-list --count "$BASE..$UPSTREAM_REMOTE/main")
echo "[3/3] Status:"
echo " upstream/main HEAD : $UPSTREAM_HEAD"
echo " $GITEA_REMOTE/$MIRROR_BRANCH : refreshed"
echo " 距上次合并到 main 的新 commit : $NEW_COMMITS"
# 没有 --try-merge 就到此为止
if [[ "${1:-}" != "--try-merge" ]]; then
echo ""
echo "完成。要尝试合并到临时分支:./tools/sync-upstream.sh --try-merge"
exit 0
fi
# ------------------------------------------------------------------
# --try-merge 模式
# ------------------------------------------------------------------
if [[ "$NEW_COMMITS" -eq 0 ]]; then
echo ""
echo "上游无新 commit跳过合并。"
exit 0
fi
# 预检:列冲突文件
echo ""
echo "[Pre-flight] 检测预计会冲突的文件..."
CONFLICT_LIST=""
# 优先用 merge-tree --name-onlygit >= 2.38
if git merge-tree --name-only --no-messages main "$UPSTREAM_REMOTE/main" >/tmp/.sync-conflicts 2>/dev/null && [[ -s /tmp/.sync-conflicts ]]; then
CONFLICT_LIST=$(cat /tmp/.sync-conflicts)
else
# Fallback求两边都改过的文件作为「潜在冲突」候选不一定真冲突但是个高准确率的提示
CONFLICT_LIST=$(comm -12 \
<(git diff --name-only "$BASE" "$UPSTREAM_REMOTE/main" | sort) \
<(git diff --name-only "$BASE" main | sort))
fi
rm -f /tmp/.sync-conflicts
if [[ -n "$CONFLICT_LIST" ]]; then
echo " 以下文件预计需要手动解冲突 (或 auto-merge 后核对):"
echo "$CONFLICT_LIST" | sed 's/^/ /'
else
echo " 无冲突预测auto-merge 应该干净通过。"
fi
# 工作树检查
if [[ -n "$(git status --porcelain)" ]]; then
echo ""
echo "Error: 工作树非干净,请先 commit 或 stash" >&2
exit 1
fi
# 同步本地 main 到远端
echo ""
echo "[Branch] 同步本地 main 到 $GITEA_REMOTE/main..."
git fetch "$GITEA_REMOTE" main >/dev/null 2>&1
git checkout main >/dev/null
if ! git merge --ff-only "$GITEA_REMOTE/main" >/dev/null 2>&1; then
echo " Warning: 本地 main 与 $GITEA_REMOTE/main 不同步(非 fast-forward。继续基于本地 main。" >&2
fi
# 创建临时分支
TIMESTAMP=$(date +%Y-%m-%d-%H%M)
TEMP_BRANCH="${TEMP_BRANCH_PREFIX}${TIMESTAMP}"
echo "[Branch] 从 main 创建临时分支 $TEMP_BRANCH..."
git checkout -b "$TEMP_BRANCH"
# 启动合并(不 commit让人工解冲突
echo "[Merge] 启动 git merge --no-commit --no-ff $UPSTREAM_REMOTE/main..."
# || true 因为冲突时 git merge 退出码非 0
git merge --no-commit --no-ff "$UPSTREAM_REMOTE/main" || true
# Next-steps 引导
cat <<EOF
================================================================
合并已在分支 $TEMP_BRANCH 上启动(停在 --no-commit
================================================================
接下来人工操作:
1. 解冲突(如果有)
git status # 看 Unmerged paths
# 编辑冲突文件git add <file>
# 全部解完后:
git commit -m "Merge upstream/main ($UPSTREAM_HEAD) into $TEMP_BRANCH"
2. 验证:
cd frontend && pnpm run typecheck && pnpm run build
cd backend && go build ./cmd/server
3. 浏览器实测:
cd frontend && pnpm run preview
# 重点回归我们改过的页面:/ /pricing /docs /login /register
4. 测试通过后合并到 main
git checkout main
git merge --ff-only $TEMP_BRANCH
git push $GITEA_REMOTE main
5. 清理临时分支:
git branch -d $TEMP_BRANCH
放弃合并:
git merge --abort
git checkout main
git branch -D $TEMP_BRANCH
EOF