How to modify history in TortoiseHg

Risks

Firstly there is no risk to modifying history on commits that you have not pushed. The risk with modifying history that you have pushed is if someone else has already pulled the commits down that you plan to modify. Take for example this:

If another developer were to modify the “Add workspace to app” commit and you pulled down that change, this is what it would look like on your local repository:

The reason this happens is because commits are identified by their hash number (see identifying commits for more details). So because the “Add workspace to app” commit was modified it now has a different hash (including all descendant commits since they’re modified too to update the parent hash reference since it’s changed), so it will appear as a different commit in the commit history alongside the original commit.

To fix you would have to strip the obsolete commit. If you have local changes not yet pushed like in this example you would first have to move them over to the new commit using rebase before stripping the obsolete commits. This is something every developer has to do if they’ve pulled down the original commit. This might be easy to communicate if you’re working within a small team but becomes much harder to communicate if it’s a large team or an open source project online. It can also cause issues with automated test build systems that keeps the repository and just updates to the latest revision between builds. So in general it is recommended not to modify history that has become public unless you know it’ll have no impact. See changeset evolution on how this might not be such a problem in the future. If you want to undo a commit alternatively you can right click the commit and select Backout instead which will create a new commit that un-does the changes without modifying history.

Phases

Now in the commit history you will notice there is a column called Phase. There are three values this can be:

  • Public - this commit has been pushed to a public repository (commits pushed to repos marked non-publishing remain in draft)
  • Draft - this commit has not yet been pushed to a public repository
  • Secret - this commit will not be pushed, pulled or cloned

The idea of the phases is so you know whether it’s safe to modify the commit or not. By default you cannot modify a commit that is public until you change it back to draft by right clicking the commit and selecting Change Phase to > draft. Secret is helpful when you are working on changes locally but don’t want to accidently push the commit when pushing other commits.

Append

Append is a quick way to allow you to modify the most recent commit. To do this you click the down arrow to the right of the commit button and select Ammend current revision:

Append allows you to do things like modify the commit message, or add/remove/modify files. But it doesn’t allow you to undo removing or adding a file from the commit, for that see MQ. Note a backup of the original commit is kept under .hg/strip-backup.

Strip

To use strip you will need to enable the strip extension. Strip allows you to remove commits from your repository. Let’s take this example:

Let’s say you wanted to remove the “Renamed help file, add service” commit and descendant. Just right click on the “Renamed help file, add service” commit then select Modify history > Strip:

To remove only the selected commit but keep the decendant commits see MQ. Note a backup of the commits you removed is kept under .hg/strip-backup. These files can be restored by going to View > Synchronize then clicking the Unbundle icon and selecting the file under the strip-backup folder. Note in order to remove commits on a remote repository the strip command will need to be run on that repository, you cannot do this through push. Services like Bitbucket add an option in settings that allow you to specify a commit that you want to strip.

Rebase

To use rebase you will need to enable the rebase extension. Rebase allows you to move one or more commits to the head of another branch. Lets take the example that you have local commits and you’ve just done a pull and find someone else has already done a commit so that you now have two heads:

First update to the commit you want to move your commit to:

Then right click on the commit you want to move and select Modify history > Rebase. This will change the parent of the selected commit to the commit you are currently updated to (which doesn’t have to be the tip).

You can also use rebase to fold commits, just update to the parent commit then rebase the child commit to the same location but select the collapse the rebased changesets option. This collapses all descendant commits, if you want control over which commits to collapse see MQ.

MQ

To use mq you will need to enable the mq extension. MQ stands for mercurial queues and provides a way to import commits into a queue (turns them into patches) where you can make changes and then reapply the patches. Unlike the Append and Strip commands MQ does not provide a backup of the original commits, so if you want a backup before starting you can just clone your local repository.

Import commits into a queue

Select the commit you would like to modify then right click and select Modify history > Import to MQ.

Here you can see I imported the “Add unit tests” commit so it and it’s descendants now have patches. The filenames of the patches, e.g. 2.diff, have been added as tags to the commits.

Refresh a patch

