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