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