🔄

GitLab から GitHub へ移行してわかったことと、対応内容の記録

に公開

GitLab Premium を利用していた弊社が、GitHub Free(組織向け)へ移行した際の実際の手順や気づきをまとめました。

移行にあたって工夫したポイントや、両サービスを使ってみて感じた違いなど、実体験ベースでご紹介しています。

背景と目的

弊社では GitLab ブロンズプラン(月額 $4/ユーザー)を利用していましたが、プラン改定・価格改定 により、Premium プラン(月額 $29/ユーザー)へと推移しました。

これにより、年間数十万円のコスト増が発生しておりました。

一方 GitHub では、Free(組織向け)でもリポジトリ数無制限で CI/CD も 2,000 分まで利用可能と、基本的な機能をカバーしています。
Team プランでも $4/ユーザーとリーズナブルで、必要に応じて段階的に拡張が可能です。

このような背景を踏まえ、GitHub Free(組織向け)への移行を決定しました。

GitLab vs GitHub 機能比較表(2025/4/7 時点)

比較項目 GitLab 特徴 GitHub 特徴
公式ドキュメントの和訳 英語が中心 主要なものは日本語対応あり
リポジトリ管理 グループ・サブグループでの階層管理が可能 単体リポジトリ中心。外部連携が豊富
ホスティング セルフホスティングに加え、オンプレ運用も可能 クラウド型(Enterprise Server あり)
CI/CD 機能 グローバル変数の簡易利用が可能
($GITHUB_ENV相当の操作不要)
GUIで環境変数の確認・管理が可能
テンプレートやMarketplaceが豊富
パッケージ管理 グループ名をスコープ名にできる パブリック公開ではストレージ・データ転送ともに無料・無制限
視覚的な統計情報
Issue・PRの操作性 Issueからブランチ作成・MR発行がワンクリックで可能 ブランチ作成やPR発行の操作がGitLabほど一体化されていない
コメント機能 Issue/MRでのスレッドコメントが標準対応 PRコメントでもスレッド対応だが一部動作が異なることも
セキュリティ管理 シークレット値の直接参照に対応 Dependabot による自動の脆弱性検出・アップデートが優秀
開発支援機能 専用の支援ツールは少なめ GitHub Copilot によるAI補完支援が強力
再利用性・拡張性 テンプレートや変数の再利用には設定が必要で、柔軟性はあるが自動化度は低め Reusable Workflowsやマトリクスジョブなど、再利用性・拡張性が高い
外部サービスとの連携 一部可能(Slack連携など) Slack, Linear, Vercel, Sentry など多彩な連携が容易
OSSとの親和性 主にプライベートなプロジェクト向けとして利用される傾向が強い OSS開発の中心的存在で、コミュニティが活発

移行方針と準備

  1. 移行対象の洗い出し

    • ブランチ
    • タグ
    • メンバー
    • 環境変数・シークレット
    • CI/CD 設定(パイプラインスケジュール含む)
    • Issue・マージリクエスト
    • NPM パッケージ(スコープ・公開設定)
  2. 移行方法の検討

    node-gitlab-2-github は以下のような課題がありました。
    ※移行ツール

    • 添付ファイルが移行できない
    • Issue の作成者がツール実行者になる
    • 元ユーザーが存在しない Issue は移行不可
      ※離任済みのユーザーを再招待する予定がない

    そのため、以下のように決めました。

    • Git リポジトリはミラーリングで対応する
    • Issue・マージリクエストは GitLab の CSV エクスポート機能で残す

    ダウンロードされた zip ファイルには、CSV には画像も含まれており、参照用途には十分でした。必要であれば復元や専用のビューアも作成可能です。

ミラーリングの手順

  1. 作業ディレクトリ構成

    意図しない先に push を行わないよう下記ディレクトリの構成でリポジトリをクローンします。

    ├── gitlab   # GitLab用:移行前確認(fetch/push: GitLab)
    ├── mirror   # ミラーリング作業用(fetch: GitLab / push: GitHub)
    ├── github   # GitHub作業用(fetch/push: GitHub)
    
  2. GitHub 組織の作成

    新しくアカウントを作成し、組織に切り替えます。

  3. ミラーリング

    ミラーリング作業用のディレクトリで下記手順を行います。

    git clone --mirror <GitLabのURL>
    cd repo
    git remote set-url --push origin <GitHubのURL>
    git push --no-verify --mirror
    

    以降の同期(任意)

    git fetch -p origin
    git push --no-verify --mirror
    
  4. デフォルトブランチの設定

    GitHub ではデフォルトが main なので、必要に応じて変更してください。Team プラン以上では保護ブランチ設定なども行うと良いです。

  5. 環境変数の移行

    GitLab 左メニュー → 設定 → CI/CD → 変数にある内容を GitHub に移行します。

