Migrating from Mercurial to Git

Since Bitbucket announced back in August that they would be discontinuing support for Mercurial in 2020, I’ve had an item on my to-do list to convert all of my old Bitbucket Mercurial repos over to Git and move them to GitHub. Bitbucket did not provide any automated way to do this, so I’ve spent some time researching the possibilities and trying out different methods. I hit a few dead ends, but eventually found a way that worked for me. So I might as well share that here, for the benefit of anyone else who’s trying to do this.

A few preliminary notes:

  • I’m primarily a Windows user. I also have a MacBook, but I do most of my programming under Windows. So I wanted a method that would work under Windows.
  • My Mercurial repos are all pretty simple: multiple check-ins, but all in a single branch. (These are personal repos, not company repos where multiple programmers were working on them.)
  • My method was pretty similar to the one described in this blog post, from 2014, so I should give credit for that.

First, a few installs:

  1. Install Git for Windows. Any recent version should be fine. Be sure to install the bash shell.
  2. Install TortoiseHg. The most recent version should be fine. You don’t really need all the fancy Tortoise stuff here, but it’s the easiest way to get a good Mercurial install on Windows.
  3. Install Python 2.7. This probably won’t work with Python 3.x, so just install the latest version of 2.7.x. Make sure you add it to your path.

Now, from the git bash shell, run the following:

$ mkdir hg2git-work
$ cd hg2git-work
$ python -m pip install mercurial
$ git clone https://github.com/frej/fast-export.git

This will install Mercurial support for Python, then pull down hg-fast-export. That’s all the initial setup, really. The trick, I found, is using the git bash shell, which is close enough to a real bash shell for the rest of this stuff to work.

The next thing to do, which might or might not be necessary, is the create an “authors.txt” file to map your name/email from the old hg repo to the new git one. In my case, I created one with two lines that looks kind of like this:

"Andrew Huey <me@domain.com>"="Andrew Huey <me@users.noreply.github.com>"
"Andrew Huey <me@another-domain.com>"="Andrew Huey <me@users.noreply.github.com>"

This way, I’m mapping my real email addresses from Bitbucket to my private GitHub address. (My old Bitbucket repos were mostly private, but I’m making the new GitHub ones public.)

Let’s say you have a Mercurial repo in Bitbucket named “euler”. (That’s one of my repos, tracking my Project Euler work.) Now, do the following:

$ hg clone https://bitbucket.org/yourname/euler
$ mkdir euler-git
$ cd euler-git
$ git init
$ ../fast-export/hg-fast-export.sh -r ../euler --force -A ../authors.txt
$ git checkout HEAD

If all goes well, this should leave you with a nice new git repo, matching your hg repo. If you do not already have your GitHub credentials stored in your global Git config, you might now need to add them, either globally or locally. I won’t go into detail on that.

Next, you need rename or copy your .hgignore file to .gitignore. Both systems use pretty much the same format for ignore files, so you probably don’t need to edit it at all.

$ cp .hgignore .gitignore
$ git add .gitignore
$ git commit -m ".hgignore copied to .gitignore"

Now, you can just create a new target repo at GitHub, and push it up. Let’s assume your new repo is named “euler”.

$ git remote add origin https://github.com/username/euler.git
$ git push -u origin master

There are definitely other ways to do this, but this is the way that worked for me.

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.