To change a commit double click it (this either applies the patch or unapplies the one after which can also be done by right clicking and accessing the option from the Modify history menu). If the commit is selected, you should now see that the commit button says QRefresh, in this example I’m modifying the “Add unit tests” commit.

You can now make changes to the files, here you can untick a file to undo add/delete from the commit unlike Append. Once you have finished click the QRefresh button.

Delete a patch

To delete a patch first make sure it’s unapplied (by double clicking the commit before it) then right click and select Delete patches. This allows you to delete a commit in the middle of the history unlike strip.

Create a new patch

To create a new patch double click the commit you want to appear before. Then make your file changes and then select the working directory in commit history and click QNew just like a normal commit.

Change patch order

To change patch order, first unapply all the patches you want to change order, then you can drag and drop the patches in the order you want them.

Fold patches

To fold patches double click the first commit to be folded (in this example it’s the “Add unit tests” commit). Then select the commits you would like to merge into it then right click and select Fold patches.

Finish patch

Once you have finished double click the last commit, in order to apply all the patches, then you can right click the last commit and choose Modify history > Finish Patch, then they will no longer be in the queue.

Create a new queue

You can view the queue of patches bottom left of TortoiseHg by selecting View > Show Patch Queue. Here you can create a new queue and use the dropdown to switch between queues.

The commit to queue actually commits the patches to a new repository created in the .hg/queue-name folder.

HistEdit

To use histedit you need to enable the histedit extension. Histedit provides similar capabilities to MQ in what you can do to alter history but without the patches and queues. There is no GUI support for histedit so you run it from the console which you can view within TortoiseHg by going to View > Show Console. See below for details on how to use this extension.

http://mercurial.selenic.com/wiki/HisteditExtension

Changeset Evolution

The risks section explained the dangers of rewriting public history. The idea behind the changeset evolution set of extensions, is instead of stripping the original commit from history, it adds an obsolescence marker to the commit along with a reference to the commit that supersedes it. Then when other developers pull down the changes the original commits will now be marked obselete and therefore hidden, and their local changes can be automatically moved to the new commit that superseded it. Note this supports append, rebase and histedit but not mq. For more details see:

http://mercurial.selenic.com/wiki/ChangesetEvolution

How to use TortoiseHg

Intro

Here is a guide on how to use TortoiseHg. This guide mostly contains things you’ll probably pick up after just a few days working with TortoiseHg, but it also contains tips I didn’t learn until much later. For those new to Hg from a SVN background basically in Hg the entire repository is located in your working folder so commit and update happens in your own copy of the repository. When you’re ready you can push one or more commits to a central repository other developers also work with, or pull new commits from the central repository to your local repository. You also have the option of push/pull from a different repository as well.

While a number of things can be done via context menus in file explorer, this guide will be focused on doing everything inside TortoiseHg Workbench. Also to learn the Hg commands for all these steps you can open View > Show Console and see what was run when you performed the step in the GUI, you can also just enter Hg commands here if that’s faster.

Creating a new repository

While you can create a repository on you local machine by File > New Repository and even serve it up over HTTP by Repository > Web Server, it is recommended to use an online source hosting servce. This is because an online service provides better backup protection in case something happens to your machine and makes it easier to share your repository with others since you’re not having to maintain your own server. The two most popular ones are bitbucket and github and both offer free plans, bitbucket is great because it supports Hg as well as Git but github only supports Git so you’ll need to use the hggit extension, see using tortoisehg with git for details.

https://bitbucket.org/plans
https://github.com/pricing

Authentication

HTTP/S

HTTP/S auth will work straight away prompting you for username or password every time you do a push or pull. In order to save the credentials the recommended approach is to enable the mercurial_keyring extension to securely store the password (see Settings file / enabling extensions on how to do this). Once enabled as long as you specify the username either in the repository url https://username@domain.com/repo (hggit doesn’t support this) or in the settings files:

Then the next time you do a push or pull you will only be prompted for password and this will automatically be saved for future use. How the settings file works is gh or bb can be anything and is just a way to group the auth settings together. If the prefix matches part of the repository url then the specified username will be used. The password can also be defined here in the settings file but then it’s being stored in plain text in a known location which is less secure than using mercurial_keyring.

