289

I need to convert a mercurial project to a git project, but I would like to keep the commit history intact. My current solution was to just remove hg related files and then git init && add manually the files I needed, but that would not keep the history. Are there any solutions to this?

James Roth
  • 6,320
  • 2
  • 15
  • 18
gandolf
  • 3,314
  • 3
  • 18
  • 19
  • 1
    A git-hg utility for checking out and tracking a mercurial repo. https://github.com/offbytwo/git-hg – MGP Apr 16 '13 at 13:11
  • 2
    You might also try [Kiln Harmony](http://blog.fogcreek.com/announcing-kiln-harmony-the-future-of-dvcs/) which keeps both a git and mercurial version of a repo and syncs everything, so it's usable from both. – Wilbert Apr 16 '13 at 13:26
  • 2
    Better approach https://github.com/buchuki/gitifyhg – sorin Mar 25 '15 at 18:21
  • 3
    @Ian and others. Its not actually a duplicate question, the other question is about migrating a specific folder, this one is about the entire repo. Although answers to this questions have been posted to that question, This is a different question. It should be marked as a related question. – simgineer Jul 06 '15 at 02:45
  • As simineer said, this is *not* a duplicate. However all the answers on that other question are ignoring the fact that the questioner only wants a single file, and are answering *this* question instead. By far the best answer is [this one](http://stackoverflow.com/a/31827990/265521). – Timmmm Oct 22 '15 at 09:46
  • `git-remote-hg`: http://stackoverflow.com/questions/883452/git-interoperability-with-a-mercurial-repository – RickyA Oct 28 '16 at 07:05
  • 4
    For reference sake, Kiln Harmony has been discontinued. – Tim Friesen Oct 26 '17 at 14:33

8 Answers8

284

You can try using fast-export:

cd ~
git clone https://github.com/frej/fast-export.git
git init git_repo
cd git_repo
~/fast-export/hg-fast-export.sh -r /path/to/old/mercurial_repo
git checkout HEAD

Also have a look at this SO question.


If you're using Mercurial version below 4.6, adrihanu got your back:

As he stated in his comment: "In case you use Mercurial < 4.6 and you got "revsymbol not found" error. You need to update your Mercurial or downgrade fast-export by running git checkout tags/v180317 inside ~/fast-export directory.".

Kyle Macey
  • 7,769
  • 2
  • 33
  • 74
akluth
  • 7,787
  • 4
  • 34
  • 41
  • 6
    As an additional note, you can also pass in `-A` with an authors map file if you need to map Mercurial authors to Git authors. – David Mohundro Jun 12 '13 at 02:15
  • 11
    n.b. Install Mercurial before executing Step 5 if you haven't already. http://mercurial.selenic.com/ – Kevin Zych Jun 18 '13 at 02:06
  • 6
    If you have errors like "repository has at least one unnamed head", you can specify `--force` option to deal with broken tree. – iurii May 21 '14 at 14:23
  • 2
    I just did this for my psutil project but tags and branches has not been migrated. – Giampaolo Rodolà May 23 '14 at 00:35
  • best answer on the internet, don't waste your time with hggit bs. – Gubatron Oct 21 '14 at 02:51
  • 15
    doesn't work out of the box for windows. therefore may as well not work for 97% of people - might be worth mentioning that you can use cygwin or similar in that case (even then it has hidden dependencies) – jheriko Jan 12 '15 at 17:26
  • I added '-f' to forcefully migrate the repo in my case. Was getting a few errors here and there. – atulkhatri Mar 23 '16 at 15:56
  • The host name does not seem to be working anymore I am getting a "Unable to connect to repo.or.cz' – fahadash Apr 15 '16 at 14:41
  • 1
    Does not work on windows: first need to install the python mercurial module (`pip install mercurial`), which fails if there is no compiler handy (with `error: Microsoft Visual C++ 10.0 is required (Unable to find vcvarsall.bat)`) – WoJ Jun 28 '16 at 12:56
  • 6
    @jheriko _doesn't work out of the box for windows. therefore may as well not work for 97% of people_ - That number (97%) you're mentioning is from 2005. – Attila Fulop Dec 09 '16 at 17:03
  • And the repo doesn't seem to be there anymore: `fatal: unable to connect to repo.or.cz: repo.or.cz[0: 195.113.20.142]: errno=Connection refused` – James Mitchell Apr 26 '17 at 09:58
  • What if I have a bunch of binary files in mercurial stored as "large files"? What will happen to them? – gp443 Feb 05 '18 at 15:41
  • Can you please link to the Git repo of Fast Export (I think from https://github.com/frej/fast-export ?) instead of just linking to a blog post about it or referencing it in your command line instructions. – Nathan Craike Feb 16 '18 at 00:55
  • 1
    `error: pathspec 'HEAD' did not match any file(s) known to git.` – serge Feb 19 '18 at 16:14
  • HEAD as the checkout target might not work if one has only pulled one branch (and not default) in their old/hg repository. replace it with the branch name in that case, else checkout won't show any files. – PypeBros Feb 28 '18 at 11:24
  • 1
    I am on Windows, this solution does not work – serge Mar 02 '18 at 15:59
  • @Serge - if you're on Windows and you understand what's going on there you should be capable of adapt these steps on your local Windows box as long as there are other errors (maybe in the fast-export tool) on your Windows box. Please be more specific about what exactly does not work. – akluth Mar 08 '18 at 13:43
  • 2
    In case you use **Mercurial < 4.6** and you got **"revsymbol not found"** error. You need to update your _Mercurial_ or downgrade _fast-export_ by running `git checkout tags/v180317` inside _~/fast-export_ directory. – adrihanu Apr 12 '19 at 11:06
  • 1
    doesn't work on mac os. – Alexey Sh. Oct 01 '19 at 17:29
  • For windows, I spent a lot of time trying to get it work. In the end I used Windows Subsystem for Linux (WSL). It does at least remove a whole category of issues. – Greg Woods Feb 07 '20 at 10:24
97

Ok I finally worked this out. This is using TortoiseHg on Windows. If you're not using that you can do it on the command line.

  1. Install TortoiseHg
  2. Right click an empty space in explorer, and go to the TortoiseHg settings:

TortoiseHg Settings

  1. Enable hggit:

enter image description here

  1. Open a command line, enter an empty directory.

  2. git init --bare .git (If you don't use a bare repo you'll get an error like abort: git remote error: refs/heads/master failed to update

  3. cd to your Mercurial repository.

  4. hg bookmarks hg

  5. hg push c:/path/to/your/git/repo

  6. In the Git directory: git config --bool core.bare false (Don't ask me why. Something about "work trees". Git is seriously unfriendly. I swear writing the actual code is easier than using Git.)

Hopefully it will work and then you can push from that new git repo to a non-bare one.

Timmmm
  • 68,359
  • 51
  • 283
  • 367
  • 3
    The push kept failing for me on the push with error "dulwich.errors.RefFormatError: refs/heads/ref". It turns out that I had several bookmarks. After deleting each bookmark, it stopped failing. – GaTechThomas Jun 30 '16 at 00:25
  • 9
    Per the [hg-git](http://hg-git.github.io/) documentation, "TortoiseHg comes with hg-git" and just needs to be enabled (as shown above). However, it is **not** included with the command line version of mercurial (It can be installed if desired). If you have both TortoiseHg & HG installed, you need to be sure the `hg.exe` from TortoiseHg is used, and not the one form the command line installation. If you get the error _No module named hggit_, try fully qualifying the hg command: `"C:\Program Files\TortoiseHg\hg" push c:/path/to/your/git/rep` – Javaru Aug 28 '16 at 14:23
  • 1
    Note that this method only seems to import the currently checked-out branch (I'm looking for a solution that will import the whole repository). – robyaw Apr 04 '17 at 09:06
  • 12
    Wouldn't `hg bookmark -r default master` be better than `hg bookmarks hg`? – Heikki Nov 01 '17 at 14:01
  • 1
    If the push keeps failing like GaTechThomas says above, you may want to use: "hg gclear" to do the clearing. – Derek Jun 12 '19 at 12:09
  • 5
    For the files to appear in the repo, do: git checkout hg – user984003 Aug 29 '19 at 13:15
  • 1
    Make sure you set `git config --bool core.bare false` correctly. I had a typo, `git config --bool core.bar false` and of course, git didn't complain. – CrazyPenguin Nov 04 '19 at 15:36
81

If you want to import your existing mercurial repository into a 'GitHub' repository, you can now simply use GitHub Importer available here [Login required]. No more messing around with fast-export etc. (although its a very good tool)

You will get all your commits, branches and tags intact. One more cool thing is that you can change the author's email-id as well. Check out below screenshots:

enter image description here

enter image description here

atulkhatri
  • 9,359
  • 3
  • 45
  • 79
  • Does it also migrate issues and wikis? – thomthom Apr 03 '16 at 16:59
  • @thomthom No only commits, branches & tags – atulkhatri Apr 03 '16 at 17:22
  • 2
    You need a paid plan on Github to create private repositories. Not a problem if what you're converting is a public source tree anyway, of course. – Åsmund Jun 30 '16 at 15:04
  • @Åsmund one could also use the tool, clone the git, then delete the public repo, if one is only worried about public exposure of the code when it is not ready – Tommy Sep 01 '16 at 01:46
  • @atulkhatri thanks for this! was going to use fast export until I saw github would solve this! – Tommy Sep 01 '16 at 01:47
  • 4
    Do you know how to upload and convert a local mercurial repository? – xslittlegrass Dec 07 '16 at 20:57
  • I have this GitHub importer and I saw that my history was not exactly the same as it was in Mercurial. The commits where not in date-order and I believe this is the main issue. Does anyone have any idea what could cause this? – Nick N. Jul 31 '17 at 08:26
  • Mine is frozen on: "Detecting your project’s version control system…" when importing from BitBucket – Jack Mar 19 '20 at 13:06
21

Some notes of my experience converting Mercurial to Git.

1. hg-fast-export

Using hg-fast-export failed and I needed --force as noted above. Next I got this error:

error: cannot lock ref 'refs/heads/stable': 'refs/heads/stable/sub-branch-name' exists; cannot create 'refs/heads/stable'

Upon completion of the hg-fast-export I ended up with an amputated repo. I think that this repo had a good few orphaned branches and that hg-fast-export needs a somewhat idealised repo. This all seemed a bit rough around the edges, so I moved on to Kiln Harmony (http://blog.fogcreek.com/announcing-kiln-harmony-the-future-of-dvcs/)

2. Kiln

Kiln Harmony does not appear to exist on a free tier account as suggested above. I could choose between Git-only and Mercurial-only repos and there is no option to switch. I raised a support ticket and will share the result if they reply.

3. hg-git

The Hg-Git mercurial plugin (http://hg-git.github.io/) did work for me. FYI on Mac OSX I installed hg-git via macports as follows:

  • sudo port install python27
  • sudo port select --set python python27
  • sudo port install py27-hggit
  • vi ~/.hgrc

.hgrc needs these lines:

[ui]
username = Name Surname <me@mydomain.com>

[extensions]
hgext.bookmarks =
hggit = 

I then had success with:

hg push git+ssh://git@bitbucket.org:myaccount/myrepo.git

4. Caveat: Know your repo

All the above are blunt instruments and I only pushed ahead because it took enough time to get the team to use git properly.

Upon first pushing the project per (3) I ended up with all new changes missing. This is because this line of code must be viewed as a guide only:

$ hg bookmark -r default master # make a bookmark of master for default, so a ref gets created

The theory is that the default branch can be deemed to be master when pushing to git, and in my case I inherited a repo where they used 'stable' as the equivalent of master. Moreover, I also discovered that the tip of the repo was a hotfix not yet merged with the 'stable' branch.

Without properly understanding both Mercurial and the repo to be converted, you are probably better off not doing the conversion.

I did the following in order to get the repo ready for a second conversion attempt:

hg update -C stable
hg merge stable/hotfix-feature
hg ci -m "Merge with stable branch"
hg push git+ssh://git@bitbucket.org:myaccount/myrepo.git

After this I had a verifiably equivalent project in git, however all the orphaned branches I mentioned earlier are gone. I don't think that is too serious, but I may well live to regret this as an oversight. Therefore my final thought is to keep the original anyway.

Edit: If you just want the latest commit in git, this is simpler than the above merge:

hg book -r tip master
hg push git+ssh://git@bitbucket.org:myaccount/myrepo.git
Dion Truter
  • 6,302
  • 1
  • 16
  • 8
11

I had a similar task to do, but it contained some aspects that were not sufficiently covered by the other answers here:

  • I wanted to convert all (in my case: two, or in general: more than one) branches of my repo.
  • I had non-ASCII and (being a Windows user) non-UTF8-encoded characters (for the curious: German umlaute) in my commit messages and file names.

I did not try fast-export and hg-fast-export, since they require that you have Python and some Mercurial Python modules on your machine, which I didn't have.

I did try hg-init with TortoiseHG, and this answer gave me a good start. But it looked like it only converts the current branch, not all at once (*). So I read the hg-init docs and this blog post and added

[git]  
branch_bookmark_suffix=_bookmark

to my mercurial.ini, and did

hg bookmarks -r default master  
hg bookmarks -r my_branch my_branch_bookmark  
hg gexport

(Repeat the 2nd line for every branch you want to convert, and repeat it again if you should happen to do another commit before executing the 3rd line). This creates a folder git within .hg, which turns out to be a bare Git repo with all the exported branches. I could clone this repo and had a working copy as desired.

Or almost...

Running

git status

on my working copy showed all files with non-ASCII characters in their names as untracked files. So I continued researching and followed this advice:

git rm -rf --cached \*  
git add --all
git commit 

And finally the repo was ready to be pushed up to Bitbucket :-)

I also tried the Github importer as mentioned in this answer. I used Bitbucket as the source system, and Github did quite a good job, i.e. it converted all branches automatically. However, it showed '?'-characters for all non-ASCII characters in my commit messages (Web-UI and locally) and filenames (Web-UI only), and while I could fix the filenames as described above, I had no idea what to do with the commit messages, and so I'd prefer the hg-init approach. Without the encoding issue the Github importer would have been a perfect and fast solution (as long as you have a paid Github account or can tolerate that your repo is public for as long as it takes to pull it from Github to your local machine).


(*) So it looked like before I discovered that I have to bookmark all the branches I want to export. If you do and push to a bare (!) repo, like the linked answer says, you get all the branches.

Community
  • 1
  • 1
Matthias
  • 1,639
  • 15
  • 32
  • 1
    to solve encoding problem with hg-fast-export (not sure for github importer) you can pass parameter 'e' like this: -e cp1251 – Pavel May 07 '18 at 14:38
  • to solve file names encoding problem with hg-fast-export you can use '--fe' option like --fe cp1251 – Sandre Oct 04 '19 at 15:26
10

From:

http://hivelogic.com/articles/converting-from-mercurial-to-git

Migrating

It’s a relatively simple process. First we download fast-export (the best way is via its Git repository, which I’ll clone right to the desktop), then we create a new git repository, perform the migration, and check out the HEAD. On the command line, it goes like this:

cd ~/Desktop
git clone git://repo.or.cz/fast-export.git
git init git_repo
cd git_repo
~/Desktop/fast-export/hg-fast-export.sh -r /path/to/old/mercurial_repo
git checkout HEAD

You should see a long listing of commits fly by as your project is migrated after running fast-export. If you see errors, they are likely related to an improperly specified Python path (see the note above and customize for your system).

That’s it, you’re done.

Reck Hou
  • 4,212
  • 7
  • 30
  • 48
  • 2
    This worked for me, but I had to add a step. fast-export broke for all but the most recent versions of Mercurial (wasn't available through apt) so you either have to manually install a shiny new Mercurial >4.6 or just downgrade fast-export by adding a `git checkout 19aa906` as a new step 3 above to get to the last commit that worked – Paul K Aug 13 '19 at 14:29
7

Another option is to create a free Kiln account -- kiln round trips between git and hg with 100% metadata retention, so you can use it for a one time convert or use it to access a repository using whichever client you prefer.

Ry4an Brase
  • 77,054
  • 6
  • 143
  • 167
  • 6
    How do you use kiln for converting? – Ofer Helman Nov 04 '14 at 08:40
  • Kiln repositories are usable by both git and hg. So you can import from one client, and then export from the other client, as many times as you like. – Michael Shaw Mar 11 '15 at 09:22
  • 3
    Kiln Harmony was very nice while it lasted, but it was [shut down](http://help.fogcreek.com/how-to-disable-kiln-harmony-on-a-repository/) in September 2016. (And Kiln's free tier is being shut off next month.) – Josh Apr 07 '17 at 00:38
  • Kiln was sold recently and has had a lot of downtime since. Their status pages don't reflect most of this, but it's about once / month. Would only recommend if you absolutely need Mercurial and can't find another host. – Josh Noe Nov 27 '19 at 20:09
2

This would be better as a comment, sorry I do not have commenting permissions.

@mar10 comment was the missing piece I needed to do this.

Note that '/path/to/old/mercurial_repo' must be a path on the file system (not a URL), so you have to clone the original repository before. – mar10 Dec 27 '13 at 16:30

This comment was in regards to the answer that solved this for me, https://stackoverflow.com/a/10710294/2148757 which is the same answer as the one marked correct here, https://stackoverflow.com/a/16037861/2148757

This moved our hg project to git with the commit history intact.

Community
  • 1
  • 1
Sashah
  • 399
  • 4
  • 16