A tool to migrate merge requests from a GitLab repository to pull requests on a GitHub repository.
- Requirements
- Installation
- Configuration
- Usage
- Images and attachments
- Limitations
- Testing & code quality
- Contributing
- License
- Credits
- PHP 8.3+
- Composer
git clone https://github.com/Maxcastel/migrate-gitlab-mr-to-github-pr.git
cd migrate-gitlab-mr-to-github-pr
composer installEach value can be set via a command-line option, an environment variable
(.env.local), or an interactive prompt if neither is set.
php bin/console import-mr \
--gitLabToken=<Your GitLab token> \
--gitLabProjectId=<Your source GitLab project ID> \
--gitLabUser=<Your GitLab user/group> \
--gitLabRepositoryName=<Your source GitLab repository name> \
--gitHubToken=<Your GitHub token> \
--gitHubUserName=<Your GitHub user name> \
--gitHubRepositoryName=<Your destination GitHub repository name>Copy the example file, then fill it in:
cp .env.local.example .env.local# GitLab (source)
GITLAB_TOKEN=
GITLAB_PROJECT_ID=
GITLAB_USER=
GITLAB_REPOSITORY_NAME=
# GitHub (destination)
GITHUB_TOKEN=
GITHUB_USERNAME=
GITHUB_REPOSITORY_NAME=
GITHUB_ASSIGNEE=Missing values are asked when the command runs:
$ php bin/console import-mr
gitLabToken? <Your GitLab token>
gitLabProjectId? <Your source GitLab project ID>Warning
Import the issues (bin/console import) before the merge requests (bin/console import-mr).
On GitLab, an issue is referenced with a # (#10) and a merge request with a !
(!10), while on GitHub both are referenced with a #.
A merge request linking to the issue #10 therefore becomes a pull request linking to
whatever holds the number 10 on GitHub, so import the issues first to keep those links on
the issues.
php bin/console importImports GitLab issues as GitHub issues:
- Run it before
import-mr: the issues take the first numbers on GitHub, so the references carried over from GitLab keep pointing at them. - Already imported issues are skipped: the command can safely be re-run.
See all options with php bin/console import --help.
php bin/console import-mrImports GitLab merge requests as GitHub pull requests:
- Syncs the branches: clones the GitLab repository and pushes its branches to GitHub.
- Recreates each merge request with its original merge commits, authors and dates, so the GitHub history mirrors GitLab's.
See all options with php bin/console import-mr --help.
| Option | Description |
|---|---|
--gitLabToken |
GitLab token |
--gitLabProjectId |
GitLab project ID |
--gitLabUser |
GitLab user or group that owns the repository (e.g. user123) |
--gitLabRepositoryName |
GitLab repository name, without owner or .git (e.g. project-abc) |
--gitHubToken |
GitHub token |
--gitHubUserName |
GitHub user name |
--gitHubRepositoryName |
GitHub repository name |
--limit=N |
Import at most N new merge requests (already imported ones don't count) |
--dry-run |
Show what would be imported, without changing anything |
--delay=N |
Wait N seconds between two merge requests (default 1, decimals allowed, 0 to disable) |
--skipSslCertificateVerification |
Disable TLS verification (for self-hosted instances with self-signed certificates) |
--skipTargetBranchProtection |
Don't protect the target branch at the end if it had no protection |
The import force-pushes the target branch, so its protection is handled automatically:
- Protected branch: the protection is removed during the import, then restored.
- Unprotected branch: a basic protection (no force-push, no deletion) is added at the end. Use
--skipTargetBranchProtectionto skip this.
Each merge request sends several write requests to GitHub, which can hit its secondary rate limit. GitHub recommends at least 1 second between write requests. To handle this:
- rate-limited requests are retried automatically;
- the import pauses 1 second between two merge requests (change it with
--delay).
GitLab links attached files with a relative path (/uploads/<secret>/<name>), which doesn't work on GitHub. So, in issues and merge requests:
- each image and video is downloaded from GitLab and uploaded to GitHub;
- GitLab image sizes (
{width=617 height=600}) become an<img>tag, the only way to size an image on GitHub. Unsupported sizes (e.g. percentages) are dropped.
- No de-duplication: running
import-mragain creates duplicate pull requests. - GitLab usernames are not mapped to GitHub: pull requests that had an assignee on GitLab are assigned to
GITHUB_ASSIGNEE(or to the authenticated user if it's empty).
php vendor/bin/phpunit
php vendor/bin/infection
php vendor/bin/phpstan
php vendor/bin/php-cs-fixer fix
php vendor/bin/rectorContributions are welcome! If you change the code for your needs, feel free to share it in a pull request.
Inspired by migrate-issues-gitlab-to-github, thanks to @tin-cat! To migrate only issues, go to that repository.