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