Migrate from Bitbucket Server or Data Center to GitLab

Moving from Bitbucket Server or Data Center to self-managed GitLab is mostly a planning exercise around users, permissions and cutover order. This page explains the documented import paths, what does not carry over, and how to sequence a large repository estate.

On this page

Migrating from Bitbucket Server to GitLab: what the move involves

Moving a Bitbucket Server or Data Center estate to self-managed GitLab is a planned migration of several kinds of data, not a bulk copy of repositories. The short answer for most teams is that the Git history is the easiest part to move, and the work that decides duration is everything attached to it: users, pull request history, permissions, pipelines and runners. Scope sets duration, so the first task is an inventory of how many projects, repositories, users and pipelines are in use, and which of them are still active. Confirm the import path for your Bitbucket version and deployment with GitLab's import documentation before estimating anything, because the importer's coverage of Bitbucket Server data determines what you will rebuild by hand.

The data that needs decisions is the part teams underestimate. Pull requests, comments and approvals may come across with their authors recorded as placeholder users, so you need to decide how many contributors must be matched to real GitLab accounts and who will confirm each match. Permissions do not map one to one: Bitbucket projects, repository permissions and default reviewers have to be translated into GitLab groups, project roles and merge request approval rules, and the mapping should be written down before the import starts. Confirm with your identity team how accounts will be created, since GitLab sign-in through your corporate identity provider affects who can be matched and who can be given access during cutover.

Pipelines and runners are a separate workstream that will not finish when the repositories do. Bitbucket Pipelines configuration, build agents, deployment variables and any secrets must be rebuilt as GitLab CI/CD and runner configuration, and the runner fleet has to be provisioned in infrastructure you control before the first job runs. Plan the cutover order around this: move low-risk repositories first, keep Bitbucket read-only for each batch, and give each team a clear date after which new work goes to GitLab. Ask any partner for the inventory method, the mapping of users and permissions, the pipeline rebuild plan and the rollback steps in the written scope before work begins.

Which Bitbucket Server features map to GitLab and which need rework

This table compares common Bitbucket Server or Data Center features with their GitLab equivalents and shows where rework is likely. Use the third column to plan which items to verify in the current GitLab importer documentation for Bitbucket Server, which to rebuild by hand, and which to schedule after cutover.

Bitbucket Server featureGitLab equivalentImport or rework
Git repositories, branches and tagsProjects with Git repositories, branches and tagsRepository history is the core of the import. Confirm how large or LFS-tracked repositories are handled for your version.
Pull requests and commentsMerge requests and threaded discussionsConfirm which pull request fields, comments and approvals the importer maps. Plan to close or merge open pull requests before cutover.
Project and repository permissionsGroup and project roles, from Guest to OwnerRebuild manually. Set roles from your access model after the import, not from the source defaults.
Users and groupsUsers, groups and placeholder usersAuthors arrive as placeholders until someone claims them. Plan reassignment as a separate step.
Bitbucket PipelinesGitLab CI/CD pipelines defined in .gitlab-ci.ymlRebuild manually. Pipelines do not convert automatically, and Pipelines is a Bitbucket Cloud feature, so confirm which CI system your Server sites use.
Bamboo or external CI buildsGitLab CI/CD jobs run by GitLab RunnerRebuild manually. Map plans, agents, triggers and secrets to jobs, runners and CI/CD variables.
Webhooks and service hooksProject webhooks and pipeline triggersRebuild manually. Recreate endpoints and secrets, and disable old hooks to avoid double processing during cutover.
Attachments, wikis and linked Jira issuesIssue attachments, wiki pages and GitLab integrationsConfirm attachment and wiki transfer in the importer documentation. Plan a separate copy and reconfigure integrations where they do not come across.

Documented import paths for Bitbucket Server projects

GitLab offers several documented routes for bringing Bitbucket Server or Data Center content into a self-managed instance. Each route fits a different slice of the work, from a few projects to hundreds of repositories, and each has limits that shape the cutover plan. Confirm the current importer behavior and prerequisites in the GitLab import documentation before you commit to a path.

GitLab Bitbucket Server importer

The built-in importer is the first path to evaluate for projects hosted on Bitbucket Server or Data Center. It brings over repositories along with supported metadata such as issues and pull requests, which makes it the natural choice for teams that want review history in GitLab. Confirm which objects the importer supports in your GitLab version, how it authenticates to Bitbucket, and how it treats attachments, comments and user identities before you run a test project.

