MercurialTips

Mercurial Tips and Tricks

The main documentation for Mercurial is here:

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.

Enter labels to add to this page:
Please wait 
Looking for a label? Just start typing.

Sign up or Log in to add a comment or watch this page.


The individuals who post here are part of the extended Sun Microsystems community and they might not be employed or in any way formally affiliated with Sun Microsystems. The opinions expressed here are their own, are not necessarily reviewed in advance by anyone but the individual authors, and neither Sun nor any other party necessarily agrees with them.

Copyright 1994-2009 Sun Microsystems, Inc.
Powered by Atlassian Confluence
Sun Guidelines on Public Discourse Privacy Policy Terms of Use Trademarks Site Map Employment Investor Relations Contact