##// END OF EJS Templates
changegroup.writebundle: HG2Y support...
Eric Sumner -
r23896:becfecaf default
parent child Browse files
Show More
@@ -1,869 +1,884 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 import weakref
8 import weakref
9 from i18n import _
9 from i18n import _
10 from node import nullrev, nullid, hex, short
10 from node import nullrev, nullid, hex, short
11 import mdiff, util, dagutil
11 import mdiff, util, dagutil
12 import struct, os, bz2, zlib, tempfile
12 import struct, os, bz2, zlib, tempfile
13 import discovery, error, phases, branchmap
13 import discovery, error, phases, branchmap
14
14
15 _CHANGEGROUPV1_DELTA_HEADER = "20s20s20s20s"
15 _CHANGEGROUPV1_DELTA_HEADER = "20s20s20s20s"
16 _CHANGEGROUPV2_DELTA_HEADER = "20s20s20s20s20s"
16 _CHANGEGROUPV2_DELTA_HEADER = "20s20s20s20s20s"
17
17
18 def readexactly(stream, n):
18 def readexactly(stream, n):
19 '''read n bytes from stream.read and abort if less was available'''
19 '''read n bytes from stream.read and abort if less was available'''
20 s = stream.read(n)
20 s = stream.read(n)
21 if len(s) < n:
21 if len(s) < n:
22 raise util.Abort(_("stream ended unexpectedly"
22 raise util.Abort(_("stream ended unexpectedly"
23 " (got %d bytes, expected %d)")
23 " (got %d bytes, expected %d)")
24 % (len(s), n))
24 % (len(s), n))
25 return s
25 return s
26
26
27 def getchunk(stream):
27 def getchunk(stream):
28 """return the next chunk from stream as a string"""
28 """return the next chunk from stream as a string"""
29 d = readexactly(stream, 4)
29 d = readexactly(stream, 4)
30 l = struct.unpack(">l", d)[0]
30 l = struct.unpack(">l", d)[0]
31 if l <= 4:
31 if l <= 4:
32 if l:
32 if l:
33 raise util.Abort(_("invalid chunk length %d") % l)
33 raise util.Abort(_("invalid chunk length %d") % l)
34 return ""
34 return ""
35 return readexactly(stream, l - 4)
35 return readexactly(stream, l - 4)
36
36
37 def chunkheader(length):
37 def chunkheader(length):
38 """return a changegroup chunk header (string)"""
38 """return a changegroup chunk header (string)"""
39 return struct.pack(">l", length + 4)
39 return struct.pack(">l", length + 4)
40
40
41 def closechunk():
41 def closechunk():
42 """return a changegroup chunk header (string) for a zero-length chunk"""
42 """return a changegroup chunk header (string) for a zero-length chunk"""
43 return struct.pack(">l", 0)
43 return struct.pack(">l", 0)
44
44
45 def combineresults(results):
45 def combineresults(results):
46 """logic to combine 0 or more addchangegroup results into one"""
46 """logic to combine 0 or more addchangegroup results into one"""
47 changedheads = 0
47 changedheads = 0
48 result = 1
48 result = 1
49 for ret in results:
49 for ret in results:
50 # If any changegroup result is 0, return 0
50 # If any changegroup result is 0, return 0
51 if ret == 0:
51 if ret == 0:
52 result = 0
52 result = 0
53 break
53 break
54 if ret < -1:
54 if ret < -1:
55 changedheads += ret + 1
55 changedheads += ret + 1
56 elif ret > 1:
56 elif ret > 1:
57 changedheads += ret - 1
57 changedheads += ret - 1
58 if changedheads > 0:
58 if changedheads > 0:
59 result = 1 + changedheads
59 result = 1 + changedheads
60 elif changedheads < 0:
60 elif changedheads < 0:
61 result = -1 + changedheads
61 result = -1 + changedheads
62 return result
62 return result
63
63
64 class nocompress(object):
64 class nocompress(object):
65 def compress(self, x):
65 def compress(self, x):
66 return x
66 return x
67 def flush(self):
67 def flush(self):
68 return ""
68 return ""
69
69
70 bundletypes = {
70 bundletypes = {
71 "": ("", nocompress), # only when using unbundle on ssh and old http servers
71 "": ("", nocompress), # only when using unbundle on ssh and old http servers
72 # since the unification ssh accepts a header but there
72 # since the unification ssh accepts a header but there
73 # is no capability signaling it.
73 # is no capability signaling it.
74 "HG2Y": (), # special-cased below
74 "HG10UN": ("HG10UN", nocompress),
75 "HG10UN": ("HG10UN", nocompress),
75 "HG10BZ": ("HG10", lambda: bz2.BZ2Compressor()),
76 "HG10BZ": ("HG10", lambda: bz2.BZ2Compressor()),
76 "HG10GZ": ("HG10GZ", lambda: zlib.compressobj()),
77 "HG10GZ": ("HG10GZ", lambda: zlib.compressobj()),
77 }
78 }
78
79
79 # hgweb uses this list to communicate its preferred type
80 # hgweb uses this list to communicate its preferred type
80 bundlepriority = ['HG10GZ', 'HG10BZ', 'HG10UN']
81 bundlepriority = ['HG10GZ', 'HG10BZ', 'HG10UN']
81
82
82 def writebundle(ui, cg, filename, bundletype, vfs=None):
83 def writebundle(ui, cg, filename, bundletype, vfs=None):
83 """Write a bundle file and return its filename.
84 """Write a bundle file and return its filename.
84
85
85 Existing files will not be overwritten.
86 Existing files will not be overwritten.
86 If no filename is specified, a temporary file is created.
87 If no filename is specified, a temporary file is created.
87 bz2 compression can be turned off.
88 bz2 compression can be turned off.
88 The bundle file will be deleted in case of errors.
89 The bundle file will be deleted in case of errors.
89 """
90 """
90
91
91 fh = None
92 fh = None
92 cleanup = None
93 cleanup = None
93 try:
94 try:
94 if filename:
95 if filename:
95 if vfs:
96 if vfs:
96 fh = vfs.open(filename, "wb")
97 fh = vfs.open(filename, "wb")
97 else:
98 else:
98 fh = open(filename, "wb")
99 fh = open(filename, "wb")
99 else:
100 else:
100 fd, filename = tempfile.mkstemp(prefix="hg-bundle-", suffix=".hg")
101 fd, filename = tempfile.mkstemp(prefix="hg-bundle-", suffix=".hg")
101 fh = os.fdopen(fd, "wb")
102 fh = os.fdopen(fd, "wb")
102 cleanup = filename
103 cleanup = filename
103
104
105 if bundletype == "HG2Y":
106 import bundle2
107 bundle = bundle2.bundle20(ui)
108 part = bundle.newpart('b2x:changegroup', data=cg.getchunks())
109 part.addparam('version', cg.version)
110 z = nocompress()
111 chunkiter = bundle.getchunks()
112 else:
113 if cg.version != '01':
114 raise util.Abort(_('Bundle1 only supports v1 changegroups\n'))
104 header, compressor = bundletypes[bundletype]
115 header, compressor = bundletypes[bundletype]
105 fh.write(header)
116 fh.write(header)
106 z = compressor()
117 z = compressor()
118 chunkiter = cg.getchunks()
107
119
108 # parse the changegroup data, otherwise we will block
120 # parse the changegroup data, otherwise we will block
109 # in case of sshrepo because we don't know the end of the stream
121 # in case of sshrepo because we don't know the end of the stream
110
122
111 # an empty chunkgroup is the end of the changegroup
123 # an empty chunkgroup is the end of the changegroup
112 # a changegroup has at least 2 chunkgroups (changelog and manifest).
124 # a changegroup has at least 2 chunkgroups (changelog and manifest).
113 # after that, an empty chunkgroup is the end of the changegroup
125 # after that, an empty chunkgroup is the end of the changegroup
114 for chunk in cg.getchunks():
126 for chunk in chunkiter:
115 fh.write(z.compress(chunk))
127 fh.write(z.compress(chunk))
116 fh.write(z.flush())
128 fh.write(z.flush())
117 cleanup = None
129 cleanup = None
118 return filename
130 return filename
119 finally:
131 finally:
120 if fh is not None:
132 if fh is not None:
121 fh.close()
133 fh.close()
122 if cleanup is not None:
134 if cleanup is not None:
123 if filename and vfs:
135 if filename and vfs:
124 vfs.unlink(cleanup)
136 vfs.unlink(cleanup)
125 else:
137 else:
126 os.unlink(cleanup)
138 os.unlink(cleanup)
127
139
128 def decompressor(fh, alg):
140 def decompressor(fh, alg):
129 if alg == 'UN':
141 if alg == 'UN':
130 return fh
142 return fh
131 elif alg == 'GZ':
143 elif alg == 'GZ':
132 def generator(f):
144 def generator(f):
133 zd = zlib.decompressobj()
145 zd = zlib.decompressobj()
134 for chunk in util.filechunkiter(f):
146 for chunk in util.filechunkiter(f):
135 yield zd.decompress(chunk)
147 yield zd.decompress(chunk)
136 elif alg == 'BZ':
148 elif alg == 'BZ':
137 def generator(f):
149 def generator(f):
138 zd = bz2.BZ2Decompressor()
150 zd = bz2.BZ2Decompressor()
139 zd.decompress("BZ")
151 zd.decompress("BZ")
140 for chunk in util.filechunkiter(f, 4096):
152 for chunk in util.filechunkiter(f, 4096):
141 yield zd.decompress(chunk)
153 yield zd.decompress(chunk)
142 else:
154 else:
143 raise util.Abort("unknown bundle compression '%s'" % alg)
155 raise util.Abort("unknown bundle compression '%s'" % alg)
144 return util.chunkbuffer(generator(fh))
156 return util.chunkbuffer(generator(fh))
145
157
146 class cg1unpacker(object):
158 class cg1unpacker(object):
147 deltaheader = _CHANGEGROUPV1_DELTA_HEADER
159 deltaheader = _CHANGEGROUPV1_DELTA_HEADER
148 deltaheadersize = struct.calcsize(deltaheader)
160 deltaheadersize = struct.calcsize(deltaheader)
161 version = '01'
149 def __init__(self, fh, alg):
162 def __init__(self, fh, alg):
150 self._stream = decompressor(fh, alg)
163 self._stream = decompressor(fh, alg)
151 self._type = alg
164 self._type = alg
152 self.callback = None
165 self.callback = None
153 def compressed(self):
166 def compressed(self):
154 return self._type != 'UN'
167 return self._type != 'UN'
155 def read(self, l):
168 def read(self, l):
156 return self._stream.read(l)
169 return self._stream.read(l)
157 def seek(self, pos):
170 def seek(self, pos):
158 return self._stream.seek(pos)
171 return self._stream.seek(pos)
159 def tell(self):
172 def tell(self):
160 return self._stream.tell()
173 return self._stream.tell()
161 def close(self):
174 def close(self):
162 return self._stream.close()
175 return self._stream.close()
163
176
164 def chunklength(self):
177 def chunklength(self):
165 d = readexactly(self._stream, 4)
178 d = readexactly(self._stream, 4)
166 l = struct.unpack(">l", d)[0]
179 l = struct.unpack(">l", d)[0]
167 if l <= 4:
180 if l <= 4:
168 if l:
181 if l:
169 raise util.Abort(_("invalid chunk length %d") % l)
182 raise util.Abort(_("invalid chunk length %d") % l)
170 return 0
183 return 0
171 if self.callback:
184 if self.callback:
172 self.callback()
185 self.callback()
173 return l - 4
186 return l - 4
174
187
175 def changelogheader(self):
188 def changelogheader(self):
176 """v10 does not have a changelog header chunk"""
189 """v10 does not have a changelog header chunk"""
177 return {}
190 return {}
178
191
179 def manifestheader(self):
192 def manifestheader(self):
180 """v10 does not have a manifest header chunk"""
193 """v10 does not have a manifest header chunk"""
181 return {}
194 return {}
182
195
183 def filelogheader(self):
196 def filelogheader(self):
184 """return the header of the filelogs chunk, v10 only has the filename"""
197 """return the header of the filelogs chunk, v10 only has the filename"""
185 l = self.chunklength()
198 l = self.chunklength()
186 if not l:
199 if not l:
187 return {}
200 return {}
188 fname = readexactly(self._stream, l)
201 fname = readexactly(self._stream, l)
189 return {'filename': fname}
202 return {'filename': fname}
190
203
191 def _deltaheader(self, headertuple, prevnode):
204 def _deltaheader(self, headertuple, prevnode):
192 node, p1, p2, cs = headertuple
205 node, p1, p2, cs = headertuple
193 if prevnode is None:
206 if prevnode is None:
194 deltabase = p1
207 deltabase = p1
195 else:
208 else:
196 deltabase = prevnode
209 deltabase = prevnode
197 return node, p1, p2, deltabase, cs
210 return node, p1, p2, deltabase, cs
198
211
199 def deltachunk(self, prevnode):
212 def deltachunk(self, prevnode):
200 l = self.chunklength()
213 l = self.chunklength()
201 if not l:
214 if not l:
202 return {}
215 return {}
203 headerdata = readexactly(self._stream, self.deltaheadersize)
216 headerdata = readexactly(self._stream, self.deltaheadersize)
204 header = struct.unpack(self.deltaheader, headerdata)
217 header = struct.unpack(self.deltaheader, headerdata)
205 delta = readexactly(self._stream, l - self.deltaheadersize)
218 delta = readexactly(self._stream, l - self.deltaheadersize)
206 node, p1, p2, deltabase, cs = self._deltaheader(header, prevnode)
219 node, p1, p2, deltabase, cs = self._deltaheader(header, prevnode)
207 return {'node': node, 'p1': p1, 'p2': p2, 'cs': cs,
220 return {'node': node, 'p1': p1, 'p2': p2, 'cs': cs,
208 'deltabase': deltabase, 'delta': delta}
221 'deltabase': deltabase, 'delta': delta}
209
222
210 def getchunks(self):
223 def getchunks(self):
211 """returns all the chunks contains in the bundle
224 """returns all the chunks contains in the bundle
212
225
213 Used when you need to forward the binary stream to a file or another
226 Used when you need to forward the binary stream to a file or another
214 network API. To do so, it parse the changegroup data, otherwise it will
227 network API. To do so, it parse the changegroup data, otherwise it will
215 block in case of sshrepo because it don't know the end of the stream.
228 block in case of sshrepo because it don't know the end of the stream.
216 """
229 """
217 # an empty chunkgroup is the end of the changegroup
230 # an empty chunkgroup is the end of the changegroup
218 # a changegroup has at least 2 chunkgroups (changelog and manifest).
231 # a changegroup has at least 2 chunkgroups (changelog and manifest).
219 # after that, an empty chunkgroup is the end of the changegroup
232 # after that, an empty chunkgroup is the end of the changegroup
220 empty = False
233 empty = False
221 count = 0
234 count = 0
222 while not empty or count <= 2:
235 while not empty or count <= 2:
223 empty = True
236 empty = True
224 count += 1
237 count += 1
225 while True:
238 while True:
226 chunk = getchunk(self)
239 chunk = getchunk(self)
227 if not chunk:
240 if not chunk:
228 break
241 break
229 empty = False
242 empty = False
230 yield chunkheader(len(chunk))
243 yield chunkheader(len(chunk))
231 pos = 0
244 pos = 0
232 while pos < len(chunk):
245 while pos < len(chunk):
233 next = pos + 2**20
246 next = pos + 2**20
234 yield chunk[pos:next]
247 yield chunk[pos:next]
235 pos = next
248 pos = next
236 yield closechunk()
249 yield closechunk()
237
250
238 class cg2unpacker(cg1unpacker):
251 class cg2unpacker(cg1unpacker):
239 deltaheader = _CHANGEGROUPV2_DELTA_HEADER
252 deltaheader = _CHANGEGROUPV2_DELTA_HEADER
240 deltaheadersize = struct.calcsize(deltaheader)
253 deltaheadersize = struct.calcsize(deltaheader)
254 version = '02'
241
255
242 def _deltaheader(self, headertuple, prevnode):
256 def _deltaheader(self, headertuple, prevnode):
243 node, p1, p2, deltabase, cs = headertuple
257 node, p1, p2, deltabase, cs = headertuple
244 return node, p1, p2, deltabase, cs
258 return node, p1, p2, deltabase, cs
245
259
246 class headerlessfixup(object):
260 class headerlessfixup(object):
247 def __init__(self, fh, h):
261 def __init__(self, fh, h):
248 self._h = h
262 self._h = h
249 self._fh = fh
263 self._fh = fh
250 def read(self, n):
264 def read(self, n):
251 if self._h:
265 if self._h:
252 d, self._h = self._h[:n], self._h[n:]
266 d, self._h = self._h[:n], self._h[n:]
253 if len(d) < n:
267 if len(d) < n:
254 d += readexactly(self._fh, n - len(d))
268 d += readexactly(self._fh, n - len(d))
255 return d
269 return d
256 return readexactly(self._fh, n)
270 return readexactly(self._fh, n)
257
271
258 class cg1packer(object):
272 class cg1packer(object):
259 deltaheader = _CHANGEGROUPV1_DELTA_HEADER
273 deltaheader = _CHANGEGROUPV1_DELTA_HEADER
274 version = '01'
260 def __init__(self, repo, bundlecaps=None):
275 def __init__(self, repo, bundlecaps=None):
261 """Given a source repo, construct a bundler.
276 """Given a source repo, construct a bundler.
262
277
263 bundlecaps is optional and can be used to specify the set of
278 bundlecaps is optional and can be used to specify the set of
264 capabilities which can be used to build the bundle.
279 capabilities which can be used to build the bundle.
265 """
280 """
266 # Set of capabilities we can use to build the bundle.
281 # Set of capabilities we can use to build the bundle.
267 if bundlecaps is None:
282 if bundlecaps is None:
268 bundlecaps = set()
283 bundlecaps = set()
269 self._bundlecaps = bundlecaps
284 self._bundlecaps = bundlecaps
270 self._changelog = repo.changelog
285 self._changelog = repo.changelog
271 self._manifest = repo.manifest
286 self._manifest = repo.manifest
272 reorder = repo.ui.config('bundle', 'reorder', 'auto')
287 reorder = repo.ui.config('bundle', 'reorder', 'auto')
273 if reorder == 'auto':
288 if reorder == 'auto':
274 reorder = None
289 reorder = None
275 else:
290 else:
276 reorder = util.parsebool(reorder)
291 reorder = util.parsebool(reorder)
277 self._repo = repo
292 self._repo = repo
278 self._reorder = reorder
293 self._reorder = reorder
279 self._progress = repo.ui.progress
294 self._progress = repo.ui.progress
280 if self._repo.ui.verbose and not self._repo.ui.debugflag:
295 if self._repo.ui.verbose and not self._repo.ui.debugflag:
281 self._verbosenote = self._repo.ui.note
296 self._verbosenote = self._repo.ui.note
282 else:
297 else:
283 self._verbosenote = lambda s: None
298 self._verbosenote = lambda s: None
284
299
285 def close(self):
300 def close(self):
286 return closechunk()
301 return closechunk()
287
302
288 def fileheader(self, fname):
303 def fileheader(self, fname):
289 return chunkheader(len(fname)) + fname
304 return chunkheader(len(fname)) + fname
290
305
291 def group(self, nodelist, revlog, lookup, units=None, reorder=None):
306 def group(self, nodelist, revlog, lookup, units=None, reorder=None):
292 """Calculate a delta group, yielding a sequence of changegroup chunks
307 """Calculate a delta group, yielding a sequence of changegroup chunks
293 (strings).
308 (strings).
294
309
295 Given a list of changeset revs, return a set of deltas and
310 Given a list of changeset revs, return a set of deltas and
296 metadata corresponding to nodes. The first delta is
311 metadata corresponding to nodes. The first delta is
297 first parent(nodelist[0]) -> nodelist[0], the receiver is
312 first parent(nodelist[0]) -> nodelist[0], the receiver is
298 guaranteed to have this parent as it has all history before
313 guaranteed to have this parent as it has all history before
299 these changesets. In the case firstparent is nullrev the
314 these changesets. In the case firstparent is nullrev the
300 changegroup starts with a full revision.
315 changegroup starts with a full revision.
301
316
302 If units is not None, progress detail will be generated, units specifies
317 If units is not None, progress detail will be generated, units specifies
303 the type of revlog that is touched (changelog, manifest, etc.).
318 the type of revlog that is touched (changelog, manifest, etc.).
304 """
319 """
305 # if we don't have any revisions touched by these changesets, bail
320 # if we don't have any revisions touched by these changesets, bail
306 if len(nodelist) == 0:
321 if len(nodelist) == 0:
307 yield self.close()
322 yield self.close()
308 return
323 return
309
324
310 # for generaldelta revlogs, we linearize the revs; this will both be
325 # for generaldelta revlogs, we linearize the revs; this will both be
311 # much quicker and generate a much smaller bundle
326 # much quicker and generate a much smaller bundle
312 if (revlog._generaldelta and reorder is not False) or reorder:
327 if (revlog._generaldelta and reorder is not False) or reorder:
313 dag = dagutil.revlogdag(revlog)
328 dag = dagutil.revlogdag(revlog)
314 revs = set(revlog.rev(n) for n in nodelist)
329 revs = set(revlog.rev(n) for n in nodelist)
315 revs = dag.linearize(revs)
330 revs = dag.linearize(revs)
316 else:
331 else:
317 revs = sorted([revlog.rev(n) for n in nodelist])
332 revs = sorted([revlog.rev(n) for n in nodelist])
318
333
319 # add the parent of the first rev
334 # add the parent of the first rev
320 p = revlog.parentrevs(revs[0])[0]
335 p = revlog.parentrevs(revs[0])[0]
321 revs.insert(0, p)
336 revs.insert(0, p)
322
337
323 # build deltas
338 # build deltas
324 total = len(revs) - 1
339 total = len(revs) - 1
325 msgbundling = _('bundling')
340 msgbundling = _('bundling')
326 for r in xrange(len(revs) - 1):
341 for r in xrange(len(revs) - 1):
327 if units is not None:
342 if units is not None:
328 self._progress(msgbundling, r + 1, unit=units, total=total)
343 self._progress(msgbundling, r + 1, unit=units, total=total)
329 prev, curr = revs[r], revs[r + 1]
344 prev, curr = revs[r], revs[r + 1]
330 linknode = lookup(revlog.node(curr))
345 linknode = lookup(revlog.node(curr))
331 for c in self.revchunk(revlog, curr, prev, linknode):
346 for c in self.revchunk(revlog, curr, prev, linknode):
332 yield c
347 yield c
333
348
334 yield self.close()
349 yield self.close()
335
350
336 # filter any nodes that claim to be part of the known set
351 # filter any nodes that claim to be part of the known set
337 def prune(self, revlog, missing, commonrevs, source):
352 def prune(self, revlog, missing, commonrevs, source):
338 rr, rl = revlog.rev, revlog.linkrev
353 rr, rl = revlog.rev, revlog.linkrev
339 return [n for n in missing if rl(rr(n)) not in commonrevs]
354 return [n for n in missing if rl(rr(n)) not in commonrevs]
340
355
341 def generate(self, commonrevs, clnodes, fastpathlinkrev, source):
356 def generate(self, commonrevs, clnodes, fastpathlinkrev, source):
342 '''yield a sequence of changegroup chunks (strings)'''
357 '''yield a sequence of changegroup chunks (strings)'''
343 repo = self._repo
358 repo = self._repo
344 cl = self._changelog
359 cl = self._changelog
345 mf = self._manifest
360 mf = self._manifest
346 reorder = self._reorder
361 reorder = self._reorder
347 progress = self._progress
362 progress = self._progress
348
363
349 # for progress output
364 # for progress output
350 msgbundling = _('bundling')
365 msgbundling = _('bundling')
351
366
352 clrevorder = {}
367 clrevorder = {}
353 mfs = {} # needed manifests
368 mfs = {} # needed manifests
354 fnodes = {} # needed file nodes
369 fnodes = {} # needed file nodes
355 changedfiles = set()
370 changedfiles = set()
356
371
357 # Callback for the changelog, used to collect changed files and manifest
372 # Callback for the changelog, used to collect changed files and manifest
358 # nodes.
373 # nodes.
359 # Returns the linkrev node (identity in the changelog case).
374 # Returns the linkrev node (identity in the changelog case).
360 def lookupcl(x):
375 def lookupcl(x):
361 c = cl.read(x)
376 c = cl.read(x)
362 clrevorder[x] = len(clrevorder)
377 clrevorder[x] = len(clrevorder)
363 changedfiles.update(c[3])
378 changedfiles.update(c[3])
364 # record the first changeset introducing this manifest version
379 # record the first changeset introducing this manifest version
365 mfs.setdefault(c[0], x)
380 mfs.setdefault(c[0], x)
366 return x
381 return x
367
382
368 self._verbosenote(_('uncompressed size of bundle content:\n'))
383 self._verbosenote(_('uncompressed size of bundle content:\n'))
369 size = 0
384 size = 0
370 for chunk in self.group(clnodes, cl, lookupcl, units=_('changesets'),
385 for chunk in self.group(clnodes, cl, lookupcl, units=_('changesets'),
371 reorder=reorder):
386 reorder=reorder):
372 size += len(chunk)
387 size += len(chunk)
373 yield chunk
388 yield chunk
374 self._verbosenote(_('%8.i (changelog)\n') % size)
389 self._verbosenote(_('%8.i (changelog)\n') % size)
375 progress(msgbundling, None)
390 progress(msgbundling, None)
376
391
377 # Callback for the manifest, used to collect linkrevs for filelog
392 # Callback for the manifest, used to collect linkrevs for filelog
378 # revisions.
393 # revisions.
379 # Returns the linkrev node (collected in lookupcl).
394 # Returns the linkrev node (collected in lookupcl).
380 def lookupmf(x):
395 def lookupmf(x):
381 clnode = mfs[x]
396 clnode = mfs[x]
382 if not fastpathlinkrev or reorder:
397 if not fastpathlinkrev or reorder:
383 mdata = mf.readfast(x)
398 mdata = mf.readfast(x)
384 for f, n in mdata.iteritems():
399 for f, n in mdata.iteritems():
385 if f in changedfiles:
400 if f in changedfiles:
386 # record the first changeset introducing this filelog
401 # record the first changeset introducing this filelog
387 # version
402 # version
388 fclnodes = fnodes.setdefault(f, {})
403 fclnodes = fnodes.setdefault(f, {})
389 fclnode = fclnodes.setdefault(n, clnode)
404 fclnode = fclnodes.setdefault(n, clnode)
390 if clrevorder[clnode] < clrevorder[fclnode]:
405 if clrevorder[clnode] < clrevorder[fclnode]:
391 fclnodes[n] = clnode
406 fclnodes[n] = clnode
392 return clnode
407 return clnode
393
408
394 mfnodes = self.prune(mf, mfs, commonrevs, source)
409 mfnodes = self.prune(mf, mfs, commonrevs, source)
395 size = 0
410 size = 0
396 for chunk in self.group(mfnodes, mf, lookupmf, units=_('manifests'),
411 for chunk in self.group(mfnodes, mf, lookupmf, units=_('manifests'),
397 reorder=reorder):
412 reorder=reorder):
398 size += len(chunk)
413 size += len(chunk)
399 yield chunk
414 yield chunk
400 self._verbosenote(_('%8.i (manifests)\n') % size)
415 self._verbosenote(_('%8.i (manifests)\n') % size)
401 progress(msgbundling, None)
416 progress(msgbundling, None)
402
417
403 mfs.clear()
418 mfs.clear()
404 needed = set(cl.rev(x) for x in clnodes)
419 needed = set(cl.rev(x) for x in clnodes)
405
420
406 def linknodes(filerevlog, fname):
421 def linknodes(filerevlog, fname):
407 if fastpathlinkrev and not reorder:
422 if fastpathlinkrev and not reorder:
408 llr = filerevlog.linkrev
423 llr = filerevlog.linkrev
409 def genfilenodes():
424 def genfilenodes():
410 for r in filerevlog:
425 for r in filerevlog:
411 linkrev = llr(r)
426 linkrev = llr(r)
412 if linkrev in needed:
427 if linkrev in needed:
413 yield filerevlog.node(r), cl.node(linkrev)
428 yield filerevlog.node(r), cl.node(linkrev)
414 return dict(genfilenodes())
429 return dict(genfilenodes())
415 return fnodes.get(fname, {})
430 return fnodes.get(fname, {})
416
431
417 for chunk in self.generatefiles(changedfiles, linknodes, commonrevs,
432 for chunk in self.generatefiles(changedfiles, linknodes, commonrevs,
418 source):
433 source):
419 yield chunk
434 yield chunk
420
435
421 yield self.close()
436 yield self.close()
422 progress(msgbundling, None)
437 progress(msgbundling, None)
423
438
424 if clnodes:
439 if clnodes:
425 repo.hook('outgoing', node=hex(clnodes[0]), source=source)
440 repo.hook('outgoing', node=hex(clnodes[0]), source=source)
426
441
427 def generatefiles(self, changedfiles, linknodes, commonrevs, source):
442 def generatefiles(self, changedfiles, linknodes, commonrevs, source):
428 repo = self._repo
443 repo = self._repo
429 progress = self._progress
444 progress = self._progress
430 reorder = self._reorder
445 reorder = self._reorder
431 msgbundling = _('bundling')
446 msgbundling = _('bundling')
432
447
433 total = len(changedfiles)
448 total = len(changedfiles)
434 # for progress output
449 # for progress output
435 msgfiles = _('files')
450 msgfiles = _('files')
436 for i, fname in enumerate(sorted(changedfiles)):
451 for i, fname in enumerate(sorted(changedfiles)):
437 filerevlog = repo.file(fname)
452 filerevlog = repo.file(fname)
438 if not filerevlog:
453 if not filerevlog:
439 raise util.Abort(_("empty or missing revlog for %s") % fname)
454 raise util.Abort(_("empty or missing revlog for %s") % fname)
440
455
441 linkrevnodes = linknodes(filerevlog, fname)
456 linkrevnodes = linknodes(filerevlog, fname)
442 # Lookup for filenodes, we collected the linkrev nodes above in the
457 # Lookup for filenodes, we collected the linkrev nodes above in the
443 # fastpath case and with lookupmf in the slowpath case.
458 # fastpath case and with lookupmf in the slowpath case.
444 def lookupfilelog(x):
459 def lookupfilelog(x):
445 return linkrevnodes[x]
460 return linkrevnodes[x]
446
461
447 filenodes = self.prune(filerevlog, linkrevnodes, commonrevs, source)
462 filenodes = self.prune(filerevlog, linkrevnodes, commonrevs, source)
448 if filenodes:
463 if filenodes:
449 progress(msgbundling, i + 1, item=fname, unit=msgfiles,
464 progress(msgbundling, i + 1, item=fname, unit=msgfiles,
450 total=total)
465 total=total)
451 h = self.fileheader(fname)
466 h = self.fileheader(fname)
452 size = len(h)
467 size = len(h)
453 yield h
468 yield h
454 for chunk in self.group(filenodes, filerevlog, lookupfilelog,
469 for chunk in self.group(filenodes, filerevlog, lookupfilelog,
455 reorder=reorder):
470 reorder=reorder):
456 size += len(chunk)
471 size += len(chunk)
457 yield chunk
472 yield chunk
458 self._verbosenote(_('%8.i %s\n') % (size, fname))
473 self._verbosenote(_('%8.i %s\n') % (size, fname))
459
474
460 def deltaparent(self, revlog, rev, p1, p2, prev):
475 def deltaparent(self, revlog, rev, p1, p2, prev):
461 return prev
476 return prev
462
477
463 def revchunk(self, revlog, rev, prev, linknode):
478 def revchunk(self, revlog, rev, prev, linknode):
464 node = revlog.node(rev)
479 node = revlog.node(rev)
465 p1, p2 = revlog.parentrevs(rev)
480 p1, p2 = revlog.parentrevs(rev)
466 base = self.deltaparent(revlog, rev, p1, p2, prev)
481 base = self.deltaparent(revlog, rev, p1, p2, prev)
467
482
468 prefix = ''
483 prefix = ''
469 if base == nullrev:
484 if base == nullrev:
470 delta = revlog.revision(node)
485 delta = revlog.revision(node)
471 prefix = mdiff.trivialdiffheader(len(delta))
486 prefix = mdiff.trivialdiffheader(len(delta))
472 else:
487 else:
473 delta = revlog.revdiff(base, rev)
488 delta = revlog.revdiff(base, rev)
474 p1n, p2n = revlog.parents(node)
489 p1n, p2n = revlog.parents(node)
475 basenode = revlog.node(base)
490 basenode = revlog.node(base)
476 meta = self.builddeltaheader(node, p1n, p2n, basenode, linknode)
491 meta = self.builddeltaheader(node, p1n, p2n, basenode, linknode)
477 meta += prefix
492 meta += prefix
478 l = len(meta) + len(delta)
493 l = len(meta) + len(delta)
479 yield chunkheader(l)
494 yield chunkheader(l)
480 yield meta
495 yield meta
481 yield delta
496 yield delta
482 def builddeltaheader(self, node, p1n, p2n, basenode, linknode):
497 def builddeltaheader(self, node, p1n, p2n, basenode, linknode):
483 # do nothing with basenode, it is implicitly the previous one in HG10
498 # do nothing with basenode, it is implicitly the previous one in HG10
484 return struct.pack(self.deltaheader, node, p1n, p2n, linknode)
499 return struct.pack(self.deltaheader, node, p1n, p2n, linknode)
485
500
486 class cg2packer(cg1packer):
501 class cg2packer(cg1packer):
487
502 version = '02'
488 deltaheader = _CHANGEGROUPV2_DELTA_HEADER
503 deltaheader = _CHANGEGROUPV2_DELTA_HEADER
489
504
490 def group(self, nodelist, revlog, lookup, units=None, reorder=None):
505 def group(self, nodelist, revlog, lookup, units=None, reorder=None):
491 if (revlog._generaldelta and reorder is not True):
506 if (revlog._generaldelta and reorder is not True):
492 reorder = False
507 reorder = False
493 return super(cg2packer, self).group(nodelist, revlog, lookup,
508 return super(cg2packer, self).group(nodelist, revlog, lookup,
494 units=units, reorder=reorder)
509 units=units, reorder=reorder)
495
510
496 def deltaparent(self, revlog, rev, p1, p2, prev):
511 def deltaparent(self, revlog, rev, p1, p2, prev):
497 dp = revlog.deltaparent(rev)
512 dp = revlog.deltaparent(rev)
498 # avoid storing full revisions; pick prev in those cases
513 # avoid storing full revisions; pick prev in those cases
499 # also pick prev when we can't be sure remote has dp
514 # also pick prev when we can't be sure remote has dp
500 if dp == nullrev or (dp != p1 and dp != p2 and dp != prev):
515 if dp == nullrev or (dp != p1 and dp != p2 and dp != prev):
501 return prev
516 return prev
502 return dp
517 return dp
503
518
504 def builddeltaheader(self, node, p1n, p2n, basenode, linknode):
519 def builddeltaheader(self, node, p1n, p2n, basenode, linknode):
505 return struct.pack(self.deltaheader, node, p1n, p2n, basenode, linknode)
520 return struct.pack(self.deltaheader, node, p1n, p2n, basenode, linknode)
506
521
507 packermap = {'01': (cg1packer, cg1unpacker),
522 packermap = {'01': (cg1packer, cg1unpacker),
508 '02': (cg2packer, cg2unpacker)}
523 '02': (cg2packer, cg2unpacker)}
509
524
510 def _changegroupinfo(repo, nodes, source):
525 def _changegroupinfo(repo, nodes, source):
511 if repo.ui.verbose or source == 'bundle':
526 if repo.ui.verbose or source == 'bundle':
512 repo.ui.status(_("%d changesets found\n") % len(nodes))
527 repo.ui.status(_("%d changesets found\n") % len(nodes))
513 if repo.ui.debugflag:
528 if repo.ui.debugflag:
514 repo.ui.debug("list of changesets:\n")
529 repo.ui.debug("list of changesets:\n")
515 for node in nodes:
530 for node in nodes:
516 repo.ui.debug("%s\n" % hex(node))
531 repo.ui.debug("%s\n" % hex(node))
517
532
518 def getsubsetraw(repo, outgoing, bundler, source, fastpath=False):
533 def getsubsetraw(repo, outgoing, bundler, source, fastpath=False):
519 repo = repo.unfiltered()
534 repo = repo.unfiltered()
520 commonrevs = outgoing.common
535 commonrevs = outgoing.common
521 csets = outgoing.missing
536 csets = outgoing.missing
522 heads = outgoing.missingheads
537 heads = outgoing.missingheads
523 # We go through the fast path if we get told to, or if all (unfiltered
538 # We go through the fast path if we get told to, or if all (unfiltered
524 # heads have been requested (since we then know there all linkrevs will
539 # heads have been requested (since we then know there all linkrevs will
525 # be pulled by the client).
540 # be pulled by the client).
526 heads.sort()
541 heads.sort()
527 fastpathlinkrev = fastpath or (
542 fastpathlinkrev = fastpath or (
528 repo.filtername is None and heads == sorted(repo.heads()))
543 repo.filtername is None and heads == sorted(repo.heads()))
529
544
530 repo.hook('preoutgoing', throw=True, source=source)
545 repo.hook('preoutgoing', throw=True, source=source)
531 _changegroupinfo(repo, csets, source)
546 _changegroupinfo(repo, csets, source)
532 return bundler.generate(commonrevs, csets, fastpathlinkrev, source)
547 return bundler.generate(commonrevs, csets, fastpathlinkrev, source)
533
548
534 def getsubset(repo, outgoing, bundler, source, fastpath=False):
549 def getsubset(repo, outgoing, bundler, source, fastpath=False):
535 gengroup = getsubsetraw(repo, outgoing, bundler, source, fastpath)
550 gengroup = getsubsetraw(repo, outgoing, bundler, source, fastpath)
536 return cg1unpacker(util.chunkbuffer(gengroup), 'UN')
551 return cg1unpacker(util.chunkbuffer(gengroup), 'UN')
537
552
538 def changegroupsubset(repo, roots, heads, source):
553 def changegroupsubset(repo, roots, heads, source):
539 """Compute a changegroup consisting of all the nodes that are
554 """Compute a changegroup consisting of all the nodes that are
540 descendants of any of the roots and ancestors of any of the heads.
555 descendants of any of the roots and ancestors of any of the heads.
541 Return a chunkbuffer object whose read() method will return
556 Return a chunkbuffer object whose read() method will return
542 successive changegroup chunks.
557 successive changegroup chunks.
543
558
544 It is fairly complex as determining which filenodes and which
559 It is fairly complex as determining which filenodes and which
545 manifest nodes need to be included for the changeset to be complete
560 manifest nodes need to be included for the changeset to be complete
546 is non-trivial.
561 is non-trivial.
547
562
548 Another wrinkle is doing the reverse, figuring out which changeset in
563 Another wrinkle is doing the reverse, figuring out which changeset in
549 the changegroup a particular filenode or manifestnode belongs to.
564 the changegroup a particular filenode or manifestnode belongs to.
550 """
565 """
551 cl = repo.changelog
566 cl = repo.changelog
552 if not roots:
567 if not roots:
553 roots = [nullid]
568 roots = [nullid]
554 # TODO: remove call to nodesbetween.
569 # TODO: remove call to nodesbetween.
555 csets, roots, heads = cl.nodesbetween(roots, heads)
570 csets, roots, heads = cl.nodesbetween(roots, heads)
556 discbases = []
571 discbases = []
557 for n in roots:
572 for n in roots:
558 discbases.extend([p for p in cl.parents(n) if p != nullid])
573 discbases.extend([p for p in cl.parents(n) if p != nullid])
559 outgoing = discovery.outgoing(cl, discbases, heads)
574 outgoing = discovery.outgoing(cl, discbases, heads)
560 bundler = cg1packer(repo)
575 bundler = cg1packer(repo)
561 return getsubset(repo, outgoing, bundler, source)
576 return getsubset(repo, outgoing, bundler, source)
562
577
563 def getlocalchangegroupraw(repo, source, outgoing, bundlecaps=None,
578 def getlocalchangegroupraw(repo, source, outgoing, bundlecaps=None,
564 version='01'):
579 version='01'):
565 """Like getbundle, but taking a discovery.outgoing as an argument.
580 """Like getbundle, but taking a discovery.outgoing as an argument.
566
581
567 This is only implemented for local repos and reuses potentially
582 This is only implemented for local repos and reuses potentially
568 precomputed sets in outgoing. Returns a raw changegroup generator."""
583 precomputed sets in outgoing. Returns a raw changegroup generator."""
569 if not outgoing.missing:
584 if not outgoing.missing:
570 return None
585 return None
571 bundler = packermap[version][0](repo, bundlecaps)
586 bundler = packermap[version][0](repo, bundlecaps)
572 return getsubsetraw(repo, outgoing, bundler, source)
587 return getsubsetraw(repo, outgoing, bundler, source)
573
588
574 def getlocalchangegroup(repo, source, outgoing, bundlecaps=None):
589 def getlocalchangegroup(repo, source, outgoing, bundlecaps=None):
575 """Like getbundle, but taking a discovery.outgoing as an argument.
590 """Like getbundle, but taking a discovery.outgoing as an argument.
576
591
577 This is only implemented for local repos and reuses potentially
592 This is only implemented for local repos and reuses potentially
578 precomputed sets in outgoing."""
593 precomputed sets in outgoing."""
579 if not outgoing.missing:
594 if not outgoing.missing:
580 return None
595 return None
581 bundler = cg1packer(repo, bundlecaps)
596 bundler = cg1packer(repo, bundlecaps)
582 return getsubset(repo, outgoing, bundler, source)
597 return getsubset(repo, outgoing, bundler, source)
583
598
584 def _computeoutgoing(repo, heads, common):
599 def _computeoutgoing(repo, heads, common):
585 """Computes which revs are outgoing given a set of common
600 """Computes which revs are outgoing given a set of common
586 and a set of heads.
601 and a set of heads.
587
602
588 This is a separate function so extensions can have access to
603 This is a separate function so extensions can have access to
589 the logic.
604 the logic.
590
605
591 Returns a discovery.outgoing object.
606 Returns a discovery.outgoing object.
592 """
607 """
593 cl = repo.changelog
608 cl = repo.changelog
594 if common:
609 if common:
595 hasnode = cl.hasnode
610 hasnode = cl.hasnode
596 common = [n for n in common if hasnode(n)]
611 common = [n for n in common if hasnode(n)]
597 else:
612 else:
598 common = [nullid]
613 common = [nullid]
599 if not heads:
614 if not heads:
600 heads = cl.heads()
615 heads = cl.heads()
601 return discovery.outgoing(cl, common, heads)
616 return discovery.outgoing(cl, common, heads)
602
617
603 def getchangegroupraw(repo, source, heads=None, common=None, bundlecaps=None,
618 def getchangegroupraw(repo, source, heads=None, common=None, bundlecaps=None,
604 version='01'):
619 version='01'):
605 """Like changegroupsubset, but returns the set difference between the
620 """Like changegroupsubset, but returns the set difference between the
606 ancestors of heads and the ancestors common.
621 ancestors of heads and the ancestors common.
607
622
608 If heads is None, use the local heads. If common is None, use [nullid].
623 If heads is None, use the local heads. If common is None, use [nullid].
609
624
610 If version is None, use a version '1' changegroup.
625 If version is None, use a version '1' changegroup.
611
626
612 The nodes in common might not all be known locally due to the way the
627 The nodes in common might not all be known locally due to the way the
613 current discovery protocol works. Returns a raw changegroup generator.
628 current discovery protocol works. Returns a raw changegroup generator.
614 """
629 """
615 outgoing = _computeoutgoing(repo, heads, common)
630 outgoing = _computeoutgoing(repo, heads, common)
616 return getlocalchangegroupraw(repo, source, outgoing, bundlecaps=bundlecaps,
631 return getlocalchangegroupraw(repo, source, outgoing, bundlecaps=bundlecaps,
617 version=version)
632 version=version)
618
633
619 def getchangegroup(repo, source, heads=None, common=None, bundlecaps=None):
634 def getchangegroup(repo, source, heads=None, common=None, bundlecaps=None):
620 """Like changegroupsubset, but returns the set difference between the
635 """Like changegroupsubset, but returns the set difference between the
621 ancestors of heads and the ancestors common.
636 ancestors of heads and the ancestors common.
622
637
623 If heads is None, use the local heads. If common is None, use [nullid].
638 If heads is None, use the local heads. If common is None, use [nullid].
624
639
625 The nodes in common might not all be known locally due to the way the
640 The nodes in common might not all be known locally due to the way the
626 current discovery protocol works.
641 current discovery protocol works.
627 """
642 """
628 outgoing = _computeoutgoing(repo, heads, common)
643 outgoing = _computeoutgoing(repo, heads, common)
629 return getlocalchangegroup(repo, source, outgoing, bundlecaps=bundlecaps)
644 return getlocalchangegroup(repo, source, outgoing, bundlecaps=bundlecaps)
630
645
631 def changegroup(repo, basenodes, source):
646 def changegroup(repo, basenodes, source):
632 # to avoid a race we use changegroupsubset() (issue1320)
647 # to avoid a race we use changegroupsubset() (issue1320)
633 return changegroupsubset(repo, basenodes, repo.heads(), source)
648 return changegroupsubset(repo, basenodes, repo.heads(), source)
634
649
635 def addchangegroupfiles(repo, source, revmap, trp, pr, needfiles):
650 def addchangegroupfiles(repo, source, revmap, trp, pr, needfiles):
636 revisions = 0
651 revisions = 0
637 files = 0
652 files = 0
638 while True:
653 while True:
639 chunkdata = source.filelogheader()
654 chunkdata = source.filelogheader()
640 if not chunkdata:
655 if not chunkdata:
641 break
656 break
642 f = chunkdata["filename"]
657 f = chunkdata["filename"]
643 repo.ui.debug("adding %s revisions\n" % f)
658 repo.ui.debug("adding %s revisions\n" % f)
644 pr()
659 pr()
645 fl = repo.file(f)
660 fl = repo.file(f)
646 o = len(fl)
661 o = len(fl)
647 if not fl.addgroup(source, revmap, trp):
662 if not fl.addgroup(source, revmap, trp):
648 raise util.Abort(_("received file revlog group is empty"))
663 raise util.Abort(_("received file revlog group is empty"))
649 revisions += len(fl) - o
664 revisions += len(fl) - o
650 files += 1
665 files += 1
651 if f in needfiles:
666 if f in needfiles:
652 needs = needfiles[f]
667 needs = needfiles[f]
653 for new in xrange(o, len(fl)):
668 for new in xrange(o, len(fl)):
654 n = fl.node(new)
669 n = fl.node(new)
655 if n in needs:
670 if n in needs:
656 needs.remove(n)
671 needs.remove(n)
657 else:
672 else:
658 raise util.Abort(
673 raise util.Abort(
659 _("received spurious file revlog entry"))
674 _("received spurious file revlog entry"))
660 if not needs:
675 if not needs:
661 del needfiles[f]
676 del needfiles[f]
662 repo.ui.progress(_('files'), None)
677 repo.ui.progress(_('files'), None)
663
678
664 for f, needs in needfiles.iteritems():
679 for f, needs in needfiles.iteritems():
665 fl = repo.file(f)
680 fl = repo.file(f)
666 for n in needs:
681 for n in needs:
667 try:
682 try:
668 fl.rev(n)
683 fl.rev(n)
669 except error.LookupError:
684 except error.LookupError:
670 raise util.Abort(
685 raise util.Abort(
671 _('missing file data for %s:%s - run hg verify') %
686 _('missing file data for %s:%s - run hg verify') %
672 (f, hex(n)))
687 (f, hex(n)))
673
688
674 return revisions, files
689 return revisions, files
675
690
676 def addchangegroup(repo, source, srctype, url, emptyok=False,
691 def addchangegroup(repo, source, srctype, url, emptyok=False,
677 targetphase=phases.draft):
692 targetphase=phases.draft):
678 """Add the changegroup returned by source.read() to this repo.
693 """Add the changegroup returned by source.read() to this repo.
679 srctype is a string like 'push', 'pull', or 'unbundle'. url is
694 srctype is a string like 'push', 'pull', or 'unbundle'. url is
680 the URL of the repo where this changegroup is coming from.
695 the URL of the repo where this changegroup is coming from.
681
696
682 Return an integer summarizing the change to this repo:
697 Return an integer summarizing the change to this repo:
683 - nothing changed or no source: 0
698 - nothing changed or no source: 0
684 - more heads than before: 1+added heads (2..n)
699 - more heads than before: 1+added heads (2..n)
685 - fewer heads than before: -1-removed heads (-2..-n)
700 - fewer heads than before: -1-removed heads (-2..-n)
686 - number of heads stays the same: 1
701 - number of heads stays the same: 1
687 """
702 """
688 repo = repo.unfiltered()
703 repo = repo.unfiltered()
689 def csmap(x):
704 def csmap(x):
690 repo.ui.debug("add changeset %s\n" % short(x))
705 repo.ui.debug("add changeset %s\n" % short(x))
691 return len(cl)
706 return len(cl)
692
707
693 def revmap(x):
708 def revmap(x):
694 return cl.rev(x)
709 return cl.rev(x)
695
710
696 if not source:
711 if not source:
697 return 0
712 return 0
698
713
699 changesets = files = revisions = 0
714 changesets = files = revisions = 0
700 efiles = set()
715 efiles = set()
701
716
702 tr = repo.transaction("\n".join([srctype, util.hidepassword(url)]))
717 tr = repo.transaction("\n".join([srctype, util.hidepassword(url)]))
703 # The transaction could have been created before and already carries source
718 # The transaction could have been created before and already carries source
704 # information. In this case we use the top level data. We overwrite the
719 # information. In this case we use the top level data. We overwrite the
705 # argument because we need to use the top level value (if they exist) in
720 # argument because we need to use the top level value (if they exist) in
706 # this function.
721 # this function.
707 srctype = tr.hookargs.setdefault('source', srctype)
722 srctype = tr.hookargs.setdefault('source', srctype)
708 url = tr.hookargs.setdefault('url', url)
723 url = tr.hookargs.setdefault('url', url)
709
724
710 # write changelog data to temp files so concurrent readers will not see
725 # write changelog data to temp files so concurrent readers will not see
711 # inconsistent view
726 # inconsistent view
712 cl = repo.changelog
727 cl = repo.changelog
713 cl.delayupdate(tr)
728 cl.delayupdate(tr)
714 oldheads = cl.heads()
729 oldheads = cl.heads()
715 try:
730 try:
716 repo.hook('prechangegroup', throw=True, **tr.hookargs)
731 repo.hook('prechangegroup', throw=True, **tr.hookargs)
717
732
718 trp = weakref.proxy(tr)
733 trp = weakref.proxy(tr)
719 # pull off the changeset group
734 # pull off the changeset group
720 repo.ui.status(_("adding changesets\n"))
735 repo.ui.status(_("adding changesets\n"))
721 clstart = len(cl)
736 clstart = len(cl)
722 class prog(object):
737 class prog(object):
723 step = _('changesets')
738 step = _('changesets')
724 count = 1
739 count = 1
725 ui = repo.ui
740 ui = repo.ui
726 total = None
741 total = None
727 def __call__(repo):
742 def __call__(repo):
728 repo.ui.progress(repo.step, repo.count, unit=_('chunks'),
743 repo.ui.progress(repo.step, repo.count, unit=_('chunks'),
729 total=repo.total)
744 total=repo.total)
730 repo.count += 1
745 repo.count += 1
731 pr = prog()
746 pr = prog()
732 source.callback = pr
747 source.callback = pr
733
748
734 source.changelogheader()
749 source.changelogheader()
735 srccontent = cl.addgroup(source, csmap, trp)
750 srccontent = cl.addgroup(source, csmap, trp)
736 if not (srccontent or emptyok):
751 if not (srccontent or emptyok):
737 raise util.Abort(_("received changelog group is empty"))
752 raise util.Abort(_("received changelog group is empty"))
738 clend = len(cl)
753 clend = len(cl)
739 changesets = clend - clstart
754 changesets = clend - clstart
740 for c in xrange(clstart, clend):
755 for c in xrange(clstart, clend):
741 efiles.update(repo[c].files())
756 efiles.update(repo[c].files())
742 efiles = len(efiles)
757 efiles = len(efiles)
743 repo.ui.progress(_('changesets'), None)
758 repo.ui.progress(_('changesets'), None)
744
759
745 # pull off the manifest group
760 # pull off the manifest group
746 repo.ui.status(_("adding manifests\n"))
761 repo.ui.status(_("adding manifests\n"))
747 pr.step = _('manifests')
762 pr.step = _('manifests')
748 pr.count = 1
763 pr.count = 1
749 pr.total = changesets # manifests <= changesets
764 pr.total = changesets # manifests <= changesets
750 # no need to check for empty manifest group here:
765 # no need to check for empty manifest group here:
751 # if the result of the merge of 1 and 2 is the same in 3 and 4,
766 # if the result of the merge of 1 and 2 is the same in 3 and 4,
752 # no new manifest will be created and the manifest group will
767 # no new manifest will be created and the manifest group will
753 # be empty during the pull
768 # be empty during the pull
754 source.manifestheader()
769 source.manifestheader()
755 repo.manifest.addgroup(source, revmap, trp)
770 repo.manifest.addgroup(source, revmap, trp)
756 repo.ui.progress(_('manifests'), None)
771 repo.ui.progress(_('manifests'), None)
757
772
758 needfiles = {}
773 needfiles = {}
759 if repo.ui.configbool('server', 'validate', default=False):
774 if repo.ui.configbool('server', 'validate', default=False):
760 # validate incoming csets have their manifests
775 # validate incoming csets have their manifests
761 for cset in xrange(clstart, clend):
776 for cset in xrange(clstart, clend):
762 mfest = repo.changelog.read(repo.changelog.node(cset))[0]
777 mfest = repo.changelog.read(repo.changelog.node(cset))[0]
763 mfest = repo.manifest.readdelta(mfest)
778 mfest = repo.manifest.readdelta(mfest)
764 # store file nodes we must see
779 # store file nodes we must see
765 for f, n in mfest.iteritems():
780 for f, n in mfest.iteritems():
766 needfiles.setdefault(f, set()).add(n)
781 needfiles.setdefault(f, set()).add(n)
767
782
768 # process the files
783 # process the files
769 repo.ui.status(_("adding file changes\n"))
784 repo.ui.status(_("adding file changes\n"))
770 pr.step = _('files')
785 pr.step = _('files')
771 pr.count = 1
786 pr.count = 1
772 pr.total = efiles
787 pr.total = efiles
773 source.callback = None
788 source.callback = None
774
789
775 newrevs, newfiles = addchangegroupfiles(repo, source, revmap, trp, pr,
790 newrevs, newfiles = addchangegroupfiles(repo, source, revmap, trp, pr,
776 needfiles)
791 needfiles)
777 revisions += newrevs
792 revisions += newrevs
778 files += newfiles
793 files += newfiles
779
794
780 dh = 0
795 dh = 0
781 if oldheads:
796 if oldheads:
782 heads = cl.heads()
797 heads = cl.heads()
783 dh = len(heads) - len(oldheads)
798 dh = len(heads) - len(oldheads)
784 for h in heads:
799 for h in heads:
785 if h not in oldheads and repo[h].closesbranch():
800 if h not in oldheads and repo[h].closesbranch():
786 dh -= 1
801 dh -= 1
787 htext = ""
802 htext = ""
788 if dh:
803 if dh:
789 htext = _(" (%+d heads)") % dh
804 htext = _(" (%+d heads)") % dh
790
805
791 repo.ui.status(_("added %d changesets"
806 repo.ui.status(_("added %d changesets"
792 " with %d changes to %d files%s\n")
807 " with %d changes to %d files%s\n")
793 % (changesets, revisions, files, htext))
808 % (changesets, revisions, files, htext))
794 repo.invalidatevolatilesets()
809 repo.invalidatevolatilesets()
795
810
796 if changesets > 0:
811 if changesets > 0:
797 p = lambda: tr.writepending() and repo.root or ""
812 p = lambda: tr.writepending() and repo.root or ""
798 if 'node' not in tr.hookargs:
813 if 'node' not in tr.hookargs:
799 tr.hookargs['node'] = hex(cl.node(clstart))
814 tr.hookargs['node'] = hex(cl.node(clstart))
800 hookargs = dict(tr.hookargs)
815 hookargs = dict(tr.hookargs)
801 else:
816 else:
802 hookargs = dict(tr.hookargs)
817 hookargs = dict(tr.hookargs)
803 hookargs['node'] = hex(cl.node(clstart))
818 hookargs['node'] = hex(cl.node(clstart))
804 repo.hook('pretxnchangegroup', throw=True, pending=p, **hookargs)
819 repo.hook('pretxnchangegroup', throw=True, pending=p, **hookargs)
805
820
806 added = [cl.node(r) for r in xrange(clstart, clend)]
821 added = [cl.node(r) for r in xrange(clstart, clend)]
807 publishing = repo.ui.configbool('phases', 'publish', True)
822 publishing = repo.ui.configbool('phases', 'publish', True)
808 if srctype in ('push', 'serve'):
823 if srctype in ('push', 'serve'):
809 # Old servers can not push the boundary themselves.
824 # Old servers can not push the boundary themselves.
810 # New servers won't push the boundary if changeset already
825 # New servers won't push the boundary if changeset already
811 # exists locally as secret
826 # exists locally as secret
812 #
827 #
813 # We should not use added here but the list of all change in
828 # We should not use added here but the list of all change in
814 # the bundle
829 # the bundle
815 if publishing:
830 if publishing:
816 phases.advanceboundary(repo, tr, phases.public, srccontent)
831 phases.advanceboundary(repo, tr, phases.public, srccontent)
817 else:
832 else:
818 # Those changesets have been pushed from the outside, their
833 # Those changesets have been pushed from the outside, their
819 # phases are going to be pushed alongside. Therefor
834 # phases are going to be pushed alongside. Therefor
820 # `targetphase` is ignored.
835 # `targetphase` is ignored.
821 phases.advanceboundary(repo, tr, phases.draft, srccontent)
836 phases.advanceboundary(repo, tr, phases.draft, srccontent)
822 phases.retractboundary(repo, tr, phases.draft, added)
837 phases.retractboundary(repo, tr, phases.draft, added)
823 elif srctype != 'strip':
838 elif srctype != 'strip':
824 # publishing only alter behavior during push
839 # publishing only alter behavior during push
825 #
840 #
826 # strip should not touch boundary at all
841 # strip should not touch boundary at all
827 phases.retractboundary(repo, tr, targetphase, added)
842 phases.retractboundary(repo, tr, targetphase, added)
828
843
829 if changesets > 0:
844 if changesets > 0:
830 if srctype != 'strip':
845 if srctype != 'strip':
831 # During strip, branchcache is invalid but coming call to
846 # During strip, branchcache is invalid but coming call to
832 # `destroyed` will repair it.
847 # `destroyed` will repair it.
833 # In other case we can safely update cache on disk.
848 # In other case we can safely update cache on disk.
834 branchmap.updatecache(repo.filtered('served'))
849 branchmap.updatecache(repo.filtered('served'))
835
850
836 def runhooks():
851 def runhooks():
837 # These hooks run when the lock releases, not when the
852 # These hooks run when the lock releases, not when the
838 # transaction closes. So it's possible for the changelog
853 # transaction closes. So it's possible for the changelog
839 # to have changed since we last saw it.
854 # to have changed since we last saw it.
840 if clstart >= len(repo):
855 if clstart >= len(repo):
841 return
856 return
842
857
843 # forcefully update the on-disk branch cache
858 # forcefully update the on-disk branch cache
844 repo.ui.debug("updating the branch cache\n")
859 repo.ui.debug("updating the branch cache\n")
845 repo.hook("changegroup", **hookargs)
860 repo.hook("changegroup", **hookargs)
846
861
847 for n in added:
862 for n in added:
848 args = hookargs.copy()
863 args = hookargs.copy()
849 args['node'] = hex(n)
864 args['node'] = hex(n)
850 repo.hook("incoming", **args)
865 repo.hook("incoming", **args)
851
866
852 newheads = [h for h in repo.heads() if h not in oldheads]
867 newheads = [h for h in repo.heads() if h not in oldheads]
853 repo.ui.log("incoming",
868 repo.ui.log("incoming",
854 "%s incoming changes - new heads: %s\n",
869 "%s incoming changes - new heads: %s\n",
855 len(added),
870 len(added),
856 ', '.join([hex(c[:6]) for c in newheads]))
871 ', '.join([hex(c[:6]) for c in newheads]))
857
872
858 tr.addpostclose('changegroup-runhooks-%020i' % clstart,
873 tr.addpostclose('changegroup-runhooks-%020i' % clstart,
859 lambda tr: repo._afterlock(runhooks))
874 lambda tr: repo._afterlock(runhooks))
860
875
861 tr.close()
876 tr.close()
862
877
863 finally:
878 finally:
864 tr.release()
879 tr.release()
865 # never return 0 here:
880 # never return 0 here:
866 if dh < 0:
881 if dh < 0:
867 return dh - 1
882 return dh - 1
868 else:
883 else:
869 return dh + 1
884 return dh + 1
@@ -1,6317 +1,6323 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 _
10 from i18n import _
11 import os, re, difflib, time, tempfile, errno, shlex
11 import os, re, difflib, time, tempfile, errno, shlex
12 import sys, socket
12 import sys, socket
13 import hg, scmutil, util, revlog, copies, error, bookmarks
13 import hg, scmutil, util, revlog, copies, error, bookmarks
14 import patch, help, encoding, templatekw, discovery
14 import patch, help, encoding, templatekw, discovery
15 import archival, changegroup, cmdutil, hbisect
15 import archival, changegroup, cmdutil, hbisect
16 import sshserver, hgweb, commandserver
16 import sshserver, hgweb, commandserver
17 import extensions
17 import extensions
18 from hgweb import server as hgweb_server
18 from hgweb import server as hgweb_server
19 import merge as mergemod
19 import merge as mergemod
20 import minirst, revset, fileset
20 import minirst, revset, fileset
21 import dagparser, context, simplemerge, graphmod, copies
21 import dagparser, context, simplemerge, graphmod, copies
22 import random
22 import random
23 import setdiscovery, treediscovery, dagutil, pvec, localrepo
23 import setdiscovery, treediscovery, dagutil, pvec, localrepo
24 import phases, obsolete, exchange, bundle2
24 import phases, obsolete, exchange, bundle2
25 import ui as uimod
25 import ui as uimod
26
26
27 table = {}
27 table = {}
28
28
29 command = cmdutil.command(table)
29 command = cmdutil.command(table)
30
30
31 # Space delimited list of commands that don't require local repositories.
31 # Space delimited list of commands that don't require local repositories.
32 # This should be populated by passing norepo=True into the @command decorator.
32 # This should be populated by passing norepo=True into the @command decorator.
33 norepo = ''
33 norepo = ''
34 # Space delimited list of commands that optionally require local repositories.
34 # Space delimited list of commands that optionally require local repositories.
35 # This should be populated by passing optionalrepo=True into the @command
35 # This should be populated by passing optionalrepo=True into the @command
36 # decorator.
36 # decorator.
37 optionalrepo = ''
37 optionalrepo = ''
38 # Space delimited list of commands that will examine arguments looking for
38 # Space delimited list of commands that will examine arguments looking for
39 # a repository. This should be populated by passing inferrepo=True into the
39 # a repository. This should be populated by passing inferrepo=True into the
40 # @command decorator.
40 # @command decorator.
41 inferrepo = ''
41 inferrepo = ''
42
42
43 # common command options
43 # common command options
44
44
45 globalopts = [
45 globalopts = [
46 ('R', 'repository', '',
46 ('R', 'repository', '',
47 _('repository root directory or name of overlay bundle file'),
47 _('repository root directory or name of overlay bundle file'),
48 _('REPO')),
48 _('REPO')),
49 ('', 'cwd', '',
49 ('', 'cwd', '',
50 _('change working directory'), _('DIR')),
50 _('change working directory'), _('DIR')),
51 ('y', 'noninteractive', None,
51 ('y', 'noninteractive', None,
52 _('do not prompt, automatically pick the first choice for all prompts')),
52 _('do not prompt, automatically pick the first choice for all prompts')),
53 ('q', 'quiet', None, _('suppress output')),
53 ('q', 'quiet', None, _('suppress output')),
54 ('v', 'verbose', None, _('enable additional output')),
54 ('v', 'verbose', None, _('enable additional output')),
55 ('', 'config', [],
55 ('', 'config', [],
56 _('set/override config option (use \'section.name=value\')'),
56 _('set/override config option (use \'section.name=value\')'),
57 _('CONFIG')),
57 _('CONFIG')),
58 ('', 'debug', None, _('enable debugging output')),
58 ('', 'debug', None, _('enable debugging output')),
59 ('', 'debugger', None, _('start debugger')),
59 ('', 'debugger', None, _('start debugger')),
60 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
60 ('', 'encoding', encoding.encoding, _('set the charset encoding'),
61 _('ENCODE')),
61 _('ENCODE')),
62 ('', 'encodingmode', encoding.encodingmode,
62 ('', 'encodingmode', encoding.encodingmode,
63 _('set the charset encoding mode'), _('MODE')),
63 _('set the charset encoding mode'), _('MODE')),
64 ('', 'traceback', None, _('always print a traceback on exception')),
64 ('', 'traceback', None, _('always print a traceback on exception')),
65 ('', 'time', None, _('time how long the command takes')),
65 ('', 'time', None, _('time how long the command takes')),
66 ('', 'profile', None, _('print command execution profile')),
66 ('', 'profile', None, _('print command execution profile')),
67 ('', 'version', None, _('output version information and exit')),
67 ('', 'version', None, _('output version information and exit')),
68 ('h', 'help', None, _('display help and exit')),
68 ('h', 'help', None, _('display help and exit')),
69 ('', 'hidden', False, _('consider hidden changesets')),
69 ('', 'hidden', False, _('consider hidden changesets')),
70 ]
70 ]
71
71
72 dryrunopts = [('n', 'dry-run', None,
72 dryrunopts = [('n', 'dry-run', None,
73 _('do not perform actions, just print output'))]
73 _('do not perform actions, just print output'))]
74
74
75 remoteopts = [
75 remoteopts = [
76 ('e', 'ssh', '',
76 ('e', 'ssh', '',
77 _('specify ssh command to use'), _('CMD')),
77 _('specify ssh command to use'), _('CMD')),
78 ('', 'remotecmd', '',
78 ('', 'remotecmd', '',
79 _('specify hg command to run on the remote side'), _('CMD')),
79 _('specify hg command to run on the remote side'), _('CMD')),
80 ('', 'insecure', None,
80 ('', 'insecure', None,
81 _('do not verify server certificate (ignoring web.cacerts config)')),
81 _('do not verify server certificate (ignoring web.cacerts config)')),
82 ]
82 ]
83
83
84 walkopts = [
84 walkopts = [
85 ('I', 'include', [],
85 ('I', 'include', [],
86 _('include names matching the given patterns'), _('PATTERN')),
86 _('include names matching the given patterns'), _('PATTERN')),
87 ('X', 'exclude', [],
87 ('X', 'exclude', [],
88 _('exclude names matching the given patterns'), _('PATTERN')),
88 _('exclude names matching the given patterns'), _('PATTERN')),
89 ]
89 ]
90
90
91 commitopts = [
91 commitopts = [
92 ('m', 'message', '',
92 ('m', 'message', '',
93 _('use text as commit message'), _('TEXT')),
93 _('use text as commit message'), _('TEXT')),
94 ('l', 'logfile', '',
94 ('l', 'logfile', '',
95 _('read commit message from file'), _('FILE')),
95 _('read commit message from file'), _('FILE')),
96 ]
96 ]
97
97
98 commitopts2 = [
98 commitopts2 = [
99 ('d', 'date', '',
99 ('d', 'date', '',
100 _('record the specified date as commit date'), _('DATE')),
100 _('record the specified date as commit date'), _('DATE')),
101 ('u', 'user', '',
101 ('u', 'user', '',
102 _('record the specified user as committer'), _('USER')),
102 _('record the specified user as committer'), _('USER')),
103 ]
103 ]
104
104
105 # hidden for now
105 # hidden for now
106 formatteropts = [
106 formatteropts = [
107 ('T', 'template', '',
107 ('T', 'template', '',
108 _('display with template (DEPRECATED)'), _('TEMPLATE')),
108 _('display with template (DEPRECATED)'), _('TEMPLATE')),
109 ]
109 ]
110
110
111 templateopts = [
111 templateopts = [
112 ('', 'style', '',
112 ('', 'style', '',
113 _('display using template map file (DEPRECATED)'), _('STYLE')),
113 _('display using template map file (DEPRECATED)'), _('STYLE')),
114 ('T', 'template', '',
114 ('T', 'template', '',
115 _('display with template'), _('TEMPLATE')),
115 _('display with template'), _('TEMPLATE')),
116 ]
116 ]
117
117
118 logopts = [
118 logopts = [
119 ('p', 'patch', None, _('show patch')),
119 ('p', 'patch', None, _('show patch')),
120 ('g', 'git', None, _('use git extended diff format')),
120 ('g', 'git', None, _('use git extended diff format')),
121 ('l', 'limit', '',
121 ('l', 'limit', '',
122 _('limit number of changes displayed'), _('NUM')),
122 _('limit number of changes displayed'), _('NUM')),
123 ('M', 'no-merges', None, _('do not show merges')),
123 ('M', 'no-merges', None, _('do not show merges')),
124 ('', 'stat', None, _('output diffstat-style summary of changes')),
124 ('', 'stat', None, _('output diffstat-style summary of changes')),
125 ('G', 'graph', None, _("show the revision DAG")),
125 ('G', 'graph', None, _("show the revision DAG")),
126 ] + templateopts
126 ] + templateopts
127
127
128 diffopts = [
128 diffopts = [
129 ('a', 'text', None, _('treat all files as text')),
129 ('a', 'text', None, _('treat all files as text')),
130 ('g', 'git', None, _('use git extended diff format')),
130 ('g', 'git', None, _('use git extended diff format')),
131 ('', 'nodates', None, _('omit dates from diff headers'))
131 ('', 'nodates', None, _('omit dates from diff headers'))
132 ]
132 ]
133
133
134 diffwsopts = [
134 diffwsopts = [
135 ('w', 'ignore-all-space', None,
135 ('w', 'ignore-all-space', None,
136 _('ignore white space when comparing lines')),
136 _('ignore white space when comparing lines')),
137 ('b', 'ignore-space-change', None,
137 ('b', 'ignore-space-change', None,
138 _('ignore changes in the amount of white space')),
138 _('ignore changes in the amount of white space')),
139 ('B', 'ignore-blank-lines', None,
139 ('B', 'ignore-blank-lines', None,
140 _('ignore changes whose lines are all blank')),
140 _('ignore changes whose lines are all blank')),
141 ]
141 ]
142
142
143 diffopts2 = [
143 diffopts2 = [
144 ('', 'noprefix', None, _('omit a/ and b/ prefixes from filenames')),
144 ('', 'noprefix', None, _('omit a/ and b/ prefixes from filenames')),
145 ('p', 'show-function', None, _('show which function each change is in')),
145 ('p', 'show-function', None, _('show which function each change is in')),
146 ('', 'reverse', None, _('produce a diff that undoes the changes')),
146 ('', 'reverse', None, _('produce a diff that undoes the changes')),
147 ] + diffwsopts + [
147 ] + diffwsopts + [
148 ('U', 'unified', '',
148 ('U', 'unified', '',
149 _('number of lines of context to show'), _('NUM')),
149 _('number of lines of context to show'), _('NUM')),
150 ('', 'stat', None, _('output diffstat-style summary of changes')),
150 ('', 'stat', None, _('output diffstat-style summary of changes')),
151 ]
151 ]
152
152
153 mergetoolopts = [
153 mergetoolopts = [
154 ('t', 'tool', '', _('specify merge tool')),
154 ('t', 'tool', '', _('specify merge tool')),
155 ]
155 ]
156
156
157 similarityopts = [
157 similarityopts = [
158 ('s', 'similarity', '',
158 ('s', 'similarity', '',
159 _('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
159 _('guess renamed files by similarity (0<=s<=100)'), _('SIMILARITY'))
160 ]
160 ]
161
161
162 subrepoopts = [
162 subrepoopts = [
163 ('S', 'subrepos', None,
163 ('S', 'subrepos', None,
164 _('recurse into subrepositories'))
164 _('recurse into subrepositories'))
165 ]
165 ]
166
166
167 # Commands start here, listed alphabetically
167 # Commands start here, listed alphabetically
168
168
169 @command('^add',
169 @command('^add',
170 walkopts + subrepoopts + dryrunopts,
170 walkopts + subrepoopts + dryrunopts,
171 _('[OPTION]... [FILE]...'),
171 _('[OPTION]... [FILE]...'),
172 inferrepo=True)
172 inferrepo=True)
173 def add(ui, repo, *pats, **opts):
173 def add(ui, repo, *pats, **opts):
174 """add the specified files on the next commit
174 """add the specified files on the next commit
175
175
176 Schedule files to be version controlled and added to the
176 Schedule files to be version controlled and added to the
177 repository.
177 repository.
178
178
179 The files will be added to the repository at the next commit. To
179 The files will be added to the repository at the next commit. To
180 undo an add before that, see :hg:`forget`.
180 undo an add before that, see :hg:`forget`.
181
181
182 If no names are given, add all files to the repository.
182 If no names are given, add all files to the repository.
183
183
184 .. container:: verbose
184 .. container:: verbose
185
185
186 An example showing how new (unknown) files are added
186 An example showing how new (unknown) files are added
187 automatically by :hg:`add`::
187 automatically by :hg:`add`::
188
188
189 $ ls
189 $ ls
190 foo.c
190 foo.c
191 $ hg status
191 $ hg status
192 ? foo.c
192 ? foo.c
193 $ hg add
193 $ hg add
194 adding foo.c
194 adding foo.c
195 $ hg status
195 $ hg status
196 A foo.c
196 A foo.c
197
197
198 Returns 0 if all files are successfully added.
198 Returns 0 if all files are successfully added.
199 """
199 """
200
200
201 m = scmutil.match(repo[None], pats, opts)
201 m = scmutil.match(repo[None], pats, opts)
202 rejected = cmdutil.add(ui, repo, m, "", False, **opts)
202 rejected = cmdutil.add(ui, repo, m, "", False, **opts)
203 return rejected and 1 or 0
203 return rejected and 1 or 0
204
204
205 @command('addremove',
205 @command('addremove',
206 similarityopts + subrepoopts + walkopts + dryrunopts,
206 similarityopts + subrepoopts + walkopts + dryrunopts,
207 _('[OPTION]... [FILE]...'),
207 _('[OPTION]... [FILE]...'),
208 inferrepo=True)
208 inferrepo=True)
209 def addremove(ui, repo, *pats, **opts):
209 def addremove(ui, repo, *pats, **opts):
210 """add all new files, delete all missing files
210 """add all new files, delete all missing files
211
211
212 Add all new files and remove all missing files from the
212 Add all new files and remove all missing files from the
213 repository.
213 repository.
214
214
215 New files are ignored if they match any of the patterns in
215 New files are ignored if they match any of the patterns in
216 ``.hgignore``. As with add, these changes take effect at the next
216 ``.hgignore``. As with add, these changes take effect at the next
217 commit.
217 commit.
218
218
219 Use the -s/--similarity option to detect renamed files. This
219 Use the -s/--similarity option to detect renamed files. This
220 option takes a percentage between 0 (disabled) and 100 (files must
220 option takes a percentage between 0 (disabled) and 100 (files must
221 be identical) as its parameter. With a parameter greater than 0,
221 be identical) as its parameter. With a parameter greater than 0,
222 this compares every removed file with every added file and records
222 this compares every removed file with every added file and records
223 those similar enough as renames. Detecting renamed files this way
223 those similar enough as renames. Detecting renamed files this way
224 can be expensive. After using this option, :hg:`status -C` can be
224 can be expensive. After using this option, :hg:`status -C` can be
225 used to check which files were identified as moved or renamed. If
225 used to check which files were identified as moved or renamed. If
226 not specified, -s/--similarity defaults to 100 and only renames of
226 not specified, -s/--similarity defaults to 100 and only renames of
227 identical files are detected.
227 identical files are detected.
228
228
229 Returns 0 if all files are successfully added.
229 Returns 0 if all files are successfully added.
230 """
230 """
231 try:
231 try:
232 sim = float(opts.get('similarity') or 100)
232 sim = float(opts.get('similarity') or 100)
233 except ValueError:
233 except ValueError:
234 raise util.Abort(_('similarity must be a number'))
234 raise util.Abort(_('similarity must be a number'))
235 if sim < 0 or sim > 100:
235 if sim < 0 or sim > 100:
236 raise util.Abort(_('similarity must be between 0 and 100'))
236 raise util.Abort(_('similarity must be between 0 and 100'))
237 matcher = scmutil.match(repo[None], pats, opts)
237 matcher = scmutil.match(repo[None], pats, opts)
238 return scmutil.addremove(repo, matcher, "", opts, similarity=sim / 100.0)
238 return scmutil.addremove(repo, matcher, "", opts, similarity=sim / 100.0)
239
239
240 @command('^annotate|blame',
240 @command('^annotate|blame',
241 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
241 [('r', 'rev', '', _('annotate the specified revision'), _('REV')),
242 ('', 'follow', None,
242 ('', 'follow', None,
243 _('follow copies/renames and list the filename (DEPRECATED)')),
243 _('follow copies/renames and list the filename (DEPRECATED)')),
244 ('', 'no-follow', None, _("don't follow copies and renames")),
244 ('', 'no-follow', None, _("don't follow copies and renames")),
245 ('a', 'text', None, _('treat all files as text')),
245 ('a', 'text', None, _('treat all files as text')),
246 ('u', 'user', None, _('list the author (long with -v)')),
246 ('u', 'user', None, _('list the author (long with -v)')),
247 ('f', 'file', None, _('list the filename')),
247 ('f', 'file', None, _('list the filename')),
248 ('d', 'date', None, _('list the date (short with -q)')),
248 ('d', 'date', None, _('list the date (short with -q)')),
249 ('n', 'number', None, _('list the revision number (default)')),
249 ('n', 'number', None, _('list the revision number (default)')),
250 ('c', 'changeset', None, _('list the changeset')),
250 ('c', 'changeset', None, _('list the changeset')),
251 ('l', 'line-number', None, _('show line number at the first appearance'))
251 ('l', 'line-number', None, _('show line number at the first appearance'))
252 ] + diffwsopts + walkopts + formatteropts,
252 ] + diffwsopts + walkopts + formatteropts,
253 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'),
253 _('[-r REV] [-f] [-a] [-u] [-d] [-n] [-c] [-l] FILE...'),
254 inferrepo=True)
254 inferrepo=True)
255 def annotate(ui, repo, *pats, **opts):
255 def annotate(ui, repo, *pats, **opts):
256 """show changeset information by line for each file
256 """show changeset information by line for each file
257
257
258 List changes in files, showing the revision id responsible for
258 List changes in files, showing the revision id responsible for
259 each line
259 each line
260
260
261 This command is useful for discovering when a change was made and
261 This command is useful for discovering when a change was made and
262 by whom.
262 by whom.
263
263
264 Without the -a/--text option, annotate will avoid processing files
264 Without the -a/--text option, annotate will avoid processing files
265 it detects as binary. With -a, annotate will annotate the file
265 it detects as binary. With -a, annotate will annotate the file
266 anyway, although the results will probably be neither useful
266 anyway, although the results will probably be neither useful
267 nor desirable.
267 nor desirable.
268
268
269 Returns 0 on success.
269 Returns 0 on success.
270 """
270 """
271 if not pats:
271 if not pats:
272 raise util.Abort(_('at least one filename or pattern is required'))
272 raise util.Abort(_('at least one filename or pattern is required'))
273
273
274 if opts.get('follow'):
274 if opts.get('follow'):
275 # --follow is deprecated and now just an alias for -f/--file
275 # --follow is deprecated and now just an alias for -f/--file
276 # to mimic the behavior of Mercurial before version 1.5
276 # to mimic the behavior of Mercurial before version 1.5
277 opts['file'] = True
277 opts['file'] = True
278
278
279 fm = ui.formatter('annotate', opts)
279 fm = ui.formatter('annotate', opts)
280 datefunc = ui.quiet and util.shortdate or util.datestr
280 datefunc = ui.quiet and util.shortdate or util.datestr
281 hexfn = fm.hexfunc
281 hexfn = fm.hexfunc
282
282
283 opmap = [('user', ' ', lambda x: x[0].user(), ui.shortuser),
283 opmap = [('user', ' ', lambda x: x[0].user(), ui.shortuser),
284 ('number', ' ', lambda x: x[0].rev(), str),
284 ('number', ' ', lambda x: x[0].rev(), str),
285 ('changeset', ' ', lambda x: hexfn(x[0].node()), str),
285 ('changeset', ' ', lambda x: hexfn(x[0].node()), str),
286 ('date', ' ', lambda x: x[0].date(), util.cachefunc(datefunc)),
286 ('date', ' ', lambda x: x[0].date(), util.cachefunc(datefunc)),
287 ('file', ' ', lambda x: x[0].path(), str),
287 ('file', ' ', lambda x: x[0].path(), str),
288 ('line_number', ':', lambda x: x[1], str),
288 ('line_number', ':', lambda x: x[1], str),
289 ]
289 ]
290 fieldnamemap = {'number': 'rev', 'changeset': 'node'}
290 fieldnamemap = {'number': 'rev', 'changeset': 'node'}
291
291
292 if (not opts.get('user') and not opts.get('changeset')
292 if (not opts.get('user') and not opts.get('changeset')
293 and not opts.get('date') and not opts.get('file')):
293 and not opts.get('date') and not opts.get('file')):
294 opts['number'] = True
294 opts['number'] = True
295
295
296 linenumber = opts.get('line_number') is not None
296 linenumber = opts.get('line_number') is not None
297 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
297 if linenumber and (not opts.get('changeset')) and (not opts.get('number')):
298 raise util.Abort(_('at least one of -n/-c is required for -l'))
298 raise util.Abort(_('at least one of -n/-c is required for -l'))
299
299
300 if fm:
300 if fm:
301 def makefunc(get, fmt):
301 def makefunc(get, fmt):
302 return get
302 return get
303 else:
303 else:
304 def makefunc(get, fmt):
304 def makefunc(get, fmt):
305 return lambda x: fmt(get(x))
305 return lambda x: fmt(get(x))
306 funcmap = [(makefunc(get, fmt), sep) for op, sep, get, fmt in opmap
306 funcmap = [(makefunc(get, fmt), sep) for op, sep, get, fmt in opmap
307 if opts.get(op)]
307 if opts.get(op)]
308 funcmap[0] = (funcmap[0][0], '') # no separator in front of first column
308 funcmap[0] = (funcmap[0][0], '') # no separator in front of first column
309 fields = ' '.join(fieldnamemap.get(op, op) for op, sep, get, fmt in opmap
309 fields = ' '.join(fieldnamemap.get(op, op) for op, sep, get, fmt in opmap
310 if opts.get(op))
310 if opts.get(op))
311
311
312 def bad(x, y):
312 def bad(x, y):
313 raise util.Abort("%s: %s" % (x, y))
313 raise util.Abort("%s: %s" % (x, y))
314
314
315 ctx = scmutil.revsingle(repo, opts.get('rev'))
315 ctx = scmutil.revsingle(repo, opts.get('rev'))
316 m = scmutil.match(ctx, pats, opts)
316 m = scmutil.match(ctx, pats, opts)
317 m.bad = bad
317 m.bad = bad
318 follow = not opts.get('no_follow')
318 follow = not opts.get('no_follow')
319 diffopts = patch.difffeatureopts(ui, opts, section='annotate',
319 diffopts = patch.difffeatureopts(ui, opts, section='annotate',
320 whitespace=True)
320 whitespace=True)
321 for abs in ctx.walk(m):
321 for abs in ctx.walk(m):
322 fctx = ctx[abs]
322 fctx = ctx[abs]
323 if not opts.get('text') and util.binary(fctx.data()):
323 if not opts.get('text') and util.binary(fctx.data()):
324 fm.plain(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs))
324 fm.plain(_("%s: binary file\n") % ((pats and m.rel(abs)) or abs))
325 continue
325 continue
326
326
327 lines = fctx.annotate(follow=follow, linenumber=linenumber,
327 lines = fctx.annotate(follow=follow, linenumber=linenumber,
328 diffopts=diffopts)
328 diffopts=diffopts)
329 formats = []
329 formats = []
330 pieces = []
330 pieces = []
331
331
332 for f, sep in funcmap:
332 for f, sep in funcmap:
333 l = [f(n) for n, dummy in lines]
333 l = [f(n) for n, dummy in lines]
334 if l:
334 if l:
335 if fm:
335 if fm:
336 formats.append(['%s' for x in l])
336 formats.append(['%s' for x in l])
337 else:
337 else:
338 sizes = [encoding.colwidth(x) for x in l]
338 sizes = [encoding.colwidth(x) for x in l]
339 ml = max(sizes)
339 ml = max(sizes)
340 formats.append([sep + ' ' * (ml - w) + '%s' for w in sizes])
340 formats.append([sep + ' ' * (ml - w) + '%s' for w in sizes])
341 pieces.append(l)
341 pieces.append(l)
342
342
343 for f, p, l in zip(zip(*formats), zip(*pieces), lines):
343 for f, p, l in zip(zip(*formats), zip(*pieces), lines):
344 fm.startitem()
344 fm.startitem()
345 fm.write(fields, "".join(f), *p)
345 fm.write(fields, "".join(f), *p)
346 fm.write('line', ": %s", l[1])
346 fm.write('line', ": %s", l[1])
347
347
348 if lines and not lines[-1][1].endswith('\n'):
348 if lines and not lines[-1][1].endswith('\n'):
349 fm.plain('\n')
349 fm.plain('\n')
350
350
351 fm.end()
351 fm.end()
352
352
353 @command('archive',
353 @command('archive',
354 [('', 'no-decode', None, _('do not pass files through decoders')),
354 [('', 'no-decode', None, _('do not pass files through decoders')),
355 ('p', 'prefix', '', _('directory prefix for files in archive'),
355 ('p', 'prefix', '', _('directory prefix for files in archive'),
356 _('PREFIX')),
356 _('PREFIX')),
357 ('r', 'rev', '', _('revision to distribute'), _('REV')),
357 ('r', 'rev', '', _('revision to distribute'), _('REV')),
358 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
358 ('t', 'type', '', _('type of distribution to create'), _('TYPE')),
359 ] + subrepoopts + walkopts,
359 ] + subrepoopts + walkopts,
360 _('[OPTION]... DEST'))
360 _('[OPTION]... DEST'))
361 def archive(ui, repo, dest, **opts):
361 def archive(ui, repo, dest, **opts):
362 '''create an unversioned archive of a repository revision
362 '''create an unversioned archive of a repository revision
363
363
364 By default, the revision used is the parent of the working
364 By default, the revision used is the parent of the working
365 directory; use -r/--rev to specify a different revision.
365 directory; use -r/--rev to specify a different revision.
366
366
367 The archive type is automatically detected based on file
367 The archive type is automatically detected based on file
368 extension (or override using -t/--type).
368 extension (or override using -t/--type).
369
369
370 .. container:: verbose
370 .. container:: verbose
371
371
372 Examples:
372 Examples:
373
373
374 - create a zip file containing the 1.0 release::
374 - create a zip file containing the 1.0 release::
375
375
376 hg archive -r 1.0 project-1.0.zip
376 hg archive -r 1.0 project-1.0.zip
377
377
378 - create a tarball excluding .hg files::
378 - create a tarball excluding .hg files::
379
379
380 hg archive project.tar.gz -X ".hg*"
380 hg archive project.tar.gz -X ".hg*"
381
381
382 Valid types are:
382 Valid types are:
383
383
384 :``files``: a directory full of files (default)
384 :``files``: a directory full of files (default)
385 :``tar``: tar archive, uncompressed
385 :``tar``: tar archive, uncompressed
386 :``tbz2``: tar archive, compressed using bzip2
386 :``tbz2``: tar archive, compressed using bzip2
387 :``tgz``: tar archive, compressed using gzip
387 :``tgz``: tar archive, compressed using gzip
388 :``uzip``: zip archive, uncompressed
388 :``uzip``: zip archive, uncompressed
389 :``zip``: zip archive, compressed using deflate
389 :``zip``: zip archive, compressed using deflate
390
390
391 The exact name of the destination archive or directory is given
391 The exact name of the destination archive or directory is given
392 using a format string; see :hg:`help export` for details.
392 using a format string; see :hg:`help export` for details.
393
393
394 Each member added to an archive file has a directory prefix
394 Each member added to an archive file has a directory prefix
395 prepended. Use -p/--prefix to specify a format string for the
395 prepended. Use -p/--prefix to specify a format string for the
396 prefix. The default is the basename of the archive, with suffixes
396 prefix. The default is the basename of the archive, with suffixes
397 removed.
397 removed.
398
398
399 Returns 0 on success.
399 Returns 0 on success.
400 '''
400 '''
401
401
402 ctx = scmutil.revsingle(repo, opts.get('rev'))
402 ctx = scmutil.revsingle(repo, opts.get('rev'))
403 if not ctx:
403 if not ctx:
404 raise util.Abort(_('no working directory: please specify a revision'))
404 raise util.Abort(_('no working directory: please specify a revision'))
405 node = ctx.node()
405 node = ctx.node()
406 dest = cmdutil.makefilename(repo, dest, node)
406 dest = cmdutil.makefilename(repo, dest, node)
407 if os.path.realpath(dest) == repo.root:
407 if os.path.realpath(dest) == repo.root:
408 raise util.Abort(_('repository root cannot be destination'))
408 raise util.Abort(_('repository root cannot be destination'))
409
409
410 kind = opts.get('type') or archival.guesskind(dest) or 'files'
410 kind = opts.get('type') or archival.guesskind(dest) or 'files'
411 prefix = opts.get('prefix')
411 prefix = opts.get('prefix')
412
412
413 if dest == '-':
413 if dest == '-':
414 if kind == 'files':
414 if kind == 'files':
415 raise util.Abort(_('cannot archive plain files to stdout'))
415 raise util.Abort(_('cannot archive plain files to stdout'))
416 dest = cmdutil.makefileobj(repo, dest)
416 dest = cmdutil.makefileobj(repo, dest)
417 if not prefix:
417 if not prefix:
418 prefix = os.path.basename(repo.root) + '-%h'
418 prefix = os.path.basename(repo.root) + '-%h'
419
419
420 prefix = cmdutil.makefilename(repo, prefix, node)
420 prefix = cmdutil.makefilename(repo, prefix, node)
421 matchfn = scmutil.match(ctx, [], opts)
421 matchfn = scmutil.match(ctx, [], opts)
422 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
422 archival.archive(repo, dest, node, kind, not opts.get('no_decode'),
423 matchfn, prefix, subrepos=opts.get('subrepos'))
423 matchfn, prefix, subrepos=opts.get('subrepos'))
424
424
425 @command('backout',
425 @command('backout',
426 [('', 'merge', None, _('merge with old dirstate parent after backout')),
426 [('', 'merge', None, _('merge with old dirstate parent after backout')),
427 ('', 'commit', None, _('commit if no conflicts were encountered')),
427 ('', 'commit', None, _('commit if no conflicts were encountered')),
428 ('', 'parent', '',
428 ('', 'parent', '',
429 _('parent to choose when backing out merge (DEPRECATED)'), _('REV')),
429 _('parent to choose when backing out merge (DEPRECATED)'), _('REV')),
430 ('r', 'rev', '', _('revision to backout'), _('REV')),
430 ('r', 'rev', '', _('revision to backout'), _('REV')),
431 ('e', 'edit', False, _('invoke editor on commit messages')),
431 ('e', 'edit', False, _('invoke editor on commit messages')),
432 ] + mergetoolopts + walkopts + commitopts + commitopts2,
432 ] + mergetoolopts + walkopts + commitopts + commitopts2,
433 _('[OPTION]... [-r] REV'))
433 _('[OPTION]... [-r] REV'))
434 def backout(ui, repo, node=None, rev=None, commit=False, **opts):
434 def backout(ui, repo, node=None, rev=None, commit=False, **opts):
435 '''reverse effect of earlier changeset
435 '''reverse effect of earlier changeset
436
436
437 Prepare a new changeset with the effect of REV undone in the
437 Prepare a new changeset with the effect of REV undone in the
438 current working directory.
438 current working directory.
439
439
440 If REV is the parent of the working directory, then this new changeset
440 If REV is the parent of the working directory, then this new changeset
441 is committed automatically. Otherwise, hg needs to merge the
441 is committed automatically. Otherwise, hg needs to merge the
442 changes and the merged result is left uncommitted.
442 changes and the merged result is left uncommitted.
443
443
444 .. note::
444 .. note::
445
445
446 backout cannot be used to fix either an unwanted or
446 backout cannot be used to fix either an unwanted or
447 incorrect merge.
447 incorrect merge.
448
448
449 .. container:: verbose
449 .. container:: verbose
450
450
451 By default, the pending changeset will have one parent,
451 By default, the pending changeset will have one parent,
452 maintaining a linear history. With --merge, the pending
452 maintaining a linear history. With --merge, the pending
453 changeset will instead have two parents: the old parent of the
453 changeset will instead have two parents: the old parent of the
454 working directory and a new child of REV that simply undoes REV.
454 working directory and a new child of REV that simply undoes REV.
455
455
456 Before version 1.7, the behavior without --merge was equivalent
456 Before version 1.7, the behavior without --merge was equivalent
457 to specifying --merge followed by :hg:`update --clean .` to
457 to specifying --merge followed by :hg:`update --clean .` to
458 cancel the merge and leave the child of REV as a head to be
458 cancel the merge and leave the child of REV as a head to be
459 merged separately.
459 merged separately.
460
460
461 See :hg:`help dates` for a list of formats valid for -d/--date.
461 See :hg:`help dates` for a list of formats valid for -d/--date.
462
462
463 Returns 0 on success, 1 if nothing to backout or there are unresolved
463 Returns 0 on success, 1 if nothing to backout or there are unresolved
464 files.
464 files.
465 '''
465 '''
466 if rev and node:
466 if rev and node:
467 raise util.Abort(_("please specify just one revision"))
467 raise util.Abort(_("please specify just one revision"))
468
468
469 if not rev:
469 if not rev:
470 rev = node
470 rev = node
471
471
472 if not rev:
472 if not rev:
473 raise util.Abort(_("please specify a revision to backout"))
473 raise util.Abort(_("please specify a revision to backout"))
474
474
475 date = opts.get('date')
475 date = opts.get('date')
476 if date:
476 if date:
477 opts['date'] = util.parsedate(date)
477 opts['date'] = util.parsedate(date)
478
478
479 cmdutil.checkunfinished(repo)
479 cmdutil.checkunfinished(repo)
480 cmdutil.bailifchanged(repo)
480 cmdutil.bailifchanged(repo)
481 node = scmutil.revsingle(repo, rev).node()
481 node = scmutil.revsingle(repo, rev).node()
482
482
483 op1, op2 = repo.dirstate.parents()
483 op1, op2 = repo.dirstate.parents()
484 if not repo.changelog.isancestor(node, op1):
484 if not repo.changelog.isancestor(node, op1):
485 raise util.Abort(_('cannot backout change that is not an ancestor'))
485 raise util.Abort(_('cannot backout change that is not an ancestor'))
486
486
487 p1, p2 = repo.changelog.parents(node)
487 p1, p2 = repo.changelog.parents(node)
488 if p1 == nullid:
488 if p1 == nullid:
489 raise util.Abort(_('cannot backout a change with no parents'))
489 raise util.Abort(_('cannot backout a change with no parents'))
490 if p2 != nullid:
490 if p2 != nullid:
491 if not opts.get('parent'):
491 if not opts.get('parent'):
492 raise util.Abort(_('cannot backout a merge changeset'))
492 raise util.Abort(_('cannot backout a merge changeset'))
493 p = repo.lookup(opts['parent'])
493 p = repo.lookup(opts['parent'])
494 if p not in (p1, p2):
494 if p not in (p1, p2):
495 raise util.Abort(_('%s is not a parent of %s') %
495 raise util.Abort(_('%s is not a parent of %s') %
496 (short(p), short(node)))
496 (short(p), short(node)))
497 parent = p
497 parent = p
498 else:
498 else:
499 if opts.get('parent'):
499 if opts.get('parent'):
500 raise util.Abort(_('cannot use --parent on non-merge changeset'))
500 raise util.Abort(_('cannot use --parent on non-merge changeset'))
501 parent = p1
501 parent = p1
502
502
503 # the backout should appear on the same branch
503 # the backout should appear on the same branch
504 wlock = repo.wlock()
504 wlock = repo.wlock()
505 try:
505 try:
506 branch = repo.dirstate.branch()
506 branch = repo.dirstate.branch()
507 bheads = repo.branchheads(branch)
507 bheads = repo.branchheads(branch)
508 rctx = scmutil.revsingle(repo, hex(parent))
508 rctx = scmutil.revsingle(repo, hex(parent))
509 if not opts.get('merge') and op1 != node:
509 if not opts.get('merge') and op1 != node:
510 try:
510 try:
511 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
511 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
512 'backout')
512 'backout')
513 repo.dirstate.beginparentchange()
513 repo.dirstate.beginparentchange()
514 stats = mergemod.update(repo, parent, True, True, False,
514 stats = mergemod.update(repo, parent, True, True, False,
515 node, False)
515 node, False)
516 repo.setparents(op1, op2)
516 repo.setparents(op1, op2)
517 repo.dirstate.endparentchange()
517 repo.dirstate.endparentchange()
518 hg._showstats(repo, stats)
518 hg._showstats(repo, stats)
519 if stats[3]:
519 if stats[3]:
520 repo.ui.status(_("use 'hg resolve' to retry unresolved "
520 repo.ui.status(_("use 'hg resolve' to retry unresolved "
521 "file merges\n"))
521 "file merges\n"))
522 return 1
522 return 1
523 elif not commit:
523 elif not commit:
524 msg = _("changeset %s backed out, "
524 msg = _("changeset %s backed out, "
525 "don't forget to commit.\n")
525 "don't forget to commit.\n")
526 ui.status(msg % short(node))
526 ui.status(msg % short(node))
527 return 0
527 return 0
528 finally:
528 finally:
529 ui.setconfig('ui', 'forcemerge', '', '')
529 ui.setconfig('ui', 'forcemerge', '', '')
530 else:
530 else:
531 hg.clean(repo, node, show_stats=False)
531 hg.clean(repo, node, show_stats=False)
532 repo.dirstate.setbranch(branch)
532 repo.dirstate.setbranch(branch)
533 cmdutil.revert(ui, repo, rctx, repo.dirstate.parents())
533 cmdutil.revert(ui, repo, rctx, repo.dirstate.parents())
534
534
535
535
536 def commitfunc(ui, repo, message, match, opts):
536 def commitfunc(ui, repo, message, match, opts):
537 editform = 'backout'
537 editform = 'backout'
538 e = cmdutil.getcommiteditor(editform=editform, **opts)
538 e = cmdutil.getcommiteditor(editform=editform, **opts)
539 if not message:
539 if not message:
540 # we don't translate commit messages
540 # we don't translate commit messages
541 message = "Backed out changeset %s" % short(node)
541 message = "Backed out changeset %s" % short(node)
542 e = cmdutil.getcommiteditor(edit=True, editform=editform)
542 e = cmdutil.getcommiteditor(edit=True, editform=editform)
543 return repo.commit(message, opts.get('user'), opts.get('date'),
543 return repo.commit(message, opts.get('user'), opts.get('date'),
544 match, editor=e)
544 match, editor=e)
545 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
545 newnode = cmdutil.commit(ui, repo, commitfunc, [], opts)
546 if not newnode:
546 if not newnode:
547 ui.status(_("nothing changed\n"))
547 ui.status(_("nothing changed\n"))
548 return 1
548 return 1
549 cmdutil.commitstatus(repo, newnode, branch, bheads)
549 cmdutil.commitstatus(repo, newnode, branch, bheads)
550
550
551 def nice(node):
551 def nice(node):
552 return '%d:%s' % (repo.changelog.rev(node), short(node))
552 return '%d:%s' % (repo.changelog.rev(node), short(node))
553 ui.status(_('changeset %s backs out changeset %s\n') %
553 ui.status(_('changeset %s backs out changeset %s\n') %
554 (nice(repo.changelog.tip()), nice(node)))
554 (nice(repo.changelog.tip()), nice(node)))
555 if opts.get('merge') and op1 != node:
555 if opts.get('merge') and op1 != node:
556 hg.clean(repo, op1, show_stats=False)
556 hg.clean(repo, op1, show_stats=False)
557 ui.status(_('merging with changeset %s\n')
557 ui.status(_('merging with changeset %s\n')
558 % nice(repo.changelog.tip()))
558 % nice(repo.changelog.tip()))
559 try:
559 try:
560 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
560 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
561 'backout')
561 'backout')
562 return hg.merge(repo, hex(repo.changelog.tip()))
562 return hg.merge(repo, hex(repo.changelog.tip()))
563 finally:
563 finally:
564 ui.setconfig('ui', 'forcemerge', '', '')
564 ui.setconfig('ui', 'forcemerge', '', '')
565 finally:
565 finally:
566 wlock.release()
566 wlock.release()
567 return 0
567 return 0
568
568
569 @command('bisect',
569 @command('bisect',
570 [('r', 'reset', False, _('reset bisect state')),
570 [('r', 'reset', False, _('reset bisect state')),
571 ('g', 'good', False, _('mark changeset good')),
571 ('g', 'good', False, _('mark changeset good')),
572 ('b', 'bad', False, _('mark changeset bad')),
572 ('b', 'bad', False, _('mark changeset bad')),
573 ('s', 'skip', False, _('skip testing changeset')),
573 ('s', 'skip', False, _('skip testing changeset')),
574 ('e', 'extend', False, _('extend the bisect range')),
574 ('e', 'extend', False, _('extend the bisect range')),
575 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
575 ('c', 'command', '', _('use command to check changeset state'), _('CMD')),
576 ('U', 'noupdate', False, _('do not update to target'))],
576 ('U', 'noupdate', False, _('do not update to target'))],
577 _("[-gbsr] [-U] [-c CMD] [REV]"))
577 _("[-gbsr] [-U] [-c CMD] [REV]"))
578 def bisect(ui, repo, rev=None, extra=None, command=None,
578 def bisect(ui, repo, rev=None, extra=None, command=None,
579 reset=None, good=None, bad=None, skip=None, extend=None,
579 reset=None, good=None, bad=None, skip=None, extend=None,
580 noupdate=None):
580 noupdate=None):
581 """subdivision search of changesets
581 """subdivision search of changesets
582
582
583 This command helps to find changesets which introduce problems. To
583 This command helps to find changesets which introduce problems. To
584 use, mark the earliest changeset you know exhibits the problem as
584 use, mark the earliest changeset you know exhibits the problem as
585 bad, then mark the latest changeset which is free from the problem
585 bad, then mark the latest changeset which is free from the problem
586 as good. Bisect will update your working directory to a revision
586 as good. Bisect will update your working directory to a revision
587 for testing (unless the -U/--noupdate option is specified). Once
587 for testing (unless the -U/--noupdate option is specified). Once
588 you have performed tests, mark the working directory as good or
588 you have performed tests, mark the working directory as good or
589 bad, and bisect will either update to another candidate changeset
589 bad, and bisect will either update to another candidate changeset
590 or announce that it has found the bad revision.
590 or announce that it has found the bad revision.
591
591
592 As a shortcut, you can also use the revision argument to mark a
592 As a shortcut, you can also use the revision argument to mark a
593 revision as good or bad without checking it out first.
593 revision as good or bad without checking it out first.
594
594
595 If you supply a command, it will be used for automatic bisection.
595 If you supply a command, it will be used for automatic bisection.
596 The environment variable HG_NODE will contain the ID of the
596 The environment variable HG_NODE will contain the ID of the
597 changeset being tested. The exit status of the command will be
597 changeset being tested. The exit status of the command will be
598 used to mark revisions as good or bad: status 0 means good, 125
598 used to mark revisions as good or bad: status 0 means good, 125
599 means to skip the revision, 127 (command not found) will abort the
599 means to skip the revision, 127 (command not found) will abort the
600 bisection, and any other non-zero exit status means the revision
600 bisection, and any other non-zero exit status means the revision
601 is bad.
601 is bad.
602
602
603 .. container:: verbose
603 .. container:: verbose
604
604
605 Some examples:
605 Some examples:
606
606
607 - start a bisection with known bad revision 34, and good revision 12::
607 - start a bisection with known bad revision 34, and good revision 12::
608
608
609 hg bisect --bad 34
609 hg bisect --bad 34
610 hg bisect --good 12
610 hg bisect --good 12
611
611
612 - advance the current bisection by marking current revision as good or
612 - advance the current bisection by marking current revision as good or
613 bad::
613 bad::
614
614
615 hg bisect --good
615 hg bisect --good
616 hg bisect --bad
616 hg bisect --bad
617
617
618 - mark the current revision, or a known revision, to be skipped (e.g. if
618 - mark the current revision, or a known revision, to be skipped (e.g. if
619 that revision is not usable because of another issue)::
619 that revision is not usable because of another issue)::
620
620
621 hg bisect --skip
621 hg bisect --skip
622 hg bisect --skip 23
622 hg bisect --skip 23
623
623
624 - skip all revisions that do not touch directories ``foo`` or ``bar``::
624 - skip all revisions that do not touch directories ``foo`` or ``bar``::
625
625
626 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
626 hg bisect --skip "!( file('path:foo') & file('path:bar') )"
627
627
628 - forget the current bisection::
628 - forget the current bisection::
629
629
630 hg bisect --reset
630 hg bisect --reset
631
631
632 - use 'make && make tests' to automatically find the first broken
632 - use 'make && make tests' to automatically find the first broken
633 revision::
633 revision::
634
634
635 hg bisect --reset
635 hg bisect --reset
636 hg bisect --bad 34
636 hg bisect --bad 34
637 hg bisect --good 12
637 hg bisect --good 12
638 hg bisect --command "make && make tests"
638 hg bisect --command "make && make tests"
639
639
640 - see all changesets whose states are already known in the current
640 - see all changesets whose states are already known in the current
641 bisection::
641 bisection::
642
642
643 hg log -r "bisect(pruned)"
643 hg log -r "bisect(pruned)"
644
644
645 - see the changeset currently being bisected (especially useful
645 - see the changeset currently being bisected (especially useful
646 if running with -U/--noupdate)::
646 if running with -U/--noupdate)::
647
647
648 hg log -r "bisect(current)"
648 hg log -r "bisect(current)"
649
649
650 - see all changesets that took part in the current bisection::
650 - see all changesets that took part in the current bisection::
651
651
652 hg log -r "bisect(range)"
652 hg log -r "bisect(range)"
653
653
654 - you can even get a nice graph::
654 - you can even get a nice graph::
655
655
656 hg log --graph -r "bisect(range)"
656 hg log --graph -r "bisect(range)"
657
657
658 See :hg:`help revsets` for more about the `bisect()` keyword.
658 See :hg:`help revsets` for more about the `bisect()` keyword.
659
659
660 Returns 0 on success.
660 Returns 0 on success.
661 """
661 """
662 def extendbisectrange(nodes, good):
662 def extendbisectrange(nodes, good):
663 # bisect is incomplete when it ends on a merge node and
663 # bisect is incomplete when it ends on a merge node and
664 # one of the parent was not checked.
664 # one of the parent was not checked.
665 parents = repo[nodes[0]].parents()
665 parents = repo[nodes[0]].parents()
666 if len(parents) > 1:
666 if len(parents) > 1:
667 side = good and state['bad'] or state['good']
667 side = good and state['bad'] or state['good']
668 num = len(set(i.node() for i in parents) & set(side))
668 num = len(set(i.node() for i in parents) & set(side))
669 if num == 1:
669 if num == 1:
670 return parents[0].ancestor(parents[1])
670 return parents[0].ancestor(parents[1])
671 return None
671 return None
672
672
673 def print_result(nodes, good):
673 def print_result(nodes, good):
674 displayer = cmdutil.show_changeset(ui, repo, {})
674 displayer = cmdutil.show_changeset(ui, repo, {})
675 if len(nodes) == 1:
675 if len(nodes) == 1:
676 # narrowed it down to a single revision
676 # narrowed it down to a single revision
677 if good:
677 if good:
678 ui.write(_("The first good revision is:\n"))
678 ui.write(_("The first good revision is:\n"))
679 else:
679 else:
680 ui.write(_("The first bad revision is:\n"))
680 ui.write(_("The first bad revision is:\n"))
681 displayer.show(repo[nodes[0]])
681 displayer.show(repo[nodes[0]])
682 extendnode = extendbisectrange(nodes, good)
682 extendnode = extendbisectrange(nodes, good)
683 if extendnode is not None:
683 if extendnode is not None:
684 ui.write(_('Not all ancestors of this changeset have been'
684 ui.write(_('Not all ancestors of this changeset have been'
685 ' checked.\nUse bisect --extend to continue the '
685 ' checked.\nUse bisect --extend to continue the '
686 'bisection from\nthe common ancestor, %s.\n')
686 'bisection from\nthe common ancestor, %s.\n')
687 % extendnode)
687 % extendnode)
688 else:
688 else:
689 # multiple possible revisions
689 # multiple possible revisions
690 if good:
690 if good:
691 ui.write(_("Due to skipped revisions, the first "
691 ui.write(_("Due to skipped revisions, the first "
692 "good revision could be any of:\n"))
692 "good revision could be any of:\n"))
693 else:
693 else:
694 ui.write(_("Due to skipped revisions, the first "
694 ui.write(_("Due to skipped revisions, the first "
695 "bad revision could be any of:\n"))
695 "bad revision could be any of:\n"))
696 for n in nodes:
696 for n in nodes:
697 displayer.show(repo[n])
697 displayer.show(repo[n])
698 displayer.close()
698 displayer.close()
699
699
700 def check_state(state, interactive=True):
700 def check_state(state, interactive=True):
701 if not state['good'] or not state['bad']:
701 if not state['good'] or not state['bad']:
702 if (good or bad or skip or reset) and interactive:
702 if (good or bad or skip or reset) and interactive:
703 return
703 return
704 if not state['good']:
704 if not state['good']:
705 raise util.Abort(_('cannot bisect (no known good revisions)'))
705 raise util.Abort(_('cannot bisect (no known good revisions)'))
706 else:
706 else:
707 raise util.Abort(_('cannot bisect (no known bad revisions)'))
707 raise util.Abort(_('cannot bisect (no known bad revisions)'))
708 return True
708 return True
709
709
710 # backward compatibility
710 # backward compatibility
711 if rev in "good bad reset init".split():
711 if rev in "good bad reset init".split():
712 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
712 ui.warn(_("(use of 'hg bisect <cmd>' is deprecated)\n"))
713 cmd, rev, extra = rev, extra, None
713 cmd, rev, extra = rev, extra, None
714 if cmd == "good":
714 if cmd == "good":
715 good = True
715 good = True
716 elif cmd == "bad":
716 elif cmd == "bad":
717 bad = True
717 bad = True
718 else:
718 else:
719 reset = True
719 reset = True
720 elif extra or good + bad + skip + reset + extend + bool(command) > 1:
720 elif extra or good + bad + skip + reset + extend + bool(command) > 1:
721 raise util.Abort(_('incompatible arguments'))
721 raise util.Abort(_('incompatible arguments'))
722
722
723 cmdutil.checkunfinished(repo)
723 cmdutil.checkunfinished(repo)
724
724
725 if reset:
725 if reset:
726 p = repo.join("bisect.state")
726 p = repo.join("bisect.state")
727 if os.path.exists(p):
727 if os.path.exists(p):
728 os.unlink(p)
728 os.unlink(p)
729 return
729 return
730
730
731 state = hbisect.load_state(repo)
731 state = hbisect.load_state(repo)
732
732
733 if command:
733 if command:
734 changesets = 1
734 changesets = 1
735 if noupdate:
735 if noupdate:
736 try:
736 try:
737 node = state['current'][0]
737 node = state['current'][0]
738 except LookupError:
738 except LookupError:
739 raise util.Abort(_('current bisect revision is unknown - '
739 raise util.Abort(_('current bisect revision is unknown - '
740 'start a new bisect to fix'))
740 'start a new bisect to fix'))
741 else:
741 else:
742 node, p2 = repo.dirstate.parents()
742 node, p2 = repo.dirstate.parents()
743 if p2 != nullid:
743 if p2 != nullid:
744 raise util.Abort(_('current bisect revision is a merge'))
744 raise util.Abort(_('current bisect revision is a merge'))
745 try:
745 try:
746 while changesets:
746 while changesets:
747 # update state
747 # update state
748 state['current'] = [node]
748 state['current'] = [node]
749 hbisect.save_state(repo, state)
749 hbisect.save_state(repo, state)
750 status = ui.system(command, environ={'HG_NODE': hex(node)})
750 status = ui.system(command, environ={'HG_NODE': hex(node)})
751 if status == 125:
751 if status == 125:
752 transition = "skip"
752 transition = "skip"
753 elif status == 0:
753 elif status == 0:
754 transition = "good"
754 transition = "good"
755 # status < 0 means process was killed
755 # status < 0 means process was killed
756 elif status == 127:
756 elif status == 127:
757 raise util.Abort(_("failed to execute %s") % command)
757 raise util.Abort(_("failed to execute %s") % command)
758 elif status < 0:
758 elif status < 0:
759 raise util.Abort(_("%s killed") % command)
759 raise util.Abort(_("%s killed") % command)
760 else:
760 else:
761 transition = "bad"
761 transition = "bad"
762 ctx = scmutil.revsingle(repo, rev, node)
762 ctx = scmutil.revsingle(repo, rev, node)
763 rev = None # clear for future iterations
763 rev = None # clear for future iterations
764 state[transition].append(ctx.node())
764 state[transition].append(ctx.node())
765 ui.status(_('changeset %d:%s: %s\n') % (ctx, ctx, transition))
765 ui.status(_('changeset %d:%s: %s\n') % (ctx, ctx, transition))
766 check_state(state, interactive=False)
766 check_state(state, interactive=False)
767 # bisect
767 # bisect
768 nodes, changesets, bgood = hbisect.bisect(repo.changelog, state)
768 nodes, changesets, bgood = hbisect.bisect(repo.changelog, state)
769 # update to next check
769 # update to next check
770 node = nodes[0]
770 node = nodes[0]
771 if not noupdate:
771 if not noupdate:
772 cmdutil.bailifchanged(repo)
772 cmdutil.bailifchanged(repo)
773 hg.clean(repo, node, show_stats=False)
773 hg.clean(repo, node, show_stats=False)
774 finally:
774 finally:
775 state['current'] = [node]
775 state['current'] = [node]
776 hbisect.save_state(repo, state)
776 hbisect.save_state(repo, state)
777 print_result(nodes, bgood)
777 print_result(nodes, bgood)
778 return
778 return
779
779
780 # update state
780 # update state
781
781
782 if rev:
782 if rev:
783 nodes = [repo.lookup(i) for i in scmutil.revrange(repo, [rev])]
783 nodes = [repo.lookup(i) for i in scmutil.revrange(repo, [rev])]
784 else:
784 else:
785 nodes = [repo.lookup('.')]
785 nodes = [repo.lookup('.')]
786
786
787 if good or bad or skip:
787 if good or bad or skip:
788 if good:
788 if good:
789 state['good'] += nodes
789 state['good'] += nodes
790 elif bad:
790 elif bad:
791 state['bad'] += nodes
791 state['bad'] += nodes
792 elif skip:
792 elif skip:
793 state['skip'] += nodes
793 state['skip'] += nodes
794 hbisect.save_state(repo, state)
794 hbisect.save_state(repo, state)
795
795
796 if not check_state(state):
796 if not check_state(state):
797 return
797 return
798
798
799 # actually bisect
799 # actually bisect
800 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
800 nodes, changesets, good = hbisect.bisect(repo.changelog, state)
801 if extend:
801 if extend:
802 if not changesets:
802 if not changesets:
803 extendnode = extendbisectrange(nodes, good)
803 extendnode = extendbisectrange(nodes, good)
804 if extendnode is not None:
804 if extendnode is not None:
805 ui.write(_("Extending search to changeset %d:%s\n")
805 ui.write(_("Extending search to changeset %d:%s\n")
806 % (extendnode.rev(), extendnode))
806 % (extendnode.rev(), extendnode))
807 state['current'] = [extendnode.node()]
807 state['current'] = [extendnode.node()]
808 hbisect.save_state(repo, state)
808 hbisect.save_state(repo, state)
809 if noupdate:
809 if noupdate:
810 return
810 return
811 cmdutil.bailifchanged(repo)
811 cmdutil.bailifchanged(repo)
812 return hg.clean(repo, extendnode.node())
812 return hg.clean(repo, extendnode.node())
813 raise util.Abort(_("nothing to extend"))
813 raise util.Abort(_("nothing to extend"))
814
814
815 if changesets == 0:
815 if changesets == 0:
816 print_result(nodes, good)
816 print_result(nodes, good)
817 else:
817 else:
818 assert len(nodes) == 1 # only a single node can be tested next
818 assert len(nodes) == 1 # only a single node can be tested next
819 node = nodes[0]
819 node = nodes[0]
820 # compute the approximate number of remaining tests
820 # compute the approximate number of remaining tests
821 tests, size = 0, 2
821 tests, size = 0, 2
822 while size <= changesets:
822 while size <= changesets:
823 tests, size = tests + 1, size * 2
823 tests, size = tests + 1, size * 2
824 rev = repo.changelog.rev(node)
824 rev = repo.changelog.rev(node)
825 ui.write(_("Testing changeset %d:%s "
825 ui.write(_("Testing changeset %d:%s "
826 "(%d changesets remaining, ~%d tests)\n")
826 "(%d changesets remaining, ~%d tests)\n")
827 % (rev, short(node), changesets, tests))
827 % (rev, short(node), changesets, tests))
828 state['current'] = [node]
828 state['current'] = [node]
829 hbisect.save_state(repo, state)
829 hbisect.save_state(repo, state)
830 if not noupdate:
830 if not noupdate:
831 cmdutil.bailifchanged(repo)
831 cmdutil.bailifchanged(repo)
832 return hg.clean(repo, node)
832 return hg.clean(repo, node)
833
833
834 @command('bookmarks|bookmark',
834 @command('bookmarks|bookmark',
835 [('f', 'force', False, _('force')),
835 [('f', 'force', False, _('force')),
836 ('r', 'rev', '', _('revision'), _('REV')),
836 ('r', 'rev', '', _('revision'), _('REV')),
837 ('d', 'delete', False, _('delete a given bookmark')),
837 ('d', 'delete', False, _('delete a given bookmark')),
838 ('m', 'rename', '', _('rename a given bookmark'), _('NAME')),
838 ('m', 'rename', '', _('rename a given bookmark'), _('NAME')),
839 ('i', 'inactive', False, _('mark a bookmark inactive')),
839 ('i', 'inactive', False, _('mark a bookmark inactive')),
840 ] + formatteropts,
840 ] + formatteropts,
841 _('hg bookmarks [OPTIONS]... [NAME]...'))
841 _('hg bookmarks [OPTIONS]... [NAME]...'))
842 def bookmark(ui, repo, *names, **opts):
842 def bookmark(ui, repo, *names, **opts):
843 '''create a new bookmark or list existing bookmarks
843 '''create a new bookmark or list existing bookmarks
844
844
845 Bookmarks are labels on changesets to help track lines of development.
845 Bookmarks are labels on changesets to help track lines of development.
846 Bookmarks are unversioned and can be moved, renamed and deleted.
846 Bookmarks are unversioned and can be moved, renamed and deleted.
847 Deleting or moving a bookmark has no effect on the associated changesets.
847 Deleting or moving a bookmark has no effect on the associated changesets.
848
848
849 Creating or updating to a bookmark causes it to be marked as 'active'.
849 Creating or updating to a bookmark causes it to be marked as 'active'.
850 The active bookmark is indicated with a '*'.
850 The active bookmark is indicated with a '*'.
851 When a commit is made, the active bookmark will advance to the new commit.
851 When a commit is made, the active bookmark will advance to the new commit.
852 A plain :hg:`update` will also advance an active bookmark, if possible.
852 A plain :hg:`update` will also advance an active bookmark, if possible.
853 Updating away from a bookmark will cause it to be deactivated.
853 Updating away from a bookmark will cause it to be deactivated.
854
854
855 Bookmarks can be pushed and pulled between repositories (see
855 Bookmarks can be pushed and pulled between repositories (see
856 :hg:`help push` and :hg:`help pull`). If a shared bookmark has
856 :hg:`help push` and :hg:`help pull`). If a shared bookmark has
857 diverged, a new 'divergent bookmark' of the form 'name@path' will
857 diverged, a new 'divergent bookmark' of the form 'name@path' will
858 be created. Using :hg:`merge` will resolve the divergence.
858 be created. Using :hg:`merge` will resolve the divergence.
859
859
860 A bookmark named '@' has the special property that :hg:`clone` will
860 A bookmark named '@' has the special property that :hg:`clone` will
861 check it out by default if it exists.
861 check it out by default if it exists.
862
862
863 .. container:: verbose
863 .. container:: verbose
864
864
865 Examples:
865 Examples:
866
866
867 - create an active bookmark for a new line of development::
867 - create an active bookmark for a new line of development::
868
868
869 hg book new-feature
869 hg book new-feature
870
870
871 - create an inactive bookmark as a place marker::
871 - create an inactive bookmark as a place marker::
872
872
873 hg book -i reviewed
873 hg book -i reviewed
874
874
875 - create an inactive bookmark on another changeset::
875 - create an inactive bookmark on another changeset::
876
876
877 hg book -r .^ tested
877 hg book -r .^ tested
878
878
879 - move the '@' bookmark from another branch::
879 - move the '@' bookmark from another branch::
880
880
881 hg book -f @
881 hg book -f @
882 '''
882 '''
883 force = opts.get('force')
883 force = opts.get('force')
884 rev = opts.get('rev')
884 rev = opts.get('rev')
885 delete = opts.get('delete')
885 delete = opts.get('delete')
886 rename = opts.get('rename')
886 rename = opts.get('rename')
887 inactive = opts.get('inactive')
887 inactive = opts.get('inactive')
888
888
889 def checkformat(mark):
889 def checkformat(mark):
890 mark = mark.strip()
890 mark = mark.strip()
891 if not mark:
891 if not mark:
892 raise util.Abort(_("bookmark names cannot consist entirely of "
892 raise util.Abort(_("bookmark names cannot consist entirely of "
893 "whitespace"))
893 "whitespace"))
894 scmutil.checknewlabel(repo, mark, 'bookmark')
894 scmutil.checknewlabel(repo, mark, 'bookmark')
895 return mark
895 return mark
896
896
897 def checkconflict(repo, mark, cur, force=False, target=None):
897 def checkconflict(repo, mark, cur, force=False, target=None):
898 if mark in marks and not force:
898 if mark in marks and not force:
899 if target:
899 if target:
900 if marks[mark] == target and target == cur:
900 if marks[mark] == target and target == cur:
901 # re-activating a bookmark
901 # re-activating a bookmark
902 return
902 return
903 anc = repo.changelog.ancestors([repo[target].rev()])
903 anc = repo.changelog.ancestors([repo[target].rev()])
904 bmctx = repo[marks[mark]]
904 bmctx = repo[marks[mark]]
905 divs = [repo[b].node() for b in marks
905 divs = [repo[b].node() for b in marks
906 if b.split('@', 1)[0] == mark.split('@', 1)[0]]
906 if b.split('@', 1)[0] == mark.split('@', 1)[0]]
907
907
908 # allow resolving a single divergent bookmark even if moving
908 # allow resolving a single divergent bookmark even if moving
909 # the bookmark across branches when a revision is specified
909 # the bookmark across branches when a revision is specified
910 # that contains a divergent bookmark
910 # that contains a divergent bookmark
911 if bmctx.rev() not in anc and target in divs:
911 if bmctx.rev() not in anc and target in divs:
912 bookmarks.deletedivergent(repo, [target], mark)
912 bookmarks.deletedivergent(repo, [target], mark)
913 return
913 return
914
914
915 deletefrom = [b for b in divs
915 deletefrom = [b for b in divs
916 if repo[b].rev() in anc or b == target]
916 if repo[b].rev() in anc or b == target]
917 bookmarks.deletedivergent(repo, deletefrom, mark)
917 bookmarks.deletedivergent(repo, deletefrom, mark)
918 if bookmarks.validdest(repo, bmctx, repo[target]):
918 if bookmarks.validdest(repo, bmctx, repo[target]):
919 ui.status(_("moving bookmark '%s' forward from %s\n") %
919 ui.status(_("moving bookmark '%s' forward from %s\n") %
920 (mark, short(bmctx.node())))
920 (mark, short(bmctx.node())))
921 return
921 return
922 raise util.Abort(_("bookmark '%s' already exists "
922 raise util.Abort(_("bookmark '%s' already exists "
923 "(use -f to force)") % mark)
923 "(use -f to force)") % mark)
924 if ((mark in repo.branchmap() or mark == repo.dirstate.branch())
924 if ((mark in repo.branchmap() or mark == repo.dirstate.branch())
925 and not force):
925 and not force):
926 raise util.Abort(
926 raise util.Abort(
927 _("a bookmark cannot have the name of an existing branch"))
927 _("a bookmark cannot have the name of an existing branch"))
928
928
929 if delete and rename:
929 if delete and rename:
930 raise util.Abort(_("--delete and --rename are incompatible"))
930 raise util.Abort(_("--delete and --rename are incompatible"))
931 if delete and rev:
931 if delete and rev:
932 raise util.Abort(_("--rev is incompatible with --delete"))
932 raise util.Abort(_("--rev is incompatible with --delete"))
933 if rename and rev:
933 if rename and rev:
934 raise util.Abort(_("--rev is incompatible with --rename"))
934 raise util.Abort(_("--rev is incompatible with --rename"))
935 if not names and (delete or rev):
935 if not names and (delete or rev):
936 raise util.Abort(_("bookmark name required"))
936 raise util.Abort(_("bookmark name required"))
937
937
938 if delete or rename or names or inactive:
938 if delete or rename or names or inactive:
939 wlock = repo.wlock()
939 wlock = repo.wlock()
940 try:
940 try:
941 cur = repo.changectx('.').node()
941 cur = repo.changectx('.').node()
942 marks = repo._bookmarks
942 marks = repo._bookmarks
943 if delete:
943 if delete:
944 for mark in names:
944 for mark in names:
945 if mark not in marks:
945 if mark not in marks:
946 raise util.Abort(_("bookmark '%s' does not exist") %
946 raise util.Abort(_("bookmark '%s' does not exist") %
947 mark)
947 mark)
948 if mark == repo._bookmarkcurrent:
948 if mark == repo._bookmarkcurrent:
949 bookmarks.unsetcurrent(repo)
949 bookmarks.unsetcurrent(repo)
950 del marks[mark]
950 del marks[mark]
951 marks.write()
951 marks.write()
952
952
953 elif rename:
953 elif rename:
954 if not names:
954 if not names:
955 raise util.Abort(_("new bookmark name required"))
955 raise util.Abort(_("new bookmark name required"))
956 elif len(names) > 1:
956 elif len(names) > 1:
957 raise util.Abort(_("only one new bookmark name allowed"))
957 raise util.Abort(_("only one new bookmark name allowed"))
958 mark = checkformat(names[0])
958 mark = checkformat(names[0])
959 if rename not in marks:
959 if rename not in marks:
960 raise util.Abort(_("bookmark '%s' does not exist") % rename)
960 raise util.Abort(_("bookmark '%s' does not exist") % rename)
961 checkconflict(repo, mark, cur, force)
961 checkconflict(repo, mark, cur, force)
962 marks[mark] = marks[rename]
962 marks[mark] = marks[rename]
963 if repo._bookmarkcurrent == rename and not inactive:
963 if repo._bookmarkcurrent == rename and not inactive:
964 bookmarks.setcurrent(repo, mark)
964 bookmarks.setcurrent(repo, mark)
965 del marks[rename]
965 del marks[rename]
966 marks.write()
966 marks.write()
967
967
968 elif names:
968 elif names:
969 newact = None
969 newact = None
970 for mark in names:
970 for mark in names:
971 mark = checkformat(mark)
971 mark = checkformat(mark)
972 if newact is None:
972 if newact is None:
973 newact = mark
973 newact = mark
974 if inactive and mark == repo._bookmarkcurrent:
974 if inactive and mark == repo._bookmarkcurrent:
975 bookmarks.unsetcurrent(repo)
975 bookmarks.unsetcurrent(repo)
976 return
976 return
977 tgt = cur
977 tgt = cur
978 if rev:
978 if rev:
979 tgt = scmutil.revsingle(repo, rev).node()
979 tgt = scmutil.revsingle(repo, rev).node()
980 checkconflict(repo, mark, cur, force, tgt)
980 checkconflict(repo, mark, cur, force, tgt)
981 marks[mark] = tgt
981 marks[mark] = tgt
982 if not inactive and cur == marks[newact] and not rev:
982 if not inactive and cur == marks[newact] and not rev:
983 bookmarks.setcurrent(repo, newact)
983 bookmarks.setcurrent(repo, newact)
984 elif cur != tgt and newact == repo._bookmarkcurrent:
984 elif cur != tgt and newact == repo._bookmarkcurrent:
985 bookmarks.unsetcurrent(repo)
985 bookmarks.unsetcurrent(repo)
986 marks.write()
986 marks.write()
987
987
988 elif inactive:
988 elif inactive:
989 if len(marks) == 0:
989 if len(marks) == 0:
990 ui.status(_("no bookmarks set\n"))
990 ui.status(_("no bookmarks set\n"))
991 elif not repo._bookmarkcurrent:
991 elif not repo._bookmarkcurrent:
992 ui.status(_("no active bookmark\n"))
992 ui.status(_("no active bookmark\n"))
993 else:
993 else:
994 bookmarks.unsetcurrent(repo)
994 bookmarks.unsetcurrent(repo)
995 finally:
995 finally:
996 wlock.release()
996 wlock.release()
997 else: # show bookmarks
997 else: # show bookmarks
998 fm = ui.formatter('bookmarks', opts)
998 fm = ui.formatter('bookmarks', opts)
999 hexfn = fm.hexfunc
999 hexfn = fm.hexfunc
1000 marks = repo._bookmarks
1000 marks = repo._bookmarks
1001 if len(marks) == 0 and not fm:
1001 if len(marks) == 0 and not fm:
1002 ui.status(_("no bookmarks set\n"))
1002 ui.status(_("no bookmarks set\n"))
1003 for bmark, n in sorted(marks.iteritems()):
1003 for bmark, n in sorted(marks.iteritems()):
1004 current = repo._bookmarkcurrent
1004 current = repo._bookmarkcurrent
1005 if bmark == current:
1005 if bmark == current:
1006 prefix, label = '*', 'bookmarks.current'
1006 prefix, label = '*', 'bookmarks.current'
1007 else:
1007 else:
1008 prefix, label = ' ', ''
1008 prefix, label = ' ', ''
1009
1009
1010 fm.startitem()
1010 fm.startitem()
1011 if not ui.quiet:
1011 if not ui.quiet:
1012 fm.plain(' %s ' % prefix, label=label)
1012 fm.plain(' %s ' % prefix, label=label)
1013 fm.write('bookmark', '%s', bmark, label=label)
1013 fm.write('bookmark', '%s', bmark, label=label)
1014 pad = " " * (25 - encoding.colwidth(bmark))
1014 pad = " " * (25 - encoding.colwidth(bmark))
1015 fm.condwrite(not ui.quiet, 'rev node', pad + ' %d:%s',
1015 fm.condwrite(not ui.quiet, 'rev node', pad + ' %d:%s',
1016 repo.changelog.rev(n), hexfn(n), label=label)
1016 repo.changelog.rev(n), hexfn(n), label=label)
1017 fm.data(active=(bmark == current))
1017 fm.data(active=(bmark == current))
1018 fm.plain('\n')
1018 fm.plain('\n')
1019 fm.end()
1019 fm.end()
1020
1020
1021 @command('branch',
1021 @command('branch',
1022 [('f', 'force', None,
1022 [('f', 'force', None,
1023 _('set branch name even if it shadows an existing branch')),
1023 _('set branch name even if it shadows an existing branch')),
1024 ('C', 'clean', None, _('reset branch name to parent branch name'))],
1024 ('C', 'clean', None, _('reset branch name to parent branch name'))],
1025 _('[-fC] [NAME]'))
1025 _('[-fC] [NAME]'))
1026 def branch(ui, repo, label=None, **opts):
1026 def branch(ui, repo, label=None, **opts):
1027 """set or show the current branch name
1027 """set or show the current branch name
1028
1028
1029 .. note::
1029 .. note::
1030
1030
1031 Branch names are permanent and global. Use :hg:`bookmark` to create a
1031 Branch names are permanent and global. Use :hg:`bookmark` to create a
1032 light-weight bookmark instead. See :hg:`help glossary` for more
1032 light-weight bookmark instead. See :hg:`help glossary` for more
1033 information about named branches and bookmarks.
1033 information about named branches and bookmarks.
1034
1034
1035 With no argument, show the current branch name. With one argument,
1035 With no argument, show the current branch name. With one argument,
1036 set the working directory branch name (the branch will not exist
1036 set the working directory branch name (the branch will not exist
1037 in the repository until the next commit). Standard practice
1037 in the repository until the next commit). Standard practice
1038 recommends that primary development take place on the 'default'
1038 recommends that primary development take place on the 'default'
1039 branch.
1039 branch.
1040
1040
1041 Unless -f/--force is specified, branch will not let you set a
1041 Unless -f/--force is specified, branch will not let you set a
1042 branch name that already exists.
1042 branch name that already exists.
1043
1043
1044 Use -C/--clean to reset the working directory branch to that of
1044 Use -C/--clean to reset the working directory branch to that of
1045 the parent of the working directory, negating a previous branch
1045 the parent of the working directory, negating a previous branch
1046 change.
1046 change.
1047
1047
1048 Use the command :hg:`update` to switch to an existing branch. Use
1048 Use the command :hg:`update` to switch to an existing branch. Use
1049 :hg:`commit --close-branch` to mark this branch as closed.
1049 :hg:`commit --close-branch` to mark this branch as closed.
1050
1050
1051 Returns 0 on success.
1051 Returns 0 on success.
1052 """
1052 """
1053 if label:
1053 if label:
1054 label = label.strip()
1054 label = label.strip()
1055
1055
1056 if not opts.get('clean') and not label:
1056 if not opts.get('clean') and not label:
1057 ui.write("%s\n" % repo.dirstate.branch())
1057 ui.write("%s\n" % repo.dirstate.branch())
1058 return
1058 return
1059
1059
1060 wlock = repo.wlock()
1060 wlock = repo.wlock()
1061 try:
1061 try:
1062 if opts.get('clean'):
1062 if opts.get('clean'):
1063 label = repo[None].p1().branch()
1063 label = repo[None].p1().branch()
1064 repo.dirstate.setbranch(label)
1064 repo.dirstate.setbranch(label)
1065 ui.status(_('reset working directory to branch %s\n') % label)
1065 ui.status(_('reset working directory to branch %s\n') % label)
1066 elif label:
1066 elif label:
1067 if not opts.get('force') and label in repo.branchmap():
1067 if not opts.get('force') and label in repo.branchmap():
1068 if label not in [p.branch() for p in repo.parents()]:
1068 if label not in [p.branch() for p in repo.parents()]:
1069 raise util.Abort(_('a branch of the same name already'
1069 raise util.Abort(_('a branch of the same name already'
1070 ' exists'),
1070 ' exists'),
1071 # i18n: "it" refers to an existing branch
1071 # i18n: "it" refers to an existing branch
1072 hint=_("use 'hg update' to switch to it"))
1072 hint=_("use 'hg update' to switch to it"))
1073 scmutil.checknewlabel(repo, label, 'branch')
1073 scmutil.checknewlabel(repo, label, 'branch')
1074 repo.dirstate.setbranch(label)
1074 repo.dirstate.setbranch(label)
1075 ui.status(_('marked working directory as branch %s\n') % label)
1075 ui.status(_('marked working directory as branch %s\n') % label)
1076 ui.status(_('(branches are permanent and global, '
1076 ui.status(_('(branches are permanent and global, '
1077 'did you want a bookmark?)\n'))
1077 'did you want a bookmark?)\n'))
1078 finally:
1078 finally:
1079 wlock.release()
1079 wlock.release()
1080
1080
1081 @command('branches',
1081 @command('branches',
1082 [('a', 'active', False,
1082 [('a', 'active', False,
1083 _('show only branches that have unmerged heads (DEPRECATED)')),
1083 _('show only branches that have unmerged heads (DEPRECATED)')),
1084 ('c', 'closed', False, _('show normal and closed branches')),
1084 ('c', 'closed', False, _('show normal and closed branches')),
1085 ] + formatteropts,
1085 ] + formatteropts,
1086 _('[-ac]'))
1086 _('[-ac]'))
1087 def branches(ui, repo, active=False, closed=False, **opts):
1087 def branches(ui, repo, active=False, closed=False, **opts):
1088 """list repository named branches
1088 """list repository named branches
1089
1089
1090 List the repository's named branches, indicating which ones are
1090 List the repository's named branches, indicating which ones are
1091 inactive. If -c/--closed is specified, also list branches which have
1091 inactive. If -c/--closed is specified, also list branches which have
1092 been marked closed (see :hg:`commit --close-branch`).
1092 been marked closed (see :hg:`commit --close-branch`).
1093
1093
1094 Use the command :hg:`update` to switch to an existing branch.
1094 Use the command :hg:`update` to switch to an existing branch.
1095
1095
1096 Returns 0.
1096 Returns 0.
1097 """
1097 """
1098
1098
1099 fm = ui.formatter('branches', opts)
1099 fm = ui.formatter('branches', opts)
1100 hexfunc = fm.hexfunc
1100 hexfunc = fm.hexfunc
1101
1101
1102 allheads = set(repo.heads())
1102 allheads = set(repo.heads())
1103 branches = []
1103 branches = []
1104 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1104 for tag, heads, tip, isclosed in repo.branchmap().iterbranches():
1105 isactive = not isclosed and bool(set(heads) & allheads)
1105 isactive = not isclosed and bool(set(heads) & allheads)
1106 branches.append((tag, repo[tip], isactive, not isclosed))
1106 branches.append((tag, repo[tip], isactive, not isclosed))
1107 branches.sort(key=lambda i: (i[2], i[1].rev(), i[0], i[3]),
1107 branches.sort(key=lambda i: (i[2], i[1].rev(), i[0], i[3]),
1108 reverse=True)
1108 reverse=True)
1109
1109
1110 for tag, ctx, isactive, isopen in branches:
1110 for tag, ctx, isactive, isopen in branches:
1111 if active and not isactive:
1111 if active and not isactive:
1112 continue
1112 continue
1113 if isactive:
1113 if isactive:
1114 label = 'branches.active'
1114 label = 'branches.active'
1115 notice = ''
1115 notice = ''
1116 elif not isopen:
1116 elif not isopen:
1117 if not closed:
1117 if not closed:
1118 continue
1118 continue
1119 label = 'branches.closed'
1119 label = 'branches.closed'
1120 notice = _(' (closed)')
1120 notice = _(' (closed)')
1121 else:
1121 else:
1122 label = 'branches.inactive'
1122 label = 'branches.inactive'
1123 notice = _(' (inactive)')
1123 notice = _(' (inactive)')
1124 current = (tag == repo.dirstate.branch())
1124 current = (tag == repo.dirstate.branch())
1125 if current:
1125 if current:
1126 label = 'branches.current'
1126 label = 'branches.current'
1127
1127
1128 fm.startitem()
1128 fm.startitem()
1129 fm.write('branch', '%s', tag, label=label)
1129 fm.write('branch', '%s', tag, label=label)
1130 rev = ctx.rev()
1130 rev = ctx.rev()
1131 padsize = max(31 - len(str(rev)) - encoding.colwidth(tag), 0)
1131 padsize = max(31 - len(str(rev)) - encoding.colwidth(tag), 0)
1132 fmt = ' ' * padsize + ' %d:%s'
1132 fmt = ' ' * padsize + ' %d:%s'
1133 fm.condwrite(not ui.quiet, 'rev node', fmt, rev, hexfunc(ctx.node()),
1133 fm.condwrite(not ui.quiet, 'rev node', fmt, rev, hexfunc(ctx.node()),
1134 label='log.changeset changeset.%s' % ctx.phasestr())
1134 label='log.changeset changeset.%s' % ctx.phasestr())
1135 fm.data(active=isactive, closed=not isopen, current=current)
1135 fm.data(active=isactive, closed=not isopen, current=current)
1136 if not ui.quiet:
1136 if not ui.quiet:
1137 fm.plain(notice)
1137 fm.plain(notice)
1138 fm.plain('\n')
1138 fm.plain('\n')
1139 fm.end()
1139 fm.end()
1140
1140
1141 @command('bundle',
1141 @command('bundle',
1142 [('f', 'force', None, _('run even when the destination is unrelated')),
1142 [('f', 'force', None, _('run even when the destination is unrelated')),
1143 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
1143 ('r', 'rev', [], _('a changeset intended to be added to the destination'),
1144 _('REV')),
1144 _('REV')),
1145 ('b', 'branch', [], _('a specific branch you would like to bundle'),
1145 ('b', 'branch', [], _('a specific branch you would like to bundle'),
1146 _('BRANCH')),
1146 _('BRANCH')),
1147 ('', 'base', [],
1147 ('', 'base', [],
1148 _('a base changeset assumed to be available at the destination'),
1148 _('a base changeset assumed to be available at the destination'),
1149 _('REV')),
1149 _('REV')),
1150 ('a', 'all', None, _('bundle all changesets in the repository')),
1150 ('a', 'all', None, _('bundle all changesets in the repository')),
1151 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
1151 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE')),
1152 ] + remoteopts,
1152 ] + remoteopts,
1153 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
1153 _('[-f] [-t TYPE] [-a] [-r REV]... [--base REV]... FILE [DEST]'))
1154 def bundle(ui, repo, fname, dest=None, **opts):
1154 def bundle(ui, repo, fname, dest=None, **opts):
1155 """create a changegroup file
1155 """create a changegroup file
1156
1156
1157 Generate a compressed changegroup file collecting changesets not
1157 Generate a compressed changegroup file collecting changesets not
1158 known to be in another repository.
1158 known to be in another repository.
1159
1159
1160 If you omit the destination repository, then hg assumes the
1160 If you omit the destination repository, then hg assumes the
1161 destination will have all the nodes you specify with --base
1161 destination will have all the nodes you specify with --base
1162 parameters. To create a bundle containing all changesets, use
1162 parameters. To create a bundle containing all changesets, use
1163 -a/--all (or --base null).
1163 -a/--all (or --base null).
1164
1164
1165 You can change compression method with the -t/--type option.
1165 You can change compression method with the -t/--type option.
1166 The available compression methods are: none, bzip2, and
1166 The available compression methods are: none, bzip2, and
1167 gzip (by default, bundles are compressed using bzip2).
1167 gzip (by default, bundles are compressed using bzip2).
1168
1168
1169 The bundle file can then be transferred using conventional means
1169 The bundle file can then be transferred using conventional means
1170 and applied to another repository with the unbundle or pull
1170 and applied to another repository with the unbundle or pull
1171 command. This is useful when direct push and pull are not
1171 command. This is useful when direct push and pull are not
1172 available or when exporting an entire repository is undesirable.
1172 available or when exporting an entire repository is undesirable.
1173
1173
1174 Applying bundles preserves all changeset contents including
1174 Applying bundles preserves all changeset contents including
1175 permissions, copy/rename information, and revision history.
1175 permissions, copy/rename information, and revision history.
1176
1176
1177 Returns 0 on success, 1 if no changes found.
1177 Returns 0 on success, 1 if no changes found.
1178 """
1178 """
1179 revs = None
1179 revs = None
1180 if 'rev' in opts:
1180 if 'rev' in opts:
1181 revs = scmutil.revrange(repo, opts['rev'])
1181 revs = scmutil.revrange(repo, opts['rev'])
1182
1182
1183 bundletype = opts.get('type', 'bzip2').lower()
1183 bundletype = opts.get('type', 'bzip2').lower()
1184 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
1184 btypes = {'none': 'HG10UN',
1185 'bzip2': 'HG10BZ',
1186 'gzip': 'HG10GZ',
1187 'bundle2': 'HG2Y'}
1185 bundletype = btypes.get(bundletype)
1188 bundletype = btypes.get(bundletype)
1186 if bundletype not in changegroup.bundletypes:
1189 if bundletype not in changegroup.bundletypes:
1187 raise util.Abort(_('unknown bundle type specified with --type'))
1190 raise util.Abort(_('unknown bundle type specified with --type'))
1188
1191
1189 if opts.get('all'):
1192 if opts.get('all'):
1190 base = ['null']
1193 base = ['null']
1191 else:
1194 else:
1192 base = scmutil.revrange(repo, opts.get('base'))
1195 base = scmutil.revrange(repo, opts.get('base'))
1193 # TODO: get desired bundlecaps from command line.
1196 # TODO: get desired bundlecaps from command line.
1194 bundlecaps = None
1197 bundlecaps = None
1195 if base:
1198 if base:
1196 if dest:
1199 if dest:
1197 raise util.Abort(_("--base is incompatible with specifying "
1200 raise util.Abort(_("--base is incompatible with specifying "
1198 "a destination"))
1201 "a destination"))
1199 common = [repo.lookup(rev) for rev in base]
1202 common = [repo.lookup(rev) for rev in base]
1200 heads = revs and map(repo.lookup, revs) or revs
1203 heads = revs and map(repo.lookup, revs) or revs
1201 cg = changegroup.getchangegroup(repo, 'bundle', heads=heads,
1204 cg = changegroup.getchangegroup(repo, 'bundle', heads=heads,
1202 common=common, bundlecaps=bundlecaps)
1205 common=common, bundlecaps=bundlecaps)
1203 outgoing = None
1206 outgoing = None
1204 else:
1207 else:
1205 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1208 dest = ui.expandpath(dest or 'default-push', dest or 'default')
1206 dest, branches = hg.parseurl(dest, opts.get('branch'))
1209 dest, branches = hg.parseurl(dest, opts.get('branch'))
1207 other = hg.peer(repo, opts, dest)
1210 other = hg.peer(repo, opts, dest)
1208 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1211 revs, checkout = hg.addbranchrevs(repo, repo, branches, revs)
1209 heads = revs and map(repo.lookup, revs) or revs
1212 heads = revs and map(repo.lookup, revs) or revs
1210 outgoing = discovery.findcommonoutgoing(repo, other,
1213 outgoing = discovery.findcommonoutgoing(repo, other,
1211 onlyheads=heads,
1214 onlyheads=heads,
1212 force=opts.get('force'),
1215 force=opts.get('force'),
1213 portable=True)
1216 portable=True)
1214 cg = changegroup.getlocalchangegroup(repo, 'bundle', outgoing,
1217 cg = changegroup.getlocalchangegroup(repo, 'bundle', outgoing,
1215 bundlecaps)
1218 bundlecaps)
1216 if not cg:
1219 if not cg:
1217 scmutil.nochangesfound(ui, repo, outgoing and outgoing.excluded)
1220 scmutil.nochangesfound(ui, repo, outgoing and outgoing.excluded)
1218 return 1
1221 return 1
1219
1222
1220 changegroup.writebundle(ui, cg, fname, bundletype)
1223 changegroup.writebundle(ui, cg, fname, bundletype)
1221
1224
1222 @command('cat',
1225 @command('cat',
1223 [('o', 'output', '',
1226 [('o', 'output', '',
1224 _('print output to file with formatted name'), _('FORMAT')),
1227 _('print output to file with formatted name'), _('FORMAT')),
1225 ('r', 'rev', '', _('print the given revision'), _('REV')),
1228 ('r', 'rev', '', _('print the given revision'), _('REV')),
1226 ('', 'decode', None, _('apply any matching decode filter')),
1229 ('', 'decode', None, _('apply any matching decode filter')),
1227 ] + walkopts,
1230 ] + walkopts,
1228 _('[OPTION]... FILE...'),
1231 _('[OPTION]... FILE...'),
1229 inferrepo=True)
1232 inferrepo=True)
1230 def cat(ui, repo, file1, *pats, **opts):
1233 def cat(ui, repo, file1, *pats, **opts):
1231 """output the current or given revision of files
1234 """output the current or given revision of files
1232
1235
1233 Print the specified files as they were at the given revision. If
1236 Print the specified files as they were at the given revision. If
1234 no revision is given, the parent of the working directory is used.
1237 no revision is given, the parent of the working directory is used.
1235
1238
1236 Output may be to a file, in which case the name of the file is
1239 Output may be to a file, in which case the name of the file is
1237 given using a format string. The formatting rules as follows:
1240 given using a format string. The formatting rules as follows:
1238
1241
1239 :``%%``: literal "%" character
1242 :``%%``: literal "%" character
1240 :``%s``: basename of file being printed
1243 :``%s``: basename of file being printed
1241 :``%d``: dirname of file being printed, or '.' if in repository root
1244 :``%d``: dirname of file being printed, or '.' if in repository root
1242 :``%p``: root-relative path name of file being printed
1245 :``%p``: root-relative path name of file being printed
1243 :``%H``: changeset hash (40 hexadecimal digits)
1246 :``%H``: changeset hash (40 hexadecimal digits)
1244 :``%R``: changeset revision number
1247 :``%R``: changeset revision number
1245 :``%h``: short-form changeset hash (12 hexadecimal digits)
1248 :``%h``: short-form changeset hash (12 hexadecimal digits)
1246 :``%r``: zero-padded changeset revision number
1249 :``%r``: zero-padded changeset revision number
1247 :``%b``: basename of the exporting repository
1250 :``%b``: basename of the exporting repository
1248
1251
1249 Returns 0 on success.
1252 Returns 0 on success.
1250 """
1253 """
1251 ctx = scmutil.revsingle(repo, opts.get('rev'))
1254 ctx = scmutil.revsingle(repo, opts.get('rev'))
1252 m = scmutil.match(ctx, (file1,) + pats, opts)
1255 m = scmutil.match(ctx, (file1,) + pats, opts)
1253
1256
1254 return cmdutil.cat(ui, repo, ctx, m, '', **opts)
1257 return cmdutil.cat(ui, repo, ctx, m, '', **opts)
1255
1258
1256 @command('^clone',
1259 @command('^clone',
1257 [('U', 'noupdate', None,
1260 [('U', 'noupdate', None,
1258 _('the clone will include an empty working copy (only a repository)')),
1261 _('the clone will include an empty working copy (only a repository)')),
1259 ('u', 'updaterev', '', _('revision, tag or branch to check out'), _('REV')),
1262 ('u', 'updaterev', '', _('revision, tag or branch to check out'), _('REV')),
1260 ('r', 'rev', [], _('include the specified changeset'), _('REV')),
1263 ('r', 'rev', [], _('include the specified changeset'), _('REV')),
1261 ('b', 'branch', [], _('clone only the specified branch'), _('BRANCH')),
1264 ('b', 'branch', [], _('clone only the specified branch'), _('BRANCH')),
1262 ('', 'pull', None, _('use pull protocol to copy metadata')),
1265 ('', 'pull', None, _('use pull protocol to copy metadata')),
1263 ('', 'uncompressed', None, _('use uncompressed transfer (fast over LAN)')),
1266 ('', 'uncompressed', None, _('use uncompressed transfer (fast over LAN)')),
1264 ] + remoteopts,
1267 ] + remoteopts,
1265 _('[OPTION]... SOURCE [DEST]'),
1268 _('[OPTION]... SOURCE [DEST]'),
1266 norepo=True)
1269 norepo=True)
1267 def clone(ui, source, dest=None, **opts):
1270 def clone(ui, source, dest=None, **opts):
1268 """make a copy of an existing repository
1271 """make a copy of an existing repository
1269
1272
1270 Create a copy of an existing repository in a new directory.
1273 Create a copy of an existing repository in a new directory.
1271
1274
1272 If no destination directory name is specified, it defaults to the
1275 If no destination directory name is specified, it defaults to the
1273 basename of the source.
1276 basename of the source.
1274
1277
1275 The location of the source is added to the new repository's
1278 The location of the source is added to the new repository's
1276 ``.hg/hgrc`` file, as the default to be used for future pulls.
1279 ``.hg/hgrc`` file, as the default to be used for future pulls.
1277
1280
1278 Only local paths and ``ssh://`` URLs are supported as
1281 Only local paths and ``ssh://`` URLs are supported as
1279 destinations. For ``ssh://`` destinations, no working directory or
1282 destinations. For ``ssh://`` destinations, no working directory or
1280 ``.hg/hgrc`` will be created on the remote side.
1283 ``.hg/hgrc`` will be created on the remote side.
1281
1284
1282 To pull only a subset of changesets, specify one or more revisions
1285 To pull only a subset of changesets, specify one or more revisions
1283 identifiers with -r/--rev or branches with -b/--branch. The
1286 identifiers with -r/--rev or branches with -b/--branch. The
1284 resulting clone will contain only the specified changesets and
1287 resulting clone will contain only the specified changesets and
1285 their ancestors. These options (or 'clone src#rev dest') imply
1288 their ancestors. These options (or 'clone src#rev dest') imply
1286 --pull, even for local source repositories. Note that specifying a
1289 --pull, even for local source repositories. Note that specifying a
1287 tag will include the tagged changeset but not the changeset
1290 tag will include the tagged changeset but not the changeset
1288 containing the tag.
1291 containing the tag.
1289
1292
1290 If the source repository has a bookmark called '@' set, that
1293 If the source repository has a bookmark called '@' set, that
1291 revision will be checked out in the new repository by default.
1294 revision will be checked out in the new repository by default.
1292
1295
1293 To check out a particular version, use -u/--update, or
1296 To check out a particular version, use -u/--update, or
1294 -U/--noupdate to create a clone with no working directory.
1297 -U/--noupdate to create a clone with no working directory.
1295
1298
1296 .. container:: verbose
1299 .. container:: verbose
1297
1300
1298 For efficiency, hardlinks are used for cloning whenever the
1301 For efficiency, hardlinks are used for cloning whenever the
1299 source and destination are on the same filesystem (note this
1302 source and destination are on the same filesystem (note this
1300 applies only to the repository data, not to the working
1303 applies only to the repository data, not to the working
1301 directory). Some filesystems, such as AFS, implement hardlinking
1304 directory). Some filesystems, such as AFS, implement hardlinking
1302 incorrectly, but do not report errors. In these cases, use the
1305 incorrectly, but do not report errors. In these cases, use the
1303 --pull option to avoid hardlinking.
1306 --pull option to avoid hardlinking.
1304
1307
1305 In some cases, you can clone repositories and the working
1308 In some cases, you can clone repositories and the working
1306 directory using full hardlinks with ::
1309 directory using full hardlinks with ::
1307
1310
1308 $ cp -al REPO REPOCLONE
1311 $ cp -al REPO REPOCLONE
1309
1312
1310 This is the fastest way to clone, but it is not always safe. The
1313 This is the fastest way to clone, but it is not always safe. The
1311 operation is not atomic (making sure REPO is not modified during
1314 operation is not atomic (making sure REPO is not modified during
1312 the operation is up to you) and you have to make sure your
1315 the operation is up to you) and you have to make sure your
1313 editor breaks hardlinks (Emacs and most Linux Kernel tools do
1316 editor breaks hardlinks (Emacs and most Linux Kernel tools do
1314 so). Also, this is not compatible with certain extensions that
1317 so). Also, this is not compatible with certain extensions that
1315 place their metadata under the .hg directory, such as mq.
1318 place their metadata under the .hg directory, such as mq.
1316
1319
1317 Mercurial will update the working directory to the first applicable
1320 Mercurial will update the working directory to the first applicable
1318 revision from this list:
1321 revision from this list:
1319
1322
1320 a) null if -U or the source repository has no changesets
1323 a) null if -U or the source repository has no changesets
1321 b) if -u . and the source repository is local, the first parent of
1324 b) if -u . and the source repository is local, the first parent of
1322 the source repository's working directory
1325 the source repository's working directory
1323 c) the changeset specified with -u (if a branch name, this means the
1326 c) the changeset specified with -u (if a branch name, this means the
1324 latest head of that branch)
1327 latest head of that branch)
1325 d) the changeset specified with -r
1328 d) the changeset specified with -r
1326 e) the tipmost head specified with -b
1329 e) the tipmost head specified with -b
1327 f) the tipmost head specified with the url#branch source syntax
1330 f) the tipmost head specified with the url#branch source syntax
1328 g) the revision marked with the '@' bookmark, if present
1331 g) the revision marked with the '@' bookmark, if present
1329 h) the tipmost head of the default branch
1332 h) the tipmost head of the default branch
1330 i) tip
1333 i) tip
1331
1334
1332 Examples:
1335 Examples:
1333
1336
1334 - clone a remote repository to a new directory named hg/::
1337 - clone a remote repository to a new directory named hg/::
1335
1338
1336 hg clone http://selenic.com/hg
1339 hg clone http://selenic.com/hg
1337
1340
1338 - create a lightweight local clone::
1341 - create a lightweight local clone::
1339
1342
1340 hg clone project/ project-feature/
1343 hg clone project/ project-feature/
1341
1344
1342 - clone from an absolute path on an ssh server (note double-slash)::
1345 - clone from an absolute path on an ssh server (note double-slash)::
1343
1346
1344 hg clone ssh://user@server//home/projects/alpha/
1347 hg clone ssh://user@server//home/projects/alpha/
1345
1348
1346 - do a high-speed clone over a LAN while checking out a
1349 - do a high-speed clone over a LAN while checking out a
1347 specified version::
1350 specified version::
1348
1351
1349 hg clone --uncompressed http://server/repo -u 1.5
1352 hg clone --uncompressed http://server/repo -u 1.5
1350
1353
1351 - create a repository without changesets after a particular revision::
1354 - create a repository without changesets after a particular revision::
1352
1355
1353 hg clone -r 04e544 experimental/ good/
1356 hg clone -r 04e544 experimental/ good/
1354
1357
1355 - clone (and track) a particular named branch::
1358 - clone (and track) a particular named branch::
1356
1359
1357 hg clone http://selenic.com/hg#stable
1360 hg clone http://selenic.com/hg#stable
1358
1361
1359 See :hg:`help urls` for details on specifying URLs.
1362 See :hg:`help urls` for details on specifying URLs.
1360
1363
1361 Returns 0 on success.
1364 Returns 0 on success.
1362 """
1365 """
1363 if opts.get('noupdate') and opts.get('updaterev'):
1366 if opts.get('noupdate') and opts.get('updaterev'):
1364 raise util.Abort(_("cannot specify both --noupdate and --updaterev"))
1367 raise util.Abort(_("cannot specify both --noupdate and --updaterev"))
1365
1368
1366 r = hg.clone(ui, opts, source, dest,
1369 r = hg.clone(ui, opts, source, dest,
1367 pull=opts.get('pull'),
1370 pull=opts.get('pull'),
1368 stream=opts.get('uncompressed'),
1371 stream=opts.get('uncompressed'),
1369 rev=opts.get('rev'),
1372 rev=opts.get('rev'),
1370 update=opts.get('updaterev') or not opts.get('noupdate'),
1373 update=opts.get('updaterev') or not opts.get('noupdate'),
1371 branch=opts.get('branch'))
1374 branch=opts.get('branch'))
1372
1375
1373 return r is None
1376 return r is None
1374
1377
1375 @command('^commit|ci',
1378 @command('^commit|ci',
1376 [('A', 'addremove', None,
1379 [('A', 'addremove', None,
1377 _('mark new/missing files as added/removed before committing')),
1380 _('mark new/missing files as added/removed before committing')),
1378 ('', 'close-branch', None,
1381 ('', 'close-branch', None,
1379 _('mark a branch as closed, hiding it from the branch list')),
1382 _('mark a branch as closed, hiding it from the branch list')),
1380 ('', 'amend', None, _('amend the parent of the working dir')),
1383 ('', 'amend', None, _('amend the parent of the working dir')),
1381 ('s', 'secret', None, _('use the secret phase for committing')),
1384 ('s', 'secret', None, _('use the secret phase for committing')),
1382 ('e', 'edit', None, _('invoke editor on commit messages')),
1385 ('e', 'edit', None, _('invoke editor on commit messages')),
1383 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1386 ] + walkopts + commitopts + commitopts2 + subrepoopts,
1384 _('[OPTION]... [FILE]...'),
1387 _('[OPTION]... [FILE]...'),
1385 inferrepo=True)
1388 inferrepo=True)
1386 def commit(ui, repo, *pats, **opts):
1389 def commit(ui, repo, *pats, **opts):
1387 """commit the specified files or all outstanding changes
1390 """commit the specified files or all outstanding changes
1388
1391
1389 Commit changes to the given files into the repository. Unlike a
1392 Commit changes to the given files into the repository. Unlike a
1390 centralized SCM, this operation is a local operation. See
1393 centralized SCM, this operation is a local operation. See
1391 :hg:`push` for a way to actively distribute your changes.
1394 :hg:`push` for a way to actively distribute your changes.
1392
1395
1393 If a list of files is omitted, all changes reported by :hg:`status`
1396 If a list of files is omitted, all changes reported by :hg:`status`
1394 will be committed.
1397 will be committed.
1395
1398
1396 If you are committing the result of a merge, do not provide any
1399 If you are committing the result of a merge, do not provide any
1397 filenames or -I/-X filters.
1400 filenames or -I/-X filters.
1398
1401
1399 If no commit message is specified, Mercurial starts your
1402 If no commit message is specified, Mercurial starts your
1400 configured editor where you can enter a message. In case your
1403 configured editor where you can enter a message. In case your
1401 commit fails, you will find a backup of your message in
1404 commit fails, you will find a backup of your message in
1402 ``.hg/last-message.txt``.
1405 ``.hg/last-message.txt``.
1403
1406
1404 The --amend flag can be used to amend the parent of the
1407 The --amend flag can be used to amend the parent of the
1405 working directory with a new commit that contains the changes
1408 working directory with a new commit that contains the changes
1406 in the parent in addition to those currently reported by :hg:`status`,
1409 in the parent in addition to those currently reported by :hg:`status`,
1407 if there are any. The old commit is stored in a backup bundle in
1410 if there are any. The old commit is stored in a backup bundle in
1408 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1411 ``.hg/strip-backup`` (see :hg:`help bundle` and :hg:`help unbundle`
1409 on how to restore it).
1412 on how to restore it).
1410
1413
1411 Message, user and date are taken from the amended commit unless
1414 Message, user and date are taken from the amended commit unless
1412 specified. When a message isn't specified on the command line,
1415 specified. When a message isn't specified on the command line,
1413 the editor will open with the message of the amended commit.
1416 the editor will open with the message of the amended commit.
1414
1417
1415 It is not possible to amend public changesets (see :hg:`help phases`)
1418 It is not possible to amend public changesets (see :hg:`help phases`)
1416 or changesets that have children.
1419 or changesets that have children.
1417
1420
1418 See :hg:`help dates` for a list of formats valid for -d/--date.
1421 See :hg:`help dates` for a list of formats valid for -d/--date.
1419
1422
1420 Returns 0 on success, 1 if nothing changed.
1423 Returns 0 on success, 1 if nothing changed.
1421 """
1424 """
1422 if opts.get('subrepos'):
1425 if opts.get('subrepos'):
1423 if opts.get('amend'):
1426 if opts.get('amend'):
1424 raise util.Abort(_('cannot amend with --subrepos'))
1427 raise util.Abort(_('cannot amend with --subrepos'))
1425 # Let --subrepos on the command line override config setting.
1428 # Let --subrepos on the command line override config setting.
1426 ui.setconfig('ui', 'commitsubrepos', True, 'commit')
1429 ui.setconfig('ui', 'commitsubrepos', True, 'commit')
1427
1430
1428 cmdutil.checkunfinished(repo, commit=True)
1431 cmdutil.checkunfinished(repo, commit=True)
1429
1432
1430 branch = repo[None].branch()
1433 branch = repo[None].branch()
1431 bheads = repo.branchheads(branch)
1434 bheads = repo.branchheads(branch)
1432
1435
1433 extra = {}
1436 extra = {}
1434 if opts.get('close_branch'):
1437 if opts.get('close_branch'):
1435 extra['close'] = 1
1438 extra['close'] = 1
1436
1439
1437 if not bheads:
1440 if not bheads:
1438 raise util.Abort(_('can only close branch heads'))
1441 raise util.Abort(_('can only close branch heads'))
1439 elif opts.get('amend'):
1442 elif opts.get('amend'):
1440 if repo.parents()[0].p1().branch() != branch and \
1443 if repo.parents()[0].p1().branch() != branch and \
1441 repo.parents()[0].p2().branch() != branch:
1444 repo.parents()[0].p2().branch() != branch:
1442 raise util.Abort(_('can only close branch heads'))
1445 raise util.Abort(_('can only close branch heads'))
1443
1446
1444 if opts.get('amend'):
1447 if opts.get('amend'):
1445 if ui.configbool('ui', 'commitsubrepos'):
1448 if ui.configbool('ui', 'commitsubrepos'):
1446 raise util.Abort(_('cannot amend with ui.commitsubrepos enabled'))
1449 raise util.Abort(_('cannot amend with ui.commitsubrepos enabled'))
1447
1450
1448 old = repo['.']
1451 old = repo['.']
1449 if not old.mutable():
1452 if not old.mutable():
1450 raise util.Abort(_('cannot amend public changesets'))
1453 raise util.Abort(_('cannot amend public changesets'))
1451 if len(repo[None].parents()) > 1:
1454 if len(repo[None].parents()) > 1:
1452 raise util.Abort(_('cannot amend while merging'))
1455 raise util.Abort(_('cannot amend while merging'))
1453 allowunstable = obsolete.isenabled(repo, obsolete.allowunstableopt)
1456 allowunstable = obsolete.isenabled(repo, obsolete.allowunstableopt)
1454 if not allowunstable and old.children():
1457 if not allowunstable and old.children():
1455 raise util.Abort(_('cannot amend changeset with children'))
1458 raise util.Abort(_('cannot amend changeset with children'))
1456
1459
1457 # commitfunc is used only for temporary amend commit by cmdutil.amend
1460 # commitfunc is used only for temporary amend commit by cmdutil.amend
1458 def commitfunc(ui, repo, message, match, opts):
1461 def commitfunc(ui, repo, message, match, opts):
1459 return repo.commit(message,
1462 return repo.commit(message,
1460 opts.get('user') or old.user(),
1463 opts.get('user') or old.user(),
1461 opts.get('date') or old.date(),
1464 opts.get('date') or old.date(),
1462 match,
1465 match,
1463 extra=extra)
1466 extra=extra)
1464
1467
1465 current = repo._bookmarkcurrent
1468 current = repo._bookmarkcurrent
1466 marks = old.bookmarks()
1469 marks = old.bookmarks()
1467 node = cmdutil.amend(ui, repo, commitfunc, old, extra, pats, opts)
1470 node = cmdutil.amend(ui, repo, commitfunc, old, extra, pats, opts)
1468 if node == old.node():
1471 if node == old.node():
1469 ui.status(_("nothing changed\n"))
1472 ui.status(_("nothing changed\n"))
1470 return 1
1473 return 1
1471 elif marks:
1474 elif marks:
1472 ui.debug('moving bookmarks %r from %s to %s\n' %
1475 ui.debug('moving bookmarks %r from %s to %s\n' %
1473 (marks, old.hex(), hex(node)))
1476 (marks, old.hex(), hex(node)))
1474 newmarks = repo._bookmarks
1477 newmarks = repo._bookmarks
1475 for bm in marks:
1478 for bm in marks:
1476 newmarks[bm] = node
1479 newmarks[bm] = node
1477 if bm == current:
1480 if bm == current:
1478 bookmarks.setcurrent(repo, bm)
1481 bookmarks.setcurrent(repo, bm)
1479 newmarks.write()
1482 newmarks.write()
1480 else:
1483 else:
1481 def commitfunc(ui, repo, message, match, opts):
1484 def commitfunc(ui, repo, message, match, opts):
1482 backup = ui.backupconfig('phases', 'new-commit')
1485 backup = ui.backupconfig('phases', 'new-commit')
1483 baseui = repo.baseui
1486 baseui = repo.baseui
1484 basebackup = baseui.backupconfig('phases', 'new-commit')
1487 basebackup = baseui.backupconfig('phases', 'new-commit')
1485 try:
1488 try:
1486 if opts.get('secret'):
1489 if opts.get('secret'):
1487 ui.setconfig('phases', 'new-commit', 'secret', 'commit')
1490 ui.setconfig('phases', 'new-commit', 'secret', 'commit')
1488 # Propagate to subrepos
1491 # Propagate to subrepos
1489 baseui.setconfig('phases', 'new-commit', 'secret', 'commit')
1492 baseui.setconfig('phases', 'new-commit', 'secret', 'commit')
1490
1493
1491 editform = cmdutil.mergeeditform(repo[None], 'commit.normal')
1494 editform = cmdutil.mergeeditform(repo[None], 'commit.normal')
1492 editor = cmdutil.getcommiteditor(editform=editform, **opts)
1495 editor = cmdutil.getcommiteditor(editform=editform, **opts)
1493 return repo.commit(message, opts.get('user'), opts.get('date'),
1496 return repo.commit(message, opts.get('user'), opts.get('date'),
1494 match,
1497 match,
1495 editor=editor,
1498 editor=editor,
1496 extra=extra)
1499 extra=extra)
1497 finally:
1500 finally:
1498 ui.restoreconfig(backup)
1501 ui.restoreconfig(backup)
1499 repo.baseui.restoreconfig(basebackup)
1502 repo.baseui.restoreconfig(basebackup)
1500
1503
1501
1504
1502 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1505 node = cmdutil.commit(ui, repo, commitfunc, pats, opts)
1503
1506
1504 if not node:
1507 if not node:
1505 stat = repo.status(match=scmutil.match(repo[None], pats, opts))
1508 stat = repo.status(match=scmutil.match(repo[None], pats, opts))
1506 if stat[3]:
1509 if stat[3]:
1507 ui.status(_("nothing changed (%d missing files, see "
1510 ui.status(_("nothing changed (%d missing files, see "
1508 "'hg status')\n") % len(stat[3]))
1511 "'hg status')\n") % len(stat[3]))
1509 else:
1512 else:
1510 ui.status(_("nothing changed\n"))
1513 ui.status(_("nothing changed\n"))
1511 return 1
1514 return 1
1512
1515
1513 cmdutil.commitstatus(repo, node, branch, bheads, opts)
1516 cmdutil.commitstatus(repo, node, branch, bheads, opts)
1514
1517
1515 @command('config|showconfig|debugconfig',
1518 @command('config|showconfig|debugconfig',
1516 [('u', 'untrusted', None, _('show untrusted configuration options')),
1519 [('u', 'untrusted', None, _('show untrusted configuration options')),
1517 ('e', 'edit', None, _('edit user config')),
1520 ('e', 'edit', None, _('edit user config')),
1518 ('l', 'local', None, _('edit repository config')),
1521 ('l', 'local', None, _('edit repository config')),
1519 ('g', 'global', None, _('edit global config'))],
1522 ('g', 'global', None, _('edit global config'))],
1520 _('[-u] [NAME]...'),
1523 _('[-u] [NAME]...'),
1521 optionalrepo=True)
1524 optionalrepo=True)
1522 def config(ui, repo, *values, **opts):
1525 def config(ui, repo, *values, **opts):
1523 """show combined config settings from all hgrc files
1526 """show combined config settings from all hgrc files
1524
1527
1525 With no arguments, print names and values of all config items.
1528 With no arguments, print names and values of all config items.
1526
1529
1527 With one argument of the form section.name, print just the value
1530 With one argument of the form section.name, print just the value
1528 of that config item.
1531 of that config item.
1529
1532
1530 With multiple arguments, print names and values of all config
1533 With multiple arguments, print names and values of all config
1531 items with matching section names.
1534 items with matching section names.
1532
1535
1533 With --edit, start an editor on the user-level config file. With
1536 With --edit, start an editor on the user-level config file. With
1534 --global, edit the system-wide config file. With --local, edit the
1537 --global, edit the system-wide config file. With --local, edit the
1535 repository-level config file.
1538 repository-level config file.
1536
1539
1537 With --debug, the source (filename and line number) is printed
1540 With --debug, the source (filename and line number) is printed
1538 for each config item.
1541 for each config item.
1539
1542
1540 See :hg:`help config` for more information about config files.
1543 See :hg:`help config` for more information about config files.
1541
1544
1542 Returns 0 on success, 1 if NAME does not exist.
1545 Returns 0 on success, 1 if NAME does not exist.
1543
1546
1544 """
1547 """
1545
1548
1546 if opts.get('edit') or opts.get('local') or opts.get('global'):
1549 if opts.get('edit') or opts.get('local') or opts.get('global'):
1547 if opts.get('local') and opts.get('global'):
1550 if opts.get('local') and opts.get('global'):
1548 raise util.Abort(_("can't use --local and --global together"))
1551 raise util.Abort(_("can't use --local and --global together"))
1549
1552
1550 if opts.get('local'):
1553 if opts.get('local'):
1551 if not repo:
1554 if not repo:
1552 raise util.Abort(_("can't use --local outside a repository"))
1555 raise util.Abort(_("can't use --local outside a repository"))
1553 paths = [repo.join('hgrc')]
1556 paths = [repo.join('hgrc')]
1554 elif opts.get('global'):
1557 elif opts.get('global'):
1555 paths = scmutil.systemrcpath()
1558 paths = scmutil.systemrcpath()
1556 else:
1559 else:
1557 paths = scmutil.userrcpath()
1560 paths = scmutil.userrcpath()
1558
1561
1559 for f in paths:
1562 for f in paths:
1560 if os.path.exists(f):
1563 if os.path.exists(f):
1561 break
1564 break
1562 else:
1565 else:
1563 if opts.get('global'):
1566 if opts.get('global'):
1564 samplehgrc = uimod.samplehgrcs['global']
1567 samplehgrc = uimod.samplehgrcs['global']
1565 elif opts.get('local'):
1568 elif opts.get('local'):
1566 samplehgrc = uimod.samplehgrcs['local']
1569 samplehgrc = uimod.samplehgrcs['local']
1567 else:
1570 else:
1568 samplehgrc = uimod.samplehgrcs['user']
1571 samplehgrc = uimod.samplehgrcs['user']
1569
1572
1570 f = paths[0]
1573 f = paths[0]
1571 fp = open(f, "w")
1574 fp = open(f, "w")
1572 fp.write(samplehgrc)
1575 fp.write(samplehgrc)
1573 fp.close()
1576 fp.close()
1574
1577
1575 editor = ui.geteditor()
1578 editor = ui.geteditor()
1576 ui.system("%s \"%s\"" % (editor, f),
1579 ui.system("%s \"%s\"" % (editor, f),
1577 onerr=util.Abort, errprefix=_("edit failed"))
1580 onerr=util.Abort, errprefix=_("edit failed"))
1578 return
1581 return
1579
1582
1580 for f in scmutil.rcpath():
1583 for f in scmutil.rcpath():
1581 ui.debug('read config from: %s\n' % f)
1584 ui.debug('read config from: %s\n' % f)
1582 untrusted = bool(opts.get('untrusted'))
1585 untrusted = bool(opts.get('untrusted'))
1583 if values:
1586 if values:
1584 sections = [v for v in values if '.' not in v]
1587 sections = [v for v in values if '.' not in v]
1585 items = [v for v in values if '.' in v]
1588 items = [v for v in values if '.' in v]
1586 if len(items) > 1 or items and sections:
1589 if len(items) > 1 or items and sections:
1587 raise util.Abort(_('only one config item permitted'))
1590 raise util.Abort(_('only one config item permitted'))
1588 matched = False
1591 matched = False
1589 for section, name, value in ui.walkconfig(untrusted=untrusted):
1592 for section, name, value in ui.walkconfig(untrusted=untrusted):
1590 value = str(value).replace('\n', '\\n')
1593 value = str(value).replace('\n', '\\n')
1591 sectname = section + '.' + name
1594 sectname = section + '.' + name
1592 if values:
1595 if values:
1593 for v in values:
1596 for v in values:
1594 if v == section:
1597 if v == section:
1595 ui.debug('%s: ' %
1598 ui.debug('%s: ' %
1596 ui.configsource(section, name, untrusted))
1599 ui.configsource(section, name, untrusted))
1597 ui.write('%s=%s\n' % (sectname, value))
1600 ui.write('%s=%s\n' % (sectname, value))
1598 matched = True
1601 matched = True
1599 elif v == sectname:
1602 elif v == sectname:
1600 ui.debug('%s: ' %
1603 ui.debug('%s: ' %
1601 ui.configsource(section, name, untrusted))
1604 ui.configsource(section, name, untrusted))
1602 ui.write(value, '\n')
1605 ui.write(value, '\n')
1603 matched = True
1606 matched = True
1604 else:
1607 else:
1605 ui.debug('%s: ' %
1608 ui.debug('%s: ' %
1606 ui.configsource(section, name, untrusted))
1609 ui.configsource(section, name, untrusted))
1607 ui.write('%s=%s\n' % (sectname, value))
1610 ui.write('%s=%s\n' % (sectname, value))
1608 matched = True
1611 matched = True
1609 if matched:
1612 if matched:
1610 return 0
1613 return 0
1611 return 1
1614 return 1
1612
1615
1613 @command('copy|cp',
1616 @command('copy|cp',
1614 [('A', 'after', None, _('record a copy that has already occurred')),
1617 [('A', 'after', None, _('record a copy that has already occurred')),
1615 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1618 ('f', 'force', None, _('forcibly copy over an existing managed file')),
1616 ] + walkopts + dryrunopts,
1619 ] + walkopts + dryrunopts,
1617 _('[OPTION]... [SOURCE]... DEST'))
1620 _('[OPTION]... [SOURCE]... DEST'))
1618 def copy(ui, repo, *pats, **opts):
1621 def copy(ui, repo, *pats, **opts):
1619 """mark files as copied for the next commit
1622 """mark files as copied for the next commit
1620
1623
1621 Mark dest as having copies of source files. If dest is a
1624 Mark dest as having copies of source files. If dest is a
1622 directory, copies are put in that directory. If dest is a file,
1625 directory, copies are put in that directory. If dest is a file,
1623 the source must be a single file.
1626 the source must be a single file.
1624
1627
1625 By default, this command copies the contents of files as they
1628 By default, this command copies the contents of files as they
1626 exist in the working directory. If invoked with -A/--after, the
1629 exist in the working directory. If invoked with -A/--after, the
1627 operation is recorded, but no copying is performed.
1630 operation is recorded, but no copying is performed.
1628
1631
1629 This command takes effect with the next commit. To undo a copy
1632 This command takes effect with the next commit. To undo a copy
1630 before that, see :hg:`revert`.
1633 before that, see :hg:`revert`.
1631
1634
1632 Returns 0 on success, 1 if errors are encountered.
1635 Returns 0 on success, 1 if errors are encountered.
1633 """
1636 """
1634 wlock = repo.wlock(False)
1637 wlock = repo.wlock(False)
1635 try:
1638 try:
1636 return cmdutil.copy(ui, repo, pats, opts)
1639 return cmdutil.copy(ui, repo, pats, opts)
1637 finally:
1640 finally:
1638 wlock.release()
1641 wlock.release()
1639
1642
1640 @command('debugancestor', [], _('[INDEX] REV1 REV2'), optionalrepo=True)
1643 @command('debugancestor', [], _('[INDEX] REV1 REV2'), optionalrepo=True)
1641 def debugancestor(ui, repo, *args):
1644 def debugancestor(ui, repo, *args):
1642 """find the ancestor revision of two revisions in a given index"""
1645 """find the ancestor revision of two revisions in a given index"""
1643 if len(args) == 3:
1646 if len(args) == 3:
1644 index, rev1, rev2 = args
1647 index, rev1, rev2 = args
1645 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), index)
1648 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), index)
1646 lookup = r.lookup
1649 lookup = r.lookup
1647 elif len(args) == 2:
1650 elif len(args) == 2:
1648 if not repo:
1651 if not repo:
1649 raise util.Abort(_("there is no Mercurial repository here "
1652 raise util.Abort(_("there is no Mercurial repository here "
1650 "(.hg not found)"))
1653 "(.hg not found)"))
1651 rev1, rev2 = args
1654 rev1, rev2 = args
1652 r = repo.changelog
1655 r = repo.changelog
1653 lookup = repo.lookup
1656 lookup = repo.lookup
1654 else:
1657 else:
1655 raise util.Abort(_('either two or three arguments required'))
1658 raise util.Abort(_('either two or three arguments required'))
1656 a = r.ancestor(lookup(rev1), lookup(rev2))
1659 a = r.ancestor(lookup(rev1), lookup(rev2))
1657 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
1660 ui.write("%d:%s\n" % (r.rev(a), hex(a)))
1658
1661
1659 @command('debugbuilddag',
1662 @command('debugbuilddag',
1660 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
1663 [('m', 'mergeable-file', None, _('add single file mergeable changes')),
1661 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
1664 ('o', 'overwritten-file', None, _('add single file all revs overwrite')),
1662 ('n', 'new-file', None, _('add new file at each rev'))],
1665 ('n', 'new-file', None, _('add new file at each rev'))],
1663 _('[OPTION]... [TEXT]'))
1666 _('[OPTION]... [TEXT]'))
1664 def debugbuilddag(ui, repo, text=None,
1667 def debugbuilddag(ui, repo, text=None,
1665 mergeable_file=False,
1668 mergeable_file=False,
1666 overwritten_file=False,
1669 overwritten_file=False,
1667 new_file=False):
1670 new_file=False):
1668 """builds a repo with a given DAG from scratch in the current empty repo
1671 """builds a repo with a given DAG from scratch in the current empty repo
1669
1672
1670 The description of the DAG is read from stdin if not given on the
1673 The description of the DAG is read from stdin if not given on the
1671 command line.
1674 command line.
1672
1675
1673 Elements:
1676 Elements:
1674
1677
1675 - "+n" is a linear run of n nodes based on the current default parent
1678 - "+n" is a linear run of n nodes based on the current default parent
1676 - "." is a single node based on the current default parent
1679 - "." is a single node based on the current default parent
1677 - "$" resets the default parent to null (implied at the start);
1680 - "$" resets the default parent to null (implied at the start);
1678 otherwise the default parent is always the last node created
1681 otherwise the default parent is always the last node created
1679 - "<p" sets the default parent to the backref p
1682 - "<p" sets the default parent to the backref p
1680 - "*p" is a fork at parent p, which is a backref
1683 - "*p" is a fork at parent p, which is a backref
1681 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
1684 - "*p1/p2" is a merge of parents p1 and p2, which are backrefs
1682 - "/p2" is a merge of the preceding node and p2
1685 - "/p2" is a merge of the preceding node and p2
1683 - ":tag" defines a local tag for the preceding node
1686 - ":tag" defines a local tag for the preceding node
1684 - "@branch" sets the named branch for subsequent nodes
1687 - "@branch" sets the named branch for subsequent nodes
1685 - "#...\\n" is a comment up to the end of the line
1688 - "#...\\n" is a comment up to the end of the line
1686
1689
1687 Whitespace between the above elements is ignored.
1690 Whitespace between the above elements is ignored.
1688
1691
1689 A backref is either
1692 A backref is either
1690
1693
1691 - a number n, which references the node curr-n, where curr is the current
1694 - a number n, which references the node curr-n, where curr is the current
1692 node, or
1695 node, or
1693 - the name of a local tag you placed earlier using ":tag", or
1696 - the name of a local tag you placed earlier using ":tag", or
1694 - empty to denote the default parent.
1697 - empty to denote the default parent.
1695
1698
1696 All string valued-elements are either strictly alphanumeric, or must
1699 All string valued-elements are either strictly alphanumeric, or must
1697 be enclosed in double quotes ("..."), with "\\" as escape character.
1700 be enclosed in double quotes ("..."), with "\\" as escape character.
1698 """
1701 """
1699
1702
1700 if text is None:
1703 if text is None:
1701 ui.status(_("reading DAG from stdin\n"))
1704 ui.status(_("reading DAG from stdin\n"))
1702 text = ui.fin.read()
1705 text = ui.fin.read()
1703
1706
1704 cl = repo.changelog
1707 cl = repo.changelog
1705 if len(cl) > 0:
1708 if len(cl) > 0:
1706 raise util.Abort(_('repository is not empty'))
1709 raise util.Abort(_('repository is not empty'))
1707
1710
1708 # determine number of revs in DAG
1711 # determine number of revs in DAG
1709 total = 0
1712 total = 0
1710 for type, data in dagparser.parsedag(text):
1713 for type, data in dagparser.parsedag(text):
1711 if type == 'n':
1714 if type == 'n':
1712 total += 1
1715 total += 1
1713
1716
1714 if mergeable_file:
1717 if mergeable_file:
1715 linesperrev = 2
1718 linesperrev = 2
1716 # make a file with k lines per rev
1719 # make a file with k lines per rev
1717 initialmergedlines = [str(i) for i in xrange(0, total * linesperrev)]
1720 initialmergedlines = [str(i) for i in xrange(0, total * linesperrev)]
1718 initialmergedlines.append("")
1721 initialmergedlines.append("")
1719
1722
1720 tags = []
1723 tags = []
1721
1724
1722 lock = tr = None
1725 lock = tr = None
1723 try:
1726 try:
1724 lock = repo.lock()
1727 lock = repo.lock()
1725 tr = repo.transaction("builddag")
1728 tr = repo.transaction("builddag")
1726
1729
1727 at = -1
1730 at = -1
1728 atbranch = 'default'
1731 atbranch = 'default'
1729 nodeids = []
1732 nodeids = []
1730 id = 0
1733 id = 0
1731 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1734 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1732 for type, data in dagparser.parsedag(text):
1735 for type, data in dagparser.parsedag(text):
1733 if type == 'n':
1736 if type == 'n':
1734 ui.note(('node %s\n' % str(data)))
1737 ui.note(('node %s\n' % str(data)))
1735 id, ps = data
1738 id, ps = data
1736
1739
1737 files = []
1740 files = []
1738 fctxs = {}
1741 fctxs = {}
1739
1742
1740 p2 = None
1743 p2 = None
1741 if mergeable_file:
1744 if mergeable_file:
1742 fn = "mf"
1745 fn = "mf"
1743 p1 = repo[ps[0]]
1746 p1 = repo[ps[0]]
1744 if len(ps) > 1:
1747 if len(ps) > 1:
1745 p2 = repo[ps[1]]
1748 p2 = repo[ps[1]]
1746 pa = p1.ancestor(p2)
1749 pa = p1.ancestor(p2)
1747 base, local, other = [x[fn].data() for x in (pa, p1,
1750 base, local, other = [x[fn].data() for x in (pa, p1,
1748 p2)]
1751 p2)]
1749 m3 = simplemerge.Merge3Text(base, local, other)
1752 m3 = simplemerge.Merge3Text(base, local, other)
1750 ml = [l.strip() for l in m3.merge_lines()]
1753 ml = [l.strip() for l in m3.merge_lines()]
1751 ml.append("")
1754 ml.append("")
1752 elif at > 0:
1755 elif at > 0:
1753 ml = p1[fn].data().split("\n")
1756 ml = p1[fn].data().split("\n")
1754 else:
1757 else:
1755 ml = initialmergedlines
1758 ml = initialmergedlines
1756 ml[id * linesperrev] += " r%i" % id
1759 ml[id * linesperrev] += " r%i" % id
1757 mergedtext = "\n".join(ml)
1760 mergedtext = "\n".join(ml)
1758 files.append(fn)
1761 files.append(fn)
1759 fctxs[fn] = context.memfilectx(repo, fn, mergedtext)
1762 fctxs[fn] = context.memfilectx(repo, fn, mergedtext)
1760
1763
1761 if overwritten_file:
1764 if overwritten_file:
1762 fn = "of"
1765 fn = "of"
1763 files.append(fn)
1766 files.append(fn)
1764 fctxs[fn] = context.memfilectx(repo, fn, "r%i\n" % id)
1767 fctxs[fn] = context.memfilectx(repo, fn, "r%i\n" % id)
1765
1768
1766 if new_file:
1769 if new_file:
1767 fn = "nf%i" % id
1770 fn = "nf%i" % id
1768 files.append(fn)
1771 files.append(fn)
1769 fctxs[fn] = context.memfilectx(repo, fn, "r%i\n" % id)
1772 fctxs[fn] = context.memfilectx(repo, fn, "r%i\n" % id)
1770 if len(ps) > 1:
1773 if len(ps) > 1:
1771 if not p2:
1774 if not p2:
1772 p2 = repo[ps[1]]
1775 p2 = repo[ps[1]]
1773 for fn in p2:
1776 for fn in p2:
1774 if fn.startswith("nf"):
1777 if fn.startswith("nf"):
1775 files.append(fn)
1778 files.append(fn)
1776 fctxs[fn] = p2[fn]
1779 fctxs[fn] = p2[fn]
1777
1780
1778 def fctxfn(repo, cx, path):
1781 def fctxfn(repo, cx, path):
1779 return fctxs.get(path)
1782 return fctxs.get(path)
1780
1783
1781 if len(ps) == 0 or ps[0] < 0:
1784 if len(ps) == 0 or ps[0] < 0:
1782 pars = [None, None]
1785 pars = [None, None]
1783 elif len(ps) == 1:
1786 elif len(ps) == 1:
1784 pars = [nodeids[ps[0]], None]
1787 pars = [nodeids[ps[0]], None]
1785 else:
1788 else:
1786 pars = [nodeids[p] for p in ps]
1789 pars = [nodeids[p] for p in ps]
1787 cx = context.memctx(repo, pars, "r%i" % id, files, fctxfn,
1790 cx = context.memctx(repo, pars, "r%i" % id, files, fctxfn,
1788 date=(id, 0),
1791 date=(id, 0),
1789 user="debugbuilddag",
1792 user="debugbuilddag",
1790 extra={'branch': atbranch})
1793 extra={'branch': atbranch})
1791 nodeid = repo.commitctx(cx)
1794 nodeid = repo.commitctx(cx)
1792 nodeids.append(nodeid)
1795 nodeids.append(nodeid)
1793 at = id
1796 at = id
1794 elif type == 'l':
1797 elif type == 'l':
1795 id, name = data
1798 id, name = data
1796 ui.note(('tag %s\n' % name))
1799 ui.note(('tag %s\n' % name))
1797 tags.append("%s %s\n" % (hex(repo.changelog.node(id)), name))
1800 tags.append("%s %s\n" % (hex(repo.changelog.node(id)), name))
1798 elif type == 'a':
1801 elif type == 'a':
1799 ui.note(('branch %s\n' % data))
1802 ui.note(('branch %s\n' % data))
1800 atbranch = data
1803 atbranch = data
1801 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1804 ui.progress(_('building'), id, unit=_('revisions'), total=total)
1802 tr.close()
1805 tr.close()
1803
1806
1804 if tags:
1807 if tags:
1805 repo.vfs.write("localtags", "".join(tags))
1808 repo.vfs.write("localtags", "".join(tags))
1806 finally:
1809 finally:
1807 ui.progress(_('building'), None)
1810 ui.progress(_('building'), None)
1808 release(tr, lock)
1811 release(tr, lock)
1809
1812
1810 @command('debugbundle',
1813 @command('debugbundle',
1811 [('a', 'all', None, _('show all details'))],
1814 [('a', 'all', None, _('show all details'))],
1812 _('FILE'),
1815 _('FILE'),
1813 norepo=True)
1816 norepo=True)
1814 def debugbundle(ui, bundlepath, all=None, **opts):
1817 def debugbundle(ui, bundlepath, all=None, **opts):
1815 """lists the contents of a bundle"""
1818 """lists the contents of a bundle"""
1816 f = hg.openpath(ui, bundlepath)
1819 f = hg.openpath(ui, bundlepath)
1817 try:
1820 try:
1818 gen = exchange.readbundle(ui, f, bundlepath)
1821 gen = exchange.readbundle(ui, f, bundlepath)
1819 if isinstance(gen, bundle2.unbundle20):
1822 if isinstance(gen, bundle2.unbundle20):
1820 return _debugbundle2(ui, gen, all=all, **opts)
1823 return _debugbundle2(ui, gen, all=all, **opts)
1821 if all:
1824 if all:
1822 ui.write(("format: id, p1, p2, cset, delta base, len(delta)\n"))
1825 ui.write(("format: id, p1, p2, cset, delta base, len(delta)\n"))
1823
1826
1824 def showchunks(named):
1827 def showchunks(named):
1825 ui.write("\n%s\n" % named)
1828 ui.write("\n%s\n" % named)
1826 chain = None
1829 chain = None
1827 while True:
1830 while True:
1828 chunkdata = gen.deltachunk(chain)
1831 chunkdata = gen.deltachunk(chain)
1829 if not chunkdata:
1832 if not chunkdata:
1830 break
1833 break
1831 node = chunkdata['node']
1834 node = chunkdata['node']
1832 p1 = chunkdata['p1']
1835 p1 = chunkdata['p1']
1833 p2 = chunkdata['p2']
1836 p2 = chunkdata['p2']
1834 cs = chunkdata['cs']
1837 cs = chunkdata['cs']
1835 deltabase = chunkdata['deltabase']
1838 deltabase = chunkdata['deltabase']
1836 delta = chunkdata['delta']
1839 delta = chunkdata['delta']
1837 ui.write("%s %s %s %s %s %s\n" %
1840 ui.write("%s %s %s %s %s %s\n" %
1838 (hex(node), hex(p1), hex(p2),
1841 (hex(node), hex(p1), hex(p2),
1839 hex(cs), hex(deltabase), len(delta)))
1842 hex(cs), hex(deltabase), len(delta)))
1840 chain = node
1843 chain = node
1841
1844
1842 chunkdata = gen.changelogheader()
1845 chunkdata = gen.changelogheader()
1843 showchunks("changelog")
1846 showchunks("changelog")
1844 chunkdata = gen.manifestheader()
1847 chunkdata = gen.manifestheader()
1845 showchunks("manifest")
1848 showchunks("manifest")
1846 while True:
1849 while True:
1847 chunkdata = gen.filelogheader()
1850 chunkdata = gen.filelogheader()
1848 if not chunkdata:
1851 if not chunkdata:
1849 break
1852 break
1850 fname = chunkdata['filename']
1853 fname = chunkdata['filename']
1851 showchunks(fname)
1854 showchunks(fname)
1852 else:
1855 else:
1853 if isinstance(gen, bundle2.unbundle20):
1856 if isinstance(gen, bundle2.unbundle20):
1854 raise util.Abort(_('use debugbundle2 for this file'))
1857 raise util.Abort(_('use debugbundle2 for this file'))
1855 chunkdata = gen.changelogheader()
1858 chunkdata = gen.changelogheader()
1856 chain = None
1859 chain = None
1857 while True:
1860 while True:
1858 chunkdata = gen.deltachunk(chain)
1861 chunkdata = gen.deltachunk(chain)
1859 if not chunkdata:
1862 if not chunkdata:
1860 break
1863 break
1861 node = chunkdata['node']
1864 node = chunkdata['node']
1862 ui.write("%s\n" % hex(node))
1865 ui.write("%s\n" % hex(node))
1863 chain = node
1866 chain = node
1864 finally:
1867 finally:
1865 f.close()
1868 f.close()
1866
1869
1867 def _debugbundle2(ui, gen, **opts):
1870 def _debugbundle2(ui, gen, **opts):
1868 """lists the contents of a bundle2"""
1871 """lists the contents of a bundle2"""
1869 if not isinstance(gen, bundle2.unbundle20):
1872 if not isinstance(gen, bundle2.unbundle20):
1870 raise util.Abort(_('not a bundle2 file'))
1873 raise util.Abort(_('not a bundle2 file'))
1871 ui.write(('Stream params: %s\n' % repr(gen.params)))
1874 ui.write(('Stream params: %s\n' % repr(gen.params)))
1872 for part in gen.iterparts():
1875 for part in gen.iterparts():
1873 ui.write('%s -- %r\n' % (part.type, repr(part.params)))
1876 ui.write('%s -- %r\n' % (part.type, repr(part.params)))
1874 if part.type == 'b2x:changegroup':
1877 if part.type == 'b2x:changegroup':
1875 version = part.params.get('version', '01')
1878 version = part.params.get('version', '01')
1876 cg = changegroup.packermap[version][1](part, 'UN')
1879 cg = changegroup.packermap[version][1](part, 'UN')
1877 chunkdata = cg.changelogheader()
1880 chunkdata = cg.changelogheader()
1878 chain = None
1881 chain = None
1879 while True:
1882 while True:
1880 chunkdata = cg.deltachunk(chain)
1883 chunkdata = cg.deltachunk(chain)
1881 if not chunkdata:
1884 if not chunkdata:
1882 break
1885 break
1883 node = chunkdata['node']
1886 node = chunkdata['node']
1884 ui.write(" %s\n" % hex(node))
1887 ui.write(" %s\n" % hex(node))
1885 chain = node
1888 chain = node
1886
1889
1887 @command('debugcheckstate', [], '')
1890 @command('debugcheckstate', [], '')
1888 def debugcheckstate(ui, repo):
1891 def debugcheckstate(ui, repo):
1889 """validate the correctness of the current dirstate"""
1892 """validate the correctness of the current dirstate"""
1890 parent1, parent2 = repo.dirstate.parents()
1893 parent1, parent2 = repo.dirstate.parents()
1891 m1 = repo[parent1].manifest()
1894 m1 = repo[parent1].manifest()
1892 m2 = repo[parent2].manifest()
1895 m2 = repo[parent2].manifest()
1893 errors = 0
1896 errors = 0
1894 for f in repo.dirstate:
1897 for f in repo.dirstate:
1895 state = repo.dirstate[f]
1898 state = repo.dirstate[f]
1896 if state in "nr" and f not in m1:
1899 if state in "nr" and f not in m1:
1897 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
1900 ui.warn(_("%s in state %s, but not in manifest1\n") % (f, state))
1898 errors += 1
1901 errors += 1
1899 if state in "a" and f in m1:
1902 if state in "a" and f in m1:
1900 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
1903 ui.warn(_("%s in state %s, but also in manifest1\n") % (f, state))
1901 errors += 1
1904 errors += 1
1902 if state in "m" and f not in m1 and f not in m2:
1905 if state in "m" and f not in m1 and f not in m2:
1903 ui.warn(_("%s in state %s, but not in either manifest\n") %
1906 ui.warn(_("%s in state %s, but not in either manifest\n") %
1904 (f, state))
1907 (f, state))
1905 errors += 1
1908 errors += 1
1906 for f in m1:
1909 for f in m1:
1907 state = repo.dirstate[f]
1910 state = repo.dirstate[f]
1908 if state not in "nrm":
1911 if state not in "nrm":
1909 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
1912 ui.warn(_("%s in manifest1, but listed as state %s") % (f, state))
1910 errors += 1
1913 errors += 1
1911 if errors:
1914 if errors:
1912 error = _(".hg/dirstate inconsistent with current parent's manifest")
1915 error = _(".hg/dirstate inconsistent with current parent's manifest")
1913 raise util.Abort(error)
1916 raise util.Abort(error)
1914
1917
1915 @command('debugcommands', [], _('[COMMAND]'), norepo=True)
1918 @command('debugcommands', [], _('[COMMAND]'), norepo=True)
1916 def debugcommands(ui, cmd='', *args):
1919 def debugcommands(ui, cmd='', *args):
1917 """list all available commands and options"""
1920 """list all available commands and options"""
1918 for cmd, vals in sorted(table.iteritems()):
1921 for cmd, vals in sorted(table.iteritems()):
1919 cmd = cmd.split('|')[0].strip('^')
1922 cmd = cmd.split('|')[0].strip('^')
1920 opts = ', '.join([i[1] for i in vals[1]])
1923 opts = ', '.join([i[1] for i in vals[1]])
1921 ui.write('%s: %s\n' % (cmd, opts))
1924 ui.write('%s: %s\n' % (cmd, opts))
1922
1925
1923 @command('debugcomplete',
1926 @command('debugcomplete',
1924 [('o', 'options', None, _('show the command options'))],
1927 [('o', 'options', None, _('show the command options'))],
1925 _('[-o] CMD'),
1928 _('[-o] CMD'),
1926 norepo=True)
1929 norepo=True)
1927 def debugcomplete(ui, cmd='', **opts):
1930 def debugcomplete(ui, cmd='', **opts):
1928 """returns the completion list associated with the given command"""
1931 """returns the completion list associated with the given command"""
1929
1932
1930 if opts.get('options'):
1933 if opts.get('options'):
1931 options = []
1934 options = []
1932 otables = [globalopts]
1935 otables = [globalopts]
1933 if cmd:
1936 if cmd:
1934 aliases, entry = cmdutil.findcmd(cmd, table, False)
1937 aliases, entry = cmdutil.findcmd(cmd, table, False)
1935 otables.append(entry[1])
1938 otables.append(entry[1])
1936 for t in otables:
1939 for t in otables:
1937 for o in t:
1940 for o in t:
1938 if "(DEPRECATED)" in o[3]:
1941 if "(DEPRECATED)" in o[3]:
1939 continue
1942 continue
1940 if o[0]:
1943 if o[0]:
1941 options.append('-%s' % o[0])
1944 options.append('-%s' % o[0])
1942 options.append('--%s' % o[1])
1945 options.append('--%s' % o[1])
1943 ui.write("%s\n" % "\n".join(options))
1946 ui.write("%s\n" % "\n".join(options))
1944 return
1947 return
1945
1948
1946 cmdlist = cmdutil.findpossible(cmd, table)
1949 cmdlist = cmdutil.findpossible(cmd, table)
1947 if ui.verbose:
1950 if ui.verbose:
1948 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
1951 cmdlist = [' '.join(c[0]) for c in cmdlist.values()]
1949 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
1952 ui.write("%s\n" % "\n".join(sorted(cmdlist)))
1950
1953
1951 @command('debugdag',
1954 @command('debugdag',
1952 [('t', 'tags', None, _('use tags as labels')),
1955 [('t', 'tags', None, _('use tags as labels')),
1953 ('b', 'branches', None, _('annotate with branch names')),
1956 ('b', 'branches', None, _('annotate with branch names')),
1954 ('', 'dots', None, _('use dots for runs')),
1957 ('', 'dots', None, _('use dots for runs')),
1955 ('s', 'spaces', None, _('separate elements by spaces'))],
1958 ('s', 'spaces', None, _('separate elements by spaces'))],
1956 _('[OPTION]... [FILE [REV]...]'),
1959 _('[OPTION]... [FILE [REV]...]'),
1957 optionalrepo=True)
1960 optionalrepo=True)
1958 def debugdag(ui, repo, file_=None, *revs, **opts):
1961 def debugdag(ui, repo, file_=None, *revs, **opts):
1959 """format the changelog or an index DAG as a concise textual description
1962 """format the changelog or an index DAG as a concise textual description
1960
1963
1961 If you pass a revlog index, the revlog's DAG is emitted. If you list
1964 If you pass a revlog index, the revlog's DAG is emitted. If you list
1962 revision numbers, they get labeled in the output as rN.
1965 revision numbers, they get labeled in the output as rN.
1963
1966
1964 Otherwise, the changelog DAG of the current repo is emitted.
1967 Otherwise, the changelog DAG of the current repo is emitted.
1965 """
1968 """
1966 spaces = opts.get('spaces')
1969 spaces = opts.get('spaces')
1967 dots = opts.get('dots')
1970 dots = opts.get('dots')
1968 if file_:
1971 if file_:
1969 rlog = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
1972 rlog = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
1970 revs = set((int(r) for r in revs))
1973 revs = set((int(r) for r in revs))
1971 def events():
1974 def events():
1972 for r in rlog:
1975 for r in rlog:
1973 yield 'n', (r, list(p for p in rlog.parentrevs(r)
1976 yield 'n', (r, list(p for p in rlog.parentrevs(r)
1974 if p != -1))
1977 if p != -1))
1975 if r in revs:
1978 if r in revs:
1976 yield 'l', (r, "r%i" % r)
1979 yield 'l', (r, "r%i" % r)
1977 elif repo:
1980 elif repo:
1978 cl = repo.changelog
1981 cl = repo.changelog
1979 tags = opts.get('tags')
1982 tags = opts.get('tags')
1980 branches = opts.get('branches')
1983 branches = opts.get('branches')
1981 if tags:
1984 if tags:
1982 labels = {}
1985 labels = {}
1983 for l, n in repo.tags().items():
1986 for l, n in repo.tags().items():
1984 labels.setdefault(cl.rev(n), []).append(l)
1987 labels.setdefault(cl.rev(n), []).append(l)
1985 def events():
1988 def events():
1986 b = "default"
1989 b = "default"
1987 for r in cl:
1990 for r in cl:
1988 if branches:
1991 if branches:
1989 newb = cl.read(cl.node(r))[5]['branch']
1992 newb = cl.read(cl.node(r))[5]['branch']
1990 if newb != b:
1993 if newb != b:
1991 yield 'a', newb
1994 yield 'a', newb
1992 b = newb
1995 b = newb
1993 yield 'n', (r, list(p for p in cl.parentrevs(r)
1996 yield 'n', (r, list(p for p in cl.parentrevs(r)
1994 if p != -1))
1997 if p != -1))
1995 if tags:
1998 if tags:
1996 ls = labels.get(r)
1999 ls = labels.get(r)
1997 if ls:
2000 if ls:
1998 for l in ls:
2001 for l in ls:
1999 yield 'l', (r, l)
2002 yield 'l', (r, l)
2000 else:
2003 else:
2001 raise util.Abort(_('need repo for changelog dag'))
2004 raise util.Abort(_('need repo for changelog dag'))
2002
2005
2003 for line in dagparser.dagtextlines(events(),
2006 for line in dagparser.dagtextlines(events(),
2004 addspaces=spaces,
2007 addspaces=spaces,
2005 wraplabels=True,
2008 wraplabels=True,
2006 wrapannotations=True,
2009 wrapannotations=True,
2007 wrapnonlinear=dots,
2010 wrapnonlinear=dots,
2008 usedots=dots,
2011 usedots=dots,
2009 maxlinewidth=70):
2012 maxlinewidth=70):
2010 ui.write(line)
2013 ui.write(line)
2011 ui.write("\n")
2014 ui.write("\n")
2012
2015
2013 @command('debugdata',
2016 @command('debugdata',
2014 [('c', 'changelog', False, _('open changelog')),
2017 [('c', 'changelog', False, _('open changelog')),
2015 ('m', 'manifest', False, _('open manifest'))],
2018 ('m', 'manifest', False, _('open manifest'))],
2016 _('-c|-m|FILE REV'))
2019 _('-c|-m|FILE REV'))
2017 def debugdata(ui, repo, file_, rev=None, **opts):
2020 def debugdata(ui, repo, file_, rev=None, **opts):
2018 """dump the contents of a data file revision"""
2021 """dump the contents of a data file revision"""
2019 if opts.get('changelog') or opts.get('manifest'):
2022 if opts.get('changelog') or opts.get('manifest'):
2020 file_, rev = None, file_
2023 file_, rev = None, file_
2021 elif rev is None:
2024 elif rev is None:
2022 raise error.CommandError('debugdata', _('invalid arguments'))
2025 raise error.CommandError('debugdata', _('invalid arguments'))
2023 r = cmdutil.openrevlog(repo, 'debugdata', file_, opts)
2026 r = cmdutil.openrevlog(repo, 'debugdata', file_, opts)
2024 try:
2027 try:
2025 ui.write(r.revision(r.lookup(rev)))
2028 ui.write(r.revision(r.lookup(rev)))
2026 except KeyError:
2029 except KeyError:
2027 raise util.Abort(_('invalid revision identifier %s') % rev)
2030 raise util.Abort(_('invalid revision identifier %s') % rev)
2028
2031
2029 @command('debugdate',
2032 @command('debugdate',
2030 [('e', 'extended', None, _('try extended date formats'))],
2033 [('e', 'extended', None, _('try extended date formats'))],
2031 _('[-e] DATE [RANGE]'),
2034 _('[-e] DATE [RANGE]'),
2032 norepo=True, optionalrepo=True)
2035 norepo=True, optionalrepo=True)
2033 def debugdate(ui, date, range=None, **opts):
2036 def debugdate(ui, date, range=None, **opts):
2034 """parse and display a date"""
2037 """parse and display a date"""
2035 if opts["extended"]:
2038 if opts["extended"]:
2036 d = util.parsedate(date, util.extendeddateformats)
2039 d = util.parsedate(date, util.extendeddateformats)
2037 else:
2040 else:
2038 d = util.parsedate(date)
2041 d = util.parsedate(date)
2039 ui.write(("internal: %s %s\n") % d)
2042 ui.write(("internal: %s %s\n") % d)
2040 ui.write(("standard: %s\n") % util.datestr(d))
2043 ui.write(("standard: %s\n") % util.datestr(d))
2041 if range:
2044 if range:
2042 m = util.matchdate(range)
2045 m = util.matchdate(range)
2043 ui.write(("match: %s\n") % m(d[0]))
2046 ui.write(("match: %s\n") % m(d[0]))
2044
2047
2045 @command('debugdiscovery',
2048 @command('debugdiscovery',
2046 [('', 'old', None, _('use old-style discovery')),
2049 [('', 'old', None, _('use old-style discovery')),
2047 ('', 'nonheads', None,
2050 ('', 'nonheads', None,
2048 _('use old-style discovery with non-heads included')),
2051 _('use old-style discovery with non-heads included')),
2049 ] + remoteopts,
2052 ] + remoteopts,
2050 _('[-l REV] [-r REV] [-b BRANCH]... [OTHER]'))
2053 _('[-l REV] [-r REV] [-b BRANCH]... [OTHER]'))
2051 def debugdiscovery(ui, repo, remoteurl="default", **opts):
2054 def debugdiscovery(ui, repo, remoteurl="default", **opts):
2052 """runs the changeset discovery protocol in isolation"""
2055 """runs the changeset discovery protocol in isolation"""
2053 remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl),
2056 remoteurl, branches = hg.parseurl(ui.expandpath(remoteurl),
2054 opts.get('branch'))
2057 opts.get('branch'))
2055 remote = hg.peer(repo, opts, remoteurl)
2058 remote = hg.peer(repo, opts, remoteurl)
2056 ui.status(_('comparing with %s\n') % util.hidepassword(remoteurl))
2059 ui.status(_('comparing with %s\n') % util.hidepassword(remoteurl))
2057
2060
2058 # make sure tests are repeatable
2061 # make sure tests are repeatable
2059 random.seed(12323)
2062 random.seed(12323)
2060
2063
2061 def doit(localheads, remoteheads, remote=remote):
2064 def doit(localheads, remoteheads, remote=remote):
2062 if opts.get('old'):
2065 if opts.get('old'):
2063 if localheads:
2066 if localheads:
2064 raise util.Abort('cannot use localheads with old style '
2067 raise util.Abort('cannot use localheads with old style '
2065 'discovery')
2068 'discovery')
2066 if not util.safehasattr(remote, 'branches'):
2069 if not util.safehasattr(remote, 'branches'):
2067 # enable in-client legacy support
2070 # enable in-client legacy support
2068 remote = localrepo.locallegacypeer(remote.local())
2071 remote = localrepo.locallegacypeer(remote.local())
2069 common, _in, hds = treediscovery.findcommonincoming(repo, remote,
2072 common, _in, hds = treediscovery.findcommonincoming(repo, remote,
2070 force=True)
2073 force=True)
2071 common = set(common)
2074 common = set(common)
2072 if not opts.get('nonheads'):
2075 if not opts.get('nonheads'):
2073 ui.write(("unpruned common: %s\n") %
2076 ui.write(("unpruned common: %s\n") %
2074 " ".join(sorted(short(n) for n in common)))
2077 " ".join(sorted(short(n) for n in common)))
2075 dag = dagutil.revlogdag(repo.changelog)
2078 dag = dagutil.revlogdag(repo.changelog)
2076 all = dag.ancestorset(dag.internalizeall(common))
2079 all = dag.ancestorset(dag.internalizeall(common))
2077 common = dag.externalizeall(dag.headsetofconnecteds(all))
2080 common = dag.externalizeall(dag.headsetofconnecteds(all))
2078 else:
2081 else:
2079 common, any, hds = setdiscovery.findcommonheads(ui, repo, remote)
2082 common, any, hds = setdiscovery.findcommonheads(ui, repo, remote)
2080 common = set(common)
2083 common = set(common)
2081 rheads = set(hds)
2084 rheads = set(hds)
2082 lheads = set(repo.heads())
2085 lheads = set(repo.heads())
2083 ui.write(("common heads: %s\n") %
2086 ui.write(("common heads: %s\n") %
2084 " ".join(sorted(short(n) for n in common)))
2087 " ".join(sorted(short(n) for n in common)))
2085 if lheads <= common:
2088 if lheads <= common:
2086 ui.write(("local is subset\n"))
2089 ui.write(("local is subset\n"))
2087 elif rheads <= common:
2090 elif rheads <= common:
2088 ui.write(("remote is subset\n"))
2091 ui.write(("remote is subset\n"))
2089
2092
2090 serverlogs = opts.get('serverlog')
2093 serverlogs = opts.get('serverlog')
2091 if serverlogs:
2094 if serverlogs:
2092 for filename in serverlogs:
2095 for filename in serverlogs:
2093 logfile = open(filename, 'r')
2096 logfile = open(filename, 'r')
2094 try:
2097 try:
2095 line = logfile.readline()
2098 line = logfile.readline()
2096 while line:
2099 while line:
2097 parts = line.strip().split(';')
2100 parts = line.strip().split(';')
2098 op = parts[1]
2101 op = parts[1]
2099 if op == 'cg':
2102 if op == 'cg':
2100 pass
2103 pass
2101 elif op == 'cgss':
2104 elif op == 'cgss':
2102 doit(parts[2].split(' '), parts[3].split(' '))
2105 doit(parts[2].split(' '), parts[3].split(' '))
2103 elif op == 'unb':
2106 elif op == 'unb':
2104 doit(parts[3].split(' '), parts[2].split(' '))
2107 doit(parts[3].split(' '), parts[2].split(' '))
2105 line = logfile.readline()
2108 line = logfile.readline()
2106 finally:
2109 finally:
2107 logfile.close()
2110 logfile.close()
2108
2111
2109 else:
2112 else:
2110 remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches,
2113 remoterevs, _checkout = hg.addbranchrevs(repo, remote, branches,
2111 opts.get('remote_head'))
2114 opts.get('remote_head'))
2112 localrevs = opts.get('local_head')
2115 localrevs = opts.get('local_head')
2113 doit(localrevs, remoterevs)
2116 doit(localrevs, remoterevs)
2114
2117
2115 @command('debugfileset',
2118 @command('debugfileset',
2116 [('r', 'rev', '', _('apply the filespec on this revision'), _('REV'))],
2119 [('r', 'rev', '', _('apply the filespec on this revision'), _('REV'))],
2117 _('[-r REV] FILESPEC'))
2120 _('[-r REV] FILESPEC'))
2118 def debugfileset(ui, repo, expr, **opts):
2121 def debugfileset(ui, repo, expr, **opts):
2119 '''parse and apply a fileset specification'''
2122 '''parse and apply a fileset specification'''
2120 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
2123 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
2121 if ui.verbose:
2124 if ui.verbose:
2122 tree = fileset.parse(expr)[0]
2125 tree = fileset.parse(expr)[0]
2123 ui.note(tree, "\n")
2126 ui.note(tree, "\n")
2124
2127
2125 for f in ctx.getfileset(expr):
2128 for f in ctx.getfileset(expr):
2126 ui.write("%s\n" % f)
2129 ui.write("%s\n" % f)
2127
2130
2128 @command('debugfsinfo', [], _('[PATH]'), norepo=True)
2131 @command('debugfsinfo', [], _('[PATH]'), norepo=True)
2129 def debugfsinfo(ui, path="."):
2132 def debugfsinfo(ui, path="."):
2130 """show information detected about current filesystem"""
2133 """show information detected about current filesystem"""
2131 util.writefile('.debugfsinfo', '')
2134 util.writefile('.debugfsinfo', '')
2132 ui.write(('exec: %s\n') % (util.checkexec(path) and 'yes' or 'no'))
2135 ui.write(('exec: %s\n') % (util.checkexec(path) and 'yes' or 'no'))
2133 ui.write(('symlink: %s\n') % (util.checklink(path) and 'yes' or 'no'))
2136 ui.write(('symlink: %s\n') % (util.checklink(path) and 'yes' or 'no'))
2134 ui.write(('hardlink: %s\n') % (util.checknlink(path) and 'yes' or 'no'))
2137 ui.write(('hardlink: %s\n') % (util.checknlink(path) and 'yes' or 'no'))
2135 ui.write(('case-sensitive: %s\n') % (util.checkcase('.debugfsinfo')
2138 ui.write(('case-sensitive: %s\n') % (util.checkcase('.debugfsinfo')
2136 and 'yes' or 'no'))
2139 and 'yes' or 'no'))
2137 os.unlink('.debugfsinfo')
2140 os.unlink('.debugfsinfo')
2138
2141
2139 @command('debuggetbundle',
2142 @command('debuggetbundle',
2140 [('H', 'head', [], _('id of head node'), _('ID')),
2143 [('H', 'head', [], _('id of head node'), _('ID')),
2141 ('C', 'common', [], _('id of common node'), _('ID')),
2144 ('C', 'common', [], _('id of common node'), _('ID')),
2142 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE'))],
2145 ('t', 'type', 'bzip2', _('bundle compression type to use'), _('TYPE'))],
2143 _('REPO FILE [-H|-C ID]...'),
2146 _('REPO FILE [-H|-C ID]...'),
2144 norepo=True)
2147 norepo=True)
2145 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
2148 def debuggetbundle(ui, repopath, bundlepath, head=None, common=None, **opts):
2146 """retrieves a bundle from a repo
2149 """retrieves a bundle from a repo
2147
2150
2148 Every ID must be a full-length hex node id string. Saves the bundle to the
2151 Every ID must be a full-length hex node id string. Saves the bundle to the
2149 given file.
2152 given file.
2150 """
2153 """
2151 repo = hg.peer(ui, opts, repopath)
2154 repo = hg.peer(ui, opts, repopath)
2152 if not repo.capable('getbundle'):
2155 if not repo.capable('getbundle'):
2153 raise util.Abort("getbundle() not supported by target repository")
2156 raise util.Abort("getbundle() not supported by target repository")
2154 args = {}
2157 args = {}
2155 if common:
2158 if common:
2156 args['common'] = [bin(s) for s in common]
2159 args['common'] = [bin(s) for s in common]
2157 if head:
2160 if head:
2158 args['heads'] = [bin(s) for s in head]
2161 args['heads'] = [bin(s) for s in head]
2159 # TODO: get desired bundlecaps from command line.
2162 # TODO: get desired bundlecaps from command line.
2160 args['bundlecaps'] = None
2163 args['bundlecaps'] = None
2161 bundle = repo.getbundle('debug', **args)
2164 bundle = repo.getbundle('debug', **args)
2162
2165
2163 bundletype = opts.get('type', 'bzip2').lower()
2166 bundletype = opts.get('type', 'bzip2').lower()
2164 btypes = {'none': 'HG10UN', 'bzip2': 'HG10BZ', 'gzip': 'HG10GZ'}
2167 btypes = {'none': 'HG10UN',
2168 'bzip2': 'HG10BZ',
2169 'gzip': 'HG10GZ',
2170 'bundle2': 'HG2Y'}
2165 bundletype = btypes.get(bundletype)
2171 bundletype = btypes.get(bundletype)
2166 if bundletype not in changegroup.bundletypes:
2172 if bundletype not in changegroup.bundletypes:
2167 raise util.Abort(_('unknown bundle type specified with --type'))
2173 raise util.Abort(_('unknown bundle type specified with --type'))
2168 changegroup.writebundle(ui, bundle, bundlepath, bundletype)
2174 changegroup.writebundle(ui, bundle, bundlepath, bundletype)
2169
2175
2170 @command('debugignore', [], '')
2176 @command('debugignore', [], '')
2171 def debugignore(ui, repo, *values, **opts):
2177 def debugignore(ui, repo, *values, **opts):
2172 """display the combined ignore pattern"""
2178 """display the combined ignore pattern"""
2173 ignore = repo.dirstate._ignore
2179 ignore = repo.dirstate._ignore
2174 includepat = getattr(ignore, 'includepat', None)
2180 includepat = getattr(ignore, 'includepat', None)
2175 if includepat is not None:
2181 if includepat is not None:
2176 ui.write("%s\n" % includepat)
2182 ui.write("%s\n" % includepat)
2177 else:
2183 else:
2178 raise util.Abort(_("no ignore patterns found"))
2184 raise util.Abort(_("no ignore patterns found"))
2179
2185
2180 @command('debugindex',
2186 @command('debugindex',
2181 [('c', 'changelog', False, _('open changelog')),
2187 [('c', 'changelog', False, _('open changelog')),
2182 ('m', 'manifest', False, _('open manifest')),
2188 ('m', 'manifest', False, _('open manifest')),
2183 ('f', 'format', 0, _('revlog format'), _('FORMAT'))],
2189 ('f', 'format', 0, _('revlog format'), _('FORMAT'))],
2184 _('[-f FORMAT] -c|-m|FILE'),
2190 _('[-f FORMAT] -c|-m|FILE'),
2185 optionalrepo=True)
2191 optionalrepo=True)
2186 def debugindex(ui, repo, file_=None, **opts):
2192 def debugindex(ui, repo, file_=None, **opts):
2187 """dump the contents of an index file"""
2193 """dump the contents of an index file"""
2188 r = cmdutil.openrevlog(repo, 'debugindex', file_, opts)
2194 r = cmdutil.openrevlog(repo, 'debugindex', file_, opts)
2189 format = opts.get('format', 0)
2195 format = opts.get('format', 0)
2190 if format not in (0, 1):
2196 if format not in (0, 1):
2191 raise util.Abort(_("unknown format %d") % format)
2197 raise util.Abort(_("unknown format %d") % format)
2192
2198
2193 generaldelta = r.version & revlog.REVLOGGENERALDELTA
2199 generaldelta = r.version & revlog.REVLOGGENERALDELTA
2194 if generaldelta:
2200 if generaldelta:
2195 basehdr = ' delta'
2201 basehdr = ' delta'
2196 else:
2202 else:
2197 basehdr = ' base'
2203 basehdr = ' base'
2198
2204
2199 if ui.debugflag:
2205 if ui.debugflag:
2200 shortfn = hex
2206 shortfn = hex
2201 else:
2207 else:
2202 shortfn = short
2208 shortfn = short
2203
2209
2204 # There might not be anything in r, so have a sane default
2210 # There might not be anything in r, so have a sane default
2205 idlen = 12
2211 idlen = 12
2206 for i in r:
2212 for i in r:
2207 idlen = len(shortfn(r.node(i)))
2213 idlen = len(shortfn(r.node(i)))
2208 break
2214 break
2209
2215
2210 if format == 0:
2216 if format == 0:
2211 ui.write(" rev offset length " + basehdr + " linkrev"
2217 ui.write(" rev offset length " + basehdr + " linkrev"
2212 " %s %s p2\n" % ("nodeid".ljust(idlen), "p1".ljust(idlen)))
2218 " %s %s p2\n" % ("nodeid".ljust(idlen), "p1".ljust(idlen)))
2213 elif format == 1:
2219 elif format == 1:
2214 ui.write(" rev flag offset length"
2220 ui.write(" rev flag offset length"
2215 " size " + basehdr + " link p1 p2"
2221 " size " + basehdr + " link p1 p2"
2216 " %s\n" % "nodeid".rjust(idlen))
2222 " %s\n" % "nodeid".rjust(idlen))
2217
2223
2218 for i in r:
2224 for i in r:
2219 node = r.node(i)
2225 node = r.node(i)
2220 if generaldelta:
2226 if generaldelta:
2221 base = r.deltaparent(i)
2227 base = r.deltaparent(i)
2222 else:
2228 else:
2223 base = r.chainbase(i)
2229 base = r.chainbase(i)
2224 if format == 0:
2230 if format == 0:
2225 try:
2231 try:
2226 pp = r.parents(node)
2232 pp = r.parents(node)
2227 except Exception:
2233 except Exception:
2228 pp = [nullid, nullid]
2234 pp = [nullid, nullid]
2229 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
2235 ui.write("% 6d % 9d % 7d % 6d % 7d %s %s %s\n" % (
2230 i, r.start(i), r.length(i), base, r.linkrev(i),
2236 i, r.start(i), r.length(i), base, r.linkrev(i),
2231 shortfn(node), shortfn(pp[0]), shortfn(pp[1])))
2237 shortfn(node), shortfn(pp[0]), shortfn(pp[1])))
2232 elif format == 1:
2238 elif format == 1:
2233 pr = r.parentrevs(i)
2239 pr = r.parentrevs(i)
2234 ui.write("% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d % 6d %s\n" % (
2240 ui.write("% 6d %04x % 8d % 8d % 8d % 6d % 6d % 6d % 6d %s\n" % (
2235 i, r.flags(i), r.start(i), r.length(i), r.rawsize(i),
2241 i, r.flags(i), r.start(i), r.length(i), r.rawsize(i),
2236 base, r.linkrev(i), pr[0], pr[1], shortfn(node)))
2242 base, r.linkrev(i), pr[0], pr[1], shortfn(node)))
2237
2243
2238 @command('debugindexdot', [], _('FILE'), optionalrepo=True)
2244 @command('debugindexdot', [], _('FILE'), optionalrepo=True)
2239 def debugindexdot(ui, repo, file_):
2245 def debugindexdot(ui, repo, file_):
2240 """dump an index DAG as a graphviz dot file"""
2246 """dump an index DAG as a graphviz dot file"""
2241 r = None
2247 r = None
2242 if repo:
2248 if repo:
2243 filelog = repo.file(file_)
2249 filelog = repo.file(file_)
2244 if len(filelog):
2250 if len(filelog):
2245 r = filelog
2251 r = filelog
2246 if not r:
2252 if not r:
2247 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
2253 r = revlog.revlog(scmutil.opener(os.getcwd(), audit=False), file_)
2248 ui.write(("digraph G {\n"))
2254 ui.write(("digraph G {\n"))
2249 for i in r:
2255 for i in r:
2250 node = r.node(i)
2256 node = r.node(i)
2251 pp = r.parents(node)
2257 pp = r.parents(node)
2252 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
2258 ui.write("\t%d -> %d\n" % (r.rev(pp[0]), i))
2253 if pp[1] != nullid:
2259 if pp[1] != nullid:
2254 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
2260 ui.write("\t%d -> %d\n" % (r.rev(pp[1]), i))
2255 ui.write("}\n")
2261 ui.write("}\n")
2256
2262
2257 @command('debuginstall', [], '', norepo=True)
2263 @command('debuginstall', [], '', norepo=True)
2258 def debuginstall(ui):
2264 def debuginstall(ui):
2259 '''test Mercurial installation
2265 '''test Mercurial installation
2260
2266
2261 Returns 0 on success.
2267 Returns 0 on success.
2262 '''
2268 '''
2263
2269
2264 def writetemp(contents):
2270 def writetemp(contents):
2265 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
2271 (fd, name) = tempfile.mkstemp(prefix="hg-debuginstall-")
2266 f = os.fdopen(fd, "wb")
2272 f = os.fdopen(fd, "wb")
2267 f.write(contents)
2273 f.write(contents)
2268 f.close()
2274 f.close()
2269 return name
2275 return name
2270
2276
2271 problems = 0
2277 problems = 0
2272
2278
2273 # encoding
2279 # encoding
2274 ui.status(_("checking encoding (%s)...\n") % encoding.encoding)
2280 ui.status(_("checking encoding (%s)...\n") % encoding.encoding)
2275 try:
2281 try:
2276 encoding.fromlocal("test")
2282 encoding.fromlocal("test")
2277 except util.Abort, inst:
2283 except util.Abort, inst:
2278 ui.write(" %s\n" % inst)
2284 ui.write(" %s\n" % inst)
2279 ui.write(_(" (check that your locale is properly set)\n"))
2285 ui.write(_(" (check that your locale is properly set)\n"))
2280 problems += 1
2286 problems += 1
2281
2287
2282 # Python
2288 # Python
2283 ui.status(_("checking Python executable (%s)\n") % sys.executable)
2289 ui.status(_("checking Python executable (%s)\n") % sys.executable)
2284 ui.status(_("checking Python version (%s)\n")
2290 ui.status(_("checking Python version (%s)\n")
2285 % ("%s.%s.%s" % sys.version_info[:3]))
2291 % ("%s.%s.%s" % sys.version_info[:3]))
2286 ui.status(_("checking Python lib (%s)...\n")
2292 ui.status(_("checking Python lib (%s)...\n")
2287 % os.path.dirname(os.__file__))
2293 % os.path.dirname(os.__file__))
2288
2294
2289 # compiled modules
2295 # compiled modules
2290 ui.status(_("checking installed modules (%s)...\n")
2296 ui.status(_("checking installed modules (%s)...\n")
2291 % os.path.dirname(__file__))
2297 % os.path.dirname(__file__))
2292 try:
2298 try:
2293 import bdiff, mpatch, base85, osutil
2299 import bdiff, mpatch, base85, osutil
2294 dir(bdiff), dir(mpatch), dir(base85), dir(osutil) # quiet pyflakes
2300 dir(bdiff), dir(mpatch), dir(base85), dir(osutil) # quiet pyflakes
2295 except Exception, inst:
2301 except Exception, inst:
2296 ui.write(" %s\n" % inst)
2302 ui.write(" %s\n" % inst)
2297 ui.write(_(" One or more extensions could not be found"))
2303 ui.write(_(" One or more extensions could not be found"))
2298 ui.write(_(" (check that you compiled the extensions)\n"))
2304 ui.write(_(" (check that you compiled the extensions)\n"))
2299 problems += 1
2305 problems += 1
2300
2306
2301 # templates
2307 # templates
2302 import templater
2308 import templater
2303 p = templater.templatepaths()
2309 p = templater.templatepaths()
2304 ui.status(_("checking templates (%s)...\n") % ' '.join(p))
2310 ui.status(_("checking templates (%s)...\n") % ' '.join(p))
2305 if p:
2311 if p:
2306 m = templater.templatepath("map-cmdline.default")
2312 m = templater.templatepath("map-cmdline.default")
2307 if m:
2313 if m:
2308 # template found, check if it is working
2314 # template found, check if it is working
2309 try:
2315 try:
2310 templater.templater(m)
2316 templater.templater(m)
2311 except Exception, inst:
2317 except Exception, inst:
2312 ui.write(" %s\n" % inst)
2318 ui.write(" %s\n" % inst)
2313 p = None
2319 p = None
2314 else:
2320 else:
2315 ui.write(_(" template 'default' not found\n"))
2321 ui.write(_(" template 'default' not found\n"))
2316 p = None
2322 p = None
2317 else:
2323 else:
2318 ui.write(_(" no template directories found\n"))
2324 ui.write(_(" no template directories found\n"))
2319 if not p:
2325 if not p:
2320 ui.write(_(" (templates seem to have been installed incorrectly)\n"))
2326 ui.write(_(" (templates seem to have been installed incorrectly)\n"))
2321 problems += 1
2327 problems += 1
2322
2328
2323 # editor
2329 # editor
2324 ui.status(_("checking commit editor...\n"))
2330 ui.status(_("checking commit editor...\n"))
2325 editor = ui.geteditor()
2331 editor = ui.geteditor()
2326 cmdpath = util.findexe(shlex.split(editor)[0])
2332 cmdpath = util.findexe(shlex.split(editor)[0])
2327 if not cmdpath:
2333 if not cmdpath:
2328 if editor == 'vi':
2334 if editor == 'vi':
2329 ui.write(_(" No commit editor set and can't find vi in PATH\n"))
2335 ui.write(_(" No commit editor set and can't find vi in PATH\n"))
2330 ui.write(_(" (specify a commit editor in your configuration"
2336 ui.write(_(" (specify a commit editor in your configuration"
2331 " file)\n"))
2337 " file)\n"))
2332 else:
2338 else:
2333 ui.write(_(" Can't find editor '%s' in PATH\n") % editor)
2339 ui.write(_(" Can't find editor '%s' in PATH\n") % editor)
2334 ui.write(_(" (specify a commit editor in your configuration"
2340 ui.write(_(" (specify a commit editor in your configuration"
2335 " file)\n"))
2341 " file)\n"))
2336 problems += 1
2342 problems += 1
2337
2343
2338 # check username
2344 # check username
2339 ui.status(_("checking username...\n"))
2345 ui.status(_("checking username...\n"))
2340 try:
2346 try:
2341 ui.username()
2347 ui.username()
2342 except util.Abort, e:
2348 except util.Abort, e:
2343 ui.write(" %s\n" % e)
2349 ui.write(" %s\n" % e)
2344 ui.write(_(" (specify a username in your configuration file)\n"))
2350 ui.write(_(" (specify a username in your configuration file)\n"))
2345 problems += 1
2351 problems += 1
2346
2352
2347 if not problems:
2353 if not problems:
2348 ui.status(_("no problems detected\n"))
2354 ui.status(_("no problems detected\n"))
2349 else:
2355 else:
2350 ui.write(_("%s problems detected,"
2356 ui.write(_("%s problems detected,"
2351 " please check your install!\n") % problems)
2357 " please check your install!\n") % problems)
2352
2358
2353 return problems
2359 return problems
2354
2360
2355 @command('debugknown', [], _('REPO ID...'), norepo=True)
2361 @command('debugknown', [], _('REPO ID...'), norepo=True)
2356 def debugknown(ui, repopath, *ids, **opts):
2362 def debugknown(ui, repopath, *ids, **opts):
2357 """test whether node ids are known to a repo
2363 """test whether node ids are known to a repo
2358
2364
2359 Every ID must be a full-length hex node id string. Returns a list of 0s
2365 Every ID must be a full-length hex node id string. Returns a list of 0s
2360 and 1s indicating unknown/known.
2366 and 1s indicating unknown/known.
2361 """
2367 """
2362 repo = hg.peer(ui, opts, repopath)
2368 repo = hg.peer(ui, opts, repopath)
2363 if not repo.capable('known'):
2369 if not repo.capable('known'):
2364 raise util.Abort("known() not supported by target repository")
2370 raise util.Abort("known() not supported by target repository")
2365 flags = repo.known([bin(s) for s in ids])
2371 flags = repo.known([bin(s) for s in ids])
2366 ui.write("%s\n" % ("".join([f and "1" or "0" for f in flags])))
2372 ui.write("%s\n" % ("".join([f and "1" or "0" for f in flags])))
2367
2373
2368 @command('debuglabelcomplete', [], _('LABEL...'))
2374 @command('debuglabelcomplete', [], _('LABEL...'))
2369 def debuglabelcomplete(ui, repo, *args):
2375 def debuglabelcomplete(ui, repo, *args):
2370 '''backwards compatibility with old bash completion scripts (DEPRECATED)'''
2376 '''backwards compatibility with old bash completion scripts (DEPRECATED)'''
2371 debugnamecomplete(ui, repo, *args)
2377 debugnamecomplete(ui, repo, *args)
2372
2378
2373 @command('debugnamecomplete', [], _('NAME...'))
2379 @command('debugnamecomplete', [], _('NAME...'))
2374 def debugnamecomplete(ui, repo, *args):
2380 def debugnamecomplete(ui, repo, *args):
2375 '''complete "names" - tags, open branch names, bookmark names'''
2381 '''complete "names" - tags, open branch names, bookmark names'''
2376
2382
2377 names = set()
2383 names = set()
2378 # since we previously only listed open branches, we will handle that
2384 # since we previously only listed open branches, we will handle that
2379 # specially (after this for loop)
2385 # specially (after this for loop)
2380 for name, ns in repo.names.iteritems():
2386 for name, ns in repo.names.iteritems():
2381 if name != 'branches':
2387 if name != 'branches':
2382 names.update(ns.listnames(repo))
2388 names.update(ns.listnames(repo))
2383 names.update(tag for (tag, heads, tip, closed)
2389 names.update(tag for (tag, heads, tip, closed)
2384 in repo.branchmap().iterbranches() if not closed)
2390 in repo.branchmap().iterbranches() if not closed)
2385 completions = set()
2391 completions = set()
2386 if not args:
2392 if not args:
2387 args = ['']
2393 args = ['']
2388 for a in args:
2394 for a in args:
2389 completions.update(n for n in names if n.startswith(a))
2395 completions.update(n for n in names if n.startswith(a))
2390 ui.write('\n'.join(sorted(completions)))
2396 ui.write('\n'.join(sorted(completions)))
2391 ui.write('\n')
2397 ui.write('\n')
2392
2398
2393 @command('debuglocks',
2399 @command('debuglocks',
2394 [('L', 'force-lock', None, _('free the store lock (DANGEROUS)')),
2400 [('L', 'force-lock', None, _('free the store lock (DANGEROUS)')),
2395 ('W', 'force-wlock', None,
2401 ('W', 'force-wlock', None,
2396 _('free the working state lock (DANGEROUS)'))],
2402 _('free the working state lock (DANGEROUS)'))],
2397 _('[OPTION]...'))
2403 _('[OPTION]...'))
2398 def debuglocks(ui, repo, **opts):
2404 def debuglocks(ui, repo, **opts):
2399 """show or modify state of locks
2405 """show or modify state of locks
2400
2406
2401 By default, this command will show which locks are held. This
2407 By default, this command will show which locks are held. This
2402 includes the user and process holding the lock, the amount of time
2408 includes the user and process holding the lock, the amount of time
2403 the lock has been held, and the machine name where the process is
2409 the lock has been held, and the machine name where the process is
2404 running if it's not local.
2410 running if it's not local.
2405
2411
2406 Locks protect the integrity of Mercurial's data, so should be
2412 Locks protect the integrity of Mercurial's data, so should be
2407 treated with care. System crashes or other interruptions may cause
2413 treated with care. System crashes or other interruptions may cause
2408 locks to not be properly released, though Mercurial will usually
2414 locks to not be properly released, though Mercurial will usually
2409 detect and remove such stale locks automatically.
2415 detect and remove such stale locks automatically.
2410
2416
2411 However, detecting stale locks may not always be possible (for
2417 However, detecting stale locks may not always be possible (for
2412 instance, on a shared filesystem). Removing locks may also be
2418 instance, on a shared filesystem). Removing locks may also be
2413 blocked by filesystem permissions.
2419 blocked by filesystem permissions.
2414
2420
2415 Returns 0 if no locks are held.
2421 Returns 0 if no locks are held.
2416
2422
2417 """
2423 """
2418
2424
2419 if opts.get('force_lock'):
2425 if opts.get('force_lock'):
2420 repo.svfs.unlink('lock')
2426 repo.svfs.unlink('lock')
2421 if opts.get('force_wlock'):
2427 if opts.get('force_wlock'):
2422 repo.vfs.unlink('wlock')
2428 repo.vfs.unlink('wlock')
2423 if opts.get('force_lock') or opts.get('force_lock'):
2429 if opts.get('force_lock') or opts.get('force_lock'):
2424 return 0
2430 return 0
2425
2431
2426 now = time.time()
2432 now = time.time()
2427 held = 0
2433 held = 0
2428
2434
2429 def report(vfs, name, method):
2435 def report(vfs, name, method):
2430 # this causes stale locks to get reaped for more accurate reporting
2436 # this causes stale locks to get reaped for more accurate reporting
2431 try:
2437 try:
2432 l = method(False)
2438 l = method(False)
2433 except error.LockHeld:
2439 except error.LockHeld:
2434 l = None
2440 l = None
2435
2441
2436 if l:
2442 if l:
2437 l.release()
2443 l.release()
2438 else:
2444 else:
2439 try:
2445 try:
2440 stat = repo.svfs.lstat(name)
2446 stat = repo.svfs.lstat(name)
2441 age = now - stat.st_mtime
2447 age = now - stat.st_mtime
2442 user = util.username(stat.st_uid)
2448 user = util.username(stat.st_uid)
2443 locker = vfs.readlock(name)
2449 locker = vfs.readlock(name)
2444 if ":" in locker:
2450 if ":" in locker:
2445 host, pid = locker.split(':')
2451 host, pid = locker.split(':')
2446 if host == socket.gethostname():
2452 if host == socket.gethostname():
2447 locker = 'user %s, process %s' % (user, pid)
2453 locker = 'user %s, process %s' % (user, pid)
2448 else:
2454 else:
2449 locker = 'user %s, process %s, host %s' \
2455 locker = 'user %s, process %s, host %s' \
2450 % (user, pid, host)
2456 % (user, pid, host)
2451 ui.write("%-6s %s (%ds)\n" % (name + ":", locker, age))
2457 ui.write("%-6s %s (%ds)\n" % (name + ":", locker, age))
2452 return 1
2458 return 1
2453 except OSError, e:
2459 except OSError, e:
2454 if e.errno != errno.ENOENT:
2460 if e.errno != errno.ENOENT:
2455 raise
2461 raise
2456
2462
2457 ui.write("%-6s free\n" % (name + ":"))
2463 ui.write("%-6s free\n" % (name + ":"))
2458 return 0
2464 return 0
2459
2465
2460 held += report(repo.svfs, "lock", repo.lock)
2466 held += report(repo.svfs, "lock", repo.lock)
2461 held += report(repo.vfs, "wlock", repo.wlock)
2467 held += report(repo.vfs, "wlock", repo.wlock)
2462
2468
2463 return held
2469 return held
2464
2470
2465 @command('debugobsolete',
2471 @command('debugobsolete',
2466 [('', 'flags', 0, _('markers flag')),
2472 [('', 'flags', 0, _('markers flag')),
2467 ('', 'record-parents', False,
2473 ('', 'record-parents', False,
2468 _('record parent information for the precursor')),
2474 _('record parent information for the precursor')),
2469 ('r', 'rev', [], _('display markers relevant to REV')),
2475 ('r', 'rev', [], _('display markers relevant to REV')),
2470 ] + commitopts2,
2476 ] + commitopts2,
2471 _('[OBSOLETED [REPLACEMENT] [REPL... ]'))
2477 _('[OBSOLETED [REPLACEMENT] [REPL... ]'))
2472 def debugobsolete(ui, repo, precursor=None, *successors, **opts):
2478 def debugobsolete(ui, repo, precursor=None, *successors, **opts):
2473 """create arbitrary obsolete marker
2479 """create arbitrary obsolete marker
2474
2480
2475 With no arguments, displays the list of obsolescence markers."""
2481 With no arguments, displays the list of obsolescence markers."""
2476
2482
2477 def parsenodeid(s):
2483 def parsenodeid(s):
2478 try:
2484 try:
2479 # We do not use revsingle/revrange functions here to accept
2485 # We do not use revsingle/revrange functions here to accept
2480 # arbitrary node identifiers, possibly not present in the
2486 # arbitrary node identifiers, possibly not present in the
2481 # local repository.
2487 # local repository.
2482 n = bin(s)
2488 n = bin(s)
2483 if len(n) != len(nullid):
2489 if len(n) != len(nullid):
2484 raise TypeError()
2490 raise TypeError()
2485 return n
2491 return n
2486 except TypeError:
2492 except TypeError:
2487 raise util.Abort('changeset references must be full hexadecimal '
2493 raise util.Abort('changeset references must be full hexadecimal '
2488 'node identifiers')
2494 'node identifiers')
2489
2495
2490 if precursor is not None:
2496 if precursor is not None:
2491 if opts['rev']:
2497 if opts['rev']:
2492 raise util.Abort('cannot select revision when creating marker')
2498 raise util.Abort('cannot select revision when creating marker')
2493 metadata = {}
2499 metadata = {}
2494 metadata['user'] = opts['user'] or ui.username()
2500 metadata['user'] = opts['user'] or ui.username()
2495 succs = tuple(parsenodeid(succ) for succ in successors)
2501 succs = tuple(parsenodeid(succ) for succ in successors)
2496 l = repo.lock()
2502 l = repo.lock()
2497 try:
2503 try:
2498 tr = repo.transaction('debugobsolete')
2504 tr = repo.transaction('debugobsolete')
2499 try:
2505 try:
2500 try:
2506 try:
2501 date = opts.get('date')
2507 date = opts.get('date')
2502 if date:
2508 if date:
2503 date = util.parsedate(date)
2509 date = util.parsedate(date)
2504 else:
2510 else:
2505 date = None
2511 date = None
2506 prec = parsenodeid(precursor)
2512 prec = parsenodeid(precursor)
2507 parents = None
2513 parents = None
2508 if opts['record_parents']:
2514 if opts['record_parents']:
2509 if prec not in repo.unfiltered():
2515 if prec not in repo.unfiltered():
2510 raise util.Abort('cannot used --record-parents on '
2516 raise util.Abort('cannot used --record-parents on '
2511 'unknown changesets')
2517 'unknown changesets')
2512 parents = repo.unfiltered()[prec].parents()
2518 parents = repo.unfiltered()[prec].parents()
2513 parents = tuple(p.node() for p in parents)
2519 parents = tuple(p.node() for p in parents)
2514 repo.obsstore.create(tr, prec, succs, opts['flags'],
2520 repo.obsstore.create(tr, prec, succs, opts['flags'],
2515 parents=parents, date=date,
2521 parents=parents, date=date,
2516 metadata=metadata)
2522 metadata=metadata)
2517 tr.close()
2523 tr.close()
2518 except ValueError, exc:
2524 except ValueError, exc:
2519 raise util.Abort(_('bad obsmarker input: %s') % exc)
2525 raise util.Abort(_('bad obsmarker input: %s') % exc)
2520 finally:
2526 finally:
2521 tr.release()
2527 tr.release()
2522 finally:
2528 finally:
2523 l.release()
2529 l.release()
2524 else:
2530 else:
2525 if opts['rev']:
2531 if opts['rev']:
2526 revs = scmutil.revrange(repo, opts['rev'])
2532 revs = scmutil.revrange(repo, opts['rev'])
2527 nodes = [repo[r].node() for r in revs]
2533 nodes = [repo[r].node() for r in revs]
2528 markers = list(obsolete.getmarkers(repo, nodes=nodes))
2534 markers = list(obsolete.getmarkers(repo, nodes=nodes))
2529 markers.sort(key=lambda x: x._data)
2535 markers.sort(key=lambda x: x._data)
2530 else:
2536 else:
2531 markers = obsolete.getmarkers(repo)
2537 markers = obsolete.getmarkers(repo)
2532
2538
2533 for m in markers:
2539 for m in markers:
2534 cmdutil.showmarker(ui, m)
2540 cmdutil.showmarker(ui, m)
2535
2541
2536 @command('debugpathcomplete',
2542 @command('debugpathcomplete',
2537 [('f', 'full', None, _('complete an entire path')),
2543 [('f', 'full', None, _('complete an entire path')),
2538 ('n', 'normal', None, _('show only normal files')),
2544 ('n', 'normal', None, _('show only normal files')),
2539 ('a', 'added', None, _('show only added files')),
2545 ('a', 'added', None, _('show only added files')),
2540 ('r', 'removed', None, _('show only removed files'))],
2546 ('r', 'removed', None, _('show only removed files'))],
2541 _('FILESPEC...'))
2547 _('FILESPEC...'))
2542 def debugpathcomplete(ui, repo, *specs, **opts):
2548 def debugpathcomplete(ui, repo, *specs, **opts):
2543 '''complete part or all of a tracked path
2549 '''complete part or all of a tracked path
2544
2550
2545 This command supports shells that offer path name completion. It
2551 This command supports shells that offer path name completion. It
2546 currently completes only files already known to the dirstate.
2552 currently completes only files already known to the dirstate.
2547
2553
2548 Completion extends only to the next path segment unless
2554 Completion extends only to the next path segment unless
2549 --full is specified, in which case entire paths are used.'''
2555 --full is specified, in which case entire paths are used.'''
2550
2556
2551 def complete(path, acceptable):
2557 def complete(path, acceptable):
2552 dirstate = repo.dirstate
2558 dirstate = repo.dirstate
2553 spec = os.path.normpath(os.path.join(os.getcwd(), path))
2559 spec = os.path.normpath(os.path.join(os.getcwd(), path))
2554 rootdir = repo.root + os.sep
2560 rootdir = repo.root + os.sep
2555 if spec != repo.root and not spec.startswith(rootdir):
2561 if spec != repo.root and not spec.startswith(rootdir):
2556 return [], []
2562 return [], []
2557 if os.path.isdir(spec):
2563 if os.path.isdir(spec):
2558 spec += '/'
2564 spec += '/'
2559 spec = spec[len(rootdir):]
2565 spec = spec[len(rootdir):]
2560 fixpaths = os.sep != '/'
2566 fixpaths = os.sep != '/'
2561 if fixpaths:
2567 if fixpaths:
2562 spec = spec.replace(os.sep, '/')
2568 spec = spec.replace(os.sep, '/')
2563 speclen = len(spec)
2569 speclen = len(spec)
2564 fullpaths = opts['full']
2570 fullpaths = opts['full']
2565 files, dirs = set(), set()
2571 files, dirs = set(), set()
2566 adddir, addfile = dirs.add, files.add
2572 adddir, addfile = dirs.add, files.add
2567 for f, st in dirstate.iteritems():
2573 for f, st in dirstate.iteritems():
2568 if f.startswith(spec) and st[0] in acceptable:
2574 if f.startswith(spec) and st[0] in acceptable:
2569 if fixpaths:
2575 if fixpaths:
2570 f = f.replace('/', os.sep)
2576 f = f.replace('/', os.sep)
2571 if fullpaths:
2577 if fullpaths:
2572 addfile(f)
2578 addfile(f)
2573 continue
2579 continue
2574 s = f.find(os.sep, speclen)
2580 s = f.find(os.sep, speclen)
2575 if s >= 0:
2581 if s >= 0:
2576 adddir(f[:s])
2582 adddir(f[:s])
2577 else:
2583 else:
2578 addfile(f)
2584 addfile(f)
2579 return files, dirs
2585 return files, dirs
2580
2586
2581 acceptable = ''
2587 acceptable = ''
2582 if opts['normal']:
2588 if opts['normal']:
2583 acceptable += 'nm'
2589 acceptable += 'nm'
2584 if opts['added']:
2590 if opts['added']:
2585 acceptable += 'a'
2591 acceptable += 'a'
2586 if opts['removed']:
2592 if opts['removed']:
2587 acceptable += 'r'
2593 acceptable += 'r'
2588 cwd = repo.getcwd()
2594 cwd = repo.getcwd()
2589 if not specs:
2595 if not specs:
2590 specs = ['.']
2596 specs = ['.']
2591
2597
2592 files, dirs = set(), set()
2598 files, dirs = set(), set()
2593 for spec in specs:
2599 for spec in specs:
2594 f, d = complete(spec, acceptable or 'nmar')
2600 f, d = complete(spec, acceptable or 'nmar')
2595 files.update(f)
2601 files.update(f)
2596 dirs.update(d)
2602 dirs.update(d)
2597 files.update(dirs)
2603 files.update(dirs)
2598 ui.write('\n'.join(repo.pathto(p, cwd) for p in sorted(files)))
2604 ui.write('\n'.join(repo.pathto(p, cwd) for p in sorted(files)))
2599 ui.write('\n')
2605 ui.write('\n')
2600
2606
2601 @command('debugpushkey', [], _('REPO NAMESPACE [KEY OLD NEW]'), norepo=True)
2607 @command('debugpushkey', [], _('REPO NAMESPACE [KEY OLD NEW]'), norepo=True)
2602 def debugpushkey(ui, repopath, namespace, *keyinfo, **opts):
2608 def debugpushkey(ui, repopath, namespace, *keyinfo, **opts):
2603 '''access the pushkey key/value protocol
2609 '''access the pushkey key/value protocol
2604
2610
2605 With two args, list the keys in the given namespace.
2611 With two args, list the keys in the given namespace.
2606
2612
2607 With five args, set a key to new if it currently is set to old.
2613 With five args, set a key to new if it currently is set to old.
2608 Reports success or failure.
2614 Reports success or failure.
2609 '''
2615 '''
2610
2616
2611 target = hg.peer(ui, {}, repopath)
2617 target = hg.peer(ui, {}, repopath)
2612 if keyinfo:
2618 if keyinfo:
2613 key, old, new = keyinfo
2619 key, old, new = keyinfo
2614 r = target.pushkey(namespace, key, old, new)
2620 r = target.pushkey(namespace, key, old, new)
2615 ui.status(str(r) + '\n')
2621 ui.status(str(r) + '\n')
2616 return not r
2622 return not r
2617 else:
2623 else:
2618 for k, v in sorted(target.listkeys(namespace).iteritems()):
2624 for k, v in sorted(target.listkeys(namespace).iteritems()):
2619 ui.write("%s\t%s\n" % (k.encode('string-escape'),
2625 ui.write("%s\t%s\n" % (k.encode('string-escape'),
2620 v.encode('string-escape')))
2626 v.encode('string-escape')))
2621
2627
2622 @command('debugpvec', [], _('A B'))
2628 @command('debugpvec', [], _('A B'))
2623 def debugpvec(ui, repo, a, b=None):
2629 def debugpvec(ui, repo, a, b=None):
2624 ca = scmutil.revsingle(repo, a)
2630 ca = scmutil.revsingle(repo, a)
2625 cb = scmutil.revsingle(repo, b)
2631 cb = scmutil.revsingle(repo, b)
2626 pa = pvec.ctxpvec(ca)
2632 pa = pvec.ctxpvec(ca)
2627 pb = pvec.ctxpvec(cb)
2633 pb = pvec.ctxpvec(cb)
2628 if pa == pb:
2634 if pa == pb:
2629 rel = "="
2635 rel = "="
2630 elif pa > pb:
2636 elif pa > pb:
2631 rel = ">"
2637 rel = ">"
2632 elif pa < pb:
2638 elif pa < pb:
2633 rel = "<"
2639 rel = "<"
2634 elif pa | pb:
2640 elif pa | pb:
2635 rel = "|"
2641 rel = "|"
2636 ui.write(_("a: %s\n") % pa)
2642 ui.write(_("a: %s\n") % pa)
2637 ui.write(_("b: %s\n") % pb)
2643 ui.write(_("b: %s\n") % pb)
2638 ui.write(_("depth(a): %d depth(b): %d\n") % (pa._depth, pb._depth))
2644 ui.write(_("depth(a): %d depth(b): %d\n") % (pa._depth, pb._depth))
2639 ui.write(_("delta: %d hdist: %d distance: %d relation: %s\n") %
2645 ui.write(_("delta: %d hdist: %d distance: %d relation: %s\n") %
2640 (abs(pa._depth - pb._depth), pvec._hamming(pa._vec, pb._vec),
2646 (abs(pa._depth - pb._depth), pvec._hamming(pa._vec, pb._vec),
2641 pa.distance(pb), rel))
2647 pa.distance(pb), rel))
2642
2648
2643 @command('debugrebuilddirstate|debugrebuildstate',
2649 @command('debugrebuilddirstate|debugrebuildstate',
2644 [('r', 'rev', '', _('revision to rebuild to'), _('REV'))],
2650 [('r', 'rev', '', _('revision to rebuild to'), _('REV'))],
2645 _('[-r REV]'))
2651 _('[-r REV]'))
2646 def debugrebuilddirstate(ui, repo, rev):
2652 def debugrebuilddirstate(ui, repo, rev):
2647 """rebuild the dirstate as it would look like for the given revision
2653 """rebuild the dirstate as it would look like for the given revision
2648
2654
2649 If no revision is specified the first current parent will be used.
2655 If no revision is specified the first current parent will be used.
2650
2656
2651 The dirstate will be set to the files of the given revision.
2657 The dirstate will be set to the files of the given revision.
2652 The actual working directory content or existing dirstate
2658 The actual working directory content or existing dirstate
2653 information such as adds or removes is not considered.
2659 information such as adds or removes is not considered.
2654
2660
2655 One use of this command is to make the next :hg:`status` invocation
2661 One use of this command is to make the next :hg:`status` invocation
2656 check the actual file content.
2662 check the actual file content.
2657 """
2663 """
2658 ctx = scmutil.revsingle(repo, rev)
2664 ctx = scmutil.revsingle(repo, rev)
2659 wlock = repo.wlock()
2665 wlock = repo.wlock()
2660 try:
2666 try:
2661 repo.dirstate.rebuild(ctx.node(), ctx.manifest())
2667 repo.dirstate.rebuild(ctx.node(), ctx.manifest())
2662 finally:
2668 finally:
2663 wlock.release()
2669 wlock.release()
2664
2670
2665 @command('debugrename',
2671 @command('debugrename',
2666 [('r', 'rev', '', _('revision to debug'), _('REV'))],
2672 [('r', 'rev', '', _('revision to debug'), _('REV'))],
2667 _('[-r REV] FILE'))
2673 _('[-r REV] FILE'))
2668 def debugrename(ui, repo, file1, *pats, **opts):
2674 def debugrename(ui, repo, file1, *pats, **opts):
2669 """dump rename information"""
2675 """dump rename information"""
2670
2676
2671 ctx = scmutil.revsingle(repo, opts.get('rev'))
2677 ctx = scmutil.revsingle(repo, opts.get('rev'))
2672 m = scmutil.match(ctx, (file1,) + pats, opts)
2678 m = scmutil.match(ctx, (file1,) + pats, opts)
2673 for abs in ctx.walk(m):
2679 for abs in ctx.walk(m):
2674 fctx = ctx[abs]
2680 fctx = ctx[abs]
2675 o = fctx.filelog().renamed(fctx.filenode())
2681 o = fctx.filelog().renamed(fctx.filenode())
2676 rel = m.rel(abs)
2682 rel = m.rel(abs)
2677 if o:
2683 if o:
2678 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
2684 ui.write(_("%s renamed from %s:%s\n") % (rel, o[0], hex(o[1])))
2679 else:
2685 else:
2680 ui.write(_("%s not renamed\n") % rel)
2686 ui.write(_("%s not renamed\n") % rel)
2681
2687
2682 @command('debugrevlog',
2688 @command('debugrevlog',
2683 [('c', 'changelog', False, _('open changelog')),
2689 [('c', 'changelog', False, _('open changelog')),
2684 ('m', 'manifest', False, _('open manifest')),
2690 ('m', 'manifest', False, _('open manifest')),
2685 ('d', 'dump', False, _('dump index data'))],
2691 ('d', 'dump', False, _('dump index data'))],
2686 _('-c|-m|FILE'),
2692 _('-c|-m|FILE'),
2687 optionalrepo=True)
2693 optionalrepo=True)
2688 def debugrevlog(ui, repo, file_=None, **opts):
2694 def debugrevlog(ui, repo, file_=None, **opts):
2689 """show data and statistics about a revlog"""
2695 """show data and statistics about a revlog"""
2690 r = cmdutil.openrevlog(repo, 'debugrevlog', file_, opts)
2696 r = cmdutil.openrevlog(repo, 'debugrevlog', file_, opts)
2691
2697
2692 if opts.get("dump"):
2698 if opts.get("dump"):
2693 numrevs = len(r)
2699 numrevs = len(r)
2694 ui.write("# rev p1rev p2rev start end deltastart base p1 p2"
2700 ui.write("# rev p1rev p2rev start end deltastart base p1 p2"
2695 " rawsize totalsize compression heads chainlen\n")
2701 " rawsize totalsize compression heads chainlen\n")
2696 ts = 0
2702 ts = 0
2697 heads = set()
2703 heads = set()
2698
2704
2699 for rev in xrange(numrevs):
2705 for rev in xrange(numrevs):
2700 dbase = r.deltaparent(rev)
2706 dbase = r.deltaparent(rev)
2701 if dbase == -1:
2707 if dbase == -1:
2702 dbase = rev
2708 dbase = rev
2703 cbase = r.chainbase(rev)
2709 cbase = r.chainbase(rev)
2704 clen = r.chainlen(rev)
2710 clen = r.chainlen(rev)
2705 p1, p2 = r.parentrevs(rev)
2711 p1, p2 = r.parentrevs(rev)
2706 rs = r.rawsize(rev)
2712 rs = r.rawsize(rev)
2707 ts = ts + rs
2713 ts = ts + rs
2708 heads -= set(r.parentrevs(rev))
2714 heads -= set(r.parentrevs(rev))
2709 heads.add(rev)
2715 heads.add(rev)
2710 ui.write("%5d %5d %5d %5d %5d %10d %4d %4d %4d %7d %9d "
2716 ui.write("%5d %5d %5d %5d %5d %10d %4d %4d %4d %7d %9d "
2711 "%11d %5d %8d\n" %
2717 "%11d %5d %8d\n" %
2712 (rev, p1, p2, r.start(rev), r.end(rev),
2718 (rev, p1, p2, r.start(rev), r.end(rev),
2713 r.start(dbase), r.start(cbase),
2719 r.start(dbase), r.start(cbase),
2714 r.start(p1), r.start(p2),
2720 r.start(p1), r.start(p2),
2715 rs, ts, ts / r.end(rev), len(heads), clen))
2721 rs, ts, ts / r.end(rev), len(heads), clen))
2716 return 0
2722 return 0
2717
2723
2718 v = r.version
2724 v = r.version
2719 format = v & 0xFFFF
2725 format = v & 0xFFFF
2720 flags = []
2726 flags = []
2721 gdelta = False
2727 gdelta = False
2722 if v & revlog.REVLOGNGINLINEDATA:
2728 if v & revlog.REVLOGNGINLINEDATA:
2723 flags.append('inline')
2729 flags.append('inline')
2724 if v & revlog.REVLOGGENERALDELTA:
2730 if v & revlog.REVLOGGENERALDELTA:
2725 gdelta = True
2731 gdelta = True
2726 flags.append('generaldelta')
2732 flags.append('generaldelta')
2727 if not flags:
2733 if not flags:
2728 flags = ['(none)']
2734 flags = ['(none)']
2729
2735
2730 nummerges = 0
2736 nummerges = 0
2731 numfull = 0
2737 numfull = 0
2732 numprev = 0
2738 numprev = 0
2733 nump1 = 0
2739 nump1 = 0
2734 nump2 = 0
2740 nump2 = 0
2735 numother = 0
2741 numother = 0
2736 nump1prev = 0
2742 nump1prev = 0
2737 nump2prev = 0
2743 nump2prev = 0
2738 chainlengths = []
2744 chainlengths = []
2739
2745
2740 datasize = [None, 0, 0L]
2746 datasize = [None, 0, 0L]
2741 fullsize = [None, 0, 0L]
2747 fullsize = [None, 0, 0L]
2742 deltasize = [None, 0, 0L]
2748 deltasize = [None, 0, 0L]
2743
2749
2744 def addsize(size, l):
2750 def addsize(size, l):
2745 if l[0] is None or size < l[0]:
2751 if l[0] is None or size < l[0]:
2746 l[0] = size
2752 l[0] = size
2747 if size > l[1]:
2753 if size > l[1]:
2748 l[1] = size
2754 l[1] = size
2749 l[2] += size
2755 l[2] += size
2750
2756
2751 numrevs = len(r)
2757 numrevs = len(r)
2752 for rev in xrange(numrevs):
2758 for rev in xrange(numrevs):
2753 p1, p2 = r.parentrevs(rev)
2759 p1, p2 = r.parentrevs(rev)
2754 delta = r.deltaparent(rev)
2760 delta = r.deltaparent(rev)
2755 if format > 0:
2761 if format > 0:
2756 addsize(r.rawsize(rev), datasize)
2762 addsize(r.rawsize(rev), datasize)
2757 if p2 != nullrev:
2763 if p2 != nullrev:
2758 nummerges += 1
2764 nummerges += 1
2759 size = r.length(rev)
2765 size = r.length(rev)
2760 if delta == nullrev:
2766 if delta == nullrev:
2761 chainlengths.append(0)
2767 chainlengths.append(0)
2762 numfull += 1
2768 numfull += 1
2763 addsize(size, fullsize)
2769 addsize(size, fullsize)
2764 else:
2770 else:
2765 chainlengths.append(chainlengths[delta] + 1)
2771 chainlengths.append(chainlengths[delta] + 1)
2766 addsize(size, deltasize)
2772 addsize(size, deltasize)
2767 if delta == rev - 1:
2773 if delta == rev - 1:
2768 numprev += 1
2774 numprev += 1
2769 if delta == p1:
2775 if delta == p1:
2770 nump1prev += 1
2776 nump1prev += 1
2771 elif delta == p2:
2777 elif delta == p2:
2772 nump2prev += 1
2778 nump2prev += 1
2773 elif delta == p1:
2779 elif delta == p1:
2774 nump1 += 1
2780 nump1 += 1
2775 elif delta == p2:
2781 elif delta == p2:
2776 nump2 += 1
2782 nump2 += 1
2777 elif delta != nullrev:
2783 elif delta != nullrev:
2778 numother += 1
2784 numother += 1
2779
2785
2780 # Adjust size min value for empty cases
2786 # Adjust size min value for empty cases
2781 for size in (datasize, fullsize, deltasize):
2787 for size in (datasize, fullsize, deltasize):
2782 if size[0] is None:
2788 if size[0] is None:
2783 size[0] = 0
2789 size[0] = 0
2784
2790
2785 numdeltas = numrevs - numfull
2791 numdeltas = numrevs - numfull
2786 numoprev = numprev - nump1prev - nump2prev
2792 numoprev = numprev - nump1prev - nump2prev
2787 totalrawsize = datasize[2]
2793 totalrawsize = datasize[2]
2788 datasize[2] /= numrevs
2794 datasize[2] /= numrevs
2789 fulltotal = fullsize[2]
2795 fulltotal = fullsize[2]
2790 fullsize[2] /= numfull
2796 fullsize[2] /= numfull
2791 deltatotal = deltasize[2]
2797 deltatotal = deltasize[2]
2792 if numrevs - numfull > 0:
2798 if numrevs - numfull > 0:
2793 deltasize[2] /= numrevs - numfull
2799 deltasize[2] /= numrevs - numfull
2794 totalsize = fulltotal + deltatotal
2800 totalsize = fulltotal + deltatotal
2795 avgchainlen = sum(chainlengths) / numrevs
2801 avgchainlen = sum(chainlengths) / numrevs
2796 compratio = totalrawsize / totalsize
2802 compratio = totalrawsize / totalsize
2797
2803
2798 basedfmtstr = '%%%dd\n'
2804 basedfmtstr = '%%%dd\n'
2799 basepcfmtstr = '%%%dd %s(%%5.2f%%%%)\n'
2805 basepcfmtstr = '%%%dd %s(%%5.2f%%%%)\n'
2800
2806
2801 def dfmtstr(max):
2807 def dfmtstr(max):
2802 return basedfmtstr % len(str(max))
2808 return basedfmtstr % len(str(max))
2803 def pcfmtstr(max, padding=0):
2809 def pcfmtstr(max, padding=0):
2804 return basepcfmtstr % (len(str(max)), ' ' * padding)
2810 return basepcfmtstr % (len(str(max)), ' ' * padding)
2805
2811
2806 def pcfmt(value, total):
2812 def pcfmt(value, total):
2807 return (value, 100 * float(value) / total)
2813 return (value, 100 * float(value) / total)
2808
2814
2809 ui.write(('format : %d\n') % format)
2815 ui.write(('format : %d\n') % format)
2810 ui.write(('flags : %s\n') % ', '.join(flags))
2816 ui.write(('flags : %s\n') % ', '.join(flags))
2811
2817
2812 ui.write('\n')
2818 ui.write('\n')
2813 fmt = pcfmtstr(totalsize)
2819 fmt = pcfmtstr(totalsize)
2814 fmt2 = dfmtstr(totalsize)
2820 fmt2 = dfmtstr(totalsize)
2815 ui.write(('revisions : ') + fmt2 % numrevs)
2821 ui.write(('revisions : ') + fmt2 % numrevs)
2816 ui.write((' merges : ') + fmt % pcfmt(nummerges, numrevs))
2822 ui.write((' merges : ') + fmt % pcfmt(nummerges, numrevs))
2817 ui.write((' normal : ') + fmt % pcfmt(numrevs - nummerges, numrevs))
2823 ui.write((' normal : ') + fmt % pcfmt(numrevs - nummerges, numrevs))
2818 ui.write(('revisions : ') + fmt2 % numrevs)
2824 ui.write(('revisions : ') + fmt2 % numrevs)
2819 ui.write((' full : ') + fmt % pcfmt(numfull, numrevs))
2825 ui.write((' full : ') + fmt % pcfmt(numfull, numrevs))
2820 ui.write((' deltas : ') + fmt % pcfmt(numdeltas, numrevs))
2826 ui.write((' deltas : ') + fmt % pcfmt(numdeltas, numrevs))
2821 ui.write(('revision size : ') + fmt2 % totalsize)
2827 ui.write(('revision size : ') + fmt2 % totalsize)
2822 ui.write((' full : ') + fmt % pcfmt(fulltotal, totalsize))
2828 ui.write((' full : ') + fmt % pcfmt(fulltotal, totalsize))
2823 ui.write((' deltas : ') + fmt % pcfmt(deltatotal, totalsize))
2829 ui.write((' deltas : ') + fmt % pcfmt(deltatotal, totalsize))
2824
2830
2825 ui.write('\n')
2831 ui.write('\n')
2826 fmt = dfmtstr(max(avgchainlen, compratio))
2832 fmt = dfmtstr(max(avgchainlen, compratio))
2827 ui.write(('avg chain length : ') + fmt % avgchainlen)
2833 ui.write(('avg chain length : ') + fmt % avgchainlen)
2828 ui.write(('compression ratio : ') + fmt % compratio)
2834 ui.write(('compression ratio : ') + fmt % compratio)
2829
2835
2830 if format > 0:
2836 if format > 0:
2831 ui.write('\n')
2837 ui.write('\n')
2832 ui.write(('uncompressed data size (min/max/avg) : %d / %d / %d\n')
2838 ui.write(('uncompressed data size (min/max/avg) : %d / %d / %d\n')
2833 % tuple(datasize))
2839 % tuple(datasize))
2834 ui.write(('full revision size (min/max/avg) : %d / %d / %d\n')
2840 ui.write(('full revision size (min/max/avg) : %d / %d / %d\n')
2835 % tuple(fullsize))
2841 % tuple(fullsize))
2836 ui.write(('delta size (min/max/avg) : %d / %d / %d\n')
2842 ui.write(('delta size (min/max/avg) : %d / %d / %d\n')
2837 % tuple(deltasize))
2843 % tuple(deltasize))
2838
2844
2839 if numdeltas > 0:
2845 if numdeltas > 0:
2840 ui.write('\n')
2846 ui.write('\n')
2841 fmt = pcfmtstr(numdeltas)
2847 fmt = pcfmtstr(numdeltas)
2842 fmt2 = pcfmtstr(numdeltas, 4)
2848 fmt2 = pcfmtstr(numdeltas, 4)
2843 ui.write(('deltas against prev : ') + fmt % pcfmt(numprev, numdeltas))
2849 ui.write(('deltas against prev : ') + fmt % pcfmt(numprev, numdeltas))
2844 if numprev > 0:
2850 if numprev > 0:
2845 ui.write((' where prev = p1 : ') + fmt2 % pcfmt(nump1prev,
2851 ui.write((' where prev = p1 : ') + fmt2 % pcfmt(nump1prev,
2846 numprev))
2852 numprev))
2847 ui.write((' where prev = p2 : ') + fmt2 % pcfmt(nump2prev,
2853 ui.write((' where prev = p2 : ') + fmt2 % pcfmt(nump2prev,
2848 numprev))
2854 numprev))
2849 ui.write((' other : ') + fmt2 % pcfmt(numoprev,
2855 ui.write((' other : ') + fmt2 % pcfmt(numoprev,
2850 numprev))
2856 numprev))
2851 if gdelta:
2857 if gdelta:
2852 ui.write(('deltas against p1 : ')
2858 ui.write(('deltas against p1 : ')
2853 + fmt % pcfmt(nump1, numdeltas))
2859 + fmt % pcfmt(nump1, numdeltas))
2854 ui.write(('deltas against p2 : ')
2860 ui.write(('deltas against p2 : ')
2855 + fmt % pcfmt(nump2, numdeltas))
2861 + fmt % pcfmt(nump2, numdeltas))
2856 ui.write(('deltas against other : ') + fmt % pcfmt(numother,
2862 ui.write(('deltas against other : ') + fmt % pcfmt(numother,
2857 numdeltas))
2863 numdeltas))
2858
2864
2859 @command('debugrevspec',
2865 @command('debugrevspec',
2860 [('', 'optimize', None, _('print parsed tree after optimizing'))],
2866 [('', 'optimize', None, _('print parsed tree after optimizing'))],
2861 ('REVSPEC'))
2867 ('REVSPEC'))
2862 def debugrevspec(ui, repo, expr, **opts):
2868 def debugrevspec(ui, repo, expr, **opts):
2863 """parse and apply a revision specification
2869 """parse and apply a revision specification
2864
2870
2865 Use --verbose to print the parsed tree before and after aliases
2871 Use --verbose to print the parsed tree before and after aliases
2866 expansion.
2872 expansion.
2867 """
2873 """
2868 if ui.verbose:
2874 if ui.verbose:
2869 tree = revset.parse(expr)[0]
2875 tree = revset.parse(expr)[0]
2870 ui.note(revset.prettyformat(tree), "\n")
2876 ui.note(revset.prettyformat(tree), "\n")
2871 newtree = revset.findaliases(ui, tree)
2877 newtree = revset.findaliases(ui, tree)
2872 if newtree != tree:
2878 if newtree != tree:
2873 ui.note(revset.prettyformat(newtree), "\n")
2879 ui.note(revset.prettyformat(newtree), "\n")
2874 tree = newtree
2880 tree = newtree
2875 newtree = revset.foldconcat(tree)
2881 newtree = revset.foldconcat(tree)
2876 if newtree != tree:
2882 if newtree != tree:
2877 ui.note(revset.prettyformat(newtree), "\n")
2883 ui.note(revset.prettyformat(newtree), "\n")
2878 if opts["optimize"]:
2884 if opts["optimize"]:
2879 weight, optimizedtree = revset.optimize(newtree, True)
2885 weight, optimizedtree = revset.optimize(newtree, True)
2880 ui.note("* optimized:\n", revset.prettyformat(optimizedtree), "\n")
2886 ui.note("* optimized:\n", revset.prettyformat(optimizedtree), "\n")
2881 func = revset.match(ui, expr)
2887 func = revset.match(ui, expr)
2882 for c in func(repo, revset.spanset(repo)):
2888 for c in func(repo, revset.spanset(repo)):
2883 ui.write("%s\n" % c)
2889 ui.write("%s\n" % c)
2884
2890
2885 @command('debugsetparents', [], _('REV1 [REV2]'))
2891 @command('debugsetparents', [], _('REV1 [REV2]'))
2886 def debugsetparents(ui, repo, rev1, rev2=None):
2892 def debugsetparents(ui, repo, rev1, rev2=None):
2887 """manually set the parents of the current working directory
2893 """manually set the parents of the current working directory
2888
2894
2889 This is useful for writing repository conversion tools, but should
2895 This is useful for writing repository conversion tools, but should
2890 be used with care.
2896 be used with care.
2891
2897
2892 Returns 0 on success.
2898 Returns 0 on success.
2893 """
2899 """
2894
2900
2895 r1 = scmutil.revsingle(repo, rev1).node()
2901 r1 = scmutil.revsingle(repo, rev1).node()
2896 r2 = scmutil.revsingle(repo, rev2, 'null').node()
2902 r2 = scmutil.revsingle(repo, rev2, 'null').node()
2897
2903
2898 wlock = repo.wlock()
2904 wlock = repo.wlock()
2899 try:
2905 try:
2900 repo.dirstate.beginparentchange()
2906 repo.dirstate.beginparentchange()
2901 repo.setparents(r1, r2)
2907 repo.setparents(r1, r2)
2902 repo.dirstate.endparentchange()
2908 repo.dirstate.endparentchange()
2903 finally:
2909 finally:
2904 wlock.release()
2910 wlock.release()
2905
2911
2906 @command('debugdirstate|debugstate',
2912 @command('debugdirstate|debugstate',
2907 [('', 'nodates', None, _('do not display the saved mtime')),
2913 [('', 'nodates', None, _('do not display the saved mtime')),
2908 ('', 'datesort', None, _('sort by saved mtime'))],
2914 ('', 'datesort', None, _('sort by saved mtime'))],
2909 _('[OPTION]...'))
2915 _('[OPTION]...'))
2910 def debugstate(ui, repo, nodates=None, datesort=None):
2916 def debugstate(ui, repo, nodates=None, datesort=None):
2911 """show the contents of the current dirstate"""
2917 """show the contents of the current dirstate"""
2912 timestr = ""
2918 timestr = ""
2913 if datesort:
2919 if datesort:
2914 keyfunc = lambda x: (x[1][3], x[0]) # sort by mtime, then by filename
2920 keyfunc = lambda x: (x[1][3], x[0]) # sort by mtime, then by filename
2915 else:
2921 else:
2916 keyfunc = None # sort by filename
2922 keyfunc = None # sort by filename
2917 for file_, ent in sorted(repo.dirstate._map.iteritems(), key=keyfunc):
2923 for file_, ent in sorted(repo.dirstate._map.iteritems(), key=keyfunc):
2918 if ent[3] == -1:
2924 if ent[3] == -1:
2919 timestr = 'unset '
2925 timestr = 'unset '
2920 elif nodates:
2926 elif nodates:
2921 timestr = 'set '
2927 timestr = 'set '
2922 else:
2928 else:
2923 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
2929 timestr = time.strftime("%Y-%m-%d %H:%M:%S ",
2924 time.localtime(ent[3]))
2930 time.localtime(ent[3]))
2925 if ent[1] & 020000:
2931 if ent[1] & 020000:
2926 mode = 'lnk'
2932 mode = 'lnk'
2927 else:
2933 else:
2928 mode = '%3o' % (ent[1] & 0777 & ~util.umask)
2934 mode = '%3o' % (ent[1] & 0777 & ~util.umask)
2929 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
2935 ui.write("%c %s %10d %s%s\n" % (ent[0], mode, ent[2], timestr, file_))
2930 for f in repo.dirstate.copies():
2936 for f in repo.dirstate.copies():
2931 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
2937 ui.write(_("copy: %s -> %s\n") % (repo.dirstate.copied(f), f))
2932
2938
2933 @command('debugsub',
2939 @command('debugsub',
2934 [('r', 'rev', '',
2940 [('r', 'rev', '',
2935 _('revision to check'), _('REV'))],
2941 _('revision to check'), _('REV'))],
2936 _('[-r REV] [REV]'))
2942 _('[-r REV] [REV]'))
2937 def debugsub(ui, repo, rev=None):
2943 def debugsub(ui, repo, rev=None):
2938 ctx = scmutil.revsingle(repo, rev, None)
2944 ctx = scmutil.revsingle(repo, rev, None)
2939 for k, v in sorted(ctx.substate.items()):
2945 for k, v in sorted(ctx.substate.items()):
2940 ui.write(('path %s\n') % k)
2946 ui.write(('path %s\n') % k)
2941 ui.write((' source %s\n') % v[0])
2947 ui.write((' source %s\n') % v[0])
2942 ui.write((' revision %s\n') % v[1])
2948 ui.write((' revision %s\n') % v[1])
2943
2949
2944 @command('debugsuccessorssets',
2950 @command('debugsuccessorssets',
2945 [],
2951 [],
2946 _('[REV]'))
2952 _('[REV]'))
2947 def debugsuccessorssets(ui, repo, *revs):
2953 def debugsuccessorssets(ui, repo, *revs):
2948 """show set of successors for revision
2954 """show set of successors for revision
2949
2955
2950 A successors set of changeset A is a consistent group of revisions that
2956 A successors set of changeset A is a consistent group of revisions that
2951 succeed A. It contains non-obsolete changesets only.
2957 succeed A. It contains non-obsolete changesets only.
2952
2958
2953 In most cases a changeset A has a single successors set containing a single
2959 In most cases a changeset A has a single successors set containing a single
2954 successor (changeset A replaced by A').
2960 successor (changeset A replaced by A').
2955
2961
2956 A changeset that is made obsolete with no successors are called "pruned".
2962 A changeset that is made obsolete with no successors are called "pruned".
2957 Such changesets have no successors sets at all.
2963 Such changesets have no successors sets at all.
2958
2964
2959 A changeset that has been "split" will have a successors set containing
2965 A changeset that has been "split" will have a successors set containing
2960 more than one successor.
2966 more than one successor.
2961
2967
2962 A changeset that has been rewritten in multiple different ways is called
2968 A changeset that has been rewritten in multiple different ways is called
2963 "divergent". Such changesets have multiple successor sets (each of which
2969 "divergent". Such changesets have multiple successor sets (each of which
2964 may also be split, i.e. have multiple successors).
2970 may also be split, i.e. have multiple successors).
2965
2971
2966 Results are displayed as follows::
2972 Results are displayed as follows::
2967
2973
2968 <rev1>
2974 <rev1>
2969 <successors-1A>
2975 <successors-1A>
2970 <rev2>
2976 <rev2>
2971 <successors-2A>
2977 <successors-2A>
2972 <successors-2B1> <successors-2B2> <successors-2B3>
2978 <successors-2B1> <successors-2B2> <successors-2B3>
2973
2979
2974 Here rev2 has two possible (i.e. divergent) successors sets. The first
2980 Here rev2 has two possible (i.e. divergent) successors sets. The first
2975 holds one element, whereas the second holds three (i.e. the changeset has
2981 holds one element, whereas the second holds three (i.e. the changeset has
2976 been split).
2982 been split).
2977 """
2983 """
2978 # passed to successorssets caching computation from one call to another
2984 # passed to successorssets caching computation from one call to another
2979 cache = {}
2985 cache = {}
2980 ctx2str = str
2986 ctx2str = str
2981 node2str = short
2987 node2str = short
2982 if ui.debug():
2988 if ui.debug():
2983 def ctx2str(ctx):
2989 def ctx2str(ctx):
2984 return ctx.hex()
2990 return ctx.hex()
2985 node2str = hex
2991 node2str = hex
2986 for rev in scmutil.revrange(repo, revs):
2992 for rev in scmutil.revrange(repo, revs):
2987 ctx = repo[rev]
2993 ctx = repo[rev]
2988 ui.write('%s\n'% ctx2str(ctx))
2994 ui.write('%s\n'% ctx2str(ctx))
2989 for succsset in obsolete.successorssets(repo, ctx.node(), cache):
2995 for succsset in obsolete.successorssets(repo, ctx.node(), cache):
2990 if succsset:
2996 if succsset:
2991 ui.write(' ')
2997 ui.write(' ')
2992 ui.write(node2str(succsset[0]))
2998 ui.write(node2str(succsset[0]))
2993 for node in succsset[1:]:
2999 for node in succsset[1:]:
2994 ui.write(' ')
3000 ui.write(' ')
2995 ui.write(node2str(node))
3001 ui.write(node2str(node))
2996 ui.write('\n')
3002 ui.write('\n')
2997
3003
2998 @command('debugwalk', walkopts, _('[OPTION]... [FILE]...'), inferrepo=True)
3004 @command('debugwalk', walkopts, _('[OPTION]... [FILE]...'), inferrepo=True)
2999 def debugwalk(ui, repo, *pats, **opts):
3005 def debugwalk(ui, repo, *pats, **opts):
3000 """show how files match on given patterns"""
3006 """show how files match on given patterns"""
3001 m = scmutil.match(repo[None], pats, opts)
3007 m = scmutil.match(repo[None], pats, opts)
3002 items = list(repo.walk(m))
3008 items = list(repo.walk(m))
3003 if not items:
3009 if not items:
3004 return
3010 return
3005 f = lambda fn: fn
3011 f = lambda fn: fn
3006 if ui.configbool('ui', 'slash') and os.sep != '/':
3012 if ui.configbool('ui', 'slash') and os.sep != '/':
3007 f = lambda fn: util.normpath(fn)
3013 f = lambda fn: util.normpath(fn)
3008 fmt = 'f %%-%ds %%-%ds %%s' % (
3014 fmt = 'f %%-%ds %%-%ds %%s' % (
3009 max([len(abs) for abs in items]),
3015 max([len(abs) for abs in items]),
3010 max([len(m.rel(abs)) for abs in items]))
3016 max([len(m.rel(abs)) for abs in items]))
3011 for abs in items:
3017 for abs in items:
3012 line = fmt % (abs, f(m.rel(abs)), m.exact(abs) and 'exact' or '')
3018 line = fmt % (abs, f(m.rel(abs)), m.exact(abs) and 'exact' or '')
3013 ui.write("%s\n" % line.rstrip())
3019 ui.write("%s\n" % line.rstrip())
3014
3020
3015 @command('debugwireargs',
3021 @command('debugwireargs',
3016 [('', 'three', '', 'three'),
3022 [('', 'three', '', 'three'),
3017 ('', 'four', '', 'four'),
3023 ('', 'four', '', 'four'),
3018 ('', 'five', '', 'five'),
3024 ('', 'five', '', 'five'),
3019 ] + remoteopts,
3025 ] + remoteopts,
3020 _('REPO [OPTIONS]... [ONE [TWO]]'),
3026 _('REPO [OPTIONS]... [ONE [TWO]]'),
3021 norepo=True)
3027 norepo=True)
3022 def debugwireargs(ui, repopath, *vals, **opts):
3028 def debugwireargs(ui, repopath, *vals, **opts):
3023 repo = hg.peer(ui, opts, repopath)
3029 repo = hg.peer(ui, opts, repopath)
3024 for opt in remoteopts:
3030 for opt in remoteopts:
3025 del opts[opt[1]]
3031 del opts[opt[1]]
3026 args = {}
3032 args = {}
3027 for k, v in opts.iteritems():
3033 for k, v in opts.iteritems():
3028 if v:
3034 if v:
3029 args[k] = v
3035 args[k] = v
3030 # run twice to check that we don't mess up the stream for the next command
3036 # run twice to check that we don't mess up the stream for the next command
3031 res1 = repo.debugwireargs(*vals, **args)
3037 res1 = repo.debugwireargs(*vals, **args)
3032 res2 = repo.debugwireargs(*vals, **args)
3038 res2 = repo.debugwireargs(*vals, **args)
3033 ui.write("%s\n" % res1)
3039 ui.write("%s\n" % res1)
3034 if res1 != res2:
3040 if res1 != res2:
3035 ui.warn("%s\n" % res2)
3041 ui.warn("%s\n" % res2)
3036
3042
3037 @command('^diff',
3043 @command('^diff',
3038 [('r', 'rev', [], _('revision'), _('REV')),
3044 [('r', 'rev', [], _('revision'), _('REV')),
3039 ('c', 'change', '', _('change made by revision'), _('REV'))
3045 ('c', 'change', '', _('change made by revision'), _('REV'))
3040 ] + diffopts + diffopts2 + walkopts + subrepoopts,
3046 ] + diffopts + diffopts2 + walkopts + subrepoopts,
3041 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'),
3047 _('[OPTION]... ([-c REV] | [-r REV1 [-r REV2]]) [FILE]...'),
3042 inferrepo=True)
3048 inferrepo=True)
3043 def diff(ui, repo, *pats, **opts):
3049 def diff(ui, repo, *pats, **opts):
3044 """diff repository (or selected files)
3050 """diff repository (or selected files)
3045
3051
3046 Show differences between revisions for the specified files.
3052 Show differences between revisions for the specified files.
3047
3053
3048 Differences between files are shown using the unified diff format.
3054 Differences between files are shown using the unified diff format.
3049
3055
3050 .. note::
3056 .. note::
3051
3057
3052 diff may generate unexpected results for merges, as it will
3058 diff may generate unexpected results for merges, as it will
3053 default to comparing against the working directory's first
3059 default to comparing against the working directory's first
3054 parent changeset if no revisions are specified.
3060 parent changeset if no revisions are specified.
3055
3061
3056 When two revision arguments are given, then changes are shown
3062 When two revision arguments are given, then changes are shown
3057 between those revisions. If only one revision is specified then
3063 between those revisions. If only one revision is specified then
3058 that revision is compared to the working directory, and, when no
3064 that revision is compared to the working directory, and, when no
3059 revisions are specified, the working directory files are compared
3065 revisions are specified, the working directory files are compared
3060 to its parent.
3066 to its parent.
3061
3067
3062 Alternatively you can specify -c/--change with a revision to see
3068 Alternatively you can specify -c/--change with a revision to see
3063 the changes in that changeset relative to its first parent.
3069 the changes in that changeset relative to its first parent.
3064
3070
3065 Without the -a/--text option, diff will avoid generating diffs of
3071 Without the -a/--text option, diff will avoid generating diffs of
3066 files it detects as binary. With -a, diff will generate a diff
3072 files it detects as binary. With -a, diff will generate a diff
3067 anyway, probably with undesirable results.
3073 anyway, probably with undesirable results.
3068
3074
3069 Use the -g/--git option to generate diffs in the git extended diff
3075 Use the -g/--git option to generate diffs in the git extended diff
3070 format. For more information, read :hg:`help diffs`.
3076 format. For more information, read :hg:`help diffs`.
3071
3077
3072 .. container:: verbose
3078 .. container:: verbose
3073
3079
3074 Examples:
3080 Examples:
3075
3081
3076 - compare a file in the current working directory to its parent::
3082 - compare a file in the current working directory to its parent::
3077
3083
3078 hg diff foo.c
3084 hg diff foo.c
3079
3085
3080 - compare two historical versions of a directory, with rename info::
3086 - compare two historical versions of a directory, with rename info::
3081
3087
3082 hg diff --git -r 1.0:1.2 lib/
3088 hg diff --git -r 1.0:1.2 lib/
3083
3089
3084 - get change stats relative to the last change on some date::
3090 - get change stats relative to the last change on some date::
3085
3091
3086 hg diff --stat -r "date('may 2')"
3092 hg diff --stat -r "date('may 2')"
3087
3093
3088 - diff all newly-added files that contain a keyword::
3094 - diff all newly-added files that contain a keyword::
3089
3095
3090 hg diff "set:added() and grep(GNU)"
3096 hg diff "set:added() and grep(GNU)"
3091
3097
3092 - compare a revision and its parents::
3098 - compare a revision and its parents::
3093
3099
3094 hg diff -c 9353 # compare against first parent
3100 hg diff -c 9353 # compare against first parent
3095 hg diff -r 9353^:9353 # same using revset syntax
3101 hg diff -r 9353^:9353 # same using revset syntax
3096 hg diff -r 9353^2:9353 # compare against the second parent
3102 hg diff -r 9353^2:9353 # compare against the second parent
3097
3103
3098 Returns 0 on success.
3104 Returns 0 on success.
3099 """
3105 """
3100
3106
3101 revs = opts.get('rev')
3107 revs = opts.get('rev')
3102 change = opts.get('change')
3108 change = opts.get('change')
3103 stat = opts.get('stat')
3109 stat = opts.get('stat')
3104 reverse = opts.get('reverse')
3110 reverse = opts.get('reverse')
3105
3111
3106 if revs and change:
3112 if revs and change:
3107 msg = _('cannot specify --rev and --change at the same time')
3113 msg = _('cannot specify --rev and --change at the same time')
3108 raise util.Abort(msg)
3114 raise util.Abort(msg)
3109 elif change:
3115 elif change:
3110 node2 = scmutil.revsingle(repo, change, None).node()
3116 node2 = scmutil.revsingle(repo, change, None).node()
3111 node1 = repo[node2].p1().node()
3117 node1 = repo[node2].p1().node()
3112 else:
3118 else:
3113 node1, node2 = scmutil.revpair(repo, revs)
3119 node1, node2 = scmutil.revpair(repo, revs)
3114
3120
3115 if reverse:
3121 if reverse:
3116 node1, node2 = node2, node1
3122 node1, node2 = node2, node1
3117
3123
3118 diffopts = patch.diffallopts(ui, opts)
3124 diffopts = patch.diffallopts(ui, opts)
3119 m = scmutil.match(repo[node2], pats, opts)
3125 m = scmutil.match(repo[node2], pats, opts)
3120 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
3126 cmdutil.diffordiffstat(ui, repo, diffopts, node1, node2, m, stat=stat,
3121 listsubrepos=opts.get('subrepos'))
3127 listsubrepos=opts.get('subrepos'))
3122
3128
3123 @command('^export',
3129 @command('^export',
3124 [('o', 'output', '',
3130 [('o', 'output', '',
3125 _('print output to file with formatted name'), _('FORMAT')),
3131 _('print output to file with formatted name'), _('FORMAT')),
3126 ('', 'switch-parent', None, _('diff against the second parent')),
3132 ('', 'switch-parent', None, _('diff against the second parent')),
3127 ('r', 'rev', [], _('revisions to export'), _('REV')),
3133 ('r', 'rev', [], _('revisions to export'), _('REV')),
3128 ] + diffopts,
3134 ] + diffopts,
3129 _('[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'))
3135 _('[OPTION]... [-o OUTFILESPEC] [-r] [REV]...'))
3130 def export(ui, repo, *changesets, **opts):
3136 def export(ui, repo, *changesets, **opts):
3131 """dump the header and diffs for one or more changesets
3137 """dump the header and diffs for one or more changesets
3132
3138
3133 Print the changeset header and diffs for one or more revisions.
3139 Print the changeset header and diffs for one or more revisions.
3134 If no revision is given, the parent of the working directory is used.
3140 If no revision is given, the parent of the working directory is used.
3135
3141
3136 The information shown in the changeset header is: author, date,
3142 The information shown in the changeset header is: author, date,
3137 branch name (if non-default), changeset hash, parent(s) and commit
3143 branch name (if non-default), changeset hash, parent(s) and commit
3138 comment.
3144 comment.
3139
3145
3140 .. note::
3146 .. note::
3141
3147
3142 export may generate unexpected diff output for merge
3148 export may generate unexpected diff output for merge
3143 changesets, as it will compare the merge changeset against its
3149 changesets, as it will compare the merge changeset against its
3144 first parent only.
3150 first parent only.
3145
3151
3146 Output may be to a file, in which case the name of the file is
3152 Output may be to a file, in which case the name of the file is
3147 given using a format string. The formatting rules are as follows:
3153 given using a format string. The formatting rules are as follows:
3148
3154
3149 :``%%``: literal "%" character
3155 :``%%``: literal "%" character
3150 :``%H``: changeset hash (40 hexadecimal digits)
3156 :``%H``: changeset hash (40 hexadecimal digits)
3151 :``%N``: number of patches being generated
3157 :``%N``: number of patches being generated
3152 :``%R``: changeset revision number
3158 :``%R``: changeset revision number
3153 :``%b``: basename of the exporting repository
3159 :``%b``: basename of the exporting repository
3154 :``%h``: short-form changeset hash (12 hexadecimal digits)
3160 :``%h``: short-form changeset hash (12 hexadecimal digits)
3155 :``%m``: first line of the commit message (only alphanumeric characters)
3161 :``%m``: first line of the commit message (only alphanumeric characters)
3156 :``%n``: zero-padded sequence number, starting at 1
3162 :``%n``: zero-padded sequence number, starting at 1
3157 :``%r``: zero-padded changeset revision number
3163 :``%r``: zero-padded changeset revision number
3158
3164
3159 Without the -a/--text option, export will avoid generating diffs
3165 Without the -a/--text option, export will avoid generating diffs
3160 of files it detects as binary. With -a, export will generate a
3166 of files it detects as binary. With -a, export will generate a
3161 diff anyway, probably with undesirable results.
3167 diff anyway, probably with undesirable results.
3162
3168
3163 Use the -g/--git option to generate diffs in the git extended diff
3169 Use the -g/--git option to generate diffs in the git extended diff
3164 format. See :hg:`help diffs` for more information.
3170 format. See :hg:`help diffs` for more information.
3165
3171
3166 With the --switch-parent option, the diff will be against the
3172 With the --switch-parent option, the diff will be against the
3167 second parent. It can be useful to review a merge.
3173 second parent. It can be useful to review a merge.
3168
3174
3169 .. container:: verbose
3175 .. container:: verbose
3170
3176
3171 Examples:
3177 Examples:
3172
3178
3173 - use export and import to transplant a bugfix to the current
3179 - use export and import to transplant a bugfix to the current
3174 branch::
3180 branch::
3175
3181
3176 hg export -r 9353 | hg import -
3182 hg export -r 9353 | hg import -
3177
3183
3178 - export all the changesets between two revisions to a file with
3184 - export all the changesets between two revisions to a file with
3179 rename information::
3185 rename information::
3180
3186
3181 hg export --git -r 123:150 > changes.txt
3187 hg export --git -r 123:150 > changes.txt
3182
3188
3183 - split outgoing changes into a series of patches with
3189 - split outgoing changes into a series of patches with
3184 descriptive names::
3190 descriptive names::
3185
3191
3186 hg export -r "outgoing()" -o "%n-%m.patch"
3192 hg export -r "outgoing()" -o "%n-%m.patch"
3187
3193
3188 Returns 0 on success.
3194 Returns 0 on success.
3189 """
3195 """
3190 changesets += tuple(opts.get('rev', []))
3196 changesets += tuple(opts.get('rev', []))
3191 if not changesets:
3197 if not changesets:
3192 changesets = ['.']
3198 changesets = ['.']
3193 revs = scmutil.revrange(repo, changesets)
3199 revs = scmutil.revrange(repo, changesets)
3194 if not revs:
3200 if not revs:
3195 raise util.Abort(_("export requires at least one changeset"))
3201 raise util.Abort(_("export requires at least one changeset"))
3196 if len(revs) > 1:
3202 if len(revs) > 1:
3197 ui.note(_('exporting patches:\n'))
3203 ui.note(_('exporting patches:\n'))
3198 else:
3204 else:
3199 ui.note(_('exporting patch:\n'))
3205 ui.note(_('exporting patch:\n'))
3200 cmdutil.export(repo, revs, template=opts.get('output'),
3206 cmdutil.export(repo, revs, template=opts.get('output'),
3201 switch_parent=opts.get('switch_parent'),
3207 switch_parent=opts.get('switch_parent'),
3202 opts=patch.diffallopts(ui, opts))
3208 opts=patch.diffallopts(ui, opts))
3203
3209
3204 @command('files',
3210 @command('files',
3205 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3211 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
3206 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3212 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
3207 ] + walkopts + formatteropts,
3213 ] + walkopts + formatteropts,
3208 _('[OPTION]... [PATTERN]...'))
3214 _('[OPTION]... [PATTERN]...'))
3209 def files(ui, repo, *pats, **opts):
3215 def files(ui, repo, *pats, **opts):
3210 """list tracked files
3216 """list tracked files
3211
3217
3212 Print files under Mercurial control in the working directory or
3218 Print files under Mercurial control in the working directory or
3213 specified revision whose names match the given patterns (excluding
3219 specified revision whose names match the given patterns (excluding
3214 removed files).
3220 removed files).
3215
3221
3216 If no patterns are given to match, this command prints the names
3222 If no patterns are given to match, this command prints the names
3217 of all files under Mercurial control in the working copy.
3223 of all files under Mercurial control in the working copy.
3218
3224
3219 .. container:: verbose
3225 .. container:: verbose
3220
3226
3221 Examples:
3227 Examples:
3222
3228
3223 - list all files under the current directory::
3229 - list all files under the current directory::
3224
3230
3225 hg files .
3231 hg files .
3226
3232
3227 - shows sizes and flags for current revision::
3233 - shows sizes and flags for current revision::
3228
3234
3229 hg files -vr .
3235 hg files -vr .
3230
3236
3231 - list all files named README::
3237 - list all files named README::
3232
3238
3233 hg files -I "**/README"
3239 hg files -I "**/README"
3234
3240
3235 - list all binary files::
3241 - list all binary files::
3236
3242
3237 hg files "set:binary()"
3243 hg files "set:binary()"
3238
3244
3239 - find files containing a regular expression::
3245 - find files containing a regular expression::
3240
3246
3241 hg files "set:grep('bob')"
3247 hg files "set:grep('bob')"
3242
3248
3243 - search tracked file contents with xargs and grep::
3249 - search tracked file contents with xargs and grep::
3244
3250
3245 hg files -0 | xargs -0 grep foo
3251 hg files -0 | xargs -0 grep foo
3246
3252
3247 See :hg:`help patterns` and :hg:`help filesets` for more information
3253 See :hg:`help patterns` and :hg:`help filesets` for more information
3248 on specifying file patterns.
3254 on specifying file patterns.
3249
3255
3250 Returns 0 if a match is found, 1 otherwise.
3256 Returns 0 if a match is found, 1 otherwise.
3251
3257
3252 """
3258 """
3253 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
3259 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
3254 rev = ctx.rev()
3260 rev = ctx.rev()
3255 ret = 1
3261 ret = 1
3256
3262
3257 end = '\n'
3263 end = '\n'
3258 if opts.get('print0'):
3264 if opts.get('print0'):
3259 end = '\0'
3265 end = '\0'
3260 fm = ui.formatter('files', opts)
3266 fm = ui.formatter('files', opts)
3261 fmt = '%s' + end
3267 fmt = '%s' + end
3262
3268
3263 m = scmutil.match(ctx, pats, opts)
3269 m = scmutil.match(ctx, pats, opts)
3264 ds = repo.dirstate
3270 ds = repo.dirstate
3265 for f in ctx.matches(m):
3271 for f in ctx.matches(m):
3266 if rev is None and ds[f] == 'r':
3272 if rev is None and ds[f] == 'r':
3267 continue
3273 continue
3268 fm.startitem()
3274 fm.startitem()
3269 if ui.verbose:
3275 if ui.verbose:
3270 fc = ctx[f]
3276 fc = ctx[f]
3271 fm.write('size flags', '% 10d % 1s ', fc.size(), fc.flags())
3277 fm.write('size flags', '% 10d % 1s ', fc.size(), fc.flags())
3272 fm.data(abspath=f)
3278 fm.data(abspath=f)
3273 fm.write('path', fmt, m.rel(f))
3279 fm.write('path', fmt, m.rel(f))
3274 ret = 0
3280 ret = 0
3275
3281
3276 fm.end()
3282 fm.end()
3277
3283
3278 return ret
3284 return ret
3279
3285
3280 @command('^forget', walkopts, _('[OPTION]... FILE...'), inferrepo=True)
3286 @command('^forget', walkopts, _('[OPTION]... FILE...'), inferrepo=True)
3281 def forget(ui, repo, *pats, **opts):
3287 def forget(ui, repo, *pats, **opts):
3282 """forget the specified files on the next commit
3288 """forget the specified files on the next commit
3283
3289
3284 Mark the specified files so they will no longer be tracked
3290 Mark the specified files so they will no longer be tracked
3285 after the next commit.
3291 after the next commit.
3286
3292
3287 This only removes files from the current branch, not from the
3293 This only removes files from the current branch, not from the
3288 entire project history, and it does not delete them from the
3294 entire project history, and it does not delete them from the
3289 working directory.
3295 working directory.
3290
3296
3291 To undo a forget before the next commit, see :hg:`add`.
3297 To undo a forget before the next commit, see :hg:`add`.
3292
3298
3293 .. container:: verbose
3299 .. container:: verbose
3294
3300
3295 Examples:
3301 Examples:
3296
3302
3297 - forget newly-added binary files::
3303 - forget newly-added binary files::
3298
3304
3299 hg forget "set:added() and binary()"
3305 hg forget "set:added() and binary()"
3300
3306
3301 - forget files that would be excluded by .hgignore::
3307 - forget files that would be excluded by .hgignore::
3302
3308
3303 hg forget "set:hgignore()"
3309 hg forget "set:hgignore()"
3304
3310
3305 Returns 0 on success.
3311 Returns 0 on success.
3306 """
3312 """
3307
3313
3308 if not pats:
3314 if not pats:
3309 raise util.Abort(_('no files specified'))
3315 raise util.Abort(_('no files specified'))
3310
3316
3311 m = scmutil.match(repo[None], pats, opts)
3317 m = scmutil.match(repo[None], pats, opts)
3312 rejected = cmdutil.forget(ui, repo, m, prefix="", explicitonly=False)[0]
3318 rejected = cmdutil.forget(ui, repo, m, prefix="", explicitonly=False)[0]
3313 return rejected and 1 or 0
3319 return rejected and 1 or 0
3314
3320
3315 @command(
3321 @command(
3316 'graft',
3322 'graft',
3317 [('r', 'rev', [], _('revisions to graft'), _('REV')),
3323 [('r', 'rev', [], _('revisions to graft'), _('REV')),
3318 ('c', 'continue', False, _('resume interrupted graft')),
3324 ('c', 'continue', False, _('resume interrupted graft')),
3319 ('e', 'edit', False, _('invoke editor on commit messages')),
3325 ('e', 'edit', False, _('invoke editor on commit messages')),
3320 ('', 'log', None, _('append graft info to log message')),
3326 ('', 'log', None, _('append graft info to log message')),
3321 ('f', 'force', False, _('force graft')),
3327 ('f', 'force', False, _('force graft')),
3322 ('D', 'currentdate', False,
3328 ('D', 'currentdate', False,
3323 _('record the current date as commit date')),
3329 _('record the current date as commit date')),
3324 ('U', 'currentuser', False,
3330 ('U', 'currentuser', False,
3325 _('record the current user as committer'), _('DATE'))]
3331 _('record the current user as committer'), _('DATE'))]
3326 + commitopts2 + mergetoolopts + dryrunopts,
3332 + commitopts2 + mergetoolopts + dryrunopts,
3327 _('[OPTION]... [-r] REV...'))
3333 _('[OPTION]... [-r] REV...'))
3328 def graft(ui, repo, *revs, **opts):
3334 def graft(ui, repo, *revs, **opts):
3329 '''copy changes from other branches onto the current branch
3335 '''copy changes from other branches onto the current branch
3330
3336
3331 This command uses Mercurial's merge logic to copy individual
3337 This command uses Mercurial's merge logic to copy individual
3332 changes from other branches without merging branches in the
3338 changes from other branches without merging branches in the
3333 history graph. This is sometimes known as 'backporting' or
3339 history graph. This is sometimes known as 'backporting' or
3334 'cherry-picking'. By default, graft will copy user, date, and
3340 'cherry-picking'. By default, graft will copy user, date, and
3335 description from the source changesets.
3341 description from the source changesets.
3336
3342
3337 Changesets that are ancestors of the current revision, that have
3343 Changesets that are ancestors of the current revision, that have
3338 already been grafted, or that are merges will be skipped.
3344 already been grafted, or that are merges will be skipped.
3339
3345
3340 If --log is specified, log messages will have a comment appended
3346 If --log is specified, log messages will have a comment appended
3341 of the form::
3347 of the form::
3342
3348
3343 (grafted from CHANGESETHASH)
3349 (grafted from CHANGESETHASH)
3344
3350
3345 If --force is specified, revisions will be grafted even if they
3351 If --force is specified, revisions will be grafted even if they
3346 are already ancestors of or have been grafted to the destination.
3352 are already ancestors of or have been grafted to the destination.
3347 This is useful when the revisions have since been backed out.
3353 This is useful when the revisions have since been backed out.
3348
3354
3349 If a graft merge results in conflicts, the graft process is
3355 If a graft merge results in conflicts, the graft process is
3350 interrupted so that the current merge can be manually resolved.
3356 interrupted so that the current merge can be manually resolved.
3351 Once all conflicts are addressed, the graft process can be
3357 Once all conflicts are addressed, the graft process can be
3352 continued with the -c/--continue option.
3358 continued with the -c/--continue option.
3353
3359
3354 .. note::
3360 .. note::
3355
3361
3356 The -c/--continue option does not reapply earlier options, except
3362 The -c/--continue option does not reapply earlier options, except
3357 for --force.
3363 for --force.
3358
3364
3359 .. container:: verbose
3365 .. container:: verbose
3360
3366
3361 Examples:
3367 Examples:
3362
3368
3363 - copy a single change to the stable branch and edit its description::
3369 - copy a single change to the stable branch and edit its description::
3364
3370
3365 hg update stable
3371 hg update stable
3366 hg graft --edit 9393
3372 hg graft --edit 9393
3367
3373
3368 - graft a range of changesets with one exception, updating dates::
3374 - graft a range of changesets with one exception, updating dates::
3369
3375
3370 hg graft -D "2085::2093 and not 2091"
3376 hg graft -D "2085::2093 and not 2091"
3371
3377
3372 - continue a graft after resolving conflicts::
3378 - continue a graft after resolving conflicts::
3373
3379
3374 hg graft -c
3380 hg graft -c
3375
3381
3376 - show the source of a grafted changeset::
3382 - show the source of a grafted changeset::
3377
3383
3378 hg log --debug -r .
3384 hg log --debug -r .
3379
3385
3380 See :hg:`help revisions` and :hg:`help revsets` for more about
3386 See :hg:`help revisions` and :hg:`help revsets` for more about
3381 specifying revisions.
3387 specifying revisions.
3382
3388
3383 Returns 0 on successful completion.
3389 Returns 0 on successful completion.
3384 '''
3390 '''
3385
3391
3386 revs = list(revs)
3392 revs = list(revs)
3387 revs.extend(opts['rev'])
3393 revs.extend(opts['rev'])
3388
3394
3389 if not opts.get('user') and opts.get('currentuser'):
3395 if not opts.get('user') and opts.get('currentuser'):
3390 opts['user'] = ui.username()
3396 opts['user'] = ui.username()
3391 if not opts.get('date') and opts.get('currentdate'):
3397 if not opts.get('date') and opts.get('currentdate'):
3392 opts['date'] = "%d %d" % util.makedate()
3398 opts['date'] = "%d %d" % util.makedate()
3393
3399
3394 editor = cmdutil.getcommiteditor(editform='graft', **opts)
3400 editor = cmdutil.getcommiteditor(editform='graft', **opts)
3395
3401
3396 cont = False
3402 cont = False
3397 if opts['continue']:
3403 if opts['continue']:
3398 cont = True
3404 cont = True
3399 if revs:
3405 if revs:
3400 raise util.Abort(_("can't specify --continue and revisions"))
3406 raise util.Abort(_("can't specify --continue and revisions"))
3401 # read in unfinished revisions
3407 # read in unfinished revisions
3402 try:
3408 try:
3403 nodes = repo.vfs.read('graftstate').splitlines()
3409 nodes = repo.vfs.read('graftstate').splitlines()
3404 revs = [repo[node].rev() for node in nodes]
3410 revs = [repo[node].rev() for node in nodes]
3405 except IOError, inst:
3411 except IOError, inst:
3406 if inst.errno != errno.ENOENT:
3412 if inst.errno != errno.ENOENT:
3407 raise
3413 raise
3408 raise util.Abort(_("no graft state found, can't continue"))
3414 raise util.Abort(_("no graft state found, can't continue"))
3409 else:
3415 else:
3410 cmdutil.checkunfinished(repo)
3416 cmdutil.checkunfinished(repo)
3411 cmdutil.bailifchanged(repo)
3417 cmdutil.bailifchanged(repo)
3412 if not revs:
3418 if not revs:
3413 raise util.Abort(_('no revisions specified'))
3419 raise util.Abort(_('no revisions specified'))
3414 revs = scmutil.revrange(repo, revs)
3420 revs = scmutil.revrange(repo, revs)
3415
3421
3416 skipped = set()
3422 skipped = set()
3417 # check for merges
3423 # check for merges
3418 for rev in repo.revs('%ld and merge()', revs):
3424 for rev in repo.revs('%ld and merge()', revs):
3419 ui.warn(_('skipping ungraftable merge revision %s\n') % rev)
3425 ui.warn(_('skipping ungraftable merge revision %s\n') % rev)
3420 skipped.add(rev)
3426 skipped.add(rev)
3421 revs = [r for r in revs if r not in skipped]
3427 revs = [r for r in revs if r not in skipped]
3422 if not revs:
3428 if not revs:
3423 return -1
3429 return -1
3424
3430
3425 # Don't check in the --continue case, in effect retaining --force across
3431 # Don't check in the --continue case, in effect retaining --force across
3426 # --continues. That's because without --force, any revisions we decided to
3432 # --continues. That's because without --force, any revisions we decided to
3427 # skip would have been filtered out here, so they wouldn't have made their
3433 # skip would have been filtered out here, so they wouldn't have made their
3428 # way to the graftstate. With --force, any revisions we would have otherwise
3434 # way to the graftstate. With --force, any revisions we would have otherwise
3429 # skipped would not have been filtered out, and if they hadn't been applied
3435 # skipped would not have been filtered out, and if they hadn't been applied
3430 # already, they'd have been in the graftstate.
3436 # already, they'd have been in the graftstate.
3431 if not (cont or opts.get('force')):
3437 if not (cont or opts.get('force')):
3432 # check for ancestors of dest branch
3438 # check for ancestors of dest branch
3433 crev = repo['.'].rev()
3439 crev = repo['.'].rev()
3434 ancestors = repo.changelog.ancestors([crev], inclusive=True)
3440 ancestors = repo.changelog.ancestors([crev], inclusive=True)
3435 # Cannot use x.remove(y) on smart set, this has to be a list.
3441 # Cannot use x.remove(y) on smart set, this has to be a list.
3436 # XXX make this lazy in the future
3442 # XXX make this lazy in the future
3437 revs = list(revs)
3443 revs = list(revs)
3438 # don't mutate while iterating, create a copy
3444 # don't mutate while iterating, create a copy
3439 for rev in list(revs):
3445 for rev in list(revs):
3440 if rev in ancestors:
3446 if rev in ancestors:
3441 ui.warn(_('skipping ancestor revision %d:%s\n') %
3447 ui.warn(_('skipping ancestor revision %d:%s\n') %
3442 (rev, repo[rev]))
3448 (rev, repo[rev]))
3443 # XXX remove on list is slow
3449 # XXX remove on list is slow
3444 revs.remove(rev)
3450 revs.remove(rev)
3445 if not revs:
3451 if not revs:
3446 return -1
3452 return -1
3447
3453
3448 # analyze revs for earlier grafts
3454 # analyze revs for earlier grafts
3449 ids = {}
3455 ids = {}
3450 for ctx in repo.set("%ld", revs):
3456 for ctx in repo.set("%ld", revs):
3451 ids[ctx.hex()] = ctx.rev()
3457 ids[ctx.hex()] = ctx.rev()
3452 n = ctx.extra().get('source')
3458 n = ctx.extra().get('source')
3453 if n:
3459 if n:
3454 ids[n] = ctx.rev()
3460 ids[n] = ctx.rev()
3455
3461
3456 # check ancestors for earlier grafts
3462 # check ancestors for earlier grafts
3457 ui.debug('scanning for duplicate grafts\n')
3463 ui.debug('scanning for duplicate grafts\n')
3458
3464
3459 for rev in repo.changelog.findmissingrevs(revs, [crev]):
3465 for rev in repo.changelog.findmissingrevs(revs, [crev]):
3460 ctx = repo[rev]
3466 ctx = repo[rev]
3461 n = ctx.extra().get('source')
3467 n = ctx.extra().get('source')
3462 if n in ids:
3468 if n in ids:
3463 try:
3469 try:
3464 r = repo[n].rev()
3470 r = repo[n].rev()
3465 except error.RepoLookupError:
3471 except error.RepoLookupError:
3466 r = None
3472 r = None
3467 if r in revs:
3473 if r in revs:
3468 ui.warn(_('skipping revision %d:%s '
3474 ui.warn(_('skipping revision %d:%s '
3469 '(already grafted to %d:%s)\n')
3475 '(already grafted to %d:%s)\n')
3470 % (r, repo[r], rev, ctx))
3476 % (r, repo[r], rev, ctx))
3471 revs.remove(r)
3477 revs.remove(r)
3472 elif ids[n] in revs:
3478 elif ids[n] in revs:
3473 if r is None:
3479 if r is None:
3474 ui.warn(_('skipping already grafted revision %d:%s '
3480 ui.warn(_('skipping already grafted revision %d:%s '
3475 '(%d:%s also has unknown origin %s)\n')
3481 '(%d:%s also has unknown origin %s)\n')
3476 % (ids[n], repo[ids[n]], rev, ctx, n[:12]))
3482 % (ids[n], repo[ids[n]], rev, ctx, n[:12]))
3477 else:
3483 else:
3478 ui.warn(_('skipping already grafted revision %d:%s '
3484 ui.warn(_('skipping already grafted revision %d:%s '
3479 '(%d:%s also has origin %d:%s)\n')
3485 '(%d:%s also has origin %d:%s)\n')
3480 % (ids[n], repo[ids[n]], rev, ctx, r, n[:12]))
3486 % (ids[n], repo[ids[n]], rev, ctx, r, n[:12]))
3481 revs.remove(ids[n])
3487 revs.remove(ids[n])
3482 elif ctx.hex() in ids:
3488 elif ctx.hex() in ids:
3483 r = ids[ctx.hex()]
3489 r = ids[ctx.hex()]
3484 ui.warn(_('skipping already grafted revision %d:%s '
3490 ui.warn(_('skipping already grafted revision %d:%s '
3485 '(was grafted from %d:%s)\n') %
3491 '(was grafted from %d:%s)\n') %
3486 (r, repo[r], rev, ctx))
3492 (r, repo[r], rev, ctx))
3487 revs.remove(r)
3493 revs.remove(r)
3488 if not revs:
3494 if not revs:
3489 return -1
3495 return -1
3490
3496
3491 wlock = repo.wlock()
3497 wlock = repo.wlock()
3492 try:
3498 try:
3493 for pos, ctx in enumerate(repo.set("%ld", revs)):
3499 for pos, ctx in enumerate(repo.set("%ld", revs)):
3494 desc = '%d:%s "%s"' % (ctx.rev(), ctx,
3500 desc = '%d:%s "%s"' % (ctx.rev(), ctx,
3495 ctx.description().split('\n', 1)[0])
3501 ctx.description().split('\n', 1)[0])
3496 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
3502 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
3497 if names:
3503 if names:
3498 desc += ' (%s)' % ' '.join(names)
3504 desc += ' (%s)' % ' '.join(names)
3499 ui.status(_('grafting %s\n') % desc)
3505 ui.status(_('grafting %s\n') % desc)
3500 if opts.get('dry_run'):
3506 if opts.get('dry_run'):
3501 continue
3507 continue
3502
3508
3503 source = ctx.extra().get('source')
3509 source = ctx.extra().get('source')
3504 if not source:
3510 if not source:
3505 source = ctx.hex()
3511 source = ctx.hex()
3506 extra = {'source': source}
3512 extra = {'source': source}
3507 user = ctx.user()
3513 user = ctx.user()
3508 if opts.get('user'):
3514 if opts.get('user'):
3509 user = opts['user']
3515 user = opts['user']
3510 date = ctx.date()
3516 date = ctx.date()
3511 if opts.get('date'):
3517 if opts.get('date'):
3512 date = opts['date']
3518 date = opts['date']
3513 message = ctx.description()
3519 message = ctx.description()
3514 if opts.get('log'):
3520 if opts.get('log'):
3515 message += '\n(grafted from %s)' % ctx.hex()
3521 message += '\n(grafted from %s)' % ctx.hex()
3516
3522
3517 # we don't merge the first commit when continuing
3523 # we don't merge the first commit when continuing
3518 if not cont:
3524 if not cont:
3519 # perform the graft merge with p1(rev) as 'ancestor'
3525 # perform the graft merge with p1(rev) as 'ancestor'
3520 try:
3526 try:
3521 # ui.forcemerge is an internal variable, do not document
3527 # ui.forcemerge is an internal variable, do not document
3522 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
3528 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
3523 'graft')
3529 'graft')
3524 stats = mergemod.graft(repo, ctx, ctx.p1(),
3530 stats = mergemod.graft(repo, ctx, ctx.p1(),
3525 ['local', 'graft'])
3531 ['local', 'graft'])
3526 finally:
3532 finally:
3527 repo.ui.setconfig('ui', 'forcemerge', '', 'graft')
3533 repo.ui.setconfig('ui', 'forcemerge', '', 'graft')
3528 # report any conflicts
3534 # report any conflicts
3529 if stats and stats[3] > 0:
3535 if stats and stats[3] > 0:
3530 # write out state for --continue
3536 # write out state for --continue
3531 nodelines = [repo[rev].hex() + "\n" for rev in revs[pos:]]
3537 nodelines = [repo[rev].hex() + "\n" for rev in revs[pos:]]
3532 repo.vfs.write('graftstate', ''.join(nodelines))
3538 repo.vfs.write('graftstate', ''.join(nodelines))
3533 raise util.Abort(
3539 raise util.Abort(
3534 _("unresolved conflicts, can't continue"),
3540 _("unresolved conflicts, can't continue"),
3535 hint=_('use hg resolve and hg graft --continue'))
3541 hint=_('use hg resolve and hg graft --continue'))
3536 else:
3542 else:
3537 cont = False
3543 cont = False
3538
3544
3539 # commit
3545 # commit
3540 node = repo.commit(text=message, user=user,
3546 node = repo.commit(text=message, user=user,
3541 date=date, extra=extra, editor=editor)
3547 date=date, extra=extra, editor=editor)
3542 if node is None:
3548 if node is None:
3543 ui.warn(
3549 ui.warn(
3544 _('note: graft of %d:%s created no changes to commit\n') %
3550 _('note: graft of %d:%s created no changes to commit\n') %
3545 (ctx.rev(), ctx))
3551 (ctx.rev(), ctx))
3546 finally:
3552 finally:
3547 wlock.release()
3553 wlock.release()
3548
3554
3549 # remove state when we complete successfully
3555 # remove state when we complete successfully
3550 if not opts.get('dry_run'):
3556 if not opts.get('dry_run'):
3551 util.unlinkpath(repo.join('graftstate'), ignoremissing=True)
3557 util.unlinkpath(repo.join('graftstate'), ignoremissing=True)
3552
3558
3553 return 0
3559 return 0
3554
3560
3555 @command('grep',
3561 @command('grep',
3556 [('0', 'print0', None, _('end fields with NUL')),
3562 [('0', 'print0', None, _('end fields with NUL')),
3557 ('', 'all', None, _('print all revisions that match')),
3563 ('', 'all', None, _('print all revisions that match')),
3558 ('a', 'text', None, _('treat all files as text')),
3564 ('a', 'text', None, _('treat all files as text')),
3559 ('f', 'follow', None,
3565 ('f', 'follow', None,
3560 _('follow changeset history,'
3566 _('follow changeset history,'
3561 ' or file history across copies and renames')),
3567 ' or file history across copies and renames')),
3562 ('i', 'ignore-case', None, _('ignore case when matching')),
3568 ('i', 'ignore-case', None, _('ignore case when matching')),
3563 ('l', 'files-with-matches', None,
3569 ('l', 'files-with-matches', None,
3564 _('print only filenames and revisions that match')),
3570 _('print only filenames and revisions that match')),
3565 ('n', 'line-number', None, _('print matching line numbers')),
3571 ('n', 'line-number', None, _('print matching line numbers')),
3566 ('r', 'rev', [],
3572 ('r', 'rev', [],
3567 _('only search files changed within revision range'), _('REV')),
3573 _('only search files changed within revision range'), _('REV')),
3568 ('u', 'user', None, _('list the author (long with -v)')),
3574 ('u', 'user', None, _('list the author (long with -v)')),
3569 ('d', 'date', None, _('list the date (short with -q)')),
3575 ('d', 'date', None, _('list the date (short with -q)')),
3570 ] + walkopts,
3576 ] + walkopts,
3571 _('[OPTION]... PATTERN [FILE]...'),
3577 _('[OPTION]... PATTERN [FILE]...'),
3572 inferrepo=True)
3578 inferrepo=True)
3573 def grep(ui, repo, pattern, *pats, **opts):
3579 def grep(ui, repo, pattern, *pats, **opts):
3574 """search for a pattern in specified files and revisions
3580 """search for a pattern in specified files and revisions
3575
3581
3576 Search revisions of files for a regular expression.
3582 Search revisions of files for a regular expression.
3577
3583
3578 This command behaves differently than Unix grep. It only accepts
3584 This command behaves differently than Unix grep. It only accepts
3579 Python/Perl regexps. It searches repository history, not the
3585 Python/Perl regexps. It searches repository history, not the
3580 working directory. It always prints the revision number in which a
3586 working directory. It always prints the revision number in which a
3581 match appears.
3587 match appears.
3582
3588
3583 By default, grep only prints output for the first revision of a
3589 By default, grep only prints output for the first revision of a
3584 file in which it finds a match. To get it to print every revision
3590 file in which it finds a match. To get it to print every revision
3585 that contains a change in match status ("-" for a match that
3591 that contains a change in match status ("-" for a match that
3586 becomes a non-match, or "+" for a non-match that becomes a match),
3592 becomes a non-match, or "+" for a non-match that becomes a match),
3587 use the --all flag.
3593 use the --all flag.
3588
3594
3589 Returns 0 if a match is found, 1 otherwise.
3595 Returns 0 if a match is found, 1 otherwise.
3590 """
3596 """
3591 reflags = re.M
3597 reflags = re.M
3592 if opts.get('ignore_case'):
3598 if opts.get('ignore_case'):
3593 reflags |= re.I
3599 reflags |= re.I
3594 try:
3600 try:
3595 regexp = util.re.compile(pattern, reflags)
3601 regexp = util.re.compile(pattern, reflags)
3596 except re.error, inst:
3602 except re.error, inst:
3597 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
3603 ui.warn(_("grep: invalid match pattern: %s\n") % inst)
3598 return 1
3604 return 1
3599 sep, eol = ':', '\n'
3605 sep, eol = ':', '\n'
3600 if opts.get('print0'):
3606 if opts.get('print0'):
3601 sep = eol = '\0'
3607 sep = eol = '\0'
3602
3608
3603 getfile = util.lrucachefunc(repo.file)
3609 getfile = util.lrucachefunc(repo.file)
3604
3610
3605 def matchlines(body):
3611 def matchlines(body):
3606 begin = 0
3612 begin = 0
3607 linenum = 0
3613 linenum = 0
3608 while begin < len(body):
3614 while begin < len(body):
3609 match = regexp.search(body, begin)
3615 match = regexp.search(body, begin)
3610 if not match:
3616 if not match:
3611 break
3617 break
3612 mstart, mend = match.span()
3618 mstart, mend = match.span()
3613 linenum += body.count('\n', begin, mstart) + 1
3619 linenum += body.count('\n', begin, mstart) + 1
3614 lstart = body.rfind('\n', begin, mstart) + 1 or begin
3620 lstart = body.rfind('\n', begin, mstart) + 1 or begin
3615 begin = body.find('\n', mend) + 1 or len(body) + 1
3621 begin = body.find('\n', mend) + 1 or len(body) + 1
3616 lend = begin - 1
3622 lend = begin - 1
3617 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
3623 yield linenum, mstart - lstart, mend - lstart, body[lstart:lend]
3618
3624
3619 class linestate(object):
3625 class linestate(object):
3620 def __init__(self, line, linenum, colstart, colend):
3626 def __init__(self, line, linenum, colstart, colend):
3621 self.line = line
3627 self.line = line
3622 self.linenum = linenum
3628 self.linenum = linenum
3623 self.colstart = colstart
3629 self.colstart = colstart
3624 self.colend = colend
3630 self.colend = colend
3625
3631
3626 def __hash__(self):
3632 def __hash__(self):
3627 return hash((self.linenum, self.line))
3633 return hash((self.linenum, self.line))
3628
3634
3629 def __eq__(self, other):
3635 def __eq__(self, other):
3630 return self.line == other.line
3636 return self.line == other.line
3631
3637
3632 def __iter__(self):
3638 def __iter__(self):
3633 yield (self.line[:self.colstart], '')
3639 yield (self.line[:self.colstart], '')
3634 yield (self.line[self.colstart:self.colend], 'grep.match')
3640 yield (self.line[self.colstart:self.colend], 'grep.match')
3635 rest = self.line[self.colend:]
3641 rest = self.line[self.colend:]
3636 while rest != '':
3642 while rest != '':
3637 match = regexp.search(rest)
3643 match = regexp.search(rest)
3638 if not match:
3644 if not match:
3639 yield (rest, '')
3645 yield (rest, '')
3640 break
3646 break
3641 mstart, mend = match.span()
3647 mstart, mend = match.span()
3642 yield (rest[:mstart], '')
3648 yield (rest[:mstart], '')
3643 yield (rest[mstart:mend], 'grep.match')
3649 yield (rest[mstart:mend], 'grep.match')
3644 rest = rest[mend:]
3650 rest = rest[mend:]
3645
3651
3646 matches = {}
3652 matches = {}
3647 copies = {}
3653 copies = {}
3648 def grepbody(fn, rev, body):
3654 def grepbody(fn, rev, body):
3649 matches[rev].setdefault(fn, [])
3655 matches[rev].setdefault(fn, [])
3650 m = matches[rev][fn]
3656 m = matches[rev][fn]
3651 for lnum, cstart, cend, line in matchlines(body):
3657 for lnum, cstart, cend, line in matchlines(body):
3652 s = linestate(line, lnum, cstart, cend)
3658 s = linestate(line, lnum, cstart, cend)
3653 m.append(s)
3659 m.append(s)
3654
3660
3655 def difflinestates(a, b):
3661 def difflinestates(a, b):
3656 sm = difflib.SequenceMatcher(None, a, b)
3662 sm = difflib.SequenceMatcher(None, a, b)
3657 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
3663 for tag, alo, ahi, blo, bhi in sm.get_opcodes():
3658 if tag == 'insert':
3664 if tag == 'insert':
3659 for i in xrange(blo, bhi):
3665 for i in xrange(blo, bhi):
3660 yield ('+', b[i])
3666 yield ('+', b[i])
3661 elif tag == 'delete':
3667 elif tag == 'delete':
3662 for i in xrange(alo, ahi):
3668 for i in xrange(alo, ahi):
3663 yield ('-', a[i])
3669 yield ('-', a[i])
3664 elif tag == 'replace':
3670 elif tag == 'replace':
3665 for i in xrange(alo, ahi):
3671 for i in xrange(alo, ahi):
3666 yield ('-', a[i])
3672 yield ('-', a[i])
3667 for i in xrange(blo, bhi):
3673 for i in xrange(blo, bhi):
3668 yield ('+', b[i])
3674 yield ('+', b[i])
3669
3675
3670 def display(fn, ctx, pstates, states):
3676 def display(fn, ctx, pstates, states):
3671 rev = ctx.rev()
3677 rev = ctx.rev()
3672 datefunc = ui.quiet and util.shortdate or util.datestr
3678 datefunc = ui.quiet and util.shortdate or util.datestr
3673 found = False
3679 found = False
3674 @util.cachefunc
3680 @util.cachefunc
3675 def binary():
3681 def binary():
3676 flog = getfile(fn)
3682 flog = getfile(fn)
3677 return util.binary(flog.read(ctx.filenode(fn)))
3683 return util.binary(flog.read(ctx.filenode(fn)))
3678
3684
3679 if opts.get('all'):
3685 if opts.get('all'):
3680 iter = difflinestates(pstates, states)
3686 iter = difflinestates(pstates, states)
3681 else:
3687 else:
3682 iter = [('', l) for l in states]
3688 iter = [('', l) for l in states]
3683 for change, l in iter:
3689 for change, l in iter:
3684 cols = [(fn, 'grep.filename'), (str(rev), 'grep.rev')]
3690 cols = [(fn, 'grep.filename'), (str(rev), 'grep.rev')]
3685
3691
3686 if opts.get('line_number'):
3692 if opts.get('line_number'):
3687 cols.append((str(l.linenum), 'grep.linenumber'))
3693 cols.append((str(l.linenum), 'grep.linenumber'))
3688 if opts.get('all'):
3694 if opts.get('all'):
3689 cols.append((change, 'grep.change'))
3695 cols.append((change, 'grep.change'))
3690 if opts.get('user'):
3696 if opts.get('user'):
3691 cols.append((ui.shortuser(ctx.user()), 'grep.user'))
3697 cols.append((ui.shortuser(ctx.user()), 'grep.user'))
3692 if opts.get('date'):
3698 if opts.get('date'):
3693 cols.append((datefunc(ctx.date()), 'grep.date'))
3699 cols.append((datefunc(ctx.date()), 'grep.date'))
3694 for col, label in cols[:-1]:
3700 for col, label in cols[:-1]:
3695 ui.write(col, label=label)
3701 ui.write(col, label=label)
3696 ui.write(sep, label='grep.sep')
3702 ui.write(sep, label='grep.sep')
3697 ui.write(cols[-1][0], label=cols[-1][1])
3703 ui.write(cols[-1][0], label=cols[-1][1])
3698 if not opts.get('files_with_matches'):
3704 if not opts.get('files_with_matches'):
3699 ui.write(sep, label='grep.sep')
3705 ui.write(sep, label='grep.sep')
3700 if not opts.get('text') and binary():
3706 if not opts.get('text') and binary():
3701 ui.write(" Binary file matches")
3707 ui.write(" Binary file matches")
3702 else:
3708 else:
3703 for s, label in l:
3709 for s, label in l:
3704 ui.write(s, label=label)
3710 ui.write(s, label=label)
3705 ui.write(eol)
3711 ui.write(eol)
3706 found = True
3712 found = True
3707 if opts.get('files_with_matches'):
3713 if opts.get('files_with_matches'):
3708 break
3714 break
3709 return found
3715 return found
3710
3716
3711 skip = {}
3717 skip = {}
3712 revfiles = {}
3718 revfiles = {}
3713 matchfn = scmutil.match(repo[None], pats, opts)
3719 matchfn = scmutil.match(repo[None], pats, opts)
3714 found = False
3720 found = False
3715 follow = opts.get('follow')
3721 follow = opts.get('follow')
3716
3722
3717 def prep(ctx, fns):
3723 def prep(ctx, fns):
3718 rev = ctx.rev()
3724 rev = ctx.rev()
3719 pctx = ctx.p1()
3725 pctx = ctx.p1()
3720 parent = pctx.rev()
3726 parent = pctx.rev()
3721 matches.setdefault(rev, {})
3727 matches.setdefault(rev, {})
3722 matches.setdefault(parent, {})
3728 matches.setdefault(parent, {})
3723 files = revfiles.setdefault(rev, [])
3729 files = revfiles.setdefault(rev, [])
3724 for fn in fns:
3730 for fn in fns:
3725 flog = getfile(fn)
3731 flog = getfile(fn)
3726 try:
3732 try:
3727 fnode = ctx.filenode(fn)
3733 fnode = ctx.filenode(fn)
3728 except error.LookupError:
3734 except error.LookupError:
3729 continue
3735 continue
3730
3736
3731 copied = flog.renamed(fnode)
3737 copied = flog.renamed(fnode)
3732 copy = follow and copied and copied[0]
3738 copy = follow and copied and copied[0]
3733 if copy:
3739 if copy:
3734 copies.setdefault(rev, {})[fn] = copy
3740 copies.setdefault(rev, {})[fn] = copy
3735 if fn in skip:
3741 if fn in skip:
3736 if copy:
3742 if copy:
3737 skip[copy] = True
3743 skip[copy] = True
3738 continue
3744 continue
3739 files.append(fn)
3745 files.append(fn)
3740
3746
3741 if fn not in matches[rev]:
3747 if fn not in matches[rev]:
3742 grepbody(fn, rev, flog.read(fnode))
3748 grepbody(fn, rev, flog.read(fnode))
3743
3749
3744 pfn = copy or fn
3750 pfn = copy or fn
3745 if pfn not in matches[parent]:
3751 if pfn not in matches[parent]:
3746 try:
3752 try:
3747 fnode = pctx.filenode(pfn)
3753 fnode = pctx.filenode(pfn)
3748 grepbody(pfn, parent, flog.read(fnode))
3754 grepbody(pfn, parent, flog.read(fnode))
3749 except error.LookupError:
3755 except error.LookupError:
3750 pass
3756 pass
3751
3757
3752 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
3758 for ctx in cmdutil.walkchangerevs(repo, matchfn, opts, prep):
3753 rev = ctx.rev()
3759 rev = ctx.rev()
3754 parent = ctx.p1().rev()
3760 parent = ctx.p1().rev()
3755 for fn in sorted(revfiles.get(rev, [])):
3761 for fn in sorted(revfiles.get(rev, [])):
3756 states = matches[rev][fn]
3762 states = matches[rev][fn]
3757 copy = copies.get(rev, {}).get(fn)
3763 copy = copies.get(rev, {}).get(fn)
3758 if fn in skip:
3764 if fn in skip:
3759 if copy:
3765 if copy:
3760 skip[copy] = True
3766 skip[copy] = True
3761 continue
3767 continue
3762 pstates = matches.get(parent, {}).get(copy or fn, [])
3768 pstates = matches.get(parent, {}).get(copy or fn, [])
3763 if pstates or states:
3769 if pstates or states:
3764 r = display(fn, ctx, pstates, states)
3770 r = display(fn, ctx, pstates, states)
3765 found = found or r
3771 found = found or r
3766 if r and not opts.get('all'):
3772 if r and not opts.get('all'):
3767 skip[fn] = True
3773 skip[fn] = True
3768 if copy:
3774 if copy:
3769 skip[copy] = True
3775 skip[copy] = True
3770 del matches[rev]
3776 del matches[rev]
3771 del revfiles[rev]
3777 del revfiles[rev]
3772
3778
3773 return not found
3779 return not found
3774
3780
3775 @command('heads',
3781 @command('heads',
3776 [('r', 'rev', '',
3782 [('r', 'rev', '',
3777 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
3783 _('show only heads which are descendants of STARTREV'), _('STARTREV')),
3778 ('t', 'topo', False, _('show topological heads only')),
3784 ('t', 'topo', False, _('show topological heads only')),
3779 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
3785 ('a', 'active', False, _('show active branchheads only (DEPRECATED)')),
3780 ('c', 'closed', False, _('show normal and closed branch heads')),
3786 ('c', 'closed', False, _('show normal and closed branch heads')),
3781 ] + templateopts,
3787 ] + templateopts,
3782 _('[-ct] [-r STARTREV] [REV]...'))
3788 _('[-ct] [-r STARTREV] [REV]...'))
3783 def heads(ui, repo, *branchrevs, **opts):
3789 def heads(ui, repo, *branchrevs, **opts):
3784 """show branch heads
3790 """show branch heads
3785
3791
3786 With no arguments, show all open branch heads in the repository.
3792 With no arguments, show all open branch heads in the repository.
3787 Branch heads are changesets that have no descendants on the
3793 Branch heads are changesets that have no descendants on the
3788 same branch. They are where development generally takes place and
3794 same branch. They are where development generally takes place and
3789 are the usual targets for update and merge operations.
3795 are the usual targets for update and merge operations.
3790
3796
3791 If one or more REVs are given, only open branch heads on the
3797 If one or more REVs are given, only open branch heads on the
3792 branches associated with the specified changesets are shown. This
3798 branches associated with the specified changesets are shown. This
3793 means that you can use :hg:`heads .` to see the heads on the
3799 means that you can use :hg:`heads .` to see the heads on the
3794 currently checked-out branch.
3800 currently checked-out branch.
3795
3801
3796 If -c/--closed is specified, also show branch heads marked closed
3802 If -c/--closed is specified, also show branch heads marked closed
3797 (see :hg:`commit --close-branch`).
3803 (see :hg:`commit --close-branch`).
3798
3804
3799 If STARTREV is specified, only those heads that are descendants of
3805 If STARTREV is specified, only those heads that are descendants of
3800 STARTREV will be displayed.
3806 STARTREV will be displayed.
3801
3807
3802 If -t/--topo is specified, named branch mechanics will be ignored and only
3808 If -t/--topo is specified, named branch mechanics will be ignored and only
3803 topological heads (changesets with no children) will be shown.
3809 topological heads (changesets with no children) will be shown.
3804
3810
3805 Returns 0 if matching heads are found, 1 if not.
3811 Returns 0 if matching heads are found, 1 if not.
3806 """
3812 """
3807
3813
3808 start = None
3814 start = None
3809 if 'rev' in opts:
3815 if 'rev' in opts:
3810 start = scmutil.revsingle(repo, opts['rev'], None).node()
3816 start = scmutil.revsingle(repo, opts['rev'], None).node()
3811
3817
3812 if opts.get('topo'):
3818 if opts.get('topo'):
3813 heads = [repo[h] for h in repo.heads(start)]
3819 heads = [repo[h] for h in repo.heads(start)]
3814 else:
3820 else:
3815 heads = []
3821 heads = []
3816 for branch in repo.branchmap():
3822 for branch in repo.branchmap():
3817 heads += repo.branchheads(branch, start, opts.get('closed'))
3823 heads += repo.branchheads(branch, start, opts.get('closed'))
3818 heads = [repo[h] for h in heads]
3824 heads = [repo[h] for h in heads]
3819
3825
3820 if branchrevs:
3826 if branchrevs:
3821 branches = set(repo[br].branch() for br in branchrevs)
3827 branches = set(repo[br].branch() for br in branchrevs)
3822 heads = [h for h in heads if h.branch() in branches]
3828 heads = [h for h in heads if h.branch() in branches]
3823
3829
3824 if opts.get('active') and branchrevs:
3830 if opts.get('active') and branchrevs:
3825 dagheads = repo.heads(start)
3831 dagheads = repo.heads(start)
3826 heads = [h for h in heads if h.node() in dagheads]
3832 heads = [h for h in heads if h.node() in dagheads]
3827
3833
3828 if branchrevs:
3834 if branchrevs:
3829 haveheads = set(h.branch() for h in heads)
3835 haveheads = set(h.branch() for h in heads)
3830 if branches - haveheads:
3836 if branches - haveheads:
3831 headless = ', '.join(b for b in branches - haveheads)
3837 headless = ', '.join(b for b in branches - haveheads)
3832 msg = _('no open branch heads found on branches %s')
3838 msg = _('no open branch heads found on branches %s')
3833 if opts.get('rev'):
3839 if opts.get('rev'):
3834 msg += _(' (started at %s)') % opts['rev']
3840 msg += _(' (started at %s)') % opts['rev']
3835 ui.warn((msg + '\n') % headless)
3841 ui.warn((msg + '\n') % headless)
3836
3842
3837 if not heads:
3843 if not heads:
3838 return 1
3844 return 1
3839
3845
3840 heads = sorted(heads, key=lambda x: -x.rev())
3846 heads = sorted(heads, key=lambda x: -x.rev())
3841 displayer = cmdutil.show_changeset(ui, repo, opts)
3847 displayer = cmdutil.show_changeset(ui, repo, opts)
3842 for ctx in heads:
3848 for ctx in heads:
3843 displayer.show(ctx)
3849 displayer.show(ctx)
3844 displayer.close()
3850 displayer.close()
3845
3851
3846 @command('help',
3852 @command('help',
3847 [('e', 'extension', None, _('show only help for extensions')),
3853 [('e', 'extension', None, _('show only help for extensions')),
3848 ('c', 'command', None, _('show only help for commands')),
3854 ('c', 'command', None, _('show only help for commands')),
3849 ('k', 'keyword', '', _('show topics matching keyword')),
3855 ('k', 'keyword', '', _('show topics matching keyword')),
3850 ],
3856 ],
3851 _('[-ec] [TOPIC]'),
3857 _('[-ec] [TOPIC]'),
3852 norepo=True)
3858 norepo=True)
3853 def help_(ui, name=None, **opts):
3859 def help_(ui, name=None, **opts):
3854 """show help for a given topic or a help overview
3860 """show help for a given topic or a help overview
3855
3861
3856 With no arguments, print a list of commands with short help messages.
3862 With no arguments, print a list of commands with short help messages.
3857
3863
3858 Given a topic, extension, or command name, print help for that
3864 Given a topic, extension, or command name, print help for that
3859 topic.
3865 topic.
3860
3866
3861 Returns 0 if successful.
3867 Returns 0 if successful.
3862 """
3868 """
3863
3869
3864 textwidth = min(ui.termwidth(), 80) - 2
3870 textwidth = min(ui.termwidth(), 80) - 2
3865
3871
3866 keep = []
3872 keep = []
3867 if ui.verbose:
3873 if ui.verbose:
3868 keep.append('verbose')
3874 keep.append('verbose')
3869 if sys.platform.startswith('win'):
3875 if sys.platform.startswith('win'):
3870 keep.append('windows')
3876 keep.append('windows')
3871 elif sys.platform == 'OpenVMS':
3877 elif sys.platform == 'OpenVMS':
3872 keep.append('vms')
3878 keep.append('vms')
3873 elif sys.platform == 'plan9':
3879 elif sys.platform == 'plan9':
3874 keep.append('plan9')
3880 keep.append('plan9')
3875 else:
3881 else:
3876 keep.append('unix')
3882 keep.append('unix')
3877 keep.append(sys.platform.lower())
3883 keep.append(sys.platform.lower())
3878
3884
3879 section = None
3885 section = None
3880 if name and '.' in name:
3886 if name and '.' in name:
3881 name, section = name.split('.', 1)
3887 name, section = name.split('.', 1)
3882
3888
3883 text = help.help_(ui, name, **opts)
3889 text = help.help_(ui, name, **opts)
3884
3890
3885 formatted, pruned = minirst.format(text, textwidth, keep=keep,
3891 formatted, pruned = minirst.format(text, textwidth, keep=keep,
3886 section=section)
3892 section=section)
3887 if section and not formatted:
3893 if section and not formatted:
3888 raise util.Abort(_("help section not found"))
3894 raise util.Abort(_("help section not found"))
3889
3895
3890 if 'verbose' in pruned:
3896 if 'verbose' in pruned:
3891 keep.append('omitted')
3897 keep.append('omitted')
3892 else:
3898 else:
3893 keep.append('notomitted')
3899 keep.append('notomitted')
3894 formatted, pruned = minirst.format(text, textwidth, keep=keep,
3900 formatted, pruned = minirst.format(text, textwidth, keep=keep,
3895 section=section)
3901 section=section)
3896 ui.write(formatted)
3902 ui.write(formatted)
3897
3903
3898
3904
3899 @command('identify|id',
3905 @command('identify|id',
3900 [('r', 'rev', '',
3906 [('r', 'rev', '',
3901 _('identify the specified revision'), _('REV')),
3907 _('identify the specified revision'), _('REV')),
3902 ('n', 'num', None, _('show local revision number')),
3908 ('n', 'num', None, _('show local revision number')),
3903 ('i', 'id', None, _('show global revision id')),
3909 ('i', 'id', None, _('show global revision id')),
3904 ('b', 'branch', None, _('show branch')),
3910 ('b', 'branch', None, _('show branch')),
3905 ('t', 'tags', None, _('show tags')),
3911 ('t', 'tags', None, _('show tags')),
3906 ('B', 'bookmarks', None, _('show bookmarks')),
3912 ('B', 'bookmarks', None, _('show bookmarks')),
3907 ] + remoteopts,
3913 ] + remoteopts,
3908 _('[-nibtB] [-r REV] [SOURCE]'),
3914 _('[-nibtB] [-r REV] [SOURCE]'),
3909 optionalrepo=True)
3915 optionalrepo=True)
3910 def identify(ui, repo, source=None, rev=None,
3916 def identify(ui, repo, source=None, rev=None,
3911 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
3917 num=None, id=None, branch=None, tags=None, bookmarks=None, **opts):
3912 """identify the working copy or specified revision
3918 """identify the working copy or specified revision
3913
3919
3914 Print a summary identifying the repository state at REV using one or
3920 Print a summary identifying the repository state at REV using one or
3915 two parent hash identifiers, followed by a "+" if the working
3921 two parent hash identifiers, followed by a "+" if the working
3916 directory has uncommitted changes, the branch name (if not default),
3922 directory has uncommitted changes, the branch name (if not default),
3917 a list of tags, and a list of bookmarks.
3923 a list of tags, and a list of bookmarks.
3918
3924
3919 When REV is not given, print a summary of the current state of the
3925 When REV is not given, print a summary of the current state of the
3920 repository.
3926 repository.
3921
3927
3922 Specifying a path to a repository root or Mercurial bundle will
3928 Specifying a path to a repository root or Mercurial bundle will
3923 cause lookup to operate on that repository/bundle.
3929 cause lookup to operate on that repository/bundle.
3924
3930
3925 .. container:: verbose
3931 .. container:: verbose
3926
3932
3927 Examples:
3933 Examples:
3928
3934
3929 - generate a build identifier for the working directory::
3935 - generate a build identifier for the working directory::
3930
3936
3931 hg id --id > build-id.dat
3937 hg id --id > build-id.dat
3932
3938
3933 - find the revision corresponding to a tag::
3939 - find the revision corresponding to a tag::
3934
3940
3935 hg id -n -r 1.3
3941 hg id -n -r 1.3
3936
3942
3937 - check the most recent revision of a remote repository::
3943 - check the most recent revision of a remote repository::
3938
3944
3939 hg id -r tip http://selenic.com/hg/
3945 hg id -r tip http://selenic.com/hg/
3940
3946
3941 Returns 0 if successful.
3947 Returns 0 if successful.
3942 """
3948 """
3943
3949
3944 if not repo and not source:
3950 if not repo and not source:
3945 raise util.Abort(_("there is no Mercurial repository here "
3951 raise util.Abort(_("there is no Mercurial repository here "
3946 "(.hg not found)"))
3952 "(.hg not found)"))
3947
3953
3948 hexfunc = ui.debugflag and hex or short
3954 hexfunc = ui.debugflag and hex or short
3949 default = not (num or id or branch or tags or bookmarks)
3955 default = not (num or id or branch or tags or bookmarks)
3950 output = []
3956 output = []
3951 revs = []
3957 revs = []
3952
3958
3953 if source:
3959 if source:
3954 source, branches = hg.parseurl(ui.expandpath(source))
3960 source, branches = hg.parseurl(ui.expandpath(source))
3955 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
3961 peer = hg.peer(repo or ui, opts, source) # only pass ui when no repo
3956 repo = peer.local()
3962 repo = peer.local()
3957 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
3963 revs, checkout = hg.addbranchrevs(repo, peer, branches, None)
3958
3964
3959 if not repo:
3965 if not repo:
3960 if num or branch or tags:
3966 if num or branch or tags:
3961 raise util.Abort(
3967 raise util.Abort(
3962 _("can't query remote revision number, branch, or tags"))
3968 _("can't query remote revision number, branch, or tags"))
3963 if not rev and revs:
3969 if not rev and revs:
3964 rev = revs[0]
3970 rev = revs[0]
3965 if not rev:
3971 if not rev:
3966 rev = "tip"
3972 rev = "tip"
3967
3973
3968 remoterev = peer.lookup(rev)
3974 remoterev = peer.lookup(rev)
3969 if default or id:
3975 if default or id:
3970 output = [hexfunc(remoterev)]
3976 output = [hexfunc(remoterev)]
3971
3977
3972 def getbms():
3978 def getbms():
3973 bms = []
3979 bms = []
3974
3980
3975 if 'bookmarks' in peer.listkeys('namespaces'):
3981 if 'bookmarks' in peer.listkeys('namespaces'):
3976 hexremoterev = hex(remoterev)
3982 hexremoterev = hex(remoterev)
3977 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
3983 bms = [bm for bm, bmr in peer.listkeys('bookmarks').iteritems()
3978 if bmr == hexremoterev]
3984 if bmr == hexremoterev]
3979
3985
3980 return sorted(bms)
3986 return sorted(bms)
3981
3987
3982 if bookmarks:
3988 if bookmarks:
3983 output.extend(getbms())
3989 output.extend(getbms())
3984 elif default and not ui.quiet:
3990 elif default and not ui.quiet:
3985 # multiple bookmarks for a single parent separated by '/'
3991 # multiple bookmarks for a single parent separated by '/'
3986 bm = '/'.join(getbms())
3992 bm = '/'.join(getbms())
3987 if bm:
3993 if bm:
3988 output.append(bm)
3994 output.append(bm)
3989 else:
3995 else:
3990 if not rev:
3996 if not rev:
3991 ctx = repo[None]
3997 ctx = repo[None]
3992 parents = ctx.parents()
3998 parents = ctx.parents()
3993 changed = ""
3999 changed = ""
3994 if default or id or num:
4000 if default or id or num:
3995 if (util.any(repo.status())
4001 if (util.any(repo.status())
3996 or util.any(ctx.sub(s).dirty() for s in ctx.substate)):
4002 or util.any(ctx.sub(s).dirty() for s in ctx.substate)):
3997 changed = '+'
4003 changed = '+'
3998 if default or id:
4004 if default or id:
3999 output = ["%s%s" %
4005 output = ["%s%s" %
4000 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
4006 ('+'.join([hexfunc(p.node()) for p in parents]), changed)]
4001 if num:
4007 if num:
4002 output.append("%s%s" %
4008 output.append("%s%s" %
4003 ('+'.join([str(p.rev()) for p in parents]), changed))
4009 ('+'.join([str(p.rev()) for p in parents]), changed))
4004 else:
4010 else:
4005 ctx = scmutil.revsingle(repo, rev)
4011 ctx = scmutil.revsingle(repo, rev)
4006 if default or id:
4012 if default or id:
4007 output = [hexfunc(ctx.node())]
4013 output = [hexfunc(ctx.node())]
4008 if num:
4014 if num:
4009 output.append(str(ctx.rev()))
4015 output.append(str(ctx.rev()))
4010
4016
4011 if default and not ui.quiet:
4017 if default and not ui.quiet:
4012 b = ctx.branch()
4018 b = ctx.branch()
4013 if b != 'default':
4019 if b != 'default':
4014 output.append("(%s)" % b)
4020 output.append("(%s)" % b)
4015
4021
4016 # multiple tags for a single parent separated by '/'
4022 # multiple tags for a single parent separated by '/'
4017 t = '/'.join(ctx.tags())
4023 t = '/'.join(ctx.tags())
4018 if t:
4024 if t:
4019 output.append(t)
4025 output.append(t)
4020
4026
4021 # multiple bookmarks for a single parent separated by '/'
4027 # multiple bookmarks for a single parent separated by '/'
4022 bm = '/'.join(ctx.bookmarks())
4028 bm = '/'.join(ctx.bookmarks())
4023 if bm:
4029 if bm:
4024 output.append(bm)
4030 output.append(bm)
4025 else:
4031 else:
4026 if branch:
4032 if branch:
4027 output.append(ctx.branch())
4033 output.append(ctx.branch())
4028
4034
4029 if tags:
4035 if tags:
4030 output.extend(ctx.tags())
4036 output.extend(ctx.tags())
4031
4037
4032 if bookmarks:
4038 if bookmarks:
4033 output.extend(ctx.bookmarks())
4039 output.extend(ctx.bookmarks())
4034
4040
4035 ui.write("%s\n" % ' '.join(output))
4041 ui.write("%s\n" % ' '.join(output))
4036
4042
4037 @command('import|patch',
4043 @command('import|patch',
4038 [('p', 'strip', 1,
4044 [('p', 'strip', 1,
4039 _('directory strip option for patch. This has the same '
4045 _('directory strip option for patch. This has the same '
4040 'meaning as the corresponding patch option'), _('NUM')),
4046 'meaning as the corresponding patch option'), _('NUM')),
4041 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
4047 ('b', 'base', '', _('base path (DEPRECATED)'), _('PATH')),
4042 ('e', 'edit', False, _('invoke editor on commit messages')),
4048 ('e', 'edit', False, _('invoke editor on commit messages')),
4043 ('f', 'force', None,
4049 ('f', 'force', None,
4044 _('skip check for outstanding uncommitted changes (DEPRECATED)')),
4050 _('skip check for outstanding uncommitted changes (DEPRECATED)')),
4045 ('', 'no-commit', None,
4051 ('', 'no-commit', None,
4046 _("don't commit, just update the working directory")),
4052 _("don't commit, just update the working directory")),
4047 ('', 'bypass', None,
4053 ('', 'bypass', None,
4048 _("apply patch without touching the working directory")),
4054 _("apply patch without touching the working directory")),
4049 ('', 'partial', None,
4055 ('', 'partial', None,
4050 _('commit even if some hunks fail')),
4056 _('commit even if some hunks fail')),
4051 ('', 'exact', None,
4057 ('', 'exact', None,
4052 _('apply patch to the nodes from which it was generated')),
4058 _('apply patch to the nodes from which it was generated')),
4053 ('', 'import-branch', None,
4059 ('', 'import-branch', None,
4054 _('use any branch information in patch (implied by --exact)'))] +
4060 _('use any branch information in patch (implied by --exact)'))] +
4055 commitopts + commitopts2 + similarityopts,
4061 commitopts + commitopts2 + similarityopts,
4056 _('[OPTION]... PATCH...'))
4062 _('[OPTION]... PATCH...'))
4057 def import_(ui, repo, patch1=None, *patches, **opts):
4063 def import_(ui, repo, patch1=None, *patches, **opts):
4058 """import an ordered set of patches
4064 """import an ordered set of patches
4059
4065
4060 Import a list of patches and commit them individually (unless
4066 Import a list of patches and commit them individually (unless
4061 --no-commit is specified).
4067 --no-commit is specified).
4062
4068
4063 Because import first applies changes to the working directory,
4069 Because import first applies changes to the working directory,
4064 import will abort if there are outstanding changes.
4070 import will abort if there are outstanding changes.
4065
4071
4066 You can import a patch straight from a mail message. Even patches
4072 You can import a patch straight from a mail message. Even patches
4067 as attachments work (to use the body part, it must have type
4073 as attachments work (to use the body part, it must have type
4068 text/plain or text/x-patch). From and Subject headers of email
4074 text/plain or text/x-patch). From and Subject headers of email
4069 message are used as default committer and commit message. All
4075 message are used as default committer and commit message. All
4070 text/plain body parts before first diff are added to commit
4076 text/plain body parts before first diff are added to commit
4071 message.
4077 message.
4072
4078
4073 If the imported patch was generated by :hg:`export`, user and
4079 If the imported patch was generated by :hg:`export`, user and
4074 description from patch override values from message headers and
4080 description from patch override values from message headers and
4075 body. Values given on command line with -m/--message and -u/--user
4081 body. Values given on command line with -m/--message and -u/--user
4076 override these.
4082 override these.
4077
4083
4078 If --exact is specified, import will set the working directory to
4084 If --exact is specified, import will set the working directory to
4079 the parent of each patch before applying it, and will abort if the
4085 the parent of each patch before applying it, and will abort if the
4080 resulting changeset has a different ID than the one recorded in
4086 resulting changeset has a different ID than the one recorded in
4081 the patch. This may happen due to character set problems or other
4087 the patch. This may happen due to character set problems or other
4082 deficiencies in the text patch format.
4088 deficiencies in the text patch format.
4083
4089
4084 Use --bypass to apply and commit patches directly to the
4090 Use --bypass to apply and commit patches directly to the
4085 repository, not touching the working directory. Without --exact,
4091 repository, not touching the working directory. Without --exact,
4086 patches will be applied on top of the working directory parent
4092 patches will be applied on top of the working directory parent
4087 revision.
4093 revision.
4088
4094
4089 With -s/--similarity, hg will attempt to discover renames and
4095 With -s/--similarity, hg will attempt to discover renames and
4090 copies in the patch in the same way as :hg:`addremove`.
4096 copies in the patch in the same way as :hg:`addremove`.
4091
4097
4092 Use --partial to ensure a changeset will be created from the patch
4098 Use --partial to ensure a changeset will be created from the patch
4093 even if some hunks fail to apply. Hunks that fail to apply will be
4099 even if some hunks fail to apply. Hunks that fail to apply will be
4094 written to a <target-file>.rej file. Conflicts can then be resolved
4100 written to a <target-file>.rej file. Conflicts can then be resolved
4095 by hand before :hg:`commit --amend` is run to update the created
4101 by hand before :hg:`commit --amend` is run to update the created
4096 changeset. This flag exists to let people import patches that
4102 changeset. This flag exists to let people import patches that
4097 partially apply without losing the associated metadata (author,
4103 partially apply without losing the associated metadata (author,
4098 date, description, ...). Note that when none of the hunk applies
4104 date, description, ...). Note that when none of the hunk applies
4099 cleanly, :hg:`import --partial` will create an empty changeset,
4105 cleanly, :hg:`import --partial` will create an empty changeset,
4100 importing only the patch metadata.
4106 importing only the patch metadata.
4101
4107
4102 To read a patch from standard input, use "-" as the patch name. If
4108 To read a patch from standard input, use "-" as the patch name. If
4103 a URL is specified, the patch will be downloaded from it.
4109 a URL is specified, the patch will be downloaded from it.
4104 See :hg:`help dates` for a list of formats valid for -d/--date.
4110 See :hg:`help dates` for a list of formats valid for -d/--date.
4105
4111
4106 .. container:: verbose
4112 .. container:: verbose
4107
4113
4108 Examples:
4114 Examples:
4109
4115
4110 - import a traditional patch from a website and detect renames::
4116 - import a traditional patch from a website and detect renames::
4111
4117
4112 hg import -s 80 http://example.com/bugfix.patch
4118 hg import -s 80 http://example.com/bugfix.patch
4113
4119
4114 - import a changeset from an hgweb server::
4120 - import a changeset from an hgweb server::
4115
4121
4116 hg import http://www.selenic.com/hg/rev/5ca8c111e9aa
4122 hg import http://www.selenic.com/hg/rev/5ca8c111e9aa
4117
4123
4118 - import all the patches in an Unix-style mbox::
4124 - import all the patches in an Unix-style mbox::
4119
4125
4120 hg import incoming-patches.mbox
4126 hg import incoming-patches.mbox
4121
4127
4122 - attempt to exactly restore an exported changeset (not always
4128 - attempt to exactly restore an exported changeset (not always
4123 possible)::
4129 possible)::
4124
4130
4125 hg import --exact proposed-fix.patch
4131 hg import --exact proposed-fix.patch
4126
4132
4127 Returns 0 on success, 1 on partial success (see --partial).
4133 Returns 0 on success, 1 on partial success (see --partial).
4128 """
4134 """
4129
4135
4130 if not patch1:
4136 if not patch1:
4131 raise util.Abort(_('need at least one patch to import'))
4137 raise util.Abort(_('need at least one patch to import'))
4132
4138
4133 patches = (patch1,) + patches
4139 patches = (patch1,) + patches
4134
4140
4135 date = opts.get('date')
4141 date = opts.get('date')
4136 if date:
4142 if date:
4137 opts['date'] = util.parsedate(date)
4143 opts['date'] = util.parsedate(date)
4138
4144
4139 update = not opts.get('bypass')
4145 update = not opts.get('bypass')
4140 if not update and opts.get('no_commit'):
4146 if not update and opts.get('no_commit'):
4141 raise util.Abort(_('cannot use --no-commit with --bypass'))
4147 raise util.Abort(_('cannot use --no-commit with --bypass'))
4142 try:
4148 try:
4143 sim = float(opts.get('similarity') or 0)
4149 sim = float(opts.get('similarity') or 0)
4144 except ValueError:
4150 except ValueError:
4145 raise util.Abort(_('similarity must be a number'))
4151 raise util.Abort(_('similarity must be a number'))
4146 if sim < 0 or sim > 100:
4152 if sim < 0 or sim > 100:
4147 raise util.Abort(_('similarity must be between 0 and 100'))
4153 raise util.Abort(_('similarity must be between 0 and 100'))
4148 if sim and not update:
4154 if sim and not update:
4149 raise util.Abort(_('cannot use --similarity with --bypass'))
4155 raise util.Abort(_('cannot use --similarity with --bypass'))
4150 if opts.get('exact') and opts.get('edit'):
4156 if opts.get('exact') and opts.get('edit'):
4151 raise util.Abort(_('cannot use --exact with --edit'))
4157 raise util.Abort(_('cannot use --exact with --edit'))
4152
4158
4153 if update:
4159 if update:
4154 cmdutil.checkunfinished(repo)
4160 cmdutil.checkunfinished(repo)
4155 if (opts.get('exact') or not opts.get('force')) and update:
4161 if (opts.get('exact') or not opts.get('force')) and update:
4156 cmdutil.bailifchanged(repo)
4162 cmdutil.bailifchanged(repo)
4157
4163
4158 base = opts["base"]
4164 base = opts["base"]
4159 wlock = lock = tr = None
4165 wlock = lock = tr = None
4160 msgs = []
4166 msgs = []
4161 ret = 0
4167 ret = 0
4162
4168
4163
4169
4164 try:
4170 try:
4165 try:
4171 try:
4166 wlock = repo.wlock()
4172 wlock = repo.wlock()
4167 repo.dirstate.beginparentchange()
4173 repo.dirstate.beginparentchange()
4168 if not opts.get('no_commit'):
4174 if not opts.get('no_commit'):
4169 lock = repo.lock()
4175 lock = repo.lock()
4170 tr = repo.transaction('import')
4176 tr = repo.transaction('import')
4171 parents = repo.parents()
4177 parents = repo.parents()
4172 for patchurl in patches:
4178 for patchurl in patches:
4173 if patchurl == '-':
4179 if patchurl == '-':
4174 ui.status(_('applying patch from stdin\n'))
4180 ui.status(_('applying patch from stdin\n'))
4175 patchfile = ui.fin
4181 patchfile = ui.fin
4176 patchurl = 'stdin' # for error message
4182 patchurl = 'stdin' # for error message
4177 else:
4183 else:
4178 patchurl = os.path.join(base, patchurl)
4184 patchurl = os.path.join(base, patchurl)
4179 ui.status(_('applying %s\n') % patchurl)
4185 ui.status(_('applying %s\n') % patchurl)
4180 patchfile = hg.openpath(ui, patchurl)
4186 patchfile = hg.openpath(ui, patchurl)
4181
4187
4182 haspatch = False
4188 haspatch = False
4183 for hunk in patch.split(patchfile):
4189 for hunk in patch.split(patchfile):
4184 (msg, node, rej) = cmdutil.tryimportone(ui, repo, hunk,
4190 (msg, node, rej) = cmdutil.tryimportone(ui, repo, hunk,
4185 parents, opts,
4191 parents, opts,
4186 msgs, hg.clean)
4192 msgs, hg.clean)
4187 if msg:
4193 if msg:
4188 haspatch = True
4194 haspatch = True
4189 ui.note(msg + '\n')
4195 ui.note(msg + '\n')
4190 if update or opts.get('exact'):
4196 if update or opts.get('exact'):
4191 parents = repo.parents()
4197 parents = repo.parents()
4192 else:
4198 else:
4193 parents = [repo[node]]
4199 parents = [repo[node]]
4194 if rej:
4200 if rej:
4195 ui.write_err(_("patch applied partially\n"))
4201 ui.write_err(_("patch applied partially\n"))
4196 ui.write_err(_("(fix the .rej files and run "
4202 ui.write_err(_("(fix the .rej files and run "
4197 "`hg commit --amend`)\n"))
4203 "`hg commit --amend`)\n"))
4198 ret = 1
4204 ret = 1
4199 break
4205 break
4200
4206
4201 if not haspatch:
4207 if not haspatch:
4202 raise util.Abort(_('%s: no diffs found') % patchurl)
4208 raise util.Abort(_('%s: no diffs found') % patchurl)
4203
4209
4204 if tr:
4210 if tr:
4205 tr.close()
4211 tr.close()
4206 if msgs:
4212 if msgs:
4207 repo.savecommitmessage('\n* * *\n'.join(msgs))
4213 repo.savecommitmessage('\n* * *\n'.join(msgs))
4208 repo.dirstate.endparentchange()
4214 repo.dirstate.endparentchange()
4209 return ret
4215 return ret
4210 except: # re-raises
4216 except: # re-raises
4211 # wlock.release() indirectly calls dirstate.write(): since
4217 # wlock.release() indirectly calls dirstate.write(): since
4212 # we're crashing, we do not want to change the working dir
4218 # we're crashing, we do not want to change the working dir
4213 # parent after all, so make sure it writes nothing
4219 # parent after all, so make sure it writes nothing
4214 repo.dirstate.invalidate()
4220 repo.dirstate.invalidate()
4215 raise
4221 raise
4216 finally:
4222 finally:
4217 if tr:
4223 if tr:
4218 tr.release()
4224 tr.release()
4219 release(lock, wlock)
4225 release(lock, wlock)
4220
4226
4221 @command('incoming|in',
4227 @command('incoming|in',
4222 [('f', 'force', None,
4228 [('f', 'force', None,
4223 _('run even if remote repository is unrelated')),
4229 _('run even if remote repository is unrelated')),
4224 ('n', 'newest-first', None, _('show newest record first')),
4230 ('n', 'newest-first', None, _('show newest record first')),
4225 ('', 'bundle', '',
4231 ('', 'bundle', '',
4226 _('file to store the bundles into'), _('FILE')),
4232 _('file to store the bundles into'), _('FILE')),
4227 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
4233 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
4228 ('B', 'bookmarks', False, _("compare bookmarks")),
4234 ('B', 'bookmarks', False, _("compare bookmarks")),
4229 ('b', 'branch', [],
4235 ('b', 'branch', [],
4230 _('a specific branch you would like to pull'), _('BRANCH')),
4236 _('a specific branch you would like to pull'), _('BRANCH')),
4231 ] + logopts + remoteopts + subrepoopts,
4237 ] + logopts + remoteopts + subrepoopts,
4232 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
4238 _('[-p] [-n] [-M] [-f] [-r REV]... [--bundle FILENAME] [SOURCE]'))
4233 def incoming(ui, repo, source="default", **opts):
4239 def incoming(ui, repo, source="default", **opts):
4234 """show new changesets found in source
4240 """show new changesets found in source
4235
4241
4236 Show new changesets found in the specified path/URL or the default
4242 Show new changesets found in the specified path/URL or the default
4237 pull location. These are the changesets that would have been pulled
4243 pull location. These are the changesets that would have been pulled
4238 if a pull at the time you issued this command.
4244 if a pull at the time you issued this command.
4239
4245
4240 For remote repository, using --bundle avoids downloading the
4246 For remote repository, using --bundle avoids downloading the
4241 changesets twice if the incoming is followed by a pull.
4247 changesets twice if the incoming is followed by a pull.
4242
4248
4243 See pull for valid source format details.
4249 See pull for valid source format details.
4244
4250
4245 .. container:: verbose
4251 .. container:: verbose
4246
4252
4247 Examples:
4253 Examples:
4248
4254
4249 - show incoming changes with patches and full description::
4255 - show incoming changes with patches and full description::
4250
4256
4251 hg incoming -vp
4257 hg incoming -vp
4252
4258
4253 - show incoming changes excluding merges, store a bundle::
4259 - show incoming changes excluding merges, store a bundle::
4254
4260
4255 hg in -vpM --bundle incoming.hg
4261 hg in -vpM --bundle incoming.hg
4256 hg pull incoming.hg
4262 hg pull incoming.hg
4257
4263
4258 - briefly list changes inside a bundle::
4264 - briefly list changes inside a bundle::
4259
4265
4260 hg in changes.hg -T "{desc|firstline}\\n"
4266 hg in changes.hg -T "{desc|firstline}\\n"
4261
4267
4262 Returns 0 if there are incoming changes, 1 otherwise.
4268 Returns 0 if there are incoming changes, 1 otherwise.
4263 """
4269 """
4264 if opts.get('graph'):
4270 if opts.get('graph'):
4265 cmdutil.checkunsupportedgraphflags([], opts)
4271 cmdutil.checkunsupportedgraphflags([], opts)
4266 def display(other, chlist, displayer):
4272 def display(other, chlist, displayer):
4267 revdag = cmdutil.graphrevs(other, chlist, opts)
4273 revdag = cmdutil.graphrevs(other, chlist, opts)
4268 showparents = [ctx.node() for ctx in repo[None].parents()]
4274 showparents = [ctx.node() for ctx in repo[None].parents()]
4269 cmdutil.displaygraph(ui, revdag, displayer, showparents,
4275 cmdutil.displaygraph(ui, revdag, displayer, showparents,
4270 graphmod.asciiedges)
4276 graphmod.asciiedges)
4271
4277
4272 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
4278 hg._incoming(display, lambda: 1, ui, repo, source, opts, buffered=True)
4273 return 0
4279 return 0
4274
4280
4275 if opts.get('bundle') and opts.get('subrepos'):
4281 if opts.get('bundle') and opts.get('subrepos'):
4276 raise util.Abort(_('cannot combine --bundle and --subrepos'))
4282 raise util.Abort(_('cannot combine --bundle and --subrepos'))
4277
4283
4278 if opts.get('bookmarks'):
4284 if opts.get('bookmarks'):
4279 source, branches = hg.parseurl(ui.expandpath(source),
4285 source, branches = hg.parseurl(ui.expandpath(source),
4280 opts.get('branch'))
4286 opts.get('branch'))
4281 other = hg.peer(repo, opts, source)
4287 other = hg.peer(repo, opts, source)
4282 if 'bookmarks' not in other.listkeys('namespaces'):
4288 if 'bookmarks' not in other.listkeys('namespaces'):
4283 ui.warn(_("remote doesn't support bookmarks\n"))
4289 ui.warn(_("remote doesn't support bookmarks\n"))
4284 return 0
4290 return 0
4285 ui.status(_('comparing with %s\n') % util.hidepassword(source))
4291 ui.status(_('comparing with %s\n') % util.hidepassword(source))
4286 return bookmarks.diff(ui, repo, other)
4292 return bookmarks.diff(ui, repo, other)
4287
4293
4288 repo._subtoppath = ui.expandpath(source)
4294 repo._subtoppath = ui.expandpath(source)
4289 try:
4295 try:
4290 return hg.incoming(ui, repo, source, opts)
4296 return hg.incoming(ui, repo, source, opts)
4291 finally:
4297 finally:
4292 del repo._subtoppath
4298 del repo._subtoppath
4293
4299
4294
4300
4295 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'),
4301 @command('^init', remoteopts, _('[-e CMD] [--remotecmd CMD] [DEST]'),
4296 norepo=True)
4302 norepo=True)
4297 def init(ui, dest=".", **opts):
4303 def init(ui, dest=".", **opts):
4298 """create a new repository in the given directory
4304 """create a new repository in the given directory
4299
4305
4300 Initialize a new repository in the given directory. If the given
4306 Initialize a new repository in the given directory. If the given
4301 directory does not exist, it will be created.
4307 directory does not exist, it will be created.
4302
4308
4303 If no directory is given, the current directory is used.
4309 If no directory is given, the current directory is used.
4304
4310
4305 It is possible to specify an ``ssh://`` URL as the destination.
4311 It is possible to specify an ``ssh://`` URL as the destination.
4306 See :hg:`help urls` for more information.
4312 See :hg:`help urls` for more information.
4307
4313
4308 Returns 0 on success.
4314 Returns 0 on success.
4309 """
4315 """
4310 hg.peer(ui, opts, ui.expandpath(dest), create=True)
4316 hg.peer(ui, opts, ui.expandpath(dest), create=True)
4311
4317
4312 @command('locate',
4318 @command('locate',
4313 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
4319 [('r', 'rev', '', _('search the repository as it is in REV'), _('REV')),
4314 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
4320 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
4315 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
4321 ('f', 'fullpath', None, _('print complete paths from the filesystem root')),
4316 ] + walkopts,
4322 ] + walkopts,
4317 _('[OPTION]... [PATTERN]...'))
4323 _('[OPTION]... [PATTERN]...'))
4318 def locate(ui, repo, *pats, **opts):
4324 def locate(ui, repo, *pats, **opts):
4319 """locate files matching specific patterns (DEPRECATED)
4325 """locate files matching specific patterns (DEPRECATED)
4320
4326
4321 Print files under Mercurial control in the working directory whose
4327 Print files under Mercurial control in the working directory whose
4322 names match the given patterns.
4328 names match the given patterns.
4323
4329
4324 By default, this command searches all directories in the working
4330 By default, this command searches all directories in the working
4325 directory. To search just the current directory and its
4331 directory. To search just the current directory and its
4326 subdirectories, use "--include .".
4332 subdirectories, use "--include .".
4327
4333
4328 If no patterns are given to match, this command prints the names
4334 If no patterns are given to match, this command prints the names
4329 of all files under Mercurial control in the working directory.
4335 of all files under Mercurial control in the working directory.
4330
4336
4331 If you want to feed the output of this command into the "xargs"
4337 If you want to feed the output of this command into the "xargs"
4332 command, use the -0 option to both this command and "xargs". This
4338 command, use the -0 option to both this command and "xargs". This
4333 will avoid the problem of "xargs" treating single filenames that
4339 will avoid the problem of "xargs" treating single filenames that
4334 contain whitespace as multiple filenames.
4340 contain whitespace as multiple filenames.
4335
4341
4336 See :hg:`help files` for a more versatile command.
4342 See :hg:`help files` for a more versatile command.
4337
4343
4338 Returns 0 if a match is found, 1 otherwise.
4344 Returns 0 if a match is found, 1 otherwise.
4339 """
4345 """
4340 end = opts.get('print0') and '\0' or '\n'
4346 end = opts.get('print0') and '\0' or '\n'
4341 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
4347 rev = scmutil.revsingle(repo, opts.get('rev'), None).node()
4342
4348
4343 ret = 1
4349 ret = 1
4344 ctx = repo[rev]
4350 ctx = repo[rev]
4345 m = scmutil.match(ctx, pats, opts, default='relglob')
4351 m = scmutil.match(ctx, pats, opts, default='relglob')
4346 m.bad = lambda x, y: False
4352 m.bad = lambda x, y: False
4347
4353
4348 for abs in ctx.matches(m):
4354 for abs in ctx.matches(m):
4349 if opts.get('fullpath'):
4355 if opts.get('fullpath'):
4350 ui.write(repo.wjoin(abs), end)
4356 ui.write(repo.wjoin(abs), end)
4351 else:
4357 else:
4352 ui.write(((pats and m.rel(abs)) or abs), end)
4358 ui.write(((pats and m.rel(abs)) or abs), end)
4353 ret = 0
4359 ret = 0
4354
4360
4355 return ret
4361 return ret
4356
4362
4357 @command('^log|history',
4363 @command('^log|history',
4358 [('f', 'follow', None,
4364 [('f', 'follow', None,
4359 _('follow changeset history, or file history across copies and renames')),
4365 _('follow changeset history, or file history across copies and renames')),
4360 ('', 'follow-first', None,
4366 ('', 'follow-first', None,
4361 _('only follow the first parent of merge changesets (DEPRECATED)')),
4367 _('only follow the first parent of merge changesets (DEPRECATED)')),
4362 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
4368 ('d', 'date', '', _('show revisions matching date spec'), _('DATE')),
4363 ('C', 'copies', None, _('show copied files')),
4369 ('C', 'copies', None, _('show copied files')),
4364 ('k', 'keyword', [],
4370 ('k', 'keyword', [],
4365 _('do case-insensitive search for a given text'), _('TEXT')),
4371 _('do case-insensitive search for a given text'), _('TEXT')),
4366 ('r', 'rev', [], _('show the specified revision or revset'), _('REV')),
4372 ('r', 'rev', [], _('show the specified revision or revset'), _('REV')),
4367 ('', 'removed', None, _('include revisions where files were removed')),
4373 ('', 'removed', None, _('include revisions where files were removed')),
4368 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
4374 ('m', 'only-merges', None, _('show only merges (DEPRECATED)')),
4369 ('u', 'user', [], _('revisions committed by user'), _('USER')),
4375 ('u', 'user', [], _('revisions committed by user'), _('USER')),
4370 ('', 'only-branch', [],
4376 ('', 'only-branch', [],
4371 _('show only changesets within the given named branch (DEPRECATED)'),
4377 _('show only changesets within the given named branch (DEPRECATED)'),
4372 _('BRANCH')),
4378 _('BRANCH')),
4373 ('b', 'branch', [],
4379 ('b', 'branch', [],
4374 _('show changesets within the given named branch'), _('BRANCH')),
4380 _('show changesets within the given named branch'), _('BRANCH')),
4375 ('P', 'prune', [],
4381 ('P', 'prune', [],
4376 _('do not display revision or any of its ancestors'), _('REV')),
4382 _('do not display revision or any of its ancestors'), _('REV')),
4377 ] + logopts + walkopts,
4383 ] + logopts + walkopts,
4378 _('[OPTION]... [FILE]'),
4384 _('[OPTION]... [FILE]'),
4379 inferrepo=True)
4385 inferrepo=True)
4380 def log(ui, repo, *pats, **opts):
4386 def log(ui, repo, *pats, **opts):
4381 """show revision history of entire repository or files
4387 """show revision history of entire repository or files
4382
4388
4383 Print the revision history of the specified files or the entire
4389 Print the revision history of the specified files or the entire
4384 project.
4390 project.
4385
4391
4386 If no revision range is specified, the default is ``tip:0`` unless
4392 If no revision range is specified, the default is ``tip:0`` unless
4387 --follow is set, in which case the working directory parent is
4393 --follow is set, in which case the working directory parent is
4388 used as the starting revision.
4394 used as the starting revision.
4389
4395
4390 File history is shown without following rename or copy history of
4396 File history is shown without following rename or copy history of
4391 files. Use -f/--follow with a filename to follow history across
4397 files. Use -f/--follow with a filename to follow history across
4392 renames and copies. --follow without a filename will only show
4398 renames and copies. --follow without a filename will only show
4393 ancestors or descendants of the starting revision.
4399 ancestors or descendants of the starting revision.
4394
4400
4395 By default this command prints revision number and changeset id,
4401 By default this command prints revision number and changeset id,
4396 tags, non-trivial parents, user, date and time, and a summary for
4402 tags, non-trivial parents, user, date and time, and a summary for
4397 each commit. When the -v/--verbose switch is used, the list of
4403 each commit. When the -v/--verbose switch is used, the list of
4398 changed files and full commit message are shown.
4404 changed files and full commit message are shown.
4399
4405
4400 With --graph the revisions are shown as an ASCII art DAG with the most
4406 With --graph the revisions are shown as an ASCII art DAG with the most
4401 recent changeset at the top.
4407 recent changeset at the top.
4402 'o' is a changeset, '@' is a working directory parent, 'x' is obsolete,
4408 'o' is a changeset, '@' is a working directory parent, 'x' is obsolete,
4403 and '+' represents a fork where the changeset from the lines below is a
4409 and '+' represents a fork where the changeset from the lines below is a
4404 parent of the 'o' merge on the same line.
4410 parent of the 'o' merge on the same line.
4405
4411
4406 .. note::
4412 .. note::
4407
4413
4408 log -p/--patch may generate unexpected diff output for merge
4414 log -p/--patch may generate unexpected diff output for merge
4409 changesets, as it will only compare the merge changeset against
4415 changesets, as it will only compare the merge changeset against
4410 its first parent. Also, only files different from BOTH parents
4416 its first parent. Also, only files different from BOTH parents
4411 will appear in files:.
4417 will appear in files:.
4412
4418
4413 .. note::
4419 .. note::
4414
4420
4415 for performance reasons, log FILE may omit duplicate changes
4421 for performance reasons, log FILE may omit duplicate changes
4416 made on branches and will not show removals or mode changes. To
4422 made on branches and will not show removals or mode changes. To
4417 see all such changes, use the --removed switch.
4423 see all such changes, use the --removed switch.
4418
4424
4419 .. container:: verbose
4425 .. container:: verbose
4420
4426
4421 Some examples:
4427 Some examples:
4422
4428
4423 - changesets with full descriptions and file lists::
4429 - changesets with full descriptions and file lists::
4424
4430
4425 hg log -v
4431 hg log -v
4426
4432
4427 - changesets ancestral to the working directory::
4433 - changesets ancestral to the working directory::
4428
4434
4429 hg log -f
4435 hg log -f
4430
4436
4431 - last 10 commits on the current branch::
4437 - last 10 commits on the current branch::
4432
4438
4433 hg log -l 10 -b .
4439 hg log -l 10 -b .
4434
4440
4435 - changesets showing all modifications of a file, including removals::
4441 - changesets showing all modifications of a file, including removals::
4436
4442
4437 hg log --removed file.c
4443 hg log --removed file.c
4438
4444
4439 - all changesets that touch a directory, with diffs, excluding merges::
4445 - all changesets that touch a directory, with diffs, excluding merges::
4440
4446
4441 hg log -Mp lib/
4447 hg log -Mp lib/
4442
4448
4443 - all revision numbers that match a keyword::
4449 - all revision numbers that match a keyword::
4444
4450
4445 hg log -k bug --template "{rev}\\n"
4451 hg log -k bug --template "{rev}\\n"
4446
4452
4447 - list available log templates::
4453 - list available log templates::
4448
4454
4449 hg log -T list
4455 hg log -T list
4450
4456
4451 - check if a given changeset is included in a tagged release::
4457 - check if a given changeset is included in a tagged release::
4452
4458
4453 hg log -r "a21ccf and ancestor(1.9)"
4459 hg log -r "a21ccf and ancestor(1.9)"
4454
4460
4455 - find all changesets by some user in a date range::
4461 - find all changesets by some user in a date range::
4456
4462
4457 hg log -k alice -d "may 2008 to jul 2008"
4463 hg log -k alice -d "may 2008 to jul 2008"
4458
4464
4459 - summary of all changesets after the last tag::
4465 - summary of all changesets after the last tag::
4460
4466
4461 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
4467 hg log -r "last(tagged())::" --template "{desc|firstline}\\n"
4462
4468
4463 See :hg:`help dates` for a list of formats valid for -d/--date.
4469 See :hg:`help dates` for a list of formats valid for -d/--date.
4464
4470
4465 See :hg:`help revisions` and :hg:`help revsets` for more about
4471 See :hg:`help revisions` and :hg:`help revsets` for more about
4466 specifying revisions.
4472 specifying revisions.
4467
4473
4468 See :hg:`help templates` for more about pre-packaged styles and
4474 See :hg:`help templates` for more about pre-packaged styles and
4469 specifying custom templates.
4475 specifying custom templates.
4470
4476
4471 Returns 0 on success.
4477 Returns 0 on success.
4472
4478
4473 """
4479 """
4474 if opts.get('graph'):
4480 if opts.get('graph'):
4475 return cmdutil.graphlog(ui, repo, *pats, **opts)
4481 return cmdutil.graphlog(ui, repo, *pats, **opts)
4476
4482
4477 revs, expr, filematcher = cmdutil.getlogrevs(repo, pats, opts)
4483 revs, expr, filematcher = cmdutil.getlogrevs(repo, pats, opts)
4478 limit = cmdutil.loglimit(opts)
4484 limit = cmdutil.loglimit(opts)
4479 count = 0
4485 count = 0
4480
4486
4481 getrenamed = None
4487 getrenamed = None
4482 if opts.get('copies'):
4488 if opts.get('copies'):
4483 endrev = None
4489 endrev = None
4484 if opts.get('rev'):
4490 if opts.get('rev'):
4485 endrev = scmutil.revrange(repo, opts.get('rev')).max() + 1
4491 endrev = scmutil.revrange(repo, opts.get('rev')).max() + 1
4486 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
4492 getrenamed = templatekw.getrenamedfn(repo, endrev=endrev)
4487
4493
4488 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
4494 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
4489 for rev in revs:
4495 for rev in revs:
4490 if count == limit:
4496 if count == limit:
4491 break
4497 break
4492 ctx = repo[rev]
4498 ctx = repo[rev]
4493 copies = None
4499 copies = None
4494 if getrenamed is not None and rev:
4500 if getrenamed is not None and rev:
4495 copies = []
4501 copies = []
4496 for fn in ctx.files():
4502 for fn in ctx.files():
4497 rename = getrenamed(fn, rev)
4503 rename = getrenamed(fn, rev)
4498 if rename:
4504 if rename:
4499 copies.append((fn, rename[0]))
4505 copies.append((fn, rename[0]))
4500 revmatchfn = filematcher and filematcher(ctx.rev()) or None
4506 revmatchfn = filematcher and filematcher(ctx.rev()) or None
4501 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
4507 displayer.show(ctx, copies=copies, matchfn=revmatchfn)
4502 if displayer.flush(rev):
4508 if displayer.flush(rev):
4503 count += 1
4509 count += 1
4504
4510
4505 displayer.close()
4511 displayer.close()
4506
4512
4507 @command('manifest',
4513 @command('manifest',
4508 [('r', 'rev', '', _('revision to display'), _('REV')),
4514 [('r', 'rev', '', _('revision to display'), _('REV')),
4509 ('', 'all', False, _("list files from all revisions"))]
4515 ('', 'all', False, _("list files from all revisions"))]
4510 + formatteropts,
4516 + formatteropts,
4511 _('[-r REV]'))
4517 _('[-r REV]'))
4512 def manifest(ui, repo, node=None, rev=None, **opts):
4518 def manifest(ui, repo, node=None, rev=None, **opts):
4513 """output the current or given revision of the project manifest
4519 """output the current or given revision of the project manifest
4514
4520
4515 Print a list of version controlled files for the given revision.
4521 Print a list of version controlled files for the given revision.
4516 If no revision is given, the first parent of the working directory
4522 If no revision is given, the first parent of the working directory
4517 is used, or the null revision if no revision is checked out.
4523 is used, or the null revision if no revision is checked out.
4518
4524
4519 With -v, print file permissions, symlink and executable bits.
4525 With -v, print file permissions, symlink and executable bits.
4520 With --debug, print file revision hashes.
4526 With --debug, print file revision hashes.
4521
4527
4522 If option --all is specified, the list of all files from all revisions
4528 If option --all is specified, the list of all files from all revisions
4523 is printed. This includes deleted and renamed files.
4529 is printed. This includes deleted and renamed files.
4524
4530
4525 Returns 0 on success.
4531 Returns 0 on success.
4526 """
4532 """
4527
4533
4528 fm = ui.formatter('manifest', opts)
4534 fm = ui.formatter('manifest', opts)
4529
4535
4530 if opts.get('all'):
4536 if opts.get('all'):
4531 if rev or node:
4537 if rev or node:
4532 raise util.Abort(_("can't specify a revision with --all"))
4538 raise util.Abort(_("can't specify a revision with --all"))
4533
4539
4534 res = []
4540 res = []
4535 prefix = "data/"
4541 prefix = "data/"
4536 suffix = ".i"
4542 suffix = ".i"
4537 plen = len(prefix)
4543 plen = len(prefix)
4538 slen = len(suffix)
4544 slen = len(suffix)
4539 lock = repo.lock()
4545 lock = repo.lock()
4540 try:
4546 try:
4541 for fn, b, size in repo.store.datafiles():
4547 for fn, b, size in repo.store.datafiles():
4542 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
4548 if size != 0 and fn[-slen:] == suffix and fn[:plen] == prefix:
4543 res.append(fn[plen:-slen])
4549 res.append(fn[plen:-slen])
4544 finally:
4550 finally:
4545 lock.release()
4551 lock.release()
4546 for f in res:
4552 for f in res:
4547 fm.startitem()
4553 fm.startitem()
4548 fm.write("path", '%s\n', f)
4554 fm.write("path", '%s\n', f)
4549 fm.end()
4555 fm.end()
4550 return
4556 return
4551
4557
4552 if rev and node:
4558 if rev and node:
4553 raise util.Abort(_("please specify just one revision"))
4559 raise util.Abort(_("please specify just one revision"))
4554
4560
4555 if not node:
4561 if not node:
4556 node = rev
4562 node = rev
4557
4563
4558 char = {'l': '@', 'x': '*', '': ''}
4564 char = {'l': '@', 'x': '*', '': ''}
4559 mode = {'l': '644', 'x': '755', '': '644'}
4565 mode = {'l': '644', 'x': '755', '': '644'}
4560 ctx = scmutil.revsingle(repo, node)
4566 ctx = scmutil.revsingle(repo, node)
4561 mf = ctx.manifest()
4567 mf = ctx.manifest()
4562 for f in ctx:
4568 for f in ctx:
4563 fm.startitem()
4569 fm.startitem()
4564 fl = ctx[f].flags()
4570 fl = ctx[f].flags()
4565 fm.condwrite(ui.debugflag, 'hash', '%s ', hex(mf[f]))
4571 fm.condwrite(ui.debugflag, 'hash', '%s ', hex(mf[f]))
4566 fm.condwrite(ui.verbose, 'mode type', '%s %1s ', mode[fl], char[fl])
4572 fm.condwrite(ui.verbose, 'mode type', '%s %1s ', mode[fl], char[fl])
4567 fm.write('path', '%s\n', f)
4573 fm.write('path', '%s\n', f)
4568 fm.end()
4574 fm.end()
4569
4575
4570 @command('^merge',
4576 @command('^merge',
4571 [('f', 'force', None,
4577 [('f', 'force', None,
4572 _('force a merge including outstanding changes (DEPRECATED)')),
4578 _('force a merge including outstanding changes (DEPRECATED)')),
4573 ('r', 'rev', '', _('revision to merge'), _('REV')),
4579 ('r', 'rev', '', _('revision to merge'), _('REV')),
4574 ('P', 'preview', None,
4580 ('P', 'preview', None,
4575 _('review revisions to merge (no merge is performed)'))
4581 _('review revisions to merge (no merge is performed)'))
4576 ] + mergetoolopts,
4582 ] + mergetoolopts,
4577 _('[-P] [-f] [[-r] REV]'))
4583 _('[-P] [-f] [[-r] REV]'))
4578 def merge(ui, repo, node=None, **opts):
4584 def merge(ui, repo, node=None, **opts):
4579 """merge another revision into working directory
4585 """merge another revision into working directory
4580
4586
4581 The current working directory is updated with all changes made in
4587 The current working directory is updated with all changes made in
4582 the requested revision since the last common predecessor revision.
4588 the requested revision since the last common predecessor revision.
4583
4589
4584 Files that changed between either parent are marked as changed for
4590 Files that changed between either parent are marked as changed for
4585 the next commit and a commit must be performed before any further
4591 the next commit and a commit must be performed before any further
4586 updates to the repository are allowed. The next commit will have
4592 updates to the repository are allowed. The next commit will have
4587 two parents.
4593 two parents.
4588
4594
4589 ``--tool`` can be used to specify the merge tool used for file
4595 ``--tool`` can be used to specify the merge tool used for file
4590 merges. It overrides the HGMERGE environment variable and your
4596 merges. It overrides the HGMERGE environment variable and your
4591 configuration files. See :hg:`help merge-tools` for options.
4597 configuration files. See :hg:`help merge-tools` for options.
4592
4598
4593 If no revision is specified, the working directory's parent is a
4599 If no revision is specified, the working directory's parent is a
4594 head revision, and the current branch contains exactly one other
4600 head revision, and the current branch contains exactly one other
4595 head, the other head is merged with by default. Otherwise, an
4601 head, the other head is merged with by default. Otherwise, an
4596 explicit revision with which to merge with must be provided.
4602 explicit revision with which to merge with must be provided.
4597
4603
4598 :hg:`resolve` must be used to resolve unresolved files.
4604 :hg:`resolve` must be used to resolve unresolved files.
4599
4605
4600 To undo an uncommitted merge, use :hg:`update --clean .` which
4606 To undo an uncommitted merge, use :hg:`update --clean .` which
4601 will check out a clean copy of the original merge parent, losing
4607 will check out a clean copy of the original merge parent, losing
4602 all changes.
4608 all changes.
4603
4609
4604 Returns 0 on success, 1 if there are unresolved files.
4610 Returns 0 on success, 1 if there are unresolved files.
4605 """
4611 """
4606
4612
4607 if opts.get('rev') and node:
4613 if opts.get('rev') and node:
4608 raise util.Abort(_("please specify just one revision"))
4614 raise util.Abort(_("please specify just one revision"))
4609 if not node:
4615 if not node:
4610 node = opts.get('rev')
4616 node = opts.get('rev')
4611
4617
4612 if node:
4618 if node:
4613 node = scmutil.revsingle(repo, node).node()
4619 node = scmutil.revsingle(repo, node).node()
4614
4620
4615 if not node and repo._bookmarkcurrent:
4621 if not node and repo._bookmarkcurrent:
4616 bmheads = repo.bookmarkheads(repo._bookmarkcurrent)
4622 bmheads = repo.bookmarkheads(repo._bookmarkcurrent)
4617 curhead = repo[repo._bookmarkcurrent].node()
4623 curhead = repo[repo._bookmarkcurrent].node()
4618 if len(bmheads) == 2:
4624 if len(bmheads) == 2:
4619 if curhead == bmheads[0]:
4625 if curhead == bmheads[0]:
4620 node = bmheads[1]
4626 node = bmheads[1]
4621 else:
4627 else:
4622 node = bmheads[0]
4628 node = bmheads[0]
4623 elif len(bmheads) > 2:
4629 elif len(bmheads) > 2:
4624 raise util.Abort(_("multiple matching bookmarks to merge - "
4630 raise util.Abort(_("multiple matching bookmarks to merge - "
4625 "please merge with an explicit rev or bookmark"),
4631 "please merge with an explicit rev or bookmark"),
4626 hint=_("run 'hg heads' to see all heads"))
4632 hint=_("run 'hg heads' to see all heads"))
4627 elif len(bmheads) <= 1:
4633 elif len(bmheads) <= 1:
4628 raise util.Abort(_("no matching bookmark to merge - "
4634 raise util.Abort(_("no matching bookmark to merge - "
4629 "please merge with an explicit rev or bookmark"),
4635 "please merge with an explicit rev or bookmark"),
4630 hint=_("run 'hg heads' to see all heads"))
4636 hint=_("run 'hg heads' to see all heads"))
4631
4637
4632 if not node and not repo._bookmarkcurrent:
4638 if not node and not repo._bookmarkcurrent:
4633 branch = repo[None].branch()
4639 branch = repo[None].branch()
4634 bheads = repo.branchheads(branch)
4640 bheads = repo.branchheads(branch)
4635 nbhs = [bh for bh in bheads if not repo[bh].bookmarks()]
4641 nbhs = [bh for bh in bheads if not repo[bh].bookmarks()]
4636
4642
4637 if len(nbhs) > 2:
4643 if len(nbhs) > 2:
4638 raise util.Abort(_("branch '%s' has %d heads - "
4644 raise util.Abort(_("branch '%s' has %d heads - "
4639 "please merge with an explicit rev")
4645 "please merge with an explicit rev")
4640 % (branch, len(bheads)),
4646 % (branch, len(bheads)),
4641 hint=_("run 'hg heads .' to see heads"))
4647 hint=_("run 'hg heads .' to see heads"))
4642
4648
4643 parent = repo.dirstate.p1()
4649 parent = repo.dirstate.p1()
4644 if len(nbhs) <= 1:
4650 if len(nbhs) <= 1:
4645 if len(bheads) > 1:
4651 if len(bheads) > 1:
4646 raise util.Abort(_("heads are bookmarked - "
4652 raise util.Abort(_("heads are bookmarked - "
4647 "please merge with an explicit rev"),
4653 "please merge with an explicit rev"),
4648 hint=_("run 'hg heads' to see all heads"))
4654 hint=_("run 'hg heads' to see all heads"))
4649 if len(repo.heads()) > 1:
4655 if len(repo.heads()) > 1:
4650 raise util.Abort(_("branch '%s' has one head - "
4656 raise util.Abort(_("branch '%s' has one head - "
4651 "please merge with an explicit rev")
4657 "please merge with an explicit rev")
4652 % branch,
4658 % branch,
4653 hint=_("run 'hg heads' to see all heads"))
4659 hint=_("run 'hg heads' to see all heads"))
4654 msg, hint = _('nothing to merge'), None
4660 msg, hint = _('nothing to merge'), None
4655 if parent != repo.lookup(branch):
4661 if parent != repo.lookup(branch):
4656 hint = _("use 'hg update' instead")
4662 hint = _("use 'hg update' instead")
4657 raise util.Abort(msg, hint=hint)
4663 raise util.Abort(msg, hint=hint)
4658
4664
4659 if parent not in bheads:
4665 if parent not in bheads:
4660 raise util.Abort(_('working directory not at a head revision'),
4666 raise util.Abort(_('working directory not at a head revision'),
4661 hint=_("use 'hg update' or merge with an "
4667 hint=_("use 'hg update' or merge with an "
4662 "explicit revision"))
4668 "explicit revision"))
4663 if parent == nbhs[0]:
4669 if parent == nbhs[0]:
4664 node = nbhs[-1]
4670 node = nbhs[-1]
4665 else:
4671 else:
4666 node = nbhs[0]
4672 node = nbhs[0]
4667
4673
4668 if opts.get('preview'):
4674 if opts.get('preview'):
4669 # find nodes that are ancestors of p2 but not of p1
4675 # find nodes that are ancestors of p2 but not of p1
4670 p1 = repo.lookup('.')
4676 p1 = repo.lookup('.')
4671 p2 = repo.lookup(node)
4677 p2 = repo.lookup(node)
4672 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
4678 nodes = repo.changelog.findmissing(common=[p1], heads=[p2])
4673
4679
4674 displayer = cmdutil.show_changeset(ui, repo, opts)
4680 displayer = cmdutil.show_changeset(ui, repo, opts)
4675 for node in nodes:
4681 for node in nodes:
4676 displayer.show(repo[node])
4682 displayer.show(repo[node])
4677 displayer.close()
4683 displayer.close()
4678 return 0
4684 return 0
4679
4685
4680 try:
4686 try:
4681 # ui.forcemerge is an internal variable, do not document
4687 # ui.forcemerge is an internal variable, do not document
4682 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''), 'merge')
4688 repo.ui.setconfig('ui', 'forcemerge', opts.get('tool', ''), 'merge')
4683 return hg.merge(repo, node, force=opts.get('force'))
4689 return hg.merge(repo, node, force=opts.get('force'))
4684 finally:
4690 finally:
4685 ui.setconfig('ui', 'forcemerge', '', 'merge')
4691 ui.setconfig('ui', 'forcemerge', '', 'merge')
4686
4692
4687 @command('outgoing|out',
4693 @command('outgoing|out',
4688 [('f', 'force', None, _('run even when the destination is unrelated')),
4694 [('f', 'force', None, _('run even when the destination is unrelated')),
4689 ('r', 'rev', [],
4695 ('r', 'rev', [],
4690 _('a changeset intended to be included in the destination'), _('REV')),
4696 _('a changeset intended to be included in the destination'), _('REV')),
4691 ('n', 'newest-first', None, _('show newest record first')),
4697 ('n', 'newest-first', None, _('show newest record first')),
4692 ('B', 'bookmarks', False, _('compare bookmarks')),
4698 ('B', 'bookmarks', False, _('compare bookmarks')),
4693 ('b', 'branch', [], _('a specific branch you would like to push'),
4699 ('b', 'branch', [], _('a specific branch you would like to push'),
4694 _('BRANCH')),
4700 _('BRANCH')),
4695 ] + logopts + remoteopts + subrepoopts,
4701 ] + logopts + remoteopts + subrepoopts,
4696 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
4702 _('[-M] [-p] [-n] [-f] [-r REV]... [DEST]'))
4697 def outgoing(ui, repo, dest=None, **opts):
4703 def outgoing(ui, repo, dest=None, **opts):
4698 """show changesets not found in the destination
4704 """show changesets not found in the destination
4699
4705
4700 Show changesets not found in the specified destination repository
4706 Show changesets not found in the specified destination repository
4701 or the default push location. These are the changesets that would
4707 or the default push location. These are the changesets that would
4702 be pushed if a push was requested.
4708 be pushed if a push was requested.
4703
4709
4704 See pull for details of valid destination formats.
4710 See pull for details of valid destination formats.
4705
4711
4706 Returns 0 if there are outgoing changes, 1 otherwise.
4712 Returns 0 if there are outgoing changes, 1 otherwise.
4707 """
4713 """
4708 if opts.get('graph'):
4714 if opts.get('graph'):
4709 cmdutil.checkunsupportedgraphflags([], opts)
4715 cmdutil.checkunsupportedgraphflags([], opts)
4710 o, other = hg._outgoing(ui, repo, dest, opts)
4716 o, other = hg._outgoing(ui, repo, dest, opts)
4711 if not o:
4717 if not o:
4712 cmdutil.outgoinghooks(ui, repo, other, opts, o)
4718 cmdutil.outgoinghooks(ui, repo, other, opts, o)
4713 return
4719 return
4714
4720
4715 revdag = cmdutil.graphrevs(repo, o, opts)
4721 revdag = cmdutil.graphrevs(repo, o, opts)
4716 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
4722 displayer = cmdutil.show_changeset(ui, repo, opts, buffered=True)
4717 showparents = [ctx.node() for ctx in repo[None].parents()]
4723 showparents = [ctx.node() for ctx in repo[None].parents()]
4718 cmdutil.displaygraph(ui, revdag, displayer, showparents,
4724 cmdutil.displaygraph(ui, revdag, displayer, showparents,
4719 graphmod.asciiedges)
4725 graphmod.asciiedges)
4720 cmdutil.outgoinghooks(ui, repo, other, opts, o)
4726 cmdutil.outgoinghooks(ui, repo, other, opts, o)
4721 return 0
4727 return 0
4722
4728
4723 if opts.get('bookmarks'):
4729 if opts.get('bookmarks'):
4724 dest = ui.expandpath(dest or 'default-push', dest or 'default')
4730 dest = ui.expandpath(dest or 'default-push', dest or 'default')
4725 dest, branches = hg.parseurl(dest, opts.get('branch'))
4731 dest, branches = hg.parseurl(dest, opts.get('branch'))
4726 other = hg.peer(repo, opts, dest)
4732 other = hg.peer(repo, opts, dest)
4727 if 'bookmarks' not in other.listkeys('namespaces'):
4733 if 'bookmarks' not in other.listkeys('namespaces'):
4728 ui.warn(_("remote doesn't support bookmarks\n"))
4734 ui.warn(_("remote doesn't support bookmarks\n"))
4729 return 0
4735 return 0
4730 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
4736 ui.status(_('comparing with %s\n') % util.hidepassword(dest))
4731 return bookmarks.diff(ui, other, repo)
4737 return bookmarks.diff(ui, other, repo)
4732
4738
4733 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
4739 repo._subtoppath = ui.expandpath(dest or 'default-push', dest or 'default')
4734 try:
4740 try:
4735 return hg.outgoing(ui, repo, dest, opts)
4741 return hg.outgoing(ui, repo, dest, opts)
4736 finally:
4742 finally:
4737 del repo._subtoppath
4743 del repo._subtoppath
4738
4744
4739 @command('parents',
4745 @command('parents',
4740 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
4746 [('r', 'rev', '', _('show parents of the specified revision'), _('REV')),
4741 ] + templateopts,
4747 ] + templateopts,
4742 _('[-r REV] [FILE]'),
4748 _('[-r REV] [FILE]'),
4743 inferrepo=True)
4749 inferrepo=True)
4744 def parents(ui, repo, file_=None, **opts):
4750 def parents(ui, repo, file_=None, **opts):
4745 """show the parents of the working directory or revision (DEPRECATED)
4751 """show the parents of the working directory or revision (DEPRECATED)
4746
4752
4747 Print the working directory's parent revisions. If a revision is
4753 Print the working directory's parent revisions. If a revision is
4748 given via -r/--rev, the parent of that revision will be printed.
4754 given via -r/--rev, the parent of that revision will be printed.
4749 If a file argument is given, the revision in which the file was
4755 If a file argument is given, the revision in which the file was
4750 last changed (before the working directory revision or the
4756 last changed (before the working directory revision or the
4751 argument to --rev if given) is printed.
4757 argument to --rev if given) is printed.
4752
4758
4753 See :hg:`summary` and :hg:`help revsets` for related information.
4759 See :hg:`summary` and :hg:`help revsets` for related information.
4754
4760
4755 Returns 0 on success.
4761 Returns 0 on success.
4756 """
4762 """
4757
4763
4758 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
4764 ctx = scmutil.revsingle(repo, opts.get('rev'), None)
4759
4765
4760 if file_:
4766 if file_:
4761 m = scmutil.match(ctx, (file_,), opts)
4767 m = scmutil.match(ctx, (file_,), opts)
4762 if m.anypats() or len(m.files()) != 1:
4768 if m.anypats() or len(m.files()) != 1:
4763 raise util.Abort(_('can only specify an explicit filename'))
4769 raise util.Abort(_('can only specify an explicit filename'))
4764 file_ = m.files()[0]
4770 file_ = m.files()[0]
4765 filenodes = []
4771 filenodes = []
4766 for cp in ctx.parents():
4772 for cp in ctx.parents():
4767 if not cp:
4773 if not cp:
4768 continue
4774 continue
4769 try:
4775 try:
4770 filenodes.append(cp.filenode(file_))
4776 filenodes.append(cp.filenode(file_))
4771 except error.LookupError:
4777 except error.LookupError:
4772 pass
4778 pass
4773 if not filenodes:
4779 if not filenodes:
4774 raise util.Abort(_("'%s' not found in manifest!") % file_)
4780 raise util.Abort(_("'%s' not found in manifest!") % file_)
4775 p = []
4781 p = []
4776 for fn in filenodes:
4782 for fn in filenodes:
4777 fctx = repo.filectx(file_, fileid=fn)
4783 fctx = repo.filectx(file_, fileid=fn)
4778 p.append(fctx.node())
4784 p.append(fctx.node())
4779 else:
4785 else:
4780 p = [cp.node() for cp in ctx.parents()]
4786 p = [cp.node() for cp in ctx.parents()]
4781
4787
4782 displayer = cmdutil.show_changeset(ui, repo, opts)
4788 displayer = cmdutil.show_changeset(ui, repo, opts)
4783 for n in p:
4789 for n in p:
4784 if n != nullid:
4790 if n != nullid:
4785 displayer.show(repo[n])
4791 displayer.show(repo[n])
4786 displayer.close()
4792 displayer.close()
4787
4793
4788 @command('paths', [], _('[NAME]'), optionalrepo=True)
4794 @command('paths', [], _('[NAME]'), optionalrepo=True)
4789 def paths(ui, repo, search=None):
4795 def paths(ui, repo, search=None):
4790 """show aliases for remote repositories
4796 """show aliases for remote repositories
4791
4797
4792 Show definition of symbolic path name NAME. If no name is given,
4798 Show definition of symbolic path name NAME. If no name is given,
4793 show definition of all available names.
4799 show definition of all available names.
4794
4800
4795 Option -q/--quiet suppresses all output when searching for NAME
4801 Option -q/--quiet suppresses all output when searching for NAME
4796 and shows only the path names when listing all definitions.
4802 and shows only the path names when listing all definitions.
4797
4803
4798 Path names are defined in the [paths] section of your
4804 Path names are defined in the [paths] section of your
4799 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
4805 configuration file and in ``/etc/mercurial/hgrc``. If run inside a
4800 repository, ``.hg/hgrc`` is used, too.
4806 repository, ``.hg/hgrc`` is used, too.
4801
4807
4802 The path names ``default`` and ``default-push`` have a special
4808 The path names ``default`` and ``default-push`` have a special
4803 meaning. When performing a push or pull operation, they are used
4809 meaning. When performing a push or pull operation, they are used
4804 as fallbacks if no location is specified on the command-line.
4810 as fallbacks if no location is specified on the command-line.
4805 When ``default-push`` is set, it will be used for push and
4811 When ``default-push`` is set, it will be used for push and
4806 ``default`` will be used for pull; otherwise ``default`` is used
4812 ``default`` will be used for pull; otherwise ``default`` is used
4807 as the fallback for both. When cloning a repository, the clone
4813 as the fallback for both. When cloning a repository, the clone
4808 source is written as ``default`` in ``.hg/hgrc``. Note that
4814 source is written as ``default`` in ``.hg/hgrc``. Note that
4809 ``default`` and ``default-push`` apply to all inbound (e.g.
4815 ``default`` and ``default-push`` apply to all inbound (e.g.
4810 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email` and
4816 :hg:`incoming`) and outbound (e.g. :hg:`outgoing`, :hg:`email` and
4811 :hg:`bundle`) operations.
4817 :hg:`bundle`) operations.
4812
4818
4813 See :hg:`help urls` for more information.
4819 See :hg:`help urls` for more information.
4814
4820
4815 Returns 0 on success.
4821 Returns 0 on success.
4816 """
4822 """
4817 if search:
4823 if search:
4818 for name, path in ui.configitems("paths"):
4824 for name, path in ui.configitems("paths"):
4819 if name == search:
4825 if name == search:
4820 ui.status("%s\n" % util.hidepassword(path))
4826 ui.status("%s\n" % util.hidepassword(path))
4821 return
4827 return
4822 if not ui.quiet:
4828 if not ui.quiet:
4823 ui.warn(_("not found!\n"))
4829 ui.warn(_("not found!\n"))
4824 return 1
4830 return 1
4825 else:
4831 else:
4826 for name, path in ui.configitems("paths"):
4832 for name, path in ui.configitems("paths"):
4827 if ui.quiet:
4833 if ui.quiet:
4828 ui.write("%s\n" % name)
4834 ui.write("%s\n" % name)
4829 else:
4835 else:
4830 ui.write("%s = %s\n" % (name, util.hidepassword(path)))
4836 ui.write("%s = %s\n" % (name, util.hidepassword(path)))
4831
4837
4832 @command('phase',
4838 @command('phase',
4833 [('p', 'public', False, _('set changeset phase to public')),
4839 [('p', 'public', False, _('set changeset phase to public')),
4834 ('d', 'draft', False, _('set changeset phase to draft')),
4840 ('d', 'draft', False, _('set changeset phase to draft')),
4835 ('s', 'secret', False, _('set changeset phase to secret')),
4841 ('s', 'secret', False, _('set changeset phase to secret')),
4836 ('f', 'force', False, _('allow to move boundary backward')),
4842 ('f', 'force', False, _('allow to move boundary backward')),
4837 ('r', 'rev', [], _('target revision'), _('REV')),
4843 ('r', 'rev', [], _('target revision'), _('REV')),
4838 ],
4844 ],
4839 _('[-p|-d|-s] [-f] [-r] REV...'))
4845 _('[-p|-d|-s] [-f] [-r] REV...'))
4840 def phase(ui, repo, *revs, **opts):
4846 def phase(ui, repo, *revs, **opts):
4841 """set or show the current phase name
4847 """set or show the current phase name
4842
4848
4843 With no argument, show the phase name of specified revisions.
4849 With no argument, show the phase name of specified revisions.
4844
4850
4845 With one of -p/--public, -d/--draft or -s/--secret, change the
4851 With one of -p/--public, -d/--draft or -s/--secret, change the
4846 phase value of the specified revisions.
4852 phase value of the specified revisions.
4847
4853
4848 Unless -f/--force is specified, :hg:`phase` won't move changeset from a
4854 Unless -f/--force is specified, :hg:`phase` won't move changeset from a
4849 lower phase to an higher phase. Phases are ordered as follows::
4855 lower phase to an higher phase. Phases are ordered as follows::
4850
4856
4851 public < draft < secret
4857 public < draft < secret
4852
4858
4853 Returns 0 on success, 1 if no phases were changed or some could not
4859 Returns 0 on success, 1 if no phases were changed or some could not
4854 be changed.
4860 be changed.
4855 """
4861 """
4856 # search for a unique phase argument
4862 # search for a unique phase argument
4857 targetphase = None
4863 targetphase = None
4858 for idx, name in enumerate(phases.phasenames):
4864 for idx, name in enumerate(phases.phasenames):
4859 if opts[name]:
4865 if opts[name]:
4860 if targetphase is not None:
4866 if targetphase is not None:
4861 raise util.Abort(_('only one phase can be specified'))
4867 raise util.Abort(_('only one phase can be specified'))
4862 targetphase = idx
4868 targetphase = idx
4863
4869
4864 # look for specified revision
4870 # look for specified revision
4865 revs = list(revs)
4871 revs = list(revs)
4866 revs.extend(opts['rev'])
4872 revs.extend(opts['rev'])
4867 if not revs:
4873 if not revs:
4868 raise util.Abort(_('no revisions specified'))
4874 raise util.Abort(_('no revisions specified'))
4869
4875
4870 revs = scmutil.revrange(repo, revs)
4876 revs = scmutil.revrange(repo, revs)
4871
4877
4872 lock = None
4878 lock = None
4873 ret = 0
4879 ret = 0
4874 if targetphase is None:
4880 if targetphase is None:
4875 # display
4881 # display
4876 for r in revs:
4882 for r in revs:
4877 ctx = repo[r]
4883 ctx = repo[r]
4878 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
4884 ui.write('%i: %s\n' % (ctx.rev(), ctx.phasestr()))
4879 else:
4885 else:
4880 tr = None
4886 tr = None
4881 lock = repo.lock()
4887 lock = repo.lock()
4882 try:
4888 try:
4883 tr = repo.transaction("phase")
4889 tr = repo.transaction("phase")
4884 # set phase
4890 # set phase
4885 if not revs:
4891 if not revs:
4886 raise util.Abort(_('empty revision set'))
4892 raise util.Abort(_('empty revision set'))
4887 nodes = [repo[r].node() for r in revs]
4893 nodes = [repo[r].node() for r in revs]
4888 # moving revision from public to draft may hide them
4894 # moving revision from public to draft may hide them
4889 # We have to check result on an unfiltered repository
4895 # We have to check result on an unfiltered repository
4890 unfi = repo.unfiltered()
4896 unfi = repo.unfiltered()
4891 getphase = unfi._phasecache.phase
4897 getphase = unfi._phasecache.phase
4892 olddata = [getphase(unfi, r) for r in unfi]
4898 olddata = [getphase(unfi, r) for r in unfi]
4893 phases.advanceboundary(repo, tr, targetphase, nodes)
4899 phases.advanceboundary(repo, tr, targetphase, nodes)
4894 if opts['force']:
4900 if opts['force']:
4895 phases.retractboundary(repo, tr, targetphase, nodes)
4901 phases.retractboundary(repo, tr, targetphase, nodes)
4896 tr.close()
4902 tr.close()
4897 finally:
4903 finally:
4898 if tr is not None:
4904 if tr is not None:
4899 tr.release()
4905 tr.release()
4900 lock.release()
4906 lock.release()
4901 getphase = unfi._phasecache.phase
4907 getphase = unfi._phasecache.phase
4902 newdata = [getphase(unfi, r) for r in unfi]
4908 newdata = [getphase(unfi, r) for r in unfi]
4903 changes = sum(newdata[r] != olddata[r] for r in unfi)
4909 changes = sum(newdata[r] != olddata[r] for r in unfi)
4904 cl = unfi.changelog
4910 cl = unfi.changelog
4905 rejected = [n for n in nodes
4911 rejected = [n for n in nodes
4906 if newdata[cl.rev(n)] < targetphase]
4912 if newdata[cl.rev(n)] < targetphase]
4907 if rejected:
4913 if rejected:
4908 ui.warn(_('cannot move %i changesets to a higher '
4914 ui.warn(_('cannot move %i changesets to a higher '
4909 'phase, use --force\n') % len(rejected))
4915 'phase, use --force\n') % len(rejected))
4910 ret = 1
4916 ret = 1
4911 if changes:
4917 if changes:
4912 msg = _('phase changed for %i changesets\n') % changes
4918 msg = _('phase changed for %i changesets\n') % changes
4913 if ret:
4919 if ret:
4914 ui.status(msg)
4920 ui.status(msg)
4915 else:
4921 else:
4916 ui.note(msg)
4922 ui.note(msg)
4917 else:
4923 else:
4918 ui.warn(_('no phases changed\n'))
4924 ui.warn(_('no phases changed\n'))
4919 ret = 1
4925 ret = 1
4920 return ret
4926 return ret
4921
4927
4922 def postincoming(ui, repo, modheads, optupdate, checkout):
4928 def postincoming(ui, repo, modheads, optupdate, checkout):
4923 if modheads == 0:
4929 if modheads == 0:
4924 return
4930 return
4925 if optupdate:
4931 if optupdate:
4926 checkout, movemarkfrom = bookmarks.calculateupdate(ui, repo, checkout)
4932 checkout, movemarkfrom = bookmarks.calculateupdate(ui, repo, checkout)
4927 try:
4933 try:
4928 ret = hg.update(repo, checkout)
4934 ret = hg.update(repo, checkout)
4929 except util.Abort, inst:
4935 except util.Abort, inst:
4930 ui.warn(_("not updating: %s\n") % str(inst))
4936 ui.warn(_("not updating: %s\n") % str(inst))
4931 if inst.hint:
4937 if inst.hint:
4932 ui.warn(_("(%s)\n") % inst.hint)
4938 ui.warn(_("(%s)\n") % inst.hint)
4933 return 0
4939 return 0
4934 if not ret and not checkout:
4940 if not ret and not checkout:
4935 if bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
4941 if bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
4936 ui.status(_("updating bookmark %s\n") % repo._bookmarkcurrent)
4942 ui.status(_("updating bookmark %s\n") % repo._bookmarkcurrent)
4937 return ret
4943 return ret
4938 if modheads > 1:
4944 if modheads > 1:
4939 currentbranchheads = len(repo.branchheads())
4945 currentbranchheads = len(repo.branchheads())
4940 if currentbranchheads == modheads:
4946 if currentbranchheads == modheads:
4941 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
4947 ui.status(_("(run 'hg heads' to see heads, 'hg merge' to merge)\n"))
4942 elif currentbranchheads > 1:
4948 elif currentbranchheads > 1:
4943 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
4949 ui.status(_("(run 'hg heads .' to see heads, 'hg merge' to "
4944 "merge)\n"))
4950 "merge)\n"))
4945 else:
4951 else:
4946 ui.status(_("(run 'hg heads' to see heads)\n"))
4952 ui.status(_("(run 'hg heads' to see heads)\n"))
4947 else:
4953 else:
4948 ui.status(_("(run 'hg update' to get a working copy)\n"))
4954 ui.status(_("(run 'hg update' to get a working copy)\n"))
4949
4955
4950 @command('^pull',
4956 @command('^pull',
4951 [('u', 'update', None,
4957 [('u', 'update', None,
4952 _('update to new branch head if changesets were pulled')),
4958 _('update to new branch head if changesets were pulled')),
4953 ('f', 'force', None, _('run even when remote repository is unrelated')),
4959 ('f', 'force', None, _('run even when remote repository is unrelated')),
4954 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
4960 ('r', 'rev', [], _('a remote changeset intended to be added'), _('REV')),
4955 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
4961 ('B', 'bookmark', [], _("bookmark to pull"), _('BOOKMARK')),
4956 ('b', 'branch', [], _('a specific branch you would like to pull'),
4962 ('b', 'branch', [], _('a specific branch you would like to pull'),
4957 _('BRANCH')),
4963 _('BRANCH')),
4958 ] + remoteopts,
4964 ] + remoteopts,
4959 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
4965 _('[-u] [-f] [-r REV]... [-e CMD] [--remotecmd CMD] [SOURCE]'))
4960 def pull(ui, repo, source="default", **opts):
4966 def pull(ui, repo, source="default", **opts):
4961 """pull changes from the specified source
4967 """pull changes from the specified source
4962
4968
4963 Pull changes from a remote repository to a local one.
4969 Pull changes from a remote repository to a local one.
4964
4970
4965 This finds all changes from the repository at the specified path
4971 This finds all changes from the repository at the specified path
4966 or URL and adds them to a local repository (the current one unless
4972 or URL and adds them to a local repository (the current one unless
4967 -R is specified). By default, this does not update the copy of the
4973 -R is specified). By default, this does not update the copy of the
4968 project in the working directory.
4974 project in the working directory.
4969
4975
4970 Use :hg:`incoming` if you want to see what would have been added
4976 Use :hg:`incoming` if you want to see what would have been added
4971 by a pull at the time you issued this command. If you then decide
4977 by a pull at the time you issued this command. If you then decide
4972 to add those changes to the repository, you should use :hg:`pull
4978 to add those changes to the repository, you should use :hg:`pull
4973 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
4979 -r X` where ``X`` is the last changeset listed by :hg:`incoming`.
4974
4980
4975 If SOURCE is omitted, the 'default' path will be used.
4981 If SOURCE is omitted, the 'default' path will be used.
4976 See :hg:`help urls` for more information.
4982 See :hg:`help urls` for more information.
4977
4983
4978 Returns 0 on success, 1 if an update had unresolved files.
4984 Returns 0 on success, 1 if an update had unresolved files.
4979 """
4985 """
4980 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
4986 source, branches = hg.parseurl(ui.expandpath(source), opts.get('branch'))
4981 other = hg.peer(repo, opts, source)
4987 other = hg.peer(repo, opts, source)
4982 try:
4988 try:
4983 ui.status(_('pulling from %s\n') % util.hidepassword(source))
4989 ui.status(_('pulling from %s\n') % util.hidepassword(source))
4984 revs, checkout = hg.addbranchrevs(repo, other, branches,
4990 revs, checkout = hg.addbranchrevs(repo, other, branches,
4985 opts.get('rev'))
4991 opts.get('rev'))
4986
4992
4987 remotebookmarks = other.listkeys('bookmarks')
4993 remotebookmarks = other.listkeys('bookmarks')
4988
4994
4989 if opts.get('bookmark'):
4995 if opts.get('bookmark'):
4990 if not revs:
4996 if not revs:
4991 revs = []
4997 revs = []
4992 for b in opts['bookmark']:
4998 for b in opts['bookmark']:
4993 if b not in remotebookmarks:
4999 if b not in remotebookmarks:
4994 raise util.Abort(_('remote bookmark %s not found!') % b)
5000 raise util.Abort(_('remote bookmark %s not found!') % b)
4995 revs.append(remotebookmarks[b])
5001 revs.append(remotebookmarks[b])
4996
5002
4997 if revs:
5003 if revs:
4998 try:
5004 try:
4999 revs = [other.lookup(rev) for rev in revs]
5005 revs = [other.lookup(rev) for rev in revs]
5000 except error.CapabilityError:
5006 except error.CapabilityError:
5001 err = _("other repository doesn't support revision lookup, "
5007 err = _("other repository doesn't support revision lookup, "
5002 "so a rev cannot be specified.")
5008 "so a rev cannot be specified.")
5003 raise util.Abort(err)
5009 raise util.Abort(err)
5004
5010
5005 modheads = exchange.pull(repo, other, heads=revs,
5011 modheads = exchange.pull(repo, other, heads=revs,
5006 force=opts.get('force'),
5012 force=opts.get('force'),
5007 bookmarks=opts.get('bookmark', ())).cgresult
5013 bookmarks=opts.get('bookmark', ())).cgresult
5008 if checkout:
5014 if checkout:
5009 checkout = str(repo.changelog.rev(other.lookup(checkout)))
5015 checkout = str(repo.changelog.rev(other.lookup(checkout)))
5010 repo._subtoppath = source
5016 repo._subtoppath = source
5011 try:
5017 try:
5012 ret = postincoming(ui, repo, modheads, opts.get('update'), checkout)
5018 ret = postincoming(ui, repo, modheads, opts.get('update'), checkout)
5013
5019
5014 finally:
5020 finally:
5015 del repo._subtoppath
5021 del repo._subtoppath
5016
5022
5017 finally:
5023 finally:
5018 other.close()
5024 other.close()
5019 return ret
5025 return ret
5020
5026
5021 @command('^push',
5027 @command('^push',
5022 [('f', 'force', None, _('force push')),
5028 [('f', 'force', None, _('force push')),
5023 ('r', 'rev', [],
5029 ('r', 'rev', [],
5024 _('a changeset intended to be included in the destination'),
5030 _('a changeset intended to be included in the destination'),
5025 _('REV')),
5031 _('REV')),
5026 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
5032 ('B', 'bookmark', [], _("bookmark to push"), _('BOOKMARK')),
5027 ('b', 'branch', [],
5033 ('b', 'branch', [],
5028 _('a specific branch you would like to push'), _('BRANCH')),
5034 _('a specific branch you would like to push'), _('BRANCH')),
5029 ('', 'new-branch', False, _('allow pushing a new branch')),
5035 ('', 'new-branch', False, _('allow pushing a new branch')),
5030 ] + remoteopts,
5036 ] + remoteopts,
5031 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
5037 _('[-f] [-r REV]... [-e CMD] [--remotecmd CMD] [DEST]'))
5032 def push(ui, repo, dest=None, **opts):
5038 def push(ui, repo, dest=None, **opts):
5033 """push changes to the specified destination
5039 """push changes to the specified destination
5034
5040
5035 Push changesets from the local repository to the specified
5041 Push changesets from the local repository to the specified
5036 destination.
5042 destination.
5037
5043
5038 This operation is symmetrical to pull: it is identical to a pull
5044 This operation is symmetrical to pull: it is identical to a pull
5039 in the destination repository from the current one.
5045 in the destination repository from the current one.
5040
5046
5041 By default, push will not allow creation of new heads at the
5047 By default, push will not allow creation of new heads at the
5042 destination, since multiple heads would make it unclear which head
5048 destination, since multiple heads would make it unclear which head
5043 to use. In this situation, it is recommended to pull and merge
5049 to use. In this situation, it is recommended to pull and merge
5044 before pushing.
5050 before pushing.
5045
5051
5046 Use --new-branch if you want to allow push to create a new named
5052 Use --new-branch if you want to allow push to create a new named
5047 branch that is not present at the destination. This allows you to
5053 branch that is not present at the destination. This allows you to
5048 only create a new branch without forcing other changes.
5054 only create a new branch without forcing other changes.
5049
5055
5050 .. note::
5056 .. note::
5051
5057
5052 Extra care should be taken with the -f/--force option,
5058 Extra care should be taken with the -f/--force option,
5053 which will push all new heads on all branches, an action which will
5059 which will push all new heads on all branches, an action which will
5054 almost always cause confusion for collaborators.
5060 almost always cause confusion for collaborators.
5055
5061
5056 If -r/--rev is used, the specified revision and all its ancestors
5062 If -r/--rev is used, the specified revision and all its ancestors
5057 will be pushed to the remote repository.
5063 will be pushed to the remote repository.
5058
5064
5059 If -B/--bookmark is used, the specified bookmarked revision, its
5065 If -B/--bookmark is used, the specified bookmarked revision, its
5060 ancestors, and the bookmark will be pushed to the remote
5066 ancestors, and the bookmark will be pushed to the remote
5061 repository.
5067 repository.
5062
5068
5063 Please see :hg:`help urls` for important details about ``ssh://``
5069 Please see :hg:`help urls` for important details about ``ssh://``
5064 URLs. If DESTINATION is omitted, a default path will be used.
5070 URLs. If DESTINATION is omitted, a default path will be used.
5065
5071
5066 Returns 0 if push was successful, 1 if nothing to push.
5072 Returns 0 if push was successful, 1 if nothing to push.
5067 """
5073 """
5068
5074
5069 if opts.get('bookmark'):
5075 if opts.get('bookmark'):
5070 ui.setconfig('bookmarks', 'pushing', opts['bookmark'], 'push')
5076 ui.setconfig('bookmarks', 'pushing', opts['bookmark'], 'push')
5071 for b in opts['bookmark']:
5077 for b in opts['bookmark']:
5072 # translate -B options to -r so changesets get pushed
5078 # translate -B options to -r so changesets get pushed
5073 if b in repo._bookmarks:
5079 if b in repo._bookmarks:
5074 opts.setdefault('rev', []).append(b)
5080 opts.setdefault('rev', []).append(b)
5075 else:
5081 else:
5076 # if we try to push a deleted bookmark, translate it to null
5082 # if we try to push a deleted bookmark, translate it to null
5077 # this lets simultaneous -r, -b options continue working
5083 # this lets simultaneous -r, -b options continue working
5078 opts.setdefault('rev', []).append("null")
5084 opts.setdefault('rev', []).append("null")
5079
5085
5080 dest = ui.expandpath(dest or 'default-push', dest or 'default')
5086 dest = ui.expandpath(dest or 'default-push', dest or 'default')
5081 dest, branches = hg.parseurl(dest, opts.get('branch'))
5087 dest, branches = hg.parseurl(dest, opts.get('branch'))
5082 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
5088 ui.status(_('pushing to %s\n') % util.hidepassword(dest))
5083 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
5089 revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
5084 try:
5090 try:
5085 other = hg.peer(repo, opts, dest)
5091 other = hg.peer(repo, opts, dest)
5086 except error.RepoError:
5092 except error.RepoError:
5087 if dest == "default-push":
5093 if dest == "default-push":
5088 raise util.Abort(_("default repository not configured!"),
5094 raise util.Abort(_("default repository not configured!"),
5089 hint=_('see the "path" section in "hg help config"'))
5095 hint=_('see the "path" section in "hg help config"'))
5090 else:
5096 else:
5091 raise
5097 raise
5092
5098
5093 if revs:
5099 if revs:
5094 revs = [repo.lookup(r) for r in scmutil.revrange(repo, revs)]
5100 revs = [repo.lookup(r) for r in scmutil.revrange(repo, revs)]
5095
5101
5096 repo._subtoppath = dest
5102 repo._subtoppath = dest
5097 try:
5103 try:
5098 # push subrepos depth-first for coherent ordering
5104 # push subrepos depth-first for coherent ordering
5099 c = repo['']
5105 c = repo['']
5100 subs = c.substate # only repos that are committed
5106 subs = c.substate # only repos that are committed
5101 for s in sorted(subs):
5107 for s in sorted(subs):
5102 result = c.sub(s).push(opts)
5108 result = c.sub(s).push(opts)
5103 if result == 0:
5109 if result == 0:
5104 return not result
5110 return not result
5105 finally:
5111 finally:
5106 del repo._subtoppath
5112 del repo._subtoppath
5107 pushop = exchange.push(repo, other, opts.get('force'), revs=revs,
5113 pushop = exchange.push(repo, other, opts.get('force'), revs=revs,
5108 newbranch=opts.get('new_branch'),
5114 newbranch=opts.get('new_branch'),
5109 bookmarks=opts.get('bookmark', ()))
5115 bookmarks=opts.get('bookmark', ()))
5110
5116
5111 result = not pushop.cgresult
5117 result = not pushop.cgresult
5112
5118
5113 if pushop.bkresult is not None:
5119 if pushop.bkresult is not None:
5114 if pushop.bkresult == 2:
5120 if pushop.bkresult == 2:
5115 result = 2
5121 result = 2
5116 elif not result and pushop.bkresult:
5122 elif not result and pushop.bkresult:
5117 result = 2
5123 result = 2
5118
5124
5119 return result
5125 return result
5120
5126
5121 @command('recover', [])
5127 @command('recover', [])
5122 def recover(ui, repo):
5128 def recover(ui, repo):
5123 """roll back an interrupted transaction
5129 """roll back an interrupted transaction
5124
5130
5125 Recover from an interrupted commit or pull.
5131 Recover from an interrupted commit or pull.
5126
5132
5127 This command tries to fix the repository status after an
5133 This command tries to fix the repository status after an
5128 interrupted operation. It should only be necessary when Mercurial
5134 interrupted operation. It should only be necessary when Mercurial
5129 suggests it.
5135 suggests it.
5130
5136
5131 Returns 0 if successful, 1 if nothing to recover or verify fails.
5137 Returns 0 if successful, 1 if nothing to recover or verify fails.
5132 """
5138 """
5133 if repo.recover():
5139 if repo.recover():
5134 return hg.verify(repo)
5140 return hg.verify(repo)
5135 return 1
5141 return 1
5136
5142
5137 @command('^remove|rm',
5143 @command('^remove|rm',
5138 [('A', 'after', None, _('record delete for missing files')),
5144 [('A', 'after', None, _('record delete for missing files')),
5139 ('f', 'force', None,
5145 ('f', 'force', None,
5140 _('remove (and delete) file even if added or modified')),
5146 _('remove (and delete) file even if added or modified')),
5141 ] + subrepoopts + walkopts,
5147 ] + subrepoopts + walkopts,
5142 _('[OPTION]... FILE...'),
5148 _('[OPTION]... FILE...'),
5143 inferrepo=True)
5149 inferrepo=True)
5144 def remove(ui, repo, *pats, **opts):
5150 def remove(ui, repo, *pats, **opts):
5145 """remove the specified files on the next commit
5151 """remove the specified files on the next commit
5146
5152
5147 Schedule the indicated files for removal from the current branch.
5153 Schedule the indicated files for removal from the current branch.
5148
5154
5149 This command schedules the files to be removed at the next commit.
5155 This command schedules the files to be removed at the next commit.
5150 To undo a remove before that, see :hg:`revert`. To undo added
5156 To undo a remove before that, see :hg:`revert`. To undo added
5151 files, see :hg:`forget`.
5157 files, see :hg:`forget`.
5152
5158
5153 .. container:: verbose
5159 .. container:: verbose
5154
5160
5155 -A/--after can be used to remove only files that have already
5161 -A/--after can be used to remove only files that have already
5156 been deleted, -f/--force can be used to force deletion, and -Af
5162 been deleted, -f/--force can be used to force deletion, and -Af
5157 can be used to remove files from the next revision without
5163 can be used to remove files from the next revision without
5158 deleting them from the working directory.
5164 deleting them from the working directory.
5159
5165
5160 The following table details the behavior of remove for different
5166 The following table details the behavior of remove for different
5161 file states (columns) and option combinations (rows). The file
5167 file states (columns) and option combinations (rows). The file
5162 states are Added [A], Clean [C], Modified [M] and Missing [!]
5168 states are Added [A], Clean [C], Modified [M] and Missing [!]
5163 (as reported by :hg:`status`). The actions are Warn, Remove
5169 (as reported by :hg:`status`). The actions are Warn, Remove
5164 (from branch) and Delete (from disk):
5170 (from branch) and Delete (from disk):
5165
5171
5166 ========= == == == ==
5172 ========= == == == ==
5167 opt/state A C M !
5173 opt/state A C M !
5168 ========= == == == ==
5174 ========= == == == ==
5169 none W RD W R
5175 none W RD W R
5170 -f R RD RD R
5176 -f R RD RD R
5171 -A W W W R
5177 -A W W W R
5172 -Af R R R R
5178 -Af R R R R
5173 ========= == == == ==
5179 ========= == == == ==
5174
5180
5175 Note that remove never deletes files in Added [A] state from the
5181 Note that remove never deletes files in Added [A] state from the
5176 working directory, not even if option --force is specified.
5182 working directory, not even if option --force is specified.
5177
5183
5178 Returns 0 on success, 1 if any warnings encountered.
5184 Returns 0 on success, 1 if any warnings encountered.
5179 """
5185 """
5180
5186
5181 after, force = opts.get('after'), opts.get('force')
5187 after, force = opts.get('after'), opts.get('force')
5182 if not pats and not after:
5188 if not pats and not after:
5183 raise util.Abort(_('no files specified'))
5189 raise util.Abort(_('no files specified'))
5184
5190
5185 m = scmutil.match(repo[None], pats, opts)
5191 m = scmutil.match(repo[None], pats, opts)
5186 subrepos = opts.get('subrepos')
5192 subrepos = opts.get('subrepos')
5187 return cmdutil.remove(ui, repo, m, "", after, force, subrepos)
5193 return cmdutil.remove(ui, repo, m, "", after, force, subrepos)
5188
5194
5189 @command('rename|move|mv',
5195 @command('rename|move|mv',
5190 [('A', 'after', None, _('record a rename that has already occurred')),
5196 [('A', 'after', None, _('record a rename that has already occurred')),
5191 ('f', 'force', None, _('forcibly copy over an existing managed file')),
5197 ('f', 'force', None, _('forcibly copy over an existing managed file')),
5192 ] + walkopts + dryrunopts,
5198 ] + walkopts + dryrunopts,
5193 _('[OPTION]... SOURCE... DEST'))
5199 _('[OPTION]... SOURCE... DEST'))
5194 def rename(ui, repo, *pats, **opts):
5200 def rename(ui, repo, *pats, **opts):
5195 """rename files; equivalent of copy + remove
5201 """rename files; equivalent of copy + remove
5196
5202
5197 Mark dest as copies of sources; mark sources for deletion. If dest
5203 Mark dest as copies of sources; mark sources for deletion. If dest
5198 is a directory, copies are put in that directory. If dest is a
5204 is a directory, copies are put in that directory. If dest is a
5199 file, there can only be one source.
5205 file, there can only be one source.
5200
5206
5201 By default, this command copies the contents of files as they
5207 By default, this command copies the contents of files as they
5202 exist in the working directory. If invoked with -A/--after, the
5208 exist in the working directory. If invoked with -A/--after, the
5203 operation is recorded, but no copying is performed.
5209 operation is recorded, but no copying is performed.
5204
5210
5205 This command takes effect at the next commit. To undo a rename
5211 This command takes effect at the next commit. To undo a rename
5206 before that, see :hg:`revert`.
5212 before that, see :hg:`revert`.
5207
5213
5208 Returns 0 on success, 1 if errors are encountered.
5214 Returns 0 on success, 1 if errors are encountered.
5209 """
5215 """
5210 wlock = repo.wlock(False)
5216 wlock = repo.wlock(False)
5211 try:
5217 try:
5212 return cmdutil.copy(ui, repo, pats, opts, rename=True)
5218 return cmdutil.copy(ui, repo, pats, opts, rename=True)
5213 finally:
5219 finally:
5214 wlock.release()
5220 wlock.release()
5215
5221
5216 @command('resolve',
5222 @command('resolve',
5217 [('a', 'all', None, _('select all unresolved files')),
5223 [('a', 'all', None, _('select all unresolved files')),
5218 ('l', 'list', None, _('list state of files needing merge')),
5224 ('l', 'list', None, _('list state of files needing merge')),
5219 ('m', 'mark', None, _('mark files as resolved')),
5225 ('m', 'mark', None, _('mark files as resolved')),
5220 ('u', 'unmark', None, _('mark files as unresolved')),
5226 ('u', 'unmark', None, _('mark files as unresolved')),
5221 ('n', 'no-status', None, _('hide status prefix'))]
5227 ('n', 'no-status', None, _('hide status prefix'))]
5222 + mergetoolopts + walkopts,
5228 + mergetoolopts + walkopts,
5223 _('[OPTION]... [FILE]...'),
5229 _('[OPTION]... [FILE]...'),
5224 inferrepo=True)
5230 inferrepo=True)
5225 def resolve(ui, repo, *pats, **opts):
5231 def resolve(ui, repo, *pats, **opts):
5226 """redo merges or set/view the merge status of files
5232 """redo merges or set/view the merge status of files
5227
5233
5228 Merges with unresolved conflicts are often the result of
5234 Merges with unresolved conflicts are often the result of
5229 non-interactive merging using the ``internal:merge`` configuration
5235 non-interactive merging using the ``internal:merge`` configuration
5230 setting, or a command-line merge tool like ``diff3``. The resolve
5236 setting, or a command-line merge tool like ``diff3``. The resolve
5231 command is used to manage the files involved in a merge, after
5237 command is used to manage the files involved in a merge, after
5232 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
5238 :hg:`merge` has been run, and before :hg:`commit` is run (i.e. the
5233 working directory must have two parents). See :hg:`help
5239 working directory must have two parents). See :hg:`help
5234 merge-tools` for information on configuring merge tools.
5240 merge-tools` for information on configuring merge tools.
5235
5241
5236 The resolve command can be used in the following ways:
5242 The resolve command can be used in the following ways:
5237
5243
5238 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
5244 - :hg:`resolve [--tool TOOL] FILE...`: attempt to re-merge the specified
5239 files, discarding any previous merge attempts. Re-merging is not
5245 files, discarding any previous merge attempts. Re-merging is not
5240 performed for files already marked as resolved. Use ``--all/-a``
5246 performed for files already marked as resolved. Use ``--all/-a``
5241 to select all unresolved files. ``--tool`` can be used to specify
5247 to select all unresolved files. ``--tool`` can be used to specify
5242 the merge tool used for the given files. It overrides the HGMERGE
5248 the merge tool used for the given files. It overrides the HGMERGE
5243 environment variable and your configuration files. Previous file
5249 environment variable and your configuration files. Previous file
5244 contents are saved with a ``.orig`` suffix.
5250 contents are saved with a ``.orig`` suffix.
5245
5251
5246 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
5252 - :hg:`resolve -m [FILE]`: mark a file as having been resolved
5247 (e.g. after having manually fixed-up the files). The default is
5253 (e.g. after having manually fixed-up the files). The default is
5248 to mark all unresolved files.
5254 to mark all unresolved files.
5249
5255
5250 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
5256 - :hg:`resolve -u [FILE]...`: mark a file as unresolved. The
5251 default is to mark all resolved files.
5257 default is to mark all resolved files.
5252
5258
5253 - :hg:`resolve -l`: list files which had or still have conflicts.
5259 - :hg:`resolve -l`: list files which had or still have conflicts.
5254 In the printed list, ``U`` = unresolved and ``R`` = resolved.
5260 In the printed list, ``U`` = unresolved and ``R`` = resolved.
5255
5261
5256 Note that Mercurial will not let you commit files with unresolved
5262 Note that Mercurial will not let you commit files with unresolved
5257 merge conflicts. You must use :hg:`resolve -m ...` before you can
5263 merge conflicts. You must use :hg:`resolve -m ...` before you can
5258 commit after a conflicting merge.
5264 commit after a conflicting merge.
5259
5265
5260 Returns 0 on success, 1 if any files fail a resolve attempt.
5266 Returns 0 on success, 1 if any files fail a resolve attempt.
5261 """
5267 """
5262
5268
5263 all, mark, unmark, show, nostatus = \
5269 all, mark, unmark, show, nostatus = \
5264 [opts.get(o) for o in 'all mark unmark list no_status'.split()]
5270 [opts.get(o) for o in 'all mark unmark list no_status'.split()]
5265
5271
5266 if (show and (mark or unmark)) or (mark and unmark):
5272 if (show and (mark or unmark)) or (mark and unmark):
5267 raise util.Abort(_("too many options specified"))
5273 raise util.Abort(_("too many options specified"))
5268 if pats and all:
5274 if pats and all:
5269 raise util.Abort(_("can't specify --all and patterns"))
5275 raise util.Abort(_("can't specify --all and patterns"))
5270 if not (all or pats or show or mark or unmark):
5276 if not (all or pats or show or mark or unmark):
5271 raise util.Abort(_('no files or directories specified'),
5277 raise util.Abort(_('no files or directories specified'),
5272 hint=('use --all to remerge all files'))
5278 hint=('use --all to remerge all files'))
5273
5279
5274 wlock = repo.wlock()
5280 wlock = repo.wlock()
5275 try:
5281 try:
5276 ms = mergemod.mergestate(repo)
5282 ms = mergemod.mergestate(repo)
5277
5283
5278 if not (ms.active() or repo.dirstate.p2() != nullid) and not show:
5284 if not (ms.active() or repo.dirstate.p2() != nullid) and not show:
5279 raise util.Abort(
5285 raise util.Abort(
5280 _('resolve command not applicable when not merging'))
5286 _('resolve command not applicable when not merging'))
5281
5287
5282 m = scmutil.match(repo[None], pats, opts)
5288 m = scmutil.match(repo[None], pats, opts)
5283 ret = 0
5289 ret = 0
5284 didwork = False
5290 didwork = False
5285
5291
5286 for f in ms:
5292 for f in ms:
5287 if not m(f):
5293 if not m(f):
5288 continue
5294 continue
5289
5295
5290 didwork = True
5296 didwork = True
5291
5297
5292 if show:
5298 if show:
5293 if nostatus:
5299 if nostatus:
5294 ui.write("%s\n" % f)
5300 ui.write("%s\n" % f)
5295 else:
5301 else:
5296 ui.write("%s %s\n" % (ms[f].upper(), f),
5302 ui.write("%s %s\n" % (ms[f].upper(), f),
5297 label='resolve.' +
5303 label='resolve.' +
5298 {'u': 'unresolved', 'r': 'resolved'}[ms[f]])
5304 {'u': 'unresolved', 'r': 'resolved'}[ms[f]])
5299 elif mark:
5305 elif mark:
5300 ms.mark(f, "r")
5306 ms.mark(f, "r")
5301 elif unmark:
5307 elif unmark:
5302 ms.mark(f, "u")
5308 ms.mark(f, "u")
5303 else:
5309 else:
5304 wctx = repo[None]
5310 wctx = repo[None]
5305
5311
5306 # backup pre-resolve (merge uses .orig for its own purposes)
5312 # backup pre-resolve (merge uses .orig for its own purposes)
5307 a = repo.wjoin(f)
5313 a = repo.wjoin(f)
5308 util.copyfile(a, a + ".resolve")
5314 util.copyfile(a, a + ".resolve")
5309
5315
5310 try:
5316 try:
5311 # resolve file
5317 # resolve file
5312 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
5318 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
5313 'resolve')
5319 'resolve')
5314 if ms.resolve(f, wctx):
5320 if ms.resolve(f, wctx):
5315 ret = 1
5321 ret = 1
5316 finally:
5322 finally:
5317 ui.setconfig('ui', 'forcemerge', '', 'resolve')
5323 ui.setconfig('ui', 'forcemerge', '', 'resolve')
5318 ms.commit()
5324 ms.commit()
5319
5325
5320 # replace filemerge's .orig file with our resolve file
5326 # replace filemerge's .orig file with our resolve file
5321 util.rename(a + ".resolve", a + ".orig")
5327 util.rename(a + ".resolve", a + ".orig")
5322
5328
5323 ms.commit()
5329 ms.commit()
5324
5330
5325 if not didwork and pats:
5331 if not didwork and pats:
5326 ui.warn(_("arguments do not match paths that need resolving\n"))
5332 ui.warn(_("arguments do not match paths that need resolving\n"))
5327
5333
5328 finally:
5334 finally:
5329 wlock.release()
5335 wlock.release()
5330
5336
5331 # Nudge users into finishing an unfinished operation. We don't print
5337 # Nudge users into finishing an unfinished operation. We don't print
5332 # this with the list/show operation because we want list/show to remain
5338 # this with the list/show operation because we want list/show to remain
5333 # machine readable.
5339 # machine readable.
5334 if not list(ms.unresolved()) and not show:
5340 if not list(ms.unresolved()) and not show:
5335 ui.status(_('(no more unresolved files)\n'))
5341 ui.status(_('(no more unresolved files)\n'))
5336
5342
5337 return ret
5343 return ret
5338
5344
5339 @command('revert',
5345 @command('revert',
5340 [('a', 'all', None, _('revert all changes when no arguments given')),
5346 [('a', 'all', None, _('revert all changes when no arguments given')),
5341 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5347 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
5342 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
5348 ('r', 'rev', '', _('revert to the specified revision'), _('REV')),
5343 ('C', 'no-backup', None, _('do not save backup copies of files')),
5349 ('C', 'no-backup', None, _('do not save backup copies of files')),
5344 ] + walkopts + dryrunopts,
5350 ] + walkopts + dryrunopts,
5345 _('[OPTION]... [-r REV] [NAME]...'))
5351 _('[OPTION]... [-r REV] [NAME]...'))
5346 def revert(ui, repo, *pats, **opts):
5352 def revert(ui, repo, *pats, **opts):
5347 """restore files to their checkout state
5353 """restore files to their checkout state
5348
5354
5349 .. note::
5355 .. note::
5350
5356
5351 To check out earlier revisions, you should use :hg:`update REV`.
5357 To check out earlier revisions, you should use :hg:`update REV`.
5352 To cancel an uncommitted merge (and lose your changes),
5358 To cancel an uncommitted merge (and lose your changes),
5353 use :hg:`update --clean .`.
5359 use :hg:`update --clean .`.
5354
5360
5355 With no revision specified, revert the specified files or directories
5361 With no revision specified, revert the specified files or directories
5356 to the contents they had in the parent of the working directory.
5362 to the contents they had in the parent of the working directory.
5357 This restores the contents of files to an unmodified
5363 This restores the contents of files to an unmodified
5358 state and unschedules adds, removes, copies, and renames. If the
5364 state and unschedules adds, removes, copies, and renames. If the
5359 working directory has two parents, you must explicitly specify a
5365 working directory has two parents, you must explicitly specify a
5360 revision.
5366 revision.
5361
5367
5362 Using the -r/--rev or -d/--date options, revert the given files or
5368 Using the -r/--rev or -d/--date options, revert the given files or
5363 directories to their states as of a specific revision. Because
5369 directories to their states as of a specific revision. Because
5364 revert does not change the working directory parents, this will
5370 revert does not change the working directory parents, this will
5365 cause these files to appear modified. This can be helpful to "back
5371 cause these files to appear modified. This can be helpful to "back
5366 out" some or all of an earlier change. See :hg:`backout` for a
5372 out" some or all of an earlier change. See :hg:`backout` for a
5367 related method.
5373 related method.
5368
5374
5369 Modified files are saved with a .orig suffix before reverting.
5375 Modified files are saved with a .orig suffix before reverting.
5370 To disable these backups, use --no-backup.
5376 To disable these backups, use --no-backup.
5371
5377
5372 See :hg:`help dates` for a list of formats valid for -d/--date.
5378 See :hg:`help dates` for a list of formats valid for -d/--date.
5373
5379
5374 Returns 0 on success.
5380 Returns 0 on success.
5375 """
5381 """
5376
5382
5377 if opts.get("date"):
5383 if opts.get("date"):
5378 if opts.get("rev"):
5384 if opts.get("rev"):
5379 raise util.Abort(_("you can't specify a revision and a date"))
5385 raise util.Abort(_("you can't specify a revision and a date"))
5380 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
5386 opts["rev"] = cmdutil.finddate(ui, repo, opts["date"])
5381
5387
5382 parent, p2 = repo.dirstate.parents()
5388 parent, p2 = repo.dirstate.parents()
5383 if not opts.get('rev') and p2 != nullid:
5389 if not opts.get('rev') and p2 != nullid:
5384 # revert after merge is a trap for new users (issue2915)
5390 # revert after merge is a trap for new users (issue2915)
5385 raise util.Abort(_('uncommitted merge with no revision specified'),
5391 raise util.Abort(_('uncommitted merge with no revision specified'),
5386 hint=_('use "hg update" or see "hg help revert"'))
5392 hint=_('use "hg update" or see "hg help revert"'))
5387
5393
5388 ctx = scmutil.revsingle(repo, opts.get('rev'))
5394 ctx = scmutil.revsingle(repo, opts.get('rev'))
5389
5395
5390 if not pats and not opts.get('all'):
5396 if not pats and not opts.get('all'):
5391 msg = _("no files or directories specified")
5397 msg = _("no files or directories specified")
5392 if p2 != nullid:
5398 if p2 != nullid:
5393 hint = _("uncommitted merge, use --all to discard all changes,"
5399 hint = _("uncommitted merge, use --all to discard all changes,"
5394 " or 'hg update -C .' to abort the merge")
5400 " or 'hg update -C .' to abort the merge")
5395 raise util.Abort(msg, hint=hint)
5401 raise util.Abort(msg, hint=hint)
5396 dirty = util.any(repo.status())
5402 dirty = util.any(repo.status())
5397 node = ctx.node()
5403 node = ctx.node()
5398 if node != parent:
5404 if node != parent:
5399 if dirty:
5405 if dirty:
5400 hint = _("uncommitted changes, use --all to discard all"
5406 hint = _("uncommitted changes, use --all to discard all"
5401 " changes, or 'hg update %s' to update") % ctx.rev()
5407 " changes, or 'hg update %s' to update") % ctx.rev()
5402 else:
5408 else:
5403 hint = _("use --all to revert all files,"
5409 hint = _("use --all to revert all files,"
5404 " or 'hg update %s' to update") % ctx.rev()
5410 " or 'hg update %s' to update") % ctx.rev()
5405 elif dirty:
5411 elif dirty:
5406 hint = _("uncommitted changes, use --all to discard all changes")
5412 hint = _("uncommitted changes, use --all to discard all changes")
5407 else:
5413 else:
5408 hint = _("use --all to revert all files")
5414 hint = _("use --all to revert all files")
5409 raise util.Abort(msg, hint=hint)
5415 raise util.Abort(msg, hint=hint)
5410
5416
5411 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats, **opts)
5417 return cmdutil.revert(ui, repo, ctx, (parent, p2), *pats, **opts)
5412
5418
5413 @command('rollback', dryrunopts +
5419 @command('rollback', dryrunopts +
5414 [('f', 'force', False, _('ignore safety measures'))])
5420 [('f', 'force', False, _('ignore safety measures'))])
5415 def rollback(ui, repo, **opts):
5421 def rollback(ui, repo, **opts):
5416 """roll back the last transaction (DANGEROUS) (DEPRECATED)
5422 """roll back the last transaction (DANGEROUS) (DEPRECATED)
5417
5423
5418 Please use :hg:`commit --amend` instead of rollback to correct
5424 Please use :hg:`commit --amend` instead of rollback to correct
5419 mistakes in the last commit.
5425 mistakes in the last commit.
5420
5426
5421 This command should be used with care. There is only one level of
5427 This command should be used with care. There is only one level of
5422 rollback, and there is no way to undo a rollback. It will also
5428 rollback, and there is no way to undo a rollback. It will also
5423 restore the dirstate at the time of the last transaction, losing
5429 restore the dirstate at the time of the last transaction, losing
5424 any dirstate changes since that time. This command does not alter
5430 any dirstate changes since that time. This command does not alter
5425 the working directory.
5431 the working directory.
5426
5432
5427 Transactions are used to encapsulate the effects of all commands
5433 Transactions are used to encapsulate the effects of all commands
5428 that create new changesets or propagate existing changesets into a
5434 that create new changesets or propagate existing changesets into a
5429 repository.
5435 repository.
5430
5436
5431 .. container:: verbose
5437 .. container:: verbose
5432
5438
5433 For example, the following commands are transactional, and their
5439 For example, the following commands are transactional, and their
5434 effects can be rolled back:
5440 effects can be rolled back:
5435
5441
5436 - commit
5442 - commit
5437 - import
5443 - import
5438 - pull
5444 - pull
5439 - push (with this repository as the destination)
5445 - push (with this repository as the destination)
5440 - unbundle
5446 - unbundle
5441
5447
5442 To avoid permanent data loss, rollback will refuse to rollback a
5448 To avoid permanent data loss, rollback will refuse to rollback a
5443 commit transaction if it isn't checked out. Use --force to
5449 commit transaction if it isn't checked out. Use --force to
5444 override this protection.
5450 override this protection.
5445
5451
5446 This command is not intended for use on public repositories. Once
5452 This command is not intended for use on public repositories. Once
5447 changes are visible for pull by other users, rolling a transaction
5453 changes are visible for pull by other users, rolling a transaction
5448 back locally is ineffective (someone else may already have pulled
5454 back locally is ineffective (someone else may already have pulled
5449 the changes). Furthermore, a race is possible with readers of the
5455 the changes). Furthermore, a race is possible with readers of the
5450 repository; for example an in-progress pull from the repository
5456 repository; for example an in-progress pull from the repository
5451 may fail if a rollback is performed.
5457 may fail if a rollback is performed.
5452
5458
5453 Returns 0 on success, 1 if no rollback data is available.
5459 Returns 0 on success, 1 if no rollback data is available.
5454 """
5460 """
5455 return repo.rollback(dryrun=opts.get('dry_run'),
5461 return repo.rollback(dryrun=opts.get('dry_run'),
5456 force=opts.get('force'))
5462 force=opts.get('force'))
5457
5463
5458 @command('root', [])
5464 @command('root', [])
5459 def root(ui, repo):
5465 def root(ui, repo):
5460 """print the root (top) of the current working directory
5466 """print the root (top) of the current working directory
5461
5467
5462 Print the root directory of the current repository.
5468 Print the root directory of the current repository.
5463
5469
5464 Returns 0 on success.
5470 Returns 0 on success.
5465 """
5471 """
5466 ui.write(repo.root + "\n")
5472 ui.write(repo.root + "\n")
5467
5473
5468 @command('^serve',
5474 @command('^serve',
5469 [('A', 'accesslog', '', _('name of access log file to write to'),
5475 [('A', 'accesslog', '', _('name of access log file to write to'),
5470 _('FILE')),
5476 _('FILE')),
5471 ('d', 'daemon', None, _('run server in background')),
5477 ('d', 'daemon', None, _('run server in background')),
5472 ('', 'daemon-pipefds', '', _('used internally by daemon mode'), _('FILE')),
5478 ('', 'daemon-pipefds', '', _('used internally by daemon mode'), _('FILE')),
5473 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
5479 ('E', 'errorlog', '', _('name of error log file to write to'), _('FILE')),
5474 # use string type, then we can check if something was passed
5480 # use string type, then we can check if something was passed
5475 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
5481 ('p', 'port', '', _('port to listen on (default: 8000)'), _('PORT')),
5476 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
5482 ('a', 'address', '', _('address to listen on (default: all interfaces)'),
5477 _('ADDR')),
5483 _('ADDR')),
5478 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
5484 ('', 'prefix', '', _('prefix path to serve from (default: server root)'),
5479 _('PREFIX')),
5485 _('PREFIX')),
5480 ('n', 'name', '',
5486 ('n', 'name', '',
5481 _('name to show in web pages (default: working directory)'), _('NAME')),
5487 _('name to show in web pages (default: working directory)'), _('NAME')),
5482 ('', 'web-conf', '',
5488 ('', 'web-conf', '',
5483 _('name of the hgweb config file (see "hg help hgweb")'), _('FILE')),
5489 _('name of the hgweb config file (see "hg help hgweb")'), _('FILE')),
5484 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
5490 ('', 'webdir-conf', '', _('name of the hgweb config file (DEPRECATED)'),
5485 _('FILE')),
5491 _('FILE')),
5486 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
5492 ('', 'pid-file', '', _('name of file to write process ID to'), _('FILE')),
5487 ('', 'stdio', None, _('for remote clients')),
5493 ('', 'stdio', None, _('for remote clients')),
5488 ('', 'cmdserver', '', _('for remote clients'), _('MODE')),
5494 ('', 'cmdserver', '', _('for remote clients'), _('MODE')),
5489 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
5495 ('t', 'templates', '', _('web templates to use'), _('TEMPLATE')),
5490 ('', 'style', '', _('template style to use'), _('STYLE')),
5496 ('', 'style', '', _('template style to use'), _('STYLE')),
5491 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
5497 ('6', 'ipv6', None, _('use IPv6 in addition to IPv4')),
5492 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))],
5498 ('', 'certificate', '', _('SSL certificate file'), _('FILE'))],
5493 _('[OPTION]...'),
5499 _('[OPTION]...'),
5494 optionalrepo=True)
5500 optionalrepo=True)
5495 def serve(ui, repo, **opts):
5501 def serve(ui, repo, **opts):
5496 """start stand-alone webserver
5502 """start stand-alone webserver
5497
5503
5498 Start a local HTTP repository browser and pull server. You can use
5504 Start a local HTTP repository browser and pull server. You can use
5499 this for ad-hoc sharing and browsing of repositories. It is
5505 this for ad-hoc sharing and browsing of repositories. It is
5500 recommended to use a real web server to serve a repository for
5506 recommended to use a real web server to serve a repository for
5501 longer periods of time.
5507 longer periods of time.
5502
5508
5503 Please note that the server does not implement access control.
5509 Please note that the server does not implement access control.
5504 This means that, by default, anybody can read from the server and
5510 This means that, by default, anybody can read from the server and
5505 nobody can write to it by default. Set the ``web.allow_push``
5511 nobody can write to it by default. Set the ``web.allow_push``
5506 option to ``*`` to allow everybody to push to the server. You
5512 option to ``*`` to allow everybody to push to the server. You
5507 should use a real web server if you need to authenticate users.
5513 should use a real web server if you need to authenticate users.
5508
5514
5509 By default, the server logs accesses to stdout and errors to
5515 By default, the server logs accesses to stdout and errors to
5510 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
5516 stderr. Use the -A/--accesslog and -E/--errorlog options to log to
5511 files.
5517 files.
5512
5518
5513 To have the server choose a free port number to listen on, specify
5519 To have the server choose a free port number to listen on, specify
5514 a port number of 0; in this case, the server will print the port
5520 a port number of 0; in this case, the server will print the port
5515 number it uses.
5521 number it uses.
5516
5522
5517 Returns 0 on success.
5523 Returns 0 on success.
5518 """
5524 """
5519
5525
5520 if opts["stdio"] and opts["cmdserver"]:
5526 if opts["stdio"] and opts["cmdserver"]:
5521 raise util.Abort(_("cannot use --stdio with --cmdserver"))
5527 raise util.Abort(_("cannot use --stdio with --cmdserver"))
5522
5528
5523 if opts["stdio"]:
5529 if opts["stdio"]:
5524 if repo is None:
5530 if repo is None:
5525 raise error.RepoError(_("there is no Mercurial repository here"
5531 raise error.RepoError(_("there is no Mercurial repository here"
5526 " (.hg not found)"))
5532 " (.hg not found)"))
5527 s = sshserver.sshserver(ui, repo)
5533 s = sshserver.sshserver(ui, repo)
5528 s.serve_forever()
5534 s.serve_forever()
5529
5535
5530 if opts["cmdserver"]:
5536 if opts["cmdserver"]:
5531 service = commandserver.createservice(ui, repo, opts)
5537 service = commandserver.createservice(ui, repo, opts)
5532 return cmdutil.service(opts, initfn=service.init, runfn=service.run)
5538 return cmdutil.service(opts, initfn=service.init, runfn=service.run)
5533
5539
5534 # this way we can check if something was given in the command-line
5540 # this way we can check if something was given in the command-line
5535 if opts.get('port'):
5541 if opts.get('port'):
5536 opts['port'] = util.getport(opts.get('port'))
5542 opts['port'] = util.getport(opts.get('port'))
5537
5543
5538 baseui = repo and repo.baseui or ui
5544 baseui = repo and repo.baseui or ui
5539 optlist = ("name templates style address port prefix ipv6"
5545 optlist = ("name templates style address port prefix ipv6"
5540 " accesslog errorlog certificate encoding")
5546 " accesslog errorlog certificate encoding")
5541 for o in optlist.split():
5547 for o in optlist.split():
5542 val = opts.get(o, '')
5548 val = opts.get(o, '')
5543 if val in (None, ''): # should check against default options instead
5549 if val in (None, ''): # should check against default options instead
5544 continue
5550 continue
5545 baseui.setconfig("web", o, val, 'serve')
5551 baseui.setconfig("web", o, val, 'serve')
5546 if repo and repo.ui != baseui:
5552 if repo and repo.ui != baseui:
5547 repo.ui.setconfig("web", o, val, 'serve')
5553 repo.ui.setconfig("web", o, val, 'serve')
5548
5554
5549 o = opts.get('web_conf') or opts.get('webdir_conf')
5555 o = opts.get('web_conf') or opts.get('webdir_conf')
5550 if not o:
5556 if not o:
5551 if not repo:
5557 if not repo:
5552 raise error.RepoError(_("there is no Mercurial repository"
5558 raise error.RepoError(_("there is no Mercurial repository"
5553 " here (.hg not found)"))
5559 " here (.hg not found)"))
5554 o = repo
5560 o = repo
5555
5561
5556 app = hgweb.hgweb(o, baseui=baseui)
5562 app = hgweb.hgweb(o, baseui=baseui)
5557 service = httpservice(ui, app, opts)
5563 service = httpservice(ui, app, opts)
5558 cmdutil.service(opts, initfn=service.init, runfn=service.run)
5564 cmdutil.service(opts, initfn=service.init, runfn=service.run)
5559
5565
5560 class httpservice(object):
5566 class httpservice(object):
5561 def __init__(self, ui, app, opts):
5567 def __init__(self, ui, app, opts):
5562 self.ui = ui
5568 self.ui = ui
5563 self.app = app
5569 self.app = app
5564 self.opts = opts
5570 self.opts = opts
5565
5571
5566 def init(self):
5572 def init(self):
5567 util.setsignalhandler()
5573 util.setsignalhandler()
5568 self.httpd = hgweb_server.create_server(self.ui, self.app)
5574 self.httpd = hgweb_server.create_server(self.ui, self.app)
5569
5575
5570 if self.opts['port'] and not self.ui.verbose:
5576 if self.opts['port'] and not self.ui.verbose:
5571 return
5577 return
5572
5578
5573 if self.httpd.prefix:
5579 if self.httpd.prefix:
5574 prefix = self.httpd.prefix.strip('/') + '/'
5580 prefix = self.httpd.prefix.strip('/') + '/'
5575 else:
5581 else:
5576 prefix = ''
5582 prefix = ''
5577
5583
5578 port = ':%d' % self.httpd.port
5584 port = ':%d' % self.httpd.port
5579 if port == ':80':
5585 if port == ':80':
5580 port = ''
5586 port = ''
5581
5587
5582 bindaddr = self.httpd.addr
5588 bindaddr = self.httpd.addr
5583 if bindaddr == '0.0.0.0':
5589 if bindaddr == '0.0.0.0':
5584 bindaddr = '*'
5590 bindaddr = '*'
5585 elif ':' in bindaddr: # IPv6
5591 elif ':' in bindaddr: # IPv6
5586 bindaddr = '[%s]' % bindaddr
5592 bindaddr = '[%s]' % bindaddr
5587
5593
5588 fqaddr = self.httpd.fqaddr
5594 fqaddr = self.httpd.fqaddr
5589 if ':' in fqaddr:
5595 if ':' in fqaddr:
5590 fqaddr = '[%s]' % fqaddr
5596 fqaddr = '[%s]' % fqaddr
5591 if self.opts['port']:
5597 if self.opts['port']:
5592 write = self.ui.status
5598 write = self.ui.status
5593 else:
5599 else:
5594 write = self.ui.write
5600 write = self.ui.write
5595 write(_('listening at http://%s%s/%s (bound to %s:%d)\n') %
5601 write(_('listening at http://%s%s/%s (bound to %s:%d)\n') %
5596 (fqaddr, port, prefix, bindaddr, self.httpd.port))
5602 (fqaddr, port, prefix, bindaddr, self.httpd.port))
5597 self.ui.flush() # avoid buffering of status message
5603 self.ui.flush() # avoid buffering of status message
5598
5604
5599 def run(self):
5605 def run(self):
5600 self.httpd.serve_forever()
5606 self.httpd.serve_forever()
5601
5607
5602
5608
5603 @command('^status|st',
5609 @command('^status|st',
5604 [('A', 'all', None, _('show status of all files')),
5610 [('A', 'all', None, _('show status of all files')),
5605 ('m', 'modified', None, _('show only modified files')),
5611 ('m', 'modified', None, _('show only modified files')),
5606 ('a', 'added', None, _('show only added files')),
5612 ('a', 'added', None, _('show only added files')),
5607 ('r', 'removed', None, _('show only removed files')),
5613 ('r', 'removed', None, _('show only removed files')),
5608 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
5614 ('d', 'deleted', None, _('show only deleted (but tracked) files')),
5609 ('c', 'clean', None, _('show only files without changes')),
5615 ('c', 'clean', None, _('show only files without changes')),
5610 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
5616 ('u', 'unknown', None, _('show only unknown (not tracked) files')),
5611 ('i', 'ignored', None, _('show only ignored files')),
5617 ('i', 'ignored', None, _('show only ignored files')),
5612 ('n', 'no-status', None, _('hide status prefix')),
5618 ('n', 'no-status', None, _('hide status prefix')),
5613 ('C', 'copies', None, _('show source of copied files')),
5619 ('C', 'copies', None, _('show source of copied files')),
5614 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
5620 ('0', 'print0', None, _('end filenames with NUL, for use with xargs')),
5615 ('', 'rev', [], _('show difference from revision'), _('REV')),
5621 ('', 'rev', [], _('show difference from revision'), _('REV')),
5616 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
5622 ('', 'change', '', _('list the changed files of a revision'), _('REV')),
5617 ] + walkopts + subrepoopts + formatteropts,
5623 ] + walkopts + subrepoopts + formatteropts,
5618 _('[OPTION]... [FILE]...'),
5624 _('[OPTION]... [FILE]...'),
5619 inferrepo=True)
5625 inferrepo=True)
5620 def status(ui, repo, *pats, **opts):
5626 def status(ui, repo, *pats, **opts):
5621 """show changed files in the working directory
5627 """show changed files in the working directory
5622
5628
5623 Show status of files in the repository. If names are given, only
5629 Show status of files in the repository. If names are given, only
5624 files that match are shown. Files that are clean or ignored or
5630 files that match are shown. Files that are clean or ignored or
5625 the source of a copy/move operation, are not listed unless
5631 the source of a copy/move operation, are not listed unless
5626 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
5632 -c/--clean, -i/--ignored, -C/--copies or -A/--all are given.
5627 Unless options described with "show only ..." are given, the
5633 Unless options described with "show only ..." are given, the
5628 options -mardu are used.
5634 options -mardu are used.
5629
5635
5630 Option -q/--quiet hides untracked (unknown and ignored) files
5636 Option -q/--quiet hides untracked (unknown and ignored) files
5631 unless explicitly requested with -u/--unknown or -i/--ignored.
5637 unless explicitly requested with -u/--unknown or -i/--ignored.
5632
5638
5633 .. note::
5639 .. note::
5634
5640
5635 status may appear to disagree with diff if permissions have
5641 status may appear to disagree with diff if permissions have
5636 changed or a merge has occurred. The standard diff format does
5642 changed or a merge has occurred. The standard diff format does
5637 not report permission changes and diff only reports changes
5643 not report permission changes and diff only reports changes
5638 relative to one merge parent.
5644 relative to one merge parent.
5639
5645
5640 If one revision is given, it is used as the base revision.
5646 If one revision is given, it is used as the base revision.
5641 If two revisions are given, the differences between them are
5647 If two revisions are given, the differences between them are
5642 shown. The --change option can also be used as a shortcut to list
5648 shown. The --change option can also be used as a shortcut to list
5643 the changed files of a revision from its first parent.
5649 the changed files of a revision from its first parent.
5644
5650
5645 The codes used to show the status of files are::
5651 The codes used to show the status of files are::
5646
5652
5647 M = modified
5653 M = modified
5648 A = added
5654 A = added
5649 R = removed
5655 R = removed
5650 C = clean
5656 C = clean
5651 ! = missing (deleted by non-hg command, but still tracked)
5657 ! = missing (deleted by non-hg command, but still tracked)
5652 ? = not tracked
5658 ? = not tracked
5653 I = ignored
5659 I = ignored
5654 = origin of the previous file (with --copies)
5660 = origin of the previous file (with --copies)
5655
5661
5656 .. container:: verbose
5662 .. container:: verbose
5657
5663
5658 Examples:
5664 Examples:
5659
5665
5660 - show changes in the working directory relative to a
5666 - show changes in the working directory relative to a
5661 changeset::
5667 changeset::
5662
5668
5663 hg status --rev 9353
5669 hg status --rev 9353
5664
5670
5665 - show all changes including copies in an existing changeset::
5671 - show all changes including copies in an existing changeset::
5666
5672
5667 hg status --copies --change 9353
5673 hg status --copies --change 9353
5668
5674
5669 - get a NUL separated list of added files, suitable for xargs::
5675 - get a NUL separated list of added files, suitable for xargs::
5670
5676
5671 hg status -an0
5677 hg status -an0
5672
5678
5673 Returns 0 on success.
5679 Returns 0 on success.
5674 """
5680 """
5675
5681
5676 revs = opts.get('rev')
5682 revs = opts.get('rev')
5677 change = opts.get('change')
5683 change = opts.get('change')
5678
5684
5679 if revs and change:
5685 if revs and change:
5680 msg = _('cannot specify --rev and --change at the same time')
5686 msg = _('cannot specify --rev and --change at the same time')
5681 raise util.Abort(msg)
5687 raise util.Abort(msg)
5682 elif change:
5688 elif change:
5683 node2 = scmutil.revsingle(repo, change, None).node()
5689 node2 = scmutil.revsingle(repo, change, None).node()
5684 node1 = repo[node2].p1().node()
5690 node1 = repo[node2].p1().node()
5685 else:
5691 else:
5686 node1, node2 = scmutil.revpair(repo, revs)
5692 node1, node2 = scmutil.revpair(repo, revs)
5687
5693
5688 cwd = (pats and repo.getcwd()) or ''
5694 cwd = (pats and repo.getcwd()) or ''
5689 end = opts.get('print0') and '\0' or '\n'
5695 end = opts.get('print0') and '\0' or '\n'
5690 copy = {}
5696 copy = {}
5691 states = 'modified added removed deleted unknown ignored clean'.split()
5697 states = 'modified added removed deleted unknown ignored clean'.split()
5692 show = [k for k in states if opts.get(k)]
5698 show = [k for k in states if opts.get(k)]
5693 if opts.get('all'):
5699 if opts.get('all'):
5694 show += ui.quiet and (states[:4] + ['clean']) or states
5700 show += ui.quiet and (states[:4] + ['clean']) or states
5695 if not show:
5701 if not show:
5696 show = ui.quiet and states[:4] or states[:5]
5702 show = ui.quiet and states[:4] or states[:5]
5697
5703
5698 stat = repo.status(node1, node2, scmutil.match(repo[node2], pats, opts),
5704 stat = repo.status(node1, node2, scmutil.match(repo[node2], pats, opts),
5699 'ignored' in show, 'clean' in show, 'unknown' in show,
5705 'ignored' in show, 'clean' in show, 'unknown' in show,
5700 opts.get('subrepos'))
5706 opts.get('subrepos'))
5701 changestates = zip(states, 'MAR!?IC', stat)
5707 changestates = zip(states, 'MAR!?IC', stat)
5702
5708
5703 if (opts.get('all') or opts.get('copies')) and not opts.get('no_status'):
5709 if (opts.get('all') or opts.get('copies')) and not opts.get('no_status'):
5704 copy = copies.pathcopies(repo[node1], repo[node2])
5710 copy = copies.pathcopies(repo[node1], repo[node2])
5705
5711
5706 fm = ui.formatter('status', opts)
5712 fm = ui.formatter('status', opts)
5707 fmt = '%s' + end
5713 fmt = '%s' + end
5708 showchar = not opts.get('no_status')
5714 showchar = not opts.get('no_status')
5709
5715
5710 for state, char, files in changestates:
5716 for state, char, files in changestates:
5711 if state in show:
5717 if state in show:
5712 label = 'status.' + state
5718 label = 'status.' + state
5713 for f in files:
5719 for f in files:
5714 fm.startitem()
5720 fm.startitem()
5715 fm.condwrite(showchar, 'status', '%s ', char, label=label)
5721 fm.condwrite(showchar, 'status', '%s ', char, label=label)
5716 fm.write('path', fmt, repo.pathto(f, cwd), label=label)
5722 fm.write('path', fmt, repo.pathto(f, cwd), label=label)
5717 if f in copy:
5723 if f in copy:
5718 fm.write("copy", ' %s' + end, repo.pathto(copy[f], cwd),
5724 fm.write("copy", ' %s' + end, repo.pathto(copy[f], cwd),
5719 label='status.copied')
5725 label='status.copied')
5720 fm.end()
5726 fm.end()
5721
5727
5722 @command('^summary|sum',
5728 @command('^summary|sum',
5723 [('', 'remote', None, _('check for push and pull'))], '[--remote]')
5729 [('', 'remote', None, _('check for push and pull'))], '[--remote]')
5724 def summary(ui, repo, **opts):
5730 def summary(ui, repo, **opts):
5725 """summarize working directory state
5731 """summarize working directory state
5726
5732
5727 This generates a brief summary of the working directory state,
5733 This generates a brief summary of the working directory state,
5728 including parents, branch, commit status, and available updates.
5734 including parents, branch, commit status, and available updates.
5729
5735
5730 With the --remote option, this will check the default paths for
5736 With the --remote option, this will check the default paths for
5731 incoming and outgoing changes. This can be time-consuming.
5737 incoming and outgoing changes. This can be time-consuming.
5732
5738
5733 Returns 0 on success.
5739 Returns 0 on success.
5734 """
5740 """
5735
5741
5736 ctx = repo[None]
5742 ctx = repo[None]
5737 parents = ctx.parents()
5743 parents = ctx.parents()
5738 pnode = parents[0].node()
5744 pnode = parents[0].node()
5739 marks = []
5745 marks = []
5740
5746
5741 for p in parents:
5747 for p in parents:
5742 # label with log.changeset (instead of log.parent) since this
5748 # label with log.changeset (instead of log.parent) since this
5743 # shows a working directory parent *changeset*:
5749 # shows a working directory parent *changeset*:
5744 # i18n: column positioning for "hg summary"
5750 # i18n: column positioning for "hg summary"
5745 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
5751 ui.write(_('parent: %d:%s ') % (p.rev(), str(p)),
5746 label='log.changeset changeset.%s' % p.phasestr())
5752 label='log.changeset changeset.%s' % p.phasestr())
5747 ui.write(' '.join(p.tags()), label='log.tag')
5753 ui.write(' '.join(p.tags()), label='log.tag')
5748 if p.bookmarks():
5754 if p.bookmarks():
5749 marks.extend(p.bookmarks())
5755 marks.extend(p.bookmarks())
5750 if p.rev() == -1:
5756 if p.rev() == -1:
5751 if not len(repo):
5757 if not len(repo):
5752 ui.write(_(' (empty repository)'))
5758 ui.write(_(' (empty repository)'))
5753 else:
5759 else:
5754 ui.write(_(' (no revision checked out)'))
5760 ui.write(_(' (no revision checked out)'))
5755 ui.write('\n')
5761 ui.write('\n')
5756 if p.description():
5762 if p.description():
5757 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
5763 ui.status(' ' + p.description().splitlines()[0].strip() + '\n',
5758 label='log.summary')
5764 label='log.summary')
5759
5765
5760 branch = ctx.branch()
5766 branch = ctx.branch()
5761 bheads = repo.branchheads(branch)
5767 bheads = repo.branchheads(branch)
5762 # i18n: column positioning for "hg summary"
5768 # i18n: column positioning for "hg summary"
5763 m = _('branch: %s\n') % branch
5769 m = _('branch: %s\n') % branch
5764 if branch != 'default':
5770 if branch != 'default':
5765 ui.write(m, label='log.branch')
5771 ui.write(m, label='log.branch')
5766 else:
5772 else:
5767 ui.status(m, label='log.branch')
5773 ui.status(m, label='log.branch')
5768
5774
5769 if marks:
5775 if marks:
5770 current = repo._bookmarkcurrent
5776 current = repo._bookmarkcurrent
5771 # i18n: column positioning for "hg summary"
5777 # i18n: column positioning for "hg summary"
5772 ui.write(_('bookmarks:'), label='log.bookmark')
5778 ui.write(_('bookmarks:'), label='log.bookmark')
5773 if current is not None:
5779 if current is not None:
5774 if current in marks:
5780 if current in marks:
5775 ui.write(' *' + current, label='bookmarks.current')
5781 ui.write(' *' + current, label='bookmarks.current')
5776 marks.remove(current)
5782 marks.remove(current)
5777 else:
5783 else:
5778 ui.write(' [%s]' % current, label='bookmarks.current')
5784 ui.write(' [%s]' % current, label='bookmarks.current')
5779 for m in marks:
5785 for m in marks:
5780 ui.write(' ' + m, label='log.bookmark')
5786 ui.write(' ' + m, label='log.bookmark')
5781 ui.write('\n', label='log.bookmark')
5787 ui.write('\n', label='log.bookmark')
5782
5788
5783 status = repo.status(unknown=True)
5789 status = repo.status(unknown=True)
5784
5790
5785 c = repo.dirstate.copies()
5791 c = repo.dirstate.copies()
5786 copied, renamed = [], []
5792 copied, renamed = [], []
5787 for d, s in c.iteritems():
5793 for d, s in c.iteritems():
5788 if s in status.removed:
5794 if s in status.removed:
5789 status.removed.remove(s)
5795 status.removed.remove(s)
5790 renamed.append(d)
5796 renamed.append(d)
5791 else:
5797 else:
5792 copied.append(d)
5798 copied.append(d)
5793 if d in status.added:
5799 if d in status.added:
5794 status.added.remove(d)
5800 status.added.remove(d)
5795
5801
5796 ms = mergemod.mergestate(repo)
5802 ms = mergemod.mergestate(repo)
5797 unresolved = [f for f in ms if ms[f] == 'u']
5803 unresolved = [f for f in ms if ms[f] == 'u']
5798
5804
5799 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
5805 subs = [s for s in ctx.substate if ctx.sub(s).dirty()]
5800
5806
5801 labels = [(ui.label(_('%d modified'), 'status.modified'), status.modified),
5807 labels = [(ui.label(_('%d modified'), 'status.modified'), status.modified),
5802 (ui.label(_('%d added'), 'status.added'), status.added),
5808 (ui.label(_('%d added'), 'status.added'), status.added),
5803 (ui.label(_('%d removed'), 'status.removed'), status.removed),
5809 (ui.label(_('%d removed'), 'status.removed'), status.removed),
5804 (ui.label(_('%d renamed'), 'status.copied'), renamed),
5810 (ui.label(_('%d renamed'), 'status.copied'), renamed),
5805 (ui.label(_('%d copied'), 'status.copied'), copied),
5811 (ui.label(_('%d copied'), 'status.copied'), copied),
5806 (ui.label(_('%d deleted'), 'status.deleted'), status.deleted),
5812 (ui.label(_('%d deleted'), 'status.deleted'), status.deleted),
5807 (ui.label(_('%d unknown'), 'status.unknown'), status.unknown),
5813 (ui.label(_('%d unknown'), 'status.unknown'), status.unknown),
5808 (ui.label(_('%d unresolved'), 'resolve.unresolved'), unresolved),
5814 (ui.label(_('%d unresolved'), 'resolve.unresolved'), unresolved),
5809 (ui.label(_('%d subrepos'), 'status.modified'), subs)]
5815 (ui.label(_('%d subrepos'), 'status.modified'), subs)]
5810 t = []
5816 t = []
5811 for l, s in labels:
5817 for l, s in labels:
5812 if s:
5818 if s:
5813 t.append(l % len(s))
5819 t.append(l % len(s))
5814
5820
5815 t = ', '.join(t)
5821 t = ', '.join(t)
5816 cleanworkdir = False
5822 cleanworkdir = False
5817
5823
5818 if repo.vfs.exists('updatestate'):
5824 if repo.vfs.exists('updatestate'):
5819 t += _(' (interrupted update)')
5825 t += _(' (interrupted update)')
5820 elif len(parents) > 1:
5826 elif len(parents) > 1:
5821 t += _(' (merge)')
5827 t += _(' (merge)')
5822 elif branch != parents[0].branch():
5828 elif branch != parents[0].branch():
5823 t += _(' (new branch)')
5829 t += _(' (new branch)')
5824 elif (parents[0].closesbranch() and
5830 elif (parents[0].closesbranch() and
5825 pnode in repo.branchheads(branch, closed=True)):
5831 pnode in repo.branchheads(branch, closed=True)):
5826 t += _(' (head closed)')
5832 t += _(' (head closed)')
5827 elif not (status.modified or status.added or status.removed or renamed or
5833 elif not (status.modified or status.added or status.removed or renamed or
5828 copied or subs):
5834 copied or subs):
5829 t += _(' (clean)')
5835 t += _(' (clean)')
5830 cleanworkdir = True
5836 cleanworkdir = True
5831 elif pnode not in bheads:
5837 elif pnode not in bheads:
5832 t += _(' (new branch head)')
5838 t += _(' (new branch head)')
5833
5839
5834 if cleanworkdir:
5840 if cleanworkdir:
5835 # i18n: column positioning for "hg summary"
5841 # i18n: column positioning for "hg summary"
5836 ui.status(_('commit: %s\n') % t.strip())
5842 ui.status(_('commit: %s\n') % t.strip())
5837 else:
5843 else:
5838 # i18n: column positioning for "hg summary"
5844 # i18n: column positioning for "hg summary"
5839 ui.write(_('commit: %s\n') % t.strip())
5845 ui.write(_('commit: %s\n') % t.strip())
5840
5846
5841 # all ancestors of branch heads - all ancestors of parent = new csets
5847 # all ancestors of branch heads - all ancestors of parent = new csets
5842 new = len(repo.changelog.findmissing([pctx.node() for pctx in parents],
5848 new = len(repo.changelog.findmissing([pctx.node() for pctx in parents],
5843 bheads))
5849 bheads))
5844
5850
5845 if new == 0:
5851 if new == 0:
5846 # i18n: column positioning for "hg summary"
5852 # i18n: column positioning for "hg summary"
5847 ui.status(_('update: (current)\n'))
5853 ui.status(_('update: (current)\n'))
5848 elif pnode not in bheads:
5854 elif pnode not in bheads:
5849 # i18n: column positioning for "hg summary"
5855 # i18n: column positioning for "hg summary"
5850 ui.write(_('update: %d new changesets (update)\n') % new)
5856 ui.write(_('update: %d new changesets (update)\n') % new)
5851 else:
5857 else:
5852 # i18n: column positioning for "hg summary"
5858 # i18n: column positioning for "hg summary"
5853 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
5859 ui.write(_('update: %d new changesets, %d branch heads (merge)\n') %
5854 (new, len(bheads)))
5860 (new, len(bheads)))
5855
5861
5856 cmdutil.summaryhooks(ui, repo)
5862 cmdutil.summaryhooks(ui, repo)
5857
5863
5858 if opts.get('remote'):
5864 if opts.get('remote'):
5859 needsincoming, needsoutgoing = True, True
5865 needsincoming, needsoutgoing = True, True
5860 else:
5866 else:
5861 needsincoming, needsoutgoing = False, False
5867 needsincoming, needsoutgoing = False, False
5862 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
5868 for i, o in cmdutil.summaryremotehooks(ui, repo, opts, None):
5863 if i:
5869 if i:
5864 needsincoming = True
5870 needsincoming = True
5865 if o:
5871 if o:
5866 needsoutgoing = True
5872 needsoutgoing = True
5867 if not needsincoming and not needsoutgoing:
5873 if not needsincoming and not needsoutgoing:
5868 return
5874 return
5869
5875
5870 def getincoming():
5876 def getincoming():
5871 source, branches = hg.parseurl(ui.expandpath('default'))
5877 source, branches = hg.parseurl(ui.expandpath('default'))
5872 sbranch = branches[0]
5878 sbranch = branches[0]
5873 try:
5879 try:
5874 other = hg.peer(repo, {}, source)
5880 other = hg.peer(repo, {}, source)
5875 except error.RepoError:
5881 except error.RepoError:
5876 if opts.get('remote'):
5882 if opts.get('remote'):
5877 raise
5883 raise
5878 return source, sbranch, None, None, None
5884 return source, sbranch, None, None, None
5879 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
5885 revs, checkout = hg.addbranchrevs(repo, other, branches, None)
5880 if revs:
5886 if revs:
5881 revs = [other.lookup(rev) for rev in revs]
5887 revs = [other.lookup(rev) for rev in revs]
5882 ui.debug('comparing with %s\n' % util.hidepassword(source))
5888 ui.debug('comparing with %s\n' % util.hidepassword(source))
5883 repo.ui.pushbuffer()
5889 repo.ui.pushbuffer()
5884 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
5890 commoninc = discovery.findcommonincoming(repo, other, heads=revs)
5885 repo.ui.popbuffer()
5891 repo.ui.popbuffer()
5886 return source, sbranch, other, commoninc, commoninc[1]
5892 return source, sbranch, other, commoninc, commoninc[1]
5887
5893
5888 if needsincoming:
5894 if needsincoming:
5889 source, sbranch, sother, commoninc, incoming = getincoming()
5895 source, sbranch, sother, commoninc, incoming = getincoming()
5890 else:
5896 else:
5891 source = sbranch = sother = commoninc = incoming = None
5897 source = sbranch = sother = commoninc = incoming = None
5892
5898
5893 def getoutgoing():
5899 def getoutgoing():
5894 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
5900 dest, branches = hg.parseurl(ui.expandpath('default-push', 'default'))
5895 dbranch = branches[0]
5901 dbranch = branches[0]
5896 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
5902 revs, checkout = hg.addbranchrevs(repo, repo, branches, None)
5897 if source != dest:
5903 if source != dest:
5898 try:
5904 try:
5899 dother = hg.peer(repo, {}, dest)
5905 dother = hg.peer(repo, {}, dest)
5900 except error.RepoError:
5906 except error.RepoError:
5901 if opts.get('remote'):
5907 if opts.get('remote'):
5902 raise
5908 raise
5903 return dest, dbranch, None, None
5909 return dest, dbranch, None, None
5904 ui.debug('comparing with %s\n' % util.hidepassword(dest))
5910 ui.debug('comparing with %s\n' % util.hidepassword(dest))
5905 elif sother is None:
5911 elif sother is None:
5906 # there is no explicit destination peer, but source one is invalid
5912 # there is no explicit destination peer, but source one is invalid
5907 return dest, dbranch, None, None
5913 return dest, dbranch, None, None
5908 else:
5914 else:
5909 dother = sother
5915 dother = sother
5910 if (source != dest or (sbranch is not None and sbranch != dbranch)):
5916 if (source != dest or (sbranch is not None and sbranch != dbranch)):
5911 common = None
5917 common = None
5912 else:
5918 else:
5913 common = commoninc
5919 common = commoninc
5914 if revs:
5920 if revs:
5915 revs = [repo.lookup(rev) for rev in revs]
5921 revs = [repo.lookup(rev) for rev in revs]
5916 repo.ui.pushbuffer()
5922 repo.ui.pushbuffer()
5917 outgoing = discovery.findcommonoutgoing(repo, dother, onlyheads=revs,
5923 outgoing = discovery.findcommonoutgoing(repo, dother, onlyheads=revs,
5918 commoninc=common)
5924 commoninc=common)
5919 repo.ui.popbuffer()
5925 repo.ui.popbuffer()
5920 return dest, dbranch, dother, outgoing
5926 return dest, dbranch, dother, outgoing
5921
5927
5922 if needsoutgoing:
5928 if needsoutgoing:
5923 dest, dbranch, dother, outgoing = getoutgoing()
5929 dest, dbranch, dother, outgoing = getoutgoing()
5924 else:
5930 else:
5925 dest = dbranch = dother = outgoing = None
5931 dest = dbranch = dother = outgoing = None
5926
5932
5927 if opts.get('remote'):
5933 if opts.get('remote'):
5928 t = []
5934 t = []
5929 if incoming:
5935 if incoming:
5930 t.append(_('1 or more incoming'))
5936 t.append(_('1 or more incoming'))
5931 o = outgoing.missing
5937 o = outgoing.missing
5932 if o:
5938 if o:
5933 t.append(_('%d outgoing') % len(o))
5939 t.append(_('%d outgoing') % len(o))
5934 other = dother or sother
5940 other = dother or sother
5935 if 'bookmarks' in other.listkeys('namespaces'):
5941 if 'bookmarks' in other.listkeys('namespaces'):
5936 lmarks = repo.listkeys('bookmarks')
5942 lmarks = repo.listkeys('bookmarks')
5937 rmarks = other.listkeys('bookmarks')
5943 rmarks = other.listkeys('bookmarks')
5938 diff = set(rmarks) - set(lmarks)
5944 diff = set(rmarks) - set(lmarks)
5939 if len(diff) > 0:
5945 if len(diff) > 0:
5940 t.append(_('%d incoming bookmarks') % len(diff))
5946 t.append(_('%d incoming bookmarks') % len(diff))
5941 diff = set(lmarks) - set(rmarks)
5947 diff = set(lmarks) - set(rmarks)
5942 if len(diff) > 0:
5948 if len(diff) > 0:
5943 t.append(_('%d outgoing bookmarks') % len(diff))
5949 t.append(_('%d outgoing bookmarks') % len(diff))
5944
5950
5945 if t:
5951 if t:
5946 # i18n: column positioning for "hg summary"
5952 # i18n: column positioning for "hg summary"
5947 ui.write(_('remote: %s\n') % (', '.join(t)))
5953 ui.write(_('remote: %s\n') % (', '.join(t)))
5948 else:
5954 else:
5949 # i18n: column positioning for "hg summary"
5955 # i18n: column positioning for "hg summary"
5950 ui.status(_('remote: (synced)\n'))
5956 ui.status(_('remote: (synced)\n'))
5951
5957
5952 cmdutil.summaryremotehooks(ui, repo, opts,
5958 cmdutil.summaryremotehooks(ui, repo, opts,
5953 ((source, sbranch, sother, commoninc),
5959 ((source, sbranch, sother, commoninc),
5954 (dest, dbranch, dother, outgoing)))
5960 (dest, dbranch, dother, outgoing)))
5955
5961
5956 @command('tag',
5962 @command('tag',
5957 [('f', 'force', None, _('force tag')),
5963 [('f', 'force', None, _('force tag')),
5958 ('l', 'local', None, _('make the tag local')),
5964 ('l', 'local', None, _('make the tag local')),
5959 ('r', 'rev', '', _('revision to tag'), _('REV')),
5965 ('r', 'rev', '', _('revision to tag'), _('REV')),
5960 ('', 'remove', None, _('remove a tag')),
5966 ('', 'remove', None, _('remove a tag')),
5961 # -l/--local is already there, commitopts cannot be used
5967 # -l/--local is already there, commitopts cannot be used
5962 ('e', 'edit', None, _('invoke editor on commit messages')),
5968 ('e', 'edit', None, _('invoke editor on commit messages')),
5963 ('m', 'message', '', _('use text as commit message'), _('TEXT')),
5969 ('m', 'message', '', _('use text as commit message'), _('TEXT')),
5964 ] + commitopts2,
5970 ] + commitopts2,
5965 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
5971 _('[-f] [-l] [-m TEXT] [-d DATE] [-u USER] [-r REV] NAME...'))
5966 def tag(ui, repo, name1, *names, **opts):
5972 def tag(ui, repo, name1, *names, **opts):
5967 """add one or more tags for the current or given revision
5973 """add one or more tags for the current or given revision
5968
5974
5969 Name a particular revision using <name>.
5975 Name a particular revision using <name>.
5970
5976
5971 Tags are used to name particular revisions of the repository and are
5977 Tags are used to name particular revisions of the repository and are
5972 very useful to compare different revisions, to go back to significant
5978 very useful to compare different revisions, to go back to significant
5973 earlier versions or to mark branch points as releases, etc. Changing
5979 earlier versions or to mark branch points as releases, etc. Changing
5974 an existing tag is normally disallowed; use -f/--force to override.
5980 an existing tag is normally disallowed; use -f/--force to override.
5975
5981
5976 If no revision is given, the parent of the working directory is
5982 If no revision is given, the parent of the working directory is
5977 used.
5983 used.
5978
5984
5979 To facilitate version control, distribution, and merging of tags,
5985 To facilitate version control, distribution, and merging of tags,
5980 they are stored as a file named ".hgtags" which is managed similarly
5986 they are stored as a file named ".hgtags" which is managed similarly
5981 to other project files and can be hand-edited if necessary. This
5987 to other project files and can be hand-edited if necessary. This
5982 also means that tagging creates a new commit. The file
5988 also means that tagging creates a new commit. The file
5983 ".hg/localtags" is used for local tags (not shared among
5989 ".hg/localtags" is used for local tags (not shared among
5984 repositories).
5990 repositories).
5985
5991
5986 Tag commits are usually made at the head of a branch. If the parent
5992 Tag commits are usually made at the head of a branch. If the parent
5987 of the working directory is not a branch head, :hg:`tag` aborts; use
5993 of the working directory is not a branch head, :hg:`tag` aborts; use
5988 -f/--force to force the tag commit to be based on a non-head
5994 -f/--force to force the tag commit to be based on a non-head
5989 changeset.
5995 changeset.
5990
5996
5991 See :hg:`help dates` for a list of formats valid for -d/--date.
5997 See :hg:`help dates` for a list of formats valid for -d/--date.
5992
5998
5993 Since tag names have priority over branch names during revision
5999 Since tag names have priority over branch names during revision
5994 lookup, using an existing branch name as a tag name is discouraged.
6000 lookup, using an existing branch name as a tag name is discouraged.
5995
6001
5996 Returns 0 on success.
6002 Returns 0 on success.
5997 """
6003 """
5998 wlock = lock = None
6004 wlock = lock = None
5999 try:
6005 try:
6000 wlock = repo.wlock()
6006 wlock = repo.wlock()
6001 lock = repo.lock()
6007 lock = repo.lock()
6002 rev_ = "."
6008 rev_ = "."
6003 names = [t.strip() for t in (name1,) + names]
6009 names = [t.strip() for t in (name1,) + names]
6004 if len(names) != len(set(names)):
6010 if len(names) != len(set(names)):
6005 raise util.Abort(_('tag names must be unique'))
6011 raise util.Abort(_('tag names must be unique'))
6006 for n in names:
6012 for n in names:
6007 scmutil.checknewlabel(repo, n, 'tag')
6013 scmutil.checknewlabel(repo, n, 'tag')
6008 if not n:
6014 if not n:
6009 raise util.Abort(_('tag names cannot consist entirely of '
6015 raise util.Abort(_('tag names cannot consist entirely of '
6010 'whitespace'))
6016 'whitespace'))
6011 if opts.get('rev') and opts.get('remove'):
6017 if opts.get('rev') and opts.get('remove'):
6012 raise util.Abort(_("--rev and --remove are incompatible"))
6018 raise util.Abort(_("--rev and --remove are incompatible"))
6013 if opts.get('rev'):
6019 if opts.get('rev'):
6014 rev_ = opts['rev']
6020 rev_ = opts['rev']
6015 message = opts.get('message')
6021 message = opts.get('message')
6016 if opts.get('remove'):
6022 if opts.get('remove'):
6017 expectedtype = opts.get('local') and 'local' or 'global'
6023 expectedtype = opts.get('local') and 'local' or 'global'
6018 for n in names:
6024 for n in names:
6019 if not repo.tagtype(n):
6025 if not repo.tagtype(n):
6020 raise util.Abort(_("tag '%s' does not exist") % n)
6026 raise util.Abort(_("tag '%s' does not exist") % n)
6021 if repo.tagtype(n) != expectedtype:
6027 if repo.tagtype(n) != expectedtype:
6022 if expectedtype == 'global':
6028 if expectedtype == 'global':
6023 raise util.Abort(_("tag '%s' is not a global tag") % n)
6029 raise util.Abort(_("tag '%s' is not a global tag") % n)
6024 else:
6030 else:
6025 raise util.Abort(_("tag '%s' is not a local tag") % n)
6031 raise util.Abort(_("tag '%s' is not a local tag") % n)
6026 rev_ = nullid
6032 rev_ = nullid
6027 if not message:
6033 if not message:
6028 # we don't translate commit messages
6034 # we don't translate commit messages
6029 message = 'Removed tag %s' % ', '.join(names)
6035 message = 'Removed tag %s' % ', '.join(names)
6030 elif not opts.get('force'):
6036 elif not opts.get('force'):
6031 for n in names:
6037 for n in names:
6032 if n in repo.tags():
6038 if n in repo.tags():
6033 raise util.Abort(_("tag '%s' already exists "
6039 raise util.Abort(_("tag '%s' already exists "
6034 "(use -f to force)") % n)
6040 "(use -f to force)") % n)
6035 if not opts.get('local'):
6041 if not opts.get('local'):
6036 p1, p2 = repo.dirstate.parents()
6042 p1, p2 = repo.dirstate.parents()
6037 if p2 != nullid:
6043 if p2 != nullid:
6038 raise util.Abort(_('uncommitted merge'))
6044 raise util.Abort(_('uncommitted merge'))
6039 bheads = repo.branchheads()
6045 bheads = repo.branchheads()
6040 if not opts.get('force') and bheads and p1 not in bheads:
6046 if not opts.get('force') and bheads and p1 not in bheads:
6041 raise util.Abort(_('not at a branch head (use -f to force)'))
6047 raise util.Abort(_('not at a branch head (use -f to force)'))
6042 r = scmutil.revsingle(repo, rev_).node()
6048 r = scmutil.revsingle(repo, rev_).node()
6043
6049
6044 if not message:
6050 if not message:
6045 # we don't translate commit messages
6051 # we don't translate commit messages
6046 message = ('Added tag %s for changeset %s' %
6052 message = ('Added tag %s for changeset %s' %
6047 (', '.join(names), short(r)))
6053 (', '.join(names), short(r)))
6048
6054
6049 date = opts.get('date')
6055 date = opts.get('date')
6050 if date:
6056 if date:
6051 date = util.parsedate(date)
6057 date = util.parsedate(date)
6052
6058
6053 if opts.get('remove'):
6059 if opts.get('remove'):
6054 editform = 'tag.remove'
6060 editform = 'tag.remove'
6055 else:
6061 else:
6056 editform = 'tag.add'
6062 editform = 'tag.add'
6057 editor = cmdutil.getcommiteditor(editform=editform, **opts)
6063 editor = cmdutil.getcommiteditor(editform=editform, **opts)
6058
6064
6059 # don't allow tagging the null rev
6065 # don't allow tagging the null rev
6060 if (not opts.get('remove') and
6066 if (not opts.get('remove') and
6061 scmutil.revsingle(repo, rev_).rev() == nullrev):
6067 scmutil.revsingle(repo, rev_).rev() == nullrev):
6062 raise util.Abort(_("cannot tag null revision"))
6068 raise util.Abort(_("cannot tag null revision"))
6063
6069
6064 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date,
6070 repo.tag(names, r, message, opts.get('local'), opts.get('user'), date,
6065 editor=editor)
6071 editor=editor)
6066 finally:
6072 finally:
6067 release(lock, wlock)
6073 release(lock, wlock)
6068
6074
6069 @command('tags', formatteropts, '')
6075 @command('tags', formatteropts, '')
6070 def tags(ui, repo, **opts):
6076 def tags(ui, repo, **opts):
6071 """list repository tags
6077 """list repository tags
6072
6078
6073 This lists both regular and local tags. When the -v/--verbose
6079 This lists both regular and local tags. When the -v/--verbose
6074 switch is used, a third column "local" is printed for local tags.
6080 switch is used, a third column "local" is printed for local tags.
6075
6081
6076 Returns 0 on success.
6082 Returns 0 on success.
6077 """
6083 """
6078
6084
6079 fm = ui.formatter('tags', opts)
6085 fm = ui.formatter('tags', opts)
6080 hexfunc = fm.hexfunc
6086 hexfunc = fm.hexfunc
6081 tagtype = ""
6087 tagtype = ""
6082
6088
6083 for t, n in reversed(repo.tagslist()):
6089 for t, n in reversed(repo.tagslist()):
6084 hn = hexfunc(n)
6090 hn = hexfunc(n)
6085 label = 'tags.normal'
6091 label = 'tags.normal'
6086 tagtype = ''
6092 tagtype = ''
6087 if repo.tagtype(t) == 'local':
6093 if repo.tagtype(t) == 'local':
6088 label = 'tags.local'
6094 label = 'tags.local'
6089 tagtype = 'local'
6095 tagtype = 'local'
6090
6096
6091 fm.startitem()
6097 fm.startitem()
6092 fm.write('tag', '%s', t, label=label)
6098 fm.write('tag', '%s', t, label=label)
6093 fmt = " " * (30 - encoding.colwidth(t)) + ' %5d:%s'
6099 fmt = " " * (30 - encoding.colwidth(t)) + ' %5d:%s'
6094 fm.condwrite(not ui.quiet, 'rev node', fmt,
6100 fm.condwrite(not ui.quiet, 'rev node', fmt,
6095 repo.changelog.rev(n), hn, label=label)
6101 repo.changelog.rev(n), hn, label=label)
6096 fm.condwrite(ui.verbose and tagtype, 'type', ' %s',
6102 fm.condwrite(ui.verbose and tagtype, 'type', ' %s',
6097 tagtype, label=label)
6103 tagtype, label=label)
6098 fm.plain('\n')
6104 fm.plain('\n')
6099 fm.end()
6105 fm.end()
6100
6106
6101 @command('tip',
6107 @command('tip',
6102 [('p', 'patch', None, _('show patch')),
6108 [('p', 'patch', None, _('show patch')),
6103 ('g', 'git', None, _('use git extended diff format')),
6109 ('g', 'git', None, _('use git extended diff format')),
6104 ] + templateopts,
6110 ] + templateopts,
6105 _('[-p] [-g]'))
6111 _('[-p] [-g]'))
6106 def tip(ui, repo, **opts):
6112 def tip(ui, repo, **opts):
6107 """show the tip revision (DEPRECATED)
6113 """show the tip revision (DEPRECATED)
6108
6114
6109 The tip revision (usually just called the tip) is the changeset
6115 The tip revision (usually just called the tip) is the changeset
6110 most recently added to the repository (and therefore the most
6116 most recently added to the repository (and therefore the most
6111 recently changed head).
6117 recently changed head).
6112
6118
6113 If you have just made a commit, that commit will be the tip. If
6119 If you have just made a commit, that commit will be the tip. If
6114 you have just pulled changes from another repository, the tip of
6120 you have just pulled changes from another repository, the tip of
6115 that repository becomes the current tip. The "tip" tag is special
6121 that repository becomes the current tip. The "tip" tag is special
6116 and cannot be renamed or assigned to a different changeset.
6122 and cannot be renamed or assigned to a different changeset.
6117
6123
6118 This command is deprecated, please use :hg:`heads` instead.
6124 This command is deprecated, please use :hg:`heads` instead.
6119
6125
6120 Returns 0 on success.
6126 Returns 0 on success.
6121 """
6127 """
6122 displayer = cmdutil.show_changeset(ui, repo, opts)
6128 displayer = cmdutil.show_changeset(ui, repo, opts)
6123 displayer.show(repo['tip'])
6129 displayer.show(repo['tip'])
6124 displayer.close()
6130 displayer.close()
6125
6131
6126 @command('unbundle',
6132 @command('unbundle',
6127 [('u', 'update', None,
6133 [('u', 'update', None,
6128 _('update to new branch head if changesets were unbundled'))],
6134 _('update to new branch head if changesets were unbundled'))],
6129 _('[-u] FILE...'))
6135 _('[-u] FILE...'))
6130 def unbundle(ui, repo, fname1, *fnames, **opts):
6136 def unbundle(ui, repo, fname1, *fnames, **opts):
6131 """apply one or more changegroup files
6137 """apply one or more changegroup files
6132
6138
6133 Apply one or more compressed changegroup files generated by the
6139 Apply one or more compressed changegroup files generated by the
6134 bundle command.
6140 bundle command.
6135
6141
6136 Returns 0 on success, 1 if an update has unresolved files.
6142 Returns 0 on success, 1 if an update has unresolved files.
6137 """
6143 """
6138 fnames = (fname1,) + fnames
6144 fnames = (fname1,) + fnames
6139
6145
6140 lock = repo.lock()
6146 lock = repo.lock()
6141 try:
6147 try:
6142 for fname in fnames:
6148 for fname in fnames:
6143 f = hg.openpath(ui, fname)
6149 f = hg.openpath(ui, fname)
6144 gen = exchange.readbundle(ui, f, fname)
6150 gen = exchange.readbundle(ui, f, fname)
6145 if isinstance(gen, bundle2.unbundle20):
6151 if isinstance(gen, bundle2.unbundle20):
6146 tr = repo.transaction('unbundle')
6152 tr = repo.transaction('unbundle')
6147 try:
6153 try:
6148 op = bundle2.processbundle(repo, gen, lambda: tr)
6154 op = bundle2.processbundle(repo, gen, lambda: tr)
6149 tr.close()
6155 tr.close()
6150 finally:
6156 finally:
6151 if tr:
6157 if tr:
6152 tr.release()
6158 tr.release()
6153 changes = [r.get('result', 0)
6159 changes = [r.get('result', 0)
6154 for r in op.records['changegroup']]
6160 for r in op.records['changegroup']]
6155 modheads = changegroup.combineresults(changes)
6161 modheads = changegroup.combineresults(changes)
6156 else:
6162 else:
6157 modheads = changegroup.addchangegroup(repo, gen, 'unbundle',
6163 modheads = changegroup.addchangegroup(repo, gen, 'unbundle',
6158 'bundle:' + fname)
6164 'bundle:' + fname)
6159 finally:
6165 finally:
6160 lock.release()
6166 lock.release()
6161
6167
6162 return postincoming(ui, repo, modheads, opts.get('update'), None)
6168 return postincoming(ui, repo, modheads, opts.get('update'), None)
6163
6169
6164 @command('^update|up|checkout|co',
6170 @command('^update|up|checkout|co',
6165 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
6171 [('C', 'clean', None, _('discard uncommitted changes (no backup)')),
6166 ('c', 'check', None,
6172 ('c', 'check', None,
6167 _('update across branches if no uncommitted changes')),
6173 _('update across branches if no uncommitted changes')),
6168 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
6174 ('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
6169 ('r', 'rev', '', _('revision'), _('REV'))
6175 ('r', 'rev', '', _('revision'), _('REV'))
6170 ] + mergetoolopts,
6176 ] + mergetoolopts,
6171 _('[-c] [-C] [-d DATE] [[-r] REV]'))
6177 _('[-c] [-C] [-d DATE] [[-r] REV]'))
6172 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False,
6178 def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False,
6173 tool=None):
6179 tool=None):
6174 """update working directory (or switch revisions)
6180 """update working directory (or switch revisions)
6175
6181
6176 Update the repository's working directory to the specified
6182 Update the repository's working directory to the specified
6177 changeset. If no changeset is specified, update to the tip of the
6183 changeset. If no changeset is specified, update to the tip of the
6178 current named branch and move the current bookmark (see :hg:`help
6184 current named branch and move the current bookmark (see :hg:`help
6179 bookmarks`).
6185 bookmarks`).
6180
6186
6181 Update sets the working directory's parent revision to the specified
6187 Update sets the working directory's parent revision to the specified
6182 changeset (see :hg:`help parents`).
6188 changeset (see :hg:`help parents`).
6183
6189
6184 If the changeset is not a descendant or ancestor of the working
6190 If the changeset is not a descendant or ancestor of the working
6185 directory's parent, the update is aborted. With the -c/--check
6191 directory's parent, the update is aborted. With the -c/--check
6186 option, the working directory is checked for uncommitted changes; if
6192 option, the working directory is checked for uncommitted changes; if
6187 none are found, the working directory is updated to the specified
6193 none are found, the working directory is updated to the specified
6188 changeset.
6194 changeset.
6189
6195
6190 .. container:: verbose
6196 .. container:: verbose
6191
6197
6192 The following rules apply when the working directory contains
6198 The following rules apply when the working directory contains
6193 uncommitted changes:
6199 uncommitted changes:
6194
6200
6195 1. If neither -c/--check nor -C/--clean is specified, and if
6201 1. If neither -c/--check nor -C/--clean is specified, and if
6196 the requested changeset is an ancestor or descendant of
6202 the requested changeset is an ancestor or descendant of
6197 the working directory's parent, the uncommitted changes
6203 the working directory's parent, the uncommitted changes
6198 are merged into the requested changeset and the merged
6204 are merged into the requested changeset and the merged
6199 result is left uncommitted. If the requested changeset is
6205 result is left uncommitted. If the requested changeset is
6200 not an ancestor or descendant (that is, it is on another
6206 not an ancestor or descendant (that is, it is on another
6201 branch), the update is aborted and the uncommitted changes
6207 branch), the update is aborted and the uncommitted changes
6202 are preserved.
6208 are preserved.
6203
6209
6204 2. With the -c/--check option, the update is aborted and the
6210 2. With the -c/--check option, the update is aborted and the
6205 uncommitted changes are preserved.
6211 uncommitted changes are preserved.
6206
6212
6207 3. With the -C/--clean option, uncommitted changes are discarded and
6213 3. With the -C/--clean option, uncommitted changes are discarded and
6208 the working directory is updated to the requested changeset.
6214 the working directory is updated to the requested changeset.
6209
6215
6210 To cancel an uncommitted merge (and lose your changes), use
6216 To cancel an uncommitted merge (and lose your changes), use
6211 :hg:`update --clean .`.
6217 :hg:`update --clean .`.
6212
6218
6213 Use null as the changeset to remove the working directory (like
6219 Use null as the changeset to remove the working directory (like
6214 :hg:`clone -U`).
6220 :hg:`clone -U`).
6215
6221
6216 If you want to revert just one file to an older revision, use
6222 If you want to revert just one file to an older revision, use
6217 :hg:`revert [-r REV] NAME`.
6223 :hg:`revert [-r REV] NAME`.
6218
6224
6219 See :hg:`help dates` for a list of formats valid for -d/--date.
6225 See :hg:`help dates` for a list of formats valid for -d/--date.
6220
6226
6221 Returns 0 on success, 1 if there are unresolved files.
6227 Returns 0 on success, 1 if there are unresolved files.
6222 """
6228 """
6223 if rev and node:
6229 if rev and node:
6224 raise util.Abort(_("please specify just one revision"))
6230 raise util.Abort(_("please specify just one revision"))
6225
6231
6226 if rev is None or rev == '':
6232 if rev is None or rev == '':
6227 rev = node
6233 rev = node
6228
6234
6229 cmdutil.clearunfinished(repo)
6235 cmdutil.clearunfinished(repo)
6230
6236
6231 # with no argument, we also move the current bookmark, if any
6237 # with no argument, we also move the current bookmark, if any
6232 rev, movemarkfrom = bookmarks.calculateupdate(ui, repo, rev)
6238 rev, movemarkfrom = bookmarks.calculateupdate(ui, repo, rev)
6233
6239
6234 # if we defined a bookmark, we have to remember the original bookmark name
6240 # if we defined a bookmark, we have to remember the original bookmark name
6235 brev = rev
6241 brev = rev
6236 rev = scmutil.revsingle(repo, rev, rev).rev()
6242 rev = scmutil.revsingle(repo, rev, rev).rev()
6237
6243
6238 if check and clean:
6244 if check and clean:
6239 raise util.Abort(_("cannot specify both -c/--check and -C/--clean"))
6245 raise util.Abort(_("cannot specify both -c/--check and -C/--clean"))
6240
6246
6241 if date:
6247 if date:
6242 if rev is not None:
6248 if rev is not None:
6243 raise util.Abort(_("you can't specify a revision and a date"))
6249 raise util.Abort(_("you can't specify a revision and a date"))
6244 rev = cmdutil.finddate(ui, repo, date)
6250 rev = cmdutil.finddate(ui, repo, date)
6245
6251
6246 if check:
6252 if check:
6247 c = repo[None]
6253 c = repo[None]
6248 if c.dirty(merge=False, branch=False, missing=True):
6254 if c.dirty(merge=False, branch=False, missing=True):
6249 raise util.Abort(_("uncommitted changes"))
6255 raise util.Abort(_("uncommitted changes"))
6250 if rev is None:
6256 if rev is None:
6251 rev = repo[repo[None].branch()].rev()
6257 rev = repo[repo[None].branch()].rev()
6252
6258
6253 repo.ui.setconfig('ui', 'forcemerge', tool, 'update')
6259 repo.ui.setconfig('ui', 'forcemerge', tool, 'update')
6254
6260
6255 if clean:
6261 if clean:
6256 ret = hg.clean(repo, rev)
6262 ret = hg.clean(repo, rev)
6257 else:
6263 else:
6258 ret = hg.update(repo, rev)
6264 ret = hg.update(repo, rev)
6259
6265
6260 if not ret and movemarkfrom:
6266 if not ret and movemarkfrom:
6261 if bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
6267 if bookmarks.update(repo, [movemarkfrom], repo['.'].node()):
6262 ui.status(_("updating bookmark %s\n") % repo._bookmarkcurrent)
6268 ui.status(_("updating bookmark %s\n") % repo._bookmarkcurrent)
6263 elif brev in repo._bookmarks:
6269 elif brev in repo._bookmarks:
6264 bookmarks.setcurrent(repo, brev)
6270 bookmarks.setcurrent(repo, brev)
6265 ui.status(_("(activating bookmark %s)\n") % brev)
6271 ui.status(_("(activating bookmark %s)\n") % brev)
6266 elif brev:
6272 elif brev:
6267 if repo._bookmarkcurrent:
6273 if repo._bookmarkcurrent:
6268 ui.status(_("(leaving bookmark %s)\n") %
6274 ui.status(_("(leaving bookmark %s)\n") %
6269 repo._bookmarkcurrent)
6275 repo._bookmarkcurrent)
6270 bookmarks.unsetcurrent(repo)
6276 bookmarks.unsetcurrent(repo)
6271
6277
6272 return ret
6278 return ret
6273
6279
6274 @command('verify', [])
6280 @command('verify', [])
6275 def verify(ui, repo):
6281 def verify(ui, repo):
6276 """verify the integrity of the repository
6282 """verify the integrity of the repository
6277
6283
6278 Verify the integrity of the current repository.
6284 Verify the integrity of the current repository.
6279
6285
6280 This will perform an extensive check of the repository's
6286 This will perform an extensive check of the repository's
6281 integrity, validating the hashes and checksums of each entry in
6287 integrity, validating the hashes and checksums of each entry in
6282 the changelog, manifest, and tracked files, as well as the
6288 the changelog, manifest, and tracked files, as well as the
6283 integrity of their crosslinks and indices.
6289 integrity of their crosslinks and indices.
6284
6290
6285 Please see http://mercurial.selenic.com/wiki/RepositoryCorruption
6291 Please see http://mercurial.selenic.com/wiki/RepositoryCorruption
6286 for more information about recovery from corruption of the
6292 for more information about recovery from corruption of the
6287 repository.
6293 repository.
6288
6294
6289 Returns 0 on success, 1 if errors are encountered.
6295 Returns 0 on success, 1 if errors are encountered.
6290 """
6296 """
6291 return hg.verify(repo)
6297 return hg.verify(repo)
6292
6298
6293 @command('version', [], norepo=True)
6299 @command('version', [], norepo=True)
6294 def version_(ui):
6300 def version_(ui):
6295 """output version and copyright information"""
6301 """output version and copyright information"""
6296 ui.write(_("Mercurial Distributed SCM (version %s)\n")
6302 ui.write(_("Mercurial Distributed SCM (version %s)\n")
6297 % util.version())
6303 % util.version())
6298 ui.status(_(
6304 ui.status(_(
6299 "(see http://mercurial.selenic.com for more information)\n"
6305 "(see http://mercurial.selenic.com for more information)\n"
6300 "\nCopyright (C) 2005-2014 Matt Mackall and others\n"
6306 "\nCopyright (C) 2005-2014 Matt Mackall and others\n"
6301 "This is free software; see the source for copying conditions. "
6307 "This is free software; see the source for copying conditions. "
6302 "There is NO\nwarranty; "
6308 "There is NO\nwarranty; "
6303 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
6309 "not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n"
6304 ))
6310 ))
6305
6311
6306 ui.note(_("\nEnabled extensions:\n\n"))
6312 ui.note(_("\nEnabled extensions:\n\n"))
6307 if ui.verbose:
6313 if ui.verbose:
6308 # format names and versions into columns
6314 # format names and versions into columns
6309 names = []
6315 names = []
6310 vers = []
6316 vers = []
6311 for name, module in extensions.extensions():
6317 for name, module in extensions.extensions():
6312 names.append(name)
6318 names.append(name)
6313 vers.append(extensions.moduleversion(module))
6319 vers.append(extensions.moduleversion(module))
6314 if names:
6320 if names:
6315 maxnamelen = max(len(n) for n in names)
6321 maxnamelen = max(len(n) for n in names)
6316 for i, name in enumerate(names):
6322 for i, name in enumerate(names):
6317 ui.write(" %-*s %s\n" % (maxnamelen, name, vers[i]))
6323 ui.write(" %-*s %s\n" % (maxnamelen, name, vers[i]))
@@ -1,249 +1,272 b''
1 #require serve
1 #require serve
2
2
3 = Test the getbundle() protocol function =
3 = Test the getbundle() protocol function =
4
4
5 Create a test repository:
5 Create a test repository:
6
6
7 $ hg init repo
7 $ hg init repo
8 $ cd repo
8 $ cd repo
9 $ hg debugbuilddag -n -m '+2 :fork +5 :p1 *fork +6 :p2 /p1 :m1 +3' > /dev/null
9 $ hg debugbuilddag -n -m '+2 :fork +5 :p1 *fork +6 :p2 /p1 :m1 +3' > /dev/null
10 $ hg log -G --template '{node}\n'
10 $ hg log -G --template '{node}\n'
11 o 10c14a2cc935e1d8c31f9e98587dcf27fb08a6da
11 o 10c14a2cc935e1d8c31f9e98587dcf27fb08a6da
12 |
12 |
13 o 4801a72e5d88cb515b0c7e40fae34180f3f837f2
13 o 4801a72e5d88cb515b0c7e40fae34180f3f837f2
14 |
14 |
15 o 0b2f73f04880d9cb6a5cd8a757f0db0ad01e32c3
15 o 0b2f73f04880d9cb6a5cd8a757f0db0ad01e32c3
16 |
16 |
17 o 8365676dbab05860ce0d9110f2af51368b961bbd
17 o 8365676dbab05860ce0d9110f2af51368b961bbd
18 |\
18 |\
19 | o 5686dbbd9fc46cb806599c878d02fe1cb56b83d3
19 | o 5686dbbd9fc46cb806599c878d02fe1cb56b83d3
20 | |
20 | |
21 | o 13c0170174366b441dc68e8e33757232fa744458
21 | o 13c0170174366b441dc68e8e33757232fa744458
22 | |
22 | |
23 | o 63476832d8ec6558cf9bbe3cbe0c757e5cf18043
23 | o 63476832d8ec6558cf9bbe3cbe0c757e5cf18043
24 | |
24 | |
25 | o 700b7e19db54103633c4bf4a6a6b6d55f4d50c03
25 | o 700b7e19db54103633c4bf4a6a6b6d55f4d50c03
26 | |
26 | |
27 | o 928b5f94cdb278bb536eba552de348a4e92ef24d
27 | o 928b5f94cdb278bb536eba552de348a4e92ef24d
28 | |
28 | |
29 | o f34414c64173e0ecb61b25dc55e116dbbcc89bee
29 | o f34414c64173e0ecb61b25dc55e116dbbcc89bee
30 | |
30 | |
31 | o 8931463777131cd73923e560b760061f2aa8a4bc
31 | o 8931463777131cd73923e560b760061f2aa8a4bc
32 | |
32 | |
33 o | 6621d79f61b23ec74cf4b69464343d9e0980ec8b
33 o | 6621d79f61b23ec74cf4b69464343d9e0980ec8b
34 | |
34 | |
35 o | bac16991d12ff45f9dc43c52da1946dfadb83e80
35 o | bac16991d12ff45f9dc43c52da1946dfadb83e80
36 | |
36 | |
37 o | ff42371d57168345fdf1a3aac66a51f6a45d41d2
37 o | ff42371d57168345fdf1a3aac66a51f6a45d41d2
38 | |
38 | |
39 o | d5f6e1ea452285324836a49d7d3c2a63cfed1d31
39 o | d5f6e1ea452285324836a49d7d3c2a63cfed1d31
40 | |
40 | |
41 o | 713346a995c363120712aed1aee7e04afd867638
41 o | 713346a995c363120712aed1aee7e04afd867638
42 |/
42 |/
43 o 29a4d1f17bd3f0779ca0525bebb1cfb51067c738
43 o 29a4d1f17bd3f0779ca0525bebb1cfb51067c738
44 |
44 |
45 o 7704483d56b2a7b5db54dcee7c62378ac629b348
45 o 7704483d56b2a7b5db54dcee7c62378ac629b348
46
46
47 $ cd ..
47 $ cd ..
48
48
49
49
50 = Test locally =
50 = Test locally =
51
51
52 Get everything:
52 Get everything:
53
53
54 $ hg debuggetbundle repo bundle
54 $ hg debuggetbundle repo bundle
55 $ hg debugbundle bundle
55 $ hg debugbundle bundle
56 7704483d56b2a7b5db54dcee7c62378ac629b348
56 7704483d56b2a7b5db54dcee7c62378ac629b348
57 29a4d1f17bd3f0779ca0525bebb1cfb51067c738
57 29a4d1f17bd3f0779ca0525bebb1cfb51067c738
58 713346a995c363120712aed1aee7e04afd867638
58 713346a995c363120712aed1aee7e04afd867638
59 d5f6e1ea452285324836a49d7d3c2a63cfed1d31
59 d5f6e1ea452285324836a49d7d3c2a63cfed1d31
60 ff42371d57168345fdf1a3aac66a51f6a45d41d2
60 ff42371d57168345fdf1a3aac66a51f6a45d41d2
61 bac16991d12ff45f9dc43c52da1946dfadb83e80
61 bac16991d12ff45f9dc43c52da1946dfadb83e80
62 6621d79f61b23ec74cf4b69464343d9e0980ec8b
62 6621d79f61b23ec74cf4b69464343d9e0980ec8b
63 8931463777131cd73923e560b760061f2aa8a4bc
63 8931463777131cd73923e560b760061f2aa8a4bc
64 f34414c64173e0ecb61b25dc55e116dbbcc89bee
64 f34414c64173e0ecb61b25dc55e116dbbcc89bee
65 928b5f94cdb278bb536eba552de348a4e92ef24d
65 928b5f94cdb278bb536eba552de348a4e92ef24d
66 700b7e19db54103633c4bf4a6a6b6d55f4d50c03
66 700b7e19db54103633c4bf4a6a6b6d55f4d50c03
67 63476832d8ec6558cf9bbe3cbe0c757e5cf18043
67 63476832d8ec6558cf9bbe3cbe0c757e5cf18043
68 13c0170174366b441dc68e8e33757232fa744458
68 13c0170174366b441dc68e8e33757232fa744458
69 5686dbbd9fc46cb806599c878d02fe1cb56b83d3
69 5686dbbd9fc46cb806599c878d02fe1cb56b83d3
70 8365676dbab05860ce0d9110f2af51368b961bbd
70 8365676dbab05860ce0d9110f2af51368b961bbd
71 0b2f73f04880d9cb6a5cd8a757f0db0ad01e32c3
71 0b2f73f04880d9cb6a5cd8a757f0db0ad01e32c3
72 4801a72e5d88cb515b0c7e40fae34180f3f837f2
72 4801a72e5d88cb515b0c7e40fae34180f3f837f2
73 10c14a2cc935e1d8c31f9e98587dcf27fb08a6da
73 10c14a2cc935e1d8c31f9e98587dcf27fb08a6da
74
74
75 Get part of linear run:
75 Get part of linear run:
76
76
77 $ hg debuggetbundle repo bundle -H 4801a72e5d88cb515b0c7e40fae34180f3f837f2 -C 8365676dbab05860ce0d9110f2af51368b961bbd
77 $ hg debuggetbundle repo bundle -H 4801a72e5d88cb515b0c7e40fae34180f3f837f2 -C 8365676dbab05860ce0d9110f2af51368b961bbd
78 $ hg debugbundle bundle
78 $ hg debugbundle bundle
79 0b2f73f04880d9cb6a5cd8a757f0db0ad01e32c3
79 0b2f73f04880d9cb6a5cd8a757f0db0ad01e32c3
80 4801a72e5d88cb515b0c7e40fae34180f3f837f2
80 4801a72e5d88cb515b0c7e40fae34180f3f837f2
81
81
82 Get missing branch and merge:
82 Get missing branch and merge:
83
83
84 $ hg debuggetbundle repo bundle -H 4801a72e5d88cb515b0c7e40fae34180f3f837f2 -C 13c0170174366b441dc68e8e33757232fa744458
84 $ hg debuggetbundle repo bundle -H 4801a72e5d88cb515b0c7e40fae34180f3f837f2 -C 13c0170174366b441dc68e8e33757232fa744458
85 $ hg debugbundle bundle
85 $ hg debugbundle bundle
86 713346a995c363120712aed1aee7e04afd867638
86 713346a995c363120712aed1aee7e04afd867638
87 d5f6e1ea452285324836a49d7d3c2a63cfed1d31
87 d5f6e1ea452285324836a49d7d3c2a63cfed1d31
88 ff42371d57168345fdf1a3aac66a51f6a45d41d2
88 ff42371d57168345fdf1a3aac66a51f6a45d41d2
89 bac16991d12ff45f9dc43c52da1946dfadb83e80
89 bac16991d12ff45f9dc43c52da1946dfadb83e80
90 6621d79f61b23ec74cf4b69464343d9e0980ec8b
90 6621d79f61b23ec74cf4b69464343d9e0980ec8b
91 5686dbbd9fc46cb806599c878d02fe1cb56b83d3
91 5686dbbd9fc46cb806599c878d02fe1cb56b83d3
92 8365676dbab05860ce0d9110f2af51368b961bbd
92 8365676dbab05860ce0d9110f2af51368b961bbd
93 0b2f73f04880d9cb6a5cd8a757f0db0ad01e32c3
93 0b2f73f04880d9cb6a5cd8a757f0db0ad01e32c3
94 4801a72e5d88cb515b0c7e40fae34180f3f837f2
94 4801a72e5d88cb515b0c7e40fae34180f3f837f2
95
95
96 Get from only one head:
96 Get from only one head:
97
97
98 $ hg debuggetbundle repo bundle -H 928b5f94cdb278bb536eba552de348a4e92ef24d -C 29a4d1f17bd3f0779ca0525bebb1cfb51067c738
98 $ hg debuggetbundle repo bundle -H 928b5f94cdb278bb536eba552de348a4e92ef24d -C 29a4d1f17bd3f0779ca0525bebb1cfb51067c738
99 $ hg debugbundle bundle
99 $ hg debugbundle bundle
100 8931463777131cd73923e560b760061f2aa8a4bc
100 8931463777131cd73923e560b760061f2aa8a4bc
101 f34414c64173e0ecb61b25dc55e116dbbcc89bee
101 f34414c64173e0ecb61b25dc55e116dbbcc89bee
102 928b5f94cdb278bb536eba552de348a4e92ef24d
102 928b5f94cdb278bb536eba552de348a4e92ef24d
103
103
104 Get parts of two branches:
104 Get parts of two branches:
105
105
106 $ hg debuggetbundle repo bundle -H 13c0170174366b441dc68e8e33757232fa744458 -C 700b7e19db54103633c4bf4a6a6b6d55f4d50c03 -H bac16991d12ff45f9dc43c52da1946dfadb83e80 -C d5f6e1ea452285324836a49d7d3c2a63cfed1d31
106 $ hg debuggetbundle repo bundle -H 13c0170174366b441dc68e8e33757232fa744458 -C 700b7e19db54103633c4bf4a6a6b6d55f4d50c03 -H bac16991d12ff45f9dc43c52da1946dfadb83e80 -C d5f6e1ea452285324836a49d7d3c2a63cfed1d31
107 $ hg debugbundle bundle
107 $ hg debugbundle bundle
108 ff42371d57168345fdf1a3aac66a51f6a45d41d2
108 ff42371d57168345fdf1a3aac66a51f6a45d41d2
109 bac16991d12ff45f9dc43c52da1946dfadb83e80
109 bac16991d12ff45f9dc43c52da1946dfadb83e80
110 63476832d8ec6558cf9bbe3cbe0c757e5cf18043
110 63476832d8ec6558cf9bbe3cbe0c757e5cf18043
111 13c0170174366b441dc68e8e33757232fa744458
111 13c0170174366b441dc68e8e33757232fa744458
112
112
113 Check that we get all needed file changes:
113 Check that we get all needed file changes:
114
114
115 $ hg debugbundle bundle --all
115 $ hg debugbundle bundle --all
116 format: id, p1, p2, cset, delta base, len(delta)
116 format: id, p1, p2, cset, delta base, len(delta)
117
117
118 changelog
118 changelog
119 ff42371d57168345fdf1a3aac66a51f6a45d41d2 d5f6e1ea452285324836a49d7d3c2a63cfed1d31 0000000000000000000000000000000000000000 ff42371d57168345fdf1a3aac66a51f6a45d41d2 d5f6e1ea452285324836a49d7d3c2a63cfed1d31 99
119 ff42371d57168345fdf1a3aac66a51f6a45d41d2 d5f6e1ea452285324836a49d7d3c2a63cfed1d31 0000000000000000000000000000000000000000 ff42371d57168345fdf1a3aac66a51f6a45d41d2 d5f6e1ea452285324836a49d7d3c2a63cfed1d31 99
120 bac16991d12ff45f9dc43c52da1946dfadb83e80 ff42371d57168345fdf1a3aac66a51f6a45d41d2 0000000000000000000000000000000000000000 bac16991d12ff45f9dc43c52da1946dfadb83e80 ff42371d57168345fdf1a3aac66a51f6a45d41d2 99
120 bac16991d12ff45f9dc43c52da1946dfadb83e80 ff42371d57168345fdf1a3aac66a51f6a45d41d2 0000000000000000000000000000000000000000 bac16991d12ff45f9dc43c52da1946dfadb83e80 ff42371d57168345fdf1a3aac66a51f6a45d41d2 99
121 63476832d8ec6558cf9bbe3cbe0c757e5cf18043 700b7e19db54103633c4bf4a6a6b6d55f4d50c03 0000000000000000000000000000000000000000 63476832d8ec6558cf9bbe3cbe0c757e5cf18043 bac16991d12ff45f9dc43c52da1946dfadb83e80 102
121 63476832d8ec6558cf9bbe3cbe0c757e5cf18043 700b7e19db54103633c4bf4a6a6b6d55f4d50c03 0000000000000000000000000000000000000000 63476832d8ec6558cf9bbe3cbe0c757e5cf18043 bac16991d12ff45f9dc43c52da1946dfadb83e80 102
122 13c0170174366b441dc68e8e33757232fa744458 63476832d8ec6558cf9bbe3cbe0c757e5cf18043 0000000000000000000000000000000000000000 13c0170174366b441dc68e8e33757232fa744458 63476832d8ec6558cf9bbe3cbe0c757e5cf18043 102
122 13c0170174366b441dc68e8e33757232fa744458 63476832d8ec6558cf9bbe3cbe0c757e5cf18043 0000000000000000000000000000000000000000 13c0170174366b441dc68e8e33757232fa744458 63476832d8ec6558cf9bbe3cbe0c757e5cf18043 102
123
123
124 manifest
124 manifest
125 dac7984588fc4eea7acbf39693a9c1b06f5b175d 591f732a3faf1fb903815273f3c199a514a61ccb 0000000000000000000000000000000000000000 ff42371d57168345fdf1a3aac66a51f6a45d41d2 591f732a3faf1fb903815273f3c199a514a61ccb 113
125 dac7984588fc4eea7acbf39693a9c1b06f5b175d 591f732a3faf1fb903815273f3c199a514a61ccb 0000000000000000000000000000000000000000 ff42371d57168345fdf1a3aac66a51f6a45d41d2 591f732a3faf1fb903815273f3c199a514a61ccb 113
126 0772616e6b48a76afb6c1458e193cbb3dae2e4ff dac7984588fc4eea7acbf39693a9c1b06f5b175d 0000000000000000000000000000000000000000 bac16991d12ff45f9dc43c52da1946dfadb83e80 dac7984588fc4eea7acbf39693a9c1b06f5b175d 113
126 0772616e6b48a76afb6c1458e193cbb3dae2e4ff dac7984588fc4eea7acbf39693a9c1b06f5b175d 0000000000000000000000000000000000000000 bac16991d12ff45f9dc43c52da1946dfadb83e80 dac7984588fc4eea7acbf39693a9c1b06f5b175d 113
127 eb498cd9af6c44108e43041e951ce829e29f6c80 bff2f4817ced57b386caf7c4e3e36a4bc9af7e93 0000000000000000000000000000000000000000 63476832d8ec6558cf9bbe3cbe0c757e5cf18043 0772616e6b48a76afb6c1458e193cbb3dae2e4ff 295
127 eb498cd9af6c44108e43041e951ce829e29f6c80 bff2f4817ced57b386caf7c4e3e36a4bc9af7e93 0000000000000000000000000000000000000000 63476832d8ec6558cf9bbe3cbe0c757e5cf18043 0772616e6b48a76afb6c1458e193cbb3dae2e4ff 295
128 b15709c071ddd2d93188508ba156196ab4f19620 eb498cd9af6c44108e43041e951ce829e29f6c80 0000000000000000000000000000000000000000 13c0170174366b441dc68e8e33757232fa744458 eb498cd9af6c44108e43041e951ce829e29f6c80 114
128 b15709c071ddd2d93188508ba156196ab4f19620 eb498cd9af6c44108e43041e951ce829e29f6c80 0000000000000000000000000000000000000000 13c0170174366b441dc68e8e33757232fa744458 eb498cd9af6c44108e43041e951ce829e29f6c80 114
129
129
130 mf
130 mf
131 4f73f97080266ab8e0c0561ca8d0da3eaf65b695 301ca08d026bb72cb4258a9d211bdf7ca0bcd810 0000000000000000000000000000000000000000 ff42371d57168345fdf1a3aac66a51f6a45d41d2 301ca08d026bb72cb4258a9d211bdf7ca0bcd810 17
131 4f73f97080266ab8e0c0561ca8d0da3eaf65b695 301ca08d026bb72cb4258a9d211bdf7ca0bcd810 0000000000000000000000000000000000000000 ff42371d57168345fdf1a3aac66a51f6a45d41d2 301ca08d026bb72cb4258a9d211bdf7ca0bcd810 17
132 c7b583de053293870e145f45bd2d61643563fd06 4f73f97080266ab8e0c0561ca8d0da3eaf65b695 0000000000000000000000000000000000000000 bac16991d12ff45f9dc43c52da1946dfadb83e80 4f73f97080266ab8e0c0561ca8d0da3eaf65b695 18
132 c7b583de053293870e145f45bd2d61643563fd06 4f73f97080266ab8e0c0561ca8d0da3eaf65b695 0000000000000000000000000000000000000000 bac16991d12ff45f9dc43c52da1946dfadb83e80 4f73f97080266ab8e0c0561ca8d0da3eaf65b695 18
133 266ee3c0302a5a18f1cf96817ac79a51836179e9 edc0f6b8db80d68ae6aff2b19f7e5347ab68fa63 0000000000000000000000000000000000000000 63476832d8ec6558cf9bbe3cbe0c757e5cf18043 c7b583de053293870e145f45bd2d61643563fd06 149
133 266ee3c0302a5a18f1cf96817ac79a51836179e9 edc0f6b8db80d68ae6aff2b19f7e5347ab68fa63 0000000000000000000000000000000000000000 63476832d8ec6558cf9bbe3cbe0c757e5cf18043 c7b583de053293870e145f45bd2d61643563fd06 149
134 698c6a36220548cd3903ca7dada27c59aa500c52 266ee3c0302a5a18f1cf96817ac79a51836179e9 0000000000000000000000000000000000000000 13c0170174366b441dc68e8e33757232fa744458 266ee3c0302a5a18f1cf96817ac79a51836179e9 19
134 698c6a36220548cd3903ca7dada27c59aa500c52 266ee3c0302a5a18f1cf96817ac79a51836179e9 0000000000000000000000000000000000000000 13c0170174366b441dc68e8e33757232fa744458 266ee3c0302a5a18f1cf96817ac79a51836179e9 19
135
135
136 nf11
136 nf11
137 33fbc651630ffa7ccbebfe4eb91320a873e7291c 0000000000000000000000000000000000000000 0000000000000000000000000000000000000000 63476832d8ec6558cf9bbe3cbe0c757e5cf18043 0000000000000000000000000000000000000000 16
137 33fbc651630ffa7ccbebfe4eb91320a873e7291c 0000000000000000000000000000000000000000 0000000000000000000000000000000000000000 63476832d8ec6558cf9bbe3cbe0c757e5cf18043 0000000000000000000000000000000000000000 16
138
138
139 nf12
139 nf12
140 ddce0544363f037e9fb889faca058f52dc01c0a5 0000000000000000000000000000000000000000 0000000000000000000000000000000000000000 13c0170174366b441dc68e8e33757232fa744458 0000000000000000000000000000000000000000 16
140 ddce0544363f037e9fb889faca058f52dc01c0a5 0000000000000000000000000000000000000000 0000000000000000000000000000000000000000 13c0170174366b441dc68e8e33757232fa744458 0000000000000000000000000000000000000000 16
141
141
142 nf4
142 nf4
143 3c1407305701051cbed9f9cb9a68bdfb5997c235 0000000000000000000000000000000000000000 0000000000000000000000000000000000000000 ff42371d57168345fdf1a3aac66a51f6a45d41d2 0000000000000000000000000000000000000000 15
143 3c1407305701051cbed9f9cb9a68bdfb5997c235 0000000000000000000000000000000000000000 0000000000000000000000000000000000000000 ff42371d57168345fdf1a3aac66a51f6a45d41d2 0000000000000000000000000000000000000000 15
144
144
145 nf5
145 nf5
146 0dbd89c185f53a1727c54cd1ce256482fa23968e 0000000000000000000000000000000000000000 0000000000000000000000000000000000000000 bac16991d12ff45f9dc43c52da1946dfadb83e80 0000000000000000000000000000000000000000 15
146 0dbd89c185f53a1727c54cd1ce256482fa23968e 0000000000000000000000000000000000000000 0000000000000000000000000000000000000000 bac16991d12ff45f9dc43c52da1946dfadb83e80 0000000000000000000000000000000000000000 15
147
147
148 Get branch and merge:
148 Get branch and merge:
149
149
150 $ hg debuggetbundle repo bundle -C 7704483d56b2a7b5db54dcee7c62378ac629b348 -H 0b2f73f04880d9cb6a5cd8a757f0db0ad01e32c3
150 $ hg debuggetbundle repo bundle -C 7704483d56b2a7b5db54dcee7c62378ac629b348 -H 0b2f73f04880d9cb6a5cd8a757f0db0ad01e32c3
151 $ hg debugbundle bundle
151 $ hg debugbundle bundle
152 29a4d1f17bd3f0779ca0525bebb1cfb51067c738
152 29a4d1f17bd3f0779ca0525bebb1cfb51067c738
153 713346a995c363120712aed1aee7e04afd867638
153 713346a995c363120712aed1aee7e04afd867638
154 d5f6e1ea452285324836a49d7d3c2a63cfed1d31
154 d5f6e1ea452285324836a49d7d3c2a63cfed1d31
155 ff42371d57168345fdf1a3aac66a51f6a45d41d2
155 ff42371d57168345fdf1a3aac66a51f6a45d41d2
156 bac16991d12ff45f9dc43c52da1946dfadb83e80
156 bac16991d12ff45f9dc43c52da1946dfadb83e80
157 6621d79f61b23ec74cf4b69464343d9e0980ec8b
157 6621d79f61b23ec74cf4b69464343d9e0980ec8b
158 8931463777131cd73923e560b760061f2aa8a4bc
158 8931463777131cd73923e560b760061f2aa8a4bc
159 f34414c64173e0ecb61b25dc55e116dbbcc89bee
159 f34414c64173e0ecb61b25dc55e116dbbcc89bee
160 928b5f94cdb278bb536eba552de348a4e92ef24d
160 928b5f94cdb278bb536eba552de348a4e92ef24d
161 700b7e19db54103633c4bf4a6a6b6d55f4d50c03
161 700b7e19db54103633c4bf4a6a6b6d55f4d50c03
162 63476832d8ec6558cf9bbe3cbe0c757e5cf18043
162 63476832d8ec6558cf9bbe3cbe0c757e5cf18043
163 13c0170174366b441dc68e8e33757232fa744458
163 13c0170174366b441dc68e8e33757232fa744458
164 5686dbbd9fc46cb806599c878d02fe1cb56b83d3
164 5686dbbd9fc46cb806599c878d02fe1cb56b83d3
165 8365676dbab05860ce0d9110f2af51368b961bbd
165 8365676dbab05860ce0d9110f2af51368b961bbd
166 0b2f73f04880d9cb6a5cd8a757f0db0ad01e32c3
166 0b2f73f04880d9cb6a5cd8a757f0db0ad01e32c3
167
167
168 = Test bundle2 =
168
169
170 $ hg debuggetbundle repo bundle -t bundle2
171 $ hg debugbundle bundle
172 Stream params: {}
173 b2x:changegroup -- "{'version': '01'}"
174 7704483d56b2a7b5db54dcee7c62378ac629b348
175 29a4d1f17bd3f0779ca0525bebb1cfb51067c738
176 713346a995c363120712aed1aee7e04afd867638
177 d5f6e1ea452285324836a49d7d3c2a63cfed1d31
178 ff42371d57168345fdf1a3aac66a51f6a45d41d2
179 bac16991d12ff45f9dc43c52da1946dfadb83e80
180 6621d79f61b23ec74cf4b69464343d9e0980ec8b
181 8931463777131cd73923e560b760061f2aa8a4bc
182 f34414c64173e0ecb61b25dc55e116dbbcc89bee
183 928b5f94cdb278bb536eba552de348a4e92ef24d
184 700b7e19db54103633c4bf4a6a6b6d55f4d50c03
185 63476832d8ec6558cf9bbe3cbe0c757e5cf18043
186 13c0170174366b441dc68e8e33757232fa744458
187 5686dbbd9fc46cb806599c878d02fe1cb56b83d3
188 8365676dbab05860ce0d9110f2af51368b961bbd
189 0b2f73f04880d9cb6a5cd8a757f0db0ad01e32c3
190 4801a72e5d88cb515b0c7e40fae34180f3f837f2
191 10c14a2cc935e1d8c31f9e98587dcf27fb08a6da
169 = Test via HTTP =
192 = Test via HTTP =
170
193
171 Get everything:
194 Get everything:
172
195
173 $ hg serve -R repo -p $HGPORT -d --pid-file=hg.pid -E error.log -A access.log
196 $ hg serve -R repo -p $HGPORT -d --pid-file=hg.pid -E error.log -A access.log
174 $ cat hg.pid >> $DAEMON_PIDS
197 $ cat hg.pid >> $DAEMON_PIDS
175 $ hg debuggetbundle http://localhost:$HGPORT/ bundle
198 $ hg debuggetbundle http://localhost:$HGPORT/ bundle
176 $ hg debugbundle bundle
199 $ hg debugbundle bundle
177 7704483d56b2a7b5db54dcee7c62378ac629b348
200 7704483d56b2a7b5db54dcee7c62378ac629b348
178 29a4d1f17bd3f0779ca0525bebb1cfb51067c738
201 29a4d1f17bd3f0779ca0525bebb1cfb51067c738
179 713346a995c363120712aed1aee7e04afd867638
202 713346a995c363120712aed1aee7e04afd867638
180 d5f6e1ea452285324836a49d7d3c2a63cfed1d31
203 d5f6e1ea452285324836a49d7d3c2a63cfed1d31
181 ff42371d57168345fdf1a3aac66a51f6a45d41d2
204 ff42371d57168345fdf1a3aac66a51f6a45d41d2
182 bac16991d12ff45f9dc43c52da1946dfadb83e80
205 bac16991d12ff45f9dc43c52da1946dfadb83e80
183 6621d79f61b23ec74cf4b69464343d9e0980ec8b
206 6621d79f61b23ec74cf4b69464343d9e0980ec8b
184 8931463777131cd73923e560b760061f2aa8a4bc
207 8931463777131cd73923e560b760061f2aa8a4bc
185 f34414c64173e0ecb61b25dc55e116dbbcc89bee
208 f34414c64173e0ecb61b25dc55e116dbbcc89bee
186 928b5f94cdb278bb536eba552de348a4e92ef24d
209 928b5f94cdb278bb536eba552de348a4e92ef24d
187 700b7e19db54103633c4bf4a6a6b6d55f4d50c03
210 700b7e19db54103633c4bf4a6a6b6d55f4d50c03
188 63476832d8ec6558cf9bbe3cbe0c757e5cf18043
211 63476832d8ec6558cf9bbe3cbe0c757e5cf18043
189 13c0170174366b441dc68e8e33757232fa744458
212 13c0170174366b441dc68e8e33757232fa744458
190 5686dbbd9fc46cb806599c878d02fe1cb56b83d3
213 5686dbbd9fc46cb806599c878d02fe1cb56b83d3
191 8365676dbab05860ce0d9110f2af51368b961bbd
214 8365676dbab05860ce0d9110f2af51368b961bbd
192 0b2f73f04880d9cb6a5cd8a757f0db0ad01e32c3
215 0b2f73f04880d9cb6a5cd8a757f0db0ad01e32c3
193 4801a72e5d88cb515b0c7e40fae34180f3f837f2
216 4801a72e5d88cb515b0c7e40fae34180f3f837f2
194 10c14a2cc935e1d8c31f9e98587dcf27fb08a6da
217 10c14a2cc935e1d8c31f9e98587dcf27fb08a6da
195
218
196 Get parts of two branches:
219 Get parts of two branches:
197
220
198 $ hg debuggetbundle http://localhost:$HGPORT/ bundle -H 13c0170174366b441dc68e8e33757232fa744458 -C 700b7e19db54103633c4bf4a6a6b6d55f4d50c03 -H bac16991d12ff45f9dc43c52da1946dfadb83e80 -C d5f6e1ea452285324836a49d7d3c2a63cfed1d31
221 $ hg debuggetbundle http://localhost:$HGPORT/ bundle -H 13c0170174366b441dc68e8e33757232fa744458 -C 700b7e19db54103633c4bf4a6a6b6d55f4d50c03 -H bac16991d12ff45f9dc43c52da1946dfadb83e80 -C d5f6e1ea452285324836a49d7d3c2a63cfed1d31
199 $ hg debugbundle bundle
222 $ hg debugbundle bundle
200 ff42371d57168345fdf1a3aac66a51f6a45d41d2
223 ff42371d57168345fdf1a3aac66a51f6a45d41d2
201 bac16991d12ff45f9dc43c52da1946dfadb83e80
224 bac16991d12ff45f9dc43c52da1946dfadb83e80
202 63476832d8ec6558cf9bbe3cbe0c757e5cf18043
225 63476832d8ec6558cf9bbe3cbe0c757e5cf18043
203 13c0170174366b441dc68e8e33757232fa744458
226 13c0170174366b441dc68e8e33757232fa744458
204
227
205 Check that we get all needed file changes:
228 Check that we get all needed file changes:
206
229
207 $ hg debugbundle bundle --all
230 $ hg debugbundle bundle --all
208 format: id, p1, p2, cset, delta base, len(delta)
231 format: id, p1, p2, cset, delta base, len(delta)
209
232
210 changelog
233 changelog
211 ff42371d57168345fdf1a3aac66a51f6a45d41d2 d5f6e1ea452285324836a49d7d3c2a63cfed1d31 0000000000000000000000000000000000000000 ff42371d57168345fdf1a3aac66a51f6a45d41d2 d5f6e1ea452285324836a49d7d3c2a63cfed1d31 99
234 ff42371d57168345fdf1a3aac66a51f6a45d41d2 d5f6e1ea452285324836a49d7d3c2a63cfed1d31 0000000000000000000000000000000000000000 ff42371d57168345fdf1a3aac66a51f6a45d41d2 d5f6e1ea452285324836a49d7d3c2a63cfed1d31 99
212 bac16991d12ff45f9dc43c52da1946dfadb83e80 ff42371d57168345fdf1a3aac66a51f6a45d41d2 0000000000000000000000000000000000000000 bac16991d12ff45f9dc43c52da1946dfadb83e80 ff42371d57168345fdf1a3aac66a51f6a45d41d2 99
235 bac16991d12ff45f9dc43c52da1946dfadb83e80 ff42371d57168345fdf1a3aac66a51f6a45d41d2 0000000000000000000000000000000000000000 bac16991d12ff45f9dc43c52da1946dfadb83e80 ff42371d57168345fdf1a3aac66a51f6a45d41d2 99
213 63476832d8ec6558cf9bbe3cbe0c757e5cf18043 700b7e19db54103633c4bf4a6a6b6d55f4d50c03 0000000000000000000000000000000000000000 63476832d8ec6558cf9bbe3cbe0c757e5cf18043 bac16991d12ff45f9dc43c52da1946dfadb83e80 102
236 63476832d8ec6558cf9bbe3cbe0c757e5cf18043 700b7e19db54103633c4bf4a6a6b6d55f4d50c03 0000000000000000000000000000000000000000 63476832d8ec6558cf9bbe3cbe0c757e5cf18043 bac16991d12ff45f9dc43c52da1946dfadb83e80 102
214 13c0170174366b441dc68e8e33757232fa744458 63476832d8ec6558cf9bbe3cbe0c757e5cf18043 0000000000000000000000000000000000000000 13c0170174366b441dc68e8e33757232fa744458 63476832d8ec6558cf9bbe3cbe0c757e5cf18043 102
237 13c0170174366b441dc68e8e33757232fa744458 63476832d8ec6558cf9bbe3cbe0c757e5cf18043 0000000000000000000000000000000000000000 13c0170174366b441dc68e8e33757232fa744458 63476832d8ec6558cf9bbe3cbe0c757e5cf18043 102
215
238
216 manifest
239 manifest
217 dac7984588fc4eea7acbf39693a9c1b06f5b175d 591f732a3faf1fb903815273f3c199a514a61ccb 0000000000000000000000000000000000000000 ff42371d57168345fdf1a3aac66a51f6a45d41d2 591f732a3faf1fb903815273f3c199a514a61ccb 113
240 dac7984588fc4eea7acbf39693a9c1b06f5b175d 591f732a3faf1fb903815273f3c199a514a61ccb 0000000000000000000000000000000000000000 ff42371d57168345fdf1a3aac66a51f6a45d41d2 591f732a3faf1fb903815273f3c199a514a61ccb 113
218 0772616e6b48a76afb6c1458e193cbb3dae2e4ff dac7984588fc4eea7acbf39693a9c1b06f5b175d 0000000000000000000000000000000000000000 bac16991d12ff45f9dc43c52da1946dfadb83e80 dac7984588fc4eea7acbf39693a9c1b06f5b175d 113
241 0772616e6b48a76afb6c1458e193cbb3dae2e4ff dac7984588fc4eea7acbf39693a9c1b06f5b175d 0000000000000000000000000000000000000000 bac16991d12ff45f9dc43c52da1946dfadb83e80 dac7984588fc4eea7acbf39693a9c1b06f5b175d 113
219 eb498cd9af6c44108e43041e951ce829e29f6c80 bff2f4817ced57b386caf7c4e3e36a4bc9af7e93 0000000000000000000000000000000000000000 63476832d8ec6558cf9bbe3cbe0c757e5cf18043 0772616e6b48a76afb6c1458e193cbb3dae2e4ff 295
242 eb498cd9af6c44108e43041e951ce829e29f6c80 bff2f4817ced57b386caf7c4e3e36a4bc9af7e93 0000000000000000000000000000000000000000 63476832d8ec6558cf9bbe3cbe0c757e5cf18043 0772616e6b48a76afb6c1458e193cbb3dae2e4ff 295
220 b15709c071ddd2d93188508ba156196ab4f19620 eb498cd9af6c44108e43041e951ce829e29f6c80 0000000000000000000000000000000000000000 13c0170174366b441dc68e8e33757232fa744458 eb498cd9af6c44108e43041e951ce829e29f6c80 114
243 b15709c071ddd2d93188508ba156196ab4f19620 eb498cd9af6c44108e43041e951ce829e29f6c80 0000000000000000000000000000000000000000 13c0170174366b441dc68e8e33757232fa744458 eb498cd9af6c44108e43041e951ce829e29f6c80 114
221
244
222 mf
245 mf
223 4f73f97080266ab8e0c0561ca8d0da3eaf65b695 301ca08d026bb72cb4258a9d211bdf7ca0bcd810 0000000000000000000000000000000000000000 ff42371d57168345fdf1a3aac66a51f6a45d41d2 301ca08d026bb72cb4258a9d211bdf7ca0bcd810 17
246 4f73f97080266ab8e0c0561ca8d0da3eaf65b695 301ca08d026bb72cb4258a9d211bdf7ca0bcd810 0000000000000000000000000000000000000000 ff42371d57168345fdf1a3aac66a51f6a45d41d2 301ca08d026bb72cb4258a9d211bdf7ca0bcd810 17
224 c7b583de053293870e145f45bd2d61643563fd06 4f73f97080266ab8e0c0561ca8d0da3eaf65b695 0000000000000000000000000000000000000000 bac16991d12ff45f9dc43c52da1946dfadb83e80 4f73f97080266ab8e0c0561ca8d0da3eaf65b695 18
247 c7b583de053293870e145f45bd2d61643563fd06 4f73f97080266ab8e0c0561ca8d0da3eaf65b695 0000000000000000000000000000000000000000 bac16991d12ff45f9dc43c52da1946dfadb83e80 4f73f97080266ab8e0c0561ca8d0da3eaf65b695 18
225 266ee3c0302a5a18f1cf96817ac79a51836179e9 edc0f6b8db80d68ae6aff2b19f7e5347ab68fa63 0000000000000000000000000000000000000000 63476832d8ec6558cf9bbe3cbe0c757e5cf18043 c7b583de053293870e145f45bd2d61643563fd06 149
248 266ee3c0302a5a18f1cf96817ac79a51836179e9 edc0f6b8db80d68ae6aff2b19f7e5347ab68fa63 0000000000000000000000000000000000000000 63476832d8ec6558cf9bbe3cbe0c757e5cf18043 c7b583de053293870e145f45bd2d61643563fd06 149
226 698c6a36220548cd3903ca7dada27c59aa500c52 266ee3c0302a5a18f1cf96817ac79a51836179e9 0000000000000000000000000000000000000000 13c0170174366b441dc68e8e33757232fa744458 266ee3c0302a5a18f1cf96817ac79a51836179e9 19
249 698c6a36220548cd3903ca7dada27c59aa500c52 266ee3c0302a5a18f1cf96817ac79a51836179e9 0000000000000000000000000000000000000000 13c0170174366b441dc68e8e33757232fa744458 266ee3c0302a5a18f1cf96817ac79a51836179e9 19
227
250
228 nf11
251 nf11
229 33fbc651630ffa7ccbebfe4eb91320a873e7291c 0000000000000000000000000000000000000000 0000000000000000000000000000000000000000 63476832d8ec6558cf9bbe3cbe0c757e5cf18043 0000000000000000000000000000000000000000 16
252 33fbc651630ffa7ccbebfe4eb91320a873e7291c 0000000000000000000000000000000000000000 0000000000000000000000000000000000000000 63476832d8ec6558cf9bbe3cbe0c757e5cf18043 0000000000000000000000000000000000000000 16
230
253
231 nf12
254 nf12
232 ddce0544363f037e9fb889faca058f52dc01c0a5 0000000000000000000000000000000000000000 0000000000000000000000000000000000000000 13c0170174366b441dc68e8e33757232fa744458 0000000000000000000000000000000000000000 16
255 ddce0544363f037e9fb889faca058f52dc01c0a5 0000000000000000000000000000000000000000 0000000000000000000000000000000000000000 13c0170174366b441dc68e8e33757232fa744458 0000000000000000000000000000000000000000 16
233
256
234 nf4
257 nf4
235 3c1407305701051cbed9f9cb9a68bdfb5997c235 0000000000000000000000000000000000000000 0000000000000000000000000000000000000000 ff42371d57168345fdf1a3aac66a51f6a45d41d2 0000000000000000000000000000000000000000 15
258 3c1407305701051cbed9f9cb9a68bdfb5997c235 0000000000000000000000000000000000000000 0000000000000000000000000000000000000000 ff42371d57168345fdf1a3aac66a51f6a45d41d2 0000000000000000000000000000000000000000 15
236
259
237 nf5
260 nf5
238 0dbd89c185f53a1727c54cd1ce256482fa23968e 0000000000000000000000000000000000000000 0000000000000000000000000000000000000000 bac16991d12ff45f9dc43c52da1946dfadb83e80 0000000000000000000000000000000000000000 15
261 0dbd89c185f53a1727c54cd1ce256482fa23968e 0000000000000000000000000000000000000000 0000000000000000000000000000000000000000 bac16991d12ff45f9dc43c52da1946dfadb83e80 0000000000000000000000000000000000000000 15
239
262
240 Verify we hit the HTTP server:
263 Verify we hit the HTTP server:
241
264
242 $ cat access.log
265 $ cat access.log
243 * - - [*] "GET /?cmd=capabilities HTTP/1.1" 200 - (glob)
266 * - - [*] "GET /?cmd=capabilities HTTP/1.1" 200 - (glob)
244 * - - [*] "GET /?cmd=getbundle HTTP/1.1" 200 - (glob)
267 * - - [*] "GET /?cmd=getbundle HTTP/1.1" 200 - (glob)
245 * - - [*] "GET /?cmd=capabilities HTTP/1.1" 200 - (glob)
268 * - - [*] "GET /?cmd=capabilities HTTP/1.1" 200 - (glob)
246 * - - [*] "GET /?cmd=getbundle HTTP/1.1" 200 - x-hgarg-1:common=700b7e19db54103633c4bf4a6a6b6d55f4d50c03+d5f6e1ea452285324836a49d7d3c2a63cfed1d31&heads=13c0170174366b441dc68e8e33757232fa744458+bac16991d12ff45f9dc43c52da1946dfadb83e80 (glob)
269 * - - [*] "GET /?cmd=getbundle HTTP/1.1" 200 - x-hgarg-1:common=700b7e19db54103633c4bf4a6a6b6d55f4d50c03+d5f6e1ea452285324836a49d7d3c2a63cfed1d31&heads=13c0170174366b441dc68e8e33757232fa744458+bac16991d12ff45f9dc43c52da1946dfadb83e80 (glob)
247
270
248 $ cat error.log
271 $ cat error.log
249
272
General Comments 0
You need to be logged in to leave comments. Login now