Skip to content

Systems and records

Retiring a self-managed GitLab server: keeping merge request history

By SourceX Editorial · Updated

Short answer

To decommission a self-managed GitLab server without losing merge request history, keep three things: a full backup proven by a test restore, an API pull of every merge request with its discussions, diff versions and approvals, and a mirror clone of each repository. Project export files are not enough, because only the latest diff version and pipeline survive an import.

Key takeaways

  • GitLab says project export files should not be used as backups, because not every item is exported.
  • After a project export and import, merge requests show only the latest diff version and latest pipeline, so earlier review rounds disappear.
  • The review trail lives in discussions, system notes, diff versions and approvals, and an API pull keeps all four in readable form.
  • A full backup is proven only when it restores on a test instance and old merge requests open correctly.
  • Power the server off only after the backup, the API archive and the repository mirrors are verified and signed off.

What merge request history does a GitLab server hold?#

A GitLab server holds merge request history as several linked records, not one object: the description, threaded discussions anchored to lines of code, system notes, a diff version for every push, approvals and the pipelines that ran against each version. Together they show how a change was proposed, challenged, revised and accepted.

Most of that lives in the PostgreSQL database, but not all of it. Repositories sit in Git storage, uploaded screenshots sit in the uploads directory, and job logs and artifacts often sit in object storage or on a separate disk. Depending on configuration, merge request diffs may also be stored outside the database, which is easy to miss in a backup plan.

What merge request history does a GitLab server hold?
Merge request recordWhat it showsHow to keep it
Description and linked issuesWhat was asked for and whyFull backup plus API pull
Diff discussionsLine-level review comments and whether each thread was resolvedAPI pull of discussions with their file and line positions
Diff versionsHow the code changed after each review roundAPI pull of every version, not only the final diff
System notesPushes, label changes, approvals and the merge, in time orderAPI pull of notes, including system notes
ApprovalsWho signed off and under which approval rulesAPI pull of approval state per merge request
Pipelines and job logsWhether tests passed on each versionFull backup, plus logs for release and incident pipelines
Commits from deleted branchesIntermediate work before a squash mergeMirror clone that fetches all references

Backup, project export or API: which one keeps the review trail?#

The full instance backup and an API pull keep the review trail; a project export keeps the merge requests but flattens their history. GitLab documents that its file export includes repositories, issues with comments, merge requests, labels, milestones, releases, LFS objects and protected branches, but it also warns that export files should not be used for backups and that, after import, merge requests show only the latest diff version and latest pipeline.

That means a migration built on project exports can look complete in the new instance while every earlier review round is gone. The reviewer comment that forced a redesign still appears, but the code it referred to does not. Treat project exports as a way to move active work, and build the archive from the backup and the API.

Backup, project export or API: which one keeps the review trail?
MethodKeepsLoses or risksBest use
Native full backupDatabase, repositories, uploads and, as configured, CI artifactsReadable only by restoring onto a matching GitLab install; configuration and secrets files are often separateComplete copy for a future restore
Project export fileRepositories, issues with comments, merge requests, labels, milestones, releasesOnly the latest diff version and pipeline per merge request after importMoving active projects to a new instance
API pullDiscussions, notes, diff versions and approvals as structured filesRun time on an old server and the effort of a resumable scriptReadable, searchable archive
Mirror cloneEvery branch, tag and commit reachable from referencesNo review discussion at allCode history next to the API archive
  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

The shutdown checklist for a self-managed GitLab server#

The shutdown checklist runs from steps that cannot be redone later, such as recording versions and storage paths, to steps that prove the archive works. Keep the server, its admin account and the engineer who knows its quirks available until the last item is signed.

  • Record the exact GitLab version and edition, the PostgreSQL version, and where repositories, uploads, diffs, artifacts and LFS objects are stored.
  • Stop new writes by archiving projects or restricting roles, and announce the date after which nothing new will be recorded.
  • Take the native full backup, copy the configuration and secrets files separately, and checksum every file.
  • Restore onto an isolated test instance of the same version and open a sample of old merge requests, including some with many review rounds.
  • Pull every merge request through the API: metadata, discussions, notes, diff versions, approvals and linked issues, keyed by project and merge request ID.
  • Mirror-clone every repository with all references, including archived projects and personal namespaces that hold company code.
  • Save job logs and artifacts for release branches and incident pipelines, and keep pipeline metadata for the rest.
  • Scan the archive for secrets and personal details, rotate any live credential, and record sign-off from engineering, security and counsel before powering off.

Running a long API pull on an old server#

A long API pull on an old GitLab server works best as a resumable job that walks one project at a time and writes raw responses to disk. List the merge requests in each project, then fetch each one's discussions, notes, versions and approvals, and record which IDs finished so a failure restarts where it stopped.

