GitHubからGitLabへ移行しよう — インポート手順と知っておくべきこと
(ご参考: "GitLab チュートリアル & GitLab Duo Agent Platform" https://qiita.com/GL_Tsukasa/items/ebe4d11acaf6eefde894 )
GitHubを長く使っていると「これでいいか」と思いがちですが、GitLabにはCI/CDパイプライン、イシュートラッカー、セキュリティスキャン、コンテナレジストリなどが1プラットフォームに統合されています。「他のツールを探している」「チームのワークフローを見直したい」という方に向けて、GitHubからGitLabへのプロジェクト移行手順を整理します。
対象バージョン・プラン
| 項目 | 内容 |
|---|---|
| 対象ティア | Free / Premium / Ultimate |
| 対象オファリング | GitLab.com / GitLab Self-Managed / GitLab Dedicated |
| Importedバッジ | GitLab 17.2 で導入 |
何が移行できるのか
GitLabのGitHubインポーターは、単純にコードをコピーするだけではありません。以下のデータが移行されます。
- リポジトリ全体のGitデータ(全ブランチ)
- オープン中のプルリクエストに関連するforkブランチ(
GH-SHA-username/pull-request-number/fork-name/branchという命名規則で取り込まれます) - リポジトリの説明
- イシュー・プルリクエストのコメント・イベント
- ラベル・マイルストーン
- ブランチ保護ルール
- コラボレーター(メンバー)
- プルリクエストのレビュー・レビューコメント・提案
- プルリクエストのアサインされたレビュアー
- プルリクエストのマージ実行者情報
- Wikiページ
- リリースノートの内容
- 添付ファイル(コメント・イシュー説明・PR説明・リリースノート)※オプション
- Git LFSオブジェクト
インポートされたイシュー・マージリクエスト・コメントには Imported バッジが表示されるので、移行データと新規データの区別が一目でわかります。
ブランチ保護ルールのマッピング
GitHubのルールはGitLabの設定に自動変換されます。
| GitHubのルール | GitLabの設定 |
|---|---|
| マージ前に会話の解決を必須にする(デフォルトブランチ) | すべてのスレッドを解決済みにする(プロジェクト設定) |
| マージ前にプルリクエストを必須にする | プッシュ・マージの許可で「なし」を設定 |
| 署名済みコミットを必須にする(デフォルトブランチ) | 未署名コミットを拒否(プッシュルール) |
| 強制プッシュを許可(全員) | 強制プッシュを許可(ブランチ保護設定) |
| コードオーナーのレビューを必須にする | コードオーナーの承認を必須にする |
なお、ステータスチェックのパスを必須にするルールは移行されません。GitLabの外部ステータスチェック機能で手動設定が必要です(issue 370948 参照)。
コラボレーターのロールマッピング
| GitHubロール | GitLabロール |
|---|---|
| Read | Guest |
| Triage | Reporter |
| Write | Developer |
| Maintain | Maintainer |
| Admin | Owner |
移行前に確認しておくこと
前提条件
- GitHubインポートソースの有効化 — GitLab.comではデフォルトで有効。Self-Managedの場合はGitLab管理者に確認してください(管理画面 > 設定 > インポートおよびエクスポート設定)。
- 権限 — 移行元GitHubプロジェクトへのアクセスと、移行先GitLabグループのMaintainerまたはOwnerロールが必要です(GitLab 16.0 で導入)。
- サードパーティアプリアクセスポリシー — GitHubリポジトリが属するOrganizationのOAuthアクセス制限が、インポート先のGitLabインスタンスをブロックしていないことを確認してください。
インポート方法は3種類
方法1 — GitHub OAuth(推奨)
GitLab.comまたはGitHub OAuthが設定されたSelf-Managedインスタンスで使えます。バックエンドが適切な権限でトークンを交換してくれるため、一番手軽です。
- 画面右上の「新規作成」から「新しいプロジェクト/リポジトリ」を選択
- 「プロジェクトをインポート」→「GitHub」を選択
- 「GitHubで認証」をクリック
- リポジトリ一覧から移行したいものを選択
方法2 — GitHubパーソナルアクセストークン(PAT)
クラシック型のPATのみサポートされています(ファインgrained PATは非対応)。
-
https://github.com/settings/tokens/new で
repoスコープを選択してトークンを発行 - コラボレーターをインポートする場合やLFSファイルがある場合は
read:orgも追加 - GitLabのインポート画面でトークンを入力して認証
方法3 — REST API
以下の用途に向いています。
- 所有していないパブリックリポジトリのインポート
- GitHub Enterprise Server(セルフホスト型) からのインポート
- UIにない
timeout_strategyオプションを使いたい場合
APIはGitLabパーソナルアクセストークン(api スコープ)での認証のみサポートしています。
curl --request POST \
--url https://gitlab.com/api/v4/import/github \
--header "PRIVATE-TOKEN: <GitLabのアクセストークン>" \
--header "Content-Type: application/json" \
--data '{
"personal_access_token": "<GitHubのアクセストークン>",
"repo_id": "<GitHubリポジトリのID>",
"target_namespace": "<移行先のネームスペース>",
"new_name": "<新しいプロジェクト名>"
}'
リポジトリ一覧の絞り込み
GitLab 16.0 で導入されたフィルタ機能で、インポート対象のリポジトリを効率よく探せます。
- Owner(デフォルト)— 自分がオーナーのリポジトリ
- Collaborated — 自分がコントリビュートしたリポジトリ
- Organization — 自分がメンバーのOrganizationのリポジトリ(さらにドロップダウンでOrganizationを絞り込み可能)
オプション:追加インポート項目
デフォルトでは速度優先のため省略されているアイテムがあります。GitLab 16.8 で導入(16.11 でGA)。
| 設定項目 | 内容 |
|---|---|
| 代替コメントインポート方法を使用 | コメントが約3万件を超えるプロジェクト向け(GitHub APIの制限回避) |
| マークダウン添付ファイルをインポート | 画像・テキスト・バイナリ添付ファイル(インポートしないとGitHub側からの削除でリンク切れになります) |
| コラボレーターをインポート | デフォルトで有効。グループのシートを消費する可能性があるため注意。GitLab 18.4以降では「グループ内プロジェクトへのメンバー追加を禁止する」グループ設定が尊重されます |
移行にかかる時間の目安
すべての移行で結果は異なりますが、GitLabの検証テストでは kubernetes/kubernetes リポジトリ(プルリクエスト約8万件、イシュー約4.5万件、コメント約150万件)を 76時間 でインポートしています。大規模リポジトリの移行は計画的に。
Self-Managedの場合:インポートを高速化する方法
Sidekiqワーカー数を増やす
以下の2つのキューを処理するSidekiqワーカーを増やすと並列処理が増えます。
github_importergithub_importer_advance_stage
推奨構成はCPUコア数と同数のスレッドを持つSidekiqプロセスを少なくとも4つ用意し、できれば別サーバーで動かすこと。4台×8コアなら最大32オブジェクトの並列インポートが可能です。
GitHub Enterprise CloudのOAuthアプリを使う(レートリミット緩和)
GitHub APIの通常レートリミットは1時間あたり5,000リクエストですが、GitHub Enterprise Cloud OrganizationのOAuthアプリを使うと 15,000リクエスト/時間 に引き上げられます。大規模移行では移行時間を大幅に短縮できます。
既知の問題と注意事項
-
2017年以前のGitHubプルリクエストコメント — GitHub APIが
in_reply_to_idを含まないため、GitLabでは別スレッドとしてインポートされます - GitHub自動マージのコミット — GitHubの内部GPGキーで署名されたコミットがGitLab上で「unverified」と表示されることがあります
-
Markdownの
#参照 — GitHubはイシューもプルリクエストも#を使いますが、GitLabはイシューが#、マージリクエストが!です。コメントノート内の参照はイシューへのリンクのみ生成されます(マージリクエストかどうか判断できないため)。イシュー・マージリクエストの説明文内の参照はリンクを一切生成しません(インポート先でまだ作成されていない可能性があるため) - SAML SSO環境 — SSO強制時にGitHub APIのPATでは添付ファイルをダウンロードできない場合があります。インポート実行ユーザーをGitHubリポジトリのOutside Collaboratorに追加することで回避できます
- GitHub Enterprise CloudのカスタムリポジトリロールはGitLab未対応 — 部分的にしかインポートされません
- GitHub Enterprise ServerのMarkdown添付ファイル — GitLab 18.3以前はインポートされません。GitLab 18.4以降は動画・画像ファイルのみインポートされ、それ以外のファイル添付は非対応です
- 2023-05-09以前にアップロードされたプライベートリポジトリの画像添付 — インポートできません。該当するリポジトリのサンプルを提供できる場合は issue 424046 にコメントしてください
ユーザー名メンションの自動エスケープ(GitLab 17.5以降)
インポートされたイシュー・マージリクエスト・ノート内のユーザー名メンションには、自動的にバッククォートが付与されます。これにより、GitHubとGitLabで同じユーザー名を持つ別人へ誤ってリンクされるのを防ぎます。
ユーザー貢献のマッピング
GitLab 17.8 から、GitLab.com・Self-Managed・Dedicatedすべてで 移行後のユーザー貢献マッピング方式(post-migration mapping)が標準になりました。インポート後にユーザーを手動でマッピングできるので、事前準備の手間が減っています。
移行後もGitHubと同期する(ミラーリング)
{{Premium / Ultimate限定}}
移行後もしばらくGitHubとGitLabを並行運用したい場合、リポジトリミラーリングを設定することでインポートしたリポジトリをGitHubのコピーと同期し続けられます。
また、GitHub Project Integration を使うと、GitLabのパイプライン実行結果をGitHub側に通知することもできます。GitHubのプルリクエスト画面でCI結果を確認したいチームに便利です。
外部リポジトリ向けCI/CD でプロジェクトをインポートした場合は、ミラーリングとパイプラインステータス通知の両方が自動的に設定されます。
注意: ミラーリングは新規・更新されたプルリクエストの同期は行いません。
イントラネット上のGitHub Enterprise Serverから移行する場合
GitHub Enterprise Serverがインターネットから隔離された内部ネットワークにある場合、リバースプロキシを立てることでGitLab.comからアクセスできるようになります。
プロキシに必要な要件は2つです。
- GitHub Enterprise Serverへリクエストを転送する
- APIレスポンスのボディおよび
Linkヘッダー内にある内部ホスト名を、プロキシの公開ホスト名に書き換える(GitHubのAPIはページネーションにLinkヘッダーを使用するため、ここも変換が必要)
以下はApache HTTP Serverを使ったリバースプロキシの設定例です。
# 必要なモジュール
LoadModule filter_module lib/httpd/modules/mod_filter.so
LoadModule reflector_module lib/httpd/modules/mod_reflector.so
LoadModule substitute_module lib/httpd/modules/mod_substitute.so
LoadModule deflate_module lib/httpd/modules/mod_deflate.so
LoadModule headers_module lib/httpd/modules/mod_headers.so
LoadModule proxy_module lib/httpd/modules/mod_proxy.so
LoadModule proxy_http_module lib/httpd/modules/mod_proxy_http.so
LoadModule ssl_module lib/httpd/modules/mod_ssl.so
<VirtualHost GITHUB_ENTERPRISE_HOSTNAME:80>
ServerName GITHUB_ENTERPRISE_HOSTNAME
SSLProxyEngine On
ProxyPass "/" "https://GITHUB_ENTERPRISE_HOSTNAME/"
ProxyPassReverse "/" "https://GITHUB_ENTERPRISE_HOSTNAME/"
# レスポンスを解凍→内部URL置換→再圧縮
AddOutputFilterByType INFLATE;SUBSTITUTE;DEFLATE application/json
Substitute "s|https://GITHUB_ENTERPRISE_HOSTNAME|https://PROXY_HOSTNAME|ni"
SubstituteMaxLineLength 50M
# LinkヘッダーのURLも置換(ページネーション対応)
Header edit* Link "https://GITHUB_ENTERPRISE_HOSTNAME" "https://PROXY_HOSTNAME"
</VirtualHost>
注意: 上記はシンプルな例のため、クライアント〜プロキシ間の通信暗号化設定が含まれていません。本番環境ではTLS/SSL設定を必ず追加してください。
設定後は以下のコマンドでプロキシ経由のAPI疎通とgit cloneが正常に動作することを確認してください。
# APIの動作確認(レスポンス内のURLがプロキシホスト名になっていることを確認)
curl --header "Authorization: Bearer <YOUR-TOKEN>" "https://{PROXY_HOSTNAME}/user"
# git cloneの動作確認
git clone -c http.extraHeader="Authorization: basic <base64エンコードしたTOKEN>" \
--mirror https://{PROXY_HOSTNAME}/{REPOSITORY_PATH}.git
トラブルシューティング
インポートが途中で失敗した場合 — Railsコンソールで手動再開
リポジトリのインポートに失敗してプロセスが中断された場合、管理者はRailsコンソールから手動で再開できます。
project_id = <PROJECT_ID>
github_access_token = <GITHUB_ACCESS_TOKEN>
github_repository_path = '<GROUP>/<REPOSITORY>'
github_repository_url = "https://#{github_access_token}@github.com/#{github_repository_path}.git"
# プロジェクトをIDで検索
project = Project.find(project_id)
# インポートURLと認証情報を設定
project.import_url = github_repository_url
project.import_type = 'github'
project.import_source = github_repository_path
project.save!
# 手動作成されたプロジェクトの場合はインポートステートを作成
project.create_import_state if project.import_state.blank?
# ステートをstartに設定
project.import_state.force_start
# オプション:タイムアウト戦略や追加ステージが必要な場合は以下で設定
Gitlab::GithubImport::Settings
.new(project)
.write(
timeout_strategy: "optimistic",
optional_stages: {
single_endpoint_issue_events_import: true,
single_endpoint_notes_import: true,
attachments_import: true,
collaborators_import: true
}
)
# 第2ステップからインポートをトリガー
Gitlab::GithubImport::Stage::ImportRepositoryWorker.perform_async(project.id)
Import failed due to a GitHub error: (HTTP 406) エラー(GitLab 16.5以降)
GitLab 16.5でGitHubインポーターが Gitlab::LegacyGithubImport::Client の使用をやめた際に、パスプレフィックス api/v3 が自動付与されなくなりました。GitHub Enterprise URLからインポートする場合は、URLに api/v3 を手動で追加してください(例:https://github-enterprise.example.com/api/v3)。
大規模プロジェクトでコメントが欠落する
GitHub APIにはページネーション制限があり、約3万件を超えるノートやdiffノートはインポートされません。この上限に達すると以下のエラーがAPIから返されます。
In order to keep the API fast for everyone, pagination is limited for this resource.
Check the rel=last link relation in the Link response header to see how far back you can traverse.
コメント数が多いプロジェクトをインポートする際は、インポート画面で 「代替コメントインポート方法を使用」 にチェックを入れてください。ネットワークリクエスト数が増えるため時間はかかりますが、コメントの欠落を防げます。
GitLab Self-ManagedインスタンスがGitHubに接続できない
GitLab 15.10以前のSelf-Managedインスタンスでプロキシ環境下にある場合、github.com および api.github.com のDNS解決に失敗することがあります。GitLabの管理画面でローカルリクエストの許可リストに github.com と api.github.com を追加してください(設定 > セキュリティ > ウェブフックとサービス > 特定のIPアドレスとドメインへの送信リクエストを許可)。
まとめ
GitHubからGitLabへの移行は、リポジトリのコードだけでなく、イシューやレビュー履歴なども含めてかなりの部分を引き継げます。プロジェクトの規模や環境(github.comかEnterprise Serverか)によって適切なインポート方法は異なりますが、小規模プロジェクトならOAuthで数クリックするだけです。
GitLabはCI/CD、セキュリティスキャン、コンテナレジストリ、パッケージレジストリ、IaCテンプレートなど、開発ライフサイクル全体をカバーする機能が揃っています。移行をきっかけに、使い慣れたGitオペレーションを超えた機能を探求してみてください。