While mercurial_keyring extension is available under Windows, under Linux you will have to install it first before it will appear under TortoiseHg extensions that you can enable:

1
2
3
easy_install keyring
easy_install keyrings.alt
easy_install mercurial_keyring

SSH

Here is a guide you can follow to setup SSH on Windows:
https://confluence.atlassian.com/display/BITBUCKET/Set+up+SSH+for+Mercurial

Linux SSH guide:
https://confluence.atlassian.com/pages/viewpage.action?pageId=271943168

Cloning a repository

File > Clone repository

Making a commit

In order to commit you must either select the working directory in the commit history or click the commit icon (green tick) in the top toolbar. To make a commit tick the files you want to include, type a commit message and click the commit button:

Note if it’s a new file that was unversioned you will be prompted to add untracked files. You can right click the file and select Add file before clicking the commit button if you want, but it will still only be included as part of the commit if you have ticked the first.

The file list only shows changes so if you don’t see the change you want to commit just click the refresh button just above the file list.

Specifying username

If you click options just above the commit message window, you should see this dialog:

There you can specify the username, and optionally save this either in your settings file for the local repository or the global settings file for future commits. Note if you use your github or bitbucket login email address the username on the commit online will appear linked to your account, if you want to keep your email address private for github you can use Display Name <username@users.noreply.github.com> and for bitbucket under settings on the website for the repository you can map names to user accounts.

Commit chunks

To commit only parts of a changed file, click the file in the file list then on the right hand side you can see a list of the changes, in that window you can tick what changes you want to include in the commit:

Rename files

To handle renaming of files in order to keep file history, you can either right click on the renamed file and select Was renamed from > original filename. Or you can use the detect renames dialog by right clicking on any file and selecting Detect renames:

Under unversioned files, select the file that was renamed and click find renames, you can lower the Min Similarity setting if the renamed file has been changed and a match was not found. Once a match has been found you can click on Accept all matches or if multiple matches are found select the correct match under candidate matches and click on Accept selected matches. Note this can also be useful when splitting a file in two but you want the same file history for both files before the split, in this case just untick Only consider deleted files before attempting to find a match. If you struggle to find a match you can undo the rename and then in file explorer rename the file by right clicking and selecting TortoiseHg > Rename file.

Deleting files

You can just tick the deleted file and when you click the commit button you will be prompted to remove selected deleted files. If you right click the file in the file list you don’t see an option to delete file just Forget file. What forget means is remove the file from source control but not actually delete it from the file system. In file explorer the is an option called Remove file that will both forget the file from source control as well as delete the file from the file system.

Ignoring files

If there a untracked files in the file list you want to ignore right click on one of those files and click Ignore files.

At the top you can select what kind of syntax you want to use glob or regexp, then specify the filter and click add. The filter should now appear in the left column, and the current list of untracked files not ignored should appear in the right hand side so you can see straight if your filter worked as expected or not. You can also click on an untracked file to prefill the filter textbox with the filename ready to create a new filter.

Note this creates a .hgingore file which you can add to source control. If you want to have a second .hgignore file that you don’t want to add to source control you can add this to your settings file:

Then in the ignore dialog you can click the dropdown to switch between ignore files. You can locate this ignore file anywhere you like some like to locate it under the .hg folder and some just at the root of their repository and then add the filename to itself to ignore.

Viewing a diff

In the file list of changes you can right click the file and select Diff to Parent to view the changes in KDiff3.

Revert changes

If you want to revert changes that have been made. In the file list just right click on the file and select Revert. If you only want to revert some of the changes see shelving changes where you can shelve the bits you want to keep, then you can revert file, then you can restore the shelved changes.

If you revert an added file, it just becomes untracked so delete file you need to right click file and select Delete Unversioned. If you revert a missing or file it will be restored.

Push / pull commits to a remote repository

After commiting changes to your local repository you need to push those commits to a remote repository. At the right hand side of the toolbar at the top there are buttons for performing a push or pull, and also buttons to preview what will be pushed or pulled.

Now when you attempt to push you may see this error:

