GitLab migration from GitHub, Bitbucket or another GitLab

Moving repositories, merge requests, issues and pipelines onto a self-managed GitLab instance is mostly a planning and cutover exercise. This page explains what the work includes, what drives its cost and duration, and what to confirm before choosing your own team or a partner.

On this page

What a GitLab migration involves

A GitLab migration moves source repositories, merge requests, issues, users and CI configuration from GitHub, Bitbucket Cloud or Server, Gitea, another GitLab instance, or plain Git repositories reached by URL or manifest, into a self-managed GitLab instance that your organization runs in its own infrastructure. The work is rarely one copy operation. Each source system exposes different objects to the importer, each has its own identity model, and each needs a cutover plan that tells developers where work now happens. Teams usually start this work for one of four reasons: a licensing or hosting policy that rules out a hosted service, data residency requirements, consolidation of several tools into one, or the retirement of an existing instance.

The GitLab importers do not carry the same things across. Repository history and branches generally move, but the set of merge request discussions, issue metadata, attachments, CI variables and pipeline history that come across depends on the source and the import method. Direct transfer between GitLab instances carries more than URL-based Git imports, and Subversion needs an external conversion step before import. Before committing to a scope, the migration lead should run a test import of a representative project from each source and compare what arrived against a written inventory. Confirm the current import matrix for each source in the GitLab import documentation, because it changes between releases.

A small team with one or two sources and modest history can often run a pilot import itself, provided it has an administrator who can run imports and a clear rollback plan. Multi-source estates, large histories, identity mapping that ties old authors to new accounts, and regulated cutovers with audit evidence are usually scoped with a partner. In those cases the hard work is in the decisions: which contributions are mapped to which people, how credentials and CI secrets are re-entered, what freezes on the old system during the cutover window, and who signs off that the new instance is the system of record.

What the migration includes

The migration runs as a set of work packages, each with a defined output. The exact set of data that carries over depends on the importer or transfer method used, so confirm it per source before the plan is final.

Source inventory and mapping

We catalog repositories, branches, tags, large files, merge requests, issues, wikis, CI configurations and integrations in the source system, then decide which move, which are archived and which are retired. The output is a mapping sheet that ties each source project to a target path, group and owner. Check early whether any repositories depend on hosted-only features you will not have after the move.

Target instance preparation

Before any data moves, we configure the self-managed GitLab instance with the import settings you need, the group and namespace structure, and a permissions model that mirrors your access policy. Decide early who may create top-level groups and who may import, because these settings shape everything that follows. Confirm that sign-up and import restrictions match your security baseline.

Repository and history transfer

Repositories move with the importer that matches the source, such as the GitHub, Bitbucket or Gitea importer, or a direct transfer between GitLab instances. Each method has its own limits on what history, refs and attachments arrive intact. We run test imports on representative projects and compare commit counts, branches and tags against the source before any bulk run.

Merge request, issue and wiki mapping

Review history, issue threads and wiki pages are mapped only where the chosen importer supports them, so some items may arrive as references or summaries rather than native objects. We document each object type in the validation log and agree with the team how gaps will be handled. Confirm the carry-over set with the importer documentation for your source before you promise it to stakeholders.

User contribution mapping

Imported contributions are attributed to GitLab users only when the source account is matched to a target account, usually by verified email or a supplied mapping file. We build the user map, reassign unmatched contributions to placeholder or owner accounts, and record every decision. Check with HR or identity owners how departed contributors and shared service accounts should be handled.

CI pipeline translation

Pipeline definitions in other systems are rewritten as .gitlab-ci.yml, with variables, secrets, images and environment rules moved to GitLab equivalents. Each pipeline also depends on runners with the right tags, executors and network access, which must exist before the first job runs. Plan runner capacity and secret storage with the pipeline inventory, not after cutover.

Subversion conversion

GitLab does not import Subversion directly, so history is converted with external tools before the result is loaded as Git. Conversion depends on the repository layout, branch conventions and author mapping, and it can change commit identifiers. Agree the conversion rules with the owning teams and test the output on copies, since errors in author or path mapping are hard to undo after the cutover.

Staged cutover with delta sync

Cutover runs in stages: a bulk import, a write freeze on the source for the affected projects, then a delta sync that carries changes made after the first pass. The freeze window and the delta size are the main drivers of downtime, so schedule them with the teams that push code. Verify the final state against the mapping sheet before the source is set to read-only.

Deliverables and runbook handover

