##// END OF EJS Templates
exchange: backout changeset c26335fa4225...
marmoute -
r45782:6063c185 stable
parent child Browse files
Show More
@@ -1,3162 +1,3157 b''
1 # exchange.py - utility to exchange data between repos.
1 # exchange.py - utility to exchange data between repos.
2 #
2 #
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
3 # Copyright 2005-2007 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 from __future__ import absolute_import
8 from __future__ import absolute_import
9
9
10 import collections
10 import collections
11 import weakref
11 import weakref
12
12
13 from .i18n import _
13 from .i18n import _
14 from .node import (
14 from .node import (
15 hex,
15 hex,
16 nullid,
16 nullid,
17 nullrev,
17 nullrev,
18 )
18 )
19 from .thirdparty import attr
19 from .thirdparty import attr
20 from . import (
20 from . import (
21 bookmarks as bookmod,
21 bookmarks as bookmod,
22 bundle2,
22 bundle2,
23 changegroup,
23 changegroup,
24 discovery,
24 discovery,
25 error,
25 error,
26 exchangev2,
26 exchangev2,
27 lock as lockmod,
27 lock as lockmod,
28 logexchange,
28 logexchange,
29 narrowspec,
29 narrowspec,
30 obsolete,
30 obsolete,
31 obsutil,
31 obsutil,
32 phases,
32 phases,
33 pushkey,
33 pushkey,
34 pycompat,
34 pycompat,
35 scmutil,
35 scmutil,
36 sslutil,
36 sslutil,
37 streamclone,
37 streamclone,
38 url as urlmod,
38 url as urlmod,
39 util,
39 util,
40 wireprototypes,
40 wireprototypes,
41 )
41 )
42 from .interfaces import repository
42 from .interfaces import repository
43 from .utils import (
43 from .utils import (
44 hashutil,
44 hashutil,
45 stringutil,
45 stringutil,
46 )
46 )
47
47
48 urlerr = util.urlerr
48 urlerr = util.urlerr
49 urlreq = util.urlreq
49 urlreq = util.urlreq
50
50
51 _NARROWACL_SECTION = b'narrowacl'
51 _NARROWACL_SECTION = b'narrowacl'
52
52
53 # Maps bundle version human names to changegroup versions.
53 # Maps bundle version human names to changegroup versions.
54 _bundlespeccgversions = {
54 _bundlespeccgversions = {
55 b'v1': b'01',
55 b'v1': b'01',
56 b'v2': b'02',
56 b'v2': b'02',
57 b'packed1': b's1',
57 b'packed1': b's1',
58 b'bundle2': b'02', # legacy
58 b'bundle2': b'02', # legacy
59 }
59 }
60
60
61 # Maps bundle version with content opts to choose which part to bundle
61 # Maps bundle version with content opts to choose which part to bundle
62 _bundlespeccontentopts = {
62 _bundlespeccontentopts = {
63 b'v1': {
63 b'v1': {
64 b'changegroup': True,
64 b'changegroup': True,
65 b'cg.version': b'01',
65 b'cg.version': b'01',
66 b'obsolescence': False,
66 b'obsolescence': False,
67 b'phases': False,
67 b'phases': False,
68 b'tagsfnodescache': False,
68 b'tagsfnodescache': False,
69 b'revbranchcache': False,
69 b'revbranchcache': False,
70 },
70 },
71 b'v2': {
71 b'v2': {
72 b'changegroup': True,
72 b'changegroup': True,
73 b'cg.version': b'02',
73 b'cg.version': b'02',
74 b'obsolescence': False,
74 b'obsolescence': False,
75 b'phases': False,
75 b'phases': False,
76 b'tagsfnodescache': True,
76 b'tagsfnodescache': True,
77 b'revbranchcache': True,
77 b'revbranchcache': True,
78 },
78 },
79 b'packed1': {b'cg.version': b's1'},
79 b'packed1': {b'cg.version': b's1'},
80 }
80 }
81 _bundlespeccontentopts[b'bundle2'] = _bundlespeccontentopts[b'v2']
81 _bundlespeccontentopts[b'bundle2'] = _bundlespeccontentopts[b'v2']
82
82
83 _bundlespecvariants = {
83 _bundlespecvariants = {
84 b"streamv2": {
84 b"streamv2": {
85 b"changegroup": False,
85 b"changegroup": False,
86 b"streamv2": True,
86 b"streamv2": True,
87 b"tagsfnodescache": False,
87 b"tagsfnodescache": False,
88 b"revbranchcache": False,
88 b"revbranchcache": False,
89 }
89 }
90 }
90 }
91
91
92 # Compression engines allowed in version 1. THIS SHOULD NEVER CHANGE.
92 # Compression engines allowed in version 1. THIS SHOULD NEVER CHANGE.
93 _bundlespecv1compengines = {b'gzip', b'bzip2', b'none'}
93 _bundlespecv1compengines = {b'gzip', b'bzip2', b'none'}
94
94
95
95
96 @attr.s
96 @attr.s
97 class bundlespec(object):
97 class bundlespec(object):
98 compression = attr.ib()
98 compression = attr.ib()
99 wirecompression = attr.ib()
99 wirecompression = attr.ib()
100 version = attr.ib()
100 version = attr.ib()
101 wireversion = attr.ib()
101 wireversion = attr.ib()
102 params = attr.ib()
102 params = attr.ib()
103 contentopts = attr.ib()
103 contentopts = attr.ib()
104
104
105
105
106 def parsebundlespec(repo, spec, strict=True):
106 def parsebundlespec(repo, spec, strict=True):
107 """Parse a bundle string specification into parts.
107 """Parse a bundle string specification into parts.
108
108
109 Bundle specifications denote a well-defined bundle/exchange format.
109 Bundle specifications denote a well-defined bundle/exchange format.
110 The content of a given specification should not change over time in
110 The content of a given specification should not change over time in
111 order to ensure that bundles produced by a newer version of Mercurial are
111 order to ensure that bundles produced by a newer version of Mercurial are
112 readable from an older version.
112 readable from an older version.
113
113
114 The string currently has the form:
114 The string currently has the form:
115
115
116 <compression>-<type>[;<parameter0>[;<parameter1>]]
116 <compression>-<type>[;<parameter0>[;<parameter1>]]
117
117
118 Where <compression> is one of the supported compression formats
118 Where <compression> is one of the supported compression formats
119 and <type> is (currently) a version string. A ";" can follow the type and
119 and <type> is (currently) a version string. A ";" can follow the type and
120 all text afterwards is interpreted as URI encoded, ";" delimited key=value
120 all text afterwards is interpreted as URI encoded, ";" delimited key=value
121 pairs.
121 pairs.
122
122
123 If ``strict`` is True (the default) <compression> is required. Otherwise,
123 If ``strict`` is True (the default) <compression> is required. Otherwise,
124 it is optional.
124 it is optional.
125
125
126 Returns a bundlespec object of (compression, version, parameters).
126 Returns a bundlespec object of (compression, version, parameters).
127 Compression will be ``None`` if not in strict mode and a compression isn't
127 Compression will be ``None`` if not in strict mode and a compression isn't
128 defined.
128 defined.
129
129
130 An ``InvalidBundleSpecification`` is raised when the specification is
130 An ``InvalidBundleSpecification`` is raised when the specification is
131 not syntactically well formed.
131 not syntactically well formed.
132
132
133 An ``UnsupportedBundleSpecification`` is raised when the compression or
133 An ``UnsupportedBundleSpecification`` is raised when the compression or
134 bundle type/version is not recognized.
134 bundle type/version is not recognized.
135
135
136 Note: this function will likely eventually return a more complex data
136 Note: this function will likely eventually return a more complex data
137 structure, including bundle2 part information.
137 structure, including bundle2 part information.
138 """
138 """
139
139
140 def parseparams(s):
140 def parseparams(s):
141 if b';' not in s:
141 if b';' not in s:
142 return s, {}
142 return s, {}
143
143
144 params = {}
144 params = {}
145 version, paramstr = s.split(b';', 1)
145 version, paramstr = s.split(b';', 1)
146
146
147 for p in paramstr.split(b';'):
147 for p in paramstr.split(b';'):
148 if b'=' not in p:
148 if b'=' not in p:
149 raise error.InvalidBundleSpecification(
149 raise error.InvalidBundleSpecification(
150 _(
150 _(
151 b'invalid bundle specification: '
151 b'invalid bundle specification: '
152 b'missing "=" in parameter: %s'
152 b'missing "=" in parameter: %s'
153 )
153 )
154 % p
154 % p
155 )
155 )
156
156
157 key, value = p.split(b'=', 1)
157 key, value = p.split(b'=', 1)
158 key = urlreq.unquote(key)
158 key = urlreq.unquote(key)
159 value = urlreq.unquote(value)
159 value = urlreq.unquote(value)
160 params[key] = value
160 params[key] = value
161
161
162 return version, params
162 return version, params
163
163
164 if strict and b'-' not in spec:
164 if strict and b'-' not in spec:
165 raise error.InvalidBundleSpecification(
165 raise error.InvalidBundleSpecification(
166 _(
166 _(
167 b'invalid bundle specification; '
167 b'invalid bundle specification; '
168 b'must be prefixed with compression: %s'
168 b'must be prefixed with compression: %s'
169 )
169 )
170 % spec
170 % spec
171 )
171 )
172
172
173 if b'-' in spec:
173 if b'-' in spec:
174 compression, version = spec.split(b'-', 1)
174 compression, version = spec.split(b'-', 1)
175
175
176 if compression not in util.compengines.supportedbundlenames:
176 if compression not in util.compengines.supportedbundlenames:
177 raise error.UnsupportedBundleSpecification(
177 raise error.UnsupportedBundleSpecification(
178 _(b'%s compression is not supported') % compression
178 _(b'%s compression is not supported') % compression
179 )
179 )
180
180
181 version, params = parseparams(version)
181 version, params = parseparams(version)
182
182
183 if version not in _bundlespeccgversions:
183 if version not in _bundlespeccgversions:
184 raise error.UnsupportedBundleSpecification(
184 raise error.UnsupportedBundleSpecification(
185 _(b'%s is not a recognized bundle version') % version
185 _(b'%s is not a recognized bundle version') % version
186 )
186 )
187 else:
187 else:
188 # Value could be just the compression or just the version, in which
188 # Value could be just the compression or just the version, in which
189 # case some defaults are assumed (but only when not in strict mode).
189 # case some defaults are assumed (but only when not in strict mode).
190 assert not strict
190 assert not strict
191
191
192 spec, params = parseparams(spec)
192 spec, params = parseparams(spec)
193
193
194 if spec in util.compengines.supportedbundlenames:
194 if spec in util.compengines.supportedbundlenames:
195 compression = spec
195 compression = spec
196 version = b'v1'
196 version = b'v1'
197 # Generaldelta repos require v2.
197 # Generaldelta repos require v2.
198 if b'generaldelta' in repo.requirements:
198 if b'generaldelta' in repo.requirements:
199 version = b'v2'
199 version = b'v2'
200 # Modern compression engines require v2.
200 # Modern compression engines require v2.
201 if compression not in _bundlespecv1compengines:
201 if compression not in _bundlespecv1compengines:
202 version = b'v2'
202 version = b'v2'
203 elif spec in _bundlespeccgversions:
203 elif spec in _bundlespeccgversions:
204 if spec == b'packed1':
204 if spec == b'packed1':
205 compression = b'none'
205 compression = b'none'
206 else:
206 else:
207 compression = b'bzip2'
207 compression = b'bzip2'
208 version = spec
208 version = spec
209 else:
209 else:
210 raise error.UnsupportedBundleSpecification(
210 raise error.UnsupportedBundleSpecification(
211 _(b'%s is not a recognized bundle specification') % spec
211 _(b'%s is not a recognized bundle specification') % spec
212 )
212 )
213
213
214 # Bundle version 1 only supports a known set of compression engines.
214 # Bundle version 1 only supports a known set of compression engines.
215 if version == b'v1' and compression not in _bundlespecv1compengines:
215 if version == b'v1' and compression not in _bundlespecv1compengines:
216 raise error.UnsupportedBundleSpecification(
216 raise error.UnsupportedBundleSpecification(
217 _(b'compression engine %s is not supported on v1 bundles')
217 _(b'compression engine %s is not supported on v1 bundles')
218 % compression
218 % compression
219 )
219 )
220
220
221 # The specification for packed1 can optionally declare the data formats
221 # The specification for packed1 can optionally declare the data formats
222 # required to apply it. If we see this metadata, compare against what the
222 # required to apply it. If we see this metadata, compare against what the
223 # repo supports and error if the bundle isn't compatible.
223 # repo supports and error if the bundle isn't compatible.
224 if version == b'packed1' and b'requirements' in params:
224 if version == b'packed1' and b'requirements' in params:
225 requirements = set(params[b'requirements'].split(b','))
225 requirements = set(params[b'requirements'].split(b','))
226 missingreqs = requirements - repo.supportedformats
226 missingreqs = requirements - repo.supportedformats
227 if missingreqs:
227 if missingreqs:
228 raise error.UnsupportedBundleSpecification(
228 raise error.UnsupportedBundleSpecification(
229 _(b'missing support for repository features: %s')
229 _(b'missing support for repository features: %s')
230 % b', '.join(sorted(missingreqs))
230 % b', '.join(sorted(missingreqs))
231 )
231 )
232
232
233 # Compute contentopts based on the version
233 # Compute contentopts based on the version
234 contentopts = _bundlespeccontentopts.get(version, {}).copy()
234 contentopts = _bundlespeccontentopts.get(version, {}).copy()
235
235
236 # Process the variants
236 # Process the variants
237 if b"stream" in params and params[b"stream"] == b"v2":
237 if b"stream" in params and params[b"stream"] == b"v2":
238 variant = _bundlespecvariants[b"streamv2"]
238 variant = _bundlespecvariants[b"streamv2"]
239 contentopts.update(variant)
239 contentopts.update(variant)
240
240
241 engine = util.compengines.forbundlename(compression)
241 engine = util.compengines.forbundlename(compression)
242 compression, wirecompression = engine.bundletype()
242 compression, wirecompression = engine.bundletype()
243 wireversion = _bundlespeccgversions[version]
243 wireversion = _bundlespeccgversions[version]
244
244
245 return bundlespec(
245 return bundlespec(
246 compression, wirecompression, version, wireversion, params, contentopts
246 compression, wirecompression, version, wireversion, params, contentopts
247 )
247 )
248
248
249
249
250 def readbundle(ui, fh, fname, vfs=None):
250 def readbundle(ui, fh, fname, vfs=None):
251 header = changegroup.readexactly(fh, 4)
251 header = changegroup.readexactly(fh, 4)
252
252
253 alg = None
253 alg = None
254 if not fname:
254 if not fname:
255 fname = b"stream"
255 fname = b"stream"
256 if not header.startswith(b'HG') and header.startswith(b'\0'):
256 if not header.startswith(b'HG') and header.startswith(b'\0'):
257 fh = changegroup.headerlessfixup(fh, header)
257 fh = changegroup.headerlessfixup(fh, header)
258 header = b"HG10"
258 header = b"HG10"
259 alg = b'UN'
259 alg = b'UN'
260 elif vfs:
260 elif vfs:
261 fname = vfs.join(fname)
261 fname = vfs.join(fname)
262
262
263 magic, version = header[0:2], header[2:4]
263 magic, version = header[0:2], header[2:4]
264
264
265 if magic != b'HG':
265 if magic != b'HG':
266 raise error.Abort(_(b'%s: not a Mercurial bundle') % fname)
266 raise error.Abort(_(b'%s: not a Mercurial bundle') % fname)
267 if version == b'10':
267 if version == b'10':
268 if alg is None:
268 if alg is None:
269 alg = changegroup.readexactly(fh, 2)
269 alg = changegroup.readexactly(fh, 2)
270 return changegroup.cg1unpacker(fh, alg)
270 return changegroup.cg1unpacker(fh, alg)
271 elif version.startswith(b'2'):
271 elif version.startswith(b'2'):
272 return bundle2.getunbundler(ui, fh, magicstring=magic + version)
272 return bundle2.getunbundler(ui, fh, magicstring=magic + version)
273 elif version == b'S1':
273 elif version == b'S1':
274 return streamclone.streamcloneapplier(fh)
274 return streamclone.streamcloneapplier(fh)
275 else:
275 else:
276 raise error.Abort(
276 raise error.Abort(
277 _(b'%s: unknown bundle version %s') % (fname, version)
277 _(b'%s: unknown bundle version %s') % (fname, version)
278 )
278 )
279
279
280
280
281 def getbundlespec(ui, fh):
281 def getbundlespec(ui, fh):
282 """Infer the bundlespec from a bundle file handle.
282 """Infer the bundlespec from a bundle file handle.
283
283
284 The input file handle is seeked and the original seek position is not
284 The input file handle is seeked and the original seek position is not
285 restored.
285 restored.
286 """
286 """
287
287
288 def speccompression(alg):
288 def speccompression(alg):
289 try:
289 try:
290 return util.compengines.forbundletype(alg).bundletype()[0]
290 return util.compengines.forbundletype(alg).bundletype()[0]
291 except KeyError:
291 except KeyError:
292 return None
292 return None
293
293
294 b = readbundle(ui, fh, None)
294 b = readbundle(ui, fh, None)
295 if isinstance(b, changegroup.cg1unpacker):
295 if isinstance(b, changegroup.cg1unpacker):
296 alg = b._type
296 alg = b._type
297 if alg == b'_truncatedBZ':
297 if alg == b'_truncatedBZ':
298 alg = b'BZ'
298 alg = b'BZ'
299 comp = speccompression(alg)
299 comp = speccompression(alg)
300 if not comp:
300 if not comp:
301 raise error.Abort(_(b'unknown compression algorithm: %s') % alg)
301 raise error.Abort(_(b'unknown compression algorithm: %s') % alg)
302 return b'%s-v1' % comp
302 return b'%s-v1' % comp
303 elif isinstance(b, bundle2.unbundle20):
303 elif isinstance(b, bundle2.unbundle20):
304 if b'Compression' in b.params:
304 if b'Compression' in b.params:
305 comp = speccompression(b.params[b'Compression'])
305 comp = speccompression(b.params[b'Compression'])
306 if not comp:
306 if not comp:
307 raise error.Abort(
307 raise error.Abort(
308 _(b'unknown compression algorithm: %s') % comp
308 _(b'unknown compression algorithm: %s') % comp
309 )
309 )
310 else:
310 else:
311 comp = b'none'
311 comp = b'none'
312
312
313 version = None
313 version = None
314 for part in b.iterparts():
314 for part in b.iterparts():
315 if part.type == b'changegroup':
315 if part.type == b'changegroup':
316 version = part.params[b'version']
316 version = part.params[b'version']
317 if version in (b'01', b'02'):
317 if version in (b'01', b'02'):
318 version = b'v2'
318 version = b'v2'
319 else:
319 else:
320 raise error.Abort(
320 raise error.Abort(
321 _(
321 _(
322 b'changegroup version %s does not have '
322 b'changegroup version %s does not have '
323 b'a known bundlespec'
323 b'a known bundlespec'
324 )
324 )
325 % version,
325 % version,
326 hint=_(b'try upgrading your Mercurial client'),
326 hint=_(b'try upgrading your Mercurial client'),
327 )
327 )
328 elif part.type == b'stream2' and version is None:
328 elif part.type == b'stream2' and version is None:
329 # A stream2 part requires to be part of a v2 bundle
329 # A stream2 part requires to be part of a v2 bundle
330 requirements = urlreq.unquote(part.params[b'requirements'])
330 requirements = urlreq.unquote(part.params[b'requirements'])
331 splitted = requirements.split()
331 splitted = requirements.split()
332 params = bundle2._formatrequirementsparams(splitted)
332 params = bundle2._formatrequirementsparams(splitted)
333 return b'none-v2;stream=v2;%s' % params
333 return b'none-v2;stream=v2;%s' % params
334
334
335 if not version:
335 if not version:
336 raise error.Abort(
336 raise error.Abort(
337 _(b'could not identify changegroup version in bundle')
337 _(b'could not identify changegroup version in bundle')
338 )
338 )
339
339
340 return b'%s-%s' % (comp, version)
340 return b'%s-%s' % (comp, version)
341 elif isinstance(b, streamclone.streamcloneapplier):
341 elif isinstance(b, streamclone.streamcloneapplier):
342 requirements = streamclone.readbundle1header(fh)[2]
342 requirements = streamclone.readbundle1header(fh)[2]
343 formatted = bundle2._formatrequirementsparams(requirements)
343 formatted = bundle2._formatrequirementsparams(requirements)
344 return b'none-packed1;%s' % formatted
344 return b'none-packed1;%s' % formatted
345 else:
345 else:
346 raise error.Abort(_(b'unknown bundle type: %s') % b)
346 raise error.Abort(_(b'unknown bundle type: %s') % b)
347
347
348
348
349 def _computeoutgoing(repo, heads, common):
349 def _computeoutgoing(repo, heads, common):
350 """Computes which revs are outgoing given a set of common
350 """Computes which revs are outgoing given a set of common
351 and a set of heads.
351 and a set of heads.
352
352
353 This is a separate function so extensions can have access to
353 This is a separate function so extensions can have access to
354 the logic.
354 the logic.
355
355
356 Returns a discovery.outgoing object.
356 Returns a discovery.outgoing object.
357 """
357 """
358 cl = repo.changelog
358 cl = repo.changelog
359 if common:
359 if common:
360 hasnode = cl.hasnode
360 hasnode = cl.hasnode
361 common = [n for n in common if hasnode(n)]
361 common = [n for n in common if hasnode(n)]
362 else:
362 else:
363 common = [nullid]
363 common = [nullid]
364 if not heads:
364 if not heads:
365 heads = cl.heads()
365 heads = cl.heads()
366 return discovery.outgoing(repo, common, heads)
366 return discovery.outgoing(repo, common, heads)
367
367
368
368
369 def _checkpublish(pushop):
369 def _checkpublish(pushop):
370 repo = pushop.repo
370 repo = pushop.repo
371 ui = repo.ui
371 ui = repo.ui
372 behavior = ui.config(b'experimental', b'auto-publish')
372 behavior = ui.config(b'experimental', b'auto-publish')
373 if pushop.publish or behavior not in (b'warn', b'confirm', b'abort'):
373 if pushop.publish or behavior not in (b'warn', b'confirm', b'abort'):
374 return
374 return
375 remotephases = listkeys(pushop.remote, b'phases')
375 remotephases = listkeys(pushop.remote, b'phases')
376 if not remotephases.get(b'publishing', False):
376 if not remotephases.get(b'publishing', False):
377 return
377 return
378
378
379 if pushop.revs is None:
379 if pushop.revs is None:
380 published = repo.filtered(b'served').revs(b'not public()')
380 published = repo.filtered(b'served').revs(b'not public()')
381 else:
381 else:
382 published = repo.revs(b'::%ln - public()', pushop.revs)
382 published = repo.revs(b'::%ln - public()', pushop.revs)
383 if published:
383 if published:
384 if behavior == b'warn':
384 if behavior == b'warn':
385 ui.warn(
385 ui.warn(
386 _(b'%i changesets about to be published\n') % len(published)
386 _(b'%i changesets about to be published\n') % len(published)
387 )
387 )
388 elif behavior == b'confirm':
388 elif behavior == b'confirm':
389 if ui.promptchoice(
389 if ui.promptchoice(
390 _(b'push and publish %i changesets (yn)?$$ &Yes $$ &No')
390 _(b'push and publish %i changesets (yn)?$$ &Yes $$ &No')
391 % len(published)
391 % len(published)
392 ):
392 ):
393 raise error.Abort(_(b'user quit'))
393 raise error.Abort(_(b'user quit'))
394 elif behavior == b'abort':
394 elif behavior == b'abort':
395 msg = _(b'push would publish %i changesets') % len(published)
395 msg = _(b'push would publish %i changesets') % len(published)
396 hint = _(
396 hint = _(
397 b"use --publish or adjust 'experimental.auto-publish'"
397 b"use --publish or adjust 'experimental.auto-publish'"
398 b" config"
398 b" config"
399 )
399 )
400 raise error.Abort(msg, hint=hint)
400 raise error.Abort(msg, hint=hint)
401
401
402
402
403 def _forcebundle1(op):
403 def _forcebundle1(op):
404 """return true if a pull/push must use bundle1
404 """return true if a pull/push must use bundle1
405
405
406 This function is used to allow testing of the older bundle version"""
406 This function is used to allow testing of the older bundle version"""
407 ui = op.repo.ui
407 ui = op.repo.ui
408 # The goal is this config is to allow developer to choose the bundle
408 # The goal is this config is to allow developer to choose the bundle
409 # version used during exchanged. This is especially handy during test.
409 # version used during exchanged. This is especially handy during test.
410 # Value is a list of bundle version to be picked from, highest version
410 # Value is a list of bundle version to be picked from, highest version
411 # should be used.
411 # should be used.
412 #
412 #
413 # developer config: devel.legacy.exchange
413 # developer config: devel.legacy.exchange
414 exchange = ui.configlist(b'devel', b'legacy.exchange')
414 exchange = ui.configlist(b'devel', b'legacy.exchange')
415 forcebundle1 = b'bundle2' not in exchange and b'bundle1' in exchange
415 forcebundle1 = b'bundle2' not in exchange and b'bundle1' in exchange
416 return forcebundle1 or not op.remote.capable(b'bundle2')
416 return forcebundle1 or not op.remote.capable(b'bundle2')
417
417
418
418
419 class pushoperation(object):
419 class pushoperation(object):
420 """A object that represent a single push operation
420 """A object that represent a single push operation
421
421
422 Its purpose is to carry push related state and very common operations.
422 Its purpose is to carry push related state and very common operations.
423
423
424 A new pushoperation should be created at the beginning of each push and
424 A new pushoperation should be created at the beginning of each push and
425 discarded afterward.
425 discarded afterward.
426 """
426 """
427
427
428 def __init__(
428 def __init__(
429 self,
429 self,
430 repo,
430 repo,
431 remote,
431 remote,
432 force=False,
432 force=False,
433 revs=None,
433 revs=None,
434 newbranch=False,
434 newbranch=False,
435 bookmarks=(),
435 bookmarks=(),
436 publish=False,
436 publish=False,
437 pushvars=None,
437 pushvars=None,
438 ):
438 ):
439 # repo we push from
439 # repo we push from
440 self.repo = repo
440 self.repo = repo
441 self.ui = repo.ui
441 self.ui = repo.ui
442 # repo we push to
442 # repo we push to
443 self.remote = remote
443 self.remote = remote
444 # force option provided
444 # force option provided
445 self.force = force
445 self.force = force
446 # revs to be pushed (None is "all")
446 # revs to be pushed (None is "all")
447 self.revs = revs
447 self.revs = revs
448 # bookmark explicitly pushed
448 # bookmark explicitly pushed
449 self.bookmarks = bookmarks
449 self.bookmarks = bookmarks
450 # allow push of new branch
450 # allow push of new branch
451 self.newbranch = newbranch
451 self.newbranch = newbranch
452 # step already performed
452 # step already performed
453 # (used to check what steps have been already performed through bundle2)
453 # (used to check what steps have been already performed through bundle2)
454 self.stepsdone = set()
454 self.stepsdone = set()
455 # Integer version of the changegroup push result
455 # Integer version of the changegroup push result
456 # - None means nothing to push
456 # - None means nothing to push
457 # - 0 means HTTP error
457 # - 0 means HTTP error
458 # - 1 means we pushed and remote head count is unchanged *or*
458 # - 1 means we pushed and remote head count is unchanged *or*
459 # we have outgoing changesets but refused to push
459 # we have outgoing changesets but refused to push
460 # - other values as described by addchangegroup()
460 # - other values as described by addchangegroup()
461 self.cgresult = None
461 self.cgresult = None
462 # Boolean value for the bookmark push
462 # Boolean value for the bookmark push
463 self.bkresult = None
463 self.bkresult = None
464 # discover.outgoing object (contains common and outgoing data)
464 # discover.outgoing object (contains common and outgoing data)
465 self.outgoing = None
465 self.outgoing = None
466 # all remote topological heads before the push
466 # all remote topological heads before the push
467 self.remoteheads = None
467 self.remoteheads = None
468 # Details of the remote branch pre and post push
468 # Details of the remote branch pre and post push
469 #
469 #
470 # mapping: {'branch': ([remoteheads],
470 # mapping: {'branch': ([remoteheads],
471 # [newheads],
471 # [newheads],
472 # [unsyncedheads],
472 # [unsyncedheads],
473 # [discardedheads])}
473 # [discardedheads])}
474 # - branch: the branch name
474 # - branch: the branch name
475 # - remoteheads: the list of remote heads known locally
475 # - remoteheads: the list of remote heads known locally
476 # None if the branch is new
476 # None if the branch is new
477 # - newheads: the new remote heads (known locally) with outgoing pushed
477 # - newheads: the new remote heads (known locally) with outgoing pushed
478 # - unsyncedheads: the list of remote heads unknown locally.
478 # - unsyncedheads: the list of remote heads unknown locally.
479 # - discardedheads: the list of remote heads made obsolete by the push
479 # - discardedheads: the list of remote heads made obsolete by the push
480 self.pushbranchmap = None
480 self.pushbranchmap = None
481 # testable as a boolean indicating if any nodes are missing locally.
481 # testable as a boolean indicating if any nodes are missing locally.
482 self.incoming = None
482 self.incoming = None
483 # summary of the remote phase situation
483 # summary of the remote phase situation
484 self.remotephases = None
484 self.remotephases = None
485 # phases changes that must be pushed along side the changesets
485 # phases changes that must be pushed along side the changesets
486 self.outdatedphases = None
486 self.outdatedphases = None
487 # phases changes that must be pushed if changeset push fails
487 # phases changes that must be pushed if changeset push fails
488 self.fallbackoutdatedphases = None
488 self.fallbackoutdatedphases = None
489 # outgoing obsmarkers
489 # outgoing obsmarkers
490 self.outobsmarkers = set()
490 self.outobsmarkers = set()
491 # outgoing bookmarks, list of (bm, oldnode | '', newnode | '')
491 # outgoing bookmarks, list of (bm, oldnode | '', newnode | '')
492 self.outbookmarks = []
492 self.outbookmarks = []
493 # transaction manager
493 # transaction manager
494 self.trmanager = None
494 self.trmanager = None
495 # map { pushkey partid -> callback handling failure}
495 # map { pushkey partid -> callback handling failure}
496 # used to handle exception from mandatory pushkey part failure
496 # used to handle exception from mandatory pushkey part failure
497 self.pkfailcb = {}
497 self.pkfailcb = {}
498 # an iterable of pushvars or None
498 # an iterable of pushvars or None
499 self.pushvars = pushvars
499 self.pushvars = pushvars
500 # publish pushed changesets
500 # publish pushed changesets
501 self.publish = publish
501 self.publish = publish
502
502
503 @util.propertycache
503 @util.propertycache
504 def futureheads(self):
504 def futureheads(self):
505 """future remote heads if the changeset push succeeds"""
505 """future remote heads if the changeset push succeeds"""
506 return self.outgoing.ancestorsof
506 return self.outgoing.ancestorsof
507
507
508 @util.propertycache
508 @util.propertycache
509 def fallbackheads(self):
509 def fallbackheads(self):
510 """future remote heads if the changeset push fails"""
510 """future remote heads if the changeset push fails"""
511 if self.revs is None:
511 if self.revs is None:
512 # not target to push, all common are relevant
512 # not target to push, all common are relevant
513 return self.outgoing.commonheads
513 return self.outgoing.commonheads
514 unfi = self.repo.unfiltered()
514 unfi = self.repo.unfiltered()
515 # I want cheads = heads(::ancestorsof and ::commonheads)
515 # I want cheads = heads(::ancestorsof and ::commonheads)
516 # (ancestorsof is revs with secret changeset filtered out)
516 # (ancestorsof is revs with secret changeset filtered out)
517 #
517 #
518 # This can be expressed as:
518 # This can be expressed as:
519 # cheads = ( (ancestorsof and ::commonheads)
519 # cheads = ( (ancestorsof and ::commonheads)
520 # + (commonheads and ::ancestorsof))"
520 # + (commonheads and ::ancestorsof))"
521 # )
521 # )
522 #
522 #
523 # while trying to push we already computed the following:
523 # while trying to push we already computed the following:
524 # common = (::commonheads)
524 # common = (::commonheads)
525 # missing = ((commonheads::ancestorsof) - commonheads)
525 # missing = ((commonheads::ancestorsof) - commonheads)
526 #
526 #
527 # We can pick:
527 # We can pick:
528 # * ancestorsof part of common (::commonheads)
528 # * ancestorsof part of common (::commonheads)
529 common = self.outgoing.common
529 common = self.outgoing.common
530 rev = self.repo.changelog.index.rev
530 rev = self.repo.changelog.index.rev
531 cheads = [node for node in self.revs if rev(node) in common]
531 cheads = [node for node in self.revs if rev(node) in common]
532 # and
532 # and
533 # * commonheads parents on missing
533 # * commonheads parents on missing
534 revset = unfi.set(
534 revset = unfi.set(
535 b'%ln and parents(roots(%ln))',
535 b'%ln and parents(roots(%ln))',
536 self.outgoing.commonheads,
536 self.outgoing.commonheads,
537 self.outgoing.missing,
537 self.outgoing.missing,
538 )
538 )
539 cheads.extend(c.node() for c in revset)
539 cheads.extend(c.node() for c in revset)
540 return cheads
540 return cheads
541
541
542 @property
542 @property
543 def commonheads(self):
543 def commonheads(self):
544 """set of all common heads after changeset bundle push"""
544 """set of all common heads after changeset bundle push"""
545 if self.cgresult:
545 if self.cgresult:
546 return self.futureheads
546 return self.futureheads
547 else:
547 else:
548 return self.fallbackheads
548 return self.fallbackheads
549
549
550
550
551 # mapping of message used when pushing bookmark
551 # mapping of message used when pushing bookmark
552 bookmsgmap = {
552 bookmsgmap = {
553 b'update': (
553 b'update': (
554 _(b"updating bookmark %s\n"),
554 _(b"updating bookmark %s\n"),
555 _(b'updating bookmark %s failed!\n'),
555 _(b'updating bookmark %s failed!\n'),
556 ),
556 ),
557 b'export': (
557 b'export': (
558 _(b"exporting bookmark %s\n"),
558 _(b"exporting bookmark %s\n"),
559 _(b'exporting bookmark %s failed!\n'),
559 _(b'exporting bookmark %s failed!\n'),
560 ),
560 ),
561 b'delete': (
561 b'delete': (
562 _(b"deleting remote bookmark %s\n"),
562 _(b"deleting remote bookmark %s\n"),
563 _(b'deleting remote bookmark %s failed!\n'),
563 _(b'deleting remote bookmark %s failed!\n'),
564 ),
564 ),
565 }
565 }
566
566
567
567
568 def push(
568 def push(
569 repo,
569 repo,
570 remote,
570 remote,
571 force=False,
571 force=False,
572 revs=None,
572 revs=None,
573 newbranch=False,
573 newbranch=False,
574 bookmarks=(),
574 bookmarks=(),
575 publish=False,
575 publish=False,
576 opargs=None,
576 opargs=None,
577 ):
577 ):
578 '''Push outgoing changesets (limited by revs) from a local
578 '''Push outgoing changesets (limited by revs) from a local
579 repository to remote. Return an integer:
579 repository to remote. Return an integer:
580 - None means nothing to push
580 - None means nothing to push
581 - 0 means HTTP error
581 - 0 means HTTP error
582 - 1 means we pushed and remote head count is unchanged *or*
582 - 1 means we pushed and remote head count is unchanged *or*
583 we have outgoing changesets but refused to push
583 we have outgoing changesets but refused to push
584 - other values as described by addchangegroup()
584 - other values as described by addchangegroup()
585 '''
585 '''
586 if opargs is None:
586 if opargs is None:
587 opargs = {}
587 opargs = {}
588 pushop = pushoperation(
588 pushop = pushoperation(
589 repo,
589 repo,
590 remote,
590 remote,
591 force,
591 force,
592 revs,
592 revs,
593 newbranch,
593 newbranch,
594 bookmarks,
594 bookmarks,
595 publish,
595 publish,
596 **pycompat.strkwargs(opargs)
596 **pycompat.strkwargs(opargs)
597 )
597 )
598 if pushop.remote.local():
598 if pushop.remote.local():
599 missing = (
599 missing = (
600 set(pushop.repo.requirements) - pushop.remote.local().supported
600 set(pushop.repo.requirements) - pushop.remote.local().supported
601 )
601 )
602 if missing:
602 if missing:
603 msg = _(
603 msg = _(
604 b"required features are not"
604 b"required features are not"
605 b" supported in the destination:"
605 b" supported in the destination:"
606 b" %s"
606 b" %s"
607 ) % (b', '.join(sorted(missing)))
607 ) % (b', '.join(sorted(missing)))
608 raise error.Abort(msg)
608 raise error.Abort(msg)
609
609
610 if not pushop.remote.canpush():
610 if not pushop.remote.canpush():
611 raise error.Abort(_(b"destination does not support push"))
611 raise error.Abort(_(b"destination does not support push"))
612
612
613 if not pushop.remote.capable(b'unbundle'):
613 if not pushop.remote.capable(b'unbundle'):
614 raise error.Abort(
614 raise error.Abort(
615 _(
615 _(
616 b'cannot push: destination does not support the '
616 b'cannot push: destination does not support the '
617 b'unbundle wire protocol command'
617 b'unbundle wire protocol command'
618 )
618 )
619 )
619 )
620
620
621 # get lock as we might write phase data
621 # get lock as we might write phase data
622 wlock = lock = None
622 wlock = lock = None
623 try:
623 try:
624 # bundle2 push may receive a reply bundle touching bookmarks
624 # bundle2 push may receive a reply bundle touching bookmarks
625 # requiring the wlock. Take it now to ensure proper ordering.
625 # requiring the wlock. Take it now to ensure proper ordering.
626 maypushback = pushop.ui.configbool(b'experimental', b'bundle2.pushback')
626 maypushback = pushop.ui.configbool(b'experimental', b'bundle2.pushback')
627 if (
627 if (
628 (not _forcebundle1(pushop))
628 (not _forcebundle1(pushop))
629 and maypushback
629 and maypushback
630 and not bookmod.bookmarksinstore(repo)
630 and not bookmod.bookmarksinstore(repo)
631 ):
631 ):
632 wlock = pushop.repo.wlock()
632 wlock = pushop.repo.wlock()
633 lock = pushop.repo.lock()
633 lock = pushop.repo.lock()
634 pushop.trmanager = transactionmanager(
634 pushop.trmanager = transactionmanager(
635 pushop.repo, b'push-response', pushop.remote.url()
635 pushop.repo, b'push-response', pushop.remote.url()
636 )
636 )
637 except error.LockUnavailable as err:
637 except error.LockUnavailable as err:
638 # source repo cannot be locked.
638 # source repo cannot be locked.
639 # We do not abort the push, but just disable the local phase
639 # We do not abort the push, but just disable the local phase
640 # synchronisation.
640 # synchronisation.
641 msg = b'cannot lock source repository: %s\n' % stringutil.forcebytestr(
641 msg = b'cannot lock source repository: %s\n' % stringutil.forcebytestr(
642 err
642 err
643 )
643 )
644 pushop.ui.debug(msg)
644 pushop.ui.debug(msg)
645
645
646 with wlock or util.nullcontextmanager():
646 with wlock or util.nullcontextmanager():
647 with lock or util.nullcontextmanager():
647 with lock or util.nullcontextmanager():
648 with pushop.trmanager or util.nullcontextmanager():
648 with pushop.trmanager or util.nullcontextmanager():
649 pushop.repo.checkpush(pushop)
649 pushop.repo.checkpush(pushop)
650 _checkpublish(pushop)
650 _checkpublish(pushop)
651 _pushdiscovery(pushop)
651 _pushdiscovery(pushop)
652 if not pushop.force:
652 if not pushop.force:
653 _checksubrepostate(pushop)
653 _checksubrepostate(pushop)
654 if not _forcebundle1(pushop):
654 if not _forcebundle1(pushop):
655 _pushbundle2(pushop)
655 _pushbundle2(pushop)
656 _pushchangeset(pushop)
656 _pushchangeset(pushop)
657 _pushsyncphase(pushop)
657 _pushsyncphase(pushop)
658 _pushobsolete(pushop)
658 _pushobsolete(pushop)
659 _pushbookmark(pushop)
659 _pushbookmark(pushop)
660
660
661 if repo.ui.configbool(b'experimental', b'remotenames'):
661 if repo.ui.configbool(b'experimental', b'remotenames'):
662 logexchange.pullremotenames(repo, remote)
662 logexchange.pullremotenames(repo, remote)
663
663
664 return pushop
664 return pushop
665
665
666
666
667 # list of steps to perform discovery before push
667 # list of steps to perform discovery before push
668 pushdiscoveryorder = []
668 pushdiscoveryorder = []
669
669
670 # Mapping between step name and function
670 # Mapping between step name and function
671 #
671 #
672 # This exists to help extensions wrap steps if necessary
672 # This exists to help extensions wrap steps if necessary
673 pushdiscoverymapping = {}
673 pushdiscoverymapping = {}
674
674
675
675
676 def pushdiscovery(stepname):
676 def pushdiscovery(stepname):
677 """decorator for function performing discovery before push
677 """decorator for function performing discovery before push
678
678
679 The function is added to the step -> function mapping and appended to the
679 The function is added to the step -> function mapping and appended to the
680 list of steps. Beware that decorated function will be added in order (this
680 list of steps. Beware that decorated function will be added in order (this
681 may matter).
681 may matter).
682
682
683 You can only use this decorator for a new step, if you want to wrap a step
683 You can only use this decorator for a new step, if you want to wrap a step
684 from an extension, change the pushdiscovery dictionary directly."""
684 from an extension, change the pushdiscovery dictionary directly."""
685
685
686 def dec(func):
686 def dec(func):
687 assert stepname not in pushdiscoverymapping
687 assert stepname not in pushdiscoverymapping
688 pushdiscoverymapping[stepname] = func
688 pushdiscoverymapping[stepname] = func
689 pushdiscoveryorder.append(stepname)
689 pushdiscoveryorder.append(stepname)
690 return func
690 return func
691
691
692 return dec
692 return dec
693
693
694
694
695 def _pushdiscovery(pushop):
695 def _pushdiscovery(pushop):
696 """Run all discovery steps"""
696 """Run all discovery steps"""
697 for stepname in pushdiscoveryorder:
697 for stepname in pushdiscoveryorder:
698 step = pushdiscoverymapping[stepname]
698 step = pushdiscoverymapping[stepname]
699 step(pushop)
699 step(pushop)
700
700
701
701
702 def _checksubrepostate(pushop):
702 def _checksubrepostate(pushop):
703 """Ensure all outgoing referenced subrepo revisions are present locally"""
703 """Ensure all outgoing referenced subrepo revisions are present locally"""
704 for n in pushop.outgoing.missing:
704 for n in pushop.outgoing.missing:
705 ctx = pushop.repo[n]
705 ctx = pushop.repo[n]
706
706
707 if b'.hgsub' in ctx.manifest() and b'.hgsubstate' in ctx.files():
707 if b'.hgsub' in ctx.manifest() and b'.hgsubstate' in ctx.files():
708 for subpath in sorted(ctx.substate):
708 for subpath in sorted(ctx.substate):
709 sub = ctx.sub(subpath)
709 sub = ctx.sub(subpath)
710 sub.verify(onpush=True)
710 sub.verify(onpush=True)
711
711
712
712
713 @pushdiscovery(b'changeset')
713 @pushdiscovery(b'changeset')
714 def _pushdiscoverychangeset(pushop):
714 def _pushdiscoverychangeset(pushop):
715 """discover the changeset that need to be pushed"""
715 """discover the changeset that need to be pushed"""
716 fci = discovery.findcommonincoming
716 fci = discovery.findcommonincoming
717 if pushop.revs:
717 if pushop.revs:
718 commoninc = fci(
718 commoninc = fci(
719 pushop.repo,
719 pushop.repo,
720 pushop.remote,
720 pushop.remote,
721 force=pushop.force,
721 force=pushop.force,
722 ancestorsof=pushop.revs,
722 ancestorsof=pushop.revs,
723 )
723 )
724 else:
724 else:
725 commoninc = fci(pushop.repo, pushop.remote, force=pushop.force)
725 commoninc = fci(pushop.repo, pushop.remote, force=pushop.force)
726 common, inc, remoteheads = commoninc
726 common, inc, remoteheads = commoninc
727 fco = discovery.findcommonoutgoing
727 fco = discovery.findcommonoutgoing
728 outgoing = fco(
728 outgoing = fco(
729 pushop.repo,
729 pushop.repo,
730 pushop.remote,
730 pushop.remote,
731 onlyheads=pushop.revs,
731 onlyheads=pushop.revs,
732 commoninc=commoninc,
732 commoninc=commoninc,
733 force=pushop.force,
733 force=pushop.force,
734 )
734 )
735 pushop.outgoing = outgoing
735 pushop.outgoing = outgoing
736 pushop.remoteheads = remoteheads
736 pushop.remoteheads = remoteheads
737 pushop.incoming = inc
737 pushop.incoming = inc
738
738
739
739
740 @pushdiscovery(b'phase')
740 @pushdiscovery(b'phase')
741 def _pushdiscoveryphase(pushop):
741 def _pushdiscoveryphase(pushop):
742 """discover the phase that needs to be pushed
742 """discover the phase that needs to be pushed
743
743
744 (computed for both success and failure case for changesets push)"""
744 (computed for both success and failure case for changesets push)"""
745 outgoing = pushop.outgoing
745 outgoing = pushop.outgoing
746 unfi = pushop.repo.unfiltered()
746 unfi = pushop.repo.unfiltered()
747 remotephases = listkeys(pushop.remote, b'phases')
747 remotephases = listkeys(pushop.remote, b'phases')
748
748
749 if (
749 if (
750 pushop.ui.configbool(b'ui', b'_usedassubrepo')
750 pushop.ui.configbool(b'ui', b'_usedassubrepo')
751 and remotephases # server supports phases
751 and remotephases # server supports phases
752 and not pushop.outgoing.missing # no changesets to be pushed
752 and not pushop.outgoing.missing # no changesets to be pushed
753 and remotephases.get(b'publishing', False)
753 and remotephases.get(b'publishing', False)
754 ):
754 ):
755 # When:
755 # When:
756 # - this is a subrepo push
756 # - this is a subrepo push
757 # - and remote support phase
757 # - and remote support phase
758 # - and no changeset are to be pushed
758 # - and no changeset are to be pushed
759 # - and remote is publishing
759 # - and remote is publishing
760 # We may be in issue 3781 case!
760 # We may be in issue 3781 case!
761 # We drop the possible phase synchronisation done by
761 # We drop the possible phase synchronisation done by
762 # courtesy to publish changesets possibly locally draft
762 # courtesy to publish changesets possibly locally draft
763 # on the remote.
763 # on the remote.
764 pushop.outdatedphases = []
764 pushop.outdatedphases = []
765 pushop.fallbackoutdatedphases = []
765 pushop.fallbackoutdatedphases = []
766 return
766 return
767
767
768 pushop.remotephases = phases.remotephasessummary(
768 pushop.remotephases = phases.remotephasessummary(
769 pushop.repo, pushop.fallbackheads, remotephases
769 pushop.repo, pushop.fallbackheads, remotephases
770 )
770 )
771 droots = pushop.remotephases.draftroots
771 droots = pushop.remotephases.draftroots
772
772
773 extracond = b''
773 extracond = b''
774 if not pushop.remotephases.publishing:
774 if not pushop.remotephases.publishing:
775 extracond = b' and public()'
775 extracond = b' and public()'
776 revset = b'heads((%%ln::%%ln) %s)' % extracond
776 revset = b'heads((%%ln::%%ln) %s)' % extracond
777 # Get the list of all revs draft on remote by public here.
777 # Get the list of all revs draft on remote by public here.
778 # XXX Beware that revset break if droots is not strictly
778 # XXX Beware that revset break if droots is not strictly
779 # XXX root we may want to ensure it is but it is costly
779 # XXX root we may want to ensure it is but it is costly
780 fallback = list(unfi.set(revset, droots, pushop.fallbackheads))
780 fallback = list(unfi.set(revset, droots, pushop.fallbackheads))
781 if not pushop.remotephases.publishing and pushop.publish:
781 if not pushop.remotephases.publishing and pushop.publish:
782 future = list(
782 future = list(
783 unfi.set(
783 unfi.set(
784 b'%ln and (not public() or %ln::)', pushop.futureheads, droots
784 b'%ln and (not public() or %ln::)', pushop.futureheads, droots
785 )
785 )
786 )
786 )
787 elif not outgoing.missing:
787 elif not outgoing.missing:
788 future = fallback
788 future = fallback
789 else:
789 else:
790 # adds changeset we are going to push as draft
790 # adds changeset we are going to push as draft
791 #
791 #
792 # should not be necessary for publishing server, but because of an
792 # should not be necessary for publishing server, but because of an
793 # issue fixed in xxxxx we have to do it anyway.
793 # issue fixed in xxxxx we have to do it anyway.
794 fdroots = list(
794 fdroots = list(
795 unfi.set(b'roots(%ln + %ln::)', outgoing.missing, droots)
795 unfi.set(b'roots(%ln + %ln::)', outgoing.missing, droots)
796 )
796 )
797 fdroots = [f.node() for f in fdroots]
797 fdroots = [f.node() for f in fdroots]
798 future = list(unfi.set(revset, fdroots, pushop.futureheads))
798 future = list(unfi.set(revset, fdroots, pushop.futureheads))
799 pushop.outdatedphases = future
799 pushop.outdatedphases = future
800 pushop.fallbackoutdatedphases = fallback
800 pushop.fallbackoutdatedphases = fallback
801
801
802
802
803 @pushdiscovery(b'obsmarker')
803 @pushdiscovery(b'obsmarker')
804 def _pushdiscoveryobsmarkers(pushop):
804 def _pushdiscoveryobsmarkers(pushop):
805 if not obsolete.isenabled(pushop.repo, obsolete.exchangeopt):
805 if not obsolete.isenabled(pushop.repo, obsolete.exchangeopt):
806 return
806 return
807
807
808 if not pushop.repo.obsstore:
808 if not pushop.repo.obsstore:
809 return
809 return
810
810
811 if b'obsolete' not in listkeys(pushop.remote, b'namespaces'):
811 if b'obsolete' not in listkeys(pushop.remote, b'namespaces'):
812 return
812 return
813
813
814 repo = pushop.repo
814 repo = pushop.repo
815 # very naive computation, that can be quite expensive on big repo.
815 # very naive computation, that can be quite expensive on big repo.
816 # However: evolution is currently slow on them anyway.
816 # However: evolution is currently slow on them anyway.
817 nodes = (c.node() for c in repo.set(b'::%ln', pushop.futureheads))
817 nodes = (c.node() for c in repo.set(b'::%ln', pushop.futureheads))
818 pushop.outobsmarkers = pushop.repo.obsstore.relevantmarkers(nodes)
818 pushop.outobsmarkers = pushop.repo.obsstore.relevantmarkers(nodes)
819
819
820
820
821 @pushdiscovery(b'bookmarks')
821 @pushdiscovery(b'bookmarks')
822 def _pushdiscoverybookmarks(pushop):
822 def _pushdiscoverybookmarks(pushop):
823 ui = pushop.ui
823 ui = pushop.ui
824 repo = pushop.repo.unfiltered()
824 repo = pushop.repo.unfiltered()
825 remote = pushop.remote
825 remote = pushop.remote
826 ui.debug(b"checking for updated bookmarks\n")
826 ui.debug(b"checking for updated bookmarks\n")
827 ancestors = ()
827 ancestors = ()
828 if pushop.revs:
828 if pushop.revs:
829 revnums = pycompat.maplist(repo.changelog.rev, pushop.revs)
829 revnums = pycompat.maplist(repo.changelog.rev, pushop.revs)
830 ancestors = repo.changelog.ancestors(revnums, inclusive=True)
830 ancestors = repo.changelog.ancestors(revnums, inclusive=True)
831
831
832 remotebookmark = bookmod.unhexlifybookmarks(listkeys(remote, b'bookmarks'))
832 remotebookmark = bookmod.unhexlifybookmarks(listkeys(remote, b'bookmarks'))
833
833
834 explicit = {
834 explicit = {
835 repo._bookmarks.expandname(bookmark) for bookmark in pushop.bookmarks
835 repo._bookmarks.expandname(bookmark) for bookmark in pushop.bookmarks
836 }
836 }
837
837
838 comp = bookmod.comparebookmarks(repo, repo._bookmarks, remotebookmark)
838 comp = bookmod.comparebookmarks(repo, repo._bookmarks, remotebookmark)
839 return _processcompared(pushop, ancestors, explicit, remotebookmark, comp)
839 return _processcompared(pushop, ancestors, explicit, remotebookmark, comp)
840
840
841
841
842 def _processcompared(pushop, pushed, explicit, remotebms, comp):
842 def _processcompared(pushop, pushed, explicit, remotebms, comp):
843 """take decision on bookmarks to push to the remote repo
843 """take decision on bookmarks to push to the remote repo
844
844
845 Exists to help extensions alter this behavior.
845 Exists to help extensions alter this behavior.
846 """
846 """
847 addsrc, adddst, advsrc, advdst, diverge, differ, invalid, same = comp
847 addsrc, adddst, advsrc, advdst, diverge, differ, invalid, same = comp
848
848
849 repo = pushop.repo
849 repo = pushop.repo
850
850
851 for b, scid, dcid in advsrc:
851 for b, scid, dcid in advsrc:
852 if b in explicit:
852 if b in explicit:
853 explicit.remove(b)
853 explicit.remove(b)
854 if not pushed or repo[scid].rev() in pushed:
854 if not pushed or repo[scid].rev() in pushed:
855 pushop.outbookmarks.append((b, dcid, scid))
855 pushop.outbookmarks.append((b, dcid, scid))
856 # search added bookmark
856 # search added bookmark
857 for b, scid, dcid in addsrc:
857 for b, scid, dcid in addsrc:
858 if b in explicit:
858 if b in explicit:
859 explicit.remove(b)
859 explicit.remove(b)
860 if bookmod.isdivergent(b):
860 if bookmod.isdivergent(b):
861 pushop.ui.warn(_(b'cannot push divergent bookmark %s!\n') % b)
861 pushop.ui.warn(_(b'cannot push divergent bookmark %s!\n') % b)
862 pushop.bkresult = 2
862 pushop.bkresult = 2
863 else:
863 else:
864 pushop.outbookmarks.append((b, b'', scid))
864 pushop.outbookmarks.append((b, b'', scid))
865 # search for overwritten bookmark
865 # search for overwritten bookmark
866 for b, scid, dcid in list(advdst) + list(diverge) + list(differ):
866 for b, scid, dcid in list(advdst) + list(diverge) + list(differ):
867 if b in explicit:
867 if b in explicit:
868 explicit.remove(b)
868 explicit.remove(b)
869 pushop.outbookmarks.append((b, dcid, scid))
869 pushop.outbookmarks.append((b, dcid, scid))
870 # search for bookmark to delete
870 # search for bookmark to delete
871 for b, scid, dcid in adddst:
871 for b, scid, dcid in adddst:
872 if b in explicit:
872 if b in explicit:
873 explicit.remove(b)
873 explicit.remove(b)
874 # treat as "deleted locally"
874 # treat as "deleted locally"
875 pushop.outbookmarks.append((b, dcid, b''))
875 pushop.outbookmarks.append((b, dcid, b''))
876 # identical bookmarks shouldn't get reported
876 # identical bookmarks shouldn't get reported
877 for b, scid, dcid in same:
877 for b, scid, dcid in same:
878 if b in explicit:
878 if b in explicit:
879 explicit.remove(b)
879 explicit.remove(b)
880
880
881 if explicit:
881 if explicit:
882 explicit = sorted(explicit)
882 explicit = sorted(explicit)
883 # we should probably list all of them
883 # we should probably list all of them
884 pushop.ui.warn(
884 pushop.ui.warn(
885 _(
885 _(
886 b'bookmark %s does not exist on the local '
886 b'bookmark %s does not exist on the local '
887 b'or remote repository!\n'
887 b'or remote repository!\n'
888 )
888 )
889 % explicit[0]
889 % explicit[0]
890 )
890 )
891 pushop.bkresult = 2
891 pushop.bkresult = 2
892
892
893 pushop.outbookmarks.sort()
893 pushop.outbookmarks.sort()
894
894
895
895
896 def _pushcheckoutgoing(pushop):
896 def _pushcheckoutgoing(pushop):
897 outgoing = pushop.outgoing
897 outgoing = pushop.outgoing
898 unfi = pushop.repo.unfiltered()
898 unfi = pushop.repo.unfiltered()
899 if not outgoing.missing:
899 if not outgoing.missing:
900 # nothing to push
900 # nothing to push
901 scmutil.nochangesfound(unfi.ui, unfi, outgoing.excluded)
901 scmutil.nochangesfound(unfi.ui, unfi, outgoing.excluded)
902 return False
902 return False
903 # something to push
903 # something to push
904 if not pushop.force:
904 if not pushop.force:
905 # if repo.obsstore == False --> no obsolete
905 # if repo.obsstore == False --> no obsolete
906 # then, save the iteration
906 # then, save the iteration
907 if unfi.obsstore:
907 if unfi.obsstore:
908 obsoletes = []
908 # this message are here for 80 char limit reason
909 unstables = []
909 mso = _(b"push includes obsolete changeset: %s!")
910 for node in outgoing.missing:
910 mspd = _(b"push includes phase-divergent changeset: %s!")
911 mscd = _(b"push includes content-divergent changeset: %s!")
912 mst = {
913 b"orphan": _(b"push includes orphan changeset: %s!"),
914 b"phase-divergent": mspd,
915 b"content-divergent": mscd,
916 }
917 # If we are to push if there is at least one
918 # obsolete or unstable changeset in missing, at
919 # least one of the missinghead will be obsolete or
920 # unstable. So checking heads only is ok
921 for node in outgoing.ancestorsof:
911 ctx = unfi[node]
922 ctx = unfi[node]
912 if ctx.obsolete():
923 if ctx.obsolete():
913 obsoletes.append(ctx)
924 raise error.Abort(mso % ctx)
914 elif ctx.isunstable():
925 elif ctx.isunstable():
915 unstables.append(ctx)
926 # TODO print more than one instability in the abort
916 if obsoletes or unstables:
927 # message
917 msg = b""
928 raise error.Abort(mst[ctx.instabilities()[0]] % ctx)
918 if obsoletes:
919 msg += _(b"push includes obsolete changesets:\n")
920 msg += b"\n".join(b' %s' % ctx for ctx in obsoletes)
921 if unstables:
922 if msg:
923 msg += b"\n"
924 msg += _(b"push includes unstable changesets:\n")
925 msg += b"\n".join(
926 b' %s (%s)'
927 % (
928 ctx,
929 b", ".join(_(ins) for ins in ctx.instabilities()),
930 )
931 for ctx in unstables
932 )
933 raise error.Abort(msg)
934
929
935 discovery.checkheads(pushop)
930 discovery.checkheads(pushop)
936 return True
931 return True
937
932
938
933
939 # List of names of steps to perform for an outgoing bundle2, order matters.
934 # List of names of steps to perform for an outgoing bundle2, order matters.
940 b2partsgenorder = []
935 b2partsgenorder = []
941
936
942 # Mapping between step name and function
937 # Mapping between step name and function
943 #
938 #
944 # This exists to help extensions wrap steps if necessary
939 # This exists to help extensions wrap steps if necessary
945 b2partsgenmapping = {}
940 b2partsgenmapping = {}
946
941
947
942
948 def b2partsgenerator(stepname, idx=None):
943 def b2partsgenerator(stepname, idx=None):
949 """decorator for function generating bundle2 part
944 """decorator for function generating bundle2 part
950
945
951 The function is added to the step -> function mapping and appended to the
946 The function is added to the step -> function mapping and appended to the
952 list of steps. Beware that decorated functions will be added in order
947 list of steps. Beware that decorated functions will be added in order
953 (this may matter).
948 (this may matter).
954
949
955 You can only use this decorator for new steps, if you want to wrap a step
950 You can only use this decorator for new steps, if you want to wrap a step
956 from an extension, attack the b2partsgenmapping dictionary directly."""
951 from an extension, attack the b2partsgenmapping dictionary directly."""
957
952
958 def dec(func):
953 def dec(func):
959 assert stepname not in b2partsgenmapping
954 assert stepname not in b2partsgenmapping
960 b2partsgenmapping[stepname] = func
955 b2partsgenmapping[stepname] = func
961 if idx is None:
956 if idx is None:
962 b2partsgenorder.append(stepname)
957 b2partsgenorder.append(stepname)
963 else:
958 else:
964 b2partsgenorder.insert(idx, stepname)
959 b2partsgenorder.insert(idx, stepname)
965 return func
960 return func
966
961
967 return dec
962 return dec
968
963
969
964
970 def _pushb2ctxcheckheads(pushop, bundler):
965 def _pushb2ctxcheckheads(pushop, bundler):
971 """Generate race condition checking parts
966 """Generate race condition checking parts
972
967
973 Exists as an independent function to aid extensions
968 Exists as an independent function to aid extensions
974 """
969 """
975 # * 'force' do not check for push race,
970 # * 'force' do not check for push race,
976 # * if we don't push anything, there are nothing to check.
971 # * if we don't push anything, there are nothing to check.
977 if not pushop.force and pushop.outgoing.ancestorsof:
972 if not pushop.force and pushop.outgoing.ancestorsof:
978 allowunrelated = b'related' in bundler.capabilities.get(
973 allowunrelated = b'related' in bundler.capabilities.get(
979 b'checkheads', ()
974 b'checkheads', ()
980 )
975 )
981 emptyremote = pushop.pushbranchmap is None
976 emptyremote = pushop.pushbranchmap is None
982 if not allowunrelated or emptyremote:
977 if not allowunrelated or emptyremote:
983 bundler.newpart(b'check:heads', data=iter(pushop.remoteheads))
978 bundler.newpart(b'check:heads', data=iter(pushop.remoteheads))
984 else:
979 else:
985 affected = set()
980 affected = set()
986 for branch, heads in pycompat.iteritems(pushop.pushbranchmap):
981 for branch, heads in pycompat.iteritems(pushop.pushbranchmap):
987 remoteheads, newheads, unsyncedheads, discardedheads = heads
982 remoteheads, newheads, unsyncedheads, discardedheads = heads
988 if remoteheads is not None:
983 if remoteheads is not None:
989 remote = set(remoteheads)
984 remote = set(remoteheads)
990 affected |= set(discardedheads) & remote
985 affected |= set(discardedheads) & remote
991 affected |= remote - set(newheads)
986 affected |= remote - set(newheads)
992 if affected:
987 if affected:
993 data = iter(sorted(affected))
988 data = iter(sorted(affected))
994 bundler.newpart(b'check:updated-heads', data=data)
989 bundler.newpart(b'check:updated-heads', data=data)
995
990
996
991
997 def _pushing(pushop):
992 def _pushing(pushop):
998 """return True if we are pushing anything"""
993 """return True if we are pushing anything"""
999 return bool(
994 return bool(
1000 pushop.outgoing.missing
995 pushop.outgoing.missing
1001 or pushop.outdatedphases
996 or pushop.outdatedphases
1002 or pushop.outobsmarkers
997 or pushop.outobsmarkers
1003 or pushop.outbookmarks
998 or pushop.outbookmarks
1004 )
999 )
1005
1000
1006
1001
1007 @b2partsgenerator(b'check-bookmarks')
1002 @b2partsgenerator(b'check-bookmarks')
1008 def _pushb2checkbookmarks(pushop, bundler):
1003 def _pushb2checkbookmarks(pushop, bundler):
1009 """insert bookmark move checking"""
1004 """insert bookmark move checking"""
1010 if not _pushing(pushop) or pushop.force:
1005 if not _pushing(pushop) or pushop.force:
1011 return
1006 return
1012 b2caps = bundle2.bundle2caps(pushop.remote)
1007 b2caps = bundle2.bundle2caps(pushop.remote)
1013 hasbookmarkcheck = b'bookmarks' in b2caps
1008 hasbookmarkcheck = b'bookmarks' in b2caps
1014 if not (pushop.outbookmarks and hasbookmarkcheck):
1009 if not (pushop.outbookmarks and hasbookmarkcheck):
1015 return
1010 return
1016 data = []
1011 data = []
1017 for book, old, new in pushop.outbookmarks:
1012 for book, old, new in pushop.outbookmarks:
1018 data.append((book, old))
1013 data.append((book, old))
1019 checkdata = bookmod.binaryencode(data)
1014 checkdata = bookmod.binaryencode(data)
1020 bundler.newpart(b'check:bookmarks', data=checkdata)
1015 bundler.newpart(b'check:bookmarks', data=checkdata)
1021
1016
1022
1017
1023 @b2partsgenerator(b'check-phases')
1018 @b2partsgenerator(b'check-phases')
1024 def _pushb2checkphases(pushop, bundler):
1019 def _pushb2checkphases(pushop, bundler):
1025 """insert phase move checking"""
1020 """insert phase move checking"""
1026 if not _pushing(pushop) or pushop.force:
1021 if not _pushing(pushop) or pushop.force:
1027 return
1022 return
1028 b2caps = bundle2.bundle2caps(pushop.remote)
1023 b2caps = bundle2.bundle2caps(pushop.remote)
1029 hasphaseheads = b'heads' in b2caps.get(b'phases', ())
1024 hasphaseheads = b'heads' in b2caps.get(b'phases', ())
1030 if pushop.remotephases is not None and hasphaseheads:
1025 if pushop.remotephases is not None and hasphaseheads:
1031 # check that the remote phase has not changed
1026 # check that the remote phase has not changed
1032 checks = {p: [] for p in phases.allphases}
1027 checks = {p: [] for p in phases.allphases}
1033 checks[phases.public].extend(pushop.remotephases.publicheads)
1028 checks[phases.public].extend(pushop.remotephases.publicheads)
1034 checks[phases.draft].extend(pushop.remotephases.draftroots)
1029 checks[phases.draft].extend(pushop.remotephases.draftroots)
1035 if any(pycompat.itervalues(checks)):
1030 if any(pycompat.itervalues(checks)):
1036 for phase in checks:
1031 for phase in checks:
1037 checks[phase].sort()
1032 checks[phase].sort()
1038 checkdata = phases.binaryencode(checks)
1033 checkdata = phases.binaryencode(checks)
1039 bundler.newpart(b'check:phases', data=checkdata)
1034 bundler.newpart(b'check:phases', data=checkdata)
1040
1035
1041
1036
1042 @b2partsgenerator(b'changeset')
1037 @b2partsgenerator(b'changeset')
1043 def _pushb2ctx(pushop, bundler):
1038 def _pushb2ctx(pushop, bundler):
1044 """handle changegroup push through bundle2
1039 """handle changegroup push through bundle2
1045
1040
1046 addchangegroup result is stored in the ``pushop.cgresult`` attribute.
1041 addchangegroup result is stored in the ``pushop.cgresult`` attribute.
1047 """
1042 """
1048 if b'changesets' in pushop.stepsdone:
1043 if b'changesets' in pushop.stepsdone:
1049 return
1044 return
1050 pushop.stepsdone.add(b'changesets')
1045 pushop.stepsdone.add(b'changesets')
1051 # Send known heads to the server for race detection.
1046 # Send known heads to the server for race detection.
1052 if not _pushcheckoutgoing(pushop):
1047 if not _pushcheckoutgoing(pushop):
1053 return
1048 return
1054 pushop.repo.prepushoutgoinghooks(pushop)
1049 pushop.repo.prepushoutgoinghooks(pushop)
1055
1050
1056 _pushb2ctxcheckheads(pushop, bundler)
1051 _pushb2ctxcheckheads(pushop, bundler)
1057
1052
1058 b2caps = bundle2.bundle2caps(pushop.remote)
1053 b2caps = bundle2.bundle2caps(pushop.remote)
1059 version = b'01'
1054 version = b'01'
1060 cgversions = b2caps.get(b'changegroup')
1055 cgversions = b2caps.get(b'changegroup')
1061 if cgversions: # 3.1 and 3.2 ship with an empty value
1056 if cgversions: # 3.1 and 3.2 ship with an empty value
1062 cgversions = [
1057 cgversions = [
1063 v
1058 v
1064 for v in cgversions
1059 for v in cgversions
1065 if v in changegroup.supportedoutgoingversions(pushop.repo)
1060 if v in changegroup.supportedoutgoingversions(pushop.repo)
1066 ]
1061 ]
1067 if not cgversions:
1062 if not cgversions:
1068 raise error.Abort(_(b'no common changegroup version'))
1063 raise error.Abort(_(b'no common changegroup version'))
1069 version = max(cgversions)
1064 version = max(cgversions)
1070 cgstream = changegroup.makestream(
1065 cgstream = changegroup.makestream(
1071 pushop.repo, pushop.outgoing, version, b'push'
1066 pushop.repo, pushop.outgoing, version, b'push'
1072 )
1067 )
1073 cgpart = bundler.newpart(b'changegroup', data=cgstream)
1068 cgpart = bundler.newpart(b'changegroup', data=cgstream)
1074 if cgversions:
1069 if cgversions:
1075 cgpart.addparam(b'version', version)
1070 cgpart.addparam(b'version', version)
1076 if b'treemanifest' in pushop.repo.requirements:
1071 if b'treemanifest' in pushop.repo.requirements:
1077 cgpart.addparam(b'treemanifest', b'1')
1072 cgpart.addparam(b'treemanifest', b'1')
1078 if b'exp-sidedata-flag' in pushop.repo.requirements:
1073 if b'exp-sidedata-flag' in pushop.repo.requirements:
1079 cgpart.addparam(b'exp-sidedata', b'1')
1074 cgpart.addparam(b'exp-sidedata', b'1')
1080
1075
1081 def handlereply(op):
1076 def handlereply(op):
1082 """extract addchangegroup returns from server reply"""
1077 """extract addchangegroup returns from server reply"""
1083 cgreplies = op.records.getreplies(cgpart.id)
1078 cgreplies = op.records.getreplies(cgpart.id)
1084 assert len(cgreplies[b'changegroup']) == 1
1079 assert len(cgreplies[b'changegroup']) == 1
1085 pushop.cgresult = cgreplies[b'changegroup'][0][b'return']
1080 pushop.cgresult = cgreplies[b'changegroup'][0][b'return']
1086
1081
1087 return handlereply
1082 return handlereply
1088
1083
1089
1084
1090 @b2partsgenerator(b'phase')
1085 @b2partsgenerator(b'phase')
1091 def _pushb2phases(pushop, bundler):
1086 def _pushb2phases(pushop, bundler):
1092 """handle phase push through bundle2"""
1087 """handle phase push through bundle2"""
1093 if b'phases' in pushop.stepsdone:
1088 if b'phases' in pushop.stepsdone:
1094 return
1089 return
1095 b2caps = bundle2.bundle2caps(pushop.remote)
1090 b2caps = bundle2.bundle2caps(pushop.remote)
1096 ui = pushop.repo.ui
1091 ui = pushop.repo.ui
1097
1092
1098 legacyphase = b'phases' in ui.configlist(b'devel', b'legacy.exchange')
1093 legacyphase = b'phases' in ui.configlist(b'devel', b'legacy.exchange')
1099 haspushkey = b'pushkey' in b2caps
1094 haspushkey = b'pushkey' in b2caps
1100 hasphaseheads = b'heads' in b2caps.get(b'phases', ())
1095 hasphaseheads = b'heads' in b2caps.get(b'phases', ())
1101
1096
1102 if hasphaseheads and not legacyphase:
1097 if hasphaseheads and not legacyphase:
1103 return _pushb2phaseheads(pushop, bundler)
1098 return _pushb2phaseheads(pushop, bundler)
1104 elif haspushkey:
1099 elif haspushkey:
1105 return _pushb2phasespushkey(pushop, bundler)
1100 return _pushb2phasespushkey(pushop, bundler)
1106
1101
1107
1102
1108 def _pushb2phaseheads(pushop, bundler):
1103 def _pushb2phaseheads(pushop, bundler):
1109 """push phase information through a bundle2 - binary part"""
1104 """push phase information through a bundle2 - binary part"""
1110 pushop.stepsdone.add(b'phases')
1105 pushop.stepsdone.add(b'phases')
1111 if pushop.outdatedphases:
1106 if pushop.outdatedphases:
1112 updates = {p: [] for p in phases.allphases}
1107 updates = {p: [] for p in phases.allphases}
1113 updates[0].extend(h.node() for h in pushop.outdatedphases)
1108 updates[0].extend(h.node() for h in pushop.outdatedphases)
1114 phasedata = phases.binaryencode(updates)
1109 phasedata = phases.binaryencode(updates)
1115 bundler.newpart(b'phase-heads', data=phasedata)
1110 bundler.newpart(b'phase-heads', data=phasedata)
1116
1111
1117
1112
1118 def _pushb2phasespushkey(pushop, bundler):
1113 def _pushb2phasespushkey(pushop, bundler):
1119 """push phase information through a bundle2 - pushkey part"""
1114 """push phase information through a bundle2 - pushkey part"""
1120 pushop.stepsdone.add(b'phases')
1115 pushop.stepsdone.add(b'phases')
1121 part2node = []
1116 part2node = []
1122
1117
1123 def handlefailure(pushop, exc):
1118 def handlefailure(pushop, exc):
1124 targetid = int(exc.partid)
1119 targetid = int(exc.partid)
1125 for partid, node in part2node:
1120 for partid, node in part2node:
1126 if partid == targetid:
1121 if partid == targetid:
1127 raise error.Abort(_(b'updating %s to public failed') % node)
1122 raise error.Abort(_(b'updating %s to public failed') % node)
1128
1123
1129 enc = pushkey.encode
1124 enc = pushkey.encode
1130 for newremotehead in pushop.outdatedphases:
1125 for newremotehead in pushop.outdatedphases:
1131 part = bundler.newpart(b'pushkey')
1126 part = bundler.newpart(b'pushkey')
1132 part.addparam(b'namespace', enc(b'phases'))
1127 part.addparam(b'namespace', enc(b'phases'))
1133 part.addparam(b'key', enc(newremotehead.hex()))
1128 part.addparam(b'key', enc(newremotehead.hex()))
1134 part.addparam(b'old', enc(b'%d' % phases.draft))
1129 part.addparam(b'old', enc(b'%d' % phases.draft))
1135 part.addparam(b'new', enc(b'%d' % phases.public))
1130 part.addparam(b'new', enc(b'%d' % phases.public))
1136 part2node.append((part.id, newremotehead))
1131 part2node.append((part.id, newremotehead))
1137 pushop.pkfailcb[part.id] = handlefailure
1132 pushop.pkfailcb[part.id] = handlefailure
1138
1133
1139 def handlereply(op):
1134 def handlereply(op):
1140 for partid, node in part2node:
1135 for partid, node in part2node:
1141 partrep = op.records.getreplies(partid)
1136 partrep = op.records.getreplies(partid)
1142 results = partrep[b'pushkey']
1137 results = partrep[b'pushkey']
1143 assert len(results) <= 1
1138 assert len(results) <= 1
1144 msg = None
1139 msg = None
1145 if not results:
1140 if not results:
1146 msg = _(b'server ignored update of %s to public!\n') % node
1141 msg = _(b'server ignored update of %s to public!\n') % node
1147 elif not int(results[0][b'return']):
1142 elif not int(results[0][b'return']):
1148 msg = _(b'updating %s to public failed!\n') % node
1143 msg = _(b'updating %s to public failed!\n') % node
1149 if msg is not None:
1144 if msg is not None:
1150 pushop.ui.warn(msg)
1145 pushop.ui.warn(msg)
1151
1146
1152 return handlereply
1147 return handlereply
1153
1148
1154
1149
1155 @b2partsgenerator(b'obsmarkers')
1150 @b2partsgenerator(b'obsmarkers')
1156 def _pushb2obsmarkers(pushop, bundler):
1151 def _pushb2obsmarkers(pushop, bundler):
1157 if b'obsmarkers' in pushop.stepsdone:
1152 if b'obsmarkers' in pushop.stepsdone:
1158 return
1153 return
1159 remoteversions = bundle2.obsmarkersversion(bundler.capabilities)
1154 remoteversions = bundle2.obsmarkersversion(bundler.capabilities)
1160 if obsolete.commonversion(remoteversions) is None:
1155 if obsolete.commonversion(remoteversions) is None:
1161 return
1156 return
1162 pushop.stepsdone.add(b'obsmarkers')
1157 pushop.stepsdone.add(b'obsmarkers')
1163 if pushop.outobsmarkers:
1158 if pushop.outobsmarkers:
1164 markers = obsutil.sortedmarkers(pushop.outobsmarkers)
1159 markers = obsutil.sortedmarkers(pushop.outobsmarkers)
1165 bundle2.buildobsmarkerspart(bundler, markers)
1160 bundle2.buildobsmarkerspart(bundler, markers)
1166
1161
1167
1162
1168 @b2partsgenerator(b'bookmarks')
1163 @b2partsgenerator(b'bookmarks')
1169 def _pushb2bookmarks(pushop, bundler):
1164 def _pushb2bookmarks(pushop, bundler):
1170 """handle bookmark push through bundle2"""
1165 """handle bookmark push through bundle2"""
1171 if b'bookmarks' in pushop.stepsdone:
1166 if b'bookmarks' in pushop.stepsdone:
1172 return
1167 return
1173 b2caps = bundle2.bundle2caps(pushop.remote)
1168 b2caps = bundle2.bundle2caps(pushop.remote)
1174
1169
1175 legacy = pushop.repo.ui.configlist(b'devel', b'legacy.exchange')
1170 legacy = pushop.repo.ui.configlist(b'devel', b'legacy.exchange')
1176 legacybooks = b'bookmarks' in legacy
1171 legacybooks = b'bookmarks' in legacy
1177
1172
1178 if not legacybooks and b'bookmarks' in b2caps:
1173 if not legacybooks and b'bookmarks' in b2caps:
1179 return _pushb2bookmarkspart(pushop, bundler)
1174 return _pushb2bookmarkspart(pushop, bundler)
1180 elif b'pushkey' in b2caps:
1175 elif b'pushkey' in b2caps:
1181 return _pushb2bookmarkspushkey(pushop, bundler)
1176 return _pushb2bookmarkspushkey(pushop, bundler)
1182
1177
1183
1178
1184 def _bmaction(old, new):
1179 def _bmaction(old, new):
1185 """small utility for bookmark pushing"""
1180 """small utility for bookmark pushing"""
1186 if not old:
1181 if not old:
1187 return b'export'
1182 return b'export'
1188 elif not new:
1183 elif not new:
1189 return b'delete'
1184 return b'delete'
1190 return b'update'
1185 return b'update'
1191
1186
1192
1187
1193 def _abortonsecretctx(pushop, node, b):
1188 def _abortonsecretctx(pushop, node, b):
1194 """abort if a given bookmark points to a secret changeset"""
1189 """abort if a given bookmark points to a secret changeset"""
1195 if node and pushop.repo[node].phase() == phases.secret:
1190 if node and pushop.repo[node].phase() == phases.secret:
1196 raise error.Abort(
1191 raise error.Abort(
1197 _(b'cannot push bookmark %s as it points to a secret changeset') % b
1192 _(b'cannot push bookmark %s as it points to a secret changeset') % b
1198 )
1193 )
1199
1194
1200
1195
1201 def _pushb2bookmarkspart(pushop, bundler):
1196 def _pushb2bookmarkspart(pushop, bundler):
1202 pushop.stepsdone.add(b'bookmarks')
1197 pushop.stepsdone.add(b'bookmarks')
1203 if not pushop.outbookmarks:
1198 if not pushop.outbookmarks:
1204 return
1199 return
1205
1200
1206 allactions = []
1201 allactions = []
1207 data = []
1202 data = []
1208 for book, old, new in pushop.outbookmarks:
1203 for book, old, new in pushop.outbookmarks:
1209 _abortonsecretctx(pushop, new, book)
1204 _abortonsecretctx(pushop, new, book)
1210 data.append((book, new))
1205 data.append((book, new))
1211 allactions.append((book, _bmaction(old, new)))
1206 allactions.append((book, _bmaction(old, new)))
1212 checkdata = bookmod.binaryencode(data)
1207 checkdata = bookmod.binaryencode(data)
1213 bundler.newpart(b'bookmarks', data=checkdata)
1208 bundler.newpart(b'bookmarks', data=checkdata)
1214
1209
1215 def handlereply(op):
1210 def handlereply(op):
1216 ui = pushop.ui
1211 ui = pushop.ui
1217 # if success
1212 # if success
1218 for book, action in allactions:
1213 for book, action in allactions:
1219 ui.status(bookmsgmap[action][0] % book)
1214 ui.status(bookmsgmap[action][0] % book)
1220
1215
1221 return handlereply
1216 return handlereply
1222
1217
1223
1218
1224 def _pushb2bookmarkspushkey(pushop, bundler):
1219 def _pushb2bookmarkspushkey(pushop, bundler):
1225 pushop.stepsdone.add(b'bookmarks')
1220 pushop.stepsdone.add(b'bookmarks')
1226 part2book = []
1221 part2book = []
1227 enc = pushkey.encode
1222 enc = pushkey.encode
1228
1223
1229 def handlefailure(pushop, exc):
1224 def handlefailure(pushop, exc):
1230 targetid = int(exc.partid)
1225 targetid = int(exc.partid)
1231 for partid, book, action in part2book:
1226 for partid, book, action in part2book:
1232 if partid == targetid:
1227 if partid == targetid:
1233 raise error.Abort(bookmsgmap[action][1].rstrip() % book)
1228 raise error.Abort(bookmsgmap[action][1].rstrip() % book)
1234 # we should not be called for part we did not generated
1229 # we should not be called for part we did not generated
1235 assert False
1230 assert False
1236
1231
1237 for book, old, new in pushop.outbookmarks:
1232 for book, old, new in pushop.outbookmarks:
1238 _abortonsecretctx(pushop, new, book)
1233 _abortonsecretctx(pushop, new, book)
1239 part = bundler.newpart(b'pushkey')
1234 part = bundler.newpart(b'pushkey')
1240 part.addparam(b'namespace', enc(b'bookmarks'))
1235 part.addparam(b'namespace', enc(b'bookmarks'))
1241 part.addparam(b'key', enc(book))
1236 part.addparam(b'key', enc(book))
1242 part.addparam(b'old', enc(hex(old)))
1237 part.addparam(b'old', enc(hex(old)))
1243 part.addparam(b'new', enc(hex(new)))
1238 part.addparam(b'new', enc(hex(new)))
1244 action = b'update'
1239 action = b'update'
1245 if not old:
1240 if not old:
1246 action = b'export'
1241 action = b'export'
1247 elif not new:
1242 elif not new:
1248 action = b'delete'
1243 action = b'delete'
1249 part2book.append((part.id, book, action))
1244 part2book.append((part.id, book, action))
1250 pushop.pkfailcb[part.id] = handlefailure
1245 pushop.pkfailcb[part.id] = handlefailure
1251
1246
1252 def handlereply(op):
1247 def handlereply(op):
1253 ui = pushop.ui
1248 ui = pushop.ui
1254 for partid, book, action in part2book:
1249 for partid, book, action in part2book:
1255 partrep = op.records.getreplies(partid)
1250 partrep = op.records.getreplies(partid)
1256 results = partrep[b'pushkey']
1251 results = partrep[b'pushkey']
1257 assert len(results) <= 1
1252 assert len(results) <= 1
1258 if not results:
1253 if not results:
1259 pushop.ui.warn(_(b'server ignored bookmark %s update\n') % book)
1254 pushop.ui.warn(_(b'server ignored bookmark %s update\n') % book)
1260 else:
1255 else:
1261 ret = int(results[0][b'return'])
1256 ret = int(results[0][b'return'])
1262 if ret:
1257 if ret:
1263 ui.status(bookmsgmap[action][0] % book)
1258 ui.status(bookmsgmap[action][0] % book)
1264 else:
1259 else:
1265 ui.warn(bookmsgmap[action][1] % book)
1260 ui.warn(bookmsgmap[action][1] % book)
1266 if pushop.bkresult is not None:
1261 if pushop.bkresult is not None:
1267 pushop.bkresult = 1
1262 pushop.bkresult = 1
1268
1263
1269 return handlereply
1264 return handlereply
1270
1265
1271
1266
1272 @b2partsgenerator(b'pushvars', idx=0)
1267 @b2partsgenerator(b'pushvars', idx=0)
1273 def _getbundlesendvars(pushop, bundler):
1268 def _getbundlesendvars(pushop, bundler):
1274 '''send shellvars via bundle2'''
1269 '''send shellvars via bundle2'''
1275 pushvars = pushop.pushvars
1270 pushvars = pushop.pushvars
1276 if pushvars:
1271 if pushvars:
1277 shellvars = {}
1272 shellvars = {}
1278 for raw in pushvars:
1273 for raw in pushvars:
1279 if b'=' not in raw:
1274 if b'=' not in raw:
1280 msg = (
1275 msg = (
1281 b"unable to parse variable '%s', should follow "
1276 b"unable to parse variable '%s', should follow "
1282 b"'KEY=VALUE' or 'KEY=' format"
1277 b"'KEY=VALUE' or 'KEY=' format"
1283 )
1278 )
1284 raise error.Abort(msg % raw)
1279 raise error.Abort(msg % raw)
1285 k, v = raw.split(b'=', 1)
1280 k, v = raw.split(b'=', 1)
1286 shellvars[k] = v
1281 shellvars[k] = v
1287
1282
1288 part = bundler.newpart(b'pushvars')
1283 part = bundler.newpart(b'pushvars')
1289
1284
1290 for key, value in pycompat.iteritems(shellvars):
1285 for key, value in pycompat.iteritems(shellvars):
1291 part.addparam(key, value, mandatory=False)
1286 part.addparam(key, value, mandatory=False)
1292
1287
1293
1288
1294 def _pushbundle2(pushop):
1289 def _pushbundle2(pushop):
1295 """push data to the remote using bundle2
1290 """push data to the remote using bundle2
1296
1291
1297 The only currently supported type of data is changegroup but this will
1292 The only currently supported type of data is changegroup but this will
1298 evolve in the future."""
1293 evolve in the future."""
1299 bundler = bundle2.bundle20(pushop.ui, bundle2.bundle2caps(pushop.remote))
1294 bundler = bundle2.bundle20(pushop.ui, bundle2.bundle2caps(pushop.remote))
1300 pushback = pushop.trmanager and pushop.ui.configbool(
1295 pushback = pushop.trmanager and pushop.ui.configbool(
1301 b'experimental', b'bundle2.pushback'
1296 b'experimental', b'bundle2.pushback'
1302 )
1297 )
1303
1298
1304 # create reply capability
1299 # create reply capability
1305 capsblob = bundle2.encodecaps(
1300 capsblob = bundle2.encodecaps(
1306 bundle2.getrepocaps(pushop.repo, allowpushback=pushback, role=b'client')
1301 bundle2.getrepocaps(pushop.repo, allowpushback=pushback, role=b'client')
1307 )
1302 )
1308 bundler.newpart(b'replycaps', data=capsblob)
1303 bundler.newpart(b'replycaps', data=capsblob)
1309 replyhandlers = []
1304 replyhandlers = []
1310 for partgenname in b2partsgenorder:
1305 for partgenname in b2partsgenorder:
1311 partgen = b2partsgenmapping[partgenname]
1306 partgen = b2partsgenmapping[partgenname]
1312 ret = partgen(pushop, bundler)
1307 ret = partgen(pushop, bundler)
1313 if callable(ret):
1308 if callable(ret):
1314 replyhandlers.append(ret)
1309 replyhandlers.append(ret)
1315 # do not push if nothing to push
1310 # do not push if nothing to push
1316 if bundler.nbparts <= 1:
1311 if bundler.nbparts <= 1:
1317 return
1312 return
1318 stream = util.chunkbuffer(bundler.getchunks())
1313 stream = util.chunkbuffer(bundler.getchunks())
1319 try:
1314 try:
1320 try:
1315 try:
1321 with pushop.remote.commandexecutor() as e:
1316 with pushop.remote.commandexecutor() as e:
1322 reply = e.callcommand(
1317 reply = e.callcommand(
1323 b'unbundle',
1318 b'unbundle',
1324 {
1319 {
1325 b'bundle': stream,
1320 b'bundle': stream,
1326 b'heads': [b'force'],
1321 b'heads': [b'force'],
1327 b'url': pushop.remote.url(),
1322 b'url': pushop.remote.url(),
1328 },
1323 },
1329 ).result()
1324 ).result()
1330 except error.BundleValueError as exc:
1325 except error.BundleValueError as exc:
1331 raise error.Abort(_(b'missing support for %s') % exc)
1326 raise error.Abort(_(b'missing support for %s') % exc)
1332 try:
1327 try:
1333 trgetter = None
1328 trgetter = None
1334 if pushback:
1329 if pushback:
1335 trgetter = pushop.trmanager.transaction
1330 trgetter = pushop.trmanager.transaction
1336 op = bundle2.processbundle(pushop.repo, reply, trgetter)
1331 op = bundle2.processbundle(pushop.repo, reply, trgetter)
1337 except error.BundleValueError as exc:
1332 except error.BundleValueError as exc:
1338 raise error.Abort(_(b'missing support for %s') % exc)
1333 raise error.Abort(_(b'missing support for %s') % exc)
1339 except bundle2.AbortFromPart as exc:
1334 except bundle2.AbortFromPart as exc:
1340 pushop.ui.status(_(b'remote: %s\n') % exc)
1335 pushop.ui.status(_(b'remote: %s\n') % exc)
1341 if exc.hint is not None:
1336 if exc.hint is not None:
1342 pushop.ui.status(_(b'remote: %s\n') % (b'(%s)' % exc.hint))
1337 pushop.ui.status(_(b'remote: %s\n') % (b'(%s)' % exc.hint))
1343 raise error.Abort(_(b'push failed on remote'))
1338 raise error.Abort(_(b'push failed on remote'))
1344 except error.PushkeyFailed as exc:
1339 except error.PushkeyFailed as exc:
1345 partid = int(exc.partid)
1340 partid = int(exc.partid)
1346 if partid not in pushop.pkfailcb:
1341 if partid not in pushop.pkfailcb:
1347 raise
1342 raise
1348 pushop.pkfailcb[partid](pushop, exc)
1343 pushop.pkfailcb[partid](pushop, exc)
1349 for rephand in replyhandlers:
1344 for rephand in replyhandlers:
1350 rephand(op)
1345 rephand(op)
1351
1346
1352
1347
1353 def _pushchangeset(pushop):
1348 def _pushchangeset(pushop):
1354 """Make the actual push of changeset bundle to remote repo"""
1349 """Make the actual push of changeset bundle to remote repo"""
1355 if b'changesets' in pushop.stepsdone:
1350 if b'changesets' in pushop.stepsdone:
1356 return
1351 return
1357 pushop.stepsdone.add(b'changesets')
1352 pushop.stepsdone.add(b'changesets')
1358 if not _pushcheckoutgoing(pushop):
1353 if not _pushcheckoutgoing(pushop):
1359 return
1354 return
1360
1355
1361 # Should have verified this in push().
1356 # Should have verified this in push().
1362 assert pushop.remote.capable(b'unbundle')
1357 assert pushop.remote.capable(b'unbundle')
1363
1358
1364 pushop.repo.prepushoutgoinghooks(pushop)
1359 pushop.repo.prepushoutgoinghooks(pushop)
1365 outgoing = pushop.outgoing
1360 outgoing = pushop.outgoing
1366 # TODO: get bundlecaps from remote
1361 # TODO: get bundlecaps from remote
1367 bundlecaps = None
1362 bundlecaps = None
1368 # create a changegroup from local
1363 # create a changegroup from local
1369 if pushop.revs is None and not (
1364 if pushop.revs is None and not (
1370 outgoing.excluded or pushop.repo.changelog.filteredrevs
1365 outgoing.excluded or pushop.repo.changelog.filteredrevs
1371 ):
1366 ):
1372 # push everything,
1367 # push everything,
1373 # use the fast path, no race possible on push
1368 # use the fast path, no race possible on push
1374 cg = changegroup.makechangegroup(
1369 cg = changegroup.makechangegroup(
1375 pushop.repo,
1370 pushop.repo,
1376 outgoing,
1371 outgoing,
1377 b'01',
1372 b'01',
1378 b'push',
1373 b'push',
1379 fastpath=True,
1374 fastpath=True,
1380 bundlecaps=bundlecaps,
1375 bundlecaps=bundlecaps,
1381 )
1376 )
1382 else:
1377 else:
1383 cg = changegroup.makechangegroup(
1378 cg = changegroup.makechangegroup(
1384 pushop.repo, outgoing, b'01', b'push', bundlecaps=bundlecaps
1379 pushop.repo, outgoing, b'01', b'push', bundlecaps=bundlecaps
1385 )
1380 )
1386
1381
1387 # apply changegroup to remote
1382 # apply changegroup to remote
1388 # local repo finds heads on server, finds out what
1383 # local repo finds heads on server, finds out what
1389 # revs it must push. once revs transferred, if server
1384 # revs it must push. once revs transferred, if server
1390 # finds it has different heads (someone else won
1385 # finds it has different heads (someone else won
1391 # commit/push race), server aborts.
1386 # commit/push race), server aborts.
1392 if pushop.force:
1387 if pushop.force:
1393 remoteheads = [b'force']
1388 remoteheads = [b'force']
1394 else:
1389 else:
1395 remoteheads = pushop.remoteheads
1390 remoteheads = pushop.remoteheads
1396 # ssh: return remote's addchangegroup()
1391 # ssh: return remote's addchangegroup()
1397 # http: return remote's addchangegroup() or 0 for error
1392 # http: return remote's addchangegroup() or 0 for error
1398 pushop.cgresult = pushop.remote.unbundle(cg, remoteheads, pushop.repo.url())
1393 pushop.cgresult = pushop.remote.unbundle(cg, remoteheads, pushop.repo.url())
1399
1394
1400
1395
1401 def _pushsyncphase(pushop):
1396 def _pushsyncphase(pushop):
1402 """synchronise phase information locally and remotely"""
1397 """synchronise phase information locally and remotely"""
1403 cheads = pushop.commonheads
1398 cheads = pushop.commonheads
1404 # even when we don't push, exchanging phase data is useful
1399 # even when we don't push, exchanging phase data is useful
1405 remotephases = listkeys(pushop.remote, b'phases')
1400 remotephases = listkeys(pushop.remote, b'phases')
1406 if (
1401 if (
1407 pushop.ui.configbool(b'ui', b'_usedassubrepo')
1402 pushop.ui.configbool(b'ui', b'_usedassubrepo')
1408 and remotephases # server supports phases
1403 and remotephases # server supports phases
1409 and pushop.cgresult is None # nothing was pushed
1404 and pushop.cgresult is None # nothing was pushed
1410 and remotephases.get(b'publishing', False)
1405 and remotephases.get(b'publishing', False)
1411 ):
1406 ):
1412 # When:
1407 # When:
1413 # - this is a subrepo push
1408 # - this is a subrepo push
1414 # - and remote support phase
1409 # - and remote support phase
1415 # - and no changeset was pushed
1410 # - and no changeset was pushed
1416 # - and remote is publishing
1411 # - and remote is publishing
1417 # We may be in issue 3871 case!
1412 # We may be in issue 3871 case!
1418 # We drop the possible phase synchronisation done by
1413 # We drop the possible phase synchronisation done by
1419 # courtesy to publish changesets possibly locally draft
1414 # courtesy to publish changesets possibly locally draft
1420 # on the remote.
1415 # on the remote.
1421 remotephases = {b'publishing': b'True'}
1416 remotephases = {b'publishing': b'True'}
1422 if not remotephases: # old server or public only reply from non-publishing
1417 if not remotephases: # old server or public only reply from non-publishing
1423 _localphasemove(pushop, cheads)
1418 _localphasemove(pushop, cheads)
1424 # don't push any phase data as there is nothing to push
1419 # don't push any phase data as there is nothing to push
1425 else:
1420 else:
1426 ana = phases.analyzeremotephases(pushop.repo, cheads, remotephases)
1421 ana = phases.analyzeremotephases(pushop.repo, cheads, remotephases)
1427 pheads, droots = ana
1422 pheads, droots = ana
1428 ### Apply remote phase on local
1423 ### Apply remote phase on local
1429 if remotephases.get(b'publishing', False):
1424 if remotephases.get(b'publishing', False):
1430 _localphasemove(pushop, cheads)
1425 _localphasemove(pushop, cheads)
1431 else: # publish = False
1426 else: # publish = False
1432 _localphasemove(pushop, pheads)
1427 _localphasemove(pushop, pheads)
1433 _localphasemove(pushop, cheads, phases.draft)
1428 _localphasemove(pushop, cheads, phases.draft)
1434 ### Apply local phase on remote
1429 ### Apply local phase on remote
1435
1430
1436 if pushop.cgresult:
1431 if pushop.cgresult:
1437 if b'phases' in pushop.stepsdone:
1432 if b'phases' in pushop.stepsdone:
1438 # phases already pushed though bundle2
1433 # phases already pushed though bundle2
1439 return
1434 return
1440 outdated = pushop.outdatedphases
1435 outdated = pushop.outdatedphases
1441 else:
1436 else:
1442 outdated = pushop.fallbackoutdatedphases
1437 outdated = pushop.fallbackoutdatedphases
1443
1438
1444 pushop.stepsdone.add(b'phases')
1439 pushop.stepsdone.add(b'phases')
1445
1440
1446 # filter heads already turned public by the push
1441 # filter heads already turned public by the push
1447 outdated = [c for c in outdated if c.node() not in pheads]
1442 outdated = [c for c in outdated if c.node() not in pheads]
1448 # fallback to independent pushkey command
1443 # fallback to independent pushkey command
1449 for newremotehead in outdated:
1444 for newremotehead in outdated:
1450 with pushop.remote.commandexecutor() as e:
1445 with pushop.remote.commandexecutor() as e:
1451 r = e.callcommand(
1446 r = e.callcommand(
1452 b'pushkey',
1447 b'pushkey',
1453 {
1448 {
1454 b'namespace': b'phases',
1449 b'namespace': b'phases',
1455 b'key': newremotehead.hex(),
1450 b'key': newremotehead.hex(),
1456 b'old': b'%d' % phases.draft,
1451 b'old': b'%d' % phases.draft,
1457 b'new': b'%d' % phases.public,
1452 b'new': b'%d' % phases.public,
1458 },
1453 },
1459 ).result()
1454 ).result()
1460
1455
1461 if not r:
1456 if not r:
1462 pushop.ui.warn(
1457 pushop.ui.warn(
1463 _(b'updating %s to public failed!\n') % newremotehead
1458 _(b'updating %s to public failed!\n') % newremotehead
1464 )
1459 )
1465
1460
1466
1461
1467 def _localphasemove(pushop, nodes, phase=phases.public):
1462 def _localphasemove(pushop, nodes, phase=phases.public):
1468 """move <nodes> to <phase> in the local source repo"""
1463 """move <nodes> to <phase> in the local source repo"""
1469 if pushop.trmanager:
1464 if pushop.trmanager:
1470 phases.advanceboundary(
1465 phases.advanceboundary(
1471 pushop.repo, pushop.trmanager.transaction(), phase, nodes
1466 pushop.repo, pushop.trmanager.transaction(), phase, nodes
1472 )
1467 )
1473 else:
1468 else:
1474 # repo is not locked, do not change any phases!
1469 # repo is not locked, do not change any phases!
1475 # Informs the user that phases should have been moved when
1470 # Informs the user that phases should have been moved when
1476 # applicable.
1471 # applicable.
1477 actualmoves = [n for n in nodes if phase < pushop.repo[n].phase()]
1472 actualmoves = [n for n in nodes if phase < pushop.repo[n].phase()]
1478 phasestr = phases.phasenames[phase]
1473 phasestr = phases.phasenames[phase]
1479 if actualmoves:
1474 if actualmoves:
1480 pushop.ui.status(
1475 pushop.ui.status(
1481 _(
1476 _(
1482 b'cannot lock source repo, skipping '
1477 b'cannot lock source repo, skipping '
1483 b'local %s phase update\n'
1478 b'local %s phase update\n'
1484 )
1479 )
1485 % phasestr
1480 % phasestr
1486 )
1481 )
1487
1482
1488
1483
1489 def _pushobsolete(pushop):
1484 def _pushobsolete(pushop):
1490 """utility function to push obsolete markers to a remote"""
1485 """utility function to push obsolete markers to a remote"""
1491 if b'obsmarkers' in pushop.stepsdone:
1486 if b'obsmarkers' in pushop.stepsdone:
1492 return
1487 return
1493 repo = pushop.repo
1488 repo = pushop.repo
1494 remote = pushop.remote
1489 remote = pushop.remote
1495 pushop.stepsdone.add(b'obsmarkers')
1490 pushop.stepsdone.add(b'obsmarkers')
1496 if pushop.outobsmarkers:
1491 if pushop.outobsmarkers:
1497 pushop.ui.debug(b'try to push obsolete markers to remote\n')
1492 pushop.ui.debug(b'try to push obsolete markers to remote\n')
1498 rslts = []
1493 rslts = []
1499 markers = obsutil.sortedmarkers(pushop.outobsmarkers)
1494 markers = obsutil.sortedmarkers(pushop.outobsmarkers)
1500 remotedata = obsolete._pushkeyescape(markers)
1495 remotedata = obsolete._pushkeyescape(markers)
1501 for key in sorted(remotedata, reverse=True):
1496 for key in sorted(remotedata, reverse=True):
1502 # reverse sort to ensure we end with dump0
1497 # reverse sort to ensure we end with dump0
1503 data = remotedata[key]
1498 data = remotedata[key]
1504 rslts.append(remote.pushkey(b'obsolete', key, b'', data))
1499 rslts.append(remote.pushkey(b'obsolete', key, b'', data))
1505 if [r for r in rslts if not r]:
1500 if [r for r in rslts if not r]:
1506 msg = _(b'failed to push some obsolete markers!\n')
1501 msg = _(b'failed to push some obsolete markers!\n')
1507 repo.ui.warn(msg)
1502 repo.ui.warn(msg)
1508
1503
1509
1504
1510 def _pushbookmark(pushop):
1505 def _pushbookmark(pushop):
1511 """Update bookmark position on remote"""
1506 """Update bookmark position on remote"""
1512 if pushop.cgresult == 0 or b'bookmarks' in pushop.stepsdone:
1507 if pushop.cgresult == 0 or b'bookmarks' in pushop.stepsdone:
1513 return
1508 return
1514 pushop.stepsdone.add(b'bookmarks')
1509 pushop.stepsdone.add(b'bookmarks')
1515 ui = pushop.ui
1510 ui = pushop.ui
1516 remote = pushop.remote
1511 remote = pushop.remote
1517
1512
1518 for b, old, new in pushop.outbookmarks:
1513 for b, old, new in pushop.outbookmarks:
1519 action = b'update'
1514 action = b'update'
1520 if not old:
1515 if not old:
1521 action = b'export'
1516 action = b'export'
1522 elif not new:
1517 elif not new:
1523 action = b'delete'
1518 action = b'delete'
1524
1519
1525 with remote.commandexecutor() as e:
1520 with remote.commandexecutor() as e:
1526 r = e.callcommand(
1521 r = e.callcommand(
1527 b'pushkey',
1522 b'pushkey',
1528 {
1523 {
1529 b'namespace': b'bookmarks',
1524 b'namespace': b'bookmarks',
1530 b'key': b,
1525 b'key': b,
1531 b'old': hex(old),
1526 b'old': hex(old),
1532 b'new': hex(new),
1527 b'new': hex(new),
1533 },
1528 },
1534 ).result()
1529 ).result()
1535
1530
1536 if r:
1531 if r:
1537 ui.status(bookmsgmap[action][0] % b)
1532 ui.status(bookmsgmap[action][0] % b)
1538 else:
1533 else:
1539 ui.warn(bookmsgmap[action][1] % b)
1534 ui.warn(bookmsgmap[action][1] % b)
1540 # discovery can have set the value form invalid entry
1535 # discovery can have set the value form invalid entry
1541 if pushop.bkresult is not None:
1536 if pushop.bkresult is not None:
1542 pushop.bkresult = 1
1537 pushop.bkresult = 1
1543
1538
1544
1539
1545 class pulloperation(object):
1540 class pulloperation(object):
1546 """A object that represent a single pull operation
1541 """A object that represent a single pull operation
1547
1542
1548 It purpose is to carry pull related state and very common operation.
1543 It purpose is to carry pull related state and very common operation.
1549
1544
1550 A new should be created at the beginning of each pull and discarded
1545 A new should be created at the beginning of each pull and discarded
1551 afterward.
1546 afterward.
1552 """
1547 """
1553
1548
1554 def __init__(
1549 def __init__(
1555 self,
1550 self,
1556 repo,
1551 repo,
1557 remote,
1552 remote,
1558 heads=None,
1553 heads=None,
1559 force=False,
1554 force=False,
1560 bookmarks=(),
1555 bookmarks=(),
1561 remotebookmarks=None,
1556 remotebookmarks=None,
1562 streamclonerequested=None,
1557 streamclonerequested=None,
1563 includepats=None,
1558 includepats=None,
1564 excludepats=None,
1559 excludepats=None,
1565 depth=None,
1560 depth=None,
1566 ):
1561 ):
1567 # repo we pull into
1562 # repo we pull into
1568 self.repo = repo
1563 self.repo = repo
1569 # repo we pull from
1564 # repo we pull from
1570 self.remote = remote
1565 self.remote = remote
1571 # revision we try to pull (None is "all")
1566 # revision we try to pull (None is "all")
1572 self.heads = heads
1567 self.heads = heads
1573 # bookmark pulled explicitly
1568 # bookmark pulled explicitly
1574 self.explicitbookmarks = [
1569 self.explicitbookmarks = [
1575 repo._bookmarks.expandname(bookmark) for bookmark in bookmarks
1570 repo._bookmarks.expandname(bookmark) for bookmark in bookmarks
1576 ]
1571 ]
1577 # do we force pull?
1572 # do we force pull?
1578 self.force = force
1573 self.force = force
1579 # whether a streaming clone was requested
1574 # whether a streaming clone was requested
1580 self.streamclonerequested = streamclonerequested
1575 self.streamclonerequested = streamclonerequested
1581 # transaction manager
1576 # transaction manager
1582 self.trmanager = None
1577 self.trmanager = None
1583 # set of common changeset between local and remote before pull
1578 # set of common changeset between local and remote before pull
1584 self.common = None
1579 self.common = None
1585 # set of pulled head
1580 # set of pulled head
1586 self.rheads = None
1581 self.rheads = None
1587 # list of missing changeset to fetch remotely
1582 # list of missing changeset to fetch remotely
1588 self.fetch = None
1583 self.fetch = None
1589 # remote bookmarks data
1584 # remote bookmarks data
1590 self.remotebookmarks = remotebookmarks
1585 self.remotebookmarks = remotebookmarks
1591 # result of changegroup pulling (used as return code by pull)
1586 # result of changegroup pulling (used as return code by pull)
1592 self.cgresult = None
1587 self.cgresult = None
1593 # list of step already done
1588 # list of step already done
1594 self.stepsdone = set()
1589 self.stepsdone = set()
1595 # Whether we attempted a clone from pre-generated bundles.
1590 # Whether we attempted a clone from pre-generated bundles.
1596 self.clonebundleattempted = False
1591 self.clonebundleattempted = False
1597 # Set of file patterns to include.
1592 # Set of file patterns to include.
1598 self.includepats = includepats
1593 self.includepats = includepats
1599 # Set of file patterns to exclude.
1594 # Set of file patterns to exclude.
1600 self.excludepats = excludepats
1595 self.excludepats = excludepats
1601 # Number of ancestor changesets to pull from each pulled head.
1596 # Number of ancestor changesets to pull from each pulled head.
1602 self.depth = depth
1597 self.depth = depth
1603
1598
1604 @util.propertycache
1599 @util.propertycache
1605 def pulledsubset(self):
1600 def pulledsubset(self):
1606 """heads of the set of changeset target by the pull"""
1601 """heads of the set of changeset target by the pull"""
1607 # compute target subset
1602 # compute target subset
1608 if self.heads is None:
1603 if self.heads is None:
1609 # We pulled every thing possible
1604 # We pulled every thing possible
1610 # sync on everything common
1605 # sync on everything common
1611 c = set(self.common)
1606 c = set(self.common)
1612 ret = list(self.common)
1607 ret = list(self.common)
1613 for n in self.rheads:
1608 for n in self.rheads:
1614 if n not in c:
1609 if n not in c:
1615 ret.append(n)
1610 ret.append(n)
1616 return ret
1611 return ret
1617 else:
1612 else:
1618 # We pulled a specific subset
1613 # We pulled a specific subset
1619 # sync on this subset
1614 # sync on this subset
1620 return self.heads
1615 return self.heads
1621
1616
1622 @util.propertycache
1617 @util.propertycache
1623 def canusebundle2(self):
1618 def canusebundle2(self):
1624 return not _forcebundle1(self)
1619 return not _forcebundle1(self)
1625
1620
1626 @util.propertycache
1621 @util.propertycache
1627 def remotebundle2caps(self):
1622 def remotebundle2caps(self):
1628 return bundle2.bundle2caps(self.remote)
1623 return bundle2.bundle2caps(self.remote)
1629
1624
1630 def gettransaction(self):
1625 def gettransaction(self):
1631 # deprecated; talk to trmanager directly
1626 # deprecated; talk to trmanager directly
1632 return self.trmanager.transaction()
1627 return self.trmanager.transaction()
1633
1628
1634
1629
1635 class transactionmanager(util.transactional):
1630 class transactionmanager(util.transactional):
1636 """An object to manage the life cycle of a transaction
1631 """An object to manage the life cycle of a transaction
1637
1632
1638 It creates the transaction on demand and calls the appropriate hooks when
1633 It creates the transaction on demand and calls the appropriate hooks when
1639 closing the transaction."""
1634 closing the transaction."""
1640
1635
1641 def __init__(self, repo, source, url):
1636 def __init__(self, repo, source, url):
1642 self.repo = repo
1637 self.repo = repo
1643 self.source = source
1638 self.source = source
1644 self.url = url
1639 self.url = url
1645 self._tr = None
1640 self._tr = None
1646
1641
1647 def transaction(self):
1642 def transaction(self):
1648 """Return an open transaction object, constructing if necessary"""
1643 """Return an open transaction object, constructing if necessary"""
1649 if not self._tr:
1644 if not self._tr:
1650 trname = b'%s\n%s' % (self.source, util.hidepassword(self.url))
1645 trname = b'%s\n%s' % (self.source, util.hidepassword(self.url))
1651 self._tr = self.repo.transaction(trname)
1646 self._tr = self.repo.transaction(trname)
1652 self._tr.hookargs[b'source'] = self.source
1647 self._tr.hookargs[b'source'] = self.source
1653 self._tr.hookargs[b'url'] = self.url
1648 self._tr.hookargs[b'url'] = self.url
1654 return self._tr
1649 return self._tr
1655
1650
1656 def close(self):
1651 def close(self):
1657 """close transaction if created"""
1652 """close transaction if created"""
1658 if self._tr is not None:
1653 if self._tr is not None:
1659 self._tr.close()
1654 self._tr.close()
1660
1655
1661 def release(self):
1656 def release(self):
1662 """release transaction if created"""
1657 """release transaction if created"""
1663 if self._tr is not None:
1658 if self._tr is not None:
1664 self._tr.release()
1659 self._tr.release()
1665
1660
1666
1661
1667 def listkeys(remote, namespace):
1662 def listkeys(remote, namespace):
1668 with remote.commandexecutor() as e:
1663 with remote.commandexecutor() as e:
1669 return e.callcommand(b'listkeys', {b'namespace': namespace}).result()
1664 return e.callcommand(b'listkeys', {b'namespace': namespace}).result()
1670
1665
1671
1666
1672 def _fullpullbundle2(repo, pullop):
1667 def _fullpullbundle2(repo, pullop):
1673 # The server may send a partial reply, i.e. when inlining
1668 # The server may send a partial reply, i.e. when inlining
1674 # pre-computed bundles. In that case, update the common
1669 # pre-computed bundles. In that case, update the common
1675 # set based on the results and pull another bundle.
1670 # set based on the results and pull another bundle.
1676 #
1671 #
1677 # There are two indicators that the process is finished:
1672 # There are two indicators that the process is finished:
1678 # - no changeset has been added, or
1673 # - no changeset has been added, or
1679 # - all remote heads are known locally.
1674 # - all remote heads are known locally.
1680 # The head check must use the unfiltered view as obsoletion
1675 # The head check must use the unfiltered view as obsoletion
1681 # markers can hide heads.
1676 # markers can hide heads.
1682 unfi = repo.unfiltered()
1677 unfi = repo.unfiltered()
1683 unficl = unfi.changelog
1678 unficl = unfi.changelog
1684
1679
1685 def headsofdiff(h1, h2):
1680 def headsofdiff(h1, h2):
1686 """Returns heads(h1 % h2)"""
1681 """Returns heads(h1 % h2)"""
1687 res = unfi.set(b'heads(%ln %% %ln)', h1, h2)
1682 res = unfi.set(b'heads(%ln %% %ln)', h1, h2)
1688 return {ctx.node() for ctx in res}
1683 return {ctx.node() for ctx in res}
1689
1684
1690 def headsofunion(h1, h2):
1685 def headsofunion(h1, h2):
1691 """Returns heads((h1 + h2) - null)"""
1686 """Returns heads((h1 + h2) - null)"""
1692 res = unfi.set(b'heads((%ln + %ln - null))', h1, h2)
1687 res = unfi.set(b'heads((%ln + %ln - null))', h1, h2)
1693 return {ctx.node() for ctx in res}
1688 return {ctx.node() for ctx in res}
1694
1689
1695 while True:
1690 while True:
1696 old_heads = unficl.heads()
1691 old_heads = unficl.heads()
1697 clstart = len(unficl)
1692 clstart = len(unficl)
1698 _pullbundle2(pullop)
1693 _pullbundle2(pullop)
1699 if repository.NARROW_REQUIREMENT in repo.requirements:
1694 if repository.NARROW_REQUIREMENT in repo.requirements:
1700 # XXX narrow clones filter the heads on the server side during
1695 # XXX narrow clones filter the heads on the server side during
1701 # XXX getbundle and result in partial replies as well.
1696 # XXX getbundle and result in partial replies as well.
1702 # XXX Disable pull bundles in this case as band aid to avoid
1697 # XXX Disable pull bundles in this case as band aid to avoid
1703 # XXX extra round trips.
1698 # XXX extra round trips.
1704 break
1699 break
1705 if clstart == len(unficl):
1700 if clstart == len(unficl):
1706 break
1701 break
1707 if all(unficl.hasnode(n) for n in pullop.rheads):
1702 if all(unficl.hasnode(n) for n in pullop.rheads):
1708 break
1703 break
1709 new_heads = headsofdiff(unficl.heads(), old_heads)
1704 new_heads = headsofdiff(unficl.heads(), old_heads)
1710 pullop.common = headsofunion(new_heads, pullop.common)
1705 pullop.common = headsofunion(new_heads, pullop.common)
1711 pullop.rheads = set(pullop.rheads) - pullop.common
1706 pullop.rheads = set(pullop.rheads) - pullop.common
1712
1707
1713
1708
1714 def add_confirm_callback(repo, pullop):
1709 def add_confirm_callback(repo, pullop):
1715 """ adds a finalize callback to transaction which can be used to show stats
1710 """ adds a finalize callback to transaction which can be used to show stats
1716 to user and confirm the pull before committing transaction """
1711 to user and confirm the pull before committing transaction """
1717
1712
1718 tr = pullop.trmanager.transaction()
1713 tr = pullop.trmanager.transaction()
1719 scmutil.registersummarycallback(
1714 scmutil.registersummarycallback(
1720 repo, tr, txnname=b'pull', as_validator=True
1715 repo, tr, txnname=b'pull', as_validator=True
1721 )
1716 )
1722 reporef = weakref.ref(repo.unfiltered())
1717 reporef = weakref.ref(repo.unfiltered())
1723
1718
1724 def prompt(tr):
1719 def prompt(tr):
1725 repo = reporef()
1720 repo = reporef()
1726 cm = _(b'accept incoming changes (yn)?$$ &Yes $$ &No')
1721 cm = _(b'accept incoming changes (yn)?$$ &Yes $$ &No')
1727 if repo.ui.promptchoice(cm):
1722 if repo.ui.promptchoice(cm):
1728 raise error.Abort("user aborted")
1723 raise error.Abort("user aborted")
1729
1724
1730 tr.addvalidator(b'900-pull-prompt', prompt)
1725 tr.addvalidator(b'900-pull-prompt', prompt)
1731
1726
1732
1727
1733 def pull(
1728 def pull(
1734 repo,
1729 repo,
1735 remote,
1730 remote,
1736 heads=None,
1731 heads=None,
1737 force=False,
1732 force=False,
1738 bookmarks=(),
1733 bookmarks=(),
1739 opargs=None,
1734 opargs=None,
1740 streamclonerequested=None,
1735 streamclonerequested=None,
1741 includepats=None,
1736 includepats=None,
1742 excludepats=None,
1737 excludepats=None,
1743 depth=None,
1738 depth=None,
1744 confirm=None,
1739 confirm=None,
1745 ):
1740 ):
1746 """Fetch repository data from a remote.
1741 """Fetch repository data from a remote.
1747
1742
1748 This is the main function used to retrieve data from a remote repository.
1743 This is the main function used to retrieve data from a remote repository.
1749
1744
1750 ``repo`` is the local repository to clone into.
1745 ``repo`` is the local repository to clone into.
1751 ``remote`` is a peer instance.
1746 ``remote`` is a peer instance.
1752 ``heads`` is an iterable of revisions we want to pull. ``None`` (the
1747 ``heads`` is an iterable of revisions we want to pull. ``None`` (the
1753 default) means to pull everything from the remote.
1748 default) means to pull everything from the remote.
1754 ``bookmarks`` is an iterable of bookmarks requesting to be pulled. By
1749 ``bookmarks`` is an iterable of bookmarks requesting to be pulled. By
1755 default, all remote bookmarks are pulled.
1750 default, all remote bookmarks are pulled.
1756 ``opargs`` are additional keyword arguments to pass to ``pulloperation``
1751 ``opargs`` are additional keyword arguments to pass to ``pulloperation``
1757 initialization.
1752 initialization.
1758 ``streamclonerequested`` is a boolean indicating whether a "streaming
1753 ``streamclonerequested`` is a boolean indicating whether a "streaming
1759 clone" is requested. A "streaming clone" is essentially a raw file copy
1754 clone" is requested. A "streaming clone" is essentially a raw file copy
1760 of revlogs from the server. This only works when the local repository is
1755 of revlogs from the server. This only works when the local repository is
1761 empty. The default value of ``None`` means to respect the server
1756 empty. The default value of ``None`` means to respect the server
1762 configuration for preferring stream clones.
1757 configuration for preferring stream clones.
1763 ``includepats`` and ``excludepats`` define explicit file patterns to
1758 ``includepats`` and ``excludepats`` define explicit file patterns to
1764 include and exclude in storage, respectively. If not defined, narrow
1759 include and exclude in storage, respectively. If not defined, narrow
1765 patterns from the repo instance are used, if available.
1760 patterns from the repo instance are used, if available.
1766 ``depth`` is an integer indicating the DAG depth of history we're
1761 ``depth`` is an integer indicating the DAG depth of history we're
1767 interested in. If defined, for each revision specified in ``heads``, we
1762 interested in. If defined, for each revision specified in ``heads``, we
1768 will fetch up to this many of its ancestors and data associated with them.
1763 will fetch up to this many of its ancestors and data associated with them.
1769 ``confirm`` is a boolean indicating whether the pull should be confirmed
1764 ``confirm`` is a boolean indicating whether the pull should be confirmed
1770 before committing the transaction. This overrides HGPLAIN.
1765 before committing the transaction. This overrides HGPLAIN.
1771
1766
1772 Returns the ``pulloperation`` created for this pull.
1767 Returns the ``pulloperation`` created for this pull.
1773 """
1768 """
1774 if opargs is None:
1769 if opargs is None:
1775 opargs = {}
1770 opargs = {}
1776
1771
1777 # We allow the narrow patterns to be passed in explicitly to provide more
1772 # We allow the narrow patterns to be passed in explicitly to provide more
1778 # flexibility for API consumers.
1773 # flexibility for API consumers.
1779 if includepats or excludepats:
1774 if includepats or excludepats:
1780 includepats = includepats or set()
1775 includepats = includepats or set()
1781 excludepats = excludepats or set()
1776 excludepats = excludepats or set()
1782 else:
1777 else:
1783 includepats, excludepats = repo.narrowpats
1778 includepats, excludepats = repo.narrowpats
1784
1779
1785 narrowspec.validatepatterns(includepats)
1780 narrowspec.validatepatterns(includepats)
1786 narrowspec.validatepatterns(excludepats)
1781 narrowspec.validatepatterns(excludepats)
1787
1782
1788 pullop = pulloperation(
1783 pullop = pulloperation(
1789 repo,
1784 repo,
1790 remote,
1785 remote,
1791 heads,
1786 heads,
1792 force,
1787 force,
1793 bookmarks=bookmarks,
1788 bookmarks=bookmarks,
1794 streamclonerequested=streamclonerequested,
1789 streamclonerequested=streamclonerequested,
1795 includepats=includepats,
1790 includepats=includepats,
1796 excludepats=excludepats,
1791 excludepats=excludepats,
1797 depth=depth,
1792 depth=depth,
1798 **pycompat.strkwargs(opargs)
1793 **pycompat.strkwargs(opargs)
1799 )
1794 )
1800
1795
1801 peerlocal = pullop.remote.local()
1796 peerlocal = pullop.remote.local()
1802 if peerlocal:
1797 if peerlocal:
1803 missing = set(peerlocal.requirements) - pullop.repo.supported
1798 missing = set(peerlocal.requirements) - pullop.repo.supported
1804 if missing:
1799 if missing:
1805 msg = _(
1800 msg = _(
1806 b"required features are not"
1801 b"required features are not"
1807 b" supported in the destination:"
1802 b" supported in the destination:"
1808 b" %s"
1803 b" %s"
1809 ) % (b', '.join(sorted(missing)))
1804 ) % (b', '.join(sorted(missing)))
1810 raise error.Abort(msg)
1805 raise error.Abort(msg)
1811
1806
1812 pullop.trmanager = transactionmanager(repo, b'pull', remote.url())
1807 pullop.trmanager = transactionmanager(repo, b'pull', remote.url())
1813 wlock = util.nullcontextmanager()
1808 wlock = util.nullcontextmanager()
1814 if not bookmod.bookmarksinstore(repo):
1809 if not bookmod.bookmarksinstore(repo):
1815 wlock = repo.wlock()
1810 wlock = repo.wlock()
1816 with wlock, repo.lock(), pullop.trmanager:
1811 with wlock, repo.lock(), pullop.trmanager:
1817 if confirm or (
1812 if confirm or (
1818 repo.ui.configbool(b"pull", b"confirm") and not repo.ui.plain()
1813 repo.ui.configbool(b"pull", b"confirm") and not repo.ui.plain()
1819 ):
1814 ):
1820 add_confirm_callback(repo, pullop)
1815 add_confirm_callback(repo, pullop)
1821
1816
1822 # Use the modern wire protocol, if available.
1817 # Use the modern wire protocol, if available.
1823 if remote.capable(b'command-changesetdata'):
1818 if remote.capable(b'command-changesetdata'):
1824 exchangev2.pull(pullop)
1819 exchangev2.pull(pullop)
1825 else:
1820 else:
1826 # This should ideally be in _pullbundle2(). However, it needs to run
1821 # This should ideally be in _pullbundle2(). However, it needs to run
1827 # before discovery to avoid extra work.
1822 # before discovery to avoid extra work.
1828 _maybeapplyclonebundle(pullop)
1823 _maybeapplyclonebundle(pullop)
1829 streamclone.maybeperformlegacystreamclone(pullop)
1824 streamclone.maybeperformlegacystreamclone(pullop)
1830 _pulldiscovery(pullop)
1825 _pulldiscovery(pullop)
1831 if pullop.canusebundle2:
1826 if pullop.canusebundle2:
1832 _fullpullbundle2(repo, pullop)
1827 _fullpullbundle2(repo, pullop)
1833 _pullchangeset(pullop)
1828 _pullchangeset(pullop)
1834 _pullphase(pullop)
1829 _pullphase(pullop)
1835 _pullbookmarks(pullop)
1830 _pullbookmarks(pullop)
1836 _pullobsolete(pullop)
1831 _pullobsolete(pullop)
1837
1832
1838 # storing remotenames
1833 # storing remotenames
1839 if repo.ui.configbool(b'experimental', b'remotenames'):
1834 if repo.ui.configbool(b'experimental', b'remotenames'):
1840 logexchange.pullremotenames(repo, remote)
1835 logexchange.pullremotenames(repo, remote)
1841
1836
1842 return pullop
1837 return pullop
1843
1838
1844
1839
1845 # list of steps to perform discovery before pull
1840 # list of steps to perform discovery before pull
1846 pulldiscoveryorder = []
1841 pulldiscoveryorder = []
1847
1842
1848 # Mapping between step name and function
1843 # Mapping between step name and function
1849 #
1844 #
1850 # This exists to help extensions wrap steps if necessary
1845 # This exists to help extensions wrap steps if necessary
1851 pulldiscoverymapping = {}
1846 pulldiscoverymapping = {}
1852
1847
1853
1848
1854 def pulldiscovery(stepname):
1849 def pulldiscovery(stepname):
1855 """decorator for function performing discovery before pull
1850 """decorator for function performing discovery before pull
1856
1851
1857 The function is added to the step -> function mapping and appended to the
1852 The function is added to the step -> function mapping and appended to the
1858 list of steps. Beware that decorated function will be added in order (this
1853 list of steps. Beware that decorated function will be added in order (this
1859 may matter).
1854 may matter).
1860
1855
1861 You can only use this decorator for a new step, if you want to wrap a step
1856 You can only use this decorator for a new step, if you want to wrap a step
1862 from an extension, change the pulldiscovery dictionary directly."""
1857 from an extension, change the pulldiscovery dictionary directly."""
1863
1858
1864 def dec(func):
1859 def dec(func):
1865 assert stepname not in pulldiscoverymapping
1860 assert stepname not in pulldiscoverymapping
1866 pulldiscoverymapping[stepname] = func
1861 pulldiscoverymapping[stepname] = func
1867 pulldiscoveryorder.append(stepname)
1862 pulldiscoveryorder.append(stepname)
1868 return func
1863 return func
1869
1864
1870 return dec
1865 return dec
1871
1866
1872
1867
1873 def _pulldiscovery(pullop):
1868 def _pulldiscovery(pullop):
1874 """Run all discovery steps"""
1869 """Run all discovery steps"""
1875 for stepname in pulldiscoveryorder:
1870 for stepname in pulldiscoveryorder:
1876 step = pulldiscoverymapping[stepname]
1871 step = pulldiscoverymapping[stepname]
1877 step(pullop)
1872 step(pullop)
1878
1873
1879
1874
1880 @pulldiscovery(b'b1:bookmarks')
1875 @pulldiscovery(b'b1:bookmarks')
1881 def _pullbookmarkbundle1(pullop):
1876 def _pullbookmarkbundle1(pullop):
1882 """fetch bookmark data in bundle1 case
1877 """fetch bookmark data in bundle1 case
1883
1878
1884 If not using bundle2, we have to fetch bookmarks before changeset
1879 If not using bundle2, we have to fetch bookmarks before changeset
1885 discovery to reduce the chance and impact of race conditions."""
1880 discovery to reduce the chance and impact of race conditions."""
1886 if pullop.remotebookmarks is not None:
1881 if pullop.remotebookmarks is not None:
1887 return
1882 return
1888 if pullop.canusebundle2 and b'listkeys' in pullop.remotebundle2caps:
1883 if pullop.canusebundle2 and b'listkeys' in pullop.remotebundle2caps:
1889 # all known bundle2 servers now support listkeys, but lets be nice with
1884 # all known bundle2 servers now support listkeys, but lets be nice with
1890 # new implementation.
1885 # new implementation.
1891 return
1886 return
1892 books = listkeys(pullop.remote, b'bookmarks')
1887 books = listkeys(pullop.remote, b'bookmarks')
1893 pullop.remotebookmarks = bookmod.unhexlifybookmarks(books)
1888 pullop.remotebookmarks = bookmod.unhexlifybookmarks(books)
1894
1889
1895
1890
1896 @pulldiscovery(b'changegroup')
1891 @pulldiscovery(b'changegroup')
1897 def _pulldiscoverychangegroup(pullop):
1892 def _pulldiscoverychangegroup(pullop):
1898 """discovery phase for the pull
1893 """discovery phase for the pull
1899
1894
1900 Current handle changeset discovery only, will change handle all discovery
1895 Current handle changeset discovery only, will change handle all discovery
1901 at some point."""
1896 at some point."""
1902 tmp = discovery.findcommonincoming(
1897 tmp = discovery.findcommonincoming(
1903 pullop.repo, pullop.remote, heads=pullop.heads, force=pullop.force
1898 pullop.repo, pullop.remote, heads=pullop.heads, force=pullop.force
1904 )
1899 )
1905 common, fetch, rheads = tmp
1900 common, fetch, rheads = tmp
1906 has_node = pullop.repo.unfiltered().changelog.index.has_node
1901 has_node = pullop.repo.unfiltered().changelog.index.has_node
1907 if fetch and rheads:
1902 if fetch and rheads:
1908 # If a remote heads is filtered locally, put in back in common.
1903 # If a remote heads is filtered locally, put in back in common.
1909 #
1904 #
1910 # This is a hackish solution to catch most of "common but locally
1905 # This is a hackish solution to catch most of "common but locally
1911 # hidden situation". We do not performs discovery on unfiltered
1906 # hidden situation". We do not performs discovery on unfiltered
1912 # repository because it end up doing a pathological amount of round
1907 # repository because it end up doing a pathological amount of round
1913 # trip for w huge amount of changeset we do not care about.
1908 # trip for w huge amount of changeset we do not care about.
1914 #
1909 #
1915 # If a set of such "common but filtered" changeset exist on the server
1910 # If a set of such "common but filtered" changeset exist on the server
1916 # but are not including a remote heads, we'll not be able to detect it,
1911 # but are not including a remote heads, we'll not be able to detect it,
1917 scommon = set(common)
1912 scommon = set(common)
1918 for n in rheads:
1913 for n in rheads:
1919 if has_node(n):
1914 if has_node(n):
1920 if n not in scommon:
1915 if n not in scommon:
1921 common.append(n)
1916 common.append(n)
1922 if set(rheads).issubset(set(common)):
1917 if set(rheads).issubset(set(common)):
1923 fetch = []
1918 fetch = []
1924 pullop.common = common
1919 pullop.common = common
1925 pullop.fetch = fetch
1920 pullop.fetch = fetch
1926 pullop.rheads = rheads
1921 pullop.rheads = rheads
1927
1922
1928
1923
1929 def _pullbundle2(pullop):
1924 def _pullbundle2(pullop):
1930 """pull data using bundle2
1925 """pull data using bundle2
1931
1926
1932 For now, the only supported data are changegroup."""
1927 For now, the only supported data are changegroup."""
1933 kwargs = {b'bundlecaps': caps20to10(pullop.repo, role=b'client')}
1928 kwargs = {b'bundlecaps': caps20to10(pullop.repo, role=b'client')}
1934
1929
1935 # make ui easier to access
1930 # make ui easier to access
1936 ui = pullop.repo.ui
1931 ui = pullop.repo.ui
1937
1932
1938 # At the moment we don't do stream clones over bundle2. If that is
1933 # At the moment we don't do stream clones over bundle2. If that is
1939 # implemented then here's where the check for that will go.
1934 # implemented then here's where the check for that will go.
1940 streaming = streamclone.canperformstreamclone(pullop, bundle2=True)[0]
1935 streaming = streamclone.canperformstreamclone(pullop, bundle2=True)[0]
1941
1936
1942 # declare pull perimeters
1937 # declare pull perimeters
1943 kwargs[b'common'] = pullop.common
1938 kwargs[b'common'] = pullop.common
1944 kwargs[b'heads'] = pullop.heads or pullop.rheads
1939 kwargs[b'heads'] = pullop.heads or pullop.rheads
1945
1940
1946 # check server supports narrow and then adding includepats and excludepats
1941 # check server supports narrow and then adding includepats and excludepats
1947 servernarrow = pullop.remote.capable(wireprototypes.NARROWCAP)
1942 servernarrow = pullop.remote.capable(wireprototypes.NARROWCAP)
1948 if servernarrow and pullop.includepats:
1943 if servernarrow and pullop.includepats:
1949 kwargs[b'includepats'] = pullop.includepats
1944 kwargs[b'includepats'] = pullop.includepats
1950 if servernarrow and pullop.excludepats:
1945 if servernarrow and pullop.excludepats:
1951 kwargs[b'excludepats'] = pullop.excludepats
1946 kwargs[b'excludepats'] = pullop.excludepats
1952
1947
1953 if streaming:
1948 if streaming:
1954 kwargs[b'cg'] = False
1949 kwargs[b'cg'] = False
1955 kwargs[b'stream'] = True
1950 kwargs[b'stream'] = True
1956 pullop.stepsdone.add(b'changegroup')
1951 pullop.stepsdone.add(b'changegroup')
1957 pullop.stepsdone.add(b'phases')
1952 pullop.stepsdone.add(b'phases')
1958
1953
1959 else:
1954 else:
1960 # pulling changegroup
1955 # pulling changegroup
1961 pullop.stepsdone.add(b'changegroup')
1956 pullop.stepsdone.add(b'changegroup')
1962
1957
1963 kwargs[b'cg'] = pullop.fetch
1958 kwargs[b'cg'] = pullop.fetch
1964
1959
1965 legacyphase = b'phases' in ui.configlist(b'devel', b'legacy.exchange')
1960 legacyphase = b'phases' in ui.configlist(b'devel', b'legacy.exchange')
1966 hasbinaryphase = b'heads' in pullop.remotebundle2caps.get(b'phases', ())
1961 hasbinaryphase = b'heads' in pullop.remotebundle2caps.get(b'phases', ())
1967 if not legacyphase and hasbinaryphase:
1962 if not legacyphase and hasbinaryphase:
1968 kwargs[b'phases'] = True
1963 kwargs[b'phases'] = True
1969 pullop.stepsdone.add(b'phases')
1964 pullop.stepsdone.add(b'phases')
1970
1965
1971 if b'listkeys' in pullop.remotebundle2caps:
1966 if b'listkeys' in pullop.remotebundle2caps:
1972 if b'phases' not in pullop.stepsdone:
1967 if b'phases' not in pullop.stepsdone:
1973 kwargs[b'listkeys'] = [b'phases']
1968 kwargs[b'listkeys'] = [b'phases']
1974
1969
1975 bookmarksrequested = False
1970 bookmarksrequested = False
1976 legacybookmark = b'bookmarks' in ui.configlist(b'devel', b'legacy.exchange')
1971 legacybookmark = b'bookmarks' in ui.configlist(b'devel', b'legacy.exchange')
1977 hasbinarybook = b'bookmarks' in pullop.remotebundle2caps
1972 hasbinarybook = b'bookmarks' in pullop.remotebundle2caps
1978
1973
1979 if pullop.remotebookmarks is not None:
1974 if pullop.remotebookmarks is not None:
1980 pullop.stepsdone.add(b'request-bookmarks')
1975 pullop.stepsdone.add(b'request-bookmarks')
1981
1976
1982 if (
1977 if (
1983 b'request-bookmarks' not in pullop.stepsdone
1978 b'request-bookmarks' not in pullop.stepsdone
1984 and pullop.remotebookmarks is None
1979 and pullop.remotebookmarks is None
1985 and not legacybookmark
1980 and not legacybookmark
1986 and hasbinarybook
1981 and hasbinarybook
1987 ):
1982 ):
1988 kwargs[b'bookmarks'] = True
1983 kwargs[b'bookmarks'] = True
1989 bookmarksrequested = True
1984 bookmarksrequested = True
1990
1985
1991 if b'listkeys' in pullop.remotebundle2caps:
1986 if b'listkeys' in pullop.remotebundle2caps:
1992 if b'request-bookmarks' not in pullop.stepsdone:
1987 if b'request-bookmarks' not in pullop.stepsdone:
1993 # make sure to always includes bookmark data when migrating
1988 # make sure to always includes bookmark data when migrating
1994 # `hg incoming --bundle` to using this function.
1989 # `hg incoming --bundle` to using this function.
1995 pullop.stepsdone.add(b'request-bookmarks')
1990 pullop.stepsdone.add(b'request-bookmarks')
1996 kwargs.setdefault(b'listkeys', []).append(b'bookmarks')
1991 kwargs.setdefault(b'listkeys', []).append(b'bookmarks')
1997
1992
1998 # If this is a full pull / clone and the server supports the clone bundles
1993 # If this is a full pull / clone and the server supports the clone bundles
1999 # feature, tell the server whether we attempted a clone bundle. The
1994 # feature, tell the server whether we attempted a clone bundle. The
2000 # presence of this flag indicates the client supports clone bundles. This
1995 # presence of this flag indicates the client supports clone bundles. This
2001 # will enable the server to treat clients that support clone bundles
1996 # will enable the server to treat clients that support clone bundles
2002 # differently from those that don't.
1997 # differently from those that don't.
2003 if (
1998 if (
2004 pullop.remote.capable(b'clonebundles')
1999 pullop.remote.capable(b'clonebundles')
2005 and pullop.heads is None
2000 and pullop.heads is None
2006 and list(pullop.common) == [nullid]
2001 and list(pullop.common) == [nullid]
2007 ):
2002 ):
2008 kwargs[b'cbattempted'] = pullop.clonebundleattempted
2003 kwargs[b'cbattempted'] = pullop.clonebundleattempted
2009
2004
2010 if streaming:
2005 if streaming:
2011 pullop.repo.ui.status(_(b'streaming all changes\n'))
2006 pullop.repo.ui.status(_(b'streaming all changes\n'))
2012 elif not pullop.fetch:
2007 elif not pullop.fetch:
2013 pullop.repo.ui.status(_(b"no changes found\n"))
2008 pullop.repo.ui.status(_(b"no changes found\n"))
2014 pullop.cgresult = 0
2009 pullop.cgresult = 0
2015 else:
2010 else:
2016 if pullop.heads is None and list(pullop.common) == [nullid]:
2011 if pullop.heads is None and list(pullop.common) == [nullid]:
2017 pullop.repo.ui.status(_(b"requesting all changes\n"))
2012 pullop.repo.ui.status(_(b"requesting all changes\n"))
2018 if obsolete.isenabled(pullop.repo, obsolete.exchangeopt):
2013 if obsolete.isenabled(pullop.repo, obsolete.exchangeopt):
2019 remoteversions = bundle2.obsmarkersversion(pullop.remotebundle2caps)
2014 remoteversions = bundle2.obsmarkersversion(pullop.remotebundle2caps)
2020 if obsolete.commonversion(remoteversions) is not None:
2015 if obsolete.commonversion(remoteversions) is not None:
2021 kwargs[b'obsmarkers'] = True
2016 kwargs[b'obsmarkers'] = True
2022 pullop.stepsdone.add(b'obsmarkers')
2017 pullop.stepsdone.add(b'obsmarkers')
2023 _pullbundle2extraprepare(pullop, kwargs)
2018 _pullbundle2extraprepare(pullop, kwargs)
2024
2019
2025 with pullop.remote.commandexecutor() as e:
2020 with pullop.remote.commandexecutor() as e:
2026 args = dict(kwargs)
2021 args = dict(kwargs)
2027 args[b'source'] = b'pull'
2022 args[b'source'] = b'pull'
2028 bundle = e.callcommand(b'getbundle', args).result()
2023 bundle = e.callcommand(b'getbundle', args).result()
2029
2024
2030 try:
2025 try:
2031 op = bundle2.bundleoperation(
2026 op = bundle2.bundleoperation(
2032 pullop.repo, pullop.gettransaction, source=b'pull'
2027 pullop.repo, pullop.gettransaction, source=b'pull'
2033 )
2028 )
2034 op.modes[b'bookmarks'] = b'records'
2029 op.modes[b'bookmarks'] = b'records'
2035 bundle2.processbundle(pullop.repo, bundle, op=op)
2030 bundle2.processbundle(pullop.repo, bundle, op=op)
2036 except bundle2.AbortFromPart as exc:
2031 except bundle2.AbortFromPart as exc:
2037 pullop.repo.ui.status(_(b'remote: abort: %s\n') % exc)
2032 pullop.repo.ui.status(_(b'remote: abort: %s\n') % exc)
2038 raise error.Abort(_(b'pull failed on remote'), hint=exc.hint)
2033 raise error.Abort(_(b'pull failed on remote'), hint=exc.hint)
2039 except error.BundleValueError as exc:
2034 except error.BundleValueError as exc:
2040 raise error.Abort(_(b'missing support for %s') % exc)
2035 raise error.Abort(_(b'missing support for %s') % exc)
2041
2036
2042 if pullop.fetch:
2037 if pullop.fetch:
2043 pullop.cgresult = bundle2.combinechangegroupresults(op)
2038 pullop.cgresult = bundle2.combinechangegroupresults(op)
2044
2039
2045 # processing phases change
2040 # processing phases change
2046 for namespace, value in op.records[b'listkeys']:
2041 for namespace, value in op.records[b'listkeys']:
2047 if namespace == b'phases':
2042 if namespace == b'phases':
2048 _pullapplyphases(pullop, value)
2043 _pullapplyphases(pullop, value)
2049
2044
2050 # processing bookmark update
2045 # processing bookmark update
2051 if bookmarksrequested:
2046 if bookmarksrequested:
2052 books = {}
2047 books = {}
2053 for record in op.records[b'bookmarks']:
2048 for record in op.records[b'bookmarks']:
2054 books[record[b'bookmark']] = record[b"node"]
2049 books[record[b'bookmark']] = record[b"node"]
2055 pullop.remotebookmarks = books
2050 pullop.remotebookmarks = books
2056 else:
2051 else:
2057 for namespace, value in op.records[b'listkeys']:
2052 for namespace, value in op.records[b'listkeys']:
2058 if namespace == b'bookmarks':
2053 if namespace == b'bookmarks':
2059 pullop.remotebookmarks = bookmod.unhexlifybookmarks(value)
2054 pullop.remotebookmarks = bookmod.unhexlifybookmarks(value)
2060
2055
2061 # bookmark data were either already there or pulled in the bundle
2056 # bookmark data were either already there or pulled in the bundle
2062 if pullop.remotebookmarks is not None:
2057 if pullop.remotebookmarks is not None:
2063 _pullbookmarks(pullop)
2058 _pullbookmarks(pullop)
2064
2059
2065
2060
2066 def _pullbundle2extraprepare(pullop, kwargs):
2061 def _pullbundle2extraprepare(pullop, kwargs):
2067 """hook function so that extensions can extend the getbundle call"""
2062 """hook function so that extensions can extend the getbundle call"""
2068
2063
2069
2064
2070 def _pullchangeset(pullop):
2065 def _pullchangeset(pullop):
2071 """pull changeset from unbundle into the local repo"""
2066 """pull changeset from unbundle into the local repo"""
2072 # We delay the open of the transaction as late as possible so we
2067 # We delay the open of the transaction as late as possible so we
2073 # don't open transaction for nothing or you break future useful
2068 # don't open transaction for nothing or you break future useful
2074 # rollback call
2069 # rollback call
2075 if b'changegroup' in pullop.stepsdone:
2070 if b'changegroup' in pullop.stepsdone:
2076 return
2071 return
2077 pullop.stepsdone.add(b'changegroup')
2072 pullop.stepsdone.add(b'changegroup')
2078 if not pullop.fetch:
2073 if not pullop.fetch:
2079 pullop.repo.ui.status(_(b"no changes found\n"))
2074 pullop.repo.ui.status(_(b"no changes found\n"))
2080 pullop.cgresult = 0
2075 pullop.cgresult = 0
2081 return
2076 return
2082 tr = pullop.gettransaction()
2077 tr = pullop.gettransaction()
2083 if pullop.heads is None and list(pullop.common) == [nullid]:
2078 if pullop.heads is None and list(pullop.common) == [nullid]:
2084 pullop.repo.ui.status(_(b"requesting all changes\n"))
2079 pullop.repo.ui.status(_(b"requesting all changes\n"))
2085 elif pullop.heads is None and pullop.remote.capable(b'changegroupsubset'):
2080 elif pullop.heads is None and pullop.remote.capable(b'changegroupsubset'):
2086 # issue1320, avoid a race if remote changed after discovery
2081 # issue1320, avoid a race if remote changed after discovery
2087 pullop.heads = pullop.rheads
2082 pullop.heads = pullop.rheads
2088
2083
2089 if pullop.remote.capable(b'getbundle'):
2084 if pullop.remote.capable(b'getbundle'):
2090 # TODO: get bundlecaps from remote
2085 # TODO: get bundlecaps from remote
2091 cg = pullop.remote.getbundle(
2086 cg = pullop.remote.getbundle(
2092 b'pull', common=pullop.common, heads=pullop.heads or pullop.rheads
2087 b'pull', common=pullop.common, heads=pullop.heads or pullop.rheads
2093 )
2088 )
2094 elif pullop.heads is None:
2089 elif pullop.heads is None:
2095 with pullop.remote.commandexecutor() as e:
2090 with pullop.remote.commandexecutor() as e:
2096 cg = e.callcommand(
2091 cg = e.callcommand(
2097 b'changegroup', {b'nodes': pullop.fetch, b'source': b'pull',}
2092 b'changegroup', {b'nodes': pullop.fetch, b'source': b'pull',}
2098 ).result()
2093 ).result()
2099
2094
2100 elif not pullop.remote.capable(b'changegroupsubset'):
2095 elif not pullop.remote.capable(b'changegroupsubset'):
2101 raise error.Abort(
2096 raise error.Abort(
2102 _(
2097 _(
2103 b"partial pull cannot be done because "
2098 b"partial pull cannot be done because "
2104 b"other repository doesn't support "
2099 b"other repository doesn't support "
2105 b"changegroupsubset."
2100 b"changegroupsubset."
2106 )
2101 )
2107 )
2102 )
2108 else:
2103 else:
2109 with pullop.remote.commandexecutor() as e:
2104 with pullop.remote.commandexecutor() as e:
2110 cg = e.callcommand(
2105 cg = e.callcommand(
2111 b'changegroupsubset',
2106 b'changegroupsubset',
2112 {
2107 {
2113 b'bases': pullop.fetch,
2108 b'bases': pullop.fetch,
2114 b'heads': pullop.heads,
2109 b'heads': pullop.heads,
2115 b'source': b'pull',
2110 b'source': b'pull',
2116 },
2111 },
2117 ).result()
2112 ).result()
2118
2113
2119 bundleop = bundle2.applybundle(
2114 bundleop = bundle2.applybundle(
2120 pullop.repo, cg, tr, b'pull', pullop.remote.url()
2115 pullop.repo, cg, tr, b'pull', pullop.remote.url()
2121 )
2116 )
2122 pullop.cgresult = bundle2.combinechangegroupresults(bundleop)
2117 pullop.cgresult = bundle2.combinechangegroupresults(bundleop)
2123
2118
2124
2119
2125 def _pullphase(pullop):
2120 def _pullphase(pullop):
2126 # Get remote phases data from remote
2121 # Get remote phases data from remote
2127 if b'phases' in pullop.stepsdone:
2122 if b'phases' in pullop.stepsdone:
2128 return
2123 return
2129 remotephases = listkeys(pullop.remote, b'phases')
2124 remotephases = listkeys(pullop.remote, b'phases')
2130 _pullapplyphases(pullop, remotephases)
2125 _pullapplyphases(pullop, remotephases)
2131
2126
2132
2127
2133 def _pullapplyphases(pullop, remotephases):
2128 def _pullapplyphases(pullop, remotephases):
2134 """apply phase movement from observed remote state"""
2129 """apply phase movement from observed remote state"""
2135 if b'phases' in pullop.stepsdone:
2130 if b'phases' in pullop.stepsdone:
2136 return
2131 return
2137 pullop.stepsdone.add(b'phases')
2132 pullop.stepsdone.add(b'phases')
2138 publishing = bool(remotephases.get(b'publishing', False))
2133 publishing = bool(remotephases.get(b'publishing', False))
2139 if remotephases and not publishing:
2134 if remotephases and not publishing:
2140 # remote is new and non-publishing
2135 # remote is new and non-publishing
2141 pheads, _dr = phases.analyzeremotephases(
2136 pheads, _dr = phases.analyzeremotephases(
2142 pullop.repo, pullop.pulledsubset, remotephases
2137 pullop.repo, pullop.pulledsubset, remotephases
2143 )
2138 )
2144 dheads = pullop.pulledsubset
2139 dheads = pullop.pulledsubset
2145 else:
2140 else:
2146 # Remote is old or publishing all common changesets
2141 # Remote is old or publishing all common changesets
2147 # should be seen as public
2142 # should be seen as public
2148 pheads = pullop.pulledsubset
2143 pheads = pullop.pulledsubset
2149 dheads = []
2144 dheads = []
2150 unfi = pullop.repo.unfiltered()
2145 unfi = pullop.repo.unfiltered()
2151 phase = unfi._phasecache.phase
2146 phase = unfi._phasecache.phase
2152 rev = unfi.changelog.index.get_rev
2147 rev = unfi.changelog.index.get_rev
2153 public = phases.public
2148 public = phases.public
2154 draft = phases.draft
2149 draft = phases.draft
2155
2150
2156 # exclude changesets already public locally and update the others
2151 # exclude changesets already public locally and update the others
2157 pheads = [pn for pn in pheads if phase(unfi, rev(pn)) > public]
2152 pheads = [pn for pn in pheads if phase(unfi, rev(pn)) > public]
2158 if pheads:
2153 if pheads:
2159 tr = pullop.gettransaction()
2154 tr = pullop.gettransaction()
2160 phases.advanceboundary(pullop.repo, tr, public, pheads)
2155 phases.advanceboundary(pullop.repo, tr, public, pheads)
2161
2156
2162 # exclude changesets already draft locally and update the others
2157 # exclude changesets already draft locally and update the others
2163 dheads = [pn for pn in dheads if phase(unfi, rev(pn)) > draft]
2158 dheads = [pn for pn in dheads if phase(unfi, rev(pn)) > draft]
2164 if dheads:
2159 if dheads:
2165 tr = pullop.gettransaction()
2160 tr = pullop.gettransaction()
2166 phases.advanceboundary(pullop.repo, tr, draft, dheads)
2161 phases.advanceboundary(pullop.repo, tr, draft, dheads)
2167
2162
2168
2163
2169 def _pullbookmarks(pullop):
2164 def _pullbookmarks(pullop):
2170 """process the remote bookmark information to update the local one"""
2165 """process the remote bookmark information to update the local one"""
2171 if b'bookmarks' in pullop.stepsdone:
2166 if b'bookmarks' in pullop.stepsdone:
2172 return
2167 return
2173 pullop.stepsdone.add(b'bookmarks')
2168 pullop.stepsdone.add(b'bookmarks')
2174 repo = pullop.repo
2169 repo = pullop.repo
2175 remotebookmarks = pullop.remotebookmarks
2170 remotebookmarks = pullop.remotebookmarks
2176 bookmod.updatefromremote(
2171 bookmod.updatefromremote(
2177 repo.ui,
2172 repo.ui,
2178 repo,
2173 repo,
2179 remotebookmarks,
2174 remotebookmarks,
2180 pullop.remote.url(),
2175 pullop.remote.url(),
2181 pullop.gettransaction,
2176 pullop.gettransaction,
2182 explicit=pullop.explicitbookmarks,
2177 explicit=pullop.explicitbookmarks,
2183 )
2178 )
2184
2179
2185
2180
2186 def _pullobsolete(pullop):
2181 def _pullobsolete(pullop):
2187 """utility function to pull obsolete markers from a remote
2182 """utility function to pull obsolete markers from a remote
2188
2183
2189 The `gettransaction` is function that return the pull transaction, creating
2184 The `gettransaction` is function that return the pull transaction, creating
2190 one if necessary. We return the transaction to inform the calling code that
2185 one if necessary. We return the transaction to inform the calling code that
2191 a new transaction have been created (when applicable).
2186 a new transaction have been created (when applicable).
2192
2187
2193 Exists mostly to allow overriding for experimentation purpose"""
2188 Exists mostly to allow overriding for experimentation purpose"""
2194 if b'obsmarkers' in pullop.stepsdone:
2189 if b'obsmarkers' in pullop.stepsdone:
2195 return
2190 return
2196 pullop.stepsdone.add(b'obsmarkers')
2191 pullop.stepsdone.add(b'obsmarkers')
2197 tr = None
2192 tr = None
2198 if obsolete.isenabled(pullop.repo, obsolete.exchangeopt):
2193 if obsolete.isenabled(pullop.repo, obsolete.exchangeopt):
2199 pullop.repo.ui.debug(b'fetching remote obsolete markers\n')
2194 pullop.repo.ui.debug(b'fetching remote obsolete markers\n')
2200 remoteobs = listkeys(pullop.remote, b'obsolete')
2195 remoteobs = listkeys(pullop.remote, b'obsolete')
2201 if b'dump0' in remoteobs:
2196 if b'dump0' in remoteobs:
2202 tr = pullop.gettransaction()
2197 tr = pullop.gettransaction()
2203 markers = []
2198 markers = []
2204 for key in sorted(remoteobs, reverse=True):
2199 for key in sorted(remoteobs, reverse=True):
2205 if key.startswith(b'dump'):
2200 if key.startswith(b'dump'):
2206 data = util.b85decode(remoteobs[key])
2201 data = util.b85decode(remoteobs[key])
2207 version, newmarks = obsolete._readmarkers(data)
2202 version, newmarks = obsolete._readmarkers(data)
2208 markers += newmarks
2203 markers += newmarks
2209 if markers:
2204 if markers:
2210 pullop.repo.obsstore.add(tr, markers)
2205 pullop.repo.obsstore.add(tr, markers)
2211 pullop.repo.invalidatevolatilesets()
2206 pullop.repo.invalidatevolatilesets()
2212 return tr
2207 return tr
2213
2208
2214
2209
2215 def applynarrowacl(repo, kwargs):
2210 def applynarrowacl(repo, kwargs):
2216 """Apply narrow fetch access control.
2211 """Apply narrow fetch access control.
2217
2212
2218 This massages the named arguments for getbundle wire protocol commands
2213 This massages the named arguments for getbundle wire protocol commands
2219 so requested data is filtered through access control rules.
2214 so requested data is filtered through access control rules.
2220 """
2215 """
2221 ui = repo.ui
2216 ui = repo.ui
2222 # TODO this assumes existence of HTTP and is a layering violation.
2217 # TODO this assumes existence of HTTP and is a layering violation.
2223 username = ui.shortuser(ui.environ.get(b'REMOTE_USER') or ui.username())
2218 username = ui.shortuser(ui.environ.get(b'REMOTE_USER') or ui.username())
2224 user_includes = ui.configlist(
2219 user_includes = ui.configlist(
2225 _NARROWACL_SECTION,
2220 _NARROWACL_SECTION,
2226 username + b'.includes',
2221 username + b'.includes',
2227 ui.configlist(_NARROWACL_SECTION, b'default.includes'),
2222 ui.configlist(_NARROWACL_SECTION, b'default.includes'),
2228 )
2223 )
2229 user_excludes = ui.configlist(
2224 user_excludes = ui.configlist(
2230 _NARROWACL_SECTION,
2225 _NARROWACL_SECTION,
2231 username + b'.excludes',
2226 username + b'.excludes',
2232 ui.configlist(_NARROWACL_SECTION, b'default.excludes'),
2227 ui.configlist(_NARROWACL_SECTION, b'default.excludes'),
2233 )
2228 )
2234 if not user_includes:
2229 if not user_includes:
2235 raise error.Abort(
2230 raise error.Abort(
2236 _(b"%s configuration for user %s is empty")
2231 _(b"%s configuration for user %s is empty")
2237 % (_NARROWACL_SECTION, username)
2232 % (_NARROWACL_SECTION, username)
2238 )
2233 )
2239
2234
2240 user_includes = [
2235 user_includes = [
2241 b'path:.' if p == b'*' else b'path:' + p for p in user_includes
2236 b'path:.' if p == b'*' else b'path:' + p for p in user_includes
2242 ]
2237 ]
2243 user_excludes = [
2238 user_excludes = [
2244 b'path:.' if p == b'*' else b'path:' + p for p in user_excludes
2239 b'path:.' if p == b'*' else b'path:' + p for p in user_excludes
2245 ]
2240 ]
2246
2241
2247 req_includes = set(kwargs.get('includepats', []))
2242 req_includes = set(kwargs.get('includepats', []))
2248 req_excludes = set(kwargs.get('excludepats', []))
2243 req_excludes = set(kwargs.get('excludepats', []))
2249
2244
2250 req_includes, req_excludes, invalid_includes = narrowspec.restrictpatterns(
2245 req_includes, req_excludes, invalid_includes = narrowspec.restrictpatterns(
2251 req_includes, req_excludes, user_includes, user_excludes
2246 req_includes, req_excludes, user_includes, user_excludes
2252 )
2247 )
2253
2248
2254 if invalid_includes:
2249 if invalid_includes:
2255 raise error.Abort(
2250 raise error.Abort(
2256 _(b"The following includes are not accessible for %s: %s")
2251 _(b"The following includes are not accessible for %s: %s")
2257 % (username, stringutil.pprint(invalid_includes))
2252 % (username, stringutil.pprint(invalid_includes))
2258 )
2253 )
2259
2254
2260 new_args = {}
2255 new_args = {}
2261 new_args.update(kwargs)
2256 new_args.update(kwargs)
2262 new_args['narrow'] = True
2257 new_args['narrow'] = True
2263 new_args['narrow_acl'] = True
2258 new_args['narrow_acl'] = True
2264 new_args['includepats'] = req_includes
2259 new_args['includepats'] = req_includes
2265 if req_excludes:
2260 if req_excludes:
2266 new_args['excludepats'] = req_excludes
2261 new_args['excludepats'] = req_excludes
2267
2262
2268 return new_args
2263 return new_args
2269
2264
2270
2265
2271 def _computeellipsis(repo, common, heads, known, match, depth=None):
2266 def _computeellipsis(repo, common, heads, known, match, depth=None):
2272 """Compute the shape of a narrowed DAG.
2267 """Compute the shape of a narrowed DAG.
2273
2268
2274 Args:
2269 Args:
2275 repo: The repository we're transferring.
2270 repo: The repository we're transferring.
2276 common: The roots of the DAG range we're transferring.
2271 common: The roots of the DAG range we're transferring.
2277 May be just [nullid], which means all ancestors of heads.
2272 May be just [nullid], which means all ancestors of heads.
2278 heads: The heads of the DAG range we're transferring.
2273 heads: The heads of the DAG range we're transferring.
2279 match: The narrowmatcher that allows us to identify relevant changes.
2274 match: The narrowmatcher that allows us to identify relevant changes.
2280 depth: If not None, only consider nodes to be full nodes if they are at
2275 depth: If not None, only consider nodes to be full nodes if they are at
2281 most depth changesets away from one of heads.
2276 most depth changesets away from one of heads.
2282
2277
2283 Returns:
2278 Returns:
2284 A tuple of (visitnodes, relevant_nodes, ellipsisroots) where:
2279 A tuple of (visitnodes, relevant_nodes, ellipsisroots) where:
2285
2280
2286 visitnodes: The list of nodes (either full or ellipsis) which
2281 visitnodes: The list of nodes (either full or ellipsis) which
2287 need to be sent to the client.
2282 need to be sent to the client.
2288 relevant_nodes: The set of changelog nodes which change a file inside
2283 relevant_nodes: The set of changelog nodes which change a file inside
2289 the narrowspec. The client needs these as non-ellipsis nodes.
2284 the narrowspec. The client needs these as non-ellipsis nodes.
2290 ellipsisroots: A dict of {rev: parents} that is used in
2285 ellipsisroots: A dict of {rev: parents} that is used in
2291 narrowchangegroup to produce ellipsis nodes with the
2286 narrowchangegroup to produce ellipsis nodes with the
2292 correct parents.
2287 correct parents.
2293 """
2288 """
2294 cl = repo.changelog
2289 cl = repo.changelog
2295 mfl = repo.manifestlog
2290 mfl = repo.manifestlog
2296
2291
2297 clrev = cl.rev
2292 clrev = cl.rev
2298
2293
2299 commonrevs = {clrev(n) for n in common} | {nullrev}
2294 commonrevs = {clrev(n) for n in common} | {nullrev}
2300 headsrevs = {clrev(n) for n in heads}
2295 headsrevs = {clrev(n) for n in heads}
2301
2296
2302 if depth:
2297 if depth:
2303 revdepth = {h: 0 for h in headsrevs}
2298 revdepth = {h: 0 for h in headsrevs}
2304
2299
2305 ellipsisheads = collections.defaultdict(set)
2300 ellipsisheads = collections.defaultdict(set)
2306 ellipsisroots = collections.defaultdict(set)
2301 ellipsisroots = collections.defaultdict(set)
2307
2302
2308 def addroot(head, curchange):
2303 def addroot(head, curchange):
2309 """Add a root to an ellipsis head, splitting heads with 3 roots."""
2304 """Add a root to an ellipsis head, splitting heads with 3 roots."""
2310 ellipsisroots[head].add(curchange)
2305 ellipsisroots[head].add(curchange)
2311 # Recursively split ellipsis heads with 3 roots by finding the
2306 # Recursively split ellipsis heads with 3 roots by finding the
2312 # roots' youngest common descendant which is an elided merge commit.
2307 # roots' youngest common descendant which is an elided merge commit.
2313 # That descendant takes 2 of the 3 roots as its own, and becomes a
2308 # That descendant takes 2 of the 3 roots as its own, and becomes a
2314 # root of the head.
2309 # root of the head.
2315 while len(ellipsisroots[head]) > 2:
2310 while len(ellipsisroots[head]) > 2:
2316 child, roots = splithead(head)
2311 child, roots = splithead(head)
2317 splitroots(head, child, roots)
2312 splitroots(head, child, roots)
2318 head = child # Recurse in case we just added a 3rd root
2313 head = child # Recurse in case we just added a 3rd root
2319
2314
2320 def splitroots(head, child, roots):
2315 def splitroots(head, child, roots):
2321 ellipsisroots[head].difference_update(roots)
2316 ellipsisroots[head].difference_update(roots)
2322 ellipsisroots[head].add(child)
2317 ellipsisroots[head].add(child)
2323 ellipsisroots[child].update(roots)
2318 ellipsisroots[child].update(roots)
2324 ellipsisroots[child].discard(child)
2319 ellipsisroots[child].discard(child)
2325
2320
2326 def splithead(head):
2321 def splithead(head):
2327 r1, r2, r3 = sorted(ellipsisroots[head])
2322 r1, r2, r3 = sorted(ellipsisroots[head])
2328 for nr1, nr2 in ((r2, r3), (r1, r3), (r1, r2)):
2323 for nr1, nr2 in ((r2, r3), (r1, r3), (r1, r2)):
2329 mid = repo.revs(
2324 mid = repo.revs(
2330 b'sort(merge() & %d::%d & %d::%d, -rev)', nr1, head, nr2, head
2325 b'sort(merge() & %d::%d & %d::%d, -rev)', nr1, head, nr2, head
2331 )
2326 )
2332 for j in mid:
2327 for j in mid:
2333 if j == nr2:
2328 if j == nr2:
2334 return nr2, (nr1, nr2)
2329 return nr2, (nr1, nr2)
2335 if j not in ellipsisroots or len(ellipsisroots[j]) < 2:
2330 if j not in ellipsisroots or len(ellipsisroots[j]) < 2:
2336 return j, (nr1, nr2)
2331 return j, (nr1, nr2)
2337 raise error.Abort(
2332 raise error.Abort(
2338 _(
2333 _(
2339 b'Failed to split up ellipsis node! head: %d, '
2334 b'Failed to split up ellipsis node! head: %d, '
2340 b'roots: %d %d %d'
2335 b'roots: %d %d %d'
2341 )
2336 )
2342 % (head, r1, r2, r3)
2337 % (head, r1, r2, r3)
2343 )
2338 )
2344
2339
2345 missing = list(cl.findmissingrevs(common=commonrevs, heads=headsrevs))
2340 missing = list(cl.findmissingrevs(common=commonrevs, heads=headsrevs))
2346 visit = reversed(missing)
2341 visit = reversed(missing)
2347 relevant_nodes = set()
2342 relevant_nodes = set()
2348 visitnodes = [cl.node(m) for m in missing]
2343 visitnodes = [cl.node(m) for m in missing]
2349 required = set(headsrevs) | known
2344 required = set(headsrevs) | known
2350 for rev in visit:
2345 for rev in visit:
2351 clrev = cl.changelogrevision(rev)
2346 clrev = cl.changelogrevision(rev)
2352 ps = [prev for prev in cl.parentrevs(rev) if prev != nullrev]
2347 ps = [prev for prev in cl.parentrevs(rev) if prev != nullrev]
2353 if depth is not None:
2348 if depth is not None:
2354 curdepth = revdepth[rev]
2349 curdepth = revdepth[rev]
2355 for p in ps:
2350 for p in ps:
2356 revdepth[p] = min(curdepth + 1, revdepth.get(p, depth + 1))
2351 revdepth[p] = min(curdepth + 1, revdepth.get(p, depth + 1))
2357 needed = False
2352 needed = False
2358 shallow_enough = depth is None or revdepth[rev] <= depth
2353 shallow_enough = depth is None or revdepth[rev] <= depth
2359 if shallow_enough:
2354 if shallow_enough:
2360 curmf = mfl[clrev.manifest].read()
2355 curmf = mfl[clrev.manifest].read()
2361 if ps:
2356 if ps:
2362 # We choose to not trust the changed files list in
2357 # We choose to not trust the changed files list in
2363 # changesets because it's not always correct. TODO: could
2358 # changesets because it's not always correct. TODO: could
2364 # we trust it for the non-merge case?
2359 # we trust it for the non-merge case?
2365 p1mf = mfl[cl.changelogrevision(ps[0]).manifest].read()
2360 p1mf = mfl[cl.changelogrevision(ps[0]).manifest].read()
2366 needed = bool(curmf.diff(p1mf, match))
2361 needed = bool(curmf.diff(p1mf, match))
2367 if not needed and len(ps) > 1:
2362 if not needed and len(ps) > 1:
2368 # For merge changes, the list of changed files is not
2363 # For merge changes, the list of changed files is not
2369 # helpful, since we need to emit the merge if a file
2364 # helpful, since we need to emit the merge if a file
2370 # in the narrow spec has changed on either side of the
2365 # in the narrow spec has changed on either side of the
2371 # merge. As a result, we do a manifest diff to check.
2366 # merge. As a result, we do a manifest diff to check.
2372 p2mf = mfl[cl.changelogrevision(ps[1]).manifest].read()
2367 p2mf = mfl[cl.changelogrevision(ps[1]).manifest].read()
2373 needed = bool(curmf.diff(p2mf, match))
2368 needed = bool(curmf.diff(p2mf, match))
2374 else:
2369 else:
2375 # For a root node, we need to include the node if any
2370 # For a root node, we need to include the node if any
2376 # files in the node match the narrowspec.
2371 # files in the node match the narrowspec.
2377 needed = any(curmf.walk(match))
2372 needed = any(curmf.walk(match))
2378
2373
2379 if needed:
2374 if needed:
2380 for head in ellipsisheads[rev]:
2375 for head in ellipsisheads[rev]:
2381 addroot(head, rev)
2376 addroot(head, rev)
2382 for p in ps:
2377 for p in ps:
2383 required.add(p)
2378 required.add(p)
2384 relevant_nodes.add(cl.node(rev))
2379 relevant_nodes.add(cl.node(rev))
2385 else:
2380 else:
2386 if not ps:
2381 if not ps:
2387 ps = [nullrev]
2382 ps = [nullrev]
2388 if rev in required:
2383 if rev in required:
2389 for head in ellipsisheads[rev]:
2384 for head in ellipsisheads[rev]:
2390 addroot(head, rev)
2385 addroot(head, rev)
2391 for p in ps:
2386 for p in ps:
2392 ellipsisheads[p].add(rev)
2387 ellipsisheads[p].add(rev)
2393 else:
2388 else:
2394 for p in ps:
2389 for p in ps:
2395 ellipsisheads[p] |= ellipsisheads[rev]
2390 ellipsisheads[p] |= ellipsisheads[rev]
2396
2391
2397 # add common changesets as roots of their reachable ellipsis heads
2392 # add common changesets as roots of their reachable ellipsis heads
2398 for c in commonrevs:
2393 for c in commonrevs:
2399 for head in ellipsisheads[c]:
2394 for head in ellipsisheads[c]:
2400 addroot(head, c)
2395 addroot(head, c)
2401 return visitnodes, relevant_nodes, ellipsisroots
2396 return visitnodes, relevant_nodes, ellipsisroots
2402
2397
2403
2398
2404 def caps20to10(repo, role):
2399 def caps20to10(repo, role):
2405 """return a set with appropriate options to use bundle20 during getbundle"""
2400 """return a set with appropriate options to use bundle20 during getbundle"""
2406 caps = {b'HG20'}
2401 caps = {b'HG20'}
2407 capsblob = bundle2.encodecaps(bundle2.getrepocaps(repo, role=role))
2402 capsblob = bundle2.encodecaps(bundle2.getrepocaps(repo, role=role))
2408 caps.add(b'bundle2=' + urlreq.quote(capsblob))
2403 caps.add(b'bundle2=' + urlreq.quote(capsblob))
2409 return caps
2404 return caps
2410
2405
2411
2406
2412 # List of names of steps to perform for a bundle2 for getbundle, order matters.
2407 # List of names of steps to perform for a bundle2 for getbundle, order matters.
2413 getbundle2partsorder = []
2408 getbundle2partsorder = []
2414
2409
2415 # Mapping between step name and function
2410 # Mapping between step name and function
2416 #
2411 #
2417 # This exists to help extensions wrap steps if necessary
2412 # This exists to help extensions wrap steps if necessary
2418 getbundle2partsmapping = {}
2413 getbundle2partsmapping = {}
2419
2414
2420
2415
2421 def getbundle2partsgenerator(stepname, idx=None):
2416 def getbundle2partsgenerator(stepname, idx=None):
2422 """decorator for function generating bundle2 part for getbundle
2417 """decorator for function generating bundle2 part for getbundle
2423
2418
2424 The function is added to the step -> function mapping and appended to the
2419 The function is added to the step -> function mapping and appended to the
2425 list of steps. Beware that decorated functions will be added in order
2420 list of steps. Beware that decorated functions will be added in order
2426 (this may matter).
2421 (this may matter).
2427
2422
2428 You can only use this decorator for new steps, if you want to wrap a step
2423 You can only use this decorator for new steps, if you want to wrap a step
2429 from an extension, attack the getbundle2partsmapping dictionary directly."""
2424 from an extension, attack the getbundle2partsmapping dictionary directly."""
2430
2425
2431 def dec(func):
2426 def dec(func):
2432 assert stepname not in getbundle2partsmapping
2427 assert stepname not in getbundle2partsmapping
2433 getbundle2partsmapping[stepname] = func
2428 getbundle2partsmapping[stepname] = func
2434 if idx is None:
2429 if idx is None:
2435 getbundle2partsorder.append(stepname)
2430 getbundle2partsorder.append(stepname)
2436 else:
2431 else:
2437 getbundle2partsorder.insert(idx, stepname)
2432 getbundle2partsorder.insert(idx, stepname)
2438 return func
2433 return func
2439
2434
2440 return dec
2435 return dec
2441
2436
2442
2437
2443 def bundle2requested(bundlecaps):
2438 def bundle2requested(bundlecaps):
2444 if bundlecaps is not None:
2439 if bundlecaps is not None:
2445 return any(cap.startswith(b'HG2') for cap in bundlecaps)
2440 return any(cap.startswith(b'HG2') for cap in bundlecaps)
2446 return False
2441 return False
2447
2442
2448
2443
2449 def getbundlechunks(
2444 def getbundlechunks(
2450 repo, source, heads=None, common=None, bundlecaps=None, **kwargs
2445 repo, source, heads=None, common=None, bundlecaps=None, **kwargs
2451 ):
2446 ):
2452 """Return chunks constituting a bundle's raw data.
2447 """Return chunks constituting a bundle's raw data.
2453
2448
2454 Could be a bundle HG10 or a bundle HG20 depending on bundlecaps
2449 Could be a bundle HG10 or a bundle HG20 depending on bundlecaps
2455 passed.
2450 passed.
2456
2451
2457 Returns a 2-tuple of a dict with metadata about the generated bundle
2452 Returns a 2-tuple of a dict with metadata about the generated bundle
2458 and an iterator over raw chunks (of varying sizes).
2453 and an iterator over raw chunks (of varying sizes).
2459 """
2454 """
2460 kwargs = pycompat.byteskwargs(kwargs)
2455 kwargs = pycompat.byteskwargs(kwargs)
2461 info = {}
2456 info = {}
2462 usebundle2 = bundle2requested(bundlecaps)
2457 usebundle2 = bundle2requested(bundlecaps)
2463 # bundle10 case
2458 # bundle10 case
2464 if not usebundle2:
2459 if not usebundle2:
2465 if bundlecaps and not kwargs.get(b'cg', True):
2460 if bundlecaps and not kwargs.get(b'cg', True):
2466 raise ValueError(
2461 raise ValueError(
2467 _(b'request for bundle10 must include changegroup')
2462 _(b'request for bundle10 must include changegroup')
2468 )
2463 )
2469
2464
2470 if kwargs:
2465 if kwargs:
2471 raise ValueError(
2466 raise ValueError(
2472 _(b'unsupported getbundle arguments: %s')
2467 _(b'unsupported getbundle arguments: %s')
2473 % b', '.join(sorted(kwargs.keys()))
2468 % b', '.join(sorted(kwargs.keys()))
2474 )
2469 )
2475 outgoing = _computeoutgoing(repo, heads, common)
2470 outgoing = _computeoutgoing(repo, heads, common)
2476 info[b'bundleversion'] = 1
2471 info[b'bundleversion'] = 1
2477 return (
2472 return (
2478 info,
2473 info,
2479 changegroup.makestream(
2474 changegroup.makestream(
2480 repo, outgoing, b'01', source, bundlecaps=bundlecaps
2475 repo, outgoing, b'01', source, bundlecaps=bundlecaps
2481 ),
2476 ),
2482 )
2477 )
2483
2478
2484 # bundle20 case
2479 # bundle20 case
2485 info[b'bundleversion'] = 2
2480 info[b'bundleversion'] = 2
2486 b2caps = {}
2481 b2caps = {}
2487 for bcaps in bundlecaps:
2482 for bcaps in bundlecaps:
2488 if bcaps.startswith(b'bundle2='):
2483 if bcaps.startswith(b'bundle2='):
2489 blob = urlreq.unquote(bcaps[len(b'bundle2=') :])
2484 blob = urlreq.unquote(bcaps[len(b'bundle2=') :])
2490 b2caps.update(bundle2.decodecaps(blob))
2485 b2caps.update(bundle2.decodecaps(blob))
2491 bundler = bundle2.bundle20(repo.ui, b2caps)
2486 bundler = bundle2.bundle20(repo.ui, b2caps)
2492
2487
2493 kwargs[b'heads'] = heads
2488 kwargs[b'heads'] = heads
2494 kwargs[b'common'] = common
2489 kwargs[b'common'] = common
2495
2490
2496 for name in getbundle2partsorder:
2491 for name in getbundle2partsorder:
2497 func = getbundle2partsmapping[name]
2492 func = getbundle2partsmapping[name]
2498 func(
2493 func(
2499 bundler,
2494 bundler,
2500 repo,
2495 repo,
2501 source,
2496 source,
2502 bundlecaps=bundlecaps,
2497 bundlecaps=bundlecaps,
2503 b2caps=b2caps,
2498 b2caps=b2caps,
2504 **pycompat.strkwargs(kwargs)
2499 **pycompat.strkwargs(kwargs)
2505 )
2500 )
2506
2501
2507 info[b'prefercompressed'] = bundler.prefercompressed
2502 info[b'prefercompressed'] = bundler.prefercompressed
2508
2503
2509 return info, bundler.getchunks()
2504 return info, bundler.getchunks()
2510
2505
2511
2506
2512 @getbundle2partsgenerator(b'stream2')
2507 @getbundle2partsgenerator(b'stream2')
2513 def _getbundlestream2(bundler, repo, *args, **kwargs):
2508 def _getbundlestream2(bundler, repo, *args, **kwargs):
2514 return bundle2.addpartbundlestream2(bundler, repo, **kwargs)
2509 return bundle2.addpartbundlestream2(bundler, repo, **kwargs)
2515
2510
2516
2511
2517 @getbundle2partsgenerator(b'changegroup')
2512 @getbundle2partsgenerator(b'changegroup')
2518 def _getbundlechangegrouppart(
2513 def _getbundlechangegrouppart(
2519 bundler,
2514 bundler,
2520 repo,
2515 repo,
2521 source,
2516 source,
2522 bundlecaps=None,
2517 bundlecaps=None,
2523 b2caps=None,
2518 b2caps=None,
2524 heads=None,
2519 heads=None,
2525 common=None,
2520 common=None,
2526 **kwargs
2521 **kwargs
2527 ):
2522 ):
2528 """add a changegroup part to the requested bundle"""
2523 """add a changegroup part to the requested bundle"""
2529 if not kwargs.get('cg', True) or not b2caps:
2524 if not kwargs.get('cg', True) or not b2caps:
2530 return
2525 return
2531
2526
2532 version = b'01'
2527 version = b'01'
2533 cgversions = b2caps.get(b'changegroup')
2528 cgversions = b2caps.get(b'changegroup')
2534 if cgversions: # 3.1 and 3.2 ship with an empty value
2529 if cgversions: # 3.1 and 3.2 ship with an empty value
2535 cgversions = [
2530 cgversions = [
2536 v
2531 v
2537 for v in cgversions
2532 for v in cgversions
2538 if v in changegroup.supportedoutgoingversions(repo)
2533 if v in changegroup.supportedoutgoingversions(repo)
2539 ]
2534 ]
2540 if not cgversions:
2535 if not cgversions:
2541 raise error.Abort(_(b'no common changegroup version'))
2536 raise error.Abort(_(b'no common changegroup version'))
2542 version = max(cgversions)
2537 version = max(cgversions)
2543
2538
2544 outgoing = _computeoutgoing(repo, heads, common)
2539 outgoing = _computeoutgoing(repo, heads, common)
2545 if not outgoing.missing:
2540 if not outgoing.missing:
2546 return
2541 return
2547
2542
2548 if kwargs.get('narrow', False):
2543 if kwargs.get('narrow', False):
2549 include = sorted(filter(bool, kwargs.get('includepats', [])))
2544 include = sorted(filter(bool, kwargs.get('includepats', [])))
2550 exclude = sorted(filter(bool, kwargs.get('excludepats', [])))
2545 exclude = sorted(filter(bool, kwargs.get('excludepats', [])))
2551 matcher = narrowspec.match(repo.root, include=include, exclude=exclude)
2546 matcher = narrowspec.match(repo.root, include=include, exclude=exclude)
2552 else:
2547 else:
2553 matcher = None
2548 matcher = None
2554
2549
2555 cgstream = changegroup.makestream(
2550 cgstream = changegroup.makestream(
2556 repo, outgoing, version, source, bundlecaps=bundlecaps, matcher=matcher
2551 repo, outgoing, version, source, bundlecaps=bundlecaps, matcher=matcher
2557 )
2552 )
2558
2553
2559 part = bundler.newpart(b'changegroup', data=cgstream)
2554 part = bundler.newpart(b'changegroup', data=cgstream)
2560 if cgversions:
2555 if cgversions:
2561 part.addparam(b'version', version)
2556 part.addparam(b'version', version)
2562
2557
2563 part.addparam(b'nbchanges', b'%d' % len(outgoing.missing), mandatory=False)
2558 part.addparam(b'nbchanges', b'%d' % len(outgoing.missing), mandatory=False)
2564
2559
2565 if b'treemanifest' in repo.requirements:
2560 if b'treemanifest' in repo.requirements:
2566 part.addparam(b'treemanifest', b'1')
2561 part.addparam(b'treemanifest', b'1')
2567
2562
2568 if b'exp-sidedata-flag' in repo.requirements:
2563 if b'exp-sidedata-flag' in repo.requirements:
2569 part.addparam(b'exp-sidedata', b'1')
2564 part.addparam(b'exp-sidedata', b'1')
2570
2565
2571 if (
2566 if (
2572 kwargs.get('narrow', False)
2567 kwargs.get('narrow', False)
2573 and kwargs.get('narrow_acl', False)
2568 and kwargs.get('narrow_acl', False)
2574 and (include or exclude)
2569 and (include or exclude)
2575 ):
2570 ):
2576 # this is mandatory because otherwise ACL clients won't work
2571 # this is mandatory because otherwise ACL clients won't work
2577 narrowspecpart = bundler.newpart(b'Narrow:responsespec')
2572 narrowspecpart = bundler.newpart(b'Narrow:responsespec')
2578 narrowspecpart.data = b'%s\0%s' % (
2573 narrowspecpart.data = b'%s\0%s' % (
2579 b'\n'.join(include),
2574 b'\n'.join(include),
2580 b'\n'.join(exclude),
2575 b'\n'.join(exclude),
2581 )
2576 )
2582
2577
2583
2578
2584 @getbundle2partsgenerator(b'bookmarks')
2579 @getbundle2partsgenerator(b'bookmarks')
2585 def _getbundlebookmarkpart(
2580 def _getbundlebookmarkpart(
2586 bundler, repo, source, bundlecaps=None, b2caps=None, **kwargs
2581 bundler, repo, source, bundlecaps=None, b2caps=None, **kwargs
2587 ):
2582 ):
2588 """add a bookmark part to the requested bundle"""
2583 """add a bookmark part to the requested bundle"""
2589 if not kwargs.get('bookmarks', False):
2584 if not kwargs.get('bookmarks', False):
2590 return
2585 return
2591 if not b2caps or b'bookmarks' not in b2caps:
2586 if not b2caps or b'bookmarks' not in b2caps:
2592 raise error.Abort(_(b'no common bookmarks exchange method'))
2587 raise error.Abort(_(b'no common bookmarks exchange method'))
2593 books = bookmod.listbinbookmarks(repo)
2588 books = bookmod.listbinbookmarks(repo)
2594 data = bookmod.binaryencode(books)
2589 data = bookmod.binaryencode(books)
2595 if data:
2590 if data:
2596 bundler.newpart(b'bookmarks', data=data)
2591 bundler.newpart(b'bookmarks', data=data)
2597
2592
2598
2593
2599 @getbundle2partsgenerator(b'listkeys')
2594 @getbundle2partsgenerator(b'listkeys')
2600 def _getbundlelistkeysparts(
2595 def _getbundlelistkeysparts(
2601 bundler, repo, source, bundlecaps=None, b2caps=None, **kwargs
2596 bundler, repo, source, bundlecaps=None, b2caps=None, **kwargs
2602 ):
2597 ):
2603 """add parts containing listkeys namespaces to the requested bundle"""
2598 """add parts containing listkeys namespaces to the requested bundle"""
2604 listkeys = kwargs.get('listkeys', ())
2599 listkeys = kwargs.get('listkeys', ())
2605 for namespace in listkeys:
2600 for namespace in listkeys:
2606 part = bundler.newpart(b'listkeys')
2601 part = bundler.newpart(b'listkeys')
2607 part.addparam(b'namespace', namespace)
2602 part.addparam(b'namespace', namespace)
2608 keys = repo.listkeys(namespace).items()
2603 keys = repo.listkeys(namespace).items()
2609 part.data = pushkey.encodekeys(keys)
2604 part.data = pushkey.encodekeys(keys)
2610
2605
2611
2606
2612 @getbundle2partsgenerator(b'obsmarkers')
2607 @getbundle2partsgenerator(b'obsmarkers')
2613 def _getbundleobsmarkerpart(
2608 def _getbundleobsmarkerpart(
2614 bundler, repo, source, bundlecaps=None, b2caps=None, heads=None, **kwargs
2609 bundler, repo, source, bundlecaps=None, b2caps=None, heads=None, **kwargs
2615 ):
2610 ):
2616 """add an obsolescence markers part to the requested bundle"""
2611 """add an obsolescence markers part to the requested bundle"""
2617 if kwargs.get('obsmarkers', False):
2612 if kwargs.get('obsmarkers', False):
2618 if heads is None:
2613 if heads is None:
2619 heads = repo.heads()
2614 heads = repo.heads()
2620 subset = [c.node() for c in repo.set(b'::%ln', heads)]
2615 subset = [c.node() for c in repo.set(b'::%ln', heads)]
2621 markers = repo.obsstore.relevantmarkers(subset)
2616 markers = repo.obsstore.relevantmarkers(subset)
2622 markers = obsutil.sortedmarkers(markers)
2617 markers = obsutil.sortedmarkers(markers)
2623 bundle2.buildobsmarkerspart(bundler, markers)
2618 bundle2.buildobsmarkerspart(bundler, markers)
2624
2619
2625
2620
2626 @getbundle2partsgenerator(b'phases')
2621 @getbundle2partsgenerator(b'phases')
2627 def _getbundlephasespart(
2622 def _getbundlephasespart(
2628 bundler, repo, source, bundlecaps=None, b2caps=None, heads=None, **kwargs
2623 bundler, repo, source, bundlecaps=None, b2caps=None, heads=None, **kwargs
2629 ):
2624 ):
2630 """add phase heads part to the requested bundle"""
2625 """add phase heads part to the requested bundle"""
2631 if kwargs.get('phases', False):
2626 if kwargs.get('phases', False):
2632 if not b2caps or b'heads' not in b2caps.get(b'phases'):
2627 if not b2caps or b'heads' not in b2caps.get(b'phases'):
2633 raise error.Abort(_(b'no common phases exchange method'))
2628 raise error.Abort(_(b'no common phases exchange method'))
2634 if heads is None:
2629 if heads is None:
2635 heads = repo.heads()
2630 heads = repo.heads()
2636
2631
2637 headsbyphase = collections.defaultdict(set)
2632 headsbyphase = collections.defaultdict(set)
2638 if repo.publishing():
2633 if repo.publishing():
2639 headsbyphase[phases.public] = heads
2634 headsbyphase[phases.public] = heads
2640 else:
2635 else:
2641 # find the appropriate heads to move
2636 # find the appropriate heads to move
2642
2637
2643 phase = repo._phasecache.phase
2638 phase = repo._phasecache.phase
2644 node = repo.changelog.node
2639 node = repo.changelog.node
2645 rev = repo.changelog.rev
2640 rev = repo.changelog.rev
2646 for h in heads:
2641 for h in heads:
2647 headsbyphase[phase(repo, rev(h))].add(h)
2642 headsbyphase[phase(repo, rev(h))].add(h)
2648 seenphases = list(headsbyphase.keys())
2643 seenphases = list(headsbyphase.keys())
2649
2644
2650 # We do not handle anything but public and draft phase for now)
2645 # We do not handle anything but public and draft phase for now)
2651 if seenphases:
2646 if seenphases:
2652 assert max(seenphases) <= phases.draft
2647 assert max(seenphases) <= phases.draft
2653
2648
2654 # if client is pulling non-public changesets, we need to find
2649 # if client is pulling non-public changesets, we need to find
2655 # intermediate public heads.
2650 # intermediate public heads.
2656 draftheads = headsbyphase.get(phases.draft, set())
2651 draftheads = headsbyphase.get(phases.draft, set())
2657 if draftheads:
2652 if draftheads:
2658 publicheads = headsbyphase.get(phases.public, set())
2653 publicheads = headsbyphase.get(phases.public, set())
2659
2654
2660 revset = b'heads(only(%ln, %ln) and public())'
2655 revset = b'heads(only(%ln, %ln) and public())'
2661 extraheads = repo.revs(revset, draftheads, publicheads)
2656 extraheads = repo.revs(revset, draftheads, publicheads)
2662 for r in extraheads:
2657 for r in extraheads:
2663 headsbyphase[phases.public].add(node(r))
2658 headsbyphase[phases.public].add(node(r))
2664
2659
2665 # transform data in a format used by the encoding function
2660 # transform data in a format used by the encoding function
2666 phasemapping = {
2661 phasemapping = {
2667 phase: sorted(headsbyphase[phase]) for phase in phases.allphases
2662 phase: sorted(headsbyphase[phase]) for phase in phases.allphases
2668 }
2663 }
2669
2664
2670 # generate the actual part
2665 # generate the actual part
2671 phasedata = phases.binaryencode(phasemapping)
2666 phasedata = phases.binaryencode(phasemapping)
2672 bundler.newpart(b'phase-heads', data=phasedata)
2667 bundler.newpart(b'phase-heads', data=phasedata)
2673
2668
2674
2669
2675 @getbundle2partsgenerator(b'hgtagsfnodes')
2670 @getbundle2partsgenerator(b'hgtagsfnodes')
2676 def _getbundletagsfnodes(
2671 def _getbundletagsfnodes(
2677 bundler,
2672 bundler,
2678 repo,
2673 repo,
2679 source,
2674 source,
2680 bundlecaps=None,
2675 bundlecaps=None,
2681 b2caps=None,
2676 b2caps=None,
2682 heads=None,
2677 heads=None,
2683 common=None,
2678 common=None,
2684 **kwargs
2679 **kwargs
2685 ):
2680 ):
2686 """Transfer the .hgtags filenodes mapping.
2681 """Transfer the .hgtags filenodes mapping.
2687
2682
2688 Only values for heads in this bundle will be transferred.
2683 Only values for heads in this bundle will be transferred.
2689
2684
2690 The part data consists of pairs of 20 byte changeset node and .hgtags
2685 The part data consists of pairs of 20 byte changeset node and .hgtags
2691 filenodes raw values.
2686 filenodes raw values.
2692 """
2687 """
2693 # Don't send unless:
2688 # Don't send unless:
2694 # - changeset are being exchanged,
2689 # - changeset are being exchanged,
2695 # - the client supports it.
2690 # - the client supports it.
2696 if not b2caps or not (kwargs.get('cg', True) and b'hgtagsfnodes' in b2caps):
2691 if not b2caps or not (kwargs.get('cg', True) and b'hgtagsfnodes' in b2caps):
2697 return
2692 return
2698
2693
2699 outgoing = _computeoutgoing(repo, heads, common)
2694 outgoing = _computeoutgoing(repo, heads, common)
2700 bundle2.addparttagsfnodescache(repo, bundler, outgoing)
2695 bundle2.addparttagsfnodescache(repo, bundler, outgoing)
2701
2696
2702
2697
2703 @getbundle2partsgenerator(b'cache:rev-branch-cache')
2698 @getbundle2partsgenerator(b'cache:rev-branch-cache')
2704 def _getbundlerevbranchcache(
2699 def _getbundlerevbranchcache(
2705 bundler,
2700 bundler,
2706 repo,
2701 repo,
2707 source,
2702 source,
2708 bundlecaps=None,
2703 bundlecaps=None,
2709 b2caps=None,
2704 b2caps=None,
2710 heads=None,
2705 heads=None,
2711 common=None,
2706 common=None,
2712 **kwargs
2707 **kwargs
2713 ):
2708 ):
2714 """Transfer the rev-branch-cache mapping
2709 """Transfer the rev-branch-cache mapping
2715
2710
2716 The payload is a series of data related to each branch
2711 The payload is a series of data related to each branch
2717
2712
2718 1) branch name length
2713 1) branch name length
2719 2) number of open heads
2714 2) number of open heads
2720 3) number of closed heads
2715 3) number of closed heads
2721 4) open heads nodes
2716 4) open heads nodes
2722 5) closed heads nodes
2717 5) closed heads nodes
2723 """
2718 """
2724 # Don't send unless:
2719 # Don't send unless:
2725 # - changeset are being exchanged,
2720 # - changeset are being exchanged,
2726 # - the client supports it.
2721 # - the client supports it.
2727 # - narrow bundle isn't in play (not currently compatible).
2722 # - narrow bundle isn't in play (not currently compatible).
2728 if (
2723 if (
2729 not kwargs.get('cg', True)
2724 not kwargs.get('cg', True)
2730 or not b2caps
2725 or not b2caps
2731 or b'rev-branch-cache' not in b2caps
2726 or b'rev-branch-cache' not in b2caps
2732 or kwargs.get('narrow', False)
2727 or kwargs.get('narrow', False)
2733 or repo.ui.has_section(_NARROWACL_SECTION)
2728 or repo.ui.has_section(_NARROWACL_SECTION)
2734 ):
2729 ):
2735 return
2730 return
2736
2731
2737 outgoing = _computeoutgoing(repo, heads, common)
2732 outgoing = _computeoutgoing(repo, heads, common)
2738 bundle2.addpartrevbranchcache(repo, bundler, outgoing)
2733 bundle2.addpartrevbranchcache(repo, bundler, outgoing)
2739
2734
2740
2735
2741 def check_heads(repo, their_heads, context):
2736 def check_heads(repo, their_heads, context):
2742 """check if the heads of a repo have been modified
2737 """check if the heads of a repo have been modified
2743
2738
2744 Used by peer for unbundling.
2739 Used by peer for unbundling.
2745 """
2740 """
2746 heads = repo.heads()
2741 heads = repo.heads()
2747 heads_hash = hashutil.sha1(b''.join(sorted(heads))).digest()
2742 heads_hash = hashutil.sha1(b''.join(sorted(heads))).digest()
2748 if not (
2743 if not (
2749 their_heads == [b'force']
2744 their_heads == [b'force']
2750 or their_heads == heads
2745 or their_heads == heads
2751 or their_heads == [b'hashed', heads_hash]
2746 or their_heads == [b'hashed', heads_hash]
2752 ):
2747 ):
2753 # someone else committed/pushed/unbundled while we
2748 # someone else committed/pushed/unbundled while we
2754 # were transferring data
2749 # were transferring data
2755 raise error.PushRaced(
2750 raise error.PushRaced(
2756 b'repository changed while %s - please try again' % context
2751 b'repository changed while %s - please try again' % context
2757 )
2752 )
2758
2753
2759
2754
2760 def unbundle(repo, cg, heads, source, url):
2755 def unbundle(repo, cg, heads, source, url):
2761 """Apply a bundle to a repo.
2756 """Apply a bundle to a repo.
2762
2757
2763 this function makes sure the repo is locked during the application and have
2758 this function makes sure the repo is locked during the application and have
2764 mechanism to check that no push race occurred between the creation of the
2759 mechanism to check that no push race occurred between the creation of the
2765 bundle and its application.
2760 bundle and its application.
2766
2761
2767 If the push was raced as PushRaced exception is raised."""
2762 If the push was raced as PushRaced exception is raised."""
2768 r = 0
2763 r = 0
2769 # need a transaction when processing a bundle2 stream
2764 # need a transaction when processing a bundle2 stream
2770 # [wlock, lock, tr] - needs to be an array so nested functions can modify it
2765 # [wlock, lock, tr] - needs to be an array so nested functions can modify it
2771 lockandtr = [None, None, None]
2766 lockandtr = [None, None, None]
2772 recordout = None
2767 recordout = None
2773 # quick fix for output mismatch with bundle2 in 3.4
2768 # quick fix for output mismatch with bundle2 in 3.4
2774 captureoutput = repo.ui.configbool(
2769 captureoutput = repo.ui.configbool(
2775 b'experimental', b'bundle2-output-capture'
2770 b'experimental', b'bundle2-output-capture'
2776 )
2771 )
2777 if url.startswith(b'remote:http:') or url.startswith(b'remote:https:'):
2772 if url.startswith(b'remote:http:') or url.startswith(b'remote:https:'):
2778 captureoutput = True
2773 captureoutput = True
2779 try:
2774 try:
2780 # note: outside bundle1, 'heads' is expected to be empty and this
2775 # note: outside bundle1, 'heads' is expected to be empty and this
2781 # 'check_heads' call wil be a no-op
2776 # 'check_heads' call wil be a no-op
2782 check_heads(repo, heads, b'uploading changes')
2777 check_heads(repo, heads, b'uploading changes')
2783 # push can proceed
2778 # push can proceed
2784 if not isinstance(cg, bundle2.unbundle20):
2779 if not isinstance(cg, bundle2.unbundle20):
2785 # legacy case: bundle1 (changegroup 01)
2780 # legacy case: bundle1 (changegroup 01)
2786 txnname = b"\n".join([source, util.hidepassword(url)])
2781 txnname = b"\n".join([source, util.hidepassword(url)])
2787 with repo.lock(), repo.transaction(txnname) as tr:
2782 with repo.lock(), repo.transaction(txnname) as tr:
2788 op = bundle2.applybundle(repo, cg, tr, source, url)
2783 op = bundle2.applybundle(repo, cg, tr, source, url)
2789 r = bundle2.combinechangegroupresults(op)
2784 r = bundle2.combinechangegroupresults(op)
2790 else:
2785 else:
2791 r = None
2786 r = None
2792 try:
2787 try:
2793
2788
2794 def gettransaction():
2789 def gettransaction():
2795 if not lockandtr[2]:
2790 if not lockandtr[2]:
2796 if not bookmod.bookmarksinstore(repo):
2791 if not bookmod.bookmarksinstore(repo):
2797 lockandtr[0] = repo.wlock()
2792 lockandtr[0] = repo.wlock()
2798 lockandtr[1] = repo.lock()
2793 lockandtr[1] = repo.lock()
2799 lockandtr[2] = repo.transaction(source)
2794 lockandtr[2] = repo.transaction(source)
2800 lockandtr[2].hookargs[b'source'] = source
2795 lockandtr[2].hookargs[b'source'] = source
2801 lockandtr[2].hookargs[b'url'] = url
2796 lockandtr[2].hookargs[b'url'] = url
2802 lockandtr[2].hookargs[b'bundle2'] = b'1'
2797 lockandtr[2].hookargs[b'bundle2'] = b'1'
2803 return lockandtr[2]
2798 return lockandtr[2]
2804
2799
2805 # Do greedy locking by default until we're satisfied with lazy
2800 # Do greedy locking by default until we're satisfied with lazy
2806 # locking.
2801 # locking.
2807 if not repo.ui.configbool(
2802 if not repo.ui.configbool(
2808 b'experimental', b'bundle2lazylocking'
2803 b'experimental', b'bundle2lazylocking'
2809 ):
2804 ):
2810 gettransaction()
2805 gettransaction()
2811
2806
2812 op = bundle2.bundleoperation(
2807 op = bundle2.bundleoperation(
2813 repo,
2808 repo,
2814 gettransaction,
2809 gettransaction,
2815 captureoutput=captureoutput,
2810 captureoutput=captureoutput,
2816 source=b'push',
2811 source=b'push',
2817 )
2812 )
2818 try:
2813 try:
2819 op = bundle2.processbundle(repo, cg, op=op)
2814 op = bundle2.processbundle(repo, cg, op=op)
2820 finally:
2815 finally:
2821 r = op.reply
2816 r = op.reply
2822 if captureoutput and r is not None:
2817 if captureoutput and r is not None:
2823 repo.ui.pushbuffer(error=True, subproc=True)
2818 repo.ui.pushbuffer(error=True, subproc=True)
2824
2819
2825 def recordout(output):
2820 def recordout(output):
2826 r.newpart(b'output', data=output, mandatory=False)
2821 r.newpart(b'output', data=output, mandatory=False)
2827
2822
2828 if lockandtr[2] is not None:
2823 if lockandtr[2] is not None:
2829 lockandtr[2].close()
2824 lockandtr[2].close()
2830 except BaseException as exc:
2825 except BaseException as exc:
2831 exc.duringunbundle2 = True
2826 exc.duringunbundle2 = True
2832 if captureoutput and r is not None:
2827 if captureoutput and r is not None:
2833 parts = exc._bundle2salvagedoutput = r.salvageoutput()
2828 parts = exc._bundle2salvagedoutput = r.salvageoutput()
2834
2829
2835 def recordout(output):
2830 def recordout(output):
2836 part = bundle2.bundlepart(
2831 part = bundle2.bundlepart(
2837 b'output', data=output, mandatory=False
2832 b'output', data=output, mandatory=False
2838 )
2833 )
2839 parts.append(part)
2834 parts.append(part)
2840
2835
2841 raise
2836 raise
2842 finally:
2837 finally:
2843 lockmod.release(lockandtr[2], lockandtr[1], lockandtr[0])
2838 lockmod.release(lockandtr[2], lockandtr[1], lockandtr[0])
2844 if recordout is not None:
2839 if recordout is not None:
2845 recordout(repo.ui.popbuffer())
2840 recordout(repo.ui.popbuffer())
2846 return r
2841 return r
2847
2842
2848
2843
2849 def _maybeapplyclonebundle(pullop):
2844 def _maybeapplyclonebundle(pullop):
2850 """Apply a clone bundle from a remote, if possible."""
2845 """Apply a clone bundle from a remote, if possible."""
2851
2846
2852 repo = pullop.repo
2847 repo = pullop.repo
2853 remote = pullop.remote
2848 remote = pullop.remote
2854
2849
2855 if not repo.ui.configbool(b'ui', b'clonebundles'):
2850 if not repo.ui.configbool(b'ui', b'clonebundles'):
2856 return
2851 return
2857
2852
2858 # Only run if local repo is empty.
2853 # Only run if local repo is empty.
2859 if len(repo):
2854 if len(repo):
2860 return
2855 return
2861
2856
2862 if pullop.heads:
2857 if pullop.heads:
2863 return
2858 return
2864
2859
2865 if not remote.capable(b'clonebundles'):
2860 if not remote.capable(b'clonebundles'):
2866 return
2861 return
2867
2862
2868 with remote.commandexecutor() as e:
2863 with remote.commandexecutor() as e:
2869 res = e.callcommand(b'clonebundles', {}).result()
2864 res = e.callcommand(b'clonebundles', {}).result()
2870
2865
2871 # If we call the wire protocol command, that's good enough to record the
2866 # If we call the wire protocol command, that's good enough to record the
2872 # attempt.
2867 # attempt.
2873 pullop.clonebundleattempted = True
2868 pullop.clonebundleattempted = True
2874
2869
2875 entries = parseclonebundlesmanifest(repo, res)
2870 entries = parseclonebundlesmanifest(repo, res)
2876 if not entries:
2871 if not entries:
2877 repo.ui.note(
2872 repo.ui.note(
2878 _(
2873 _(
2879 b'no clone bundles available on remote; '
2874 b'no clone bundles available on remote; '
2880 b'falling back to regular clone\n'
2875 b'falling back to regular clone\n'
2881 )
2876 )
2882 )
2877 )
2883 return
2878 return
2884
2879
2885 entries = filterclonebundleentries(
2880 entries = filterclonebundleentries(
2886 repo, entries, streamclonerequested=pullop.streamclonerequested
2881 repo, entries, streamclonerequested=pullop.streamclonerequested
2887 )
2882 )
2888
2883
2889 if not entries:
2884 if not entries:
2890 # There is a thundering herd concern here. However, if a server
2885 # There is a thundering herd concern here. However, if a server
2891 # operator doesn't advertise bundles appropriate for its clients,
2886 # operator doesn't advertise bundles appropriate for its clients,
2892 # they deserve what's coming. Furthermore, from a client's
2887 # they deserve what's coming. Furthermore, from a client's
2893 # perspective, no automatic fallback would mean not being able to
2888 # perspective, no automatic fallback would mean not being able to
2894 # clone!
2889 # clone!
2895 repo.ui.warn(
2890 repo.ui.warn(
2896 _(
2891 _(
2897 b'no compatible clone bundles available on server; '
2892 b'no compatible clone bundles available on server; '
2898 b'falling back to regular clone\n'
2893 b'falling back to regular clone\n'
2899 )
2894 )
2900 )
2895 )
2901 repo.ui.warn(
2896 repo.ui.warn(
2902 _(b'(you may want to report this to the server operator)\n')
2897 _(b'(you may want to report this to the server operator)\n')
2903 )
2898 )
2904 return
2899 return
2905
2900
2906 entries = sortclonebundleentries(repo.ui, entries)
2901 entries = sortclonebundleentries(repo.ui, entries)
2907
2902
2908 url = entries[0][b'URL']
2903 url = entries[0][b'URL']
2909 repo.ui.status(_(b'applying clone bundle from %s\n') % url)
2904 repo.ui.status(_(b'applying clone bundle from %s\n') % url)
2910 if trypullbundlefromurl(repo.ui, repo, url):
2905 if trypullbundlefromurl(repo.ui, repo, url):
2911 repo.ui.status(_(b'finished applying clone bundle\n'))
2906 repo.ui.status(_(b'finished applying clone bundle\n'))
2912 # Bundle failed.
2907 # Bundle failed.
2913 #
2908 #
2914 # We abort by default to avoid the thundering herd of
2909 # We abort by default to avoid the thundering herd of
2915 # clients flooding a server that was expecting expensive
2910 # clients flooding a server that was expecting expensive
2916 # clone load to be offloaded.
2911 # clone load to be offloaded.
2917 elif repo.ui.configbool(b'ui', b'clonebundlefallback'):
2912 elif repo.ui.configbool(b'ui', b'clonebundlefallback'):
2918 repo.ui.warn(_(b'falling back to normal clone\n'))
2913 repo.ui.warn(_(b'falling back to normal clone\n'))
2919 else:
2914 else:
2920 raise error.Abort(
2915 raise error.Abort(
2921 _(b'error applying bundle'),
2916 _(b'error applying bundle'),
2922 hint=_(
2917 hint=_(
2923 b'if this error persists, consider contacting '
2918 b'if this error persists, consider contacting '
2924 b'the server operator or disable clone '
2919 b'the server operator or disable clone '
2925 b'bundles via '
2920 b'bundles via '
2926 b'"--config ui.clonebundles=false"'
2921 b'"--config ui.clonebundles=false"'
2927 ),
2922 ),
2928 )
2923 )
2929
2924
2930
2925
2931 def parseclonebundlesmanifest(repo, s):
2926 def parseclonebundlesmanifest(repo, s):
2932 """Parses the raw text of a clone bundles manifest.
2927 """Parses the raw text of a clone bundles manifest.
2933
2928
2934 Returns a list of dicts. The dicts have a ``URL`` key corresponding
2929 Returns a list of dicts. The dicts have a ``URL`` key corresponding
2935 to the URL and other keys are the attributes for the entry.
2930 to the URL and other keys are the attributes for the entry.
2936 """
2931 """
2937 m = []
2932 m = []
2938 for line in s.splitlines():
2933 for line in s.splitlines():
2939 fields = line.split()
2934 fields = line.split()
2940 if not fields:
2935 if not fields:
2941 continue
2936 continue
2942 attrs = {b'URL': fields[0]}
2937 attrs = {b'URL': fields[0]}
2943 for rawattr in fields[1:]:
2938 for rawattr in fields[1:]:
2944 key, value = rawattr.split(b'=', 1)
2939 key, value = rawattr.split(b'=', 1)
2945 key = urlreq.unquote(key)
2940 key = urlreq.unquote(key)
2946 value = urlreq.unquote(value)
2941 value = urlreq.unquote(value)
2947 attrs[key] = value
2942 attrs[key] = value
2948
2943
2949 # Parse BUNDLESPEC into components. This makes client-side
2944 # Parse BUNDLESPEC into components. This makes client-side
2950 # preferences easier to specify since you can prefer a single
2945 # preferences easier to specify since you can prefer a single
2951 # component of the BUNDLESPEC.
2946 # component of the BUNDLESPEC.
2952 if key == b'BUNDLESPEC':
2947 if key == b'BUNDLESPEC':
2953 try:
2948 try:
2954 bundlespec = parsebundlespec(repo, value)
2949 bundlespec = parsebundlespec(repo, value)
2955 attrs[b'COMPRESSION'] = bundlespec.compression
2950 attrs[b'COMPRESSION'] = bundlespec.compression
2956 attrs[b'VERSION'] = bundlespec.version
2951 attrs[b'VERSION'] = bundlespec.version
2957 except error.InvalidBundleSpecification:
2952 except error.InvalidBundleSpecification:
2958 pass
2953 pass
2959 except error.UnsupportedBundleSpecification:
2954 except error.UnsupportedBundleSpecification:
2960 pass
2955 pass
2961
2956
2962 m.append(attrs)
2957 m.append(attrs)
2963
2958
2964 return m
2959 return m
2965
2960
2966
2961
2967 def isstreamclonespec(bundlespec):
2962 def isstreamclonespec(bundlespec):
2968 # Stream clone v1
2963 # Stream clone v1
2969 if bundlespec.wirecompression == b'UN' and bundlespec.wireversion == b's1':
2964 if bundlespec.wirecompression == b'UN' and bundlespec.wireversion == b's1':
2970 return True
2965 return True
2971
2966
2972 # Stream clone v2
2967 # Stream clone v2
2973 if (
2968 if (
2974 bundlespec.wirecompression == b'UN'
2969 bundlespec.wirecompression == b'UN'
2975 and bundlespec.wireversion == b'02'
2970 and bundlespec.wireversion == b'02'
2976 and bundlespec.contentopts.get(b'streamv2')
2971 and bundlespec.contentopts.get(b'streamv2')
2977 ):
2972 ):
2978 return True
2973 return True
2979
2974
2980 return False
2975 return False
2981
2976
2982
2977
2983 def filterclonebundleentries(repo, entries, streamclonerequested=False):
2978 def filterclonebundleentries(repo, entries, streamclonerequested=False):
2984 """Remove incompatible clone bundle manifest entries.
2979 """Remove incompatible clone bundle manifest entries.
2985
2980
2986 Accepts a list of entries parsed with ``parseclonebundlesmanifest``
2981 Accepts a list of entries parsed with ``parseclonebundlesmanifest``
2987 and returns a new list consisting of only the entries that this client
2982 and returns a new list consisting of only the entries that this client
2988 should be able to apply.
2983 should be able to apply.
2989
2984
2990 There is no guarantee we'll be able to apply all returned entries because
2985 There is no guarantee we'll be able to apply all returned entries because
2991 the metadata we use to filter on may be missing or wrong.
2986 the metadata we use to filter on may be missing or wrong.
2992 """
2987 """
2993 newentries = []
2988 newentries = []
2994 for entry in entries:
2989 for entry in entries:
2995 spec = entry.get(b'BUNDLESPEC')
2990 spec = entry.get(b'BUNDLESPEC')
2996 if spec:
2991 if spec:
2997 try:
2992 try:
2998 bundlespec = parsebundlespec(repo, spec, strict=True)
2993 bundlespec = parsebundlespec(repo, spec, strict=True)
2999
2994
3000 # If a stream clone was requested, filter out non-streamclone
2995 # If a stream clone was requested, filter out non-streamclone
3001 # entries.
2996 # entries.
3002 if streamclonerequested and not isstreamclonespec(bundlespec):
2997 if streamclonerequested and not isstreamclonespec(bundlespec):
3003 repo.ui.debug(
2998 repo.ui.debug(
3004 b'filtering %s because not a stream clone\n'
2999 b'filtering %s because not a stream clone\n'
3005 % entry[b'URL']
3000 % entry[b'URL']
3006 )
3001 )
3007 continue
3002 continue
3008
3003
3009 except error.InvalidBundleSpecification as e:
3004 except error.InvalidBundleSpecification as e:
3010 repo.ui.debug(stringutil.forcebytestr(e) + b'\n')
3005 repo.ui.debug(stringutil.forcebytestr(e) + b'\n')
3011 continue
3006 continue
3012 except error.UnsupportedBundleSpecification as e:
3007 except error.UnsupportedBundleSpecification as e:
3013 repo.ui.debug(
3008 repo.ui.debug(
3014 b'filtering %s because unsupported bundle '
3009 b'filtering %s because unsupported bundle '
3015 b'spec: %s\n' % (entry[b'URL'], stringutil.forcebytestr(e))
3010 b'spec: %s\n' % (entry[b'URL'], stringutil.forcebytestr(e))
3016 )
3011 )
3017 continue
3012 continue
3018 # If we don't have a spec and requested a stream clone, we don't know
3013 # If we don't have a spec and requested a stream clone, we don't know
3019 # what the entry is so don't attempt to apply it.
3014 # what the entry is so don't attempt to apply it.
3020 elif streamclonerequested:
3015 elif streamclonerequested:
3021 repo.ui.debug(
3016 repo.ui.debug(
3022 b'filtering %s because cannot determine if a stream '
3017 b'filtering %s because cannot determine if a stream '
3023 b'clone bundle\n' % entry[b'URL']
3018 b'clone bundle\n' % entry[b'URL']
3024 )
3019 )
3025 continue
3020 continue
3026
3021
3027 if b'REQUIRESNI' in entry and not sslutil.hassni:
3022 if b'REQUIRESNI' in entry and not sslutil.hassni:
3028 repo.ui.debug(
3023 repo.ui.debug(
3029 b'filtering %s because SNI not supported\n' % entry[b'URL']
3024 b'filtering %s because SNI not supported\n' % entry[b'URL']
3030 )
3025 )
3031 continue
3026 continue
3032
3027
3033 if b'REQUIREDRAM' in entry:
3028 if b'REQUIREDRAM' in entry:
3034 try:
3029 try:
3035 requiredram = util.sizetoint(entry[b'REQUIREDRAM'])
3030 requiredram = util.sizetoint(entry[b'REQUIREDRAM'])
3036 except error.ParseError:
3031 except error.ParseError:
3037 repo.ui.debug(
3032 repo.ui.debug(
3038 b'filtering %s due to a bad REQUIREDRAM attribute\n'
3033 b'filtering %s due to a bad REQUIREDRAM attribute\n'
3039 % entry[b'URL']
3034 % entry[b'URL']
3040 )
3035 )
3041 continue
3036 continue
3042 actualram = repo.ui.estimatememory()
3037 actualram = repo.ui.estimatememory()
3043 if actualram is not None and actualram * 0.66 < requiredram:
3038 if actualram is not None and actualram * 0.66 < requiredram:
3044 repo.ui.debug(
3039 repo.ui.debug(
3045 b'filtering %s as it needs more than 2/3 of system memory\n'
3040 b'filtering %s as it needs more than 2/3 of system memory\n'
3046 % entry[b'URL']
3041 % entry[b'URL']
3047 )
3042 )
3048 continue
3043 continue
3049
3044
3050 newentries.append(entry)
3045 newentries.append(entry)
3051
3046
3052 return newentries
3047 return newentries
3053
3048
3054
3049
3055 class clonebundleentry(object):
3050 class clonebundleentry(object):
3056 """Represents an item in a clone bundles manifest.
3051 """Represents an item in a clone bundles manifest.
3057
3052
3058 This rich class is needed to support sorting since sorted() in Python 3
3053 This rich class is needed to support sorting since sorted() in Python 3
3059 doesn't support ``cmp`` and our comparison is complex enough that ``key=``
3054 doesn't support ``cmp`` and our comparison is complex enough that ``key=``
3060 won't work.
3055 won't work.
3061 """
3056 """
3062
3057
3063 def __init__(self, value, prefers):
3058 def __init__(self, value, prefers):
3064 self.value = value
3059 self.value = value
3065 self.prefers = prefers
3060 self.prefers = prefers
3066
3061
3067 def _cmp(self, other):
3062 def _cmp(self, other):
3068 for prefkey, prefvalue in self.prefers:
3063 for prefkey, prefvalue in self.prefers:
3069 avalue = self.value.get(prefkey)
3064 avalue = self.value.get(prefkey)
3070 bvalue = other.value.get(prefkey)
3065 bvalue = other.value.get(prefkey)
3071
3066
3072 # Special case for b missing attribute and a matches exactly.
3067 # Special case for b missing attribute and a matches exactly.
3073 if avalue is not None and bvalue is None and avalue == prefvalue:
3068 if avalue is not None and bvalue is None and avalue == prefvalue:
3074 return -1
3069 return -1
3075
3070
3076 # Special case for a missing attribute and b matches exactly.
3071 # Special case for a missing attribute and b matches exactly.
3077 if bvalue is not None and avalue is None and bvalue == prefvalue:
3072 if bvalue is not None and avalue is None and bvalue == prefvalue:
3078 return 1
3073 return 1
3079
3074
3080 # We can't compare unless attribute present on both.
3075 # We can't compare unless attribute present on both.
3081 if avalue is None or bvalue is None:
3076 if avalue is None or bvalue is None:
3082 continue
3077 continue
3083
3078
3084 # Same values should fall back to next attribute.
3079 # Same values should fall back to next attribute.
3085 if avalue == bvalue:
3080 if avalue == bvalue:
3086 continue
3081 continue
3087
3082
3088 # Exact matches come first.
3083 # Exact matches come first.
3089 if avalue == prefvalue:
3084 if avalue == prefvalue:
3090 return -1
3085 return -1
3091 if bvalue == prefvalue:
3086 if bvalue == prefvalue:
3092 return 1
3087 return 1
3093
3088
3094 # Fall back to next attribute.
3089 # Fall back to next attribute.
3095 continue
3090 continue
3096
3091
3097 # If we got here we couldn't sort by attributes and prefers. Fall
3092 # If we got here we couldn't sort by attributes and prefers. Fall
3098 # back to index order.
3093 # back to index order.
3099 return 0
3094 return 0
3100
3095
3101 def __lt__(self, other):
3096 def __lt__(self, other):
3102 return self._cmp(other) < 0
3097 return self._cmp(other) < 0
3103
3098
3104 def __gt__(self, other):
3099 def __gt__(self, other):
3105 return self._cmp(other) > 0
3100 return self._cmp(other) > 0
3106
3101
3107 def __eq__(self, other):
3102 def __eq__(self, other):
3108 return self._cmp(other) == 0
3103 return self._cmp(other) == 0
3109
3104
3110 def __le__(self, other):
3105 def __le__(self, other):
3111 return self._cmp(other) <= 0
3106 return self._cmp(other) <= 0
3112
3107
3113 def __ge__(self, other):
3108 def __ge__(self, other):
3114 return self._cmp(other) >= 0
3109 return self._cmp(other) >= 0
3115
3110
3116 def __ne__(self, other):
3111 def __ne__(self, other):
3117 return self._cmp(other) != 0
3112 return self._cmp(other) != 0
3118
3113
3119
3114
3120 def sortclonebundleentries(ui, entries):
3115 def sortclonebundleentries(ui, entries):
3121 prefers = ui.configlist(b'ui', b'clonebundleprefers')
3116 prefers = ui.configlist(b'ui', b'clonebundleprefers')
3122 if not prefers:
3117 if not prefers:
3123 return list(entries)
3118 return list(entries)
3124
3119
3125 def _split(p):
3120 def _split(p):
3126 if b'=' not in p:
3121 if b'=' not in p:
3127 hint = _(b"each comma separated item should be key=value pairs")
3122 hint = _(b"each comma separated item should be key=value pairs")
3128 raise error.Abort(
3123 raise error.Abort(
3129 _(b"invalid ui.clonebundleprefers item: %s") % p, hint=hint
3124 _(b"invalid ui.clonebundleprefers item: %s") % p, hint=hint
3130 )
3125 )
3131 return p.split(b'=', 1)
3126 return p.split(b'=', 1)
3132
3127
3133 prefers = [_split(p) for p in prefers]
3128 prefers = [_split(p) for p in prefers]
3134
3129
3135 items = sorted(clonebundleentry(v, prefers) for v in entries)
3130 items = sorted(clonebundleentry(v, prefers) for v in entries)
3136 return [i.value for i in items]
3131 return [i.value for i in items]
3137
3132
3138
3133
3139 def trypullbundlefromurl(ui, repo, url):
3134 def trypullbundlefromurl(ui, repo, url):
3140 """Attempt to apply a bundle from a URL."""
3135 """Attempt to apply a bundle from a URL."""
3141 with repo.lock(), repo.transaction(b'bundleurl') as tr:
3136 with repo.lock(), repo.transaction(b'bundleurl') as tr:
3142 try:
3137 try:
3143 fh = urlmod.open(ui, url)
3138 fh = urlmod.open(ui, url)
3144 cg = readbundle(ui, fh, b'stream')
3139 cg = readbundle(ui, fh, b'stream')
3145
3140
3146 if isinstance(cg, streamclone.streamcloneapplier):
3141 if isinstance(cg, streamclone.streamcloneapplier):
3147 cg.apply(repo)
3142 cg.apply(repo)
3148 else:
3143 else:
3149 bundle2.applybundle(repo, cg, tr, b'clonebundles', url)
3144 bundle2.applybundle(repo, cg, tr, b'clonebundles', url)
3150 return True
3145 return True
3151 except urlerr.httperror as e:
3146 except urlerr.httperror as e:
3152 ui.warn(
3147 ui.warn(
3153 _(b'HTTP error fetching bundle: %s\n')
3148 _(b'HTTP error fetching bundle: %s\n')
3154 % stringutil.forcebytestr(e)
3149 % stringutil.forcebytestr(e)
3155 )
3150 )
3156 except urlerr.urlerror as e:
3151 except urlerr.urlerror as e:
3157 ui.warn(
3152 ui.warn(
3158 _(b'error fetching bundle: %s\n')
3153 _(b'error fetching bundle: %s\n')
3159 % stringutil.forcebytestr(e.reason)
3154 % stringutil.forcebytestr(e.reason)
3160 )
3155 )
3161
3156
3162 return False
3157 return False
@@ -1,800 +1,798 b''
1 Test file dedicated to testing the divergent troubles from obsolete changeset.
1 Test file dedicated to testing the divergent troubles from obsolete changeset.
2
2
3 This is the most complex troubles from far so we isolate it in a dedicated
3 This is the most complex troubles from far so we isolate it in a dedicated
4 file.
4 file.
5
5
6 Enable obsolete
6 Enable obsolete
7
7
8 $ cat >> $HGRCPATH << EOF
8 $ cat >> $HGRCPATH << EOF
9 > [ui]
9 > [ui]
10 > logtemplate = {rev}:{node|short} {desc}{if(obsfate, " [{join(obsfate, "; ")}]")}\n
10 > logtemplate = {rev}:{node|short} {desc}{if(obsfate, " [{join(obsfate, "; ")}]")}\n
11 > [experimental]
11 > [experimental]
12 > evolution.createmarkers=True
12 > evolution.createmarkers=True
13 > [extensions]
13 > [extensions]
14 > drawdag=$TESTDIR/drawdag.py
14 > drawdag=$TESTDIR/drawdag.py
15 > [alias]
15 > [alias]
16 > debugobsolete = debugobsolete -d '0 0'
16 > debugobsolete = debugobsolete -d '0 0'
17 > [phases]
17 > [phases]
18 > publish=False
18 > publish=False
19 > [templates]
19 > [templates]
20 > wuentryshort = '{instability}:{if(divergentnodes, " ")}{divergentnodes} {reason} {node|shortest}\n'
20 > wuentryshort = '{instability}:{if(divergentnodes, " ")}{divergentnodes} {reason} {node|shortest}\n'
21 > whyunstableshort = '{whyunstable % wuentryshort}'
21 > whyunstableshort = '{whyunstable % wuentryshort}'
22 > wuentryshorter = '{instability}:{divergentnodes % " {node|shortest} ({phase})"} {reason} {node|shortest}\n'
22 > wuentryshorter = '{instability}:{divergentnodes % " {node|shortest} ({phase})"} {reason} {node|shortest}\n'
23 > whyunstableshorter = '{whyunstable % wuentryshorter}'
23 > whyunstableshorter = '{whyunstable % wuentryshorter}'
24 > EOF
24 > EOF
25
25
26
26
27 $ mkcommit() {
27 $ mkcommit() {
28 > echo "$1" > "$1"
28 > echo "$1" > "$1"
29 > hg add "$1"
29 > hg add "$1"
30 > hg ci -m "$1"
30 > hg ci -m "$1"
31 > }
31 > }
32 $ getid() {
32 $ getid() {
33 > hg log --hidden -r "desc('$1')" -T '{node}\n'
33 > hg log --hidden -r "desc('$1')" -T '{node}\n'
34 > }
34 > }
35
35
36 setup repo
36 setup repo
37
37
38 $ hg init reference
38 $ hg init reference
39 $ cd reference
39 $ cd reference
40 $ mkcommit base
40 $ mkcommit base
41 $ mkcommit A_0
41 $ mkcommit A_0
42 $ hg up 0
42 $ hg up 0
43 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
43 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
44 $ mkcommit A_1
44 $ mkcommit A_1
45 created new head
45 created new head
46 $ hg up 0
46 $ hg up 0
47 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
47 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
48 $ mkcommit A_2
48 $ mkcommit A_2
49 created new head
49 created new head
50 $ hg up 0
50 $ hg up 0
51 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
51 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
52 $ cd ..
52 $ cd ..
53
53
54
54
55 $ newcase() {
55 $ newcase() {
56 > hg clone -u 0 -q reference $1
56 > hg clone -u 0 -q reference $1
57 > cd $1
57 > cd $1
58 > }
58 > }
59
59
60 direct divergence
60 direct divergence
61 -----------------
61 -----------------
62
62
63 A_1 have two direct and divergent successors A_1 and A_1
63 A_1 have two direct and divergent successors A_1 and A_1
64
64
65 $ newcase direct
65 $ newcase direct
66 $ hg debugobsolete `getid A_0` `getid A_1`
66 $ hg debugobsolete `getid A_0` `getid A_1`
67 1 new obsolescence markers
67 1 new obsolescence markers
68 obsoleted 1 changesets
68 obsoleted 1 changesets
69 $ hg debugobsolete `getid A_0` `getid A_2`
69 $ hg debugobsolete `getid A_0` `getid A_2`
70 1 new obsolescence markers
70 1 new obsolescence markers
71 2 new content-divergent changesets
71 2 new content-divergent changesets
72 $ hg log -G --hidden
72 $ hg log -G --hidden
73 * 3:392fd25390da A_2
73 * 3:392fd25390da A_2
74 |
74 |
75 | * 2:82623d38b9ba A_1
75 | * 2:82623d38b9ba A_1
76 |/
76 |/
77 | x 1:007dc284c1f8 A_0 [rewritten as 2:82623d38b9ba; rewritten as 3:392fd25390da]
77 | x 1:007dc284c1f8 A_0 [rewritten as 2:82623d38b9ba; rewritten as 3:392fd25390da]
78 |/
78 |/
79 @ 0:d20a80d4def3 base
79 @ 0:d20a80d4def3 base
80
80
81 $ hg debugsuccessorssets --hidden 'all()'
81 $ hg debugsuccessorssets --hidden 'all()'
82 d20a80d4def3
82 d20a80d4def3
83 d20a80d4def3
83 d20a80d4def3
84 007dc284c1f8
84 007dc284c1f8
85 82623d38b9ba
85 82623d38b9ba
86 392fd25390da
86 392fd25390da
87 82623d38b9ba
87 82623d38b9ba
88 82623d38b9ba
88 82623d38b9ba
89 392fd25390da
89 392fd25390da
90 392fd25390da
90 392fd25390da
91 $ hg log -r 'contentdivergent()'
91 $ hg log -r 'contentdivergent()'
92 2:82623d38b9ba A_1
92 2:82623d38b9ba A_1
93 3:392fd25390da A_2
93 3:392fd25390da A_2
94 $ hg log -r 'unstable()'
94 $ hg log -r 'unstable()'
95 2:82623d38b9ba A_1
95 2:82623d38b9ba A_1
96 3:392fd25390da A_2
96 3:392fd25390da A_2
97 $ hg debugsuccessorssets 'all()' --closest
97 $ hg debugsuccessorssets 'all()' --closest
98 d20a80d4def3
98 d20a80d4def3
99 d20a80d4def3
99 d20a80d4def3
100 82623d38b9ba
100 82623d38b9ba
101 82623d38b9ba
101 82623d38b9ba
102 392fd25390da
102 392fd25390da
103 392fd25390da
103 392fd25390da
104 $ hg debugsuccessorssets 'all()' --closest --hidden
104 $ hg debugsuccessorssets 'all()' --closest --hidden
105 d20a80d4def3
105 d20a80d4def3
106 d20a80d4def3
106 d20a80d4def3
107 007dc284c1f8
107 007dc284c1f8
108 82623d38b9ba
108 82623d38b9ba
109 392fd25390da
109 392fd25390da
110 82623d38b9ba
110 82623d38b9ba
111 82623d38b9ba
111 82623d38b9ba
112 392fd25390da
112 392fd25390da
113 392fd25390da
113 392fd25390da
114
114
115 check that mercurial refuse to push
115 check that mercurial refuse to push
116
116
117 $ hg init ../other
117 $ hg init ../other
118 $ hg push ../other
118 $ hg push ../other
119 pushing to ../other
119 pushing to ../other
120 searching for changes
120 searching for changes
121 abort: push includes unstable changesets:
121 abort: push includes content-divergent changeset: 392fd25390da!
122 82623d38b9ba (content-divergent)
123 392fd25390da (content-divergent)
124 [255]
122 [255]
125
123
126 $ cd ..
124 $ cd ..
127
125
128
126
129 indirect divergence with known changeset
127 indirect divergence with known changeset
130 -------------------------------------------
128 -------------------------------------------
131
129
132 $ newcase indirect_known
130 $ newcase indirect_known
133 $ hg debugobsolete `getid A_0` `getid A_1`
131 $ hg debugobsolete `getid A_0` `getid A_1`
134 1 new obsolescence markers
132 1 new obsolescence markers
135 obsoleted 1 changesets
133 obsoleted 1 changesets
136 $ hg debugobsolete `getid A_0` `getid A_2`
134 $ hg debugobsolete `getid A_0` `getid A_2`
137 1 new obsolescence markers
135 1 new obsolescence markers
138 2 new content-divergent changesets
136 2 new content-divergent changesets
139 $ mkcommit A_3
137 $ mkcommit A_3
140 created new head
138 created new head
141 $ hg debugobsolete `getid A_2` `getid A_3`
139 $ hg debugobsolete `getid A_2` `getid A_3`
142 1 new obsolescence markers
140 1 new obsolescence markers
143 obsoleted 1 changesets
141 obsoleted 1 changesets
144 $ hg log -G --hidden
142 $ hg log -G --hidden
145 @ 4:01f36c5a8fda A_3
143 @ 4:01f36c5a8fda A_3
146 |
144 |
147 | x 3:392fd25390da A_2 [rewritten as 4:01f36c5a8fda]
145 | x 3:392fd25390da A_2 [rewritten as 4:01f36c5a8fda]
148 |/
146 |/
149 | * 2:82623d38b9ba A_1
147 | * 2:82623d38b9ba A_1
150 |/
148 |/
151 | x 1:007dc284c1f8 A_0 [rewritten as 2:82623d38b9ba; rewritten as 3:392fd25390da]
149 | x 1:007dc284c1f8 A_0 [rewritten as 2:82623d38b9ba; rewritten as 3:392fd25390da]
152 |/
150 |/
153 o 0:d20a80d4def3 base
151 o 0:d20a80d4def3 base
154
152
155 $ hg debugsuccessorssets --hidden 'all()'
153 $ hg debugsuccessorssets --hidden 'all()'
156 d20a80d4def3
154 d20a80d4def3
157 d20a80d4def3
155 d20a80d4def3
158 007dc284c1f8
156 007dc284c1f8
159 82623d38b9ba
157 82623d38b9ba
160 01f36c5a8fda
158 01f36c5a8fda
161 82623d38b9ba
159 82623d38b9ba
162 82623d38b9ba
160 82623d38b9ba
163 392fd25390da
161 392fd25390da
164 01f36c5a8fda
162 01f36c5a8fda
165 01f36c5a8fda
163 01f36c5a8fda
166 01f36c5a8fda
164 01f36c5a8fda
167 $ hg log -r 'contentdivergent()'
165 $ hg log -r 'contentdivergent()'
168 2:82623d38b9ba A_1
166 2:82623d38b9ba A_1
169 4:01f36c5a8fda A_3
167 4:01f36c5a8fda A_3
170 $ hg debugsuccessorssets 'all()' --closest
168 $ hg debugsuccessorssets 'all()' --closest
171 d20a80d4def3
169 d20a80d4def3
172 d20a80d4def3
170 d20a80d4def3
173 82623d38b9ba
171 82623d38b9ba
174 82623d38b9ba
172 82623d38b9ba
175 01f36c5a8fda
173 01f36c5a8fda
176 01f36c5a8fda
174 01f36c5a8fda
177 $ hg debugsuccessorssets 'all()' --closest --hidden
175 $ hg debugsuccessorssets 'all()' --closest --hidden
178 d20a80d4def3
176 d20a80d4def3
179 d20a80d4def3
177 d20a80d4def3
180 007dc284c1f8
178 007dc284c1f8
181 82623d38b9ba
179 82623d38b9ba
182 392fd25390da
180 392fd25390da
183 82623d38b9ba
181 82623d38b9ba
184 82623d38b9ba
182 82623d38b9ba
185 392fd25390da
183 392fd25390da
186 392fd25390da
184 392fd25390da
187 01f36c5a8fda
185 01f36c5a8fda
188 01f36c5a8fda
186 01f36c5a8fda
189 $ cd ..
187 $ cd ..
190
188
191
189
192 indirect divergence with known changeset
190 indirect divergence with known changeset
193 -------------------------------------------
191 -------------------------------------------
194
192
195 $ newcase indirect_unknown
193 $ newcase indirect_unknown
196 $ hg debugobsolete `getid A_0` aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
194 $ hg debugobsolete `getid A_0` aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
197 1 new obsolescence markers
195 1 new obsolescence markers
198 obsoleted 1 changesets
196 obsoleted 1 changesets
199 $ hg debugobsolete aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa `getid A_1`
197 $ hg debugobsolete aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa `getid A_1`
200 1 new obsolescence markers
198 1 new obsolescence markers
201 $ hg debugobsolete `getid A_0` `getid A_2`
199 $ hg debugobsolete `getid A_0` `getid A_2`
202 1 new obsolescence markers
200 1 new obsolescence markers
203 2 new content-divergent changesets
201 2 new content-divergent changesets
204 $ hg log -G --hidden
202 $ hg log -G --hidden
205 * 3:392fd25390da A_2
203 * 3:392fd25390da A_2
206 |
204 |
207 | * 2:82623d38b9ba A_1
205 | * 2:82623d38b9ba A_1
208 |/
206 |/
209 | x 1:007dc284c1f8 A_0 [rewritten as 2:82623d38b9ba; rewritten as 3:392fd25390da]
207 | x 1:007dc284c1f8 A_0 [rewritten as 2:82623d38b9ba; rewritten as 3:392fd25390da]
210 |/
208 |/
211 @ 0:d20a80d4def3 base
209 @ 0:d20a80d4def3 base
212
210
213 $ hg debugsuccessorssets --hidden 'all()'
211 $ hg debugsuccessorssets --hidden 'all()'
214 d20a80d4def3
212 d20a80d4def3
215 d20a80d4def3
213 d20a80d4def3
216 007dc284c1f8
214 007dc284c1f8
217 82623d38b9ba
215 82623d38b9ba
218 392fd25390da
216 392fd25390da
219 82623d38b9ba
217 82623d38b9ba
220 82623d38b9ba
218 82623d38b9ba
221 392fd25390da
219 392fd25390da
222 392fd25390da
220 392fd25390da
223 $ hg log -r 'contentdivergent()'
221 $ hg log -r 'contentdivergent()'
224 2:82623d38b9ba A_1
222 2:82623d38b9ba A_1
225 3:392fd25390da A_2
223 3:392fd25390da A_2
226 $ hg debugsuccessorssets 'all()' --closest
224 $ hg debugsuccessorssets 'all()' --closest
227 d20a80d4def3
225 d20a80d4def3
228 d20a80d4def3
226 d20a80d4def3
229 82623d38b9ba
227 82623d38b9ba
230 82623d38b9ba
228 82623d38b9ba
231 392fd25390da
229 392fd25390da
232 392fd25390da
230 392fd25390da
233 $ hg debugsuccessorssets 'all()' --closest --hidden
231 $ hg debugsuccessorssets 'all()' --closest --hidden
234 d20a80d4def3
232 d20a80d4def3
235 d20a80d4def3
233 d20a80d4def3
236 007dc284c1f8
234 007dc284c1f8
237 82623d38b9ba
235 82623d38b9ba
238 392fd25390da
236 392fd25390da
239 82623d38b9ba
237 82623d38b9ba
240 82623d38b9ba
238 82623d38b9ba
241 392fd25390da
239 392fd25390da
242 392fd25390da
240 392fd25390da
243 $ cd ..
241 $ cd ..
244
242
245 do not take unknown node in account if they are final
243 do not take unknown node in account if they are final
246 -----------------------------------------------------
244 -----------------------------------------------------
247
245
248 $ newcase final-unknown
246 $ newcase final-unknown
249 $ hg debugobsolete `getid A_0` `getid A_1`
247 $ hg debugobsolete `getid A_0` `getid A_1`
250 1 new obsolescence markers
248 1 new obsolescence markers
251 obsoleted 1 changesets
249 obsoleted 1 changesets
252 $ hg debugobsolete `getid A_1` `getid A_2`
250 $ hg debugobsolete `getid A_1` `getid A_2`
253 1 new obsolescence markers
251 1 new obsolescence markers
254 obsoleted 1 changesets
252 obsoleted 1 changesets
255 $ hg debugobsolete `getid A_0` bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
253 $ hg debugobsolete `getid A_0` bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
256 1 new obsolescence markers
254 1 new obsolescence markers
257 $ hg debugobsolete bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb cccccccccccccccccccccccccccccccccccccccc
255 $ hg debugobsolete bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb cccccccccccccccccccccccccccccccccccccccc
258 1 new obsolescence markers
256 1 new obsolescence markers
259 $ hg debugobsolete `getid A_1` dddddddddddddddddddddddddddddddddddddddd
257 $ hg debugobsolete `getid A_1` dddddddddddddddddddddddddddddddddddddddd
260 1 new obsolescence markers
258 1 new obsolescence markers
261
259
262 $ hg debugsuccessorssets --hidden 'desc('A_0')'
260 $ hg debugsuccessorssets --hidden 'desc('A_0')'
263 007dc284c1f8
261 007dc284c1f8
264 392fd25390da
262 392fd25390da
265 $ hg debugsuccessorssets 'desc('A_0')' --closest
263 $ hg debugsuccessorssets 'desc('A_0')' --closest
266 $ hg debugsuccessorssets 'desc('A_0')' --closest --hidden
264 $ hg debugsuccessorssets 'desc('A_0')' --closest --hidden
267 007dc284c1f8
265 007dc284c1f8
268 82623d38b9ba
266 82623d38b9ba
269
267
270 $ cd ..
268 $ cd ..
271
269
272 divergence that converge again is not divergence anymore
270 divergence that converge again is not divergence anymore
273 -----------------------------------------------------
271 -----------------------------------------------------
274
272
275 $ newcase converged_divergence
273 $ newcase converged_divergence
276 $ hg debugobsolete `getid A_0` `getid A_1`
274 $ hg debugobsolete `getid A_0` `getid A_1`
277 1 new obsolescence markers
275 1 new obsolescence markers
278 obsoleted 1 changesets
276 obsoleted 1 changesets
279 $ hg debugobsolete `getid A_0` `getid A_2`
277 $ hg debugobsolete `getid A_0` `getid A_2`
280 1 new obsolescence markers
278 1 new obsolescence markers
281 2 new content-divergent changesets
279 2 new content-divergent changesets
282 $ mkcommit A_3
280 $ mkcommit A_3
283 created new head
281 created new head
284 $ hg debugobsolete `getid A_1` `getid A_3`
282 $ hg debugobsolete `getid A_1` `getid A_3`
285 1 new obsolescence markers
283 1 new obsolescence markers
286 obsoleted 1 changesets
284 obsoleted 1 changesets
287 $ hg debugobsolete `getid A_2` `getid A_3`
285 $ hg debugobsolete `getid A_2` `getid A_3`
288 1 new obsolescence markers
286 1 new obsolescence markers
289 obsoleted 1 changesets
287 obsoleted 1 changesets
290 $ hg log -G --hidden
288 $ hg log -G --hidden
291 @ 4:01f36c5a8fda A_3
289 @ 4:01f36c5a8fda A_3
292 |
290 |
293 | x 3:392fd25390da A_2 [rewritten as 4:01f36c5a8fda]
291 | x 3:392fd25390da A_2 [rewritten as 4:01f36c5a8fda]
294 |/
292 |/
295 | x 2:82623d38b9ba A_1 [rewritten as 4:01f36c5a8fda]
293 | x 2:82623d38b9ba A_1 [rewritten as 4:01f36c5a8fda]
296 |/
294 |/
297 | x 1:007dc284c1f8 A_0 [rewritten as 2:82623d38b9ba; rewritten as 3:392fd25390da]
295 | x 1:007dc284c1f8 A_0 [rewritten as 2:82623d38b9ba; rewritten as 3:392fd25390da]
298 |/
296 |/
299 o 0:d20a80d4def3 base
297 o 0:d20a80d4def3 base
300
298
301 $ hg debugsuccessorssets --hidden 'all()'
299 $ hg debugsuccessorssets --hidden 'all()'
302 d20a80d4def3
300 d20a80d4def3
303 d20a80d4def3
301 d20a80d4def3
304 007dc284c1f8
302 007dc284c1f8
305 01f36c5a8fda
303 01f36c5a8fda
306 82623d38b9ba
304 82623d38b9ba
307 01f36c5a8fda
305 01f36c5a8fda
308 392fd25390da
306 392fd25390da
309 01f36c5a8fda
307 01f36c5a8fda
310 01f36c5a8fda
308 01f36c5a8fda
311 01f36c5a8fda
309 01f36c5a8fda
312 $ hg log -r 'contentdivergent()'
310 $ hg log -r 'contentdivergent()'
313 $ hg debugsuccessorssets 'all()' --closest
311 $ hg debugsuccessorssets 'all()' --closest
314 d20a80d4def3
312 d20a80d4def3
315 d20a80d4def3
313 d20a80d4def3
316 01f36c5a8fda
314 01f36c5a8fda
317 01f36c5a8fda
315 01f36c5a8fda
318 $ hg debugsuccessorssets 'all()' --closest --hidden
316 $ hg debugsuccessorssets 'all()' --closest --hidden
319 d20a80d4def3
317 d20a80d4def3
320 d20a80d4def3
318 d20a80d4def3
321 007dc284c1f8
319 007dc284c1f8
322 82623d38b9ba
320 82623d38b9ba
323 392fd25390da
321 392fd25390da
324 82623d38b9ba
322 82623d38b9ba
325 82623d38b9ba
323 82623d38b9ba
326 392fd25390da
324 392fd25390da
327 392fd25390da
325 392fd25390da
328 01f36c5a8fda
326 01f36c5a8fda
329 01f36c5a8fda
327 01f36c5a8fda
330 $ cd ..
328 $ cd ..
331
329
332 split is not divergences
330 split is not divergences
333 -----------------------------
331 -----------------------------
334
332
335 $ newcase split
333 $ newcase split
336 $ hg debugobsolete `getid A_0` `getid A_1` `getid A_2`
334 $ hg debugobsolete `getid A_0` `getid A_1` `getid A_2`
337 1 new obsolescence markers
335 1 new obsolescence markers
338 obsoleted 1 changesets
336 obsoleted 1 changesets
339 $ hg log -G --hidden
337 $ hg log -G --hidden
340 o 3:392fd25390da A_2
338 o 3:392fd25390da A_2
341 |
339 |
342 | o 2:82623d38b9ba A_1
340 | o 2:82623d38b9ba A_1
343 |/
341 |/
344 | x 1:007dc284c1f8 A_0 [split as 2:82623d38b9ba, 3:392fd25390da]
342 | x 1:007dc284c1f8 A_0 [split as 2:82623d38b9ba, 3:392fd25390da]
345 |/
343 |/
346 @ 0:d20a80d4def3 base
344 @ 0:d20a80d4def3 base
347
345
348 $ hg debugsuccessorssets --hidden 'all()'
346 $ hg debugsuccessorssets --hidden 'all()'
349 d20a80d4def3
347 d20a80d4def3
350 d20a80d4def3
348 d20a80d4def3
351 007dc284c1f8
349 007dc284c1f8
352 82623d38b9ba 392fd25390da
350 82623d38b9ba 392fd25390da
353 82623d38b9ba
351 82623d38b9ba
354 82623d38b9ba
352 82623d38b9ba
355 392fd25390da
353 392fd25390da
356 392fd25390da
354 392fd25390da
357 $ hg log -r 'contentdivergent()'
355 $ hg log -r 'contentdivergent()'
358 $ hg debugsuccessorssets 'all()' --closest
356 $ hg debugsuccessorssets 'all()' --closest
359 d20a80d4def3
357 d20a80d4def3
360 d20a80d4def3
358 d20a80d4def3
361 82623d38b9ba
359 82623d38b9ba
362 82623d38b9ba
360 82623d38b9ba
363 392fd25390da
361 392fd25390da
364 392fd25390da
362 392fd25390da
365 $ hg debugsuccessorssets 'all()' --closest --hidden
363 $ hg debugsuccessorssets 'all()' --closest --hidden
366 d20a80d4def3
364 d20a80d4def3
367 d20a80d4def3
365 d20a80d4def3
368 007dc284c1f8
366 007dc284c1f8
369 82623d38b9ba 392fd25390da
367 82623d38b9ba 392fd25390da
370 82623d38b9ba
368 82623d38b9ba
371 82623d38b9ba
369 82623d38b9ba
372 392fd25390da
370 392fd25390da
373 392fd25390da
371 392fd25390da
374
372
375 Even when subsequent rewriting happen
373 Even when subsequent rewriting happen
376
374
377 $ mkcommit A_3
375 $ mkcommit A_3
378 created new head
376 created new head
379 $ hg debugobsolete `getid A_1` `getid A_3`
377 $ hg debugobsolete `getid A_1` `getid A_3`
380 1 new obsolescence markers
378 1 new obsolescence markers
381 obsoleted 1 changesets
379 obsoleted 1 changesets
382 $ hg up 0
380 $ hg up 0
383 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
381 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
384 $ mkcommit A_4
382 $ mkcommit A_4
385 created new head
383 created new head
386 $ hg debugobsolete `getid A_2` `getid A_4`
384 $ hg debugobsolete `getid A_2` `getid A_4`
387 1 new obsolescence markers
385 1 new obsolescence markers
388 obsoleted 1 changesets
386 obsoleted 1 changesets
389 $ hg up 0
387 $ hg up 0
390 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
388 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
391 $ mkcommit A_5
389 $ mkcommit A_5
392 created new head
390 created new head
393 $ hg debugobsolete `getid A_4` `getid A_5`
391 $ hg debugobsolete `getid A_4` `getid A_5`
394 1 new obsolescence markers
392 1 new obsolescence markers
395 obsoleted 1 changesets
393 obsoleted 1 changesets
396 $ hg log -G --hidden
394 $ hg log -G --hidden
397 @ 6:e442cfc57690 A_5
395 @ 6:e442cfc57690 A_5
398 |
396 |
399 | x 5:6a411f0d7a0a A_4 [rewritten as 6:e442cfc57690]
397 | x 5:6a411f0d7a0a A_4 [rewritten as 6:e442cfc57690]
400 |/
398 |/
401 | o 4:01f36c5a8fda A_3
399 | o 4:01f36c5a8fda A_3
402 |/
400 |/
403 | x 3:392fd25390da A_2 [rewritten as 5:6a411f0d7a0a]
401 | x 3:392fd25390da A_2 [rewritten as 5:6a411f0d7a0a]
404 |/
402 |/
405 | x 2:82623d38b9ba A_1 [rewritten as 4:01f36c5a8fda]
403 | x 2:82623d38b9ba A_1 [rewritten as 4:01f36c5a8fda]
406 |/
404 |/
407 | x 1:007dc284c1f8 A_0 [split as 2:82623d38b9ba, 3:392fd25390da]
405 | x 1:007dc284c1f8 A_0 [split as 2:82623d38b9ba, 3:392fd25390da]
408 |/
406 |/
409 o 0:d20a80d4def3 base
407 o 0:d20a80d4def3 base
410
408
411 $ hg debugsuccessorssets --hidden 'all()'
409 $ hg debugsuccessorssets --hidden 'all()'
412 d20a80d4def3
410 d20a80d4def3
413 d20a80d4def3
411 d20a80d4def3
414 007dc284c1f8
412 007dc284c1f8
415 01f36c5a8fda e442cfc57690
413 01f36c5a8fda e442cfc57690
416 82623d38b9ba
414 82623d38b9ba
417 01f36c5a8fda
415 01f36c5a8fda
418 392fd25390da
416 392fd25390da
419 e442cfc57690
417 e442cfc57690
420 01f36c5a8fda
418 01f36c5a8fda
421 01f36c5a8fda
419 01f36c5a8fda
422 6a411f0d7a0a
420 6a411f0d7a0a
423 e442cfc57690
421 e442cfc57690
424 e442cfc57690
422 e442cfc57690
425 e442cfc57690
423 e442cfc57690
426 $ hg debugsuccessorssets 'all()' --closest
424 $ hg debugsuccessorssets 'all()' --closest
427 d20a80d4def3
425 d20a80d4def3
428 d20a80d4def3
426 d20a80d4def3
429 01f36c5a8fda
427 01f36c5a8fda
430 01f36c5a8fda
428 01f36c5a8fda
431 e442cfc57690
429 e442cfc57690
432 e442cfc57690
430 e442cfc57690
433 $ hg debugsuccessorssets 'all()' --closest --hidden
431 $ hg debugsuccessorssets 'all()' --closest --hidden
434 d20a80d4def3
432 d20a80d4def3
435 d20a80d4def3
433 d20a80d4def3
436 007dc284c1f8
434 007dc284c1f8
437 82623d38b9ba 392fd25390da
435 82623d38b9ba 392fd25390da
438 82623d38b9ba
436 82623d38b9ba
439 82623d38b9ba
437 82623d38b9ba
440 392fd25390da
438 392fd25390da
441 392fd25390da
439 392fd25390da
442 01f36c5a8fda
440 01f36c5a8fda
443 01f36c5a8fda
441 01f36c5a8fda
444 6a411f0d7a0a
442 6a411f0d7a0a
445 e442cfc57690
443 e442cfc57690
446 e442cfc57690
444 e442cfc57690
447 e442cfc57690
445 e442cfc57690
448 $ hg log -r 'contentdivergent()'
446 $ hg log -r 'contentdivergent()'
449
447
450 Check more complex obsolescence graft (with divergence)
448 Check more complex obsolescence graft (with divergence)
451
449
452 $ mkcommit B_0; hg up 0
450 $ mkcommit B_0; hg up 0
453 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
451 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
454 $ hg debugobsolete `getid B_0` `getid A_2`
452 $ hg debugobsolete `getid B_0` `getid A_2`
455 1 new obsolescence markers
453 1 new obsolescence markers
456 obsoleted 1 changesets
454 obsoleted 1 changesets
457 $ mkcommit A_7; hg up 0
455 $ mkcommit A_7; hg up 0
458 created new head
456 created new head
459 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
457 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
460 $ mkcommit A_8; hg up 0
458 $ mkcommit A_8; hg up 0
461 created new head
459 created new head
462 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
460 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
463 $ hg debugobsolete `getid A_5` `getid A_7` `getid A_8`
461 $ hg debugobsolete `getid A_5` `getid A_7` `getid A_8`
464 1 new obsolescence markers
462 1 new obsolescence markers
465 obsoleted 1 changesets
463 obsoleted 1 changesets
466 $ mkcommit A_9; hg up 0
464 $ mkcommit A_9; hg up 0
467 created new head
465 created new head
468 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
466 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
469 $ hg debugobsolete `getid A_5` `getid A_9`
467 $ hg debugobsolete `getid A_5` `getid A_9`
470 1 new obsolescence markers
468 1 new obsolescence markers
471 4 new content-divergent changesets
469 4 new content-divergent changesets
472 $ hg log -G --hidden
470 $ hg log -G --hidden
473 * 10:bed64f5d2f5a A_9
471 * 10:bed64f5d2f5a A_9
474 |
472 |
475 | * 9:14608b260df8 A_8
473 | * 9:14608b260df8 A_8
476 |/
474 |/
477 | * 8:7ae126973a96 A_7
475 | * 8:7ae126973a96 A_7
478 |/
476 |/
479 | x 7:3750ebee865d B_0 [rewritten as 3:392fd25390da]
477 | x 7:3750ebee865d B_0 [rewritten as 3:392fd25390da]
480 | |
478 | |
481 | x 6:e442cfc57690 A_5 [rewritten as 10:bed64f5d2f5a; split as 8:7ae126973a96, 9:14608b260df8]
479 | x 6:e442cfc57690 A_5 [rewritten as 10:bed64f5d2f5a; split as 8:7ae126973a96, 9:14608b260df8]
482 |/
480 |/
483 | x 5:6a411f0d7a0a A_4 [rewritten as 6:e442cfc57690]
481 | x 5:6a411f0d7a0a A_4 [rewritten as 6:e442cfc57690]
484 |/
482 |/
485 | * 4:01f36c5a8fda A_3
483 | * 4:01f36c5a8fda A_3
486 |/
484 |/
487 | x 3:392fd25390da A_2 [rewritten as 5:6a411f0d7a0a]
485 | x 3:392fd25390da A_2 [rewritten as 5:6a411f0d7a0a]
488 |/
486 |/
489 | x 2:82623d38b9ba A_1 [rewritten as 4:01f36c5a8fda]
487 | x 2:82623d38b9ba A_1 [rewritten as 4:01f36c5a8fda]
490 |/
488 |/
491 | x 1:007dc284c1f8 A_0 [split as 2:82623d38b9ba, 3:392fd25390da]
489 | x 1:007dc284c1f8 A_0 [split as 2:82623d38b9ba, 3:392fd25390da]
492 |/
490 |/
493 @ 0:d20a80d4def3 base
491 @ 0:d20a80d4def3 base
494
492
495 $ hg debugsuccessorssets --hidden 'all()'
493 $ hg debugsuccessorssets --hidden 'all()'
496 d20a80d4def3
494 d20a80d4def3
497 d20a80d4def3
495 d20a80d4def3
498 007dc284c1f8
496 007dc284c1f8
499 01f36c5a8fda bed64f5d2f5a
497 01f36c5a8fda bed64f5d2f5a
500 01f36c5a8fda 7ae126973a96 14608b260df8
498 01f36c5a8fda 7ae126973a96 14608b260df8
501 82623d38b9ba
499 82623d38b9ba
502 01f36c5a8fda
500 01f36c5a8fda
503 392fd25390da
501 392fd25390da
504 bed64f5d2f5a
502 bed64f5d2f5a
505 7ae126973a96 14608b260df8
503 7ae126973a96 14608b260df8
506 01f36c5a8fda
504 01f36c5a8fda
507 01f36c5a8fda
505 01f36c5a8fda
508 6a411f0d7a0a
506 6a411f0d7a0a
509 bed64f5d2f5a
507 bed64f5d2f5a
510 7ae126973a96 14608b260df8
508 7ae126973a96 14608b260df8
511 e442cfc57690
509 e442cfc57690
512 bed64f5d2f5a
510 bed64f5d2f5a
513 7ae126973a96 14608b260df8
511 7ae126973a96 14608b260df8
514 3750ebee865d
512 3750ebee865d
515 bed64f5d2f5a
513 bed64f5d2f5a
516 7ae126973a96 14608b260df8
514 7ae126973a96 14608b260df8
517 7ae126973a96
515 7ae126973a96
518 7ae126973a96
516 7ae126973a96
519 14608b260df8
517 14608b260df8
520 14608b260df8
518 14608b260df8
521 bed64f5d2f5a
519 bed64f5d2f5a
522 bed64f5d2f5a
520 bed64f5d2f5a
523 $ hg debugsuccessorssets 'all()' --closest
521 $ hg debugsuccessorssets 'all()' --closest
524 d20a80d4def3
522 d20a80d4def3
525 d20a80d4def3
523 d20a80d4def3
526 01f36c5a8fda
524 01f36c5a8fda
527 01f36c5a8fda
525 01f36c5a8fda
528 7ae126973a96
526 7ae126973a96
529 7ae126973a96
527 7ae126973a96
530 14608b260df8
528 14608b260df8
531 14608b260df8
529 14608b260df8
532 bed64f5d2f5a
530 bed64f5d2f5a
533 bed64f5d2f5a
531 bed64f5d2f5a
534 $ hg debugsuccessorssets 'all()' --closest --hidden
532 $ hg debugsuccessorssets 'all()' --closest --hidden
535 d20a80d4def3
533 d20a80d4def3
536 d20a80d4def3
534 d20a80d4def3
537 007dc284c1f8
535 007dc284c1f8
538 82623d38b9ba 392fd25390da
536 82623d38b9ba 392fd25390da
539 82623d38b9ba
537 82623d38b9ba
540 82623d38b9ba
538 82623d38b9ba
541 392fd25390da
539 392fd25390da
542 392fd25390da
540 392fd25390da
543 01f36c5a8fda
541 01f36c5a8fda
544 01f36c5a8fda
542 01f36c5a8fda
545 6a411f0d7a0a
543 6a411f0d7a0a
546 e442cfc57690
544 e442cfc57690
547 e442cfc57690
545 e442cfc57690
548 e442cfc57690
546 e442cfc57690
549 3750ebee865d
547 3750ebee865d
550 392fd25390da
548 392fd25390da
551 7ae126973a96
549 7ae126973a96
552 7ae126973a96
550 7ae126973a96
553 14608b260df8
551 14608b260df8
554 14608b260df8
552 14608b260df8
555 bed64f5d2f5a
553 bed64f5d2f5a
556 bed64f5d2f5a
554 bed64f5d2f5a
557 $ hg log -r 'contentdivergent()'
555 $ hg log -r 'contentdivergent()'
558 4:01f36c5a8fda A_3
556 4:01f36c5a8fda A_3
559 8:7ae126973a96 A_7
557 8:7ae126973a96 A_7
560 9:14608b260df8 A_8
558 9:14608b260df8 A_8
561 10:bed64f5d2f5a A_9
559 10:bed64f5d2f5a A_9
562
560
563 $ hg log -r bed64f5d2f5a -T '{whyunstable}\n' | sort
561 $ hg log -r bed64f5d2f5a -T '{whyunstable}\n' | sort
564 content-divergent: 4:01f36c5a8fda (draft) 8:7ae126973a96 (draft) 9:14608b260df8 (draft) predecessor 007dc284c1f8
562 content-divergent: 4:01f36c5a8fda (draft) 8:7ae126973a96 (draft) 9:14608b260df8 (draft) predecessor 007dc284c1f8
565 content-divergent: 8:7ae126973a96 (draft) 9:14608b260df8 (draft) predecessor e442cfc57690
563 content-divergent: 8:7ae126973a96 (draft) 9:14608b260df8 (draft) predecessor e442cfc57690
566 $ hg log -r bed64f5d2f5a -T whyunstableshort | sort
564 $ hg log -r bed64f5d2f5a -T whyunstableshort | sort
567 content-divergent: 4:01f36c5a8fda (draft) 8:7ae126973a96 (draft) 9:14608b260df8 (draft) predecessor 007d
565 content-divergent: 4:01f36c5a8fda (draft) 8:7ae126973a96 (draft) 9:14608b260df8 (draft) predecessor 007d
568 content-divergent: 8:7ae126973a96 (draft) 9:14608b260df8 (draft) predecessor e442
566 content-divergent: 8:7ae126973a96 (draft) 9:14608b260df8 (draft) predecessor e442
569 $ hg log -r bed64f5d2f5a -T whyunstableshorter | sort
567 $ hg log -r bed64f5d2f5a -T whyunstableshorter | sort
570 content-divergent: 01f3 (draft) 7ae1 (draft) 1460 (draft) predecessor 007d
568 content-divergent: 01f3 (draft) 7ae1 (draft) 1460 (draft) predecessor 007d
571 content-divergent: 7ae1 (draft) 1460 (draft) predecessor e442
569 content-divergent: 7ae1 (draft) 1460 (draft) predecessor e442
572
570
573 fix the divergence
571 fix the divergence
574
572
575 $ mkcommit A_A; hg up 0
573 $ mkcommit A_A; hg up 0
576 created new head
574 created new head
577 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
575 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
578 $ hg debugobsolete `getid A_9` `getid A_A`
576 $ hg debugobsolete `getid A_9` `getid A_A`
579 1 new obsolescence markers
577 1 new obsolescence markers
580 obsoleted 1 changesets
578 obsoleted 1 changesets
581 $ hg debugobsolete `getid A_7` `getid A_A`
579 $ hg debugobsolete `getid A_7` `getid A_A`
582 1 new obsolescence markers
580 1 new obsolescence markers
583 obsoleted 1 changesets
581 obsoleted 1 changesets
584 $ hg debugobsolete `getid A_8` `getid A_A`
582 $ hg debugobsolete `getid A_8` `getid A_A`
585 1 new obsolescence markers
583 1 new obsolescence markers
586 obsoleted 1 changesets
584 obsoleted 1 changesets
587 $ hg log -G --hidden
585 $ hg log -G --hidden
588 o 11:a139f71be9da A_A
586 o 11:a139f71be9da A_A
589 |
587 |
590 | x 10:bed64f5d2f5a A_9 [rewritten as 11:a139f71be9da]
588 | x 10:bed64f5d2f5a A_9 [rewritten as 11:a139f71be9da]
591 |/
589 |/
592 | x 9:14608b260df8 A_8 [rewritten as 11:a139f71be9da]
590 | x 9:14608b260df8 A_8 [rewritten as 11:a139f71be9da]
593 |/
591 |/
594 | x 8:7ae126973a96 A_7 [rewritten as 11:a139f71be9da]
592 | x 8:7ae126973a96 A_7 [rewritten as 11:a139f71be9da]
595 |/
593 |/
596 | x 7:3750ebee865d B_0 [rewritten as 3:392fd25390da]
594 | x 7:3750ebee865d B_0 [rewritten as 3:392fd25390da]
597 | |
595 | |
598 | x 6:e442cfc57690 A_5 [rewritten as 10:bed64f5d2f5a; split as 8:7ae126973a96, 9:14608b260df8]
596 | x 6:e442cfc57690 A_5 [rewritten as 10:bed64f5d2f5a; split as 8:7ae126973a96, 9:14608b260df8]
599 |/
597 |/
600 | x 5:6a411f0d7a0a A_4 [rewritten as 6:e442cfc57690]
598 | x 5:6a411f0d7a0a A_4 [rewritten as 6:e442cfc57690]
601 |/
599 |/
602 | o 4:01f36c5a8fda A_3
600 | o 4:01f36c5a8fda A_3
603 |/
601 |/
604 | x 3:392fd25390da A_2 [rewritten as 5:6a411f0d7a0a]
602 | x 3:392fd25390da A_2 [rewritten as 5:6a411f0d7a0a]
605 |/
603 |/
606 | x 2:82623d38b9ba A_1 [rewritten as 4:01f36c5a8fda]
604 | x 2:82623d38b9ba A_1 [rewritten as 4:01f36c5a8fda]
607 |/
605 |/
608 | x 1:007dc284c1f8 A_0 [split as 2:82623d38b9ba, 3:392fd25390da]
606 | x 1:007dc284c1f8 A_0 [split as 2:82623d38b9ba, 3:392fd25390da]
609 |/
607 |/
610 @ 0:d20a80d4def3 base
608 @ 0:d20a80d4def3 base
611
609
612 $ hg debugsuccessorssets --hidden 'all()'
610 $ hg debugsuccessorssets --hidden 'all()'
613 d20a80d4def3
611 d20a80d4def3
614 d20a80d4def3
612 d20a80d4def3
615 007dc284c1f8
613 007dc284c1f8
616 01f36c5a8fda a139f71be9da
614 01f36c5a8fda a139f71be9da
617 82623d38b9ba
615 82623d38b9ba
618 01f36c5a8fda
616 01f36c5a8fda
619 392fd25390da
617 392fd25390da
620 a139f71be9da
618 a139f71be9da
621 01f36c5a8fda
619 01f36c5a8fda
622 01f36c5a8fda
620 01f36c5a8fda
623 6a411f0d7a0a
621 6a411f0d7a0a
624 a139f71be9da
622 a139f71be9da
625 e442cfc57690
623 e442cfc57690
626 a139f71be9da
624 a139f71be9da
627 3750ebee865d
625 3750ebee865d
628 a139f71be9da
626 a139f71be9da
629 7ae126973a96
627 7ae126973a96
630 a139f71be9da
628 a139f71be9da
631 14608b260df8
629 14608b260df8
632 a139f71be9da
630 a139f71be9da
633 bed64f5d2f5a
631 bed64f5d2f5a
634 a139f71be9da
632 a139f71be9da
635 a139f71be9da
633 a139f71be9da
636 a139f71be9da
634 a139f71be9da
637 $ hg debugsuccessorssets 'all()' --closest
635 $ hg debugsuccessorssets 'all()' --closest
638 d20a80d4def3
636 d20a80d4def3
639 d20a80d4def3
637 d20a80d4def3
640 01f36c5a8fda
638 01f36c5a8fda
641 01f36c5a8fda
639 01f36c5a8fda
642 a139f71be9da
640 a139f71be9da
643 a139f71be9da
641 a139f71be9da
644 $ hg debugsuccessorssets 'all()' --closest --hidden
642 $ hg debugsuccessorssets 'all()' --closest --hidden
645 d20a80d4def3
643 d20a80d4def3
646 d20a80d4def3
644 d20a80d4def3
647 007dc284c1f8
645 007dc284c1f8
648 82623d38b9ba 392fd25390da
646 82623d38b9ba 392fd25390da
649 82623d38b9ba
647 82623d38b9ba
650 82623d38b9ba
648 82623d38b9ba
651 392fd25390da
649 392fd25390da
652 392fd25390da
650 392fd25390da
653 01f36c5a8fda
651 01f36c5a8fda
654 01f36c5a8fda
652 01f36c5a8fda
655 6a411f0d7a0a
653 6a411f0d7a0a
656 e442cfc57690
654 e442cfc57690
657 e442cfc57690
655 e442cfc57690
658 e442cfc57690
656 e442cfc57690
659 3750ebee865d
657 3750ebee865d
660 392fd25390da
658 392fd25390da
661 7ae126973a96
659 7ae126973a96
662 a139f71be9da
660 a139f71be9da
663 14608b260df8
661 14608b260df8
664 a139f71be9da
662 a139f71be9da
665 bed64f5d2f5a
663 bed64f5d2f5a
666 a139f71be9da
664 a139f71be9da
667 a139f71be9da
665 a139f71be9da
668 a139f71be9da
666 a139f71be9da
669 $ hg log -r 'contentdivergent()'
667 $ hg log -r 'contentdivergent()'
670
668
671 #if serve
669 #if serve
672
670
673 $ hg serve -n test -p $HGPORT -d --pid-file=hg.pid --config web.view=all \
671 $ hg serve -n test -p $HGPORT -d --pid-file=hg.pid --config web.view=all \
674 > -A access.log -E errors.log
672 > -A access.log -E errors.log
675 $ cat hg.pid >> $DAEMON_PIDS
673 $ cat hg.pid >> $DAEMON_PIDS
676
674
677 check an obsolete changeset that was rewritten and also split
675 check an obsolete changeset that was rewritten and also split
678
676
679 $ get-with-headers.py localhost:$HGPORT 'rev/e442cfc57690?style=paper' | egrep 'rewritten|split'
677 $ get-with-headers.py localhost:$HGPORT 'rev/e442cfc57690?style=paper' | egrep 'rewritten|split'
680 <td>rewritten as <a href="/rev/bed64f5d2f5a?style=paper">bed64f5d2f5a</a> by &#116;&#101;&#115;&#116; <span class="age">Thu, 01 Jan 1970 00:00:00 +0000</span><br>
678 <td>rewritten as <a href="/rev/bed64f5d2f5a?style=paper">bed64f5d2f5a</a> by &#116;&#101;&#115;&#116; <span class="age">Thu, 01 Jan 1970 00:00:00 +0000</span><br>
681 split as <a href="/rev/7ae126973a96?style=paper">7ae126973a96</a> <a href="/rev/14608b260df8?style=paper">14608b260df8</a> by &#116;&#101;&#115;&#116; <span class="age">Thu, 01 Jan 1970 00:00:00 +0000</span></td>
679 split as <a href="/rev/7ae126973a96?style=paper">7ae126973a96</a> <a href="/rev/14608b260df8?style=paper">14608b260df8</a> by &#116;&#101;&#115;&#116; <span class="age">Thu, 01 Jan 1970 00:00:00 +0000</span></td>
682 $ get-with-headers.py localhost:$HGPORT 'rev/e442cfc57690?style=coal' | egrep 'rewritten|split'
680 $ get-with-headers.py localhost:$HGPORT 'rev/e442cfc57690?style=coal' | egrep 'rewritten|split'
683 <td>rewritten as <a href="/rev/bed64f5d2f5a?style=coal">bed64f5d2f5a</a> by &#116;&#101;&#115;&#116; <span class="age">Thu, 01 Jan 1970 00:00:00 +0000</span><br>
681 <td>rewritten as <a href="/rev/bed64f5d2f5a?style=coal">bed64f5d2f5a</a> by &#116;&#101;&#115;&#116; <span class="age">Thu, 01 Jan 1970 00:00:00 +0000</span><br>
684 split as <a href="/rev/7ae126973a96?style=coal">7ae126973a96</a> <a href="/rev/14608b260df8?style=coal">14608b260df8</a> by &#116;&#101;&#115;&#116; <span class="age">Thu, 01 Jan 1970 00:00:00 +0000</span></td>
682 split as <a href="/rev/7ae126973a96?style=coal">7ae126973a96</a> <a href="/rev/14608b260df8?style=coal">14608b260df8</a> by &#116;&#101;&#115;&#116; <span class="age">Thu, 01 Jan 1970 00:00:00 +0000</span></td>
685 $ get-with-headers.py localhost:$HGPORT 'rev/e442cfc57690?style=gitweb' | egrep 'rewritten|split'
683 $ get-with-headers.py localhost:$HGPORT 'rev/e442cfc57690?style=gitweb' | egrep 'rewritten|split'
686 <td>rewritten as <a class="list" href="/rev/bed64f5d2f5a?style=gitweb">bed64f5d2f5a</a> by &#116;&#101;&#115;&#116; <span class="age">Thu, 01 Jan 1970 00:00:00 +0000</span></td>
684 <td>rewritten as <a class="list" href="/rev/bed64f5d2f5a?style=gitweb">bed64f5d2f5a</a> by &#116;&#101;&#115;&#116; <span class="age">Thu, 01 Jan 1970 00:00:00 +0000</span></td>
687 <td>split as <a class="list" href="/rev/7ae126973a96?style=gitweb">7ae126973a96</a> <a class="list" href="/rev/14608b260df8?style=gitweb">14608b260df8</a> by &#116;&#101;&#115;&#116; <span class="age">Thu, 01 Jan 1970 00:00:00 +0000</span></td>
685 <td>split as <a class="list" href="/rev/7ae126973a96?style=gitweb">7ae126973a96</a> <a class="list" href="/rev/14608b260df8?style=gitweb">14608b260df8</a> by &#116;&#101;&#115;&#116; <span class="age">Thu, 01 Jan 1970 00:00:00 +0000</span></td>
688 $ get-with-headers.py localhost:$HGPORT 'rev/e442cfc57690?style=monoblue' | egrep 'rewritten|split'
686 $ get-with-headers.py localhost:$HGPORT 'rev/e442cfc57690?style=monoblue' | egrep 'rewritten|split'
689 <dd>rewritten as <a href="/rev/bed64f5d2f5a?style=monoblue">bed64f5d2f5a</a> by &#116;&#101;&#115;&#116; <span class="age">Thu, 01 Jan 1970 00:00:00 +0000</span></dd>
687 <dd>rewritten as <a href="/rev/bed64f5d2f5a?style=monoblue">bed64f5d2f5a</a> by &#116;&#101;&#115;&#116; <span class="age">Thu, 01 Jan 1970 00:00:00 +0000</span></dd>
690 <dd>split as <a href="/rev/7ae126973a96?style=monoblue">7ae126973a96</a> <a href="/rev/14608b260df8?style=monoblue">14608b260df8</a> by &#116;&#101;&#115;&#116; <span class="age">Thu, 01 Jan 1970 00:00:00 +0000</span></dd>
688 <dd>split as <a href="/rev/7ae126973a96?style=monoblue">7ae126973a96</a> <a href="/rev/14608b260df8?style=monoblue">14608b260df8</a> by &#116;&#101;&#115;&#116; <span class="age">Thu, 01 Jan 1970 00:00:00 +0000</span></dd>
691 $ get-with-headers.py localhost:$HGPORT 'rev/e442cfc57690?style=spartan' | egrep 'rewritten|split'
689 $ get-with-headers.py localhost:$HGPORT 'rev/e442cfc57690?style=spartan' | egrep 'rewritten|split'
692 <td class="obsolete">rewritten as <a href="/rev/bed64f5d2f5a?style=spartan">bed64f5d2f5a</a> by &#116;&#101;&#115;&#116; <span class="age">Thu, 01 Jan 1970 00:00:00 +0000</span></td>
690 <td class="obsolete">rewritten as <a href="/rev/bed64f5d2f5a?style=spartan">bed64f5d2f5a</a> by &#116;&#101;&#115;&#116; <span class="age">Thu, 01 Jan 1970 00:00:00 +0000</span></td>
693 <td class="obsolete">split as <a href="/rev/7ae126973a96?style=spartan">7ae126973a96</a> <a href="/rev/14608b260df8?style=spartan">14608b260df8</a> by &#116;&#101;&#115;&#116; <span class="age">Thu, 01 Jan 1970 00:00:00 +0000</span></td>
691 <td class="obsolete">split as <a href="/rev/7ae126973a96?style=spartan">7ae126973a96</a> <a href="/rev/14608b260df8?style=spartan">14608b260df8</a> by &#116;&#101;&#115;&#116; <span class="age">Thu, 01 Jan 1970 00:00:00 +0000</span></td>
694
692
695 $ killdaemons.py
693 $ killdaemons.py
696
694
697 #endif
695 #endif
698
696
699 $ cd ..
697 $ cd ..
700
698
701
699
702 Subset does not diverge
700 Subset does not diverge
703 ------------------------------
701 ------------------------------
704
702
705 Do not report divergent successors-set if it is a subset of another
703 Do not report divergent successors-set if it is a subset of another
706 successors-set. (report [A,B] not [A] + [A,B])
704 successors-set. (report [A,B] not [A] + [A,B])
707
705
708 $ newcase subset
706 $ newcase subset
709 $ hg debugobsolete `getid A_0` `getid A_2`
707 $ hg debugobsolete `getid A_0` `getid A_2`
710 1 new obsolescence markers
708 1 new obsolescence markers
711 obsoleted 1 changesets
709 obsoleted 1 changesets
712 $ hg debugobsolete `getid A_0` `getid A_1` `getid A_2`
710 $ hg debugobsolete `getid A_0` `getid A_1` `getid A_2`
713 1 new obsolescence markers
711 1 new obsolescence markers
714 $ hg debugsuccessorssets --hidden 'desc('A_0')'
712 $ hg debugsuccessorssets --hidden 'desc('A_0')'
715 007dc284c1f8
713 007dc284c1f8
716 82623d38b9ba 392fd25390da
714 82623d38b9ba 392fd25390da
717 $ hg debugsuccessorssets 'desc('A_0')' --closest
715 $ hg debugsuccessorssets 'desc('A_0')' --closest
718 $ hg debugsuccessorssets 'desc('A_0')' --closest --hidden
716 $ hg debugsuccessorssets 'desc('A_0')' --closest --hidden
719 007dc284c1f8
717 007dc284c1f8
720 82623d38b9ba 392fd25390da
718 82623d38b9ba 392fd25390da
721
719
722 $ cd ..
720 $ cd ..
723
721
724 Use scmutil.cleanupnodes API to create divergence
722 Use scmutil.cleanupnodes API to create divergence
725
723
726 $ hg init cleanupnodes
724 $ hg init cleanupnodes
727 $ cd cleanupnodes
725 $ cd cleanupnodes
728 $ hg debugdrawdag <<'EOS'
726 $ hg debugdrawdag <<'EOS'
729 > B1 B3 B4
727 > B1 B3 B4
730 > | \|
728 > | \|
731 > A Z
729 > A Z
732 > EOS
730 > EOS
733
731
734 $ hg update -q B1
732 $ hg update -q B1
735 $ echo 3 >> B
733 $ echo 3 >> B
736 $ hg commit --amend -m B2
734 $ hg commit --amend -m B2
737 $ cat > $TESTTMP/scmutilcleanup.py <<EOF
735 $ cat > $TESTTMP/scmutilcleanup.py <<EOF
738 > from mercurial import registrar, scmutil
736 > from mercurial import registrar, scmutil
739 > cmdtable = {}
737 > cmdtable = {}
740 > command = registrar.command(cmdtable)
738 > command = registrar.command(cmdtable)
741 > @command(b'cleanup')
739 > @command(b'cleanup')
742 > def cleanup(ui, repo):
740 > def cleanup(ui, repo):
743 > def node(expr):
741 > def node(expr):
744 > unfi = repo.unfiltered()
742 > unfi = repo.unfiltered()
745 > rev = unfi.revs(expr).first()
743 > rev = unfi.revs(expr).first()
746 > return unfi.changelog.node(rev)
744 > return unfi.changelog.node(rev)
747 > with repo.wlock(), repo.lock(), repo.transaction(b'delayedstrip'):
745 > with repo.wlock(), repo.lock(), repo.transaction(b'delayedstrip'):
748 > mapping = {node(b'desc(B1)'): [node(b'desc(B3)')],
746 > mapping = {node(b'desc(B1)'): [node(b'desc(B3)')],
749 > node(b'desc(B3)'): [node(b'desc(B4)')]}
747 > node(b'desc(B3)'): [node(b'desc(B4)')]}
750 > scmutil.cleanupnodes(repo, mapping, b'test')
748 > scmutil.cleanupnodes(repo, mapping, b'test')
751 > EOF
749 > EOF
752
750
753 $ rm .hg/localtags
751 $ rm .hg/localtags
754 $ hg cleanup --config extensions.t=$TESTTMP/scmutilcleanup.py
752 $ hg cleanup --config extensions.t=$TESTTMP/scmutilcleanup.py
755 2 new content-divergent changesets
753 2 new content-divergent changesets
756 $ hg log -G -T '{rev}:{node|short} {desc} {instabilities}' -r 'sort(all(), topo)'
754 $ hg log -G -T '{rev}:{node|short} {desc} {instabilities}' -r 'sort(all(), topo)'
757 @ 5:1a2a9b5b0030 B2 content-divergent
755 @ 5:1a2a9b5b0030 B2 content-divergent
758 |
756 |
759 | * 4:70d5a63ca112 B4 content-divergent
757 | * 4:70d5a63ca112 B4 content-divergent
760 | |
758 | |
761 | o 1:48b9aae0607f Z
759 | o 1:48b9aae0607f Z
762 |
760 |
763 o 0:426bada5c675 A
761 o 0:426bada5c675 A
764
762
765 $ hg debugobsolete
763 $ hg debugobsolete
766 a178212c3433c4e77b573f6011e29affb8aefa33 1a2a9b5b0030632400aa78e00388c20f99d3ec44 0 (Thu Jan 01 00:00:00 1970 +0000) {'ef1': '1', 'operation': 'amend', 'user': 'test'}
764 a178212c3433c4e77b573f6011e29affb8aefa33 1a2a9b5b0030632400aa78e00388c20f99d3ec44 0 (Thu Jan 01 00:00:00 1970 +0000) {'ef1': '1', 'operation': 'amend', 'user': 'test'}
767 a178212c3433c4e77b573f6011e29affb8aefa33 ad6478fb94ecec98b86daae98722865d494ac561 0 (Thu Jan 01 00:00:00 1970 +0000) {'ef1': '13', 'operation': 'test', 'user': 'test'}
765 a178212c3433c4e77b573f6011e29affb8aefa33 ad6478fb94ecec98b86daae98722865d494ac561 0 (Thu Jan 01 00:00:00 1970 +0000) {'ef1': '13', 'operation': 'test', 'user': 'test'}
768 ad6478fb94ecec98b86daae98722865d494ac561 70d5a63ca112acb3764bc1d7320ca90ea688d671 0 (Thu Jan 01 00:00:00 1970 +0000) {'ef1': '9', 'operation': 'test', 'user': 'test'}
766 ad6478fb94ecec98b86daae98722865d494ac561 70d5a63ca112acb3764bc1d7320ca90ea688d671 0 (Thu Jan 01 00:00:00 1970 +0000) {'ef1': '9', 'operation': 'test', 'user': 'test'}
769
767
770 $ hg debugwhyunstable 1a2a9b5b0030
768 $ hg debugwhyunstable 1a2a9b5b0030
771 content-divergent: 70d5a63ca112acb3764bc1d7320ca90ea688d671 (draft) predecessor a178212c3433c4e77b573f6011e29affb8aefa33
769 content-divergent: 70d5a63ca112acb3764bc1d7320ca90ea688d671 (draft) predecessor a178212c3433c4e77b573f6011e29affb8aefa33
772
770
773 $ hg log -r 1a2a9b5b0030 -T '{whyunstable}\n'
771 $ hg log -r 1a2a9b5b0030 -T '{whyunstable}\n'
774 content-divergent: 4:70d5a63ca112 (draft) predecessor a178212c3433
772 content-divergent: 4:70d5a63ca112 (draft) predecessor a178212c3433
775 $ hg log -r 1a2a9b5b0030 -T whyunstableshort
773 $ hg log -r 1a2a9b5b0030 -T whyunstableshort
776 content-divergent: 4:70d5a63ca112 (draft) predecessor a178
774 content-divergent: 4:70d5a63ca112 (draft) predecessor a178
777 $ hg log -r 1a2a9b5b0030 -T whyunstableshorter
775 $ hg log -r 1a2a9b5b0030 -T whyunstableshorter
778 content-divergent: 70d5 (draft) predecessor a178
776 content-divergent: 70d5 (draft) predecessor a178
779
777
780 #if serve
778 #if serve
781
779
782 $ hg serve -n test -p $HGPORT -d --pid-file=hg.pid -A access.log -E errors.log
780 $ hg serve -n test -p $HGPORT -d --pid-file=hg.pid -A access.log -E errors.log
783 $ cat hg.pid >> $DAEMON_PIDS
781 $ cat hg.pid >> $DAEMON_PIDS
784
782
785 check explanation for a content-divergent changeset
783 check explanation for a content-divergent changeset
786
784
787 $ get-with-headers.py localhost:$HGPORT 'rev/1a2a9b5b0030?style=paper' | grep divergent:
785 $ get-with-headers.py localhost:$HGPORT 'rev/1a2a9b5b0030?style=paper' | grep divergent:
788 <td>content-divergent: <a href="/rev/70d5a63ca112?style=paper">70d5a63ca112</a> (draft) predecessor <a href="/rev/a178212c3433?style=paper">a178212c3433</a></td>
786 <td>content-divergent: <a href="/rev/70d5a63ca112?style=paper">70d5a63ca112</a> (draft) predecessor <a href="/rev/a178212c3433?style=paper">a178212c3433</a></td>
789 $ get-with-headers.py localhost:$HGPORT 'rev/1a2a9b5b0030?style=coal' | grep divergent:
787 $ get-with-headers.py localhost:$HGPORT 'rev/1a2a9b5b0030?style=coal' | grep divergent:
790 <td>content-divergent: <a href="/rev/70d5a63ca112?style=coal">70d5a63ca112</a> (draft) predecessor <a href="/rev/a178212c3433?style=coal">a178212c3433</a></td>
788 <td>content-divergent: <a href="/rev/70d5a63ca112?style=coal">70d5a63ca112</a> (draft) predecessor <a href="/rev/a178212c3433?style=coal">a178212c3433</a></td>
791 $ get-with-headers.py localhost:$HGPORT 'rev/1a2a9b5b0030?style=gitweb' | grep divergent:
789 $ get-with-headers.py localhost:$HGPORT 'rev/1a2a9b5b0030?style=gitweb' | grep divergent:
792 <td>content-divergent: <a class="list" href="/rev/70d5a63ca112?style=gitweb">70d5a63ca112</a> (draft) predecessor <a class="list" href="/rev/a178212c3433?style=gitweb">a178212c3433</a></td>
790 <td>content-divergent: <a class="list" href="/rev/70d5a63ca112?style=gitweb">70d5a63ca112</a> (draft) predecessor <a class="list" href="/rev/a178212c3433?style=gitweb">a178212c3433</a></td>
793 $ get-with-headers.py localhost:$HGPORT 'rev/1a2a9b5b0030?style=monoblue' | grep divergent:
791 $ get-with-headers.py localhost:$HGPORT 'rev/1a2a9b5b0030?style=monoblue' | grep divergent:
794 <dd>content-divergent: <a href="/rev/70d5a63ca112?style=monoblue">70d5a63ca112</a> (draft) predecessor <a href="/rev/a178212c3433?style=monoblue">a178212c3433</a></dd>
792 <dd>content-divergent: <a href="/rev/70d5a63ca112?style=monoblue">70d5a63ca112</a> (draft) predecessor <a href="/rev/a178212c3433?style=monoblue">a178212c3433</a></dd>
795 $ get-with-headers.py localhost:$HGPORT 'rev/1a2a9b5b0030?style=spartan' | grep divergent:
793 $ get-with-headers.py localhost:$HGPORT 'rev/1a2a9b5b0030?style=spartan' | grep divergent:
796 <td class="unstable">content-divergent: <a href="/rev/70d5a63ca112?style=spartan">70d5a63ca112</a> (draft) predecessor <a href="/rev/a178212c3433?style=spartan">a178212c3433</a></td>
794 <td class="unstable">content-divergent: <a href="/rev/70d5a63ca112?style=spartan">70d5a63ca112</a> (draft) predecessor <a href="/rev/a178212c3433?style=spartan">a178212c3433</a></td>
797
795
798 $ killdaemons.py
796 $ killdaemons.py
799
797
800 #endif
798 #endif
@@ -1,1825 +1,1792 b''
1 $ cat >> $HGRCPATH << EOF
1 $ cat >> $HGRCPATH << EOF
2 > [phases]
2 > [phases]
3 > # public changeset are not obsolete
3 > # public changeset are not obsolete
4 > publish=false
4 > publish=false
5 > [ui]
5 > [ui]
6 > logtemplate="{rev}:{node|short} ({phase}{if(obsolete, ' *{obsolete}*')}{if(instabilities, ' {instabilities}')}) [{tags} {bookmarks}] {desc|firstline}{if(obsfate, " [{join(obsfate, "; ")}]")}\n"
6 > logtemplate="{rev}:{node|short} ({phase}{if(obsolete, ' *{obsolete}*')}{if(instabilities, ' {instabilities}')}) [{tags} {bookmarks}] {desc|firstline}{if(obsfate, " [{join(obsfate, "; ")}]")}\n"
7 > EOF
7 > EOF
8 $ mkcommit() {
8 $ mkcommit() {
9 > echo "$1" > "$1"
9 > echo "$1" > "$1"
10 > hg add "$1"
10 > hg add "$1"
11 > hg ci -m "add $1"
11 > hg ci -m "add $1"
12 > }
12 > }
13 $ getid() {
13 $ getid() {
14 > hg log -T "{node}\n" --hidden -r "desc('$1')"
14 > hg log -T "{node}\n" --hidden -r "desc('$1')"
15 > }
15 > }
16
16
17 $ cat > debugkeys.py <<EOF
17 $ cat > debugkeys.py <<EOF
18 > def reposetup(ui, repo):
18 > def reposetup(ui, repo):
19 > class debugkeysrepo(repo.__class__):
19 > class debugkeysrepo(repo.__class__):
20 > def listkeys(self, namespace):
20 > def listkeys(self, namespace):
21 > ui.write(b'listkeys %s\n' % (namespace,))
21 > ui.write(b'listkeys %s\n' % (namespace,))
22 > return super(debugkeysrepo, self).listkeys(namespace)
22 > return super(debugkeysrepo, self).listkeys(namespace)
23 >
23 >
24 > if repo.local():
24 > if repo.local():
25 > repo.__class__ = debugkeysrepo
25 > repo.__class__ = debugkeysrepo
26 > EOF
26 > EOF
27
27
28 $ hg init tmpa
28 $ hg init tmpa
29 $ cd tmpa
29 $ cd tmpa
30 $ mkcommit kill_me
30 $ mkcommit kill_me
31
31
32 Checking that the feature is properly disabled
32 Checking that the feature is properly disabled
33
33
34 $ hg debugobsolete -d '0 0' `getid kill_me` -u babar
34 $ hg debugobsolete -d '0 0' `getid kill_me` -u babar
35 abort: creating obsolete markers is not enabled on this repo
35 abort: creating obsolete markers is not enabled on this repo
36 [255]
36 [255]
37
37
38 Enabling it
38 Enabling it
39
39
40 $ cat >> $HGRCPATH << EOF
40 $ cat >> $HGRCPATH << EOF
41 > [experimental]
41 > [experimental]
42 > evolution=exchange
42 > evolution=exchange
43 > evolution.createmarkers=True
43 > evolution.createmarkers=True
44 > EOF
44 > EOF
45
45
46 Killing a single changeset without replacement
46 Killing a single changeset without replacement
47
47
48 $ hg debugobsolete 0
48 $ hg debugobsolete 0
49 abort: changeset references must be full hexadecimal node identifiers
49 abort: changeset references must be full hexadecimal node identifiers
50 [255]
50 [255]
51 $ hg debugobsolete '00'
51 $ hg debugobsolete '00'
52 abort: changeset references must be full hexadecimal node identifiers
52 abort: changeset references must be full hexadecimal node identifiers
53 [255]
53 [255]
54 $ hg debugobsolete -d '0 0' `getid kill_me` -u babar
54 $ hg debugobsolete -d '0 0' `getid kill_me` -u babar
55 1 new obsolescence markers
55 1 new obsolescence markers
56 obsoleted 1 changesets
56 obsoleted 1 changesets
57 $ hg debugobsolete
57 $ hg debugobsolete
58 97b7c2d76b1845ed3eb988cd612611e72406cef0 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'babar'}
58 97b7c2d76b1845ed3eb988cd612611e72406cef0 0 (Thu Jan 01 00:00:00 1970 +0000) {'user': 'babar'}
59
59
60 (test that mercurial is not confused)
60 (test that mercurial is not confused)
61
61
62 $ hg up null --quiet # having 0 as parent prevents it to be hidden
62 $ hg up null --quiet # having 0 as parent prevents it to be hidden
63 $ hg tip
63 $ hg tip
64 -1:000000000000 (public) [tip ]
64 -1:000000000000 (public) [tip ]
65 $ hg up --hidden tip --quiet
65 $ hg up --hidden tip --quiet
66 updated to hidden changeset 97b7c2d76b18
66 updated to hidden changeset 97b7c2d76b18
67 (hidden revision '97b7c2d76b18' is pruned)
67 (hidden revision '97b7c2d76b18' is pruned)
68
68
69 Killing a single changeset with itself should fail
69 Killing a single changeset with itself should fail
70 (simple local safeguard)
70 (simple local safeguard)
71
71
72 $ hg debugobsolete `getid kill_me` `getid kill_me`
72 $ hg debugobsolete `getid kill_me` `getid kill_me`
73 abort: bad obsmarker input: in-marker cycle with 97b7c2d76b1845ed3eb988cd612611e72406cef0
73 abort: bad obsmarker input: in-marker cycle with 97b7c2d76b1845ed3eb988cd612611e72406cef0
74 [255]
74 [255]
75
75
76 $ cd ..
76 $ cd ..
77
77
78 Killing a single changeset with replacement
78 Killing a single changeset with replacement
79 (and testing the format option)
79 (and testing the format option)
80
80
81 $ hg init tmpb
81 $ hg init tmpb
82 $ cd tmpb
82 $ cd tmpb
83 $ mkcommit a
83 $ mkcommit a
84 $ mkcommit b
84 $ mkcommit b
85 $ mkcommit original_c
85 $ mkcommit original_c
86 $ hg up "desc('b')"
86 $ hg up "desc('b')"
87 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
87 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
88 $ mkcommit new_c
88 $ mkcommit new_c
89 created new head
89 created new head
90 $ hg log -r 'hidden()' --template '{rev}:{node|short} {desc}\n' --hidden
90 $ hg log -r 'hidden()' --template '{rev}:{node|short} {desc}\n' --hidden
91 $ hg debugobsolete --config format.obsstore-version=0 --flag 12 `getid original_c` `getid new_c` -d '121 120'
91 $ hg debugobsolete --config format.obsstore-version=0 --flag 12 `getid original_c` `getid new_c` -d '121 120'
92 1 new obsolescence markers
92 1 new obsolescence markers
93 obsoleted 1 changesets
93 obsoleted 1 changesets
94 $ hg log -r 'hidden()' --template '{rev}:{node|short} {desc}\n' --hidden
94 $ hg log -r 'hidden()' --template '{rev}:{node|short} {desc}\n' --hidden
95 2:245bde4270cd add original_c
95 2:245bde4270cd add original_c
96 $ hg debugrevlog -cd
96 $ hg debugrevlog -cd
97 # rev p1rev p2rev start end deltastart base p1 p2 rawsize totalsize compression heads chainlen
97 # rev p1rev p2rev start end deltastart base p1 p2 rawsize totalsize compression heads chainlen
98 0 -1 -1 0 59 0 0 0 0 58 58 0 1 0
98 0 -1 -1 0 59 0 0 0 0 58 58 0 1 0
99 1 0 -1 59 118 59 59 0 0 58 116 0 1 0
99 1 0 -1 59 118 59 59 0 0 58 116 0 1 0
100 2 1 -1 118 193 118 118 59 0 76 192 0 1 0
100 2 1 -1 118 193 118 118 59 0 76 192 0 1 0
101 3 1 -1 193 260 193 193 59 0 66 258 0 2 0
101 3 1 -1 193 260 193 193 59 0 66 258 0 2 0
102 $ hg debugobsolete
102 $ hg debugobsolete
103 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C (Thu Jan 01 00:00:01 1970 -0002) {'user': 'test'}
103 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C (Thu Jan 01 00:00:01 1970 -0002) {'user': 'test'}
104
104
105 (check for version number of the obsstore)
105 (check for version number of the obsstore)
106
106
107 $ dd bs=1 count=1 if=.hg/store/obsstore 2>/dev/null
107 $ dd bs=1 count=1 if=.hg/store/obsstore 2>/dev/null
108 \x00 (no-eol) (esc)
108 \x00 (no-eol) (esc)
109
109
110 do it again (it read the obsstore before adding new changeset)
110 do it again (it read the obsstore before adding new changeset)
111
111
112 $ hg up '.^'
112 $ hg up '.^'
113 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
113 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
114 $ mkcommit new_2_c
114 $ mkcommit new_2_c
115 created new head
115 created new head
116 $ hg debugobsolete -d '1337 0' `getid new_c` `getid new_2_c`
116 $ hg debugobsolete -d '1337 0' `getid new_c` `getid new_2_c`
117 1 new obsolescence markers
117 1 new obsolescence markers
118 obsoleted 1 changesets
118 obsoleted 1 changesets
119 $ hg debugobsolete
119 $ hg debugobsolete
120 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C (Thu Jan 01 00:00:01 1970 -0002) {'user': 'test'}
120 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C (Thu Jan 01 00:00:01 1970 -0002) {'user': 'test'}
121 cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 (Thu Jan 01 00:22:17 1970 +0000) {'user': 'test'}
121 cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 (Thu Jan 01 00:22:17 1970 +0000) {'user': 'test'}
122
122
123 Register two markers with a missing node
123 Register two markers with a missing node
124
124
125 $ hg up '.^'
125 $ hg up '.^'
126 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
126 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
127 $ mkcommit new_3_c
127 $ mkcommit new_3_c
128 created new head
128 created new head
129 $ hg debugobsolete -d '1338 0' `getid new_2_c` 1337133713371337133713371337133713371337
129 $ hg debugobsolete -d '1338 0' `getid new_2_c` 1337133713371337133713371337133713371337
130 1 new obsolescence markers
130 1 new obsolescence markers
131 obsoleted 1 changesets
131 obsoleted 1 changesets
132 $ hg debugobsolete -d '1339 0' 1337133713371337133713371337133713371337 `getid new_3_c`
132 $ hg debugobsolete -d '1339 0' 1337133713371337133713371337133713371337 `getid new_3_c`
133 1 new obsolescence markers
133 1 new obsolescence markers
134 $ hg debugobsolete
134 $ hg debugobsolete
135 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C (Thu Jan 01 00:00:01 1970 -0002) {'user': 'test'}
135 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C (Thu Jan 01 00:00:01 1970 -0002) {'user': 'test'}
136 cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 (Thu Jan 01 00:22:17 1970 +0000) {'user': 'test'}
136 cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 (Thu Jan 01 00:22:17 1970 +0000) {'user': 'test'}
137 ca819180edb99ed25ceafb3e9584ac287e240b00 1337133713371337133713371337133713371337 0 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
137 ca819180edb99ed25ceafb3e9584ac287e240b00 1337133713371337133713371337133713371337 0 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
138 1337133713371337133713371337133713371337 5601fb93a350734d935195fee37f4054c529ff39 0 (Thu Jan 01 00:22:19 1970 +0000) {'user': 'test'}
138 1337133713371337133713371337133713371337 5601fb93a350734d935195fee37f4054c529ff39 0 (Thu Jan 01 00:22:19 1970 +0000) {'user': 'test'}
139
139
140 Test the --index option of debugobsolete command
140 Test the --index option of debugobsolete command
141 $ hg debugobsolete --index
141 $ hg debugobsolete --index
142 0 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C (Thu Jan 01 00:00:01 1970 -0002) {'user': 'test'}
142 0 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C (Thu Jan 01 00:00:01 1970 -0002) {'user': 'test'}
143 1 cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 (Thu Jan 01 00:22:17 1970 +0000) {'user': 'test'}
143 1 cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 (Thu Jan 01 00:22:17 1970 +0000) {'user': 'test'}
144 2 ca819180edb99ed25ceafb3e9584ac287e240b00 1337133713371337133713371337133713371337 0 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
144 2 ca819180edb99ed25ceafb3e9584ac287e240b00 1337133713371337133713371337133713371337 0 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
145 3 1337133713371337133713371337133713371337 5601fb93a350734d935195fee37f4054c529ff39 0 (Thu Jan 01 00:22:19 1970 +0000) {'user': 'test'}
145 3 1337133713371337133713371337133713371337 5601fb93a350734d935195fee37f4054c529ff39 0 (Thu Jan 01 00:22:19 1970 +0000) {'user': 'test'}
146
146
147 Refuse pathological nullid successors
147 Refuse pathological nullid successors
148 $ hg debugobsolete -d '9001 0' 1337133713371337133713371337133713371337 0000000000000000000000000000000000000000
148 $ hg debugobsolete -d '9001 0' 1337133713371337133713371337133713371337 0000000000000000000000000000000000000000
149 transaction abort!
149 transaction abort!
150 rollback completed
150 rollback completed
151 abort: bad obsolescence marker detected: invalid successors nullid
151 abort: bad obsolescence marker detected: invalid successors nullid
152 [255]
152 [255]
153
153
154 Check that graphlog detect that a changeset is obsolete:
154 Check that graphlog detect that a changeset is obsolete:
155
155
156 $ hg log -G
156 $ hg log -G
157 @ 5:5601fb93a350 (draft) [tip ] add new_3_c
157 @ 5:5601fb93a350 (draft) [tip ] add new_3_c
158 |
158 |
159 o 1:7c3bad9141dc (draft) [ ] add b
159 o 1:7c3bad9141dc (draft) [ ] add b
160 |
160 |
161 o 0:1f0dee641bb7 (draft) [ ] add a
161 o 0:1f0dee641bb7 (draft) [ ] add a
162
162
163
163
164 check that heads does not report them
164 check that heads does not report them
165
165
166 $ hg heads
166 $ hg heads
167 5:5601fb93a350 (draft) [tip ] add new_3_c
167 5:5601fb93a350 (draft) [tip ] add new_3_c
168 $ hg heads --hidden
168 $ hg heads --hidden
169 5:5601fb93a350 (draft) [tip ] add new_3_c
169 5:5601fb93a350 (draft) [tip ] add new_3_c
170 4:ca819180edb9 (draft *obsolete*) [ ] add new_2_c [rewritten as 5:5601fb93a350]
170 4:ca819180edb9 (draft *obsolete*) [ ] add new_2_c [rewritten as 5:5601fb93a350]
171 3:cdbce2fbb163 (draft *obsolete*) [ ] add new_c [rewritten as 4:ca819180edb9]
171 3:cdbce2fbb163 (draft *obsolete*) [ ] add new_c [rewritten as 4:ca819180edb9]
172 2:245bde4270cd (draft *obsolete*) [ ] add original_c [rewritten as 3:cdbce2fbb163]
172 2:245bde4270cd (draft *obsolete*) [ ] add original_c [rewritten as 3:cdbce2fbb163]
173
173
174
174
175 check that summary does not report them
175 check that summary does not report them
176
176
177 $ hg init ../sink
177 $ hg init ../sink
178 $ echo '[paths]' >> .hg/hgrc
178 $ echo '[paths]' >> .hg/hgrc
179 $ echo 'default=../sink' >> .hg/hgrc
179 $ echo 'default=../sink' >> .hg/hgrc
180 $ hg summary --remote
180 $ hg summary --remote
181 parent: 5:5601fb93a350 tip
181 parent: 5:5601fb93a350 tip
182 add new_3_c
182 add new_3_c
183 branch: default
183 branch: default
184 commit: (clean)
184 commit: (clean)
185 update: (current)
185 update: (current)
186 phases: 3 draft
186 phases: 3 draft
187 remote: 3 outgoing
187 remote: 3 outgoing
188
188
189 $ hg summary --remote --hidden
189 $ hg summary --remote --hidden
190 parent: 5:5601fb93a350 tip
190 parent: 5:5601fb93a350 tip
191 add new_3_c
191 add new_3_c
192 branch: default
192 branch: default
193 commit: (clean)
193 commit: (clean)
194 update: 3 new changesets, 4 branch heads (merge)
194 update: 3 new changesets, 4 branch heads (merge)
195 phases: 6 draft
195 phases: 6 draft
196 remote: 3 outgoing
196 remote: 3 outgoing
197
197
198 check that various commands work well with filtering
198 check that various commands work well with filtering
199
199
200 $ hg tip
200 $ hg tip
201 5:5601fb93a350 (draft) [tip ] add new_3_c
201 5:5601fb93a350 (draft) [tip ] add new_3_c
202 $ hg log -r 6
202 $ hg log -r 6
203 abort: unknown revision '6'!
203 abort: unknown revision '6'!
204 [255]
204 [255]
205 $ hg log -r 4
205 $ hg log -r 4
206 abort: hidden revision '4' was rewritten as: 5601fb93a350!
206 abort: hidden revision '4' was rewritten as: 5601fb93a350!
207 (use --hidden to access hidden revisions)
207 (use --hidden to access hidden revisions)
208 [255]
208 [255]
209 $ hg debugrevspec 'rev(6)'
209 $ hg debugrevspec 'rev(6)'
210 $ hg debugrevspec 'rev(4)'
210 $ hg debugrevspec 'rev(4)'
211 $ hg debugrevspec 'null'
211 $ hg debugrevspec 'null'
212 -1
212 -1
213
213
214 Check that public changeset are not accounted as obsolete:
214 Check that public changeset are not accounted as obsolete:
215
215
216 $ hg --hidden phase --public 2
216 $ hg --hidden phase --public 2
217 1 new phase-divergent changesets
217 1 new phase-divergent changesets
218 $ hg log -G
218 $ hg log -G
219 @ 5:5601fb93a350 (draft phase-divergent) [tip ] add new_3_c
219 @ 5:5601fb93a350 (draft phase-divergent) [tip ] add new_3_c
220 |
220 |
221 | o 2:245bde4270cd (public) [ ] add original_c
221 | o 2:245bde4270cd (public) [ ] add original_c
222 |/
222 |/
223 o 1:7c3bad9141dc (public) [ ] add b
223 o 1:7c3bad9141dc (public) [ ] add b
224 |
224 |
225 o 0:1f0dee641bb7 (public) [ ] add a
225 o 0:1f0dee641bb7 (public) [ ] add a
226
226
227 $ hg log -r 'unstable()'
227 $ hg log -r 'unstable()'
228 5:5601fb93a350 (draft phase-divergent) [tip ] add new_3_c
228 5:5601fb93a350 (draft phase-divergent) [tip ] add new_3_c
229
229
230
230
231 And that bumped changeset are detected
231 And that bumped changeset are detected
232 --------------------------------------
232 --------------------------------------
233
233
234 If we didn't filtered obsolete changesets out, 3 and 4 would show up too. Also
234 If we didn't filtered obsolete changesets out, 3 and 4 would show up too. Also
235 note that the bumped changeset (5:5601fb93a350) is not a direct successor of
235 note that the bumped changeset (5:5601fb93a350) is not a direct successor of
236 the public changeset
236 the public changeset
237
237
238 $ hg log --hidden -r 'phasedivergent()'
238 $ hg log --hidden -r 'phasedivergent()'
239 5:5601fb93a350 (draft phase-divergent) [tip ] add new_3_c
239 5:5601fb93a350 (draft phase-divergent) [tip ] add new_3_c
240
240
241 And that we can't push bumped changeset
241 And that we can't push bumped changeset
242
242
243 $ hg push ../tmpa -r 0 --force #(make repo related)
243 $ hg push ../tmpa -r 0 --force #(make repo related)
244 pushing to ../tmpa
244 pushing to ../tmpa
245 searching for changes
245 searching for changes
246 warning: repository is unrelated
246 warning: repository is unrelated
247 adding changesets
247 adding changesets
248 adding manifests
248 adding manifests
249 adding file changes
249 adding file changes
250 added 1 changesets with 1 changes to 1 files (+1 heads)
250 added 1 changesets with 1 changes to 1 files (+1 heads)
251 $ hg push ../tmpa
251 $ hg push ../tmpa
252 pushing to ../tmpa
252 pushing to ../tmpa
253 searching for changes
253 searching for changes
254 abort: push includes unstable changesets:
254 abort: push includes phase-divergent changeset: 5601fb93a350!
255 5601fb93a350 (phase-divergent)
256 [255]
255 [255]
257
256
258 Fixing "bumped" situation
257 Fixing "bumped" situation
259 We need to create a clone of 5 and add a special marker with a flag
258 We need to create a clone of 5 and add a special marker with a flag
260
259
261 $ hg summary
260 $ hg summary
262 parent: 5:5601fb93a350 tip (phase-divergent)
261 parent: 5:5601fb93a350 tip (phase-divergent)
263 add new_3_c
262 add new_3_c
264 branch: default
263 branch: default
265 commit: (clean)
264 commit: (clean)
266 update: 1 new changesets, 2 branch heads (merge)
265 update: 1 new changesets, 2 branch heads (merge)
267 phases: 1 draft
266 phases: 1 draft
268 phase-divergent: 1 changesets
267 phase-divergent: 1 changesets
269 $ hg up '5^'
268 $ hg up '5^'
270 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
269 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
271 $ hg revert -ar 5
270 $ hg revert -ar 5
272 adding new_3_c
271 adding new_3_c
273 $ hg ci -m 'add n3w_3_c'
272 $ hg ci -m 'add n3w_3_c'
274 created new head
273 created new head
275 $ hg debugobsolete -d '1338 0' --flags 1 `getid new_3_c` `getid n3w_3_c`
274 $ hg debugobsolete -d '1338 0' --flags 1 `getid new_3_c` `getid n3w_3_c`
276 1 new obsolescence markers
275 1 new obsolescence markers
277 obsoleted 1 changesets
276 obsoleted 1 changesets
278 $ hg log -r 'phasedivergent()'
277 $ hg log -r 'phasedivergent()'
279 $ hg log -G
278 $ hg log -G
280 @ 6:6f9641995072 (draft) [tip ] add n3w_3_c
279 @ 6:6f9641995072 (draft) [tip ] add n3w_3_c
281 |
280 |
282 | o 2:245bde4270cd (public) [ ] add original_c
281 | o 2:245bde4270cd (public) [ ] add original_c
283 |/
282 |/
284 o 1:7c3bad9141dc (public) [ ] add b
283 o 1:7c3bad9141dc (public) [ ] add b
285 |
284 |
286 o 0:1f0dee641bb7 (public) [ ] add a
285 o 0:1f0dee641bb7 (public) [ ] add a
287
286
288
287
289 Basic exclusive testing
288 Basic exclusive testing
290
289
291 $ hg log -G --hidden
290 $ hg log -G --hidden
292 @ 6:6f9641995072 (draft) [tip ] add n3w_3_c
291 @ 6:6f9641995072 (draft) [tip ] add n3w_3_c
293 |
292 |
294 | x 5:5601fb93a350 (draft *obsolete*) [ ] add new_3_c [rewritten as 6:6f9641995072]
293 | x 5:5601fb93a350 (draft *obsolete*) [ ] add new_3_c [rewritten as 6:6f9641995072]
295 |/
294 |/
296 | x 4:ca819180edb9 (draft *obsolete*) [ ] add new_2_c [rewritten as 5:5601fb93a350]
295 | x 4:ca819180edb9 (draft *obsolete*) [ ] add new_2_c [rewritten as 5:5601fb93a350]
297 |/
296 |/
298 | x 3:cdbce2fbb163 (draft *obsolete*) [ ] add new_c [rewritten as 4:ca819180edb9]
297 | x 3:cdbce2fbb163 (draft *obsolete*) [ ] add new_c [rewritten as 4:ca819180edb9]
299 |/
298 |/
300 | o 2:245bde4270cd (public) [ ] add original_c
299 | o 2:245bde4270cd (public) [ ] add original_c
301 |/
300 |/
302 o 1:7c3bad9141dc (public) [ ] add b
301 o 1:7c3bad9141dc (public) [ ] add b
303 |
302 |
304 o 0:1f0dee641bb7 (public) [ ] add a
303 o 0:1f0dee641bb7 (public) [ ] add a
305
304
306 $ hg debugobsolete --rev 6f9641995072
305 $ hg debugobsolete --rev 6f9641995072
307 1337133713371337133713371337133713371337 5601fb93a350734d935195fee37f4054c529ff39 0 (Thu Jan 01 00:22:19 1970 +0000) {'user': 'test'}
306 1337133713371337133713371337133713371337 5601fb93a350734d935195fee37f4054c529ff39 0 (Thu Jan 01 00:22:19 1970 +0000) {'user': 'test'}
308 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C (Thu Jan 01 00:00:01 1970 -0002) {'user': 'test'}
307 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C (Thu Jan 01 00:00:01 1970 -0002) {'user': 'test'}
309 5601fb93a350734d935195fee37f4054c529ff39 6f96419950729f3671185b847352890f074f7557 1 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
308 5601fb93a350734d935195fee37f4054c529ff39 6f96419950729f3671185b847352890f074f7557 1 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
310 ca819180edb99ed25ceafb3e9584ac287e240b00 1337133713371337133713371337133713371337 0 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
309 ca819180edb99ed25ceafb3e9584ac287e240b00 1337133713371337133713371337133713371337 0 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
311 cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 (Thu Jan 01 00:22:17 1970 +0000) {'user': 'test'}
310 cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 (Thu Jan 01 00:22:17 1970 +0000) {'user': 'test'}
312 $ hg debugobsolete --rev 6f9641995072 --exclusive
311 $ hg debugobsolete --rev 6f9641995072 --exclusive
313 5601fb93a350734d935195fee37f4054c529ff39 6f96419950729f3671185b847352890f074f7557 1 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
312 5601fb93a350734d935195fee37f4054c529ff39 6f96419950729f3671185b847352890f074f7557 1 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
314 $ hg debugobsolete --rev 5601fb93a350 --hidden
313 $ hg debugobsolete --rev 5601fb93a350 --hidden
315 1337133713371337133713371337133713371337 5601fb93a350734d935195fee37f4054c529ff39 0 (Thu Jan 01 00:22:19 1970 +0000) {'user': 'test'}
314 1337133713371337133713371337133713371337 5601fb93a350734d935195fee37f4054c529ff39 0 (Thu Jan 01 00:22:19 1970 +0000) {'user': 'test'}
316 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C (Thu Jan 01 00:00:01 1970 -0002) {'user': 'test'}
315 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C (Thu Jan 01 00:00:01 1970 -0002) {'user': 'test'}
317 ca819180edb99ed25ceafb3e9584ac287e240b00 1337133713371337133713371337133713371337 0 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
316 ca819180edb99ed25ceafb3e9584ac287e240b00 1337133713371337133713371337133713371337 0 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
318 cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 (Thu Jan 01 00:22:17 1970 +0000) {'user': 'test'}
317 cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 (Thu Jan 01 00:22:17 1970 +0000) {'user': 'test'}
319 $ hg debugobsolete --rev 5601fb93a350 --hidden --exclusive
318 $ hg debugobsolete --rev 5601fb93a350 --hidden --exclusive
320 $ hg debugobsolete --rev 5601fb93a350+6f9641995072 --hidden --exclusive
319 $ hg debugobsolete --rev 5601fb93a350+6f9641995072 --hidden --exclusive
321 1337133713371337133713371337133713371337 5601fb93a350734d935195fee37f4054c529ff39 0 (Thu Jan 01 00:22:19 1970 +0000) {'user': 'test'}
320 1337133713371337133713371337133713371337 5601fb93a350734d935195fee37f4054c529ff39 0 (Thu Jan 01 00:22:19 1970 +0000) {'user': 'test'}
322 5601fb93a350734d935195fee37f4054c529ff39 6f96419950729f3671185b847352890f074f7557 1 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
321 5601fb93a350734d935195fee37f4054c529ff39 6f96419950729f3671185b847352890f074f7557 1 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
323 ca819180edb99ed25ceafb3e9584ac287e240b00 1337133713371337133713371337133713371337 0 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
322 ca819180edb99ed25ceafb3e9584ac287e240b00 1337133713371337133713371337133713371337 0 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
324
323
325 $ cd ..
324 $ cd ..
326
325
327 Revision 0 is hidden
326 Revision 0 is hidden
328 --------------------
327 --------------------
329
328
330 $ hg init rev0hidden
329 $ hg init rev0hidden
331 $ cd rev0hidden
330 $ cd rev0hidden
332
331
333 $ mkcommit kill0
332 $ mkcommit kill0
334 $ hg up -q null
333 $ hg up -q null
335 $ hg debugobsolete `getid kill0`
334 $ hg debugobsolete `getid kill0`
336 1 new obsolescence markers
335 1 new obsolescence markers
337 obsoleted 1 changesets
336 obsoleted 1 changesets
338 $ mkcommit a
337 $ mkcommit a
339 $ mkcommit b
338 $ mkcommit b
340
339
341 Should pick the first visible revision as "repo" node
340 Should pick the first visible revision as "repo" node
342
341
343 $ hg archive ../archive-null
342 $ hg archive ../archive-null
344 $ cat ../archive-null/.hg_archival.txt
343 $ cat ../archive-null/.hg_archival.txt
345 repo: 1f0dee641bb7258c56bd60e93edfa2405381c41e
344 repo: 1f0dee641bb7258c56bd60e93edfa2405381c41e
346 node: 7c3bad9141dcb46ff89abf5f61856facd56e476c
345 node: 7c3bad9141dcb46ff89abf5f61856facd56e476c
347 branch: default
346 branch: default
348 latesttag: null
347 latesttag: null
349 latesttagdistance: 2
348 latesttagdistance: 2
350 changessincelatesttag: 2
349 changessincelatesttag: 2
351
350
352
351
353 $ cd ..
352 $ cd ..
354
353
355 Can disable transaction summary report
354 Can disable transaction summary report
356
355
357 $ hg init transaction-summary
356 $ hg init transaction-summary
358 $ cd transaction-summary
357 $ cd transaction-summary
359 $ mkcommit a
358 $ mkcommit a
360 $ mkcommit b
359 $ mkcommit b
361 $ hg up -q null
360 $ hg up -q null
362 $ hg --config experimental.evolution.report-instabilities=false debugobsolete `getid a`
361 $ hg --config experimental.evolution.report-instabilities=false debugobsolete `getid a`
363 1 new obsolescence markers
362 1 new obsolescence markers
364 obsoleted 1 changesets
363 obsoleted 1 changesets
365 $ cd ..
364 $ cd ..
366
365
367 Exchange Test
366 Exchange Test
368 ============================
367 ============================
369
368
370 Destination repo does not have any data
369 Destination repo does not have any data
371 ---------------------------------------
370 ---------------------------------------
372
371
373 Simple incoming test
372 Simple incoming test
374
373
375 $ hg init tmpc
374 $ hg init tmpc
376 $ cd tmpc
375 $ cd tmpc
377 $ hg incoming ../tmpb
376 $ hg incoming ../tmpb
378 comparing with ../tmpb
377 comparing with ../tmpb
379 0:1f0dee641bb7 (public) [ ] add a
378 0:1f0dee641bb7 (public) [ ] add a
380 1:7c3bad9141dc (public) [ ] add b
379 1:7c3bad9141dc (public) [ ] add b
381 2:245bde4270cd (public) [ ] add original_c
380 2:245bde4270cd (public) [ ] add original_c
382 6:6f9641995072 (draft) [tip ] add n3w_3_c
381 6:6f9641995072 (draft) [tip ] add n3w_3_c
383
382
384 Try to pull markers while testing pull --confirm
383 Try to pull markers while testing pull --confirm
385 (extinct changeset are excluded but marker are pushed)
384 (extinct changeset are excluded but marker are pushed)
386
385
387 $ hg pull ../tmpb --confirm --config ui.interactive=true <<EOF
386 $ hg pull ../tmpb --confirm --config ui.interactive=true <<EOF
388 > n
387 > n
389 > EOF
388 > EOF
390 pulling from ../tmpb
389 pulling from ../tmpb
391 requesting all changes
390 requesting all changes
392 adding changesets
391 adding changesets
393 adding manifests
392 adding manifests
394 adding file changes
393 adding file changes
395 adding 4 changesets with 4 changes to 4 files (+1 heads)
394 adding 4 changesets with 4 changes to 4 files (+1 heads)
396 5 new obsolescence markers
395 5 new obsolescence markers
397 new changesets 1f0dee641bb7:6f9641995072 (1 drafts)
396 new changesets 1f0dee641bb7:6f9641995072 (1 drafts)
398 accept incoming changes (yn)? n
397 accept incoming changes (yn)? n
399 transaction abort!
398 transaction abort!
400 rollback completed
399 rollback completed
401 abort: user aborted
400 abort: user aborted
402 [255]
401 [255]
403 $ HGPLAIN=1 hg pull ../tmpb --confirm --config ui.interactive=true <<EOF
402 $ HGPLAIN=1 hg pull ../tmpb --confirm --config ui.interactive=true <<EOF
404 > n
403 > n
405 > EOF
404 > EOF
406 pulling from ../tmpb
405 pulling from ../tmpb
407 requesting all changes
406 requesting all changes
408 adding changesets
407 adding changesets
409 adding manifests
408 adding manifests
410 adding file changes
409 adding file changes
411 adding 4 changesets with 4 changes to 4 files (+1 heads)
410 adding 4 changesets with 4 changes to 4 files (+1 heads)
412 5 new obsolescence markers
411 5 new obsolescence markers
413 new changesets 1f0dee641bb7:6f9641995072 (1 drafts)
412 new changesets 1f0dee641bb7:6f9641995072 (1 drafts)
414 accept incoming changes (yn)? n
413 accept incoming changes (yn)? n
415 transaction abort!
414 transaction abort!
416 rollback completed
415 rollback completed
417 abort: user aborted
416 abort: user aborted
418 [255]
417 [255]
419 $ hg pull ../tmpb --confirm --config ui.interactive=true <<EOF
418 $ hg pull ../tmpb --confirm --config ui.interactive=true <<EOF
420 > y
419 > y
421 > EOF
420 > EOF
422 pulling from ../tmpb
421 pulling from ../tmpb
423 requesting all changes
422 requesting all changes
424 adding changesets
423 adding changesets
425 adding manifests
424 adding manifests
426 adding file changes
425 adding file changes
427 adding 4 changesets with 4 changes to 4 files (+1 heads)
426 adding 4 changesets with 4 changes to 4 files (+1 heads)
428 5 new obsolescence markers
427 5 new obsolescence markers
429 new changesets 1f0dee641bb7:6f9641995072 (1 drafts)
428 new changesets 1f0dee641bb7:6f9641995072 (1 drafts)
430 accept incoming changes (yn)? y
429 accept incoming changes (yn)? y
431 added 4 changesets with 4 changes to 4 files (+1 heads)
430 added 4 changesets with 4 changes to 4 files (+1 heads)
432 5 new obsolescence markers
431 5 new obsolescence markers
433 new changesets 1f0dee641bb7:6f9641995072 (1 drafts)
432 new changesets 1f0dee641bb7:6f9641995072 (1 drafts)
434 (run 'hg heads' to see heads, 'hg merge' to merge)
433 (run 'hg heads' to see heads, 'hg merge' to merge)
435 $ hg debugobsolete
434 $ hg debugobsolete
436 1337133713371337133713371337133713371337 5601fb93a350734d935195fee37f4054c529ff39 0 (Thu Jan 01 00:22:19 1970 +0000) {'user': 'test'}
435 1337133713371337133713371337133713371337 5601fb93a350734d935195fee37f4054c529ff39 0 (Thu Jan 01 00:22:19 1970 +0000) {'user': 'test'}
437 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C (Thu Jan 01 00:00:01 1970 -0002) {'user': 'test'}
436 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C (Thu Jan 01 00:00:01 1970 -0002) {'user': 'test'}
438 5601fb93a350734d935195fee37f4054c529ff39 6f96419950729f3671185b847352890f074f7557 1 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
437 5601fb93a350734d935195fee37f4054c529ff39 6f96419950729f3671185b847352890f074f7557 1 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
439 ca819180edb99ed25ceafb3e9584ac287e240b00 1337133713371337133713371337133713371337 0 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
438 ca819180edb99ed25ceafb3e9584ac287e240b00 1337133713371337133713371337133713371337 0 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
440 cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 (Thu Jan 01 00:22:17 1970 +0000) {'user': 'test'}
439 cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 (Thu Jan 01 00:22:17 1970 +0000) {'user': 'test'}
441
440
442 Rollback//Transaction support
441 Rollback//Transaction support
443
442
444 $ hg debugobsolete -d '1340 0' aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
443 $ hg debugobsolete -d '1340 0' aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
445 1 new obsolescence markers
444 1 new obsolescence markers
446 $ hg debugobsolete
445 $ hg debugobsolete
447 1337133713371337133713371337133713371337 5601fb93a350734d935195fee37f4054c529ff39 0 (Thu Jan 01 00:22:19 1970 +0000) {'user': 'test'}
446 1337133713371337133713371337133713371337 5601fb93a350734d935195fee37f4054c529ff39 0 (Thu Jan 01 00:22:19 1970 +0000) {'user': 'test'}
448 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C (Thu Jan 01 00:00:01 1970 -0002) {'user': 'test'}
447 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C (Thu Jan 01 00:00:01 1970 -0002) {'user': 'test'}
449 5601fb93a350734d935195fee37f4054c529ff39 6f96419950729f3671185b847352890f074f7557 1 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
448 5601fb93a350734d935195fee37f4054c529ff39 6f96419950729f3671185b847352890f074f7557 1 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
450 ca819180edb99ed25ceafb3e9584ac287e240b00 1337133713371337133713371337133713371337 0 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
449 ca819180edb99ed25ceafb3e9584ac287e240b00 1337133713371337133713371337133713371337 0 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
451 cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 (Thu Jan 01 00:22:17 1970 +0000) {'user': 'test'}
450 cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 (Thu Jan 01 00:22:17 1970 +0000) {'user': 'test'}
452 aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb 0 (Thu Jan 01 00:22:20 1970 +0000) {'user': 'test'}
451 aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb 0 (Thu Jan 01 00:22:20 1970 +0000) {'user': 'test'}
453 $ hg rollback -n
452 $ hg rollback -n
454 repository tip rolled back to revision 3 (undo debugobsolete)
453 repository tip rolled back to revision 3 (undo debugobsolete)
455 $ hg rollback
454 $ hg rollback
456 repository tip rolled back to revision 3 (undo debugobsolete)
455 repository tip rolled back to revision 3 (undo debugobsolete)
457 $ hg debugobsolete
456 $ hg debugobsolete
458 1337133713371337133713371337133713371337 5601fb93a350734d935195fee37f4054c529ff39 0 (Thu Jan 01 00:22:19 1970 +0000) {'user': 'test'}
457 1337133713371337133713371337133713371337 5601fb93a350734d935195fee37f4054c529ff39 0 (Thu Jan 01 00:22:19 1970 +0000) {'user': 'test'}
459 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C (Thu Jan 01 00:00:01 1970 -0002) {'user': 'test'}
458 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C (Thu Jan 01 00:00:01 1970 -0002) {'user': 'test'}
460 5601fb93a350734d935195fee37f4054c529ff39 6f96419950729f3671185b847352890f074f7557 1 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
459 5601fb93a350734d935195fee37f4054c529ff39 6f96419950729f3671185b847352890f074f7557 1 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
461 ca819180edb99ed25ceafb3e9584ac287e240b00 1337133713371337133713371337133713371337 0 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
460 ca819180edb99ed25ceafb3e9584ac287e240b00 1337133713371337133713371337133713371337 0 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
462 cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 (Thu Jan 01 00:22:17 1970 +0000) {'user': 'test'}
461 cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 (Thu Jan 01 00:22:17 1970 +0000) {'user': 'test'}
463
462
464 $ cd ..
463 $ cd ..
465
464
466 Try to push markers
465 Try to push markers
467
466
468 $ hg init tmpd
467 $ hg init tmpd
469 $ hg -R tmpb push tmpd
468 $ hg -R tmpb push tmpd
470 pushing to tmpd
469 pushing to tmpd
471 searching for changes
470 searching for changes
472 adding changesets
471 adding changesets
473 adding manifests
472 adding manifests
474 adding file changes
473 adding file changes
475 added 4 changesets with 4 changes to 4 files (+1 heads)
474 added 4 changesets with 4 changes to 4 files (+1 heads)
476 5 new obsolescence markers
475 5 new obsolescence markers
477 $ hg -R tmpd debugobsolete | sort
476 $ hg -R tmpd debugobsolete | sort
478 1337133713371337133713371337133713371337 5601fb93a350734d935195fee37f4054c529ff39 0 (Thu Jan 01 00:22:19 1970 +0000) {'user': 'test'}
477 1337133713371337133713371337133713371337 5601fb93a350734d935195fee37f4054c529ff39 0 (Thu Jan 01 00:22:19 1970 +0000) {'user': 'test'}
479 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C (Thu Jan 01 00:00:01 1970 -0002) {'user': 'test'}
478 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C (Thu Jan 01 00:00:01 1970 -0002) {'user': 'test'}
480 5601fb93a350734d935195fee37f4054c529ff39 6f96419950729f3671185b847352890f074f7557 1 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
479 5601fb93a350734d935195fee37f4054c529ff39 6f96419950729f3671185b847352890f074f7557 1 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
481 ca819180edb99ed25ceafb3e9584ac287e240b00 1337133713371337133713371337133713371337 0 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
480 ca819180edb99ed25ceafb3e9584ac287e240b00 1337133713371337133713371337133713371337 0 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
482 cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 (Thu Jan 01 00:22:17 1970 +0000) {'user': 'test'}
481 cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 (Thu Jan 01 00:22:17 1970 +0000) {'user': 'test'}
483
482
484 Check obsolete keys are exchanged only if source has an obsolete store
483 Check obsolete keys are exchanged only if source has an obsolete store
485
484
486 $ hg init empty
485 $ hg init empty
487 $ hg --config extensions.debugkeys=debugkeys.py -R empty push tmpd
486 $ hg --config extensions.debugkeys=debugkeys.py -R empty push tmpd
488 pushing to tmpd
487 pushing to tmpd
489 listkeys phases
488 listkeys phases
490 listkeys bookmarks
489 listkeys bookmarks
491 no changes found
490 no changes found
492 listkeys phases
491 listkeys phases
493 [1]
492 [1]
494
493
495 clone support
494 clone support
496 (markers are copied and extinct changesets are included to allow hardlinks)
495 (markers are copied and extinct changesets are included to allow hardlinks)
497
496
498 $ hg clone tmpb clone-dest
497 $ hg clone tmpb clone-dest
499 updating to branch default
498 updating to branch default
500 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
499 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
501 $ hg -R clone-dest log -G --hidden
500 $ hg -R clone-dest log -G --hidden
502 @ 6:6f9641995072 (draft) [tip ] add n3w_3_c
501 @ 6:6f9641995072 (draft) [tip ] add n3w_3_c
503 |
502 |
504 | x 5:5601fb93a350 (draft *obsolete*) [ ] add new_3_c [rewritten as 6:6f9641995072]
503 | x 5:5601fb93a350 (draft *obsolete*) [ ] add new_3_c [rewritten as 6:6f9641995072]
505 |/
504 |/
506 | x 4:ca819180edb9 (draft *obsolete*) [ ] add new_2_c [rewritten as 5:5601fb93a350]
505 | x 4:ca819180edb9 (draft *obsolete*) [ ] add new_2_c [rewritten as 5:5601fb93a350]
507 |/
506 |/
508 | x 3:cdbce2fbb163 (draft *obsolete*) [ ] add new_c [rewritten as 4:ca819180edb9]
507 | x 3:cdbce2fbb163 (draft *obsolete*) [ ] add new_c [rewritten as 4:ca819180edb9]
509 |/
508 |/
510 | o 2:245bde4270cd (public) [ ] add original_c
509 | o 2:245bde4270cd (public) [ ] add original_c
511 |/
510 |/
512 o 1:7c3bad9141dc (public) [ ] add b
511 o 1:7c3bad9141dc (public) [ ] add b
513 |
512 |
514 o 0:1f0dee641bb7 (public) [ ] add a
513 o 0:1f0dee641bb7 (public) [ ] add a
515
514
516 $ hg -R clone-dest debugobsolete
515 $ hg -R clone-dest debugobsolete
517 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C (Thu Jan 01 00:00:01 1970 -0002) {'user': 'test'}
516 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C (Thu Jan 01 00:00:01 1970 -0002) {'user': 'test'}
518 cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 (Thu Jan 01 00:22:17 1970 +0000) {'user': 'test'}
517 cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 (Thu Jan 01 00:22:17 1970 +0000) {'user': 'test'}
519 ca819180edb99ed25ceafb3e9584ac287e240b00 1337133713371337133713371337133713371337 0 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
518 ca819180edb99ed25ceafb3e9584ac287e240b00 1337133713371337133713371337133713371337 0 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
520 1337133713371337133713371337133713371337 5601fb93a350734d935195fee37f4054c529ff39 0 (Thu Jan 01 00:22:19 1970 +0000) {'user': 'test'}
519 1337133713371337133713371337133713371337 5601fb93a350734d935195fee37f4054c529ff39 0 (Thu Jan 01 00:22:19 1970 +0000) {'user': 'test'}
521 5601fb93a350734d935195fee37f4054c529ff39 6f96419950729f3671185b847352890f074f7557 1 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
520 5601fb93a350734d935195fee37f4054c529ff39 6f96419950729f3671185b847352890f074f7557 1 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
522
521
523
522
524 Destination repo have existing data
523 Destination repo have existing data
525 ---------------------------------------
524 ---------------------------------------
526
525
527 On pull
526 On pull
528
527
529 $ hg init tmpe
528 $ hg init tmpe
530 $ cd tmpe
529 $ cd tmpe
531 $ hg debugobsolete -d '1339 0' 1339133913391339133913391339133913391339 ca819180edb99ed25ceafb3e9584ac287e240b00
530 $ hg debugobsolete -d '1339 0' 1339133913391339133913391339133913391339 ca819180edb99ed25ceafb3e9584ac287e240b00
532 1 new obsolescence markers
531 1 new obsolescence markers
533 $ hg pull ../tmpb
532 $ hg pull ../tmpb
534 pulling from ../tmpb
533 pulling from ../tmpb
535 requesting all changes
534 requesting all changes
536 adding changesets
535 adding changesets
537 adding manifests
536 adding manifests
538 adding file changes
537 adding file changes
539 added 4 changesets with 4 changes to 4 files (+1 heads)
538 added 4 changesets with 4 changes to 4 files (+1 heads)
540 5 new obsolescence markers
539 5 new obsolescence markers
541 new changesets 1f0dee641bb7:6f9641995072 (1 drafts)
540 new changesets 1f0dee641bb7:6f9641995072 (1 drafts)
542 (run 'hg heads' to see heads, 'hg merge' to merge)
541 (run 'hg heads' to see heads, 'hg merge' to merge)
543 $ hg debugobsolete
542 $ hg debugobsolete
544 1339133913391339133913391339133913391339 ca819180edb99ed25ceafb3e9584ac287e240b00 0 (Thu Jan 01 00:22:19 1970 +0000) {'user': 'test'}
543 1339133913391339133913391339133913391339 ca819180edb99ed25ceafb3e9584ac287e240b00 0 (Thu Jan 01 00:22:19 1970 +0000) {'user': 'test'}
545 1337133713371337133713371337133713371337 5601fb93a350734d935195fee37f4054c529ff39 0 (Thu Jan 01 00:22:19 1970 +0000) {'user': 'test'}
544 1337133713371337133713371337133713371337 5601fb93a350734d935195fee37f4054c529ff39 0 (Thu Jan 01 00:22:19 1970 +0000) {'user': 'test'}
546 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C (Thu Jan 01 00:00:01 1970 -0002) {'user': 'test'}
545 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C (Thu Jan 01 00:00:01 1970 -0002) {'user': 'test'}
547 5601fb93a350734d935195fee37f4054c529ff39 6f96419950729f3671185b847352890f074f7557 1 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
546 5601fb93a350734d935195fee37f4054c529ff39 6f96419950729f3671185b847352890f074f7557 1 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
548 ca819180edb99ed25ceafb3e9584ac287e240b00 1337133713371337133713371337133713371337 0 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
547 ca819180edb99ed25ceafb3e9584ac287e240b00 1337133713371337133713371337133713371337 0 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
549 cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 (Thu Jan 01 00:22:17 1970 +0000) {'user': 'test'}
548 cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 (Thu Jan 01 00:22:17 1970 +0000) {'user': 'test'}
550
549
551
550
552 On push
551 On push
553
552
554 $ hg push ../tmpc
553 $ hg push ../tmpc
555 pushing to ../tmpc
554 pushing to ../tmpc
556 searching for changes
555 searching for changes
557 no changes found
556 no changes found
558 1 new obsolescence markers
557 1 new obsolescence markers
559 [1]
558 [1]
560 $ hg -R ../tmpc debugobsolete
559 $ hg -R ../tmpc debugobsolete
561 1337133713371337133713371337133713371337 5601fb93a350734d935195fee37f4054c529ff39 0 (Thu Jan 01 00:22:19 1970 +0000) {'user': 'test'}
560 1337133713371337133713371337133713371337 5601fb93a350734d935195fee37f4054c529ff39 0 (Thu Jan 01 00:22:19 1970 +0000) {'user': 'test'}
562 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C (Thu Jan 01 00:00:01 1970 -0002) {'user': 'test'}
561 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C (Thu Jan 01 00:00:01 1970 -0002) {'user': 'test'}
563 5601fb93a350734d935195fee37f4054c529ff39 6f96419950729f3671185b847352890f074f7557 1 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
562 5601fb93a350734d935195fee37f4054c529ff39 6f96419950729f3671185b847352890f074f7557 1 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
564 ca819180edb99ed25ceafb3e9584ac287e240b00 1337133713371337133713371337133713371337 0 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
563 ca819180edb99ed25ceafb3e9584ac287e240b00 1337133713371337133713371337133713371337 0 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
565 cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 (Thu Jan 01 00:22:17 1970 +0000) {'user': 'test'}
564 cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 (Thu Jan 01 00:22:17 1970 +0000) {'user': 'test'}
566 1339133913391339133913391339133913391339 ca819180edb99ed25ceafb3e9584ac287e240b00 0 (Thu Jan 01 00:22:19 1970 +0000) {'user': 'test'}
565 1339133913391339133913391339133913391339 ca819180edb99ed25ceafb3e9584ac287e240b00 0 (Thu Jan 01 00:22:19 1970 +0000) {'user': 'test'}
567
566
568 detect outgoing obsolete and unstable
567 detect outgoing obsolete and unstable
569 ---------------------------------------
568 ---------------------------------------
570
569
571
570
572 $ hg log -G
571 $ hg log -G
573 o 3:6f9641995072 (draft) [tip ] add n3w_3_c
572 o 3:6f9641995072 (draft) [tip ] add n3w_3_c
574 |
573 |
575 | o 2:245bde4270cd (public) [ ] add original_c
574 | o 2:245bde4270cd (public) [ ] add original_c
576 |/
575 |/
577 o 1:7c3bad9141dc (public) [ ] add b
576 o 1:7c3bad9141dc (public) [ ] add b
578 |
577 |
579 o 0:1f0dee641bb7 (public) [ ] add a
578 o 0:1f0dee641bb7 (public) [ ] add a
580
579
581 $ hg up 'desc("n3w_3_c")'
580 $ hg up 'desc("n3w_3_c")'
582 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
581 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
583 $ mkcommit original_d
582 $ mkcommit original_d
584 $ mkcommit original_e
583 $ mkcommit original_e
585 $ hg debugobsolete --record-parents `getid original_d` -d '0 0'
584 $ hg debugobsolete --record-parents `getid original_d` -d '0 0'
586 1 new obsolescence markers
585 1 new obsolescence markers
587 obsoleted 1 changesets
586 obsoleted 1 changesets
588 1 new orphan changesets
587 1 new orphan changesets
589 $ hg log -r 'unstable()'
588 $ hg log -r 'unstable()'
590 5:cda648ca50f5 (draft orphan) [tip ] add original_e
589 5:cda648ca50f5 (draft orphan) [tip ] add original_e
591 $ hg debugobsolete | grep `getid original_d`
590 $ hg debugobsolete | grep `getid original_d`
592 94b33453f93bdb8d457ef9b770851a618bf413e1 0 {6f96419950729f3671185b847352890f074f7557} (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
591 94b33453f93bdb8d457ef9b770851a618bf413e1 0 {6f96419950729f3671185b847352890f074f7557} (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
593 $ hg log -r 'obsolete()'
592 $ hg log -r 'obsolete()'
594 4:94b33453f93b (draft *obsolete*) [ ] add original_d [pruned]
593 4:94b33453f93b (draft *obsolete*) [ ] add original_d [pruned]
595 $ hg summary
594 $ hg summary
596 parent: 5:cda648ca50f5 tip (orphan)
595 parent: 5:cda648ca50f5 tip (orphan)
597 add original_e
596 add original_e
598 branch: default
597 branch: default
599 commit: (clean)
598 commit: (clean)
600 update: 1 new changesets, 2 branch heads (merge)
599 update: 1 new changesets, 2 branch heads (merge)
601 phases: 3 draft
600 phases: 3 draft
602 orphan: 1 changesets
601 orphan: 1 changesets
603 $ hg log -G -r '::orphan()'
602 $ hg log -G -r '::orphan()'
604 @ 5:cda648ca50f5 (draft orphan) [tip ] add original_e
603 @ 5:cda648ca50f5 (draft orphan) [tip ] add original_e
605 |
604 |
606 x 4:94b33453f93b (draft *obsolete*) [ ] add original_d [pruned]
605 x 4:94b33453f93b (draft *obsolete*) [ ] add original_d [pruned]
607 |
606 |
608 o 3:6f9641995072 (draft) [ ] add n3w_3_c
607 o 3:6f9641995072 (draft) [ ] add n3w_3_c
609 |
608 |
610 o 1:7c3bad9141dc (public) [ ] add b
609 o 1:7c3bad9141dc (public) [ ] add b
611 |
610 |
612 o 0:1f0dee641bb7 (public) [ ] add a
611 o 0:1f0dee641bb7 (public) [ ] add a
613
612
614
613
615 refuse to push obsolete changeset
614 refuse to push obsolete changeset
616
615
617 $ hg push ../tmpc/ -r 'desc("original_d")'
616 $ hg push ../tmpc/ -r 'desc("original_d")'
618 pushing to ../tmpc/
617 pushing to ../tmpc/
619 searching for changes
618 searching for changes
620 abort: push includes obsolete changesets:
619 abort: push includes obsolete changeset: 94b33453f93b!
621 94b33453f93b
622 [255]
620 [255]
623
621
624 refuse to push unstable changeset
622 refuse to push unstable changeset
625
623
626 $ hg push ../tmpc/
624 $ hg push ../tmpc/
627 pushing to ../tmpc/
625 pushing to ../tmpc/
628 searching for changes
626 searching for changes
629 abort: push includes obsolete changesets:
627 abort: push includes orphan changeset: cda648ca50f5!
630 94b33453f93b
631 push includes unstable changesets:
632 cda648ca50f5 (orphan)
633 [255]
628 [255]
634
629
635 with --force it will work anyway
630 with --force it will work anyway
636
631
637 $ hg push ../tmpc/ --force
632 $ hg push ../tmpc/ --force
638 pushing to ../tmpc/
633 pushing to ../tmpc/
639 searching for changes
634 searching for changes
640 adding changesets
635 adding changesets
641 adding manifests
636 adding manifests
642 adding file changes
637 adding file changes
643 added 2 changesets with 2 changes to 2 files
638 added 2 changesets with 2 changes to 2 files
644 1 new obsolescence markers
639 1 new obsolescence markers
645 1 new orphan changesets
640 1 new orphan changesets
646
641
647 if the orphan changeset is already on the server, pushing should work
642 if the orphan changeset is already on the server, pushing should work
648
643
649 $ hg push ../tmpc/
644 $ hg push ../tmpc/
650 pushing to ../tmpc/
645 pushing to ../tmpc/
651 searching for changes
646 searching for changes
652 no changes found
647 no changes found
653 [1]
648 [1]
654
649
655 pushing should work even if the outgoing changes contain an unrelated changeset
656 (neither obsolete nor unstable) (issue6372)
657
658 $ hg up 1 -q
659 $ hg branch new -q
660 $ mkcommit c
661
662 $ hg push ../tmpc/ --new-branch
663 pushing to ../tmpc/
664 searching for changes
665 adding changesets
666 adding manifests
667 adding file changes
668 added 1 changesets with 1 changes to 1 files (+1 heads)
669
670 make later tests work unmodified
671
672 $ hg --config extensions.strip= strip tip -q
673 $ hg up 5 -q
674
675 Test that extinct changeset are properly detected
650 Test that extinct changeset are properly detected
676
651
677 $ hg log -r 'extinct()'
652 $ hg log -r 'extinct()'
678
653
679 Don't try to push extinct changeset
654 Don't try to push extinct changeset
680
655
681 $ hg init ../tmpf
656 $ hg init ../tmpf
682 $ hg out ../tmpf
657 $ hg out ../tmpf
683 comparing with ../tmpf
658 comparing with ../tmpf
684 searching for changes
659 searching for changes
685 0:1f0dee641bb7 (public) [ ] add a
660 0:1f0dee641bb7 (public) [ ] add a
686 1:7c3bad9141dc (public) [ ] add b
661 1:7c3bad9141dc (public) [ ] add b
687 2:245bde4270cd (public) [ ] add original_c
662 2:245bde4270cd (public) [ ] add original_c
688 3:6f9641995072 (draft) [ ] add n3w_3_c
663 3:6f9641995072 (draft) [ ] add n3w_3_c
689 4:94b33453f93b (draft *obsolete*) [ ] add original_d [pruned]
664 4:94b33453f93b (draft *obsolete*) [ ] add original_d [pruned]
690 5:cda648ca50f5 (draft orphan) [tip ] add original_e
665 5:cda648ca50f5 (draft orphan) [tip ] add original_e
691 $ hg push ../tmpf -f # -f because be push unstable too
666 $ hg push ../tmpf -f # -f because be push unstable too
692 pushing to ../tmpf
667 pushing to ../tmpf
693 searching for changes
668 searching for changes
694 adding changesets
669 adding changesets
695 adding manifests
670 adding manifests
696 adding file changes
671 adding file changes
697 added 6 changesets with 6 changes to 6 files (+1 heads)
672 added 6 changesets with 6 changes to 6 files (+1 heads)
698 7 new obsolescence markers
673 7 new obsolescence markers
699 1 new orphan changesets
674 1 new orphan changesets
700
675
701 no warning displayed
676 no warning displayed
702
677
703 $ hg push ../tmpf
678 $ hg push ../tmpf
704 pushing to ../tmpf
679 pushing to ../tmpf
705 searching for changes
680 searching for changes
706 no changes found
681 no changes found
707 [1]
682 [1]
708
683
709 Do not warn about new head when the new head is a successors of a remote one
684 Do not warn about new head when the new head is a successors of a remote one
710
685
711 $ hg log -G
686 $ hg log -G
712 @ 5:cda648ca50f5 (draft orphan) [tip ] add original_e
687 @ 5:cda648ca50f5 (draft orphan) [tip ] add original_e
713 |
688 |
714 x 4:94b33453f93b (draft *obsolete*) [ ] add original_d [pruned]
689 x 4:94b33453f93b (draft *obsolete*) [ ] add original_d [pruned]
715 |
690 |
716 o 3:6f9641995072 (draft) [ ] add n3w_3_c
691 o 3:6f9641995072 (draft) [ ] add n3w_3_c
717 |
692 |
718 | o 2:245bde4270cd (public) [ ] add original_c
693 | o 2:245bde4270cd (public) [ ] add original_c
719 |/
694 |/
720 o 1:7c3bad9141dc (public) [ ] add b
695 o 1:7c3bad9141dc (public) [ ] add b
721 |
696 |
722 o 0:1f0dee641bb7 (public) [ ] add a
697 o 0:1f0dee641bb7 (public) [ ] add a
723
698
724 $ hg up -q 'desc(n3w_3_c)'
699 $ hg up -q 'desc(n3w_3_c)'
725 $ mkcommit obsolete_e
700 $ mkcommit obsolete_e
726 created new head
701 created new head
727 $ hg debugobsolete `getid 'original_e'` `getid 'obsolete_e'` \
702 $ hg debugobsolete `getid 'original_e'` `getid 'obsolete_e'` \
728 > -u 'test <test@example.net>'
703 > -u 'test <test@example.net>'
729 1 new obsolescence markers
704 1 new obsolescence markers
730 obsoleted 1 changesets
705 obsoleted 1 changesets
731 $ hg outgoing ../tmpf # parasite hg outgoing testin
706 $ hg outgoing ../tmpf # parasite hg outgoing testin
732 comparing with ../tmpf
707 comparing with ../tmpf
733 searching for changes
708 searching for changes
734 6:3de5eca88c00 (draft) [tip ] add obsolete_e
709 6:3de5eca88c00 (draft) [tip ] add obsolete_e
735 $ hg push ../tmpf
710 $ hg push ../tmpf
736 pushing to ../tmpf
711 pushing to ../tmpf
737 searching for changes
712 searching for changes
738 adding changesets
713 adding changesets
739 adding manifests
714 adding manifests
740 adding file changes
715 adding file changes
741 added 1 changesets with 1 changes to 1 files (+1 heads)
716 added 1 changesets with 1 changes to 1 files (+1 heads)
742 1 new obsolescence markers
717 1 new obsolescence markers
743 obsoleted 1 changesets
718 obsoleted 1 changesets
744
719
745 test relevance computation
720 test relevance computation
746 ---------------------------------------
721 ---------------------------------------
747
722
748 Checking simple case of "marker relevance".
723 Checking simple case of "marker relevance".
749
724
750
725
751 Reminder of the repo situation
726 Reminder of the repo situation
752
727
753 $ hg log --hidden --graph
728 $ hg log --hidden --graph
754 @ 6:3de5eca88c00 (draft) [tip ] add obsolete_e
729 @ 6:3de5eca88c00 (draft) [tip ] add obsolete_e
755 |
730 |
756 | x 5:cda648ca50f5 (draft *obsolete*) [ ] add original_e [rewritten as 6:3de5eca88c00 by test <test@example.net>]
731 | x 5:cda648ca50f5 (draft *obsolete*) [ ] add original_e [rewritten as 6:3de5eca88c00 by test <test@example.net>]
757 | |
732 | |
758 | x 4:94b33453f93b (draft *obsolete*) [ ] add original_d [pruned]
733 | x 4:94b33453f93b (draft *obsolete*) [ ] add original_d [pruned]
759 |/
734 |/
760 o 3:6f9641995072 (draft) [ ] add n3w_3_c
735 o 3:6f9641995072 (draft) [ ] add n3w_3_c
761 |
736 |
762 | o 2:245bde4270cd (public) [ ] add original_c
737 | o 2:245bde4270cd (public) [ ] add original_c
763 |/
738 |/
764 o 1:7c3bad9141dc (public) [ ] add b
739 o 1:7c3bad9141dc (public) [ ] add b
765 |
740 |
766 o 0:1f0dee641bb7 (public) [ ] add a
741 o 0:1f0dee641bb7 (public) [ ] add a
767
742
768
743
769 List of all markers
744 List of all markers
770
745
771 $ hg debugobsolete
746 $ hg debugobsolete
772 1339133913391339133913391339133913391339 ca819180edb99ed25ceafb3e9584ac287e240b00 0 (Thu Jan 01 00:22:19 1970 +0000) {'user': 'test'}
747 1339133913391339133913391339133913391339 ca819180edb99ed25ceafb3e9584ac287e240b00 0 (Thu Jan 01 00:22:19 1970 +0000) {'user': 'test'}
773 1337133713371337133713371337133713371337 5601fb93a350734d935195fee37f4054c529ff39 0 (Thu Jan 01 00:22:19 1970 +0000) {'user': 'test'}
748 1337133713371337133713371337133713371337 5601fb93a350734d935195fee37f4054c529ff39 0 (Thu Jan 01 00:22:19 1970 +0000) {'user': 'test'}
774 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C (Thu Jan 01 00:00:01 1970 -0002) {'user': 'test'}
749 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C (Thu Jan 01 00:00:01 1970 -0002) {'user': 'test'}
775 5601fb93a350734d935195fee37f4054c529ff39 6f96419950729f3671185b847352890f074f7557 1 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
750 5601fb93a350734d935195fee37f4054c529ff39 6f96419950729f3671185b847352890f074f7557 1 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
776 ca819180edb99ed25ceafb3e9584ac287e240b00 1337133713371337133713371337133713371337 0 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
751 ca819180edb99ed25ceafb3e9584ac287e240b00 1337133713371337133713371337133713371337 0 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
777 cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 (Thu Jan 01 00:22:17 1970 +0000) {'user': 'test'}
752 cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 (Thu Jan 01 00:22:17 1970 +0000) {'user': 'test'}
778 94b33453f93bdb8d457ef9b770851a618bf413e1 0 {6f96419950729f3671185b847352890f074f7557} (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
753 94b33453f93bdb8d457ef9b770851a618bf413e1 0 {6f96419950729f3671185b847352890f074f7557} (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
779 cda648ca50f50482b7055c0b0c4c117bba6733d9 3de5eca88c00aa039da7399a220f4a5221faa585 0 (*) {'user': 'test <test@example.net>'} (glob)
754 cda648ca50f50482b7055c0b0c4c117bba6733d9 3de5eca88c00aa039da7399a220f4a5221faa585 0 (*) {'user': 'test <test@example.net>'} (glob)
780
755
781 List of changesets with no chain
756 List of changesets with no chain
782
757
783 $ hg debugobsolete --hidden --rev ::2
758 $ hg debugobsolete --hidden --rev ::2
784
759
785 List of changesets that are included on marker chain
760 List of changesets that are included on marker chain
786
761
787 $ hg debugobsolete --hidden --rev 6
762 $ hg debugobsolete --hidden --rev 6
788 cda648ca50f50482b7055c0b0c4c117bba6733d9 3de5eca88c00aa039da7399a220f4a5221faa585 0 (*) {'user': 'test <test@example.net>'} (glob)
763 cda648ca50f50482b7055c0b0c4c117bba6733d9 3de5eca88c00aa039da7399a220f4a5221faa585 0 (*) {'user': 'test <test@example.net>'} (glob)
789
764
790 List of changesets with a longer chain, (including a pruned children)
765 List of changesets with a longer chain, (including a pruned children)
791
766
792 $ hg debugobsolete --hidden --rev 3
767 $ hg debugobsolete --hidden --rev 3
793 1337133713371337133713371337133713371337 5601fb93a350734d935195fee37f4054c529ff39 0 (Thu Jan 01 00:22:19 1970 +0000) {'user': 'test'}
768 1337133713371337133713371337133713371337 5601fb93a350734d935195fee37f4054c529ff39 0 (Thu Jan 01 00:22:19 1970 +0000) {'user': 'test'}
794 1339133913391339133913391339133913391339 ca819180edb99ed25ceafb3e9584ac287e240b00 0 (Thu Jan 01 00:22:19 1970 +0000) {'user': 'test'}
769 1339133913391339133913391339133913391339 ca819180edb99ed25ceafb3e9584ac287e240b00 0 (Thu Jan 01 00:22:19 1970 +0000) {'user': 'test'}
795 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C (Thu Jan 01 00:00:01 1970 -0002) {'user': 'test'}
770 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C (Thu Jan 01 00:00:01 1970 -0002) {'user': 'test'}
796 5601fb93a350734d935195fee37f4054c529ff39 6f96419950729f3671185b847352890f074f7557 1 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
771 5601fb93a350734d935195fee37f4054c529ff39 6f96419950729f3671185b847352890f074f7557 1 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
797 94b33453f93bdb8d457ef9b770851a618bf413e1 0 {6f96419950729f3671185b847352890f074f7557} (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
772 94b33453f93bdb8d457ef9b770851a618bf413e1 0 {6f96419950729f3671185b847352890f074f7557} (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
798 ca819180edb99ed25ceafb3e9584ac287e240b00 1337133713371337133713371337133713371337 0 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
773 ca819180edb99ed25ceafb3e9584ac287e240b00 1337133713371337133713371337133713371337 0 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
799 cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 (Thu Jan 01 00:22:17 1970 +0000) {'user': 'test'}
774 cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 (Thu Jan 01 00:22:17 1970 +0000) {'user': 'test'}
800
775
801 List of both
776 List of both
802
777
803 $ hg debugobsolete --hidden --rev 3::6
778 $ hg debugobsolete --hidden --rev 3::6
804 1337133713371337133713371337133713371337 5601fb93a350734d935195fee37f4054c529ff39 0 (Thu Jan 01 00:22:19 1970 +0000) {'user': 'test'}
779 1337133713371337133713371337133713371337 5601fb93a350734d935195fee37f4054c529ff39 0 (Thu Jan 01 00:22:19 1970 +0000) {'user': 'test'}
805 1339133913391339133913391339133913391339 ca819180edb99ed25ceafb3e9584ac287e240b00 0 (Thu Jan 01 00:22:19 1970 +0000) {'user': 'test'}
780 1339133913391339133913391339133913391339 ca819180edb99ed25ceafb3e9584ac287e240b00 0 (Thu Jan 01 00:22:19 1970 +0000) {'user': 'test'}
806 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C (Thu Jan 01 00:00:01 1970 -0002) {'user': 'test'}
781 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C (Thu Jan 01 00:00:01 1970 -0002) {'user': 'test'}
807 5601fb93a350734d935195fee37f4054c529ff39 6f96419950729f3671185b847352890f074f7557 1 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
782 5601fb93a350734d935195fee37f4054c529ff39 6f96419950729f3671185b847352890f074f7557 1 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
808 94b33453f93bdb8d457ef9b770851a618bf413e1 0 {6f96419950729f3671185b847352890f074f7557} (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
783 94b33453f93bdb8d457ef9b770851a618bf413e1 0 {6f96419950729f3671185b847352890f074f7557} (Thu Jan 01 00:00:00 1970 +0000) {'user': 'test'}
809 ca819180edb99ed25ceafb3e9584ac287e240b00 1337133713371337133713371337133713371337 0 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
784 ca819180edb99ed25ceafb3e9584ac287e240b00 1337133713371337133713371337133713371337 0 (Thu Jan 01 00:22:18 1970 +0000) {'user': 'test'}
810 cda648ca50f50482b7055c0b0c4c117bba6733d9 3de5eca88c00aa039da7399a220f4a5221faa585 0 (*) {'user': 'test <test@example.net>'} (glob)
785 cda648ca50f50482b7055c0b0c4c117bba6733d9 3de5eca88c00aa039da7399a220f4a5221faa585 0 (*) {'user': 'test <test@example.net>'} (glob)
811 cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 (Thu Jan 01 00:22:17 1970 +0000) {'user': 'test'}
786 cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 (Thu Jan 01 00:22:17 1970 +0000) {'user': 'test'}
812
787
813 List of all markers in JSON
788 List of all markers in JSON
814
789
815 $ hg debugobsolete -Tjson
790 $ hg debugobsolete -Tjson
816 [
791 [
817 {
792 {
818 "date": [1339, 0],
793 "date": [1339, 0],
819 "flag": 0,
794 "flag": 0,
820 "metadata": {"user": "test"},
795 "metadata": {"user": "test"},
821 "prednode": "1339133913391339133913391339133913391339",
796 "prednode": "1339133913391339133913391339133913391339",
822 "succnodes": ["ca819180edb99ed25ceafb3e9584ac287e240b00"]
797 "succnodes": ["ca819180edb99ed25ceafb3e9584ac287e240b00"]
823 },
798 },
824 {
799 {
825 "date": [1339, 0],
800 "date": [1339, 0],
826 "flag": 0,
801 "flag": 0,
827 "metadata": {"user": "test"},
802 "metadata": {"user": "test"},
828 "prednode": "1337133713371337133713371337133713371337",
803 "prednode": "1337133713371337133713371337133713371337",
829 "succnodes": ["5601fb93a350734d935195fee37f4054c529ff39"]
804 "succnodes": ["5601fb93a350734d935195fee37f4054c529ff39"]
830 },
805 },
831 {
806 {
832 "date": [121, 120],
807 "date": [121, 120],
833 "flag": 12,
808 "flag": 12,
834 "metadata": {"user": "test"},
809 "metadata": {"user": "test"},
835 "prednode": "245bde4270cd1072a27757984f9cda8ba26f08ca",
810 "prednode": "245bde4270cd1072a27757984f9cda8ba26f08ca",
836 "succnodes": ["cdbce2fbb16313928851e97e0d85413f3f7eb77f"]
811 "succnodes": ["cdbce2fbb16313928851e97e0d85413f3f7eb77f"]
837 },
812 },
838 {
813 {
839 "date": [1338, 0],
814 "date": [1338, 0],
840 "flag": 1,
815 "flag": 1,
841 "metadata": {"user": "test"},
816 "metadata": {"user": "test"},
842 "prednode": "5601fb93a350734d935195fee37f4054c529ff39",
817 "prednode": "5601fb93a350734d935195fee37f4054c529ff39",
843 "succnodes": ["6f96419950729f3671185b847352890f074f7557"]
818 "succnodes": ["6f96419950729f3671185b847352890f074f7557"]
844 },
819 },
845 {
820 {
846 "date": [1338, 0],
821 "date": [1338, 0],
847 "flag": 0,
822 "flag": 0,
848 "metadata": {"user": "test"},
823 "metadata": {"user": "test"},
849 "prednode": "ca819180edb99ed25ceafb3e9584ac287e240b00",
824 "prednode": "ca819180edb99ed25ceafb3e9584ac287e240b00",
850 "succnodes": ["1337133713371337133713371337133713371337"]
825 "succnodes": ["1337133713371337133713371337133713371337"]
851 },
826 },
852 {
827 {
853 "date": [1337, 0],
828 "date": [1337, 0],
854 "flag": 0,
829 "flag": 0,
855 "metadata": {"user": "test"},
830 "metadata": {"user": "test"},
856 "prednode": "cdbce2fbb16313928851e97e0d85413f3f7eb77f",
831 "prednode": "cdbce2fbb16313928851e97e0d85413f3f7eb77f",
857 "succnodes": ["ca819180edb99ed25ceafb3e9584ac287e240b00"]
832 "succnodes": ["ca819180edb99ed25ceafb3e9584ac287e240b00"]
858 },
833 },
859 {
834 {
860 "date": [0, 0],
835 "date": [0, 0],
861 "flag": 0,
836 "flag": 0,
862 "metadata": {"user": "test"},
837 "metadata": {"user": "test"},
863 "parentnodes": ["6f96419950729f3671185b847352890f074f7557"],
838 "parentnodes": ["6f96419950729f3671185b847352890f074f7557"],
864 "prednode": "94b33453f93bdb8d457ef9b770851a618bf413e1",
839 "prednode": "94b33453f93bdb8d457ef9b770851a618bf413e1",
865 "succnodes": []
840 "succnodes": []
866 },
841 },
867 {
842 {
868 "date": *, (glob)
843 "date": *, (glob)
869 "flag": 0,
844 "flag": 0,
870 "metadata": {"user": "test <test@example.net>"},
845 "metadata": {"user": "test <test@example.net>"},
871 "prednode": "cda648ca50f50482b7055c0b0c4c117bba6733d9",
846 "prednode": "cda648ca50f50482b7055c0b0c4c117bba6733d9",
872 "succnodes": ["3de5eca88c00aa039da7399a220f4a5221faa585"]
847 "succnodes": ["3de5eca88c00aa039da7399a220f4a5221faa585"]
873 }
848 }
874 ]
849 ]
875
850
876 Template keywords
851 Template keywords
877
852
878 $ hg debugobsolete -r6 -T '{succnodes % "{node|short}"} {date|shortdate}\n'
853 $ hg debugobsolete -r6 -T '{succnodes % "{node|short}"} {date|shortdate}\n'
879 3de5eca88c00 ????-??-?? (glob)
854 3de5eca88c00 ????-??-?? (glob)
880 $ hg debugobsolete -r6 -T '{join(metadata % "{key}={value}", " ")}\n'
855 $ hg debugobsolete -r6 -T '{join(metadata % "{key}={value}", " ")}\n'
881 user=test <test@example.net>
856 user=test <test@example.net>
882 $ hg debugobsolete -r6 -T '{metadata}\n{metadata}\n'
857 $ hg debugobsolete -r6 -T '{metadata}\n{metadata}\n'
883 'user': 'test <test@example.net>'
858 'user': 'test <test@example.net>'
884 'user': 'test <test@example.net>'
859 'user': 'test <test@example.net>'
885 $ hg debugobsolete -r6 -T '{succnodes}\n{succnodes}\n'
860 $ hg debugobsolete -r6 -T '{succnodes}\n{succnodes}\n'
886 3de5eca88c00aa039da7399a220f4a5221faa585
861 3de5eca88c00aa039da7399a220f4a5221faa585
887 3de5eca88c00aa039da7399a220f4a5221faa585
862 3de5eca88c00aa039da7399a220f4a5221faa585
888 $ hg debugobsolete -r6 -T '{flag} {get(metadata, "user")}\n'
863 $ hg debugobsolete -r6 -T '{flag} {get(metadata, "user")}\n'
889 0 test <test@example.net>
864 0 test <test@example.net>
890
865
891 Test the debug output for exchange
866 Test the debug output for exchange
892 ----------------------------------
867 ----------------------------------
893
868
894 $ hg pull ../tmpb --config 'experimental.obsmarkers-exchange-debug=True' # bundle2
869 $ hg pull ../tmpb --config 'experimental.obsmarkers-exchange-debug=True' # bundle2
895 pulling from ../tmpb
870 pulling from ../tmpb
896 searching for changes
871 searching for changes
897 no changes found
872 no changes found
898 obsmarker-exchange: 346 bytes received
873 obsmarker-exchange: 346 bytes received
899
874
900 check hgweb does not explode
875 check hgweb does not explode
901 ====================================
876 ====================================
902
877
903 $ hg unbundle $TESTDIR/bundles/hgweb+obs.hg
878 $ hg unbundle $TESTDIR/bundles/hgweb+obs.hg
904 adding changesets
879 adding changesets
905 adding manifests
880 adding manifests
906 adding file changes
881 adding file changes
907 added 62 changesets with 63 changes to 9 files (+60 heads)
882 added 62 changesets with 63 changes to 9 files (+60 heads)
908 new changesets 50c51b361e60:c15e9edfca13 (62 drafts)
883 new changesets 50c51b361e60:c15e9edfca13 (62 drafts)
909 (2 other changesets obsolete on arrival)
884 (2 other changesets obsolete on arrival)
910 (run 'hg heads .' to see heads, 'hg merge' to merge)
885 (run 'hg heads .' to see heads, 'hg merge' to merge)
911 $ for node in `hg log -r 'desc(babar_)' --template '{node}\n'`;
886 $ for node in `hg log -r 'desc(babar_)' --template '{node}\n'`;
912 > do
887 > do
913 > hg debugobsolete $node
888 > hg debugobsolete $node
914 > done
889 > done
915 1 new obsolescence markers
890 1 new obsolescence markers
916 obsoleted 1 changesets
891 obsoleted 1 changesets
917 1 new obsolescence markers
892 1 new obsolescence markers
918 obsoleted 1 changesets
893 obsoleted 1 changesets
919 1 new obsolescence markers
894 1 new obsolescence markers
920 obsoleted 1 changesets
895 obsoleted 1 changesets
921 1 new obsolescence markers
896 1 new obsolescence markers
922 obsoleted 1 changesets
897 obsoleted 1 changesets
923 1 new obsolescence markers
898 1 new obsolescence markers
924 obsoleted 1 changesets
899 obsoleted 1 changesets
925 1 new obsolescence markers
900 1 new obsolescence markers
926 obsoleted 1 changesets
901 obsoleted 1 changesets
927 1 new obsolescence markers
902 1 new obsolescence markers
928 obsoleted 1 changesets
903 obsoleted 1 changesets
929 1 new obsolescence markers
904 1 new obsolescence markers
930 obsoleted 1 changesets
905 obsoleted 1 changesets
931 1 new obsolescence markers
906 1 new obsolescence markers
932 obsoleted 1 changesets
907 obsoleted 1 changesets
933 1 new obsolescence markers
908 1 new obsolescence markers
934 obsoleted 1 changesets
909 obsoleted 1 changesets
935 1 new obsolescence markers
910 1 new obsolescence markers
936 obsoleted 1 changesets
911 obsoleted 1 changesets
937 1 new obsolescence markers
912 1 new obsolescence markers
938 obsoleted 1 changesets
913 obsoleted 1 changesets
939 1 new obsolescence markers
914 1 new obsolescence markers
940 obsoleted 1 changesets
915 obsoleted 1 changesets
941 1 new obsolescence markers
916 1 new obsolescence markers
942 obsoleted 1 changesets
917 obsoleted 1 changesets
943 1 new obsolescence markers
918 1 new obsolescence markers
944 obsoleted 1 changesets
919 obsoleted 1 changesets
945 1 new obsolescence markers
920 1 new obsolescence markers
946 obsoleted 1 changesets
921 obsoleted 1 changesets
947 1 new obsolescence markers
922 1 new obsolescence markers
948 obsoleted 1 changesets
923 obsoleted 1 changesets
949 1 new obsolescence markers
924 1 new obsolescence markers
950 obsoleted 1 changesets
925 obsoleted 1 changesets
951 1 new obsolescence markers
926 1 new obsolescence markers
952 obsoleted 1 changesets
927 obsoleted 1 changesets
953 1 new obsolescence markers
928 1 new obsolescence markers
954 obsoleted 1 changesets
929 obsoleted 1 changesets
955 1 new obsolescence markers
930 1 new obsolescence markers
956 obsoleted 1 changesets
931 obsoleted 1 changesets
957 1 new obsolescence markers
932 1 new obsolescence markers
958 obsoleted 1 changesets
933 obsoleted 1 changesets
959 1 new obsolescence markers
934 1 new obsolescence markers
960 obsoleted 1 changesets
935 obsoleted 1 changesets
961 1 new obsolescence markers
936 1 new obsolescence markers
962 obsoleted 1 changesets
937 obsoleted 1 changesets
963 1 new obsolescence markers
938 1 new obsolescence markers
964 obsoleted 1 changesets
939 obsoleted 1 changesets
965 1 new obsolescence markers
940 1 new obsolescence markers
966 obsoleted 1 changesets
941 obsoleted 1 changesets
967 1 new obsolescence markers
942 1 new obsolescence markers
968 obsoleted 1 changesets
943 obsoleted 1 changesets
969 1 new obsolescence markers
944 1 new obsolescence markers
970 obsoleted 1 changesets
945 obsoleted 1 changesets
971 1 new obsolescence markers
946 1 new obsolescence markers
972 obsoleted 1 changesets
947 obsoleted 1 changesets
973 1 new obsolescence markers
948 1 new obsolescence markers
974 obsoleted 1 changesets
949 obsoleted 1 changesets
975 1 new obsolescence markers
950 1 new obsolescence markers
976 obsoleted 1 changesets
951 obsoleted 1 changesets
977 1 new obsolescence markers
952 1 new obsolescence markers
978 obsoleted 1 changesets
953 obsoleted 1 changesets
979 1 new obsolescence markers
954 1 new obsolescence markers
980 obsoleted 1 changesets
955 obsoleted 1 changesets
981 1 new obsolescence markers
956 1 new obsolescence markers
982 obsoleted 1 changesets
957 obsoleted 1 changesets
983 1 new obsolescence markers
958 1 new obsolescence markers
984 obsoleted 1 changesets
959 obsoleted 1 changesets
985 1 new obsolescence markers
960 1 new obsolescence markers
986 obsoleted 1 changesets
961 obsoleted 1 changesets
987 1 new obsolescence markers
962 1 new obsolescence markers
988 obsoleted 1 changesets
963 obsoleted 1 changesets
989 1 new obsolescence markers
964 1 new obsolescence markers
990 obsoleted 1 changesets
965 obsoleted 1 changesets
991 1 new obsolescence markers
966 1 new obsolescence markers
992 obsoleted 1 changesets
967 obsoleted 1 changesets
993 1 new obsolescence markers
968 1 new obsolescence markers
994 obsoleted 1 changesets
969 obsoleted 1 changesets
995 1 new obsolescence markers
970 1 new obsolescence markers
996 obsoleted 1 changesets
971 obsoleted 1 changesets
997 1 new obsolescence markers
972 1 new obsolescence markers
998 obsoleted 1 changesets
973 obsoleted 1 changesets
999 1 new obsolescence markers
974 1 new obsolescence markers
1000 obsoleted 1 changesets
975 obsoleted 1 changesets
1001 1 new obsolescence markers
976 1 new obsolescence markers
1002 obsoleted 1 changesets
977 obsoleted 1 changesets
1003 1 new obsolescence markers
978 1 new obsolescence markers
1004 obsoleted 1 changesets
979 obsoleted 1 changesets
1005 1 new obsolescence markers
980 1 new obsolescence markers
1006 obsoleted 1 changesets
981 obsoleted 1 changesets
1007 1 new obsolescence markers
982 1 new obsolescence markers
1008 obsoleted 1 changesets
983 obsoleted 1 changesets
1009 1 new obsolescence markers
984 1 new obsolescence markers
1010 obsoleted 1 changesets
985 obsoleted 1 changesets
1011 1 new obsolescence markers
986 1 new obsolescence markers
1012 obsoleted 1 changesets
987 obsoleted 1 changesets
1013 1 new obsolescence markers
988 1 new obsolescence markers
1014 obsoleted 1 changesets
989 obsoleted 1 changesets
1015 1 new obsolescence markers
990 1 new obsolescence markers
1016 obsoleted 1 changesets
991 obsoleted 1 changesets
1017 1 new obsolescence markers
992 1 new obsolescence markers
1018 obsoleted 1 changesets
993 obsoleted 1 changesets
1019 1 new obsolescence markers
994 1 new obsolescence markers
1020 obsoleted 1 changesets
995 obsoleted 1 changesets
1021 1 new obsolescence markers
996 1 new obsolescence markers
1022 obsoleted 1 changesets
997 obsoleted 1 changesets
1023 1 new obsolescence markers
998 1 new obsolescence markers
1024 obsoleted 1 changesets
999 obsoleted 1 changesets
1025 1 new obsolescence markers
1000 1 new obsolescence markers
1026 obsoleted 1 changesets
1001 obsoleted 1 changesets
1027 1 new obsolescence markers
1002 1 new obsolescence markers
1028 obsoleted 1 changesets
1003 obsoleted 1 changesets
1029 1 new obsolescence markers
1004 1 new obsolescence markers
1030 obsoleted 1 changesets
1005 obsoleted 1 changesets
1031 1 new obsolescence markers
1006 1 new obsolescence markers
1032 obsoleted 1 changesets
1007 obsoleted 1 changesets
1033 1 new obsolescence markers
1008 1 new obsolescence markers
1034 obsoleted 1 changesets
1009 obsoleted 1 changesets
1035 $ hg up tip
1010 $ hg up tip
1036 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
1011 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
1037
1012
1038 #if serve
1013 #if serve
1039
1014
1040 $ hg serve -n test -p $HGPORT -d --pid-file=hg.pid -A access.log -E errors.log
1015 $ hg serve -n test -p $HGPORT -d --pid-file=hg.pid -A access.log -E errors.log
1041 $ cat hg.pid >> $DAEMON_PIDS
1016 $ cat hg.pid >> $DAEMON_PIDS
1042
1017
1043 check changelog view
1018 check changelog view
1044
1019
1045 $ get-with-headers.py --headeronly localhost:$HGPORT 'shortlog/'
1020 $ get-with-headers.py --headeronly localhost:$HGPORT 'shortlog/'
1046 200 Script output follows
1021 200 Script output follows
1047
1022
1048 check graph view
1023 check graph view
1049
1024
1050 $ get-with-headers.py --headeronly localhost:$HGPORT 'graph'
1025 $ get-with-headers.py --headeronly localhost:$HGPORT 'graph'
1051 200 Script output follows
1026 200 Script output follows
1052
1027
1053 check filelog view
1028 check filelog view
1054
1029
1055 $ get-with-headers.py --headeronly localhost:$HGPORT 'log/'`hg log -r . -T "{node}"`/'babar'
1030 $ get-with-headers.py --headeronly localhost:$HGPORT 'log/'`hg log -r . -T "{node}"`/'babar'
1056 200 Script output follows
1031 200 Script output follows
1057
1032
1058 check filelog view for hidden commits (obsolete ones are hidden here)
1033 check filelog view for hidden commits (obsolete ones are hidden here)
1059
1034
1060 $ get-with-headers.py localhost:$HGPORT 'log/'`hg log -r . -T "{node}"`/'babar' | grep obsolete
1035 $ get-with-headers.py localhost:$HGPORT 'log/'`hg log -r . -T "{node}"`/'babar' | grep obsolete
1061 [1]
1036 [1]
1062
1037
1063 $ get-with-headers.py --headeronly localhost:$HGPORT 'rev/68'
1038 $ get-with-headers.py --headeronly localhost:$HGPORT 'rev/68'
1064 200 Script output follows
1039 200 Script output follows
1065 $ get-with-headers.py --headeronly localhost:$HGPORT 'rev/67'
1040 $ get-with-headers.py --headeronly localhost:$HGPORT 'rev/67'
1066 404 Not Found
1041 404 Not Found
1067 [1]
1042 [1]
1068
1043
1069 check that web.view config option:
1044 check that web.view config option:
1070
1045
1071 $ killdaemons.py hg.pid
1046 $ killdaemons.py hg.pid
1072 $ cat >> .hg/hgrc << EOF
1047 $ cat >> .hg/hgrc << EOF
1073 > [web]
1048 > [web]
1074 > view=all
1049 > view=all
1075 > EOF
1050 > EOF
1076 $ wait
1051 $ wait
1077 $ hg serve -n test -p $HGPORT -d --pid-file=hg.pid -A access.log -E errors.log
1052 $ hg serve -n test -p $HGPORT -d --pid-file=hg.pid -A access.log -E errors.log
1078 $ get-with-headers.py --headeronly localhost:$HGPORT 'rev/67'
1053 $ get-with-headers.py --headeronly localhost:$HGPORT 'rev/67'
1079 200 Script output follows
1054 200 Script output follows
1080 $ killdaemons.py hg.pid
1055 $ killdaemons.py hg.pid
1081
1056
1082 Checking _enable=False warning if obsolete marker exists
1057 Checking _enable=False warning if obsolete marker exists
1083
1058
1084 $ echo '[experimental]' >> $HGRCPATH
1059 $ echo '[experimental]' >> $HGRCPATH
1085 $ echo "evolution=" >> $HGRCPATH
1060 $ echo "evolution=" >> $HGRCPATH
1086 $ hg log -r tip
1061 $ hg log -r tip
1087 68:c15e9edfca13 (draft) [tip ] add celestine
1062 68:c15e9edfca13 (draft) [tip ] add celestine
1088
1063
1089 reenable for later test
1064 reenable for later test
1090
1065
1091 $ echo '[experimental]' >> $HGRCPATH
1066 $ echo '[experimental]' >> $HGRCPATH
1092 $ echo "evolution.exchange=True" >> $HGRCPATH
1067 $ echo "evolution.exchange=True" >> $HGRCPATH
1093 $ echo "evolution.createmarkers=True" >> $HGRCPATH
1068 $ echo "evolution.createmarkers=True" >> $HGRCPATH
1094
1069
1095 $ rm access.log errors.log
1070 $ rm access.log errors.log
1096 #endif
1071 #endif
1097
1072
1098 Several troubles on the same changeset (create an unstable and bumped and content-divergent changeset)
1073 Several troubles on the same changeset (create an unstable and bumped and content-divergent changeset)
1099
1074
1100 $ hg debugobsolete `getid obsolete_e`
1075 $ hg debugobsolete `getid obsolete_e`
1101 1 new obsolescence markers
1076 1 new obsolescence markers
1102 obsoleted 1 changesets
1077 obsoleted 1 changesets
1103 2 new orphan changesets
1078 2 new orphan changesets
1104 $ hg debugobsolete `getid original_c` `getid babar`
1079 $ hg debugobsolete `getid original_c` `getid babar`
1105 1 new obsolescence markers
1080 1 new obsolescence markers
1106 1 new phase-divergent changesets
1081 1 new phase-divergent changesets
1107 2 new content-divergent changesets
1082 2 new content-divergent changesets
1108 $ hg log --config ui.logtemplate= -r 'phasedivergent() and orphan() and contentdivergent()'
1083 $ hg log --config ui.logtemplate= -r 'phasedivergent() and orphan() and contentdivergent()'
1109 changeset: 7:50c51b361e60
1084 changeset: 7:50c51b361e60
1110 user: test
1085 user: test
1111 date: Thu Jan 01 00:00:00 1970 +0000
1086 date: Thu Jan 01 00:00:00 1970 +0000
1112 instability: orphan, phase-divergent, content-divergent
1087 instability: orphan, phase-divergent, content-divergent
1113 summary: add babar
1088 summary: add babar
1114
1089
1115 test the "obsolete" templatekw
1090 test the "obsolete" templatekw
1116
1091
1117 $ hg log -r 'obsolete()'
1092 $ hg log -r 'obsolete()'
1118 6:3de5eca88c00 (draft *obsolete*) [ ] add obsolete_e [pruned]
1093 6:3de5eca88c00 (draft *obsolete*) [ ] add obsolete_e [pruned]
1119
1094
1120 test the "troubles" templatekw
1095 test the "troubles" templatekw
1121
1096
1122 $ hg log -r 'phasedivergent() and orphan()'
1097 $ hg log -r 'phasedivergent() and orphan()'
1123 7:50c51b361e60 (draft orphan phase-divergent content-divergent) [ ] add babar
1098 7:50c51b361e60 (draft orphan phase-divergent content-divergent) [ ] add babar
1124
1099
1125 test the default cmdline template
1100 test the default cmdline template
1126
1101
1127 $ hg log -T default -r 'phasedivergent()'
1102 $ hg log -T default -r 'phasedivergent()'
1128 changeset: 7:50c51b361e60
1103 changeset: 7:50c51b361e60
1129 user: test
1104 user: test
1130 date: Thu Jan 01 00:00:00 1970 +0000
1105 date: Thu Jan 01 00:00:00 1970 +0000
1131 instability: orphan, phase-divergent, content-divergent
1106 instability: orphan, phase-divergent, content-divergent
1132 summary: add babar
1107 summary: add babar
1133
1108
1134 $ hg log -T default -r 'obsolete()'
1109 $ hg log -T default -r 'obsolete()'
1135 changeset: 6:3de5eca88c00
1110 changeset: 6:3de5eca88c00
1136 parent: 3:6f9641995072
1111 parent: 3:6f9641995072
1137 user: test
1112 user: test
1138 date: Thu Jan 01 00:00:00 1970 +0000
1113 date: Thu Jan 01 00:00:00 1970 +0000
1139 obsolete: pruned
1114 obsolete: pruned
1140 summary: add obsolete_e
1115 summary: add obsolete_e
1141
1116
1142
1117
1143 test the obsolete labels
1118 test the obsolete labels
1144
1119
1145 $ hg log --config ui.logtemplate= --color=debug -r 'phasedivergent()'
1120 $ hg log --config ui.logtemplate= --color=debug -r 'phasedivergent()'
1146 [log.changeset changeset.draft changeset.unstable instability.orphan instability.phase-divergent instability.content-divergent|changeset: 7:50c51b361e60]
1121 [log.changeset changeset.draft changeset.unstable instability.orphan instability.phase-divergent instability.content-divergent|changeset: 7:50c51b361e60]
1147 [log.user|user: test]
1122 [log.user|user: test]
1148 [log.date|date: Thu Jan 01 00:00:00 1970 +0000]
1123 [log.date|date: Thu Jan 01 00:00:00 1970 +0000]
1149 [log.instability|instability: orphan, phase-divergent, content-divergent]
1124 [log.instability|instability: orphan, phase-divergent, content-divergent]
1150 [log.summary|summary: add babar]
1125 [log.summary|summary: add babar]
1151
1126
1152
1127
1153 $ hg log -T default -r 'phasedivergent()' --color=debug
1128 $ hg log -T default -r 'phasedivergent()' --color=debug
1154 [log.changeset changeset.draft changeset.unstable instability.orphan instability.phase-divergent instability.content-divergent|changeset: 7:50c51b361e60]
1129 [log.changeset changeset.draft changeset.unstable instability.orphan instability.phase-divergent instability.content-divergent|changeset: 7:50c51b361e60]
1155 [log.user|user: test]
1130 [log.user|user: test]
1156 [log.date|date: Thu Jan 01 00:00:00 1970 +0000]
1131 [log.date|date: Thu Jan 01 00:00:00 1970 +0000]
1157 [log.instability|instability: orphan, phase-divergent, content-divergent]
1132 [log.instability|instability: orphan, phase-divergent, content-divergent]
1158 [log.summary|summary: add babar]
1133 [log.summary|summary: add babar]
1159
1134
1160
1135
1161 $ hg log --config ui.logtemplate= --color=debug -r "obsolete()"
1136 $ hg log --config ui.logtemplate= --color=debug -r "obsolete()"
1162 [log.changeset changeset.draft changeset.obsolete|changeset: 6:3de5eca88c00]
1137 [log.changeset changeset.draft changeset.obsolete|changeset: 6:3de5eca88c00]
1163 [log.parent changeset.draft|parent: 3:6f9641995072]
1138 [log.parent changeset.draft|parent: 3:6f9641995072]
1164 [log.user|user: test]
1139 [log.user|user: test]
1165 [log.date|date: Thu Jan 01 00:00:00 1970 +0000]
1140 [log.date|date: Thu Jan 01 00:00:00 1970 +0000]
1166 [log.obsfate|obsolete: pruned]
1141 [log.obsfate|obsolete: pruned]
1167 [log.summary|summary: add obsolete_e]
1142 [log.summary|summary: add obsolete_e]
1168
1143
1169
1144
1170 $ hg log -T default -r 'obsolete()' --color=debug
1145 $ hg log -T default -r 'obsolete()' --color=debug
1171 [log.changeset changeset.draft changeset.obsolete|changeset: 6:3de5eca88c00]
1146 [log.changeset changeset.draft changeset.obsolete|changeset: 6:3de5eca88c00]
1172 [log.parent changeset.draft|parent: 3:6f9641995072]
1147 [log.parent changeset.draft|parent: 3:6f9641995072]
1173 [log.user|user: test]
1148 [log.user|user: test]
1174 [log.date|date: Thu Jan 01 00:00:00 1970 +0000]
1149 [log.date|date: Thu Jan 01 00:00:00 1970 +0000]
1175 [log.obsfate|obsolete: pruned]
1150 [log.obsfate|obsolete: pruned]
1176 [log.summary|summary: add obsolete_e]
1151 [log.summary|summary: add obsolete_e]
1177
1152
1178
1153
1179 test summary output
1154 test summary output
1180
1155
1181 $ hg up -r 'phasedivergent() and orphan()'
1156 $ hg up -r 'phasedivergent() and orphan()'
1182 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
1157 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
1183 $ hg summary
1158 $ hg summary
1184 parent: 7:50c51b361e60 (orphan, phase-divergent, content-divergent)
1159 parent: 7:50c51b361e60 (orphan, phase-divergent, content-divergent)
1185 add babar
1160 add babar
1186 branch: default
1161 branch: default
1187 commit: (clean)
1162 commit: (clean)
1188 update: 2 new changesets (update)
1163 update: 2 new changesets (update)
1189 phases: 4 draft
1164 phases: 4 draft
1190 orphan: 2 changesets
1165 orphan: 2 changesets
1191 content-divergent: 2 changesets
1166 content-divergent: 2 changesets
1192 phase-divergent: 1 changesets
1167 phase-divergent: 1 changesets
1193 $ hg up -r 'obsolete()'
1168 $ hg up -r 'obsolete()'
1194 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
1169 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
1195 $ hg summary
1170 $ hg summary
1196 parent: 6:3de5eca88c00 (obsolete)
1171 parent: 6:3de5eca88c00 (obsolete)
1197 add obsolete_e
1172 add obsolete_e
1198 branch: default
1173 branch: default
1199 commit: (clean)
1174 commit: (clean)
1200 update: 3 new changesets (update)
1175 update: 3 new changesets (update)
1201 phases: 4 draft
1176 phases: 4 draft
1202 orphan: 2 changesets
1177 orphan: 2 changesets
1203 content-divergent: 2 changesets
1178 content-divergent: 2 changesets
1204 phase-divergent: 1 changesets
1179 phase-divergent: 1 changesets
1205
1180
1206 test debugwhyunstable output
1181 test debugwhyunstable output
1207
1182
1208 $ hg debugwhyunstable 50c51b361e60
1183 $ hg debugwhyunstable 50c51b361e60
1209 orphan: obsolete parent 3de5eca88c00aa039da7399a220f4a5221faa585
1184 orphan: obsolete parent 3de5eca88c00aa039da7399a220f4a5221faa585
1210 phase-divergent: immutable predecessor 245bde4270cd1072a27757984f9cda8ba26f08ca
1185 phase-divergent: immutable predecessor 245bde4270cd1072a27757984f9cda8ba26f08ca
1211 content-divergent: 6f96419950729f3671185b847352890f074f7557 (draft) predecessor 245bde4270cd1072a27757984f9cda8ba26f08ca
1186 content-divergent: 6f96419950729f3671185b847352890f074f7557 (draft) predecessor 245bde4270cd1072a27757984f9cda8ba26f08ca
1212
1187
1213 test whyunstable template keyword
1188 test whyunstable template keyword
1214
1189
1215 $ hg log -r 50c51b361e60 -T '{whyunstable}\n'
1190 $ hg log -r 50c51b361e60 -T '{whyunstable}\n'
1216 orphan: obsolete parent 3de5eca88c00
1191 orphan: obsolete parent 3de5eca88c00
1217 phase-divergent: immutable predecessor 245bde4270cd
1192 phase-divergent: immutable predecessor 245bde4270cd
1218 content-divergent: 3:6f9641995072 (draft) predecessor 245bde4270cd
1193 content-divergent: 3:6f9641995072 (draft) predecessor 245bde4270cd
1219 $ hg log -r 50c51b361e60 -T '{whyunstable % "{instability}: {reason} {node|shortest}\n"}'
1194 $ hg log -r 50c51b361e60 -T '{whyunstable % "{instability}: {reason} {node|shortest}\n"}'
1220 orphan: obsolete parent 3de5
1195 orphan: obsolete parent 3de5
1221 phase-divergent: immutable predecessor 245b
1196 phase-divergent: immutable predecessor 245b
1222 content-divergent: predecessor 245b
1197 content-divergent: predecessor 245b
1223
1198
1224 $ hg push ../tmpf -r 50c51b361e60
1225 pushing to ../tmpf
1226 searching for changes
1227 abort: push includes unstable changesets:
1228 50c51b361e60 (orphan, phase-divergent, content-divergent)
1229 [255]
1230
1231
1232 #if serve
1199 #if serve
1233
1200
1234 $ hg serve -n test -p $HGPORT -d --pid-file=hg.pid -A access.log -E errors.log
1201 $ hg serve -n test -p $HGPORT -d --pid-file=hg.pid -A access.log -E errors.log
1235 $ cat hg.pid >> $DAEMON_PIDS
1202 $ cat hg.pid >> $DAEMON_PIDS
1236
1203
1237 check obsolete changeset
1204 check obsolete changeset
1238
1205
1239 $ get-with-headers.py localhost:$HGPORT 'log?rev=first(obsolete())&style=paper' | grep '<span class="obsolete">'
1206 $ get-with-headers.py localhost:$HGPORT 'log?rev=first(obsolete())&style=paper' | grep '<span class="obsolete">'
1240 <span class="phase">draft</span> <span class="obsolete">obsolete</span>
1207 <span class="phase">draft</span> <span class="obsolete">obsolete</span>
1241 $ get-with-headers.py localhost:$HGPORT 'log?rev=first(obsolete())&style=coal' | grep '<span class="obsolete">'
1208 $ get-with-headers.py localhost:$HGPORT 'log?rev=first(obsolete())&style=coal' | grep '<span class="obsolete">'
1242 <span class="phase">draft</span> <span class="obsolete">obsolete</span>
1209 <span class="phase">draft</span> <span class="obsolete">obsolete</span>
1243 $ get-with-headers.py localhost:$HGPORT 'log?rev=first(obsolete())&style=gitweb' | grep '<span class="logtags">'
1210 $ get-with-headers.py localhost:$HGPORT 'log?rev=first(obsolete())&style=gitweb' | grep '<span class="logtags">'
1244 <span class="logtags"><span class="phasetag" title="draft">draft</span> <span class="obsoletetag" title="obsolete">obsolete</span> </span>
1211 <span class="logtags"><span class="phasetag" title="draft">draft</span> <span class="obsoletetag" title="obsolete">obsolete</span> </span>
1245 $ get-with-headers.py localhost:$HGPORT 'log?rev=first(obsolete())&style=monoblue' | grep '<span class="logtags">'
1212 $ get-with-headers.py localhost:$HGPORT 'log?rev=first(obsolete())&style=monoblue' | grep '<span class="logtags">'
1246 <span class="logtags"><span class="phasetag" title="draft">draft</span> <span class="obsoletetag" title="obsolete">obsolete</span> </span>
1213 <span class="logtags"><span class="phasetag" title="draft">draft</span> <span class="obsoletetag" title="obsolete">obsolete</span> </span>
1247 $ get-with-headers.py localhost:$HGPORT 'log?rev=first(obsolete())&style=spartan' | grep 'class="obsolete"'
1214 $ get-with-headers.py localhost:$HGPORT 'log?rev=first(obsolete())&style=spartan' | grep 'class="obsolete"'
1248 <th class="obsolete">obsolete:</th>
1215 <th class="obsolete">obsolete:</th>
1249 <td class="obsolete">pruned by &#116;&#101;&#115;&#116; <span class="age">Thu, 01 Jan 1970 00:00:00 +0000</span></td>
1216 <td class="obsolete">pruned by &#116;&#101;&#115;&#116; <span class="age">Thu, 01 Jan 1970 00:00:00 +0000</span></td>
1250
1217
1251 check changeset with instabilities
1218 check changeset with instabilities
1252
1219
1253 $ get-with-headers.py localhost:$HGPORT 'log?rev=first(phasedivergent())&style=paper' | grep '<span class="instability">'
1220 $ get-with-headers.py localhost:$HGPORT 'log?rev=first(phasedivergent())&style=paper' | grep '<span class="instability">'
1254 <span class="phase">draft</span> <span class="instability">orphan</span> <span class="instability">phase-divergent</span> <span class="instability">content-divergent</span>
1221 <span class="phase">draft</span> <span class="instability">orphan</span> <span class="instability">phase-divergent</span> <span class="instability">content-divergent</span>
1255 $ get-with-headers.py localhost:$HGPORT 'log?rev=first(phasedivergent())&style=coal' | grep '<span class="instability">'
1222 $ get-with-headers.py localhost:$HGPORT 'log?rev=first(phasedivergent())&style=coal' | grep '<span class="instability">'
1256 <span class="phase">draft</span> <span class="instability">orphan</span> <span class="instability">phase-divergent</span> <span class="instability">content-divergent</span>
1223 <span class="phase">draft</span> <span class="instability">orphan</span> <span class="instability">phase-divergent</span> <span class="instability">content-divergent</span>
1257 $ get-with-headers.py localhost:$HGPORT 'log?rev=first(phasedivergent())&style=gitweb' | grep '<span class="logtags">'
1224 $ get-with-headers.py localhost:$HGPORT 'log?rev=first(phasedivergent())&style=gitweb' | grep '<span class="logtags">'
1258 <span class="logtags"><span class="phasetag" title="draft">draft</span> <span class="instabilitytag" title="orphan">orphan</span> <span class="instabilitytag" title="phase-divergent">phase-divergent</span> <span class="instabilitytag" title="content-divergent">content-divergent</span> </span>
1225 <span class="logtags"><span class="phasetag" title="draft">draft</span> <span class="instabilitytag" title="orphan">orphan</span> <span class="instabilitytag" title="phase-divergent">phase-divergent</span> <span class="instabilitytag" title="content-divergent">content-divergent</span> </span>
1259 $ get-with-headers.py localhost:$HGPORT 'log?rev=first(phasedivergent())&style=monoblue' | grep '<span class="logtags">'
1226 $ get-with-headers.py localhost:$HGPORT 'log?rev=first(phasedivergent())&style=monoblue' | grep '<span class="logtags">'
1260 <span class="logtags"><span class="phasetag" title="draft">draft</span> <span class="instabilitytag" title="orphan">orphan</span> <span class="instabilitytag" title="phase-divergent">phase-divergent</span> <span class="instabilitytag" title="content-divergent">content-divergent</span> </span>
1227 <span class="logtags"><span class="phasetag" title="draft">draft</span> <span class="instabilitytag" title="orphan">orphan</span> <span class="instabilitytag" title="phase-divergent">phase-divergent</span> <span class="instabilitytag" title="content-divergent">content-divergent</span> </span>
1261 $ get-with-headers.py localhost:$HGPORT 'log?rev=first(phasedivergent())&style=spartan' | grep 'class="unstable"'
1228 $ get-with-headers.py localhost:$HGPORT 'log?rev=first(phasedivergent())&style=spartan' | grep 'class="unstable"'
1262 <th class="unstable">unstable:</th>
1229 <th class="unstable">unstable:</th>
1263 <td class="unstable">orphan: obsolete parent <a href="/rev/3de5eca88c00?style=spartan">3de5eca88c00</a></td>
1230 <td class="unstable">orphan: obsolete parent <a href="/rev/3de5eca88c00?style=spartan">3de5eca88c00</a></td>
1264 <th class="unstable">unstable:</th>
1231 <th class="unstable">unstable:</th>
1265 <td class="unstable">phase-divergent: immutable predecessor <a href="/rev/245bde4270cd?style=spartan">245bde4270cd</a></td>
1232 <td class="unstable">phase-divergent: immutable predecessor <a href="/rev/245bde4270cd?style=spartan">245bde4270cd</a></td>
1266 <th class="unstable">unstable:</th>
1233 <th class="unstable">unstable:</th>
1267 <td class="unstable">content-divergent: <a href="/rev/6f9641995072?style=spartan">6f9641995072</a> (draft) predecessor <a href="/rev/245bde4270cd?style=spartan">245bde4270cd</a></td>
1234 <td class="unstable">content-divergent: <a href="/rev/6f9641995072?style=spartan">6f9641995072</a> (draft) predecessor <a href="/rev/245bde4270cd?style=spartan">245bde4270cd</a></td>
1268
1235
1269 check explanation for an orphan, phase-divergent and content-divergent changeset
1236 check explanation for an orphan, phase-divergent and content-divergent changeset
1270
1237
1271 $ get-with-headers.py localhost:$HGPORT 'rev/50c51b361e60?style=paper' | egrep '(orphan|phase-divergent|content-divergent):'
1238 $ get-with-headers.py localhost:$HGPORT 'rev/50c51b361e60?style=paper' | egrep '(orphan|phase-divergent|content-divergent):'
1272 <td>orphan: obsolete parent <a href="/rev/3de5eca88c00?style=paper">3de5eca88c00</a><br>
1239 <td>orphan: obsolete parent <a href="/rev/3de5eca88c00?style=paper">3de5eca88c00</a><br>
1273 phase-divergent: immutable predecessor <a href="/rev/245bde4270cd?style=paper">245bde4270cd</a><br>
1240 phase-divergent: immutable predecessor <a href="/rev/245bde4270cd?style=paper">245bde4270cd</a><br>
1274 content-divergent: <a href="/rev/6f9641995072?style=paper">6f9641995072</a> (draft) predecessor <a href="/rev/245bde4270cd?style=paper">245bde4270cd</a></td>
1241 content-divergent: <a href="/rev/6f9641995072?style=paper">6f9641995072</a> (draft) predecessor <a href="/rev/245bde4270cd?style=paper">245bde4270cd</a></td>
1275 $ get-with-headers.py localhost:$HGPORT 'rev/50c51b361e60?style=coal' | egrep '(orphan|phase-divergent|content-divergent):'
1242 $ get-with-headers.py localhost:$HGPORT 'rev/50c51b361e60?style=coal' | egrep '(orphan|phase-divergent|content-divergent):'
1276 <td>orphan: obsolete parent <a href="/rev/3de5eca88c00?style=coal">3de5eca88c00</a><br>
1243 <td>orphan: obsolete parent <a href="/rev/3de5eca88c00?style=coal">3de5eca88c00</a><br>
1277 phase-divergent: immutable predecessor <a href="/rev/245bde4270cd?style=coal">245bde4270cd</a><br>
1244 phase-divergent: immutable predecessor <a href="/rev/245bde4270cd?style=coal">245bde4270cd</a><br>
1278 content-divergent: <a href="/rev/6f9641995072?style=coal">6f9641995072</a> (draft) predecessor <a href="/rev/245bde4270cd?style=coal">245bde4270cd</a></td>
1245 content-divergent: <a href="/rev/6f9641995072?style=coal">6f9641995072</a> (draft) predecessor <a href="/rev/245bde4270cd?style=coal">245bde4270cd</a></td>
1279 $ get-with-headers.py localhost:$HGPORT 'rev/50c51b361e60?style=gitweb' | egrep '(orphan|phase-divergent|content-divergent):'
1246 $ get-with-headers.py localhost:$HGPORT 'rev/50c51b361e60?style=gitweb' | egrep '(orphan|phase-divergent|content-divergent):'
1280 <td>orphan: obsolete parent <a class="list" href="/rev/3de5eca88c00?style=gitweb">3de5eca88c00</a></td>
1247 <td>orphan: obsolete parent <a class="list" href="/rev/3de5eca88c00?style=gitweb">3de5eca88c00</a></td>
1281 <td>phase-divergent: immutable predecessor <a class="list" href="/rev/245bde4270cd?style=gitweb">245bde4270cd</a></td>
1248 <td>phase-divergent: immutable predecessor <a class="list" href="/rev/245bde4270cd?style=gitweb">245bde4270cd</a></td>
1282 <td>content-divergent: <a class="list" href="/rev/6f9641995072?style=gitweb">6f9641995072</a> (draft) predecessor <a class="list" href="/rev/245bde4270cd?style=gitweb">245bde4270cd</a></td>
1249 <td>content-divergent: <a class="list" href="/rev/6f9641995072?style=gitweb">6f9641995072</a> (draft) predecessor <a class="list" href="/rev/245bde4270cd?style=gitweb">245bde4270cd</a></td>
1283 $ get-with-headers.py localhost:$HGPORT 'rev/50c51b361e60?style=monoblue' | egrep '(orphan|phase-divergent|content-divergent):'
1250 $ get-with-headers.py localhost:$HGPORT 'rev/50c51b361e60?style=monoblue' | egrep '(orphan|phase-divergent|content-divergent):'
1284 <dd>orphan: obsolete parent <a href="/rev/3de5eca88c00?style=monoblue">3de5eca88c00</a></dd>
1251 <dd>orphan: obsolete parent <a href="/rev/3de5eca88c00?style=monoblue">3de5eca88c00</a></dd>
1285 <dd>phase-divergent: immutable predecessor <a href="/rev/245bde4270cd?style=monoblue">245bde4270cd</a></dd>
1252 <dd>phase-divergent: immutable predecessor <a href="/rev/245bde4270cd?style=monoblue">245bde4270cd</a></dd>
1286 <dd>content-divergent: <a href="/rev/6f9641995072?style=monoblue">6f9641995072</a> (draft) predecessor <a href="/rev/245bde4270cd?style=monoblue">245bde4270cd</a></dd>
1253 <dd>content-divergent: <a href="/rev/6f9641995072?style=monoblue">6f9641995072</a> (draft) predecessor <a href="/rev/245bde4270cd?style=monoblue">245bde4270cd</a></dd>
1287 $ get-with-headers.py localhost:$HGPORT 'rev/50c51b361e60?style=spartan' | egrep '(orphan|phase-divergent|content-divergent):'
1254 $ get-with-headers.py localhost:$HGPORT 'rev/50c51b361e60?style=spartan' | egrep '(orphan|phase-divergent|content-divergent):'
1288 <td class="unstable">orphan: obsolete parent <a href="/rev/3de5eca88c00?style=spartan">3de5eca88c00</a></td>
1255 <td class="unstable">orphan: obsolete parent <a href="/rev/3de5eca88c00?style=spartan">3de5eca88c00</a></td>
1289 <td class="unstable">phase-divergent: immutable predecessor <a href="/rev/245bde4270cd?style=spartan">245bde4270cd</a></td>
1256 <td class="unstable">phase-divergent: immutable predecessor <a href="/rev/245bde4270cd?style=spartan">245bde4270cd</a></td>
1290 <td class="unstable">content-divergent: <a href="/rev/6f9641995072?style=spartan">6f9641995072</a> (draft) predecessor <a href="/rev/245bde4270cd?style=spartan">245bde4270cd</a></td>
1257 <td class="unstable">content-divergent: <a href="/rev/6f9641995072?style=spartan">6f9641995072</a> (draft) predecessor <a href="/rev/245bde4270cd?style=spartan">245bde4270cd</a></td>
1291
1258
1292 $ killdaemons.py
1259 $ killdaemons.py
1293
1260
1294 $ rm hg.pid access.log errors.log
1261 $ rm hg.pid access.log errors.log
1295
1262
1296 #endif
1263 #endif
1297
1264
1298 Test incoming/outcoming with changesets obsoleted remotely, known locally
1265 Test incoming/outcoming with changesets obsoleted remotely, known locally
1299 ===============================================================================
1266 ===============================================================================
1300
1267
1301 This test issue 3805
1268 This test issue 3805
1302
1269
1303 $ hg init repo-issue3805
1270 $ hg init repo-issue3805
1304 $ cd repo-issue3805
1271 $ cd repo-issue3805
1305 $ echo "base" > base
1272 $ echo "base" > base
1306 $ hg ci -Am "base"
1273 $ hg ci -Am "base"
1307 adding base
1274 adding base
1308 $ echo "foo" > foo
1275 $ echo "foo" > foo
1309 $ hg ci -Am "A"
1276 $ hg ci -Am "A"
1310 adding foo
1277 adding foo
1311 $ hg clone . ../other-issue3805
1278 $ hg clone . ../other-issue3805
1312 updating to branch default
1279 updating to branch default
1313 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
1280 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
1314 $ echo "bar" >> foo
1281 $ echo "bar" >> foo
1315 $ hg ci --amend
1282 $ hg ci --amend
1316 $ cd ../other-issue3805
1283 $ cd ../other-issue3805
1317 $ hg log -G
1284 $ hg log -G
1318 @ 1:29f0c6921ddd (draft) [tip ] A
1285 @ 1:29f0c6921ddd (draft) [tip ] A
1319 |
1286 |
1320 o 0:d20a80d4def3 (draft) [ ] base
1287 o 0:d20a80d4def3 (draft) [ ] base
1321
1288
1322 $ hg log -G -R ../repo-issue3805
1289 $ hg log -G -R ../repo-issue3805
1323 @ 2:323a9c3ddd91 (draft) [tip ] A
1290 @ 2:323a9c3ddd91 (draft) [tip ] A
1324 |
1291 |
1325 o 0:d20a80d4def3 (draft) [ ] base
1292 o 0:d20a80d4def3 (draft) [ ] base
1326
1293
1327 $ hg incoming
1294 $ hg incoming
1328 comparing with $TESTTMP/tmpe/repo-issue3805
1295 comparing with $TESTTMP/tmpe/repo-issue3805
1329 searching for changes
1296 searching for changes
1330 2:323a9c3ddd91 (draft) [tip ] A
1297 2:323a9c3ddd91 (draft) [tip ] A
1331 $ hg incoming --bundle ../issue3805.hg
1298 $ hg incoming --bundle ../issue3805.hg
1332 comparing with $TESTTMP/tmpe/repo-issue3805
1299 comparing with $TESTTMP/tmpe/repo-issue3805
1333 searching for changes
1300 searching for changes
1334 2:323a9c3ddd91 (draft) [tip ] A
1301 2:323a9c3ddd91 (draft) [tip ] A
1335 $ hg outgoing
1302 $ hg outgoing
1336 comparing with $TESTTMP/tmpe/repo-issue3805
1303 comparing with $TESTTMP/tmpe/repo-issue3805
1337 searching for changes
1304 searching for changes
1338 1:29f0c6921ddd (draft) [tip ] A
1305 1:29f0c6921ddd (draft) [tip ] A
1339
1306
1340 #if serve
1307 #if serve
1341
1308
1342 $ hg serve -R ../repo-issue3805 -n test -p $HGPORT -d --pid-file=hg.pid -A access.log -E errors.log
1309 $ hg serve -R ../repo-issue3805 -n test -p $HGPORT -d --pid-file=hg.pid -A access.log -E errors.log
1343 $ cat hg.pid >> $DAEMON_PIDS
1310 $ cat hg.pid >> $DAEMON_PIDS
1344
1311
1345 $ hg incoming http://localhost:$HGPORT
1312 $ hg incoming http://localhost:$HGPORT
1346 comparing with http://localhost:$HGPORT/
1313 comparing with http://localhost:$HGPORT/
1347 searching for changes
1314 searching for changes
1348 2:323a9c3ddd91 (draft) [tip ] A
1315 2:323a9c3ddd91 (draft) [tip ] A
1349 $ hg outgoing http://localhost:$HGPORT
1316 $ hg outgoing http://localhost:$HGPORT
1350 comparing with http://localhost:$HGPORT/
1317 comparing with http://localhost:$HGPORT/
1351 searching for changes
1318 searching for changes
1352 1:29f0c6921ddd (draft) [tip ] A
1319 1:29f0c6921ddd (draft) [tip ] A
1353
1320
1354 $ killdaemons.py
1321 $ killdaemons.py
1355
1322
1356 #endif
1323 #endif
1357
1324
1358 This test issue 3814
1325 This test issue 3814
1359
1326
1360 (nothing to push but locally hidden changeset)
1327 (nothing to push but locally hidden changeset)
1361
1328
1362 $ cd ..
1329 $ cd ..
1363 $ hg init repo-issue3814
1330 $ hg init repo-issue3814
1364 $ cd repo-issue3805
1331 $ cd repo-issue3805
1365 $ hg push -r 323a9c3ddd91 ../repo-issue3814
1332 $ hg push -r 323a9c3ddd91 ../repo-issue3814
1366 pushing to ../repo-issue3814
1333 pushing to ../repo-issue3814
1367 searching for changes
1334 searching for changes
1368 adding changesets
1335 adding changesets
1369 adding manifests
1336 adding manifests
1370 adding file changes
1337 adding file changes
1371 added 2 changesets with 2 changes to 2 files
1338 added 2 changesets with 2 changes to 2 files
1372 1 new obsolescence markers
1339 1 new obsolescence markers
1373 $ hg out ../repo-issue3814
1340 $ hg out ../repo-issue3814
1374 comparing with ../repo-issue3814
1341 comparing with ../repo-issue3814
1375 searching for changes
1342 searching for changes
1376 no changes found
1343 no changes found
1377 [1]
1344 [1]
1378
1345
1379 Test that a local tag blocks a changeset from being hidden
1346 Test that a local tag blocks a changeset from being hidden
1380
1347
1381 $ hg tag -l visible -r 1 --hidden
1348 $ hg tag -l visible -r 1 --hidden
1382 $ hg log -G
1349 $ hg log -G
1383 @ 2:323a9c3ddd91 (draft) [tip ] A
1350 @ 2:323a9c3ddd91 (draft) [tip ] A
1384 |
1351 |
1385 | x 1:29f0c6921ddd (draft *obsolete*) [visible ] A [rewritten using amend as 2:323a9c3ddd91]
1352 | x 1:29f0c6921ddd (draft *obsolete*) [visible ] A [rewritten using amend as 2:323a9c3ddd91]
1386 |/
1353 |/
1387 o 0:d20a80d4def3 (draft) [ ] base
1354 o 0:d20a80d4def3 (draft) [ ] base
1388
1355
1389 Test that removing a local tag does not cause some commands to fail
1356 Test that removing a local tag does not cause some commands to fail
1390
1357
1391 $ hg tag -l -r tip tiptag
1358 $ hg tag -l -r tip tiptag
1392 $ hg tags
1359 $ hg tags
1393 tiptag 2:323a9c3ddd91
1360 tiptag 2:323a9c3ddd91
1394 tip 2:323a9c3ddd91
1361 tip 2:323a9c3ddd91
1395 visible 1:29f0c6921ddd
1362 visible 1:29f0c6921ddd
1396 $ hg --config extensions.strip= strip -r tip --no-backup
1363 $ hg --config extensions.strip= strip -r tip --no-backup
1397 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
1364 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
1398 $ hg tags
1365 $ hg tags
1399 visible 1:29f0c6921ddd
1366 visible 1:29f0c6921ddd
1400 tip 1:29f0c6921ddd
1367 tip 1:29f0c6921ddd
1401
1368
1402 Test bundle overlay onto hidden revision
1369 Test bundle overlay onto hidden revision
1403
1370
1404 $ cd ..
1371 $ cd ..
1405 $ hg init repo-bundleoverlay
1372 $ hg init repo-bundleoverlay
1406 $ cd repo-bundleoverlay
1373 $ cd repo-bundleoverlay
1407 $ echo "A" > foo
1374 $ echo "A" > foo
1408 $ hg ci -Am "A"
1375 $ hg ci -Am "A"
1409 adding foo
1376 adding foo
1410 $ echo "B" >> foo
1377 $ echo "B" >> foo
1411 $ hg ci -m "B"
1378 $ hg ci -m "B"
1412 $ hg up 0
1379 $ hg up 0
1413 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1380 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1414 $ echo "C" >> foo
1381 $ echo "C" >> foo
1415 $ hg ci -m "C"
1382 $ hg ci -m "C"
1416 created new head
1383 created new head
1417 $ hg log -G
1384 $ hg log -G
1418 @ 2:c186d7714947 (draft) [tip ] C
1385 @ 2:c186d7714947 (draft) [tip ] C
1419 |
1386 |
1420 | o 1:44526ebb0f98 (draft) [ ] B
1387 | o 1:44526ebb0f98 (draft) [ ] B
1421 |/
1388 |/
1422 o 0:4b34ecfb0d56 (draft) [ ] A
1389 o 0:4b34ecfb0d56 (draft) [ ] A
1423
1390
1424
1391
1425 $ hg clone -r1 . ../other-bundleoverlay
1392 $ hg clone -r1 . ../other-bundleoverlay
1426 adding changesets
1393 adding changesets
1427 adding manifests
1394 adding manifests
1428 adding file changes
1395 adding file changes
1429 added 2 changesets with 2 changes to 1 files
1396 added 2 changesets with 2 changes to 1 files
1430 new changesets 4b34ecfb0d56:44526ebb0f98 (2 drafts)
1397 new changesets 4b34ecfb0d56:44526ebb0f98 (2 drafts)
1431 updating to branch default
1398 updating to branch default
1432 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1399 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1433 $ cd ../other-bundleoverlay
1400 $ cd ../other-bundleoverlay
1434 $ echo "B+" >> foo
1401 $ echo "B+" >> foo
1435 $ hg ci --amend -m "B+"
1402 $ hg ci --amend -m "B+"
1436 $ hg log -G --hidden
1403 $ hg log -G --hidden
1437 @ 2:b7d587542d40 (draft) [tip ] B+
1404 @ 2:b7d587542d40 (draft) [tip ] B+
1438 |
1405 |
1439 | x 1:44526ebb0f98 (draft *obsolete*) [ ] B [rewritten using amend as 2:b7d587542d40]
1406 | x 1:44526ebb0f98 (draft *obsolete*) [ ] B [rewritten using amend as 2:b7d587542d40]
1440 |/
1407 |/
1441 o 0:4b34ecfb0d56 (draft) [ ] A
1408 o 0:4b34ecfb0d56 (draft) [ ] A
1442
1409
1443
1410
1444 #if repobundlerepo
1411 #if repobundlerepo
1445 $ hg incoming ../repo-bundleoverlay --bundle ../bundleoverlay.hg
1412 $ hg incoming ../repo-bundleoverlay --bundle ../bundleoverlay.hg
1446 comparing with ../repo-bundleoverlay
1413 comparing with ../repo-bundleoverlay
1447 searching for changes
1414 searching for changes
1448 1:44526ebb0f98 (draft) [ ] B
1415 1:44526ebb0f98 (draft) [ ] B
1449 2:c186d7714947 (draft) [tip ] C
1416 2:c186d7714947 (draft) [tip ] C
1450 $ hg log -G -R ../bundleoverlay.hg
1417 $ hg log -G -R ../bundleoverlay.hg
1451 o 3:c186d7714947 (draft) [tip ] C
1418 o 3:c186d7714947 (draft) [tip ] C
1452 |
1419 |
1453 | @ 2:b7d587542d40 (draft) [ ] B+
1420 | @ 2:b7d587542d40 (draft) [ ] B+
1454 |/
1421 |/
1455 o 0:4b34ecfb0d56 (draft) [ ] A
1422 o 0:4b34ecfb0d56 (draft) [ ] A
1456
1423
1457 #endif
1424 #endif
1458
1425
1459 #if serve
1426 #if serve
1460
1427
1461 Test issue 4506
1428 Test issue 4506
1462
1429
1463 $ cd ..
1430 $ cd ..
1464 $ hg init repo-issue4506
1431 $ hg init repo-issue4506
1465 $ cd repo-issue4506
1432 $ cd repo-issue4506
1466 $ echo "0" > foo
1433 $ echo "0" > foo
1467 $ hg add foo
1434 $ hg add foo
1468 $ hg ci -m "content-0"
1435 $ hg ci -m "content-0"
1469
1436
1470 $ hg up null
1437 $ hg up null
1471 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
1438 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
1472 $ echo "1" > bar
1439 $ echo "1" > bar
1473 $ hg add bar
1440 $ hg add bar
1474 $ hg ci -m "content-1"
1441 $ hg ci -m "content-1"
1475 created new head
1442 created new head
1476 $ hg up 0
1443 $ hg up 0
1477 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
1444 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
1478 $ hg graft 1
1445 $ hg graft 1
1479 grafting 1:1c9eddb02162 "content-1" (tip)
1446 grafting 1:1c9eddb02162 "content-1" (tip)
1480
1447
1481 $ hg debugobsolete `hg log -r1 -T'{node}'` `hg log -r2 -T'{node}'`
1448 $ hg debugobsolete `hg log -r1 -T'{node}'` `hg log -r2 -T'{node}'`
1482 1 new obsolescence markers
1449 1 new obsolescence markers
1483 obsoleted 1 changesets
1450 obsoleted 1 changesets
1484
1451
1485 $ hg serve -n test -p $HGPORT -d --pid-file=hg.pid -A access.log -E errors.log
1452 $ hg serve -n test -p $HGPORT -d --pid-file=hg.pid -A access.log -E errors.log
1486 $ cat hg.pid >> $DAEMON_PIDS
1453 $ cat hg.pid >> $DAEMON_PIDS
1487
1454
1488 $ get-with-headers.py --headeronly localhost:$HGPORT 'rev/1'
1455 $ get-with-headers.py --headeronly localhost:$HGPORT 'rev/1'
1489 404 Not Found
1456 404 Not Found
1490 [1]
1457 [1]
1491 $ get-with-headers.py --headeronly localhost:$HGPORT 'file/tip/bar'
1458 $ get-with-headers.py --headeronly localhost:$HGPORT 'file/tip/bar'
1492 200 Script output follows
1459 200 Script output follows
1493 $ get-with-headers.py --headeronly localhost:$HGPORT 'annotate/tip/bar'
1460 $ get-with-headers.py --headeronly localhost:$HGPORT 'annotate/tip/bar'
1494 200 Script output follows
1461 200 Script output follows
1495
1462
1496 $ killdaemons.py
1463 $ killdaemons.py
1497
1464
1498 #endif
1465 #endif
1499
1466
1500 Test heads computation on pending index changes with obsolescence markers
1467 Test heads computation on pending index changes with obsolescence markers
1501 $ cd ..
1468 $ cd ..
1502 $ cat >$TESTTMP/test_extension.py << EOF
1469 $ cat >$TESTTMP/test_extension.py << EOF
1503 > from __future__ import absolute_import
1470 > from __future__ import absolute_import
1504 > from mercurial.i18n import _
1471 > from mercurial.i18n import _
1505 > from mercurial import cmdutil, pycompat, registrar
1472 > from mercurial import cmdutil, pycompat, registrar
1506 > from mercurial.utils import stringutil
1473 > from mercurial.utils import stringutil
1507 >
1474 >
1508 > cmdtable = {}
1475 > cmdtable = {}
1509 > command = registrar.command(cmdtable)
1476 > command = registrar.command(cmdtable)
1510 > @command(b"amendtransient",[], _(b'hg amendtransient [rev]'))
1477 > @command(b"amendtransient",[], _(b'hg amendtransient [rev]'))
1511 > def amend(ui, repo, *pats, **opts):
1478 > def amend(ui, repo, *pats, **opts):
1512 > opts = pycompat.byteskwargs(opts)
1479 > opts = pycompat.byteskwargs(opts)
1513 > opts[b'message'] = b'Test'
1480 > opts[b'message'] = b'Test'
1514 > opts[b'logfile'] = None
1481 > opts[b'logfile'] = None
1515 > cmdutil.amend(ui, repo, repo[b'.'], {}, pats, opts)
1482 > cmdutil.amend(ui, repo, repo[b'.'], {}, pats, opts)
1516 > ui.write(b'%s\n' % stringutil.pprint(repo.changelog.headrevs()))
1483 > ui.write(b'%s\n' % stringutil.pprint(repo.changelog.headrevs()))
1517 > EOF
1484 > EOF
1518 $ cat >> $HGRCPATH << EOF
1485 $ cat >> $HGRCPATH << EOF
1519 > [extensions]
1486 > [extensions]
1520 > testextension=$TESTTMP/test_extension.py
1487 > testextension=$TESTTMP/test_extension.py
1521 > EOF
1488 > EOF
1522 $ hg init repo-issue-nativerevs-pending-changes
1489 $ hg init repo-issue-nativerevs-pending-changes
1523 $ cd repo-issue-nativerevs-pending-changes
1490 $ cd repo-issue-nativerevs-pending-changes
1524 $ mkcommit a
1491 $ mkcommit a
1525 $ mkcommit b
1492 $ mkcommit b
1526 $ hg up ".^"
1493 $ hg up ".^"
1527 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
1494 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
1528 $ echo aa > a
1495 $ echo aa > a
1529 $ hg amendtransient
1496 $ hg amendtransient
1530 1 new orphan changesets
1497 1 new orphan changesets
1531 [1, 2]
1498 [1, 2]
1532
1499
1533 Test cache consistency for the visible filter
1500 Test cache consistency for the visible filter
1534 1) We want to make sure that the cached filtered revs are invalidated when
1501 1) We want to make sure that the cached filtered revs are invalidated when
1535 bookmarks change
1502 bookmarks change
1536 $ cd ..
1503 $ cd ..
1537 $ cat >$TESTTMP/test_extension.py << EOF
1504 $ cat >$TESTTMP/test_extension.py << EOF
1538 > from __future__ import absolute_import, print_function
1505 > from __future__ import absolute_import, print_function
1539 > import weakref
1506 > import weakref
1540 > from mercurial import (
1507 > from mercurial import (
1541 > bookmarks,
1508 > bookmarks,
1542 > cmdutil,
1509 > cmdutil,
1543 > extensions,
1510 > extensions,
1544 > repoview,
1511 > repoview,
1545 > )
1512 > )
1546 > def _bookmarkchanged(orig, bkmstoreinst, *args, **kwargs):
1513 > def _bookmarkchanged(orig, bkmstoreinst, *args, **kwargs):
1547 > reporef = weakref.ref(bkmstoreinst._repo)
1514 > reporef = weakref.ref(bkmstoreinst._repo)
1548 > def trhook(tr):
1515 > def trhook(tr):
1549 > repo = reporef()
1516 > repo = reporef()
1550 > hidden1 = repoview.computehidden(repo)
1517 > hidden1 = repoview.computehidden(repo)
1551 > hidden = repoview.filterrevs(repo, b'visible')
1518 > hidden = repoview.filterrevs(repo, b'visible')
1552 > if sorted(hidden1) != sorted(hidden):
1519 > if sorted(hidden1) != sorted(hidden):
1553 > print("cache inconsistency")
1520 > print("cache inconsistency")
1554 > bkmstoreinst._repo.currenttransaction().addpostclose(b'test_extension', trhook)
1521 > bkmstoreinst._repo.currenttransaction().addpostclose(b'test_extension', trhook)
1555 > orig(bkmstoreinst, *args, **kwargs)
1522 > orig(bkmstoreinst, *args, **kwargs)
1556 > def extsetup(ui):
1523 > def extsetup(ui):
1557 > extensions.wrapfunction(bookmarks.bmstore, '_recordchange',
1524 > extensions.wrapfunction(bookmarks.bmstore, '_recordchange',
1558 > _bookmarkchanged)
1525 > _bookmarkchanged)
1559 > EOF
1526 > EOF
1560
1527
1561 $ hg init repo-cache-inconsistency
1528 $ hg init repo-cache-inconsistency
1562 $ cd repo-issue-nativerevs-pending-changes
1529 $ cd repo-issue-nativerevs-pending-changes
1563 $ mkcommit a
1530 $ mkcommit a
1564 a already tracked!
1531 a already tracked!
1565 $ mkcommit b
1532 $ mkcommit b
1566 $ hg id
1533 $ hg id
1567 13bedc178fce tip
1534 13bedc178fce tip
1568 $ echo "hello" > b
1535 $ echo "hello" > b
1569 $ hg commit --amend -m "message"
1536 $ hg commit --amend -m "message"
1570 $ hg book bookb -r 13bedc178fce --hidden
1537 $ hg book bookb -r 13bedc178fce --hidden
1571 bookmarking hidden changeset 13bedc178fce
1538 bookmarking hidden changeset 13bedc178fce
1572 (hidden revision '13bedc178fce' was rewritten as: a9b1f8652753)
1539 (hidden revision '13bedc178fce' was rewritten as: a9b1f8652753)
1573 $ hg log -r 13bedc178fce
1540 $ hg log -r 13bedc178fce
1574 4:13bedc178fce (draft *obsolete*) [ bookb] add b [rewritten using amend as 5:a9b1f8652753]
1541 4:13bedc178fce (draft *obsolete*) [ bookb] add b [rewritten using amend as 5:a9b1f8652753]
1575 $ hg book -d bookb
1542 $ hg book -d bookb
1576 $ hg log -r 13bedc178fce
1543 $ hg log -r 13bedc178fce
1577 abort: hidden revision '13bedc178fce' was rewritten as: a9b1f8652753!
1544 abort: hidden revision '13bedc178fce' was rewritten as: a9b1f8652753!
1578 (use --hidden to access hidden revisions)
1545 (use --hidden to access hidden revisions)
1579 [255]
1546 [255]
1580
1547
1581 Empty out the test extension, as it isn't compatible with later parts
1548 Empty out the test extension, as it isn't compatible with later parts
1582 of the test.
1549 of the test.
1583 $ echo > $TESTTMP/test_extension.py
1550 $ echo > $TESTTMP/test_extension.py
1584
1551
1585 Test ability to pull changeset with locally applying obsolescence markers
1552 Test ability to pull changeset with locally applying obsolescence markers
1586 (issue4945)
1553 (issue4945)
1587
1554
1588 $ cd ..
1555 $ cd ..
1589 $ hg init issue4845
1556 $ hg init issue4845
1590 $ cd issue4845
1557 $ cd issue4845
1591
1558
1592 $ echo foo > f0
1559 $ echo foo > f0
1593 $ hg add f0
1560 $ hg add f0
1594 $ hg ci -m '0'
1561 $ hg ci -m '0'
1595 $ echo foo > f1
1562 $ echo foo > f1
1596 $ hg add f1
1563 $ hg add f1
1597 $ hg ci -m '1'
1564 $ hg ci -m '1'
1598 $ echo foo > f2
1565 $ echo foo > f2
1599 $ hg add f2
1566 $ hg add f2
1600 $ hg ci -m '2'
1567 $ hg ci -m '2'
1601
1568
1602 $ echo bar > f2
1569 $ echo bar > f2
1603 $ hg commit --amend --config experimental.evolution.createmarkers=True
1570 $ hg commit --amend --config experimental.evolution.createmarkers=True
1604 $ hg log -G
1571 $ hg log -G
1605 @ 3:b0551702f918 (draft) [tip ] 2
1572 @ 3:b0551702f918 (draft) [tip ] 2
1606 |
1573 |
1607 o 1:e016b03fd86f (draft) [ ] 1
1574 o 1:e016b03fd86f (draft) [ ] 1
1608 |
1575 |
1609 o 0:a78f55e5508c (draft) [ ] 0
1576 o 0:a78f55e5508c (draft) [ ] 0
1610
1577
1611 $ hg log -G --hidden
1578 $ hg log -G --hidden
1612 @ 3:b0551702f918 (draft) [tip ] 2
1579 @ 3:b0551702f918 (draft) [tip ] 2
1613 |
1580 |
1614 | x 2:e008cf283490 (draft *obsolete*) [ ] 2 [rewritten using amend as 3:b0551702f918]
1581 | x 2:e008cf283490 (draft *obsolete*) [ ] 2 [rewritten using amend as 3:b0551702f918]
1615 |/
1582 |/
1616 o 1:e016b03fd86f (draft) [ ] 1
1583 o 1:e016b03fd86f (draft) [ ] 1
1617 |
1584 |
1618 o 0:a78f55e5508c (draft) [ ] 0
1585 o 0:a78f55e5508c (draft) [ ] 0
1619
1586
1620
1587
1621 $ hg strip --hidden -r 2 --config extensions.strip= --config devel.strip-obsmarkers=no
1588 $ hg strip --hidden -r 2 --config extensions.strip= --config devel.strip-obsmarkers=no
1622 saved backup bundle to $TESTTMP/tmpe/issue4845/.hg/strip-backup/e008cf283490-ede36964-backup.hg
1589 saved backup bundle to $TESTTMP/tmpe/issue4845/.hg/strip-backup/e008cf283490-ede36964-backup.hg
1623 $ hg debugobsolete
1590 $ hg debugobsolete
1624 e008cf2834908e5d6b0f792a9d4b0e2272260fb8 b0551702f918510f01ae838ab03a463054c67b46 0 (Thu Jan 01 00:00:00 1970 +0000) {'ef1': '8', 'operation': 'amend', 'user': 'test'}
1591 e008cf2834908e5d6b0f792a9d4b0e2272260fb8 b0551702f918510f01ae838ab03a463054c67b46 0 (Thu Jan 01 00:00:00 1970 +0000) {'ef1': '8', 'operation': 'amend', 'user': 'test'}
1625 $ hg log -G
1592 $ hg log -G
1626 @ 2:b0551702f918 (draft) [tip ] 2
1593 @ 2:b0551702f918 (draft) [tip ] 2
1627 |
1594 |
1628 o 1:e016b03fd86f (draft) [ ] 1
1595 o 1:e016b03fd86f (draft) [ ] 1
1629 |
1596 |
1630 o 0:a78f55e5508c (draft) [ ] 0
1597 o 0:a78f55e5508c (draft) [ ] 0
1631
1598
1632 $ hg log -G --hidden
1599 $ hg log -G --hidden
1633 @ 2:b0551702f918 (draft) [tip ] 2
1600 @ 2:b0551702f918 (draft) [tip ] 2
1634 |
1601 |
1635 o 1:e016b03fd86f (draft) [ ] 1
1602 o 1:e016b03fd86f (draft) [ ] 1
1636 |
1603 |
1637 o 0:a78f55e5508c (draft) [ ] 0
1604 o 0:a78f55e5508c (draft) [ ] 0
1638
1605
1639 $ hg debugbundle .hg/strip-backup/e008cf283490-*-backup.hg
1606 $ hg debugbundle .hg/strip-backup/e008cf283490-*-backup.hg
1640 Stream params: {Compression: BZ}
1607 Stream params: {Compression: BZ}
1641 changegroup -- {nbchanges: 1, version: 02} (mandatory: True)
1608 changegroup -- {nbchanges: 1, version: 02} (mandatory: True)
1642 e008cf2834908e5d6b0f792a9d4b0e2272260fb8
1609 e008cf2834908e5d6b0f792a9d4b0e2272260fb8
1643 cache:rev-branch-cache -- {} (mandatory: False)
1610 cache:rev-branch-cache -- {} (mandatory: False)
1644 phase-heads -- {} (mandatory: True)
1611 phase-heads -- {} (mandatory: True)
1645 e008cf2834908e5d6b0f792a9d4b0e2272260fb8 draft
1612 e008cf2834908e5d6b0f792a9d4b0e2272260fb8 draft
1646
1613
1647 #if repobundlerepo
1614 #if repobundlerepo
1648 $ hg pull .hg/strip-backup/e008cf283490-*-backup.hg
1615 $ hg pull .hg/strip-backup/e008cf283490-*-backup.hg
1649 pulling from .hg/strip-backup/e008cf283490-ede36964-backup.hg
1616 pulling from .hg/strip-backup/e008cf283490-ede36964-backup.hg
1650 searching for changes
1617 searching for changes
1651 no changes found
1618 no changes found
1652 #endif
1619 #endif
1653 $ hg debugobsolete
1620 $ hg debugobsolete
1654 e008cf2834908e5d6b0f792a9d4b0e2272260fb8 b0551702f918510f01ae838ab03a463054c67b46 0 (Thu Jan 01 00:00:00 1970 +0000) {'ef1': '8', 'operation': 'amend', 'user': 'test'}
1621 e008cf2834908e5d6b0f792a9d4b0e2272260fb8 b0551702f918510f01ae838ab03a463054c67b46 0 (Thu Jan 01 00:00:00 1970 +0000) {'ef1': '8', 'operation': 'amend', 'user': 'test'}
1655 $ hg log -G
1622 $ hg log -G
1656 @ 2:b0551702f918 (draft) [tip ] 2
1623 @ 2:b0551702f918 (draft) [tip ] 2
1657 |
1624 |
1658 o 1:e016b03fd86f (draft) [ ] 1
1625 o 1:e016b03fd86f (draft) [ ] 1
1659 |
1626 |
1660 o 0:a78f55e5508c (draft) [ ] 0
1627 o 0:a78f55e5508c (draft) [ ] 0
1661
1628
1662 $ hg log -G --hidden
1629 $ hg log -G --hidden
1663 @ 2:b0551702f918 (draft) [tip ] 2
1630 @ 2:b0551702f918 (draft) [tip ] 2
1664 |
1631 |
1665 o 1:e016b03fd86f (draft) [ ] 1
1632 o 1:e016b03fd86f (draft) [ ] 1
1666 |
1633 |
1667 o 0:a78f55e5508c (draft) [ ] 0
1634 o 0:a78f55e5508c (draft) [ ] 0
1668
1635
1669
1636
1670 Testing that strip remove markers:
1637 Testing that strip remove markers:
1671
1638
1672 $ hg strip -r 1 --config extensions.strip=
1639 $ hg strip -r 1 --config extensions.strip=
1673 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
1640 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
1674 saved backup bundle to $TESTTMP/tmpe/issue4845/.hg/strip-backup/e016b03fd86f-65ede734-backup.hg
1641 saved backup bundle to $TESTTMP/tmpe/issue4845/.hg/strip-backup/e016b03fd86f-65ede734-backup.hg
1675 $ hg debugobsolete
1642 $ hg debugobsolete
1676 $ hg log -G
1643 $ hg log -G
1677 @ 0:a78f55e5508c (draft) [tip ] 0
1644 @ 0:a78f55e5508c (draft) [tip ] 0
1678
1645
1679 $ hg log -G --hidden
1646 $ hg log -G --hidden
1680 @ 0:a78f55e5508c (draft) [tip ] 0
1647 @ 0:a78f55e5508c (draft) [tip ] 0
1681
1648
1682 $ hg debugbundle .hg/strip-backup/e016b03fd86f-*-backup.hg
1649 $ hg debugbundle .hg/strip-backup/e016b03fd86f-*-backup.hg
1683 Stream params: {Compression: BZ}
1650 Stream params: {Compression: BZ}
1684 changegroup -- {nbchanges: 2, version: 02} (mandatory: True)
1651 changegroup -- {nbchanges: 2, version: 02} (mandatory: True)
1685 e016b03fd86fcccc54817d120b90b751aaf367d6
1652 e016b03fd86fcccc54817d120b90b751aaf367d6
1686 b0551702f918510f01ae838ab03a463054c67b46
1653 b0551702f918510f01ae838ab03a463054c67b46
1687 cache:rev-branch-cache -- {} (mandatory: False)
1654 cache:rev-branch-cache -- {} (mandatory: False)
1688 obsmarkers -- {} (mandatory: True)
1655 obsmarkers -- {} (mandatory: True)
1689 version: 1 (92 bytes)
1656 version: 1 (92 bytes)
1690 e008cf2834908e5d6b0f792a9d4b0e2272260fb8 b0551702f918510f01ae838ab03a463054c67b46 0 (Thu Jan 01 00:00:00 1970 +0000) {'ef1': '8', 'operation': 'amend', 'user': 'test'}
1657 e008cf2834908e5d6b0f792a9d4b0e2272260fb8 b0551702f918510f01ae838ab03a463054c67b46 0 (Thu Jan 01 00:00:00 1970 +0000) {'ef1': '8', 'operation': 'amend', 'user': 'test'}
1691 phase-heads -- {} (mandatory: True)
1658 phase-heads -- {} (mandatory: True)
1692 b0551702f918510f01ae838ab03a463054c67b46 draft
1659 b0551702f918510f01ae838ab03a463054c67b46 draft
1693
1660
1694 $ hg unbundle .hg/strip-backup/e016b03fd86f-*-backup.hg
1661 $ hg unbundle .hg/strip-backup/e016b03fd86f-*-backup.hg
1695 adding changesets
1662 adding changesets
1696 adding manifests
1663 adding manifests
1697 adding file changes
1664 adding file changes
1698 added 2 changesets with 2 changes to 2 files
1665 added 2 changesets with 2 changes to 2 files
1699 1 new obsolescence markers
1666 1 new obsolescence markers
1700 new changesets e016b03fd86f:b0551702f918 (2 drafts)
1667 new changesets e016b03fd86f:b0551702f918 (2 drafts)
1701 (run 'hg update' to get a working copy)
1668 (run 'hg update' to get a working copy)
1702 $ hg debugobsolete | sort
1669 $ hg debugobsolete | sort
1703 e008cf2834908e5d6b0f792a9d4b0e2272260fb8 b0551702f918510f01ae838ab03a463054c67b46 0 (Thu Jan 01 00:00:00 1970 +0000) {'ef1': '8', 'operation': 'amend', 'user': 'test'}
1670 e008cf2834908e5d6b0f792a9d4b0e2272260fb8 b0551702f918510f01ae838ab03a463054c67b46 0 (Thu Jan 01 00:00:00 1970 +0000) {'ef1': '8', 'operation': 'amend', 'user': 'test'}
1704 $ hg log -G
1671 $ hg log -G
1705 o 2:b0551702f918 (draft) [tip ] 2
1672 o 2:b0551702f918 (draft) [tip ] 2
1706 |
1673 |
1707 o 1:e016b03fd86f (draft) [ ] 1
1674 o 1:e016b03fd86f (draft) [ ] 1
1708 |
1675 |
1709 @ 0:a78f55e5508c (draft) [ ] 0
1676 @ 0:a78f55e5508c (draft) [ ] 0
1710
1677
1711 $ hg log -G --hidden
1678 $ hg log -G --hidden
1712 o 2:b0551702f918 (draft) [tip ] 2
1679 o 2:b0551702f918 (draft) [tip ] 2
1713 |
1680 |
1714 o 1:e016b03fd86f (draft) [ ] 1
1681 o 1:e016b03fd86f (draft) [ ] 1
1715 |
1682 |
1716 @ 0:a78f55e5508c (draft) [ ] 0
1683 @ 0:a78f55e5508c (draft) [ ] 0
1717
1684
1718 Test that 'hg debugobsolete --index --rev' can show indices of obsmarkers when
1685 Test that 'hg debugobsolete --index --rev' can show indices of obsmarkers when
1719 only a subset of those are displayed (because of --rev option)
1686 only a subset of those are displayed (because of --rev option)
1720 $ hg init doindexrev
1687 $ hg init doindexrev
1721 $ cd doindexrev
1688 $ cd doindexrev
1722 $ echo a > a
1689 $ echo a > a
1723 $ hg ci -Am a
1690 $ hg ci -Am a
1724 adding a
1691 adding a
1725 $ hg ci --amend -m aa
1692 $ hg ci --amend -m aa
1726 $ echo b > b
1693 $ echo b > b
1727 $ hg ci -Am b
1694 $ hg ci -Am b
1728 adding b
1695 adding b
1729 $ hg ci --amend -m bb
1696 $ hg ci --amend -m bb
1730 $ echo c > c
1697 $ echo c > c
1731 $ hg ci -Am c
1698 $ hg ci -Am c
1732 adding c
1699 adding c
1733 $ hg ci --amend -m cc
1700 $ hg ci --amend -m cc
1734 $ echo d > d
1701 $ echo d > d
1735 $ hg ci -Am d
1702 $ hg ci -Am d
1736 adding d
1703 adding d
1737 $ hg ci --amend -m dd --config experimental.evolution.track-operation=1
1704 $ hg ci --amend -m dd --config experimental.evolution.track-operation=1
1738 $ hg debugobsolete --index --rev "3+7"
1705 $ hg debugobsolete --index --rev "3+7"
1739 1 6fdef60fcbabbd3d50e9b9cbc2a240724b91a5e1 d27fb9b066076fd921277a4b9e8b9cb48c95bc6a 0 (Thu Jan 01 00:00:00 1970 +0000) {'ef1': '1', 'operation': 'amend', 'user': 'test'}
1706 1 6fdef60fcbabbd3d50e9b9cbc2a240724b91a5e1 d27fb9b066076fd921277a4b9e8b9cb48c95bc6a 0 (Thu Jan 01 00:00:00 1970 +0000) {'ef1': '1', 'operation': 'amend', 'user': 'test'}
1740 3 4715cf767440ed891755448016c2b8cf70760c30 7ae79c5d60f049c7b0dd02f5f25b9d60aaf7b36d 0 (Thu Jan 01 00:00:00 1970 +0000) {'ef1': '1', 'operation': 'amend', 'user': 'test'}
1707 3 4715cf767440ed891755448016c2b8cf70760c30 7ae79c5d60f049c7b0dd02f5f25b9d60aaf7b36d 0 (Thu Jan 01 00:00:00 1970 +0000) {'ef1': '1', 'operation': 'amend', 'user': 'test'}
1741 $ hg debugobsolete --index --rev "3+7" -Tjson
1708 $ hg debugobsolete --index --rev "3+7" -Tjson
1742 [
1709 [
1743 {
1710 {
1744 "date": [0, 0],
1711 "date": [0, 0],
1745 "flag": 0,
1712 "flag": 0,
1746 "index": 1,
1713 "index": 1,
1747 "metadata": {"ef1": "1", "operation": "amend", "user": "test"},
1714 "metadata": {"ef1": "1", "operation": "amend", "user": "test"},
1748 "prednode": "6fdef60fcbabbd3d50e9b9cbc2a240724b91a5e1",
1715 "prednode": "6fdef60fcbabbd3d50e9b9cbc2a240724b91a5e1",
1749 "succnodes": ["d27fb9b066076fd921277a4b9e8b9cb48c95bc6a"]
1716 "succnodes": ["d27fb9b066076fd921277a4b9e8b9cb48c95bc6a"]
1750 },
1717 },
1751 {
1718 {
1752 "date": [0, 0],
1719 "date": [0, 0],
1753 "flag": 0,
1720 "flag": 0,
1754 "index": 3,
1721 "index": 3,
1755 "metadata": {"ef1": "1", "operation": "amend", "user": "test"},
1722 "metadata": {"ef1": "1", "operation": "amend", "user": "test"},
1756 "prednode": "4715cf767440ed891755448016c2b8cf70760c30",
1723 "prednode": "4715cf767440ed891755448016c2b8cf70760c30",
1757 "succnodes": ["7ae79c5d60f049c7b0dd02f5f25b9d60aaf7b36d"]
1724 "succnodes": ["7ae79c5d60f049c7b0dd02f5f25b9d60aaf7b36d"]
1758 }
1725 }
1759 ]
1726 ]
1760
1727
1761 Test the --delete option of debugobsolete command
1728 Test the --delete option of debugobsolete command
1762 $ hg debugobsolete --index
1729 $ hg debugobsolete --index
1763 0 cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b f9bd49731b0b175e42992a3c8fa6c678b2bc11f1 0 (Thu Jan 01 00:00:00 1970 +0000) {'ef1': '1', 'operation': 'amend', 'user': 'test'}
1730 0 cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b f9bd49731b0b175e42992a3c8fa6c678b2bc11f1 0 (Thu Jan 01 00:00:00 1970 +0000) {'ef1': '1', 'operation': 'amend', 'user': 'test'}
1764 1 6fdef60fcbabbd3d50e9b9cbc2a240724b91a5e1 d27fb9b066076fd921277a4b9e8b9cb48c95bc6a 0 (Thu Jan 01 00:00:00 1970 +0000) {'ef1': '1', 'operation': 'amend', 'user': 'test'}
1731 1 6fdef60fcbabbd3d50e9b9cbc2a240724b91a5e1 d27fb9b066076fd921277a4b9e8b9cb48c95bc6a 0 (Thu Jan 01 00:00:00 1970 +0000) {'ef1': '1', 'operation': 'amend', 'user': 'test'}
1765 2 1ab51af8f9b41ef8c7f6f3312d4706d870b1fb74 29346082e4a9e27042b62d2da0e2de211c027621 0 (Thu Jan 01 00:00:00 1970 +0000) {'ef1': '1', 'operation': 'amend', 'user': 'test'}
1732 2 1ab51af8f9b41ef8c7f6f3312d4706d870b1fb74 29346082e4a9e27042b62d2da0e2de211c027621 0 (Thu Jan 01 00:00:00 1970 +0000) {'ef1': '1', 'operation': 'amend', 'user': 'test'}
1766 3 4715cf767440ed891755448016c2b8cf70760c30 7ae79c5d60f049c7b0dd02f5f25b9d60aaf7b36d 0 (Thu Jan 01 00:00:00 1970 +0000) {'ef1': '1', 'operation': 'amend', 'user': 'test'}
1733 3 4715cf767440ed891755448016c2b8cf70760c30 7ae79c5d60f049c7b0dd02f5f25b9d60aaf7b36d 0 (Thu Jan 01 00:00:00 1970 +0000) {'ef1': '1', 'operation': 'amend', 'user': 'test'}
1767 $ hg debugobsolete --delete 1 --delete 3
1734 $ hg debugobsolete --delete 1 --delete 3
1768 deleted 2 obsolescence markers
1735 deleted 2 obsolescence markers
1769 $ hg debugobsolete
1736 $ hg debugobsolete
1770 cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b f9bd49731b0b175e42992a3c8fa6c678b2bc11f1 0 (Thu Jan 01 00:00:00 1970 +0000) {'ef1': '1', 'operation': 'amend', 'user': 'test'}
1737 cb9a9f314b8b07ba71012fcdbc544b5a4d82ff5b f9bd49731b0b175e42992a3c8fa6c678b2bc11f1 0 (Thu Jan 01 00:00:00 1970 +0000) {'ef1': '1', 'operation': 'amend', 'user': 'test'}
1771 1ab51af8f9b41ef8c7f6f3312d4706d870b1fb74 29346082e4a9e27042b62d2da0e2de211c027621 0 (Thu Jan 01 00:00:00 1970 +0000) {'ef1': '1', 'operation': 'amend', 'user': 'test'}
1738 1ab51af8f9b41ef8c7f6f3312d4706d870b1fb74 29346082e4a9e27042b62d2da0e2de211c027621 0 (Thu Jan 01 00:00:00 1970 +0000) {'ef1': '1', 'operation': 'amend', 'user': 'test'}
1772
1739
1773 Test adding changeset after obsmarkers affecting it
1740 Test adding changeset after obsmarkers affecting it
1774 (eg: during pull, or unbundle)
1741 (eg: during pull, or unbundle)
1775
1742
1776 $ mkcommit e
1743 $ mkcommit e
1777 $ hg bundle -r . --base .~1 ../bundle-2.hg
1744 $ hg bundle -r . --base .~1 ../bundle-2.hg
1778 1 changesets found
1745 1 changesets found
1779 $ getid .
1746 $ getid .
1780 $ hg --config extensions.strip= strip -r .
1747 $ hg --config extensions.strip= strip -r .
1781 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
1748 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
1782 saved backup bundle to $TESTTMP/tmpe/issue4845/doindexrev/.hg/strip-backup/9bc153528424-ee80edd4-backup.hg
1749 saved backup bundle to $TESTTMP/tmpe/issue4845/doindexrev/.hg/strip-backup/9bc153528424-ee80edd4-backup.hg
1783 $ hg debugobsolete 9bc153528424ea266d13e57f9ff0d799dfe61e4b
1750 $ hg debugobsolete 9bc153528424ea266d13e57f9ff0d799dfe61e4b
1784 1 new obsolescence markers
1751 1 new obsolescence markers
1785 $ hg unbundle ../bundle-2.hg
1752 $ hg unbundle ../bundle-2.hg
1786 adding changesets
1753 adding changesets
1787 adding manifests
1754 adding manifests
1788 adding file changes
1755 adding file changes
1789 added 1 changesets with 1 changes to 1 files
1756 added 1 changesets with 1 changes to 1 files
1790 (1 other changesets obsolete on arrival)
1757 (1 other changesets obsolete on arrival)
1791 (run 'hg update' to get a working copy)
1758 (run 'hg update' to get a working copy)
1792 $ hg log -G
1759 $ hg log -G
1793 @ 7:7ae79c5d60f0 (draft) [tip ] dd
1760 @ 7:7ae79c5d60f0 (draft) [tip ] dd
1794 |
1761 |
1795 | o 6:4715cf767440 (draft) [ ] d
1762 | o 6:4715cf767440 (draft) [ ] d
1796 |/
1763 |/
1797 o 5:29346082e4a9 (draft) [ ] cc
1764 o 5:29346082e4a9 (draft) [ ] cc
1798 |
1765 |
1799 o 3:d27fb9b06607 (draft) [ ] bb
1766 o 3:d27fb9b06607 (draft) [ ] bb
1800 |
1767 |
1801 | o 2:6fdef60fcbab (draft) [ ] b
1768 | o 2:6fdef60fcbab (draft) [ ] b
1802 |/
1769 |/
1803 o 1:f9bd49731b0b (draft) [ ] aa
1770 o 1:f9bd49731b0b (draft) [ ] aa
1804
1771
1805
1772
1806 $ cd ..
1773 $ cd ..
1807
1774
1808 Test issue 5783
1775 Test issue 5783
1809
1776
1810 $ hg init issue-5783 --config format.obsstore-version=0
1777 $ hg init issue-5783 --config format.obsstore-version=0
1811 $ cd issue-5783
1778 $ cd issue-5783
1812 $ touch a.cpp
1779 $ touch a.cpp
1813 $ hg add a.cpp
1780 $ hg add a.cpp
1814 $ hg commit -m 'Add a.cpp'
1781 $ hg commit -m 'Add a.cpp'
1815 $ echo 'Hello' > a.cpp
1782 $ echo 'Hello' > a.cpp
1816 $ hg amend -n 'Testing::Obsstore' --config format.obsstore-version=0 --config extensions.amend=
1783 $ hg amend -n 'Testing::Obsstore' --config format.obsstore-version=0 --config extensions.amend=
1817 $ touch b.cpp
1784 $ touch b.cpp
1818 $ hg add b.cpp
1785 $ hg add b.cpp
1819 $ hg commit -m 'Add b.cpp'
1786 $ hg commit -m 'Add b.cpp'
1820 $ echo 'Hello' > b.cpp
1787 $ echo 'Hello' > b.cpp
1821 $ hg amend -n 'Testing::Obsstore2' --config extensions.amend=
1788 $ hg amend -n 'Testing::Obsstore2' --config extensions.amend=
1822 $ hg debugobsolete
1789 $ hg debugobsolete
1823 d1b09fe3ad2b2a03e23a72f0c582e29a49570145 1a1a11184d2588af24e767e5335d5d9d07e8c550 0 (Thu Jan 01 00:00:00 1970 +0000) {'ef1': '8', 'note': 'Testing::Obsstore', 'operation': 'amend', 'user': 'test'}
1790 d1b09fe3ad2b2a03e23a72f0c582e29a49570145 1a1a11184d2588af24e767e5335d5d9d07e8c550 0 (Thu Jan 01 00:00:00 1970 +0000) {'ef1': '8', 'note': 'Testing::Obsstore', 'operation': 'amend', 'user': 'test'}
1824 1bfd8e3868f641e048b6667cd672c68932f26d00 79959ca316d5b27ac6be1dd0cfd0843a5b5412eb 0 (Thu Jan 01 00:00:00 1970 +0000) {'ef1': '8', 'note': 'Testing::Obsstore2', 'operation': 'amend', 'user': 'test'}
1791 1bfd8e3868f641e048b6667cd672c68932f26d00 79959ca316d5b27ac6be1dd0cfd0843a5b5412eb 0 (Thu Jan 01 00:00:00 1970 +0000) {'ef1': '8', 'note': 'Testing::Obsstore2', 'operation': 'amend', 'user': 'test'}
1825 $ cd ..
1792 $ cd ..
General Comments 0
You need to be logged in to leave comments. Login now