進捗を止めないために:GitHubからGitLab、Bitbucketへリポジトリを自動ミラーリングする方法

Git tutorial - IT technology blog
Git tutorial - IT technology blog

なぜ複数の場所にコードを同期させる必要があるのか?

半年間の受託プロジェクトでの経験から、私は痛い教訓を得ました:卵を一つのカゴに盛るな、ということです。GitHubが稼働率99.9%を保証していても、メンテナンスや国際海底ケーブルの故障などで、20人のチーム全員がコードをプッシュできずにお茶を濁す事態は十分に起こり得ます。

また、独自のCI/CDを実行するために社内のGitLabでの管理を求めるクライアントも多い一方、開発チームは強力なエコシステムを持つGitHub Actionsを好むこともあります。そんな時、リポジトリの「ミラーリング(Mirroring)」は両者のニーズを満たす最適な解決策です。git pushコマンドを手動で何度も打つ必要はなく、あらゆる場所にコードが並行して存在することになります。

私はこの習慣に救われたことがあります。ある新人エンジニアが誤ってgit push –forceを行い、developブランチを上書きしてしまったのです。幸い、社内のGitLabサーバーにミラーリングしていたため、わずか5分で全コミット履歴を復旧できました。もしミラーリングがなければ、チーム全員で徹夜してコードを修復する羽目になっていたでしょう。

リポジトリミラーリングの概念:単なるコピーではない

2つ目のリモートを追加することと、ミラーリングを混同している人が多くいます。git remote addコマンドは、単にコードをプッシュする先のアドレスを追加するだけです。真の意味でのミラーリングは、すべてのブランチ、タグ、そして全コミット履歴(commit history)を同期させることを指します。

区別すべき2つの形式があります:

  • Push Mirroring: 元のリポジトリ(Source)が、変更があった瞬間にターゲットリポジトリ(Destination)へデータを能動的にプッシュします。
  • Pull Mirroring: ターゲットリポジトリが定期的に元のリポジトリを「訪問」し、コードを取得(Pull)します。

方法1:Git CLIによる手動ミラーリング(緊急対応用)

複雑な設定なしでデータを同期する最も速い方法です。Gitの--mirrorフラグを活用します。

# 1. --mirrorフラグを付けて元のリポジトリをクローン
git clone --mirror https://github.com/user/repo-goc.git

# 2. クローンしたディレクトリに移動
cd repo-goc.git

# 3. ターゲットリポジトリへすべてをプッシュ
git push --mirror https://gitlab.com/user/repo-dich.git

警告: git push --mirrorコマンドは非常に強力です。ターゲット側のすべてを完全に上書きします。もしターゲット側にソース側に存在しないブランチがある場合、Gitは容赦なくそれらを削除します。

方法2:GitHub Actionsによる自動化(最適な選択肢)

GitHubを「本拠地」としているなら、誰かがプルリクエストをマージするたびに GitHub Actionsで自動的にGitLabやBitbucketへコードをプッシュさせましょう。この方法はよりプロフェッショナルで、手間もかかりません。

ステップ1:アクセス権限の設定

2つのプラットフォーム間で通信を行うには、Personal Access Tokenよりもセキュリティが高いSSHキーの使用をお勧めします。

  • 新しいSSHキーペアを作成します(個人のキーと共用しないでください)。
  • GitLabやBitbucketのDeploy Keysに公開鍵(Public Key)を追加します(Write権限のチェックを忘れずに)。
  • GitHubのSecrets and variables > Actionsに、GITLAB_SSH_PRIVATE_KEYという名前で秘密鍵(Private Key)をコピーします。

ステップ2:ワークフローの設定

.github/workflows/mirror.ymlファイルを作成します。このスクリプトは、メインブランチにプッシュされるたびに実行されます。

name: Mirror to GitLab

on:
  push:
    branches: [ main, develop ]

jobs:
  git-mirror:
    runs-on: ubuntu-latest
    steps:
      - name: ソースコードのチェックアウト
        uses: actions/checkout@v4
        with:
          fetch-depth: 0 # ミラーリングには全履歴を取得する必要がある

      - name: SSHキーの設定
        run: |
          mkdir -p ~/.ssh
          echo "${{ secrets.GITLAB_SSH_PRIVATE_KEY }}" > ~/.ssh/id_rsa
          chmod 600 ~/.ssh/id_rsa
          ssh-keyscan gitlab.com >> ~/.ssh/known_hosts

      - name: GitLabへプッシュ
        run: |
          git remote add gitlab [email protected]:username/project-mirror.git
          git push --force --prune gitlab "refs/remotes/origin/*:refs/heads/*"
          git push --force --tags gitlab

スクリプト内の--pruneフラグは、GitHub側で削除されたブランチを整理し、ターゲットリポジトリを常にクリーンな状態に保つのに役立ちます。

方法3:GitLabの標準ミラーリング機能を活用する

GitHubからコードを取得したい場合(Pull Mirroring)、GitLabの無料版が非常に優れたサポートを提供しています。これは定期的バックアップのための「楽な」しかし非常に効果的な方法です。

  1. GitLabのプロジェクトにアクセスし、Settings > Repositoryを選択。
  2. Mirroring repositoriesセクションを開く。
  3. GitHubのURLを入力(形式:https://github.com/user/repo.git)。
  4. 同期の方向(Mirror direction)をPullに設定。
  5. Authentication(認証)セクションにGitHubのPAT(Personal Access Token)を入力。

通常、GitLab無料版は数時間ごとに自動更新されます。急ぎの場合は、Refreshボタンを押して即座に同期することも可能です。

運用における「痛恨の教訓」

大規模システムの構築を何度も経験して得た、3つの重要な教訓を紹介します:

1. 無限ループの阻止

AからBへプッシュし、BからAへもプッシュし返すような双方向ミラーリングは絶対に設定しないでください。フィルターがないと、双方が互いのトリガーを起動し続け、CI/CDシステムをハングアップさせ、リソースを無駄に消費します。

2. 大容量ファイルの処理 (Git LFS)

通常のgit pushコマンドは大きなファイルを無視します。プロジェクトに多くのアセット(画像、動画、AIモデルなど)が含まれている場合は、両方の環境にGit LFSをインストールし、ミラーリングを実行する前にgit lfs fetch --allを実行するようにしてください。

3. 権限の同期

コードをミラーリングしても、アクセス権限まではミラーリングされません。新しいメンバーが加わった際は、両方のプラットフォームでコードレビューに参加したりCI/CDログを確認したりできるよう、両方にユーザーを追加する必要があります。

まとめ

リポジトリミラーリングの設定は、単なるバックアップではありません。GitHubでタスク管理を行い、GitLabで自社サーバーのパイプラインを実行してコストを最適化するなど、各プラットフォームの強みを活かすための賢明な戦略です。

サーバーに障害が発生してから慌ててデータ救出に走らないでください。設定には15〜30分ほどしかかかりませんが、それによって得られるプロジェクトの安心感は計り知れません。

Share: