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