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