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