GitLab to GitHub migration in 2026: the 7 things GEI will not move

GEI now self-serves GitLab migrations. Repos and issues transfer; CI/CD, LFS binaries and group settings do not.

Read time
19 min
Word count
3.1K
Sections
14
FAQs
8
Share
Diagram of a GitLab to GitHub migration showing repositories and issues transferring while CI/CD is rebuilt
GitHub Enterprise Importer reached general availability for GitLab sources on 3 August 2026.
On this page · 14 sections
  1. What changed on 3 August 2026
  2. What GEI actually migrates from GitLab
  3. The 7 things that do not migrate
  4. The three ceilings that shape your batch plan
  5. The CI/CD rebuild is the real project
  6. Running it: trial run, script, production
  7. Follow-up work before anyone can use the repository
  8. Seat cost, honestly
  9. Why teams are re-evaluating in the first place
  10. India-specific considerations
  11. A sequence that survives contact with a real estate
  12. FAQ
  13. How eCorpIT can help
  14. 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.

  1. 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.
  1. 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.
  1. 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.
  1. 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.
  1. CI/CD pipelines and pipeline schedules. GitHub states plainly that .gitlab-ci.yml has no automatic GitHub Actions equivalent. Schedules go too.
  1. 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.
  1. 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:

  • audit analyses 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-run converts a pipeline to a GitHub Actions workflow and writes out the YAML without touching anything.
  • migrate converts 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

  1. Inventory. Run gh actions-importer audit gitlab and git-sizer across every candidate repository. You now have two numbers that matter: distinct pipeline templates, and repositories over the size ceilings.
  1. 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.
  1. Decide storage. GitHub-owned blob storage or your own S3/Azure account. Regulated workloads: your own.
  1. Sandbox trial. One sandbox organization, a representative batch of ten repositories covering your worst cases, full follow-up tasks completed, owners validating.
  1. Rebuild pipelines in parallel. Dry-run conversions, review the YAML, wire secrets and environments. This runs alongside trials, not after them.
  1. Re-create the policy layer. Rulesets, required reviews, code owners, teams and repository access, environment protection. None of it came across.
  1. Production batches with a freeze. Generate the script, scope it, review it, halt work, run it.
  1. Follow-up immediately. Migration logs, visibility, mannequin reclaim, IP allow list cleanup. Do it per batch, not at the end.
  1. 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.
  1. 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

  1. GitHub Changelog, Migrate from GitLab to GitHub with GitHub Enterprise Importer, 3 August 2026.
  1. GitHub Docs, Understand migrations from GitLab to GitHub.
  1. GitHub Docs, Migrate your repositories from GitLab to GitHub.
  1. GitHub Docs, Follow-up tasks after a GitLab migration.
  1. GitHub Docs, About GitHub Enterprise Importer.
  1. GitHub Docs, Migration paths to GitHub.
  1. GitHub Docs, Automating migration with GitHub Actions Importer.
  1. GitHub Docs, Migrating from GitLab with GitHub Actions Importer.
  1. GitHub, Pricing: plans for every developer, read 5 August 2026.
  1. GitLab, Pricing, read 5 August 2026.
  1. GitLab Docs, Statement of support and maintained versions.
  1. TechCrunch, GitLab cuts 14% of staff as it scales its platform to serve AI workloads, 3 June 2026.
  1. GitHub, git-sizer repository.

Last updated: 5 August 2026.

Frequently asked

Quick answers.

01 Can I migrate from GitLab to GitHub Enterprise Server?
No. GitHub's changelog for the 3 August 2026 release states that migrations from GitLab to GitHub Enterprise Server are not supported. GitHub Enterprise Importer targets GitHub Enterprise Cloud only, on github.com or ghe.com. A GitLab to Enterprise Server move needs the expert-led gl-exporter path followed by ghe-migrator instead.
02 Does GitHub Enterprise Importer convert my .gitlab-ci.yml files?
No. GitHub's documentation states that CI/CD pipelines and pipeline schedules are not migrated because .gitlab-ci.yml has no automatic GitHub Actions equivalent. A separate tool, GitHub Actions Importer, converts pipelines with its audit, dry-run and migrate subcommands, but its output is a draft workflow you still have to review and wire up.
03 What happens to Git LFS objects during the migration?
Pointer files travel with the Git history, but the binary objects themselves are not migrated. GitHub documents this as a follow-up task: after the repository lands, you push the LFS objects to the destination separately. Budget bandwidth and time for it, and price GitHub's Git LFS storage at $5 a month per 50 GB.
04 How large can a repository be before GEI rejects it?
Three ceilings apply. GitLab's project export API will not produce an archive larger than 40 GB on GitLab.com, counting metadata and source together. GEI enforces a 40 GiB limit on Git source in public preview and a 400 MiB single-file limit during migration. After migration, GitHub's standing 100 MiB file limit applies.
05 Why is all my issue history attributed to strangers?
All user activity except Git commits is attributed to placeholder identities called mannequins. Commits keep their real authorship. An organization owner has to reclaim each mannequin and map it to a real member, which can be done in bulk through the GitHub CLI. Until then, searches for mannequin-associated content may return nothing.
06 Can I run the migration in stages while people keep working?
Trial runs, yes. Production migrations, no. GitHub Enterprise Importer does not support delta migrations, so any change made in GitLab during or after the production run has to be moved by hand. GitHub recommends halting work in the repositories you are migrating for the duration of the production batch.
07 Where is the migration archive stored while it uploads?
The gh gl2gh extension stages the archive locally on the machine running the command, then uploads it to blob storage GitHub can read. You choose between GitHub-owned storage with --use-github-storage or an AWS S3 or Azure Blob Storage account you control. Regulated teams generally pick their own account.
08 Does GitHub Enterprise Cloud offer data residency in India?
Not as listed on GitHub's pricing page on 5 August 2026, which names the EU and Australia with additional regions described as coming. Teams with a hard India residency requirement should note that GitLab to GitHub Enterprise Server, which could be hosted in-country, is not a supported GEI path either.

About the author

Manu Shukla

Founder & Director

Founder of eCorpIT. Hands-on engineer leading senior-only delivery for AI apps, custom software, and cloud systems for global clients.

Subscribe

One engineering note a week. No fluff, no spam.

Senior-architect playbooks on AI agents, mobile apps, cloud, security, data, and marketing — delivered every Wednesday.

Past the reading

Read enough. Let's build something.

A senior architect responds in 24 working hours with scope, indicative cost, and a timeline. NDA before any technical conversation.