1. 为什么需要同步Github到Gitee?
作为国内开发者,我经常遇到访问Github速度慢甚至无法访问的情况。特别是在使用阿里云服务器进行持续集成时,Github仓库的拉取速度常常成为整个流程的瓶颈。这时候,将Github仓库同步到国内的Gitee平台就显得尤为重要。
同步Github到Gitee主要有以下几个优势:
- 访问速度提升:Gitee作为国内代码托管平台,服务器位于国内,访问速度比Github快很多
- 稳定性保障:避免因网络问题导致无法访问Github仓库的情况
- 备份作用:相当于为Github仓库增加了一个国内镜像
- CI/CD优化:在阿里云服务器上使用Gitee仓库可以显著提升构建速度
2. 同步方案选型与对比
2.1 手动同步 vs 自动同步
手动同步虽然简单直接,但每次都需要重复操作,效率低下。而自动同步方案可以设置定时任务,实现无人值守的持续同步。
2.2 基于Git命令的同步方案
最基础的同步方式是通过git命令手动操作:
bash复制git clone --mirror git@github.com:user/repo.git
cd repo.git
git push --mirror git@gitee.com:user/repo.git
这种方式虽然可行,但每次同步都需要重新克隆整个仓库,效率不高。
2.3 基于Git Hook的同步方案
可以在Github仓库设置Webhook,当有代码推送时自动触发同步到Gitee。这种方式实时性好,但配置相对复杂,需要服务器端支持。
2.4 基于脚本的定时同步方案
综合考虑易用性和效率,我最终选择了编写Shell脚本配合crontab定时任务的方案。这种方案:
- 配置简单,只需一次设置
- 可以灵活控制同步频率
- 资源消耗小
- 易于监控和调试
3. 同步脚本详细实现
3.1 环境准备
在阿里云服务器上需要确保已安装:
- Git
- SSH密钥配置(用于免密操作)
- 基本的Shell环境
3.2 核心脚本代码
以下是经过实际验证的同步脚本:
bash复制#!/bin/bash
# 配置信息
GITHUB_REPO="git@github.com:username/repository.git"
GITEE_REPO="git@gitee.com:username/repository.git"
LOCAL_REPO_DIR="/path/to/local/repo"
LOG_FILE="/var/log/github2gitee.log"
# 创建日志目录
mkdir -p $(dirname $LOG_FILE)
# 记录日志函数
log() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" >> $LOG_FILE
}
# 检查本地仓库是否存在
if [ ! -d "$LOCAL_REPO_DIR" ]; then
log "本地仓库不存在,开始克隆Github仓库..."
git clone --mirror $GITHUB_REPO $LOCAL_REPO_DIR || {
log "克隆Github仓库失败"
exit 1
}
cd $LOCAL_REPO_DIR
git remote add gitee $GITEE_REPO
else
cd $LOCAL_REPO_DIR
fi
# 同步操作
log "开始同步Github到Gitee..."
git fetch --prune origin || {
log "从Github拉取更新失败"
exit 1
}
git push --prune gitee || {
log "推送到Gitee失败"
exit 1
}
log "同步完成"
3.3 脚本关键点解析
- --mirror参数:使用mirror模式克隆可以完整复制所有分支、标签和引用
- --prune参数:自动清理远程已删除的分支
- 日志记录:完善的日志记录便于问题排查
- 错误处理:对关键操作进行错误检测和记录
3.4 脚本优化版本
在实际使用中,我对脚本进行了以下优化:
bash复制#!/bin/bash
# 增强版同步脚本
# 配置
CONFIG_FILE="/etc/github2gitee.conf"
source $CONFIG_FILE
# 检查配置
if [ -z "$GITHUB_REPO" ] || [ -z "$GITEE_REPO" ] || [ -z "$LOCAL_REPO_DIR" ]; then
echo "配置文件中缺少必要参数" >&2
exit 1
fi
# 初始化
mkdir -p $(dirname $LOG_FILE)
exec >> $LOG_FILE 2>&1
# 函数:发送通知
send_notification() {
if [ -n "$NOTIFICATION_URL" ]; then
curl -X POST -d "message=$1" $NOTIFICATION_URL
fi
}
echo "[$(date '+%Y-%m-%d %H:%M:%S')] 同步任务开始"
# 检查本地仓库
if [ ! -d "$LOCAL_REPO_DIR" ]; then
echo "初始化本地镜像仓库..."
git clone --mirror $GITHUB_REPO $LOCAL_REPO_DIR || {
echo "初始化失败"
send_notification "Github到Gitee同步失败:初始化仓库出错"
exit 1
}
cd $LOCAL_REPO_DIR
git remote add gitee $GITEE_REPO
else
cd $LOCAL_REPO_DIR
fi
# 获取当前HEAD的commit id
OLD_HEAD=$(git rev-parse HEAD)
# 同步更新
echo "从Github拉取更新..."
git fetch --prune origin || {
echo "拉取更新失败"
send_notification "Github到Gitee同步失败:拉取Github更新出错"
exit 1
}
# 检查是否有更新
NEW_HEAD=$(git rev-parse HEAD)
if [ "$OLD_HEAD" = "$NEW_HEAD" ]; then
echo "没有新更新,跳过推送"
exit 0
fi
# 推送到Gitee
echo "推送到Gitee..."
git push --prune gitee || {
echo "推送失败"
send_notification "Github到Gitee同步失败:推送到Gitee出错"
exit 1
}
# 记录同步详情
echo "同步完成"
echo "变更统计:"
git log --pretty=oneline --abbrev-commit $OLD_HEAD..$NEW_HEAD
send_notification "Github到Gitee同步成功:$(git log --pretty=oneline --abbrev-commit -n 1 $NEW_HEAD)"
优化点包括:
- 使用配置文件分离敏感信息
- 增加变更检测,无更新时不进行推送
- 添加通知功能
- 记录详细的变更信息
- 改进错误处理和日志记录
4. 部署与定时执行
4.1 配置准备
创建配置文件/etc/github2gitee.conf:
bash复制# Github仓库地址
GITHUB_REPO="git@github.com:username/repository.git"
# Gitee仓库地址
GITEE_REPO="git@gitee.com:username/repository.git"
# 本地镜像路径
LOCAL_REPO_DIR="/opt/mirrors/repository.git"
# 日志文件路径
LOG_FILE="/var/log/github2gitee.log"
# 可选:通知URL(如Webhook)
NOTIFICATION_URL="http://your-notification-service/endpoint"
4.2 设置定时任务
使用crontab设置定时同步,例如每小时同步一次:
bash复制# 编辑当前用户的crontab
crontab -e
# 添加以下内容
0 * * * * /path/to/github2gitee.sh
4.3 权限设置
确保脚本有执行权限:
bash复制chmod +x /path/to/github2gitee.sh
日志目录需要可写权限:
bash复制mkdir -p /var/log/
touch /var/log/github2gitee.log
chmod 666 /var/log/github2gitee.log
5. 常见问题与解决方案
5.1 认证失败问题
问题现象:
code复制Permission denied (publickey).
fatal: Could not read from remote repository.
解决方案:
- 确保在阿里云服务器上生成了SSH密钥
- 将公钥添加到Github和Gitee的账户设置中
- 测试SSH连接:
bash复制
ssh -T git@github.com ssh -T git@gitee.com
5.2 仓库不存在问题
问题现象:
code复制remote: Repository not found.
fatal: repository '...' not found
解决方案:
- 确保Gitee上已创建对应的仓库
- 检查仓库地址是否正确
- 确保有推送权限
5.3 网络连接问题
问题现象:
code复制ssh: connect to host github.com port 22: Connection timed out
解决方案:
- 检查阿里云服务器的网络连接
- 尝试使用HTTPS协议替代SSH(需修改仓库URL)
- 考虑使用代理(需符合相关规定)
5.4 磁盘空间不足
问题现象:
code复制fatal: write error: No space left on device
解决方案:
- 清理磁盘空间
- 考虑将本地镜像仓库放在更大的磁盘分区
- 对于特别大的仓库,可以使用
--depth参数进行浅克隆
6. 高级应用场景
6.1 多仓库批量同步
如果需要同步多个仓库,可以修改脚本支持批量操作:
bash复制#!/bin/bash
# 仓库列表
REPO_LIST=(
"repo1"
"repo2"
"repo3"
)
# 基础配置
GITHUB_ORG="your_github_org"
GITEE_ORG="your_gitee_org"
BASE_DIR="/opt/mirrors"
for repo in "${REPO_LIST[@]}"; do
echo "处理仓库: $repo"
GITHUB_REPO="git@github.com:${GITHUB_ORG}/${repo}.git"
GITEE_REPO="git@gitee.com:${GITEE_ORG}/${repo}.git"
LOCAL_REPO_DIR="${BASE_DIR}/${repo}.git"
# 调用同步函数或执行同步命令
# ...
done
6.2 与CI/CD集成
可以将同步脚本集成到CI/CD流程中,确保每次Github更新后自动触发构建:
bash复制#!/bin/bash
# 同步代码
/path/to/github2gitee.sh
# 只有在同步成功时才继续执行构建
if [ $? -eq 0 ]; then
# 执行构建步骤
cd /path/to/project
git pull origin master
npm install
npm run build
# ...其他构建步骤
fi
6.3 增量同步优化
对于大型仓库,可以优化同步策略,减少数据传输量:
bash复制#!/bin/bash
# 使用增量同步策略
git fetch --prune --tags origin
git push --prune --tags gitee
# 只同步特定分支
BRANCHES=("master" "develop")
for branch in "${BRANCHES[@]}"; do
git push gitee refs/remotes/origin/${branch}:refs/heads/${branch}
done
7. 监控与维护
7.1 日志监控
建议设置日志监控,及时发现同步问题:
bash复制# 检查最近是否有错误日志
grep -i "error\|fail" /var/log/github2gitee.log
# 或者使用logrotate管理日志
cat > /etc/logrotate.d/github2gitee <<EOF
/var/log/github2gitee.log {
weekly
missingok
rotate 4
compress
delaycompress
notifempty
create 0644 root root
}
EOF
7.2 性能优化
对于大型仓库,可以考虑以下优化措施:
- 使用
git repack减少仓库体积 - 定期执行
git gc清理无用对象 - 考虑使用浅克隆(
--depth=1)如果不需要完整历史
7.3 安全考虑
- 配置文件应设置适当权限:
bash复制chmod 600 /etc/github2gitee.conf - 脚本不应包含明文密码,使用SSH认证
- 定期检查SSH密钥安全性
8. 替代方案比较
8.1 Gitee的仓库镜像功能
Gitee官方提供了仓库镜像功能,可以在网页端配置。相比脚本方案:
- 优点:无需服务器,配置简单
- 缺点:同步频率受限,灵活性差,无法自定义处理逻辑
8.2 第三方同步服务
如Repo Sync等第三方服务:
- 优点:开箱即用
- 缺点:可能有安全顾虑,依赖外部服务
8.3 自建Git服务器中间层
更复杂的方案是自建Git服务器作为中间层:
- 优点:完全控制,可扩展性强
- 缺点:维护成本高
对于大多数个人开发者和中小团队,本文的脚本方案在灵活性、可控性和易用性之间取得了良好平衡。
