なぜ複数の場所にコードを同期させる必要があるのか?
半年間の受託プロジェクトでの経験から、私は痛い教訓を得ました:卵を一つのカゴに盛るな、ということです。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の無料版が非常に優れたサポートを提供しています。これは定期的バックアップのための「楽な」しかし非常に効果的な方法です。
- GitLabのプロジェクトにアクセスし、Settings > Repositoryを選択。
- Mirroring repositoriesセクションを開く。
- GitHubのURLを入力(形式:
https://github.com/user/repo.git)。 - 同期の方向(Mirror direction)をPullに設定。
- 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分ほどしかかかりませんが、それによって得られるプロジェクトの安心感は計り知れません。

