##// END OF EJS Templates
narrow: support debugupgraderepo...
Arseniy Alekseyev -
r49942:cb21c9c1 default draft
parent child Browse files
Show More
@@ -1,1095 +1,1096 b''
1 # upgrade.py - functions for in place upgrade of Mercurial repository
1 # upgrade.py - functions for in place upgrade of Mercurial repository
2 #
2 #
3 # Copyright (c) 2016-present, Gregory Szorc
3 # Copyright (c) 2016-present, Gregory Szorc
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
8
9 from ..i18n import _
9 from ..i18n import _
10 from .. import (
10 from .. import (
11 error,
11 error,
12 localrepo,
12 localrepo,
13 pycompat,
13 pycompat,
14 requirements,
14 requirements,
15 revlog,
15 revlog,
16 util,
16 util,
17 )
17 )
18
18
19 from ..utils import compression
19 from ..utils import compression
20
20
21 if pycompat.TYPE_CHECKING:
21 if pycompat.TYPE_CHECKING:
22 from typing import (
22 from typing import (
23 List,
23 List,
24 Type,
24 Type,
25 )
25 )
26
26
27
27
28 # list of requirements that request a clone of all revlog if added/removed
28 # list of requirements that request a clone of all revlog if added/removed
29 RECLONES_REQUIREMENTS = {
29 RECLONES_REQUIREMENTS = {
30 requirements.GENERALDELTA_REQUIREMENT,
30 requirements.GENERALDELTA_REQUIREMENT,
31 requirements.SPARSEREVLOG_REQUIREMENT,
31 requirements.SPARSEREVLOG_REQUIREMENT,
32 requirements.REVLOGV2_REQUIREMENT,
32 requirements.REVLOGV2_REQUIREMENT,
33 requirements.CHANGELOGV2_REQUIREMENT,
33 requirements.CHANGELOGV2_REQUIREMENT,
34 }
34 }
35
35
36
37 def preservedrequirements(repo):
36 def preservedrequirements(repo):
38 preserved = {
37 preserved = {
39 requirements.SHARED_REQUIREMENT,
38 requirements.SHARED_REQUIREMENT,
39 requirements.NARROW_REQUIREMENT,
40 }
40 }
41 return preserved & repo.requirements
41 return preserved & repo.requirements
42
42
43
43
44 FORMAT_VARIANT = b'deficiency'
44 FORMAT_VARIANT = b'deficiency'
45 OPTIMISATION = b'optimization'
45 OPTIMISATION = b'optimization'
46
46
47
47
48 class improvement:
48 class improvement:
49 """Represents an improvement that can be made as part of an upgrade."""
49 """Represents an improvement that can be made as part of an upgrade."""
50
50
51 ### The following attributes should be defined for each subclass:
51 ### The following attributes should be defined for each subclass:
52
52
53 # Either ``FORMAT_VARIANT`` or ``OPTIMISATION``.
53 # Either ``FORMAT_VARIANT`` or ``OPTIMISATION``.
54 # A format variant is where we change the storage format. Not all format
54 # A format variant is where we change the storage format. Not all format
55 # variant changes are an obvious problem.
55 # variant changes are an obvious problem.
56 # An optimization is an action (sometimes optional) that
56 # An optimization is an action (sometimes optional) that
57 # can be taken to further improve the state of the repository.
57 # can be taken to further improve the state of the repository.
58 type = None
58 type = None
59
59
60 # machine-readable string uniquely identifying this improvement. it will be
60 # machine-readable string uniquely identifying this improvement. it will be
61 # mapped to an action later in the upgrade process.
61 # mapped to an action later in the upgrade process.
62 name = None
62 name = None
63
63
64 # message intended for humans explaining the improvement in more detail,
64 # message intended for humans explaining the improvement in more detail,
65 # including the implications of it ``FORMAT_VARIANT`` types, should be
65 # including the implications of it ``FORMAT_VARIANT`` types, should be
66 # worded
66 # worded
67 # in the present tense.
67 # in the present tense.
68 description = None
68 description = None
69
69
70 # message intended for humans explaining what an upgrade addressing this
70 # message intended for humans explaining what an upgrade addressing this
71 # issue will do. should be worded in the future tense.
71 # issue will do. should be worded in the future tense.
72 upgrademessage = None
72 upgrademessage = None
73
73
74 # value of current Mercurial default for new repository
74 # value of current Mercurial default for new repository
75 default = None
75 default = None
76
76
77 # Message intended for humans which will be shown post an upgrade
77 # Message intended for humans which will be shown post an upgrade
78 # operation when the improvement will be added
78 # operation when the improvement will be added
79 postupgrademessage = None
79 postupgrademessage = None
80
80
81 # Message intended for humans which will be shown post an upgrade
81 # Message intended for humans which will be shown post an upgrade
82 # operation in which this improvement was removed
82 # operation in which this improvement was removed
83 postdowngrademessage = None
83 postdowngrademessage = None
84
84
85 # By default we assume that every improvement touches requirements and all revlogs
85 # By default we assume that every improvement touches requirements and all revlogs
86
86
87 # Whether this improvement touches filelogs
87 # Whether this improvement touches filelogs
88 touches_filelogs = True
88 touches_filelogs = True
89
89
90 # Whether this improvement touches manifests
90 # Whether this improvement touches manifests
91 touches_manifests = True
91 touches_manifests = True
92
92
93 # Whether this improvement touches changelog
93 # Whether this improvement touches changelog
94 touches_changelog = True
94 touches_changelog = True
95
95
96 # Whether this improvement changes repository requirements
96 # Whether this improvement changes repository requirements
97 touches_requirements = True
97 touches_requirements = True
98
98
99 # Whether this improvement touches the dirstate
99 # Whether this improvement touches the dirstate
100 touches_dirstate = False
100 touches_dirstate = False
101
101
102 # Can this action be run on a share instead of its mains repository
102 # Can this action be run on a share instead of its mains repository
103 compatible_with_share = False
103 compatible_with_share = False
104
104
105
105
106 allformatvariant = [] # type: List[Type['formatvariant']]
106 allformatvariant = [] # type: List[Type['formatvariant']]
107
107
108
108
109 def registerformatvariant(cls):
109 def registerformatvariant(cls):
110 allformatvariant.append(cls)
110 allformatvariant.append(cls)
111 return cls
111 return cls
112
112
113
113
114 class formatvariant(improvement):
114 class formatvariant(improvement):
115 """an improvement subclass dedicated to repository format"""
115 """an improvement subclass dedicated to repository format"""
116
116
117 type = FORMAT_VARIANT
117 type = FORMAT_VARIANT
118
118
119 @staticmethod
119 @staticmethod
120 def fromrepo(repo):
120 def fromrepo(repo):
121 """current value of the variant in the repository"""
121 """current value of the variant in the repository"""
122 raise NotImplementedError()
122 raise NotImplementedError()
123
123
124 @staticmethod
124 @staticmethod
125 def fromconfig(repo):
125 def fromconfig(repo):
126 """current value of the variant in the configuration"""
126 """current value of the variant in the configuration"""
127 raise NotImplementedError()
127 raise NotImplementedError()
128
128
129
129
130 class requirementformatvariant(formatvariant):
130 class requirementformatvariant(formatvariant):
131 """formatvariant based on a 'requirement' name.
131 """formatvariant based on a 'requirement' name.
132
132
133 Many format variant are controlled by a 'requirement'. We define a small
133 Many format variant are controlled by a 'requirement'. We define a small
134 subclass to factor the code.
134 subclass to factor the code.
135 """
135 """
136
136
137 # the requirement that control this format variant
137 # the requirement that control this format variant
138 _requirement = None
138 _requirement = None
139
139
140 @staticmethod
140 @staticmethod
141 def _newreporequirements(ui):
141 def _newreporequirements(ui):
142 return localrepo.newreporequirements(
142 return localrepo.newreporequirements(
143 ui, localrepo.defaultcreateopts(ui)
143 ui, localrepo.defaultcreateopts(ui)
144 )
144 )
145
145
146 @classmethod
146 @classmethod
147 def fromrepo(cls, repo):
147 def fromrepo(cls, repo):
148 assert cls._requirement is not None
148 assert cls._requirement is not None
149 return cls._requirement in repo.requirements
149 return cls._requirement in repo.requirements
150
150
151 @classmethod
151 @classmethod
152 def fromconfig(cls, repo):
152 def fromconfig(cls, repo):
153 assert cls._requirement is not None
153 assert cls._requirement is not None
154 return cls._requirement in cls._newreporequirements(repo.ui)
154 return cls._requirement in cls._newreporequirements(repo.ui)
155
155
156
156
157 @registerformatvariant
157 @registerformatvariant
158 class fncache(requirementformatvariant):
158 class fncache(requirementformatvariant):
159 name = b'fncache'
159 name = b'fncache'
160
160
161 _requirement = requirements.FNCACHE_REQUIREMENT
161 _requirement = requirements.FNCACHE_REQUIREMENT
162
162
163 default = True
163 default = True
164
164
165 description = _(
165 description = _(
166 b'long and reserved filenames may not work correctly; '
166 b'long and reserved filenames may not work correctly; '
167 b'repository performance is sub-optimal'
167 b'repository performance is sub-optimal'
168 )
168 )
169
169
170 upgrademessage = _(
170 upgrademessage = _(
171 b'repository will be more resilient to storing '
171 b'repository will be more resilient to storing '
172 b'certain paths and performance of certain '
172 b'certain paths and performance of certain '
173 b'operations should be improved'
173 b'operations should be improved'
174 )
174 )
175
175
176
176
177 @registerformatvariant
177 @registerformatvariant
178 class dirstatev2(requirementformatvariant):
178 class dirstatev2(requirementformatvariant):
179 name = b'dirstate-v2'
179 name = b'dirstate-v2'
180 _requirement = requirements.DIRSTATE_V2_REQUIREMENT
180 _requirement = requirements.DIRSTATE_V2_REQUIREMENT
181
181
182 default = False
182 default = False
183
183
184 description = _(
184 description = _(
185 b'version 1 of the dirstate file format requires '
185 b'version 1 of the dirstate file format requires '
186 b'reading and parsing it all at once.\n'
186 b'reading and parsing it all at once.\n'
187 b'Version 2 has a better structure,'
187 b'Version 2 has a better structure,'
188 b'better information and lighter update mechanism'
188 b'better information and lighter update mechanism'
189 )
189 )
190
190
191 upgrademessage = _(b'"hg status" will be faster')
191 upgrademessage = _(b'"hg status" will be faster')
192
192
193 touches_filelogs = False
193 touches_filelogs = False
194 touches_manifests = False
194 touches_manifests = False
195 touches_changelog = False
195 touches_changelog = False
196 touches_requirements = True
196 touches_requirements = True
197 touches_dirstate = True
197 touches_dirstate = True
198 compatible_with_share = True
198 compatible_with_share = True
199
199
200
200
201 @registerformatvariant
201 @registerformatvariant
202 class dirstatetrackedkey(requirementformatvariant):
202 class dirstatetrackedkey(requirementformatvariant):
203 name = b'tracked-hint'
203 name = b'tracked-hint'
204 _requirement = requirements.DIRSTATE_TRACKED_HINT_V1
204 _requirement = requirements.DIRSTATE_TRACKED_HINT_V1
205
205
206 default = False
206 default = False
207
207
208 description = _(
208 description = _(
209 b'Add a small file to help external tooling that watch the tracked set'
209 b'Add a small file to help external tooling that watch the tracked set'
210 )
210 )
211
211
212 upgrademessage = _(
212 upgrademessage = _(
213 b'external tools will be informated of potential change in the tracked set'
213 b'external tools will be informated of potential change in the tracked set'
214 )
214 )
215
215
216 touches_filelogs = False
216 touches_filelogs = False
217 touches_manifests = False
217 touches_manifests = False
218 touches_changelog = False
218 touches_changelog = False
219 touches_requirements = True
219 touches_requirements = True
220 touches_dirstate = True
220 touches_dirstate = True
221 compatible_with_share = True
221 compatible_with_share = True
222
222
223
223
224 @registerformatvariant
224 @registerformatvariant
225 class dotencode(requirementformatvariant):
225 class dotencode(requirementformatvariant):
226 name = b'dotencode'
226 name = b'dotencode'
227
227
228 _requirement = requirements.DOTENCODE_REQUIREMENT
228 _requirement = requirements.DOTENCODE_REQUIREMENT
229
229
230 default = True
230 default = True
231
231
232 description = _(
232 description = _(
233 b'storage of filenames beginning with a period or '
233 b'storage of filenames beginning with a period or '
234 b'space may not work correctly'
234 b'space may not work correctly'
235 )
235 )
236
236
237 upgrademessage = _(
237 upgrademessage = _(
238 b'repository will be better able to store files '
238 b'repository will be better able to store files '
239 b'beginning with a space or period'
239 b'beginning with a space or period'
240 )
240 )
241
241
242
242
243 @registerformatvariant
243 @registerformatvariant
244 class generaldelta(requirementformatvariant):
244 class generaldelta(requirementformatvariant):
245 name = b'generaldelta'
245 name = b'generaldelta'
246
246
247 _requirement = requirements.GENERALDELTA_REQUIREMENT
247 _requirement = requirements.GENERALDELTA_REQUIREMENT
248
248
249 default = True
249 default = True
250
250
251 description = _(
251 description = _(
252 b'deltas within internal storage are unable to '
252 b'deltas within internal storage are unable to '
253 b'choose optimal revisions; repository is larger and '
253 b'choose optimal revisions; repository is larger and '
254 b'slower than it could be; interaction with other '
254 b'slower than it could be; interaction with other '
255 b'repositories may require extra network and CPU '
255 b'repositories may require extra network and CPU '
256 b'resources, making "hg push" and "hg pull" slower'
256 b'resources, making "hg push" and "hg pull" slower'
257 )
257 )
258
258
259 upgrademessage = _(
259 upgrademessage = _(
260 b'repository storage will be able to create '
260 b'repository storage will be able to create '
261 b'optimal deltas; new repository data will be '
261 b'optimal deltas; new repository data will be '
262 b'smaller and read times should decrease; '
262 b'smaller and read times should decrease; '
263 b'interacting with other repositories using this '
263 b'interacting with other repositories using this '
264 b'storage model should require less network and '
264 b'storage model should require less network and '
265 b'CPU resources, making "hg push" and "hg pull" '
265 b'CPU resources, making "hg push" and "hg pull" '
266 b'faster'
266 b'faster'
267 )
267 )
268
268
269
269
270 @registerformatvariant
270 @registerformatvariant
271 class sharesafe(requirementformatvariant):
271 class sharesafe(requirementformatvariant):
272 name = b'share-safe'
272 name = b'share-safe'
273 _requirement = requirements.SHARESAFE_REQUIREMENT
273 _requirement = requirements.SHARESAFE_REQUIREMENT
274
274
275 default = True
275 default = True
276
276
277 description = _(
277 description = _(
278 b'old shared repositories do not share source repository '
278 b'old shared repositories do not share source repository '
279 b'requirements and config. This leads to various problems '
279 b'requirements and config. This leads to various problems '
280 b'when the source repository format is upgraded or some new '
280 b'when the source repository format is upgraded or some new '
281 b'extensions are enabled.'
281 b'extensions are enabled.'
282 )
282 )
283
283
284 upgrademessage = _(
284 upgrademessage = _(
285 b'Upgrades a repository to share-safe format so that future '
285 b'Upgrades a repository to share-safe format so that future '
286 b'shares of this repository share its requirements and configs.'
286 b'shares of this repository share its requirements and configs.'
287 )
287 )
288
288
289 postdowngrademessage = _(
289 postdowngrademessage = _(
290 b'repository downgraded to not use share safe mode, '
290 b'repository downgraded to not use share safe mode, '
291 b'existing shares will not work and needs to'
291 b'existing shares will not work and needs to'
292 b' be reshared.'
292 b' be reshared.'
293 )
293 )
294
294
295 postupgrademessage = _(
295 postupgrademessage = _(
296 b'repository upgraded to share safe mode, existing'
296 b'repository upgraded to share safe mode, existing'
297 b' shares will still work in old non-safe mode. '
297 b' shares will still work in old non-safe mode. '
298 b'Re-share existing shares to use them in safe mode'
298 b'Re-share existing shares to use them in safe mode'
299 b' New shares will be created in safe mode.'
299 b' New shares will be created in safe mode.'
300 )
300 )
301
301
302 # upgrade only needs to change the requirements
302 # upgrade only needs to change the requirements
303 touches_filelogs = False
303 touches_filelogs = False
304 touches_manifests = False
304 touches_manifests = False
305 touches_changelog = False
305 touches_changelog = False
306 touches_requirements = True
306 touches_requirements = True
307
307
308
308
309 @registerformatvariant
309 @registerformatvariant
310 class sparserevlog(requirementformatvariant):
310 class sparserevlog(requirementformatvariant):
311 name = b'sparserevlog'
311 name = b'sparserevlog'
312
312
313 _requirement = requirements.SPARSEREVLOG_REQUIREMENT
313 _requirement = requirements.SPARSEREVLOG_REQUIREMENT
314
314
315 default = True
315 default = True
316
316
317 description = _(
317 description = _(
318 b'in order to limit disk reading and memory usage on older '
318 b'in order to limit disk reading and memory usage on older '
319 b'version, the span of a delta chain from its root to its '
319 b'version, the span of a delta chain from its root to its '
320 b'end is limited, whatever the relevant data in this span. '
320 b'end is limited, whatever the relevant data in this span. '
321 b'This can severly limit Mercurial ability to build good '
321 b'This can severly limit Mercurial ability to build good '
322 b'chain of delta resulting is much more storage space being '
322 b'chain of delta resulting is much more storage space being '
323 b'taken and limit reusability of on disk delta during '
323 b'taken and limit reusability of on disk delta during '
324 b'exchange.'
324 b'exchange.'
325 )
325 )
326
326
327 upgrademessage = _(
327 upgrademessage = _(
328 b'Revlog supports delta chain with more unused data '
328 b'Revlog supports delta chain with more unused data '
329 b'between payload. These gaps will be skipped at read '
329 b'between payload. These gaps will be skipped at read '
330 b'time. This allows for better delta chains, making a '
330 b'time. This allows for better delta chains, making a '
331 b'better compression and faster exchange with server.'
331 b'better compression and faster exchange with server.'
332 )
332 )
333
333
334
334
335 @registerformatvariant
335 @registerformatvariant
336 class persistentnodemap(requirementformatvariant):
336 class persistentnodemap(requirementformatvariant):
337 name = b'persistent-nodemap'
337 name = b'persistent-nodemap'
338
338
339 _requirement = requirements.NODEMAP_REQUIREMENT
339 _requirement = requirements.NODEMAP_REQUIREMENT
340
340
341 default = False
341 default = False
342
342
343 description = _(
343 description = _(
344 b'persist the node -> rev mapping on disk to speedup lookup'
344 b'persist the node -> rev mapping on disk to speedup lookup'
345 )
345 )
346
346
347 upgrademessage = _(b'Speedup revision lookup by node id.')
347 upgrademessage = _(b'Speedup revision lookup by node id.')
348
348
349
349
350 @registerformatvariant
350 @registerformatvariant
351 class copiessdc(requirementformatvariant):
351 class copiessdc(requirementformatvariant):
352 name = b'copies-sdc'
352 name = b'copies-sdc'
353
353
354 _requirement = requirements.COPIESSDC_REQUIREMENT
354 _requirement = requirements.COPIESSDC_REQUIREMENT
355
355
356 default = False
356 default = False
357
357
358 description = _(b'Stores copies information alongside changesets.')
358 description = _(b'Stores copies information alongside changesets.')
359
359
360 upgrademessage = _(
360 upgrademessage = _(
361 b'Allows to use more efficient algorithm to deal with ' b'copy tracing.'
361 b'Allows to use more efficient algorithm to deal with ' b'copy tracing.'
362 )
362 )
363
363
364
364
365 @registerformatvariant
365 @registerformatvariant
366 class revlogv2(requirementformatvariant):
366 class revlogv2(requirementformatvariant):
367 name = b'revlog-v2'
367 name = b'revlog-v2'
368 _requirement = requirements.REVLOGV2_REQUIREMENT
368 _requirement = requirements.REVLOGV2_REQUIREMENT
369 default = False
369 default = False
370 description = _(b'Version 2 of the revlog.')
370 description = _(b'Version 2 of the revlog.')
371 upgrademessage = _(b'very experimental')
371 upgrademessage = _(b'very experimental')
372
372
373
373
374 @registerformatvariant
374 @registerformatvariant
375 class changelogv2(requirementformatvariant):
375 class changelogv2(requirementformatvariant):
376 name = b'changelog-v2'
376 name = b'changelog-v2'
377 _requirement = requirements.CHANGELOGV2_REQUIREMENT
377 _requirement = requirements.CHANGELOGV2_REQUIREMENT
378 default = False
378 default = False
379 description = _(b'An iteration of the revlog focussed on changelog needs.')
379 description = _(b'An iteration of the revlog focussed on changelog needs.')
380 upgrademessage = _(b'quite experimental')
380 upgrademessage = _(b'quite experimental')
381
381
382
382
383 @registerformatvariant
383 @registerformatvariant
384 class removecldeltachain(formatvariant):
384 class removecldeltachain(formatvariant):
385 name = b'plain-cl-delta'
385 name = b'plain-cl-delta'
386
386
387 default = True
387 default = True
388
388
389 description = _(
389 description = _(
390 b'changelog storage is using deltas instead of '
390 b'changelog storage is using deltas instead of '
391 b'raw entries; changelog reading and any '
391 b'raw entries; changelog reading and any '
392 b'operation relying on changelog data are slower '
392 b'operation relying on changelog data are slower '
393 b'than they could be'
393 b'than they could be'
394 )
394 )
395
395
396 upgrademessage = _(
396 upgrademessage = _(
397 b'changelog storage will be reformated to '
397 b'changelog storage will be reformated to '
398 b'store raw entries; changelog reading will be '
398 b'store raw entries; changelog reading will be '
399 b'faster; changelog size may be reduced'
399 b'faster; changelog size may be reduced'
400 )
400 )
401
401
402 @staticmethod
402 @staticmethod
403 def fromrepo(repo):
403 def fromrepo(repo):
404 # Mercurial 4.0 changed changelogs to not use delta chains. Search for
404 # Mercurial 4.0 changed changelogs to not use delta chains. Search for
405 # changelogs with deltas.
405 # changelogs with deltas.
406 cl = repo.changelog
406 cl = repo.changelog
407 chainbase = cl.chainbase
407 chainbase = cl.chainbase
408 return all(rev == chainbase(rev) for rev in cl)
408 return all(rev == chainbase(rev) for rev in cl)
409
409
410 @staticmethod
410 @staticmethod
411 def fromconfig(repo):
411 def fromconfig(repo):
412 return True
412 return True
413
413
414
414
415 _has_zstd = (
415 _has_zstd = (
416 b'zstd' in util.compengines
416 b'zstd' in util.compengines
417 and util.compengines[b'zstd'].available()
417 and util.compengines[b'zstd'].available()
418 and util.compengines[b'zstd'].revlogheader()
418 and util.compengines[b'zstd'].revlogheader()
419 )
419 )
420
420
421
421
422 @registerformatvariant
422 @registerformatvariant
423 class compressionengine(formatvariant):
423 class compressionengine(formatvariant):
424 name = b'compression'
424 name = b'compression'
425
425
426 if _has_zstd:
426 if _has_zstd:
427 default = b'zstd'
427 default = b'zstd'
428 else:
428 else:
429 default = b'zlib'
429 default = b'zlib'
430
430
431 description = _(
431 description = _(
432 b'Compresion algorithm used to compress data. '
432 b'Compresion algorithm used to compress data. '
433 b'Some engine are faster than other'
433 b'Some engine are faster than other'
434 )
434 )
435
435
436 upgrademessage = _(
436 upgrademessage = _(
437 b'revlog content will be recompressed with the new algorithm.'
437 b'revlog content will be recompressed with the new algorithm.'
438 )
438 )
439
439
440 @classmethod
440 @classmethod
441 def fromrepo(cls, repo):
441 def fromrepo(cls, repo):
442 # we allow multiple compression engine requirement to co-exist because
442 # we allow multiple compression engine requirement to co-exist because
443 # strickly speaking, revlog seems to support mixed compression style.
443 # strickly speaking, revlog seems to support mixed compression style.
444 #
444 #
445 # The compression used for new entries will be "the last one"
445 # The compression used for new entries will be "the last one"
446 compression = b'zlib'
446 compression = b'zlib'
447 for req in repo.requirements:
447 for req in repo.requirements:
448 prefix = req.startswith
448 prefix = req.startswith
449 if prefix(b'revlog-compression-') or prefix(b'exp-compression-'):
449 if prefix(b'revlog-compression-') or prefix(b'exp-compression-'):
450 compression = req.split(b'-', 2)[2]
450 compression = req.split(b'-', 2)[2]
451 return compression
451 return compression
452
452
453 @classmethod
453 @classmethod
454 def fromconfig(cls, repo):
454 def fromconfig(cls, repo):
455 compengines = repo.ui.configlist(b'format', b'revlog-compression')
455 compengines = repo.ui.configlist(b'format', b'revlog-compression')
456 # return the first valid value as the selection code would do
456 # return the first valid value as the selection code would do
457 for comp in compengines:
457 for comp in compengines:
458 if comp in util.compengines:
458 if comp in util.compengines:
459 e = util.compengines[comp]
459 e = util.compengines[comp]
460 if e.available() and e.revlogheader():
460 if e.available() and e.revlogheader():
461 return comp
461 return comp
462
462
463 # no valide compression found lets display it all for clarity
463 # no valide compression found lets display it all for clarity
464 return b','.join(compengines)
464 return b','.join(compengines)
465
465
466
466
467 @registerformatvariant
467 @registerformatvariant
468 class compressionlevel(formatvariant):
468 class compressionlevel(formatvariant):
469 name = b'compression-level'
469 name = b'compression-level'
470 default = b'default'
470 default = b'default'
471
471
472 description = _(b'compression level')
472 description = _(b'compression level')
473
473
474 upgrademessage = _(b'revlog content will be recompressed')
474 upgrademessage = _(b'revlog content will be recompressed')
475
475
476 @classmethod
476 @classmethod
477 def fromrepo(cls, repo):
477 def fromrepo(cls, repo):
478 comp = compressionengine.fromrepo(repo)
478 comp = compressionengine.fromrepo(repo)
479 level = None
479 level = None
480 if comp == b'zlib':
480 if comp == b'zlib':
481 level = repo.ui.configint(b'storage', b'revlog.zlib.level')
481 level = repo.ui.configint(b'storage', b'revlog.zlib.level')
482 elif comp == b'zstd':
482 elif comp == b'zstd':
483 level = repo.ui.configint(b'storage', b'revlog.zstd.level')
483 level = repo.ui.configint(b'storage', b'revlog.zstd.level')
484 if level is None:
484 if level is None:
485 return b'default'
485 return b'default'
486 return bytes(level)
486 return bytes(level)
487
487
488 @classmethod
488 @classmethod
489 def fromconfig(cls, repo):
489 def fromconfig(cls, repo):
490 comp = compressionengine.fromconfig(repo)
490 comp = compressionengine.fromconfig(repo)
491 level = None
491 level = None
492 if comp == b'zlib':
492 if comp == b'zlib':
493 level = repo.ui.configint(b'storage', b'revlog.zlib.level')
493 level = repo.ui.configint(b'storage', b'revlog.zlib.level')
494 elif comp == b'zstd':
494 elif comp == b'zstd':
495 level = repo.ui.configint(b'storage', b'revlog.zstd.level')
495 level = repo.ui.configint(b'storage', b'revlog.zstd.level')
496 if level is None:
496 if level is None:
497 return b'default'
497 return b'default'
498 return bytes(level)
498 return bytes(level)
499
499
500
500
501 def find_format_upgrades(repo):
501 def find_format_upgrades(repo):
502 """returns a list of format upgrades which can be perform on the repo"""
502 """returns a list of format upgrades which can be perform on the repo"""
503 upgrades = []
503 upgrades = []
504
504
505 # We could detect lack of revlogv1 and store here, but they were added
505 # We could detect lack of revlogv1 and store here, but they were added
506 # in 0.9.2 and we don't support upgrading repos without these
506 # in 0.9.2 and we don't support upgrading repos without these
507 # requirements, so let's not bother.
507 # requirements, so let's not bother.
508
508
509 for fv in allformatvariant:
509 for fv in allformatvariant:
510 if not fv.fromrepo(repo):
510 if not fv.fromrepo(repo):
511 upgrades.append(fv)
511 upgrades.append(fv)
512
512
513 return upgrades
513 return upgrades
514
514
515
515
516 def find_format_downgrades(repo):
516 def find_format_downgrades(repo):
517 """returns a list of format downgrades which will be performed on the repo
517 """returns a list of format downgrades which will be performed on the repo
518 because of disabled config option for them"""
518 because of disabled config option for them"""
519
519
520 downgrades = []
520 downgrades = []
521
521
522 for fv in allformatvariant:
522 for fv in allformatvariant:
523 if fv.name == b'compression':
523 if fv.name == b'compression':
524 # If there is a compression change between repository
524 # If there is a compression change between repository
525 # and config, destination repository compression will change
525 # and config, destination repository compression will change
526 # and current compression will be removed.
526 # and current compression will be removed.
527 if fv.fromrepo(repo) != fv.fromconfig(repo):
527 if fv.fromrepo(repo) != fv.fromconfig(repo):
528 downgrades.append(fv)
528 downgrades.append(fv)
529 continue
529 continue
530 # format variant exist in repo but does not exist in new repository
530 # format variant exist in repo but does not exist in new repository
531 # config
531 # config
532 if fv.fromrepo(repo) and not fv.fromconfig(repo):
532 if fv.fromrepo(repo) and not fv.fromconfig(repo):
533 downgrades.append(fv)
533 downgrades.append(fv)
534
534
535 return downgrades
535 return downgrades
536
536
537
537
538 ALL_OPTIMISATIONS = []
538 ALL_OPTIMISATIONS = []
539
539
540
540
541 def register_optimization(obj):
541 def register_optimization(obj):
542 ALL_OPTIMISATIONS.append(obj)
542 ALL_OPTIMISATIONS.append(obj)
543 return obj
543 return obj
544
544
545
545
546 class optimization(improvement):
546 class optimization(improvement):
547 """an improvement subclass dedicated to optimizations"""
547 """an improvement subclass dedicated to optimizations"""
548
548
549 type = OPTIMISATION
549 type = OPTIMISATION
550
550
551
551
552 @register_optimization
552 @register_optimization
553 class redeltaparents(optimization):
553 class redeltaparents(optimization):
554 name = b're-delta-parent'
554 name = b're-delta-parent'
555
555
556 type = OPTIMISATION
556 type = OPTIMISATION
557
557
558 description = _(
558 description = _(
559 b'deltas within internal storage will be recalculated to '
559 b'deltas within internal storage will be recalculated to '
560 b'choose an optimal base revision where this was not '
560 b'choose an optimal base revision where this was not '
561 b'already done; the size of the repository may shrink and '
561 b'already done; the size of the repository may shrink and '
562 b'various operations may become faster; the first time '
562 b'various operations may become faster; the first time '
563 b'this optimization is performed could slow down upgrade '
563 b'this optimization is performed could slow down upgrade '
564 b'execution considerably; subsequent invocations should '
564 b'execution considerably; subsequent invocations should '
565 b'not run noticeably slower'
565 b'not run noticeably slower'
566 )
566 )
567
567
568 upgrademessage = _(
568 upgrademessage = _(
569 b'deltas within internal storage will choose a new '
569 b'deltas within internal storage will choose a new '
570 b'base revision if needed'
570 b'base revision if needed'
571 )
571 )
572
572
573
573
574 @register_optimization
574 @register_optimization
575 class redeltamultibase(optimization):
575 class redeltamultibase(optimization):
576 name = b're-delta-multibase'
576 name = b're-delta-multibase'
577
577
578 type = OPTIMISATION
578 type = OPTIMISATION
579
579
580 description = _(
580 description = _(
581 b'deltas within internal storage will be recalculated '
581 b'deltas within internal storage will be recalculated '
582 b'against multiple base revision and the smallest '
582 b'against multiple base revision and the smallest '
583 b'difference will be used; the size of the repository may '
583 b'difference will be used; the size of the repository may '
584 b'shrink significantly when there are many merges; this '
584 b'shrink significantly when there are many merges; this '
585 b'optimization will slow down execution in proportion to '
585 b'optimization will slow down execution in proportion to '
586 b'the number of merges in the repository and the amount '
586 b'the number of merges in the repository and the amount '
587 b'of files in the repository; this slow down should not '
587 b'of files in the repository; this slow down should not '
588 b'be significant unless there are tens of thousands of '
588 b'be significant unless there are tens of thousands of '
589 b'files and thousands of merges'
589 b'files and thousands of merges'
590 )
590 )
591
591
592 upgrademessage = _(
592 upgrademessage = _(
593 b'deltas within internal storage will choose an '
593 b'deltas within internal storage will choose an '
594 b'optimal delta by computing deltas against multiple '
594 b'optimal delta by computing deltas against multiple '
595 b'parents; may slow down execution time '
595 b'parents; may slow down execution time '
596 b'significantly'
596 b'significantly'
597 )
597 )
598
598
599
599
600 @register_optimization
600 @register_optimization
601 class redeltaall(optimization):
601 class redeltaall(optimization):
602 name = b're-delta-all'
602 name = b're-delta-all'
603
603
604 type = OPTIMISATION
604 type = OPTIMISATION
605
605
606 description = _(
606 description = _(
607 b'deltas within internal storage will always be '
607 b'deltas within internal storage will always be '
608 b'recalculated without reusing prior deltas; this will '
608 b'recalculated without reusing prior deltas; this will '
609 b'likely make execution run several times slower; this '
609 b'likely make execution run several times slower; this '
610 b'optimization is typically not needed'
610 b'optimization is typically not needed'
611 )
611 )
612
612
613 upgrademessage = _(
613 upgrademessage = _(
614 b'deltas within internal storage will be fully '
614 b'deltas within internal storage will be fully '
615 b'recomputed; this will likely drastically slow down '
615 b'recomputed; this will likely drastically slow down '
616 b'execution time'
616 b'execution time'
617 )
617 )
618
618
619
619
620 @register_optimization
620 @register_optimization
621 class redeltafulladd(optimization):
621 class redeltafulladd(optimization):
622 name = b're-delta-fulladd'
622 name = b're-delta-fulladd'
623
623
624 type = OPTIMISATION
624 type = OPTIMISATION
625
625
626 description = _(
626 description = _(
627 b'every revision will be re-added as if it was new '
627 b'every revision will be re-added as if it was new '
628 b'content. It will go through the full storage '
628 b'content. It will go through the full storage '
629 b'mechanism giving extensions a chance to process it '
629 b'mechanism giving extensions a chance to process it '
630 b'(eg. lfs). This is similar to "re-delta-all" but even '
630 b'(eg. lfs). This is similar to "re-delta-all" but even '
631 b'slower since more logic is involved.'
631 b'slower since more logic is involved.'
632 )
632 )
633
633
634 upgrademessage = _(
634 upgrademessage = _(
635 b'each revision will be added as new content to the '
635 b'each revision will be added as new content to the '
636 b'internal storage; this will likely drastically slow '
636 b'internal storage; this will likely drastically slow '
637 b'down execution time, but some extensions might need '
637 b'down execution time, but some extensions might need '
638 b'it'
638 b'it'
639 )
639 )
640
640
641
641
642 def findoptimizations(repo):
642 def findoptimizations(repo):
643 """Determine optimisation that could be used during upgrade"""
643 """Determine optimisation that could be used during upgrade"""
644 # These are unconditionally added. There is logic later that figures out
644 # These are unconditionally added. There is logic later that figures out
645 # which ones to apply.
645 # which ones to apply.
646 return list(ALL_OPTIMISATIONS)
646 return list(ALL_OPTIMISATIONS)
647
647
648
648
649 def determine_upgrade_actions(
649 def determine_upgrade_actions(
650 repo, format_upgrades, optimizations, sourcereqs, destreqs
650 repo, format_upgrades, optimizations, sourcereqs, destreqs
651 ):
651 ):
652 """Determine upgrade actions that will be performed.
652 """Determine upgrade actions that will be performed.
653
653
654 Given a list of improvements as returned by ``find_format_upgrades`` and
654 Given a list of improvements as returned by ``find_format_upgrades`` and
655 ``findoptimizations``, determine the list of upgrade actions that
655 ``findoptimizations``, determine the list of upgrade actions that
656 will be performed.
656 will be performed.
657
657
658 The role of this function is to filter improvements if needed, apply
658 The role of this function is to filter improvements if needed, apply
659 recommended optimizations from the improvements list that make sense,
659 recommended optimizations from the improvements list that make sense,
660 etc.
660 etc.
661
661
662 Returns a list of action names.
662 Returns a list of action names.
663 """
663 """
664 newactions = []
664 newactions = []
665
665
666 for d in format_upgrades:
666 for d in format_upgrades:
667 if util.safehasattr(d, '_requirement'):
667 if util.safehasattr(d, '_requirement'):
668 name = d._requirement
668 name = d._requirement
669 else:
669 else:
670 name = None
670 name = None
671
671
672 # If the action is a requirement that doesn't show up in the
672 # If the action is a requirement that doesn't show up in the
673 # destination requirements, prune the action.
673 # destination requirements, prune the action.
674 if name is not None and name not in destreqs:
674 if name is not None and name not in destreqs:
675 continue
675 continue
676
676
677 newactions.append(d)
677 newactions.append(d)
678
678
679 newactions.extend(o for o in sorted(optimizations) if o not in newactions)
679 newactions.extend(o for o in sorted(optimizations) if o not in newactions)
680
680
681 # FUTURE consider adding some optimizations here for certain transitions.
681 # FUTURE consider adding some optimizations here for certain transitions.
682 # e.g. adding generaldelta could schedule parent redeltas.
682 # e.g. adding generaldelta could schedule parent redeltas.
683
683
684 return newactions
684 return newactions
685
685
686
686
687 class UpgradeOperation:
687 class UpgradeOperation:
688 """represent the work to be done during an upgrade"""
688 """represent the work to be done during an upgrade"""
689
689
690 def __init__(
690 def __init__(
691 self,
691 self,
692 ui,
692 ui,
693 new_requirements,
693 new_requirements,
694 current_requirements,
694 current_requirements,
695 upgrade_actions,
695 upgrade_actions,
696 removed_actions,
696 removed_actions,
697 revlogs_to_process,
697 revlogs_to_process,
698 backup_store,
698 backup_store,
699 ):
699 ):
700 self.ui = ui
700 self.ui = ui
701 self.new_requirements = new_requirements
701 self.new_requirements = new_requirements
702 self.current_requirements = current_requirements
702 self.current_requirements = current_requirements
703 # list of upgrade actions the operation will perform
703 # list of upgrade actions the operation will perform
704 self.upgrade_actions = upgrade_actions
704 self.upgrade_actions = upgrade_actions
705 self.removed_actions = removed_actions
705 self.removed_actions = removed_actions
706 self.revlogs_to_process = revlogs_to_process
706 self.revlogs_to_process = revlogs_to_process
707 # requirements which will be added by the operation
707 # requirements which will be added by the operation
708 self._added_requirements = (
708 self._added_requirements = (
709 self.new_requirements - self.current_requirements
709 self.new_requirements - self.current_requirements
710 )
710 )
711 # requirements which will be removed by the operation
711 # requirements which will be removed by the operation
712 self._removed_requirements = (
712 self._removed_requirements = (
713 self.current_requirements - self.new_requirements
713 self.current_requirements - self.new_requirements
714 )
714 )
715 # requirements which will be preserved by the operation
715 # requirements which will be preserved by the operation
716 self._preserved_requirements = (
716 self._preserved_requirements = (
717 self.current_requirements & self.new_requirements
717 self.current_requirements & self.new_requirements
718 )
718 )
719 # optimizations which are not used and it's recommended that they
719 # optimizations which are not used and it's recommended that they
720 # should use them
720 # should use them
721 all_optimizations = findoptimizations(None)
721 all_optimizations = findoptimizations(None)
722 self.unused_optimizations = [
722 self.unused_optimizations = [
723 i for i in all_optimizations if i not in self.upgrade_actions
723 i for i in all_optimizations if i not in self.upgrade_actions
724 ]
724 ]
725
725
726 # delta reuse mode of this upgrade operation
726 # delta reuse mode of this upgrade operation
727 upgrade_actions_names = self.upgrade_actions_names
727 upgrade_actions_names = self.upgrade_actions_names
728 self.delta_reuse_mode = revlog.revlog.DELTAREUSEALWAYS
728 self.delta_reuse_mode = revlog.revlog.DELTAREUSEALWAYS
729 if b're-delta-all' in upgrade_actions_names:
729 if b're-delta-all' in upgrade_actions_names:
730 self.delta_reuse_mode = revlog.revlog.DELTAREUSENEVER
730 self.delta_reuse_mode = revlog.revlog.DELTAREUSENEVER
731 elif b're-delta-parent' in upgrade_actions_names:
731 elif b're-delta-parent' in upgrade_actions_names:
732 self.delta_reuse_mode = revlog.revlog.DELTAREUSESAMEREVS
732 self.delta_reuse_mode = revlog.revlog.DELTAREUSESAMEREVS
733 elif b're-delta-multibase' in upgrade_actions_names:
733 elif b're-delta-multibase' in upgrade_actions_names:
734 self.delta_reuse_mode = revlog.revlog.DELTAREUSESAMEREVS
734 self.delta_reuse_mode = revlog.revlog.DELTAREUSESAMEREVS
735 elif b're-delta-fulladd' in upgrade_actions_names:
735 elif b're-delta-fulladd' in upgrade_actions_names:
736 self.delta_reuse_mode = revlog.revlog.DELTAREUSEFULLADD
736 self.delta_reuse_mode = revlog.revlog.DELTAREUSEFULLADD
737
737
738 # should this operation force re-delta of both parents
738 # should this operation force re-delta of both parents
739 self.force_re_delta_both_parents = (
739 self.force_re_delta_both_parents = (
740 b're-delta-multibase' in upgrade_actions_names
740 b're-delta-multibase' in upgrade_actions_names
741 )
741 )
742
742
743 # should this operation create a backup of the store
743 # should this operation create a backup of the store
744 self.backup_store = backup_store
744 self.backup_store = backup_store
745
745
746 @property
746 @property
747 def upgrade_actions_names(self):
747 def upgrade_actions_names(self):
748 return set([a.name for a in self.upgrade_actions])
748 return set([a.name for a in self.upgrade_actions])
749
749
750 @property
750 @property
751 def requirements_only(self):
751 def requirements_only(self):
752 # does the operation only touches repository requirement
752 # does the operation only touches repository requirement
753 return (
753 return (
754 self.touches_requirements
754 self.touches_requirements
755 and not self.touches_filelogs
755 and not self.touches_filelogs
756 and not self.touches_manifests
756 and not self.touches_manifests
757 and not self.touches_changelog
757 and not self.touches_changelog
758 and not self.touches_dirstate
758 and not self.touches_dirstate
759 )
759 )
760
760
761 @property
761 @property
762 def touches_filelogs(self):
762 def touches_filelogs(self):
763 for a in self.upgrade_actions:
763 for a in self.upgrade_actions:
764 # in optimisations, we re-process the revlogs again
764 # in optimisations, we re-process the revlogs again
765 if a.type == OPTIMISATION:
765 if a.type == OPTIMISATION:
766 return True
766 return True
767 elif a.touches_filelogs:
767 elif a.touches_filelogs:
768 return True
768 return True
769 for a in self.removed_actions:
769 for a in self.removed_actions:
770 if a.touches_filelogs:
770 if a.touches_filelogs:
771 return True
771 return True
772 return False
772 return False
773
773
774 @property
774 @property
775 def touches_manifests(self):
775 def touches_manifests(self):
776 for a in self.upgrade_actions:
776 for a in self.upgrade_actions:
777 # in optimisations, we re-process the revlogs again
777 # in optimisations, we re-process the revlogs again
778 if a.type == OPTIMISATION:
778 if a.type == OPTIMISATION:
779 return True
779 return True
780 elif a.touches_manifests:
780 elif a.touches_manifests:
781 return True
781 return True
782 for a in self.removed_actions:
782 for a in self.removed_actions:
783 if a.touches_manifests:
783 if a.touches_manifests:
784 return True
784 return True
785 return False
785 return False
786
786
787 @property
787 @property
788 def touches_changelog(self):
788 def touches_changelog(self):
789 for a in self.upgrade_actions:
789 for a in self.upgrade_actions:
790 # in optimisations, we re-process the revlogs again
790 # in optimisations, we re-process the revlogs again
791 if a.type == OPTIMISATION:
791 if a.type == OPTIMISATION:
792 return True
792 return True
793 elif a.touches_changelog:
793 elif a.touches_changelog:
794 return True
794 return True
795 for a in self.removed_actions:
795 for a in self.removed_actions:
796 if a.touches_changelog:
796 if a.touches_changelog:
797 return True
797 return True
798 return False
798 return False
799
799
800 @property
800 @property
801 def touches_requirements(self):
801 def touches_requirements(self):
802 for a in self.upgrade_actions:
802 for a in self.upgrade_actions:
803 # optimisations are used to re-process revlogs and does not result
803 # optimisations are used to re-process revlogs and does not result
804 # in a requirement being added or removed
804 # in a requirement being added or removed
805 if a.type == OPTIMISATION:
805 if a.type == OPTIMISATION:
806 pass
806 pass
807 elif a.touches_requirements:
807 elif a.touches_requirements:
808 return True
808 return True
809 for a in self.removed_actions:
809 for a in self.removed_actions:
810 if a.touches_requirements:
810 if a.touches_requirements:
811 return True
811 return True
812
812
813 @property
813 @property
814 def touches_dirstate(self):
814 def touches_dirstate(self):
815 for a in self.upgrade_actions:
815 for a in self.upgrade_actions:
816 # revlog optimisations do not affect the dirstate
816 # revlog optimisations do not affect the dirstate
817 if a.type == OPTIMISATION:
817 if a.type == OPTIMISATION:
818 pass
818 pass
819 elif a.touches_dirstate:
819 elif a.touches_dirstate:
820 return True
820 return True
821 for a in self.removed_actions:
821 for a in self.removed_actions:
822 if a.touches_dirstate:
822 if a.touches_dirstate:
823 return True
823 return True
824
824
825 return False
825 return False
826
826
827 def _write_labeled(self, l, label):
827 def _write_labeled(self, l, label):
828 """
828 """
829 Utility function to aid writing of a list under one label
829 Utility function to aid writing of a list under one label
830 """
830 """
831 first = True
831 first = True
832 for r in sorted(l):
832 for r in sorted(l):
833 if not first:
833 if not first:
834 self.ui.write(b', ')
834 self.ui.write(b', ')
835 self.ui.write(r, label=label)
835 self.ui.write(r, label=label)
836 first = False
836 first = False
837
837
838 def print_requirements(self):
838 def print_requirements(self):
839 self.ui.write(_(b'requirements\n'))
839 self.ui.write(_(b'requirements\n'))
840 self.ui.write(_(b' preserved: '))
840 self.ui.write(_(b' preserved: '))
841 self._write_labeled(
841 self._write_labeled(
842 self._preserved_requirements, "upgrade-repo.requirement.preserved"
842 self._preserved_requirements, "upgrade-repo.requirement.preserved"
843 )
843 )
844 self.ui.write((b'\n'))
844 self.ui.write((b'\n'))
845 if self._removed_requirements:
845 if self._removed_requirements:
846 self.ui.write(_(b' removed: '))
846 self.ui.write(_(b' removed: '))
847 self._write_labeled(
847 self._write_labeled(
848 self._removed_requirements, "upgrade-repo.requirement.removed"
848 self._removed_requirements, "upgrade-repo.requirement.removed"
849 )
849 )
850 self.ui.write((b'\n'))
850 self.ui.write((b'\n'))
851 if self._added_requirements:
851 if self._added_requirements:
852 self.ui.write(_(b' added: '))
852 self.ui.write(_(b' added: '))
853 self._write_labeled(
853 self._write_labeled(
854 self._added_requirements, "upgrade-repo.requirement.added"
854 self._added_requirements, "upgrade-repo.requirement.added"
855 )
855 )
856 self.ui.write((b'\n'))
856 self.ui.write((b'\n'))
857 self.ui.write(b'\n')
857 self.ui.write(b'\n')
858
858
859 def print_optimisations(self):
859 def print_optimisations(self):
860 optimisations = [
860 optimisations = [
861 a for a in self.upgrade_actions if a.type == OPTIMISATION
861 a for a in self.upgrade_actions if a.type == OPTIMISATION
862 ]
862 ]
863 optimisations.sort(key=lambda a: a.name)
863 optimisations.sort(key=lambda a: a.name)
864 if optimisations:
864 if optimisations:
865 self.ui.write(_(b'optimisations: '))
865 self.ui.write(_(b'optimisations: '))
866 self._write_labeled(
866 self._write_labeled(
867 [a.name for a in optimisations],
867 [a.name for a in optimisations],
868 "upgrade-repo.optimisation.performed",
868 "upgrade-repo.optimisation.performed",
869 )
869 )
870 self.ui.write(b'\n\n')
870 self.ui.write(b'\n\n')
871
871
872 def print_upgrade_actions(self):
872 def print_upgrade_actions(self):
873 for a in self.upgrade_actions:
873 for a in self.upgrade_actions:
874 self.ui.status(b'%s\n %s\n\n' % (a.name, a.upgrademessage))
874 self.ui.status(b'%s\n %s\n\n' % (a.name, a.upgrademessage))
875
875
876 def print_affected_revlogs(self):
876 def print_affected_revlogs(self):
877 if not self.revlogs_to_process:
877 if not self.revlogs_to_process:
878 self.ui.write((b'no revlogs to process\n'))
878 self.ui.write((b'no revlogs to process\n'))
879 else:
879 else:
880 self.ui.write((b'processed revlogs:\n'))
880 self.ui.write((b'processed revlogs:\n'))
881 for r in sorted(self.revlogs_to_process):
881 for r in sorted(self.revlogs_to_process):
882 self.ui.write((b' - %s\n' % r))
882 self.ui.write((b' - %s\n' % r))
883 self.ui.write((b'\n'))
883 self.ui.write((b'\n'))
884
884
885 def print_unused_optimizations(self):
885 def print_unused_optimizations(self):
886 for i in self.unused_optimizations:
886 for i in self.unused_optimizations:
887 self.ui.status(_(b'%s\n %s\n\n') % (i.name, i.description))
887 self.ui.status(_(b'%s\n %s\n\n') % (i.name, i.description))
888
888
889 def has_upgrade_action(self, name):
889 def has_upgrade_action(self, name):
890 """Check whether the upgrade operation will perform this action"""
890 """Check whether the upgrade operation will perform this action"""
891 return name in self._upgrade_actions_names
891 return name in self._upgrade_actions_names
892
892
893 def print_post_op_messages(self):
893 def print_post_op_messages(self):
894 """print post upgrade operation warning messages"""
894 """print post upgrade operation warning messages"""
895 for a in self.upgrade_actions:
895 for a in self.upgrade_actions:
896 if a.postupgrademessage is not None:
896 if a.postupgrademessage is not None:
897 self.ui.warn(b'%s\n' % a.postupgrademessage)
897 self.ui.warn(b'%s\n' % a.postupgrademessage)
898 for a in self.removed_actions:
898 for a in self.removed_actions:
899 if a.postdowngrademessage is not None:
899 if a.postdowngrademessage is not None:
900 self.ui.warn(b'%s\n' % a.postdowngrademessage)
900 self.ui.warn(b'%s\n' % a.postdowngrademessage)
901
901
902
902
903 ### Code checking if a repository can got through the upgrade process at all. #
903 ### Code checking if a repository can got through the upgrade process at all. #
904
904
905
905
906 def requiredsourcerequirements(repo):
906 def requiredsourcerequirements(repo):
907 """Obtain requirements required to be present to upgrade a repo.
907 """Obtain requirements required to be present to upgrade a repo.
908
908
909 An upgrade will not be allowed if the repository doesn't have the
909 An upgrade will not be allowed if the repository doesn't have the
910 requirements returned by this function.
910 requirements returned by this function.
911 """
911 """
912 return {
912 return {
913 # Introduced in Mercurial 0.9.2.
913 # Introduced in Mercurial 0.9.2.
914 requirements.STORE_REQUIREMENT,
914 requirements.STORE_REQUIREMENT,
915 }
915 }
916
916
917
917
918 def blocksourcerequirements(repo):
918 def blocksourcerequirements(repo):
919 """Obtain requirements that will prevent an upgrade from occurring.
919 """Obtain requirements that will prevent an upgrade from occurring.
920
920
921 An upgrade cannot be performed if the source repository contains a
921 An upgrade cannot be performed if the source repository contains a
922 requirements in the returned set.
922 requirements in the returned set.
923 """
923 """
924 return {
924 return {
925 # The upgrade code does not yet support these experimental features.
925 # The upgrade code does not yet support these experimental features.
926 # This is an artificial limitation.
926 # This is an artificial limitation.
927 requirements.TREEMANIFEST_REQUIREMENT,
927 requirements.TREEMANIFEST_REQUIREMENT,
928 # This was a precursor to generaldelta and was never enabled by default.
928 # This was a precursor to generaldelta and was never enabled by default.
929 # It should (hopefully) not exist in the wild.
929 # It should (hopefully) not exist in the wild.
930 b'parentdelta',
930 b'parentdelta',
931 }
931 }
932
932
933
933
934 def check_revlog_version(reqs):
934 def check_revlog_version(reqs):
935 """Check that the requirements contain at least one Revlog version"""
935 """Check that the requirements contain at least one Revlog version"""
936 all_revlogs = {
936 all_revlogs = {
937 requirements.REVLOGV1_REQUIREMENT,
937 requirements.REVLOGV1_REQUIREMENT,
938 requirements.REVLOGV2_REQUIREMENT,
938 requirements.REVLOGV2_REQUIREMENT,
939 }
939 }
940 if not all_revlogs.intersection(reqs):
940 if not all_revlogs.intersection(reqs):
941 msg = _(b'cannot upgrade repository; missing a revlog version')
941 msg = _(b'cannot upgrade repository; missing a revlog version')
942 raise error.Abort(msg)
942 raise error.Abort(msg)
943
943
944
944
945 def check_source_requirements(repo):
945 def check_source_requirements(repo):
946 """Ensure that no existing requirements prevent the repository upgrade"""
946 """Ensure that no existing requirements prevent the repository upgrade"""
947
947
948 check_revlog_version(repo.requirements)
948 check_revlog_version(repo.requirements)
949 required = requiredsourcerequirements(repo)
949 required = requiredsourcerequirements(repo)
950 missingreqs = required - repo.requirements
950 missingreqs = required - repo.requirements
951 if missingreqs:
951 if missingreqs:
952 msg = _(b'cannot upgrade repository; requirement missing: %s')
952 msg = _(b'cannot upgrade repository; requirement missing: %s')
953 missingreqs = b', '.join(sorted(missingreqs))
953 missingreqs = b', '.join(sorted(missingreqs))
954 raise error.Abort(msg % missingreqs)
954 raise error.Abort(msg % missingreqs)
955
955
956 blocking = blocksourcerequirements(repo)
956 blocking = blocksourcerequirements(repo)
957 blockingreqs = blocking & repo.requirements
957 blockingreqs = blocking & repo.requirements
958 if blockingreqs:
958 if blockingreqs:
959 m = _(b'cannot upgrade repository; unsupported source requirement: %s')
959 m = _(b'cannot upgrade repository; unsupported source requirement: %s')
960 blockingreqs = b', '.join(sorted(blockingreqs))
960 blockingreqs = b', '.join(sorted(blockingreqs))
961 raise error.Abort(m % blockingreqs)
961 raise error.Abort(m % blockingreqs)
962 # Upgrade should operate on the actual store, not the shared link.
962 # Upgrade should operate on the actual store, not the shared link.
963
963
964 bad_share = (
964 bad_share = (
965 requirements.SHARED_REQUIREMENT in repo.requirements
965 requirements.SHARED_REQUIREMENT in repo.requirements
966 and requirements.SHARESAFE_REQUIREMENT not in repo.requirements
966 and requirements.SHARESAFE_REQUIREMENT not in repo.requirements
967 )
967 )
968 if bad_share:
968 if bad_share:
969 m = _(b'cannot upgrade repository; share repository without share-safe')
969 m = _(b'cannot upgrade repository; share repository without share-safe')
970 h = _(b'check :hg:`help config.format.use-share-safe`')
970 h = _(b'check :hg:`help config.format.use-share-safe`')
971 raise error.Abort(m, hint=h)
971 raise error.Abort(m, hint=h)
972
972
973
973
974 ### Verify the validity of the planned requirement changes ####################
974 ### Verify the validity of the planned requirement changes ####################
975
975
976
976
977 def supportremovedrequirements(repo):
977 def supportremovedrequirements(repo):
978 """Obtain requirements that can be removed during an upgrade.
978 """Obtain requirements that can be removed during an upgrade.
979
979
980 If an upgrade were to create a repository that dropped a requirement,
980 If an upgrade were to create a repository that dropped a requirement,
981 the dropped requirement must appear in the returned set for the upgrade
981 the dropped requirement must appear in the returned set for the upgrade
982 to be allowed.
982 to be allowed.
983 """
983 """
984 supported = {
984 supported = {
985 requirements.SPARSEREVLOG_REQUIREMENT,
985 requirements.SPARSEREVLOG_REQUIREMENT,
986 requirements.COPIESSDC_REQUIREMENT,
986 requirements.COPIESSDC_REQUIREMENT,
987 requirements.NODEMAP_REQUIREMENT,
987 requirements.NODEMAP_REQUIREMENT,
988 requirements.SHARESAFE_REQUIREMENT,
988 requirements.SHARESAFE_REQUIREMENT,
989 requirements.REVLOGV2_REQUIREMENT,
989 requirements.REVLOGV2_REQUIREMENT,
990 requirements.CHANGELOGV2_REQUIREMENT,
990 requirements.CHANGELOGV2_REQUIREMENT,
991 requirements.REVLOGV1_REQUIREMENT,
991 requirements.REVLOGV1_REQUIREMENT,
992 requirements.DIRSTATE_TRACKED_HINT_V1,
992 requirements.DIRSTATE_TRACKED_HINT_V1,
993 requirements.DIRSTATE_V2_REQUIREMENT,
993 requirements.DIRSTATE_V2_REQUIREMENT,
994 }
994 }
995 for name in compression.compengines:
995 for name in compression.compengines:
996 engine = compression.compengines[name]
996 engine = compression.compengines[name]
997 if engine.available() and engine.revlogheader():
997 if engine.available() and engine.revlogheader():
998 supported.add(b'exp-compression-%s' % name)
998 supported.add(b'exp-compression-%s' % name)
999 if engine.name() == b'zstd':
999 if engine.name() == b'zstd':
1000 supported.add(b'revlog-compression-zstd')
1000 supported.add(b'revlog-compression-zstd')
1001 return supported
1001 return supported
1002
1002
1003
1003
1004 def supporteddestrequirements(repo):
1004 def supporteddestrequirements(repo):
1005 """Obtain requirements that upgrade supports in the destination.
1005 """Obtain requirements that upgrade supports in the destination.
1006
1006
1007 If the result of the upgrade would create requirements not in this set,
1007 If the result of the upgrade would have requirements not in this set,
1008 the upgrade is disallowed.
1008 the upgrade is disallowed.
1009
1009
1010 Extensions should monkeypatch this to add their custom requirements.
1010 Extensions should monkeypatch this to add their custom requirements.
1011 """
1011 """
1012 supported = {
1012 supported = {
1013 requirements.CHANGELOGV2_REQUIREMENT,
1013 requirements.CHANGELOGV2_REQUIREMENT,
1014 requirements.COPIESSDC_REQUIREMENT,
1014 requirements.COPIESSDC_REQUIREMENT,
1015 requirements.DIRSTATE_TRACKED_HINT_V1,
1015 requirements.DIRSTATE_TRACKED_HINT_V1,
1016 requirements.DIRSTATE_V2_REQUIREMENT,
1016 requirements.DIRSTATE_V2_REQUIREMENT,
1017 requirements.DOTENCODE_REQUIREMENT,
1017 requirements.DOTENCODE_REQUIREMENT,
1018 requirements.FNCACHE_REQUIREMENT,
1018 requirements.FNCACHE_REQUIREMENT,
1019 requirements.GENERALDELTA_REQUIREMENT,
1019 requirements.GENERALDELTA_REQUIREMENT,
1020 requirements.NODEMAP_REQUIREMENT,
1020 requirements.NODEMAP_REQUIREMENT,
1021 requirements.REVLOGV1_REQUIREMENT, # allowed in case of downgrade
1021 requirements.REVLOGV1_REQUIREMENT, # allowed in case of downgrade
1022 requirements.REVLOGV2_REQUIREMENT,
1022 requirements.REVLOGV2_REQUIREMENT,
1023 requirements.SHARED_REQUIREMENT,
1023 requirements.SHARED_REQUIREMENT,
1024 requirements.SHARESAFE_REQUIREMENT,
1024 requirements.SHARESAFE_REQUIREMENT,
1025 requirements.SPARSEREVLOG_REQUIREMENT,
1025 requirements.SPARSEREVLOG_REQUIREMENT,
1026 requirements.STORE_REQUIREMENT,
1026 requirements.STORE_REQUIREMENT,
1027 requirements.NARROW_REQUIREMENT,
1027 }
1028 }
1028 for name in compression.compengines:
1029 for name in compression.compengines:
1029 engine = compression.compengines[name]
1030 engine = compression.compengines[name]
1030 if engine.available() and engine.revlogheader():
1031 if engine.available() and engine.revlogheader():
1031 supported.add(b'exp-compression-%s' % name)
1032 supported.add(b'exp-compression-%s' % name)
1032 if engine.name() == b'zstd':
1033 if engine.name() == b'zstd':
1033 supported.add(b'revlog-compression-zstd')
1034 supported.add(b'revlog-compression-zstd')
1034 return supported
1035 return supported
1035
1036
1036
1037
1037 def allowednewrequirements(repo):
1038 def allowednewrequirements(repo):
1038 """Obtain requirements that can be added to a repository during upgrade.
1039 """Obtain requirements that can be added to a repository during upgrade.
1039
1040
1040 This is used to disallow proposed requirements from being added when
1041 This is used to disallow proposed requirements from being added when
1041 they weren't present before.
1042 they weren't present before.
1042
1043
1043 We use a list of allowed requirement additions instead of a list of known
1044 We use a list of allowed requirement additions instead of a list of known
1044 bad additions because the whitelist approach is safer and will prevent
1045 bad additions because the whitelist approach is safer and will prevent
1045 future, unknown requirements from accidentally being added.
1046 future, unknown requirements from accidentally being added.
1046 """
1047 """
1047 supported = {
1048 supported = {
1048 requirements.DOTENCODE_REQUIREMENT,
1049 requirements.DOTENCODE_REQUIREMENT,
1049 requirements.FNCACHE_REQUIREMENT,
1050 requirements.FNCACHE_REQUIREMENT,
1050 requirements.GENERALDELTA_REQUIREMENT,
1051 requirements.GENERALDELTA_REQUIREMENT,
1051 requirements.SPARSEREVLOG_REQUIREMENT,
1052 requirements.SPARSEREVLOG_REQUIREMENT,
1052 requirements.COPIESSDC_REQUIREMENT,
1053 requirements.COPIESSDC_REQUIREMENT,
1053 requirements.NODEMAP_REQUIREMENT,
1054 requirements.NODEMAP_REQUIREMENT,
1054 requirements.SHARESAFE_REQUIREMENT,
1055 requirements.SHARESAFE_REQUIREMENT,
1055 requirements.REVLOGV1_REQUIREMENT,
1056 requirements.REVLOGV1_REQUIREMENT,
1056 requirements.REVLOGV2_REQUIREMENT,
1057 requirements.REVLOGV2_REQUIREMENT,
1057 requirements.CHANGELOGV2_REQUIREMENT,
1058 requirements.CHANGELOGV2_REQUIREMENT,
1058 requirements.DIRSTATE_TRACKED_HINT_V1,
1059 requirements.DIRSTATE_TRACKED_HINT_V1,
1059 requirements.DIRSTATE_V2_REQUIREMENT,
1060 requirements.DIRSTATE_V2_REQUIREMENT,
1060 }
1061 }
1061 for name in compression.compengines:
1062 for name in compression.compengines:
1062 engine = compression.compengines[name]
1063 engine = compression.compengines[name]
1063 if engine.available() and engine.revlogheader():
1064 if engine.available() and engine.revlogheader():
1064 supported.add(b'exp-compression-%s' % name)
1065 supported.add(b'exp-compression-%s' % name)
1065 if engine.name() == b'zstd':
1066 if engine.name() == b'zstd':
1066 supported.add(b'revlog-compression-zstd')
1067 supported.add(b'revlog-compression-zstd')
1067 return supported
1068 return supported
1068
1069
1069
1070
1070 def check_requirements_changes(repo, new_reqs):
1071 def check_requirements_changes(repo, new_reqs):
1071 old_reqs = repo.requirements
1072 old_reqs = repo.requirements
1072 check_revlog_version(repo.requirements)
1073 check_revlog_version(repo.requirements)
1073 support_removal = supportremovedrequirements(repo)
1074 support_removal = supportremovedrequirements(repo)
1074 no_remove_reqs = old_reqs - new_reqs - support_removal
1075 no_remove_reqs = old_reqs - new_reqs - support_removal
1075 if no_remove_reqs:
1076 if no_remove_reqs:
1076 msg = _(b'cannot upgrade repository; requirement would be removed: %s')
1077 msg = _(b'cannot upgrade repository; requirement would be removed: %s')
1077 no_remove_reqs = b', '.join(sorted(no_remove_reqs))
1078 no_remove_reqs = b', '.join(sorted(no_remove_reqs))
1078 raise error.Abort(msg % no_remove_reqs)
1079 raise error.Abort(msg % no_remove_reqs)
1079
1080
1080 support_addition = allowednewrequirements(repo)
1081 support_addition = allowednewrequirements(repo)
1081 no_add_reqs = new_reqs - old_reqs - support_addition
1082 no_add_reqs = new_reqs - old_reqs - support_addition
1082 if no_add_reqs:
1083 if no_add_reqs:
1083 m = _(b'cannot upgrade repository; do not support adding requirement: ')
1084 m = _(b'cannot upgrade repository; do not support adding requirement: ')
1084 no_add_reqs = b', '.join(sorted(no_add_reqs))
1085 no_add_reqs = b', '.join(sorted(no_add_reqs))
1085 raise error.Abort(m + no_add_reqs)
1086 raise error.Abort(m + no_add_reqs)
1086
1087
1087 supported = supporteddestrequirements(repo)
1088 supported = supporteddestrequirements(repo)
1088 unsupported_reqs = new_reqs - supported
1089 unsupported_reqs = new_reqs - supported
1089 if unsupported_reqs:
1090 if unsupported_reqs:
1090 msg = _(
1091 msg = _(
1091 b'cannot upgrade repository; do not support destination '
1092 b'cannot upgrade repository; do not support destination '
1092 b'requirement: %s'
1093 b'requirement: %s'
1093 )
1094 )
1094 unsupported_reqs = b', '.join(sorted(unsupported_reqs))
1095 unsupported_reqs = b', '.join(sorted(unsupported_reqs))
1095 raise error.Abort(msg % unsupported_reqs)
1096 raise error.Abort(msg % unsupported_reqs)
@@ -1,541 +1,552 b''
1 #testcases flat tree
1 #testcases flat tree
2 #testcases lfs-on lfs-off
2 #testcases lfs-on lfs-off
3
3
4 $ cat >> $HGRCPATH << EOF
4 $ cat >> $HGRCPATH << EOF
5 > [experimental]
5 > [experimental]
6 > evolution=createmarkers
6 > evolution=createmarkers
7 > EOF
7 > EOF
8
8
9 #if lfs-on
9 #if lfs-on
10 $ cat >> $HGRCPATH <<EOF
10 $ cat >> $HGRCPATH <<EOF
11 > [extensions]
11 > [extensions]
12 > lfs =
12 > lfs =
13 > EOF
13 > EOF
14 #endif
14 #endif
15
15
16 $ . "$TESTDIR/narrow-library.sh"
16 $ . "$TESTDIR/narrow-library.sh"
17
17
18 #if tree
18 #if tree
19 $ cat << EOF >> $HGRCPATH
19 $ cat << EOF >> $HGRCPATH
20 > [experimental]
20 > [experimental]
21 > treemanifest = 1
21 > treemanifest = 1
22 > EOF
22 > EOF
23 #endif
23 #endif
24
24
25 $ hg init master
25 $ hg init master
26 $ cd master
26 $ cd master
27 $ cat >> .hg/hgrc <<EOF
27 $ cat >> .hg/hgrc <<EOF
28 > [narrow]
28 > [narrow]
29 > serveellipses=True
29 > serveellipses=True
30 > EOF
30 > EOF
31 $ for x in `$TESTDIR/seq.py 0 10`
31 $ for x in `$TESTDIR/seq.py 0 10`
32 > do
32 > do
33 > mkdir d$x
33 > mkdir d$x
34 > echo $x > d$x/f
34 > echo $x > d$x/f
35 > hg add d$x/f
35 > hg add d$x/f
36 > hg commit -m "add d$x/f"
36 > hg commit -m "add d$x/f"
37 > done
37 > done
38 $ hg log -T "{rev}: {desc}\n"
38 $ hg log -T "{rev}: {desc}\n"
39 10: add d10/f
39 10: add d10/f
40 9: add d9/f
40 9: add d9/f
41 8: add d8/f
41 8: add d8/f
42 7: add d7/f
42 7: add d7/f
43 6: add d6/f
43 6: add d6/f
44 5: add d5/f
44 5: add d5/f
45 4: add d4/f
45 4: add d4/f
46 3: add d3/f
46 3: add d3/f
47 2: add d2/f
47 2: add d2/f
48 1: add d1/f
48 1: add d1/f
49 0: add d0/f
49 0: add d0/f
50 $ cd ..
50 $ cd ..
51
51
52 Error if '.' or '..' are in the directory to track.
52 Error if '.' or '..' are in the directory to track.
53 $ hg clone --narrow ssh://user@dummy/master foo --include ./asdf
53 $ hg clone --narrow ssh://user@dummy/master foo --include ./asdf
54 abort: "." and ".." are not allowed in narrowspec paths
54 abort: "." and ".." are not allowed in narrowspec paths
55 [255]
55 [255]
56 $ hg clone --narrow ssh://user@dummy/master foo --include asdf/..
56 $ hg clone --narrow ssh://user@dummy/master foo --include asdf/..
57 abort: "." and ".." are not allowed in narrowspec paths
57 abort: "." and ".." are not allowed in narrowspec paths
58 [255]
58 [255]
59 $ hg clone --narrow ssh://user@dummy/master foo --include a/./c
59 $ hg clone --narrow ssh://user@dummy/master foo --include a/./c
60 abort: "." and ".." are not allowed in narrowspec paths
60 abort: "." and ".." are not allowed in narrowspec paths
61 [255]
61 [255]
62
62
63 Names with '.' in them are OK.
63 Names with '.' in them are OK.
64 $ hg clone --narrow ./master should-work --include a/.b/c
64 $ hg clone --narrow ./master should-work --include a/.b/c
65 requesting all changes
65 requesting all changes
66 adding changesets
66 adding changesets
67 adding manifests
67 adding manifests
68 adding file changes
68 adding file changes
69 added 1 changesets with 0 changes to 0 files
69 added 1 changesets with 0 changes to 0 files
70 new changesets * (glob)
70 new changesets * (glob)
71 updating to branch default
71 updating to branch default
72 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
72 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
73
73
74 The "narrow" repo requirement is ignored by [debugupgraderepo]
75
76 #if tree
77 $ (cd should-work; hg debugupgraderepo)
78 abort: cannot upgrade repository; unsupported source requirement: treemanifest
79 [255]
80 #else
81 $ (cd should-work; hg debugupgraderepo | grep 'no format upgrades found in existing repository')
82 (no format upgrades found in existing repository)
83 #endif
84
74 Test repo with local changes
85 Test repo with local changes
75 $ hg clone --narrow ssh://user@dummy/master narrow-local-changes --include d0 --include d3 --include d6
86 $ hg clone --narrow ssh://user@dummy/master narrow-local-changes --include d0 --include d3 --include d6
76 requesting all changes
87 requesting all changes
77 adding changesets
88 adding changesets
78 adding manifests
89 adding manifests
79 adding file changes
90 adding file changes
80 added 6 changesets with 3 changes to 3 files
91 added 6 changesets with 3 changes to 3 files
81 new changesets *:* (glob)
92 new changesets *:* (glob)
82 updating to branch default
93 updating to branch default
83 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
94 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
84 $ cd narrow-local-changes
95 $ cd narrow-local-changes
85 $ echo local change >> d0/f
96 $ echo local change >> d0/f
86 $ hg ci -m 'local change to d0'
97 $ hg ci -m 'local change to d0'
87 $ hg co '.^'
98 $ hg co '.^'
88 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
99 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
89 $ echo local change >> d3/f
100 $ echo local change >> d3/f
90 $ hg ci -m 'local hidden change to d3'
101 $ hg ci -m 'local hidden change to d3'
91 created new head
102 created new head
92 $ hg ci --amend -m 'local change to d3'
103 $ hg ci --amend -m 'local change to d3'
93 $ hg tracked --removeinclude d0
104 $ hg tracked --removeinclude d0
94 comparing with ssh://user@dummy/master
105 comparing with ssh://user@dummy/master
95 searching for changes
106 searching for changes
96 looking for local changes to affected paths
107 looking for local changes to affected paths
97 The following changeset(s) or their ancestors have local changes not on the remote:
108 The following changeset(s) or their ancestors have local changes not on the remote:
98 * (glob)
109 * (glob)
99 abort: local changes found
110 abort: local changes found
100 (use --force-delete-local-changes to ignore)
111 (use --force-delete-local-changes to ignore)
101 [20]
112 [20]
102 Check that nothing was removed by the failed attempts
113 Check that nothing was removed by the failed attempts
103 $ hg tracked
114 $ hg tracked
104 I path:d0
115 I path:d0
105 I path:d3
116 I path:d3
106 I path:d6
117 I path:d6
107 $ hg files
118 $ hg files
108 d0/f
119 d0/f
109 d3/f
120 d3/f
110 d6/f
121 d6/f
111 $ find *
122 $ find *
112 d0
123 d0
113 d0/f
124 d0/f
114 d3
125 d3
115 d3/f
126 d3/f
116 d6
127 d6
117 d6/f
128 d6/f
118 $ hg verify -q
129 $ hg verify -q
119 Force deletion of local changes
130 Force deletion of local changes
120 $ hg log -T "{rev}: {desc} {outsidenarrow}\n"
131 $ hg log -T "{rev}: {desc} {outsidenarrow}\n"
121 8: local change to d3
132 8: local change to d3
122 6: local change to d0
133 6: local change to d0
123 5: add d10/f outsidenarrow
134 5: add d10/f outsidenarrow
124 4: add d6/f
135 4: add d6/f
125 3: add d5/f outsidenarrow
136 3: add d5/f outsidenarrow
126 2: add d3/f
137 2: add d3/f
127 1: add d2/f outsidenarrow
138 1: add d2/f outsidenarrow
128 0: add d0/f
139 0: add d0/f
129 $ hg tracked --removeinclude d0 --force-delete-local-changes
140 $ hg tracked --removeinclude d0 --force-delete-local-changes
130 comparing with ssh://user@dummy/master
141 comparing with ssh://user@dummy/master
131 searching for changes
142 searching for changes
132 looking for local changes to affected paths
143 looking for local changes to affected paths
133 The following changeset(s) or their ancestors have local changes not on the remote:
144 The following changeset(s) or their ancestors have local changes not on the remote:
134 * (glob)
145 * (glob)
135 moving unwanted changesets to backup
146 moving unwanted changesets to backup
136 saved backup bundle to $TESTTMP/narrow-local-changes/.hg/strip-backup/*-narrow.hg (glob)
147 saved backup bundle to $TESTTMP/narrow-local-changes/.hg/strip-backup/*-narrow.hg (glob)
137 deleting data/d0/f.i (reporevlogstore !)
148 deleting data/d0/f.i (reporevlogstore !)
138 deleting meta/d0/00manifest.i (tree !)
149 deleting meta/d0/00manifest.i (tree !)
139 deleting data/d0/f/362fef284ce2ca02aecc8de6d5e8a1c3af0556fe (reposimplestore !)
150 deleting data/d0/f/362fef284ce2ca02aecc8de6d5e8a1c3af0556fe (reposimplestore !)
140 deleting data/d0/f/4374b5650fc5ae54ac857c0f0381971fdde376f7 (reposimplestore !)
151 deleting data/d0/f/4374b5650fc5ae54ac857c0f0381971fdde376f7 (reposimplestore !)
141 deleting data/d0/f/index (reposimplestore !)
152 deleting data/d0/f/index (reposimplestore !)
142 deleting unwanted files from working copy
153 deleting unwanted files from working copy
143
154
144 $ hg log -T "{rev}: {desc} {outsidenarrow}\n"
155 $ hg log -T "{rev}: {desc} {outsidenarrow}\n"
145 7: local change to d3
156 7: local change to d3
146 5: add d10/f outsidenarrow
157 5: add d10/f outsidenarrow
147 4: add d6/f
158 4: add d6/f
148 3: add d5/f outsidenarrow
159 3: add d5/f outsidenarrow
149 2: add d3/f
160 2: add d3/f
150 1: add d2/f outsidenarrow
161 1: add d2/f outsidenarrow
151 0: add d0/f outsidenarrow
162 0: add d0/f outsidenarrow
152 Can restore stripped local changes after widening
163 Can restore stripped local changes after widening
153 $ hg tracked --addinclude d0 -q
164 $ hg tracked --addinclude d0 -q
154 $ hg unbundle .hg/strip-backup/*-narrow.hg -q
165 $ hg unbundle .hg/strip-backup/*-narrow.hg -q
155 $ hg --hidden co -r 'desc("local change to d0")' -q
166 $ hg --hidden co -r 'desc("local change to d0")' -q
156 $ cat d0/f
167 $ cat d0/f
157 0
168 0
158 local change
169 local change
159 Pruned commits affecting removed paths should not prevent narrowing
170 Pruned commits affecting removed paths should not prevent narrowing
160 $ hg co '.^'
171 $ hg co '.^'
161 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
172 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
162 $ hg debugobsolete `hg log -T '{node}' -r 'desc("local change to d0")'`
173 $ hg debugobsolete `hg log -T '{node}' -r 'desc("local change to d0")'`
163 1 new obsolescence markers
174 1 new obsolescence markers
164 obsoleted 1 changesets
175 obsoleted 1 changesets
165 $ hg tracked --removeinclude d0
176 $ hg tracked --removeinclude d0
166 comparing with ssh://user@dummy/master
177 comparing with ssh://user@dummy/master
167 searching for changes
178 searching for changes
168 looking for local changes to affected paths
179 looking for local changes to affected paths
169 moving unwanted changesets to backup
180 moving unwanted changesets to backup
170 saved backup bundle to $TESTTMP/narrow-local-changes/.hg/strip-backup/*-narrow.hg (glob)
181 saved backup bundle to $TESTTMP/narrow-local-changes/.hg/strip-backup/*-narrow.hg (glob)
171 deleting data/d0/f.i (reporevlogstore !)
182 deleting data/d0/f.i (reporevlogstore !)
172 deleting meta/d0/00manifest.i (tree !)
183 deleting meta/d0/00manifest.i (tree !)
173 deleting data/d0/f/362fef284ce2ca02aecc8de6d5e8a1c3af0556fe (reposimplestore !)
184 deleting data/d0/f/362fef284ce2ca02aecc8de6d5e8a1c3af0556fe (reposimplestore !)
174 deleting data/d0/f/4374b5650fc5ae54ac857c0f0381971fdde376f7 (reposimplestore !)
185 deleting data/d0/f/4374b5650fc5ae54ac857c0f0381971fdde376f7 (reposimplestore !)
175 deleting data/d0/f/index (reposimplestore !)
186 deleting data/d0/f/index (reposimplestore !)
176 deleting unwanted files from working copy
187 deleting unwanted files from working copy
177
188
178 Updates off of stripped commit if necessary
189 Updates off of stripped commit if necessary
179 $ hg co -r 'desc("local change to d3")' -q
190 $ hg co -r 'desc("local change to d3")' -q
180 $ echo local change >> d6/f
191 $ echo local change >> d6/f
181 $ hg ci -m 'local change to d6'
192 $ hg ci -m 'local change to d6'
182 $ hg tracked --removeinclude d3 --force-delete-local-changes
193 $ hg tracked --removeinclude d3 --force-delete-local-changes
183 comparing with ssh://user@dummy/master
194 comparing with ssh://user@dummy/master
184 searching for changes
195 searching for changes
185 looking for local changes to affected paths
196 looking for local changes to affected paths
186 The following changeset(s) or their ancestors have local changes not on the remote:
197 The following changeset(s) or their ancestors have local changes not on the remote:
187 * (glob)
198 * (glob)
188 * (glob)
199 * (glob)
189 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
200 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
190 moving unwanted changesets to backup
201 moving unwanted changesets to backup
191 saved backup bundle to $TESTTMP/narrow-local-changes/.hg/strip-backup/*-narrow.hg (glob)
202 saved backup bundle to $TESTTMP/narrow-local-changes/.hg/strip-backup/*-narrow.hg (glob)
192 deleting data/d3/f.i (reporevlogstore !)
203 deleting data/d3/f.i (reporevlogstore !)
193 deleting meta/d3/00manifest.i (tree !)
204 deleting meta/d3/00manifest.i (tree !)
194 deleting data/d3/f/2661d26c649684b482d10f91960cc3db683c38b4 (reposimplestore !)
205 deleting data/d3/f/2661d26c649684b482d10f91960cc3db683c38b4 (reposimplestore !)
195 deleting data/d3/f/99fa7136105a15e2045ce3d9152e4837c5349e4d (reposimplestore !)
206 deleting data/d3/f/99fa7136105a15e2045ce3d9152e4837c5349e4d (reposimplestore !)
196 deleting data/d3/f/index (reposimplestore !)
207 deleting data/d3/f/index (reposimplestore !)
197 deleting unwanted files from working copy
208 deleting unwanted files from working copy
198 $ hg log -T '{desc}\n' -r .
209 $ hg log -T '{desc}\n' -r .
199 add d10/f
210 add d10/f
200 Updates to nullid if necessary
211 Updates to nullid if necessary
201 $ hg tracked --addinclude d3 -q
212 $ hg tracked --addinclude d3 -q
202 $ hg co null -q
213 $ hg co null -q
203 $ mkdir d3
214 $ mkdir d3
204 $ echo local change > d3/f
215 $ echo local change > d3/f
205 $ hg add d3/f
216 $ hg add d3/f
206 $ hg ci -m 'local change to d3'
217 $ hg ci -m 'local change to d3'
207 created new head
218 created new head
208 $ hg tracked --removeinclude d3 --force-delete-local-changes
219 $ hg tracked --removeinclude d3 --force-delete-local-changes
209 comparing with ssh://user@dummy/master
220 comparing with ssh://user@dummy/master
210 searching for changes
221 searching for changes
211 looking for local changes to affected paths
222 looking for local changes to affected paths
212 The following changeset(s) or their ancestors have local changes not on the remote:
223 The following changeset(s) or their ancestors have local changes not on the remote:
213 * (glob)
224 * (glob)
214 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
225 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
215 moving unwanted changesets to backup
226 moving unwanted changesets to backup
216 saved backup bundle to $TESTTMP/narrow-local-changes/.hg/strip-backup/*-narrow.hg (glob)
227 saved backup bundle to $TESTTMP/narrow-local-changes/.hg/strip-backup/*-narrow.hg (glob)
217 deleting data/d3/f.i (reporevlogstore !)
228 deleting data/d3/f.i (reporevlogstore !)
218 deleting meta/d3/00manifest.i (tree !)
229 deleting meta/d3/00manifest.i (tree !)
219 deleting data/d3/f/2661d26c649684b482d10f91960cc3db683c38b4 (reposimplestore !)
230 deleting data/d3/f/2661d26c649684b482d10f91960cc3db683c38b4 (reposimplestore !)
220 deleting data/d3/f/5ce0767945cbdbca3b924bb9fbf5143f72ab40ac (reposimplestore !)
231 deleting data/d3/f/5ce0767945cbdbca3b924bb9fbf5143f72ab40ac (reposimplestore !)
221 deleting data/d3/f/index (reposimplestore !)
232 deleting data/d3/f/index (reposimplestore !)
222 deleting unwanted files from working copy
233 deleting unwanted files from working copy
223 $ hg id
234 $ hg id
224 000000000000
235 000000000000
225 $ cd ..
236 $ cd ..
226
237
227 Narrowing doesn't resurrect old commits (unlike what regular `hg strip` does)
238 Narrowing doesn't resurrect old commits (unlike what regular `hg strip` does)
228 $ hg clone --narrow ssh://user@dummy/master narrow-obsmarkers --include d0 --include d3 -q
239 $ hg clone --narrow ssh://user@dummy/master narrow-obsmarkers --include d0 --include d3 -q
229 $ cd narrow-obsmarkers
240 $ cd narrow-obsmarkers
230 $ echo a >> d0/f2
241 $ echo a >> d0/f2
231 $ hg add d0/f2
242 $ hg add d0/f2
232 $ hg ci -m 'modify d0/'
243 $ hg ci -m 'modify d0/'
233 $ echo a >> d3/f2
244 $ echo a >> d3/f2
234 $ hg add d3/f2
245 $ hg add d3/f2
235 $ hg commit --amend -m 'modify d0/ and d3/'
246 $ hg commit --amend -m 'modify d0/ and d3/'
236 $ hg log -T "{rev}: {desc}\n"
247 $ hg log -T "{rev}: {desc}\n"
237 5: modify d0/ and d3/
248 5: modify d0/ and d3/
238 3: add d10/f
249 3: add d10/f
239 2: add d3/f
250 2: add d3/f
240 1: add d2/f
251 1: add d2/f
241 0: add d0/f
252 0: add d0/f
242 $ hg tracked --removeinclude d3 --force-delete-local-changes -q
253 $ hg tracked --removeinclude d3 --force-delete-local-changes -q
243 $ hg log -T "{rev}: {desc}\n"
254 $ hg log -T "{rev}: {desc}\n"
244 3: add d10/f
255 3: add d10/f
245 2: add d3/f
256 2: add d3/f
246 1: add d2/f
257 1: add d2/f
247 0: add d0/f
258 0: add d0/f
248 $ cd ..
259 $ cd ..
249
260
250 Widening doesn't lose bookmarks
261 Widening doesn't lose bookmarks
251 $ hg clone --narrow ssh://user@dummy/master widen-bookmarks --include d0 -q
262 $ hg clone --narrow ssh://user@dummy/master widen-bookmarks --include d0 -q
252 $ cd widen-bookmarks
263 $ cd widen-bookmarks
253 $ hg bookmark my-bookmark
264 $ hg bookmark my-bookmark
254 $ hg log -T "{rev}: {desc} {bookmarks}\n"
265 $ hg log -T "{rev}: {desc} {bookmarks}\n"
255 1: add d10/f my-bookmark
266 1: add d10/f my-bookmark
256 0: add d0/f
267 0: add d0/f
257 $ hg tracked --addinclude d3 -q
268 $ hg tracked --addinclude d3 -q
258 $ hg log -T "{rev}: {desc} {bookmarks}\n"
269 $ hg log -T "{rev}: {desc} {bookmarks}\n"
259 3: add d10/f my-bookmark
270 3: add d10/f my-bookmark
260 2: add d3/f
271 2: add d3/f
261 1: add d2/f
272 1: add d2/f
262 0: add d0/f
273 0: add d0/f
263 $ cd ..
274 $ cd ..
264
275
265 Can remove last include, making repo empty
276 Can remove last include, making repo empty
266 $ hg clone --narrow ssh://user@dummy/master narrow-empty --include d0 -r 5
277 $ hg clone --narrow ssh://user@dummy/master narrow-empty --include d0 -r 5
267 adding changesets
278 adding changesets
268 adding manifests
279 adding manifests
269 adding file changes
280 adding file changes
270 added 2 changesets with 1 changes to 1 files
281 added 2 changesets with 1 changes to 1 files
271 new changesets *:* (glob)
282 new changesets *:* (glob)
272 updating to branch default
283 updating to branch default
273 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
284 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
274 $ cd narrow-empty
285 $ cd narrow-empty
275 $ hg tracked --removeinclude d0
286 $ hg tracked --removeinclude d0
276 comparing with ssh://user@dummy/master
287 comparing with ssh://user@dummy/master
277 searching for changes
288 searching for changes
278 looking for local changes to affected paths
289 looking for local changes to affected paths
279 deleting data/d0/f.i (reporevlogstore !)
290 deleting data/d0/f.i (reporevlogstore !)
280 deleting meta/d0/00manifest.i (tree !)
291 deleting meta/d0/00manifest.i (tree !)
281 deleting data/d0/f/362fef284ce2ca02aecc8de6d5e8a1c3af0556fe (reposimplestore !)
292 deleting data/d0/f/362fef284ce2ca02aecc8de6d5e8a1c3af0556fe (reposimplestore !)
282 deleting data/d0/f/index (reposimplestore !)
293 deleting data/d0/f/index (reposimplestore !)
283 deleting unwanted files from working copy
294 deleting unwanted files from working copy
284 $ hg tracked
295 $ hg tracked
285 $ hg files
296 $ hg files
286 [1]
297 [1]
287 $ test -d d0
298 $ test -d d0
288 [1]
299 [1]
289 Do some work in the empty clone
300 Do some work in the empty clone
290 $ hg diff --change .
301 $ hg diff --change .
291 $ hg branch foo
302 $ hg branch foo
292 marked working directory as branch foo
303 marked working directory as branch foo
293 (branches are permanent and global, did you want a bookmark?)
304 (branches are permanent and global, did you want a bookmark?)
294 $ hg ci -m empty
305 $ hg ci -m empty
295 $ hg log -T "{rev}: {desc} {outsidenarrow}\n"
306 $ hg log -T "{rev}: {desc} {outsidenarrow}\n"
296 2: empty
307 2: empty
297 1: add d5/f outsidenarrow
308 1: add d5/f outsidenarrow
298 0: add d0/f outsidenarrow
309 0: add d0/f outsidenarrow
299 $ hg pull -q
310 $ hg pull -q
300 Can widen the empty clone
311 Can widen the empty clone
301 $ hg tracked --addinclude d0
312 $ hg tracked --addinclude d0
302 comparing with ssh://user@dummy/master
313 comparing with ssh://user@dummy/master
303 searching for changes
314 searching for changes
304 saved backup bundle to $TESTTMP/narrow-empty/.hg/strip-backup/*-widen.hg (glob)
315 saved backup bundle to $TESTTMP/narrow-empty/.hg/strip-backup/*-widen.hg (glob)
305 adding changesets
316 adding changesets
306 adding manifests
317 adding manifests
307 adding file changes
318 adding file changes
308 added 4 changesets with 1 changes to 1 files (+1 heads)
319 added 4 changesets with 1 changes to 1 files (+1 heads)
309 $ hg tracked
320 $ hg tracked
310 I path:d0
321 I path:d0
311 $ hg files
322 $ hg files
312 d0/f
323 d0/f
313 $ find *
324 $ find *
314 d0
325 d0
315 d0/f
326 d0/f
316 $ cd ..
327 $ cd ..
317
328
318 TODO(martinvonz): test including e.g. d3/g and then removing it once
329 TODO(martinvonz): test including e.g. d3/g and then removing it once
319 https://bitbucket.org/Google/narrowhg/issues/6 is fixed
330 https://bitbucket.org/Google/narrowhg/issues/6 is fixed
320
331
321 $ hg clone --narrow ssh://user@dummy/master narrow --include d0 --include d3 --include d6 --include d9
332 $ hg clone --narrow ssh://user@dummy/master narrow --include d0 --include d3 --include d6 --include d9
322 requesting all changes
333 requesting all changes
323 adding changesets
334 adding changesets
324 adding manifests
335 adding manifests
325 adding file changes
336 adding file changes
326 added 8 changesets with 4 changes to 4 files
337 added 8 changesets with 4 changes to 4 files
327 new changesets *:* (glob)
338 new changesets *:* (glob)
328 updating to branch default
339 updating to branch default
329 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
340 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
330 $ cd narrow
341 $ cd narrow
331 $ hg tracked
342 $ hg tracked
332 I path:d0
343 I path:d0
333 I path:d3
344 I path:d3
334 I path:d6
345 I path:d6
335 I path:d9
346 I path:d9
336 $ hg tracked --removeinclude d6
347 $ hg tracked --removeinclude d6
337 comparing with ssh://user@dummy/master
348 comparing with ssh://user@dummy/master
338 searching for changes
349 searching for changes
339 looking for local changes to affected paths
350 looking for local changes to affected paths
340 deleting data/d6/f.i (reporevlogstore !)
351 deleting data/d6/f.i (reporevlogstore !)
341 deleting meta/d6/00manifest.i (tree !)
352 deleting meta/d6/00manifest.i (tree !)
342 deleting data/d6/f/7339d30678f451ac8c3f38753beeb4cf2e1655c7 (reposimplestore !)
353 deleting data/d6/f/7339d30678f451ac8c3f38753beeb4cf2e1655c7 (reposimplestore !)
343 deleting data/d6/f/index (reposimplestore !)
354 deleting data/d6/f/index (reposimplestore !)
344 deleting unwanted files from working copy
355 deleting unwanted files from working copy
345 $ hg tracked
356 $ hg tracked
346 I path:d0
357 I path:d0
347 I path:d3
358 I path:d3
348 I path:d9
359 I path:d9
349 #if repofncache
360 #if repofncache
350 $ hg debugrebuildfncache
361 $ hg debugrebuildfncache
351 fncache already up to date
362 fncache already up to date
352 #endif
363 #endif
353 $ find *
364 $ find *
354 d0
365 d0
355 d0/f
366 d0/f
356 d3
367 d3
357 d3/f
368 d3/f
358 d9
369 d9
359 d9/f
370 d9/f
360 $ hg verify -q
371 $ hg verify -q
361 $ hg tracked --addexclude d3/f
372 $ hg tracked --addexclude d3/f
362 comparing with ssh://user@dummy/master
373 comparing with ssh://user@dummy/master
363 searching for changes
374 searching for changes
364 looking for local changes to affected paths
375 looking for local changes to affected paths
365 deleting data/d3/f.i (reporevlogstore !)
376 deleting data/d3/f.i (reporevlogstore !)
366 deleting data/d3/f/2661d26c649684b482d10f91960cc3db683c38b4 (reposimplestore !)
377 deleting data/d3/f/2661d26c649684b482d10f91960cc3db683c38b4 (reposimplestore !)
367 deleting data/d3/f/index (reposimplestore !)
378 deleting data/d3/f/index (reposimplestore !)
368 deleting unwanted files from working copy
379 deleting unwanted files from working copy
369 $ hg tracked
380 $ hg tracked
370 I path:d0
381 I path:d0
371 I path:d3
382 I path:d3
372 I path:d9
383 I path:d9
373 X path:d3/f
384 X path:d3/f
374 #if repofncache
385 #if repofncache
375 $ hg debugrebuildfncache
386 $ hg debugrebuildfncache
376 fncache already up to date
387 fncache already up to date
377 #endif
388 #endif
378 $ find *
389 $ find *
379 d0
390 d0
380 d0/f
391 d0/f
381 d9
392 d9
382 d9/f
393 d9/f
383 $ hg verify -q
394 $ hg verify -q
384 $ hg tracked --addexclude d0
395 $ hg tracked --addexclude d0
385 comparing with ssh://user@dummy/master
396 comparing with ssh://user@dummy/master
386 searching for changes
397 searching for changes
387 looking for local changes to affected paths
398 looking for local changes to affected paths
388 deleting data/d0/f.i (reporevlogstore !)
399 deleting data/d0/f.i (reporevlogstore !)
389 deleting meta/d0/00manifest.i (tree !)
400 deleting meta/d0/00manifest.i (tree !)
390 deleting data/d0/f/362fef284ce2ca02aecc8de6d5e8a1c3af0556fe (reposimplestore !)
401 deleting data/d0/f/362fef284ce2ca02aecc8de6d5e8a1c3af0556fe (reposimplestore !)
391 deleting data/d0/f/index (reposimplestore !)
402 deleting data/d0/f/index (reposimplestore !)
392 deleting unwanted files from working copy
403 deleting unwanted files from working copy
393 $ hg tracked
404 $ hg tracked
394 I path:d3
405 I path:d3
395 I path:d9
406 I path:d9
396 X path:d0
407 X path:d0
397 X path:d3/f
408 X path:d3/f
398 #if repofncache
409 #if repofncache
399 $ hg debugrebuildfncache
410 $ hg debugrebuildfncache
400 fncache already up to date
411 fncache already up to date
401 #endif
412 #endif
402 $ find *
413 $ find *
403 d9
414 d9
404 d9/f
415 d9/f
405
416
406 Make a 15 of changes to d9 to test the path without --verbose
417 Make a 15 of changes to d9 to test the path without --verbose
407 (Note: using regexes instead of "* (glob)" because if the test fails, it
418 (Note: using regexes instead of "* (glob)" because if the test fails, it
408 produces more sensible diffs)
419 produces more sensible diffs)
409 $ hg tracked
420 $ hg tracked
410 I path:d3
421 I path:d3
411 I path:d9
422 I path:d9
412 X path:d0
423 X path:d0
413 X path:d3/f
424 X path:d3/f
414 $ for x in `$TESTDIR/seq.py 1 15`
425 $ for x in `$TESTDIR/seq.py 1 15`
415 > do
426 > do
416 > echo local change >> d9/f
427 > echo local change >> d9/f
417 > hg commit -m "change $x to d9/f"
428 > hg commit -m "change $x to d9/f"
418 > done
429 > done
419 $ hg tracked --removeinclude d9
430 $ hg tracked --removeinclude d9
420 comparing with ssh://user@dummy/master
431 comparing with ssh://user@dummy/master
421 searching for changes
432 searching for changes
422 looking for local changes to affected paths
433 looking for local changes to affected paths
423 The following changeset(s) or their ancestors have local changes not on the remote:
434 The following changeset(s) or their ancestors have local changes not on the remote:
424 ^[0-9a-f]{12}$ (re)
435 ^[0-9a-f]{12}$ (re)
425 ^[0-9a-f]{12}$ (re)
436 ^[0-9a-f]{12}$ (re)
426 ^[0-9a-f]{12}$ (re)
437 ^[0-9a-f]{12}$ (re)
427 ^[0-9a-f]{12}$ (re)
438 ^[0-9a-f]{12}$ (re)
428 ^[0-9a-f]{12}$ (re)
439 ^[0-9a-f]{12}$ (re)
429 ^[0-9a-f]{12}$ (re)
440 ^[0-9a-f]{12}$ (re)
430 ^[0-9a-f]{12}$ (re)
441 ^[0-9a-f]{12}$ (re)
431 ^[0-9a-f]{12}$ (re)
442 ^[0-9a-f]{12}$ (re)
432 ^[0-9a-f]{12}$ (re)
443 ^[0-9a-f]{12}$ (re)
433 ^[0-9a-f]{12}$ (re)
444 ^[0-9a-f]{12}$ (re)
434 ...and 5 more, use --verbose to list all
445 ...and 5 more, use --verbose to list all
435 abort: local changes found
446 abort: local changes found
436 (use --force-delete-local-changes to ignore)
447 (use --force-delete-local-changes to ignore)
437 [20]
448 [20]
438 Now test it *with* verbose.
449 Now test it *with* verbose.
439 $ hg tracked --removeinclude d9 --verbose
450 $ hg tracked --removeinclude d9 --verbose
440 comparing with ssh://user@dummy/master
451 comparing with ssh://user@dummy/master
441 searching for changes
452 searching for changes
442 looking for local changes to affected paths
453 looking for local changes to affected paths
443 The following changeset(s) or their ancestors have local changes not on the remote:
454 The following changeset(s) or their ancestors have local changes not on the remote:
444 ^[0-9a-f]{12}$ (re)
455 ^[0-9a-f]{12}$ (re)
445 ^[0-9a-f]{12}$ (re)
456 ^[0-9a-f]{12}$ (re)
446 ^[0-9a-f]{12}$ (re)
457 ^[0-9a-f]{12}$ (re)
447 ^[0-9a-f]{12}$ (re)
458 ^[0-9a-f]{12}$ (re)
448 ^[0-9a-f]{12}$ (re)
459 ^[0-9a-f]{12}$ (re)
449 ^[0-9a-f]{12}$ (re)
460 ^[0-9a-f]{12}$ (re)
450 ^[0-9a-f]{12}$ (re)
461 ^[0-9a-f]{12}$ (re)
451 ^[0-9a-f]{12}$ (re)
462 ^[0-9a-f]{12}$ (re)
452 ^[0-9a-f]{12}$ (re)
463 ^[0-9a-f]{12}$ (re)
453 ^[0-9a-f]{12}$ (re)
464 ^[0-9a-f]{12}$ (re)
454 ^[0-9a-f]{12}$ (re)
465 ^[0-9a-f]{12}$ (re)
455 ^[0-9a-f]{12}$ (re)
466 ^[0-9a-f]{12}$ (re)
456 ^[0-9a-f]{12}$ (re)
467 ^[0-9a-f]{12}$ (re)
457 ^[0-9a-f]{12}$ (re)
468 ^[0-9a-f]{12}$ (re)
458 ^[0-9a-f]{12}$ (re)
469 ^[0-9a-f]{12}$ (re)
459 abort: local changes found
470 abort: local changes found
460 (use --force-delete-local-changes to ignore)
471 (use --force-delete-local-changes to ignore)
461 [20]
472 [20]
462 $ cd ..
473 $ cd ..
463
474
464 Test --auto-remove-includes
475 Test --auto-remove-includes
465 $ hg clone --narrow ssh://user@dummy/master narrow-auto-remove -q \
476 $ hg clone --narrow ssh://user@dummy/master narrow-auto-remove -q \
466 > --include d0 --include d1 --include d2
477 > --include d0 --include d1 --include d2
467 $ cd narrow-auto-remove
478 $ cd narrow-auto-remove
468 $ echo a >> d0/f
479 $ echo a >> d0/f
469 $ hg ci -m 'local change to d0'
480 $ hg ci -m 'local change to d0'
470 $ hg co '.^'
481 $ hg co '.^'
471 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
482 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
472 $ echo a >> d1/f
483 $ echo a >> d1/f
473 $ hg ci -m 'local change to d1'
484 $ hg ci -m 'local change to d1'
474 created new head
485 created new head
475 $ hg debugobsolete $(hg log -T '{node}' -r 'desc("local change to d0")')
486 $ hg debugobsolete $(hg log -T '{node}' -r 'desc("local change to d0")')
476 1 new obsolescence markers
487 1 new obsolescence markers
477 obsoleted 1 changesets
488 obsoleted 1 changesets
478 $ echo n | hg tracked --auto-remove-includes --config ui.interactive=yes
489 $ echo n | hg tracked --auto-remove-includes --config ui.interactive=yes
479 comparing with ssh://user@dummy/master
490 comparing with ssh://user@dummy/master
480 searching for changes
491 searching for changes
481 looking for unused includes to remove
492 looking for unused includes to remove
482 path:d0
493 path:d0
483 path:d2
494 path:d2
484 remove these unused includes (yn)? n
495 remove these unused includes (yn)? n
485 $ hg tracked --auto-remove-includes
496 $ hg tracked --auto-remove-includes
486 comparing with ssh://user@dummy/master
497 comparing with ssh://user@dummy/master
487 searching for changes
498 searching for changes
488 looking for unused includes to remove
499 looking for unused includes to remove
489 path:d0
500 path:d0
490 path:d2
501 path:d2
491 remove these unused includes (yn)? y
502 remove these unused includes (yn)? y
492 looking for local changes to affected paths
503 looking for local changes to affected paths
493 moving unwanted changesets to backup
504 moving unwanted changesets to backup
494 saved backup bundle to $TESTTMP/narrow-auto-remove/.hg/strip-backup/*-narrow.hg (glob)
505 saved backup bundle to $TESTTMP/narrow-auto-remove/.hg/strip-backup/*-narrow.hg (glob)
495 deleting data/d0/f.i
506 deleting data/d0/f.i
496 deleting data/d2/f.i
507 deleting data/d2/f.i
497 deleting meta/d0/00manifest.i (tree !)
508 deleting meta/d0/00manifest.i (tree !)
498 deleting meta/d2/00manifest.i (tree !)
509 deleting meta/d2/00manifest.i (tree !)
499 deleting unwanted files from working copy
510 deleting unwanted files from working copy
500 $ hg tracked
511 $ hg tracked
501 I path:d1
512 I path:d1
502 $ hg files
513 $ hg files
503 d1/f
514 d1/f
504 $ hg tracked --auto-remove-includes
515 $ hg tracked --auto-remove-includes
505 comparing with ssh://user@dummy/master
516 comparing with ssh://user@dummy/master
506 searching for changes
517 searching for changes
507 looking for unused includes to remove
518 looking for unused includes to remove
508 found no unused includes
519 found no unused includes
509 Test --no-backup
520 Test --no-backup
510 $ hg tracked --addinclude d0 --addinclude d2 -q
521 $ hg tracked --addinclude d0 --addinclude d2 -q
511 $ hg unbundle .hg/strip-backup/*-narrow.hg -q
522 $ hg unbundle .hg/strip-backup/*-narrow.hg -q
512 $ rm .hg/strip-backup/*
523 $ rm .hg/strip-backup/*
513 $ hg tracked --auto-remove-includes --no-backup
524 $ hg tracked --auto-remove-includes --no-backup
514 comparing with ssh://user@dummy/master
525 comparing with ssh://user@dummy/master
515 searching for changes
526 searching for changes
516 looking for unused includes to remove
527 looking for unused includes to remove
517 path:d0
528 path:d0
518 path:d2
529 path:d2
519 remove these unused includes (yn)? y
530 remove these unused includes (yn)? y
520 looking for local changes to affected paths
531 looking for local changes to affected paths
521 deleting unwanted changesets
532 deleting unwanted changesets
522 deleting data/d0/f.i
533 deleting data/d0/f.i
523 deleting data/d2/f.i
534 deleting data/d2/f.i
524 deleting meta/d0/00manifest.i (tree !)
535 deleting meta/d0/00manifest.i (tree !)
525 deleting meta/d2/00manifest.i (tree !)
536 deleting meta/d2/00manifest.i (tree !)
526 deleting unwanted files from working copy
537 deleting unwanted files from working copy
527 $ ls .hg/strip-backup/
538 $ ls .hg/strip-backup/
528
539
529
540
530 Test removing include while concurrently modifying file in that path
541 Test removing include while concurrently modifying file in that path
531 $ hg clone --narrow ssh://user@dummy/master narrow-concurrent-modify -q \
542 $ hg clone --narrow ssh://user@dummy/master narrow-concurrent-modify -q \
532 > --include d0 --include d1
543 > --include d0 --include d1
533 $ cd narrow-concurrent-modify
544 $ cd narrow-concurrent-modify
534 $ hg --config 'hooks.pretxnopen = echo modified >> d0/f' tracked --removeinclude d0
545 $ hg --config 'hooks.pretxnopen = echo modified >> d0/f' tracked --removeinclude d0
535 comparing with ssh://user@dummy/master
546 comparing with ssh://user@dummy/master
536 searching for changes
547 searching for changes
537 looking for local changes to affected paths
548 looking for local changes to affected paths
538 deleting data/d0/f.i
549 deleting data/d0/f.i
539 deleting meta/d0/00manifest.i (tree !)
550 deleting meta/d0/00manifest.i (tree !)
540 deleting unwanted files from working copy
551 deleting unwanted files from working copy
541 not deleting possibly dirty file d0/f
552 not deleting possibly dirty file d0/f
General Comments 0
You need to be logged in to leave comments. Login now