Git import by URL or manifest

When the built-in importer cannot handle a project, a plain Git import by repository URL is the fallback. It moves the Git history and branches but leaves behind review discussions, issues and most Bitbucket metadata. A manifest-based import can be used to queue many repositories in one run. Plan a separate record of what was lost, and confirm that the manifest format and credential handling match your GitLab version.

GitLab API for scripted bulk creation

The GitLab REST API lets you create groups and projects in a repeatable script, which suits estates with hundreds of repositories that follow a naming and permission model. Scripts can set visibility, default branches and group membership from a reviewed inventory. The API does not replace the importer for content, so pair it with a clear mapping file. Test the script against a staging instance and keep its output as part of the migration record.

File export and direct transfer

Direct transfer and file export move groups and projects between GitLab instances, not from Bitbucket. They matter when a team first lands on a GitLab instance and later consolidates, or when a project is relocated after cutover. Direct transfer requires an administrator to enable the feature and the source and target instances to be compatible. Confirm the version alignment and the known gaps for your release before you plan any second move.

Limits that shape the choice

Every path has boundaries, and most surprises come from assuming one path covers everything. Pull requests, comments, attachments, permissions and CI configuration are the usual gaps, and they differ by path. Build a matrix that lists each object type in your Bitbucket estate, the path that carries it, and the owner who verifies it. This matrix is the input to the cutover sequence and to the decision on whether a second tool is needed.

How user contributions map from Bitbucket Server to GitLab

Imported authors and reviewers arrive in GitLab as placeholder users, not active accounts, so every Bitbucket Server contribution needs an owner decision before cutover. A placeholder is created for each historical author that GitLab cannot match to an existing user, and the commits, comments and approvals stay attached to it until someone reassigns them or the person claims the placeholder. In a small migration this is a handful of clicks. Across thousands of repositories and years of pull request history, the number of placeholders can grow into the hundreds or more, and reviewing them during a cutover window becomes the bottleneck. Confirm the placeholder behavior and any limits for your GitLab version in the GitLab import documentation before you size the work.

Plan identity before the import starts, not after. Export the user list from Bitbucket Server, including usernames and email addresses, and compare it with the accounts your identity provider holds in Entra ID, Okta, Google or an LDAP directory. Provision the matching accounts through SAML, LDAP or SCIM so that people already exist in GitLab when the import runs. Matching typically depends on the email address on each account, so check how your GitLab version matches users and whether shared, renamed or service accounts in Bitbucket Server will match at all. Name one migration owner, usually the platform team, to run reassignment, with project owners approving reassignments for their own repositories and security or compliance signing off on unmatched accounts.

Decide the policy for unmatched users in advance. The usual options are reassigning the contribution to an existing account, leaving it under a placeholder for former employees or external contractors, or deferring the decision until the person claims it. Reassignment changes how the contribution is displayed in GitLab, so record every decision in a mapping file that you export before cutover. Keep the Bitbucket Server backup available in read-only form, and confirm with your auditors which evidence they need, such as original author names and timestamps in commit history, the mapping file and the date of each reassignment. Do not reassign on name similarity alone, because a wrong match rewrites attribution in a record that someone may later need to explain.

Sequencing a large Bitbucket Server cutover to GitLab

