##// END OF EJS Templates
bundler: make parsechunk return the base revision of the delta
Benoit Boissinot -
r14141:bd1cbfe5 default
parent child Browse files
Show More
@@ -1,213 +1,227 b''
1 # changegroup.py - Mercurial changegroup manipulation functions
1 # changegroup.py - Mercurial changegroup manipulation functions
2 #
2 #
3 # Copyright 2006 Matt Mackall <mpm@selenic.com>
3 # Copyright 2006 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 from i18n import _
8 from i18n import _
9 import util
9 import util
10 import struct, os, bz2, zlib, tempfile
10 import struct, os, bz2, zlib, tempfile
11
11
12 _BUNDLE10_DELTA_HEADER = "20s20s20s20s"
13
12 def readexactly(stream, n):
14 def readexactly(stream, n):
13 '''read n bytes from stream.read and abort if less was available'''
15 '''read n bytes from stream.read and abort if less was available'''
14 s = stream.read(n)
16 s = stream.read(n)
15 if len(s) < n:
17 if len(s) < n:
16 raise util.Abort(_("stream ended unexpectedly"
18 raise util.Abort(_("stream ended unexpectedly"
17 " (got %d bytes, expected %d)")
19 " (got %d bytes, expected %d)")
18 % (len(s), n))
20 % (len(s), n))
19 return s
21 return s
20
22
21 def getchunk(stream):
23 def getchunk(stream):
22 """return the next chunk from stream as a string"""
24 """return the next chunk from stream as a string"""
23 d = readexactly(stream, 4)
25 d = readexactly(stream, 4)
24 l = struct.unpack(">l", d)[0]
26 l = struct.unpack(">l", d)[0]
25 if l <= 4:
27 if l <= 4:
26 if l:
28 if l:
27 raise util.Abort(_("invalid chunk length %d") % l)
29 raise util.Abort(_("invalid chunk length %d") % l)
28 return ""
30 return ""
29 return readexactly(stream, l - 4)
31 return readexactly(stream, l - 4)
30
32
31 def chunkheader(length):
33 def chunkheader(length):
32 """return a changegroup chunk header (string)"""
34 """return a changegroup chunk header (string)"""
33 return struct.pack(">l", length + 4)
35 return struct.pack(">l", length + 4)
34
36
35 def closechunk():
37 def closechunk():
36 """return a changegroup chunk header (string) for a zero-length chunk"""
38 """return a changegroup chunk header (string) for a zero-length chunk"""
37 return struct.pack(">l", 0)
39 return struct.pack(">l", 0)
38
40
39 class nocompress(object):
41 class nocompress(object):
40 def compress(self, x):
42 def compress(self, x):
41 return x
43 return x
42 def flush(self):
44 def flush(self):
43 return ""
45 return ""
44
46
45 bundletypes = {
47 bundletypes = {
46 "": ("", nocompress), # only when using unbundle on ssh and old http servers
48 "": ("", nocompress), # only when using unbundle on ssh and old http servers
47 # since the unification ssh accepts a header but there
49 # since the unification ssh accepts a header but there
48 # is no capability signaling it.
50 # is no capability signaling it.
49 "HG10UN": ("HG10UN", nocompress),
51 "HG10UN": ("HG10UN", nocompress),
50 "HG10BZ": ("HG10", lambda: bz2.BZ2Compressor()),
52 "HG10BZ": ("HG10", lambda: bz2.BZ2Compressor()),
51 "HG10GZ": ("HG10GZ", lambda: zlib.compressobj()),
53 "HG10GZ": ("HG10GZ", lambda: zlib.compressobj()),
52 }
54 }
53
55
54 # hgweb uses this list to communicate its preferred type
56 # hgweb uses this list to communicate its preferred type
55 bundlepriority = ['HG10GZ', 'HG10BZ', 'HG10UN']
57 bundlepriority = ['HG10GZ', 'HG10BZ', 'HG10UN']
56
58
57 def writebundle(cg, filename, bundletype):
59 def writebundle(cg, filename, bundletype):
58 """Write a bundle file and return its filename.
60 """Write a bundle file and return its filename.
59
61
60 Existing files will not be overwritten.
62 Existing files will not be overwritten.
61 If no filename is specified, a temporary file is created.
63 If no filename is specified, a temporary file is created.
62 bz2 compression can be turned off.
64 bz2 compression can be turned off.
63 The bundle file will be deleted in case of errors.
65 The bundle file will be deleted in case of errors.
64 """
66 """
65
67
66 fh = None
68 fh = None
67 cleanup = None
69 cleanup = None
68 try:
70 try:
69 if filename:
71 if filename:
70 fh = open(filename, "wb")
72 fh = open(filename, "wb")
71 else:
73 else:
72 fd, filename = tempfile.mkstemp(prefix="hg-bundle-", suffix=".hg")
74 fd, filename = tempfile.mkstemp(prefix="hg-bundle-", suffix=".hg")
73 fh = os.fdopen(fd, "wb")
75 fh = os.fdopen(fd, "wb")
74 cleanup = filename
76 cleanup = filename
75
77
76 header, compressor = bundletypes[bundletype]
78 header, compressor = bundletypes[bundletype]
77 fh.write(header)
79 fh.write(header)
78 z = compressor()
80 z = compressor()
79
81
80 # parse the changegroup data, otherwise we will block
82 # parse the changegroup data, otherwise we will block
81 # in case of sshrepo because we don't know the end of the stream
83 # in case of sshrepo because we don't know the end of the stream
82
84
83 # an empty chunkgroup is the end of the changegroup
85 # an empty chunkgroup is the end of the changegroup
84 # a changegroup has at least 2 chunkgroups (changelog and manifest).
86 # a changegroup has at least 2 chunkgroups (changelog and manifest).
85 # after that, an empty chunkgroup is the end of the changegroup
87 # after that, an empty chunkgroup is the end of the changegroup
86 empty = False
88 empty = False
87 count = 0
89 count = 0
88 while not empty or count <= 2:
90 while not empty or count <= 2:
89 empty = True
91 empty = True
90 count += 1
92 count += 1
91 while 1:
93 while 1:
92 chunk = getchunk(cg)
94 chunk = getchunk(cg)
93 if not chunk:
95 if not chunk:
94 break
96 break
95 empty = False
97 empty = False
96 fh.write(z.compress(chunkheader(len(chunk))))
98 fh.write(z.compress(chunkheader(len(chunk))))
97 pos = 0
99 pos = 0
98 while pos < len(chunk):
100 while pos < len(chunk):
99 next = pos + 2**20
101 next = pos + 2**20
100 fh.write(z.compress(chunk[pos:next]))
102 fh.write(z.compress(chunk[pos:next]))
101 pos = next
103 pos = next
102 fh.write(z.compress(closechunk()))
104 fh.write(z.compress(closechunk()))
103 fh.write(z.flush())
105 fh.write(z.flush())
104 cleanup = None
106 cleanup = None
105 return filename
107 return filename
106 finally:
108 finally:
107 if fh is not None:
109 if fh is not None:
108 fh.close()
110 fh.close()
109 if cleanup is not None:
111 if cleanup is not None:
110 os.unlink(cleanup)
112 os.unlink(cleanup)
111
113
112 def decompressor(fh, alg):
114 def decompressor(fh, alg):
113 if alg == 'UN':
115 if alg == 'UN':
114 return fh
116 return fh
115 elif alg == 'GZ':
117 elif alg == 'GZ':
116 def generator(f):
118 def generator(f):
117 zd = zlib.decompressobj()
119 zd = zlib.decompressobj()
118 for chunk in f:
120 for chunk in f:
119 yield zd.decompress(chunk)
121 yield zd.decompress(chunk)
120 elif alg == 'BZ':
122 elif alg == 'BZ':
121 def generator(f):
123 def generator(f):
122 zd = bz2.BZ2Decompressor()
124 zd = bz2.BZ2Decompressor()
123 zd.decompress("BZ")
125 zd.decompress("BZ")
124 for chunk in util.filechunkiter(f, 4096):
126 for chunk in util.filechunkiter(f, 4096):
125 yield zd.decompress(chunk)
127 yield zd.decompress(chunk)
126 else:
128 else:
127 raise util.Abort("unknown bundle compression '%s'" % alg)
129 raise util.Abort("unknown bundle compression '%s'" % alg)
128 return util.chunkbuffer(generator(fh))
130 return util.chunkbuffer(generator(fh))
129
131
130 class unbundle10(object):
132 class unbundle10(object):
133 deltaheader = _BUNDLE10_DELTA_HEADER
134 deltaheadersize = struct.calcsize(deltaheader)
131 def __init__(self, fh, alg):
135 def __init__(self, fh, alg):
132 self._stream = decompressor(fh, alg)
136 self._stream = decompressor(fh, alg)
133 self._type = alg
137 self._type = alg
134 self.callback = None
138 self.callback = None
135 def compressed(self):
139 def compressed(self):
136 return self._type != 'UN'
140 return self._type != 'UN'
137 def read(self, l):
141 def read(self, l):
138 return self._stream.read(l)
142 return self._stream.read(l)
139 def seek(self, pos):
143 def seek(self, pos):
140 return self._stream.seek(pos)
144 return self._stream.seek(pos)
141 def tell(self):
145 def tell(self):
142 return self._stream.tell()
146 return self._stream.tell()
143 def close(self):
147 def close(self):
144 return self._stream.close()
148 return self._stream.close()
145
149
146 def chunklength(self):
150 def chunklength(self):
147 d = readexactly(self._stream, 4)
151 d = readexactly(self._stream, 4)
148 l = struct.unpack(">l", d)[0]
152 l = struct.unpack(">l", d)[0]
149 if l <= 4:
153 if l <= 4:
150 if l:
154 if l:
151 raise util.Abort(_("invalid chunk length %d") % l)
155 raise util.Abort(_("invalid chunk length %d") % l)
152 return 0
156 return 0
153 if self.callback:
157 if self.callback:
154 self.callback()
158 self.callback()
155 return l - 4
159 return l - 4
156
160
157 def chunk(self):
161 def chunk(self):
158 """return the next chunk from changegroup 'source' as a string"""
162 """return the next chunk from changegroup 'source' as a string"""
159 l = self.chunklength()
163 l = self.chunklength()
160 return readexactly(self._stream, l)
164 return readexactly(self._stream, l)
161
165
162 def parsechunk(self):
166 def _deltaheader(self, headertuple, prevnode):
167 node, p1, p2, cs = headertuple
168 if prevnode is None:
169 deltabase = p1
170 else:
171 deltabase = prevnode
172 return node, p1, p2, deltabase, cs
173
174 def parsechunk(self, prevnode):
163 l = self.chunklength()
175 l = self.chunklength()
164 if not l:
176 if not l:
165 return {}
177 return {}
166 h = readexactly(self._stream, 80)
178 headerdata = readexactly(self._stream, self.deltaheadersize)
167 node, p1, p2, cs = struct.unpack("20s20s20s20s", h)
179 header = struct.unpack(self.deltaheader, headerdata)
168 data = readexactly(self._stream, l - 80)
180 delta = readexactly(self._stream, l - self.deltaheadersize)
169 return dict(node=node, p1=p1, p2=p2, cs=cs, data=data)
181 node, p1, p2, deltabase, cs = self._deltaheader(header, prevnode)
182 return dict(node=node, p1=p1, p2=p2, cs=cs,
183 deltabase=deltabase, delta=delta)
170
184
171 class headerlessfixup(object):
185 class headerlessfixup(object):
172 def __init__(self, fh, h):
186 def __init__(self, fh, h):
173 self._h = h
187 self._h = h
174 self._fh = fh
188 self._fh = fh
175 def read(self, n):
189 def read(self, n):
176 if self._h:
190 if self._h:
177 d, self._h = self._h[:n], self._h[n:]
191 d, self._h = self._h[:n], self._h[n:]
178 if len(d) < n:
192 if len(d) < n:
179 d += readexactly(self._fh, n - len(d))
193 d += readexactly(self._fh, n - len(d))
180 return d
194 return d
181 return readexactly(self._fh, n)
195 return readexactly(self._fh, n)
182
196
183 def readbundle(fh, fname):
197 def readbundle(fh, fname):
184 header = readexactly(fh, 6)
198 header = readexactly(fh, 6)
185
199
186 if not fname:
200 if not fname:
187 fname = "stream"
201 fname = "stream"
188 if not header.startswith('HG') and header.startswith('\0'):
202 if not header.startswith('HG') and header.startswith('\0'):
189 fh = headerlessfixup(fh, header)
203 fh = headerlessfixup(fh, header)
190 header = "HG10UN"
204 header = "HG10UN"
191
205
192 magic, version, alg = header[0:2], header[2:4], header[4:6]
206 magic, version, alg = header[0:2], header[2:4], header[4:6]
193
207
194 if magic != 'HG':
208 if magic != 'HG':
195 raise util.Abort(_('%s: not a Mercurial bundle') % fname)
209 raise util.Abort(_('%s: not a Mercurial bundle') % fname)
196 if version != '10':
210 if version != '10':
197 raise util.Abort(_('%s: unknown bundle version %s') % (fname, version))
211 raise util.Abort(_('%s: unknown bundle version %s') % (fname, version))
198 return unbundle10(fh, alg)
212 return unbundle10(fh, alg)
199
213
200 class bundle10(object):
214 class bundle10(object):
201 def __init__(self, lookup):
215 def __init__(self, lookup):
202 self._lookup = lookup
216 self._lookup = lookup
203 def close(self):
217 def close(self):
204 return closechunk()
218 return closechunk()
205 def fileheader(self, fname):
219 def fileheader(self, fname):
206 return chunkheader(len(fname)) + fname
220 return chunkheader(len(fname)) + fname
207 def revchunk(self, revlog, node='', p1='', p2='', prefix='', data=''):
221 def revchunk(self, revlog, node='', p1='', p2='', prefix='', data=''):
208 linknode = self._lookup(revlog, node)
222 linknode = self._lookup(revlog, node)
209 meta = node + p1 + p2 + linknode + prefix
223 meta = node + p1 + p2 + linknode + prefix
210 l = len(meta) + len(data)
224 l = len(meta) + len(data)
211 yield chunkheader(l)
225 yield chunkheader(l)
212 yield meta
226 yield meta
213 yield data
227 yield data
@@ -1,4875 +1,4880 b''
1 # commands.py - command processing for mercurial
1 # commands.py - command processing for mercurial
2 #
2 #
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 from node import hex, bin, nullid, nullrev, short
8 from node import hex, bin, nullid, nullrev, short
9 from lock import release
9 from lock import release
10 from i18n import _, gettext
10 from i18n import _, gettext
11 import os, re, sys, difflib, time, tempfile
11 import os, re, sys, difflib, time, tempfile
12 import hg, scmutil, util, revlog, extensions, copies, error, bookmarks
12 import hg, scmutil, util, revlog, extensions, copies, error, bookmarks
13 import patch, help, url, encoding, templatekw, discovery
13 import patch, help, url, encoding, templatekw, discovery
14 import archival, changegroup, cmdutil, sshserver, hbisect, hgweb, hgweb.server
14 import archival, changegroup, cmdutil, sshserver, hbisect, hgweb, hgweb.server
15 import merge as mergemod
15 import merge as mergemod
16 import minirst, revset, templatefilters
16 import minirst, revset, templatefilters
17 import dagparser
17 import dagparser
18
18
19 # Commands start here, listed alphabetically
19 # Commands start here, listed alphabetically
20
20
21 def add(ui, repo, *pats, **opts):
21 def add(ui, repo, *pats, **opts):
22 """add the specified files on the next commit
22 """add the specified files on the next commit
23
23
24 Schedule files to be version controlled and added to the
24 Schedule files to be version controlled and added to the
25 repository.
25 repository.
26
26
27 The files will be added to the repository at the next commit. To
27 The files will be added to the repository at the next commit. To
28 undo an add before that, see :hg:`forget`.
28 undo an add before that, see :hg:`forget`.
29
29
30 If no names are given, add all files to the repository.
30 If no names are given, add all files to the repository.
31
31
32 .. container:: verbose
32 .. container:: verbose
33
33
34 An example showing how new (unknown) files are added
34 An example showing how new (unknown) files are added
35 automatically by :hg:`add`::
35 automatically by :hg:`add`::
36
36
37 $ ls
37 $ ls
38 foo.c
38 foo.c
39 $ hg status
39 $ hg status
40 ? foo.c
40 ? foo.c
41 $ hg add
41 $ hg add
42 adding foo.c
42 adding foo.c
43 $ hg status
43 $ hg status
44 A foo.c
44 A foo.c
45
45
46 Returns 0 if all files are successfully added.
46 Returns 0 if all files are successfully added.
47 """
47 """
48
48
49 m = cmdutil.match(repo, pats, opts)
49 m = cmdutil.match(repo, pats, opts)
50 rejected = cmdutil.add(ui, repo, m, opts.get('dry_run'),
50 rejected = cmdutil.add(ui, repo, m, opts.get('dry_run'),
51 opts.get('subrepos'), prefix="")
51 opts.get('subrepos'), prefix="")
52 return rejected and 1 or 0
52 return rejected and 1 or 0
53
53
54 def addremove(ui, repo, *pats, **opts):
54 def addremove(ui, repo, *pats, **opts):
55 """add all new files, delete all missing files
55 """add all new files, delete all missing files
56
56
57 Add all new files and remove all missing files from the
57 Add all new files and remove all missing files from the
58 repository.
58 repository.
59
59
60 New files are ignored if they match any of the patterns in
60 New files are ignored if they match any of the patterns in
61 ``.hgignore``. As with add, these changes take effect at the next
61 ``.hgignore``. As with add, these changes take effect at the next
62 commit.
62 commit.
63
63
64 Use the -s/--similarity option to detect renamed files. With a
64 Use the -s/--similarity option to detect renamed files. With a
65 parameter greater than 0, this compares every removed file with
65 parameter greater than 0, this compares every removed file with
66 every added file and records those similar enough as renames. This
66 every added file and records those similar enough as renames. This
67 option takes a percentage between 0 (disabled) and 100 (files must
67 option takes a percentage between 0 (disabled) and 100 (files must
68 be identical) as its parameter. Detecting renamed files this way
68 be identical) as its parameter. Detecting renamed files this way
69 can be expensive. After using this option, :hg:`status -C` can be
69 can be expensive. After using this option, :hg:`status -C` can be
70 used to check which files were identified as moved or renamed.
70 used to check which files were identified as moved or renamed.
71
71
72 Returns 0 if all files are successfully added.
72 Returns 0 if all files are successfully added.
73 """
73 """
74 try:
74 try:
75 sim = float(opts.get('similarity') or 100)
75 sim = float(opts.get('similarity') or 100)
76 except ValueError:
76 except ValueError:
77 raise util.Abort(_('similarity must be a number'))
77 raise util.Abort(_('similarity must be a number'))
78 if sim < 0 or sim > 100:
78 if sim < 0 or sim > 100:
79 raise util.Abort(_('similarity must be between 0 and 100'))
79 raise util.Abort(_('similarity must be between 0 and 100'))
80 return cmdutil.addremove(repo, pats, opts, similarity=sim / 100.0)
80 return cmdutil.addremove(repo, pats, opts, similarity=sim / 100.0)
81
81
82 def annotate(ui, repo, *pats, **opts):
82 def annotate(ui, repo, *pats, **opts):
83 """show changeset information by line for each file
83 """show changeset information by line for each file
84
84
85 List changes in files, showing the revision id responsible for
85 List changes in files, showing the revision id responsible for
86 each line
86 each line
87
87
88 This command is useful for discovering when a change was made and
88 This command is useful for discovering when a change was made and
89 by whom.
89 by whom.
90
90
91 Without the -a/--text option, annotate will avoid processing files
91 Without the -a/--text option, annotate will avoid processing files
92 it detects as binary. With -a, annotate will annotate the file
92 it detects as binary. With -a, annotate will annotate the file
93 anyway, although the results will probably be neither useful
93 anyway, although the results will probably be neither useful
94 nor desirable.
94 nor desirable.
95
95
96 Returns 0 on success.
96 Returns 0 on success.
97 """
97 """
98 if opts.get('follow'):
98 if opts.get('follow'):
99 # --follow is deprecated and now just an alias for -f/--file
99 # --follow is deprecated and now just an alias for -f/--file
100 # to mimic the behavior of Mercurial before version 1.5
100 # to mimic the behavior of Mercurial before version 1.5
101 opts['file'] = 1
101 opts['file'] = 1
102
102
103 datefunc = ui.quiet and util.shortdate or util.datestr
103 datefunc = ui.quiet and util.shortdate or util.datestr
104 getdate = util.cachefunc(lambda x: datefunc(x[0].date()))
104 getdate = util.cachefunc(lambda x: datefunc(x[0].date()))
105
105
106 if not pats:
106 if not pats:
107 raise util.Abort(_('at least one filename or pattern is required'))
107 raise util.Abort(_('at least one filename or pattern is required'))
108
108
109 opmap = [('user', lambda x: ui.shortuser(x[0].user())),
109 opmap = [('user', lambda x: ui.shortuser(x[0].user())),
110 ('number', lambda x: str(x[0].rev())),
110 ('number', lambda x: str(x[0].rev())),
111 ('changeset', lambda x: short(x[0].node())),
111 ('changeset', lambda x: short(x[0].node())),
112 ('date', getdate),
112 ('date', getdate),
113 ('file', lambda x: x[0].path()),
113 ('file', lambda x: x[0].path()),
114 ]
114 ]
115
115
116 if (not opts.get('user') and not opts.get('changeset')
116 if (not opts.get('user') and not opts.get('changeset')
117 and not opts.get('date') and not opts.get('file')):
117 and not opts.get('date') and not opts.get('file')):
118 opts['number'] = 1
118 opts['number'] = 1
119
119
120 linenumber = opts.get('line_number') is not None
120 linenumber = opts.get('line_number') is not None
121 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
121 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
122 raise util.Abort(_('at least one of -n/-c is required for -l'))
122 raise util.Abort(_('at least one of -n/-c is required for -l'))
123
123
124 funcmap = [func for op, func in opmap if opts.get(op)]
124 funcmap = [func for op, func in opmap if opts.get(op)]
125 if linenumber:
125 if linenumber:
126 lastfunc = funcmap[-1]
126 lastfunc = funcmap[-1]
127 funcmap[-1] = lambda x: "%s:%s" % (lastfunc(x), x[1])
127 funcmap[-1] = lambda x: "%s:%s" % (lastfunc(x), x[1])
128
128
129 def bad(x, y):
129 def bad(x, y):
130 raise util.Abort("%s: %s" % (x, y))
130 raise util.Abort("%s: %s" % (x, y))
131
131
132 ctx = cmdutil.revsingle(repo, opts.get('rev'))
132 ctx = cmdutil.revsingle(repo, opts.get('rev'))
133 m = cmdutil.match(repo, pats, opts)
133 m = cmdutil.match(repo, pats, opts)
134 m.bad = bad
134 m.bad = bad
135 follow = not opts.get('no_follow')
135 follow = not opts.get('no_follow')
136 for abs in ctx.walk(m):
136 for abs in ctx.walk(m):
137 fctx = ctx[abs]
137 fctx = ctx[abs]
138 if not opts.get('text') and util.binary(fctx.data()):
138 if not opts.get('text') and util.binary(fctx.data()):
139 ui.write(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs))
139 ui.write(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs))
140 continue
140 continue
141
141
142 lines = fctx.annotate(follow=follow, linenumber=linenumber)
142 lines = fctx.annotate(follow=follow, linenumber=linenumber)
143 pieces = []
143 pieces = []
144
144
145 for f in funcmap:
145 for f in funcmap:
146 l = [f(n) for n, dummy in lines]
146 l = [f(n) for n, dummy in lines]
147 if l:
147 if l:
148 sized = [(x, encoding.colwidth(x)) for x in l]
148 sized = [(x, encoding.colwidth(x)) for x in l]
149 ml = max([w for x, w in sized])
149 ml = max([w for x, w in sized])
150 pieces.append(["%s%s" % (' ' * (ml - w), x) for x, w in sized])
150 pieces.append(["%s%s" % (' ' * (ml - w), x) for x, w in sized])
151
151
152 if pieces:
152 if pieces:
153 for p, l in zip(zip(*pieces), lines):
153 for p, l in zip(zip(*pieces), lines):
154 ui.write("%s: %s" % (" ".join(p), l[1]))
154 ui.write("%s: %s" % (" ".join(p), l[1]))
155
155
156 def archive(ui, repo, dest, **opts):
156 def archive(ui, repo, dest, **opts):
157 '''create an unversioned archive of a repository revision
157 '''create an unversioned archive of a repository revision
158
158
159 By default, the revision used is the parent of the working
159 By default, the revision used is the parent of the working
160 directory; use -r/--rev to specify a different revision.
160 directory; use -r/--rev to specify a different revision.
161
161
162 The archive type is automatically detected based on file
162 The archive type is automatically detected based on file
163 extension (or override using -t/--type).
163 extension (or override using -t/--type).
164
164
165 Valid types are:
165 Valid types are:
166
166
167 :``files``: a directory full of files (default)
167 :``files``: a directory full of files (default)
168 :``tar``: tar archive, uncompressed
168 :``tar``: tar archive, uncompressed
169 :``tbz2``: tar archive, compressed using bzip2
169 :``tbz2``: tar archive, compressed using bzip2
170 :``tgz``: tar archive, compressed using gzip
170 :``tgz``: tar archive, compressed using gzip
171 :``uzip``: zip archive, uncompressed
171 :``uzip``: zip archive, uncompressed
172 :``zip``: zip archive, compressed using deflate
172 :``zip``: zip archive, compressed using deflate
173
173
174 The exact name of the destination archive or directory is given
174 The exact name of the destination archive or directory is given
175 using a format string; see :hg:`help export` for details.
175 using a format string; see :hg:`help export` for details.
176
176
177 Each member added to an archive file has a directory prefix
177 Each member added to an archive file has a directory prefix
178 prepended. Use -p/--prefix to specify a format string for the
178 prepended. Use -p/--prefix to specify a format string for the
179 prefix. The default is the basename of the archive, with suffixes
179 prefix. The default is the basename of the archive, with suffixes
180 removed.
180 removed.
181
181
182 Returns 0 on success.
182 Returns 0 on success.
183 '''
183 '''
184
184
185 ctx = cmdutil.revsingle(repo, opts.get('rev'))
185 ctx = cmdutil.revsingle(repo, opts.get('rev'))
186 if not ctx:
186 if not ctx:
187 raise util.Abort(_('no working directory: please specify a revision'))
187 raise util.Abort(_('no working directory: please specify a revision'))
188 node = ctx.node()
188 node = ctx.node()
189 dest = cmdutil.make_filename(repo, dest, node)
189 dest = cmdutil.make_filename(repo, dest, node)
190 if os.path.realpath(dest) == repo.root:
190 if os.path.realpath(dest) == repo.root:
191 raise util.Abort(_('repository root cannot be destination'))
191 raise util.Abort(_('repository root cannot be destination'))
192
192
193 kind = opts.get('type') or archival.guesskind(dest) or 'files'
193 kind = opts.get('type') or archival.guesskind(dest) or 'files'
194 prefix = opts.get('prefix')
194 prefix = opts.get('prefix')
195
195
196 if dest == '-':
196 if dest == '-':
197 if kind == 'files':
197 if kind == 'files':
198 raise util.Abort(_('cannot archive plain files to stdout'))
198 raise util.Abort(_('cannot archive plain files to stdout'))
199 dest = sys.stdout
199 dest = sys.stdout
200 if not prefix:
200 if not prefix:
201 prefix = os.path.basename(repo.root) + '-%h'
201 prefix = os.path.basename(repo.root) + '-%h'
202
202
203 prefix = cmdutil.make_filename(repo, prefix, node)
203 prefix = cmdutil.make_filename(repo, prefix, node)
204 matchfn = cmdutil.match(repo, [], opts)
204 matchfn = cmdutil.match(repo, [], opts)
205 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
205 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
206 matchfn, prefix, subrepos=opts.get('subrepos'))
206 matchfn, prefix, subrepos=opts.get('subrepos'))
207
207
208 def backout(ui, repo, node=None, rev=None, **opts):
208 def backout(ui, repo, node=None, rev=None, **opts):
209 '''reverse effect of earlier changeset
209 '''reverse effect of earlier changeset
210
210
211 Prepare a new changeset with the effect of REV undone in the
211 Prepare a new changeset with the effect of REV undone in the
212 current working directory.
212 current working directory.
213
213
214 If REV is the parent of the working directory, then this new changeset
214 If REV is the parent of the working directory, then this new changeset
215 is committed automatically. Otherwise, hg needs to merge the
215 is committed automatically. Otherwise, hg needs to merge the
216 changes and the merged result is left uncommitted.
216 changes and the merged result is left uncommitted.
217
217
218 By default, the pending changeset will have one parent,
218 By default, the pending changeset will have one parent,
219 maintaining a linear history. With --merge, the pending changeset
219 maintaining a linear history. With --merge, the pending changeset
220 will instead have two parents: the old parent of the working
220 will instead have two parents: the old parent of the working
221 directory and a new child of REV that simply undoes REV.
221 directory and a new child of REV that simply undoes REV.
222
222
223 Before version 1.7, the behavior without --merge was equivalent to
223 Before version 1.7, the behavior without --merge was equivalent to
224 specifying --merge followed by :hg:`update --clean .` to cancel
224 specifying --merge followed by :hg:`update --clean .` to cancel
225 the merge and leave the child of REV as a head to be merged
225 the merge and leave the child of REV as a head to be merged
226 separately.
226 separately.
227
227
228 See :hg:`help dates` for a list of formats valid for -d/--date.
228 See :hg:`help dates` for a list of formats valid for -d/--date.
229
229
230 Returns 0 on success.
230 Returns 0 on success.
231 '''
231 '''
232 if rev and node:
232 if rev and node:
233 raise util.Abort(_("please specify just one revision"))
233 raise util.Abort(_("please specify just one revision"))
234
234
235 if not rev:
235 if not rev:
236 rev = node
236 rev = node
237
237
238 if not rev:
238 if not rev:
239 raise util.Abort(_("please specify a revision to backout"))
239 raise util.Abort(_("please specify a revision to backout"))
240
240
241 date = opts.get('date')
241 date = opts.get('date')
242 if date:
242 if date:
243 opts['date'] = util.parsedate(date)
243 opts['date'] = util.parsedate(date)
244
244
245 cmdutil.bail_if_changed(repo)
245 cmdutil.bail_if_changed(repo)
246 node = cmdutil.revsingle(repo, rev).node()
246 node = cmdutil.revsingle(repo, rev).node()
247
247
248 op1, op2 = repo.dirstate.parents()
248 op1, op2 = repo.dirstate.parents()
249 a = repo.changelog.ancestor(op1, node)
249 a = repo.changelog.ancestor(op1, node)
250 if a != node:
250 if a != node:
251 raise util.Abort(_('cannot backout change on a different branch'))
251 raise util.Abort(_('cannot backout change on a different branch'))
252
252
253 p1, p2 = repo.changelog.parents(node)
253 p1, p2 = repo.changelog.parents(node)
254 if p1 == nullid:
254 if p1 == nullid:
255 raise util.Abort(_('cannot backout a change with no parents'))
255 raise util.Abort(_('cannot backout a change with no parents'))
256 if p2 != nullid:
256 if p2 != nullid:
257 if not opts.get('parent'):
257 if not opts.get('parent'):
258 raise util.Abort(_('cannot backout a merge changeset without '
258 raise util.Abort(_('cannot backout a merge changeset without '
259 '--parent'))
259 '--parent'))
260 p = repo.lookup(opts['parent'])
260 p = repo.lookup(opts['parent'])
261 if p not in (p1, p2):
261 if p not in (p1, p2):
262 raise util.Abort(_('%s is not a parent of %s') %
262 raise util.Abort(_('%s is not a parent of %s') %
263 (short(p), short(node)))
263 (short(p), short(node)))
264 parent = p
264 parent = p
265 else:
265 else:
266 if opts.get('parent'):
266 if opts.get('parent'):
267 raise util.Abort(_('cannot use --parent on non-merge changeset'))
267 raise util.Abort(_('cannot use --parent on non-merge changeset'))
268 parent = p1
268 parent = p1
269
269
270 # the backout should appear on the same branch
270 # the backout should appear on the same branch
271 branch = repo.dirstate.branch()
271 branch = repo.dirstate.branch()
272 hg.clean(repo, node, show_stats=False)
272 hg.clean(repo, node, show_stats=False)
273 repo.dirstate.setbranch(branch)
273 repo.dirstate.setbranch(branch)
274 revert_opts = opts.copy()
274 revert_opts = opts.copy()
275 revert_opts['date'] = None
275 revert_opts['date'] = None
276 revert_opts['all'] = True
276 revert_opts['all'] = True
277 revert_opts['rev'] = hex(parent)
277 revert_opts['rev'] = hex(parent)
278 revert_opts['no_backup'] = None
278 revert_opts['no_backup'] = None
279 revert(ui, repo, **revert_opts)
279 revert(ui, repo, **revert_opts)
280 if not opts.get('merge') and op1 != node:
280 if not opts.get('merge') and op1 != node:
281 try:
281 try:
282 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
282 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
283 return hg.update(repo, op1)
283 return hg.update(repo, op1)
284 finally:
284 finally:
285 ui.setconfig('ui', 'forcemerge', '')
285 ui.setconfig('ui', 'forcemerge', '')
286
286
287 commit_opts = opts.copy()
287 commit_opts = opts.copy()
288 commit_opts['addremove'] = False
288 commit_opts['addremove'] = False
289 if not commit_opts['message'] and not commit_opts['logfile']:
289 if not commit_opts['message'] and not commit_opts['logfile']:
290 # we don't translate commit messages
290 # we don't translate commit messages
291 commit_opts['message'] = "Backed out changeset %s" % short(node)
291 commit_opts['message'] = "Backed out changeset %s" % short(node)
292 commit_opts['force_editor'] = True
292 commit_opts['force_editor'] = True
293 commit(ui, repo, **commit_opts)
293 commit(ui, repo, **commit_opts)
294 def nice(node):
294 def nice(node):
295 return '%d:%s' % (repo.changelog.rev(node), short(node))
295 return '%d:%s' % (repo.changelog.rev(node), short(node))
296 ui.status(_('changeset %s backs out changeset %s\n') %
296 ui.status(_('changeset %s backs out changeset %s\n') %
297 (nice(repo.changelog.tip()), nice(node)))
297 (nice(repo.changelog.tip()), nice(node)))
298 if opts.get('merge') and op1 != node:
298 if opts.get('merge') and op1 != node:
299 hg.clean(repo, op1, show_stats=False)
299 hg.clean(repo, op1, show_stats=False)
300 ui.status(_('merging with changeset %s\n')
300 ui.status(_('merging with changeset %s\n')
301 % nice(repo.changelog.tip()))
301 % nice(repo.changelog.tip()))
302 try:
302 try:
303 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
303 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
304 return hg.merge(repo, hex(repo.changelog.tip()))
304 return hg.merge(repo, hex(repo.changelog.tip()))
305 finally:
305 finally:
306 ui.setconfig('ui', 'forcemerge', '')
306 ui.setconfig('ui', 'forcemerge', '')
307 return 0
307 return 0
308
308
309 def bisect(ui, repo, rev=None, extra=None, command=None,
309 def bisect(ui, repo, rev=None, extra=None, command=None,
310 reset=None, good=None, bad=None, skip=None, extend=None,
310 reset=None, good=None, bad=None, skip=None, extend=None,
311 noupdate=None):
311 noupdate=None):
312 """subdivision search of changesets
312 """subdivision search of changesets
313
313
314 This command helps to find changesets which introduce problems. To
314 This command helps to find changesets which introduce problems. To
315 use, mark the earliest changeset you know exhibits the problem as
315 use, mark the earliest changeset you know exhibits the problem as
316 bad, then mark the latest changeset which is free from the problem
316 bad, then mark the latest changeset which is free from the problem
317 as good. Bisect will update your working directory to a revision
317 as good. Bisect will update your working directory to a revision
318 for testing (unless the -U/--noupdate option is specified). Once
318 for testing (unless the -U/--noupdate option is specified). Once
319 you have performed tests, mark the working directory as good or
319 you have performed tests, mark the working directory as good or
320 bad, and bisect will either update to another candidate changeset
320 bad, and bisect will either update to another candidate changeset
321 or announce that it has found the bad revision.
321 or announce that it has found the bad revision.
322
322
323 As a shortcut, you can also use the revision argument to mark a
323 As a shortcut, you can also use the revision argument to mark a
324 revision as good or bad without checking it out first.
324 revision as good or bad without checking it out first.
325
325
326 If you supply a command, it will be used for automatic bisection.
326 If you supply a command, it will be used for automatic bisection.
327 Its exit status will be used to mark revisions as good or bad:
327 Its exit status will be used to mark revisions as good or bad:
328 status 0 means good, 125 means to skip the revision, 127
328 status 0 means good, 125 means to skip the revision, 127
329 (command not found) will abort the bisection, and any other
329 (command not found) will abort the bisection, and any other
330 non-zero exit status means the revision is bad.
330 non-zero exit status means the revision is bad.
331
331
332 Returns 0 on success.
332 Returns 0 on success.
333 """
333 """
334 def extendbisectrange(nodes, good):
334 def extendbisectrange(nodes, good):
335 # bisect is incomplete when it ends on a merge node and
335 # bisect is incomplete when it ends on a merge node and
336 # one of the parent was not checked.
336 # one of the parent was not checked.
337 parents = repo[nodes[0]].parents()
337 parents = repo[nodes[0]].parents()
338 if len(parents) > 1:
338 if len(parents) > 1:
339 side = good and state['bad'] or state['good']
339 side = good and state['bad'] or state['good']
340 num = len(set(i.node() for i in parents) & set(side))
340 num = len(set(i.node() for i in parents) & set(side))
341 if num == 1:
341 if num == 1:
342 return parents[0].ancestor(parents[1])
342 return parents[0].ancestor(parents[1])
343 return None
343 return None
344
344
345 def print_result(nodes, good):
345 def print_result(nodes, good):
346 displayer = cmdutil.show_changeset(ui, repo, {})
346 displayer = cmdutil.show_changeset(ui, repo, {})
347 if len(nodes) == 1:
347 if len(nodes) == 1:
348 # narrowed it down to a single revision
348 # narrowed it down to a single revision
349 if good:
349 if good:
350 ui.write(_("The first good revision is:\n"))
350 ui.write(_("The first good revision is:\n"))
351 else:
351 else:
352 ui.write(_("The first bad revision is:\n"))
352 ui.write(_("The first bad revision is:\n"))
353 displayer.show(repo[nodes[0]])
353 displayer.show(repo[nodes[0]])
354 extendnode = extendbisectrange(nodes, good)
354 extendnode = extendbisectrange(nodes, good)
355 if extendnode is not None:
355 if extendnode is not None:
356 ui.write(_('Not all ancestors of this changeset have been'
356 ui.write(_('Not all ancestors of this changeset have been'
357 ' checked.\nUse bisect --extend to continue the '
357 ' checked.\nUse bisect --extend to continue the '
358 'bisection from\nthe common ancestor, %s.\n')
358 'bisection from\nthe common ancestor, %s.\n')
359 % extendnode)
359 % extendnode)
360 else:
360 else:
361 # multiple possible revisions
361 # multiple possible revisions
362 if good:
362 if good:
363 ui.write(_("Due to skipped revisions, the first "
363 ui.write(_("Due to skipped revisions, the first "
364 "good revision could be any of:\n"))
364 "good revision could be any of:\n"))
365 else:
365 else:
366 ui.write(_("Due to skipped revisions, the first "
366 ui.write(_("Due to skipped revisions, the first "
367 "bad revision could be any of:\n"))
367 "bad revision could be any of:\n"))
368 for n in nodes:
368 for n in nodes:
369 displayer.show(repo[n])
369 displayer.show(repo[n])
370 displayer.close()
370 displayer.close()
371
371
372 def check_state(state, interactive=True):
372 def check_state(state, interactive=True):
373 if not state['good'] or not state['bad']:
373 if not state['good'] or not state['bad']:
374 if (good or bad or skip or reset) and interactive:
374 if (good or bad or skip or reset) and interactive:
375 return
375 return
376 if not state['good']:
376 if not state['good']:
377 raise util.Abort(_('cannot bisect (no known good revisions)'))
377 raise util.Abort(_('cannot bisect (no known good revisions)'))
378 else:
378 else:
379 raise util.Abort(_('cannot bisect (no known bad revisions)'))
379 raise util.Abort(_('cannot bisect (no known bad revisions)'))
380 return True
380 return True
381
381
382 # backward compatibility
382 # backward compatibility
383 if rev in "good bad reset init".split():
383 if rev in "good bad reset init".split():
384 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
384 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
385 cmd, rev, extra = rev, extra, None
385 cmd, rev, extra = rev, extra, None
386 if cmd == "good":
386 if cmd == "good":
387 good = True
387 good = True
388 elif cmd == "bad":
388 elif cmd == "bad":
389 bad = True
389 bad = True
390 else:
390 else:
391 reset = True
391 reset = True
392 elif extra or good + bad + skip + reset + extend + bool(command) > 1:
392 elif extra or good + bad + skip + reset + extend + bool(command) > 1:
393 raise util.Abort(_('incompatible arguments'))
393 raise util.Abort(_('incompatible arguments'))
394
394
395 if reset:
395 if reset:
396 p = repo.join("bisect.state")
396 p = repo.join("bisect.state")
397 if os.path.exists(p):
397 if os.path.exists(p):
398 os.unlink(p)
398 os.unlink(p)
399 return
399 return
400
400
401 state = hbisect.load_state(repo)
401 state = hbisect.load_state(repo)
402
402
403 if command:
403 if command:
404 changesets = 1
404 changesets = 1
405 try:
405 try:
406 while changesets:
406 while changesets:
407 # update state
407 # update state
408 status = util.system(command)
408 status = util.system(command)
409 if status == 125:
409 if status == 125:
410 transition = "skip"
410 transition = "skip"
411 elif status == 0:
411 elif status == 0:
412 transition = "good"
412 transition = "good"
413 # status < 0 means process was killed
413 # status < 0 means process was killed
414 elif status == 127:
414 elif status == 127:
415 raise util.Abort(_("failed to execute %s") % command)
415 raise util.Abort(_("failed to execute %s") % command)
416 elif status < 0:
416 elif status < 0:
417 raise util.Abort(_("%s killed") % command)
417 raise util.Abort(_("%s killed") % command)
418 else:
418 else:
419 transition = "bad"
419 transition = "bad"
420 ctx = cmdutil.revsingle(repo, rev)
420 ctx = cmdutil.revsingle(repo, rev)
421 rev = None # clear for future iterations
421 rev = None # clear for future iterations
422 state[transition].append(ctx.node())
422 state[transition].append(ctx.node())
423 ui.status(_('Changeset %d:%s: %s\n') % (ctx, ctx, transition))
423 ui.status(_('Changeset %d:%s: %s\n') % (ctx, ctx, transition))
424 check_state(state, interactive=False)
424 check_state(state, interactive=False)
425 # bisect
425 # bisect
426 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
426 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
427 # update to next check
427 # update to next check
428 cmdutil.bail_if_changed(repo)
428 cmdutil.bail_if_changed(repo)
429 hg.clean(repo, nodes[0], show_stats=False)
429 hg.clean(repo, nodes[0], show_stats=False)
430 finally:
430 finally:
431 hbisect.save_state(repo, state)
431 hbisect.save_state(repo, state)
432 print_result(nodes, good)
432 print_result(nodes, good)
433 return
433 return
434
434
435 # update state
435 # update state
436
436
437 if rev:
437 if rev:
438 nodes = [repo.lookup(i) for i in cmdutil.revrange(repo, [rev])]
438 nodes = [repo.lookup(i) for i in cmdutil.revrange(repo, [rev])]
439 else:
439 else:
440 nodes = [repo.lookup('.')]
440 nodes = [repo.lookup('.')]
441
441
442 if good or bad or skip:
442 if good or bad or skip:
443 if good:
443 if good:
444 state['good'] += nodes
444 state['good'] += nodes
445 elif bad:
445 elif bad:
446 state['bad'] += nodes
446 state['bad'] += nodes
447 elif skip:
447 elif skip:
448 state['skip'] += nodes
448 state['skip'] += nodes
449 hbisect.save_state(repo, state)
449 hbisect.save_state(repo, state)
450
450
451 if not check_state(state):
451 if not check_state(state):
452 return
452 return
453
453
454 # actually bisect
454 # actually bisect
455 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
455 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
456 if extend:
456 if extend:
457 if not changesets:
457 if not changesets:
458 extendnode = extendbisectrange(nodes, good)
458 extendnode = extendbisectrange(nodes, good)
459 if extendnode is not None:
459 if extendnode is not None:
460 ui.write(_("Extending search to changeset %d:%s\n"
460 ui.write(_("Extending search to changeset %d:%s\n"
461 % (extendnode.rev(), extendnode)))
461 % (extendnode.rev(), extendnode)))
462 if noupdate:
462 if noupdate:
463 return
463 return
464 cmdutil.bail_if_changed(repo)
464 cmdutil.bail_if_changed(repo)
465 return hg.clean(repo, extendnode.node())
465 return hg.clean(repo, extendnode.node())
466 raise util.Abort(_("nothing to extend"))
466 raise util.Abort(_("nothing to extend"))
467
467
468 if changesets == 0:
468 if changesets == 0:
469 print_result(nodes, good)
469 print_result(nodes, good)
470 else:
470 else:
471 assert len(nodes) == 1 # only a single node can be tested next
471 assert len(nodes) == 1 # only a single node can be tested next
472 node = nodes[0]
472 node = nodes[0]
473 # compute the approximate number of remaining tests
473 # compute the approximate number of remaining tests
474 tests, size = 0, 2
474 tests, size = 0, 2
475 while size <= changesets:
475 while size <= changesets:
476 tests, size = tests + 1, size * 2
476 tests, size = tests + 1, size * 2
477 rev = repo.changelog.rev(node)
477 rev = repo.changelog.rev(node)
478 ui.write(_("Testing changeset %d:%s "
478 ui.write(_("Testing changeset %d:%s "
479 "(%d changesets remaining, ~%d tests)\n")
479 "(%d changesets remaining, ~%d tests)\n")
480 % (rev, short(node), changesets, tests))
480 % (rev, short(node), changesets, tests))
481 if not noupdate:
481 if not noupdate:
482 cmdutil.bail_if_changed(repo)
482 cmdutil.bail_if_changed(repo)
483 return hg.clean(repo, node)
483 return hg.clean(repo, node)
484
484
485 def bookmark(ui, repo, mark=None, rev=None, force=False, delete=False, rename=None):
485 def bookmark(ui, repo, mark=None, rev=None, force=False, delete=False, rename=None):
486 '''track a line of development with movable markers
486 '''track a line of development with movable markers
487
487
488 Bookmarks are pointers to certain commits that move when
488 Bookmarks are pointers to certain commits that move when
489 committing. Bookmarks are local. They can be renamed, copied and
489 committing. Bookmarks are local. They can be renamed, copied and
490 deleted. It is possible to use bookmark names in :hg:`merge` and
490 deleted. It is possible to use bookmark names in :hg:`merge` and
491 :hg:`update` to merge and update respectively to a given bookmark.
491 :hg:`update` to merge and update respectively to a given bookmark.
492
492
493 You can use :hg:`bookmark NAME` to set a bookmark on the working
493 You can use :hg:`bookmark NAME` to set a bookmark on the working
494 directory's parent revision with the given name. If you specify
494 directory's parent revision with the given name. If you specify
495 a revision using -r REV (where REV may be an existing bookmark),
495 a revision using -r REV (where REV may be an existing bookmark),
496 the bookmark is assigned to that revision.
496 the bookmark is assigned to that revision.
497
497
498 Bookmarks can be pushed and pulled between repositories (see :hg:`help
498 Bookmarks can be pushed and pulled between repositories (see :hg:`help
499 push` and :hg:`help pull`). This requires both the local and remote
499 push` and :hg:`help pull`). This requires both the local and remote
500 repositories to support bookmarks. For versions prior to 1.8, this means
500 repositories to support bookmarks. For versions prior to 1.8, this means
501 the bookmarks extension must be enabled.
501 the bookmarks extension must be enabled.
502 '''
502 '''
503 hexfn = ui.debugflag and hex or short
503 hexfn = ui.debugflag and hex or short
504 marks = repo._bookmarks
504 marks = repo._bookmarks
505 cur = repo.changectx('.').node()
505 cur = repo.changectx('.').node()
506
506
507 if rename:
507 if rename:
508 if rename not in marks:
508 if rename not in marks:
509 raise util.Abort(_("bookmark '%s' does not exist") % rename)
509 raise util.Abort(_("bookmark '%s' does not exist") % rename)
510 if mark in marks and not force:
510 if mark in marks and not force:
511 raise util.Abort(_("bookmark '%s' already exists "
511 raise util.Abort(_("bookmark '%s' already exists "
512 "(use -f to force)") % mark)
512 "(use -f to force)") % mark)
513 if mark is None:
513 if mark is None:
514 raise util.Abort(_("new bookmark name required"))
514 raise util.Abort(_("new bookmark name required"))
515 marks[mark] = marks[rename]
515 marks[mark] = marks[rename]
516 if repo._bookmarkcurrent == rename:
516 if repo._bookmarkcurrent == rename:
517 bookmarks.setcurrent(repo, mark)
517 bookmarks.setcurrent(repo, mark)
518 del marks[rename]
518 del marks[rename]
519 bookmarks.write(repo)
519 bookmarks.write(repo)
520 return
520 return
521
521
522 if delete:
522 if delete:
523 if mark is None:
523 if mark is None:
524 raise util.Abort(_("bookmark name required"))
524 raise util.Abort(_("bookmark name required"))
525 if mark not in marks:
525 if mark not in marks:
526 raise util.Abort(_("bookmark '%s' does not exist") % mark)
526 raise util.Abort(_("bookmark '%s' does not exist") % mark)
527 if mark == repo._bookmarkcurrent:
527 if mark == repo._bookmarkcurrent:
528 bookmarks.setcurrent(repo, None)
528 bookmarks.setcurrent(repo, None)
529 del marks[mark]
529 del marks[mark]
530 bookmarks.write(repo)
530 bookmarks.write(repo)
531 return
531 return
532
532
533 if mark is not None:
533 if mark is not None:
534 if "\n" in mark:
534 if "\n" in mark:
535 raise util.Abort(_("bookmark name cannot contain newlines"))
535 raise util.Abort(_("bookmark name cannot contain newlines"))
536 mark = mark.strip()
536 mark = mark.strip()
537 if not mark:
537 if not mark:
538 raise util.Abort(_("bookmark names cannot consist entirely of "
538 raise util.Abort(_("bookmark names cannot consist entirely of "
539 "whitespace"))
539 "whitespace"))
540 if mark in marks and not force:
540 if mark in marks and not force:
541 raise util.Abort(_("bookmark '%s' already exists "
541 raise util.Abort(_("bookmark '%s' already exists "
542 "(use -f to force)") % mark)
542 "(use -f to force)") % mark)
543 if ((mark in repo.branchtags() or mark == repo.dirstate.branch())
543 if ((mark in repo.branchtags() or mark == repo.dirstate.branch())
544 and not force):
544 and not force):
545 raise util.Abort(
545 raise util.Abort(
546 _("a bookmark cannot have the name of an existing branch"))
546 _("a bookmark cannot have the name of an existing branch"))
547 if rev:
547 if rev:
548 marks[mark] = repo.lookup(rev)
548 marks[mark] = repo.lookup(rev)
549 else:
549 else:
550 marks[mark] = repo.changectx('.').node()
550 marks[mark] = repo.changectx('.').node()
551 if repo.changectx('.').node() == marks[mark]:
551 if repo.changectx('.').node() == marks[mark]:
552 bookmarks.setcurrent(repo, mark)
552 bookmarks.setcurrent(repo, mark)
553 bookmarks.write(repo)
553 bookmarks.write(repo)
554 return
554 return
555
555
556 if mark is None:
556 if mark is None:
557 if rev:
557 if rev:
558 raise util.Abort(_("bookmark name required"))
558 raise util.Abort(_("bookmark name required"))
559 if len(marks) == 0:
559 if len(marks) == 0:
560 ui.status(_("no bookmarks set\n"))
560 ui.status(_("no bookmarks set\n"))
561 else:
561 else:
562 for bmark, n in sorted(marks.iteritems()):
562 for bmark, n in sorted(marks.iteritems()):
563 current = repo._bookmarkcurrent
563 current = repo._bookmarkcurrent
564 if bmark == current and n == cur:
564 if bmark == current and n == cur:
565 prefix, label = '*', 'bookmarks.current'
565 prefix, label = '*', 'bookmarks.current'
566 else:
566 else:
567 prefix, label = ' ', ''
567 prefix, label = ' ', ''
568
568
569 if ui.quiet:
569 if ui.quiet:
570 ui.write("%s\n" % bmark, label=label)
570 ui.write("%s\n" % bmark, label=label)
571 else:
571 else:
572 ui.write(" %s %-25s %d:%s\n" % (
572 ui.write(" %s %-25s %d:%s\n" % (
573 prefix, bmark, repo.changelog.rev(n), hexfn(n)),
573 prefix, bmark, repo.changelog.rev(n), hexfn(n)),
574 label=label)
574 label=label)
575 return
575 return
576
576
577 def branch(ui, repo, label=None, **opts):
577 def branch(ui, repo, label=None, **opts):
578 """set or show the current branch name
578 """set or show the current branch name
579
579
580 With no argument, show the current branch name. With one argument,
580 With no argument, show the current branch name. With one argument,
581 set the working directory branch name (the branch will not exist
581 set the working directory branch name (the branch will not exist
582 in the repository until the next commit). Standard practice
582 in the repository until the next commit). Standard practice
583 recommends that primary development take place on the 'default'
583 recommends that primary development take place on the 'default'
584 branch.
584 branch.
585
585
586 Unless -f/--force is specified, branch will not let you set a
586 Unless -f/--force is specified, branch will not let you set a
587 branch name that already exists, even if it's inactive.
587 branch name that already exists, even if it's inactive.
588
588
589 Use -C/--clean to reset the working directory branch to that of
589 Use -C/--clean to reset the working directory branch to that of
590 the parent of the working directory, negating a previous branch
590 the parent of the working directory, negating a previous branch
591 change.
591 change.
592
592
593 Use the command :hg:`update` to switch to an existing branch. Use
593 Use the command :hg:`update` to switch to an existing branch. Use
594 :hg:`commit --close-branch` to mark this branch as closed.
594 :hg:`commit --close-branch` to mark this branch as closed.
595
595
596 Returns 0 on success.
596 Returns 0 on success.
597 """
597 """
598
598
599 if opts.get('clean'):
599 if opts.get('clean'):
600 label = repo[None].p1().branch()
600 label = repo[None].p1().branch()
601 repo.dirstate.setbranch(label)
601 repo.dirstate.setbranch(label)
602 ui.status(_('reset working directory to branch %s\n') % label)
602 ui.status(_('reset working directory to branch %s\n') % label)
603 elif label:
603 elif label:
604 if not opts.get('force') and label in repo.branchtags():
604 if not opts.get('force') and label in repo.branchtags():
605 if label not in [p.branch() for p in repo.parents()]:
605 if label not in [p.branch() for p in repo.parents()]:
606 raise util.Abort(_('a branch of the same name already exists'
606 raise util.Abort(_('a branch of the same name already exists'
607 " (use 'hg update' to switch to it)"))
607 " (use 'hg update' to switch to it)"))
608 repo.dirstate.setbranch(label)
608 repo.dirstate.setbranch(label)
609 ui.status(_('marked working directory as branch %s\n') % label)
609 ui.status(_('marked working directory as branch %s\n') % label)
610 else:
610 else:
611 ui.write("%s\n" % repo.dirstate.branch())
611 ui.write("%s\n" % repo.dirstate.branch())
612
612
613 def branches(ui, repo, active=False, closed=False):
613 def branches(ui, repo, active=False, closed=False):
614 """list repository named branches
614 """list repository named branches
615
615
616 List the repository's named branches, indicating which ones are
616 List the repository's named branches, indicating which ones are
617 inactive. If -c/--closed is specified, also list branches which have
617 inactive. If -c/--closed is specified, also list branches which have
618 been marked closed (see :hg:`commit --close-branch`).
618 been marked closed (see :hg:`commit --close-branch`).
619
619
620 If -a/--active is specified, only show active branches. A branch
620 If -a/--active is specified, only show active branches. A branch
621 is considered active if it contains repository heads.
621 is considered active if it contains repository heads.
622
622
623 Use the command :hg:`update` to switch to an existing branch.
623 Use the command :hg:`update` to switch to an existing branch.
624
624
625 Returns 0.
625 Returns 0.
626 """
626 """
627
627
628 hexfunc = ui.debugflag and hex or short
628 hexfunc = ui.debugflag and hex or short
629 activebranches = [repo[n].branch() for n in repo.heads()]
629 activebranches = [repo[n].branch() for n in repo.heads()]
630 def testactive(tag, node):
630 def testactive(tag, node):
631 realhead = tag in activebranches
631 realhead = tag in activebranches
632 open = node in repo.branchheads(tag, closed=False)
632 open = node in repo.branchheads(tag, closed=False)
633 return realhead and open
633 return realhead and open
634 branches = sorted([(testactive(tag, node), repo.changelog.rev(node), tag)
634 branches = sorted([(testactive(tag, node), repo.changelog.rev(node), tag)
635 for tag, node in repo.branchtags().items()],
635 for tag, node in repo.branchtags().items()],
636 reverse=True)
636 reverse=True)
637
637
638 for isactive, node, tag in branches:
638 for isactive, node, tag in branches:
639 if (not active) or isactive:
639 if (not active) or isactive:
640 if ui.quiet:
640 if ui.quiet:
641 ui.write("%s\n" % tag)
641 ui.write("%s\n" % tag)
642 else:
642 else:
643 hn = repo.lookup(node)
643 hn = repo.lookup(node)
644 if isactive:
644 if isactive:
645 label = 'branches.active'
645 label = 'branches.active'
646 notice = ''
646 notice = ''
647 elif hn not in repo.branchheads(tag, closed=False):
647 elif hn not in repo.branchheads(tag, closed=False):
648 if not closed:
648 if not closed:
649 continue
649 continue
650 label = 'branches.closed'
650 label = 'branches.closed'
651 notice = _(' (closed)')
651 notice = _(' (closed)')
652 else:
652 else:
653 label = 'branches.inactive'
653 label = 'branches.inactive'
654 notice = _(' (inactive)')
654 notice = _(' (inactive)')
655 if tag == repo.dirstate.branch():
655 if tag == repo.dirstate.branch():
656 label = 'branches.current'
656 label = 'branches.current'
657 rev = str(node).rjust(31 - encoding.colwidth(tag))
657 rev = str(node).rjust(31 - encoding.colwidth(tag))
658 rev = ui.label('%s:%s' % (rev, hexfunc(hn)), 'log.changeset')
658 rev = ui.label('%s:%s' % (rev, hexfunc(hn)), 'log.changeset')
659 tag = ui.label(tag, label)
659 tag = ui.label(tag, label)
660 ui.write("%s %s%s\n" % (tag, rev, notice))
660 ui.write("%s %s%s\n" % (tag, rev, notice))
661
661
662 def bundle(ui, repo, fname, dest=None, **opts):
662 def bundle(ui, repo, fname, dest=None, **opts):
663 """create a changegroup file
663 """create a changegroup file
664
664
665 Generate a compressed changegroup file collecting changesets not
665 Generate a compressed changegroup file collecting changesets not
666 known to be in another repository.
666 known to be in another repository.
667
667
668 If you omit the destination repository, then hg assumes the
668 If you omit the destination repository, then hg assumes the
669 destination will have all the nodes you specify with --base
669 destination will have all the nodes you specify with --base
670 parameters. To create a bundle containing all changesets, use
670 parameters. To create a bundle containing all changesets, use
671 -a/--all (or --base null).
671 -a/--all (or --base null).
672
672
673 You can change compression method with the -t/--type option.
673 You can change compression method with the -t/--type option.
674 The available compression methods are: none, bzip2, and
674 The available compression methods are: none, bzip2, and
675 gzip (by default, bundles are compressed using bzip2).
675 gzip (by default, bundles are compressed using bzip2).
676
676
677 The bundle file can then be transferred using conventional means
677 The bundle file can then be transferred using conventional means
678 and applied to another repository with the unbundle or pull
678 and applied to another repository with the unbundle or pull
679 command. This is useful when direct push and pull are not
679 command. This is useful when direct push and pull are not
680 available or when exporting an entire repository is undesirable.
680 available or when exporting an entire repository is undesirable.
681
681
682 Applying bundles preserves all changeset contents including
682 Applying bundles preserves all changeset contents including
683 permissions, copy/rename information, and revision history.
683 permissions, copy/rename information, and revision history.
684
684
685 Returns 0 on success, 1 if no changes found.
685 Returns 0 on success, 1 if no changes found.
686 """
686 """
687 revs = None
687 revs = None
688 if 'rev' in opts:
688 if 'rev' in opts:
689 revs = cmdutil.revrange(repo, opts['rev'])
689 revs = cmdutil.revrange(repo, opts['rev'])
690
690
691 if opts.get('all'):
691 if opts.get('all'):
692 base = ['null']
692 base = ['null']
693 else:
693 else:
694 base = cmdutil.revrange(repo, opts.get('base'))
694 base = cmdutil.revrange(repo, opts.get('base'))
695 if base:
695 if base:
696 if dest:
696 if dest:
697 raise util.Abort(_("--base is incompatible with specifying "
697 raise util.Abort(_("--base is incompatible with specifying "
698 "a destination"))
698 "a destination"))
699 common = [repo.lookup(rev) for rev in base]
699 common = [repo.lookup(rev) for rev in base]
700 else:
700 else:
701 dest = ui.expandpath(dest or 'default-push', dest or 'default')
701 dest = ui.expandpath(dest or 'default-push', dest or 'default')
702 dest, branches = hg.parseurl(dest, opts.get('branch'))
702 dest, branches = hg.parseurl(dest, opts.get('branch'))
703 other = hg.repository(hg.remoteui(repo, opts), dest)
703 other = hg.repository(hg.remoteui(repo, opts), dest)
704 revs, checkout = hg.addbranchrevs(repo, other, branches, revs)
704 revs, checkout = hg.addbranchrevs(repo, other, branches, revs)
705 inc = discovery.findcommonincoming(repo, other, force=opts.get('force'))
705 inc = discovery.findcommonincoming(repo, other, force=opts.get('force'))
706 common, _anyinc, _heads = inc
706 common, _anyinc, _heads = inc
707
707
708 nodes = revs and map(repo.lookup, revs) or revs
708 nodes = revs and map(repo.lookup, revs) or revs
709 cg = repo.getbundle('bundle', common=common, heads=nodes)
709 cg = repo.getbundle('bundle', common=common, heads=nodes)
710 if not cg:
710 if not cg:
711 ui.status(_("no changes found\n"))
711 ui.status(_("no changes found\n"))
712 return 1
712 return 1
713
713
714 bundletype = opts.get('type', 'bzip2').lower()
714 bundletype = opts.get('type', 'bzip2').lower()
715 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
715 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
716 bundletype = btypes.get(bundletype)
716 bundletype = btypes.get(bundletype)
717 if bundletype not in changegroup.bundletypes:
717 if bundletype not in changegroup.bundletypes:
718 raise util.Abort(_('unknown bundle type specified with --type'))
718 raise util.Abort(_('unknown bundle type specified with --type'))
719
719
720 changegroup.writebundle(cg, fname, bundletype)
720 changegroup.writebundle(cg, fname, bundletype)
721
721
722 def cat(ui, repo, file1, *pats, **opts):
722 def cat(ui, repo, file1, *pats, **opts):
723 """output the current or given revision of files
723 """output the current or given revision of files
724
724
725 Print the specified files as they were at the given revision. If
725 Print the specified files as they were at the given revision. If
726 no revision is given, the parent of the working directory is used,
726 no revision is given, the parent of the working directory is used,
727 or tip if no revision is checked out.
727 or tip if no revision is checked out.
728
728
729 Output may be to a file, in which case the name of the file is
729 Output may be to a file, in which case the name of the file is
730 given using a format string. The formatting rules are the same as
730 given using a format string. The formatting rules are the same as
731 for the export command, with the following additions:
731 for the export command, with the following additions:
732
732
733 :``%s``: basename of file being printed
733 :``%s``: basename of file being printed
734 :``%d``: dirname of file being printed, or '.' if in repository root
734 :``%d``: dirname of file being printed, or '.' if in repository root
735 :``%p``: root-relative path name of file being printed
735 :``%p``: root-relative path name of file being printed
736
736
737 Returns 0 on success.
737 Returns 0 on success.
738 """
738 """
739 ctx = cmdutil.revsingle(repo, opts.get('rev'))
739 ctx = cmdutil.revsingle(repo, opts.get('rev'))
740 err = 1
740 err = 1
741 m = cmdutil.match(repo, (file1,) + pats, opts)
741 m = cmdutil.match(repo, (file1,) + pats, opts)
742 for abs in ctx.walk(m):
742 for abs in ctx.walk(m):
743 fp = cmdutil.make_file(repo, opts.get('output'), ctx.node(), pathname=abs)
743 fp = cmdutil.make_file(repo, opts.get('output'), ctx.node(), pathname=abs)
744 data = ctx[abs].data()
744 data = ctx[abs].data()
745 if opts.get('decode'):
745 if opts.get('decode'):
746 data = repo.wwritedata(abs, data)
746 data = repo.wwritedata(abs, data)
747 fp.write(data)
747 fp.write(data)
748 fp.close()
748 fp.close()
749 err = 0
749 err = 0
750 return err
750 return err
751
751
752 def clone(ui, source, dest=None, **opts):
752 def clone(ui, source, dest=None, **opts):
753 """make a copy of an existing repository
753 """make a copy of an existing repository
754
754
755 Create a copy of an existing repository in a new directory.
755 Create a copy of an existing repository in a new directory.
756
756
757 If no destination directory name is specified, it defaults to the
757 If no destination directory name is specified, it defaults to the
758 basename of the source.
758 basename of the source.
759
759
760 The location of the source is added to the new repository's
760 The location of the source is added to the new repository's
761 ``.hg/hgrc`` file, as the default to be used for future pulls.
761 ``.hg/hgrc`` file, as the default to be used for future pulls.
762
762
763 See :hg:`help urls` for valid source format details.
763 See :hg:`help urls` for valid source format details.
764
764
765 It is possible to specify an ``ssh://`` URL as the destination, but no
765 It is possible to specify an ``ssh://`` URL as the destination, but no
766 ``.hg/hgrc`` and working directory will be created on the remote side.
766 ``.hg/hgrc`` and working directory will be created on the remote side.
767 Please see :hg:`help urls` for important details about ``ssh://`` URLs.
767 Please see :hg:`help urls` for important details about ``ssh://`` URLs.
768
768
769 A set of changesets (tags, or branch names) to pull may be specified
769 A set of changesets (tags, or branch names) to pull may be specified
770 by listing each changeset (tag, or branch name) with -r/--rev.
770 by listing each changeset (tag, or branch name) with -r/--rev.
771 If -r/--rev is used, the cloned repository will contain only a subset
771 If -r/--rev is used, the cloned repository will contain only a subset
772 of the changesets of the source repository. Only the set of changesets
772 of the changesets of the source repository. Only the set of changesets
773 defined by all -r/--rev options (including all their ancestors)
773 defined by all -r/--rev options (including all their ancestors)
774 will be pulled into the destination repository.
774 will be pulled into the destination repository.
775 No subsequent changesets (including subsequent tags) will be present
775 No subsequent changesets (including subsequent tags) will be present
776 in the destination.
776 in the destination.
777
777
778 Using -r/--rev (or 'clone src#rev dest') implies --pull, even for
778 Using -r/--rev (or 'clone src#rev dest') implies --pull, even for
779 local source repositories.
779 local source repositories.
780
780
781 For efficiency, hardlinks are used for cloning whenever the source
781 For efficiency, hardlinks are used for cloning whenever the source
782 and destination are on the same filesystem (note this applies only
782 and destination are on the same filesystem (note this applies only
783 to the repository data, not to the working directory). Some
783 to the repository data, not to the working directory). Some
784 filesystems, such as AFS, implement hardlinking incorrectly, but
784 filesystems, such as AFS, implement hardlinking incorrectly, but
785 do not report errors. In these cases, use the --pull option to
785 do not report errors. In these cases, use the --pull option to
786 avoid hardlinking.
786 avoid hardlinking.
787
787
788 In some cases, you can clone repositories and the working directory
788 In some cases, you can clone repositories and the working directory
789 using full hardlinks with ::
789 using full hardlinks with ::
790
790
791 $ cp -al REPO REPOCLONE
791 $ cp -al REPO REPOCLONE
792
792
793 This is the fastest way to clone, but it is not always safe. The
793 This is the fastest way to clone, but it is not always safe. The
794 operation is not atomic (making sure REPO is not modified during
794 operation is not atomic (making sure REPO is not modified during
795 the operation is up to you) and you have to make sure your editor
795 the operation is up to you) and you have to make sure your editor
796 breaks hardlinks (Emacs and most Linux Kernel tools do so). Also,
796 breaks hardlinks (Emacs and most Linux Kernel tools do so). Also,
797 this is not compatible with certain extensions that place their
797 this is not compatible with certain extensions that place their
798 metadata under the .hg directory, such as mq.
798 metadata under the .hg directory, such as mq.
799
799
800 Mercurial will update the working directory to the first applicable
800 Mercurial will update the working directory to the first applicable
801 revision from this list:
801 revision from this list:
802
802
803 a) null if -U or the source repository has no changesets
803 a) null if -U or the source repository has no changesets
804 b) if -u . and the source repository is local, the first parent of
804 b) if -u . and the source repository is local, the first parent of
805 the source repository's working directory
805 the source repository's working directory
806 c) the changeset specified with -u (if a branch name, this means the
806 c) the changeset specified with -u (if a branch name, this means the
807 latest head of that branch)
807 latest head of that branch)
808 d) the changeset specified with -r
808 d) the changeset specified with -r
809 e) the tipmost head specified with -b
809 e) the tipmost head specified with -b
810 f) the tipmost head specified with the url#branch source syntax
810 f) the tipmost head specified with the url#branch source syntax
811 g) the tipmost head of the default branch
811 g) the tipmost head of the default branch
812 h) tip
812 h) tip
813
813
814 Returns 0 on success.
814 Returns 0 on success.
815 """
815 """
816 if opts.get('noupdate') and opts.get('updaterev'):
816 if opts.get('noupdate') and opts.get('updaterev'):
817 raise util.Abort(_("cannot specify both --noupdate and --updaterev"))
817 raise util.Abort(_("cannot specify both --noupdate and --updaterev"))
818
818
819 r = hg.clone(hg.remoteui(ui, opts), source, dest,
819 r = hg.clone(hg.remoteui(ui, opts), source, dest,
820 pull=opts.get('pull'),
820 pull=opts.get('pull'),
821 stream=opts.get('uncompressed'),
821 stream=opts.get('uncompressed'),
822 rev=opts.get('rev'),
822 rev=opts.get('rev'),
823 update=opts.get('updaterev') or not opts.get('noupdate'),
823 update=opts.get('updaterev') or not opts.get('noupdate'),
824 branch=opts.get('branch'))
824 branch=opts.get('branch'))
825
825
826 return r is None
826 return r is None
827
827
828 def commit(ui, repo, *pats, **opts):
828 def commit(ui, repo, *pats, **opts):
829 """commit the specified files or all outstanding changes
829 """commit the specified files or all outstanding changes
830
830
831 Commit changes to the given files into the repository. Unlike a
831 Commit changes to the given files into the repository. Unlike a
832 centralized SCM, this operation is a local operation. See
832 centralized SCM, this operation is a local operation. See
833 :hg:`push` for a way to actively distribute your changes.
833 :hg:`push` for a way to actively distribute your changes.
834
834
835 If a list of files is omitted, all changes reported by :hg:`status`
835 If a list of files is omitted, all changes reported by :hg:`status`
836 will be committed.
836 will be committed.
837
837
838 If you are committing the result of a merge, do not provide any
838 If you are committing the result of a merge, do not provide any
839 filenames or -I/-X filters.
839 filenames or -I/-X filters.
840
840
841 If no commit message is specified, Mercurial starts your
841 If no commit message is specified, Mercurial starts your
842 configured editor where you can enter a message. In case your
842 configured editor where you can enter a message. In case your
843 commit fails, you will find a backup of your message in
843 commit fails, you will find a backup of your message in
844 ``.hg/last-message.txt``.
844 ``.hg/last-message.txt``.
845
845
846 See :hg:`help dates` for a list of formats valid for -d/--date.
846 See :hg:`help dates` for a list of formats valid for -d/--date.
847
847
848 Returns 0 on success, 1 if nothing changed.
848 Returns 0 on success, 1 if nothing changed.
849 """
849 """
850 extra = {}
850 extra = {}
851 if opts.get('close_branch'):
851 if opts.get('close_branch'):
852 if repo['.'].node() not in repo.branchheads():
852 if repo['.'].node() not in repo.branchheads():
853 # The topo heads set is included in the branch heads set of the
853 # The topo heads set is included in the branch heads set of the
854 # current branch, so it's sufficient to test branchheads
854 # current branch, so it's sufficient to test branchheads
855 raise util.Abort(_('can only close branch heads'))
855 raise util.Abort(_('can only close branch heads'))
856 extra['close'] = 1
856 extra['close'] = 1
857 e = cmdutil.commiteditor
857 e = cmdutil.commiteditor
858 if opts.get('force_editor'):
858 if opts.get('force_editor'):
859 e = cmdutil.commitforceeditor
859 e = cmdutil.commitforceeditor
860
860
861 def commitfunc(ui, repo, message, match, opts):
861 def commitfunc(ui, repo, message, match, opts):
862 return repo.commit(message, opts.get('user'), opts.get('date'), match,
862 return repo.commit(message, opts.get('user'), opts.get('date'), match,
863 editor=e, extra=extra)
863 editor=e, extra=extra)
864
864
865 branch = repo[None].branch()
865 branch = repo[None].branch()
866 bheads = repo.branchheads(branch)
866 bheads = repo.branchheads(branch)
867
867
868 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
868 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
869 if not node:
869 if not node:
870 stat = repo.status(match=cmdutil.match(repo, pats, opts))
870 stat = repo.status(match=cmdutil.match(repo, pats, opts))
871 if stat[3]:
871 if stat[3]:
872 ui.status(_("nothing changed (%d missing files, see 'hg status')\n")
872 ui.status(_("nothing changed (%d missing files, see 'hg status')\n")
873 % len(stat[3]))
873 % len(stat[3]))
874 else:
874 else:
875 ui.status(_("nothing changed\n"))
875 ui.status(_("nothing changed\n"))
876 return 1
876 return 1
877
877
878 ctx = repo[node]
878 ctx = repo[node]
879 parents = ctx.parents()
879 parents = ctx.parents()
880
880
881 if bheads and not [x for x in parents
881 if bheads and not [x for x in parents
882 if x.node() in bheads and x.branch() == branch]:
882 if x.node() in bheads and x.branch() == branch]:
883 ui.status(_('created new head\n'))
883 ui.status(_('created new head\n'))
884 # The message is not printed for initial roots. For the other
884 # The message is not printed for initial roots. For the other
885 # changesets, it is printed in the following situations:
885 # changesets, it is printed in the following situations:
886 #
886 #
887 # Par column: for the 2 parents with ...
887 # Par column: for the 2 parents with ...
888 # N: null or no parent
888 # N: null or no parent
889 # B: parent is on another named branch
889 # B: parent is on another named branch
890 # C: parent is a regular non head changeset
890 # C: parent is a regular non head changeset
891 # H: parent was a branch head of the current branch
891 # H: parent was a branch head of the current branch
892 # Msg column: whether we print "created new head" message
892 # Msg column: whether we print "created new head" message
893 # In the following, it is assumed that there already exists some
893 # In the following, it is assumed that there already exists some
894 # initial branch heads of the current branch, otherwise nothing is
894 # initial branch heads of the current branch, otherwise nothing is
895 # printed anyway.
895 # printed anyway.
896 #
896 #
897 # Par Msg Comment
897 # Par Msg Comment
898 # NN y additional topo root
898 # NN y additional topo root
899 #
899 #
900 # BN y additional branch root
900 # BN y additional branch root
901 # CN y additional topo head
901 # CN y additional topo head
902 # HN n usual case
902 # HN n usual case
903 #
903 #
904 # BB y weird additional branch root
904 # BB y weird additional branch root
905 # CB y branch merge
905 # CB y branch merge
906 # HB n merge with named branch
906 # HB n merge with named branch
907 #
907 #
908 # CC y additional head from merge
908 # CC y additional head from merge
909 # CH n merge with a head
909 # CH n merge with a head
910 #
910 #
911 # HH n head merge: head count decreases
911 # HH n head merge: head count decreases
912
912
913 if not opts.get('close_branch'):
913 if not opts.get('close_branch'):
914 for r in parents:
914 for r in parents:
915 if r.extra().get('close') and r.branch() == branch:
915 if r.extra().get('close') and r.branch() == branch:
916 ui.status(_('reopening closed branch head %d\n') % r)
916 ui.status(_('reopening closed branch head %d\n') % r)
917
917
918 if ui.debugflag:
918 if ui.debugflag:
919 ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx.hex()))
919 ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx.hex()))
920 elif ui.verbose:
920 elif ui.verbose:
921 ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx))
921 ui.write(_('committed changeset %d:%s\n') % (int(ctx), ctx))
922
922
923 def copy(ui, repo, *pats, **opts):
923 def copy(ui, repo, *pats, **opts):
924 """mark files as copied for the next commit
924 """mark files as copied for the next commit
925
925
926 Mark dest as having copies of source files. If dest is a
926 Mark dest as having copies of source files. If dest is a
927 directory, copies are put in that directory. If dest is a file,
927 directory, copies are put in that directory. If dest is a file,
928 the source must be a single file.
928 the source must be a single file.
929
929
930 By default, this command copies the contents of files as they
930 By default, this command copies the contents of files as they
931 exist in the working directory. If invoked with -A/--after, the
931 exist in the working directory. If invoked with -A/--after, the
932 operation is recorded, but no copying is performed.
932 operation is recorded, but no copying is performed.
933
933
934 This command takes effect with the next commit. To undo a copy
934 This command takes effect with the next commit. To undo a copy
935 before that, see :hg:`revert`.
935 before that, see :hg:`revert`.
936
936
937 Returns 0 on success, 1 if errors are encountered.
937 Returns 0 on success, 1 if errors are encountered.
938 """
938 """
939 wlock = repo.wlock(False)
939 wlock = repo.wlock(False)
940 try:
940 try:
941 return cmdutil.copy(ui, repo, pats, opts)
941 return cmdutil.copy(ui, repo, pats, opts)
942 finally:
942 finally:
943 wlock.release()
943 wlock.release()
944
944
945 def debugancestor(ui, repo, *args):
945 def debugancestor(ui, repo, *args):
946 """find the ancestor revision of two revisions in a given index"""
946 """find the ancestor revision of two revisions in a given index"""
947 if len(args) == 3:
947 if len(args) == 3:
948 index, rev1, rev2 = args
948 index, rev1, rev2 = args
949 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), index)
949 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), index)
950 lookup = r.lookup
950 lookup = r.lookup
951 elif len(args) == 2:
951 elif len(args) == 2:
952 if not repo:
952 if not repo:
953 raise util.Abort(_("there is no Mercurial repository here "
953 raise util.Abort(_("there is no Mercurial repository here "
954 "(.hg not found)"))
954 "(.hg not found)"))
955 rev1, rev2 = args
955 rev1, rev2 = args
956 r = repo.changelog
956 r = repo.changelog
957 lookup = repo.lookup
957 lookup = repo.lookup
958 else:
958 else:
959 raise util.Abort(_('either two or three arguments required'))
959 raise util.Abort(_('either two or three arguments required'))
960 a = r.ancestor(lookup(rev1), lookup(rev2))
960 a = r.ancestor(lookup(rev1), lookup(rev2))
961 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
961 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
962
962
963 def debugbuilddag(ui, repo, text,
963 def debugbuilddag(ui, repo, text,
964 mergeable_file=False,
964 mergeable_file=False,
965 appended_file=False,
965 appended_file=False,
966 overwritten_file=False,
966 overwritten_file=False,
967 new_file=False):
967 new_file=False):
968 """builds a repo with a given dag from scratch in the current empty repo
968 """builds a repo with a given dag from scratch in the current empty repo
969
969
970 Elements:
970 Elements:
971
971
972 - "+n" is a linear run of n nodes based on the current default parent
972 - "+n" is a linear run of n nodes based on the current default parent
973 - "." is a single node based on the current default parent
973 - "." is a single node based on the current default parent
974 - "$" resets the default parent to null (implied at the start);
974 - "$" resets the default parent to null (implied at the start);
975 otherwise the default parent is always the last node created
975 otherwise the default parent is always the last node created
976 - "<p" sets the default parent to the backref p
976 - "<p" sets the default parent to the backref p
977 - "*p" is a fork at parent p, which is a backref
977 - "*p" is a fork at parent p, which is a backref
978 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
978 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
979 - "/p2" is a merge of the preceding node and p2
979 - "/p2" is a merge of the preceding node and p2
980 - ":tag" defines a local tag for the preceding node
980 - ":tag" defines a local tag for the preceding node
981 - "@branch" sets the named branch for subsequent nodes
981 - "@branch" sets the named branch for subsequent nodes
982 - "!command" runs the command using your shell
982 - "!command" runs the command using your shell
983 - "!!my command\\n" is like "!", but to the end of the line
983 - "!!my command\\n" is like "!", but to the end of the line
984 - "#...\\n" is a comment up to the end of the line
984 - "#...\\n" is a comment up to the end of the line
985
985
986 Whitespace between the above elements is ignored.
986 Whitespace between the above elements is ignored.
987
987
988 A backref is either
988 A backref is either
989
989
990 - a number n, which references the node curr-n, where curr is the current
990 - a number n, which references the node curr-n, where curr is the current
991 node, or
991 node, or
992 - the name of a local tag you placed earlier using ":tag", or
992 - the name of a local tag you placed earlier using ":tag", or
993 - empty to denote the default parent.
993 - empty to denote the default parent.
994
994
995 All string valued-elements are either strictly alphanumeric, or must
995 All string valued-elements are either strictly alphanumeric, or must
996 be enclosed in double quotes ("..."), with "\\" as escape character.
996 be enclosed in double quotes ("..."), with "\\" as escape character.
997
997
998 Note that the --overwritten-file and --appended-file options imply the
998 Note that the --overwritten-file and --appended-file options imply the
999 use of "HGMERGE=internal:local" during DAG buildup.
999 use of "HGMERGE=internal:local" during DAG buildup.
1000 """
1000 """
1001
1001
1002 if not (mergeable_file or appended_file or overwritten_file or new_file):
1002 if not (mergeable_file or appended_file or overwritten_file or new_file):
1003 raise util.Abort(_('need at least one of -m, -a, -o, -n'))
1003 raise util.Abort(_('need at least one of -m, -a, -o, -n'))
1004
1004
1005 if len(repo.changelog) > 0:
1005 if len(repo.changelog) > 0:
1006 raise util.Abort(_('repository is not empty'))
1006 raise util.Abort(_('repository is not empty'))
1007
1007
1008 if overwritten_file or appended_file:
1008 if overwritten_file or appended_file:
1009 # we don't want to fail in merges during buildup
1009 # we don't want to fail in merges during buildup
1010 os.environ['HGMERGE'] = 'internal:local'
1010 os.environ['HGMERGE'] = 'internal:local'
1011
1011
1012 def writefile(fname, text, fmode="wb"):
1012 def writefile(fname, text, fmode="wb"):
1013 f = open(fname, fmode)
1013 f = open(fname, fmode)
1014 try:
1014 try:
1015 f.write(text)
1015 f.write(text)
1016 finally:
1016 finally:
1017 f.close()
1017 f.close()
1018
1018
1019 if mergeable_file:
1019 if mergeable_file:
1020 linesperrev = 2
1020 linesperrev = 2
1021 # determine number of revs in DAG
1021 # determine number of revs in DAG
1022 n = 0
1022 n = 0
1023 for type, data in dagparser.parsedag(text):
1023 for type, data in dagparser.parsedag(text):
1024 if type == 'n':
1024 if type == 'n':
1025 n += 1
1025 n += 1
1026 # make a file with k lines per rev
1026 # make a file with k lines per rev
1027 writefile("mf", "\n".join(str(i) for i in xrange(0, n * linesperrev))
1027 writefile("mf", "\n".join(str(i) for i in xrange(0, n * linesperrev))
1028 + "\n")
1028 + "\n")
1029
1029
1030 at = -1
1030 at = -1
1031 atbranch = 'default'
1031 atbranch = 'default'
1032 for type, data in dagparser.parsedag(text):
1032 for type, data in dagparser.parsedag(text):
1033 if type == 'n':
1033 if type == 'n':
1034 ui.status('node %s\n' % str(data))
1034 ui.status('node %s\n' % str(data))
1035 id, ps = data
1035 id, ps = data
1036 p1 = ps[0]
1036 p1 = ps[0]
1037 if p1 != at:
1037 if p1 != at:
1038 update(ui, repo, node=str(p1), clean=True)
1038 update(ui, repo, node=str(p1), clean=True)
1039 at = p1
1039 at = p1
1040 if repo.dirstate.branch() != atbranch:
1040 if repo.dirstate.branch() != atbranch:
1041 branch(ui, repo, atbranch, force=True)
1041 branch(ui, repo, atbranch, force=True)
1042 if len(ps) > 1:
1042 if len(ps) > 1:
1043 p2 = ps[1]
1043 p2 = ps[1]
1044 merge(ui, repo, node=p2)
1044 merge(ui, repo, node=p2)
1045
1045
1046 if mergeable_file:
1046 if mergeable_file:
1047 f = open("mf", "rb+")
1047 f = open("mf", "rb+")
1048 try:
1048 try:
1049 lines = f.read().split("\n")
1049 lines = f.read().split("\n")
1050 lines[id * linesperrev] += " r%i" % id
1050 lines[id * linesperrev] += " r%i" % id
1051 f.seek(0)
1051 f.seek(0)
1052 f.write("\n".join(lines))
1052 f.write("\n".join(lines))
1053 finally:
1053 finally:
1054 f.close()
1054 f.close()
1055
1055
1056 if appended_file:
1056 if appended_file:
1057 writefile("af", "r%i\n" % id, "ab")
1057 writefile("af", "r%i\n" % id, "ab")
1058
1058
1059 if overwritten_file:
1059 if overwritten_file:
1060 writefile("of", "r%i\n" % id)
1060 writefile("of", "r%i\n" % id)
1061
1061
1062 if new_file:
1062 if new_file:
1063 writefile("nf%i" % id, "r%i\n" % id)
1063 writefile("nf%i" % id, "r%i\n" % id)
1064
1064
1065 commit(ui, repo, addremove=True, message="r%i" % id, date=(id, 0))
1065 commit(ui, repo, addremove=True, message="r%i" % id, date=(id, 0))
1066 at = id
1066 at = id
1067 elif type == 'l':
1067 elif type == 'l':
1068 id, name = data
1068 id, name = data
1069 ui.status('tag %s\n' % name)
1069 ui.status('tag %s\n' % name)
1070 tag(ui, repo, name, local=True)
1070 tag(ui, repo, name, local=True)
1071 elif type == 'a':
1071 elif type == 'a':
1072 ui.status('branch %s\n' % data)
1072 ui.status('branch %s\n' % data)
1073 atbranch = data
1073 atbranch = data
1074 elif type in 'cC':
1074 elif type in 'cC':
1075 r = util.system(data, cwd=repo.root)
1075 r = util.system(data, cwd=repo.root)
1076 if r:
1076 if r:
1077 desc, r = util.explain_exit(r)
1077 desc, r = util.explain_exit(r)
1078 raise util.Abort(_('%s command %s') % (data, desc))
1078 raise util.Abort(_('%s command %s') % (data, desc))
1079
1079
1080 def debugcommands(ui, cmd='', *args):
1080 def debugcommands(ui, cmd='', *args):
1081 """list all available commands and options"""
1081 """list all available commands and options"""
1082 for cmd, vals in sorted(table.iteritems()):
1082 for cmd, vals in sorted(table.iteritems()):
1083 cmd = cmd.split('|')[0].strip('^')
1083 cmd = cmd.split('|')[0].strip('^')
1084 opts = ', '.join([i[1] for i in vals[1]])
1084 opts = ', '.join([i[1] for i in vals[1]])
1085 ui.write('%s: %s\n' % (cmd, opts))
1085 ui.write('%s: %s\n' % (cmd, opts))
1086
1086
1087 def debugcomplete(ui, cmd='', **opts):
1087 def debugcomplete(ui, cmd='', **opts):
1088 """returns the completion list associated with the given command"""
1088 """returns the completion list associated with the given command"""
1089
1089
1090 if opts.get('options'):
1090 if opts.get('options'):
1091 options = []
1091 options = []
1092 otables = [globalopts]
1092 otables = [globalopts]
1093 if cmd:
1093 if cmd:
1094 aliases, entry = cmdutil.findcmd(cmd, table, False)
1094 aliases, entry = cmdutil.findcmd(cmd, table, False)
1095 otables.append(entry[1])
1095 otables.append(entry[1])
1096 for t in otables:
1096 for t in otables:
1097 for o in t:
1097 for o in t:
1098 if "(DEPRECATED)" in o[3]:
1098 if "(DEPRECATED)" in o[3]:
1099 continue
1099 continue
1100 if o[0]:
1100 if o[0]:
1101 options.append('-%s' % o[0])
1101 options.append('-%s' % o[0])
1102 options.append('--%s' % o[1])
1102 options.append('--%s' % o[1])
1103 ui.write("%s\n" % "\n".join(options))
1103 ui.write("%s\n" % "\n".join(options))
1104 return
1104 return
1105
1105
1106 cmdlist = cmdutil.findpossible(cmd, table)
1106 cmdlist = cmdutil.findpossible(cmd, table)
1107 if ui.verbose:
1107 if ui.verbose:
1108 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
1108 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
1109 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
1109 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
1110
1110
1111 def debugfsinfo(ui, path = "."):
1111 def debugfsinfo(ui, path = "."):
1112 """show information detected about current filesystem"""
1112 """show information detected about current filesystem"""
1113 open('.debugfsinfo', 'w').write('')
1113 open('.debugfsinfo', 'w').write('')
1114 ui.write('exec: %s\n' % (util.checkexec(path) and 'yes' or 'no'))
1114 ui.write('exec: %s\n' % (util.checkexec(path) and 'yes' or 'no'))
1115 ui.write('symlink: %s\n' % (util.checklink(path) and 'yes' or 'no'))
1115 ui.write('symlink: %s\n' % (util.checklink(path) and 'yes' or 'no'))
1116 ui.write('case-sensitive: %s\n' % (util.checkcase('.debugfsinfo')
1116 ui.write('case-sensitive: %s\n' % (util.checkcase('.debugfsinfo')
1117 and 'yes' or 'no'))
1117 and 'yes' or 'no'))
1118 os.unlink('.debugfsinfo')
1118 os.unlink('.debugfsinfo')
1119
1119
1120 def debugrebuildstate(ui, repo, rev="tip"):
1120 def debugrebuildstate(ui, repo, rev="tip"):
1121 """rebuild the dirstate as it would look like for the given revision"""
1121 """rebuild the dirstate as it would look like for the given revision"""
1122 ctx = cmdutil.revsingle(repo, rev)
1122 ctx = cmdutil.revsingle(repo, rev)
1123 wlock = repo.wlock()
1123 wlock = repo.wlock()
1124 try:
1124 try:
1125 repo.dirstate.rebuild(ctx.node(), ctx.manifest())
1125 repo.dirstate.rebuild(ctx.node(), ctx.manifest())
1126 finally:
1126 finally:
1127 wlock.release()
1127 wlock.release()
1128
1128
1129 def debugcheckstate(ui, repo):
1129 def debugcheckstate(ui, repo):
1130 """validate the correctness of the current dirstate"""
1130 """validate the correctness of the current dirstate"""
1131 parent1, parent2 = repo.dirstate.parents()
1131 parent1, parent2 = repo.dirstate.parents()
1132 m1 = repo[parent1].manifest()
1132 m1 = repo[parent1].manifest()
1133 m2 = repo[parent2].manifest()
1133 m2 = repo[parent2].manifest()
1134 errors = 0
1134 errors = 0
1135 for f in repo.dirstate:
1135 for f in repo.dirstate:
1136 state = repo.dirstate[f]
1136 state = repo.dirstate[f]
1137 if state in "nr" and f not in m1:
1137 if state in "nr" and f not in m1:
1138 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
1138 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
1139 errors += 1
1139 errors += 1
1140 if state in "a" and f in m1:
1140 if state in "a" and f in m1:
1141 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
1141 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
1142 errors += 1
1142 errors += 1
1143 if state in "m" and f not in m1 and f not in m2:
1143 if state in "m" and f not in m1 and f not in m2:
1144 ui.warn(_("%s in state %s, but not in either manifest\n") %
1144 ui.warn(_("%s in state %s, but not in either manifest\n") %
1145 (f, state))
1145 (f, state))
1146 errors += 1
1146 errors += 1
1147 for f in m1:
1147 for f in m1:
1148 state = repo.dirstate[f]
1148 state = repo.dirstate[f]
1149 if state not in "nrm":
1149 if state not in "nrm":
1150 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
1150 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
1151 errors += 1
1151 errors += 1
1152 if errors:
1152 if errors:
1153 error = _(".hg/dirstate inconsistent with current parent's manifest")
1153 error = _(".hg/dirstate inconsistent with current parent's manifest")
1154 raise util.Abort(error)
1154 raise util.Abort(error)
1155
1155
1156 def showconfig(ui, repo, *values, **opts):
1156 def showconfig(ui, repo, *values, **opts):
1157 """show combined config settings from all hgrc files
1157 """show combined config settings from all hgrc files
1158
1158
1159 With no arguments, print names and values of all config items.
1159 With no arguments, print names and values of all config items.
1160
1160
1161 With one argument of the form section.name, print just the value
1161 With one argument of the form section.name, print just the value
1162 of that config item.
1162 of that config item.
1163
1163
1164 With multiple arguments, print names and values of all config
1164 With multiple arguments, print names and values of all config
1165 items with matching section names.
1165 items with matching section names.
1166
1166
1167 With --debug, the source (filename and line number) is printed
1167 With --debug, the source (filename and line number) is printed
1168 for each config item.
1168 for each config item.
1169
1169
1170 Returns 0 on success.
1170 Returns 0 on success.
1171 """
1171 """
1172
1172
1173 for f in scmutil.rcpath():
1173 for f in scmutil.rcpath():
1174 ui.debug(_('read config from: %s\n') % f)
1174 ui.debug(_('read config from: %s\n') % f)
1175 untrusted = bool(opts.get('untrusted'))
1175 untrusted = bool(opts.get('untrusted'))
1176 if values:
1176 if values:
1177 sections = [v for v in values if '.' not in v]
1177 sections = [v for v in values if '.' not in v]
1178 items = [v for v in values if '.' in v]
1178 items = [v for v in values if '.' in v]
1179 if len(items) > 1 or items and sections:
1179 if len(items) > 1 or items and sections:
1180 raise util.Abort(_('only one config item permitted'))
1180 raise util.Abort(_('only one config item permitted'))
1181 for section, name, value in ui.walkconfig(untrusted=untrusted):
1181 for section, name, value in ui.walkconfig(untrusted=untrusted):
1182 value = str(value).replace('\n', '\\n')
1182 value = str(value).replace('\n', '\\n')
1183 sectname = section + '.' + name
1183 sectname = section + '.' + name
1184 if values:
1184 if values:
1185 for v in values:
1185 for v in values:
1186 if v == section:
1186 if v == section:
1187 ui.debug('%s: ' %
1187 ui.debug('%s: ' %
1188 ui.configsource(section, name, untrusted))
1188 ui.configsource(section, name, untrusted))
1189 ui.write('%s=%s\n' % (sectname, value))
1189 ui.write('%s=%s\n' % (sectname, value))
1190 elif v == sectname:
1190 elif v == sectname:
1191 ui.debug('%s: ' %
1191 ui.debug('%s: ' %
1192 ui.configsource(section, name, untrusted))
1192 ui.configsource(section, name, untrusted))
1193 ui.write(value, '\n')
1193 ui.write(value, '\n')
1194 else:
1194 else:
1195 ui.debug('%s: ' %
1195 ui.debug('%s: ' %
1196 ui.configsource(section, name, untrusted))
1196 ui.configsource(section, name, untrusted))
1197 ui.write('%s=%s\n' % (sectname, value))
1197 ui.write('%s=%s\n' % (sectname, value))
1198
1198
1199 def debugknown(ui, repopath, *ids, **opts):
1199 def debugknown(ui, repopath, *ids, **opts):
1200 """test whether node ids are known to a repo
1200 """test whether node ids are known to a repo
1201
1201
1202 Every ID must be a full-length hex node id string. Returns a list of 0s and 1s
1202 Every ID must be a full-length hex node id string. Returns a list of 0s and 1s
1203 indicating unknown/known.
1203 indicating unknown/known.
1204 """
1204 """
1205 repo = hg.repository(ui, repopath)
1205 repo = hg.repository(ui, repopath)
1206 if not repo.capable('known'):
1206 if not repo.capable('known'):
1207 raise util.Abort("known() not supported by target repository")
1207 raise util.Abort("known() not supported by target repository")
1208 flags = repo.known([bin(s) for s in ids])
1208 flags = repo.known([bin(s) for s in ids])
1209 ui.write("%s\n" % ("".join([f and "1" or "0" for f in flags])))
1209 ui.write("%s\n" % ("".join([f and "1" or "0" for f in flags])))
1210
1210
1211 def debugbundle(ui, bundlepath, all=None, **opts):
1211 def debugbundle(ui, bundlepath, all=None, **opts):
1212 """lists the contents of a bundle"""
1212 """lists the contents of a bundle"""
1213 f = url.open(ui, bundlepath)
1213 f = url.open(ui, bundlepath)
1214 try:
1214 try:
1215 gen = changegroup.readbundle(f, bundlepath)
1215 gen = changegroup.readbundle(f, bundlepath)
1216 if all:
1216 if all:
1217 ui.write("format: id, p1, p2, cset, len(delta)\n")
1217 ui.write("format: id, p1, p2, cset, delta base, len(delta)\n")
1218
1218
1219 def showchunks(named):
1219 def showchunks(named):
1220 ui.write("\n%s\n" % named)
1220 ui.write("\n%s\n" % named)
1221 chain = None
1221 while 1:
1222 while 1:
1222 chunkdata = gen.parsechunk()
1223 chunkdata = gen.parsechunk(chain)
1223 if not chunkdata:
1224 if not chunkdata:
1224 break
1225 break
1225 node = chunkdata['node']
1226 node = chunkdata['node']
1226 p1 = chunkdata['p1']
1227 p1 = chunkdata['p1']
1227 p2 = chunkdata['p2']
1228 p2 = chunkdata['p2']
1228 cs = chunkdata['cs']
1229 cs = chunkdata['cs']
1229 delta = chunkdata['data']
1230 deltabase = chunkdata['deltabase']
1230 ui.write("%s %s %s %s %s\n" %
1231 delta = chunkdata['delta']
1232 ui.write("%s %s %s %s %s %s\n" %
1231 (hex(node), hex(p1), hex(p2),
1233 (hex(node), hex(p1), hex(p2),
1232 hex(cs), len(delta)))
1234 hex(cs), hex(deltabase), len(delta)))
1235 chain = node
1233
1236
1234 showchunks("changelog")
1237 showchunks("changelog")
1235 showchunks("manifest")
1238 showchunks("manifest")
1236 while 1:
1239 while 1:
1237 fname = gen.chunk()
1240 fname = gen.chunk()
1238 if not fname:
1241 if not fname:
1239 break
1242 break
1240 showchunks(fname)
1243 showchunks(fname)
1241 else:
1244 else:
1245 chain = None
1242 while 1:
1246 while 1:
1243 chunkdata = gen.parsechunk()
1247 chunkdata = gen.parsechunk(chain)
1244 if not chunkdata:
1248 if not chunkdata:
1245 break
1249 break
1246 node = chunkdata['node']
1250 node = chunkdata['node']
1247 ui.write("%s\n" % hex(node))
1251 ui.write("%s\n" % hex(node))
1252 chain = node
1248 finally:
1253 finally:
1249 f.close()
1254 f.close()
1250
1255
1251 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
1256 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
1252 """retrieves a bundle from a repo
1257 """retrieves a bundle from a repo
1253
1258
1254 Every ID must be a full-length hex node id string. Saves the bundle to the
1259 Every ID must be a full-length hex node id string. Saves the bundle to the
1255 given file.
1260 given file.
1256 """
1261 """
1257 repo = hg.repository(ui, repopath)
1262 repo = hg.repository(ui, repopath)
1258 if not repo.capable('getbundle'):
1263 if not repo.capable('getbundle'):
1259 raise util.Abort("getbundle() not supported by target repository")
1264 raise util.Abort("getbundle() not supported by target repository")
1260 args = {}
1265 args = {}
1261 if common:
1266 if common:
1262 args['common'] = [bin(s) for s in common]
1267 args['common'] = [bin(s) for s in common]
1263 if head:
1268 if head:
1264 args['heads'] = [bin(s) for s in head]
1269 args['heads'] = [bin(s) for s in head]
1265 bundle = repo.getbundle('debug', **args)
1270 bundle = repo.getbundle('debug', **args)
1266
1271
1267 bundletype = opts.get('type', 'bzip2').lower()
1272 bundletype = opts.get('type', 'bzip2').lower()
1268 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
1273 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
1269 bundletype = btypes.get(bundletype)
1274 bundletype = btypes.get(bundletype)
1270 if bundletype not in changegroup.bundletypes:
1275 if bundletype not in changegroup.bundletypes:
1271 raise util.Abort(_('unknown bundle type specified with --type'))
1276 raise util.Abort(_('unknown bundle type specified with --type'))
1272 changegroup.writebundle(bundle, bundlepath, bundletype)
1277 changegroup.writebundle(bundle, bundlepath, bundletype)
1273
1278
1274 def debugpushkey(ui, repopath, namespace, *keyinfo):
1279 def debugpushkey(ui, repopath, namespace, *keyinfo):
1275 '''access the pushkey key/value protocol
1280 '''access the pushkey key/value protocol
1276
1281
1277 With two args, list the keys in the given namespace.
1282 With two args, list the keys in the given namespace.
1278
1283
1279 With five args, set a key to new if it currently is set to old.
1284 With five args, set a key to new if it currently is set to old.
1280 Reports success or failure.
1285 Reports success or failure.
1281 '''
1286 '''
1282
1287
1283 target = hg.repository(ui, repopath)
1288 target = hg.repository(ui, repopath)
1284 if keyinfo:
1289 if keyinfo:
1285 key, old, new = keyinfo
1290 key, old, new = keyinfo
1286 r = target.pushkey(namespace, key, old, new)
1291 r = target.pushkey(namespace, key, old, new)
1287 ui.status(str(r) + '\n')
1292 ui.status(str(r) + '\n')
1288 return not r
1293 return not r
1289 else:
1294 else:
1290 for k, v in target.listkeys(namespace).iteritems():
1295 for k, v in target.listkeys(namespace).iteritems():
1291 ui.write("%s\t%s\n" % (k.encode('string-escape'),
1296 ui.write("%s\t%s\n" % (k.encode('string-escape'),
1292 v.encode('string-escape')))
1297 v.encode('string-escape')))
1293
1298
1294 def debugrevspec(ui, repo, expr):
1299 def debugrevspec(ui, repo, expr):
1295 '''parse and apply a revision specification'''
1300 '''parse and apply a revision specification'''
1296 if ui.verbose:
1301 if ui.verbose:
1297 tree = revset.parse(expr)[0]
1302 tree = revset.parse(expr)[0]
1298 ui.note(tree, "\n")
1303 ui.note(tree, "\n")
1299 newtree = revset.findaliases(ui, tree)
1304 newtree = revset.findaliases(ui, tree)
1300 if newtree != tree:
1305 if newtree != tree:
1301 ui.note(newtree, "\n")
1306 ui.note(newtree, "\n")
1302 func = revset.match(ui, expr)
1307 func = revset.match(ui, expr)
1303 for c in func(repo, range(len(repo))):
1308 for c in func(repo, range(len(repo))):
1304 ui.write("%s\n" % c)
1309 ui.write("%s\n" % c)
1305
1310
1306 def debugsetparents(ui, repo, rev1, rev2=None):
1311 def debugsetparents(ui, repo, rev1, rev2=None):
1307 """manually set the parents of the current working directory
1312 """manually set the parents of the current working directory
1308
1313
1309 This is useful for writing repository conversion tools, but should
1314 This is useful for writing repository conversion tools, but should
1310 be used with care.
1315 be used with care.
1311
1316
1312 Returns 0 on success.
1317 Returns 0 on success.
1313 """
1318 """
1314
1319
1315 r1 = cmdutil.revsingle(repo, rev1).node()
1320 r1 = cmdutil.revsingle(repo, rev1).node()
1316 r2 = cmdutil.revsingle(repo, rev2, 'null').node()
1321 r2 = cmdutil.revsingle(repo, rev2, 'null').node()
1317
1322
1318 wlock = repo.wlock()
1323 wlock = repo.wlock()
1319 try:
1324 try:
1320 repo.dirstate.setparents(r1, r2)
1325 repo.dirstate.setparents(r1, r2)
1321 finally:
1326 finally:
1322 wlock.release()
1327 wlock.release()
1323
1328
1324 def debugstate(ui, repo, nodates=None, datesort=None):
1329 def debugstate(ui, repo, nodates=None, datesort=None):
1325 """show the contents of the current dirstate"""
1330 """show the contents of the current dirstate"""
1326 timestr = ""
1331 timestr = ""
1327 showdate = not nodates
1332 showdate = not nodates
1328 if datesort:
1333 if datesort:
1329 keyfunc = lambda x: (x[1][3], x[0]) # sort by mtime, then by filename
1334 keyfunc = lambda x: (x[1][3], x[0]) # sort by mtime, then by filename
1330 else:
1335 else:
1331 keyfunc = None # sort by filename
1336 keyfunc = None # sort by filename
1332 for file_, ent in sorted(repo.dirstate._map.iteritems(), key=keyfunc):
1337 for file_, ent in sorted(repo.dirstate._map.iteritems(), key=keyfunc):
1333 if showdate:
1338 if showdate:
1334 if ent[3] == -1:
1339 if ent[3] == -1:
1335 # Pad or slice to locale representation
1340 # Pad or slice to locale representation
1336 locale_len = len(time.strftime("%Y-%m-%d %H:%M:%S ",
1341 locale_len = len(time.strftime("%Y-%m-%d %H:%M:%S ",
1337 time.localtime(0)))
1342 time.localtime(0)))
1338 timestr = 'unset'
1343 timestr = 'unset'
1339 timestr = (timestr[:locale_len] +
1344 timestr = (timestr[:locale_len] +
1340 ' ' * (locale_len - len(timestr)))
1345 ' ' * (locale_len - len(timestr)))
1341 else:
1346 else:
1342 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
1347 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
1343 time.localtime(ent[3]))
1348 time.localtime(ent[3]))
1344 if ent[1] & 020000:
1349 if ent[1] & 020000:
1345 mode = 'lnk'
1350 mode = 'lnk'
1346 else:
1351 else:
1347 mode = '%3o' % (ent[1] & 0777)
1352 mode = '%3o' % (ent[1] & 0777)
1348 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
1353 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
1349 for f in repo.dirstate.copies():
1354 for f in repo.dirstate.copies():
1350 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
1355 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
1351
1356
1352 def debugsub(ui, repo, rev=None):
1357 def debugsub(ui, repo, rev=None):
1353 ctx = cmdutil.revsingle(repo, rev, None)
1358 ctx = cmdutil.revsingle(repo, rev, None)
1354 for k, v in sorted(ctx.substate.items()):
1359 for k, v in sorted(ctx.substate.items()):
1355 ui.write('path %s\n' % k)
1360 ui.write('path %s\n' % k)
1356 ui.write(' source %s\n' % v[0])
1361 ui.write(' source %s\n' % v[0])
1357 ui.write(' revision %s\n' % v[1])
1362 ui.write(' revision %s\n' % v[1])
1358
1363
1359 def debugdag(ui, repo, file_=None, *revs, **opts):
1364 def debugdag(ui, repo, file_=None, *revs, **opts):
1360 """format the changelog or an index DAG as a concise textual description
1365 """format the changelog or an index DAG as a concise textual description
1361
1366
1362 If you pass a revlog index, the revlog's DAG is emitted. If you list
1367 If you pass a revlog index, the revlog's DAG is emitted. If you list
1363 revision numbers, they get labelled in the output as rN.
1368 revision numbers, they get labelled in the output as rN.
1364
1369
1365 Otherwise, the changelog DAG of the current repo is emitted.
1370 Otherwise, the changelog DAG of the current repo is emitted.
1366 """
1371 """
1367 spaces = opts.get('spaces')
1372 spaces = opts.get('spaces')
1368 dots = opts.get('dots')
1373 dots = opts.get('dots')
1369 if file_:
1374 if file_:
1370 rlog = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
1375 rlog = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
1371 revs = set((int(r) for r in revs))
1376 revs = set((int(r) for r in revs))
1372 def events():
1377 def events():
1373 for r in rlog:
1378 for r in rlog:
1374 yield 'n', (r, list(set(p for p in rlog.parentrevs(r) if p != -1)))
1379 yield 'n', (r, list(set(p for p in rlog.parentrevs(r) if p != -1)))
1375 if r in revs:
1380 if r in revs:
1376 yield 'l', (r, "r%i" % r)
1381 yield 'l', (r, "r%i" % r)
1377 elif repo:
1382 elif repo:
1378 cl = repo.changelog
1383 cl = repo.changelog
1379 tags = opts.get('tags')
1384 tags = opts.get('tags')
1380 branches = opts.get('branches')
1385 branches = opts.get('branches')
1381 if tags:
1386 if tags:
1382 labels = {}
1387 labels = {}
1383 for l, n in repo.tags().items():
1388 for l, n in repo.tags().items():
1384 labels.setdefault(cl.rev(n), []).append(l)
1389 labels.setdefault(cl.rev(n), []).append(l)
1385 def events():
1390 def events():
1386 b = "default"
1391 b = "default"
1387 for r in cl:
1392 for r in cl:
1388 if branches:
1393 if branches:
1389 newb = cl.read(cl.node(r))[5]['branch']
1394 newb = cl.read(cl.node(r))[5]['branch']
1390 if newb != b:
1395 if newb != b:
1391 yield 'a', newb
1396 yield 'a', newb
1392 b = newb
1397 b = newb
1393 yield 'n', (r, list(set(p for p in cl.parentrevs(r) if p != -1)))
1398 yield 'n', (r, list(set(p for p in cl.parentrevs(r) if p != -1)))
1394 if tags:
1399 if tags:
1395 ls = labels.get(r)
1400 ls = labels.get(r)
1396 if ls:
1401 if ls:
1397 for l in ls:
1402 for l in ls:
1398 yield 'l', (r, l)
1403 yield 'l', (r, l)
1399 else:
1404 else:
1400 raise util.Abort(_('need repo for changelog dag'))
1405 raise util.Abort(_('need repo for changelog dag'))
1401
1406
1402 for line in dagparser.dagtextlines(events(),
1407 for line in dagparser.dagtextlines(events(),
1403 addspaces=spaces,
1408 addspaces=spaces,
1404 wraplabels=True,
1409 wraplabels=True,
1405 wrapannotations=True,
1410 wrapannotations=True,
1406 wrapnonlinear=dots,
1411 wrapnonlinear=dots,
1407 usedots=dots,
1412 usedots=dots,
1408 maxlinewidth=70):
1413 maxlinewidth=70):
1409 ui.write(line)
1414 ui.write(line)
1410 ui.write("\n")
1415 ui.write("\n")
1411
1416
1412 def debugdata(ui, repo, file_, rev):
1417 def debugdata(ui, repo, file_, rev):
1413 """dump the contents of a data file revision"""
1418 """dump the contents of a data file revision"""
1414 r = None
1419 r = None
1415 if repo:
1420 if repo:
1416 filelog = repo.file(file_)
1421 filelog = repo.file(file_)
1417 if len(filelog):
1422 if len(filelog):
1418 r = filelog
1423 r = filelog
1419 if not r:
1424 if not r:
1420 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False),
1425 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False),
1421 file_[:-2] + ".i")
1426 file_[:-2] + ".i")
1422 try:
1427 try:
1423 ui.write(r.revision(r.lookup(rev)))
1428 ui.write(r.revision(r.lookup(rev)))
1424 except KeyError:
1429 except KeyError:
1425 raise util.Abort(_('invalid revision identifier %s') % rev)
1430 raise util.Abort(_('invalid revision identifier %s') % rev)
1426
1431
1427 def debugdate(ui, date, range=None, **opts):
1432 def debugdate(ui, date, range=None, **opts):
1428 """parse and display a date"""
1433 """parse and display a date"""
1429 if opts["extended"]:
1434 if opts["extended"]:
1430 d = util.parsedate(date, util.extendeddateformats)
1435 d = util.parsedate(date, util.extendeddateformats)
1431 else:
1436 else:
1432 d = util.parsedate(date)
1437 d = util.parsedate(date)
1433 ui.write("internal: %s %s\n" % d)
1438 ui.write("internal: %s %s\n" % d)
1434 ui.write("standard: %s\n" % util.datestr(d))
1439 ui.write("standard: %s\n" % util.datestr(d))
1435 if range:
1440 if range:
1436 m = util.matchdate(range)
1441 m = util.matchdate(range)
1437 ui.write("match: %s\n" % m(d[0]))
1442 ui.write("match: %s\n" % m(d[0]))
1438
1443
1439 def debugignore(ui, repo, *values, **opts):
1444 def debugignore(ui, repo, *values, **opts):
1440 """display the combined ignore pattern"""
1445 """display the combined ignore pattern"""
1441 ignore = repo.dirstate._ignore
1446 ignore = repo.dirstate._ignore
1442 if hasattr(ignore, 'includepat'):
1447 if hasattr(ignore, 'includepat'):
1443 ui.write("%s\n" % ignore.includepat)
1448 ui.write("%s\n" % ignore.includepat)
1444 else:
1449 else:
1445 raise util.Abort(_("no ignore patterns found"))
1450 raise util.Abort(_("no ignore patterns found"))
1446
1451
1447 def debugindex(ui, repo, file_, **opts):
1452 def debugindex(ui, repo, file_, **opts):
1448 """dump the contents of an index file"""
1453 """dump the contents of an index file"""
1449 r = None
1454 r = None
1450 if repo:
1455 if repo:
1451 filelog = repo.file(file_)
1456 filelog = repo.file(file_)
1452 if len(filelog):
1457 if len(filelog):
1453 r = filelog
1458 r = filelog
1454
1459
1455 format = opts.get('format', 0)
1460 format = opts.get('format', 0)
1456 if format not in (0, 1):
1461 if format not in (0, 1):
1457 raise util.Abort(_("unknown format %d") % format)
1462 raise util.Abort(_("unknown format %d") % format)
1458
1463
1459 if not r:
1464 if not r:
1460 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
1465 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
1461
1466
1462 if format == 0:
1467 if format == 0:
1463 ui.write(" rev offset length base linkrev"
1468 ui.write(" rev offset length base linkrev"
1464 " nodeid p1 p2\n")
1469 " nodeid p1 p2\n")
1465 elif format == 1:
1470 elif format == 1:
1466 ui.write(" rev flag offset length"
1471 ui.write(" rev flag offset length"
1467 " size base link p1 p2 nodeid\n")
1472 " size base link p1 p2 nodeid\n")
1468
1473
1469 for i in r:
1474 for i in r:
1470 node = r.node(i)
1475 node = r.node(i)
1471 if format == 0:
1476 if format == 0:
1472 try:
1477 try:
1473 pp = r.parents(node)
1478 pp = r.parents(node)
1474 except:
1479 except:
1475 pp = [nullid, nullid]
1480 pp = [nullid, nullid]
1476 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
1481 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
1477 i, r.start(i), r.length(i), r.base(i), r.linkrev(i),
1482 i, r.start(i), r.length(i), r.base(i), r.linkrev(i),
1478 short(node), short(pp[0]), short(pp[1])))
1483 short(node), short(pp[0]), short(pp[1])))
1479 elif format == 1:
1484 elif format == 1:
1480 pr = r.parentrevs(i)
1485 pr = r.parentrevs(i)
1481 ui.write("% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d % 6d %s\n" % (
1486 ui.write("% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d % 6d %s\n" % (
1482 i, r.flags(i), r.start(i), r.length(i), r.rawsize(i),
1487 i, r.flags(i), r.start(i), r.length(i), r.rawsize(i),
1483 r.base(i), r.linkrev(i), pr[0], pr[1], short(node)))
1488 r.base(i), r.linkrev(i), pr[0], pr[1], short(node)))
1484
1489
1485 def debugindexdot(ui, repo, file_):
1490 def debugindexdot(ui, repo, file_):
1486 """dump an index DAG as a graphviz dot file"""
1491 """dump an index DAG as a graphviz dot file"""
1487 r = None
1492 r = None
1488 if repo:
1493 if repo:
1489 filelog = repo.file(file_)
1494 filelog = repo.file(file_)
1490 if len(filelog):
1495 if len(filelog):
1491 r = filelog
1496 r = filelog
1492 if not r:
1497 if not r:
1493 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
1498 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
1494 ui.write("digraph G {\n")
1499 ui.write("digraph G {\n")
1495 for i in r:
1500 for i in r:
1496 node = r.node(i)
1501 node = r.node(i)
1497 pp = r.parents(node)
1502 pp = r.parents(node)
1498 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
1503 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
1499 if pp[1] != nullid:
1504 if pp[1] != nullid:
1500 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
1505 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
1501 ui.write("}\n")
1506 ui.write("}\n")
1502
1507
1503 def debuginstall(ui):
1508 def debuginstall(ui):
1504 '''test Mercurial installation
1509 '''test Mercurial installation
1505
1510
1506 Returns 0 on success.
1511 Returns 0 on success.
1507 '''
1512 '''
1508
1513
1509 def writetemp(contents):
1514 def writetemp(contents):
1510 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
1515 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
1511 f = os.fdopen(fd, "wb")
1516 f = os.fdopen(fd, "wb")
1512 f.write(contents)
1517 f.write(contents)
1513 f.close()
1518 f.close()
1514 return name
1519 return name
1515
1520
1516 problems = 0
1521 problems = 0
1517
1522
1518 # encoding
1523 # encoding
1519 ui.status(_("Checking encoding (%s)...\n") % encoding.encoding)
1524 ui.status(_("Checking encoding (%s)...\n") % encoding.encoding)
1520 try:
1525 try:
1521 encoding.fromlocal("test")
1526 encoding.fromlocal("test")
1522 except util.Abort, inst:
1527 except util.Abort, inst:
1523 ui.write(" %s\n" % inst)
1528 ui.write(" %s\n" % inst)
1524 ui.write(_(" (check that your locale is properly set)\n"))
1529 ui.write(_(" (check that your locale is properly set)\n"))
1525 problems += 1
1530 problems += 1
1526
1531
1527 # compiled modules
1532 # compiled modules
1528 ui.status(_("Checking installed modules (%s)...\n")
1533 ui.status(_("Checking installed modules (%s)...\n")
1529 % os.path.dirname(__file__))
1534 % os.path.dirname(__file__))
1530 try:
1535 try:
1531 import bdiff, mpatch, base85, osutil
1536 import bdiff, mpatch, base85, osutil
1532 except Exception, inst:
1537 except Exception, inst:
1533 ui.write(" %s\n" % inst)
1538 ui.write(" %s\n" % inst)
1534 ui.write(_(" One or more extensions could not be found"))
1539 ui.write(_(" One or more extensions could not be found"))
1535 ui.write(_(" (check that you compiled the extensions)\n"))
1540 ui.write(_(" (check that you compiled the extensions)\n"))
1536 problems += 1
1541 problems += 1
1537
1542
1538 # templates
1543 # templates
1539 ui.status(_("Checking templates...\n"))
1544 ui.status(_("Checking templates...\n"))
1540 try:
1545 try:
1541 import templater
1546 import templater
1542 templater.templater(templater.templatepath("map-cmdline.default"))
1547 templater.templater(templater.templatepath("map-cmdline.default"))
1543 except Exception, inst:
1548 except Exception, inst:
1544 ui.write(" %s\n" % inst)
1549 ui.write(" %s\n" % inst)
1545 ui.write(_(" (templates seem to have been installed incorrectly)\n"))
1550 ui.write(_(" (templates seem to have been installed incorrectly)\n"))
1546 problems += 1
1551 problems += 1
1547
1552
1548 # editor
1553 # editor
1549 ui.status(_("Checking commit editor...\n"))
1554 ui.status(_("Checking commit editor...\n"))
1550 editor = ui.geteditor()
1555 editor = ui.geteditor()
1551 cmdpath = util.find_exe(editor) or util.find_exe(editor.split()[0])
1556 cmdpath = util.find_exe(editor) or util.find_exe(editor.split()[0])
1552 if not cmdpath:
1557 if not cmdpath:
1553 if editor == 'vi':
1558 if editor == 'vi':
1554 ui.write(_(" No commit editor set and can't find vi in PATH\n"))
1559 ui.write(_(" No commit editor set and can't find vi in PATH\n"))
1555 ui.write(_(" (specify a commit editor in your configuration"
1560 ui.write(_(" (specify a commit editor in your configuration"
1556 " file)\n"))
1561 " file)\n"))
1557 else:
1562 else:
1558 ui.write(_(" Can't find editor '%s' in PATH\n") % editor)
1563 ui.write(_(" Can't find editor '%s' in PATH\n") % editor)
1559 ui.write(_(" (specify a commit editor in your configuration"
1564 ui.write(_(" (specify a commit editor in your configuration"
1560 " file)\n"))
1565 " file)\n"))
1561 problems += 1
1566 problems += 1
1562
1567
1563 # check username
1568 # check username
1564 ui.status(_("Checking username...\n"))
1569 ui.status(_("Checking username...\n"))
1565 try:
1570 try:
1566 ui.username()
1571 ui.username()
1567 except util.Abort, e:
1572 except util.Abort, e:
1568 ui.write(" %s\n" % e)
1573 ui.write(" %s\n" % e)
1569 ui.write(_(" (specify a username in your configuration file)\n"))
1574 ui.write(_(" (specify a username in your configuration file)\n"))
1570 problems += 1
1575 problems += 1
1571
1576
1572 if not problems:
1577 if not problems:
1573 ui.status(_("No problems detected\n"))
1578 ui.status(_("No problems detected\n"))
1574 else:
1579 else:
1575 ui.write(_("%s problems detected,"
1580 ui.write(_("%s problems detected,"
1576 " please check your install!\n") % problems)
1581 " please check your install!\n") % problems)
1577
1582
1578 return problems
1583 return problems
1579
1584
1580 def debugrename(ui, repo, file1, *pats, **opts):
1585 def debugrename(ui, repo, file1, *pats, **opts):
1581 """dump rename information"""
1586 """dump rename information"""
1582
1587
1583 ctx = cmdutil.revsingle(repo, opts.get('rev'))
1588 ctx = cmdutil.revsingle(repo, opts.get('rev'))
1584 m = cmdutil.match(repo, (file1,) + pats, opts)
1589 m = cmdutil.match(repo, (file1,) + pats, opts)
1585 for abs in ctx.walk(m):
1590 for abs in ctx.walk(m):
1586 fctx = ctx[abs]
1591 fctx = ctx[abs]
1587 o = fctx.filelog().renamed(fctx.filenode())
1592 o = fctx.filelog().renamed(fctx.filenode())
1588 rel = m.rel(abs)
1593 rel = m.rel(abs)
1589 if o:
1594 if o:
1590 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
1595 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
1591 else:
1596 else:
1592 ui.write(_("%s not renamed\n") % rel)
1597 ui.write(_("%s not renamed\n") % rel)
1593
1598
1594 def debugwalk(ui, repo, *pats, **opts):
1599 def debugwalk(ui, repo, *pats, **opts):
1595 """show how files match on given patterns"""
1600 """show how files match on given patterns"""
1596 m = cmdutil.match(repo, pats, opts)
1601 m = cmdutil.match(repo, pats, opts)
1597 items = list(repo.walk(m))
1602 items = list(repo.walk(m))
1598 if not items:
1603 if not items:
1599 return
1604 return
1600 fmt = 'f %%-%ds %%-%ds %%s' % (
1605 fmt = 'f %%-%ds %%-%ds %%s' % (
1601 max([len(abs) for abs in items]),
1606 max([len(abs) for abs in items]),
1602 max([len(m.rel(abs)) for abs in items]))
1607 max([len(m.rel(abs)) for abs in items]))
1603 for abs in items:
1608 for abs in items:
1604 line = fmt % (abs, m.rel(abs), m.exact(abs) and 'exact' or '')
1609 line = fmt % (abs, m.rel(abs), m.exact(abs) and 'exact' or '')
1605 ui.write("%s\n" % line.rstrip())
1610 ui.write("%s\n" % line.rstrip())
1606
1611
1607 def debugwireargs(ui, repopath, *vals, **opts):
1612 def debugwireargs(ui, repopath, *vals, **opts):
1608 repo = hg.repository(hg.remoteui(ui, opts), repopath)
1613 repo = hg.repository(hg.remoteui(ui, opts), repopath)
1609 for opt in remoteopts:
1614 for opt in remoteopts:
1610 del opts[opt[1]]
1615 del opts[opt[1]]
1611 args = {}
1616 args = {}
1612 for k, v in opts.iteritems():
1617 for k, v in opts.iteritems():
1613 if v:
1618 if v:
1614 args[k] = v
1619 args[k] = v
1615 # run twice to check that we don't mess up the stream for the next command
1620 # run twice to check that we don't mess up the stream for the next command
1616 res1 = repo.debugwireargs(*vals, **args)
1621 res1 = repo.debugwireargs(*vals, **args)
1617 res2 = repo.debugwireargs(*vals, **args)
1622 res2 = repo.debugwireargs(*vals, **args)
1618 ui.write("%s\n" % res1)
1623 ui.write("%s\n" % res1)
1619 if res1 != res2:
1624 if res1 != res2:
1620 ui.warn("%s\n" % res2)
1625 ui.warn("%s\n" % res2)
1621
1626
1622 def diff(ui, repo, *pats, **opts):
1627 def diff(ui, repo, *pats, **opts):
1623 """diff repository (or selected files)
1628 """diff repository (or selected files)
1624
1629
1625 Show differences between revisions for the specified files.
1630 Show differences between revisions for the specified files.
1626
1631
1627 Differences between files are shown using the unified diff format.
1632 Differences between files are shown using the unified diff format.
1628
1633
1629 .. note::
1634 .. note::
1630 diff may generate unexpected results for merges, as it will
1635 diff may generate unexpected results for merges, as it will
1631 default to comparing against the working directory's first
1636 default to comparing against the working directory's first
1632 parent changeset if no revisions are specified.
1637 parent changeset if no revisions are specified.
1633
1638
1634 When two revision arguments are given, then changes are shown
1639 When two revision arguments are given, then changes are shown
1635 between those revisions. If only one revision is specified then
1640 between those revisions. If only one revision is specified then
1636 that revision is compared to the working directory, and, when no
1641 that revision is compared to the working directory, and, when no
1637 revisions are specified, the working directory files are compared
1642 revisions are specified, the working directory files are compared
1638 to its parent.
1643 to its parent.
1639
1644
1640 Alternatively you can specify -c/--change with a revision to see
1645 Alternatively you can specify -c/--change with a revision to see
1641 the changes in that changeset relative to its first parent.
1646 the changes in that changeset relative to its first parent.
1642
1647
1643 Without the -a/--text option, diff will avoid generating diffs of
1648 Without the -a/--text option, diff will avoid generating diffs of
1644 files it detects as binary. With -a, diff will generate a diff
1649 files it detects as binary. With -a, diff will generate a diff
1645 anyway, probably with undesirable results.
1650 anyway, probably with undesirable results.
1646
1651
1647 Use the -g/--git option to generate diffs in the git extended diff
1652 Use the -g/--git option to generate diffs in the git extended diff
1648 format. For more information, read :hg:`help diffs`.
1653 format. For more information, read :hg:`help diffs`.
1649
1654
1650 Returns 0 on success.
1655 Returns 0 on success.
1651 """
1656 """
1652
1657
1653 revs = opts.get('rev')
1658 revs = opts.get('rev')
1654 change = opts.get('change')
1659 change = opts.get('change')
1655 stat = opts.get('stat')
1660 stat = opts.get('stat')
1656 reverse = opts.get('reverse')
1661 reverse = opts.get('reverse')
1657
1662
1658 if revs and change:
1663 if revs and change:
1659 msg = _('cannot specify --rev and --change at the same time')
1664 msg = _('cannot specify --rev and --change at the same time')
1660 raise util.Abort(msg)
1665 raise util.Abort(msg)
1661 elif change:
1666 elif change:
1662 node2 = cmdutil.revsingle(repo, change, None).node()
1667 node2 = cmdutil.revsingle(repo, change, None).node()
1663 node1 = repo[node2].p1().node()
1668 node1 = repo[node2].p1().node()
1664 else:
1669 else:
1665 node1, node2 = cmdutil.revpair(repo, revs)
1670 node1, node2 = cmdutil.revpair(repo, revs)
1666
1671
1667 if reverse:
1672 if reverse:
1668 node1, node2 = node2, node1
1673 node1, node2 = node2, node1
1669
1674
1670 diffopts = patch.diffopts(ui, opts)
1675 diffopts = patch.diffopts(ui, opts)
1671 m = cmdutil.match(repo, pats, opts)
1676 m = cmdutil.match(repo, pats, opts)
1672 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
1677 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
1673 listsubrepos=opts.get('subrepos'))
1678 listsubrepos=opts.get('subrepos'))
1674
1679
1675 def export(ui, repo, *changesets, **opts):
1680 def export(ui, repo, *changesets, **opts):
1676 """dump the header and diffs for one or more changesets
1681 """dump the header and diffs for one or more changesets
1677
1682
1678 Print the changeset header and diffs for one or more revisions.
1683 Print the changeset header and diffs for one or more revisions.
1679
1684
1680 The information shown in the changeset header is: author, date,
1685 The information shown in the changeset header is: author, date,
1681 branch name (if non-default), changeset hash, parent(s) and commit
1686 branch name (if non-default), changeset hash, parent(s) and commit
1682 comment.
1687 comment.
1683
1688
1684 .. note::
1689 .. note::
1685 export may generate unexpected diff output for merge
1690 export may generate unexpected diff output for merge
1686 changesets, as it will compare the merge changeset against its
1691 changesets, as it will compare the merge changeset against its
1687 first parent only.
1692 first parent only.
1688
1693
1689 Output may be to a file, in which case the name of the file is
1694 Output may be to a file, in which case the name of the file is
1690 given using a format string. The formatting rules are as follows:
1695 given using a format string. The formatting rules are as follows:
1691
1696
1692 :``%%``: literal "%" character
1697 :``%%``: literal "%" character
1693 :``%H``: changeset hash (40 hexadecimal digits)
1698 :``%H``: changeset hash (40 hexadecimal digits)
1694 :``%N``: number of patches being generated
1699 :``%N``: number of patches being generated
1695 :``%R``: changeset revision number
1700 :``%R``: changeset revision number
1696 :``%b``: basename of the exporting repository
1701 :``%b``: basename of the exporting repository
1697 :``%h``: short-form changeset hash (12 hexadecimal digits)
1702 :``%h``: short-form changeset hash (12 hexadecimal digits)
1698 :``%n``: zero-padded sequence number, starting at 1
1703 :``%n``: zero-padded sequence number, starting at 1
1699 :``%r``: zero-padded changeset revision number
1704 :``%r``: zero-padded changeset revision number
1700
1705
1701 Without the -a/--text option, export will avoid generating diffs
1706 Without the -a/--text option, export will avoid generating diffs
1702 of files it detects as binary. With -a, export will generate a
1707 of files it detects as binary. With -a, export will generate a
1703 diff anyway, probably with undesirable results.
1708 diff anyway, probably with undesirable results.
1704
1709
1705 Use the -g/--git option to generate diffs in the git extended diff
1710 Use the -g/--git option to generate diffs in the git extended diff
1706 format. See :hg:`help diffs` for more information.
1711 format. See :hg:`help diffs` for more information.
1707
1712
1708 With the --switch-parent option, the diff will be against the
1713 With the --switch-parent option, the diff will be against the
1709 second parent. It can be useful to review a merge.
1714 second parent. It can be useful to review a merge.
1710
1715
1711 Returns 0 on success.
1716 Returns 0 on success.
1712 """
1717 """
1713 changesets += tuple(opts.get('rev', []))
1718 changesets += tuple(opts.get('rev', []))
1714 if not changesets:
1719 if not changesets:
1715 raise util.Abort(_("export requires at least one changeset"))
1720 raise util.Abort(_("export requires at least one changeset"))
1716 revs = cmdutil.revrange(repo, changesets)
1721 revs = cmdutil.revrange(repo, changesets)
1717 if len(revs) > 1:
1722 if len(revs) > 1:
1718 ui.note(_('exporting patches:\n'))
1723 ui.note(_('exporting patches:\n'))
1719 else:
1724 else:
1720 ui.note(_('exporting patch:\n'))
1725 ui.note(_('exporting patch:\n'))
1721 cmdutil.export(repo, revs, template=opts.get('output'),
1726 cmdutil.export(repo, revs, template=opts.get('output'),
1722 switch_parent=opts.get('switch_parent'),
1727 switch_parent=opts.get('switch_parent'),
1723 opts=patch.diffopts(ui, opts))
1728 opts=patch.diffopts(ui, opts))
1724
1729
1725 def forget(ui, repo, *pats, **opts):
1730 def forget(ui, repo, *pats, **opts):
1726 """forget the specified files on the next commit
1731 """forget the specified files on the next commit
1727
1732
1728 Mark the specified files so they will no longer be tracked
1733 Mark the specified files so they will no longer be tracked
1729 after the next commit.
1734 after the next commit.
1730
1735
1731 This only removes files from the current branch, not from the
1736 This only removes files from the current branch, not from the
1732 entire project history, and it does not delete them from the
1737 entire project history, and it does not delete them from the
1733 working directory.
1738 working directory.
1734
1739
1735 To undo a forget before the next commit, see :hg:`add`.
1740 To undo a forget before the next commit, see :hg:`add`.
1736
1741
1737 Returns 0 on success.
1742 Returns 0 on success.
1738 """
1743 """
1739
1744
1740 if not pats:
1745 if not pats:
1741 raise util.Abort(_('no files specified'))
1746 raise util.Abort(_('no files specified'))
1742
1747
1743 m = cmdutil.match(repo, pats, opts)
1748 m = cmdutil.match(repo, pats, opts)
1744 s = repo.status(match=m, clean=True)
1749 s = repo.status(match=m, clean=True)
1745 forget = sorted(s[0] + s[1] + s[3] + s[6])
1750 forget = sorted(s[0] + s[1] + s[3] + s[6])
1746 errs = 0
1751 errs = 0
1747
1752
1748 for f in m.files():
1753 for f in m.files():
1749 if f not in repo.dirstate and not os.path.isdir(m.rel(f)):
1754 if f not in repo.dirstate and not os.path.isdir(m.rel(f)):
1750 ui.warn(_('not removing %s: file is already untracked\n')
1755 ui.warn(_('not removing %s: file is already untracked\n')
1751 % m.rel(f))
1756 % m.rel(f))
1752 errs = 1
1757 errs = 1
1753
1758
1754 for f in forget:
1759 for f in forget:
1755 if ui.verbose or not m.exact(f):
1760 if ui.verbose or not m.exact(f):
1756 ui.status(_('removing %s\n') % m.rel(f))
1761 ui.status(_('removing %s\n') % m.rel(f))
1757
1762
1758 repo[None].remove(forget, unlink=False)
1763 repo[None].remove(forget, unlink=False)
1759 return errs
1764 return errs
1760
1765
1761 def grep(ui, repo, pattern, *pats, **opts):
1766 def grep(ui, repo, pattern, *pats, **opts):
1762 """search for a pattern in specified files and revisions
1767 """search for a pattern in specified files and revisions
1763
1768
1764 Search revisions of files for a regular expression.
1769 Search revisions of files for a regular expression.
1765
1770
1766 This command behaves differently than Unix grep. It only accepts
1771 This command behaves differently than Unix grep. It only accepts
1767 Python/Perl regexps. It searches repository history, not the
1772 Python/Perl regexps. It searches repository history, not the
1768 working directory. It always prints the revision number in which a
1773 working directory. It always prints the revision number in which a
1769 match appears.
1774 match appears.
1770
1775
1771 By default, grep only prints output for the first revision of a
1776 By default, grep only prints output for the first revision of a
1772 file in which it finds a match. To get it to print every revision
1777 file in which it finds a match. To get it to print every revision
1773 that contains a change in match status ("-" for a match that
1778 that contains a change in match status ("-" for a match that
1774 becomes a non-match, or "+" for a non-match that becomes a match),
1779 becomes a non-match, or "+" for a non-match that becomes a match),
1775 use the --all flag.
1780 use the --all flag.
1776
1781
1777 Returns 0 if a match is found, 1 otherwise.
1782 Returns 0 if a match is found, 1 otherwise.
1778 """
1783 """
1779 reflags = 0
1784 reflags = 0
1780 if opts.get('ignore_case'):
1785 if opts.get('ignore_case'):
1781 reflags |= re.I
1786 reflags |= re.I
1782 try:
1787 try:
1783 regexp = re.compile(pattern, reflags)
1788 regexp = re.compile(pattern, reflags)
1784 except re.error, inst:
1789 except re.error, inst:
1785 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
1790 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
1786 return 1
1791 return 1
1787 sep, eol = ':', '\n'
1792 sep, eol = ':', '\n'
1788 if opts.get('print0'):
1793 if opts.get('print0'):
1789 sep = eol = '\0'
1794 sep = eol = '\0'
1790
1795
1791 getfile = util.lrucachefunc(repo.file)
1796 getfile = util.lrucachefunc(repo.file)
1792
1797
1793 def matchlines(body):
1798 def matchlines(body):
1794 begin = 0
1799 begin = 0
1795 linenum = 0
1800 linenum = 0
1796 while True:
1801 while True:
1797 match = regexp.search(body, begin)
1802 match = regexp.search(body, begin)
1798 if not match:
1803 if not match:
1799 break
1804 break
1800 mstart, mend = match.span()
1805 mstart, mend = match.span()
1801 linenum += body.count('\n', begin, mstart) + 1
1806 linenum += body.count('\n', begin, mstart) + 1
1802 lstart = body.rfind('\n', begin, mstart) + 1 or begin
1807 lstart = body.rfind('\n', begin, mstart) + 1 or begin
1803 begin = body.find('\n', mend) + 1 or len(body)
1808 begin = body.find('\n', mend) + 1 or len(body)
1804 lend = begin - 1
1809 lend = begin - 1
1805 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
1810 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
1806
1811
1807 class linestate(object):
1812 class linestate(object):
1808 def __init__(self, line, linenum, colstart, colend):
1813 def __init__(self, line, linenum, colstart, colend):
1809 self.line = line
1814 self.line = line
1810 self.linenum = linenum
1815 self.linenum = linenum
1811 self.colstart = colstart
1816 self.colstart = colstart
1812 self.colend = colend
1817 self.colend = colend
1813
1818
1814 def __hash__(self):
1819 def __hash__(self):
1815 return hash((self.linenum, self.line))
1820 return hash((self.linenum, self.line))
1816
1821
1817 def __eq__(self, other):
1822 def __eq__(self, other):
1818 return self.line == other.line
1823 return self.line == other.line
1819
1824
1820 matches = {}
1825 matches = {}
1821 copies = {}
1826 copies = {}
1822 def grepbody(fn, rev, body):
1827 def grepbody(fn, rev, body):
1823 matches[rev].setdefault(fn, [])
1828 matches[rev].setdefault(fn, [])
1824 m = matches[rev][fn]
1829 m = matches[rev][fn]
1825 for lnum, cstart, cend, line in matchlines(body):
1830 for lnum, cstart, cend, line in matchlines(body):
1826 s = linestate(line, lnum, cstart, cend)
1831 s = linestate(line, lnum, cstart, cend)
1827 m.append(s)
1832 m.append(s)
1828
1833
1829 def difflinestates(a, b):
1834 def difflinestates(a, b):
1830 sm = difflib.SequenceMatcher(None, a, b)
1835 sm = difflib.SequenceMatcher(None, a, b)
1831 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
1836 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
1832 if tag == 'insert':
1837 if tag == 'insert':
1833 for i in xrange(blo, bhi):
1838 for i in xrange(blo, bhi):
1834 yield ('+', b[i])
1839 yield ('+', b[i])
1835 elif tag == 'delete':
1840 elif tag == 'delete':
1836 for i in xrange(alo, ahi):
1841 for i in xrange(alo, ahi):
1837 yield ('-', a[i])
1842 yield ('-', a[i])
1838 elif tag == 'replace':
1843 elif tag == 'replace':
1839 for i in xrange(alo, ahi):
1844 for i in xrange(alo, ahi):
1840 yield ('-', a[i])
1845 yield ('-', a[i])
1841 for i in xrange(blo, bhi):
1846 for i in xrange(blo, bhi):
1842 yield ('+', b[i])
1847 yield ('+', b[i])
1843
1848
1844 def display(fn, ctx, pstates, states):
1849 def display(fn, ctx, pstates, states):
1845 rev = ctx.rev()
1850 rev = ctx.rev()
1846 datefunc = ui.quiet and util.shortdate or util.datestr
1851 datefunc = ui.quiet and util.shortdate or util.datestr
1847 found = False
1852 found = False
1848 filerevmatches = {}
1853 filerevmatches = {}
1849 def binary():
1854 def binary():
1850 flog = getfile(fn)
1855 flog = getfile(fn)
1851 return util.binary(flog.read(ctx.filenode(fn)))
1856 return util.binary(flog.read(ctx.filenode(fn)))
1852
1857
1853 if opts.get('all'):
1858 if opts.get('all'):
1854 iter = difflinestates(pstates, states)
1859 iter = difflinestates(pstates, states)
1855 else:
1860 else:
1856 iter = [('', l) for l in states]
1861 iter = [('', l) for l in states]
1857 for change, l in iter:
1862 for change, l in iter:
1858 cols = [fn, str(rev)]
1863 cols = [fn, str(rev)]
1859 before, match, after = None, None, None
1864 before, match, after = None, None, None
1860 if opts.get('line_number'):
1865 if opts.get('line_number'):
1861 cols.append(str(l.linenum))
1866 cols.append(str(l.linenum))
1862 if opts.get('all'):
1867 if opts.get('all'):
1863 cols.append(change)
1868 cols.append(change)
1864 if opts.get('user'):
1869 if opts.get('user'):
1865 cols.append(ui.shortuser(ctx.user()))
1870 cols.append(ui.shortuser(ctx.user()))
1866 if opts.get('date'):
1871 if opts.get('date'):
1867 cols.append(datefunc(ctx.date()))
1872 cols.append(datefunc(ctx.date()))
1868 if opts.get('files_with_matches'):
1873 if opts.get('files_with_matches'):
1869 c = (fn, rev)
1874 c = (fn, rev)
1870 if c in filerevmatches:
1875 if c in filerevmatches:
1871 continue
1876 continue
1872 filerevmatches[c] = 1
1877 filerevmatches[c] = 1
1873 else:
1878 else:
1874 before = l.line[:l.colstart]
1879 before = l.line[:l.colstart]
1875 match = l.line[l.colstart:l.colend]
1880 match = l.line[l.colstart:l.colend]
1876 after = l.line[l.colend:]
1881 after = l.line[l.colend:]
1877 ui.write(sep.join(cols))
1882 ui.write(sep.join(cols))
1878 if before is not None:
1883 if before is not None:
1879 if not opts.get('text') and binary():
1884 if not opts.get('text') and binary():
1880 ui.write(sep + " Binary file matches")
1885 ui.write(sep + " Binary file matches")
1881 else:
1886 else:
1882 ui.write(sep + before)
1887 ui.write(sep + before)
1883 ui.write(match, label='grep.match')
1888 ui.write(match, label='grep.match')
1884 ui.write(after)
1889 ui.write(after)
1885 ui.write(eol)
1890 ui.write(eol)
1886 found = True
1891 found = True
1887 return found
1892 return found
1888
1893
1889 skip = {}
1894 skip = {}
1890 revfiles = {}
1895 revfiles = {}
1891 matchfn = cmdutil.match(repo, pats, opts)
1896 matchfn = cmdutil.match(repo, pats, opts)
1892 found = False
1897 found = False
1893 follow = opts.get('follow')
1898 follow = opts.get('follow')
1894
1899
1895 def prep(ctx, fns):
1900 def prep(ctx, fns):
1896 rev = ctx.rev()
1901 rev = ctx.rev()
1897 pctx = ctx.p1()
1902 pctx = ctx.p1()
1898 parent = pctx.rev()
1903 parent = pctx.rev()
1899 matches.setdefault(rev, {})
1904 matches.setdefault(rev, {})
1900 matches.setdefault(parent, {})
1905 matches.setdefault(parent, {})
1901 files = revfiles.setdefault(rev, [])
1906 files = revfiles.setdefault(rev, [])
1902 for fn in fns:
1907 for fn in fns:
1903 flog = getfile(fn)
1908 flog = getfile(fn)
1904 try:
1909 try:
1905 fnode = ctx.filenode(fn)
1910 fnode = ctx.filenode(fn)
1906 except error.LookupError:
1911 except error.LookupError:
1907 continue
1912 continue
1908
1913
1909 copied = flog.renamed(fnode)
1914 copied = flog.renamed(fnode)
1910 copy = follow and copied and copied[0]
1915 copy = follow and copied and copied[0]
1911 if copy:
1916 if copy:
1912 copies.setdefault(rev, {})[fn] = copy
1917 copies.setdefault(rev, {})[fn] = copy
1913 if fn in skip:
1918 if fn in skip:
1914 if copy:
1919 if copy:
1915 skip[copy] = True
1920 skip[copy] = True
1916 continue
1921 continue
1917 files.append(fn)
1922 files.append(fn)
1918
1923
1919 if fn not in matches[rev]:
1924 if fn not in matches[rev]:
1920 grepbody(fn, rev, flog.read(fnode))
1925 grepbody(fn, rev, flog.read(fnode))
1921
1926
1922 pfn = copy or fn
1927 pfn = copy or fn
1923 if pfn not in matches[parent]:
1928 if pfn not in matches[parent]:
1924 try:
1929 try:
1925 fnode = pctx.filenode(pfn)
1930 fnode = pctx.filenode(pfn)
1926 grepbody(pfn, parent, flog.read(fnode))
1931 grepbody(pfn, parent, flog.read(fnode))
1927 except error.LookupError:
1932 except error.LookupError:
1928 pass
1933 pass
1929
1934
1930 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
1935 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
1931 rev = ctx.rev()
1936 rev = ctx.rev()
1932 parent = ctx.p1().rev()
1937 parent = ctx.p1().rev()
1933 for fn in sorted(revfiles.get(rev, [])):
1938 for fn in sorted(revfiles.get(rev, [])):
1934 states = matches[rev][fn]
1939 states = matches[rev][fn]
1935 copy = copies.get(rev, {}).get(fn)
1940 copy = copies.get(rev, {}).get(fn)
1936 if fn in skip:
1941 if fn in skip:
1937 if copy:
1942 if copy:
1938 skip[copy] = True
1943 skip[copy] = True
1939 continue
1944 continue
1940 pstates = matches.get(parent, {}).get(copy or fn, [])
1945 pstates = matches.get(parent, {}).get(copy or fn, [])
1941 if pstates or states:
1946 if pstates or states:
1942 r = display(fn, ctx, pstates, states)
1947 r = display(fn, ctx, pstates, states)
1943 found = found or r
1948 found = found or r
1944 if r and not opts.get('all'):
1949 if r and not opts.get('all'):
1945 skip[fn] = True
1950 skip[fn] = True
1946 if copy:
1951 if copy:
1947 skip[copy] = True
1952 skip[copy] = True
1948 del matches[rev]
1953 del matches[rev]
1949 del revfiles[rev]
1954 del revfiles[rev]
1950
1955
1951 return not found
1956 return not found
1952
1957
1953 def heads(ui, repo, *branchrevs, **opts):
1958 def heads(ui, repo, *branchrevs, **opts):
1954 """show current repository heads or show branch heads
1959 """show current repository heads or show branch heads
1955
1960
1956 With no arguments, show all repository branch heads.
1961 With no arguments, show all repository branch heads.
1957
1962
1958 Repository "heads" are changesets with no child changesets. They are
1963 Repository "heads" are changesets with no child changesets. They are
1959 where development generally takes place and are the usual targets
1964 where development generally takes place and are the usual targets
1960 for update and merge operations. Branch heads are changesets that have
1965 for update and merge operations. Branch heads are changesets that have
1961 no child changeset on the same branch.
1966 no child changeset on the same branch.
1962
1967
1963 If one or more REVs are given, only branch heads on the branches
1968 If one or more REVs are given, only branch heads on the branches
1964 associated with the specified changesets are shown.
1969 associated with the specified changesets are shown.
1965
1970
1966 If -c/--closed is specified, also show branch heads marked closed
1971 If -c/--closed is specified, also show branch heads marked closed
1967 (see :hg:`commit --close-branch`).
1972 (see :hg:`commit --close-branch`).
1968
1973
1969 If STARTREV is specified, only those heads that are descendants of
1974 If STARTREV is specified, only those heads that are descendants of
1970 STARTREV will be displayed.
1975 STARTREV will be displayed.
1971
1976
1972 If -t/--topo is specified, named branch mechanics will be ignored and only
1977 If -t/--topo is specified, named branch mechanics will be ignored and only
1973 changesets without children will be shown.
1978 changesets without children will be shown.
1974
1979
1975 Returns 0 if matching heads are found, 1 if not.
1980 Returns 0 if matching heads are found, 1 if not.
1976 """
1981 """
1977
1982
1978 start = None
1983 start = None
1979 if 'rev' in opts:
1984 if 'rev' in opts:
1980 start = cmdutil.revsingle(repo, opts['rev'], None).node()
1985 start = cmdutil.revsingle(repo, opts['rev'], None).node()
1981
1986
1982 if opts.get('topo'):
1987 if opts.get('topo'):
1983 heads = [repo[h] for h in repo.heads(start)]
1988 heads = [repo[h] for h in repo.heads(start)]
1984 else:
1989 else:
1985 heads = []
1990 heads = []
1986 for b, ls in repo.branchmap().iteritems():
1991 for b, ls in repo.branchmap().iteritems():
1987 if start is None:
1992 if start is None:
1988 heads += [repo[h] for h in ls]
1993 heads += [repo[h] for h in ls]
1989 continue
1994 continue
1990 startrev = repo.changelog.rev(start)
1995 startrev = repo.changelog.rev(start)
1991 descendants = set(repo.changelog.descendants(startrev))
1996 descendants = set(repo.changelog.descendants(startrev))
1992 descendants.add(startrev)
1997 descendants.add(startrev)
1993 rev = repo.changelog.rev
1998 rev = repo.changelog.rev
1994 heads += [repo[h] for h in ls if rev(h) in descendants]
1999 heads += [repo[h] for h in ls if rev(h) in descendants]
1995
2000
1996 if branchrevs:
2001 if branchrevs:
1997 branches = set(repo[br].branch() for br in branchrevs)
2002 branches = set(repo[br].branch() for br in branchrevs)
1998 heads = [h for h in heads if h.branch() in branches]
2003 heads = [h for h in heads if h.branch() in branches]
1999
2004
2000 if not opts.get('closed'):
2005 if not opts.get('closed'):
2001 heads = [h for h in heads if not h.extra().get('close')]
2006 heads = [h for h in heads if not h.extra().get('close')]
2002
2007
2003 if opts.get('active') and branchrevs:
2008 if opts.get('active') and branchrevs:
2004 dagheads = repo.heads(start)
2009 dagheads = repo.heads(start)
2005 heads = [h for h in heads if h.node() in dagheads]
2010 heads = [h for h in heads if h.node() in dagheads]
2006
2011
2007 if branchrevs:
2012 if branchrevs:
2008 haveheads = set(h.branch() for h in heads)
2013 haveheads = set(h.branch() for h in heads)
2009 if branches - haveheads:
2014 if branches - haveheads:
2010 headless = ', '.join(b for b in branches - haveheads)
2015 headless = ', '.join(b for b in branches - haveheads)
2011 msg = _('no open branch heads found on branches %s')
2016 msg = _('no open branch heads found on branches %s')
2012 if opts.get('rev'):
2017 if opts.get('rev'):
2013 msg += _(' (started at %s)' % opts['rev'])
2018 msg += _(' (started at %s)' % opts['rev'])
2014 ui.warn((msg + '\n') % headless)
2019 ui.warn((msg + '\n') % headless)
2015
2020
2016 if not heads:
2021 if not heads:
2017 return 1
2022 return 1
2018
2023
2019 heads = sorted(heads, key=lambda x: -x.rev())
2024 heads = sorted(heads, key=lambda x: -x.rev())
2020 displayer = cmdutil.show_changeset(ui, repo, opts)
2025 displayer = cmdutil.show_changeset(ui, repo, opts)
2021 for ctx in heads:
2026 for ctx in heads:
2022 displayer.show(ctx)
2027 displayer.show(ctx)
2023 displayer.close()
2028 displayer.close()
2024
2029
2025 def help_(ui, name=None, with_version=False, unknowncmd=False, full=True):
2030 def help_(ui, name=None, with_version=False, unknowncmd=False, full=True):
2026 """show help for a given topic or a help overview
2031 """show help for a given topic or a help overview
2027
2032
2028 With no arguments, print a list of commands with short help messages.
2033 With no arguments, print a list of commands with short help messages.
2029
2034
2030 Given a topic, extension, or command name, print help for that
2035 Given a topic, extension, or command name, print help for that
2031 topic.
2036 topic.
2032
2037
2033 Returns 0 if successful.
2038 Returns 0 if successful.
2034 """
2039 """
2035 option_lists = []
2040 option_lists = []
2036 textwidth = min(ui.termwidth(), 80) - 2
2041 textwidth = min(ui.termwidth(), 80) - 2
2037
2042
2038 def addglobalopts(aliases):
2043 def addglobalopts(aliases):
2039 if ui.verbose:
2044 if ui.verbose:
2040 option_lists.append((_("global options:"), globalopts))
2045 option_lists.append((_("global options:"), globalopts))
2041 if name == 'shortlist':
2046 if name == 'shortlist':
2042 option_lists.append((_('use "hg help" for the full list '
2047 option_lists.append((_('use "hg help" for the full list '
2043 'of commands'), ()))
2048 'of commands'), ()))
2044 else:
2049 else:
2045 if name == 'shortlist':
2050 if name == 'shortlist':
2046 msg = _('use "hg help" for the full list of commands '
2051 msg = _('use "hg help" for the full list of commands '
2047 'or "hg -v" for details')
2052 'or "hg -v" for details')
2048 elif name and not full:
2053 elif name and not full:
2049 msg = _('use "hg help %s" to show the full help text' % name)
2054 msg = _('use "hg help %s" to show the full help text' % name)
2050 elif aliases:
2055 elif aliases:
2051 msg = _('use "hg -v help%s" to show builtin aliases and '
2056 msg = _('use "hg -v help%s" to show builtin aliases and '
2052 'global options') % (name and " " + name or "")
2057 'global options') % (name and " " + name or "")
2053 else:
2058 else:
2054 msg = _('use "hg -v help %s" to show global options') % name
2059 msg = _('use "hg -v help %s" to show global options') % name
2055 option_lists.append((msg, ()))
2060 option_lists.append((msg, ()))
2056
2061
2057 def helpcmd(name):
2062 def helpcmd(name):
2058 if with_version:
2063 if with_version:
2059 version_(ui)
2064 version_(ui)
2060 ui.write('\n')
2065 ui.write('\n')
2061
2066
2062 try:
2067 try:
2063 aliases, entry = cmdutil.findcmd(name, table, strict=unknowncmd)
2068 aliases, entry = cmdutil.findcmd(name, table, strict=unknowncmd)
2064 except error.AmbiguousCommand, inst:
2069 except error.AmbiguousCommand, inst:
2065 # py3k fix: except vars can't be used outside the scope of the
2070 # py3k fix: except vars can't be used outside the scope of the
2066 # except block, nor can be used inside a lambda. python issue4617
2071 # except block, nor can be used inside a lambda. python issue4617
2067 prefix = inst.args[0]
2072 prefix = inst.args[0]
2068 select = lambda c: c.lstrip('^').startswith(prefix)
2073 select = lambda c: c.lstrip('^').startswith(prefix)
2069 helplist(_('list of commands:\n\n'), select)
2074 helplist(_('list of commands:\n\n'), select)
2070 return
2075 return
2071
2076
2072 # check if it's an invalid alias and display its error if it is
2077 # check if it's an invalid alias and display its error if it is
2073 if getattr(entry[0], 'badalias', False):
2078 if getattr(entry[0], 'badalias', False):
2074 if not unknowncmd:
2079 if not unknowncmd:
2075 entry[0](ui)
2080 entry[0](ui)
2076 return
2081 return
2077
2082
2078 # synopsis
2083 # synopsis
2079 if len(entry) > 2:
2084 if len(entry) > 2:
2080 if entry[2].startswith('hg'):
2085 if entry[2].startswith('hg'):
2081 ui.write("%s\n" % entry[2])
2086 ui.write("%s\n" % entry[2])
2082 else:
2087 else:
2083 ui.write('hg %s %s\n' % (aliases[0], entry[2]))
2088 ui.write('hg %s %s\n' % (aliases[0], entry[2]))
2084 else:
2089 else:
2085 ui.write('hg %s\n' % aliases[0])
2090 ui.write('hg %s\n' % aliases[0])
2086
2091
2087 # aliases
2092 # aliases
2088 if full and not ui.quiet and len(aliases) > 1:
2093 if full and not ui.quiet and len(aliases) > 1:
2089 ui.write(_("\naliases: %s\n") % ', '.join(aliases[1:]))
2094 ui.write(_("\naliases: %s\n") % ', '.join(aliases[1:]))
2090
2095
2091 # description
2096 # description
2092 doc = gettext(entry[0].__doc__)
2097 doc = gettext(entry[0].__doc__)
2093 if not doc:
2098 if not doc:
2094 doc = _("(no help text available)")
2099 doc = _("(no help text available)")
2095 if hasattr(entry[0], 'definition'): # aliased command
2100 if hasattr(entry[0], 'definition'): # aliased command
2096 if entry[0].definition.startswith('!'): # shell alias
2101 if entry[0].definition.startswith('!'): # shell alias
2097 doc = _('shell alias for::\n\n %s') % entry[0].definition[1:]
2102 doc = _('shell alias for::\n\n %s') % entry[0].definition[1:]
2098 else:
2103 else:
2099 doc = _('alias for: hg %s\n\n%s') % (entry[0].definition, doc)
2104 doc = _('alias for: hg %s\n\n%s') % (entry[0].definition, doc)
2100 if ui.quiet or not full:
2105 if ui.quiet or not full:
2101 doc = doc.splitlines()[0]
2106 doc = doc.splitlines()[0]
2102 keep = ui.verbose and ['verbose'] or []
2107 keep = ui.verbose and ['verbose'] or []
2103 formatted, pruned = minirst.format(doc, textwidth, keep=keep)
2108 formatted, pruned = minirst.format(doc, textwidth, keep=keep)
2104 ui.write("\n%s\n" % formatted)
2109 ui.write("\n%s\n" % formatted)
2105 if pruned:
2110 if pruned:
2106 ui.write(_('\nuse "hg -v help %s" to show verbose help\n') % name)
2111 ui.write(_('\nuse "hg -v help %s" to show verbose help\n') % name)
2107
2112
2108 if not ui.quiet:
2113 if not ui.quiet:
2109 # options
2114 # options
2110 if entry[1]:
2115 if entry[1]:
2111 option_lists.append((_("options:\n"), entry[1]))
2116 option_lists.append((_("options:\n"), entry[1]))
2112
2117
2113 addglobalopts(False)
2118 addglobalopts(False)
2114
2119
2115 def helplist(header, select=None):
2120 def helplist(header, select=None):
2116 h = {}
2121 h = {}
2117 cmds = {}
2122 cmds = {}
2118 for c, e in table.iteritems():
2123 for c, e in table.iteritems():
2119 f = c.split("|", 1)[0]
2124 f = c.split("|", 1)[0]
2120 if select and not select(f):
2125 if select and not select(f):
2121 continue
2126 continue
2122 if (not select and name != 'shortlist' and
2127 if (not select and name != 'shortlist' and
2123 e[0].__module__ != __name__):
2128 e[0].__module__ != __name__):
2124 continue
2129 continue
2125 if name == "shortlist" and not f.startswith("^"):
2130 if name == "shortlist" and not f.startswith("^"):
2126 continue
2131 continue
2127 f = f.lstrip("^")
2132 f = f.lstrip("^")
2128 if not ui.debugflag and f.startswith("debug"):
2133 if not ui.debugflag and f.startswith("debug"):
2129 continue
2134 continue
2130 doc = e[0].__doc__
2135 doc = e[0].__doc__
2131 if doc and 'DEPRECATED' in doc and not ui.verbose:
2136 if doc and 'DEPRECATED' in doc and not ui.verbose:
2132 continue
2137 continue
2133 doc = gettext(doc)
2138 doc = gettext(doc)
2134 if not doc:
2139 if not doc:
2135 doc = _("(no help text available)")
2140 doc = _("(no help text available)")
2136 h[f] = doc.splitlines()[0].rstrip()
2141 h[f] = doc.splitlines()[0].rstrip()
2137 cmds[f] = c.lstrip("^")
2142 cmds[f] = c.lstrip("^")
2138
2143
2139 if not h:
2144 if not h:
2140 ui.status(_('no commands defined\n'))
2145 ui.status(_('no commands defined\n'))
2141 return
2146 return
2142
2147
2143 ui.status(header)
2148 ui.status(header)
2144 fns = sorted(h)
2149 fns = sorted(h)
2145 m = max(map(len, fns))
2150 m = max(map(len, fns))
2146 for f in fns:
2151 for f in fns:
2147 if ui.verbose:
2152 if ui.verbose:
2148 commands = cmds[f].replace("|",", ")
2153 commands = cmds[f].replace("|",", ")
2149 ui.write(" %s:\n %s\n"%(commands, h[f]))
2154 ui.write(" %s:\n %s\n"%(commands, h[f]))
2150 else:
2155 else:
2151 ui.write('%s\n' % (util.wrap(h[f], textwidth,
2156 ui.write('%s\n' % (util.wrap(h[f], textwidth,
2152 initindent=' %-*s ' % (m, f),
2157 initindent=' %-*s ' % (m, f),
2153 hangindent=' ' * (m + 4))))
2158 hangindent=' ' * (m + 4))))
2154
2159
2155 if not ui.quiet:
2160 if not ui.quiet:
2156 addglobalopts(True)
2161 addglobalopts(True)
2157
2162
2158 def helptopic(name):
2163 def helptopic(name):
2159 for names, header, doc in help.helptable:
2164 for names, header, doc in help.helptable:
2160 if name in names:
2165 if name in names:
2161 break
2166 break
2162 else:
2167 else:
2163 raise error.UnknownCommand(name)
2168 raise error.UnknownCommand(name)
2164
2169
2165 # description
2170 # description
2166 if not doc:
2171 if not doc:
2167 doc = _("(no help text available)")
2172 doc = _("(no help text available)")
2168 if hasattr(doc, '__call__'):
2173 if hasattr(doc, '__call__'):
2169 doc = doc()
2174 doc = doc()
2170
2175
2171 ui.write("%s\n\n" % header)
2176 ui.write("%s\n\n" % header)
2172 ui.write("%s\n" % minirst.format(doc, textwidth, indent=4))
2177 ui.write("%s\n" % minirst.format(doc, textwidth, indent=4))
2173
2178
2174 def helpext(name):
2179 def helpext(name):
2175 try:
2180 try:
2176 mod = extensions.find(name)
2181 mod = extensions.find(name)
2177 doc = gettext(mod.__doc__) or _('no help text available')
2182 doc = gettext(mod.__doc__) or _('no help text available')
2178 except KeyError:
2183 except KeyError:
2179 mod = None
2184 mod = None
2180 doc = extensions.disabledext(name)
2185 doc = extensions.disabledext(name)
2181 if not doc:
2186 if not doc:
2182 raise error.UnknownCommand(name)
2187 raise error.UnknownCommand(name)
2183
2188
2184 if '\n' not in doc:
2189 if '\n' not in doc:
2185 head, tail = doc, ""
2190 head, tail = doc, ""
2186 else:
2191 else:
2187 head, tail = doc.split('\n', 1)
2192 head, tail = doc.split('\n', 1)
2188 ui.write(_('%s extension - %s\n\n') % (name.split('.')[-1], head))
2193 ui.write(_('%s extension - %s\n\n') % (name.split('.')[-1], head))
2189 if tail:
2194 if tail:
2190 ui.write(minirst.format(tail, textwidth))
2195 ui.write(minirst.format(tail, textwidth))
2191 ui.status('\n\n')
2196 ui.status('\n\n')
2192
2197
2193 if mod:
2198 if mod:
2194 try:
2199 try:
2195 ct = mod.cmdtable
2200 ct = mod.cmdtable
2196 except AttributeError:
2201 except AttributeError:
2197 ct = {}
2202 ct = {}
2198 modcmds = set([c.split('|', 1)[0] for c in ct])
2203 modcmds = set([c.split('|', 1)[0] for c in ct])
2199 helplist(_('list of commands:\n\n'), modcmds.__contains__)
2204 helplist(_('list of commands:\n\n'), modcmds.__contains__)
2200 else:
2205 else:
2201 ui.write(_('use "hg help extensions" for information on enabling '
2206 ui.write(_('use "hg help extensions" for information on enabling '
2202 'extensions\n'))
2207 'extensions\n'))
2203
2208
2204 def helpextcmd(name):
2209 def helpextcmd(name):
2205 cmd, ext, mod = extensions.disabledcmd(ui, name, ui.config('ui', 'strict'))
2210 cmd, ext, mod = extensions.disabledcmd(ui, name, ui.config('ui', 'strict'))
2206 doc = gettext(mod.__doc__).splitlines()[0]
2211 doc = gettext(mod.__doc__).splitlines()[0]
2207
2212
2208 msg = help.listexts(_("'%s' is provided by the following "
2213 msg = help.listexts(_("'%s' is provided by the following "
2209 "extension:") % cmd, {ext: doc}, len(ext),
2214 "extension:") % cmd, {ext: doc}, len(ext),
2210 indent=4)
2215 indent=4)
2211 ui.write(minirst.format(msg, textwidth))
2216 ui.write(minirst.format(msg, textwidth))
2212 ui.write('\n\n')
2217 ui.write('\n\n')
2213 ui.write(_('use "hg help extensions" for information on enabling '
2218 ui.write(_('use "hg help extensions" for information on enabling '
2214 'extensions\n'))
2219 'extensions\n'))
2215
2220
2216 help.addtopichook('revsets', revset.makedoc)
2221 help.addtopichook('revsets', revset.makedoc)
2217 help.addtopichook('templates', templatekw.makedoc)
2222 help.addtopichook('templates', templatekw.makedoc)
2218 help.addtopichook('templates', templatefilters.makedoc)
2223 help.addtopichook('templates', templatefilters.makedoc)
2219
2224
2220 if name and name != 'shortlist':
2225 if name and name != 'shortlist':
2221 i = None
2226 i = None
2222 if unknowncmd:
2227 if unknowncmd:
2223 queries = (helpextcmd,)
2228 queries = (helpextcmd,)
2224 else:
2229 else:
2225 queries = (helptopic, helpcmd, helpext, helpextcmd)
2230 queries = (helptopic, helpcmd, helpext, helpextcmd)
2226 for f in queries:
2231 for f in queries:
2227 try:
2232 try:
2228 f(name)
2233 f(name)
2229 i = None
2234 i = None
2230 break
2235 break
2231 except error.UnknownCommand, inst:
2236 except error.UnknownCommand, inst:
2232 i = inst
2237 i = inst
2233 if i:
2238 if i:
2234 raise i
2239 raise i
2235
2240
2236 else:
2241 else:
2237 # program name
2242 # program name
2238 if ui.verbose or with_version:
2243 if ui.verbose or with_version:
2239 version_(ui)
2244 version_(ui)
2240 else:
2245 else:
2241 ui.status(_("Mercurial Distributed SCM\n"))
2246 ui.status(_("Mercurial Distributed SCM\n"))
2242 ui.status('\n')
2247 ui.status('\n')
2243
2248
2244 # list of commands
2249 # list of commands
2245 if name == "shortlist":
2250 if name == "shortlist":
2246 header = _('basic commands:\n\n')
2251 header = _('basic commands:\n\n')
2247 else:
2252 else:
2248 header = _('list of commands:\n\n')
2253 header = _('list of commands:\n\n')
2249
2254
2250 helplist(header)
2255 helplist(header)
2251 if name != 'shortlist':
2256 if name != 'shortlist':
2252 exts, maxlength = extensions.enabled()
2257 exts, maxlength = extensions.enabled()
2253 text = help.listexts(_('enabled extensions:'), exts, maxlength)
2258 text = help.listexts(_('enabled extensions:'), exts, maxlength)
2254 if text:
2259 if text:
2255 ui.write("\n%s\n" % minirst.format(text, textwidth))
2260 ui.write("\n%s\n" % minirst.format(text, textwidth))
2256
2261
2257 # list all option lists
2262 # list all option lists
2258 opt_output = []
2263 opt_output = []
2259 multioccur = False
2264 multioccur = False
2260 for title, options in option_lists:
2265 for title, options in option_lists:
2261 opt_output.append(("\n%s" % title, None))
2266 opt_output.append(("\n%s" % title, None))
2262 for option in options:
2267 for option in options:
2263 if len(option) == 5:
2268 if len(option) == 5:
2264 shortopt, longopt, default, desc, optlabel = option
2269 shortopt, longopt, default, desc, optlabel = option
2265 else:
2270 else:
2266 shortopt, longopt, default, desc = option
2271 shortopt, longopt, default, desc = option
2267 optlabel = _("VALUE") # default label
2272 optlabel = _("VALUE") # default label
2268
2273
2269 if _("DEPRECATED") in desc and not ui.verbose:
2274 if _("DEPRECATED") in desc and not ui.verbose:
2270 continue
2275 continue
2271 if isinstance(default, list):
2276 if isinstance(default, list):
2272 numqualifier = " %s [+]" % optlabel
2277 numqualifier = " %s [+]" % optlabel
2273 multioccur = True
2278 multioccur = True
2274 elif (default is not None) and not isinstance(default, bool):
2279 elif (default is not None) and not isinstance(default, bool):
2275 numqualifier = " %s" % optlabel
2280 numqualifier = " %s" % optlabel
2276 else:
2281 else:
2277 numqualifier = ""
2282 numqualifier = ""
2278 opt_output.append(("%2s%s" %
2283 opt_output.append(("%2s%s" %
2279 (shortopt and "-%s" % shortopt,
2284 (shortopt and "-%s" % shortopt,
2280 longopt and " --%s%s" %
2285 longopt and " --%s%s" %
2281 (longopt, numqualifier)),
2286 (longopt, numqualifier)),
2282 "%s%s" % (desc,
2287 "%s%s" % (desc,
2283 default
2288 default
2284 and _(" (default: %s)") % default
2289 and _(" (default: %s)") % default
2285 or "")))
2290 or "")))
2286 if multioccur:
2291 if multioccur:
2287 msg = _("\n[+] marked option can be specified multiple times")
2292 msg = _("\n[+] marked option can be specified multiple times")
2288 if ui.verbose and name != 'shortlist':
2293 if ui.verbose and name != 'shortlist':
2289 opt_output.append((msg, None))
2294 opt_output.append((msg, None))
2290 else:
2295 else:
2291 opt_output.insert(-1, (msg, None))
2296 opt_output.insert(-1, (msg, None))
2292
2297
2293 if not name:
2298 if not name:
2294 ui.write(_("\nadditional help topics:\n\n"))
2299 ui.write(_("\nadditional help topics:\n\n"))
2295 topics = []
2300 topics = []
2296 for names, header, doc in help.helptable:
2301 for names, header, doc in help.helptable:
2297 topics.append((sorted(names, key=len, reverse=True)[0], header))
2302 topics.append((sorted(names, key=len, reverse=True)[0], header))
2298 topics_len = max([len(s[0]) for s in topics])
2303 topics_len = max([len(s[0]) for s in topics])
2299 for t, desc in topics:
2304 for t, desc in topics:
2300 ui.write(" %-*s %s\n" % (topics_len, t, desc))
2305 ui.write(" %-*s %s\n" % (topics_len, t, desc))
2301
2306
2302 if opt_output:
2307 if opt_output:
2303 colwidth = encoding.colwidth
2308 colwidth = encoding.colwidth
2304 # normalize: (opt or message, desc or None, width of opt)
2309 # normalize: (opt or message, desc or None, width of opt)
2305 entries = [desc and (opt, desc, colwidth(opt)) or (opt, None, 0)
2310 entries = [desc and (opt, desc, colwidth(opt)) or (opt, None, 0)
2306 for opt, desc in opt_output]
2311 for opt, desc in opt_output]
2307 hanging = max([e[2] for e in entries])
2312 hanging = max([e[2] for e in entries])
2308 for opt, desc, width in entries:
2313 for opt, desc, width in entries:
2309 if desc:
2314 if desc:
2310 initindent = ' %s%s ' % (opt, ' ' * (hanging - width))
2315 initindent = ' %s%s ' % (opt, ' ' * (hanging - width))
2311 hangindent = ' ' * (hanging + 3)
2316 hangindent = ' ' * (hanging + 3)
2312 ui.write('%s\n' % (util.wrap(desc, textwidth,
2317 ui.write('%s\n' % (util.wrap(desc, textwidth,
2313 initindent=initindent,
2318 initindent=initindent,
2314 hangindent=hangindent)))
2319 hangindent=hangindent)))
2315 else:
2320 else:
2316 ui.write("%s\n" % opt)
2321 ui.write("%s\n" % opt)
2317
2322
2318 def identify(ui, repo, source=None, rev=None,
2323 def identify(ui, repo, source=None, rev=None,
2319 num=None, id=None, branch=None, tags=None, bookmarks=None):
2324 num=None, id=None, branch=None, tags=None, bookmarks=None):
2320 """identify the working copy or specified revision
2325 """identify the working copy or specified revision
2321
2326
2322 Print a summary identifying the repository state at REV using one or
2327 Print a summary identifying the repository state at REV using one or
2323 two parent hash identifiers, followed by a "+" if the working
2328 two parent hash identifiers, followed by a "+" if the working
2324 directory has uncommitted changes, the branch name (if not default),
2329 directory has uncommitted changes, the branch name (if not default),
2325 a list of tags, and a list of bookmarks.
2330 a list of tags, and a list of bookmarks.
2326
2331
2327 When REV is not given, print a summary of the current state of the
2332 When REV is not given, print a summary of the current state of the
2328 repository.
2333 repository.
2329
2334
2330 Specifying a path to a repository root or Mercurial bundle will
2335 Specifying a path to a repository root or Mercurial bundle will
2331 cause lookup to operate on that repository/bundle.
2336 cause lookup to operate on that repository/bundle.
2332
2337
2333 Returns 0 if successful.
2338 Returns 0 if successful.
2334 """
2339 """
2335
2340
2336 if not repo and not source:
2341 if not repo and not source:
2337 raise util.Abort(_("there is no Mercurial repository here "
2342 raise util.Abort(_("there is no Mercurial repository here "
2338 "(.hg not found)"))
2343 "(.hg not found)"))
2339
2344
2340 hexfunc = ui.debugflag and hex or short
2345 hexfunc = ui.debugflag and hex or short
2341 default = not (num or id or branch or tags or bookmarks)
2346 default = not (num or id or branch or tags or bookmarks)
2342 output = []
2347 output = []
2343 revs = []
2348 revs = []
2344
2349
2345 if source:
2350 if source:
2346 source, branches = hg.parseurl(ui.expandpath(source))
2351 source, branches = hg.parseurl(ui.expandpath(source))
2347 repo = hg.repository(ui, source)
2352 repo = hg.repository(ui, source)
2348 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
2353 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
2349
2354
2350 if not repo.local():
2355 if not repo.local():
2351 if num or branch or tags:
2356 if num or branch or tags:
2352 raise util.Abort(
2357 raise util.Abort(
2353 _("can't query remote revision number, branch, or tags"))
2358 _("can't query remote revision number, branch, or tags"))
2354 if not rev and revs:
2359 if not rev and revs:
2355 rev = revs[0]
2360 rev = revs[0]
2356 if not rev:
2361 if not rev:
2357 rev = "tip"
2362 rev = "tip"
2358
2363
2359 remoterev = repo.lookup(rev)
2364 remoterev = repo.lookup(rev)
2360 if default or id:
2365 if default or id:
2361 output = [hexfunc(remoterev)]
2366 output = [hexfunc(remoterev)]
2362
2367
2363 def getbms():
2368 def getbms():
2364 bms = []
2369 bms = []
2365
2370
2366 if 'bookmarks' in repo.listkeys('namespaces'):
2371 if 'bookmarks' in repo.listkeys('namespaces'):
2367 hexremoterev = hex(remoterev)
2372 hexremoterev = hex(remoterev)
2368 bms = [bm for bm, bmr in repo.listkeys('bookmarks').iteritems()
2373 bms = [bm for bm, bmr in repo.listkeys('bookmarks').iteritems()
2369 if bmr == hexremoterev]
2374 if bmr == hexremoterev]
2370
2375
2371 return bms
2376 return bms
2372
2377
2373 if bookmarks:
2378 if bookmarks:
2374 output.extend(getbms())
2379 output.extend(getbms())
2375 elif default and not ui.quiet:
2380 elif default and not ui.quiet:
2376 # multiple bookmarks for a single parent separated by '/'
2381 # multiple bookmarks for a single parent separated by '/'
2377 bm = '/'.join(getbms())
2382 bm = '/'.join(getbms())
2378 if bm:
2383 if bm:
2379 output.append(bm)
2384 output.append(bm)
2380 else:
2385 else:
2381 if not rev:
2386 if not rev:
2382 ctx = repo[None]
2387 ctx = repo[None]
2383 parents = ctx.parents()
2388 parents = ctx.parents()
2384 changed = ""
2389 changed = ""
2385 if default or id or num:
2390 if default or id or num:
2386 changed = util.any(repo.status()) and "+" or ""
2391 changed = util.any(repo.status()) and "+" or ""
2387 if default or id:
2392 if default or id:
2388 output = ["%s%s" %
2393 output = ["%s%s" %
2389 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
2394 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
2390 if num:
2395 if num:
2391 output.append("%s%s" %
2396 output.append("%s%s" %
2392 ('+'.join([str(p.rev()) for p in parents]), changed))
2397 ('+'.join([str(p.rev()) for p in parents]), changed))
2393 else:
2398 else:
2394 ctx = cmdutil.revsingle(repo, rev)
2399 ctx = cmdutil.revsingle(repo, rev)
2395 if default or id:
2400 if default or id:
2396 output = [hexfunc(ctx.node())]
2401 output = [hexfunc(ctx.node())]
2397 if num:
2402 if num:
2398 output.append(str(ctx.rev()))
2403 output.append(str(ctx.rev()))
2399
2404
2400 if default and not ui.quiet:
2405 if default and not ui.quiet:
2401 b = ctx.branch()
2406 b = ctx.branch()
2402 if b != 'default':
2407 if b != 'default':
2403 output.append("(%s)" % b)
2408 output.append("(%s)" % b)
2404
2409
2405 # multiple tags for a single parent separated by '/'
2410 # multiple tags for a single parent separated by '/'
2406 t = '/'.join(ctx.tags())
2411 t = '/'.join(ctx.tags())
2407 if t:
2412 if t:
2408 output.append(t)
2413 output.append(t)
2409
2414
2410 # multiple bookmarks for a single parent separated by '/'
2415 # multiple bookmarks for a single parent separated by '/'
2411 bm = '/'.join(ctx.bookmarks())
2416 bm = '/'.join(ctx.bookmarks())
2412 if bm:
2417 if bm:
2413 output.append(bm)
2418 output.append(bm)
2414 else:
2419 else:
2415 if branch:
2420 if branch:
2416 output.append(ctx.branch())
2421 output.append(ctx.branch())
2417
2422
2418 if tags:
2423 if tags:
2419 output.extend(ctx.tags())
2424 output.extend(ctx.tags())
2420
2425
2421 if bookmarks:
2426 if bookmarks:
2422 output.extend(ctx.bookmarks())
2427 output.extend(ctx.bookmarks())
2423
2428
2424 ui.write("%s\n" % ' '.join(output))
2429 ui.write("%s\n" % ' '.join(output))
2425
2430
2426 def import_(ui, repo, patch1, *patches, **opts):
2431 def import_(ui, repo, patch1, *patches, **opts):
2427 """import an ordered set of patches
2432 """import an ordered set of patches
2428
2433
2429 Import a list of patches and commit them individually (unless
2434 Import a list of patches and commit them individually (unless
2430 --no-commit is specified).
2435 --no-commit is specified).
2431
2436
2432 If there are outstanding changes in the working directory, import
2437 If there are outstanding changes in the working directory, import
2433 will abort unless given the -f/--force flag.
2438 will abort unless given the -f/--force flag.
2434
2439
2435 You can import a patch straight from a mail message. Even patches
2440 You can import a patch straight from a mail message. Even patches
2436 as attachments work (to use the body part, it must have type
2441 as attachments work (to use the body part, it must have type
2437 text/plain or text/x-patch). From and Subject headers of email
2442 text/plain or text/x-patch). From and Subject headers of email
2438 message are used as default committer and commit message. All
2443 message are used as default committer and commit message. All
2439 text/plain body parts before first diff are added to commit
2444 text/plain body parts before first diff are added to commit
2440 message.
2445 message.
2441
2446
2442 If the imported patch was generated by :hg:`export`, user and
2447 If the imported patch was generated by :hg:`export`, user and
2443 description from patch override values from message headers and
2448 description from patch override values from message headers and
2444 body. Values given on command line with -m/--message and -u/--user
2449 body. Values given on command line with -m/--message and -u/--user
2445 override these.
2450 override these.
2446
2451
2447 If --exact is specified, import will set the working directory to
2452 If --exact is specified, import will set the working directory to
2448 the parent of each patch before applying it, and will abort if the
2453 the parent of each patch before applying it, and will abort if the
2449 resulting changeset has a different ID than the one recorded in
2454 resulting changeset has a different ID than the one recorded in
2450 the patch. This may happen due to character set problems or other
2455 the patch. This may happen due to character set problems or other
2451 deficiencies in the text patch format.
2456 deficiencies in the text patch format.
2452
2457
2453 With -s/--similarity, hg will attempt to discover renames and
2458 With -s/--similarity, hg will attempt to discover renames and
2454 copies in the patch in the same way as 'addremove'.
2459 copies in the patch in the same way as 'addremove'.
2455
2460
2456 To read a patch from standard input, use "-" as the patch name. If
2461 To read a patch from standard input, use "-" as the patch name. If
2457 a URL is specified, the patch will be downloaded from it.
2462 a URL is specified, the patch will be downloaded from it.
2458 See :hg:`help dates` for a list of formats valid for -d/--date.
2463 See :hg:`help dates` for a list of formats valid for -d/--date.
2459
2464
2460 Returns 0 on success.
2465 Returns 0 on success.
2461 """
2466 """
2462 patches = (patch1,) + patches
2467 patches = (patch1,) + patches
2463
2468
2464 date = opts.get('date')
2469 date = opts.get('date')
2465 if date:
2470 if date:
2466 opts['date'] = util.parsedate(date)
2471 opts['date'] = util.parsedate(date)
2467
2472
2468 try:
2473 try:
2469 sim = float(opts.get('similarity') or 0)
2474 sim = float(opts.get('similarity') or 0)
2470 except ValueError:
2475 except ValueError:
2471 raise util.Abort(_('similarity must be a number'))
2476 raise util.Abort(_('similarity must be a number'))
2472 if sim < 0 or sim > 100:
2477 if sim < 0 or sim > 100:
2473 raise util.Abort(_('similarity must be between 0 and 100'))
2478 raise util.Abort(_('similarity must be between 0 and 100'))
2474
2479
2475 if opts.get('exact') or not opts.get('force'):
2480 if opts.get('exact') or not opts.get('force'):
2476 cmdutil.bail_if_changed(repo)
2481 cmdutil.bail_if_changed(repo)
2477
2482
2478 d = opts["base"]
2483 d = opts["base"]
2479 strip = opts["strip"]
2484 strip = opts["strip"]
2480 wlock = lock = None
2485 wlock = lock = None
2481 msgs = []
2486 msgs = []
2482
2487
2483 def tryone(ui, hunk):
2488 def tryone(ui, hunk):
2484 tmpname, message, user, date, branch, nodeid, p1, p2 = \
2489 tmpname, message, user, date, branch, nodeid, p1, p2 = \
2485 patch.extract(ui, hunk)
2490 patch.extract(ui, hunk)
2486
2491
2487 if not tmpname:
2492 if not tmpname:
2488 return None
2493 return None
2489 commitid = _('to working directory')
2494 commitid = _('to working directory')
2490
2495
2491 try:
2496 try:
2492 cmdline_message = cmdutil.logmessage(opts)
2497 cmdline_message = cmdutil.logmessage(opts)
2493 if cmdline_message:
2498 if cmdline_message:
2494 # pickup the cmdline msg
2499 # pickup the cmdline msg
2495 message = cmdline_message
2500 message = cmdline_message
2496 elif message:
2501 elif message:
2497 # pickup the patch msg
2502 # pickup the patch msg
2498 message = message.strip()
2503 message = message.strip()
2499 else:
2504 else:
2500 # launch the editor
2505 # launch the editor
2501 message = None
2506 message = None
2502 ui.debug('message:\n%s\n' % message)
2507 ui.debug('message:\n%s\n' % message)
2503
2508
2504 wp = repo.parents()
2509 wp = repo.parents()
2505 if opts.get('exact'):
2510 if opts.get('exact'):
2506 if not nodeid or not p1:
2511 if not nodeid or not p1:
2507 raise util.Abort(_('not a Mercurial patch'))
2512 raise util.Abort(_('not a Mercurial patch'))
2508 p1 = repo.lookup(p1)
2513 p1 = repo.lookup(p1)
2509 p2 = repo.lookup(p2 or hex(nullid))
2514 p2 = repo.lookup(p2 or hex(nullid))
2510
2515
2511 if p1 != wp[0].node():
2516 if p1 != wp[0].node():
2512 hg.clean(repo, p1)
2517 hg.clean(repo, p1)
2513 repo.dirstate.setparents(p1, p2)
2518 repo.dirstate.setparents(p1, p2)
2514 elif p2:
2519 elif p2:
2515 try:
2520 try:
2516 p1 = repo.lookup(p1)
2521 p1 = repo.lookup(p1)
2517 p2 = repo.lookup(p2)
2522 p2 = repo.lookup(p2)
2518 if p1 == wp[0].node():
2523 if p1 == wp[0].node():
2519 repo.dirstate.setparents(p1, p2)
2524 repo.dirstate.setparents(p1, p2)
2520 except error.RepoError:
2525 except error.RepoError:
2521 pass
2526 pass
2522 if opts.get('exact') or opts.get('import_branch'):
2527 if opts.get('exact') or opts.get('import_branch'):
2523 repo.dirstate.setbranch(branch or 'default')
2528 repo.dirstate.setbranch(branch or 'default')
2524
2529
2525 files = {}
2530 files = {}
2526 try:
2531 try:
2527 patch.patch(tmpname, ui, strip=strip, cwd=repo.root,
2532 patch.patch(tmpname, ui, strip=strip, cwd=repo.root,
2528 files=files, eolmode=None)
2533 files=files, eolmode=None)
2529 finally:
2534 finally:
2530 files = cmdutil.updatedir(ui, repo, files,
2535 files = cmdutil.updatedir(ui, repo, files,
2531 similarity=sim / 100.0)
2536 similarity=sim / 100.0)
2532 if opts.get('no_commit'):
2537 if opts.get('no_commit'):
2533 if message:
2538 if message:
2534 msgs.append(message)
2539 msgs.append(message)
2535 else:
2540 else:
2536 if opts.get('exact'):
2541 if opts.get('exact'):
2537 m = None
2542 m = None
2538 else:
2543 else:
2539 m = cmdutil.matchfiles(repo, files or [])
2544 m = cmdutil.matchfiles(repo, files or [])
2540 n = repo.commit(message, opts.get('user') or user,
2545 n = repo.commit(message, opts.get('user') or user,
2541 opts.get('date') or date, match=m,
2546 opts.get('date') or date, match=m,
2542 editor=cmdutil.commiteditor)
2547 editor=cmdutil.commiteditor)
2543 if opts.get('exact'):
2548 if opts.get('exact'):
2544 if hex(n) != nodeid:
2549 if hex(n) != nodeid:
2545 repo.rollback()
2550 repo.rollback()
2546 raise util.Abort(_('patch is damaged'
2551 raise util.Abort(_('patch is damaged'
2547 ' or loses information'))
2552 ' or loses information'))
2548 # Force a dirstate write so that the next transaction
2553 # Force a dirstate write so that the next transaction
2549 # backups an up-do-date file.
2554 # backups an up-do-date file.
2550 repo.dirstate.write()
2555 repo.dirstate.write()
2551 if n:
2556 if n:
2552 commitid = short(n)
2557 commitid = short(n)
2553
2558
2554 return commitid
2559 return commitid
2555 finally:
2560 finally:
2556 os.unlink(tmpname)
2561 os.unlink(tmpname)
2557
2562
2558 try:
2563 try:
2559 wlock = repo.wlock()
2564 wlock = repo.wlock()
2560 lock = repo.lock()
2565 lock = repo.lock()
2561 lastcommit = None
2566 lastcommit = None
2562 for p in patches:
2567 for p in patches:
2563 pf = os.path.join(d, p)
2568 pf = os.path.join(d, p)
2564
2569
2565 if pf == '-':
2570 if pf == '-':
2566 ui.status(_("applying patch from stdin\n"))
2571 ui.status(_("applying patch from stdin\n"))
2567 pf = sys.stdin
2572 pf = sys.stdin
2568 else:
2573 else:
2569 ui.status(_("applying %s\n") % p)
2574 ui.status(_("applying %s\n") % p)
2570 pf = url.open(ui, pf)
2575 pf = url.open(ui, pf)
2571
2576
2572 haspatch = False
2577 haspatch = False
2573 for hunk in patch.split(pf):
2578 for hunk in patch.split(pf):
2574 commitid = tryone(ui, hunk)
2579 commitid = tryone(ui, hunk)
2575 if commitid:
2580 if commitid:
2576 haspatch = True
2581 haspatch = True
2577 if lastcommit:
2582 if lastcommit:
2578 ui.status(_('applied %s\n') % lastcommit)
2583 ui.status(_('applied %s\n') % lastcommit)
2579 lastcommit = commitid
2584 lastcommit = commitid
2580
2585
2581 if not haspatch:
2586 if not haspatch:
2582 raise util.Abort(_('no diffs found'))
2587 raise util.Abort(_('no diffs found'))
2583
2588
2584 if msgs:
2589 if msgs:
2585 repo.opener('last-message.txt', 'wb').write('\n* * *\n'.join(msgs))
2590 repo.opener('last-message.txt', 'wb').write('\n* * *\n'.join(msgs))
2586 finally:
2591 finally:
2587 release(lock, wlock)
2592 release(lock, wlock)
2588
2593
2589 def incoming(ui, repo, source="default", **opts):
2594 def incoming(ui, repo, source="default", **opts):
2590 """show new changesets found in source
2595 """show new changesets found in source
2591
2596
2592 Show new changesets found in the specified path/URL or the default
2597 Show new changesets found in the specified path/URL or the default
2593 pull location. These are the changesets that would have been pulled
2598 pull location. These are the changesets that would have been pulled
2594 if a pull at the time you issued this command.
2599 if a pull at the time you issued this command.
2595
2600
2596 For remote repository, using --bundle avoids downloading the
2601 For remote repository, using --bundle avoids downloading the
2597 changesets twice if the incoming is followed by a pull.
2602 changesets twice if the incoming is followed by a pull.
2598
2603
2599 See pull for valid source format details.
2604 See pull for valid source format details.
2600
2605
2601 Returns 0 if there are incoming changes, 1 otherwise.
2606 Returns 0 if there are incoming changes, 1 otherwise.
2602 """
2607 """
2603 if opts.get('bundle') and opts.get('subrepos'):
2608 if opts.get('bundle') and opts.get('subrepos'):
2604 raise util.Abort(_('cannot combine --bundle and --subrepos'))
2609 raise util.Abort(_('cannot combine --bundle and --subrepos'))
2605
2610
2606 if opts.get('bookmarks'):
2611 if opts.get('bookmarks'):
2607 source, branches = hg.parseurl(ui.expandpath(source),
2612 source, branches = hg.parseurl(ui.expandpath(source),
2608 opts.get('branch'))
2613 opts.get('branch'))
2609 other = hg.repository(hg.remoteui(repo, opts), source)
2614 other = hg.repository(hg.remoteui(repo, opts), source)
2610 if 'bookmarks' not in other.listkeys('namespaces'):
2615 if 'bookmarks' not in other.listkeys('namespaces'):
2611 ui.warn(_("remote doesn't support bookmarks\n"))
2616 ui.warn(_("remote doesn't support bookmarks\n"))
2612 return 0
2617 return 0
2613 ui.status(_('comparing with %s\n') % util.hidepassword(source))
2618 ui.status(_('comparing with %s\n') % util.hidepassword(source))
2614 return bookmarks.diff(ui, repo, other)
2619 return bookmarks.diff(ui, repo, other)
2615
2620
2616 ret = hg.incoming(ui, repo, source, opts)
2621 ret = hg.incoming(ui, repo, source, opts)
2617 return ret
2622 return ret
2618
2623
2619 def init(ui, dest=".", **opts):
2624 def init(ui, dest=".", **opts):
2620 """create a new repository in the given directory
2625 """create a new repository in the given directory
2621
2626
2622 Initialize a new repository in the given directory. If the given
2627 Initialize a new repository in the given directory. If the given
2623 directory does not exist, it will be created.
2628 directory does not exist, it will be created.
2624
2629
2625 If no directory is given, the current directory is used.
2630 If no directory is given, the current directory is used.
2626
2631
2627 It is possible to specify an ``ssh://`` URL as the destination.
2632 It is possible to specify an ``ssh://`` URL as the destination.
2628 See :hg:`help urls` for more information.
2633 See :hg:`help urls` for more information.
2629
2634
2630 Returns 0 on success.
2635 Returns 0 on success.
2631 """
2636 """
2632 hg.repository(hg.remoteui(ui, opts), ui.expandpath(dest), create=1)
2637 hg.repository(hg.remoteui(ui, opts), ui.expandpath(dest), create=1)
2633
2638
2634 def locate(ui, repo, *pats, **opts):
2639 def locate(ui, repo, *pats, **opts):
2635 """locate files matching specific patterns
2640 """locate files matching specific patterns
2636
2641
2637 Print files under Mercurial control in the working directory whose
2642 Print files under Mercurial control in the working directory whose
2638 names match the given patterns.
2643 names match the given patterns.
2639
2644
2640 By default, this command searches all directories in the working
2645 By default, this command searches all directories in the working
2641 directory. To search just the current directory and its
2646 directory. To search just the current directory and its
2642 subdirectories, use "--include .".
2647 subdirectories, use "--include .".
2643
2648
2644 If no patterns are given to match, this command prints the names
2649 If no patterns are given to match, this command prints the names
2645 of all files under Mercurial control in the working directory.
2650 of all files under Mercurial control in the working directory.
2646
2651
2647 If you want to feed the output of this command into the "xargs"
2652 If you want to feed the output of this command into the "xargs"
2648 command, use the -0 option to both this command and "xargs". This
2653 command, use the -0 option to both this command and "xargs". This
2649 will avoid the problem of "xargs" treating single filenames that
2654 will avoid the problem of "xargs" treating single filenames that
2650 contain whitespace as multiple filenames.
2655 contain whitespace as multiple filenames.
2651
2656
2652 Returns 0 if a match is found, 1 otherwise.
2657 Returns 0 if a match is found, 1 otherwise.
2653 """
2658 """
2654 end = opts.get('print0') and '\0' or '\n'
2659 end = opts.get('print0') and '\0' or '\n'
2655 rev = cmdutil.revsingle(repo, opts.get('rev'), None).node()
2660 rev = cmdutil.revsingle(repo, opts.get('rev'), None).node()
2656
2661
2657 ret = 1
2662 ret = 1
2658 m = cmdutil.match(repo, pats, opts, default='relglob')
2663 m = cmdutil.match(repo, pats, opts, default='relglob')
2659 m.bad = lambda x, y: False
2664 m.bad = lambda x, y: False
2660 for abs in repo[rev].walk(m):
2665 for abs in repo[rev].walk(m):
2661 if not rev and abs not in repo.dirstate:
2666 if not rev and abs not in repo.dirstate:
2662 continue
2667 continue
2663 if opts.get('fullpath'):
2668 if opts.get('fullpath'):
2664 ui.write(repo.wjoin(abs), end)
2669 ui.write(repo.wjoin(abs), end)
2665 else:
2670 else:
2666 ui.write(((pats and m.rel(abs)) or abs), end)
2671 ui.write(((pats and m.rel(abs)) or abs), end)
2667 ret = 0
2672 ret = 0
2668
2673
2669 return ret
2674 return ret
2670
2675
2671 def log(ui, repo, *pats, **opts):
2676 def log(ui, repo, *pats, **opts):
2672 """show revision history of entire repository or files
2677 """show revision history of entire repository or files
2673
2678
2674 Print the revision history of the specified files or the entire
2679 Print the revision history of the specified files or the entire
2675 project.
2680 project.
2676
2681
2677 File history is shown without following rename or copy history of
2682 File history is shown without following rename or copy history of
2678 files. Use -f/--follow with a filename to follow history across
2683 files. Use -f/--follow with a filename to follow history across
2679 renames and copies. --follow without a filename will only show
2684 renames and copies. --follow without a filename will only show
2680 ancestors or descendants of the starting revision. --follow-first
2685 ancestors or descendants of the starting revision. --follow-first
2681 only follows the first parent of merge revisions.
2686 only follows the first parent of merge revisions.
2682
2687
2683 If no revision range is specified, the default is ``tip:0`` unless
2688 If no revision range is specified, the default is ``tip:0`` unless
2684 --follow is set, in which case the working directory parent is
2689 --follow is set, in which case the working directory parent is
2685 used as the starting revision. You can specify a revision set for
2690 used as the starting revision. You can specify a revision set for
2686 log, see :hg:`help revsets` for more information.
2691 log, see :hg:`help revsets` for more information.
2687
2692
2688 See :hg:`help dates` for a list of formats valid for -d/--date.
2693 See :hg:`help dates` for a list of formats valid for -d/--date.
2689
2694
2690 By default this command prints revision number and changeset id,
2695 By default this command prints revision number and changeset id,
2691 tags, non-trivial parents, user, date and time, and a summary for
2696 tags, non-trivial parents, user, date and time, and a summary for
2692 each commit. When the -v/--verbose switch is used, the list of
2697 each commit. When the -v/--verbose switch is used, the list of
2693 changed files and full commit message are shown.
2698 changed files and full commit message are shown.
2694
2699
2695 .. note::
2700 .. note::
2696 log -p/--patch may generate unexpected diff output for merge
2701 log -p/--patch may generate unexpected diff output for merge
2697 changesets, as it will only compare the merge changeset against
2702 changesets, as it will only compare the merge changeset against
2698 its first parent. Also, only files different from BOTH parents
2703 its first parent. Also, only files different from BOTH parents
2699 will appear in files:.
2704 will appear in files:.
2700
2705
2701 Returns 0 on success.
2706 Returns 0 on success.
2702 """
2707 """
2703
2708
2704 matchfn = cmdutil.match(repo, pats, opts)
2709 matchfn = cmdutil.match(repo, pats, opts)
2705 limit = cmdutil.loglimit(opts)
2710 limit = cmdutil.loglimit(opts)
2706 count = 0
2711 count = 0
2707
2712
2708 endrev = None
2713 endrev = None
2709 if opts.get('copies') and opts.get('rev'):
2714 if opts.get('copies') and opts.get('rev'):
2710 endrev = max(cmdutil.revrange(repo, opts.get('rev'))) + 1
2715 endrev = max(cmdutil.revrange(repo, opts.get('rev'))) + 1
2711
2716
2712 df = False
2717 df = False
2713 if opts["date"]:
2718 if opts["date"]:
2714 df = util.matchdate(opts["date"])
2719 df = util.matchdate(opts["date"])
2715
2720
2716 branches = opts.get('branch', []) + opts.get('only_branch', [])
2721 branches = opts.get('branch', []) + opts.get('only_branch', [])
2717 opts['branch'] = [repo.lookupbranch(b) for b in branches]
2722 opts['branch'] = [repo.lookupbranch(b) for b in branches]
2718
2723
2719 displayer = cmdutil.show_changeset(ui, repo, opts, True)
2724 displayer = cmdutil.show_changeset(ui, repo, opts, True)
2720 def prep(ctx, fns):
2725 def prep(ctx, fns):
2721 rev = ctx.rev()
2726 rev = ctx.rev()
2722 parents = [p for p in repo.changelog.parentrevs(rev)
2727 parents = [p for p in repo.changelog.parentrevs(rev)
2723 if p != nullrev]
2728 if p != nullrev]
2724 if opts.get('no_merges') and len(parents) == 2:
2729 if opts.get('no_merges') and len(parents) == 2:
2725 return
2730 return
2726 if opts.get('only_merges') and len(parents) != 2:
2731 if opts.get('only_merges') and len(parents) != 2:
2727 return
2732 return
2728 if opts.get('branch') and ctx.branch() not in opts['branch']:
2733 if opts.get('branch') and ctx.branch() not in opts['branch']:
2729 return
2734 return
2730 if df and not df(ctx.date()[0]):
2735 if df and not df(ctx.date()[0]):
2731 return
2736 return
2732 if opts['user'] and not [k for k in opts['user']
2737 if opts['user'] and not [k for k in opts['user']
2733 if k.lower() in ctx.user().lower()]:
2738 if k.lower() in ctx.user().lower()]:
2734 return
2739 return
2735 if opts.get('keyword'):
2740 if opts.get('keyword'):
2736 for k in [kw.lower() for kw in opts['keyword']]:
2741 for k in [kw.lower() for kw in opts['keyword']]:
2737 if (k in ctx.user().lower() or
2742 if (k in ctx.user().lower() or
2738 k in ctx.description().lower() or
2743 k in ctx.description().lower() or
2739 k in " ".join(ctx.files()).lower()):
2744 k in " ".join(ctx.files()).lower()):
2740 break
2745 break
2741 else:
2746 else:
2742 return
2747 return
2743
2748
2744 copies = None
2749 copies = None
2745 if opts.get('copies') and rev:
2750 if opts.get('copies') and rev:
2746 copies = []
2751 copies = []
2747 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
2752 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
2748 for fn in ctx.files():
2753 for fn in ctx.files():
2749 rename = getrenamed(fn, rev)
2754 rename = getrenamed(fn, rev)
2750 if rename:
2755 if rename:
2751 copies.append((fn, rename[0]))
2756 copies.append((fn, rename[0]))
2752
2757
2753 revmatchfn = None
2758 revmatchfn = None
2754 if opts.get('patch') or opts.get('stat'):
2759 if opts.get('patch') or opts.get('stat'):
2755 if opts.get('follow') or opts.get('follow_first'):
2760 if opts.get('follow') or opts.get('follow_first'):
2756 # note: this might be wrong when following through merges
2761 # note: this might be wrong when following through merges
2757 revmatchfn = cmdutil.match(repo, fns, default='path')
2762 revmatchfn = cmdutil.match(repo, fns, default='path')
2758 else:
2763 else:
2759 revmatchfn = matchfn
2764 revmatchfn = matchfn
2760
2765
2761 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
2766 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
2762
2767
2763 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
2768 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
2764 if count == limit:
2769 if count == limit:
2765 break
2770 break
2766 if displayer.flush(ctx.rev()):
2771 if displayer.flush(ctx.rev()):
2767 count += 1
2772 count += 1
2768 displayer.close()
2773 displayer.close()
2769
2774
2770 def manifest(ui, repo, node=None, rev=None):
2775 def manifest(ui, repo, node=None, rev=None):
2771 """output the current or given revision of the project manifest
2776 """output the current or given revision of the project manifest
2772
2777
2773 Print a list of version controlled files for the given revision.
2778 Print a list of version controlled files for the given revision.
2774 If no revision is given, the first parent of the working directory
2779 If no revision is given, the first parent of the working directory
2775 is used, or the null revision if no revision is checked out.
2780 is used, or the null revision if no revision is checked out.
2776
2781
2777 With -v, print file permissions, symlink and executable bits.
2782 With -v, print file permissions, symlink and executable bits.
2778 With --debug, print file revision hashes.
2783 With --debug, print file revision hashes.
2779
2784
2780 Returns 0 on success.
2785 Returns 0 on success.
2781 """
2786 """
2782
2787
2783 if rev and node:
2788 if rev and node:
2784 raise util.Abort(_("please specify just one revision"))
2789 raise util.Abort(_("please specify just one revision"))
2785
2790
2786 if not node:
2791 if not node:
2787 node = rev
2792 node = rev
2788
2793
2789 decor = {'l':'644 @ ', 'x':'755 * ', '':'644 '}
2794 decor = {'l':'644 @ ', 'x':'755 * ', '':'644 '}
2790 ctx = cmdutil.revsingle(repo, node)
2795 ctx = cmdutil.revsingle(repo, node)
2791 for f in ctx:
2796 for f in ctx:
2792 if ui.debugflag:
2797 if ui.debugflag:
2793 ui.write("%40s " % hex(ctx.manifest()[f]))
2798 ui.write("%40s " % hex(ctx.manifest()[f]))
2794 if ui.verbose:
2799 if ui.verbose:
2795 ui.write(decor[ctx.flags(f)])
2800 ui.write(decor[ctx.flags(f)])
2796 ui.write("%s\n" % f)
2801 ui.write("%s\n" % f)
2797
2802
2798 def merge(ui, repo, node=None, **opts):
2803 def merge(ui, repo, node=None, **opts):
2799 """merge working directory with another revision
2804 """merge working directory with another revision
2800
2805
2801 The current working directory is updated with all changes made in
2806 The current working directory is updated with all changes made in
2802 the requested revision since the last common predecessor revision.
2807 the requested revision since the last common predecessor revision.
2803
2808
2804 Files that changed between either parent are marked as changed for
2809 Files that changed between either parent are marked as changed for
2805 the next commit and a commit must be performed before any further
2810 the next commit and a commit must be performed before any further
2806 updates to the repository are allowed. The next commit will have
2811 updates to the repository are allowed. The next commit will have
2807 two parents.
2812 two parents.
2808
2813
2809 ``--tool`` can be used to specify the merge tool used for file
2814 ``--tool`` can be used to specify the merge tool used for file
2810 merges. It overrides the HGMERGE environment variable and your
2815 merges. It overrides the HGMERGE environment variable and your
2811 configuration files. See :hg:`help merge-tools` for options.
2816 configuration files. See :hg:`help merge-tools` for options.
2812
2817
2813 If no revision is specified, the working directory's parent is a
2818 If no revision is specified, the working directory's parent is a
2814 head revision, and the current branch contains exactly one other
2819 head revision, and the current branch contains exactly one other
2815 head, the other head is merged with by default. Otherwise, an
2820 head, the other head is merged with by default. Otherwise, an
2816 explicit revision with which to merge with must be provided.
2821 explicit revision with which to merge with must be provided.
2817
2822
2818 :hg:`resolve` must be used to resolve unresolved files.
2823 :hg:`resolve` must be used to resolve unresolved files.
2819
2824
2820 To undo an uncommitted merge, use :hg:`update --clean .` which
2825 To undo an uncommitted merge, use :hg:`update --clean .` which
2821 will check out a clean copy of the original merge parent, losing
2826 will check out a clean copy of the original merge parent, losing
2822 all changes.
2827 all changes.
2823
2828
2824 Returns 0 on success, 1 if there are unresolved files.
2829 Returns 0 on success, 1 if there are unresolved files.
2825 """
2830 """
2826
2831
2827 if opts.get('rev') and node:
2832 if opts.get('rev') and node:
2828 raise util.Abort(_("please specify just one revision"))
2833 raise util.Abort(_("please specify just one revision"))
2829 if not node:
2834 if not node:
2830 node = opts.get('rev')
2835 node = opts.get('rev')
2831
2836
2832 if not node:
2837 if not node:
2833 branch = repo[None].branch()
2838 branch = repo[None].branch()
2834 bheads = repo.branchheads(branch)
2839 bheads = repo.branchheads(branch)
2835 if len(bheads) > 2:
2840 if len(bheads) > 2:
2836 raise util.Abort(_(
2841 raise util.Abort(_(
2837 'branch \'%s\' has %d heads - '
2842 'branch \'%s\' has %d heads - '
2838 'please merge with an explicit rev\n'
2843 'please merge with an explicit rev\n'
2839 '(run \'hg heads .\' to see heads)')
2844 '(run \'hg heads .\' to see heads)')
2840 % (branch, len(bheads)))
2845 % (branch, len(bheads)))
2841
2846
2842 parent = repo.dirstate.p1()
2847 parent = repo.dirstate.p1()
2843 if len(bheads) == 1:
2848 if len(bheads) == 1:
2844 if len(repo.heads()) > 1:
2849 if len(repo.heads()) > 1:
2845 raise util.Abort(_(
2850 raise util.Abort(_(
2846 'branch \'%s\' has one head - '
2851 'branch \'%s\' has one head - '
2847 'please merge with an explicit rev\n'
2852 'please merge with an explicit rev\n'
2848 '(run \'hg heads\' to see all heads)')
2853 '(run \'hg heads\' to see all heads)')
2849 % branch)
2854 % branch)
2850 msg = _('there is nothing to merge')
2855 msg = _('there is nothing to merge')
2851 if parent != repo.lookup(repo[None].branch()):
2856 if parent != repo.lookup(repo[None].branch()):
2852 msg = _('%s - use "hg update" instead') % msg
2857 msg = _('%s - use "hg update" instead') % msg
2853 raise util.Abort(msg)
2858 raise util.Abort(msg)
2854
2859
2855 if parent not in bheads:
2860 if parent not in bheads:
2856 raise util.Abort(_('working dir not at a head rev - '
2861 raise util.Abort(_('working dir not at a head rev - '
2857 'use "hg update" or merge with an explicit rev'))
2862 'use "hg update" or merge with an explicit rev'))
2858 node = parent == bheads[0] and bheads[-1] or bheads[0]
2863 node = parent == bheads[0] and bheads[-1] or bheads[0]
2859 else:
2864 else:
2860 node = cmdutil.revsingle(repo, node).node()
2865 node = cmdutil.revsingle(repo, node).node()
2861
2866
2862 if opts.get('preview'):
2867 if opts.get('preview'):
2863 # find nodes that are ancestors of p2 but not of p1
2868 # find nodes that are ancestors of p2 but not of p1
2864 p1 = repo.lookup('.')
2869 p1 = repo.lookup('.')
2865 p2 = repo.lookup(node)
2870 p2 = repo.lookup(node)
2866 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
2871 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
2867
2872
2868 displayer = cmdutil.show_changeset(ui, repo, opts)
2873 displayer = cmdutil.show_changeset(ui, repo, opts)
2869 for node in nodes:
2874 for node in nodes:
2870 displayer.show(repo[node])
2875 displayer.show(repo[node])
2871 displayer.close()
2876 displayer.close()
2872 return 0
2877 return 0
2873
2878
2874 try:
2879 try:
2875 # ui.forcemerge is an internal variable, do not document
2880 # ui.forcemerge is an internal variable, do not document
2876 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
2881 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
2877 return hg.merge(repo, node, force=opts.get('force'))
2882 return hg.merge(repo, node, force=opts.get('force'))
2878 finally:
2883 finally:
2879 ui.setconfig('ui', 'forcemerge', '')
2884 ui.setconfig('ui', 'forcemerge', '')
2880
2885
2881 def outgoing(ui, repo, dest=None, **opts):
2886 def outgoing(ui, repo, dest=None, **opts):
2882 """show changesets not found in the destination
2887 """show changesets not found in the destination
2883
2888
2884 Show changesets not found in the specified destination repository
2889 Show changesets not found in the specified destination repository
2885 or the default push location. These are the changesets that would
2890 or the default push location. These are the changesets that would
2886 be pushed if a push was requested.
2891 be pushed if a push was requested.
2887
2892
2888 See pull for details of valid destination formats.
2893 See pull for details of valid destination formats.
2889
2894
2890 Returns 0 if there are outgoing changes, 1 otherwise.
2895 Returns 0 if there are outgoing changes, 1 otherwise.
2891 """
2896 """
2892
2897
2893 if opts.get('bookmarks'):
2898 if opts.get('bookmarks'):
2894 dest = ui.expandpath(dest or 'default-push', dest or 'default')
2899 dest = ui.expandpath(dest or 'default-push', dest or 'default')
2895 dest, branches = hg.parseurl(dest, opts.get('branch'))
2900 dest, branches = hg.parseurl(dest, opts.get('branch'))
2896 other = hg.repository(hg.remoteui(repo, opts), dest)
2901 other = hg.repository(hg.remoteui(repo, opts), dest)
2897 if 'bookmarks' not in other.listkeys('namespaces'):
2902 if 'bookmarks' not in other.listkeys('namespaces'):
2898 ui.warn(_("remote doesn't support bookmarks\n"))
2903 ui.warn(_("remote doesn't support bookmarks\n"))
2899 return 0
2904 return 0
2900 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
2905 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
2901 return bookmarks.diff(ui, other, repo)
2906 return bookmarks.diff(ui, other, repo)
2902
2907
2903 ret = hg.outgoing(ui, repo, dest, opts)
2908 ret = hg.outgoing(ui, repo, dest, opts)
2904 return ret
2909 return ret
2905
2910
2906 def parents(ui, repo, file_=None, **opts):
2911 def parents(ui, repo, file_=None, **opts):
2907 """show the parents of the working directory or revision
2912 """show the parents of the working directory or revision
2908
2913
2909 Print the working directory's parent revisions. If a revision is
2914 Print the working directory's parent revisions. If a revision is
2910 given via -r/--rev, the parent of that revision will be printed.
2915 given via -r/--rev, the parent of that revision will be printed.
2911 If a file argument is given, the revision in which the file was
2916 If a file argument is given, the revision in which the file was
2912 last changed (before the working directory revision or the
2917 last changed (before the working directory revision or the
2913 argument to --rev if given) is printed.
2918 argument to --rev if given) is printed.
2914
2919
2915 Returns 0 on success.
2920 Returns 0 on success.
2916 """
2921 """
2917
2922
2918 ctx = cmdutil.revsingle(repo, opts.get('rev'), None)
2923 ctx = cmdutil.revsingle(repo, opts.get('rev'), None)
2919
2924
2920 if file_:
2925 if file_:
2921 m = cmdutil.match(repo, (file_,), opts)
2926 m = cmdutil.match(repo, (file_,), opts)
2922 if m.anypats() or len(m.files()) != 1:
2927 if m.anypats() or len(m.files()) != 1:
2923 raise util.Abort(_('can only specify an explicit filename'))
2928 raise util.Abort(_('can only specify an explicit filename'))
2924 file_ = m.files()[0]
2929 file_ = m.files()[0]
2925 filenodes = []
2930 filenodes = []
2926 for cp in ctx.parents():
2931 for cp in ctx.parents():
2927 if not cp:
2932 if not cp:
2928 continue
2933 continue
2929 try:
2934 try:
2930 filenodes.append(cp.filenode(file_))
2935 filenodes.append(cp.filenode(file_))
2931 except error.LookupError:
2936 except error.LookupError:
2932 pass
2937 pass
2933 if not filenodes:
2938 if not filenodes:
2934 raise util.Abort(_("'%s' not found in manifest!") % file_)
2939 raise util.Abort(_("'%s' not found in manifest!") % file_)
2935 fl = repo.file(file_)
2940 fl = repo.file(file_)
2936 p = [repo.lookup(fl.linkrev(fl.rev(fn))) for fn in filenodes]
2941 p = [repo.lookup(fl.linkrev(fl.rev(fn))) for fn in filenodes]
2937 else:
2942 else:
2938 p = [cp.node() for cp in ctx.parents()]
2943 p = [cp.node() for cp in ctx.parents()]
2939
2944
2940 displayer = cmdutil.show_changeset(ui, repo, opts)
2945 displayer = cmdutil.show_changeset(ui, repo, opts)
2941 for n in p:
2946 for n in p:
2942 if n != nullid:
2947 if n != nullid:
2943 displayer.show(repo[n])
2948 displayer.show(repo[n])
2944 displayer.close()
2949 displayer.close()
2945
2950
2946 def paths(ui, repo, search=None):
2951 def paths(ui, repo, search=None):
2947 """show aliases for remote repositories
2952 """show aliases for remote repositories
2948
2953
2949 Show definition of symbolic path name NAME. If no name is given,
2954 Show definition of symbolic path name NAME. If no name is given,
2950 show definition of all available names.
2955 show definition of all available names.
2951
2956
2952 Path names are defined in the [paths] section of your
2957 Path names are defined in the [paths] section of your
2953 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
2958 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
2954 repository, ``.hg/hgrc`` is used, too.
2959 repository, ``.hg/hgrc`` is used, too.
2955
2960
2956 The path names ``default`` and ``default-push`` have a special
2961 The path names ``default`` and ``default-push`` have a special
2957 meaning. When performing a push or pull operation, they are used
2962 meaning. When performing a push or pull operation, they are used
2958 as fallbacks if no location is specified on the command-line.
2963 as fallbacks if no location is specified on the command-line.
2959 When ``default-push`` is set, it will be used for push and
2964 When ``default-push`` is set, it will be used for push and
2960 ``default`` will be used for pull; otherwise ``default`` is used
2965 ``default`` will be used for pull; otherwise ``default`` is used
2961 as the fallback for both. When cloning a repository, the clone
2966 as the fallback for both. When cloning a repository, the clone
2962 source is written as ``default`` in ``.hg/hgrc``. Note that
2967 source is written as ``default`` in ``.hg/hgrc``. Note that
2963 ``default`` and ``default-push`` apply to all inbound (e.g.
2968 ``default`` and ``default-push`` apply to all inbound (e.g.
2964 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email` and
2969 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email` and
2965 :hg:`bundle`) operations.
2970 :hg:`bundle`) operations.
2966
2971
2967 See :hg:`help urls` for more information.
2972 See :hg:`help urls` for more information.
2968
2973
2969 Returns 0 on success.
2974 Returns 0 on success.
2970 """
2975 """
2971 if search:
2976 if search:
2972 for name, path in ui.configitems("paths"):
2977 for name, path in ui.configitems("paths"):
2973 if name == search:
2978 if name == search:
2974 ui.write("%s\n" % util.hidepassword(path))
2979 ui.write("%s\n" % util.hidepassword(path))
2975 return
2980 return
2976 ui.warn(_("not found!\n"))
2981 ui.warn(_("not found!\n"))
2977 return 1
2982 return 1
2978 else:
2983 else:
2979 for name, path in ui.configitems("paths"):
2984 for name, path in ui.configitems("paths"):
2980 ui.write("%s = %s\n" % (name, util.hidepassword(path)))
2985 ui.write("%s = %s\n" % (name, util.hidepassword(path)))
2981
2986
2982 def postincoming(ui, repo, modheads, optupdate, checkout):
2987 def postincoming(ui, repo, modheads, optupdate, checkout):
2983 if modheads == 0:
2988 if modheads == 0:
2984 return
2989 return
2985 if optupdate:
2990 if optupdate:
2986 if (modheads <= 1 or len(repo.branchheads()) == 1) or checkout:
2991 if (modheads <= 1 or len(repo.branchheads()) == 1) or checkout:
2987 return hg.update(repo, checkout)
2992 return hg.update(repo, checkout)
2988 else:
2993 else:
2989 ui.status(_("not updating, since new heads added\n"))
2994 ui.status(_("not updating, since new heads added\n"))
2990 if modheads > 1:
2995 if modheads > 1:
2991 currentbranchheads = len(repo.branchheads())
2996 currentbranchheads = len(repo.branchheads())
2992 if currentbranchheads == modheads:
2997 if currentbranchheads == modheads:
2993 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
2998 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
2994 elif currentbranchheads > 1:
2999 elif currentbranchheads > 1:
2995 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to merge)\n"))
3000 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to merge)\n"))
2996 else:
3001 else:
2997 ui.status(_("(run 'hg heads' to see heads)\n"))
3002 ui.status(_("(run 'hg heads' to see heads)\n"))
2998 else:
3003 else:
2999 ui.status(_("(run 'hg update' to get a working copy)\n"))
3004 ui.status(_("(run 'hg update' to get a working copy)\n"))
3000
3005
3001 def pull(ui, repo, source="default", **opts):
3006 def pull(ui, repo, source="default", **opts):
3002 """pull changes from the specified source
3007 """pull changes from the specified source
3003
3008
3004 Pull changes from a remote repository to a local one.
3009 Pull changes from a remote repository to a local one.
3005
3010
3006 This finds all changes from the repository at the specified path
3011 This finds all changes from the repository at the specified path
3007 or URL and adds them to a local repository (the current one unless
3012 or URL and adds them to a local repository (the current one unless
3008 -R is specified). By default, this does not update the copy of the
3013 -R is specified). By default, this does not update the copy of the
3009 project in the working directory.
3014 project in the working directory.
3010
3015
3011 Use :hg:`incoming` if you want to see what would have been added
3016 Use :hg:`incoming` if you want to see what would have been added
3012 by a pull at the time you issued this command. If you then decide
3017 by a pull at the time you issued this command. If you then decide
3013 to add those changes to the repository, you should use :hg:`pull
3018 to add those changes to the repository, you should use :hg:`pull
3014 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
3019 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
3015
3020
3016 If SOURCE is omitted, the 'default' path will be used.
3021 If SOURCE is omitted, the 'default' path will be used.
3017 See :hg:`help urls` for more information.
3022 See :hg:`help urls` for more information.
3018
3023
3019 Returns 0 on success, 1 if an update had unresolved files.
3024 Returns 0 on success, 1 if an update had unresolved files.
3020 """
3025 """
3021 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
3026 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
3022 other = hg.repository(hg.remoteui(repo, opts), source)
3027 other = hg.repository(hg.remoteui(repo, opts), source)
3023 ui.status(_('pulling from %s\n') % util.hidepassword(source))
3028 ui.status(_('pulling from %s\n') % util.hidepassword(source))
3024 revs, checkout = hg.addbranchrevs(repo, other, branches, opts.get('rev'))
3029 revs, checkout = hg.addbranchrevs(repo, other, branches, opts.get('rev'))
3025
3030
3026 if opts.get('bookmark'):
3031 if opts.get('bookmark'):
3027 if not revs:
3032 if not revs:
3028 revs = []
3033 revs = []
3029 rb = other.listkeys('bookmarks')
3034 rb = other.listkeys('bookmarks')
3030 for b in opts['bookmark']:
3035 for b in opts['bookmark']:
3031 if b not in rb:
3036 if b not in rb:
3032 raise util.Abort(_('remote bookmark %s not found!') % b)
3037 raise util.Abort(_('remote bookmark %s not found!') % b)
3033 revs.append(rb[b])
3038 revs.append(rb[b])
3034
3039
3035 if revs:
3040 if revs:
3036 try:
3041 try:
3037 revs = [other.lookup(rev) for rev in revs]
3042 revs = [other.lookup(rev) for rev in revs]
3038 except error.CapabilityError:
3043 except error.CapabilityError:
3039 err = _("other repository doesn't support revision lookup, "
3044 err = _("other repository doesn't support revision lookup, "
3040 "so a rev cannot be specified.")
3045 "so a rev cannot be specified.")
3041 raise util.Abort(err)
3046 raise util.Abort(err)
3042
3047
3043 modheads = repo.pull(other, heads=revs, force=opts.get('force'))
3048 modheads = repo.pull(other, heads=revs, force=opts.get('force'))
3044 bookmarks.updatefromremote(ui, repo, other)
3049 bookmarks.updatefromremote(ui, repo, other)
3045 if checkout:
3050 if checkout:
3046 checkout = str(repo.changelog.rev(other.lookup(checkout)))
3051 checkout = str(repo.changelog.rev(other.lookup(checkout)))
3047 repo._subtoppath = source
3052 repo._subtoppath = source
3048 try:
3053 try:
3049 ret = postincoming(ui, repo, modheads, opts.get('update'), checkout)
3054 ret = postincoming(ui, repo, modheads, opts.get('update'), checkout)
3050
3055
3051 finally:
3056 finally:
3052 del repo._subtoppath
3057 del repo._subtoppath
3053
3058
3054 # update specified bookmarks
3059 # update specified bookmarks
3055 if opts.get('bookmark'):
3060 if opts.get('bookmark'):
3056 for b in opts['bookmark']:
3061 for b in opts['bookmark']:
3057 # explicit pull overrides local bookmark if any
3062 # explicit pull overrides local bookmark if any
3058 ui.status(_("importing bookmark %s\n") % b)
3063 ui.status(_("importing bookmark %s\n") % b)
3059 repo._bookmarks[b] = repo[rb[b]].node()
3064 repo._bookmarks[b] = repo[rb[b]].node()
3060 bookmarks.write(repo)
3065 bookmarks.write(repo)
3061
3066
3062 return ret
3067 return ret
3063
3068
3064 def push(ui, repo, dest=None, **opts):
3069 def push(ui, repo, dest=None, **opts):
3065 """push changes to the specified destination
3070 """push changes to the specified destination
3066
3071
3067 Push changesets from the local repository to the specified
3072 Push changesets from the local repository to the specified
3068 destination.
3073 destination.
3069
3074
3070 This operation is symmetrical to pull: it is identical to a pull
3075 This operation is symmetrical to pull: it is identical to a pull
3071 in the destination repository from the current one.
3076 in the destination repository from the current one.
3072
3077
3073 By default, push will not allow creation of new heads at the
3078 By default, push will not allow creation of new heads at the
3074 destination, since multiple heads would make it unclear which head
3079 destination, since multiple heads would make it unclear which head
3075 to use. In this situation, it is recommended to pull and merge
3080 to use. In this situation, it is recommended to pull and merge
3076 before pushing.
3081 before pushing.
3077
3082
3078 Use --new-branch if you want to allow push to create a new named
3083 Use --new-branch if you want to allow push to create a new named
3079 branch that is not present at the destination. This allows you to
3084 branch that is not present at the destination. This allows you to
3080 only create a new branch without forcing other changes.
3085 only create a new branch without forcing other changes.
3081
3086
3082 Use -f/--force to override the default behavior and push all
3087 Use -f/--force to override the default behavior and push all
3083 changesets on all branches.
3088 changesets on all branches.
3084
3089
3085 If -r/--rev is used, the specified revision and all its ancestors
3090 If -r/--rev is used, the specified revision and all its ancestors
3086 will be pushed to the remote repository.
3091 will be pushed to the remote repository.
3087
3092
3088 Please see :hg:`help urls` for important details about ``ssh://``
3093 Please see :hg:`help urls` for important details about ``ssh://``
3089 URLs. If DESTINATION is omitted, a default path will be used.
3094 URLs. If DESTINATION is omitted, a default path will be used.
3090
3095
3091 Returns 0 if push was successful, 1 if nothing to push.
3096 Returns 0 if push was successful, 1 if nothing to push.
3092 """
3097 """
3093
3098
3094 if opts.get('bookmark'):
3099 if opts.get('bookmark'):
3095 for b in opts['bookmark']:
3100 for b in opts['bookmark']:
3096 # translate -B options to -r so changesets get pushed
3101 # translate -B options to -r so changesets get pushed
3097 if b in repo._bookmarks:
3102 if b in repo._bookmarks:
3098 opts.setdefault('rev', []).append(b)
3103 opts.setdefault('rev', []).append(b)
3099 else:
3104 else:
3100 # if we try to push a deleted bookmark, translate it to null
3105 # if we try to push a deleted bookmark, translate it to null
3101 # this lets simultaneous -r, -b options continue working
3106 # this lets simultaneous -r, -b options continue working
3102 opts.setdefault('rev', []).append("null")
3107 opts.setdefault('rev', []).append("null")
3103
3108
3104 dest = ui.expandpath(dest or 'default-push', dest or 'default')
3109 dest = ui.expandpath(dest or 'default-push', dest or 'default')
3105 dest, branches = hg.parseurl(dest, opts.get('branch'))
3110 dest, branches = hg.parseurl(dest, opts.get('branch'))
3106 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
3111 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
3107 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
3112 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
3108 other = hg.repository(hg.remoteui(repo, opts), dest)
3113 other = hg.repository(hg.remoteui(repo, opts), dest)
3109 if revs:
3114 if revs:
3110 revs = [repo.lookup(rev) for rev in revs]
3115 revs = [repo.lookup(rev) for rev in revs]
3111
3116
3112 repo._subtoppath = dest
3117 repo._subtoppath = dest
3113 try:
3118 try:
3114 # push subrepos depth-first for coherent ordering
3119 # push subrepos depth-first for coherent ordering
3115 c = repo['']
3120 c = repo['']
3116 subs = c.substate # only repos that are committed
3121 subs = c.substate # only repos that are committed
3117 for s in sorted(subs):
3122 for s in sorted(subs):
3118 if not c.sub(s).push(opts.get('force')):
3123 if not c.sub(s).push(opts.get('force')):
3119 return False
3124 return False
3120 finally:
3125 finally:
3121 del repo._subtoppath
3126 del repo._subtoppath
3122 result = repo.push(other, opts.get('force'), revs=revs,
3127 result = repo.push(other, opts.get('force'), revs=revs,
3123 newbranch=opts.get('new_branch'))
3128 newbranch=opts.get('new_branch'))
3124
3129
3125 result = (result == 0)
3130 result = (result == 0)
3126
3131
3127 if opts.get('bookmark'):
3132 if opts.get('bookmark'):
3128 rb = other.listkeys('bookmarks')
3133 rb = other.listkeys('bookmarks')
3129 for b in opts['bookmark']:
3134 for b in opts['bookmark']:
3130 # explicit push overrides remote bookmark if any
3135 # explicit push overrides remote bookmark if any
3131 if b in repo._bookmarks:
3136 if b in repo._bookmarks:
3132 ui.status(_("exporting bookmark %s\n") % b)
3137 ui.status(_("exporting bookmark %s\n") % b)
3133 new = repo[b].hex()
3138 new = repo[b].hex()
3134 elif b in rb:
3139 elif b in rb:
3135 ui.status(_("deleting remote bookmark %s\n") % b)
3140 ui.status(_("deleting remote bookmark %s\n") % b)
3136 new = '' # delete
3141 new = '' # delete
3137 else:
3142 else:
3138 ui.warn(_('bookmark %s does not exist on the local '
3143 ui.warn(_('bookmark %s does not exist on the local '
3139 'or remote repository!\n') % b)
3144 'or remote repository!\n') % b)
3140 return 2
3145 return 2
3141 old = rb.get(b, '')
3146 old = rb.get(b, '')
3142 r = other.pushkey('bookmarks', b, old, new)
3147 r = other.pushkey('bookmarks', b, old, new)
3143 if not r:
3148 if not r:
3144 ui.warn(_('updating bookmark %s failed!\n') % b)
3149 ui.warn(_('updating bookmark %s failed!\n') % b)
3145 if not result:
3150 if not result:
3146 result = 2
3151 result = 2
3147
3152
3148 return result
3153 return result
3149
3154
3150 def recover(ui, repo):
3155 def recover(ui, repo):
3151 """roll back an interrupted transaction
3156 """roll back an interrupted transaction
3152
3157
3153 Recover from an interrupted commit or pull.
3158 Recover from an interrupted commit or pull.
3154
3159
3155 This command tries to fix the repository status after an
3160 This command tries to fix the repository status after an
3156 interrupted operation. It should only be necessary when Mercurial
3161 interrupted operation. It should only be necessary when Mercurial
3157 suggests it.
3162 suggests it.
3158
3163
3159 Returns 0 if successful, 1 if nothing to recover or verify fails.
3164 Returns 0 if successful, 1 if nothing to recover or verify fails.
3160 """
3165 """
3161 if repo.recover():
3166 if repo.recover():
3162 return hg.verify(repo)
3167 return hg.verify(repo)
3163 return 1
3168 return 1
3164
3169
3165 def remove(ui, repo, *pats, **opts):
3170 def remove(ui, repo, *pats, **opts):
3166 """remove the specified files on the next commit
3171 """remove the specified files on the next commit
3167
3172
3168 Schedule the indicated files for removal from the repository.
3173 Schedule the indicated files for removal from the repository.
3169
3174
3170 This only removes files from the current branch, not from the
3175 This only removes files from the current branch, not from the
3171 entire project history. -A/--after can be used to remove only
3176 entire project history. -A/--after can be used to remove only
3172 files that have already been deleted, -f/--force can be used to
3177 files that have already been deleted, -f/--force can be used to
3173 force deletion, and -Af can be used to remove files from the next
3178 force deletion, and -Af can be used to remove files from the next
3174 revision without deleting them from the working directory.
3179 revision without deleting them from the working directory.
3175
3180
3176 The following table details the behavior of remove for different
3181 The following table details the behavior of remove for different
3177 file states (columns) and option combinations (rows). The file
3182 file states (columns) and option combinations (rows). The file
3178 states are Added [A], Clean [C], Modified [M] and Missing [!] (as
3183 states are Added [A], Clean [C], Modified [M] and Missing [!] (as
3179 reported by :hg:`status`). The actions are Warn, Remove (from
3184 reported by :hg:`status`). The actions are Warn, Remove (from
3180 branch) and Delete (from disk)::
3185 branch) and Delete (from disk)::
3181
3186
3182 A C M !
3187 A C M !
3183 none W RD W R
3188 none W RD W R
3184 -f R RD RD R
3189 -f R RD RD R
3185 -A W W W R
3190 -A W W W R
3186 -Af R R R R
3191 -Af R R R R
3187
3192
3188 This command schedules the files to be removed at the next commit.
3193 This command schedules the files to be removed at the next commit.
3189 To undo a remove before that, see :hg:`revert`.
3194 To undo a remove before that, see :hg:`revert`.
3190
3195
3191 Returns 0 on success, 1 if any warnings encountered.
3196 Returns 0 on success, 1 if any warnings encountered.
3192 """
3197 """
3193
3198
3194 ret = 0
3199 ret = 0
3195 after, force = opts.get('after'), opts.get('force')
3200 after, force = opts.get('after'), opts.get('force')
3196 if not pats and not after:
3201 if not pats and not after:
3197 raise util.Abort(_('no files specified'))
3202 raise util.Abort(_('no files specified'))
3198
3203
3199 m = cmdutil.match(repo, pats, opts)
3204 m = cmdutil.match(repo, pats, opts)
3200 s = repo.status(match=m, clean=True)
3205 s = repo.status(match=m, clean=True)
3201 modified, added, deleted, clean = s[0], s[1], s[3], s[6]
3206 modified, added, deleted, clean = s[0], s[1], s[3], s[6]
3202
3207
3203 for f in m.files():
3208 for f in m.files():
3204 if f not in repo.dirstate and not os.path.isdir(m.rel(f)):
3209 if f not in repo.dirstate and not os.path.isdir(m.rel(f)):
3205 ui.warn(_('not removing %s: file is untracked\n') % m.rel(f))
3210 ui.warn(_('not removing %s: file is untracked\n') % m.rel(f))
3206 ret = 1
3211 ret = 1
3207
3212
3208 if force:
3213 if force:
3209 remove, forget = modified + deleted + clean, added
3214 remove, forget = modified + deleted + clean, added
3210 elif after:
3215 elif after:
3211 remove, forget = deleted, []
3216 remove, forget = deleted, []
3212 for f in modified + added + clean:
3217 for f in modified + added + clean:
3213 ui.warn(_('not removing %s: file still exists (use -f'
3218 ui.warn(_('not removing %s: file still exists (use -f'
3214 ' to force removal)\n') % m.rel(f))
3219 ' to force removal)\n') % m.rel(f))
3215 ret = 1
3220 ret = 1
3216 else:
3221 else:
3217 remove, forget = deleted + clean, []
3222 remove, forget = deleted + clean, []
3218 for f in modified:
3223 for f in modified:
3219 ui.warn(_('not removing %s: file is modified (use -f'
3224 ui.warn(_('not removing %s: file is modified (use -f'
3220 ' to force removal)\n') % m.rel(f))
3225 ' to force removal)\n') % m.rel(f))
3221 ret = 1
3226 ret = 1
3222 for f in added:
3227 for f in added:
3223 ui.warn(_('not removing %s: file has been marked for add (use -f'
3228 ui.warn(_('not removing %s: file has been marked for add (use -f'
3224 ' to force removal)\n') % m.rel(f))
3229 ' to force removal)\n') % m.rel(f))
3225 ret = 1
3230 ret = 1
3226
3231
3227 for f in sorted(remove + forget):
3232 for f in sorted(remove + forget):
3228 if ui.verbose or not m.exact(f):
3233 if ui.verbose or not m.exact(f):
3229 ui.status(_('removing %s\n') % m.rel(f))
3234 ui.status(_('removing %s\n') % m.rel(f))
3230
3235
3231 repo[None].forget(forget)
3236 repo[None].forget(forget)
3232 repo[None].remove(remove, unlink=not after)
3237 repo[None].remove(remove, unlink=not after)
3233 return ret
3238 return ret
3234
3239
3235 def rename(ui, repo, *pats, **opts):
3240 def rename(ui, repo, *pats, **opts):
3236 """rename files; equivalent of copy + remove
3241 """rename files; equivalent of copy + remove
3237
3242
3238 Mark dest as copies of sources; mark sources for deletion. If dest
3243 Mark dest as copies of sources; mark sources for deletion. If dest
3239 is a directory, copies are put in that directory. If dest is a
3244 is a directory, copies are put in that directory. If dest is a
3240 file, there can only be one source.
3245 file, there can only be one source.
3241
3246
3242 By default, this command copies the contents of files as they
3247 By default, this command copies the contents of files as they
3243 exist in the working directory. If invoked with -A/--after, the
3248 exist in the working directory. If invoked with -A/--after, the
3244 operation is recorded, but no copying is performed.
3249 operation is recorded, but no copying is performed.
3245
3250
3246 This command takes effect at the next commit. To undo a rename
3251 This command takes effect at the next commit. To undo a rename
3247 before that, see :hg:`revert`.
3252 before that, see :hg:`revert`.
3248
3253
3249 Returns 0 on success, 1 if errors are encountered.
3254 Returns 0 on success, 1 if errors are encountered.
3250 """
3255 """
3251 wlock = repo.wlock(False)
3256 wlock = repo.wlock(False)
3252 try:
3257 try:
3253 return cmdutil.copy(ui, repo, pats, opts, rename=True)
3258 return cmdutil.copy(ui, repo, pats, opts, rename=True)
3254 finally:
3259 finally:
3255 wlock.release()
3260 wlock.release()
3256
3261
3257 def resolve(ui, repo, *pats, **opts):
3262 def resolve(ui, repo, *pats, **opts):
3258 """redo merges or set/view the merge status of files
3263 """redo merges or set/view the merge status of files
3259
3264
3260 Merges with unresolved conflicts are often the result of
3265 Merges with unresolved conflicts are often the result of
3261 non-interactive merging using the ``internal:merge`` configuration
3266 non-interactive merging using the ``internal:merge`` configuration
3262 setting, or a command-line merge tool like ``diff3``. The resolve
3267 setting, or a command-line merge tool like ``diff3``. The resolve
3263 command is used to manage the files involved in a merge, after
3268 command is used to manage the files involved in a merge, after
3264 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
3269 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
3265 working directory must have two parents).
3270 working directory must have two parents).
3266
3271
3267 The resolve command can be used in the following ways:
3272 The resolve command can be used in the following ways:
3268
3273
3269 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
3274 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
3270 files, discarding any previous merge attempts. Re-merging is not
3275 files, discarding any previous merge attempts. Re-merging is not
3271 performed for files already marked as resolved. Use ``--all/-a``
3276 performed for files already marked as resolved. Use ``--all/-a``
3272 to selects all unresolved files. ``--tool`` can be used to specify
3277 to selects all unresolved files. ``--tool`` can be used to specify
3273 the merge tool used for the given files. It overrides the HGMERGE
3278 the merge tool used for the given files. It overrides the HGMERGE
3274 environment variable and your configuration files.
3279 environment variable and your configuration files.
3275
3280
3276 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
3281 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
3277 (e.g. after having manually fixed-up the files). The default is
3282 (e.g. after having manually fixed-up the files). The default is
3278 to mark all unresolved files.
3283 to mark all unresolved files.
3279
3284
3280 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
3285 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
3281 default is to mark all resolved files.
3286 default is to mark all resolved files.
3282
3287
3283 - :hg:`resolve -l`: list files which had or still have conflicts.
3288 - :hg:`resolve -l`: list files which had or still have conflicts.
3284 In the printed list, ``U`` = unresolved and ``R`` = resolved.
3289 In the printed list, ``U`` = unresolved and ``R`` = resolved.
3285
3290
3286 Note that Mercurial will not let you commit files with unresolved
3291 Note that Mercurial will not let you commit files with unresolved
3287 merge conflicts. You must use :hg:`resolve -m ...` before you can
3292 merge conflicts. You must use :hg:`resolve -m ...` before you can
3288 commit after a conflicting merge.
3293 commit after a conflicting merge.
3289
3294
3290 Returns 0 on success, 1 if any files fail a resolve attempt.
3295 Returns 0 on success, 1 if any files fail a resolve attempt.
3291 """
3296 """
3292
3297
3293 all, mark, unmark, show, nostatus = \
3298 all, mark, unmark, show, nostatus = \
3294 [opts.get(o) for o in 'all mark unmark list no_status'.split()]
3299 [opts.get(o) for o in 'all mark unmark list no_status'.split()]
3295
3300
3296 if (show and (mark or unmark)) or (mark and unmark):
3301 if (show and (mark or unmark)) or (mark and unmark):
3297 raise util.Abort(_("too many options specified"))
3302 raise util.Abort(_("too many options specified"))
3298 if pats and all:
3303 if pats and all:
3299 raise util.Abort(_("can't specify --all and patterns"))
3304 raise util.Abort(_("can't specify --all and patterns"))
3300 if not (all or pats or show or mark or unmark):
3305 if not (all or pats or show or mark or unmark):
3301 raise util.Abort(_('no files or directories specified; '
3306 raise util.Abort(_('no files or directories specified; '
3302 'use --all to remerge all files'))
3307 'use --all to remerge all files'))
3303
3308
3304 ms = mergemod.mergestate(repo)
3309 ms = mergemod.mergestate(repo)
3305 m = cmdutil.match(repo, pats, opts)
3310 m = cmdutil.match(repo, pats, opts)
3306 ret = 0
3311 ret = 0
3307
3312
3308 for f in ms:
3313 for f in ms:
3309 if m(f):
3314 if m(f):
3310 if show:
3315 if show:
3311 if nostatus:
3316 if nostatus:
3312 ui.write("%s\n" % f)
3317 ui.write("%s\n" % f)
3313 else:
3318 else:
3314 ui.write("%s %s\n" % (ms[f].upper(), f),
3319 ui.write("%s %s\n" % (ms[f].upper(), f),
3315 label='resolve.' +
3320 label='resolve.' +
3316 {'u': 'unresolved', 'r': 'resolved'}[ms[f]])
3321 {'u': 'unresolved', 'r': 'resolved'}[ms[f]])
3317 elif mark:
3322 elif mark:
3318 ms.mark(f, "r")
3323 ms.mark(f, "r")
3319 elif unmark:
3324 elif unmark:
3320 ms.mark(f, "u")
3325 ms.mark(f, "u")
3321 else:
3326 else:
3322 wctx = repo[None]
3327 wctx = repo[None]
3323 mctx = wctx.parents()[-1]
3328 mctx = wctx.parents()[-1]
3324
3329
3325 # backup pre-resolve (merge uses .orig for its own purposes)
3330 # backup pre-resolve (merge uses .orig for its own purposes)
3326 a = repo.wjoin(f)
3331 a = repo.wjoin(f)
3327 util.copyfile(a, a + ".resolve")
3332 util.copyfile(a, a + ".resolve")
3328
3333
3329 try:
3334 try:
3330 # resolve file
3335 # resolve file
3331 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
3336 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''))
3332 if ms.resolve(f, wctx, mctx):
3337 if ms.resolve(f, wctx, mctx):
3333 ret = 1
3338 ret = 1
3334 finally:
3339 finally:
3335 ui.setconfig('ui', 'forcemerge', '')
3340 ui.setconfig('ui', 'forcemerge', '')
3336
3341
3337 # replace filemerge's .orig file with our resolve file
3342 # replace filemerge's .orig file with our resolve file
3338 util.rename(a + ".resolve", a + ".orig")
3343 util.rename(a + ".resolve", a + ".orig")
3339
3344
3340 ms.commit()
3345 ms.commit()
3341 return ret
3346 return ret
3342
3347
3343 def revert(ui, repo, *pats, **opts):
3348 def revert(ui, repo, *pats, **opts):
3344 """restore individual files or directories to an earlier state
3349 """restore individual files or directories to an earlier state
3345
3350
3346 .. note::
3351 .. note::
3347 This command is most likely not what you are looking for.
3352 This command is most likely not what you are looking for.
3348 Revert will partially overwrite content in the working
3353 Revert will partially overwrite content in the working
3349 directory without changing the working directory parents. Use
3354 directory without changing the working directory parents. Use
3350 :hg:`update -r rev` to check out earlier revisions, or
3355 :hg:`update -r rev` to check out earlier revisions, or
3351 :hg:`update --clean .` to undo a merge which has added another
3356 :hg:`update --clean .` to undo a merge which has added another
3352 parent.
3357 parent.
3353
3358
3354 With no revision specified, revert the named files or directories
3359 With no revision specified, revert the named files or directories
3355 to the contents they had in the parent of the working directory.
3360 to the contents they had in the parent of the working directory.
3356 This restores the contents of the affected files to an unmodified
3361 This restores the contents of the affected files to an unmodified
3357 state and unschedules adds, removes, copies, and renames. If the
3362 state and unschedules adds, removes, copies, and renames. If the
3358 working directory has two parents, you must explicitly specify a
3363 working directory has two parents, you must explicitly specify a
3359 revision.
3364 revision.
3360
3365
3361 Using the -r/--rev option, revert the given files or directories
3366 Using the -r/--rev option, revert the given files or directories
3362 to their contents as of a specific revision. This can be helpful
3367 to their contents as of a specific revision. This can be helpful
3363 to "roll back" some or all of an earlier change. See :hg:`help
3368 to "roll back" some or all of an earlier change. See :hg:`help
3364 dates` for a list of formats valid for -d/--date.
3369 dates` for a list of formats valid for -d/--date.
3365
3370
3366 Revert modifies the working directory. It does not commit any
3371 Revert modifies the working directory. It does not commit any
3367 changes, or change the parent of the working directory. If you
3372 changes, or change the parent of the working directory. If you
3368 revert to a revision other than the parent of the working
3373 revert to a revision other than the parent of the working
3369 directory, the reverted files will thus appear modified
3374 directory, the reverted files will thus appear modified
3370 afterwards.
3375 afterwards.
3371
3376
3372 If a file has been deleted, it is restored. Files scheduled for
3377 If a file has been deleted, it is restored. Files scheduled for
3373 addition are just unscheduled and left as they are. If the
3378 addition are just unscheduled and left as they are. If the
3374 executable mode of a file was changed, it is reset.
3379 executable mode of a file was changed, it is reset.
3375
3380
3376 If names are given, all files matching the names are reverted.
3381 If names are given, all files matching the names are reverted.
3377 If no arguments are given, no files are reverted.
3382 If no arguments are given, no files are reverted.
3378
3383
3379 Modified files are saved with a .orig suffix before reverting.
3384 Modified files are saved with a .orig suffix before reverting.
3380 To disable these backups, use --no-backup.
3385 To disable these backups, use --no-backup.
3381
3386
3382 Returns 0 on success.
3387 Returns 0 on success.
3383 """
3388 """
3384
3389
3385 if opts.get("date"):
3390 if opts.get("date"):
3386 if opts.get("rev"):
3391 if opts.get("rev"):
3387 raise util.Abort(_("you can't specify a revision and a date"))
3392 raise util.Abort(_("you can't specify a revision and a date"))
3388 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
3393 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
3389
3394
3390 parent, p2 = repo.dirstate.parents()
3395 parent, p2 = repo.dirstate.parents()
3391 if not opts.get('rev') and p2 != nullid:
3396 if not opts.get('rev') and p2 != nullid:
3392 raise util.Abort(_('uncommitted merge - '
3397 raise util.Abort(_('uncommitted merge - '
3393 'use "hg update", see "hg help revert"'))
3398 'use "hg update", see "hg help revert"'))
3394
3399
3395 if not pats and not opts.get('all'):
3400 if not pats and not opts.get('all'):
3396 raise util.Abort(_('no files or directories specified; '
3401 raise util.Abort(_('no files or directories specified; '
3397 'use --all to revert the whole repo'))
3402 'use --all to revert the whole repo'))
3398
3403
3399 ctx = cmdutil.revsingle(repo, opts.get('rev'))
3404 ctx = cmdutil.revsingle(repo, opts.get('rev'))
3400 node = ctx.node()
3405 node = ctx.node()
3401 mf = ctx.manifest()
3406 mf = ctx.manifest()
3402 if node == parent:
3407 if node == parent:
3403 pmf = mf
3408 pmf = mf
3404 else:
3409 else:
3405 pmf = None
3410 pmf = None
3406
3411
3407 # need all matching names in dirstate and manifest of target rev,
3412 # need all matching names in dirstate and manifest of target rev,
3408 # so have to walk both. do not print errors if files exist in one
3413 # so have to walk both. do not print errors if files exist in one
3409 # but not other.
3414 # but not other.
3410
3415
3411 names = {}
3416 names = {}
3412
3417
3413 wlock = repo.wlock()
3418 wlock = repo.wlock()
3414 try:
3419 try:
3415 # walk dirstate.
3420 # walk dirstate.
3416
3421
3417 m = cmdutil.match(repo, pats, opts)
3422 m = cmdutil.match(repo, pats, opts)
3418 m.bad = lambda x, y: False
3423 m.bad = lambda x, y: False
3419 for abs in repo.walk(m):
3424 for abs in repo.walk(m):
3420 names[abs] = m.rel(abs), m.exact(abs)
3425 names[abs] = m.rel(abs), m.exact(abs)
3421
3426
3422 # walk target manifest.
3427 # walk target manifest.
3423
3428
3424 def badfn(path, msg):
3429 def badfn(path, msg):
3425 if path in names:
3430 if path in names:
3426 return
3431 return
3427 path_ = path + '/'
3432 path_ = path + '/'
3428 for f in names:
3433 for f in names:
3429 if f.startswith(path_):
3434 if f.startswith(path_):
3430 return
3435 return
3431 ui.warn("%s: %s\n" % (m.rel(path), msg))
3436 ui.warn("%s: %s\n" % (m.rel(path), msg))
3432
3437
3433 m = cmdutil.match(repo, pats, opts)
3438 m = cmdutil.match(repo, pats, opts)
3434 m.bad = badfn
3439 m.bad = badfn
3435 for abs in repo[node].walk(m):
3440 for abs in repo[node].walk(m):
3436 if abs not in names:
3441 if abs not in names:
3437 names[abs] = m.rel(abs), m.exact(abs)
3442 names[abs] = m.rel(abs), m.exact(abs)
3438
3443
3439 m = cmdutil.matchfiles(repo, names)
3444 m = cmdutil.matchfiles(repo, names)
3440 changes = repo.status(match=m)[:4]
3445 changes = repo.status(match=m)[:4]
3441 modified, added, removed, deleted = map(set, changes)
3446 modified, added, removed, deleted = map(set, changes)
3442
3447
3443 # if f is a rename, also revert the source
3448 # if f is a rename, also revert the source
3444 cwd = repo.getcwd()
3449 cwd = repo.getcwd()
3445 for f in added:
3450 for f in added:
3446 src = repo.dirstate.copied(f)
3451 src = repo.dirstate.copied(f)
3447 if src and src not in names and repo.dirstate[src] == 'r':
3452 if src and src not in names and repo.dirstate[src] == 'r':
3448 removed.add(src)
3453 removed.add(src)
3449 names[src] = (repo.pathto(src, cwd), True)
3454 names[src] = (repo.pathto(src, cwd), True)
3450
3455
3451 def removeforget(abs):
3456 def removeforget(abs):
3452 if repo.dirstate[abs] == 'a':
3457 if repo.dirstate[abs] == 'a':
3453 return _('forgetting %s\n')
3458 return _('forgetting %s\n')
3454 return _('removing %s\n')
3459 return _('removing %s\n')
3455
3460
3456 revert = ([], _('reverting %s\n'))
3461 revert = ([], _('reverting %s\n'))
3457 add = ([], _('adding %s\n'))
3462 add = ([], _('adding %s\n'))
3458 remove = ([], removeforget)
3463 remove = ([], removeforget)
3459 undelete = ([], _('undeleting %s\n'))
3464 undelete = ([], _('undeleting %s\n'))
3460
3465
3461 disptable = (
3466 disptable = (
3462 # dispatch table:
3467 # dispatch table:
3463 # file state
3468 # file state
3464 # action if in target manifest
3469 # action if in target manifest
3465 # action if not in target manifest
3470 # action if not in target manifest
3466 # make backup if in target manifest
3471 # make backup if in target manifest
3467 # make backup if not in target manifest
3472 # make backup if not in target manifest
3468 (modified, revert, remove, True, True),
3473 (modified, revert, remove, True, True),
3469 (added, revert, remove, True, False),
3474 (added, revert, remove, True, False),
3470 (removed, undelete, None, False, False),
3475 (removed, undelete, None, False, False),
3471 (deleted, revert, remove, False, False),
3476 (deleted, revert, remove, False, False),
3472 )
3477 )
3473
3478
3474 for abs, (rel, exact) in sorted(names.items()):
3479 for abs, (rel, exact) in sorted(names.items()):
3475 mfentry = mf.get(abs)
3480 mfentry = mf.get(abs)
3476 target = repo.wjoin(abs)
3481 target = repo.wjoin(abs)
3477 def handle(xlist, dobackup):
3482 def handle(xlist, dobackup):
3478 xlist[0].append(abs)
3483 xlist[0].append(abs)
3479 if (dobackup and not opts.get('no_backup') and
3484 if (dobackup and not opts.get('no_backup') and
3480 os.path.lexists(target)):
3485 os.path.lexists(target)):
3481 bakname = "%s.orig" % rel
3486 bakname = "%s.orig" % rel
3482 ui.note(_('saving current version of %s as %s\n') %
3487 ui.note(_('saving current version of %s as %s\n') %
3483 (rel, bakname))
3488 (rel, bakname))
3484 if not opts.get('dry_run'):
3489 if not opts.get('dry_run'):
3485 util.rename(target, bakname)
3490 util.rename(target, bakname)
3486 if ui.verbose or not exact:
3491 if ui.verbose or not exact:
3487 msg = xlist[1]
3492 msg = xlist[1]
3488 if not isinstance(msg, basestring):
3493 if not isinstance(msg, basestring):
3489 msg = msg(abs)
3494 msg = msg(abs)
3490 ui.status(msg % rel)
3495 ui.status(msg % rel)
3491 for table, hitlist, misslist, backuphit, backupmiss in disptable:
3496 for table, hitlist, misslist, backuphit, backupmiss in disptable:
3492 if abs not in table:
3497 if abs not in table:
3493 continue
3498 continue
3494 # file has changed in dirstate
3499 # file has changed in dirstate
3495 if mfentry:
3500 if mfentry:
3496 handle(hitlist, backuphit)
3501 handle(hitlist, backuphit)
3497 elif misslist is not None:
3502 elif misslist is not None:
3498 handle(misslist, backupmiss)
3503 handle(misslist, backupmiss)
3499 break
3504 break
3500 else:
3505 else:
3501 if abs not in repo.dirstate:
3506 if abs not in repo.dirstate:
3502 if mfentry:
3507 if mfentry:
3503 handle(add, True)
3508 handle(add, True)
3504 elif exact:
3509 elif exact:
3505 ui.warn(_('file not managed: %s\n') % rel)
3510 ui.warn(_('file not managed: %s\n') % rel)
3506 continue
3511 continue
3507 # file has not changed in dirstate
3512 # file has not changed in dirstate
3508 if node == parent:
3513 if node == parent:
3509 if exact:
3514 if exact:
3510 ui.warn(_('no changes needed to %s\n') % rel)
3515 ui.warn(_('no changes needed to %s\n') % rel)
3511 continue
3516 continue
3512 if pmf is None:
3517 if pmf is None:
3513 # only need parent manifest in this unlikely case,
3518 # only need parent manifest in this unlikely case,
3514 # so do not read by default
3519 # so do not read by default
3515 pmf = repo[parent].manifest()
3520 pmf = repo[parent].manifest()
3516 if abs in pmf:
3521 if abs in pmf:
3517 if mfentry:
3522 if mfentry:
3518 # if version of file is same in parent and target
3523 # if version of file is same in parent and target
3519 # manifests, do nothing
3524 # manifests, do nothing
3520 if (pmf[abs] != mfentry or
3525 if (pmf[abs] != mfentry or
3521 pmf.flags(abs) != mf.flags(abs)):
3526 pmf.flags(abs) != mf.flags(abs)):
3522 handle(revert, False)
3527 handle(revert, False)
3523 else:
3528 else:
3524 handle(remove, False)
3529 handle(remove, False)
3525
3530
3526 if not opts.get('dry_run'):
3531 if not opts.get('dry_run'):
3527 def checkout(f):
3532 def checkout(f):
3528 fc = ctx[f]
3533 fc = ctx[f]
3529 repo.wwrite(f, fc.data(), fc.flags())
3534 repo.wwrite(f, fc.data(), fc.flags())
3530
3535
3531 audit_path = scmutil.path_auditor(repo.root)
3536 audit_path = scmutil.path_auditor(repo.root)
3532 for f in remove[0]:
3537 for f in remove[0]:
3533 if repo.dirstate[f] == 'a':
3538 if repo.dirstate[f] == 'a':
3534 repo.dirstate.forget(f)
3539 repo.dirstate.forget(f)
3535 continue
3540 continue
3536 audit_path(f)
3541 audit_path(f)
3537 try:
3542 try:
3538 util.unlinkpath(repo.wjoin(f))
3543 util.unlinkpath(repo.wjoin(f))
3539 except OSError:
3544 except OSError:
3540 pass
3545 pass
3541 repo.dirstate.remove(f)
3546 repo.dirstate.remove(f)
3542
3547
3543 normal = None
3548 normal = None
3544 if node == parent:
3549 if node == parent:
3545 # We're reverting to our parent. If possible, we'd like status
3550 # We're reverting to our parent. If possible, we'd like status
3546 # to report the file as clean. We have to use normallookup for
3551 # to report the file as clean. We have to use normallookup for
3547 # merges to avoid losing information about merged/dirty files.
3552 # merges to avoid losing information about merged/dirty files.
3548 if p2 != nullid:
3553 if p2 != nullid:
3549 normal = repo.dirstate.normallookup
3554 normal = repo.dirstate.normallookup
3550 else:
3555 else:
3551 normal = repo.dirstate.normal
3556 normal = repo.dirstate.normal
3552 for f in revert[0]:
3557 for f in revert[0]:
3553 checkout(f)
3558 checkout(f)
3554 if normal:
3559 if normal:
3555 normal(f)
3560 normal(f)
3556
3561
3557 for f in add[0]:
3562 for f in add[0]:
3558 checkout(f)
3563 checkout(f)
3559 repo.dirstate.add(f)
3564 repo.dirstate.add(f)
3560
3565
3561 normal = repo.dirstate.normallookup
3566 normal = repo.dirstate.normallookup
3562 if node == parent and p2 == nullid:
3567 if node == parent and p2 == nullid:
3563 normal = repo.dirstate.normal
3568 normal = repo.dirstate.normal
3564 for f in undelete[0]:
3569 for f in undelete[0]:
3565 checkout(f)
3570 checkout(f)
3566 normal(f)
3571 normal(f)
3567
3572
3568 finally:
3573 finally:
3569 wlock.release()
3574 wlock.release()
3570
3575
3571 def rollback(ui, repo, **opts):
3576 def rollback(ui, repo, **opts):
3572 """roll back the last transaction (dangerous)
3577 """roll back the last transaction (dangerous)
3573
3578
3574 This command should be used with care. There is only one level of
3579 This command should be used with care. There is only one level of
3575 rollback, and there is no way to undo a rollback. It will also
3580 rollback, and there is no way to undo a rollback. It will also
3576 restore the dirstate at the time of the last transaction, losing
3581 restore the dirstate at the time of the last transaction, losing
3577 any dirstate changes since that time. This command does not alter
3582 any dirstate changes since that time. This command does not alter
3578 the working directory.
3583 the working directory.
3579
3584
3580 Transactions are used to encapsulate the effects of all commands
3585 Transactions are used to encapsulate the effects of all commands
3581 that create new changesets or propagate existing changesets into a
3586 that create new changesets or propagate existing changesets into a
3582 repository. For example, the following commands are transactional,
3587 repository. For example, the following commands are transactional,
3583 and their effects can be rolled back:
3588 and their effects can be rolled back:
3584
3589
3585 - commit
3590 - commit
3586 - import
3591 - import
3587 - pull
3592 - pull
3588 - push (with this repository as the destination)
3593 - push (with this repository as the destination)
3589 - unbundle
3594 - unbundle
3590
3595
3591 This command is not intended for use on public repositories. Once
3596 This command is not intended for use on public repositories. Once
3592 changes are visible for pull by other users, rolling a transaction
3597 changes are visible for pull by other users, rolling a transaction
3593 back locally is ineffective (someone else may already have pulled
3598 back locally is ineffective (someone else may already have pulled
3594 the changes). Furthermore, a race is possible with readers of the
3599 the changes). Furthermore, a race is possible with readers of the
3595 repository; for example an in-progress pull from the repository
3600 repository; for example an in-progress pull from the repository
3596 may fail if a rollback is performed.
3601 may fail if a rollback is performed.
3597
3602
3598 Returns 0 on success, 1 if no rollback data is available.
3603 Returns 0 on success, 1 if no rollback data is available.
3599 """
3604 """
3600 return repo.rollback(opts.get('dry_run'))
3605 return repo.rollback(opts.get('dry_run'))
3601
3606
3602 def root(ui, repo):
3607 def root(ui, repo):
3603 """print the root (top) of the current working directory
3608 """print the root (top) of the current working directory
3604
3609
3605 Print the root directory of the current repository.
3610 Print the root directory of the current repository.
3606
3611
3607 Returns 0 on success.
3612 Returns 0 on success.
3608 """
3613 """
3609 ui.write(repo.root + "\n")
3614 ui.write(repo.root + "\n")
3610
3615
3611 def serve(ui, repo, **opts):
3616 def serve(ui, repo, **opts):
3612 """start stand-alone webserver
3617 """start stand-alone webserver
3613
3618
3614 Start a local HTTP repository browser and pull server. You can use
3619 Start a local HTTP repository browser and pull server. You can use
3615 this for ad-hoc sharing and browsing of repositories. It is
3620 this for ad-hoc sharing and browsing of repositories. It is
3616 recommended to use a real web server to serve a repository for
3621 recommended to use a real web server to serve a repository for
3617 longer periods of time.
3622 longer periods of time.
3618
3623
3619 Please note that the server does not implement access control.
3624 Please note that the server does not implement access control.
3620 This means that, by default, anybody can read from the server and
3625 This means that, by default, anybody can read from the server and
3621 nobody can write to it by default. Set the ``web.allow_push``
3626 nobody can write to it by default. Set the ``web.allow_push``
3622 option to ``*`` to allow everybody to push to the server. You
3627 option to ``*`` to allow everybody to push to the server. You
3623 should use a real web server if you need to authenticate users.
3628 should use a real web server if you need to authenticate users.
3624
3629
3625 By default, the server logs accesses to stdout and errors to
3630 By default, the server logs accesses to stdout and errors to
3626 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
3631 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
3627 files.
3632 files.
3628
3633
3629 To have the server choose a free port number to listen on, specify
3634 To have the server choose a free port number to listen on, specify
3630 a port number of 0; in this case, the server will print the port
3635 a port number of 0; in this case, the server will print the port
3631 number it uses.
3636 number it uses.
3632
3637
3633 Returns 0 on success.
3638 Returns 0 on success.
3634 """
3639 """
3635
3640
3636 if opts["stdio"]:
3641 if opts["stdio"]:
3637 if repo is None:
3642 if repo is None:
3638 raise error.RepoError(_("There is no Mercurial repository here"
3643 raise error.RepoError(_("There is no Mercurial repository here"
3639 " (.hg not found)"))
3644 " (.hg not found)"))
3640 s = sshserver.sshserver(ui, repo)
3645 s = sshserver.sshserver(ui, repo)
3641 s.serve_forever()
3646 s.serve_forever()
3642
3647
3643 # this way we can check if something was given in the command-line
3648 # this way we can check if something was given in the command-line
3644 if opts.get('port'):
3649 if opts.get('port'):
3645 opts['port'] = util.getport(opts.get('port'))
3650 opts['port'] = util.getport(opts.get('port'))
3646
3651
3647 baseui = repo and repo.baseui or ui
3652 baseui = repo and repo.baseui or ui
3648 optlist = ("name templates style address port prefix ipv6"
3653 optlist = ("name templates style address port prefix ipv6"
3649 " accesslog errorlog certificate encoding")
3654 " accesslog errorlog certificate encoding")
3650 for o in optlist.split():
3655 for o in optlist.split():
3651 val = opts.get(o, '')
3656 val = opts.get(o, '')
3652 if val in (None, ''): # should check against default options instead
3657 if val in (None, ''): # should check against default options instead
3653 continue
3658 continue
3654 baseui.setconfig("web", o, val)
3659 baseui.setconfig("web", o, val)
3655 if repo and repo.ui != baseui:
3660 if repo and repo.ui != baseui:
3656 repo.ui.setconfig("web", o, val)
3661 repo.ui.setconfig("web", o, val)
3657
3662
3658 o = opts.get('web_conf') or opts.get('webdir_conf')
3663 o = opts.get('web_conf') or opts.get('webdir_conf')
3659 if not o:
3664 if not o:
3660 if not repo:
3665 if not repo:
3661 raise error.RepoError(_("There is no Mercurial repository"
3666 raise error.RepoError(_("There is no Mercurial repository"
3662 " here (.hg not found)"))
3667 " here (.hg not found)"))
3663 o = repo.root
3668 o = repo.root
3664
3669
3665 app = hgweb.hgweb(o, baseui=ui)
3670 app = hgweb.hgweb(o, baseui=ui)
3666
3671
3667 class service(object):
3672 class service(object):
3668 def init(self):
3673 def init(self):
3669 util.set_signal_handler()
3674 util.set_signal_handler()
3670 self.httpd = hgweb.server.create_server(ui, app)
3675 self.httpd = hgweb.server.create_server(ui, app)
3671
3676
3672 if opts['port'] and not ui.verbose:
3677 if opts['port'] and not ui.verbose:
3673 return
3678 return
3674
3679
3675 if self.httpd.prefix:
3680 if self.httpd.prefix:
3676 prefix = self.httpd.prefix.strip('/') + '/'
3681 prefix = self.httpd.prefix.strip('/') + '/'
3677 else:
3682 else:
3678 prefix = ''
3683 prefix = ''
3679
3684
3680 port = ':%d' % self.httpd.port
3685 port = ':%d' % self.httpd.port
3681 if port == ':80':
3686 if port == ':80':
3682 port = ''
3687 port = ''
3683
3688
3684 bindaddr = self.httpd.addr
3689 bindaddr = self.httpd.addr
3685 if bindaddr == '0.0.0.0':
3690 if bindaddr == '0.0.0.0':
3686 bindaddr = '*'
3691 bindaddr = '*'
3687 elif ':' in bindaddr: # IPv6
3692 elif ':' in bindaddr: # IPv6
3688 bindaddr = '[%s]' % bindaddr
3693 bindaddr = '[%s]' % bindaddr
3689
3694
3690 fqaddr = self.httpd.fqaddr
3695 fqaddr = self.httpd.fqaddr
3691 if ':' in fqaddr:
3696 if ':' in fqaddr:
3692 fqaddr = '[%s]' % fqaddr
3697 fqaddr = '[%s]' % fqaddr
3693 if opts['port']:
3698 if opts['port']:
3694 write = ui.status
3699 write = ui.status
3695 else:
3700 else:
3696 write = ui.write
3701 write = ui.write
3697 write(_('listening at http://%s%s/%s (bound to %s:%d)\n') %
3702 write(_('listening at http://%s%s/%s (bound to %s:%d)\n') %
3698 (fqaddr, port, prefix, bindaddr, self.httpd.port))
3703 (fqaddr, port, prefix, bindaddr, self.httpd.port))
3699
3704
3700 def run(self):
3705 def run(self):
3701 self.httpd.serve_forever()
3706 self.httpd.serve_forever()
3702
3707
3703 service = service()
3708 service = service()
3704
3709
3705 cmdutil.service(opts, initfn=service.init, runfn=service.run)
3710 cmdutil.service(opts, initfn=service.init, runfn=service.run)
3706
3711
3707 def status(ui, repo, *pats, **opts):
3712 def status(ui, repo, *pats, **opts):
3708 """show changed files in the working directory
3713 """show changed files in the working directory
3709
3714
3710 Show status of files in the repository. If names are given, only
3715 Show status of files in the repository. If names are given, only
3711 files that match are shown. Files that are clean or ignored or
3716 files that match are shown. Files that are clean or ignored or
3712 the source of a copy/move operation, are not listed unless
3717 the source of a copy/move operation, are not listed unless
3713 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
3718 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
3714 Unless options described with "show only ..." are given, the
3719 Unless options described with "show only ..." are given, the
3715 options -mardu are used.
3720 options -mardu are used.
3716
3721
3717 Option -q/--quiet hides untracked (unknown and ignored) files
3722 Option -q/--quiet hides untracked (unknown and ignored) files
3718 unless explicitly requested with -u/--unknown or -i/--ignored.
3723 unless explicitly requested with -u/--unknown or -i/--ignored.
3719
3724
3720 .. note::
3725 .. note::
3721 status may appear to disagree with diff if permissions have
3726 status may appear to disagree with diff if permissions have
3722 changed or a merge has occurred. The standard diff format does
3727 changed or a merge has occurred. The standard diff format does
3723 not report permission changes and diff only reports changes
3728 not report permission changes and diff only reports changes
3724 relative to one merge parent.
3729 relative to one merge parent.
3725
3730
3726 If one revision is given, it is used as the base revision.
3731 If one revision is given, it is used as the base revision.
3727 If two revisions are given, the differences between them are
3732 If two revisions are given, the differences between them are
3728 shown. The --change option can also be used as a shortcut to list
3733 shown. The --change option can also be used as a shortcut to list
3729 the changed files of a revision from its first parent.
3734 the changed files of a revision from its first parent.
3730
3735
3731 The codes used to show the status of files are::
3736 The codes used to show the status of files are::
3732
3737
3733 M = modified
3738 M = modified
3734 A = added
3739 A = added
3735 R = removed
3740 R = removed
3736 C = clean
3741 C = clean
3737 ! = missing (deleted by non-hg command, but still tracked)
3742 ! = missing (deleted by non-hg command, but still tracked)
3738 ? = not tracked
3743 ? = not tracked
3739 I = ignored
3744 I = ignored
3740 = origin of the previous file listed as A (added)
3745 = origin of the previous file listed as A (added)
3741
3746
3742 Returns 0 on success.
3747 Returns 0 on success.
3743 """
3748 """
3744
3749
3745 revs = opts.get('rev')
3750 revs = opts.get('rev')
3746 change = opts.get('change')
3751 change = opts.get('change')
3747
3752
3748 if revs and change:
3753 if revs and change:
3749 msg = _('cannot specify --rev and --change at the same time')
3754 msg = _('cannot specify --rev and --change at the same time')
3750 raise util.Abort(msg)
3755 raise util.Abort(msg)
3751 elif change:
3756 elif change:
3752 node2 = repo.lookup(change)
3757 node2 = repo.lookup(change)
3753 node1 = repo[node2].p1().node()
3758 node1 = repo[node2].p1().node()
3754 else:
3759 else:
3755 node1, node2 = cmdutil.revpair(repo, revs)
3760 node1, node2 = cmdutil.revpair(repo, revs)
3756
3761
3757 cwd = (pats and repo.getcwd()) or ''
3762 cwd = (pats and repo.getcwd()) or ''
3758 end = opts.get('print0') and '\0' or '\n'
3763 end = opts.get('print0') and '\0' or '\n'
3759 copy = {}
3764 copy = {}
3760 states = 'modified added removed deleted unknown ignored clean'.split()
3765 states = 'modified added removed deleted unknown ignored clean'.split()
3761 show = [k for k in states if opts.get(k)]
3766 show = [k for k in states if opts.get(k)]
3762 if opts.get('all'):
3767 if opts.get('all'):
3763 show += ui.quiet and (states[:4] + ['clean']) or states
3768 show += ui.quiet and (states[:4] + ['clean']) or states
3764 if not show:
3769 if not show:
3765 show = ui.quiet and states[:4] or states[:5]
3770 show = ui.quiet and states[:4] or states[:5]
3766
3771
3767 stat = repo.status(node1, node2, cmdutil.match(repo, pats, opts),
3772 stat = repo.status(node1, node2, cmdutil.match(repo, pats, opts),
3768 'ignored' in show, 'clean' in show, 'unknown' in show,
3773 'ignored' in show, 'clean' in show, 'unknown' in show,
3769 opts.get('subrepos'))
3774 opts.get('subrepos'))
3770 changestates = zip(states, 'MAR!?IC', stat)
3775 changestates = zip(states, 'MAR!?IC', stat)
3771
3776
3772 if (opts.get('all') or opts.get('copies')) and not opts.get('no_status'):
3777 if (opts.get('all') or opts.get('copies')) and not opts.get('no_status'):
3773 ctxn = repo[nullid]
3778 ctxn = repo[nullid]
3774 ctx1 = repo[node1]
3779 ctx1 = repo[node1]
3775 ctx2 = repo[node2]
3780 ctx2 = repo[node2]
3776 added = stat[1]
3781 added = stat[1]
3777 if node2 is None:
3782 if node2 is None:
3778 added = stat[0] + stat[1] # merged?
3783 added = stat[0] + stat[1] # merged?
3779
3784
3780 for k, v in copies.copies(repo, ctx1, ctx2, ctxn)[0].iteritems():
3785 for k, v in copies.copies(repo, ctx1, ctx2, ctxn)[0].iteritems():
3781 if k in added:
3786 if k in added:
3782 copy[k] = v
3787 copy[k] = v
3783 elif v in added:
3788 elif v in added:
3784 copy[v] = k
3789 copy[v] = k
3785
3790
3786 for state, char, files in changestates:
3791 for state, char, files in changestates:
3787 if state in show:
3792 if state in show:
3788 format = "%s %%s%s" % (char, end)
3793 format = "%s %%s%s" % (char, end)
3789 if opts.get('no_status'):
3794 if opts.get('no_status'):
3790 format = "%%s%s" % end
3795 format = "%%s%s" % end
3791
3796
3792 for f in files:
3797 for f in files:
3793 ui.write(format % repo.pathto(f, cwd),
3798 ui.write(format % repo.pathto(f, cwd),
3794 label='status.' + state)
3799 label='status.' + state)
3795 if f in copy:
3800 if f in copy:
3796 ui.write(' %s%s' % (repo.pathto(copy[f], cwd), end),
3801 ui.write(' %s%s' % (repo.pathto(copy[f], cwd), end),
3797 label='status.copied')
3802 label='status.copied')
3798
3803
3799 def summary(ui, repo, **opts):
3804 def summary(ui, repo, **opts):
3800 """summarize working directory state
3805 """summarize working directory state
3801
3806
3802 This generates a brief summary of the working directory state,
3807 This generates a brief summary of the working directory state,
3803 including parents, branch, commit status, and available updates.
3808 including parents, branch, commit status, and available updates.
3804
3809
3805 With the --remote option, this will check the default paths for
3810 With the --remote option, this will check the default paths for
3806 incoming and outgoing changes. This can be time-consuming.
3811 incoming and outgoing changes. This can be time-consuming.
3807
3812
3808 Returns 0 on success.
3813 Returns 0 on success.
3809 """
3814 """
3810
3815
3811 ctx = repo[None]
3816 ctx = repo[None]
3812 parents = ctx.parents()
3817 parents = ctx.parents()
3813 pnode = parents[0].node()
3818 pnode = parents[0].node()
3814
3819
3815 for p in parents:
3820 for p in parents:
3816 # label with log.changeset (instead of log.parent) since this
3821 # label with log.changeset (instead of log.parent) since this
3817 # shows a working directory parent *changeset*:
3822 # shows a working directory parent *changeset*:
3818 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
3823 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
3819 label='log.changeset')
3824 label='log.changeset')
3820 ui.write(' '.join(p.tags()), label='log.tag')
3825 ui.write(' '.join(p.tags()), label='log.tag')
3821 if p.bookmarks():
3826 if p.bookmarks():
3822 ui.write(' ' + ' '.join(p.bookmarks()), label='log.bookmark')
3827 ui.write(' ' + ' '.join(p.bookmarks()), label='log.bookmark')
3823 if p.rev() == -1:
3828 if p.rev() == -1:
3824 if not len(repo):
3829 if not len(repo):
3825 ui.write(_(' (empty repository)'))
3830 ui.write(_(' (empty repository)'))
3826 else:
3831 else:
3827 ui.write(_(' (no revision checked out)'))
3832 ui.write(_(' (no revision checked out)'))
3828 ui.write('\n')
3833 ui.write('\n')
3829 if p.description():
3834 if p.description():
3830 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
3835 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
3831 label='log.summary')
3836 label='log.summary')
3832
3837
3833 branch = ctx.branch()
3838 branch = ctx.branch()
3834 bheads = repo.branchheads(branch)
3839 bheads = repo.branchheads(branch)
3835 m = _('branch: %s\n') % branch
3840 m = _('branch: %s\n') % branch
3836 if branch != 'default':
3841 if branch != 'default':
3837 ui.write(m, label='log.branch')
3842 ui.write(m, label='log.branch')
3838 else:
3843 else:
3839 ui.status(m, label='log.branch')
3844 ui.status(m, label='log.branch')
3840
3845
3841 st = list(repo.status(unknown=True))[:6]
3846 st = list(repo.status(unknown=True))[:6]
3842
3847
3843 c = repo.dirstate.copies()
3848 c = repo.dirstate.copies()
3844 copied, renamed = [], []
3849 copied, renamed = [], []
3845 for d, s in c.iteritems():
3850 for d, s in c.iteritems():
3846 if s in st[2]:
3851 if s in st[2]:
3847 st[2].remove(s)
3852 st[2].remove(s)
3848 renamed.append(d)
3853 renamed.append(d)
3849 else:
3854 else:
3850 copied.append(d)
3855 copied.append(d)
3851 if d in st[1]:
3856 if d in st[1]:
3852 st[1].remove(d)
3857 st[1].remove(d)
3853 st.insert(3, renamed)
3858 st.insert(3, renamed)
3854 st.insert(4, copied)
3859 st.insert(4, copied)
3855
3860
3856 ms = mergemod.mergestate(repo)
3861 ms = mergemod.mergestate(repo)
3857 st.append([f for f in ms if ms[f] == 'u'])
3862 st.append([f for f in ms if ms[f] == 'u'])
3858
3863
3859 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
3864 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
3860 st.append(subs)
3865 st.append(subs)
3861
3866
3862 labels = [ui.label(_('%d modified'), 'status.modified'),
3867 labels = [ui.label(_('%d modified'), 'status.modified'),
3863 ui.label(_('%d added'), 'status.added'),
3868 ui.label(_('%d added'), 'status.added'),
3864 ui.label(_('%d removed'), 'status.removed'),
3869 ui.label(_('%d removed'), 'status.removed'),
3865 ui.label(_('%d renamed'), 'status.copied'),
3870 ui.label(_('%d renamed'), 'status.copied'),
3866 ui.label(_('%d copied'), 'status.copied'),
3871 ui.label(_('%d copied'), 'status.copied'),
3867 ui.label(_('%d deleted'), 'status.deleted'),
3872 ui.label(_('%d deleted'), 'status.deleted'),
3868 ui.label(_('%d unknown'), 'status.unknown'),
3873 ui.label(_('%d unknown'), 'status.unknown'),
3869 ui.label(_('%d ignored'), 'status.ignored'),
3874 ui.label(_('%d ignored'), 'status.ignored'),
3870 ui.label(_('%d unresolved'), 'resolve.unresolved'),
3875 ui.label(_('%d unresolved'), 'resolve.unresolved'),
3871 ui.label(_('%d subrepos'), 'status.modified')]
3876 ui.label(_('%d subrepos'), 'status.modified')]
3872 t = []
3877 t = []
3873 for s, l in zip(st, labels):
3878 for s, l in zip(st, labels):
3874 if s:
3879 if s:
3875 t.append(l % len(s))
3880 t.append(l % len(s))
3876
3881
3877 t = ', '.join(t)
3882 t = ', '.join(t)
3878 cleanworkdir = False
3883 cleanworkdir = False
3879
3884
3880 if len(parents) > 1:
3885 if len(parents) > 1:
3881 t += _(' (merge)')
3886 t += _(' (merge)')
3882 elif branch != parents[0].branch():
3887 elif branch != parents[0].branch():
3883 t += _(' (new branch)')
3888 t += _(' (new branch)')
3884 elif (parents[0].extra().get('close') and
3889 elif (parents[0].extra().get('close') and
3885 pnode in repo.branchheads(branch, closed=True)):
3890 pnode in repo.branchheads(branch, closed=True)):
3886 t += _(' (head closed)')
3891 t += _(' (head closed)')
3887 elif not (st[0] or st[1] or st[2] or st[3] or st[4] or st[9]):
3892 elif not (st[0] or st[1] or st[2] or st[3] or st[4] or st[9]):
3888 t += _(' (clean)')
3893 t += _(' (clean)')
3889 cleanworkdir = True
3894 cleanworkdir = True
3890 elif pnode not in bheads:
3895 elif pnode not in bheads:
3891 t += _(' (new branch head)')
3896 t += _(' (new branch head)')
3892
3897
3893 if cleanworkdir:
3898 if cleanworkdir:
3894 ui.status(_('commit: %s\n') % t.strip())
3899 ui.status(_('commit: %s\n') % t.strip())
3895 else:
3900 else:
3896 ui.write(_('commit: %s\n') % t.strip())
3901 ui.write(_('commit: %s\n') % t.strip())
3897
3902
3898 # all ancestors of branch heads - all ancestors of parent = new csets
3903 # all ancestors of branch heads - all ancestors of parent = new csets
3899 new = [0] * len(repo)
3904 new = [0] * len(repo)
3900 cl = repo.changelog
3905 cl = repo.changelog
3901 for a in [cl.rev(n) for n in bheads]:
3906 for a in [cl.rev(n) for n in bheads]:
3902 new[a] = 1
3907 new[a] = 1
3903 for a in cl.ancestors(*[cl.rev(n) for n in bheads]):
3908 for a in cl.ancestors(*[cl.rev(n) for n in bheads]):
3904 new[a] = 1
3909 new[a] = 1
3905 for a in [p.rev() for p in parents]:
3910 for a in [p.rev() for p in parents]:
3906 if a >= 0:
3911 if a >= 0:
3907 new[a] = 0
3912 new[a] = 0
3908 for a in cl.ancestors(*[p.rev() for p in parents]):
3913 for a in cl.ancestors(*[p.rev() for p in parents]):
3909 new[a] = 0
3914 new[a] = 0
3910 new = sum(new)
3915 new = sum(new)
3911
3916
3912 if new == 0:
3917 if new == 0:
3913 ui.status(_('update: (current)\n'))
3918 ui.status(_('update: (current)\n'))
3914 elif pnode not in bheads:
3919 elif pnode not in bheads:
3915 ui.write(_('update: %d new changesets (update)\n') % new)
3920 ui.write(_('update: %d new changesets (update)\n') % new)
3916 else:
3921 else:
3917 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
3922 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
3918 (new, len(bheads)))
3923 (new, len(bheads)))
3919
3924
3920 if opts.get('remote'):
3925 if opts.get('remote'):
3921 t = []
3926 t = []
3922 source, branches = hg.parseurl(ui.expandpath('default'))
3927 source, branches = hg.parseurl(ui.expandpath('default'))
3923 other = hg.repository(hg.remoteui(repo, {}), source)
3928 other = hg.repository(hg.remoteui(repo, {}), source)
3924 revs, checkout = hg.addbranchrevs(repo, other, branches, opts.get('rev'))
3929 revs, checkout = hg.addbranchrevs(repo, other, branches, opts.get('rev'))
3925 ui.debug('comparing with %s\n' % util.hidepassword(source))
3930 ui.debug('comparing with %s\n' % util.hidepassword(source))
3926 repo.ui.pushbuffer()
3931 repo.ui.pushbuffer()
3927 common, incoming, rheads = discovery.findcommonincoming(repo, other)
3932 common, incoming, rheads = discovery.findcommonincoming(repo, other)
3928 repo.ui.popbuffer()
3933 repo.ui.popbuffer()
3929 if incoming:
3934 if incoming:
3930 t.append(_('1 or more incoming'))
3935 t.append(_('1 or more incoming'))
3931
3936
3932 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
3937 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
3933 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
3938 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
3934 other = hg.repository(hg.remoteui(repo, {}), dest)
3939 other = hg.repository(hg.remoteui(repo, {}), dest)
3935 ui.debug('comparing with %s\n' % util.hidepassword(dest))
3940 ui.debug('comparing with %s\n' % util.hidepassword(dest))
3936 repo.ui.pushbuffer()
3941 repo.ui.pushbuffer()
3937 common, _anyinc, _heads = discovery.findcommonincoming(repo, other)
3942 common, _anyinc, _heads = discovery.findcommonincoming(repo, other)
3938 repo.ui.popbuffer()
3943 repo.ui.popbuffer()
3939 o = repo.changelog.findmissing(common=common)
3944 o = repo.changelog.findmissing(common=common)
3940 if o:
3945 if o:
3941 t.append(_('%d outgoing') % len(o))
3946 t.append(_('%d outgoing') % len(o))
3942 if 'bookmarks' in other.listkeys('namespaces'):
3947 if 'bookmarks' in other.listkeys('namespaces'):
3943 lmarks = repo.listkeys('bookmarks')
3948 lmarks = repo.listkeys('bookmarks')
3944 rmarks = other.listkeys('bookmarks')
3949 rmarks = other.listkeys('bookmarks')
3945 diff = set(rmarks) - set(lmarks)
3950 diff = set(rmarks) - set(lmarks)
3946 if len(diff) > 0:
3951 if len(diff) > 0:
3947 t.append(_('%d incoming bookmarks') % len(diff))
3952 t.append(_('%d incoming bookmarks') % len(diff))
3948 diff = set(lmarks) - set(rmarks)
3953 diff = set(lmarks) - set(rmarks)
3949 if len(diff) > 0:
3954 if len(diff) > 0:
3950 t.append(_('%d outgoing bookmarks') % len(diff))
3955 t.append(_('%d outgoing bookmarks') % len(diff))
3951
3956
3952 if t:
3957 if t:
3953 ui.write(_('remote: %s\n') % (', '.join(t)))
3958 ui.write(_('remote: %s\n') % (', '.join(t)))
3954 else:
3959 else:
3955 ui.status(_('remote: (synced)\n'))
3960 ui.status(_('remote: (synced)\n'))
3956
3961
3957 def tag(ui, repo, name1, *names, **opts):
3962 def tag(ui, repo, name1, *names, **opts):
3958 """add one or more tags for the current or given revision
3963 """add one or more tags for the current or given revision
3959
3964
3960 Name a particular revision using <name>.
3965 Name a particular revision using <name>.
3961
3966
3962 Tags are used to name particular revisions of the repository and are
3967 Tags are used to name particular revisions of the repository and are
3963 very useful to compare different revisions, to go back to significant
3968 very useful to compare different revisions, to go back to significant
3964 earlier versions or to mark branch points as releases, etc. Changing
3969 earlier versions or to mark branch points as releases, etc. Changing
3965 an existing tag is normally disallowed; use -f/--force to override.
3970 an existing tag is normally disallowed; use -f/--force to override.
3966
3971
3967 If no revision is given, the parent of the working directory is
3972 If no revision is given, the parent of the working directory is
3968 used, or tip if no revision is checked out.
3973 used, or tip if no revision is checked out.
3969
3974
3970 To facilitate version control, distribution, and merging of tags,
3975 To facilitate version control, distribution, and merging of tags,
3971 they are stored as a file named ".hgtags" which is managed similarly
3976 they are stored as a file named ".hgtags" which is managed similarly
3972 to other project files and can be hand-edited if necessary. This
3977 to other project files and can be hand-edited if necessary. This
3973 also means that tagging creates a new commit. The file
3978 also means that tagging creates a new commit. The file
3974 ".hg/localtags" is used for local tags (not shared among
3979 ".hg/localtags" is used for local tags (not shared among
3975 repositories).
3980 repositories).
3976
3981
3977 Tag commits are usually made at the head of a branch. If the parent
3982 Tag commits are usually made at the head of a branch. If the parent
3978 of the working directory is not a branch head, :hg:`tag` aborts; use
3983 of the working directory is not a branch head, :hg:`tag` aborts; use
3979 -f/--force to force the tag commit to be based on a non-head
3984 -f/--force to force the tag commit to be based on a non-head
3980 changeset.
3985 changeset.
3981
3986
3982 See :hg:`help dates` for a list of formats valid for -d/--date.
3987 See :hg:`help dates` for a list of formats valid for -d/--date.
3983
3988
3984 Since tag names have priority over branch names during revision
3989 Since tag names have priority over branch names during revision
3985 lookup, using an existing branch name as a tag name is discouraged.
3990 lookup, using an existing branch name as a tag name is discouraged.
3986
3991
3987 Returns 0 on success.
3992 Returns 0 on success.
3988 """
3993 """
3989
3994
3990 rev_ = "."
3995 rev_ = "."
3991 names = [t.strip() for t in (name1,) + names]
3996 names = [t.strip() for t in (name1,) + names]
3992 if len(names) != len(set(names)):
3997 if len(names) != len(set(names)):
3993 raise util.Abort(_('tag names must be unique'))
3998 raise util.Abort(_('tag names must be unique'))
3994 for n in names:
3999 for n in names:
3995 if n in ['tip', '.', 'null']:
4000 if n in ['tip', '.', 'null']:
3996 raise util.Abort(_('the name \'%s\' is reserved') % n)
4001 raise util.Abort(_('the name \'%s\' is reserved') % n)
3997 if not n:
4002 if not n:
3998 raise util.Abort(_('tag names cannot consist entirely of whitespace'))
4003 raise util.Abort(_('tag names cannot consist entirely of whitespace'))
3999 if opts.get('rev') and opts.get('remove'):
4004 if opts.get('rev') and opts.get('remove'):
4000 raise util.Abort(_("--rev and --remove are incompatible"))
4005 raise util.Abort(_("--rev and --remove are incompatible"))
4001 if opts.get('rev'):
4006 if opts.get('rev'):
4002 rev_ = opts['rev']
4007 rev_ = opts['rev']
4003 message = opts.get('message')
4008 message = opts.get('message')
4004 if opts.get('remove'):
4009 if opts.get('remove'):
4005 expectedtype = opts.get('local') and 'local' or 'global'
4010 expectedtype = opts.get('local') and 'local' or 'global'
4006 for n in names:
4011 for n in names:
4007 if not repo.tagtype(n):
4012 if not repo.tagtype(n):
4008 raise util.Abort(_('tag \'%s\' does not exist') % n)
4013 raise util.Abort(_('tag \'%s\' does not exist') % n)
4009 if repo.tagtype(n) != expectedtype:
4014 if repo.tagtype(n) != expectedtype:
4010 if expectedtype == 'global':
4015 if expectedtype == 'global':
4011 raise util.Abort(_('tag \'%s\' is not a global tag') % n)
4016 raise util.Abort(_('tag \'%s\' is not a global tag') % n)
4012 else:
4017 else:
4013 raise util.Abort(_('tag \'%s\' is not a local tag') % n)
4018 raise util.Abort(_('tag \'%s\' is not a local tag') % n)
4014 rev_ = nullid
4019 rev_ = nullid
4015 if not message:
4020 if not message:
4016 # we don't translate commit messages
4021 # we don't translate commit messages
4017 message = 'Removed tag %s' % ', '.join(names)
4022 message = 'Removed tag %s' % ', '.join(names)
4018 elif not opts.get('force'):
4023 elif not opts.get('force'):
4019 for n in names:
4024 for n in names:
4020 if n in repo.tags():
4025 if n in repo.tags():
4021 raise util.Abort(_('tag \'%s\' already exists '
4026 raise util.Abort(_('tag \'%s\' already exists '
4022 '(use -f to force)') % n)
4027 '(use -f to force)') % n)
4023 if not opts.get('local'):
4028 if not opts.get('local'):
4024 p1, p2 = repo.dirstate.parents()
4029 p1, p2 = repo.dirstate.parents()
4025 if p2 != nullid:
4030 if p2 != nullid:
4026 raise util.Abort(_('uncommitted merge'))
4031 raise util.Abort(_('uncommitted merge'))
4027 bheads = repo.branchheads()
4032 bheads = repo.branchheads()
4028 if not opts.get('force') and bheads and p1 not in bheads:
4033 if not opts.get('force') and bheads and p1 not in bheads:
4029 raise util.Abort(_('not at a branch head (use -f to force)'))
4034 raise util.Abort(_('not at a branch head (use -f to force)'))
4030 r = cmdutil.revsingle(repo, rev_).node()
4035 r = cmdutil.revsingle(repo, rev_).node()
4031
4036
4032 if not message:
4037 if not message:
4033 # we don't translate commit messages
4038 # we don't translate commit messages
4034 message = ('Added tag %s for changeset %s' %
4039 message = ('Added tag %s for changeset %s' %
4035 (', '.join(names), short(r)))
4040 (', '.join(names), short(r)))
4036
4041
4037 date = opts.get('date')
4042 date = opts.get('date')
4038 if date:
4043 if date:
4039 date = util.parsedate(date)
4044 date = util.parsedate(date)
4040
4045
4041 if opts.get('edit'):
4046 if opts.get('edit'):
4042 message = ui.edit(message, ui.username())
4047 message = ui.edit(message, ui.username())
4043
4048
4044 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date)
4049 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date)
4045
4050
4046 def tags(ui, repo):
4051 def tags(ui, repo):
4047 """list repository tags
4052 """list repository tags
4048
4053
4049 This lists both regular and local tags. When the -v/--verbose
4054 This lists both regular and local tags. When the -v/--verbose
4050 switch is used, a third column "local" is printed for local tags.
4055 switch is used, a third column "local" is printed for local tags.
4051
4056
4052 Returns 0 on success.
4057 Returns 0 on success.
4053 """
4058 """
4054
4059
4055 hexfunc = ui.debugflag and hex or short
4060 hexfunc = ui.debugflag and hex or short
4056 tagtype = ""
4061 tagtype = ""
4057
4062
4058 for t, n in reversed(repo.tagslist()):
4063 for t, n in reversed(repo.tagslist()):
4059 if ui.quiet:
4064 if ui.quiet:
4060 ui.write("%s\n" % t)
4065 ui.write("%s\n" % t)
4061 continue
4066 continue
4062
4067
4063 hn = hexfunc(n)
4068 hn = hexfunc(n)
4064 r = "%5d:%s" % (repo.changelog.rev(n), hn)
4069 r = "%5d:%s" % (repo.changelog.rev(n), hn)
4065 spaces = " " * (30 - encoding.colwidth(t))
4070 spaces = " " * (30 - encoding.colwidth(t))
4066
4071
4067 if ui.verbose:
4072 if ui.verbose:
4068 if repo.tagtype(t) == 'local':
4073 if repo.tagtype(t) == 'local':
4069 tagtype = " local"
4074 tagtype = " local"
4070 else:
4075 else:
4071 tagtype = ""
4076 tagtype = ""
4072 ui.write("%s%s %s%s\n" % (t, spaces, r, tagtype))
4077 ui.write("%s%s %s%s\n" % (t, spaces, r, tagtype))
4073
4078
4074 def tip(ui, repo, **opts):
4079 def tip(ui, repo, **opts):
4075 """show the tip revision
4080 """show the tip revision
4076
4081
4077 The tip revision (usually just called the tip) is the changeset
4082 The tip revision (usually just called the tip) is the changeset
4078 most recently added to the repository (and therefore the most
4083 most recently added to the repository (and therefore the most
4079 recently changed head).
4084 recently changed head).
4080
4085
4081 If you have just made a commit, that commit will be the tip. If
4086 If you have just made a commit, that commit will be the tip. If
4082 you have just pulled changes from another repository, the tip of
4087 you have just pulled changes from another repository, the tip of
4083 that repository becomes the current tip. The "tip" tag is special
4088 that repository becomes the current tip. The "tip" tag is special
4084 and cannot be renamed or assigned to a different changeset.
4089 and cannot be renamed or assigned to a different changeset.
4085
4090
4086 Returns 0 on success.
4091 Returns 0 on success.
4087 """
4092 """
4088 displayer = cmdutil.show_changeset(ui, repo, opts)
4093 displayer = cmdutil.show_changeset(ui, repo, opts)
4089 displayer.show(repo[len(repo) - 1])
4094 displayer.show(repo[len(repo) - 1])
4090 displayer.close()
4095 displayer.close()
4091
4096
4092 def unbundle(ui, repo, fname1, *fnames, **opts):
4097 def unbundle(ui, repo, fname1, *fnames, **opts):
4093 """apply one or more changegroup files
4098 """apply one or more changegroup files
4094
4099
4095 Apply one or more compressed changegroup files generated by the
4100 Apply one or more compressed changegroup files generated by the
4096 bundle command.
4101 bundle command.
4097
4102
4098 Returns 0 on success, 1 if an update has unresolved files.
4103 Returns 0 on success, 1 if an update has unresolved files.
4099 """
4104 """
4100 fnames = (fname1,) + fnames
4105 fnames = (fname1,) + fnames
4101
4106
4102 lock = repo.lock()
4107 lock = repo.lock()
4103 wc = repo['.']
4108 wc = repo['.']
4104 try:
4109 try:
4105 for fname in fnames:
4110 for fname in fnames:
4106 f = url.open(ui, fname)
4111 f = url.open(ui, fname)
4107 gen = changegroup.readbundle(f, fname)
4112 gen = changegroup.readbundle(f, fname)
4108 modheads = repo.addchangegroup(gen, 'unbundle', 'bundle:' + fname,
4113 modheads = repo.addchangegroup(gen, 'unbundle', 'bundle:' + fname,
4109 lock=lock)
4114 lock=lock)
4110 bookmarks.updatecurrentbookmark(repo, wc.node(), wc.branch())
4115 bookmarks.updatecurrentbookmark(repo, wc.node(), wc.branch())
4111 finally:
4116 finally:
4112 lock.release()
4117 lock.release()
4113 return postincoming(ui, repo, modheads, opts.get('update'), None)
4118 return postincoming(ui, repo, modheads, opts.get('update'), None)
4114
4119
4115 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False):
4120 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False):
4116 """update working directory (or switch revisions)
4121 """update working directory (or switch revisions)
4117
4122
4118 Update the repository's working directory to the specified
4123 Update the repository's working directory to the specified
4119 changeset. If no changeset is specified, update to the tip of the
4124 changeset. If no changeset is specified, update to the tip of the
4120 current named branch.
4125 current named branch.
4121
4126
4122 If the changeset is not a descendant of the working directory's
4127 If the changeset is not a descendant of the working directory's
4123 parent, the update is aborted. With the -c/--check option, the
4128 parent, the update is aborted. With the -c/--check option, the
4124 working directory is checked for uncommitted changes; if none are
4129 working directory is checked for uncommitted changes; if none are
4125 found, the working directory is updated to the specified
4130 found, the working directory is updated to the specified
4126 changeset.
4131 changeset.
4127
4132
4128 The following rules apply when the working directory contains
4133 The following rules apply when the working directory contains
4129 uncommitted changes:
4134 uncommitted changes:
4130
4135
4131 1. If neither -c/--check nor -C/--clean is specified, and if
4136 1. If neither -c/--check nor -C/--clean is specified, and if
4132 the requested changeset is an ancestor or descendant of
4137 the requested changeset is an ancestor or descendant of
4133 the working directory's parent, the uncommitted changes
4138 the working directory's parent, the uncommitted changes
4134 are merged into the requested changeset and the merged
4139 are merged into the requested changeset and the merged
4135 result is left uncommitted. If the requested changeset is
4140 result is left uncommitted. If the requested changeset is
4136 not an ancestor or descendant (that is, it is on another
4141 not an ancestor or descendant (that is, it is on another
4137 branch), the update is aborted and the uncommitted changes
4142 branch), the update is aborted and the uncommitted changes
4138 are preserved.
4143 are preserved.
4139
4144
4140 2. With the -c/--check option, the update is aborted and the
4145 2. With the -c/--check option, the update is aborted and the
4141 uncommitted changes are preserved.
4146 uncommitted changes are preserved.
4142
4147
4143 3. With the -C/--clean option, uncommitted changes are discarded and
4148 3. With the -C/--clean option, uncommitted changes are discarded and
4144 the working directory is updated to the requested changeset.
4149 the working directory is updated to the requested changeset.
4145
4150
4146 Use null as the changeset to remove the working directory (like
4151 Use null as the changeset to remove the working directory (like
4147 :hg:`clone -U`).
4152 :hg:`clone -U`).
4148
4153
4149 If you want to update just one file to an older changeset, use
4154 If you want to update just one file to an older changeset, use
4150 :hg:`revert`.
4155 :hg:`revert`.
4151
4156
4152 See :hg:`help dates` for a list of formats valid for -d/--date.
4157 See :hg:`help dates` for a list of formats valid for -d/--date.
4153
4158
4154 Returns 0 on success, 1 if there are unresolved files.
4159 Returns 0 on success, 1 if there are unresolved files.
4155 """
4160 """
4156 if rev and node:
4161 if rev and node:
4157 raise util.Abort(_("please specify just one revision"))
4162 raise util.Abort(_("please specify just one revision"))
4158
4163
4159 if rev is None or rev == '':
4164 if rev is None or rev == '':
4160 rev = node
4165 rev = node
4161
4166
4162 # if we defined a bookmark, we have to remember the original bookmark name
4167 # if we defined a bookmark, we have to remember the original bookmark name
4163 brev = rev
4168 brev = rev
4164 rev = cmdutil.revsingle(repo, rev, rev).rev()
4169 rev = cmdutil.revsingle(repo, rev, rev).rev()
4165
4170
4166 if check and clean:
4171 if check and clean:
4167 raise util.Abort(_("cannot specify both -c/--check and -C/--clean"))
4172 raise util.Abort(_("cannot specify both -c/--check and -C/--clean"))
4168
4173
4169 if check:
4174 if check:
4170 # we could use dirty() but we can ignore merge and branch trivia
4175 # we could use dirty() but we can ignore merge and branch trivia
4171 c = repo[None]
4176 c = repo[None]
4172 if c.modified() or c.added() or c.removed():
4177 if c.modified() or c.added() or c.removed():
4173 raise util.Abort(_("uncommitted local changes"))
4178 raise util.Abort(_("uncommitted local changes"))
4174
4179
4175 if date:
4180 if date:
4176 if rev is not None:
4181 if rev is not None:
4177 raise util.Abort(_("you can't specify a revision and a date"))
4182 raise util.Abort(_("you can't specify a revision and a date"))
4178 rev = cmdutil.finddate(ui, repo, date)
4183 rev = cmdutil.finddate(ui, repo, date)
4179
4184
4180 if clean or check:
4185 if clean or check:
4181 ret = hg.clean(repo, rev)
4186 ret = hg.clean(repo, rev)
4182 else:
4187 else:
4183 ret = hg.update(repo, rev)
4188 ret = hg.update(repo, rev)
4184
4189
4185 if brev in repo._bookmarks:
4190 if brev in repo._bookmarks:
4186 bookmarks.setcurrent(repo, brev)
4191 bookmarks.setcurrent(repo, brev)
4187
4192
4188 return ret
4193 return ret
4189
4194
4190 def verify(ui, repo):
4195 def verify(ui, repo):
4191 """verify the integrity of the repository
4196 """verify the integrity of the repository
4192
4197
4193 Verify the integrity of the current repository.
4198 Verify the integrity of the current repository.
4194
4199
4195 This will perform an extensive check of the repository's
4200 This will perform an extensive check of the repository's
4196 integrity, validating the hashes and checksums of each entry in
4201 integrity, validating the hashes and checksums of each entry in
4197 the changelog, manifest, and tracked files, as well as the
4202 the changelog, manifest, and tracked files, as well as the
4198 integrity of their crosslinks and indices.
4203 integrity of their crosslinks and indices.
4199
4204
4200 Returns 0 on success, 1 if errors are encountered.
4205 Returns 0 on success, 1 if errors are encountered.
4201 """
4206 """
4202 return hg.verify(repo)
4207 return hg.verify(repo)
4203
4208
4204 def version_(ui):
4209 def version_(ui):
4205 """output version and copyright information"""
4210 """output version and copyright information"""
4206 ui.write(_("Mercurial Distributed SCM (version %s)\n")
4211 ui.write(_("Mercurial Distributed SCM (version %s)\n")
4207 % util.version())
4212 % util.version())
4208 ui.status(_(
4213 ui.status(_(
4209 "(see http://mercurial.selenic.com for more information)\n"
4214 "(see http://mercurial.selenic.com for more information)\n"
4210 "\nCopyright (C) 2005-2011 Matt Mackall and others\n"
4215 "\nCopyright (C) 2005-2011 Matt Mackall and others\n"
4211 "This is free software; see the source for copying conditions. "
4216 "This is free software; see the source for copying conditions. "
4212 "There is NO\nwarranty; "
4217 "There is NO\nwarranty; "
4213 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
4218 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
4214 ))
4219 ))
4215
4220
4216 # Command options and aliases are listed here, alphabetically
4221 # Command options and aliases are listed here, alphabetically
4217
4222
4218 globalopts = [
4223 globalopts = [
4219 ('R', 'repository', '',
4224 ('R', 'repository', '',
4220 _('repository root directory or name of overlay bundle file'),
4225 _('repository root directory or name of overlay bundle file'),
4221 _('REPO')),
4226 _('REPO')),
4222 ('', 'cwd', '',
4227 ('', 'cwd', '',
4223 _('change working directory'), _('DIR')),
4228 _('change working directory'), _('DIR')),
4224 ('y', 'noninteractive', None,
4229 ('y', 'noninteractive', None,
4225 _('do not prompt, assume \'yes\' for any required answers')),
4230 _('do not prompt, assume \'yes\' for any required answers')),
4226 ('q', 'quiet', None, _('suppress output')),
4231 ('q', 'quiet', None, _('suppress output')),
4227 ('v', 'verbose', None, _('enable additional output')),
4232 ('v', 'verbose', None, _('enable additional output')),
4228 ('', 'config', [],
4233 ('', 'config', [],
4229 _('set/override config option (use \'section.name=value\')'),
4234 _('set/override config option (use \'section.name=value\')'),
4230 _('CONFIG')),
4235 _('CONFIG')),
4231 ('', 'debug', None, _('enable debugging output')),
4236 ('', 'debug', None, _('enable debugging output')),
4232 ('', 'debugger', None, _('start debugger')),
4237 ('', 'debugger', None, _('start debugger')),
4233 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
4238 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
4234 _('ENCODE')),
4239 _('ENCODE')),
4235 ('', 'encodingmode', encoding.encodingmode,
4240 ('', 'encodingmode', encoding.encodingmode,
4236 _('set the charset encoding mode'), _('MODE')),
4241 _('set the charset encoding mode'), _('MODE')),
4237 ('', 'traceback', None, _('always print a traceback on exception')),
4242 ('', 'traceback', None, _('always print a traceback on exception')),
4238 ('', 'time', None, _('time how long the command takes')),
4243 ('', 'time', None, _('time how long the command takes')),
4239 ('', 'profile', None, _('print command execution profile')),
4244 ('', 'profile', None, _('print command execution profile')),
4240 ('', 'version', None, _('output version information and exit')),
4245 ('', 'version', None, _('output version information and exit')),
4241 ('h', 'help', None, _('display help and exit')),
4246 ('h', 'help', None, _('display help and exit')),
4242 ]
4247 ]
4243
4248
4244 dryrunopts = [('n', 'dry-run', None,
4249 dryrunopts = [('n', 'dry-run', None,
4245 _('do not perform actions, just print output'))]
4250 _('do not perform actions, just print output'))]
4246
4251
4247 remoteopts = [
4252 remoteopts = [
4248 ('e', 'ssh', '',
4253 ('e', 'ssh', '',
4249 _('specify ssh command to use'), _('CMD')),
4254 _('specify ssh command to use'), _('CMD')),
4250 ('', 'remotecmd', '',
4255 ('', 'remotecmd', '',
4251 _('specify hg command to run on the remote side'), _('CMD')),
4256 _('specify hg command to run on the remote side'), _('CMD')),
4252 ('', 'insecure', None,
4257 ('', 'insecure', None,
4253 _('do not verify server certificate (ignoring web.cacerts config)')),
4258 _('do not verify server certificate (ignoring web.cacerts config)')),
4254 ]
4259 ]
4255
4260
4256 walkopts = [
4261 walkopts = [
4257 ('I', 'include', [],
4262 ('I', 'include', [],
4258 _('include names matching the given patterns'), _('PATTERN')),
4263 _('include names matching the given patterns'), _('PATTERN')),
4259 ('X', 'exclude', [],
4264 ('X', 'exclude', [],
4260 _('exclude names matching the given patterns'), _('PATTERN')),
4265 _('exclude names matching the given patterns'), _('PATTERN')),
4261 ]
4266 ]
4262
4267
4263 commitopts = [
4268 commitopts = [
4264 ('m', 'message', '',
4269 ('m', 'message', '',
4265 _('use text as commit message'), _('TEXT')),
4270 _('use text as commit message'), _('TEXT')),
4266 ('l', 'logfile', '',
4271 ('l', 'logfile', '',
4267 _('read commit message from file'), _('FILE')),
4272 _('read commit message from file'), _('FILE')),
4268 ]
4273 ]
4269
4274
4270 commitopts2 = [
4275 commitopts2 = [
4271 ('d', 'date', '',
4276 ('d', 'date', '',
4272 _('record the specified date as commit date'), _('DATE')),
4277 _('record the specified date as commit date'), _('DATE')),
4273 ('u', 'user', '',
4278 ('u', 'user', '',
4274 _('record the specified user as committer'), _('USER')),
4279 _('record the specified user as committer'), _('USER')),
4275 ]
4280 ]
4276
4281
4277 templateopts = [
4282 templateopts = [
4278 ('', 'style', '',
4283 ('', 'style', '',
4279 _('display using template map file'), _('STYLE')),
4284 _('display using template map file'), _('STYLE')),
4280 ('', 'template', '',
4285 ('', 'template', '',
4281 _('display with template'), _('TEMPLATE')),
4286 _('display with template'), _('TEMPLATE')),
4282 ]
4287 ]
4283
4288
4284 logopts = [
4289 logopts = [
4285 ('p', 'patch', None, _('show patch')),
4290 ('p', 'patch', None, _('show patch')),
4286 ('g', 'git', None, _('use git extended diff format')),
4291 ('g', 'git', None, _('use git extended diff format')),
4287 ('l', 'limit', '',
4292 ('l', 'limit', '',
4288 _('limit number of changes displayed'), _('NUM')),
4293 _('limit number of changes displayed'), _('NUM')),
4289 ('M', 'no-merges', None, _('do not show merges')),
4294 ('M', 'no-merges', None, _('do not show merges')),
4290 ('', 'stat', None, _('output diffstat-style summary of changes')),
4295 ('', 'stat', None, _('output diffstat-style summary of changes')),
4291 ] + templateopts
4296 ] + templateopts
4292
4297
4293 diffopts = [
4298 diffopts = [
4294 ('a', 'text', None, _('treat all files as text')),
4299 ('a', 'text', None, _('treat all files as text')),
4295 ('g', 'git', None, _('use git extended diff format')),
4300 ('g', 'git', None, _('use git extended diff format')),
4296 ('', 'nodates', None, _('omit dates from diff headers'))
4301 ('', 'nodates', None, _('omit dates from diff headers'))
4297 ]
4302 ]
4298
4303
4299 diffopts2 = [
4304 diffopts2 = [
4300 ('p', 'show-function', None, _('show which function each change is in')),
4305 ('p', 'show-function', None, _('show which function each change is in')),
4301 ('', 'reverse', None, _('produce a diff that undoes the changes')),
4306 ('', 'reverse', None, _('produce a diff that undoes the changes')),
4302 ('w', 'ignore-all-space', None,
4307 ('w', 'ignore-all-space', None,
4303 _('ignore white space when comparing lines')),
4308 _('ignore white space when comparing lines')),
4304 ('b', 'ignore-space-change', None,
4309 ('b', 'ignore-space-change', None,
4305 _('ignore changes in the amount of white space')),
4310 _('ignore changes in the amount of white space')),
4306 ('B', 'ignore-blank-lines', None,
4311 ('B', 'ignore-blank-lines', None,
4307 _('ignore changes whose lines are all blank')),
4312 _('ignore changes whose lines are all blank')),
4308 ('U', 'unified', '',
4313 ('U', 'unified', '',
4309 _('number of lines of context to show'), _('NUM')),
4314 _('number of lines of context to show'), _('NUM')),
4310 ('', 'stat', None, _('output diffstat-style summary of changes')),
4315 ('', 'stat', None, _('output diffstat-style summary of changes')),
4311 ]
4316 ]
4312
4317
4313 similarityopts = [
4318 similarityopts = [
4314 ('s', 'similarity', '',
4319 ('s', 'similarity', '',
4315 _('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
4320 _('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
4316 ]
4321 ]
4317
4322
4318 subrepoopts = [
4323 subrepoopts = [
4319 ('S', 'subrepos', None,
4324 ('S', 'subrepos', None,
4320 _('recurse into subrepositories'))
4325 _('recurse into subrepositories'))
4321 ]
4326 ]
4322
4327
4323 table = {
4328 table = {
4324 "^add": (add, walkopts + subrepoopts + dryrunopts,
4329 "^add": (add, walkopts + subrepoopts + dryrunopts,
4325 _('[OPTION]... [FILE]...')),
4330 _('[OPTION]... [FILE]...')),
4326 "addremove":
4331 "addremove":
4327 (addremove, similarityopts + walkopts + dryrunopts,
4332 (addremove, similarityopts + walkopts + dryrunopts,
4328 _('[OPTION]... [FILE]...')),
4333 _('[OPTION]... [FILE]...')),
4329 "^annotate|blame":
4334 "^annotate|blame":
4330 (annotate,
4335 (annotate,
4331 [('r', 'rev', '',
4336 [('r', 'rev', '',
4332 _('annotate the specified revision'), _('REV')),
4337 _('annotate the specified revision'), _('REV')),
4333 ('', 'follow', None,
4338 ('', 'follow', None,
4334 _('follow copies/renames and list the filename (DEPRECATED)')),
4339 _('follow copies/renames and list the filename (DEPRECATED)')),
4335 ('', 'no-follow', None, _("don't follow copies and renames")),
4340 ('', 'no-follow', None, _("don't follow copies and renames")),
4336 ('a', 'text', None, _('treat all files as text')),
4341 ('a', 'text', None, _('treat all files as text')),
4337 ('u', 'user', None, _('list the author (long with -v)')),
4342 ('u', 'user', None, _('list the author (long with -v)')),
4338 ('f', 'file', None, _('list the filename')),
4343 ('f', 'file', None, _('list the filename')),
4339 ('d', 'date', None, _('list the date (short with -q)')),
4344 ('d', 'date', None, _('list the date (short with -q)')),
4340 ('n', 'number', None, _('list the revision number (default)')),
4345 ('n', 'number', None, _('list the revision number (default)')),
4341 ('c', 'changeset', None, _('list the changeset')),
4346 ('c', 'changeset', None, _('list the changeset')),
4342 ('l', 'line-number', None,
4347 ('l', 'line-number', None,
4343 _('show line number at the first appearance'))
4348 _('show line number at the first appearance'))
4344 ] + walkopts,
4349 ] + walkopts,
4345 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...')),
4350 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...')),
4346 "archive":
4351 "archive":
4347 (archive,
4352 (archive,
4348 [('', 'no-decode', None, _('do not pass files through decoders')),
4353 [('', 'no-decode', None, _('do not pass files through decoders')),
4349 ('p', 'prefix', '',
4354 ('p', 'prefix', '',
4350 _('directory prefix for files in archive'), _('PREFIX')),
4355 _('directory prefix for files in archive'), _('PREFIX')),
4351 ('r', 'rev', '',
4356 ('r', 'rev', '',
4352 _('revision to distribute'), _('REV')),
4357 _('revision to distribute'), _('REV')),
4353 ('t', 'type', '',
4358 ('t', 'type', '',
4354 _('type of distribution to create'), _('TYPE')),
4359 _('type of distribution to create'), _('TYPE')),
4355 ] + subrepoopts + walkopts,
4360 ] + subrepoopts + walkopts,
4356 _('[OPTION]... DEST')),
4361 _('[OPTION]... DEST')),
4357 "backout":
4362 "backout":
4358 (backout,
4363 (backout,
4359 [('', 'merge', None,
4364 [('', 'merge', None,
4360 _('merge with old dirstate parent after backout')),
4365 _('merge with old dirstate parent after backout')),
4361 ('', 'parent', '',
4366 ('', 'parent', '',
4362 _('parent to choose when backing out merge'), _('REV')),
4367 _('parent to choose when backing out merge'), _('REV')),
4363 ('t', 'tool', '',
4368 ('t', 'tool', '',
4364 _('specify merge tool')),
4369 _('specify merge tool')),
4365 ('r', 'rev', '',
4370 ('r', 'rev', '',
4366 _('revision to backout'), _('REV')),
4371 _('revision to backout'), _('REV')),
4367 ] + walkopts + commitopts + commitopts2,
4372 ] + walkopts + commitopts + commitopts2,
4368 _('[OPTION]... [-r] REV')),
4373 _('[OPTION]... [-r] REV')),
4369 "bisect":
4374 "bisect":
4370 (bisect,
4375 (bisect,
4371 [('r', 'reset', False, _('reset bisect state')),
4376 [('r', 'reset', False, _('reset bisect state')),
4372 ('g', 'good', False, _('mark changeset good')),
4377 ('g', 'good', False, _('mark changeset good')),
4373 ('b', 'bad', False, _('mark changeset bad')),
4378 ('b', 'bad', False, _('mark changeset bad')),
4374 ('s', 'skip', False, _('skip testing changeset')),
4379 ('s', 'skip', False, _('skip testing changeset')),
4375 ('e', 'extend', False, _('extend the bisect range')),
4380 ('e', 'extend', False, _('extend the bisect range')),
4376 ('c', 'command', '',
4381 ('c', 'command', '',
4377 _('use command to check changeset state'), _('CMD')),
4382 _('use command to check changeset state'), _('CMD')),
4378 ('U', 'noupdate', False, _('do not update to target'))],
4383 ('U', 'noupdate', False, _('do not update to target'))],
4379 _("[-gbsr] [-U] [-c CMD] [REV]")),
4384 _("[-gbsr] [-U] [-c CMD] [REV]")),
4380 "bookmarks":
4385 "bookmarks":
4381 (bookmark,
4386 (bookmark,
4382 [('f', 'force', False, _('force')),
4387 [('f', 'force', False, _('force')),
4383 ('r', 'rev', '', _('revision'), _('REV')),
4388 ('r', 'rev', '', _('revision'), _('REV')),
4384 ('d', 'delete', False, _('delete a given bookmark')),
4389 ('d', 'delete', False, _('delete a given bookmark')),
4385 ('m', 'rename', '', _('rename a given bookmark'), _('NAME'))],
4390 ('m', 'rename', '', _('rename a given bookmark'), _('NAME'))],
4386 _('hg bookmarks [-f] [-d] [-m NAME] [-r REV] [NAME]')),
4391 _('hg bookmarks [-f] [-d] [-m NAME] [-r REV] [NAME]')),
4387 "branch":
4392 "branch":
4388 (branch,
4393 (branch,
4389 [('f', 'force', None,
4394 [('f', 'force', None,
4390 _('set branch name even if it shadows an existing branch')),
4395 _('set branch name even if it shadows an existing branch')),
4391 ('C', 'clean', None, _('reset branch name to parent branch name'))],
4396 ('C', 'clean', None, _('reset branch name to parent branch name'))],
4392 _('[-fC] [NAME]')),
4397 _('[-fC] [NAME]')),
4393 "branches":
4398 "branches":
4394 (branches,
4399 (branches,
4395 [('a', 'active', False,
4400 [('a', 'active', False,
4396 _('show only branches that have unmerged heads')),
4401 _('show only branches that have unmerged heads')),
4397 ('c', 'closed', False,
4402 ('c', 'closed', False,
4398 _('show normal and closed branches'))],
4403 _('show normal and closed branches'))],
4399 _('[-ac]')),
4404 _('[-ac]')),
4400 "bundle":
4405 "bundle":
4401 (bundle,
4406 (bundle,
4402 [('f', 'force', None,
4407 [('f', 'force', None,
4403 _('run even when the destination is unrelated')),
4408 _('run even when the destination is unrelated')),
4404 ('r', 'rev', [],
4409 ('r', 'rev', [],
4405 _('a changeset intended to be added to the destination'),
4410 _('a changeset intended to be added to the destination'),
4406 _('REV')),
4411 _('REV')),
4407 ('b', 'branch', [],
4412 ('b', 'branch', [],
4408 _('a specific branch you would like to bundle'),
4413 _('a specific branch you would like to bundle'),
4409 _('BRANCH')),
4414 _('BRANCH')),
4410 ('', 'base', [],
4415 ('', 'base', [],
4411 _('a base changeset assumed to be available at the destination'),
4416 _('a base changeset assumed to be available at the destination'),
4412 _('REV')),
4417 _('REV')),
4413 ('a', 'all', None, _('bundle all changesets in the repository')),
4418 ('a', 'all', None, _('bundle all changesets in the repository')),
4414 ('t', 'type', 'bzip2',
4419 ('t', 'type', 'bzip2',
4415 _('bundle compression type to use'), _('TYPE')),
4420 _('bundle compression type to use'), _('TYPE')),
4416 ] + remoteopts,
4421 ] + remoteopts,
4417 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]')),
4422 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]')),
4418 "cat":
4423 "cat":
4419 (cat,
4424 (cat,
4420 [('o', 'output', '',
4425 [('o', 'output', '',
4421 _('print output to file with formatted name'), _('FORMAT')),
4426 _('print output to file with formatted name'), _('FORMAT')),
4422 ('r', 'rev', '',
4427 ('r', 'rev', '',
4423 _('print the given revision'), _('REV')),
4428 _('print the given revision'), _('REV')),
4424 ('', 'decode', None, _('apply any matching decode filter')),
4429 ('', 'decode', None, _('apply any matching decode filter')),
4425 ] + walkopts,
4430 ] + walkopts,
4426 _('[OPTION]... FILE...')),
4431 _('[OPTION]... FILE...')),
4427 "^clone":
4432 "^clone":
4428 (clone,
4433 (clone,
4429 [('U', 'noupdate', None,
4434 [('U', 'noupdate', None,
4430 _('the clone will include an empty working copy (only a repository)')),
4435 _('the clone will include an empty working copy (only a repository)')),
4431 ('u', 'updaterev', '',
4436 ('u', 'updaterev', '',
4432 _('revision, tag or branch to check out'), _('REV')),
4437 _('revision, tag or branch to check out'), _('REV')),
4433 ('r', 'rev', [],
4438 ('r', 'rev', [],
4434 _('include the specified changeset'), _('REV')),
4439 _('include the specified changeset'), _('REV')),
4435 ('b', 'branch', [],
4440 ('b', 'branch', [],
4436 _('clone only the specified branch'), _('BRANCH')),
4441 _('clone only the specified branch'), _('BRANCH')),
4437 ('', 'pull', None, _('use pull protocol to copy metadata')),
4442 ('', 'pull', None, _('use pull protocol to copy metadata')),
4438 ('', 'uncompressed', None,
4443 ('', 'uncompressed', None,
4439 _('use uncompressed transfer (fast over LAN)')),
4444 _('use uncompressed transfer (fast over LAN)')),
4440 ] + remoteopts,
4445 ] + remoteopts,
4441 _('[OPTION]... SOURCE [DEST]')),
4446 _('[OPTION]... SOURCE [DEST]')),
4442 "^commit|ci":
4447 "^commit|ci":
4443 (commit,
4448 (commit,
4444 [('A', 'addremove', None,
4449 [('A', 'addremove', None,
4445 _('mark new/missing files as added/removed before committing')),
4450 _('mark new/missing files as added/removed before committing')),
4446 ('', 'close-branch', None,
4451 ('', 'close-branch', None,
4447 _('mark a branch as closed, hiding it from the branch list')),
4452 _('mark a branch as closed, hiding it from the branch list')),
4448 ] + walkopts + commitopts + commitopts2,
4453 ] + walkopts + commitopts + commitopts2,
4449 _('[OPTION]... [FILE]...')),
4454 _('[OPTION]... [FILE]...')),
4450 "copy|cp":
4455 "copy|cp":
4451 (copy,
4456 (copy,
4452 [('A', 'after', None, _('record a copy that has already occurred')),
4457 [('A', 'after', None, _('record a copy that has already occurred')),
4453 ('f', 'force', None,
4458 ('f', 'force', None,
4454 _('forcibly copy over an existing managed file')),
4459 _('forcibly copy over an existing managed file')),
4455 ] + walkopts + dryrunopts,
4460 ] + walkopts + dryrunopts,
4456 _('[OPTION]... [SOURCE]... DEST')),
4461 _('[OPTION]... [SOURCE]... DEST')),
4457 "debugancestor": (debugancestor, [], _('[INDEX] REV1 REV2')),
4462 "debugancestor": (debugancestor, [], _('[INDEX] REV1 REV2')),
4458 "debugbuilddag":
4463 "debugbuilddag":
4459 (debugbuilddag,
4464 (debugbuilddag,
4460 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
4465 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
4461 ('a', 'appended-file', None, _('add single file all revs append to')),
4466 ('a', 'appended-file', None, _('add single file all revs append to')),
4462 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
4467 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
4463 ('n', 'new-file', None, _('add new file at each rev')),
4468 ('n', 'new-file', None, _('add new file at each rev')),
4464 ],
4469 ],
4465 _('[OPTION]... TEXT')),
4470 _('[OPTION]... TEXT')),
4466 "debugbundle":
4471 "debugbundle":
4467 (debugbundle,
4472 (debugbundle,
4468 [('a', 'all', None, _('show all details')),
4473 [('a', 'all', None, _('show all details')),
4469 ],
4474 ],
4470 _('FILE')),
4475 _('FILE')),
4471 "debugcheckstate": (debugcheckstate, [], ''),
4476 "debugcheckstate": (debugcheckstate, [], ''),
4472 "debugcommands": (debugcommands, [], _('[COMMAND]')),
4477 "debugcommands": (debugcommands, [], _('[COMMAND]')),
4473 "debugcomplete":
4478 "debugcomplete":
4474 (debugcomplete,
4479 (debugcomplete,
4475 [('o', 'options', None, _('show the command options'))],
4480 [('o', 'options', None, _('show the command options'))],
4476 _('[-o] CMD')),
4481 _('[-o] CMD')),
4477 "debugdag":
4482 "debugdag":
4478 (debugdag,
4483 (debugdag,
4479 [('t', 'tags', None, _('use tags as labels')),
4484 [('t', 'tags', None, _('use tags as labels')),
4480 ('b', 'branches', None, _('annotate with branch names')),
4485 ('b', 'branches', None, _('annotate with branch names')),
4481 ('', 'dots', None, _('use dots for runs')),
4486 ('', 'dots', None, _('use dots for runs')),
4482 ('s', 'spaces', None, _('separate elements by spaces')),
4487 ('s', 'spaces', None, _('separate elements by spaces')),
4483 ],
4488 ],
4484 _('[OPTION]... [FILE [REV]...]')),
4489 _('[OPTION]... [FILE [REV]...]')),
4485 "debugdate":
4490 "debugdate":
4486 (debugdate,
4491 (debugdate,
4487 [('e', 'extended', None, _('try extended date formats'))],
4492 [('e', 'extended', None, _('try extended date formats'))],
4488 _('[-e] DATE [RANGE]')),
4493 _('[-e] DATE [RANGE]')),
4489 "debugdata": (debugdata, [], _('FILE REV')),
4494 "debugdata": (debugdata, [], _('FILE REV')),
4490 "debugfsinfo": (debugfsinfo, [], _('[PATH]')),
4495 "debugfsinfo": (debugfsinfo, [], _('[PATH]')),
4491 "debuggetbundle":
4496 "debuggetbundle":
4492 (debuggetbundle,
4497 (debuggetbundle,
4493 [('H', 'head', [], _('id of head node'), _('ID')),
4498 [('H', 'head', [], _('id of head node'), _('ID')),
4494 ('C', 'common', [], _('id of common node'), _('ID')),
4499 ('C', 'common', [], _('id of common node'), _('ID')),
4495 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
4500 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
4496 ],
4501 ],
4497 _('REPO FILE [-H|-C ID]...')),
4502 _('REPO FILE [-H|-C ID]...')),
4498 "debugignore": (debugignore, [], ''),
4503 "debugignore": (debugignore, [], ''),
4499 "debugindex": (debugindex,
4504 "debugindex": (debugindex,
4500 [('f', 'format', 0, _('revlog format'), _('FORMAT'))],
4505 [('f', 'format', 0, _('revlog format'), _('FORMAT'))],
4501 _('FILE')),
4506 _('FILE')),
4502 "debugindexdot": (debugindexdot, [], _('FILE')),
4507 "debugindexdot": (debugindexdot, [], _('FILE')),
4503 "debuginstall": (debuginstall, [], ''),
4508 "debuginstall": (debuginstall, [], ''),
4504 "debugknown": (debugknown, [], _('REPO ID...')),
4509 "debugknown": (debugknown, [], _('REPO ID...')),
4505 "debugpushkey": (debugpushkey, [], _('REPO NAMESPACE [KEY OLD NEW]')),
4510 "debugpushkey": (debugpushkey, [], _('REPO NAMESPACE [KEY OLD NEW]')),
4506 "debugrebuildstate":
4511 "debugrebuildstate":
4507 (debugrebuildstate,
4512 (debugrebuildstate,
4508 [('r', 'rev', '',
4513 [('r', 'rev', '',
4509 _('revision to rebuild to'), _('REV'))],
4514 _('revision to rebuild to'), _('REV'))],
4510 _('[-r REV] [REV]')),
4515 _('[-r REV] [REV]')),
4511 "debugrename":
4516 "debugrename":
4512 (debugrename,
4517 (debugrename,
4513 [('r', 'rev', '',
4518 [('r', 'rev', '',
4514 _('revision to debug'), _('REV'))],
4519 _('revision to debug'), _('REV'))],
4515 _('[-r REV] FILE')),
4520 _('[-r REV] FILE')),
4516 "debugrevspec":
4521 "debugrevspec":
4517 (debugrevspec, [], ('REVSPEC')),
4522 (debugrevspec, [], ('REVSPEC')),
4518 "debugsetparents":
4523 "debugsetparents":
4519 (debugsetparents, [], _('REV1 [REV2]')),
4524 (debugsetparents, [], _('REV1 [REV2]')),
4520 "debugstate":
4525 "debugstate":
4521 (debugstate,
4526 (debugstate,
4522 [('', 'nodates', None, _('do not display the saved mtime')),
4527 [('', 'nodates', None, _('do not display the saved mtime')),
4523 ('', 'datesort', None, _('sort by saved mtime'))],
4528 ('', 'datesort', None, _('sort by saved mtime'))],
4524 _('[OPTION]...')),
4529 _('[OPTION]...')),
4525 "debugsub":
4530 "debugsub":
4526 (debugsub,
4531 (debugsub,
4527 [('r', 'rev', '',
4532 [('r', 'rev', '',
4528 _('revision to check'), _('REV'))],
4533 _('revision to check'), _('REV'))],
4529 _('[-r REV] [REV]')),
4534 _('[-r REV] [REV]')),
4530 "debugwalk": (debugwalk, walkopts, _('[OPTION]... [FILE]...')),
4535 "debugwalk": (debugwalk, walkopts, _('[OPTION]... [FILE]...')),
4531 "debugwireargs":
4536 "debugwireargs":
4532 (debugwireargs,
4537 (debugwireargs,
4533 [('', 'three', '', 'three'),
4538 [('', 'three', '', 'three'),
4534 ('', 'four', '', 'four'),
4539 ('', 'four', '', 'four'),
4535 ('', 'five', '', 'five'),
4540 ('', 'five', '', 'five'),
4536 ] + remoteopts,
4541 ] + remoteopts,
4537 _('REPO [OPTIONS]... [ONE [TWO]]')),
4542 _('REPO [OPTIONS]... [ONE [TWO]]')),
4538 "^diff":
4543 "^diff":
4539 (diff,
4544 (diff,
4540 [('r', 'rev', [],
4545 [('r', 'rev', [],
4541 _('revision'), _('REV')),
4546 _('revision'), _('REV')),
4542 ('c', 'change', '',
4547 ('c', 'change', '',
4543 _('change made by revision'), _('REV'))
4548 _('change made by revision'), _('REV'))
4544 ] + diffopts + diffopts2 + walkopts + subrepoopts,
4549 ] + diffopts + diffopts2 + walkopts + subrepoopts,
4545 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...')),
4550 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...')),
4546 "^export":
4551 "^export":
4547 (export,
4552 (export,
4548 [('o', 'output', '',
4553 [('o', 'output', '',
4549 _('print output to file with formatted name'), _('FORMAT')),
4554 _('print output to file with formatted name'), _('FORMAT')),
4550 ('', 'switch-parent', None, _('diff against the second parent')),
4555 ('', 'switch-parent', None, _('diff against the second parent')),
4551 ('r', 'rev', [],
4556 ('r', 'rev', [],
4552 _('revisions to export'), _('REV')),
4557 _('revisions to export'), _('REV')),
4553 ] + diffopts,
4558 ] + diffopts,
4554 _('[OPTION]... [-o OUTFILESPEC] REV...')),
4559 _('[OPTION]... [-o OUTFILESPEC] REV...')),
4555 "^forget":
4560 "^forget":
4556 (forget,
4561 (forget,
4557 [] + walkopts,
4562 [] + walkopts,
4558 _('[OPTION]... FILE...')),
4563 _('[OPTION]... FILE...')),
4559 "grep":
4564 "grep":
4560 (grep,
4565 (grep,
4561 [('0', 'print0', None, _('end fields with NUL')),
4566 [('0', 'print0', None, _('end fields with NUL')),
4562 ('', 'all', None, _('print all revisions that match')),
4567 ('', 'all', None, _('print all revisions that match')),
4563 ('a', 'text', None, _('treat all files as text')),
4568 ('a', 'text', None, _('treat all files as text')),
4564 ('f', 'follow', None,
4569 ('f', 'follow', None,
4565 _('follow changeset history,'
4570 _('follow changeset history,'
4566 ' or file history across copies and renames')),
4571 ' or file history across copies and renames')),
4567 ('i', 'ignore-case', None, _('ignore case when matching')),
4572 ('i', 'ignore-case', None, _('ignore case when matching')),
4568 ('l', 'files-with-matches', None,
4573 ('l', 'files-with-matches', None,
4569 _('print only filenames and revisions that match')),
4574 _('print only filenames and revisions that match')),
4570 ('n', 'line-number', None, _('print matching line numbers')),
4575 ('n', 'line-number', None, _('print matching line numbers')),
4571 ('r', 'rev', [],
4576 ('r', 'rev', [],
4572 _('only search files changed within revision range'), _('REV')),
4577 _('only search files changed within revision range'), _('REV')),
4573 ('u', 'user', None, _('list the author (long with -v)')),
4578 ('u', 'user', None, _('list the author (long with -v)')),
4574 ('d', 'date', None, _('list the date (short with -q)')),
4579 ('d', 'date', None, _('list the date (short with -q)')),
4575 ] + walkopts,
4580 ] + walkopts,
4576 _('[OPTION]... PATTERN [FILE]...')),
4581 _('[OPTION]... PATTERN [FILE]...')),
4577 "heads":
4582 "heads":
4578 (heads,
4583 (heads,
4579 [('r', 'rev', '',
4584 [('r', 'rev', '',
4580 _('show only heads which are descendants of STARTREV'),
4585 _('show only heads which are descendants of STARTREV'),
4581 _('STARTREV')),
4586 _('STARTREV')),
4582 ('t', 'topo', False, _('show topological heads only')),
4587 ('t', 'topo', False, _('show topological heads only')),
4583 ('a', 'active', False,
4588 ('a', 'active', False,
4584 _('show active branchheads only (DEPRECATED)')),
4589 _('show active branchheads only (DEPRECATED)')),
4585 ('c', 'closed', False,
4590 ('c', 'closed', False,
4586 _('show normal and closed branch heads')),
4591 _('show normal and closed branch heads')),
4587 ] + templateopts,
4592 ] + templateopts,
4588 _('[-ac] [-r STARTREV] [REV]...')),
4593 _('[-ac] [-r STARTREV] [REV]...')),
4589 "help": (help_, [], _('[TOPIC]')),
4594 "help": (help_, [], _('[TOPIC]')),
4590 "identify|id":
4595 "identify|id":
4591 (identify,
4596 (identify,
4592 [('r', 'rev', '',
4597 [('r', 'rev', '',
4593 _('identify the specified revision'), _('REV')),
4598 _('identify the specified revision'), _('REV')),
4594 ('n', 'num', None, _('show local revision number')),
4599 ('n', 'num', None, _('show local revision number')),
4595 ('i', 'id', None, _('show global revision id')),
4600 ('i', 'id', None, _('show global revision id')),
4596 ('b', 'branch', None, _('show branch')),
4601 ('b', 'branch', None, _('show branch')),
4597 ('t', 'tags', None, _('show tags')),
4602 ('t', 'tags', None, _('show tags')),
4598 ('B', 'bookmarks', None, _('show bookmarks'))],
4603 ('B', 'bookmarks', None, _('show bookmarks'))],
4599 _('[-nibtB] [-r REV] [SOURCE]')),
4604 _('[-nibtB] [-r REV] [SOURCE]')),
4600 "import|patch":
4605 "import|patch":
4601 (import_,
4606 (import_,
4602 [('p', 'strip', 1,
4607 [('p', 'strip', 1,
4603 _('directory strip option for patch. This has the same '
4608 _('directory strip option for patch. This has the same '
4604 'meaning as the corresponding patch option'),
4609 'meaning as the corresponding patch option'),
4605 _('NUM')),
4610 _('NUM')),
4606 ('b', 'base', '',
4611 ('b', 'base', '',
4607 _('base path'), _('PATH')),
4612 _('base path'), _('PATH')),
4608 ('f', 'force', None,
4613 ('f', 'force', None,
4609 _('skip check for outstanding uncommitted changes')),
4614 _('skip check for outstanding uncommitted changes')),
4610 ('', 'no-commit', None,
4615 ('', 'no-commit', None,
4611 _("don't commit, just update the working directory")),
4616 _("don't commit, just update the working directory")),
4612 ('', 'exact', None,
4617 ('', 'exact', None,
4613 _('apply patch to the nodes from which it was generated')),
4618 _('apply patch to the nodes from which it was generated')),
4614 ('', 'import-branch', None,
4619 ('', 'import-branch', None,
4615 _('use any branch information in patch (implied by --exact)'))] +
4620 _('use any branch information in patch (implied by --exact)'))] +
4616 commitopts + commitopts2 + similarityopts,
4621 commitopts + commitopts2 + similarityopts,
4617 _('[OPTION]... PATCH...')),
4622 _('[OPTION]... PATCH...')),
4618 "incoming|in":
4623 "incoming|in":
4619 (incoming,
4624 (incoming,
4620 [('f', 'force', None,
4625 [('f', 'force', None,
4621 _('run even if remote repository is unrelated')),
4626 _('run even if remote repository is unrelated')),
4622 ('n', 'newest-first', None, _('show newest record first')),
4627 ('n', 'newest-first', None, _('show newest record first')),
4623 ('', 'bundle', '',
4628 ('', 'bundle', '',
4624 _('file to store the bundles into'), _('FILE')),
4629 _('file to store the bundles into'), _('FILE')),
4625 ('r', 'rev', [],
4630 ('r', 'rev', [],
4626 _('a remote changeset intended to be added'), _('REV')),
4631 _('a remote changeset intended to be added'), _('REV')),
4627 ('B', 'bookmarks', False, _("compare bookmarks")),
4632 ('B', 'bookmarks', False, _("compare bookmarks")),
4628 ('b', 'branch', [],
4633 ('b', 'branch', [],
4629 _('a specific branch you would like to pull'), _('BRANCH')),
4634 _('a specific branch you would like to pull'), _('BRANCH')),
4630 ] + logopts + remoteopts + subrepoopts,
4635 ] + logopts + remoteopts + subrepoopts,
4631 _('[-p] [-n] [-M] [-f] [-r REV]...'
4636 _('[-p] [-n] [-M] [-f] [-r REV]...'
4632 ' [--bundle FILENAME] [SOURCE]')),
4637 ' [--bundle FILENAME] [SOURCE]')),
4633 "^init":
4638 "^init":
4634 (init,
4639 (init,
4635 remoteopts,
4640 remoteopts,
4636 _('[-e CMD] [--remotecmd CMD] [DEST]')),
4641 _('[-e CMD] [--remotecmd CMD] [DEST]')),
4637 "locate":
4642 "locate":
4638 (locate,
4643 (locate,
4639 [('r', 'rev', '',
4644 [('r', 'rev', '',
4640 _('search the repository as it is in REV'), _('REV')),
4645 _('search the repository as it is in REV'), _('REV')),
4641 ('0', 'print0', None,
4646 ('0', 'print0', None,
4642 _('end filenames with NUL, for use with xargs')),
4647 _('end filenames with NUL, for use with xargs')),
4643 ('f', 'fullpath', None,
4648 ('f', 'fullpath', None,
4644 _('print complete paths from the filesystem root')),
4649 _('print complete paths from the filesystem root')),
4645 ] + walkopts,
4650 ] + walkopts,
4646 _('[OPTION]... [PATTERN]...')),
4651 _('[OPTION]... [PATTERN]...')),
4647 "^log|history":
4652 "^log|history":
4648 (log,
4653 (log,
4649 [('f', 'follow', None,
4654 [('f', 'follow', None,
4650 _('follow changeset history,'
4655 _('follow changeset history,'
4651 ' or file history across copies and renames')),
4656 ' or file history across copies and renames')),
4652 ('', 'follow-first', None,
4657 ('', 'follow-first', None,
4653 _('only follow the first parent of merge changesets')),
4658 _('only follow the first parent of merge changesets')),
4654 ('d', 'date', '',
4659 ('d', 'date', '',
4655 _('show revisions matching date spec'), _('DATE')),
4660 _('show revisions matching date spec'), _('DATE')),
4656 ('C', 'copies', None, _('show copied files')),
4661 ('C', 'copies', None, _('show copied files')),
4657 ('k', 'keyword', [],
4662 ('k', 'keyword', [],
4658 _('do case-insensitive search for a given text'), _('TEXT')),
4663 _('do case-insensitive search for a given text'), _('TEXT')),
4659 ('r', 'rev', [],
4664 ('r', 'rev', [],
4660 _('show the specified revision or range'), _('REV')),
4665 _('show the specified revision or range'), _('REV')),
4661 ('', 'removed', None, _('include revisions where files were removed')),
4666 ('', 'removed', None, _('include revisions where files were removed')),
4662 ('m', 'only-merges', None, _('show only merges')),
4667 ('m', 'only-merges', None, _('show only merges')),
4663 ('u', 'user', [],
4668 ('u', 'user', [],
4664 _('revisions committed by user'), _('USER')),
4669 _('revisions committed by user'), _('USER')),
4665 ('', 'only-branch', [],
4670 ('', 'only-branch', [],
4666 _('show only changesets within the given named branch (DEPRECATED)'),
4671 _('show only changesets within the given named branch (DEPRECATED)'),
4667 _('BRANCH')),
4672 _('BRANCH')),
4668 ('b', 'branch', [],
4673 ('b', 'branch', [],
4669 _('show changesets within the given named branch'), _('BRANCH')),
4674 _('show changesets within the given named branch'), _('BRANCH')),
4670 ('P', 'prune', [],
4675 ('P', 'prune', [],
4671 _('do not display revision or any of its ancestors'), _('REV')),
4676 _('do not display revision or any of its ancestors'), _('REV')),
4672 ] + logopts + walkopts,
4677 ] + logopts + walkopts,
4673 _('[OPTION]... [FILE]')),
4678 _('[OPTION]... [FILE]')),
4674 "manifest":
4679 "manifest":
4675 (manifest,
4680 (manifest,
4676 [('r', 'rev', '',
4681 [('r', 'rev', '',
4677 _('revision to display'), _('REV'))],
4682 _('revision to display'), _('REV'))],
4678 _('[-r REV]')),
4683 _('[-r REV]')),
4679 "^merge":
4684 "^merge":
4680 (merge,
4685 (merge,
4681 [('f', 'force', None, _('force a merge with outstanding changes')),
4686 [('f', 'force', None, _('force a merge with outstanding changes')),
4682 ('t', 'tool', '', _('specify merge tool')),
4687 ('t', 'tool', '', _('specify merge tool')),
4683 ('r', 'rev', '',
4688 ('r', 'rev', '',
4684 _('revision to merge'), _('REV')),
4689 _('revision to merge'), _('REV')),
4685 ('P', 'preview', None,
4690 ('P', 'preview', None,
4686 _('review revisions to merge (no merge is performed)'))],
4691 _('review revisions to merge (no merge is performed)'))],
4687 _('[-P] [-f] [[-r] REV]')),
4692 _('[-P] [-f] [[-r] REV]')),
4688 "outgoing|out":
4693 "outgoing|out":
4689 (outgoing,
4694 (outgoing,
4690 [('f', 'force', None,
4695 [('f', 'force', None,
4691 _('run even when the destination is unrelated')),
4696 _('run even when the destination is unrelated')),
4692 ('r', 'rev', [],
4697 ('r', 'rev', [],
4693 _('a changeset intended to be included in the destination'),
4698 _('a changeset intended to be included in the destination'),
4694 _('REV')),
4699 _('REV')),
4695 ('n', 'newest-first', None, _('show newest record first')),
4700 ('n', 'newest-first', None, _('show newest record first')),
4696 ('B', 'bookmarks', False, _("compare bookmarks")),
4701 ('B', 'bookmarks', False, _("compare bookmarks")),
4697 ('b', 'branch', [],
4702 ('b', 'branch', [],
4698 _('a specific branch you would like to push'), _('BRANCH')),
4703 _('a specific branch you would like to push'), _('BRANCH')),
4699 ] + logopts + remoteopts + subrepoopts,
4704 ] + logopts + remoteopts + subrepoopts,
4700 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]')),
4705 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]')),
4701 "parents":
4706 "parents":
4702 (parents,
4707 (parents,
4703 [('r', 'rev', '',
4708 [('r', 'rev', '',
4704 _('show parents of the specified revision'), _('REV')),
4709 _('show parents of the specified revision'), _('REV')),
4705 ] + templateopts,
4710 ] + templateopts,
4706 _('[-r REV] [FILE]')),
4711 _('[-r REV] [FILE]')),
4707 "paths": (paths, [], _('[NAME]')),
4712 "paths": (paths, [], _('[NAME]')),
4708 "^pull":
4713 "^pull":
4709 (pull,
4714 (pull,
4710 [('u', 'update', None,
4715 [('u', 'update', None,
4711 _('update to new branch head if changesets were pulled')),
4716 _('update to new branch head if changesets were pulled')),
4712 ('f', 'force', None,
4717 ('f', 'force', None,
4713 _('run even when remote repository is unrelated')),
4718 _('run even when remote repository is unrelated')),
4714 ('r', 'rev', [],
4719 ('r', 'rev', [],
4715 _('a remote changeset intended to be added'), _('REV')),
4720 _('a remote changeset intended to be added'), _('REV')),
4716 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
4721 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
4717 ('b', 'branch', [],
4722 ('b', 'branch', [],
4718 _('a specific branch you would like to pull'), _('BRANCH')),
4723 _('a specific branch you would like to pull'), _('BRANCH')),
4719 ] + remoteopts,
4724 ] + remoteopts,
4720 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]')),
4725 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]')),
4721 "^push":
4726 "^push":
4722 (push,
4727 (push,
4723 [('f', 'force', None, _('force push')),
4728 [('f', 'force', None, _('force push')),
4724 ('r', 'rev', [],
4729 ('r', 'rev', [],
4725 _('a changeset intended to be included in the destination'),
4730 _('a changeset intended to be included in the destination'),
4726 _('REV')),
4731 _('REV')),
4727 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
4732 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
4728 ('b', 'branch', [],
4733 ('b', 'branch', [],
4729 _('a specific branch you would like to push'), _('BRANCH')),
4734 _('a specific branch you would like to push'), _('BRANCH')),
4730 ('', 'new-branch', False, _('allow pushing a new branch')),
4735 ('', 'new-branch', False, _('allow pushing a new branch')),
4731 ] + remoteopts,
4736 ] + remoteopts,
4732 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]')),
4737 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]')),
4733 "recover": (recover, []),
4738 "recover": (recover, []),
4734 "^remove|rm":
4739 "^remove|rm":
4735 (remove,
4740 (remove,
4736 [('A', 'after', None, _('record delete for missing files')),
4741 [('A', 'after', None, _('record delete for missing files')),
4737 ('f', 'force', None,
4742 ('f', 'force', None,
4738 _('remove (and delete) file even if added or modified')),
4743 _('remove (and delete) file even if added or modified')),
4739 ] + walkopts,
4744 ] + walkopts,
4740 _('[OPTION]... FILE...')),
4745 _('[OPTION]... FILE...')),
4741 "rename|move|mv":
4746 "rename|move|mv":
4742 (rename,
4747 (rename,
4743 [('A', 'after', None, _('record a rename that has already occurred')),
4748 [('A', 'after', None, _('record a rename that has already occurred')),
4744 ('f', 'force', None,
4749 ('f', 'force', None,
4745 _('forcibly copy over an existing managed file')),
4750 _('forcibly copy over an existing managed file')),
4746 ] + walkopts + dryrunopts,
4751 ] + walkopts + dryrunopts,
4747 _('[OPTION]... SOURCE... DEST')),
4752 _('[OPTION]... SOURCE... DEST')),
4748 "resolve":
4753 "resolve":
4749 (resolve,
4754 (resolve,
4750 [('a', 'all', None, _('select all unresolved files')),
4755 [('a', 'all', None, _('select all unresolved files')),
4751 ('l', 'list', None, _('list state of files needing merge')),
4756 ('l', 'list', None, _('list state of files needing merge')),
4752 ('m', 'mark', None, _('mark files as resolved')),
4757 ('m', 'mark', None, _('mark files as resolved')),
4753 ('u', 'unmark', None, _('mark files as unresolved')),
4758 ('u', 'unmark', None, _('mark files as unresolved')),
4754 ('t', 'tool', '', _('specify merge tool')),
4759 ('t', 'tool', '', _('specify merge tool')),
4755 ('n', 'no-status', None, _('hide status prefix'))]
4760 ('n', 'no-status', None, _('hide status prefix'))]
4756 + walkopts,
4761 + walkopts,
4757 _('[OPTION]... [FILE]...')),
4762 _('[OPTION]... [FILE]...')),
4758 "revert":
4763 "revert":
4759 (revert,
4764 (revert,
4760 [('a', 'all', None, _('revert all changes when no arguments given')),
4765 [('a', 'all', None, _('revert all changes when no arguments given')),
4761 ('d', 'date', '',
4766 ('d', 'date', '',
4762 _('tipmost revision matching date'), _('DATE')),
4767 _('tipmost revision matching date'), _('DATE')),
4763 ('r', 'rev', '',
4768 ('r', 'rev', '',
4764 _('revert to the specified revision'), _('REV')),
4769 _('revert to the specified revision'), _('REV')),
4765 ('', 'no-backup', None, _('do not save backup copies of files')),
4770 ('', 'no-backup', None, _('do not save backup copies of files')),
4766 ] + walkopts + dryrunopts,
4771 ] + walkopts + dryrunopts,
4767 _('[OPTION]... [-r REV] [NAME]...')),
4772 _('[OPTION]... [-r REV] [NAME]...')),
4768 "rollback": (rollback, dryrunopts),
4773 "rollback": (rollback, dryrunopts),
4769 "root": (root, []),
4774 "root": (root, []),
4770 "^serve":
4775 "^serve":
4771 (serve,
4776 (serve,
4772 [('A', 'accesslog', '',
4777 [('A', 'accesslog', '',
4773 _('name of access log file to write to'), _('FILE')),
4778 _('name of access log file to write to'), _('FILE')),
4774 ('d', 'daemon', None, _('run server in background')),
4779 ('d', 'daemon', None, _('run server in background')),
4775 ('', 'daemon-pipefds', '',
4780 ('', 'daemon-pipefds', '',
4776 _('used internally by daemon mode'), _('NUM')),
4781 _('used internally by daemon mode'), _('NUM')),
4777 ('E', 'errorlog', '',
4782 ('E', 'errorlog', '',
4778 _('name of error log file to write to'), _('FILE')),
4783 _('name of error log file to write to'), _('FILE')),
4779 # use string type, then we can check if something was passed
4784 # use string type, then we can check if something was passed
4780 ('p', 'port', '',
4785 ('p', 'port', '',
4781 _('port to listen on (default: 8000)'), _('PORT')),
4786 _('port to listen on (default: 8000)'), _('PORT')),
4782 ('a', 'address', '',
4787 ('a', 'address', '',
4783 _('address to listen on (default: all interfaces)'), _('ADDR')),
4788 _('address to listen on (default: all interfaces)'), _('ADDR')),
4784 ('', 'prefix', '',
4789 ('', 'prefix', '',
4785 _('prefix path to serve from (default: server root)'), _('PREFIX')),
4790 _('prefix path to serve from (default: server root)'), _('PREFIX')),
4786 ('n', 'name', '',
4791 ('n', 'name', '',
4787 _('name to show in web pages (default: working directory)'),
4792 _('name to show in web pages (default: working directory)'),
4788 _('NAME')),
4793 _('NAME')),
4789 ('', 'web-conf', '',
4794 ('', 'web-conf', '',
4790 _('name of the hgweb config file (see "hg help hgweb")'),
4795 _('name of the hgweb config file (see "hg help hgweb")'),
4791 _('FILE')),
4796 _('FILE')),
4792 ('', 'webdir-conf', '',
4797 ('', 'webdir-conf', '',
4793 _('name of the hgweb config file (DEPRECATED)'), _('FILE')),
4798 _('name of the hgweb config file (DEPRECATED)'), _('FILE')),
4794 ('', 'pid-file', '',
4799 ('', 'pid-file', '',
4795 _('name of file to write process ID to'), _('FILE')),
4800 _('name of file to write process ID to'), _('FILE')),
4796 ('', 'stdio', None, _('for remote clients')),
4801 ('', 'stdio', None, _('for remote clients')),
4797 ('t', 'templates', '',
4802 ('t', 'templates', '',
4798 _('web templates to use'), _('TEMPLATE')),
4803 _('web templates to use'), _('TEMPLATE')),
4799 ('', 'style', '',
4804 ('', 'style', '',
4800 _('template style to use'), _('STYLE')),
4805 _('template style to use'), _('STYLE')),
4801 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
4806 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
4802 ('', 'certificate', '',
4807 ('', 'certificate', '',
4803 _('SSL certificate file'), _('FILE'))],
4808 _('SSL certificate file'), _('FILE'))],
4804 _('[OPTION]...')),
4809 _('[OPTION]...')),
4805 "showconfig|debugconfig":
4810 "showconfig|debugconfig":
4806 (showconfig,
4811 (showconfig,
4807 [('u', 'untrusted', None, _('show untrusted configuration options'))],
4812 [('u', 'untrusted', None, _('show untrusted configuration options'))],
4808 _('[-u] [NAME]...')),
4813 _('[-u] [NAME]...')),
4809 "^summary|sum":
4814 "^summary|sum":
4810 (summary,
4815 (summary,
4811 [('', 'remote', None, _('check for push and pull'))], '[--remote]'),
4816 [('', 'remote', None, _('check for push and pull'))], '[--remote]'),
4812 "^status|st":
4817 "^status|st":
4813 (status,
4818 (status,
4814 [('A', 'all', None, _('show status of all files')),
4819 [('A', 'all', None, _('show status of all files')),
4815 ('m', 'modified', None, _('show only modified files')),
4820 ('m', 'modified', None, _('show only modified files')),
4816 ('a', 'added', None, _('show only added files')),
4821 ('a', 'added', None, _('show only added files')),
4817 ('r', 'removed', None, _('show only removed files')),
4822 ('r', 'removed', None, _('show only removed files')),
4818 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
4823 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
4819 ('c', 'clean', None, _('show only files without changes')),
4824 ('c', 'clean', None, _('show only files without changes')),
4820 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
4825 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
4821 ('i', 'ignored', None, _('show only ignored files')),
4826 ('i', 'ignored', None, _('show only ignored files')),
4822 ('n', 'no-status', None, _('hide status prefix')),
4827 ('n', 'no-status', None, _('hide status prefix')),
4823 ('C', 'copies', None, _('show source of copied files')),
4828 ('C', 'copies', None, _('show source of copied files')),
4824 ('0', 'print0', None,
4829 ('0', 'print0', None,
4825 _('end filenames with NUL, for use with xargs')),
4830 _('end filenames with NUL, for use with xargs')),
4826 ('', 'rev', [],
4831 ('', 'rev', [],
4827 _('show difference from revision'), _('REV')),
4832 _('show difference from revision'), _('REV')),
4828 ('', 'change', '',
4833 ('', 'change', '',
4829 _('list the changed files of a revision'), _('REV')),
4834 _('list the changed files of a revision'), _('REV')),
4830 ] + walkopts + subrepoopts,
4835 ] + walkopts + subrepoopts,
4831 _('[OPTION]... [FILE]...')),
4836 _('[OPTION]... [FILE]...')),
4832 "tag":
4837 "tag":
4833 (tag,
4838 (tag,
4834 [('f', 'force', None, _('force tag')),
4839 [('f', 'force', None, _('force tag')),
4835 ('l', 'local', None, _('make the tag local')),
4840 ('l', 'local', None, _('make the tag local')),
4836 ('r', 'rev', '',
4841 ('r', 'rev', '',
4837 _('revision to tag'), _('REV')),
4842 _('revision to tag'), _('REV')),
4838 ('', 'remove', None, _('remove a tag')),
4843 ('', 'remove', None, _('remove a tag')),
4839 # -l/--local is already there, commitopts cannot be used
4844 # -l/--local is already there, commitopts cannot be used
4840 ('e', 'edit', None, _('edit commit message')),
4845 ('e', 'edit', None, _('edit commit message')),
4841 ('m', 'message', '',
4846 ('m', 'message', '',
4842 _('use <text> as commit message'), _('TEXT')),
4847 _('use <text> as commit message'), _('TEXT')),
4843 ] + commitopts2,
4848 ] + commitopts2,
4844 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...')),
4849 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...')),
4845 "tags": (tags, [], ''),
4850 "tags": (tags, [], ''),
4846 "tip":
4851 "tip":
4847 (tip,
4852 (tip,
4848 [('p', 'patch', None, _('show patch')),
4853 [('p', 'patch', None, _('show patch')),
4849 ('g', 'git', None, _('use git extended diff format')),
4854 ('g', 'git', None, _('use git extended diff format')),
4850 ] + templateopts,
4855 ] + templateopts,
4851 _('[-p] [-g]')),
4856 _('[-p] [-g]')),
4852 "unbundle":
4857 "unbundle":
4853 (unbundle,
4858 (unbundle,
4854 [('u', 'update', None,
4859 [('u', 'update', None,
4855 _('update to new branch head if changesets were unbundled'))],
4860 _('update to new branch head if changesets were unbundled'))],
4856 _('[-u] FILE...')),
4861 _('[-u] FILE...')),
4857 "^update|up|checkout|co":
4862 "^update|up|checkout|co":
4858 (update,
4863 (update,
4859 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
4864 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
4860 ('c', 'check', None,
4865 ('c', 'check', None,
4861 _('update across branches if no uncommitted changes')),
4866 _('update across branches if no uncommitted changes')),
4862 ('d', 'date', '',
4867 ('d', 'date', '',
4863 _('tipmost revision matching date'), _('DATE')),
4868 _('tipmost revision matching date'), _('DATE')),
4864 ('r', 'rev', '',
4869 ('r', 'rev', '',
4865 _('revision'), _('REV'))],
4870 _('revision'), _('REV'))],
4866 _('[-c] [-C] [-d DATE] [[-r] REV]')),
4871 _('[-c] [-C] [-d DATE] [[-r] REV]')),
4867 "verify": (verify, []),
4872 "verify": (verify, []),
4868 "version": (version_, []),
4873 "version": (version_, []),
4869 }
4874 }
4870
4875
4871 norepo = ("clone init version help debugcommands debugcomplete"
4876 norepo = ("clone init version help debugcommands debugcomplete"
4872 " debugdate debuginstall debugfsinfo debugpushkey debugwireargs"
4877 " debugdate debuginstall debugfsinfo debugpushkey debugwireargs"
4873 " debugknown debuggetbundle debugbundle")
4878 " debugknown debuggetbundle debugbundle")
4874 optionalrepo = ("identify paths serve showconfig debugancestor debugdag"
4879 optionalrepo = ("identify paths serve showconfig debugancestor debugdag"
4875 " debugdata debugindex debugindexdot")
4880 " debugdata debugindex debugindexdot")
@@ -1,1275 +1,1274 b''
1 # revlog.py - storage back-end for mercurial
1 # revlog.py - storage back-end for mercurial
2 #
2 #
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 """Storage back-end for Mercurial.
8 """Storage back-end for Mercurial.
9
9
10 This provides efficient delta storage with O(1) retrieve and append
10 This provides efficient delta storage with O(1) retrieve and append
11 and O(changes) merge between branches.
11 and O(changes) merge between branches.
12 """
12 """
13
13
14 # import stuff from node for others to import from revlog
14 # import stuff from node for others to import from revlog
15 from node import bin, hex, nullid, nullrev, short #@UnusedImport
15 from node import bin, hex, nullid, nullrev, short #@UnusedImport
16 from i18n import _
16 from i18n import _
17 import ancestor, mdiff, parsers, error, util
17 import ancestor, mdiff, parsers, error, util
18 import struct, zlib, errno
18 import struct, zlib, errno
19
19
20 _pack = struct.pack
20 _pack = struct.pack
21 _unpack = struct.unpack
21 _unpack = struct.unpack
22 _compress = zlib.compress
22 _compress = zlib.compress
23 _decompress = zlib.decompress
23 _decompress = zlib.decompress
24 _sha = util.sha1
24 _sha = util.sha1
25
25
26 # revlog header flags
26 # revlog header flags
27 REVLOGV0 = 0
27 REVLOGV0 = 0
28 REVLOGNG = 1
28 REVLOGNG = 1
29 REVLOGNGINLINEDATA = (1 << 16)
29 REVLOGNGINLINEDATA = (1 << 16)
30 REVLOGSHALLOW = (1 << 17)
30 REVLOGSHALLOW = (1 << 17)
31 REVLOG_DEFAULT_FLAGS = REVLOGNGINLINEDATA
31 REVLOG_DEFAULT_FLAGS = REVLOGNGINLINEDATA
32 REVLOG_DEFAULT_FORMAT = REVLOGNG
32 REVLOG_DEFAULT_FORMAT = REVLOGNG
33 REVLOG_DEFAULT_VERSION = REVLOG_DEFAULT_FORMAT | REVLOG_DEFAULT_FLAGS
33 REVLOG_DEFAULT_VERSION = REVLOG_DEFAULT_FORMAT | REVLOG_DEFAULT_FLAGS
34 REVLOGNG_FLAGS = REVLOGNGINLINEDATA | REVLOGSHALLOW
34 REVLOGNG_FLAGS = REVLOGNGINLINEDATA | REVLOGSHALLOW
35
35
36 # revlog index flags
36 # revlog index flags
37 REVIDX_PARENTDELTA = 1
37 REVIDX_PARENTDELTA = 1
38 REVIDX_PUNCHED_FLAG = 2
38 REVIDX_PUNCHED_FLAG = 2
39 REVIDX_KNOWN_FLAGS = REVIDX_PUNCHED_FLAG | REVIDX_PARENTDELTA
39 REVIDX_KNOWN_FLAGS = REVIDX_PUNCHED_FLAG | REVIDX_PARENTDELTA
40
40
41 # max size of revlog with inline data
41 # max size of revlog with inline data
42 _maxinline = 131072
42 _maxinline = 131072
43 _chunksize = 1048576
43 _chunksize = 1048576
44
44
45 RevlogError = error.RevlogError
45 RevlogError = error.RevlogError
46 LookupError = error.LookupError
46 LookupError = error.LookupError
47
47
48 def getoffset(q):
48 def getoffset(q):
49 return int(q >> 16)
49 return int(q >> 16)
50
50
51 def gettype(q):
51 def gettype(q):
52 return int(q & 0xFFFF)
52 return int(q & 0xFFFF)
53
53
54 def offset_type(offset, type):
54 def offset_type(offset, type):
55 return long(long(offset) << 16 | type)
55 return long(long(offset) << 16 | type)
56
56
57 nullhash = _sha(nullid)
57 nullhash = _sha(nullid)
58
58
59 def hash(text, p1, p2):
59 def hash(text, p1, p2):
60 """generate a hash from the given text and its parent hashes
60 """generate a hash from the given text and its parent hashes
61
61
62 This hash combines both the current file contents and its history
62 This hash combines both the current file contents and its history
63 in a manner that makes it easy to distinguish nodes with the same
63 in a manner that makes it easy to distinguish nodes with the same
64 content in the revision graph.
64 content in the revision graph.
65 """
65 """
66 # As of now, if one of the parent node is null, p2 is null
66 # As of now, if one of the parent node is null, p2 is null
67 if p2 == nullid:
67 if p2 == nullid:
68 # deep copy of a hash is faster than creating one
68 # deep copy of a hash is faster than creating one
69 s = nullhash.copy()
69 s = nullhash.copy()
70 s.update(p1)
70 s.update(p1)
71 else:
71 else:
72 # none of the parent nodes are nullid
72 # none of the parent nodes are nullid
73 l = [p1, p2]
73 l = [p1, p2]
74 l.sort()
74 l.sort()
75 s = _sha(l[0])
75 s = _sha(l[0])
76 s.update(l[1])
76 s.update(l[1])
77 s.update(text)
77 s.update(text)
78 return s.digest()
78 return s.digest()
79
79
80 def compress(text):
80 def compress(text):
81 """ generate a possibly-compressed representation of text """
81 """ generate a possibly-compressed representation of text """
82 if not text:
82 if not text:
83 return ("", text)
83 return ("", text)
84 l = len(text)
84 l = len(text)
85 bin = None
85 bin = None
86 if l < 44:
86 if l < 44:
87 pass
87 pass
88 elif l > 1000000:
88 elif l > 1000000:
89 # zlib makes an internal copy, thus doubling memory usage for
89 # zlib makes an internal copy, thus doubling memory usage for
90 # large files, so lets do this in pieces
90 # large files, so lets do this in pieces
91 z = zlib.compressobj()
91 z = zlib.compressobj()
92 p = []
92 p = []
93 pos = 0
93 pos = 0
94 while pos < l:
94 while pos < l:
95 pos2 = pos + 2**20
95 pos2 = pos + 2**20
96 p.append(z.compress(text[pos:pos2]))
96 p.append(z.compress(text[pos:pos2]))
97 pos = pos2
97 pos = pos2
98 p.append(z.flush())
98 p.append(z.flush())
99 if sum(map(len, p)) < l:
99 if sum(map(len, p)) < l:
100 bin = "".join(p)
100 bin = "".join(p)
101 else:
101 else:
102 bin = _compress(text)
102 bin = _compress(text)
103 if bin is None or len(bin) > l:
103 if bin is None or len(bin) > l:
104 if text[0] == '\0':
104 if text[0] == '\0':
105 return ("", text)
105 return ("", text)
106 return ('u', text)
106 return ('u', text)
107 return ("", bin)
107 return ("", bin)
108
108
109 def decompress(bin):
109 def decompress(bin):
110 """ decompress the given input """
110 """ decompress the given input """
111 if not bin:
111 if not bin:
112 return bin
112 return bin
113 t = bin[0]
113 t = bin[0]
114 if t == '\0':
114 if t == '\0':
115 return bin
115 return bin
116 if t == 'x':
116 if t == 'x':
117 return _decompress(bin)
117 return _decompress(bin)
118 if t == 'u':
118 if t == 'u':
119 return bin[1:]
119 return bin[1:]
120 raise RevlogError(_("unknown compression type %r") % t)
120 raise RevlogError(_("unknown compression type %r") % t)
121
121
122 indexformatv0 = ">4l20s20s20s"
122 indexformatv0 = ">4l20s20s20s"
123 v0shaoffset = 56
123 v0shaoffset = 56
124
124
125 class revlogoldio(object):
125 class revlogoldio(object):
126 def __init__(self):
126 def __init__(self):
127 self.size = struct.calcsize(indexformatv0)
127 self.size = struct.calcsize(indexformatv0)
128
128
129 def parseindex(self, data, inline):
129 def parseindex(self, data, inline):
130 s = self.size
130 s = self.size
131 index = []
131 index = []
132 nodemap = {nullid: nullrev}
132 nodemap = {nullid: nullrev}
133 n = off = 0
133 n = off = 0
134 l = len(data)
134 l = len(data)
135 while off + s <= l:
135 while off + s <= l:
136 cur = data[off:off + s]
136 cur = data[off:off + s]
137 off += s
137 off += s
138 e = _unpack(indexformatv0, cur)
138 e = _unpack(indexformatv0, cur)
139 # transform to revlogv1 format
139 # transform to revlogv1 format
140 e2 = (offset_type(e[0], 0), e[1], -1, e[2], e[3],
140 e2 = (offset_type(e[0], 0), e[1], -1, e[2], e[3],
141 nodemap.get(e[4], nullrev), nodemap.get(e[5], nullrev), e[6])
141 nodemap.get(e[4], nullrev), nodemap.get(e[5], nullrev), e[6])
142 index.append(e2)
142 index.append(e2)
143 nodemap[e[6]] = n
143 nodemap[e[6]] = n
144 n += 1
144 n += 1
145
145
146 # add the magic null revision at -1
146 # add the magic null revision at -1
147 index.append((0, 0, 0, -1, -1, -1, -1, nullid))
147 index.append((0, 0, 0, -1, -1, -1, -1, nullid))
148
148
149 return index, nodemap, None
149 return index, nodemap, None
150
150
151 def packentry(self, entry, node, version, rev):
151 def packentry(self, entry, node, version, rev):
152 if gettype(entry[0]):
152 if gettype(entry[0]):
153 raise RevlogError(_("index entry flags need RevlogNG"))
153 raise RevlogError(_("index entry flags need RevlogNG"))
154 e2 = (getoffset(entry[0]), entry[1], entry[3], entry[4],
154 e2 = (getoffset(entry[0]), entry[1], entry[3], entry[4],
155 node(entry[5]), node(entry[6]), entry[7])
155 node(entry[5]), node(entry[6]), entry[7])
156 return _pack(indexformatv0, *e2)
156 return _pack(indexformatv0, *e2)
157
157
158 # index ng:
158 # index ng:
159 # 6 bytes: offset
159 # 6 bytes: offset
160 # 2 bytes: flags
160 # 2 bytes: flags
161 # 4 bytes: compressed length
161 # 4 bytes: compressed length
162 # 4 bytes: uncompressed length
162 # 4 bytes: uncompressed length
163 # 4 bytes: base rev
163 # 4 bytes: base rev
164 # 4 bytes: link rev
164 # 4 bytes: link rev
165 # 4 bytes: parent 1 rev
165 # 4 bytes: parent 1 rev
166 # 4 bytes: parent 2 rev
166 # 4 bytes: parent 2 rev
167 # 32 bytes: nodeid
167 # 32 bytes: nodeid
168 indexformatng = ">Qiiiiii20s12x"
168 indexformatng = ">Qiiiiii20s12x"
169 ngshaoffset = 32
169 ngshaoffset = 32
170 versionformat = ">I"
170 versionformat = ">I"
171
171
172 class revlogio(object):
172 class revlogio(object):
173 def __init__(self):
173 def __init__(self):
174 self.size = struct.calcsize(indexformatng)
174 self.size = struct.calcsize(indexformatng)
175
175
176 def parseindex(self, data, inline):
176 def parseindex(self, data, inline):
177 # call the C implementation to parse the index data
177 # call the C implementation to parse the index data
178 index, cache = parsers.parse_index2(data, inline)
178 index, cache = parsers.parse_index2(data, inline)
179 return index, None, cache
179 return index, None, cache
180
180
181 def packentry(self, entry, node, version, rev):
181 def packentry(self, entry, node, version, rev):
182 p = _pack(indexformatng, *entry)
182 p = _pack(indexformatng, *entry)
183 if rev == 0:
183 if rev == 0:
184 p = _pack(versionformat, version) + p[4:]
184 p = _pack(versionformat, version) + p[4:]
185 return p
185 return p
186
186
187 class revlog(object):
187 class revlog(object):
188 """
188 """
189 the underlying revision storage object
189 the underlying revision storage object
190
190
191 A revlog consists of two parts, an index and the revision data.
191 A revlog consists of two parts, an index and the revision data.
192
192
193 The index is a file with a fixed record size containing
193 The index is a file with a fixed record size containing
194 information on each revision, including its nodeid (hash), the
194 information on each revision, including its nodeid (hash), the
195 nodeids of its parents, the position and offset of its data within
195 nodeids of its parents, the position and offset of its data within
196 the data file, and the revision it's based on. Finally, each entry
196 the data file, and the revision it's based on. Finally, each entry
197 contains a linkrev entry that can serve as a pointer to external
197 contains a linkrev entry that can serve as a pointer to external
198 data.
198 data.
199
199
200 The revision data itself is a linear collection of data chunks.
200 The revision data itself is a linear collection of data chunks.
201 Each chunk represents a revision and is usually represented as a
201 Each chunk represents a revision and is usually represented as a
202 delta against the previous chunk. To bound lookup time, runs of
202 delta against the previous chunk. To bound lookup time, runs of
203 deltas are limited to about 2 times the length of the original
203 deltas are limited to about 2 times the length of the original
204 version data. This makes retrieval of a version proportional to
204 version data. This makes retrieval of a version proportional to
205 its size, or O(1) relative to the number of revisions.
205 its size, or O(1) relative to the number of revisions.
206
206
207 Both pieces of the revlog are written to in an append-only
207 Both pieces of the revlog are written to in an append-only
208 fashion, which means we never need to rewrite a file to insert or
208 fashion, which means we never need to rewrite a file to insert or
209 remove data, and can use some simple techniques to avoid the need
209 remove data, and can use some simple techniques to avoid the need
210 for locking while reading.
210 for locking while reading.
211 """
211 """
212 def __init__(self, opener, indexfile, shallowroot=None):
212 def __init__(self, opener, indexfile, shallowroot=None):
213 """
213 """
214 create a revlog object
214 create a revlog object
215
215
216 opener is a function that abstracts the file opening operation
216 opener is a function that abstracts the file opening operation
217 and can be used to implement COW semantics or the like.
217 and can be used to implement COW semantics or the like.
218 """
218 """
219 self.indexfile = indexfile
219 self.indexfile = indexfile
220 self.datafile = indexfile[:-2] + ".d"
220 self.datafile = indexfile[:-2] + ".d"
221 self.opener = opener
221 self.opener = opener
222 self._cache = None
222 self._cache = None
223 self._chunkcache = (0, '')
223 self._chunkcache = (0, '')
224 self.index = []
224 self.index = []
225 self._shallowroot = shallowroot
225 self._shallowroot = shallowroot
226 self._parentdelta = 0
226 self._parentdelta = 0
227 self._pcache = {}
227 self._pcache = {}
228 self._nodecache = {nullid: nullrev}
228 self._nodecache = {nullid: nullrev}
229 self._nodepos = None
229 self._nodepos = None
230
230
231 v = REVLOG_DEFAULT_VERSION
231 v = REVLOG_DEFAULT_VERSION
232 if hasattr(opener, 'options') and 'defversion' in opener.options:
232 if hasattr(opener, 'options') and 'defversion' in opener.options:
233 v = opener.options['defversion']
233 v = opener.options['defversion']
234 if v & REVLOGNG:
234 if v & REVLOGNG:
235 v |= REVLOGNGINLINEDATA
235 v |= REVLOGNGINLINEDATA
236 if v & REVLOGNG and 'parentdelta' in opener.options:
236 if v & REVLOGNG and 'parentdelta' in opener.options:
237 self._parentdelta = 1
237 self._parentdelta = 1
238
238
239 if shallowroot:
239 if shallowroot:
240 v |= REVLOGSHALLOW
240 v |= REVLOGSHALLOW
241
241
242 i = ''
242 i = ''
243 try:
243 try:
244 f = self.opener(self.indexfile)
244 f = self.opener(self.indexfile)
245 i = f.read()
245 i = f.read()
246 f.close()
246 f.close()
247 if len(i) > 0:
247 if len(i) > 0:
248 v = struct.unpack(versionformat, i[:4])[0]
248 v = struct.unpack(versionformat, i[:4])[0]
249 except IOError, inst:
249 except IOError, inst:
250 if inst.errno != errno.ENOENT:
250 if inst.errno != errno.ENOENT:
251 raise
251 raise
252
252
253 self.version = v
253 self.version = v
254 self._inline = v & REVLOGNGINLINEDATA
254 self._inline = v & REVLOGNGINLINEDATA
255 self._shallow = v & REVLOGSHALLOW
255 self._shallow = v & REVLOGSHALLOW
256 flags = v & ~0xFFFF
256 flags = v & ~0xFFFF
257 fmt = v & 0xFFFF
257 fmt = v & 0xFFFF
258 if fmt == REVLOGV0 and flags:
258 if fmt == REVLOGV0 and flags:
259 raise RevlogError(_("index %s unknown flags %#04x for format v0")
259 raise RevlogError(_("index %s unknown flags %#04x for format v0")
260 % (self.indexfile, flags >> 16))
260 % (self.indexfile, flags >> 16))
261 elif fmt == REVLOGNG and flags & ~REVLOGNG_FLAGS:
261 elif fmt == REVLOGNG and flags & ~REVLOGNG_FLAGS:
262 raise RevlogError(_("index %s unknown flags %#04x for revlogng")
262 raise RevlogError(_("index %s unknown flags %#04x for revlogng")
263 % (self.indexfile, flags >> 16))
263 % (self.indexfile, flags >> 16))
264 elif fmt > REVLOGNG:
264 elif fmt > REVLOGNG:
265 raise RevlogError(_("index %s unknown format %d")
265 raise RevlogError(_("index %s unknown format %d")
266 % (self.indexfile, fmt))
266 % (self.indexfile, fmt))
267
267
268 self._io = revlogio()
268 self._io = revlogio()
269 if self.version == REVLOGV0:
269 if self.version == REVLOGV0:
270 self._io = revlogoldio()
270 self._io = revlogoldio()
271 try:
271 try:
272 d = self._io.parseindex(i, self._inline)
272 d = self._io.parseindex(i, self._inline)
273 except (ValueError, IndexError):
273 except (ValueError, IndexError):
274 raise RevlogError(_("index %s is corrupted") % (self.indexfile))
274 raise RevlogError(_("index %s is corrupted") % (self.indexfile))
275 self.index, nodemap, self._chunkcache = d
275 self.index, nodemap, self._chunkcache = d
276 if nodemap is not None:
276 if nodemap is not None:
277 self.nodemap = self._nodecache = nodemap
277 self.nodemap = self._nodecache = nodemap
278 if not self._chunkcache:
278 if not self._chunkcache:
279 self._chunkclear()
279 self._chunkclear()
280
280
281 def tip(self):
281 def tip(self):
282 return self.node(len(self.index) - 2)
282 return self.node(len(self.index) - 2)
283 def __len__(self):
283 def __len__(self):
284 return len(self.index) - 1
284 return len(self.index) - 1
285 def __iter__(self):
285 def __iter__(self):
286 for i in xrange(len(self)):
286 for i in xrange(len(self)):
287 yield i
287 yield i
288
288
289 @util.propertycache
289 @util.propertycache
290 def nodemap(self):
290 def nodemap(self):
291 self.rev(self.node(0))
291 self.rev(self.node(0))
292 return self._nodecache
292 return self._nodecache
293
293
294 def rev(self, node):
294 def rev(self, node):
295 try:
295 try:
296 return self._nodecache[node]
296 return self._nodecache[node]
297 except KeyError:
297 except KeyError:
298 n = self._nodecache
298 n = self._nodecache
299 i = self.index
299 i = self.index
300 p = self._nodepos
300 p = self._nodepos
301 if p is None:
301 if p is None:
302 p = len(i) - 2
302 p = len(i) - 2
303 for r in xrange(p, -1, -1):
303 for r in xrange(p, -1, -1):
304 v = i[r][7]
304 v = i[r][7]
305 n[v] = r
305 n[v] = r
306 if v == node:
306 if v == node:
307 self._nodepos = r - 1
307 self._nodepos = r - 1
308 return r
308 return r
309 raise LookupError(node, self.indexfile, _('no node'))
309 raise LookupError(node, self.indexfile, _('no node'))
310
310
311 def node(self, rev):
311 def node(self, rev):
312 return self.index[rev][7]
312 return self.index[rev][7]
313 def linkrev(self, rev):
313 def linkrev(self, rev):
314 return self.index[rev][4]
314 return self.index[rev][4]
315 def parents(self, node):
315 def parents(self, node):
316 i = self.index
316 i = self.index
317 d = i[self.rev(node)]
317 d = i[self.rev(node)]
318 return i[d[5]][7], i[d[6]][7] # map revisions to nodes inline
318 return i[d[5]][7], i[d[6]][7] # map revisions to nodes inline
319 def parentrevs(self, rev):
319 def parentrevs(self, rev):
320 return self.index[rev][5:7]
320 return self.index[rev][5:7]
321 def start(self, rev):
321 def start(self, rev):
322 return int(self.index[rev][0] >> 16)
322 return int(self.index[rev][0] >> 16)
323 def end(self, rev):
323 def end(self, rev):
324 return self.start(rev) + self.length(rev)
324 return self.start(rev) + self.length(rev)
325 def length(self, rev):
325 def length(self, rev):
326 return self.index[rev][1]
326 return self.index[rev][1]
327 def base(self, rev):
327 def base(self, rev):
328 return self.index[rev][3]
328 return self.index[rev][3]
329 def flags(self, rev):
329 def flags(self, rev):
330 return self.index[rev][0] & 0xFFFF
330 return self.index[rev][0] & 0xFFFF
331 def rawsize(self, rev):
331 def rawsize(self, rev):
332 """return the length of the uncompressed text for a given revision"""
332 """return the length of the uncompressed text for a given revision"""
333 l = self.index[rev][2]
333 l = self.index[rev][2]
334 if l >= 0:
334 if l >= 0:
335 return l
335 return l
336
336
337 t = self.revision(self.node(rev))
337 t = self.revision(self.node(rev))
338 return len(t)
338 return len(t)
339 size = rawsize
339 size = rawsize
340
340
341 def reachable(self, node, stop=None):
341 def reachable(self, node, stop=None):
342 """return the set of all nodes ancestral to a given node, including
342 """return the set of all nodes ancestral to a given node, including
343 the node itself, stopping when stop is matched"""
343 the node itself, stopping when stop is matched"""
344 reachable = set((node,))
344 reachable = set((node,))
345 visit = [node]
345 visit = [node]
346 if stop:
346 if stop:
347 stopn = self.rev(stop)
347 stopn = self.rev(stop)
348 else:
348 else:
349 stopn = 0
349 stopn = 0
350 while visit:
350 while visit:
351 n = visit.pop(0)
351 n = visit.pop(0)
352 if n == stop:
352 if n == stop:
353 continue
353 continue
354 if n == nullid:
354 if n == nullid:
355 continue
355 continue
356 for p in self.parents(n):
356 for p in self.parents(n):
357 if self.rev(p) < stopn:
357 if self.rev(p) < stopn:
358 continue
358 continue
359 if p not in reachable:
359 if p not in reachable:
360 reachable.add(p)
360 reachable.add(p)
361 visit.append(p)
361 visit.append(p)
362 return reachable
362 return reachable
363
363
364 def ancestors(self, *revs):
364 def ancestors(self, *revs):
365 """Generate the ancestors of 'revs' in reverse topological order.
365 """Generate the ancestors of 'revs' in reverse topological order.
366
366
367 Yield a sequence of revision numbers starting with the parents
367 Yield a sequence of revision numbers starting with the parents
368 of each revision in revs, i.e., each revision is *not* considered
368 of each revision in revs, i.e., each revision is *not* considered
369 an ancestor of itself. Results are in breadth-first order:
369 an ancestor of itself. Results are in breadth-first order:
370 parents of each rev in revs, then parents of those, etc. Result
370 parents of each rev in revs, then parents of those, etc. Result
371 does not include the null revision."""
371 does not include the null revision."""
372 visit = list(revs)
372 visit = list(revs)
373 seen = set([nullrev])
373 seen = set([nullrev])
374 while visit:
374 while visit:
375 for parent in self.parentrevs(visit.pop(0)):
375 for parent in self.parentrevs(visit.pop(0)):
376 if parent not in seen:
376 if parent not in seen:
377 visit.append(parent)
377 visit.append(parent)
378 seen.add(parent)
378 seen.add(parent)
379 yield parent
379 yield parent
380
380
381 def descendants(self, *revs):
381 def descendants(self, *revs):
382 """Generate the descendants of 'revs' in revision order.
382 """Generate the descendants of 'revs' in revision order.
383
383
384 Yield a sequence of revision numbers starting with a child of
384 Yield a sequence of revision numbers starting with a child of
385 some rev in revs, i.e., each revision is *not* considered a
385 some rev in revs, i.e., each revision is *not* considered a
386 descendant of itself. Results are ordered by revision number (a
386 descendant of itself. Results are ordered by revision number (a
387 topological sort)."""
387 topological sort)."""
388 first = min(revs)
388 first = min(revs)
389 if first == nullrev:
389 if first == nullrev:
390 for i in self:
390 for i in self:
391 yield i
391 yield i
392 return
392 return
393
393
394 seen = set(revs)
394 seen = set(revs)
395 for i in xrange(first + 1, len(self)):
395 for i in xrange(first + 1, len(self)):
396 for x in self.parentrevs(i):
396 for x in self.parentrevs(i):
397 if x != nullrev and x in seen:
397 if x != nullrev and x in seen:
398 seen.add(i)
398 seen.add(i)
399 yield i
399 yield i
400 break
400 break
401
401
402 def findcommonmissing(self, common=None, heads=None):
402 def findcommonmissing(self, common=None, heads=None):
403 """Return a tuple of the ancestors of common and the ancestors of heads
403 """Return a tuple of the ancestors of common and the ancestors of heads
404 that are not ancestors of common.
404 that are not ancestors of common.
405
405
406 More specifically, the second element is a list of nodes N such that
406 More specifically, the second element is a list of nodes N such that
407 every N satisfies the following constraints:
407 every N satisfies the following constraints:
408
408
409 1. N is an ancestor of some node in 'heads'
409 1. N is an ancestor of some node in 'heads'
410 2. N is not an ancestor of any node in 'common'
410 2. N is not an ancestor of any node in 'common'
411
411
412 The list is sorted by revision number, meaning it is
412 The list is sorted by revision number, meaning it is
413 topologically sorted.
413 topologically sorted.
414
414
415 'heads' and 'common' are both lists of node IDs. If heads is
415 'heads' and 'common' are both lists of node IDs. If heads is
416 not supplied, uses all of the revlog's heads. If common is not
416 not supplied, uses all of the revlog's heads. If common is not
417 supplied, uses nullid."""
417 supplied, uses nullid."""
418 if common is None:
418 if common is None:
419 common = [nullid]
419 common = [nullid]
420 if heads is None:
420 if heads is None:
421 heads = self.heads()
421 heads = self.heads()
422
422
423 common = [self.rev(n) for n in common]
423 common = [self.rev(n) for n in common]
424 heads = [self.rev(n) for n in heads]
424 heads = [self.rev(n) for n in heads]
425
425
426 # we want the ancestors, but inclusive
426 # we want the ancestors, but inclusive
427 has = set(self.ancestors(*common))
427 has = set(self.ancestors(*common))
428 has.add(nullrev)
428 has.add(nullrev)
429 has.update(common)
429 has.update(common)
430
430
431 # take all ancestors from heads that aren't in has
431 # take all ancestors from heads that aren't in has
432 missing = set()
432 missing = set()
433 visit = [r for r in heads if r not in has]
433 visit = [r for r in heads if r not in has]
434 while visit:
434 while visit:
435 r = visit.pop(0)
435 r = visit.pop(0)
436 if r in missing:
436 if r in missing:
437 continue
437 continue
438 else:
438 else:
439 missing.add(r)
439 missing.add(r)
440 for p in self.parentrevs(r):
440 for p in self.parentrevs(r):
441 if p not in has:
441 if p not in has:
442 visit.append(p)
442 visit.append(p)
443 missing = list(missing)
443 missing = list(missing)
444 missing.sort()
444 missing.sort()
445 return has, [self.node(r) for r in missing]
445 return has, [self.node(r) for r in missing]
446
446
447 def findmissing(self, common=None, heads=None):
447 def findmissing(self, common=None, heads=None):
448 """Return the ancestors of heads that are not ancestors of common.
448 """Return the ancestors of heads that are not ancestors of common.
449
449
450 More specifically, return a list of nodes N such that every N
450 More specifically, return a list of nodes N such that every N
451 satisfies the following constraints:
451 satisfies the following constraints:
452
452
453 1. N is an ancestor of some node in 'heads'
453 1. N is an ancestor of some node in 'heads'
454 2. N is not an ancestor of any node in 'common'
454 2. N is not an ancestor of any node in 'common'
455
455
456 The list is sorted by revision number, meaning it is
456 The list is sorted by revision number, meaning it is
457 topologically sorted.
457 topologically sorted.
458
458
459 'heads' and 'common' are both lists of node IDs. If heads is
459 'heads' and 'common' are both lists of node IDs. If heads is
460 not supplied, uses all of the revlog's heads. If common is not
460 not supplied, uses all of the revlog's heads. If common is not
461 supplied, uses nullid."""
461 supplied, uses nullid."""
462 _common, missing = self.findcommonmissing(common, heads)
462 _common, missing = self.findcommonmissing(common, heads)
463 return missing
463 return missing
464
464
465 def nodesbetween(self, roots=None, heads=None):
465 def nodesbetween(self, roots=None, heads=None):
466 """Return a topological path from 'roots' to 'heads'.
466 """Return a topological path from 'roots' to 'heads'.
467
467
468 Return a tuple (nodes, outroots, outheads) where 'nodes' is a
468 Return a tuple (nodes, outroots, outheads) where 'nodes' is a
469 topologically sorted list of all nodes N that satisfy both of
469 topologically sorted list of all nodes N that satisfy both of
470 these constraints:
470 these constraints:
471
471
472 1. N is a descendant of some node in 'roots'
472 1. N is a descendant of some node in 'roots'
473 2. N is an ancestor of some node in 'heads'
473 2. N is an ancestor of some node in 'heads'
474
474
475 Every node is considered to be both a descendant and an ancestor
475 Every node is considered to be both a descendant and an ancestor
476 of itself, so every reachable node in 'roots' and 'heads' will be
476 of itself, so every reachable node in 'roots' and 'heads' will be
477 included in 'nodes'.
477 included in 'nodes'.
478
478
479 'outroots' is the list of reachable nodes in 'roots', i.e., the
479 'outroots' is the list of reachable nodes in 'roots', i.e., the
480 subset of 'roots' that is returned in 'nodes'. Likewise,
480 subset of 'roots' that is returned in 'nodes'. Likewise,
481 'outheads' is the subset of 'heads' that is also in 'nodes'.
481 'outheads' is the subset of 'heads' that is also in 'nodes'.
482
482
483 'roots' and 'heads' are both lists of node IDs. If 'roots' is
483 'roots' and 'heads' are both lists of node IDs. If 'roots' is
484 unspecified, uses nullid as the only root. If 'heads' is
484 unspecified, uses nullid as the only root. If 'heads' is
485 unspecified, uses list of all of the revlog's heads."""
485 unspecified, uses list of all of the revlog's heads."""
486 nonodes = ([], [], [])
486 nonodes = ([], [], [])
487 if roots is not None:
487 if roots is not None:
488 roots = list(roots)
488 roots = list(roots)
489 if not roots:
489 if not roots:
490 return nonodes
490 return nonodes
491 lowestrev = min([self.rev(n) for n in roots])
491 lowestrev = min([self.rev(n) for n in roots])
492 else:
492 else:
493 roots = [nullid] # Everybody's a descendent of nullid
493 roots = [nullid] # Everybody's a descendent of nullid
494 lowestrev = nullrev
494 lowestrev = nullrev
495 if (lowestrev == nullrev) and (heads is None):
495 if (lowestrev == nullrev) and (heads is None):
496 # We want _all_ the nodes!
496 # We want _all_ the nodes!
497 return ([self.node(r) for r in self], [nullid], list(self.heads()))
497 return ([self.node(r) for r in self], [nullid], list(self.heads()))
498 if heads is None:
498 if heads is None:
499 # All nodes are ancestors, so the latest ancestor is the last
499 # All nodes are ancestors, so the latest ancestor is the last
500 # node.
500 # node.
501 highestrev = len(self) - 1
501 highestrev = len(self) - 1
502 # Set ancestors to None to signal that every node is an ancestor.
502 # Set ancestors to None to signal that every node is an ancestor.
503 ancestors = None
503 ancestors = None
504 # Set heads to an empty dictionary for later discovery of heads
504 # Set heads to an empty dictionary for later discovery of heads
505 heads = {}
505 heads = {}
506 else:
506 else:
507 heads = list(heads)
507 heads = list(heads)
508 if not heads:
508 if not heads:
509 return nonodes
509 return nonodes
510 ancestors = set()
510 ancestors = set()
511 # Turn heads into a dictionary so we can remove 'fake' heads.
511 # Turn heads into a dictionary so we can remove 'fake' heads.
512 # Also, later we will be using it to filter out the heads we can't
512 # Also, later we will be using it to filter out the heads we can't
513 # find from roots.
513 # find from roots.
514 heads = dict.fromkeys(heads, 0)
514 heads = dict.fromkeys(heads, 0)
515 # Start at the top and keep marking parents until we're done.
515 # Start at the top and keep marking parents until we're done.
516 nodestotag = set(heads)
516 nodestotag = set(heads)
517 # Remember where the top was so we can use it as a limit later.
517 # Remember where the top was so we can use it as a limit later.
518 highestrev = max([self.rev(n) for n in nodestotag])
518 highestrev = max([self.rev(n) for n in nodestotag])
519 while nodestotag:
519 while nodestotag:
520 # grab a node to tag
520 # grab a node to tag
521 n = nodestotag.pop()
521 n = nodestotag.pop()
522 # Never tag nullid
522 # Never tag nullid
523 if n == nullid:
523 if n == nullid:
524 continue
524 continue
525 # A node's revision number represents its place in a
525 # A node's revision number represents its place in a
526 # topologically sorted list of nodes.
526 # topologically sorted list of nodes.
527 r = self.rev(n)
527 r = self.rev(n)
528 if r >= lowestrev:
528 if r >= lowestrev:
529 if n not in ancestors:
529 if n not in ancestors:
530 # If we are possibly a descendent of one of the roots
530 # If we are possibly a descendent of one of the roots
531 # and we haven't already been marked as an ancestor
531 # and we haven't already been marked as an ancestor
532 ancestors.add(n) # Mark as ancestor
532 ancestors.add(n) # Mark as ancestor
533 # Add non-nullid parents to list of nodes to tag.
533 # Add non-nullid parents to list of nodes to tag.
534 nodestotag.update([p for p in self.parents(n) if
534 nodestotag.update([p for p in self.parents(n) if
535 p != nullid])
535 p != nullid])
536 elif n in heads: # We've seen it before, is it a fake head?
536 elif n in heads: # We've seen it before, is it a fake head?
537 # So it is, real heads should not be the ancestors of
537 # So it is, real heads should not be the ancestors of
538 # any other heads.
538 # any other heads.
539 heads.pop(n)
539 heads.pop(n)
540 if not ancestors:
540 if not ancestors:
541 return nonodes
541 return nonodes
542 # Now that we have our set of ancestors, we want to remove any
542 # Now that we have our set of ancestors, we want to remove any
543 # roots that are not ancestors.
543 # roots that are not ancestors.
544
544
545 # If one of the roots was nullid, everything is included anyway.
545 # If one of the roots was nullid, everything is included anyway.
546 if lowestrev > nullrev:
546 if lowestrev > nullrev:
547 # But, since we weren't, let's recompute the lowest rev to not
547 # But, since we weren't, let's recompute the lowest rev to not
548 # include roots that aren't ancestors.
548 # include roots that aren't ancestors.
549
549
550 # Filter out roots that aren't ancestors of heads
550 # Filter out roots that aren't ancestors of heads
551 roots = [n for n in roots if n in ancestors]
551 roots = [n for n in roots if n in ancestors]
552 # Recompute the lowest revision
552 # Recompute the lowest revision
553 if roots:
553 if roots:
554 lowestrev = min([self.rev(n) for n in roots])
554 lowestrev = min([self.rev(n) for n in roots])
555 else:
555 else:
556 # No more roots? Return empty list
556 # No more roots? Return empty list
557 return nonodes
557 return nonodes
558 else:
558 else:
559 # We are descending from nullid, and don't need to care about
559 # We are descending from nullid, and don't need to care about
560 # any other roots.
560 # any other roots.
561 lowestrev = nullrev
561 lowestrev = nullrev
562 roots = [nullid]
562 roots = [nullid]
563 # Transform our roots list into a set.
563 # Transform our roots list into a set.
564 descendents = set(roots)
564 descendents = set(roots)
565 # Also, keep the original roots so we can filter out roots that aren't
565 # Also, keep the original roots so we can filter out roots that aren't
566 # 'real' roots (i.e. are descended from other roots).
566 # 'real' roots (i.e. are descended from other roots).
567 roots = descendents.copy()
567 roots = descendents.copy()
568 # Our topologically sorted list of output nodes.
568 # Our topologically sorted list of output nodes.
569 orderedout = []
569 orderedout = []
570 # Don't start at nullid since we don't want nullid in our output list,
570 # Don't start at nullid since we don't want nullid in our output list,
571 # and if nullid shows up in descedents, empty parents will look like
571 # and if nullid shows up in descedents, empty parents will look like
572 # they're descendents.
572 # they're descendents.
573 for r in xrange(max(lowestrev, 0), highestrev + 1):
573 for r in xrange(max(lowestrev, 0), highestrev + 1):
574 n = self.node(r)
574 n = self.node(r)
575 isdescendent = False
575 isdescendent = False
576 if lowestrev == nullrev: # Everybody is a descendent of nullid
576 if lowestrev == nullrev: # Everybody is a descendent of nullid
577 isdescendent = True
577 isdescendent = True
578 elif n in descendents:
578 elif n in descendents:
579 # n is already a descendent
579 # n is already a descendent
580 isdescendent = True
580 isdescendent = True
581 # This check only needs to be done here because all the roots
581 # This check only needs to be done here because all the roots
582 # will start being marked is descendents before the loop.
582 # will start being marked is descendents before the loop.
583 if n in roots:
583 if n in roots:
584 # If n was a root, check if it's a 'real' root.
584 # If n was a root, check if it's a 'real' root.
585 p = tuple(self.parents(n))
585 p = tuple(self.parents(n))
586 # If any of its parents are descendents, it's not a root.
586 # If any of its parents are descendents, it's not a root.
587 if (p[0] in descendents) or (p[1] in descendents):
587 if (p[0] in descendents) or (p[1] in descendents):
588 roots.remove(n)
588 roots.remove(n)
589 else:
589 else:
590 p = tuple(self.parents(n))
590 p = tuple(self.parents(n))
591 # A node is a descendent if either of its parents are
591 # A node is a descendent if either of its parents are
592 # descendents. (We seeded the dependents list with the roots
592 # descendents. (We seeded the dependents list with the roots
593 # up there, remember?)
593 # up there, remember?)
594 if (p[0] in descendents) or (p[1] in descendents):
594 if (p[0] in descendents) or (p[1] in descendents):
595 descendents.add(n)
595 descendents.add(n)
596 isdescendent = True
596 isdescendent = True
597 if isdescendent and ((ancestors is None) or (n in ancestors)):
597 if isdescendent and ((ancestors is None) or (n in ancestors)):
598 # Only include nodes that are both descendents and ancestors.
598 # Only include nodes that are both descendents and ancestors.
599 orderedout.append(n)
599 orderedout.append(n)
600 if (ancestors is not None) and (n in heads):
600 if (ancestors is not None) and (n in heads):
601 # We're trying to figure out which heads are reachable
601 # We're trying to figure out which heads are reachable
602 # from roots.
602 # from roots.
603 # Mark this head as having been reached
603 # Mark this head as having been reached
604 heads[n] = 1
604 heads[n] = 1
605 elif ancestors is None:
605 elif ancestors is None:
606 # Otherwise, we're trying to discover the heads.
606 # Otherwise, we're trying to discover the heads.
607 # Assume this is a head because if it isn't, the next step
607 # Assume this is a head because if it isn't, the next step
608 # will eventually remove it.
608 # will eventually remove it.
609 heads[n] = 1
609 heads[n] = 1
610 # But, obviously its parents aren't.
610 # But, obviously its parents aren't.
611 for p in self.parents(n):
611 for p in self.parents(n):
612 heads.pop(p, None)
612 heads.pop(p, None)
613 heads = [n for n in heads.iterkeys() if heads[n] != 0]
613 heads = [n for n in heads.iterkeys() if heads[n] != 0]
614 roots = list(roots)
614 roots = list(roots)
615 assert orderedout
615 assert orderedout
616 assert roots
616 assert roots
617 assert heads
617 assert heads
618 return (orderedout, roots, heads)
618 return (orderedout, roots, heads)
619
619
620 def heads(self, start=None, stop=None):
620 def heads(self, start=None, stop=None):
621 """return the list of all nodes that have no children
621 """return the list of all nodes that have no children
622
622
623 if start is specified, only heads that are descendants of
623 if start is specified, only heads that are descendants of
624 start will be returned
624 start will be returned
625 if stop is specified, it will consider all the revs from stop
625 if stop is specified, it will consider all the revs from stop
626 as if they had no children
626 as if they had no children
627 """
627 """
628 if start is None and stop is None:
628 if start is None and stop is None:
629 count = len(self)
629 count = len(self)
630 if not count:
630 if not count:
631 return [nullid]
631 return [nullid]
632 ishead = [1] * (count + 1)
632 ishead = [1] * (count + 1)
633 index = self.index
633 index = self.index
634 for r in xrange(count):
634 for r in xrange(count):
635 e = index[r]
635 e = index[r]
636 ishead[e[5]] = ishead[e[6]] = 0
636 ishead[e[5]] = ishead[e[6]] = 0
637 return [self.node(r) for r in xrange(count) if ishead[r]]
637 return [self.node(r) for r in xrange(count) if ishead[r]]
638
638
639 if start is None:
639 if start is None:
640 start = nullid
640 start = nullid
641 if stop is None:
641 if stop is None:
642 stop = []
642 stop = []
643 stoprevs = set([self.rev(n) for n in stop])
643 stoprevs = set([self.rev(n) for n in stop])
644 startrev = self.rev(start)
644 startrev = self.rev(start)
645 reachable = set((startrev,))
645 reachable = set((startrev,))
646 heads = set((startrev,))
646 heads = set((startrev,))
647
647
648 parentrevs = self.parentrevs
648 parentrevs = self.parentrevs
649 for r in xrange(startrev + 1, len(self)):
649 for r in xrange(startrev + 1, len(self)):
650 for p in parentrevs(r):
650 for p in parentrevs(r):
651 if p in reachable:
651 if p in reachable:
652 if r not in stoprevs:
652 if r not in stoprevs:
653 reachable.add(r)
653 reachable.add(r)
654 heads.add(r)
654 heads.add(r)
655 if p in heads and p not in stoprevs:
655 if p in heads and p not in stoprevs:
656 heads.remove(p)
656 heads.remove(p)
657
657
658 return [self.node(r) for r in heads]
658 return [self.node(r) for r in heads]
659
659
660 def children(self, node):
660 def children(self, node):
661 """find the children of a given node"""
661 """find the children of a given node"""
662 c = []
662 c = []
663 p = self.rev(node)
663 p = self.rev(node)
664 for r in range(p + 1, len(self)):
664 for r in range(p + 1, len(self)):
665 prevs = [pr for pr in self.parentrevs(r) if pr != nullrev]
665 prevs = [pr for pr in self.parentrevs(r) if pr != nullrev]
666 if prevs:
666 if prevs:
667 for pr in prevs:
667 for pr in prevs:
668 if pr == p:
668 if pr == p:
669 c.append(self.node(r))
669 c.append(self.node(r))
670 elif p == nullrev:
670 elif p == nullrev:
671 c.append(self.node(r))
671 c.append(self.node(r))
672 return c
672 return c
673
673
674 def descendant(self, start, end):
674 def descendant(self, start, end):
675 if start == nullrev:
675 if start == nullrev:
676 return True
676 return True
677 for i in self.descendants(start):
677 for i in self.descendants(start):
678 if i == end:
678 if i == end:
679 return True
679 return True
680 elif i > end:
680 elif i > end:
681 break
681 break
682 return False
682 return False
683
683
684 def ancestor(self, a, b):
684 def ancestor(self, a, b):
685 """calculate the least common ancestor of nodes a and b"""
685 """calculate the least common ancestor of nodes a and b"""
686
686
687 # fast path, check if it is a descendant
687 # fast path, check if it is a descendant
688 a, b = self.rev(a), self.rev(b)
688 a, b = self.rev(a), self.rev(b)
689 start, end = sorted((a, b))
689 start, end = sorted((a, b))
690 if self.descendant(start, end):
690 if self.descendant(start, end):
691 return self.node(start)
691 return self.node(start)
692
692
693 def parents(rev):
693 def parents(rev):
694 return [p for p in self.parentrevs(rev) if p != nullrev]
694 return [p for p in self.parentrevs(rev) if p != nullrev]
695
695
696 c = ancestor.ancestor(a, b, parents)
696 c = ancestor.ancestor(a, b, parents)
697 if c is None:
697 if c is None:
698 return nullid
698 return nullid
699
699
700 return self.node(c)
700 return self.node(c)
701
701
702 def _match(self, id):
702 def _match(self, id):
703 if isinstance(id, (long, int)):
703 if isinstance(id, (long, int)):
704 # rev
704 # rev
705 return self.node(id)
705 return self.node(id)
706 if len(id) == 20:
706 if len(id) == 20:
707 # possibly a binary node
707 # possibly a binary node
708 # odds of a binary node being all hex in ASCII are 1 in 10**25
708 # odds of a binary node being all hex in ASCII are 1 in 10**25
709 try:
709 try:
710 node = id
710 node = id
711 self.rev(node) # quick search the index
711 self.rev(node) # quick search the index
712 return node
712 return node
713 except LookupError:
713 except LookupError:
714 pass # may be partial hex id
714 pass # may be partial hex id
715 try:
715 try:
716 # str(rev)
716 # str(rev)
717 rev = int(id)
717 rev = int(id)
718 if str(rev) != id:
718 if str(rev) != id:
719 raise ValueError
719 raise ValueError
720 if rev < 0:
720 if rev < 0:
721 rev = len(self) + rev
721 rev = len(self) + rev
722 if rev < 0 or rev >= len(self):
722 if rev < 0 or rev >= len(self):
723 raise ValueError
723 raise ValueError
724 return self.node(rev)
724 return self.node(rev)
725 except (ValueError, OverflowError):
725 except (ValueError, OverflowError):
726 pass
726 pass
727 if len(id) == 40:
727 if len(id) == 40:
728 try:
728 try:
729 # a full hex nodeid?
729 # a full hex nodeid?
730 node = bin(id)
730 node = bin(id)
731 self.rev(node)
731 self.rev(node)
732 return node
732 return node
733 except (TypeError, LookupError):
733 except (TypeError, LookupError):
734 pass
734 pass
735
735
736 def _partialmatch(self, id):
736 def _partialmatch(self, id):
737 if id in self._pcache:
737 if id in self._pcache:
738 return self._pcache[id]
738 return self._pcache[id]
739
739
740 if len(id) < 40:
740 if len(id) < 40:
741 try:
741 try:
742 # hex(node)[:...]
742 # hex(node)[:...]
743 l = len(id) // 2 # grab an even number of digits
743 l = len(id) // 2 # grab an even number of digits
744 prefix = bin(id[:l * 2])
744 prefix = bin(id[:l * 2])
745 nl = [e[7] for e in self.index if e[7].startswith(prefix)]
745 nl = [e[7] for e in self.index if e[7].startswith(prefix)]
746 nl = [n for n in nl if hex(n).startswith(id)]
746 nl = [n for n in nl if hex(n).startswith(id)]
747 if len(nl) > 0:
747 if len(nl) > 0:
748 if len(nl) == 1:
748 if len(nl) == 1:
749 self._pcache[id] = nl[0]
749 self._pcache[id] = nl[0]
750 return nl[0]
750 return nl[0]
751 raise LookupError(id, self.indexfile,
751 raise LookupError(id, self.indexfile,
752 _('ambiguous identifier'))
752 _('ambiguous identifier'))
753 return None
753 return None
754 except TypeError:
754 except TypeError:
755 pass
755 pass
756
756
757 def lookup(self, id):
757 def lookup(self, id):
758 """locate a node based on:
758 """locate a node based on:
759 - revision number or str(revision number)
759 - revision number or str(revision number)
760 - nodeid or subset of hex nodeid
760 - nodeid or subset of hex nodeid
761 """
761 """
762 n = self._match(id)
762 n = self._match(id)
763 if n is not None:
763 if n is not None:
764 return n
764 return n
765 n = self._partialmatch(id)
765 n = self._partialmatch(id)
766 if n:
766 if n:
767 return n
767 return n
768
768
769 raise LookupError(id, self.indexfile, _('no match found'))
769 raise LookupError(id, self.indexfile, _('no match found'))
770
770
771 def cmp(self, node, text):
771 def cmp(self, node, text):
772 """compare text with a given file revision
772 """compare text with a given file revision
773
773
774 returns True if text is different than what is stored.
774 returns True if text is different than what is stored.
775 """
775 """
776 p1, p2 = self.parents(node)
776 p1, p2 = self.parents(node)
777 return hash(text, p1, p2) != node
777 return hash(text, p1, p2) != node
778
778
779 def _addchunk(self, offset, data):
779 def _addchunk(self, offset, data):
780 o, d = self._chunkcache
780 o, d = self._chunkcache
781 # try to add to existing cache
781 # try to add to existing cache
782 if o + len(d) == offset and len(d) + len(data) < _chunksize:
782 if o + len(d) == offset and len(d) + len(data) < _chunksize:
783 self._chunkcache = o, d + data
783 self._chunkcache = o, d + data
784 else:
784 else:
785 self._chunkcache = offset, data
785 self._chunkcache = offset, data
786
786
787 def _loadchunk(self, offset, length):
787 def _loadchunk(self, offset, length):
788 if self._inline:
788 if self._inline:
789 df = self.opener(self.indexfile)
789 df = self.opener(self.indexfile)
790 else:
790 else:
791 df = self.opener(self.datafile)
791 df = self.opener(self.datafile)
792
792
793 readahead = max(65536, length)
793 readahead = max(65536, length)
794 df.seek(offset)
794 df.seek(offset)
795 d = df.read(readahead)
795 d = df.read(readahead)
796 self._addchunk(offset, d)
796 self._addchunk(offset, d)
797 if readahead > length:
797 if readahead > length:
798 return d[:length]
798 return d[:length]
799 return d
799 return d
800
800
801 def _getchunk(self, offset, length):
801 def _getchunk(self, offset, length):
802 o, d = self._chunkcache
802 o, d = self._chunkcache
803 l = len(d)
803 l = len(d)
804
804
805 # is it in the cache?
805 # is it in the cache?
806 cachestart = offset - o
806 cachestart = offset - o
807 cacheend = cachestart + length
807 cacheend = cachestart + length
808 if cachestart >= 0 and cacheend <= l:
808 if cachestart >= 0 and cacheend <= l:
809 if cachestart == 0 and cacheend == l:
809 if cachestart == 0 and cacheend == l:
810 return d # avoid a copy
810 return d # avoid a copy
811 return d[cachestart:cacheend]
811 return d[cachestart:cacheend]
812
812
813 return self._loadchunk(offset, length)
813 return self._loadchunk(offset, length)
814
814
815 def _chunkraw(self, startrev, endrev):
815 def _chunkraw(self, startrev, endrev):
816 start = self.start(startrev)
816 start = self.start(startrev)
817 length = self.end(endrev) - start
817 length = self.end(endrev) - start
818 if self._inline:
818 if self._inline:
819 start += (startrev + 1) * self._io.size
819 start += (startrev + 1) * self._io.size
820 return self._getchunk(start, length)
820 return self._getchunk(start, length)
821
821
822 def _chunk(self, rev):
822 def _chunk(self, rev):
823 return decompress(self._chunkraw(rev, rev))
823 return decompress(self._chunkraw(rev, rev))
824
824
825 def _chunkbase(self, rev):
825 def _chunkbase(self, rev):
826 return self._chunk(rev)
826 return self._chunk(rev)
827
827
828 def _chunkclear(self):
828 def _chunkclear(self):
829 self._chunkcache = (0, '')
829 self._chunkcache = (0, '')
830
830
831 def deltaparent(self, rev):
831 def deltaparent(self, rev):
832 """return previous revision or parentrev according to flags"""
832 """return previous revision or parentrev according to flags"""
833 if self.flags(rev) & REVIDX_PARENTDELTA:
833 if self.flags(rev) & REVIDX_PARENTDELTA:
834 return self.parentrevs(rev)[0]
834 return self.parentrevs(rev)[0]
835 else:
835 else:
836 return rev - 1
836 return rev - 1
837
837
838 def revdiff(self, rev1, rev2):
838 def revdiff(self, rev1, rev2):
839 """return or calculate a delta between two revisions"""
839 """return or calculate a delta between two revisions"""
840 if self.base(rev2) != rev2 and self.deltaparent(rev2) == rev1:
840 if self.base(rev2) != rev2 and self.deltaparent(rev2) == rev1:
841 return self._chunk(rev2)
841 return self._chunk(rev2)
842
842
843 return mdiff.textdiff(self.revision(self.node(rev1)),
843 return mdiff.textdiff(self.revision(self.node(rev1)),
844 self.revision(self.node(rev2)))
844 self.revision(self.node(rev2)))
845
845
846 def revision(self, node):
846 def revision(self, node):
847 """return an uncompressed revision of a given node"""
847 """return an uncompressed revision of a given node"""
848 cachedrev = None
848 cachedrev = None
849 if node == nullid:
849 if node == nullid:
850 return ""
850 return ""
851 if self._cache:
851 if self._cache:
852 if self._cache[0] == node:
852 if self._cache[0] == node:
853 return self._cache[2]
853 return self._cache[2]
854 cachedrev = self._cache[1]
854 cachedrev = self._cache[1]
855
855
856 # look up what we need to read
856 # look up what we need to read
857 text = None
857 text = None
858 rev = self.rev(node)
858 rev = self.rev(node)
859 base = self.base(rev)
859 base = self.base(rev)
860
860
861 # check rev flags
861 # check rev flags
862 if self.flags(rev) & ~REVIDX_KNOWN_FLAGS:
862 if self.flags(rev) & ~REVIDX_KNOWN_FLAGS:
863 raise RevlogError(_('incompatible revision flag %x') %
863 raise RevlogError(_('incompatible revision flag %x') %
864 (self.flags(rev) & ~REVIDX_KNOWN_FLAGS))
864 (self.flags(rev) & ~REVIDX_KNOWN_FLAGS))
865
865
866 # build delta chain
866 # build delta chain
867 chain = []
867 chain = []
868 index = self.index # for performance
868 index = self.index # for performance
869 iterrev = rev
869 iterrev = rev
870 e = index[iterrev]
870 e = index[iterrev]
871 while iterrev != base and iterrev != cachedrev:
871 while iterrev != base and iterrev != cachedrev:
872 chain.append(iterrev)
872 chain.append(iterrev)
873 if e[0] & REVIDX_PARENTDELTA:
873 if e[0] & REVIDX_PARENTDELTA:
874 iterrev = e[5]
874 iterrev = e[5]
875 else:
875 else:
876 iterrev -= 1
876 iterrev -= 1
877 e = index[iterrev]
877 e = index[iterrev]
878 chain.reverse()
878 chain.reverse()
879 base = iterrev
879 base = iterrev
880
880
881 if iterrev == cachedrev:
881 if iterrev == cachedrev:
882 # cache hit
882 # cache hit
883 text = self._cache[2]
883 text = self._cache[2]
884
884
885 # drop cache to save memory
885 # drop cache to save memory
886 self._cache = None
886 self._cache = None
887
887
888 self._chunkraw(base, rev)
888 self._chunkraw(base, rev)
889 if text is None:
889 if text is None:
890 text = self._chunkbase(base)
890 text = self._chunkbase(base)
891
891
892 bins = [self._chunk(r) for r in chain]
892 bins = [self._chunk(r) for r in chain]
893 text = mdiff.patches(text, bins)
893 text = mdiff.patches(text, bins)
894
894
895 text = self._checkhash(text, node, rev)
895 text = self._checkhash(text, node, rev)
896
896
897 self._cache = (node, rev, text)
897 self._cache = (node, rev, text)
898 return text
898 return text
899
899
900 def _checkhash(self, text, node, rev):
900 def _checkhash(self, text, node, rev):
901 p1, p2 = self.parents(node)
901 p1, p2 = self.parents(node)
902 if (node != hash(text, p1, p2) and
902 if (node != hash(text, p1, p2) and
903 not (self.flags(rev) & REVIDX_PUNCHED_FLAG)):
903 not (self.flags(rev) & REVIDX_PUNCHED_FLAG)):
904 raise RevlogError(_("integrity check failed on %s:%d")
904 raise RevlogError(_("integrity check failed on %s:%d")
905 % (self.indexfile, rev))
905 % (self.indexfile, rev))
906 return text
906 return text
907
907
908 def checkinlinesize(self, tr, fp=None):
908 def checkinlinesize(self, tr, fp=None):
909 if not self._inline or (self.start(-2) + self.length(-2)) < _maxinline:
909 if not self._inline or (self.start(-2) + self.length(-2)) < _maxinline:
910 return
910 return
911
911
912 trinfo = tr.find(self.indexfile)
912 trinfo = tr.find(self.indexfile)
913 if trinfo is None:
913 if trinfo is None:
914 raise RevlogError(_("%s not found in the transaction")
914 raise RevlogError(_("%s not found in the transaction")
915 % self.indexfile)
915 % self.indexfile)
916
916
917 trindex = trinfo[2]
917 trindex = trinfo[2]
918 dataoff = self.start(trindex)
918 dataoff = self.start(trindex)
919
919
920 tr.add(self.datafile, dataoff)
920 tr.add(self.datafile, dataoff)
921
921
922 if fp:
922 if fp:
923 fp.flush()
923 fp.flush()
924 fp.close()
924 fp.close()
925
925
926 df = self.opener(self.datafile, 'w')
926 df = self.opener(self.datafile, 'w')
927 try:
927 try:
928 for r in self:
928 for r in self:
929 df.write(self._chunkraw(r, r))
929 df.write(self._chunkraw(r, r))
930 finally:
930 finally:
931 df.close()
931 df.close()
932
932
933 fp = self.opener(self.indexfile, 'w', atomictemp=True)
933 fp = self.opener(self.indexfile, 'w', atomictemp=True)
934 self.version &= ~(REVLOGNGINLINEDATA)
934 self.version &= ~(REVLOGNGINLINEDATA)
935 self._inline = False
935 self._inline = False
936 for i in self:
936 for i in self:
937 e = self._io.packentry(self.index[i], self.node, self.version, i)
937 e = self._io.packentry(self.index[i], self.node, self.version, i)
938 fp.write(e)
938 fp.write(e)
939
939
940 # if we don't call rename, the temp file will never replace the
940 # if we don't call rename, the temp file will never replace the
941 # real index
941 # real index
942 fp.rename()
942 fp.rename()
943
943
944 tr.replace(self.indexfile, trindex * self._io.size)
944 tr.replace(self.indexfile, trindex * self._io.size)
945 self._chunkclear()
945 self._chunkclear()
946
946
947 def addrevision(self, text, transaction, link, p1, p2, cachedelta=None):
947 def addrevision(self, text, transaction, link, p1, p2, cachedelta=None):
948 """add a revision to the log
948 """add a revision to the log
949
949
950 text - the revision data to add
950 text - the revision data to add
951 transaction - the transaction object used for rollback
951 transaction - the transaction object used for rollback
952 link - the linkrev data to add
952 link - the linkrev data to add
953 p1, p2 - the parent nodeids of the revision
953 p1, p2 - the parent nodeids of the revision
954 cachedelta - an optional precomputed delta
954 cachedelta - an optional precomputed delta
955 """
955 """
956 node = hash(text, p1, p2)
956 node = hash(text, p1, p2)
957 if (node in self.nodemap and
957 if (node in self.nodemap and
958 (not self.flags(self.rev(node)) & REVIDX_PUNCHED_FLAG)):
958 (not self.flags(self.rev(node)) & REVIDX_PUNCHED_FLAG)):
959 return node
959 return node
960
960
961 dfh = None
961 dfh = None
962 if not self._inline:
962 if not self._inline:
963 dfh = self.opener(self.datafile, "a")
963 dfh = self.opener(self.datafile, "a")
964 ifh = self.opener(self.indexfile, "a+")
964 ifh = self.opener(self.indexfile, "a+")
965 try:
965 try:
966 return self._addrevision(node, text, transaction, link, p1, p2,
966 return self._addrevision(node, text, transaction, link, p1, p2,
967 cachedelta, ifh, dfh)
967 cachedelta, ifh, dfh)
968 finally:
968 finally:
969 if dfh:
969 if dfh:
970 dfh.close()
970 dfh.close()
971 ifh.close()
971 ifh.close()
972
972
973 def _addrevision(self, node, text, transaction, link, p1, p2,
973 def _addrevision(self, node, text, transaction, link, p1, p2,
974 cachedelta, ifh, dfh):
974 cachedelta, ifh, dfh):
975
975
976 btext = [text]
976 btext = [text]
977 def buildtext():
977 def buildtext():
978 if btext[0] is not None:
978 if btext[0] is not None:
979 return btext[0]
979 return btext[0]
980 # flush any pending writes here so we can read it in revision
980 # flush any pending writes here so we can read it in revision
981 if dfh:
981 if dfh:
982 dfh.flush()
982 dfh.flush()
983 ifh.flush()
983 ifh.flush()
984 basetext = self.revision(self.node(cachedelta[0]))
984 basetext = self.revision(self.node(cachedelta[0]))
985 btext[0] = mdiff.patch(basetext, cachedelta[1])
985 btext[0] = mdiff.patch(basetext, cachedelta[1])
986 chk = hash(btext[0], p1, p2)
986 chk = hash(btext[0], p1, p2)
987 if chk != node:
987 if chk != node:
988 raise RevlogError(_("consistency error in delta"))
988 raise RevlogError(_("consistency error in delta"))
989 return btext[0]
989 return btext[0]
990
990
991 def builddelta(rev):
991 def builddelta(rev):
992 # can we use the cached delta?
992 # can we use the cached delta?
993 if cachedelta and cachedelta[0] == rev:
993 if cachedelta and cachedelta[0] == rev:
994 delta = cachedelta[1]
994 delta = cachedelta[1]
995 else:
995 else:
996 t = buildtext()
996 t = buildtext()
997 ptext = self.revision(self.node(rev))
997 ptext = self.revision(self.node(rev))
998 delta = mdiff.textdiff(ptext, t)
998 delta = mdiff.textdiff(ptext, t)
999 data = compress(delta)
999 data = compress(delta)
1000 l = len(data[1]) + len(data[0])
1000 l = len(data[1]) + len(data[0])
1001 base = self.base(rev)
1001 base = self.base(rev)
1002 dist = l + offset - self.start(base)
1002 dist = l + offset - self.start(base)
1003 return dist, l, data, base
1003 return dist, l, data, base
1004
1004
1005 curr = len(self)
1005 curr = len(self)
1006 prev = curr - 1
1006 prev = curr - 1
1007 base = curr
1007 base = curr
1008 offset = self.end(prev)
1008 offset = self.end(prev)
1009 flags = 0
1009 flags = 0
1010 d = None
1010 d = None
1011 p1r, p2r = self.rev(p1), self.rev(p2)
1011 p1r, p2r = self.rev(p1), self.rev(p2)
1012
1012
1013 # should we try to build a delta?
1013 # should we try to build a delta?
1014 if prev != nullrev:
1014 if prev != nullrev:
1015 d = builddelta(prev)
1015 d = builddelta(prev)
1016 if self._parentdelta and prev != p1r:
1016 if self._parentdelta and prev != p1r:
1017 d2 = builddelta(p1r)
1017 d2 = builddelta(p1r)
1018 if d2 < d:
1018 if d2 < d:
1019 d = d2
1019 d = d2
1020 flags = REVIDX_PARENTDELTA
1020 flags = REVIDX_PARENTDELTA
1021 dist, l, data, base = d
1021 dist, l, data, base = d
1022
1022
1023 # full versions are inserted when the needed deltas
1023 # full versions are inserted when the needed deltas
1024 # become comparable to the uncompressed text
1024 # become comparable to the uncompressed text
1025 # or the base revision is punched
1025 # or the base revision is punched
1026 if text is None:
1026 if text is None:
1027 textlen = mdiff.patchedsize(self.rawsize(cachedelta[0]),
1027 textlen = mdiff.patchedsize(self.rawsize(cachedelta[0]),
1028 cachedelta[1])
1028 cachedelta[1])
1029 else:
1029 else:
1030 textlen = len(text)
1030 textlen = len(text)
1031 if (d is None or dist > textlen * 2 or
1031 if (d is None or dist > textlen * 2 or
1032 (self.flags(base) & REVIDX_PUNCHED_FLAG)):
1032 (self.flags(base) & REVIDX_PUNCHED_FLAG)):
1033 text = buildtext()
1033 text = buildtext()
1034 data = compress(text)
1034 data = compress(text)
1035 l = len(data[1]) + len(data[0])
1035 l = len(data[1]) + len(data[0])
1036 base = curr
1036 base = curr
1037
1037
1038 e = (offset_type(offset, flags), l, textlen,
1038 e = (offset_type(offset, flags), l, textlen,
1039 base, link, p1r, p2r, node)
1039 base, link, p1r, p2r, node)
1040 self.index.insert(-1, e)
1040 self.index.insert(-1, e)
1041 self.nodemap[node] = curr
1041 self.nodemap[node] = curr
1042
1042
1043 entry = self._io.packentry(e, self.node, self.version, curr)
1043 entry = self._io.packentry(e, self.node, self.version, curr)
1044 if not self._inline:
1044 if not self._inline:
1045 transaction.add(self.datafile, offset)
1045 transaction.add(self.datafile, offset)
1046 transaction.add(self.indexfile, curr * len(entry))
1046 transaction.add(self.indexfile, curr * len(entry))
1047 if data[0]:
1047 if data[0]:
1048 dfh.write(data[0])
1048 dfh.write(data[0])
1049 dfh.write(data[1])
1049 dfh.write(data[1])
1050 dfh.flush()
1050 dfh.flush()
1051 ifh.write(entry)
1051 ifh.write(entry)
1052 else:
1052 else:
1053 offset += curr * self._io.size
1053 offset += curr * self._io.size
1054 transaction.add(self.indexfile, offset, curr)
1054 transaction.add(self.indexfile, offset, curr)
1055 ifh.write(entry)
1055 ifh.write(entry)
1056 ifh.write(data[0])
1056 ifh.write(data[0])
1057 ifh.write(data[1])
1057 ifh.write(data[1])
1058 self.checkinlinesize(transaction, ifh)
1058 self.checkinlinesize(transaction, ifh)
1059
1059
1060 if type(text) == str: # only accept immutable objects
1060 if type(text) == str: # only accept immutable objects
1061 self._cache = (node, curr, text)
1061 self._cache = (node, curr, text)
1062 return node
1062 return node
1063
1063
1064 def group(self, nodelist, bundler):
1064 def group(self, nodelist, bundler):
1065 """Calculate a delta group, yielding a sequence of changegroup chunks
1065 """Calculate a delta group, yielding a sequence of changegroup chunks
1066 (strings).
1066 (strings).
1067
1067
1068 Given a list of changeset revs, return a set of deltas and
1068 Given a list of changeset revs, return a set of deltas and
1069 metadata corresponding to nodes. The first delta is
1069 metadata corresponding to nodes. The first delta is
1070 first parent(nodelist[0]) -> nodelist[0], the receiver is
1070 first parent(nodelist[0]) -> nodelist[0], the receiver is
1071 guaranteed to have this parent as it has all history before
1071 guaranteed to have this parent as it has all history before
1072 these changesets. In the case firstparent is nullrev the
1072 these changesets. In the case firstparent is nullrev the
1073 changegroup starts with a full revision.
1073 changegroup starts with a full revision.
1074 """
1074 """
1075
1075
1076 revs = sorted([self.rev(n) for n in nodelist])
1076 revs = sorted([self.rev(n) for n in nodelist])
1077
1077
1078 # if we don't have any revisions touched by these changesets, bail
1078 # if we don't have any revisions touched by these changesets, bail
1079 if not revs:
1079 if not revs:
1080 yield bundler.close()
1080 yield bundler.close()
1081 return
1081 return
1082
1082
1083 # add the parent of the first rev
1083 # add the parent of the first rev
1084 p = self.parentrevs(revs[0])[0]
1084 p = self.parentrevs(revs[0])[0]
1085 revs.insert(0, p)
1085 revs.insert(0, p)
1086
1086
1087 # build deltas
1087 # build deltas
1088 for r in xrange(len(revs) - 1):
1088 for r in xrange(len(revs) - 1):
1089 a, b = revs[r], revs[r + 1]
1089 a, b = revs[r], revs[r + 1]
1090 nb = self.node(b)
1090 nb = self.node(b)
1091 p1, p2 = self.parents(nb)
1091 p1, p2 = self.parents(nb)
1092 prefix = ''
1092 prefix = ''
1093
1093
1094 if a == nullrev:
1094 if a == nullrev:
1095 d = self.revision(nb)
1095 d = self.revision(nb)
1096 prefix = mdiff.trivialdiffheader(len(d))
1096 prefix = mdiff.trivialdiffheader(len(d))
1097 else:
1097 else:
1098 d = self.revdiff(a, b)
1098 d = self.revdiff(a, b)
1099 for c in bundler.revchunk(self, nb, p1, p2, prefix, d):
1099 for c in bundler.revchunk(self, nb, p1, p2, prefix, d):
1100 yield c
1100 yield c
1101
1101
1102 yield bundler.close()
1102 yield bundler.close()
1103
1103
1104 def addgroup(self, bundle, linkmapper, transaction):
1104 def addgroup(self, bundle, linkmapper, transaction):
1105 """
1105 """
1106 add a delta group
1106 add a delta group
1107
1107
1108 given a set of deltas, add them to the revision log. the
1108 given a set of deltas, add them to the revision log. the
1109 first delta is against its parent, which should be in our
1109 first delta is against its parent, which should be in our
1110 log, the rest are against the previous delta.
1110 log, the rest are against the previous delta.
1111 """
1111 """
1112
1112
1113 # track the base of the current delta log
1113 # track the base of the current delta log
1114 node = None
1114 node = None
1115
1115
1116 r = len(self)
1116 r = len(self)
1117 end = 0
1117 end = 0
1118 if r:
1118 if r:
1119 end = self.end(r - 1)
1119 end = self.end(r - 1)
1120 ifh = self.opener(self.indexfile, "a+")
1120 ifh = self.opener(self.indexfile, "a+")
1121 isize = r * self._io.size
1121 isize = r * self._io.size
1122 if self._inline:
1122 if self._inline:
1123 transaction.add(self.indexfile, end + isize, r)
1123 transaction.add(self.indexfile, end + isize, r)
1124 dfh = None
1124 dfh = None
1125 else:
1125 else:
1126 transaction.add(self.indexfile, isize, r)
1126 transaction.add(self.indexfile, isize, r)
1127 transaction.add(self.datafile, end)
1127 transaction.add(self.datafile, end)
1128 dfh = self.opener(self.datafile, "a")
1128 dfh = self.opener(self.datafile, "a")
1129
1129
1130 try:
1130 try:
1131 # loop through our set of deltas
1131 # loop through our set of deltas
1132 chain = None
1132 chain = None
1133 while 1:
1133 while 1:
1134 chunkdata = bundle.parsechunk()
1134 chunkdata = bundle.parsechunk(chain)
1135 if not chunkdata:
1135 if not chunkdata:
1136 break
1136 break
1137 node = chunkdata['node']
1137 node = chunkdata['node']
1138 p1 = chunkdata['p1']
1138 p1 = chunkdata['p1']
1139 p2 = chunkdata['p2']
1139 p2 = chunkdata['p2']
1140 cs = chunkdata['cs']
1140 cs = chunkdata['cs']
1141 delta = chunkdata['data']
1141 deltabase = chunkdata['deltabase']
1142 delta = chunkdata['delta']
1142
1143
1143 link = linkmapper(cs)
1144 link = linkmapper(cs)
1144 if (node in self.nodemap and
1145 if (node in self.nodemap and
1145 (not self.flags(self.rev(node)) & REVIDX_PUNCHED_FLAG)):
1146 (not self.flags(self.rev(node)) & REVIDX_PUNCHED_FLAG)):
1146 # this can happen if two branches make the same change
1147 # this can happen if two branches make the same change
1147 chain = node
1148 chain = node
1148 continue
1149 continue
1149
1150
1150 for p in (p1, p2):
1151 for p in (p1, p2):
1151 if not p in self.nodemap:
1152 if not p in self.nodemap:
1152 if self._shallow:
1153 if self._shallow:
1153 # add null entries for missing parents
1154 # add null entries for missing parents
1154 # XXX FIXME
1155 # XXX FIXME
1155 #if base == nullrev:
1156 #if base == nullrev:
1156 # base = len(self)
1157 # base = len(self)
1157 #e = (offset_type(end, REVIDX_PUNCHED_FLAG),
1158 #e = (offset_type(end, REVIDX_PUNCHED_FLAG),
1158 # 0, 0, base, nullrev, nullrev, nullrev, p)
1159 # 0, 0, base, nullrev, nullrev, nullrev, p)
1159 #self.index.insert(-1, e)
1160 #self.index.insert(-1, e)
1160 #self.nodemap[p] = r
1161 #self.nodemap[p] = r
1161 #entry = self._io.packentry(e, self.node,
1162 #entry = self._io.packentry(e, self.node,
1162 # self.version, r)
1163 # self.version, r)
1163 #ifh.write(entry)
1164 #ifh.write(entry)
1164 #t, r = r, r + 1
1165 #t, r = r, r + 1
1165 raise LookupError(p, self.indexfile,
1166 raise LookupError(p, self.indexfile,
1166 _('unknown parent'))
1167 _('unknown parent'))
1167 else:
1168 else:
1168 raise LookupError(p, self.indexfile,
1169 raise LookupError(p, self.indexfile,
1169 _('unknown parent'))
1170 _('unknown parent'))
1170
1171
1171 if not chain:
1172 if deltabase not in self.nodemap:
1172 # retrieve the parent revision of the delta chain
1173 raise LookupError(deltabase, self.indexfile,
1173 chain = p1
1174 _('unknown delta base'))
1174 if not chain in self.nodemap:
1175 raise LookupError(chain, self.indexfile, _('unknown base'))
1176
1175
1177 chainrev = self.rev(chain)
1176 baserev = self.rev(deltabase)
1178 chain = self._addrevision(node, None, transaction, link,
1177 chain = self._addrevision(node, None, transaction, link,
1179 p1, p2, (chainrev, delta), ifh, dfh)
1178 p1, p2, (baserev, delta), ifh, dfh)
1180 if not dfh and not self._inline:
1179 if not dfh and not self._inline:
1181 # addrevision switched from inline to conventional
1180 # addrevision switched from inline to conventional
1182 # reopen the index
1181 # reopen the index
1183 ifh.close()
1182 ifh.close()
1184 dfh = self.opener(self.datafile, "a")
1183 dfh = self.opener(self.datafile, "a")
1185 ifh = self.opener(self.indexfile, "a")
1184 ifh = self.opener(self.indexfile, "a")
1186 finally:
1185 finally:
1187 if dfh:
1186 if dfh:
1188 dfh.close()
1187 dfh.close()
1189 ifh.close()
1188 ifh.close()
1190
1189
1191 return node
1190 return node
1192
1191
1193 def strip(self, minlink, transaction):
1192 def strip(self, minlink, transaction):
1194 """truncate the revlog on the first revision with a linkrev >= minlink
1193 """truncate the revlog on the first revision with a linkrev >= minlink
1195
1194
1196 This function is called when we're stripping revision minlink and
1195 This function is called when we're stripping revision minlink and
1197 its descendants from the repository.
1196 its descendants from the repository.
1198
1197
1199 We have to remove all revisions with linkrev >= minlink, because
1198 We have to remove all revisions with linkrev >= minlink, because
1200 the equivalent changelog revisions will be renumbered after the
1199 the equivalent changelog revisions will be renumbered after the
1201 strip.
1200 strip.
1202
1201
1203 So we truncate the revlog on the first of these revisions, and
1202 So we truncate the revlog on the first of these revisions, and
1204 trust that the caller has saved the revisions that shouldn't be
1203 trust that the caller has saved the revisions that shouldn't be
1205 removed and that it'll readd them after this truncation.
1204 removed and that it'll readd them after this truncation.
1206 """
1205 """
1207 if len(self) == 0:
1206 if len(self) == 0:
1208 return
1207 return
1209
1208
1210 for rev in self:
1209 for rev in self:
1211 if self.index[rev][4] >= minlink:
1210 if self.index[rev][4] >= minlink:
1212 break
1211 break
1213 else:
1212 else:
1214 return
1213 return
1215
1214
1216 # first truncate the files on disk
1215 # first truncate the files on disk
1217 end = self.start(rev)
1216 end = self.start(rev)
1218 if not self._inline:
1217 if not self._inline:
1219 transaction.add(self.datafile, end)
1218 transaction.add(self.datafile, end)
1220 end = rev * self._io.size
1219 end = rev * self._io.size
1221 else:
1220 else:
1222 end += rev * self._io.size
1221 end += rev * self._io.size
1223
1222
1224 transaction.add(self.indexfile, end)
1223 transaction.add(self.indexfile, end)
1225
1224
1226 # then reset internal state in memory to forget those revisions
1225 # then reset internal state in memory to forget those revisions
1227 self._cache = None
1226 self._cache = None
1228 self._chunkclear()
1227 self._chunkclear()
1229 for x in xrange(rev, len(self)):
1228 for x in xrange(rev, len(self)):
1230 del self.nodemap[self.node(x)]
1229 del self.nodemap[self.node(x)]
1231
1230
1232 del self.index[rev:-1]
1231 del self.index[rev:-1]
1233
1232
1234 def checksize(self):
1233 def checksize(self):
1235 expected = 0
1234 expected = 0
1236 if len(self):
1235 if len(self):
1237 expected = max(0, self.end(len(self) - 1))
1236 expected = max(0, self.end(len(self) - 1))
1238
1237
1239 try:
1238 try:
1240 f = self.opener(self.datafile)
1239 f = self.opener(self.datafile)
1241 f.seek(0, 2)
1240 f.seek(0, 2)
1242 actual = f.tell()
1241 actual = f.tell()
1243 f.close()
1242 f.close()
1244 dd = actual - expected
1243 dd = actual - expected
1245 except IOError, inst:
1244 except IOError, inst:
1246 if inst.errno != errno.ENOENT:
1245 if inst.errno != errno.ENOENT:
1247 raise
1246 raise
1248 dd = 0
1247 dd = 0
1249
1248
1250 try:
1249 try:
1251 f = self.opener(self.indexfile)
1250 f = self.opener(self.indexfile)
1252 f.seek(0, 2)
1251 f.seek(0, 2)
1253 actual = f.tell()
1252 actual = f.tell()
1254 f.close()
1253 f.close()
1255 s = self._io.size
1254 s = self._io.size
1256 i = max(0, actual // s)
1255 i = max(0, actual // s)
1257 di = actual - (i * s)
1256 di = actual - (i * s)
1258 if self._inline:
1257 if self._inline:
1259 databytes = 0
1258 databytes = 0
1260 for r in self:
1259 for r in self:
1261 databytes += max(0, self.length(r))
1260 databytes += max(0, self.length(r))
1262 dd = 0
1261 dd = 0
1263 di = actual - len(self) * s - databytes
1262 di = actual - len(self) * s - databytes
1264 except IOError, inst:
1263 except IOError, inst:
1265 if inst.errno != errno.ENOENT:
1264 if inst.errno != errno.ENOENT:
1266 raise
1265 raise
1267 di = 0
1266 di = 0
1268
1267
1269 return (dd, di)
1268 return (dd, di)
1270
1269
1271 def files(self):
1270 def files(self):
1272 res = [self.indexfile]
1271 res = [self.indexfile]
1273 if not self._inline:
1272 if not self._inline:
1274 res.append(self.datafile)
1273 res.append(self.datafile)
1275 return res
1274 return res
@@ -1,36 +1,36 b''
1
1
2 Create a test repository:
2 Create a test repository:
3
3
4 $ hg init repo
4 $ hg init repo
5 $ cd repo
5 $ cd repo
6 $ touch a ; hg add a ; hg ci -ma
6 $ touch a ; hg add a ; hg ci -ma
7 $ touch b ; hg add b ; hg ci -mb
7 $ touch b ; hg add b ; hg ci -mb
8 $ touch c ; hg add c ; hg ci -mc
8 $ touch c ; hg add c ; hg ci -mc
9 $ hg bundle --base 0 --rev tip bundle.hg
9 $ hg bundle --base 0 --rev tip bundle.hg
10 2 changesets found
10 2 changesets found
11
11
12 Terse output:
12 Terse output:
13
13
14 $ hg debugbundle bundle.hg
14 $ hg debugbundle bundle.hg
15 0e067c57feba1a5694ca4844f05588bb1bf82342
15 0e067c57feba1a5694ca4844f05588bb1bf82342
16 991a3460af53952d10ec8a295d3d2cc2e5fa9690
16 991a3460af53952d10ec8a295d3d2cc2e5fa9690
17
17
18 Verbose output:
18 Verbose output:
19
19
20 $ hg debugbundle --all bundle.hg
20 $ hg debugbundle --all bundle.hg
21 format: id, p1, p2, cset, len(delta)
21 format: id, p1, p2, cset, delta base, len(delta)
22
22
23 changelog
23 changelog
24 0e067c57feba1a5694ca4844f05588bb1bf82342 3903775176ed42b1458a6281db4a0ccf4d9f287a 0000000000000000000000000000000000000000 0e067c57feba1a5694ca4844f05588bb1bf82342 80
24 0e067c57feba1a5694ca4844f05588bb1bf82342 3903775176ed42b1458a6281db4a0ccf4d9f287a 0000000000000000000000000000000000000000 0e067c57feba1a5694ca4844f05588bb1bf82342 3903775176ed42b1458a6281db4a0ccf4d9f287a 80
25 991a3460af53952d10ec8a295d3d2cc2e5fa9690 0e067c57feba1a5694ca4844f05588bb1bf82342 0000000000000000000000000000000000000000 991a3460af53952d10ec8a295d3d2cc2e5fa9690 80
25 991a3460af53952d10ec8a295d3d2cc2e5fa9690 0e067c57feba1a5694ca4844f05588bb1bf82342 0000000000000000000000000000000000000000 991a3460af53952d10ec8a295d3d2cc2e5fa9690 0e067c57feba1a5694ca4844f05588bb1bf82342 80
26
26
27 manifest
27 manifest
28 686dbf0aeca417636fa26a9121c681eabbb15a20 8515d4bfda768e04af4c13a69a72e28c7effbea7 0000000000000000000000000000000000000000 0e067c57feba1a5694ca4844f05588bb1bf82342 55
28 686dbf0aeca417636fa26a9121c681eabbb15a20 8515d4bfda768e04af4c13a69a72e28c7effbea7 0000000000000000000000000000000000000000 0e067c57feba1a5694ca4844f05588bb1bf82342 8515d4bfda768e04af4c13a69a72e28c7effbea7 55
29 ae25a31b30b3490a981e7b96a3238cc69583fda1 686dbf0aeca417636fa26a9121c681eabbb15a20 0000000000000000000000000000000000000000 991a3460af53952d10ec8a295d3d2cc2e5fa9690 55
29 ae25a31b30b3490a981e7b96a3238cc69583fda1 686dbf0aeca417636fa26a9121c681eabbb15a20 0000000000000000000000000000000000000000 991a3460af53952d10ec8a295d3d2cc2e5fa9690 686dbf0aeca417636fa26a9121c681eabbb15a20 55
30
30
31 b
31 b
32 b80de5d138758541c5f05265ad144ab9fa86d1db 0000000000000000000000000000000000000000 0000000000000000000000000000000000000000 0e067c57feba1a5694ca4844f05588bb1bf82342 12
32 b80de5d138758541c5f05265ad144ab9fa86d1db 0000000000000000000000000000000000000000 0000000000000000000000000000000000000000 0e067c57feba1a5694ca4844f05588bb1bf82342 0000000000000000000000000000000000000000 12
33
33
34 c
34 c
35 b80de5d138758541c5f05265ad144ab9fa86d1db 0000000000000000000000000000000000000000 0000000000000000000000000000000000000000 991a3460af53952d10ec8a295d3d2cc2e5fa9690 12
35 b80de5d138758541c5f05265ad144ab9fa86d1db 0000000000000000000000000000000000000000 0000000000000000000000000000000000000000 991a3460af53952d10ec8a295d3d2cc2e5fa9690 0000000000000000000000000000000000000000 12
36
36
@@ -1,253 +1,253 b''
1
1
2 = Test the getbundle() protocol function =
2 = Test the getbundle() protocol function =
3
3
4 Enable graphlog extension:
4 Enable graphlog extension:
5
5
6 $ echo "[extensions]" >> $HGRCPATH
6 $ echo "[extensions]" >> $HGRCPATH
7 $ echo "graphlog=" >> $HGRCPATH
7 $ echo "graphlog=" >> $HGRCPATH
8
8
9 Create a test repository:
9 Create a test repository:
10
10
11 $ hg init repo
11 $ hg init repo
12 $ cd repo
12 $ cd repo
13 $ hg debugbuilddag -n -m '+2 :fork +5 :p1 *fork +6 :p2 /p1 :m1 +3' > /dev/null
13 $ hg debugbuilddag -n -m '+2 :fork +5 :p1 *fork +6 :p2 /p1 :m1 +3' > /dev/null
14 $ hg glog --template '{node}\n'
14 $ hg glog --template '{node}\n'
15 @ 2bba2f40f321484159b395a43f20101d4bb7ead0
15 @ 2bba2f40f321484159b395a43f20101d4bb7ead0
16 |
16 |
17 o d9e5488323c782fe684573f3043369d199038b6f
17 o d9e5488323c782fe684573f3043369d199038b6f
18 |
18 |
19 o 6e9a5adf5437e49c746288cf95c5ac34fa8f2f72
19 o 6e9a5adf5437e49c746288cf95c5ac34fa8f2f72
20 |
20 |
21 o 733bf0910832b26b768a09172f325f995b5476e1
21 o 733bf0910832b26b768a09172f325f995b5476e1
22 |\
22 |\
23 | o b5af5d6ea56d73ce24c40bc3cd19a862f74888ac
23 | o b5af5d6ea56d73ce24c40bc3cd19a862f74888ac
24 | |
24 | |
25 | o 6b57ee934bb2996050540f84cdfc8dcad1e7267d
25 | o 6b57ee934bb2996050540f84cdfc8dcad1e7267d
26 | |
26 | |
27 | o 2c0ec49482e8abe888b7bd090b5827acfc22b3d7
27 | o 2c0ec49482e8abe888b7bd090b5827acfc22b3d7
28 | |
28 | |
29 | o c1818a9f5977dd4139a48f93f5425c67d44a9368
29 | o c1818a9f5977dd4139a48f93f5425c67d44a9368
30 | |
30 | |
31 | o 6c725a58ad10aea441540bfd06c507f63e8b9cdd
31 | o 6c725a58ad10aea441540bfd06c507f63e8b9cdd
32 | |
32 | |
33 | o 18063366a155bd56b5618229ae2ac3e91849aa5e
33 | o 18063366a155bd56b5618229ae2ac3e91849aa5e
34 | |
34 | |
35 | o a21d913c992197a2eb60b298521ec0f045a04799
35 | o a21d913c992197a2eb60b298521ec0f045a04799
36 | |
36 | |
37 o | b6b2b682253df2ffedc10e9415e4114202b303c5
37 o | b6b2b682253df2ffedc10e9415e4114202b303c5
38 | |
38 | |
39 o | 2114148793524fd045998f71a45b0aaf139f752b
39 o | 2114148793524fd045998f71a45b0aaf139f752b
40 | |
40 | |
41 o | 74a573f2ae100f1cedfad9aa7b96f8eaab1dabfc
41 o | 74a573f2ae100f1cedfad9aa7b96f8eaab1dabfc
42 | |
42 | |
43 o | ea919464b16e003894c48b6cb68df3cd9411b544
43 o | ea919464b16e003894c48b6cb68df3cd9411b544
44 | |
44 | |
45 o | 0f82d97ec2778746743fbc996740d409558fda22
45 o | 0f82d97ec2778746743fbc996740d409558fda22
46 |/
46 |/
47 o 6e23b016bc0f0e79c7bd9dd372ccee07055d7fd4
47 o 6e23b016bc0f0e79c7bd9dd372ccee07055d7fd4
48 |
48 |
49 o 10e64d654571f11577745b4d8372e859d9e4df63
49 o 10e64d654571f11577745b4d8372e859d9e4df63
50
50
51 $ cd ..
51 $ cd ..
52
52
53
53
54 = Test locally =
54 = Test locally =
55
55
56 Get everything:
56 Get everything:
57
57
58 $ hg debuggetbundle repo bundle
58 $ hg debuggetbundle repo bundle
59 $ hg debugbundle bundle
59 $ hg debugbundle bundle
60 10e64d654571f11577745b4d8372e859d9e4df63
60 10e64d654571f11577745b4d8372e859d9e4df63
61 6e23b016bc0f0e79c7bd9dd372ccee07055d7fd4
61 6e23b016bc0f0e79c7bd9dd372ccee07055d7fd4
62 0f82d97ec2778746743fbc996740d409558fda22
62 0f82d97ec2778746743fbc996740d409558fda22
63 ea919464b16e003894c48b6cb68df3cd9411b544
63 ea919464b16e003894c48b6cb68df3cd9411b544
64 74a573f2ae100f1cedfad9aa7b96f8eaab1dabfc
64 74a573f2ae100f1cedfad9aa7b96f8eaab1dabfc
65 2114148793524fd045998f71a45b0aaf139f752b
65 2114148793524fd045998f71a45b0aaf139f752b
66 b6b2b682253df2ffedc10e9415e4114202b303c5
66 b6b2b682253df2ffedc10e9415e4114202b303c5
67 a21d913c992197a2eb60b298521ec0f045a04799
67 a21d913c992197a2eb60b298521ec0f045a04799
68 18063366a155bd56b5618229ae2ac3e91849aa5e
68 18063366a155bd56b5618229ae2ac3e91849aa5e
69 6c725a58ad10aea441540bfd06c507f63e8b9cdd
69 6c725a58ad10aea441540bfd06c507f63e8b9cdd
70 c1818a9f5977dd4139a48f93f5425c67d44a9368
70 c1818a9f5977dd4139a48f93f5425c67d44a9368
71 2c0ec49482e8abe888b7bd090b5827acfc22b3d7
71 2c0ec49482e8abe888b7bd090b5827acfc22b3d7
72 6b57ee934bb2996050540f84cdfc8dcad1e7267d
72 6b57ee934bb2996050540f84cdfc8dcad1e7267d
73 b5af5d6ea56d73ce24c40bc3cd19a862f74888ac
73 b5af5d6ea56d73ce24c40bc3cd19a862f74888ac
74 733bf0910832b26b768a09172f325f995b5476e1
74 733bf0910832b26b768a09172f325f995b5476e1
75 6e9a5adf5437e49c746288cf95c5ac34fa8f2f72
75 6e9a5adf5437e49c746288cf95c5ac34fa8f2f72
76 d9e5488323c782fe684573f3043369d199038b6f
76 d9e5488323c782fe684573f3043369d199038b6f
77 2bba2f40f321484159b395a43f20101d4bb7ead0
77 2bba2f40f321484159b395a43f20101d4bb7ead0
78
78
79 Get part of linear run:
79 Get part of linear run:
80
80
81 $ hg debuggetbundle repo bundle -H d9e5488323c782fe684573f3043369d199038b6f -C 733bf0910832b26b768a09172f325f995b5476e1
81 $ hg debuggetbundle repo bundle -H d9e5488323c782fe684573f3043369d199038b6f -C 733bf0910832b26b768a09172f325f995b5476e1
82 $ hg debugbundle bundle
82 $ hg debugbundle bundle
83 6e9a5adf5437e49c746288cf95c5ac34fa8f2f72
83 6e9a5adf5437e49c746288cf95c5ac34fa8f2f72
84 d9e5488323c782fe684573f3043369d199038b6f
84 d9e5488323c782fe684573f3043369d199038b6f
85
85
86 Get missing branch and merge:
86 Get missing branch and merge:
87
87
88 $ hg debuggetbundle repo bundle -H d9e5488323c782fe684573f3043369d199038b6f -C 6b57ee934bb2996050540f84cdfc8dcad1e7267d
88 $ hg debuggetbundle repo bundle -H d9e5488323c782fe684573f3043369d199038b6f -C 6b57ee934bb2996050540f84cdfc8dcad1e7267d
89 $ hg debugbundle bundle
89 $ hg debugbundle bundle
90 0f82d97ec2778746743fbc996740d409558fda22
90 0f82d97ec2778746743fbc996740d409558fda22
91 ea919464b16e003894c48b6cb68df3cd9411b544
91 ea919464b16e003894c48b6cb68df3cd9411b544
92 74a573f2ae100f1cedfad9aa7b96f8eaab1dabfc
92 74a573f2ae100f1cedfad9aa7b96f8eaab1dabfc
93 2114148793524fd045998f71a45b0aaf139f752b
93 2114148793524fd045998f71a45b0aaf139f752b
94 b6b2b682253df2ffedc10e9415e4114202b303c5
94 b6b2b682253df2ffedc10e9415e4114202b303c5
95 b5af5d6ea56d73ce24c40bc3cd19a862f74888ac
95 b5af5d6ea56d73ce24c40bc3cd19a862f74888ac
96 733bf0910832b26b768a09172f325f995b5476e1
96 733bf0910832b26b768a09172f325f995b5476e1
97 6e9a5adf5437e49c746288cf95c5ac34fa8f2f72
97 6e9a5adf5437e49c746288cf95c5ac34fa8f2f72
98 d9e5488323c782fe684573f3043369d199038b6f
98 d9e5488323c782fe684573f3043369d199038b6f
99
99
100 Get from only one head:
100 Get from only one head:
101
101
102 $ hg debuggetbundle repo bundle -H 6c725a58ad10aea441540bfd06c507f63e8b9cdd -C 6e23b016bc0f0e79c7bd9dd372ccee07055d7fd4
102 $ hg debuggetbundle repo bundle -H 6c725a58ad10aea441540bfd06c507f63e8b9cdd -C 6e23b016bc0f0e79c7bd9dd372ccee07055d7fd4
103 $ hg debugbundle bundle
103 $ hg debugbundle bundle
104 a21d913c992197a2eb60b298521ec0f045a04799
104 a21d913c992197a2eb60b298521ec0f045a04799
105 18063366a155bd56b5618229ae2ac3e91849aa5e
105 18063366a155bd56b5618229ae2ac3e91849aa5e
106 6c725a58ad10aea441540bfd06c507f63e8b9cdd
106 6c725a58ad10aea441540bfd06c507f63e8b9cdd
107
107
108 Get parts of two branches:
108 Get parts of two branches:
109
109
110 $ hg debuggetbundle repo bundle -H 6b57ee934bb2996050540f84cdfc8dcad1e7267d -C c1818a9f5977dd4139a48f93f5425c67d44a9368 -H 2114148793524fd045998f71a45b0aaf139f752b -C ea919464b16e003894c48b6cb68df3cd9411b544
110 $ hg debuggetbundle repo bundle -H 6b57ee934bb2996050540f84cdfc8dcad1e7267d -C c1818a9f5977dd4139a48f93f5425c67d44a9368 -H 2114148793524fd045998f71a45b0aaf139f752b -C ea919464b16e003894c48b6cb68df3cd9411b544
111 $ hg debugbundle bundle
111 $ hg debugbundle bundle
112 74a573f2ae100f1cedfad9aa7b96f8eaab1dabfc
112 74a573f2ae100f1cedfad9aa7b96f8eaab1dabfc
113 2114148793524fd045998f71a45b0aaf139f752b
113 2114148793524fd045998f71a45b0aaf139f752b
114 2c0ec49482e8abe888b7bd090b5827acfc22b3d7
114 2c0ec49482e8abe888b7bd090b5827acfc22b3d7
115 6b57ee934bb2996050540f84cdfc8dcad1e7267d
115 6b57ee934bb2996050540f84cdfc8dcad1e7267d
116
116
117 Check that we get all needed file changes:
117 Check that we get all needed file changes:
118
118
119 $ hg debugbundle bundle --all
119 $ hg debugbundle bundle --all
120 format: id, p1, p2, cset, len(delta)
120 format: id, p1, p2, cset, delta base, len(delta)
121
121
122 changelog
122 changelog
123 74a573f2ae100f1cedfad9aa7b96f8eaab1dabfc ea919464b16e003894c48b6cb68df3cd9411b544 0000000000000000000000000000000000000000 74a573f2ae100f1cedfad9aa7b96f8eaab1dabfc 99
123 74a573f2ae100f1cedfad9aa7b96f8eaab1dabfc ea919464b16e003894c48b6cb68df3cd9411b544 0000000000000000000000000000000000000000 74a573f2ae100f1cedfad9aa7b96f8eaab1dabfc ea919464b16e003894c48b6cb68df3cd9411b544 99
124 2114148793524fd045998f71a45b0aaf139f752b 74a573f2ae100f1cedfad9aa7b96f8eaab1dabfc 0000000000000000000000000000000000000000 2114148793524fd045998f71a45b0aaf139f752b 99
124 2114148793524fd045998f71a45b0aaf139f752b 74a573f2ae100f1cedfad9aa7b96f8eaab1dabfc 0000000000000000000000000000000000000000 2114148793524fd045998f71a45b0aaf139f752b 74a573f2ae100f1cedfad9aa7b96f8eaab1dabfc 99
125 2c0ec49482e8abe888b7bd090b5827acfc22b3d7 c1818a9f5977dd4139a48f93f5425c67d44a9368 0000000000000000000000000000000000000000 2c0ec49482e8abe888b7bd090b5827acfc22b3d7 102
125 2c0ec49482e8abe888b7bd090b5827acfc22b3d7 c1818a9f5977dd4139a48f93f5425c67d44a9368 0000000000000000000000000000000000000000 2c0ec49482e8abe888b7bd090b5827acfc22b3d7 2114148793524fd045998f71a45b0aaf139f752b 102
126 6b57ee934bb2996050540f84cdfc8dcad1e7267d 2c0ec49482e8abe888b7bd090b5827acfc22b3d7 0000000000000000000000000000000000000000 6b57ee934bb2996050540f84cdfc8dcad1e7267d 102
126 6b57ee934bb2996050540f84cdfc8dcad1e7267d 2c0ec49482e8abe888b7bd090b5827acfc22b3d7 0000000000000000000000000000000000000000 6b57ee934bb2996050540f84cdfc8dcad1e7267d 2c0ec49482e8abe888b7bd090b5827acfc22b3d7 102
127
127
128 manifest
128 manifest
129 dac7984588fc4eea7acbf39693a9c1b06f5b175d 591f732a3faf1fb903815273f3c199a514a61ccb 0000000000000000000000000000000000000000 74a573f2ae100f1cedfad9aa7b96f8eaab1dabfc 113
129 dac7984588fc4eea7acbf39693a9c1b06f5b175d 591f732a3faf1fb903815273f3c199a514a61ccb 0000000000000000000000000000000000000000 74a573f2ae100f1cedfad9aa7b96f8eaab1dabfc 591f732a3faf1fb903815273f3c199a514a61ccb 113
130 0772616e6b48a76afb6c1458e193cbb3dae2e4ff dac7984588fc4eea7acbf39693a9c1b06f5b175d 0000000000000000000000000000000000000000 2114148793524fd045998f71a45b0aaf139f752b 113
130 0772616e6b48a76afb6c1458e193cbb3dae2e4ff dac7984588fc4eea7acbf39693a9c1b06f5b175d 0000000000000000000000000000000000000000 2114148793524fd045998f71a45b0aaf139f752b dac7984588fc4eea7acbf39693a9c1b06f5b175d 113
131 eb498cd9af6c44108e43041e951ce829e29f6c80 bff2f4817ced57b386caf7c4e3e36a4bc9af7e93 0000000000000000000000000000000000000000 2c0ec49482e8abe888b7bd090b5827acfc22b3d7 295
131 eb498cd9af6c44108e43041e951ce829e29f6c80 bff2f4817ced57b386caf7c4e3e36a4bc9af7e93 0000000000000000000000000000000000000000 2c0ec49482e8abe888b7bd090b5827acfc22b3d7 0772616e6b48a76afb6c1458e193cbb3dae2e4ff 295
132 b15709c071ddd2d93188508ba156196ab4f19620 eb498cd9af6c44108e43041e951ce829e29f6c80 0000000000000000000000000000000000000000 6b57ee934bb2996050540f84cdfc8dcad1e7267d 114
132 b15709c071ddd2d93188508ba156196ab4f19620 eb498cd9af6c44108e43041e951ce829e29f6c80 0000000000000000000000000000000000000000 6b57ee934bb2996050540f84cdfc8dcad1e7267d eb498cd9af6c44108e43041e951ce829e29f6c80 114
133
133
134 mf
134 mf
135 4f73f97080266ab8e0c0561ca8d0da3eaf65b695 301ca08d026bb72cb4258a9d211bdf7ca0bcd810 0000000000000000000000000000000000000000 74a573f2ae100f1cedfad9aa7b96f8eaab1dabfc 17
135 4f73f97080266ab8e0c0561ca8d0da3eaf65b695 301ca08d026bb72cb4258a9d211bdf7ca0bcd810 0000000000000000000000000000000000000000 74a573f2ae100f1cedfad9aa7b96f8eaab1dabfc 301ca08d026bb72cb4258a9d211bdf7ca0bcd810 17
136 c7b583de053293870e145f45bd2d61643563fd06 4f73f97080266ab8e0c0561ca8d0da3eaf65b695 0000000000000000000000000000000000000000 2114148793524fd045998f71a45b0aaf139f752b 18
136 c7b583de053293870e145f45bd2d61643563fd06 4f73f97080266ab8e0c0561ca8d0da3eaf65b695 0000000000000000000000000000000000000000 2114148793524fd045998f71a45b0aaf139f752b 4f73f97080266ab8e0c0561ca8d0da3eaf65b695 18
137 266ee3c0302a5a18f1cf96817ac79a51836179e9 edc0f6b8db80d68ae6aff2b19f7e5347ab68fa63 0000000000000000000000000000000000000000 2c0ec49482e8abe888b7bd090b5827acfc22b3d7 149
137 266ee3c0302a5a18f1cf96817ac79a51836179e9 edc0f6b8db80d68ae6aff2b19f7e5347ab68fa63 0000000000000000000000000000000000000000 2c0ec49482e8abe888b7bd090b5827acfc22b3d7 c7b583de053293870e145f45bd2d61643563fd06 149
138 698c6a36220548cd3903ca7dada27c59aa500c52 266ee3c0302a5a18f1cf96817ac79a51836179e9 0000000000000000000000000000000000000000 6b57ee934bb2996050540f84cdfc8dcad1e7267d 19
138 698c6a36220548cd3903ca7dada27c59aa500c52 266ee3c0302a5a18f1cf96817ac79a51836179e9 0000000000000000000000000000000000000000 6b57ee934bb2996050540f84cdfc8dcad1e7267d 266ee3c0302a5a18f1cf96817ac79a51836179e9 19
139
139
140 nf11
140 nf11
141 33fbc651630ffa7ccbebfe4eb91320a873e7291c 0000000000000000000000000000000000000000 0000000000000000000000000000000000000000 2c0ec49482e8abe888b7bd090b5827acfc22b3d7 16
141 33fbc651630ffa7ccbebfe4eb91320a873e7291c 0000000000000000000000000000000000000000 0000000000000000000000000000000000000000 2c0ec49482e8abe888b7bd090b5827acfc22b3d7 0000000000000000000000000000000000000000 16
142
142
143 nf12
143 nf12
144 ddce0544363f037e9fb889faca058f52dc01c0a5 0000000000000000000000000000000000000000 0000000000000000000000000000000000000000 6b57ee934bb2996050540f84cdfc8dcad1e7267d 16
144 ddce0544363f037e9fb889faca058f52dc01c0a5 0000000000000000000000000000000000000000 0000000000000000000000000000000000000000 6b57ee934bb2996050540f84cdfc8dcad1e7267d 0000000000000000000000000000000000000000 16
145
145
146 nf4
146 nf4
147 3c1407305701051cbed9f9cb9a68bdfb5997c235 0000000000000000000000000000000000000000 0000000000000000000000000000000000000000 74a573f2ae100f1cedfad9aa7b96f8eaab1dabfc 15
147 3c1407305701051cbed9f9cb9a68bdfb5997c235 0000000000000000000000000000000000000000 0000000000000000000000000000000000000000 74a573f2ae100f1cedfad9aa7b96f8eaab1dabfc 0000000000000000000000000000000000000000 15
148
148
149 nf5
149 nf5
150 0dbd89c185f53a1727c54cd1ce256482fa23968e 0000000000000000000000000000000000000000 0000000000000000000000000000000000000000 2114148793524fd045998f71a45b0aaf139f752b 15
150 0dbd89c185f53a1727c54cd1ce256482fa23968e 0000000000000000000000000000000000000000 0000000000000000000000000000000000000000 2114148793524fd045998f71a45b0aaf139f752b 0000000000000000000000000000000000000000 15
151
151
152 Get branch and merge:
152 Get branch and merge:
153
153
154 $ hg debuggetbundle repo bundle -C 10e64d654571f11577745b4d8372e859d9e4df63 -H 6e9a5adf5437e49c746288cf95c5ac34fa8f2f72
154 $ hg debuggetbundle repo bundle -C 10e64d654571f11577745b4d8372e859d9e4df63 -H 6e9a5adf5437e49c746288cf95c5ac34fa8f2f72
155 $ hg debugbundle bundle
155 $ hg debugbundle bundle
156 6e23b016bc0f0e79c7bd9dd372ccee07055d7fd4
156 6e23b016bc0f0e79c7bd9dd372ccee07055d7fd4
157 0f82d97ec2778746743fbc996740d409558fda22
157 0f82d97ec2778746743fbc996740d409558fda22
158 ea919464b16e003894c48b6cb68df3cd9411b544
158 ea919464b16e003894c48b6cb68df3cd9411b544
159 74a573f2ae100f1cedfad9aa7b96f8eaab1dabfc
159 74a573f2ae100f1cedfad9aa7b96f8eaab1dabfc
160 2114148793524fd045998f71a45b0aaf139f752b
160 2114148793524fd045998f71a45b0aaf139f752b
161 b6b2b682253df2ffedc10e9415e4114202b303c5
161 b6b2b682253df2ffedc10e9415e4114202b303c5
162 a21d913c992197a2eb60b298521ec0f045a04799
162 a21d913c992197a2eb60b298521ec0f045a04799
163 18063366a155bd56b5618229ae2ac3e91849aa5e
163 18063366a155bd56b5618229ae2ac3e91849aa5e
164 6c725a58ad10aea441540bfd06c507f63e8b9cdd
164 6c725a58ad10aea441540bfd06c507f63e8b9cdd
165 c1818a9f5977dd4139a48f93f5425c67d44a9368
165 c1818a9f5977dd4139a48f93f5425c67d44a9368
166 2c0ec49482e8abe888b7bd090b5827acfc22b3d7
166 2c0ec49482e8abe888b7bd090b5827acfc22b3d7
167 6b57ee934bb2996050540f84cdfc8dcad1e7267d
167 6b57ee934bb2996050540f84cdfc8dcad1e7267d
168 b5af5d6ea56d73ce24c40bc3cd19a862f74888ac
168 b5af5d6ea56d73ce24c40bc3cd19a862f74888ac
169 733bf0910832b26b768a09172f325f995b5476e1
169 733bf0910832b26b768a09172f325f995b5476e1
170 6e9a5adf5437e49c746288cf95c5ac34fa8f2f72
170 6e9a5adf5437e49c746288cf95c5ac34fa8f2f72
171
171
172
172
173 = Test via HTTP =
173 = Test via HTTP =
174
174
175 Get everything:
175 Get everything:
176
176
177 $ hg serve -R repo -p $HGPORT -d --pid-file=hg.pid -E error.log -A access.log
177 $ hg serve -R repo -p $HGPORT -d --pid-file=hg.pid -E error.log -A access.log
178 $ cat hg.pid >> $DAEMON_PIDS
178 $ cat hg.pid >> $DAEMON_PIDS
179 $ hg debuggetbundle http://localhost:$HGPORT/ bundle
179 $ hg debuggetbundle http://localhost:$HGPORT/ bundle
180 $ hg debugbundle bundle
180 $ hg debugbundle bundle
181 10e64d654571f11577745b4d8372e859d9e4df63
181 10e64d654571f11577745b4d8372e859d9e4df63
182 6e23b016bc0f0e79c7bd9dd372ccee07055d7fd4
182 6e23b016bc0f0e79c7bd9dd372ccee07055d7fd4
183 0f82d97ec2778746743fbc996740d409558fda22
183 0f82d97ec2778746743fbc996740d409558fda22
184 ea919464b16e003894c48b6cb68df3cd9411b544
184 ea919464b16e003894c48b6cb68df3cd9411b544
185 74a573f2ae100f1cedfad9aa7b96f8eaab1dabfc
185 74a573f2ae100f1cedfad9aa7b96f8eaab1dabfc
186 2114148793524fd045998f71a45b0aaf139f752b
186 2114148793524fd045998f71a45b0aaf139f752b
187 b6b2b682253df2ffedc10e9415e4114202b303c5
187 b6b2b682253df2ffedc10e9415e4114202b303c5
188 a21d913c992197a2eb60b298521ec0f045a04799
188 a21d913c992197a2eb60b298521ec0f045a04799
189 18063366a155bd56b5618229ae2ac3e91849aa5e
189 18063366a155bd56b5618229ae2ac3e91849aa5e
190 6c725a58ad10aea441540bfd06c507f63e8b9cdd
190 6c725a58ad10aea441540bfd06c507f63e8b9cdd
191 c1818a9f5977dd4139a48f93f5425c67d44a9368
191 c1818a9f5977dd4139a48f93f5425c67d44a9368
192 2c0ec49482e8abe888b7bd090b5827acfc22b3d7
192 2c0ec49482e8abe888b7bd090b5827acfc22b3d7
193 6b57ee934bb2996050540f84cdfc8dcad1e7267d
193 6b57ee934bb2996050540f84cdfc8dcad1e7267d
194 b5af5d6ea56d73ce24c40bc3cd19a862f74888ac
194 b5af5d6ea56d73ce24c40bc3cd19a862f74888ac
195 733bf0910832b26b768a09172f325f995b5476e1
195 733bf0910832b26b768a09172f325f995b5476e1
196 6e9a5adf5437e49c746288cf95c5ac34fa8f2f72
196 6e9a5adf5437e49c746288cf95c5ac34fa8f2f72
197 d9e5488323c782fe684573f3043369d199038b6f
197 d9e5488323c782fe684573f3043369d199038b6f
198 2bba2f40f321484159b395a43f20101d4bb7ead0
198 2bba2f40f321484159b395a43f20101d4bb7ead0
199
199
200 Get parts of two branches:
200 Get parts of two branches:
201
201
202 $ hg debuggetbundle http://localhost:$HGPORT/ bundle -H 6b57ee934bb2996050540f84cdfc8dcad1e7267d -C c1818a9f5977dd4139a48f93f5425c67d44a9368 -H 2114148793524fd045998f71a45b0aaf139f752b -C ea919464b16e003894c48b6cb68df3cd9411b544
202 $ hg debuggetbundle http://localhost:$HGPORT/ bundle -H 6b57ee934bb2996050540f84cdfc8dcad1e7267d -C c1818a9f5977dd4139a48f93f5425c67d44a9368 -H 2114148793524fd045998f71a45b0aaf139f752b -C ea919464b16e003894c48b6cb68df3cd9411b544
203 $ hg debugbundle bundle
203 $ hg debugbundle bundle
204 74a573f2ae100f1cedfad9aa7b96f8eaab1dabfc
204 74a573f2ae100f1cedfad9aa7b96f8eaab1dabfc
205 2114148793524fd045998f71a45b0aaf139f752b
205 2114148793524fd045998f71a45b0aaf139f752b
206 2c0ec49482e8abe888b7bd090b5827acfc22b3d7
206 2c0ec49482e8abe888b7bd090b5827acfc22b3d7
207 6b57ee934bb2996050540f84cdfc8dcad1e7267d
207 6b57ee934bb2996050540f84cdfc8dcad1e7267d
208
208
209 Check that we get all needed file changes:
209 Check that we get all needed file changes:
210
210
211 $ hg debugbundle bundle --all
211 $ hg debugbundle bundle --all
212 format: id, p1, p2, cset, len(delta)
212 format: id, p1, p2, cset, delta base, len(delta)
213
213
214 changelog
214 changelog
215 74a573f2ae100f1cedfad9aa7b96f8eaab1dabfc ea919464b16e003894c48b6cb68df3cd9411b544 0000000000000000000000000000000000000000 74a573f2ae100f1cedfad9aa7b96f8eaab1dabfc 99
215 74a573f2ae100f1cedfad9aa7b96f8eaab1dabfc ea919464b16e003894c48b6cb68df3cd9411b544 0000000000000000000000000000000000000000 74a573f2ae100f1cedfad9aa7b96f8eaab1dabfc ea919464b16e003894c48b6cb68df3cd9411b544 99
216 2114148793524fd045998f71a45b0aaf139f752b 74a573f2ae100f1cedfad9aa7b96f8eaab1dabfc 0000000000000000000000000000000000000000 2114148793524fd045998f71a45b0aaf139f752b 99
216 2114148793524fd045998f71a45b0aaf139f752b 74a573f2ae100f1cedfad9aa7b96f8eaab1dabfc 0000000000000000000000000000000000000000 2114148793524fd045998f71a45b0aaf139f752b 74a573f2ae100f1cedfad9aa7b96f8eaab1dabfc 99
217 2c0ec49482e8abe888b7bd090b5827acfc22b3d7 c1818a9f5977dd4139a48f93f5425c67d44a9368 0000000000000000000000000000000000000000 2c0ec49482e8abe888b7bd090b5827acfc22b3d7 102
217 2c0ec49482e8abe888b7bd090b5827acfc22b3d7 c1818a9f5977dd4139a48f93f5425c67d44a9368 0000000000000000000000000000000000000000 2c0ec49482e8abe888b7bd090b5827acfc22b3d7 2114148793524fd045998f71a45b0aaf139f752b 102
218 6b57ee934bb2996050540f84cdfc8dcad1e7267d 2c0ec49482e8abe888b7bd090b5827acfc22b3d7 0000000000000000000000000000000000000000 6b57ee934bb2996050540f84cdfc8dcad1e7267d 102
218 6b57ee934bb2996050540f84cdfc8dcad1e7267d 2c0ec49482e8abe888b7bd090b5827acfc22b3d7 0000000000000000000000000000000000000000 6b57ee934bb2996050540f84cdfc8dcad1e7267d 2c0ec49482e8abe888b7bd090b5827acfc22b3d7 102
219
219
220 manifest
220 manifest
221 dac7984588fc4eea7acbf39693a9c1b06f5b175d 591f732a3faf1fb903815273f3c199a514a61ccb 0000000000000000000000000000000000000000 74a573f2ae100f1cedfad9aa7b96f8eaab1dabfc 113
221 dac7984588fc4eea7acbf39693a9c1b06f5b175d 591f732a3faf1fb903815273f3c199a514a61ccb 0000000000000000000000000000000000000000 74a573f2ae100f1cedfad9aa7b96f8eaab1dabfc 591f732a3faf1fb903815273f3c199a514a61ccb 113
222 0772616e6b48a76afb6c1458e193cbb3dae2e4ff dac7984588fc4eea7acbf39693a9c1b06f5b175d 0000000000000000000000000000000000000000 2114148793524fd045998f71a45b0aaf139f752b 113
222 0772616e6b48a76afb6c1458e193cbb3dae2e4ff dac7984588fc4eea7acbf39693a9c1b06f5b175d 0000000000000000000000000000000000000000 2114148793524fd045998f71a45b0aaf139f752b dac7984588fc4eea7acbf39693a9c1b06f5b175d 113
223 eb498cd9af6c44108e43041e951ce829e29f6c80 bff2f4817ced57b386caf7c4e3e36a4bc9af7e93 0000000000000000000000000000000000000000 2c0ec49482e8abe888b7bd090b5827acfc22b3d7 295
223 eb498cd9af6c44108e43041e951ce829e29f6c80 bff2f4817ced57b386caf7c4e3e36a4bc9af7e93 0000000000000000000000000000000000000000 2c0ec49482e8abe888b7bd090b5827acfc22b3d7 0772616e6b48a76afb6c1458e193cbb3dae2e4ff 295
224 b15709c071ddd2d93188508ba156196ab4f19620 eb498cd9af6c44108e43041e951ce829e29f6c80 0000000000000000000000000000000000000000 6b57ee934bb2996050540f84cdfc8dcad1e7267d 114
224 b15709c071ddd2d93188508ba156196ab4f19620 eb498cd9af6c44108e43041e951ce829e29f6c80 0000000000000000000000000000000000000000 6b57ee934bb2996050540f84cdfc8dcad1e7267d eb498cd9af6c44108e43041e951ce829e29f6c80 114
225
225
226 mf
226 mf
227 4f73f97080266ab8e0c0561ca8d0da3eaf65b695 301ca08d026bb72cb4258a9d211bdf7ca0bcd810 0000000000000000000000000000000000000000 74a573f2ae100f1cedfad9aa7b96f8eaab1dabfc 17
227 4f73f97080266ab8e0c0561ca8d0da3eaf65b695 301ca08d026bb72cb4258a9d211bdf7ca0bcd810 0000000000000000000000000000000000000000 74a573f2ae100f1cedfad9aa7b96f8eaab1dabfc 301ca08d026bb72cb4258a9d211bdf7ca0bcd810 17
228 c7b583de053293870e145f45bd2d61643563fd06 4f73f97080266ab8e0c0561ca8d0da3eaf65b695 0000000000000000000000000000000000000000 2114148793524fd045998f71a45b0aaf139f752b 18
228 c7b583de053293870e145f45bd2d61643563fd06 4f73f97080266ab8e0c0561ca8d0da3eaf65b695 0000000000000000000000000000000000000000 2114148793524fd045998f71a45b0aaf139f752b 4f73f97080266ab8e0c0561ca8d0da3eaf65b695 18
229 266ee3c0302a5a18f1cf96817ac79a51836179e9 edc0f6b8db80d68ae6aff2b19f7e5347ab68fa63 0000000000000000000000000000000000000000 2c0ec49482e8abe888b7bd090b5827acfc22b3d7 149
229 266ee3c0302a5a18f1cf96817ac79a51836179e9 edc0f6b8db80d68ae6aff2b19f7e5347ab68fa63 0000000000000000000000000000000000000000 2c0ec49482e8abe888b7bd090b5827acfc22b3d7 c7b583de053293870e145f45bd2d61643563fd06 149
230 698c6a36220548cd3903ca7dada27c59aa500c52 266ee3c0302a5a18f1cf96817ac79a51836179e9 0000000000000000000000000000000000000000 6b57ee934bb2996050540f84cdfc8dcad1e7267d 19
230 698c6a36220548cd3903ca7dada27c59aa500c52 266ee3c0302a5a18f1cf96817ac79a51836179e9 0000000000000000000000000000000000000000 6b57ee934bb2996050540f84cdfc8dcad1e7267d 266ee3c0302a5a18f1cf96817ac79a51836179e9 19
231
231
232 nf11
232 nf11
233 33fbc651630ffa7ccbebfe4eb91320a873e7291c 0000000000000000000000000000000000000000 0000000000000000000000000000000000000000 2c0ec49482e8abe888b7bd090b5827acfc22b3d7 16
233 33fbc651630ffa7ccbebfe4eb91320a873e7291c 0000000000000000000000000000000000000000 0000000000000000000000000000000000000000 2c0ec49482e8abe888b7bd090b5827acfc22b3d7 0000000000000000000000000000000000000000 16
234
234
235 nf12
235 nf12
236 ddce0544363f037e9fb889faca058f52dc01c0a5 0000000000000000000000000000000000000000 0000000000000000000000000000000000000000 6b57ee934bb2996050540f84cdfc8dcad1e7267d 16
236 ddce0544363f037e9fb889faca058f52dc01c0a5 0000000000000000000000000000000000000000 0000000000000000000000000000000000000000 6b57ee934bb2996050540f84cdfc8dcad1e7267d 0000000000000000000000000000000000000000 16
237
237
238 nf4
238 nf4
239 3c1407305701051cbed9f9cb9a68bdfb5997c235 0000000000000000000000000000000000000000 0000000000000000000000000000000000000000 74a573f2ae100f1cedfad9aa7b96f8eaab1dabfc 15
239 3c1407305701051cbed9f9cb9a68bdfb5997c235 0000000000000000000000000000000000000000 0000000000000000000000000000000000000000 74a573f2ae100f1cedfad9aa7b96f8eaab1dabfc 0000000000000000000000000000000000000000 15
240
240
241 nf5
241 nf5
242 0dbd89c185f53a1727c54cd1ce256482fa23968e 0000000000000000000000000000000000000000 0000000000000000000000000000000000000000 2114148793524fd045998f71a45b0aaf139f752b 15
242 0dbd89c185f53a1727c54cd1ce256482fa23968e 0000000000000000000000000000000000000000 0000000000000000000000000000000000000000 2114148793524fd045998f71a45b0aaf139f752b 0000000000000000000000000000000000000000 15
243
243
244 Verify we hit the HTTP server:
244 Verify we hit the HTTP server:
245
245
246 $ cat access.log
246 $ cat access.log
247 * - - [*] "GET /?cmd=capabilities HTTP/1.1" 200 - (glob)
247 * - - [*] "GET /?cmd=capabilities HTTP/1.1" 200 - (glob)
248 * - - [*] "GET /?cmd=getbundle HTTP/1.1" 200 - (glob)
248 * - - [*] "GET /?cmd=getbundle HTTP/1.1" 200 - (glob)
249 * - - [*] "GET /?cmd=capabilities HTTP/1.1" 200 - (glob)
249 * - - [*] "GET /?cmd=capabilities HTTP/1.1" 200 - (glob)
250 * - - [*] "GET /?cmd=getbundle HTTP/1.1" 200 - x-hgarg-1:common=c1818a9f5977dd4139a48f93f5425c67d44a9368+ea919464b16e003894c48b6cb68df3cd9411b544&heads=6b57ee934bb2996050540f84cdfc8dcad1e7267d+2114148793524fd045998f71a45b0aaf139f752b (glob)
250 * - - [*] "GET /?cmd=getbundle HTTP/1.1" 200 - x-hgarg-1:common=c1818a9f5977dd4139a48f93f5425c67d44a9368+ea919464b16e003894c48b6cb68df3cd9411b544&heads=6b57ee934bb2996050540f84cdfc8dcad1e7267d+2114148793524fd045998f71a45b0aaf139f752b (glob)
251
251
252 $ cat error.log
252 $ cat error.log
253
253
General Comments 0
You need to be logged in to leave comments. Login now