On this page · 14 sections
- What changed on 3 August 2026
- What GEI actually migrates from GitLab
- The 7 things that do not migrate
- The three ceilings that shape your batch plan
- The CI/CD rebuild is the real project
- Running it: trial run, script, production
- Follow-up work before anyone can use the repository
- Seat cost, honestly
- Why teams are re-evaluating in the first place
- India-specific considerations
- A sequence that survives contact with a real estate
- FAQ
- How eCorpIT can help
- References
Summary. GitHub made GitLab migrations generally available on 3 August 2026 through GitHub Enterprise Importer and a new gh gl2gh command-line extension. Repositories, issues, merge requests, milestones, releases and wikis transfer. Seven categories of data do not, and the largest of them is your entire CI/CD estate: GitHub's own documentation states that .gitlab-ci.yml "has no automatic GitHub Actions equivalent". Three hard ceilings shape the plan: a 40 GiB limit on the GitLab export archive, a 40 GiB limit on the Git source that GEI will accept, and a 400 MiB per-file cap during migration that drops to 100 MiB once you are live. On list prices read on 5 August 2026, GitLab Premium is $29 per user/month billed annually while GitHub Enterprise starts at $21 per user/month for the first 12 months, so a 200-seat team is comparing roughly $69,600 a year against $50,400 in year one. That gap is not the decision. The rebuild is.
The GA announcement is short and the docs behind it are long, which is the usual shape of a migration that looks cheap in a changelog and expensive in a sprint. GitHub's changelog entry says you can now "self-serve these migrations using GEI and the gh gl2gh command-line extension", covering both gitlab.com and currently maintained GitLab Self-Managed versions. Destinations are GitHub Enterprise Cloud on github.com and on ghe.com. Migrations from GitLab into GitHub Enterprise Server are not supported at all.
What changed on 3 August 2026
Until this release, a GitLab-to-GitHub move with metadata fidelity ran through GitHub's Expert Services team. The tooling existed; you could not drive it yourself. Now a platform team can install a GitHub CLI extension and run the whole thing.
The mechanics per repository are four steps, in GitHub's own description: the extension exports the GitLab project to a .tar.gz archive containing the Git repository plus project metadata, stages the archive locally on the machine running the command, uploads it to blob storage GitHub can read, and imports it into the destination organization while transforming GitLab entities into GitHub equivalents.
The blob storage choice matters more than it looks. You can pass --use-github-storage and let GitHub host the staging archive, or point the extension at an AWS S3 or Azure Blob Storage account you own. Regulated teams that cannot let a project archive containing source and issue history transit a vendor-owned bucket will want the second option, and that decision needs to be made before the first trial run, not after.
One more constraint sits underneath everything: GEI does not support delta migrations. GitHub's guidance is direct about the consequence. Any change made in a GitLab project during or after the production migration has to be moved by hand. That single sentence is what turns a technical migration into a scheduling problem.
What GEI actually migrates from GitLab
GitHub publishes the list, and it is more generous than most teams expect. When the data is present in the GitLab export archive, the importer moves the following.
| Data type | Transfers | What to check after |
|---|---|---|
| Git source and full commit history | Yes | Ref names under 255 bytes; no commit over 2 GiB |
| Repository wiki | Yes | Wiki links that pointed at GitLab paths |
| Issues, issue comments, state, milestone events | Yes | Threaded discussions arrive as flat comments |
| Merge requests, converted to pull requests | Yes | Only the latest diff is in the export |
| Reviewers and approvers on merge requests | Yes | Approval rules themselves do not come |
| Milestones, timeline events, emoji reactions | Yes | Attribution shows mannequins until reclaimed |
| Uploads and attachments | Yes | Large attachments against the archive cap |
| Releases and release assets | Yes | Asset URLs in external systems |
| Project members | As mannequins | Reclaim needs an organization owner |
Two entries deserve a second look. Merge request comments migrate as review comments only when diff data is present in the export, and otherwise land as flat issue comments; because GitLab's export carries only the latest diff, review threads on superseded revisions lose their anchoring. And every piece of non-commit activity is attributed to a placeholder identity called a mannequin until someone reclaims it. Git commits keep their real authorship. Everything else does not, until an organization owner runs the reclaim.
The 7 things that do not migrate
This is the list that decides your budget. GitHub groups the gaps into seven categories.
- Git LFS objects. Pointer files ride along inside the Git history. The binaries do not. They have to be pushed to the destination separately as a follow-up task, which for a repository with years of design assets or model weights is its own bandwidth exercise.
- Repository policies. Merge trains, pipeline gates, required approvals, topics, avatars and mirroring all stop at the border. GitHub has equivalents for most of these in rulesets and required reviews, but they are re-expressed, not copied.
- Group settings and group membership. Your GitLab group hierarchy and its permission model has no import path. Teams, org roles and repository access get rebuilt in the destination.
- Snippets, issue boards, time-tracking data and design-management data. Boards are the painful one for delivery managers. Time-tracking history is usually the one nobody notices missing until a quarterly report.
- CI/CD pipelines and pipeline schedules. GitHub states plainly that
.gitlab-ci.ymlhas no automatic GitHub Actions equivalent. Schedules go too.
- Vulnerability reports. Any security findings history in GitLab does not transfer. You start a fresh baseline on GitHub Advanced Security or whatever scanner you standardise on.
- Anything GitLab omits from the export. Webhooks, CI/CD variables, job traces and artifacts, child-pipeline history and pipeline triggers are absent from GitLab's export in the first place, so no importer could move them.
Item 7 is the quiet one. CI/CD variables not being in the export means every secret, every registry credential, every environment token has to be re-created in GitHub before a single workflow can run green. On a 400-repository estate that is a multi-week task with a security review attached to it, and it is invisible in any migration status dashboard.
The three ceilings that shape your batch plan
Size limits come from three different places and they do not agree with each other, which is exactly how teams get surprised mid-batch.
| Limit | Value | Set by | Applies to |
|---|---|---|---|
| GitLab export archive | 40 GB | GitLab.com project export API | Whole archive: metadata plus Git source |
| Git repository size | 40 GiB | GEI (public preview limit) | Source code only |
| Single file during migration | 400 MiB | GEI | Any file in the repository |
| Single file after migration | 100 MiB | GitHub | Any file, ongoing |
| Single commit | 2 GiB | GitHub | Any commit in history |
| Single push | 2 GiB | GitHub | Post-migration pushes |
| Git reference name | 255 bytes | GitHub | Branch and tag names |
The archive ceiling is the one that bites first, because it counts issue history and attachments alongside code. A repository whose source is a comfortable 12 GiB can still fail if a decade of screenshots pushed the archive past 40 GB. GitHub's advice is to run git-sizer against each candidate repository and read the total blob size before you schedule anything, and the same tool surfaces the oversized files and tree counts that break a migration halfway through.
Note that the archive limit is set by GitLab and may differ on self-managed instances, which is one of the few places where running your own GitLab instance makes a migration easier rather than harder.
There is also a failure mode that has nothing to do with size. Rulesets configured on the destination organization can reject a migration outright. GitHub's example is a rule requiring commit author emails to end in a particular domain: if any commit in the incoming history violates it, the whole migration fails. Turn destination rulesets off for the migration window and back on afterwards.
The CI/CD rebuild is the real project
Every other line item in this migration is measured in hours. The pipeline rebuild is measured in weeks, and it is the reason a GitLab exit needs a budget rather than a maintenance window.
GitHub ships a separate tool for it, GitHub Actions Importer, and it does support GitLab as a source. Three subcommands carry the work:
auditanalyses the current CI/CD footprint and outputs an inventory of what is in use across a GitLab instance. It only works against an organization account.
dry-runconverts a pipeline to a GitHub Actions workflow and writes out the YAML without touching anything.
migrateconverts a pipeline and opens a pull request with the result.
All three accept --config-file-path, so you can feed the importer custom source files instead of having it fetch from source control, which is how you test conversions against a sanitised copy of a pipeline that references internal registries.
# Inventory first. This is the number your estimate is built on.
gh actions-importer audit gitlab \
--output-dir tmp/audit \
--gitlab-instance-url https://gitlab.example.com
# Convert one pipeline and read the YAML before trusting anything.
gh actions-importer dry-run gitlab \
--output-dir tmp/dry-run \
--gitlab-instance-url https://gitlab.example.com \
--namespace platform --project payments-api
# Only then open PRs.
gh actions-importer migrate gitlab \
--target-url https://github.com/acme/payments-api \
--gitlab-instance-url https://gitlab.example.com \
--namespace platform --project payments-api
Treat the importer's output as a first draft with a real acceptance cost. Converted workflows still need runner selection, secret wiring, environment protection rules, caching strategy and concurrency groups re-thought against GitHub's model, and self-hosted runners bring their own governance work that is worth reading up on before the cutover rather than during it. Teams already running Actions have learned this from the self-hosted runner version enforcement rules and from how Actions handles secret isolation on runners; both shape how you re-create GitLab CI variables safely rather than pasting them into repository secrets and moving on.
The honest planning number: assume the audit inventory, not the repository count, is what you are estimating. A hundred repositories sharing eight pipeline templates is a small job. Forty repositories with forty bespoke pipelines is not.
Running it: trial run, script, production
GitHub's sequence is seven documented phases, and the trial run is not optional in practice.
Trial run. Create a sandbox organization, name it with a -sandbox suffix so nobody mistakes it for production, and migrate into it. The trial answers three questions: whether a given repository completes at all, whether it comes back to a workable state, and how long it takes. Trials can run at any time and work does not need to stop, so batch them back to back and let repository owners validate on their own schedule.
Single repository. The command is one call:
gh gl2gh migrate-repo \
--gitlab-server-url https://gitlab.example.com \
--gitlab-group platform \
--gitlab-project payments-api \
--github-org acme \
--github-repo payments-api \
--use-github-storage
Nested subgroups use the full path, such as parent-group/subgroup. Useful flags: --target-repo-visibility sets public, private or internal and defaults to private; --archive-url and --archive-path re-import an archive you already exported rather than exporting again, which saves a great deal of time on a retry; --keep-archive retains the local archive after a successful upload. If the destination is ghe.com you also need --target-api-url, for example https://api.octocorp.ghe.com, and with GitHub-owned storage a matching --target-uploads-url.
Bulk. gh gl2gh generate-script writes one migrate-repo command per repository into a file. By default it includes every project the token can see, so scope it with --gitlab-group before you generate rather than deleting hundreds of lines afterwards. The generated script requires PowerShell to run, including on macOS and Linux, which is a small but real prerequisite to check with whoever owns the migration host.
Review the script before running it. Delete repositories you do not want, rename destinations with --github-repo, and set visibility per repository. Then halt work in the affected projects and run it.
Prerequisite that trips people. The GitLab project must have exports enabled. On self-managed instances that is an admin setting, and on a large instance the Sidekiq configuration for imports matters for throughput. Check both before the batch, not during.
Follow-up work before anyone can use the repository
A successful migration does not produce a usable repository. Four tasks stand between the two.
Read the migration log. Every migrated repository gets an issue titled "Migration Log" in the destination, readable by anyone with read access. GEI deliberately continues through non-critical errors rather than failing the whole run, so a migration that reports State: SUCCEEDED can still have dropped a pull request comment. The log is the only place that says so.
Set visibility. Everything arrives private, visible only to the user who ran the migration and organization owners. A one-liner fixes a whole org:
export ORG=YOUR_ORG
gh repo list "$ORG" --limit 100000 --json name -q '.[].name' \
| xargs -I{} gh repo edit "$ORG/{}" --visibility internal
Reclaim mannequins. Only organization owners can do this. If your migration was run by someone holding the dedicated migrator role, they cannot finish this step themselves. Bulk reclaim is available through the GitHub CLI. Until reclaim happens, searching for content associated with a mannequin, such as issues assigned to a departed teammate, may return nothing.
Undo the migration-window exceptions. If you widened an IP allow list for GEI or relaxed identity-provider restrictions on the destination enterprise, put them back.
Seat cost, honestly
List prices, read on 5 August 2026.
| Plan | List price | Included Actions/CI minutes | Included package storage |
|---|---|---|---|
| GitHub Free | $0 | 2,000 minutes/month | 500 MB |
| GitHub Team | $4 per user/month, first 12 months | 3,000 minutes/month | 2 GB |
| GitHub Enterprise | From $21 per user/month, first 12 months | 50,000 minutes/month | 50 GB |
| GitLab Free | $0 | Instance runner minutes metered | Metered |
| GitLab Premium | $29 per user/month, billed annually | Includes $12/user/month in GitLab Credits | Metered |
| GitLab Ultimate | Custom pricing | Includes $24/user/month in GitLab Credits | Metered |
Read the asterisks. GitHub's $4 and $21 figures are both marked "for the first 12 months" on its pricing page, so a two-year comparison is not the one the pricing page shows you, and any serious negotiation happens through sales anyway. GitLab Ultimate has no list price at all. The credits lines are not discounts on seats: they are allowances for the GitLab Duo Agent Platform, which only counts as savings if your teams would otherwise buy AI tooling.
For a 200-engineer organisation the arithmetic on those list prices is roughly $69,600 a year on GitLab Premium against $50,400 in a first year on GitHub Enterprise, before Advanced Security, Copilot or Codespaces. Codespaces alone starts at $0.18 per compute hour and $0.07 per GB-month of storage, and Git LFS runs $5 a month per 50 GB of storage and bandwidth, which is worth pricing precisely if the LFS objects you are about to push by hand are large. Teams doing this arithmetic across a wider tooling estate usually get more out of the discipline in our cloud FinOps guide for Indian teams than out of a seat-price spreadsheet.
The real cost is the migration, not the licence. A 400-repository estate with bespoke pipelines will spend more engineering time re-creating CI/CD variables and rebuilding merge policies than the first-year seat difference is worth. Do the rebuild estimate before the seat estimate.
Why teams are re-evaluating in the first place
Neither vendor is standing still, and both are under the same pressure. GitLab announced a restructuring in May 2026 that reduced headcount by about 14%, around 350 employees, and exited 22 countries, while reporting first-quarter revenue of $264 million, up 23% year over year, at 88% gross margins. The stated reason for the restructuring was infrastructure investment for AI workloads.
Bill Staples, CEO of GitLab, put the technical problem this way on the company's Q1 FY2027 earnings call in early June 2026:
Agents work at machine scale, and they're pushing competitors to the brink. This quarter we began a generational rebuild of git to support the scale and features required for 100x growth. This is a scale requirement that didn't exist before and has become a real pain point for every team on their agentic journey.
GitHub has had the same problem from the other side, publishing its own update on availability in 2026 after a run of incidents attributed in part to an influx of AI-driven activity. Anyone choosing between the two on reliability grounds in 2026 is choosing between two platforms actively rebuilding underneath their customers. Choose on the work you have to do, not on the incident that made the news last month.
India-specific considerations
Three things change the shape of this project for a team in India.
Data residency. GitHub Enterprise Cloud offers regional deployment on ghe.com, available in the EU and Australia as listed on GitHub's pricing page on 5 August 2026, with more regions described as coming. India is not currently among them. If your obligation is that source code and developer activity data rest in India, GitHub Enterprise Cloud does not satisfy it today, and the migration path into GitHub Enterprise Server, which you could host in-country, is explicitly unsupported from GitLab with GEI. That combination pushes an India-residency requirement towards staying on self-managed GitLab or towards an expert-led route.
DPDP obligations. Repository metadata carries personal data: names, work email addresses, commit trailers, issue mentions. Under the Digital Personal Data Protection Act 2023, moving that to a new processor is a processing change your records should reflect, and the staging bucket choice matters here. If you use your own AWS S3 or Azure Blob account in an India region for the archive, the project export never rests in vendor-owned storage outside your control. That is a cheap way to keep the paperwork simple.
Timing against the working week. Because GEI does not support delta migrations, production batches need a genuine freeze. For distributed teams with engineering in India and stakeholders in the US or Europe, the practical freeze window is a weekend, and the batch has to be sized to finish inside it. Trial runs are what tell you how many repositories fit.
A sequence that survives contact with a real estate
- Inventory. Run
gh actions-importer audit gitlabandgit-sizeracross every candidate repository. You now have two numbers that matter: distinct pipeline templates, and repositories over the size ceilings.
- Triage by size. Anything near 40 GiB of source or 40 GB of archive gets its own plan, usually history rewriting or LFS adoption, before it joins a batch.
- Decide storage. GitHub-owned blob storage or your own S3/Azure account. Regulated workloads: your own.
- Sandbox trial. One sandbox organization, a representative batch of ten repositories covering your worst cases, full follow-up tasks completed, owners validating.
- Rebuild pipelines in parallel. Dry-run conversions, review the YAML, wire secrets and environments. This runs alongside trials, not after them.
- Re-create the policy layer. Rulesets, required reviews, code owners, teams and repository access, environment protection. None of it came across.
- Production batches with a freeze. Generate the script, scope it, review it, halt work, run it.
- Follow-up immediately. Migration logs, visibility, mannequin reclaim, IP allow list cleanup. Do it per batch, not at the end.
- Re-enable destination rulesets you disabled for the migration window, and re-baseline security scanning, since vulnerability history did not transfer. Teams standardising on GitHub's own scanner will find the CodeQL code scanning setup guide covers the rollout decisions this step forces.
- Expect a re-index delay. Code search takes a few hours to re-index after each repository migrates, and results are unreliable until it finishes. Tell people, or you will get bug reports.
A migration run this way is boring, which is the point. The teams that struggle are the ones that migrated repositories first and discovered the pipeline rebuild afterwards, when the freeze had already happened and half the estate could not ship.
FAQ
How eCorpIT can help
eCorpIT is a Gurugram-based technology consultancy, CMMI Level 5 and ISO 27001:2022 certified, with senior engineering teams that run platform migrations end to end: inventory and sizing, pipeline conversion and acceptance testing, policy and access rebuild, and the follow-up work most plans forget. We design migrations aligned with DPDP requirements, including keeping export archives inside storage accounts you control. If you are scoping a GitLab exit and want an estimate built on your audit inventory rather than your repository count, talk to us — our release engineering and CI/CD platform practice exists for exactly this shape of project.
References
- GitHub Changelog, Migrate from GitLab to GitHub with GitHub Enterprise Importer, 3 August 2026.
- GitHub Docs, Understand migrations from GitLab to GitHub.
- GitHub Docs, Migrate your repositories from GitLab to GitHub.
- GitHub Docs, Follow-up tasks after a GitLab migration.
- GitHub Docs, About GitHub Enterprise Importer.
- GitHub Docs, Migration paths to GitHub.
- GitHub Docs, Automating migration with GitHub Actions Importer.
- GitHub Docs, Migrating from GitLab with GitHub Actions Importer.
- GitHub, Pricing: plans for every developer, read 5 August 2026.
- GitLab, Pricing, read 5 August 2026.
- GitLab Docs, Statement of support and maintained versions.
- TechCrunch, GitLab cuts 14% of staff as it scales its platform to serve AI workloads, 3 June 2026.
- GitHub, git-sizer repository.
Last updated: 5 August 2026.