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