You receive a migration report, the mapping sheet, the validation log, updated developer documentation for new repository locations and pipelines, and the runbook for repeating or reversing steps. The runbook is handed to your platform team so they can run later imports without us. Ask for the exact format of each deliverable in the written scope before work starts.

What drives cost and duration

Each row names a factor that changes how much work a GitLab migration takes, why it matters, and what to do to keep it under control.

DriverWhy it mattersHow to keep it down
Number and size of repositoriesEach repository needs its own import run, verification and access check. Large histories and many repositories multiply rehearsal and validation time.Inventory every repository with its size and last activity. Archive or skip inactive projects, and move large history in a separate, scheduled batch.
Number of source systems and versionsGitHub, Bitbucket Cloud, Bitbucket Server, Gitea and older GitLab instances each have their own importer behavior, limits and authentication. Older source versions may need extra steps.Group repositories by source system and rehearse one group at a time. Confirm the importer and source version combination in the GitLab import documentation before scoping.
Merge request and issue volumeMerge requests, comments, reviews and issues carry references, labels and attachments that must map correctly. High volumes increase import time and review of results.Decide which open items must move and which can be closed or linked as archive references. Set a clear cutoff date for in-flight work.
Contribution mapping and identity cleanlinessImported authorship only maps to real accounts when the source email matches a verified user on the new instance. Duplicate or unverified identities leave work attributed to placeholder users.Export the user list from each source early, resolve duplicates and departed staff, and agree the mapping rules with the people who own the identities.
CI/CD complexity and pipeline countPipeline definitions, variables, secrets and runner tags do not move automatically in the same form. Each pipeline needs translation, testing and runner capacity on the new side.Start with a pipeline inventory. Group pipelines by runner need, reuse shared templates, and plan runner setup before cutover. Confirm which secrets must be re-entered by hand.
Subversion or other non-Git sourcesSubversion history needs external conversion tools before it can enter GitLab. Conversion of long or messy histories can take more effort than the import itself.Limit conversion to the history the business needs. Test conversion on a copy of a representative repository and agree the result with its owners before the main run.
Binary files and LFS contentLarge binaries and Git LFS objects increase transfer size, storage and the time to verify. LFS objects may need to be copied separately from the Git history.Measure binary volume per repository. Move large artifacts to the artifact or package store you control and confirm how LFS objects will be transferred.
Compliance evidence requirementsAudit or assessment scope may require records of who moved what, when, and how access was checked. Collecting this evidence after the fact takes longer than planning for it.Define the evidence list before the first rehearsal. Keep import logs, mapping decisions and access reviews in a controlled location. Compliance assessors decide sufficiency, so confirm requirements with them.
Environments and air-gapped operationStaging, production and disaster recovery instances each need configuration and testing. An air-gapped network adds offline package transfer and limits access to external source systems during the move.Plan one repeatable rehearsal environment that matches production. For air-gapped sites, confirm early how source data reaches the isolated network and which transfer method your security team approves.
Number of cutover wavesEach wave adds a freeze window, a delta sync, a communication step and a rollback plan. More waves reduce risk per step but increase coordination work.Group teams by dependency rather than by size. Keep the number of waves small, and use the same runbook for each one.
Tier choice (Free, Premium or Ultimate)The tier does not change how the import works. It affects which features teams rely on after the move, such as advanced CI/CD or security and compliance features, and therefore the configuration and training needed.Decide the tier from the features your teams will use after cutover, not from the import. Confirm current tier features on the GitLab pricing page before the decision.

Migration phases and outputs

