← All playbooks
Development migration

GitHub → GitLab

Move repositories and collaboration history from GitHub to GitLab with explicit handling for identities, LFS, attachments, CI/CD, protections, integrations, secrets, package registries, cutover, and mirror-based rollback.

Typical timelineEditorial estimate: 15–30 business daysEditorial estimate: 70–130 active hours active work
Statusagent reviewed
Source profileGitHub backup documentation reviewed 2026-07-27
Destination profileGitLab GitHub importer documentation reviewed 2026-07-27
Documentation date
Review window
Evidence4 sources
This route was independently agent reviewed.Its documented claims passed a two-agent source review. It is not a substitute for a representative migration test before production.
Before you migrate

Should you make this move?

Both platforms have a case. Compare what you gain with what you give up before scheduling the cutover.

Current platform

GitHub

Reasons to stay
  • The largest developer ecosystem combines collaboration, automation, and public discovery
  • Repository-centered workflows keep code, review, and automation close together
Reasons to leave
  • Enterprise planning and governance can require several overlapping GitHub products
  • Advanced governance and automation can become configuration-heavy
New platform

GitLab

What gets better
  • A comprehensive DevSecOps platform offers deep CI/CD and self-hosting options
  • Repository-centered workflows keep code, review, and automation close together
What gets worse
  • Breadth, upgrades, and administration can be heavy for smaller teams
  • Advanced governance and automation can become configuration-heavy
Best of the move

GitLab: A comprehensive DevSecOps platform offers deep CI/CD and self-hosting options. This removes a major source-side concern: Enterprise planning and governance can require several overlapping GitHub products.

Worst of the move

What you lose: The largest developer ecosystem combines collaboration, automation, and public discovery. What you inherit: Breadth, upgrades, and administration can be heavy for smaller teams.

Jump to a section
01At a glance

Know the shape of the move.

Transfer outcome14 features audited
Transfer outcome distributionClean transfer: 1, Partial transfer: 7, Manual rebuild: 4, Not transferred: 2.
Clean1
Partial7
Manual4
Lost2
Mapping route11 of 12 fields have a destination path

This timeline assumes

  • Editorial planning scale, not a GitHub or GitLab product limit: one GitHub.com organization with at most 100 repositories and 500 users; repositories near or above GitLab's documented approximate 30,000-comment threshold require the alternative comments option.
  • You control organization settings, GitLab top-level groups, DNS, CI credentials, registries, OAuth applications, and production deployment targets.
  • Every repository receives a mirror backup and its wiki, LFS objects, releases, packages, secrets, environments, and integrations are inventoried separately.
  • GitLab groups and users are prepared before import; after import, GitLab's current post-migration contribution and membership mapping is completed, and any unmapped contribution is accepted only with an explicit attribution exception.
  • Each repository is frozen before its production importer run and remains locked; production deploys are also frozen while the final scoped Git mirror, CI switch, and webhook cutover occur.
02What transfers

What survives the move.

“Partial” and “manual” are not footnotes. They are work that must be scheduled and verified.