This basically means there are new commits on the remote repository you need to pull first before you can push, after pulling you will see something like this in your history graph:

Now if you try to push you will get an error because there are now two heads to this branch when there can only be one. There are two approaches, you can either merge:

Or you can rebase:

Rebase is nice in that it keeps the history linear which makes it easier to follow so tends to be the preferred approach. Now that you have one head you are now ready to push.

Update

The idea of update is to update your working directory to a particular version in your source control history. This can be done by right clicking on the commit in commit history you want to update to and selecting Update from the context menu. If you have local uncommitted changes you may be prompted to either discard or shelve those changes.

Shelving changes

The idea of shelving changes is to temporarily move changes made to your working directory in another location so they can be restored later. To open the shelve tool select the working directory in commit history and then click this icon just below the commit message window:

Now you should see this:

On the left column you should see a list of changes in the working directory. On the right column you should see a list of changes in the shelf I’ve called Default. Before you can start moving changes across you will need to create a new shelf by clicking the icon just above the shelf dropdown on the left side of the right column. You can now click the Move all files or Move selected files icons at the top to move file changes between the working directory and the shelf. You can even select parts of a file change by selecting the file and then ticking underneath what chunks you want to copy and then clicking the Move selected chunks button as illustrated in the image above.

Note you can create more than one shelf, and even select a shelf in the dropdown in the left column to move changes between shelves. Clear just empties the shelf or working directory of all changes, and delete will delete the shelf.

Handling conflicts

Sometimes if when you try to restore changes you have shelved to your working directory you may see this:

When you yes you will see something like this:

How this dialog works is in top box it shows the current file in the working directory which you can edit here. Underneath are two columns, the first column is a list of the changes or chunks for the file that are in the shelf, the second column shows what the change is for the selected chunk.

The idea here is that you manually apply the change for the selected chunk to the top box and then click the green tick between the two columns to say it’s resolved before proceeding to the next chunk. When you have finished you click save.

Branches

To create a new branch, click the branch label just above the commit message window:

And you should see this:

From here you can create new branches or close existing branches, this change happens once you have completed the commit. Note you filter the commit history to only show commits for a specified branch, first select the Filter graph with revision sets icon from the toolbar at the top. When the filter toolbar appears you can select the branch you want from the dropdown on the right hand side.

Merging / handling conflicts

When you want to merge between branches update to the branch you want to merge the changes into by selecting the latest commit then right click and select Update. If you are merging between two heads of the same branch then it doesn’t matter which head you pick to update to. Then you select the head of the other branch and then right click and select Merge with Local like below:

You will see a dialog called Prepare to merge here you may need to discard or shelve local uncomitted changes before continuing then click next. If on the next screen you see this:

You have merge conflicts that need resolving, to resolve click the highlighted word Resolve and you should see this:

Here there are five options:

  • Mercurial Resolve - allow mercurial to attempt to automatically resolve the conflict for example if the changes are located in different parts of the file then this should work
  • Tool Resolve - this also attempts to automatically resolve using the configured diff tool instead (by default KDiff3) and if this fails will show a dialog where you can manually resolve the dialog
  • Take Local - chooses the file from the branch/head that you updated to over the one you merging from
  • Take Other - chooses the file from the branch/head that you are merging from over the one you have updated to
  • Mark as Resolved - at this point you can open the file in conflict from the working directory and manually resolve it in a text editor, when you’re finished you can come back to this dialog and select mark as resolved

Usually you can just just select all the conflicted files and choose tool resolve, this is the dialog it shows (if using KDiff3) if there is a conflict on a particular line:

On the left column (A) is the common ancestor for both heads, in the middle column (B) you have the current head you have updated to, and on the right column (C) is the head you a merging from. And at the bottom shows the merged output, so here you can see the line that has caused the conflict.

So toolbar you can select what lines you want from A, B or C. In this case looking at the diff we see we probably want the lines from B and C as shown:

Now that the first conflict is resolved we can click the triple down arrow in the toolbar to proceed to the next conflict:

Now for this conflict we also want to pick the lines from B and C as shown. However here you can see that the output is invalid and needs to be manually fixed:

