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