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