Mercurial Tips and Tricks
The main documentation for Mercurial is here:
- http://www.selenic.com/mercurial/wiki/index.cgi/ManPages
- http://www.selenic.com/mercurial/wiki/index.cgi/TipsAndTricks
- http://www.selenic.com/mercurial/hg.1.html (big HG man page)
- http://hgbook.red-bean.com/hgbookch12.html (patch queue information)
Little mercurial languages
The hg man page includes important hard-to-find information on file name patterns and revision number syntax.
Pattern examples:
| pattern | type | relative to | equiv. ^anchored$ RE | equiv. shell name |
|---|---|---|---|---|
| path:foo | pathname | hg root | foo | $(hg root)/foo |
| path:path:foo | pathname | hg root | path:foo | $(hg root)/path:foo |
| glob:*.c | wildcard | pwd | [^/]*[.]c | ./*.c |
| glob:**.c | wildcard | pwd | .*[.]c | $(find . -name '*.c') |
| glob:foo/*.c | wildcard | pwd | foo/[^/]*[.]c | foo/*.c |
| glob:foo/**.c | wildcard | pwd | foo/.*[.]c | $(find foo -name '*.c') |
| re:.*\.c$ | regexp | hg root | .*[.]c | $(find $(hg root) -name '*.c') |
Patterns are quite powerful when used with command options like -X (exclude) and -I (include).
When a file name argument is required (e.g., the qrefresh command), a directory can often act as a sort of wildcard for all the files it (recursively) contains.
File name arguments can be relative to the current directory, even if the current directory is nested under the repository root. But only shell-style ("glob") patterns are interpreted relative to the current directory. Both path-style and RE patterns are always absolute to the repository root.
All these patterns (as well as file name arguments) are anchored; they must match the whole file name. You must use something like .* or ** at the front or end of a pattern to unanchor it.
Within an hgignore file, both glob and regexp syntaxes are supported, as controlled by separate lines (between the ignore patterns) of the form syntax: glob and syntax: regexp. Patterns in the hgignore file are not anchored, so you do not need .* or **, and you must use ^ and/or $ if you want to anchor the ends.
Revision number examples:
| revision | meaning |
|---|---|
| 0 | oldest in repo |
| 1 | second oldest in repo |
| -1 | newest in repo (including mq patches if any) |
| -2 | second newest in repo |
| tip | same as -1 |
| qtip | newest mq patch (same as -1) |
| qbase | oldest mq patch |
| qparent | newest committed rev (pred. to qbase) |
| foo.patch | mq patch, by name |
| jdk7-b24 | a revision tag, specified on commit |
| a61af66fc99e | committed revision by hash |
| a61a | same committed revision (if unique prefix) |
| x:y | interval from x to y inclusive |
| 3:5 | revisions 3, 4, 5 (oldest first) |
| 5:3 | revisions 5, 4, 3 (newest first) |
| x: | same as x:-1 |
| :y | same as 0:y |
| : | same as 0:-1 (all revisions) |
Here are some local favorite tips and tricks:
The fastest workpace clone uses hard links.
But, be aware of how your tools handle hard links. Both mercurial and emacs respect hard links; vi might not.
The Linux/BSD/Mac cp has a nice '-l' option (see http://linux.die.net/man/1/hg):
cp -al $REPO $REPOCLONE
On most any Unix, 'pax -rwl' also works but has a less friendly UI:
REPOCLONE=$(cd $REPOCLONE; pwd -P)
(cd $REPO; pax -rwl -s '|^\./||' . ${REPOCLONE})
A typical hgrc setup might look like this.
$ cd $ ls -l .hgrc lrwxrwxrwx 1 joeuser other 12 Nov 7 19:21 .hgrc -> env/hgrc.txt $ cat env/hgrc.txt [ui] username = joeuser ssh = ssh -C ignore = ~/env/hgignore.txt [extensions] alias = fetch = hbisect = hgext.mq = hgext.forest = ~/env/hgforest/forest.py [alias] qstatus = status --rev -2:-1 qclear = qrefresh -X re:. $ cat env/hgignore.txt ... (see hgignore.txt attachment) $ ls env/hgforest ...
Here is a typical hgignore.txt file .
Managing configuration files in my home directory
I (jrose) like to put my ~/.foo configuration files in a folder called env, symbolically linked under non-dotted names like ~/env/foo.txt. This makes it easier to port around my environment, and to work with the files under Finder.
Working with patch queues (mq)
Patch queues are a great way to keep your work fluid. You don't have to do "hg commit" until you actually do "hg push". That way you can refactor your change sets up to the last moment.
See http://hgbook.red-bean.com/hgbookch12.html for the full information.
Creating a patch
If your working files already have exactly the
content you want, make a new patch in one command by specifying
the repository root directory as an extra argument:
$ vi ... $ hg qnew -f foo.patch "."
You don't need the quotes, once you notice that there's a dot inside them!
Here's an extremely cautious version of patch importing:
$ patch --dry-run -p1 < ...somewhere/foo.patch ... fix patch problems ... $ hg qnew foo.patch # start a new empty patch in my repo $ patch -p1 < ...somewhere/foo.patch ... fix *.rej problems ... vi foo/bar.txt ... # make more changes $ hg addremove -n ... # pick up any files added or removed by the patch $ hg qrefresh # pull accepted diffs into .hg/patches/foo.patch vi baz/bat.txt ... # make more changes $ hg qref # refresh the patch from time to time $ hg qpop # put aside the patch and work on something else $ vi .hg/patches/foo.patch # cheat by tweaking the patch (only when popped!!) $ hg qpush foo.patch # back to work on foo
If you are feeling lucky, the simple command hg qimport will more or less substitute for all of the above.
$ hg qimport ...somewhere/foo.patch
Help, where am I?
$ hg st # aka status; change not yet in any patch
...prints files changed in working copy...
$ hg st --rev -2:qtip # aka the qstatus alias
...prints files changed (only) in the current patch...
$ hg qa # aka qapplied
patchA.patch
patchB.patch
$ hg qu # aka qunapplied
patchC.patch
patchD.patch
$ (hg qa; hg qu) | diff .hg/patches/series - | wc
0 0 0
$ hg qseries | diff .hg/patches/series - | wc
0 0 0
To back out of the current patch queue entry
$ hg diff | wc # no un-queued changes in working files
0 0 0
$ hg qdiff | wc # lots of queued changes in the current patch
30 135 1365
$ qrefresh -X re:. # aka the qclear alias
$ hg qdiff | wc # current patch now has amnesia
0 0 0
$ hg diff | wc # but the diffs are still in the working files
30 135 1365
$ hg qrefresh # pull the changes back into the patch
$ hg qdiff | wc # back to where we started
30 135 1365
To split an external patch in multiple parts by file
$ patch < patchABC*Z # or, assume many files are edited by some other means $ hg qnew -f patchA.patch Afile... $ hg qnew -f patchB.patch Bfile... $ hg qnew -f patchC.patch Cfile... $ hg qnew -f patchZ.patch "." # get rest of changes, if any $ hg status # should be empty now
To split an internal (mq) patch in multiple parts by file
$ hg qa foo.patch $ hg qclear # see alias above $ hg qnew -f patchA.patch Afile... $ hg qnew -f patchB.patch Bfile... $ hg qnew -f patchC.patch Cfile... $ hg qa foo.patch patchA.patch patchB.patch patchC.patch $ hg qgoto qtip-3 # the '3' pops the previous three new patches $ hg qa foo.patch $ hg qrefresh # pull remaining changes, if any, into foo.patch $ hg status # should be empty now
The command hg qrefresh Afile Bfile... is powerful and dangerous, because it collapses the current patch to only the given file(s). Modified working versions of other files can then be pushed into
new patches using hg qnew -f.