How to move from GitHub to GitLab: the importer, permissions and known gaps
SwitchTo HQ · Updated 18 October 2026 · Websites, analytics and code · How we write
GitLab has a built-in importer for GitHub repositories. It brings across the Git history plus most of the project around it, including issues, pull requests (as merge requests), comments, labels, milestones, releases and wiki pages. It doesn't convert your GitHub Actions workflows, and there are some known gaps worth checking before you rely on the result. This guide follows GitLab's Migrate from GitHub documentation.
Before you start
Permissions. GitLab says you need access to the source GitHub repository and the Maintainer or Owner role in the destination GitLab group. The GitHub organisation must not have a third-party application access policy that blocks the GitLab instance you are importing into.
Import source. The GitHub import source must be enabled on the GitLab instance. It is on by default on GitLab.com. On a self-managed instance, ask your administrator.
Groups and organisations aren't migrated. GitLab is clear that importing projects doesn't create any groups or organisations. Create your GitLab group structure first, then import each repository into the right place.
Size and time. Large repositories take a long time. GitLab reports that in its own testing, importing the Kubernetes repository (around 80,000 pull requests, 45,000 issues and 1.5 million comments) took 76 hours. Most repositories are far smaller, but plan large imports for a quiet period.
Choose how to authenticate
GitLab offers three methods:
| Method | When to use it |
|---|---|
| GitHub OAuth | Importing into GitLab.com, or a self-managed instance with GitHub OAuth configured. GitLab says it is preferable to a token because the right permissions are exchanged automatically |
| Personal access token | When OAuth isn't available. Only classic tokens are supported, with the repo scope, plus read:org to import collaborators or Git LFS files |
| Import API | Required for self-hosted GitHub Enterprise Server. Can also import public repositories you don't own |
If you use a personal access token, give it a short expiry date and revoke it in GitHub once the import is done.
Run the import
- In GitLab, select Create new (the plus icon), then New project/repository.
- Select Import project, then GitHub.
- Choose Authorize with GitHub, or paste your personal access token and select Authenticate.
- Check the proposed namespaces and names, and edit them if needed.
- Select Import next to each repository, or Import all repositories. You can filter by name first.
The Status column shows progress. When finished, an import is Complete, Partially completed or Failed. A partial import means some items didn't come across, so check the details. Imported issues, merge requests, comments and events carry an Imported badge.
What is imported
According to GitLab, the importer brings across:
- Git repository data, all branches and Git LFS objects
- branches from forks that relate to open pull requests
- issues, pull requests, comments, reviews, review comments and suggestions
- labels, milestones, release notes and wiki pages
- collaborators, and branch protection rules (mapped to GitLab protection rules or project settings)
- attachments in comments, descriptions and release notes, with the limits below
Each repository keeps its visibility level, unless that level is restricted on the GitLab instance.
Known issues to check
GitLab lists several known issues:
- Old review comments. Pull request review comments created before 2017 are imported as separate threads, because of a limitation in GitHub's API.
- Attachments. In GitLab 18.4 and later, only image and video files in Markdown attachments are imported. Other attachment types aren't. Images uploaded to private repositories before 9 May 2023 can't be imported.
- SSO-protected organisations. With SAML SSO enforced, attachments might fail to import. GitLab suggests adding the importing user as an outside collaborator on the GitHub repository.
- Issue and merge request references. GitHub uses
#for both issues and pull requests. GitLab uses#for issues and!for merge requests. In imported comments, GitLab only links references to issues. In descriptions, it doesn't create links at all. - Signed commits from auto-merge. Projects that used GitHub auto-merge can end up with merge commits shown as unverified if they were signed with GitHub's internal GPG key.
Map users to their contributions
GitLab uses a post-migration method to map contributions. Imported comments and issues are first attributed to placeholder users, and group owners then reassign them to real GitLab accounts. Make sure your team has GitLab accounts before you start reassigning. GitLab's post-migration mapping documentation explains the process in detail.
Move your CI from GitHub Actions
Your .github/workflows files come across as part of the repository, but GitLab CI/CD doesn't run them. You need to write an equivalent .gitlab-ci.yml. GitLab's guide to migrating from GitHub Actions compares the concepts (jobs, runners, secrets and so on) and explains how to translate them. Recreate your secrets as GitLab CI/CD variables. Never paste them into the repository.
Cut over
- Update local clones:
git remote set-url origin <new GitLab URL>. - Update deploy keys, webhooks and integrations to point at GitLab.
- Archive the GitHub repository and add a README pointing to the new location, rather than deleting it straight away.
Checklist
- Create GitLab groups first, and check you have the Maintainer or Owner role.
- Use OAuth if possible, or a classic token with
repo(andread:org). - Import, then check the status and look for partial imports.
- Review attachments, references and old review threads.
- Reassign contributions from placeholder users.
- Rewrite GitHub Actions as GitLab CI, and move secrets to CI/CD variables.
- Update remotes and integrations, then archive the GitHub repository.