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