##// END OF EJS Templates
help: explain that revsets can be used where 1 or 2 revs are wanted...
Martin von Zweigbergk -
r30771:c2cbc1b0 default
parent child Browse files
Show More
@@ -1,190 +1,206 b''
1 1 Mercurial supports several ways to specify revisions.
2 2
3 3 Specifying single revisions
4 4 ===========================
5 5
6 6 A plain integer is treated as a revision number. Negative integers are
7 7 treated as sequential offsets from the tip, with -1 denoting the tip,
8 8 -2 denoting the revision prior to the tip, and so forth.
9 9
10 10 A 40-digit hexadecimal string is treated as a unique revision identifier.
11 11 A hexadecimal string less than 40 characters long is treated as a
12 12 unique revision identifier and is referred to as a short-form
13 13 identifier. A short-form identifier is only valid if it is the prefix
14 14 of exactly one full-length identifier.
15 15
16 16 Any other string is treated as a bookmark, tag, or branch name. A
17 17 bookmark is a movable pointer to a revision. A tag is a permanent name
18 18 associated with a revision. A branch name denotes the tipmost open branch head
19 19 of that branch - or if they are all closed, the tipmost closed head of the
20 20 branch. Bookmark, tag, and branch names must not contain the ":" character.
21 21
22 22 The reserved name "tip" always identifies the most recent revision.
23 23
24 24 The reserved name "null" indicates the null revision. This is the
25 25 revision of an empty repository, and the parent of revision 0.
26 26
27 27 The reserved name "." indicates the working directory parent. If no
28 28 working directory is checked out, it is equivalent to null. If an
29 29 uncommitted merge is in progress, "." is the revision of the first
30 30 parent.
31 31
32 Finally, commands that expect a single revision (like ``hg update``) also
33 accept revsets (see below for details). When given a revset, they use the
34 last revision of the revset. A few commands accept two single revisions
35 (like ``hg diff``). When given a revset, they use the first and the last
36 revisions of the revset.
37
32 38 Specifying multiple revisions
33 39 =============================
34 40
35 41 Mercurial supports a functional language for selecting a set of
36 42 revisions. Expressions in this language are called revsets.
37 43
38 44 The language supports a number of predicates which are joined by infix
39 45 operators. Parenthesis can be used for grouping.
40 46
41 47 Identifiers such as branch names may need quoting with single or
42 48 double quotes if they contain characters like ``-`` or if they match
43 49 one of the predefined predicates.
44 50
45 51 Special characters can be used in quoted identifiers by escaping them,
46 52 e.g., ``\n`` is interpreted as a newline. To prevent them from being
47 53 interpreted, strings can be prefixed with ``r``, e.g. ``r'...'``.
48 54
49 55 Operators
50 56 =========
51 57
52 58 There is a single prefix operator:
53 59
54 60 ``not x``
55 61 Changesets not in x. Short form is ``! x``.
56 62
57 63 These are the supported infix operators:
58 64
59 65 ``x::y``
60 66 A DAG range, meaning all changesets that are descendants of x and
61 67 ancestors of y, including x and y themselves. If the first endpoint
62 68 is left out, this is equivalent to ``ancestors(y)``, if the second
63 69 is left out it is equivalent to ``descendants(x)``.
64 70
65 71 An alternative syntax is ``x..y``.
66 72
67 73 ``x:y``
68 74 All changesets with revision numbers between x and y, both
69 75 inclusive. Either endpoint can be left out, they default to 0 and
70 76 tip.
71 77
72 78 ``x and y``
73 79 The intersection of changesets in x and y. Short form is ``x & y``.
74 80
75 81 ``x or y``
76 82 The union of changesets in x and y. There are two alternative short
77 83 forms: ``x | y`` and ``x + y``.
78 84
79 85 ``x - y``
80 86 Changesets in x but not in y.
81 87
82 88 ``x % y``
83 89 Changesets that are ancestors of x but not ancestors of y (i.e. ::x - ::y).
84 90 This is shorthand notation for ``only(x, y)`` (see below). The second
85 91 argument is optional and, if left out, is equivalent to ``only(x)``.
86 92
87 93 ``x^n``
88 94 The nth parent of x, n == 0, 1, or 2.
89 95 For n == 0, x; for n == 1, the first parent of each changeset in x;
90 96 for n == 2, the second parent of changeset in x.
91 97
92 98 ``x~n``
93 99 The nth first ancestor of x; ``x~0`` is x; ``x~3`` is ``x^^^``.
94 100
95 101 ``x ## y``
96 102 Concatenate strings and identifiers into one string.
97 103
98 104 All other prefix, infix and postfix operators have lower priority than
99 105 ``##``. For example, ``a1 ## a2~2`` is equivalent to ``(a1 ## a2)~2``.
100 106
101 107 For example::
102 108
103 109 [revsetalias]
104 110 issue(a1) = grep(r'\bissue[ :]?' ## a1 ## r'\b|\bbug\(' ## a1 ## r'\)')
105 111
106 112 ``issue(1234)`` is equivalent to
107 113 ``grep(r'\bissue[ :]?1234\b|\bbug\(1234\)')``
108 114 in this case. This matches against all of "issue 1234", "issue:1234",
109 115 "issue1234" and "bug(1234)".
110 116
111 117 There is a single postfix operator:
112 118
113 119 ``x^``
114 120 Equivalent to ``x^1``, the first parent of each changeset in x.
115 121
116 122 Predicates
117 123 ==========
118 124
119 125 The following predicates are supported:
120 126
121 127 .. predicatesmarker
122 128
123 129 Aliases
124 130 =======
125 131
126 132 New predicates (known as "aliases") can be defined, using any combination of
127 133 existing predicates or other aliases. An alias definition looks like::
128 134
129 135 <alias> = <definition>
130 136
131 137 in the ``revsetalias`` section of a Mercurial configuration file. Arguments
132 138 of the form `a1`, `a2`, etc. are substituted from the alias into the
133 139 definition.
134 140
135 141 For example,
136 142
137 143 ::
138 144
139 145 [revsetalias]
140 146 h = heads()
141 147 d(s) = sort(s, date)
142 148 rs(s, k) = reverse(sort(s, k))
143 149
144 150 defines three aliases, ``h``, ``d``, and ``rs``. ``rs(0:tip, author)`` is
145 151 exactly equivalent to ``reverse(sort(0:tip, author))``.
146 152
147 153 Equivalents
148 154 ===========
149 155
150 156 Command line equivalents for :hg:`log`::
151 157
152 158 -f -> ::.
153 159 -d x -> date(x)
154 160 -k x -> keyword(x)
155 161 -m -> merge()
156 162 -u x -> user(x)
157 163 -b x -> branch(x)
158 164 -P x -> !::x
159 165 -l x -> limit(expr, x)
160 166
161 167 Examples
162 168 ========
163 169
164 170 Some sample queries:
165 171
166 172 - Changesets on the default branch::
167 173
168 174 hg log -r "branch(default)"
169 175
170 176 - Changesets on the default branch since tag 1.5 (excluding merges)::
171 177
172 178 hg log -r "branch(default) and 1.5:: and not merge()"
173 179
174 180 - Open branch heads::
175 181
176 182 hg log -r "head() and not closed()"
177 183
178 184 - Changesets between tags 1.3 and 1.5 mentioning "bug" that affect
179 185 ``hgext/*``::
180 186
181 187 hg log -r "1.3::1.5 and keyword(bug) and file('hgext/*')"
182 188
183 189 - Changesets committed in May 2008, sorted by user::
184 190
185 191 hg log -r "sort(date('May 2008'), user)"
186 192
187 193 - Changesets mentioning "bug" or "issue" that are not in a tagged
188 194 release::
189 195
190 196 hg log -r "(keyword(bug) or keyword(issue)) and not ancestors(tag())"
197
198 - Update to commit that bookmark @ is pointing too, without activating the
199 bookmark (this works because the last revision of the revset is used)::
200
201 hg update :@
202
203 - Show diff between tags 1.3 and 1.5 (this works because the first and the
204 last revisions of the revset are used)::
205
206 hg diff -r 1.3::1.5
@@ -1,1527 +1,1527 b''
1 1 Test basic extension support
2 2
3 3 $ cat > foobar.py <<EOF
4 4 > import os
5 5 > from mercurial import cmdutil, commands
6 6 > cmdtable = {}
7 7 > command = cmdutil.command(cmdtable)
8 8 > def uisetup(ui):
9 9 > ui.write("uisetup called\\n")
10 10 > ui.flush()
11 11 > def reposetup(ui, repo):
12 12 > ui.write("reposetup called for %s\\n" % os.path.basename(repo.root))
13 13 > ui.write("ui %s= repo.ui\\n" % (ui == repo.ui and "=" or "!"))
14 14 > ui.flush()
15 15 > @command('foo', [], 'hg foo')
16 16 > def foo(ui, *args, **kwargs):
17 17 > ui.write("Foo\\n")
18 18 > @command('bar', [], 'hg bar', norepo=True)
19 19 > def bar(ui, *args, **kwargs):
20 20 > ui.write("Bar\\n")
21 21 > EOF
22 22 $ abspath=`pwd`/foobar.py
23 23
24 24 $ mkdir barfoo
25 25 $ cp foobar.py barfoo/__init__.py
26 26 $ barfoopath=`pwd`/barfoo
27 27
28 28 $ hg init a
29 29 $ cd a
30 30 $ echo foo > file
31 31 $ hg add file
32 32 $ hg commit -m 'add file'
33 33
34 34 $ echo '[extensions]' >> $HGRCPATH
35 35 $ echo "foobar = $abspath" >> $HGRCPATH
36 36 $ hg foo
37 37 uisetup called
38 38 reposetup called for a
39 39 ui == repo.ui
40 40 Foo
41 41
42 42 $ cd ..
43 43 $ hg clone a b
44 44 uisetup called
45 45 reposetup called for a
46 46 ui == repo.ui
47 47 reposetup called for b
48 48 ui == repo.ui
49 49 updating to branch default
50 50 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
51 51
52 52 $ hg bar
53 53 uisetup called
54 54 Bar
55 55 $ echo 'foobar = !' >> $HGRCPATH
56 56
57 57 module/__init__.py-style
58 58
59 59 $ echo "barfoo = $barfoopath" >> $HGRCPATH
60 60 $ cd a
61 61 $ hg foo
62 62 uisetup called
63 63 reposetup called for a
64 64 ui == repo.ui
65 65 Foo
66 66 $ echo 'barfoo = !' >> $HGRCPATH
67 67
68 68 Check that extensions are loaded in phases:
69 69
70 70 $ cat > foo.py <<EOF
71 71 > import os
72 72 > name = os.path.basename(__file__).rsplit('.', 1)[0]
73 73 > print "1) %s imported" % name
74 74 > def uisetup(ui):
75 75 > print "2) %s uisetup" % name
76 76 > def extsetup():
77 77 > print "3) %s extsetup" % name
78 78 > def reposetup(ui, repo):
79 79 > print "4) %s reposetup" % name
80 80 > EOF
81 81
82 82 $ cp foo.py bar.py
83 83 $ echo 'foo = foo.py' >> $HGRCPATH
84 84 $ echo 'bar = bar.py' >> $HGRCPATH
85 85
86 86 Command with no output, we just want to see the extensions loaded:
87 87
88 88 $ hg paths
89 89 1) foo imported
90 90 1) bar imported
91 91 2) foo uisetup
92 92 2) bar uisetup
93 93 3) foo extsetup
94 94 3) bar extsetup
95 95 4) foo reposetup
96 96 4) bar reposetup
97 97
98 98 Check hgweb's load order:
99 99
100 100 $ cat > hgweb.cgi <<EOF
101 101 > #!/usr/bin/env python
102 102 > from mercurial import demandimport; demandimport.enable()
103 103 > from mercurial.hgweb import hgweb
104 104 > from mercurial.hgweb import wsgicgi
105 105 > application = hgweb('.', 'test repo')
106 106 > wsgicgi.launch(application)
107 107 > EOF
108 108
109 109 $ REQUEST_METHOD='GET' PATH_INFO='/' SCRIPT_NAME='' QUERY_STRING='' \
110 110 > SERVER_PORT='80' SERVER_NAME='localhost' python hgweb.cgi \
111 111 > | grep '^[0-9]) ' # ignores HTML output
112 112 1) foo imported
113 113 1) bar imported
114 114 2) foo uisetup
115 115 2) bar uisetup
116 116 3) foo extsetup
117 117 3) bar extsetup
118 118 4) foo reposetup
119 119 4) bar reposetup
120 120
121 121 $ echo 'foo = !' >> $HGRCPATH
122 122 $ echo 'bar = !' >> $HGRCPATH
123 123
124 124 Check "from __future__ import absolute_import" support for external libraries
125 125
126 126 #if windows
127 127 $ PATHSEP=";"
128 128 #else
129 129 $ PATHSEP=":"
130 130 #endif
131 131 $ export PATHSEP
132 132
133 133 $ mkdir $TESTTMP/libroot
134 134 $ echo "s = 'libroot/ambig.py'" > $TESTTMP/libroot/ambig.py
135 135 $ mkdir $TESTTMP/libroot/mod
136 136 $ touch $TESTTMP/libroot/mod/__init__.py
137 137 $ echo "s = 'libroot/mod/ambig.py'" > $TESTTMP/libroot/mod/ambig.py
138 138
139 139 #if absimport
140 140 $ cat > $TESTTMP/libroot/mod/ambigabs.py <<EOF
141 141 > from __future__ import absolute_import
142 142 > import ambig # should load "libroot/ambig.py"
143 143 > s = ambig.s
144 144 > EOF
145 145 $ cat > loadabs.py <<EOF
146 146 > import mod.ambigabs as ambigabs
147 147 > def extsetup():
148 148 > print 'ambigabs.s=%s' % ambigabs.s
149 149 > EOF
150 150 $ (PYTHONPATH=${PYTHONPATH}${PATHSEP}${TESTTMP}/libroot; hg --config extensions.loadabs=loadabs.py root)
151 151 ambigabs.s=libroot/ambig.py
152 152 $TESTTMP/a (glob)
153 153 #endif
154 154
155 155 #if no-py3k
156 156 $ cat > $TESTTMP/libroot/mod/ambigrel.py <<EOF
157 157 > import ambig # should load "libroot/mod/ambig.py"
158 158 > s = ambig.s
159 159 > EOF
160 160 $ cat > loadrel.py <<EOF
161 161 > import mod.ambigrel as ambigrel
162 162 > def extsetup():
163 163 > print 'ambigrel.s=%s' % ambigrel.s
164 164 > EOF
165 165 $ (PYTHONPATH=${PYTHONPATH}${PATHSEP}${TESTTMP}/libroot; hg --config extensions.loadrel=loadrel.py root)
166 166 ambigrel.s=libroot/mod/ambig.py
167 167 $TESTTMP/a (glob)
168 168 #endif
169 169
170 170 Check absolute/relative import of extension specific modules
171 171
172 172 $ mkdir $TESTTMP/extroot
173 173 $ cat > $TESTTMP/extroot/bar.py <<EOF
174 174 > s = 'this is extroot.bar'
175 175 > EOF
176 176 $ mkdir $TESTTMP/extroot/sub1
177 177 $ cat > $TESTTMP/extroot/sub1/__init__.py <<EOF
178 178 > s = 'this is extroot.sub1.__init__'
179 179 > EOF
180 180 $ cat > $TESTTMP/extroot/sub1/baz.py <<EOF
181 181 > s = 'this is extroot.sub1.baz'
182 182 > EOF
183 183 $ cat > $TESTTMP/extroot/__init__.py <<EOF
184 184 > s = 'this is extroot.__init__'
185 185 > import foo
186 186 > def extsetup(ui):
187 187 > ui.write('(extroot) ', foo.func(), '\n')
188 188 > ui.flush()
189 189 > EOF
190 190
191 191 $ cat > $TESTTMP/extroot/foo.py <<EOF
192 192 > # test absolute import
193 193 > buf = []
194 194 > def func():
195 195 > # "not locals" case
196 196 > import extroot.bar
197 197 > buf.append('import extroot.bar in func(): %s' % extroot.bar.s)
198 198 > return '\n(extroot) '.join(buf)
199 199 > # "fromlist == ('*',)" case
200 200 > from extroot.bar import *
201 201 > buf.append('from extroot.bar import *: %s' % s)
202 202 > # "not fromlist" and "if '.' in name" case
203 203 > import extroot.sub1.baz
204 204 > buf.append('import extroot.sub1.baz: %s' % extroot.sub1.baz.s)
205 205 > # "not fromlist" and NOT "if '.' in name" case
206 206 > import extroot
207 207 > buf.append('import extroot: %s' % extroot.s)
208 208 > # NOT "not fromlist" and NOT "level != -1" case
209 209 > from extroot.bar import s
210 210 > buf.append('from extroot.bar import s: %s' % s)
211 211 > EOF
212 212 $ (PYTHONPATH=${PYTHONPATH}${PATHSEP}${TESTTMP}; hg --config extensions.extroot=$TESTTMP/extroot root)
213 213 (extroot) from extroot.bar import *: this is extroot.bar
214 214 (extroot) import extroot.sub1.baz: this is extroot.sub1.baz
215 215 (extroot) import extroot: this is extroot.__init__
216 216 (extroot) from extroot.bar import s: this is extroot.bar
217 217 (extroot) import extroot.bar in func(): this is extroot.bar
218 218 $TESTTMP/a (glob)
219 219
220 220 #if no-py3k
221 221 $ rm "$TESTTMP"/extroot/foo.*
222 222 $ cat > $TESTTMP/extroot/foo.py <<EOF
223 223 > # test relative import
224 224 > buf = []
225 225 > def func():
226 226 > # "not locals" case
227 227 > import bar
228 228 > buf.append('import bar in func(): %s' % bar.s)
229 229 > return '\n(extroot) '.join(buf)
230 230 > # "fromlist == ('*',)" case
231 231 > from bar import *
232 232 > buf.append('from bar import *: %s' % s)
233 233 > # "not fromlist" and "if '.' in name" case
234 234 > import sub1.baz
235 235 > buf.append('import sub1.baz: %s' % sub1.baz.s)
236 236 > # "not fromlist" and NOT "if '.' in name" case
237 237 > import sub1
238 238 > buf.append('import sub1: %s' % sub1.s)
239 239 > # NOT "not fromlist" and NOT "level != -1" case
240 240 > from bar import s
241 241 > buf.append('from bar import s: %s' % s)
242 242 > EOF
243 243 $ hg --config extensions.extroot=$TESTTMP/extroot root
244 244 (extroot) from bar import *: this is extroot.bar
245 245 (extroot) import sub1.baz: this is extroot.sub1.baz
246 246 (extroot) import sub1: this is extroot.sub1.__init__
247 247 (extroot) from bar import s: this is extroot.bar
248 248 (extroot) import bar in func(): this is extroot.bar
249 249 $TESTTMP/a (glob)
250 250 #endif
251 251
252 252 #if demandimport absimport
253 253
254 254 Examine whether module loading is delayed until actual referring, even
255 255 though module is imported with "absolute_import" feature.
256 256
257 257 Files below in each packages are used for described purpose:
258 258
259 259 - "called": examine whether "from MODULE import ATTR" works correctly
260 260 - "unused": examine whether loading is delayed correctly
261 261 - "used": examine whether "from PACKAGE import MODULE" works correctly
262 262
263 263 Package hierarchy is needed to examine whether demand importing works
264 264 as expected for "from SUB.PACK.AGE import MODULE".
265 265
266 266 Setup "external library" to be imported with "absolute_import"
267 267 feature.
268 268
269 269 $ mkdir -p $TESTTMP/extlibroot/lsub1/lsub2
270 270 $ touch $TESTTMP/extlibroot/__init__.py
271 271 $ touch $TESTTMP/extlibroot/lsub1/__init__.py
272 272 $ touch $TESTTMP/extlibroot/lsub1/lsub2/__init__.py
273 273
274 274 $ cat > $TESTTMP/extlibroot/lsub1/lsub2/called.py <<EOF
275 275 > def func():
276 276 > return "this is extlibroot.lsub1.lsub2.called.func()"
277 277 > EOF
278 278 $ cat > $TESTTMP/extlibroot/lsub1/lsub2/unused.py <<EOF
279 279 > raise Exception("extlibroot.lsub1.lsub2.unused is loaded unintentionally")
280 280 > EOF
281 281 $ cat > $TESTTMP/extlibroot/lsub1/lsub2/used.py <<EOF
282 282 > detail = "this is extlibroot.lsub1.lsub2.used"
283 283 > EOF
284 284
285 285 Setup sub-package of "external library", which causes instantiation of
286 286 demandmod in "recurse down the module chain" code path. Relative
287 287 importing with "absolute_import" feature isn't tested, because "level
288 288 >=1 " doesn't cause instantiation of demandmod.
289 289
290 290 $ mkdir -p $TESTTMP/extlibroot/recursedown/abs
291 291 $ cat > $TESTTMP/extlibroot/recursedown/abs/used.py <<EOF
292 292 > detail = "this is extlibroot.recursedown.abs.used"
293 293 > EOF
294 294 $ cat > $TESTTMP/extlibroot/recursedown/abs/__init__.py <<EOF
295 295 > from __future__ import absolute_import
296 296 > from extlibroot.recursedown.abs.used import detail
297 297 > EOF
298 298
299 299 $ mkdir -p $TESTTMP/extlibroot/recursedown/legacy
300 300 $ cat > $TESTTMP/extlibroot/recursedown/legacy/used.py <<EOF
301 301 > detail = "this is extlibroot.recursedown.legacy.used"
302 302 > EOF
303 303 $ cat > $TESTTMP/extlibroot/recursedown/legacy/__init__.py <<EOF
304 304 > # legacy style (level == -1) import
305 305 > from extlibroot.recursedown.legacy.used import detail
306 306 > EOF
307 307
308 308 $ cat > $TESTTMP/extlibroot/recursedown/__init__.py <<EOF
309 309 > from __future__ import absolute_import
310 310 > from extlibroot.recursedown.abs import detail as absdetail
311 311 > from .legacy import detail as legacydetail
312 312 > EOF
313 313
314 314 Setup extension local modules to be imported with "absolute_import"
315 315 feature.
316 316
317 317 $ mkdir -p $TESTTMP/absextroot/xsub1/xsub2
318 318 $ touch $TESTTMP/absextroot/xsub1/__init__.py
319 319 $ touch $TESTTMP/absextroot/xsub1/xsub2/__init__.py
320 320
321 321 $ cat > $TESTTMP/absextroot/xsub1/xsub2/called.py <<EOF
322 322 > def func():
323 323 > return "this is absextroot.xsub1.xsub2.called.func()"
324 324 > EOF
325 325 $ cat > $TESTTMP/absextroot/xsub1/xsub2/unused.py <<EOF
326 326 > raise Exception("absextroot.xsub1.xsub2.unused is loaded unintentionally")
327 327 > EOF
328 328 $ cat > $TESTTMP/absextroot/xsub1/xsub2/used.py <<EOF
329 329 > detail = "this is absextroot.xsub1.xsub2.used"
330 330 > EOF
331 331
332 332 Setup extension local modules to examine whether demand importing
333 333 works as expected in "level > 1" case.
334 334
335 335 $ cat > $TESTTMP/absextroot/relimportee.py <<EOF
336 336 > detail = "this is absextroot.relimportee"
337 337 > EOF
338 338 $ cat > $TESTTMP/absextroot/xsub1/xsub2/relimporter.py <<EOF
339 339 > from __future__ import absolute_import
340 340 > from ... import relimportee
341 341 > detail = "this relimporter imports %r" % (relimportee.detail)
342 342 > EOF
343 343
344 344 Setup modules, which actually import extension local modules at
345 345 runtime.
346 346
347 347 $ cat > $TESTTMP/absextroot/absolute.py << EOF
348 348 > from __future__ import absolute_import
349 349 >
350 350 > # import extension local modules absolutely (level = 0)
351 351 > from absextroot.xsub1.xsub2 import used, unused
352 352 > from absextroot.xsub1.xsub2.called import func
353 353 >
354 354 > def getresult():
355 355 > result = []
356 356 > result.append(used.detail)
357 357 > result.append(func())
358 358 > return result
359 359 > EOF
360 360
361 361 $ cat > $TESTTMP/absextroot/relative.py << EOF
362 362 > from __future__ import absolute_import
363 363 >
364 364 > # import extension local modules relatively (level == 1)
365 365 > from .xsub1.xsub2 import used, unused
366 366 > from .xsub1.xsub2.called import func
367 367 >
368 368 > # import a module, which implies "importing with level > 1"
369 369 > from .xsub1.xsub2 import relimporter
370 370 >
371 371 > def getresult():
372 372 > result = []
373 373 > result.append(used.detail)
374 374 > result.append(func())
375 375 > result.append(relimporter.detail)
376 376 > return result
377 377 > EOF
378 378
379 379 Setup main procedure of extension.
380 380
381 381 $ cat > $TESTTMP/absextroot/__init__.py <<EOF
382 382 > from __future__ import absolute_import
383 383 > from mercurial import cmdutil
384 384 > cmdtable = {}
385 385 > command = cmdutil.command(cmdtable)
386 386 >
387 387 > # "absolute" and "relative" shouldn't be imported before actual
388 388 > # command execution, because (1) they import same modules, and (2)
389 389 > # preceding import (= instantiate "demandmod" object instead of
390 390 > # real "module" object) might hide problem of succeeding import.
391 391 >
392 392 > @command('showabsolute', [], norepo=True)
393 393 > def showabsolute(ui, *args, **opts):
394 394 > from absextroot import absolute
395 395 > ui.write('ABS: %s\n' % '\nABS: '.join(absolute.getresult()))
396 396 >
397 397 > @command('showrelative', [], norepo=True)
398 398 > def showrelative(ui, *args, **opts):
399 399 > from . import relative
400 400 > ui.write('REL: %s\n' % '\nREL: '.join(relative.getresult()))
401 401 >
402 402 > # import modules from external library
403 403 > from extlibroot.lsub1.lsub2 import used as lused, unused as lunused
404 404 > from extlibroot.lsub1.lsub2.called import func as lfunc
405 405 > from extlibroot.recursedown import absdetail, legacydetail
406 406 >
407 407 > def uisetup(ui):
408 408 > result = []
409 409 > result.append(lused.detail)
410 410 > result.append(lfunc())
411 411 > result.append(absdetail)
412 412 > result.append(legacydetail)
413 413 > ui.write('LIB: %s\n' % '\nLIB: '.join(result))
414 414 > EOF
415 415
416 416 Examine module importing.
417 417
418 418 $ (PYTHONPATH=${PYTHONPATH}${PATHSEP}${TESTTMP}; hg --config extensions.absextroot=$TESTTMP/absextroot showabsolute)
419 419 LIB: this is extlibroot.lsub1.lsub2.used
420 420 LIB: this is extlibroot.lsub1.lsub2.called.func()
421 421 LIB: this is extlibroot.recursedown.abs.used
422 422 LIB: this is extlibroot.recursedown.legacy.used
423 423 ABS: this is absextroot.xsub1.xsub2.used
424 424 ABS: this is absextroot.xsub1.xsub2.called.func()
425 425
426 426 $ (PYTHONPATH=${PYTHONPATH}${PATHSEP}${TESTTMP}; hg --config extensions.absextroot=$TESTTMP/absextroot showrelative)
427 427 LIB: this is extlibroot.lsub1.lsub2.used
428 428 LIB: this is extlibroot.lsub1.lsub2.called.func()
429 429 LIB: this is extlibroot.recursedown.abs.used
430 430 LIB: this is extlibroot.recursedown.legacy.used
431 431 REL: this is absextroot.xsub1.xsub2.used
432 432 REL: this is absextroot.xsub1.xsub2.called.func()
433 433 REL: this relimporter imports 'this is absextroot.relimportee'
434 434
435 435 Examine whether sub-module is imported relatively as expected.
436 436
437 437 See also issue5208 for detail about example case on Python 3.x.
438 438
439 439 $ f -q $TESTTMP/extlibroot/lsub1/lsub2/notexist.py
440 440 $TESTTMP/extlibroot/lsub1/lsub2/notexist.py: file not found
441 441
442 442 $ cat > $TESTTMP/notexist.py <<EOF
443 443 > text = 'notexist.py at root is loaded unintentionally\n'
444 444 > EOF
445 445
446 446 $ cat > $TESTTMP/checkrelativity.py <<EOF
447 447 > from mercurial import cmdutil
448 448 > cmdtable = {}
449 449 > command = cmdutil.command(cmdtable)
450 450 >
451 451 > # demand import avoids failure of importing notexist here
452 452 > import extlibroot.lsub1.lsub2.notexist
453 453 >
454 454 > @command('checkrelativity', [], norepo=True)
455 455 > def checkrelativity(ui, *args, **opts):
456 456 > try:
457 457 > ui.write(extlibroot.lsub1.lsub2.notexist.text)
458 458 > return 1 # unintentional success
459 459 > except ImportError:
460 460 > pass # intentional failure
461 461 > EOF
462 462
463 463 $ (PYTHONPATH=${PYTHONPATH}${PATHSEP}${TESTTMP}; hg --config extensions.checkrelativity=$TESTTMP/checkrelativity.py checkrelativity)
464 464
465 465 #endif
466 466
467 467 $ cd ..
468 468
469 469 hide outer repo
470 470 $ hg init
471 471
472 472 $ cat > empty.py <<EOF
473 473 > '''empty cmdtable
474 474 > '''
475 475 > cmdtable = {}
476 476 > EOF
477 477 $ emptypath=`pwd`/empty.py
478 478 $ echo "empty = $emptypath" >> $HGRCPATH
479 479 $ hg help empty
480 480 empty extension - empty cmdtable
481 481
482 482 no commands defined
483 483
484 484
485 485 $ echo 'empty = !' >> $HGRCPATH
486 486
487 487 $ cat > debugextension.py <<EOF
488 488 > '''only debugcommands
489 489 > '''
490 490 > from mercurial import cmdutil
491 491 > cmdtable = {}
492 492 > command = cmdutil.command(cmdtable)
493 493 > @command('debugfoobar', [], 'hg debugfoobar')
494 494 > def debugfoobar(ui, repo, *args, **opts):
495 495 > "yet another debug command"
496 496 > pass
497 497 > @command('foo', [], 'hg foo')
498 498 > def foo(ui, repo, *args, **opts):
499 499 > """yet another foo command
500 500 > This command has been DEPRECATED since forever.
501 501 > """
502 502 > pass
503 503 > EOF
504 504 $ debugpath=`pwd`/debugextension.py
505 505 $ echo "debugextension = $debugpath" >> $HGRCPATH
506 506
507 507 $ hg help debugextension
508 508 hg debugextensions
509 509
510 510 show information about active extensions
511 511
512 512 options:
513 513
514 514 (some details hidden, use --verbose to show complete help)
515 515
516 516
517 517 $ hg --verbose help debugextension
518 518 hg debugextensions
519 519
520 520 show information about active extensions
521 521
522 522 options:
523 523
524 524 -T --template TEMPLATE display with template (EXPERIMENTAL)
525 525
526 526 global options ([+] can be repeated):
527 527
528 528 -R --repository REPO repository root directory or name of overlay bundle
529 529 file
530 530 --cwd DIR change working directory
531 531 -y --noninteractive do not prompt, automatically pick the first choice for
532 532 all prompts
533 533 -q --quiet suppress output
534 534 -v --verbose enable additional output
535 535 --config CONFIG [+] set/override config option (use 'section.name=value')
536 536 --debug enable debugging output
537 537 --debugger start debugger
538 538 --encoding ENCODE set the charset encoding (default: ascii)
539 539 --encodingmode MODE set the charset encoding mode (default: strict)
540 540 --traceback always print a traceback on exception
541 541 --time time how long the command takes
542 542 --profile print command execution profile
543 543 --version output version information and exit
544 544 -h --help display help and exit
545 545 --hidden consider hidden changesets
546 546
547 547
548 548
549 549
550 550
551 551
552 552 $ hg --debug help debugextension
553 553 hg debugextensions
554 554
555 555 show information about active extensions
556 556
557 557 options:
558 558
559 559 -T --template TEMPLATE display with template (EXPERIMENTAL)
560 560
561 561 global options ([+] can be repeated):
562 562
563 563 -R --repository REPO repository root directory or name of overlay bundle
564 564 file
565 565 --cwd DIR change working directory
566 566 -y --noninteractive do not prompt, automatically pick the first choice for
567 567 all prompts
568 568 -q --quiet suppress output
569 569 -v --verbose enable additional output
570 570 --config CONFIG [+] set/override config option (use 'section.name=value')
571 571 --debug enable debugging output
572 572 --debugger start debugger
573 573 --encoding ENCODE set the charset encoding (default: ascii)
574 574 --encodingmode MODE set the charset encoding mode (default: strict)
575 575 --traceback always print a traceback on exception
576 576 --time time how long the command takes
577 577 --profile print command execution profile
578 578 --version output version information and exit
579 579 -h --help display help and exit
580 580 --hidden consider hidden changesets
581 581
582 582
583 583
584 584
585 585
586 586 $ echo 'debugextension = !' >> $HGRCPATH
587 587
588 588 Asking for help about a deprecated extension should do something useful:
589 589
590 590 $ hg help glog
591 591 'glog' is provided by the following extension:
592 592
593 593 graphlog command to view revision graphs from a shell (DEPRECATED)
594 594
595 595 (use 'hg help extensions' for information on enabling extensions)
596 596
597 597 Extension module help vs command help:
598 598
599 599 $ echo 'extdiff =' >> $HGRCPATH
600 600 $ hg help extdiff
601 601 hg extdiff [OPT]... [FILE]...
602 602
603 603 use external program to diff repository (or selected files)
604 604
605 605 Show differences between revisions for the specified files, using an
606 606 external program. The default program used is diff, with default options
607 607 "-Npru".
608 608
609 609 To select a different program, use the -p/--program option. The program
610 610 will be passed the names of two directories to compare. To pass additional
611 611 options to the program, use -o/--option. These will be passed before the
612 612 names of the directories to compare.
613 613
614 614 When two revision arguments are given, then changes are shown between
615 615 those revisions. If only one revision is specified then that revision is
616 616 compared to the working directory, and, when no revisions are specified,
617 617 the working directory files are compared to its parent.
618 618
619 619 (use 'hg help -e extdiff' to show help for the extdiff extension)
620 620
621 621 options ([+] can be repeated):
622 622
623 623 -p --program CMD comparison program to run
624 624 -o --option OPT [+] pass option to comparison program
625 625 -r --rev REV [+] revision
626 626 -c --change REV change made by revision
627 627 --patch compare patches for two revisions
628 628 -I --include PATTERN [+] include names matching the given patterns
629 629 -X --exclude PATTERN [+] exclude names matching the given patterns
630 630 -S --subrepos recurse into subrepositories
631 631
632 632 (some details hidden, use --verbose to show complete help)
633 633
634 634
635 635
636 636
637 637
638 638
639 639
640 640
641 641
642 642
643 643 $ hg help --extension extdiff
644 644 extdiff extension - command to allow external programs to compare revisions
645 645
646 646 The extdiff Mercurial extension allows you to use external programs to compare
647 647 revisions, or revision with working directory. The external diff programs are
648 648 called with a configurable set of options and two non-option arguments: paths
649 649 to directories containing snapshots of files to compare.
650 650
651 651 The extdiff extension also allows you to configure new diff commands, so you
652 652 do not need to type 'hg extdiff -p kdiff3' always.
653 653
654 654 [extdiff]
655 655 # add new command that runs GNU diff(1) in 'context diff' mode
656 656 cdiff = gdiff -Nprc5
657 657 ## or the old way:
658 658 #cmd.cdiff = gdiff
659 659 #opts.cdiff = -Nprc5
660 660
661 661 # add new command called meld, runs meld (no need to name twice). If
662 662 # the meld executable is not available, the meld tool in [merge-tools]
663 663 # will be used, if available
664 664 meld =
665 665
666 666 # add new command called vimdiff, runs gvimdiff with DirDiff plugin
667 667 # (see http://www.vim.org/scripts/script.php?script_id=102) Non
668 668 # English user, be sure to put "let g:DirDiffDynamicDiffText = 1" in
669 669 # your .vimrc
670 670 vimdiff = gvim -f "+next" \
671 671 "+execute 'DirDiff' fnameescape(argv(0)) fnameescape(argv(1))"
672 672
673 673 Tool arguments can include variables that are expanded at runtime:
674 674
675 675 $parent1, $plabel1 - filename, descriptive label of first parent
676 676 $child, $clabel - filename, descriptive label of child revision
677 677 $parent2, $plabel2 - filename, descriptive label of second parent
678 678 $root - repository root
679 679 $parent is an alias for $parent1.
680 680
681 681 The extdiff extension will look in your [diff-tools] and [merge-tools]
682 682 sections for diff tool arguments, when none are specified in [extdiff].
683 683
684 684 [extdiff]
685 685 kdiff3 =
686 686
687 687 [diff-tools]
688 688 kdiff3.diffargs=--L1 '$plabel1' --L2 '$clabel' $parent $child
689 689
690 690 You can use -I/-X and list of file or directory names like normal 'hg diff'
691 691 command. The extdiff extension makes snapshots of only needed files, so
692 692 running the external diff program will actually be pretty fast (at least
693 693 faster than having to compare the entire tree).
694 694
695 695 list of commands:
696 696
697 697 extdiff use external program to diff repository (or selected files)
698 698
699 699 (use 'hg help -v -e extdiff' to show built-in aliases and global options)
700 700
701 701
702 702
703 703
704 704
705 705
706 706
707 707
708 708
709 709
710 710
711 711
712 712
713 713
714 714
715 715
716 716 $ echo 'extdiff = !' >> $HGRCPATH
717 717
718 718 Test help topic with same name as extension
719 719
720 720 $ cat > multirevs.py <<EOF
721 721 > from mercurial import cmdutil, commands
722 722 > cmdtable = {}
723 723 > command = cmdutil.command(cmdtable)
724 724 > """multirevs extension
725 725 > Big multi-line module docstring."""
726 726 > @command('multirevs', [], 'ARG', norepo=True)
727 727 > def multirevs(ui, repo, arg, *args, **opts):
728 728 > """multirevs command"""
729 729 > pass
730 730 > EOF
731 731 $ echo "multirevs = multirevs.py" >> $HGRCPATH
732 732
733 733 $ hg help multirevs | tail
734 bookmark (this works because the last revision of the revset is used):
734 735
735 - Changesets committed in May 2008, sorted by user:
736 hg update :@
736 737
737 hg log -r "sort(date('May 2008'), user)"
738 - Show diff between tags 1.3 and 1.5 (this works because the first and the
739 last revisions of the revset are used):
738 740
739 - Changesets mentioning "bug" or "issue" that are not in a tagged release:
740
741 hg log -r "(keyword(bug) or keyword(issue)) and not ancestors(tag())"
741 hg diff -r 1.3::1.5
742 742
743 743 use 'hg help -c multirevs' to see help for the multirevs command
744 744
745 745
746 746
747 747
748 748
749 749
750 750 $ hg help -c multirevs
751 751 hg multirevs ARG
752 752
753 753 multirevs command
754 754
755 755 (some details hidden, use --verbose to show complete help)
756 756
757 757
758 758
759 759 $ hg multirevs
760 760 hg multirevs: invalid arguments
761 761 hg multirevs ARG
762 762
763 763 multirevs command
764 764
765 765 (use 'hg multirevs -h' to show more help)
766 766 [255]
767 767
768 768
769 769
770 770 $ echo "multirevs = !" >> $HGRCPATH
771 771
772 772 Issue811: Problem loading extensions twice (by site and by user)
773 773
774 774 $ cat <<EOF >> $HGRCPATH
775 775 > mq =
776 776 > strip =
777 777 > hgext.mq =
778 778 > hgext/mq =
779 779 > EOF
780 780
781 781 Show extensions:
782 782 (note that mq force load strip, also checking it's not loaded twice)
783 783
784 784 $ hg debugextensions
785 785 mq
786 786 strip
787 787
788 788 For extensions, which name matches one of its commands, help
789 789 message should ask '-v -e' to get list of built-in aliases
790 790 along with extension help itself
791 791
792 792 $ mkdir $TESTTMP/d
793 793 $ cat > $TESTTMP/d/dodo.py <<EOF
794 794 > """
795 795 > This is an awesome 'dodo' extension. It does nothing and
796 796 > writes 'Foo foo'
797 797 > """
798 798 > from mercurial import cmdutil, commands
799 799 > cmdtable = {}
800 800 > command = cmdutil.command(cmdtable)
801 801 > @command('dodo', [], 'hg dodo')
802 802 > def dodo(ui, *args, **kwargs):
803 803 > """Does nothing"""
804 804 > ui.write("I do nothing. Yay\\n")
805 805 > @command('foofoo', [], 'hg foofoo')
806 806 > def foofoo(ui, *args, **kwargs):
807 807 > """Writes 'Foo foo'"""
808 808 > ui.write("Foo foo\\n")
809 809 > EOF
810 810 $ dodopath=$TESTTMP/d/dodo.py
811 811
812 812 $ echo "dodo = $dodopath" >> $HGRCPATH
813 813
814 814 Make sure that user is asked to enter '-v -e' to get list of built-in aliases
815 815 $ hg help -e dodo
816 816 dodo extension -
817 817
818 818 This is an awesome 'dodo' extension. It does nothing and writes 'Foo foo'
819 819
820 820 list of commands:
821 821
822 822 dodo Does nothing
823 823 foofoo Writes 'Foo foo'
824 824
825 825 (use 'hg help -v -e dodo' to show built-in aliases and global options)
826 826
827 827 Make sure that '-v -e' prints list of built-in aliases along with
828 828 extension help itself
829 829 $ hg help -v -e dodo
830 830 dodo extension -
831 831
832 832 This is an awesome 'dodo' extension. It does nothing and writes 'Foo foo'
833 833
834 834 list of commands:
835 835
836 836 dodo Does nothing
837 837 foofoo Writes 'Foo foo'
838 838
839 839 global options ([+] can be repeated):
840 840
841 841 -R --repository REPO repository root directory or name of overlay bundle
842 842 file
843 843 --cwd DIR change working directory
844 844 -y --noninteractive do not prompt, automatically pick the first choice for
845 845 all prompts
846 846 -q --quiet suppress output
847 847 -v --verbose enable additional output
848 848 --config CONFIG [+] set/override config option (use 'section.name=value')
849 849 --debug enable debugging output
850 850 --debugger start debugger
851 851 --encoding ENCODE set the charset encoding (default: ascii)
852 852 --encodingmode MODE set the charset encoding mode (default: strict)
853 853 --traceback always print a traceback on exception
854 854 --time time how long the command takes
855 855 --profile print command execution profile
856 856 --version output version information and exit
857 857 -h --help display help and exit
858 858 --hidden consider hidden changesets
859 859
860 860 Make sure that single '-v' option shows help and built-ins only for 'dodo' command
861 861 $ hg help -v dodo
862 862 hg dodo
863 863
864 864 Does nothing
865 865
866 866 (use 'hg help -e dodo' to show help for the dodo extension)
867 867
868 868 options:
869 869
870 870 --mq operate on patch repository
871 871
872 872 global options ([+] can be repeated):
873 873
874 874 -R --repository REPO repository root directory or name of overlay bundle
875 875 file
876 876 --cwd DIR change working directory
877 877 -y --noninteractive do not prompt, automatically pick the first choice for
878 878 all prompts
879 879 -q --quiet suppress output
880 880 -v --verbose enable additional output
881 881 --config CONFIG [+] set/override config option (use 'section.name=value')
882 882 --debug enable debugging output
883 883 --debugger start debugger
884 884 --encoding ENCODE set the charset encoding (default: ascii)
885 885 --encodingmode MODE set the charset encoding mode (default: strict)
886 886 --traceback always print a traceback on exception
887 887 --time time how long the command takes
888 888 --profile print command execution profile
889 889 --version output version information and exit
890 890 -h --help display help and exit
891 891 --hidden consider hidden changesets
892 892
893 893 In case when extension name doesn't match any of its commands,
894 894 help message should ask for '-v' to get list of built-in aliases
895 895 along with extension help
896 896 $ cat > $TESTTMP/d/dudu.py <<EOF
897 897 > """
898 898 > This is an awesome 'dudu' extension. It does something and
899 899 > also writes 'Beep beep'
900 900 > """
901 901 > from mercurial import cmdutil, commands
902 902 > cmdtable = {}
903 903 > command = cmdutil.command(cmdtable)
904 904 > @command('something', [], 'hg something')
905 905 > def something(ui, *args, **kwargs):
906 906 > """Does something"""
907 907 > ui.write("I do something. Yaaay\\n")
908 908 > @command('beep', [], 'hg beep')
909 909 > def beep(ui, *args, **kwargs):
910 910 > """Writes 'Beep beep'"""
911 911 > ui.write("Beep beep\\n")
912 912 > EOF
913 913 $ dudupath=$TESTTMP/d/dudu.py
914 914
915 915 $ echo "dudu = $dudupath" >> $HGRCPATH
916 916
917 917 $ hg help -e dudu
918 918 dudu extension -
919 919
920 920 This is an awesome 'dudu' extension. It does something and also writes 'Beep
921 921 beep'
922 922
923 923 list of commands:
924 924
925 925 beep Writes 'Beep beep'
926 926 something Does something
927 927
928 928 (use 'hg help -v dudu' to show built-in aliases and global options)
929 929
930 930 In case when extension name doesn't match any of its commands,
931 931 help options '-v' and '-v -e' should be equivalent
932 932 $ hg help -v dudu
933 933 dudu extension -
934 934
935 935 This is an awesome 'dudu' extension. It does something and also writes 'Beep
936 936 beep'
937 937
938 938 list of commands:
939 939
940 940 beep Writes 'Beep beep'
941 941 something Does something
942 942
943 943 global options ([+] can be repeated):
944 944
945 945 -R --repository REPO repository root directory or name of overlay bundle
946 946 file
947 947 --cwd DIR change working directory
948 948 -y --noninteractive do not prompt, automatically pick the first choice for
949 949 all prompts
950 950 -q --quiet suppress output
951 951 -v --verbose enable additional output
952 952 --config CONFIG [+] set/override config option (use 'section.name=value')
953 953 --debug enable debugging output
954 954 --debugger start debugger
955 955 --encoding ENCODE set the charset encoding (default: ascii)
956 956 --encodingmode MODE set the charset encoding mode (default: strict)
957 957 --traceback always print a traceback on exception
958 958 --time time how long the command takes
959 959 --profile print command execution profile
960 960 --version output version information and exit
961 961 -h --help display help and exit
962 962 --hidden consider hidden changesets
963 963
964 964 $ hg help -v -e dudu
965 965 dudu extension -
966 966
967 967 This is an awesome 'dudu' extension. It does something and also writes 'Beep
968 968 beep'
969 969
970 970 list of commands:
971 971
972 972 beep Writes 'Beep beep'
973 973 something Does something
974 974
975 975 global options ([+] can be repeated):
976 976
977 977 -R --repository REPO repository root directory or name of overlay bundle
978 978 file
979 979 --cwd DIR change working directory
980 980 -y --noninteractive do not prompt, automatically pick the first choice for
981 981 all prompts
982 982 -q --quiet suppress output
983 983 -v --verbose enable additional output
984 984 --config CONFIG [+] set/override config option (use 'section.name=value')
985 985 --debug enable debugging output
986 986 --debugger start debugger
987 987 --encoding ENCODE set the charset encoding (default: ascii)
988 988 --encodingmode MODE set the charset encoding mode (default: strict)
989 989 --traceback always print a traceback on exception
990 990 --time time how long the command takes
991 991 --profile print command execution profile
992 992 --version output version information and exit
993 993 -h --help display help and exit
994 994 --hidden consider hidden changesets
995 995
996 996 Disabled extension commands:
997 997
998 998 $ ORGHGRCPATH=$HGRCPATH
999 999 $ HGRCPATH=
1000 1000 $ export HGRCPATH
1001 1001 $ hg help email
1002 1002 'email' is provided by the following extension:
1003 1003
1004 1004 patchbomb command to send changesets as (a series of) patch emails
1005 1005
1006 1006 (use 'hg help extensions' for information on enabling extensions)
1007 1007
1008 1008
1009 1009 $ hg qdel
1010 1010 hg: unknown command 'qdel'
1011 1011 'qdelete' is provided by the following extension:
1012 1012
1013 1013 mq manage a stack of patches
1014 1014
1015 1015 (use 'hg help extensions' for information on enabling extensions)
1016 1016 [255]
1017 1017
1018 1018
1019 1019 $ hg churn
1020 1020 hg: unknown command 'churn'
1021 1021 'churn' is provided by the following extension:
1022 1022
1023 1023 churn command to display statistics about repository history
1024 1024
1025 1025 (use 'hg help extensions' for information on enabling extensions)
1026 1026 [255]
1027 1027
1028 1028
1029 1029
1030 1030 Disabled extensions:
1031 1031
1032 1032 $ hg help churn
1033 1033 churn extension - command to display statistics about repository history
1034 1034
1035 1035 (use 'hg help extensions' for information on enabling extensions)
1036 1036
1037 1037 $ hg help patchbomb
1038 1038 patchbomb extension - command to send changesets as (a series of) patch emails
1039 1039
1040 1040 The series is started off with a "[PATCH 0 of N]" introduction, which
1041 1041 describes the series as a whole.
1042 1042
1043 1043 Each patch email has a Subject line of "[PATCH M of N] ...", using the first
1044 1044 line of the changeset description as the subject text. The message contains
1045 1045 two or three body parts:
1046 1046
1047 1047 - The changeset description.
1048 1048 - [Optional] The result of running diffstat on the patch.
1049 1049 - The patch itself, as generated by 'hg export'.
1050 1050
1051 1051 Each message refers to the first in the series using the In-Reply-To and
1052 1052 References headers, so they will show up as a sequence in threaded mail and
1053 1053 news readers, and in mail archives.
1054 1054
1055 1055 To configure other defaults, add a section like this to your configuration
1056 1056 file:
1057 1057
1058 1058 [email]
1059 1059 from = My Name <my@email>
1060 1060 to = recipient1, recipient2, ...
1061 1061 cc = cc1, cc2, ...
1062 1062 bcc = bcc1, bcc2, ...
1063 1063 reply-to = address1, address2, ...
1064 1064
1065 1065 Use "[patchbomb]" as configuration section name if you need to override global
1066 1066 "[email]" address settings.
1067 1067
1068 1068 Then you can use the 'hg email' command to mail a series of changesets as a
1069 1069 patchbomb.
1070 1070
1071 1071 You can also either configure the method option in the email section to be a
1072 1072 sendmail compatible mailer or fill out the [smtp] section so that the
1073 1073 patchbomb extension can automatically send patchbombs directly from the
1074 1074 commandline. See the [email] and [smtp] sections in hgrc(5) for details.
1075 1075
1076 1076 By default, 'hg email' will prompt for a "To" or "CC" header if you do not
1077 1077 supply one via configuration or the command line. You can override this to
1078 1078 never prompt by configuring an empty value:
1079 1079
1080 1080 [email]
1081 1081 cc =
1082 1082
1083 1083 You can control the default inclusion of an introduction message with the
1084 1084 "patchbomb.intro" configuration option. The configuration is always
1085 1085 overwritten by command line flags like --intro and --desc:
1086 1086
1087 1087 [patchbomb]
1088 1088 intro=auto # include introduction message if more than 1 patch (default)
1089 1089 intro=never # never include an introduction message
1090 1090 intro=always # always include an introduction message
1091 1091
1092 1092 You can set patchbomb to always ask for confirmation by setting
1093 1093 "patchbomb.confirm" to true.
1094 1094
1095 1095 (use 'hg help extensions' for information on enabling extensions)
1096 1096
1097 1097
1098 1098 Broken disabled extension and command:
1099 1099
1100 1100 $ mkdir hgext
1101 1101 $ echo > hgext/__init__.py
1102 1102 $ cat > hgext/broken.py <<EOF
1103 1103 > "broken extension'
1104 1104 > EOF
1105 1105 $ cat > path.py <<EOF
1106 1106 > import os, sys
1107 1107 > sys.path.insert(0, os.environ['HGEXTPATH'])
1108 1108 > EOF
1109 1109 $ HGEXTPATH=`pwd`
1110 1110 $ export HGEXTPATH
1111 1111
1112 1112 $ hg --config extensions.path=./path.py help broken
1113 1113 broken extension - (no help text available)
1114 1114
1115 1115 (use 'hg help extensions' for information on enabling extensions)
1116 1116
1117 1117
1118 1118 $ cat > hgext/forest.py <<EOF
1119 1119 > cmdtable = None
1120 1120 > EOF
1121 1121 $ hg --config extensions.path=./path.py help foo > /dev/null
1122 1122 warning: error finding commands in $TESTTMP/hgext/forest.py (glob)
1123 1123 abort: no such help topic: foo
1124 1124 (try 'hg help --keyword foo')
1125 1125 [255]
1126 1126
1127 1127 $ cat > throw.py <<EOF
1128 1128 > from mercurial import cmdutil, commands, util
1129 1129 > cmdtable = {}
1130 1130 > command = cmdutil.command(cmdtable)
1131 1131 > class Bogon(Exception): pass
1132 1132 > @command('throw', [], 'hg throw', norepo=True)
1133 1133 > def throw(ui, **opts):
1134 1134 > """throws an exception"""
1135 1135 > raise Bogon()
1136 1136 > EOF
1137 1137
1138 1138 No declared supported version, extension complains:
1139 1139 $ hg --config extensions.throw=throw.py throw 2>&1 | egrep '^\*\*'
1140 1140 ** Unknown exception encountered with possibly-broken third-party extension throw
1141 1141 ** which supports versions unknown of Mercurial.
1142 1142 ** Please disable throw and try your action again.
1143 1143 ** If that fixes the bug please report it to the extension author.
1144 1144 ** Python * (glob)
1145 1145 ** Mercurial Distributed SCM * (glob)
1146 1146 ** Extensions loaded: throw
1147 1147
1148 1148 empty declaration of supported version, extension complains:
1149 1149 $ echo "testedwith = ''" >> throw.py
1150 1150 $ hg --config extensions.throw=throw.py throw 2>&1 | egrep '^\*\*'
1151 1151 ** Unknown exception encountered with possibly-broken third-party extension throw
1152 1152 ** which supports versions unknown of Mercurial.
1153 1153 ** Please disable throw and try your action again.
1154 1154 ** If that fixes the bug please report it to the extension author.
1155 1155 ** Python * (glob)
1156 1156 ** Mercurial Distributed SCM (*) (glob)
1157 1157 ** Extensions loaded: throw
1158 1158
1159 1159 If the extension specifies a buglink, show that:
1160 1160 $ echo 'buglink = "http://example.com/bts"' >> throw.py
1161 1161 $ rm -f throw.pyc throw.pyo
1162 1162 $ hg --config extensions.throw=throw.py throw 2>&1 | egrep '^\*\*'
1163 1163 ** Unknown exception encountered with possibly-broken third-party extension throw
1164 1164 ** which supports versions unknown of Mercurial.
1165 1165 ** Please disable throw and try your action again.
1166 1166 ** If that fixes the bug please report it to http://example.com/bts
1167 1167 ** Python * (glob)
1168 1168 ** Mercurial Distributed SCM (*) (glob)
1169 1169 ** Extensions loaded: throw
1170 1170
1171 1171 If the extensions declare outdated versions, accuse the older extension first:
1172 1172 $ echo "from mercurial import util" >> older.py
1173 1173 $ echo "util.version = lambda:'2.2'" >> older.py
1174 1174 $ echo "testedwith = '1.9.3'" >> older.py
1175 1175 $ echo "testedwith = '2.1.1'" >> throw.py
1176 1176 $ rm -f throw.pyc throw.pyo
1177 1177 $ hg --config extensions.throw=throw.py --config extensions.older=older.py \
1178 1178 > throw 2>&1 | egrep '^\*\*'
1179 1179 ** Unknown exception encountered with possibly-broken third-party extension older
1180 1180 ** which supports versions 1.9 of Mercurial.
1181 1181 ** Please disable older and try your action again.
1182 1182 ** If that fixes the bug please report it to the extension author.
1183 1183 ** Python * (glob)
1184 1184 ** Mercurial Distributed SCM (version 2.2)
1185 1185 ** Extensions loaded: throw, older
1186 1186
1187 1187 One extension only tested with older, one only with newer versions:
1188 1188 $ echo "util.version = lambda:'2.1'" >> older.py
1189 1189 $ rm -f older.pyc older.pyo
1190 1190 $ hg --config extensions.throw=throw.py --config extensions.older=older.py \
1191 1191 > throw 2>&1 | egrep '^\*\*'
1192 1192 ** Unknown exception encountered with possibly-broken third-party extension older
1193 1193 ** which supports versions 1.9 of Mercurial.
1194 1194 ** Please disable older and try your action again.
1195 1195 ** If that fixes the bug please report it to the extension author.
1196 1196 ** Python * (glob)
1197 1197 ** Mercurial Distributed SCM (version 2.1)
1198 1198 ** Extensions loaded: throw, older
1199 1199
1200 1200 Older extension is tested with current version, the other only with newer:
1201 1201 $ echo "util.version = lambda:'1.9.3'" >> older.py
1202 1202 $ rm -f older.pyc older.pyo
1203 1203 $ hg --config extensions.throw=throw.py --config extensions.older=older.py \
1204 1204 > throw 2>&1 | egrep '^\*\*'
1205 1205 ** Unknown exception encountered with possibly-broken third-party extension throw
1206 1206 ** which supports versions 2.1 of Mercurial.
1207 1207 ** Please disable throw and try your action again.
1208 1208 ** If that fixes the bug please report it to http://example.com/bts
1209 1209 ** Python * (glob)
1210 1210 ** Mercurial Distributed SCM (version 1.9.3)
1211 1211 ** Extensions loaded: throw, older
1212 1212
1213 1213 Ability to point to a different point
1214 1214 $ hg --config extensions.throw=throw.py --config extensions.older=older.py \
1215 1215 > --config ui.supportcontact='Your Local Goat Lenders' throw 2>&1 | egrep '^\*\*'
1216 1216 ** unknown exception encountered, please report by visiting
1217 1217 ** Your Local Goat Lenders
1218 1218 ** Python * (glob)
1219 1219 ** Mercurial Distributed SCM (*) (glob)
1220 1220 ** Extensions loaded: throw, older
1221 1221
1222 1222 Declare the version as supporting this hg version, show regular bts link:
1223 1223 $ hgver=`hg debuginstall -T '{hgver}'`
1224 1224 $ echo 'testedwith = """'"$hgver"'"""' >> throw.py
1225 1225 $ if [ -z "$hgver" ]; then
1226 1226 > echo "unable to fetch a mercurial version. Make sure __version__ is correct";
1227 1227 > fi
1228 1228 $ rm -f throw.pyc throw.pyo
1229 1229 $ hg --config extensions.throw=throw.py throw 2>&1 | egrep '^\*\*'
1230 1230 ** unknown exception encountered, please report by visiting
1231 1231 ** https://mercurial-scm.org/wiki/BugTracker
1232 1232 ** Python * (glob)
1233 1233 ** Mercurial Distributed SCM (*) (glob)
1234 1234 ** Extensions loaded: throw
1235 1235
1236 1236 Patch version is ignored during compatibility check
1237 1237 $ echo "testedwith = '3.2'" >> throw.py
1238 1238 $ echo "util.version = lambda:'3.2.2'" >> throw.py
1239 1239 $ rm -f throw.pyc throw.pyo
1240 1240 $ hg --config extensions.throw=throw.py throw 2>&1 | egrep '^\*\*'
1241 1241 ** unknown exception encountered, please report by visiting
1242 1242 ** https://mercurial-scm.org/wiki/BugTracker
1243 1243 ** Python * (glob)
1244 1244 ** Mercurial Distributed SCM (*) (glob)
1245 1245 ** Extensions loaded: throw
1246 1246
1247 1247 Test version number support in 'hg version':
1248 1248 $ echo '__version__ = (1, 2, 3)' >> throw.py
1249 1249 $ rm -f throw.pyc throw.pyo
1250 1250 $ hg version -v
1251 1251 Mercurial Distributed SCM (version *) (glob)
1252 1252 (see https://mercurial-scm.org for more information)
1253 1253
1254 1254 Copyright (C) 2005-* Matt Mackall and others (glob)
1255 1255 This is free software; see the source for copying conditions. There is NO
1256 1256 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
1257 1257
1258 1258 Enabled extensions:
1259 1259
1260 1260
1261 1261 $ hg version -v --config extensions.throw=throw.py
1262 1262 Mercurial Distributed SCM (version *) (glob)
1263 1263 (see https://mercurial-scm.org for more information)
1264 1264
1265 1265 Copyright (C) 2005-* Matt Mackall and others (glob)
1266 1266 This is free software; see the source for copying conditions. There is NO
1267 1267 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
1268 1268
1269 1269 Enabled extensions:
1270 1270
1271 1271 throw external 1.2.3
1272 1272 $ echo 'getversion = lambda: "1.twentythree"' >> throw.py
1273 1273 $ rm -f throw.pyc throw.pyo
1274 1274 $ hg version -v --config extensions.throw=throw.py --config extensions.strip=
1275 1275 Mercurial Distributed SCM (version *) (glob)
1276 1276 (see https://mercurial-scm.org for more information)
1277 1277
1278 1278 Copyright (C) 2005-* Matt Mackall and others (glob)
1279 1279 This is free software; see the source for copying conditions. There is NO
1280 1280 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
1281 1281
1282 1282 Enabled extensions:
1283 1283
1284 1284 throw external 1.twentythree
1285 1285 strip internal
1286 1286
1287 1287 $ hg version -q --config extensions.throw=throw.py
1288 1288 Mercurial Distributed SCM (version *) (glob)
1289 1289
1290 1290 Test JSON output of version:
1291 1291
1292 1292 $ hg version -Tjson
1293 1293 [
1294 1294 {
1295 1295 "extensions": [],
1296 1296 "ver": "*" (glob)
1297 1297 }
1298 1298 ]
1299 1299
1300 1300 $ hg version --config extensions.throw=throw.py -Tjson
1301 1301 [
1302 1302 {
1303 1303 "extensions": [{"bundled": false, "name": "throw", "ver": "1.twentythree"}],
1304 1304 "ver": "3.2.2"
1305 1305 }
1306 1306 ]
1307 1307
1308 1308 $ hg version --config extensions.strip= -Tjson
1309 1309 [
1310 1310 {
1311 1311 "extensions": [{"bundled": true, "name": "strip", "ver": null}],
1312 1312 "ver": "*" (glob)
1313 1313 }
1314 1314 ]
1315 1315
1316 1316 Test template output of version:
1317 1317
1318 1318 $ hg version --config extensions.throw=throw.py --config extensions.strip= \
1319 1319 > -T'{extensions % "{name} {pad(ver, 16)} ({if(bundled, "internal", "external")})\n"}'
1320 1320 throw 1.twentythree (external)
1321 1321 strip (internal)
1322 1322
1323 1323 Refuse to load extensions with minimum version requirements
1324 1324
1325 1325 $ cat > minversion1.py << EOF
1326 1326 > from mercurial import util
1327 1327 > util.version = lambda: '3.5.2'
1328 1328 > minimumhgversion = '3.6'
1329 1329 > EOF
1330 1330 $ hg --config extensions.minversion=minversion1.py version
1331 1331 (third party extension minversion requires version 3.6 or newer of Mercurial; disabling)
1332 1332 Mercurial Distributed SCM (version 3.5.2)
1333 1333 (see https://mercurial-scm.org for more information)
1334 1334
1335 1335 Copyright (C) 2005-* Matt Mackall and others (glob)
1336 1336 This is free software; see the source for copying conditions. There is NO
1337 1337 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
1338 1338
1339 1339 $ cat > minversion2.py << EOF
1340 1340 > from mercurial import util
1341 1341 > util.version = lambda: '3.6'
1342 1342 > minimumhgversion = '3.7'
1343 1343 > EOF
1344 1344 $ hg --config extensions.minversion=minversion2.py version 2>&1 | egrep '\(third'
1345 1345 (third party extension minversion requires version 3.7 or newer of Mercurial; disabling)
1346 1346
1347 1347 Can load version that is only off by point release
1348 1348
1349 1349 $ cat > minversion2.py << EOF
1350 1350 > from mercurial import util
1351 1351 > util.version = lambda: '3.6.1'
1352 1352 > minimumhgversion = '3.6'
1353 1353 > EOF
1354 1354 $ hg --config extensions.minversion=minversion3.py version 2>&1 | egrep '\(third'
1355 1355 [1]
1356 1356
1357 1357 Can load minimum version identical to current
1358 1358
1359 1359 $ cat > minversion3.py << EOF
1360 1360 > from mercurial import util
1361 1361 > util.version = lambda: '3.5'
1362 1362 > minimumhgversion = '3.5'
1363 1363 > EOF
1364 1364 $ hg --config extensions.minversion=minversion3.py version 2>&1 | egrep '\(third'
1365 1365 [1]
1366 1366
1367 1367 Restore HGRCPATH
1368 1368
1369 1369 $ HGRCPATH=$ORGHGRCPATH
1370 1370 $ export HGRCPATH
1371 1371
1372 1372 Commands handling multiple repositories at a time should invoke only
1373 1373 "reposetup()" of extensions enabling in the target repository.
1374 1374
1375 1375 $ mkdir reposetup-test
1376 1376 $ cd reposetup-test
1377 1377
1378 1378 $ cat > $TESTTMP/reposetuptest.py <<EOF
1379 1379 > from mercurial import extensions
1380 1380 > def reposetup(ui, repo):
1381 1381 > ui.write('reposetup() for %s\n' % (repo.root))
1382 1382 > ui.flush()
1383 1383 > EOF
1384 1384 $ hg init src
1385 1385 $ echo a > src/a
1386 1386 $ hg -R src commit -Am '#0 at src/a'
1387 1387 adding a
1388 1388 $ echo '[extensions]' >> src/.hg/hgrc
1389 1389 $ echo '# enable extension locally' >> src/.hg/hgrc
1390 1390 $ echo "reposetuptest = $TESTTMP/reposetuptest.py" >> src/.hg/hgrc
1391 1391 $ hg -R src status
1392 1392 reposetup() for $TESTTMP/reposetup-test/src (glob)
1393 1393
1394 1394 $ hg clone -U src clone-dst1
1395 1395 reposetup() for $TESTTMP/reposetup-test/src (glob)
1396 1396 $ hg init push-dst1
1397 1397 $ hg -q -R src push push-dst1
1398 1398 reposetup() for $TESTTMP/reposetup-test/src (glob)
1399 1399 $ hg init pull-src1
1400 1400 $ hg -q -R pull-src1 pull src
1401 1401 reposetup() for $TESTTMP/reposetup-test/src (glob)
1402 1402
1403 1403 $ cat <<EOF >> $HGRCPATH
1404 1404 > [extensions]
1405 1405 > # disable extension globally and explicitly
1406 1406 > reposetuptest = !
1407 1407 > EOF
1408 1408 $ hg clone -U src clone-dst2
1409 1409 reposetup() for $TESTTMP/reposetup-test/src (glob)
1410 1410 $ hg init push-dst2
1411 1411 $ hg -q -R src push push-dst2
1412 1412 reposetup() for $TESTTMP/reposetup-test/src (glob)
1413 1413 $ hg init pull-src2
1414 1414 $ hg -q -R pull-src2 pull src
1415 1415 reposetup() for $TESTTMP/reposetup-test/src (glob)
1416 1416
1417 1417 $ cat <<EOF >> $HGRCPATH
1418 1418 > [extensions]
1419 1419 > # enable extension globally
1420 1420 > reposetuptest = $TESTTMP/reposetuptest.py
1421 1421 > EOF
1422 1422 $ hg clone -U src clone-dst3
1423 1423 reposetup() for $TESTTMP/reposetup-test/src (glob)
1424 1424 reposetup() for $TESTTMP/reposetup-test/clone-dst3 (glob)
1425 1425 $ hg init push-dst3
1426 1426 reposetup() for $TESTTMP/reposetup-test/push-dst3 (glob)
1427 1427 $ hg -q -R src push push-dst3
1428 1428 reposetup() for $TESTTMP/reposetup-test/src (glob)
1429 1429 reposetup() for $TESTTMP/reposetup-test/push-dst3 (glob)
1430 1430 $ hg init pull-src3
1431 1431 reposetup() for $TESTTMP/reposetup-test/pull-src3 (glob)
1432 1432 $ hg -q -R pull-src3 pull src
1433 1433 reposetup() for $TESTTMP/reposetup-test/pull-src3 (glob)
1434 1434 reposetup() for $TESTTMP/reposetup-test/src (glob)
1435 1435
1436 1436 $ echo '[extensions]' >> src/.hg/hgrc
1437 1437 $ echo '# disable extension locally' >> src/.hg/hgrc
1438 1438 $ echo 'reposetuptest = !' >> src/.hg/hgrc
1439 1439 $ hg clone -U src clone-dst4
1440 1440 reposetup() for $TESTTMP/reposetup-test/clone-dst4 (glob)
1441 1441 $ hg init push-dst4
1442 1442 reposetup() for $TESTTMP/reposetup-test/push-dst4 (glob)
1443 1443 $ hg -q -R src push push-dst4
1444 1444 reposetup() for $TESTTMP/reposetup-test/push-dst4 (glob)
1445 1445 $ hg init pull-src4
1446 1446 reposetup() for $TESTTMP/reposetup-test/pull-src4 (glob)
1447 1447 $ hg -q -R pull-src4 pull src
1448 1448 reposetup() for $TESTTMP/reposetup-test/pull-src4 (glob)
1449 1449
1450 1450 disabling in command line overlays with all configuration
1451 1451 $ hg --config extensions.reposetuptest=! clone -U src clone-dst5
1452 1452 $ hg --config extensions.reposetuptest=! init push-dst5
1453 1453 $ hg --config extensions.reposetuptest=! -q -R src push push-dst5
1454 1454 $ hg --config extensions.reposetuptest=! init pull-src5
1455 1455 $ hg --config extensions.reposetuptest=! -q -R pull-src5 pull src
1456 1456
1457 1457 $ cat <<EOF >> $HGRCPATH
1458 1458 > [extensions]
1459 1459 > # disable extension globally and explicitly
1460 1460 > reposetuptest = !
1461 1461 > EOF
1462 1462 $ hg init parent
1463 1463 $ hg init parent/sub1
1464 1464 $ echo 1 > parent/sub1/1
1465 1465 $ hg -R parent/sub1 commit -Am '#0 at parent/sub1'
1466 1466 adding 1
1467 1467 $ hg init parent/sub2
1468 1468 $ hg init parent/sub2/sub21
1469 1469 $ echo 21 > parent/sub2/sub21/21
1470 1470 $ hg -R parent/sub2/sub21 commit -Am '#0 at parent/sub2/sub21'
1471 1471 adding 21
1472 1472 $ cat > parent/sub2/.hgsub <<EOF
1473 1473 > sub21 = sub21
1474 1474 > EOF
1475 1475 $ hg -R parent/sub2 commit -Am '#0 at parent/sub2'
1476 1476 adding .hgsub
1477 1477 $ hg init parent/sub3
1478 1478 $ echo 3 > parent/sub3/3
1479 1479 $ hg -R parent/sub3 commit -Am '#0 at parent/sub3'
1480 1480 adding 3
1481 1481 $ cat > parent/.hgsub <<EOF
1482 1482 > sub1 = sub1
1483 1483 > sub2 = sub2
1484 1484 > sub3 = sub3
1485 1485 > EOF
1486 1486 $ hg -R parent commit -Am '#0 at parent'
1487 1487 adding .hgsub
1488 1488 $ echo '[extensions]' >> parent/.hg/hgrc
1489 1489 $ echo '# enable extension locally' >> parent/.hg/hgrc
1490 1490 $ echo "reposetuptest = $TESTTMP/reposetuptest.py" >> parent/.hg/hgrc
1491 1491 $ cp parent/.hg/hgrc parent/sub2/.hg/hgrc
1492 1492 $ hg -R parent status -S -A
1493 1493 reposetup() for $TESTTMP/reposetup-test/parent (glob)
1494 1494 reposetup() for $TESTTMP/reposetup-test/parent/sub2 (glob)
1495 1495 C .hgsub
1496 1496 C .hgsubstate
1497 1497 C sub1/1
1498 1498 C sub2/.hgsub
1499 1499 C sub2/.hgsubstate
1500 1500 C sub2/sub21/21
1501 1501 C sub3/3
1502 1502
1503 1503 $ cd ..
1504 1504
1505 1505 Test synopsis and docstring extending
1506 1506
1507 1507 $ hg init exthelp
1508 1508 $ cat > exthelp.py <<EOF
1509 1509 > from mercurial import commands, extensions
1510 1510 > def exbookmarks(orig, *args, **opts):
1511 1511 > return orig(*args, **opts)
1512 1512 > def uisetup(ui):
1513 1513 > synopsis = ' GREPME [--foo] [-x]'
1514 1514 > docstring = '''
1515 1515 > GREPME make sure that this is in the help!
1516 1516 > '''
1517 1517 > extensions.wrapcommand(commands.table, 'bookmarks', exbookmarks,
1518 1518 > synopsis, docstring)
1519 1519 > EOF
1520 1520 $ abspath=`pwd`/exthelp.py
1521 1521 $ echo '[extensions]' >> $HGRCPATH
1522 1522 $ echo "exthelp = $abspath" >> $HGRCPATH
1523 1523 $ cd exthelp
1524 1524 $ hg help bookmarks | grep GREPME
1525 1525 hg bookmarks [OPTIONS]... [NAME]... GREPME [--foo] [-x]
1526 1526 GREPME make sure that this is in the help!
1527 1527
General Comments 0
You need to be logged in to leave comments. Login now