##// END OF EJS Templates
[PATCH] New export patch...
mpm@selenic.com -
r580:353a2ce5 default
parent child Browse files
Show More
@@ -129,11 +129,27 b' diff [-r revision] [-r revision] [files '
129 129 revisions are specified, the working directory files are compared
130 130 to its parent.
131 131
132 export [revision]::
133 Print the changeset header and diffs for a particular revision.
132 export [-o filespec] [revision] ...::
133 Print the changeset header and diffs for one or more revisions.
134
135 The information shown in the changeset header is: author,
136 changeset hash, parent and commit comment.
137
138 Output may be to a file, in which case the name of the file is
139 given using a format string. The formatting rules are as follows:
134 140
135 The information shown in the changeset header is: author, changeset hash,
136 parent and commit comment.
141 %% literal "%" character
142 %H changeset hash (40 bytes of hexadecimal)
143 %N number of patches being generated
144 %R changeset revision number
145 %b basename of the exporting repository
146 %h short-form changeset hash (12 bytes of hexadecimal)
147 %n zero-padded sequence number, starting at 1
148 %r zero-padded changeset revision number
149
150 Options:
151
152 -o, --output <filespec> print output to file with formatted named
137 153
138 154 forget [files]::
139 155 Undo an 'hg add' scheduled for the next commit.
@@ -317,6 +333,49 b' verify::'
317 333 the changelog, manifest, and tracked files, as well as the
318 334 integrity of their crosslinks and indices.
319 335
336 SPECIFYING SINGLE REVISIONS
337 ---------------------------
338
339 Mercurial accepts several notations for identifying individual
340 revisions.
341
342 A plain integer is treated as a revision number. Negative
343 integers are treated as offsets from the tip, with -1 denoting the
344 tip.
345
346 A 40-digit hexadecimal string is treated as a unique revision
347 identifier.
348
349 A hexadecimal string less than 40 characters long is treated as a
350 unique revision identifier, and referred to as a short-form
351 identifier. A short-form identifier is only valid if it is the
352 prefix of one full-length identifier.
353
354 Any other string is treated as a tag name, which is a symbolic
355 name associated with a revision identifier. Tag names may not
356 contain the ":" character.
357
358 The reserved name "tip" is a special tag that always identifies
359 the most recent revision.
360
361 SPECIFYING MULTIPLE REVISIONS
362 -----------------------------
363
364 When Mercurial accepts more than one revision, they may be
365 specified individually, or provided as a continuous range,
366 separated by the ":" character.
367
368 The syntax of range notation is [BEGIN]:[END], where BEGIN and END
369 are revision identifiers. Both BEGIN and END are optional. If
370 BEGIN is not specified, it defaults to revision number 0. If END
371 is not specified, it defaults to the tip. The range ":" thus
372 means "all revisions".
373
374 If BEGIN is greater than END, revisions are treated in reverse
375 order.
376
377 A range acts as an open interval. This means that a range of 3:5
378 gives 3, 4 and 5. Similarly, a range of 4:2 gives 4, 3, and 2.
320 379
321 380 ENVIRONMENT VARIABLES
322 381 ---------------------
@@ -33,7 +33,47 b' def relpath(repo, args):'
33 33 for x in args ]
34 34 return args
35 35
36 def dodiff(ui, repo, files = None, node1 = None, node2 = None):
36 revrangesep = ':'
37
38 def revrange(ui, repo, revs = [], revlog = None):
39 if revlog is None:
40 revlog = repo.changelog
41 revcount = revlog.count()
42 def fix(val, defval):
43 if not val: return defval
44 try:
45 num = int(val)
46 if str(num) != val: raise ValueError
47 if num < 0: num += revcount
48 if not (0 <= num < revcount):
49 raise ValueError
50 except ValueError:
51 try:
52 num = repo.changelog.rev(repo.lookup(val))
53 except KeyError:
54 try:
55 num = revlog.rev(revlog.lookup(val))
56 except KeyError:
57 ui.warn('abort: invalid revision identifier %s\n' % val)
58 sys.exit(1)
59 return num
60 for spec in revs:
61 if spec.find(revrangesep) >= 0:
62 start, end = spec.split(revrangesep, 1)
63 start = fix(start, 0)
64 end = fix(end, revcount - 1)
65 if end > start:
66 end += 1
67 step = 1
68 else:
69 end -= 1
70 step = -1
71 for rev in xrange(start, end, step):
72 yield str(rev)
73 else:
74 yield spec
75
76 def dodiff(fp, ui, repo, files = None, node1 = None, node2 = None):
37 77 def date(c):
38 78 return time.asctime(time.gmtime(float(c[2].split(' ')[0])))
39 79
@@ -70,15 +110,15 b' def dodiff(ui, repo, files = None, node1'
70 110 if f in mmap:
71 111 to = repo.file(f).read(mmap[f])
72 112 tn = read(f)
73 sys.stdout.write(mdiff.unidiff(to, date1, tn, date2, f, r))
113 fp.write(mdiff.unidiff(to, date1, tn, date2, f, r))
74 114 for f in a:
75 115 to = None
76 116 tn = read(f)
77 sys.stdout.write(mdiff.unidiff(to, date1, tn, date2, f, r))
117 fp.write(mdiff.unidiff(to, date1, tn, date2, f, r))
78 118 for f in d:
79 119 to = repo.file(f).read(mmap[f])
80 120 tn = None
81 sys.stdout.write(mdiff.unidiff(to, date1, tn, date2, f, r))
121 fp.write(mdiff.unidiff(to, date1, tn, date2, f, r))
82 122
83 123 def show_changeset(ui, repo, rev=0, changenode=None, filelog=None):
84 124 """show a single changeset or file revision"""
@@ -421,24 +461,68 b' def diff(ui, repo, *files, **opts):'
421 461 else:
422 462 files = relpath(repo, [""])
423 463
424 dodiff(ui, repo, files, *revs)
464 dodiff(sys.stdout, ui, repo, files, *revs)
425 465
426 def export(ui, repo, changeset):
427 """dump the changeset header and diffs for a revision"""
466 def doexport(ui, repo, changeset, seqno, total, revwidth, opts):
428 467 node = repo.lookup(changeset)
429 468 prev, other = repo.changelog.parents(node)
430 469 change = repo.changelog.read(node)
431 print "# HG changeset patch"
432 print "# User %s" % change[1]
433 print "# Node ID %s" % hg.hex(node)
434 print "# Parent %s" % hg.hex(prev)
435 print
470
471 def expand(name):
472 expansions = {
473 '%': lambda: '%',
474 'H': lambda: hg.hex(node),
475 'N': lambda: str(total),
476 'R': lambda: str(repo.changelog.rev(node)),
477 'b': lambda: os.path.basename(repo.root),
478 'h': lambda: hg.short(node),
479 'n': lambda: str(seqno).zfill(len(str(total))),
480 'r': lambda: str(repo.changelog.rev(node)).zfill(revwidth),
481 }
482 newname = []
483 namelen = len(name)
484 i = 0
485 while i < namelen:
486 c = name[i]
487 if c == '%':
488 i += 1
489 c = name[i]
490 c = expansions[c]()
491 newname.append(c)
492 i += 1
493 return ''.join(newname)
494
495 if opts['output'] and opts['output'] != '-':
496 try:
497 fp = open(expand(opts['output']), 'w')
498 except KeyError, inst:
499 ui.warn("error: invalid format spec '%%%s' in output file name\n" %
500 inst.args[0])
501 sys.exit(1)
502 else:
503 fp = sys.stdout
504
505 print >> fp, "# HG changeset patch"
506 print >> fp, "# User %s" % change[1]
507 print >> fp, "# Node ID %s" % hg.hex(node)
508 print >> fp, "# Parent %s" % hg.hex(prev)
509 print >> fp
436 510 if other != hg.nullid:
437 print "# Parent %s" % hg.hex(other)
438 print change[4].rstrip()
439 print
511 print >> fp, "# Parent %s" % hg.hex(other)
512 print >> fp, change[4].rstrip()
513 print >> fp
514
515 dodiff(fp, ui, repo, None, prev, node)
440 516
441 dodiff(ui, repo, None, prev, node)
517 def export(ui, repo, *changesets, **opts):
518 """dump the header and diffs for one or more changesets"""
519 seqno = 0
520 revs = list(revrange(ui, repo, changesets))
521 total = len(revs)
522 revwidth = max(len(revs[0]), len(revs[-1]))
523 for cset in revs:
524 seqno += 1
525 doexport(ui, repo, cset, seqno, total, revwidth, opts)
442 526
443 527 def forget(ui, repo, file, *files):
444 528 """don't add the specified files on the next commit"""
@@ -585,7 +669,7 b' def pull(ui, repo, source="default", **o'
585 669 if cg and not r:
586 670 if opts['update']:
587 671 return update(ui, repo)
588 else:
672 else:
589 673 ui.status("(run 'hg update' to get a working copy)\n")
590 674
591 675 return r
@@ -679,15 +763,18 b' def tag(ui, repo, name, rev = None, **op'
679 763 """add a tag for the current tip or a given revision"""
680 764
681 765 if name == "tip":
682 ui.warn("abort: 'tip' is a reserved name!\n")
683 return -1
766 ui.warn("abort: 'tip' is a reserved name!\n")
767 return -1
768 if name.find(revrangesep) >= 0:
769 ui.warn("abort: '%s' cannot be used in a tag name\n" % revrangesep)
770 return -1
684 771
685 772 (c, a, d, u) = repo.changes(None, None)
686 773 for x in (c, a, d, u):
687 if ".hgtags" in x:
688 ui.warn("abort: working copy of .hgtags is changed!\n")
774 if ".hgtags" in x:
775 ui.warn("abort: working copy of .hgtags is changed!\n")
689 776 ui.status("(please commit .hgtags manually)\n")
690 return -1
777 return -1
691 778
692 779 if rev:
693 780 r = hg.hex(repo.lookup(rev))
@@ -773,7 +860,8 b' table = {'
773 860 "debugindexdot": (debugindexdot, [], 'debugindexdot <file>'),
774 861 "diff": (diff, [('r', 'rev', [], 'revision')],
775 862 'hg diff [-r A] [-r B] [files]'),
776 "export": (export, [], "hg export <changeset>"),
863 "export": (export, [('o', 'output', "", 'output to file')],
864 "hg export [-o file] <changeset> ..."),
777 865 "forget": (forget, [], "hg forget [files]"),
778 866 "heads": (heads, [], 'hg heads'),
779 867 "help": (help, [], 'hg help [command]'),
@@ -790,7 +878,7 b' table = {'
790 878 "parents": (parents, [], 'hg parents [node]'),
791 879 "pull": (pull,
792 880 [('u', 'update', None, 'update working directory')],
793 'hg pull [options] [source]'),
881 'hg pull [options] [source]'),
794 882 "push": (push, [], 'hg push <destination>'),
795 883 "rawcommit": (rawcommit,
796 884 [('p', 'parent', [], 'parent'),
@@ -943,4 +1031,3 b' def dispatch(args):'
943 1031 help(u, cmd)
944 1032
945 1033 sys.exit(-1)
946
General Comments 0
You need to be logged in to leave comments. Login now