GitLabからGitHubへリポジトリを移行しました


My Redmine

開発グループの石川です。
ファーエンドテクノロジーでは、GitLabでリポジトリの管理を行っていましたが、昨年の12月にGitHubでの管理に変更しました。移行の際には考慮漏れも多く結構苦戦したので、同じように移行する方の参考になれば良いかないうことで共有します。

移行対象のリポジトリは100以上あり、手作業での移行は大変なのでGitLabやGitHubのAPIを使って進めました。APIを利用するために書いたスクリプトについても公開できれば良かったのですが、少し前に書いたスクリプトで現在も利用できる状態かわからないため今回はざっくりとした説明のみにしています。

流れに沿って移行の様子を振り返り

1. 移行したいリポジトリを調査

GitLabを使っていて管理しているリポジトリの中には不要になったリポジトリや検証用のリポジトリもあったため、事前に移行したいリポジトリを調査しました。また、この時にマージリクエストの移行が必要かも調べ、マージリクエスト上のレビューのやりとりが知見として大きいということで一部のリポジトリについてはマージリクエストも移行することになりました。

2. GitHubに空リポジトリを作成し、GitLabのRepository mirroring機能を使ってGitLabからミラーするように設定

リポジトリの移行については、GitLabのRepository mirroring機能を利用し、次の処理をリポジトリ単位で何度も繰り返し実行することでリポジトリの移行を行いました。ミラーすることで、GitLabを利用した業務を止めないままにGitHubへのリポジトリ移行を進めることができます。

  1. GitHubのOrganizationにGitLabと同じ名前で空リポジトリを作成
  2. GitLabのCreate a push mirror APIを使ってGitHubに作った空リポジトリにミラーする設定を追加
  3. 数秒sleep

しかし、終わってから考えてみると、GitLabの利用を一時的に止めて各リポジトリをgit cloneで取得してGitHubにgit pushするやり方の方が良かったかもと思っています。

GitLabのRepository mirroring機能について、ミラー設定はAPIで追加できるのですが、同期のトリガーは「git push」か「手動でボタンを押す」の二つしか無くAPIからはトリガーできません。ミラー設定をしてから1週間くらいは置いたためその間にpushがあったリポジトリについてはGitHubに自動で移行できたのですが、アクティブに動いていないリポジトリについては「手動でボタンを押す」必要があり、それが想定以上に大変でした。(同期ができていないリポジトリを絞り込むため、API(List organization repositories)を使ってOrganizationのリポジトリ一覧を取得し、その中からsizeが0のリポジトリのみに絞り込んで対応しました。)

使ったAPI

3. 同期したGitHub側のリポジトリでデフォルトブランチがおかしくなる問題が発生したため対応

GitHubへのミラー設定後、同期できたGitHub側のリポジトリでデフォルトブランチがおかしくなる問題が発生しました。

原因

空リポジトリを作ったときにデフォルトブランチはmainで作られていましたが、GitLabにあるリポジトリのほとんどがmasterブランチをデフォルトとしていてmainブランチが存在しませんでした。GitHubがデフォルトとして設定されているmainブランチを探しても見つからなかったために他のブランチがデフォルトとして表示されてしまっていました。

対応

masterからmainへのブランチ名変更を急にやると問題が起きかねないので、GitHub側のデフォルトブランチ設定をmainからmasterに変えるように変更しました(Update repository APIでdefault_branchをmasterに変更)。移行後に新しく作ったリポジトリのデフォルトブランチは、特に理由が無ければmainにしています。

使ったAPI

4. アクセス権限の設定

仕事内容に応じたTeamに所属するように設定し、そのTeamを各リポジトリに割り当てました。リポジトリ件数が多かったので、これも権限のリストを元に自作スクリプトによって一気に設定しました。

使ったAPI

5. 社内でGitHubの移行説明会を実施

git remoteがGitLabのリポジトリになっているのをGitHubのリポジトリに変更する作業は、説明会を開いて一気にやってもらいました。コマンドの実行でうまくいかないところがあっても、同時に作業することで周りのうまくいっている人や詳しい人に聞きやすく、大きな問題無く設定変更を行うことができました。

6. 原則GitHubの利用に切り替え

説明会終了後に自社サーバーで動かしていたGitLabにIPアドレス制限をかけ、原則GitHubを使って業務を行うように切り替えました。

7. GitLabのRepository mirroring機能を使って同期していた処理をGitHub Actionsで置き換え

2. GitHubに空リポジトリを作成し、GitLabのRepository mirroring機能を使ってGitLabからミラーするように設定 の手順でもRepository mirroring機能を利用しましたが、デプロイの自動化などをこの機能をトリガーに実現している物がいくつかあったため、GitHub Actionsで置き換えました。 GitLabのようにGUI上だけでは設定できませんが、一度コードを書いてしまえば他のリポジトリに対しても一部書き換えるだけで流用できたと思います。

GitHubの移行に切り替えてから対応の必要性に気づいたので、事前に洗い出せなかったという点は反省ポイントです。

