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