If you're using Mercurial to collaborate on a project, see the tips and notes on this page.
Edit me
This is my reference notes and quick reference for using Mercurial.
Terminology
- Distributed revision control
- Mercurial is distributed revision control instead of centralized revision control. This means everyone keeps a copy of the repo on their local machine, and then they merge back the changes. With centralized revision control, team members check out a version that remains in a central repo, and it becomes locked when checked out. The latter results in more wait time to check out files, little innovation for experimentation without committing, latency, and other issues.
- Working directory
- The files that Mercurial is tracking in a directory.
- Changeset
- A list of the most recent changes to the repo.
- Tip
- The name of the latest changeset.
- Tags
- A more user-friendly way to name changesets.
- Default
- The name of the main repo. This is defined in the .hg/hgrc file in the `[paths]` section. When you run `hg push` and other commands, if you don't specify another source, the default path gets used.
- Diff
- A list of differences with a file.
- Patch
- Synonym for diff.
- Repo
- The directory where Mercurial is activated.
- head
- A changeset with no child changesets. When you get two heads, it's because you pulled in changes.
- parent
- The previous changeset before the latest change.
- child
- Later in the changeset history. the first parent is the first changeset, and then you have a list of descendants, which are the children.
- merge conflict scenarios
- Merge conflicts happen when add or modify a file that another has removed from one commit to another, you make conflicting changes to the same file from one commit to another, or Mercurial notes some other file discrepancy. When a merge conflict happens, Mercurial launches a merge program to resolve the conflict. When merge conflicts happen, Mercurial removes the problematic files from the working directory until you fix them. You have to add them again to the working directory.
- bookmarks:
- This is a way to create branches in Mercurial. First run
hg bookmark hell
. Then hg checkout hell
. Now you're working in hell. Then run hg bookmark --delete hell
to delete hell.
- branches
- You don't really work with branches in Mercurial. If you create a branch, it's considered a separate line of code. Rarely do you merge branches back in. In this regard, Mercurial differs greatly from Git. However, Mercurial's approach to branching is that you should simply clone the repository. When you want to merge your clone, you pull changes from your clone. There's really no reason to add in this new "branching" functionality when all you're doing is basically the same clone operation.
.
Commands
Commands |
Description |
clone |
copy a specific repository (can be URL or local path) |
init |
initialize Mercurial in the existing repository |
outgoing |
show changes committed locally but not yet pushed |
incoming |
show changes committed to remote but not yet pulled |
pull |
pull the latest changeset into local repo |
pull -u |
pull the latest changeset into local repo and update working directory to that changeset |
fetch |
pull -u + merge + commit (if merge was successful) all in one command |
help -v |
show help in verbose mode |
help (command) |
shows help about a specific command |
summary |
summarizes the state of the current local working directory |
summary –remote |
summarizes the state of the remote working directory |
log |
show history of all change sets in the repo |
log -r 2 -v |
show the history of changeset 2 in the repo, with verbose details |
log -r 2:4 |
show history of change sets from ranges 2 to 4 |
log -p home.md |
show log of changes (patches) for specific file |
log -v -p -r 2 or log -vpr2 |
show a diff of what has changed in a specific changeset (2) |
diff (filename) |
shows differences in a file |
status |
gives you details about the repo’s files that have been modified, added, or removed since the last change. The files in the response will show ? for untracked, A for added, M for modified, and R for removed. |
tip |
show the latest changset |
tip -vp |
show the latest changeset and list verbose details of the differences |
update |
pull the latest changeset into the working directory. By default pull just brings in the changeset, but it doesn’t change your working directory to the latest changeset. |
heads |
Shows the heads in the repo |
addremove |
add all files in directory, remove missing files from previous tracking. (This is the equivalent of using hg add and hg rm for all the files.) |
merge |
After you do a merge, you have to commit the merge. |
commit -m ‘Merged remote changes’ |
|
add |
add a file to Mercurial’s working directory. You can list a filename or a directory. Or “ .” to select all. |
remove |
delete the file and tell Mercurial to stop tracking it. (addremove is a way of bulk doing this.) |
resolve –mark |
|
forget (filename) |
tells Mercurial to stop tracking a file |
branches |
lists the branches created for the repo |
bookmarks |
lists the bookmarks you have set |
bookmark {bookmark_name} |
creates a bookmark named sophia |
checkout {bookmark_name} |
checks out the bookmark. now you’re working in bookmark_name. |
bookmark –delete {bookmark_name |
deletes the bookmark |
revert |
go back to the way the files were at the last commit |
Note: You can add a source for all of these commands. If no source is specified, the default repo (from which the existing repo was cloned) is used. For example, pull (source) will pull from a source other than the default if specified.
When you run hg status
, there are various icons next to the files.
hg status icons |
Description |
! |
Mercurial can’t find the file. You probably deleted it manually and didn’t do an hg rm filename or hg addremove. |
? |
Mercurial doesn’t know anything about this file, even though it’s in the same directory as other files you’re tracking. |
M |
you modified this file. |
A |
Mercurial added this file to the list of files you’re tracking. |
R |
removed from tracking and the directory. |
General workflow
As a general worfklow:
- Commit
- Pull -u (or fetch)
- Merge
- Push
Merge conflicts
When a conflict happens, the default merge program configured in .hgrc launches. P4Merge works well.
To configure Mercurial to use p4merge, install P4Merge, and then put this into your .hgrc file (if it’s not already there).
p4merge.executable = /Applications/p4merge.app/Contents/MacOS/p4merge
p4merge.priority = 50
p4merge.premerge = True
p4merge.gui = True
p4merge.args = $base $local $other $output
p4merge.binary = True
When P4Merge launches to resolve a merge conflict, you select the change you want, or add your own. Then Save. Then quit P4merge completely.
(I am not sure if you have to run hg addremove
and then hg resolve --mark
to mark the conflict as resolved.)
For more details, see P4Merge.
Binary files
P4Merge can’t handle merges with binary files. However, you can run a diff to see the differences between files. You would need to clone your repository and use a different changeset for that repo. Then compare the same file in the different repos in different changesets.
Ignoring certain files
Some files you don’t want in Mercurial because they only have relevance locally. Here is the list of files to ignore to add to your .hgignore file:
.jekyll-metadata
_site
.DS_Store
.idea
If you forget to add certain files to your ignore list, you can add them later and apply the ignore rule retroactively. See this stackoverflow thread for more details. once you make the update, run hg forget "set:hgignore()"
.
Merge conflicts
Here’s the scenario. After you do hg pull -u
, you get this error message:
abort: untracked files in working directory differ from files in requested revision
The problem is that you modified files in your working directory, such as adding or removing a file. Another person added or removed the same file and committed to the repo. Now when you get the latest changeset that has a discrepancy with the added/removed files, Mercurial complains.
For example, Writer A removes file apple.md from his working directory. Writer B adds file apple.md to his working directory. Writer B commits. Now Writer A does a pull -u. At this point, Mercurial responds with the abort message listed above because Writer A’s files don’t match up with the incoming revision.
Theoretically, you can do an hg merge and resolve the issue. However, when I tried this, the abort message didn’t go away.
Saga continued. I’m actually unclear how to resolve this. After fruitless attempts to fix it, I moved on to the nuclear option.
Exercising the Nuclear Option
When you run into problems with Mercurial, you should try to sort it out the best you can. However, if things just won’t behave, you can always exercise the nuclear option.
- Change the name of your “repo” to “repo-old”.
- Reclone the project.
- Copy over the contents from repo-old into repo. (Don’t copy over the .hg. idea, .DS_Store, or .hgignore files.)
Now follow the standard Commit and Push instructions here. It should fix the issue.
Creating a Mercurial Test Playground on Your Local Machine
You can create some local Mercurial repos on your machine so you can play around with commits, merges, and other experiments.
Create a folder and initialize Mercurial in the folder:
This creates a folder called hgrepo. This is your main repository.
Now change into hgrepo and add a file:
cd hgrepo
touch mytestfile.txt
open mytestfile.txt
Type some text and then click Ctrl + S to save it. Then Ctrl + W to close.
Add the file to Mercurial’s tracking and make a commit:
hg addremove
hg commit -m "my first commit"
Now make a couple of clones of the repo:
cd ../
hg clone /Users/tjohnson/projects/hgrepo hgclone1
and
hg clone /Users/tjohnson/projects/hgrepo hgclone2
(Replace /Users/tjohnson/projects/hgrepo with the path to your repo.)
You should now have a file structure that looks like this:
hgrepo
- mytestfile.txt
hgclone1
- mytestfile.txt
hgclone2
- mytestfile.txt
In iTerm, open two separate tabs and go into hgclone1 and hgclone2 on the different tabs. Now you can make changes to mytestfile.txt and commit and push it into the main repo.
Stop Tracking a File
Sometimes you inadvertently add a file into Mercurial that you really don’t want to track. One example is the .jekyll-metadata file that is included by default when you do incremental builds. This file is used locally to remember what changes have been made to your build and what haven’t.
This file shouldn’t be pushed to Mercurial because it will conflict with the content of other people’s .jekyll-metadata files. You need to tell Mercurial to stop tracking the file and then add it to the ignore list.
To stop tracking a file:
If you run the hg addremove command, Mercurial will simply add back the file you ignored.
You should add this file to an ignore list.
- Go to the root directory of your jekyll project.
- Create a file called .hgignore.
- Add each file you want to ignore (e.g., .jekyll-metadata) on a separate line.
- Now make sure that everyone else adds these files to their ignore list. If someone else commits a file that you’ve ignored, Mercurial will complain when you pull the latest revision.