To fix the output window is editable so you can manually fix the conflict like below.

Once there are no more conflicts, the next conflict button is disabled, you can click save at the top and then close the window. Once all the conflicts are resolved you can close TortoiseHg’s resolve conflicts dialog and click next on the merge window. On this next screen you can enter the commit message and then click Commit Now. You are now done.

Graft / Transplant

To use graft you will need to enable the transplant extension. Graft allows you to copy one commit from one branch to another. Take for example this scenario:

To copy the “Add build status to readme” commit to the default branch, we would first update to the default branch, then right click the commit we want to copy and select Graft to Local. You have now copied the commit:

Annotating files (Blame)

To look at the history of a file, simply right click on the file in the file list of changes and select File History / Annotate. If you do not see the file since it hasn’t changed you can either find it in file explorer or right click the working directory in the commit history and select Browse at Revision and then find the file there. Now you will see a dialog like this:

Here you can see a list of commits when the file was changed, which you can select to see what the changes were. At the top of the bottom box you can toggle between three different views, the first two allow you to switch between diff style views patch and inline (you can still right click the commit and select Diff to Parent to use a diffing tool like KDiff3). And the last view is called annotate which displays the whole file with the revision number on the left hand side of each line when that line was last changed, you can then hover over that line to see who made the commit and what the commit message was in the status bar.

Identifying commits

Note that the revision numbers you see in your commit history can be different to the revision numbers other developers see in their local repository. This is simply because the numbers are incremental in the order the commits are made on your local repository. For example if you made a commit and then pulled a new commit in and then merged before pushing your commit history will look like this:

While the other developer who made the new commit, after they pull your changes in his commit history will look like this:

Instead the reliable way to identify a commit when working with other developers is by it’s hash, right click on a commit and select Copy Hash as this will be the same on both yours and other developers repositories. The purpose of the revision number is to simplify working with Hg from the console on your local repository where a revision number is much shorter and easier to remeber than a hash (you can use just the start of the hash as well), all commands accept either a hash or revision number.

Note if you use hggit then your local hash will be different to the remote repository’s commit hash since your local repository is mercurial and the remote repository is git and they both store commits in a different way hence the generated hash will be different. Not sure if it’s the same as other developers using hggit though.

Tags

Tags are simply a label you can attach to a particular commit, this is stored in a .hgtags file at the root of your repository. These can be useful for things like tagging what commit relates to a particular version of your software that was released. When creating a tag under options you can specify local tag, this simply means the tag is only local to your repository and won’t get pushed to remote repositories, it does this by storing the tag information under .hg/localtags instead. The commit message options are because adding a tag automatically adds a commit for this change and you can customize what that commit message is or just use the default.

Settings file / enabling extensions

To open the main settings dialog right click on a repository and select Settings:

At the top of the settings dialog you will see two tabs, the first is global settings and here you can configure the default settings you want to use across all your repositories. The second tab is repository settings and these, which can override the global settings, only apply for the selected repository.

All settings changes made through the GUI are saved in the settings file allowing for easy restore and backup. It also allows you to enter settings directly in the file instead of through the GUI. To open just click Edit File located at the top, the file for the repository settings is separate to the file for the global settings.

To enable various extensions you can either enable them using the GUI:

Or directly in the settings file.

If you are installing an extension not bundled with TortoiseHg then you need to specify the file path. Usually this is done by cloning the repository and then providing the file path to the folder containing the file called __init__.py which maybe a subfolder in the repository.

If you want to share settings between repositories, but not with every repository which the global settings file does, then you can create a new settings file and import it in you repositories settings file like this:

Pull requests

And finally just a quick mention about pull requests or forking you may often seen mention. This is more related to services like Github or Bitbucket than TortoiseHg. The idea is if there is an open source project you’d like to contribute to but don’t have write access to, you would click the fork button on the repository’s webpage to make a copy of the repository under your account. You can then clone that repository to your local machine and commit changes that you push back up to the online forked repository. You can then click the create pull request button on your online forked repository that will appear on the original repository listing the new commits you have made. Here they can see the combined diff of all your commits and make comments on what they’d like to see changed before they accept it. They may want you to combine all the commits into one or change existing commits instead of making new ones, see here about how to do this by rewriting history. If they accept it, the pull request will be merged into the original repository and you have now contributed to an open source project.

