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