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