Another usage is when working on your own repository in a team. Here you might create a branch to work on an issue, when you are ready you create a pull request that another developer reviews, if they accept it the pull request gets merged into the main branch and the issue branch can be closed.

Linking commits to online issues / changesets

It is possible for TortoiseHg to automatically turn issue numbers or planning story numbers into hyperlinks to the relevant webpage.

So here you could link to the github or bitbucket issue you’re fixing, in this example I’m linking any number prefixed with a ‘#’. But this could also be used for story planning cards like JIRA and you can make this mandatory so that you will be prevented from making a commit without one. You can also link the commits hash to the online view of the commit. Note you may need to restart TortoiseHg for these changes to take effect. Below you can see the changeset hash and issue number in the commit message turned into a hyperlink:

Using TortoiseHg with Git

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
2
3
git+https://github.com/company/project.git
git+ssh://git@github.com/company/project.git
git://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
2
[extensions]
hggit = /path/hg-git/hggit or C:\path\hg-git\hggit

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
2
3
4
5
[hooks]
# linux
pre-pull = powershell.exe -command "& { hg bookmarks | %{$_.trim('*',' ').split(' ')[0]} | %{hg bookmark -d $_} }"
# windows
pre-pull = hg bookmarks | tr -d '*' | tr -s ' ' | cut -d ' ' -f 2 | xargs hg bookmark -d

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
2
3
4
5
6
7
sudo apt-get remove python-dulwich
cd /tmp
# get url for latest version here https://pypi.python.org/pypi/dulwich
wget https://pypi.python.org/packages/source/d/dulwich/dulwich-0.9.8.tar.gz
tar zxvf dulwich-0.9.8.tar.gz
cd dulwich-0.9.8
sudo python setup.py --pure install

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.

How to install TortoiseHg on Ubuntu

There are linux installation packages available you can use: http://tortoisehg.bitbucket.org/download/#linux. But most of these are for old versions of TortoiseHg, so if you want the latest installing from source is the only way. So the following are the instructions on how to do this.

Install Mercurial

1
2
3
4
5
6
7
8
9
10
11
sudo su 
apt-get purge mercurial tortoisehg tortoisehg-nautilus python-dulwich mercurial-common
apt-get install python-dev python-docutils checkinstall python-qt4 pyqt4-dev-tools python-qscintilla2 appmenu-gtk python-nautilus python-setuptools python-iniparse
cd /tmp
# get latest url for source release from http://mercurial.selenic.com/downloads
wget http://mercurial.selenic.com/release/mercurial-3.7.1.tar.gz
tar zxvf mercurial-3.7.1.tar.gz
cd mercurial-3.7.1
make local
checkinstall # the default settings are fine so can just hit enter
hg version

Install TortoiseHg

1
2
3
4
5
6
cd ~/
hg clone http://bitbucket.org/tortoisehg/thg tortoisehg
cd tortoisehg/
hg update stable
ln -s ~/tortoisehg/thg /usr/bin
echo "%include ~/tortoisehg/contrib/mergetools.rc" >> ~/.hgrc

Integrate into File Explorer (Nautilus)

1
2
mkdir -p ~/.local/share/nautilus-python/extensions 
ln -s ~/tortoisehg/contrib/nautilus-thg.py ~/.local/share/nautilus-python/extensions nautilus -q

If you’d like to use HTTP/S when working with remote repositories see here on setting up mercurial_keyring to securely store passwords.

If using TortoiseHg with Git, it is recommended to update Dulwich to the latest version see here for details.

To Update

1
2
3
4
5
6
7
8
9
10
11
sudo su
cd /tmp
wget http://mercurial.selenic.com/release/mercurial-3.8.tar.gz
tar zxvf mercurial-3.8.tar.gz
cd mercurial-3.8
make local
checkinstall

cd ~/tortoisehg
hg pull
hg update stable