zhuyuan-ice-gl-zy001/BRIDGE/tools/zy-repo-sync.sh

87 lines
4.7 KiB
Shell
Raw Permalink Normal View History

#!/bin/bash
# ═══ zy-repo-sync · 移动硬盘 git 仓库 → 京东服务器 Forgejo 在线仓库 ═══
# 冰朔 2026-09-01 令(瞄点000092轮):"给服务器上开发个啥,能让移动硬盘里的
# git仓库同步到远端服务器上去变成在线仓库"。服务器上的"啥"=Forgejo(guanghulab.com/code/);
# 本工具=把任意本地 git 仓库接上去:不存在则建(默认私有)、挂干净远端、令牌只在内存。
# 纪律(同 zy-push):令牌只从 macOS 钥匙串读,永不落盘、永不进日志、永不进仓库;
# 永不 force push;线上若分叉先 fetch 对齐,接不上就停等人处理。
# 超大仓库引导(>前置反代请求体限制,公网推会 HTTP 413):走 SSH 隧道直连京东 Forgejo 本体——
# ssh -f -N -L 13340:127.0.0.1:3340 jd-fd-primary
# git push http://x-access-token:<令牌>@localhost:13340/bingshuo/<仓库名>.git main (注意:隧道内路径无 /code/ 前缀)
# 推完 pkill -f "ssh.*13340"。之后增量推送走公网即可(体量小,前置代理可容)。
# 用法:zy-repo-sync.sh <仓库路径> <仓库名> [private|public]
# 例:zy-repo-sync.sh "/Volumes/JZAO/铸渊-ICE-GL-ZY001" zhuyuan-ice-gl-zy001 private
set -uo pipefail
REPO_PATH="${1:?用法: zy-repo-sync.sh <仓库路径> <仓库名> [private|public]}"
REPO_NAME="${2:?缺仓库名}"
VISIBILITY="${3:-private}"
API_BASE="https://guanghulab.com/code/api/v1"
REMOTE_PATH="guanghulab.com/code/bingshuo/${REPO_NAME}.git"
KC_SERVICE="zhuyuan-forgejo-token"
KC_ACCOUNT="bingshuo"
LOG="$HOME/Library/Logs/zhuyuan-repo-sync.log"
log() { printf '%s %s\n' "$(date '+%Y-%m-%d %H:%M:%S')" "$*" >> "$LOG"; }
[ -d "$REPO_PATH/.git" ] || { echo "FAIL 不是git仓库: $REPO_PATH"; exit 1; }
cd "$REPO_PATH" || exit 1
BRANCH=$(git branch --show-current)
[ -n "$BRANCH" ] || { echo "FAIL 无当前分支( detached? )"; exit 1; }
TOKEN=$(security find-generic-password -s "$KC_SERVICE" -a "$KC_ACCOUNT" -w 2>/dev/null)
[ -n "${TOKEN:-}" ] || { echo "FAIL 钥匙串无 ${KC_SERVICE}/${KC_ACCOUNT}(先跑 zy-push-install.sh)"; exit 1; }
scrub() { sed "s|${TOKEN}|***|g"; }
trap 'unset TOKEN PUSH_URL' EXIT
# ── 1 · 仓库线上存在吗?不存在则建 ──────────────────────────
CODE=$(curl -s -m 15 -o /tmp/zrs-check.$$ -w "%{http_code}" \
-H "Authorization: token $TOKEN" "$API_BASE/repos/bingshuo/$REPO_NAME")
if [ "$CODE" = "404" ]; then
PRIV=$([ "$VISIBILITY" = "private" ] && echo true || echo false)
CODE=$(curl -s -m 20 -o /tmp/zrs-create.$$ -w "%{http_code}" \
-X POST -H "Authorization: token $TOKEN" -H "Content-Type: application/json" \
-d "{\"name\":\"$REPO_NAME\",\"private\":$PRIV,\"default_branch\":\"main\",\"auto_init\":false}" \
"$API_BASE/user/repos")
if [ "$CODE" != "201" ]; then
echo "FAIL 建仓失败 HTTP $CODE: $(head -c 300 /tmp/zrs-create.$$ | scrub)"; log "FAIL create $REPO_NAME HTTP $CODE"; exit 1
fi
echo "已建仓 bingshuo/$REPO_NAME ($VISIBILITY)"
elif [ "$CODE" != "200" ]; then
echo "FAIL 查仓异常 HTTP $CODE: $(head -c 200 /tmp/zrs-check.$$ | scrub)"; exit 1
else
echo "仓已存在 bingshuo/$REPO_NAME"
fi
rm -f /tmp/zrs-check.$$ /tmp/zrs-create.$$
# ── 2 · 挂干净远端(URL 不含令牌,可安全留在 .git/config)────
if git remote get-url origin >/dev/null 2>&1; then
git remote set-url origin "https://$REMOTE_PATH"
else
git remote add origin "https://$REMOTE_PATH"
fi
# ── 3 · 推(永不 force);线上已有历史则先 fetch 对齐 ────────
PUSH_URL="https://x-access-token:${TOKEN}@${REMOTE_PATH}"
REMOTE_HEAD=$(git ls-remote "$PUSH_URL" "refs/heads/$BRANCH" 2>/dev/null | awk '{print $1}')
if [ -n "$REMOTE_HEAD" ] && [ "$REMOTE_HEAD" != "$(git rev-parse HEAD)" ]; then
if ! git fetch -q "$PUSH_URL" "$BRANCH" 2>&1 | scrub; then
echo "FAIL fetch 失败(网络或令牌)"; log "FAIL fetch $REPO_NAME"; exit 1
fi
if git merge-base --is-ancestor FETCH_HEAD HEAD; then
: # 本地已包含线上历史,直接快进推
else
echo "FAIL 与线上分叉,需人工处理(不 force)"; log "DIVERGED $REPO_NAME"; exit 1
fi
fi
if git push -q "$PUSH_URL" "$BRANCH:$BRANCH" 2>&1 | scrub | head -3; then
NEW_HEAD=$(git ls-remote "$PUSH_URL" "refs/heads/$BRANCH" 2>/dev/null | awk '{print $1}')
if [ "$NEW_HEAD" = "$(git rev-parse HEAD)" ]; then
echo "PASS 已同步 $BRANCH $(git rev-parse --short HEAD) → bingshuo/${REPO_NAME}(线上备份在位)"
log "PASS $REPO_NAME $BRANCH $(git rev-parse --short HEAD)"
else
echo "FAIL 推后核验不一致"; log "FAIL verify $REPO_NAME"; exit 1
fi
else
echo "FAIL push 失败"; log "FAIL push $REPO_NAME"; exit 1
fi