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