This sequence moves a large Bitbucket Server estate into self-managed GitLab in gated stages, so each phase proves a specific thing before the next one starts and the final switch happens only after the pilot and parallel run have held up.

  1. Inventory projects, repositories, pull requests and pipelines

    Your team, with DeployOpen if you engage us, exports a complete list of Bitbucket Server projects and repositories, including size, last activity, open pull requests, branch protection rules, webhooks, and every pipeline or external CI system that reads from each repository. Tag each item as migrate, archive or retire. Confirm which Bitbucket items the GitLab importer does not carry over, such as certain pull request details and CI configuration, by checking the current import documentation rather than relying on assumptions. The step is done when every repository has an owner and a disposition, and the list is signed off by the people who run the work.

  2. Design groups, permissions and identity mapping

    Map Bitbucket projects and permission schemes onto GitLab groups, subgroups and project roles, and decide which teams get Maintainer, Developer or Reporter access. Agree how Bitbucket users will be matched to GitLab accounts, since contributions from imported history are attributed through placeholder users that a person must claim after import. Confirm your identity source (for example SAML, LDAP or SCIM, as supported by your GitLab tier) so accounts exist before the pilot. The step is complete when a written group model and a user-matching list exist and the security owner has approved the visibility defaults.

  3. Run a pilot with representative projects

    Import a small set of projects that cover the hard cases: a large repository, one with long history, one with many pull requests, one with branch protection, and one tied to an existing pipeline. Compare commit counts, branches, tags, pull request titles and comments, and file contents against the source. Have a developer from each team review their imported project and claim their placeholder user. Record every gap as a defect, a manual task or an accepted loss. The pilot is finished when the gap register is agreed and the team leads accept the import quality in writing.

  4. Rebuild pipelines and run both systems in parallel

    Recreate CI/CD for pilot repositories in GitLab, and point runners at the correct environments. Run both Bitbucket Server and GitLab for a defined period, with each repository assigned a single system of record, so teams never push the same change to both. Track which system owns each project, and route webhooks and deployment triggers deliberately. Verify that builds on GitLab match or improve on Bitbucket results and that runners are patched and aligned with the GitLab version. The step is complete when every pilot project has run through a normal release cycle with no ownership disputes.

  5. Schedule waves and import the remaining estate

    Group the remaining repositories into waves by team or dependency, starting with low-risk projects. Run the import for each wave, apply the same verification checks used in the pilot, and close placeholder assignments before moving on. Confirm that the GitLab instance has capacity for the number of users and API load you expect by checking the published reference architectures against your sizing. Each wave is done when its checks pass and its owners confirm the system of record has moved.

  6. Freeze writes on Bitbucket Server and cut over

    Announce a change window, then block pushes and pull request changes on each repository in Bitbucket Server. Run a final incremental import, verify the last commits and open pull requests, update remote URLs, webhooks and CI triggers, and reopen the repositories for writes in GitLab. Keep the Bitbucket Server instance read-only and retain a verified backup of it. The cutover is complete when developers can push to GitLab, deployments run from GitLab pipelines, and no writes appear on Bitbucket Server after the freeze.

  7. Decommission Bitbucket Server after retention checks

    Once the retention and audit requirements agreed with compliance are met, remove Bitbucket Server integrations, revoke access tokens and service accounts, and archive the final backup in storage you control. Confirm with your compliance owner which evidence of the migration must be kept and where it is stored. Document the decommission in your change records and close the project. The step is done when the server is shut down or archived, no integrations still point to it, and the retained backup has been verified for restoration.

What drives the cost and duration of a Bitbucket Server move

This table lists the factors that change the effort of moving from Bitbucket Server or Data Center to self-managed GitLab, with what raises or lowers each one and what to ask for in a quote. Read each row as a question to answer about your own estate before comparing proposals. The main takeaway is that repository count, pull request history, user mapping and pipeline rebuilds usually matter more than the import itself.

DriverWhat raises or lowers effortWhat to ask for in a quote
Repositories and history sizeMany repositories and large Git histories with binaries raise import time and retry work. A clean inventory with archived or abandoned projects removed lowers it.Itemized inventory by project key, repository count, total size and largest repositories, plus the import sequence and retry handling.
Active pull requests and comment historyOpen pull requests and long review threads need mapping and verification. Closing or archiving stale pull requests before the move lowers effort.Whether pull requests are imported, how comments and reviewer assignments are carried over, and what is left as a manual record.
Users needing contribution mappingEach Bitbucket account must match a GitLab user or a placeholder. Inconsistent emails, departed staff and service accounts raise the work.How placeholders are created and reassigned, who approves mappings, and how the user count is capped or staged.
Permission model complexityProjects, groups and per-repository access rules that do not map cleanly to GitLab groups and roles add design and review time.A permission mapping table from Bitbucket projects and groups to GitLab groups, roles and project memberships, with sign-off steps.
Pipelines and Bamboo-linked buildsBitbucket Pipelines files and Bamboo plans must be rewritten as GitLab CI/CD and matched to runners. Many unique pipelines, custom images and deployment secrets raise effort.Count of pipelines by type, which need rewrite versus retirement, runner plan, and how CI/CD variables and secrets are migrated.
Issue tracker and chat integrationsJira links, build status hooks, chat notifications and webhooks each need reconfiguration or replacement. Few integrations keep the work small.A list of every integration, the target GitLab equivalent, and which ones are tested before cutover.
Parallel run and cutover sequencingRunning Bitbucket and GitLab side by side for teams or repositories adds sync, freeze and communication work. A single cutover window is simpler but needs a rollback plan.The cutover model (wave-based or single window), freeze rules for writes, the rollback procedure and the verification checklist per wave.
Self-managed GitLab readinessAn instance that is not yet sized, backed up or hardened adds platform work before any import. A ready instance with tested backups lowers risk and rework.Whether the quote includes instance readiness work or assumes an existing, sized and backed-up GitLab environment.

