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