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