What usually goes wrong in Bitbucket Server to GitLab migrations

Most Bitbucket Server to GitLab problems are not technical failures of the importer. They come from assumptions about what moves, who owns imported history, and how long old and new systems run side by side. Each card below names one risk and the check that prevents it.

Placeholder users left unassigned

Imported comments, reviews and commits are attributed to placeholder users until someone maps them to real GitLab accounts. If those mappings are skipped, the audit trail shows work by accounts that do not correspond to any employee. Before the import, export the list of Bitbucket users who authored content and confirm each one has a GitLab account or a planned mapping. Decide who approves reassignments and record that decision.

Permissions recreated incorrectly

Bitbucket Server project and repository permissions do not map one to one onto GitLab group, project and role settings. Teams that rebuild access by hand often grant broader rights than before, or leave a group without write access it needs. Write the target access model for each project group first, then compare it against the imported result for a sample of repositories in each business unit.

Pull request history assumed to carry over

Teams often expect every pull request, review thread and approval to appear in GitLab as it did in Bitbucket. Confirm with the importer documentation which pull request data is brought across and which is not, and test one representative project end to end. Agree in writing whether open pull requests will be merged, closed or recreated before cutover, and keep Bitbucket read-only for the archive.

Pipelines assumed to migrate

Bitbucket Pipelines definitions, repository variables and deployment settings do not become working GitLab CI/CD pipelines by importing the repository. Each pipeline must be rewritten as .gitlab-ci.yml and tested on a GitLab Runner that you operate. Inventory every pipeline and its secrets before cutover, and list which teams own the rewrite and the runner capacity that will execute the jobs.

Large repositories timing out

Repositories with long histories, large binaries or many branches can fail or stall during import, especially when run in bulk. Identify the largest repositories from the Bitbucket Server instance before starting and run them in separate, monitored batches. Plan a retry path for each failure and check that the GitLab instance has enough disk and resources for the imported Git data.

Developers pushing to the old system

During a parallel run, some developers keep pushing to Bitbucket Server because the cutover date is unclear or a pipeline still points there. Those commits then diverge from GitLab and must be reconciled by hand. Announce a freeze date, switch Bitbucket repositories to read-only at that point, and confirm that no CI jobs, webhooks or deploy scripts still reference the old remote.

Questions buyers ask before moving Bitbucket Server to GitLab

What drives the cost of moving from Bitbucket Server to GitLab?

The cost depends mostly on the number of repositories, the volume of pull request and issue history you need, how many pipelines must be rebuilt, and how much access control and identity work sits around the move. Each of these creates a separate line of work, so ask for a quote that lists them individually. Your GitLab subscription is a separate, recurring cost. The GitLab pricing page lists Free at 0 dollars and Premium at 29 US dollars per user per month billed annually, with Ultimate custom priced, and all three tiers are available for self-managed installations. Confirm current terms with GitLab before budgeting.

How long does a Bitbucket Server to GitLab move usually take?

Duration depends on repository count, history size, the number of projects that need a clean cutover, and how many pipelines are rewritten. Small instances with a handful of projects move far faster than large estates that need sequenced waves. The most useful planning step is a written inventory of projects, owners and CI dependencies, which turns a vague estimate into a schedule. DeployOpen agrees timelines in writing as part of a fixed-scope plan, so ask for milestones tied to that inventory. Do not accept a duration that was not built from your inventory.

What does our team need to provide for the migration?

Expect to supply access to the source Bitbucket Server or Data Center instance with an account that can read every project, a list of owners who can approve each wave, and the target GitLab environment with its identity provider details. You will also need someone who decides which repositories, branches and issues are in scope, and who can confirm user identities. Ask the provider to list these inputs in the written scope so that decisions are not made late in the cutover window.

Can our own platform team run the migration without a partner?

Yes, many teams do, especially when the repository count is modest and they already operate Linux infrastructure. The GitLab import documentation covers importing from Bitbucket Server, so the mechanics are documented. The harder parts are sequencing, user mapping at scale, rebuilding pipelines and verifying results for each project. Weigh your team's capacity against the number of waves and the regulatory evidence you must keep. A partner is most useful when the cutover must be sequenced across many teams while normal development continues.

