Migrating from GitLab to GitHub

The Method of Code Migration

Unsurprisingly, there are a variety of ways to migrate projects in this Git-centric environment.

GitHub Importer

GitHub themselves, keen to pull in as many new (ideally paying) users as possible, provide a simple import tool:

How to access the GitHub importer

3rd Party Migration Tools

There are of course other tools for this process available on the internet. Typically they work by checking out your projects and pushing them to GitHub — much like the next section — but what I personally found was that I had a hard time trusting these tools. Those that were open-source tended to be semi-abandoned, and those that were closed-source were… closed-source.

There’s little more important to a software company than its code.


I’m a software engineer, so of course the idea of writing my own script came to mind. In addition, the GitHub API is truly wonderful. It covers just about every conceivable thing you could do on GitHub, and covers it well.

  1. It checked out all existing repositories from GitLab, re-pointed them to a GitHub of my choosing, and pushed them all (the actual migration)
  2. It checked out all GitLab and GitHub repositories side-by-side (for ensuring the migration had worked successfully)
  3. It deleted all repositories on the target GitHub server (for clean-up after test runs — note that this script only worked on non-production GitHub’s, or else I’d risk deleting some valuable corporate property!)
If you want something done right, do it yourself (even Git migration scripts)

A Note on Merge Requests

Unfortunately, GitLab Merge Requests (MRs) and GitHub Pull Requests (PRs) are not the same. They’re very similar, but they don’t follow a standard implementation like Git itself does. What that means is that MRs cannot be drag-and-dropped onto GitHub. Conversion must take place.

Pre-Migration Activities

In addition to running the actual migration, there are a few pre-migration activities I’d definitely recommend carrying out.

A Spreadsheet (who doesn’t love a spreadsheet?)

As a lover of spreadsheets, this one was a no-brainer. Before I started anything, I created a spreadsheet and entered all my repositories into it. This then gave me a central point in which to manage not only the migration progress of each repository, but also to automate the creation of certain things, such as JSON data.

Those Excel formulas you learned in high school finally have a chance to shine

Renaming Projects

One thing I needed to address early on, was the fact that repositories on the target GitHub followed a naming convention that ours didn’t currently adhere to. This was a trivial thing to address with a formula in the spreadsheet, which then output the new name into the JSON data, which in turn was fed to the migration script.

Adding Secondary Emails

One issue with migrating from an on-prem GitLab instance to a cloud-based GitHub one, was that user accounts were not consistent across the two. If a developer committed to GitLab with amy@yourcompany.com, they probably didn’t also have a GitHub account under the same email. So, when the migration was done, you had an existing user of amy@yourcompany.com, and a new user of amy@gmail.com going forward.

How my GitHub account looked for the migration (with emails redacted)

Test Runs

I’d like to think this point is too obvious to say, but I’ll say it anyway: You should always test your migration to a non-production environment first. Ideally, you should also test migrating from a non-production environment, but I appreciate that’s a little more cumbersome to set up.

Post-Migration Activities

Getting your code across may be all you need to achieve. But below are some additional things I had to take care of.

Assigning Topics

One feature that the target GitHub made use of which didn’t exist in GitLab was topics. Most were a fairly generic company-division topic, but others were project-specific. The way I managed the creation of the list of topics was to (mostly) automate it on the master spreadsheet, which in turn generated an array of topics as part of the JSON used to feed the migration. Once again, spreadsheets to the rescue!

Assigning Teams

Much like with topics, there was also a requirement to assign each repository to a target team. This was preferable to assigning individual users as it meant each repository could be assigned a team, and then the team’s members could be managed in one place. Once again this was auto-populated by the spreadsheet, and so could be manipulated to separate projects into different teams.

Checking / Testing

So you’ve just migrated the core of your company’s assets across the open internet, and are ready to decommission its old home. But before you do, you obviously want to test that everything has moved as expected.

Redirecting the Development Team

Once the code had moved across, it was time to notify the development team. But of course, they now had to begin working from the new GitHub environment.

git remote set-url origin https://github.com/gitHubOrganisation/target-repository.git

Locking GitLab

Finally, it’s time to lock and / or close down GitLab. Don’t be scared, you’ve done your tests, confirmed the code is safely in its new home, and of course, you’ve backed up your GitLab instance just in case, right?



Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store
Duncan McArdle

Duncan McArdle


Full-stack software developer from the UK, author of the Aftermath book series, full time tech-nerd.