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