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