There is a mercurial plugin called hggit that allows you to push and pull to/from a Git remote repository from Hg.
To use you just prefix the source repository url with git+
e.g.
1 | git+https://github.com/company/project.git |
Installation
TortoiseHg comes with hggit bundled so you can be enable it by going to File > Settings
and then under the global settings tab and extensions option as seen in the screenshot below; tick hggit
and then restart TortoiseHg.
There have been a couple of TortoiseHg releases in the past where the bundled version of hggit of didn’t work. So alternatively hggit can be manually installed by first cloning the repo:
1 | hg clone https://bitbucket.org/durin42/hg-git |
And then under File > Settings > Edit File
add the following:
1 | [extensions] |
Branches
You cannot create branches the normal Hg way for a Git repo. Hg branches store the branch information as part of each commit, which Git does not support instead it just stores what the latest commit for the branch is in a separate file similar to tags. This does allow branches to be created/deleted/renamed/moved without rewriting the commit history. It also means you don’t have the problem of needing to resolve multiple heads on a branch like you do in Hg since a bookmark can only point to one commit so a branch will only ever have one head. Hg can support Git style branches through the use of a feature called bookmarks
and this is what hggit uses to represent Git branches. To use you move or add a new bookmark to the latest commit that’s represented by the branch. Any commits not part of a branch, i.e. has no bookmark pointing to it or a descendant, will not get pushed or pulled (they will still appear in the outgoing changesets preview though but don’t actually get pushed). Hggit also creates a local tag labelled default/<branch name>
to mimic git’s origin/<branch name>
; default is the alias name for the remote repository url as specified in the settings files.
In the bookmark dialog the new name field is used for renaming an existing bookmark; to add a new bookmark enter the name under the bookmark field and click add. To activate a bookmark means this is the bookmark that will be automatically brought forward when you make your next commit.
Modifying Public History
After rewriting the public history under View > Show Console
execute the command:
hg git-cleanup
Then restart TortoiseHg, and perform a pull. This will restore the original commit you had modified, move the bookmark to the tip of the newly created commit (only needed if using the deleted bookmarks workaround). Then perform a forced push:
hg push -f
Afterwards the original commit can be stripped if hg strip extension is enabled by right clicking the commit and selecting strip under modify history context menu.
Note if you’re doing this to remove a password accidentily commited and pushed, it is strongly recommended to change the password as well. Using the above, commits are not removed in Git they’re just hidden (as mentioned here to remove instead of hide on Github involves creating a new repo) so while people can no longer see the original commit in the repository online or pull it down, they can still see it in the activity log sites like Github and Bitbucket provides and click the link to see the hidden commit.
Note #2, if you import a commit into MQ and then unapply and reapply that commit it will have a different hash id even if you made no changes. This only happens with commits you pulled down, commits made locally will have the same hash id if no changes are made. https://bitbucket.org/durin42/hg-git/issue/143
Windows / Linux Issues
Refreshing working directory file status is slow
Sometimes refreshing the status of the files in working directory in TortoiseHg workbench can take a while, especially if you have a large number of ignored files like a node_modules folder. The fix is to make a copy of .gitignore and name it .hgignore instead. When .hgignore exists .gitignore is no longer processed so you may miss changes when performing a pull, the solution is to symlink .gitignore to .hgignore. Note you may need to change the ignore syntax to work with Hg since there are differences, also you can add .hgignore into itself so you won’t be shown .hgingore as an uncommited file.
Push restores old branches that others have deleted
Note when you perform a pull hggit does not delete branches locally that others have deleted from the remote repository, so the next time you do a push you end up restoring the deleted branches (Hg by default pushes all branches unlike Git which by default only pushes the current branch, this can be changed via File > Settings > Sync > Default Push
).
The workaround is to add the following to your global settings file File > Settings > Edit File
:
1 | [hooks] |
This deletes all the local bookmarks on pre-pull so that pull will restore only the bookmarks that exist on the remote repository. It does mean you will have to re-do any bookmark changes you’ve made like moving a bookmark to the tip that normally happens automatically when you make a commit before pushing. You may experience an error ocassionally I think with the linux version due to no local bookmarks if so just temporarily comment out the pre-pull setting and after pulling re-enable it.
https://bitbucket.org/durin42/hg-git/issue/107
Can’t clone empty repository
Unlike Hg in Git you cannot clone a repository until you have at least one commit, so this isn’t actually a hggit limitation. You can just create a repository locally using File > New Repository
and then set the remote url via View > Synchronize
and enter url in the textbox then click the save icon to the left of the textbox.
Linux Only Issues
Performing pull is slow
I have experienced it talking a few minutes to perform a pull even when there are no changes to download. This only happens for me with SSH, the workaround is to use HTTPS instead which performs at normal speed (it’s also mentioned upgrading dulwich may solve this but I’ve not tried it after doing so). See here on how to save authentication credentials for HTTPS.
https://bitbucket.org/durin42/hg-git/issue/69
Get “init() got an unexpected keyword argument ‘opener’” error
If you see this error, it likely means your version of dulwich is out of date. Dulwich is a python based implementation of Git that hggit uses.
1 | sudo apt-get remove python-dulwich |
https://bitbucket.org/durin42/hg-git/issue/124
Update: This issue is now resolved so on a version of hggit later than 0.8 you won’t experience this issue but it is still recommended to install the latest version of dulwich anyway.