通过gitlab流水线自动备份仓库

会自动对比提交,如果没有新的提交,则不会备份,避免空提交导致意外错误

gitlab仓库根目录新建.gitlab-ci.yml文件,复制粘贴以下配置,使用方法见文件注释

# gitlab流水线 自动备份仓库配置
# 将配置保存为 .gitlab-ci.yml 文件,放在 GitLab 仓库根目录下。
# 进入项目 → 设置 → 仓库 → 受保护分支 → 选择Developers + Maintainers两个角色
# 进入项目 → 设置 → 访问令牌 → 角色选择 Developer → 权限勾选 write_repository
# 进入项目 → 构建 → 流水线计划 → 添加定时任务

# 必填变量:
# GITHUB_REPO_URL: 需要备份的目标仓库地址(如:https://github.com/username/repo.git)
# GITLAB_USER_NAME: Git提交的用户名
# GITLAB_USER_EMAIL: Git提交的邮箱
# PROJECT_TOKEN:gitlab访问令牌(进入项目 → 设置 → CI/CD → 变量)

# 可选变量:
# GITHUB_TOKEN: GitHub 个人访问令牌(用于私有仓库或提高 API 限制)

variables:
  GITHUB_REPO_URL: "https://github.com/username/repo.git"
  GITLAB_USER_NAME: "user123456"
  GITLAB_USER_EMAIL: "[email protected]"

  BACKUP_BRANCH: "main" # 上游仓库分支
  GIT_STRATEGY: none
  GIT_DEPTH: 0

stages:
  - backup

backup_github_repo:
  stage: backup
  image: alpine:latest
  
  rules:
    - if: '$CI_PIPELINE_SOURCE == "schedule" && ($CI_COMMIT_REF_NAME == "main" || $CI_COMMIT_REF_NAME == "master")'
      when: always
    - if: '$CI_PIPELINE_SOURCE == "web" && ($CI_COMMIT_REF_NAME == "main" || $CI_COMMIT_REF_NAME == "master")'
      when: manual
  
  timeout: 1h
  
  before_script:
    - echo "开始备份 GitHub 仓库..."
    - apk add --no-cache git curl jq bash
    - git config --global user.name "$GITLAB_USER_NAME"
    - git config --global user.email "$GITLAB_USER_EMAIL"
    - git config --global init.defaultBranch main
    
  script:
    - WORK_DIR="/tmp/github_backup_$(date +%s)"
    - mkdir -p "$WORK_DIR"
    - cd "$WORK_DIR"
    - echo "工作目录:$WORK_DIR"
    
    - echo "正在克隆 GitHub 仓库..."
    - |
      if [ -n "$GITHUB_TOKEN" ]; then
        GITHUB_CLONE_URL=$(echo "$GITHUB_REPO_URL" | sed "s|https://|https://$GITHUB_TOKEN@|")
      else
        GITHUB_CLONE_URL="$GITHUB_REPO_URL"
      fi
    
    - git clone --branch "$BACKUP_BRANCH" --single-branch "$GITHUB_CLONE_URL" github_source
    - cd github_source
    
    - |
      if [ ! -d ".git" ]; then
        echo "错误:GitHub 仓库克隆失败!"
        exit 1
      fi
    
    - FILE_COUNT=$(find . -type f ! -path './.git/*' | wc -l)
    - |
      if [ "$FILE_COUNT" -eq 0 ]; then
        echo "警告:检测到空仓库,跳过备份"
        exit 0
      fi
    
    - echo "检测到 $FILE_COUNT 个文件,继续备份过程"
    
    - LATEST_COMMIT=$(git rev-parse HEAD)
    - COMMIT_MESSAGE=$(git log -1 --pretty=format:"%s")
    - COMMIT_DATE=$(git log -1 --pretty=format:"%cd" --date=iso)
    
    - echo "最新提交:$LATEST_COMMIT"
    - echo "提交信息:$COMMIT_MESSAGE"
    - echo "提交时间:$COMMIT_DATE"
    
    - cd "$WORK_DIR"
    - rm -rf github_source/.git
    
    - |
      git clone "https://project_${PROJECT_TOKEN}@$CI_SERVER_HOST/$CI_PROJECT_PATH.git" gitlab_backup
      cd gitlab_backup
      cp .gitlab-ci.yml ../gitlab-ci.yml.backup 2>/dev/null || true
      cp README* ../readme.backup 2>/dev/null || true
      find . -type f ! -name '.gitlab-ci.yml' ! -name 'README*' ! -path './.git/*' ! -name '.gitignore' -delete
      find . -type d -empty ! -path './.git*' -delete 2>/dev/null || true
      cp -r ../github_source/* ./ 2>/dev/null || true
      cp -r ../github_source/.[!.]* ./ 2>/dev/null || true
      cp ../gitlab-ci.yml.backup .gitlab-ci.yml 2>/dev/null || true
      if [ -f "../readme.backup" ] && [ ! -f "README.md" ] && [ ! -f "README.rst" ] && [ ! -f "README.txt" ]; then
        cp ../readme.backup README.md 2>/dev/null || true
      fi
    
    - git add .
    - |
      if git diff --staged --quiet; then
        echo "没有检测到变更,GitHub 仓库无新更新,跳过提交"
        echo "最后检查的 GitHub 提交:$LATEST_COMMIT"
        exit 0
      fi
    
    - echo "检测到文件变更,准备同步到 GitLab"
    
    - |
      BACKUP_MESSAGE="同步 GitHub 仓库更新 $(date '+%Y-%m-%d %H:%M:%S')"
      BACKUP_MESSAGE="$BACKUP_MESSAGE

      同步信息:
      - GitHub 提交:$LATEST_COMMIT
      - 提交信息:$COMMIT_MESSAGE  
      - 提交时间:$COMMIT_DATE
      - 同步时间:$(date -Iseconds)
      - 文件数量:$FILE_COUNT"
      git commit -m "$BACKUP_MESSAGE"
      git push "https://gitlab-ci-token:${PROJECT_TOKEN}@$CI_SERVER_HOST/$CI_PROJECT_PATH.git" main
    
    - echo "同步完成!GitLab 仓库已更新"
    
  after_script:
    - echo "清理临时文件..."
    - rm -rf /tmp/github_backup_* 2>/dev/null || true
❤️转载请注明出处❤️