##// END OF EJS Templates
minirst: simplify and standardize field list formatting...
Olav Reinert -
r15861:ee8f5e4c default
parent child Browse files
Show More
@@ -1,687 +1,677 b''
1 1 # minirst.py - minimal reStructuredText parser
2 2 #
3 3 # Copyright 2009, 2010 Matt Mackall <mpm@selenic.com> and others
4 4 #
5 5 # This software may be used and distributed according to the terms of the
6 6 # GNU General Public License version 2 or any later version.
7 7
8 8 """simplified reStructuredText parser.
9 9
10 10 This parser knows just enough about reStructuredText to parse the
11 11 Mercurial docstrings.
12 12
13 13 It cheats in a major way: nested blocks are not really nested. They
14 14 are just indented blocks that look like they are nested. This relies
15 15 on the user to keep the right indentation for the blocks.
16 16
17 17 Remember to update http://mercurial.selenic.com/wiki/HelpStyleGuide
18 18 when adding support for new constructs.
19 19 """
20 20
21 21 import re
22 22 import util, encoding
23 23 from i18n import _
24 24
25 25 def replace(text, substs):
26 26 '''
27 27 Apply a list of (find, replace) pairs to a text.
28 28
29 29 >>> replace("foo bar", [('f', 'F'), ('b', 'B')])
30 30 'Foo Bar'
31 31 >>> encoding.encoding = 'latin1'
32 32 >>> replace('\\x81\\\\', [('\\\\', '/')])
33 33 '\\x81/'
34 34 >>> encoding.encoding = 'shiftjis'
35 35 >>> replace('\\x81\\\\', [('\\\\', '/')])
36 36 '\\x81\\\\'
37 37 '''
38 38
39 39 # some character encodings (cp932 for Japanese, at least) use
40 40 # ASCII characters other than control/alphabet/digit as a part of
41 41 # multi-bytes characters, so direct replacing with such characters
42 42 # on strings in local encoding causes invalid byte sequences.
43 43 utext = text.decode(encoding.encoding)
44 44 for f, t in substs:
45 45 utext = utext.replace(f, t)
46 46 return utext.encode(encoding.encoding)
47 47
48 48 _blockre = re.compile(r"\n(?:\s*\n)+")
49 49
50 50 def findblocks(text):
51 51 """Find continuous blocks of lines in text.
52 52
53 53 Returns a list of dictionaries representing the blocks. Each block
54 54 has an 'indent' field and a 'lines' field.
55 55 """
56 56 blocks = []
57 57 for b in _blockre.split(text.lstrip('\n').rstrip()):
58 58 lines = b.splitlines()
59 59 if lines:
60 60 indent = min((len(l) - len(l.lstrip())) for l in lines)
61 61 lines = [l[indent:] for l in lines]
62 62 blocks.append(dict(indent=indent, lines=lines))
63 63 return blocks
64 64
65 65 def findliteralblocks(blocks):
66 66 """Finds literal blocks and adds a 'type' field to the blocks.
67 67
68 68 Literal blocks are given the type 'literal', all other blocks are
69 69 given type the 'paragraph'.
70 70 """
71 71 i = 0
72 72 while i < len(blocks):
73 73 # Searching for a block that looks like this:
74 74 #
75 75 # +------------------------------+
76 76 # | paragraph |
77 77 # | (ends with "::") |
78 78 # +------------------------------+
79 79 # +---------------------------+
80 80 # | indented literal block |
81 81 # +---------------------------+
82 82 blocks[i]['type'] = 'paragraph'
83 83 if blocks[i]['lines'][-1].endswith('::') and i + 1 < len(blocks):
84 84 indent = blocks[i]['indent']
85 85 adjustment = blocks[i + 1]['indent'] - indent
86 86
87 87 if blocks[i]['lines'] == ['::']:
88 88 # Expanded form: remove block
89 89 del blocks[i]
90 90 i -= 1
91 91 elif blocks[i]['lines'][-1].endswith(' ::'):
92 92 # Partially minimized form: remove space and both
93 93 # colons.
94 94 blocks[i]['lines'][-1] = blocks[i]['lines'][-1][:-3]
95 95 else:
96 96 # Fully minimized form: remove just one colon.
97 97 blocks[i]['lines'][-1] = blocks[i]['lines'][-1][:-1]
98 98
99 99 # List items are formatted with a hanging indent. We must
100 100 # correct for this here while we still have the original
101 101 # information on the indentation of the subsequent literal
102 102 # blocks available.
103 103 m = _bulletre.match(blocks[i]['lines'][0])
104 104 if m:
105 105 indent += m.end()
106 106 adjustment -= m.end()
107 107
108 108 # Mark the following indented blocks.
109 109 while i + 1 < len(blocks) and blocks[i + 1]['indent'] > indent:
110 110 blocks[i + 1]['type'] = 'literal'
111 111 blocks[i + 1]['indent'] -= adjustment
112 112 i += 1
113 113 i += 1
114 114 return blocks
115 115
116 116 _bulletre = re.compile(r'(-|[0-9A-Za-z]+\.|\(?[0-9A-Za-z]+\)|\|) ')
117 117 _optionre = re.compile(r'^(-([a-zA-Z0-9]), )?(--[a-z0-9-]+)'
118 118 r'((.*) +)(.*)$')
119 119 _fieldre = re.compile(r':(?![: ])([^:]*)(?<! ):[ ]+(.*)')
120 120 _definitionre = re.compile(r'[^ ]')
121 121 _tablere = re.compile(r'(=+\s+)*=+')
122 122
123 123 def splitparagraphs(blocks):
124 124 """Split paragraphs into lists."""
125 125 # Tuples with (list type, item regexp, single line items?). Order
126 126 # matters: definition lists has the least specific regexp and must
127 127 # come last.
128 128 listtypes = [('bullet', _bulletre, True),
129 129 ('option', _optionre, True),
130 130 ('field', _fieldre, True),
131 131 ('definition', _definitionre, False)]
132 132
133 133 def match(lines, i, itemre, singleline):
134 134 """Does itemre match an item at line i?
135 135
136 136 A list item can be followed by an idented line or another list
137 137 item (but only if singleline is True).
138 138 """
139 139 line1 = lines[i]
140 140 line2 = i + 1 < len(lines) and lines[i + 1] or ''
141 141 if not itemre.match(line1):
142 142 return False
143 143 if singleline:
144 144 return line2 == '' or line2[0] == ' ' or itemre.match(line2)
145 145 else:
146 146 return line2.startswith(' ')
147 147
148 148 i = 0
149 149 while i < len(blocks):
150 150 if blocks[i]['type'] == 'paragraph':
151 151 lines = blocks[i]['lines']
152 152 for type, itemre, singleline in listtypes:
153 153 if match(lines, 0, itemre, singleline):
154 154 items = []
155 155 for j, line in enumerate(lines):
156 156 if match(lines, j, itemre, singleline):
157 157 items.append(dict(type=type, lines=[],
158 158 indent=blocks[i]['indent']))
159 159 items[-1]['lines'].append(line)
160 160 blocks[i:i + 1] = items
161 161 break
162 162 i += 1
163 163 return blocks
164 164
165 _fieldwidth = 12
165 _fieldwidth = 14
166 166
167 167 def updatefieldlists(blocks):
168 """Find key and maximum key width for field lists."""
168 """Find key for field lists."""
169 169 i = 0
170 170 while i < len(blocks):
171 171 if blocks[i]['type'] != 'field':
172 172 i += 1
173 173 continue
174 174
175 keywidth = 0
176 175 j = i
177 176 while j < len(blocks) and blocks[j]['type'] == 'field':
178 177 m = _fieldre.match(blocks[j]['lines'][0])
179 178 key, rest = m.groups()
180 179 blocks[j]['lines'][0] = rest
181 180 blocks[j]['key'] = key
182 keywidth = max(keywidth, len(key))
183 181 j += 1
184 182
185 for block in blocks[i:j]:
186 block['keywidth'] = keywidth
187 183 i = j + 1
188 184
189 185 return blocks
190 186
191 187 def updateoptionlists(blocks):
192 188 i = 0
193 189 while i < len(blocks):
194 190 if blocks[i]['type'] != 'option':
195 191 i += 1
196 192 continue
197 193
198 194 optstrwidth = 0
199 195 j = i
200 196 while j < len(blocks) and blocks[j]['type'] == 'option':
201 197 m = _optionre.match(blocks[j]['lines'][0])
202 198
203 199 shortoption = m.group(2)
204 200 group3 = m.group(3)
205 201 longoption = group3[2:].strip()
206 202 desc = m.group(6).strip()
207 203 longoptionarg = m.group(5).strip()
208 204 blocks[j]['lines'][0] = desc
209 205
210 206 noshortop = ''
211 207 if not shortoption:
212 208 noshortop = ' '
213 209
214 210 opt = "%s%s" % (shortoption and "-%s " % shortoption or '',
215 211 ("%s--%s %s") % (noshortop, longoption,
216 212 longoptionarg))
217 213 opt = opt.rstrip()
218 214 blocks[j]['optstr'] = opt
219 215 optstrwidth = max(optstrwidth, encoding.colwidth(opt))
220 216 j += 1
221 217
222 218 for block in blocks[i:j]:
223 219 block['optstrwidth'] = optstrwidth
224 220 i = j + 1
225 221 return blocks
226 222
227 223 def prunecontainers(blocks, keep):
228 224 """Prune unwanted containers.
229 225
230 226 The blocks must have a 'type' field, i.e., they should have been
231 227 run through findliteralblocks first.
232 228 """
233 229 pruned = []
234 230 i = 0
235 231 while i + 1 < len(blocks):
236 232 # Searching for a block that looks like this:
237 233 #
238 234 # +-------+---------------------------+
239 235 # | ".. container ::" type |
240 236 # +---+ |
241 237 # | blocks |
242 238 # +-------------------------------+
243 239 if (blocks[i]['type'] == 'paragraph' and
244 240 blocks[i]['lines'][0].startswith('.. container::')):
245 241 indent = blocks[i]['indent']
246 242 adjustment = blocks[i + 1]['indent'] - indent
247 243 containertype = blocks[i]['lines'][0][15:]
248 244 prune = containertype not in keep
249 245 if prune:
250 246 pruned.append(containertype)
251 247
252 248 # Always delete "..container:: type" block
253 249 del blocks[i]
254 250 j = i
255 251 i -= 1
256 252 while j < len(blocks) and blocks[j]['indent'] > indent:
257 253 if prune:
258 254 del blocks[j]
259 255 else:
260 256 blocks[j]['indent'] -= adjustment
261 257 j += 1
262 258 i += 1
263 259 return blocks, pruned
264 260
265 261 _sectionre = re.compile(r"""^([-=`:.'"~^_*+#])\1+$""")
266 262
267 263 def findtables(blocks):
268 264 '''Find simple tables
269 265
270 266 Only simple one-line table elements are supported
271 267 '''
272 268
273 269 for block in blocks:
274 270 # Searching for a block that looks like this:
275 271 #
276 272 # === ==== ===
277 273 # A B C
278 274 # === ==== === <- optional
279 275 # 1 2 3
280 276 # x y z
281 277 # === ==== ===
282 278 if (block['type'] == 'paragraph' and
283 279 len(block['lines']) > 2 and
284 280 _tablere.match(block['lines'][0]) and
285 281 block['lines'][0] == block['lines'][-1]):
286 282 block['type'] = 'table'
287 283 block['header'] = False
288 284 div = block['lines'][0]
289 285
290 286 # column markers are ASCII so we can calculate column
291 287 # position in bytes
292 288 columns = [x for x in xrange(len(div))
293 289 if div[x] == '=' and (x == 0 or div[x - 1] == ' ')]
294 290 rows = []
295 291 for l in block['lines'][1:-1]:
296 292 if l == div:
297 293 block['header'] = True
298 294 continue
299 295 row = []
300 296 # we measure columns not in bytes or characters but in
301 297 # colwidth which makes things tricky
302 298 pos = columns[0] # leading whitespace is bytes
303 299 for n, start in enumerate(columns):
304 300 if n + 1 < len(columns):
305 301 width = columns[n + 1] - start
306 302 v = encoding.getcols(l, pos, width) # gather columns
307 303 pos += len(v) # calculate byte position of end
308 304 row.append(v.strip())
309 305 else:
310 306 row.append(l[pos:].strip())
311 307 rows.append(row)
312 308
313 309 block['table'] = rows
314 310
315 311 return blocks
316 312
317 313 def findsections(blocks):
318 314 """Finds sections.
319 315
320 316 The blocks must have a 'type' field, i.e., they should have been
321 317 run through findliteralblocks first.
322 318 """
323 319 for block in blocks:
324 320 # Searching for a block that looks like this:
325 321 #
326 322 # +------------------------------+
327 323 # | Section title |
328 324 # | ------------- |
329 325 # +------------------------------+
330 326 if (block['type'] == 'paragraph' and
331 327 len(block['lines']) == 2 and
332 328 encoding.colwidth(block['lines'][0]) == len(block['lines'][1]) and
333 329 _sectionre.match(block['lines'][1])):
334 330 block['underline'] = block['lines'][1][0]
335 331 block['type'] = 'section'
336 332 del block['lines'][1]
337 333 return blocks
338 334
339 335 def inlineliterals(blocks):
340 336 substs = [('``', '"')]
341 337 for b in blocks:
342 338 if b['type'] in ('paragraph', 'section'):
343 339 b['lines'] = [replace(l, substs) for l in b['lines']]
344 340 return blocks
345 341
346 342 def hgrole(blocks):
347 343 substs = [(':hg:`', '"hg '), ('`', '"')]
348 344 for b in blocks:
349 345 if b['type'] in ('paragraph', 'section'):
350 346 # Turn :hg:`command` into "hg command". This also works
351 347 # when there is a line break in the command and relies on
352 348 # the fact that we have no stray back-quotes in the input
353 349 # (run the blocks through inlineliterals first).
354 350 b['lines'] = [replace(l, substs) for l in b['lines']]
355 351 return blocks
356 352
357 353 def addmargins(blocks):
358 354 """Adds empty blocks for vertical spacing.
359 355
360 356 This groups bullets, options, and definitions together with no vertical
361 357 space between them, and adds an empty block between all other blocks.
362 358 """
363 359 i = 1
364 360 while i < len(blocks):
365 361 if (blocks[i]['type'] == blocks[i - 1]['type'] and
366 362 blocks[i]['type'] in ('bullet', 'option', 'field')):
367 363 i += 1
368 364 else:
369 365 blocks.insert(i, dict(lines=[''], indent=0, type='margin'))
370 366 i += 2
371 367 return blocks
372 368
373 369 def prunecomments(blocks):
374 370 """Remove comments."""
375 371 i = 0
376 372 while i < len(blocks):
377 373 b = blocks[i]
378 374 if b['type'] == 'paragraph' and (b['lines'][0].startswith('.. ') or
379 375 b['lines'] == ['..']):
380 376 del blocks[i]
381 377 if i < len(blocks) and blocks[i]['type'] == 'margin':
382 378 del blocks[i]
383 379 else:
384 380 i += 1
385 381 return blocks
386 382
387 383 _admonitionre = re.compile(r"\.\. (admonition|attention|caution|danger|"
388 384 r"error|hint|important|note|tip|warning)::",
389 385 flags=re.IGNORECASE)
390 386
391 387 def findadmonitions(blocks):
392 388 """
393 389 Makes the type of the block an admonition block if
394 390 the first line is an admonition directive
395 391 """
396 392 i = 0
397 393 while i < len(blocks):
398 394 m = _admonitionre.match(blocks[i]['lines'][0])
399 395 if m:
400 396 blocks[i]['type'] = 'admonition'
401 397 admonitiontitle = blocks[i]['lines'][0][3:m.end() - 2].lower()
402 398
403 399 firstline = blocks[i]['lines'][0][m.end() + 1:]
404 400 if firstline:
405 401 blocks[i]['lines'].insert(1, ' ' + firstline)
406 402
407 403 blocks[i]['admonitiontitle'] = admonitiontitle
408 404 del blocks[i]['lines'][0]
409 405 i = i + 1
410 406 return blocks
411 407
412 408 _admonitiontitles = {'attention': _('Attention:'),
413 409 'caution': _('Caution:'),
414 410 'danger': _('!Danger!') ,
415 411 'error': _('Error:'),
416 412 'hint': _('Hint:'),
417 413 'important': _('Important:'),
418 414 'note': _('Note:'),
419 415 'tip': _('Tip:'),
420 416 'warning': _('Warning!')}
421 417
422 418 def formatoption(block, width):
423 419 desc = ' '.join(map(str.strip, block['lines']))
424 420 colwidth = encoding.colwidth(block['optstr'])
425 421 usablewidth = width - 1
426 422 hanging = block['optstrwidth']
427 423 initindent = '%s%s ' % (block['optstr'], ' ' * ((hanging - colwidth)))
428 424 hangindent = ' ' * (encoding.colwidth(initindent) + 1)
429 425 return ' %s\n' % (util.wrap(desc, usablewidth,
430 426 initindent=initindent,
431 427 hangindent=hangindent))
432 428
433 429 def formatblock(block, width):
434 430 """Format a block according to width."""
435 431 if width <= 0:
436 432 width = 78
437 433 indent = ' ' * block['indent']
438 434 if block['type'] == 'admonition':
439 435 admonition = _admonitiontitles[block['admonitiontitle']]
440 436 hang = len(block['lines'][-1]) - len(block['lines'][-1].lstrip())
441 437
442 438 defindent = indent + hang * ' '
443 439 text = ' '.join(map(str.strip, block['lines']))
444 440 return '%s\n%s\n' % (indent + admonition,
445 441 util.wrap(text, width=width,
446 442 initindent=defindent,
447 443 hangindent=defindent))
448 444 if block['type'] == 'margin':
449 445 return '\n'
450 446 if block['type'] == 'literal':
451 447 indent += ' '
452 448 return indent + ('\n' + indent).join(block['lines']) + '\n'
453 449 if block['type'] == 'section':
454 450 underline = encoding.colwidth(block['lines'][0]) * block['underline']
455 451 return "%s%s\n%s%s\n" % (indent, block['lines'][0],indent, underline)
456 452 if block['type'] == 'table':
457 453 table = block['table']
458 454 # compute column widths
459 455 widths = [max([encoding.colwidth(e) for e in c]) for c in zip(*table)]
460 456 text = ''
461 457 span = sum(widths) + len(widths) - 1
462 458 indent = ' ' * block['indent']
463 459 hang = ' ' * (len(indent) + span - widths[-1])
464 460
465 461 for row in table:
466 462 l = []
467 463 for w, v in zip(widths, row):
468 464 pad = ' ' * (w - encoding.colwidth(v))
469 465 l.append(v + pad)
470 466 l = ' '.join(l)
471 467 l = util.wrap(l, width=width, initindent=indent, hangindent=hang)
472 468 if not text and block['header']:
473 469 text = l + '\n' + indent + '-' * (min(width, span)) + '\n'
474 470 else:
475 471 text += l + "\n"
476 472 return text
477 473 if block['type'] == 'definition':
478 474 term = indent + block['lines'][0]
479 475 hang = len(block['lines'][-1]) - len(block['lines'][-1].lstrip())
480 476 defindent = indent + hang * ' '
481 477 text = ' '.join(map(str.strip, block['lines'][1:]))
482 478 return '%s\n%s\n' % (term, util.wrap(text, width=width,
483 479 initindent=defindent,
484 480 hangindent=defindent))
485 481 subindent = indent
486 482 if block['type'] == 'bullet':
487 483 if block['lines'][0].startswith('| '):
488 484 # Remove bullet for line blocks and add no extra
489 485 # indention.
490 486 block['lines'][0] = block['lines'][0][2:]
491 487 else:
492 488 m = _bulletre.match(block['lines'][0])
493 489 subindent = indent + m.end() * ' '
494 490 elif block['type'] == 'field':
495 keywidth = block['keywidth']
496 491 key = block['key']
497
498 492 subindent = indent + _fieldwidth * ' '
499 493 if len(key) + 2 > _fieldwidth:
500 494 # key too large, use full line width
501 495 key = key.ljust(width)
502 elif keywidth + 2 < _fieldwidth:
503 # all keys are small, add only two spaces
504 key = key.ljust(keywidth + 2)
505 subindent = indent + (keywidth + 2) * ' '
506 496 else:
507 # mixed sizes, use fieldwidth for this one
497 # key fits within field width
508 498 key = key.ljust(_fieldwidth)
509 499 block['lines'][0] = key + block['lines'][0]
510 500 elif block['type'] == 'option':
511 501 return formatoption(block, width)
512 502
513 503 text = ' '.join(map(str.strip, block['lines']))
514 504 return util.wrap(text, width=width,
515 505 initindent=indent,
516 506 hangindent=subindent) + '\n'
517 507
518 508 def formathtml(blocks):
519 509 """Format RST blocks as HTML"""
520 510
521 511 out = []
522 512 headernest = ''
523 513 listnest = []
524 514
525 515 def openlist(start, level):
526 516 if not listnest or listnest[-1][0] != start:
527 517 listnest.append((start, level))
528 518 out.append('<%s>\n' % start)
529 519
530 520 blocks = [b for b in blocks if b['type'] != 'margin']
531 521
532 522 for pos, b in enumerate(blocks):
533 523 btype = b['type']
534 524 level = b['indent']
535 525 lines = b['lines']
536 526
537 527 if btype == 'admonition':
538 528 admonition = _admonitiontitles[b['admonitiontitle']]
539 529 text = ' '.join(map(str.strip, lines))
540 530 out.append('<p>\n<b>%s</b> %s\n</p>\n' % (admonition, text))
541 531 elif btype == 'paragraph':
542 532 out.append('<p>\n%s\n</p>\n' % '\n'.join(lines))
543 533 elif btype == 'margin':
544 534 pass
545 535 elif btype == 'literal':
546 536 out.append('<pre>\n%s\n</pre>\n' % '\n'.join(lines))
547 537 elif btype == 'section':
548 538 i = b['underline']
549 539 if i not in headernest:
550 540 headernest += i
551 541 level = headernest.index(i) + 1
552 542 out.append('<h%d>%s</h%d>\n' % (level, lines[0], level))
553 543 elif btype == 'table':
554 544 table = b['table']
555 545 t = []
556 546 for row in table:
557 547 l = []
558 548 for v in zip(row):
559 549 if not t:
560 550 l.append('<th>%s</th>' % v)
561 551 else:
562 552 l.append('<td>%s</td>' % v)
563 553 t.append(' <tr>%s</tr>\n' % ''.join(l))
564 554 out.append('<table>\n%s</table>\n' % ''.join(t))
565 555 elif btype == 'definition':
566 556 openlist('dl', level)
567 557 term = lines[0]
568 558 text = ' '.join(map(str.strip, lines[1:]))
569 559 out.append(' <dt>%s\n <dd>%s\n' % (term, text))
570 560 elif btype == 'bullet':
571 561 bullet, head = lines[0].split(' ', 1)
572 562 if bullet == '-':
573 563 openlist('ul', level)
574 564 else:
575 565 openlist('ol', level)
576 566 out.append(' <li> %s\n' % ' '.join([head] + lines[1:]))
577 567 elif btype == 'field':
578 568 openlist('dl', level)
579 569 key = b['key']
580 570 text = ' '.join(map(str.strip, lines))
581 571 out.append(' <dt>%s\n <dd>%s\n' % (key, text))
582 572 elif btype == 'option':
583 573 openlist('dl', level)
584 574 opt = b['optstr']
585 575 desc = ' '.join(map(str.strip, lines))
586 576 out.append(' <dt>%s\n <dd>%s\n' % (opt, desc))
587 577
588 578 # close lists if indent level of next block is lower
589 579 if listnest:
590 580 start, level = listnest[-1]
591 581 if pos == len(blocks) - 1:
592 582 out.append('</%s>\n' % start)
593 583 listnest.pop()
594 584 else:
595 585 nb = blocks[pos + 1]
596 586 ni = nb['indent']
597 587 if (ni < level or
598 588 (ni == level and
599 589 nb['type'] not in 'definition bullet field option')):
600 590 out.append('</%s>\n' % start)
601 591 listnest.pop()
602 592
603 593 return ''.join(out)
604 594
605 595 def parse(text, indent=0, keep=None):
606 596 """Parse text into a list of blocks"""
607 597 pruned = []
608 598 blocks = findblocks(text)
609 599 for b in blocks:
610 600 b['indent'] += indent
611 601 blocks = findliteralblocks(blocks)
612 602 blocks = findtables(blocks)
613 603 blocks, pruned = prunecontainers(blocks, keep or [])
614 604 blocks = findsections(blocks)
615 605 blocks = inlineliterals(blocks)
616 606 blocks = hgrole(blocks)
617 607 blocks = splitparagraphs(blocks)
618 608 blocks = updatefieldlists(blocks)
619 609 blocks = updateoptionlists(blocks)
620 610 blocks = addmargins(blocks)
621 611 blocks = prunecomments(blocks)
622 612 blocks = findadmonitions(blocks)
623 613 return blocks, pruned
624 614
625 615 def formatblocks(blocks, width):
626 616 text = ''.join(formatblock(b, width) for b in blocks)
627 617 return text
628 618
629 619 def format(text, width=80, indent=0, keep=None, style='plain'):
630 620 """Parse and format the text according to width."""
631 621 blocks, pruned = parse(text, indent, keep or [])
632 622 if style == 'html':
633 623 text = formathtml(blocks)
634 624 else:
635 625 text = ''.join(formatblock(b, width) for b in blocks)
636 626 if keep is None:
637 627 return text
638 628 else:
639 629 return text, pruned
640 630
641 631 def getsections(blocks):
642 632 '''return a list of (section name, nesting level, blocks) tuples'''
643 633 nest = ""
644 634 level = 0
645 635 secs = []
646 636 for b in blocks:
647 637 if b['type'] == 'section':
648 638 i = b['underline']
649 639 if i not in nest:
650 640 nest += i
651 641 level = nest.index(i) + 1
652 642 nest = nest[:level]
653 643 secs.append((b['lines'][0], level, [b]))
654 644 else:
655 645 if not secs:
656 646 # add an initial empty section
657 647 secs = [('', 0, [])]
658 648 secs[-1][2].append(b)
659 649 return secs
660 650
661 651 def decorateblocks(blocks, width):
662 652 '''generate a list of (section name, line text) pairs for search'''
663 653 lines = []
664 654 for s in getsections(blocks):
665 655 section = s[0]
666 656 text = formatblocks(s[2], width)
667 657 lines.append([(section, l) for l in text.splitlines(True)])
668 658 return lines
669 659
670 660 def maketable(data, indent=0, header=False):
671 661 '''Generate an RST table for the given table data'''
672 662
673 663 widths = [max(encoding.colwidth(e) for e in c) for c in zip(*data)]
674 664 indent = ' ' * indent
675 665 div = indent + ' '.join('=' * w for w in widths) + '\n'
676 666
677 667 out = [div]
678 668 for row in data:
679 669 l = []
680 670 for w, v in zip(widths, row):
681 671 pad = ' ' * (w - encoding.colwidth(v))
682 672 l.append(v + pad)
683 673 out.append(indent + ' '.join(l) + "\n")
684 674 if header and len(data) > 1:
685 675 out.insert(2, div)
686 676 out.append(div)
687 677 return ''.join(out)
@@ -1,393 +1,395 b''
1 1 $ "$TESTDIR/hghave" unix-permissions || exit 80
2 2
3 3 $ cat >> $HGRCPATH <<EOF
4 4 > [extensions]
5 5 > convert=
6 6 > [convert]
7 7 > hg.saverev=False
8 8 > EOF
9 9 $ hg help convert
10 10 hg convert [OPTION]... SOURCE [DEST [REVMAP]]
11 11
12 12 convert a foreign SCM repository to a Mercurial one.
13 13
14 14 Accepted source formats [identifiers]:
15 15
16 16 - Mercurial [hg]
17 17 - CVS [cvs]
18 18 - Darcs [darcs]
19 19 - git [git]
20 20 - Subversion [svn]
21 21 - Monotone [mtn]
22 22 - GNU Arch [gnuarch]
23 23 - Bazaar [bzr]
24 24 - Perforce [p4]
25 25
26 26 Accepted destination formats [identifiers]:
27 27
28 28 - Mercurial [hg]
29 29 - Subversion [svn] (history on branches is not preserved)
30 30
31 31 If no revision is given, all revisions will be converted. Otherwise,
32 32 convert will only import up to the named revision (given in a format
33 33 understood by the source).
34 34
35 35 If no destination directory name is specified, it defaults to the basename
36 36 of the source with "-hg" appended. If the destination repository doesn't
37 37 exist, it will be created.
38 38
39 39 By default, all sources except Mercurial will use --branchsort. Mercurial
40 40 uses --sourcesort to preserve original revision numbers order. Sort modes
41 41 have the following effects:
42 42
43 43 --branchsort convert from parent to child revision when possible, which
44 44 means branches are usually converted one after the other.
45 45 It generates more compact repositories.
46 46 --datesort sort revisions by date. Converted repositories have good-
47 47 looking changelogs but are often an order of magnitude
48 48 larger than the same ones generated by --branchsort.
49 49 --sourcesort try to preserve source revisions order, only supported by
50 50 Mercurial sources.
51 51
52 52 If "REVMAP" isn't given, it will be put in a default location
53 53 ("<dest>/.hg/shamap" by default). The "REVMAP" is a simple text file that
54 54 maps each source commit ID to the destination ID for that revision, like
55 55 so:
56 56
57 57 <source ID> <destination ID>
58 58
59 59 If the file doesn't exist, it's automatically created. It's updated on
60 60 each commit copied, so "hg convert" can be interrupted and can be run
61 61 repeatedly to copy new commits.
62 62
63 63 The authormap is a simple text file that maps each source commit author to
64 64 a destination commit author. It is handy for source SCMs that use unix
65 65 logins to identify authors (eg: CVS). One line per author mapping and the
66 66 line format is:
67 67
68 68 source author = destination author
69 69
70 70 Empty lines and lines starting with a "#" are ignored.
71 71
72 72 The filemap is a file that allows filtering and remapping of files and
73 73 directories. Each line can contain one of the following directives:
74 74
75 75 include path/to/file-or-dir
76 76
77 77 exclude path/to/file-or-dir
78 78
79 79 rename path/to/source path/to/destination
80 80
81 81 Comment lines start with "#". A specified path matches if it equals the
82 82 full relative name of a file or one of its parent directories. The
83 83 "include" or "exclude" directive with the longest matching path applies,
84 84 so line order does not matter.
85 85
86 86 The "include" directive causes a file, or all files under a directory, to
87 87 be included in the destination repository, and the exclusion of all other
88 88 files and directories not explicitly included. The "exclude" directive
89 89 causes files or directories to be omitted. The "rename" directive renames
90 90 a file or directory if it is converted. To rename from a subdirectory into
91 91 the root of the repository, use "." as the path to rename to.
92 92
93 93 The splicemap is a file that allows insertion of synthetic history,
94 94 letting you specify the parents of a revision. This is useful if you want
95 95 to e.g. give a Subversion merge two parents, or graft two disconnected
96 96 series of history together. Each entry contains a key, followed by a
97 97 space, followed by one or two comma-separated values:
98 98
99 99 key parent1, parent2
100 100
101 101 The key is the revision ID in the source revision control system whose
102 102 parents should be modified (same format as a key in .hg/shamap). The
103 103 values are the revision IDs (in either the source or destination revision
104 104 control system) that should be used as the new parents for that node. For
105 105 example, if you have merged "release-1.0" into "trunk", then you should
106 106 specify the revision on "trunk" as the first parent and the one on the
107 107 "release-1.0" branch as the second.
108 108
109 109 The branchmap is a file that allows you to rename a branch when it is
110 110 being brought in from whatever external repository. When used in
111 111 conjunction with a splicemap, it allows for a powerful combination to help
112 112 fix even the most badly mismanaged repositories and turn them into nicely
113 113 structured Mercurial repositories. The branchmap contains lines of the
114 114 form:
115 115
116 116 original_branch_name new_branch_name
117 117
118 118 where "original_branch_name" is the name of the branch in the source
119 119 repository, and "new_branch_name" is the name of the branch is the
120 120 destination repository. No whitespace is allowed in the branch names. This
121 121 can be used to (for instance) move code in one repository from "default"
122 122 to a named branch.
123 123
124 124 Mercurial Source
125 125 ''''''''''''''''
126 126
127 127 The Mercurial source recognizes the following configuration options, which
128 128 you can set on the command line with "--config":
129 129
130 130 convert.hg.ignoreerrors
131 ignore integrity errors when reading. Use it to fix Mercurial
132 repositories with missing revlogs, by converting from and to
133 Mercurial. Default is False.
131 ignore integrity errors when reading. Use it to fix
132 Mercurial repositories with missing revlogs, by converting
133 from and to Mercurial. Default is False.
134 134 convert.hg.saverev
135 store original revision ID in changeset (forces target IDs to
136 change). It takes a boolean argument and defaults to False.
135 store original revision ID in changeset (forces target IDs
136 to change). It takes a boolean argument and defaults to
137 False.
137 138 convert.hg.startrev
138 convert start revision and its descendants. It takes a hg
139 revision identifier and defaults to 0.
139 convert start revision and its descendants. It takes a hg
140 revision identifier and defaults to 0.
140 141
141 142 CVS Source
142 143 ''''''''''
143 144
144 145 CVS source will use a sandbox (i.e. a checked-out copy) from CVS to
145 146 indicate the starting point of what will be converted. Direct access to
146 147 the repository files is not needed, unless of course the repository is
147 148 ":local:". The conversion uses the top level directory in the sandbox to
148 149 find the CVS repository, and then uses CVS rlog commands to find files to
149 150 convert. This means that unless a filemap is given, all files under the
150 151 starting directory will be converted, and that any directory
151 152 reorganization in the CVS sandbox is ignored.
152 153
153 154 The following options can be used with "--config":
154 155
155 156 convert.cvsps.cache
156 Set to False to disable remote log caching, for testing and
157 debugging purposes. Default is True.
157 Set to False to disable remote log caching, for testing and
158 debugging purposes. Default is True.
158 159 convert.cvsps.fuzz
159 Specify the maximum time (in seconds) that is allowed between
160 commits with identical user and log message in a single
161 changeset. When very large files were checked in as part of a
162 changeset then the default may not be long enough. The default
163 is 60.
160 Specify the maximum time (in seconds) that is allowed
161 between commits with identical user and log message in a
162 single changeset. When very large files were checked in as
163 part of a changeset then the default may not be long enough.
164 The default is 60.
164 165 convert.cvsps.mergeto
165 Specify a regular expression to which commit log messages are
166 matched. If a match occurs, then the conversion process will
167 insert a dummy revision merging the branch on which this log
168 message occurs to the branch indicated in the regex. Default
169 is "{{mergetobranch ([-\w]+)}}"
166 Specify a regular expression to which commit log messages
167 are matched. If a match occurs, then the conversion process
168 will insert a dummy revision merging the branch on which
169 this log message occurs to the branch indicated in the
170 regex. Default is "{{mergetobranch ([-\w]+)}}"
170 171 convert.cvsps.mergefrom
171 Specify a regular expression to which commit log messages are
172 matched. If a match occurs, then the conversion process will
173 add the most recent revision on the branch indicated in the
174 regex as the second parent of the changeset. Default is
175 "{{mergefrombranch ([-\w]+)}}"
176 hook.cvslog
177 Specify a Python function to be called at the end of gathering
178 the CVS log. The function is passed a list with the log
179 entries, and can modify the entries in-place, or add or delete
180 them.
172 Specify a regular expression to which commit log messages
173 are matched. If a match occurs, then the conversion process
174 will add the most recent revision on the branch indicated in
175 the regex as the second parent of the changeset. Default is
176 "{{mergefrombranch ([-\w]+)}}"
177 hook.cvslog Specify a Python function to be called at the end of
178 gathering the CVS log. The function is passed a list with
179 the log entries, and can modify the entries in-place, or add
180 or delete them.
181 181 hook.cvschangesets
182 Specify a Python function to be called after the changesets
183 are calculated from the the CVS log. The function is passed a
184 list with the changeset entries, and can modify the changesets
185 in-place, or add or delete them.
182 Specify a Python function to be called after the changesets
183 are calculated from the the CVS log. The function is passed
184 a list with the changeset entries, and can modify the
185 changesets in-place, or add or delete them.
186 186
187 187 An additional "debugcvsps" Mercurial command allows the builtin changeset
188 188 merging code to be run without doing a conversion. Its parameters and
189 189 output are similar to that of cvsps 2.1. Please see the command help for
190 190 more details.
191 191
192 192 Subversion Source
193 193 '''''''''''''''''
194 194
195 195 Subversion source detects classical trunk/branches/tags layouts. By
196 196 default, the supplied "svn://repo/path/" source URL is converted as a
197 197 single branch. If "svn://repo/path/trunk" exists it replaces the default
198 198 branch. If "svn://repo/path/branches" exists, its subdirectories are
199 199 listed as possible branches. If "svn://repo/path/tags" exists, it is
200 200 looked for tags referencing converted branches. Default "trunk",
201 201 "branches" and "tags" values can be overridden with following options. Set
202 202 them to paths relative to the source URL, or leave them blank to disable
203 203 auto detection.
204 204
205 205 The following options can be set with "--config":
206 206
207 207 convert.svn.branches
208 specify the directory containing branches. The default is
209 "branches".
208 specify the directory containing branches. The default is
209 "branches".
210 210 convert.svn.tags
211 specify the directory containing tags. The default is "tags".
211 specify the directory containing tags. The default is
212 "tags".
212 213 convert.svn.trunk
213 specify the name of the trunk branch. The default is "trunk".
214 specify the name of the trunk branch. The default is
215 "trunk".
214 216
215 217 Source history can be retrieved starting at a specific revision, instead
216 218 of being integrally converted. Only single branch conversions are
217 219 supported.
218 220
219 221 convert.svn.startrev
220 specify start Subversion revision number. The default is 0.
222 specify start Subversion revision number. The default is 0.
221 223
222 224 Perforce Source
223 225 '''''''''''''''
224 226
225 227 The Perforce (P4) importer can be given a p4 depot path or a client
226 228 specification as source. It will convert all files in the source to a flat
227 229 Mercurial repository, ignoring labels, branches and integrations. Note
228 230 that when a depot path is given you then usually should specify a target
229 231 directory, because otherwise the target may be named "...-hg".
230 232
231 233 It is possible to limit the amount of source history to be converted by
232 234 specifying an initial Perforce revision:
233 235
234 236 convert.p4.startrev
235 specify initial Perforce revision (a Perforce changelist
236 number).
237 specify initial Perforce revision (a Perforce changelist
238 number).
237 239
238 240 Mercurial Destination
239 241 '''''''''''''''''''''
240 242
241 243 The following options are supported:
242 244
243 245 convert.hg.clonebranches
244 dispatch source branches in separate clones. The default is
245 False.
246 dispatch source branches in separate clones. The default is
247 False.
246 248 convert.hg.tagsbranch
247 branch name for tag revisions, defaults to "default".
249 branch name for tag revisions, defaults to "default".
248 250 convert.hg.usebranchnames
249 preserve branch names. The default is True.
251 preserve branch names. The default is True.
250 252
251 253 options:
252 254
253 255 -s --source-type TYPE source repository type
254 256 -d --dest-type TYPE destination repository type
255 257 -r --rev REV import up to target revision REV
256 258 -A --authormap FILE remap usernames using this file
257 259 --filemap FILE remap file names using contents of file
258 260 --splicemap FILE splice synthesized history into place
259 261 --branchmap FILE change branch names while converting
260 262 --branchsort try to sort changesets by branches
261 263 --datesort try to sort changesets by date
262 264 --sourcesort preserve source changesets order
263 265
264 266 use "hg -v help convert" to show more info
265 267 $ hg init a
266 268 $ cd a
267 269 $ echo a > a
268 270 $ hg ci -d'0 0' -Ama
269 271 adding a
270 272 $ hg cp a b
271 273 $ hg ci -d'1 0' -mb
272 274 $ hg rm a
273 275 $ hg ci -d'2 0' -mc
274 276 $ hg mv b a
275 277 $ hg ci -d'3 0' -md
276 278 $ echo a >> a
277 279 $ hg ci -d'4 0' -me
278 280 $ cd ..
279 281 $ hg convert a 2>&1 | grep -v 'subversion python bindings could not be loaded'
280 282 assuming destination a-hg
281 283 initializing destination a-hg repository
282 284 scanning source...
283 285 sorting...
284 286 converting...
285 287 4 a
286 288 3 b
287 289 2 c
288 290 1 d
289 291 0 e
290 292 $ hg --cwd a-hg pull ../a
291 293 pulling from ../a
292 294 searching for changes
293 295 no changes found
294 296 $ touch bogusfile
295 297
296 298 should fail
297 299
298 300 $ hg convert a bogusfile
299 301 initializing destination bogusfile repository
300 302 abort: cannot create new bundle repository
301 303 [255]
302 304 $ mkdir bogusdir
303 305 $ chmod 000 bogusdir
304 306
305 307 should fail
306 308
307 309 $ hg convert a bogusdir
308 310 abort: Permission denied: bogusdir
309 311 [255]
310 312
311 313 should succeed
312 314
313 315 $ chmod 700 bogusdir
314 316 $ hg convert a bogusdir
315 317 initializing destination bogusdir repository
316 318 scanning source...
317 319 sorting...
318 320 converting...
319 321 4 a
320 322 3 b
321 323 2 c
322 324 1 d
323 325 0 e
324 326
325 327 test pre and post conversion actions
326 328
327 329 $ echo 'include b' > filemap
328 330 $ hg convert --debug --filemap filemap a partialb | \
329 331 > grep 'run hg'
330 332 run hg source pre-conversion action
331 333 run hg sink pre-conversion action
332 334 run hg sink post-conversion action
333 335 run hg source post-conversion action
334 336
335 337 converting empty dir should fail "nicely
336 338
337 339 $ mkdir emptydir
338 340
339 341 override $PATH to ensure p4 not visible; use $PYTHON in case we're
340 342 running from a devel copy, not a temp installation
341 343
342 344 $ PATH="$BINDIR" $PYTHON "$BINDIR"/hg convert emptydir
343 345 assuming destination emptydir-hg
344 346 initializing destination emptydir-hg repository
345 347 emptydir does not look like a CVS checkout
346 348 emptydir does not look like a Git repository
347 349 emptydir does not look like a Subversion repository
348 350 emptydir is not a local Mercurial repository
349 351 emptydir does not look like a darcs repository
350 352 emptydir does not look like a monotone repository
351 353 emptydir does not look like a GNU Arch repository
352 354 emptydir does not look like a Bazaar repository
353 355 cannot find required "p4" tool
354 356 abort: emptydir: missing or unsupported repository
355 357 [255]
356 358
357 359 convert with imaginary source type
358 360
359 361 $ hg convert --source-type foo a a-foo
360 362 initializing destination a-foo repository
361 363 abort: foo: invalid source repository type
362 364 [255]
363 365
364 366 convert with imaginary sink type
365 367
366 368 $ hg convert --dest-type foo a a-foo
367 369 abort: foo: invalid destination repository type
368 370 [255]
369 371
370 372 testing: convert must not produce duplicate entries in fncache
371 373
372 374 $ hg convert a b
373 375 initializing destination b repository
374 376 scanning source...
375 377 sorting...
376 378 converting...
377 379 4 a
378 380 3 b
379 381 2 c
380 382 1 d
381 383 0 e
382 384
383 385 contents of fncache file:
384 386
385 387 $ cat b/.hg/store/fncache | sort
386 388 data/a.i
387 389 data/b.i
388 390
389 391 test bogus URL
390 392
391 393 $ hg convert -q bzr+ssh://foobar@selenic.com/baz baz
392 394 abort: bzr+ssh://foobar@selenic.com/baz: missing or unsupported repository
393 395 [255]
@@ -1,479 +1,479 b''
1 1 Test basic extension support
2 2
3 3 $ "$TESTDIR/hghave" no-outer-repo || exit 80
4 4
5 5 $ cat > foobar.py <<EOF
6 6 > import os
7 7 > from mercurial import commands
8 8 >
9 9 > def uisetup(ui):
10 10 > ui.write("uisetup called\\n")
11 11 >
12 12 > def reposetup(ui, repo):
13 13 > ui.write("reposetup called for %s\\n" % os.path.basename(repo.root))
14 14 > ui.write("ui %s= repo.ui\\n" % (ui == repo.ui and "=" or "!"))
15 15 >
16 16 > def foo(ui, *args, **kwargs):
17 17 > ui.write("Foo\\n")
18 18 >
19 19 > def bar(ui, *args, **kwargs):
20 20 > ui.write("Bar\\n")
21 21 >
22 22 > cmdtable = {
23 23 > "foo": (foo, [], "hg foo"),
24 24 > "bar": (bar, [], "hg bar"),
25 25 > }
26 26 >
27 27 > commands.norepo += ' bar'
28 28 > EOF
29 29 $ abspath=`pwd`/foobar.py
30 30
31 31 $ mkdir barfoo
32 32 $ cp foobar.py barfoo/__init__.py
33 33 $ barfoopath=`pwd`/barfoo
34 34
35 35 $ hg init a
36 36 $ cd a
37 37 $ echo foo > file
38 38 $ hg add file
39 39 $ hg commit -m 'add file'
40 40
41 41 $ echo '[extensions]' >> $HGRCPATH
42 42 $ echo "foobar = $abspath" >> $HGRCPATH
43 43 $ hg foo
44 44 uisetup called
45 45 reposetup called for a
46 46 ui == repo.ui
47 47 Foo
48 48
49 49 $ cd ..
50 50 $ hg clone a b
51 51 uisetup called
52 52 reposetup called for a
53 53 ui == repo.ui
54 54 reposetup called for b
55 55 ui == repo.ui
56 56 updating to branch default
57 57 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
58 58
59 59 $ hg bar
60 60 uisetup called
61 61 Bar
62 62 $ echo 'foobar = !' >> $HGRCPATH
63 63
64 64 module/__init__.py-style
65 65
66 66 $ echo "barfoo = $barfoopath" >> $HGRCPATH
67 67 $ cd a
68 68 $ hg foo
69 69 uisetup called
70 70 reposetup called for a
71 71 ui == repo.ui
72 72 Foo
73 73 $ echo 'barfoo = !' >> $HGRCPATH
74 74
75 75 Check that extensions are loaded in phases:
76 76
77 77 $ cat > foo.py <<EOF
78 78 > import os
79 79 > name = os.path.basename(__file__).rsplit('.', 1)[0]
80 80 > print "1) %s imported" % name
81 81 > def uisetup(ui):
82 82 > print "2) %s uisetup" % name
83 83 > def extsetup():
84 84 > print "3) %s extsetup" % name
85 85 > def reposetup(ui, repo):
86 86 > print "4) %s reposetup" % name
87 87 > EOF
88 88
89 89 $ cp foo.py bar.py
90 90 $ echo 'foo = foo.py' >> $HGRCPATH
91 91 $ echo 'bar = bar.py' >> $HGRCPATH
92 92
93 93 Command with no output, we just want to see the extensions loaded:
94 94
95 95 $ hg paths
96 96 1) foo imported
97 97 1) bar imported
98 98 2) foo uisetup
99 99 2) bar uisetup
100 100 3) foo extsetup
101 101 3) bar extsetup
102 102 4) foo reposetup
103 103 4) bar reposetup
104 104
105 105 Check hgweb's load order:
106 106
107 107 $ cat > hgweb.cgi <<EOF
108 108 > #!/usr/bin/env python
109 109 > from mercurial import demandimport; demandimport.enable()
110 110 > from mercurial.hgweb import hgweb
111 111 > from mercurial.hgweb import wsgicgi
112 112 >
113 113 > application = hgweb('.', 'test repo')
114 114 > wsgicgi.launch(application)
115 115 > EOF
116 116
117 117 $ SCRIPT_NAME='/' SERVER_PORT='80' SERVER_NAME='localhost' python hgweb.cgi \
118 118 > | grep '^[0-9]) ' # ignores HTML output
119 119 1) foo imported
120 120 1) bar imported
121 121 2) foo uisetup
122 122 2) bar uisetup
123 123 3) foo extsetup
124 124 3) bar extsetup
125 125 4) foo reposetup
126 126 4) bar reposetup
127 127 4) foo reposetup
128 128 4) bar reposetup
129 129
130 130 $ echo 'foo = !' >> $HGRCPATH
131 131 $ echo 'bar = !' >> $HGRCPATH
132 132
133 133 $ cd ..
134 134
135 135 $ cat > empty.py <<EOF
136 136 > '''empty cmdtable
137 137 > '''
138 138 > cmdtable = {}
139 139 > EOF
140 140 $ emptypath=`pwd`/empty.py
141 141 $ echo "empty = $emptypath" >> $HGRCPATH
142 142 $ hg help empty
143 143 empty extension - empty cmdtable
144 144
145 145 no commands defined
146 146
147 147 $ echo 'empty = !' >> $HGRCPATH
148 148
149 149 $ cat > debugextension.py <<EOF
150 150 > '''only debugcommands
151 151 > '''
152 152 > def debugfoobar(ui, repo, *args, **opts):
153 153 > "yet another debug command"
154 154 > pass
155 155 >
156 156 > def foo(ui, repo, *args, **opts):
157 157 > """yet another foo command
158 158 >
159 159 > This command has been DEPRECATED since forever.
160 160 > """
161 161 > pass
162 162 >
163 163 > cmdtable = {
164 164 > "debugfoobar": (debugfoobar, (), "hg debugfoobar"),
165 165 > "foo": (foo, (), "hg foo")
166 166 > }
167 167 > EOF
168 168 $ debugpath=`pwd`/debugextension.py
169 169 $ echo "debugextension = $debugpath" >> $HGRCPATH
170 170
171 171 $ hg help debugextension
172 172 debugextension extension - only debugcommands
173 173
174 174 no commands defined
175 175
176 176 $ hg --verbose help debugextension
177 177 debugextension extension - only debugcommands
178 178
179 179 list of commands:
180 180
181 181 foo:
182 182 yet another foo command
183 183
184 184 global options:
185 185
186 186 -R --repository REPO repository root directory or name of overlay bundle
187 187 file
188 188 --cwd DIR change working directory
189 189 -y --noninteractive do not prompt, automatically pick the first choice for
190 190 all prompts
191 191 -q --quiet suppress output
192 192 -v --verbose enable additional output
193 193 --config CONFIG [+] set/override config option (use 'section.name=value')
194 194 --debug enable debugging output
195 195 --debugger start debugger
196 196 --encoding ENCODE set the charset encoding (default: ascii)
197 197 --encodingmode MODE set the charset encoding mode (default: strict)
198 198 --traceback always print a traceback on exception
199 199 --time time how long the command takes
200 200 --profile print command execution profile
201 201 --version output version information and exit
202 202 -h --help display help and exit
203 203
204 204 [+] marked option can be specified multiple times
205 205
206 206 $ hg --debug help debugextension
207 207 debugextension extension - only debugcommands
208 208
209 209 list of commands:
210 210
211 211 debugfoobar:
212 212 yet another debug command
213 213 foo:
214 214 yet another foo command
215 215
216 216 global options:
217 217
218 218 -R --repository REPO repository root directory or name of overlay bundle
219 219 file
220 220 --cwd DIR change working directory
221 221 -y --noninteractive do not prompt, automatically pick the first choice for
222 222 all prompts
223 223 -q --quiet suppress output
224 224 -v --verbose enable additional output
225 225 --config CONFIG [+] set/override config option (use 'section.name=value')
226 226 --debug enable debugging output
227 227 --debugger start debugger
228 228 --encoding ENCODE set the charset encoding (default: ascii)
229 229 --encodingmode MODE set the charset encoding mode (default: strict)
230 230 --traceback always print a traceback on exception
231 231 --time time how long the command takes
232 232 --profile print command execution profile
233 233 --version output version information and exit
234 234 -h --help display help and exit
235 235
236 236 [+] marked option can be specified multiple times
237 237 $ echo 'debugextension = !' >> $HGRCPATH
238 238
239 239 Extension module help vs command help:
240 240
241 241 $ echo 'extdiff =' >> $HGRCPATH
242 242 $ hg help extdiff
243 243 hg extdiff [OPT]... [FILE]...
244 244
245 245 use external program to diff repository (or selected files)
246 246
247 247 Show differences between revisions for the specified files, using an
248 248 external program. The default program used is diff, with default options
249 249 "-Npru".
250 250
251 251 To select a different program, use the -p/--program option. The program
252 252 will be passed the names of two directories to compare. To pass additional
253 253 options to the program, use -o/--option. These will be passed before the
254 254 names of the directories to compare.
255 255
256 256 When two revision arguments are given, then changes are shown between
257 257 those revisions. If only one revision is specified then that revision is
258 258 compared to the working directory, and, when no revisions are specified,
259 259 the working directory files are compared to its parent.
260 260
261 261 use "hg help -e extdiff" to show help for the extdiff extension
262 262
263 263 options:
264 264
265 265 -p --program CMD comparison program to run
266 266 -o --option OPT [+] pass option to comparison program
267 267 -r --rev REV [+] revision
268 268 -c --change REV change made by revision
269 269 -I --include PATTERN [+] include names matching the given patterns
270 270 -X --exclude PATTERN [+] exclude names matching the given patterns
271 271
272 272 [+] marked option can be specified multiple times
273 273
274 274 use "hg -v help extdiff" to show more info
275 275
276 276 $ hg help --extension extdiff
277 277 extdiff extension - command to allow external programs to compare revisions
278 278
279 279 The extdiff Mercurial extension allows you to use external programs to compare
280 280 revisions, or revision with working directory. The external diff programs are
281 281 called with a configurable set of options and two non-option arguments: paths
282 282 to directories containing snapshots of files to compare.
283 283
284 284 The extdiff extension also allows you to configure new diff commands, so you
285 285 do not need to type "hg extdiff -p kdiff3" always.
286 286
287 287 [extdiff]
288 288 # add new command that runs GNU diff(1) in 'context diff' mode
289 289 cdiff = gdiff -Nprc5
290 290 ## or the old way:
291 291 #cmd.cdiff = gdiff
292 292 #opts.cdiff = -Nprc5
293 293
294 294 # add new command called vdiff, runs kdiff3
295 295 vdiff = kdiff3
296 296
297 297 # add new command called meld, runs meld (no need to name twice)
298 298 meld =
299 299
300 300 # add new command called vimdiff, runs gvimdiff with DirDiff plugin
301 301 # (see http://www.vim.org/scripts/script.php?script_id=102) Non
302 302 # English user, be sure to put "let g:DirDiffDynamicDiffText = 1" in
303 303 # your .vimrc
304 304 vimdiff = gvim -f '+next' '+execute "DirDiff" argv(0) argv(1)'
305 305
306 306 Tool arguments can include variables that are expanded at runtime:
307 307
308 308 $parent1, $plabel1 - filename, descriptive label of first parent
309 309 $child, $clabel - filename, descriptive label of child revision
310 310 $parent2, $plabel2 - filename, descriptive label of second parent
311 311 $root - repository root
312 312 $parent is an alias for $parent1.
313 313
314 314 The extdiff extension will look in your [diff-tools] and [merge-tools]
315 315 sections for diff tool arguments, when none are specified in [extdiff].
316 316
317 317 [extdiff]
318 318 kdiff3 =
319 319
320 320 [diff-tools]
321 321 kdiff3.diffargs=--L1 '$plabel1' --L2 '$clabel' $parent $child
322 322
323 323 You can use -I/-X and list of file or directory names like normal "hg diff"
324 324 command. The extdiff extension makes snapshots of only needed files, so
325 325 running the external diff program will actually be pretty fast (at least
326 326 faster than having to compare the entire tree).
327 327
328 328 list of commands:
329 329
330 330 extdiff use external program to diff repository (or selected files)
331 331
332 332 use "hg -v help extdiff" to show builtin aliases and global options
333 333
334 334 $ echo 'extdiff = !' >> $HGRCPATH
335 335
336 336 Test help topic with same name as extension
337 337
338 338 $ cat > multirevs.py <<EOF
339 339 > from mercurial import commands
340 340 > """multirevs extension
341 341 > Big multi-line module docstring."""
342 342 > def multirevs(ui, repo, arg, *args, **opts):
343 343 > """multirevs command"""
344 344 > pass
345 345 > cmdtable = {
346 346 > "multirevs": (multirevs, [], 'ARG')
347 347 > }
348 348 > commands.norepo += ' multirevs'
349 349 > EOF
350 350 $ echo "multirevs = multirevs.py" >> $HGRCPATH
351 351
352 352 $ hg help multirevs
353 353 Specifying Multiple Revisions
354 354
355 355 When Mercurial accepts more than one revision, they may be specified
356 356 individually, or provided as a topologically continuous range, separated
357 357 by the ":" character.
358 358
359 359 The syntax of range notation is [BEGIN]:[END], where BEGIN and END are
360 360 revision identifiers. Both BEGIN and END are optional. If BEGIN is not
361 361 specified, it defaults to revision number 0. If END is not specified, it
362 362 defaults to the tip. The range ":" thus means "all revisions".
363 363
364 364 If BEGIN is greater than END, revisions are treated in reverse order.
365 365
366 366 A range acts as a closed interval. This means that a range of 3:5 gives 3,
367 367 4 and 5. Similarly, a range of 9:6 gives 9, 8, 7, and 6.
368 368
369 369 use "hg help -c multirevs" to see help for the multirevs command
370 370
371 371 $ hg help -c multirevs
372 372 hg multirevs ARG
373 373
374 374 multirevs command
375 375
376 376 use "hg -v help multirevs" to show more info
377 377
378 378 $ hg multirevs
379 379 hg multirevs: invalid arguments
380 380 hg multirevs ARG
381 381
382 382 multirevs command
383 383
384 384 use "hg help multirevs" to show the full help text
385 385 [255]
386 386
387 387 $ echo "multirevs = !" >> $HGRCPATH
388 388
389 389 Issue811: Problem loading extensions twice (by site and by user)
390 390
391 391 $ debugpath=`pwd`/debugissue811.py
392 392 $ cat > debugissue811.py <<EOF
393 393 > '''show all loaded extensions
394 394 > '''
395 395 > from mercurial import extensions, commands
396 396 >
397 397 > def debugextensions(ui):
398 398 > "yet another debug command"
399 399 > ui.write("%s\n" % '\n'.join([x for x, y in extensions.extensions()]))
400 400 >
401 401 > cmdtable = {"debugextensions": (debugextensions, (), "hg debugextensions")}
402 402 > commands.norepo += " debugextensions"
403 403 > EOF
404 404 $ echo "debugissue811 = $debugpath" >> $HGRCPATH
405 405 $ echo "mq=" >> $HGRCPATH
406 406 $ echo "hgext.mq=" >> $HGRCPATH
407 407 $ echo "hgext/mq=" >> $HGRCPATH
408 408
409 409 Show extensions:
410 410
411 411 $ hg debugextensions
412 412 debugissue811
413 413 mq
414 414
415 415 Disabled extension commands:
416 416
417 417 $ HGRCPATH=
418 418 $ export HGRCPATH
419 419 $ hg help email
420 420 'email' is provided by the following extension:
421 421
422 patchbomb command to send changesets as (a series of) patch emails
422 patchbomb command to send changesets as (a series of) patch emails
423 423
424 424 use "hg help extensions" for information on enabling extensions
425 425 $ hg qdel
426 426 hg: unknown command 'qdel'
427 427 'qdelete' is provided by the following extension:
428 428
429 mq manage a stack of patches
429 mq manage a stack of patches
430 430
431 431 use "hg help extensions" for information on enabling extensions
432 432 [255]
433 433 $ hg churn
434 434 hg: unknown command 'churn'
435 435 'churn' is provided by the following extension:
436 436
437 churn command to display statistics about repository history
437 churn command to display statistics about repository history
438 438
439 439 use "hg help extensions" for information on enabling extensions
440 440 [255]
441 441
442 442 Disabled extensions:
443 443
444 444 $ hg help churn
445 445 churn extension - command to display statistics about repository history
446 446
447 447 use "hg help extensions" for information on enabling extensions
448 448 $ hg help patchbomb
449 449 patchbomb extension - command to send changesets as (a series of) patch emails
450 450
451 451 use "hg help extensions" for information on enabling extensions
452 452
453 453 Broken disabled extension and command:
454 454
455 455 $ mkdir hgext
456 456 $ echo > hgext/__init__.py
457 457 $ cat > hgext/broken.py <<EOF
458 458 > "broken extension'
459 459 > EOF
460 460 $ cat > path.py <<EOF
461 461 > import os, sys
462 462 > sys.path.insert(0, os.environ['HGEXTPATH'])
463 463 > EOF
464 464 $ HGEXTPATH=`pwd`
465 465 $ export HGEXTPATH
466 466
467 467 $ hg --config extensions.path=./path.py help broken
468 468 broken extension - (no help text available)
469 469
470 470 use "hg help extensions" for information on enabling extensions
471 471
472 472 $ cat > hgext/forest.py <<EOF
473 473 > cmdtable = None
474 474 > EOF
475 475 $ hg --config extensions.path=./path.py help foo > /dev/null
476 476 warning: error finding commands in $TESTTMP/hgext/forest.py (glob)
477 477 hg: unknown command 'foo'
478 478 warning: error finding commands in $TESTTMP/hgext/forest.py (glob)
479 479 [255]
@@ -1,781 +1,781 b''
1 1 Short help:
2 2
3 3 $ hg
4 4 Mercurial Distributed SCM
5 5
6 6 basic commands:
7 7
8 8 add add the specified files on the next commit
9 9 annotate show changeset information by line for each file
10 10 clone make a copy of an existing repository
11 11 commit commit the specified files or all outstanding changes
12 12 diff diff repository (or selected files)
13 13 export dump the header and diffs for one or more changesets
14 14 forget forget the specified files on the next commit
15 15 init create a new repository in the given directory
16 16 log show revision history of entire repository or files
17 17 merge merge working directory with another revision
18 18 phase set or show the current phase name
19 19 pull pull changes from the specified source
20 20 push push changes to the specified destination
21 21 remove remove the specified files on the next commit
22 22 serve start stand-alone webserver
23 23 status show changed files in the working directory
24 24 summary summarize working directory state
25 25 update update working directory (or switch revisions)
26 26
27 27 use "hg help" for the full list of commands or "hg -v" for details
28 28
29 29 $ hg -q
30 30 add add the specified files on the next commit
31 31 annotate show changeset information by line for each file
32 32 clone make a copy of an existing repository
33 33 commit commit the specified files or all outstanding changes
34 34 diff diff repository (or selected files)
35 35 export dump the header and diffs for one or more changesets
36 36 forget forget the specified files on the next commit
37 37 init create a new repository in the given directory
38 38 log show revision history of entire repository or files
39 39 merge merge working directory with another revision
40 40 phase set or show the current phase name
41 41 pull pull changes from the specified source
42 42 push push changes to the specified destination
43 43 remove remove the specified files on the next commit
44 44 serve start stand-alone webserver
45 45 status show changed files in the working directory
46 46 summary summarize working directory state
47 47 update update working directory (or switch revisions)
48 48
49 49 $ hg help
50 50 Mercurial Distributed SCM
51 51
52 52 list of commands:
53 53
54 54 add add the specified files on the next commit
55 55 addremove add all new files, delete all missing files
56 56 annotate show changeset information by line for each file
57 57 archive create an unversioned archive of a repository revision
58 58 backout reverse effect of earlier changeset
59 59 bisect subdivision search of changesets
60 60 bookmarks track a line of development with movable markers
61 61 branch set or show the current branch name
62 62 branches list repository named branches
63 63 bundle create a changegroup file
64 64 cat output the current or given revision of files
65 65 clone make a copy of an existing repository
66 66 commit commit the specified files or all outstanding changes
67 67 copy mark files as copied for the next commit
68 68 diff diff repository (or selected files)
69 69 export dump the header and diffs for one or more changesets
70 70 forget forget the specified files on the next commit
71 71 graft copy changes from other branches onto the current branch
72 72 grep search for a pattern in specified files and revisions
73 73 heads show current repository heads or show branch heads
74 74 help show help for a given topic or a help overview
75 75 identify identify the working copy or specified revision
76 76 import import an ordered set of patches
77 77 incoming show new changesets found in source
78 78 init create a new repository in the given directory
79 79 locate locate files matching specific patterns
80 80 log show revision history of entire repository or files
81 81 manifest output the current or given revision of the project manifest
82 82 merge merge working directory with another revision
83 83 outgoing show changesets not found in the destination
84 84 parents show the parents of the working directory or revision
85 85 paths show aliases for remote repositories
86 86 phase set or show the current phase name
87 87 pull pull changes from the specified source
88 88 push push changes to the specified destination
89 89 recover roll back an interrupted transaction
90 90 remove remove the specified files on the next commit
91 91 rename rename files; equivalent of copy + remove
92 92 resolve redo merges or set/view the merge status of files
93 93 revert restore files to their checkout state
94 94 rollback roll back the last transaction (dangerous)
95 95 root print the root (top) of the current working directory
96 96 serve start stand-alone webserver
97 97 showconfig show combined config settings from all hgrc files
98 98 status show changed files in the working directory
99 99 summary summarize working directory state
100 100 tag add one or more tags for the current or given revision
101 101 tags list repository tags
102 102 tip show the tip revision
103 103 unbundle apply one or more changegroup files
104 104 update update working directory (or switch revisions)
105 105 verify verify the integrity of the repository
106 106 version output version and copyright information
107 107
108 108 additional help topics:
109 109
110 110 config Configuration Files
111 111 dates Date Formats
112 112 diffs Diff Formats
113 113 environment Environment Variables
114 114 extensions Using additional features
115 115 filesets Specifying File Sets
116 116 glossary Glossary
117 117 hgignore syntax for Mercurial ignore files
118 118 hgweb Configuring hgweb
119 119 merge-tools Merge Tools
120 120 multirevs Specifying Multiple Revisions
121 121 patterns File Name Patterns
122 122 revisions Specifying Single Revisions
123 123 revsets Specifying Revision Sets
124 124 subrepos Subrepositories
125 125 templating Template Usage
126 126 urls URL Paths
127 127
128 128 use "hg -v help" to show builtin aliases and global options
129 129
130 130 $ hg -q help
131 131 add add the specified files on the next commit
132 132 addremove add all new files, delete all missing files
133 133 annotate show changeset information by line for each file
134 134 archive create an unversioned archive of a repository revision
135 135 backout reverse effect of earlier changeset
136 136 bisect subdivision search of changesets
137 137 bookmarks track a line of development with movable markers
138 138 branch set or show the current branch name
139 139 branches list repository named branches
140 140 bundle create a changegroup file
141 141 cat output the current or given revision of files
142 142 clone make a copy of an existing repository
143 143 commit commit the specified files or all outstanding changes
144 144 copy mark files as copied for the next commit
145 145 diff diff repository (or selected files)
146 146 export dump the header and diffs for one or more changesets
147 147 forget forget the specified files on the next commit
148 148 graft copy changes from other branches onto the current branch
149 149 grep search for a pattern in specified files and revisions
150 150 heads show current repository heads or show branch heads
151 151 help show help for a given topic or a help overview
152 152 identify identify the working copy or specified revision
153 153 import import an ordered set of patches
154 154 incoming show new changesets found in source
155 155 init create a new repository in the given directory
156 156 locate locate files matching specific patterns
157 157 log show revision history of entire repository or files
158 158 manifest output the current or given revision of the project manifest
159 159 merge merge working directory with another revision
160 160 outgoing show changesets not found in the destination
161 161 parents show the parents of the working directory or revision
162 162 paths show aliases for remote repositories
163 163 phase set or show the current phase name
164 164 pull pull changes from the specified source
165 165 push push changes to the specified destination
166 166 recover roll back an interrupted transaction
167 167 remove remove the specified files on the next commit
168 168 rename rename files; equivalent of copy + remove
169 169 resolve redo merges or set/view the merge status of files
170 170 revert restore files to their checkout state
171 171 rollback roll back the last transaction (dangerous)
172 172 root print the root (top) of the current working directory
173 173 serve start stand-alone webserver
174 174 showconfig show combined config settings from all hgrc files
175 175 status show changed files in the working directory
176 176 summary summarize working directory state
177 177 tag add one or more tags for the current or given revision
178 178 tags list repository tags
179 179 tip show the tip revision
180 180 unbundle apply one or more changegroup files
181 181 update update working directory (or switch revisions)
182 182 verify verify the integrity of the repository
183 183 version output version and copyright information
184 184
185 185 additional help topics:
186 186
187 187 config Configuration Files
188 188 dates Date Formats
189 189 diffs Diff Formats
190 190 environment Environment Variables
191 191 extensions Using additional features
192 192 filesets Specifying File Sets
193 193 glossary Glossary
194 194 hgignore syntax for Mercurial ignore files
195 195 hgweb Configuring hgweb
196 196 merge-tools Merge Tools
197 197 multirevs Specifying Multiple Revisions
198 198 patterns File Name Patterns
199 199 revisions Specifying Single Revisions
200 200 revsets Specifying Revision Sets
201 201 subrepos Subrepositories
202 202 templating Template Usage
203 203 urls URL Paths
204 204
205 205 Test short command list with verbose option
206 206
207 207 $ hg -v help shortlist
208 208 Mercurial Distributed SCM
209 209
210 210 basic commands:
211 211
212 212 add:
213 213 add the specified files on the next commit
214 214 annotate, blame:
215 215 show changeset information by line for each file
216 216 clone:
217 217 make a copy of an existing repository
218 218 commit, ci:
219 219 commit the specified files or all outstanding changes
220 220 diff:
221 221 diff repository (or selected files)
222 222 export:
223 223 dump the header and diffs for one or more changesets
224 224 forget:
225 225 forget the specified files on the next commit
226 226 init:
227 227 create a new repository in the given directory
228 228 log, history:
229 229 show revision history of entire repository or files
230 230 merge:
231 231 merge working directory with another revision
232 232 phase:
233 233 set or show the current phase name
234 234 pull:
235 235 pull changes from the specified source
236 236 push:
237 237 push changes to the specified destination
238 238 remove, rm:
239 239 remove the specified files on the next commit
240 240 serve:
241 241 start stand-alone webserver
242 242 status, st:
243 243 show changed files in the working directory
244 244 summary, sum:
245 245 summarize working directory state
246 246 update, up, checkout, co:
247 247 update working directory (or switch revisions)
248 248
249 249 global options:
250 250
251 251 -R --repository REPO repository root directory or name of overlay bundle
252 252 file
253 253 --cwd DIR change working directory
254 254 -y --noninteractive do not prompt, automatically pick the first choice for
255 255 all prompts
256 256 -q --quiet suppress output
257 257 -v --verbose enable additional output
258 258 --config CONFIG [+] set/override config option (use 'section.name=value')
259 259 --debug enable debugging output
260 260 --debugger start debugger
261 261 --encoding ENCODE set the charset encoding (default: ascii)
262 262 --encodingmode MODE set the charset encoding mode (default: strict)
263 263 --traceback always print a traceback on exception
264 264 --time time how long the command takes
265 265 --profile print command execution profile
266 266 --version output version information and exit
267 267 -h --help display help and exit
268 268
269 269 [+] marked option can be specified multiple times
270 270
271 271 use "hg help" for the full list of commands
272 272
273 273 $ hg add -h
274 274 hg add [OPTION]... [FILE]...
275 275
276 276 add the specified files on the next commit
277 277
278 278 Schedule files to be version controlled and added to the repository.
279 279
280 280 The files will be added to the repository at the next commit. To undo an
281 281 add before that, see "hg forget".
282 282
283 283 If no names are given, add all files to the repository.
284 284
285 285 Returns 0 if all files are successfully added.
286 286
287 287 options:
288 288
289 289 -I --include PATTERN [+] include names matching the given patterns
290 290 -X --exclude PATTERN [+] exclude names matching the given patterns
291 291 -S --subrepos recurse into subrepositories
292 292 -n --dry-run do not perform actions, just print output
293 293
294 294 [+] marked option can be specified multiple times
295 295
296 296 use "hg -v help add" to show more info
297 297
298 298 Verbose help for add
299 299
300 300 $ hg add -hv
301 301 hg add [OPTION]... [FILE]...
302 302
303 303 add the specified files on the next commit
304 304
305 305 Schedule files to be version controlled and added to the repository.
306 306
307 307 The files will be added to the repository at the next commit. To undo an
308 308 add before that, see "hg forget".
309 309
310 310 If no names are given, add all files to the repository.
311 311
312 312 An example showing how new (unknown) files are added automatically by "hg
313 313 add":
314 314
315 315 $ ls
316 316 foo.c
317 317 $ hg status
318 318 ? foo.c
319 319 $ hg add
320 320 adding foo.c
321 321 $ hg status
322 322 A foo.c
323 323
324 324 Returns 0 if all files are successfully added.
325 325
326 326 options:
327 327
328 328 -I --include PATTERN [+] include names matching the given patterns
329 329 -X --exclude PATTERN [+] exclude names matching the given patterns
330 330 -S --subrepos recurse into subrepositories
331 331 -n --dry-run do not perform actions, just print output
332 332
333 333 [+] marked option can be specified multiple times
334 334
335 335 global options:
336 336
337 337 -R --repository REPO repository root directory or name of overlay bundle
338 338 file
339 339 --cwd DIR change working directory
340 340 -y --noninteractive do not prompt, automatically pick the first choice for
341 341 all prompts
342 342 -q --quiet suppress output
343 343 -v --verbose enable additional output
344 344 --config CONFIG [+] set/override config option (use 'section.name=value')
345 345 --debug enable debugging output
346 346 --debugger start debugger
347 347 --encoding ENCODE set the charset encoding (default: ascii)
348 348 --encodingmode MODE set the charset encoding mode (default: strict)
349 349 --traceback always print a traceback on exception
350 350 --time time how long the command takes
351 351 --profile print command execution profile
352 352 --version output version information and exit
353 353 -h --help display help and exit
354 354
355 355 [+] marked option can be specified multiple times
356 356
357 357 Test help option with version option
358 358
359 359 $ hg add -h --version
360 360 Mercurial Distributed SCM (version *) (glob)
361 361 (see http://mercurial.selenic.com for more information)
362 362
363 363 Copyright (C) 2005-2012 Matt Mackall and others
364 364 This is free software; see the source for copying conditions. There is NO
365 365 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
366 366
367 367 $ hg add --skjdfks
368 368 hg add: option --skjdfks not recognized
369 369 hg add [OPTION]... [FILE]...
370 370
371 371 add the specified files on the next commit
372 372
373 373 options:
374 374
375 375 -I --include PATTERN [+] include names matching the given patterns
376 376 -X --exclude PATTERN [+] exclude names matching the given patterns
377 377 -S --subrepos recurse into subrepositories
378 378 -n --dry-run do not perform actions, just print output
379 379
380 380 [+] marked option can be specified multiple times
381 381
382 382 use "hg help add" to show the full help text
383 383 [255]
384 384
385 385 Test ambiguous command help
386 386
387 387 $ hg help ad
388 388 list of commands:
389 389
390 390 add add the specified files on the next commit
391 391 addremove add all new files, delete all missing files
392 392
393 393 use "hg -v help ad" to show builtin aliases and global options
394 394
395 395 Test command without options
396 396
397 397 $ hg help verify
398 398 hg verify
399 399
400 400 verify the integrity of the repository
401 401
402 402 Verify the integrity of the current repository.
403 403
404 404 This will perform an extensive check of the repository's integrity,
405 405 validating the hashes and checksums of each entry in the changelog,
406 406 manifest, and tracked files, as well as the integrity of their crosslinks
407 407 and indices.
408 408
409 409 Returns 0 on success, 1 if errors are encountered.
410 410
411 411 use "hg -v help verify" to show more info
412 412
413 413 $ hg help diff
414 414 hg diff [OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...
415 415
416 416 diff repository (or selected files)
417 417
418 418 Show differences between revisions for the specified files.
419 419
420 420 Differences between files are shown using the unified diff format.
421 421
422 422 Note:
423 423 diff may generate unexpected results for merges, as it will default to
424 424 comparing against the working directory's first parent changeset if no
425 425 revisions are specified.
426 426
427 427 When two revision arguments are given, then changes are shown between
428 428 those revisions. If only one revision is specified then that revision is
429 429 compared to the working directory, and, when no revisions are specified,
430 430 the working directory files are compared to its parent.
431 431
432 432 Alternatively you can specify -c/--change with a revision to see the
433 433 changes in that changeset relative to its first parent.
434 434
435 435 Without the -a/--text option, diff will avoid generating diffs of files it
436 436 detects as binary. With -a, diff will generate a diff anyway, probably
437 437 with undesirable results.
438 438
439 439 Use the -g/--git option to generate diffs in the git extended diff format.
440 440 For more information, read "hg help diffs".
441 441
442 442 Returns 0 on success.
443 443
444 444 options:
445 445
446 446 -r --rev REV [+] revision
447 447 -c --change REV change made by revision
448 448 -a --text treat all files as text
449 449 -g --git use git extended diff format
450 450 --nodates omit dates from diff headers
451 451 -p --show-function show which function each change is in
452 452 --reverse produce a diff that undoes the changes
453 453 -w --ignore-all-space ignore white space when comparing lines
454 454 -b --ignore-space-change ignore changes in the amount of white space
455 455 -B --ignore-blank-lines ignore changes whose lines are all blank
456 456 -U --unified NUM number of lines of context to show
457 457 --stat output diffstat-style summary of changes
458 458 -I --include PATTERN [+] include names matching the given patterns
459 459 -X --exclude PATTERN [+] exclude names matching the given patterns
460 460 -S --subrepos recurse into subrepositories
461 461
462 462 [+] marked option can be specified multiple times
463 463
464 464 use "hg -v help diff" to show more info
465 465
466 466 $ hg help status
467 467 hg status [OPTION]... [FILE]...
468 468
469 469 aliases: st
470 470
471 471 show changed files in the working directory
472 472
473 473 Show status of files in the repository. If names are given, only files
474 474 that match are shown. Files that are clean or ignored or the source of a
475 475 copy/move operation, are not listed unless -c/--clean, -i/--ignored,
476 476 -C/--copies or -A/--all are given. Unless options described with "show
477 477 only ..." are given, the options -mardu are used.
478 478
479 479 Option -q/--quiet hides untracked (unknown and ignored) files unless
480 480 explicitly requested with -u/--unknown or -i/--ignored.
481 481
482 482 Note:
483 483 status may appear to disagree with diff if permissions have changed or
484 484 a merge has occurred. The standard diff format does not report
485 485 permission changes and diff only reports changes relative to one merge
486 486 parent.
487 487
488 488 If one revision is given, it is used as the base revision. If two
489 489 revisions are given, the differences between them are shown. The --change
490 490 option can also be used as a shortcut to list the changed files of a
491 491 revision from its first parent.
492 492
493 493 The codes used to show the status of files are:
494 494
495 495 M = modified
496 496 A = added
497 497 R = removed
498 498 C = clean
499 499 ! = missing (deleted by non-hg command, but still tracked)
500 500 ? = not tracked
501 501 I = ignored
502 502 = origin of the previous file listed as A (added)
503 503
504 504 Returns 0 on success.
505 505
506 506 options:
507 507
508 508 -A --all show status of all files
509 509 -m --modified show only modified files
510 510 -a --added show only added files
511 511 -r --removed show only removed files
512 512 -d --deleted show only deleted (but tracked) files
513 513 -c --clean show only files without changes
514 514 -u --unknown show only unknown (not tracked) files
515 515 -i --ignored show only ignored files
516 516 -n --no-status hide status prefix
517 517 -C --copies show source of copied files
518 518 -0 --print0 end filenames with NUL, for use with xargs
519 519 --rev REV [+] show difference from revision
520 520 --change REV list the changed files of a revision
521 521 -I --include PATTERN [+] include names matching the given patterns
522 522 -X --exclude PATTERN [+] exclude names matching the given patterns
523 523 -S --subrepos recurse into subrepositories
524 524
525 525 [+] marked option can be specified multiple times
526 526
527 527 use "hg -v help status" to show more info
528 528
529 529 $ hg -q help status
530 530 hg status [OPTION]... [FILE]...
531 531
532 532 show changed files in the working directory
533 533
534 534 $ hg help foo
535 535 hg: unknown command 'foo'
536 536 Mercurial Distributed SCM
537 537
538 538 basic commands:
539 539
540 540 add add the specified files on the next commit
541 541 annotate show changeset information by line for each file
542 542 clone make a copy of an existing repository
543 543 commit commit the specified files or all outstanding changes
544 544 diff diff repository (or selected files)
545 545 export dump the header and diffs for one or more changesets
546 546 forget forget the specified files on the next commit
547 547 init create a new repository in the given directory
548 548 log show revision history of entire repository or files
549 549 merge merge working directory with another revision
550 550 phase set or show the current phase name
551 551 pull pull changes from the specified source
552 552 push push changes to the specified destination
553 553 remove remove the specified files on the next commit
554 554 serve start stand-alone webserver
555 555 status show changed files in the working directory
556 556 summary summarize working directory state
557 557 update update working directory (or switch revisions)
558 558
559 559 use "hg help" for the full list of commands or "hg -v" for details
560 560 [255]
561 561
562 562 $ hg skjdfks
563 563 hg: unknown command 'skjdfks'
564 564 Mercurial Distributed SCM
565 565
566 566 basic commands:
567 567
568 568 add add the specified files on the next commit
569 569 annotate show changeset information by line for each file
570 570 clone make a copy of an existing repository
571 571 commit commit the specified files or all outstanding changes
572 572 diff diff repository (or selected files)
573 573 export dump the header and diffs for one or more changesets
574 574 forget forget the specified files on the next commit
575 575 init create a new repository in the given directory
576 576 log show revision history of entire repository or files
577 577 merge merge working directory with another revision
578 578 phase set or show the current phase name
579 579 pull pull changes from the specified source
580 580 push push changes to the specified destination
581 581 remove remove the specified files on the next commit
582 582 serve start stand-alone webserver
583 583 status show changed files in the working directory
584 584 summary summarize working directory state
585 585 update update working directory (or switch revisions)
586 586
587 587 use "hg help" for the full list of commands or "hg -v" for details
588 588 [255]
589 589
590 590 $ cat > helpext.py <<EOF
591 591 > import os
592 592 > from mercurial import commands
593 593 >
594 594 > def nohelp(ui, *args, **kwargs):
595 595 > pass
596 596 >
597 597 > cmdtable = {
598 598 > "nohelp": (nohelp, [], "hg nohelp"),
599 599 > }
600 600 >
601 601 > commands.norepo += ' nohelp'
602 602 > EOF
603 603 $ echo '[extensions]' >> $HGRCPATH
604 604 $ echo "helpext = `pwd`/helpext.py" >> $HGRCPATH
605 605
606 606 Test command with no help text
607 607
608 608 $ hg help nohelp
609 609 hg nohelp
610 610
611 611 (no help text available)
612 612
613 613 use "hg -v help nohelp" to show more info
614 614
615 615 Test that default list of commands omits extension commands
616 616
617 617 $ hg help
618 618 Mercurial Distributed SCM
619 619
620 620 list of commands:
621 621
622 622 add add the specified files on the next commit
623 623 addremove add all new files, delete all missing files
624 624 annotate show changeset information by line for each file
625 625 archive create an unversioned archive of a repository revision
626 626 backout reverse effect of earlier changeset
627 627 bisect subdivision search of changesets
628 628 bookmarks track a line of development with movable markers
629 629 branch set or show the current branch name
630 630 branches list repository named branches
631 631 bundle create a changegroup file
632 632 cat output the current or given revision of files
633 633 clone make a copy of an existing repository
634 634 commit commit the specified files or all outstanding changes
635 635 copy mark files as copied for the next commit
636 636 diff diff repository (or selected files)
637 637 export dump the header and diffs for one or more changesets
638 638 forget forget the specified files on the next commit
639 639 graft copy changes from other branches onto the current branch
640 640 grep search for a pattern in specified files and revisions
641 641 heads show current repository heads or show branch heads
642 642 help show help for a given topic or a help overview
643 643 identify identify the working copy or specified revision
644 644 import import an ordered set of patches
645 645 incoming show new changesets found in source
646 646 init create a new repository in the given directory
647 647 locate locate files matching specific patterns
648 648 log show revision history of entire repository or files
649 649 manifest output the current or given revision of the project manifest
650 650 merge merge working directory with another revision
651 651 outgoing show changesets not found in the destination
652 652 parents show the parents of the working directory or revision
653 653 paths show aliases for remote repositories
654 654 phase set or show the current phase name
655 655 pull pull changes from the specified source
656 656 push push changes to the specified destination
657 657 recover roll back an interrupted transaction
658 658 remove remove the specified files on the next commit
659 659 rename rename files; equivalent of copy + remove
660 660 resolve redo merges or set/view the merge status of files
661 661 revert restore files to their checkout state
662 662 rollback roll back the last transaction (dangerous)
663 663 root print the root (top) of the current working directory
664 664 serve start stand-alone webserver
665 665 showconfig show combined config settings from all hgrc files
666 666 status show changed files in the working directory
667 667 summary summarize working directory state
668 668 tag add one or more tags for the current or given revision
669 669 tags list repository tags
670 670 tip show the tip revision
671 671 unbundle apply one or more changegroup files
672 672 update update working directory (or switch revisions)
673 673 verify verify the integrity of the repository
674 674 version output version and copyright information
675 675
676 676 enabled extensions:
677 677
678 helpext (no help text available)
678 helpext (no help text available)
679 679
680 680 additional help topics:
681 681
682 682 config Configuration Files
683 683 dates Date Formats
684 684 diffs Diff Formats
685 685 environment Environment Variables
686 686 extensions Using additional features
687 687 filesets Specifying File Sets
688 688 glossary Glossary
689 689 hgignore syntax for Mercurial ignore files
690 690 hgweb Configuring hgweb
691 691 merge-tools Merge Tools
692 692 multirevs Specifying Multiple Revisions
693 693 patterns File Name Patterns
694 694 revisions Specifying Single Revisions
695 695 revsets Specifying Revision Sets
696 696 subrepos Subrepositories
697 697 templating Template Usage
698 698 urls URL Paths
699 699
700 700 use "hg -v help" to show builtin aliases and global options
701 701
702 702
703 703
704 704 Test list of commands with command with no help text
705 705
706 706 $ hg help helpext
707 707 helpext extension - no help text available
708 708
709 709 list of commands:
710 710
711 711 nohelp (no help text available)
712 712
713 713 use "hg -v help helpext" to show builtin aliases and global options
714 714
715 715 Test a help topic
716 716
717 717 $ hg help revs
718 718 Specifying Single Revisions
719 719
720 720 Mercurial supports several ways to specify individual revisions.
721 721
722 722 A plain integer is treated as a revision number. Negative integers are
723 723 treated as sequential offsets from the tip, with -1 denoting the tip, -2
724 724 denoting the revision prior to the tip, and so forth.
725 725
726 726 A 40-digit hexadecimal string is treated as a unique revision identifier.
727 727
728 728 A hexadecimal string less than 40 characters long is treated as a unique
729 729 revision identifier and is referred to as a short-form identifier. A
730 730 short-form identifier is only valid if it is the prefix of exactly one
731 731 full-length identifier.
732 732
733 733 Any other string is treated as a tag or branch name. A tag name is a
734 734 symbolic name associated with a revision identifier. A branch name denotes
735 735 the tipmost revision of that branch. Tag and branch names must not contain
736 736 the ":" character.
737 737
738 738 The reserved name "tip" is a special tag that always identifies the most
739 739 recent revision.
740 740
741 741 The reserved name "null" indicates the null revision. This is the revision
742 742 of an empty repository, and the parent of revision 0.
743 743
744 744 The reserved name "." indicates the working directory parent. If no
745 745 working directory is checked out, it is equivalent to null. If an
746 746 uncommitted merge is in progress, "." is the revision of the first parent.
747 747
748 748 Test templating help
749 749
750 750 $ hg help templating | egrep '(desc|diffstat|firstline|nonempty) '
751 desc String. The text of the changeset description.
752 diffstat String. Statistics of changes with the following format:
753 firstline Any text. Returns the first line of text.
754 nonempty Any text. Returns '(none)' if the string is empty.
751 desc String. The text of the changeset description.
752 diffstat String. Statistics of changes with the following format:
753 firstline Any text. Returns the first line of text.
754 nonempty Any text. Returns '(none)' if the string is empty.
755 755
756 756 Test help hooks
757 757
758 758 $ cat > helphook1.py <<EOF
759 759 > from mercurial import help
760 760 >
761 761 > def rewrite(topic, doc):
762 762 > return doc + '\nhelphook1\n'
763 763 >
764 764 > def extsetup(ui):
765 765 > help.addtopichook('revsets', rewrite)
766 766 > EOF
767 767 $ cat > helphook2.py <<EOF
768 768 > from mercurial import help
769 769 >
770 770 > def rewrite(topic, doc):
771 771 > return doc + '\nhelphook2\n'
772 772 >
773 773 > def extsetup(ui):
774 774 > help.addtopichook('revsets', rewrite)
775 775 > EOF
776 776 $ echo '[extensions]' >> $HGRCPATH
777 777 $ echo "helphook1 = `pwd`/helphook1.py" >> $HGRCPATH
778 778 $ echo "helphook2 = `pwd`/helphook2.py" >> $HGRCPATH
779 779 $ hg help revsets | grep helphook
780 780 helphook1
781 781 helphook2
@@ -1,764 +1,766 b''
1 1 == paragraphs ==
2 2 60 column format:
3 3 ----------------------------------------------------------------------
4 4 This is some text in the first paragraph.
5 5
6 6 A small indented paragraph. It is followed by some lines
7 7 containing random whitespace.
8 8
9 9 The third and final paragraph.
10 10 ----------------------------------------------------------------------
11 11
12 12 30 column format:
13 13 ----------------------------------------------------------------------
14 14 This is some text in the first
15 15 paragraph.
16 16
17 17 A small indented paragraph.
18 18 It is followed by some lines
19 19 containing random
20 20 whitespace.
21 21
22 22 The third and final paragraph.
23 23 ----------------------------------------------------------------------
24 24
25 25 html format:
26 26 ----------------------------------------------------------------------
27 27 <p>
28 28 This is some text in the first paragraph.
29 29 </p>
30 30 <p>
31 31 A small indented paragraph.
32 32 It is followed by some lines
33 33 containing random whitespace.
34 34 </p>
35 35 <p>
36 36 The third and final paragraph.
37 37 </p>
38 38 ----------------------------------------------------------------------
39 39
40 40 == definitions ==
41 41 60 column format:
42 42 ----------------------------------------------------------------------
43 43 A Term
44 44 Definition. The indented lines make up the definition.
45 45
46 46 Another Term
47 47 Another definition. The final line in the definition
48 48 determines the indentation, so this will be indented
49 49 with four spaces.
50 50
51 51 A Nested/Indented Term
52 52 Definition.
53 53 ----------------------------------------------------------------------
54 54
55 55 30 column format:
56 56 ----------------------------------------------------------------------
57 57 A Term
58 58 Definition. The indented
59 59 lines make up the
60 60 definition.
61 61
62 62 Another Term
63 63 Another definition. The
64 64 final line in the
65 65 definition determines the
66 66 indentation, so this will
67 67 be indented with four
68 68 spaces.
69 69
70 70 A Nested/Indented Term
71 71 Definition.
72 72 ----------------------------------------------------------------------
73 73
74 74 html format:
75 75 ----------------------------------------------------------------------
76 76 <dl>
77 77 <dt>A Term
78 78 <dd>Definition. The indented lines make up the definition.
79 79 <dt>Another Term
80 80 <dd>Another definition. The final line in the definition determines the indentation, so this will be indented with four spaces.
81 81 <dt>A Nested/Indented Term
82 82 <dd>Definition.
83 83 </dl>
84 84 ----------------------------------------------------------------------
85 85
86 86 == literals ==
87 87 60 column format:
88 88 ----------------------------------------------------------------------
89 89 The fully minimized form is the most convenient form:
90 90
91 91 Hello
92 92 literal
93 93 world
94 94
95 95 In the partially minimized form a paragraph simply ends with
96 96 space-double-colon.
97 97
98 98 ////////////////////////////////////////
99 99 long un-wrapped line in a literal block
100 100 \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
101 101
102 102 This literal block is started with '::',
103 103 the so-called expanded form. The paragraph
104 104 with '::' disappears in the final output.
105 105 ----------------------------------------------------------------------
106 106
107 107 30 column format:
108 108 ----------------------------------------------------------------------
109 109 The fully minimized form is
110 110 the most convenient form:
111 111
112 112 Hello
113 113 literal
114 114 world
115 115
116 116 In the partially minimized
117 117 form a paragraph simply ends
118 118 with space-double-colon.
119 119
120 120 ////////////////////////////////////////
121 121 long un-wrapped line in a literal block
122 122 \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
123 123
124 124 This literal block is started with '::',
125 125 the so-called expanded form. The paragraph
126 126 with '::' disappears in the final output.
127 127 ----------------------------------------------------------------------
128 128
129 129 html format:
130 130 ----------------------------------------------------------------------
131 131 <p>
132 132 The fully minimized form is the most
133 133 convenient form:
134 134 </p>
135 135 <pre>
136 136 Hello
137 137 literal
138 138 world
139 139 </pre>
140 140 <p>
141 141 In the partially minimized form a paragraph
142 142 simply ends with space-double-colon.
143 143 </p>
144 144 <pre>
145 145 ////////////////////////////////////////
146 146 long un-wrapped line in a literal block
147 147 \\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\
148 148 </pre>
149 149 <pre>
150 150 This literal block is started with '::',
151 151 the so-called expanded form. The paragraph
152 152 with '::' disappears in the final output.
153 153 </pre>
154 154 ----------------------------------------------------------------------
155 155
156 156 == lists ==
157 157 60 column format:
158 158 ----------------------------------------------------------------------
159 159 - This is the first list item.
160 160
161 161 Second paragraph in the first list item.
162 162
163 163 - List items need not be separated by a blank line.
164 164 - And will be rendered without one in any case.
165 165
166 166 We can have indented lists:
167 167
168 168 - This is an indented list item
169 169 - Another indented list item:
170 170
171 171 - A literal block in the middle
172 172 of an indented list.
173 173
174 174 (The above is not a list item since we are in the literal block.)
175 175
176 176 Literal block with no indentation (apart from
177 177 the two spaces added to all literal blocks).
178 178
179 179 1. This is an enumerated list (first item).
180 180 2. Continuing with the second item.
181 181 (1) foo
182 182 (2) bar
183 183 1) Another
184 184 2) List
185 185
186 186 Line blocks are also a form of list:
187 187
188 188 This is the first line. The line continues here.
189 189 This is the second line.
190 190 ----------------------------------------------------------------------
191 191
192 192 30 column format:
193 193 ----------------------------------------------------------------------
194 194 - This is the first list item.
195 195
196 196 Second paragraph in the
197 197 first list item.
198 198
199 199 - List items need not be
200 200 separated by a blank line.
201 201 - And will be rendered without
202 202 one in any case.
203 203
204 204 We can have indented lists:
205 205
206 206 - This is an indented list
207 207 item
208 208 - Another indented list
209 209 item:
210 210
211 211 - A literal block in the middle
212 212 of an indented list.
213 213
214 214 (The above is not a list item since we are in the literal block.)
215 215
216 216 Literal block with no indentation (apart from
217 217 the two spaces added to all literal blocks).
218 218
219 219 1. This is an enumerated list
220 220 (first item).
221 221 2. Continuing with the second
222 222 item.
223 223 (1) foo
224 224 (2) bar
225 225 1) Another
226 226 2) List
227 227
228 228 Line blocks are also a form of
229 229 list:
230 230
231 231 This is the first line. The
232 232 line continues here.
233 233 This is the second line.
234 234 ----------------------------------------------------------------------
235 235
236 236 html format:
237 237 ----------------------------------------------------------------------
238 238 <ul>
239 239 <li> This is the first list item.
240 240 <p>
241 241 Second paragraph in the first list item.
242 242 </p>
243 243 <li> List items need not be separated by a blank line.
244 244 <li> And will be rendered without one in any case.
245 245 </ul>
246 246 <p>
247 247 We can have indented lists:
248 248 </p>
249 249 <ul>
250 250 <li> This is an indented list item
251 251 <li> Another indented list item:
252 252 <pre>
253 253 - A literal block in the middle
254 254 of an indented list.
255 255 </pre>
256 256 <pre>
257 257 (The above is not a list item since we are in the literal block.)
258 258 </pre>
259 259 </ul>
260 260 <pre>
261 261 Literal block with no indentation (apart from
262 262 the two spaces added to all literal blocks).
263 263 </pre>
264 264 <ol>
265 265 <li> This is an enumerated list (first item).
266 266 <li> Continuing with the second item.
267 267 <li> foo
268 268 <li> bar
269 269 <li> Another
270 270 <li> List
271 271 </ol>
272 272 <p>
273 273 Line blocks are also a form of list:
274 274 </p>
275 275 <ol>
276 276 <li> This is the first line. The line continues here.
277 277 <li> This is the second line.
278 278 </ol>
279 279 ----------------------------------------------------------------------
280 280
281 281 == options ==
282 282 60 column format:
283 283 ----------------------------------------------------------------------
284 284 There is support for simple option lists, but only with long
285 285 options:
286 286
287 287 -X --exclude filter an option with a short and long option
288 288 with an argument
289 289 -I --include an option with both a short option and
290 290 a long option
291 291 --all Output all.
292 292 --both Output both (this description is quite
293 293 long).
294 294 --long Output all day long.
295 295 --par This option has two paragraphs in its
296 296 description. This is the first.
297 297
298 298 This is the second. Blank lines may
299 299 be omitted between options (as above)
300 300 or left in (as here).
301 301
302 302 The next paragraph looks like an option list, but lacks the
303 303 two-space marker after the option. It is treated as a normal
304 304 paragraph:
305 305
306 306 --foo bar baz
307 307 ----------------------------------------------------------------------
308 308
309 309 30 column format:
310 310 ----------------------------------------------------------------------
311 311 There is support for simple
312 312 option lists, but only with
313 313 long options:
314 314
315 315 -X --exclude filter an
316 316 option
317 317 with a
318 318 short
319 319 and
320 320 long
321 321 option
322 322 with an
323 323 argumen
324 324 t
325 325 -I --include an
326 326 option
327 327 with
328 328 both a
329 329 short
330 330 option
331 331 and a
332 332 long
333 333 option
334 334 --all Output
335 335 all.
336 336 --both Output
337 337 both
338 338 (this d
339 339 escript
340 340 ion is
341 341 quite
342 342 long).
343 343 --long Output
344 344 all day
345 345 long.
346 346 --par This
347 347 option
348 348 has two
349 349 paragra
350 350 phs in
351 351 its des
352 352 criptio
353 353 n. This
354 354 is the
355 355 first.
356 356
357 357 This is
358 358 the
359 359 second.
360 360 Blank
361 361 lines
362 362 may be
363 363 omitted
364 364 between
365 365 options
366 366 (as
367 367 above)
368 368 or left
369 369 in (as
370 370 here).
371 371
372 372 The next paragraph looks like
373 373 an option list, but lacks the
374 374 two-space marker after the
375 375 option. It is treated as a
376 376 normal paragraph:
377 377
378 378 --foo bar baz
379 379 ----------------------------------------------------------------------
380 380
381 381 html format:
382 382 ----------------------------------------------------------------------
383 383 <p>
384 384 There is support for simple option lists,
385 385 but only with long options:
386 386 </p>
387 387 <dl>
388 388 <dt>-X --exclude filter
389 389 <dd>an option with a short and long option with an argument
390 390 <dt>-I --include
391 391 <dd>an option with both a short option and a long option
392 392 <dt> --all
393 393 <dd>Output all.
394 394 <dt> --both
395 395 <dd>Output both (this description is quite long).
396 396 <dt> --long
397 397 <dd>Output all day long.
398 398 <dt> --par
399 399 <dd>This option has two paragraphs in its description. This is the first.
400 400 <p>
401 401 This is the second. Blank lines may be omitted between
402 402 options (as above) or left in (as here).
403 403 </p>
404 404 </dl>
405 405 <p>
406 406 The next paragraph looks like an option list, but lacks the two-space
407 407 marker after the option. It is treated as a normal paragraph:
408 408 </p>
409 409 <p>
410 410 --foo bar baz
411 411 </p>
412 412 ----------------------------------------------------------------------
413 413
414 414 == fields ==
415 415 60 column format:
416 416 ----------------------------------------------------------------------
417 a First item.
418 ab Second item. Indentation and wrapping is handled
419 automatically.
417 a First item.
418 ab Second item. Indentation and wrapping is
419 handled automatically.
420 420
421 421 Next list:
422 422
423 small The larger key below triggers full indentation
424 here.
423 small The larger key below triggers full indentation
424 here.
425 425 much too large
426 This key is big enough to get its own line.
426 This key is big enough to get its own line.
427 427 ----------------------------------------------------------------------
428 428
429 429 30 column format:
430 430 ----------------------------------------------------------------------
431 a First item.
432 ab Second item. Indentation
433 and wrapping is handled
434 automatically.
431 a First item.
432 ab Second item.
433 Indentation and
434 wrapping is
435 handled
436 automatically.
435 437
436 438 Next list:
437 439
438 small The larger key
439 below triggers
440 full indentation
441 here.
440 small The larger key
441 below triggers
442 full indentation
443 here.
442 444 much too large
443 This key is big
444 enough to get its
445 own line.
445 This key is big
446 enough to get
447 its own line.
446 448 ----------------------------------------------------------------------
447 449
448 450 html format:
449 451 ----------------------------------------------------------------------
450 452 <dl>
451 453 <dt>a
452 454 <dd>First item.
453 455 <dt>ab
454 456 <dd>Second item. Indentation and wrapping is handled automatically.
455 457 </dl>
456 458 <p>
457 459 Next list:
458 460 </p>
459 461 <dl>
460 462 <dt>small
461 463 <dd>The larger key below triggers full indentation here.
462 464 <dt>much too large
463 465 <dd>This key is big enough to get its own line.
464 466 </dl>
465 467 ----------------------------------------------------------------------
466 468
467 469 == containers (normal) ==
468 470 60 column format:
469 471 ----------------------------------------------------------------------
470 472 Normal output.
471 473 ----------------------------------------------------------------------
472 474
473 475 30 column format:
474 476 ----------------------------------------------------------------------
475 477 Normal output.
476 478 ----------------------------------------------------------------------
477 479
478 480 html format:
479 481 ----------------------------------------------------------------------
480 482 <p>
481 483 Normal output.
482 484 </p>
483 485 ----------------------------------------------------------------------
484 486
485 487 == containers (verbose) ==
486 488 60 column format:
487 489 ----------------------------------------------------------------------
488 490 Normal output.
489 491
490 492 Verbose output.
491 493 ----------------------------------------------------------------------
492 494 ['debug', 'debug']
493 495 ----------------------------------------------------------------------
494 496
495 497 30 column format:
496 498 ----------------------------------------------------------------------
497 499 Normal output.
498 500
499 501 Verbose output.
500 502 ----------------------------------------------------------------------
501 503 ['debug', 'debug']
502 504 ----------------------------------------------------------------------
503 505
504 506 html format:
505 507 ----------------------------------------------------------------------
506 508 <p>
507 509 Normal output.
508 510 </p>
509 511 <p>
510 512 Verbose output.
511 513 </p>
512 514 ----------------------------------------------------------------------
513 515 ['debug', 'debug']
514 516 ----------------------------------------------------------------------
515 517
516 518 == containers (debug) ==
517 519 60 column format:
518 520 ----------------------------------------------------------------------
519 521 Normal output.
520 522
521 523 Initial debug output.
522 524 ----------------------------------------------------------------------
523 525 ['verbose']
524 526 ----------------------------------------------------------------------
525 527
526 528 30 column format:
527 529 ----------------------------------------------------------------------
528 530 Normal output.
529 531
530 532 Initial debug output.
531 533 ----------------------------------------------------------------------
532 534 ['verbose']
533 535 ----------------------------------------------------------------------
534 536
535 537 html format:
536 538 ----------------------------------------------------------------------
537 539 <p>
538 540 Normal output.
539 541 </p>
540 542 <p>
541 543 Initial debug output.
542 544 </p>
543 545 ----------------------------------------------------------------------
544 546 ['verbose']
545 547 ----------------------------------------------------------------------
546 548
547 549 == containers (verbose debug) ==
548 550 60 column format:
549 551 ----------------------------------------------------------------------
550 552 Normal output.
551 553
552 554 Initial debug output.
553 555
554 556 Verbose output.
555 557
556 558 Debug output.
557 559 ----------------------------------------------------------------------
558 560 []
559 561 ----------------------------------------------------------------------
560 562
561 563 30 column format:
562 564 ----------------------------------------------------------------------
563 565 Normal output.
564 566
565 567 Initial debug output.
566 568
567 569 Verbose output.
568 570
569 571 Debug output.
570 572 ----------------------------------------------------------------------
571 573 []
572 574 ----------------------------------------------------------------------
573 575
574 576 html format:
575 577 ----------------------------------------------------------------------
576 578 <p>
577 579 Normal output.
578 580 </p>
579 581 <p>
580 582 Initial debug output.
581 583 </p>
582 584 <p>
583 585 Verbose output.
584 586 </p>
585 587 <p>
586 588 Debug output.
587 589 </p>
588 590 ----------------------------------------------------------------------
589 591 []
590 592 ----------------------------------------------------------------------
591 593
592 594 == roles ==
593 595 60 column format:
594 596 ----------------------------------------------------------------------
595 597 Please see "hg add".
596 598 ----------------------------------------------------------------------
597 599
598 600 30 column format:
599 601 ----------------------------------------------------------------------
600 602 Please see "hg add".
601 603 ----------------------------------------------------------------------
602 604
603 605 html format:
604 606 ----------------------------------------------------------------------
605 607 <p>
606 608 Please see "hg add".
607 609 </p>
608 610 ----------------------------------------------------------------------
609 611
610 612 == sections ==
611 613 60 column format:
612 614 ----------------------------------------------------------------------
613 615 Title
614 616 =====
615 617
616 618 Section
617 619 -------
618 620
619 621 Subsection
620 622 ''''''''''
621 623
622 624 Markup: "foo" and "hg help"
623 625 ---------------------------
624 626 ----------------------------------------------------------------------
625 627
626 628 30 column format:
627 629 ----------------------------------------------------------------------
628 630 Title
629 631 =====
630 632
631 633 Section
632 634 -------
633 635
634 636 Subsection
635 637 ''''''''''
636 638
637 639 Markup: "foo" and "hg help"
638 640 ---------------------------
639 641 ----------------------------------------------------------------------
640 642
641 643 html format:
642 644 ----------------------------------------------------------------------
643 645 <h1>Title</h1>
644 646 <h2>Section</h2>
645 647 <h3>Subsection</h3>
646 648 <h2>Markup: "foo" and "hg help"</h2>
647 649 ----------------------------------------------------------------------
648 650
649 651 == admonitions ==
650 652 60 column format:
651 653 ----------------------------------------------------------------------
652 654 Note:
653 655 This is a note
654 656
655 657 - Bullet 1
656 658 - Bullet 2
657 659
658 660 Warning!
659 661 This is a warning Second input line of warning
660 662
661 663 !Danger!
662 664 This is danger
663 665 ----------------------------------------------------------------------
664 666
665 667 30 column format:
666 668 ----------------------------------------------------------------------
667 669 Note:
668 670 This is a note
669 671
670 672 - Bullet 1
671 673 - Bullet 2
672 674
673 675 Warning!
674 676 This is a warning Second
675 677 input line of warning
676 678
677 679 !Danger!
678 680 This is danger
679 681 ----------------------------------------------------------------------
680 682
681 683 html format:
682 684 ----------------------------------------------------------------------
683 685 <p>
684 686 <b>Note:</b> This is a note
685 687 </p>
686 688 <ul>
687 689 <li> Bullet 1
688 690 <li> Bullet 2
689 691 </ul>
690 692 <p>
691 693 <b>Warning!</b> This is a warning Second input line of warning
692 694 </p>
693 695 <p>
694 696 <b>!Danger!</b> This is danger
695 697 </p>
696 698 ----------------------------------------------------------------------
697 699
698 700 == comments ==
699 701 60 column format:
700 702 ----------------------------------------------------------------------
701 703 Some text.
702 704
703 705 Some indented text.
704 706
705 707 Empty comment above
706 708 ----------------------------------------------------------------------
707 709
708 710 30 column format:
709 711 ----------------------------------------------------------------------
710 712 Some text.
711 713
712 714 Some indented text.
713 715
714 716 Empty comment above
715 717 ----------------------------------------------------------------------
716 718
717 719 html format:
718 720 ----------------------------------------------------------------------
719 721 <p>
720 722 Some text.
721 723 </p>
722 724 <p>
723 725 Some indented text.
724 726 </p>
725 727 <p>
726 728 Empty comment above
727 729 </p>
728 730 ----------------------------------------------------------------------
729 731
730 732 === === ========================================
731 733 a b c
732 734 === === ========================================
733 735 1 2 3
734 736 foo bar baz this list is very very very long man
735 737 === === ========================================
736 738
737 739 == table ==
738 740 60 column format:
739 741 ----------------------------------------------------------------------
740 742 a b c
741 743 ------------------------------------------------
742 744 1 2 3
743 745 foo bar baz this list is very very very long man
744 746 ----------------------------------------------------------------------
745 747
746 748 30 column format:
747 749 ----------------------------------------------------------------------
748 750 a b c
749 751 ------------------------------
750 752 1 2 3
751 753 foo bar baz this list is
752 754 very very very long
753 755 man
754 756 ----------------------------------------------------------------------
755 757
756 758 html format:
757 759 ----------------------------------------------------------------------
758 760 <table>
759 761 <tr><th>a</th><th>b</th><th>c</th></tr>
760 762 <tr><td>1</td><td>2</td><td>3</td></tr>
761 763 <tr><td>foo</td><td>bar</td><td>baz this list is very very very long man</td></tr>
762 764 </table>
763 765 ----------------------------------------------------------------------
764 766
@@ -1,397 +1,397 b''
1 1 Create configuration
2 2
3 3 $ echo "[ui]" >> $HGRCPATH
4 4 $ echo "interactive=true" >> $HGRCPATH
5 5
6 6 help record (no record)
7 7
8 8 $ hg help record
9 9 record extension - commands to interactively select changes for commit/qrefresh
10 10
11 11 use "hg help extensions" for information on enabling extensions
12 12
13 13 help qrecord (no record)
14 14
15 15 $ hg help qrecord
16 16 'qrecord' is provided by the following extension:
17 17
18 record commands to interactively select changes for commit/qrefresh
18 record commands to interactively select changes for commit/qrefresh
19 19
20 20 use "hg help extensions" for information on enabling extensions
21 21
22 22 $ echo "[extensions]" >> $HGRCPATH
23 23 $ echo "record=" >> $HGRCPATH
24 24
25 25 help record (record)
26 26
27 27 $ hg help record
28 28 hg record [OPTION]... [FILE]...
29 29
30 30 interactively select changes to commit
31 31
32 32 If a list of files is omitted, all changes reported by "hg status" will be
33 33 candidates for recording.
34 34
35 35 See "hg help dates" for a list of formats valid for -d/--date.
36 36
37 37 You will be prompted for whether to record changes to each modified file,
38 38 and for files with multiple changes, for each change to use. For each
39 39 query, the following responses are possible:
40 40
41 41 y - record this change
42 42 n - skip this change
43 43
44 44 s - skip remaining changes to this file
45 45 f - record remaining changes to this file
46 46
47 47 d - done, skip remaining changes and files
48 48 a - record all changes to all remaining files
49 49 q - quit, recording no changes
50 50
51 51 ? - display help
52 52
53 53 This command is not available when committing a merge.
54 54
55 55 options:
56 56
57 57 -A --addremove mark new/missing files as added/removed before
58 58 committing
59 59 --close-branch mark a branch as closed, hiding it from the branch
60 60 list
61 61 -I --include PATTERN [+] include names matching the given patterns
62 62 -X --exclude PATTERN [+] exclude names matching the given patterns
63 63 -m --message TEXT use text as commit message
64 64 -l --logfile FILE read commit message from file
65 65 -d --date DATE record the specified date as commit date
66 66 -u --user USER record the specified user as committer
67 67 -S --subrepos recurse into subrepositories
68 68 -w --ignore-all-space ignore white space when comparing lines
69 69 -b --ignore-space-change ignore changes in the amount of white space
70 70 -B --ignore-blank-lines ignore changes whose lines are all blank
71 71
72 72 [+] marked option can be specified multiple times
73 73
74 74 use "hg -v help record" to show more info
75 75
76 76 help (no mq, so no qrecord)
77 77
78 78 $ hg help qrecord
79 79 hg qrecord [OPTION]... PATCH [FILE]...
80 80
81 81 interactively record a new patch
82 82
83 83 See "hg help qnew" & "hg help record" for more information and usage.
84 84
85 85 use "hg -v help qrecord" to show more info
86 86
87 87 $ hg init a
88 88
89 89 qrecord (mq not present)
90 90
91 91 $ hg -R a qrecord
92 92 hg qrecord: invalid arguments
93 93 hg qrecord [OPTION]... PATCH [FILE]...
94 94
95 95 interactively record a new patch
96 96
97 97 use "hg help qrecord" to show the full help text
98 98 [255]
99 99
100 100 qrecord patch (mq not present)
101 101
102 102 $ hg -R a qrecord patch
103 103 abort: 'mq' extension not loaded
104 104 [255]
105 105
106 106 help (bad mq)
107 107
108 108 $ echo "mq=nonexistant" >> $HGRCPATH
109 109 $ hg help qrecord
110 110 *** failed to import extension mq from nonexistant: [Errno 2] * (glob)
111 111 hg qrecord [OPTION]... PATCH [FILE]...
112 112
113 113 interactively record a new patch
114 114
115 115 See "hg help qnew" & "hg help record" for more information and usage.
116 116
117 117 use "hg -v help qrecord" to show more info
118 118
119 119 help (mq present)
120 120
121 121 $ sed 's/mq=nonexistant/mq=/' $HGRCPATH > hgrc.tmp
122 122 $ mv hgrc.tmp $HGRCPATH
123 123
124 124 $ hg help qrecord
125 125 hg qrecord [OPTION]... PATCH [FILE]...
126 126
127 127 interactively record a new patch
128 128
129 129 See "hg help qnew" & "hg help record" for more information and usage.
130 130
131 131 options:
132 132
133 133 -e --edit edit commit message
134 134 -g --git use git extended diff format
135 135 -U --currentuser add "From: <current user>" to patch
136 136 -u --user USER add "From: <USER>" to patch
137 137 -D --currentdate add "Date: <current date>" to patch
138 138 -d --date DATE add "Date: <DATE>" to patch
139 139 -I --include PATTERN [+] include names matching the given patterns
140 140 -X --exclude PATTERN [+] exclude names matching the given patterns
141 141 -m --message TEXT use text as commit message
142 142 -l --logfile FILE read commit message from file
143 143 -w --ignore-all-space ignore white space when comparing lines
144 144 -b --ignore-space-change ignore changes in the amount of white space
145 145 -B --ignore-blank-lines ignore changes whose lines are all blank
146 146 --mq operate on patch repository
147 147
148 148 [+] marked option can be specified multiple times
149 149
150 150 use "hg -v help qrecord" to show more info
151 151
152 152 $ cd a
153 153
154 154 Base commit
155 155
156 156 $ cat > 1.txt <<EOF
157 157 > 1
158 158 > 2
159 159 > 3
160 160 > 4
161 161 > 5
162 162 > EOF
163 163 $ cat > 2.txt <<EOF
164 164 > a
165 165 > b
166 166 > c
167 167 > d
168 168 > e
169 169 > f
170 170 > EOF
171 171
172 172 $ mkdir dir
173 173 $ cat > dir/a.txt <<EOF
174 174 > hello world
175 175 >
176 176 > someone
177 177 > up
178 178 > there
179 179 > loves
180 180 > me
181 181 > EOF
182 182
183 183 $ hg add 1.txt 2.txt dir/a.txt
184 184 $ hg commit -m 'initial checkin'
185 185
186 186 Changing files
187 187
188 188 $ sed -e 's/2/2 2/;s/4/4 4/' 1.txt > 1.txt.new
189 189 $ sed -e 's/b/b b/' 2.txt > 2.txt.new
190 190 $ sed -e 's/hello world/hello world!/' dir/a.txt > dir/a.txt.new
191 191
192 192 $ mv -f 1.txt.new 1.txt
193 193 $ mv -f 2.txt.new 2.txt
194 194 $ mv -f dir/a.txt.new dir/a.txt
195 195
196 196 Whole diff
197 197
198 198 $ hg diff --nodates
199 199 diff -r 1057167b20ef 1.txt
200 200 --- a/1.txt
201 201 +++ b/1.txt
202 202 @@ -1,5 +1,5 @@
203 203 1
204 204 -2
205 205 +2 2
206 206 3
207 207 -4
208 208 +4 4
209 209 5
210 210 diff -r 1057167b20ef 2.txt
211 211 --- a/2.txt
212 212 +++ b/2.txt
213 213 @@ -1,5 +1,5 @@
214 214 a
215 215 -b
216 216 +b b
217 217 c
218 218 d
219 219 e
220 220 diff -r 1057167b20ef dir/a.txt
221 221 --- a/dir/a.txt
222 222 +++ b/dir/a.txt
223 223 @@ -1,4 +1,4 @@
224 224 -hello world
225 225 +hello world!
226 226
227 227 someone
228 228 up
229 229
230 230 qrecord with bad patch name, should abort before prompting
231 231
232 232 $ hg qrecord .hg
233 233 abort: patch name cannot begin with ".hg"
234 234 [255]
235 235
236 236 qrecord a.patch
237 237
238 238 $ hg qrecord -d '0 0' -m aaa a.patch <<EOF
239 239 > y
240 240 > y
241 241 > n
242 242 > y
243 243 > y
244 244 > n
245 245 > EOF
246 246 diff --git a/1.txt b/1.txt
247 247 2 hunks, 2 lines changed
248 248 examine changes to '1.txt'? [Ynsfdaq?]
249 249 @@ -1,3 +1,3 @@
250 250 1
251 251 -2
252 252 +2 2
253 253 3
254 254 record change 1/4 to '1.txt'? [Ynsfdaq?]
255 255 @@ -3,3 +3,3 @@
256 256 3
257 257 -4
258 258 +4 4
259 259 5
260 260 record change 2/4 to '1.txt'? [Ynsfdaq?]
261 261 diff --git a/2.txt b/2.txt
262 262 1 hunks, 1 lines changed
263 263 examine changes to '2.txt'? [Ynsfdaq?]
264 264 @@ -1,5 +1,5 @@
265 265 a
266 266 -b
267 267 +b b
268 268 c
269 269 d
270 270 e
271 271 record change 3/4 to '2.txt'? [Ynsfdaq?]
272 272 diff --git a/dir/a.txt b/dir/a.txt
273 273 1 hunks, 1 lines changed
274 274 examine changes to 'dir/a.txt'? [Ynsfdaq?]
275 275
276 276 After qrecord a.patch 'tip'"
277 277
278 278 $ hg tip -p
279 279 changeset: 1:5d1ca63427ee
280 280 tag: a.patch
281 281 tag: qbase
282 282 tag: qtip
283 283 tag: tip
284 284 user: test
285 285 date: Thu Jan 01 00:00:00 1970 +0000
286 286 summary: aaa
287 287
288 288 diff -r 1057167b20ef -r 5d1ca63427ee 1.txt
289 289 --- a/1.txt Thu Jan 01 00:00:00 1970 +0000
290 290 +++ b/1.txt Thu Jan 01 00:00:00 1970 +0000
291 291 @@ -1,5 +1,5 @@
292 292 1
293 293 -2
294 294 +2 2
295 295 3
296 296 4
297 297 5
298 298 diff -r 1057167b20ef -r 5d1ca63427ee 2.txt
299 299 --- a/2.txt Thu Jan 01 00:00:00 1970 +0000
300 300 +++ b/2.txt Thu Jan 01 00:00:00 1970 +0000
301 301 @@ -1,5 +1,5 @@
302 302 a
303 303 -b
304 304 +b b
305 305 c
306 306 d
307 307 e
308 308
309 309
310 310 After qrecord a.patch 'diff'"
311 311
312 312 $ hg diff --nodates
313 313 diff -r 5d1ca63427ee 1.txt
314 314 --- a/1.txt
315 315 +++ b/1.txt
316 316 @@ -1,5 +1,5 @@
317 317 1
318 318 2 2
319 319 3
320 320 -4
321 321 +4 4
322 322 5
323 323 diff -r 5d1ca63427ee dir/a.txt
324 324 --- a/dir/a.txt
325 325 +++ b/dir/a.txt
326 326 @@ -1,4 +1,4 @@
327 327 -hello world
328 328 +hello world!
329 329
330 330 someone
331 331 up
332 332
333 333 qrecord b.patch
334 334
335 335 $ hg qrecord -d '0 0' -m bbb b.patch <<EOF
336 336 > y
337 337 > y
338 338 > y
339 339 > y
340 340 > EOF
341 341 diff --git a/1.txt b/1.txt
342 342 1 hunks, 1 lines changed
343 343 examine changes to '1.txt'? [Ynsfdaq?]
344 344 @@ -1,5 +1,5 @@
345 345 1
346 346 2 2
347 347 3
348 348 -4
349 349 +4 4
350 350 5
351 351 record change 1/2 to '1.txt'? [Ynsfdaq?]
352 352 diff --git a/dir/a.txt b/dir/a.txt
353 353 1 hunks, 1 lines changed
354 354 examine changes to 'dir/a.txt'? [Ynsfdaq?]
355 355 @@ -1,4 +1,4 @@
356 356 -hello world
357 357 +hello world!
358 358
359 359 someone
360 360 up
361 361 record change 2/2 to 'dir/a.txt'? [Ynsfdaq?]
362 362
363 363 After qrecord b.patch 'tip'
364 364
365 365 $ hg tip -p
366 366 changeset: 2:b056198bf878
367 367 tag: b.patch
368 368 tag: qtip
369 369 tag: tip
370 370 user: test
371 371 date: Thu Jan 01 00:00:00 1970 +0000
372 372 summary: bbb
373 373
374 374 diff -r 5d1ca63427ee -r b056198bf878 1.txt
375 375 --- a/1.txt Thu Jan 01 00:00:00 1970 +0000
376 376 +++ b/1.txt Thu Jan 01 00:00:00 1970 +0000
377 377 @@ -1,5 +1,5 @@
378 378 1
379 379 2 2
380 380 3
381 381 -4
382 382 +4 4
383 383 5
384 384 diff -r 5d1ca63427ee -r b056198bf878 dir/a.txt
385 385 --- a/dir/a.txt Thu Jan 01 00:00:00 1970 +0000
386 386 +++ b/dir/a.txt Thu Jan 01 00:00:00 1970 +0000
387 387 @@ -1,4 +1,4 @@
388 388 -hello world
389 389 +hello world!
390 390
391 391 someone
392 392 up
393 393
394 394
395 395 After qrecord b.patch 'diff'
396 396
397 397 $ hg diff --nodates
General Comments 0
You need to be logged in to leave comments. Login now