Skip to content

Software companies

Migrating between GitHub, GitLab and Bitbucket: keeping pull request review history

By SourceX Editorial · Updated

Short answer

When you migrate between GitHub, GitLab and Bitbucket, git history moves cleanly but pull request review history depends on the importer. Descriptions and comments often transfer, while approvals, review states, inline comment positions, CI results and user identities are frequently lost or altered. Archive every pull request through the source platform's API before switching the old platform off.

Key takeaways

  • A git clone carries commits, branches and tags, never pull requests or review threads.
  • Importer coverage differs by source, destination and edition, so test one repository and compare counts.
  • Inline review comments can lose their position when the new platform rebuilds the diff.
  • Map users before importing, or review history may be attributed to a single migration account.
  • Keep an API export of pull requests, comments, reviews and statuses as a read-only archive.

What does a repository migration actually move?#

A repository migration moves two different layers, and only one of them lives in git. The git layer, meaning commits, branches and tags, travels with any mirror clone or push. The platform layer, meaning pull requests, review comments, approvals, status checks and links, lives in the hosting platform's database and moves only if an importer carries it.

The table shows how each record typically behaves. Treat it as a checklist for your test import rather than a description of any specific tool, because importer coverage varies by direction and changes over time.

What does a repository migration actually move?
RecordIn git itself?Typical importer behaviorWhat to check
Commits, branches and tagsYesMoved by mirror push or importerBranch protection and signing settings, which are platform settings
Pull request titles and descriptionsNoOften importedLinks to old issue keys and URLs
General pull request commentsNoOften imported, sometimes under a migration accountAuthor attribution
Inline review commentsNoImported by some tools; positions can shift or detachComments marked outdated or orphaned
Approvals and review statesNoFrequently dropped or flattened into commentsWhether approved or changes requested survives
CI status checks and build logsNoUsually not importedExport from the CI system separately
Closed and declined pull requestsNoVaries by toolCounts by state, source against destination
Images and files attached in commentsNoMay still point to the old platformBroken images after the old platform closes

Why review history is worth the extra work#

Review history is worth the extra work because it records why code changed, not just what changed. A pull request thread shows the bug a reviewer caught, the design a senior engineer pushed back on and the approach that was abandoned, which a commit message rarely captures.

Engineering teams use that history during incident analysis, audits and onboarding. AI developers building coding assistants value the same review threads, because they pair code with expert critique and an outcome: merged, revised or rejected.

  1. 01Your work records
  2. 02Personal details removed
  3. 03You approve the release
  4. 04Licensed to AI developers
How it works with SourceX: Your work records → Personal details removed → You approve the release → Licensed to AI developers.Illustrative

Questions to ask any importer before you trust it#

Importers for GitHub, GitLab and Bitbucket each support some sources, some destinations and some object types, and the details depend on cloud versus self-managed editions. Read the importer's current documentation for the objects it carries, then confirm with a test on one busy repository.

Self-managed sources such as Bitbucket Data Center or a GitLab server add practical steps: network access from the destination, tokens with admin scope and enough time to import large histories without hitting rate limits.

  • Which pull request states does it import: open, merged, closed and declined?
  • Does it carry inline review comments, and what happens when the diff cannot be rebuilt?
  • Are approvals and review states imported as records, as comments or not at all?
  • How are users matched, and what appears when a user cannot be matched?
  • Are attachments, images and reactions copied or left as links to the old platform?
  • Does it rewrite links between pull requests and issues, or leave old URLs in place?

What each platform documents about its own export tools#

Each platform documents its own export tools more clearly than cross-platform importers, and those documents show where review history is at risk. Read them before trusting any migration path, because a tool built for moving projects is not always built for keeping history.

GitLab is unusually direct. Its project file export includes merge requests, issues with comments, labels, milestones and releases, but GitLab says these files should not be used as backups because not all items are exported, and after an import only the latest diff version and latest pipeline of each merge request remain visible. That is one way inline review comments made on earlier versions of a merge request can lose their context.

What each platform documents about its own export tools
Platform routeWhat the vendor documentsReview history risk
Git mirror clone and push, any platformCommits, branches and tags onlyNo pull requests, reviews or comments at all
GitLab project file export and importMerge requests, issues with comments, labels, milestones, releases; not a backupOnly the latest diff version and pipeline stay visible on imported merge requests
GitHub.com migration archive via the APISelected repositories exported as an archive for import into GitHub Enterprise ServerNeeds owner permissions and a token with repo and admin:org scopes
Bitbucket Cloud issue tracker exportIssues as a zip with a db-2.0.json file and optional attachments; spam-flagged issues left outAtlassian announced removal of the issue tracker and wiki on August 20, 2026, so links to them may already be dead
Your own API export of pull requestsWhatever you request and save as raw JSONRate limits set the pace on large repositories

Archive before you switch: the export step#

The export step creates a platform-independent archive of every pull request before the old platform is switched off. Even when the importer works well, the archive is your evidence of what existed, and it protects the record if a later cleanup on the new platform deletes stale pull requests.

