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