##// END OF EJS Templates
annotate: add option to annotate working-directory files...
Yuya Nishihara -
r24421:77881cad default
parent child Browse files
Show More
@@ -1,6367 +1,6397
1 1 # commands.py - command processing for mercurial
2 2 #
3 3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
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 from node import hex, bin, nullid, nullrev, short
9 9 from lock import release
10 10 from i18n import _
11 11 import os, re, difflib, time, tempfile, errno, shlex
12 12 import sys, socket
13 13 import hg, scmutil, util, revlog, copies, error, bookmarks
14 14 import patch, help, encoding, templatekw, discovery
15 15 import archival, changegroup, cmdutil, hbisect
16 16 import sshserver, hgweb, commandserver
17 17 import extensions
18 18 from hgweb import server as hgweb_server
19 19 import merge as mergemod
20 20 import minirst, revset, fileset
21 21 import dagparser, context, simplemerge, graphmod, copies
22 22 import random
23 23 import setdiscovery, treediscovery, dagutil, pvec, localrepo
24 24 import phases, obsolete, exchange, bundle2
25 25 import ui as uimod
26 26
27 27 table = {}
28 28
29 29 command = cmdutil.command(table)
30 30
31 31 # Space delimited list of commands that don't require local repositories.
32 32 # This should be populated by passing norepo=True into the @command decorator.
33 33 norepo = ''
34 34 # Space delimited list of commands that optionally require local repositories.
35 35 # This should be populated by passing optionalrepo=True into the @command
36 36 # decorator.
37 37 optionalrepo = ''
38 38 # Space delimited list of commands that will examine arguments looking for
39 39 # a repository. This should be populated by passing inferrepo=True into the
40 40 # @command decorator.
41 41 inferrepo = ''
42 42
43 43 # common command options
44 44
45 45 globalopts = [
46 46 ('R', 'repository', '',
47 47 _('repository root directory or name of overlay bundle file'),
48 48 _('REPO')),
49 49 ('', 'cwd', '',
50 50 _('change working directory'), _('DIR')),
51 51 ('y', 'noninteractive', None,
52 52 _('do not prompt, automatically pick the first choice for all prompts')),
53 53 ('q', 'quiet', None, _('suppress output')),
54 54 ('v', 'verbose', None, _('enable additional output')),
55 55 ('', 'config', [],
56 56 _('set/override config option (use \'section.name=value\')'),
57 57 _('CONFIG')),
58 58 ('', 'debug', None, _('enable debugging output')),
59 59 ('', 'debugger', None, _('start debugger')),
60 60 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
61 61 _('ENCODE')),
62 62 ('', 'encodingmode', encoding.encodingmode,
63 63 _('set the charset encoding mode'), _('MODE')),
64 64 ('', 'traceback', None, _('always print a traceback on exception')),
65 65 ('', 'time', None, _('time how long the command takes')),
66 66 ('', 'profile', None, _('print command execution profile')),
67 67 ('', 'version', None, _('output version information and exit')),
68 68 ('h', 'help', None, _('display help and exit')),
69 69 ('', 'hidden', False, _('consider hidden changesets')),
70 70 ]
71 71
72 72 dryrunopts = [('n', 'dry-run', None,
73 73 _('do not perform actions, just print output'))]
74 74
75 75 remoteopts = [
76 76 ('e', 'ssh', '',
77 77 _('specify ssh command to use'), _('CMD')),
78 78 ('', 'remotecmd', '',
79 79 _('specify hg command to run on the remote side'), _('CMD')),
80 80 ('', 'insecure', None,
81 81 _('do not verify server certificate (ignoring web.cacerts config)')),
82 82 ]
83 83
84 84 walkopts = [
85 85 ('I', 'include', [],
86 86 _('include names matching the given patterns'), _('PATTERN')),
87 87 ('X', 'exclude', [],
88 88 _('exclude names matching the given patterns'), _('PATTERN')),
89 89 ]
90 90
91 91 commitopts = [
92 92 ('m', 'message', '',
93 93 _('use text as commit message'), _('TEXT')),
94 94 ('l', 'logfile', '',
95 95 _('read commit message from file'), _('FILE')),
96 96 ]
97 97
98 98 commitopts2 = [
99 99 ('d', 'date', '',
100 100 _('record the specified date as commit date'), _('DATE')),
101 101 ('u', 'user', '',
102 102 _('record the specified user as committer'), _('USER')),
103 103 ]
104 104
105 105 # hidden for now
106 106 formatteropts = [
107 107 ('T', 'template', '',
108 108 _('display with template (DEPRECATED)'), _('TEMPLATE')),
109 109 ]
110 110
111 111 templateopts = [
112 112 ('', 'style', '',
113 113 _('display using template map file (DEPRECATED)'), _('STYLE')),
114 114 ('T', 'template', '',
115 115 _('display with template'), _('TEMPLATE')),
116 116 ]
117 117
118 118 logopts = [
119 119 ('p', 'patch', None, _('show patch')),
120 120 ('g', 'git', None, _('use git extended diff format')),
121 121 ('l', 'limit', '',
122 122 _('limit number of changes displayed'), _('NUM')),
123 123 ('M', 'no-merges', None, _('do not show merges')),
124 124 ('', 'stat', None, _('output diffstat-style summary of changes')),
125 125 ('G', 'graph', None, _("show the revision DAG")),
126 126 ] + templateopts
127 127
128 128 diffopts = [
129 129 ('a', 'text', None, _('treat all files as text')),
130 130 ('g', 'git', None, _('use git extended diff format')),
131 131 ('', 'nodates', None, _('omit dates from diff headers'))
132 132 ]
133 133
134 134 diffwsopts = [
135 135 ('w', 'ignore-all-space', None,
136 136 _('ignore white space when comparing lines')),
137 137 ('b', 'ignore-space-change', None,
138 138 _('ignore changes in the amount of white space')),
139 139 ('B', 'ignore-blank-lines', None,
140 140 _('ignore changes whose lines are all blank')),
141 141 ]
142 142
143 143 diffopts2 = [
144 144 ('', 'noprefix', None, _('omit a/ and b/ prefixes from filenames')),
145 145 ('p', 'show-function', None, _('show which function each change is in')),
146 146 ('', 'reverse', None, _('produce a diff that undoes the changes')),
147 147 ] + diffwsopts + [
148 148 ('U', 'unified', '',
149 149 _('number of lines of context to show'), _('NUM')),
150 150 ('', 'stat', None, _('output diffstat-style summary of changes')),
151 151 ]
152 152
153 153 mergetoolopts = [
154 154 ('t', 'tool', '', _('specify merge tool')),
155 155 ]
156 156
157 157 similarityopts = [
158 158 ('s', 'similarity', '',
159 159 _('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
160 160 ]
161 161
162 162 subrepoopts = [
163 163 ('S', 'subrepos', None,
164 164 _('recurse into subrepositories'))
165 165 ]
166 166
167 167 # Commands start here, listed alphabetically
168 168
169 169 @command('^add',
170 170 walkopts + subrepoopts + dryrunopts,
171 171 _('[OPTION]... [FILE]...'),
172 172 inferrepo=True)
173 173 def add(ui, repo, *pats, **opts):
174 174 """add the specified files on the next commit
175 175
176 176 Schedule files to be version controlled and added to the
177 177 repository.
178 178
179 179 The files will be added to the repository at the next commit. To
180 180 undo an add before that, see :hg:`forget`.
181 181
182 182 If no names are given, add all files to the repository.
183 183
184 184 .. container:: verbose
185 185
186 186 An example showing how new (unknown) files are added
187 187 automatically by :hg:`add`::
188 188
189 189 $ ls
190 190 foo.c
191 191 $ hg status
192 192 ? foo.c
193 193 $ hg add
194 194 adding foo.c
195 195 $ hg status
196 196 A foo.c
197 197
198 198 Returns 0 if all files are successfully added.
199 199 """
200 200
201 201 m = scmutil.match(repo[None], pats, opts)
202 202 rejected = cmdutil.add(ui, repo, m, "", False, **opts)
203 203 return rejected and 1 or 0
204 204
205 205 @command('addremove',
206 206 similarityopts + subrepoopts + walkopts + dryrunopts,
207 207 _('[OPTION]... [FILE]...'),
208 208 inferrepo=True)
209 209 def addremove(ui, repo, *pats, **opts):
210 210 """add all new files, delete all missing files
211 211
212 212 Add all new files and remove all missing files from the
213 213 repository.
214 214
215 215 New files are ignored if they match any of the patterns in
216 216 ``.hgignore``. As with add, these changes take effect at the next
217 217 commit.
218 218
219 219 Use the -s/--similarity option to detect renamed files. This
220 220 option takes a percentage between 0 (disabled) and 100 (files must
221 221 be identical) as its parameter. With a parameter greater than 0,
222 222 this compares every removed file with every added file and records
223 223 those similar enough as renames. Detecting renamed files this way
224 224 can be expensive. After using this option, :hg:`status -C` can be
225 225 used to check which files were identified as moved or renamed. If
226 226 not specified, -s/--similarity defaults to 100 and only renames of
227 227 identical files are detected.
228 228
229 229 Returns 0 if all files are successfully added.
230 230 """
231 231 try:
232 232 sim = float(opts.get('similarity') or 100)
233 233 except ValueError:
234 234 raise util.Abort(_('similarity must be a number'))
235 235 if sim < 0 or sim > 100:
236 236 raise util.Abort(_('similarity must be between 0 and 100'))
237 237 matcher = scmutil.match(repo[None], pats, opts)
238 238 return scmutil.addremove(repo, matcher, "", opts, similarity=sim / 100.0)
239 239
240 240 @command('^annotate|blame',
241 241 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
242 242 ('', 'follow', None,
243 243 _('follow copies/renames and list the filename (DEPRECATED)')),
244 244 ('', 'no-follow', None, _("don't follow copies and renames")),
245 245 ('a', 'text', None, _('treat all files as text')),
246 246 ('u', 'user', None, _('list the author (long with -v)')),
247 247 ('f', 'file', None, _('list the filename')),
248 248 ('d', 'date', None, _('list the date (short with -q)')),
249 249 ('n', 'number', None, _('list the revision number (default)')),
250 250 ('c', 'changeset', None, _('list the changeset')),
251 251 ('l', 'line-number', None, _('show line number at the first appearance'))
252 252 ] + diffwsopts + walkopts + formatteropts,
253 253 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'),
254 254 inferrepo=True)
255 255 def annotate(ui, repo, *pats, **opts):
256 256 """show changeset information by line for each file
257 257
258 258 List changes in files, showing the revision id responsible for
259 259 each line
260 260
261 261 This command is useful for discovering when a change was made and
262 262 by whom.
263 263
264 264 Without the -a/--text option, annotate will avoid processing files
265 265 it detects as binary. With -a, annotate will annotate the file
266 266 anyway, although the results will probably be neither useful
267 267 nor desirable.
268 268
269 By default, annotate files in the parent of the working directory.
270 Use -r "wdir()" to annotate the working directory files.
271
269 272 Returns 0 on success.
270 273 """
271 274 if not pats:
272 275 raise util.Abort(_('at least one filename or pattern is required'))
273 276
274 277 if opts.get('follow'):
275 278 # --follow is deprecated and now just an alias for -f/--file
276 279 # to mimic the behavior of Mercurial before version 1.5
277 280 opts['file'] = True
278 281
282 ctx = scmutil.revsingle(repo, opts.get('rev'))
283
279 284 fm = ui.formatter('annotate', opts)
280 285 if ui.quiet:
281 286 datefunc = util.shortdate
282 287 else:
283 288 datefunc = util.datestr
289 if ctx.rev() is None:
290 def hexfn(node):
291 if node is None:
292 return None
293 else:
294 return fm.hexfunc(node)
295 if opts.get('changeset'):
296 # omit "+" suffix which is appended to node hex
297 def formatrev(rev):
298 if rev is None:
299 return '%d' % ctx.p1().rev()
300 else:
301 return '%d' % rev
302 else:
303 def formatrev(rev):
304 if rev is None:
305 return '%d+' % ctx.p1().rev()
306 else:
307 return '%d ' % rev
308 def formathex(hex):
309 if hex is None:
310 return '%s+' % fm.hexfunc(ctx.p1().node())
311 else:
312 return '%s ' % hex
313 else:
284 314 hexfn = fm.hexfunc
315 formatrev = formathex = str
285 316
286 317 opmap = [('user', ' ', lambda x: x[0].user(), ui.shortuser),
287 ('number', ' ', lambda x: x[0].rev(), str),
288 ('changeset', ' ', lambda x: hexfn(x[0].node()), str),
318 ('number', ' ', lambda x: x[0].rev(), formatrev),
319 ('changeset', ' ', lambda x: hexfn(x[0].node()), formathex),
289 320 ('date', ' ', lambda x: x[0].date(), util.cachefunc(datefunc)),
290 321 ('file', ' ', lambda x: x[0].path(), str),
291 322 ('line_number', ':', lambda x: x[1], str),
292 323 ]
293 324 fieldnamemap = {'number': 'rev', 'changeset': 'node'}
294 325
295 326 if (not opts.get('user') and not opts.get('changeset')
296 327 and not opts.get('date') and not opts.get('file')):
297 328 opts['number'] = True
298 329
299 330 linenumber = opts.get('line_number') is not None
300 331 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
301 332 raise util.Abort(_('at least one of -n/-c is required for -l'))
302 333
303 334 if fm:
304 335 def makefunc(get, fmt):
305 336 return get
306 337 else:
307 338 def makefunc(get, fmt):
308 339 return lambda x: fmt(get(x))
309 340 funcmap = [(makefunc(get, fmt), sep) for op, sep, get, fmt in opmap
310 341 if opts.get(op)]
311 342 funcmap[0] = (funcmap[0][0], '') # no separator in front of first column
312 343 fields = ' '.join(fieldnamemap.get(op, op) for op, sep, get, fmt in opmap
313 344 if opts.get(op))
314 345
315 346 def bad(x, y):
316 347 raise util.Abort("%s: %s" % (x, y))
317 348
318 ctx = scmutil.revsingle(repo, opts.get('rev'))
319 349 m = scmutil.match(ctx, pats, opts)
320 350 m.bad = bad
321 351 follow = not opts.get('no_follow')
322 352 diffopts = patch.difffeatureopts(ui, opts, section='annotate',
323 353 whitespace=True)
324 354 for abs in ctx.walk(m):
325 355 fctx = ctx[abs]
326 356 if not opts.get('text') and util.binary(fctx.data()):
327 357 fm.plain(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs))
328 358 continue
329 359
330 360 lines = fctx.annotate(follow=follow, linenumber=linenumber,
331 361 diffopts=diffopts)
332 362 formats = []
333 363 pieces = []
334 364
335 365 for f, sep in funcmap:
336 366 l = [f(n) for n, dummy in lines]
337 367 if l:
338 368 if fm:
339 369 formats.append(['%s' for x in l])
340 370 else:
341 371 sizes = [encoding.colwidth(x) for x in l]
342 372 ml = max(sizes)
343 373 formats.append([sep + ' ' * (ml - w) + '%s' for w in sizes])
344 374 pieces.append(l)
345 375
346 376 for f, p, l in zip(zip(*formats), zip(*pieces), lines):
347 377 fm.startitem()
348 378 fm.write(fields, "".join(f), *p)
349 379 fm.write('line', ": %s", l[1])
350 380
351 381 if lines and not lines[-1][1].endswith('\n'):
352 382 fm.plain('\n')
353 383
354 384 fm.end()
355 385
356 386 @command('archive',
357 387 [('', 'no-decode', None, _('do not pass files through decoders')),
358 388 ('p', 'prefix', '', _('directory prefix for files in archive'),
359 389 _('PREFIX')),
360 390 ('r', 'rev', '', _('revision to distribute'), _('REV')),
361 391 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
362 392 ] + subrepoopts + walkopts,
363 393 _('[OPTION]... DEST'))
364 394 def archive(ui, repo, dest, **opts):
365 395 '''create an unversioned archive of a repository revision
366 396
367 397 By default, the revision used is the parent of the working
368 398 directory; use -r/--rev to specify a different revision.
369 399
370 400 The archive type is automatically detected based on file
371 401 extension (or override using -t/--type).
372 402
373 403 .. container:: verbose
374 404
375 405 Examples:
376 406
377 407 - create a zip file containing the 1.0 release::
378 408
379 409 hg archive -r 1.0 project-1.0.zip
380 410
381 411 - create a tarball excluding .hg files::
382 412
383 413 hg archive project.tar.gz -X ".hg*"
384 414
385 415 Valid types are:
386 416
387 417 :``files``: a directory full of files (default)
388 418 :``tar``: tar archive, uncompressed
389 419 :``tbz2``: tar archive, compressed using bzip2
390 420 :``tgz``: tar archive, compressed using gzip
391 421 :``uzip``: zip archive, uncompressed
392 422 :``zip``: zip archive, compressed using deflate
393 423
394 424 The exact name of the destination archive or directory is given
395 425 using a format string; see :hg:`help export` for details.
396 426
397 427 Each member added to an archive file has a directory prefix
398 428 prepended. Use -p/--prefix to specify a format string for the
399 429 prefix. The default is the basename of the archive, with suffixes
400 430 removed.
401 431
402 432 Returns 0 on success.
403 433 '''
404 434
405 435 ctx = scmutil.revsingle(repo, opts.get('rev'))
406 436 if not ctx:
407 437 raise util.Abort(_('no working directory: please specify a revision'))
408 438 node = ctx.node()
409 439 dest = cmdutil.makefilename(repo, dest, node)
410 440 if os.path.realpath(dest) == repo.root:
411 441 raise util.Abort(_('repository root cannot be destination'))
412 442
413 443 kind = opts.get('type') or archival.guesskind(dest) or 'files'
414 444 prefix = opts.get('prefix')
415 445
416 446 if dest == '-':
417 447 if kind == 'files':
418 448 raise util.Abort(_('cannot archive plain files to stdout'))
419 449 dest = cmdutil.makefileobj(repo, dest)
420 450 if not prefix:
421 451 prefix = os.path.basename(repo.root) + '-%h'
422 452
423 453 prefix = cmdutil.makefilename(repo, prefix, node)
424 454 matchfn = scmutil.match(ctx, [], opts)
425 455 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
426 456 matchfn, prefix, subrepos=opts.get('subrepos'))
427 457
428 458 @command('backout',
429 459 [('', 'merge', None, _('merge with old dirstate parent after backout')),
430 460 ('', 'commit', None, _('commit if no conflicts were encountered')),
431 461 ('', 'parent', '',
432 462 _('parent to choose when backing out merge (DEPRECATED)'), _('REV')),
433 463 ('r', 'rev', '', _('revision to backout'), _('REV')),
434 464 ('e', 'edit', False, _('invoke editor on commit messages')),
435 465 ] + mergetoolopts + walkopts + commitopts + commitopts2,
436 466 _('[OPTION]... [-r] REV'))
437 467 def backout(ui, repo, node=None, rev=None, commit=False, **opts):
438 468 '''reverse effect of earlier changeset
439 469
440 470 Prepare a new changeset with the effect of REV undone in the
441 471 current working directory.
442 472
443 473 If REV is the parent of the working directory, then this new changeset
444 474 is committed automatically. Otherwise, hg needs to merge the
445 475 changes and the merged result is left uncommitted.
446 476
447 477 .. note::
448 478
449 479 backout cannot be used to fix either an unwanted or
450 480 incorrect merge.
451 481
452 482 .. container:: verbose
453 483
454 484 By default, the pending changeset will have one parent,
455 485 maintaining a linear history. With --merge, the pending
456 486 changeset will instead have two parents: the old parent of the
457 487 working directory and a new child of REV that simply undoes REV.
458 488
459 489 Before version 1.7, the behavior without --merge was equivalent
460 490 to specifying --merge followed by :hg:`update --clean .` to
461 491 cancel the merge and leave the child of REV as a head to be
462 492 merged separately.
463 493
464 494 See :hg:`help dates` for a list of formats valid for -d/--date.
465 495
466 496 Returns 0 on success, 1 if nothing to backout or there are unresolved
467 497 files.
468 498 '''
469 499 if rev and node:
470 500 raise util.Abort(_("please specify just one revision"))
471 501
472 502 if not rev:
473 503 rev = node
474 504
475 505 if not rev:
476 506 raise util.Abort(_("please specify a revision to backout"))
477 507
478 508 date = opts.get('date')
479 509 if date:
480 510 opts['date'] = util.parsedate(date)
481 511
482 512 cmdutil.checkunfinished(repo)
483 513 cmdutil.bailifchanged(repo)
484 514 node = scmutil.revsingle(repo, rev).node()
485 515
486 516 op1, op2 = repo.dirstate.parents()
487 517 if not repo.changelog.isancestor(node, op1):
488 518 raise util.Abort(_('cannot backout change that is not an ancestor'))
489 519
490 520 p1, p2 = repo.changelog.parents(node)
491 521 if p1 == nullid:
492 522 raise util.Abort(_('cannot backout a change with no parents'))
493 523 if p2 != nullid:
494 524 if not opts.get('parent'):
495 525 raise util.Abort(_('cannot backout a merge changeset'))
496 526 p = repo.lookup(opts['parent'])
497 527 if p not in (p1, p2):
498 528 raise util.Abort(_('%s is not a parent of %s') %
499 529 (short(p), short(node)))
500 530 parent = p
501 531 else:
502 532 if opts.get('parent'):
503 533 raise util.Abort(_('cannot use --parent on non-merge changeset'))
504 534 parent = p1
505 535
506 536 # the backout should appear on the same branch
507 537 wlock = repo.wlock()
508 538 try:
509 539 branch = repo.dirstate.branch()
510 540 bheads = repo.branchheads(branch)
511 541 rctx = scmutil.revsingle(repo, hex(parent))
512 542 if not opts.get('merge') and op1 != node:
513 543 try:
514 544 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
515 545 'backout')
516 546 repo.dirstate.beginparentchange()
517 547 stats = mergemod.update(repo, parent, True, True, False,
518 548 node, False)
519 549 repo.setparents(op1, op2)
520 550 repo.dirstate.endparentchange()
521 551 hg._showstats(repo, stats)
522 552 if stats[3]:
523 553 repo.ui.status(_("use 'hg resolve' to retry unresolved "
524 554 "file merges\n"))
525 555 return 1
526 556 elif not commit:
527 557 msg = _("changeset %s backed out, "
528 558 "don't forget to commit.\n")
529 559 ui.status(msg % short(node))
530 560 return 0
531 561 finally:
532 562 ui.setconfig('ui', 'forcemerge', '', '')
533 563 else:
534 564 hg.clean(repo, node, show_stats=False)
535 565 repo.dirstate.setbranch(branch)
536 566 cmdutil.revert(ui, repo, rctx, repo.dirstate.parents())
537 567
538 568
539 569 def commitfunc(ui, repo, message, match, opts):
540 570 editform = 'backout'
541 571 e = cmdutil.getcommiteditor(editform=editform, **opts)
542 572 if not message:
543 573 # we don't translate commit messages
544 574 message = "Backed out changeset %s" % short(node)
545 575 e = cmdutil.getcommiteditor(edit=True, editform=editform)
546 576 return repo.commit(message, opts.get('user'), opts.get('date'),
547 577 match, editor=e)
548 578 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
549 579 if not newnode:
550 580 ui.status(_("nothing changed\n"))
551 581 return 1
552 582 cmdutil.commitstatus(repo, newnode, branch, bheads)
553 583
554 584 def nice(node):
555 585 return '%d:%s' % (repo.changelog.rev(node), short(node))
556 586 ui.status(_('changeset %s backs out changeset %s\n') %
557 587 (nice(repo.changelog.tip()), nice(node)))
558 588 if opts.get('merge') and op1 != node:
559 589 hg.clean(repo, op1, show_stats=False)
560 590 ui.status(_('merging with changeset %s\n')
561 591 % nice(repo.changelog.tip()))
562 592 try:
563 593 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
564 594 'backout')
565 595 return hg.merge(repo, hex(repo.changelog.tip()))
566 596 finally:
567 597 ui.setconfig('ui', 'forcemerge', '', '')
568 598 finally:
569 599 wlock.release()
570 600 return 0
571 601
572 602 @command('bisect',
573 603 [('r', 'reset', False, _('reset bisect state')),
574 604 ('g', 'good', False, _('mark changeset good')),
575 605 ('b', 'bad', False, _('mark changeset bad')),
576 606 ('s', 'skip', False, _('skip testing changeset')),
577 607 ('e', 'extend', False, _('extend the bisect range')),
578 608 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
579 609 ('U', 'noupdate', False, _('do not update to target'))],
580 610 _("[-gbsr] [-U] [-c CMD] [REV]"))
581 611 def bisect(ui, repo, rev=None, extra=None, command=None,
582 612 reset=None, good=None, bad=None, skip=None, extend=None,
583 613 noupdate=None):
584 614 """subdivision search of changesets
585 615
586 616 This command helps to find changesets which introduce problems. To
587 617 use, mark the earliest changeset you know exhibits the problem as
588 618 bad, then mark the latest changeset which is free from the problem
589 619 as good. Bisect will update your working directory to a revision
590 620 for testing (unless the -U/--noupdate option is specified). Once
591 621 you have performed tests, mark the working directory as good or
592 622 bad, and bisect will either update to another candidate changeset
593 623 or announce that it has found the bad revision.
594 624
595 625 As a shortcut, you can also use the revision argument to mark a
596 626 revision as good or bad without checking it out first.
597 627
598 628 If you supply a command, it will be used for automatic bisection.
599 629 The environment variable HG_NODE will contain the ID of the
600 630 changeset being tested. The exit status of the command will be
601 631 used to mark revisions as good or bad: status 0 means good, 125
602 632 means to skip the revision, 127 (command not found) will abort the
603 633 bisection, and any other non-zero exit status means the revision
604 634 is bad.
605 635
606 636 .. container:: verbose
607 637
608 638 Some examples:
609 639
610 640 - start a bisection with known bad revision 34, and good revision 12::
611 641
612 642 hg bisect --bad 34
613 643 hg bisect --good 12
614 644
615 645 - advance the current bisection by marking current revision as good or
616 646 bad::
617 647
618 648 hg bisect --good
619 649 hg bisect --bad
620 650
621 651 - mark the current revision, or a known revision, to be skipped (e.g. if
622 652 that revision is not usable because of another issue)::
623 653
624 654 hg bisect --skip
625 655 hg bisect --skip 23
626 656
627 657 - skip all revisions that do not touch directories ``foo`` or ``bar``::
628 658
629 659 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
630 660
631 661 - forget the current bisection::
632 662
633 663 hg bisect --reset
634 664
635 665 - use 'make && make tests' to automatically find the first broken
636 666 revision::
637 667
638 668 hg bisect --reset
639 669 hg bisect --bad 34
640 670 hg bisect --good 12
641 671 hg bisect --command "make && make tests"
642 672
643 673 - see all changesets whose states are already known in the current
644 674 bisection::
645 675
646 676 hg log -r "bisect(pruned)"
647 677
648 678 - see the changeset currently being bisected (especially useful
649 679 if running with -U/--noupdate)::
650 680
651 681 hg log -r "bisect(current)"
652 682
653 683 - see all changesets that took part in the current bisection::
654 684
655 685 hg log -r "bisect(range)"
656 686
657 687 - you can even get a nice graph::
658 688
659 689 hg log --graph -r "bisect(range)"
660 690
661 691 See :hg:`help revsets` for more about the `bisect()` keyword.
662 692
663 693 Returns 0 on success.
664 694 """
665 695 def extendbisectrange(nodes, good):
666 696 # bisect is incomplete when it ends on a merge node and
667 697 # one of the parent was not checked.
668 698 parents = repo[nodes[0]].parents()
669 699 if len(parents) > 1:
670 700 if good:
671 701 side = state['bad']
672 702 else:
673 703 side = state['good']
674 704 num = len(set(i.node() for i in parents) & set(side))
675 705 if num == 1:
676 706 return parents[0].ancestor(parents[1])
677 707 return None
678 708
679 709 def print_result(nodes, good):
680 710 displayer = cmdutil.show_changeset(ui, repo, {})
681 711 if len(nodes) == 1:
682 712 # narrowed it down to a single revision
683 713 if good:
684 714 ui.write(_("The first good revision is:\n"))
685 715 else:
686 716 ui.write(_("The first bad revision is:\n"))
687 717 displayer.show(repo[nodes[0]])
688 718 extendnode = extendbisectrange(nodes, good)
689 719 if extendnode is not None:
690 720 ui.write(_('Not all ancestors of this changeset have been'
691 721 ' checked.\nUse bisect --extend to continue the '
692 722 'bisection from\nthe common ancestor, %s.\n')
693 723 % extendnode)
694 724 else:
695 725 # multiple possible revisions
696 726 if good:
697 727 ui.write(_("Due to skipped revisions, the first "
698 728 "good revision could be any of:\n"))
699 729 else:
700 730 ui.write(_("Due to skipped revisions, the first "
701 731 "bad revision could be any of:\n"))
702 732 for n in nodes:
703 733 displayer.show(repo[n])
704 734 displayer.close()
705 735
706 736 def check_state(state, interactive=True):
707 737 if not state['good'] or not state['bad']:
708 738 if (good or bad or skip or reset) and interactive:
709 739 return
710 740 if not state['good']:
711 741 raise util.Abort(_('cannot bisect (no known good revisions)'))
712 742 else:
713 743 raise util.Abort(_('cannot bisect (no known bad revisions)'))
714 744 return True
715 745
716 746 # backward compatibility
717 747 if rev in "good bad reset init".split():
718 748 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
719 749 cmd, rev, extra = rev, extra, None
720 750 if cmd == "good":
721 751 good = True
722 752 elif cmd == "bad":
723 753 bad = True
724 754 else:
725 755 reset = True
726 756 elif extra or good + bad + skip + reset + extend + bool(command) > 1:
727 757 raise util.Abort(_('incompatible arguments'))
728 758
729 759 cmdutil.checkunfinished(repo)
730 760
731 761 if reset:
732 762 p = repo.join("bisect.state")
733 763 if os.path.exists(p):
734 764 os.unlink(p)
735 765 return
736 766
737 767 state = hbisect.load_state(repo)
738 768
739 769 if command:
740 770 changesets = 1
741 771 if noupdate:
742 772 try:
743 773 node = state['current'][0]
744 774 except LookupError:
745 775 raise util.Abort(_('current bisect revision is unknown - '
746 776 'start a new bisect to fix'))
747 777 else:
748 778 node, p2 = repo.dirstate.parents()
749 779 if p2 != nullid:
750 780 raise util.Abort(_('current bisect revision is a merge'))
751 781 try:
752 782 while changesets:
753 783 # update state
754 784 state['current'] = [node]
755 785 hbisect.save_state(repo, state)
756 786 status = ui.system(command, environ={'HG_NODE': hex(node)})
757 787 if status == 125:
758 788 transition = "skip"
759 789 elif status == 0:
760 790 transition = "good"
761 791 # status < 0 means process was killed
762 792 elif status == 127:
763 793 raise util.Abort(_("failed to execute %s") % command)
764 794 elif status < 0:
765 795 raise util.Abort(_("%s killed") % command)
766 796 else:
767 797 transition = "bad"
768 798 ctx = scmutil.revsingle(repo, rev, node)
769 799 rev = None # clear for future iterations
770 800 state[transition].append(ctx.node())
771 801 ui.status(_('changeset %d:%s: %s\n') % (ctx, ctx, transition))
772 802 check_state(state, interactive=False)
773 803 # bisect
774 804 nodes, changesets, bgood = hbisect.bisect(repo.changelog, state)
775 805 # update to next check
776 806 node = nodes[0]
777 807 if not noupdate:
778 808 cmdutil.bailifchanged(repo)
779 809 hg.clean(repo, node, show_stats=False)
780 810 finally:
781 811 state['current'] = [node]
782 812 hbisect.save_state(repo, state)
783 813 print_result(nodes, bgood)
784 814 return
785 815
786 816 # update state
787 817
788 818 if rev:
789 819 nodes = [repo.lookup(i) for i in scmutil.revrange(repo, [rev])]
790 820 else:
791 821 nodes = [repo.lookup('.')]
792 822
793 823 if good or bad or skip:
794 824 if good:
795 825 state['good'] += nodes
796 826 elif bad:
797 827 state['bad'] += nodes
798 828 elif skip:
799 829 state['skip'] += nodes
800 830 hbisect.save_state(repo, state)
801 831
802 832 if not check_state(state):
803 833 return
804 834
805 835 # actually bisect
806 836 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
807 837 if extend:
808 838 if not changesets:
809 839 extendnode = extendbisectrange(nodes, good)
810 840 if extendnode is not None:
811 841 ui.write(_("Extending search to changeset %d:%s\n")
812 842 % (extendnode.rev(), extendnode))
813 843 state['current'] = [extendnode.node()]
814 844 hbisect.save_state(repo, state)
815 845 if noupdate:
816 846 return
817 847 cmdutil.bailifchanged(repo)
818 848 return hg.clean(repo, extendnode.node())
819 849 raise util.Abort(_("nothing to extend"))
820 850
821 851 if changesets == 0:
822 852 print_result(nodes, good)
823 853 else:
824 854 assert len(nodes) == 1 # only a single node can be tested next
825 855 node = nodes[0]
826 856 # compute the approximate number of remaining tests
827 857 tests, size = 0, 2
828 858 while size <= changesets:
829 859 tests, size = tests + 1, size * 2
830 860 rev = repo.changelog.rev(node)
831 861 ui.write(_("Testing changeset %d:%s "
832 862 "(%d changesets remaining, ~%d tests)\n")
833 863 % (rev, short(node), changesets, tests))
834 864 state['current'] = [node]
835 865 hbisect.save_state(repo, state)
836 866 if not noupdate:
837 867 cmdutil.bailifchanged(repo)
838 868 return hg.clean(repo, node)
839 869
840 870 @command('bookmarks|bookmark',
841 871 [('f', 'force', False, _('force')),
842 872 ('r', 'rev', '', _('revision'), _('REV')),
843 873 ('d', 'delete', False, _('delete a given bookmark')),
844 874 ('m', 'rename', '', _('rename a given bookmark'), _('NAME')),
845 875 ('i', 'inactive', False, _('mark a bookmark inactive')),
846 876 ] + formatteropts,
847 877 _('hg bookmarks [OPTIONS]... [NAME]...'))
848 878 def bookmark(ui, repo, *names, **opts):
849 879 '''create a new bookmark or list existing bookmarks
850 880
851 881 Bookmarks are labels on changesets to help track lines of development.
852 882 Bookmarks are unversioned and can be moved, renamed and deleted.
853 883 Deleting or moving a bookmark has no effect on the associated changesets.
854 884
855 885 Creating or updating to a bookmark causes it to be marked as 'active'.
856 886 The active bookmark is indicated with a '*'.
857 887 When a commit is made, the active bookmark will advance to the new commit.
858 888 A plain :hg:`update` will also advance an active bookmark, if possible.
859 889 Updating away from a bookmark will cause it to be deactivated.
860 890
861 891 Bookmarks can be pushed and pulled between repositories (see
862 892 :hg:`help push` and :hg:`help pull`). If a shared bookmark has
863 893 diverged, a new 'divergent bookmark' of the form 'name@path' will
864 894 be created. Using :hg:`merge` will resolve the divergence.
865 895
866 896 A bookmark named '@' has the special property that :hg:`clone` will
867 897 check it out by default if it exists.
868 898
869 899 .. container:: verbose
870 900
871 901 Examples:
872 902
873 903 - create an active bookmark for a new line of development::
874 904
875 905 hg book new-feature
876 906
877 907 - create an inactive bookmark as a place marker::
878 908
879 909 hg book -i reviewed
880 910
881 911 - create an inactive bookmark on another changeset::
882 912
883 913 hg book -r .^ tested
884 914
885 915 - move the '@' bookmark from another branch::
886 916
887 917 hg book -f @
888 918 '''
889 919 force = opts.get('force')
890 920 rev = opts.get('rev')
891 921 delete = opts.get('delete')
892 922 rename = opts.get('rename')
893 923 inactive = opts.get('inactive')
894 924
895 925 def checkformat(mark):
896 926 mark = mark.strip()
897 927 if not mark:
898 928 raise util.Abort(_("bookmark names cannot consist entirely of "
899 929 "whitespace"))
900 930 scmutil.checknewlabel(repo, mark, 'bookmark')
901 931 return mark
902 932
903 933 def checkconflict(repo, mark, cur, force=False, target=None):
904 934 if mark in marks and not force:
905 935 if target:
906 936 if marks[mark] == target and target == cur:
907 937 # re-activating a bookmark
908 938 return
909 939 anc = repo.changelog.ancestors([repo[target].rev()])
910 940 bmctx = repo[marks[mark]]
911 941 divs = [repo[b].node() for b in marks
912 942 if b.split('@', 1)[0] == mark.split('@', 1)[0]]
913 943
914 944 # allow resolving a single divergent bookmark even if moving
915 945 # the bookmark across branches when a revision is specified
916 946 # that contains a divergent bookmark
917 947 if bmctx.rev() not in anc and target in divs:
918 948 bookmarks.deletedivergent(repo, [target], mark)
919 949 return
920 950
921 951 deletefrom = [b for b in divs
922 952 if repo[b].rev() in anc or b == target]
923 953 bookmarks.deletedivergent(repo, deletefrom, mark)
924 954 if bookmarks.validdest(repo, bmctx, repo[target]):
925 955 ui.status(_("moving bookmark '%s' forward from %s\n") %
926 956 (mark, short(bmctx.node())))
927 957 return
928 958 raise util.Abort(_("bookmark '%s' already exists "
929 959 "(use -f to force)") % mark)
930 960 if ((mark in repo.branchmap() or mark == repo.dirstate.branch())
931 961 and not force):
932 962 raise util.Abort(
933 963 _("a bookmark cannot have the name of an existing branch"))
934 964
935 965 if delete and rename:
936 966 raise util.Abort(_("--delete and --rename are incompatible"))
937 967 if delete and rev:
938 968 raise util.Abort(_("--rev is incompatible with --delete"))
939 969 if rename and rev:
940 970 raise util.Abort(_("--rev is incompatible with --rename"))
941 971 if not names and (delete or rev):
942 972 raise util.Abort(_("bookmark name required"))
943 973
944 974 if delete or rename or names or inactive:
945 975 wlock = repo.wlock()
946 976 try:
947 977 cur = repo.changectx('.').node()
948 978 marks = repo._bookmarks
949 979 if delete:
950 980 for mark in names:
951 981 if mark not in marks:
952 982 raise util.Abort(_("bookmark '%s' does not exist") %
953 983 mark)
954 984 if mark == repo._bookmarkcurrent:
955 985 bookmarks.unsetcurrent(repo)
956 986 del marks[mark]
957 987 marks.write()
958 988
959 989 elif rename:
960 990 if not names:
961 991 raise util.Abort(_("new bookmark name required"))
962 992 elif len(names) > 1:
963 993 raise util.Abort(_("only one new bookmark name allowed"))
964 994 mark = checkformat(names[0])
965 995 if rename not in marks:
966 996 raise util.Abort(_("bookmark '%s' does not exist") % rename)
967 997 checkconflict(repo, mark, cur, force)
968 998 marks[mark] = marks[rename]
969 999 if repo._bookmarkcurrent == rename and not inactive:
970 1000 bookmarks.setcurrent(repo, mark)
971 1001 del marks[rename]
972 1002 marks.write()
973 1003
974 1004 elif names:
975 1005 newact = None
976 1006 for mark in names:
977 1007 mark = checkformat(mark)
978 1008 if newact is None:
979 1009 newact = mark
980 1010 if inactive and mark == repo._bookmarkcurrent:
981 1011 bookmarks.unsetcurrent(repo)
982 1012 return
983 1013 tgt = cur
984 1014 if rev:
985 1015 tgt = scmutil.revsingle(repo, rev).node()
986 1016 checkconflict(repo, mark, cur, force, tgt)
987 1017 marks[mark] = tgt
988 1018 if not inactive and cur == marks[newact] and not rev:
989 1019 bookmarks.setcurrent(repo, newact)
990 1020 elif cur != tgt and newact == repo._bookmarkcurrent:
991 1021 bookmarks.unsetcurrent(repo)
992 1022 marks.write()
993 1023
994 1024 elif inactive:
995 1025 if len(marks) == 0:
996 1026 ui.status(_("no bookmarks set\n"))
997 1027 elif not repo._bookmarkcurrent:
998 1028 ui.status(_("no active bookmark\n"))
999 1029 else:
1000 1030 bookmarks.unsetcurrent(repo)
1001 1031 finally:
1002 1032 wlock.release()
1003 1033 else: # show bookmarks
1004 1034 fm = ui.formatter('bookmarks', opts)
1005 1035 hexfn = fm.hexfunc
1006 1036 marks = repo._bookmarks
1007 1037 if len(marks) == 0 and not fm:
1008 1038 ui.status(_("no bookmarks set\n"))
1009 1039 for bmark, n in sorted(marks.iteritems()):
1010 1040 current = repo._bookmarkcurrent
1011 1041 if bmark == current:
1012 1042 prefix, label = '*', 'bookmarks.current'
1013 1043 else:
1014 1044 prefix, label = ' ', ''
1015 1045
1016 1046 fm.startitem()
1017 1047 if not ui.quiet:
1018 1048 fm.plain(' %s ' % prefix, label=label)
1019 1049 fm.write('bookmark', '%s', bmark, label=label)
1020 1050 pad = " " * (25 - encoding.colwidth(bmark))
1021 1051 fm.condwrite(not ui.quiet, 'rev node', pad + ' %d:%s',
1022 1052 repo.changelog.rev(n), hexfn(n), label=label)
1023 1053 fm.data(active=(bmark == current))
1024 1054 fm.plain('\n')
1025 1055 fm.end()
1026 1056
1027 1057 @command('branch',
1028 1058 [('f', 'force', None,
1029 1059 _('set branch name even if it shadows an existing branch')),
1030 1060 ('C', 'clean', None, _('reset branch name to parent branch name'))],
1031 1061 _('[-fC] [NAME]'))
1032 1062 def branch(ui, repo, label=None, **opts):
1033 1063 """set or show the current branch name
1034 1064
1035 1065 .. note::
1036 1066
1037 1067 Branch names are permanent and global. Use :hg:`bookmark` to create a
1038 1068 light-weight bookmark instead. See :hg:`help glossary` for more
1039 1069 information about named branches and bookmarks.
1040 1070
1041 1071 With no argument, show the current branch name. With one argument,
1042 1072 set the working directory branch name (the branch will not exist
1043 1073 in the repository until the next commit). Standard practice
1044 1074 recommends that primary development take place on the 'default'
1045 1075 branch.
1046 1076
1047 1077 Unless -f/--force is specified, branch will not let you set a
1048 1078 branch name that already exists.
1049 1079
1050 1080 Use -C/--clean to reset the working directory branch to that of
1051 1081 the parent of the working directory, negating a previous branch
1052 1082 change.
1053 1083
1054 1084 Use the command :hg:`update` to switch to an existing branch. Use
1055 1085 :hg:`commit --close-branch` to mark this branch as closed.
1056 1086
1057 1087 Returns 0 on success.
1058 1088 """
1059 1089 if label:
1060 1090 label = label.strip()
1061 1091
1062 1092 if not opts.get('clean') and not label:
1063 1093 ui.write("%s\n" % repo.dirstate.branch())
1064 1094 return
1065 1095
1066 1096 wlock = repo.wlock()
1067 1097 try:
1068 1098 if opts.get('clean'):
1069 1099 label = repo[None].p1().branch()
1070 1100 repo.dirstate.setbranch(label)
1071 1101 ui.status(_('reset working directory to branch %s\n') % label)
1072 1102 elif label:
1073 1103 if not opts.get('force') and label in repo.branchmap():
1074 1104 if label not in [p.branch() for p in repo.parents()]:
1075 1105 raise util.Abort(_('a branch of the same name already'
1076 1106 ' exists'),
1077 1107 # i18n: "it" refers to an existing branch
1078 1108 hint=_("use 'hg update' to switch to it"))
1079 1109 scmutil.checknewlabel(repo, label, 'branch')
1080 1110 repo.dirstate.setbranch(label)
1081 1111 ui.status(_('marked working directory as branch %s\n') % label)
1082 1112 ui.status(_('(branches are permanent and global, '
1083 1113 'did you want a bookmark?)\n'))
1084 1114 finally:
1085 1115 wlock.release()
1086 1116
1087 1117 @command('branches',
1088 1118 [('a', 'active', False,
1089 1119 _('show only branches that have unmerged heads (DEPRECATED)')),
1090 1120 ('c', 'closed', False, _('show normal and closed branches')),
1091 1121 ] + formatteropts,
1092 1122 _('[-ac]'))
1093 1123 def branches(ui, repo, active=False, closed=False, **opts):
1094 1124 """list repository named branches
1095 1125
1096 1126 List the repository's named branches, indicating which ones are
1097 1127 inactive. If -c/--closed is specified, also list branches which have
1098 1128 been marked closed (see :hg:`commit --close-branch`).
1099 1129
1100 1130 Use the command :hg:`update` to switch to an existing branch.
1101 1131
1102 1132 Returns 0.
1103 1133 """
1104 1134
1105 1135 fm = ui.formatter('branches', opts)
1106 1136 hexfunc = fm.hexfunc
1107 1137
1108 1138 allheads = set(repo.heads())
1109 1139 branches = []
1110 1140 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1111 1141 isactive = not isclosed and bool(set(heads) & allheads)
1112 1142 branches.append((tag, repo[tip], isactive, not isclosed))
1113 1143 branches.sort(key=lambda i: (i[2], i[1].rev(), i[0], i[3]),
1114 1144 reverse=True)
1115 1145
1116 1146 for tag, ctx, isactive, isopen in branches:
1117 1147 if active and not isactive:
1118 1148 continue
1119 1149 if isactive:
1120 1150 label = 'branches.active'
1121 1151 notice = ''
1122 1152 elif not isopen:
1123 1153 if not closed:
1124 1154 continue
1125 1155 label = 'branches.closed'
1126 1156 notice = _(' (closed)')
1127 1157 else:
1128 1158 label = 'branches.inactive'
1129 1159 notice = _(' (inactive)')
1130 1160 current = (tag == repo.dirstate.branch())
1131 1161 if current:
1132 1162 label = 'branches.current'
1133 1163
1134 1164 fm.startitem()
1135 1165 fm.write('branch', '%s', tag, label=label)
1136 1166 rev = ctx.rev()
1137 1167 padsize = max(31 - len(str(rev)) - encoding.colwidth(tag), 0)
1138 1168 fmt = ' ' * padsize + ' %d:%s'
1139 1169 fm.condwrite(not ui.quiet, 'rev node', fmt, rev, hexfunc(ctx.node()),
1140 1170 label='log.changeset changeset.%s' % ctx.phasestr())
1141 1171 fm.data(active=isactive, closed=not isopen, current=current)
1142 1172 if not ui.quiet:
1143 1173 fm.plain(notice)
1144 1174 fm.plain('\n')
1145 1175 fm.end()
1146 1176
1147 1177 @command('bundle',
1148 1178 [('f', 'force', None, _('run even when the destination is unrelated')),
1149 1179 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
1150 1180 _('REV')),
1151 1181 ('b', 'branch', [], _('a specific branch you would like to bundle'),
1152 1182 _('BRANCH')),
1153 1183 ('', 'base', [],
1154 1184 _('a base changeset assumed to be available at the destination'),
1155 1185 _('REV')),
1156 1186 ('a', 'all', None, _('bundle all changesets in the repository')),
1157 1187 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
1158 1188 ] + remoteopts,
1159 1189 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
1160 1190 def bundle(ui, repo, fname, dest=None, **opts):
1161 1191 """create a changegroup file
1162 1192
1163 1193 Generate a compressed changegroup file collecting changesets not
1164 1194 known to be in another repository.
1165 1195
1166 1196 If you omit the destination repository, then hg assumes the
1167 1197 destination will have all the nodes you specify with --base
1168 1198 parameters. To create a bundle containing all changesets, use
1169 1199 -a/--all (or --base null).
1170 1200
1171 1201 You can change compression method with the -t/--type option.
1172 1202 The available compression methods are: none, bzip2, and
1173 1203 gzip (by default, bundles are compressed using bzip2).
1174 1204
1175 1205 The bundle file can then be transferred using conventional means
1176 1206 and applied to another repository with the unbundle or pull
1177 1207 command. This is useful when direct push and pull are not
1178 1208 available or when exporting an entire repository is undesirable.
1179 1209
1180 1210 Applying bundles preserves all changeset contents including
1181 1211 permissions, copy/rename information, and revision history.
1182 1212
1183 1213 Returns 0 on success, 1 if no changes found.
1184 1214 """
1185 1215 revs = None
1186 1216 if 'rev' in opts:
1187 1217 revs = scmutil.revrange(repo, opts['rev'])
1188 1218
1189 1219 bundletype = opts.get('type', 'bzip2').lower()
1190 1220 btypes = {'none': 'HG10UN',
1191 1221 'bzip2': 'HG10BZ',
1192 1222 'gzip': 'HG10GZ',
1193 1223 'bundle2': 'HG2Y'}
1194 1224 bundletype = btypes.get(bundletype)
1195 1225 if bundletype not in changegroup.bundletypes:
1196 1226 raise util.Abort(_('unknown bundle type specified with --type'))
1197 1227
1198 1228 if opts.get('all'):
1199 1229 base = ['null']
1200 1230 else:
1201 1231 base = scmutil.revrange(repo, opts.get('base'))
1202 1232 # TODO: get desired bundlecaps from command line.
1203 1233 bundlecaps = None
1204 1234 if base:
1205 1235 if dest:
1206 1236 raise util.Abort(_("--base is incompatible with specifying "
1207 1237 "a destination"))
1208 1238 common = [repo.lookup(rev) for rev in base]
1209 1239 heads = revs and map(repo.lookup, revs) or revs
1210 1240 cg = changegroup.getchangegroup(repo, 'bundle', heads=heads,
1211 1241 common=common, bundlecaps=bundlecaps)
1212 1242 outgoing = None
1213 1243 else:
1214 1244 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1215 1245 dest, branches = hg.parseurl(dest, opts.get('branch'))
1216 1246 other = hg.peer(repo, opts, dest)
1217 1247 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1218 1248 heads = revs and map(repo.lookup, revs) or revs
1219 1249 outgoing = discovery.findcommonoutgoing(repo, other,
1220 1250 onlyheads=heads,
1221 1251 force=opts.get('force'),
1222 1252 portable=True)
1223 1253 cg = changegroup.getlocalchangegroup(repo, 'bundle', outgoing,
1224 1254 bundlecaps)
1225 1255 if not cg:
1226 1256 scmutil.nochangesfound(ui, repo, outgoing and outgoing.excluded)
1227 1257 return 1
1228 1258
1229 1259 changegroup.writebundle(ui, cg, fname, bundletype)
1230 1260
1231 1261 @command('cat',
1232 1262 [('o', 'output', '',
1233 1263 _('print output to file with formatted name'), _('FORMAT')),
1234 1264 ('r', 'rev', '', _('print the given revision'), _('REV')),
1235 1265 ('', 'decode', None, _('apply any matching decode filter')),
1236 1266 ] + walkopts,
1237 1267 _('[OPTION]... FILE...'),
1238 1268 inferrepo=True)
1239 1269 def cat(ui, repo, file1, *pats, **opts):
1240 1270 """output the current or given revision of files
1241 1271
1242 1272 Print the specified files as they were at the given revision. If
1243 1273 no revision is given, the parent of the working directory is used.
1244 1274
1245 1275 Output may be to a file, in which case the name of the file is
1246 1276 given using a format string. The formatting rules as follows:
1247 1277
1248 1278 :``%%``: literal "%" character
1249 1279 :``%s``: basename of file being printed
1250 1280 :``%d``: dirname of file being printed, or '.' if in repository root
1251 1281 :``%p``: root-relative path name of file being printed
1252 1282 :``%H``: changeset hash (40 hexadecimal digits)
1253 1283 :``%R``: changeset revision number
1254 1284 :``%h``: short-form changeset hash (12 hexadecimal digits)
1255 1285 :``%r``: zero-padded changeset revision number
1256 1286 :``%b``: basename of the exporting repository
1257 1287
1258 1288 Returns 0 on success.
1259 1289 """
1260 1290 ctx = scmutil.revsingle(repo, opts.get('rev'))
1261 1291 m = scmutil.match(ctx, (file1,) + pats, opts)
1262 1292
1263 1293 return cmdutil.cat(ui, repo, ctx, m, '', **opts)
1264 1294
1265 1295 @command('^clone',
1266 1296 [('U', 'noupdate', None, _('the clone will include an empty working '
1267 1297 'directory (only a repository)')),
1268 1298 ('u', 'updaterev', '', _('revision, tag or branch to check out'), _('REV')),
1269 1299 ('r', 'rev', [], _('include the specified changeset'), _('REV')),
1270 1300 ('b', 'branch', [], _('clone only the specified branch'), _('BRANCH')),
1271 1301 ('', 'pull', None, _('use pull protocol to copy metadata')),
1272 1302 ('', 'uncompressed', None, _('use uncompressed transfer (fast over LAN)')),
1273 1303 ] + remoteopts,
1274 1304 _('[OPTION]... SOURCE [DEST]'),
1275 1305 norepo=True)
1276 1306 def clone(ui, source, dest=None, **opts):
1277 1307 """make a copy of an existing repository
1278 1308
1279 1309 Create a copy of an existing repository in a new directory.
1280 1310
1281 1311 If no destination directory name is specified, it defaults to the
1282 1312 basename of the source.
1283 1313
1284 1314 The location of the source is added to the new repository's
1285 1315 ``.hg/hgrc`` file, as the default to be used for future pulls.
1286 1316
1287 1317 Only local paths and ``ssh://`` URLs are supported as
1288 1318 destinations. For ``ssh://`` destinations, no working directory or
1289 1319 ``.hg/hgrc`` will be created on the remote side.
1290 1320
1291 1321 To pull only a subset of changesets, specify one or more revisions
1292 1322 identifiers with -r/--rev or branches with -b/--branch. The
1293 1323 resulting clone will contain only the specified changesets and
1294 1324 their ancestors. These options (or 'clone src#rev dest') imply
1295 1325 --pull, even for local source repositories. Note that specifying a
1296 1326 tag will include the tagged changeset but not the changeset
1297 1327 containing the tag.
1298 1328
1299 1329 If the source repository has a bookmark called '@' set, that
1300 1330 revision will be checked out in the new repository by default.
1301 1331
1302 1332 To check out a particular version, use -u/--update, or
1303 1333 -U/--noupdate to create a clone with no working directory.
1304 1334
1305 1335 .. container:: verbose
1306 1336
1307 1337 For efficiency, hardlinks are used for cloning whenever the
1308 1338 source and destination are on the same filesystem (note this
1309 1339 applies only to the repository data, not to the working
1310 1340 directory). Some filesystems, such as AFS, implement hardlinking
1311 1341 incorrectly, but do not report errors. In these cases, use the
1312 1342 --pull option to avoid hardlinking.
1313 1343
1314 1344 In some cases, you can clone repositories and the working
1315 1345 directory using full hardlinks with ::
1316 1346
1317 1347 $ cp -al REPO REPOCLONE
1318 1348
1319 1349 This is the fastest way to clone, but it is not always safe. The
1320 1350 operation is not atomic (making sure REPO is not modified during
1321 1351 the operation is up to you) and you have to make sure your
1322 1352 editor breaks hardlinks (Emacs and most Linux Kernel tools do
1323 1353 so). Also, this is not compatible with certain extensions that
1324 1354 place their metadata under the .hg directory, such as mq.
1325 1355
1326 1356 Mercurial will update the working directory to the first applicable
1327 1357 revision from this list:
1328 1358
1329 1359 a) null if -U or the source repository has no changesets
1330 1360 b) if -u . and the source repository is local, the first parent of
1331 1361 the source repository's working directory
1332 1362 c) the changeset specified with -u (if a branch name, this means the
1333 1363 latest head of that branch)
1334 1364 d) the changeset specified with -r
1335 1365 e) the tipmost head specified with -b
1336 1366 f) the tipmost head specified with the url#branch source syntax
1337 1367 g) the revision marked with the '@' bookmark, if present
1338 1368 h) the tipmost head of the default branch
1339 1369 i) tip
1340 1370
1341 1371 Examples:
1342 1372
1343 1373 - clone a remote repository to a new directory named hg/::
1344 1374
1345 1375 hg clone http://selenic.com/hg
1346 1376
1347 1377 - create a lightweight local clone::
1348 1378
1349 1379 hg clone project/ project-feature/
1350 1380
1351 1381 - clone from an absolute path on an ssh server (note double-slash)::
1352 1382
1353 1383 hg clone ssh://user@server//home/projects/alpha/
1354 1384
1355 1385 - do a high-speed clone over a LAN while checking out a
1356 1386 specified version::
1357 1387
1358 1388 hg clone --uncompressed http://server/repo -u 1.5
1359 1389
1360 1390 - create a repository without changesets after a particular revision::
1361 1391
1362 1392 hg clone -r 04e544 experimental/ good/
1363 1393
1364 1394 - clone (and track) a particular named branch::
1365 1395
1366 1396 hg clone http://selenic.com/hg#stable
1367 1397
1368 1398 See :hg:`help urls` for details on specifying URLs.
1369 1399
1370 1400 Returns 0 on success.
1371 1401 """
1372 1402 if opts.get('noupdate') and opts.get('updaterev'):
1373 1403 raise util.Abort(_("cannot specify both --noupdate and --updaterev"))
1374 1404
1375 1405 r = hg.clone(ui, opts, source, dest,
1376 1406 pull=opts.get('pull'),
1377 1407 stream=opts.get('uncompressed'),
1378 1408 rev=opts.get('rev'),
1379 1409 update=opts.get('updaterev') or not opts.get('noupdate'),
1380 1410 branch=opts.get('branch'))
1381 1411
1382 1412 return r is None
1383 1413
1384 1414 @command('^commit|ci',
1385 1415 [('A', 'addremove', None,
1386 1416 _('mark new/missing files as added/removed before committing')),
1387 1417 ('', 'close-branch', None,
1388 1418 _('mark a branch as closed, hiding it from the branch list')),
1389 1419 ('', 'amend', None, _('amend the parent of the working directory')),
1390 1420 ('s', 'secret', None, _('use the secret phase for committing')),
1391 1421 ('e', 'edit', None, _('invoke editor on commit messages')),
1392 1422 ('i', 'interactive', None, _('use interactive mode')),
1393 1423 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1394 1424 _('[OPTION]... [FILE]...'),
1395 1425 inferrepo=True)
1396 1426 def commit(ui, repo, *pats, **opts):
1397 1427 """commit the specified files or all outstanding changes
1398 1428
1399 1429 Commit changes to the given files into the repository. Unlike a
1400 1430 centralized SCM, this operation is a local operation. See
1401 1431 :hg:`push` for a way to actively distribute your changes.
1402 1432
1403 1433 If a list of files is omitted, all changes reported by :hg:`status`
1404 1434 will be committed.
1405 1435
1406 1436 If you are committing the result of a merge, do not provide any
1407 1437 filenames or -I/-X filters.
1408 1438
1409 1439 If no commit message is specified, Mercurial starts your
1410 1440 configured editor where you can enter a message. In case your
1411 1441 commit fails, you will find a backup of your message in
1412 1442 ``.hg/last-message.txt``.
1413 1443
1414 1444 The --amend flag can be used to amend the parent of the
1415 1445 working directory with a new commit that contains the changes
1416 1446 in the parent in addition to those currently reported by :hg:`status`,
1417 1447 if there are any. The old commit is stored in a backup bundle in
1418 1448 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1419 1449 on how to restore it).
1420 1450
1421 1451 Message, user and date are taken from the amended commit unless
1422 1452 specified. When a message isn't specified on the command line,
1423 1453 the editor will open with the message of the amended commit.
1424 1454
1425 1455 It is not possible to amend public changesets (see :hg:`help phases`)
1426 1456 or changesets that have children.
1427 1457
1428 1458 See :hg:`help dates` for a list of formats valid for -d/--date.
1429 1459
1430 1460 Returns 0 on success, 1 if nothing changed.
1431 1461 """
1432 1462 if opts.get('interactive'):
1433 1463 opts.pop('interactive')
1434 1464 cmdutil.dorecord(ui, repo, commit, 'commit', False,
1435 1465 cmdutil.recordfilter, *pats, **opts)
1436 1466 return
1437 1467
1438 1468 if opts.get('subrepos'):
1439 1469 if opts.get('amend'):
1440 1470 raise util.Abort(_('cannot amend with --subrepos'))
1441 1471 # Let --subrepos on the command line override config setting.
1442 1472 ui.setconfig('ui', 'commitsubrepos', True, 'commit')
1443 1473
1444 1474 cmdutil.checkunfinished(repo, commit=True)
1445 1475
1446 1476 branch = repo[None].branch()
1447 1477 bheads = repo.branchheads(branch)
1448 1478
1449 1479 extra = {}
1450 1480 if opts.get('close_branch'):
1451 1481 extra['close'] = 1
1452 1482
1453 1483 if not bheads:
1454 1484 raise util.Abort(_('can only close branch heads'))
1455 1485 elif opts.get('amend'):
1456 1486 if repo.parents()[0].p1().branch() != branch and \
1457 1487 repo.parents()[0].p2().branch() != branch:
1458 1488 raise util.Abort(_('can only close branch heads'))
1459 1489
1460 1490 if opts.get('amend'):
1461 1491 if ui.configbool('ui', 'commitsubrepos'):
1462 1492 raise util.Abort(_('cannot amend with ui.commitsubrepos enabled'))
1463 1493
1464 1494 old = repo['.']
1465 1495 if not old.mutable():
1466 1496 raise util.Abort(_('cannot amend public changesets'))
1467 1497 if len(repo[None].parents()) > 1:
1468 1498 raise util.Abort(_('cannot amend while merging'))
1469 1499 allowunstable = obsolete.isenabled(repo, obsolete.allowunstableopt)
1470 1500 if not allowunstable and old.children():
1471 1501 raise util.Abort(_('cannot amend changeset with children'))
1472 1502
1473 1503 # commitfunc is used only for temporary amend commit by cmdutil.amend
1474 1504 def commitfunc(ui, repo, message, match, opts):
1475 1505 return repo.commit(message,
1476 1506 opts.get('user') or old.user(),
1477 1507 opts.get('date') or old.date(),
1478 1508 match,
1479 1509 extra=extra)
1480 1510
1481 1511 current = repo._bookmarkcurrent
1482 1512 marks = old.bookmarks()
1483 1513 node = cmdutil.amend(ui, repo, commitfunc, old, extra, pats, opts)
1484 1514 if node == old.node():
1485 1515 ui.status(_("nothing changed\n"))
1486 1516 return 1
1487 1517 elif marks:
1488 1518 ui.debug('moving bookmarks %r from %s to %s\n' %
1489 1519 (marks, old.hex(), hex(node)))
1490 1520 newmarks = repo._bookmarks
1491 1521 for bm in marks:
1492 1522 newmarks[bm] = node
1493 1523 if bm == current:
1494 1524 bookmarks.setcurrent(repo, bm)
1495 1525 newmarks.write()
1496 1526 else:
1497 1527 def commitfunc(ui, repo, message, match, opts):
1498 1528 backup = ui.backupconfig('phases', 'new-commit')
1499 1529 baseui = repo.baseui
1500 1530 basebackup = baseui.backupconfig('phases', 'new-commit')
1501 1531 try:
1502 1532 if opts.get('secret'):
1503 1533 ui.setconfig('phases', 'new-commit', 'secret', 'commit')
1504 1534 # Propagate to subrepos
1505 1535 baseui.setconfig('phases', 'new-commit', 'secret', 'commit')
1506 1536
1507 1537 editform = cmdutil.mergeeditform(repo[None], 'commit.normal')
1508 1538 editor = cmdutil.getcommiteditor(editform=editform, **opts)
1509 1539 return repo.commit(message, opts.get('user'), opts.get('date'),
1510 1540 match,
1511 1541 editor=editor,
1512 1542 extra=extra)
1513 1543 finally:
1514 1544 ui.restoreconfig(backup)
1515 1545 repo.baseui.restoreconfig(basebackup)
1516 1546
1517 1547
1518 1548 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1519 1549
1520 1550 if not node:
1521 1551 stat = repo.status(match=scmutil.match(repo[None], pats, opts))
1522 1552 if stat[3]:
1523 1553 ui.status(_("nothing changed (%d missing files, see "
1524 1554 "'hg status')\n") % len(stat[3]))
1525 1555 else:
1526 1556 ui.status(_("nothing changed\n"))
1527 1557 return 1
1528 1558
1529 1559 cmdutil.commitstatus(repo, node, branch, bheads, opts)
1530 1560
1531 1561 @command('config|showconfig|debugconfig',
1532 1562 [('u', 'untrusted', None, _('show untrusted configuration options')),
1533 1563 ('e', 'edit', None, _('edit user config')),
1534 1564 ('l', 'local', None, _('edit repository config')),
1535 1565 ('g', 'global', None, _('edit global config'))],
1536 1566 _('[-u] [NAME]...'),
1537 1567 optionalrepo=True)
1538 1568 def config(ui, repo, *values, **opts):
1539 1569 """show combined config settings from all hgrc files
1540 1570
1541 1571 With no arguments, print names and values of all config items.
1542 1572
1543 1573 With one argument of the form section.name, print just the value
1544 1574 of that config item.
1545 1575
1546 1576 With multiple arguments, print names and values of all config
1547 1577 items with matching section names.
1548 1578
1549 1579 With --edit, start an editor on the user-level config file. With
1550 1580 --global, edit the system-wide config file. With --local, edit the
1551 1581 repository-level config file.
1552 1582
1553 1583 With --debug, the source (filename and line number) is printed
1554 1584 for each config item.
1555 1585
1556 1586 See :hg:`help config` for more information about config files.
1557 1587
1558 1588 Returns 0 on success, 1 if NAME does not exist.
1559 1589
1560 1590 """
1561 1591
1562 1592 if opts.get('edit') or opts.get('local') or opts.get('global'):
1563 1593 if opts.get('local') and opts.get('global'):
1564 1594 raise util.Abort(_("can't use --local and --global together"))
1565 1595
1566 1596 if opts.get('local'):
1567 1597 if not repo:
1568 1598 raise util.Abort(_("can't use --local outside a repository"))
1569 1599 paths = [repo.join('hgrc')]
1570 1600 elif opts.get('global'):
1571 1601 paths = scmutil.systemrcpath()
1572 1602 else:
1573 1603 paths = scmutil.userrcpath()
1574 1604
1575 1605 for f in paths:
1576 1606 if os.path.exists(f):
1577 1607 break
1578 1608 else:
1579 1609 if opts.get('global'):
1580 1610 samplehgrc = uimod.samplehgrcs['global']
1581 1611 elif opts.get('local'):
1582 1612 samplehgrc = uimod.samplehgrcs['local']
1583 1613 else:
1584 1614 samplehgrc = uimod.samplehgrcs['user']
1585 1615
1586 1616 f = paths[0]
1587 1617 fp = open(f, "w")
1588 1618 fp.write(samplehgrc)
1589 1619 fp.close()
1590 1620
1591 1621 editor = ui.geteditor()
1592 1622 ui.system("%s \"%s\"" % (editor, f),
1593 1623 onerr=util.Abort, errprefix=_("edit failed"))
1594 1624 return
1595 1625
1596 1626 for f in scmutil.rcpath():
1597 1627 ui.debug('read config from: %s\n' % f)
1598 1628 untrusted = bool(opts.get('untrusted'))
1599 1629 if values:
1600 1630 sections = [v for v in values if '.' not in v]
1601 1631 items = [v for v in values if '.' in v]
1602 1632 if len(items) > 1 or items and sections:
1603 1633 raise util.Abort(_('only one config item permitted'))
1604 1634 matched = False
1605 1635 for section, name, value in ui.walkconfig(untrusted=untrusted):
1606 1636 value = str(value).replace('\n', '\\n')
1607 1637 sectname = section + '.' + name
1608 1638 if values:
1609 1639 for v in values:
1610 1640 if v == section:
1611 1641 ui.debug('%s: ' %
1612 1642 ui.configsource(section, name, untrusted))
1613 1643 ui.write('%s=%s\n' % (sectname, value))
1614 1644 matched = True
1615 1645 elif v == sectname:
1616 1646 ui.debug('%s: ' %
1617 1647 ui.configsource(section, name, untrusted))
1618 1648 ui.write(value, '\n')
1619 1649 matched = True
1620 1650 else:
1621 1651 ui.debug('%s: ' %
1622 1652 ui.configsource(section, name, untrusted))
1623 1653 ui.write('%s=%s\n' % (sectname, value))
1624 1654 matched = True
1625 1655 if matched:
1626 1656 return 0
1627 1657 return 1
1628 1658
1629 1659 @command('copy|cp',
1630 1660 [('A', 'after', None, _('record a copy that has already occurred')),
1631 1661 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1632 1662 ] + walkopts + dryrunopts,
1633 1663 _('[OPTION]... [SOURCE]... DEST'))
1634 1664 def copy(ui, repo, *pats, **opts):
1635 1665 """mark files as copied for the next commit
1636 1666
1637 1667 Mark dest as having copies of source files. If dest is a
1638 1668 directory, copies are put in that directory. If dest is a file,
1639 1669 the source must be a single file.
1640 1670
1641 1671 By default, this command copies the contents of files as they
1642 1672 exist in the working directory. If invoked with -A/--after, the
1643 1673 operation is recorded, but no copying is performed.
1644 1674
1645 1675 This command takes effect with the next commit. To undo a copy
1646 1676 before that, see :hg:`revert`.
1647 1677
1648 1678 Returns 0 on success, 1 if errors are encountered.
1649 1679 """
1650 1680 wlock = repo.wlock(False)
1651 1681 try:
1652 1682 return cmdutil.copy(ui, repo, pats, opts)
1653 1683 finally:
1654 1684 wlock.release()
1655 1685
1656 1686 @command('debugancestor', [], _('[INDEX] REV1 REV2'), optionalrepo=True)
1657 1687 def debugancestor(ui, repo, *args):
1658 1688 """find the ancestor revision of two revisions in a given index"""
1659 1689 if len(args) == 3:
1660 1690 index, rev1, rev2 = args
1661 1691 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), index)
1662 1692 lookup = r.lookup
1663 1693 elif len(args) == 2:
1664 1694 if not repo:
1665 1695 raise util.Abort(_("there is no Mercurial repository here "
1666 1696 "(.hg not found)"))
1667 1697 rev1, rev2 = args
1668 1698 r = repo.changelog
1669 1699 lookup = repo.lookup
1670 1700 else:
1671 1701 raise util.Abort(_('either two or three arguments required'))
1672 1702 a = r.ancestor(lookup(rev1), lookup(rev2))
1673 1703 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
1674 1704
1675 1705 @command('debugbuilddag',
1676 1706 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
1677 1707 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
1678 1708 ('n', 'new-file', None, _('add new file at each rev'))],
1679 1709 _('[OPTION]... [TEXT]'))
1680 1710 def debugbuilddag(ui, repo, text=None,
1681 1711 mergeable_file=False,
1682 1712 overwritten_file=False,
1683 1713 new_file=False):
1684 1714 """builds a repo with a given DAG from scratch in the current empty repo
1685 1715
1686 1716 The description of the DAG is read from stdin if not given on the
1687 1717 command line.
1688 1718
1689 1719 Elements:
1690 1720
1691 1721 - "+n" is a linear run of n nodes based on the current default parent
1692 1722 - "." is a single node based on the current default parent
1693 1723 - "$" resets the default parent to null (implied at the start);
1694 1724 otherwise the default parent is always the last node created
1695 1725 - "<p" sets the default parent to the backref p
1696 1726 - "*p" is a fork at parent p, which is a backref
1697 1727 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
1698 1728 - "/p2" is a merge of the preceding node and p2
1699 1729 - ":tag" defines a local tag for the preceding node
1700 1730 - "@branch" sets the named branch for subsequent nodes
1701 1731 - "#...\\n" is a comment up to the end of the line
1702 1732
1703 1733 Whitespace between the above elements is ignored.
1704 1734
1705 1735 A backref is either
1706 1736
1707 1737 - a number n, which references the node curr-n, where curr is the current
1708 1738 node, or
1709 1739 - the name of a local tag you placed earlier using ":tag", or
1710 1740 - empty to denote the default parent.
1711 1741
1712 1742 All string valued-elements are either strictly alphanumeric, or must
1713 1743 be enclosed in double quotes ("..."), with "\\" as escape character.
1714 1744 """
1715 1745
1716 1746 if text is None:
1717 1747 ui.status(_("reading DAG from stdin\n"))
1718 1748 text = ui.fin.read()
1719 1749
1720 1750 cl = repo.changelog
1721 1751 if len(cl) > 0:
1722 1752 raise util.Abort(_('repository is not empty'))
1723 1753
1724 1754 # determine number of revs in DAG
1725 1755 total = 0
1726 1756 for type, data in dagparser.parsedag(text):
1727 1757 if type == 'n':
1728 1758 total += 1
1729 1759
1730 1760 if mergeable_file:
1731 1761 linesperrev = 2
1732 1762 # make a file with k lines per rev
1733 1763 initialmergedlines = [str(i) for i in xrange(0, total * linesperrev)]
1734 1764 initialmergedlines.append("")
1735 1765
1736 1766 tags = []
1737 1767
1738 1768 lock = tr = None
1739 1769 try:
1740 1770 lock = repo.lock()
1741 1771 tr = repo.transaction("builddag")
1742 1772
1743 1773 at = -1
1744 1774 atbranch = 'default'
1745 1775 nodeids = []
1746 1776 id = 0
1747 1777 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1748 1778 for type, data in dagparser.parsedag(text):
1749 1779 if type == 'n':
1750 1780 ui.note(('node %s\n' % str(data)))
1751 1781 id, ps = data
1752 1782
1753 1783 files = []
1754 1784 fctxs = {}
1755 1785
1756 1786 p2 = None
1757 1787 if mergeable_file:
1758 1788 fn = "mf"
1759 1789 p1 = repo[ps[0]]
1760 1790 if len(ps) > 1:
1761 1791 p2 = repo[ps[1]]
1762 1792 pa = p1.ancestor(p2)
1763 1793 base, local, other = [x[fn].data() for x in (pa, p1,
1764 1794 p2)]
1765 1795 m3 = simplemerge.Merge3Text(base, local, other)
1766 1796 ml = [l.strip() for l in m3.merge_lines()]
1767 1797 ml.append("")
1768 1798 elif at > 0:
1769 1799 ml = p1[fn].data().split("\n")
1770 1800 else:
1771 1801 ml = initialmergedlines
1772 1802 ml[id * linesperrev] += " r%i" % id
1773 1803 mergedtext = "\n".join(ml)
1774 1804 files.append(fn)
1775 1805 fctxs[fn] = context.memfilectx(repo, fn, mergedtext)
1776 1806
1777 1807 if overwritten_file:
1778 1808 fn = "of"
1779 1809 files.append(fn)
1780 1810 fctxs[fn] = context.memfilectx(repo, fn, "r%i\n" % id)
1781 1811
1782 1812 if new_file:
1783 1813 fn = "nf%i" % id
1784 1814 files.append(fn)
1785 1815 fctxs[fn] = context.memfilectx(repo, fn, "r%i\n" % id)
1786 1816 if len(ps) > 1:
1787 1817 if not p2:
1788 1818 p2 = repo[ps[1]]
1789 1819 for fn in p2:
1790 1820 if fn.startswith("nf"):
1791 1821 files.append(fn)
1792 1822 fctxs[fn] = p2[fn]
1793 1823
1794 1824 def fctxfn(repo, cx, path):
1795 1825 return fctxs.get(path)
1796 1826
1797 1827 if len(ps) == 0 or ps[0] < 0:
1798 1828 pars = [None, None]
1799 1829 elif len(ps) == 1:
1800 1830 pars = [nodeids[ps[0]], None]
1801 1831 else:
1802 1832 pars = [nodeids[p] for p in ps]
1803 1833 cx = context.memctx(repo, pars, "r%i" % id, files, fctxfn,
1804 1834 date=(id, 0),
1805 1835 user="debugbuilddag",
1806 1836 extra={'branch': atbranch})
1807 1837 nodeid = repo.commitctx(cx)
1808 1838 nodeids.append(nodeid)
1809 1839 at = id
1810 1840 elif type == 'l':
1811 1841 id, name = data
1812 1842 ui.note(('tag %s\n' % name))
1813 1843 tags.append("%s %s\n" % (hex(repo.changelog.node(id)), name))
1814 1844 elif type == 'a':
1815 1845 ui.note(('branch %s\n' % data))
1816 1846 atbranch = data
1817 1847 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1818 1848 tr.close()
1819 1849
1820 1850 if tags:
1821 1851 repo.vfs.write("localtags", "".join(tags))
1822 1852 finally:
1823 1853 ui.progress(_('building'), None)
1824 1854 release(tr, lock)
1825 1855
1826 1856 @command('debugbundle',
1827 1857 [('a', 'all', None, _('show all details'))],
1828 1858 _('FILE'),
1829 1859 norepo=True)
1830 1860 def debugbundle(ui, bundlepath, all=None, **opts):
1831 1861 """lists the contents of a bundle"""
1832 1862 f = hg.openpath(ui, bundlepath)
1833 1863 try:
1834 1864 gen = exchange.readbundle(ui, f, bundlepath)
1835 1865 if isinstance(gen, bundle2.unbundle20):
1836 1866 return _debugbundle2(ui, gen, all=all, **opts)
1837 1867 if all:
1838 1868 ui.write(("format: id, p1, p2, cset, delta base, len(delta)\n"))
1839 1869
1840 1870 def showchunks(named):
1841 1871 ui.write("\n%s\n" % named)
1842 1872 chain = None
1843 1873 while True:
1844 1874 chunkdata = gen.deltachunk(chain)
1845 1875 if not chunkdata:
1846 1876 break
1847 1877 node = chunkdata['node']
1848 1878 p1 = chunkdata['p1']
1849 1879 p2 = chunkdata['p2']
1850 1880 cs = chunkdata['cs']
1851 1881 deltabase = chunkdata['deltabase']
1852 1882 delta = chunkdata['delta']
1853 1883 ui.write("%s %s %s %s %s %s\n" %
1854 1884 (hex(node), hex(p1), hex(p2),
1855 1885 hex(cs), hex(deltabase), len(delta)))
1856 1886 chain = node
1857 1887
1858 1888 chunkdata = gen.changelogheader()
1859 1889 showchunks("changelog")
1860 1890 chunkdata = gen.manifestheader()
1861 1891 showchunks("manifest")
1862 1892 while True:
1863 1893 chunkdata = gen.filelogheader()
1864 1894 if not chunkdata:
1865 1895 break
1866 1896 fname = chunkdata['filename']
1867 1897 showchunks(fname)
1868 1898 else:
1869 1899 if isinstance(gen, bundle2.unbundle20):
1870 1900 raise util.Abort(_('use debugbundle2 for this file'))
1871 1901 chunkdata = gen.changelogheader()
1872 1902 chain = None
1873 1903 while True:
1874 1904 chunkdata = gen.deltachunk(chain)
1875 1905 if not chunkdata:
1876 1906 break
1877 1907 node = chunkdata['node']
1878 1908 ui.write("%s\n" % hex(node))
1879 1909 chain = node
1880 1910 finally:
1881 1911 f.close()
1882 1912
1883 1913 def _debugbundle2(ui, gen, **opts):
1884 1914 """lists the contents of a bundle2"""
1885 1915 if not isinstance(gen, bundle2.unbundle20):
1886 1916 raise util.Abort(_('not a bundle2 file'))
1887 1917 ui.write(('Stream params: %s\n' % repr(gen.params)))
1888 1918 for part in gen.iterparts():
1889 1919 ui.write('%s -- %r\n' % (part.type, repr(part.params)))
1890 1920 if part.type == 'b2x:changegroup':
1891 1921 version = part.params.get('version', '01')
1892 1922 cg = changegroup.packermap[version][1](part, 'UN')
1893 1923 chunkdata = cg.changelogheader()
1894 1924 chain = None
1895 1925 while True:
1896 1926 chunkdata = cg.deltachunk(chain)
1897 1927 if not chunkdata:
1898 1928 break
1899 1929 node = chunkdata['node']
1900 1930 ui.write(" %s\n" % hex(node))
1901 1931 chain = node
1902 1932
1903 1933 @command('debugcheckstate', [], '')
1904 1934 def debugcheckstate(ui, repo):
1905 1935 """validate the correctness of the current dirstate"""
1906 1936 parent1, parent2 = repo.dirstate.parents()
1907 1937 m1 = repo[parent1].manifest()
1908 1938 m2 = repo[parent2].manifest()
1909 1939 errors = 0
1910 1940 for f in repo.dirstate:
1911 1941 state = repo.dirstate[f]
1912 1942 if state in "nr" and f not in m1:
1913 1943 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
1914 1944 errors += 1
1915 1945 if state in "a" and f in m1:
1916 1946 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
1917 1947 errors += 1
1918 1948 if state in "m" and f not in m1 and f not in m2:
1919 1949 ui.warn(_("%s in state %s, but not in either manifest\n") %
1920 1950 (f, state))
1921 1951 errors += 1
1922 1952 for f in m1:
1923 1953 state = repo.dirstate[f]
1924 1954 if state not in "nrm":
1925 1955 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
1926 1956 errors += 1
1927 1957 if errors:
1928 1958 error = _(".hg/dirstate inconsistent with current parent's manifest")
1929 1959 raise util.Abort(error)
1930 1960
1931 1961 @command('debugcommands', [], _('[COMMAND]'), norepo=True)
1932 1962 def debugcommands(ui, cmd='', *args):
1933 1963 """list all available commands and options"""
1934 1964 for cmd, vals in sorted(table.iteritems()):
1935 1965 cmd = cmd.split('|')[0].strip('^')
1936 1966 opts = ', '.join([i[1] for i in vals[1]])
1937 1967 ui.write('%s: %s\n' % (cmd, opts))
1938 1968
1939 1969 @command('debugcomplete',
1940 1970 [('o', 'options', None, _('show the command options'))],
1941 1971 _('[-o] CMD'),
1942 1972 norepo=True)
1943 1973 def debugcomplete(ui, cmd='', **opts):
1944 1974 """returns the completion list associated with the given command"""
1945 1975
1946 1976 if opts.get('options'):
1947 1977 options = []
1948 1978 otables = [globalopts]
1949 1979 if cmd:
1950 1980 aliases, entry = cmdutil.findcmd(cmd, table, False)
1951 1981 otables.append(entry[1])
1952 1982 for t in otables:
1953 1983 for o in t:
1954 1984 if "(DEPRECATED)" in o[3]:
1955 1985 continue
1956 1986 if o[0]:
1957 1987 options.append('-%s' % o[0])
1958 1988 options.append('--%s' % o[1])
1959 1989 ui.write("%s\n" % "\n".join(options))
1960 1990 return
1961 1991
1962 1992 cmdlist, unused_allcmds = cmdutil.findpossible(cmd, table)
1963 1993 if ui.verbose:
1964 1994 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
1965 1995 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
1966 1996
1967 1997 @command('debugdag',
1968 1998 [('t', 'tags', None, _('use tags as labels')),
1969 1999 ('b', 'branches', None, _('annotate with branch names')),
1970 2000 ('', 'dots', None, _('use dots for runs')),
1971 2001 ('s', 'spaces', None, _('separate elements by spaces'))],
1972 2002 _('[OPTION]... [FILE [REV]...]'),
1973 2003 optionalrepo=True)
1974 2004 def debugdag(ui, repo, file_=None, *revs, **opts):
1975 2005 """format the changelog or an index DAG as a concise textual description
1976 2006
1977 2007 If you pass a revlog index, the revlog's DAG is emitted. If you list
1978 2008 revision numbers, they get labeled in the output as rN.
1979 2009
1980 2010 Otherwise, the changelog DAG of the current repo is emitted.
1981 2011 """
1982 2012 spaces = opts.get('spaces')
1983 2013 dots = opts.get('dots')
1984 2014 if file_:
1985 2015 rlog = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
1986 2016 revs = set((int(r) for r in revs))
1987 2017 def events():
1988 2018 for r in rlog:
1989 2019 yield 'n', (r, list(p for p in rlog.parentrevs(r)
1990 2020 if p != -1))
1991 2021 if r in revs:
1992 2022 yield 'l', (r, "r%i" % r)
1993 2023 elif repo:
1994 2024 cl = repo.changelog
1995 2025 tags = opts.get('tags')
1996 2026 branches = opts.get('branches')
1997 2027 if tags:
1998 2028 labels = {}
1999 2029 for l, n in repo.tags().items():
2000 2030 labels.setdefault(cl.rev(n), []).append(l)
2001 2031 def events():
2002 2032 b = "default"
2003 2033 for r in cl:
2004 2034 if branches:
2005 2035 newb = cl.read(cl.node(r))[5]['branch']
2006 2036 if newb != b:
2007 2037 yield 'a', newb
2008 2038 b = newb
2009 2039 yield 'n', (r, list(p for p in cl.parentrevs(r)
2010 2040 if p != -1))
2011 2041 if tags:
2012 2042 ls = labels.get(r)
2013 2043 if ls:
2014 2044 for l in ls:
2015 2045 yield 'l', (r, l)
2016 2046 else:
2017 2047 raise util.Abort(_('need repo for changelog dag'))
2018 2048
2019 2049 for line in dagparser.dagtextlines(events(),
2020 2050 addspaces=spaces,
2021 2051 wraplabels=True,
2022 2052 wrapannotations=True,
2023 2053 wrapnonlinear=dots,
2024 2054 usedots=dots,
2025 2055 maxlinewidth=70):
2026 2056 ui.write(line)
2027 2057 ui.write("\n")
2028 2058
2029 2059 @command('debugdata',
2030 2060 [('c', 'changelog', False, _('open changelog')),
2031 2061 ('m', 'manifest', False, _('open manifest'))],
2032 2062 _('-c|-m|FILE REV'))
2033 2063 def debugdata(ui, repo, file_, rev=None, **opts):
2034 2064 """dump the contents of a data file revision"""
2035 2065 if opts.get('changelog') or opts.get('manifest'):
2036 2066 file_, rev = None, file_
2037 2067 elif rev is None:
2038 2068 raise error.CommandError('debugdata', _('invalid arguments'))
2039 2069 r = cmdutil.openrevlog(repo, 'debugdata', file_, opts)
2040 2070 try:
2041 2071 ui.write(r.revision(r.lookup(rev)))
2042 2072 except KeyError:
2043 2073 raise util.Abort(_('invalid revision identifier %s') % rev)
2044 2074
2045 2075 @command('debugdate',
2046 2076 [('e', 'extended', None, _('try extended date formats'))],
2047 2077 _('[-e] DATE [RANGE]'),
2048 2078 norepo=True, optionalrepo=True)
2049 2079 def debugdate(ui, date, range=None, **opts):
2050 2080 """parse and display a date"""
2051 2081 if opts["extended"]:
2052 2082 d = util.parsedate(date, util.extendeddateformats)
2053 2083 else:
2054 2084 d = util.parsedate(date)
2055 2085 ui.write(("internal: %s %s\n") % d)
2056 2086 ui.write(("standard: %s\n") % util.datestr(d))
2057 2087 if range:
2058 2088 m = util.matchdate(range)
2059 2089 ui.write(("match: %s\n") % m(d[0]))
2060 2090
2061 2091 @command('debugdiscovery',
2062 2092 [('', 'old', None, _('use old-style discovery')),
2063 2093 ('', 'nonheads', None,
2064 2094 _('use old-style discovery with non-heads included')),
2065 2095 ] + remoteopts,
2066 2096 _('[-l REV] [-r REV] [-b BRANCH]... [OTHER]'))
2067 2097 def debugdiscovery(ui, repo, remoteurl="default", **opts):
2068 2098 """runs the changeset discovery protocol in isolation"""
2069 2099 remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl),
2070 2100 opts.get('branch'))
2071 2101 remote = hg.peer(repo, opts, remoteurl)
2072 2102 ui.status(_('comparing with %s\n') % util.hidepassword(remoteurl))
2073 2103
2074 2104 # make sure tests are repeatable
2075 2105 random.seed(12323)
2076 2106
2077 2107 def doit(localheads, remoteheads, remote=remote):
2078 2108 if opts.get('old'):
2079 2109 if localheads:
2080 2110 raise util.Abort('cannot use localheads with old style '
2081 2111 'discovery')
2082 2112 if not util.safehasattr(remote, 'branches'):
2083 2113 # enable in-client legacy support
2084 2114 remote = localrepo.locallegacypeer(remote.local())
2085 2115 common, _in, hds = treediscovery.findcommonincoming(repo, remote,
2086 2116 force=True)
2087 2117 common = set(common)
2088 2118 if not opts.get('nonheads'):
2089 2119 ui.write(("unpruned common: %s\n") %
2090 2120 " ".join(sorted(short(n) for n in common)))
2091 2121 dag = dagutil.revlogdag(repo.changelog)
2092 2122 all = dag.ancestorset(dag.internalizeall(common))
2093 2123 common = dag.externalizeall(dag.headsetofconnecteds(all))
2094 2124 else:
2095 2125 common, any, hds = setdiscovery.findcommonheads(ui, repo, remote)
2096 2126 common = set(common)
2097 2127 rheads = set(hds)
2098 2128 lheads = set(repo.heads())
2099 2129 ui.write(("common heads: %s\n") %
2100 2130 " ".join(sorted(short(n) for n in common)))
2101 2131 if lheads <= common:
2102 2132 ui.write(("local is subset\n"))
2103 2133 elif rheads <= common:
2104 2134 ui.write(("remote is subset\n"))
2105 2135
2106 2136 serverlogs = opts.get('serverlog')
2107 2137 if serverlogs:
2108 2138 for filename in serverlogs:
2109 2139 logfile = open(filename, 'r')
2110 2140 try:
2111 2141 line = logfile.readline()
2112 2142 while line:
2113 2143 parts = line.strip().split(';')
2114 2144 op = parts[1]
2115 2145 if op == 'cg':
2116 2146 pass
2117 2147 elif op == 'cgss':
2118 2148 doit(parts[2].split(' '), parts[3].split(' '))
2119 2149 elif op == 'unb':
2120 2150 doit(parts[3].split(' '), parts[2].split(' '))
2121 2151 line = logfile.readline()
2122 2152 finally:
2123 2153 logfile.close()
2124 2154
2125 2155 else:
2126 2156 remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches,
2127 2157 opts.get('remote_head'))
2128 2158 localrevs = opts.get('local_head')
2129 2159 doit(localrevs, remoterevs)
2130 2160
2131 2161 @command('debugfileset',
2132 2162 [('r', 'rev', '', _('apply the filespec on this revision'), _('REV'))],
2133 2163 _('[-r REV] FILESPEC'))
2134 2164 def debugfileset(ui, repo, expr, **opts):
2135 2165 '''parse and apply a fileset specification'''
2136 2166 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
2137 2167 if ui.verbose:
2138 2168 tree = fileset.parse(expr)[0]
2139 2169 ui.note(tree, "\n")
2140 2170
2141 2171 for f in ctx.getfileset(expr):
2142 2172 ui.write("%s\n" % f)
2143 2173
2144 2174 @command('debugfsinfo', [], _('[PATH]'), norepo=True)
2145 2175 def debugfsinfo(ui, path="."):
2146 2176 """show information detected about current filesystem"""
2147 2177 util.writefile('.debugfsinfo', '')
2148 2178 ui.write(('exec: %s\n') % (util.checkexec(path) and 'yes' or 'no'))
2149 2179 ui.write(('symlink: %s\n') % (util.checklink(path) and 'yes' or 'no'))
2150 2180 ui.write(('hardlink: %s\n') % (util.checknlink(path) and 'yes' or 'no'))
2151 2181 ui.write(('case-sensitive: %s\n') % (util.checkcase('.debugfsinfo')
2152 2182 and 'yes' or 'no'))
2153 2183 os.unlink('.debugfsinfo')
2154 2184
2155 2185 @command('debuggetbundle',
2156 2186 [('H', 'head', [], _('id of head node'), _('ID')),
2157 2187 ('C', 'common', [], _('id of common node'), _('ID')),
2158 2188 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE'))],
2159 2189 _('REPO FILE [-H|-C ID]...'),
2160 2190 norepo=True)
2161 2191 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
2162 2192 """retrieves a bundle from a repo
2163 2193
2164 2194 Every ID must be a full-length hex node id string. Saves the bundle to the
2165 2195 given file.
2166 2196 """
2167 2197 repo = hg.peer(ui, opts, repopath)
2168 2198 if not repo.capable('getbundle'):
2169 2199 raise util.Abort("getbundle() not supported by target repository")
2170 2200 args = {}
2171 2201 if common:
2172 2202 args['common'] = [bin(s) for s in common]
2173 2203 if head:
2174 2204 args['heads'] = [bin(s) for s in head]
2175 2205 # TODO: get desired bundlecaps from command line.
2176 2206 args['bundlecaps'] = None
2177 2207 bundle = repo.getbundle('debug', **args)
2178 2208
2179 2209 bundletype = opts.get('type', 'bzip2').lower()
2180 2210 btypes = {'none': 'HG10UN',
2181 2211 'bzip2': 'HG10BZ',
2182 2212 'gzip': 'HG10GZ',
2183 2213 'bundle2': 'HG2Y'}
2184 2214 bundletype = btypes.get(bundletype)
2185 2215 if bundletype not in changegroup.bundletypes:
2186 2216 raise util.Abort(_('unknown bundle type specified with --type'))
2187 2217 changegroup.writebundle(ui, bundle, bundlepath, bundletype)
2188 2218
2189 2219 @command('debugignore', [], '')
2190 2220 def debugignore(ui, repo, *values, **opts):
2191 2221 """display the combined ignore pattern"""
2192 2222 ignore = repo.dirstate._ignore
2193 2223 includepat = getattr(ignore, 'includepat', None)
2194 2224 if includepat is not None:
2195 2225 ui.write("%s\n" % includepat)
2196 2226 else:
2197 2227 raise util.Abort(_("no ignore patterns found"))
2198 2228
2199 2229 @command('debugindex',
2200 2230 [('c', 'changelog', False, _('open changelog')),
2201 2231 ('m', 'manifest', False, _('open manifest')),
2202 2232 ('f', 'format', 0, _('revlog format'), _('FORMAT'))],
2203 2233 _('[-f FORMAT] -c|-m|FILE'),
2204 2234 optionalrepo=True)
2205 2235 def debugindex(ui, repo, file_=None, **opts):
2206 2236 """dump the contents of an index file"""
2207 2237 r = cmdutil.openrevlog(repo, 'debugindex', file_, opts)
2208 2238 format = opts.get('format', 0)
2209 2239 if format not in (0, 1):
2210 2240 raise util.Abort(_("unknown format %d") % format)
2211 2241
2212 2242 generaldelta = r.version & revlog.REVLOGGENERALDELTA
2213 2243 if generaldelta:
2214 2244 basehdr = ' delta'
2215 2245 else:
2216 2246 basehdr = ' base'
2217 2247
2218 2248 if ui.debugflag:
2219 2249 shortfn = hex
2220 2250 else:
2221 2251 shortfn = short
2222 2252
2223 2253 # There might not be anything in r, so have a sane default
2224 2254 idlen = 12
2225 2255 for i in r:
2226 2256 idlen = len(shortfn(r.node(i)))
2227 2257 break
2228 2258
2229 2259 if format == 0:
2230 2260 ui.write(" rev offset length " + basehdr + " linkrev"
2231 2261 " %s %s p2\n" % ("nodeid".ljust(idlen), "p1".ljust(idlen)))
2232 2262 elif format == 1:
2233 2263 ui.write(" rev flag offset length"
2234 2264 " size " + basehdr + " link p1 p2"
2235 2265 " %s\n" % "nodeid".rjust(idlen))
2236 2266
2237 2267 for i in r:
2238 2268 node = r.node(i)
2239 2269 if generaldelta:
2240 2270 base = r.deltaparent(i)
2241 2271 else:
2242 2272 base = r.chainbase(i)
2243 2273 if format == 0:
2244 2274 try:
2245 2275 pp = r.parents(node)
2246 2276 except Exception:
2247 2277 pp = [nullid, nullid]
2248 2278 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
2249 2279 i, r.start(i), r.length(i), base, r.linkrev(i),
2250 2280 shortfn(node), shortfn(pp[0]), shortfn(pp[1])))
2251 2281 elif format == 1:
2252 2282 pr = r.parentrevs(i)
2253 2283 ui.write("% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d % 6d %s\n" % (
2254 2284 i, r.flags(i), r.start(i), r.length(i), r.rawsize(i),
2255 2285 base, r.linkrev(i), pr[0], pr[1], shortfn(node)))
2256 2286
2257 2287 @command('debugindexdot', [], _('FILE'), optionalrepo=True)
2258 2288 def debugindexdot(ui, repo, file_):
2259 2289 """dump an index DAG as a graphviz dot file"""
2260 2290 r = None
2261 2291 if repo:
2262 2292 filelog = repo.file(file_)
2263 2293 if len(filelog):
2264 2294 r = filelog
2265 2295 if not r:
2266 2296 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
2267 2297 ui.write(("digraph G {\n"))
2268 2298 for i in r:
2269 2299 node = r.node(i)
2270 2300 pp = r.parents(node)
2271 2301 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
2272 2302 if pp[1] != nullid:
2273 2303 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
2274 2304 ui.write("}\n")
2275 2305
2276 2306 @command('debuginstall', [], '', norepo=True)
2277 2307 def debuginstall(ui):
2278 2308 '''test Mercurial installation
2279 2309
2280 2310 Returns 0 on success.
2281 2311 '''
2282 2312
2283 2313 def writetemp(contents):
2284 2314 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
2285 2315 f = os.fdopen(fd, "wb")
2286 2316 f.write(contents)
2287 2317 f.close()
2288 2318 return name
2289 2319
2290 2320 problems = 0
2291 2321
2292 2322 # encoding
2293 2323 ui.status(_("checking encoding (%s)...\n") % encoding.encoding)
2294 2324 try:
2295 2325 encoding.fromlocal("test")
2296 2326 except util.Abort, inst:
2297 2327 ui.write(" %s\n" % inst)
2298 2328 ui.write(_(" (check that your locale is properly set)\n"))
2299 2329 problems += 1
2300 2330
2301 2331 # Python
2302 2332 ui.status(_("checking Python executable (%s)\n") % sys.executable)
2303 2333 ui.status(_("checking Python version (%s)\n")
2304 2334 % ("%s.%s.%s" % sys.version_info[:3]))
2305 2335 ui.status(_("checking Python lib (%s)...\n")
2306 2336 % os.path.dirname(os.__file__))
2307 2337
2308 2338 # compiled modules
2309 2339 ui.status(_("checking installed modules (%s)...\n")
2310 2340 % os.path.dirname(__file__))
2311 2341 try:
2312 2342 import bdiff, mpatch, base85, osutil
2313 2343 dir(bdiff), dir(mpatch), dir(base85), dir(osutil) # quiet pyflakes
2314 2344 except Exception, inst:
2315 2345 ui.write(" %s\n" % inst)
2316 2346 ui.write(_(" One or more extensions could not be found"))
2317 2347 ui.write(_(" (check that you compiled the extensions)\n"))
2318 2348 problems += 1
2319 2349
2320 2350 # templates
2321 2351 import templater
2322 2352 p = templater.templatepaths()
2323 2353 ui.status(_("checking templates (%s)...\n") % ' '.join(p))
2324 2354 if p:
2325 2355 m = templater.templatepath("map-cmdline.default")
2326 2356 if m:
2327 2357 # template found, check if it is working
2328 2358 try:
2329 2359 templater.templater(m)
2330 2360 except Exception, inst:
2331 2361 ui.write(" %s\n" % inst)
2332 2362 p = None
2333 2363 else:
2334 2364 ui.write(_(" template 'default' not found\n"))
2335 2365 p = None
2336 2366 else:
2337 2367 ui.write(_(" no template directories found\n"))
2338 2368 if not p:
2339 2369 ui.write(_(" (templates seem to have been installed incorrectly)\n"))
2340 2370 problems += 1
2341 2371
2342 2372 # editor
2343 2373 ui.status(_("checking commit editor...\n"))
2344 2374 editor = ui.geteditor()
2345 2375 cmdpath = util.findexe(shlex.split(editor)[0])
2346 2376 if not cmdpath:
2347 2377 if editor == 'vi':
2348 2378 ui.write(_(" No commit editor set and can't find vi in PATH\n"))
2349 2379 ui.write(_(" (specify a commit editor in your configuration"
2350 2380 " file)\n"))
2351 2381 else:
2352 2382 ui.write(_(" Can't find editor '%s' in PATH\n") % editor)
2353 2383 ui.write(_(" (specify a commit editor in your configuration"
2354 2384 " file)\n"))
2355 2385 problems += 1
2356 2386
2357 2387 # check username
2358 2388 ui.status(_("checking username...\n"))
2359 2389 try:
2360 2390 ui.username()
2361 2391 except util.Abort, e:
2362 2392 ui.write(" %s\n" % e)
2363 2393 ui.write(_(" (specify a username in your configuration file)\n"))
2364 2394 problems += 1
2365 2395
2366 2396 if not problems:
2367 2397 ui.status(_("no problems detected\n"))
2368 2398 else:
2369 2399 ui.write(_("%s problems detected,"
2370 2400 " please check your install!\n") % problems)
2371 2401
2372 2402 return problems
2373 2403
2374 2404 @command('debugknown', [], _('REPO ID...'), norepo=True)
2375 2405 def debugknown(ui, repopath, *ids, **opts):
2376 2406 """test whether node ids are known to a repo
2377 2407
2378 2408 Every ID must be a full-length hex node id string. Returns a list of 0s
2379 2409 and 1s indicating unknown/known.
2380 2410 """
2381 2411 repo = hg.peer(ui, opts, repopath)
2382 2412 if not repo.capable('known'):
2383 2413 raise util.Abort("known() not supported by target repository")
2384 2414 flags = repo.known([bin(s) for s in ids])
2385 2415 ui.write("%s\n" % ("".join([f and "1" or "0" for f in flags])))
2386 2416
2387 2417 @command('debuglabelcomplete', [], _('LABEL...'))
2388 2418 def debuglabelcomplete(ui, repo, *args):
2389 2419 '''backwards compatibility with old bash completion scripts (DEPRECATED)'''
2390 2420 debugnamecomplete(ui, repo, *args)
2391 2421
2392 2422 @command('debugnamecomplete', [], _('NAME...'))
2393 2423 def debugnamecomplete(ui, repo, *args):
2394 2424 '''complete "names" - tags, open branch names, bookmark names'''
2395 2425
2396 2426 names = set()
2397 2427 # since we previously only listed open branches, we will handle that
2398 2428 # specially (after this for loop)
2399 2429 for name, ns in repo.names.iteritems():
2400 2430 if name != 'branches':
2401 2431 names.update(ns.listnames(repo))
2402 2432 names.update(tag for (tag, heads, tip, closed)
2403 2433 in repo.branchmap().iterbranches() if not closed)
2404 2434 completions = set()
2405 2435 if not args:
2406 2436 args = ['']
2407 2437 for a in args:
2408 2438 completions.update(n for n in names if n.startswith(a))
2409 2439 ui.write('\n'.join(sorted(completions)))
2410 2440 ui.write('\n')
2411 2441
2412 2442 @command('debuglocks',
2413 2443 [('L', 'force-lock', None, _('free the store lock (DANGEROUS)')),
2414 2444 ('W', 'force-wlock', None,
2415 2445 _('free the working state lock (DANGEROUS)'))],
2416 2446 _('[OPTION]...'))
2417 2447 def debuglocks(ui, repo, **opts):
2418 2448 """show or modify state of locks
2419 2449
2420 2450 By default, this command will show which locks are held. This
2421 2451 includes the user and process holding the lock, the amount of time
2422 2452 the lock has been held, and the machine name where the process is
2423 2453 running if it's not local.
2424 2454
2425 2455 Locks protect the integrity of Mercurial's data, so should be
2426 2456 treated with care. System crashes or other interruptions may cause
2427 2457 locks to not be properly released, though Mercurial will usually
2428 2458 detect and remove such stale locks automatically.
2429 2459
2430 2460 However, detecting stale locks may not always be possible (for
2431 2461 instance, on a shared filesystem). Removing locks may also be
2432 2462 blocked by filesystem permissions.
2433 2463
2434 2464 Returns 0 if no locks are held.
2435 2465
2436 2466 """
2437 2467
2438 2468 if opts.get('force_lock'):
2439 2469 repo.svfs.unlink('lock')
2440 2470 if opts.get('force_wlock'):
2441 2471 repo.vfs.unlink('wlock')
2442 2472 if opts.get('force_lock') or opts.get('force_lock'):
2443 2473 return 0
2444 2474
2445 2475 now = time.time()
2446 2476 held = 0
2447 2477
2448 2478 def report(vfs, name, method):
2449 2479 # this causes stale locks to get reaped for more accurate reporting
2450 2480 try:
2451 2481 l = method(False)
2452 2482 except error.LockHeld:
2453 2483 l = None
2454 2484
2455 2485 if l:
2456 2486 l.release()
2457 2487 else:
2458 2488 try:
2459 2489 stat = repo.svfs.lstat(name)
2460 2490 age = now - stat.st_mtime
2461 2491 user = util.username(stat.st_uid)
2462 2492 locker = vfs.readlock(name)
2463 2493 if ":" in locker:
2464 2494 host, pid = locker.split(':')
2465 2495 if host == socket.gethostname():
2466 2496 locker = 'user %s, process %s' % (user, pid)
2467 2497 else:
2468 2498 locker = 'user %s, process %s, host %s' \
2469 2499 % (user, pid, host)
2470 2500 ui.write("%-6s %s (%ds)\n" % (name + ":", locker, age))
2471 2501 return 1
2472 2502 except OSError, e:
2473 2503 if e.errno != errno.ENOENT:
2474 2504 raise
2475 2505
2476 2506 ui.write("%-6s free\n" % (name + ":"))
2477 2507 return 0
2478 2508
2479 2509 held += report(repo.svfs, "lock", repo.lock)
2480 2510 held += report(repo.vfs, "wlock", repo.wlock)
2481 2511
2482 2512 return held
2483 2513
2484 2514 @command('debugobsolete',
2485 2515 [('', 'flags', 0, _('markers flag')),
2486 2516 ('', 'record-parents', False,
2487 2517 _('record parent information for the precursor')),
2488 2518 ('r', 'rev', [], _('display markers relevant to REV')),
2489 2519 ] + commitopts2,
2490 2520 _('[OBSOLETED [REPLACEMENT] [REPL... ]'))
2491 2521 def debugobsolete(ui, repo, precursor=None, *successors, **opts):
2492 2522 """create arbitrary obsolete marker
2493 2523
2494 2524 With no arguments, displays the list of obsolescence markers."""
2495 2525
2496 2526 def parsenodeid(s):
2497 2527 try:
2498 2528 # We do not use revsingle/revrange functions here to accept
2499 2529 # arbitrary node identifiers, possibly not present in the
2500 2530 # local repository.
2501 2531 n = bin(s)
2502 2532 if len(n) != len(nullid):
2503 2533 raise TypeError()
2504 2534 return n
2505 2535 except TypeError:
2506 2536 raise util.Abort('changeset references must be full hexadecimal '
2507 2537 'node identifiers')
2508 2538
2509 2539 if precursor is not None:
2510 2540 if opts['rev']:
2511 2541 raise util.Abort('cannot select revision when creating marker')
2512 2542 metadata = {}
2513 2543 metadata['user'] = opts['user'] or ui.username()
2514 2544 succs = tuple(parsenodeid(succ) for succ in successors)
2515 2545 l = repo.lock()
2516 2546 try:
2517 2547 tr = repo.transaction('debugobsolete')
2518 2548 try:
2519 2549 try:
2520 2550 date = opts.get('date')
2521 2551 if date:
2522 2552 date = util.parsedate(date)
2523 2553 else:
2524 2554 date = None
2525 2555 prec = parsenodeid(precursor)
2526 2556 parents = None
2527 2557 if opts['record_parents']:
2528 2558 if prec not in repo.unfiltered():
2529 2559 raise util.Abort('cannot used --record-parents on '
2530 2560 'unknown changesets')
2531 2561 parents = repo.unfiltered()[prec].parents()
2532 2562 parents = tuple(p.node() for p in parents)
2533 2563 repo.obsstore.create(tr, prec, succs, opts['flags'],
2534 2564 parents=parents, date=date,
2535 2565 metadata=metadata)
2536 2566 tr.close()
2537 2567 except ValueError, exc:
2538 2568 raise util.Abort(_('bad obsmarker input: %s') % exc)
2539 2569 finally:
2540 2570 tr.release()
2541 2571 finally:
2542 2572 l.release()
2543 2573 else:
2544 2574 if opts['rev']:
2545 2575 revs = scmutil.revrange(repo, opts['rev'])
2546 2576 nodes = [repo[r].node() for r in revs]
2547 2577 markers = list(obsolete.getmarkers(repo, nodes=nodes))
2548 2578 markers.sort(key=lambda x: x._data)
2549 2579 else:
2550 2580 markers = obsolete.getmarkers(repo)
2551 2581
2552 2582 for m in markers:
2553 2583 cmdutil.showmarker(ui, m)
2554 2584
2555 2585 @command('debugpathcomplete',
2556 2586 [('f', 'full', None, _('complete an entire path')),
2557 2587 ('n', 'normal', None, _('show only normal files')),
2558 2588 ('a', 'added', None, _('show only added files')),
2559 2589 ('r', 'removed', None, _('show only removed files'))],
2560 2590 _('FILESPEC...'))
2561 2591 def debugpathcomplete(ui, repo, *specs, **opts):
2562 2592 '''complete part or all of a tracked path
2563 2593
2564 2594 This command supports shells that offer path name completion. It
2565 2595 currently completes only files already known to the dirstate.
2566 2596
2567 2597 Completion extends only to the next path segment unless
2568 2598 --full is specified, in which case entire paths are used.'''
2569 2599
2570 2600 def complete(path, acceptable):
2571 2601 dirstate = repo.dirstate
2572 2602 spec = os.path.normpath(os.path.join(os.getcwd(), path))
2573 2603 rootdir = repo.root + os.sep
2574 2604 if spec != repo.root and not spec.startswith(rootdir):
2575 2605 return [], []
2576 2606 if os.path.isdir(spec):
2577 2607 spec += '/'
2578 2608 spec = spec[len(rootdir):]
2579 2609 fixpaths = os.sep != '/'
2580 2610 if fixpaths:
2581 2611 spec = spec.replace(os.sep, '/')
2582 2612 speclen = len(spec)
2583 2613 fullpaths = opts['full']
2584 2614 files, dirs = set(), set()
2585 2615 adddir, addfile = dirs.add, files.add
2586 2616 for f, st in dirstate.iteritems():
2587 2617 if f.startswith(spec) and st[0] in acceptable:
2588 2618 if fixpaths:
2589 2619 f = f.replace('/', os.sep)
2590 2620 if fullpaths:
2591 2621 addfile(f)
2592 2622 continue
2593 2623 s = f.find(os.sep, speclen)
2594 2624 if s >= 0:
2595 2625 adddir(f[:s])
2596 2626 else:
2597 2627 addfile(f)
2598 2628 return files, dirs
2599 2629
2600 2630 acceptable = ''
2601 2631 if opts['normal']:
2602 2632 acceptable += 'nm'
2603 2633 if opts['added']:
2604 2634 acceptable += 'a'
2605 2635 if opts['removed']:
2606 2636 acceptable += 'r'
2607 2637 cwd = repo.getcwd()
2608 2638 if not specs:
2609 2639 specs = ['.']
2610 2640
2611 2641 files, dirs = set(), set()
2612 2642 for spec in specs:
2613 2643 f, d = complete(spec, acceptable or 'nmar')
2614 2644 files.update(f)
2615 2645 dirs.update(d)
2616 2646 files.update(dirs)
2617 2647 ui.write('\n'.join(repo.pathto(p, cwd) for p in sorted(files)))
2618 2648 ui.write('\n')
2619 2649
2620 2650 @command('debugpushkey', [], _('REPO NAMESPACE [KEY OLD NEW]'), norepo=True)
2621 2651 def debugpushkey(ui, repopath, namespace, *keyinfo, **opts):
2622 2652 '''access the pushkey key/value protocol
2623 2653
2624 2654 With two args, list the keys in the given namespace.
2625 2655
2626 2656 With five args, set a key to new if it currently is set to old.
2627 2657 Reports success or failure.
2628 2658 '''
2629 2659
2630 2660 target = hg.peer(ui, {}, repopath)
2631 2661 if keyinfo:
2632 2662 key, old, new = keyinfo
2633 2663 r = target.pushkey(namespace, key, old, new)
2634 2664 ui.status(str(r) + '\n')
2635 2665 return not r
2636 2666 else:
2637 2667 for k, v in sorted(target.listkeys(namespace).iteritems()):
2638 2668 ui.write("%s\t%s\n" % (k.encode('string-escape'),
2639 2669 v.encode('string-escape')))
2640 2670
2641 2671 @command('debugpvec', [], _('A B'))
2642 2672 def debugpvec(ui, repo, a, b=None):
2643 2673 ca = scmutil.revsingle(repo, a)
2644 2674 cb = scmutil.revsingle(repo, b)
2645 2675 pa = pvec.ctxpvec(ca)
2646 2676 pb = pvec.ctxpvec(cb)
2647 2677 if pa == pb:
2648 2678 rel = "="
2649 2679 elif pa > pb:
2650 2680 rel = ">"
2651 2681 elif pa < pb:
2652 2682 rel = "<"
2653 2683 elif pa | pb:
2654 2684 rel = "|"
2655 2685 ui.write(_("a: %s\n") % pa)
2656 2686 ui.write(_("b: %s\n") % pb)
2657 2687 ui.write(_("depth(a): %d depth(b): %d\n") % (pa._depth, pb._depth))
2658 2688 ui.write(_("delta: %d hdist: %d distance: %d relation: %s\n") %
2659 2689 (abs(pa._depth - pb._depth), pvec._hamming(pa._vec, pb._vec),
2660 2690 pa.distance(pb), rel))
2661 2691
2662 2692 @command('debugrebuilddirstate|debugrebuildstate',
2663 2693 [('r', 'rev', '', _('revision to rebuild to'), _('REV'))],
2664 2694 _('[-r REV]'))
2665 2695 def debugrebuilddirstate(ui, repo, rev):
2666 2696 """rebuild the dirstate as it would look like for the given revision
2667 2697
2668 2698 If no revision is specified the first current parent will be used.
2669 2699
2670 2700 The dirstate will be set to the files of the given revision.
2671 2701 The actual working directory content or existing dirstate
2672 2702 information such as adds or removes is not considered.
2673 2703
2674 2704 One use of this command is to make the next :hg:`status` invocation
2675 2705 check the actual file content.
2676 2706 """
2677 2707 ctx = scmutil.revsingle(repo, rev)
2678 2708 wlock = repo.wlock()
2679 2709 try:
2680 2710 repo.dirstate.rebuild(ctx.node(), ctx.manifest())
2681 2711 finally:
2682 2712 wlock.release()
2683 2713
2684 2714 @command('debugrename',
2685 2715 [('r', 'rev', '', _('revision to debug'), _('REV'))],
2686 2716 _('[-r REV] FILE'))
2687 2717 def debugrename(ui, repo, file1, *pats, **opts):
2688 2718 """dump rename information"""
2689 2719
2690 2720 ctx = scmutil.revsingle(repo, opts.get('rev'))
2691 2721 m = scmutil.match(ctx, (file1,) + pats, opts)
2692 2722 for abs in ctx.walk(m):
2693 2723 fctx = ctx[abs]
2694 2724 o = fctx.filelog().renamed(fctx.filenode())
2695 2725 rel = m.rel(abs)
2696 2726 if o:
2697 2727 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
2698 2728 else:
2699 2729 ui.write(_("%s not renamed\n") % rel)
2700 2730
2701 2731 @command('debugrevlog',
2702 2732 [('c', 'changelog', False, _('open changelog')),
2703 2733 ('m', 'manifest', False, _('open manifest')),
2704 2734 ('d', 'dump', False, _('dump index data'))],
2705 2735 _('-c|-m|FILE'),
2706 2736 optionalrepo=True)
2707 2737 def debugrevlog(ui, repo, file_=None, **opts):
2708 2738 """show data and statistics about a revlog"""
2709 2739 r = cmdutil.openrevlog(repo, 'debugrevlog', file_, opts)
2710 2740
2711 2741 if opts.get("dump"):
2712 2742 numrevs = len(r)
2713 2743 ui.write("# rev p1rev p2rev start end deltastart base p1 p2"
2714 2744 " rawsize totalsize compression heads chainlen\n")
2715 2745 ts = 0
2716 2746 heads = set()
2717 2747
2718 2748 for rev in xrange(numrevs):
2719 2749 dbase = r.deltaparent(rev)
2720 2750 if dbase == -1:
2721 2751 dbase = rev
2722 2752 cbase = r.chainbase(rev)
2723 2753 clen = r.chainlen(rev)
2724 2754 p1, p2 = r.parentrevs(rev)
2725 2755 rs = r.rawsize(rev)
2726 2756 ts = ts + rs
2727 2757 heads -= set(r.parentrevs(rev))
2728 2758 heads.add(rev)
2729 2759 ui.write("%5d %5d %5d %5d %5d %10d %4d %4d %4d %7d %9d "
2730 2760 "%11d %5d %8d\n" %
2731 2761 (rev, p1, p2, r.start(rev), r.end(rev),
2732 2762 r.start(dbase), r.start(cbase),
2733 2763 r.start(p1), r.start(p2),
2734 2764 rs, ts, ts / r.end(rev), len(heads), clen))
2735 2765 return 0
2736 2766
2737 2767 v = r.version
2738 2768 format = v & 0xFFFF
2739 2769 flags = []
2740 2770 gdelta = False
2741 2771 if v & revlog.REVLOGNGINLINEDATA:
2742 2772 flags.append('inline')
2743 2773 if v & revlog.REVLOGGENERALDELTA:
2744 2774 gdelta = True
2745 2775 flags.append('generaldelta')
2746 2776 if not flags:
2747 2777 flags = ['(none)']
2748 2778
2749 2779 nummerges = 0
2750 2780 numfull = 0
2751 2781 numprev = 0
2752 2782 nump1 = 0
2753 2783 nump2 = 0
2754 2784 numother = 0
2755 2785 nump1prev = 0
2756 2786 nump2prev = 0
2757 2787 chainlengths = []
2758 2788
2759 2789 datasize = [None, 0, 0L]
2760 2790 fullsize = [None, 0, 0L]
2761 2791 deltasize = [None, 0, 0L]
2762 2792
2763 2793 def addsize(size, l):
2764 2794 if l[0] is None or size < l[0]:
2765 2795 l[0] = size
2766 2796 if size > l[1]:
2767 2797 l[1] = size
2768 2798 l[2] += size
2769 2799
2770 2800 numrevs = len(r)
2771 2801 for rev in xrange(numrevs):
2772 2802 p1, p2 = r.parentrevs(rev)
2773 2803 delta = r.deltaparent(rev)
2774 2804 if format > 0:
2775 2805 addsize(r.rawsize(rev), datasize)
2776 2806 if p2 != nullrev:
2777 2807 nummerges += 1
2778 2808 size = r.length(rev)
2779 2809 if delta == nullrev:
2780 2810 chainlengths.append(0)
2781 2811 numfull += 1
2782 2812 addsize(size, fullsize)
2783 2813 else:
2784 2814 chainlengths.append(chainlengths[delta] + 1)
2785 2815 addsize(size, deltasize)
2786 2816 if delta == rev - 1:
2787 2817 numprev += 1
2788 2818 if delta == p1:
2789 2819 nump1prev += 1
2790 2820 elif delta == p2:
2791 2821 nump2prev += 1
2792 2822 elif delta == p1:
2793 2823 nump1 += 1
2794 2824 elif delta == p2:
2795 2825 nump2 += 1
2796 2826 elif delta != nullrev:
2797 2827 numother += 1
2798 2828
2799 2829 # Adjust size min value for empty cases
2800 2830 for size in (datasize, fullsize, deltasize):
2801 2831 if size[0] is None:
2802 2832 size[0] = 0
2803 2833
2804 2834 numdeltas = numrevs - numfull
2805 2835 numoprev = numprev - nump1prev - nump2prev
2806 2836 totalrawsize = datasize[2]
2807 2837 datasize[2] /= numrevs
2808 2838 fulltotal = fullsize[2]
2809 2839 fullsize[2] /= numfull
2810 2840 deltatotal = deltasize[2]
2811 2841 if numrevs - numfull > 0:
2812 2842 deltasize[2] /= numrevs - numfull
2813 2843 totalsize = fulltotal + deltatotal
2814 2844 avgchainlen = sum(chainlengths) / numrevs
2815 2845 compratio = totalrawsize / totalsize
2816 2846
2817 2847 basedfmtstr = '%%%dd\n'
2818 2848 basepcfmtstr = '%%%dd %s(%%5.2f%%%%)\n'
2819 2849
2820 2850 def dfmtstr(max):
2821 2851 return basedfmtstr % len(str(max))
2822 2852 def pcfmtstr(max, padding=0):
2823 2853 return basepcfmtstr % (len(str(max)), ' ' * padding)
2824 2854
2825 2855 def pcfmt(value, total):
2826 2856 return (value, 100 * float(value) / total)
2827 2857
2828 2858 ui.write(('format : %d\n') % format)
2829 2859 ui.write(('flags : %s\n') % ', '.join(flags))
2830 2860
2831 2861 ui.write('\n')
2832 2862 fmt = pcfmtstr(totalsize)
2833 2863 fmt2 = dfmtstr(totalsize)
2834 2864 ui.write(('revisions : ') + fmt2 % numrevs)
2835 2865 ui.write((' merges : ') + fmt % pcfmt(nummerges, numrevs))
2836 2866 ui.write((' normal : ') + fmt % pcfmt(numrevs - nummerges, numrevs))
2837 2867 ui.write(('revisions : ') + fmt2 % numrevs)
2838 2868 ui.write((' full : ') + fmt % pcfmt(numfull, numrevs))
2839 2869 ui.write((' deltas : ') + fmt % pcfmt(numdeltas, numrevs))
2840 2870 ui.write(('revision size : ') + fmt2 % totalsize)
2841 2871 ui.write((' full : ') + fmt % pcfmt(fulltotal, totalsize))
2842 2872 ui.write((' deltas : ') + fmt % pcfmt(deltatotal, totalsize))
2843 2873
2844 2874 ui.write('\n')
2845 2875 fmt = dfmtstr(max(avgchainlen, compratio))
2846 2876 ui.write(('avg chain length : ') + fmt % avgchainlen)
2847 2877 ui.write(('compression ratio : ') + fmt % compratio)
2848 2878
2849 2879 if format > 0:
2850 2880 ui.write('\n')
2851 2881 ui.write(('uncompressed data size (min/max/avg) : %d / %d / %d\n')
2852 2882 % tuple(datasize))
2853 2883 ui.write(('full revision size (min/max/avg) : %d / %d / %d\n')
2854 2884 % tuple(fullsize))
2855 2885 ui.write(('delta size (min/max/avg) : %d / %d / %d\n')
2856 2886 % tuple(deltasize))
2857 2887
2858 2888 if numdeltas > 0:
2859 2889 ui.write('\n')
2860 2890 fmt = pcfmtstr(numdeltas)
2861 2891 fmt2 = pcfmtstr(numdeltas, 4)
2862 2892 ui.write(('deltas against prev : ') + fmt % pcfmt(numprev, numdeltas))
2863 2893 if numprev > 0:
2864 2894 ui.write((' where prev = p1 : ') + fmt2 % pcfmt(nump1prev,
2865 2895 numprev))
2866 2896 ui.write((' where prev = p2 : ') + fmt2 % pcfmt(nump2prev,
2867 2897 numprev))
2868 2898 ui.write((' other : ') + fmt2 % pcfmt(numoprev,
2869 2899 numprev))
2870 2900 if gdelta:
2871 2901 ui.write(('deltas against p1 : ')
2872 2902 + fmt % pcfmt(nump1, numdeltas))
2873 2903 ui.write(('deltas against p2 : ')
2874 2904 + fmt % pcfmt(nump2, numdeltas))
2875 2905 ui.write(('deltas against other : ') + fmt % pcfmt(numother,
2876 2906 numdeltas))
2877 2907
2878 2908 @command('debugrevspec',
2879 2909 [('', 'optimize', None, _('print parsed tree after optimizing'))],
2880 2910 ('REVSPEC'))
2881 2911 def debugrevspec(ui, repo, expr, **opts):
2882 2912 """parse and apply a revision specification
2883 2913
2884 2914 Use --verbose to print the parsed tree before and after aliases
2885 2915 expansion.
2886 2916 """
2887 2917 if ui.verbose:
2888 2918 tree = revset.parse(expr)[0]
2889 2919 ui.note(revset.prettyformat(tree), "\n")
2890 2920 newtree = revset.findaliases(ui, tree)
2891 2921 if newtree != tree:
2892 2922 ui.note(revset.prettyformat(newtree), "\n")
2893 2923 tree = newtree
2894 2924 newtree = revset.foldconcat(tree)
2895 2925 if newtree != tree:
2896 2926 ui.note(revset.prettyformat(newtree), "\n")
2897 2927 if opts["optimize"]:
2898 2928 weight, optimizedtree = revset.optimize(newtree, True)
2899 2929 ui.note("* optimized:\n", revset.prettyformat(optimizedtree), "\n")
2900 2930 func = revset.match(ui, expr)
2901 2931 for c in func(repo):
2902 2932 ui.write("%s\n" % c)
2903 2933
2904 2934 @command('debugsetparents', [], _('REV1 [REV2]'))
2905 2935 def debugsetparents(ui, repo, rev1, rev2=None):
2906 2936 """manually set the parents of the current working directory
2907 2937
2908 2938 This is useful for writing repository conversion tools, but should
2909 2939 be used with care. For example, neither the working directory nor the
2910 2940 dirstate is updated, so file status may be incorrect after running this
2911 2941 command.
2912 2942
2913 2943 Returns 0 on success.
2914 2944 """
2915 2945
2916 2946 r1 = scmutil.revsingle(repo, rev1).node()
2917 2947 r2 = scmutil.revsingle(repo, rev2, 'null').node()
2918 2948
2919 2949 wlock = repo.wlock()
2920 2950 try:
2921 2951 repo.dirstate.beginparentchange()
2922 2952 repo.setparents(r1, r2)
2923 2953 repo.dirstate.endparentchange()
2924 2954 finally:
2925 2955 wlock.release()
2926 2956
2927 2957 @command('debugdirstate|debugstate',
2928 2958 [('', 'nodates', None, _('do not display the saved mtime')),
2929 2959 ('', 'datesort', None, _('sort by saved mtime'))],
2930 2960 _('[OPTION]...'))
2931 2961 def debugstate(ui, repo, nodates=None, datesort=None):
2932 2962 """show the contents of the current dirstate"""
2933 2963 timestr = ""
2934 2964 if datesort:
2935 2965 keyfunc = lambda x: (x[1][3], x[0]) # sort by mtime, then by filename
2936 2966 else:
2937 2967 keyfunc = None # sort by filename
2938 2968 for file_, ent in sorted(repo.dirstate._map.iteritems(), key=keyfunc):
2939 2969 if ent[3] == -1:
2940 2970 timestr = 'unset '
2941 2971 elif nodates:
2942 2972 timestr = 'set '
2943 2973 else:
2944 2974 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
2945 2975 time.localtime(ent[3]))
2946 2976 if ent[1] & 020000:
2947 2977 mode = 'lnk'
2948 2978 else:
2949 2979 mode = '%3o' % (ent[1] & 0777 & ~util.umask)
2950 2980 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
2951 2981 for f in repo.dirstate.copies():
2952 2982 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
2953 2983
2954 2984 @command('debugsub',
2955 2985 [('r', 'rev', '',
2956 2986 _('revision to check'), _('REV'))],
2957 2987 _('[-r REV] [REV]'))
2958 2988 def debugsub(ui, repo, rev=None):
2959 2989 ctx = scmutil.revsingle(repo, rev, None)
2960 2990 for k, v in sorted(ctx.substate.items()):
2961 2991 ui.write(('path %s\n') % k)
2962 2992 ui.write((' source %s\n') % v[0])
2963 2993 ui.write((' revision %s\n') % v[1])
2964 2994
2965 2995 @command('debugsuccessorssets',
2966 2996 [],
2967 2997 _('[REV]'))
2968 2998 def debugsuccessorssets(ui, repo, *revs):
2969 2999 """show set of successors for revision
2970 3000
2971 3001 A successors set of changeset A is a consistent group of revisions that
2972 3002 succeed A. It contains non-obsolete changesets only.
2973 3003
2974 3004 In most cases a changeset A has a single successors set containing a single
2975 3005 successor (changeset A replaced by A').
2976 3006
2977 3007 A changeset that is made obsolete with no successors are called "pruned".
2978 3008 Such changesets have no successors sets at all.
2979 3009
2980 3010 A changeset that has been "split" will have a successors set containing
2981 3011 more than one successor.
2982 3012
2983 3013 A changeset that has been rewritten in multiple different ways is called
2984 3014 "divergent". Such changesets have multiple successor sets (each of which
2985 3015 may also be split, i.e. have multiple successors).
2986 3016
2987 3017 Results are displayed as follows::
2988 3018
2989 3019 <rev1>
2990 3020 <successors-1A>
2991 3021 <rev2>
2992 3022 <successors-2A>
2993 3023 <successors-2B1> <successors-2B2> <successors-2B3>
2994 3024
2995 3025 Here rev2 has two possible (i.e. divergent) successors sets. The first
2996 3026 holds one element, whereas the second holds three (i.e. the changeset has
2997 3027 been split).
2998 3028 """
2999 3029 # passed to successorssets caching computation from one call to another
3000 3030 cache = {}
3001 3031 ctx2str = str
3002 3032 node2str = short
3003 3033 if ui.debug():
3004 3034 def ctx2str(ctx):
3005 3035 return ctx.hex()
3006 3036 node2str = hex
3007 3037 for rev in scmutil.revrange(repo, revs):
3008 3038 ctx = repo[rev]
3009 3039 ui.write('%s\n'% ctx2str(ctx))
3010 3040 for succsset in obsolete.successorssets(repo, ctx.node(), cache):
3011 3041 if succsset:
3012 3042 ui.write(' ')
3013 3043 ui.write(node2str(succsset[0]))
3014 3044 for node in succsset[1:]:
3015 3045 ui.write(' ')
3016 3046 ui.write(node2str(node))
3017 3047 ui.write('\n')
3018 3048
3019 3049 @command('debugwalk', walkopts, _('[OPTION]... [FILE]...'), inferrepo=True)
3020 3050 def debugwalk(ui, repo, *pats, **opts):
3021 3051 """show how files match on given patterns"""
3022 3052 m = scmutil.match(repo[None], pats, opts)
3023 3053 items = list(repo.walk(m))
3024 3054 if not items:
3025 3055 return
3026 3056 f = lambda fn: fn
3027 3057 if ui.configbool('ui', 'slash') and os.sep != '/':
3028 3058 f = lambda fn: util.normpath(fn)
3029 3059 fmt = 'f %%-%ds %%-%ds %%s' % (
3030 3060 max([len(abs) for abs in items]),
3031 3061 max([len(m.rel(abs)) for abs in items]))
3032 3062 for abs in items:
3033 3063 line = fmt % (abs, f(m.rel(abs)), m.exact(abs) and 'exact' or '')
3034 3064 ui.write("%s\n" % line.rstrip())
3035 3065
3036 3066 @command('debugwireargs',
3037 3067 [('', 'three', '', 'three'),
3038 3068 ('', 'four', '', 'four'),
3039 3069 ('', 'five', '', 'five'),
3040 3070 ] + remoteopts,
3041 3071 _('REPO [OPTIONS]... [ONE [TWO]]'),
3042 3072 norepo=True)
3043 3073 def debugwireargs(ui, repopath, *vals, **opts):
3044 3074 repo = hg.peer(ui, opts, repopath)
3045 3075 for opt in remoteopts:
3046 3076 del opts[opt[1]]
3047 3077 args = {}
3048 3078 for k, v in opts.iteritems():
3049 3079 if v:
3050 3080 args[k] = v
3051 3081 # run twice to check that we don't mess up the stream for the next command
3052 3082 res1 = repo.debugwireargs(*vals, **args)
3053 3083 res2 = repo.debugwireargs(*vals, **args)
3054 3084 ui.write("%s\n" % res1)
3055 3085 if res1 != res2:
3056 3086 ui.warn("%s\n" % res2)
3057 3087
3058 3088 @command('^diff',
3059 3089 [('r', 'rev', [], _('revision'), _('REV')),
3060 3090 ('c', 'change', '', _('change made by revision'), _('REV'))
3061 3091 ] + diffopts + diffopts2 + walkopts + subrepoopts,
3062 3092 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'),
3063 3093 inferrepo=True)
3064 3094 def diff(ui, repo, *pats, **opts):
3065 3095 """diff repository (or selected files)
3066 3096
3067 3097 Show differences between revisions for the specified files.
3068 3098
3069 3099 Differences between files are shown using the unified diff format.
3070 3100
3071 3101 .. note::
3072 3102
3073 3103 diff may generate unexpected results for merges, as it will
3074 3104 default to comparing against the working directory's first
3075 3105 parent changeset if no revisions are specified.
3076 3106
3077 3107 When two revision arguments are given, then changes are shown
3078 3108 between those revisions. If only one revision is specified then
3079 3109 that revision is compared to the working directory, and, when no
3080 3110 revisions are specified, the working directory files are compared
3081 3111 to its parent.
3082 3112
3083 3113 Alternatively you can specify -c/--change with a revision to see
3084 3114 the changes in that changeset relative to its first parent.
3085 3115
3086 3116 Without the -a/--text option, diff will avoid generating diffs of
3087 3117 files it detects as binary. With -a, diff will generate a diff
3088 3118 anyway, probably with undesirable results.
3089 3119
3090 3120 Use the -g/--git option to generate diffs in the git extended diff
3091 3121 format. For more information, read :hg:`help diffs`.
3092 3122
3093 3123 .. container:: verbose
3094 3124
3095 3125 Examples:
3096 3126
3097 3127 - compare a file in the current working directory to its parent::
3098 3128
3099 3129 hg diff foo.c
3100 3130
3101 3131 - compare two historical versions of a directory, with rename info::
3102 3132
3103 3133 hg diff --git -r 1.0:1.2 lib/
3104 3134
3105 3135 - get change stats relative to the last change on some date::
3106 3136
3107 3137 hg diff --stat -r "date('may 2')"
3108 3138
3109 3139 - diff all newly-added files that contain a keyword::
3110 3140
3111 3141 hg diff "set:added() and grep(GNU)"
3112 3142
3113 3143 - compare a revision and its parents::
3114 3144
3115 3145 hg diff -c 9353 # compare against first parent
3116 3146 hg diff -r 9353^:9353 # same using revset syntax
3117 3147 hg diff -r 9353^2:9353 # compare against the second parent
3118 3148
3119 3149 Returns 0 on success.
3120 3150 """
3121 3151
3122 3152 revs = opts.get('rev')
3123 3153 change = opts.get('change')
3124 3154 stat = opts.get('stat')
3125 3155 reverse = opts.get('reverse')
3126 3156
3127 3157 if revs and change:
3128 3158 msg = _('cannot specify --rev and --change at the same time')
3129 3159 raise util.Abort(msg)
3130 3160 elif change:
3131 3161 node2 = scmutil.revsingle(repo, change, None).node()
3132 3162 node1 = repo[node2].p1().node()
3133 3163 else:
3134 3164 node1, node2 = scmutil.revpair(repo, revs)
3135 3165
3136 3166 if reverse:
3137 3167 node1, node2 = node2, node1
3138 3168
3139 3169 diffopts = patch.diffallopts(ui, opts)
3140 3170 m = scmutil.match(repo[node2], pats, opts)
3141 3171 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
3142 3172 listsubrepos=opts.get('subrepos'))
3143 3173
3144 3174 @command('^export',
3145 3175 [('o', 'output', '',
3146 3176 _('print output to file with formatted name'), _('FORMAT')),
3147 3177 ('', 'switch-parent', None, _('diff against the second parent')),
3148 3178 ('r', 'rev', [], _('revisions to export'), _('REV')),
3149 3179 ] + diffopts,
3150 3180 _('[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'))
3151 3181 def export(ui, repo, *changesets, **opts):
3152 3182 """dump the header and diffs for one or more changesets
3153 3183
3154 3184 Print the changeset header and diffs for one or more revisions.
3155 3185 If no revision is given, the parent of the working directory is used.
3156 3186
3157 3187 The information shown in the changeset header is: author, date,
3158 3188 branch name (if non-default), changeset hash, parent(s) and commit
3159 3189 comment.
3160 3190
3161 3191 .. note::
3162 3192
3163 3193 export may generate unexpected diff output for merge
3164 3194 changesets, as it will compare the merge changeset against its
3165 3195 first parent only.
3166 3196
3167 3197 Output may be to a file, in which case the name of the file is
3168 3198 given using a format string. The formatting rules are as follows:
3169 3199
3170 3200 :``%%``: literal "%" character
3171 3201 :``%H``: changeset hash (40 hexadecimal digits)
3172 3202 :``%N``: number of patches being generated
3173 3203 :``%R``: changeset revision number
3174 3204 :``%b``: basename of the exporting repository
3175 3205 :``%h``: short-form changeset hash (12 hexadecimal digits)
3176 3206 :``%m``: first line of the commit message (only alphanumeric characters)
3177 3207 :``%n``: zero-padded sequence number, starting at 1
3178 3208 :``%r``: zero-padded changeset revision number
3179 3209
3180 3210 Without the -a/--text option, export will avoid generating diffs
3181 3211 of files it detects as binary. With -a, export will generate a
3182 3212 diff anyway, probably with undesirable results.
3183 3213
3184 3214 Use the -g/--git option to generate diffs in the git extended diff
3185 3215 format. See :hg:`help diffs` for more information.
3186 3216
3187 3217 With the --switch-parent option, the diff will be against the
3188 3218 second parent. It can be useful to review a merge.
3189 3219
3190 3220 .. container:: verbose
3191 3221
3192 3222 Examples:
3193 3223
3194 3224 - use export and import to transplant a bugfix to the current
3195 3225 branch::
3196 3226
3197 3227 hg export -r 9353 | hg import -
3198 3228
3199 3229 - export all the changesets between two revisions to a file with
3200 3230 rename information::
3201 3231
3202 3232 hg export --git -r 123:150 > changes.txt
3203 3233
3204 3234 - split outgoing changes into a series of patches with
3205 3235 descriptive names::
3206 3236
3207 3237 hg export -r "outgoing()" -o "%n-%m.patch"
3208 3238
3209 3239 Returns 0 on success.
3210 3240 """
3211 3241 changesets += tuple(opts.get('rev', []))
3212 3242 if not changesets:
3213 3243 changesets = ['.']
3214 3244 revs = scmutil.revrange(repo, changesets)
3215 3245 if not revs:
3216 3246 raise util.Abort(_("export requires at least one changeset"))
3217 3247 if len(revs) > 1:
3218 3248 ui.note(_('exporting patches:\n'))
3219 3249 else:
3220 3250 ui.note(_('exporting patch:\n'))
3221 3251 cmdutil.export(repo, revs, template=opts.get('output'),
3222 3252 switch_parent=opts.get('switch_parent'),
3223 3253 opts=patch.diffallopts(ui, opts))
3224 3254
3225 3255 @command('files',
3226 3256 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3227 3257 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3228 3258 ] + walkopts + formatteropts + subrepoopts,
3229 3259 _('[OPTION]... [PATTERN]...'))
3230 3260 def files(ui, repo, *pats, **opts):
3231 3261 """list tracked files
3232 3262
3233 3263 Print files under Mercurial control in the working directory or
3234 3264 specified revision whose names match the given patterns (excluding
3235 3265 removed files).
3236 3266
3237 3267 If no patterns are given to match, this command prints the names
3238 3268 of all files under Mercurial control in the working directory.
3239 3269
3240 3270 .. container:: verbose
3241 3271
3242 3272 Examples:
3243 3273
3244 3274 - list all files under the current directory::
3245 3275
3246 3276 hg files .
3247 3277
3248 3278 - shows sizes and flags for current revision::
3249 3279
3250 3280 hg files -vr .
3251 3281
3252 3282 - list all files named README::
3253 3283
3254 3284 hg files -I "**/README"
3255 3285
3256 3286 - list all binary files::
3257 3287
3258 3288 hg files "set:binary()"
3259 3289
3260 3290 - find files containing a regular expression::
3261 3291
3262 3292 hg files "set:grep('bob')"
3263 3293
3264 3294 - search tracked file contents with xargs and grep::
3265 3295
3266 3296 hg files -0 | xargs -0 grep foo
3267 3297
3268 3298 See :hg:`help patterns` and :hg:`help filesets` for more information
3269 3299 on specifying file patterns.
3270 3300
3271 3301 Returns 0 if a match is found, 1 otherwise.
3272 3302
3273 3303 """
3274 3304 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
3275 3305
3276 3306 end = '\n'
3277 3307 if opts.get('print0'):
3278 3308 end = '\0'
3279 3309 fm = ui.formatter('files', opts)
3280 3310 fmt = '%s' + end
3281 3311
3282 3312 m = scmutil.match(ctx, pats, opts)
3283 3313 ret = cmdutil.files(ui, ctx, m, fm, fmt, opts.get('subrepos'))
3284 3314
3285 3315 fm.end()
3286 3316
3287 3317 return ret
3288 3318
3289 3319 @command('^forget', walkopts, _('[OPTION]... FILE...'), inferrepo=True)
3290 3320 def forget(ui, repo, *pats, **opts):
3291 3321 """forget the specified files on the next commit
3292 3322
3293 3323 Mark the specified files so they will no longer be tracked
3294 3324 after the next commit.
3295 3325
3296 3326 This only removes files from the current branch, not from the
3297 3327 entire project history, and it does not delete them from the
3298 3328 working directory.
3299 3329
3300 3330 To undo a forget before the next commit, see :hg:`add`.
3301 3331
3302 3332 .. container:: verbose
3303 3333
3304 3334 Examples:
3305 3335
3306 3336 - forget newly-added binary files::
3307 3337
3308 3338 hg forget "set:added() and binary()"
3309 3339
3310 3340 - forget files that would be excluded by .hgignore::
3311 3341
3312 3342 hg forget "set:hgignore()"
3313 3343
3314 3344 Returns 0 on success.
3315 3345 """
3316 3346
3317 3347 if not pats:
3318 3348 raise util.Abort(_('no files specified'))
3319 3349
3320 3350 m = scmutil.match(repo[None], pats, opts)
3321 3351 rejected = cmdutil.forget(ui, repo, m, prefix="", explicitonly=False)[0]
3322 3352 return rejected and 1 or 0
3323 3353
3324 3354 @command(
3325 3355 'graft',
3326 3356 [('r', 'rev', [], _('revisions to graft'), _('REV')),
3327 3357 ('c', 'continue', False, _('resume interrupted graft')),
3328 3358 ('e', 'edit', False, _('invoke editor on commit messages')),
3329 3359 ('', 'log', None, _('append graft info to log message')),
3330 3360 ('f', 'force', False, _('force graft')),
3331 3361 ('D', 'currentdate', False,
3332 3362 _('record the current date as commit date')),
3333 3363 ('U', 'currentuser', False,
3334 3364 _('record the current user as committer'), _('DATE'))]
3335 3365 + commitopts2 + mergetoolopts + dryrunopts,
3336 3366 _('[OPTION]... [-r] REV...'))
3337 3367 def graft(ui, repo, *revs, **opts):
3338 3368 '''copy changes from other branches onto the current branch
3339 3369
3340 3370 This command uses Mercurial's merge logic to copy individual
3341 3371 changes from other branches without merging branches in the
3342 3372 history graph. This is sometimes known as 'backporting' or
3343 3373 'cherry-picking'. By default, graft will copy user, date, and
3344 3374 description from the source changesets.
3345 3375
3346 3376 Changesets that are ancestors of the current revision, that have
3347 3377 already been grafted, or that are merges will be skipped.
3348 3378
3349 3379 If --log is specified, log messages will have a comment appended
3350 3380 of the form::
3351 3381
3352 3382 (grafted from CHANGESETHASH)
3353 3383
3354 3384 If --force is specified, revisions will be grafted even if they
3355 3385 are already ancestors of or have been grafted to the destination.
3356 3386 This is useful when the revisions have since been backed out.
3357 3387
3358 3388 If a graft merge results in conflicts, the graft process is
3359 3389 interrupted so that the current merge can be manually resolved.
3360 3390 Once all conflicts are addressed, the graft process can be
3361 3391 continued with the -c/--continue option.
3362 3392
3363 3393 .. note::
3364 3394
3365 3395 The -c/--continue option does not reapply earlier options, except
3366 3396 for --force.
3367 3397
3368 3398 .. container:: verbose
3369 3399
3370 3400 Examples:
3371 3401
3372 3402 - copy a single change to the stable branch and edit its description::
3373 3403
3374 3404 hg update stable
3375 3405 hg graft --edit 9393
3376 3406
3377 3407 - graft a range of changesets with one exception, updating dates::
3378 3408
3379 3409 hg graft -D "2085::2093 and not 2091"
3380 3410
3381 3411 - continue a graft after resolving conflicts::
3382 3412
3383 3413 hg graft -c
3384 3414
3385 3415 - show the source of a grafted changeset::
3386 3416
3387 3417 hg log --debug -r .
3388 3418
3389 3419 See :hg:`help revisions` and :hg:`help revsets` for more about
3390 3420 specifying revisions.
3391 3421
3392 3422 Returns 0 on successful completion.
3393 3423 '''
3394 3424
3395 3425 revs = list(revs)
3396 3426 revs.extend(opts['rev'])
3397 3427
3398 3428 if not opts.get('user') and opts.get('currentuser'):
3399 3429 opts['user'] = ui.username()
3400 3430 if not opts.get('date') and opts.get('currentdate'):
3401 3431 opts['date'] = "%d %d" % util.makedate()
3402 3432
3403 3433 editor = cmdutil.getcommiteditor(editform='graft', **opts)
3404 3434
3405 3435 cont = False
3406 3436 if opts['continue']:
3407 3437 cont = True
3408 3438 if revs:
3409 3439 raise util.Abort(_("can't specify --continue and revisions"))
3410 3440 # read in unfinished revisions
3411 3441 try:
3412 3442 nodes = repo.vfs.read('graftstate').splitlines()
3413 3443 revs = [repo[node].rev() for node in nodes]
3414 3444 except IOError, inst:
3415 3445 if inst.errno != errno.ENOENT:
3416 3446 raise
3417 3447 raise util.Abort(_("no graft state found, can't continue"))
3418 3448 else:
3419 3449 cmdutil.checkunfinished(repo)
3420 3450 cmdutil.bailifchanged(repo)
3421 3451 if not revs:
3422 3452 raise util.Abort(_('no revisions specified'))
3423 3453 revs = scmutil.revrange(repo, revs)
3424 3454
3425 3455 skipped = set()
3426 3456 # check for merges
3427 3457 for rev in repo.revs('%ld and merge()', revs):
3428 3458 ui.warn(_('skipping ungraftable merge revision %s\n') % rev)
3429 3459 skipped.add(rev)
3430 3460 revs = [r for r in revs if r not in skipped]
3431 3461 if not revs:
3432 3462 return -1
3433 3463
3434 3464 # Don't check in the --continue case, in effect retaining --force across
3435 3465 # --continues. That's because without --force, any revisions we decided to
3436 3466 # skip would have been filtered out here, so they wouldn't have made their
3437 3467 # way to the graftstate. With --force, any revisions we would have otherwise
3438 3468 # skipped would not have been filtered out, and if they hadn't been applied
3439 3469 # already, they'd have been in the graftstate.
3440 3470 if not (cont or opts.get('force')):
3441 3471 # check for ancestors of dest branch
3442 3472 crev = repo['.'].rev()
3443 3473 ancestors = repo.changelog.ancestors([crev], inclusive=True)
3444 3474 # Cannot use x.remove(y) on smart set, this has to be a list.
3445 3475 # XXX make this lazy in the future
3446 3476 revs = list(revs)
3447 3477 # don't mutate while iterating, create a copy
3448 3478 for rev in list(revs):
3449 3479 if rev in ancestors:
3450 3480 ui.warn(_('skipping ancestor revision %d:%s\n') %
3451 3481 (rev, repo[rev]))
3452 3482 # XXX remove on list is slow
3453 3483 revs.remove(rev)
3454 3484 if not revs:
3455 3485 return -1
3456 3486
3457 3487 # analyze revs for earlier grafts
3458 3488 ids = {}
3459 3489 for ctx in repo.set("%ld", revs):
3460 3490 ids[ctx.hex()] = ctx.rev()
3461 3491 n = ctx.extra().get('source')
3462 3492 if n:
3463 3493 ids[n] = ctx.rev()
3464 3494
3465 3495 # check ancestors for earlier grafts
3466 3496 ui.debug('scanning for duplicate grafts\n')
3467 3497
3468 3498 for rev in repo.changelog.findmissingrevs(revs, [crev]):
3469 3499 ctx = repo[rev]
3470 3500 n = ctx.extra().get('source')
3471 3501 if n in ids:
3472 3502 try:
3473 3503 r = repo[n].rev()
3474 3504 except error.RepoLookupError:
3475 3505 r = None
3476 3506 if r in revs:
3477 3507 ui.warn(_('skipping revision %d:%s '
3478 3508 '(already grafted to %d:%s)\n')
3479 3509 % (r, repo[r], rev, ctx))
3480 3510 revs.remove(r)
3481 3511 elif ids[n] in revs:
3482 3512 if r is None:
3483 3513 ui.warn(_('skipping already grafted revision %d:%s '
3484 3514 '(%d:%s also has unknown origin %s)\n')
3485 3515 % (ids[n], repo[ids[n]], rev, ctx, n[:12]))
3486 3516 else:
3487 3517 ui.warn(_('skipping already grafted revision %d:%s '
3488 3518 '(%d:%s also has origin %d:%s)\n')
3489 3519 % (ids[n], repo[ids[n]], rev, ctx, r, n[:12]))
3490 3520 revs.remove(ids[n])
3491 3521 elif ctx.hex() in ids:
3492 3522 r = ids[ctx.hex()]
3493 3523 ui.warn(_('skipping already grafted revision %d:%s '
3494 3524 '(was grafted from %d:%s)\n') %
3495 3525 (r, repo[r], rev, ctx))
3496 3526 revs.remove(r)
3497 3527 if not revs:
3498 3528 return -1
3499 3529
3500 3530 wlock = repo.wlock()
3501 3531 try:
3502 3532 for pos, ctx in enumerate(repo.set("%ld", revs)):
3503 3533 desc = '%d:%s "%s"' % (ctx.rev(), ctx,
3504 3534 ctx.description().split('\n', 1)[0])
3505 3535 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
3506 3536 if names:
3507 3537 desc += ' (%s)' % ' '.join(names)
3508 3538 ui.status(_('grafting %s\n') % desc)
3509 3539 if opts.get('dry_run'):
3510 3540 continue
3511 3541
3512 3542 source = ctx.extra().get('source')
3513 3543 if not source:
3514 3544 source = ctx.hex()
3515 3545 extra = {'source': source}
3516 3546 user = ctx.user()
3517 3547 if opts.get('user'):
3518 3548 user = opts['user']
3519 3549 date = ctx.date()
3520 3550 if opts.get('date'):
3521 3551 date = opts['date']
3522 3552 message = ctx.description()
3523 3553 if opts.get('log'):
3524 3554 message += '\n(grafted from %s)' % ctx.hex()
3525 3555
3526 3556 # we don't merge the first commit when continuing
3527 3557 if not cont:
3528 3558 # perform the graft merge with p1(rev) as 'ancestor'
3529 3559 try:
3530 3560 # ui.forcemerge is an internal variable, do not document
3531 3561 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
3532 3562 'graft')
3533 3563 stats = mergemod.graft(repo, ctx, ctx.p1(),
3534 3564 ['local', 'graft'])
3535 3565 finally:
3536 3566 repo.ui.setconfig('ui', 'forcemerge', '', 'graft')
3537 3567 # report any conflicts
3538 3568 if stats and stats[3] > 0:
3539 3569 # write out state for --continue
3540 3570 nodelines = [repo[rev].hex() + "\n" for rev in revs[pos:]]
3541 3571 repo.vfs.write('graftstate', ''.join(nodelines))
3542 3572 raise util.Abort(
3543 3573 _("unresolved conflicts, can't continue"),
3544 3574 hint=_('use hg resolve and hg graft --continue'))
3545 3575 else:
3546 3576 cont = False
3547 3577
3548 3578 # commit
3549 3579 node = repo.commit(text=message, user=user,
3550 3580 date=date, extra=extra, editor=editor)
3551 3581 if node is None:
3552 3582 ui.warn(
3553 3583 _('note: graft of %d:%s created no changes to commit\n') %
3554 3584 (ctx.rev(), ctx))
3555 3585 finally:
3556 3586 wlock.release()
3557 3587
3558 3588 # remove state when we complete successfully
3559 3589 if not opts.get('dry_run'):
3560 3590 util.unlinkpath(repo.join('graftstate'), ignoremissing=True)
3561 3591
3562 3592 return 0
3563 3593
3564 3594 @command('grep',
3565 3595 [('0', 'print0', None, _('end fields with NUL')),
3566 3596 ('', 'all', None, _('print all revisions that match')),
3567 3597 ('a', 'text', None, _('treat all files as text')),
3568 3598 ('f', 'follow', None,
3569 3599 _('follow changeset history,'
3570 3600 ' or file history across copies and renames')),
3571 3601 ('i', 'ignore-case', None, _('ignore case when matching')),
3572 3602 ('l', 'files-with-matches', None,
3573 3603 _('print only filenames and revisions that match')),
3574 3604 ('n', 'line-number', None, _('print matching line numbers')),
3575 3605 ('r', 'rev', [],
3576 3606 _('only search files changed within revision range'), _('REV')),
3577 3607 ('u', 'user', None, _('list the author (long with -v)')),
3578 3608 ('d', 'date', None, _('list the date (short with -q)')),
3579 3609 ] + walkopts,
3580 3610 _('[OPTION]... PATTERN [FILE]...'),
3581 3611 inferrepo=True)
3582 3612 def grep(ui, repo, pattern, *pats, **opts):
3583 3613 """search for a pattern in specified files and revisions
3584 3614
3585 3615 Search revisions of files for a regular expression.
3586 3616
3587 3617 This command behaves differently than Unix grep. It only accepts
3588 3618 Python/Perl regexps. It searches repository history, not the
3589 3619 working directory. It always prints the revision number in which a
3590 3620 match appears.
3591 3621
3592 3622 By default, grep only prints output for the first revision of a
3593 3623 file in which it finds a match. To get it to print every revision
3594 3624 that contains a change in match status ("-" for a match that
3595 3625 becomes a non-match, or "+" for a non-match that becomes a match),
3596 3626 use the --all flag.
3597 3627
3598 3628 Returns 0 if a match is found, 1 otherwise.
3599 3629 """
3600 3630 reflags = re.M
3601 3631 if opts.get('ignore_case'):
3602 3632 reflags |= re.I
3603 3633 try:
3604 3634 regexp = util.re.compile(pattern, reflags)
3605 3635 except re.error, inst:
3606 3636 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
3607 3637 return 1
3608 3638 sep, eol = ':', '\n'
3609 3639 if opts.get('print0'):
3610 3640 sep = eol = '\0'
3611 3641
3612 3642 getfile = util.lrucachefunc(repo.file)
3613 3643
3614 3644 def matchlines(body):
3615 3645 begin = 0
3616 3646 linenum = 0
3617 3647 while begin < len(body):
3618 3648 match = regexp.search(body, begin)
3619 3649 if not match:
3620 3650 break
3621 3651 mstart, mend = match.span()
3622 3652 linenum += body.count('\n', begin, mstart) + 1
3623 3653 lstart = body.rfind('\n', begin, mstart) + 1 or begin
3624 3654 begin = body.find('\n', mend) + 1 or len(body) + 1
3625 3655 lend = begin - 1
3626 3656 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
3627 3657
3628 3658 class linestate(object):
3629 3659 def __init__(self, line, linenum, colstart, colend):
3630 3660 self.line = line
3631 3661 self.linenum = linenum
3632 3662 self.colstart = colstart
3633 3663 self.colend = colend
3634 3664
3635 3665 def __hash__(self):
3636 3666 return hash((self.linenum, self.line))
3637 3667
3638 3668 def __eq__(self, other):
3639 3669 return self.line == other.line
3640 3670
3641 3671 def __iter__(self):
3642 3672 yield (self.line[:self.colstart], '')
3643 3673 yield (self.line[self.colstart:self.colend], 'grep.match')
3644 3674 rest = self.line[self.colend:]
3645 3675 while rest != '':
3646 3676 match = regexp.search(rest)
3647 3677 if not match:
3648 3678 yield (rest, '')
3649 3679 break
3650 3680 mstart, mend = match.span()
3651 3681 yield (rest[:mstart], '')
3652 3682 yield (rest[mstart:mend], 'grep.match')
3653 3683 rest = rest[mend:]
3654 3684
3655 3685 matches = {}
3656 3686 copies = {}
3657 3687 def grepbody(fn, rev, body):
3658 3688 matches[rev].setdefault(fn, [])
3659 3689 m = matches[rev][fn]
3660 3690 for lnum, cstart, cend, line in matchlines(body):
3661 3691 s = linestate(line, lnum, cstart, cend)
3662 3692 m.append(s)
3663 3693
3664 3694 def difflinestates(a, b):
3665 3695 sm = difflib.SequenceMatcher(None, a, b)
3666 3696 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
3667 3697 if tag == 'insert':
3668 3698 for i in xrange(blo, bhi):
3669 3699 yield ('+', b[i])
3670 3700 elif tag == 'delete':
3671 3701 for i in xrange(alo, ahi):
3672 3702 yield ('-', a[i])
3673 3703 elif tag == 'replace':
3674 3704 for i in xrange(alo, ahi):
3675 3705 yield ('-', a[i])
3676 3706 for i in xrange(blo, bhi):
3677 3707 yield ('+', b[i])
3678 3708
3679 3709 def display(fn, ctx, pstates, states):
3680 3710 rev = ctx.rev()
3681 3711 if ui.quiet:
3682 3712 datefunc = util.shortdate
3683 3713 else:
3684 3714 datefunc = util.datestr
3685 3715 found = False
3686 3716 @util.cachefunc
3687 3717 def binary():
3688 3718 flog = getfile(fn)
3689 3719 return util.binary(flog.read(ctx.filenode(fn)))
3690 3720
3691 3721 if opts.get('all'):
3692 3722 iter = difflinestates(pstates, states)
3693 3723 else:
3694 3724 iter = [('', l) for l in states]
3695 3725 for change, l in iter:
3696 3726 cols = [(fn, 'grep.filename'), (str(rev), 'grep.rev')]
3697 3727
3698 3728 if opts.get('line_number'):
3699 3729 cols.append((str(l.linenum), 'grep.linenumber'))
3700 3730 if opts.get('all'):
3701 3731 cols.append((change, 'grep.change'))
3702 3732 if opts.get('user'):
3703 3733 cols.append((ui.shortuser(ctx.user()), 'grep.user'))
3704 3734 if opts.get('date'):
3705 3735 cols.append((datefunc(ctx.date()), 'grep.date'))
3706 3736 for col, label in cols[:-1]:
3707 3737 ui.write(col, label=label)
3708 3738 ui.write(sep, label='grep.sep')
3709 3739 ui.write(cols[-1][0], label=cols[-1][1])
3710 3740 if not opts.get('files_with_matches'):
3711 3741 ui.write(sep, label='grep.sep')
3712 3742 if not opts.get('text') and binary():
3713 3743 ui.write(" Binary file matches")
3714 3744 else:
3715 3745 for s, label in l:
3716 3746 ui.write(s, label=label)
3717 3747 ui.write(eol)
3718 3748 found = True
3719 3749 if opts.get('files_with_matches'):
3720 3750 break
3721 3751 return found
3722 3752
3723 3753 skip = {}
3724 3754 revfiles = {}
3725 3755 matchfn = scmutil.match(repo[None], pats, opts)
3726 3756 found = False
3727 3757 follow = opts.get('follow')
3728 3758
3729 3759 def prep(ctx, fns):
3730 3760 rev = ctx.rev()
3731 3761 pctx = ctx.p1()
3732 3762 parent = pctx.rev()
3733 3763 matches.setdefault(rev, {})
3734 3764 matches.setdefault(parent, {})
3735 3765 files = revfiles.setdefault(rev, [])
3736 3766 for fn in fns:
3737 3767 flog = getfile(fn)
3738 3768 try:
3739 3769 fnode = ctx.filenode(fn)
3740 3770 except error.LookupError:
3741 3771 continue
3742 3772
3743 3773 copied = flog.renamed(fnode)
3744 3774 copy = follow and copied and copied[0]
3745 3775 if copy:
3746 3776 copies.setdefault(rev, {})[fn] = copy
3747 3777 if fn in skip:
3748 3778 if copy:
3749 3779 skip[copy] = True
3750 3780 continue
3751 3781 files.append(fn)
3752 3782
3753 3783 if fn not in matches[rev]:
3754 3784 grepbody(fn, rev, flog.read(fnode))
3755 3785
3756 3786 pfn = copy or fn
3757 3787 if pfn not in matches[parent]:
3758 3788 try:
3759 3789 fnode = pctx.filenode(pfn)
3760 3790 grepbody(pfn, parent, flog.read(fnode))
3761 3791 except error.LookupError:
3762 3792 pass
3763 3793
3764 3794 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
3765 3795 rev = ctx.rev()
3766 3796 parent = ctx.p1().rev()
3767 3797 for fn in sorted(revfiles.get(rev, [])):
3768 3798 states = matches[rev][fn]
3769 3799 copy = copies.get(rev, {}).get(fn)
3770 3800 if fn in skip:
3771 3801 if copy:
3772 3802 skip[copy] = True
3773 3803 continue
3774 3804 pstates = matches.get(parent, {}).get(copy or fn, [])
3775 3805 if pstates or states:
3776 3806 r = display(fn, ctx, pstates, states)
3777 3807 found = found or r
3778 3808 if r and not opts.get('all'):
3779 3809 skip[fn] = True
3780 3810 if copy:
3781 3811 skip[copy] = True
3782 3812 del matches[rev]
3783 3813 del revfiles[rev]
3784 3814
3785 3815 return not found
3786 3816
3787 3817 @command('heads',
3788 3818 [('r', 'rev', '',
3789 3819 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
3790 3820 ('t', 'topo', False, _('show topological heads only')),
3791 3821 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
3792 3822 ('c', 'closed', False, _('show normal and closed branch heads')),
3793 3823 ] + templateopts,
3794 3824 _('[-ct] [-r STARTREV] [REV]...'))
3795 3825 def heads(ui, repo, *branchrevs, **opts):
3796 3826 """show branch heads
3797 3827
3798 3828 With no arguments, show all open branch heads in the repository.
3799 3829 Branch heads are changesets that have no descendants on the
3800 3830 same branch. They are where development generally takes place and
3801 3831 are the usual targets for update and merge operations.
3802 3832
3803 3833 If one or more REVs are given, only open branch heads on the
3804 3834 branches associated with the specified changesets are shown. This
3805 3835 means that you can use :hg:`heads .` to see the heads on the
3806 3836 currently checked-out branch.
3807 3837
3808 3838 If -c/--closed is specified, also show branch heads marked closed
3809 3839 (see :hg:`commit --close-branch`).
3810 3840
3811 3841 If STARTREV is specified, only those heads that are descendants of
3812 3842 STARTREV will be displayed.
3813 3843
3814 3844 If -t/--topo is specified, named branch mechanics will be ignored and only
3815 3845 topological heads (changesets with no children) will be shown.
3816 3846
3817 3847 Returns 0 if matching heads are found, 1 if not.
3818 3848 """
3819 3849
3820 3850 start = None
3821 3851 if 'rev' in opts:
3822 3852 start = scmutil.revsingle(repo, opts['rev'], None).node()
3823 3853
3824 3854 if opts.get('topo'):
3825 3855 heads = [repo[h] for h in repo.heads(start)]
3826 3856 else:
3827 3857 heads = []
3828 3858 for branch in repo.branchmap():
3829 3859 heads += repo.branchheads(branch, start, opts.get('closed'))
3830 3860 heads = [repo[h] for h in heads]
3831 3861
3832 3862 if branchrevs:
3833 3863 branches = set(repo[br].branch() for br in branchrevs)
3834 3864 heads = [h for h in heads if h.branch() in branches]
3835 3865
3836 3866 if opts.get('active') and branchrevs:
3837 3867 dagheads = repo.heads(start)
3838 3868 heads = [h for h in heads if h.node() in dagheads]
3839 3869
3840 3870 if branchrevs:
3841 3871 haveheads = set(h.branch() for h in heads)
3842 3872 if branches - haveheads:
3843 3873 headless = ', '.join(b for b in branches - haveheads)
3844 3874 msg = _('no open branch heads found on branches %s')
3845 3875 if opts.get('rev'):
3846 3876 msg += _(' (started at %s)') % opts['rev']
3847 3877 ui.warn((msg + '\n') % headless)
3848 3878
3849 3879 if not heads:
3850 3880 return 1
3851 3881
3852 3882 heads = sorted(heads, key=lambda x: -x.rev())
3853 3883 displayer = cmdutil.show_changeset(ui, repo, opts)
3854 3884 for ctx in heads:
3855 3885 displayer.show(ctx)
3856 3886 displayer.close()
3857 3887
3858 3888 @command('help',
3859 3889 [('e', 'extension', None, _('show only help for extensions')),
3860 3890 ('c', 'command', None, _('show only help for commands')),
3861 3891 ('k', 'keyword', '', _('show topics matching keyword')),
3862 3892 ],
3863 3893 _('[-ec] [TOPIC]'),
3864 3894 norepo=True)
3865 3895 def help_(ui, name=None, **opts):
3866 3896 """show help for a given topic or a help overview
3867 3897
3868 3898 With no arguments, print a list of commands with short help messages.
3869 3899
3870 3900 Given a topic, extension, or command name, print help for that
3871 3901 topic.
3872 3902
3873 3903 Returns 0 if successful.
3874 3904 """
3875 3905
3876 3906 textwidth = min(ui.termwidth(), 80) - 2
3877 3907
3878 3908 keep = []
3879 3909 if ui.verbose:
3880 3910 keep.append('verbose')
3881 3911 if sys.platform.startswith('win'):
3882 3912 keep.append('windows')
3883 3913 elif sys.platform == 'OpenVMS':
3884 3914 keep.append('vms')
3885 3915 elif sys.platform == 'plan9':
3886 3916 keep.append('plan9')
3887 3917 else:
3888 3918 keep.append('unix')
3889 3919 keep.append(sys.platform.lower())
3890 3920
3891 3921 section = None
3892 3922 if name and '.' in name:
3893 3923 name, section = name.split('.', 1)
3894 3924
3895 3925 text = help.help_(ui, name, **opts)
3896 3926
3897 3927 formatted, pruned = minirst.format(text, textwidth, keep=keep,
3898 3928 section=section)
3899 3929 if section and not formatted:
3900 3930 raise util.Abort(_("help section not found"))
3901 3931
3902 3932 if 'verbose' in pruned:
3903 3933 keep.append('omitted')
3904 3934 else:
3905 3935 keep.append('notomitted')
3906 3936 formatted, pruned = minirst.format(text, textwidth, keep=keep,
3907 3937 section=section)
3908 3938 ui.write(formatted)
3909 3939
3910 3940
3911 3941 @command('identify|id',
3912 3942 [('r', 'rev', '',
3913 3943 _('identify the specified revision'), _('REV')),
3914 3944 ('n', 'num', None, _('show local revision number')),
3915 3945 ('i', 'id', None, _('show global revision id')),
3916 3946 ('b', 'branch', None, _('show branch')),
3917 3947 ('t', 'tags', None, _('show tags')),
3918 3948 ('B', 'bookmarks', None, _('show bookmarks')),
3919 3949 ] + remoteopts,
3920 3950 _('[-nibtB] [-r REV] [SOURCE]'),
3921 3951 optionalrepo=True)
3922 3952 def identify(ui, repo, source=None, rev=None,
3923 3953 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
3924 3954 """identify the working directory or specified revision
3925 3955
3926 3956 Print a summary identifying the repository state at REV using one or
3927 3957 two parent hash identifiers, followed by a "+" if the working
3928 3958 directory has uncommitted changes, the branch name (if not default),
3929 3959 a list of tags, and a list of bookmarks.
3930 3960
3931 3961 When REV is not given, print a summary of the current state of the
3932 3962 repository.
3933 3963
3934 3964 Specifying a path to a repository root or Mercurial bundle will
3935 3965 cause lookup to operate on that repository/bundle.
3936 3966
3937 3967 .. container:: verbose
3938 3968
3939 3969 Examples:
3940 3970
3941 3971 - generate a build identifier for the working directory::
3942 3972
3943 3973 hg id --id > build-id.dat
3944 3974
3945 3975 - find the revision corresponding to a tag::
3946 3976
3947 3977 hg id -n -r 1.3
3948 3978
3949 3979 - check the most recent revision of a remote repository::
3950 3980
3951 3981 hg id -r tip http://selenic.com/hg/
3952 3982
3953 3983 Returns 0 if successful.
3954 3984 """
3955 3985
3956 3986 if not repo and not source:
3957 3987 raise util.Abort(_("there is no Mercurial repository here "
3958 3988 "(.hg not found)"))
3959 3989
3960 3990 if ui.debugflag:
3961 3991 hexfunc = hex
3962 3992 else:
3963 3993 hexfunc = short
3964 3994 default = not (num or id or branch or tags or bookmarks)
3965 3995 output = []
3966 3996 revs = []
3967 3997
3968 3998 if source:
3969 3999 source, branches = hg.parseurl(ui.expandpath(source))
3970 4000 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
3971 4001 repo = peer.local()
3972 4002 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
3973 4003
3974 4004 if not repo:
3975 4005 if num or branch or tags:
3976 4006 raise util.Abort(
3977 4007 _("can't query remote revision number, branch, or tags"))
3978 4008 if not rev and revs:
3979 4009 rev = revs[0]
3980 4010 if not rev:
3981 4011 rev = "tip"
3982 4012
3983 4013 remoterev = peer.lookup(rev)
3984 4014 if default or id:
3985 4015 output = [hexfunc(remoterev)]
3986 4016
3987 4017 def getbms():
3988 4018 bms = []
3989 4019
3990 4020 if 'bookmarks' in peer.listkeys('namespaces'):
3991 4021 hexremoterev = hex(remoterev)
3992 4022 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
3993 4023 if bmr == hexremoterev]
3994 4024
3995 4025 return sorted(bms)
3996 4026
3997 4027 if bookmarks:
3998 4028 output.extend(getbms())
3999 4029 elif default and not ui.quiet:
4000 4030 # multiple bookmarks for a single parent separated by '/'
4001 4031 bm = '/'.join(getbms())
4002 4032 if bm:
4003 4033 output.append(bm)
4004 4034 else:
4005 4035 if not rev:
4006 4036 ctx = repo[None]
4007 4037 parents = ctx.parents()
4008 4038 changed = ""
4009 4039 if default or id or num:
4010 4040 if (util.any(repo.status())
4011 4041 or util.any(ctx.sub(s).dirty() for s in ctx.substate)):
4012 4042 changed = '+'
4013 4043 if default or id:
4014 4044 output = ["%s%s" %
4015 4045 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
4016 4046 if num:
4017 4047 output.append("%s%s" %
4018 4048 ('+'.join([str(p.rev()) for p in parents]), changed))
4019 4049 else:
4020 4050 ctx = scmutil.revsingle(repo, rev)
4021 4051 if default or id:
4022 4052 output = [hexfunc(ctx.node())]
4023 4053 if num:
4024 4054 output.append(str(ctx.rev()))
4025 4055
4026 4056 if default and not ui.quiet:
4027 4057 b = ctx.branch()
4028 4058 if b != 'default':
4029 4059 output.append("(%s)" % b)
4030 4060
4031 4061 # multiple tags for a single parent separated by '/'
4032 4062 t = '/'.join(ctx.tags())
4033 4063 if t:
4034 4064 output.append(t)
4035 4065
4036 4066 # multiple bookmarks for a single parent separated by '/'
4037 4067 bm = '/'.join(ctx.bookmarks())
4038 4068 if bm:
4039 4069 output.append(bm)
4040 4070 else:
4041 4071 if branch:
4042 4072 output.append(ctx.branch())
4043 4073
4044 4074 if tags:
4045 4075 output.extend(ctx.tags())
4046 4076
4047 4077 if bookmarks:
4048 4078 output.extend(ctx.bookmarks())
4049 4079
4050 4080 ui.write("%s\n" % ' '.join(output))
4051 4081
4052 4082 @command('import|patch',
4053 4083 [('p', 'strip', 1,
4054 4084 _('directory strip option for patch. This has the same '
4055 4085 'meaning as the corresponding patch option'), _('NUM')),
4056 4086 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
4057 4087 ('e', 'edit', False, _('invoke editor on commit messages')),
4058 4088 ('f', 'force', None,
4059 4089 _('skip check for outstanding uncommitted changes (DEPRECATED)')),
4060 4090 ('', 'no-commit', None,
4061 4091 _("don't commit, just update the working directory")),
4062 4092 ('', 'bypass', None,
4063 4093 _("apply patch without touching the working directory")),
4064 4094 ('', 'partial', None,
4065 4095 _('commit even if some hunks fail')),
4066 4096 ('', 'exact', None,
4067 4097 _('apply patch to the nodes from which it was generated')),
4068 4098 ('', 'prefix', '',
4069 4099 _('apply patch to subdirectory'), _('DIR')),
4070 4100 ('', 'import-branch', None,
4071 4101 _('use any branch information in patch (implied by --exact)'))] +
4072 4102 commitopts + commitopts2 + similarityopts,
4073 4103 _('[OPTION]... PATCH...'))
4074 4104 def import_(ui, repo, patch1=None, *patches, **opts):
4075 4105 """import an ordered set of patches
4076 4106
4077 4107 Import a list of patches and commit them individually (unless
4078 4108 --no-commit is specified).
4079 4109
4080 4110 Because import first applies changes to the working directory,
4081 4111 import will abort if there are outstanding changes.
4082 4112
4083 4113 You can import a patch straight from a mail message. Even patches
4084 4114 as attachments work (to use the body part, it must have type
4085 4115 text/plain or text/x-patch). From and Subject headers of email
4086 4116 message are used as default committer and commit message. All
4087 4117 text/plain body parts before first diff are added to commit
4088 4118 message.
4089 4119
4090 4120 If the imported patch was generated by :hg:`export`, user and
4091 4121 description from patch override values from message headers and
4092 4122 body. Values given on command line with -m/--message and -u/--user
4093 4123 override these.
4094 4124
4095 4125 If --exact is specified, import will set the working directory to
4096 4126 the parent of each patch before applying it, and will abort if the
4097 4127 resulting changeset has a different ID than the one recorded in
4098 4128 the patch. This may happen due to character set problems or other
4099 4129 deficiencies in the text patch format.
4100 4130
4101 4131 Use --bypass to apply and commit patches directly to the
4102 4132 repository, not touching the working directory. Without --exact,
4103 4133 patches will be applied on top of the working directory parent
4104 4134 revision.
4105 4135
4106 4136 With -s/--similarity, hg will attempt to discover renames and
4107 4137 copies in the patch in the same way as :hg:`addremove`.
4108 4138
4109 4139 Use --partial to ensure a changeset will be created from the patch
4110 4140 even if some hunks fail to apply. Hunks that fail to apply will be
4111 4141 written to a <target-file>.rej file. Conflicts can then be resolved
4112 4142 by hand before :hg:`commit --amend` is run to update the created
4113 4143 changeset. This flag exists to let people import patches that
4114 4144 partially apply without losing the associated metadata (author,
4115 4145 date, description, ...). Note that when none of the hunk applies
4116 4146 cleanly, :hg:`import --partial` will create an empty changeset,
4117 4147 importing only the patch metadata.
4118 4148
4119 4149 To read a patch from standard input, use "-" as the patch name. If
4120 4150 a URL is specified, the patch will be downloaded from it.
4121 4151 See :hg:`help dates` for a list of formats valid for -d/--date.
4122 4152
4123 4153 .. container:: verbose
4124 4154
4125 4155 Examples:
4126 4156
4127 4157 - import a traditional patch from a website and detect renames::
4128 4158
4129 4159 hg import -s 80 http://example.com/bugfix.patch
4130 4160
4131 4161 - import a changeset from an hgweb server::
4132 4162
4133 4163 hg import http://www.selenic.com/hg/rev/5ca8c111e9aa
4134 4164
4135 4165 - import all the patches in an Unix-style mbox::
4136 4166
4137 4167 hg import incoming-patches.mbox
4138 4168
4139 4169 - attempt to exactly restore an exported changeset (not always
4140 4170 possible)::
4141 4171
4142 4172 hg import --exact proposed-fix.patch
4143 4173
4144 4174 Returns 0 on success, 1 on partial success (see --partial).
4145 4175 """
4146 4176
4147 4177 if not patch1:
4148 4178 raise util.Abort(_('need at least one patch to import'))
4149 4179
4150 4180 patches = (patch1,) + patches
4151 4181
4152 4182 date = opts.get('date')
4153 4183 if date:
4154 4184 opts['date'] = util.parsedate(date)
4155 4185
4156 4186 update = not opts.get('bypass')
4157 4187 if not update and opts.get('no_commit'):
4158 4188 raise util.Abort(_('cannot use --no-commit with --bypass'))
4159 4189 try:
4160 4190 sim = float(opts.get('similarity') or 0)
4161 4191 except ValueError:
4162 4192 raise util.Abort(_('similarity must be a number'))
4163 4193 if sim < 0 or sim > 100:
4164 4194 raise util.Abort(_('similarity must be between 0 and 100'))
4165 4195 if sim and not update:
4166 4196 raise util.Abort(_('cannot use --similarity with --bypass'))
4167 4197 if opts.get('exact') and opts.get('edit'):
4168 4198 raise util.Abort(_('cannot use --exact with --edit'))
4169 4199 if opts.get('exact') and opts.get('prefix'):
4170 4200 raise util.Abort(_('cannot use --exact with --prefix'))
4171 4201
4172 4202 if update:
4173 4203 cmdutil.checkunfinished(repo)
4174 4204 if (opts.get('exact') or not opts.get('force')) and update:
4175 4205 cmdutil.bailifchanged(repo)
4176 4206
4177 4207 base = opts["base"]
4178 4208 wlock = lock = tr = None
4179 4209 msgs = []
4180 4210 ret = 0
4181 4211
4182 4212
4183 4213 try:
4184 4214 try:
4185 4215 wlock = repo.wlock()
4186 4216 repo.dirstate.beginparentchange()
4187 4217 if not opts.get('no_commit'):
4188 4218 lock = repo.lock()
4189 4219 tr = repo.transaction('import')
4190 4220 parents = repo.parents()
4191 4221 for patchurl in patches:
4192 4222 if patchurl == '-':
4193 4223 ui.status(_('applying patch from stdin\n'))
4194 4224 patchfile = ui.fin
4195 4225 patchurl = 'stdin' # for error message
4196 4226 else:
4197 4227 patchurl = os.path.join(base, patchurl)
4198 4228 ui.status(_('applying %s\n') % patchurl)
4199 4229 patchfile = hg.openpath(ui, patchurl)
4200 4230
4201 4231 haspatch = False
4202 4232 for hunk in patch.split(patchfile):
4203 4233 (msg, node, rej) = cmdutil.tryimportone(ui, repo, hunk,
4204 4234 parents, opts,
4205 4235 msgs, hg.clean)
4206 4236 if msg:
4207 4237 haspatch = True
4208 4238 ui.note(msg + '\n')
4209 4239 if update or opts.get('exact'):
4210 4240 parents = repo.parents()
4211 4241 else:
4212 4242 parents = [repo[node]]
4213 4243 if rej:
4214 4244 ui.write_err(_("patch applied partially\n"))
4215 4245 ui.write_err(_("(fix the .rej files and run "
4216 4246 "`hg commit --amend`)\n"))
4217 4247 ret = 1
4218 4248 break
4219 4249
4220 4250 if not haspatch:
4221 4251 raise util.Abort(_('%s: no diffs found') % patchurl)
4222 4252
4223 4253 if tr:
4224 4254 tr.close()
4225 4255 if msgs:
4226 4256 repo.savecommitmessage('\n* * *\n'.join(msgs))
4227 4257 repo.dirstate.endparentchange()
4228 4258 return ret
4229 4259 except: # re-raises
4230 4260 # wlock.release() indirectly calls dirstate.write(): since
4231 4261 # we're crashing, we do not want to change the working dir
4232 4262 # parent after all, so make sure it writes nothing
4233 4263 repo.dirstate.invalidate()
4234 4264 raise
4235 4265 finally:
4236 4266 if tr:
4237 4267 tr.release()
4238 4268 release(lock, wlock)
4239 4269
4240 4270 @command('incoming|in',
4241 4271 [('f', 'force', None,
4242 4272 _('run even if remote repository is unrelated')),
4243 4273 ('n', 'newest-first', None, _('show newest record first')),
4244 4274 ('', 'bundle', '',
4245 4275 _('file to store the bundles into'), _('FILE')),
4246 4276 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
4247 4277 ('B', 'bookmarks', False, _("compare bookmarks")),
4248 4278 ('b', 'branch', [],
4249 4279 _('a specific branch you would like to pull'), _('BRANCH')),
4250 4280 ] + logopts + remoteopts + subrepoopts,
4251 4281 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
4252 4282 def incoming(ui, repo, source="default", **opts):
4253 4283 """show new changesets found in source
4254 4284
4255 4285 Show new changesets found in the specified path/URL or the default
4256 4286 pull location. These are the changesets that would have been pulled
4257 4287 if a pull at the time you issued this command.
4258 4288
4259 4289 See pull for valid source format details.
4260 4290
4261 4291 .. container:: verbose
4262 4292
4263 4293 For remote repository, using --bundle avoids downloading the
4264 4294 changesets twice if the incoming is followed by a pull.
4265 4295
4266 4296 Examples:
4267 4297
4268 4298 - show incoming changes with patches and full description::
4269 4299
4270 4300 hg incoming -vp
4271 4301
4272 4302 - show incoming changes excluding merges, store a bundle::
4273 4303
4274 4304 hg in -vpM --bundle incoming.hg
4275 4305 hg pull incoming.hg
4276 4306
4277 4307 - briefly list changes inside a bundle::
4278 4308
4279 4309 hg in changes.hg -T "{desc|firstline}\\n"
4280 4310
4281 4311 Returns 0 if there are incoming changes, 1 otherwise.
4282 4312 """
4283 4313 if opts.get('graph'):
4284 4314 cmdutil.checkunsupportedgraphflags([], opts)
4285 4315 def display(other, chlist, displayer):
4286 4316 revdag = cmdutil.graphrevs(other, chlist, opts)
4287 4317 showparents = [ctx.node() for ctx in repo[None].parents()]
4288 4318 cmdutil.displaygraph(ui, revdag, displayer, showparents,
4289 4319 graphmod.asciiedges)
4290 4320
4291 4321 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
4292 4322 return 0
4293 4323
4294 4324 if opts.get('bundle') and opts.get('subrepos'):
4295 4325 raise util.Abort(_('cannot combine --bundle and --subrepos'))
4296 4326
4297 4327 if opts.get('bookmarks'):
4298 4328 source, branches = hg.parseurl(ui.expandpath(source),
4299 4329 opts.get('branch'))
4300 4330 other = hg.peer(repo, opts, source)
4301 4331 if 'bookmarks' not in other.listkeys('namespaces'):
4302 4332 ui.warn(_("remote doesn't support bookmarks\n"))
4303 4333 return 0
4304 4334 ui.status(_('comparing with %s\n') % util.hidepassword(source))
4305 4335 return bookmarks.incoming(ui, repo, other)
4306 4336
4307 4337 repo._subtoppath = ui.expandpath(source)
4308 4338 try:
4309 4339 return hg.incoming(ui, repo, source, opts)
4310 4340 finally:
4311 4341 del repo._subtoppath
4312 4342
4313 4343
4314 4344 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'),
4315 4345 norepo=True)
4316 4346 def init(ui, dest=".", **opts):
4317 4347 """create a new repository in the given directory
4318 4348
4319 4349 Initialize a new repository in the given directory. If the given
4320 4350 directory does not exist, it will be created.
4321 4351
4322 4352 If no directory is given, the current directory is used.
4323 4353
4324 4354 It is possible to specify an ``ssh://`` URL as the destination.
4325 4355 See :hg:`help urls` for more information.
4326 4356
4327 4357 Returns 0 on success.
4328 4358 """
4329 4359 hg.peer(ui, opts, ui.expandpath(dest), create=True)
4330 4360
4331 4361 @command('locate',
4332 4362 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
4333 4363 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
4334 4364 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
4335 4365 ] + walkopts,
4336 4366 _('[OPTION]... [PATTERN]...'))
4337 4367 def locate(ui, repo, *pats, **opts):
4338 4368 """locate files matching specific patterns (DEPRECATED)
4339 4369
4340 4370 Print files under Mercurial control in the working directory whose
4341 4371 names match the given patterns.
4342 4372
4343 4373 By default, this command searches all directories in the working
4344 4374 directory. To search just the current directory and its
4345 4375 subdirectories, use "--include .".
4346 4376
4347 4377 If no patterns are given to match, this command prints the names
4348 4378 of all files under Mercurial control in the working directory.
4349 4379
4350 4380 If you want to feed the output of this command into the "xargs"
4351 4381 command, use the -0 option to both this command and "xargs". This
4352 4382 will avoid the problem of "xargs" treating single filenames that
4353 4383 contain whitespace as multiple filenames.
4354 4384
4355 4385 See :hg:`help files` for a more versatile command.
4356 4386
4357 4387 Returns 0 if a match is found, 1 otherwise.
4358 4388 """
4359 4389 if opts.get('print0'):
4360 4390 end = '\0'
4361 4391 else:
4362 4392 end = '\n'
4363 4393 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
4364 4394
4365 4395 ret = 1
4366 4396 ctx = repo[rev]
4367 4397 m = scmutil.match(ctx, pats, opts, default='relglob')
4368 4398 m.bad = lambda x, y: False
4369 4399
4370 4400 for abs in ctx.matches(m):
4371 4401 if opts.get('fullpath'):
4372 4402 ui.write(repo.wjoin(abs), end)
4373 4403 else:
4374 4404 ui.write(((pats and m.rel(abs)) or abs), end)
4375 4405 ret = 0
4376 4406
4377 4407 return ret
4378 4408
4379 4409 @command('^log|history',
4380 4410 [('f', 'follow', None,
4381 4411 _('follow changeset history, or file history across copies and renames')),
4382 4412 ('', 'follow-first', None,
4383 4413 _('only follow the first parent of merge changesets (DEPRECATED)')),
4384 4414 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
4385 4415 ('C', 'copies', None, _('show copied files')),
4386 4416 ('k', 'keyword', [],
4387 4417 _('do case-insensitive search for a given text'), _('TEXT')),
4388 4418 ('r', 'rev', [], _('show the specified revision or revset'), _('REV')),
4389 4419 ('', 'removed', None, _('include revisions where files were removed')),
4390 4420 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
4391 4421 ('u', 'user', [], _('revisions committed by user'), _('USER')),
4392 4422 ('', 'only-branch', [],
4393 4423 _('show only changesets within the given named branch (DEPRECATED)'),
4394 4424 _('BRANCH')),
4395 4425 ('b', 'branch', [],
4396 4426 _('show changesets within the given named branch'), _('BRANCH')),
4397 4427 ('P', 'prune', [],
4398 4428 _('do not display revision or any of its ancestors'), _('REV')),
4399 4429 ] + logopts + walkopts,
4400 4430 _('[OPTION]... [FILE]'),
4401 4431 inferrepo=True)
4402 4432 def log(ui, repo, *pats, **opts):
4403 4433 """show revision history of entire repository or files
4404 4434
4405 4435 Print the revision history of the specified files or the entire
4406 4436 project.
4407 4437
4408 4438 If no revision range is specified, the default is ``tip:0`` unless
4409 4439 --follow is set, in which case the working directory parent is
4410 4440 used as the starting revision.
4411 4441
4412 4442 File history is shown without following rename or copy history of
4413 4443 files. Use -f/--follow with a filename to follow history across
4414 4444 renames and copies. --follow without a filename will only show
4415 4445 ancestors or descendants of the starting revision.
4416 4446
4417 4447 By default this command prints revision number and changeset id,
4418 4448 tags, non-trivial parents, user, date and time, and a summary for
4419 4449 each commit. When the -v/--verbose switch is used, the list of
4420 4450 changed files and full commit message are shown.
4421 4451
4422 4452 With --graph the revisions are shown as an ASCII art DAG with the most
4423 4453 recent changeset at the top.
4424 4454 'o' is a changeset, '@' is a working directory parent, 'x' is obsolete,
4425 4455 and '+' represents a fork where the changeset from the lines below is a
4426 4456 parent of the 'o' merge on the same line.
4427 4457
4428 4458 .. note::
4429 4459
4430 4460 log -p/--patch may generate unexpected diff output for merge
4431 4461 changesets, as it will only compare the merge changeset against
4432 4462 its first parent. Also, only files different from BOTH parents
4433 4463 will appear in files:.
4434 4464
4435 4465 .. note::
4436 4466
4437 4467 for performance reasons, log FILE may omit duplicate changes
4438 4468 made on branches and will not show removals or mode changes. To
4439 4469 see all such changes, use the --removed switch.
4440 4470
4441 4471 .. container:: verbose
4442 4472
4443 4473 Some examples:
4444 4474
4445 4475 - changesets with full descriptions and file lists::
4446 4476
4447 4477 hg log -v
4448 4478
4449 4479 - changesets ancestral to the working directory::
4450 4480
4451 4481 hg log -f
4452 4482
4453 4483 - last 10 commits on the current branch::
4454 4484
4455 4485 hg log -l 10 -b .
4456 4486
4457 4487 - changesets showing all modifications of a file, including removals::
4458 4488
4459 4489 hg log --removed file.c
4460 4490
4461 4491 - all changesets that touch a directory, with diffs, excluding merges::
4462 4492
4463 4493 hg log -Mp lib/
4464 4494
4465 4495 - all revision numbers that match a keyword::
4466 4496
4467 4497 hg log -k bug --template "{rev}\\n"
4468 4498
4469 4499 - list available log templates::
4470 4500
4471 4501 hg log -T list
4472 4502
4473 4503 - check if a given changeset is included in a tagged release::
4474 4504
4475 4505 hg log -r "a21ccf and ancestor(1.9)"
4476 4506
4477 4507 - find all changesets by some user in a date range::
4478 4508
4479 4509 hg log -k alice -d "may 2008 to jul 2008"
4480 4510
4481 4511 - summary of all changesets after the last tag::
4482 4512
4483 4513 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
4484 4514
4485 4515 See :hg:`help dates` for a list of formats valid for -d/--date.
4486 4516
4487 4517 See :hg:`help revisions` and :hg:`help revsets` for more about
4488 4518 specifying revisions.
4489 4519
4490 4520 See :hg:`help templates` for more about pre-packaged styles and
4491 4521 specifying custom templates.
4492 4522
4493 4523 Returns 0 on success.
4494 4524
4495 4525 """
4496 4526 if opts.get('follow') and opts.get('rev'):
4497 4527 opts['rev'] = [revset.formatspec('reverse(::%lr)', opts.get('rev'))]
4498 4528 del opts['follow']
4499 4529
4500 4530 if opts.get('graph'):
4501 4531 return cmdutil.graphlog(ui, repo, *pats, **opts)
4502 4532
4503 4533 revs, expr, filematcher = cmdutil.getlogrevs(repo, pats, opts)
4504 4534 limit = cmdutil.loglimit(opts)
4505 4535 count = 0
4506 4536
4507 4537 getrenamed = None
4508 4538 if opts.get('copies'):
4509 4539 endrev = None
4510 4540 if opts.get('rev'):
4511 4541 endrev = scmutil.revrange(repo, opts.get('rev')).max() + 1
4512 4542 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
4513 4543
4514 4544 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
4515 4545 for rev in revs:
4516 4546 if count == limit:
4517 4547 break
4518 4548 ctx = repo[rev]
4519 4549 copies = None
4520 4550 if getrenamed is not None and rev:
4521 4551 copies = []
4522 4552 for fn in ctx.files():
4523 4553 rename = getrenamed(fn, rev)
4524 4554 if rename:
4525 4555 copies.append((fn, rename[0]))
4526 4556 if filematcher:
4527 4557 revmatchfn = filematcher(ctx.rev())
4528 4558 else:
4529 4559 revmatchfn = None
4530 4560 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
4531 4561 if displayer.flush(rev):
4532 4562 count += 1
4533 4563
4534 4564 displayer.close()
4535 4565
4536 4566 @command('manifest',
4537 4567 [('r', 'rev', '', _('revision to display'), _('REV')),
4538 4568 ('', 'all', False, _("list files from all revisions"))]
4539 4569 + formatteropts,
4540 4570 _('[-r REV]'))
4541 4571 def manifest(ui, repo, node=None, rev=None, **opts):
4542 4572 """output the current or given revision of the project manifest
4543 4573
4544 4574 Print a list of version controlled files for the given revision.
4545 4575 If no revision is given, the first parent of the working directory
4546 4576 is used, or the null revision if no revision is checked out.
4547 4577
4548 4578 With -v, print file permissions, symlink and executable bits.
4549 4579 With --debug, print file revision hashes.
4550 4580
4551 4581 If option --all is specified, the list of all files from all revisions
4552 4582 is printed. This includes deleted and renamed files.
4553 4583
4554 4584 Returns 0 on success.
4555 4585 """
4556 4586
4557 4587 fm = ui.formatter('manifest', opts)
4558 4588
4559 4589 if opts.get('all'):
4560 4590 if rev or node:
4561 4591 raise util.Abort(_("can't specify a revision with --all"))
4562 4592
4563 4593 res = []
4564 4594 prefix = "data/"
4565 4595 suffix = ".i"
4566 4596 plen = len(prefix)
4567 4597 slen = len(suffix)
4568 4598 lock = repo.lock()
4569 4599 try:
4570 4600 for fn, b, size in repo.store.datafiles():
4571 4601 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
4572 4602 res.append(fn[plen:-slen])
4573 4603 finally:
4574 4604 lock.release()
4575 4605 for f in res:
4576 4606 fm.startitem()
4577 4607 fm.write("path", '%s\n', f)
4578 4608 fm.end()
4579 4609 return
4580 4610
4581 4611 if rev and node:
4582 4612 raise util.Abort(_("please specify just one revision"))
4583 4613
4584 4614 if not node:
4585 4615 node = rev
4586 4616
4587 4617 char = {'l': '@', 'x': '*', '': ''}
4588 4618 mode = {'l': '644', 'x': '755', '': '644'}
4589 4619 ctx = scmutil.revsingle(repo, node)
4590 4620 mf = ctx.manifest()
4591 4621 for f in ctx:
4592 4622 fm.startitem()
4593 4623 fl = ctx[f].flags()
4594 4624 fm.condwrite(ui.debugflag, 'hash', '%s ', hex(mf[f]))
4595 4625 fm.condwrite(ui.verbose, 'mode type', '%s %1s ', mode[fl], char[fl])
4596 4626 fm.write('path', '%s\n', f)
4597 4627 fm.end()
4598 4628
4599 4629 @command('^merge',
4600 4630 [('f', 'force', None,
4601 4631 _('force a merge including outstanding changes (DEPRECATED)')),
4602 4632 ('r', 'rev', '', _('revision to merge'), _('REV')),
4603 4633 ('P', 'preview', None,
4604 4634 _('review revisions to merge (no merge is performed)'))
4605 4635 ] + mergetoolopts,
4606 4636 _('[-P] [-f] [[-r] REV]'))
4607 4637 def merge(ui, repo, node=None, **opts):
4608 4638 """merge another revision into working directory
4609 4639
4610 4640 The current working directory is updated with all changes made in
4611 4641 the requested revision since the last common predecessor revision.
4612 4642
4613 4643 Files that changed between either parent are marked as changed for
4614 4644 the next commit and a commit must be performed before any further
4615 4645 updates to the repository are allowed. The next commit will have
4616 4646 two parents.
4617 4647
4618 4648 ``--tool`` can be used to specify the merge tool used for file
4619 4649 merges. It overrides the HGMERGE environment variable and your
4620 4650 configuration files. See :hg:`help merge-tools` for options.
4621 4651
4622 4652 If no revision is specified, the working directory's parent is a
4623 4653 head revision, and the current branch contains exactly one other
4624 4654 head, the other head is merged with by default. Otherwise, an
4625 4655 explicit revision with which to merge with must be provided.
4626 4656
4627 4657 :hg:`resolve` must be used to resolve unresolved files.
4628 4658
4629 4659 To undo an uncommitted merge, use :hg:`update --clean .` which
4630 4660 will check out a clean copy of the original merge parent, losing
4631 4661 all changes.
4632 4662
4633 4663 Returns 0 on success, 1 if there are unresolved files.
4634 4664 """
4635 4665
4636 4666 if opts.get('rev') and node:
4637 4667 raise util.Abort(_("please specify just one revision"))
4638 4668 if not node:
4639 4669 node = opts.get('rev')
4640 4670
4641 4671 if node:
4642 4672 node = scmutil.revsingle(repo, node).node()
4643 4673
4644 4674 if not node and repo._bookmarkcurrent:
4645 4675 bmheads = repo.bookmarkheads(repo._bookmarkcurrent)
4646 4676 curhead = repo[repo._bookmarkcurrent].node()
4647 4677 if len(bmheads) == 2:
4648 4678 if curhead == bmheads[0]:
4649 4679 node = bmheads[1]
4650 4680 else:
4651 4681 node = bmheads[0]
4652 4682 elif len(bmheads) > 2:
4653 4683 raise util.Abort(_("multiple matching bookmarks to merge - "
4654 4684 "please merge with an explicit rev or bookmark"),
4655 4685 hint=_("run 'hg heads' to see all heads"))
4656 4686 elif len(bmheads) <= 1:
4657 4687 raise util.Abort(_("no matching bookmark to merge - "
4658 4688 "please merge with an explicit rev or bookmark"),
4659 4689 hint=_("run 'hg heads' to see all heads"))
4660 4690
4661 4691 if not node and not repo._bookmarkcurrent:
4662 4692 branch = repo[None].branch()
4663 4693 bheads = repo.branchheads(branch)
4664 4694 nbhs = [bh for bh in bheads if not repo[bh].bookmarks()]
4665 4695
4666 4696 if len(nbhs) > 2:
4667 4697 raise util.Abort(_("branch '%s' has %d heads - "
4668 4698 "please merge with an explicit rev")
4669 4699 % (branch, len(bheads)),
4670 4700 hint=_("run 'hg heads .' to see heads"))
4671 4701
4672 4702 parent = repo.dirstate.p1()
4673 4703 if len(nbhs) <= 1:
4674 4704 if len(bheads) > 1:
4675 4705 raise util.Abort(_("heads are bookmarked - "
4676 4706 "please merge with an explicit rev"),
4677 4707 hint=_("run 'hg heads' to see all heads"))
4678 4708 if len(repo.heads()) > 1:
4679 4709 raise util.Abort(_("branch '%s' has one head - "
4680 4710 "please merge with an explicit rev")
4681 4711 % branch,
4682 4712 hint=_("run 'hg heads' to see all heads"))
4683 4713 msg, hint = _('nothing to merge'), None
4684 4714 if parent != repo.lookup(branch):
4685 4715 hint = _("use 'hg update' instead")
4686 4716 raise util.Abort(msg, hint=hint)
4687 4717
4688 4718 if parent not in bheads:
4689 4719 raise util.Abort(_('working directory not at a head revision'),
4690 4720 hint=_("use 'hg update' or merge with an "
4691 4721 "explicit revision"))
4692 4722 if parent == nbhs[0]:
4693 4723 node = nbhs[-1]
4694 4724 else:
4695 4725 node = nbhs[0]
4696 4726
4697 4727 if opts.get('preview'):
4698 4728 # find nodes that are ancestors of p2 but not of p1
4699 4729 p1 = repo.lookup('.')
4700 4730 p2 = repo.lookup(node)
4701 4731 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
4702 4732
4703 4733 displayer = cmdutil.show_changeset(ui, repo, opts)
4704 4734 for node in nodes:
4705 4735 displayer.show(repo[node])
4706 4736 displayer.close()
4707 4737 return 0
4708 4738
4709 4739 try:
4710 4740 # ui.forcemerge is an internal variable, do not document
4711 4741 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''), 'merge')
4712 4742 return hg.merge(repo, node, force=opts.get('force'))
4713 4743 finally:
4714 4744 ui.setconfig('ui', 'forcemerge', '', 'merge')
4715 4745
4716 4746 @command('outgoing|out',
4717 4747 [('f', 'force', None, _('run even when the destination is unrelated')),
4718 4748 ('r', 'rev', [],
4719 4749 _('a changeset intended to be included in the destination'), _('REV')),
4720 4750 ('n', 'newest-first', None, _('show newest record first')),
4721 4751 ('B', 'bookmarks', False, _('compare bookmarks')),
4722 4752 ('b', 'branch', [], _('a specific branch you would like to push'),
4723 4753 _('BRANCH')),
4724 4754 ] + logopts + remoteopts + subrepoopts,
4725 4755 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
4726 4756 def outgoing(ui, repo, dest=None, **opts):
4727 4757 """show changesets not found in the destination
4728 4758
4729 4759 Show changesets not found in the specified destination repository
4730 4760 or the default push location. These are the changesets that would
4731 4761 be pushed if a push was requested.
4732 4762
4733 4763 See pull for details of valid destination formats.
4734 4764
4735 4765 Returns 0 if there are outgoing changes, 1 otherwise.
4736 4766 """
4737 4767 if opts.get('graph'):
4738 4768 cmdutil.checkunsupportedgraphflags([], opts)
4739 4769 o, other = hg._outgoing(ui, repo, dest, opts)
4740 4770 if not o:
4741 4771 cmdutil.outgoinghooks(ui, repo, other, opts, o)
4742 4772 return
4743 4773
4744 4774 revdag = cmdutil.graphrevs(repo, o, opts)
4745 4775 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
4746 4776 showparents = [ctx.node() for ctx in repo[None].parents()]
4747 4777 cmdutil.displaygraph(ui, revdag, displayer, showparents,
4748 4778 graphmod.asciiedges)
4749 4779 cmdutil.outgoinghooks(ui, repo, other, opts, o)
4750 4780 return 0
4751 4781
4752 4782 if opts.get('bookmarks'):
4753 4783 dest = ui.expandpath(dest or 'default-push', dest or 'default')
4754 4784 dest, branches = hg.parseurl(dest, opts.get('branch'))
4755 4785 other = hg.peer(repo, opts, dest)
4756 4786 if 'bookmarks' not in other.listkeys('namespaces'):
4757 4787 ui.warn(_("remote doesn't support bookmarks\n"))
4758 4788 return 0
4759 4789 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
4760 4790 return bookmarks.outgoing(ui, repo, other)
4761 4791
4762 4792 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
4763 4793 try:
4764 4794 return hg.outgoing(ui, repo, dest, opts)
4765 4795 finally:
4766 4796 del repo._subtoppath
4767 4797
4768 4798 @command('parents',
4769 4799 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
4770 4800 ] + templateopts,
4771 4801 _('[-r REV] [FILE]'),
4772 4802 inferrepo=True)
4773 4803 def parents(ui, repo, file_=None, **opts):
4774 4804 """show the parents of the working directory or revision (DEPRECATED)
4775 4805
4776 4806 Print the working directory's parent revisions. If a revision is
4777 4807 given via -r/--rev, the parent of that revision will be printed.
4778 4808 If a file argument is given, the revision in which the file was
4779 4809 last changed (before the working directory revision or the
4780 4810 argument to --rev if given) is printed.
4781 4811
4782 4812 See :hg:`summary` and :hg:`help revsets` for related information.
4783 4813
4784 4814 Returns 0 on success.
4785 4815 """
4786 4816
4787 4817 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
4788 4818
4789 4819 if file_:
4790 4820 m = scmutil.match(ctx, (file_,), opts)
4791 4821 if m.anypats() or len(m.files()) != 1:
4792 4822 raise util.Abort(_('can only specify an explicit filename'))
4793 4823 file_ = m.files()[0]
4794 4824 filenodes = []
4795 4825 for cp in ctx.parents():
4796 4826 if not cp:
4797 4827 continue
4798 4828 try:
4799 4829 filenodes.append(cp.filenode(file_))
4800 4830 except error.LookupError:
4801 4831 pass
4802 4832 if not filenodes:
4803 4833 raise util.Abort(_("'%s' not found in manifest!") % file_)
4804 4834 p = []
4805 4835 for fn in filenodes:
4806 4836 fctx = repo.filectx(file_, fileid=fn)
4807 4837 p.append(fctx.node())
4808 4838 else:
4809 4839 p = [cp.node() for cp in ctx.parents()]
4810 4840
4811 4841 displayer = cmdutil.show_changeset(ui, repo, opts)
4812 4842 for n in p:
4813 4843 if n != nullid:
4814 4844 displayer.show(repo[n])
4815 4845 displayer.close()
4816 4846
4817 4847 @command('paths', [], _('[NAME]'), optionalrepo=True)
4818 4848 def paths(ui, repo, search=None):
4819 4849 """show aliases for remote repositories
4820 4850
4821 4851 Show definition of symbolic path name NAME. If no name is given,
4822 4852 show definition of all available names.
4823 4853
4824 4854 Option -q/--quiet suppresses all output when searching for NAME
4825 4855 and shows only the path names when listing all definitions.
4826 4856
4827 4857 Path names are defined in the [paths] section of your
4828 4858 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
4829 4859 repository, ``.hg/hgrc`` is used, too.
4830 4860
4831 4861 The path names ``default`` and ``default-push`` have a special
4832 4862 meaning. When performing a push or pull operation, they are used
4833 4863 as fallbacks if no location is specified on the command-line.
4834 4864 When ``default-push`` is set, it will be used for push and
4835 4865 ``default`` will be used for pull; otherwise ``default`` is used
4836 4866 as the fallback for both. When cloning a repository, the clone
4837 4867 source is written as ``default`` in ``.hg/hgrc``. Note that
4838 4868 ``default`` and ``default-push`` apply to all inbound (e.g.
4839 4869 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email` and
4840 4870 :hg:`bundle`) operations.
4841 4871
4842 4872 See :hg:`help urls` for more information.
4843 4873
4844 4874 Returns 0 on success.
4845 4875 """
4846 4876 if search:
4847 4877 for name, path in sorted(ui.paths.iteritems()):
4848 4878 if name == search:
4849 4879 ui.status("%s\n" % util.hidepassword(path.loc))
4850 4880 return
4851 4881 if not ui.quiet:
4852 4882 ui.warn(_("not found!\n"))
4853 4883 return 1
4854 4884 else:
4855 4885 for name, path in sorted(ui.paths.iteritems()):
4856 4886 if ui.quiet:
4857 4887 ui.write("%s\n" % name)
4858 4888 else:
4859 4889 ui.write("%s = %s\n" % (name,
4860 4890 util.hidepassword(path.loc)))
4861 4891
4862 4892 @command('phase',
4863 4893 [('p', 'public', False, _('set changeset phase to public')),
4864 4894 ('d', 'draft', False, _('set changeset phase to draft')),
4865 4895 ('s', 'secret', False, _('set changeset phase to secret')),
4866 4896 ('f', 'force', False, _('allow to move boundary backward')),
4867 4897 ('r', 'rev', [], _('target revision'), _('REV')),
4868 4898 ],
4869 4899 _('[-p|-d|-s] [-f] [-r] REV...'))
4870 4900 def phase(ui, repo, *revs, **opts):
4871 4901 """set or show the current phase name
4872 4902
4873 4903 With no argument, show the phase name of specified revisions.
4874 4904
4875 4905 With one of -p/--public, -d/--draft or -s/--secret, change the
4876 4906 phase value of the specified revisions.
4877 4907
4878 4908 Unless -f/--force is specified, :hg:`phase` won't move changeset from a
4879 4909 lower phase to an higher phase. Phases are ordered as follows::
4880 4910
4881 4911 public < draft < secret
4882 4912
4883 4913 Returns 0 on success, 1 if no phases were changed or some could not
4884 4914 be changed.
4885 4915 """
4886 4916 # search for a unique phase argument
4887 4917 targetphase = None
4888 4918 for idx, name in enumerate(phases.phasenames):
4889 4919 if opts[name]:
4890 4920 if targetphase is not None:
4891 4921 raise util.Abort(_('only one phase can be specified'))
4892 4922 targetphase = idx
4893 4923
4894 4924 # look for specified revision
4895 4925 revs = list(revs)
4896 4926 revs.extend(opts['rev'])
4897 4927 if not revs:
4898 4928 raise util.Abort(_('no revisions specified'))
4899 4929
4900 4930 revs = scmutil.revrange(repo, revs)
4901 4931
4902 4932 lock = None
4903 4933 ret = 0
4904 4934 if targetphase is None:
4905 4935 # display
4906 4936 for r in revs:
4907 4937 ctx = repo[r]
4908 4938 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
4909 4939 else:
4910 4940 tr = None
4911 4941 lock = repo.lock()
4912 4942 try:
4913 4943 tr = repo.transaction("phase")
4914 4944 # set phase
4915 4945 if not revs:
4916 4946 raise util.Abort(_('empty revision set'))
4917 4947 nodes = [repo[r].node() for r in revs]
4918 4948 # moving revision from public to draft may hide them
4919 4949 # We have to check result on an unfiltered repository
4920 4950 unfi = repo.unfiltered()
4921 4951 getphase = unfi._phasecache.phase
4922 4952 olddata = [getphase(unfi, r) for r in unfi]
4923 4953 phases.advanceboundary(repo, tr, targetphase, nodes)
4924 4954 if opts['force']:
4925 4955 phases.retractboundary(repo, tr, targetphase, nodes)
4926 4956 tr.close()
4927 4957 finally:
4928 4958 if tr is not None:
4929 4959 tr.release()
4930 4960 lock.release()
4931 4961 getphase = unfi._phasecache.phase
4932 4962 newdata = [getphase(unfi, r) for r in unfi]
4933 4963 changes = sum(newdata[r] != olddata[r] for r in unfi)
4934 4964 cl = unfi.changelog
4935 4965 rejected = [n for n in nodes
4936 4966 if newdata[cl.rev(n)] < targetphase]
4937 4967 if rejected:
4938 4968 ui.warn(_('cannot move %i changesets to a higher '
4939 4969 'phase, use --force\n') % len(rejected))
4940 4970 ret = 1
4941 4971 if changes:
4942 4972 msg = _('phase changed for %i changesets\n') % changes
4943 4973 if ret:
4944 4974 ui.status(msg)
4945 4975 else:
4946 4976 ui.note(msg)
4947 4977 else:
4948 4978 ui.warn(_('no phases changed\n'))
4949 4979 ret = 1
4950 4980 return ret
4951 4981
4952 4982 def postincoming(ui, repo, modheads, optupdate, checkout):
4953 4983 if modheads == 0:
4954 4984 return
4955 4985 if optupdate:
4956 4986 checkout, movemarkfrom = bookmarks.calculateupdate(ui, repo, checkout)
4957 4987 try:
4958 4988 ret = hg.update(repo, checkout)
4959 4989 except util.Abort, inst:
4960 4990 ui.warn(_("not updating: %s\n") % str(inst))
4961 4991 if inst.hint:
4962 4992 ui.warn(_("(%s)\n") % inst.hint)
4963 4993 return 0
4964 4994 if not ret and not checkout:
4965 4995 if bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
4966 4996 ui.status(_("updating bookmark %s\n") % repo._bookmarkcurrent)
4967 4997 return ret
4968 4998 if modheads > 1:
4969 4999 currentbranchheads = len(repo.branchheads())
4970 5000 if currentbranchheads == modheads:
4971 5001 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
4972 5002 elif currentbranchheads > 1:
4973 5003 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
4974 5004 "merge)\n"))
4975 5005 else:
4976 5006 ui.status(_("(run 'hg heads' to see heads)\n"))
4977 5007 else:
4978 5008 ui.status(_("(run 'hg update' to get a working copy)\n"))
4979 5009
4980 5010 @command('^pull',
4981 5011 [('u', 'update', None,
4982 5012 _('update to new branch head if changesets were pulled')),
4983 5013 ('f', 'force', None, _('run even when remote repository is unrelated')),
4984 5014 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
4985 5015 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
4986 5016 ('b', 'branch', [], _('a specific branch you would like to pull'),
4987 5017 _('BRANCH')),
4988 5018 ] + remoteopts,
4989 5019 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
4990 5020 def pull(ui, repo, source="default", **opts):
4991 5021 """pull changes from the specified source
4992 5022
4993 5023 Pull changes from a remote repository to a local one.
4994 5024
4995 5025 This finds all changes from the repository at the specified path
4996 5026 or URL and adds them to a local repository (the current one unless
4997 5027 -R is specified). By default, this does not update the copy of the
4998 5028 project in the working directory.
4999 5029
5000 5030 Use :hg:`incoming` if you want to see what would have been added
5001 5031 by a pull at the time you issued this command. If you then decide
5002 5032 to add those changes to the repository, you should use :hg:`pull
5003 5033 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
5004 5034
5005 5035 If SOURCE is omitted, the 'default' path will be used.
5006 5036 See :hg:`help urls` for more information.
5007 5037
5008 5038 Returns 0 on success, 1 if an update had unresolved files.
5009 5039 """
5010 5040 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
5011 5041 ui.status(_('pulling from %s\n') % util.hidepassword(source))
5012 5042 other = hg.peer(repo, opts, source)
5013 5043 try:
5014 5044 revs, checkout = hg.addbranchrevs(repo, other, branches,
5015 5045 opts.get('rev'))
5016 5046
5017 5047 remotebookmarks = other.listkeys('bookmarks')
5018 5048
5019 5049 if opts.get('bookmark'):
5020 5050 if not revs:
5021 5051 revs = []
5022 5052 for b in opts['bookmark']:
5023 5053 if b not in remotebookmarks:
5024 5054 raise util.Abort(_('remote bookmark %s not found!') % b)
5025 5055 revs.append(remotebookmarks[b])
5026 5056
5027 5057 if revs:
5028 5058 try:
5029 5059 revs = [other.lookup(rev) for rev in revs]
5030 5060 except error.CapabilityError:
5031 5061 err = _("other repository doesn't support revision lookup, "
5032 5062 "so a rev cannot be specified.")
5033 5063 raise util.Abort(err)
5034 5064
5035 5065 modheads = exchange.pull(repo, other, heads=revs,
5036 5066 force=opts.get('force'),
5037 5067 bookmarks=opts.get('bookmark', ())).cgresult
5038 5068 if checkout:
5039 5069 checkout = str(repo.changelog.rev(other.lookup(checkout)))
5040 5070 repo._subtoppath = source
5041 5071 try:
5042 5072 ret = postincoming(ui, repo, modheads, opts.get('update'), checkout)
5043 5073
5044 5074 finally:
5045 5075 del repo._subtoppath
5046 5076
5047 5077 finally:
5048 5078 other.close()
5049 5079 return ret
5050 5080
5051 5081 @command('^push',
5052 5082 [('f', 'force', None, _('force push')),
5053 5083 ('r', 'rev', [],
5054 5084 _('a changeset intended to be included in the destination'),
5055 5085 _('REV')),
5056 5086 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
5057 5087 ('b', 'branch', [],
5058 5088 _('a specific branch you would like to push'), _('BRANCH')),
5059 5089 ('', 'new-branch', False, _('allow pushing a new branch')),
5060 5090 ] + remoteopts,
5061 5091 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
5062 5092 def push(ui, repo, dest=None, **opts):
5063 5093 """push changes to the specified destination
5064 5094
5065 5095 Push changesets from the local repository to the specified
5066 5096 destination.
5067 5097
5068 5098 This operation is symmetrical to pull: it is identical to a pull
5069 5099 in the destination repository from the current one.
5070 5100
5071 5101 By default, push will not allow creation of new heads at the
5072 5102 destination, since multiple heads would make it unclear which head
5073 5103 to use. In this situation, it is recommended to pull and merge
5074 5104 before pushing.
5075 5105
5076 5106 Use --new-branch if you want to allow push to create a new named
5077 5107 branch that is not present at the destination. This allows you to
5078 5108 only create a new branch without forcing other changes.
5079 5109
5080 5110 .. note::
5081 5111
5082 5112 Extra care should be taken with the -f/--force option,
5083 5113 which will push all new heads on all branches, an action which will
5084 5114 almost always cause confusion for collaborators.
5085 5115
5086 5116 If -r/--rev is used, the specified revision and all its ancestors
5087 5117 will be pushed to the remote repository.
5088 5118
5089 5119 If -B/--bookmark is used, the specified bookmarked revision, its
5090 5120 ancestors, and the bookmark will be pushed to the remote
5091 5121 repository.
5092 5122
5093 5123 Please see :hg:`help urls` for important details about ``ssh://``
5094 5124 URLs. If DESTINATION is omitted, a default path will be used.
5095 5125
5096 5126 Returns 0 if push was successful, 1 if nothing to push.
5097 5127 """
5098 5128
5099 5129 if opts.get('bookmark'):
5100 5130 ui.setconfig('bookmarks', 'pushing', opts['bookmark'], 'push')
5101 5131 for b in opts['bookmark']:
5102 5132 # translate -B options to -r so changesets get pushed
5103 5133 if b in repo._bookmarks:
5104 5134 opts.setdefault('rev', []).append(b)
5105 5135 else:
5106 5136 # if we try to push a deleted bookmark, translate it to null
5107 5137 # this lets simultaneous -r, -b options continue working
5108 5138 opts.setdefault('rev', []).append("null")
5109 5139
5110 5140 dest = ui.expandpath(dest or 'default-push', dest or 'default')
5111 5141 dest, branches = hg.parseurl(dest, opts.get('branch'))
5112 5142 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
5113 5143 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
5114 5144 try:
5115 5145 other = hg.peer(repo, opts, dest)
5116 5146 except error.RepoError:
5117 5147 if dest == "default-push":
5118 5148 raise util.Abort(_("default repository not configured!"),
5119 5149 hint=_('see the "path" section in "hg help config"'))
5120 5150 else:
5121 5151 raise
5122 5152
5123 5153 if revs:
5124 5154 revs = [repo.lookup(r) for r in scmutil.revrange(repo, revs)]
5125 5155
5126 5156 repo._subtoppath = dest
5127 5157 try:
5128 5158 # push subrepos depth-first for coherent ordering
5129 5159 c = repo['']
5130 5160 subs = c.substate # only repos that are committed
5131 5161 for s in sorted(subs):
5132 5162 result = c.sub(s).push(opts)
5133 5163 if result == 0:
5134 5164 return not result
5135 5165 finally:
5136 5166 del repo._subtoppath
5137 5167 pushop = exchange.push(repo, other, opts.get('force'), revs=revs,
5138 5168 newbranch=opts.get('new_branch'),
5139 5169 bookmarks=opts.get('bookmark', ()))
5140 5170
5141 5171 result = not pushop.cgresult
5142 5172
5143 5173 if pushop.bkresult is not None:
5144 5174 if pushop.bkresult == 2:
5145 5175 result = 2
5146 5176 elif not result and pushop.bkresult:
5147 5177 result = 2
5148 5178
5149 5179 return result
5150 5180
5151 5181 @command('recover', [])
5152 5182 def recover(ui, repo):
5153 5183 """roll back an interrupted transaction
5154 5184
5155 5185 Recover from an interrupted commit or pull.
5156 5186
5157 5187 This command tries to fix the repository status after an
5158 5188 interrupted operation. It should only be necessary when Mercurial
5159 5189 suggests it.
5160 5190
5161 5191 Returns 0 if successful, 1 if nothing to recover or verify fails.
5162 5192 """
5163 5193 if repo.recover():
5164 5194 return hg.verify(repo)
5165 5195 return 1
5166 5196
5167 5197 @command('^remove|rm',
5168 5198 [('A', 'after', None, _('record delete for missing files')),
5169 5199 ('f', 'force', None,
5170 5200 _('remove (and delete) file even if added or modified')),
5171 5201 ] + subrepoopts + walkopts,
5172 5202 _('[OPTION]... FILE...'),
5173 5203 inferrepo=True)
5174 5204 def remove(ui, repo, *pats, **opts):
5175 5205 """remove the specified files on the next commit
5176 5206
5177 5207 Schedule the indicated files for removal from the current branch.
5178 5208
5179 5209 This command schedules the files to be removed at the next commit.
5180 5210 To undo a remove before that, see :hg:`revert`. To undo added
5181 5211 files, see :hg:`forget`.
5182 5212
5183 5213 .. container:: verbose
5184 5214
5185 5215 -A/--after can be used to remove only files that have already
5186 5216 been deleted, -f/--force can be used to force deletion, and -Af
5187 5217 can be used to remove files from the next revision without
5188 5218 deleting them from the working directory.
5189 5219
5190 5220 The following table details the behavior of remove for different
5191 5221 file states (columns) and option combinations (rows). The file
5192 5222 states are Added [A], Clean [C], Modified [M] and Missing [!]
5193 5223 (as reported by :hg:`status`). The actions are Warn, Remove
5194 5224 (from branch) and Delete (from disk):
5195 5225
5196 5226 ========= == == == ==
5197 5227 opt/state A C M !
5198 5228 ========= == == == ==
5199 5229 none W RD W R
5200 5230 -f R RD RD R
5201 5231 -A W W W R
5202 5232 -Af R R R R
5203 5233 ========= == == == ==
5204 5234
5205 5235 Note that remove never deletes files in Added [A] state from the
5206 5236 working directory, not even if option --force is specified.
5207 5237
5208 5238 Returns 0 on success, 1 if any warnings encountered.
5209 5239 """
5210 5240
5211 5241 after, force = opts.get('after'), opts.get('force')
5212 5242 if not pats and not after:
5213 5243 raise util.Abort(_('no files specified'))
5214 5244
5215 5245 m = scmutil.match(repo[None], pats, opts)
5216 5246 subrepos = opts.get('subrepos')
5217 5247 return cmdutil.remove(ui, repo, m, "", after, force, subrepos)
5218 5248
5219 5249 @command('rename|move|mv',
5220 5250 [('A', 'after', None, _('record a rename that has already occurred')),
5221 5251 ('f', 'force', None, _('forcibly copy over an existing managed file')),
5222 5252 ] + walkopts + dryrunopts,
5223 5253 _('[OPTION]... SOURCE... DEST'))
5224 5254 def rename(ui, repo, *pats, **opts):
5225 5255 """rename files; equivalent of copy + remove
5226 5256
5227 5257 Mark dest as copies of sources; mark sources for deletion. If dest
5228 5258 is a directory, copies are put in that directory. If dest is a
5229 5259 file, there can only be one source.
5230 5260
5231 5261 By default, this command copies the contents of files as they
5232 5262 exist in the working directory. If invoked with -A/--after, the
5233 5263 operation is recorded, but no copying is performed.
5234 5264
5235 5265 This command takes effect at the next commit. To undo a rename
5236 5266 before that, see :hg:`revert`.
5237 5267
5238 5268 Returns 0 on success, 1 if errors are encountered.
5239 5269 """
5240 5270 wlock = repo.wlock(False)
5241 5271 try:
5242 5272 return cmdutil.copy(ui, repo, pats, opts, rename=True)
5243 5273 finally:
5244 5274 wlock.release()
5245 5275
5246 5276 @command('resolve',
5247 5277 [('a', 'all', None, _('select all unresolved files')),
5248 5278 ('l', 'list', None, _('list state of files needing merge')),
5249 5279 ('m', 'mark', None, _('mark files as resolved')),
5250 5280 ('u', 'unmark', None, _('mark files as unresolved')),
5251 5281 ('n', 'no-status', None, _('hide status prefix'))]
5252 5282 + mergetoolopts + walkopts + formatteropts,
5253 5283 _('[OPTION]... [FILE]...'),
5254 5284 inferrepo=True)
5255 5285 def resolve(ui, repo, *pats, **opts):
5256 5286 """redo merges or set/view the merge status of files
5257 5287
5258 5288 Merges with unresolved conflicts are often the result of
5259 5289 non-interactive merging using the ``internal:merge`` configuration
5260 5290 setting, or a command-line merge tool like ``diff3``. The resolve
5261 5291 command is used to manage the files involved in a merge, after
5262 5292 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
5263 5293 working directory must have two parents). See :hg:`help
5264 5294 merge-tools` for information on configuring merge tools.
5265 5295
5266 5296 The resolve command can be used in the following ways:
5267 5297
5268 5298 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
5269 5299 files, discarding any previous merge attempts. Re-merging is not
5270 5300 performed for files already marked as resolved. Use ``--all/-a``
5271 5301 to select all unresolved files. ``--tool`` can be used to specify
5272 5302 the merge tool used for the given files. It overrides the HGMERGE
5273 5303 environment variable and your configuration files. Previous file
5274 5304 contents are saved with a ``.orig`` suffix.
5275 5305
5276 5306 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
5277 5307 (e.g. after having manually fixed-up the files). The default is
5278 5308 to mark all unresolved files.
5279 5309
5280 5310 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
5281 5311 default is to mark all resolved files.
5282 5312
5283 5313 - :hg:`resolve -l`: list files which had or still have conflicts.
5284 5314 In the printed list, ``U`` = unresolved and ``R`` = resolved.
5285 5315
5286 5316 Note that Mercurial will not let you commit files with unresolved
5287 5317 merge conflicts. You must use :hg:`resolve -m ...` before you can
5288 5318 commit after a conflicting merge.
5289 5319
5290 5320 Returns 0 on success, 1 if any files fail a resolve attempt.
5291 5321 """
5292 5322
5293 5323 all, mark, unmark, show, nostatus = \
5294 5324 [opts.get(o) for o in 'all mark unmark list no_status'.split()]
5295 5325
5296 5326 if (show and (mark or unmark)) or (mark and unmark):
5297 5327 raise util.Abort(_("too many options specified"))
5298 5328 if pats and all:
5299 5329 raise util.Abort(_("can't specify --all and patterns"))
5300 5330 if not (all or pats or show or mark or unmark):
5301 5331 raise util.Abort(_('no files or directories specified'),
5302 5332 hint=('use --all to remerge all files'))
5303 5333
5304 5334 if show:
5305 5335 fm = ui.formatter('resolve', opts)
5306 5336 ms = mergemod.mergestate(repo)
5307 5337 m = scmutil.match(repo[None], pats, opts)
5308 5338 for f in ms:
5309 5339 if not m(f):
5310 5340 continue
5311 5341 l = 'resolve.' + {'u': 'unresolved', 'r': 'resolved'}[ms[f]]
5312 5342 fm.startitem()
5313 5343 fm.condwrite(not nostatus, 'status', '%s ', ms[f].upper(), label=l)
5314 5344 fm.write('path', '%s\n', f, label=l)
5315 5345 fm.end()
5316 5346 return 0
5317 5347
5318 5348 wlock = repo.wlock()
5319 5349 try:
5320 5350 ms = mergemod.mergestate(repo)
5321 5351
5322 5352 if not (ms.active() or repo.dirstate.p2() != nullid):
5323 5353 raise util.Abort(
5324 5354 _('resolve command not applicable when not merging'))
5325 5355
5326 5356 m = scmutil.match(repo[None], pats, opts)
5327 5357 ret = 0
5328 5358 didwork = False
5329 5359
5330 5360 for f in ms:
5331 5361 if not m(f):
5332 5362 continue
5333 5363
5334 5364 didwork = True
5335 5365
5336 5366 if mark:
5337 5367 ms.mark(f, "r")
5338 5368 elif unmark:
5339 5369 ms.mark(f, "u")
5340 5370 else:
5341 5371 wctx = repo[None]
5342 5372
5343 5373 # backup pre-resolve (merge uses .orig for its own purposes)
5344 5374 a = repo.wjoin(f)
5345 5375 util.copyfile(a, a + ".resolve")
5346 5376
5347 5377 try:
5348 5378 # resolve file
5349 5379 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
5350 5380 'resolve')
5351 5381 if ms.resolve(f, wctx):
5352 5382 ret = 1
5353 5383 finally:
5354 5384 ui.setconfig('ui', 'forcemerge', '', 'resolve')
5355 5385 ms.commit()
5356 5386
5357 5387 # replace filemerge's .orig file with our resolve file
5358 5388 util.rename(a + ".resolve", a + ".orig")
5359 5389
5360 5390 ms.commit()
5361 5391
5362 5392 if not didwork and pats:
5363 5393 ui.warn(_("arguments do not match paths that need resolving\n"))
5364 5394
5365 5395 finally:
5366 5396 wlock.release()
5367 5397
5368 5398 # Nudge users into finishing an unfinished operation
5369 5399 if not list(ms.unresolved()):
5370 5400 ui.status(_('(no more unresolved files)\n'))
5371 5401
5372 5402 return ret
5373 5403
5374 5404 @command('revert',
5375 5405 [('a', 'all', None, _('revert all changes when no arguments given')),
5376 5406 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5377 5407 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
5378 5408 ('C', 'no-backup', None, _('do not save backup copies of files')),
5379 5409 ('i', 'interactive', None, _('interactively select the changes')),
5380 5410 ] + walkopts + dryrunopts,
5381 5411 _('[OPTION]... [-r REV] [NAME]...'))
5382 5412 def revert(ui, repo, *pats, **opts):
5383 5413 """restore files to their checkout state
5384 5414
5385 5415 .. note::
5386 5416
5387 5417 To check out earlier revisions, you should use :hg:`update REV`.
5388 5418 To cancel an uncommitted merge (and lose your changes),
5389 5419 use :hg:`update --clean .`.
5390 5420
5391 5421 With no revision specified, revert the specified files or directories
5392 5422 to the contents they had in the parent of the working directory.
5393 5423 This restores the contents of files to an unmodified
5394 5424 state and unschedules adds, removes, copies, and renames. If the
5395 5425 working directory has two parents, you must explicitly specify a
5396 5426 revision.
5397 5427
5398 5428 Using the -r/--rev or -d/--date options, revert the given files or
5399 5429 directories to their states as of a specific revision. Because
5400 5430 revert does not change the working directory parents, this will
5401 5431 cause these files to appear modified. This can be helpful to "back
5402 5432 out" some or all of an earlier change. See :hg:`backout` for a
5403 5433 related method.
5404 5434
5405 5435 Modified files are saved with a .orig suffix before reverting.
5406 5436 To disable these backups, use --no-backup.
5407 5437
5408 5438 See :hg:`help dates` for a list of formats valid for -d/--date.
5409 5439
5410 5440 Returns 0 on success.
5411 5441 """
5412 5442
5413 5443 if opts.get("date"):
5414 5444 if opts.get("rev"):
5415 5445 raise util.Abort(_("you can't specify a revision and a date"))
5416 5446 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
5417 5447
5418 5448 parent, p2 = repo.dirstate.parents()
5419 5449 if not opts.get('rev') and p2 != nullid:
5420 5450 # revert after merge is a trap for new users (issue2915)
5421 5451 raise util.Abort(_('uncommitted merge with no revision specified'),
5422 5452 hint=_('use "hg update" or see "hg help revert"'))
5423 5453
5424 5454 ctx = scmutil.revsingle(repo, opts.get('rev'))
5425 5455
5426 5456 if not pats and not opts.get('all'):
5427 5457 msg = _("no files or directories specified")
5428 5458 if p2 != nullid:
5429 5459 hint = _("uncommitted merge, use --all to discard all changes,"
5430 5460 " or 'hg update -C .' to abort the merge")
5431 5461 raise util.Abort(msg, hint=hint)
5432 5462 dirty = util.any(repo.status())
5433 5463 node = ctx.node()
5434 5464 if node != parent:
5435 5465 if dirty:
5436 5466 hint = _("uncommitted changes, use --all to discard all"
5437 5467 " changes, or 'hg update %s' to update") % ctx.rev()
5438 5468 else:
5439 5469 hint = _("use --all to revert all files,"
5440 5470 " or 'hg update %s' to update") % ctx.rev()
5441 5471 elif dirty:
5442 5472 hint = _("uncommitted changes, use --all to discard all changes")
5443 5473 else:
5444 5474 hint = _("use --all to revert all files")
5445 5475 raise util.Abort(msg, hint=hint)
5446 5476
5447 5477 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats, **opts)
5448 5478
5449 5479 @command('rollback', dryrunopts +
5450 5480 [('f', 'force', False, _('ignore safety measures'))])
5451 5481 def rollback(ui, repo, **opts):
5452 5482 """roll back the last transaction (DANGEROUS) (DEPRECATED)
5453 5483
5454 5484 Please use :hg:`commit --amend` instead of rollback to correct
5455 5485 mistakes in the last commit.
5456 5486
5457 5487 This command should be used with care. There is only one level of
5458 5488 rollback, and there is no way to undo a rollback. It will also
5459 5489 restore the dirstate at the time of the last transaction, losing
5460 5490 any dirstate changes since that time. This command does not alter
5461 5491 the working directory.
5462 5492
5463 5493 Transactions are used to encapsulate the effects of all commands
5464 5494 that create new changesets or propagate existing changesets into a
5465 5495 repository.
5466 5496
5467 5497 .. container:: verbose
5468 5498
5469 5499 For example, the following commands are transactional, and their
5470 5500 effects can be rolled back:
5471 5501
5472 5502 - commit
5473 5503 - import
5474 5504 - pull
5475 5505 - push (with this repository as the destination)
5476 5506 - unbundle
5477 5507
5478 5508 To avoid permanent data loss, rollback will refuse to rollback a
5479 5509 commit transaction if it isn't checked out. Use --force to
5480 5510 override this protection.
5481 5511
5482 5512 This command is not intended for use on public repositories. Once
5483 5513 changes are visible for pull by other users, rolling a transaction
5484 5514 back locally is ineffective (someone else may already have pulled
5485 5515 the changes). Furthermore, a race is possible with readers of the
5486 5516 repository; for example an in-progress pull from the repository
5487 5517 may fail if a rollback is performed.
5488 5518
5489 5519 Returns 0 on success, 1 if no rollback data is available.
5490 5520 """
5491 5521 return repo.rollback(dryrun=opts.get('dry_run'),
5492 5522 force=opts.get('force'))
5493 5523
5494 5524 @command('root', [])
5495 5525 def root(ui, repo):
5496 5526 """print the root (top) of the current working directory
5497 5527
5498 5528 Print the root directory of the current repository.
5499 5529
5500 5530 Returns 0 on success.
5501 5531 """
5502 5532 ui.write(repo.root + "\n")
5503 5533
5504 5534 @command('^serve',
5505 5535 [('A', 'accesslog', '', _('name of access log file to write to'),
5506 5536 _('FILE')),
5507 5537 ('d', 'daemon', None, _('run server in background')),
5508 5538 ('', 'daemon-pipefds', '', _('used internally by daemon mode'), _('FILE')),
5509 5539 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
5510 5540 # use string type, then we can check if something was passed
5511 5541 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
5512 5542 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
5513 5543 _('ADDR')),
5514 5544 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
5515 5545 _('PREFIX')),
5516 5546 ('n', 'name', '',
5517 5547 _('name to show in web pages (default: working directory)'), _('NAME')),
5518 5548 ('', 'web-conf', '',
5519 5549 _('name of the hgweb config file (see "hg help hgweb")'), _('FILE')),
5520 5550 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
5521 5551 _('FILE')),
5522 5552 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
5523 5553 ('', 'stdio', None, _('for remote clients')),
5524 5554 ('', 'cmdserver', '', _('for remote clients'), _('MODE')),
5525 5555 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
5526 5556 ('', 'style', '', _('template style to use'), _('STYLE')),
5527 5557 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
5528 5558 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))],
5529 5559 _('[OPTION]...'),
5530 5560 optionalrepo=True)
5531 5561 def serve(ui, repo, **opts):
5532 5562 """start stand-alone webserver
5533 5563
5534 5564 Start a local HTTP repository browser and pull server. You can use
5535 5565 this for ad-hoc sharing and browsing of repositories. It is
5536 5566 recommended to use a real web server to serve a repository for
5537 5567 longer periods of time.
5538 5568
5539 5569 Please note that the server does not implement access control.
5540 5570 This means that, by default, anybody can read from the server and
5541 5571 nobody can write to it by default. Set the ``web.allow_push``
5542 5572 option to ``*`` to allow everybody to push to the server. You
5543 5573 should use a real web server if you need to authenticate users.
5544 5574
5545 5575 By default, the server logs accesses to stdout and errors to
5546 5576 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
5547 5577 files.
5548 5578
5549 5579 To have the server choose a free port number to listen on, specify
5550 5580 a port number of 0; in this case, the server will print the port
5551 5581 number it uses.
5552 5582
5553 5583 Returns 0 on success.
5554 5584 """
5555 5585
5556 5586 if opts["stdio"] and opts["cmdserver"]:
5557 5587 raise util.Abort(_("cannot use --stdio with --cmdserver"))
5558 5588
5559 5589 if opts["stdio"]:
5560 5590 if repo is None:
5561 5591 raise error.RepoError(_("there is no Mercurial repository here"
5562 5592 " (.hg not found)"))
5563 5593 s = sshserver.sshserver(ui, repo)
5564 5594 s.serve_forever()
5565 5595
5566 5596 if opts["cmdserver"]:
5567 5597 service = commandserver.createservice(ui, repo, opts)
5568 5598 return cmdutil.service(opts, initfn=service.init, runfn=service.run)
5569 5599
5570 5600 # this way we can check if something was given in the command-line
5571 5601 if opts.get('port'):
5572 5602 opts['port'] = util.getport(opts.get('port'))
5573 5603
5574 5604 if repo:
5575 5605 baseui = repo.baseui
5576 5606 else:
5577 5607 baseui = ui
5578 5608 optlist = ("name templates style address port prefix ipv6"
5579 5609 " accesslog errorlog certificate encoding")
5580 5610 for o in optlist.split():
5581 5611 val = opts.get(o, '')
5582 5612 if val in (None, ''): # should check against default options instead
5583 5613 continue
5584 5614 baseui.setconfig("web", o, val, 'serve')
5585 5615 if repo and repo.ui != baseui:
5586 5616 repo.ui.setconfig("web", o, val, 'serve')
5587 5617
5588 5618 o = opts.get('web_conf') or opts.get('webdir_conf')
5589 5619 if not o:
5590 5620 if not repo:
5591 5621 raise error.RepoError(_("there is no Mercurial repository"
5592 5622 " here (.hg not found)"))
5593 5623 o = repo
5594 5624
5595 5625 app = hgweb.hgweb(o, baseui=baseui)
5596 5626 service = httpservice(ui, app, opts)
5597 5627 cmdutil.service(opts, initfn=service.init, runfn=service.run)
5598 5628
5599 5629 class httpservice(object):
5600 5630 def __init__(self, ui, app, opts):
5601 5631 self.ui = ui
5602 5632 self.app = app
5603 5633 self.opts = opts
5604 5634
5605 5635 def init(self):
5606 5636 util.setsignalhandler()
5607 5637 self.httpd = hgweb_server.create_server(self.ui, self.app)
5608 5638
5609 5639 if self.opts['port'] and not self.ui.verbose:
5610 5640 return
5611 5641
5612 5642 if self.httpd.prefix:
5613 5643 prefix = self.httpd.prefix.strip('/') + '/'
5614 5644 else:
5615 5645 prefix = ''
5616 5646
5617 5647 port = ':%d' % self.httpd.port
5618 5648 if port == ':80':
5619 5649 port = ''
5620 5650
5621 5651 bindaddr = self.httpd.addr
5622 5652 if bindaddr == '0.0.0.0':
5623 5653 bindaddr = '*'
5624 5654 elif ':' in bindaddr: # IPv6
5625 5655 bindaddr = '[%s]' % bindaddr
5626 5656
5627 5657 fqaddr = self.httpd.fqaddr
5628 5658 if ':' in fqaddr:
5629 5659 fqaddr = '[%s]' % fqaddr
5630 5660 if self.opts['port']:
5631 5661 write = self.ui.status
5632 5662 else:
5633 5663 write = self.ui.write
5634 5664 write(_('listening at http://%s%s/%s (bound to %s:%d)\n') %
5635 5665 (fqaddr, port, prefix, bindaddr, self.httpd.port))
5636 5666 self.ui.flush() # avoid buffering of status message
5637 5667
5638 5668 def run(self):
5639 5669 self.httpd.serve_forever()
5640 5670
5641 5671
5642 5672 @command('^status|st',
5643 5673 [('A', 'all', None, _('show status of all files')),
5644 5674 ('m', 'modified', None, _('show only modified files')),
5645 5675 ('a', 'added', None, _('show only added files')),
5646 5676 ('r', 'removed', None, _('show only removed files')),
5647 5677 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
5648 5678 ('c', 'clean', None, _('show only files without changes')),
5649 5679 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
5650 5680 ('i', 'ignored', None, _('show only ignored files')),
5651 5681 ('n', 'no-status', None, _('hide status prefix')),
5652 5682 ('C', 'copies', None, _('show source of copied files')),
5653 5683 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
5654 5684 ('', 'rev', [], _('show difference from revision'), _('REV')),
5655 5685 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
5656 5686 ] + walkopts + subrepoopts + formatteropts,
5657 5687 _('[OPTION]... [FILE]...'),
5658 5688 inferrepo=True)
5659 5689 def status(ui, repo, *pats, **opts):
5660 5690 """show changed files in the working directory
5661 5691
5662 5692 Show status of files in the repository. If names are given, only
5663 5693 files that match are shown. Files that are clean or ignored or
5664 5694 the source of a copy/move operation, are not listed unless
5665 5695 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
5666 5696 Unless options described with "show only ..." are given, the
5667 5697 options -mardu are used.
5668 5698
5669 5699 Option -q/--quiet hides untracked (unknown and ignored) files
5670 5700 unless explicitly requested with -u/--unknown or -i/--ignored.
5671 5701
5672 5702 .. note::
5673 5703
5674 5704 status may appear to disagree with diff if permissions have
5675 5705 changed or a merge has occurred. The standard diff format does
5676 5706 not report permission changes and diff only reports changes
5677 5707 relative to one merge parent.
5678 5708
5679 5709 If one revision is given, it is used as the base revision.
5680 5710 If two revisions are given, the differences between them are
5681 5711 shown. The --change option can also be used as a shortcut to list
5682 5712 the changed files of a revision from its first parent.
5683 5713
5684 5714 The codes used to show the status of files are::
5685 5715
5686 5716 M = modified
5687 5717 A = added
5688 5718 R = removed
5689 5719 C = clean
5690 5720 ! = missing (deleted by non-hg command, but still tracked)
5691 5721 ? = not tracked
5692 5722 I = ignored
5693 5723 = origin of the previous file (with --copies)
5694 5724
5695 5725 .. container:: verbose
5696 5726
5697 5727 Examples:
5698 5728
5699 5729 - show changes in the working directory relative to a
5700 5730 changeset::
5701 5731
5702 5732 hg status --rev 9353
5703 5733
5704 5734 - show all changes including copies in an existing changeset::
5705 5735
5706 5736 hg status --copies --change 9353
5707 5737
5708 5738 - get a NUL separated list of added files, suitable for xargs::
5709 5739
5710 5740 hg status -an0
5711 5741
5712 5742 Returns 0 on success.
5713 5743 """
5714 5744
5715 5745 revs = opts.get('rev')
5716 5746 change = opts.get('change')
5717 5747
5718 5748 if revs and change:
5719 5749 msg = _('cannot specify --rev and --change at the same time')
5720 5750 raise util.Abort(msg)
5721 5751 elif change:
5722 5752 node2 = scmutil.revsingle(repo, change, None).node()
5723 5753 node1 = repo[node2].p1().node()
5724 5754 else:
5725 5755 node1, node2 = scmutil.revpair(repo, revs)
5726 5756
5727 5757 if pats:
5728 5758 cwd = repo.getcwd()
5729 5759 else:
5730 5760 cwd = ''
5731 5761
5732 5762 if opts.get('print0'):
5733 5763 end = '\0'
5734 5764 else:
5735 5765 end = '\n'
5736 5766 copy = {}
5737 5767 states = 'modified added removed deleted unknown ignored clean'.split()
5738 5768 show = [k for k in states if opts.get(k)]
5739 5769 if opts.get('all'):
5740 5770 show += ui.quiet and (states[:4] + ['clean']) or states
5741 5771 if not show:
5742 5772 if ui.quiet:
5743 5773 show = states[:4]
5744 5774 else:
5745 5775 show = states[:5]
5746 5776
5747 5777 stat = repo.status(node1, node2, scmutil.match(repo[node2], pats, opts),
5748 5778 'ignored' in show, 'clean' in show, 'unknown' in show,
5749 5779 opts.get('subrepos'))
5750 5780 changestates = zip(states, 'MAR!?IC', stat)
5751 5781
5752 5782 if (opts.get('all') or opts.get('copies')) and not opts.get('no_status'):
5753 5783 copy = copies.pathcopies(repo[node1], repo[node2])
5754 5784
5755 5785 fm = ui.formatter('status', opts)
5756 5786 fmt = '%s' + end
5757 5787 showchar = not opts.get('no_status')
5758 5788
5759 5789 for state, char, files in changestates:
5760 5790 if state in show:
5761 5791 label = 'status.' + state
5762 5792 for f in files:
5763 5793 fm.startitem()
5764 5794 fm.condwrite(showchar, 'status', '%s ', char, label=label)
5765 5795 fm.write('path', fmt, repo.pathto(f, cwd), label=label)
5766 5796 if f in copy:
5767 5797 fm.write("copy", ' %s' + end, repo.pathto(copy[f], cwd),
5768 5798 label='status.copied')
5769 5799 fm.end()
5770 5800
5771 5801 @command('^summary|sum',
5772 5802 [('', 'remote', None, _('check for push and pull'))], '[--remote]')
5773 5803 def summary(ui, repo, **opts):
5774 5804 """summarize working directory state
5775 5805
5776 5806 This generates a brief summary of the working directory state,
5777 5807 including parents, branch, commit status, and available updates.
5778 5808
5779 5809 With the --remote option, this will check the default paths for
5780 5810 incoming and outgoing changes. This can be time-consuming.
5781 5811
5782 5812 Returns 0 on success.
5783 5813 """
5784 5814
5785 5815 ctx = repo[None]
5786 5816 parents = ctx.parents()
5787 5817 pnode = parents[0].node()
5788 5818 marks = []
5789 5819
5790 5820 for p in parents:
5791 5821 # label with log.changeset (instead of log.parent) since this
5792 5822 # shows a working directory parent *changeset*:
5793 5823 # i18n: column positioning for "hg summary"
5794 5824 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
5795 5825 label='log.changeset changeset.%s' % p.phasestr())
5796 5826 ui.write(' '.join(p.tags()), label='log.tag')
5797 5827 if p.bookmarks():
5798 5828 marks.extend(p.bookmarks())
5799 5829 if p.rev() == -1:
5800 5830 if not len(repo):
5801 5831 ui.write(_(' (empty repository)'))
5802 5832 else:
5803 5833 ui.write(_(' (no revision checked out)'))
5804 5834 ui.write('\n')
5805 5835 if p.description():
5806 5836 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
5807 5837 label='log.summary')
5808 5838
5809 5839 branch = ctx.branch()
5810 5840 bheads = repo.branchheads(branch)
5811 5841 # i18n: column positioning for "hg summary"
5812 5842 m = _('branch: %s\n') % branch
5813 5843 if branch != 'default':
5814 5844 ui.write(m, label='log.branch')
5815 5845 else:
5816 5846 ui.status(m, label='log.branch')
5817 5847
5818 5848 if marks:
5819 5849 current = repo._bookmarkcurrent
5820 5850 # i18n: column positioning for "hg summary"
5821 5851 ui.write(_('bookmarks:'), label='log.bookmark')
5822 5852 if current is not None:
5823 5853 if current in marks:
5824 5854 ui.write(' *' + current, label='bookmarks.current')
5825 5855 marks.remove(current)
5826 5856 else:
5827 5857 ui.write(' [%s]' % current, label='bookmarks.current')
5828 5858 for m in marks:
5829 5859 ui.write(' ' + m, label='log.bookmark')
5830 5860 ui.write('\n', label='log.bookmark')
5831 5861
5832 5862 status = repo.status(unknown=True)
5833 5863
5834 5864 c = repo.dirstate.copies()
5835 5865 copied, renamed = [], []
5836 5866 for d, s in c.iteritems():
5837 5867 if s in status.removed:
5838 5868 status.removed.remove(s)
5839 5869 renamed.append(d)
5840 5870 else:
5841 5871 copied.append(d)
5842 5872 if d in status.added:
5843 5873 status.added.remove(d)
5844 5874
5845 5875 ms = mergemod.mergestate(repo)
5846 5876 unresolved = [f for f in ms if ms[f] == 'u']
5847 5877
5848 5878 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
5849 5879
5850 5880 labels = [(ui.label(_('%d modified'), 'status.modified'), status.modified),
5851 5881 (ui.label(_('%d added'), 'status.added'), status.added),
5852 5882 (ui.label(_('%d removed'), 'status.removed'), status.removed),
5853 5883 (ui.label(_('%d renamed'), 'status.copied'), renamed),
5854 5884 (ui.label(_('%d copied'), 'status.copied'), copied),
5855 5885 (ui.label(_('%d deleted'), 'status.deleted'), status.deleted),
5856 5886 (ui.label(_('%d unknown'), 'status.unknown'), status.unknown),
5857 5887 (ui.label(_('%d unresolved'), 'resolve.unresolved'), unresolved),
5858 5888 (ui.label(_('%d subrepos'), 'status.modified'), subs)]
5859 5889 t = []
5860 5890 for l, s in labels:
5861 5891 if s:
5862 5892 t.append(l % len(s))
5863 5893
5864 5894 t = ', '.join(t)
5865 5895 cleanworkdir = False
5866 5896
5867 5897 if repo.vfs.exists('updatestate'):
5868 5898 t += _(' (interrupted update)')
5869 5899 elif len(parents) > 1:
5870 5900 t += _(' (merge)')
5871 5901 elif branch != parents[0].branch():
5872 5902 t += _(' (new branch)')
5873 5903 elif (parents[0].closesbranch() and
5874 5904 pnode in repo.branchheads(branch, closed=True)):
5875 5905 t += _(' (head closed)')
5876 5906 elif not (status.modified or status.added or status.removed or renamed or
5877 5907 copied or subs):
5878 5908 t += _(' (clean)')
5879 5909 cleanworkdir = True
5880 5910 elif pnode not in bheads:
5881 5911 t += _(' (new branch head)')
5882 5912
5883 5913 if cleanworkdir:
5884 5914 # i18n: column positioning for "hg summary"
5885 5915 ui.status(_('commit: %s\n') % t.strip())
5886 5916 else:
5887 5917 # i18n: column positioning for "hg summary"
5888 5918 ui.write(_('commit: %s\n') % t.strip())
5889 5919
5890 5920 # all ancestors of branch heads - all ancestors of parent = new csets
5891 5921 new = len(repo.changelog.findmissing([pctx.node() for pctx in parents],
5892 5922 bheads))
5893 5923
5894 5924 if new == 0:
5895 5925 # i18n: column positioning for "hg summary"
5896 5926 ui.status(_('update: (current)\n'))
5897 5927 elif pnode not in bheads:
5898 5928 # i18n: column positioning for "hg summary"
5899 5929 ui.write(_('update: %d new changesets (update)\n') % new)
5900 5930 else:
5901 5931 # i18n: column positioning for "hg summary"
5902 5932 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
5903 5933 (new, len(bheads)))
5904 5934
5905 5935 cmdutil.summaryhooks(ui, repo)
5906 5936
5907 5937 if opts.get('remote'):
5908 5938 needsincoming, needsoutgoing = True, True
5909 5939 else:
5910 5940 needsincoming, needsoutgoing = False, False
5911 5941 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
5912 5942 if i:
5913 5943 needsincoming = True
5914 5944 if o:
5915 5945 needsoutgoing = True
5916 5946 if not needsincoming and not needsoutgoing:
5917 5947 return
5918 5948
5919 5949 def getincoming():
5920 5950 source, branches = hg.parseurl(ui.expandpath('default'))
5921 5951 sbranch = branches[0]
5922 5952 try:
5923 5953 other = hg.peer(repo, {}, source)
5924 5954 except error.RepoError:
5925 5955 if opts.get('remote'):
5926 5956 raise
5927 5957 return source, sbranch, None, None, None
5928 5958 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
5929 5959 if revs:
5930 5960 revs = [other.lookup(rev) for rev in revs]
5931 5961 ui.debug('comparing with %s\n' % util.hidepassword(source))
5932 5962 repo.ui.pushbuffer()
5933 5963 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
5934 5964 repo.ui.popbuffer()
5935 5965 return source, sbranch, other, commoninc, commoninc[1]
5936 5966
5937 5967 if needsincoming:
5938 5968 source, sbranch, sother, commoninc, incoming = getincoming()
5939 5969 else:
5940 5970 source = sbranch = sother = commoninc = incoming = None
5941 5971
5942 5972 def getoutgoing():
5943 5973 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
5944 5974 dbranch = branches[0]
5945 5975 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
5946 5976 if source != dest:
5947 5977 try:
5948 5978 dother = hg.peer(repo, {}, dest)
5949 5979 except error.RepoError:
5950 5980 if opts.get('remote'):
5951 5981 raise
5952 5982 return dest, dbranch, None, None
5953 5983 ui.debug('comparing with %s\n' % util.hidepassword(dest))
5954 5984 elif sother is None:
5955 5985 # there is no explicit destination peer, but source one is invalid
5956 5986 return dest, dbranch, None, None
5957 5987 else:
5958 5988 dother = sother
5959 5989 if (source != dest or (sbranch is not None and sbranch != dbranch)):
5960 5990 common = None
5961 5991 else:
5962 5992 common = commoninc
5963 5993 if revs:
5964 5994 revs = [repo.lookup(rev) for rev in revs]
5965 5995 repo.ui.pushbuffer()
5966 5996 outgoing = discovery.findcommonoutgoing(repo, dother, onlyheads=revs,
5967 5997 commoninc=common)
5968 5998 repo.ui.popbuffer()
5969 5999 return dest, dbranch, dother, outgoing
5970 6000
5971 6001 if needsoutgoing:
5972 6002 dest, dbranch, dother, outgoing = getoutgoing()
5973 6003 else:
5974 6004 dest = dbranch = dother = outgoing = None
5975 6005
5976 6006 if opts.get('remote'):
5977 6007 t = []
5978 6008 if incoming:
5979 6009 t.append(_('1 or more incoming'))
5980 6010 o = outgoing.missing
5981 6011 if o:
5982 6012 t.append(_('%d outgoing') % len(o))
5983 6013 other = dother or sother
5984 6014 if 'bookmarks' in other.listkeys('namespaces'):
5985 6015 counts = bookmarks.summary(repo, other)
5986 6016 if counts[0] > 0:
5987 6017 t.append(_('%d incoming bookmarks') % counts[0])
5988 6018 if counts[1] > 0:
5989 6019 t.append(_('%d outgoing bookmarks') % counts[1])
5990 6020
5991 6021 if t:
5992 6022 # i18n: column positioning for "hg summary"
5993 6023 ui.write(_('remote: %s\n') % (', '.join(t)))
5994 6024 else:
5995 6025 # i18n: column positioning for "hg summary"
5996 6026 ui.status(_('remote: (synced)\n'))
5997 6027
5998 6028 cmdutil.summaryremotehooks(ui, repo, opts,
5999 6029 ((source, sbranch, sother, commoninc),
6000 6030 (dest, dbranch, dother, outgoing)))
6001 6031
6002 6032 @command('tag',
6003 6033 [('f', 'force', None, _('force tag')),
6004 6034 ('l', 'local', None, _('make the tag local')),
6005 6035 ('r', 'rev', '', _('revision to tag'), _('REV')),
6006 6036 ('', 'remove', None, _('remove a tag')),
6007 6037 # -l/--local is already there, commitopts cannot be used
6008 6038 ('e', 'edit', None, _('invoke editor on commit messages')),
6009 6039 ('m', 'message', '', _('use text as commit message'), _('TEXT')),
6010 6040 ] + commitopts2,
6011 6041 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
6012 6042 def tag(ui, repo, name1, *names, **opts):
6013 6043 """add one or more tags for the current or given revision
6014 6044
6015 6045 Name a particular revision using <name>.
6016 6046
6017 6047 Tags are used to name particular revisions of the repository and are
6018 6048 very useful to compare different revisions, to go back to significant
6019 6049 earlier versions or to mark branch points as releases, etc. Changing
6020 6050 an existing tag is normally disallowed; use -f/--force to override.
6021 6051
6022 6052 If no revision is given, the parent of the working directory is
6023 6053 used.
6024 6054
6025 6055 To facilitate version control, distribution, and merging of tags,
6026 6056 they are stored as a file named ".hgtags" which is managed similarly
6027 6057 to other project files and can be hand-edited if necessary. This
6028 6058 also means that tagging creates a new commit. The file
6029 6059 ".hg/localtags" is used for local tags (not shared among
6030 6060 repositories).
6031 6061
6032 6062 Tag commits are usually made at the head of a branch. If the parent
6033 6063 of the working directory is not a branch head, :hg:`tag` aborts; use
6034 6064 -f/--force to force the tag commit to be based on a non-head
6035 6065 changeset.
6036 6066
6037 6067 See :hg:`help dates` for a list of formats valid for -d/--date.
6038 6068
6039 6069 Since tag names have priority over branch names during revision
6040 6070 lookup, using an existing branch name as a tag name is discouraged.
6041 6071
6042 6072 Returns 0 on success.
6043 6073 """
6044 6074 wlock = lock = None
6045 6075 try:
6046 6076 wlock = repo.wlock()
6047 6077 lock = repo.lock()
6048 6078 rev_ = "."
6049 6079 names = [t.strip() for t in (name1,) + names]
6050 6080 if len(names) != len(set(names)):
6051 6081 raise util.Abort(_('tag names must be unique'))
6052 6082 for n in names:
6053 6083 scmutil.checknewlabel(repo, n, 'tag')
6054 6084 if not n:
6055 6085 raise util.Abort(_('tag names cannot consist entirely of '
6056 6086 'whitespace'))
6057 6087 if opts.get('rev') and opts.get('remove'):
6058 6088 raise util.Abort(_("--rev and --remove are incompatible"))
6059 6089 if opts.get('rev'):
6060 6090 rev_ = opts['rev']
6061 6091 message = opts.get('message')
6062 6092 if opts.get('remove'):
6063 6093 if opts.get('local'):
6064 6094 expectedtype = 'local'
6065 6095 else:
6066 6096 expectedtype = 'global'
6067 6097
6068 6098 for n in names:
6069 6099 if not repo.tagtype(n):
6070 6100 raise util.Abort(_("tag '%s' does not exist") % n)
6071 6101 if repo.tagtype(n) != expectedtype:
6072 6102 if expectedtype == 'global':
6073 6103 raise util.Abort(_("tag '%s' is not a global tag") % n)
6074 6104 else:
6075 6105 raise util.Abort(_("tag '%s' is not a local tag") % n)
6076 6106 rev_ = nullid
6077 6107 if not message:
6078 6108 # we don't translate commit messages
6079 6109 message = 'Removed tag %s' % ', '.join(names)
6080 6110 elif not opts.get('force'):
6081 6111 for n in names:
6082 6112 if n in repo.tags():
6083 6113 raise util.Abort(_("tag '%s' already exists "
6084 6114 "(use -f to force)") % n)
6085 6115 if not opts.get('local'):
6086 6116 p1, p2 = repo.dirstate.parents()
6087 6117 if p2 != nullid:
6088 6118 raise util.Abort(_('uncommitted merge'))
6089 6119 bheads = repo.branchheads()
6090 6120 if not opts.get('force') and bheads and p1 not in bheads:
6091 6121 raise util.Abort(_('not at a branch head (use -f to force)'))
6092 6122 r = scmutil.revsingle(repo, rev_).node()
6093 6123
6094 6124 if not message:
6095 6125 # we don't translate commit messages
6096 6126 message = ('Added tag %s for changeset %s' %
6097 6127 (', '.join(names), short(r)))
6098 6128
6099 6129 date = opts.get('date')
6100 6130 if date:
6101 6131 date = util.parsedate(date)
6102 6132
6103 6133 if opts.get('remove'):
6104 6134 editform = 'tag.remove'
6105 6135 else:
6106 6136 editform = 'tag.add'
6107 6137 editor = cmdutil.getcommiteditor(editform=editform, **opts)
6108 6138
6109 6139 # don't allow tagging the null rev
6110 6140 if (not opts.get('remove') and
6111 6141 scmutil.revsingle(repo, rev_).rev() == nullrev):
6112 6142 raise util.Abort(_("cannot tag null revision"))
6113 6143
6114 6144 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date,
6115 6145 editor=editor)
6116 6146 finally:
6117 6147 release(lock, wlock)
6118 6148
6119 6149 @command('tags', formatteropts, '')
6120 6150 def tags(ui, repo, **opts):
6121 6151 """list repository tags
6122 6152
6123 6153 This lists both regular and local tags. When the -v/--verbose
6124 6154 switch is used, a third column "local" is printed for local tags.
6125 6155
6126 6156 Returns 0 on success.
6127 6157 """
6128 6158
6129 6159 fm = ui.formatter('tags', opts)
6130 6160 hexfunc = fm.hexfunc
6131 6161 tagtype = ""
6132 6162
6133 6163 for t, n in reversed(repo.tagslist()):
6134 6164 hn = hexfunc(n)
6135 6165 label = 'tags.normal'
6136 6166 tagtype = ''
6137 6167 if repo.tagtype(t) == 'local':
6138 6168 label = 'tags.local'
6139 6169 tagtype = 'local'
6140 6170
6141 6171 fm.startitem()
6142 6172 fm.write('tag', '%s', t, label=label)
6143 6173 fmt = " " * (30 - encoding.colwidth(t)) + ' %5d:%s'
6144 6174 fm.condwrite(not ui.quiet, 'rev node', fmt,
6145 6175 repo.changelog.rev(n), hn, label=label)
6146 6176 fm.condwrite(ui.verbose and tagtype, 'type', ' %s',
6147 6177 tagtype, label=label)
6148 6178 fm.plain('\n')
6149 6179 fm.end()
6150 6180
6151 6181 @command('tip',
6152 6182 [('p', 'patch', None, _('show patch')),
6153 6183 ('g', 'git', None, _('use git extended diff format')),
6154 6184 ] + templateopts,
6155 6185 _('[-p] [-g]'))
6156 6186 def tip(ui, repo, **opts):
6157 6187 """show the tip revision (DEPRECATED)
6158 6188
6159 6189 The tip revision (usually just called the tip) is the changeset
6160 6190 most recently added to the repository (and therefore the most
6161 6191 recently changed head).
6162 6192
6163 6193 If you have just made a commit, that commit will be the tip. If
6164 6194 you have just pulled changes from another repository, the tip of
6165 6195 that repository becomes the current tip. The "tip" tag is special
6166 6196 and cannot be renamed or assigned to a different changeset.
6167 6197
6168 6198 This command is deprecated, please use :hg:`heads` instead.
6169 6199
6170 6200 Returns 0 on success.
6171 6201 """
6172 6202 displayer = cmdutil.show_changeset(ui, repo, opts)
6173 6203 displayer.show(repo['tip'])
6174 6204 displayer.close()
6175 6205
6176 6206 @command('unbundle',
6177 6207 [('u', 'update', None,
6178 6208 _('update to new branch head if changesets were unbundled'))],
6179 6209 _('[-u] FILE...'))
6180 6210 def unbundle(ui, repo, fname1, *fnames, **opts):
6181 6211 """apply one or more changegroup files
6182 6212
6183 6213 Apply one or more compressed changegroup files generated by the
6184 6214 bundle command.
6185 6215
6186 6216 Returns 0 on success, 1 if an update has unresolved files.
6187 6217 """
6188 6218 fnames = (fname1,) + fnames
6189 6219
6190 6220 lock = repo.lock()
6191 6221 try:
6192 6222 for fname in fnames:
6193 6223 f = hg.openpath(ui, fname)
6194 6224 gen = exchange.readbundle(ui, f, fname)
6195 6225 if isinstance(gen, bundle2.unbundle20):
6196 6226 tr = repo.transaction('unbundle')
6197 6227 try:
6198 6228 op = bundle2.processbundle(repo, gen, lambda: tr)
6199 6229 tr.close()
6200 6230 finally:
6201 6231 if tr:
6202 6232 tr.release()
6203 6233 changes = [r.get('result', 0)
6204 6234 for r in op.records['changegroup']]
6205 6235 modheads = changegroup.combineresults(changes)
6206 6236 else:
6207 6237 modheads = changegroup.addchangegroup(repo, gen, 'unbundle',
6208 6238 'bundle:' + fname)
6209 6239 finally:
6210 6240 lock.release()
6211 6241
6212 6242 return postincoming(ui, repo, modheads, opts.get('update'), None)
6213 6243
6214 6244 @command('^update|up|checkout|co',
6215 6245 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
6216 6246 ('c', 'check', None,
6217 6247 _('update across branches if no uncommitted changes')),
6218 6248 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
6219 6249 ('r', 'rev', '', _('revision'), _('REV'))
6220 6250 ] + mergetoolopts,
6221 6251 _('[-c] [-C] [-d DATE] [[-r] REV]'))
6222 6252 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False,
6223 6253 tool=None):
6224 6254 """update working directory (or switch revisions)
6225 6255
6226 6256 Update the repository's working directory to the specified
6227 6257 changeset. If no changeset is specified, update to the tip of the
6228 6258 current named branch and move the current bookmark (see :hg:`help
6229 6259 bookmarks`).
6230 6260
6231 6261 Update sets the working directory's parent revision to the specified
6232 6262 changeset (see :hg:`help parents`).
6233 6263
6234 6264 If the changeset is not a descendant or ancestor of the working
6235 6265 directory's parent, the update is aborted. With the -c/--check
6236 6266 option, the working directory is checked for uncommitted changes; if
6237 6267 none are found, the working directory is updated to the specified
6238 6268 changeset.
6239 6269
6240 6270 .. container:: verbose
6241 6271
6242 6272 The following rules apply when the working directory contains
6243 6273 uncommitted changes:
6244 6274
6245 6275 1. If neither -c/--check nor -C/--clean is specified, and if
6246 6276 the requested changeset is an ancestor or descendant of
6247 6277 the working directory's parent, the uncommitted changes
6248 6278 are merged into the requested changeset and the merged
6249 6279 result is left uncommitted. If the requested changeset is
6250 6280 not an ancestor or descendant (that is, it is on another
6251 6281 branch), the update is aborted and the uncommitted changes
6252 6282 are preserved.
6253 6283
6254 6284 2. With the -c/--check option, the update is aborted and the
6255 6285 uncommitted changes are preserved.
6256 6286
6257 6287 3. With the -C/--clean option, uncommitted changes are discarded and
6258 6288 the working directory is updated to the requested changeset.
6259 6289
6260 6290 To cancel an uncommitted merge (and lose your changes), use
6261 6291 :hg:`update --clean .`.
6262 6292
6263 6293 Use null as the changeset to remove the working directory (like
6264 6294 :hg:`clone -U`).
6265 6295
6266 6296 If you want to revert just one file to an older revision, use
6267 6297 :hg:`revert [-r REV] NAME`.
6268 6298
6269 6299 See :hg:`help dates` for a list of formats valid for -d/--date.
6270 6300
6271 6301 Returns 0 on success, 1 if there are unresolved files.
6272 6302 """
6273 6303 if rev and node:
6274 6304 raise util.Abort(_("please specify just one revision"))
6275 6305
6276 6306 if rev is None or rev == '':
6277 6307 rev = node
6278 6308
6279 6309 cmdutil.clearunfinished(repo)
6280 6310
6281 6311 # with no argument, we also move the current bookmark, if any
6282 6312 rev, movemarkfrom = bookmarks.calculateupdate(ui, repo, rev)
6283 6313
6284 6314 # if we defined a bookmark, we have to remember the original bookmark name
6285 6315 brev = rev
6286 6316 rev = scmutil.revsingle(repo, rev, rev).rev()
6287 6317
6288 6318 if check and clean:
6289 6319 raise util.Abort(_("cannot specify both -c/--check and -C/--clean"))
6290 6320
6291 6321 if date:
6292 6322 if rev is not None:
6293 6323 raise util.Abort(_("you can't specify a revision and a date"))
6294 6324 rev = cmdutil.finddate(ui, repo, date)
6295 6325
6296 6326 if check:
6297 6327 c = repo[None]
6298 6328 if c.dirty(merge=False, branch=False, missing=True):
6299 6329 raise util.Abort(_("uncommitted changes"))
6300 6330 if rev is None:
6301 6331 rev = repo[repo[None].branch()].rev()
6302 6332
6303 6333 repo.ui.setconfig('ui', 'forcemerge', tool, 'update')
6304 6334
6305 6335 if clean:
6306 6336 ret = hg.clean(repo, rev)
6307 6337 else:
6308 6338 ret = hg.update(repo, rev)
6309 6339
6310 6340 if not ret and movemarkfrom:
6311 6341 if bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
6312 6342 ui.status(_("updating bookmark %s\n") % repo._bookmarkcurrent)
6313 6343 elif brev in repo._bookmarks:
6314 6344 bookmarks.setcurrent(repo, brev)
6315 6345 ui.status(_("(activating bookmark %s)\n") % brev)
6316 6346 elif brev:
6317 6347 if repo._bookmarkcurrent:
6318 6348 ui.status(_("(leaving bookmark %s)\n") %
6319 6349 repo._bookmarkcurrent)
6320 6350 bookmarks.unsetcurrent(repo)
6321 6351
6322 6352 return ret
6323 6353
6324 6354 @command('verify', [])
6325 6355 def verify(ui, repo):
6326 6356 """verify the integrity of the repository
6327 6357
6328 6358 Verify the integrity of the current repository.
6329 6359
6330 6360 This will perform an extensive check of the repository's
6331 6361 integrity, validating the hashes and checksums of each entry in
6332 6362 the changelog, manifest, and tracked files, as well as the
6333 6363 integrity of their crosslinks and indices.
6334 6364
6335 6365 Please see http://mercurial.selenic.com/wiki/RepositoryCorruption
6336 6366 for more information about recovery from corruption of the
6337 6367 repository.
6338 6368
6339 6369 Returns 0 on success, 1 if errors are encountered.
6340 6370 """
6341 6371 return hg.verify(repo)
6342 6372
6343 6373 @command('version', [], norepo=True)
6344 6374 def version_(ui):
6345 6375 """output version and copyright information"""
6346 6376 ui.write(_("Mercurial Distributed SCM (version %s)\n")
6347 6377 % util.version())
6348 6378 ui.status(_(
6349 6379 "(see http://mercurial.selenic.com for more information)\n"
6350 6380 "\nCopyright (C) 2005-2015 Matt Mackall and others\n"
6351 6381 "This is free software; see the source for copying conditions. "
6352 6382 "There is NO\nwarranty; "
6353 6383 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
6354 6384 ))
6355 6385
6356 6386 ui.note(_("\nEnabled extensions:\n\n"))
6357 6387 if ui.verbose:
6358 6388 # format names and versions into columns
6359 6389 names = []
6360 6390 vers = []
6361 6391 for name, module in extensions.extensions():
6362 6392 names.append(name)
6363 6393 vers.append(extensions.moduleversion(module))
6364 6394 if names:
6365 6395 maxnamelen = max(len(n) for n in names)
6366 6396 for i, name in enumerate(names):
6367 6397 ui.write(" %-*s %s\n" % (maxnamelen, name, vers[i]))
@@ -1,519 +1,589
1 1 $ HGMERGE=true; export HGMERGE
2 2
3 3 init
4 4
5 5 $ hg init repo
6 6 $ cd repo
7 7
8 8 commit
9 9
10 10 $ echo 'a' > a
11 11 $ hg ci -A -m test -u nobody -d '1 0'
12 12 adding a
13 13
14 14 annotate -c
15 15
16 16 $ hg annotate -c a
17 17 8435f90966e4: a
18 18
19 19 annotate -cl
20 20
21 21 $ hg annotate -cl a
22 22 8435f90966e4:1: a
23 23
24 24 annotate -d
25 25
26 26 $ hg annotate -d a
27 27 Thu Jan 01 00:00:01 1970 +0000: a
28 28
29 29 annotate -n
30 30
31 31 $ hg annotate -n a
32 32 0: a
33 33
34 34 annotate -nl
35 35
36 36 $ hg annotate -nl a
37 37 0:1: a
38 38
39 39 annotate -u
40 40
41 41 $ hg annotate -u a
42 42 nobody: a
43 43
44 44 annotate -cdnu
45 45
46 46 $ hg annotate -cdnu a
47 47 nobody 0 8435f90966e4 Thu Jan 01 00:00:01 1970 +0000: a
48 48
49 49 annotate -cdnul
50 50
51 51 $ hg annotate -cdnul a
52 52 nobody 0 8435f90966e4 Thu Jan 01 00:00:01 1970 +0000:1: a
53 53
54 54 annotate (JSON)
55 55
56 56 $ hg annotate -Tjson a
57 57 [
58 58 {
59 59 "line": "a\n",
60 60 "rev": 0
61 61 }
62 62 ]
63 63
64 64 $ hg annotate -Tjson -cdfnul a
65 65 [
66 66 {
67 67 "date": [1.0, 0],
68 68 "file": "a",
69 69 "line": "a\n",
70 70 "line_number": 1,
71 71 "node": "8435f90966e442695d2ded29fdade2bac5ad8065",
72 72 "rev": 0,
73 73 "user": "nobody"
74 74 }
75 75 ]
76 76
77 77 $ cat <<EOF >>a
78 78 > a
79 79 > a
80 80 > EOF
81 81 $ hg ci -ma1 -d '1 0'
82 82 $ hg cp a b
83 83 $ hg ci -mb -d '1 0'
84 84 $ cat <<EOF >> b
85 85 > b4
86 86 > b5
87 87 > b6
88 88 > EOF
89 89 $ hg ci -mb2 -d '2 0'
90 90
91 91 annotate -n b
92 92
93 93 $ hg annotate -n b
94 94 0: a
95 95 1: a
96 96 1: a
97 97 3: b4
98 98 3: b5
99 99 3: b6
100 100
101 101 annotate --no-follow b
102 102
103 103 $ hg annotate --no-follow b
104 104 2: a
105 105 2: a
106 106 2: a
107 107 3: b4
108 108 3: b5
109 109 3: b6
110 110
111 111 annotate -nl b
112 112
113 113 $ hg annotate -nl b
114 114 0:1: a
115 115 1:2: a
116 116 1:3: a
117 117 3:4: b4
118 118 3:5: b5
119 119 3:6: b6
120 120
121 121 annotate -nf b
122 122
123 123 $ hg annotate -nf b
124 124 0 a: a
125 125 1 a: a
126 126 1 a: a
127 127 3 b: b4
128 128 3 b: b5
129 129 3 b: b6
130 130
131 131 annotate -nlf b
132 132
133 133 $ hg annotate -nlf b
134 134 0 a:1: a
135 135 1 a:2: a
136 136 1 a:3: a
137 137 3 b:4: b4
138 138 3 b:5: b5
139 139 3 b:6: b6
140 140
141 141 $ hg up -C 2
142 142 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
143 143 $ cat <<EOF >> b
144 144 > b4
145 145 > c
146 146 > b5
147 147 > EOF
148 148 $ hg ci -mb2.1 -d '2 0'
149 149 created new head
150 150 $ hg merge
151 151 merging b
152 152 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
153 153 (branch merge, don't forget to commit)
154 154 $ hg ci -mmergeb -d '3 0'
155 155
156 156 annotate after merge
157 157
158 158 $ hg annotate -nf b
159 159 0 a: a
160 160 1 a: a
161 161 1 a: a
162 162 3 b: b4
163 163 4 b: c
164 164 3 b: b5
165 165
166 166 annotate after merge with -l
167 167
168 168 $ hg annotate -nlf b
169 169 0 a:1: a
170 170 1 a:2: a
171 171 1 a:3: a
172 172 3 b:4: b4
173 173 4 b:5: c
174 174 3 b:5: b5
175 175
176 176 $ hg up -C 1
177 177 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
178 178 $ hg cp a b
179 179 $ cat <<EOF > b
180 180 > a
181 181 > z
182 182 > a
183 183 > EOF
184 184 $ hg ci -mc -d '3 0'
185 185 created new head
186 186 $ hg merge
187 187 merging b
188 188 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
189 189 (branch merge, don't forget to commit)
190 190 $ cat <<EOF >> b
191 191 > b4
192 192 > c
193 193 > b5
194 194 > EOF
195 195 $ echo d >> b
196 196 $ hg ci -mmerge2 -d '4 0'
197 197
198 198 annotate after rename merge
199 199
200 200 $ hg annotate -nf b
201 201 0 a: a
202 202 6 b: z
203 203 1 a: a
204 204 3 b: b4
205 205 4 b: c
206 206 3 b: b5
207 207 7 b: d
208 208
209 209 annotate after rename merge with -l
210 210
211 211 $ hg annotate -nlf b
212 212 0 a:1: a
213 213 6 b:2: z
214 214 1 a:3: a
215 215 3 b:4: b4
216 216 4 b:5: c
217 217 3 b:5: b5
218 218 7 b:7: d
219 219
220 220 Issue2807: alignment of line numbers with -l
221 221
222 222 $ echo more >> b
223 223 $ hg ci -mmore -d '5 0'
224 224 $ echo more >> b
225 225 $ hg ci -mmore -d '6 0'
226 226 $ echo more >> b
227 227 $ hg ci -mmore -d '7 0'
228 228 $ hg annotate -nlf b
229 229 0 a: 1: a
230 230 6 b: 2: z
231 231 1 a: 3: a
232 232 3 b: 4: b4
233 233 4 b: 5: c
234 234 3 b: 5: b5
235 235 7 b: 7: d
236 236 8 b: 8: more
237 237 9 b: 9: more
238 238 10 b:10: more
239 239
240 240 linkrev vs rev
241 241
242 242 $ hg annotate -r tip -n a
243 243 0: a
244 244 1: a
245 245 1: a
246 246
247 247 linkrev vs rev with -l
248 248
249 249 $ hg annotate -r tip -nl a
250 250 0:1: a
251 251 1:2: a
252 252 1:3: a
253 253
254 254 Issue589: "undelete" sequence leads to crash
255 255
256 256 annotate was crashing when trying to --follow something
257 257
258 258 like A -> B -> A
259 259
260 260 generate ABA rename configuration
261 261
262 262 $ echo foo > foo
263 263 $ hg add foo
264 264 $ hg ci -m addfoo
265 265 $ hg rename foo bar
266 266 $ hg ci -m renamefoo
267 267 $ hg rename bar foo
268 268 $ hg ci -m renamebar
269 269
270 270 annotate after ABA with follow
271 271
272 272 $ hg annotate --follow foo
273 273 foo: foo
274 274
275 275 missing file
276 276
277 277 $ hg ann nosuchfile
278 278 abort: nosuchfile: no such file in rev e9e6b4fa872f
279 279 [255]
280 280
281 281 annotate file without '\n' on last line
282 282
283 283 $ printf "" > c
284 284 $ hg ci -A -m test -u nobody -d '1 0'
285 285 adding c
286 286 $ hg annotate c
287 287 $ printf "a\nb" > c
288 288 $ hg ci -m test
289 289 $ hg annotate c
290 290 [0-9]+: a (re)
291 291 [0-9]+: b (re)
292 292
293 293 Issue3841: check annotation of the file of which filelog includes
294 294 merging between the revision and its ancestor
295 295
296 296 to reproduce the situation with recent Mercurial, this script uses (1)
297 297 "hg debugsetparents" to merge without ancestor check by "hg merge",
298 298 and (2) the extension to allow filelog merging between the revision
299 299 and its ancestor by overriding "repo._filecommit".
300 300
301 301 $ cat > ../legacyrepo.py <<EOF
302 302 > from mercurial import node, util
303 303 > def reposetup(ui, repo):
304 304 > class legacyrepo(repo.__class__):
305 305 > def _filecommit(self, fctx, manifest1, manifest2,
306 306 > linkrev, tr, changelist):
307 307 > fname = fctx.path()
308 308 > text = fctx.data()
309 309 > flog = self.file(fname)
310 310 > fparent1 = manifest1.get(fname, node.nullid)
311 311 > fparent2 = manifest2.get(fname, node.nullid)
312 312 > meta = {}
313 313 > copy = fctx.renamed()
314 314 > if copy and copy[0] != fname:
315 315 > raise util.Abort('copying is not supported')
316 316 > if fparent2 != node.nullid:
317 317 > changelist.append(fname)
318 318 > return flog.add(text, meta, tr, linkrev,
319 319 > fparent1, fparent2)
320 320 > raise util.Abort('only merging is supported')
321 321 > repo.__class__ = legacyrepo
322 322 > EOF
323 323
324 324 $ cat > baz <<EOF
325 325 > 1
326 326 > 2
327 327 > 3
328 328 > 4
329 329 > 5
330 330 > EOF
331 331 $ hg add baz
332 332 $ hg commit -m "baz:0"
333 333
334 334 $ cat > baz <<EOF
335 335 > 1 baz:1
336 336 > 2
337 337 > 3
338 338 > 4
339 339 > 5
340 340 > EOF
341 341 $ hg commit -m "baz:1"
342 342
343 343 $ cat > baz <<EOF
344 344 > 1 baz:1
345 345 > 2 baz:2
346 346 > 3
347 347 > 4
348 348 > 5
349 349 > EOF
350 350 $ hg debugsetparents 17 17
351 351 $ hg --config extensions.legacyrepo=../legacyrepo.py commit -m "baz:2"
352 352 $ hg debugindexdot .hg/store/data/baz.i
353 353 digraph G {
354 354 -1 -> 0
355 355 0 -> 1
356 356 1 -> 2
357 357 1 -> 2
358 358 }
359 359 $ hg annotate baz
360 360 17: 1 baz:1
361 361 18: 2 baz:2
362 362 16: 3
363 363 16: 4
364 364 16: 5
365 365
366 366 $ cat > baz <<EOF
367 367 > 1 baz:1
368 368 > 2 baz:2
369 369 > 3 baz:3
370 370 > 4
371 371 > 5
372 372 > EOF
373 373 $ hg commit -m "baz:3"
374 374
375 375 $ cat > baz <<EOF
376 376 > 1 baz:1
377 377 > 2 baz:2
378 378 > 3 baz:3
379 379 > 4 baz:4
380 380 > 5
381 381 > EOF
382 382 $ hg debugsetparents 19 18
383 383 $ hg --config extensions.legacyrepo=../legacyrepo.py commit -m "baz:4"
384 384 $ hg debugindexdot .hg/store/data/baz.i
385 385 digraph G {
386 386 -1 -> 0
387 387 0 -> 1
388 388 1 -> 2
389 389 1 -> 2
390 390 2 -> 3
391 391 3 -> 4
392 392 2 -> 4
393 393 }
394 394 $ hg annotate baz
395 395 17: 1 baz:1
396 396 18: 2 baz:2
397 397 19: 3 baz:3
398 398 20: 4 baz:4
399 399 16: 5
400 400
401 annotate clean file
402
403 $ hg annotate -ncr "wdir()" foo
404 11 472b18db256d : foo
405
406 annotate modified file
407
408 $ echo foofoo >> foo
409 $ hg annotate -r "wdir()" foo
410 11 : foo
411 20+: foofoo
412
413 $ hg annotate -cr "wdir()" foo
414 472b18db256d : foo
415 b6bedd5477e7+: foofoo
416
417 $ hg annotate -ncr "wdir()" foo
418 11 472b18db256d : foo
419 20 b6bedd5477e7+: foofoo
420
421 $ hg annotate --debug -ncr "wdir()" foo
422 11 472b18db256d1e8282064eab4bfdaf48cbfe83cd : foo
423 20 b6bedd5477e797f25e568a6402d4697f3f895a72+: foofoo
424
425 $ hg annotate -udr "wdir()" foo
426 test Thu Jan 01 00:00:00 1970 +0000: foo
427 test [A-Za-z0-9:+ ]+: foofoo (re)
428
429 $ hg annotate -ncr "wdir()" -Tjson foo
430 [
431 {
432 "line": "foo\n",
433 "node": "472b18db256d1e8282064eab4bfdaf48cbfe83cd",
434 "rev": 11
435 },
436 {
437 "line": "foofoo\n",
438 "node": null,
439 "rev": null
440 }
441 ]
442
443 annotate added file
444
445 $ echo bar > bar
446 $ hg add bar
447 $ hg annotate -ncr "wdir()" bar
448 20 b6bedd5477e7+: bar
449
450 annotate renamed file
451
452 $ hg rename foo renamefoo2
453 $ hg annotate -ncr "wdir()" renamefoo2
454 11 472b18db256d : foo
455 20 b6bedd5477e7+: foofoo
456
457 annotate missing file
458
459 $ rm baz
460 $ hg annotate -ncr "wdir()" baz
461 abort: No such file or directory: $TESTTMP/repo/baz
462 [255]
463
464 annotate removed file
465
466 $ hg rm baz
467 $ hg annotate -ncr "wdir()" baz
468 abort: No such file or directory: $TESTTMP/repo/baz
469 [255]
470
401 471 Test annotate with whitespace options
402 472
403 473 $ cd ..
404 474 $ hg init repo-ws
405 475 $ cd repo-ws
406 476 $ cat > a <<EOF
407 477 > aa
408 478 >
409 479 > b b
410 480 > EOF
411 481 $ hg ci -Am "adda"
412 482 adding a
413 483 $ sed 's/EOL$//g' > a <<EOF
414 484 > a a
415 485 >
416 486 > EOL
417 487 > b b
418 488 > EOF
419 489 $ hg ci -m "changea"
420 490
421 491 Annotate with no option
422 492
423 493 $ hg annotate a
424 494 1: a a
425 495 0:
426 496 1:
427 497 1: b b
428 498
429 499 Annotate with --ignore-space-change
430 500
431 501 $ hg annotate --ignore-space-change a
432 502 1: a a
433 503 1:
434 504 0:
435 505 0: b b
436 506
437 507 Annotate with --ignore-all-space
438 508
439 509 $ hg annotate --ignore-all-space a
440 510 0: a a
441 511 0:
442 512 1:
443 513 0: b b
444 514
445 515 Annotate with --ignore-blank-lines (similar to no options case)
446 516
447 517 $ hg annotate --ignore-blank-lines a
448 518 1: a a
449 519 0:
450 520 1:
451 521 1: b b
452 522
453 523 $ cd ..
454 524
455 525 Annotate with linkrev pointing to another branch
456 526 ------------------------------------------------
457 527
458 528 create history with a filerev whose linkrev points to another branch
459 529
460 530 $ hg init branchedlinkrev
461 531 $ cd branchedlinkrev
462 532 $ echo A > a
463 533 $ hg commit -Am 'contentA'
464 534 adding a
465 535 $ echo B >> a
466 536 $ hg commit -m 'contentB'
467 537 $ hg up --rev 'desc(contentA)'
468 538 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
469 539 $ echo unrelated > unrelated
470 540 $ hg commit -Am 'unrelated'
471 541 adding unrelated
472 542 created new head
473 543 $ hg graft -r 'desc(contentB)'
474 544 grafting 1:fd27c222e3e6 "contentB"
475 545 $ echo C >> a
476 546 $ hg commit -m 'contentC'
477 547 $ hg log -G
478 548 @ changeset: 4:072f1e8df249
479 549 | tag: tip
480 550 | user: test
481 551 | date: Thu Jan 01 00:00:00 1970 +0000
482 552 | summary: contentC
483 553 |
484 554 o changeset: 3:ff38df03cc4b
485 555 | user: test
486 556 | date: Thu Jan 01 00:00:00 1970 +0000
487 557 | summary: contentB
488 558 |
489 559 o changeset: 2:62aaf3f6fc06
490 560 | parent: 0:f0932f74827e
491 561 | user: test
492 562 | date: Thu Jan 01 00:00:00 1970 +0000
493 563 | summary: unrelated
494 564 |
495 565 | o changeset: 1:fd27c222e3e6
496 566 |/ user: test
497 567 | date: Thu Jan 01 00:00:00 1970 +0000
498 568 | summary: contentB
499 569 |
500 570 o changeset: 0:f0932f74827e
501 571 user: test
502 572 date: Thu Jan 01 00:00:00 1970 +0000
503 573 summary: contentA
504 574
505 575
506 576 Annotate should list ancestor of starting revision only
507 577
508 578 $ hg annotate a
509 579 0: A
510 580 3: B
511 581 4: C
512 582
513 583 Even when the starting revision is the linkrev-shadowed one:
514 584
515 585 $ hg annotate a -r 3
516 586 0: A
517 587 3: B
518 588
519 589 $ cd ..
General Comments 0
You need to be logged in to leave comments. Login now