8. マージリクエストの移行

マージリクエストの移行には、API経由でマージリクエストやIssueの移行を行うためのスクリプトが公開されていたため、それを利用させていただきました。
https://github.com/piceaTech/node-gitlab-2-github

node-gitlab-2-githubではsettings.tsにリポジトリの情報を書いた上で npm run start を実行するとそのリポジトリのマージリクエストなど指定した情報をGitLabからGitHubに移行できるというものです。

GitLabではすでにマージした作業用ブランチはほとんど削除していたため、useIssuesForAllMergeRequests設定を有効にしてマージリクエストをGitHubのIssueとして移行しました(ブランチが残っていないとプルリクエストとしての移行ができないため)。issueに移行した分多少見やすさは落ちますが、コードに対してのコメントはどの行へのコメントが分かるようになっていたりと良くできているので、後から変更の経緯や情報を探す分には問題ありません。


マージリクエストを移行したissueの様子(例)

node-gitlab-2-githubではリポジトリ1つずつしか移行ができないのですが、一気に実行してしまいたかったため

  1. settings.tsを書き換え
  2. npm run start で移行を実行
  3. 数秒sleep

という処理をリポジトリ単位で何度も繰り返し実行するスクリプトを書き、cronで深夜に動くようにして実行しました。一気に実行しすぎるとGitHubにリクエストを弾かれるため、sleepは結構多めに取りました。

マージリクエストの移行で失敗した点

マージリクエストの移行では、GitHubのリポジトリのIssueにたくさんのコメントが追加されるため、1つのリポジトリを移行しただけでも数千単位の通知メールが発行されることになります。マージリクエストの移行よりも先にGitHubでの運用を始めてしまっていたためにリポジトリに変更を加えるとそのリポジトリをウォッチしているユーザーに大量の通知が届く可能性があり、それを避ける方法が無いかいろいろ検証が必要になりました。

結局「GitHubですべてのメール通知を一時的にオフにする」か「マージリクエスト移行対象のwatchを外す」という対応を利用者全員に依頼することになり、手間をかけることになってしまいました。

=> 4. アクセス権限の設定 よりも先にマージリクエストの移行を行っていれば、この問題は回避できるはずです。

9. GitLabの利用を停止

マージリクエストの移行が完了したのを確認してから、GitLabへのアクセスを停止しました。GitHubへ運用を移してから一定期間はGitLabにもアクセスできるようにしていたことで、必要なデータを失うといったトラブルもなく移行が無事完了しました。

移行をした感想

GitLab・GitHubともにAPIが充実しているため、やりたいことのほとんどをコード化できたのは良かったです。手作業でやるのと違って作業漏れなどを防げますし、100以上のリポジトリに対してもあまり時間をかけずに移行することができました。失敗した点なども含めて、GitLabからGitHubへの移行を考えている方の参考になれば幸いです。


移行に使ったスクリプトたち
My Redmine

こちらの記事もオススメです!
チームで共通のフックスクリプト(Git hook)を使っています
Gitでバージョン管理されたスクリプトをフックスクリプトとして実行するために core.hooksPath の設定を利用しています。
Redmineのバグを見つけて改善できた話
会社で使っているRedmineでバグを発見。Redmineの改善につなげるため気がついたことを共有しています。
RedMica 2.1(Redmine 5.0互換)と Azure AD で SAML認証 をする方法
RedMica stable-2.1(Redmine 5.0互換)でSAML認証する方法。
Rails7.0にアプリケーションをアップデートしています
社内で開発中のRuby on RailsアプリケーションをVer6.1系からVer7.0系にアップデートした手順の一部をご紹介します。
AWS マネジメントコンソールへのログイン通知(2022年版)
証跡をマルチリージョン対応し他のサービスを連携して比較的簡単に対応ができました。
ファーエンドテクノロジーからのお知らせ(2024/04/24更新)
入門Redmine 第6版 出版記念企画セミナー「Redmineのアクセス制御」【2024/5/30開催】
入門Redmine 第6版(2024年3月23日発売)の書籍から「Redmineのアクセス制御」について解説します。
My Redmine 初回ご契約で「入門Redmine 第6版」プレゼントのお知らせ
Redmineのクラウドサービス「My Redmine」を初めてご契約いただいたお客様にRedmine解説書「入門Redmine 第6版」を進呈いたします。
2024年度ブランドパートナーに島根県在住のモデル ユイさんを継続起用
ユイさん(モデルスタジオミューズ所属)をファーエンドテクノロジーの2024年度ブランドパートナーとして継続して起用します。
My Redmine スタンダードプランおよびAdminサポートデスクプランの料金改定のお知らせ【2024年4月ご利用分より】
2024年4月ご利用分より、My Redmine スタンダードプラン(民間企業・個人向け及び官公庁向け)とAdminサポートデスクプランの料金を改定いたします。
Redmineの最新情報をメールでお知らせする「Redmine News」配信中
新バージョンやセキュリティ修正のリリース情報、そのほか最新情報を迅速にお届け