Use the source platform's REST or GraphQL API and save raw JSON, so nothing is reshaped by the export. Keep commit hashes on every record, because they tie review comments back to the exact code reviewed. Budget time for rate limits: GitHub's REST API allows 5,000 requests per hour with a personal access token, and a GitHub App installed on a GitHub Enterprise Cloud organization gets 15,000, so a busy repository's review history can take hours to pull.

  • Step 1: inventory repositories with pull request counts by state.
  • Step 2: take a mirror clone of each repository for the full git history.
  • Step 3: export pull requests, general comments, inline review comments, reviews and status checks through the API.
  • Step 4: download images and files attached in comments, since their links will break.
  • Step 5: export CI logs separately if build outcomes matter to your history.
  • Step 6: store the archive read-only with checksums and reconcile counts against the source.

Identities and links decide whether an imported review history still makes sense to a reader. Without a user mapping, every comment from a former employee can collapse into a single placeholder account, and the thread loses the distinction between reviewer and author.

Build the mapping by email before importing, include former employees and bots, and keep the original usernames in the archive. For links, decide whether to rewrite old pull request and issue URLs or keep a mapping table from old identifiers to new ones; either works, as long as the choice is written down.

Issue keys need the same care when the issue tracker moves too. A pull request titled with a Jira key stays meaningful only while that key resolves somewhere, so if projects are renamed or the team moves to GitLab issues, record old and new keys side by side. A reader of an archived thread can then still find the bug it fixed.

Illustrative: an inventory software company consolidates on GitLab#

Illustrative: a fictional restaurant inventory software company on self-managed GitLab acquired a smaller competitor whose code lived in Bitbucket Cloud. The CTO wanted one platform and asked for a test import of the acquired company's busiest repository.

The test showed approvals missing and some inline comments detached on pull requests that had been rebased before merging. The CTO kept the plan to consolidate but added an archive step first: a mirror clone and a full API export of every Bitbucket pull request, with commit hashes and attachments. Active repositories were imported, Bitbucket stayed read-only until counts reconciled, and the acquired team's review history remained searchable in the archive.

How SourceX approaches code review archives#

SourceX approaches code review archives as engineering records whose value depends on linkage: pull requests tied to issues, reviews tied to commits, and outcomes recorded. A complete archive made before a migration often preserves more of that linkage than the imported copy on the new platform.

Licensing review history follows the SourceX five-step transaction, Supply, Rights, Preparation, Approval and Delivery, with engineering-specific work at two points. The Rights step separates customer-owned code and contractor work, and Preparation adds secret scanning and the removal of personal details from comments. The SourceX Evidence Packet then notes which export method produced the archive, on what date and with which known gaps.

Frequently asked questions

Will commit hashes change during the migration?

Not if the repository is mirrored without rewriting history. Hashes change when history is rewritten, for example to strip large files or old secrets, and that breaks the link between archived review comments and the code they discuss. Decide on any rewrite before exporting, and keep a mapping of old to new hashes if you do rewrite.

Do we need to keep closed and declined pull requests?

On the new platform, often not. In the archive, yes. Declined and abandoned pull requests show approaches the team rejected and why, which is useful for future design decisions and is part of the reasoning AI developers value in review history. Keep them with their final state and the reason they were closed, where one was given.

What about secrets in old pull request comments?

Old comments and diffs can contain passwords, API keys and tokens that engineers pasted while debugging. Open-source scanners such as gitleaks detect secrets in git repositories and files, and similar scanning can be run over exported comment text. Rotate anything live, and redact it from archive copies used for review.

Can we keep the old platform read-only instead?

Yes, for a period, and many teams do while the archive is verified. Read-only access still costs licenses or hosting, and acquired platforms tend to be cancelled during cost reviews. Treat read-only mode as a bridge to a verified archive, not a substitute for one.

Does a migration change who owns the review history?

No. The company owns its review history wherever it is hosted. What can limit later use is the content: customer-owned code, contractor agreements and personal details in comments. Those questions belong in a rights review, assessed with counsel, before review history is used outside the company.

Sources

  • Gitleaks is an MIT-licensed tool for detecting secrets such as passwords, API keys and tokens in git repositories, files and stdin. Source
  • GitLab's file-export migration includes project and wiki repositories, uploads, issues with comments, merge requests, labels, milestones, snippets and releases; GitLab says export files should not be used to back up data because not all items are exported, and after import or export only the latest diff version and latest pipeline in merge requests are visible. Source
  • Migration data can be exported from an organization on GitHub.com by using the API to select repositories and generate a migration archive for import into GitHub Enterprise Server, which requires owner permissions and a token with the repo and admin:org scopes. Source
  • Atlassian announced that the Bitbucket Cloud issue tracker and wiki would be removed on August 20, 2026, with issues exportable as a zip file or migratable to Jira. Source
  • Bitbucket Cloud issue export packages are ZIP files containing a db-2.0.json file and optionally an attachments directory; issues flagged as spam are not exported. Source
  • GitHub's REST API allows 5,000 requests per hour for requests made with a personal access token, while a GitHub App installation on a GitHub Enterprise Cloud organization gets 15,000 requests per hour. Source

Related resources

See if your company qualifies

A short company assessment. No data uploads are needed.

See if your company qualifies