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