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