A staged sequence that moves repositories, review history and pipelines into self-managed GitLab with a checked rehearsal and a controlled cutover.

  1. Inventory sources and dependencies

    Your team and DeployOpen list every repository, branch rule, merge request, issue, wiki, pipeline and integration on the source system, then flag what GitLab's importers cannot carry over. Ownership of each project is recorded. The closing output is an inventory that the written scope references, and the step is done when the owners of the source projects have signed off on it.

  2. Design target groups, permissions and identity

    Groups, subgroups, project visibility, roles and the identity provider are designed against the inventory, and the user contribution mapping approach is agreed so that imported comments and merge requests attribute to the right people. DeployOpen drafts the structure; your identity and security owners approve it. The output is a target design document and the mapping sheet of source users to GitLab accounts.

  3. Run a pilot import of representative projects

    A small set of projects that cover the awkward cases, such as large histories, LFS objects, many merge requests, unusual branch names and heavy CI use, is imported with the built-in importers or direct transfer. Each result is compared against the source. The pilot report lists what arrived intact, what was partial and what needs a workaround, and the step closes when that report is accepted.

  4. Map pipelines and translate CI configuration

    Source pipeline definitions are rewritten as GitLab CI/CD configuration, secrets are re-entered through protected variables, and runners are matched to the jobs that need them. Where a source system used a plugin or external tool, the replacement is recorded. The output is a mapping sheet linking each source pipeline, its target job, its runner tag and its open issues, and the step is done when a test pipeline passes on the target.

  5. Rehearse the full import and validate

    The complete migration runs against a non-production instance on the same schedule and steps planned for cutover. Repository counts, commit hashes, branch protections, merge request states, user mappings and pipeline results are checked with a written validation list. Every failure is logged with its cause and fix. The rehearsal log is the record that the cutover plan is trusted, and the step closes when a clean run is recorded.

  6. Execute a staged cutover with freeze and delta sync

    Teams are told when writes to the source stop, the freeze window opens and the final import captures changes made since the earlier passes. Access to the old system is then restricted and the new system is opened to developers. The cutover record notes times, operator, validation results and any exceptions. Timing is set in the written scope, not assumed here.

  7. Harden the target and decommission the source

    After cutover, the new instance is hardened against the agreed baseline, backups are verified with a restore test, and integrations are repointed. The source is kept read-only for an agreed period, then archived and shut down once no dependency remains. The decommissioning checklist records access revocation, data retention copies and sign-off, and the migration closes when that checklist is complete.

What stays in-house and what to outsource

This table shows which parts of a GitLab migration your own people should keep and which parts a partner can usually take on, with the skills each part requires.

Work partUsually kept in-houseUsually outsourcedSkills required
Repository ownership and retirementDeciding which repositories move, who owns each one after import, and when old GitHub, Bitbucket or GitLab projects are archived or made read-onlyPreparing an inventory report of repositories, sizes, branches and last activity to support those decisionsEngineering management, repository governance, knowledge of team structure
Project validationDevelopers checking that code history, branches, tags, merge requests and issues arrived intact and that their workflows still functionWriting reconciliation checks that compare counts and references between source and target, and logging the discrepancies foundHands-on Git and GitLab use, familiarity with each project's build and review practices
User and identity mappingIdentity and access owners approving which source accounts map to which GitLab users, and deciding how contributions are attributedBuilding mapping scripts or CSV templates, running dry-run comparisons and reporting unmatched accountsDirectory administration, SSO and SCIM concepts, privacy and attribution rules
CI pipelines and runnersCI owners rewriting or approving pipeline definitions, secrets and variables, and deciding which runners will execute jobs after cutoverHelping convert pipeline definitions where needed and setting up runner capacity or images on requestCI/CD design, runner operations, secrets handling, container image management
Target instance platformPlatform engineers owning the self-managed GitLab instance, its sizing, backups, upgrades and access policies after go-liveInstalling and configuring the instance, applying hardening and documenting the build, with ongoing support available under a retainerLinux administration, PostgreSQL and object storage basics, backup and restore practice
Import execution and toolingApproving the import order, timing and rollback criteria, and receiving the migration logsRunning the built-in GitHub, Bitbucket, Gitea and GitLab transfer tools, writing automation for bulk imports and converting Subversion history with external tools where neededScripting against GitLab and source platform APIs, Git internals, troubleshooting large imports
Rehearsal and cutover runbooksBusiness owners signing off on the cutover window, freeze rules and go or no-go decisionDrafting the staged runbook, running at least one rehearsal on a copy of the data and documenting timings and failure handlingChange management, incident response, runbook writing, cross-team coordination
Source system shutdown and link updatesTeams updating local remotes, webhooks, deploy keys and external links that point to the old platformListing webhooks, integrations and API consumers found in the source system so the owners can update themIntegration inventory, webhook and token administration, communication with dependent teams

What usually goes wrong

Most GitLab migrations that stall or lose data do so for a small set of predictable reasons. Each card names one failure mode and the step that prevents it.

Importers skip items silently

The built-in importers for GitHub, Bitbucket and Gitea move repositories, merge requests, issues and some CI data, but not every object type carries over the same way. Teams often assume wikis, releases, attachments or certain review comments moved when they did not. Run a rehearsal import, then compare object counts per project against the source using a written inventory of what must move.

Contributions attributed to placeholder users

When an imported author cannot be matched to an existing GitLab account, history is attributed to a placeholder user instead of the original person. This affects blame, review history and audit trails that auditors may sample. Review the user mapping before the final import, and decide in advance who approves mappings that cannot be matched automatically.

Usernames and emails that do not match