ItemOutcomeImpactWhat happensMitigation
Approved user branches, tags, fork branches, commits, and revision historycleancriticalGit parity is clean for approved user branches and tags plus fork branches required by imported pull requests when their tips and objects are explicitly reconciled.Record the approved ref scope, run fsck, compare those ref tips and commit graphs, and handle submodules separately.
Provider-owned and synthetic refsmanualmediumGitHub-owned pull-request, merge, notes, and other synthetic refs are not ordinary user branches and should not be treated as required one-for-one Git parity.Classify refs by namespace, preserve a mirror backup, and verify corresponding imported pull-request metadata instead of publishing provider refs.
Issues and pull requestspartialcriticalThe GitLab importer moves issues and pull requests into GitLab concepts, but state, review semantics, references, and edge cases are not identical.Pilot repositories with complex reviews, cross-links, draft PRs, and merged branches.
Comments and review commentspartialhighLarge projects with roughly 30,000 or more comments can exceed the recommended importer path; attribution also depends on user mapping.Use GitLab's documented alternate method for large projects and reconcile counts by type.
Markdown attachmentspartialhighAttachments require the relevant importer option; otherwise links in migrated Markdown can break.Enable attachment import, scan migrated Markdown URLs, and preserve a source archive.
Git LFS objectspartialcriticalGitLab lists LFS objects as imported data, but its GitHub importer requires the documented token scope for repositories with LFS. A separate mirror backup also requires an explicit Git LFS fetch.Use the required importer scope, fetch all LFS objects into the backup, compare object inventories, and download representative binaries.
Users and organization structuremanualcriticalThe GitHub importer does not create GitLab groups from organizations and imports only supported direct collaborators; outside collaborators can be omitted. Current GitLab versions use post-migration contribution and membership mapping.Create groups, subgroups, and users first; complete post-import contribution and membership mapping, then audit attribution and effective membership.
Branch protection and rulesetspartialcriticalSome branch protection can map, but GitHub rulesets, status-check requirements, bypass actors, and custom roles are not equivalent.Rebuild protected branches, approval rules, push rules, CODEOWNERS, and merge checks from an approved policy matrix.
GitHub Actions workflowsmanualcriticalWorkflow YAML, runners, environments, approvals, OIDC trust, caches, and marketplace actions do not become GitLab CI behavior automatically.Translate to .gitlab-ci.yml, replace actions, use GitLab variables and identities, and run release-path tests.
Secrets, variables, and environmentslostcriticalSecret values are intentionally not exportable and environment rules differ.Create a secret inventory without values, rotate credentials, and enter them through approved GitLab secret controls.
Packages, releases, and artifactspartialhighRelease metadata, binary assets, container images, packages, Actions artifacts, and caches have separate migration paths and retention rules.Inventory each registry and artifact class, then copy and verify with native clients.
Wikis and GitHub PagespartialhighGitLab lists wikis as supported by the GitHub importer, but wiki content still requires count and content verification; Pages build and deployment settings are platform-specific.Verify the imported wiki and keep a .wiki.git mirror as fallback; rebuild Pages publishing and domains in GitLab.
Webhooks, apps, bots, and integrationslostcriticalInstallation IDs, tokens, webhook secrets, checks, project boards, Dependabot, and external automation do not transfer as working integrations.Reauthorize or replace each integration and test delivery before disabling GitHub.
Fork relationshipsmanualhighGitLab documents importing fork branches associated with open pull requests, but the reviewed documentation does not promise recreation of the GitHub organization-wide fork network.Document required fork topology and manually verify or rebuild upstream/downstream contribution flows.
03Field and feature mapping

Where each thing goes.

