將GitHub專案自動化同步至GitLab

注意

本文由 Gemini 3.1 Pro 語言模型產生。

面對第三方代管平台(如 GitHub)無預警鎖帳號或服務中斷的風險,建立「異地備援」是開發者保護資產的核心策略。本文件將說明如何將專案從 GitHub 完整備份至 GitLab。

一、 事前準備:取得 GitLab 存取金鑰(PAT)

無論是手動匯入還是自動化推送,建議先申請一把具備「寫入」權限的鑰匙。

  1. 登入 GitLab,點擊右上角個人頭像 → SettingsAccess Tokens
  2. 點擊 Add new token
    • Token name:建議命名為 GitHub_Backup_Sync
    • Select scopes:勾選 write_repository
  3. 點擊建立後,務必立即複製並保存該 Token,離開頁面後將無法再次查看。

二、 手動匯入:適用於「不常更新」的冷備份

對於已經進入維護期、不常有 Commit 的專案,直接使用 GitLab 內建的匯入工具最省事,且能完整保存 Issues 與 PR 紀錄。

步驟

  1. 在 GitLab 點擊 New projectImport projectGitHub
  2. 點擊 Authenticate with GitHub,引導到 GitHub 進行授權。
  3. 在專案列表中選擇要備份的儲存庫。
  4. 關鍵勾選項目:
    • Import Markdown attachments:強烈建議勾選,這會將 Issues 裡的圖片實體下載到 GitLab 伺服器,避免 GitHub 帳號刪除後圖片失效。
    • Import collaborators:建議取消勾選,避免將 GitHub 的歷史貢獻者誤判為 GitLab 使用者而達到免費帳號的人數上限(402 錯誤)。

三、 GitHub Actions 自動化:適用於「活躍更新」專案

透過 GitHub Actions,可以在你每次 git push 到 GitHub 時,自動「主動推送」一份副本到 GitLab。

第一步:在 GitHub 設定 Secrets

進入 GitHub 專案的 SettingsSecrets and variablesActions,新增以下 Secret:

  • NameGITLAB_TOKEN
  • Value:貼上你在第一階段申請的 GitLab PAT。

第二步:建立自動化工作流

在專案根目錄建立 .github/workflows/mirror.yml

場景 A:標準專案(無 LFS 大檔案)

適用於一般的程式碼、設定檔或 Astro 靜態網站。

name: Mirror to GitLab

on:
  push:
    branches: [ "main" ] # 確保分支名稱與你的一致
  workflow_dispatch: # 啟用手動執行按鈕

jobs:
  mirror:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout repository
        uses: actions/checkout@v4
        with:
          fetch-depth: 0 # 抓取完整歷史紀錄

      - name: Push to GitLab
        env:
          GITLAB_TOKEN: ${{ secrets.GITLAB_TOKEN }}
          GITLAB_USERNAME: "你的GitLab帳號"
          GITLAB_REPO: "你的GitLab專案名稱"
        run: |
          REMOTE_URL="https://oauth2:${GITLAB_TOKEN}@gitlab.com/${GITLAB_USERNAME}/${GITLAB_REPO}.git"
          git remote add gitlab $REMOTE_URL
          # 強制推送所有分支與標籤,避開隱藏的快取節點
          git push gitlab "refs/remotes/origin/*:refs/heads/*" --force
          git push gitlab "refs/tags/*:refs/tags/*" --force

場景 B:含有 LFS 歷史紀錄的專案(如 Hexo 部落格)

如果你曾在專案中使用過大圖檔並開啟 LFS,為了避免因「幽靈檔案(GitHub 伺服器已刪除但歷史紀錄仍有指標)」導致推送失敗,請使用此修正版。

核心重點:

  1. GitLab 端:進入 SettingsGeneralVisibility,關閉 Git Large File Storage (LFS) 選項。
  2. 腳本端:加入 GIT_LFS_SKIP_PUSH=1 咒語。
    name: Mirror to GitLab (LFS Optimized)
    
    on:
      push:
        branches: [ "main" ]
      workflow_dispatch:
    
    jobs:
      mirror:
        runs-on: ubuntu-latest
        steps:
          - name: Checkout repository
            uses: actions/checkout@v4
            with:
              fetch-depth: 0
              lfs: true # 下載目前的 LFS 實體檔案
    
          - name: Push to GitLab
            env:
              GITLAB_TOKEN: ${{ secrets.GITLAB_TOKEN }}
              GITLAB_USERNAME: "你的GitLab帳號"
              GITLAB_REPO: "你的GitLab專案名稱"
            run: |
              REMOTE_URL="https://oauth2:${GITLAB_TOKEN}@gitlab.com/${GITLAB_USERNAME}/${GITLAB_REPO}.git"
              git remote add gitlab $REMOTE_URL
    
              # 解決 LFS 幽靈檔案報錯的關鍵:
              # 1. 允許不完整的推送 (忽略 404 檔案)
              git config lfs.allowincompletepush true
              # 2. 略過對 GitLab 的 LFS 實體上傳,僅上傳程式碼與指標
              export GIT_LFS_SKIP_PUSH=1
    
              git push gitlab "refs/remotes/origin/*:refs/heads/*" --force
              git push gitlab "refs/tags/*:refs/tags/*" --force
    

四、 常見錯誤與排除(FAQ)

  • 錯誤 403 Forbidden:檢查 GITLAB_TOKEN。請確認它是從「個人 Profile」申請的全局 PAT,而非單一專案的 Token。
  • 錯誤 402 User Limit Exceeded:檢查 GitLab 專案成員。如果是從 GitHub 匯入的,請去 GitLab 的 Project InformationMembers 移除除了自己以外的所有幽靈成員。
  • 預設分支被保護:如果推送失敗顯示 pre-receive hook declined,請到 GitLab 專案的 SettingsRepositoryProtected branches,將 Allowed to force push 打開。