Mapping depends on matching source identities to GitLab accounts, and mismatched usernames or email addresses block that step. People who changed employers, renamed accounts or used personal addresses in commits are the usual cases. Export the source user list early, reconcile it against your identity provider, and agree on a rule for contributors who have left the organization.

Large or LFS-heavy repositories time out

Repositories with long histories, large binaries or Git LFS objects can exceed import time limits or fail partway through, and LFS objects need their own transfer path. Identify the largest repositories during planning, test them separately in the rehearsal, and confirm how LFS content is moved and verified on your instance and storage backend.

CI definitions waiting on runners and secrets

Imported pipeline definitions run only when a matching runner exists with the right tags, and variables or secrets used by jobs are not always carried over. Pipelines then fail or sit in a pending state on cutover day. Register runners and tags before cutover, recreate protected variables in your secrets store, and run a pipeline for each critical project in the rehearsal.

Webhooks and integrations still point at the old source

Chat notifications, deployment triggers, issue trackers and scheduled jobs often reference the old host or hold tokens tied to the old system. After cutover they stay silent or keep building the wrong code. Build an inventory of webhooks, integrations and service accounts for each project, repoint them during the cutover window, and confirm each one fires a test event.

Subversion history lost in conversion

GitLab does not import Subversion directly, so teams rely on external conversion tools, and the converted history can differ from the original in branch layout, tags, author names or ignored properties. Decide which history must be preserved, convert a sample repository in the rehearsal, and sign off the converted output with the teams who depend on it before retiring the Subversion server.

Cutover without a write freeze

If developers keep pushing to the old system after the final import, commits land on a source that no longer reflects the new state. Reconciling those changes by hand is error prone. Set a freeze window on the old system, run a final incremental sync after the freeze starts, and use a post-cutover checklist to confirm no new commits arrived after the cutover point.

Instance hardening and backups missing at go-live

A migrated project is only as safe as the instance it lands on. Teams sometimes import data before backups, restore testing, access controls and the runner and secrets setup are in place, so the first production change has no recovery path. Make a backup and restore test a go-live gate, and document who can approve the cutover.

How the work changes by starting point

GitLab includes built-in importers for GitHub and Gitea, so most of the effort goes to credentials, user mapping and checking what each import leaves behind. Run a test import on a sample group before you move the full list.

  • Importer path: the built-in GitHub or Gitea importer, started from the new project menu, using a token that can read the source projects.
  • Typically carried over: repository history and the issue and pull request content the importer supports. Confirm in your pilot which review comments, labels, milestones and attachments arrive.
  • Needs rebuilding: GitHub Actions workflows cannot run unchanged on GitLab, so translate them into .gitlab-ci.yml and provide runners. Webhooks, GitHub Apps and repository secrets are recreated by hand.
  • User mapping: authors are matched to GitLab users by username or email. Confirm how your identities line up with your identity provider before cutover, because unmatched authors keep placeholder attribution.

What you need to provide

Before work starts, the client supplies a target GitLab instance with an installation method agreed in writing, plus admin access to it. The installation method decides how the instance is built and patched, so confirm it early with the platform team that will run it. Each source system (GitHub, Bitbucket, Gitea or another GitLab) also needs a service account with read access to every repository in scope, and an owner who can approve changes to that account's permissions.

Next, supply an inventory of repositories and their owners, including who holds maintainer rights and which projects are archived or abandoned. Decide which history and items must move: full Git history, branches and tags, merge requests, issues, wiki pages, releases and attachments. Each item type has different import behavior, so a written decision here prevents rework later. Name who signs off on that list, because it sets the scope of the migration.

For contribution mapping, provide the identity source and a user list that matches source accounts to people, with the email addresses each person uses. Decide whether mapping happens by verified email or by manual review, and name the person who resolves unmatched accounts. Also provide the CI inventory: which pipelines, variables, and secrets exist, and which runners are available in the target network. Confirm runner capacity with the team that owns it, since jobs will need runners as soon as pipelines are re-enabled.

Finally, name the people who make the cutover decisions. Provide change windows agreed with operations, a freeze owner who can stop merges on the source during the final sync, and named decision-makers who approve retirement of each old source. Retirement should not start until the decision-makers have confirmed that teams no longer depend on the old system. Confirm these roles in writing before the first test import.

Frequently asked questions

Can our own team migrate repositories to self-managed GitLab without a partner?

Yes, many teams do the work in-house, and the deciding factors are capacity, history volume and risk tolerance. The built-in importers for GitHub, Bitbucket and Gitea, and the direct transfer between GitLab instances, cover the common cases. Your team needs someone who owns the target instance, knows your branch protection and CI setup, and can run a rehearsal before the cutover date. Ask the partner for a written scope that lists which of these tasks they would take on, so you can compare it with your own staffing plan.

