##// END OF EJS Templates
changegroup: properly compute common base in changeggroupsubset (issue4736)...
Pierre-Yves David -
r25677:af5b2f4e stable
parent child Browse files
Show More
@@ -1,899 +1,901 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 "HG20": (), # special-cased below
74 "HG20": (), # special-cased below
75 "HG10UN": ("HG10UN", nocompress),
75 "HG10UN": ("HG10UN", nocompress),
76 "HG10BZ": ("HG10", lambda: bz2.BZ2Compressor()),
76 "HG10BZ": ("HG10", lambda: bz2.BZ2Compressor()),
77 "HG10GZ": ("HG10GZ", lambda: zlib.compressobj()),
77 "HG10GZ": ("HG10GZ", lambda: zlib.compressobj()),
78 }
78 }
79
79
80 # hgweb uses this list to communicate its preferred type
80 # hgweb uses this list to communicate its preferred type
81 bundlepriority = ['HG10GZ', 'HG10BZ', 'HG10UN']
81 bundlepriority = ['HG10GZ', 'HG10BZ', 'HG10UN']
82
82
83 def writebundle(ui, cg, filename, bundletype, vfs=None):
83 def writebundle(ui, cg, filename, bundletype, vfs=None):
84 """Write a bundle file and return its filename.
84 """Write a bundle file and return its filename.
85
85
86 Existing files will not be overwritten.
86 Existing files will not be overwritten.
87 If no filename is specified, a temporary file is created.
87 If no filename is specified, a temporary file is created.
88 bz2 compression can be turned off.
88 bz2 compression can be turned off.
89 The bundle file will be deleted in case of errors.
89 The bundle file will be deleted in case of errors.
90 """
90 """
91
91
92 fh = None
92 fh = None
93 cleanup = None
93 cleanup = None
94 try:
94 try:
95 if filename:
95 if filename:
96 if vfs:
96 if vfs:
97 fh = vfs.open(filename, "wb")
97 fh = vfs.open(filename, "wb")
98 else:
98 else:
99 fh = open(filename, "wb")
99 fh = open(filename, "wb")
100 else:
100 else:
101 fd, filename = tempfile.mkstemp(prefix="hg-bundle-", suffix=".hg")
101 fd, filename = tempfile.mkstemp(prefix="hg-bundle-", suffix=".hg")
102 fh = os.fdopen(fd, "wb")
102 fh = os.fdopen(fd, "wb")
103 cleanup = filename
103 cleanup = filename
104
104
105 if bundletype == "HG20":
105 if bundletype == "HG20":
106 import bundle2
106 import bundle2
107 bundle = bundle2.bundle20(ui)
107 bundle = bundle2.bundle20(ui)
108 part = bundle.newpart('changegroup', data=cg.getchunks())
108 part = bundle.newpart('changegroup', data=cg.getchunks())
109 part.addparam('version', cg.version)
109 part.addparam('version', cg.version)
110 z = nocompress()
110 z = nocompress()
111 chunkiter = bundle.getchunks()
111 chunkiter = bundle.getchunks()
112 else:
112 else:
113 if cg.version != '01':
113 if cg.version != '01':
114 raise util.Abort(_('old bundle types only supports v1 '
114 raise util.Abort(_('old bundle types only supports v1 '
115 'changegroups'))
115 'changegroups'))
116 header, compressor = bundletypes[bundletype]
116 header, compressor = bundletypes[bundletype]
117 fh.write(header)
117 fh.write(header)
118 z = compressor()
118 z = compressor()
119 chunkiter = cg.getchunks()
119 chunkiter = cg.getchunks()
120
120
121 # parse the changegroup data, otherwise we will block
121 # parse the changegroup data, otherwise we will block
122 # in case of sshrepo because we don't know the end of the stream
122 # in case of sshrepo because we don't know the end of the stream
123
123
124 # an empty chunkgroup is the end of the changegroup
124 # an empty chunkgroup is the end of the changegroup
125 # a changegroup has at least 2 chunkgroups (changelog and manifest).
125 # a changegroup has at least 2 chunkgroups (changelog and manifest).
126 # after that, an empty chunkgroup is the end of the changegroup
126 # after that, an empty chunkgroup is the end of the changegroup
127 for chunk in chunkiter:
127 for chunk in chunkiter:
128 fh.write(z.compress(chunk))
128 fh.write(z.compress(chunk))
129 fh.write(z.flush())
129 fh.write(z.flush())
130 cleanup = None
130 cleanup = None
131 return filename
131 return filename
132 finally:
132 finally:
133 if fh is not None:
133 if fh is not None:
134 fh.close()
134 fh.close()
135 if cleanup is not None:
135 if cleanup is not None:
136 if filename and vfs:
136 if filename and vfs:
137 vfs.unlink(cleanup)
137 vfs.unlink(cleanup)
138 else:
138 else:
139 os.unlink(cleanup)
139 os.unlink(cleanup)
140
140
141 def decompressor(fh, alg):
141 def decompressor(fh, alg):
142 if alg == 'UN':
142 if alg == 'UN':
143 return fh
143 return fh
144 elif alg == 'GZ':
144 elif alg == 'GZ':
145 def generator(f):
145 def generator(f):
146 zd = zlib.decompressobj()
146 zd = zlib.decompressobj()
147 for chunk in util.filechunkiter(f):
147 for chunk in util.filechunkiter(f):
148 yield zd.decompress(chunk)
148 yield zd.decompress(chunk)
149 elif alg == 'BZ':
149 elif alg == 'BZ':
150 def generator(f):
150 def generator(f):
151 zd = bz2.BZ2Decompressor()
151 zd = bz2.BZ2Decompressor()
152 zd.decompress("BZ")
152 zd.decompress("BZ")
153 for chunk in util.filechunkiter(f, 4096):
153 for chunk in util.filechunkiter(f, 4096):
154 yield zd.decompress(chunk)
154 yield zd.decompress(chunk)
155 else:
155 else:
156 raise util.Abort("unknown bundle compression '%s'" % alg)
156 raise util.Abort("unknown bundle compression '%s'" % alg)
157 return util.chunkbuffer(generator(fh))
157 return util.chunkbuffer(generator(fh))
158
158
159 class cg1unpacker(object):
159 class cg1unpacker(object):
160 deltaheader = _CHANGEGROUPV1_DELTA_HEADER
160 deltaheader = _CHANGEGROUPV1_DELTA_HEADER
161 deltaheadersize = struct.calcsize(deltaheader)
161 deltaheadersize = struct.calcsize(deltaheader)
162 version = '01'
162 version = '01'
163 def __init__(self, fh, alg):
163 def __init__(self, fh, alg):
164 self._stream = decompressor(fh, alg)
164 self._stream = decompressor(fh, alg)
165 self._type = alg
165 self._type = alg
166 self.callback = None
166 self.callback = None
167 def compressed(self):
167 def compressed(self):
168 return self._type != 'UN'
168 return self._type != 'UN'
169 def read(self, l):
169 def read(self, l):
170 return self._stream.read(l)
170 return self._stream.read(l)
171 def seek(self, pos):
171 def seek(self, pos):
172 return self._stream.seek(pos)
172 return self._stream.seek(pos)
173 def tell(self):
173 def tell(self):
174 return self._stream.tell()
174 return self._stream.tell()
175 def close(self):
175 def close(self):
176 return self._stream.close()
176 return self._stream.close()
177
177
178 def chunklength(self):
178 def chunklength(self):
179 d = readexactly(self._stream, 4)
179 d = readexactly(self._stream, 4)
180 l = struct.unpack(">l", d)[0]
180 l = struct.unpack(">l", d)[0]
181 if l <= 4:
181 if l <= 4:
182 if l:
182 if l:
183 raise util.Abort(_("invalid chunk length %d") % l)
183 raise util.Abort(_("invalid chunk length %d") % l)
184 return 0
184 return 0
185 if self.callback:
185 if self.callback:
186 self.callback()
186 self.callback()
187 return l - 4
187 return l - 4
188
188
189 def changelogheader(self):
189 def changelogheader(self):
190 """v10 does not have a changelog header chunk"""
190 """v10 does not have a changelog header chunk"""
191 return {}
191 return {}
192
192
193 def manifestheader(self):
193 def manifestheader(self):
194 """v10 does not have a manifest header chunk"""
194 """v10 does not have a manifest header chunk"""
195 return {}
195 return {}
196
196
197 def filelogheader(self):
197 def filelogheader(self):
198 """return the header of the filelogs chunk, v10 only has the filename"""
198 """return the header of the filelogs chunk, v10 only has the filename"""
199 l = self.chunklength()
199 l = self.chunklength()
200 if not l:
200 if not l:
201 return {}
201 return {}
202 fname = readexactly(self._stream, l)
202 fname = readexactly(self._stream, l)
203 return {'filename': fname}
203 return {'filename': fname}
204
204
205 def _deltaheader(self, headertuple, prevnode):
205 def _deltaheader(self, headertuple, prevnode):
206 node, p1, p2, cs = headertuple
206 node, p1, p2, cs = headertuple
207 if prevnode is None:
207 if prevnode is None:
208 deltabase = p1
208 deltabase = p1
209 else:
209 else:
210 deltabase = prevnode
210 deltabase = prevnode
211 return node, p1, p2, deltabase, cs
211 return node, p1, p2, deltabase, cs
212
212
213 def deltachunk(self, prevnode):
213 def deltachunk(self, prevnode):
214 l = self.chunklength()
214 l = self.chunklength()
215 if not l:
215 if not l:
216 return {}
216 return {}
217 headerdata = readexactly(self._stream, self.deltaheadersize)
217 headerdata = readexactly(self._stream, self.deltaheadersize)
218 header = struct.unpack(self.deltaheader, headerdata)
218 header = struct.unpack(self.deltaheader, headerdata)
219 delta = readexactly(self._stream, l - self.deltaheadersize)
219 delta = readexactly(self._stream, l - self.deltaheadersize)
220 node, p1, p2, deltabase, cs = self._deltaheader(header, prevnode)
220 node, p1, p2, deltabase, cs = self._deltaheader(header, prevnode)
221 return {'node': node, 'p1': p1, 'p2': p2, 'cs': cs,
221 return {'node': node, 'p1': p1, 'p2': p2, 'cs': cs,
222 'deltabase': deltabase, 'delta': delta}
222 'deltabase': deltabase, 'delta': delta}
223
223
224 def getchunks(self):
224 def getchunks(self):
225 """returns all the chunks contains in the bundle
225 """returns all the chunks contains in the bundle
226
226
227 Used when you need to forward the binary stream to a file or another
227 Used when you need to forward the binary stream to a file or another
228 network API. To do so, it parse the changegroup data, otherwise it will
228 network API. To do so, it parse the changegroup data, otherwise it will
229 block in case of sshrepo because it don't know the end of the stream.
229 block in case of sshrepo because it don't know the end of the stream.
230 """
230 """
231 # an empty chunkgroup is the end of the changegroup
231 # an empty chunkgroup is the end of the changegroup
232 # a changegroup has at least 2 chunkgroups (changelog and manifest).
232 # a changegroup has at least 2 chunkgroups (changelog and manifest).
233 # after that, an empty chunkgroup is the end of the changegroup
233 # after that, an empty chunkgroup is the end of the changegroup
234 empty = False
234 empty = False
235 count = 0
235 count = 0
236 while not empty or count <= 2:
236 while not empty or count <= 2:
237 empty = True
237 empty = True
238 count += 1
238 count += 1
239 while True:
239 while True:
240 chunk = getchunk(self)
240 chunk = getchunk(self)
241 if not chunk:
241 if not chunk:
242 break
242 break
243 empty = False
243 empty = False
244 yield chunkheader(len(chunk))
244 yield chunkheader(len(chunk))
245 pos = 0
245 pos = 0
246 while pos < len(chunk):
246 while pos < len(chunk):
247 next = pos + 2**20
247 next = pos + 2**20
248 yield chunk[pos:next]
248 yield chunk[pos:next]
249 pos = next
249 pos = next
250 yield closechunk()
250 yield closechunk()
251
251
252 class cg2unpacker(cg1unpacker):
252 class cg2unpacker(cg1unpacker):
253 deltaheader = _CHANGEGROUPV2_DELTA_HEADER
253 deltaheader = _CHANGEGROUPV2_DELTA_HEADER
254 deltaheadersize = struct.calcsize(deltaheader)
254 deltaheadersize = struct.calcsize(deltaheader)
255 version = '02'
255 version = '02'
256
256
257 def _deltaheader(self, headertuple, prevnode):
257 def _deltaheader(self, headertuple, prevnode):
258 node, p1, p2, deltabase, cs = headertuple
258 node, p1, p2, deltabase, cs = headertuple
259 return node, p1, p2, deltabase, cs
259 return node, p1, p2, deltabase, cs
260
260
261 class headerlessfixup(object):
261 class headerlessfixup(object):
262 def __init__(self, fh, h):
262 def __init__(self, fh, h):
263 self._h = h
263 self._h = h
264 self._fh = fh
264 self._fh = fh
265 def read(self, n):
265 def read(self, n):
266 if self._h:
266 if self._h:
267 d, self._h = self._h[:n], self._h[n:]
267 d, self._h = self._h[:n], self._h[n:]
268 if len(d) < n:
268 if len(d) < n:
269 d += readexactly(self._fh, n - len(d))
269 d += readexactly(self._fh, n - len(d))
270 return d
270 return d
271 return readexactly(self._fh, n)
271 return readexactly(self._fh, n)
272
272
273 class cg1packer(object):
273 class cg1packer(object):
274 deltaheader = _CHANGEGROUPV1_DELTA_HEADER
274 deltaheader = _CHANGEGROUPV1_DELTA_HEADER
275 version = '01'
275 version = '01'
276 def __init__(self, repo, bundlecaps=None):
276 def __init__(self, repo, bundlecaps=None):
277 """Given a source repo, construct a bundler.
277 """Given a source repo, construct a bundler.
278
278
279 bundlecaps is optional and can be used to specify the set of
279 bundlecaps is optional and can be used to specify the set of
280 capabilities which can be used to build the bundle.
280 capabilities which can be used to build the bundle.
281 """
281 """
282 # Set of capabilities we can use to build the bundle.
282 # Set of capabilities we can use to build the bundle.
283 if bundlecaps is None:
283 if bundlecaps is None:
284 bundlecaps = set()
284 bundlecaps = set()
285 self._bundlecaps = bundlecaps
285 self._bundlecaps = bundlecaps
286 self._changelog = repo.changelog
286 self._changelog = repo.changelog
287 self._manifest = repo.manifest
287 self._manifest = repo.manifest
288 reorder = repo.ui.config('bundle', 'reorder', 'auto')
288 reorder = repo.ui.config('bundle', 'reorder', 'auto')
289 if reorder == 'auto':
289 if reorder == 'auto':
290 reorder = None
290 reorder = None
291 else:
291 else:
292 reorder = util.parsebool(reorder)
292 reorder = util.parsebool(reorder)
293 self._repo = repo
293 self._repo = repo
294 self._reorder = reorder
294 self._reorder = reorder
295 self._progress = repo.ui.progress
295 self._progress = repo.ui.progress
296 if self._repo.ui.verbose and not self._repo.ui.debugflag:
296 if self._repo.ui.verbose and not self._repo.ui.debugflag:
297 self._verbosenote = self._repo.ui.note
297 self._verbosenote = self._repo.ui.note
298 else:
298 else:
299 self._verbosenote = lambda s: None
299 self._verbosenote = lambda s: None
300
300
301 def close(self):
301 def close(self):
302 return closechunk()
302 return closechunk()
303
303
304 def fileheader(self, fname):
304 def fileheader(self, fname):
305 return chunkheader(len(fname)) + fname
305 return chunkheader(len(fname)) + fname
306
306
307 def group(self, nodelist, revlog, lookup, units=None, reorder=None):
307 def group(self, nodelist, revlog, lookup, units=None, reorder=None):
308 """Calculate a delta group, yielding a sequence of changegroup chunks
308 """Calculate a delta group, yielding a sequence of changegroup chunks
309 (strings).
309 (strings).
310
310
311 Given a list of changeset revs, return a set of deltas and
311 Given a list of changeset revs, return a set of deltas and
312 metadata corresponding to nodes. The first delta is
312 metadata corresponding to nodes. The first delta is
313 first parent(nodelist[0]) -> nodelist[0], the receiver is
313 first parent(nodelist[0]) -> nodelist[0], the receiver is
314 guaranteed to have this parent as it has all history before
314 guaranteed to have this parent as it has all history before
315 these changesets. In the case firstparent is nullrev the
315 these changesets. In the case firstparent is nullrev the
316 changegroup starts with a full revision.
316 changegroup starts with a full revision.
317
317
318 If units is not None, progress detail will be generated, units specifies
318 If units is not None, progress detail will be generated, units specifies
319 the type of revlog that is touched (changelog, manifest, etc.).
319 the type of revlog that is touched (changelog, manifest, etc.).
320 """
320 """
321 # if we don't have any revisions touched by these changesets, bail
321 # if we don't have any revisions touched by these changesets, bail
322 if len(nodelist) == 0:
322 if len(nodelist) == 0:
323 yield self.close()
323 yield self.close()
324 return
324 return
325
325
326 # for generaldelta revlogs, we linearize the revs; this will both be
326 # for generaldelta revlogs, we linearize the revs; this will both be
327 # much quicker and generate a much smaller bundle
327 # much quicker and generate a much smaller bundle
328 if (revlog._generaldelta and reorder is not False) or reorder:
328 if (revlog._generaldelta and reorder is not False) or reorder:
329 dag = dagutil.revlogdag(revlog)
329 dag = dagutil.revlogdag(revlog)
330 revs = set(revlog.rev(n) for n in nodelist)
330 revs = set(revlog.rev(n) for n in nodelist)
331 revs = dag.linearize(revs)
331 revs = dag.linearize(revs)
332 else:
332 else:
333 revs = sorted([revlog.rev(n) for n in nodelist])
333 revs = sorted([revlog.rev(n) for n in nodelist])
334
334
335 # add the parent of the first rev
335 # add the parent of the first rev
336 p = revlog.parentrevs(revs[0])[0]
336 p = revlog.parentrevs(revs[0])[0]
337 revs.insert(0, p)
337 revs.insert(0, p)
338
338
339 # build deltas
339 # build deltas
340 total = len(revs) - 1
340 total = len(revs) - 1
341 msgbundling = _('bundling')
341 msgbundling = _('bundling')
342 for r in xrange(len(revs) - 1):
342 for r in xrange(len(revs) - 1):
343 if units is not None:
343 if units is not None:
344 self._progress(msgbundling, r + 1, unit=units, total=total)
344 self._progress(msgbundling, r + 1, unit=units, total=total)
345 prev, curr = revs[r], revs[r + 1]
345 prev, curr = revs[r], revs[r + 1]
346 linknode = lookup(revlog.node(curr))
346 linknode = lookup(revlog.node(curr))
347 for c in self.revchunk(revlog, curr, prev, linknode):
347 for c in self.revchunk(revlog, curr, prev, linknode):
348 yield c
348 yield c
349
349
350 yield self.close()
350 yield self.close()
351
351
352 # filter any nodes that claim to be part of the known set
352 # filter any nodes that claim to be part of the known set
353 def prune(self, revlog, missing, commonrevs, source):
353 def prune(self, revlog, missing, commonrevs, source):
354 rr, rl = revlog.rev, revlog.linkrev
354 rr, rl = revlog.rev, revlog.linkrev
355 return [n for n in missing if rl(rr(n)) not in commonrevs]
355 return [n for n in missing if rl(rr(n)) not in commonrevs]
356
356
357 def generate(self, commonrevs, clnodes, fastpathlinkrev, source):
357 def generate(self, commonrevs, clnodes, fastpathlinkrev, source):
358 '''yield a sequence of changegroup chunks (strings)'''
358 '''yield a sequence of changegroup chunks (strings)'''
359 repo = self._repo
359 repo = self._repo
360 cl = self._changelog
360 cl = self._changelog
361 mf = self._manifest
361 mf = self._manifest
362 reorder = self._reorder
362 reorder = self._reorder
363 progress = self._progress
363 progress = self._progress
364
364
365 # for progress output
365 # for progress output
366 msgbundling = _('bundling')
366 msgbundling = _('bundling')
367
367
368 clrevorder = {}
368 clrevorder = {}
369 mfs = {} # needed manifests
369 mfs = {} # needed manifests
370 fnodes = {} # needed file nodes
370 fnodes = {} # needed file nodes
371 changedfiles = set()
371 changedfiles = set()
372
372
373 # Callback for the changelog, used to collect changed files and manifest
373 # Callback for the changelog, used to collect changed files and manifest
374 # nodes.
374 # nodes.
375 # Returns the linkrev node (identity in the changelog case).
375 # Returns the linkrev node (identity in the changelog case).
376 def lookupcl(x):
376 def lookupcl(x):
377 c = cl.read(x)
377 c = cl.read(x)
378 clrevorder[x] = len(clrevorder)
378 clrevorder[x] = len(clrevorder)
379 changedfiles.update(c[3])
379 changedfiles.update(c[3])
380 # record the first changeset introducing this manifest version
380 # record the first changeset introducing this manifest version
381 mfs.setdefault(c[0], x)
381 mfs.setdefault(c[0], x)
382 return x
382 return x
383
383
384 self._verbosenote(_('uncompressed size of bundle content:\n'))
384 self._verbosenote(_('uncompressed size of bundle content:\n'))
385 size = 0
385 size = 0
386 for chunk in self.group(clnodes, cl, lookupcl, units=_('changesets'),
386 for chunk in self.group(clnodes, cl, lookupcl, units=_('changesets'),
387 reorder=reorder):
387 reorder=reorder):
388 size += len(chunk)
388 size += len(chunk)
389 yield chunk
389 yield chunk
390 self._verbosenote(_('%8.i (changelog)\n') % size)
390 self._verbosenote(_('%8.i (changelog)\n') % size)
391 progress(msgbundling, None)
391 progress(msgbundling, None)
392
392
393 # Callback for the manifest, used to collect linkrevs for filelog
393 # Callback for the manifest, used to collect linkrevs for filelog
394 # revisions.
394 # revisions.
395 # Returns the linkrev node (collected in lookupcl).
395 # Returns the linkrev node (collected in lookupcl).
396 def lookupmf(x):
396 def lookupmf(x):
397 clnode = mfs[x]
397 clnode = mfs[x]
398 if not fastpathlinkrev or reorder:
398 if not fastpathlinkrev or reorder:
399 mdata = mf.readfast(x)
399 mdata = mf.readfast(x)
400 for f, n in mdata.iteritems():
400 for f, n in mdata.iteritems():
401 if f in changedfiles:
401 if f in changedfiles:
402 # record the first changeset introducing this filelog
402 # record the first changeset introducing this filelog
403 # version
403 # version
404 fclnodes = fnodes.setdefault(f, {})
404 fclnodes = fnodes.setdefault(f, {})
405 fclnode = fclnodes.setdefault(n, clnode)
405 fclnode = fclnodes.setdefault(n, clnode)
406 if clrevorder[clnode] < clrevorder[fclnode]:
406 if clrevorder[clnode] < clrevorder[fclnode]:
407 fclnodes[n] = clnode
407 fclnodes[n] = clnode
408 return clnode
408 return clnode
409
409
410 mfnodes = self.prune(mf, mfs, commonrevs, source)
410 mfnodes = self.prune(mf, mfs, commonrevs, source)
411 size = 0
411 size = 0
412 for chunk in self.group(mfnodes, mf, lookupmf, units=_('manifests'),
412 for chunk in self.group(mfnodes, mf, lookupmf, units=_('manifests'),
413 reorder=reorder):
413 reorder=reorder):
414 size += len(chunk)
414 size += len(chunk)
415 yield chunk
415 yield chunk
416 self._verbosenote(_('%8.i (manifests)\n') % size)
416 self._verbosenote(_('%8.i (manifests)\n') % size)
417 progress(msgbundling, None)
417 progress(msgbundling, None)
418
418
419 mfs.clear()
419 mfs.clear()
420 needed = set(cl.rev(x) for x in clnodes)
420 needed = set(cl.rev(x) for x in clnodes)
421
421
422 def linknodes(filerevlog, fname):
422 def linknodes(filerevlog, fname):
423 if fastpathlinkrev and not reorder:
423 if fastpathlinkrev and not reorder:
424 llr = filerevlog.linkrev
424 llr = filerevlog.linkrev
425 def genfilenodes():
425 def genfilenodes():
426 for r in filerevlog:
426 for r in filerevlog:
427 linkrev = llr(r)
427 linkrev = llr(r)
428 if linkrev in needed:
428 if linkrev in needed:
429 yield filerevlog.node(r), cl.node(linkrev)
429 yield filerevlog.node(r), cl.node(linkrev)
430 return dict(genfilenodes())
430 return dict(genfilenodes())
431 return fnodes.get(fname, {})
431 return fnodes.get(fname, {})
432
432
433 for chunk in self.generatefiles(changedfiles, linknodes, commonrevs,
433 for chunk in self.generatefiles(changedfiles, linknodes, commonrevs,
434 source):
434 source):
435 yield chunk
435 yield chunk
436
436
437 yield self.close()
437 yield self.close()
438 progress(msgbundling, None)
438 progress(msgbundling, None)
439
439
440 if clnodes:
440 if clnodes:
441 repo.hook('outgoing', node=hex(clnodes[0]), source=source)
441 repo.hook('outgoing', node=hex(clnodes[0]), source=source)
442
442
443 def generatefiles(self, changedfiles, linknodes, commonrevs, source):
443 def generatefiles(self, changedfiles, linknodes, commonrevs, source):
444 repo = self._repo
444 repo = self._repo
445 progress = self._progress
445 progress = self._progress
446 reorder = self._reorder
446 reorder = self._reorder
447 msgbundling = _('bundling')
447 msgbundling = _('bundling')
448
448
449 total = len(changedfiles)
449 total = len(changedfiles)
450 # for progress output
450 # for progress output
451 msgfiles = _('files')
451 msgfiles = _('files')
452 for i, fname in enumerate(sorted(changedfiles)):
452 for i, fname in enumerate(sorted(changedfiles)):
453 filerevlog = repo.file(fname)
453 filerevlog = repo.file(fname)
454 if not filerevlog:
454 if not filerevlog:
455 raise util.Abort(_("empty or missing revlog for %s") % fname)
455 raise util.Abort(_("empty or missing revlog for %s") % fname)
456
456
457 linkrevnodes = linknodes(filerevlog, fname)
457 linkrevnodes = linknodes(filerevlog, fname)
458 # Lookup for filenodes, we collected the linkrev nodes above in the
458 # Lookup for filenodes, we collected the linkrev nodes above in the
459 # fastpath case and with lookupmf in the slowpath case.
459 # fastpath case and with lookupmf in the slowpath case.
460 def lookupfilelog(x):
460 def lookupfilelog(x):
461 return linkrevnodes[x]
461 return linkrevnodes[x]
462
462
463 filenodes = self.prune(filerevlog, linkrevnodes, commonrevs, source)
463 filenodes = self.prune(filerevlog, linkrevnodes, commonrevs, source)
464 if filenodes:
464 if filenodes:
465 progress(msgbundling, i + 1, item=fname, unit=msgfiles,
465 progress(msgbundling, i + 1, item=fname, unit=msgfiles,
466 total=total)
466 total=total)
467 h = self.fileheader(fname)
467 h = self.fileheader(fname)
468 size = len(h)
468 size = len(h)
469 yield h
469 yield h
470 for chunk in self.group(filenodes, filerevlog, lookupfilelog,
470 for chunk in self.group(filenodes, filerevlog, lookupfilelog,
471 reorder=reorder):
471 reorder=reorder):
472 size += len(chunk)
472 size += len(chunk)
473 yield chunk
473 yield chunk
474 self._verbosenote(_('%8.i %s\n') % (size, fname))
474 self._verbosenote(_('%8.i %s\n') % (size, fname))
475
475
476 def deltaparent(self, revlog, rev, p1, p2, prev):
476 def deltaparent(self, revlog, rev, p1, p2, prev):
477 return prev
477 return prev
478
478
479 def revchunk(self, revlog, rev, prev, linknode):
479 def revchunk(self, revlog, rev, prev, linknode):
480 node = revlog.node(rev)
480 node = revlog.node(rev)
481 p1, p2 = revlog.parentrevs(rev)
481 p1, p2 = revlog.parentrevs(rev)
482 base = self.deltaparent(revlog, rev, p1, p2, prev)
482 base = self.deltaparent(revlog, rev, p1, p2, prev)
483
483
484 prefix = ''
484 prefix = ''
485 if revlog.iscensored(base) or revlog.iscensored(rev):
485 if revlog.iscensored(base) or revlog.iscensored(rev):
486 try:
486 try:
487 delta = revlog.revision(node)
487 delta = revlog.revision(node)
488 except error.CensoredNodeError, e:
488 except error.CensoredNodeError, e:
489 delta = e.tombstone
489 delta = e.tombstone
490 if base == nullrev:
490 if base == nullrev:
491 prefix = mdiff.trivialdiffheader(len(delta))
491 prefix = mdiff.trivialdiffheader(len(delta))
492 else:
492 else:
493 baselen = revlog.rawsize(base)
493 baselen = revlog.rawsize(base)
494 prefix = mdiff.replacediffheader(baselen, len(delta))
494 prefix = mdiff.replacediffheader(baselen, len(delta))
495 elif base == nullrev:
495 elif base == nullrev:
496 delta = revlog.revision(node)
496 delta = revlog.revision(node)
497 prefix = mdiff.trivialdiffheader(len(delta))
497 prefix = mdiff.trivialdiffheader(len(delta))
498 else:
498 else:
499 delta = revlog.revdiff(base, rev)
499 delta = revlog.revdiff(base, rev)
500 p1n, p2n = revlog.parents(node)
500 p1n, p2n = revlog.parents(node)
501 basenode = revlog.node(base)
501 basenode = revlog.node(base)
502 meta = self.builddeltaheader(node, p1n, p2n, basenode, linknode)
502 meta = self.builddeltaheader(node, p1n, p2n, basenode, linknode)
503 meta += prefix
503 meta += prefix
504 l = len(meta) + len(delta)
504 l = len(meta) + len(delta)
505 yield chunkheader(l)
505 yield chunkheader(l)
506 yield meta
506 yield meta
507 yield delta
507 yield delta
508 def builddeltaheader(self, node, p1n, p2n, basenode, linknode):
508 def builddeltaheader(self, node, p1n, p2n, basenode, linknode):
509 # do nothing with basenode, it is implicitly the previous one in HG10
509 # do nothing with basenode, it is implicitly the previous one in HG10
510 return struct.pack(self.deltaheader, node, p1n, p2n, linknode)
510 return struct.pack(self.deltaheader, node, p1n, p2n, linknode)
511
511
512 class cg2packer(cg1packer):
512 class cg2packer(cg1packer):
513 version = '02'
513 version = '02'
514 deltaheader = _CHANGEGROUPV2_DELTA_HEADER
514 deltaheader = _CHANGEGROUPV2_DELTA_HEADER
515
515
516 def group(self, nodelist, revlog, lookup, units=None, reorder=None):
516 def group(self, nodelist, revlog, lookup, units=None, reorder=None):
517 if (revlog._generaldelta and reorder is not True):
517 if (revlog._generaldelta and reorder is not True):
518 reorder = False
518 reorder = False
519 return super(cg2packer, self).group(nodelist, revlog, lookup,
519 return super(cg2packer, self).group(nodelist, revlog, lookup,
520 units=units, reorder=reorder)
520 units=units, reorder=reorder)
521
521
522 def deltaparent(self, revlog, rev, p1, p2, prev):
522 def deltaparent(self, revlog, rev, p1, p2, prev):
523 dp = revlog.deltaparent(rev)
523 dp = revlog.deltaparent(rev)
524 # avoid storing full revisions; pick prev in those cases
524 # avoid storing full revisions; pick prev in those cases
525 # also pick prev when we can't be sure remote has dp
525 # also pick prev when we can't be sure remote has dp
526 if dp == nullrev or (dp != p1 and dp != p2 and dp != prev):
526 if dp == nullrev or (dp != p1 and dp != p2 and dp != prev):
527 return prev
527 return prev
528 return dp
528 return dp
529
529
530 def builddeltaheader(self, node, p1n, p2n, basenode, linknode):
530 def builddeltaheader(self, node, p1n, p2n, basenode, linknode):
531 return struct.pack(self.deltaheader, node, p1n, p2n, basenode, linknode)
531 return struct.pack(self.deltaheader, node, p1n, p2n, basenode, linknode)
532
532
533 packermap = {'01': (cg1packer, cg1unpacker),
533 packermap = {'01': (cg1packer, cg1unpacker),
534 '02': (cg2packer, cg2unpacker)}
534 '02': (cg2packer, cg2unpacker)}
535
535
536 def _changegroupinfo(repo, nodes, source):
536 def _changegroupinfo(repo, nodes, source):
537 if repo.ui.verbose or source == 'bundle':
537 if repo.ui.verbose or source == 'bundle':
538 repo.ui.status(_("%d changesets found\n") % len(nodes))
538 repo.ui.status(_("%d changesets found\n") % len(nodes))
539 if repo.ui.debugflag:
539 if repo.ui.debugflag:
540 repo.ui.debug("list of changesets:\n")
540 repo.ui.debug("list of changesets:\n")
541 for node in nodes:
541 for node in nodes:
542 repo.ui.debug("%s\n" % hex(node))
542 repo.ui.debug("%s\n" % hex(node))
543
543
544 def getsubsetraw(repo, outgoing, bundler, source, fastpath=False):
544 def getsubsetraw(repo, outgoing, bundler, source, fastpath=False):
545 repo = repo.unfiltered()
545 repo = repo.unfiltered()
546 commonrevs = outgoing.common
546 commonrevs = outgoing.common
547 csets = outgoing.missing
547 csets = outgoing.missing
548 heads = outgoing.missingheads
548 heads = outgoing.missingheads
549 # We go through the fast path if we get told to, or if all (unfiltered
549 # We go through the fast path if we get told to, or if all (unfiltered
550 # heads have been requested (since we then know there all linkrevs will
550 # heads have been requested (since we then know there all linkrevs will
551 # be pulled by the client).
551 # be pulled by the client).
552 heads.sort()
552 heads.sort()
553 fastpathlinkrev = fastpath or (
553 fastpathlinkrev = fastpath or (
554 repo.filtername is None and heads == sorted(repo.heads()))
554 repo.filtername is None and heads == sorted(repo.heads()))
555
555
556 repo.hook('preoutgoing', throw=True, source=source)
556 repo.hook('preoutgoing', throw=True, source=source)
557 _changegroupinfo(repo, csets, source)
557 _changegroupinfo(repo, csets, source)
558 return bundler.generate(commonrevs, csets, fastpathlinkrev, source)
558 return bundler.generate(commonrevs, csets, fastpathlinkrev, source)
559
559
560 def getsubset(repo, outgoing, bundler, source, fastpath=False, version='01'):
560 def getsubset(repo, outgoing, bundler, source, fastpath=False, version='01'):
561 gengroup = getsubsetraw(repo, outgoing, bundler, source, fastpath)
561 gengroup = getsubsetraw(repo, outgoing, bundler, source, fastpath)
562 return packermap[version][1](util.chunkbuffer(gengroup), 'UN')
562 return packermap[version][1](util.chunkbuffer(gengroup), 'UN')
563
563
564 def changegroupsubset(repo, roots, heads, source, version='01'):
564 def changegroupsubset(repo, roots, heads, source, version='01'):
565 """Compute a changegroup consisting of all the nodes that are
565 """Compute a changegroup consisting of all the nodes that are
566 descendants of any of the roots and ancestors of any of the heads.
566 descendants of any of the roots and ancestors of any of the heads.
567 Return a chunkbuffer object whose read() method will return
567 Return a chunkbuffer object whose read() method will return
568 successive changegroup chunks.
568 successive changegroup chunks.
569
569
570 It is fairly complex as determining which filenodes and which
570 It is fairly complex as determining which filenodes and which
571 manifest nodes need to be included for the changeset to be complete
571 manifest nodes need to be included for the changeset to be complete
572 is non-trivial.
572 is non-trivial.
573
573
574 Another wrinkle is doing the reverse, figuring out which changeset in
574 Another wrinkle is doing the reverse, figuring out which changeset in
575 the changegroup a particular filenode or manifestnode belongs to.
575 the changegroup a particular filenode or manifestnode belongs to.
576 """
576 """
577 cl = repo.changelog
577 cl = repo.changelog
578 if not roots:
578 if not roots:
579 roots = [nullid]
579 roots = [nullid]
580 # TODO: remove call to nodesbetween.
581 csets, roots, heads = cl.nodesbetween(roots, heads)
582 discbases = []
580 discbases = []
583 for n in roots:
581 for n in roots:
584 discbases.extend([p for p in cl.parents(n) if p != nullid])
582 discbases.extend([p for p in cl.parents(n) if p != nullid])
583 # TODO: remove call to nodesbetween.
584 csets, roots, heads = cl.nodesbetween(roots, heads)
585 included = set(csets)
586 discbases = [n for n in discbases if n not in included]
585 outgoing = discovery.outgoing(cl, discbases, heads)
587 outgoing = discovery.outgoing(cl, discbases, heads)
586 bundler = packermap[version][0](repo)
588 bundler = packermap[version][0](repo)
587 return getsubset(repo, outgoing, bundler, source, version=version)
589 return getsubset(repo, outgoing, bundler, source, version=version)
588
590
589 def getlocalchangegroupraw(repo, source, outgoing, bundlecaps=None,
591 def getlocalchangegroupraw(repo, source, outgoing, bundlecaps=None,
590 version='01'):
592 version='01'):
591 """Like getbundle, but taking a discovery.outgoing as an argument.
593 """Like getbundle, but taking a discovery.outgoing as an argument.
592
594
593 This is only implemented for local repos and reuses potentially
595 This is only implemented for local repos and reuses potentially
594 precomputed sets in outgoing. Returns a raw changegroup generator."""
596 precomputed sets in outgoing. Returns a raw changegroup generator."""
595 if not outgoing.missing:
597 if not outgoing.missing:
596 return None
598 return None
597 bundler = packermap[version][0](repo, bundlecaps)
599 bundler = packermap[version][0](repo, bundlecaps)
598 return getsubsetraw(repo, outgoing, bundler, source)
600 return getsubsetraw(repo, outgoing, bundler, source)
599
601
600 def getlocalchangegroup(repo, source, outgoing, bundlecaps=None):
602 def getlocalchangegroup(repo, source, outgoing, bundlecaps=None):
601 """Like getbundle, but taking a discovery.outgoing as an argument.
603 """Like getbundle, but taking a discovery.outgoing as an argument.
602
604
603 This is only implemented for local repos and reuses potentially
605 This is only implemented for local repos and reuses potentially
604 precomputed sets in outgoing."""
606 precomputed sets in outgoing."""
605 if not outgoing.missing:
607 if not outgoing.missing:
606 return None
608 return None
607 bundler = cg1packer(repo, bundlecaps)
609 bundler = cg1packer(repo, bundlecaps)
608 return getsubset(repo, outgoing, bundler, source)
610 return getsubset(repo, outgoing, bundler, source)
609
611
610 def _computeoutgoing(repo, heads, common):
612 def _computeoutgoing(repo, heads, common):
611 """Computes which revs are outgoing given a set of common
613 """Computes which revs are outgoing given a set of common
612 and a set of heads.
614 and a set of heads.
613
615
614 This is a separate function so extensions can have access to
616 This is a separate function so extensions can have access to
615 the logic.
617 the logic.
616
618
617 Returns a discovery.outgoing object.
619 Returns a discovery.outgoing object.
618 """
620 """
619 cl = repo.changelog
621 cl = repo.changelog
620 if common:
622 if common:
621 hasnode = cl.hasnode
623 hasnode = cl.hasnode
622 common = [n for n in common if hasnode(n)]
624 common = [n for n in common if hasnode(n)]
623 else:
625 else:
624 common = [nullid]
626 common = [nullid]
625 if not heads:
627 if not heads:
626 heads = cl.heads()
628 heads = cl.heads()
627 return discovery.outgoing(cl, common, heads)
629 return discovery.outgoing(cl, common, heads)
628
630
629 def getchangegroupraw(repo, source, heads=None, common=None, bundlecaps=None,
631 def getchangegroupraw(repo, source, heads=None, common=None, bundlecaps=None,
630 version='01'):
632 version='01'):
631 """Like changegroupsubset, but returns the set difference between the
633 """Like changegroupsubset, but returns the set difference between the
632 ancestors of heads and the ancestors common.
634 ancestors of heads and the ancestors common.
633
635
634 If heads is None, use the local heads. If common is None, use [nullid].
636 If heads is None, use the local heads. If common is None, use [nullid].
635
637
636 If version is None, use a version '1' changegroup.
638 If version is None, use a version '1' changegroup.
637
639
638 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
639 current discovery protocol works. Returns a raw changegroup generator.
641 current discovery protocol works. Returns a raw changegroup generator.
640 """
642 """
641 outgoing = _computeoutgoing(repo, heads, common)
643 outgoing = _computeoutgoing(repo, heads, common)
642 return getlocalchangegroupraw(repo, source, outgoing, bundlecaps=bundlecaps,
644 return getlocalchangegroupraw(repo, source, outgoing, bundlecaps=bundlecaps,
643 version=version)
645 version=version)
644
646
645 def getchangegroup(repo, source, heads=None, common=None, bundlecaps=None):
647 def getchangegroup(repo, source, heads=None, common=None, bundlecaps=None):
646 """Like changegroupsubset, but returns the set difference between the
648 """Like changegroupsubset, but returns the set difference between the
647 ancestors of heads and the ancestors common.
649 ancestors of heads and the ancestors common.
648
650
649 If heads is None, use the local heads. If common is None, use [nullid].
651 If heads is None, use the local heads. If common is None, use [nullid].
650
652
651 The nodes in common might not all be known locally due to the way the
653 The nodes in common might not all be known locally due to the way the
652 current discovery protocol works.
654 current discovery protocol works.
653 """
655 """
654 outgoing = _computeoutgoing(repo, heads, common)
656 outgoing = _computeoutgoing(repo, heads, common)
655 return getlocalchangegroup(repo, source, outgoing, bundlecaps=bundlecaps)
657 return getlocalchangegroup(repo, source, outgoing, bundlecaps=bundlecaps)
656
658
657 def changegroup(repo, basenodes, source):
659 def changegroup(repo, basenodes, source):
658 # to avoid a race we use changegroupsubset() (issue1320)
660 # to avoid a race we use changegroupsubset() (issue1320)
659 return changegroupsubset(repo, basenodes, repo.heads(), source)
661 return changegroupsubset(repo, basenodes, repo.heads(), source)
660
662
661 def addchangegroupfiles(repo, source, revmap, trp, pr, needfiles):
663 def addchangegroupfiles(repo, source, revmap, trp, pr, needfiles):
662 revisions = 0
664 revisions = 0
663 files = 0
665 files = 0
664 while True:
666 while True:
665 chunkdata = source.filelogheader()
667 chunkdata = source.filelogheader()
666 if not chunkdata:
668 if not chunkdata:
667 break
669 break
668 f = chunkdata["filename"]
670 f = chunkdata["filename"]
669 repo.ui.debug("adding %s revisions\n" % f)
671 repo.ui.debug("adding %s revisions\n" % f)
670 pr()
672 pr()
671 fl = repo.file(f)
673 fl = repo.file(f)
672 o = len(fl)
674 o = len(fl)
673 try:
675 try:
674 if not fl.addgroup(source, revmap, trp):
676 if not fl.addgroup(source, revmap, trp):
675 raise util.Abort(_("received file revlog group is empty"))
677 raise util.Abort(_("received file revlog group is empty"))
676 except error.CensoredBaseError, e:
678 except error.CensoredBaseError, e:
677 raise util.Abort(_("received delta base is censored: %s") % e)
679 raise util.Abort(_("received delta base is censored: %s") % e)
678 revisions += len(fl) - o
680 revisions += len(fl) - o
679 files += 1
681 files += 1
680 if f in needfiles:
682 if f in needfiles:
681 needs = needfiles[f]
683 needs = needfiles[f]
682 for new in xrange(o, len(fl)):
684 for new in xrange(o, len(fl)):
683 n = fl.node(new)
685 n = fl.node(new)
684 if n in needs:
686 if n in needs:
685 needs.remove(n)
687 needs.remove(n)
686 else:
688 else:
687 raise util.Abort(
689 raise util.Abort(
688 _("received spurious file revlog entry"))
690 _("received spurious file revlog entry"))
689 if not needs:
691 if not needs:
690 del needfiles[f]
692 del needfiles[f]
691 repo.ui.progress(_('files'), None)
693 repo.ui.progress(_('files'), None)
692
694
693 for f, needs in needfiles.iteritems():
695 for f, needs in needfiles.iteritems():
694 fl = repo.file(f)
696 fl = repo.file(f)
695 for n in needs:
697 for n in needs:
696 try:
698 try:
697 fl.rev(n)
699 fl.rev(n)
698 except error.LookupError:
700 except error.LookupError:
699 raise util.Abort(
701 raise util.Abort(
700 _('missing file data for %s:%s - run hg verify') %
702 _('missing file data for %s:%s - run hg verify') %
701 (f, hex(n)))
703 (f, hex(n)))
702
704
703 return revisions, files
705 return revisions, files
704
706
705 def addchangegroup(repo, source, srctype, url, emptyok=False,
707 def addchangegroup(repo, source, srctype, url, emptyok=False,
706 targetphase=phases.draft):
708 targetphase=phases.draft):
707 """Add the changegroup returned by source.read() to this repo.
709 """Add the changegroup returned by source.read() to this repo.
708 srctype is a string like 'push', 'pull', or 'unbundle'. url is
710 srctype is a string like 'push', 'pull', or 'unbundle'. url is
709 the URL of the repo where this changegroup is coming from.
711 the URL of the repo where this changegroup is coming from.
710
712
711 Return an integer summarizing the change to this repo:
713 Return an integer summarizing the change to this repo:
712 - nothing changed or no source: 0
714 - nothing changed or no source: 0
713 - more heads than before: 1+added heads (2..n)
715 - more heads than before: 1+added heads (2..n)
714 - fewer heads than before: -1-removed heads (-2..-n)
716 - fewer heads than before: -1-removed heads (-2..-n)
715 - number of heads stays the same: 1
717 - number of heads stays the same: 1
716 """
718 """
717 repo = repo.unfiltered()
719 repo = repo.unfiltered()
718 def csmap(x):
720 def csmap(x):
719 repo.ui.debug("add changeset %s\n" % short(x))
721 repo.ui.debug("add changeset %s\n" % short(x))
720 return len(cl)
722 return len(cl)
721
723
722 def revmap(x):
724 def revmap(x):
723 return cl.rev(x)
725 return cl.rev(x)
724
726
725 if not source:
727 if not source:
726 return 0
728 return 0
727
729
728 changesets = files = revisions = 0
730 changesets = files = revisions = 0
729 efiles = set()
731 efiles = set()
730
732
731 tr = repo.transaction("\n".join([srctype, util.hidepassword(url)]))
733 tr = repo.transaction("\n".join([srctype, util.hidepassword(url)]))
732 # The transaction could have been created before and already carries source
734 # The transaction could have been created before and already carries source
733 # information. In this case we use the top level data. We overwrite the
735 # information. In this case we use the top level data. We overwrite the
734 # argument because we need to use the top level value (if they exist) in
736 # argument because we need to use the top level value (if they exist) in
735 # this function.
737 # this function.
736 srctype = tr.hookargs.setdefault('source', srctype)
738 srctype = tr.hookargs.setdefault('source', srctype)
737 url = tr.hookargs.setdefault('url', url)
739 url = tr.hookargs.setdefault('url', url)
738
740
739 # write changelog data to temp files so concurrent readers will not see
741 # write changelog data to temp files so concurrent readers will not see
740 # inconsistent view
742 # inconsistent view
741 cl = repo.changelog
743 cl = repo.changelog
742 cl.delayupdate(tr)
744 cl.delayupdate(tr)
743 oldheads = cl.heads()
745 oldheads = cl.heads()
744 try:
746 try:
745 repo.hook('prechangegroup', throw=True, **tr.hookargs)
747 repo.hook('prechangegroup', throw=True, **tr.hookargs)
746
748
747 trp = weakref.proxy(tr)
749 trp = weakref.proxy(tr)
748 # pull off the changeset group
750 # pull off the changeset group
749 repo.ui.status(_("adding changesets\n"))
751 repo.ui.status(_("adding changesets\n"))
750 clstart = len(cl)
752 clstart = len(cl)
751 class prog(object):
753 class prog(object):
752 step = _('changesets')
754 step = _('changesets')
753 count = 1
755 count = 1
754 ui = repo.ui
756 ui = repo.ui
755 total = None
757 total = None
756 def __call__(repo):
758 def __call__(repo):
757 repo.ui.progress(repo.step, repo.count, unit=_('chunks'),
759 repo.ui.progress(repo.step, repo.count, unit=_('chunks'),
758 total=repo.total)
760 total=repo.total)
759 repo.count += 1
761 repo.count += 1
760 pr = prog()
762 pr = prog()
761 source.callback = pr
763 source.callback = pr
762
764
763 source.changelogheader()
765 source.changelogheader()
764 srccontent = cl.addgroup(source, csmap, trp)
766 srccontent = cl.addgroup(source, csmap, trp)
765 if not (srccontent or emptyok):
767 if not (srccontent or emptyok):
766 raise util.Abort(_("received changelog group is empty"))
768 raise util.Abort(_("received changelog group is empty"))
767 clend = len(cl)
769 clend = len(cl)
768 changesets = clend - clstart
770 changesets = clend - clstart
769 for c in xrange(clstart, clend):
771 for c in xrange(clstart, clend):
770 efiles.update(repo[c].files())
772 efiles.update(repo[c].files())
771 efiles = len(efiles)
773 efiles = len(efiles)
772 repo.ui.progress(_('changesets'), None)
774 repo.ui.progress(_('changesets'), None)
773
775
774 # pull off the manifest group
776 # pull off the manifest group
775 repo.ui.status(_("adding manifests\n"))
777 repo.ui.status(_("adding manifests\n"))
776 pr.step = _('manifests')
778 pr.step = _('manifests')
777 pr.count = 1
779 pr.count = 1
778 pr.total = changesets # manifests <= changesets
780 pr.total = changesets # manifests <= changesets
779 # no need to check for empty manifest group here:
781 # no need to check for empty manifest group here:
780 # if the result of the merge of 1 and 2 is the same in 3 and 4,
782 # if the result of the merge of 1 and 2 is the same in 3 and 4,
781 # no new manifest will be created and the manifest group will
783 # no new manifest will be created and the manifest group will
782 # be empty during the pull
784 # be empty during the pull
783 source.manifestheader()
785 source.manifestheader()
784 repo.manifest.addgroup(source, revmap, trp)
786 repo.manifest.addgroup(source, revmap, trp)
785 repo.ui.progress(_('manifests'), None)
787 repo.ui.progress(_('manifests'), None)
786
788
787 needfiles = {}
789 needfiles = {}
788 if repo.ui.configbool('server', 'validate', default=False):
790 if repo.ui.configbool('server', 'validate', default=False):
789 # validate incoming csets have their manifests
791 # validate incoming csets have their manifests
790 for cset in xrange(clstart, clend):
792 for cset in xrange(clstart, clend):
791 mfest = repo.changelog.read(repo.changelog.node(cset))[0]
793 mfest = repo.changelog.read(repo.changelog.node(cset))[0]
792 mfest = repo.manifest.readdelta(mfest)
794 mfest = repo.manifest.readdelta(mfest)
793 # store file nodes we must see
795 # store file nodes we must see
794 for f, n in mfest.iteritems():
796 for f, n in mfest.iteritems():
795 needfiles.setdefault(f, set()).add(n)
797 needfiles.setdefault(f, set()).add(n)
796
798
797 # process the files
799 # process the files
798 repo.ui.status(_("adding file changes\n"))
800 repo.ui.status(_("adding file changes\n"))
799 pr.step = _('files')
801 pr.step = _('files')
800 pr.count = 1
802 pr.count = 1
801 pr.total = efiles
803 pr.total = efiles
802 source.callback = None
804 source.callback = None
803
805
804 newrevs, newfiles = addchangegroupfiles(repo, source, revmap, trp, pr,
806 newrevs, newfiles = addchangegroupfiles(repo, source, revmap, trp, pr,
805 needfiles)
807 needfiles)
806 revisions += newrevs
808 revisions += newrevs
807 files += newfiles
809 files += newfiles
808
810
809 dh = 0
811 dh = 0
810 if oldheads:
812 if oldheads:
811 heads = cl.heads()
813 heads = cl.heads()
812 dh = len(heads) - len(oldheads)
814 dh = len(heads) - len(oldheads)
813 for h in heads:
815 for h in heads:
814 if h not in oldheads and repo[h].closesbranch():
816 if h not in oldheads and repo[h].closesbranch():
815 dh -= 1
817 dh -= 1
816 htext = ""
818 htext = ""
817 if dh:
819 if dh:
818 htext = _(" (%+d heads)") % dh
820 htext = _(" (%+d heads)") % dh
819
821
820 repo.ui.status(_("added %d changesets"
822 repo.ui.status(_("added %d changesets"
821 " with %d changes to %d files%s\n")
823 " with %d changes to %d files%s\n")
822 % (changesets, revisions, files, htext))
824 % (changesets, revisions, files, htext))
823 repo.invalidatevolatilesets()
825 repo.invalidatevolatilesets()
824
826
825 if changesets > 0:
827 if changesets > 0:
826 p = lambda: tr.writepending() and repo.root or ""
828 p = lambda: tr.writepending() and repo.root or ""
827 if 'node' not in tr.hookargs:
829 if 'node' not in tr.hookargs:
828 tr.hookargs['node'] = hex(cl.node(clstart))
830 tr.hookargs['node'] = hex(cl.node(clstart))
829 hookargs = dict(tr.hookargs)
831 hookargs = dict(tr.hookargs)
830 else:
832 else:
831 hookargs = dict(tr.hookargs)
833 hookargs = dict(tr.hookargs)
832 hookargs['node'] = hex(cl.node(clstart))
834 hookargs['node'] = hex(cl.node(clstart))
833 repo.hook('pretxnchangegroup', throw=True, pending=p, **hookargs)
835 repo.hook('pretxnchangegroup', throw=True, pending=p, **hookargs)
834
836
835 added = [cl.node(r) for r in xrange(clstart, clend)]
837 added = [cl.node(r) for r in xrange(clstart, clend)]
836 publishing = repo.ui.configbool('phases', 'publish', True)
838 publishing = repo.ui.configbool('phases', 'publish', True)
837 if srctype in ('push', 'serve'):
839 if srctype in ('push', 'serve'):
838 # Old servers can not push the boundary themselves.
840 # Old servers can not push the boundary themselves.
839 # New servers won't push the boundary if changeset already
841 # New servers won't push the boundary if changeset already
840 # exists locally as secret
842 # exists locally as secret
841 #
843 #
842 # We should not use added here but the list of all change in
844 # We should not use added here but the list of all change in
843 # the bundle
845 # the bundle
844 if publishing:
846 if publishing:
845 phases.advanceboundary(repo, tr, phases.public, srccontent)
847 phases.advanceboundary(repo, tr, phases.public, srccontent)
846 else:
848 else:
847 # Those changesets have been pushed from the outside, their
849 # Those changesets have been pushed from the outside, their
848 # phases are going to be pushed alongside. Therefor
850 # phases are going to be pushed alongside. Therefor
849 # `targetphase` is ignored.
851 # `targetphase` is ignored.
850 phases.advanceboundary(repo, tr, phases.draft, srccontent)
852 phases.advanceboundary(repo, tr, phases.draft, srccontent)
851 phases.retractboundary(repo, tr, phases.draft, added)
853 phases.retractboundary(repo, tr, phases.draft, added)
852 elif srctype != 'strip':
854 elif srctype != 'strip':
853 # publishing only alter behavior during push
855 # publishing only alter behavior during push
854 #
856 #
855 # strip should not touch boundary at all
857 # strip should not touch boundary at all
856 phases.retractboundary(repo, tr, targetphase, added)
858 phases.retractboundary(repo, tr, targetphase, added)
857
859
858 if changesets > 0:
860 if changesets > 0:
859 if srctype != 'strip':
861 if srctype != 'strip':
860 # During strip, branchcache is invalid but coming call to
862 # During strip, branchcache is invalid but coming call to
861 # `destroyed` will repair it.
863 # `destroyed` will repair it.
862 # In other case we can safely update cache on disk.
864 # In other case we can safely update cache on disk.
863 branchmap.updatecache(repo.filtered('served'))
865 branchmap.updatecache(repo.filtered('served'))
864
866
865 def runhooks():
867 def runhooks():
866 # These hooks run when the lock releases, not when the
868 # These hooks run when the lock releases, not when the
867 # transaction closes. So it's possible for the changelog
869 # transaction closes. So it's possible for the changelog
868 # to have changed since we last saw it.
870 # to have changed since we last saw it.
869 if clstart >= len(repo):
871 if clstart >= len(repo):
870 return
872 return
871
873
872 # forcefully update the on-disk branch cache
874 # forcefully update the on-disk branch cache
873 repo.ui.debug("updating the branch cache\n")
875 repo.ui.debug("updating the branch cache\n")
874 repo.hook("changegroup", **hookargs)
876 repo.hook("changegroup", **hookargs)
875
877
876 for n in added:
878 for n in added:
877 args = hookargs.copy()
879 args = hookargs.copy()
878 args['node'] = hex(n)
880 args['node'] = hex(n)
879 repo.hook("incoming", **args)
881 repo.hook("incoming", **args)
880
882
881 newheads = [h for h in repo.heads() if h not in oldheads]
883 newheads = [h for h in repo.heads() if h not in oldheads]
882 repo.ui.log("incoming",
884 repo.ui.log("incoming",
883 "%s incoming changes - new heads: %s\n",
885 "%s incoming changes - new heads: %s\n",
884 len(added),
886 len(added),
885 ', '.join([hex(c[:6]) for c in newheads]))
887 ', '.join([hex(c[:6]) for c in newheads]))
886
888
887 tr.addpostclose('changegroup-runhooks-%020i' % clstart,
889 tr.addpostclose('changegroup-runhooks-%020i' % clstart,
888 lambda tr: repo._afterlock(runhooks))
890 lambda tr: repo._afterlock(runhooks))
889
891
890 tr.close()
892 tr.close()
891
893
892 finally:
894 finally:
893 tr.release()
895 tr.release()
894 repo.ui.flush()
896 repo.ui.flush()
895 # never return 0 here:
897 # never return 0 here:
896 if dh < 0:
898 if dh < 0:
897 return dh - 1
899 return dh - 1
898 else:
900 else:
899 return dh + 1
901 return dh + 1
@@ -1,327 +1,324 b''
1 $ cat >> $HGRCPATH <<EOF
1 $ cat >> $HGRCPATH <<EOF
2 > [extensions]
2 > [extensions]
3 > rebase=
3 > rebase=
4 >
4 >
5 > [phases]
5 > [phases]
6 > publish=False
6 > publish=False
7 >
7 >
8 > [alias]
8 > [alias]
9 > tglog = log -G --template "{rev}:{phase} '{desc}' {branches} {bookmarks}\n"
9 > tglog = log -G --template "{rev}:{phase} '{desc}' {branches} {bookmarks}\n"
10 > EOF
10 > EOF
11
11
12 $ hg init a
12 $ hg init a
13 $ cd a
13 $ cd a
14 $ echo c1 >common
14 $ echo c1 >common
15 $ hg add common
15 $ hg add common
16 $ hg ci -m C1
16 $ hg ci -m C1
17
17
18 $ echo c2 >>common
18 $ echo c2 >>common
19 $ hg ci -m C2
19 $ hg ci -m C2
20
20
21 $ echo c3 >>common
21 $ echo c3 >>common
22 $ hg ci -m C3
22 $ hg ci -m C3
23
23
24 $ hg up -q -C 1
24 $ hg up -q -C 1
25
25
26 $ echo l1 >>extra
26 $ echo l1 >>extra
27 $ hg add extra
27 $ hg add extra
28 $ hg ci -m L1
28 $ hg ci -m L1
29 created new head
29 created new head
30
30
31 $ sed -e 's/c2/l2/' common > common.new
31 $ sed -e 's/c2/l2/' common > common.new
32 $ mv common.new common
32 $ mv common.new common
33 $ hg ci -m L2
33 $ hg ci -m L2
34
34
35 $ echo l3 >> extra2
35 $ echo l3 >> extra2
36 $ hg add extra2
36 $ hg add extra2
37 $ hg ci -m L3
37 $ hg ci -m L3
38 $ hg bookmark mybook
38 $ hg bookmark mybook
39
39
40 $ hg phase --force --secret 4
40 $ hg phase --force --secret 4
41
41
42 $ hg tglog
42 $ hg tglog
43 @ 5:secret 'L3' mybook
43 @ 5:secret 'L3' mybook
44 |
44 |
45 o 4:secret 'L2'
45 o 4:secret 'L2'
46 |
46 |
47 o 3:draft 'L1'
47 o 3:draft 'L1'
48 |
48 |
49 | o 2:draft 'C3'
49 | o 2:draft 'C3'
50 |/
50 |/
51 o 1:draft 'C2'
51 o 1:draft 'C2'
52 |
52 |
53 o 0:draft 'C1'
53 o 0:draft 'C1'
54
54
55 Try to call --continue:
55 Try to call --continue:
56
56
57 $ hg rebase --continue
57 $ hg rebase --continue
58 abort: no rebase in progress
58 abort: no rebase in progress
59 [255]
59 [255]
60
60
61 Conflicting rebase:
61 Conflicting rebase:
62
62
63 $ hg rebase -s 3 -d 2
63 $ hg rebase -s 3 -d 2
64 rebasing 3:3163e20567cc "L1"
64 rebasing 3:3163e20567cc "L1"
65 rebasing 4:46f0b057b5c0 "L2"
65 rebasing 4:46f0b057b5c0 "L2"
66 merging common
66 merging common
67 warning: conflicts during merge.
67 warning: conflicts during merge.
68 merging common incomplete! (edit conflicts, then use 'hg resolve --mark')
68 merging common incomplete! (edit conflicts, then use 'hg resolve --mark')
69 unresolved conflicts (see hg resolve, then hg rebase --continue)
69 unresolved conflicts (see hg resolve, then hg rebase --continue)
70 [1]
70 [1]
71
71
72 Try to continue without solving the conflict:
72 Try to continue without solving the conflict:
73
73
74 $ hg rebase --continue
74 $ hg rebase --continue
75 already rebased 3:3163e20567cc "L1" as 3e046f2ecedb
75 already rebased 3:3163e20567cc "L1" as 3e046f2ecedb
76 rebasing 4:46f0b057b5c0 "L2"
76 rebasing 4:46f0b057b5c0 "L2"
77 abort: unresolved merge conflicts (see "hg help resolve")
77 abort: unresolved merge conflicts (see "hg help resolve")
78 [255]
78 [255]
79
79
80 Conclude rebase:
80 Conclude rebase:
81
81
82 $ echo 'resolved merge' >common
82 $ echo 'resolved merge' >common
83 $ hg resolve -m common
83 $ hg resolve -m common
84 (no more unresolved files)
84 (no more unresolved files)
85 $ hg rebase --continue
85 $ hg rebase --continue
86 already rebased 3:3163e20567cc "L1" as 3e046f2ecedb
86 already rebased 3:3163e20567cc "L1" as 3e046f2ecedb
87 rebasing 4:46f0b057b5c0 "L2"
87 rebasing 4:46f0b057b5c0 "L2"
88 rebasing 5:8029388f38dc "L3" (mybook)
88 rebasing 5:8029388f38dc "L3" (mybook)
89 saved backup bundle to $TESTTMP/a/.hg/strip-backup/3163e20567cc-5ca4656e-backup.hg (glob)
89 saved backup bundle to $TESTTMP/a/.hg/strip-backup/3163e20567cc-5ca4656e-backup.hg (glob)
90
90
91 $ hg tglog
91 $ hg tglog
92 @ 5:secret 'L3' mybook
92 @ 5:secret 'L3' mybook
93 |
93 |
94 o 4:secret 'L2'
94 o 4:secret 'L2'
95 |
95 |
96 o 3:draft 'L1'
96 o 3:draft 'L1'
97 |
97 |
98 o 2:draft 'C3'
98 o 2:draft 'C3'
99 |
99 |
100 o 1:draft 'C2'
100 o 1:draft 'C2'
101 |
101 |
102 o 0:draft 'C1'
102 o 0:draft 'C1'
103
103
104 Check correctness:
104 Check correctness:
105
105
106 $ hg cat -r 0 common
106 $ hg cat -r 0 common
107 c1
107 c1
108
108
109 $ hg cat -r 1 common
109 $ hg cat -r 1 common
110 c1
110 c1
111 c2
111 c2
112
112
113 $ hg cat -r 2 common
113 $ hg cat -r 2 common
114 c1
114 c1
115 c2
115 c2
116 c3
116 c3
117
117
118 $ hg cat -r 3 common
118 $ hg cat -r 3 common
119 c1
119 c1
120 c2
120 c2
121 c3
121 c3
122
122
123 $ hg cat -r 4 common
123 $ hg cat -r 4 common
124 resolved merge
124 resolved merge
125
125
126 $ hg cat -r 5 common
126 $ hg cat -r 5 common
127 resolved merge
127 resolved merge
128
128
129 Bookmark stays active after --continue
129 Bookmark stays active after --continue
130 $ hg bookmarks
130 $ hg bookmarks
131 * mybook 5:d67b21408fc0
131 * mybook 5:d67b21408fc0
132
132
133 $ cd ..
133 $ cd ..
134
134
135 Check that the right ancestors is used while rebasing a merge (issue4041)
135 Check that the right ancestors is used while rebasing a merge (issue4041)
136
136
137 $ hg clone "$TESTDIR/bundles/issue4041.hg" issue4041
137 $ hg clone "$TESTDIR/bundles/issue4041.hg" issue4041
138 requesting all changes
138 requesting all changes
139 adding changesets
139 adding changesets
140 adding manifests
140 adding manifests
141 adding file changes
141 adding file changes
142 added 11 changesets with 8 changes to 3 files (+1 heads)
142 added 11 changesets with 8 changes to 3 files (+1 heads)
143 updating to branch default
143 updating to branch default
144 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
144 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
145 $ cd issue4041
145 $ cd issue4041
146 $ hg log -G
146 $ hg log -G
147 o changeset: 10:2f2496ddf49d
147 o changeset: 10:2f2496ddf49d
148 |\ branch: f1
148 |\ branch: f1
149 | | tag: tip
149 | | tag: tip
150 | | parent: 7:4c9fbe56a16f
150 | | parent: 7:4c9fbe56a16f
151 | | parent: 9:e31216eec445
151 | | parent: 9:e31216eec445
152 | | user: szhang
152 | | user: szhang
153 | | date: Thu Sep 05 12:59:39 2013 -0400
153 | | date: Thu Sep 05 12:59:39 2013 -0400
154 | | summary: merge
154 | | summary: merge
155 | |
155 | |
156 | o changeset: 9:e31216eec445
156 | o changeset: 9:e31216eec445
157 | | branch: f1
157 | | branch: f1
158 | | user: szhang
158 | | user: szhang
159 | | date: Thu Sep 05 12:59:10 2013 -0400
159 | | date: Thu Sep 05 12:59:10 2013 -0400
160 | | summary: more changes to f1
160 | | summary: more changes to f1
161 | |
161 | |
162 | o changeset: 8:8e4e2c1a07ae
162 | o changeset: 8:8e4e2c1a07ae
163 | |\ branch: f1
163 | |\ branch: f1
164 | | | parent: 2:4bc80088dc6b
164 | | | parent: 2:4bc80088dc6b
165 | | | parent: 6:400110238667
165 | | | parent: 6:400110238667
166 | | | user: szhang
166 | | | user: szhang
167 | | | date: Thu Sep 05 12:57:59 2013 -0400
167 | | | date: Thu Sep 05 12:57:59 2013 -0400
168 | | | summary: bad merge
168 | | | summary: bad merge
169 | | |
169 | | |
170 o | | changeset: 7:4c9fbe56a16f
170 o | | changeset: 7:4c9fbe56a16f
171 |/ / branch: f1
171 |/ / branch: f1
172 | | parent: 2:4bc80088dc6b
172 | | parent: 2:4bc80088dc6b
173 | | user: szhang
173 | | user: szhang
174 | | date: Thu Sep 05 12:54:00 2013 -0400
174 | | date: Thu Sep 05 12:54:00 2013 -0400
175 | | summary: changed f1
175 | | summary: changed f1
176 | |
176 | |
177 | o changeset: 6:400110238667
177 | o changeset: 6:400110238667
178 | | branch: f2
178 | | branch: f2
179 | | parent: 4:12e8ec6bb010
179 | | parent: 4:12e8ec6bb010
180 | | user: szhang
180 | | user: szhang
181 | | date: Tue Sep 03 13:58:02 2013 -0400
181 | | date: Tue Sep 03 13:58:02 2013 -0400
182 | | summary: changed f2 on f2
182 | | summary: changed f2 on f2
183 | |
183 | |
184 | | @ changeset: 5:d79e2059b5c0
184 | | @ changeset: 5:d79e2059b5c0
185 | | | parent: 3:8a951942e016
185 | | | parent: 3:8a951942e016
186 | | | user: szhang
186 | | | user: szhang
187 | | | date: Tue Sep 03 13:57:39 2013 -0400
187 | | | date: Tue Sep 03 13:57:39 2013 -0400
188 | | | summary: changed f2 on default
188 | | | summary: changed f2 on default
189 | | |
189 | | |
190 | o | changeset: 4:12e8ec6bb010
190 | o | changeset: 4:12e8ec6bb010
191 | |/ branch: f2
191 | |/ branch: f2
192 | | user: szhang
192 | | user: szhang
193 | | date: Tue Sep 03 13:57:18 2013 -0400
193 | | date: Tue Sep 03 13:57:18 2013 -0400
194 | | summary: created f2 branch
194 | | summary: created f2 branch
195 | |
195 | |
196 | o changeset: 3:8a951942e016
196 | o changeset: 3:8a951942e016
197 | | parent: 0:24797d4f68de
197 | | parent: 0:24797d4f68de
198 | | user: szhang
198 | | user: szhang
199 | | date: Tue Sep 03 13:57:11 2013 -0400
199 | | date: Tue Sep 03 13:57:11 2013 -0400
200 | | summary: added f2.txt
200 | | summary: added f2.txt
201 | |
201 | |
202 o | changeset: 2:4bc80088dc6b
202 o | changeset: 2:4bc80088dc6b
203 | | branch: f1
203 | | branch: f1
204 | | user: szhang
204 | | user: szhang
205 | | date: Tue Sep 03 13:56:20 2013 -0400
205 | | date: Tue Sep 03 13:56:20 2013 -0400
206 | | summary: added f1.txt
206 | | summary: added f1.txt
207 | |
207 | |
208 o | changeset: 1:ef53c9e6b608
208 o | changeset: 1:ef53c9e6b608
209 |/ branch: f1
209 |/ branch: f1
210 | user: szhang
210 | user: szhang
211 | date: Tue Sep 03 13:55:26 2013 -0400
211 | date: Tue Sep 03 13:55:26 2013 -0400
212 | summary: created f1 branch
212 | summary: created f1 branch
213 |
213 |
214 o changeset: 0:24797d4f68de
214 o changeset: 0:24797d4f68de
215 user: szhang
215 user: szhang
216 date: Tue Sep 03 13:55:08 2013 -0400
216 date: Tue Sep 03 13:55:08 2013 -0400
217 summary: added default.txt
217 summary: added default.txt
218
218
219 $ hg rebase -s9 -d2 --debug # use debug to really check merge base used
219 $ hg rebase -s9 -d2 --debug # use debug to really check merge base used
220 rebase onto 2 starting from e31216eec445
220 rebase onto 2 starting from e31216eec445
221 ignoring null merge rebase of 3
221 ignoring null merge rebase of 3
222 ignoring null merge rebase of 4
222 ignoring null merge rebase of 4
223 ignoring null merge rebase of 6
223 ignoring null merge rebase of 6
224 ignoring null merge rebase of 8
224 ignoring null merge rebase of 8
225 rebasing 9:e31216eec445 "more changes to f1"
225 rebasing 9:e31216eec445 "more changes to f1"
226 rebasing: 9:e31216eec445 5/6 changesets (83.33%)
226 rebasing: 9:e31216eec445 5/6 changesets (83.33%)
227 future parents are 2 and -1
227 future parents are 2 and -1
228 rebase status stored
228 rebase status stored
229 update to 2:4bc80088dc6b
229 update to 2:4bc80088dc6b
230 resolving manifests
230 resolving manifests
231 branchmerge: False, force: True, partial: False
231 branchmerge: False, force: True, partial: False
232 ancestor: d79e2059b5c0+, local: d79e2059b5c0+, remote: 4bc80088dc6b
232 ancestor: d79e2059b5c0+, local: d79e2059b5c0+, remote: 4bc80088dc6b
233 f2.txt: other deleted -> r
233 f2.txt: other deleted -> r
234 removing f2.txt
234 removing f2.txt
235 updating: f2.txt 1/2 files (50.00%)
235 updating: f2.txt 1/2 files (50.00%)
236 f1.txt: remote created -> g
236 f1.txt: remote created -> g
237 getting f1.txt
237 getting f1.txt
238 updating: f1.txt 2/2 files (100.00%)
238 updating: f1.txt 2/2 files (100.00%)
239 merge against 9:e31216eec445
239 merge against 9:e31216eec445
240 detach base 8:8e4e2c1a07ae
240 detach base 8:8e4e2c1a07ae
241 searching for copies back to rev 3
241 searching for copies back to rev 3
242 resolving manifests
242 resolving manifests
243 branchmerge: True, force: True, partial: False
243 branchmerge: True, force: True, partial: False
244 ancestor: 8e4e2c1a07ae, local: 4bc80088dc6b+, remote: e31216eec445
244 ancestor: 8e4e2c1a07ae, local: 4bc80088dc6b+, remote: e31216eec445
245 f1.txt: remote is newer -> g
245 f1.txt: remote is newer -> g
246 getting f1.txt
246 getting f1.txt
247 updating: f1.txt 1/1 files (100.00%)
247 updating: f1.txt 1/1 files (100.00%)
248 committing files:
248 committing files:
249 f1.txt
249 f1.txt
250 committing manifest
250 committing manifest
251 committing changelog
251 committing changelog
252 rebased as 19c888675e13
252 rebased as 19c888675e13
253 rebasing 10:2f2496ddf49d "merge" (tip)
253 rebasing 10:2f2496ddf49d "merge" (tip)
254 rebasing: 10:2f2496ddf49d 6/6 changesets (100.00%)
254 rebasing: 10:2f2496ddf49d 6/6 changesets (100.00%)
255 future parents are 11 and 7
255 future parents are 11 and 7
256 rebase status stored
256 rebase status stored
257 already in target
257 already in target
258 merge against 10:2f2496ddf49d
258 merge against 10:2f2496ddf49d
259 detach base 9:e31216eec445
259 detach base 9:e31216eec445
260 searching for copies back to rev 3
260 searching for copies back to rev 3
261 resolving manifests
261 resolving manifests
262 branchmerge: True, force: True, partial: False
262 branchmerge: True, force: True, partial: False
263 ancestor: e31216eec445, local: 19c888675e13+, remote: 2f2496ddf49d
263 ancestor: e31216eec445, local: 19c888675e13+, remote: 2f2496ddf49d
264 f1.txt: remote is newer -> g
264 f1.txt: remote is newer -> g
265 getting f1.txt
265 getting f1.txt
266 updating: f1.txt 1/1 files (100.00%)
266 updating: f1.txt 1/1 files (100.00%)
267 committing files:
267 committing files:
268 f1.txt
268 f1.txt
269 committing manifest
269 committing manifest
270 committing changelog
270 committing changelog
271 rebased as 2a7f09cac94c
271 rebased as 2a7f09cac94c
272 rebase merging completed
272 rebase merging completed
273 update back to initial working directory parent
273 update back to initial working directory parent
274 resolving manifests
274 resolving manifests
275 branchmerge: False, force: False, partial: False
275 branchmerge: False, force: False, partial: False
276 ancestor: 2a7f09cac94c, local: 2a7f09cac94c+, remote: d79e2059b5c0
276 ancestor: 2a7f09cac94c, local: 2a7f09cac94c+, remote: d79e2059b5c0
277 f1.txt: other deleted -> r
277 f1.txt: other deleted -> r
278 removing f1.txt
278 removing f1.txt
279 updating: f1.txt 1/2 files (50.00%)
279 updating: f1.txt 1/2 files (50.00%)
280 f2.txt: remote created -> g
280 f2.txt: remote created -> g
281 getting f2.txt
281 getting f2.txt
282 updating: f2.txt 2/2 files (100.00%)
282 updating: f2.txt 2/2 files (100.00%)
283 3 changesets found
283 2 changesets found
284 list of changesets:
284 list of changesets:
285 4c9fbe56a16f30c0d5dcc40ec1a97bbe3325209c
286 e31216eec445e44352c5f01588856059466a24c9
285 e31216eec445e44352c5f01588856059466a24c9
287 2f2496ddf49d69b5ef23ad8cf9fb2e0e4faf0ac2
286 2f2496ddf49d69b5ef23ad8cf9fb2e0e4faf0ac2
288 bundling: 1/3 changesets (33.33%)
287 bundling: 1/2 changesets (50.00%)
289 bundling: 2/3 changesets (66.67%)
288 bundling: 2/2 changesets (100.00%)
290 bundling: 3/3 changesets (100.00%)
289 bundling: 1/2 manifests (50.00%)
291 bundling: 1/3 manifests (33.33%)
290 bundling: 2/2 manifests (100.00%)
292 bundling: 2/3 manifests (66.67%)
293 bundling: 3/3 manifests (100.00%)
294 bundling: f1.txt 1/1 files (100.00%)
291 bundling: f1.txt 1/1 files (100.00%)
295 saved backup bundle to $TESTTMP/issue4041/.hg/strip-backup/e31216eec445-15f7a814-backup.hg (glob)
292 saved backup bundle to $TESTTMP/issue4041/.hg/strip-backup/e31216eec445-15f7a814-backup.hg (glob)
296 3 changesets found
293 3 changesets found
297 list of changesets:
294 list of changesets:
298 4c9fbe56a16f30c0d5dcc40ec1a97bbe3325209c
295 4c9fbe56a16f30c0d5dcc40ec1a97bbe3325209c
299 19c888675e133ab5dff84516926a65672eaf04d9
296 19c888675e133ab5dff84516926a65672eaf04d9
300 2a7f09cac94c7f4b73ebd5cd1a62d3b2e8e336bf
297 2a7f09cac94c7f4b73ebd5cd1a62d3b2e8e336bf
301 bundling: 1/3 changesets (33.33%)
298 bundling: 1/3 changesets (33.33%)
302 bundling: 2/3 changesets (66.67%)
299 bundling: 2/3 changesets (66.67%)
303 bundling: 3/3 changesets (100.00%)
300 bundling: 3/3 changesets (100.00%)
304 bundling: 1/3 manifests (33.33%)
301 bundling: 1/3 manifests (33.33%)
305 bundling: 2/3 manifests (66.67%)
302 bundling: 2/3 manifests (66.67%)
306 bundling: 3/3 manifests (100.00%)
303 bundling: 3/3 manifests (100.00%)
307 bundling: f1.txt 1/1 files (100.00%)
304 bundling: f1.txt 1/1 files (100.00%)
308 adding branch
305 adding branch
309 adding changesets
306 adding changesets
310 changesets: 1 chunks
307 changesets: 1 chunks
311 add changeset 4c9fbe56a16f
308 add changeset 4c9fbe56a16f
312 changesets: 2 chunks
309 changesets: 2 chunks
313 add changeset 19c888675e13
310 add changeset 19c888675e13
314 changesets: 3 chunks
311 changesets: 3 chunks
315 add changeset 2a7f09cac94c
312 add changeset 2a7f09cac94c
316 adding manifests
313 adding manifests
317 manifests: 1/2 chunks (50.00%)
314 manifests: 1/2 chunks (50.00%)
318 manifests: 2/2 chunks (100.00%)
315 manifests: 2/2 chunks (100.00%)
319 manifests: 3/2 chunks (150.00%)
316 manifests: 3/2 chunks (150.00%)
320 adding file changes
317 adding file changes
321 adding f1.txt revisions
318 adding f1.txt revisions
322 files: 1/1 chunks (100.00%)
319 files: 1/1 chunks (100.00%)
323 added 2 changesets with 2 changes to 1 files
320 added 2 changesets with 2 changes to 1 files
324 invalid branchheads cache (served): tip differs
321 invalid branchheads cache (served): tip differs
325 rebase completed
322 rebase completed
326 updating the branch cache
323 updating the branch cache
327 truncating cache/rbc-revs-v1 to 72
324 truncating cache/rbc-revs-v1 to 72
@@ -1,692 +1,832 b''
1 $ echo "[extensions]" >> $HGRCPATH
1 $ echo "[extensions]" >> $HGRCPATH
2 $ echo "strip=" >> $HGRCPATH
2 $ echo "strip=" >> $HGRCPATH
3
3
4 $ restore() {
4 $ restore() {
5 > hg unbundle -q .hg/strip-backup/*
5 > hg unbundle -q .hg/strip-backup/*
6 > rm .hg/strip-backup/*
6 > rm .hg/strip-backup/*
7 > }
7 > }
8 $ teststrip() {
8 $ teststrip() {
9 > hg up -C $1
9 > hg up -C $1
10 > echo % before update $1, strip $2
10 > echo % before update $1, strip $2
11 > hg parents
11 > hg parents
12 > hg --traceback strip $2
12 > hg --traceback strip $2
13 > echo % after update $1, strip $2
13 > echo % after update $1, strip $2
14 > hg parents
14 > hg parents
15 > restore
15 > restore
16 > }
16 > }
17
17
18 $ hg init test
18 $ hg init test
19 $ cd test
19 $ cd test
20
20
21 $ echo foo > bar
21 $ echo foo > bar
22 $ hg ci -Ama
22 $ hg ci -Ama
23 adding bar
23 adding bar
24
24
25 $ echo more >> bar
25 $ echo more >> bar
26 $ hg ci -Amb
26 $ hg ci -Amb
27
27
28 $ echo blah >> bar
28 $ echo blah >> bar
29 $ hg ci -Amc
29 $ hg ci -Amc
30
30
31 $ hg up 1
31 $ hg up 1
32 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
32 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
33 $ echo blah >> bar
33 $ echo blah >> bar
34 $ hg ci -Amd
34 $ hg ci -Amd
35 created new head
35 created new head
36
36
37 $ echo final >> bar
37 $ echo final >> bar
38 $ hg ci -Ame
38 $ hg ci -Ame
39
39
40 $ hg log
40 $ hg log
41 changeset: 4:443431ffac4f
41 changeset: 4:443431ffac4f
42 tag: tip
42 tag: tip
43 user: test
43 user: test
44 date: Thu Jan 01 00:00:00 1970 +0000
44 date: Thu Jan 01 00:00:00 1970 +0000
45 summary: e
45 summary: e
46
46
47 changeset: 3:65bd5f99a4a3
47 changeset: 3:65bd5f99a4a3
48 parent: 1:ef3a871183d7
48 parent: 1:ef3a871183d7
49 user: test
49 user: test
50 date: Thu Jan 01 00:00:00 1970 +0000
50 date: Thu Jan 01 00:00:00 1970 +0000
51 summary: d
51 summary: d
52
52
53 changeset: 2:264128213d29
53 changeset: 2:264128213d29
54 user: test
54 user: test
55 date: Thu Jan 01 00:00:00 1970 +0000
55 date: Thu Jan 01 00:00:00 1970 +0000
56 summary: c
56 summary: c
57
57
58 changeset: 1:ef3a871183d7
58 changeset: 1:ef3a871183d7
59 user: test
59 user: test
60 date: Thu Jan 01 00:00:00 1970 +0000
60 date: Thu Jan 01 00:00:00 1970 +0000
61 summary: b
61 summary: b
62
62
63 changeset: 0:9ab35a2d17cb
63 changeset: 0:9ab35a2d17cb
64 user: test
64 user: test
65 date: Thu Jan 01 00:00:00 1970 +0000
65 date: Thu Jan 01 00:00:00 1970 +0000
66 summary: a
66 summary: a
67
67
68
68
69 $ teststrip 4 4
69 $ teststrip 4 4
70 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
70 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
71 % before update 4, strip 4
71 % before update 4, strip 4
72 changeset: 4:443431ffac4f
72 changeset: 4:443431ffac4f
73 tag: tip
73 tag: tip
74 user: test
74 user: test
75 date: Thu Jan 01 00:00:00 1970 +0000
75 date: Thu Jan 01 00:00:00 1970 +0000
76 summary: e
76 summary: e
77
77
78 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
78 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
79 saved backup bundle to $TESTTMP/test/.hg/strip-backup/*-backup.hg (glob)
79 saved backup bundle to $TESTTMP/test/.hg/strip-backup/*-backup.hg (glob)
80 % after update 4, strip 4
80 % after update 4, strip 4
81 changeset: 3:65bd5f99a4a3
81 changeset: 3:65bd5f99a4a3
82 tag: tip
82 tag: tip
83 parent: 1:ef3a871183d7
83 parent: 1:ef3a871183d7
84 user: test
84 user: test
85 date: Thu Jan 01 00:00:00 1970 +0000
85 date: Thu Jan 01 00:00:00 1970 +0000
86 summary: d
86 summary: d
87
87
88 $ teststrip 4 3
88 $ teststrip 4 3
89 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
89 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
90 % before update 4, strip 3
90 % before update 4, strip 3
91 changeset: 4:443431ffac4f
91 changeset: 4:443431ffac4f
92 tag: tip
92 tag: tip
93 user: test
93 user: test
94 date: Thu Jan 01 00:00:00 1970 +0000
94 date: Thu Jan 01 00:00:00 1970 +0000
95 summary: e
95 summary: e
96
96
97 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
97 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
98 saved backup bundle to $TESTTMP/test/.hg/strip-backup/*-backup.hg (glob)
98 saved backup bundle to $TESTTMP/test/.hg/strip-backup/*-backup.hg (glob)
99 % after update 4, strip 3
99 % after update 4, strip 3
100 changeset: 1:ef3a871183d7
100 changeset: 1:ef3a871183d7
101 user: test
101 user: test
102 date: Thu Jan 01 00:00:00 1970 +0000
102 date: Thu Jan 01 00:00:00 1970 +0000
103 summary: b
103 summary: b
104
104
105 $ teststrip 1 4
105 $ teststrip 1 4
106 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
106 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
107 % before update 1, strip 4
107 % before update 1, strip 4
108 changeset: 1:ef3a871183d7
108 changeset: 1:ef3a871183d7
109 user: test
109 user: test
110 date: Thu Jan 01 00:00:00 1970 +0000
110 date: Thu Jan 01 00:00:00 1970 +0000
111 summary: b
111 summary: b
112
112
113 saved backup bundle to $TESTTMP/test/.hg/strip-backup/*-backup.hg (glob)
113 saved backup bundle to $TESTTMP/test/.hg/strip-backup/*-backup.hg (glob)
114 % after update 1, strip 4
114 % after update 1, strip 4
115 changeset: 1:ef3a871183d7
115 changeset: 1:ef3a871183d7
116 user: test
116 user: test
117 date: Thu Jan 01 00:00:00 1970 +0000
117 date: Thu Jan 01 00:00:00 1970 +0000
118 summary: b
118 summary: b
119
119
120 $ teststrip 4 2
120 $ teststrip 4 2
121 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
121 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
122 % before update 4, strip 2
122 % before update 4, strip 2
123 changeset: 4:443431ffac4f
123 changeset: 4:443431ffac4f
124 tag: tip
124 tag: tip
125 user: test
125 user: test
126 date: Thu Jan 01 00:00:00 1970 +0000
126 date: Thu Jan 01 00:00:00 1970 +0000
127 summary: e
127 summary: e
128
128
129 saved backup bundle to $TESTTMP/test/.hg/strip-backup/*-backup.hg (glob)
129 saved backup bundle to $TESTTMP/test/.hg/strip-backup/*-backup.hg (glob)
130 % after update 4, strip 2
130 % after update 4, strip 2
131 changeset: 3:443431ffac4f
131 changeset: 3:443431ffac4f
132 tag: tip
132 tag: tip
133 user: test
133 user: test
134 date: Thu Jan 01 00:00:00 1970 +0000
134 date: Thu Jan 01 00:00:00 1970 +0000
135 summary: e
135 summary: e
136
136
137 $ teststrip 4 1
137 $ teststrip 4 1
138 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
138 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
139 % before update 4, strip 1
139 % before update 4, strip 1
140 changeset: 4:264128213d29
140 changeset: 4:264128213d29
141 tag: tip
141 tag: tip
142 parent: 1:ef3a871183d7
142 parent: 1:ef3a871183d7
143 user: test
143 user: test
144 date: Thu Jan 01 00:00:00 1970 +0000
144 date: Thu Jan 01 00:00:00 1970 +0000
145 summary: c
145 summary: c
146
146
147 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
147 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
148 saved backup bundle to $TESTTMP/test/.hg/strip-backup/*-backup.hg (glob)
148 saved backup bundle to $TESTTMP/test/.hg/strip-backup/*-backup.hg (glob)
149 % after update 4, strip 1
149 % after update 4, strip 1
150 changeset: 0:9ab35a2d17cb
150 changeset: 0:9ab35a2d17cb
151 tag: tip
151 tag: tip
152 user: test
152 user: test
153 date: Thu Jan 01 00:00:00 1970 +0000
153 date: Thu Jan 01 00:00:00 1970 +0000
154 summary: a
154 summary: a
155
155
156 $ teststrip null 4
156 $ teststrip null 4
157 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
157 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
158 % before update null, strip 4
158 % before update null, strip 4
159 saved backup bundle to $TESTTMP/test/.hg/strip-backup/*-backup.hg (glob)
159 saved backup bundle to $TESTTMP/test/.hg/strip-backup/*-backup.hg (glob)
160 % after update null, strip 4
160 % after update null, strip 4
161
161
162 $ hg log
162 $ hg log
163 changeset: 4:264128213d29
163 changeset: 4:264128213d29
164 tag: tip
164 tag: tip
165 parent: 1:ef3a871183d7
165 parent: 1:ef3a871183d7
166 user: test
166 user: test
167 date: Thu Jan 01 00:00:00 1970 +0000
167 date: Thu Jan 01 00:00:00 1970 +0000
168 summary: c
168 summary: c
169
169
170 changeset: 3:443431ffac4f
170 changeset: 3:443431ffac4f
171 user: test
171 user: test
172 date: Thu Jan 01 00:00:00 1970 +0000
172 date: Thu Jan 01 00:00:00 1970 +0000
173 summary: e
173 summary: e
174
174
175 changeset: 2:65bd5f99a4a3
175 changeset: 2:65bd5f99a4a3
176 user: test
176 user: test
177 date: Thu Jan 01 00:00:00 1970 +0000
177 date: Thu Jan 01 00:00:00 1970 +0000
178 summary: d
178 summary: d
179
179
180 changeset: 1:ef3a871183d7
180 changeset: 1:ef3a871183d7
181 user: test
181 user: test
182 date: Thu Jan 01 00:00:00 1970 +0000
182 date: Thu Jan 01 00:00:00 1970 +0000
183 summary: b
183 summary: b
184
184
185 changeset: 0:9ab35a2d17cb
185 changeset: 0:9ab35a2d17cb
186 user: test
186 user: test
187 date: Thu Jan 01 00:00:00 1970 +0000
187 date: Thu Jan 01 00:00:00 1970 +0000
188 summary: a
188 summary: a
189
189
190 $ hg up -C 4
190 $ hg up -C 4
191 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
191 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
192 $ hg parents
192 $ hg parents
193 changeset: 4:264128213d29
193 changeset: 4:264128213d29
194 tag: tip
194 tag: tip
195 parent: 1:ef3a871183d7
195 parent: 1:ef3a871183d7
196 user: test
196 user: test
197 date: Thu Jan 01 00:00:00 1970 +0000
197 date: Thu Jan 01 00:00:00 1970 +0000
198 summary: c
198 summary: c
199
199
200 $ hg --config experimental.bundle2-exp=True --config experimental.strip-bundle2-version=INVALID strip 4
200 $ hg --config experimental.bundle2-exp=True --config experimental.strip-bundle2-version=INVALID strip 4
201 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
201 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
202 unknown strip-bundle2-version value 'INVALID'; should be one of ['01', '02']
202 unknown strip-bundle2-version value 'INVALID'; should be one of ['01', '02']
203 saved backup bundle to $TESTTMP/test/.hg/strip-backup/264128213d29-0b39d6bf-backup.hg (glob)
203 saved backup bundle to $TESTTMP/test/.hg/strip-backup/264128213d29-0b39d6bf-backup.hg (glob)
204 $ hg debugbundle .hg/strip-backup/*
204 $ hg debugbundle .hg/strip-backup/*
205 264128213d290d868c54642d13aeaa3675551a78
205 264128213d290d868c54642d13aeaa3675551a78
206 $ restore
206 $ restore
207
207
208 $ hg up -C 4
208 $ hg up -C 4
209 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
209 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
210 $ hg --config experimental.bundle2-exp=True --config experimental.strip-bundle2-version=02 --traceback strip 4
210 $ hg --config experimental.bundle2-exp=True --config experimental.strip-bundle2-version=02 --traceback strip 4
211 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
211 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
212 saved backup bundle to $TESTTMP/test/.hg/strip-backup/264128213d29-0b39d6bf-backup.hg (glob)
212 saved backup bundle to $TESTTMP/test/.hg/strip-backup/264128213d29-0b39d6bf-backup.hg (glob)
213 $ hg parents
213 $ hg parents
214 changeset: 1:ef3a871183d7
214 changeset: 1:ef3a871183d7
215 user: test
215 user: test
216 date: Thu Jan 01 00:00:00 1970 +0000
216 date: Thu Jan 01 00:00:00 1970 +0000
217 summary: b
217 summary: b
218
218
219 $ hg debugbundle .hg/strip-backup/*
219 $ hg debugbundle .hg/strip-backup/*
220 Stream params: {}
220 Stream params: {}
221 changegroup -- "{'version': '02'}"
221 changegroup -- "{'version': '02'}"
222 264128213d290d868c54642d13aeaa3675551a78
222 264128213d290d868c54642d13aeaa3675551a78
223 $ hg incoming .hg/strip-backup/*
223 $ hg incoming .hg/strip-backup/*
224 comparing with .hg/strip-backup/264128213d29-0b39d6bf-backup.hg
224 comparing with .hg/strip-backup/264128213d29-0b39d6bf-backup.hg
225 searching for changes
225 searching for changes
226 changeset: 4:264128213d29
226 changeset: 4:264128213d29
227 tag: tip
227 tag: tip
228 parent: 1:ef3a871183d7
228 parent: 1:ef3a871183d7
229 user: test
229 user: test
230 date: Thu Jan 01 00:00:00 1970 +0000
230 date: Thu Jan 01 00:00:00 1970 +0000
231 summary: c
231 summary: c
232
232
233 $ restore
233 $ restore
234 $ hg up -C 4
234 $ hg up -C 4
235 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
235 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
236 $ hg --config experimental.bundle2-exp=True --config experimental.strip-bundle2-version=02 --traceback strip 4
236 $ hg --config experimental.bundle2-exp=True --config experimental.strip-bundle2-version=02 --traceback strip 4
237 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
237 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
238 saved backup bundle to $TESTTMP/test/.hg/strip-backup/264128213d29-0b39d6bf-backup.hg (glob)
238 saved backup bundle to $TESTTMP/test/.hg/strip-backup/264128213d29-0b39d6bf-backup.hg (glob)
239 $ hg parents
239 $ hg parents
240 changeset: 1:ef3a871183d7
240 changeset: 1:ef3a871183d7
241 user: test
241 user: test
242 date: Thu Jan 01 00:00:00 1970 +0000
242 date: Thu Jan 01 00:00:00 1970 +0000
243 summary: b
243 summary: b
244
244
245 $ hg debugbundle .hg/strip-backup/*
245 $ hg debugbundle .hg/strip-backup/*
246 Stream params: {}
246 Stream params: {}
247 changegroup -- "{'version': '02'}"
247 changegroup -- "{'version': '02'}"
248 264128213d290d868c54642d13aeaa3675551a78
248 264128213d290d868c54642d13aeaa3675551a78
249 $ hg pull .hg/strip-backup/*
249 $ hg pull .hg/strip-backup/*
250 pulling from .hg/strip-backup/264128213d29-0b39d6bf-backup.hg
250 pulling from .hg/strip-backup/264128213d29-0b39d6bf-backup.hg
251 searching for changes
251 searching for changes
252 adding changesets
252 adding changesets
253 adding manifests
253 adding manifests
254 adding file changes
254 adding file changes
255 added 1 changesets with 0 changes to 0 files (+1 heads)
255 added 1 changesets with 0 changes to 0 files (+1 heads)
256 (run 'hg heads' to see heads, 'hg merge' to merge)
256 (run 'hg heads' to see heads, 'hg merge' to merge)
257 $ rm .hg/strip-backup/*
257 $ rm .hg/strip-backup/*
258 $ hg log --graph
258 $ hg log --graph
259 o changeset: 4:264128213d29
259 o changeset: 4:264128213d29
260 | tag: tip
260 | tag: tip
261 | parent: 1:ef3a871183d7
261 | parent: 1:ef3a871183d7
262 | user: test
262 | user: test
263 | date: Thu Jan 01 00:00:00 1970 +0000
263 | date: Thu Jan 01 00:00:00 1970 +0000
264 | summary: c
264 | summary: c
265 |
265 |
266 | o changeset: 3:443431ffac4f
266 | o changeset: 3:443431ffac4f
267 | | user: test
267 | | user: test
268 | | date: Thu Jan 01 00:00:00 1970 +0000
268 | | date: Thu Jan 01 00:00:00 1970 +0000
269 | | summary: e
269 | | summary: e
270 | |
270 | |
271 | o changeset: 2:65bd5f99a4a3
271 | o changeset: 2:65bd5f99a4a3
272 |/ user: test
272 |/ user: test
273 | date: Thu Jan 01 00:00:00 1970 +0000
273 | date: Thu Jan 01 00:00:00 1970 +0000
274 | summary: d
274 | summary: d
275 |
275 |
276 @ changeset: 1:ef3a871183d7
276 @ changeset: 1:ef3a871183d7
277 | user: test
277 | user: test
278 | date: Thu Jan 01 00:00:00 1970 +0000
278 | date: Thu Jan 01 00:00:00 1970 +0000
279 | summary: b
279 | summary: b
280 |
280 |
281 o changeset: 0:9ab35a2d17cb
281 o changeset: 0:9ab35a2d17cb
282 user: test
282 user: test
283 date: Thu Jan 01 00:00:00 1970 +0000
283 date: Thu Jan 01 00:00:00 1970 +0000
284 summary: a
284 summary: a
285
285
286 $ hg up -C 2
286 $ hg up -C 2
287 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
287 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
288 $ hg merge 4
288 $ hg merge 4
289 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
289 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
290 (branch merge, don't forget to commit)
290 (branch merge, don't forget to commit)
291
291
292 before strip of merge parent
292 before strip of merge parent
293
293
294 $ hg parents
294 $ hg parents
295 changeset: 2:65bd5f99a4a3
295 changeset: 2:65bd5f99a4a3
296 user: test
296 user: test
297 date: Thu Jan 01 00:00:00 1970 +0000
297 date: Thu Jan 01 00:00:00 1970 +0000
298 summary: d
298 summary: d
299
299
300 changeset: 4:264128213d29
300 changeset: 4:264128213d29
301 tag: tip
301 tag: tip
302 parent: 1:ef3a871183d7
302 parent: 1:ef3a871183d7
303 user: test
303 user: test
304 date: Thu Jan 01 00:00:00 1970 +0000
304 date: Thu Jan 01 00:00:00 1970 +0000
305 summary: c
305 summary: c
306
306
307 $ hg strip 4
307 $ hg strip 4
308 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
308 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
309 saved backup bundle to $TESTTMP/test/.hg/strip-backup/*-backup.hg (glob)
309 saved backup bundle to $TESTTMP/test/.hg/strip-backup/*-backup.hg (glob)
310
310
311 after strip of merge parent
311 after strip of merge parent
312
312
313 $ hg parents
313 $ hg parents
314 changeset: 1:ef3a871183d7
314 changeset: 1:ef3a871183d7
315 user: test
315 user: test
316 date: Thu Jan 01 00:00:00 1970 +0000
316 date: Thu Jan 01 00:00:00 1970 +0000
317 summary: b
317 summary: b
318
318
319 $ restore
319 $ restore
320
320
321 $ hg up
321 $ hg up
322 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
322 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
323 $ hg log -G
323 $ hg log -G
324 @ changeset: 4:264128213d29
324 @ changeset: 4:264128213d29
325 | tag: tip
325 | tag: tip
326 | parent: 1:ef3a871183d7
326 | parent: 1:ef3a871183d7
327 | user: test
327 | user: test
328 | date: Thu Jan 01 00:00:00 1970 +0000
328 | date: Thu Jan 01 00:00:00 1970 +0000
329 | summary: c
329 | summary: c
330 |
330 |
331 | o changeset: 3:443431ffac4f
331 | o changeset: 3:443431ffac4f
332 | | user: test
332 | | user: test
333 | | date: Thu Jan 01 00:00:00 1970 +0000
333 | | date: Thu Jan 01 00:00:00 1970 +0000
334 | | summary: e
334 | | summary: e
335 | |
335 | |
336 | o changeset: 2:65bd5f99a4a3
336 | o changeset: 2:65bd5f99a4a3
337 |/ user: test
337 |/ user: test
338 | date: Thu Jan 01 00:00:00 1970 +0000
338 | date: Thu Jan 01 00:00:00 1970 +0000
339 | summary: d
339 | summary: d
340 |
340 |
341 o changeset: 1:ef3a871183d7
341 o changeset: 1:ef3a871183d7
342 | user: test
342 | user: test
343 | date: Thu Jan 01 00:00:00 1970 +0000
343 | date: Thu Jan 01 00:00:00 1970 +0000
344 | summary: b
344 | summary: b
345 |
345 |
346 o changeset: 0:9ab35a2d17cb
346 o changeset: 0:9ab35a2d17cb
347 user: test
347 user: test
348 date: Thu Jan 01 00:00:00 1970 +0000
348 date: Thu Jan 01 00:00:00 1970 +0000
349 summary: a
349 summary: a
350
350
351
351
352 2 is parent of 3, only one strip should happen
352 2 is parent of 3, only one strip should happen
353
353
354 $ hg strip "roots(2)" 3
354 $ hg strip "roots(2)" 3
355 saved backup bundle to $TESTTMP/test/.hg/strip-backup/*-backup.hg (glob)
355 saved backup bundle to $TESTTMP/test/.hg/strip-backup/*-backup.hg (glob)
356 $ hg log -G
356 $ hg log -G
357 @ changeset: 2:264128213d29
357 @ changeset: 2:264128213d29
358 | tag: tip
358 | tag: tip
359 | user: test
359 | user: test
360 | date: Thu Jan 01 00:00:00 1970 +0000
360 | date: Thu Jan 01 00:00:00 1970 +0000
361 | summary: c
361 | summary: c
362 |
362 |
363 o changeset: 1:ef3a871183d7
363 o changeset: 1:ef3a871183d7
364 | user: test
364 | user: test
365 | date: Thu Jan 01 00:00:00 1970 +0000
365 | date: Thu Jan 01 00:00:00 1970 +0000
366 | summary: b
366 | summary: b
367 |
367 |
368 o changeset: 0:9ab35a2d17cb
368 o changeset: 0:9ab35a2d17cb
369 user: test
369 user: test
370 date: Thu Jan 01 00:00:00 1970 +0000
370 date: Thu Jan 01 00:00:00 1970 +0000
371 summary: a
371 summary: a
372
372
373 $ restore
373 $ restore
374 $ hg log -G
374 $ hg log -G
375 o changeset: 4:443431ffac4f
375 o changeset: 4:443431ffac4f
376 | tag: tip
376 | tag: tip
377 | user: test
377 | user: test
378 | date: Thu Jan 01 00:00:00 1970 +0000
378 | date: Thu Jan 01 00:00:00 1970 +0000
379 | summary: e
379 | summary: e
380 |
380 |
381 o changeset: 3:65bd5f99a4a3
381 o changeset: 3:65bd5f99a4a3
382 | parent: 1:ef3a871183d7
382 | parent: 1:ef3a871183d7
383 | user: test
383 | user: test
384 | date: Thu Jan 01 00:00:00 1970 +0000
384 | date: Thu Jan 01 00:00:00 1970 +0000
385 | summary: d
385 | summary: d
386 |
386 |
387 | @ changeset: 2:264128213d29
387 | @ changeset: 2:264128213d29
388 |/ user: test
388 |/ user: test
389 | date: Thu Jan 01 00:00:00 1970 +0000
389 | date: Thu Jan 01 00:00:00 1970 +0000
390 | summary: c
390 | summary: c
391 |
391 |
392 o changeset: 1:ef3a871183d7
392 o changeset: 1:ef3a871183d7
393 | user: test
393 | user: test
394 | date: Thu Jan 01 00:00:00 1970 +0000
394 | date: Thu Jan 01 00:00:00 1970 +0000
395 | summary: b
395 | summary: b
396 |
396 |
397 o changeset: 0:9ab35a2d17cb
397 o changeset: 0:9ab35a2d17cb
398 user: test
398 user: test
399 date: Thu Jan 01 00:00:00 1970 +0000
399 date: Thu Jan 01 00:00:00 1970 +0000
400 summary: a
400 summary: a
401
401
402
402
403 2 different branches: 2 strips
403 2 different branches: 2 strips
404
404
405 $ hg strip 2 4
405 $ hg strip 2 4
406 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
406 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
407 saved backup bundle to $TESTTMP/test/.hg/strip-backup/*-backup.hg (glob)
407 saved backup bundle to $TESTTMP/test/.hg/strip-backup/*-backup.hg (glob)
408 $ hg log -G
408 $ hg log -G
409 o changeset: 2:65bd5f99a4a3
409 o changeset: 2:65bd5f99a4a3
410 | tag: tip
410 | tag: tip
411 | user: test
411 | user: test
412 | date: Thu Jan 01 00:00:00 1970 +0000
412 | date: Thu Jan 01 00:00:00 1970 +0000
413 | summary: d
413 | summary: d
414 |
414 |
415 @ changeset: 1:ef3a871183d7
415 @ changeset: 1:ef3a871183d7
416 | user: test
416 | user: test
417 | date: Thu Jan 01 00:00:00 1970 +0000
417 | date: Thu Jan 01 00:00:00 1970 +0000
418 | summary: b
418 | summary: b
419 |
419 |
420 o changeset: 0:9ab35a2d17cb
420 o changeset: 0:9ab35a2d17cb
421 user: test
421 user: test
422 date: Thu Jan 01 00:00:00 1970 +0000
422 date: Thu Jan 01 00:00:00 1970 +0000
423 summary: a
423 summary: a
424
424
425 $ restore
425 $ restore
426
426
427 2 different branches and a common ancestor: 1 strip
427 2 different branches and a common ancestor: 1 strip
428
428
429 $ hg strip 1 "2|4"
429 $ hg strip 1 "2|4"
430 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
430 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
431 saved backup bundle to $TESTTMP/test/.hg/strip-backup/*-backup.hg (glob)
431 saved backup bundle to $TESTTMP/test/.hg/strip-backup/*-backup.hg (glob)
432 $ restore
432 $ restore
433
433
434 verify fncache is kept up-to-date
434 verify fncache is kept up-to-date
435
435
436 $ touch a
436 $ touch a
437 $ hg ci -qAm a
437 $ hg ci -qAm a
438 $ cat .hg/store/fncache | sort
438 $ cat .hg/store/fncache | sort
439 data/a.i
439 data/a.i
440 data/bar.i
440 data/bar.i
441 $ hg strip tip
441 $ hg strip tip
442 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
442 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
443 saved backup bundle to $TESTTMP/test/.hg/strip-backup/*-backup.hg (glob)
443 saved backup bundle to $TESTTMP/test/.hg/strip-backup/*-backup.hg (glob)
444 $ cat .hg/store/fncache
444 $ cat .hg/store/fncache
445 data/bar.i
445 data/bar.i
446
446
447 stripping an empty revset
447 stripping an empty revset
448
448
449 $ hg strip "1 and not 1"
449 $ hg strip "1 and not 1"
450 abort: empty revision set
450 abort: empty revision set
451 [255]
451 [255]
452
452
453 remove branchy history for qimport tests
453 remove branchy history for qimport tests
454
454
455 $ hg strip 3
455 $ hg strip 3
456 saved backup bundle to $TESTTMP/test/.hg/strip-backup/*-backup.hg (glob)
456 saved backup bundle to $TESTTMP/test/.hg/strip-backup/*-backup.hg (glob)
457
457
458
458
459 strip of applied mq should cleanup status file
459 strip of applied mq should cleanup status file
460
460
461 $ echo "mq=" >> $HGRCPATH
461 $ echo "mq=" >> $HGRCPATH
462 $ hg up -C 3
462 $ hg up -C 3
463 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
463 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
464 $ echo fooagain >> bar
464 $ echo fooagain >> bar
465 $ hg ci -mf
465 $ hg ci -mf
466 $ hg qimport -r tip:2
466 $ hg qimport -r tip:2
467
467
468 applied patches before strip
468 applied patches before strip
469
469
470 $ hg qapplied
470 $ hg qapplied
471 2.diff
471 2.diff
472 3.diff
472 3.diff
473 4.diff
473 4.diff
474
474
475 stripping revision in queue
475 stripping revision in queue
476
476
477 $ hg strip 3
477 $ hg strip 3
478 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
478 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
479 saved backup bundle to $TESTTMP/test/.hg/strip-backup/*-backup.hg (glob)
479 saved backup bundle to $TESTTMP/test/.hg/strip-backup/*-backup.hg (glob)
480
480
481 applied patches after stripping rev in queue
481 applied patches after stripping rev in queue
482
482
483 $ hg qapplied
483 $ hg qapplied
484 2.diff
484 2.diff
485
485
486 stripping ancestor of queue
486 stripping ancestor of queue
487
487
488 $ hg strip 1
488 $ hg strip 1
489 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
489 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
490 saved backup bundle to $TESTTMP/test/.hg/strip-backup/*-backup.hg (glob)
490 saved backup bundle to $TESTTMP/test/.hg/strip-backup/*-backup.hg (glob)
491
491
492 applied patches after stripping ancestor of queue
492 applied patches after stripping ancestor of queue
493
493
494 $ hg qapplied
494 $ hg qapplied
495
495
496 Verify strip protects against stripping wc parent when there are uncommitted mods
496 Verify strip protects against stripping wc parent when there are uncommitted mods
497
497
498 $ echo b > b
498 $ echo b > b
499 $ echo bb > bar
499 $ echo bb > bar
500 $ hg add b
500 $ hg add b
501 $ hg ci -m 'b'
501 $ hg ci -m 'b'
502 $ hg log --graph
502 $ hg log --graph
503 @ changeset: 1:76dcf9fab855
503 @ changeset: 1:76dcf9fab855
504 | tag: tip
504 | tag: tip
505 | user: test
505 | user: test
506 | date: Thu Jan 01 00:00:00 1970 +0000
506 | date: Thu Jan 01 00:00:00 1970 +0000
507 | summary: b
507 | summary: b
508 |
508 |
509 o changeset: 0:9ab35a2d17cb
509 o changeset: 0:9ab35a2d17cb
510 user: test
510 user: test
511 date: Thu Jan 01 00:00:00 1970 +0000
511 date: Thu Jan 01 00:00:00 1970 +0000
512 summary: a
512 summary: a
513
513
514 $ hg up 0
514 $ hg up 0
515 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
515 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
516 $ echo c > bar
516 $ echo c > bar
517 $ hg up -t false
517 $ hg up -t false
518 merging bar
518 merging bar
519 merging bar failed!
519 merging bar failed!
520 1 files updated, 0 files merged, 0 files removed, 1 files unresolved
520 1 files updated, 0 files merged, 0 files removed, 1 files unresolved
521 use 'hg resolve' to retry unresolved file merges
521 use 'hg resolve' to retry unresolved file merges
522 [1]
522 [1]
523 $ hg sum
523 $ hg sum
524 parent: 1:76dcf9fab855 tip
524 parent: 1:76dcf9fab855 tip
525 b
525 b
526 branch: default
526 branch: default
527 commit: 1 modified, 1 unknown, 1 unresolved
527 commit: 1 modified, 1 unknown, 1 unresolved
528 update: (current)
528 update: (current)
529 mq: 3 unapplied
529 mq: 3 unapplied
530
530
531 $ echo c > b
531 $ echo c > b
532 $ hg strip tip
532 $ hg strip tip
533 abort: local changes found
533 abort: local changes found
534 [255]
534 [255]
535 $ hg strip tip --keep
535 $ hg strip tip --keep
536 saved backup bundle to $TESTTMP/test/.hg/strip-backup/*-backup.hg (glob)
536 saved backup bundle to $TESTTMP/test/.hg/strip-backup/*-backup.hg (glob)
537 $ hg log --graph
537 $ hg log --graph
538 @ changeset: 0:9ab35a2d17cb
538 @ changeset: 0:9ab35a2d17cb
539 tag: tip
539 tag: tip
540 user: test
540 user: test
541 date: Thu Jan 01 00:00:00 1970 +0000
541 date: Thu Jan 01 00:00:00 1970 +0000
542 summary: a
542 summary: a
543
543
544 $ hg status
544 $ hg status
545 M bar
545 M bar
546 ? b
546 ? b
547 ? bar.orig
547 ? bar.orig
548
548
549 $ rm bar.orig
549 $ rm bar.orig
550 $ hg sum
550 $ hg sum
551 parent: 0:9ab35a2d17cb tip
551 parent: 0:9ab35a2d17cb tip
552 a
552 a
553 branch: default
553 branch: default
554 commit: 1 modified, 1 unknown
554 commit: 1 modified, 1 unknown
555 update: (current)
555 update: (current)
556 mq: 3 unapplied
556 mq: 3 unapplied
557
557
558 Strip adds, removes, modifies with --keep
558 Strip adds, removes, modifies with --keep
559
559
560 $ touch b
560 $ touch b
561 $ hg add b
561 $ hg add b
562 $ hg commit -mb
562 $ hg commit -mb
563 $ touch c
563 $ touch c
564
564
565 ... with a clean working dir
565 ... with a clean working dir
566
566
567 $ hg add c
567 $ hg add c
568 $ hg rm bar
568 $ hg rm bar
569 $ hg commit -mc
569 $ hg commit -mc
570 $ hg status
570 $ hg status
571 $ hg strip --keep tip
571 $ hg strip --keep tip
572 saved backup bundle to $TESTTMP/test/.hg/strip-backup/*-backup.hg (glob)
572 saved backup bundle to $TESTTMP/test/.hg/strip-backup/*-backup.hg (glob)
573 $ hg status
573 $ hg status
574 ! bar
574 ! bar
575 ? c
575 ? c
576
576
577 ... with a dirty working dir
577 ... with a dirty working dir
578
578
579 $ hg add c
579 $ hg add c
580 $ hg rm bar
580 $ hg rm bar
581 $ hg commit -mc
581 $ hg commit -mc
582 $ hg status
582 $ hg status
583 $ echo b > b
583 $ echo b > b
584 $ echo d > d
584 $ echo d > d
585 $ hg strip --keep tip
585 $ hg strip --keep tip
586 saved backup bundle to $TESTTMP/test/.hg/strip-backup/57e364c8a475-4cfed93c-backup.hg (glob)
586 saved backup bundle to $TESTTMP/test/.hg/strip-backup/57e364c8a475-4cfed93c-backup.hg (glob)
587 $ hg status
587 $ hg status
588 M b
588 M b
589 ! bar
589 ! bar
590 ? c
590 ? c
591 ? d
591 ? d
592 $ cd ..
592 $ cd ..
593
593
594 stripping many nodes on a complex graph (issue3299)
594 stripping many nodes on a complex graph (issue3299)
595
595
596 $ hg init issue3299
596 $ hg init issue3299
597 $ cd issue3299
597 $ cd issue3299
598 $ hg debugbuilddag '@a.:a@b.:b.:x<a@a.:a<b@b.:b<a@a.:a'
598 $ hg debugbuilddag '@a.:a@b.:b.:x<a@a.:a<b@b.:b<a@a.:a'
599 $ hg strip 'not ancestors(x)'
599 $ hg strip 'not ancestors(x)'
600 saved backup bundle to $TESTTMP/issue3299/.hg/strip-backup/*-backup.hg (glob)
600 saved backup bundle to $TESTTMP/issue3299/.hg/strip-backup/*-backup.hg (glob)
601
601
602 test hg strip -B bookmark
602 test hg strip -B bookmark
603
603
604 $ cd ..
604 $ cd ..
605 $ hg init bookmarks
605 $ hg init bookmarks
606 $ cd bookmarks
606 $ cd bookmarks
607 $ hg debugbuilddag '..<2.*1/2:m<2+3:c<m+3:a<2.:b'
607 $ hg debugbuilddag '..<2.*1/2:m<2+3:c<m+3:a<2.:b'
608 $ hg bookmark -r 'a' 'todelete'
608 $ hg bookmark -r 'a' 'todelete'
609 $ hg bookmark -r 'b' 'B'
609 $ hg bookmark -r 'b' 'B'
610 $ hg bookmark -r 'b' 'nostrip'
610 $ hg bookmark -r 'b' 'nostrip'
611 $ hg bookmark -r 'c' 'delete'
611 $ hg bookmark -r 'c' 'delete'
612 $ hg up -C todelete
612 $ hg up -C todelete
613 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
613 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
614 (activating bookmark todelete)
614 (activating bookmark todelete)
615 $ hg strip -B nostrip
615 $ hg strip -B nostrip
616 bookmark 'nostrip' deleted
616 bookmark 'nostrip' deleted
617 abort: empty revision set
617 abort: empty revision set
618 [255]
618 [255]
619 $ hg strip -B todelete
619 $ hg strip -B todelete
620 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
620 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
621 saved backup bundle to $TESTTMP/bookmarks/.hg/strip-backup/*-backup.hg (glob)
621 saved backup bundle to $TESTTMP/bookmarks/.hg/strip-backup/*-backup.hg (glob)
622 bookmark 'todelete' deleted
622 bookmark 'todelete' deleted
623 $ hg id -ir dcbb326fdec2
623 $ hg id -ir dcbb326fdec2
624 abort: unknown revision 'dcbb326fdec2'!
624 abort: unknown revision 'dcbb326fdec2'!
625 [255]
625 [255]
626 $ hg id -ir d62d843c9a01
626 $ hg id -ir d62d843c9a01
627 d62d843c9a01
627 d62d843c9a01
628 $ hg bookmarks
628 $ hg bookmarks
629 B 9:ff43616e5d0f
629 B 9:ff43616e5d0f
630 delete 6:2702dd0c91e7
630 delete 6:2702dd0c91e7
631 $ hg strip -B delete
631 $ hg strip -B delete
632 saved backup bundle to $TESTTMP/bookmarks/.hg/strip-backup/*-backup.hg (glob)
632 saved backup bundle to $TESTTMP/bookmarks/.hg/strip-backup/*-backup.hg (glob)
633 bookmark 'delete' deleted
633 bookmark 'delete' deleted
634 $ hg id -ir 6:2702dd0c91e7
634 $ hg id -ir 6:2702dd0c91e7
635 abort: unknown revision '2702dd0c91e7'!
635 abort: unknown revision '2702dd0c91e7'!
636 [255]
636 [255]
637 $ hg update B
637 $ hg update B
638 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
638 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
639 (activating bookmark B)
639 (activating bookmark B)
640 $ echo a > a
640 $ echo a > a
641 $ hg add a
641 $ hg add a
642 $ hg strip -B B
642 $ hg strip -B B
643 abort: local changes found
643 abort: local changes found
644 [255]
644 [255]
645 $ hg bookmarks
645 $ hg bookmarks
646 * B 6:ff43616e5d0f
646 * B 6:ff43616e5d0f
647
647
648 Make sure no one adds back a -b option:
648 Make sure no one adds back a -b option:
649
649
650 $ hg strip -b tip
650 $ hg strip -b tip
651 hg strip: option -b not recognized
651 hg strip: option -b not recognized
652 hg strip [-k] [-f] [-n] [-B bookmark] [-r] REV...
652 hg strip [-k] [-f] [-n] [-B bookmark] [-r] REV...
653
653
654 strip changesets and all their descendants from the repository
654 strip changesets and all their descendants from the repository
655
655
656 (use "hg help -e strip" to show help for the strip extension)
656 (use "hg help -e strip" to show help for the strip extension)
657
657
658 options ([+] can be repeated):
658 options ([+] can be repeated):
659
659
660 -r --rev REV [+] strip specified revision (optional, can specify revisions
660 -r --rev REV [+] strip specified revision (optional, can specify revisions
661 without this option)
661 without this option)
662 -f --force force removal of changesets, discard uncommitted changes
662 -f --force force removal of changesets, discard uncommitted changes
663 (no backup)
663 (no backup)
664 --no-backup no backups
664 --no-backup no backups
665 -k --keep do not modify working directory during strip
665 -k --keep do not modify working directory during strip
666 -B --bookmark VALUE remove revs only reachable from given bookmark
666 -B --bookmark VALUE remove revs only reachable from given bookmark
667 --mq operate on patch repository
667 --mq operate on patch repository
668
668
669 (use "hg strip -h" to show more help)
669 (use "hg strip -h" to show more help)
670 [255]
670 [255]
671
671
672 $ cd ..
672 $ cd ..
673
673
674 Verify bundles don't get overwritten:
674 Verify bundles don't get overwritten:
675
675
676 $ hg init doublebundle
676 $ hg init doublebundle
677 $ cd doublebundle
677 $ cd doublebundle
678 $ touch a
678 $ touch a
679 $ hg commit -Aqm a
679 $ hg commit -Aqm a
680 $ touch b
680 $ touch b
681 $ hg commit -Aqm b
681 $ hg commit -Aqm b
682 $ hg strip -r 0
682 $ hg strip -r 0
683 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
683 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
684 saved backup bundle to $TESTTMP/doublebundle/.hg/strip-backup/3903775176ed-e68910bd-backup.hg (glob)
684 saved backup bundle to $TESTTMP/doublebundle/.hg/strip-backup/3903775176ed-e68910bd-backup.hg (glob)
685 $ ls .hg/strip-backup
685 $ ls .hg/strip-backup
686 3903775176ed-e68910bd-backup.hg
686 3903775176ed-e68910bd-backup.hg
687 $ hg pull -q -r 3903775176ed .hg/strip-backup/3903775176ed-e68910bd-backup.hg
687 $ hg pull -q -r 3903775176ed .hg/strip-backup/3903775176ed-e68910bd-backup.hg
688 $ hg strip -r 0
688 $ hg strip -r 0
689 saved backup bundle to $TESTTMP/doublebundle/.hg/strip-backup/3903775176ed-54390173-backup.hg (glob)
689 saved backup bundle to $TESTTMP/doublebundle/.hg/strip-backup/3903775176ed-54390173-backup.hg (glob)
690 $ ls .hg/strip-backup
690 $ ls .hg/strip-backup
691 3903775176ed-54390173-backup.hg
691 3903775176ed-54390173-backup.hg
692 3903775176ed-e68910bd-backup.hg
692 3903775176ed-e68910bd-backup.hg
693 $ cd ..
694
695 Test that we only bundle the stripped changesets (issue4736)
696 ------------------------------------------------------------
697
698 initialisation (previous repo is empty anyway)
699
700 $ hg init issue4736
701 $ cd issue4736
702 $ echo a > a
703 $ hg add a
704 $ hg commit -m commitA
705 $ echo b > b
706 $ hg add b
707 $ hg commit -m commitB
708 $ echo c > c
709 $ hg add c
710 $ hg commit -m commitC
711 $ hg up 'desc(commitB)'
712 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
713 $ echo d > d
714 $ hg add d
715 $ hg commit -m commitD
716 created new head
717 $ hg up 'desc(commitC)'
718 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
719 $ hg merge 'desc(commitD)'
720 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
721 (branch merge, don't forget to commit)
722 $ hg ci -m 'mergeCD'
723 $ hg log -G
724 @ changeset: 4:d8db9d137221
725 |\ tag: tip
726 | | parent: 2:5c51d8d6557d
727 | | parent: 3:6625a5168474
728 | | user: test
729 | | date: Thu Jan 01 00:00:00 1970 +0000
730 | | summary: mergeCD
731 | |
732 | o changeset: 3:6625a5168474
733 | | parent: 1:eca11cf91c71
734 | | user: test
735 | | date: Thu Jan 01 00:00:00 1970 +0000
736 | | summary: commitD
737 | |
738 o | changeset: 2:5c51d8d6557d
739 |/ user: test
740 | date: Thu Jan 01 00:00:00 1970 +0000
741 | summary: commitC
742 |
743 o changeset: 1:eca11cf91c71
744 | user: test
745 | date: Thu Jan 01 00:00:00 1970 +0000
746 | summary: commitB
747 |
748 o changeset: 0:105141ef12d0
749 user: test
750 date: Thu Jan 01 00:00:00 1970 +0000
751 summary: commitA
752
753
754 Check bundle behavior:
755
756 $ hg bundle -r 'desc(mergeCD)' --base 'desc(commitC)' ../issue4736.hg
757 2 changesets found
758 $ hg log -r 'bundle()' -R ../issue4736.hg
759 changeset: 3:6625a5168474
760 parent: 1:eca11cf91c71
761 user: test
762 date: Thu Jan 01 00:00:00 1970 +0000
763 summary: commitD
764
765 changeset: 4:d8db9d137221
766 tag: tip
767 parent: 2:5c51d8d6557d
768 parent: 3:6625a5168474
769 user: test
770 date: Thu Jan 01 00:00:00 1970 +0000
771 summary: mergeCD
772
773
774 check strip behavior
775
776 $ hg --config extensions.strip= strip 'desc(commitD)' --debug
777 resolving manifests
778 branchmerge: False, force: True, partial: False
779 ancestor: d8db9d137221+, local: d8db9d137221+, remote: eca11cf91c71
780 c: other deleted -> r
781 removing c
782 d: other deleted -> r
783 removing d
784 updating: d 2/2 files (100.00%)
785 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
786 2 changesets found
787 list of changesets:
788 6625a516847449b6f0fa3737b9ba56e9f0f3032c
789 d8db9d1372214336d2b5570f20ee468d2c72fa8b
790 bundling: 1/2 changesets (50.00%)
791 bundling: 2/2 changesets (100.00%)
792 bundling: 1/2 manifests (50.00%)
793 bundling: 2/2 manifests (100.00%)
794 bundling: d 1/1 files (100.00%)
795 saved backup bundle to $TESTTMP/issue4736/.hg/strip-backup/6625a5168474-345bb43d-backup.hg (glob)
796 invalid branchheads cache (served): tip differs
797 truncating cache/rbc-revs-v1 to 24
798 $ hg log -G
799 o changeset: 2:5c51d8d6557d
800 | tag: tip
801 | user: test
802 | date: Thu Jan 01 00:00:00 1970 +0000
803 | summary: commitC
804 |
805 @ changeset: 1:eca11cf91c71
806 | user: test
807 | date: Thu Jan 01 00:00:00 1970 +0000
808 | summary: commitB
809 |
810 o changeset: 0:105141ef12d0
811 user: test
812 date: Thu Jan 01 00:00:00 1970 +0000
813 summary: commitA
814
815
816 strip backup content
817
818 $ hg log -r 'bundle()' -R .hg/strip-backup/6625a5168474-*-backup.hg
819 changeset: 3:6625a5168474
820 parent: 1:eca11cf91c71
821 user: test
822 date: Thu Jan 01 00:00:00 1970 +0000
823 summary: commitD
824
825 changeset: 4:d8db9d137221
826 tag: tip
827 parent: 2:5c51d8d6557d
828 parent: 3:6625a5168474
829 user: test
830 date: Thu Jan 01 00:00:00 1970 +0000
831 summary: mergeCD
832
General Comments 0
You need to be logged in to leave comments. Login now