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