What drives the cost of a GitLab migration project?

The main cost drivers are the number of repositories and users, the volume of merge requests, issues and CI configuration, the number of source systems, and any non-Git history that needs conversion. Fixed-scope projects are priced from a written scope, so there is no public price list to quote from. Ask for a quote that separates one-time work (planning, mapping, rehearsals, cutover) from any recurring retainer for support or upgrades, and that states what the client must provide, such as admin access and a named approver.

How long does a migration take, and what sets the schedule?

Duration depends on the number of repositories, the size of the largest histories, how much review and issue history must follow the code, and how many CI pipelines need rework. Access approvals, the availability of key developers for user mapping and the number of cutover windows also shape the timeline. Ask for a schedule with explicit dependencies, a rehearsal stage and a freeze window, and confirm which milestones the written scope commits to.

Does GitLab import merge requests and issues from GitHub or Bitbucket?

GitLab's import documentation lists GitHub, Bitbucket Cloud and Server, and Gitea as sources for its built-in importers, and these importers can bring over more than repository content, but you must confirm which object types each importer carries for your version and source. Test this on a sample project before planning the full migration. Jira and FogBugz issue imports are also documented separately. Check any gaps, such as attachments, review comments or CI variables, against the import documentation for your target GitLab version.

Can Subversion history move into GitLab, and how do contributors map to users?

Subversion is not imported directly by GitLab, so it needs an external conversion tool, and the conversion has to be tested for author mapping, branch layout and tags before any cutover. Contributor mapping links historical commit author names and emails to GitLab user accounts. Plan this with the people who know the contributor list, decide how departed or external authors are represented, and confirm that commit authorship is preserved in the target instance.

What happens to CI pipelines and cutover with no lost commits?

Imported repositories do not automatically run CI as the source system did, so pipeline definitions, runners, variables and secrets must be reviewed and rebuilt in GitLab CI/CD. For cutover, the usual approach is a short write freeze on the source, a final sync of refs and a verification that commit counts, tags and default branches match. Ask the partner to show the verification checklist, the rollback path and who signs off, and confirm these steps in the written scope.

How DeployOpen delivers GitLab migrations

DeployOpen plans and runs GitLab migrations from GitHub, Bitbucket or another GitLab instance onto a self-managed GitLab you operate in your own infrastructure. The work moves repositories, merge requests, issues and CI configuration through a staged cutover with user contribution mapping checked before go-live.

How we scope

  • The written scope lists which repositories, merge requests, issues and pipeline configurations move, and which stay behind as archives.
  • Source system inventory covers projects, groups, users, large files, integrations and any Subversion repositories that need external conversion.
  • Scope sets the target GitLab edition, reference architecture and whether Runners are migrated or rebuilt on the new instance.
  • Engagements are fixed-scope, so scope, deliverables and timelines are agreed in writing before migration work starts.

How we build

  • Migration rehearsals run on a test instance using the GitHub, Bitbucket, Gitea or GitLab import path that fits each source.
  • User contribution mapping links commits, comments and merge requests to the correct GitLab accounts before the production import.
  • CI/CD configuration is reviewed for runner tags, protected variables and secrets so pipelines run on the target instance without manual repair.
  • Each rehearsal is checked against an agreed list of repository, issue and merge request counts, with differences documented and resolved.

How we hand over

  • Cutover runbook records the freeze window, final sync, DNS or remote changes, rollback steps and the owner of each step.
  • Documentation covers the configured instance, backup jobs, restore procedure and the upgrade stops your team must plan for.
  • Handover includes a walkthrough with administrators and a list of source systems to decommission or set to read-only after cutover.
  • Acceptance criteria in the written scope define what counts as a completed migration before the project closes.

How we support

  • Ongoing support, upgrades and continuous testing are available as retainers after the migration closes.
  • Post-cutover support covers reconciling late-arriving issues, fixing mapping gaps and answering questions from teams during their first weeks.
  • Retainer support can include planned GitLab upgrades that pass through required upgrade stops, rather than ad hoc version jumps.
  • Ask in your quote which post-cutover support is included, how long it runs and how requests are prioritized and recorded.

Sources and further reading

Talk to our team.

Tell us what you're working on, whether it's a deployment, an audit, a security test or a cyber range. You'll speak with an engineer who can help you scope it.

  • 30-minute call: free, with no obligation.
  • NDA on request: we can sign before you share details.
  • Clear next steps: a scope and plan after the call.