CI/CD の移行

  1. 内容の把握

    • .gitlab-ci.yml の有無
    • 過去に稼働していたジョブ(左メニュー → ビルド → ジョブ)
    • パイプラインスケジュールの有無(左メニュー → ビルド → パイプラインスケジュール)
  2. .github/workflows/*.yml への分割

    まとまったジョブ単位で GitHub Actions に分割して移行します。

プロジェクトのエクスポート

GitLab のエクスポート機能で CSV を出力。Issue、マージリクエスト、画像などが含まれます。Self-managed や Free プランでも利用可能です。

CI/CD 移行後の対応

  • GitLab 側のパイプライン無効化
  • GitHub 側での CI/CD 稼働開始
  • 必要に応じたメンバー招待やチーム作成、アナウンス

運用上のTips(補足)

共通変数のワークフロー化。

再利用される側

name: Common Environment Variables
on:
  workflow_call:
    outputs:
      ENV:
        description: "環境識別子"
        value: ${{ jobs.set-env.outputs.ENV }}

jobs:
  set-env:
    runs-on: ubuntu-latest
    outputs:
      ENV: ${{ steps.set-env.outputs.ENV }}
    steps:
      - id: set-env
        run: |
          case "${{ github.ref }}" in
            "refs/heads/develop") ENV="DEV" ;;
            "refs/heads/main") ENV="PROD" ;;
          esac

          echo "ENV=$ENV" >> "$GITHUB_OUTPUT"

呼び出し側

name: Deploy Workflow

on:
  push:
    branches:
      - develop
      - main
  workflow_dispatch: # 手動実行:デバッグ用

jobs:
  call-env:
    uses: ./.github/workflows/env.yml

  setup:
    runs-on: ubuntu-latest
    needs: call-env
    env:
      ENV: ${{ needs.call-env.outputs.ENV }}
    outputs:
      ENV: ${{ steps.set-env.outputs.ENV }}
      PROJECT_ID: ${{ steps.set-env.outputs.PROJECT_ID }}
    steps:
      - name: Checkout repository
        uses: actions/checkout@v4

      - name: Set Environment Variables
        id: set-env
        run: |
          # 他ジョブでも使用する環境変数をOUTPUTに設定
          {
            echo "ENV=$ENV"
            echo "PROJECT_ID=acomo-$ACOMO_ENV"
          } >> $GITHUB_OUTPUT

  backend-migrate:
    runs-on: ubuntu-latest
    needs: setup
    env:
      ENV: ${{ needs.setup.outputs.ENV }}
    steps:
      - name: Checkout repository
        uses: actions/checkout@v4

      - name: Set Env
        run: |
            echo "ENV=$ENV"
            echo "ENV=env.ENV"
            echo "PROJECT_ID=${{ needs.setup.outputs.PROJECT_ID }}"

このように workflow_call を使って共通化を行うこともできます。

冗長になってしまうので、ベタで書いて見通しよくするか、再利用性を高めるかはケースバイケースです。

動的シークレット参照。
echo KEY_ENV=${{ secrets[format('KEY_{0}', ENV)] }}
echo KEY_ENV=${{ secrets[format('KEY_{0}', env.ENV)] }}
echo KEY_ENV=${{ secrets[format('KEY_{0}', needs.setup.outputs.ENV )] }}

このうち、2 行目(env.ENV を使ったもの)のみが有効です。

NPM レジストリへの公開。
- uses: actions/setup-node@v4
  with:
    node-version: '22.x'
    registry-url: 'https://registry.npmjs.org/'

- name: コミットしてパッケージ公開:差分がある場合のみ
    env:
        NODE_AUTH_TOKEN: ${{secrets.NPM_TOKEN_ACOMO}}
    run: |
        # 将来的には、release-it に差し替えても良い
        npm run client:patch

        # acomo-clientのパッケージバージョンを更新するのでgitにコミットする
        if [ -n "$(git status --porcelain)" ]; then # 変更差分チェック
            git add acomo-client/package.json

            # [skip ci]でCIの再実行を無効化
            git commit -m "[skip ci] update acomo-client package version patch"

            git push -f

            # パッケージ公開(非公開の場合は課金が必要です)
            npm publish --access public
        fi

おわりに

GitHub への移行はコスト面では大きなメリットがありました。一方で、GitLab の機能の細やかさや管理のしやすさは、やはり組織規模や運用ポリシーによっては魅力的でもあります。

移行を検討されている方にとって、手順の参考、判断材料のひとつになれば幸いです。

Discussion