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