Migrating Mercurial Repos To Git

In August 2019, BitBucket – a popular cloud source code hosting and project management service run by Atlassian – announced that it was dropping support for Mercurial repositories. Mercurial is a distributed source control management tool similar to, but less popular than Git.

This move isn’t surprising. Mercurial has lost the popularity war with Git and BitBucket claims that less than 1% of new repositories on their service use Mercurial. The surprising thing is that BitBucket announced that they are deleting Mercurial repositories from their service as of June 2020. Leaving developers and companies who use Mercurial with less than one year to migrate.

This move by BitBucket seems inevitable, but the timeline and hard-deletion that BitBucket is giving their loyal customers seems harsh. For me, I have around 25 projects that need to be migrated.

Here’s how to do so, in a few easy steps!

1. Decide Where To Go

Options abound! If you want to keep your repos on Mercurial, then you do have other hosting options including SourceHug, SourceForge, CodeBase and more. The Mercurial website has a full list of options for Mercurial hosting.

You might want to give serious thought to switching to Git.
Detailed Git tutorials are everywhere online and learning the basics is not too hard. For me, I was already learning and using Git, so this transition was a no-brainer. Since I’m unhappy with BitBucket in general, and this new issue doesn’t help, I’ve decided to move my projects away from BitBucket. At this time I’m keeping my Open Source projects on GitHub, and my private projects will be on GitLab.

For the purposes of this tutorial, I’ll be teaching you how to switch to Git.

2. Create A New Git Repo

First, using the tools on the cloud service where you will host your Git repos, create a new empty repo. Don’t initialize it with a README file if that option is offered. Give some thought to how you want to organize and name your projects because this can be a pain to change later. Some services let you sort repos into groups, projects, or workspaces. Now is a good time to think about how you’ll want to sort them when you have a ton of projects in the future. Don’t just put them all in the root group.

Make note of the SSL url to the repo. For GitLab this looks like:

git@gitlab.com:username/repo-name.git

3. Install Fast Export

There is an awesome tool called Fast Export for converting Mercurial repositories to Git. Create a directory on your development machine where you want to install Fast Export. Such as /home/tools/fast-export/. From a terminal in that directory, clone the Fast Export tool with:

git clone https://github.com/frej/fast-export.git .

Note: If you are using Mercurial version < 4.6 and you get a “revsymbol not found” error, either update Mercurial, or use an older version of Fast Export by running this in the fast-export directory:
git checkout tags/v180317

4. Prepare New Local Repo

Create a local directory where you will keep the new Git repo we are going to create with Fast Export. Initialize a new Git repo in there. Note that terminal commands may vary if you are on Windows.

mkdir /home/repos/git/my-project/
cd $_
git init

5. Use Fast Export to Convert

First make sure you have all the latest changes pulled into your local copy of the Mercurial repo. Then, from inside the newly initialized Git directory:

/home/tools/fast-export/hg-fast-export.sh -r /home/repos/mercurial/my-project/

This runs the fast export shell script on the Mercurial repo. You’ll see some nice output from Fast Export that looks like:

Next, checkout the HEAD commit like so:

git checkout HEAD

When it’s done, make sure to look at the hidden files and remove any Mercurial specific ones like .hgignore.

6. Connect To Remote

Connect the local Git repo to your new cloud hosted Git repo by setting the upstream SSH URL that you made note of earlier. In my case this looks like:

git remote add origin git@gitlab.com:username/repo-name.git

If you haven’t already, set up an SSH Key for connecting to your hosting service. I strongly recommend this over username/password authentication. GitLab’s documentation on SSH Keys is very complete.

7. Push The New Repo To The Remote Repository

Push the local Git repo to the remote. If you put a password on your SSH Key (recommended) then you will be prompted for it. To make sure you get everything up there, do:

git push -u origin --all
git push -u origin --tags

When these are done, visit the remote repo on GitLab or whichever service you chose, via your web browser. Confirm that the code and commit history is there. You may want to make a small local edit, then commit and push it to test it’s all working.

These steps should work for a straightforward Mercurial repository. If you have branch names that don’t convert to Git, or if you want the author information converted, there are ways to do this, just check out the Fast Export Documentation.

Bonus! Fix Line Endings

If like me, you received a bunch of warnings that your project has Windows style line endings (CRLF) and that Git was replacing them with Linux style endings (LF), you might want to ensure your local copy has the proper endings too. Many of my projects were originally created on a Windows machine but I now work on Linux, so these mixed endings have been everywhere. To make sure your local matches the remote, you can reset your local to what’s now in Git. First make sure everything is pushed to the remote successfully, then do:

git rm --cached -r .
git reset --hard

This removes everything locally and then resets your working tree to the last commit. You’ll lose the exiting working tree and staging area. If no commit is specified, then HEAD is assumed. Make sure your editor is using the correct line endings.

Wrap Up

That’s it! Once you get this process down, migrating a Mercurial repo can take as little as 10 minutes. It’s a good idea if you’re new to Git, to create a sandbox repository where you can experiment and try out Git’s commands. Many people like to use a GUI interface for Git as well.

For me, it is a fond farewell to Mercurial. It has served me well over 10+ years of development and I’ll miss its simplicity. ❤

Good Luck with your own migration!

4 thoughts on “Migrating Mercurial Repos To Git

  1. Using same tutorial, getting error while running fast-export.sh
    *** failed to import extension hggit from C:\Users\Desktop\Projects\hg-git-branch-default\hggit: future feature generator_stop is not defined (__init__.py, line 151)
    Traceback (most recent call last):
    File “C:/Users/Desktop/Projects/Git/migration_git/hg-fast-export.py”, line 709, in
    plugins=plugins_dict))
    File “C:/Users/Desktop/Projects/Git/migration_git/hg-fast-export.py”, line 519, in hg2git
    ui,repo=setup_repo(repourl)
    File “C:\Users\Desktop\Projects\Git\migration_git\hg2git.py”, line 47, in setup_repo
    return myui,hg.repository(myui, fsencode(url)).unfiltered()
    File “C:\Python27\lib\site-packages\mercurial\hg.py”, line 179, in repository
    intents=intents)
    File “C:\Python27\lib\site-packages\mercurial\hg.py”, line 163, in _peerorrepo
    obj = _peerlookup(path).instance(ui, path, create, intents=intents)
    File “C:\Python27\lib\site-packages\mercurial\localrepo.py”, line 2337, in instance
    intents=intents)
    File “C:\Python27\lib\site-packages\mercurial\localrepo.py”, line 494, in __init__
    self.vfs, self.supported)
    File “C:\Python27\lib\site-packages\mercurial\scmutil.py”, line 1031, in readrequires
    hint=_(“see https://mercurial-scm.org/wiki/MissingRequirement
    mercurial.error.RequirementError: repository requires features unknown to this Mercurial: share-safe

Leave a Reply to sandeep Cancel reply

Your email address will not be published. Required fields are marked *