How are users and contributions handled after the import?

Imported contributions are attached to placeholder users until someone with the right identity claims them, so the mapping process matters as much as the data copy. Plan which people will be matched to existing GitLab accounts, how external contributors are handled, and how many placeholder users your instance and plan can handle for a large migration. Confirm the current placeholder behavior and limits in the GitLab documentation for your version before you start. Identity sign-in should be settled first, because accounts that do not exist yet cannot claim their history.

Do Bitbucket Pipelines move to GitLab automatically?

No. The repository importer does not rewrite Bitbucket Pipelines into GitLab CI/CD, so each pipeline must be rebuilt as a .gitlab-ci.yml configuration and tested against runners you operate. Secrets, deployment variables and build images also need to be recreated with the right protection levels. Start by listing which pipelines are critical, then rebuild them in the same order as the repository waves. Confirm the rebuilt pipelines produce the same artifacts and deployments before you retire the old ones.

What changes for developers after the cutover?

Developers change their remote URLs, learn the GitLab merge request flow, and use a new CI/CD configuration and runner set. Local clones keep their history, but any scripts, links, webhooks and branch protection rules that pointed at Bitbucket need updating. Plan a short freeze window per project, publish a clear checklist and provide a fallback path for the first days after cutover. Ask for a training and support plan that covers these changes so that delivery teams are not blocked while the old system is still accessible.

Choosing the GitLab tier and deployment before the import

The target edition and install method should be settled before any Bitbucket Server or Data Center project is imported, because both shape what the import can be checked against and what runs after cutover. GitLab Free costs nothing, Premium is listed at 29 US dollars per user per month billed annually according to the GitLab pricing page, and Ultimate is custom priced. Premium adds advanced CI/CD and priority support, while Ultimate adds application security testing, software supply chain security, vulnerability management and compliance features. Confirm which of these your teams will use on day one, because pipelines and security features that depend on a tier cannot be validated on a lower one. Ask the vendor for a written quote that states the seat count, the billing term and what happens when users are added mid-term, since the Premium price is per user and placeholder accounts created by the import may count toward your planning.

The install method is the second decision. The Linux package is the most mature and scalable option according to GitLab's installation methods page, and it bundles PostgreSQL, Redis and Sidekiq. The Helm chart, the GitLab Operator, Docker and source installs are also documented. Pick the method that your platform team can patch, back up and restore on a fixed schedule, because an import rehearsal is only useful if it runs on the same stack you will operate. Check the reference architecture for your expected user count and API load before you size the target, since the docs generally recommend a high availability strategy at 3,000 or more users.

If the Bitbucket Server or Data Center environment sits in an air-gapped or offline network, plan that separately. GitLab documents offline environments, and it provides separate guidance for its security scanners and for GitLab Duo Self-Hosted in those settings. Confirm how packages, container images and scanner data will reach the target network, who approves each transfer, and whether the import itself needs network routes back to the Bitbucket source during the cutover window. Settle these questions first, because they determine whether the import runs from a connected staging network or from inside the restricted zone.

How DeployOpen works on this

DeployOpen plans, builds and hands over the move from Bitbucket Server or Data Center into self-managed GitLab inside infrastructure you control. Engagements are fixed-scope, with the repositories, user mapping, cutover sequence and deliverables agreed in writing before work starts.

How we scope

  • Inventory repositories, projects, pull requests, attachments and users to define which Bitbucket data moves and which stays behind
  • Agree in writing how Bitbucket Pipelines, permissions and integrations are handled, since these are not part of the importer output
  • Confirm the target GitLab edition, instance sizing and runner capacity the cutover will depend on before a quote is issued

How we build

  • Run trial imports against a copy of representative projects and record what arrives, what fails and what needs manual handling
  • Build the user mapping file and reassignment steps so contributions are attributed to the right people before production import
  • Test the cutover sequence in a staging GitLab instance, including freezes on Bitbucket writes and DNS or remote changes

How we hand over

  • Document the import runbook, mapping decisions, exceptions and a verified list of migrated repositories and their owners
  • Deliver a rollback and post-cutover checklist, so your team can confirm results and act on issues without our involvement
  • Walk your administrators through the GitLab configuration, backups and runner setup that the migration depends on

How we support

  • Provide post-cutover assistance within the agreed scope for issues found once teams start working in GitLab
  • Offer ongoing support, upgrades and continuous testing as a retainer after the move is complete
  • Keep the migration record and evidence in your environment so your change management and audit teams can review it

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.