##// END OF EJS Templates
obsolete: add a flag that allows fixing "bumped" changeset...
Pierre-Yves David -
r17831:70b08df2 default
parent child Browse files
Show More
@@ -1,491 +1,526 b''
1 # obsolete.py - obsolete markers handling
1 # obsolete.py - obsolete markers handling
2 #
2 #
3 # Copyright 2012 Pierre-Yves David <pierre-yves.david@ens-lyon.org>
3 # Copyright 2012 Pierre-Yves David <pierre-yves.david@ens-lyon.org>
4 # Logilab SA <contact@logilab.fr>
4 # Logilab SA <contact@logilab.fr>
5 #
5 #
6 # This software may be used and distributed according to the terms of the
6 # This software may be used and distributed according to the terms of the
7 # GNU General Public License version 2 or any later version.
7 # GNU General Public License version 2 or any later version.
8
8
9 """Obsolete markers handling
9 """Obsolete markers handling
10
10
11 An obsolete marker maps an old changeset to a list of new
11 An obsolete marker maps an old changeset to a list of new
12 changesets. If the list of new changesets is empty, the old changeset
12 changesets. If the list of new changesets is empty, the old changeset
13 is said to be "killed". Otherwise, the old changeset is being
13 is said to be "killed". Otherwise, the old changeset is being
14 "replaced" by the new changesets.
14 "replaced" by the new changesets.
15
15
16 Obsolete markers can be used to record and distribute changeset graph
16 Obsolete markers can be used to record and distribute changeset graph
17 transformations performed by history rewriting operations, and help
17 transformations performed by history rewriting operations, and help
18 building new tools to reconciliate conflicting rewriting actions. To
18 building new tools to reconciliate conflicting rewriting actions. To
19 facilitate conflicts resolution, markers include various annotations
19 facilitate conflicts resolution, markers include various annotations
20 besides old and news changeset identifiers, such as creation date or
20 besides old and news changeset identifiers, such as creation date or
21 author name.
21 author name.
22
22
23 The old obsoleted changeset is called "precursor" and possible replacements are
23 The old obsoleted changeset is called "precursor" and possible replacements are
24 called "successors". Markers that used changeset X as a precursors are called
24 called "successors". Markers that used changeset X as a precursors are called
25 "successor markers of X" because they hold information about the successors of
25 "successor markers of X" because they hold information about the successors of
26 X. Markers that use changeset Y as a successors are call "precursor markers of
26 X. Markers that use changeset Y as a successors are call "precursor markers of
27 Y" because they hold information about the precursors of Y.
27 Y" because they hold information about the precursors of Y.
28
28
29 Examples:
29 Examples:
30
30
31 - When changeset A is replacement by a changeset A', one marker is stored:
31 - When changeset A is replacement by a changeset A', one marker is stored:
32
32
33 (A, (A'))
33 (A, (A'))
34
34
35 - When changesets A and B are folded into a new changeset C two markers are
35 - When changesets A and B are folded into a new changeset C two markers are
36 stored:
36 stored:
37
37
38 (A, (C,)) and (B, (C,))
38 (A, (C,)) and (B, (C,))
39
39
40 - When changeset A is simply "pruned" from the graph, a marker in create:
40 - When changeset A is simply "pruned" from the graph, a marker in create:
41
41
42 (A, ())
42 (A, ())
43
43
44 - When changeset A is split into B and C, a single marker are used:
44 - When changeset A is split into B and C, a single marker are used:
45
45
46 (A, (C, C))
46 (A, (C, C))
47
47
48 We use a single marker to distinct the "split" case from the "divergence"
48 We use a single marker to distinct the "split" case from the "divergence"
49 case. If two independants operation rewrite the same changeset A in to A' and
49 case. If two independants operation rewrite the same changeset A in to A' and
50 A'' when have an error case: divergent rewriting. We can detect it because
50 A'' when have an error case: divergent rewriting. We can detect it because
51 two markers will be created independently:
51 two markers will be created independently:
52
52
53 (A, (B,)) and (A, (C,))
53 (A, (B,)) and (A, (C,))
54
54
55 Format
55 Format
56 ------
56 ------
57
57
58 Markers are stored in an append-only file stored in
58 Markers are stored in an append-only file stored in
59 '.hg/store/obsstore'.
59 '.hg/store/obsstore'.
60
60
61 The file starts with a version header:
61 The file starts with a version header:
62
62
63 - 1 unsigned byte: version number, starting at zero.
63 - 1 unsigned byte: version number, starting at zero.
64
64
65
65
66 The header is followed by the markers. Each marker is made of:
66 The header is followed by the markers. Each marker is made of:
67
67
68 - 1 unsigned byte: number of new changesets "R", could be zero.
68 - 1 unsigned byte: number of new changesets "R", could be zero.
69
69
70 - 1 unsigned 32-bits integer: metadata size "M" in bytes.
70 - 1 unsigned 32-bits integer: metadata size "M" in bytes.
71
71
72 - 1 byte: a bit field. It is reserved for flags used in obsolete
72 - 1 byte: a bit field. It is reserved for flags used in obsolete
73 markers common operations, to avoid repeated decoding of metadata
73 markers common operations, to avoid repeated decoding of metadata
74 entries.
74 entries.
75
75
76 - 20 bytes: obsoleted changeset identifier.
76 - 20 bytes: obsoleted changeset identifier.
77
77
78 - N*20 bytes: new changesets identifiers.
78 - N*20 bytes: new changesets identifiers.
79
79
80 - M bytes: metadata as a sequence of nul-terminated strings. Each
80 - M bytes: metadata as a sequence of nul-terminated strings. Each
81 string contains a key and a value, separated by a color ':', without
81 string contains a key and a value, separated by a color ':', without
82 additional encoding. Keys cannot contain '\0' or ':' and values
82 additional encoding. Keys cannot contain '\0' or ':' and values
83 cannot contain '\0'.
83 cannot contain '\0'.
84 """
84 """
85 import struct
85 import struct
86 import util, base85, node
86 import util, base85, node
87 from i18n import _
87 from i18n import _
88
88
89 _pack = struct.pack
89 _pack = struct.pack
90 _unpack = struct.unpack
90 _unpack = struct.unpack
91
91
92 _SEEK_END = 2 # os.SEEK_END was introduced in Python 2.5
92 _SEEK_END = 2 # os.SEEK_END was introduced in Python 2.5
93
93
94 # the obsolete feature is not mature enough to be enabled by default.
94 # the obsolete feature is not mature enough to be enabled by default.
95 # you have to rely on third party extension extension to enable this.
95 # you have to rely on third party extension extension to enable this.
96 _enabled = False
96 _enabled = False
97
97
98 # data used for parsing and writing
98 # data used for parsing and writing
99 _fmversion = 0
99 _fmversion = 0
100 _fmfixed = '>BIB20s'
100 _fmfixed = '>BIB20s'
101 _fmnode = '20s'
101 _fmnode = '20s'
102 _fmfsize = struct.calcsize(_fmfixed)
102 _fmfsize = struct.calcsize(_fmfixed)
103 _fnodesize = struct.calcsize(_fmnode)
103 _fnodesize = struct.calcsize(_fmnode)
104
104
105 ### obsolescence marker flag
106
107 ## bumpedfix flag
108 #
109 # When a changeset A' succeed to a changeset A which became public, we call A'
110 # "bumped" because it's a successors of a public changesets
111 #
112 # o A' (bumped)
113 # |`:
114 # | o A
115 # |/
116 # o Z
117 #
118 # The way to solve this situation is to create a new changeset Ad as children
119 # of A. This changeset have the same content than A'. So the diff from A to A'
120 # is the same than the diff from A to Ad. Ad is marked as a successors of A'
121 #
122 # o Ad
123 # |`:
124 # | x A'
125 # |'|
126 # o | A
127 # |/
128 # o Z
129 #
130 # But by transitivity Ad is also a successors of A. To avoid having Ad marked
131 # as bumped too, we add the `bumpedfix` flag to the marker. <A', (Ad,)>.
132 # This flag mean that the successors are an interdiff that fix the bumped
133 # situation, breaking the transitivity of "bumped" here.
134 bumpedfix = 1
135
105 def _readmarkers(data):
136 def _readmarkers(data):
106 """Read and enumerate markers from raw data"""
137 """Read and enumerate markers from raw data"""
107 off = 0
138 off = 0
108 diskversion = _unpack('>B', data[off:off + 1])[0]
139 diskversion = _unpack('>B', data[off:off + 1])[0]
109 off += 1
140 off += 1
110 if diskversion != _fmversion:
141 if diskversion != _fmversion:
111 raise util.Abort(_('parsing obsolete marker: unknown version %r')
142 raise util.Abort(_('parsing obsolete marker: unknown version %r')
112 % diskversion)
143 % diskversion)
113
144
114 # Loop on markers
145 # Loop on markers
115 l = len(data)
146 l = len(data)
116 while off + _fmfsize <= l:
147 while off + _fmfsize <= l:
117 # read fixed part
148 # read fixed part
118 cur = data[off:off + _fmfsize]
149 cur = data[off:off + _fmfsize]
119 off += _fmfsize
150 off += _fmfsize
120 nbsuc, mdsize, flags, pre = _unpack(_fmfixed, cur)
151 nbsuc, mdsize, flags, pre = _unpack(_fmfixed, cur)
121 # read replacement
152 # read replacement
122 sucs = ()
153 sucs = ()
123 if nbsuc:
154 if nbsuc:
124 s = (_fnodesize * nbsuc)
155 s = (_fnodesize * nbsuc)
125 cur = data[off:off + s]
156 cur = data[off:off + s]
126 sucs = _unpack(_fmnode * nbsuc, cur)
157 sucs = _unpack(_fmnode * nbsuc, cur)
127 off += s
158 off += s
128 # read metadata
159 # read metadata
129 # (metadata will be decoded on demand)
160 # (metadata will be decoded on demand)
130 metadata = data[off:off + mdsize]
161 metadata = data[off:off + mdsize]
131 if len(metadata) != mdsize:
162 if len(metadata) != mdsize:
132 raise util.Abort(_('parsing obsolete marker: metadata is too '
163 raise util.Abort(_('parsing obsolete marker: metadata is too '
133 'short, %d bytes expected, got %d')
164 'short, %d bytes expected, got %d')
134 % (mdsize, len(metadata)))
165 % (mdsize, len(metadata)))
135 off += mdsize
166 off += mdsize
136 yield (pre, sucs, flags, metadata)
167 yield (pre, sucs, flags, metadata)
137
168
138 def encodemeta(meta):
169 def encodemeta(meta):
139 """Return encoded metadata string to string mapping.
170 """Return encoded metadata string to string mapping.
140
171
141 Assume no ':' in key and no '\0' in both key and value."""
172 Assume no ':' in key and no '\0' in both key and value."""
142 for key, value in meta.iteritems():
173 for key, value in meta.iteritems():
143 if ':' in key or '\0' in key:
174 if ':' in key or '\0' in key:
144 raise ValueError("':' and '\0' are forbidden in metadata key'")
175 raise ValueError("':' and '\0' are forbidden in metadata key'")
145 if '\0' in value:
176 if '\0' in value:
146 raise ValueError("':' are forbidden in metadata value'")
177 raise ValueError("':' are forbidden in metadata value'")
147 return '\0'.join(['%s:%s' % (k, meta[k]) for k in sorted(meta)])
178 return '\0'.join(['%s:%s' % (k, meta[k]) for k in sorted(meta)])
148
179
149 def decodemeta(data):
180 def decodemeta(data):
150 """Return string to string dictionary from encoded version."""
181 """Return string to string dictionary from encoded version."""
151 d = {}
182 d = {}
152 for l in data.split('\0'):
183 for l in data.split('\0'):
153 if l:
184 if l:
154 key, value = l.split(':')
185 key, value = l.split(':')
155 d[key] = value
186 d[key] = value
156 return d
187 return d
157
188
158 class marker(object):
189 class marker(object):
159 """Wrap obsolete marker raw data"""
190 """Wrap obsolete marker raw data"""
160
191
161 def __init__(self, repo, data):
192 def __init__(self, repo, data):
162 # the repo argument will be used to create changectx in later version
193 # the repo argument will be used to create changectx in later version
163 self._repo = repo
194 self._repo = repo
164 self._data = data
195 self._data = data
165 self._decodedmeta = None
196 self._decodedmeta = None
166
197
167 def precnode(self):
198 def precnode(self):
168 """Precursor changeset node identifier"""
199 """Precursor changeset node identifier"""
169 return self._data[0]
200 return self._data[0]
170
201
171 def succnodes(self):
202 def succnodes(self):
172 """List of successor changesets node identifiers"""
203 """List of successor changesets node identifiers"""
173 return self._data[1]
204 return self._data[1]
174
205
175 def metadata(self):
206 def metadata(self):
176 """Decoded metadata dictionary"""
207 """Decoded metadata dictionary"""
177 if self._decodedmeta is None:
208 if self._decodedmeta is None:
178 self._decodedmeta = decodemeta(self._data[3])
209 self._decodedmeta = decodemeta(self._data[3])
179 return self._decodedmeta
210 return self._decodedmeta
180
211
181 def date(self):
212 def date(self):
182 """Creation date as (unixtime, offset)"""
213 """Creation date as (unixtime, offset)"""
183 parts = self.metadata()['date'].split(' ')
214 parts = self.metadata()['date'].split(' ')
184 return (float(parts[0]), int(parts[1]))
215 return (float(parts[0]), int(parts[1]))
185
216
186 class obsstore(object):
217 class obsstore(object):
187 """Store obsolete markers
218 """Store obsolete markers
188
219
189 Markers can be accessed with two mappings:
220 Markers can be accessed with two mappings:
190 - precursors[x] -> set(markers on precursors edges of x)
221 - precursors[x] -> set(markers on precursors edges of x)
191 - successors[x] -> set(markers on successors edges of x)
222 - successors[x] -> set(markers on successors edges of x)
192 """
223 """
193
224
194 def __init__(self, sopener):
225 def __init__(self, sopener):
195 # caches for various obsolescence related cache
226 # caches for various obsolescence related cache
196 self.caches = {}
227 self.caches = {}
197 self._all = []
228 self._all = []
198 # new markers to serialize
229 # new markers to serialize
199 self.precursors = {}
230 self.precursors = {}
200 self.successors = {}
231 self.successors = {}
201 self.sopener = sopener
232 self.sopener = sopener
202 data = sopener.tryread('obsstore')
233 data = sopener.tryread('obsstore')
203 if data:
234 if data:
204 self._load(_readmarkers(data))
235 self._load(_readmarkers(data))
205
236
206 def __iter__(self):
237 def __iter__(self):
207 return iter(self._all)
238 return iter(self._all)
208
239
209 def __nonzero__(self):
240 def __nonzero__(self):
210 return bool(self._all)
241 return bool(self._all)
211
242
212 def create(self, transaction, prec, succs=(), flag=0, metadata=None):
243 def create(self, transaction, prec, succs=(), flag=0, metadata=None):
213 """obsolete: add a new obsolete marker
244 """obsolete: add a new obsolete marker
214
245
215 * ensuring it is hashable
246 * ensuring it is hashable
216 * check mandatory metadata
247 * check mandatory metadata
217 * encode metadata
248 * encode metadata
218 """
249 """
219 if metadata is None:
250 if metadata is None:
220 metadata = {}
251 metadata = {}
221 if len(prec) != 20:
252 if len(prec) != 20:
222 raise ValueError(prec)
253 raise ValueError(prec)
223 for succ in succs:
254 for succ in succs:
224 if len(succ) != 20:
255 if len(succ) != 20:
225 raise ValueError(succ)
256 raise ValueError(succ)
226 marker = (str(prec), tuple(succs), int(flag), encodemeta(metadata))
257 marker = (str(prec), tuple(succs), int(flag), encodemeta(metadata))
227 self.add(transaction, [marker])
258 self.add(transaction, [marker])
228
259
229 def add(self, transaction, markers):
260 def add(self, transaction, markers):
230 """Add new markers to the store
261 """Add new markers to the store
231
262
232 Take care of filtering duplicate.
263 Take care of filtering duplicate.
233 Return the number of new marker."""
264 Return the number of new marker."""
234 if not _enabled:
265 if not _enabled:
235 raise util.Abort('obsolete feature is not enabled on this repo')
266 raise util.Abort('obsolete feature is not enabled on this repo')
236 new = [m for m in markers if m not in self._all]
267 new = [m for m in markers if m not in self._all]
237 if new:
268 if new:
238 f = self.sopener('obsstore', 'ab')
269 f = self.sopener('obsstore', 'ab')
239 try:
270 try:
240 # Whether the file's current position is at the begin or at
271 # Whether the file's current position is at the begin or at
241 # the end after opening a file for appending is implementation
272 # the end after opening a file for appending is implementation
242 # defined. So we must seek to the end before calling tell(),
273 # defined. So we must seek to the end before calling tell(),
243 # or we may get a zero offset for non-zero sized files on
274 # or we may get a zero offset for non-zero sized files on
244 # some platforms (issue3543).
275 # some platforms (issue3543).
245 f.seek(0, _SEEK_END)
276 f.seek(0, _SEEK_END)
246 offset = f.tell()
277 offset = f.tell()
247 transaction.add('obsstore', offset)
278 transaction.add('obsstore', offset)
248 # offset == 0: new file - add the version header
279 # offset == 0: new file - add the version header
249 for bytes in _encodemarkers(new, offset == 0):
280 for bytes in _encodemarkers(new, offset == 0):
250 f.write(bytes)
281 f.write(bytes)
251 finally:
282 finally:
252 # XXX: f.close() == filecache invalidation == obsstore rebuilt.
283 # XXX: f.close() == filecache invalidation == obsstore rebuilt.
253 # call 'filecacheentry.refresh()' here
284 # call 'filecacheentry.refresh()' here
254 f.close()
285 f.close()
255 self._load(new)
286 self._load(new)
256 # new marker *may* have changed several set. invalidate the cache.
287 # new marker *may* have changed several set. invalidate the cache.
257 self.caches.clear()
288 self.caches.clear()
258 return len(new)
289 return len(new)
259
290
260 def mergemarkers(self, transaction, data):
291 def mergemarkers(self, transaction, data):
261 markers = _readmarkers(data)
292 markers = _readmarkers(data)
262 self.add(transaction, markers)
293 self.add(transaction, markers)
263
294
264 def _load(self, markers):
295 def _load(self, markers):
265 for mark in markers:
296 for mark in markers:
266 self._all.append(mark)
297 self._all.append(mark)
267 pre, sucs = mark[:2]
298 pre, sucs = mark[:2]
268 self.successors.setdefault(pre, set()).add(mark)
299 self.successors.setdefault(pre, set()).add(mark)
269 for suc in sucs:
300 for suc in sucs:
270 self.precursors.setdefault(suc, set()).add(mark)
301 self.precursors.setdefault(suc, set()).add(mark)
271 if node.nullid in self.precursors:
302 if node.nullid in self.precursors:
272 raise util.Abort(_('bad obsolescence marker detected: '
303 raise util.Abort(_('bad obsolescence marker detected: '
273 'invalid successors nullid'))
304 'invalid successors nullid'))
274
305
275 def _encodemarkers(markers, addheader=False):
306 def _encodemarkers(markers, addheader=False):
276 # Kept separate from flushmarkers(), it will be reused for
307 # Kept separate from flushmarkers(), it will be reused for
277 # markers exchange.
308 # markers exchange.
278 if addheader:
309 if addheader:
279 yield _pack('>B', _fmversion)
310 yield _pack('>B', _fmversion)
280 for marker in markers:
311 for marker in markers:
281 yield _encodeonemarker(marker)
312 yield _encodeonemarker(marker)
282
313
283
314
284 def _encodeonemarker(marker):
315 def _encodeonemarker(marker):
285 pre, sucs, flags, metadata = marker
316 pre, sucs, flags, metadata = marker
286 nbsuc = len(sucs)
317 nbsuc = len(sucs)
287 format = _fmfixed + (_fmnode * nbsuc)
318 format = _fmfixed + (_fmnode * nbsuc)
288 data = [nbsuc, len(metadata), flags, pre]
319 data = [nbsuc, len(metadata), flags, pre]
289 data.extend(sucs)
320 data.extend(sucs)
290 return _pack(format, *data) + metadata
321 return _pack(format, *data) + metadata
291
322
292 # arbitrary picked to fit into 8K limit from HTTP server
323 # arbitrary picked to fit into 8K limit from HTTP server
293 # you have to take in account:
324 # you have to take in account:
294 # - the version header
325 # - the version header
295 # - the base85 encoding
326 # - the base85 encoding
296 _maxpayload = 5300
327 _maxpayload = 5300
297
328
298 def listmarkers(repo):
329 def listmarkers(repo):
299 """List markers over pushkey"""
330 """List markers over pushkey"""
300 if not repo.obsstore:
331 if not repo.obsstore:
301 return {}
332 return {}
302 keys = {}
333 keys = {}
303 parts = []
334 parts = []
304 currentlen = _maxpayload * 2 # ensure we create a new part
335 currentlen = _maxpayload * 2 # ensure we create a new part
305 for marker in repo.obsstore:
336 for marker in repo.obsstore:
306 nextdata = _encodeonemarker(marker)
337 nextdata = _encodeonemarker(marker)
307 if (len(nextdata) + currentlen > _maxpayload):
338 if (len(nextdata) + currentlen > _maxpayload):
308 currentpart = []
339 currentpart = []
309 currentlen = 0
340 currentlen = 0
310 parts.append(currentpart)
341 parts.append(currentpart)
311 currentpart.append(nextdata)
342 currentpart.append(nextdata)
312 currentlen += len(nextdata)
343 currentlen += len(nextdata)
313 for idx, part in enumerate(reversed(parts)):
344 for idx, part in enumerate(reversed(parts)):
314 data = ''.join([_pack('>B', _fmversion)] + part)
345 data = ''.join([_pack('>B', _fmversion)] + part)
315 keys['dump%i' % idx] = base85.b85encode(data)
346 keys['dump%i' % idx] = base85.b85encode(data)
316 return keys
347 return keys
317
348
318 def pushmarker(repo, key, old, new):
349 def pushmarker(repo, key, old, new):
319 """Push markers over pushkey"""
350 """Push markers over pushkey"""
320 if not key.startswith('dump'):
351 if not key.startswith('dump'):
321 repo.ui.warn(_('unknown key: %r') % key)
352 repo.ui.warn(_('unknown key: %r') % key)
322 return 0
353 return 0
323 if old:
354 if old:
324 repo.ui.warn(_('unexpected old value') % key)
355 repo.ui.warn(_('unexpected old value') % key)
325 return 0
356 return 0
326 data = base85.b85decode(new)
357 data = base85.b85decode(new)
327 lock = repo.lock()
358 lock = repo.lock()
328 try:
359 try:
329 tr = repo.transaction('pushkey: obsolete markers')
360 tr = repo.transaction('pushkey: obsolete markers')
330 try:
361 try:
331 repo.obsstore.mergemarkers(tr, data)
362 repo.obsstore.mergemarkers(tr, data)
332 tr.close()
363 tr.close()
333 return 1
364 return 1
334 finally:
365 finally:
335 tr.release()
366 tr.release()
336 finally:
367 finally:
337 lock.release()
368 lock.release()
338
369
339 def allmarkers(repo):
370 def allmarkers(repo):
340 """all obsolete markers known in a repository"""
371 """all obsolete markers known in a repository"""
341 for markerdata in repo.obsstore:
372 for markerdata in repo.obsstore:
342 yield marker(repo, markerdata)
373 yield marker(repo, markerdata)
343
374
344 def precursormarkers(ctx):
375 def precursormarkers(ctx):
345 """obsolete marker marking this changeset as a successors"""
376 """obsolete marker marking this changeset as a successors"""
346 for data in ctx._repo.obsstore.precursors.get(ctx.node(), ()):
377 for data in ctx._repo.obsstore.precursors.get(ctx.node(), ()):
347 yield marker(ctx._repo, data)
378 yield marker(ctx._repo, data)
348
379
349 def successormarkers(ctx):
380 def successormarkers(ctx):
350 """obsolete marker making this changeset obsolete"""
381 """obsolete marker making this changeset obsolete"""
351 for data in ctx._repo.obsstore.successors.get(ctx.node(), ()):
382 for data in ctx._repo.obsstore.successors.get(ctx.node(), ()):
352 yield marker(ctx._repo, data)
383 yield marker(ctx._repo, data)
353
384
354 def allsuccessors(obsstore, nodes):
385 def allsuccessors(obsstore, nodes, ignoreflags=0):
355 """Yield node for every successor of <nodes>.
386 """Yield node for every successor of <nodes>.
356
387
357 Some successors may be unknown locally.
388 Some successors may be unknown locally.
358
389
359 This is a linear yield unsuited to detecting split changesets."""
390 This is a linear yield unsuited to detecting split changesets."""
360 remaining = set(nodes)
391 remaining = set(nodes)
361 seen = set(remaining)
392 seen = set(remaining)
362 while remaining:
393 while remaining:
363 current = remaining.pop()
394 current = remaining.pop()
364 yield current
395 yield current
365 for mark in obsstore.successors.get(current, ()):
396 for mark in obsstore.successors.get(current, ()):
397 # ignore marker flagged with with specified flag
398 if mark[2] & ignoreflags:
399 continue
366 for suc in mark[1]:
400 for suc in mark[1]:
367 if suc not in seen:
401 if suc not in seen:
368 seen.add(suc)
402 seen.add(suc)
369 remaining.add(suc)
403 remaining.add(suc)
370
404
371 def _knownrevs(repo, nodes):
405 def _knownrevs(repo, nodes):
372 """yield revision numbers of known nodes passed in parameters
406 """yield revision numbers of known nodes passed in parameters
373
407
374 Unknown revisions are silently ignored."""
408 Unknown revisions are silently ignored."""
375 torev = repo.changelog.nodemap.get
409 torev = repo.changelog.nodemap.get
376 for n in nodes:
410 for n in nodes:
377 rev = torev(n)
411 rev = torev(n)
378 if rev is not None:
412 if rev is not None:
379 yield rev
413 yield rev
380
414
381 # mapping of 'set-name' -> <function to compute this set>
415 # mapping of 'set-name' -> <function to compute this set>
382 cachefuncs = {}
416 cachefuncs = {}
383 def cachefor(name):
417 def cachefor(name):
384 """Decorator to register a function as computing the cache for a set"""
418 """Decorator to register a function as computing the cache for a set"""
385 def decorator(func):
419 def decorator(func):
386 assert name not in cachefuncs
420 assert name not in cachefuncs
387 cachefuncs[name] = func
421 cachefuncs[name] = func
388 return func
422 return func
389 return decorator
423 return decorator
390
424
391 def getrevs(repo, name):
425 def getrevs(repo, name):
392 """Return the set of revision that belong to the <name> set
426 """Return the set of revision that belong to the <name> set
393
427
394 Such access may compute the set and cache it for future use"""
428 Such access may compute the set and cache it for future use"""
395 if not repo.obsstore:
429 if not repo.obsstore:
396 return ()
430 return ()
397 if name not in repo.obsstore.caches:
431 if name not in repo.obsstore.caches:
398 repo.obsstore.caches[name] = cachefuncs[name](repo)
432 repo.obsstore.caches[name] = cachefuncs[name](repo)
399 return repo.obsstore.caches[name]
433 return repo.obsstore.caches[name]
400
434
401 # To be simple we need to invalidate obsolescence cache when:
435 # To be simple we need to invalidate obsolescence cache when:
402 #
436 #
403 # - new changeset is added:
437 # - new changeset is added:
404 # - public phase is changed
438 # - public phase is changed
405 # - obsolescence marker are added
439 # - obsolescence marker are added
406 # - strip is used a repo
440 # - strip is used a repo
407 def clearobscaches(repo):
441 def clearobscaches(repo):
408 """Remove all obsolescence related cache from a repo
442 """Remove all obsolescence related cache from a repo
409
443
410 This remove all cache in obsstore is the obsstore already exist on the
444 This remove all cache in obsstore is the obsstore already exist on the
411 repo.
445 repo.
412
446
413 (We could be smarter here given the exact event that trigger the cache
447 (We could be smarter here given the exact event that trigger the cache
414 clearing)"""
448 clearing)"""
415 # only clear cache is there is obsstore data in this repo
449 # only clear cache is there is obsstore data in this repo
416 if 'obsstore' in repo._filecache:
450 if 'obsstore' in repo._filecache:
417 repo.obsstore.caches.clear()
451 repo.obsstore.caches.clear()
418
452
419 @cachefor('obsolete')
453 @cachefor('obsolete')
420 def _computeobsoleteset(repo):
454 def _computeobsoleteset(repo):
421 """the set of obsolete revisions"""
455 """the set of obsolete revisions"""
422 obs = set()
456 obs = set()
423 nm = repo.changelog.nodemap
457 nm = repo.changelog.nodemap
424 for node in repo.obsstore.successors:
458 for node in repo.obsstore.successors:
425 rev = nm.get(node)
459 rev = nm.get(node)
426 if rev is not None:
460 if rev is not None:
427 obs.add(rev)
461 obs.add(rev)
428 return set(repo.revs('%ld - public()', obs))
462 return set(repo.revs('%ld - public()', obs))
429
463
430 @cachefor('unstable')
464 @cachefor('unstable')
431 def _computeunstableset(repo):
465 def _computeunstableset(repo):
432 """the set of non obsolete revisions with obsolete parents"""
466 """the set of non obsolete revisions with obsolete parents"""
433 return set(repo.revs('(obsolete()::) - obsolete()'))
467 return set(repo.revs('(obsolete()::) - obsolete()'))
434
468
435 @cachefor('suspended')
469 @cachefor('suspended')
436 def _computesuspendedset(repo):
470 def _computesuspendedset(repo):
437 """the set of obsolete parents with non obsolete descendants"""
471 """the set of obsolete parents with non obsolete descendants"""
438 return set(repo.revs('obsolete() and obsolete()::unstable()'))
472 return set(repo.revs('obsolete() and obsolete()::unstable()'))
439
473
440 @cachefor('extinct')
474 @cachefor('extinct')
441 def _computeextinctset(repo):
475 def _computeextinctset(repo):
442 """the set of obsolete parents without non obsolete descendants"""
476 """the set of obsolete parents without non obsolete descendants"""
443 return set(repo.revs('obsolete() - obsolete()::unstable()'))
477 return set(repo.revs('obsolete() - obsolete()::unstable()'))
444
478
445
479
446 @cachefor('bumped')
480 @cachefor('bumped')
447 def _computebumpedset(repo):
481 def _computebumpedset(repo):
448 """the set of revs trying to obsolete public revisions"""
482 """the set of revs trying to obsolete public revisions"""
449 # get all possible bumped changesets
483 # get all possible bumped changesets
450 tonode = repo.changelog.node
484 tonode = repo.changelog.node
451 publicnodes = (tonode(r) for r in repo.revs('public()'))
485 publicnodes = (tonode(r) for r in repo.revs('public()'))
452 successors = allsuccessors(repo.obsstore, publicnodes)
486 successors = allsuccessors(repo.obsstore, publicnodes,
487 ignoreflags=bumpedfix)
453 # revision public or already obsolete don't count as bumped
488 # revision public or already obsolete don't count as bumped
454 query = '%ld - obsolete() - public()'
489 query = '%ld - obsolete() - public()'
455 return set(repo.revs(query, _knownrevs(repo, successors)))
490 return set(repo.revs(query, _knownrevs(repo, successors)))
456
491
457 def createmarkers(repo, relations, flag=0, metadata=None):
492 def createmarkers(repo, relations, flag=0, metadata=None):
458 """Add obsolete markers between changesets in a repo
493 """Add obsolete markers between changesets in a repo
459
494
460 <relations> must be an iterable of (<old>, (<new>, ...)) tuple.
495 <relations> must be an iterable of (<old>, (<new>, ...)) tuple.
461 `old` and `news` are changectx.
496 `old` and `news` are changectx.
462
497
463 Trying to obsolete a public changeset will raise an exception.
498 Trying to obsolete a public changeset will raise an exception.
464
499
465 Current user and date are used except if specified otherwise in the
500 Current user and date are used except if specified otherwise in the
466 metadata attribute.
501 metadata attribute.
467
502
468 This function operates within a transaction of its own, but does
503 This function operates within a transaction of its own, but does
469 not take any lock on the repo.
504 not take any lock on the repo.
470 """
505 """
471 # prepare metadata
506 # prepare metadata
472 if metadata is None:
507 if metadata is None:
473 metadata = {}
508 metadata = {}
474 if 'date' not in metadata:
509 if 'date' not in metadata:
475 metadata['date'] = '%i %i' % util.makedate()
510 metadata['date'] = '%i %i' % util.makedate()
476 if 'user' not in metadata:
511 if 'user' not in metadata:
477 metadata['user'] = repo.ui.username()
512 metadata['user'] = repo.ui.username()
478 tr = repo.transaction('add-obsolescence-marker')
513 tr = repo.transaction('add-obsolescence-marker')
479 try:
514 try:
480 for prec, sucs in relations:
515 for prec, sucs in relations:
481 if not prec.mutable():
516 if not prec.mutable():
482 raise util.Abort("cannot obsolete immutable changeset: %s"
517 raise util.Abort("cannot obsolete immutable changeset: %s"
483 % prec)
518 % prec)
484 nprec = prec.node()
519 nprec = prec.node()
485 nsucs = tuple(s.node() for s in sucs)
520 nsucs = tuple(s.node() for s in sucs)
486 if nprec in nsucs:
521 if nprec in nsucs:
487 raise util.Abort("changeset %s cannot obsolete itself" % prec)
522 raise util.Abort("changeset %s cannot obsolete itself" % prec)
488 repo.obsstore.create(tr, nprec, nsucs, flag, metadata)
523 repo.obsstore.create(tr, nprec, nsucs, flag, metadata)
489 tr.close()
524 tr.close()
490 finally:
525 finally:
491 tr.release()
526 tr.release()
@@ -1,534 +1,584 b''
1 $ cat >> $HGRCPATH << EOF
1 $ cat >> $HGRCPATH << EOF
2 > [extensions]
2 > [extensions]
3 > graphlog=
3 > graphlog=
4 > [phases]
4 > [phases]
5 > # public changeset are not obsolete
5 > # public changeset are not obsolete
6 > publish=false
6 > publish=false
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 id --debug -ir "desc('$1')"
14 > hg id --debug -ir "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('listkeys %s\n' % (namespace,))
21 > ui.write('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: obsolete feature is not enabled on this repo
35 abort: obsolete feature is not enabled on this repo
36 [255]
36 [255]
37
37
38 Enabling it
38 Enabling it
39
39
40 $ cat > ../obs.py << EOF
40 $ cat > ../obs.py << EOF
41 > import mercurial.obsolete
41 > import mercurial.obsolete
42 > mercurial.obsolete._enabled = True
42 > mercurial.obsolete._enabled = True
43 > EOF
43 > EOF
44 $ echo '[extensions]' >> $HGRCPATH
44 $ echo '[extensions]' >> $HGRCPATH
45 $ echo "obs=${TESTTMP}/obs.py" >> $HGRCPATH
45 $ echo "obs=${TESTTMP}/obs.py" >> $HGRCPATH
46
46
47 Killing a single changeset without replacement
47 Killing a single changeset without replacement
48
48
49 $ hg debugobsolete 0
49 $ hg debugobsolete 0
50 abort: changeset references must be full hexadecimal node identifiers
50 abort: changeset references must be full hexadecimal node identifiers
51 [255]
51 [255]
52 $ hg debugobsolete '00'
52 $ hg debugobsolete '00'
53 abort: changeset references must be full hexadecimal node identifiers
53 abort: changeset references must be full hexadecimal node identifiers
54 [255]
54 [255]
55 $ hg debugobsolete -d '0 0' `getid kill_me` -u babar
55 $ hg debugobsolete -d '0 0' `getid kill_me` -u babar
56 $ hg debugobsolete
56 $ hg debugobsolete
57 97b7c2d76b1845ed3eb988cd612611e72406cef0 0 {'date': '0 0', 'user': 'babar'}
57 97b7c2d76b1845ed3eb988cd612611e72406cef0 0 {'date': '0 0', 'user': 'babar'}
58 $ cd ..
58 $ cd ..
59
59
60 Killing a single changeset with replacement
60 Killing a single changeset with replacement
61
61
62 $ hg init tmpb
62 $ hg init tmpb
63 $ cd tmpb
63 $ cd tmpb
64 $ mkcommit a
64 $ mkcommit a
65 $ mkcommit b
65 $ mkcommit b
66 $ mkcommit original_c
66 $ mkcommit original_c
67 $ hg up "desc('b')"
67 $ hg up "desc('b')"
68 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
68 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
69 $ mkcommit new_c
69 $ mkcommit new_c
70 created new head
70 created new head
71 $ hg log -r 'hidden()' --template '{rev}:{node|short} {desc}\n' --hidden
71 $ hg log -r 'hidden()' --template '{rev}:{node|short} {desc}\n' --hidden
72 $ hg debugobsolete --flag 12 `getid original_c` `getid new_c` -d '56 12'
72 $ hg debugobsolete --flag 12 `getid original_c` `getid new_c` -d '56 12'
73 $ hg log -r 'hidden()' --template '{rev}:{node|short} {desc}\n' --hidden
73 $ hg log -r 'hidden()' --template '{rev}:{node|short} {desc}\n' --hidden
74 2:245bde4270cd add original_c
74 2:245bde4270cd add original_c
75 $ hg debugobsolete
75 $ hg debugobsolete
76 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C {'date': '56 12', 'user': 'test'}
76 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C {'date': '56 12', 'user': 'test'}
77
77
78 do it again (it read the obsstore before adding new changeset)
78 do it again (it read the obsstore before adding new changeset)
79
79
80 $ hg up '.^'
80 $ hg up '.^'
81 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
81 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
82 $ mkcommit new_2_c
82 $ mkcommit new_2_c
83 created new head
83 created new head
84 $ hg debugobsolete -d '1337 0' `getid new_c` `getid new_2_c`
84 $ hg debugobsolete -d '1337 0' `getid new_c` `getid new_2_c`
85 $ hg debugobsolete
85 $ hg debugobsolete
86 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C {'date': '56 12', 'user': 'test'}
86 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C {'date': '56 12', 'user': 'test'}
87 cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 {'date': '1337 0', 'user': 'test'}
87 cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 {'date': '1337 0', 'user': 'test'}
88
88
89 Register two markers with a missing node
89 Register two markers with a missing node
90
90
91 $ hg up '.^'
91 $ hg up '.^'
92 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
92 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
93 $ mkcommit new_3_c
93 $ mkcommit new_3_c
94 created new head
94 created new head
95 $ hg debugobsolete -d '1338 0' `getid new_2_c` 1337133713371337133713371337133713371337
95 $ hg debugobsolete -d '1338 0' `getid new_2_c` 1337133713371337133713371337133713371337
96 $ hg debugobsolete -d '1339 0' 1337133713371337133713371337133713371337 `getid new_3_c`
96 $ hg debugobsolete -d '1339 0' 1337133713371337133713371337133713371337 `getid new_3_c`
97 $ hg debugobsolete
97 $ hg debugobsolete
98 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C {'date': '56 12', 'user': 'test'}
98 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C {'date': '56 12', 'user': 'test'}
99 cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 {'date': '1337 0', 'user': 'test'}
99 cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 {'date': '1337 0', 'user': 'test'}
100 ca819180edb99ed25ceafb3e9584ac287e240b00 1337133713371337133713371337133713371337 0 {'date': '1338 0', 'user': 'test'}
100 ca819180edb99ed25ceafb3e9584ac287e240b00 1337133713371337133713371337133713371337 0 {'date': '1338 0', 'user': 'test'}
101 1337133713371337133713371337133713371337 5601fb93a350734d935195fee37f4054c529ff39 0 {'date': '1339 0', 'user': 'test'}
101 1337133713371337133713371337133713371337 5601fb93a350734d935195fee37f4054c529ff39 0 {'date': '1339 0', 'user': 'test'}
102
102
103 Refuse pathological nullid successors
103 Refuse pathological nullid successors
104 $ hg debugobsolete -d '9001 0' 1337133713371337133713371337133713371337 0000000000000000000000000000000000000000
104 $ hg debugobsolete -d '9001 0' 1337133713371337133713371337133713371337 0000000000000000000000000000000000000000
105 transaction abort!
105 transaction abort!
106 rollback completed
106 rollback completed
107 abort: bad obsolescence marker detected: invalid successors nullid
107 abort: bad obsolescence marker detected: invalid successors nullid
108 [255]
108 [255]
109
109
110 Check that graphlog detect that a changeset is obsolete:
110 Check that graphlog detect that a changeset is obsolete:
111
111
112 $ hg glog
112 $ hg glog
113 @ changeset: 5:5601fb93a350
113 @ changeset: 5:5601fb93a350
114 | tag: tip
114 | tag: tip
115 | parent: 1:7c3bad9141dc
115 | parent: 1:7c3bad9141dc
116 | user: test
116 | user: test
117 | date: Thu Jan 01 00:00:00 1970 +0000
117 | date: Thu Jan 01 00:00:00 1970 +0000
118 | summary: add new_3_c
118 | summary: add new_3_c
119 |
119 |
120 o changeset: 1:7c3bad9141dc
120 o changeset: 1:7c3bad9141dc
121 | user: test
121 | user: test
122 | date: Thu Jan 01 00:00:00 1970 +0000
122 | date: Thu Jan 01 00:00:00 1970 +0000
123 | summary: add b
123 | summary: add b
124 |
124 |
125 o changeset: 0:1f0dee641bb7
125 o changeset: 0:1f0dee641bb7
126 user: test
126 user: test
127 date: Thu Jan 01 00:00:00 1970 +0000
127 date: Thu Jan 01 00:00:00 1970 +0000
128 summary: add a
128 summary: add a
129
129
130
130
131 Check that public changeset are not accounted as obsolete:
131 Check that public changeset are not accounted as obsolete:
132
132
133 $ hg phase --public 2
133 $ hg phase --public 2
134 $ hg --config 'extensions.graphlog=' glog
134 $ hg --config 'extensions.graphlog=' glog
135 @ changeset: 5:5601fb93a350
135 @ changeset: 5:5601fb93a350
136 | tag: tip
136 | tag: tip
137 | parent: 1:7c3bad9141dc
137 | parent: 1:7c3bad9141dc
138 | user: test
138 | user: test
139 | date: Thu Jan 01 00:00:00 1970 +0000
139 | date: Thu Jan 01 00:00:00 1970 +0000
140 | summary: add new_3_c
140 | summary: add new_3_c
141 |
141 |
142 | o changeset: 2:245bde4270cd
142 | o changeset: 2:245bde4270cd
143 |/ user: test
143 |/ user: test
144 | date: Thu Jan 01 00:00:00 1970 +0000
144 | date: Thu Jan 01 00:00:00 1970 +0000
145 | summary: add original_c
145 | summary: add original_c
146 |
146 |
147 o changeset: 1:7c3bad9141dc
147 o changeset: 1:7c3bad9141dc
148 | user: test
148 | user: test
149 | date: Thu Jan 01 00:00:00 1970 +0000
149 | date: Thu Jan 01 00:00:00 1970 +0000
150 | summary: add b
150 | summary: add b
151 |
151 |
152 o changeset: 0:1f0dee641bb7
152 o changeset: 0:1f0dee641bb7
153 user: test
153 user: test
154 date: Thu Jan 01 00:00:00 1970 +0000
154 date: Thu Jan 01 00:00:00 1970 +0000
155 summary: add a
155 summary: add a
156
156
157
157
158 And that bumped changeset are detected
158 And that bumped changeset are detected
159 --------------------------------------
159 --------------------------------------
160
160
161 If we didn't filtered obsolete changesets out, 3 and 4 would show up too. Also
161 If we didn't filtered obsolete changesets out, 3 and 4 would show up too. Also
162 note that the bumped changeset (5:5601fb93a350) is not a direct successor of
162 note that the bumped changeset (5:5601fb93a350) is not a direct successor of
163 the public changeset
163 the public changeset
164
164
165 $ hg log --hidden -r 'bumped()'
165 $ hg log --hidden -r 'bumped()'
166 changeset: 5:5601fb93a350
166 changeset: 5:5601fb93a350
167 tag: tip
167 tag: tip
168 parent: 1:7c3bad9141dc
168 parent: 1:7c3bad9141dc
169 user: test
169 user: test
170 date: Thu Jan 01 00:00:00 1970 +0000
170 date: Thu Jan 01 00:00:00 1970 +0000
171 summary: add new_3_c
171 summary: add new_3_c
172
172
173
173
174 Fixing "bumped" situation
175 We need to create a clone of 5 and add a special marker with a flag
176
177 $ hg up '5^'
178 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
179 $ hg revert -ar 5
180 adding new_3_c
181 $ hg ci -m 'add n3w_3_c'
182 created new head
183 $ hg debugobsolete -d '1338 0' --flags 1 `getid new_3_c` `getid n3w_3_c`
184 $ hg log -r 'bumped()'
185 $ hg log -G
186 @ changeset: 6:6f9641995072
187 | tag: tip
188 | parent: 1:7c3bad9141dc
189 | user: test
190 | date: Thu Jan 01 00:00:00 1970 +0000
191 | summary: add n3w_3_c
192 |
193 | o changeset: 2:245bde4270cd
194 |/ user: test
195 | date: Thu Jan 01 00:00:00 1970 +0000
196 | summary: add original_c
197 |
198 o changeset: 1:7c3bad9141dc
199 | user: test
200 | date: Thu Jan 01 00:00:00 1970 +0000
201 | summary: add b
202 |
203 o changeset: 0:1f0dee641bb7
204 user: test
205 date: Thu Jan 01 00:00:00 1970 +0000
206 summary: add a
207
208
209
210
174 $ cd ..
211 $ cd ..
175
212
176 Exchange Test
213 Exchange Test
177 ============================
214 ============================
178
215
179 Destination repo does not have any data
216 Destination repo does not have any data
180 ---------------------------------------
217 ---------------------------------------
181
218
182 Try to pull markers
219 Try to pull markers
183 (extinct changeset are excluded but marker are pushed)
220 (extinct changeset are excluded but marker are pushed)
184
221
185 $ hg init tmpc
222 $ hg init tmpc
186 $ cd tmpc
223 $ cd tmpc
187 $ hg pull ../tmpb
224 $ hg pull ../tmpb
188 pulling from ../tmpb
225 pulling from ../tmpb
189 requesting all changes
226 requesting all changes
190 adding changesets
227 adding changesets
191 adding manifests
228 adding manifests
192 adding file changes
229 adding file changes
193 added 4 changesets with 4 changes to 4 files (+1 heads)
230 added 4 changesets with 4 changes to 4 files (+1 heads)
194 (run 'hg heads' to see heads, 'hg merge' to merge)
231 (run 'hg heads' to see heads, 'hg merge' to merge)
195 $ hg debugobsolete
232 $ hg debugobsolete
196 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C {'date': '56 12', 'user': 'test'}
233 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C {'date': '56 12', 'user': 'test'}
197 cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 {'date': '1337 0', 'user': 'test'}
234 cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 {'date': '1337 0', 'user': 'test'}
198 ca819180edb99ed25ceafb3e9584ac287e240b00 1337133713371337133713371337133713371337 0 {'date': '1338 0', 'user': 'test'}
235 ca819180edb99ed25ceafb3e9584ac287e240b00 1337133713371337133713371337133713371337 0 {'date': '1338 0', 'user': 'test'}
199 1337133713371337133713371337133713371337 5601fb93a350734d935195fee37f4054c529ff39 0 {'date': '1339 0', 'user': 'test'}
236 1337133713371337133713371337133713371337 5601fb93a350734d935195fee37f4054c529ff39 0 {'date': '1339 0', 'user': 'test'}
237 5601fb93a350734d935195fee37f4054c529ff39 6f96419950729f3671185b847352890f074f7557 1 {'date': '1338 0', 'user': 'test'}
200
238
201 Rollback//Transaction support
239 Rollback//Transaction support
202
240
203 $ hg debugobsolete -d '1340 0' aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
241 $ hg debugobsolete -d '1340 0' aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb
204 $ hg debugobsolete
242 $ hg debugobsolete
205 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C {'date': '56 12', 'user': 'test'}
243 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C {'date': '56 12', 'user': 'test'}
206 cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 {'date': '1337 0', 'user': 'test'}
244 cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 {'date': '1337 0', 'user': 'test'}
207 ca819180edb99ed25ceafb3e9584ac287e240b00 1337133713371337133713371337133713371337 0 {'date': '1338 0', 'user': 'test'}
245 ca819180edb99ed25ceafb3e9584ac287e240b00 1337133713371337133713371337133713371337 0 {'date': '1338 0', 'user': 'test'}
208 1337133713371337133713371337133713371337 5601fb93a350734d935195fee37f4054c529ff39 0 {'date': '1339 0', 'user': 'test'}
246 1337133713371337133713371337133713371337 5601fb93a350734d935195fee37f4054c529ff39 0 {'date': '1339 0', 'user': 'test'}
247 5601fb93a350734d935195fee37f4054c529ff39 6f96419950729f3671185b847352890f074f7557 1 {'date': '1338 0', 'user': 'test'}
209 aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb 0 {'date': '1340 0', 'user': 'test'}
248 aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb 0 {'date': '1340 0', 'user': 'test'}
210 $ hg rollback -n
249 $ hg rollback -n
211 repository tip rolled back to revision 3 (undo debugobsolete)
250 repository tip rolled back to revision 3 (undo debugobsolete)
212 $ hg rollback
251 $ hg rollback
213 repository tip rolled back to revision 3 (undo debugobsolete)
252 repository tip rolled back to revision 3 (undo debugobsolete)
214 $ hg debugobsolete
253 $ hg debugobsolete
215 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C {'date': '56 12', 'user': 'test'}
254 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C {'date': '56 12', 'user': 'test'}
216 cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 {'date': '1337 0', 'user': 'test'}
255 cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 {'date': '1337 0', 'user': 'test'}
217 ca819180edb99ed25ceafb3e9584ac287e240b00 1337133713371337133713371337133713371337 0 {'date': '1338 0', 'user': 'test'}
256 ca819180edb99ed25ceafb3e9584ac287e240b00 1337133713371337133713371337133713371337 0 {'date': '1338 0', 'user': 'test'}
218 1337133713371337133713371337133713371337 5601fb93a350734d935195fee37f4054c529ff39 0 {'date': '1339 0', 'user': 'test'}
257 1337133713371337133713371337133713371337 5601fb93a350734d935195fee37f4054c529ff39 0 {'date': '1339 0', 'user': 'test'}
258 5601fb93a350734d935195fee37f4054c529ff39 6f96419950729f3671185b847352890f074f7557 1 {'date': '1338 0', 'user': 'test'}
219
259
220 $ cd ..
260 $ cd ..
221
261
222 Try to pull markers
262 Try to pull markers
223
263
224 $ hg init tmpd
264 $ hg init tmpd
225 $ hg -R tmpb push tmpd
265 $ hg -R tmpb push tmpd
226 pushing to tmpd
266 pushing to tmpd
227 searching for changes
267 searching for changes
228 adding changesets
268 adding changesets
229 adding manifests
269 adding manifests
230 adding file changes
270 adding file changes
231 added 4 changesets with 4 changes to 4 files (+1 heads)
271 added 4 changesets with 4 changes to 4 files (+1 heads)
232 $ hg -R tmpd debugobsolete
272 $ hg -R tmpd debugobsolete
233 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C {'date': '56 12', 'user': 'test'}
273 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C {'date': '56 12', 'user': 'test'}
234 cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 {'date': '1337 0', 'user': 'test'}
274 cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 {'date': '1337 0', 'user': 'test'}
235 ca819180edb99ed25ceafb3e9584ac287e240b00 1337133713371337133713371337133713371337 0 {'date': '1338 0', 'user': 'test'}
275 ca819180edb99ed25ceafb3e9584ac287e240b00 1337133713371337133713371337133713371337 0 {'date': '1338 0', 'user': 'test'}
236 1337133713371337133713371337133713371337 5601fb93a350734d935195fee37f4054c529ff39 0 {'date': '1339 0', 'user': 'test'}
276 1337133713371337133713371337133713371337 5601fb93a350734d935195fee37f4054c529ff39 0 {'date': '1339 0', 'user': 'test'}
277 5601fb93a350734d935195fee37f4054c529ff39 6f96419950729f3671185b847352890f074f7557 1 {'date': '1338 0', 'user': 'test'}
237
278
238 Check obsolete keys are exchanged only if source has an obsolete store
279 Check obsolete keys are exchanged only if source has an obsolete store
239
280
240 $ hg init empty
281 $ hg init empty
241 $ hg --config extensions.debugkeys=debugkeys.py -R empty push tmpd
282 $ hg --config extensions.debugkeys=debugkeys.py -R empty push tmpd
242 pushing to tmpd
283 pushing to tmpd
243 no changes found
284 no changes found
244 listkeys phases
285 listkeys phases
245 listkeys bookmarks
286 listkeys bookmarks
246 [1]
287 [1]
247
288
248 clone support
289 clone support
249 (markers are copied and extinct changesets are included to allow hardlinks)
290 (markers are copied and extinct changesets are included to allow hardlinks)
250
291
251 $ hg clone tmpb clone-dest
292 $ hg clone tmpb clone-dest
252 updating to branch default
293 updating to branch default
253 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
294 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
254 $ hg -R clone-dest log -G --hidden
295 $ hg -R clone-dest log -G --hidden
255 @ changeset: 5:5601fb93a350
296 @ changeset: 6:6f9641995072
256 | tag: tip
297 | tag: tip
257 | parent: 1:7c3bad9141dc
298 | parent: 1:7c3bad9141dc
258 | user: test
299 | user: test
259 | date: Thu Jan 01 00:00:00 1970 +0000
300 | date: Thu Jan 01 00:00:00 1970 +0000
260 | summary: add new_3_c
301 | summary: add n3w_3_c
302 |
303 | x changeset: 5:5601fb93a350
304 |/ parent: 1:7c3bad9141dc
305 | user: test
306 | date: Thu Jan 01 00:00:00 1970 +0000
307 | summary: add new_3_c
261 |
308 |
262 | x changeset: 4:ca819180edb9
309 | x changeset: 4:ca819180edb9
263 |/ parent: 1:7c3bad9141dc
310 |/ parent: 1:7c3bad9141dc
264 | user: test
311 | user: test
265 | date: Thu Jan 01 00:00:00 1970 +0000
312 | date: Thu Jan 01 00:00:00 1970 +0000
266 | summary: add new_2_c
313 | summary: add new_2_c
267 |
314 |
268 | x changeset: 3:cdbce2fbb163
315 | x changeset: 3:cdbce2fbb163
269 |/ parent: 1:7c3bad9141dc
316 |/ parent: 1:7c3bad9141dc
270 | user: test
317 | user: test
271 | date: Thu Jan 01 00:00:00 1970 +0000
318 | date: Thu Jan 01 00:00:00 1970 +0000
272 | summary: add new_c
319 | summary: add new_c
273 |
320 |
274 | o changeset: 2:245bde4270cd
321 | o changeset: 2:245bde4270cd
275 |/ user: test
322 |/ user: test
276 | date: Thu Jan 01 00:00:00 1970 +0000
323 | date: Thu Jan 01 00:00:00 1970 +0000
277 | summary: add original_c
324 | summary: add original_c
278 |
325 |
279 o changeset: 1:7c3bad9141dc
326 o changeset: 1:7c3bad9141dc
280 | user: test
327 | user: test
281 | date: Thu Jan 01 00:00:00 1970 +0000
328 | date: Thu Jan 01 00:00:00 1970 +0000
282 | summary: add b
329 | summary: add b
283 |
330 |
284 o changeset: 0:1f0dee641bb7
331 o changeset: 0:1f0dee641bb7
285 user: test
332 user: test
286 date: Thu Jan 01 00:00:00 1970 +0000
333 date: Thu Jan 01 00:00:00 1970 +0000
287 summary: add a
334 summary: add a
288
335
289 $ hg -R clone-dest debugobsolete
336 $ hg -R clone-dest debugobsolete
290 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C {'date': '56 12', 'user': 'test'}
337 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C {'date': '56 12', 'user': 'test'}
291 cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 {'date': '1337 0', 'user': 'test'}
338 cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 {'date': '1337 0', 'user': 'test'}
292 ca819180edb99ed25ceafb3e9584ac287e240b00 1337133713371337133713371337133713371337 0 {'date': '1338 0', 'user': 'test'}
339 ca819180edb99ed25ceafb3e9584ac287e240b00 1337133713371337133713371337133713371337 0 {'date': '1338 0', 'user': 'test'}
293 1337133713371337133713371337133713371337 5601fb93a350734d935195fee37f4054c529ff39 0 {'date': '1339 0', 'user': 'test'}
340 1337133713371337133713371337133713371337 5601fb93a350734d935195fee37f4054c529ff39 0 {'date': '1339 0', 'user': 'test'}
341 5601fb93a350734d935195fee37f4054c529ff39 6f96419950729f3671185b847352890f074f7557 1 {'date': '1338 0', 'user': 'test'}
294
342
295
343
296 Destination repo have existing data
344 Destination repo have existing data
297 ---------------------------------------
345 ---------------------------------------
298
346
299 On pull
347 On pull
300
348
301 $ hg init tmpe
349 $ hg init tmpe
302 $ cd tmpe
350 $ cd tmpe
303 $ hg debugobsolete -d '1339 0' 2448244824482448244824482448244824482448 1339133913391339133913391339133913391339
351 $ hg debugobsolete -d '1339 0' 2448244824482448244824482448244824482448 1339133913391339133913391339133913391339
304 $ hg pull ../tmpb
352 $ hg pull ../tmpb
305 pulling from ../tmpb
353 pulling from ../tmpb
306 requesting all changes
354 requesting all changes
307 adding changesets
355 adding changesets
308 adding manifests
356 adding manifests
309 adding file changes
357 adding file changes
310 added 4 changesets with 4 changes to 4 files (+1 heads)
358 added 4 changesets with 4 changes to 4 files (+1 heads)
311 (run 'hg heads' to see heads, 'hg merge' to merge)
359 (run 'hg heads' to see heads, 'hg merge' to merge)
312 $ hg debugobsolete
360 $ hg debugobsolete
313 2448244824482448244824482448244824482448 1339133913391339133913391339133913391339 0 {'date': '1339 0', 'user': 'test'}
361 2448244824482448244824482448244824482448 1339133913391339133913391339133913391339 0 {'date': '1339 0', 'user': 'test'}
314 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C {'date': '56 12', 'user': 'test'}
362 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C {'date': '56 12', 'user': 'test'}
315 cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 {'date': '1337 0', 'user': 'test'}
363 cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 {'date': '1337 0', 'user': 'test'}
316 ca819180edb99ed25ceafb3e9584ac287e240b00 1337133713371337133713371337133713371337 0 {'date': '1338 0', 'user': 'test'}
364 ca819180edb99ed25ceafb3e9584ac287e240b00 1337133713371337133713371337133713371337 0 {'date': '1338 0', 'user': 'test'}
317 1337133713371337133713371337133713371337 5601fb93a350734d935195fee37f4054c529ff39 0 {'date': '1339 0', 'user': 'test'}
365 1337133713371337133713371337133713371337 5601fb93a350734d935195fee37f4054c529ff39 0 {'date': '1339 0', 'user': 'test'}
366 5601fb93a350734d935195fee37f4054c529ff39 6f96419950729f3671185b847352890f074f7557 1 {'date': '1338 0', 'user': 'test'}
318
367
319
368
320 On push
369 On push
321
370
322 $ hg push ../tmpc
371 $ hg push ../tmpc
323 pushing to ../tmpc
372 pushing to ../tmpc
324 searching for changes
373 searching for changes
325 no changes found
374 no changes found
326 [1]
375 [1]
327 $ hg -R ../tmpc debugobsolete
376 $ hg -R ../tmpc debugobsolete
328 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C {'date': '56 12', 'user': 'test'}
377 245bde4270cd1072a27757984f9cda8ba26f08ca cdbce2fbb16313928851e97e0d85413f3f7eb77f C {'date': '56 12', 'user': 'test'}
329 cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 {'date': '1337 0', 'user': 'test'}
378 cdbce2fbb16313928851e97e0d85413f3f7eb77f ca819180edb99ed25ceafb3e9584ac287e240b00 0 {'date': '1337 0', 'user': 'test'}
330 ca819180edb99ed25ceafb3e9584ac287e240b00 1337133713371337133713371337133713371337 0 {'date': '1338 0', 'user': 'test'}
379 ca819180edb99ed25ceafb3e9584ac287e240b00 1337133713371337133713371337133713371337 0 {'date': '1338 0', 'user': 'test'}
331 1337133713371337133713371337133713371337 5601fb93a350734d935195fee37f4054c529ff39 0 {'date': '1339 0', 'user': 'test'}
380 1337133713371337133713371337133713371337 5601fb93a350734d935195fee37f4054c529ff39 0 {'date': '1339 0', 'user': 'test'}
381 5601fb93a350734d935195fee37f4054c529ff39 6f96419950729f3671185b847352890f074f7557 1 {'date': '1338 0', 'user': 'test'}
332 2448244824482448244824482448244824482448 1339133913391339133913391339133913391339 0 {'date': '1339 0', 'user': 'test'}
382 2448244824482448244824482448244824482448 1339133913391339133913391339133913391339 0 {'date': '1339 0', 'user': 'test'}
333
383
334 detect outgoing obsolete and unstable
384 detect outgoing obsolete and unstable
335 ---------------------------------------
385 ---------------------------------------
336
386
337
387
338 $ hg glog
388 $ hg glog
339 o changeset: 3:5601fb93a350
389 o changeset: 3:6f9641995072
340 | tag: tip
390 | tag: tip
341 | parent: 1:7c3bad9141dc
391 | parent: 1:7c3bad9141dc
342 | user: test
392 | user: test
343 | date: Thu Jan 01 00:00:00 1970 +0000
393 | date: Thu Jan 01 00:00:00 1970 +0000
344 | summary: add new_3_c
394 | summary: add n3w_3_c
345 |
395 |
346 | o changeset: 2:245bde4270cd
396 | o changeset: 2:245bde4270cd
347 |/ user: test
397 |/ user: test
348 | date: Thu Jan 01 00:00:00 1970 +0000
398 | date: Thu Jan 01 00:00:00 1970 +0000
349 | summary: add original_c
399 | summary: add original_c
350 |
400 |
351 o changeset: 1:7c3bad9141dc
401 o changeset: 1:7c3bad9141dc
352 | user: test
402 | user: test
353 | date: Thu Jan 01 00:00:00 1970 +0000
403 | date: Thu Jan 01 00:00:00 1970 +0000
354 | summary: add b
404 | summary: add b
355 |
405 |
356 o changeset: 0:1f0dee641bb7
406 o changeset: 0:1f0dee641bb7
357 user: test
407 user: test
358 date: Thu Jan 01 00:00:00 1970 +0000
408 date: Thu Jan 01 00:00:00 1970 +0000
359 summary: add a
409 summary: add a
360
410
361 $ hg up 'desc("new_3_c")'
411 $ hg up 'desc("n3w_3_c")'
362 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
412 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
363 $ mkcommit original_d
413 $ mkcommit original_d
364 $ mkcommit original_e
414 $ mkcommit original_e
365 $ hg debugobsolete `getid original_d` -d '0 0'
415 $ hg debugobsolete `getid original_d` -d '0 0'
366 $ hg log -r 'obsolete()'
416 $ hg log -r 'obsolete()'
367 changeset: 4:7c694bff0650
417 changeset: 4:94b33453f93b
368 user: test
418 user: test
369 date: Thu Jan 01 00:00:00 1970 +0000
419 date: Thu Jan 01 00:00:00 1970 +0000
370 summary: add original_d
420 summary: add original_d
371
421
372 $ hg glog -r '::unstable()'
422 $ hg glog -r '::unstable()'
373 @ changeset: 5:6e572121998e
423 @ changeset: 5:cda648ca50f5
374 | tag: tip
424 | tag: tip
375 | user: test
425 | user: test
376 | date: Thu Jan 01 00:00:00 1970 +0000
426 | date: Thu Jan 01 00:00:00 1970 +0000
377 | summary: add original_e
427 | summary: add original_e
378 |
428 |
379 x changeset: 4:7c694bff0650
429 x changeset: 4:94b33453f93b
380 | user: test
430 | user: test
381 | date: Thu Jan 01 00:00:00 1970 +0000
431 | date: Thu Jan 01 00:00:00 1970 +0000
382 | summary: add original_d
432 | summary: add original_d
383 |
433 |
384 o changeset: 3:5601fb93a350
434 o changeset: 3:6f9641995072
385 | parent: 1:7c3bad9141dc
435 | parent: 1:7c3bad9141dc
386 | user: test
436 | user: test
387 | date: Thu Jan 01 00:00:00 1970 +0000
437 | date: Thu Jan 01 00:00:00 1970 +0000
388 | summary: add new_3_c
438 | summary: add n3w_3_c
389 |
439 |
390 o changeset: 1:7c3bad9141dc
440 o changeset: 1:7c3bad9141dc
391 | user: test
441 | user: test
392 | date: Thu Jan 01 00:00:00 1970 +0000
442 | date: Thu Jan 01 00:00:00 1970 +0000
393 | summary: add b
443 | summary: add b
394 |
444 |
395 o changeset: 0:1f0dee641bb7
445 o changeset: 0:1f0dee641bb7
396 user: test
446 user: test
397 date: Thu Jan 01 00:00:00 1970 +0000
447 date: Thu Jan 01 00:00:00 1970 +0000
398 summary: add a
448 summary: add a
399
449
400
450
401 refuse to push obsolete changeset
451 refuse to push obsolete changeset
402
452
403 $ hg push ../tmpc/ -r 'desc("original_d")'
453 $ hg push ../tmpc/ -r 'desc("original_d")'
404 pushing to ../tmpc/
454 pushing to ../tmpc/
405 searching for changes
455 searching for changes
406 abort: push includes an obsolete changeset: 7c694bff0650!
456 abort: push includes an obsolete changeset: 94b33453f93b!
407 [255]
457 [255]
408
458
409 refuse to push unstable changeset
459 refuse to push unstable changeset
410
460
411 $ hg push ../tmpc/
461 $ hg push ../tmpc/
412 pushing to ../tmpc/
462 pushing to ../tmpc/
413 searching for changes
463 searching for changes
414 abort: push includes an unstable changeset: 6e572121998e!
464 abort: push includes an unstable changeset: cda648ca50f5!
415 [255]
465 [255]
416
466
417 Test that extinct changeset are properly detected
467 Test that extinct changeset are properly detected
418
468
419 $ hg log -r 'extinct()'
469 $ hg log -r 'extinct()'
420
470
421 Don't try to push extinct changeset
471 Don't try to push extinct changeset
422
472
423 $ hg init ../tmpf
473 $ hg init ../tmpf
424 $ hg out ../tmpf
474 $ hg out ../tmpf
425 comparing with ../tmpf
475 comparing with ../tmpf
426 searching for changes
476 searching for changes
427 changeset: 0:1f0dee641bb7
477 changeset: 0:1f0dee641bb7
428 user: test
478 user: test
429 date: Thu Jan 01 00:00:00 1970 +0000
479 date: Thu Jan 01 00:00:00 1970 +0000
430 summary: add a
480 summary: add a
431
481
432 changeset: 1:7c3bad9141dc
482 changeset: 1:7c3bad9141dc
433 user: test
483 user: test
434 date: Thu Jan 01 00:00:00 1970 +0000
484 date: Thu Jan 01 00:00:00 1970 +0000
435 summary: add b
485 summary: add b
436
486
437 changeset: 2:245bde4270cd
487 changeset: 2:245bde4270cd
438 user: test
488 user: test
439 date: Thu Jan 01 00:00:00 1970 +0000
489 date: Thu Jan 01 00:00:00 1970 +0000
440 summary: add original_c
490 summary: add original_c
441
491
442 changeset: 3:5601fb93a350
492 changeset: 3:6f9641995072
443 parent: 1:7c3bad9141dc
493 parent: 1:7c3bad9141dc
444 user: test
494 user: test
445 date: Thu Jan 01 00:00:00 1970 +0000
495 date: Thu Jan 01 00:00:00 1970 +0000
446 summary: add new_3_c
496 summary: add n3w_3_c
447
497
448 changeset: 4:7c694bff0650
498 changeset: 4:94b33453f93b
449 user: test
499 user: test
450 date: Thu Jan 01 00:00:00 1970 +0000
500 date: Thu Jan 01 00:00:00 1970 +0000
451 summary: add original_d
501 summary: add original_d
452
502
453 changeset: 5:6e572121998e
503 changeset: 5:cda648ca50f5
454 tag: tip
504 tag: tip
455 user: test
505 user: test
456 date: Thu Jan 01 00:00:00 1970 +0000
506 date: Thu Jan 01 00:00:00 1970 +0000
457 summary: add original_e
507 summary: add original_e
458
508
459 $ hg push ../tmpf -f # -f because be push unstable too
509 $ hg push ../tmpf -f # -f because be push unstable too
460 pushing to ../tmpf
510 pushing to ../tmpf
461 searching for changes
511 searching for changes
462 adding changesets
512 adding changesets
463 adding manifests
513 adding manifests
464 adding file changes
514 adding file changes
465 added 6 changesets with 6 changes to 6 files (+1 heads)
515 added 6 changesets with 6 changes to 6 files (+1 heads)
466
516
467 no warning displayed
517 no warning displayed
468
518
469 $ hg push ../tmpf
519 $ hg push ../tmpf
470 pushing to ../tmpf
520 pushing to ../tmpf
471 searching for changes
521 searching for changes
472 no changes found
522 no changes found
473 [1]
523 [1]
474
524
475 Do not warn about new head when the new head is a successors of a remote one
525 Do not warn about new head when the new head is a successors of a remote one
476
526
477 $ hg glog
527 $ hg glog
478 @ changeset: 5:6e572121998e
528 @ changeset: 5:cda648ca50f5
479 | tag: tip
529 | tag: tip
480 | user: test
530 | user: test
481 | date: Thu Jan 01 00:00:00 1970 +0000
531 | date: Thu Jan 01 00:00:00 1970 +0000
482 | summary: add original_e
532 | summary: add original_e
483 |
533 |
484 x changeset: 4:7c694bff0650
534 x changeset: 4:94b33453f93b
485 | user: test
535 | user: test
486 | date: Thu Jan 01 00:00:00 1970 +0000
536 | date: Thu Jan 01 00:00:00 1970 +0000
487 | summary: add original_d
537 | summary: add original_d
488 |
538 |
489 o changeset: 3:5601fb93a350
539 o changeset: 3:6f9641995072
490 | parent: 1:7c3bad9141dc
540 | parent: 1:7c3bad9141dc
491 | user: test
541 | user: test
492 | date: Thu Jan 01 00:00:00 1970 +0000
542 | date: Thu Jan 01 00:00:00 1970 +0000
493 | summary: add new_3_c
543 | summary: add n3w_3_c
494 |
544 |
495 | o changeset: 2:245bde4270cd
545 | o changeset: 2:245bde4270cd
496 |/ user: test
546 |/ user: test
497 | date: Thu Jan 01 00:00:00 1970 +0000
547 | date: Thu Jan 01 00:00:00 1970 +0000
498 | summary: add original_c
548 | summary: add original_c
499 |
549 |
500 o changeset: 1:7c3bad9141dc
550 o changeset: 1:7c3bad9141dc
501 | user: test
551 | user: test
502 | date: Thu Jan 01 00:00:00 1970 +0000
552 | date: Thu Jan 01 00:00:00 1970 +0000
503 | summary: add b
553 | summary: add b
504 |
554 |
505 o changeset: 0:1f0dee641bb7
555 o changeset: 0:1f0dee641bb7
506 user: test
556 user: test
507 date: Thu Jan 01 00:00:00 1970 +0000
557 date: Thu Jan 01 00:00:00 1970 +0000
508 summary: add a
558 summary: add a
509
559
510 $ hg up -q 'desc(new_3_c)'
560 $ hg up -q 'desc(n3w_3_c)'
511 $ mkcommit obsolete_e
561 $ mkcommit obsolete_e
512 created new head
562 created new head
513 $ hg debugobsolete `getid 'original_e'` `getid 'obsolete_e'`
563 $ hg debugobsolete `getid 'original_e'` `getid 'obsolete_e'`
514 $ hg push ../tmpf
564 $ hg push ../tmpf
515 pushing to ../tmpf
565 pushing to ../tmpf
516 searching for changes
566 searching for changes
517 adding changesets
567 adding changesets
518 adding manifests
568 adding manifests
519 adding file changes
569 adding file changes
520 added 1 changesets with 1 changes to 1 files (+1 heads)
570 added 1 changesets with 1 changes to 1 files (+1 heads)
521
571
522 Checking _enable=False warning if obsolete marker exists
572 Checking _enable=False warning if obsolete marker exists
523
573
524 $ echo '[extensions]' >> $HGRCPATH
574 $ echo '[extensions]' >> $HGRCPATH
525 $ echo "obs=!" >> $HGRCPATH
575 $ echo "obs=!" >> $HGRCPATH
526 $ hg log -r tip
576 $ hg log -r tip
527 obsolete feature not enabled but 7 markers found!
577 obsolete feature not enabled but 8 markers found!
528 changeset: 6:d6a026544050
578 changeset: 6:3de5eca88c00
529 tag: tip
579 tag: tip
530 parent: 3:5601fb93a350
580 parent: 3:6f9641995072
531 user: test
581 user: test
532 date: Thu Jan 01 00:00:00 1970 +0000
582 date: Thu Jan 01 00:00:00 1970 +0000
533 summary: add obsolete_e
583 summary: add obsolete_e
534
584
General Comments 0
You need to be logged in to leave comments. Login now