下面的脚本,可以实现镜像分支与二开分支的同步。
bash# .cnb/.scripts/safe-sync-upstream.sh
#!/bin/bash
set -eo pipefail
# 颜色定义
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color
echo -e "${GREEN}🚀 开始安全同步上游仓库...${NC}"
echo "---------------------------------"
# 1. 基础配置
git config --global user.name "CI Sync Bot"
git config --global user.email "ci@example.com"
# 2. 添加上游仓库
if ! git remote | grep -q "upstream"; then
git remote add upstream https://github.com/Kele-Bingtang/vitepress-theme-teek
echo -e "${GREEN}✅ 已添加上游仓库${NC}"
fi
# 3. 分支定义(严格隔离)
readonly UPSTREAM_BRANCHES=("main" "dev")
readonly LOCAL_MIRROR_PREFIX="mirror_"
readonly CUSTOM_BRANCHES=("master" "develop")
readonly SYNC_DEFAULT_BRANCH=true # 是否同步默认分支
readonly DEFAULT_BRANCH="main" # 默认分支名称
readonly SYNC_SOURCE="master" # 同步源分支
# 4. 获取最新代码
echo -e "${GREEN}🔍 正在获取上游最新代码...${NC}"
git fetch upstream --prune --quiet
echo -e "${GREEN}✅ 已获取上游最新代码${NC}"
echo "---------------------------------"
echo -e "${GREEN}🔍 正在获取本地最新代码...${NC}"
git fetch origin --prune --quiet
echo -e "${GREEN}✅ 已获取本地最新代码${NC}"
echo "---------------------------------"
# 5. 保存当前分支
original_branch=$(git branch --show-current)
trap '[[ -n "$original_branch" ]] && git checkout "$original_branch" 2>/dev/null || true' EXIT
# 6. 创建本地镜像分支
create_mirror_branches() {
for branch in "${UPSTREAM_BRANCHES[@]}"; do
local mirror_branch="${LOCAL_MIRROR_PREFIX}${branch}"
local upstream_ref="upstream/${branch}"
echo -e "${YELLOW}🔄 正在同步镜像分支: ${mirror_branch}${NC}"
if git rev-parse --verify -q "$mirror_branch" >/dev/null; then
# 分支已存在,检查是否需要更新
if ! git diff --quiet "$mirror_branch" "$upstream_ref"; then
git checkout -B "$mirror_branch" "$upstream_ref" --quiet
git push origin "$mirror_branch" --force 2>/dev/null
echo -e "${GREEN} ✅ 已更新: ${mirror_branch} -> $(git rev-parse --short HEAD)${NC}"
else
echo -e " 🔹 无需更新: ${mirror_branch} 已是最新"
fi
else
# 分支不存在,创建新分支
git checkout -B "$mirror_branch" "$upstream_ref" --quiet
git push origin "$mirror_branch" 2>/dev/null
echo -e "${GREEN} ✅ 已创建: ${mirror_branch} -> $(git rev-parse --short HEAD)${NC}"
fi
done
}
# 7. 安全合并测试(改进版)
safe_merge_test() {
echo "DEBUG: 进入safe_merge_test: $1, $2"
local custom_branch=$1
local mirror_branch="${LOCAL_MIRROR_PREFIX}${2}"
# 添加标题输出(确保在函数开始时输出)
echo -e "${YELLOW}🛡️ 检查分支: ${custom_branch}${NC}"
# 保存当前分支
local current_branch=$(git symbolic-ref --short HEAD 2>/dev/null)
local stash_created=0
local result=0
# 如果有未提交的更改,先stash
if ! git diff --quiet || ! git diff --cached --quiet; then
git stash push --quiet --include-untracked >/dev/null 2>&1
stash_created=1
fi
# 检查本地分支是否存在
if git rev-parse --verify -q "$custom_branch" >/dev/null; then
echo -e "${GREEN} ✅ 使用本地分支: ${custom_branch}${NC}"
local temp_branch="temp_merge_${custom_branch}_$(date +%s)"
if ! git checkout -b "$temp_branch" "$custom_branch" --quiet >/dev/null 2>&1; then
echo -e "${RED} ❌ 创建测试分支失败${NC}"
result=1
elif git merge --no-commit --no-ff "$mirror_branch" --quiet >/dev/null 2>&1; then
echo -e "${GREEN} ✅ 可自动合并: ${custom_branch} ← ${mirror_branch}${NC}"
result=0
else
echo -e "${RED}⛔ 存在合并冲突: ${custom_branch} ← ${mirror_branch}${NC}"
result=1
fi
# 清理临时分支
git merge --abort --quiet >/dev/null 2>&1 || true
git checkout "$current_branch" --quiet >/dev/null 2>&1 || true
git branch -D "$temp_branch" --quiet >/dev/null 2>&1 || true
# 检查origin分支是否存在
elif git rev-parse --verify -q "origin/$custom_branch" >/dev/null; then
echo -e "${YELLOW} 🔄 从origin检出分支进行测试: ${custom_branch}${NC}"
local temp_branch="temp_test_${custom_branch}_$(date +%s)"
if ! git checkout -b "$temp_branch" "origin/$custom_branch" --quiet >/dev/null 2>&1; then
echo -e "${RED} ❌ 检出分支失败: ${custom_branch}${NC}"
result=1
elif git merge --no-commit --no-ff "$mirror_branch" --quiet >/dev/null 2>&1; then
echo -e "${GREEN} ✅ 可自动合并: ${custom_branch} ← ${mirror_branch}${NC}"
result=0
else
echo -e "${RED}⛔ 存在合并冲突: ${custom_branch} ← ${mirror_branch}${NC}"
result=1
fi
# 清理临时分支
git merge --abort --quiet >/dev/null 2>&1 || true
git checkout "$current_branch" --quiet >/dev/null 2>&1 || true
git branch -D "$temp_branch" --quiet >/dev/null 2>&1 || true
# 都不存在
else
echo -e "${YELLOW} ⚠️ 分支 ${custom_branch} 在本地和origin均不存在,跳过合并测试${NC}"
result=2
fi
# 确保恢复原分支
[[ -n "$current_branch" ]] && git checkout "$current_branch" --quiet >/dev/null 2>&1 || true
return $result
}
# 8. 执行合并操作(改进版)
perform_merge() {
local custom_branch=$1
local mirror_branch="${LOCAL_MIRROR_PREFIX}${2}"
# 检查本地分支是否存在
if git rev-parse --verify -q "$custom_branch" >/dev/null; then
if ! git diff --quiet "$custom_branch" "$mirror_branch"; then
if git merge --no-edit --no-ff "$mirror_branch" >/dev/null 2>&1; then
echo -e "${GREEN} ✅ 已合并更新: ${custom_branch} ← ${mirror_branch}${NC}"
return 0
else
echo -e "${RED}💥 合并冲突: ${custom_branch} ← ${mirror_branch}${NC}"
return 1
fi
else
echo " 🔹 无需合并: ${custom_branch} 已包含所有更新"
return 0
fi
# 检查origin分支是否存在
elif git rev-parse --verify -q "origin/$custom_branch" >/dev/null; then
echo -e "${YELLOW} 🔄 从origin检出分支进行合并: ${custom_branch}${NC}"
# 创建并切换到分支
if git checkout -b "$custom_branch" "origin/$custom_branch" --quiet >/dev/null 2>&1; then
if git merge --no-edit --no-ff "$mirror_branch" >/dev/null 2>&1; then
echo -e "${GREEN} ✅ 已合并更新: ${custom_branch} ← ${mirror_branch}${NC}"
# 设置上游跟踪
git branch -u "origin/$custom_branch" >/dev/null 2>&1
return 0
else
echo -e "${RED}💥 合并冲突: ${custom_branch} ← ${mirror_branch}${NC}"
return 1
fi
else
echo -e "${RED} ❌ 无法检出分支: ${custom_branch}${NC}"
return 1
fi
# 都不存在
else
echo -e "${YELLOW} ⚠️ 分支 ${custom_branch} 在本地和origin均不存在,跳过合并${NC}"
return 2
fi
}
# 9. 获取分支状态信息(改进版)
get_branch_status() {
local custom_branch=$1
local mirror_branch=$2
# 检查本地分支
if git rev-parse --verify -q "$custom_branch" >/dev/null; then
if git diff --quiet "$custom_branch" "$mirror_branch"; then
echo " ${custom_branch} 与 ${mirror_branch} 同步"
else
local behind_count=$(git rev-list --count "${custom_branch}..${mirror_branch}" 2>/dev/null || echo "未知")
if [[ "$behind_count" -eq "0" ]]; then
echo " ${custom_branch} 与 ${mirror_branch} 同步"
else
echo " ${custom_branch} 落后于 ${mirror_branch} (差异: ${behind_count} commits)"
fi
fi
# 检查origin分支
elif git rev-parse --verify -q "origin/$custom_branch" >/dev/null; then
# 创建临时分支进行比较
local temp_branch="temp_status_${custom_branch}_$(date +%s)"
if git checkout -b "$temp_branch" "origin/$custom_branch" --quiet >/dev/null 2>&1; then
if git diff --quiet "$temp_branch" "$mirror_branch"; then
echo " ${custom_branch} (origin) 与 ${mirror_branch} 同步"
else
local behind_count=$(git rev-list --count "${temp_branch}..${mirror_branch}" 2>/dev/null || echo "未知")
echo " ${custom_branch} (origin) 落后于 ${mirror_branch} (差异: ${behind_count} commits)"
fi
# 清理临时分支并恢复
git checkout - --quiet >/dev/null 2>&1
git branch -D "$temp_branch" --quiet >/dev/null 2>&1
else
echo " ${custom_branch} -> 状态检查失败"
fi
# 都不存在
else
echo " ${custom_branch} -> 分支不存在"
fi
}
# 10. 同步默认分支(改进版)
sync_default_branch() {
local default_branch="main"
local custom_branch="master"
echo "---------------------------------"
echo -e "${YELLOW}🔄 同步默认分支: ${default_branch} -> ${custom_branch}${NC}"
# 检查 custom_branch 是否存在
if ! git rev-parse --verify -q "$custom_branch" >/dev/null; then
echo " ⚠️ 二开分支 ${custom_branch} 不存在,跳过同步"
return 1
fi
# 处理 default_branch
if git rev-parse --verify -q "$default_branch" >/dev/null; then
# default_branch 已存在,进行同步
if ! git diff --quiet "$default_branch" "$custom_branch"; then
git checkout "$default_branch" --quiet >/dev/null 2>&1
if git merge --no-edit --no-ff "$custom_branch" --quiet >/dev/null 2>&1; then
echo -e "${GREEN} ✅ 已同步: ${default_branch} ← ${custom_branch}${NC}"
else
echo -e "${RED} ❌ 同步失败: ${default_branch} ← ${custom_branch}${NC}"
git merge --abort --quiet >/dev/null 2>&1
fi
else
echo " 🔹 无需同步: ${default_branch} 已与 ${custom_branch} 同步"
fi
else
# default_branch 不存在,创建并同步
git checkout -b "$default_branch" "$custom_branch" --quiet >/dev/null 2>&1
echo -e "${GREEN} ✅ 已创建: ${default_branch} → ${custom_branch}${NC}"
# 如果远程存在 default_branch,设置跟踪
if git rev-parse --verify -q "origin/$default_branch" >/dev/null; then
git branch -u "origin/$default_branch" >/dev/null 2>&1
echo -e "${GREEN} 📡 已设置远程跟踪: ${default_branch} -> origin/${default_branch}${NC}"
fi
fi
# 恢复原分支
git checkout "$original_branch" --quiet >/dev/null 2>&1
return 0
}
# 在主流程中调用(在最终状态报告前)
sync_default_branch
# ----------------------------
# 主执行流程
# ----------------------------
# A. 创建/更新镜像分支
create_mirror_branches
# B. 安全合并检测
echo -e "${YELLOW}🔎 正在检查合并兼容性...${NC}"
conflict_detected=0
skip_count=0
# 在主循环前添加调试
echo "DEBUG: 开始检查合并兼容性,分支数量: ${#CUSTOM_BRANCHES[@]}"
for i in "${!CUSTOM_BRANCHES[@]}"; do
echo "DEBUG: 准备检查分支 ${CUSTOM_BRANCHES[$i]} -> ${UPSTREAM_BRANCHES[$i]}"
done
for i in "${!UPSTREAM_BRANCHES[@]}"; do
echo "---------------------------------"
result=$(safe_merge_test "${CUSTOM_BRANCHES[$i]}" "${UPSTREAM_BRANCHES[$i]}")
echo "$result"
# 解析返回结果
if [[ "$result" == *"存在合并冲突"* ]]; then
conflict_detected=1
elif [[ "$result" == *"均不存在"* ]]; then
skip_count=$((skip_count + 1))
fi
done
# C. 执行合并(仅当无冲突且不是全部跳过)
if [[ $conflict_detected -eq 0 && $skip_count -lt ${#CUSTOM_BRANCHES[@]} ]]; then
echo "---------------------------------"
echo -e "${GREEN}🚀 正在执行安全合并...${NC}"
for i in "${!UPSTREAM_BRANCHES[@]}"; do
perform_merge "${CUSTOM_BRANCHES[$i]}" "${UPSTREAM_BRANCHES[$i]}"
done
else
echo "---------------------------------"
if [[ $conflict_detected -eq 1 ]]; then
echo -e "${RED}⚠️ 检测到冲突,已中止自动合并${NC}"
elif [[ $skip_count -eq ${#CUSTOM_BRANCHES[@]} ]]; then
echo -e "${YELLOW}⚠️ 所有二开分支均不存在,跳过合并${NC}"
fi
fi
# D. 同步默认分支
if [[ "$SYNC_DEFAULT_BRANCH" == "true" ]]; then
sync_default_branch "$DEFAULT_BRANCH" "$SYNC_SOURCE"
fi
# E. 最终状态报告
echo "================================="
echo -e "${GREEN}🌿 分支状态摘要:${NC}"
echo "---------------------------------"
echo -e "${YELLOW}【上游镜像分支】${NC}"
for branch in "${UPSTREAM_BRANCHES[@]}"; do
mirror_branch="${LOCAL_MIRROR_PREFIX}${branch}"
echo " ${mirror_branch} -> $(git rev-parse --short ${mirror_branch} 2>/dev/null || echo '未知')"
done
echo "---------------------------------"
echo -e "${YELLOW}【二开分支】${NC}"
for branch in "${CUSTOM_BRANCHES[@]}"; do
if git rev-parse --verify -q "$branch" >/dev/null; then
echo " ${branch} -> $(git rev-parse --short ${branch})"
elif git rev-parse --verify -q "origin/$branch" >/dev/null; then
echo " ${branch} -> (仅存在于origin)"
else
echo " ${branch} -> 不存在"
fi
done
echo "---------------------------------"
echo -e "${YELLOW}【分支差异状态】${NC}"
for i in "${!UPSTREAM_BRANCHES[@]}"; do
mirror_branch="${LOCAL_MIRROR_PREFIX}${UPSTREAM_BRANCHES[$i]}"
custom_branch="${CUSTOM_BRANCHES[$i]}"
get_branch_status "$custom_branch" "$mirror_branch"
done
echo "---------------------------------"
echo -e "${YELLOW}【远程分支状态】${NC}"
git remote show origin 2>/dev/null | grep -E '^(Local|Remote) branch' -A1 | sed 's/^/ /' || echo " 远程状态检查跳过"
echo "---------------------------------"
echo "🕒 最后同步时间: $(date '+%Y-%m-%d %H:%M:%S')"
echo "================================="
echo -e "${GREEN}✅ 同步完成。当前分支: ${original_branch}${NC}"
echo "================================="
echo "当前仓库分支关系图: "
echo "---------------------------------"
git branch -avv 2>/dev/null | grep -E '^( |* )' | sed 's/^/ /' || echo " 无法获取分支关系图"
echo "================================="
echo "🔧 请根据需要手动合并或更新分支。"
echo "================================="
# 在脚本最后添加推送环节
echo "---------------------------------"
echo -e "${YELLOW}🚀 推送二开分支到origin...${NC}"
# 推送master分支
if git push origin master --quiet 2>/dev/null; then
echo -e "${GREEN} ✅ 已推送: master → origin/master${NC}"
else
echo -e "${RED} ❌ 推送失败: master → origin/master${NC}"
fi
# 推送develop分支
if git push origin develop --quiet 2>/dev/null; then
echo -e "${GREEN} ✅ 已推送: develop → origin/develop${NC}"
else
echo -e "${RED} ❌ 推送失败: develop → origin/develop${NC}"
fi
echo "---------------------------------"
本文作者:任浪漫
本文链接:
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!