On a self-managed instance the administrators set the rate limits, so the constraint is usually aging hardware rather than policy. Run pulls outside working hours if the server still serves users, and watch database load. If you also use project exports, GitLab's documented defaults allow six project exports per minute per user and one export download per minute per user, and admins can change them.

Check completeness against the instance, not against memory. Compare merge request counts per project with the totals the server reports, spot-check threads with many replies, and keep an index listing project, merge request ID, title, author, dates, state and archive path for each record.

Rights and privacy questions before the server goes off#

Rights and privacy questions on a GitLab archive start with whose code it is. Most repositories hold company-owned work, but services teams sometimes keep customer-owned code in the same instance, and acquired products may carry terms from their previous owner. Flag those projects in the index so they can be handled separately.

On a self-managed server the records sit on your own infrastructure, and Section 8.4 of the GitLab Subscription Agreement version GLSA_01.12.26 v8 states that the customer retains all right, title and interest in its Customer Content, subject to a limited license to GitLab; older versions word this differently, so confirm which version your company signed. Personal details still need care: commit metadata, user tables and review comments carry names and email addresses, and pipeline logs can expose credentials.

Ask counsel whether any project is under a legal hold or contractual retention duty before anything is deleted. Then store the archive encrypted, limit access to a named group, and add it to your retention schedule like any other record system.

Illustrative: a fleet software company switches off its old GitLab#

Illustrative: a fictional fleet maintenance software company ran a self-managed GitLab on an aging virtual machine for most of its history. Engineering moved active projects to a cloud GitLab instance using project exports, and the old server was scheduled for shutdown when the hosting contract ended.

During a final check, the CTO opened an old merge request in the new instance and saw only the final diff. Reviewer comments about a rounding change in service interval calculations pointed at code that no longer appeared. The team paused the shutdown, took a full backup, proved it on a test instance, pulled every merge request through the API and mirror-cloned all repositories, including a retired mobile app.

The verified backup, the API archive and the index now sit in encrypted company storage. When a customer later questioned how service intervals were calculated, engineers traced the answer through the original review rounds instead of reconstructing it from the final code.

How SourceX approaches a retired GitLab archive#

SourceX treats a retired GitLab archive as engineering history whose value depends on links: a merge request tied to the issue that prompted it, the review that shaped it and the release that shipped it. In the Supply step of the SourceX five-step transaction, a company describes versions, years of history and how those records connect; no files are shared at that stage.

If the company proceeds, the Rights, Preparation, Approval and Delivery steps follow, with customer-owned code excluded, secrets and personal details removed, and every release approved by the company. The archive stays in the company's own storage or ships on encrypted drives, and the SourceX Evidence Packet records provenance, licensing rights, permitted use, the privacy record and release authorization.

Frequently asked questions

Can we keep the old GitLab server running read-only instead?

For a short bridge, yes. Archived projects and restricted roles stop new writes while people can still browse. An unpatched server is a security exposure, though, so limit network access, set an end date and finish the backup and API archive while it runs, rather than treating read-only mode as the archive.

Do merge requests that were closed without merging matter?

Yes. Closed merge requests often record approaches the team rejected and the reasons reviewers gave, which is some of the most instructive history on the server. They cost little to keep, and dropping them breaks issue links that still point to them.

Does moving projects to GitLab.com keep merge request history?

It depends on the method. With project export files, merge requests and comments move, but only the latest diff version and pipeline remain visible after import. Whatever method you use, open a sample of complex merge requests in both instances and compare them before relying on the new copy.

What about personal namespaces and forks?

Inventory them before shutdown. Engineers often keep forks or experiments in personal namespaces, and some hold company code or the only copy of a prototype. Decide project by project whether each one is company work to archive or personal material to exclude, and record the decision.

Who should sign off before the server is powered off?

The engineering lead confirms the restore test and the API archive, security confirms secrets were rotated and the archive is encrypted, and counsel confirms there are no legal holds or retention duties. Record each sign-off with its date and keep it with the archive index.

Sources

  • GitLab's file-export migration includes project and wiki repositories, uploads, project configuration (excluding integrations), issues with comments, merge requests, labels, milestones, snippets, releases, design files, LFS objects, issue boards, and protected branches and tags. Source
  • GitLab says project 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
  • GitLab's default rate limits for file exports are 6 project exports per minute per user and 1 project export download per minute per user; self-managed admins can change them. Source
  • Section 8.4 of the GitLab Subscription Agreement (version GLSA_01.12.26 v8) states the customer retains all right, title and interest in and to Customer Content, subject to a limited license to GitLab. Source

Related resources

See if your company qualifies

A short company assessment. No data uploads are needed.

See if your company qualifies