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