SourceDestinationMethodNotes
GitHub organizationGitLab top-level groupmanualCreate group and subgroup hierarchy before project import.
RepositoryGitLab projecttransformRun the GitHub importer and confirm visibility, default branch, namespace, path, optional stages, and final import status.
Approved user branches/tags and required fork branchesGitLab branches and tagsautomaticCompare the approved user-ref scope and classify provider-owned synthetic refs separately.
Pull requestMerge requesttransformGitLab imports pull requests and related review data, subject to documented mapping and known issues; reconcile states, references, reviewers, and discussions.
Issue and labelIssue and labeltransformGitLab lists these as imported, but identities, references, states, and partial imports still require reconciliation.
GitHub user and contributionGitLab user, contribution, and membershiptransformPrepare destination users, then complete GitLab's current post-migration contribution and membership mapping and record every unresolved identity.
Branch protection/rulesetProtected branch and approval/merge rulesmanualRecreate policy from intent; status checks are not imported as an equivalent rule.
.github/workflows/*.yml.gitlab-ci.yml and CI includesmanualTranslate jobs, matrices, permissions, environments, caching, and release steps.
Actions secretGitLab masked/protected CI/CD variable or external secretmanualRotate; secret values cannot be exported safely.
GitHub release and assetGitLab release and package/generic assettransformCopy binaries and verify checksums.
GitHub wikiGitLab wikitransformUse the importer-supported wiki path, verify content, and retain a .wiki.git mirror fallback.
GitHub App/webhookNo destinationunsupportedInstall a GitLab-native integration or update the external service.
04Before you begin

Make the move recoverable.

Backup procedure

Create the source-of-truth backup

Preserve every repository and the operational metadata required to reconstruct development and release workflows.

  1. Inventory repositories, visibility, archived/fork/template status, refs, LFS, submodules, wikis, Pages, issues, PRs, releases, packages, Actions, environments, rules, teams, apps, webhooks, deploy keys, and production dependencies.
  2. Create a --mirror clone of every repository and wiki, fetch all LFS objects, run git fsck, and record ref tips.
  3. Export organization/repository metadata and issue/PR counts through approved GitHub APIs or enterprise migration exports.
  4. Download required release assets and package/container artifacts with checksums.
  5. Record secret names and consumers without exporting values; plan rotation.

Proof to capture: A repository-by-repository manifest contains mirror hashes, ref and LFS counts, collaboration counts, assets, policies, integration owners, and restore instructions.

Transformation · GitLab post-migration contribution and membership mapping plus a reviewed namespace table

Identity and namespace map

Preserve attribution and least-privilege access.

  1. Map organization, teams, users, bots, externals, and emails.
  2. Create GitLab groups and users before import.
  3. After import, complete contribution and membership mapping and list every unresolved identity as a blocking exception.

Proof to capture: Save the input, output, command or tool settings, warnings, and final item counts.

Transformation · GitLab CI lint and isolated runners

CI/CD translation

Rebuild tested pipelines rather than copying inert workflow files.

  1. Map triggers, jobs, services, permissions, caches, artifacts, environments, and approvals.
  2. Rotate variables and update OIDC/cloud trust.
  3. Run build, test, preview, production, and rollback paths.

Proof to capture: Save the input, output, command or tool settings, warnings, and final item counts.

Transformation · Branch/ruleset policy matrix

Policy reconstruction

Recreate repository protection from its security intent.

  1. Inventory GitHub rulesets, protections, CODEOWNERS, status checks, and bypass actors.
  2. Map to protected branches, approvals, push rules, and merge checks.
  3. Test allowed and forbidden actions with role accounts.

Proof to capture: Save the input, output, command or tool settings, warnings, and final item counts.

05Handle with care

The things most likely to hurt.

These are operating limits. Treat every “Stop if” condition as a blocked migration, not a suggestion.

Cutover

Developers push to both hosts

criticalpossible likelihood

New commits appear on GitHub after the final mirror starts.

Consequence
Histories diverge and releases use inconsistent source.
Mitigation
Freeze pushes, archive or lock GitHub, and advertise one canonical remote.

Stop if: Any uncaptured GitHub ref advances after the freeze.

CI/CD

CI reaches production with broader credentials

criticalpossible likelihood

Translated jobs use long-lived or unprotected variables.

Consequence
Source or infrastructure compromise.
Mitigation
Rotate secrets, minimize job tokens, protect environments, and test untrusted merge requests.

Stop if: A non-protected pipeline can read a production credential.

Policy

Required merge controls disappear

criticalpossible likelihood

A role account can merge without required approval or checks.

Consequence
Unreviewed code reaches protected branches.
Mitigation
Run explicit negative policy tests.

Stop if: Any forbidden push or merge succeeds.

Data

LFS or release binaries are missing

criticalpossible likelihood

Pointers resolve but binaries fail to download.

Consequence
Builds, releases, or historical checkouts break.
Mitigation
Compare object inventories and checksums.

Stop if: Any production-required binary is unavailable.

Import

Importer rate limits or partial states are ignored

highlikely likelihood

GitLab marks a project partial or reports failed relation types.

Consequence
The project looks available while metadata is incomplete.
Mitigation
Save status details, retry controlled failures, and reconcile all object counts.

Stop if: Any project remains partial without an accepted exception.

06Precise timeline

Do the work in this order.

Estimate forEditorial planning profile, not a vendor limit: one organization with up to 100 repositories and 500 users
Total elapsedEditorial estimate: 15–30 business days
Active workEditorial estimate: 70–130 active hours
BufferEditorial allowance; add 1–3 weeks for complex Actions pipelines, large comment histories, registries, compliance approval, or external integrations. GitLab notes that actual importer duration varies and can be much longer for very large projects.
01
Days 1–4Inventory and target design4 days
02
Days 5–7Mirrors and evidence3 days
03
Days 8–11Pilot representative projects4 days
04
Days 12–20Frozen production imports in waves5–9 days
05
Days 21–23Final reconciliation and control-plane switch1–3 days
06
Days 24–30Read-only observation5–7 days
  1. Days 1–4 · inventory

    Inventory and target design

    18–28 hours active4 days elapsedOwner and security review waiting
    • Inventory repositories, identities, collaboration data, policies, CI/CD, artifacts, and integrations.
    • Create namespace, identity, retention, and freeze plans.

    Depends on: GitHub organization owner and GitLab owner access

    Stop / go checkpoint

    Approve migration waves?

    Go when: Every repository and operational dependency has an owner and method.

    Stop when: A production pipeline, secret consumer, or compliance requirement is unknown.

  2. Days 5–7 · backup

    Mirrors and evidence

    12–20 hours active3 days elapsedClone, LFS, and artifact transfer waiting
    • Create and validate Git, wiki, LFS, asset, and metadata backups.
    • Record source ref and object counts.

    Depends on: Approved inventory

    Stop / go checkpoint

    Can every repository be restored?

    Go when: Mirrors pass fsck and all critical binaries and metadata are accounted for.

    Stop when: A required ref, LFS object, release asset, or wiki is absent.

  3. Days 8–11 · pilot

    Pilot representative projects

    14–22 hours active4 days elapsedImporter and CI runs waiting
    • Import simple, large-history, LFS, release, and complex-CI projects.
    • Validate attribution, policies, pipeline permissions, artifacts, and integrations.

    Depends on: GitLab groups and users, Backups

    Stop / go checkpoint

    Approve bulk import?

    Go when: All critical project archetypes pass data, security, CI, and release checks.

    Stop when: Attribution, protections, binaries, or production rollback cannot be proven.

  4. Days 12–20 · waves

    Frozen production imports in waves

    18–35 hours active5–9 days elapsedGitHub API limits and import queues waiting
    • Freeze each GitHub repository before its production importer run and keep it locked after the import starts.
    • Import projects by dependency wave, complete post-import identity mapping, and reconcile metadata and importer status before advancing.
    • Translate CI, policies, assets, and webhooks while the source repository remains locked.

    Depends on: Approved pilot

    Stop / go checkpoint

    Schedule control-plane switch?

    Go when: Every locked repository is complete or has an approved exception, its metadata ledger is reconciled, and release paths pass.

    Stop when: Any source repository advances, importer partial state remains unexplained, or critical CI fails.

  5. Days 21–23 · cutover

    Final reconciliation and control-plane switch

    5–9 hours active1–3 days elapsedFinal CI and webhook runs waiting
    • Confirm every imported GitHub repository has remained locked since its production import.
    • Reconcile any approved source metadata delta manually; do not rely on Git mirroring to update issues, pull requests, comments, reviews, releases, wiki content, or policy.
    • Mirror the approved final user-ref scope and LFS, rotate secrets, switch webhooks/remotes, then run staged pipelines.

    Depends on: Approved waves, Maintenance window

    Stop / go checkpoint

    Make GitLab canonical?

    Go when: Approved refs match, the metadata-delta ledger is empty, policies reject forbidden actions, and production release/rollback pass.

    Stop when: Any source repository advanced without reconciliation or production controls differ from policy.

  6. Days 24–30 · observe

    Read-only observation

    3–16 hours active5–7 days elapsedDeveloper feedback and scheduled jobs waiting
    • Keep GitHub read-only and monitor clones, webhooks, pipelines, releases, bots, and developer workflows.
    • Complete verification and owner sign-off.

    Depends on: Successful cutover

    Stop / go checkpoint

    Close rollback window?

    Go when: Blocking checks pass across normal and scheduled workflows.

    Stop when: A critical integration still writes to GitHub or a GitLab workflow is unsafe.

07The point of change

Cut over with a way back.

Go live

Cutover

Make GitLab the only writable source and CI/CD control plane while preserving a final verified GitHub snapshot.

Recommended window: A low-release Friday with the final mirror after code freeze and a staffed verification period before Monday.

  1. Confirm every GitHub repository was frozen before its production importer run and has remained locked.
  2. Reconcile any approved post-import GitHub metadata change manually; Git mirroring does not update pull requests or other imported metadata.
  3. Record the approved user-branch, tag, and required fork-branch scope; mirror those final Git refs and LFS and reconcile object counts while classifying provider-owned synthetic refs separately.
  4. Complete GitLab's post-migration contribution and membership mapping and resolve every blocking attribution exception.
  5. Rotate credentials and configure protected GitLab variables, deploy keys, runners, and environments.
  6. Switch remotes, webhooks, apps, registries, badges, documentation, and deployment integrations.
  7. Run protected-branch negative tests and staged build, test, release, deploy, and rollback pipelines.
  8. Keep GitHub repositories locked or archived and show the canonical GitLab URL.

Proof to capture: Final refs match, policy tests pass, all critical binaries resolve, and one complete production release and rollback simulation succeeds from GitLab.

Return to safety

Rollback

Restore GitHub as canonical without discarding GitLab commits or security changes.

Deadline: Within 72 hours and before multiple independent releases or package publications occur on GitLab.

  1. Freeze GitLab pushes, pipelines, releases, and package publication.
  2. Mirror new GitLab refs and LFS objects into a quarantine backup.
  3. Review and push approved new refs back to GitHub.
  4. Restore rotated GitHub secrets, integrations, branch rules, remotes, and deployment controls.
  5. Run GitHub policy and release-path tests before reopening writes.

Proof to capture: GitHub contains all approved refs, rejects forbidden actions, and completes the tested release path while GitLab is read-only.

Rollback immediately when
  • Missing refs, LFS objects, or critical assets
  • Required policy bypass is possible
  • Production pipeline or rollback fails
  • Identity or permission mapping exposes restricted projects
  • Critical integration cannot operate against GitLab
08Verification report

Prove the migration worked.

Every blocking check must pass. Capture the evidence before cleanup begins.

0%
Interactive report preview0 / 8 checks passed
PassIDCheckMethodExpected resultEvidence
V-01BlockingApproved refs and objectsCompare approved user branch and tag tips plus required fork-branch tips, classify provider-owned synthetic refs separately, run fsck, and sample historical checkouts.Exact parity for the approved ref scope and no corrupt or missing required object.Scoped ref diff, namespace classification, and fsck logs.
V-02BlockingLarge-file availabilityCompare LFS inventories and download production-critical objects.Every required pointer resolves to the correct checksum.LFS object report.
V-03BlockingIssues, merge requests, comments, and attributionReconcile counts and inspect representative complex histories.Every object is imported or listed as an approved exception; authorship is explained.Object-count reconciliation.
V-04BlockingMembership and visibilityTest internal, external, bot, and unauthorized role accounts.Least-privilege access matches the approved matrix.Role test matrix.
V-05BlockingProtected workflowAttempt forbidden push, merge, approval, and secret-access scenarios.Every forbidden action fails and required checks block correctly.Negative-test log.
V-06BlockingRelease pathRun build, test, artifact, preview, protected deploy, and rollback scenarios.Outputs and approvals match the accepted pipeline specification.Pipeline URLs and deployment evidence.
V-07BlockingReleases, packages, containers, and wikiReconcile inventories and verify representative checksums and clones.Every retained artifact class is usable from its destination.Artifact manifest.
V-08BlockingExternal eventsTrigger each webhook, bot, scanner, notification, Pages build, and deployment integration.One successful destination event and no production write to GitHub.Integration delivery log.
09Post-migration cleanup

Remove the scaffolding safely.

Safe after: At least two normal release cycles, all scheduled workflows, and 30 days without a rollback trigger.

  1. Preserve mirrors, LFS, assets, manifests, importer logs, identity mappings, policy tests, and verification evidence.
  2. Revoke GitHub PATs, deploy keys, app installations, webhooks, runner tokens, and machine credentials no longer required.
  3. Delete temporary migration tokens and staging mirrors from unsecured machines.
  4. Retain GitHub repositories archived for the approved compliance window before any deletion decision.
  5. Update onboarding, incident response, backup, release, and ownership documentation.
  6. Schedule quarterly restore, access, policy, integration, and dormant-secret reviews.
10Experiences from the field

When the plan met reality.

First-hand accounts are preferred. Vendor case studies are labeled, and every note below is an editorial paraphrase—follow the link for the full context.

First-person accountCaio Andrade · The Startup

We Migrated From GitHub to GitLab2020

Caio Andrade recounts Mercos moving its repositories and engineering workflow from GitHub to GitLab after evaluating price, stability, import tooling, CI, issue boards, dependency updates, and static analysis. The team treated source hosting as only one part of the move because GitHub-integrated services and GitHub Actions behavior also needed replacements. The author specifically recommends archiving source repositories to prevent writes during the cutover.

What they recommend
  • Inventory CI, dependency automation, code analysis, issue tracking, and third-party integrations alongside the repositories themselves.
  • Archive the GitHub repositories at cutover so no new commits or issues appear after the final import snapshot.
Worth noticing
  • The migration decision was driven by an integrated engineering platform rather than the mechanics of copying Git repositories.
  • Pricing changed shortly after the move, reinforcing the value of documenting broader workflow reasons instead of relying on cost alone.
Sources and evidence

Verify against the primary material.

Platform behavior changes. Check these sources and the review dates above before executing a production migration.

  1. GitLab Docs: migrate from GitHubAccessed 2026-07-27
  2. GitLab Docs: troubleshoot GitHub migrationAccessed 2026-07-27
  3. GitHub Docs: back up a repositoryAccessed 2026-07-27
  4. GitHub Docs: export organization migration dataAccessed 2026-07-27