##// END OF EJS Templates
walk: remove rel and exact returns
Matt Mackall -
r6584:29c77e5d default
parent child Browse files
Show More
@@ -1,1183 +1,1187 b''
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
6 6 # of the GNU General Public License, incorporated herein by reference.
7 7
8 8 from node import hex, nullid, nullrev, short
9 9 from i18n import _
10 10 import os, sys, bisect, stat
11 11 import mdiff, bdiff, util, templater, templatefilters, patch, errno
12 12 import match as _match
13 13
14 14 revrangesep = ':'
15 15
16 16 class UnknownCommand(Exception):
17 17 """Exception raised if command is not in the command table."""
18 18 class AmbiguousCommand(Exception):
19 19 """Exception raised if command shortcut matches more than one command."""
20 20
21 21 def findpossible(ui, cmd, table):
22 22 """
23 23 Return cmd -> (aliases, command table entry)
24 24 for each matching command.
25 25 Return debug commands (or their aliases) only if no normal command matches.
26 26 """
27 27 choice = {}
28 28 debugchoice = {}
29 29 for e in table.keys():
30 30 aliases = e.lstrip("^").split("|")
31 31 found = None
32 32 if cmd in aliases:
33 33 found = cmd
34 34 elif not ui.config("ui", "strict"):
35 35 for a in aliases:
36 36 if a.startswith(cmd):
37 37 found = a
38 38 break
39 39 if found is not None:
40 40 if aliases[0].startswith("debug") or found.startswith("debug"):
41 41 debugchoice[found] = (aliases, table[e])
42 42 else:
43 43 choice[found] = (aliases, table[e])
44 44
45 45 if not choice and debugchoice:
46 46 choice = debugchoice
47 47
48 48 return choice
49 49
50 50 def findcmd(ui, cmd, table):
51 51 """Return (aliases, command table entry) for command string."""
52 52 choice = findpossible(ui, cmd, table)
53 53
54 54 if cmd in choice:
55 55 return choice[cmd]
56 56
57 57 if len(choice) > 1:
58 58 clist = choice.keys()
59 59 clist.sort()
60 60 raise AmbiguousCommand(cmd, clist)
61 61
62 62 if choice:
63 63 return choice.values()[0]
64 64
65 65 raise UnknownCommand(cmd)
66 66
67 67 def bail_if_changed(repo):
68 68 if repo.dirstate.parents()[1] != nullid:
69 69 raise util.Abort(_('outstanding uncommitted merge'))
70 70 modified, added, removed, deleted = repo.status()[:4]
71 71 if modified or added or removed or deleted:
72 72 raise util.Abort(_("outstanding uncommitted changes"))
73 73
74 74 def logmessage(opts):
75 75 """ get the log message according to -m and -l option """
76 76 message = opts['message']
77 77 logfile = opts['logfile']
78 78
79 79 if message and logfile:
80 80 raise util.Abort(_('options --message and --logfile are mutually '
81 81 'exclusive'))
82 82 if not message and logfile:
83 83 try:
84 84 if logfile == '-':
85 85 message = sys.stdin.read()
86 86 else:
87 87 message = open(logfile).read()
88 88 except IOError, inst:
89 89 raise util.Abort(_("can't read commit message '%s': %s") %
90 90 (logfile, inst.strerror))
91 91 return message
92 92
93 93 def loglimit(opts):
94 94 """get the log limit according to option -l/--limit"""
95 95 limit = opts.get('limit')
96 96 if limit:
97 97 try:
98 98 limit = int(limit)
99 99 except ValueError:
100 100 raise util.Abort(_('limit must be a positive integer'))
101 101 if limit <= 0: raise util.Abort(_('limit must be positive'))
102 102 else:
103 103 limit = sys.maxint
104 104 return limit
105 105
106 106 def setremoteconfig(ui, opts):
107 107 "copy remote options to ui tree"
108 108 if opts.get('ssh'):
109 109 ui.setconfig("ui", "ssh", opts['ssh'])
110 110 if opts.get('remotecmd'):
111 111 ui.setconfig("ui", "remotecmd", opts['remotecmd'])
112 112
113 113 def revpair(repo, revs):
114 114 '''return pair of nodes, given list of revisions. second item can
115 115 be None, meaning use working dir.'''
116 116
117 117 def revfix(repo, val, defval):
118 118 if not val and val != 0 and defval is not None:
119 119 val = defval
120 120 return repo.lookup(val)
121 121
122 122 if not revs:
123 123 return repo.dirstate.parents()[0], None
124 124 end = None
125 125 if len(revs) == 1:
126 126 if revrangesep in revs[0]:
127 127 start, end = revs[0].split(revrangesep, 1)
128 128 start = revfix(repo, start, 0)
129 129 end = revfix(repo, end, repo.changelog.count() - 1)
130 130 else:
131 131 start = revfix(repo, revs[0], None)
132 132 elif len(revs) == 2:
133 133 if revrangesep in revs[0] or revrangesep in revs[1]:
134 134 raise util.Abort(_('too many revisions specified'))
135 135 start = revfix(repo, revs[0], None)
136 136 end = revfix(repo, revs[1], None)
137 137 else:
138 138 raise util.Abort(_('too many revisions specified'))
139 139 return start, end
140 140
141 141 def revrange(repo, revs):
142 142 """Yield revision as strings from a list of revision specifications."""
143 143
144 144 def revfix(repo, val, defval):
145 145 if not val and val != 0 and defval is not None:
146 146 return defval
147 147 return repo.changelog.rev(repo.lookup(val))
148 148
149 149 seen, l = {}, []
150 150 for spec in revs:
151 151 if revrangesep in spec:
152 152 start, end = spec.split(revrangesep, 1)
153 153 start = revfix(repo, start, 0)
154 154 end = revfix(repo, end, repo.changelog.count() - 1)
155 155 step = start > end and -1 or 1
156 156 for rev in xrange(start, end+step, step):
157 157 if rev in seen:
158 158 continue
159 159 seen[rev] = 1
160 160 l.append(rev)
161 161 else:
162 162 rev = revfix(repo, spec, None)
163 163 if rev in seen:
164 164 continue
165 165 seen[rev] = 1
166 166 l.append(rev)
167 167
168 168 return l
169 169
170 170 def make_filename(repo, pat, node,
171 171 total=None, seqno=None, revwidth=None, pathname=None):
172 172 node_expander = {
173 173 'H': lambda: hex(node),
174 174 'R': lambda: str(repo.changelog.rev(node)),
175 175 'h': lambda: short(node),
176 176 }
177 177 expander = {
178 178 '%': lambda: '%',
179 179 'b': lambda: os.path.basename(repo.root),
180 180 }
181 181
182 182 try:
183 183 if node:
184 184 expander.update(node_expander)
185 185 if node:
186 186 expander['r'] = (lambda:
187 187 str(repo.changelog.rev(node)).zfill(revwidth or 0))
188 188 if total is not None:
189 189 expander['N'] = lambda: str(total)
190 190 if seqno is not None:
191 191 expander['n'] = lambda: str(seqno)
192 192 if total is not None and seqno is not None:
193 193 expander['n'] = lambda: str(seqno).zfill(len(str(total)))
194 194 if pathname is not None:
195 195 expander['s'] = lambda: os.path.basename(pathname)
196 196 expander['d'] = lambda: os.path.dirname(pathname) or '.'
197 197 expander['p'] = lambda: pathname
198 198
199 199 newname = []
200 200 patlen = len(pat)
201 201 i = 0
202 202 while i < patlen:
203 203 c = pat[i]
204 204 if c == '%':
205 205 i += 1
206 206 c = pat[i]
207 207 c = expander[c]()
208 208 newname.append(c)
209 209 i += 1
210 210 return ''.join(newname)
211 211 except KeyError, inst:
212 212 raise util.Abort(_("invalid format spec '%%%s' in output file name") %
213 213 inst.args[0])
214 214
215 215 def make_file(repo, pat, node=None,
216 216 total=None, seqno=None, revwidth=None, mode='wb', pathname=None):
217 217 if not pat or pat == '-':
218 218 return 'w' in mode and sys.stdout or sys.stdin
219 219 if hasattr(pat, 'write') and 'w' in mode:
220 220 return pat
221 221 if hasattr(pat, 'read') and 'r' in mode:
222 222 return pat
223 223 return open(make_filename(repo, pat, node, total, seqno, revwidth,
224 224 pathname),
225 225 mode)
226 226
227 227 def match(repo, pats=[], opts={}, globbed=False, default='relpath'):
228 228 if not globbed and default == 'relpath':
229 229 pats = util.expand_glob(pats or [])
230 230 m = _match.match(repo.root, repo.getcwd(), pats,
231 231 opts.get('include'), opts.get('exclude'), default)
232 232 def badfn(f, msg):
233 233 repo.ui.warn("%s: %s\n" % (m.rel(f), msg))
234 234 return False
235 235 m.bad = badfn
236 236 return m
237 237
238 238 def walk(repo, match, node=None):
239 239 for src, fn in repo.walk(node, match):
240 yield src, fn, match.rel(fn), match.exact(fn)
240 yield src, fn
241 241
242 242 def findrenames(repo, added=None, removed=None, threshold=0.5):
243 243 '''find renamed files -- yields (before, after, score) tuples'''
244 244 if added is None or removed is None:
245 245 added, removed = repo.status()[1:3]
246 246 ctx = repo.changectx()
247 247 for a in added:
248 248 aa = repo.wread(a)
249 249 bestname, bestscore = None, threshold
250 250 for r in removed:
251 251 rr = ctx.filectx(r).data()
252 252
253 253 # bdiff.blocks() returns blocks of matching lines
254 254 # count the number of bytes in each
255 255 equal = 0
256 256 alines = mdiff.splitnewlines(aa)
257 257 matches = bdiff.blocks(aa, rr)
258 258 for x1,x2,y1,y2 in matches:
259 259 for line in alines[x1:x2]:
260 260 equal += len(line)
261 261
262 262 lengths = len(aa) + len(rr)
263 263 if lengths:
264 264 myscore = equal*2.0 / lengths
265 265 if myscore >= bestscore:
266 266 bestname, bestscore = r, myscore
267 267 if bestname:
268 268 yield bestname, a, bestscore
269 269
270 270 def addremove(repo, pats=[], opts={}, dry_run=None, similarity=None):
271 271 if dry_run is None:
272 272 dry_run = opts.get('dry_run')
273 273 if similarity is None:
274 274 similarity = float(opts.get('similarity') or 0)
275 275 add, remove = [], []
276 276 mapping = {}
277 277 m = match(repo, pats, opts)
278 for src, abs, rel, exact in walk(repo, m):
278 for src, abs in walk(repo, m):
279 279 target = repo.wjoin(abs)
280 rel = m.rel(abs)
281 exact = m.exact(abs)
280 282 if src == 'f' and abs not in repo.dirstate:
281 283 add.append(abs)
282 mapping[abs] = rel, exact
284 mapping[abs] = rel, m.exact(abs)
283 285 if repo.ui.verbose or not exact:
284 286 repo.ui.status(_('adding %s\n') % ((pats and rel) or abs))
285 287 if repo.dirstate[abs] != 'r' and (not util.lexists(target)
286 288 or (os.path.isdir(target) and not os.path.islink(target))):
287 289 remove.append(abs)
288 290 mapping[abs] = rel, exact
289 291 if repo.ui.verbose or not exact:
290 292 repo.ui.status(_('removing %s\n') % ((pats and rel) or abs))
291 293 if not dry_run:
292 294 repo.remove(remove)
293 295 repo.add(add)
294 296 if similarity > 0:
295 297 for old, new, score in findrenames(repo, add, remove, similarity):
296 298 oldrel, oldexact = mapping[old]
297 299 newrel, newexact = mapping[new]
298 300 if repo.ui.verbose or not oldexact or not newexact:
299 301 repo.ui.status(_('recording removal of %s as rename to %s '
300 302 '(%d%% similar)\n') %
301 303 (oldrel, newrel, score * 100))
302 304 if not dry_run:
303 305 repo.copy(old, new)
304 306
305 307 def copy(ui, repo, pats, opts, rename=False):
306 308 # called with the repo lock held
307 309 #
308 310 # hgsep => pathname that uses "/" to separate directories
309 311 # ossep => pathname that uses os.sep to separate directories
310 312 cwd = repo.getcwd()
311 313 targets = {}
312 314 after = opts.get("after")
313 315 dryrun = opts.get("dry_run")
314 316
315 317 def walkpat(pat):
316 318 srcs = []
317 319 m = match(repo, [pat], opts, globbed=True)
318 for tag, abs, rel, exact in walk(repo, m):
320 for tag, abs in walk(repo, m):
319 321 state = repo.dirstate[abs]
322 rel = m.rel(abs)
323 exact = m.exact(abs)
320 324 if state in '?r':
321 325 if exact and state == '?':
322 326 ui.warn(_('%s: not copying - file is not managed\n') % rel)
323 327 if exact and state == 'r':
324 328 ui.warn(_('%s: not copying - file has been marked for'
325 329 ' remove\n') % rel)
326 330 continue
327 331 # abs: hgsep
328 332 # rel: ossep
329 333 srcs.append((abs, rel, exact))
330 334 return srcs
331 335
332 336 # abssrc: hgsep
333 337 # relsrc: ossep
334 338 # otarget: ossep
335 339 def copyfile(abssrc, relsrc, otarget, exact):
336 340 abstarget = util.canonpath(repo.root, cwd, otarget)
337 341 reltarget = repo.pathto(abstarget, cwd)
338 342 target = repo.wjoin(abstarget)
339 343 src = repo.wjoin(abssrc)
340 344 state = repo.dirstate[abstarget]
341 345
342 346 # check for collisions
343 347 prevsrc = targets.get(abstarget)
344 348 if prevsrc is not None:
345 349 ui.warn(_('%s: not overwriting - %s collides with %s\n') %
346 350 (reltarget, repo.pathto(abssrc, cwd),
347 351 repo.pathto(prevsrc, cwd)))
348 352 return
349 353
350 354 # check for overwrites
351 355 exists = os.path.exists(target)
352 356 if (not after and exists or after and state in 'mn'):
353 357 if not opts['force']:
354 358 ui.warn(_('%s: not overwriting - file exists\n') %
355 359 reltarget)
356 360 return
357 361
358 362 if after:
359 363 if not exists:
360 364 return
361 365 elif not dryrun:
362 366 try:
363 367 if exists:
364 368 os.unlink(target)
365 369 targetdir = os.path.dirname(target) or '.'
366 370 if not os.path.isdir(targetdir):
367 371 os.makedirs(targetdir)
368 372 util.copyfile(src, target)
369 373 except IOError, inst:
370 374 if inst.errno == errno.ENOENT:
371 375 ui.warn(_('%s: deleted in working copy\n') % relsrc)
372 376 else:
373 377 ui.warn(_('%s: cannot copy - %s\n') %
374 378 (relsrc, inst.strerror))
375 379 return True # report a failure
376 380
377 381 if ui.verbose or not exact:
378 382 action = rename and "moving" or "copying"
379 383 ui.status(_('%s %s to %s\n') % (action, relsrc, reltarget))
380 384
381 385 targets[abstarget] = abssrc
382 386
383 387 # fix up dirstate
384 388 origsrc = repo.dirstate.copied(abssrc) or abssrc
385 389 if abstarget == origsrc: # copying back a copy?
386 390 if state not in 'mn' and not dryrun:
387 391 repo.dirstate.normallookup(abstarget)
388 392 else:
389 393 if repo.dirstate[origsrc] == 'a':
390 394 if not ui.quiet:
391 395 ui.warn(_("%s has not been committed yet, so no copy "
392 396 "data will be stored for %s.\n")
393 397 % (repo.pathto(origsrc, cwd), reltarget))
394 398 if abstarget not in repo.dirstate and not dryrun:
395 399 repo.add([abstarget])
396 400 elif not dryrun:
397 401 repo.copy(origsrc, abstarget)
398 402
399 403 if rename and not dryrun:
400 404 repo.remove([abssrc], not after)
401 405
402 406 # pat: ossep
403 407 # dest ossep
404 408 # srcs: list of (hgsep, hgsep, ossep, bool)
405 409 # return: function that takes hgsep and returns ossep
406 410 def targetpathfn(pat, dest, srcs):
407 411 if os.path.isdir(pat):
408 412 abspfx = util.canonpath(repo.root, cwd, pat)
409 413 abspfx = util.localpath(abspfx)
410 414 if destdirexists:
411 415 striplen = len(os.path.split(abspfx)[0])
412 416 else:
413 417 striplen = len(abspfx)
414 418 if striplen:
415 419 striplen += len(os.sep)
416 420 res = lambda p: os.path.join(dest, util.localpath(p)[striplen:])
417 421 elif destdirexists:
418 422 res = lambda p: os.path.join(dest,
419 423 os.path.basename(util.localpath(p)))
420 424 else:
421 425 res = lambda p: dest
422 426 return res
423 427
424 428 # pat: ossep
425 429 # dest ossep
426 430 # srcs: list of (hgsep, hgsep, ossep, bool)
427 431 # return: function that takes hgsep and returns ossep
428 432 def targetpathafterfn(pat, dest, srcs):
429 433 if util.patkind(pat, None)[0]:
430 434 # a mercurial pattern
431 435 res = lambda p: os.path.join(dest,
432 436 os.path.basename(util.localpath(p)))
433 437 else:
434 438 abspfx = util.canonpath(repo.root, cwd, pat)
435 439 if len(abspfx) < len(srcs[0][0]):
436 440 # A directory. Either the target path contains the last
437 441 # component of the source path or it does not.
438 442 def evalpath(striplen):
439 443 score = 0
440 444 for s in srcs:
441 445 t = os.path.join(dest, util.localpath(s[0])[striplen:])
442 446 if os.path.exists(t):
443 447 score += 1
444 448 return score
445 449
446 450 abspfx = util.localpath(abspfx)
447 451 striplen = len(abspfx)
448 452 if striplen:
449 453 striplen += len(os.sep)
450 454 if os.path.isdir(os.path.join(dest, os.path.split(abspfx)[1])):
451 455 score = evalpath(striplen)
452 456 striplen1 = len(os.path.split(abspfx)[0])
453 457 if striplen1:
454 458 striplen1 += len(os.sep)
455 459 if evalpath(striplen1) > score:
456 460 striplen = striplen1
457 461 res = lambda p: os.path.join(dest,
458 462 util.localpath(p)[striplen:])
459 463 else:
460 464 # a file
461 465 if destdirexists:
462 466 res = lambda p: os.path.join(dest,
463 467 os.path.basename(util.localpath(p)))
464 468 else:
465 469 res = lambda p: dest
466 470 return res
467 471
468 472
469 473 pats = util.expand_glob(pats)
470 474 if not pats:
471 475 raise util.Abort(_('no source or destination specified'))
472 476 if len(pats) == 1:
473 477 raise util.Abort(_('no destination specified'))
474 478 dest = pats.pop()
475 479 destdirexists = os.path.isdir(dest) and not os.path.islink(dest)
476 480 if not destdirexists:
477 481 if len(pats) > 1 or util.patkind(pats[0], None)[0]:
478 482 raise util.Abort(_('with multiple sources, destination must be an '
479 483 'existing directory'))
480 484 if util.endswithsep(dest):
481 485 raise util.Abort(_('destination %s is not a directory') % dest)
482 486
483 487 tfn = targetpathfn
484 488 if after:
485 489 tfn = targetpathafterfn
486 490 copylist = []
487 491 for pat in pats:
488 492 srcs = walkpat(pat)
489 493 if not srcs:
490 494 continue
491 495 copylist.append((tfn(pat, dest, srcs), srcs))
492 496 if not copylist:
493 497 raise util.Abort(_('no files to copy'))
494 498
495 499 errors = 0
496 500 for targetpath, srcs in copylist:
497 501 for abssrc, relsrc, exact in srcs:
498 502 if copyfile(abssrc, relsrc, targetpath(abssrc), exact):
499 503 errors += 1
500 504
501 505 if errors:
502 506 ui.warn(_('(consider using --after)\n'))
503 507
504 508 return errors
505 509
506 510 def service(opts, parentfn=None, initfn=None, runfn=None):
507 511 '''Run a command as a service.'''
508 512
509 513 if opts['daemon'] and not opts['daemon_pipefds']:
510 514 rfd, wfd = os.pipe()
511 515 args = sys.argv[:]
512 516 args.append('--daemon-pipefds=%d,%d' % (rfd, wfd))
513 517 # Don't pass --cwd to the child process, because we've already
514 518 # changed directory.
515 519 for i in xrange(1,len(args)):
516 520 if args[i].startswith('--cwd='):
517 521 del args[i]
518 522 break
519 523 elif args[i].startswith('--cwd'):
520 524 del args[i:i+2]
521 525 break
522 526 pid = os.spawnvp(os.P_NOWAIT | getattr(os, 'P_DETACH', 0),
523 527 args[0], args)
524 528 os.close(wfd)
525 529 os.read(rfd, 1)
526 530 if parentfn:
527 531 return parentfn(pid)
528 532 else:
529 533 os._exit(0)
530 534
531 535 if initfn:
532 536 initfn()
533 537
534 538 if opts['pid_file']:
535 539 fp = open(opts['pid_file'], 'w')
536 540 fp.write(str(os.getpid()) + '\n')
537 541 fp.close()
538 542
539 543 if opts['daemon_pipefds']:
540 544 rfd, wfd = [int(x) for x in opts['daemon_pipefds'].split(',')]
541 545 os.close(rfd)
542 546 try:
543 547 os.setsid()
544 548 except AttributeError:
545 549 pass
546 550 os.write(wfd, 'y')
547 551 os.close(wfd)
548 552 sys.stdout.flush()
549 553 sys.stderr.flush()
550 554 fd = os.open(util.nulldev, os.O_RDWR)
551 555 if fd != 0: os.dup2(fd, 0)
552 556 if fd != 1: os.dup2(fd, 1)
553 557 if fd != 2: os.dup2(fd, 2)
554 558 if fd not in (0, 1, 2): os.close(fd)
555 559
556 560 if runfn:
557 561 return runfn()
558 562
559 563 class changeset_printer(object):
560 564 '''show changeset information when templating not requested.'''
561 565
562 566 def __init__(self, ui, repo, patch, buffered):
563 567 self.ui = ui
564 568 self.repo = repo
565 569 self.buffered = buffered
566 570 self.patch = patch
567 571 self.header = {}
568 572 self.hunk = {}
569 573 self.lastheader = None
570 574
571 575 def flush(self, rev):
572 576 if rev in self.header:
573 577 h = self.header[rev]
574 578 if h != self.lastheader:
575 579 self.lastheader = h
576 580 self.ui.write(h)
577 581 del self.header[rev]
578 582 if rev in self.hunk:
579 583 self.ui.write(self.hunk[rev])
580 584 del self.hunk[rev]
581 585 return 1
582 586 return 0
583 587
584 588 def show(self, rev=0, changenode=None, copies=(), **props):
585 589 if self.buffered:
586 590 self.ui.pushbuffer()
587 591 self._show(rev, changenode, copies, props)
588 592 self.hunk[rev] = self.ui.popbuffer()
589 593 else:
590 594 self._show(rev, changenode, copies, props)
591 595
592 596 def _show(self, rev, changenode, copies, props):
593 597 '''show a single changeset or file revision'''
594 598 log = self.repo.changelog
595 599 if changenode is None:
596 600 changenode = log.node(rev)
597 601 elif not rev:
598 602 rev = log.rev(changenode)
599 603
600 604 if self.ui.quiet:
601 605 self.ui.write("%d:%s\n" % (rev, short(changenode)))
602 606 return
603 607
604 608 changes = log.read(changenode)
605 609 date = util.datestr(changes[2])
606 610 extra = changes[5]
607 611 branch = extra.get("branch")
608 612
609 613 hexfunc = self.ui.debugflag and hex or short
610 614
611 615 parents = [(p, hexfunc(log.node(p)))
612 616 for p in self._meaningful_parentrevs(log, rev)]
613 617
614 618 self.ui.write(_("changeset: %d:%s\n") % (rev, hexfunc(changenode)))
615 619
616 620 # don't show the default branch name
617 621 if branch != 'default':
618 622 branch = util.tolocal(branch)
619 623 self.ui.write(_("branch: %s\n") % branch)
620 624 for tag in self.repo.nodetags(changenode):
621 625 self.ui.write(_("tag: %s\n") % tag)
622 626 for parent in parents:
623 627 self.ui.write(_("parent: %d:%s\n") % parent)
624 628
625 629 if self.ui.debugflag:
626 630 self.ui.write(_("manifest: %d:%s\n") %
627 631 (self.repo.manifest.rev(changes[0]), hex(changes[0])))
628 632 self.ui.write(_("user: %s\n") % changes[1])
629 633 self.ui.write(_("date: %s\n") % date)
630 634
631 635 if self.ui.debugflag:
632 636 files = self.repo.status(log.parents(changenode)[0], changenode)[:3]
633 637 for key, value in zip([_("files:"), _("files+:"), _("files-:")],
634 638 files):
635 639 if value:
636 640 self.ui.write("%-12s %s\n" % (key, " ".join(value)))
637 641 elif changes[3] and self.ui.verbose:
638 642 self.ui.write(_("files: %s\n") % " ".join(changes[3]))
639 643 if copies and self.ui.verbose:
640 644 copies = ['%s (%s)' % c for c in copies]
641 645 self.ui.write(_("copies: %s\n") % ' '.join(copies))
642 646
643 647 if extra and self.ui.debugflag:
644 648 extraitems = extra.items()
645 649 extraitems.sort()
646 650 for key, value in extraitems:
647 651 self.ui.write(_("extra: %s=%s\n")
648 652 % (key, value.encode('string_escape')))
649 653
650 654 description = changes[4].strip()
651 655 if description:
652 656 if self.ui.verbose:
653 657 self.ui.write(_("description:\n"))
654 658 self.ui.write(description)
655 659 self.ui.write("\n\n")
656 660 else:
657 661 self.ui.write(_("summary: %s\n") %
658 662 description.splitlines()[0])
659 663 self.ui.write("\n")
660 664
661 665 self.showpatch(changenode)
662 666
663 667 def showpatch(self, node):
664 668 if self.patch:
665 669 prev = self.repo.changelog.parents(node)[0]
666 670 patch.diff(self.repo, prev, node, match=self.patch, fp=self.ui,
667 671 opts=patch.diffopts(self.ui))
668 672 self.ui.write("\n")
669 673
670 674 def _meaningful_parentrevs(self, log, rev):
671 675 """Return list of meaningful (or all if debug) parentrevs for rev.
672 676
673 677 For merges (two non-nullrev revisions) both parents are meaningful.
674 678 Otherwise the first parent revision is considered meaningful if it
675 679 is not the preceding revision.
676 680 """
677 681 parents = log.parentrevs(rev)
678 682 if not self.ui.debugflag and parents[1] == nullrev:
679 683 if parents[0] >= rev - 1:
680 684 parents = []
681 685 else:
682 686 parents = [parents[0]]
683 687 return parents
684 688
685 689
686 690 class changeset_templater(changeset_printer):
687 691 '''format changeset information.'''
688 692
689 693 def __init__(self, ui, repo, patch, mapfile, buffered):
690 694 changeset_printer.__init__(self, ui, repo, patch, buffered)
691 695 filters = templatefilters.filters.copy()
692 696 filters['formatnode'] = (ui.debugflag and (lambda x: x)
693 697 or (lambda x: x[:12]))
694 698 self.t = templater.templater(mapfile, filters,
695 699 cache={
696 700 'parent': '{rev}:{node|formatnode} ',
697 701 'manifest': '{rev}:{node|formatnode}',
698 702 'filecopy': '{name} ({source})'})
699 703
700 704 def use_template(self, t):
701 705 '''set template string to use'''
702 706 self.t.cache['changeset'] = t
703 707
704 708 def _show(self, rev, changenode, copies, props):
705 709 '''show a single changeset or file revision'''
706 710 log = self.repo.changelog
707 711 if changenode is None:
708 712 changenode = log.node(rev)
709 713 elif not rev:
710 714 rev = log.rev(changenode)
711 715
712 716 changes = log.read(changenode)
713 717
714 718 def showlist(name, values, plural=None, **args):
715 719 '''expand set of values.
716 720 name is name of key in template map.
717 721 values is list of strings or dicts.
718 722 plural is plural of name, if not simply name + 's'.
719 723
720 724 expansion works like this, given name 'foo'.
721 725
722 726 if values is empty, expand 'no_foos'.
723 727
724 728 if 'foo' not in template map, return values as a string,
725 729 joined by space.
726 730
727 731 expand 'start_foos'.
728 732
729 733 for each value, expand 'foo'. if 'last_foo' in template
730 734 map, expand it instead of 'foo' for last key.
731 735
732 736 expand 'end_foos'.
733 737 '''
734 738 if plural: names = plural
735 739 else: names = name + 's'
736 740 if not values:
737 741 noname = 'no_' + names
738 742 if noname in self.t:
739 743 yield self.t(noname, **args)
740 744 return
741 745 if name not in self.t:
742 746 if isinstance(values[0], str):
743 747 yield ' '.join(values)
744 748 else:
745 749 for v in values:
746 750 yield dict(v, **args)
747 751 return
748 752 startname = 'start_' + names
749 753 if startname in self.t:
750 754 yield self.t(startname, **args)
751 755 vargs = args.copy()
752 756 def one(v, tag=name):
753 757 try:
754 758 vargs.update(v)
755 759 except (AttributeError, ValueError):
756 760 try:
757 761 for a, b in v:
758 762 vargs[a] = b
759 763 except ValueError:
760 764 vargs[name] = v
761 765 return self.t(tag, **vargs)
762 766 lastname = 'last_' + name
763 767 if lastname in self.t:
764 768 last = values.pop()
765 769 else:
766 770 last = None
767 771 for v in values:
768 772 yield one(v)
769 773 if last is not None:
770 774 yield one(last, tag=lastname)
771 775 endname = 'end_' + names
772 776 if endname in self.t:
773 777 yield self.t(endname, **args)
774 778
775 779 def showbranches(**args):
776 780 branch = changes[5].get("branch")
777 781 if branch != 'default':
778 782 branch = util.tolocal(branch)
779 783 return showlist('branch', [branch], plural='branches', **args)
780 784
781 785 def showparents(**args):
782 786 parents = [[('rev', p), ('node', hex(log.node(p)))]
783 787 for p in self._meaningful_parentrevs(log, rev)]
784 788 return showlist('parent', parents, **args)
785 789
786 790 def showtags(**args):
787 791 return showlist('tag', self.repo.nodetags(changenode), **args)
788 792
789 793 def showextras(**args):
790 794 extras = changes[5].items()
791 795 extras.sort()
792 796 for key, value in extras:
793 797 args = args.copy()
794 798 args.update(dict(key=key, value=value))
795 799 yield self.t('extra', **args)
796 800
797 801 def showcopies(**args):
798 802 c = [{'name': x[0], 'source': x[1]} for x in copies]
799 803 return showlist('file_copy', c, plural='file_copies', **args)
800 804
801 805 files = []
802 806 def getfiles():
803 807 if not files:
804 808 files[:] = self.repo.status(
805 809 log.parents(changenode)[0], changenode)[:3]
806 810 return files
807 811 def showfiles(**args):
808 812 return showlist('file', changes[3], **args)
809 813 def showmods(**args):
810 814 return showlist('file_mod', getfiles()[0], **args)
811 815 def showadds(**args):
812 816 return showlist('file_add', getfiles()[1], **args)
813 817 def showdels(**args):
814 818 return showlist('file_del', getfiles()[2], **args)
815 819 def showmanifest(**args):
816 820 args = args.copy()
817 821 args.update(dict(rev=self.repo.manifest.rev(changes[0]),
818 822 node=hex(changes[0])))
819 823 return self.t('manifest', **args)
820 824
821 825 defprops = {
822 826 'author': changes[1],
823 827 'branches': showbranches,
824 828 'date': changes[2],
825 829 'desc': changes[4].strip(),
826 830 'file_adds': showadds,
827 831 'file_dels': showdels,
828 832 'file_mods': showmods,
829 833 'files': showfiles,
830 834 'file_copies': showcopies,
831 835 'manifest': showmanifest,
832 836 'node': hex(changenode),
833 837 'parents': showparents,
834 838 'rev': rev,
835 839 'tags': showtags,
836 840 'extras': showextras,
837 841 }
838 842 props = props.copy()
839 843 props.update(defprops)
840 844
841 845 try:
842 846 if self.ui.debugflag and 'header_debug' in self.t:
843 847 key = 'header_debug'
844 848 elif self.ui.quiet and 'header_quiet' in self.t:
845 849 key = 'header_quiet'
846 850 elif self.ui.verbose and 'header_verbose' in self.t:
847 851 key = 'header_verbose'
848 852 elif 'header' in self.t:
849 853 key = 'header'
850 854 else:
851 855 key = ''
852 856 if key:
853 857 h = templater.stringify(self.t(key, **props))
854 858 if self.buffered:
855 859 self.header[rev] = h
856 860 else:
857 861 self.ui.write(h)
858 862 if self.ui.debugflag and 'changeset_debug' in self.t:
859 863 key = 'changeset_debug'
860 864 elif self.ui.quiet and 'changeset_quiet' in self.t:
861 865 key = 'changeset_quiet'
862 866 elif self.ui.verbose and 'changeset_verbose' in self.t:
863 867 key = 'changeset_verbose'
864 868 else:
865 869 key = 'changeset'
866 870 self.ui.write(templater.stringify(self.t(key, **props)))
867 871 self.showpatch(changenode)
868 872 except KeyError, inst:
869 873 raise util.Abort(_("%s: no key named '%s'") % (self.t.mapfile,
870 874 inst.args[0]))
871 875 except SyntaxError, inst:
872 876 raise util.Abort(_('%s: %s') % (self.t.mapfile, inst.args[0]))
873 877
874 878 def show_changeset(ui, repo, opts, buffered=False, matchfn=False):
875 879 """show one changeset using template or regular display.
876 880
877 881 Display format will be the first non-empty hit of:
878 882 1. option 'template'
879 883 2. option 'style'
880 884 3. [ui] setting 'logtemplate'
881 885 4. [ui] setting 'style'
882 886 If all of these values are either the unset or the empty string,
883 887 regular display via changeset_printer() is done.
884 888 """
885 889 # options
886 890 patch = False
887 891 if opts.get('patch'):
888 892 patch = matchfn or util.always
889 893
890 894 tmpl = opts.get('template')
891 895 mapfile = None
892 896 if tmpl:
893 897 tmpl = templater.parsestring(tmpl, quoted=False)
894 898 else:
895 899 mapfile = opts.get('style')
896 900 # ui settings
897 901 if not mapfile:
898 902 tmpl = ui.config('ui', 'logtemplate')
899 903 if tmpl:
900 904 tmpl = templater.parsestring(tmpl)
901 905 else:
902 906 mapfile = ui.config('ui', 'style')
903 907
904 908 if tmpl or mapfile:
905 909 if mapfile:
906 910 if not os.path.split(mapfile)[0]:
907 911 mapname = (templater.templatepath('map-cmdline.' + mapfile)
908 912 or templater.templatepath(mapfile))
909 913 if mapname: mapfile = mapname
910 914 try:
911 915 t = changeset_templater(ui, repo, patch, mapfile, buffered)
912 916 except SyntaxError, inst:
913 917 raise util.Abort(inst.args[0])
914 918 if tmpl: t.use_template(tmpl)
915 919 return t
916 920 return changeset_printer(ui, repo, patch, buffered)
917 921
918 922 def finddate(ui, repo, date):
919 923 """Find the tipmost changeset that matches the given date spec"""
920 924 df = util.matchdate(date)
921 925 get = util.cachefunc(lambda r: repo.changectx(r).changeset())
922 926 changeiter, matchfn = walkchangerevs(ui, repo, [], get, {'rev':None})
923 927 results = {}
924 928 for st, rev, fns in changeiter:
925 929 if st == 'add':
926 930 d = get(rev)[2]
927 931 if df(d[0]):
928 932 results[rev] = d
929 933 elif st == 'iter':
930 934 if rev in results:
931 935 ui.status("Found revision %s from %s\n" %
932 936 (rev, util.datestr(results[rev])))
933 937 return str(rev)
934 938
935 939 raise util.Abort(_("revision matching date not found"))
936 940
937 941 def walkchangerevs(ui, repo, pats, change, opts):
938 942 '''Iterate over files and the revs they changed in.
939 943
940 944 Callers most commonly need to iterate backwards over the history
941 945 it is interested in. Doing so has awful (quadratic-looking)
942 946 performance, so we use iterators in a "windowed" way.
943 947
944 948 We walk a window of revisions in the desired order. Within the
945 949 window, we first walk forwards to gather data, then in the desired
946 950 order (usually backwards) to display it.
947 951
948 952 This function returns an (iterator, matchfn) tuple. The iterator
949 953 yields 3-tuples. They will be of one of the following forms:
950 954
951 955 "window", incrementing, lastrev: stepping through a window,
952 956 positive if walking forwards through revs, last rev in the
953 957 sequence iterated over - use to reset state for the current window
954 958
955 959 "add", rev, fns: out-of-order traversal of the given file names
956 960 fns, which changed during revision rev - use to gather data for
957 961 possible display
958 962
959 963 "iter", rev, None: in-order traversal of the revs earlier iterated
960 964 over with "add" - use to display data'''
961 965
962 966 def increasing_windows(start, end, windowsize=8, sizelimit=512):
963 967 if start < end:
964 968 while start < end:
965 969 yield start, min(windowsize, end-start)
966 970 start += windowsize
967 971 if windowsize < sizelimit:
968 972 windowsize *= 2
969 973 else:
970 974 while start > end:
971 975 yield start, min(windowsize, start-end-1)
972 976 start -= windowsize
973 977 if windowsize < sizelimit:
974 978 windowsize *= 2
975 979
976 980 m = match(repo, pats, opts)
977 981 follow = opts.get('follow') or opts.get('follow_first')
978 982
979 983 if repo.changelog.count() == 0:
980 984 return [], m
981 985
982 986 if follow:
983 987 defrange = '%s:0' % repo.changectx().rev()
984 988 else:
985 989 defrange = '-1:0'
986 990 revs = revrange(repo, opts['rev'] or [defrange])
987 991 wanted = {}
988 992 slowpath = m.anypats() or opts.get('removed')
989 993 fncache = {}
990 994
991 995 if not slowpath and not m.files():
992 996 # No files, no patterns. Display all revs.
993 997 wanted = dict.fromkeys(revs)
994 998 copies = []
995 999 if not slowpath:
996 1000 # Only files, no patterns. Check the history of each file.
997 1001 def filerevgen(filelog, node):
998 1002 cl_count = repo.changelog.count()
999 1003 if node is None:
1000 1004 last = filelog.count() - 1
1001 1005 else:
1002 1006 last = filelog.rev(node)
1003 1007 for i, window in increasing_windows(last, nullrev):
1004 1008 revs = []
1005 1009 for j in xrange(i - window, i + 1):
1006 1010 n = filelog.node(j)
1007 1011 revs.append((filelog.linkrev(n),
1008 1012 follow and filelog.renamed(n)))
1009 1013 revs.reverse()
1010 1014 for rev in revs:
1011 1015 # only yield rev for which we have the changelog, it can
1012 1016 # happen while doing "hg log" during a pull or commit
1013 1017 if rev[0] < cl_count:
1014 1018 yield rev
1015 1019 def iterfiles():
1016 1020 for filename in m.files():
1017 1021 yield filename, None
1018 1022 for filename_node in copies:
1019 1023 yield filename_node
1020 1024 minrev, maxrev = min(revs), max(revs)
1021 1025 for file_, node in iterfiles():
1022 1026 filelog = repo.file(file_)
1023 1027 if filelog.count() == 0:
1024 1028 if node is None:
1025 1029 # A zero count may be a directory or deleted file, so
1026 1030 # try to find matching entries on the slow path.
1027 1031 slowpath = True
1028 1032 break
1029 1033 else:
1030 1034 ui.warn(_('%s:%s copy source revision cannot be found!\n')
1031 1035 % (file_, short(node)))
1032 1036 continue
1033 1037 for rev, copied in filerevgen(filelog, node):
1034 1038 if rev <= maxrev:
1035 1039 if rev < minrev:
1036 1040 break
1037 1041 fncache.setdefault(rev, [])
1038 1042 fncache[rev].append(file_)
1039 1043 wanted[rev] = 1
1040 1044 if follow and copied:
1041 1045 copies.append(copied)
1042 1046 if slowpath:
1043 1047 if follow:
1044 1048 raise util.Abort(_('can only follow copies/renames for explicit '
1045 1049 'file names'))
1046 1050
1047 1051 # The slow path checks files modified in every changeset.
1048 1052 def changerevgen():
1049 1053 for i, window in increasing_windows(repo.changelog.count()-1,
1050 1054 nullrev):
1051 1055 for j in xrange(i - window, i + 1):
1052 1056 yield j, change(j)[3]
1053 1057
1054 1058 for rev, changefiles in changerevgen():
1055 1059 matches = filter(m, changefiles)
1056 1060 if matches:
1057 1061 fncache[rev] = matches
1058 1062 wanted[rev] = 1
1059 1063
1060 1064 class followfilter:
1061 1065 def __init__(self, onlyfirst=False):
1062 1066 self.startrev = nullrev
1063 1067 self.roots = []
1064 1068 self.onlyfirst = onlyfirst
1065 1069
1066 1070 def match(self, rev):
1067 1071 def realparents(rev):
1068 1072 if self.onlyfirst:
1069 1073 return repo.changelog.parentrevs(rev)[0:1]
1070 1074 else:
1071 1075 return filter(lambda x: x != nullrev,
1072 1076 repo.changelog.parentrevs(rev))
1073 1077
1074 1078 if self.startrev == nullrev:
1075 1079 self.startrev = rev
1076 1080 return True
1077 1081
1078 1082 if rev > self.startrev:
1079 1083 # forward: all descendants
1080 1084 if not self.roots:
1081 1085 self.roots.append(self.startrev)
1082 1086 for parent in realparents(rev):
1083 1087 if parent in self.roots:
1084 1088 self.roots.append(rev)
1085 1089 return True
1086 1090 else:
1087 1091 # backwards: all parents
1088 1092 if not self.roots:
1089 1093 self.roots.extend(realparents(self.startrev))
1090 1094 if rev in self.roots:
1091 1095 self.roots.remove(rev)
1092 1096 self.roots.extend(realparents(rev))
1093 1097 return True
1094 1098
1095 1099 return False
1096 1100
1097 1101 # it might be worthwhile to do this in the iterator if the rev range
1098 1102 # is descending and the prune args are all within that range
1099 1103 for rev in opts.get('prune', ()):
1100 1104 rev = repo.changelog.rev(repo.lookup(rev))
1101 1105 ff = followfilter()
1102 1106 stop = min(revs[0], revs[-1])
1103 1107 for x in xrange(rev, stop-1, -1):
1104 1108 if ff.match(x) and x in wanted:
1105 1109 del wanted[x]
1106 1110
1107 1111 def iterate():
1108 1112 if follow and not m.files():
1109 1113 ff = followfilter(onlyfirst=opts.get('follow_first'))
1110 1114 def want(rev):
1111 1115 if ff.match(rev) and rev in wanted:
1112 1116 return True
1113 1117 return False
1114 1118 else:
1115 1119 def want(rev):
1116 1120 return rev in wanted
1117 1121
1118 1122 for i, window in increasing_windows(0, len(revs)):
1119 1123 yield 'window', revs[0] < revs[-1], revs[-1]
1120 1124 nrevs = [rev for rev in revs[i:i+window] if want(rev)]
1121 1125 srevs = list(nrevs)
1122 1126 srevs.sort()
1123 1127 for rev in srevs:
1124 1128 fns = fncache.get(rev)
1125 1129 if not fns:
1126 1130 def fns_generator():
1127 1131 for f in change(rev)[3]:
1128 1132 if m(f):
1129 1133 yield f
1130 1134 fns = fns_generator()
1131 1135 yield 'add', rev, fns
1132 1136 for rev in nrevs:
1133 1137 yield 'iter', rev, None
1134 1138 return iterate(), m
1135 1139
1136 1140 def commit(ui, repo, commitfunc, pats, opts):
1137 1141 '''commit the specified files or all outstanding changes'''
1138 1142 date = opts.get('date')
1139 1143 if date:
1140 1144 opts['date'] = util.parsedate(date)
1141 1145 message = logmessage(opts)
1142 1146
1143 1147 # extract addremove carefully -- this function can be called from a command
1144 1148 # that doesn't support addremove
1145 1149 if opts.get('addremove'):
1146 1150 addremove(repo, pats, opts)
1147 1151
1148 1152 m = match(repo, pats, opts)
1149 1153 if pats:
1150 1154 status = repo.status(files=m.files(), match=m)
1151 1155 modified, added, removed, deleted, unknown = status[:5]
1152 1156 files = modified + added + removed
1153 1157 slist = None
1154 1158 for f in m.files():
1155 1159 if f == '.':
1156 1160 continue
1157 1161 if f not in files:
1158 1162 rf = repo.wjoin(f)
1159 1163 rel = repo.pathto(f)
1160 1164 try:
1161 1165 mode = os.lstat(rf)[stat.ST_MODE]
1162 1166 except OSError:
1163 1167 raise util.Abort(_("file %s not found!") % rel)
1164 1168 if stat.S_ISDIR(mode):
1165 1169 name = f + '/'
1166 1170 if slist is None:
1167 1171 slist = list(files)
1168 1172 slist.sort()
1169 1173 i = bisect.bisect(slist, name)
1170 1174 if i >= len(slist) or not slist[i].startswith(name):
1171 1175 raise util.Abort(_("no match under directory %s!")
1172 1176 % rel)
1173 1177 elif not (stat.S_ISREG(mode) or stat.S_ISLNK(mode)):
1174 1178 raise util.Abort(_("can't commit %s: "
1175 1179 "unsupported file type!") % rel)
1176 1180 elif f not in repo.dirstate:
1177 1181 raise util.Abort(_("file %s not tracked!") % rel)
1178 1182 else:
1179 1183 files = []
1180 1184 try:
1181 1185 return commitfunc(ui, repo, files, message, m, opts)
1182 1186 except ValueError, inst:
1183 1187 raise util.Abort(str(inst))
@@ -1,3327 +1,3327 b''
1 1 # commands.py - command processing for mercurial
2 2 #
3 3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
4 4 #
5 5 # This software may be used and distributed according to the terms
6 6 # of the GNU General Public License, incorporated herein by reference.
7 7
8 8 from node import hex, nullid, nullrev, short
9 9 from repo import RepoError, NoCapability
10 10 from i18n import _
11 11 import os, re, sys, urllib
12 12 import hg, util, revlog, bundlerepo, extensions, copies
13 13 import difflib, patch, time, help, mdiff, tempfile
14 14 import version, socket
15 15 import archival, changegroup, cmdutil, hgweb.server, sshserver, hbisect
16 16 import merge as merge_
17 17
18 18 # Commands start here, listed alphabetically
19 19
20 20 def add(ui, repo, *pats, **opts):
21 21 """add the specified files on the next commit
22 22
23 23 Schedule files to be version controlled and added to the repository.
24 24
25 25 The files will be added to the repository at the next commit. To
26 26 undo an add before that, see hg revert.
27 27
28 28 If no names are given, add all files in the repository.
29 29 """
30 30
31 31 rejected = None
32 32 exacts = {}
33 33 names = []
34 34 m = cmdutil.match(repo, pats, opts)
35 35 m.bad = lambda x,y: True
36 for src, abs, rel, exact in cmdutil.walk(repo, m):
37 if exact:
36 for src, abs in cmdutil.walk(repo, m):
37 if m.exact(abs):
38 38 if ui.verbose:
39 ui.status(_('adding %s\n') % rel)
39 ui.status(_('adding %s\n') % m.rel(abs))
40 40 names.append(abs)
41 41 exacts[abs] = 1
42 42 elif abs not in repo.dirstate:
43 ui.status(_('adding %s\n') % rel)
43 ui.status(_('adding %s\n') % m.rel(abs))
44 44 names.append(abs)
45 45 if not opts.get('dry_run'):
46 46 rejected = repo.add(names)
47 47 rejected = [p for p in rejected if p in exacts]
48 48 return rejected and 1 or 0
49 49
50 50 def addremove(ui, repo, *pats, **opts):
51 51 """add all new files, delete all missing files
52 52
53 53 Add all new files and remove all missing files from the repository.
54 54
55 55 New files are ignored if they match any of the patterns in .hgignore. As
56 56 with add, these changes take effect at the next commit.
57 57
58 58 Use the -s option to detect renamed files. With a parameter > 0,
59 59 this compares every removed file with every added file and records
60 60 those similar enough as renames. This option takes a percentage
61 61 between 0 (disabled) and 100 (files must be identical) as its
62 62 parameter. Detecting renamed files this way can be expensive.
63 63 """
64 64 try:
65 65 sim = float(opts.get('similarity') or 0)
66 66 except ValueError:
67 67 raise util.Abort(_('similarity must be a number'))
68 68 if sim < 0 or sim > 100:
69 69 raise util.Abort(_('similarity must be between 0 and 100'))
70 70 return cmdutil.addremove(repo, pats, opts, similarity=sim/100.)
71 71
72 72 def annotate(ui, repo, *pats, **opts):
73 73 """show changeset information per file line
74 74
75 75 List changes in files, showing the revision id responsible for each line
76 76
77 77 This command is useful to discover who did a change or when a change took
78 78 place.
79 79
80 80 Without the -a option, annotate will avoid processing files it
81 81 detects as binary. With -a, annotate will generate an annotation
82 82 anyway, probably with undesirable results.
83 83 """
84 84 datefunc = ui.quiet and util.shortdate or util.datestr
85 85 getdate = util.cachefunc(lambda x: datefunc(x[0].date()))
86 86
87 87 if not pats:
88 88 raise util.Abort(_('at least one file name or pattern required'))
89 89
90 90 opmap = [('user', lambda x: ui.shortuser(x[0].user())),
91 91 ('number', lambda x: str(x[0].rev())),
92 92 ('changeset', lambda x: short(x[0].node())),
93 93 ('date', getdate),
94 94 ('follow', lambda x: x[0].path()),
95 95 ]
96 96
97 97 if (not opts['user'] and not opts['changeset'] and not opts['date']
98 98 and not opts['follow']):
99 99 opts['number'] = 1
100 100
101 101 linenumber = opts.get('line_number') is not None
102 102 if (linenumber and (not opts['changeset']) and (not opts['number'])):
103 103 raise util.Abort(_('at least one of -n/-c is required for -l'))
104 104
105 105 funcmap = [func for op, func in opmap if opts.get(op)]
106 106 if linenumber:
107 107 lastfunc = funcmap[-1]
108 108 funcmap[-1] = lambda x: "%s:%s" % (lastfunc(x), x[1])
109 109
110 110 ctx = repo.changectx(opts['rev'])
111 111
112 112 m = cmdutil.match(repo, pats, opts)
113 for src, abs, rel, exact in cmdutil.walk(repo, m, ctx.node()):
113 for src, abs in cmdutil.walk(repo, m, ctx.node()):
114 114 fctx = ctx.filectx(abs)
115 115 if not opts['text'] and util.binary(fctx.data()):
116 ui.write(_("%s: binary file\n") % ((pats and rel) or abs))
116 ui.write(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs))
117 117 continue
118 118
119 119 lines = fctx.annotate(follow=opts.get('follow'),
120 120 linenumber=linenumber)
121 121 pieces = []
122 122
123 123 for f in funcmap:
124 124 l = [f(n) for n, dummy in lines]
125 125 if l:
126 126 m = max(map(len, l))
127 127 pieces.append(["%*s" % (m, x) for x in l])
128 128
129 129 if pieces:
130 130 for p, l in zip(zip(*pieces), lines):
131 131 ui.write("%s: %s" % (" ".join(p), l[1]))
132 132
133 133 def archive(ui, repo, dest, **opts):
134 134 '''create unversioned archive of a repository revision
135 135
136 136 By default, the revision used is the parent of the working
137 137 directory; use "-r" to specify a different revision.
138 138
139 139 To specify the type of archive to create, use "-t". Valid
140 140 types are:
141 141
142 142 "files" (default): a directory full of files
143 143 "tar": tar archive, uncompressed
144 144 "tbz2": tar archive, compressed using bzip2
145 145 "tgz": tar archive, compressed using gzip
146 146 "uzip": zip archive, uncompressed
147 147 "zip": zip archive, compressed using deflate
148 148
149 149 The exact name of the destination archive or directory is given
150 150 using a format string; see "hg help export" for details.
151 151
152 152 Each member added to an archive file has a directory prefix
153 153 prepended. Use "-p" to specify a format string for the prefix.
154 154 The default is the basename of the archive, with suffixes removed.
155 155 '''
156 156
157 157 ctx = repo.changectx(opts['rev'])
158 158 if not ctx:
159 159 raise util.Abort(_('repository has no revisions'))
160 160 node = ctx.node()
161 161 dest = cmdutil.make_filename(repo, dest, node)
162 162 if os.path.realpath(dest) == repo.root:
163 163 raise util.Abort(_('repository root cannot be destination'))
164 164 matchfn = cmdutil.match(repo, [], opts)
165 165 kind = opts.get('type') or 'files'
166 166 prefix = opts['prefix']
167 167 if dest == '-':
168 168 if kind == 'files':
169 169 raise util.Abort(_('cannot archive plain files to stdout'))
170 170 dest = sys.stdout
171 171 if not prefix: prefix = os.path.basename(repo.root) + '-%h'
172 172 prefix = cmdutil.make_filename(repo, prefix, node)
173 173 archival.archive(repo, dest, node, kind, not opts['no_decode'],
174 174 matchfn, prefix)
175 175
176 176 def backout(ui, repo, node=None, rev=None, **opts):
177 177 '''reverse effect of earlier changeset
178 178
179 179 Commit the backed out changes as a new changeset. The new
180 180 changeset is a child of the backed out changeset.
181 181
182 182 If you back out a changeset other than the tip, a new head is
183 183 created. This head will be the new tip and you should merge this
184 184 backout changeset with another head (current one by default).
185 185
186 186 The --merge option remembers the parent of the working directory
187 187 before starting the backout, then merges the new head with that
188 188 changeset afterwards. This saves you from doing the merge by
189 189 hand. The result of this merge is not committed, as for a normal
190 190 merge.
191 191
192 192 See 'hg help dates' for a list of formats valid for -d/--date.
193 193 '''
194 194 if rev and node:
195 195 raise util.Abort(_("please specify just one revision"))
196 196
197 197 if not rev:
198 198 rev = node
199 199
200 200 if not rev:
201 201 raise util.Abort(_("please specify a revision to backout"))
202 202
203 203 date = opts.get('date')
204 204 if date:
205 205 opts['date'] = util.parsedate(date)
206 206
207 207 cmdutil.bail_if_changed(repo)
208 208 node = repo.lookup(rev)
209 209
210 210 op1, op2 = repo.dirstate.parents()
211 211 a = repo.changelog.ancestor(op1, node)
212 212 if a != node:
213 213 raise util.Abort(_('cannot back out change on a different branch'))
214 214
215 215 p1, p2 = repo.changelog.parents(node)
216 216 if p1 == nullid:
217 217 raise util.Abort(_('cannot back out a change with no parents'))
218 218 if p2 != nullid:
219 219 if not opts['parent']:
220 220 raise util.Abort(_('cannot back out a merge changeset without '
221 221 '--parent'))
222 222 p = repo.lookup(opts['parent'])
223 223 if p not in (p1, p2):
224 224 raise util.Abort(_('%s is not a parent of %s') %
225 225 (short(p), short(node)))
226 226 parent = p
227 227 else:
228 228 if opts['parent']:
229 229 raise util.Abort(_('cannot use --parent on non-merge changeset'))
230 230 parent = p1
231 231
232 232 # the backout should appear on the same branch
233 233 branch = repo.dirstate.branch()
234 234 hg.clean(repo, node, show_stats=False)
235 235 repo.dirstate.setbranch(branch)
236 236 revert_opts = opts.copy()
237 237 revert_opts['date'] = None
238 238 revert_opts['all'] = True
239 239 revert_opts['rev'] = hex(parent)
240 240 revert_opts['no_backup'] = None
241 241 revert(ui, repo, **revert_opts)
242 242 commit_opts = opts.copy()
243 243 commit_opts['addremove'] = False
244 244 if not commit_opts['message'] and not commit_opts['logfile']:
245 245 commit_opts['message'] = _("Backed out changeset %s") % (short(node))
246 246 commit_opts['force_editor'] = True
247 247 commit(ui, repo, **commit_opts)
248 248 def nice(node):
249 249 return '%d:%s' % (repo.changelog.rev(node), short(node))
250 250 ui.status(_('changeset %s backs out changeset %s\n') %
251 251 (nice(repo.changelog.tip()), nice(node)))
252 252 if op1 != node:
253 253 hg.clean(repo, op1, show_stats=False)
254 254 if opts['merge']:
255 255 ui.status(_('merging with changeset %s\n') % nice(repo.changelog.tip()))
256 256 hg.merge(repo, hex(repo.changelog.tip()))
257 257 else:
258 258 ui.status(_('the backout changeset is a new head - '
259 259 'do not forget to merge\n'))
260 260 ui.status(_('(use "backout --merge" '
261 261 'if you want to auto-merge)\n'))
262 262
263 263 def bisect(ui, repo, rev=None, extra=None,
264 264 reset=None, good=None, bad=None, skip=None, noupdate=None):
265 265 """subdivision search of changesets
266 266
267 267 This command helps to find changesets which introduce problems.
268 268 To use, mark the earliest changeset you know exhibits the problem
269 269 as bad, then mark the latest changeset which is free from the
270 270 problem as good. Bisect will update your working directory to a
271 271 revision for testing. Once you have performed tests, mark the
272 272 working directory as bad or good and bisect will either update to
273 273 another candidate changeset or announce that it has found the bad
274 274 revision.
275 275 """
276 276 # backward compatibility
277 277 if rev in "good bad reset init".split():
278 278 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
279 279 cmd, rev, extra = rev, extra, None
280 280 if cmd == "good":
281 281 good = True
282 282 elif cmd == "bad":
283 283 bad = True
284 284 else:
285 285 reset = True
286 286 elif extra or good + bad + skip + reset > 1:
287 287 raise util.Abort("Incompatible arguments")
288 288
289 289 if reset:
290 290 p = repo.join("bisect.state")
291 291 if os.path.exists(p):
292 292 os.unlink(p)
293 293 return
294 294
295 295 # load state
296 296 state = {'good': [], 'bad': [], 'skip': []}
297 297 if os.path.exists(repo.join("bisect.state")):
298 298 for l in repo.opener("bisect.state"):
299 299 kind, node = l[:-1].split()
300 300 node = repo.lookup(node)
301 301 if kind not in state:
302 302 raise util.Abort(_("unknown bisect kind %s") % kind)
303 303 state[kind].append(node)
304 304
305 305 # update state
306 306 node = repo.lookup(rev or '.')
307 307 if good:
308 308 state['good'].append(node)
309 309 elif bad:
310 310 state['bad'].append(node)
311 311 elif skip:
312 312 state['skip'].append(node)
313 313
314 314 # save state
315 315 f = repo.opener("bisect.state", "w", atomictemp=True)
316 316 wlock = repo.wlock()
317 317 try:
318 318 for kind in state:
319 319 for node in state[kind]:
320 320 f.write("%s %s\n" % (kind, hex(node)))
321 321 f.rename()
322 322 finally:
323 323 del wlock
324 324
325 325 if not state['good'] or not state['bad']:
326 326 return
327 327
328 328 # actually bisect
329 329 node, changesets, good = hbisect.bisect(repo.changelog, state)
330 330 if changesets == 0:
331 331 ui.write(_("The first %s revision is:\n") % (good and "good" or "bad"))
332 332 displayer = cmdutil.show_changeset(ui, repo, {})
333 333 displayer.show(changenode=node)
334 334 elif node is not None:
335 335 # compute the approximate number of remaining tests
336 336 tests, size = 0, 2
337 337 while size <= changesets:
338 338 tests, size = tests + 1, size * 2
339 339 rev = repo.changelog.rev(node)
340 340 ui.write(_("Testing changeset %s:%s "
341 341 "(%s changesets remaining, ~%s tests)\n")
342 342 % (rev, short(node), changesets, tests))
343 343 if not noupdate:
344 344 cmdutil.bail_if_changed(repo)
345 345 return hg.clean(repo, node)
346 346
347 347 def branch(ui, repo, label=None, **opts):
348 348 """set or show the current branch name
349 349
350 350 With no argument, show the current branch name. With one argument,
351 351 set the working directory branch name (the branch does not exist in
352 352 the repository until the next commit).
353 353
354 354 Unless --force is specified, branch will not let you set a
355 355 branch name that shadows an existing branch.
356 356
357 357 Use the command 'hg update' to switch to an existing branch.
358 358 """
359 359
360 360 if label:
361 361 if not opts.get('force') and label in repo.branchtags():
362 362 if label not in [p.branch() for p in repo.workingctx().parents()]:
363 363 raise util.Abort(_('a branch of the same name already exists'
364 364 ' (use --force to override)'))
365 365 repo.dirstate.setbranch(util.fromlocal(label))
366 366 ui.status(_('marked working directory as branch %s\n') % label)
367 367 else:
368 368 ui.write("%s\n" % util.tolocal(repo.dirstate.branch()))
369 369
370 370 def branches(ui, repo, active=False):
371 371 """list repository named branches
372 372
373 373 List the repository's named branches, indicating which ones are
374 374 inactive. If active is specified, only show active branches.
375 375
376 376 A branch is considered active if it contains unmerged heads.
377 377
378 378 Use the command 'hg update' to switch to an existing branch.
379 379 """
380 380 b = repo.branchtags()
381 381 heads = dict.fromkeys(repo.heads(), 1)
382 382 l = [((n in heads), repo.changelog.rev(n), n, t) for t, n in b.items()]
383 383 l.sort()
384 384 l.reverse()
385 385 for ishead, r, n, t in l:
386 386 if active and not ishead:
387 387 # If we're only displaying active branches, abort the loop on
388 388 # encountering the first inactive head
389 389 break
390 390 else:
391 391 hexfunc = ui.debugflag and hex or short
392 392 if ui.quiet:
393 393 ui.write("%s\n" % t)
394 394 else:
395 395 spaces = " " * (30 - util.locallen(t))
396 396 # The code only gets here if inactive branches are being
397 397 # displayed or the branch is active.
398 398 isinactive = ((not ishead) and " (inactive)") or ''
399 399 ui.write("%s%s %s:%s%s\n" % (t, spaces, r, hexfunc(n), isinactive))
400 400
401 401 def bundle(ui, repo, fname, dest=None, **opts):
402 402 """create a changegroup file
403 403
404 404 Generate a compressed changegroup file collecting changesets not
405 405 found in the other repository.
406 406
407 407 If no destination repository is specified the destination is
408 408 assumed to have all the nodes specified by one or more --base
409 409 parameters. To create a bundle containing all changesets, use
410 410 --all (or --base null). To change the compression method applied,
411 411 use the -t option (by default, bundles are compressed using bz2).
412 412
413 413 The bundle file can then be transferred using conventional means and
414 414 applied to another repository with the unbundle or pull command.
415 415 This is useful when direct push and pull are not available or when
416 416 exporting an entire repository is undesirable.
417 417
418 418 Applying bundles preserves all changeset contents including
419 419 permissions, copy/rename information, and revision history.
420 420 """
421 421 revs = opts.get('rev') or None
422 422 if revs:
423 423 revs = [repo.lookup(rev) for rev in revs]
424 424 if opts.get('all'):
425 425 base = ['null']
426 426 else:
427 427 base = opts.get('base')
428 428 if base:
429 429 if dest:
430 430 raise util.Abort(_("--base is incompatible with specifiying "
431 431 "a destination"))
432 432 base = [repo.lookup(rev) for rev in base]
433 433 # create the right base
434 434 # XXX: nodesbetween / changegroup* should be "fixed" instead
435 435 o = []
436 436 has = {nullid: None}
437 437 for n in base:
438 438 has.update(repo.changelog.reachable(n))
439 439 if revs:
440 440 visit = list(revs)
441 441 else:
442 442 visit = repo.changelog.heads()
443 443 seen = {}
444 444 while visit:
445 445 n = visit.pop(0)
446 446 parents = [p for p in repo.changelog.parents(n) if p not in has]
447 447 if len(parents) == 0:
448 448 o.insert(0, n)
449 449 else:
450 450 for p in parents:
451 451 if p not in seen:
452 452 seen[p] = 1
453 453 visit.append(p)
454 454 else:
455 455 cmdutil.setremoteconfig(ui, opts)
456 456 dest, revs, checkout = hg.parseurl(
457 457 ui.expandpath(dest or 'default-push', dest or 'default'), revs)
458 458 other = hg.repository(ui, dest)
459 459 o = repo.findoutgoing(other, force=opts['force'])
460 460
461 461 if revs:
462 462 cg = repo.changegroupsubset(o, revs, 'bundle')
463 463 else:
464 464 cg = repo.changegroup(o, 'bundle')
465 465
466 466 bundletype = opts.get('type', 'bzip2').lower()
467 467 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
468 468 bundletype = btypes.get(bundletype)
469 469 if bundletype not in changegroup.bundletypes:
470 470 raise util.Abort(_('unknown bundle type specified with --type'))
471 471
472 472 changegroup.writebundle(cg, fname, bundletype)
473 473
474 474 def cat(ui, repo, file1, *pats, **opts):
475 475 """output the current or given revision of files
476 476
477 477 Print the specified files as they were at the given revision.
478 478 If no revision is given, the parent of the working directory is used,
479 479 or tip if no revision is checked out.
480 480
481 481 Output may be to a file, in which case the name of the file is
482 482 given using a format string. The formatting rules are the same as
483 483 for the export command, with the following additions:
484 484
485 485 %s basename of file being printed
486 486 %d dirname of file being printed, or '.' if in repo root
487 487 %p root-relative path name of file being printed
488 488 """
489 489 ctx = repo.changectx(opts['rev'])
490 490 err = 1
491 491 m = cmdutil.match(repo, (file1,) + pats, opts)
492 for src, abs, rel, exact in cmdutil.walk(repo, m, ctx.node()):
492 for src, abs in cmdutil.walk(repo, m, ctx.node()):
493 493 fp = cmdutil.make_file(repo, opts['output'], ctx.node(), pathname=abs)
494 494 data = ctx.filectx(abs).data()
495 495 if opts.get('decode'):
496 496 data = repo.wwritedata(abs, data)
497 497 fp.write(data)
498 498 err = 0
499 499 return err
500 500
501 501 def clone(ui, source, dest=None, **opts):
502 502 """make a copy of an existing repository
503 503
504 504 Create a copy of an existing repository in a new directory.
505 505
506 506 If no destination directory name is specified, it defaults to the
507 507 basename of the source.
508 508
509 509 The location of the source is added to the new repository's
510 510 .hg/hgrc file, as the default to be used for future pulls.
511 511
512 512 For efficiency, hardlinks are used for cloning whenever the source
513 513 and destination are on the same filesystem (note this applies only
514 514 to the repository data, not to the checked out files). Some
515 515 filesystems, such as AFS, implement hardlinking incorrectly, but
516 516 do not report errors. In these cases, use the --pull option to
517 517 avoid hardlinking.
518 518
519 519 In some cases, you can clone repositories and checked out files
520 520 using full hardlinks with
521 521
522 522 $ cp -al REPO REPOCLONE
523 523
524 524 This is the fastest way to clone, but it is not always safe. The
525 525 operation is not atomic (making sure REPO is not modified during
526 526 the operation is up to you) and you have to make sure your editor
527 527 breaks hardlinks (Emacs and most Linux Kernel tools do so). Also,
528 528 this is not compatible with certain extensions that place their
529 529 metadata under the .hg directory, such as mq.
530 530
531 531 If you use the -r option to clone up to a specific revision, no
532 532 subsequent revisions will be present in the cloned repository.
533 533 This option implies --pull, even on local repositories.
534 534
535 535 See pull for valid source format details.
536 536
537 537 It is possible to specify an ssh:// URL as the destination, but no
538 538 .hg/hgrc and working directory will be created on the remote side.
539 539 Look at the help text for the pull command for important details
540 540 about ssh:// URLs.
541 541 """
542 542 cmdutil.setremoteconfig(ui, opts)
543 543 hg.clone(ui, source, dest,
544 544 pull=opts['pull'],
545 545 stream=opts['uncompressed'],
546 546 rev=opts['rev'],
547 547 update=not opts['noupdate'])
548 548
549 549 def commit(ui, repo, *pats, **opts):
550 550 """commit the specified files or all outstanding changes
551 551
552 552 Commit changes to the given files into the repository.
553 553
554 554 If a list of files is omitted, all changes reported by "hg status"
555 555 will be committed.
556 556
557 557 If you are committing the result of a merge, do not provide any
558 558 file names or -I/-X filters.
559 559
560 560 If no commit message is specified, the configured editor is started to
561 561 enter a message.
562 562
563 563 See 'hg help dates' for a list of formats valid for -d/--date.
564 564 """
565 565 def commitfunc(ui, repo, files, message, match, opts):
566 566 return repo.commit(files, message, opts['user'], opts['date'], match,
567 567 force_editor=opts.get('force_editor'))
568 568
569 569 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
570 570 if not node:
571 571 return
572 572 cl = repo.changelog
573 573 rev = cl.rev(node)
574 574 parents = cl.parentrevs(rev)
575 575 if rev - 1 in parents:
576 576 # one of the parents was the old tip
577 577 return
578 578 if (parents == (nullrev, nullrev) or
579 579 len(cl.heads(cl.node(parents[0]))) > 1 and
580 580 (parents[1] == nullrev or len(cl.heads(cl.node(parents[1]))) > 1)):
581 581 ui.status(_('created new head\n'))
582 582
583 583 def copy(ui, repo, *pats, **opts):
584 584 """mark files as copied for the next commit
585 585
586 586 Mark dest as having copies of source files. If dest is a
587 587 directory, copies are put in that directory. If dest is a file,
588 588 there can only be one source.
589 589
590 590 By default, this command copies the contents of files as they
591 591 stand in the working directory. If invoked with --after, the
592 592 operation is recorded, but no copying is performed.
593 593
594 594 This command takes effect in the next commit. To undo a copy
595 595 before that, see hg revert.
596 596 """
597 597 wlock = repo.wlock(False)
598 598 try:
599 599 return cmdutil.copy(ui, repo, pats, opts)
600 600 finally:
601 601 del wlock
602 602
603 603 def debugancestor(ui, repo, *args):
604 604 """find the ancestor revision of two revisions in a given index"""
605 605 if len(args) == 3:
606 606 index, rev1, rev2 = args
607 607 r = revlog.revlog(util.opener(os.getcwd(), audit=False), index)
608 608 lookup = r.lookup
609 609 elif len(args) == 2:
610 610 if not repo:
611 611 raise util.Abort(_("There is no Mercurial repository here "
612 612 "(.hg not found)"))
613 613 rev1, rev2 = args
614 614 r = repo.changelog
615 615 lookup = repo.lookup
616 616 else:
617 617 raise util.Abort(_('either two or three arguments required'))
618 618 a = r.ancestor(lookup(rev1), lookup(rev2))
619 619 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
620 620
621 621 def debugcomplete(ui, cmd='', **opts):
622 622 """returns the completion list associated with the given command"""
623 623
624 624 if opts['options']:
625 625 options = []
626 626 otables = [globalopts]
627 627 if cmd:
628 628 aliases, entry = cmdutil.findcmd(ui, cmd, table)
629 629 otables.append(entry[1])
630 630 for t in otables:
631 631 for o in t:
632 632 if o[0]:
633 633 options.append('-%s' % o[0])
634 634 options.append('--%s' % o[1])
635 635 ui.write("%s\n" % "\n".join(options))
636 636 return
637 637
638 638 clist = cmdutil.findpossible(ui, cmd, table).keys()
639 639 clist.sort()
640 640 ui.write("%s\n" % "\n".join(clist))
641 641
642 642 def debugfsinfo(ui, path = "."):
643 643 file('.debugfsinfo', 'w').write('')
644 644 ui.write('exec: %s\n' % (util.checkexec(path) and 'yes' or 'no'))
645 645 ui.write('symlink: %s\n' % (util.checklink(path) and 'yes' or 'no'))
646 646 ui.write('case-sensitive: %s\n' % (util.checkfolding('.debugfsinfo')
647 647 and 'yes' or 'no'))
648 648 os.unlink('.debugfsinfo')
649 649
650 650 def debugrebuildstate(ui, repo, rev=""):
651 651 """rebuild the dirstate as it would look like for the given revision"""
652 652 if rev == "":
653 653 rev = repo.changelog.tip()
654 654 ctx = repo.changectx(rev)
655 655 files = ctx.manifest()
656 656 wlock = repo.wlock()
657 657 try:
658 658 repo.dirstate.rebuild(rev, files)
659 659 finally:
660 660 del wlock
661 661
662 662 def debugcheckstate(ui, repo):
663 663 """validate the correctness of the current dirstate"""
664 664 parent1, parent2 = repo.dirstate.parents()
665 665 m1 = repo.changectx(parent1).manifest()
666 666 m2 = repo.changectx(parent2).manifest()
667 667 errors = 0
668 668 for f in repo.dirstate:
669 669 state = repo.dirstate[f]
670 670 if state in "nr" and f not in m1:
671 671 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
672 672 errors += 1
673 673 if state in "a" and f in m1:
674 674 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
675 675 errors += 1
676 676 if state in "m" and f not in m1 and f not in m2:
677 677 ui.warn(_("%s in state %s, but not in either manifest\n") %
678 678 (f, state))
679 679 errors += 1
680 680 for f in m1:
681 681 state = repo.dirstate[f]
682 682 if state not in "nrm":
683 683 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
684 684 errors += 1
685 685 if errors:
686 686 error = _(".hg/dirstate inconsistent with current parent's manifest")
687 687 raise util.Abort(error)
688 688
689 689 def showconfig(ui, repo, *values, **opts):
690 690 """show combined config settings from all hgrc files
691 691
692 692 With no args, print names and values of all config items.
693 693
694 694 With one arg of the form section.name, print just the value of
695 695 that config item.
696 696
697 697 With multiple args, print names and values of all config items
698 698 with matching section names."""
699 699
700 700 untrusted = bool(opts.get('untrusted'))
701 701 if values:
702 702 if len([v for v in values if '.' in v]) > 1:
703 703 raise util.Abort(_('only one config item permitted'))
704 704 for section, name, value in ui.walkconfig(untrusted=untrusted):
705 705 sectname = section + '.' + name
706 706 if values:
707 707 for v in values:
708 708 if v == section:
709 709 ui.write('%s=%s\n' % (sectname, value))
710 710 elif v == sectname:
711 711 ui.write(value, '\n')
712 712 else:
713 713 ui.write('%s=%s\n' % (sectname, value))
714 714
715 715 def debugsetparents(ui, repo, rev1, rev2=None):
716 716 """manually set the parents of the current working directory
717 717
718 718 This is useful for writing repository conversion tools, but should
719 719 be used with care.
720 720 """
721 721
722 722 if not rev2:
723 723 rev2 = hex(nullid)
724 724
725 725 wlock = repo.wlock()
726 726 try:
727 727 repo.dirstate.setparents(repo.lookup(rev1), repo.lookup(rev2))
728 728 finally:
729 729 del wlock
730 730
731 731 def debugstate(ui, repo, nodates=None):
732 732 """show the contents of the current dirstate"""
733 733 k = repo.dirstate._map.items()
734 734 k.sort()
735 735 timestr = ""
736 736 showdate = not nodates
737 737 for file_, ent in k:
738 738 if showdate:
739 739 if ent[3] == -1:
740 740 # Pad or slice to locale representation
741 741 locale_len = len(time.strftime("%Y-%m-%d %H:%M:%S ", time.localtime(0)))
742 742 timestr = 'unset'
743 743 timestr = timestr[:locale_len] + ' '*(locale_len - len(timestr))
744 744 else:
745 745 timestr = time.strftime("%Y-%m-%d %H:%M:%S ", time.localtime(ent[3]))
746 746 if ent[1] & 020000:
747 747 mode = 'lnk'
748 748 else:
749 749 mode = '%3o' % (ent[1] & 0777)
750 750 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
751 751 for f in repo.dirstate.copies():
752 752 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
753 753
754 754 def debugdata(ui, file_, rev):
755 755 """dump the contents of a data file revision"""
756 756 r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_[:-2] + ".i")
757 757 try:
758 758 ui.write(r.revision(r.lookup(rev)))
759 759 except KeyError:
760 760 raise util.Abort(_('invalid revision identifier %s') % rev)
761 761
762 762 def debugdate(ui, date, range=None, **opts):
763 763 """parse and display a date"""
764 764 if opts["extended"]:
765 765 d = util.parsedate(date, util.extendeddateformats)
766 766 else:
767 767 d = util.parsedate(date)
768 768 ui.write("internal: %s %s\n" % d)
769 769 ui.write("standard: %s\n" % util.datestr(d))
770 770 if range:
771 771 m = util.matchdate(range)
772 772 ui.write("match: %s\n" % m(d[0]))
773 773
774 774 def debugindex(ui, file_):
775 775 """dump the contents of an index file"""
776 776 r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_)
777 777 ui.write(" rev offset length base linkrev" +
778 778 " nodeid p1 p2\n")
779 779 for i in xrange(r.count()):
780 780 node = r.node(i)
781 781 try:
782 782 pp = r.parents(node)
783 783 except:
784 784 pp = [nullid, nullid]
785 785 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
786 786 i, r.start(i), r.length(i), r.base(i), r.linkrev(node),
787 787 short(node), short(pp[0]), short(pp[1])))
788 788
789 789 def debugindexdot(ui, file_):
790 790 """dump an index DAG as a .dot file"""
791 791 r = revlog.revlog(util.opener(os.getcwd(), audit=False), file_)
792 792 ui.write("digraph G {\n")
793 793 for i in xrange(r.count()):
794 794 node = r.node(i)
795 795 pp = r.parents(node)
796 796 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
797 797 if pp[1] != nullid:
798 798 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
799 799 ui.write("}\n")
800 800
801 801 def debuginstall(ui):
802 802 '''test Mercurial installation'''
803 803
804 804 def writetemp(contents):
805 805 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
806 806 f = os.fdopen(fd, "wb")
807 807 f.write(contents)
808 808 f.close()
809 809 return name
810 810
811 811 problems = 0
812 812
813 813 # encoding
814 814 ui.status(_("Checking encoding (%s)...\n") % util._encoding)
815 815 try:
816 816 util.fromlocal("test")
817 817 except util.Abort, inst:
818 818 ui.write(" %s\n" % inst)
819 819 ui.write(_(" (check that your locale is properly set)\n"))
820 820 problems += 1
821 821
822 822 # compiled modules
823 823 ui.status(_("Checking extensions...\n"))
824 824 try:
825 825 import bdiff, mpatch, base85
826 826 except Exception, inst:
827 827 ui.write(" %s\n" % inst)
828 828 ui.write(_(" One or more extensions could not be found"))
829 829 ui.write(_(" (check that you compiled the extensions)\n"))
830 830 problems += 1
831 831
832 832 # templates
833 833 ui.status(_("Checking templates...\n"))
834 834 try:
835 835 import templater
836 836 t = templater.templater(templater.templatepath("map-cmdline.default"))
837 837 except Exception, inst:
838 838 ui.write(" %s\n" % inst)
839 839 ui.write(_(" (templates seem to have been installed incorrectly)\n"))
840 840 problems += 1
841 841
842 842 # patch
843 843 ui.status(_("Checking patch...\n"))
844 844 patchproblems = 0
845 845 a = "1\n2\n3\n4\n"
846 846 b = "1\n2\n3\ninsert\n4\n"
847 847 fa = writetemp(a)
848 848 d = mdiff.unidiff(a, None, b, None, os.path.basename(fa),
849 849 os.path.basename(fa))
850 850 fd = writetemp(d)
851 851
852 852 files = {}
853 853 try:
854 854 patch.patch(fd, ui, cwd=os.path.dirname(fa), files=files)
855 855 except util.Abort, e:
856 856 ui.write(_(" patch call failed:\n"))
857 857 ui.write(" " + str(e) + "\n")
858 858 patchproblems += 1
859 859 else:
860 860 if list(files) != [os.path.basename(fa)]:
861 861 ui.write(_(" unexpected patch output!\n"))
862 862 patchproblems += 1
863 863 a = file(fa).read()
864 864 if a != b:
865 865 ui.write(_(" patch test failed!\n"))
866 866 patchproblems += 1
867 867
868 868 if patchproblems:
869 869 if ui.config('ui', 'patch'):
870 870 ui.write(_(" (Current patch tool may be incompatible with patch,"
871 871 " or misconfigured. Please check your .hgrc file)\n"))
872 872 else:
873 873 ui.write(_(" Internal patcher failure, please report this error"
874 874 " to http://www.selenic.com/mercurial/bts\n"))
875 875 problems += patchproblems
876 876
877 877 os.unlink(fa)
878 878 os.unlink(fd)
879 879
880 880 # editor
881 881 ui.status(_("Checking commit editor...\n"))
882 882 editor = ui.geteditor()
883 883 cmdpath = util.find_exe(editor) or util.find_exe(editor.split()[0])
884 884 if not cmdpath:
885 885 if editor == 'vi':
886 886 ui.write(_(" No commit editor set and can't find vi in PATH\n"))
887 887 ui.write(_(" (specify a commit editor in your .hgrc file)\n"))
888 888 else:
889 889 ui.write(_(" Can't find editor '%s' in PATH\n") % editor)
890 890 ui.write(_(" (specify a commit editor in your .hgrc file)\n"))
891 891 problems += 1
892 892
893 893 # check username
894 894 ui.status(_("Checking username...\n"))
895 895 user = os.environ.get("HGUSER")
896 896 if user is None:
897 897 user = ui.config("ui", "username")
898 898 if user is None:
899 899 user = os.environ.get("EMAIL")
900 900 if not user:
901 901 ui.warn(" ")
902 902 ui.username()
903 903 ui.write(_(" (specify a username in your .hgrc file)\n"))
904 904
905 905 if not problems:
906 906 ui.status(_("No problems detected\n"))
907 907 else:
908 908 ui.write(_("%s problems detected,"
909 909 " please check your install!\n") % problems)
910 910
911 911 return problems
912 912
913 913 def debugrename(ui, repo, file1, *pats, **opts):
914 914 """dump rename information"""
915 915
916 916 ctx = repo.changectx(opts.get('rev', 'tip'))
917 917 m = cmdutil.match(repo, (file1,) + pats, opts)
918 for src, abs, rel, exact in cmdutil.walk(repo, m, ctx.node()):
918 for src, abs in cmdutil.walk(repo, m, ctx.node()):
919 919 fctx = ctx.filectx(abs)
920 920 o = fctx.filelog().renamed(fctx.filenode())
921 rel = m.rel(abs)
921 922 if o:
922 923 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
923 924 else:
924 925 ui.write(_("%s not renamed\n") % rel)
925 926
926 927 def debugwalk(ui, repo, *pats, **opts):
927 928 """show how files match on given patterns"""
928 929 m = cmdutil.match(repo, pats, opts)
929 930 items = list(cmdutil.walk(repo, m))
930 931 if not items:
931 932 return
932 933 fmt = '%%s %%-%ds %%-%ds %%s' % (
933 max([len(abs) for (src, abs, rel, exact) in items]),
934 max([len(rel) for (src, abs, rel, exact) in items]))
935 for src, abs, rel, exact in items:
936 line = fmt % (src, abs, rel, exact and 'exact' or '')
934 max([len(abs) for (src, abs) in items]),
935 max([len(m.rel(abs)) for (src, abs) in items]))
936 for src, abs in items:
937 line = fmt % (src, abs, m.rel(abs), m.exact(abs) and 'exact' or '')
937 938 ui.write("%s\n" % line.rstrip())
938 939
939 940 def diff(ui, repo, *pats, **opts):
940 941 """diff repository (or selected files)
941 942
942 943 Show differences between revisions for the specified files.
943 944
944 945 Differences between files are shown using the unified diff format.
945 946
946 947 NOTE: diff may generate unexpected results for merges, as it will
947 948 default to comparing against the working directory's first parent
948 949 changeset if no revisions are specified.
949 950
950 951 When two revision arguments are given, then changes are shown
951 952 between those revisions. If only one revision is specified then
952 953 that revision is compared to the working directory, and, when no
953 954 revisions are specified, the working directory files are compared
954 955 to its parent.
955 956
956 957 Without the -a option, diff will avoid generating diffs of files
957 958 it detects as binary. With -a, diff will generate a diff anyway,
958 959 probably with undesirable results.
959 960 """
960 961 node1, node2 = cmdutil.revpair(repo, opts['rev'])
961 962
962 963 m = cmdutil.match(repo, pats, opts)
963 964 patch.diff(repo, node1, node2, m.files(), match=m,
964 965 opts=patch.diffopts(ui, opts))
965 966
966 967 def export(ui, repo, *changesets, **opts):
967 968 """dump the header and diffs for one or more changesets
968 969
969 970 Print the changeset header and diffs for one or more revisions.
970 971
971 972 The information shown in the changeset header is: author,
972 973 changeset hash, parent(s) and commit comment.
973 974
974 975 NOTE: export may generate unexpected diff output for merge changesets,
975 976 as it will compare the merge changeset against its first parent only.
976 977
977 978 Output may be to a file, in which case the name of the file is
978 979 given using a format string. The formatting rules are as follows:
979 980
980 981 %% literal "%" character
981 982 %H changeset hash (40 bytes of hexadecimal)
982 983 %N number of patches being generated
983 984 %R changeset revision number
984 985 %b basename of the exporting repository
985 986 %h short-form changeset hash (12 bytes of hexadecimal)
986 987 %n zero-padded sequence number, starting at 1
987 988 %r zero-padded changeset revision number
988 989
989 990 Without the -a option, export will avoid generating diffs of files
990 991 it detects as binary. With -a, export will generate a diff anyway,
991 992 probably with undesirable results.
992 993
993 994 With the --switch-parent option, the diff will be against the second
994 995 parent. It can be useful to review a merge.
995 996 """
996 997 if not changesets:
997 998 raise util.Abort(_("export requires at least one changeset"))
998 999 revs = cmdutil.revrange(repo, changesets)
999 1000 if len(revs) > 1:
1000 1001 ui.note(_('exporting patches:\n'))
1001 1002 else:
1002 1003 ui.note(_('exporting patch:\n'))
1003 1004 patch.export(repo, revs, template=opts['output'],
1004 1005 switch_parent=opts['switch_parent'],
1005 1006 opts=patch.diffopts(ui, opts))
1006 1007
1007 1008 def grep(ui, repo, pattern, *pats, **opts):
1008 1009 """search for a pattern in specified files and revisions
1009 1010
1010 1011 Search revisions of files for a regular expression.
1011 1012
1012 1013 This command behaves differently than Unix grep. It only accepts
1013 1014 Python/Perl regexps. It searches repository history, not the
1014 1015 working directory. It always prints the revision number in which
1015 1016 a match appears.
1016 1017
1017 1018 By default, grep only prints output for the first revision of a
1018 1019 file in which it finds a match. To get it to print every revision
1019 1020 that contains a change in match status ("-" for a match that
1020 1021 becomes a non-match, or "+" for a non-match that becomes a match),
1021 1022 use the --all flag.
1022 1023 """
1023 1024 reflags = 0
1024 1025 if opts['ignore_case']:
1025 1026 reflags |= re.I
1026 1027 try:
1027 1028 regexp = re.compile(pattern, reflags)
1028 1029 except Exception, inst:
1029 1030 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
1030 1031 return None
1031 1032 sep, eol = ':', '\n'
1032 1033 if opts['print0']:
1033 1034 sep = eol = '\0'
1034 1035
1035 1036 fcache = {}
1036 1037 def getfile(fn):
1037 1038 if fn not in fcache:
1038 1039 fcache[fn] = repo.file(fn)
1039 1040 return fcache[fn]
1040 1041
1041 1042 def matchlines(body):
1042 1043 begin = 0
1043 1044 linenum = 0
1044 1045 while True:
1045 1046 match = regexp.search(body, begin)
1046 1047 if not match:
1047 1048 break
1048 1049 mstart, mend = match.span()
1049 1050 linenum += body.count('\n', begin, mstart) + 1
1050 1051 lstart = body.rfind('\n', begin, mstart) + 1 or begin
1051 1052 lend = body.find('\n', mend)
1052 1053 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
1053 1054 begin = lend + 1
1054 1055
1055 1056 class linestate(object):
1056 1057 def __init__(self, line, linenum, colstart, colend):
1057 1058 self.line = line
1058 1059 self.linenum = linenum
1059 1060 self.colstart = colstart
1060 1061 self.colend = colend
1061 1062
1062 1063 def __hash__(self):
1063 1064 return hash((self.linenum, self.line))
1064 1065
1065 1066 def __eq__(self, other):
1066 1067 return self.line == other.line
1067 1068
1068 1069 matches = {}
1069 1070 copies = {}
1070 1071 def grepbody(fn, rev, body):
1071 1072 matches[rev].setdefault(fn, [])
1072 1073 m = matches[rev][fn]
1073 1074 for lnum, cstart, cend, line in matchlines(body):
1074 1075 s = linestate(line, lnum, cstart, cend)
1075 1076 m.append(s)
1076 1077
1077 1078 def difflinestates(a, b):
1078 1079 sm = difflib.SequenceMatcher(None, a, b)
1079 1080 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
1080 1081 if tag == 'insert':
1081 1082 for i in xrange(blo, bhi):
1082 1083 yield ('+', b[i])
1083 1084 elif tag == 'delete':
1084 1085 for i in xrange(alo, ahi):
1085 1086 yield ('-', a[i])
1086 1087 elif tag == 'replace':
1087 1088 for i in xrange(alo, ahi):
1088 1089 yield ('-', a[i])
1089 1090 for i in xrange(blo, bhi):
1090 1091 yield ('+', b[i])
1091 1092
1092 1093 prev = {}
1093 1094 def display(fn, rev, states, prevstates):
1094 1095 datefunc = ui.quiet and util.shortdate or util.datestr
1095 1096 found = False
1096 1097 filerevmatches = {}
1097 1098 r = prev.get(fn, -1)
1098 1099 if opts['all']:
1099 1100 iter = difflinestates(states, prevstates)
1100 1101 else:
1101 1102 iter = [('', l) for l in prevstates]
1102 1103 for change, l in iter:
1103 1104 cols = [fn, str(r)]
1104 1105 if opts['line_number']:
1105 1106 cols.append(str(l.linenum))
1106 1107 if opts['all']:
1107 1108 cols.append(change)
1108 1109 if opts['user']:
1109 1110 cols.append(ui.shortuser(get(r)[1]))
1110 1111 if opts.get('date'):
1111 1112 cols.append(datefunc(get(r)[2]))
1112 1113 if opts['files_with_matches']:
1113 1114 c = (fn, r)
1114 1115 if c in filerevmatches:
1115 1116 continue
1116 1117 filerevmatches[c] = 1
1117 1118 else:
1118 1119 cols.append(l.line)
1119 1120 ui.write(sep.join(cols), eol)
1120 1121 found = True
1121 1122 return found
1122 1123
1123 1124 fstate = {}
1124 1125 skip = {}
1125 1126 get = util.cachefunc(lambda r: repo.changectx(r).changeset())
1126 1127 changeiter, matchfn = cmdutil.walkchangerevs(ui, repo, pats, get, opts)
1127 1128 found = False
1128 1129 follow = opts.get('follow')
1129 1130 for st, rev, fns in changeiter:
1130 1131 if st == 'window':
1131 1132 matches.clear()
1132 1133 elif st == 'add':
1133 1134 ctx = repo.changectx(rev)
1134 1135 matches[rev] = {}
1135 1136 for fn in fns:
1136 1137 if fn in skip:
1137 1138 continue
1138 1139 try:
1139 1140 grepbody(fn, rev, getfile(fn).read(ctx.filenode(fn)))
1140 1141 fstate.setdefault(fn, [])
1141 1142 if follow:
1142 1143 copied = getfile(fn).renamed(ctx.filenode(fn))
1143 1144 if copied:
1144 1145 copies.setdefault(rev, {})[fn] = copied[0]
1145 1146 except revlog.LookupError:
1146 1147 pass
1147 1148 elif st == 'iter':
1148 1149 states = matches[rev].items()
1149 1150 states.sort()
1150 1151 for fn, m in states:
1151 1152 copy = copies.get(rev, {}).get(fn)
1152 1153 if fn in skip:
1153 1154 if copy:
1154 1155 skip[copy] = True
1155 1156 continue
1156 1157 if fn in prev or fstate[fn]:
1157 1158 r = display(fn, rev, m, fstate[fn])
1158 1159 found = found or r
1159 1160 if r and not opts['all']:
1160 1161 skip[fn] = True
1161 1162 if copy:
1162 1163 skip[copy] = True
1163 1164 fstate[fn] = m
1164 1165 if copy:
1165 1166 fstate[copy] = m
1166 1167 prev[fn] = rev
1167 1168
1168 1169 fstate = fstate.items()
1169 1170 fstate.sort()
1170 1171 for fn, state in fstate:
1171 1172 if fn in skip:
1172 1173 continue
1173 1174 if fn not in copies.get(prev[fn], {}):
1174 1175 found = display(fn, rev, {}, state) or found
1175 1176 return (not found and 1) or 0
1176 1177
1177 1178 def heads(ui, repo, *branchrevs, **opts):
1178 1179 """show current repository heads or show branch heads
1179 1180
1180 1181 With no arguments, show all repository head changesets.
1181 1182
1182 1183 If branch or revisions names are given this will show the heads of
1183 1184 the specified branches or the branches those revisions are tagged
1184 1185 with.
1185 1186
1186 1187 Repository "heads" are changesets that don't have child
1187 1188 changesets. They are where development generally takes place and
1188 1189 are the usual targets for update and merge operations.
1189 1190
1190 1191 Branch heads are changesets that have a given branch tag, but have
1191 1192 no child changesets with that tag. They are usually where
1192 1193 development on the given branch takes place.
1193 1194 """
1194 1195 if opts['rev']:
1195 1196 start = repo.lookup(opts['rev'])
1196 1197 else:
1197 1198 start = None
1198 1199 if not branchrevs:
1199 1200 # Assume we're looking repo-wide heads if no revs were specified.
1200 1201 heads = repo.heads(start)
1201 1202 else:
1202 1203 heads = []
1203 1204 visitedset = util.set()
1204 1205 for branchrev in branchrevs:
1205 1206 branch = repo.changectx(branchrev).branch()
1206 1207 if branch in visitedset:
1207 1208 continue
1208 1209 visitedset.add(branch)
1209 1210 bheads = repo.branchheads(branch, start)
1210 1211 if not bheads:
1211 1212 if branch != branchrev:
1212 1213 ui.warn(_("no changes on branch %s containing %s are "
1213 1214 "reachable from %s\n")
1214 1215 % (branch, branchrev, opts['rev']))
1215 1216 else:
1216 1217 ui.warn(_("no changes on branch %s are reachable from %s\n")
1217 1218 % (branch, opts['rev']))
1218 1219 heads.extend(bheads)
1219 1220 if not heads:
1220 1221 return 1
1221 1222 displayer = cmdutil.show_changeset(ui, repo, opts)
1222 1223 for n in heads:
1223 1224 displayer.show(changenode=n)
1224 1225
1225 1226 def help_(ui, name=None, with_version=False):
1226 1227 """show help for a command, extension, or list of commands
1227 1228
1228 1229 With no arguments, print a list of commands and short help.
1229 1230
1230 1231 Given a command name, print help for that command.
1231 1232
1232 1233 Given an extension name, print help for that extension, and the
1233 1234 commands it provides."""
1234 1235 option_lists = []
1235 1236
1236 1237 def addglobalopts(aliases):
1237 1238 if ui.verbose:
1238 1239 option_lists.append((_("global options:"), globalopts))
1239 1240 if name == 'shortlist':
1240 1241 option_lists.append((_('use "hg help" for the full list '
1241 1242 'of commands'), ()))
1242 1243 else:
1243 1244 if name == 'shortlist':
1244 1245 msg = _('use "hg help" for the full list of commands '
1245 1246 'or "hg -v" for details')
1246 1247 elif aliases:
1247 1248 msg = _('use "hg -v help%s" to show aliases and '
1248 1249 'global options') % (name and " " + name or "")
1249 1250 else:
1250 1251 msg = _('use "hg -v help %s" to show global options') % name
1251 1252 option_lists.append((msg, ()))
1252 1253
1253 1254 def helpcmd(name):
1254 1255 if with_version:
1255 1256 version_(ui)
1256 1257 ui.write('\n')
1257 1258 aliases, i = cmdutil.findcmd(ui, name, table)
1258 1259 # synopsis
1259 1260 ui.write("%s\n" % i[2])
1260 1261
1261 1262 # aliases
1262 1263 if not ui.quiet and len(aliases) > 1:
1263 1264 ui.write(_("\naliases: %s\n") % ', '.join(aliases[1:]))
1264 1265
1265 1266 # description
1266 1267 doc = i[0].__doc__
1267 1268 if not doc:
1268 1269 doc = _("(No help text available)")
1269 1270 if ui.quiet:
1270 1271 doc = doc.splitlines(0)[0]
1271 1272 ui.write("\n%s\n" % doc.rstrip())
1272 1273
1273 1274 if not ui.quiet:
1274 1275 # options
1275 1276 if i[1]:
1276 1277 option_lists.append((_("options:\n"), i[1]))
1277 1278
1278 1279 addglobalopts(False)
1279 1280
1280 1281 def helplist(header, select=None):
1281 1282 h = {}
1282 1283 cmds = {}
1283 1284 for c, e in table.items():
1284 1285 f = c.split("|", 1)[0]
1285 1286 if select and not select(f):
1286 1287 continue
1287 1288 if name == "shortlist" and not f.startswith("^"):
1288 1289 continue
1289 1290 f = f.lstrip("^")
1290 1291 if not ui.debugflag and f.startswith("debug"):
1291 1292 continue
1292 1293 doc = e[0].__doc__
1293 1294 if not doc:
1294 1295 doc = _("(No help text available)")
1295 1296 h[f] = doc.splitlines(0)[0].rstrip()
1296 1297 cmds[f] = c.lstrip("^")
1297 1298
1298 1299 if not h:
1299 1300 ui.status(_('no commands defined\n'))
1300 1301 return
1301 1302
1302 1303 ui.status(header)
1303 1304 fns = h.keys()
1304 1305 fns.sort()
1305 1306 m = max(map(len, fns))
1306 1307 for f in fns:
1307 1308 if ui.verbose:
1308 1309 commands = cmds[f].replace("|",", ")
1309 1310 ui.write(" %s:\n %s\n"%(commands, h[f]))
1310 1311 else:
1311 1312 ui.write(' %-*s %s\n' % (m, f, h[f]))
1312 1313
1313 1314 if not ui.quiet:
1314 1315 addglobalopts(True)
1315 1316
1316 1317 def helptopic(name):
1317 1318 v = None
1318 1319 for i in help.helptable:
1319 1320 l = i.split('|')
1320 1321 if name in l:
1321 1322 v = i
1322 1323 header = l[-1]
1323 1324 if not v:
1324 1325 raise cmdutil.UnknownCommand(name)
1325 1326
1326 1327 # description
1327 1328 doc = help.helptable[v]
1328 1329 if not doc:
1329 1330 doc = _("(No help text available)")
1330 1331 if callable(doc):
1331 1332 doc = doc()
1332 1333
1333 1334 ui.write("%s\n" % header)
1334 1335 ui.write("%s\n" % doc.rstrip())
1335 1336
1336 1337 def helpext(name):
1337 1338 try:
1338 1339 mod = extensions.find(name)
1339 1340 except KeyError:
1340 1341 raise cmdutil.UnknownCommand(name)
1341 1342
1342 1343 doc = (mod.__doc__ or _('No help text available')).splitlines(0)
1343 1344 ui.write(_('%s extension - %s\n') % (name.split('.')[-1], doc[0]))
1344 1345 for d in doc[1:]:
1345 1346 ui.write(d, '\n')
1346 1347
1347 1348 ui.status('\n')
1348 1349
1349 1350 try:
1350 1351 ct = mod.cmdtable
1351 1352 except AttributeError:
1352 1353 ct = {}
1353 1354
1354 1355 modcmds = dict.fromkeys([c.split('|', 1)[0] for c in ct])
1355 1356 helplist(_('list of commands:\n\n'), modcmds.has_key)
1356 1357
1357 1358 if name and name != 'shortlist':
1358 1359 i = None
1359 1360 for f in (helpcmd, helptopic, helpext):
1360 1361 try:
1361 1362 f(name)
1362 1363 i = None
1363 1364 break
1364 1365 except cmdutil.UnknownCommand, inst:
1365 1366 i = inst
1366 1367 if i:
1367 1368 raise i
1368 1369
1369 1370 else:
1370 1371 # program name
1371 1372 if ui.verbose or with_version:
1372 1373 version_(ui)
1373 1374 else:
1374 1375 ui.status(_("Mercurial Distributed SCM\n"))
1375 1376 ui.status('\n')
1376 1377
1377 1378 # list of commands
1378 1379 if name == "shortlist":
1379 1380 header = _('basic commands:\n\n')
1380 1381 else:
1381 1382 header = _('list of commands:\n\n')
1382 1383
1383 1384 helplist(header)
1384 1385
1385 1386 # list all option lists
1386 1387 opt_output = []
1387 1388 for title, options in option_lists:
1388 1389 opt_output.append(("\n%s" % title, None))
1389 1390 for shortopt, longopt, default, desc in options:
1390 1391 if "DEPRECATED" in desc and not ui.verbose: continue
1391 1392 opt_output.append(("%2s%s" % (shortopt and "-%s" % shortopt,
1392 1393 longopt and " --%s" % longopt),
1393 1394 "%s%s" % (desc,
1394 1395 default
1395 1396 and _(" (default: %s)") % default
1396 1397 or "")))
1397 1398
1398 1399 if opt_output:
1399 1400 opts_len = max([len(line[0]) for line in opt_output if line[1]] or [0])
1400 1401 for first, second in opt_output:
1401 1402 if second:
1402 1403 ui.write(" %-*s %s\n" % (opts_len, first, second))
1403 1404 else:
1404 1405 ui.write("%s\n" % first)
1405 1406
1406 1407 def identify(ui, repo, source=None,
1407 1408 rev=None, num=None, id=None, branch=None, tags=None):
1408 1409 """identify the working copy or specified revision
1409 1410
1410 1411 With no revision, print a summary of the current state of the repo.
1411 1412
1412 1413 With a path, do a lookup in another repository.
1413 1414
1414 1415 This summary identifies the repository state using one or two parent
1415 1416 hash identifiers, followed by a "+" if there are uncommitted changes
1416 1417 in the working directory, a list of tags for this revision and a branch
1417 1418 name for non-default branches.
1418 1419 """
1419 1420
1420 1421 if not repo and not source:
1421 1422 raise util.Abort(_("There is no Mercurial repository here "
1422 1423 "(.hg not found)"))
1423 1424
1424 1425 hexfunc = ui.debugflag and hex or short
1425 1426 default = not (num or id or branch or tags)
1426 1427 output = []
1427 1428
1428 1429 if source:
1429 1430 source, revs, checkout = hg.parseurl(ui.expandpath(source), [])
1430 1431 srepo = hg.repository(ui, source)
1431 1432 if not rev and revs:
1432 1433 rev = revs[0]
1433 1434 if not rev:
1434 1435 rev = "tip"
1435 1436 if num or branch or tags:
1436 1437 raise util.Abort(
1437 1438 "can't query remote revision number, branch, or tags")
1438 1439 output = [hexfunc(srepo.lookup(rev))]
1439 1440 elif not rev:
1440 1441 ctx = repo.workingctx()
1441 1442 parents = ctx.parents()
1442 1443 changed = False
1443 1444 if default or id or num:
1444 1445 changed = ctx.files() + ctx.deleted()
1445 1446 if default or id:
1446 1447 output = ["%s%s" % ('+'.join([hexfunc(p.node()) for p in parents]),
1447 1448 (changed) and "+" or "")]
1448 1449 if num:
1449 1450 output.append("%s%s" % ('+'.join([str(p.rev()) for p in parents]),
1450 1451 (changed) and "+" or ""))
1451 1452 else:
1452 1453 ctx = repo.changectx(rev)
1453 1454 if default or id:
1454 1455 output = [hexfunc(ctx.node())]
1455 1456 if num:
1456 1457 output.append(str(ctx.rev()))
1457 1458
1458 1459 if not source and default and not ui.quiet:
1459 1460 b = util.tolocal(ctx.branch())
1460 1461 if b != 'default':
1461 1462 output.append("(%s)" % b)
1462 1463
1463 1464 # multiple tags for a single parent separated by '/'
1464 1465 t = "/".join(ctx.tags())
1465 1466 if t:
1466 1467 output.append(t)
1467 1468
1468 1469 if branch:
1469 1470 output.append(util.tolocal(ctx.branch()))
1470 1471
1471 1472 if tags:
1472 1473 output.extend(ctx.tags())
1473 1474
1474 1475 ui.write("%s\n" % ' '.join(output))
1475 1476
1476 1477 def import_(ui, repo, patch1, *patches, **opts):
1477 1478 """import an ordered set of patches
1478 1479
1479 1480 Import a list of patches and commit them individually.
1480 1481
1481 1482 If there are outstanding changes in the working directory, import
1482 1483 will abort unless given the -f flag.
1483 1484
1484 1485 You can import a patch straight from a mail message. Even patches
1485 1486 as attachments work (body part must be type text/plain or
1486 1487 text/x-patch to be used). From and Subject headers of email
1487 1488 message are used as default committer and commit message. All
1488 1489 text/plain body parts before first diff are added to commit
1489 1490 message.
1490 1491
1491 1492 If the imported patch was generated by hg export, user and description
1492 1493 from patch override values from message headers and body. Values
1493 1494 given on command line with -m and -u override these.
1494 1495
1495 1496 If --exact is specified, import will set the working directory
1496 1497 to the parent of each patch before applying it, and will abort
1497 1498 if the resulting changeset has a different ID than the one
1498 1499 recorded in the patch. This may happen due to character set
1499 1500 problems or other deficiencies in the text patch format.
1500 1501
1501 1502 To read a patch from standard input, use patch name "-".
1502 1503 See 'hg help dates' for a list of formats valid for -d/--date.
1503 1504 """
1504 1505 patches = (patch1,) + patches
1505 1506
1506 1507 date = opts.get('date')
1507 1508 if date:
1508 1509 opts['date'] = util.parsedate(date)
1509 1510
1510 1511 if opts.get('exact') or not opts['force']:
1511 1512 cmdutil.bail_if_changed(repo)
1512 1513
1513 1514 d = opts["base"]
1514 1515 strip = opts["strip"]
1515 1516 wlock = lock = None
1516 1517 try:
1517 1518 wlock = repo.wlock()
1518 1519 lock = repo.lock()
1519 1520 for p in patches:
1520 1521 pf = os.path.join(d, p)
1521 1522
1522 1523 if pf == '-':
1523 1524 ui.status(_("applying patch from stdin\n"))
1524 1525 data = patch.extract(ui, sys.stdin)
1525 1526 else:
1526 1527 ui.status(_("applying %s\n") % p)
1527 1528 if os.path.exists(pf):
1528 1529 data = patch.extract(ui, file(pf, 'rb'))
1529 1530 else:
1530 1531 data = patch.extract(ui, urllib.urlopen(pf))
1531 1532 tmpname, message, user, date, branch, nodeid, p1, p2 = data
1532 1533
1533 1534 if tmpname is None:
1534 1535 raise util.Abort(_('no diffs found'))
1535 1536
1536 1537 try:
1537 1538 cmdline_message = cmdutil.logmessage(opts)
1538 1539 if cmdline_message:
1539 1540 # pickup the cmdline msg
1540 1541 message = cmdline_message
1541 1542 elif message:
1542 1543 # pickup the patch msg
1543 1544 message = message.strip()
1544 1545 else:
1545 1546 # launch the editor
1546 1547 message = None
1547 1548 ui.debug(_('message:\n%s\n') % message)
1548 1549
1549 1550 wp = repo.workingctx().parents()
1550 1551 if opts.get('exact'):
1551 1552 if not nodeid or not p1:
1552 1553 raise util.Abort(_('not a mercurial patch'))
1553 1554 p1 = repo.lookup(p1)
1554 1555 p2 = repo.lookup(p2 or hex(nullid))
1555 1556
1556 1557 if p1 != wp[0].node():
1557 1558 hg.clean(repo, p1)
1558 1559 repo.dirstate.setparents(p1, p2)
1559 1560 elif p2:
1560 1561 try:
1561 1562 p1 = repo.lookup(p1)
1562 1563 p2 = repo.lookup(p2)
1563 1564 if p1 == wp[0].node():
1564 1565 repo.dirstate.setparents(p1, p2)
1565 1566 except RepoError:
1566 1567 pass
1567 1568 if opts.get('exact') or opts.get('import_branch'):
1568 1569 repo.dirstate.setbranch(branch or 'default')
1569 1570
1570 1571 files = {}
1571 1572 try:
1572 1573 fuzz = patch.patch(tmpname, ui, strip=strip, cwd=repo.root,
1573 1574 files=files)
1574 1575 finally:
1575 1576 files = patch.updatedir(ui, repo, files)
1576 1577 if not opts.get('no_commit'):
1577 1578 n = repo.commit(files, message, opts.get('user') or user,
1578 1579 opts.get('date') or date)
1579 1580 if opts.get('exact'):
1580 1581 if hex(n) != nodeid:
1581 1582 repo.rollback()
1582 1583 raise util.Abort(_('patch is damaged'
1583 1584 ' or loses information'))
1584 1585 # Force a dirstate write so that the next transaction
1585 1586 # backups an up-do-date file.
1586 1587 repo.dirstate.write()
1587 1588 finally:
1588 1589 os.unlink(tmpname)
1589 1590 finally:
1590 1591 del lock, wlock
1591 1592
1592 1593 def incoming(ui, repo, source="default", **opts):
1593 1594 """show new changesets found in source
1594 1595
1595 1596 Show new changesets found in the specified path/URL or the default
1596 1597 pull location. These are the changesets that would be pulled if a pull
1597 1598 was requested.
1598 1599
1599 1600 For remote repository, using --bundle avoids downloading the changesets
1600 1601 twice if the incoming is followed by a pull.
1601 1602
1602 1603 See pull for valid source format details.
1603 1604 """
1604 1605 limit = cmdutil.loglimit(opts)
1605 1606 source, revs, checkout = hg.parseurl(ui.expandpath(source), opts['rev'])
1606 1607 cmdutil.setremoteconfig(ui, opts)
1607 1608
1608 1609 other = hg.repository(ui, source)
1609 1610 ui.status(_('comparing with %s\n') % util.hidepassword(source))
1610 1611 if revs:
1611 1612 revs = [other.lookup(rev) for rev in revs]
1612 1613 incoming = repo.findincoming(other, heads=revs, force=opts["force"])
1613 1614 if not incoming:
1614 1615 try:
1615 1616 os.unlink(opts["bundle"])
1616 1617 except:
1617 1618 pass
1618 1619 ui.status(_("no changes found\n"))
1619 1620 return 1
1620 1621
1621 1622 cleanup = None
1622 1623 try:
1623 1624 fname = opts["bundle"]
1624 1625 if fname or not other.local():
1625 1626 # create a bundle (uncompressed if other repo is not local)
1626 1627 if revs is None:
1627 1628 cg = other.changegroup(incoming, "incoming")
1628 1629 else:
1629 1630 cg = other.changegroupsubset(incoming, revs, 'incoming')
1630 1631 bundletype = other.local() and "HG10BZ" or "HG10UN"
1631 1632 fname = cleanup = changegroup.writebundle(cg, fname, bundletype)
1632 1633 # keep written bundle?
1633 1634 if opts["bundle"]:
1634 1635 cleanup = None
1635 1636 if not other.local():
1636 1637 # use the created uncompressed bundlerepo
1637 1638 other = bundlerepo.bundlerepository(ui, repo.root, fname)
1638 1639
1639 1640 o = other.changelog.nodesbetween(incoming, revs)[0]
1640 1641 if opts['newest_first']:
1641 1642 o.reverse()
1642 1643 displayer = cmdutil.show_changeset(ui, other, opts)
1643 1644 count = 0
1644 1645 for n in o:
1645 1646 if count >= limit:
1646 1647 break
1647 1648 parents = [p for p in other.changelog.parents(n) if p != nullid]
1648 1649 if opts['no_merges'] and len(parents) == 2:
1649 1650 continue
1650 1651 count += 1
1651 1652 displayer.show(changenode=n)
1652 1653 finally:
1653 1654 if hasattr(other, 'close'):
1654 1655 other.close()
1655 1656 if cleanup:
1656 1657 os.unlink(cleanup)
1657 1658
1658 1659 def init(ui, dest=".", **opts):
1659 1660 """create a new repository in the given directory
1660 1661
1661 1662 Initialize a new repository in the given directory. If the given
1662 1663 directory does not exist, it is created.
1663 1664
1664 1665 If no directory is given, the current directory is used.
1665 1666
1666 1667 It is possible to specify an ssh:// URL as the destination.
1667 1668 Look at the help text for the pull command for important details
1668 1669 about ssh:// URLs.
1669 1670 """
1670 1671 cmdutil.setremoteconfig(ui, opts)
1671 1672 hg.repository(ui, dest, create=1)
1672 1673
1673 1674 def locate(ui, repo, *pats, **opts):
1674 1675 """locate files matching specific patterns
1675 1676
1676 1677 Print all files under Mercurial control whose names match the
1677 1678 given patterns.
1678 1679
1679 1680 This command searches the entire repository by default. To search
1680 1681 just the current directory and its subdirectories, use
1681 1682 "--include .".
1682 1683
1683 1684 If no patterns are given to match, this command prints all file
1684 1685 names.
1685 1686
1686 1687 If you want to feed the output of this command into the "xargs"
1687 1688 command, use the "-0" option to both this command and "xargs".
1688 1689 This will avoid the problem of "xargs" treating single filenames
1689 1690 that contain white space as multiple filenames.
1690 1691 """
1691 1692 end = opts['print0'] and '\0' or '\n'
1692 1693 rev = opts['rev']
1693 1694 if rev:
1694 1695 node = repo.lookup(rev)
1695 1696 else:
1696 1697 node = None
1697 1698
1698 1699 ret = 1
1699 1700 m = cmdutil.match(repo, pats, opts, default='relglob')
1700 1701 m.bad = lambda x,y: False
1701 for src, abs, rel, exact in cmdutil.walk(repo, m, node):
1702 for src, abs in cmdutil.walk(repo, m, node):
1702 1703 if not node and abs not in repo.dirstate:
1703 1704 continue
1704 1705 if opts['fullpath']:
1705 1706 ui.write(os.path.join(repo.root, abs), end)
1706 1707 else:
1707 ui.write(((pats and rel) or abs), end)
1708 ui.write(((pats and m.rel(abs)) or abs), end)
1708 1709 ret = 0
1709 1710
1710 1711 return ret
1711 1712
1712 1713 def log(ui, repo, *pats, **opts):
1713 1714 """show revision history of entire repository or files
1714 1715
1715 1716 Print the revision history of the specified files or the entire
1716 1717 project.
1717 1718
1718 1719 File history is shown without following rename or copy history of
1719 1720 files. Use -f/--follow with a file name to follow history across
1720 1721 renames and copies. --follow without a file name will only show
1721 1722 ancestors or descendants of the starting revision. --follow-first
1722 1723 only follows the first parent of merge revisions.
1723 1724
1724 1725 If no revision range is specified, the default is tip:0 unless
1725 1726 --follow is set, in which case the working directory parent is
1726 1727 used as the starting revision.
1727 1728
1728 1729 See 'hg help dates' for a list of formats valid for -d/--date.
1729 1730
1730 1731 By default this command outputs: changeset id and hash, tags,
1731 1732 non-trivial parents, user, date and time, and a summary for each
1732 1733 commit. When the -v/--verbose switch is used, the list of changed
1733 1734 files and full commit message is shown.
1734 1735
1735 1736 NOTE: log -p may generate unexpected diff output for merge
1736 1737 changesets, as it will compare the merge changeset against its
1737 1738 first parent only. Also, the files: list will only reflect files
1738 1739 that are different from BOTH parents.
1739 1740
1740 1741 """
1741 1742
1742 1743 get = util.cachefunc(lambda r: repo.changectx(r).changeset())
1743 1744 changeiter, matchfn = cmdutil.walkchangerevs(ui, repo, pats, get, opts)
1744 1745
1745 1746 limit = cmdutil.loglimit(opts)
1746 1747 count = 0
1747 1748
1748 1749 if opts['copies'] and opts['rev']:
1749 1750 endrev = max(cmdutil.revrange(repo, opts['rev'])) + 1
1750 1751 else:
1751 1752 endrev = repo.changelog.count()
1752 1753 rcache = {}
1753 1754 ncache = {}
1754 1755 def getrenamed(fn, rev):
1755 1756 '''looks up all renames for a file (up to endrev) the first
1756 1757 time the file is given. It indexes on the changerev and only
1757 1758 parses the manifest if linkrev != changerev.
1758 1759 Returns rename info for fn at changerev rev.'''
1759 1760 if fn not in rcache:
1760 1761 rcache[fn] = {}
1761 1762 ncache[fn] = {}
1762 1763 fl = repo.file(fn)
1763 1764 for i in xrange(fl.count()):
1764 1765 node = fl.node(i)
1765 1766 lr = fl.linkrev(node)
1766 1767 renamed = fl.renamed(node)
1767 1768 rcache[fn][lr] = renamed
1768 1769 if renamed:
1769 1770 ncache[fn][node] = renamed
1770 1771 if lr >= endrev:
1771 1772 break
1772 1773 if rev in rcache[fn]:
1773 1774 return rcache[fn][rev]
1774 1775
1775 1776 # If linkrev != rev (i.e. rev not found in rcache) fallback to
1776 1777 # filectx logic.
1777 1778
1778 1779 try:
1779 1780 return repo.changectx(rev).filectx(fn).renamed()
1780 1781 except revlog.LookupError:
1781 1782 pass
1782 1783 return None
1783 1784
1784 1785 df = False
1785 1786 if opts["date"]:
1786 1787 df = util.matchdate(opts["date"])
1787 1788
1788 1789 only_branches = opts['only_branch']
1789 1790
1790 1791 displayer = cmdutil.show_changeset(ui, repo, opts, True, matchfn)
1791 1792 for st, rev, fns in changeiter:
1792 1793 if st == 'add':
1793 1794 changenode = repo.changelog.node(rev)
1794 1795 parents = [p for p in repo.changelog.parentrevs(rev)
1795 1796 if p != nullrev]
1796 1797 if opts['no_merges'] and len(parents) == 2:
1797 1798 continue
1798 1799 if opts['only_merges'] and len(parents) != 2:
1799 1800 continue
1800 1801
1801 1802 if only_branches:
1802 1803 revbranch = get(rev)[5]['branch']
1803 1804 if revbranch not in only_branches:
1804 1805 continue
1805 1806
1806 1807 if df:
1807 1808 changes = get(rev)
1808 1809 if not df(changes[2][0]):
1809 1810 continue
1810 1811
1811 1812 if opts['keyword']:
1812 1813 changes = get(rev)
1813 1814 miss = 0
1814 1815 for k in [kw.lower() for kw in opts['keyword']]:
1815 1816 if not (k in changes[1].lower() or
1816 1817 k in changes[4].lower() or
1817 1818 k in " ".join(changes[3]).lower()):
1818 1819 miss = 1
1819 1820 break
1820 1821 if miss:
1821 1822 continue
1822 1823
1823 1824 copies = []
1824 1825 if opts.get('copies') and rev:
1825 1826 for fn in get(rev)[3]:
1826 1827 rename = getrenamed(fn, rev)
1827 1828 if rename:
1828 1829 copies.append((fn, rename[0]))
1829 1830 displayer.show(rev, changenode, copies=copies)
1830 1831 elif st == 'iter':
1831 1832 if count == limit: break
1832 1833 if displayer.flush(rev):
1833 1834 count += 1
1834 1835
1835 1836 def manifest(ui, repo, node=None, rev=None):
1836 1837 """output the current or given revision of the project manifest
1837 1838
1838 1839 Print a list of version controlled files for the given revision.
1839 1840 If no revision is given, the parent of the working directory is used,
1840 1841 or tip if no revision is checked out.
1841 1842
1842 1843 The manifest is the list of files being version controlled. If no revision
1843 1844 is given then the first parent of the working directory is used.
1844 1845
1845 1846 With -v flag, print file permissions, symlink and executable bits. With
1846 1847 --debug flag, print file revision hashes.
1847 1848 """
1848 1849
1849 1850 if rev and node:
1850 1851 raise util.Abort(_("please specify just one revision"))
1851 1852
1852 1853 if not node:
1853 1854 node = rev
1854 1855
1855 1856 m = repo.changectx(node).manifest()
1856 1857 files = m.keys()
1857 1858 files.sort()
1858 1859
1859 1860 for f in files:
1860 1861 if ui.debugflag:
1861 1862 ui.write("%40s " % hex(m[f]))
1862 1863 if ui.verbose:
1863 1864 type = m.execf(f) and "*" or m.linkf(f) and "@" or " "
1864 1865 perm = m.execf(f) and "755" or "644"
1865 1866 ui.write("%3s %1s " % (perm, type))
1866 1867 ui.write("%s\n" % f)
1867 1868
1868 1869 def merge(ui, repo, node=None, force=None, rev=None):
1869 1870 """merge working directory with another revision
1870 1871
1871 1872 Merge the contents of the current working directory and the
1872 1873 requested revision. Files that changed between either parent are
1873 1874 marked as changed for the next commit and a commit must be
1874 1875 performed before any further updates are allowed.
1875 1876
1876 1877 If no revision is specified, the working directory's parent is a
1877 1878 head revision, and the repository contains exactly one other head,
1878 1879 the other head is merged with by default. Otherwise, an explicit
1879 1880 revision to merge with must be provided.
1880 1881 """
1881 1882
1882 1883 if rev and node:
1883 1884 raise util.Abort(_("please specify just one revision"))
1884 1885 if not node:
1885 1886 node = rev
1886 1887
1887 1888 if not node:
1888 1889 heads = repo.heads()
1889 1890 if len(heads) > 2:
1890 1891 raise util.Abort(_('repo has %d heads - '
1891 1892 'please merge with an explicit rev') %
1892 1893 len(heads))
1893 1894 parent = repo.dirstate.parents()[0]
1894 1895 if len(heads) == 1:
1895 1896 msg = _('there is nothing to merge')
1896 1897 if parent != repo.lookup(repo.workingctx().branch()):
1897 1898 msg = _('%s - use "hg update" instead') % msg
1898 1899 raise util.Abort(msg)
1899 1900
1900 1901 if parent not in heads:
1901 1902 raise util.Abort(_('working dir not at a head rev - '
1902 1903 'use "hg update" or merge with an explicit rev'))
1903 1904 node = parent == heads[0] and heads[-1] or heads[0]
1904 1905 return hg.merge(repo, node, force=force)
1905 1906
1906 1907 def outgoing(ui, repo, dest=None, **opts):
1907 1908 """show changesets not found in destination
1908 1909
1909 1910 Show changesets not found in the specified destination repository or
1910 1911 the default push location. These are the changesets that would be pushed
1911 1912 if a push was requested.
1912 1913
1913 1914 See pull for valid destination format details.
1914 1915 """
1915 1916 limit = cmdutil.loglimit(opts)
1916 1917 dest, revs, checkout = hg.parseurl(
1917 1918 ui.expandpath(dest or 'default-push', dest or 'default'), opts['rev'])
1918 1919 cmdutil.setremoteconfig(ui, opts)
1919 1920 if revs:
1920 1921 revs = [repo.lookup(rev) for rev in revs]
1921 1922
1922 1923 other = hg.repository(ui, dest)
1923 1924 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
1924 1925 o = repo.findoutgoing(other, force=opts['force'])
1925 1926 if not o:
1926 1927 ui.status(_("no changes found\n"))
1927 1928 return 1
1928 1929 o = repo.changelog.nodesbetween(o, revs)[0]
1929 1930 if opts['newest_first']:
1930 1931 o.reverse()
1931 1932 displayer = cmdutil.show_changeset(ui, repo, opts)
1932 1933 count = 0
1933 1934 for n in o:
1934 1935 if count >= limit:
1935 1936 break
1936 1937 parents = [p for p in repo.changelog.parents(n) if p != nullid]
1937 1938 if opts['no_merges'] and len(parents) == 2:
1938 1939 continue
1939 1940 count += 1
1940 1941 displayer.show(changenode=n)
1941 1942
1942 1943 def parents(ui, repo, file_=None, **opts):
1943 1944 """show the parents of the working dir or revision
1944 1945
1945 1946 Print the working directory's parent revisions. If a
1946 1947 revision is given via --rev, the parent of that revision
1947 1948 will be printed. If a file argument is given, revision in
1948 1949 which the file was last changed (before the working directory
1949 1950 revision or the argument to --rev if given) is printed.
1950 1951 """
1951 1952 rev = opts.get('rev')
1952 1953 if rev:
1953 1954 ctx = repo.changectx(rev)
1954 1955 else:
1955 1956 ctx = repo.workingctx()
1956 1957
1957 1958 if file_:
1958 1959 m = cmdutil.match(repo, (file_,), opts)
1959 1960 if m.anypats() or len(m.files()) != 1:
1960 1961 raise util.Abort(_('can only specify an explicit file name'))
1961 1962 file_ = m.files()[0]
1962 1963 filenodes = []
1963 1964 for cp in ctx.parents():
1964 1965 if not cp:
1965 1966 continue
1966 1967 try:
1967 1968 filenodes.append(cp.filenode(file_))
1968 1969 except revlog.LookupError:
1969 1970 pass
1970 1971 if not filenodes:
1971 1972 raise util.Abort(_("'%s' not found in manifest!") % file_)
1972 1973 fl = repo.file(file_)
1973 1974 p = [repo.lookup(fl.linkrev(fn)) for fn in filenodes]
1974 1975 else:
1975 1976 p = [cp.node() for cp in ctx.parents()]
1976 1977
1977 1978 displayer = cmdutil.show_changeset(ui, repo, opts)
1978 1979 for n in p:
1979 1980 if n != nullid:
1980 1981 displayer.show(changenode=n)
1981 1982
1982 1983 def paths(ui, repo, search=None):
1983 1984 """show definition of symbolic path names
1984 1985
1985 1986 Show definition of symbolic path name NAME. If no name is given, show
1986 1987 definition of available names.
1987 1988
1988 1989 Path names are defined in the [paths] section of /etc/mercurial/hgrc
1989 1990 and $HOME/.hgrc. If run inside a repository, .hg/hgrc is used, too.
1990 1991 """
1991 1992 if search:
1992 1993 for name, path in ui.configitems("paths"):
1993 1994 if name == search:
1994 1995 ui.write("%s\n" % util.hidepassword(path))
1995 1996 return
1996 1997 ui.warn(_("not found!\n"))
1997 1998 return 1
1998 1999 else:
1999 2000 for name, path in ui.configitems("paths"):
2000 2001 ui.write("%s = %s\n" % (name, util.hidepassword(path)))
2001 2002
2002 2003 def postincoming(ui, repo, modheads, optupdate, checkout):
2003 2004 if modheads == 0:
2004 2005 return
2005 2006 if optupdate:
2006 2007 if modheads <= 1 or checkout:
2007 2008 return hg.update(repo, checkout)
2008 2009 else:
2009 2010 ui.status(_("not updating, since new heads added\n"))
2010 2011 if modheads > 1:
2011 2012 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
2012 2013 else:
2013 2014 ui.status(_("(run 'hg update' to get a working copy)\n"))
2014 2015
2015 2016 def pull(ui, repo, source="default", **opts):
2016 2017 """pull changes from the specified source
2017 2018
2018 2019 Pull changes from a remote repository to a local one.
2019 2020
2020 2021 This finds all changes from the repository at the specified path
2021 2022 or URL and adds them to the local repository. By default, this
2022 2023 does not update the copy of the project in the working directory.
2023 2024
2024 2025 Valid URLs are of the form:
2025 2026
2026 2027 local/filesystem/path (or file://local/filesystem/path)
2027 2028 http://[user@]host[:port]/[path]
2028 2029 https://[user@]host[:port]/[path]
2029 2030 ssh://[user@]host[:port]/[path]
2030 2031 static-http://host[:port]/[path]
2031 2032
2032 2033 Paths in the local filesystem can either point to Mercurial
2033 2034 repositories or to bundle files (as created by 'hg bundle' or
2034 2035 'hg incoming --bundle'). The static-http:// protocol, albeit slow,
2035 2036 allows access to a Mercurial repository where you simply use a web
2036 2037 server to publish the .hg directory as static content.
2037 2038
2038 2039 An optional identifier after # indicates a particular branch, tag,
2039 2040 or changeset to pull.
2040 2041
2041 2042 Some notes about using SSH with Mercurial:
2042 2043 - SSH requires an accessible shell account on the destination machine
2043 2044 and a copy of hg in the remote path or specified with as remotecmd.
2044 2045 - path is relative to the remote user's home directory by default.
2045 2046 Use an extra slash at the start of a path to specify an absolute path:
2046 2047 ssh://example.com//tmp/repository
2047 2048 - Mercurial doesn't use its own compression via SSH; the right thing
2048 2049 to do is to configure it in your ~/.ssh/config, e.g.:
2049 2050 Host *.mylocalnetwork.example.com
2050 2051 Compression no
2051 2052 Host *
2052 2053 Compression yes
2053 2054 Alternatively specify "ssh -C" as your ssh command in your hgrc or
2054 2055 with the --ssh command line option.
2055 2056 """
2056 2057 source, revs, checkout = hg.parseurl(ui.expandpath(source), opts['rev'])
2057 2058 cmdutil.setremoteconfig(ui, opts)
2058 2059
2059 2060 other = hg.repository(ui, source)
2060 2061 ui.status(_('pulling from %s\n') % util.hidepassword(source))
2061 2062 if revs:
2062 2063 try:
2063 2064 revs = [other.lookup(rev) for rev in revs]
2064 2065 except NoCapability:
2065 2066 error = _("Other repository doesn't support revision lookup, "
2066 2067 "so a rev cannot be specified.")
2067 2068 raise util.Abort(error)
2068 2069
2069 2070 modheads = repo.pull(other, heads=revs, force=opts['force'])
2070 2071 return postincoming(ui, repo, modheads, opts['update'], checkout)
2071 2072
2072 2073 def push(ui, repo, dest=None, **opts):
2073 2074 """push changes to the specified destination
2074 2075
2075 2076 Push changes from the local repository to the given destination.
2076 2077
2077 2078 This is the symmetrical operation for pull. It helps to move
2078 2079 changes from the current repository to a different one. If the
2079 2080 destination is local this is identical to a pull in that directory
2080 2081 from the current one.
2081 2082
2082 2083 By default, push will refuse to run if it detects the result would
2083 2084 increase the number of remote heads. This generally indicates the
2084 2085 the client has forgotten to sync and merge before pushing.
2085 2086
2086 2087 Valid URLs are of the form:
2087 2088
2088 2089 local/filesystem/path (or file://local/filesystem/path)
2089 2090 ssh://[user@]host[:port]/[path]
2090 2091 http://[user@]host[:port]/[path]
2091 2092 https://[user@]host[:port]/[path]
2092 2093
2093 2094 An optional identifier after # indicates a particular branch, tag,
2094 2095 or changeset to push.
2095 2096
2096 2097 Look at the help text for the pull command for important details
2097 2098 about ssh:// URLs.
2098 2099
2099 2100 Pushing to http:// and https:// URLs is only possible, if this
2100 2101 feature is explicitly enabled on the remote Mercurial server.
2101 2102 """
2102 2103 dest, revs, checkout = hg.parseurl(
2103 2104 ui.expandpath(dest or 'default-push', dest or 'default'), opts['rev'])
2104 2105 cmdutil.setremoteconfig(ui, opts)
2105 2106
2106 2107 other = hg.repository(ui, dest)
2107 2108 ui.status('pushing to %s\n' % util.hidepassword(dest))
2108 2109 if revs:
2109 2110 revs = [repo.lookup(rev) for rev in revs]
2110 2111 r = repo.push(other, opts['force'], revs=revs)
2111 2112 return r == 0
2112 2113
2113 2114 def rawcommit(ui, repo, *pats, **opts):
2114 2115 """raw commit interface (DEPRECATED)
2115 2116
2116 2117 (DEPRECATED)
2117 2118 Lowlevel commit, for use in helper scripts.
2118 2119
2119 2120 This command is not intended to be used by normal users, as it is
2120 2121 primarily useful for importing from other SCMs.
2121 2122
2122 2123 This command is now deprecated and will be removed in a future
2123 2124 release, please use debugsetparents and commit instead.
2124 2125 """
2125 2126
2126 2127 ui.warn(_("(the rawcommit command is deprecated)\n"))
2127 2128
2128 2129 message = cmdutil.logmessage(opts)
2129 2130
2130 2131 files = cmdutil.match(repo, pats, opts).files()
2131 2132 if opts['files']:
2132 2133 files += open(opts['files']).read().splitlines()
2133 2134
2134 2135 parents = [repo.lookup(p) for p in opts['parent']]
2135 2136
2136 2137 try:
2137 2138 repo.rawcommit(files, message, opts['user'], opts['date'], *parents)
2138 2139 except ValueError, inst:
2139 2140 raise util.Abort(str(inst))
2140 2141
2141 2142 def recover(ui, repo):
2142 2143 """roll back an interrupted transaction
2143 2144
2144 2145 Recover from an interrupted commit or pull.
2145 2146
2146 2147 This command tries to fix the repository status after an interrupted
2147 2148 operation. It should only be necessary when Mercurial suggests it.
2148 2149 """
2149 2150 if repo.recover():
2150 2151 return hg.verify(repo)
2151 2152 return 1
2152 2153
2153 2154 def remove(ui, repo, *pats, **opts):
2154 2155 """remove the specified files on the next commit
2155 2156
2156 2157 Schedule the indicated files for removal from the repository.
2157 2158
2158 2159 This only removes files from the current branch, not from the entire
2159 2160 project history. -A can be used to remove only files that have already
2160 2161 been deleted, -f can be used to force deletion, and -Af can be used
2161 2162 to remove files from the next revision without deleting them.
2162 2163
2163 2164 The following table details the behavior of remove for different file
2164 2165 states (columns) and option combinations (rows). The file states are
2165 2166 Added, Clean, Modified and Missing (as reported by hg status). The
2166 2167 actions are Warn, Remove (from branch) and Delete (from disk).
2167 2168
2168 2169 A C M !
2169 2170 none W RD W R
2170 2171 -f R RD RD R
2171 2172 -A W W W R
2172 2173 -Af R R R R
2173 2174
2174 2175 This command schedules the files to be removed at the next commit.
2175 2176 To undo a remove before that, see hg revert.
2176 2177 """
2177 2178
2178 2179 after, force = opts.get('after'), opts.get('force')
2179 2180 if not pats and not after:
2180 2181 raise util.Abort(_('no files specified'))
2181 2182
2182 2183 m = cmdutil.match(repo, pats, opts)
2183 2184 mardu = map(dict.fromkeys, repo.status(files=m.files(), match=m))[:5]
2184 2185 modified, added, removed, deleted, unknown = mardu
2185 2186
2186 2187 remove, forget = [], []
2187 for src, abs, rel, exact in cmdutil.walk(repo, m):
2188 for src, abs in cmdutil.walk(repo, m):
2188 2189
2189 2190 reason = None
2190 2191 if abs in removed or abs in unknown:
2191 2192 continue
2192 2193
2193 2194 # last column
2194 2195 elif abs in deleted:
2195 2196 remove.append(abs)
2196 2197
2197 2198 # rest of the third row
2198 2199 elif after and not force:
2199 2200 reason = _('still exists (use -f to force removal)')
2200 2201
2201 2202 # rest of the first column
2202 2203 elif abs in added:
2203 2204 if not force:
2204 2205 reason = _('has been marked for add (use -f to force removal)')
2205 2206 else:
2206 2207 forget.append(abs)
2207 2208
2208 2209 # rest of the third column
2209 2210 elif abs in modified:
2210 2211 if not force:
2211 2212 reason = _('is modified (use -f to force removal)')
2212 2213 else:
2213 2214 remove.append(abs)
2214 2215
2215 2216 # rest of the second column
2216 2217 elif not reason:
2217 2218 remove.append(abs)
2218 2219
2219 2220 if reason:
2220 ui.warn(_('not removing %s: file %s\n') % (rel, reason))
2221 elif ui.verbose or not exact:
2222 ui.status(_('removing %s\n') % rel)
2221 ui.warn(_('not removing %s: file %s\n') % (m.rel(abs), reason))
2222 elif ui.verbose or not m.exact(abs):
2223 ui.status(_('removing %s\n') % m.rel(abs))
2223 2224
2224 2225 repo.forget(forget)
2225 2226 repo.remove(remove, unlink=not after)
2226 2227
2227 2228 def rename(ui, repo, *pats, **opts):
2228 2229 """rename files; equivalent of copy + remove
2229 2230
2230 2231 Mark dest as copies of sources; mark sources for deletion. If
2231 2232 dest is a directory, copies are put in that directory. If dest is
2232 2233 a file, there can only be one source.
2233 2234
2234 2235 By default, this command copies the contents of files as they
2235 2236 stand in the working directory. If invoked with --after, the
2236 2237 operation is recorded, but no copying is performed.
2237 2238
2238 2239 This command takes effect in the next commit. To undo a rename
2239 2240 before that, see hg revert.
2240 2241 """
2241 2242 wlock = repo.wlock(False)
2242 2243 try:
2243 2244 return cmdutil.copy(ui, repo, pats, opts, rename=True)
2244 2245 finally:
2245 2246 del wlock
2246 2247
2247 2248 def resolve(ui, repo, *pats, **opts):
2248 2249 """resolve file merges from a branch merge or update
2249 2250
2250 2251 This command will attempt to resolve unresolved merges from the
2251 2252 last update or merge command. This will use the local file
2252 2253 revision preserved at the last update or merge to cleanly retry
2253 2254 the file merge attempt. With no file or options specified, this
2254 2255 command will attempt to resolve all unresolved files.
2255 2256 """
2256 2257
2257 2258 if len([x for x in opts if opts[x]]) > 1:
2258 2259 raise util.Abort(_("too many options specified"))
2259 2260
2260 2261 ms = merge_.mergestate(repo)
2261 2262 mf = util.matcher(repo.root, "", pats, [], [])[1]
2262 2263
2263 2264 for f in ms:
2264 2265 if mf(f):
2265 2266 if opts.get("list"):
2266 2267 ui.write("%s %s\n" % (ms[f].upper(), f))
2267 2268 elif opts.get("mark"):
2268 2269 ms.mark(f, "r")
2269 2270 elif opts.get("unmark"):
2270 2271 ms.mark(f, "u")
2271 2272 else:
2272 2273 wctx = repo.workingctx()
2273 2274 mctx = wctx.parents()[-1]
2274 2275 ms.resolve(f, wctx, mctx)
2275 2276
2276 2277 def revert(ui, repo, *pats, **opts):
2277 2278 """restore individual files or dirs to an earlier state
2278 2279
2279 2280 (use update -r to check out earlier revisions, revert does not
2280 2281 change the working dir parents)
2281 2282
2282 2283 With no revision specified, revert the named files or directories
2283 2284 to the contents they had in the parent of the working directory.
2284 2285 This restores the contents of the affected files to an unmodified
2285 2286 state and unschedules adds, removes, copies, and renames. If the
2286 2287 working directory has two parents, you must explicitly specify the
2287 2288 revision to revert to.
2288 2289
2289 2290 Using the -r option, revert the given files or directories to their
2290 2291 contents as of a specific revision. This can be helpful to "roll
2291 2292 back" some or all of an earlier change.
2292 2293 See 'hg help dates' for a list of formats valid for -d/--date.
2293 2294
2294 2295 Revert modifies the working directory. It does not commit any
2295 2296 changes, or change the parent of the working directory. If you
2296 2297 revert to a revision other than the parent of the working
2297 2298 directory, the reverted files will thus appear modified
2298 2299 afterwards.
2299 2300
2300 2301 If a file has been deleted, it is restored. If the executable
2301 2302 mode of a file was changed, it is reset.
2302 2303
2303 2304 If names are given, all files matching the names are reverted.
2304 2305 If no arguments are given, no files are reverted.
2305 2306
2306 2307 Modified files are saved with a .orig suffix before reverting.
2307 2308 To disable these backups, use --no-backup.
2308 2309 """
2309 2310
2310 2311 if opts["date"]:
2311 2312 if opts["rev"]:
2312 2313 raise util.Abort(_("you can't specify a revision and a date"))
2313 2314 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
2314 2315
2315 2316 if not pats and not opts['all']:
2316 2317 raise util.Abort(_('no files or directories specified; '
2317 2318 'use --all to revert the whole repo'))
2318 2319
2319 2320 parent, p2 = repo.dirstate.parents()
2320 2321 if not opts['rev'] and p2 != nullid:
2321 2322 raise util.Abort(_('uncommitted merge - please provide a '
2322 2323 'specific revision'))
2323 2324 ctx = repo.changectx(opts['rev'])
2324 2325 node = ctx.node()
2325 2326 mf = ctx.manifest()
2326 2327 if node == parent:
2327 2328 pmf = mf
2328 2329 else:
2329 2330 pmf = None
2330 2331
2331 2332 # need all matching names in dirstate and manifest of target rev,
2332 2333 # so have to walk both. do not print errors if files exist in one
2333 2334 # but not other.
2334 2335
2335 2336 names = {}
2336 2337
2337 2338 wlock = repo.wlock()
2338 2339 try:
2339 2340 # walk dirstate.
2340 2341 files = []
2341 2342
2342 2343 m = cmdutil.match(repo, pats, opts)
2343 2344 m.bad = lambda x,y: False
2344 for src, abs, rel, exact in cmdutil.walk(repo, m):
2345 names[abs] = (rel, exact)
2345 for src, abs in cmdutil.walk(repo, m):
2346 names[abs] = m.rel(abs), m.exact(abs)
2346 2347
2347 2348 # walk target manifest.
2348 2349
2349 2350 def badfn(path, msg):
2350 2351 if path in names:
2351 2352 return False
2352 2353 path_ = path + '/'
2353 2354 for f in names:
2354 2355 if f.startswith(path_):
2355 2356 return False
2356 2357 repo.ui.warn("%s: %s\n" % (m.rel(path), msg))
2357 2358 return False
2358 2359
2359 2360 m = cmdutil.match(repo, pats, opts)
2360 2361 m.bad = badfn
2361 for src, abs, rel, exact in cmdutil.walk(repo, m, node=node):
2362 if abs in names:
2363 continue
2364 names[abs] = (rel, exact)
2362 for src, abs in cmdutil.walk(repo, m, node=node):
2363 if abs not in names:
2364 names[abs] = m.rel(abs), m.exact(abs)
2365 2365
2366 2366 changes = repo.status(files=files, match=names.has_key)[:4]
2367 2367 modified, added, removed, deleted = map(dict.fromkeys, changes)
2368 2368
2369 2369 # if f is a rename, also revert the source
2370 2370 cwd = repo.getcwd()
2371 2371 for f in added:
2372 2372 src = repo.dirstate.copied(f)
2373 2373 if src and src not in names and repo.dirstate[src] == 'r':
2374 2374 removed[src] = None
2375 2375 names[src] = (repo.pathto(src, cwd), True)
2376 2376
2377 2377 def removeforget(abs):
2378 2378 if repo.dirstate[abs] == 'a':
2379 2379 return _('forgetting %s\n')
2380 2380 return _('removing %s\n')
2381 2381
2382 2382 revert = ([], _('reverting %s\n'))
2383 2383 add = ([], _('adding %s\n'))
2384 2384 remove = ([], removeforget)
2385 2385 undelete = ([], _('undeleting %s\n'))
2386 2386
2387 2387 disptable = (
2388 2388 # dispatch table:
2389 2389 # file state
2390 2390 # action if in target manifest
2391 2391 # action if not in target manifest
2392 2392 # make backup if in target manifest
2393 2393 # make backup if not in target manifest
2394 2394 (modified, revert, remove, True, True),
2395 2395 (added, revert, remove, True, False),
2396 2396 (removed, undelete, None, False, False),
2397 2397 (deleted, revert, remove, False, False),
2398 2398 )
2399 2399
2400 2400 entries = names.items()
2401 2401 entries.sort()
2402 2402
2403 2403 for abs, (rel, exact) in entries:
2404 2404 mfentry = mf.get(abs)
2405 2405 target = repo.wjoin(abs)
2406 2406 def handle(xlist, dobackup):
2407 2407 xlist[0].append(abs)
2408 2408 if dobackup and not opts['no_backup'] and util.lexists(target):
2409 2409 bakname = "%s.orig" % rel
2410 2410 ui.note(_('saving current version of %s as %s\n') %
2411 2411 (rel, bakname))
2412 2412 if not opts.get('dry_run'):
2413 2413 util.copyfile(target, bakname)
2414 2414 if ui.verbose or not exact:
2415 2415 msg = xlist[1]
2416 2416 if not isinstance(msg, basestring):
2417 2417 msg = msg(abs)
2418 2418 ui.status(msg % rel)
2419 2419 for table, hitlist, misslist, backuphit, backupmiss in disptable:
2420 2420 if abs not in table: continue
2421 2421 # file has changed in dirstate
2422 2422 if mfentry:
2423 2423 handle(hitlist, backuphit)
2424 2424 elif misslist is not None:
2425 2425 handle(misslist, backupmiss)
2426 2426 break
2427 2427 else:
2428 2428 if abs not in repo.dirstate:
2429 2429 if mfentry:
2430 2430 handle(add, True)
2431 2431 elif exact:
2432 2432 ui.warn(_('file not managed: %s\n') % rel)
2433 2433 continue
2434 2434 # file has not changed in dirstate
2435 2435 if node == parent:
2436 2436 if exact: ui.warn(_('no changes needed to %s\n') % rel)
2437 2437 continue
2438 2438 if pmf is None:
2439 2439 # only need parent manifest in this unlikely case,
2440 2440 # so do not read by default
2441 2441 pmf = repo.changectx(parent).manifest()
2442 2442 if abs in pmf:
2443 2443 if mfentry:
2444 2444 # if version of file is same in parent and target
2445 2445 # manifests, do nothing
2446 2446 if (pmf[abs] != mfentry or
2447 2447 pmf.flags(abs) != mf.flags(abs)):
2448 2448 handle(revert, False)
2449 2449 else:
2450 2450 handle(remove, False)
2451 2451
2452 2452 if not opts.get('dry_run'):
2453 2453 def checkout(f):
2454 2454 fc = ctx[f]
2455 2455 repo.wwrite(f, fc.data(), fc.fileflags())
2456 2456
2457 2457 audit_path = util.path_auditor(repo.root)
2458 2458 for f in remove[0]:
2459 2459 if repo.dirstate[f] == 'a':
2460 2460 repo.dirstate.forget(f)
2461 2461 continue
2462 2462 audit_path(f)
2463 2463 try:
2464 2464 util.unlink(repo.wjoin(f))
2465 2465 except OSError:
2466 2466 pass
2467 2467 repo.dirstate.remove(f)
2468 2468
2469 2469 normal = None
2470 2470 if node == parent:
2471 2471 # We're reverting to our parent. If possible, we'd like status
2472 2472 # to report the file as clean. We have to use normallookup for
2473 2473 # merges to avoid losing information about merged/dirty files.
2474 2474 if p2 != nullid:
2475 2475 normal = repo.dirstate.normallookup
2476 2476 else:
2477 2477 normal = repo.dirstate.normal
2478 2478 for f in revert[0]:
2479 2479 checkout(f)
2480 2480 if normal:
2481 2481 normal(f)
2482 2482
2483 2483 for f in add[0]:
2484 2484 checkout(f)
2485 2485 repo.dirstate.add(f)
2486 2486
2487 2487 normal = repo.dirstate.normallookup
2488 2488 if node == parent and p2 == nullid:
2489 2489 normal = repo.dirstate.normal
2490 2490 for f in undelete[0]:
2491 2491 checkout(f)
2492 2492 normal(f)
2493 2493
2494 2494 finally:
2495 2495 del wlock
2496 2496
2497 2497 def rollback(ui, repo):
2498 2498 """roll back the last transaction
2499 2499
2500 2500 This command should be used with care. There is only one level of
2501 2501 rollback, and there is no way to undo a rollback. It will also
2502 2502 restore the dirstate at the time of the last transaction, losing
2503 2503 any dirstate changes since that time.
2504 2504
2505 2505 Transactions are used to encapsulate the effects of all commands
2506 2506 that create new changesets or propagate existing changesets into a
2507 2507 repository. For example, the following commands are transactional,
2508 2508 and their effects can be rolled back:
2509 2509
2510 2510 commit
2511 2511 import
2512 2512 pull
2513 2513 push (with this repository as destination)
2514 2514 unbundle
2515 2515
2516 2516 This command is not intended for use on public repositories. Once
2517 2517 changes are visible for pull by other users, rolling a transaction
2518 2518 back locally is ineffective (someone else may already have pulled
2519 2519 the changes). Furthermore, a race is possible with readers of the
2520 2520 repository; for example an in-progress pull from the repository
2521 2521 may fail if a rollback is performed.
2522 2522 """
2523 2523 repo.rollback()
2524 2524
2525 2525 def root(ui, repo):
2526 2526 """print the root (top) of the current working dir
2527 2527
2528 2528 Print the root directory of the current repository.
2529 2529 """
2530 2530 ui.write(repo.root + "\n")
2531 2531
2532 2532 def serve(ui, repo, **opts):
2533 2533 """export the repository via HTTP
2534 2534
2535 2535 Start a local HTTP repository browser and pull server.
2536 2536
2537 2537 By default, the server logs accesses to stdout and errors to
2538 2538 stderr. Use the "-A" and "-E" options to log to files.
2539 2539 """
2540 2540
2541 2541 if opts["stdio"]:
2542 2542 if repo is None:
2543 2543 raise RepoError(_("There is no Mercurial repository here"
2544 2544 " (.hg not found)"))
2545 2545 s = sshserver.sshserver(ui, repo)
2546 2546 s.serve_forever()
2547 2547
2548 2548 parentui = ui.parentui or ui
2549 2549 optlist = ("name templates style address port prefix ipv6"
2550 2550 " accesslog errorlog webdir_conf certificate")
2551 2551 for o in optlist.split():
2552 2552 if opts[o]:
2553 2553 parentui.setconfig("web", o, str(opts[o]))
2554 2554 if (repo is not None) and (repo.ui != parentui):
2555 2555 repo.ui.setconfig("web", o, str(opts[o]))
2556 2556
2557 2557 if repo is None and not ui.config("web", "webdir_conf"):
2558 2558 raise RepoError(_("There is no Mercurial repository here"
2559 2559 " (.hg not found)"))
2560 2560
2561 2561 class service:
2562 2562 def init(self):
2563 2563 util.set_signal_handler()
2564 2564 self.httpd = hgweb.server.create_server(parentui, repo)
2565 2565
2566 2566 if not ui.verbose: return
2567 2567
2568 2568 if self.httpd.prefix:
2569 2569 prefix = self.httpd.prefix.strip('/') + '/'
2570 2570 else:
2571 2571 prefix = ''
2572 2572
2573 2573 port = ':%d' % self.httpd.port
2574 2574 if port == ':80':
2575 2575 port = ''
2576 2576
2577 2577 bindaddr = self.httpd.addr
2578 2578 if bindaddr == '0.0.0.0':
2579 2579 bindaddr = '*'
2580 2580 elif ':' in bindaddr: # IPv6
2581 2581 bindaddr = '[%s]' % bindaddr
2582 2582
2583 2583 fqaddr = self.httpd.fqaddr
2584 2584 if ':' in fqaddr:
2585 2585 fqaddr = '[%s]' % fqaddr
2586 2586 ui.status(_('listening at http://%s%s/%s (bound to %s:%d)\n') %
2587 2587 (fqaddr, port, prefix, bindaddr, self.httpd.port))
2588 2588
2589 2589 def run(self):
2590 2590 self.httpd.serve_forever()
2591 2591
2592 2592 service = service()
2593 2593
2594 2594 cmdutil.service(opts, initfn=service.init, runfn=service.run)
2595 2595
2596 2596 def status(ui, repo, *pats, **opts):
2597 2597 """show changed files in the working directory
2598 2598
2599 2599 Show status of files in the repository. If names are given, only
2600 2600 files that match are shown. Files that are clean or ignored or
2601 2601 source of a copy/move operation, are not listed unless -c (clean),
2602 2602 -i (ignored), -C (copies) or -A is given. Unless options described
2603 2603 with "show only ..." are given, the options -mardu are used.
2604 2604
2605 2605 Option -q/--quiet hides untracked (unknown and ignored) files
2606 2606 unless explicitly requested with -u/--unknown or -i/-ignored.
2607 2607
2608 2608 NOTE: status may appear to disagree with diff if permissions have
2609 2609 changed or a merge has occurred. The standard diff format does not
2610 2610 report permission changes and diff only reports changes relative
2611 2611 to one merge parent.
2612 2612
2613 2613 If one revision is given, it is used as the base revision.
2614 2614 If two revisions are given, the difference between them is shown.
2615 2615
2616 2616 The codes used to show the status of files are:
2617 2617 M = modified
2618 2618 A = added
2619 2619 R = removed
2620 2620 C = clean
2621 2621 ! = deleted, but still tracked
2622 2622 ? = not tracked
2623 2623 I = ignored
2624 2624 = the previous added file was copied from here
2625 2625 """
2626 2626
2627 2627 all = opts['all']
2628 2628 node1, node2 = cmdutil.revpair(repo, opts.get('rev'))
2629 2629
2630 2630 matcher = cmdutil.match(repo, pats, opts)
2631 2631 cwd = (pats and repo.getcwd()) or ''
2632 2632 modified, added, removed, deleted, unknown, ignored, clean = [
2633 2633 n for n in repo.status(node1, node2, matcher.files(), matcher,
2634 2634 list_ignored=opts['ignored']
2635 2635 or all and not ui.quiet,
2636 2636 list_clean=opts['clean'] or all,
2637 2637 list_unknown=opts['unknown']
2638 2638 or not (ui.quiet or
2639 2639 opts['modified'] or
2640 2640 opts['added'] or
2641 2641 opts['removed'] or
2642 2642 opts['deleted'] or
2643 2643 opts['ignored']))]
2644 2644
2645 2645 changetypes = (('modified', 'M', modified),
2646 2646 ('added', 'A', added),
2647 2647 ('removed', 'R', removed),
2648 2648 ('deleted', '!', deleted),
2649 2649 ('unknown', '?', unknown),
2650 2650 ('ignored', 'I', ignored))
2651 2651
2652 2652 explicit_changetypes = changetypes + (('clean', 'C', clean),)
2653 2653
2654 2654 copy = {}
2655 2655 showcopy = {}
2656 2656 if ((all or opts.get('copies')) and not opts.get('no_status')):
2657 2657 if opts.get('rev') == []:
2658 2658 # fast path, more correct with merge parents
2659 2659 showcopy = copy = repo.dirstate.copies().copy()
2660 2660 else:
2661 2661 ctxn = repo.changectx(nullid)
2662 2662 ctx1 = repo.changectx(node1)
2663 2663 ctx2 = repo.changectx(node2)
2664 2664 if node2 is None:
2665 2665 ctx2 = repo.workingctx()
2666 2666 copy, diverge = copies.copies(repo, ctx1, ctx2, ctxn)
2667 2667 for k, v in copy.items():
2668 2668 copy[v] = k
2669 2669
2670 2670 end = opts['print0'] and '\0' or '\n'
2671 2671
2672 2672 for opt, char, changes in ([ct for ct in explicit_changetypes
2673 2673 if all or opts[ct[0]]]
2674 2674 or changetypes):
2675 2675
2676 2676 if opts['no_status']:
2677 2677 format = "%%s%s" % end
2678 2678 else:
2679 2679 format = "%s %%s%s" % (char, end)
2680 2680
2681 2681 for f in changes:
2682 2682 ui.write(format % repo.pathto(f, cwd))
2683 2683 if f in copy and (f in added or f in showcopy):
2684 2684 ui.write(' %s%s' % (repo.pathto(copy[f], cwd), end))
2685 2685
2686 2686 def tag(ui, repo, name1, *names, **opts):
2687 2687 """add one or more tags for the current or given revision
2688 2688
2689 2689 Name a particular revision using <name>.
2690 2690
2691 2691 Tags are used to name particular revisions of the repository and are
2692 2692 very useful to compare different revisions, to go back to significant
2693 2693 earlier versions or to mark branch points as releases, etc.
2694 2694
2695 2695 If no revision is given, the parent of the working directory is used,
2696 2696 or tip if no revision is checked out.
2697 2697
2698 2698 To facilitate version control, distribution, and merging of tags,
2699 2699 they are stored as a file named ".hgtags" which is managed
2700 2700 similarly to other project files and can be hand-edited if
2701 2701 necessary. The file '.hg/localtags' is used for local tags (not
2702 2702 shared among repositories).
2703 2703
2704 2704 See 'hg help dates' for a list of formats valid for -d/--date.
2705 2705 """
2706 2706
2707 2707 rev_ = None
2708 2708 names = (name1,) + names
2709 2709 if len(names) != len(dict.fromkeys(names)):
2710 2710 raise util.Abort(_('tag names must be unique'))
2711 2711 for n in names:
2712 2712 if n in ['tip', '.', 'null']:
2713 2713 raise util.Abort(_('the name \'%s\' is reserved') % n)
2714 2714 if opts['rev'] and opts['remove']:
2715 2715 raise util.Abort(_("--rev and --remove are incompatible"))
2716 2716 if opts['rev']:
2717 2717 rev_ = opts['rev']
2718 2718 message = opts['message']
2719 2719 if opts['remove']:
2720 2720 expectedtype = opts['local'] and 'local' or 'global'
2721 2721 for n in names:
2722 2722 if not repo.tagtype(n):
2723 2723 raise util.Abort(_('tag \'%s\' does not exist') % n)
2724 2724 if repo.tagtype(n) != expectedtype:
2725 2725 raise util.Abort(_('tag \'%s\' is not a %s tag') %
2726 2726 (n, expectedtype))
2727 2727 rev_ = nullid
2728 2728 if not message:
2729 2729 message = _('Removed tag %s') % ', '.join(names)
2730 2730 elif not opts['force']:
2731 2731 for n in names:
2732 2732 if n in repo.tags():
2733 2733 raise util.Abort(_('tag \'%s\' already exists '
2734 2734 '(use -f to force)') % n)
2735 2735 if not rev_ and repo.dirstate.parents()[1] != nullid:
2736 2736 raise util.Abort(_('uncommitted merge - please provide a '
2737 2737 'specific revision'))
2738 2738 r = repo.changectx(rev_).node()
2739 2739
2740 2740 if not message:
2741 2741 message = (_('Added tag %s for changeset %s') %
2742 2742 (', '.join(names), short(r)))
2743 2743
2744 2744 date = opts.get('date')
2745 2745 if date:
2746 2746 date = util.parsedate(date)
2747 2747
2748 2748 repo.tag(names, r, message, opts['local'], opts['user'], date)
2749 2749
2750 2750 def tags(ui, repo):
2751 2751 """list repository tags
2752 2752
2753 2753 List the repository tags.
2754 2754
2755 2755 This lists both regular and local tags. When the -v/--verbose switch
2756 2756 is used, a third column "local" is printed for local tags.
2757 2757 """
2758 2758
2759 2759 l = repo.tagslist()
2760 2760 l.reverse()
2761 2761 hexfunc = ui.debugflag and hex or short
2762 2762 tagtype = ""
2763 2763
2764 2764 for t, n in l:
2765 2765 if ui.quiet:
2766 2766 ui.write("%s\n" % t)
2767 2767 continue
2768 2768
2769 2769 try:
2770 2770 hn = hexfunc(n)
2771 2771 r = "%5d:%s" % (repo.changelog.rev(n), hn)
2772 2772 except revlog.LookupError:
2773 2773 r = " ?:%s" % hn
2774 2774 else:
2775 2775 spaces = " " * (30 - util.locallen(t))
2776 2776 if ui.verbose:
2777 2777 if repo.tagtype(t) == 'local':
2778 2778 tagtype = " local"
2779 2779 else:
2780 2780 tagtype = ""
2781 2781 ui.write("%s%s %s%s\n" % (t, spaces, r, tagtype))
2782 2782
2783 2783 def tip(ui, repo, **opts):
2784 2784 """show the tip revision
2785 2785
2786 2786 The tip revision (usually just called the tip) is the most
2787 2787 recently added changeset in the repository, the most recently
2788 2788 changed head.
2789 2789
2790 2790 If you have just made a commit, that commit will be the tip. If
2791 2791 you have just pulled changes from another repository, the tip of
2792 2792 that repository becomes the current tip. The "tip" tag is special
2793 2793 and cannot be renamed or assigned to a different changeset.
2794 2794 """
2795 2795 cmdutil.show_changeset(ui, repo, opts).show(nullrev+repo.changelog.count())
2796 2796
2797 2797 def unbundle(ui, repo, fname1, *fnames, **opts):
2798 2798 """apply one or more changegroup files
2799 2799
2800 2800 Apply one or more compressed changegroup files generated by the
2801 2801 bundle command.
2802 2802 """
2803 2803 fnames = (fname1,) + fnames
2804 2804
2805 2805 lock = None
2806 2806 try:
2807 2807 lock = repo.lock()
2808 2808 for fname in fnames:
2809 2809 if os.path.exists(fname):
2810 2810 f = open(fname, "rb")
2811 2811 else:
2812 2812 f = urllib.urlopen(fname)
2813 2813 gen = changegroup.readbundle(f, fname)
2814 2814 modheads = repo.addchangegroup(gen, 'unbundle', 'bundle:' + fname)
2815 2815 finally:
2816 2816 del lock
2817 2817
2818 2818 return postincoming(ui, repo, modheads, opts['update'], None)
2819 2819
2820 2820 def update(ui, repo, node=None, rev=None, clean=False, date=None):
2821 2821 """update working directory
2822 2822
2823 2823 Update the working directory to the specified revision, or the
2824 2824 tip of the current branch if none is specified.
2825 2825
2826 2826 If the requested revision is a descendant of the working
2827 2827 directory, any outstanding changes in the working directory will
2828 2828 be merged into the result. If it is not directly descended but is
2829 2829 on the same named branch, update aborts with a suggestion to use
2830 2830 merge or update -C instead.
2831 2831
2832 2832 If the requested revision is on a different named branch and the
2833 2833 working directory is clean, update quietly switches branches.
2834 2834
2835 2835 See 'hg help dates' for a list of formats valid for --date.
2836 2836 """
2837 2837 if rev and node:
2838 2838 raise util.Abort(_("please specify just one revision"))
2839 2839
2840 2840 if not rev:
2841 2841 rev = node
2842 2842
2843 2843 if date:
2844 2844 if rev:
2845 2845 raise util.Abort(_("you can't specify a revision and a date"))
2846 2846 rev = cmdutil.finddate(ui, repo, date)
2847 2847
2848 2848 if clean:
2849 2849 return hg.clean(repo, rev)
2850 2850 else:
2851 2851 return hg.update(repo, rev)
2852 2852
2853 2853 def verify(ui, repo):
2854 2854 """verify the integrity of the repository
2855 2855
2856 2856 Verify the integrity of the current repository.
2857 2857
2858 2858 This will perform an extensive check of the repository's
2859 2859 integrity, validating the hashes and checksums of each entry in
2860 2860 the changelog, manifest, and tracked files, as well as the
2861 2861 integrity of their crosslinks and indices.
2862 2862 """
2863 2863 return hg.verify(repo)
2864 2864
2865 2865 def version_(ui):
2866 2866 """output version and copyright information"""
2867 2867 ui.write(_("Mercurial Distributed SCM (version %s)\n")
2868 2868 % version.get_version())
2869 2869 ui.status(_(
2870 2870 "\nCopyright (C) 2005-2008 Matt Mackall <mpm@selenic.com> and others\n"
2871 2871 "This is free software; see the source for copying conditions. "
2872 2872 "There is NO\nwarranty; "
2873 2873 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
2874 2874 ))
2875 2875
2876 2876 # Command options and aliases are listed here, alphabetically
2877 2877
2878 2878 globalopts = [
2879 2879 ('R', 'repository', '',
2880 2880 _('repository root directory or symbolic path name')),
2881 2881 ('', 'cwd', '', _('change working directory')),
2882 2882 ('y', 'noninteractive', None,
2883 2883 _('do not prompt, assume \'yes\' for any required answers')),
2884 2884 ('q', 'quiet', None, _('suppress output')),
2885 2885 ('v', 'verbose', None, _('enable additional output')),
2886 2886 ('', 'config', [], _('set/override config option')),
2887 2887 ('', 'debug', None, _('enable debugging output')),
2888 2888 ('', 'debugger', None, _('start debugger')),
2889 2889 ('', 'encoding', util._encoding, _('set the charset encoding')),
2890 2890 ('', 'encodingmode', util._encodingmode, _('set the charset encoding mode')),
2891 2891 ('', 'lsprof', None, _('print improved command execution profile')),
2892 2892 ('', 'traceback', None, _('print traceback on exception')),
2893 2893 ('', 'time', None, _('time how long the command takes')),
2894 2894 ('', 'profile', None, _('print command execution profile')),
2895 2895 ('', 'version', None, _('output version information and exit')),
2896 2896 ('h', 'help', None, _('display help and exit')),
2897 2897 ]
2898 2898
2899 2899 dryrunopts = [('n', 'dry-run', None,
2900 2900 _('do not perform actions, just print output'))]
2901 2901
2902 2902 remoteopts = [
2903 2903 ('e', 'ssh', '', _('specify ssh command to use')),
2904 2904 ('', 'remotecmd', '', _('specify hg command to run on the remote side')),
2905 2905 ]
2906 2906
2907 2907 walkopts = [
2908 2908 ('I', 'include', [], _('include names matching the given patterns')),
2909 2909 ('X', 'exclude', [], _('exclude names matching the given patterns')),
2910 2910 ]
2911 2911
2912 2912 commitopts = [
2913 2913 ('m', 'message', '', _('use <text> as commit message')),
2914 2914 ('l', 'logfile', '', _('read commit message from <file>')),
2915 2915 ]
2916 2916
2917 2917 commitopts2 = [
2918 2918 ('d', 'date', '', _('record datecode as commit date')),
2919 2919 ('u', 'user', '', _('record user as committer')),
2920 2920 ]
2921 2921
2922 2922 templateopts = [
2923 2923 ('', 'style', '', _('display using template map file')),
2924 2924 ('', 'template', '', _('display with template')),
2925 2925 ]
2926 2926
2927 2927 logopts = [
2928 2928 ('p', 'patch', None, _('show patch')),
2929 2929 ('l', 'limit', '', _('limit number of changes displayed')),
2930 2930 ('M', 'no-merges', None, _('do not show merges')),
2931 2931 ] + templateopts
2932 2932
2933 2933 table = {
2934 2934 "^add": (add, walkopts + dryrunopts, _('hg add [OPTION]... [FILE]...')),
2935 2935 "addremove":
2936 2936 (addremove,
2937 2937 [('s', 'similarity', '',
2938 2938 _('guess renamed files by similarity (0<=s<=100)')),
2939 2939 ] + walkopts + dryrunopts,
2940 2940 _('hg addremove [OPTION]... [FILE]...')),
2941 2941 "^annotate|blame":
2942 2942 (annotate,
2943 2943 [('r', 'rev', '', _('annotate the specified revision')),
2944 2944 ('f', 'follow', None, _('follow file copies and renames')),
2945 2945 ('a', 'text', None, _('treat all files as text')),
2946 2946 ('u', 'user', None, _('list the author (long with -v)')),
2947 2947 ('d', 'date', None, _('list the date (short with -q)')),
2948 2948 ('n', 'number', None, _('list the revision number (default)')),
2949 2949 ('c', 'changeset', None, _('list the changeset')),
2950 2950 ('l', 'line-number', None,
2951 2951 _('show line number at the first appearance'))
2952 2952 ] + walkopts,
2953 2953 _('hg annotate [-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...')),
2954 2954 "archive":
2955 2955 (archive,
2956 2956 [('', 'no-decode', None, _('do not pass files through decoders')),
2957 2957 ('p', 'prefix', '', _('directory prefix for files in archive')),
2958 2958 ('r', 'rev', '', _('revision to distribute')),
2959 2959 ('t', 'type', '', _('type of distribution to create')),
2960 2960 ] + walkopts,
2961 2961 _('hg archive [OPTION]... DEST')),
2962 2962 "backout":
2963 2963 (backout,
2964 2964 [('', 'merge', None,
2965 2965 _('merge with old dirstate parent after backout')),
2966 2966 ('', 'parent', '', _('parent to choose when backing out merge')),
2967 2967 ('r', 'rev', '', _('revision to backout')),
2968 2968 ] + walkopts + commitopts + commitopts2,
2969 2969 _('hg backout [OPTION]... [-r] REV')),
2970 2970 "bisect":
2971 2971 (bisect,
2972 2972 [('r', 'reset', False, _('reset bisect state')),
2973 2973 ('g', 'good', False, _('mark changeset good')),
2974 2974 ('b', 'bad', False, _('mark changeset bad')),
2975 2975 ('s', 'skip', False, _('skip testing changeset')),
2976 2976 ('U', 'noupdate', False, _('do not update to target'))],
2977 2977 _("hg bisect [-gbsr] [REV]")),
2978 2978 "branch":
2979 2979 (branch,
2980 2980 [('f', 'force', None,
2981 2981 _('set branch name even if it shadows an existing branch'))],
2982 2982 _('hg branch [-f] [NAME]')),
2983 2983 "branches":
2984 2984 (branches,
2985 2985 [('a', 'active', False,
2986 2986 _('show only branches that have unmerged heads'))],
2987 2987 _('hg branches [-a]')),
2988 2988 "bundle":
2989 2989 (bundle,
2990 2990 [('f', 'force', None,
2991 2991 _('run even when remote repository is unrelated')),
2992 2992 ('r', 'rev', [],
2993 2993 _('a changeset up to which you would like to bundle')),
2994 2994 ('', 'base', [],
2995 2995 _('a base changeset to specify instead of a destination')),
2996 2996 ('a', 'all', None, _('bundle all changesets in the repository')),
2997 2997 ('t', 'type', 'bzip2', _('bundle compression type to use')),
2998 2998 ] + remoteopts,
2999 2999 _('hg bundle [-f] [-a] [-r REV]... [--base REV]... FILE [DEST]')),
3000 3000 "cat":
3001 3001 (cat,
3002 3002 [('o', 'output', '', _('print output to file with formatted name')),
3003 3003 ('r', 'rev', '', _('print the given revision')),
3004 3004 ('', 'decode', None, _('apply any matching decode filter')),
3005 3005 ] + walkopts,
3006 3006 _('hg cat [OPTION]... FILE...')),
3007 3007 "^clone":
3008 3008 (clone,
3009 3009 [('U', 'noupdate', None, _('do not update the new working directory')),
3010 3010 ('r', 'rev', [],
3011 3011 _('a changeset you would like to have after cloning')),
3012 3012 ('', 'pull', None, _('use pull protocol to copy metadata')),
3013 3013 ('', 'uncompressed', None,
3014 3014 _('use uncompressed transfer (fast over LAN)')),
3015 3015 ] + remoteopts,
3016 3016 _('hg clone [OPTION]... SOURCE [DEST]')),
3017 3017 "^commit|ci":
3018 3018 (commit,
3019 3019 [('A', 'addremove', None,
3020 3020 _('mark new/missing files as added/removed before committing')),
3021 3021 ] + walkopts + commitopts + commitopts2,
3022 3022 _('hg commit [OPTION]... [FILE]...')),
3023 3023 "copy|cp":
3024 3024 (copy,
3025 3025 [('A', 'after', None, _('record a copy that has already occurred')),
3026 3026 ('f', 'force', None,
3027 3027 _('forcibly copy over an existing managed file')),
3028 3028 ] + walkopts + dryrunopts,
3029 3029 _('hg copy [OPTION]... [SOURCE]... DEST')),
3030 3030 "debugancestor": (debugancestor, [],
3031 3031 _('hg debugancestor [INDEX] REV1 REV2')),
3032 3032 "debugcheckstate": (debugcheckstate, [], _('hg debugcheckstate')),
3033 3033 "debugcomplete":
3034 3034 (debugcomplete,
3035 3035 [('o', 'options', None, _('show the command options'))],
3036 3036 _('hg debugcomplete [-o] CMD')),
3037 3037 "debugdate":
3038 3038 (debugdate,
3039 3039 [('e', 'extended', None, _('try extended date formats'))],
3040 3040 _('hg debugdate [-e] DATE [RANGE]')),
3041 3041 "debugdata": (debugdata, [], _('hg debugdata FILE REV')),
3042 3042 "debugfsinfo": (debugfsinfo, [], _('hg debugfsinfo [PATH]')),
3043 3043 "debugindex": (debugindex, [], _('hg debugindex FILE')),
3044 3044 "debugindexdot": (debugindexdot, [], _('hg debugindexdot FILE')),
3045 3045 "debuginstall": (debuginstall, [], _('hg debuginstall')),
3046 3046 "debugrawcommit|rawcommit":
3047 3047 (rawcommit,
3048 3048 [('p', 'parent', [], _('parent')),
3049 3049 ('F', 'files', '', _('file list'))
3050 3050 ] + commitopts + commitopts2,
3051 3051 _('hg debugrawcommit [OPTION]... [FILE]...')),
3052 3052 "debugrebuildstate":
3053 3053 (debugrebuildstate,
3054 3054 [('r', 'rev', '', _('revision to rebuild to'))],
3055 3055 _('hg debugrebuildstate [-r REV] [REV]')),
3056 3056 "debugrename":
3057 3057 (debugrename,
3058 3058 [('r', 'rev', '', _('revision to debug'))],
3059 3059 _('hg debugrename [-r REV] FILE')),
3060 3060 "debugsetparents":
3061 3061 (debugsetparents,
3062 3062 [],
3063 3063 _('hg debugsetparents REV1 [REV2]')),
3064 3064 "debugstate":
3065 3065 (debugstate,
3066 3066 [('', 'nodates', None, _('do not display the saved mtime'))],
3067 3067 _('hg debugstate [OPTS]')),
3068 3068 "debugwalk": (debugwalk, walkopts, _('hg debugwalk [OPTION]... [FILE]...')),
3069 3069 "^diff":
3070 3070 (diff,
3071 3071 [('r', 'rev', [], _('revision')),
3072 3072 ('a', 'text', None, _('treat all files as text')),
3073 3073 ('p', 'show-function', None,
3074 3074 _('show which function each change is in')),
3075 3075 ('g', 'git', None, _('use git extended diff format')),
3076 3076 ('', 'nodates', None, _("don't include dates in diff headers")),
3077 3077 ('w', 'ignore-all-space', None,
3078 3078 _('ignore white space when comparing lines')),
3079 3079 ('b', 'ignore-space-change', None,
3080 3080 _('ignore changes in the amount of white space')),
3081 3081 ('B', 'ignore-blank-lines', None,
3082 3082 _('ignore changes whose lines are all blank')),
3083 3083 ('U', 'unified', '',
3084 3084 _('number of lines of context to show'))
3085 3085 ] + walkopts,
3086 3086 _('hg diff [OPTION]... [-r REV1 [-r REV2]] [FILE]...')),
3087 3087 "^export":
3088 3088 (export,
3089 3089 [('o', 'output', '', _('print output to file with formatted name')),
3090 3090 ('a', 'text', None, _('treat all files as text')),
3091 3091 ('g', 'git', None, _('use git extended diff format')),
3092 3092 ('', 'nodates', None, _("don't include dates in diff headers")),
3093 3093 ('', 'switch-parent', None, _('diff against the second parent'))],
3094 3094 _('hg export [OPTION]... [-o OUTFILESPEC] REV...')),
3095 3095 "grep":
3096 3096 (grep,
3097 3097 [('0', 'print0', None, _('end fields with NUL')),
3098 3098 ('', 'all', None, _('print all revisions that match')),
3099 3099 ('f', 'follow', None,
3100 3100 _('follow changeset history, or file history across copies and renames')),
3101 3101 ('i', 'ignore-case', None, _('ignore case when matching')),
3102 3102 ('l', 'files-with-matches', None,
3103 3103 _('print only filenames and revs that match')),
3104 3104 ('n', 'line-number', None, _('print matching line numbers')),
3105 3105 ('r', 'rev', [], _('search in given revision range')),
3106 3106 ('u', 'user', None, _('list the author (long with -v)')),
3107 3107 ('d', 'date', None, _('list the date (short with -q)')),
3108 3108 ] + walkopts,
3109 3109 _('hg grep [OPTION]... PATTERN [FILE]...')),
3110 3110 "heads":
3111 3111 (heads,
3112 3112 [('r', 'rev', '', _('show only heads which are descendants of rev')),
3113 3113 ] + templateopts,
3114 3114 _('hg heads [-r REV] [REV]...')),
3115 3115 "help": (help_, [], _('hg help [COMMAND]')),
3116 3116 "identify|id":
3117 3117 (identify,
3118 3118 [('r', 'rev', '', _('identify the specified rev')),
3119 3119 ('n', 'num', None, _('show local revision number')),
3120 3120 ('i', 'id', None, _('show global revision id')),
3121 3121 ('b', 'branch', None, _('show branch')),
3122 3122 ('t', 'tags', None, _('show tags'))],
3123 3123 _('hg identify [-nibt] [-r REV] [SOURCE]')),
3124 3124 "import|patch":
3125 3125 (import_,
3126 3126 [('p', 'strip', 1,
3127 3127 _('directory strip option for patch. This has the same\n'
3128 3128 'meaning as the corresponding patch option')),
3129 3129 ('b', 'base', '', _('base path')),
3130 3130 ('f', 'force', None,
3131 3131 _('skip check for outstanding uncommitted changes')),
3132 3132 ('', 'no-commit', None, _("don't commit, just update the working directory")),
3133 3133 ('', 'exact', None,
3134 3134 _('apply patch to the nodes from which it was generated')),
3135 3135 ('', 'import-branch', None,
3136 3136 _('Use any branch information in patch (implied by --exact)'))] +
3137 3137 commitopts + commitopts2,
3138 3138 _('hg import [OPTION]... PATCH...')),
3139 3139 "incoming|in":
3140 3140 (incoming,
3141 3141 [('f', 'force', None,
3142 3142 _('run even when remote repository is unrelated')),
3143 3143 ('n', 'newest-first', None, _('show newest record first')),
3144 3144 ('', 'bundle', '', _('file to store the bundles into')),
3145 3145 ('r', 'rev', [],
3146 3146 _('a specific revision up to which you would like to pull')),
3147 3147 ] + logopts + remoteopts,
3148 3148 _('hg incoming [-p] [-n] [-M] [-f] [-r REV]...'
3149 3149 ' [--bundle FILENAME] [SOURCE]')),
3150 3150 "^init":
3151 3151 (init,
3152 3152 remoteopts,
3153 3153 _('hg init [-e CMD] [--remotecmd CMD] [DEST]')),
3154 3154 "locate":
3155 3155 (locate,
3156 3156 [('r', 'rev', '', _('search the repository as it stood at rev')),
3157 3157 ('0', 'print0', None,
3158 3158 _('end filenames with NUL, for use with xargs')),
3159 3159 ('f', 'fullpath', None,
3160 3160 _('print complete paths from the filesystem root')),
3161 3161 ] + walkopts,
3162 3162 _('hg locate [OPTION]... [PATTERN]...')),
3163 3163 "^log|history":
3164 3164 (log,
3165 3165 [('f', 'follow', None,
3166 3166 _('follow changeset history, or file history across copies and renames')),
3167 3167 ('', 'follow-first', None,
3168 3168 _('only follow the first parent of merge changesets')),
3169 3169 ('d', 'date', '', _('show revs matching date spec')),
3170 3170 ('C', 'copies', None, _('show copied files')),
3171 3171 ('k', 'keyword', [], _('do case-insensitive search for a keyword')),
3172 3172 ('r', 'rev', [], _('show the specified revision or range')),
3173 3173 ('', 'removed', None, _('include revs where files were removed')),
3174 3174 ('m', 'only-merges', None, _('show only merges')),
3175 3175 ('b', 'only-branch', [],
3176 3176 _('show only changesets within the given named branch')),
3177 3177 ('P', 'prune', [], _('do not display revision or any of its ancestors')),
3178 3178 ] + logopts + walkopts,
3179 3179 _('hg log [OPTION]... [FILE]')),
3180 3180 "manifest":
3181 3181 (manifest,
3182 3182 [('r', 'rev', '', _('revision to display'))],
3183 3183 _('hg manifest [-r REV]')),
3184 3184 "^merge":
3185 3185 (merge,
3186 3186 [('f', 'force', None, _('force a merge with outstanding changes')),
3187 3187 ('r', 'rev', '', _('revision to merge')),
3188 3188 ],
3189 3189 _('hg merge [-f] [[-r] REV]')),
3190 3190 "outgoing|out":
3191 3191 (outgoing,
3192 3192 [('f', 'force', None,
3193 3193 _('run even when remote repository is unrelated')),
3194 3194 ('r', 'rev', [],
3195 3195 _('a specific revision up to which you would like to push')),
3196 3196 ('n', 'newest-first', None, _('show newest record first')),
3197 3197 ] + logopts + remoteopts,
3198 3198 _('hg outgoing [-M] [-p] [-n] [-f] [-r REV]... [DEST]')),
3199 3199 "^parents":
3200 3200 (parents,
3201 3201 [('r', 'rev', '', _('show parents from the specified rev')),
3202 3202 ] + templateopts,
3203 3203 _('hg parents [-r REV] [FILE]')),
3204 3204 "paths": (paths, [], _('hg paths [NAME]')),
3205 3205 "^pull":
3206 3206 (pull,
3207 3207 [('u', 'update', None,
3208 3208 _('update to new tip if changesets were pulled')),
3209 3209 ('f', 'force', None,
3210 3210 _('run even when remote repository is unrelated')),
3211 3211 ('r', 'rev', [],
3212 3212 _('a specific revision up to which you would like to pull')),
3213 3213 ] + remoteopts,
3214 3214 _('hg pull [-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]')),
3215 3215 "^push":
3216 3216 (push,
3217 3217 [('f', 'force', None, _('force push')),
3218 3218 ('r', 'rev', [],
3219 3219 _('a specific revision up to which you would like to push')),
3220 3220 ] + remoteopts,
3221 3221 _('hg push [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]')),
3222 3222 "recover": (recover, [], _('hg recover')),
3223 3223 "^remove|rm":
3224 3224 (remove,
3225 3225 [('A', 'after', None, _('record delete for missing files')),
3226 3226 ('f', 'force', None,
3227 3227 _('remove (and delete) file even if added or modified')),
3228 3228 ] + walkopts,
3229 3229 _('hg remove [OPTION]... FILE...')),
3230 3230 "rename|mv":
3231 3231 (rename,
3232 3232 [('A', 'after', None, _('record a rename that has already occurred')),
3233 3233 ('f', 'force', None,
3234 3234 _('forcibly copy over an existing managed file')),
3235 3235 ] + walkopts + dryrunopts,
3236 3236 _('hg rename [OPTION]... SOURCE... DEST')),
3237 3237 "resolve":
3238 3238 (resolve,
3239 3239 [('l', 'list', None, _('list state of files needing merge')),
3240 3240 ('m', 'mark', None, _('mark files as resolved')),
3241 3241 ('u', 'unmark', None, _('unmark files as resolved'))],
3242 3242 ('hg resolve [OPTION] [FILES...]')),
3243 3243 "revert":
3244 3244 (revert,
3245 3245 [('a', 'all', None, _('revert all changes when no arguments given')),
3246 3246 ('d', 'date', '', _('tipmost revision matching date')),
3247 3247 ('r', 'rev', '', _('revision to revert to')),
3248 3248 ('', 'no-backup', None, _('do not save backup copies of files')),
3249 3249 ] + walkopts + dryrunopts,
3250 3250 _('hg revert [OPTION]... [-r REV] [NAME]...')),
3251 3251 "rollback": (rollback, [], _('hg rollback')),
3252 3252 "root": (root, [], _('hg root')),
3253 3253 "^serve":
3254 3254 (serve,
3255 3255 [('A', 'accesslog', '', _('name of access log file to write to')),
3256 3256 ('d', 'daemon', None, _('run server in background')),
3257 3257 ('', 'daemon-pipefds', '', _('used internally by daemon mode')),
3258 3258 ('E', 'errorlog', '', _('name of error log file to write to')),
3259 3259 ('p', 'port', 0, _('port to listen on (default: 8000)')),
3260 3260 ('a', 'address', '', _('address to listen on (default: all interfaces)')),
3261 3261 ('', 'prefix', '', _('prefix path to serve from (default: server root)')),
3262 3262 ('n', 'name', '',
3263 3263 _('name to show in web pages (default: working dir)')),
3264 3264 ('', 'webdir-conf', '', _('name of the webdir config file'
3265 3265 ' (serve more than one repo)')),
3266 3266 ('', 'pid-file', '', _('name of file to write process ID to')),
3267 3267 ('', 'stdio', None, _('for remote clients')),
3268 3268 ('t', 'templates', '', _('web templates to use')),
3269 3269 ('', 'style', '', _('template style to use')),
3270 3270 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
3271 3271 ('', 'certificate', '', _('SSL certificate file'))],
3272 3272 _('hg serve [OPTION]...')),
3273 3273 "showconfig|debugconfig":
3274 3274 (showconfig,
3275 3275 [('u', 'untrusted', None, _('show untrusted configuration options'))],
3276 3276 _('hg showconfig [-u] [NAME]...')),
3277 3277 "^status|st":
3278 3278 (status,
3279 3279 [('A', 'all', None, _('show status of all files')),
3280 3280 ('m', 'modified', None, _('show only modified files')),
3281 3281 ('a', 'added', None, _('show only added files')),
3282 3282 ('r', 'removed', None, _('show only removed files')),
3283 3283 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
3284 3284 ('c', 'clean', None, _('show only files without changes')),
3285 3285 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
3286 3286 ('i', 'ignored', None, _('show only ignored files')),
3287 3287 ('n', 'no-status', None, _('hide status prefix')),
3288 3288 ('C', 'copies', None, _('show source of copied files')),
3289 3289 ('0', 'print0', None,
3290 3290 _('end filenames with NUL, for use with xargs')),
3291 3291 ('', 'rev', [], _('show difference from revision')),
3292 3292 ] + walkopts,
3293 3293 _('hg status [OPTION]... [FILE]...')),
3294 3294 "tag":
3295 3295 (tag,
3296 3296 [('f', 'force', None, _('replace existing tag')),
3297 3297 ('l', 'local', None, _('make the tag local')),
3298 3298 ('r', 'rev', '', _('revision to tag')),
3299 3299 ('', 'remove', None, _('remove a tag')),
3300 3300 # -l/--local is already there, commitopts cannot be used
3301 3301 ('m', 'message', '', _('use <text> as commit message')),
3302 3302 ] + commitopts2,
3303 3303 _('hg tag [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...')),
3304 3304 "tags": (tags, [], _('hg tags')),
3305 3305 "tip":
3306 3306 (tip,
3307 3307 [('p', 'patch', None, _('show patch')),
3308 3308 ] + templateopts,
3309 3309 _('hg tip [-p]')),
3310 3310 "unbundle":
3311 3311 (unbundle,
3312 3312 [('u', 'update', None,
3313 3313 _('update to new tip if changesets were unbundled'))],
3314 3314 _('hg unbundle [-u] FILE...')),
3315 3315 "^update|up|checkout|co":
3316 3316 (update,
3317 3317 [('C', 'clean', None, _('overwrite locally modified files')),
3318 3318 ('d', 'date', '', _('tipmost revision matching date')),
3319 3319 ('r', 'rev', '', _('revision'))],
3320 3320 _('hg update [-C] [-d DATE] [[-r] REV]')),
3321 3321 "verify": (verify, [], _('hg verify')),
3322 3322 "version": (version_, [], _('hg version')),
3323 3323 }
3324 3324
3325 3325 norepo = ("clone init version help debugcomplete debugdata"
3326 3326 " debugindex debugindexdot debugdate debuginstall debugfsinfo")
3327 3327 optionalrepo = ("identify paths serve showconfig debugancestor")
General Comments 0
You need to be logged in to leave comments. Login now