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