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