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