##// END OF EJS Templates
dirstate-v2: Add `hg debugupgraderepo` command support...
Simon Sapin -
r48111:a43d256c default
parent child Browse files
Show More
@@ -1,1979 +1,1980 b''
1 # dirstate.py - working directory tracking for mercurial
1 # dirstate.py - working directory tracking for mercurial
2 #
2 #
3 # Copyright 2005-2007 Olivia Mackall <olivia@selenic.com>
3 # Copyright 2005-2007 Olivia Mackall <olivia@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 from __future__ import absolute_import
8 from __future__ import absolute_import
9
9
10 import collections
10 import collections
11 import contextlib
11 import contextlib
12 import errno
12 import errno
13 import os
13 import os
14 import stat
14 import stat
15
15
16 from .i18n import _
16 from .i18n import _
17 from .pycompat import delattr
17 from .pycompat import delattr
18
18
19 from hgdemandimport import tracing
19 from hgdemandimport import tracing
20
20
21 from . import (
21 from . import (
22 encoding,
22 encoding,
23 error,
23 error,
24 match as matchmod,
24 match as matchmod,
25 pathutil,
25 pathutil,
26 policy,
26 policy,
27 pycompat,
27 pycompat,
28 scmutil,
28 scmutil,
29 sparse,
29 sparse,
30 txnutil,
30 txnutil,
31 util,
31 util,
32 )
32 )
33
33
34 from .interfaces import (
34 from .interfaces import (
35 dirstate as intdirstate,
35 dirstate as intdirstate,
36 util as interfaceutil,
36 util as interfaceutil,
37 )
37 )
38
38
39 parsers = policy.importmod('parsers')
39 parsers = policy.importmod('parsers')
40 rustmod = policy.importrust('dirstate')
40 rustmod = policy.importrust('dirstate')
41
41
42 SUPPORTS_DIRSTATE_V2 = rustmod is not None
42 SUPPORTS_DIRSTATE_V2 = rustmod is not None
43
43
44 propertycache = util.propertycache
44 propertycache = util.propertycache
45 filecache = scmutil.filecache
45 filecache = scmutil.filecache
46 _rangemask = 0x7FFFFFFF
46 _rangemask = 0x7FFFFFFF
47
47
48 dirstatetuple = parsers.dirstatetuple
48 dirstatetuple = parsers.dirstatetuple
49
49
50
50
51 class repocache(filecache):
51 class repocache(filecache):
52 """filecache for files in .hg/"""
52 """filecache for files in .hg/"""
53
53
54 def join(self, obj, fname):
54 def join(self, obj, fname):
55 return obj._opener.join(fname)
55 return obj._opener.join(fname)
56
56
57
57
58 class rootcache(filecache):
58 class rootcache(filecache):
59 """filecache for files in the repository root"""
59 """filecache for files in the repository root"""
60
60
61 def join(self, obj, fname):
61 def join(self, obj, fname):
62 return obj._join(fname)
62 return obj._join(fname)
63
63
64
64
65 def _getfsnow(vfs):
65 def _getfsnow(vfs):
66 '''Get "now" timestamp on filesystem'''
66 '''Get "now" timestamp on filesystem'''
67 tmpfd, tmpname = vfs.mkstemp()
67 tmpfd, tmpname = vfs.mkstemp()
68 try:
68 try:
69 return os.fstat(tmpfd)[stat.ST_MTIME]
69 return os.fstat(tmpfd)[stat.ST_MTIME]
70 finally:
70 finally:
71 os.close(tmpfd)
71 os.close(tmpfd)
72 vfs.unlink(tmpname)
72 vfs.unlink(tmpname)
73
73
74
74
75 @interfaceutil.implementer(intdirstate.idirstate)
75 @interfaceutil.implementer(intdirstate.idirstate)
76 class dirstate(object):
76 class dirstate(object):
77 def __init__(
77 def __init__(
78 self,
78 self,
79 opener,
79 opener,
80 ui,
80 ui,
81 root,
81 root,
82 validate,
82 validate,
83 sparsematchfn,
83 sparsematchfn,
84 nodeconstants,
84 nodeconstants,
85 use_dirstate_v2,
85 use_dirstate_v2,
86 ):
86 ):
87 """Create a new dirstate object.
87 """Create a new dirstate object.
88
88
89 opener is an open()-like callable that can be used to open the
89 opener is an open()-like callable that can be used to open the
90 dirstate file; root is the root of the directory tracked by
90 dirstate file; root is the root of the directory tracked by
91 the dirstate.
91 the dirstate.
92 """
92 """
93 self._use_dirstate_v2 = use_dirstate_v2
93 self._use_dirstate_v2 = use_dirstate_v2
94 self._nodeconstants = nodeconstants
94 self._nodeconstants = nodeconstants
95 self._opener = opener
95 self._opener = opener
96 self._validate = validate
96 self._validate = validate
97 self._root = root
97 self._root = root
98 self._sparsematchfn = sparsematchfn
98 self._sparsematchfn = sparsematchfn
99 # ntpath.join(root, '') of Python 2.7.9 does not add sep if root is
99 # ntpath.join(root, '') of Python 2.7.9 does not add sep if root is
100 # UNC path pointing to root share (issue4557)
100 # UNC path pointing to root share (issue4557)
101 self._rootdir = pathutil.normasprefix(root)
101 self._rootdir = pathutil.normasprefix(root)
102 self._dirty = False
102 self._dirty = False
103 self._lastnormaltime = 0
103 self._lastnormaltime = 0
104 self._ui = ui
104 self._ui = ui
105 self._filecache = {}
105 self._filecache = {}
106 self._parentwriters = 0
106 self._parentwriters = 0
107 self._filename = b'dirstate'
107 self._filename = b'dirstate'
108 self._pendingfilename = b'%s.pending' % self._filename
108 self._pendingfilename = b'%s.pending' % self._filename
109 self._plchangecallbacks = {}
109 self._plchangecallbacks = {}
110 self._origpl = None
110 self._origpl = None
111 self._updatedfiles = set()
111 self._updatedfiles = set()
112 self._mapcls = dirstatemap
112 self._mapcls = dirstatemap
113 # Access and cache cwd early, so we don't access it for the first time
113 # Access and cache cwd early, so we don't access it for the first time
114 # after a working-copy update caused it to not exist (accessing it then
114 # after a working-copy update caused it to not exist (accessing it then
115 # raises an exception).
115 # raises an exception).
116 self._cwd
116 self._cwd
117
117
118 def prefetch_parents(self):
118 def prefetch_parents(self):
119 """make sure the parents are loaded
119 """make sure the parents are loaded
120
120
121 Used to avoid a race condition.
121 Used to avoid a race condition.
122 """
122 """
123 self._pl
123 self._pl
124
124
125 @contextlib.contextmanager
125 @contextlib.contextmanager
126 def parentchange(self):
126 def parentchange(self):
127 """Context manager for handling dirstate parents.
127 """Context manager for handling dirstate parents.
128
128
129 If an exception occurs in the scope of the context manager,
129 If an exception occurs in the scope of the context manager,
130 the incoherent dirstate won't be written when wlock is
130 the incoherent dirstate won't be written when wlock is
131 released.
131 released.
132 """
132 """
133 self._parentwriters += 1
133 self._parentwriters += 1
134 yield
134 yield
135 # Typically we want the "undo" step of a context manager in a
135 # Typically we want the "undo" step of a context manager in a
136 # finally block so it happens even when an exception
136 # finally block so it happens even when an exception
137 # occurs. In this case, however, we only want to decrement
137 # occurs. In this case, however, we only want to decrement
138 # parentwriters if the code in the with statement exits
138 # parentwriters if the code in the with statement exits
139 # normally, so we don't have a try/finally here on purpose.
139 # normally, so we don't have a try/finally here on purpose.
140 self._parentwriters -= 1
140 self._parentwriters -= 1
141
141
142 def pendingparentchange(self):
142 def pendingparentchange(self):
143 """Returns true if the dirstate is in the middle of a set of changes
143 """Returns true if the dirstate is in the middle of a set of changes
144 that modify the dirstate parent.
144 that modify the dirstate parent.
145 """
145 """
146 return self._parentwriters > 0
146 return self._parentwriters > 0
147
147
148 @propertycache
148 @propertycache
149 def _map(self):
149 def _map(self):
150 """Return the dirstate contents (see documentation for dirstatemap)."""
150 """Return the dirstate contents (see documentation for dirstatemap)."""
151 self._map = self._mapcls(
151 self._map = self._mapcls(
152 self._ui,
152 self._ui,
153 self._opener,
153 self._opener,
154 self._root,
154 self._root,
155 self._nodeconstants,
155 self._nodeconstants,
156 self._use_dirstate_v2,
156 self._use_dirstate_v2,
157 )
157 )
158 return self._map
158 return self._map
159
159
160 @property
160 @property
161 def _sparsematcher(self):
161 def _sparsematcher(self):
162 """The matcher for the sparse checkout.
162 """The matcher for the sparse checkout.
163
163
164 The working directory may not include every file from a manifest. The
164 The working directory may not include every file from a manifest. The
165 matcher obtained by this property will match a path if it is to be
165 matcher obtained by this property will match a path if it is to be
166 included in the working directory.
166 included in the working directory.
167 """
167 """
168 # TODO there is potential to cache this property. For now, the matcher
168 # TODO there is potential to cache this property. For now, the matcher
169 # is resolved on every access. (But the called function does use a
169 # is resolved on every access. (But the called function does use a
170 # cache to keep the lookup fast.)
170 # cache to keep the lookup fast.)
171 return self._sparsematchfn()
171 return self._sparsematchfn()
172
172
173 @repocache(b'branch')
173 @repocache(b'branch')
174 def _branch(self):
174 def _branch(self):
175 try:
175 try:
176 return self._opener.read(b"branch").strip() or b"default"
176 return self._opener.read(b"branch").strip() or b"default"
177 except IOError as inst:
177 except IOError as inst:
178 if inst.errno != errno.ENOENT:
178 if inst.errno != errno.ENOENT:
179 raise
179 raise
180 return b"default"
180 return b"default"
181
181
182 @property
182 @property
183 def _pl(self):
183 def _pl(self):
184 return self._map.parents()
184 return self._map.parents()
185
185
186 def hasdir(self, d):
186 def hasdir(self, d):
187 return self._map.hastrackeddir(d)
187 return self._map.hastrackeddir(d)
188
188
189 @rootcache(b'.hgignore')
189 @rootcache(b'.hgignore')
190 def _ignore(self):
190 def _ignore(self):
191 files = self._ignorefiles()
191 files = self._ignorefiles()
192 if not files:
192 if not files:
193 return matchmod.never()
193 return matchmod.never()
194
194
195 pats = [b'include:%s' % f for f in files]
195 pats = [b'include:%s' % f for f in files]
196 return matchmod.match(self._root, b'', [], pats, warn=self._ui.warn)
196 return matchmod.match(self._root, b'', [], pats, warn=self._ui.warn)
197
197
198 @propertycache
198 @propertycache
199 def _slash(self):
199 def _slash(self):
200 return self._ui.configbool(b'ui', b'slash') and pycompat.ossep != b'/'
200 return self._ui.configbool(b'ui', b'slash') and pycompat.ossep != b'/'
201
201
202 @propertycache
202 @propertycache
203 def _checklink(self):
203 def _checklink(self):
204 return util.checklink(self._root)
204 return util.checklink(self._root)
205
205
206 @propertycache
206 @propertycache
207 def _checkexec(self):
207 def _checkexec(self):
208 return bool(util.checkexec(self._root))
208 return bool(util.checkexec(self._root))
209
209
210 @propertycache
210 @propertycache
211 def _checkcase(self):
211 def _checkcase(self):
212 return not util.fscasesensitive(self._join(b'.hg'))
212 return not util.fscasesensitive(self._join(b'.hg'))
213
213
214 def _join(self, f):
214 def _join(self, f):
215 # much faster than os.path.join()
215 # much faster than os.path.join()
216 # it's safe because f is always a relative path
216 # it's safe because f is always a relative path
217 return self._rootdir + f
217 return self._rootdir + f
218
218
219 def flagfunc(self, buildfallback):
219 def flagfunc(self, buildfallback):
220 if self._checklink and self._checkexec:
220 if self._checklink and self._checkexec:
221
221
222 def f(x):
222 def f(x):
223 try:
223 try:
224 st = os.lstat(self._join(x))
224 st = os.lstat(self._join(x))
225 if util.statislink(st):
225 if util.statislink(st):
226 return b'l'
226 return b'l'
227 if util.statisexec(st):
227 if util.statisexec(st):
228 return b'x'
228 return b'x'
229 except OSError:
229 except OSError:
230 pass
230 pass
231 return b''
231 return b''
232
232
233 return f
233 return f
234
234
235 fallback = buildfallback()
235 fallback = buildfallback()
236 if self._checklink:
236 if self._checklink:
237
237
238 def f(x):
238 def f(x):
239 if os.path.islink(self._join(x)):
239 if os.path.islink(self._join(x)):
240 return b'l'
240 return b'l'
241 if b'x' in fallback(x):
241 if b'x' in fallback(x):
242 return b'x'
242 return b'x'
243 return b''
243 return b''
244
244
245 return f
245 return f
246 if self._checkexec:
246 if self._checkexec:
247
247
248 def f(x):
248 def f(x):
249 if b'l' in fallback(x):
249 if b'l' in fallback(x):
250 return b'l'
250 return b'l'
251 if util.isexec(self._join(x)):
251 if util.isexec(self._join(x)):
252 return b'x'
252 return b'x'
253 return b''
253 return b''
254
254
255 return f
255 return f
256 else:
256 else:
257 return fallback
257 return fallback
258
258
259 @propertycache
259 @propertycache
260 def _cwd(self):
260 def _cwd(self):
261 # internal config: ui.forcecwd
261 # internal config: ui.forcecwd
262 forcecwd = self._ui.config(b'ui', b'forcecwd')
262 forcecwd = self._ui.config(b'ui', b'forcecwd')
263 if forcecwd:
263 if forcecwd:
264 return forcecwd
264 return forcecwd
265 return encoding.getcwd()
265 return encoding.getcwd()
266
266
267 def getcwd(self):
267 def getcwd(self):
268 """Return the path from which a canonical path is calculated.
268 """Return the path from which a canonical path is calculated.
269
269
270 This path should be used to resolve file patterns or to convert
270 This path should be used to resolve file patterns or to convert
271 canonical paths back to file paths for display. It shouldn't be
271 canonical paths back to file paths for display. It shouldn't be
272 used to get real file paths. Use vfs functions instead.
272 used to get real file paths. Use vfs functions instead.
273 """
273 """
274 cwd = self._cwd
274 cwd = self._cwd
275 if cwd == self._root:
275 if cwd == self._root:
276 return b''
276 return b''
277 # self._root ends with a path separator if self._root is '/' or 'C:\'
277 # self._root ends with a path separator if self._root is '/' or 'C:\'
278 rootsep = self._root
278 rootsep = self._root
279 if not util.endswithsep(rootsep):
279 if not util.endswithsep(rootsep):
280 rootsep += pycompat.ossep
280 rootsep += pycompat.ossep
281 if cwd.startswith(rootsep):
281 if cwd.startswith(rootsep):
282 return cwd[len(rootsep) :]
282 return cwd[len(rootsep) :]
283 else:
283 else:
284 # we're outside the repo. return an absolute path.
284 # we're outside the repo. return an absolute path.
285 return cwd
285 return cwd
286
286
287 def pathto(self, f, cwd=None):
287 def pathto(self, f, cwd=None):
288 if cwd is None:
288 if cwd is None:
289 cwd = self.getcwd()
289 cwd = self.getcwd()
290 path = util.pathto(self._root, cwd, f)
290 path = util.pathto(self._root, cwd, f)
291 if self._slash:
291 if self._slash:
292 return util.pconvert(path)
292 return util.pconvert(path)
293 return path
293 return path
294
294
295 def __getitem__(self, key):
295 def __getitem__(self, key):
296 """Return the current state of key (a filename) in the dirstate.
296 """Return the current state of key (a filename) in the dirstate.
297
297
298 States are:
298 States are:
299 n normal
299 n normal
300 m needs merging
300 m needs merging
301 r marked for removal
301 r marked for removal
302 a marked for addition
302 a marked for addition
303 ? not tracked
303 ? not tracked
304 """
304 """
305 return self._map.get(key, (b"?",))[0]
305 return self._map.get(key, (b"?",))[0]
306
306
307 def __contains__(self, key):
307 def __contains__(self, key):
308 return key in self._map
308 return key in self._map
309
309
310 def __iter__(self):
310 def __iter__(self):
311 return iter(sorted(self._map))
311 return iter(sorted(self._map))
312
312
313 def items(self):
313 def items(self):
314 return pycompat.iteritems(self._map)
314 return pycompat.iteritems(self._map)
315
315
316 iteritems = items
316 iteritems = items
317
317
318 def parents(self):
318 def parents(self):
319 return [self._validate(p) for p in self._pl]
319 return [self._validate(p) for p in self._pl]
320
320
321 def p1(self):
321 def p1(self):
322 return self._validate(self._pl[0])
322 return self._validate(self._pl[0])
323
323
324 def p2(self):
324 def p2(self):
325 return self._validate(self._pl[1])
325 return self._validate(self._pl[1])
326
326
327 def branch(self):
327 def branch(self):
328 return encoding.tolocal(self._branch)
328 return encoding.tolocal(self._branch)
329
329
330 def setparents(self, p1, p2=None):
330 def setparents(self, p1, p2=None):
331 """Set dirstate parents to p1 and p2.
331 """Set dirstate parents to p1 and p2.
332
332
333 When moving from two parents to one, 'm' merged entries a
333 When moving from two parents to one, 'm' merged entries a
334 adjusted to normal and previous copy records discarded and
334 adjusted to normal and previous copy records discarded and
335 returned by the call.
335 returned by the call.
336
336
337 See localrepo.setparents()
337 See localrepo.setparents()
338 """
338 """
339 if p2 is None:
339 if p2 is None:
340 p2 = self._nodeconstants.nullid
340 p2 = self._nodeconstants.nullid
341 if self._parentwriters == 0:
341 if self._parentwriters == 0:
342 raise ValueError(
342 raise ValueError(
343 b"cannot set dirstate parent outside of "
343 b"cannot set dirstate parent outside of "
344 b"dirstate.parentchange context manager"
344 b"dirstate.parentchange context manager"
345 )
345 )
346
346
347 self._dirty = True
347 self._dirty = True
348 oldp2 = self._pl[1]
348 oldp2 = self._pl[1]
349 if self._origpl is None:
349 if self._origpl is None:
350 self._origpl = self._pl
350 self._origpl = self._pl
351 self._map.setparents(p1, p2)
351 self._map.setparents(p1, p2)
352 copies = {}
352 copies = {}
353 if (
353 if (
354 oldp2 != self._nodeconstants.nullid
354 oldp2 != self._nodeconstants.nullid
355 and p2 == self._nodeconstants.nullid
355 and p2 == self._nodeconstants.nullid
356 ):
356 ):
357 candidatefiles = self._map.non_normal_or_other_parent_paths()
357 candidatefiles = self._map.non_normal_or_other_parent_paths()
358
358
359 for f in candidatefiles:
359 for f in candidatefiles:
360 s = self._map.get(f)
360 s = self._map.get(f)
361 if s is None:
361 if s is None:
362 continue
362 continue
363
363
364 # Discard 'm' markers when moving away from a merge state
364 # Discard 'm' markers when moving away from a merge state
365 if s[0] == b'm':
365 if s[0] == b'm':
366 source = self._map.copymap.get(f)
366 source = self._map.copymap.get(f)
367 if source:
367 if source:
368 copies[f] = source
368 copies[f] = source
369 self.normallookup(f)
369 self.normallookup(f)
370 # Also fix up otherparent markers
370 # Also fix up otherparent markers
371 elif s[0] == b'n' and s[2] == -2:
371 elif s[0] == b'n' and s[2] == -2:
372 source = self._map.copymap.get(f)
372 source = self._map.copymap.get(f)
373 if source:
373 if source:
374 copies[f] = source
374 copies[f] = source
375 self.add(f)
375 self.add(f)
376 return copies
376 return copies
377
377
378 def setbranch(self, branch):
378 def setbranch(self, branch):
379 self.__class__._branch.set(self, encoding.fromlocal(branch))
379 self.__class__._branch.set(self, encoding.fromlocal(branch))
380 f = self._opener(b'branch', b'w', atomictemp=True, checkambig=True)
380 f = self._opener(b'branch', b'w', atomictemp=True, checkambig=True)
381 try:
381 try:
382 f.write(self._branch + b'\n')
382 f.write(self._branch + b'\n')
383 f.close()
383 f.close()
384
384
385 # make sure filecache has the correct stat info for _branch after
385 # make sure filecache has the correct stat info for _branch after
386 # replacing the underlying file
386 # replacing the underlying file
387 ce = self._filecache[b'_branch']
387 ce = self._filecache[b'_branch']
388 if ce:
388 if ce:
389 ce.refresh()
389 ce.refresh()
390 except: # re-raises
390 except: # re-raises
391 f.discard()
391 f.discard()
392 raise
392 raise
393
393
394 def invalidate(self):
394 def invalidate(self):
395 """Causes the next access to reread the dirstate.
395 """Causes the next access to reread the dirstate.
396
396
397 This is different from localrepo.invalidatedirstate() because it always
397 This is different from localrepo.invalidatedirstate() because it always
398 rereads the dirstate. Use localrepo.invalidatedirstate() if you want to
398 rereads the dirstate. Use localrepo.invalidatedirstate() if you want to
399 check whether the dirstate has changed before rereading it."""
399 check whether the dirstate has changed before rereading it."""
400
400
401 for a in ("_map", "_branch", "_ignore"):
401 for a in ("_map", "_branch", "_ignore"):
402 if a in self.__dict__:
402 if a in self.__dict__:
403 delattr(self, a)
403 delattr(self, a)
404 self._lastnormaltime = 0
404 self._lastnormaltime = 0
405 self._dirty = False
405 self._dirty = False
406 self._updatedfiles.clear()
406 self._updatedfiles.clear()
407 self._parentwriters = 0
407 self._parentwriters = 0
408 self._origpl = None
408 self._origpl = None
409
409
410 def copy(self, source, dest):
410 def copy(self, source, dest):
411 """Mark dest as a copy of source. Unmark dest if source is None."""
411 """Mark dest as a copy of source. Unmark dest if source is None."""
412 if source == dest:
412 if source == dest:
413 return
413 return
414 self._dirty = True
414 self._dirty = True
415 if source is not None:
415 if source is not None:
416 self._map.copymap[dest] = source
416 self._map.copymap[dest] = source
417 self._updatedfiles.add(source)
417 self._updatedfiles.add(source)
418 self._updatedfiles.add(dest)
418 self._updatedfiles.add(dest)
419 elif self._map.copymap.pop(dest, None):
419 elif self._map.copymap.pop(dest, None):
420 self._updatedfiles.add(dest)
420 self._updatedfiles.add(dest)
421
421
422 def copied(self, file):
422 def copied(self, file):
423 return self._map.copymap.get(file, None)
423 return self._map.copymap.get(file, None)
424
424
425 def copies(self):
425 def copies(self):
426 return self._map.copymap
426 return self._map.copymap
427
427
428 def _addpath(self, f, state, mode, size, mtime):
428 def _addpath(self, f, state, mode, size, mtime):
429 oldstate = self[f]
429 oldstate = self[f]
430 if state == b'a' or oldstate == b'r':
430 if state == b'a' or oldstate == b'r':
431 scmutil.checkfilename(f)
431 scmutil.checkfilename(f)
432 if self._map.hastrackeddir(f):
432 if self._map.hastrackeddir(f):
433 raise error.Abort(
433 raise error.Abort(
434 _(b'directory %r already in dirstate') % pycompat.bytestr(f)
434 _(b'directory %r already in dirstate') % pycompat.bytestr(f)
435 )
435 )
436 # shadows
436 # shadows
437 for d in pathutil.finddirs(f):
437 for d in pathutil.finddirs(f):
438 if self._map.hastrackeddir(d):
438 if self._map.hastrackeddir(d):
439 break
439 break
440 entry = self._map.get(d)
440 entry = self._map.get(d)
441 if entry is not None and entry[0] != b'r':
441 if entry is not None and entry[0] != b'r':
442 raise error.Abort(
442 raise error.Abort(
443 _(b'file %r in dirstate clashes with %r')
443 _(b'file %r in dirstate clashes with %r')
444 % (pycompat.bytestr(d), pycompat.bytestr(f))
444 % (pycompat.bytestr(d), pycompat.bytestr(f))
445 )
445 )
446 self._dirty = True
446 self._dirty = True
447 self._updatedfiles.add(f)
447 self._updatedfiles.add(f)
448 self._map.addfile(f, oldstate, state, mode, size, mtime)
448 self._map.addfile(f, oldstate, state, mode, size, mtime)
449
449
450 def normal(self, f, parentfiledata=None):
450 def normal(self, f, parentfiledata=None):
451 """Mark a file normal and clean.
451 """Mark a file normal and clean.
452
452
453 parentfiledata: (mode, size, mtime) of the clean file
453 parentfiledata: (mode, size, mtime) of the clean file
454
454
455 parentfiledata should be computed from memory (for mode,
455 parentfiledata should be computed from memory (for mode,
456 size), as or close as possible from the point where we
456 size), as or close as possible from the point where we
457 determined the file was clean, to limit the risk of the
457 determined the file was clean, to limit the risk of the
458 file having been changed by an external process between the
458 file having been changed by an external process between the
459 moment where the file was determined to be clean and now."""
459 moment where the file was determined to be clean and now."""
460 if parentfiledata:
460 if parentfiledata:
461 (mode, size, mtime) = parentfiledata
461 (mode, size, mtime) = parentfiledata
462 else:
462 else:
463 s = os.lstat(self._join(f))
463 s = os.lstat(self._join(f))
464 mode = s.st_mode
464 mode = s.st_mode
465 size = s.st_size
465 size = s.st_size
466 mtime = s[stat.ST_MTIME]
466 mtime = s[stat.ST_MTIME]
467 self._addpath(f, b'n', mode, size & _rangemask, mtime & _rangemask)
467 self._addpath(f, b'n', mode, size & _rangemask, mtime & _rangemask)
468 self._map.copymap.pop(f, None)
468 self._map.copymap.pop(f, None)
469 if f in self._map.nonnormalset:
469 if f in self._map.nonnormalset:
470 self._map.nonnormalset.remove(f)
470 self._map.nonnormalset.remove(f)
471 if mtime > self._lastnormaltime:
471 if mtime > self._lastnormaltime:
472 # Remember the most recent modification timeslot for status(),
472 # Remember the most recent modification timeslot for status(),
473 # to make sure we won't miss future size-preserving file content
473 # to make sure we won't miss future size-preserving file content
474 # modifications that happen within the same timeslot.
474 # modifications that happen within the same timeslot.
475 self._lastnormaltime = mtime
475 self._lastnormaltime = mtime
476
476
477 def normallookup(self, f):
477 def normallookup(self, f):
478 '''Mark a file normal, but possibly dirty.'''
478 '''Mark a file normal, but possibly dirty.'''
479 if self._pl[1] != self._nodeconstants.nullid:
479 if self._pl[1] != self._nodeconstants.nullid:
480 # if there is a merge going on and the file was either
480 # if there is a merge going on and the file was either
481 # in state 'm' (-1) or coming from other parent (-2) before
481 # in state 'm' (-1) or coming from other parent (-2) before
482 # being removed, restore that state.
482 # being removed, restore that state.
483 entry = self._map.get(f)
483 entry = self._map.get(f)
484 if entry is not None:
484 if entry is not None:
485 if entry[0] == b'r' and entry[2] in (-1, -2):
485 if entry[0] == b'r' and entry[2] in (-1, -2):
486 source = self._map.copymap.get(f)
486 source = self._map.copymap.get(f)
487 if entry[2] == -1:
487 if entry[2] == -1:
488 self.merge(f)
488 self.merge(f)
489 elif entry[2] == -2:
489 elif entry[2] == -2:
490 self.otherparent(f)
490 self.otherparent(f)
491 if source:
491 if source:
492 self.copy(source, f)
492 self.copy(source, f)
493 return
493 return
494 if entry[0] == b'm' or entry[0] == b'n' and entry[2] == -2:
494 if entry[0] == b'm' or entry[0] == b'n' and entry[2] == -2:
495 return
495 return
496 self._addpath(f, b'n', 0, -1, -1)
496 self._addpath(f, b'n', 0, -1, -1)
497 self._map.copymap.pop(f, None)
497 self._map.copymap.pop(f, None)
498
498
499 def otherparent(self, f):
499 def otherparent(self, f):
500 '''Mark as coming from the other parent, always dirty.'''
500 '''Mark as coming from the other parent, always dirty.'''
501 if self._pl[1] == self._nodeconstants.nullid:
501 if self._pl[1] == self._nodeconstants.nullid:
502 raise error.Abort(
502 raise error.Abort(
503 _(b"setting %r to other parent only allowed in merges") % f
503 _(b"setting %r to other parent only allowed in merges") % f
504 )
504 )
505 if f in self and self[f] == b'n':
505 if f in self and self[f] == b'n':
506 # merge-like
506 # merge-like
507 self._addpath(f, b'm', 0, -2, -1)
507 self._addpath(f, b'm', 0, -2, -1)
508 else:
508 else:
509 # add-like
509 # add-like
510 self._addpath(f, b'n', 0, -2, -1)
510 self._addpath(f, b'n', 0, -2, -1)
511 self._map.copymap.pop(f, None)
511 self._map.copymap.pop(f, None)
512
512
513 def add(self, f):
513 def add(self, f):
514 '''Mark a file added.'''
514 '''Mark a file added.'''
515 self._addpath(f, b'a', 0, -1, -1)
515 self._addpath(f, b'a', 0, -1, -1)
516 self._map.copymap.pop(f, None)
516 self._map.copymap.pop(f, None)
517
517
518 def remove(self, f):
518 def remove(self, f):
519 '''Mark a file removed.'''
519 '''Mark a file removed.'''
520 self._dirty = True
520 self._dirty = True
521 oldstate = self[f]
521 oldstate = self[f]
522 size = 0
522 size = 0
523 if self._pl[1] != self._nodeconstants.nullid:
523 if self._pl[1] != self._nodeconstants.nullid:
524 entry = self._map.get(f)
524 entry = self._map.get(f)
525 if entry is not None:
525 if entry is not None:
526 # backup the previous state
526 # backup the previous state
527 if entry[0] == b'm': # merge
527 if entry[0] == b'm': # merge
528 size = -1
528 size = -1
529 elif entry[0] == b'n' and entry[2] == -2: # other parent
529 elif entry[0] == b'n' and entry[2] == -2: # other parent
530 size = -2
530 size = -2
531 self._map.otherparentset.add(f)
531 self._map.otherparentset.add(f)
532 self._updatedfiles.add(f)
532 self._updatedfiles.add(f)
533 self._map.removefile(f, oldstate, size)
533 self._map.removefile(f, oldstate, size)
534 if size == 0:
534 if size == 0:
535 self._map.copymap.pop(f, None)
535 self._map.copymap.pop(f, None)
536
536
537 def merge(self, f):
537 def merge(self, f):
538 '''Mark a file merged.'''
538 '''Mark a file merged.'''
539 if self._pl[1] == self._nodeconstants.nullid:
539 if self._pl[1] == self._nodeconstants.nullid:
540 return self.normallookup(f)
540 return self.normallookup(f)
541 return self.otherparent(f)
541 return self.otherparent(f)
542
542
543 def drop(self, f):
543 def drop(self, f):
544 '''Drop a file from the dirstate'''
544 '''Drop a file from the dirstate'''
545 oldstate = self[f]
545 oldstate = self[f]
546 if self._map.dropfile(f, oldstate):
546 if self._map.dropfile(f, oldstate):
547 self._dirty = True
547 self._dirty = True
548 self._updatedfiles.add(f)
548 self._updatedfiles.add(f)
549 self._map.copymap.pop(f, None)
549 self._map.copymap.pop(f, None)
550
550
551 def _discoverpath(self, path, normed, ignoremissing, exists, storemap):
551 def _discoverpath(self, path, normed, ignoremissing, exists, storemap):
552 if exists is None:
552 if exists is None:
553 exists = os.path.lexists(os.path.join(self._root, path))
553 exists = os.path.lexists(os.path.join(self._root, path))
554 if not exists:
554 if not exists:
555 # Maybe a path component exists
555 # Maybe a path component exists
556 if not ignoremissing and b'/' in path:
556 if not ignoremissing and b'/' in path:
557 d, f = path.rsplit(b'/', 1)
557 d, f = path.rsplit(b'/', 1)
558 d = self._normalize(d, False, ignoremissing, None)
558 d = self._normalize(d, False, ignoremissing, None)
559 folded = d + b"/" + f
559 folded = d + b"/" + f
560 else:
560 else:
561 # No path components, preserve original case
561 # No path components, preserve original case
562 folded = path
562 folded = path
563 else:
563 else:
564 # recursively normalize leading directory components
564 # recursively normalize leading directory components
565 # against dirstate
565 # against dirstate
566 if b'/' in normed:
566 if b'/' in normed:
567 d, f = normed.rsplit(b'/', 1)
567 d, f = normed.rsplit(b'/', 1)
568 d = self._normalize(d, False, ignoremissing, True)
568 d = self._normalize(d, False, ignoremissing, True)
569 r = self._root + b"/" + d
569 r = self._root + b"/" + d
570 folded = d + b"/" + util.fspath(f, r)
570 folded = d + b"/" + util.fspath(f, r)
571 else:
571 else:
572 folded = util.fspath(normed, self._root)
572 folded = util.fspath(normed, self._root)
573 storemap[normed] = folded
573 storemap[normed] = folded
574
574
575 return folded
575 return folded
576
576
577 def _normalizefile(self, path, isknown, ignoremissing=False, exists=None):
577 def _normalizefile(self, path, isknown, ignoremissing=False, exists=None):
578 normed = util.normcase(path)
578 normed = util.normcase(path)
579 folded = self._map.filefoldmap.get(normed, None)
579 folded = self._map.filefoldmap.get(normed, None)
580 if folded is None:
580 if folded is None:
581 if isknown:
581 if isknown:
582 folded = path
582 folded = path
583 else:
583 else:
584 folded = self._discoverpath(
584 folded = self._discoverpath(
585 path, normed, ignoremissing, exists, self._map.filefoldmap
585 path, normed, ignoremissing, exists, self._map.filefoldmap
586 )
586 )
587 return folded
587 return folded
588
588
589 def _normalize(self, path, isknown, ignoremissing=False, exists=None):
589 def _normalize(self, path, isknown, ignoremissing=False, exists=None):
590 normed = util.normcase(path)
590 normed = util.normcase(path)
591 folded = self._map.filefoldmap.get(normed, None)
591 folded = self._map.filefoldmap.get(normed, None)
592 if folded is None:
592 if folded is None:
593 folded = self._map.dirfoldmap.get(normed, None)
593 folded = self._map.dirfoldmap.get(normed, None)
594 if folded is None:
594 if folded is None:
595 if isknown:
595 if isknown:
596 folded = path
596 folded = path
597 else:
597 else:
598 # store discovered result in dirfoldmap so that future
598 # store discovered result in dirfoldmap so that future
599 # normalizefile calls don't start matching directories
599 # normalizefile calls don't start matching directories
600 folded = self._discoverpath(
600 folded = self._discoverpath(
601 path, normed, ignoremissing, exists, self._map.dirfoldmap
601 path, normed, ignoremissing, exists, self._map.dirfoldmap
602 )
602 )
603 return folded
603 return folded
604
604
605 def normalize(self, path, isknown=False, ignoremissing=False):
605 def normalize(self, path, isknown=False, ignoremissing=False):
606 """
606 """
607 normalize the case of a pathname when on a casefolding filesystem
607 normalize the case of a pathname when on a casefolding filesystem
608
608
609 isknown specifies whether the filename came from walking the
609 isknown specifies whether the filename came from walking the
610 disk, to avoid extra filesystem access.
610 disk, to avoid extra filesystem access.
611
611
612 If ignoremissing is True, missing path are returned
612 If ignoremissing is True, missing path are returned
613 unchanged. Otherwise, we try harder to normalize possibly
613 unchanged. Otherwise, we try harder to normalize possibly
614 existing path components.
614 existing path components.
615
615
616 The normalized case is determined based on the following precedence:
616 The normalized case is determined based on the following precedence:
617
617
618 - version of name already stored in the dirstate
618 - version of name already stored in the dirstate
619 - version of name stored on disk
619 - version of name stored on disk
620 - version provided via command arguments
620 - version provided via command arguments
621 """
621 """
622
622
623 if self._checkcase:
623 if self._checkcase:
624 return self._normalize(path, isknown, ignoremissing)
624 return self._normalize(path, isknown, ignoremissing)
625 return path
625 return path
626
626
627 def clear(self):
627 def clear(self):
628 self._map.clear()
628 self._map.clear()
629 self._lastnormaltime = 0
629 self._lastnormaltime = 0
630 self._updatedfiles.clear()
630 self._updatedfiles.clear()
631 self._dirty = True
631 self._dirty = True
632
632
633 def rebuild(self, parent, allfiles, changedfiles=None):
633 def rebuild(self, parent, allfiles, changedfiles=None):
634 if changedfiles is None:
634 if changedfiles is None:
635 # Rebuild entire dirstate
635 # Rebuild entire dirstate
636 to_lookup = allfiles
636 to_lookup = allfiles
637 to_drop = []
637 to_drop = []
638 lastnormaltime = self._lastnormaltime
638 lastnormaltime = self._lastnormaltime
639 self.clear()
639 self.clear()
640 self._lastnormaltime = lastnormaltime
640 self._lastnormaltime = lastnormaltime
641 elif len(changedfiles) < 10:
641 elif len(changedfiles) < 10:
642 # Avoid turning allfiles into a set, which can be expensive if it's
642 # Avoid turning allfiles into a set, which can be expensive if it's
643 # large.
643 # large.
644 to_lookup = []
644 to_lookup = []
645 to_drop = []
645 to_drop = []
646 for f in changedfiles:
646 for f in changedfiles:
647 if f in allfiles:
647 if f in allfiles:
648 to_lookup.append(f)
648 to_lookup.append(f)
649 else:
649 else:
650 to_drop.append(f)
650 to_drop.append(f)
651 else:
651 else:
652 changedfilesset = set(changedfiles)
652 changedfilesset = set(changedfiles)
653 to_lookup = changedfilesset & set(allfiles)
653 to_lookup = changedfilesset & set(allfiles)
654 to_drop = changedfilesset - to_lookup
654 to_drop = changedfilesset - to_lookup
655
655
656 if self._origpl is None:
656 if self._origpl is None:
657 self._origpl = self._pl
657 self._origpl = self._pl
658 self._map.setparents(parent, self._nodeconstants.nullid)
658 self._map.setparents(parent, self._nodeconstants.nullid)
659
659
660 for f in to_lookup:
660 for f in to_lookup:
661 self.normallookup(f)
661 self.normallookup(f)
662 for f in to_drop:
662 for f in to_drop:
663 self.drop(f)
663 self.drop(f)
664
664
665 self._dirty = True
665 self._dirty = True
666
666
667 def identity(self):
667 def identity(self):
668 """Return identity of dirstate itself to detect changing in storage
668 """Return identity of dirstate itself to detect changing in storage
669
669
670 If identity of previous dirstate is equal to this, writing
670 If identity of previous dirstate is equal to this, writing
671 changes based on the former dirstate out can keep consistency.
671 changes based on the former dirstate out can keep consistency.
672 """
672 """
673 return self._map.identity
673 return self._map.identity
674
674
675 def write(self, tr):
675 def write(self, tr):
676 if not self._dirty:
676 if not self._dirty:
677 return
677 return
678
678
679 filename = self._filename
679 filename = self._filename
680 if tr:
680 if tr:
681 # 'dirstate.write()' is not only for writing in-memory
681 # 'dirstate.write()' is not only for writing in-memory
682 # changes out, but also for dropping ambiguous timestamp.
682 # changes out, but also for dropping ambiguous timestamp.
683 # delayed writing re-raise "ambiguous timestamp issue".
683 # delayed writing re-raise "ambiguous timestamp issue".
684 # See also the wiki page below for detail:
684 # See also the wiki page below for detail:
685 # https://www.mercurial-scm.org/wiki/DirstateTransactionPlan
685 # https://www.mercurial-scm.org/wiki/DirstateTransactionPlan
686
686
687 # emulate dropping timestamp in 'parsers.pack_dirstate'
687 # emulate dropping timestamp in 'parsers.pack_dirstate'
688 now = _getfsnow(self._opener)
688 now = _getfsnow(self._opener)
689 self._map.clearambiguoustimes(self._updatedfiles, now)
689 self._map.clearambiguoustimes(self._updatedfiles, now)
690
690
691 # emulate that all 'dirstate.normal' results are written out
691 # emulate that all 'dirstate.normal' results are written out
692 self._lastnormaltime = 0
692 self._lastnormaltime = 0
693 self._updatedfiles.clear()
693 self._updatedfiles.clear()
694
694
695 # delay writing in-memory changes out
695 # delay writing in-memory changes out
696 tr.addfilegenerator(
696 tr.addfilegenerator(
697 b'dirstate',
697 b'dirstate',
698 (self._filename,),
698 (self._filename,),
699 self._writedirstate,
699 self._writedirstate,
700 location=b'plain',
700 location=b'plain',
701 )
701 )
702 return
702 return
703
703
704 st = self._opener(filename, b"w", atomictemp=True, checkambig=True)
704 st = self._opener(filename, b"w", atomictemp=True, checkambig=True)
705 self._writedirstate(st)
705 self._writedirstate(st)
706
706
707 def addparentchangecallback(self, category, callback):
707 def addparentchangecallback(self, category, callback):
708 """add a callback to be called when the wd parents are changed
708 """add a callback to be called when the wd parents are changed
709
709
710 Callback will be called with the following arguments:
710 Callback will be called with the following arguments:
711 dirstate, (oldp1, oldp2), (newp1, newp2)
711 dirstate, (oldp1, oldp2), (newp1, newp2)
712
712
713 Category is a unique identifier to allow overwriting an old callback
713 Category is a unique identifier to allow overwriting an old callback
714 with a newer callback.
714 with a newer callback.
715 """
715 """
716 self._plchangecallbacks[category] = callback
716 self._plchangecallbacks[category] = callback
717
717
718 def _writedirstate(self, st):
718 def _writedirstate(self, st):
719 # notify callbacks about parents change
719 # notify callbacks about parents change
720 if self._origpl is not None and self._origpl != self._pl:
720 if self._origpl is not None and self._origpl != self._pl:
721 for c, callback in sorted(
721 for c, callback in sorted(
722 pycompat.iteritems(self._plchangecallbacks)
722 pycompat.iteritems(self._plchangecallbacks)
723 ):
723 ):
724 callback(self, self._origpl, self._pl)
724 callback(self, self._origpl, self._pl)
725 self._origpl = None
725 self._origpl = None
726 # use the modification time of the newly created temporary file as the
726 # use the modification time of the newly created temporary file as the
727 # filesystem's notion of 'now'
727 # filesystem's notion of 'now'
728 now = util.fstat(st)[stat.ST_MTIME] & _rangemask
728 now = util.fstat(st)[stat.ST_MTIME] & _rangemask
729
729
730 # enough 'delaywrite' prevents 'pack_dirstate' from dropping
730 # enough 'delaywrite' prevents 'pack_dirstate' from dropping
731 # timestamp of each entries in dirstate, because of 'now > mtime'
731 # timestamp of each entries in dirstate, because of 'now > mtime'
732 delaywrite = self._ui.configint(b'debug', b'dirstate.delaywrite')
732 delaywrite = self._ui.configint(b'debug', b'dirstate.delaywrite')
733 if delaywrite > 0:
733 if delaywrite > 0:
734 # do we have any files to delay for?
734 # do we have any files to delay for?
735 for f, e in pycompat.iteritems(self._map):
735 for f, e in pycompat.iteritems(self._map):
736 if e[0] == b'n' and e[3] == now:
736 if e[0] == b'n' and e[3] == now:
737 import time # to avoid useless import
737 import time # to avoid useless import
738
738
739 # rather than sleep n seconds, sleep until the next
739 # rather than sleep n seconds, sleep until the next
740 # multiple of n seconds
740 # multiple of n seconds
741 clock = time.time()
741 clock = time.time()
742 start = int(clock) - (int(clock) % delaywrite)
742 start = int(clock) - (int(clock) % delaywrite)
743 end = start + delaywrite
743 end = start + delaywrite
744 time.sleep(end - clock)
744 time.sleep(end - clock)
745 now = end # trust our estimate that the end is near now
745 now = end # trust our estimate that the end is near now
746 break
746 break
747
747
748 self._map.write(st, now)
748 self._map.write(st, now)
749 self._lastnormaltime = 0
749 self._lastnormaltime = 0
750 self._dirty = False
750 self._dirty = False
751
751
752 def _dirignore(self, f):
752 def _dirignore(self, f):
753 if self._ignore(f):
753 if self._ignore(f):
754 return True
754 return True
755 for p in pathutil.finddirs(f):
755 for p in pathutil.finddirs(f):
756 if self._ignore(p):
756 if self._ignore(p):
757 return True
757 return True
758 return False
758 return False
759
759
760 def _ignorefiles(self):
760 def _ignorefiles(self):
761 files = []
761 files = []
762 if os.path.exists(self._join(b'.hgignore')):
762 if os.path.exists(self._join(b'.hgignore')):
763 files.append(self._join(b'.hgignore'))
763 files.append(self._join(b'.hgignore'))
764 for name, path in self._ui.configitems(b"ui"):
764 for name, path in self._ui.configitems(b"ui"):
765 if name == b'ignore' or name.startswith(b'ignore.'):
765 if name == b'ignore' or name.startswith(b'ignore.'):
766 # we need to use os.path.join here rather than self._join
766 # we need to use os.path.join here rather than self._join
767 # because path is arbitrary and user-specified
767 # because path is arbitrary and user-specified
768 files.append(os.path.join(self._rootdir, util.expandpath(path)))
768 files.append(os.path.join(self._rootdir, util.expandpath(path)))
769 return files
769 return files
770
770
771 def _ignorefileandline(self, f):
771 def _ignorefileandline(self, f):
772 files = collections.deque(self._ignorefiles())
772 files = collections.deque(self._ignorefiles())
773 visited = set()
773 visited = set()
774 while files:
774 while files:
775 i = files.popleft()
775 i = files.popleft()
776 patterns = matchmod.readpatternfile(
776 patterns = matchmod.readpatternfile(
777 i, self._ui.warn, sourceinfo=True
777 i, self._ui.warn, sourceinfo=True
778 )
778 )
779 for pattern, lineno, line in patterns:
779 for pattern, lineno, line in patterns:
780 kind, p = matchmod._patsplit(pattern, b'glob')
780 kind, p = matchmod._patsplit(pattern, b'glob')
781 if kind == b"subinclude":
781 if kind == b"subinclude":
782 if p not in visited:
782 if p not in visited:
783 files.append(p)
783 files.append(p)
784 continue
784 continue
785 m = matchmod.match(
785 m = matchmod.match(
786 self._root, b'', [], [pattern], warn=self._ui.warn
786 self._root, b'', [], [pattern], warn=self._ui.warn
787 )
787 )
788 if m(f):
788 if m(f):
789 return (i, lineno, line)
789 return (i, lineno, line)
790 visited.add(i)
790 visited.add(i)
791 return (None, -1, b"")
791 return (None, -1, b"")
792
792
793 def _walkexplicit(self, match, subrepos):
793 def _walkexplicit(self, match, subrepos):
794 """Get stat data about the files explicitly specified by match.
794 """Get stat data about the files explicitly specified by match.
795
795
796 Return a triple (results, dirsfound, dirsnotfound).
796 Return a triple (results, dirsfound, dirsnotfound).
797 - results is a mapping from filename to stat result. It also contains
797 - results is a mapping from filename to stat result. It also contains
798 listings mapping subrepos and .hg to None.
798 listings mapping subrepos and .hg to None.
799 - dirsfound is a list of files found to be directories.
799 - dirsfound is a list of files found to be directories.
800 - dirsnotfound is a list of files that the dirstate thinks are
800 - dirsnotfound is a list of files that the dirstate thinks are
801 directories and that were not found."""
801 directories and that were not found."""
802
802
803 def badtype(mode):
803 def badtype(mode):
804 kind = _(b'unknown')
804 kind = _(b'unknown')
805 if stat.S_ISCHR(mode):
805 if stat.S_ISCHR(mode):
806 kind = _(b'character device')
806 kind = _(b'character device')
807 elif stat.S_ISBLK(mode):
807 elif stat.S_ISBLK(mode):
808 kind = _(b'block device')
808 kind = _(b'block device')
809 elif stat.S_ISFIFO(mode):
809 elif stat.S_ISFIFO(mode):
810 kind = _(b'fifo')
810 kind = _(b'fifo')
811 elif stat.S_ISSOCK(mode):
811 elif stat.S_ISSOCK(mode):
812 kind = _(b'socket')
812 kind = _(b'socket')
813 elif stat.S_ISDIR(mode):
813 elif stat.S_ISDIR(mode):
814 kind = _(b'directory')
814 kind = _(b'directory')
815 return _(b'unsupported file type (type is %s)') % kind
815 return _(b'unsupported file type (type is %s)') % kind
816
816
817 badfn = match.bad
817 badfn = match.bad
818 dmap = self._map
818 dmap = self._map
819 lstat = os.lstat
819 lstat = os.lstat
820 getkind = stat.S_IFMT
820 getkind = stat.S_IFMT
821 dirkind = stat.S_IFDIR
821 dirkind = stat.S_IFDIR
822 regkind = stat.S_IFREG
822 regkind = stat.S_IFREG
823 lnkkind = stat.S_IFLNK
823 lnkkind = stat.S_IFLNK
824 join = self._join
824 join = self._join
825 dirsfound = []
825 dirsfound = []
826 foundadd = dirsfound.append
826 foundadd = dirsfound.append
827 dirsnotfound = []
827 dirsnotfound = []
828 notfoundadd = dirsnotfound.append
828 notfoundadd = dirsnotfound.append
829
829
830 if not match.isexact() and self._checkcase:
830 if not match.isexact() and self._checkcase:
831 normalize = self._normalize
831 normalize = self._normalize
832 else:
832 else:
833 normalize = None
833 normalize = None
834
834
835 files = sorted(match.files())
835 files = sorted(match.files())
836 subrepos.sort()
836 subrepos.sort()
837 i, j = 0, 0
837 i, j = 0, 0
838 while i < len(files) and j < len(subrepos):
838 while i < len(files) and j < len(subrepos):
839 subpath = subrepos[j] + b"/"
839 subpath = subrepos[j] + b"/"
840 if files[i] < subpath:
840 if files[i] < subpath:
841 i += 1
841 i += 1
842 continue
842 continue
843 while i < len(files) and files[i].startswith(subpath):
843 while i < len(files) and files[i].startswith(subpath):
844 del files[i]
844 del files[i]
845 j += 1
845 j += 1
846
846
847 if not files or b'' in files:
847 if not files or b'' in files:
848 files = [b'']
848 files = [b'']
849 # constructing the foldmap is expensive, so don't do it for the
849 # constructing the foldmap is expensive, so don't do it for the
850 # common case where files is ['']
850 # common case where files is ['']
851 normalize = None
851 normalize = None
852 results = dict.fromkeys(subrepos)
852 results = dict.fromkeys(subrepos)
853 results[b'.hg'] = None
853 results[b'.hg'] = None
854
854
855 for ff in files:
855 for ff in files:
856 if normalize:
856 if normalize:
857 nf = normalize(ff, False, True)
857 nf = normalize(ff, False, True)
858 else:
858 else:
859 nf = ff
859 nf = ff
860 if nf in results:
860 if nf in results:
861 continue
861 continue
862
862
863 try:
863 try:
864 st = lstat(join(nf))
864 st = lstat(join(nf))
865 kind = getkind(st.st_mode)
865 kind = getkind(st.st_mode)
866 if kind == dirkind:
866 if kind == dirkind:
867 if nf in dmap:
867 if nf in dmap:
868 # file replaced by dir on disk but still in dirstate
868 # file replaced by dir on disk but still in dirstate
869 results[nf] = None
869 results[nf] = None
870 foundadd((nf, ff))
870 foundadd((nf, ff))
871 elif kind == regkind or kind == lnkkind:
871 elif kind == regkind or kind == lnkkind:
872 results[nf] = st
872 results[nf] = st
873 else:
873 else:
874 badfn(ff, badtype(kind))
874 badfn(ff, badtype(kind))
875 if nf in dmap:
875 if nf in dmap:
876 results[nf] = None
876 results[nf] = None
877 except OSError as inst: # nf not found on disk - it is dirstate only
877 except OSError as inst: # nf not found on disk - it is dirstate only
878 if nf in dmap: # does it exactly match a missing file?
878 if nf in dmap: # does it exactly match a missing file?
879 results[nf] = None
879 results[nf] = None
880 else: # does it match a missing directory?
880 else: # does it match a missing directory?
881 if self._map.hasdir(nf):
881 if self._map.hasdir(nf):
882 notfoundadd(nf)
882 notfoundadd(nf)
883 else:
883 else:
884 badfn(ff, encoding.strtolocal(inst.strerror))
884 badfn(ff, encoding.strtolocal(inst.strerror))
885
885
886 # match.files() may contain explicitly-specified paths that shouldn't
886 # match.files() may contain explicitly-specified paths that shouldn't
887 # be taken; drop them from the list of files found. dirsfound/notfound
887 # be taken; drop them from the list of files found. dirsfound/notfound
888 # aren't filtered here because they will be tested later.
888 # aren't filtered here because they will be tested later.
889 if match.anypats():
889 if match.anypats():
890 for f in list(results):
890 for f in list(results):
891 if f == b'.hg' or f in subrepos:
891 if f == b'.hg' or f in subrepos:
892 # keep sentinel to disable further out-of-repo walks
892 # keep sentinel to disable further out-of-repo walks
893 continue
893 continue
894 if not match(f):
894 if not match(f):
895 del results[f]
895 del results[f]
896
896
897 # Case insensitive filesystems cannot rely on lstat() failing to detect
897 # Case insensitive filesystems cannot rely on lstat() failing to detect
898 # a case-only rename. Prune the stat object for any file that does not
898 # a case-only rename. Prune the stat object for any file that does not
899 # match the case in the filesystem, if there are multiple files that
899 # match the case in the filesystem, if there are multiple files that
900 # normalize to the same path.
900 # normalize to the same path.
901 if match.isexact() and self._checkcase:
901 if match.isexact() and self._checkcase:
902 normed = {}
902 normed = {}
903
903
904 for f, st in pycompat.iteritems(results):
904 for f, st in pycompat.iteritems(results):
905 if st is None:
905 if st is None:
906 continue
906 continue
907
907
908 nc = util.normcase(f)
908 nc = util.normcase(f)
909 paths = normed.get(nc)
909 paths = normed.get(nc)
910
910
911 if paths is None:
911 if paths is None:
912 paths = set()
912 paths = set()
913 normed[nc] = paths
913 normed[nc] = paths
914
914
915 paths.add(f)
915 paths.add(f)
916
916
917 for norm, paths in pycompat.iteritems(normed):
917 for norm, paths in pycompat.iteritems(normed):
918 if len(paths) > 1:
918 if len(paths) > 1:
919 for path in paths:
919 for path in paths:
920 folded = self._discoverpath(
920 folded = self._discoverpath(
921 path, norm, True, None, self._map.dirfoldmap
921 path, norm, True, None, self._map.dirfoldmap
922 )
922 )
923 if path != folded:
923 if path != folded:
924 results[path] = None
924 results[path] = None
925
925
926 return results, dirsfound, dirsnotfound
926 return results, dirsfound, dirsnotfound
927
927
928 def walk(self, match, subrepos, unknown, ignored, full=True):
928 def walk(self, match, subrepos, unknown, ignored, full=True):
929 """
929 """
930 Walk recursively through the directory tree, finding all files
930 Walk recursively through the directory tree, finding all files
931 matched by match.
931 matched by match.
932
932
933 If full is False, maybe skip some known-clean files.
933 If full is False, maybe skip some known-clean files.
934
934
935 Return a dict mapping filename to stat-like object (either
935 Return a dict mapping filename to stat-like object (either
936 mercurial.osutil.stat instance or return value of os.stat()).
936 mercurial.osutil.stat instance or return value of os.stat()).
937
937
938 """
938 """
939 # full is a flag that extensions that hook into walk can use -- this
939 # full is a flag that extensions that hook into walk can use -- this
940 # implementation doesn't use it at all. This satisfies the contract
940 # implementation doesn't use it at all. This satisfies the contract
941 # because we only guarantee a "maybe".
941 # because we only guarantee a "maybe".
942
942
943 if ignored:
943 if ignored:
944 ignore = util.never
944 ignore = util.never
945 dirignore = util.never
945 dirignore = util.never
946 elif unknown:
946 elif unknown:
947 ignore = self._ignore
947 ignore = self._ignore
948 dirignore = self._dirignore
948 dirignore = self._dirignore
949 else:
949 else:
950 # if not unknown and not ignored, drop dir recursion and step 2
950 # if not unknown and not ignored, drop dir recursion and step 2
951 ignore = util.always
951 ignore = util.always
952 dirignore = util.always
952 dirignore = util.always
953
953
954 matchfn = match.matchfn
954 matchfn = match.matchfn
955 matchalways = match.always()
955 matchalways = match.always()
956 matchtdir = match.traversedir
956 matchtdir = match.traversedir
957 dmap = self._map
957 dmap = self._map
958 listdir = util.listdir
958 listdir = util.listdir
959 lstat = os.lstat
959 lstat = os.lstat
960 dirkind = stat.S_IFDIR
960 dirkind = stat.S_IFDIR
961 regkind = stat.S_IFREG
961 regkind = stat.S_IFREG
962 lnkkind = stat.S_IFLNK
962 lnkkind = stat.S_IFLNK
963 join = self._join
963 join = self._join
964
964
965 exact = skipstep3 = False
965 exact = skipstep3 = False
966 if match.isexact(): # match.exact
966 if match.isexact(): # match.exact
967 exact = True
967 exact = True
968 dirignore = util.always # skip step 2
968 dirignore = util.always # skip step 2
969 elif match.prefix(): # match.match, no patterns
969 elif match.prefix(): # match.match, no patterns
970 skipstep3 = True
970 skipstep3 = True
971
971
972 if not exact and self._checkcase:
972 if not exact and self._checkcase:
973 normalize = self._normalize
973 normalize = self._normalize
974 normalizefile = self._normalizefile
974 normalizefile = self._normalizefile
975 skipstep3 = False
975 skipstep3 = False
976 else:
976 else:
977 normalize = self._normalize
977 normalize = self._normalize
978 normalizefile = None
978 normalizefile = None
979
979
980 # step 1: find all explicit files
980 # step 1: find all explicit files
981 results, work, dirsnotfound = self._walkexplicit(match, subrepos)
981 results, work, dirsnotfound = self._walkexplicit(match, subrepos)
982 if matchtdir:
982 if matchtdir:
983 for d in work:
983 for d in work:
984 matchtdir(d[0])
984 matchtdir(d[0])
985 for d in dirsnotfound:
985 for d in dirsnotfound:
986 matchtdir(d)
986 matchtdir(d)
987
987
988 skipstep3 = skipstep3 and not (work or dirsnotfound)
988 skipstep3 = skipstep3 and not (work or dirsnotfound)
989 work = [d for d in work if not dirignore(d[0])]
989 work = [d for d in work if not dirignore(d[0])]
990
990
991 # step 2: visit subdirectories
991 # step 2: visit subdirectories
992 def traverse(work, alreadynormed):
992 def traverse(work, alreadynormed):
993 wadd = work.append
993 wadd = work.append
994 while work:
994 while work:
995 tracing.counter('dirstate.walk work', len(work))
995 tracing.counter('dirstate.walk work', len(work))
996 nd = work.pop()
996 nd = work.pop()
997 visitentries = match.visitchildrenset(nd)
997 visitentries = match.visitchildrenset(nd)
998 if not visitentries:
998 if not visitentries:
999 continue
999 continue
1000 if visitentries == b'this' or visitentries == b'all':
1000 if visitentries == b'this' or visitentries == b'all':
1001 visitentries = None
1001 visitentries = None
1002 skip = None
1002 skip = None
1003 if nd != b'':
1003 if nd != b'':
1004 skip = b'.hg'
1004 skip = b'.hg'
1005 try:
1005 try:
1006 with tracing.log('dirstate.walk.traverse listdir %s', nd):
1006 with tracing.log('dirstate.walk.traverse listdir %s', nd):
1007 entries = listdir(join(nd), stat=True, skip=skip)
1007 entries = listdir(join(nd), stat=True, skip=skip)
1008 except OSError as inst:
1008 except OSError as inst:
1009 if inst.errno in (errno.EACCES, errno.ENOENT):
1009 if inst.errno in (errno.EACCES, errno.ENOENT):
1010 match.bad(
1010 match.bad(
1011 self.pathto(nd), encoding.strtolocal(inst.strerror)
1011 self.pathto(nd), encoding.strtolocal(inst.strerror)
1012 )
1012 )
1013 continue
1013 continue
1014 raise
1014 raise
1015 for f, kind, st in entries:
1015 for f, kind, st in entries:
1016 # Some matchers may return files in the visitentries set,
1016 # Some matchers may return files in the visitentries set,
1017 # instead of 'this', if the matcher explicitly mentions them
1017 # instead of 'this', if the matcher explicitly mentions them
1018 # and is not an exactmatcher. This is acceptable; we do not
1018 # and is not an exactmatcher. This is acceptable; we do not
1019 # make any hard assumptions about file-or-directory below
1019 # make any hard assumptions about file-or-directory below
1020 # based on the presence of `f` in visitentries. If
1020 # based on the presence of `f` in visitentries. If
1021 # visitchildrenset returned a set, we can always skip the
1021 # visitchildrenset returned a set, we can always skip the
1022 # entries *not* in the set it provided regardless of whether
1022 # entries *not* in the set it provided regardless of whether
1023 # they're actually a file or a directory.
1023 # they're actually a file or a directory.
1024 if visitentries and f not in visitentries:
1024 if visitentries and f not in visitentries:
1025 continue
1025 continue
1026 if normalizefile:
1026 if normalizefile:
1027 # even though f might be a directory, we're only
1027 # even though f might be a directory, we're only
1028 # interested in comparing it to files currently in the
1028 # interested in comparing it to files currently in the
1029 # dmap -- therefore normalizefile is enough
1029 # dmap -- therefore normalizefile is enough
1030 nf = normalizefile(
1030 nf = normalizefile(
1031 nd and (nd + b"/" + f) or f, True, True
1031 nd and (nd + b"/" + f) or f, True, True
1032 )
1032 )
1033 else:
1033 else:
1034 nf = nd and (nd + b"/" + f) or f
1034 nf = nd and (nd + b"/" + f) or f
1035 if nf not in results:
1035 if nf not in results:
1036 if kind == dirkind:
1036 if kind == dirkind:
1037 if not ignore(nf):
1037 if not ignore(nf):
1038 if matchtdir:
1038 if matchtdir:
1039 matchtdir(nf)
1039 matchtdir(nf)
1040 wadd(nf)
1040 wadd(nf)
1041 if nf in dmap and (matchalways or matchfn(nf)):
1041 if nf in dmap and (matchalways or matchfn(nf)):
1042 results[nf] = None
1042 results[nf] = None
1043 elif kind == regkind or kind == lnkkind:
1043 elif kind == regkind or kind == lnkkind:
1044 if nf in dmap:
1044 if nf in dmap:
1045 if matchalways or matchfn(nf):
1045 if matchalways or matchfn(nf):
1046 results[nf] = st
1046 results[nf] = st
1047 elif (matchalways or matchfn(nf)) and not ignore(
1047 elif (matchalways or matchfn(nf)) and not ignore(
1048 nf
1048 nf
1049 ):
1049 ):
1050 # unknown file -- normalize if necessary
1050 # unknown file -- normalize if necessary
1051 if not alreadynormed:
1051 if not alreadynormed:
1052 nf = normalize(nf, False, True)
1052 nf = normalize(nf, False, True)
1053 results[nf] = st
1053 results[nf] = st
1054 elif nf in dmap and (matchalways or matchfn(nf)):
1054 elif nf in dmap and (matchalways or matchfn(nf)):
1055 results[nf] = None
1055 results[nf] = None
1056
1056
1057 for nd, d in work:
1057 for nd, d in work:
1058 # alreadynormed means that processwork doesn't have to do any
1058 # alreadynormed means that processwork doesn't have to do any
1059 # expensive directory normalization
1059 # expensive directory normalization
1060 alreadynormed = not normalize or nd == d
1060 alreadynormed = not normalize or nd == d
1061 traverse([d], alreadynormed)
1061 traverse([d], alreadynormed)
1062
1062
1063 for s in subrepos:
1063 for s in subrepos:
1064 del results[s]
1064 del results[s]
1065 del results[b'.hg']
1065 del results[b'.hg']
1066
1066
1067 # step 3: visit remaining files from dmap
1067 # step 3: visit remaining files from dmap
1068 if not skipstep3 and not exact:
1068 if not skipstep3 and not exact:
1069 # If a dmap file is not in results yet, it was either
1069 # If a dmap file is not in results yet, it was either
1070 # a) not matching matchfn b) ignored, c) missing, or d) under a
1070 # a) not matching matchfn b) ignored, c) missing, or d) under a
1071 # symlink directory.
1071 # symlink directory.
1072 if not results and matchalways:
1072 if not results and matchalways:
1073 visit = [f for f in dmap]
1073 visit = [f for f in dmap]
1074 else:
1074 else:
1075 visit = [f for f in dmap if f not in results and matchfn(f)]
1075 visit = [f for f in dmap if f not in results and matchfn(f)]
1076 visit.sort()
1076 visit.sort()
1077
1077
1078 if unknown:
1078 if unknown:
1079 # unknown == True means we walked all dirs under the roots
1079 # unknown == True means we walked all dirs under the roots
1080 # that wasn't ignored, and everything that matched was stat'ed
1080 # that wasn't ignored, and everything that matched was stat'ed
1081 # and is already in results.
1081 # and is already in results.
1082 # The rest must thus be ignored or under a symlink.
1082 # The rest must thus be ignored or under a symlink.
1083 audit_path = pathutil.pathauditor(self._root, cached=True)
1083 audit_path = pathutil.pathauditor(self._root, cached=True)
1084
1084
1085 for nf in iter(visit):
1085 for nf in iter(visit):
1086 # If a stat for the same file was already added with a
1086 # If a stat for the same file was already added with a
1087 # different case, don't add one for this, since that would
1087 # different case, don't add one for this, since that would
1088 # make it appear as if the file exists under both names
1088 # make it appear as if the file exists under both names
1089 # on disk.
1089 # on disk.
1090 if (
1090 if (
1091 normalizefile
1091 normalizefile
1092 and normalizefile(nf, True, True) in results
1092 and normalizefile(nf, True, True) in results
1093 ):
1093 ):
1094 results[nf] = None
1094 results[nf] = None
1095 # Report ignored items in the dmap as long as they are not
1095 # Report ignored items in the dmap as long as they are not
1096 # under a symlink directory.
1096 # under a symlink directory.
1097 elif audit_path.check(nf):
1097 elif audit_path.check(nf):
1098 try:
1098 try:
1099 results[nf] = lstat(join(nf))
1099 results[nf] = lstat(join(nf))
1100 # file was just ignored, no links, and exists
1100 # file was just ignored, no links, and exists
1101 except OSError:
1101 except OSError:
1102 # file doesn't exist
1102 # file doesn't exist
1103 results[nf] = None
1103 results[nf] = None
1104 else:
1104 else:
1105 # It's either missing or under a symlink directory
1105 # It's either missing or under a symlink directory
1106 # which we in this case report as missing
1106 # which we in this case report as missing
1107 results[nf] = None
1107 results[nf] = None
1108 else:
1108 else:
1109 # We may not have walked the full directory tree above,
1109 # We may not have walked the full directory tree above,
1110 # so stat and check everything we missed.
1110 # so stat and check everything we missed.
1111 iv = iter(visit)
1111 iv = iter(visit)
1112 for st in util.statfiles([join(i) for i in visit]):
1112 for st in util.statfiles([join(i) for i in visit]):
1113 results[next(iv)] = st
1113 results[next(iv)] = st
1114 return results
1114 return results
1115
1115
1116 def _rust_status(self, matcher, list_clean, list_ignored, list_unknown):
1116 def _rust_status(self, matcher, list_clean, list_ignored, list_unknown):
1117 # Force Rayon (Rust parallelism library) to respect the number of
1117 # Force Rayon (Rust parallelism library) to respect the number of
1118 # workers. This is a temporary workaround until Rust code knows
1118 # workers. This is a temporary workaround until Rust code knows
1119 # how to read the config file.
1119 # how to read the config file.
1120 numcpus = self._ui.configint(b"worker", b"numcpus")
1120 numcpus = self._ui.configint(b"worker", b"numcpus")
1121 if numcpus is not None:
1121 if numcpus is not None:
1122 encoding.environ.setdefault(b'RAYON_NUM_THREADS', b'%d' % numcpus)
1122 encoding.environ.setdefault(b'RAYON_NUM_THREADS', b'%d' % numcpus)
1123
1123
1124 workers_enabled = self._ui.configbool(b"worker", b"enabled", True)
1124 workers_enabled = self._ui.configbool(b"worker", b"enabled", True)
1125 if not workers_enabled:
1125 if not workers_enabled:
1126 encoding.environ[b"RAYON_NUM_THREADS"] = b"1"
1126 encoding.environ[b"RAYON_NUM_THREADS"] = b"1"
1127
1127
1128 (
1128 (
1129 lookup,
1129 lookup,
1130 modified,
1130 modified,
1131 added,
1131 added,
1132 removed,
1132 removed,
1133 deleted,
1133 deleted,
1134 clean,
1134 clean,
1135 ignored,
1135 ignored,
1136 unknown,
1136 unknown,
1137 warnings,
1137 warnings,
1138 bad,
1138 bad,
1139 traversed,
1139 traversed,
1140 ) = rustmod.status(
1140 ) = rustmod.status(
1141 self._map._rustmap,
1141 self._map._rustmap,
1142 matcher,
1142 matcher,
1143 self._rootdir,
1143 self._rootdir,
1144 self._ignorefiles(),
1144 self._ignorefiles(),
1145 self._checkexec,
1145 self._checkexec,
1146 self._lastnormaltime,
1146 self._lastnormaltime,
1147 bool(list_clean),
1147 bool(list_clean),
1148 bool(list_ignored),
1148 bool(list_ignored),
1149 bool(list_unknown),
1149 bool(list_unknown),
1150 bool(matcher.traversedir),
1150 bool(matcher.traversedir),
1151 )
1151 )
1152
1152
1153 if matcher.traversedir:
1153 if matcher.traversedir:
1154 for dir in traversed:
1154 for dir in traversed:
1155 matcher.traversedir(dir)
1155 matcher.traversedir(dir)
1156
1156
1157 if self._ui.warn:
1157 if self._ui.warn:
1158 for item in warnings:
1158 for item in warnings:
1159 if isinstance(item, tuple):
1159 if isinstance(item, tuple):
1160 file_path, syntax = item
1160 file_path, syntax = item
1161 msg = _(b"%s: ignoring invalid syntax '%s'\n") % (
1161 msg = _(b"%s: ignoring invalid syntax '%s'\n") % (
1162 file_path,
1162 file_path,
1163 syntax,
1163 syntax,
1164 )
1164 )
1165 self._ui.warn(msg)
1165 self._ui.warn(msg)
1166 else:
1166 else:
1167 msg = _(b"skipping unreadable pattern file '%s': %s\n")
1167 msg = _(b"skipping unreadable pattern file '%s': %s\n")
1168 self._ui.warn(
1168 self._ui.warn(
1169 msg
1169 msg
1170 % (
1170 % (
1171 pathutil.canonpath(
1171 pathutil.canonpath(
1172 self._rootdir, self._rootdir, item
1172 self._rootdir, self._rootdir, item
1173 ),
1173 ),
1174 b"No such file or directory",
1174 b"No such file or directory",
1175 )
1175 )
1176 )
1176 )
1177
1177
1178 for (fn, message) in bad:
1178 for (fn, message) in bad:
1179 matcher.bad(fn, encoding.strtolocal(message))
1179 matcher.bad(fn, encoding.strtolocal(message))
1180
1180
1181 status = scmutil.status(
1181 status = scmutil.status(
1182 modified=modified,
1182 modified=modified,
1183 added=added,
1183 added=added,
1184 removed=removed,
1184 removed=removed,
1185 deleted=deleted,
1185 deleted=deleted,
1186 unknown=unknown,
1186 unknown=unknown,
1187 ignored=ignored,
1187 ignored=ignored,
1188 clean=clean,
1188 clean=clean,
1189 )
1189 )
1190 return (lookup, status)
1190 return (lookup, status)
1191
1191
1192 def status(self, match, subrepos, ignored, clean, unknown):
1192 def status(self, match, subrepos, ignored, clean, unknown):
1193 """Determine the status of the working copy relative to the
1193 """Determine the status of the working copy relative to the
1194 dirstate and return a pair of (unsure, status), where status is of type
1194 dirstate and return a pair of (unsure, status), where status is of type
1195 scmutil.status and:
1195 scmutil.status and:
1196
1196
1197 unsure:
1197 unsure:
1198 files that might have been modified since the dirstate was
1198 files that might have been modified since the dirstate was
1199 written, but need to be read to be sure (size is the same
1199 written, but need to be read to be sure (size is the same
1200 but mtime differs)
1200 but mtime differs)
1201 status.modified:
1201 status.modified:
1202 files that have definitely been modified since the dirstate
1202 files that have definitely been modified since the dirstate
1203 was written (different size or mode)
1203 was written (different size or mode)
1204 status.clean:
1204 status.clean:
1205 files that have definitely not been modified since the
1205 files that have definitely not been modified since the
1206 dirstate was written
1206 dirstate was written
1207 """
1207 """
1208 listignored, listclean, listunknown = ignored, clean, unknown
1208 listignored, listclean, listunknown = ignored, clean, unknown
1209 lookup, modified, added, unknown, ignored = [], [], [], [], []
1209 lookup, modified, added, unknown, ignored = [], [], [], [], []
1210 removed, deleted, clean = [], [], []
1210 removed, deleted, clean = [], [], []
1211
1211
1212 dmap = self._map
1212 dmap = self._map
1213 dmap.preload()
1213 dmap.preload()
1214
1214
1215 use_rust = True
1215 use_rust = True
1216
1216
1217 allowed_matchers = (
1217 allowed_matchers = (
1218 matchmod.alwaysmatcher,
1218 matchmod.alwaysmatcher,
1219 matchmod.exactmatcher,
1219 matchmod.exactmatcher,
1220 matchmod.includematcher,
1220 matchmod.includematcher,
1221 )
1221 )
1222
1222
1223 if rustmod is None:
1223 if rustmod is None:
1224 use_rust = False
1224 use_rust = False
1225 elif self._checkcase:
1225 elif self._checkcase:
1226 # Case-insensitive filesystems are not handled yet
1226 # Case-insensitive filesystems are not handled yet
1227 use_rust = False
1227 use_rust = False
1228 elif subrepos:
1228 elif subrepos:
1229 use_rust = False
1229 use_rust = False
1230 elif sparse.enabled:
1230 elif sparse.enabled:
1231 use_rust = False
1231 use_rust = False
1232 elif not isinstance(match, allowed_matchers):
1232 elif not isinstance(match, allowed_matchers):
1233 # Some matchers have yet to be implemented
1233 # Some matchers have yet to be implemented
1234 use_rust = False
1234 use_rust = False
1235
1235
1236 if use_rust:
1236 if use_rust:
1237 try:
1237 try:
1238 return self._rust_status(
1238 return self._rust_status(
1239 match, listclean, listignored, listunknown
1239 match, listclean, listignored, listunknown
1240 )
1240 )
1241 except rustmod.FallbackError:
1241 except rustmod.FallbackError:
1242 pass
1242 pass
1243
1243
1244 def noop(f):
1244 def noop(f):
1245 pass
1245 pass
1246
1246
1247 dcontains = dmap.__contains__
1247 dcontains = dmap.__contains__
1248 dget = dmap.__getitem__
1248 dget = dmap.__getitem__
1249 ladd = lookup.append # aka "unsure"
1249 ladd = lookup.append # aka "unsure"
1250 madd = modified.append
1250 madd = modified.append
1251 aadd = added.append
1251 aadd = added.append
1252 uadd = unknown.append if listunknown else noop
1252 uadd = unknown.append if listunknown else noop
1253 iadd = ignored.append if listignored else noop
1253 iadd = ignored.append if listignored else noop
1254 radd = removed.append
1254 radd = removed.append
1255 dadd = deleted.append
1255 dadd = deleted.append
1256 cadd = clean.append if listclean else noop
1256 cadd = clean.append if listclean else noop
1257 mexact = match.exact
1257 mexact = match.exact
1258 dirignore = self._dirignore
1258 dirignore = self._dirignore
1259 checkexec = self._checkexec
1259 checkexec = self._checkexec
1260 copymap = self._map.copymap
1260 copymap = self._map.copymap
1261 lastnormaltime = self._lastnormaltime
1261 lastnormaltime = self._lastnormaltime
1262
1262
1263 # We need to do full walks when either
1263 # We need to do full walks when either
1264 # - we're listing all clean files, or
1264 # - we're listing all clean files, or
1265 # - match.traversedir does something, because match.traversedir should
1265 # - match.traversedir does something, because match.traversedir should
1266 # be called for every dir in the working dir
1266 # be called for every dir in the working dir
1267 full = listclean or match.traversedir is not None
1267 full = listclean or match.traversedir is not None
1268 for fn, st in pycompat.iteritems(
1268 for fn, st in pycompat.iteritems(
1269 self.walk(match, subrepos, listunknown, listignored, full=full)
1269 self.walk(match, subrepos, listunknown, listignored, full=full)
1270 ):
1270 ):
1271 if not dcontains(fn):
1271 if not dcontains(fn):
1272 if (listignored or mexact(fn)) and dirignore(fn):
1272 if (listignored or mexact(fn)) and dirignore(fn):
1273 if listignored:
1273 if listignored:
1274 iadd(fn)
1274 iadd(fn)
1275 else:
1275 else:
1276 uadd(fn)
1276 uadd(fn)
1277 continue
1277 continue
1278
1278
1279 # This is equivalent to 'state, mode, size, time = dmap[fn]' but not
1279 # This is equivalent to 'state, mode, size, time = dmap[fn]' but not
1280 # written like that for performance reasons. dmap[fn] is not a
1280 # written like that for performance reasons. dmap[fn] is not a
1281 # Python tuple in compiled builds. The CPython UNPACK_SEQUENCE
1281 # Python tuple in compiled builds. The CPython UNPACK_SEQUENCE
1282 # opcode has fast paths when the value to be unpacked is a tuple or
1282 # opcode has fast paths when the value to be unpacked is a tuple or
1283 # a list, but falls back to creating a full-fledged iterator in
1283 # a list, but falls back to creating a full-fledged iterator in
1284 # general. That is much slower than simply accessing and storing the
1284 # general. That is much slower than simply accessing and storing the
1285 # tuple members one by one.
1285 # tuple members one by one.
1286 t = dget(fn)
1286 t = dget(fn)
1287 state = t[0]
1287 state = t[0]
1288 mode = t[1]
1288 mode = t[1]
1289 size = t[2]
1289 size = t[2]
1290 time = t[3]
1290 time = t[3]
1291
1291
1292 if not st and state in b"nma":
1292 if not st and state in b"nma":
1293 dadd(fn)
1293 dadd(fn)
1294 elif state == b'n':
1294 elif state == b'n':
1295 if (
1295 if (
1296 size >= 0
1296 size >= 0
1297 and (
1297 and (
1298 (size != st.st_size and size != st.st_size & _rangemask)
1298 (size != st.st_size and size != st.st_size & _rangemask)
1299 or ((mode ^ st.st_mode) & 0o100 and checkexec)
1299 or ((mode ^ st.st_mode) & 0o100 and checkexec)
1300 )
1300 )
1301 or size == -2 # other parent
1301 or size == -2 # other parent
1302 or fn in copymap
1302 or fn in copymap
1303 ):
1303 ):
1304 if stat.S_ISLNK(st.st_mode) and size != st.st_size:
1304 if stat.S_ISLNK(st.st_mode) and size != st.st_size:
1305 # issue6456: Size returned may be longer due to
1305 # issue6456: Size returned may be longer due to
1306 # encryption on EXT-4 fscrypt, undecided.
1306 # encryption on EXT-4 fscrypt, undecided.
1307 ladd(fn)
1307 ladd(fn)
1308 else:
1308 else:
1309 madd(fn)
1309 madd(fn)
1310 elif (
1310 elif (
1311 time != st[stat.ST_MTIME]
1311 time != st[stat.ST_MTIME]
1312 and time != st[stat.ST_MTIME] & _rangemask
1312 and time != st[stat.ST_MTIME] & _rangemask
1313 ):
1313 ):
1314 ladd(fn)
1314 ladd(fn)
1315 elif st[stat.ST_MTIME] == lastnormaltime:
1315 elif st[stat.ST_MTIME] == lastnormaltime:
1316 # fn may have just been marked as normal and it may have
1316 # fn may have just been marked as normal and it may have
1317 # changed in the same second without changing its size.
1317 # changed in the same second without changing its size.
1318 # This can happen if we quickly do multiple commits.
1318 # This can happen if we quickly do multiple commits.
1319 # Force lookup, so we don't miss such a racy file change.
1319 # Force lookup, so we don't miss such a racy file change.
1320 ladd(fn)
1320 ladd(fn)
1321 elif listclean:
1321 elif listclean:
1322 cadd(fn)
1322 cadd(fn)
1323 elif state == b'm':
1323 elif state == b'm':
1324 madd(fn)
1324 madd(fn)
1325 elif state == b'a':
1325 elif state == b'a':
1326 aadd(fn)
1326 aadd(fn)
1327 elif state == b'r':
1327 elif state == b'r':
1328 radd(fn)
1328 radd(fn)
1329 status = scmutil.status(
1329 status = scmutil.status(
1330 modified, added, removed, deleted, unknown, ignored, clean
1330 modified, added, removed, deleted, unknown, ignored, clean
1331 )
1331 )
1332 return (lookup, status)
1332 return (lookup, status)
1333
1333
1334 def matches(self, match):
1334 def matches(self, match):
1335 """
1335 """
1336 return files in the dirstate (in whatever state) filtered by match
1336 return files in the dirstate (in whatever state) filtered by match
1337 """
1337 """
1338 dmap = self._map
1338 dmap = self._map
1339 if rustmod is not None:
1339 if rustmod is not None:
1340 dmap = self._map._rustmap
1340 dmap = self._map._rustmap
1341
1341
1342 if match.always():
1342 if match.always():
1343 return dmap.keys()
1343 return dmap.keys()
1344 files = match.files()
1344 files = match.files()
1345 if match.isexact():
1345 if match.isexact():
1346 # fast path -- filter the other way around, since typically files is
1346 # fast path -- filter the other way around, since typically files is
1347 # much smaller than dmap
1347 # much smaller than dmap
1348 return [f for f in files if f in dmap]
1348 return [f for f in files if f in dmap]
1349 if match.prefix() and all(fn in dmap for fn in files):
1349 if match.prefix() and all(fn in dmap for fn in files):
1350 # fast path -- all the values are known to be files, so just return
1350 # fast path -- all the values are known to be files, so just return
1351 # that
1351 # that
1352 return list(files)
1352 return list(files)
1353 return [f for f in dmap if match(f)]
1353 return [f for f in dmap if match(f)]
1354
1354
1355 def _actualfilename(self, tr):
1355 def _actualfilename(self, tr):
1356 if tr:
1356 if tr:
1357 return self._pendingfilename
1357 return self._pendingfilename
1358 else:
1358 else:
1359 return self._filename
1359 return self._filename
1360
1360
1361 def savebackup(self, tr, backupname):
1361 def savebackup(self, tr, backupname):
1362 '''Save current dirstate into backup file'''
1362 '''Save current dirstate into backup file'''
1363 filename = self._actualfilename(tr)
1363 filename = self._actualfilename(tr)
1364 assert backupname != filename
1364 assert backupname != filename
1365
1365
1366 # use '_writedirstate' instead of 'write' to write changes certainly,
1366 # use '_writedirstate' instead of 'write' to write changes certainly,
1367 # because the latter omits writing out if transaction is running.
1367 # because the latter omits writing out if transaction is running.
1368 # output file will be used to create backup of dirstate at this point.
1368 # output file will be used to create backup of dirstate at this point.
1369 if self._dirty or not self._opener.exists(filename):
1369 if self._dirty or not self._opener.exists(filename):
1370 self._writedirstate(
1370 self._writedirstate(
1371 self._opener(filename, b"w", atomictemp=True, checkambig=True)
1371 self._opener(filename, b"w", atomictemp=True, checkambig=True)
1372 )
1372 )
1373
1373
1374 if tr:
1374 if tr:
1375 # ensure that subsequent tr.writepending returns True for
1375 # ensure that subsequent tr.writepending returns True for
1376 # changes written out above, even if dirstate is never
1376 # changes written out above, even if dirstate is never
1377 # changed after this
1377 # changed after this
1378 tr.addfilegenerator(
1378 tr.addfilegenerator(
1379 b'dirstate',
1379 b'dirstate',
1380 (self._filename,),
1380 (self._filename,),
1381 self._writedirstate,
1381 self._writedirstate,
1382 location=b'plain',
1382 location=b'plain',
1383 )
1383 )
1384
1384
1385 # ensure that pending file written above is unlinked at
1385 # ensure that pending file written above is unlinked at
1386 # failure, even if tr.writepending isn't invoked until the
1386 # failure, even if tr.writepending isn't invoked until the
1387 # end of this transaction
1387 # end of this transaction
1388 tr.registertmp(filename, location=b'plain')
1388 tr.registertmp(filename, location=b'plain')
1389
1389
1390 self._opener.tryunlink(backupname)
1390 self._opener.tryunlink(backupname)
1391 # hardlink backup is okay because _writedirstate is always called
1391 # hardlink backup is okay because _writedirstate is always called
1392 # with an "atomictemp=True" file.
1392 # with an "atomictemp=True" file.
1393 util.copyfile(
1393 util.copyfile(
1394 self._opener.join(filename),
1394 self._opener.join(filename),
1395 self._opener.join(backupname),
1395 self._opener.join(backupname),
1396 hardlink=True,
1396 hardlink=True,
1397 )
1397 )
1398
1398
1399 def restorebackup(self, tr, backupname):
1399 def restorebackup(self, tr, backupname):
1400 '''Restore dirstate by backup file'''
1400 '''Restore dirstate by backup file'''
1401 # this "invalidate()" prevents "wlock.release()" from writing
1401 # this "invalidate()" prevents "wlock.release()" from writing
1402 # changes of dirstate out after restoring from backup file
1402 # changes of dirstate out after restoring from backup file
1403 self.invalidate()
1403 self.invalidate()
1404 filename = self._actualfilename(tr)
1404 filename = self._actualfilename(tr)
1405 o = self._opener
1405 o = self._opener
1406 if util.samefile(o.join(backupname), o.join(filename)):
1406 if util.samefile(o.join(backupname), o.join(filename)):
1407 o.unlink(backupname)
1407 o.unlink(backupname)
1408 else:
1408 else:
1409 o.rename(backupname, filename, checkambig=True)
1409 o.rename(backupname, filename, checkambig=True)
1410
1410
1411 def clearbackup(self, tr, backupname):
1411 def clearbackup(self, tr, backupname):
1412 '''Clear backup file'''
1412 '''Clear backup file'''
1413 self._opener.unlink(backupname)
1413 self._opener.unlink(backupname)
1414
1414
1415
1415
1416 class dirstatemap(object):
1416 class dirstatemap(object):
1417 """Map encapsulating the dirstate's contents.
1417 """Map encapsulating the dirstate's contents.
1418
1418
1419 The dirstate contains the following state:
1419 The dirstate contains the following state:
1420
1420
1421 - `identity` is the identity of the dirstate file, which can be used to
1421 - `identity` is the identity of the dirstate file, which can be used to
1422 detect when changes have occurred to the dirstate file.
1422 detect when changes have occurred to the dirstate file.
1423
1423
1424 - `parents` is a pair containing the parents of the working copy. The
1424 - `parents` is a pair containing the parents of the working copy. The
1425 parents are updated by calling `setparents`.
1425 parents are updated by calling `setparents`.
1426
1426
1427 - the state map maps filenames to tuples of (state, mode, size, mtime),
1427 - the state map maps filenames to tuples of (state, mode, size, mtime),
1428 where state is a single character representing 'normal', 'added',
1428 where state is a single character representing 'normal', 'added',
1429 'removed', or 'merged'. It is read by treating the dirstate as a
1429 'removed', or 'merged'. It is read by treating the dirstate as a
1430 dict. File state is updated by calling the `addfile`, `removefile` and
1430 dict. File state is updated by calling the `addfile`, `removefile` and
1431 `dropfile` methods.
1431 `dropfile` methods.
1432
1432
1433 - `copymap` maps destination filenames to their source filename.
1433 - `copymap` maps destination filenames to their source filename.
1434
1434
1435 The dirstate also provides the following views onto the state:
1435 The dirstate also provides the following views onto the state:
1436
1436
1437 - `nonnormalset` is a set of the filenames that have state other
1437 - `nonnormalset` is a set of the filenames that have state other
1438 than 'normal', or are normal but have an mtime of -1 ('normallookup').
1438 than 'normal', or are normal but have an mtime of -1 ('normallookup').
1439
1439
1440 - `otherparentset` is a set of the filenames that are marked as coming
1440 - `otherparentset` is a set of the filenames that are marked as coming
1441 from the second parent when the dirstate is currently being merged.
1441 from the second parent when the dirstate is currently being merged.
1442
1442
1443 - `filefoldmap` is a dict mapping normalized filenames to the denormalized
1443 - `filefoldmap` is a dict mapping normalized filenames to the denormalized
1444 form that they appear as in the dirstate.
1444 form that they appear as in the dirstate.
1445
1445
1446 - `dirfoldmap` is a dict mapping normalized directory names to the
1446 - `dirfoldmap` is a dict mapping normalized directory names to the
1447 denormalized form that they appear as in the dirstate.
1447 denormalized form that they appear as in the dirstate.
1448 """
1448 """
1449
1449
1450 def __init__(self, ui, opener, root, nodeconstants, use_dirstate_v2):
1450 def __init__(self, ui, opener, root, nodeconstants, use_dirstate_v2):
1451 self._ui = ui
1451 self._ui = ui
1452 self._opener = opener
1452 self._opener = opener
1453 self._root = root
1453 self._root = root
1454 self._filename = b'dirstate'
1454 self._filename = b'dirstate'
1455 self._nodelen = 20
1455 self._nodelen = 20
1456 self._nodeconstants = nodeconstants
1456 self._nodeconstants = nodeconstants
1457 assert (
1457 assert (
1458 not use_dirstate_v2
1458 not use_dirstate_v2
1459 ), "should have detected unsupported requirement"
1459 ), "should have detected unsupported requirement"
1460
1460
1461 self._parents = None
1461 self._parents = None
1462 self._dirtyparents = False
1462 self._dirtyparents = False
1463
1463
1464 # for consistent view between _pl() and _read() invocations
1464 # for consistent view between _pl() and _read() invocations
1465 self._pendingmode = None
1465 self._pendingmode = None
1466
1466
1467 @propertycache
1467 @propertycache
1468 def _map(self):
1468 def _map(self):
1469 self._map = {}
1469 self._map = {}
1470 self.read()
1470 self.read()
1471 return self._map
1471 return self._map
1472
1472
1473 @propertycache
1473 @propertycache
1474 def copymap(self):
1474 def copymap(self):
1475 self.copymap = {}
1475 self.copymap = {}
1476 self._map
1476 self._map
1477 return self.copymap
1477 return self.copymap
1478
1478
1479 def clear(self):
1479 def clear(self):
1480 self._map.clear()
1480 self._map.clear()
1481 self.copymap.clear()
1481 self.copymap.clear()
1482 self.setparents(self._nodeconstants.nullid, self._nodeconstants.nullid)
1482 self.setparents(self._nodeconstants.nullid, self._nodeconstants.nullid)
1483 util.clearcachedproperty(self, b"_dirs")
1483 util.clearcachedproperty(self, b"_dirs")
1484 util.clearcachedproperty(self, b"_alldirs")
1484 util.clearcachedproperty(self, b"_alldirs")
1485 util.clearcachedproperty(self, b"filefoldmap")
1485 util.clearcachedproperty(self, b"filefoldmap")
1486 util.clearcachedproperty(self, b"dirfoldmap")
1486 util.clearcachedproperty(self, b"dirfoldmap")
1487 util.clearcachedproperty(self, b"nonnormalset")
1487 util.clearcachedproperty(self, b"nonnormalset")
1488 util.clearcachedproperty(self, b"otherparentset")
1488 util.clearcachedproperty(self, b"otherparentset")
1489
1489
1490 def items(self):
1490 def items(self):
1491 return pycompat.iteritems(self._map)
1491 return pycompat.iteritems(self._map)
1492
1492
1493 # forward for python2,3 compat
1493 # forward for python2,3 compat
1494 iteritems = items
1494 iteritems = items
1495
1495
1496 def __len__(self):
1496 def __len__(self):
1497 return len(self._map)
1497 return len(self._map)
1498
1498
1499 def __iter__(self):
1499 def __iter__(self):
1500 return iter(self._map)
1500 return iter(self._map)
1501
1501
1502 def get(self, key, default=None):
1502 def get(self, key, default=None):
1503 return self._map.get(key, default)
1503 return self._map.get(key, default)
1504
1504
1505 def __contains__(self, key):
1505 def __contains__(self, key):
1506 return key in self._map
1506 return key in self._map
1507
1507
1508 def __getitem__(self, key):
1508 def __getitem__(self, key):
1509 return self._map[key]
1509 return self._map[key]
1510
1510
1511 def keys(self):
1511 def keys(self):
1512 return self._map.keys()
1512 return self._map.keys()
1513
1513
1514 def preload(self):
1514 def preload(self):
1515 """Loads the underlying data, if it's not already loaded"""
1515 """Loads the underlying data, if it's not already loaded"""
1516 self._map
1516 self._map
1517
1517
1518 def addfile(self, f, oldstate, state, mode, size, mtime):
1518 def addfile(self, f, oldstate, state, mode, size, mtime):
1519 """Add a tracked file to the dirstate."""
1519 """Add a tracked file to the dirstate."""
1520 if oldstate in b"?r" and "_dirs" in self.__dict__:
1520 if oldstate in b"?r" and "_dirs" in self.__dict__:
1521 self._dirs.addpath(f)
1521 self._dirs.addpath(f)
1522 if oldstate == b"?" and "_alldirs" in self.__dict__:
1522 if oldstate == b"?" and "_alldirs" in self.__dict__:
1523 self._alldirs.addpath(f)
1523 self._alldirs.addpath(f)
1524 self._map[f] = dirstatetuple(state, mode, size, mtime)
1524 self._map[f] = dirstatetuple(state, mode, size, mtime)
1525 if state != b'n' or mtime == -1:
1525 if state != b'n' or mtime == -1:
1526 self.nonnormalset.add(f)
1526 self.nonnormalset.add(f)
1527 if size == -2:
1527 if size == -2:
1528 self.otherparentset.add(f)
1528 self.otherparentset.add(f)
1529
1529
1530 def removefile(self, f, oldstate, size):
1530 def removefile(self, f, oldstate, size):
1531 """
1531 """
1532 Mark a file as removed in the dirstate.
1532 Mark a file as removed in the dirstate.
1533
1533
1534 The `size` parameter is used to store sentinel values that indicate
1534 The `size` parameter is used to store sentinel values that indicate
1535 the file's previous state. In the future, we should refactor this
1535 the file's previous state. In the future, we should refactor this
1536 to be more explicit about what that state is.
1536 to be more explicit about what that state is.
1537 """
1537 """
1538 if oldstate not in b"?r" and "_dirs" in self.__dict__:
1538 if oldstate not in b"?r" and "_dirs" in self.__dict__:
1539 self._dirs.delpath(f)
1539 self._dirs.delpath(f)
1540 if oldstate == b"?" and "_alldirs" in self.__dict__:
1540 if oldstate == b"?" and "_alldirs" in self.__dict__:
1541 self._alldirs.addpath(f)
1541 self._alldirs.addpath(f)
1542 if "filefoldmap" in self.__dict__:
1542 if "filefoldmap" in self.__dict__:
1543 normed = util.normcase(f)
1543 normed = util.normcase(f)
1544 self.filefoldmap.pop(normed, None)
1544 self.filefoldmap.pop(normed, None)
1545 self._map[f] = dirstatetuple(b'r', 0, size, 0)
1545 self._map[f] = dirstatetuple(b'r', 0, size, 0)
1546 self.nonnormalset.add(f)
1546 self.nonnormalset.add(f)
1547
1547
1548 def dropfile(self, f, oldstate):
1548 def dropfile(self, f, oldstate):
1549 """
1549 """
1550 Remove a file from the dirstate. Returns True if the file was
1550 Remove a file from the dirstate. Returns True if the file was
1551 previously recorded.
1551 previously recorded.
1552 """
1552 """
1553 exists = self._map.pop(f, None) is not None
1553 exists = self._map.pop(f, None) is not None
1554 if exists:
1554 if exists:
1555 if oldstate != b"r" and "_dirs" in self.__dict__:
1555 if oldstate != b"r" and "_dirs" in self.__dict__:
1556 self._dirs.delpath(f)
1556 self._dirs.delpath(f)
1557 if "_alldirs" in self.__dict__:
1557 if "_alldirs" in self.__dict__:
1558 self._alldirs.delpath(f)
1558 self._alldirs.delpath(f)
1559 if "filefoldmap" in self.__dict__:
1559 if "filefoldmap" in self.__dict__:
1560 normed = util.normcase(f)
1560 normed = util.normcase(f)
1561 self.filefoldmap.pop(normed, None)
1561 self.filefoldmap.pop(normed, None)
1562 self.nonnormalset.discard(f)
1562 self.nonnormalset.discard(f)
1563 return exists
1563 return exists
1564
1564
1565 def clearambiguoustimes(self, files, now):
1565 def clearambiguoustimes(self, files, now):
1566 for f in files:
1566 for f in files:
1567 e = self.get(f)
1567 e = self.get(f)
1568 if e is not None and e[0] == b'n' and e[3] == now:
1568 if e is not None and e[0] == b'n' and e[3] == now:
1569 self._map[f] = dirstatetuple(e[0], e[1], e[2], -1)
1569 self._map[f] = dirstatetuple(e[0], e[1], e[2], -1)
1570 self.nonnormalset.add(f)
1570 self.nonnormalset.add(f)
1571
1571
1572 def nonnormalentries(self):
1572 def nonnormalentries(self):
1573 '''Compute the nonnormal dirstate entries from the dmap'''
1573 '''Compute the nonnormal dirstate entries from the dmap'''
1574 try:
1574 try:
1575 return parsers.nonnormalotherparententries(self._map)
1575 return parsers.nonnormalotherparententries(self._map)
1576 except AttributeError:
1576 except AttributeError:
1577 nonnorm = set()
1577 nonnorm = set()
1578 otherparent = set()
1578 otherparent = set()
1579 for fname, e in pycompat.iteritems(self._map):
1579 for fname, e in pycompat.iteritems(self._map):
1580 if e[0] != b'n' or e[3] == -1:
1580 if e[0] != b'n' or e[3] == -1:
1581 nonnorm.add(fname)
1581 nonnorm.add(fname)
1582 if e[0] == b'n' and e[2] == -2:
1582 if e[0] == b'n' and e[2] == -2:
1583 otherparent.add(fname)
1583 otherparent.add(fname)
1584 return nonnorm, otherparent
1584 return nonnorm, otherparent
1585
1585
1586 @propertycache
1586 @propertycache
1587 def filefoldmap(self):
1587 def filefoldmap(self):
1588 """Returns a dictionary mapping normalized case paths to their
1588 """Returns a dictionary mapping normalized case paths to their
1589 non-normalized versions.
1589 non-normalized versions.
1590 """
1590 """
1591 try:
1591 try:
1592 makefilefoldmap = parsers.make_file_foldmap
1592 makefilefoldmap = parsers.make_file_foldmap
1593 except AttributeError:
1593 except AttributeError:
1594 pass
1594 pass
1595 else:
1595 else:
1596 return makefilefoldmap(
1596 return makefilefoldmap(
1597 self._map, util.normcasespec, util.normcasefallback
1597 self._map, util.normcasespec, util.normcasefallback
1598 )
1598 )
1599
1599
1600 f = {}
1600 f = {}
1601 normcase = util.normcase
1601 normcase = util.normcase
1602 for name, s in pycompat.iteritems(self._map):
1602 for name, s in pycompat.iteritems(self._map):
1603 if s[0] != b'r':
1603 if s[0] != b'r':
1604 f[normcase(name)] = name
1604 f[normcase(name)] = name
1605 f[b'.'] = b'.' # prevents useless util.fspath() invocation
1605 f[b'.'] = b'.' # prevents useless util.fspath() invocation
1606 return f
1606 return f
1607
1607
1608 def hastrackeddir(self, d):
1608 def hastrackeddir(self, d):
1609 """
1609 """
1610 Returns True if the dirstate contains a tracked (not removed) file
1610 Returns True if the dirstate contains a tracked (not removed) file
1611 in this directory.
1611 in this directory.
1612 """
1612 """
1613 return d in self._dirs
1613 return d in self._dirs
1614
1614
1615 def hasdir(self, d):
1615 def hasdir(self, d):
1616 """
1616 """
1617 Returns True if the dirstate contains a file (tracked or removed)
1617 Returns True if the dirstate contains a file (tracked or removed)
1618 in this directory.
1618 in this directory.
1619 """
1619 """
1620 return d in self._alldirs
1620 return d in self._alldirs
1621
1621
1622 @propertycache
1622 @propertycache
1623 def _dirs(self):
1623 def _dirs(self):
1624 return pathutil.dirs(self._map, b'r')
1624 return pathutil.dirs(self._map, b'r')
1625
1625
1626 @propertycache
1626 @propertycache
1627 def _alldirs(self):
1627 def _alldirs(self):
1628 return pathutil.dirs(self._map)
1628 return pathutil.dirs(self._map)
1629
1629
1630 def _opendirstatefile(self):
1630 def _opendirstatefile(self):
1631 fp, mode = txnutil.trypending(self._root, self._opener, self._filename)
1631 fp, mode = txnutil.trypending(self._root, self._opener, self._filename)
1632 if self._pendingmode is not None and self._pendingmode != mode:
1632 if self._pendingmode is not None and self._pendingmode != mode:
1633 fp.close()
1633 fp.close()
1634 raise error.Abort(
1634 raise error.Abort(
1635 _(b'working directory state may be changed parallelly')
1635 _(b'working directory state may be changed parallelly')
1636 )
1636 )
1637 self._pendingmode = mode
1637 self._pendingmode = mode
1638 return fp
1638 return fp
1639
1639
1640 def parents(self):
1640 def parents(self):
1641 if not self._parents:
1641 if not self._parents:
1642 try:
1642 try:
1643 fp = self._opendirstatefile()
1643 fp = self._opendirstatefile()
1644 st = fp.read(2 * self._nodelen)
1644 st = fp.read(2 * self._nodelen)
1645 fp.close()
1645 fp.close()
1646 except IOError as err:
1646 except IOError as err:
1647 if err.errno != errno.ENOENT:
1647 if err.errno != errno.ENOENT:
1648 raise
1648 raise
1649 # File doesn't exist, so the current state is empty
1649 # File doesn't exist, so the current state is empty
1650 st = b''
1650 st = b''
1651
1651
1652 l = len(st)
1652 l = len(st)
1653 if l == self._nodelen * 2:
1653 if l == self._nodelen * 2:
1654 self._parents = (
1654 self._parents = (
1655 st[: self._nodelen],
1655 st[: self._nodelen],
1656 st[self._nodelen : 2 * self._nodelen],
1656 st[self._nodelen : 2 * self._nodelen],
1657 )
1657 )
1658 elif l == 0:
1658 elif l == 0:
1659 self._parents = (
1659 self._parents = (
1660 self._nodeconstants.nullid,
1660 self._nodeconstants.nullid,
1661 self._nodeconstants.nullid,
1661 self._nodeconstants.nullid,
1662 )
1662 )
1663 else:
1663 else:
1664 raise error.Abort(
1664 raise error.Abort(
1665 _(b'working directory state appears damaged!')
1665 _(b'working directory state appears damaged!')
1666 )
1666 )
1667
1667
1668 return self._parents
1668 return self._parents
1669
1669
1670 def setparents(self, p1, p2):
1670 def setparents(self, p1, p2):
1671 self._parents = (p1, p2)
1671 self._parents = (p1, p2)
1672 self._dirtyparents = True
1672 self._dirtyparents = True
1673
1673
1674 def read(self):
1674 def read(self):
1675 # ignore HG_PENDING because identity is used only for writing
1675 # ignore HG_PENDING because identity is used only for writing
1676 self.identity = util.filestat.frompath(
1676 self.identity = util.filestat.frompath(
1677 self._opener.join(self._filename)
1677 self._opener.join(self._filename)
1678 )
1678 )
1679
1679
1680 try:
1680 try:
1681 fp = self._opendirstatefile()
1681 fp = self._opendirstatefile()
1682 try:
1682 try:
1683 st = fp.read()
1683 st = fp.read()
1684 finally:
1684 finally:
1685 fp.close()
1685 fp.close()
1686 except IOError as err:
1686 except IOError as err:
1687 if err.errno != errno.ENOENT:
1687 if err.errno != errno.ENOENT:
1688 raise
1688 raise
1689 return
1689 return
1690 if not st:
1690 if not st:
1691 return
1691 return
1692
1692
1693 if util.safehasattr(parsers, b'dict_new_presized'):
1693 if util.safehasattr(parsers, b'dict_new_presized'):
1694 # Make an estimate of the number of files in the dirstate based on
1694 # Make an estimate of the number of files in the dirstate based on
1695 # its size. This trades wasting some memory for avoiding costly
1695 # its size. This trades wasting some memory for avoiding costly
1696 # resizes. Each entry have a prefix of 17 bytes followed by one or
1696 # resizes. Each entry have a prefix of 17 bytes followed by one or
1697 # two path names. Studies on various large-scale real-world repositories
1697 # two path names. Studies on various large-scale real-world repositories
1698 # found 54 bytes a reasonable upper limit for the average path names.
1698 # found 54 bytes a reasonable upper limit for the average path names.
1699 # Copy entries are ignored for the sake of this estimate.
1699 # Copy entries are ignored for the sake of this estimate.
1700 self._map = parsers.dict_new_presized(len(st) // 71)
1700 self._map = parsers.dict_new_presized(len(st) // 71)
1701
1701
1702 # Python's garbage collector triggers a GC each time a certain number
1702 # Python's garbage collector triggers a GC each time a certain number
1703 # of container objects (the number being defined by
1703 # of container objects (the number being defined by
1704 # gc.get_threshold()) are allocated. parse_dirstate creates a tuple
1704 # gc.get_threshold()) are allocated. parse_dirstate creates a tuple
1705 # for each file in the dirstate. The C version then immediately marks
1705 # for each file in the dirstate. The C version then immediately marks
1706 # them as not to be tracked by the collector. However, this has no
1706 # them as not to be tracked by the collector. However, this has no
1707 # effect on when GCs are triggered, only on what objects the GC looks
1707 # effect on when GCs are triggered, only on what objects the GC looks
1708 # into. This means that O(number of files) GCs are unavoidable.
1708 # into. This means that O(number of files) GCs are unavoidable.
1709 # Depending on when in the process's lifetime the dirstate is parsed,
1709 # Depending on when in the process's lifetime the dirstate is parsed,
1710 # this can get very expensive. As a workaround, disable GC while
1710 # this can get very expensive. As a workaround, disable GC while
1711 # parsing the dirstate.
1711 # parsing the dirstate.
1712 #
1712 #
1713 # (we cannot decorate the function directly since it is in a C module)
1713 # (we cannot decorate the function directly since it is in a C module)
1714 parse_dirstate = util.nogc(parsers.parse_dirstate)
1714 parse_dirstate = util.nogc(parsers.parse_dirstate)
1715 p = parse_dirstate(self._map, self.copymap, st)
1715 p = parse_dirstate(self._map, self.copymap, st)
1716 if not self._dirtyparents:
1716 if not self._dirtyparents:
1717 self.setparents(*p)
1717 self.setparents(*p)
1718
1718
1719 # Avoid excess attribute lookups by fast pathing certain checks
1719 # Avoid excess attribute lookups by fast pathing certain checks
1720 self.__contains__ = self._map.__contains__
1720 self.__contains__ = self._map.__contains__
1721 self.__getitem__ = self._map.__getitem__
1721 self.__getitem__ = self._map.__getitem__
1722 self.get = self._map.get
1722 self.get = self._map.get
1723
1723
1724 def write(self, st, now):
1724 def write(self, st, now):
1725 st.write(
1725 st.write(
1726 parsers.pack_dirstate(self._map, self.copymap, self.parents(), now)
1726 parsers.pack_dirstate(self._map, self.copymap, self.parents(), now)
1727 )
1727 )
1728 st.close()
1728 st.close()
1729 self._dirtyparents = False
1729 self._dirtyparents = False
1730 self.nonnormalset, self.otherparentset = self.nonnormalentries()
1730 self.nonnormalset, self.otherparentset = self.nonnormalentries()
1731
1731
1732 @propertycache
1732 @propertycache
1733 def nonnormalset(self):
1733 def nonnormalset(self):
1734 nonnorm, otherparents = self.nonnormalentries()
1734 nonnorm, otherparents = self.nonnormalentries()
1735 self.otherparentset = otherparents
1735 self.otherparentset = otherparents
1736 return nonnorm
1736 return nonnorm
1737
1737
1738 @propertycache
1738 @propertycache
1739 def otherparentset(self):
1739 def otherparentset(self):
1740 nonnorm, otherparents = self.nonnormalentries()
1740 nonnorm, otherparents = self.nonnormalentries()
1741 self.nonnormalset = nonnorm
1741 self.nonnormalset = nonnorm
1742 return otherparents
1742 return otherparents
1743
1743
1744 def non_normal_or_other_parent_paths(self):
1744 def non_normal_or_other_parent_paths(self):
1745 return self.nonnormalset.union(self.otherparentset)
1745 return self.nonnormalset.union(self.otherparentset)
1746
1746
1747 @propertycache
1747 @propertycache
1748 def identity(self):
1748 def identity(self):
1749 self._map
1749 self._map
1750 return self.identity
1750 return self.identity
1751
1751
1752 @propertycache
1752 @propertycache
1753 def dirfoldmap(self):
1753 def dirfoldmap(self):
1754 f = {}
1754 f = {}
1755 normcase = util.normcase
1755 normcase = util.normcase
1756 for name in self._dirs:
1756 for name in self._dirs:
1757 f[normcase(name)] = name
1757 f[normcase(name)] = name
1758 return f
1758 return f
1759
1759
1760
1760
1761 if rustmod is not None:
1761 if rustmod is not None:
1762
1762
1763 class dirstatemap(object):
1763 class dirstatemap(object):
1764 def __init__(self, ui, opener, root, nodeconstants, use_dirstate_v2):
1764 def __init__(self, ui, opener, root, nodeconstants, use_dirstate_v2):
1765 self._use_dirstate_v2 = use_dirstate_v2
1765 self._use_dirstate_v2 = use_dirstate_v2
1766 self._nodeconstants = nodeconstants
1766 self._nodeconstants = nodeconstants
1767 self._ui = ui
1767 self._ui = ui
1768 self._opener = opener
1768 self._opener = opener
1769 self._root = root
1769 self._root = root
1770 self._filename = b'dirstate'
1770 self._filename = b'dirstate'
1771 self._nodelen = 20 # Also update Rust code when changing this!
1771 self._nodelen = 20 # Also update Rust code when changing this!
1772 self._parents = None
1772 self._parents = None
1773 self._dirtyparents = False
1773 self._dirtyparents = False
1774
1774
1775 # for consistent view between _pl() and _read() invocations
1775 # for consistent view between _pl() and _read() invocations
1776 self._pendingmode = None
1776 self._pendingmode = None
1777
1777
1778 self._use_dirstate_tree = self._ui.configbool(
1779 b"experimental",
1780 b"dirstate-tree.in-memory",
1781 False,
1782 )
1783
1778 def addfile(self, *args, **kwargs):
1784 def addfile(self, *args, **kwargs):
1779 return self._rustmap.addfile(*args, **kwargs)
1785 return self._rustmap.addfile(*args, **kwargs)
1780
1786
1781 def removefile(self, *args, **kwargs):
1787 def removefile(self, *args, **kwargs):
1782 return self._rustmap.removefile(*args, **kwargs)
1788 return self._rustmap.removefile(*args, **kwargs)
1783
1789
1784 def dropfile(self, *args, **kwargs):
1790 def dropfile(self, *args, **kwargs):
1785 return self._rustmap.dropfile(*args, **kwargs)
1791 return self._rustmap.dropfile(*args, **kwargs)
1786
1792
1787 def clearambiguoustimes(self, *args, **kwargs):
1793 def clearambiguoustimes(self, *args, **kwargs):
1788 return self._rustmap.clearambiguoustimes(*args, **kwargs)
1794 return self._rustmap.clearambiguoustimes(*args, **kwargs)
1789
1795
1790 def nonnormalentries(self):
1796 def nonnormalentries(self):
1791 return self._rustmap.nonnormalentries()
1797 return self._rustmap.nonnormalentries()
1792
1798
1793 def get(self, *args, **kwargs):
1799 def get(self, *args, **kwargs):
1794 return self._rustmap.get(*args, **kwargs)
1800 return self._rustmap.get(*args, **kwargs)
1795
1801
1796 @property
1802 @property
1797 def copymap(self):
1803 def copymap(self):
1798 return self._rustmap.copymap()
1804 return self._rustmap.copymap()
1799
1805
1800 def preload(self):
1806 def preload(self):
1801 self._rustmap
1807 self._rustmap
1802
1808
1803 def clear(self):
1809 def clear(self):
1804 self._rustmap.clear()
1810 self._rustmap.clear()
1805 self.setparents(
1811 self.setparents(
1806 self._nodeconstants.nullid, self._nodeconstants.nullid
1812 self._nodeconstants.nullid, self._nodeconstants.nullid
1807 )
1813 )
1808 util.clearcachedproperty(self, b"_dirs")
1814 util.clearcachedproperty(self, b"_dirs")
1809 util.clearcachedproperty(self, b"_alldirs")
1815 util.clearcachedproperty(self, b"_alldirs")
1810 util.clearcachedproperty(self, b"dirfoldmap")
1816 util.clearcachedproperty(self, b"dirfoldmap")
1811
1817
1812 def items(self):
1818 def items(self):
1813 return self._rustmap.items()
1819 return self._rustmap.items()
1814
1820
1815 def keys(self):
1821 def keys(self):
1816 return iter(self._rustmap)
1822 return iter(self._rustmap)
1817
1823
1818 def __contains__(self, key):
1824 def __contains__(self, key):
1819 return key in self._rustmap
1825 return key in self._rustmap
1820
1826
1821 def __getitem__(self, item):
1827 def __getitem__(self, item):
1822 return self._rustmap[item]
1828 return self._rustmap[item]
1823
1829
1824 def __len__(self):
1830 def __len__(self):
1825 return len(self._rustmap)
1831 return len(self._rustmap)
1826
1832
1827 def __iter__(self):
1833 def __iter__(self):
1828 return iter(self._rustmap)
1834 return iter(self._rustmap)
1829
1835
1830 # forward for python2,3 compat
1836 # forward for python2,3 compat
1831 iteritems = items
1837 iteritems = items
1832
1838
1833 def _opendirstatefile(self):
1839 def _opendirstatefile(self):
1834 fp, mode = txnutil.trypending(
1840 fp, mode = txnutil.trypending(
1835 self._root, self._opener, self._filename
1841 self._root, self._opener, self._filename
1836 )
1842 )
1837 if self._pendingmode is not None and self._pendingmode != mode:
1843 if self._pendingmode is not None and self._pendingmode != mode:
1838 fp.close()
1844 fp.close()
1839 raise error.Abort(
1845 raise error.Abort(
1840 _(b'working directory state may be changed parallelly')
1846 _(b'working directory state may be changed parallelly')
1841 )
1847 )
1842 self._pendingmode = mode
1848 self._pendingmode = mode
1843 return fp
1849 return fp
1844
1850
1845 def setparents(self, p1, p2):
1851 def setparents(self, p1, p2):
1846 self._parents = (p1, p2)
1852 self._parents = (p1, p2)
1847 self._dirtyparents = True
1853 self._dirtyparents = True
1848
1854
1849 def parents(self):
1855 def parents(self):
1850 if not self._parents:
1856 if not self._parents:
1851 if self._use_dirstate_v2:
1857 if self._use_dirstate_v2:
1852 offset = len(rustmod.V2_FORMAT_MARKER)
1858 offset = len(rustmod.V2_FORMAT_MARKER)
1853 else:
1859 else:
1854 offset = 0
1860 offset = 0
1855 read_len = offset + self._nodelen * 2
1861 read_len = offset + self._nodelen * 2
1856 try:
1862 try:
1857 fp = self._opendirstatefile()
1863 fp = self._opendirstatefile()
1858 st = fp.read(read_len)
1864 st = fp.read(read_len)
1859 fp.close()
1865 fp.close()
1860 except IOError as err:
1866 except IOError as err:
1861 if err.errno != errno.ENOENT:
1867 if err.errno != errno.ENOENT:
1862 raise
1868 raise
1863 # File doesn't exist, so the current state is empty
1869 # File doesn't exist, so the current state is empty
1864 st = b''
1870 st = b''
1865
1871
1866 l = len(st)
1872 l = len(st)
1867 if l == read_len:
1873 if l == read_len:
1868 st = st[offset:]
1874 st = st[offset:]
1869 self._parents = (
1875 self._parents = (
1870 st[: self._nodelen],
1876 st[: self._nodelen],
1871 st[self._nodelen : 2 * self._nodelen],
1877 st[self._nodelen : 2 * self._nodelen],
1872 )
1878 )
1873 elif l == 0:
1879 elif l == 0:
1874 self._parents = (
1880 self._parents = (
1875 self._nodeconstants.nullid,
1881 self._nodeconstants.nullid,
1876 self._nodeconstants.nullid,
1882 self._nodeconstants.nullid,
1877 )
1883 )
1878 else:
1884 else:
1879 raise error.Abort(
1885 raise error.Abort(
1880 _(b'working directory state appears damaged!')
1886 _(b'working directory state appears damaged!')
1881 )
1887 )
1882
1888
1883 return self._parents
1889 return self._parents
1884
1890
1885 @propertycache
1891 @propertycache
1886 def _rustmap(self):
1892 def _rustmap(self):
1887 """
1893 """
1888 Fills the Dirstatemap when called.
1894 Fills the Dirstatemap when called.
1889 """
1895 """
1890 # ignore HG_PENDING because identity is used only for writing
1896 # ignore HG_PENDING because identity is used only for writing
1891 self.identity = util.filestat.frompath(
1897 self.identity = util.filestat.frompath(
1892 self._opener.join(self._filename)
1898 self._opener.join(self._filename)
1893 )
1899 )
1894
1900
1895 try:
1901 try:
1896 fp = self._opendirstatefile()
1902 fp = self._opendirstatefile()
1897 try:
1903 try:
1898 st = fp.read()
1904 st = fp.read()
1899 finally:
1905 finally:
1900 fp.close()
1906 fp.close()
1901 except IOError as err:
1907 except IOError as err:
1902 if err.errno != errno.ENOENT:
1908 if err.errno != errno.ENOENT:
1903 raise
1909 raise
1904 st = b''
1910 st = b''
1905
1911
1906 use_dirstate_tree = self._ui.configbool(
1907 b"experimental",
1908 b"dirstate-tree.in-memory",
1909 False,
1910 )
1911 self._rustmap, parents = rustmod.DirstateMap.new(
1912 self._rustmap, parents = rustmod.DirstateMap.new(
1912 use_dirstate_tree, self._use_dirstate_v2, st
1913 self._use_dirstate_tree, self._use_dirstate_v2, st
1913 )
1914 )
1914
1915
1915 if parents and not self._dirtyparents:
1916 if parents and not self._dirtyparents:
1916 self.setparents(*parents)
1917 self.setparents(*parents)
1917
1918
1918 self.__contains__ = self._rustmap.__contains__
1919 self.__contains__ = self._rustmap.__contains__
1919 self.__getitem__ = self._rustmap.__getitem__
1920 self.__getitem__ = self._rustmap.__getitem__
1920 self.get = self._rustmap.get
1921 self.get = self._rustmap.get
1921 return self._rustmap
1922 return self._rustmap
1922
1923
1923 def write(self, st, now):
1924 def write(self, st, now):
1924 parents = self.parents()
1925 parents = self.parents()
1925 packed = self._rustmap.write(
1926 packed = self._rustmap.write(
1926 self._use_dirstate_v2, parents[0], parents[1], now
1927 self._use_dirstate_v2, parents[0], parents[1], now
1927 )
1928 )
1928 st.write(packed)
1929 st.write(packed)
1929 st.close()
1930 st.close()
1930 self._dirtyparents = False
1931 self._dirtyparents = False
1931
1932
1932 @propertycache
1933 @propertycache
1933 def filefoldmap(self):
1934 def filefoldmap(self):
1934 """Returns a dictionary mapping normalized case paths to their
1935 """Returns a dictionary mapping normalized case paths to their
1935 non-normalized versions.
1936 non-normalized versions.
1936 """
1937 """
1937 return self._rustmap.filefoldmapasdict()
1938 return self._rustmap.filefoldmapasdict()
1938
1939
1939 def hastrackeddir(self, d):
1940 def hastrackeddir(self, d):
1940 self._dirs # Trigger Python's propertycache
1941 self._dirs # Trigger Python's propertycache
1941 return self._rustmap.hastrackeddir(d)
1942 return self._rustmap.hastrackeddir(d)
1942
1943
1943 def hasdir(self, d):
1944 def hasdir(self, d):
1944 self._dirs # Trigger Python's propertycache
1945 self._dirs # Trigger Python's propertycache
1945 return self._rustmap.hasdir(d)
1946 return self._rustmap.hasdir(d)
1946
1947
1947 @propertycache
1948 @propertycache
1948 def _dirs(self):
1949 def _dirs(self):
1949 return self._rustmap.getdirs()
1950 return self._rustmap.getdirs()
1950
1951
1951 @propertycache
1952 @propertycache
1952 def _alldirs(self):
1953 def _alldirs(self):
1953 return self._rustmap.getalldirs()
1954 return self._rustmap.getalldirs()
1954
1955
1955 @propertycache
1956 @propertycache
1956 def identity(self):
1957 def identity(self):
1957 self._rustmap
1958 self._rustmap
1958 return self.identity
1959 return self.identity
1959
1960
1960 @property
1961 @property
1961 def nonnormalset(self):
1962 def nonnormalset(self):
1962 nonnorm = self._rustmap.non_normal_entries()
1963 nonnorm = self._rustmap.non_normal_entries()
1963 return nonnorm
1964 return nonnorm
1964
1965
1965 @propertycache
1966 @propertycache
1966 def otherparentset(self):
1967 def otherparentset(self):
1967 otherparents = self._rustmap.other_parent_entries()
1968 otherparents = self._rustmap.other_parent_entries()
1968 return otherparents
1969 return otherparents
1969
1970
1970 def non_normal_or_other_parent_paths(self):
1971 def non_normal_or_other_parent_paths(self):
1971 return self._rustmap.non_normal_or_other_parent_paths()
1972 return self._rustmap.non_normal_or_other_parent_paths()
1972
1973
1973 @propertycache
1974 @propertycache
1974 def dirfoldmap(self):
1975 def dirfoldmap(self):
1975 f = {}
1976 f = {}
1976 normcase = util.normcase
1977 normcase = util.normcase
1977 for name in self._dirs:
1978 for name in self._dirs:
1978 f[normcase(name)] = name
1979 f[normcase(name)] = name
1979 return f
1980 return f
@@ -1,1008 +1,1049 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 from __future__ import absolute_import
8 from __future__ import absolute_import
9
9
10 from ..i18n import _
10 from ..i18n import _
11 from .. import (
11 from .. import (
12 error,
12 error,
13 localrepo,
13 localrepo,
14 pycompat,
14 pycompat,
15 requirements,
15 requirements,
16 revlog,
16 revlog,
17 util,
17 util,
18 )
18 )
19
19
20 from ..utils import compression
20 from ..utils import compression
21
21
22 if pycompat.TYPE_CHECKING:
22 if pycompat.TYPE_CHECKING:
23 from typing import (
23 from typing import (
24 List,
24 List,
25 Type,
25 Type,
26 )
26 )
27
27
28
28
29 # list of requirements that request a clone of all revlog if added/removed
29 # list of requirements that request a clone of all revlog if added/removed
30 RECLONES_REQUIREMENTS = {
30 RECLONES_REQUIREMENTS = {
31 requirements.GENERALDELTA_REQUIREMENT,
31 requirements.GENERALDELTA_REQUIREMENT,
32 requirements.SPARSEREVLOG_REQUIREMENT,
32 requirements.SPARSEREVLOG_REQUIREMENT,
33 requirements.REVLOGV2_REQUIREMENT,
33 requirements.REVLOGV2_REQUIREMENT,
34 requirements.CHANGELOGV2_REQUIREMENT,
34 requirements.CHANGELOGV2_REQUIREMENT,
35 }
35 }
36
36
37
37
38 def preservedrequirements(repo):
38 def preservedrequirements(repo):
39 return set()
39 return set()
40
40
41
41
42 FORMAT_VARIANT = b'deficiency'
42 FORMAT_VARIANT = b'deficiency'
43 OPTIMISATION = b'optimization'
43 OPTIMISATION = b'optimization'
44
44
45
45
46 class improvement(object):
46 class improvement(object):
47 """Represents an improvement that can be made as part of an upgrade."""
47 """Represents an improvement that can be made as part of an upgrade."""
48
48
49 ### The following attributes should be defined for each subclass:
49 ### The following attributes should be defined for each subclass:
50
50
51 # Either ``FORMAT_VARIANT`` or ``OPTIMISATION``.
51 # Either ``FORMAT_VARIANT`` or ``OPTIMISATION``.
52 # A format variant is where we change the storage format. Not all format
52 # A format variant is where we change the storage format. Not all format
53 # variant changes are an obvious problem.
53 # variant changes are an obvious problem.
54 # An optimization is an action (sometimes optional) that
54 # An optimization is an action (sometimes optional) that
55 # can be taken to further improve the state of the repository.
55 # can be taken to further improve the state of the repository.
56 type = None
56 type = None
57
57
58 # machine-readable string uniquely identifying this improvement. it will be
58 # machine-readable string uniquely identifying this improvement. it will be
59 # mapped to an action later in the upgrade process.
59 # mapped to an action later in the upgrade process.
60 name = None
60 name = None
61
61
62 # message intended for humans explaining the improvement in more detail,
62 # message intended for humans explaining the improvement in more detail,
63 # including the implications of it ``FORMAT_VARIANT`` types, should be
63 # including the implications of it ``FORMAT_VARIANT`` types, should be
64 # worded
64 # worded
65 # in the present tense.
65 # in the present tense.
66 description = None
66 description = None
67
67
68 # message intended for humans explaining what an upgrade addressing this
68 # message intended for humans explaining what an upgrade addressing this
69 # issue will do. should be worded in the future tense.
69 # issue will do. should be worded in the future tense.
70 upgrademessage = None
70 upgrademessage = None
71
71
72 # value of current Mercurial default for new repository
72 # value of current Mercurial default for new repository
73 default = None
73 default = None
74
74
75 # Message intended for humans which will be shown post an upgrade
75 # Message intended for humans which will be shown post an upgrade
76 # operation when the improvement will be added
76 # operation when the improvement will be added
77 postupgrademessage = None
77 postupgrademessage = None
78
78
79 # Message intended for humans which will be shown post an upgrade
79 # Message intended for humans which will be shown post an upgrade
80 # operation in which this improvement was removed
80 # operation in which this improvement was removed
81 postdowngrademessage = None
81 postdowngrademessage = None
82
82
83 # By default for now, we assume every improvement touches all the things
83 # By default we assume that every improvement touches requirements and all revlogs
84
84
85 # Whether this improvement touches filelogs
85 # Whether this improvement touches filelogs
86 touches_filelogs = True
86 touches_filelogs = True
87
87
88 # Whether this improvement touches manifests
88 # Whether this improvement touches manifests
89 touches_manifests = True
89 touches_manifests = True
90
90
91 # Whether this improvement touches changelog
91 # Whether this improvement touches changelog
92 touches_changelog = True
92 touches_changelog = True
93
93
94 # Whether this improvement changes repository requirements
94 # Whether this improvement changes repository requirements
95 touches_requirements = True
95 touches_requirements = True
96
96
97 # Whether this improvement touches the dirstate
98 touches_dirstate = False
99
97
100
98 allformatvariant = [] # type: List[Type['formatvariant']]
101 allformatvariant = [] # type: List[Type['formatvariant']]
99
102
100
103
101 def registerformatvariant(cls):
104 def registerformatvariant(cls):
102 allformatvariant.append(cls)
105 allformatvariant.append(cls)
103 return cls
106 return cls
104
107
105
108
106 class formatvariant(improvement):
109 class formatvariant(improvement):
107 """an improvement subclass dedicated to repository format"""
110 """an improvement subclass dedicated to repository format"""
108
111
109 type = FORMAT_VARIANT
112 type = FORMAT_VARIANT
110
113
111 @staticmethod
114 @staticmethod
112 def fromrepo(repo):
115 def fromrepo(repo):
113 """current value of the variant in the repository"""
116 """current value of the variant in the repository"""
114 raise NotImplementedError()
117 raise NotImplementedError()
115
118
116 @staticmethod
119 @staticmethod
117 def fromconfig(repo):
120 def fromconfig(repo):
118 """current value of the variant in the configuration"""
121 """current value of the variant in the configuration"""
119 raise NotImplementedError()
122 raise NotImplementedError()
120
123
121
124
122 class requirementformatvariant(formatvariant):
125 class requirementformatvariant(formatvariant):
123 """formatvariant based on a 'requirement' name.
126 """formatvariant based on a 'requirement' name.
124
127
125 Many format variant are controlled by a 'requirement'. We define a small
128 Many format variant are controlled by a 'requirement'. We define a small
126 subclass to factor the code.
129 subclass to factor the code.
127 """
130 """
128
131
129 # the requirement that control this format variant
132 # the requirement that control this format variant
130 _requirement = None
133 _requirement = None
131
134
132 @staticmethod
135 @staticmethod
133 def _newreporequirements(ui):
136 def _newreporequirements(ui):
134 return localrepo.newreporequirements(
137 return localrepo.newreporequirements(
135 ui, localrepo.defaultcreateopts(ui)
138 ui, localrepo.defaultcreateopts(ui)
136 )
139 )
137
140
138 @classmethod
141 @classmethod
139 def fromrepo(cls, repo):
142 def fromrepo(cls, repo):
140 assert cls._requirement is not None
143 assert cls._requirement is not None
141 return cls._requirement in repo.requirements
144 return cls._requirement in repo.requirements
142
145
143 @classmethod
146 @classmethod
144 def fromconfig(cls, repo):
147 def fromconfig(cls, repo):
145 assert cls._requirement is not None
148 assert cls._requirement is not None
146 return cls._requirement in cls._newreporequirements(repo.ui)
149 return cls._requirement in cls._newreporequirements(repo.ui)
147
150
148
151
149 @registerformatvariant
152 @registerformatvariant
150 class fncache(requirementformatvariant):
153 class fncache(requirementformatvariant):
151 name = b'fncache'
154 name = b'fncache'
152
155
153 _requirement = requirements.FNCACHE_REQUIREMENT
156 _requirement = requirements.FNCACHE_REQUIREMENT
154
157
155 default = True
158 default = True
156
159
157 description = _(
160 description = _(
158 b'long and reserved filenames may not work correctly; '
161 b'long and reserved filenames may not work correctly; '
159 b'repository performance is sub-optimal'
162 b'repository performance is sub-optimal'
160 )
163 )
161
164
162 upgrademessage = _(
165 upgrademessage = _(
163 b'repository will be more resilient to storing '
166 b'repository will be more resilient to storing '
164 b'certain paths and performance of certain '
167 b'certain paths and performance of certain '
165 b'operations should be improved'
168 b'operations should be improved'
166 )
169 )
167
170
168
171
169 @registerformatvariant
172 @registerformatvariant
173 class dirstatev2(requirementformatvariant):
174 name = b'dirstate-v2'
175 _requirement = requirements.DIRSTATE_V2_REQUIREMENT
176
177 default = False
178
179 description = _(
180 b'version 1 of the dirstate file format requires '
181 b'reading and parsing it all at once.'
182 )
183
184 upgrademessage = _(b'"hg status" will be faster')
185
186 touches_filelogs = False
187 touches_manifests = False
188 touches_changelog = False
189 touches_requirements = True
190 touches_dirstate = True
191
192
193 @registerformatvariant
170 class dotencode(requirementformatvariant):
194 class dotencode(requirementformatvariant):
171 name = b'dotencode'
195 name = b'dotencode'
172
196
173 _requirement = requirements.DOTENCODE_REQUIREMENT
197 _requirement = requirements.DOTENCODE_REQUIREMENT
174
198
175 default = True
199 default = True
176
200
177 description = _(
201 description = _(
178 b'storage of filenames beginning with a period or '
202 b'storage of filenames beginning with a period or '
179 b'space may not work correctly'
203 b'space may not work correctly'
180 )
204 )
181
205
182 upgrademessage = _(
206 upgrademessage = _(
183 b'repository will be better able to store files '
207 b'repository will be better able to store files '
184 b'beginning with a space or period'
208 b'beginning with a space or period'
185 )
209 )
186
210
187
211
188 @registerformatvariant
212 @registerformatvariant
189 class generaldelta(requirementformatvariant):
213 class generaldelta(requirementformatvariant):
190 name = b'generaldelta'
214 name = b'generaldelta'
191
215
192 _requirement = requirements.GENERALDELTA_REQUIREMENT
216 _requirement = requirements.GENERALDELTA_REQUIREMENT
193
217
194 default = True
218 default = True
195
219
196 description = _(
220 description = _(
197 b'deltas within internal storage are unable to '
221 b'deltas within internal storage are unable to '
198 b'choose optimal revisions; repository is larger and '
222 b'choose optimal revisions; repository is larger and '
199 b'slower than it could be; interaction with other '
223 b'slower than it could be; interaction with other '
200 b'repositories may require extra network and CPU '
224 b'repositories may require extra network and CPU '
201 b'resources, making "hg push" and "hg pull" slower'
225 b'resources, making "hg push" and "hg pull" slower'
202 )
226 )
203
227
204 upgrademessage = _(
228 upgrademessage = _(
205 b'repository storage will be able to create '
229 b'repository storage will be able to create '
206 b'optimal deltas; new repository data will be '
230 b'optimal deltas; new repository data will be '
207 b'smaller and read times should decrease; '
231 b'smaller and read times should decrease; '
208 b'interacting with other repositories using this '
232 b'interacting with other repositories using this '
209 b'storage model should require less network and '
233 b'storage model should require less network and '
210 b'CPU resources, making "hg push" and "hg pull" '
234 b'CPU resources, making "hg push" and "hg pull" '
211 b'faster'
235 b'faster'
212 )
236 )
213
237
214
238
215 @registerformatvariant
239 @registerformatvariant
216 class sharesafe(requirementformatvariant):
240 class sharesafe(requirementformatvariant):
217 name = b'share-safe'
241 name = b'share-safe'
218 _requirement = requirements.SHARESAFE_REQUIREMENT
242 _requirement = requirements.SHARESAFE_REQUIREMENT
219
243
220 default = False
244 default = False
221
245
222 description = _(
246 description = _(
223 b'old shared repositories do not share source repository '
247 b'old shared repositories do not share source repository '
224 b'requirements and config. This leads to various problems '
248 b'requirements and config. This leads to various problems '
225 b'when the source repository format is upgraded or some new '
249 b'when the source repository format is upgraded or some new '
226 b'extensions are enabled.'
250 b'extensions are enabled.'
227 )
251 )
228
252
229 upgrademessage = _(
253 upgrademessage = _(
230 b'Upgrades a repository to share-safe format so that future '
254 b'Upgrades a repository to share-safe format so that future '
231 b'shares of this repository share its requirements and configs.'
255 b'shares of this repository share its requirements and configs.'
232 )
256 )
233
257
234 postdowngrademessage = _(
258 postdowngrademessage = _(
235 b'repository downgraded to not use share safe mode, '
259 b'repository downgraded to not use share safe mode, '
236 b'existing shares will not work and needs to'
260 b'existing shares will not work and needs to'
237 b' be reshared.'
261 b' be reshared.'
238 )
262 )
239
263
240 postupgrademessage = _(
264 postupgrademessage = _(
241 b'repository upgraded to share safe mode, existing'
265 b'repository upgraded to share safe mode, existing'
242 b' shares will still work in old non-safe mode. '
266 b' shares will still work in old non-safe mode. '
243 b'Re-share existing shares to use them in safe mode'
267 b'Re-share existing shares to use them in safe mode'
244 b' New shares will be created in safe mode.'
268 b' New shares will be created in safe mode.'
245 )
269 )
246
270
247 # upgrade only needs to change the requirements
271 # upgrade only needs to change the requirements
248 touches_filelogs = False
272 touches_filelogs = False
249 touches_manifests = False
273 touches_manifests = False
250 touches_changelog = False
274 touches_changelog = False
251 touches_requirements = True
275 touches_requirements = True
252
276
253
277
254 @registerformatvariant
278 @registerformatvariant
255 class sparserevlog(requirementformatvariant):
279 class sparserevlog(requirementformatvariant):
256 name = b'sparserevlog'
280 name = b'sparserevlog'
257
281
258 _requirement = requirements.SPARSEREVLOG_REQUIREMENT
282 _requirement = requirements.SPARSEREVLOG_REQUIREMENT
259
283
260 default = True
284 default = True
261
285
262 description = _(
286 description = _(
263 b'in order to limit disk reading and memory usage on older '
287 b'in order to limit disk reading and memory usage on older '
264 b'version, the span of a delta chain from its root to its '
288 b'version, the span of a delta chain from its root to its '
265 b'end is limited, whatever the relevant data in this span. '
289 b'end is limited, whatever the relevant data in this span. '
266 b'This can severly limit Mercurial ability to build good '
290 b'This can severly limit Mercurial ability to build good '
267 b'chain of delta resulting is much more storage space being '
291 b'chain of delta resulting is much more storage space being '
268 b'taken and limit reusability of on disk delta during '
292 b'taken and limit reusability of on disk delta during '
269 b'exchange.'
293 b'exchange.'
270 )
294 )
271
295
272 upgrademessage = _(
296 upgrademessage = _(
273 b'Revlog supports delta chain with more unused data '
297 b'Revlog supports delta chain with more unused data '
274 b'between payload. These gaps will be skipped at read '
298 b'between payload. These gaps will be skipped at read '
275 b'time. This allows for better delta chains, making a '
299 b'time. This allows for better delta chains, making a '
276 b'better compression and faster exchange with server.'
300 b'better compression and faster exchange with server.'
277 )
301 )
278
302
279
303
280 @registerformatvariant
304 @registerformatvariant
281 class persistentnodemap(requirementformatvariant):
305 class persistentnodemap(requirementformatvariant):
282 name = b'persistent-nodemap'
306 name = b'persistent-nodemap'
283
307
284 _requirement = requirements.NODEMAP_REQUIREMENT
308 _requirement = requirements.NODEMAP_REQUIREMENT
285
309
286 default = False
310 default = False
287
311
288 description = _(
312 description = _(
289 b'persist the node -> rev mapping on disk to speedup lookup'
313 b'persist the node -> rev mapping on disk to speedup lookup'
290 )
314 )
291
315
292 upgrademessage = _(b'Speedup revision lookup by node id.')
316 upgrademessage = _(b'Speedup revision lookup by node id.')
293
317
294
318
295 @registerformatvariant
319 @registerformatvariant
296 class copiessdc(requirementformatvariant):
320 class copiessdc(requirementformatvariant):
297 name = b'copies-sdc'
321 name = b'copies-sdc'
298
322
299 _requirement = requirements.COPIESSDC_REQUIREMENT
323 _requirement = requirements.COPIESSDC_REQUIREMENT
300
324
301 default = False
325 default = False
302
326
303 description = _(b'Stores copies information alongside changesets.')
327 description = _(b'Stores copies information alongside changesets.')
304
328
305 upgrademessage = _(
329 upgrademessage = _(
306 b'Allows to use more efficient algorithm to deal with ' b'copy tracing.'
330 b'Allows to use more efficient algorithm to deal with ' b'copy tracing.'
307 )
331 )
308
332
309
333
310 @registerformatvariant
334 @registerformatvariant
311 class revlogv2(requirementformatvariant):
335 class revlogv2(requirementformatvariant):
312 name = b'revlog-v2'
336 name = b'revlog-v2'
313 _requirement = requirements.REVLOGV2_REQUIREMENT
337 _requirement = requirements.REVLOGV2_REQUIREMENT
314 default = False
338 default = False
315 description = _(b'Version 2 of the revlog.')
339 description = _(b'Version 2 of the revlog.')
316 upgrademessage = _(b'very experimental')
340 upgrademessage = _(b'very experimental')
317
341
318
342
319 @registerformatvariant
343 @registerformatvariant
320 class changelogv2(requirementformatvariant):
344 class changelogv2(requirementformatvariant):
321 name = b'changelog-v2'
345 name = b'changelog-v2'
322 _requirement = requirements.CHANGELOGV2_REQUIREMENT
346 _requirement = requirements.CHANGELOGV2_REQUIREMENT
323 default = False
347 default = False
324 description = _(b'An iteration of the revlog focussed on changelog needs.')
348 description = _(b'An iteration of the revlog focussed on changelog needs.')
325 upgrademessage = _(b'quite experimental')
349 upgrademessage = _(b'quite experimental')
326
350
327
351
328 @registerformatvariant
352 @registerformatvariant
329 class removecldeltachain(formatvariant):
353 class removecldeltachain(formatvariant):
330 name = b'plain-cl-delta'
354 name = b'plain-cl-delta'
331
355
332 default = True
356 default = True
333
357
334 description = _(
358 description = _(
335 b'changelog storage is using deltas instead of '
359 b'changelog storage is using deltas instead of '
336 b'raw entries; changelog reading and any '
360 b'raw entries; changelog reading and any '
337 b'operation relying on changelog data are slower '
361 b'operation relying on changelog data are slower '
338 b'than they could be'
362 b'than they could be'
339 )
363 )
340
364
341 upgrademessage = _(
365 upgrademessage = _(
342 b'changelog storage will be reformated to '
366 b'changelog storage will be reformated to '
343 b'store raw entries; changelog reading will be '
367 b'store raw entries; changelog reading will be '
344 b'faster; changelog size may be reduced'
368 b'faster; changelog size may be reduced'
345 )
369 )
346
370
347 @staticmethod
371 @staticmethod
348 def fromrepo(repo):
372 def fromrepo(repo):
349 # Mercurial 4.0 changed changelogs to not use delta chains. Search for
373 # Mercurial 4.0 changed changelogs to not use delta chains. Search for
350 # changelogs with deltas.
374 # changelogs with deltas.
351 cl = repo.changelog
375 cl = repo.changelog
352 chainbase = cl.chainbase
376 chainbase = cl.chainbase
353 return all(rev == chainbase(rev) for rev in cl)
377 return all(rev == chainbase(rev) for rev in cl)
354
378
355 @staticmethod
379 @staticmethod
356 def fromconfig(repo):
380 def fromconfig(repo):
357 return True
381 return True
358
382
359
383
360 _has_zstd = (
384 _has_zstd = (
361 b'zstd' in util.compengines
385 b'zstd' in util.compengines
362 and util.compengines[b'zstd'].available()
386 and util.compengines[b'zstd'].available()
363 and util.compengines[b'zstd'].revlogheader()
387 and util.compengines[b'zstd'].revlogheader()
364 )
388 )
365
389
366
390
367 @registerformatvariant
391 @registerformatvariant
368 class compressionengine(formatvariant):
392 class compressionengine(formatvariant):
369 name = b'compression'
393 name = b'compression'
370
394
371 if _has_zstd:
395 if _has_zstd:
372 default = b'zstd'
396 default = b'zstd'
373 else:
397 else:
374 default = b'zlib'
398 default = b'zlib'
375
399
376 description = _(
400 description = _(
377 b'Compresion algorithm used to compress data. '
401 b'Compresion algorithm used to compress data. '
378 b'Some engine are faster than other'
402 b'Some engine are faster than other'
379 )
403 )
380
404
381 upgrademessage = _(
405 upgrademessage = _(
382 b'revlog content will be recompressed with the new algorithm.'
406 b'revlog content will be recompressed with the new algorithm.'
383 )
407 )
384
408
385 @classmethod
409 @classmethod
386 def fromrepo(cls, repo):
410 def fromrepo(cls, repo):
387 # we allow multiple compression engine requirement to co-exist because
411 # we allow multiple compression engine requirement to co-exist because
388 # strickly speaking, revlog seems to support mixed compression style.
412 # strickly speaking, revlog seems to support mixed compression style.
389 #
413 #
390 # The compression used for new entries will be "the last one"
414 # The compression used for new entries will be "the last one"
391 compression = b'zlib'
415 compression = b'zlib'
392 for req in repo.requirements:
416 for req in repo.requirements:
393 prefix = req.startswith
417 prefix = req.startswith
394 if prefix(b'revlog-compression-') or prefix(b'exp-compression-'):
418 if prefix(b'revlog-compression-') or prefix(b'exp-compression-'):
395 compression = req.split(b'-', 2)[2]
419 compression = req.split(b'-', 2)[2]
396 return compression
420 return compression
397
421
398 @classmethod
422 @classmethod
399 def fromconfig(cls, repo):
423 def fromconfig(cls, repo):
400 compengines = repo.ui.configlist(b'format', b'revlog-compression')
424 compengines = repo.ui.configlist(b'format', b'revlog-compression')
401 # return the first valid value as the selection code would do
425 # return the first valid value as the selection code would do
402 for comp in compengines:
426 for comp in compengines:
403 if comp in util.compengines:
427 if comp in util.compengines:
404 e = util.compengines[comp]
428 e = util.compengines[comp]
405 if e.available() and e.revlogheader():
429 if e.available() and e.revlogheader():
406 return comp
430 return comp
407
431
408 # no valide compression found lets display it all for clarity
432 # no valide compression found lets display it all for clarity
409 return b','.join(compengines)
433 return b','.join(compengines)
410
434
411
435
412 @registerformatvariant
436 @registerformatvariant
413 class compressionlevel(formatvariant):
437 class compressionlevel(formatvariant):
414 name = b'compression-level'
438 name = b'compression-level'
415 default = b'default'
439 default = b'default'
416
440
417 description = _(b'compression level')
441 description = _(b'compression level')
418
442
419 upgrademessage = _(b'revlog content will be recompressed')
443 upgrademessage = _(b'revlog content will be recompressed')
420
444
421 @classmethod
445 @classmethod
422 def fromrepo(cls, repo):
446 def fromrepo(cls, repo):
423 comp = compressionengine.fromrepo(repo)
447 comp = compressionengine.fromrepo(repo)
424 level = None
448 level = None
425 if comp == b'zlib':
449 if comp == b'zlib':
426 level = repo.ui.configint(b'storage', b'revlog.zlib.level')
450 level = repo.ui.configint(b'storage', b'revlog.zlib.level')
427 elif comp == b'zstd':
451 elif comp == b'zstd':
428 level = repo.ui.configint(b'storage', b'revlog.zstd.level')
452 level = repo.ui.configint(b'storage', b'revlog.zstd.level')
429 if level is None:
453 if level is None:
430 return b'default'
454 return b'default'
431 return bytes(level)
455 return bytes(level)
432
456
433 @classmethod
457 @classmethod
434 def fromconfig(cls, repo):
458 def fromconfig(cls, repo):
435 comp = compressionengine.fromconfig(repo)
459 comp = compressionengine.fromconfig(repo)
436 level = None
460 level = None
437 if comp == b'zlib':
461 if comp == b'zlib':
438 level = repo.ui.configint(b'storage', b'revlog.zlib.level')
462 level = repo.ui.configint(b'storage', b'revlog.zlib.level')
439 elif comp == b'zstd':
463 elif comp == b'zstd':
440 level = repo.ui.configint(b'storage', b'revlog.zstd.level')
464 level = repo.ui.configint(b'storage', b'revlog.zstd.level')
441 if level is None:
465 if level is None:
442 return b'default'
466 return b'default'
443 return bytes(level)
467 return bytes(level)
444
468
445
469
446 def find_format_upgrades(repo):
470 def find_format_upgrades(repo):
447 """returns a list of format upgrades which can be perform on the repo"""
471 """returns a list of format upgrades which can be perform on the repo"""
448 upgrades = []
472 upgrades = []
449
473
450 # We could detect lack of revlogv1 and store here, but they were added
474 # We could detect lack of revlogv1 and store here, but they were added
451 # in 0.9.2 and we don't support upgrading repos without these
475 # in 0.9.2 and we don't support upgrading repos without these
452 # requirements, so let's not bother.
476 # requirements, so let's not bother.
453
477
454 for fv in allformatvariant:
478 for fv in allformatvariant:
455 if not fv.fromrepo(repo):
479 if not fv.fromrepo(repo):
456 upgrades.append(fv)
480 upgrades.append(fv)
457
481
458 return upgrades
482 return upgrades
459
483
460
484
461 def find_format_downgrades(repo):
485 def find_format_downgrades(repo):
462 """returns a list of format downgrades which will be performed on the repo
486 """returns a list of format downgrades which will be performed on the repo
463 because of disabled config option for them"""
487 because of disabled config option for them"""
464
488
465 downgrades = []
489 downgrades = []
466
490
467 for fv in allformatvariant:
491 for fv in allformatvariant:
468 if fv.name == b'compression':
492 if fv.name == b'compression':
469 # If there is a compression change between repository
493 # If there is a compression change between repository
470 # and config, destination repository compression will change
494 # and config, destination repository compression will change
471 # and current compression will be removed.
495 # and current compression will be removed.
472 if fv.fromrepo(repo) != fv.fromconfig(repo):
496 if fv.fromrepo(repo) != fv.fromconfig(repo):
473 downgrades.append(fv)
497 downgrades.append(fv)
474 continue
498 continue
475 # format variant exist in repo but does not exist in new repository
499 # format variant exist in repo but does not exist in new repository
476 # config
500 # config
477 if fv.fromrepo(repo) and not fv.fromconfig(repo):
501 if fv.fromrepo(repo) and not fv.fromconfig(repo):
478 downgrades.append(fv)
502 downgrades.append(fv)
479
503
480 return downgrades
504 return downgrades
481
505
482
506
483 ALL_OPTIMISATIONS = []
507 ALL_OPTIMISATIONS = []
484
508
485
509
486 def register_optimization(obj):
510 def register_optimization(obj):
487 ALL_OPTIMISATIONS.append(obj)
511 ALL_OPTIMISATIONS.append(obj)
488 return obj
512 return obj
489
513
490
514
491 class optimization(improvement):
515 class optimization(improvement):
492 """an improvement subclass dedicated to optimizations"""
516 """an improvement subclass dedicated to optimizations"""
493
517
494 type = OPTIMISATION
518 type = OPTIMISATION
495
519
496
520
497 @register_optimization
521 @register_optimization
498 class redeltaparents(optimization):
522 class redeltaparents(optimization):
499 name = b're-delta-parent'
523 name = b're-delta-parent'
500
524
501 type = OPTIMISATION
525 type = OPTIMISATION
502
526
503 description = _(
527 description = _(
504 b'deltas within internal storage will be recalculated to '
528 b'deltas within internal storage will be recalculated to '
505 b'choose an optimal base revision where this was not '
529 b'choose an optimal base revision where this was not '
506 b'already done; the size of the repository may shrink and '
530 b'already done; the size of the repository may shrink and '
507 b'various operations may become faster; the first time '
531 b'various operations may become faster; the first time '
508 b'this optimization is performed could slow down upgrade '
532 b'this optimization is performed could slow down upgrade '
509 b'execution considerably; subsequent invocations should '
533 b'execution considerably; subsequent invocations should '
510 b'not run noticeably slower'
534 b'not run noticeably slower'
511 )
535 )
512
536
513 upgrademessage = _(
537 upgrademessage = _(
514 b'deltas within internal storage will choose a new '
538 b'deltas within internal storage will choose a new '
515 b'base revision if needed'
539 b'base revision if needed'
516 )
540 )
517
541
518
542
519 @register_optimization
543 @register_optimization
520 class redeltamultibase(optimization):
544 class redeltamultibase(optimization):
521 name = b're-delta-multibase'
545 name = b're-delta-multibase'
522
546
523 type = OPTIMISATION
547 type = OPTIMISATION
524
548
525 description = _(
549 description = _(
526 b'deltas within internal storage will be recalculated '
550 b'deltas within internal storage will be recalculated '
527 b'against multiple base revision and the smallest '
551 b'against multiple base revision and the smallest '
528 b'difference will be used; the size of the repository may '
552 b'difference will be used; the size of the repository may '
529 b'shrink significantly when there are many merges; this '
553 b'shrink significantly when there are many merges; this '
530 b'optimization will slow down execution in proportion to '
554 b'optimization will slow down execution in proportion to '
531 b'the number of merges in the repository and the amount '
555 b'the number of merges in the repository and the amount '
532 b'of files in the repository; this slow down should not '
556 b'of files in the repository; this slow down should not '
533 b'be significant unless there are tens of thousands of '
557 b'be significant unless there are tens of thousands of '
534 b'files and thousands of merges'
558 b'files and thousands of merges'
535 )
559 )
536
560
537 upgrademessage = _(
561 upgrademessage = _(
538 b'deltas within internal storage will choose an '
562 b'deltas within internal storage will choose an '
539 b'optimal delta by computing deltas against multiple '
563 b'optimal delta by computing deltas against multiple '
540 b'parents; may slow down execution time '
564 b'parents; may slow down execution time '
541 b'significantly'
565 b'significantly'
542 )
566 )
543
567
544
568
545 @register_optimization
569 @register_optimization
546 class redeltaall(optimization):
570 class redeltaall(optimization):
547 name = b're-delta-all'
571 name = b're-delta-all'
548
572
549 type = OPTIMISATION
573 type = OPTIMISATION
550
574
551 description = _(
575 description = _(
552 b'deltas within internal storage will always be '
576 b'deltas within internal storage will always be '
553 b'recalculated without reusing prior deltas; this will '
577 b'recalculated without reusing prior deltas; this will '
554 b'likely make execution run several times slower; this '
578 b'likely make execution run several times slower; this '
555 b'optimization is typically not needed'
579 b'optimization is typically not needed'
556 )
580 )
557
581
558 upgrademessage = _(
582 upgrademessage = _(
559 b'deltas within internal storage will be fully '
583 b'deltas within internal storage will be fully '
560 b'recomputed; this will likely drastically slow down '
584 b'recomputed; this will likely drastically slow down '
561 b'execution time'
585 b'execution time'
562 )
586 )
563
587
564
588
565 @register_optimization
589 @register_optimization
566 class redeltafulladd(optimization):
590 class redeltafulladd(optimization):
567 name = b're-delta-fulladd'
591 name = b're-delta-fulladd'
568
592
569 type = OPTIMISATION
593 type = OPTIMISATION
570
594
571 description = _(
595 description = _(
572 b'every revision will be re-added as if it was new '
596 b'every revision will be re-added as if it was new '
573 b'content. It will go through the full storage '
597 b'content. It will go through the full storage '
574 b'mechanism giving extensions a chance to process it '
598 b'mechanism giving extensions a chance to process it '
575 b'(eg. lfs). This is similar to "re-delta-all" but even '
599 b'(eg. lfs). This is similar to "re-delta-all" but even '
576 b'slower since more logic is involved.'
600 b'slower since more logic is involved.'
577 )
601 )
578
602
579 upgrademessage = _(
603 upgrademessage = _(
580 b'each revision will be added as new content to the '
604 b'each revision will be added as new content to the '
581 b'internal storage; this will likely drastically slow '
605 b'internal storage; this will likely drastically slow '
582 b'down execution time, but some extensions might need '
606 b'down execution time, but some extensions might need '
583 b'it'
607 b'it'
584 )
608 )
585
609
586
610
587 def findoptimizations(repo):
611 def findoptimizations(repo):
588 """Determine optimisation that could be used during upgrade"""
612 """Determine optimisation that could be used during upgrade"""
589 # These are unconditionally added. There is logic later that figures out
613 # These are unconditionally added. There is logic later that figures out
590 # which ones to apply.
614 # which ones to apply.
591 return list(ALL_OPTIMISATIONS)
615 return list(ALL_OPTIMISATIONS)
592
616
593
617
594 def determine_upgrade_actions(
618 def determine_upgrade_actions(
595 repo, format_upgrades, optimizations, sourcereqs, destreqs
619 repo, format_upgrades, optimizations, sourcereqs, destreqs
596 ):
620 ):
597 """Determine upgrade actions that will be performed.
621 """Determine upgrade actions that will be performed.
598
622
599 Given a list of improvements as returned by ``find_format_upgrades`` and
623 Given a list of improvements as returned by ``find_format_upgrades`` and
600 ``findoptimizations``, determine the list of upgrade actions that
624 ``findoptimizations``, determine the list of upgrade actions that
601 will be performed.
625 will be performed.
602
626
603 The role of this function is to filter improvements if needed, apply
627 The role of this function is to filter improvements if needed, apply
604 recommended optimizations from the improvements list that make sense,
628 recommended optimizations from the improvements list that make sense,
605 etc.
629 etc.
606
630
607 Returns a list of action names.
631 Returns a list of action names.
608 """
632 """
609 newactions = []
633 newactions = []
610
634
611 for d in format_upgrades:
635 for d in format_upgrades:
612 name = d._requirement
636 name = d._requirement
613
637
614 # If the action is a requirement that doesn't show up in the
638 # If the action is a requirement that doesn't show up in the
615 # destination requirements, prune the action.
639 # destination requirements, prune the action.
616 if name is not None and name not in destreqs:
640 if name is not None and name not in destreqs:
617 continue
641 continue
618
642
619 newactions.append(d)
643 newactions.append(d)
620
644
621 newactions.extend(o for o in sorted(optimizations) if o not in newactions)
645 newactions.extend(o for o in sorted(optimizations) if o not in newactions)
622
646
623 # FUTURE consider adding some optimizations here for certain transitions.
647 # FUTURE consider adding some optimizations here for certain transitions.
624 # e.g. adding generaldelta could schedule parent redeltas.
648 # e.g. adding generaldelta could schedule parent redeltas.
625
649
626 return newactions
650 return newactions
627
651
628
652
629 class UpgradeOperation(object):
653 class UpgradeOperation(object):
630 """represent the work to be done during an upgrade"""
654 """represent the work to be done during an upgrade"""
631
655
632 def __init__(
656 def __init__(
633 self,
657 self,
634 ui,
658 ui,
635 new_requirements,
659 new_requirements,
636 current_requirements,
660 current_requirements,
637 upgrade_actions,
661 upgrade_actions,
638 removed_actions,
662 removed_actions,
639 revlogs_to_process,
663 revlogs_to_process,
640 backup_store,
664 backup_store,
641 ):
665 ):
642 self.ui = ui
666 self.ui = ui
643 self.new_requirements = new_requirements
667 self.new_requirements = new_requirements
644 self.current_requirements = current_requirements
668 self.current_requirements = current_requirements
645 # list of upgrade actions the operation will perform
669 # list of upgrade actions the operation will perform
646 self.upgrade_actions = upgrade_actions
670 self.upgrade_actions = upgrade_actions
647 self._upgrade_actions_names = set([a.name for a in upgrade_actions])
648 self.removed_actions = removed_actions
671 self.removed_actions = removed_actions
649 self.revlogs_to_process = revlogs_to_process
672 self.revlogs_to_process = revlogs_to_process
650 # requirements which will be added by the operation
673 # requirements which will be added by the operation
651 self._added_requirements = (
674 self._added_requirements = (
652 self.new_requirements - self.current_requirements
675 self.new_requirements - self.current_requirements
653 )
676 )
654 # requirements which will be removed by the operation
677 # requirements which will be removed by the operation
655 self._removed_requirements = (
678 self._removed_requirements = (
656 self.current_requirements - self.new_requirements
679 self.current_requirements - self.new_requirements
657 )
680 )
658 # requirements which will be preserved by the operation
681 # requirements which will be preserved by the operation
659 self._preserved_requirements = (
682 self._preserved_requirements = (
660 self.current_requirements & self.new_requirements
683 self.current_requirements & self.new_requirements
661 )
684 )
662 # optimizations which are not used and it's recommended that they
685 # optimizations which are not used and it's recommended that they
663 # should use them
686 # should use them
664 all_optimizations = findoptimizations(None)
687 all_optimizations = findoptimizations(None)
665 self.unused_optimizations = [
688 self.unused_optimizations = [
666 i for i in all_optimizations if i not in self.upgrade_actions
689 i for i in all_optimizations if i not in self.upgrade_actions
667 ]
690 ]
668
691
669 # delta reuse mode of this upgrade operation
692 # delta reuse mode of this upgrade operation
693 upgrade_actions_names = self.upgrade_actions_names
670 self.delta_reuse_mode = revlog.revlog.DELTAREUSEALWAYS
694 self.delta_reuse_mode = revlog.revlog.DELTAREUSEALWAYS
671 if b're-delta-all' in self._upgrade_actions_names:
695 if b're-delta-all' in upgrade_actions_names:
672 self.delta_reuse_mode = revlog.revlog.DELTAREUSENEVER
696 self.delta_reuse_mode = revlog.revlog.DELTAREUSENEVER
673 elif b're-delta-parent' in self._upgrade_actions_names:
697 elif b're-delta-parent' in upgrade_actions_names:
674 self.delta_reuse_mode = revlog.revlog.DELTAREUSESAMEREVS
698 self.delta_reuse_mode = revlog.revlog.DELTAREUSESAMEREVS
675 elif b're-delta-multibase' in self._upgrade_actions_names:
699 elif b're-delta-multibase' in upgrade_actions_names:
676 self.delta_reuse_mode = revlog.revlog.DELTAREUSESAMEREVS
700 self.delta_reuse_mode = revlog.revlog.DELTAREUSESAMEREVS
677 elif b're-delta-fulladd' in self._upgrade_actions_names:
701 elif b're-delta-fulladd' in upgrade_actions_names:
678 self.delta_reuse_mode = revlog.revlog.DELTAREUSEFULLADD
702 self.delta_reuse_mode = revlog.revlog.DELTAREUSEFULLADD
679
703
680 # should this operation force re-delta of both parents
704 # should this operation force re-delta of both parents
681 self.force_re_delta_both_parents = (
705 self.force_re_delta_both_parents = (
682 b're-delta-multibase' in self._upgrade_actions_names
706 b're-delta-multibase' in upgrade_actions_names
683 )
707 )
684
708
685 # should this operation create a backup of the store
709 # should this operation create a backup of the store
686 self.backup_store = backup_store
710 self.backup_store = backup_store
687
711
688 # whether the operation touches different revlogs at all or not
712 @property
689 self.touches_filelogs = self._touches_filelogs()
713 def upgrade_actions_names(self):
690 self.touches_manifests = self._touches_manifests()
714 return set([a.name for a in self.upgrade_actions])
691 self.touches_changelog = self._touches_changelog()
715
692 # whether the operation touches requirements file or not
716 @property
693 self.touches_requirements = self._touches_requirements()
717 def requirements_only(self):
694 self.touches_store = (
695 self.touches_filelogs
696 or self.touches_manifests
697 or self.touches_changelog
698 )
699 # does the operation only touches repository requirement
718 # does the operation only touches repository requirement
700 self.requirements_only = (
719 return (
701 self.touches_requirements and not self.touches_store
720 self.touches_requirements
721 and not self.touches_filelogs
722 and not self.touches_manifests
723 and not self.touches_changelog
724 and not self.touches_dirstate
702 )
725 )
703
726
704 def _touches_filelogs(self):
727 @property
728 def touches_filelogs(self):
705 for a in self.upgrade_actions:
729 for a in self.upgrade_actions:
706 # in optimisations, we re-process the revlogs again
730 # in optimisations, we re-process the revlogs again
707 if a.type == OPTIMISATION:
731 if a.type == OPTIMISATION:
708 return True
732 return True
709 elif a.touches_filelogs:
733 elif a.touches_filelogs:
710 return True
734 return True
711 for a in self.removed_actions:
735 for a in self.removed_actions:
712 if a.touches_filelogs:
736 if a.touches_filelogs:
713 return True
737 return True
714 return False
738 return False
715
739
716 def _touches_manifests(self):
740 @property
741 def touches_manifests(self):
717 for a in self.upgrade_actions:
742 for a in self.upgrade_actions:
718 # in optimisations, we re-process the revlogs again
743 # in optimisations, we re-process the revlogs again
719 if a.type == OPTIMISATION:
744 if a.type == OPTIMISATION:
720 return True
745 return True
721 elif a.touches_manifests:
746 elif a.touches_manifests:
722 return True
747 return True
723 for a in self.removed_actions:
748 for a in self.removed_actions:
724 if a.touches_manifests:
749 if a.touches_manifests:
725 return True
750 return True
726 return False
751 return False
727
752
728 def _touches_changelog(self):
753 @property
754 def touches_changelog(self):
729 for a in self.upgrade_actions:
755 for a in self.upgrade_actions:
730 # in optimisations, we re-process the revlogs again
756 # in optimisations, we re-process the revlogs again
731 if a.type == OPTIMISATION:
757 if a.type == OPTIMISATION:
732 return True
758 return True
733 elif a.touches_changelog:
759 elif a.touches_changelog:
734 return True
760 return True
735 for a in self.removed_actions:
761 for a in self.removed_actions:
736 if a.touches_changelog:
762 if a.touches_changelog:
737 return True
763 return True
738 return False
764 return False
739
765
740 def _touches_requirements(self):
766 @property
767 def touches_requirements(self):
741 for a in self.upgrade_actions:
768 for a in self.upgrade_actions:
742 # optimisations are used to re-process revlogs and does not result
769 # optimisations are used to re-process revlogs and does not result
743 # in a requirement being added or removed
770 # in a requirement being added or removed
744 if a.type == OPTIMISATION:
771 if a.type == OPTIMISATION:
745 pass
772 pass
746 elif a.touches_requirements:
773 elif a.touches_requirements:
747 return True
774 return True
748 for a in self.removed_actions:
775 for a in self.removed_actions:
749 if a.touches_requirements:
776 if a.touches_requirements:
750 return True
777 return True
751
778
779 @property
780 def touches_dirstate(self):
781 for a in self.upgrade_actions:
782 # revlog optimisations do not affect the dirstate
783 if a.type == OPTIMISATION:
784 pass
785 elif a.touches_dirstate:
786 return True
787 for a in self.removed_actions:
788 if a.touches_dirstate:
789 return True
790
752 return False
791 return False
753
792
754 def _write_labeled(self, l, label):
793 def _write_labeled(self, l, label):
755 """
794 """
756 Utility function to aid writing of a list under one label
795 Utility function to aid writing of a list under one label
757 """
796 """
758 first = True
797 first = True
759 for r in sorted(l):
798 for r in sorted(l):
760 if not first:
799 if not first:
761 self.ui.write(b', ')
800 self.ui.write(b', ')
762 self.ui.write(r, label=label)
801 self.ui.write(r, label=label)
763 first = False
802 first = False
764
803
765 def print_requirements(self):
804 def print_requirements(self):
766 self.ui.write(_(b'requirements\n'))
805 self.ui.write(_(b'requirements\n'))
767 self.ui.write(_(b' preserved: '))
806 self.ui.write(_(b' preserved: '))
768 self._write_labeled(
807 self._write_labeled(
769 self._preserved_requirements, "upgrade-repo.requirement.preserved"
808 self._preserved_requirements, "upgrade-repo.requirement.preserved"
770 )
809 )
771 self.ui.write((b'\n'))
810 self.ui.write((b'\n'))
772 if self._removed_requirements:
811 if self._removed_requirements:
773 self.ui.write(_(b' removed: '))
812 self.ui.write(_(b' removed: '))
774 self._write_labeled(
813 self._write_labeled(
775 self._removed_requirements, "upgrade-repo.requirement.removed"
814 self._removed_requirements, "upgrade-repo.requirement.removed"
776 )
815 )
777 self.ui.write((b'\n'))
816 self.ui.write((b'\n'))
778 if self._added_requirements:
817 if self._added_requirements:
779 self.ui.write(_(b' added: '))
818 self.ui.write(_(b' added: '))
780 self._write_labeled(
819 self._write_labeled(
781 self._added_requirements, "upgrade-repo.requirement.added"
820 self._added_requirements, "upgrade-repo.requirement.added"
782 )
821 )
783 self.ui.write((b'\n'))
822 self.ui.write((b'\n'))
784 self.ui.write(b'\n')
823 self.ui.write(b'\n')
785
824
786 def print_optimisations(self):
825 def print_optimisations(self):
787 optimisations = [
826 optimisations = [
788 a for a in self.upgrade_actions if a.type == OPTIMISATION
827 a for a in self.upgrade_actions if a.type == OPTIMISATION
789 ]
828 ]
790 optimisations.sort(key=lambda a: a.name)
829 optimisations.sort(key=lambda a: a.name)
791 if optimisations:
830 if optimisations:
792 self.ui.write(_(b'optimisations: '))
831 self.ui.write(_(b'optimisations: '))
793 self._write_labeled(
832 self._write_labeled(
794 [a.name for a in optimisations],
833 [a.name for a in optimisations],
795 "upgrade-repo.optimisation.performed",
834 "upgrade-repo.optimisation.performed",
796 )
835 )
797 self.ui.write(b'\n\n')
836 self.ui.write(b'\n\n')
798
837
799 def print_upgrade_actions(self):
838 def print_upgrade_actions(self):
800 for a in self.upgrade_actions:
839 for a in self.upgrade_actions:
801 self.ui.status(b'%s\n %s\n\n' % (a.name, a.upgrademessage))
840 self.ui.status(b'%s\n %s\n\n' % (a.name, a.upgrademessage))
802
841
803 def print_affected_revlogs(self):
842 def print_affected_revlogs(self):
804 if not self.revlogs_to_process:
843 if not self.revlogs_to_process:
805 self.ui.write((b'no revlogs to process\n'))
844 self.ui.write((b'no revlogs to process\n'))
806 else:
845 else:
807 self.ui.write((b'processed revlogs:\n'))
846 self.ui.write((b'processed revlogs:\n'))
808 for r in sorted(self.revlogs_to_process):
847 for r in sorted(self.revlogs_to_process):
809 self.ui.write((b' - %s\n' % r))
848 self.ui.write((b' - %s\n' % r))
810 self.ui.write((b'\n'))
849 self.ui.write((b'\n'))
811
850
812 def print_unused_optimizations(self):
851 def print_unused_optimizations(self):
813 for i in self.unused_optimizations:
852 for i in self.unused_optimizations:
814 self.ui.status(_(b'%s\n %s\n\n') % (i.name, i.description))
853 self.ui.status(_(b'%s\n %s\n\n') % (i.name, i.description))
815
854
816 def has_upgrade_action(self, name):
855 def has_upgrade_action(self, name):
817 """Check whether the upgrade operation will perform this action"""
856 """Check whether the upgrade operation will perform this action"""
818 return name in self._upgrade_actions_names
857 return name in self._upgrade_actions_names
819
858
820 def print_post_op_messages(self):
859 def print_post_op_messages(self):
821 """print post upgrade operation warning messages"""
860 """print post upgrade operation warning messages"""
822 for a in self.upgrade_actions:
861 for a in self.upgrade_actions:
823 if a.postupgrademessage is not None:
862 if a.postupgrademessage is not None:
824 self.ui.warn(b'%s\n' % a.postupgrademessage)
863 self.ui.warn(b'%s\n' % a.postupgrademessage)
825 for a in self.removed_actions:
864 for a in self.removed_actions:
826 if a.postdowngrademessage is not None:
865 if a.postdowngrademessage is not None:
827 self.ui.warn(b'%s\n' % a.postdowngrademessage)
866 self.ui.warn(b'%s\n' % a.postdowngrademessage)
828
867
829
868
830 ### Code checking if a repository can got through the upgrade process at all. #
869 ### Code checking if a repository can got through the upgrade process at all. #
831
870
832
871
833 def requiredsourcerequirements(repo):
872 def requiredsourcerequirements(repo):
834 """Obtain requirements required to be present to upgrade a repo.
873 """Obtain requirements required to be present to upgrade a repo.
835
874
836 An upgrade will not be allowed if the repository doesn't have the
875 An upgrade will not be allowed if the repository doesn't have the
837 requirements returned by this function.
876 requirements returned by this function.
838 """
877 """
839 return {
878 return {
840 # Introduced in Mercurial 0.9.2.
879 # Introduced in Mercurial 0.9.2.
841 requirements.STORE_REQUIREMENT,
880 requirements.STORE_REQUIREMENT,
842 }
881 }
843
882
844
883
845 def blocksourcerequirements(repo):
884 def blocksourcerequirements(repo):
846 """Obtain requirements that will prevent an upgrade from occurring.
885 """Obtain requirements that will prevent an upgrade from occurring.
847
886
848 An upgrade cannot be performed if the source repository contains a
887 An upgrade cannot be performed if the source repository contains a
849 requirements in the returned set.
888 requirements in the returned set.
850 """
889 """
851 return {
890 return {
852 # The upgrade code does not yet support these experimental features.
891 # The upgrade code does not yet support these experimental features.
853 # This is an artificial limitation.
892 # This is an artificial limitation.
854 requirements.TREEMANIFEST_REQUIREMENT,
893 requirements.TREEMANIFEST_REQUIREMENT,
855 # This was a precursor to generaldelta and was never enabled by default.
894 # This was a precursor to generaldelta and was never enabled by default.
856 # It should (hopefully) not exist in the wild.
895 # It should (hopefully) not exist in the wild.
857 b'parentdelta',
896 b'parentdelta',
858 # Upgrade should operate on the actual store, not the shared link.
897 # Upgrade should operate on the actual store, not the shared link.
859 requirements.SHARED_REQUIREMENT,
898 requirements.SHARED_REQUIREMENT,
860 }
899 }
861
900
862
901
863 def check_revlog_version(reqs):
902 def check_revlog_version(reqs):
864 """Check that the requirements contain at least one Revlog version"""
903 """Check that the requirements contain at least one Revlog version"""
865 all_revlogs = {
904 all_revlogs = {
866 requirements.REVLOGV1_REQUIREMENT,
905 requirements.REVLOGV1_REQUIREMENT,
867 requirements.REVLOGV2_REQUIREMENT,
906 requirements.REVLOGV2_REQUIREMENT,
868 }
907 }
869 if not all_revlogs.intersection(reqs):
908 if not all_revlogs.intersection(reqs):
870 msg = _(b'cannot upgrade repository; missing a revlog version')
909 msg = _(b'cannot upgrade repository; missing a revlog version')
871 raise error.Abort(msg)
910 raise error.Abort(msg)
872
911
873
912
874 def check_source_requirements(repo):
913 def check_source_requirements(repo):
875 """Ensure that no existing requirements prevent the repository upgrade"""
914 """Ensure that no existing requirements prevent the repository upgrade"""
876
915
877 check_revlog_version(repo.requirements)
916 check_revlog_version(repo.requirements)
878 required = requiredsourcerequirements(repo)
917 required = requiredsourcerequirements(repo)
879 missingreqs = required - repo.requirements
918 missingreqs = required - repo.requirements
880 if missingreqs:
919 if missingreqs:
881 msg = _(b'cannot upgrade repository; requirement missing: %s')
920 msg = _(b'cannot upgrade repository; requirement missing: %s')
882 missingreqs = b', '.join(sorted(missingreqs))
921 missingreqs = b', '.join(sorted(missingreqs))
883 raise error.Abort(msg % missingreqs)
922 raise error.Abort(msg % missingreqs)
884
923
885 blocking = blocksourcerequirements(repo)
924 blocking = blocksourcerequirements(repo)
886 blockingreqs = blocking & repo.requirements
925 blockingreqs = blocking & repo.requirements
887 if blockingreqs:
926 if blockingreqs:
888 m = _(b'cannot upgrade repository; unsupported source requirement: %s')
927 m = _(b'cannot upgrade repository; unsupported source requirement: %s')
889 blockingreqs = b', '.join(sorted(blockingreqs))
928 blockingreqs = b', '.join(sorted(blockingreqs))
890 raise error.Abort(m % blockingreqs)
929 raise error.Abort(m % blockingreqs)
891
930
892
931
893 ### Verify the validity of the planned requirement changes ####################
932 ### Verify the validity of the planned requirement changes ####################
894
933
895
934
896 def supportremovedrequirements(repo):
935 def supportremovedrequirements(repo):
897 """Obtain requirements that can be removed during an upgrade.
936 """Obtain requirements that can be removed during an upgrade.
898
937
899 If an upgrade were to create a repository that dropped a requirement,
938 If an upgrade were to create a repository that dropped a requirement,
900 the dropped requirement must appear in the returned set for the upgrade
939 the dropped requirement must appear in the returned set for the upgrade
901 to be allowed.
940 to be allowed.
902 """
941 """
903 supported = {
942 supported = {
904 requirements.SPARSEREVLOG_REQUIREMENT,
943 requirements.SPARSEREVLOG_REQUIREMENT,
905 requirements.COPIESSDC_REQUIREMENT,
944 requirements.COPIESSDC_REQUIREMENT,
906 requirements.NODEMAP_REQUIREMENT,
945 requirements.NODEMAP_REQUIREMENT,
907 requirements.SHARESAFE_REQUIREMENT,
946 requirements.SHARESAFE_REQUIREMENT,
908 requirements.REVLOGV2_REQUIREMENT,
947 requirements.REVLOGV2_REQUIREMENT,
909 requirements.CHANGELOGV2_REQUIREMENT,
948 requirements.CHANGELOGV2_REQUIREMENT,
910 requirements.REVLOGV1_REQUIREMENT,
949 requirements.REVLOGV1_REQUIREMENT,
950 requirements.DIRSTATE_V2_REQUIREMENT,
911 }
951 }
912 for name in compression.compengines:
952 for name in compression.compengines:
913 engine = compression.compengines[name]
953 engine = compression.compengines[name]
914 if engine.available() and engine.revlogheader():
954 if engine.available() and engine.revlogheader():
915 supported.add(b'exp-compression-%s' % name)
955 supported.add(b'exp-compression-%s' % name)
916 if engine.name() == b'zstd':
956 if engine.name() == b'zstd':
917 supported.add(b'revlog-compression-zstd')
957 supported.add(b'revlog-compression-zstd')
918 return supported
958 return supported
919
959
920
960
921 def supporteddestrequirements(repo):
961 def supporteddestrequirements(repo):
922 """Obtain requirements that upgrade supports in the destination.
962 """Obtain requirements that upgrade supports in the destination.
923
963
924 If the result of the upgrade would create requirements not in this set,
964 If the result of the upgrade would create requirements not in this set,
925 the upgrade is disallowed.
965 the upgrade is disallowed.
926
966
927 Extensions should monkeypatch this to add their custom requirements.
967 Extensions should monkeypatch this to add their custom requirements.
928 """
968 """
929 supported = {
969 supported = {
930 requirements.DOTENCODE_REQUIREMENT,
970 requirements.DOTENCODE_REQUIREMENT,
931 requirements.FNCACHE_REQUIREMENT,
971 requirements.FNCACHE_REQUIREMENT,
932 requirements.GENERALDELTA_REQUIREMENT,
972 requirements.GENERALDELTA_REQUIREMENT,
933 requirements.REVLOGV1_REQUIREMENT, # allowed in case of downgrade
973 requirements.REVLOGV1_REQUIREMENT, # allowed in case of downgrade
934 requirements.STORE_REQUIREMENT,
974 requirements.STORE_REQUIREMENT,
935 requirements.SPARSEREVLOG_REQUIREMENT,
975 requirements.SPARSEREVLOG_REQUIREMENT,
936 requirements.COPIESSDC_REQUIREMENT,
976 requirements.COPIESSDC_REQUIREMENT,
937 requirements.NODEMAP_REQUIREMENT,
977 requirements.NODEMAP_REQUIREMENT,
938 requirements.SHARESAFE_REQUIREMENT,
978 requirements.SHARESAFE_REQUIREMENT,
939 requirements.REVLOGV2_REQUIREMENT,
979 requirements.REVLOGV2_REQUIREMENT,
940 requirements.CHANGELOGV2_REQUIREMENT,
980 requirements.CHANGELOGV2_REQUIREMENT,
941 requirements.DIRSTATE_V2_REQUIREMENT,
981 requirements.DIRSTATE_V2_REQUIREMENT,
942 }
982 }
943 for name in compression.compengines:
983 for name in compression.compengines:
944 engine = compression.compengines[name]
984 engine = compression.compengines[name]
945 if engine.available() and engine.revlogheader():
985 if engine.available() and engine.revlogheader():
946 supported.add(b'exp-compression-%s' % name)
986 supported.add(b'exp-compression-%s' % name)
947 if engine.name() == b'zstd':
987 if engine.name() == b'zstd':
948 supported.add(b'revlog-compression-zstd')
988 supported.add(b'revlog-compression-zstd')
949 return supported
989 return supported
950
990
951
991
952 def allowednewrequirements(repo):
992 def allowednewrequirements(repo):
953 """Obtain requirements that can be added to a repository during upgrade.
993 """Obtain requirements that can be added to a repository during upgrade.
954
994
955 This is used to disallow proposed requirements from being added when
995 This is used to disallow proposed requirements from being added when
956 they weren't present before.
996 they weren't present before.
957
997
958 We use a list of allowed requirement additions instead of a list of known
998 We use a list of allowed requirement additions instead of a list of known
959 bad additions because the whitelist approach is safer and will prevent
999 bad additions because the whitelist approach is safer and will prevent
960 future, unknown requirements from accidentally being added.
1000 future, unknown requirements from accidentally being added.
961 """
1001 """
962 supported = {
1002 supported = {
963 requirements.DOTENCODE_REQUIREMENT,
1003 requirements.DOTENCODE_REQUIREMENT,
964 requirements.FNCACHE_REQUIREMENT,
1004 requirements.FNCACHE_REQUIREMENT,
965 requirements.GENERALDELTA_REQUIREMENT,
1005 requirements.GENERALDELTA_REQUIREMENT,
966 requirements.SPARSEREVLOG_REQUIREMENT,
1006 requirements.SPARSEREVLOG_REQUIREMENT,
967 requirements.COPIESSDC_REQUIREMENT,
1007 requirements.COPIESSDC_REQUIREMENT,
968 requirements.NODEMAP_REQUIREMENT,
1008 requirements.NODEMAP_REQUIREMENT,
969 requirements.SHARESAFE_REQUIREMENT,
1009 requirements.SHARESAFE_REQUIREMENT,
970 requirements.REVLOGV1_REQUIREMENT,
1010 requirements.REVLOGV1_REQUIREMENT,
971 requirements.REVLOGV2_REQUIREMENT,
1011 requirements.REVLOGV2_REQUIREMENT,
972 requirements.CHANGELOGV2_REQUIREMENT,
1012 requirements.CHANGELOGV2_REQUIREMENT,
1013 requirements.DIRSTATE_V2_REQUIREMENT,
973 }
1014 }
974 for name in compression.compengines:
1015 for name in compression.compengines:
975 engine = compression.compengines[name]
1016 engine = compression.compengines[name]
976 if engine.available() and engine.revlogheader():
1017 if engine.available() and engine.revlogheader():
977 supported.add(b'exp-compression-%s' % name)
1018 supported.add(b'exp-compression-%s' % name)
978 if engine.name() == b'zstd':
1019 if engine.name() == b'zstd':
979 supported.add(b'revlog-compression-zstd')
1020 supported.add(b'revlog-compression-zstd')
980 return supported
1021 return supported
981
1022
982
1023
983 def check_requirements_changes(repo, new_reqs):
1024 def check_requirements_changes(repo, new_reqs):
984 old_reqs = repo.requirements
1025 old_reqs = repo.requirements
985 check_revlog_version(repo.requirements)
1026 check_revlog_version(repo.requirements)
986 support_removal = supportremovedrequirements(repo)
1027 support_removal = supportremovedrequirements(repo)
987 no_remove_reqs = old_reqs - new_reqs - support_removal
1028 no_remove_reqs = old_reqs - new_reqs - support_removal
988 if no_remove_reqs:
1029 if no_remove_reqs:
989 msg = _(b'cannot upgrade repository; requirement would be removed: %s')
1030 msg = _(b'cannot upgrade repository; requirement would be removed: %s')
990 no_remove_reqs = b', '.join(sorted(no_remove_reqs))
1031 no_remove_reqs = b', '.join(sorted(no_remove_reqs))
991 raise error.Abort(msg % no_remove_reqs)
1032 raise error.Abort(msg % no_remove_reqs)
992
1033
993 support_addition = allowednewrequirements(repo)
1034 support_addition = allowednewrequirements(repo)
994 no_add_reqs = new_reqs - old_reqs - support_addition
1035 no_add_reqs = new_reqs - old_reqs - support_addition
995 if no_add_reqs:
1036 if no_add_reqs:
996 m = _(b'cannot upgrade repository; do not support adding requirement: ')
1037 m = _(b'cannot upgrade repository; do not support adding requirement: ')
997 no_add_reqs = b', '.join(sorted(no_add_reqs))
1038 no_add_reqs = b', '.join(sorted(no_add_reqs))
998 raise error.Abort(m + no_add_reqs)
1039 raise error.Abort(m + no_add_reqs)
999
1040
1000 supported = supporteddestrequirements(repo)
1041 supported = supporteddestrequirements(repo)
1001 unsupported_reqs = new_reqs - supported
1042 unsupported_reqs = new_reqs - supported
1002 if unsupported_reqs:
1043 if unsupported_reqs:
1003 msg = _(
1044 msg = _(
1004 b'cannot upgrade repository; do not support destination '
1045 b'cannot upgrade repository; do not support destination '
1005 b'requirement: %s'
1046 b'requirement: %s'
1006 )
1047 )
1007 unsupported_reqs = b', '.join(sorted(unsupported_reqs))
1048 unsupported_reqs = b', '.join(sorted(unsupported_reqs))
1008 raise error.Abort(msg % unsupported_reqs)
1049 raise error.Abort(msg % unsupported_reqs)
@@ -1,593 +1,632 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 from __future__ import absolute_import
8 from __future__ import absolute_import
9
9
10 import stat
10 import stat
11
11
12 from ..i18n import _
12 from ..i18n import _
13 from ..pycompat import getattr
13 from ..pycompat import getattr
14 from .. import (
14 from .. import (
15 changelog,
15 changelog,
16 error,
16 error,
17 filelog,
17 filelog,
18 manifest,
18 manifest,
19 metadata,
19 metadata,
20 pycompat,
20 pycompat,
21 requirements,
21 requirements,
22 scmutil,
22 scmutil,
23 store,
23 store,
24 util,
24 util,
25 vfs as vfsmod,
25 vfs as vfsmod,
26 )
26 )
27 from ..revlogutils import (
27 from ..revlogutils import (
28 constants as revlogconst,
28 constants as revlogconst,
29 flagutil,
29 flagutil,
30 nodemap,
30 nodemap,
31 sidedata as sidedatamod,
31 sidedata as sidedatamod,
32 )
32 )
33 from . import actions as upgrade_actions
33
34
34
35
35 def get_sidedata_helpers(srcrepo, dstrepo):
36 def get_sidedata_helpers(srcrepo, dstrepo):
36 use_w = srcrepo.ui.configbool(b'experimental', b'worker.repository-upgrade')
37 use_w = srcrepo.ui.configbool(b'experimental', b'worker.repository-upgrade')
37 sequential = pycompat.iswindows or not use_w
38 sequential = pycompat.iswindows or not use_w
38 if not sequential:
39 if not sequential:
39 srcrepo.register_sidedata_computer(
40 srcrepo.register_sidedata_computer(
40 revlogconst.KIND_CHANGELOG,
41 revlogconst.KIND_CHANGELOG,
41 sidedatamod.SD_FILES,
42 sidedatamod.SD_FILES,
42 (sidedatamod.SD_FILES,),
43 (sidedatamod.SD_FILES,),
43 metadata._get_worker_sidedata_adder(srcrepo, dstrepo),
44 metadata._get_worker_sidedata_adder(srcrepo, dstrepo),
44 flagutil.REVIDX_HASCOPIESINFO,
45 flagutil.REVIDX_HASCOPIESINFO,
45 replace=True,
46 replace=True,
46 )
47 )
47 return sidedatamod.get_sidedata_helpers(srcrepo, dstrepo._wanted_sidedata)
48 return sidedatamod.get_sidedata_helpers(srcrepo, dstrepo._wanted_sidedata)
48
49
49
50
50 def _revlogfrompath(repo, rl_type, path):
51 def _revlogfrompath(repo, rl_type, path):
51 """Obtain a revlog from a repo path.
52 """Obtain a revlog from a repo path.
52
53
53 An instance of the appropriate class is returned.
54 An instance of the appropriate class is returned.
54 """
55 """
55 if rl_type & store.FILEFLAGS_CHANGELOG:
56 if rl_type & store.FILEFLAGS_CHANGELOG:
56 return changelog.changelog(repo.svfs)
57 return changelog.changelog(repo.svfs)
57 elif rl_type & store.FILEFLAGS_MANIFESTLOG:
58 elif rl_type & store.FILEFLAGS_MANIFESTLOG:
58 mandir = b''
59 mandir = b''
59 if b'/' in path:
60 if b'/' in path:
60 mandir = path.rsplit(b'/', 1)[0]
61 mandir = path.rsplit(b'/', 1)[0]
61 return manifest.manifestrevlog(
62 return manifest.manifestrevlog(
62 repo.nodeconstants, repo.svfs, tree=mandir
63 repo.nodeconstants, repo.svfs, tree=mandir
63 )
64 )
64 else:
65 else:
65 # drop the extension and the `data/` prefix
66 # drop the extension and the `data/` prefix
66 path = path.rsplit(b'.', 1)[0].split(b'/', 1)[1]
67 path = path.rsplit(b'.', 1)[0].split(b'/', 1)[1]
67 return filelog.filelog(repo.svfs, path)
68 return filelog.filelog(repo.svfs, path)
68
69
69
70
70 def _copyrevlog(tr, destrepo, oldrl, rl_type, unencodedname):
71 def _copyrevlog(tr, destrepo, oldrl, rl_type, unencodedname):
71 """copy all relevant files for `oldrl` into `destrepo` store
72 """copy all relevant files for `oldrl` into `destrepo` store
72
73
73 Files are copied "as is" without any transformation. The copy is performed
74 Files are copied "as is" without any transformation. The copy is performed
74 without extra checks. Callers are responsible for making sure the copied
75 without extra checks. Callers are responsible for making sure the copied
75 content is compatible with format of the destination repository.
76 content is compatible with format of the destination repository.
76 """
77 """
77 oldrl = getattr(oldrl, '_revlog', oldrl)
78 oldrl = getattr(oldrl, '_revlog', oldrl)
78 newrl = _revlogfrompath(destrepo, rl_type, unencodedname)
79 newrl = _revlogfrompath(destrepo, rl_type, unencodedname)
79 newrl = getattr(newrl, '_revlog', newrl)
80 newrl = getattr(newrl, '_revlog', newrl)
80
81
81 oldvfs = oldrl.opener
82 oldvfs = oldrl.opener
82 newvfs = newrl.opener
83 newvfs = newrl.opener
83 oldindex = oldvfs.join(oldrl._indexfile)
84 oldindex = oldvfs.join(oldrl._indexfile)
84 newindex = newvfs.join(newrl._indexfile)
85 newindex = newvfs.join(newrl._indexfile)
85 olddata = oldvfs.join(oldrl._datafile)
86 olddata = oldvfs.join(oldrl._datafile)
86 newdata = newvfs.join(newrl._datafile)
87 newdata = newvfs.join(newrl._datafile)
87
88
88 with newvfs(newrl._indexfile, b'w'):
89 with newvfs(newrl._indexfile, b'w'):
89 pass # create all the directories
90 pass # create all the directories
90
91
91 util.copyfile(oldindex, newindex)
92 util.copyfile(oldindex, newindex)
92 copydata = oldrl.opener.exists(oldrl._datafile)
93 copydata = oldrl.opener.exists(oldrl._datafile)
93 if copydata:
94 if copydata:
94 util.copyfile(olddata, newdata)
95 util.copyfile(olddata, newdata)
95
96
96 if rl_type & store.FILEFLAGS_FILELOG:
97 if rl_type & store.FILEFLAGS_FILELOG:
97 destrepo.svfs.fncache.add(unencodedname)
98 destrepo.svfs.fncache.add(unencodedname)
98 if copydata:
99 if copydata:
99 destrepo.svfs.fncache.add(unencodedname[:-2] + b'.d')
100 destrepo.svfs.fncache.add(unencodedname[:-2] + b'.d')
100
101
101
102
102 UPGRADE_CHANGELOG = b"changelog"
103 UPGRADE_CHANGELOG = b"changelog"
103 UPGRADE_MANIFEST = b"manifest"
104 UPGRADE_MANIFEST = b"manifest"
104 UPGRADE_FILELOGS = b"all-filelogs"
105 UPGRADE_FILELOGS = b"all-filelogs"
105
106
106 UPGRADE_ALL_REVLOGS = frozenset(
107 UPGRADE_ALL_REVLOGS = frozenset(
107 [UPGRADE_CHANGELOG, UPGRADE_MANIFEST, UPGRADE_FILELOGS]
108 [UPGRADE_CHANGELOG, UPGRADE_MANIFEST, UPGRADE_FILELOGS]
108 )
109 )
109
110
110
111
111 def matchrevlog(revlogfilter, rl_type):
112 def matchrevlog(revlogfilter, rl_type):
112 """check if a revlog is selected for cloning.
113 """check if a revlog is selected for cloning.
113
114
114 In other words, are there any updates which need to be done on revlog
115 In other words, are there any updates which need to be done on revlog
115 or it can be blindly copied.
116 or it can be blindly copied.
116
117
117 The store entry is checked against the passed filter"""
118 The store entry is checked against the passed filter"""
118 if rl_type & store.FILEFLAGS_CHANGELOG:
119 if rl_type & store.FILEFLAGS_CHANGELOG:
119 return UPGRADE_CHANGELOG in revlogfilter
120 return UPGRADE_CHANGELOG in revlogfilter
120 elif rl_type & store.FILEFLAGS_MANIFESTLOG:
121 elif rl_type & store.FILEFLAGS_MANIFESTLOG:
121 return UPGRADE_MANIFEST in revlogfilter
122 return UPGRADE_MANIFEST in revlogfilter
122 assert rl_type & store.FILEFLAGS_FILELOG
123 assert rl_type & store.FILEFLAGS_FILELOG
123 return UPGRADE_FILELOGS in revlogfilter
124 return UPGRADE_FILELOGS in revlogfilter
124
125
125
126
126 def _perform_clone(
127 def _perform_clone(
127 ui,
128 ui,
128 dstrepo,
129 dstrepo,
129 tr,
130 tr,
130 old_revlog,
131 old_revlog,
131 rl_type,
132 rl_type,
132 unencoded,
133 unencoded,
133 upgrade_op,
134 upgrade_op,
134 sidedata_helpers,
135 sidedata_helpers,
135 oncopiedrevision,
136 oncopiedrevision,
136 ):
137 ):
137 """returns the new revlog object created"""
138 """returns the new revlog object created"""
138 newrl = None
139 newrl = None
139 if matchrevlog(upgrade_op.revlogs_to_process, rl_type):
140 if matchrevlog(upgrade_op.revlogs_to_process, rl_type):
140 ui.note(
141 ui.note(
141 _(b'cloning %d revisions from %s\n') % (len(old_revlog), unencoded)
142 _(b'cloning %d revisions from %s\n') % (len(old_revlog), unencoded)
142 )
143 )
143 newrl = _revlogfrompath(dstrepo, rl_type, unencoded)
144 newrl = _revlogfrompath(dstrepo, rl_type, unencoded)
144 old_revlog.clone(
145 old_revlog.clone(
145 tr,
146 tr,
146 newrl,
147 newrl,
147 addrevisioncb=oncopiedrevision,
148 addrevisioncb=oncopiedrevision,
148 deltareuse=upgrade_op.delta_reuse_mode,
149 deltareuse=upgrade_op.delta_reuse_mode,
149 forcedeltabothparents=upgrade_op.force_re_delta_both_parents,
150 forcedeltabothparents=upgrade_op.force_re_delta_both_parents,
150 sidedata_helpers=sidedata_helpers,
151 sidedata_helpers=sidedata_helpers,
151 )
152 )
152 else:
153 else:
153 msg = _(b'blindly copying %s containing %i revisions\n')
154 msg = _(b'blindly copying %s containing %i revisions\n')
154 ui.note(msg % (unencoded, len(old_revlog)))
155 ui.note(msg % (unencoded, len(old_revlog)))
155 _copyrevlog(tr, dstrepo, old_revlog, rl_type, unencoded)
156 _copyrevlog(tr, dstrepo, old_revlog, rl_type, unencoded)
156
157
157 newrl = _revlogfrompath(dstrepo, rl_type, unencoded)
158 newrl = _revlogfrompath(dstrepo, rl_type, unencoded)
158 return newrl
159 return newrl
159
160
160
161
161 def _clonerevlogs(
162 def _clonerevlogs(
162 ui,
163 ui,
163 srcrepo,
164 srcrepo,
164 dstrepo,
165 dstrepo,
165 tr,
166 tr,
166 upgrade_op,
167 upgrade_op,
167 ):
168 ):
168 """Copy revlogs between 2 repos."""
169 """Copy revlogs between 2 repos."""
169 revcount = 0
170 revcount = 0
170 srcsize = 0
171 srcsize = 0
171 srcrawsize = 0
172 srcrawsize = 0
172 dstsize = 0
173 dstsize = 0
173 fcount = 0
174 fcount = 0
174 frevcount = 0
175 frevcount = 0
175 fsrcsize = 0
176 fsrcsize = 0
176 frawsize = 0
177 frawsize = 0
177 fdstsize = 0
178 fdstsize = 0
178 mcount = 0
179 mcount = 0
179 mrevcount = 0
180 mrevcount = 0
180 msrcsize = 0
181 msrcsize = 0
181 mrawsize = 0
182 mrawsize = 0
182 mdstsize = 0
183 mdstsize = 0
183 crevcount = 0
184 crevcount = 0
184 csrcsize = 0
185 csrcsize = 0
185 crawsize = 0
186 crawsize = 0
186 cdstsize = 0
187 cdstsize = 0
187
188
188 alldatafiles = list(srcrepo.store.walk())
189 alldatafiles = list(srcrepo.store.walk())
189 # mapping of data files which needs to be cloned
190 # mapping of data files which needs to be cloned
190 # key is unencoded filename
191 # key is unencoded filename
191 # value is revlog_object_from_srcrepo
192 # value is revlog_object_from_srcrepo
192 manifests = {}
193 manifests = {}
193 changelogs = {}
194 changelogs = {}
194 filelogs = {}
195 filelogs = {}
195
196
196 # Perform a pass to collect metadata. This validates we can open all
197 # Perform a pass to collect metadata. This validates we can open all
197 # source files and allows a unified progress bar to be displayed.
198 # source files and allows a unified progress bar to be displayed.
198 for rl_type, unencoded, encoded, size in alldatafiles:
199 for rl_type, unencoded, encoded, size in alldatafiles:
199 if not rl_type & store.FILEFLAGS_REVLOG_MAIN:
200 if not rl_type & store.FILEFLAGS_REVLOG_MAIN:
200 continue
201 continue
201
202
202 rl = _revlogfrompath(srcrepo, rl_type, unencoded)
203 rl = _revlogfrompath(srcrepo, rl_type, unencoded)
203
204
204 info = rl.storageinfo(
205 info = rl.storageinfo(
205 exclusivefiles=True,
206 exclusivefiles=True,
206 revisionscount=True,
207 revisionscount=True,
207 trackedsize=True,
208 trackedsize=True,
208 storedsize=True,
209 storedsize=True,
209 )
210 )
210
211
211 revcount += info[b'revisionscount'] or 0
212 revcount += info[b'revisionscount'] or 0
212 datasize = info[b'storedsize'] or 0
213 datasize = info[b'storedsize'] or 0
213 rawsize = info[b'trackedsize'] or 0
214 rawsize = info[b'trackedsize'] or 0
214
215
215 srcsize += datasize
216 srcsize += datasize
216 srcrawsize += rawsize
217 srcrawsize += rawsize
217
218
218 # This is for the separate progress bars.
219 # This is for the separate progress bars.
219 if rl_type & store.FILEFLAGS_CHANGELOG:
220 if rl_type & store.FILEFLAGS_CHANGELOG:
220 changelogs[unencoded] = (rl_type, rl)
221 changelogs[unencoded] = (rl_type, rl)
221 crevcount += len(rl)
222 crevcount += len(rl)
222 csrcsize += datasize
223 csrcsize += datasize
223 crawsize += rawsize
224 crawsize += rawsize
224 elif rl_type & store.FILEFLAGS_MANIFESTLOG:
225 elif rl_type & store.FILEFLAGS_MANIFESTLOG:
225 manifests[unencoded] = (rl_type, rl)
226 manifests[unencoded] = (rl_type, rl)
226 mcount += 1
227 mcount += 1
227 mrevcount += len(rl)
228 mrevcount += len(rl)
228 msrcsize += datasize
229 msrcsize += datasize
229 mrawsize += rawsize
230 mrawsize += rawsize
230 elif rl_type & store.FILEFLAGS_FILELOG:
231 elif rl_type & store.FILEFLAGS_FILELOG:
231 filelogs[unencoded] = (rl_type, rl)
232 filelogs[unencoded] = (rl_type, rl)
232 fcount += 1
233 fcount += 1
233 frevcount += len(rl)
234 frevcount += len(rl)
234 fsrcsize += datasize
235 fsrcsize += datasize
235 frawsize += rawsize
236 frawsize += rawsize
236 else:
237 else:
237 error.ProgrammingError(b'unknown revlog type')
238 error.ProgrammingError(b'unknown revlog type')
238
239
239 if not revcount:
240 if not revcount:
240 return
241 return
241
242
242 ui.status(
243 ui.status(
243 _(
244 _(
244 b'migrating %d total revisions (%d in filelogs, %d in manifests, '
245 b'migrating %d total revisions (%d in filelogs, %d in manifests, '
245 b'%d in changelog)\n'
246 b'%d in changelog)\n'
246 )
247 )
247 % (revcount, frevcount, mrevcount, crevcount)
248 % (revcount, frevcount, mrevcount, crevcount)
248 )
249 )
249 ui.status(
250 ui.status(
250 _(b'migrating %s in store; %s tracked data\n')
251 _(b'migrating %s in store; %s tracked data\n')
251 % ((util.bytecount(srcsize), util.bytecount(srcrawsize)))
252 % ((util.bytecount(srcsize), util.bytecount(srcrawsize)))
252 )
253 )
253
254
254 # Used to keep track of progress.
255 # Used to keep track of progress.
255 progress = None
256 progress = None
256
257
257 def oncopiedrevision(rl, rev, node):
258 def oncopiedrevision(rl, rev, node):
258 progress.increment()
259 progress.increment()
259
260
260 sidedata_helpers = get_sidedata_helpers(srcrepo, dstrepo)
261 sidedata_helpers = get_sidedata_helpers(srcrepo, dstrepo)
261
262
262 # Migrating filelogs
263 # Migrating filelogs
263 ui.status(
264 ui.status(
264 _(
265 _(
265 b'migrating %d filelogs containing %d revisions '
266 b'migrating %d filelogs containing %d revisions '
266 b'(%s in store; %s tracked data)\n'
267 b'(%s in store; %s tracked data)\n'
267 )
268 )
268 % (
269 % (
269 fcount,
270 fcount,
270 frevcount,
271 frevcount,
271 util.bytecount(fsrcsize),
272 util.bytecount(fsrcsize),
272 util.bytecount(frawsize),
273 util.bytecount(frawsize),
273 )
274 )
274 )
275 )
275 progress = srcrepo.ui.makeprogress(_(b'file revisions'), total=frevcount)
276 progress = srcrepo.ui.makeprogress(_(b'file revisions'), total=frevcount)
276 for unencoded, (rl_type, oldrl) in sorted(filelogs.items()):
277 for unencoded, (rl_type, oldrl) in sorted(filelogs.items()):
277 newrl = _perform_clone(
278 newrl = _perform_clone(
278 ui,
279 ui,
279 dstrepo,
280 dstrepo,
280 tr,
281 tr,
281 oldrl,
282 oldrl,
282 rl_type,
283 rl_type,
283 unencoded,
284 unencoded,
284 upgrade_op,
285 upgrade_op,
285 sidedata_helpers,
286 sidedata_helpers,
286 oncopiedrevision,
287 oncopiedrevision,
287 )
288 )
288 info = newrl.storageinfo(storedsize=True)
289 info = newrl.storageinfo(storedsize=True)
289 fdstsize += info[b'storedsize'] or 0
290 fdstsize += info[b'storedsize'] or 0
290 ui.status(
291 ui.status(
291 _(
292 _(
292 b'finished migrating %d filelog revisions across %d '
293 b'finished migrating %d filelog revisions across %d '
293 b'filelogs; change in size: %s\n'
294 b'filelogs; change in size: %s\n'
294 )
295 )
295 % (frevcount, fcount, util.bytecount(fdstsize - fsrcsize))
296 % (frevcount, fcount, util.bytecount(fdstsize - fsrcsize))
296 )
297 )
297
298
298 # Migrating manifests
299 # Migrating manifests
299 ui.status(
300 ui.status(
300 _(
301 _(
301 b'migrating %d manifests containing %d revisions '
302 b'migrating %d manifests containing %d revisions '
302 b'(%s in store; %s tracked data)\n'
303 b'(%s in store; %s tracked data)\n'
303 )
304 )
304 % (
305 % (
305 mcount,
306 mcount,
306 mrevcount,
307 mrevcount,
307 util.bytecount(msrcsize),
308 util.bytecount(msrcsize),
308 util.bytecount(mrawsize),
309 util.bytecount(mrawsize),
309 )
310 )
310 )
311 )
311 if progress:
312 if progress:
312 progress.complete()
313 progress.complete()
313 progress = srcrepo.ui.makeprogress(
314 progress = srcrepo.ui.makeprogress(
314 _(b'manifest revisions'), total=mrevcount
315 _(b'manifest revisions'), total=mrevcount
315 )
316 )
316 for unencoded, (rl_type, oldrl) in sorted(manifests.items()):
317 for unencoded, (rl_type, oldrl) in sorted(manifests.items()):
317 newrl = _perform_clone(
318 newrl = _perform_clone(
318 ui,
319 ui,
319 dstrepo,
320 dstrepo,
320 tr,
321 tr,
321 oldrl,
322 oldrl,
322 rl_type,
323 rl_type,
323 unencoded,
324 unencoded,
324 upgrade_op,
325 upgrade_op,
325 sidedata_helpers,
326 sidedata_helpers,
326 oncopiedrevision,
327 oncopiedrevision,
327 )
328 )
328 info = newrl.storageinfo(storedsize=True)
329 info = newrl.storageinfo(storedsize=True)
329 mdstsize += info[b'storedsize'] or 0
330 mdstsize += info[b'storedsize'] or 0
330 ui.status(
331 ui.status(
331 _(
332 _(
332 b'finished migrating %d manifest revisions across %d '
333 b'finished migrating %d manifest revisions across %d '
333 b'manifests; change in size: %s\n'
334 b'manifests; change in size: %s\n'
334 )
335 )
335 % (mrevcount, mcount, util.bytecount(mdstsize - msrcsize))
336 % (mrevcount, mcount, util.bytecount(mdstsize - msrcsize))
336 )
337 )
337
338
338 # Migrating changelog
339 # Migrating changelog
339 ui.status(
340 ui.status(
340 _(
341 _(
341 b'migrating changelog containing %d revisions '
342 b'migrating changelog containing %d revisions '
342 b'(%s in store; %s tracked data)\n'
343 b'(%s in store; %s tracked data)\n'
343 )
344 )
344 % (
345 % (
345 crevcount,
346 crevcount,
346 util.bytecount(csrcsize),
347 util.bytecount(csrcsize),
347 util.bytecount(crawsize),
348 util.bytecount(crawsize),
348 )
349 )
349 )
350 )
350 if progress:
351 if progress:
351 progress.complete()
352 progress.complete()
352 progress = srcrepo.ui.makeprogress(
353 progress = srcrepo.ui.makeprogress(
353 _(b'changelog revisions'), total=crevcount
354 _(b'changelog revisions'), total=crevcount
354 )
355 )
355 for unencoded, (rl_type, oldrl) in sorted(changelogs.items()):
356 for unencoded, (rl_type, oldrl) in sorted(changelogs.items()):
356 newrl = _perform_clone(
357 newrl = _perform_clone(
357 ui,
358 ui,
358 dstrepo,
359 dstrepo,
359 tr,
360 tr,
360 oldrl,
361 oldrl,
361 rl_type,
362 rl_type,
362 unencoded,
363 unencoded,
363 upgrade_op,
364 upgrade_op,
364 sidedata_helpers,
365 sidedata_helpers,
365 oncopiedrevision,
366 oncopiedrevision,
366 )
367 )
367 info = newrl.storageinfo(storedsize=True)
368 info = newrl.storageinfo(storedsize=True)
368 cdstsize += info[b'storedsize'] or 0
369 cdstsize += info[b'storedsize'] or 0
369 progress.complete()
370 progress.complete()
370 ui.status(
371 ui.status(
371 _(
372 _(
372 b'finished migrating %d changelog revisions; change in size: '
373 b'finished migrating %d changelog revisions; change in size: '
373 b'%s\n'
374 b'%s\n'
374 )
375 )
375 % (crevcount, util.bytecount(cdstsize - csrcsize))
376 % (crevcount, util.bytecount(cdstsize - csrcsize))
376 )
377 )
377
378
378 dstsize = fdstsize + mdstsize + cdstsize
379 dstsize = fdstsize + mdstsize + cdstsize
379 ui.status(
380 ui.status(
380 _(
381 _(
381 b'finished migrating %d total revisions; total change in store '
382 b'finished migrating %d total revisions; total change in store '
382 b'size: %s\n'
383 b'size: %s\n'
383 )
384 )
384 % (revcount, util.bytecount(dstsize - srcsize))
385 % (revcount, util.bytecount(dstsize - srcsize))
385 )
386 )
386
387
387
388
388 def _files_to_copy_post_revlog_clone(srcrepo):
389 def _files_to_copy_post_revlog_clone(srcrepo):
389 """yields files which should be copied to destination after revlogs
390 """yields files which should be copied to destination after revlogs
390 are cloned"""
391 are cloned"""
391 for path, kind, st in sorted(srcrepo.store.vfs.readdir(b'', stat=True)):
392 for path, kind, st in sorted(srcrepo.store.vfs.readdir(b'', stat=True)):
392 # don't copy revlogs as they are already cloned
393 # don't copy revlogs as they are already cloned
393 if store.revlog_type(path) is not None:
394 if store.revlog_type(path) is not None:
394 continue
395 continue
395 # Skip transaction related files.
396 # Skip transaction related files.
396 if path.startswith(b'undo'):
397 if path.startswith(b'undo'):
397 continue
398 continue
398 # Only copy regular files.
399 # Only copy regular files.
399 if kind != stat.S_IFREG:
400 if kind != stat.S_IFREG:
400 continue
401 continue
401 # Skip other skipped files.
402 # Skip other skipped files.
402 if path in (b'lock', b'fncache'):
403 if path in (b'lock', b'fncache'):
403 continue
404 continue
404 # TODO: should we skip cache too?
405 # TODO: should we skip cache too?
405
406
406 yield path
407 yield path
407
408
408
409
409 def _replacestores(currentrepo, upgradedrepo, backupvfs, upgrade_op):
410 def _replacestores(currentrepo, upgradedrepo, backupvfs, upgrade_op):
410 """Replace the stores after current repository is upgraded
411 """Replace the stores after current repository is upgraded
411
412
412 Creates a backup of current repository store at backup path
413 Creates a backup of current repository store at backup path
413 Replaces upgraded store files in current repo from upgraded one
414 Replaces upgraded store files in current repo from upgraded one
414
415
415 Arguments:
416 Arguments:
416 currentrepo: repo object of current repository
417 currentrepo: repo object of current repository
417 upgradedrepo: repo object of the upgraded data
418 upgradedrepo: repo object of the upgraded data
418 backupvfs: vfs object for the backup path
419 backupvfs: vfs object for the backup path
419 upgrade_op: upgrade operation object
420 upgrade_op: upgrade operation object
420 to be used to decide what all is upgraded
421 to be used to decide what all is upgraded
421 """
422 """
422 # TODO: don't blindly rename everything in store
423 # TODO: don't blindly rename everything in store
423 # There can be upgrades where store is not touched at all
424 # There can be upgrades where store is not touched at all
424 if upgrade_op.backup_store:
425 if upgrade_op.backup_store:
425 util.rename(currentrepo.spath, backupvfs.join(b'store'))
426 util.rename(currentrepo.spath, backupvfs.join(b'store'))
426 else:
427 else:
427 currentrepo.vfs.rmtree(b'store', forcibly=True)
428 currentrepo.vfs.rmtree(b'store', forcibly=True)
428 util.rename(upgradedrepo.spath, currentrepo.spath)
429 util.rename(upgradedrepo.spath, currentrepo.spath)
429
430
430
431
431 def finishdatamigration(ui, srcrepo, dstrepo, requirements):
432 def finishdatamigration(ui, srcrepo, dstrepo, requirements):
432 """Hook point for extensions to perform additional actions during upgrade.
433 """Hook point for extensions to perform additional actions during upgrade.
433
434
434 This function is called after revlogs and store files have been copied but
435 This function is called after revlogs and store files have been copied but
435 before the new store is swapped into the original location.
436 before the new store is swapped into the original location.
436 """
437 """
437
438
438
439
439 def upgrade(ui, srcrepo, dstrepo, upgrade_op):
440 def upgrade(ui, srcrepo, dstrepo, upgrade_op):
440 """Do the low-level work of upgrading a repository.
441 """Do the low-level work of upgrading a repository.
441
442
442 The upgrade is effectively performed as a copy between a source
443 The upgrade is effectively performed as a copy between a source
443 repository and a temporary destination repository.
444 repository and a temporary destination repository.
444
445
445 The source repository is unmodified for as long as possible so the
446 The source repository is unmodified for as long as possible so the
446 upgrade can abort at any time without causing loss of service for
447 upgrade can abort at any time without causing loss of service for
447 readers and without corrupting the source repository.
448 readers and without corrupting the source repository.
448 """
449 """
449 assert srcrepo.currentwlock()
450 assert srcrepo.currentwlock()
450 assert dstrepo.currentwlock()
451 assert dstrepo.currentwlock()
451 backuppath = None
452 backuppath = None
452 backupvfs = None
453 backupvfs = None
453
454
454 ui.status(
455 ui.status(
455 _(
456 _(
456 b'(it is safe to interrupt this process any time before '
457 b'(it is safe to interrupt this process any time before '
457 b'data migration completes)\n'
458 b'data migration completes)\n'
458 )
459 )
459 )
460 )
460
461
462 if upgrade_actions.dirstatev2 in upgrade_op.upgrade_actions:
463 ui.status(_(b'upgrading to dirstate-v2 from v1\n'))
464 upgrade_dirstate(ui, srcrepo, upgrade_op, b'v1', b'v2')
465 upgrade_op.upgrade_actions.remove(upgrade_actions.dirstatev2)
466
467 if upgrade_actions.dirstatev2 in upgrade_op.removed_actions:
468 ui.status(_(b'downgrading from dirstate-v2 to v1\n'))
469 upgrade_dirstate(ui, srcrepo, upgrade_op, b'v2', b'v1')
470 upgrade_op.removed_actions.remove(upgrade_actions.dirstatev2)
471
472 if not (upgrade_op.upgrade_actions or upgrade_op.removed_actions):
473 return
474
461 if upgrade_op.requirements_only:
475 if upgrade_op.requirements_only:
462 ui.status(_(b'upgrading repository requirements\n'))
476 ui.status(_(b'upgrading repository requirements\n'))
463 scmutil.writereporequirements(srcrepo, upgrade_op.new_requirements)
477 scmutil.writereporequirements(srcrepo, upgrade_op.new_requirements)
464 # if there is only one action and that is persistent nodemap upgrade
478 # if there is only one action and that is persistent nodemap upgrade
465 # directly write the nodemap file and update requirements instead of going
479 # directly write the nodemap file and update requirements instead of going
466 # through the whole cloning process
480 # through the whole cloning process
467 elif (
481 elif (
468 len(upgrade_op.upgrade_actions) == 1
482 len(upgrade_op.upgrade_actions) == 1
469 and b'persistent-nodemap' in upgrade_op._upgrade_actions_names
483 and b'persistent-nodemap' in upgrade_op.upgrade_actions_names
470 and not upgrade_op.removed_actions
484 and not upgrade_op.removed_actions
471 ):
485 ):
472 ui.status(
486 ui.status(
473 _(b'upgrading repository to use persistent nodemap feature\n')
487 _(b'upgrading repository to use persistent nodemap feature\n')
474 )
488 )
475 with srcrepo.transaction(b'upgrade') as tr:
489 with srcrepo.transaction(b'upgrade') as tr:
476 unfi = srcrepo.unfiltered()
490 unfi = srcrepo.unfiltered()
477 cl = unfi.changelog
491 cl = unfi.changelog
478 nodemap.persist_nodemap(tr, cl, force=True)
492 nodemap.persist_nodemap(tr, cl, force=True)
479 # we want to directly operate on the underlying revlog to force
493 # we want to directly operate on the underlying revlog to force
480 # create a nodemap file. This is fine since this is upgrade code
494 # create a nodemap file. This is fine since this is upgrade code
481 # and it heavily relies on repository being revlog based
495 # and it heavily relies on repository being revlog based
482 # hence accessing private attributes can be justified
496 # hence accessing private attributes can be justified
483 nodemap.persist_nodemap(
497 nodemap.persist_nodemap(
484 tr, unfi.manifestlog._rootstore._revlog, force=True
498 tr, unfi.manifestlog._rootstore._revlog, force=True
485 )
499 )
486 scmutil.writereporequirements(srcrepo, upgrade_op.new_requirements)
500 scmutil.writereporequirements(srcrepo, upgrade_op.new_requirements)
487 elif (
501 elif (
488 len(upgrade_op.removed_actions) == 1
502 len(upgrade_op.removed_actions) == 1
489 and [
503 and [
490 x
504 x
491 for x in upgrade_op.removed_actions
505 for x in upgrade_op.removed_actions
492 if x.name == b'persistent-nodemap'
506 if x.name == b'persistent-nodemap'
493 ]
507 ]
494 and not upgrade_op.upgrade_actions
508 and not upgrade_op.upgrade_actions
495 ):
509 ):
496 ui.status(
510 ui.status(
497 _(b'downgrading repository to not use persistent nodemap feature\n')
511 _(b'downgrading repository to not use persistent nodemap feature\n')
498 )
512 )
499 with srcrepo.transaction(b'upgrade') as tr:
513 with srcrepo.transaction(b'upgrade') as tr:
500 unfi = srcrepo.unfiltered()
514 unfi = srcrepo.unfiltered()
501 cl = unfi.changelog
515 cl = unfi.changelog
502 nodemap.delete_nodemap(tr, srcrepo, cl)
516 nodemap.delete_nodemap(tr, srcrepo, cl)
503 # check comment 20 lines above for accessing private attributes
517 # check comment 20 lines above for accessing private attributes
504 nodemap.delete_nodemap(
518 nodemap.delete_nodemap(
505 tr, srcrepo, unfi.manifestlog._rootstore._revlog
519 tr, srcrepo, unfi.manifestlog._rootstore._revlog
506 )
520 )
507 scmutil.writereporequirements(srcrepo, upgrade_op.new_requirements)
521 scmutil.writereporequirements(srcrepo, upgrade_op.new_requirements)
508 else:
522 else:
509 with dstrepo.transaction(b'upgrade') as tr:
523 with dstrepo.transaction(b'upgrade') as tr:
510 _clonerevlogs(
524 _clonerevlogs(
511 ui,
525 ui,
512 srcrepo,
526 srcrepo,
513 dstrepo,
527 dstrepo,
514 tr,
528 tr,
515 upgrade_op,
529 upgrade_op,
516 )
530 )
517
531
518 # Now copy other files in the store directory.
532 # Now copy other files in the store directory.
519 for p in _files_to_copy_post_revlog_clone(srcrepo):
533 for p in _files_to_copy_post_revlog_clone(srcrepo):
520 srcrepo.ui.status(_(b'copying %s\n') % p)
534 srcrepo.ui.status(_(b'copying %s\n') % p)
521 src = srcrepo.store.rawvfs.join(p)
535 src = srcrepo.store.rawvfs.join(p)
522 dst = dstrepo.store.rawvfs.join(p)
536 dst = dstrepo.store.rawvfs.join(p)
523 util.copyfile(src, dst, copystat=True)
537 util.copyfile(src, dst, copystat=True)
524
538
525 finishdatamigration(ui, srcrepo, dstrepo, requirements)
539 finishdatamigration(ui, srcrepo, dstrepo, requirements)
526
540
527 ui.status(_(b'data fully upgraded in a temporary repository\n'))
541 ui.status(_(b'data fully upgraded in a temporary repository\n'))
528
542
529 if upgrade_op.backup_store:
543 if upgrade_op.backup_store:
530 backuppath = pycompat.mkdtemp(
544 backuppath = pycompat.mkdtemp(
531 prefix=b'upgradebackup.', dir=srcrepo.path
545 prefix=b'upgradebackup.', dir=srcrepo.path
532 )
546 )
533 backupvfs = vfsmod.vfs(backuppath)
547 backupvfs = vfsmod.vfs(backuppath)
534
548
535 # Make a backup of requires file first, as it is the first to be modified.
549 # Make a backup of requires file first, as it is the first to be modified.
536 util.copyfile(
550 util.copyfile(
537 srcrepo.vfs.join(b'requires'), backupvfs.join(b'requires')
551 srcrepo.vfs.join(b'requires'), backupvfs.join(b'requires')
538 )
552 )
539
553
540 # We install an arbitrary requirement that clients must not support
554 # We install an arbitrary requirement that clients must not support
541 # as a mechanism to lock out new clients during the data swap. This is
555 # as a mechanism to lock out new clients during the data swap. This is
542 # better than allowing a client to continue while the repository is in
556 # better than allowing a client to continue while the repository is in
543 # an inconsistent state.
557 # an inconsistent state.
544 ui.status(
558 ui.status(
545 _(
559 _(
546 b'marking source repository as being upgraded; clients will be '
560 b'marking source repository as being upgraded; clients will be '
547 b'unable to read from repository\n'
561 b'unable to read from repository\n'
548 )
562 )
549 )
563 )
550 scmutil.writereporequirements(
564 scmutil.writereporequirements(
551 srcrepo, srcrepo.requirements | {b'upgradeinprogress'}
565 srcrepo, srcrepo.requirements | {b'upgradeinprogress'}
552 )
566 )
553
567
554 ui.status(_(b'starting in-place swap of repository data\n'))
568 ui.status(_(b'starting in-place swap of repository data\n'))
555 if upgrade_op.backup_store:
569 if upgrade_op.backup_store:
556 ui.status(
570 ui.status(
557 _(b'replaced files will be backed up at %s\n') % backuppath
571 _(b'replaced files will be backed up at %s\n') % backuppath
558 )
572 )
559
573
560 # Now swap in the new store directory. Doing it as a rename should make
574 # Now swap in the new store directory. Doing it as a rename should make
561 # the operation nearly instantaneous and atomic (at least in well-behaved
575 # the operation nearly instantaneous and atomic (at least in well-behaved
562 # environments).
576 # environments).
563 ui.status(_(b'replacing store...\n'))
577 ui.status(_(b'replacing store...\n'))
564 tstart = util.timer()
578 tstart = util.timer()
565 _replacestores(srcrepo, dstrepo, backupvfs, upgrade_op)
579 _replacestores(srcrepo, dstrepo, backupvfs, upgrade_op)
566 elapsed = util.timer() - tstart
580 elapsed = util.timer() - tstart
567 ui.status(
581 ui.status(
568 _(
582 _(
569 b'store replacement complete; repository was inconsistent for '
583 b'store replacement complete; repository was inconsistent for '
570 b'%0.1fs\n'
584 b'%0.1fs\n'
571 )
585 )
572 % elapsed
586 % elapsed
573 )
587 )
574
588
575 # We first write the requirements file. Any new requirements will lock
589 # We first write the requirements file. Any new requirements will lock
576 # out legacy clients.
590 # out legacy clients.
577 ui.status(
591 ui.status(
578 _(
592 _(
579 b'finalizing requirements file and making repository readable '
593 b'finalizing requirements file and making repository readable '
580 b'again\n'
594 b'again\n'
581 )
595 )
582 )
596 )
583 scmutil.writereporequirements(srcrepo, upgrade_op.new_requirements)
597 scmutil.writereporequirements(srcrepo, upgrade_op.new_requirements)
584
598
585 if upgrade_op.backup_store:
599 if upgrade_op.backup_store:
586 # The lock file from the old store won't be removed because nothing has a
600 # The lock file from the old store won't be removed because nothing has a
587 # reference to its new location. So clean it up manually. Alternatively, we
601 # reference to its new location. So clean it up manually. Alternatively, we
588 # could update srcrepo.svfs and other variables to point to the new
602 # could update srcrepo.svfs and other variables to point to the new
589 # location. This is simpler.
603 # location. This is simpler.
590 assert backupvfs is not None # help pytype
604 assert backupvfs is not None # help pytype
591 backupvfs.unlink(b'store/lock')
605 backupvfs.unlink(b'store/lock')
592
606
593 return backuppath
607 return backuppath
608
609
610 def upgrade_dirstate(ui, srcrepo, upgrade_op, old, new):
611 if upgrade_op.backup_store:
612 backuppath = pycompat.mkdtemp(
613 prefix=b'upgradebackup.', dir=srcrepo.path
614 )
615 ui.status(_(b'replaced files will be backed up at %s\n') % backuppath)
616 backupvfs = vfsmod.vfs(backuppath)
617 util.copyfile(
618 srcrepo.vfs.join(b'requires'), backupvfs.join(b'requires')
619 )
620 util.copyfile(
621 srcrepo.vfs.join(b'dirstate'), backupvfs.join(b'dirstate')
622 )
623
624 assert srcrepo.dirstate._use_dirstate_v2 == (old == b'v2')
625 srcrepo.dirstate._map._use_dirstate_tree = True
626 srcrepo.dirstate._map.preload()
627 srcrepo.dirstate._use_dirstate_v2 = new == b'v2'
628 srcrepo.dirstate._map._use_dirstate_v2 = srcrepo.dirstate._use_dirstate_v2
629 srcrepo.dirstate._dirty = True
630 srcrepo.dirstate.write(None)
631
632 scmutil.writereporequirements(srcrepo, upgrade_op.new_requirements)
@@ -1,3872 +1,3874 b''
1 #testcases filelog compatibility changeset sidedata upgraded upgraded-parallel pull push pull-upgrade push-upgrade
1 #testcases filelog compatibility changeset sidedata upgraded upgraded-parallel pull push pull-upgrade push-upgrade
2
2
3 =====================================================
3 =====================================================
4 Test Copy tracing for chain of copies involving merge
4 Test Copy tracing for chain of copies involving merge
5 =====================================================
5 =====================================================
6
6
7 This test files covers copies/rename case for a chains of commit where merges
7 This test files covers copies/rename case for a chains of commit where merges
8 are involved. It cheks we do not have unwanted update of behavior and that the
8 are involved. It cheks we do not have unwanted update of behavior and that the
9 different options to retrieve copies behave correctly.
9 different options to retrieve copies behave correctly.
10
10
11
11
12 Setup
12 Setup
13 =====
13 =====
14
14
15 use git diff to see rename
15 use git diff to see rename
16
16
17 $ cat << EOF >> ./no-linkrev
17 $ cat << EOF >> ./no-linkrev
18 > #!$PYTHON
18 > #!$PYTHON
19 > # filter out linkrev part of the debugindex command
19 > # filter out linkrev part of the debugindex command
20 > import sys
20 > import sys
21 > for line in sys.stdin:
21 > for line in sys.stdin:
22 > if " linkrev " in line:
22 > if " linkrev " in line:
23 > print(line.rstrip())
23 > print(line.rstrip())
24 > else:
24 > else:
25 > l = "%s *%s" % (line[:6], line[14:].rstrip())
25 > l = "%s *%s" % (line[:6], line[14:].rstrip())
26 > print(l)
26 > print(l)
27 > EOF
27 > EOF
28
28
29 $ cat << EOF >> $HGRCPATH
29 $ cat << EOF >> $HGRCPATH
30 > [diff]
30 > [diff]
31 > git=yes
31 > git=yes
32 > [command-templates]
32 > [command-templates]
33 > log={desc}\n
33 > log={desc}\n
34 > EOF
34 > EOF
35
35
36 #if compatibility
36 #if compatibility
37 $ cat >> $HGRCPATH << EOF
37 $ cat >> $HGRCPATH << EOF
38 > [experimental]
38 > [experimental]
39 > copies.read-from = compatibility
39 > copies.read-from = compatibility
40 > EOF
40 > EOF
41 #endif
41 #endif
42
42
43 #if changeset
43 #if changeset
44 $ cat >> $HGRCPATH << EOF
44 $ cat >> $HGRCPATH << EOF
45 > [experimental]
45 > [experimental]
46 > copies.read-from = changeset-only
46 > copies.read-from = changeset-only
47 > copies.write-to = changeset-only
47 > copies.write-to = changeset-only
48 > EOF
48 > EOF
49 #endif
49 #endif
50
50
51 #if sidedata
51 #if sidedata
52 $ cat >> $HGRCPATH << EOF
52 $ cat >> $HGRCPATH << EOF
53 > [format]
53 > [format]
54 > exp-use-copies-side-data-changeset = yes
54 > exp-use-copies-side-data-changeset = yes
55 > EOF
55 > EOF
56 #endif
56 #endif
57
57
58 #if pull
58 #if pull
59 $ cat >> $HGRCPATH << EOF
59 $ cat >> $HGRCPATH << EOF
60 > [format]
60 > [format]
61 > exp-use-copies-side-data-changeset = yes
61 > exp-use-copies-side-data-changeset = yes
62 > EOF
62 > EOF
63 #endif
63 #endif
64
64
65 #if push
65 #if push
66 $ cat >> $HGRCPATH << EOF
66 $ cat >> $HGRCPATH << EOF
67 > [format]
67 > [format]
68 > exp-use-copies-side-data-changeset = yes
68 > exp-use-copies-side-data-changeset = yes
69 > EOF
69 > EOF
70 #endif
70 #endif
71
71
72 #if pull-upgrade
72 #if pull-upgrade
73 $ cat >> $HGRCPATH << EOF
73 $ cat >> $HGRCPATH << EOF
74 > [format]
74 > [format]
75 > exp-use-copies-side-data-changeset = no
75 > exp-use-copies-side-data-changeset = no
76 > [experimental]
76 > [experimental]
77 > changegroup4 = yes
77 > changegroup4 = yes
78 > EOF
78 > EOF
79 #endif
79 #endif
80
80
81 #if push-upgrade
81 #if push-upgrade
82 $ cat >> $HGRCPATH << EOF
82 $ cat >> $HGRCPATH << EOF
83 > [format]
83 > [format]
84 > exp-use-copies-side-data-changeset = no
84 > exp-use-copies-side-data-changeset = no
85 > [experimental]
85 > [experimental]
86 > changegroup4 = yes
86 > changegroup4 = yes
87 > EOF
87 > EOF
88 #endif
88 #endif
89
89
90 $ cat > same-content.txt << EOF
90 $ cat > same-content.txt << EOF
91 > Here is some content that will be the same accros multiple file.
91 > Here is some content that will be the same accros multiple file.
92 >
92 >
93 > This is done on purpose so that we end up in some merge situation, were the
93 > This is done on purpose so that we end up in some merge situation, were the
94 > resulting content is the same as in the parent(s), but a new filenodes still
94 > resulting content is the same as in the parent(s), but a new filenodes still
95 > need to be created to record some file history information (especially
95 > need to be created to record some file history information (especially
96 > about copies).
96 > about copies).
97 > EOF
97 > EOF
98
98
99 $ hg init repo-chain
99 $ hg init repo-chain
100 $ cd repo-chain
100 $ cd repo-chain
101
101
102 Add some linear rename initialy
102 Add some linear rename initialy
103
103
104 $ cp ../same-content.txt a
104 $ cp ../same-content.txt a
105 $ cp ../same-content.txt b
105 $ cp ../same-content.txt b
106 $ cp ../same-content.txt h
106 $ cp ../same-content.txt h
107 $ echo "original content for P" > p
107 $ echo "original content for P" > p
108 $ echo "original content for Q" > q
108 $ echo "original content for Q" > q
109 $ echo "original content for R" > r
109 $ echo "original content for R" > r
110 $ hg ci -Am 'i-0 initial commit: a b h p q r'
110 $ hg ci -Am 'i-0 initial commit: a b h p q r'
111 adding a
111 adding a
112 adding b
112 adding b
113 adding h
113 adding h
114 adding p
114 adding p
115 adding q
115 adding q
116 adding r
116 adding r
117 $ hg mv a c
117 $ hg mv a c
118 $ hg mv p s
118 $ hg mv p s
119 $ hg ci -Am 'i-1: a -move-> c, p -move-> s'
119 $ hg ci -Am 'i-1: a -move-> c, p -move-> s'
120 $ hg mv c d
120 $ hg mv c d
121 $ hg mv s t
121 $ hg mv s t
122 $ hg ci -Am 'i-2: c -move-> d, s -move-> t'
122 $ hg ci -Am 'i-2: c -move-> d, s -move-> t'
123 $ hg log -G
123 $ hg log -G
124 @ i-2: c -move-> d, s -move-> t
124 @ i-2: c -move-> d, s -move-> t
125 |
125 |
126 o i-1: a -move-> c, p -move-> s
126 o i-1: a -move-> c, p -move-> s
127 |
127 |
128 o i-0 initial commit: a b h p q r
128 o i-0 initial commit: a b h p q r
129
129
130
130
131 And having another branch with renames on the other side
131 And having another branch with renames on the other side
132
132
133 $ hg mv d e
133 $ hg mv d e
134 $ hg ci -Am 'a-1: d -move-> e'
134 $ hg ci -Am 'a-1: d -move-> e'
135 $ hg mv e f
135 $ hg mv e f
136 $ hg ci -Am 'a-2: e -move-> f'
136 $ hg ci -Am 'a-2: e -move-> f'
137 $ hg log -G --rev '::.'
137 $ hg log -G --rev '::.'
138 @ a-2: e -move-> f
138 @ a-2: e -move-> f
139 |
139 |
140 o a-1: d -move-> e
140 o a-1: d -move-> e
141 |
141 |
142 o i-2: c -move-> d, s -move-> t
142 o i-2: c -move-> d, s -move-> t
143 |
143 |
144 o i-1: a -move-> c, p -move-> s
144 o i-1: a -move-> c, p -move-> s
145 |
145 |
146 o i-0 initial commit: a b h p q r
146 o i-0 initial commit: a b h p q r
147
147
148
148
149 Have a branching with nothing on one side
149 Have a branching with nothing on one side
150
150
151 $ hg up 'desc("i-2")'
151 $ hg up 'desc("i-2")'
152 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
152 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
153 $ echo foo > b
153 $ echo foo > b
154 $ hg ci -m 'b-1: b update'
154 $ hg ci -m 'b-1: b update'
155 created new head
155 created new head
156 $ hg log -G --rev '::.'
156 $ hg log -G --rev '::.'
157 @ b-1: b update
157 @ b-1: b update
158 |
158 |
159 o i-2: c -move-> d, s -move-> t
159 o i-2: c -move-> d, s -move-> t
160 |
160 |
161 o i-1: a -move-> c, p -move-> s
161 o i-1: a -move-> c, p -move-> s
162 |
162 |
163 o i-0 initial commit: a b h p q r
163 o i-0 initial commit: a b h p q r
164
164
165
165
166 Create a branch that delete a file previous renamed
166 Create a branch that delete a file previous renamed
167
167
168 $ hg up 'desc("i-2")'
168 $ hg up 'desc("i-2")'
169 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
169 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
170 $ hg rm d
170 $ hg rm d
171 $ hg ci -m 'c-1 delete d'
171 $ hg ci -m 'c-1 delete d'
172 created new head
172 created new head
173 $ hg log -G --rev '::.'
173 $ hg log -G --rev '::.'
174 @ c-1 delete d
174 @ c-1 delete d
175 |
175 |
176 o i-2: c -move-> d, s -move-> t
176 o i-2: c -move-> d, s -move-> t
177 |
177 |
178 o i-1: a -move-> c, p -move-> s
178 o i-1: a -move-> c, p -move-> s
179 |
179 |
180 o i-0 initial commit: a b h p q r
180 o i-0 initial commit: a b h p q r
181
181
182
182
183 Create a branch that delete a file previous renamed and recreate it
183 Create a branch that delete a file previous renamed and recreate it
184
184
185 $ hg up 'desc("i-2")'
185 $ hg up 'desc("i-2")'
186 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
186 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
187 $ hg rm d
187 $ hg rm d
188 $ hg ci -m 'd-1 delete d'
188 $ hg ci -m 'd-1 delete d'
189 created new head
189 created new head
190 $ echo bar > d
190 $ echo bar > d
191 $ hg add d
191 $ hg add d
192 $ hg ci -m 'd-2 re-add d'
192 $ hg ci -m 'd-2 re-add d'
193 $ hg log -G --rev '::.'
193 $ hg log -G --rev '::.'
194 @ d-2 re-add d
194 @ d-2 re-add d
195 |
195 |
196 o d-1 delete d
196 o d-1 delete d
197 |
197 |
198 o i-2: c -move-> d, s -move-> t
198 o i-2: c -move-> d, s -move-> t
199 |
199 |
200 o i-1: a -move-> c, p -move-> s
200 o i-1: a -move-> c, p -move-> s
201 |
201 |
202 o i-0 initial commit: a b h p q r
202 o i-0 initial commit: a b h p q r
203
203
204
204
205 Having another branch renaming a different file to the same filename as another
205 Having another branch renaming a different file to the same filename as another
206
206
207 $ hg up 'desc("i-2")'
207 $ hg up 'desc("i-2")'
208 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
208 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
209 $ hg mv b g
209 $ hg mv b g
210 $ hg ci -m 'e-1 b -move-> g'
210 $ hg ci -m 'e-1 b -move-> g'
211 created new head
211 created new head
212 $ hg mv g f
212 $ hg mv g f
213 $ hg ci -m 'e-2 g -move-> f'
213 $ hg ci -m 'e-2 g -move-> f'
214 $ hg log -G --rev '::.'
214 $ hg log -G --rev '::.'
215 @ e-2 g -move-> f
215 @ e-2 g -move-> f
216 |
216 |
217 o e-1 b -move-> g
217 o e-1 b -move-> g
218 |
218 |
219 o i-2: c -move-> d, s -move-> t
219 o i-2: c -move-> d, s -move-> t
220 |
220 |
221 o i-1: a -move-> c, p -move-> s
221 o i-1: a -move-> c, p -move-> s
222 |
222 |
223 o i-0 initial commit: a b h p q r
223 o i-0 initial commit: a b h p q r
224
224
225 $ hg up -q null
225 $ hg up -q null
226
226
227 Having a branch similar to the 'a' one, but moving the 'p' file around.
227 Having a branch similar to the 'a' one, but moving the 'p' file around.
228
228
229 $ hg up 'desc("i-2")'
229 $ hg up 'desc("i-2")'
230 6 files updated, 0 files merged, 0 files removed, 0 files unresolved
230 6 files updated, 0 files merged, 0 files removed, 0 files unresolved
231 $ hg mv t u
231 $ hg mv t u
232 $ hg ci -Am 'p-1: t -move-> u'
232 $ hg ci -Am 'p-1: t -move-> u'
233 created new head
233 created new head
234 $ hg mv u v
234 $ hg mv u v
235 $ hg ci -Am 'p-2: u -move-> v'
235 $ hg ci -Am 'p-2: u -move-> v'
236 $ hg log -G --rev '::.'
236 $ hg log -G --rev '::.'
237 @ p-2: u -move-> v
237 @ p-2: u -move-> v
238 |
238 |
239 o p-1: t -move-> u
239 o p-1: t -move-> u
240 |
240 |
241 o i-2: c -move-> d, s -move-> t
241 o i-2: c -move-> d, s -move-> t
242 |
242 |
243 o i-1: a -move-> c, p -move-> s
243 o i-1: a -move-> c, p -move-> s
244 |
244 |
245 o i-0 initial commit: a b h p q r
245 o i-0 initial commit: a b h p q r
246
246
247 $ hg up -q null
247 $ hg up -q null
248
248
249 Having another branch renaming a different file to the same filename as another
249 Having another branch renaming a different file to the same filename as another
250
250
251 $ hg up 'desc("i-2")'
251 $ hg up 'desc("i-2")'
252 6 files updated, 0 files merged, 0 files removed, 0 files unresolved
252 6 files updated, 0 files merged, 0 files removed, 0 files unresolved
253 $ hg mv r w
253 $ hg mv r w
254 $ hg ci -m 'q-1 r -move-> w'
254 $ hg ci -m 'q-1 r -move-> w'
255 created new head
255 created new head
256 $ hg mv w v
256 $ hg mv w v
257 $ hg ci -m 'q-2 w -move-> v'
257 $ hg ci -m 'q-2 w -move-> v'
258 $ hg log -G --rev '::.'
258 $ hg log -G --rev '::.'
259 @ q-2 w -move-> v
259 @ q-2 w -move-> v
260 |
260 |
261 o q-1 r -move-> w
261 o q-1 r -move-> w
262 |
262 |
263 o i-2: c -move-> d, s -move-> t
263 o i-2: c -move-> d, s -move-> t
264 |
264 |
265 o i-1: a -move-> c, p -move-> s
265 o i-1: a -move-> c, p -move-> s
266 |
266 |
267 o i-0 initial commit: a b h p q r
267 o i-0 initial commit: a b h p q r
268
268
269 $ hg up -q null
269 $ hg up -q null
270
270
271 Setup all merge
271 Setup all merge
272 ===============
272 ===============
273
273
274 This is done beforehand to validate that the upgrade process creates valid copy
274 This is done beforehand to validate that the upgrade process creates valid copy
275 information.
275 information.
276
276
277 merging with unrelated change does not interfere with the renames
277 merging with unrelated change does not interfere with the renames
278 ---------------------------------------------------------------
278 ---------------------------------------------------------------
279
279
280 - rename on one side
280 - rename on one side
281 - unrelated change on the other side
281 - unrelated change on the other side
282
282
283 $ case_desc="simple merge - A side: multiple renames, B side: unrelated update"
283 $ case_desc="simple merge - A side: multiple renames, B side: unrelated update"
284
284
285 $ hg up 'desc("b-1")'
285 $ hg up 'desc("b-1")'
286 6 files updated, 0 files merged, 0 files removed, 0 files unresolved
286 6 files updated, 0 files merged, 0 files removed, 0 files unresolved
287 $ hg merge 'desc("a-2")'
287 $ hg merge 'desc("a-2")'
288 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
288 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
289 (branch merge, don't forget to commit)
289 (branch merge, don't forget to commit)
290 $ hg ci -m "mBAm-0 $case_desc - one way"
290 $ hg ci -m "mBAm-0 $case_desc - one way"
291 $ hg up 'desc("a-2")'
291 $ hg up 'desc("a-2")'
292 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
292 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
293 $ hg merge 'desc("b-1")'
293 $ hg merge 'desc("b-1")'
294 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
294 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
295 (branch merge, don't forget to commit)
295 (branch merge, don't forget to commit)
296 $ hg ci -m "mABm-0 $case_desc - the other way"
296 $ hg ci -m "mABm-0 $case_desc - the other way"
297 created new head
297 created new head
298 $ hg log -G --rev '::(desc("mABm")+desc("mBAm"))'
298 $ hg log -G --rev '::(desc("mABm")+desc("mBAm"))'
299 @ mABm-0 simple merge - A side: multiple renames, B side: unrelated update - the other way
299 @ mABm-0 simple merge - A side: multiple renames, B side: unrelated update - the other way
300 |\
300 |\
301 +---o mBAm-0 simple merge - A side: multiple renames, B side: unrelated update - one way
301 +---o mBAm-0 simple merge - A side: multiple renames, B side: unrelated update - one way
302 | |/
302 | |/
303 | o b-1: b update
303 | o b-1: b update
304 | |
304 | |
305 o | a-2: e -move-> f
305 o | a-2: e -move-> f
306 | |
306 | |
307 o | a-1: d -move-> e
307 o | a-1: d -move-> e
308 |/
308 |/
309 o i-2: c -move-> d, s -move-> t
309 o i-2: c -move-> d, s -move-> t
310 |
310 |
311 o i-1: a -move-> c, p -move-> s
311 o i-1: a -move-> c, p -move-> s
312 |
312 |
313 o i-0 initial commit: a b h p q r
313 o i-0 initial commit: a b h p q r
314
314
315
315
316
316
317 merging with the side having a delete
317 merging with the side having a delete
318 -------------------------------------
318 -------------------------------------
319
319
320 case summary:
320 case summary:
321 - one with change to an unrelated file
321 - one with change to an unrelated file
322 - one deleting the change
322 - one deleting the change
323 and recreate an unrelated file after the merge
323 and recreate an unrelated file after the merge
324
324
325 $ case_desc="simple merge - C side: delete a file with copies history , B side: unrelated update"
325 $ case_desc="simple merge - C side: delete a file with copies history , B side: unrelated update"
326
326
327 $ hg up 'desc("b-1")'
327 $ hg up 'desc("b-1")'
328 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
328 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
329 $ hg merge 'desc("c-1")'
329 $ hg merge 'desc("c-1")'
330 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
330 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
331 (branch merge, don't forget to commit)
331 (branch merge, don't forget to commit)
332 $ hg ci -m "mBCm-0 $case_desc - one way"
332 $ hg ci -m "mBCm-0 $case_desc - one way"
333 $ echo bar > d
333 $ echo bar > d
334 $ hg add d
334 $ hg add d
335 $ hg ci -m 'mBCm-1 re-add d'
335 $ hg ci -m 'mBCm-1 re-add d'
336 $ hg up 'desc("c-1")'
336 $ hg up 'desc("c-1")'
337 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
337 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
338 $ hg merge 'desc("b-1")'
338 $ hg merge 'desc("b-1")'
339 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
339 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
340 (branch merge, don't forget to commit)
340 (branch merge, don't forget to commit)
341 $ hg ci -m "mCBm-0 $case_desc - the other way"
341 $ hg ci -m "mCBm-0 $case_desc - the other way"
342 created new head
342 created new head
343 $ echo bar > d
343 $ echo bar > d
344 $ hg add d
344 $ hg add d
345 $ hg ci -m 'mCBm-1 re-add d'
345 $ hg ci -m 'mCBm-1 re-add d'
346 $ hg log -G --rev '::(desc("mCBm")+desc("mBCm"))'
346 $ hg log -G --rev '::(desc("mCBm")+desc("mBCm"))'
347 @ mCBm-1 re-add d
347 @ mCBm-1 re-add d
348 |
348 |
349 o mCBm-0 simple merge - C side: delete a file with copies history , B side: unrelated update - the other way
349 o mCBm-0 simple merge - C side: delete a file with copies history , B side: unrelated update - the other way
350 |\
350 |\
351 | | o mBCm-1 re-add d
351 | | o mBCm-1 re-add d
352 | | |
352 | | |
353 +---o mBCm-0 simple merge - C side: delete a file with copies history , B side: unrelated update - one way
353 +---o mBCm-0 simple merge - C side: delete a file with copies history , B side: unrelated update - one way
354 | |/
354 | |/
355 | o c-1 delete d
355 | o c-1 delete d
356 | |
356 | |
357 o | b-1: b update
357 o | b-1: b update
358 |/
358 |/
359 o i-2: c -move-> d, s -move-> t
359 o i-2: c -move-> d, s -move-> t
360 |
360 |
361 o i-1: a -move-> c, p -move-> s
361 o i-1: a -move-> c, p -move-> s
362 |
362 |
363 o i-0 initial commit: a b h p q r
363 o i-0 initial commit: a b h p q r
364
364
365
365
366 Comparing with a merge re-adding the file afterward
366 Comparing with a merge re-adding the file afterward
367 ---------------------------------------------------
367 ---------------------------------------------------
368
368
369 Merge:
369 Merge:
370 - one with change to an unrelated file
370 - one with change to an unrelated file
371 - one deleting and recreating the change
371 - one deleting and recreating the change
372
372
373 $ case_desc="simple merge - B side: unrelated update, D side: delete and recreate a file (with different content)"
373 $ case_desc="simple merge - B side: unrelated update, D side: delete and recreate a file (with different content)"
374
374
375 $ hg up 'desc("b-1")'
375 $ hg up 'desc("b-1")'
376 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
376 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
377 $ hg merge 'desc("d-2")'
377 $ hg merge 'desc("d-2")'
378 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
378 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
379 (branch merge, don't forget to commit)
379 (branch merge, don't forget to commit)
380 $ hg ci -m "mBDm-0 $case_desc - one way"
380 $ hg ci -m "mBDm-0 $case_desc - one way"
381 $ hg up 'desc("d-2")'
381 $ hg up 'desc("d-2")'
382 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
382 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
383 $ hg merge 'desc("b-1")'
383 $ hg merge 'desc("b-1")'
384 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
384 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
385 (branch merge, don't forget to commit)
385 (branch merge, don't forget to commit)
386 $ hg ci -m "mDBm-0 $case_desc - the other way"
386 $ hg ci -m "mDBm-0 $case_desc - the other way"
387 created new head
387 created new head
388 $ hg log -G --rev '::(desc("mDBm")+desc("mBDm"))'
388 $ hg log -G --rev '::(desc("mDBm")+desc("mBDm"))'
389 @ mDBm-0 simple merge - B side: unrelated update, D side: delete and recreate a file (with different content) - the other way
389 @ mDBm-0 simple merge - B side: unrelated update, D side: delete and recreate a file (with different content) - the other way
390 |\
390 |\
391 +---o mBDm-0 simple merge - B side: unrelated update, D side: delete and recreate a file (with different content) - one way
391 +---o mBDm-0 simple merge - B side: unrelated update, D side: delete and recreate a file (with different content) - one way
392 | |/
392 | |/
393 | o d-2 re-add d
393 | o d-2 re-add d
394 | |
394 | |
395 | o d-1 delete d
395 | o d-1 delete d
396 | |
396 | |
397 o | b-1: b update
397 o | b-1: b update
398 |/
398 |/
399 o i-2: c -move-> d, s -move-> t
399 o i-2: c -move-> d, s -move-> t
400 |
400 |
401 o i-1: a -move-> c, p -move-> s
401 o i-1: a -move-> c, p -move-> s
402 |
402 |
403 o i-0 initial commit: a b h p q r
403 o i-0 initial commit: a b h p q r
404
404
405
405
406
406
407 Comparing with a merge with colliding rename
407 Comparing with a merge with colliding rename
408 --------------------------------------------
408 --------------------------------------------
409
409
410 Subcase: new copy information on both side
410 Subcase: new copy information on both side
411 ``````````````````````````````````````````
411 ``````````````````````````````````````````
412
412
413 - the "e-" branch renaming b to f (through 'g')
413 - the "e-" branch renaming b to f (through 'g')
414 - the "a-" branch renaming d to f (through e)
414 - the "a-" branch renaming d to f (through e)
415
415
416 $ case_desc="merge with copies info on both side - A side: rename d to f, E side: b to f, (same content for f)"
416 $ case_desc="merge with copies info on both side - A side: rename d to f, E side: b to f, (same content for f)"
417
417
418 $ hg up 'desc("a-2")'
418 $ hg up 'desc("a-2")'
419 2 files updated, 0 files merged, 1 files removed, 0 files unresolved
419 2 files updated, 0 files merged, 1 files removed, 0 files unresolved
420 $ hg merge 'desc("e-2")'
420 $ hg merge 'desc("e-2")'
421 1 files updated, 0 files merged, 1 files removed, 0 files unresolved (no-changeset !)
421 1 files updated, 0 files merged, 1 files removed, 0 files unresolved (no-changeset !)
422 0 files updated, 0 files merged, 1 files removed, 0 files unresolved (changeset !)
422 0 files updated, 0 files merged, 1 files removed, 0 files unresolved (changeset !)
423 (branch merge, don't forget to commit)
423 (branch merge, don't forget to commit)
424 $ hg ci -m "mAEm-0 $case_desc - one way"
424 $ hg ci -m "mAEm-0 $case_desc - one way"
425 $ hg up 'desc("e-2")'
425 $ hg up 'desc("e-2")'
426 2 files updated, 0 files merged, 0 files removed, 0 files unresolved (no-changeset !)
426 2 files updated, 0 files merged, 0 files removed, 0 files unresolved (no-changeset !)
427 1 files updated, 0 files merged, 0 files removed, 0 files unresolved (changeset !)
427 1 files updated, 0 files merged, 0 files removed, 0 files unresolved (changeset !)
428 $ hg merge 'desc("a-2")'
428 $ hg merge 'desc("a-2")'
429 1 files updated, 0 files merged, 1 files removed, 0 files unresolved (no-changeset !)
429 1 files updated, 0 files merged, 1 files removed, 0 files unresolved (no-changeset !)
430 0 files updated, 0 files merged, 1 files removed, 0 files unresolved (changeset !)
430 0 files updated, 0 files merged, 1 files removed, 0 files unresolved (changeset !)
431 (branch merge, don't forget to commit)
431 (branch merge, don't forget to commit)
432 $ hg ci -m "mEAm-0 $case_desc - the other way"
432 $ hg ci -m "mEAm-0 $case_desc - the other way"
433 created new head
433 created new head
434 $ hg log -G --rev '::(desc("mAEm")+desc("mEAm"))'
434 $ hg log -G --rev '::(desc("mAEm")+desc("mEAm"))'
435 @ mEAm-0 merge with copies info on both side - A side: rename d to f, E side: b to f, (same content for f) - the other way
435 @ mEAm-0 merge with copies info on both side - A side: rename d to f, E side: b to f, (same content for f) - the other way
436 |\
436 |\
437 +---o mAEm-0 merge with copies info on both side - A side: rename d to f, E side: b to f, (same content for f) - one way
437 +---o mAEm-0 merge with copies info on both side - A side: rename d to f, E side: b to f, (same content for f) - one way
438 | |/
438 | |/
439 | o e-2 g -move-> f
439 | o e-2 g -move-> f
440 | |
440 | |
441 | o e-1 b -move-> g
441 | o e-1 b -move-> g
442 | |
442 | |
443 o | a-2: e -move-> f
443 o | a-2: e -move-> f
444 | |
444 | |
445 o | a-1: d -move-> e
445 o | a-1: d -move-> e
446 |/
446 |/
447 o i-2: c -move-> d, s -move-> t
447 o i-2: c -move-> d, s -move-> t
448 |
448 |
449 o i-1: a -move-> c, p -move-> s
449 o i-1: a -move-> c, p -move-> s
450 |
450 |
451 o i-0 initial commit: a b h p q r
451 o i-0 initial commit: a b h p q r
452
452
453
453
454 Subcase: new copy information on both side with an actual merge happening
454 Subcase: new copy information on both side with an actual merge happening
455 `````````````````````````````````````````````````````````````````````````
455 `````````````````````````````````````````````````````````````````````````
456
456
457 - the "p-" branch renaming 't' to 'v' (through 'u')
457 - the "p-" branch renaming 't' to 'v' (through 'u')
458 - the "q-" branch renaming 'r' to 'v' (through 'w')
458 - the "q-" branch renaming 'r' to 'v' (through 'w')
459
459
460 $ case_desc="merge with copies info on both side - P side: rename t to v, Q side: r to v, (different content)"
460 $ case_desc="merge with copies info on both side - P side: rename t to v, Q side: r to v, (different content)"
461
461
462 $ hg up 'desc("p-2")'
462 $ hg up 'desc("p-2")'
463 3 files updated, 0 files merged, 2 files removed, 0 files unresolved
463 3 files updated, 0 files merged, 2 files removed, 0 files unresolved
464 $ hg merge 'desc("q-2")' --tool ':union'
464 $ hg merge 'desc("q-2")' --tool ':union'
465 merging v
465 merging v
466 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
466 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
467 (branch merge, don't forget to commit)
467 (branch merge, don't forget to commit)
468 $ hg ci -m "mPQm-0 $case_desc - one way"
468 $ hg ci -m "mPQm-0 $case_desc - one way"
469 $ hg up 'desc("q-2")'
469 $ hg up 'desc("q-2")'
470 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
470 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
471 $ hg merge 'desc("p-2")' --tool ':union'
471 $ hg merge 'desc("p-2")' --tool ':union'
472 merging v
472 merging v
473 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
473 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
474 (branch merge, don't forget to commit)
474 (branch merge, don't forget to commit)
475 $ hg ci -m "mQPm-0 $case_desc - the other way"
475 $ hg ci -m "mQPm-0 $case_desc - the other way"
476 created new head
476 created new head
477 $ hg log -G --rev '::(desc("mAEm")+desc("mEAm"))'
477 $ hg log -G --rev '::(desc("mAEm")+desc("mEAm"))'
478 o mEAm-0 merge with copies info on both side - A side: rename d to f, E side: b to f, (same content for f) - the other way
478 o mEAm-0 merge with copies info on both side - A side: rename d to f, E side: b to f, (same content for f) - the other way
479 |\
479 |\
480 +---o mAEm-0 merge with copies info on both side - A side: rename d to f, E side: b to f, (same content for f) - one way
480 +---o mAEm-0 merge with copies info on both side - A side: rename d to f, E side: b to f, (same content for f) - one way
481 | |/
481 | |/
482 | o e-2 g -move-> f
482 | o e-2 g -move-> f
483 | |
483 | |
484 | o e-1 b -move-> g
484 | o e-1 b -move-> g
485 | |
485 | |
486 o | a-2: e -move-> f
486 o | a-2: e -move-> f
487 | |
487 | |
488 o | a-1: d -move-> e
488 o | a-1: d -move-> e
489 |/
489 |/
490 o i-2: c -move-> d, s -move-> t
490 o i-2: c -move-> d, s -move-> t
491 |
491 |
492 o i-1: a -move-> c, p -move-> s
492 o i-1: a -move-> c, p -move-> s
493 |
493 |
494 o i-0 initial commit: a b h p q r
494 o i-0 initial commit: a b h p q r
495
495
496
496
497 Subcase: existing copy information overwritten on one branch
497 Subcase: existing copy information overwritten on one branch
498 ````````````````````````````````````````````````````````````
498 ````````````````````````````````````````````````````````````
499
499
500 Merge:
500 Merge:
501 - one with change to an unrelated file (b)
501 - one with change to an unrelated file (b)
502 - one overwriting a file (d) with a rename (from h to i to d)
502 - one overwriting a file (d) with a rename (from h to i to d)
503
503
504 $ case_desc="simple merge - B side: unrelated change, F side: overwrite d with a copy (from h->i->d)"
504 $ case_desc="simple merge - B side: unrelated change, F side: overwrite d with a copy (from h->i->d)"
505
505
506 $ hg up 'desc("i-2")'
506 $ hg up 'desc("i-2")'
507 2 files updated, 0 files merged, 1 files removed, 0 files unresolved
507 2 files updated, 0 files merged, 1 files removed, 0 files unresolved
508 $ hg mv h i
508 $ hg mv h i
509 $ hg commit -m "f-1: rename h -> i"
509 $ hg commit -m "f-1: rename h -> i"
510 created new head
510 created new head
511 $ hg mv --force i d
511 $ hg mv --force i d
512 $ hg commit -m "f-2: rename i -> d"
512 $ hg commit -m "f-2: rename i -> d"
513 $ hg debugindex d | "$PYTHON" ../no-linkrev
513 $ hg debugindex d | "$PYTHON" ../no-linkrev
514 rev linkrev nodeid p1 p2
514 rev linkrev nodeid p1 p2
515 0 * d8252ab2e760 000000000000 000000000000 (no-changeset !)
515 0 * d8252ab2e760 000000000000 000000000000 (no-changeset !)
516 0 * ae258f702dfe 000000000000 000000000000 (changeset !)
516 0 * ae258f702dfe 000000000000 000000000000 (changeset !)
517 1 * b004912a8510 000000000000 000000000000
517 1 * b004912a8510 000000000000 000000000000
518 2 * 7b79e2fe0c89 000000000000 000000000000 (no-changeset !)
518 2 * 7b79e2fe0c89 000000000000 000000000000 (no-changeset !)
519 $ hg up 'desc("b-1")'
519 $ hg up 'desc("b-1")'
520 3 files updated, 0 files merged, 0 files removed, 0 files unresolved (no-changeset !)
520 3 files updated, 0 files merged, 0 files removed, 0 files unresolved (no-changeset !)
521 2 files updated, 0 files merged, 0 files removed, 0 files unresolved (changeset !)
521 2 files updated, 0 files merged, 0 files removed, 0 files unresolved (changeset !)
522 $ hg merge 'desc("f-2")'
522 $ hg merge 'desc("f-2")'
523 1 files updated, 0 files merged, 1 files removed, 0 files unresolved (no-changeset !)
523 1 files updated, 0 files merged, 1 files removed, 0 files unresolved (no-changeset !)
524 0 files updated, 0 files merged, 1 files removed, 0 files unresolved (changeset !)
524 0 files updated, 0 files merged, 1 files removed, 0 files unresolved (changeset !)
525 (branch merge, don't forget to commit)
525 (branch merge, don't forget to commit)
526 $ hg ci -m "mBFm-0 $case_desc - one way"
526 $ hg ci -m "mBFm-0 $case_desc - one way"
527 $ hg up 'desc("f-2")'
527 $ hg up 'desc("f-2")'
528 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
528 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
529 $ hg merge 'desc("b-1")'
529 $ hg merge 'desc("b-1")'
530 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
530 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
531 (branch merge, don't forget to commit)
531 (branch merge, don't forget to commit)
532 $ hg ci -m "mFBm-0 $case_desc - the other way"
532 $ hg ci -m "mFBm-0 $case_desc - the other way"
533 created new head
533 created new head
534 $ hg up null --quiet
534 $ hg up null --quiet
535 $ hg log -G --rev '::(desc("mBFm")+desc("mFBm"))'
535 $ hg log -G --rev '::(desc("mBFm")+desc("mFBm"))'
536 o mFBm-0 simple merge - B side: unrelated change, F side: overwrite d with a copy (from h->i->d) - the other way
536 o mFBm-0 simple merge - B side: unrelated change, F side: overwrite d with a copy (from h->i->d) - the other way
537 |\
537 |\
538 +---o mBFm-0 simple merge - B side: unrelated change, F side: overwrite d with a copy (from h->i->d) - one way
538 +---o mBFm-0 simple merge - B side: unrelated change, F side: overwrite d with a copy (from h->i->d) - one way
539 | |/
539 | |/
540 | o f-2: rename i -> d
540 | o f-2: rename i -> d
541 | |
541 | |
542 | o f-1: rename h -> i
542 | o f-1: rename h -> i
543 | |
543 | |
544 o | b-1: b update
544 o | b-1: b update
545 |/
545 |/
546 o i-2: c -move-> d, s -move-> t
546 o i-2: c -move-> d, s -move-> t
547 |
547 |
548 o i-1: a -move-> c, p -move-> s
548 o i-1: a -move-> c, p -move-> s
549 |
549 |
550 o i-0 initial commit: a b h p q r
550 o i-0 initial commit: a b h p q r
551
551
552
552
553 Subcase: existing copy information overwritten on one branch, with different content)
553 Subcase: existing copy information overwritten on one branch, with different content)
554 `````````````````````````````````````````````````````````````````````````````````````
554 `````````````````````````````````````````````````````````````````````````````````````
555
555
556 Merge:
556 Merge:
557 - one with change to an unrelated file (b)
557 - one with change to an unrelated file (b)
558 - one overwriting a file (t) with a rename (from r to x to t), v content is not the same as on the other branch
558 - one overwriting a file (t) with a rename (from r to x to t), v content is not the same as on the other branch
559
559
560 $ case_desc="simple merge - B side: unrelated change, R side: overwrite d with a copy (from r->x->t) different content"
560 $ case_desc="simple merge - B side: unrelated change, R side: overwrite d with a copy (from r->x->t) different content"
561
561
562 $ hg up 'desc("i-2")'
562 $ hg up 'desc("i-2")'
563 6 files updated, 0 files merged, 0 files removed, 0 files unresolved
563 6 files updated, 0 files merged, 0 files removed, 0 files unresolved
564 $ hg mv r x
564 $ hg mv r x
565 $ hg commit -m "r-1: rename r -> x"
565 $ hg commit -m "r-1: rename r -> x"
566 created new head
566 created new head
567 $ hg mv --force x t
567 $ hg mv --force x t
568 $ hg commit -m "r-2: rename t -> x"
568 $ hg commit -m "r-2: rename t -> x"
569 $ hg debugindex t | "$PYTHON" ../no-linkrev
569 $ hg debugindex t | "$PYTHON" ../no-linkrev
570 rev linkrev nodeid p1 p2
570 rev linkrev nodeid p1 p2
571 0 * d74efbf65309 000000000000 000000000000 (no-changeset !)
571 0 * d74efbf65309 000000000000 000000000000 (no-changeset !)
572 1 * 02a930b9d7ad 000000000000 000000000000 (no-changeset !)
572 1 * 02a930b9d7ad 000000000000 000000000000 (no-changeset !)
573 0 * 5aed6a8dbff0 000000000000 000000000000 (changeset !)
573 0 * 5aed6a8dbff0 000000000000 000000000000 (changeset !)
574 1 * a38b2fa17021 000000000000 000000000000 (changeset !)
574 1 * a38b2fa17021 000000000000 000000000000 (changeset !)
575 $ hg up 'desc("b-1")'
575 $ hg up 'desc("b-1")'
576 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
576 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
577 $ hg merge 'desc("r-2")'
577 $ hg merge 'desc("r-2")'
578 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
578 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
579 (branch merge, don't forget to commit)
579 (branch merge, don't forget to commit)
580 $ hg ci -m "mBRm-0 $case_desc - one way"
580 $ hg ci -m "mBRm-0 $case_desc - one way"
581 $ hg up 'desc("r-2")'
581 $ hg up 'desc("r-2")'
582 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
582 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
583 $ hg merge 'desc("b-1")'
583 $ hg merge 'desc("b-1")'
584 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
584 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
585 (branch merge, don't forget to commit)
585 (branch merge, don't forget to commit)
586 $ hg ci -m "mRBm-0 $case_desc - the other way"
586 $ hg ci -m "mRBm-0 $case_desc - the other way"
587 created new head
587 created new head
588 $ hg up null --quiet
588 $ hg up null --quiet
589 $ hg log -G --rev '::(desc("mBRm")+desc("mRBm"))'
589 $ hg log -G --rev '::(desc("mBRm")+desc("mRBm"))'
590 o mRBm-0 simple merge - B side: unrelated change, R side: overwrite d with a copy (from r->x->t) different content - the other way
590 o mRBm-0 simple merge - B side: unrelated change, R side: overwrite d with a copy (from r->x->t) different content - the other way
591 |\
591 |\
592 +---o mBRm-0 simple merge - B side: unrelated change, R side: overwrite d with a copy (from r->x->t) different content - one way
592 +---o mBRm-0 simple merge - B side: unrelated change, R side: overwrite d with a copy (from r->x->t) different content - one way
593 | |/
593 | |/
594 | o r-2: rename t -> x
594 | o r-2: rename t -> x
595 | |
595 | |
596 | o r-1: rename r -> x
596 | o r-1: rename r -> x
597 | |
597 | |
598 o | b-1: b update
598 o | b-1: b update
599 |/
599 |/
600 o i-2: c -move-> d, s -move-> t
600 o i-2: c -move-> d, s -move-> t
601 |
601 |
602 o i-1: a -move-> c, p -move-> s
602 o i-1: a -move-> c, p -move-> s
603 |
603 |
604 o i-0 initial commit: a b h p q r
604 o i-0 initial commit: a b h p q r
605
605
606
606
607
607
608 Subcase: reset of the copy history on one side
608 Subcase: reset of the copy history on one side
609 ``````````````````````````````````````````````
609 ``````````````````````````````````````````````
610
610
611 Merge:
611 Merge:
612 - one with change to a file
612 - one with change to a file
613 - one deleting and recreating the file
613 - one deleting and recreating the file
614
614
615 Unlike in the 'BD/DB' cases, an actual merge happened here. So we should
615 Unlike in the 'BD/DB' cases, an actual merge happened here. So we should
616 consider history and rename on both branch of the merge.
616 consider history and rename on both branch of the merge.
617
617
618 $ case_desc="actual content merge, copies on one side - D side: delete and re-add (different content), G side: update content"
618 $ case_desc="actual content merge, copies on one side - D side: delete and re-add (different content), G side: update content"
619
619
620 $ hg up 'desc("i-2")'
620 $ hg up 'desc("i-2")'
621 6 files updated, 0 files merged, 0 files removed, 0 files unresolved
621 6 files updated, 0 files merged, 0 files removed, 0 files unresolved
622 $ echo "some update" >> d
622 $ echo "some update" >> d
623 $ hg commit -m "g-1: update d"
623 $ hg commit -m "g-1: update d"
624 created new head
624 created new head
625 $ hg up 'desc("d-2")'
625 $ hg up 'desc("d-2")'
626 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
626 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
627 $ hg merge 'desc("g-1")' --tool :union
627 $ hg merge 'desc("g-1")' --tool :union
628 merging d
628 merging d
629 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
629 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
630 (branch merge, don't forget to commit)
630 (branch merge, don't forget to commit)
631 $ hg ci -m "mDGm-0 $case_desc - one way"
631 $ hg ci -m "mDGm-0 $case_desc - one way"
632 $ hg up 'desc("g-1")'
632 $ hg up 'desc("g-1")'
633 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
633 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
634 $ hg merge 'desc("d-2")' --tool :union
634 $ hg merge 'desc("d-2")' --tool :union
635 merging d
635 merging d
636 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
636 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
637 (branch merge, don't forget to commit)
637 (branch merge, don't forget to commit)
638 $ hg ci -m "mGDm-0 $case_desc - the other way"
638 $ hg ci -m "mGDm-0 $case_desc - the other way"
639 created new head
639 created new head
640 $ hg log -G --rev '::(desc("mDGm")+desc("mGDm"))'
640 $ hg log -G --rev '::(desc("mDGm")+desc("mGDm"))'
641 @ mGDm-0 actual content merge, copies on one side - D side: delete and re-add (different content), G side: update content - the other way
641 @ mGDm-0 actual content merge, copies on one side - D side: delete and re-add (different content), G side: update content - the other way
642 |\
642 |\
643 +---o mDGm-0 actual content merge, copies on one side - D side: delete and re-add (different content), G side: update content - one way
643 +---o mDGm-0 actual content merge, copies on one side - D side: delete and re-add (different content), G side: update content - one way
644 | |/
644 | |/
645 | o g-1: update d
645 | o g-1: update d
646 | |
646 | |
647 o | d-2 re-add d
647 o | d-2 re-add d
648 | |
648 | |
649 o | d-1 delete d
649 o | d-1 delete d
650 |/
650 |/
651 o i-2: c -move-> d, s -move-> t
651 o i-2: c -move-> d, s -move-> t
652 |
652 |
653 o i-1: a -move-> c, p -move-> s
653 o i-1: a -move-> c, p -move-> s
654 |
654 |
655 o i-0 initial commit: a b h p q r
655 o i-0 initial commit: a b h p q r
656
656
657
657
658 Subcase: merging a change to a file with a "copy overwrite" to that file from another branch
658 Subcase: merging a change to a file with a "copy overwrite" to that file from another branch
659 ````````````````````````````````````````````````````````````````````````````````````````````
659 ````````````````````````````````````````````````````````````````````````````````````````````
660
660
661 Merge:
661 Merge:
662 - one with change to a file (d)
662 - one with change to a file (d)
663 - one overwriting that file with a rename (from h to i, to d)
663 - one overwriting that file with a rename (from h to i, to d)
664
664
665 This case is similar to BF/FB, but an actual merge happens, so both side of the
665 This case is similar to BF/FB, but an actual merge happens, so both side of the
666 history are relevant.
666 history are relevant.
667
667
668 Note:
668 Note:
669 | In this case, the merge get conflicting information since on one side we have
669 | In this case, the merge get conflicting information since on one side we have
670 | "a -> c -> d". and one the other one we have "h -> i -> d".
670 | "a -> c -> d". and one the other one we have "h -> i -> d".
671 |
671 |
672 | The current code arbitrarily pick one side
672 | The current code arbitrarily pick one side
673
673
674 $ case_desc="merge - G side: content change, F side: copy overwrite, no content change"
674 $ case_desc="merge - G side: content change, F side: copy overwrite, no content change"
675
675
676 $ hg up 'desc("f-2")'
676 $ hg up 'desc("f-2")'
677 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
677 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
678 $ hg merge 'desc("g-1")' --tool :union
678 $ hg merge 'desc("g-1")' --tool :union
679 merging d (no-changeset !)
679 merging d (no-changeset !)
680 0 files updated, 1 files merged, 0 files removed, 0 files unresolved (no-changeset !)
680 0 files updated, 1 files merged, 0 files removed, 0 files unresolved (no-changeset !)
681 1 files updated, 0 files merged, 0 files removed, 0 files unresolved (changeset !)
681 1 files updated, 0 files merged, 0 files removed, 0 files unresolved (changeset !)
682 (branch merge, don't forget to commit)
682 (branch merge, don't forget to commit)
683 $ hg ci -m "mFGm-0 $case_desc - one way"
683 $ hg ci -m "mFGm-0 $case_desc - one way"
684 created new head
684 created new head
685 $ hg up 'desc("g-1")'
685 $ hg up 'desc("g-1")'
686 2 files updated, 0 files merged, 0 files removed, 0 files unresolved (no-changeset !)
686 2 files updated, 0 files merged, 0 files removed, 0 files unresolved (no-changeset !)
687 1 files updated, 0 files merged, 0 files removed, 0 files unresolved (changeset !)
687 1 files updated, 0 files merged, 0 files removed, 0 files unresolved (changeset !)
688 $ hg merge 'desc("f-2")' --tool :union
688 $ hg merge 'desc("f-2")' --tool :union
689 merging d (no-changeset !)
689 merging d (no-changeset !)
690 0 files updated, 1 files merged, 1 files removed, 0 files unresolved (no-changeset !)
690 0 files updated, 1 files merged, 1 files removed, 0 files unresolved (no-changeset !)
691 0 files updated, 0 files merged, 1 files removed, 0 files unresolved (changeset !)
691 0 files updated, 0 files merged, 1 files removed, 0 files unresolved (changeset !)
692 (branch merge, don't forget to commit)
692 (branch merge, don't forget to commit)
693 $ hg ci -m "mGFm-0 $case_desc - the other way"
693 $ hg ci -m "mGFm-0 $case_desc - the other way"
694 created new head
694 created new head
695 $ hg log -G --rev '::(desc("mGFm")+desc("mFGm"))'
695 $ hg log -G --rev '::(desc("mGFm")+desc("mFGm"))'
696 @ mGFm-0 merge - G side: content change, F side: copy overwrite, no content change - the other way
696 @ mGFm-0 merge - G side: content change, F side: copy overwrite, no content change - the other way
697 |\
697 |\
698 +---o mFGm-0 merge - G side: content change, F side: copy overwrite, no content change - one way
698 +---o mFGm-0 merge - G side: content change, F side: copy overwrite, no content change - one way
699 | |/
699 | |/
700 | o g-1: update d
700 | o g-1: update d
701 | |
701 | |
702 o | f-2: rename i -> d
702 o | f-2: rename i -> d
703 | |
703 | |
704 o | f-1: rename h -> i
704 o | f-1: rename h -> i
705 |/
705 |/
706 o i-2: c -move-> d, s -move-> t
706 o i-2: c -move-> d, s -move-> t
707 |
707 |
708 o i-1: a -move-> c, p -move-> s
708 o i-1: a -move-> c, p -move-> s
709 |
709 |
710 o i-0 initial commit: a b h p q r
710 o i-0 initial commit: a b h p q r
711
711
712
712
713
713
714 Comparing with merging with a deletion (and keeping the file)
714 Comparing with merging with a deletion (and keeping the file)
715 -------------------------------------------------------------
715 -------------------------------------------------------------
716
716
717 Merge:
717 Merge:
718 - one removing a file (d)
718 - one removing a file (d)
719 - one updating that file
719 - one updating that file
720 - the merge keep the modified version of the file (canceling the delete)
720 - the merge keep the modified version of the file (canceling the delete)
721
721
722 In this case, the file keep on living after the merge. So we should not drop its
722 In this case, the file keep on living after the merge. So we should not drop its
723 copy tracing chain.
723 copy tracing chain.
724
724
725 $ case_desc="merge updated/deleted - revive the file (updated content)"
725 $ case_desc="merge updated/deleted - revive the file (updated content)"
726
726
727 $ hg up 'desc("c-1")'
727 $ hg up 'desc("c-1")'
728 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
728 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
729 $ hg merge 'desc("g-1")'
729 $ hg merge 'desc("g-1")'
730 file 'd' was deleted in local [working copy] but was modified in other [merge rev].
730 file 'd' was deleted in local [working copy] but was modified in other [merge rev].
731 You can use (c)hanged version, leave (d)eleted, or leave (u)nresolved.
731 You can use (c)hanged version, leave (d)eleted, or leave (u)nresolved.
732 What do you want to do? u
732 What do you want to do? u
733 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
733 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
734 use 'hg resolve' to retry unresolved file merges or 'hg merge --abort' to abandon
734 use 'hg resolve' to retry unresolved file merges or 'hg merge --abort' to abandon
735 [1]
735 [1]
736 $ hg resolve -t :other d
736 $ hg resolve -t :other d
737 (no more unresolved files)
737 (no more unresolved files)
738 $ hg ci -m "mCGm-0 $case_desc - one way"
738 $ hg ci -m "mCGm-0 $case_desc - one way"
739 created new head
739 created new head
740
740
741 $ hg up 'desc("g-1")'
741 $ hg up 'desc("g-1")'
742 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
742 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
743 $ hg merge 'desc("c-1")'
743 $ hg merge 'desc("c-1")'
744 file 'd' was deleted in other [merge rev] but was modified in local [working copy].
744 file 'd' was deleted in other [merge rev] but was modified in local [working copy].
745 You can use (c)hanged version, (d)elete, or leave (u)nresolved.
745 You can use (c)hanged version, (d)elete, or leave (u)nresolved.
746 What do you want to do? u
746 What do you want to do? u
747 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
747 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
748 use 'hg resolve' to retry unresolved file merges or 'hg merge --abort' to abandon
748 use 'hg resolve' to retry unresolved file merges or 'hg merge --abort' to abandon
749 [1]
749 [1]
750 $ hg resolve -t :local d
750 $ hg resolve -t :local d
751 (no more unresolved files)
751 (no more unresolved files)
752 $ hg ci -m "mGCm-0 $case_desc - the other way"
752 $ hg ci -m "mGCm-0 $case_desc - the other way"
753 created new head
753 created new head
754
754
755 $ hg log -G --rev '::(desc("mCGm")+desc("mGCm"))'
755 $ hg log -G --rev '::(desc("mCGm")+desc("mGCm"))'
756 @ mGCm-0 merge updated/deleted - revive the file (updated content) - the other way
756 @ mGCm-0 merge updated/deleted - revive the file (updated content) - the other way
757 |\
757 |\
758 +---o mCGm-0 merge updated/deleted - revive the file (updated content) - one way
758 +---o mCGm-0 merge updated/deleted - revive the file (updated content) - one way
759 | |/
759 | |/
760 | o g-1: update d
760 | o g-1: update d
761 | |
761 | |
762 o | c-1 delete d
762 o | c-1 delete d
763 |/
763 |/
764 o i-2: c -move-> d, s -move-> t
764 o i-2: c -move-> d, s -move-> t
765 |
765 |
766 o i-1: a -move-> c, p -move-> s
766 o i-1: a -move-> c, p -move-> s
767 |
767 |
768 o i-0 initial commit: a b h p q r
768 o i-0 initial commit: a b h p q r
769
769
770
770
771
771
772
772
773 Comparing with merge restoring an untouched deleted file
773 Comparing with merge restoring an untouched deleted file
774 --------------------------------------------------------
774 --------------------------------------------------------
775
775
776 Merge:
776 Merge:
777 - one removing a file (d)
777 - one removing a file (d)
778 - one leaving the file untouched
778 - one leaving the file untouched
779 - the merge actively restore the file to the same content.
779 - the merge actively restore the file to the same content.
780
780
781 In this case, the file keep on living after the merge. So we should not drop its
781 In this case, the file keep on living after the merge. So we should not drop its
782 copy tracing chain.
782 copy tracing chain.
783
783
784 $ case_desc="merge explicitely revive deleted file - B side: unrelated change, C side: delete d (restored by merge)"
784 $ case_desc="merge explicitely revive deleted file - B side: unrelated change, C side: delete d (restored by merge)"
785
785
786 $ hg up 'desc("c-1")'
786 $ hg up 'desc("c-1")'
787 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
787 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
788 $ hg merge 'desc("b-1")'
788 $ hg merge 'desc("b-1")'
789 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
789 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
790 (branch merge, don't forget to commit)
790 (branch merge, don't forget to commit)
791 $ hg revert --rev 'desc("b-1")' d
791 $ hg revert --rev 'desc("b-1")' d
792 $ hg ci -m "mCB-revert-m-0 $case_desc - one way"
792 $ hg ci -m "mCB-revert-m-0 $case_desc - one way"
793 created new head
793 created new head
794
794
795 $ hg up 'desc("b-1")'
795 $ hg up 'desc("b-1")'
796 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
796 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
797 $ hg merge 'desc("c-1")'
797 $ hg merge 'desc("c-1")'
798 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
798 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
799 (branch merge, don't forget to commit)
799 (branch merge, don't forget to commit)
800 $ hg revert --rev 'desc("b-1")' d
800 $ hg revert --rev 'desc("b-1")' d
801 $ hg ci -m "mBC-revert-m-0 $case_desc - the other way"
801 $ hg ci -m "mBC-revert-m-0 $case_desc - the other way"
802 created new head
802 created new head
803
803
804 $ hg log -G --rev '::(desc("mCB-revert-m")+desc("mBC-revert-m"))'
804 $ hg log -G --rev '::(desc("mCB-revert-m")+desc("mBC-revert-m"))'
805 @ mBC-revert-m-0 merge explicitely revive deleted file - B side: unrelated change, C side: delete d (restored by merge) - the other way
805 @ mBC-revert-m-0 merge explicitely revive deleted file - B side: unrelated change, C side: delete d (restored by merge) - the other way
806 |\
806 |\
807 +---o mCB-revert-m-0 merge explicitely revive deleted file - B side: unrelated change, C side: delete d (restored by merge) - one way
807 +---o mCB-revert-m-0 merge explicitely revive deleted file - B side: unrelated change, C side: delete d (restored by merge) - one way
808 | |/
808 | |/
809 | o c-1 delete d
809 | o c-1 delete d
810 | |
810 | |
811 o | b-1: b update
811 o | b-1: b update
812 |/
812 |/
813 o i-2: c -move-> d, s -move-> t
813 o i-2: c -move-> d, s -move-> t
814 |
814 |
815 o i-1: a -move-> c, p -move-> s
815 o i-1: a -move-> c, p -move-> s
816 |
816 |
817 o i-0 initial commit: a b h p q r
817 o i-0 initial commit: a b h p q r
818
818
819
819
820
820
821 $ hg up null --quiet
821 $ hg up null --quiet
822
822
823 Merging a branch where a rename was deleted with a branch where the same file was renamed
823 Merging a branch where a rename was deleted with a branch where the same file was renamed
824 ------------------------------------------------------------------------------------------
824 ------------------------------------------------------------------------------------------
825
825
826 Create a "conflicting" merge where `d` get removed on one branch before its
826 Create a "conflicting" merge where `d` get removed on one branch before its
827 rename information actually conflict with the other branch.
827 rename information actually conflict with the other branch.
828
828
829 (the copy information from the branch that was not deleted should win).
829 (the copy information from the branch that was not deleted should win).
830
830
831 $ case_desc="simple merge - C side: d is the results of renames then deleted, H side: d is result of another rename (same content as the other branch)"
831 $ case_desc="simple merge - C side: d is the results of renames then deleted, H side: d is result of another rename (same content as the other branch)"
832
832
833 $ hg up 'desc("i-0")'
833 $ hg up 'desc("i-0")'
834 6 files updated, 0 files merged, 0 files removed, 0 files unresolved
834 6 files updated, 0 files merged, 0 files removed, 0 files unresolved
835 $ hg mv b d
835 $ hg mv b d
836 $ hg ci -m "h-1: b -(move)-> d"
836 $ hg ci -m "h-1: b -(move)-> d"
837 created new head
837 created new head
838
838
839 $ hg up 'desc("c-1")'
839 $ hg up 'desc("c-1")'
840 2 files updated, 0 files merged, 3 files removed, 0 files unresolved
840 2 files updated, 0 files merged, 3 files removed, 0 files unresolved
841 $ hg merge 'desc("h-1")'
841 $ hg merge 'desc("h-1")'
842 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
842 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
843 (branch merge, don't forget to commit)
843 (branch merge, don't forget to commit)
844 $ hg ci -m "mCH-delete-before-conflict-m-0 $case_desc - one way"
844 $ hg ci -m "mCH-delete-before-conflict-m-0 $case_desc - one way"
845
845
846 $ hg up 'desc("h-1")'
846 $ hg up 'desc("h-1")'
847 2 files updated, 0 files merged, 1 files removed, 0 files unresolved
847 2 files updated, 0 files merged, 1 files removed, 0 files unresolved
848 $ hg merge 'desc("c-1")'
848 $ hg merge 'desc("c-1")'
849 1 files updated, 0 files merged, 2 files removed, 0 files unresolved
849 1 files updated, 0 files merged, 2 files removed, 0 files unresolved
850 (branch merge, don't forget to commit)
850 (branch merge, don't forget to commit)
851 $ hg ci -m "mHC-delete-before-conflict-m-0 $case_desc - the other way"
851 $ hg ci -m "mHC-delete-before-conflict-m-0 $case_desc - the other way"
852 created new head
852 created new head
853 $ hg log -G --rev '::(desc("mCH-delete-before-conflict-m")+desc("mHC-delete-before-conflict-m"))'
853 $ hg log -G --rev '::(desc("mCH-delete-before-conflict-m")+desc("mHC-delete-before-conflict-m"))'
854 @ mHC-delete-before-conflict-m-0 simple merge - C side: d is the results of renames then deleted, H side: d is result of another rename (same content as the other branch) - the other way
854 @ mHC-delete-before-conflict-m-0 simple merge - C side: d is the results of renames then deleted, H side: d is result of another rename (same content as the other branch) - the other way
855 |\
855 |\
856 +---o mCH-delete-before-conflict-m-0 simple merge - C side: d is the results of renames then deleted, H side: d is result of another rename (same content as the other branch) - one way
856 +---o mCH-delete-before-conflict-m-0 simple merge - C side: d is the results of renames then deleted, H side: d is result of another rename (same content as the other branch) - one way
857 | |/
857 | |/
858 | o h-1: b -(move)-> d
858 | o h-1: b -(move)-> d
859 | |
859 | |
860 o | c-1 delete d
860 o | c-1 delete d
861 | |
861 | |
862 o | i-2: c -move-> d, s -move-> t
862 o | i-2: c -move-> d, s -move-> t
863 | |
863 | |
864 o | i-1: a -move-> c, p -move-> s
864 o | i-1: a -move-> c, p -move-> s
865 |/
865 |/
866 o i-0 initial commit: a b h p q r
866 o i-0 initial commit: a b h p q r
867
867
868
868
869 Variant of previous with extra changes introduced by the merge
869 Variant of previous with extra changes introduced by the merge
870 --------------------------------------------------------------
870 --------------------------------------------------------------
871
871
872 Multiple cases above explicitely test cases where content are the same on both side during merge. In this section we will introduce variants for theses cases where new change are introduced to these file content during the merges.
872 Multiple cases above explicitely test cases where content are the same on both side during merge. In this section we will introduce variants for theses cases where new change are introduced to these file content during the merges.
873
873
874
874
875 Subcase: merge has same initial content on both side, but merge introduced a change
875 Subcase: merge has same initial content on both side, but merge introduced a change
876 ```````````````````````````````````````````````````````````````````````````````````
876 ```````````````````````````````````````````````````````````````````````````````````
877
877
878 Same as `mAEm` and `mEAm` but with extra change to the file before commiting
878 Same as `mAEm` and `mEAm` but with extra change to the file before commiting
879
879
880 - the "e-" branch renaming b to f (through 'g')
880 - the "e-" branch renaming b to f (through 'g')
881 - the "a-" branch renaming d to f (through e)
881 - the "a-" branch renaming d to f (through e)
882
882
883 $ case_desc="merge with file update and copies info on both side - A side: rename d to f, E side: b to f, (same content for f in parent)"
883 $ case_desc="merge with file update and copies info on both side - A side: rename d to f, E side: b to f, (same content for f in parent)"
884
884
885 $ hg up 'desc("a-2")'
885 $ hg up 'desc("a-2")'
886 2 files updated, 0 files merged, 1 files removed, 0 files unresolved
886 2 files updated, 0 files merged, 1 files removed, 0 files unresolved
887 $ hg merge 'desc("e-2")'
887 $ hg merge 'desc("e-2")'
888 1 files updated, 0 files merged, 1 files removed, 0 files unresolved (no-changeset !)
888 1 files updated, 0 files merged, 1 files removed, 0 files unresolved (no-changeset !)
889 0 files updated, 0 files merged, 1 files removed, 0 files unresolved (changeset !)
889 0 files updated, 0 files merged, 1 files removed, 0 files unresolved (changeset !)
890 (branch merge, don't forget to commit)
890 (branch merge, don't forget to commit)
891 $ echo "content change for mAE-change-m" > f
891 $ echo "content change for mAE-change-m" > f
892 $ hg ci -m "mAE-change-m-0 $case_desc - one way"
892 $ hg ci -m "mAE-change-m-0 $case_desc - one way"
893 created new head
893 created new head
894 $ hg up 'desc("e-2")'
894 $ hg up 'desc("e-2")'
895 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
895 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
896 $ hg merge 'desc("a-2")'
896 $ hg merge 'desc("a-2")'
897 1 files updated, 0 files merged, 1 files removed, 0 files unresolved (no-changeset !)
897 1 files updated, 0 files merged, 1 files removed, 0 files unresolved (no-changeset !)
898 0 files updated, 0 files merged, 1 files removed, 0 files unresolved (changeset !)
898 0 files updated, 0 files merged, 1 files removed, 0 files unresolved (changeset !)
899 (branch merge, don't forget to commit)
899 (branch merge, don't forget to commit)
900 $ echo "content change for mEA-change-m" > f
900 $ echo "content change for mEA-change-m" > f
901 $ hg ci -m "mEA-change-m-0 $case_desc - the other way"
901 $ hg ci -m "mEA-change-m-0 $case_desc - the other way"
902 created new head
902 created new head
903 $ hg log -G --rev '::(desc("mAE-change-m")+desc("mEA-change-m"))'
903 $ hg log -G --rev '::(desc("mAE-change-m")+desc("mEA-change-m"))'
904 @ mEA-change-m-0 merge with file update and copies info on both side - A side: rename d to f, E side: b to f, (same content for f in parent) - the other way
904 @ mEA-change-m-0 merge with file update and copies info on both side - A side: rename d to f, E side: b to f, (same content for f in parent) - the other way
905 |\
905 |\
906 +---o mAE-change-m-0 merge with file update and copies info on both side - A side: rename d to f, E side: b to f, (same content for f in parent) - one way
906 +---o mAE-change-m-0 merge with file update and copies info on both side - A side: rename d to f, E side: b to f, (same content for f in parent) - one way
907 | |/
907 | |/
908 | o e-2 g -move-> f
908 | o e-2 g -move-> f
909 | |
909 | |
910 | o e-1 b -move-> g
910 | o e-1 b -move-> g
911 | |
911 | |
912 o | a-2: e -move-> f
912 o | a-2: e -move-> f
913 | |
913 | |
914 o | a-1: d -move-> e
914 o | a-1: d -move-> e
915 |/
915 |/
916 o i-2: c -move-> d, s -move-> t
916 o i-2: c -move-> d, s -move-> t
917 |
917 |
918 o i-1: a -move-> c, p -move-> s
918 o i-1: a -move-> c, p -move-> s
919 |
919 |
920 o i-0 initial commit: a b h p q r
920 o i-0 initial commit: a b h p q r
921
921
922
922
923 Subcase: merge overwrite common copy information, but with extra change during the merge
923 Subcase: merge overwrite common copy information, but with extra change during the merge
924 ````````````````````````````````````````````````````````````````````````````````````````
924 ````````````````````````````````````````````````````````````````````````````````````````
925
925
926 Merge:
926 Merge:
927 - one with change to an unrelated file (b)
927 - one with change to an unrelated file (b)
928 - one overwriting a file (d) with a rename (from h to i to d)
928 - one overwriting a file (d) with a rename (from h to i to d)
929 - the merge update f content
929 - the merge update f content
930
930
931 $ case_desc="merge with extra change - B side: unrelated change, F side: overwrite d with a copy (from h->i->d)"
931 $ case_desc="merge with extra change - B side: unrelated change, F side: overwrite d with a copy (from h->i->d)"
932
932
933 $ hg up 'desc("f-2")'
933 $ hg up 'desc("f-2")'
934 2 files updated, 0 files merged, 2 files removed, 0 files unresolved
934 2 files updated, 0 files merged, 2 files removed, 0 files unresolved
935 #if no-changeset
935 #if no-changeset
936 $ hg debugindex d | "$PYTHON" ../no-linkrev
936 $ hg debugindex d | "$PYTHON" ../no-linkrev
937 rev linkrev nodeid p1 p2
937 rev linkrev nodeid p1 p2
938 0 * d8252ab2e760 000000000000 000000000000
938 0 * d8252ab2e760 000000000000 000000000000
939 1 * b004912a8510 000000000000 000000000000
939 1 * b004912a8510 000000000000 000000000000
940 2 * 7b79e2fe0c89 000000000000 000000000000
940 2 * 7b79e2fe0c89 000000000000 000000000000
941 3 * 17ec97e60577 d8252ab2e760 000000000000
941 3 * 17ec97e60577 d8252ab2e760 000000000000
942 4 * 06dabf50734c b004912a8510 17ec97e60577
942 4 * 06dabf50734c b004912a8510 17ec97e60577
943 5 * 19c0e3924691 17ec97e60577 b004912a8510
943 5 * 19c0e3924691 17ec97e60577 b004912a8510
944 6 * 89c873a01d97 7b79e2fe0c89 17ec97e60577
944 6 * 89c873a01d97 7b79e2fe0c89 17ec97e60577
945 7 * d55cb4e9ef57 000000000000 000000000000
945 7 * d55cb4e9ef57 000000000000 000000000000
946 #else
946 #else
947 $ hg debugindex d | "$PYTHON" ../no-linkrev
947 $ hg debugindex d | "$PYTHON" ../no-linkrev
948 rev linkrev nodeid p1 p2
948 rev linkrev nodeid p1 p2
949 0 * ae258f702dfe 000000000000 000000000000
949 0 * ae258f702dfe 000000000000 000000000000
950 1 * b004912a8510 000000000000 000000000000
950 1 * b004912a8510 000000000000 000000000000
951 2 * 5cce88bf349f ae258f702dfe 000000000000
951 2 * 5cce88bf349f ae258f702dfe 000000000000
952 3 * cc269dd788c8 b004912a8510 5cce88bf349f
952 3 * cc269dd788c8 b004912a8510 5cce88bf349f
953 4 * 51c91a115080 5cce88bf349f b004912a8510
953 4 * 51c91a115080 5cce88bf349f b004912a8510
954 #endif
954 #endif
955 $ hg up 'desc("b-1")'
955 $ hg up 'desc("b-1")'
956 3 files updated, 0 files merged, 0 files removed, 0 files unresolved (no-changeset !)
956 3 files updated, 0 files merged, 0 files removed, 0 files unresolved (no-changeset !)
957 2 files updated, 0 files merged, 0 files removed, 0 files unresolved (changeset !)
957 2 files updated, 0 files merged, 0 files removed, 0 files unresolved (changeset !)
958 $ hg merge 'desc("f-2")'
958 $ hg merge 'desc("f-2")'
959 1 files updated, 0 files merged, 1 files removed, 0 files unresolved (no-changeset !)
959 1 files updated, 0 files merged, 1 files removed, 0 files unresolved (no-changeset !)
960 0 files updated, 0 files merged, 1 files removed, 0 files unresolved (changeset !)
960 0 files updated, 0 files merged, 1 files removed, 0 files unresolved (changeset !)
961 (branch merge, don't forget to commit)
961 (branch merge, don't forget to commit)
962 $ echo "extra-change to (formelly h) during the merge" > d
962 $ echo "extra-change to (formelly h) during the merge" > d
963 $ hg ci -m "mBF-change-m-0 $case_desc - one way"
963 $ hg ci -m "mBF-change-m-0 $case_desc - one way"
964 created new head
964 created new head
965 $ hg manifest --rev . --debug | grep " d"
965 $ hg manifest --rev . --debug | grep " d"
966 1c334238bd42ec85c6a0d83fd1b2a898a6a3215d 644 d (no-changeset !)
966 1c334238bd42ec85c6a0d83fd1b2a898a6a3215d 644 d (no-changeset !)
967 cea2d99c0fde64672ef61953786fdff34f16e230 644 d (changeset !)
967 cea2d99c0fde64672ef61953786fdff34f16e230 644 d (changeset !)
968
968
969 $ hg up 'desc("f-2")'
969 $ hg up 'desc("f-2")'
970 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
970 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
971 $ hg merge 'desc("b-1")'
971 $ hg merge 'desc("b-1")'
972 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
972 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
973 (branch merge, don't forget to commit)
973 (branch merge, don't forget to commit)
974 $ echo "extra-change to (formelly h) during the merge" > d
974 $ echo "extra-change to (formelly h) during the merge" > d
975 $ hg ci -m "mFB-change-m-0 $case_desc - the other way"
975 $ hg ci -m "mFB-change-m-0 $case_desc - the other way"
976 created new head
976 created new head
977 $ hg manifest --rev . --debug | grep " d"
977 $ hg manifest --rev . --debug | grep " d"
978 1c334238bd42ec85c6a0d83fd1b2a898a6a3215d 644 d (no-changeset !)
978 1c334238bd42ec85c6a0d83fd1b2a898a6a3215d 644 d (no-changeset !)
979 cea2d99c0fde64672ef61953786fdff34f16e230 644 d (changeset !)
979 cea2d99c0fde64672ef61953786fdff34f16e230 644 d (changeset !)
980 #if no-changeset
980 #if no-changeset
981 $ hg debugindex d | "$PYTHON" ../no-linkrev
981 $ hg debugindex d | "$PYTHON" ../no-linkrev
982 rev linkrev nodeid p1 p2
982 rev linkrev nodeid p1 p2
983 0 * d8252ab2e760 000000000000 000000000000
983 0 * d8252ab2e760 000000000000 000000000000
984 1 * b004912a8510 000000000000 000000000000
984 1 * b004912a8510 000000000000 000000000000
985 2 * 7b79e2fe0c89 000000000000 000000000000
985 2 * 7b79e2fe0c89 000000000000 000000000000
986 3 * 17ec97e60577 d8252ab2e760 000000000000
986 3 * 17ec97e60577 d8252ab2e760 000000000000
987 4 * 06dabf50734c b004912a8510 17ec97e60577
987 4 * 06dabf50734c b004912a8510 17ec97e60577
988 5 * 19c0e3924691 17ec97e60577 b004912a8510
988 5 * 19c0e3924691 17ec97e60577 b004912a8510
989 6 * 89c873a01d97 7b79e2fe0c89 17ec97e60577
989 6 * 89c873a01d97 7b79e2fe0c89 17ec97e60577
990 7 * d55cb4e9ef57 000000000000 000000000000
990 7 * d55cb4e9ef57 000000000000 000000000000
991 8 * 1c334238bd42 7b79e2fe0c89 000000000000
991 8 * 1c334238bd42 7b79e2fe0c89 000000000000
992 #else
992 #else
993 $ hg debugindex d | "$PYTHON" ../no-linkrev
993 $ hg debugindex d | "$PYTHON" ../no-linkrev
994 rev linkrev nodeid p1 p2
994 rev linkrev nodeid p1 p2
995 0 * ae258f702dfe 000000000000 000000000000
995 0 * ae258f702dfe 000000000000 000000000000
996 1 * b004912a8510 000000000000 000000000000
996 1 * b004912a8510 000000000000 000000000000
997 2 * 5cce88bf349f ae258f702dfe 000000000000
997 2 * 5cce88bf349f ae258f702dfe 000000000000
998 3 * cc269dd788c8 b004912a8510 5cce88bf349f
998 3 * cc269dd788c8 b004912a8510 5cce88bf349f
999 4 * 51c91a115080 5cce88bf349f b004912a8510
999 4 * 51c91a115080 5cce88bf349f b004912a8510
1000 5 * cea2d99c0fde ae258f702dfe 000000000000
1000 5 * cea2d99c0fde ae258f702dfe 000000000000
1001 #endif
1001 #endif
1002 $ hg log -G --rev '::(desc("mBF-change-m")+desc("mFB-change-m"))'
1002 $ hg log -G --rev '::(desc("mBF-change-m")+desc("mFB-change-m"))'
1003 @ mFB-change-m-0 merge with extra change - B side: unrelated change, F side: overwrite d with a copy (from h->i->d) - the other way
1003 @ mFB-change-m-0 merge with extra change - B side: unrelated change, F side: overwrite d with a copy (from h->i->d) - the other way
1004 |\
1004 |\
1005 +---o mBF-change-m-0 merge with extra change - B side: unrelated change, F side: overwrite d with a copy (from h->i->d) - one way
1005 +---o mBF-change-m-0 merge with extra change - B side: unrelated change, F side: overwrite d with a copy (from h->i->d) - one way
1006 | |/
1006 | |/
1007 | o f-2: rename i -> d
1007 | o f-2: rename i -> d
1008 | |
1008 | |
1009 | o f-1: rename h -> i
1009 | o f-1: rename h -> i
1010 | |
1010 | |
1011 o | b-1: b update
1011 o | b-1: b update
1012 |/
1012 |/
1013 o i-2: c -move-> d, s -move-> t
1013 o i-2: c -move-> d, s -move-> t
1014 |
1014 |
1015 o i-1: a -move-> c, p -move-> s
1015 o i-1: a -move-> c, p -move-> s
1016 |
1016 |
1017 o i-0 initial commit: a b h p q r
1017 o i-0 initial commit: a b h p q r
1018
1018
1019
1019
1020 Subcase: restoring and untouched deleted file, while touching it
1020 Subcase: restoring and untouched deleted file, while touching it
1021 ````````````````````````````````````````````````````````````````
1021 ````````````````````````````````````````````````````````````````
1022
1022
1023 Merge:
1023 Merge:
1024 - one removing a file (d)
1024 - one removing a file (d)
1025 - one leaving the file untouched
1025 - one leaving the file untouched
1026 - the merge actively restore the file to the same content.
1026 - the merge actively restore the file to the same content.
1027
1027
1028 In this case, the file keep on living after the merge. So we should not drop its
1028 In this case, the file keep on living after the merge. So we should not drop its
1029 copy tracing chain.
1029 copy tracing chain.
1030
1030
1031 $ case_desc="merge explicitely revive deleted file - B side: unrelated change, C side: delete d (restored by merge)"
1031 $ case_desc="merge explicitely revive deleted file - B side: unrelated change, C side: delete d (restored by merge)"
1032
1032
1033 $ hg up 'desc("c-1")'
1033 $ hg up 'desc("c-1")'
1034 2 files updated, 0 files merged, 1 files removed, 0 files unresolved
1034 2 files updated, 0 files merged, 1 files removed, 0 files unresolved
1035 $ hg merge 'desc("b-1")'
1035 $ hg merge 'desc("b-1")'
1036 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1036 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1037 (branch merge, don't forget to commit)
1037 (branch merge, don't forget to commit)
1038 $ hg revert --rev 'desc("b-1")' d
1038 $ hg revert --rev 'desc("b-1")' d
1039 $ echo "new content for d after the revert" > d
1039 $ echo "new content for d after the revert" > d
1040 $ hg ci -m "mCB-change-m-0 $case_desc - one way"
1040 $ hg ci -m "mCB-change-m-0 $case_desc - one way"
1041 created new head
1041 created new head
1042 $ hg manifest --rev . --debug | grep " d"
1042 $ hg manifest --rev . --debug | grep " d"
1043 e333780c17752a3b0dd15e3ad48aa4e5c745f621 644 d (no-changeset !)
1043 e333780c17752a3b0dd15e3ad48aa4e5c745f621 644 d (no-changeset !)
1044 4b540a18ad699234b2b2aa18cb69555ac9c4b1df 644 d (changeset !)
1044 4b540a18ad699234b2b2aa18cb69555ac9c4b1df 644 d (changeset !)
1045
1045
1046 $ hg up 'desc("b-1")'
1046 $ hg up 'desc("b-1")'
1047 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1047 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1048 $ hg merge 'desc("c-1")'
1048 $ hg merge 'desc("c-1")'
1049 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
1049 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
1050 (branch merge, don't forget to commit)
1050 (branch merge, don't forget to commit)
1051 $ hg revert --rev 'desc("b-1")' d
1051 $ hg revert --rev 'desc("b-1")' d
1052 $ echo "new content for d after the revert" > d
1052 $ echo "new content for d after the revert" > d
1053 $ hg ci -m "mBC-change-m-0 $case_desc - the other way"
1053 $ hg ci -m "mBC-change-m-0 $case_desc - the other way"
1054 created new head
1054 created new head
1055 $ hg manifest --rev . --debug | grep " d"
1055 $ hg manifest --rev . --debug | grep " d"
1056 e333780c17752a3b0dd15e3ad48aa4e5c745f621 644 d (no-changeset !)
1056 e333780c17752a3b0dd15e3ad48aa4e5c745f621 644 d (no-changeset !)
1057 4b540a18ad699234b2b2aa18cb69555ac9c4b1df 644 d (changeset !)
1057 4b540a18ad699234b2b2aa18cb69555ac9c4b1df 644 d (changeset !)
1058
1058
1059
1059
1060 $ hg up null --quiet
1060 $ hg up null --quiet
1061 $ hg log -G --rev '::(desc("mCB-change-m")+desc("mBC-change-m"))'
1061 $ hg log -G --rev '::(desc("mCB-change-m")+desc("mBC-change-m"))'
1062 o mBC-change-m-0 merge explicitely revive deleted file - B side: unrelated change, C side: delete d (restored by merge) - the other way
1062 o mBC-change-m-0 merge explicitely revive deleted file - B side: unrelated change, C side: delete d (restored by merge) - the other way
1063 |\
1063 |\
1064 +---o mCB-change-m-0 merge explicitely revive deleted file - B side: unrelated change, C side: delete d (restored by merge) - one way
1064 +---o mCB-change-m-0 merge explicitely revive deleted file - B side: unrelated change, C side: delete d (restored by merge) - one way
1065 | |/
1065 | |/
1066 | o c-1 delete d
1066 | o c-1 delete d
1067 | |
1067 | |
1068 o | b-1: b update
1068 o | b-1: b update
1069 |/
1069 |/
1070 o i-2: c -move-> d, s -move-> t
1070 o i-2: c -move-> d, s -move-> t
1071 |
1071 |
1072 o i-1: a -move-> c, p -move-> s
1072 o i-1: a -move-> c, p -move-> s
1073 |
1073 |
1074 o i-0 initial commit: a b h p q r
1074 o i-0 initial commit: a b h p q r
1075
1075
1076
1076
1077 Decision from previous merge are properly chained with later merge
1077 Decision from previous merge are properly chained with later merge
1078 ------------------------------------------------------------------
1078 ------------------------------------------------------------------
1079
1079
1080 Subcase: chaining conflicting rename resolution
1080 Subcase: chaining conflicting rename resolution
1081 ```````````````````````````````````````````````
1081 ```````````````````````````````````````````````
1082
1082
1083 The "mAEm" and "mEAm" case create a rename tracking conflict on file 'f'. We
1083 The "mAEm" and "mEAm" case create a rename tracking conflict on file 'f'. We
1084 add more change on the respective branch and merge again. These second merge
1084 add more change on the respective branch and merge again. These second merge
1085 does not involve the file 'f' and the arbitration done within "mAEm" and "mEA"
1085 does not involve the file 'f' and the arbitration done within "mAEm" and "mEA"
1086 about that file should stay unchanged.
1086 about that file should stay unchanged.
1087
1087
1088 We also touch J during some of the merge to check for unrelated change to new file during merge.
1088 We also touch J during some of the merge to check for unrelated change to new file during merge.
1089
1089
1090 $ case_desc="chained merges (conflict -> simple) - same content everywhere"
1090 $ case_desc="chained merges (conflict -> simple) - same content everywhere"
1091
1091
1092 (extra unrelated changes)
1092 (extra unrelated changes)
1093
1093
1094 $ hg up 'desc("a-2")'
1094 $ hg up 'desc("a-2")'
1095 6 files updated, 0 files merged, 0 files removed, 0 files unresolved
1095 6 files updated, 0 files merged, 0 files removed, 0 files unresolved
1096 $ echo j > unrelated-j
1096 $ echo j > unrelated-j
1097 $ hg add unrelated-j
1097 $ hg add unrelated-j
1098 $ hg ci -m 'j-1: unrelated changes (based on the "a" series of changes)'
1098 $ hg ci -m 'j-1: unrelated changes (based on the "a" series of changes)'
1099 created new head
1099 created new head
1100
1100
1101 $ hg up 'desc("e-2")'
1101 $ hg up 'desc("e-2")'
1102 2 files updated, 0 files merged, 2 files removed, 0 files unresolved (no-changeset !)
1102 2 files updated, 0 files merged, 2 files removed, 0 files unresolved (no-changeset !)
1103 1 files updated, 0 files merged, 2 files removed, 0 files unresolved (changeset !)
1103 1 files updated, 0 files merged, 2 files removed, 0 files unresolved (changeset !)
1104 $ echo k > unrelated-k
1104 $ echo k > unrelated-k
1105 $ hg add unrelated-k
1105 $ hg add unrelated-k
1106 $ hg ci -m 'k-1: unrelated changes (based on "e" changes)'
1106 $ hg ci -m 'k-1: unrelated changes (based on "e" changes)'
1107 created new head
1107 created new head
1108
1108
1109 (merge variant 1)
1109 (merge variant 1)
1110
1110
1111 $ hg up 'desc("mAEm")'
1111 $ hg up 'desc("mAEm")'
1112 1 files updated, 0 files merged, 2 files removed, 0 files unresolved (no-changeset !)
1112 1 files updated, 0 files merged, 2 files removed, 0 files unresolved (no-changeset !)
1113 0 files updated, 0 files merged, 2 files removed, 0 files unresolved (changeset !)
1113 0 files updated, 0 files merged, 2 files removed, 0 files unresolved (changeset !)
1114 $ hg merge 'desc("k-1")'
1114 $ hg merge 'desc("k-1")'
1115 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1115 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1116 (branch merge, don't forget to commit)
1116 (branch merge, don't forget to commit)
1117 $ hg ci -m "mAE,Km: $case_desc"
1117 $ hg ci -m "mAE,Km: $case_desc"
1118
1118
1119 (merge variant 2)
1119 (merge variant 2)
1120
1120
1121 $ hg up 'desc("k-1")'
1121 $ hg up 'desc("k-1")'
1122 2 files updated, 0 files merged, 0 files removed, 0 files unresolved (no-changeset !)
1122 2 files updated, 0 files merged, 0 files removed, 0 files unresolved (no-changeset !)
1123 1 files updated, 0 files merged, 0 files removed, 0 files unresolved (changeset !)
1123 1 files updated, 0 files merged, 0 files removed, 0 files unresolved (changeset !)
1124
1124
1125 $ hg merge 'desc("mAEm")'
1125 $ hg merge 'desc("mAEm")'
1126 1 files updated, 0 files merged, 1 files removed, 0 files unresolved (no-changeset !)
1126 1 files updated, 0 files merged, 1 files removed, 0 files unresolved (no-changeset !)
1127 0 files updated, 0 files merged, 1 files removed, 0 files unresolved (changeset !)
1127 0 files updated, 0 files merged, 1 files removed, 0 files unresolved (changeset !)
1128 (branch merge, don't forget to commit)
1128 (branch merge, don't forget to commit)
1129 $ hg ci -m "mK,AEm: $case_desc"
1129 $ hg ci -m "mK,AEm: $case_desc"
1130 created new head
1130 created new head
1131
1131
1132 (merge variant 3)
1132 (merge variant 3)
1133
1133
1134 $ hg up 'desc("mEAm")'
1134 $ hg up 'desc("mEAm")'
1135 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
1135 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
1136 $ hg merge 'desc("j-1")'
1136 $ hg merge 'desc("j-1")'
1137 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1137 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1138 (branch merge, don't forget to commit)
1138 (branch merge, don't forget to commit)
1139 $ echo jj > unrelated-j
1139 $ echo jj > unrelated-j
1140 $ hg ci -m "mEA,Jm: $case_desc"
1140 $ hg ci -m "mEA,Jm: $case_desc"
1141
1141
1142 (merge variant 4)
1142 (merge variant 4)
1143
1143
1144 $ hg up 'desc("j-1")'
1144 $ hg up 'desc("j-1")'
1145 3 files updated, 0 files merged, 0 files removed, 0 files unresolved (no-changeset !)
1145 3 files updated, 0 files merged, 0 files removed, 0 files unresolved (no-changeset !)
1146 2 files updated, 0 files merged, 0 files removed, 0 files unresolved (changeset !)
1146 2 files updated, 0 files merged, 0 files removed, 0 files unresolved (changeset !)
1147 $ hg merge 'desc("mEAm")'
1147 $ hg merge 'desc("mEAm")'
1148 1 files updated, 0 files merged, 1 files removed, 0 files unresolved (no-changeset !)
1148 1 files updated, 0 files merged, 1 files removed, 0 files unresolved (no-changeset !)
1149 0 files updated, 0 files merged, 1 files removed, 0 files unresolved (changeset !)
1149 0 files updated, 0 files merged, 1 files removed, 0 files unresolved (changeset !)
1150 (branch merge, don't forget to commit)
1150 (branch merge, don't forget to commit)
1151 $ echo jj > unrelated-j
1151 $ echo jj > unrelated-j
1152 $ hg ci -m "mJ,EAm: $case_desc"
1152 $ hg ci -m "mJ,EAm: $case_desc"
1153 created new head
1153 created new head
1154
1154
1155
1155
1156 $ hg log -G --rev '::(desc("mAE,Km") + desc("mK,AEm") + desc("mEA,Jm") + desc("mJ,EAm"))'
1156 $ hg log -G --rev '::(desc("mAE,Km") + desc("mK,AEm") + desc("mEA,Jm") + desc("mJ,EAm"))'
1157 @ mJ,EAm: chained merges (conflict -> simple) - same content everywhere
1157 @ mJ,EAm: chained merges (conflict -> simple) - same content everywhere
1158 |\
1158 |\
1159 +---o mEA,Jm: chained merges (conflict -> simple) - same content everywhere
1159 +---o mEA,Jm: chained merges (conflict -> simple) - same content everywhere
1160 | |/
1160 | |/
1161 | | o mK,AEm: chained merges (conflict -> simple) - same content everywhere
1161 | | o mK,AEm: chained merges (conflict -> simple) - same content everywhere
1162 | | |\
1162 | | |\
1163 | | +---o mAE,Km: chained merges (conflict -> simple) - same content everywhere
1163 | | +---o mAE,Km: chained merges (conflict -> simple) - same content everywhere
1164 | | | |/
1164 | | | |/
1165 | | | o k-1: unrelated changes (based on "e" changes)
1165 | | | o k-1: unrelated changes (based on "e" changes)
1166 | | | |
1166 | | | |
1167 | o | | j-1: unrelated changes (based on the "a" series of changes)
1167 | o | | j-1: unrelated changes (based on the "a" series of changes)
1168 | | | |
1168 | | | |
1169 o-----+ mEAm-0 merge with copies info on both side - A side: rename d to f, E side: b to f, (same content for f) - the other way
1169 o-----+ mEAm-0 merge with copies info on both side - A side: rename d to f, E side: b to f, (same content for f) - the other way
1170 |/ / /
1170 |/ / /
1171 | o / mAEm-0 merge with copies info on both side - A side: rename d to f, E side: b to f, (same content for f) - one way
1171 | o / mAEm-0 merge with copies info on both side - A side: rename d to f, E side: b to f, (same content for f) - one way
1172 |/|/
1172 |/|/
1173 | o e-2 g -move-> f
1173 | o e-2 g -move-> f
1174 | |
1174 | |
1175 | o e-1 b -move-> g
1175 | o e-1 b -move-> g
1176 | |
1176 | |
1177 o | a-2: e -move-> f
1177 o | a-2: e -move-> f
1178 | |
1178 | |
1179 o | a-1: d -move-> e
1179 o | a-1: d -move-> e
1180 |/
1180 |/
1181 o i-2: c -move-> d, s -move-> t
1181 o i-2: c -move-> d, s -move-> t
1182 |
1182 |
1183 o i-1: a -move-> c, p -move-> s
1183 o i-1: a -move-> c, p -move-> s
1184 |
1184 |
1185 o i-0 initial commit: a b h p q r
1185 o i-0 initial commit: a b h p q r
1186
1186
1187
1187
1188 Subcase: chaining conflicting rename resolution, with actual merging happening
1188 Subcase: chaining conflicting rename resolution, with actual merging happening
1189 ``````````````````````````````````````````````````````````````````````````````
1189 ``````````````````````````````````````````````````````````````````````````````
1190
1190
1191 The "mPQm" and "mQPm" case create a rename tracking conflict on file 't'. We
1191 The "mPQm" and "mQPm" case create a rename tracking conflict on file 't'. We
1192 add more change on the respective branch and merge again. These second merge
1192 add more change on the respective branch and merge again. These second merge
1193 does not involve the file 't' and the arbitration done within "mPQm" and "mQP"
1193 does not involve the file 't' and the arbitration done within "mPQm" and "mQP"
1194 about that file should stay unchanged.
1194 about that file should stay unchanged.
1195
1195
1196 $ case_desc="chained merges (conflict -> simple) - different content"
1196 $ case_desc="chained merges (conflict -> simple) - different content"
1197
1197
1198 (extra unrelated changes)
1198 (extra unrelated changes)
1199
1199
1200 $ hg up 'desc("p-2")'
1200 $ hg up 'desc("p-2")'
1201 3 files updated, 0 files merged, 3 files removed, 0 files unresolved
1201 3 files updated, 0 files merged, 3 files removed, 0 files unresolved
1202 $ echo s > unrelated-s
1202 $ echo s > unrelated-s
1203 $ hg add unrelated-s
1203 $ hg add unrelated-s
1204 $ hg ci -m 's-1: unrelated changes (based on the "p" series of changes)'
1204 $ hg ci -m 's-1: unrelated changes (based on the "p" series of changes)'
1205 created new head
1205 created new head
1206
1206
1207 $ hg up 'desc("q-2")'
1207 $ hg up 'desc("q-2")'
1208 2 files updated, 0 files merged, 2 files removed, 0 files unresolved
1208 2 files updated, 0 files merged, 2 files removed, 0 files unresolved
1209 $ echo t > unrelated-t
1209 $ echo t > unrelated-t
1210 $ hg add unrelated-t
1210 $ hg add unrelated-t
1211 $ hg ci -m 't-1: unrelated changes (based on "q" changes)'
1211 $ hg ci -m 't-1: unrelated changes (based on "q" changes)'
1212 created new head
1212 created new head
1213
1213
1214 (merge variant 1)
1214 (merge variant 1)
1215
1215
1216 $ hg up 'desc("mPQm")'
1216 $ hg up 'desc("mPQm")'
1217 1 files updated, 0 files merged, 2 files removed, 0 files unresolved
1217 1 files updated, 0 files merged, 2 files removed, 0 files unresolved
1218 $ hg merge 'desc("t-1")'
1218 $ hg merge 'desc("t-1")'
1219 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1219 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1220 (branch merge, don't forget to commit)
1220 (branch merge, don't forget to commit)
1221 $ hg ci -m "mPQ,Tm: $case_desc"
1221 $ hg ci -m "mPQ,Tm: $case_desc"
1222
1222
1223 (merge variant 2)
1223 (merge variant 2)
1224
1224
1225 $ hg up 'desc("t-1")'
1225 $ hg up 'desc("t-1")'
1226 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
1226 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
1227
1227
1228 $ hg merge 'desc("mPQm")'
1228 $ hg merge 'desc("mPQm")'
1229 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
1229 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
1230 (branch merge, don't forget to commit)
1230 (branch merge, don't forget to commit)
1231 $ hg ci -m "mT,PQm: $case_desc"
1231 $ hg ci -m "mT,PQm: $case_desc"
1232 created new head
1232 created new head
1233
1233
1234 (merge variant 3)
1234 (merge variant 3)
1235
1235
1236 $ hg up 'desc("mQPm")'
1236 $ hg up 'desc("mQPm")'
1237 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
1237 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
1238 $ hg merge 'desc("s-1")'
1238 $ hg merge 'desc("s-1")'
1239 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1239 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1240 (branch merge, don't forget to commit)
1240 (branch merge, don't forget to commit)
1241 $ hg ci -m "mQP,Sm: $case_desc"
1241 $ hg ci -m "mQP,Sm: $case_desc"
1242
1242
1243 (merge variant 4)
1243 (merge variant 4)
1244
1244
1245 $ hg up 'desc("s-1")'
1245 $ hg up 'desc("s-1")'
1246 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
1246 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
1247 $ hg merge 'desc("mQPm")'
1247 $ hg merge 'desc("mQPm")'
1248 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
1248 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
1249 (branch merge, don't forget to commit)
1249 (branch merge, don't forget to commit)
1250 $ hg ci -m "mS,QPm: $case_desc"
1250 $ hg ci -m "mS,QPm: $case_desc"
1251 created new head
1251 created new head
1252 $ hg up null --quiet
1252 $ hg up null --quiet
1253
1253
1254
1254
1255 $ hg log -G --rev '::(desc("mPQ,Tm") + desc("mT,PQm") + desc("mQP,Sm") + desc("mS,QPm"))'
1255 $ hg log -G --rev '::(desc("mPQ,Tm") + desc("mT,PQm") + desc("mQP,Sm") + desc("mS,QPm"))'
1256 o mS,QPm: chained merges (conflict -> simple) - different content
1256 o mS,QPm: chained merges (conflict -> simple) - different content
1257 |\
1257 |\
1258 +---o mQP,Sm: chained merges (conflict -> simple) - different content
1258 +---o mQP,Sm: chained merges (conflict -> simple) - different content
1259 | |/
1259 | |/
1260 | | o mT,PQm: chained merges (conflict -> simple) - different content
1260 | | o mT,PQm: chained merges (conflict -> simple) - different content
1261 | | |\
1261 | | |\
1262 | | +---o mPQ,Tm: chained merges (conflict -> simple) - different content
1262 | | +---o mPQ,Tm: chained merges (conflict -> simple) - different content
1263 | | | |/
1263 | | | |/
1264 | | | o t-1: unrelated changes (based on "q" changes)
1264 | | | o t-1: unrelated changes (based on "q" changes)
1265 | | | |
1265 | | | |
1266 | o | | s-1: unrelated changes (based on the "p" series of changes)
1266 | o | | s-1: unrelated changes (based on the "p" series of changes)
1267 | | | |
1267 | | | |
1268 o-----+ mQPm-0 merge with copies info on both side - P side: rename t to v, Q side: r to v, (different content) - the other way
1268 o-----+ mQPm-0 merge with copies info on both side - P side: rename t to v, Q side: r to v, (different content) - the other way
1269 |/ / /
1269 |/ / /
1270 | o / mPQm-0 merge with copies info on both side - P side: rename t to v, Q side: r to v, (different content) - one way
1270 | o / mPQm-0 merge with copies info on both side - P side: rename t to v, Q side: r to v, (different content) - one way
1271 |/|/
1271 |/|/
1272 | o q-2 w -move-> v
1272 | o q-2 w -move-> v
1273 | |
1273 | |
1274 | o q-1 r -move-> w
1274 | o q-1 r -move-> w
1275 | |
1275 | |
1276 o | p-2: u -move-> v
1276 o | p-2: u -move-> v
1277 | |
1277 | |
1278 o | p-1: t -move-> u
1278 o | p-1: t -move-> u
1279 |/
1279 |/
1280 o i-2: c -move-> d, s -move-> t
1280 o i-2: c -move-> d, s -move-> t
1281 |
1281 |
1282 o i-1: a -move-> c, p -move-> s
1282 o i-1: a -move-> c, p -move-> s
1283 |
1283 |
1284 o i-0 initial commit: a b h p q r
1284 o i-0 initial commit: a b h p q r
1285
1285
1286
1286
1287 Subcase: chaining salvage information during a merge
1287 Subcase: chaining salvage information during a merge
1288 ````````````````````````````````````````````````````
1288 ````````````````````````````````````````````````````
1289
1289
1290 We add more change on the branch were the file was deleted. merging again
1290 We add more change on the branch were the file was deleted. merging again
1291 should preserve the fact eh file was salvaged.
1291 should preserve the fact eh file was salvaged.
1292
1292
1293 $ case_desc="chained merges (salvaged -> simple) - same content (when the file exists)"
1293 $ case_desc="chained merges (salvaged -> simple) - same content (when the file exists)"
1294
1294
1295 (creating the change)
1295 (creating the change)
1296
1296
1297 $ hg up 'desc("c-1")'
1297 $ hg up 'desc("c-1")'
1298 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
1298 5 files updated, 0 files merged, 0 files removed, 0 files unresolved
1299 $ echo l > unrelated-l
1299 $ echo l > unrelated-l
1300 $ hg add unrelated-l
1300 $ hg add unrelated-l
1301 $ hg ci -m 'l-1: unrelated changes (based on "c" changes)'
1301 $ hg ci -m 'l-1: unrelated changes (based on "c" changes)'
1302 created new head
1302 created new head
1303
1303
1304 (Merge variant 1)
1304 (Merge variant 1)
1305
1305
1306 $ hg up 'desc("mBC-revert-m")'
1306 $ hg up 'desc("mBC-revert-m")'
1307 2 files updated, 0 files merged, 1 files removed, 0 files unresolved
1307 2 files updated, 0 files merged, 1 files removed, 0 files unresolved
1308 $ hg merge 'desc("l-1")'
1308 $ hg merge 'desc("l-1")'
1309 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1309 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1310 (branch merge, don't forget to commit)
1310 (branch merge, don't forget to commit)
1311 $ hg ci -m "mBC+revert,Lm: $case_desc"
1311 $ hg ci -m "mBC+revert,Lm: $case_desc"
1312
1312
1313 (Merge variant 2)
1313 (Merge variant 2)
1314
1314
1315 $ hg up 'desc("mCB-revert-m")'
1315 $ hg up 'desc("mCB-revert-m")'
1316 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
1316 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
1317 $ hg merge 'desc("l-1")'
1317 $ hg merge 'desc("l-1")'
1318 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1318 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1319 (branch merge, don't forget to commit)
1319 (branch merge, don't forget to commit)
1320 $ hg ci -m "mCB+revert,Lm: $case_desc"
1320 $ hg ci -m "mCB+revert,Lm: $case_desc"
1321
1321
1322 (Merge variant 3)
1322 (Merge variant 3)
1323
1323
1324 $ hg up 'desc("l-1")'
1324 $ hg up 'desc("l-1")'
1325 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
1325 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
1326
1326
1327 $ hg merge 'desc("mBC-revert-m")'
1327 $ hg merge 'desc("mBC-revert-m")'
1328 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
1328 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
1329 (branch merge, don't forget to commit)
1329 (branch merge, don't forget to commit)
1330 $ hg ci -m "mL,BC+revertm: $case_desc"
1330 $ hg ci -m "mL,BC+revertm: $case_desc"
1331 created new head
1331 created new head
1332
1332
1333 (Merge variant 4)
1333 (Merge variant 4)
1334
1334
1335 $ hg up 'desc("l-1")'
1335 $ hg up 'desc("l-1")'
1336 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
1336 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
1337
1337
1338 $ hg merge 'desc("mCB-revert-m")'
1338 $ hg merge 'desc("mCB-revert-m")'
1339 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
1339 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
1340 (branch merge, don't forget to commit)
1340 (branch merge, don't forget to commit)
1341 $ hg ci -m "mL,CB+revertm: $case_desc"
1341 $ hg ci -m "mL,CB+revertm: $case_desc"
1342 created new head
1342 created new head
1343
1343
1344 $ hg log -G --rev '::(desc("mBC+revert,Lm") + desc("mCB+revert,Lm") + desc("mL,BC+revertm") + desc("mL,CB+revertm"))'
1344 $ hg log -G --rev '::(desc("mBC+revert,Lm") + desc("mCB+revert,Lm") + desc("mL,BC+revertm") + desc("mL,CB+revertm"))'
1345 @ mL,CB+revertm: chained merges (salvaged -> simple) - same content (when the file exists)
1345 @ mL,CB+revertm: chained merges (salvaged -> simple) - same content (when the file exists)
1346 |\
1346 |\
1347 | | o mL,BC+revertm: chained merges (salvaged -> simple) - same content (when the file exists)
1347 | | o mL,BC+revertm: chained merges (salvaged -> simple) - same content (when the file exists)
1348 | |/|
1348 | |/|
1349 +-+---o mCB+revert,Lm: chained merges (salvaged -> simple) - same content (when the file exists)
1349 +-+---o mCB+revert,Lm: chained merges (salvaged -> simple) - same content (when the file exists)
1350 | | |
1350 | | |
1351 | +---o mBC+revert,Lm: chained merges (salvaged -> simple) - same content (when the file exists)
1351 | +---o mBC+revert,Lm: chained merges (salvaged -> simple) - same content (when the file exists)
1352 | | |/
1352 | | |/
1353 | o | l-1: unrelated changes (based on "c" changes)
1353 | o | l-1: unrelated changes (based on "c" changes)
1354 | | |
1354 | | |
1355 | | o mBC-revert-m-0 merge explicitely revive deleted file - B side: unrelated change, C side: delete d (restored by merge) - the other way
1355 | | o mBC-revert-m-0 merge explicitely revive deleted file - B side: unrelated change, C side: delete d (restored by merge) - the other way
1356 | |/|
1356 | |/|
1357 o---+ mCB-revert-m-0 merge explicitely revive deleted file - B side: unrelated change, C side: delete d (restored by merge) - one way
1357 o---+ mCB-revert-m-0 merge explicitely revive deleted file - B side: unrelated change, C side: delete d (restored by merge) - one way
1358 |/ /
1358 |/ /
1359 o | c-1 delete d
1359 o | c-1 delete d
1360 | |
1360 | |
1361 | o b-1: b update
1361 | o b-1: b update
1362 |/
1362 |/
1363 o i-2: c -move-> d, s -move-> t
1363 o i-2: c -move-> d, s -move-> t
1364 |
1364 |
1365 o i-1: a -move-> c, p -move-> s
1365 o i-1: a -move-> c, p -move-> s
1366 |
1366 |
1367 o i-0 initial commit: a b h p q r
1367 o i-0 initial commit: a b h p q r
1368
1368
1369
1369
1370
1370
1371 Subcase: chaining "merged" information during a merge
1371 Subcase: chaining "merged" information during a merge
1372 ``````````````````````````````````````````````````````
1372 ``````````````````````````````````````````````````````
1373
1373
1374 When a non-rename change are merged with a copy overwrite, the merge pick the copy source from (p1) as the reference. We should preserve this information in subsequent merges.
1374 When a non-rename change are merged with a copy overwrite, the merge pick the copy source from (p1) as the reference. We should preserve this information in subsequent merges.
1375
1375
1376 $ case_desc="chained merges (copy-overwrite -> simple) - same content"
1376 $ case_desc="chained merges (copy-overwrite -> simple) - same content"
1377
1377
1378 (extra unrelated changes)
1378 (extra unrelated changes)
1379
1379
1380 $ hg up 'desc("f-2")'
1380 $ hg up 'desc("f-2")'
1381 2 files updated, 0 files merged, 2 files removed, 0 files unresolved (no-changeset !)
1381 2 files updated, 0 files merged, 2 files removed, 0 files unresolved (no-changeset !)
1382 1 files updated, 0 files merged, 2 files removed, 0 files unresolved (changeset !)
1382 1 files updated, 0 files merged, 2 files removed, 0 files unresolved (changeset !)
1383 $ echo n > unrelated-n
1383 $ echo n > unrelated-n
1384 $ hg add unrelated-n
1384 $ hg add unrelated-n
1385 $ hg ci -m 'n-1: unrelated changes (based on the "f" series of changes)'
1385 $ hg ci -m 'n-1: unrelated changes (based on the "f" series of changes)'
1386 created new head
1386 created new head
1387
1387
1388 $ hg up 'desc("g-1")'
1388 $ hg up 'desc("g-1")'
1389 2 files updated, 0 files merged, 1 files removed, 0 files unresolved
1389 2 files updated, 0 files merged, 1 files removed, 0 files unresolved
1390 $ echo o > unrelated-o
1390 $ echo o > unrelated-o
1391 $ hg add unrelated-o
1391 $ hg add unrelated-o
1392 $ hg ci -m 'o-1: unrelated changes (based on "g" changes)'
1392 $ hg ci -m 'o-1: unrelated changes (based on "g" changes)'
1393 created new head
1393 created new head
1394
1394
1395 (merge variant 1)
1395 (merge variant 1)
1396
1396
1397 $ hg up 'desc("mFGm")'
1397 $ hg up 'desc("mFGm")'
1398 1 files updated, 0 files merged, 2 files removed, 0 files unresolved (no-changeset !)
1398 1 files updated, 0 files merged, 2 files removed, 0 files unresolved (no-changeset !)
1399 0 files updated, 0 files merged, 2 files removed, 0 files unresolved (changeset !)
1399 0 files updated, 0 files merged, 2 files removed, 0 files unresolved (changeset !)
1400 $ hg merge 'desc("o-1")'
1400 $ hg merge 'desc("o-1")'
1401 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1401 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1402 (branch merge, don't forget to commit)
1402 (branch merge, don't forget to commit)
1403 $ hg ci -m "mFG,Om: $case_desc"
1403 $ hg ci -m "mFG,Om: $case_desc"
1404
1404
1405 (merge variant 2)
1405 (merge variant 2)
1406
1406
1407 $ hg up 'desc("o-1")'
1407 $ hg up 'desc("o-1")'
1408 2 files updated, 0 files merged, 0 files removed, 0 files unresolved (no-changeset !)
1408 2 files updated, 0 files merged, 0 files removed, 0 files unresolved (no-changeset !)
1409 1 files updated, 0 files merged, 0 files removed, 0 files unresolved (changeset !)
1409 1 files updated, 0 files merged, 0 files removed, 0 files unresolved (changeset !)
1410 $ hg merge 'desc("FGm")'
1410 $ hg merge 'desc("FGm")'
1411 1 files updated, 0 files merged, 1 files removed, 0 files unresolved (no-changeset !)
1411 1 files updated, 0 files merged, 1 files removed, 0 files unresolved (no-changeset !)
1412 0 files updated, 0 files merged, 1 files removed, 0 files unresolved (changeset !)
1412 0 files updated, 0 files merged, 1 files removed, 0 files unresolved (changeset !)
1413 (branch merge, don't forget to commit)
1413 (branch merge, don't forget to commit)
1414 $ hg ci -m "mO,FGm: $case_desc"
1414 $ hg ci -m "mO,FGm: $case_desc"
1415 created new head
1415 created new head
1416
1416
1417 (merge variant 3)
1417 (merge variant 3)
1418
1418
1419 $ hg up 'desc("mGFm")'
1419 $ hg up 'desc("mGFm")'
1420 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
1420 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
1421 $ hg merge 'desc("n-1")'
1421 $ hg merge 'desc("n-1")'
1422 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1422 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1423 (branch merge, don't forget to commit)
1423 (branch merge, don't forget to commit)
1424 $ hg ci -m "mGF,Nm: $case_desc"
1424 $ hg ci -m "mGF,Nm: $case_desc"
1425
1425
1426 (merge variant 4)
1426 (merge variant 4)
1427
1427
1428 $ hg up 'desc("n-1")'
1428 $ hg up 'desc("n-1")'
1429 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1429 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1430 $ hg merge 'desc("mGFm")'
1430 $ hg merge 'desc("mGFm")'
1431 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1431 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1432 (branch merge, don't forget to commit)
1432 (branch merge, don't forget to commit)
1433 $ hg ci -m "mN,GFm: $case_desc"
1433 $ hg ci -m "mN,GFm: $case_desc"
1434 created new head
1434 created new head
1435
1435
1436 $ hg log -G --rev '::(desc("mFG,Om") + desc("mO,FGm") + desc("mGF,Nm") + desc("mN,GFm"))'
1436 $ hg log -G --rev '::(desc("mFG,Om") + desc("mO,FGm") + desc("mGF,Nm") + desc("mN,GFm"))'
1437 @ mN,GFm: chained merges (copy-overwrite -> simple) - same content
1437 @ mN,GFm: chained merges (copy-overwrite -> simple) - same content
1438 |\
1438 |\
1439 +---o mGF,Nm: chained merges (copy-overwrite -> simple) - same content
1439 +---o mGF,Nm: chained merges (copy-overwrite -> simple) - same content
1440 | |/
1440 | |/
1441 | | o mO,FGm: chained merges (copy-overwrite -> simple) - same content
1441 | | o mO,FGm: chained merges (copy-overwrite -> simple) - same content
1442 | | |\
1442 | | |\
1443 | | +---o mFG,Om: chained merges (copy-overwrite -> simple) - same content
1443 | | +---o mFG,Om: chained merges (copy-overwrite -> simple) - same content
1444 | | | |/
1444 | | | |/
1445 | | | o o-1: unrelated changes (based on "g" changes)
1445 | | | o o-1: unrelated changes (based on "g" changes)
1446 | | | |
1446 | | | |
1447 | o | | n-1: unrelated changes (based on the "f" series of changes)
1447 | o | | n-1: unrelated changes (based on the "f" series of changes)
1448 | | | |
1448 | | | |
1449 o-----+ mGFm-0 merge - G side: content change, F side: copy overwrite, no content change - the other way
1449 o-----+ mGFm-0 merge - G side: content change, F side: copy overwrite, no content change - the other way
1450 |/ / /
1450 |/ / /
1451 | o / mFGm-0 merge - G side: content change, F side: copy overwrite, no content change - one way
1451 | o / mFGm-0 merge - G side: content change, F side: copy overwrite, no content change - one way
1452 |/|/
1452 |/|/
1453 | o g-1: update d
1453 | o g-1: update d
1454 | |
1454 | |
1455 o | f-2: rename i -> d
1455 o | f-2: rename i -> d
1456 | |
1456 | |
1457 o | f-1: rename h -> i
1457 o | f-1: rename h -> i
1458 |/
1458 |/
1459 o i-2: c -move-> d, s -move-> t
1459 o i-2: c -move-> d, s -move-> t
1460 |
1460 |
1461 o i-1: a -move-> c, p -move-> s
1461 o i-1: a -move-> c, p -move-> s
1462 |
1462 |
1463 o i-0 initial commit: a b h p q r
1463 o i-0 initial commit: a b h p q r
1464
1464
1465
1465
1466 Subcase: chaining conflicting rename resolution, with extra change during the merge
1466 Subcase: chaining conflicting rename resolution, with extra change during the merge
1467 ```````````````````````````````````````````````````````````````````````````````````
1467 ```````````````````````````````````````````````````````````````````````````````````
1468
1468
1469 The "mEA-change-m-0" and "mAE-change-m-0" case create a rename tracking conflict on file 'f'. We
1469 The "mEA-change-m-0" and "mAE-change-m-0" case create a rename tracking conflict on file 'f'. We
1470 add more change on the respective branch and merge again. These second merge
1470 add more change on the respective branch and merge again. These second merge
1471 does not involve the file 'f' and the arbitration done within "mAEm" and "mEA"
1471 does not involve the file 'f' and the arbitration done within "mAEm" and "mEA"
1472 about that file should stay unchanged.
1472 about that file should stay unchanged.
1473
1473
1474 $ case_desc="chained merges (conflict+change -> simple) - same content on both branch in the initial merge"
1474 $ case_desc="chained merges (conflict+change -> simple) - same content on both branch in the initial merge"
1475
1475
1476
1476
1477 (merge variant 1)
1477 (merge variant 1)
1478
1478
1479 $ hg up 'desc("mAE-change-m")'
1479 $ hg up 'desc("mAE-change-m")'
1480 2 files updated, 0 files merged, 3 files removed, 0 files unresolved
1480 2 files updated, 0 files merged, 3 files removed, 0 files unresolved
1481 $ hg merge 'desc("k-1")'
1481 $ hg merge 'desc("k-1")'
1482 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1482 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1483 (branch merge, don't forget to commit)
1483 (branch merge, don't forget to commit)
1484 $ hg ci -m "mAE-change,Km: $case_desc"
1484 $ hg ci -m "mAE-change,Km: $case_desc"
1485
1485
1486 (merge variant 2)
1486 (merge variant 2)
1487
1487
1488 $ hg up 'desc("k-1")'
1488 $ hg up 'desc("k-1")'
1489 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
1489 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
1490
1490
1491 $ hg merge 'desc("mAE-change-m")'
1491 $ hg merge 'desc("mAE-change-m")'
1492 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
1492 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
1493 (branch merge, don't forget to commit)
1493 (branch merge, don't forget to commit)
1494 $ hg ci -m "mK,AE-change-m: $case_desc"
1494 $ hg ci -m "mK,AE-change-m: $case_desc"
1495 created new head
1495 created new head
1496
1496
1497 (merge variant 3)
1497 (merge variant 3)
1498
1498
1499 $ hg up 'desc("mEA-change-m")'
1499 $ hg up 'desc("mEA-change-m")'
1500 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
1500 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
1501 $ hg merge 'desc("j-1")'
1501 $ hg merge 'desc("j-1")'
1502 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1502 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
1503 (branch merge, don't forget to commit)
1503 (branch merge, don't forget to commit)
1504 $ hg ci -m "mEA-change,Jm: $case_desc"
1504 $ hg ci -m "mEA-change,Jm: $case_desc"
1505
1505
1506 (merge variant 4)
1506 (merge variant 4)
1507
1507
1508 $ hg up 'desc("j-1")'
1508 $ hg up 'desc("j-1")'
1509 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
1509 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
1510 $ hg merge 'desc("mEA-change-m")'
1510 $ hg merge 'desc("mEA-change-m")'
1511 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
1511 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
1512 (branch merge, don't forget to commit)
1512 (branch merge, don't forget to commit)
1513 $ hg ci -m "mJ,EA-change-m: $case_desc"
1513 $ hg ci -m "mJ,EA-change-m: $case_desc"
1514 created new head
1514 created new head
1515
1515
1516
1516
1517 $ hg log -G --rev '::(desc("mAE-change,Km") + desc("mK,AE-change-m") + desc("mEA-change,Jm") + desc("mJ,EA-change-m"))'
1517 $ hg log -G --rev '::(desc("mAE-change,Km") + desc("mK,AE-change-m") + desc("mEA-change,Jm") + desc("mJ,EA-change-m"))'
1518 @ mJ,EA-change-m: chained merges (conflict+change -> simple) - same content on both branch in the initial merge
1518 @ mJ,EA-change-m: chained merges (conflict+change -> simple) - same content on both branch in the initial merge
1519 |\
1519 |\
1520 +---o mEA-change,Jm: chained merges (conflict+change -> simple) - same content on both branch in the initial merge
1520 +---o mEA-change,Jm: chained merges (conflict+change -> simple) - same content on both branch in the initial merge
1521 | |/
1521 | |/
1522 | | o mK,AE-change-m: chained merges (conflict+change -> simple) - same content on both branch in the initial merge
1522 | | o mK,AE-change-m: chained merges (conflict+change -> simple) - same content on both branch in the initial merge
1523 | | |\
1523 | | |\
1524 | | +---o mAE-change,Km: chained merges (conflict+change -> simple) - same content on both branch in the initial merge
1524 | | +---o mAE-change,Km: chained merges (conflict+change -> simple) - same content on both branch in the initial merge
1525 | | | |/
1525 | | | |/
1526 | | | o k-1: unrelated changes (based on "e" changes)
1526 | | | o k-1: unrelated changes (based on "e" changes)
1527 | | | |
1527 | | | |
1528 | o | | j-1: unrelated changes (based on the "a" series of changes)
1528 | o | | j-1: unrelated changes (based on the "a" series of changes)
1529 | | | |
1529 | | | |
1530 o-----+ mEA-change-m-0 merge with file update and copies info on both side - A side: rename d to f, E side: b to f, (same content for f in parent) - the other way
1530 o-----+ mEA-change-m-0 merge with file update and copies info on both side - A side: rename d to f, E side: b to f, (same content for f in parent) - the other way
1531 |/ / /
1531 |/ / /
1532 | o / mAE-change-m-0 merge with file update and copies info on both side - A side: rename d to f, E side: b to f, (same content for f in parent) - one way
1532 | o / mAE-change-m-0 merge with file update and copies info on both side - A side: rename d to f, E side: b to f, (same content for f in parent) - one way
1533 |/|/
1533 |/|/
1534 | o e-2 g -move-> f
1534 | o e-2 g -move-> f
1535 | |
1535 | |
1536 | o e-1 b -move-> g
1536 | o e-1 b -move-> g
1537 | |
1537 | |
1538 o | a-2: e -move-> f
1538 o | a-2: e -move-> f
1539 | |
1539 | |
1540 o | a-1: d -move-> e
1540 o | a-1: d -move-> e
1541 |/
1541 |/
1542 o i-2: c -move-> d, s -move-> t
1542 o i-2: c -move-> d, s -move-> t
1543 |
1543 |
1544 o i-1: a -move-> c, p -move-> s
1544 o i-1: a -move-> c, p -move-> s
1545 |
1545 |
1546 o i-0 initial commit: a b h p q r
1546 o i-0 initial commit: a b h p q r
1547
1547
1548
1548
1549 Summary of all created cases
1549 Summary of all created cases
1550 ----------------------------
1550 ----------------------------
1551
1551
1552 $ hg up --quiet null
1552 $ hg up --quiet null
1553
1553
1554 (This exists to help keeping a compact list of the various cases we have built)
1554 (This exists to help keeping a compact list of the various cases we have built)
1555
1555
1556 $ hg log -T '{desc|firstline}\n'| sort
1556 $ hg log -T '{desc|firstline}\n'| sort
1557 a-1: d -move-> e
1557 a-1: d -move-> e
1558 a-2: e -move-> f
1558 a-2: e -move-> f
1559 b-1: b update
1559 b-1: b update
1560 c-1 delete d
1560 c-1 delete d
1561 d-1 delete d
1561 d-1 delete d
1562 d-2 re-add d
1562 d-2 re-add d
1563 e-1 b -move-> g
1563 e-1 b -move-> g
1564 e-2 g -move-> f
1564 e-2 g -move-> f
1565 f-1: rename h -> i
1565 f-1: rename h -> i
1566 f-2: rename i -> d
1566 f-2: rename i -> d
1567 g-1: update d
1567 g-1: update d
1568 h-1: b -(move)-> d
1568 h-1: b -(move)-> d
1569 i-0 initial commit: a b h p q r
1569 i-0 initial commit: a b h p q r
1570 i-1: a -move-> c, p -move-> s
1570 i-1: a -move-> c, p -move-> s
1571 i-2: c -move-> d, s -move-> t
1571 i-2: c -move-> d, s -move-> t
1572 j-1: unrelated changes (based on the "a" series of changes)
1572 j-1: unrelated changes (based on the "a" series of changes)
1573 k-1: unrelated changes (based on "e" changes)
1573 k-1: unrelated changes (based on "e" changes)
1574 l-1: unrelated changes (based on "c" changes)
1574 l-1: unrelated changes (based on "c" changes)
1575 mABm-0 simple merge - A side: multiple renames, B side: unrelated update - the other way
1575 mABm-0 simple merge - A side: multiple renames, B side: unrelated update - the other way
1576 mAE,Km: chained merges (conflict -> simple) - same content everywhere
1576 mAE,Km: chained merges (conflict -> simple) - same content everywhere
1577 mAE-change,Km: chained merges (conflict+change -> simple) - same content on both branch in the initial merge
1577 mAE-change,Km: chained merges (conflict+change -> simple) - same content on both branch in the initial merge
1578 mAE-change-m-0 merge with file update and copies info on both side - A side: rename d to f, E side: b to f, (same content for f in parent) - one way
1578 mAE-change-m-0 merge with file update and copies info on both side - A side: rename d to f, E side: b to f, (same content for f in parent) - one way
1579 mAEm-0 merge with copies info on both side - A side: rename d to f, E side: b to f, (same content for f) - one way
1579 mAEm-0 merge with copies info on both side - A side: rename d to f, E side: b to f, (same content for f) - one way
1580 mBAm-0 simple merge - A side: multiple renames, B side: unrelated update - one way
1580 mBAm-0 simple merge - A side: multiple renames, B side: unrelated update - one way
1581 mBC+revert,Lm: chained merges (salvaged -> simple) - same content (when the file exists)
1581 mBC+revert,Lm: chained merges (salvaged -> simple) - same content (when the file exists)
1582 mBC-change-m-0 merge explicitely revive deleted file - B side: unrelated change, C side: delete d (restored by merge) - the other way
1582 mBC-change-m-0 merge explicitely revive deleted file - B side: unrelated change, C side: delete d (restored by merge) - the other way
1583 mBC-revert-m-0 merge explicitely revive deleted file - B side: unrelated change, C side: delete d (restored by merge) - the other way
1583 mBC-revert-m-0 merge explicitely revive deleted file - B side: unrelated change, C side: delete d (restored by merge) - the other way
1584 mBCm-0 simple merge - C side: delete a file with copies history , B side: unrelated update - one way
1584 mBCm-0 simple merge - C side: delete a file with copies history , B side: unrelated update - one way
1585 mBCm-1 re-add d
1585 mBCm-1 re-add d
1586 mBDm-0 simple merge - B side: unrelated update, D side: delete and recreate a file (with different content) - one way
1586 mBDm-0 simple merge - B side: unrelated update, D side: delete and recreate a file (with different content) - one way
1587 mBF-change-m-0 merge with extra change - B side: unrelated change, F side: overwrite d with a copy (from h->i->d) - one way
1587 mBF-change-m-0 merge with extra change - B side: unrelated change, F side: overwrite d with a copy (from h->i->d) - one way
1588 mBFm-0 simple merge - B side: unrelated change, F side: overwrite d with a copy (from h->i->d) - one way
1588 mBFm-0 simple merge - B side: unrelated change, F side: overwrite d with a copy (from h->i->d) - one way
1589 mBRm-0 simple merge - B side: unrelated change, R side: overwrite d with a copy (from r->x->t) different content - one way
1589 mBRm-0 simple merge - B side: unrelated change, R side: overwrite d with a copy (from r->x->t) different content - one way
1590 mCB+revert,Lm: chained merges (salvaged -> simple) - same content (when the file exists)
1590 mCB+revert,Lm: chained merges (salvaged -> simple) - same content (when the file exists)
1591 mCB-change-m-0 merge explicitely revive deleted file - B side: unrelated change, C side: delete d (restored by merge) - one way
1591 mCB-change-m-0 merge explicitely revive deleted file - B side: unrelated change, C side: delete d (restored by merge) - one way
1592 mCB-revert-m-0 merge explicitely revive deleted file - B side: unrelated change, C side: delete d (restored by merge) - one way
1592 mCB-revert-m-0 merge explicitely revive deleted file - B side: unrelated change, C side: delete d (restored by merge) - one way
1593 mCBm-0 simple merge - C side: delete a file with copies history , B side: unrelated update - the other way
1593 mCBm-0 simple merge - C side: delete a file with copies history , B side: unrelated update - the other way
1594 mCBm-1 re-add d
1594 mCBm-1 re-add d
1595 mCGm-0 merge updated/deleted - revive the file (updated content) - one way
1595 mCGm-0 merge updated/deleted - revive the file (updated content) - one way
1596 mCH-delete-before-conflict-m-0 simple merge - C side: d is the results of renames then deleted, H side: d is result of another rename (same content as the other branch) - one way
1596 mCH-delete-before-conflict-m-0 simple merge - C side: d is the results of renames then deleted, H side: d is result of another rename (same content as the other branch) - one way
1597 mDBm-0 simple merge - B side: unrelated update, D side: delete and recreate a file (with different content) - the other way
1597 mDBm-0 simple merge - B side: unrelated update, D side: delete and recreate a file (with different content) - the other way
1598 mDGm-0 actual content merge, copies on one side - D side: delete and re-add (different content), G side: update content - one way
1598 mDGm-0 actual content merge, copies on one side - D side: delete and re-add (different content), G side: update content - one way
1599 mEA,Jm: chained merges (conflict -> simple) - same content everywhere
1599 mEA,Jm: chained merges (conflict -> simple) - same content everywhere
1600 mEA-change,Jm: chained merges (conflict+change -> simple) - same content on both branch in the initial merge
1600 mEA-change,Jm: chained merges (conflict+change -> simple) - same content on both branch in the initial merge
1601 mEA-change-m-0 merge with file update and copies info on both side - A side: rename d to f, E side: b to f, (same content for f in parent) - the other way
1601 mEA-change-m-0 merge with file update and copies info on both side - A side: rename d to f, E side: b to f, (same content for f in parent) - the other way
1602 mEAm-0 merge with copies info on both side - A side: rename d to f, E side: b to f, (same content for f) - the other way
1602 mEAm-0 merge with copies info on both side - A side: rename d to f, E side: b to f, (same content for f) - the other way
1603 mFB-change-m-0 merge with extra change - B side: unrelated change, F side: overwrite d with a copy (from h->i->d) - the other way
1603 mFB-change-m-0 merge with extra change - B side: unrelated change, F side: overwrite d with a copy (from h->i->d) - the other way
1604 mFBm-0 simple merge - B side: unrelated change, F side: overwrite d with a copy (from h->i->d) - the other way
1604 mFBm-0 simple merge - B side: unrelated change, F side: overwrite d with a copy (from h->i->d) - the other way
1605 mFG,Om: chained merges (copy-overwrite -> simple) - same content
1605 mFG,Om: chained merges (copy-overwrite -> simple) - same content
1606 mFGm-0 merge - G side: content change, F side: copy overwrite, no content change - one way
1606 mFGm-0 merge - G side: content change, F side: copy overwrite, no content change - one way
1607 mGCm-0 merge updated/deleted - revive the file (updated content) - the other way
1607 mGCm-0 merge updated/deleted - revive the file (updated content) - the other way
1608 mGDm-0 actual content merge, copies on one side - D side: delete and re-add (different content), G side: update content - the other way
1608 mGDm-0 actual content merge, copies on one side - D side: delete and re-add (different content), G side: update content - the other way
1609 mGF,Nm: chained merges (copy-overwrite -> simple) - same content
1609 mGF,Nm: chained merges (copy-overwrite -> simple) - same content
1610 mGFm-0 merge - G side: content change, F side: copy overwrite, no content change - the other way
1610 mGFm-0 merge - G side: content change, F side: copy overwrite, no content change - the other way
1611 mHC-delete-before-conflict-m-0 simple merge - C side: d is the results of renames then deleted, H side: d is result of another rename (same content as the other branch) - the other way
1611 mHC-delete-before-conflict-m-0 simple merge - C side: d is the results of renames then deleted, H side: d is result of another rename (same content as the other branch) - the other way
1612 mJ,EA-change-m: chained merges (conflict+change -> simple) - same content on both branch in the initial merge
1612 mJ,EA-change-m: chained merges (conflict+change -> simple) - same content on both branch in the initial merge
1613 mJ,EAm: chained merges (conflict -> simple) - same content everywhere
1613 mJ,EAm: chained merges (conflict -> simple) - same content everywhere
1614 mK,AE-change-m: chained merges (conflict+change -> simple) - same content on both branch in the initial merge
1614 mK,AE-change-m: chained merges (conflict+change -> simple) - same content on both branch in the initial merge
1615 mK,AEm: chained merges (conflict -> simple) - same content everywhere
1615 mK,AEm: chained merges (conflict -> simple) - same content everywhere
1616 mL,BC+revertm: chained merges (salvaged -> simple) - same content (when the file exists)
1616 mL,BC+revertm: chained merges (salvaged -> simple) - same content (when the file exists)
1617 mL,CB+revertm: chained merges (salvaged -> simple) - same content (when the file exists)
1617 mL,CB+revertm: chained merges (salvaged -> simple) - same content (when the file exists)
1618 mN,GFm: chained merges (copy-overwrite -> simple) - same content
1618 mN,GFm: chained merges (copy-overwrite -> simple) - same content
1619 mO,FGm: chained merges (copy-overwrite -> simple) - same content
1619 mO,FGm: chained merges (copy-overwrite -> simple) - same content
1620 mPQ,Tm: chained merges (conflict -> simple) - different content
1620 mPQ,Tm: chained merges (conflict -> simple) - different content
1621 mPQm-0 merge with copies info on both side - P side: rename t to v, Q side: r to v, (different content) - one way
1621 mPQm-0 merge with copies info on both side - P side: rename t to v, Q side: r to v, (different content) - one way
1622 mQP,Sm: chained merges (conflict -> simple) - different content
1622 mQP,Sm: chained merges (conflict -> simple) - different content
1623 mQPm-0 merge with copies info on both side - P side: rename t to v, Q side: r to v, (different content) - the other way
1623 mQPm-0 merge with copies info on both side - P side: rename t to v, Q side: r to v, (different content) - the other way
1624 mRBm-0 simple merge - B side: unrelated change, R side: overwrite d with a copy (from r->x->t) different content - the other way
1624 mRBm-0 simple merge - B side: unrelated change, R side: overwrite d with a copy (from r->x->t) different content - the other way
1625 mS,QPm: chained merges (conflict -> simple) - different content
1625 mS,QPm: chained merges (conflict -> simple) - different content
1626 mT,PQm: chained merges (conflict -> simple) - different content
1626 mT,PQm: chained merges (conflict -> simple) - different content
1627 n-1: unrelated changes (based on the "f" series of changes)
1627 n-1: unrelated changes (based on the "f" series of changes)
1628 o-1: unrelated changes (based on "g" changes)
1628 o-1: unrelated changes (based on "g" changes)
1629 p-1: t -move-> u
1629 p-1: t -move-> u
1630 p-2: u -move-> v
1630 p-2: u -move-> v
1631 q-1 r -move-> w
1631 q-1 r -move-> w
1632 q-2 w -move-> v
1632 q-2 w -move-> v
1633 r-1: rename r -> x
1633 r-1: rename r -> x
1634 r-2: rename t -> x
1634 r-2: rename t -> x
1635 s-1: unrelated changes (based on the "p" series of changes)
1635 s-1: unrelated changes (based on the "p" series of changes)
1636 t-1: unrelated changes (based on "q" changes)
1636 t-1: unrelated changes (based on "q" changes)
1637
1637
1638
1638
1639 Test that sidedata computations during upgrades are correct
1639 Test that sidedata computations during upgrades are correct
1640 ===========================================================
1640 ===========================================================
1641
1641
1642 We upgrade a repository that is not using sidedata (the filelog case) and
1642 We upgrade a repository that is not using sidedata (the filelog case) and
1643 check that the same side data have been generated as if they were computed at
1643 check that the same side data have been generated as if they were computed at
1644 commit time.
1644 commit time.
1645
1645
1646
1646
1647 #if upgraded
1647 #if upgraded
1648 $ cat >> $HGRCPATH << EOF
1648 $ cat >> $HGRCPATH << EOF
1649 > [format]
1649 > [format]
1650 > exp-use-copies-side-data-changeset = yes
1650 > exp-use-copies-side-data-changeset = yes
1651 > EOF
1651 > EOF
1652 $ hg debugformat -v
1652 $ hg debugformat -v
1653 format-variant repo config default
1653 format-variant repo config default
1654 fncache: yes yes yes
1654 fncache: yes yes yes
1655 dirstate-v2: no no no
1655 dotencode: yes yes yes
1656 dotencode: yes yes yes
1656 generaldelta: yes yes yes
1657 generaldelta: yes yes yes
1657 share-safe: no no no
1658 share-safe: no no no
1658 sparserevlog: yes yes yes
1659 sparserevlog: yes yes yes
1659 persistent-nodemap: no no no (no-rust !)
1660 persistent-nodemap: no no no (no-rust !)
1660 persistent-nodemap: yes yes no (rust !)
1661 persistent-nodemap: yes yes no (rust !)
1661 copies-sdc: no yes no
1662 copies-sdc: no yes no
1662 revlog-v2: no no no
1663 revlog-v2: no no no
1663 changelog-v2: no yes no
1664 changelog-v2: no yes no
1664 plain-cl-delta: yes yes yes
1665 plain-cl-delta: yes yes yes
1665 compression: * (glob)
1666 compression: * (glob)
1666 compression-level: default default default
1667 compression-level: default default default
1667 $ hg debugupgraderepo --run --quiet
1668 $ hg debugupgraderepo --run --quiet
1668 upgrade will perform the following actions:
1669 upgrade will perform the following actions:
1669
1670
1670 requirements
1671 requirements
1671 preserved: * (glob)
1672 preserved: * (glob)
1672 added: exp-changelog-v2, exp-copies-sidedata-changeset
1673 added: exp-changelog-v2, exp-copies-sidedata-changeset
1673
1674
1674 processed revlogs:
1675 processed revlogs:
1675 - all-filelogs
1676 - all-filelogs
1676 - changelog
1677 - changelog
1677 - manifest
1678 - manifest
1678
1679
1679 #endif
1680 #endif
1680
1681
1681 #if upgraded-parallel
1682 #if upgraded-parallel
1682 $ cat >> $HGRCPATH << EOF
1683 $ cat >> $HGRCPATH << EOF
1683 > [format]
1684 > [format]
1684 > exp-use-copies-side-data-changeset = yes
1685 > exp-use-copies-side-data-changeset = yes
1685 > [experimental]
1686 > [experimental]
1686 > worker.repository-upgrade=yes
1687 > worker.repository-upgrade=yes
1687 > [worker]
1688 > [worker]
1688 > enabled=yes
1689 > enabled=yes
1689 > numcpus=8
1690 > numcpus=8
1690 > EOF
1691 > EOF
1691 $ hg debugformat -v
1692 $ hg debugformat -v
1692 format-variant repo config default
1693 format-variant repo config default
1693 fncache: yes yes yes
1694 fncache: yes yes yes
1695 dirstate-v2: no no no
1694 dotencode: yes yes yes
1696 dotencode: yes yes yes
1695 generaldelta: yes yes yes
1697 generaldelta: yes yes yes
1696 share-safe: no no no
1698 share-safe: no no no
1697 sparserevlog: yes yes yes
1699 sparserevlog: yes yes yes
1698 persistent-nodemap: no no no (no-rust !)
1700 persistent-nodemap: no no no (no-rust !)
1699 persistent-nodemap: yes yes no (rust !)
1701 persistent-nodemap: yes yes no (rust !)
1700 copies-sdc: no yes no
1702 copies-sdc: no yes no
1701 revlog-v2: no no no
1703 revlog-v2: no no no
1702 changelog-v2: no yes no
1704 changelog-v2: no yes no
1703 plain-cl-delta: yes yes yes
1705 plain-cl-delta: yes yes yes
1704 compression: * (glob)
1706 compression: * (glob)
1705 compression-level: default default default
1707 compression-level: default default default
1706 $ hg debugupgraderepo --run --quiet
1708 $ hg debugupgraderepo --run --quiet
1707 upgrade will perform the following actions:
1709 upgrade will perform the following actions:
1708
1710
1709 requirements
1711 requirements
1710 preserved: * (glob)
1712 preserved: * (glob)
1711 added: exp-changelog-v2, exp-copies-sidedata-changeset
1713 added: exp-changelog-v2, exp-copies-sidedata-changeset
1712
1714
1713 processed revlogs:
1715 processed revlogs:
1714 - all-filelogs
1716 - all-filelogs
1715 - changelog
1717 - changelog
1716 - manifest
1718 - manifest
1717
1719
1718 #endif
1720 #endif
1719
1721
1720 #if pull
1722 #if pull
1721 $ cd ..
1723 $ cd ..
1722 $ mv repo-chain repo-source
1724 $ mv repo-chain repo-source
1723 $ hg init repo-chain
1725 $ hg init repo-chain
1724 $ cd repo-chain
1726 $ cd repo-chain
1725 $ hg pull ../repo-source
1727 $ hg pull ../repo-source
1726 pulling from ../repo-source
1728 pulling from ../repo-source
1727 requesting all changes
1729 requesting all changes
1728 adding changesets
1730 adding changesets
1729 adding manifests
1731 adding manifests
1730 adding file changes
1732 adding file changes
1731 added 80 changesets with 44 changes to 25 files (+39 heads)
1733 added 80 changesets with 44 changes to 25 files (+39 heads)
1732 new changesets a3a31bbefea6:908ce9259ffa
1734 new changesets a3a31bbefea6:908ce9259ffa
1733 (run 'hg heads' to see heads, 'hg merge' to merge)
1735 (run 'hg heads' to see heads, 'hg merge' to merge)
1734 #endif
1736 #endif
1735
1737
1736 #if pull-upgrade
1738 #if pull-upgrade
1737 $ cat >> $HGRCPATH << EOF
1739 $ cat >> $HGRCPATH << EOF
1738 > [format]
1740 > [format]
1739 > exp-use-copies-side-data-changeset = yes
1741 > exp-use-copies-side-data-changeset = yes
1740 > [experimental]
1742 > [experimental]
1741 > changegroup4 = yes
1743 > changegroup4 = yes
1742 > EOF
1744 > EOF
1743 $ cd ..
1745 $ cd ..
1744 $ mv repo-chain repo-source
1746 $ mv repo-chain repo-source
1745 $ hg init repo-chain
1747 $ hg init repo-chain
1746 $ cd repo-chain
1748 $ cd repo-chain
1747 $ hg pull ../repo-source
1749 $ hg pull ../repo-source
1748 pulling from ../repo-source
1750 pulling from ../repo-source
1749 requesting all changes
1751 requesting all changes
1750 adding changesets
1752 adding changesets
1751 adding manifests
1753 adding manifests
1752 adding file changes
1754 adding file changes
1753 added 80 changesets with 44 changes to 25 files (+39 heads)
1755 added 80 changesets with 44 changes to 25 files (+39 heads)
1754 new changesets a3a31bbefea6:908ce9259ffa
1756 new changesets a3a31bbefea6:908ce9259ffa
1755 (run 'hg heads' to see heads, 'hg merge' to merge)
1757 (run 'hg heads' to see heads, 'hg merge' to merge)
1756 #endif
1758 #endif
1757
1759
1758 #if push
1760 #if push
1759 $ cd ..
1761 $ cd ..
1760 $ mv repo-chain repo-source
1762 $ mv repo-chain repo-source
1761 $ hg init repo-chain
1763 $ hg init repo-chain
1762 $ cd repo-source
1764 $ cd repo-source
1763 $ hg push ../repo-chain
1765 $ hg push ../repo-chain
1764 pushing to ../repo-chain
1766 pushing to ../repo-chain
1765 searching for changes
1767 searching for changes
1766 adding changesets
1768 adding changesets
1767 adding manifests
1769 adding manifests
1768 adding file changes
1770 adding file changes
1769 added 80 changesets with 44 changes to 25 files (+39 heads)
1771 added 80 changesets with 44 changes to 25 files (+39 heads)
1770 $ cd ../repo-chain
1772 $ cd ../repo-chain
1771 #endif
1773 #endif
1772
1774
1773 #if push-upgrade
1775 #if push-upgrade
1774 $ cat >> $HGRCPATH << EOF
1776 $ cat >> $HGRCPATH << EOF
1775 > [format]
1777 > [format]
1776 > exp-use-copies-side-data-changeset = yes
1778 > exp-use-copies-side-data-changeset = yes
1777 > [experimental]
1779 > [experimental]
1778 > changegroup4 = yes
1780 > changegroup4 = yes
1779 > EOF
1781 > EOF
1780 $ cd ..
1782 $ cd ..
1781 $ mv repo-chain repo-source
1783 $ mv repo-chain repo-source
1782 $ hg init repo-chain
1784 $ hg init repo-chain
1783 $ cd repo-source
1785 $ cd repo-source
1784 $ hg push ../repo-chain
1786 $ hg push ../repo-chain
1785 pushing to ../repo-chain
1787 pushing to ../repo-chain
1786 searching for changes
1788 searching for changes
1787 adding changesets
1789 adding changesets
1788 adding manifests
1790 adding manifests
1789 adding file changes
1791 adding file changes
1790 added 80 changesets with 44 changes to 25 files (+39 heads)
1792 added 80 changesets with 44 changes to 25 files (+39 heads)
1791 $ cd ../repo-chain
1793 $ cd ../repo-chain
1792 #endif
1794 #endif
1793
1795
1794 #if no-compatibility no-filelog no-changeset
1796 #if no-compatibility no-filelog no-changeset
1795
1797
1796 $ hg debugchangedfiles --compute 0
1798 $ hg debugchangedfiles --compute 0
1797 added : a, ;
1799 added : a, ;
1798 added : b, ;
1800 added : b, ;
1799 added : h, ;
1801 added : h, ;
1800 added : p, ;
1802 added : p, ;
1801 added : q, ;
1803 added : q, ;
1802 added : r, ;
1804 added : r, ;
1803
1805
1804 $ for rev in `hg log --rev 'all()' -T '{rev}\n'`; do
1806 $ for rev in `hg log --rev 'all()' -T '{rev}\n'`; do
1805 > case_id=`hg log -r $rev -T '{word(0, desc, ":")}\n'`
1807 > case_id=`hg log -r $rev -T '{word(0, desc, ":")}\n'`
1806 > echo "##### revision \"$case_id\" #####"
1808 > echo "##### revision \"$case_id\" #####"
1807 > hg debugsidedata -c -v -- $rev
1809 > hg debugsidedata -c -v -- $rev
1808 > hg debugchangedfiles $rev
1810 > hg debugchangedfiles $rev
1809 > done
1811 > done
1810 ##### revision "i-0 initial commit" #####
1812 ##### revision "i-0 initial commit" #####
1811 1 sidedata entries
1813 1 sidedata entries
1812 entry-0014 size 64
1814 entry-0014 size 64
1813 '\x00\x00\x00\x06\x04\x00\x00\x00\x01\x00\x00\x00\x00\x04\x00\x00\x00\x02\x00\x00\x00\x00\x04\x00\x00\x00\x03\x00\x00\x00\x00\x04\x00\x00\x00\x04\x00\x00\x00\x00\x04\x00\x00\x00\x05\x00\x00\x00\x00\x04\x00\x00\x00\x06\x00\x00\x00\x00abhpqr'
1815 '\x00\x00\x00\x06\x04\x00\x00\x00\x01\x00\x00\x00\x00\x04\x00\x00\x00\x02\x00\x00\x00\x00\x04\x00\x00\x00\x03\x00\x00\x00\x00\x04\x00\x00\x00\x04\x00\x00\x00\x00\x04\x00\x00\x00\x05\x00\x00\x00\x00\x04\x00\x00\x00\x06\x00\x00\x00\x00abhpqr'
1814 added : a, ;
1816 added : a, ;
1815 added : b, ;
1817 added : b, ;
1816 added : h, ;
1818 added : h, ;
1817 added : p, ;
1819 added : p, ;
1818 added : q, ;
1820 added : q, ;
1819 added : r, ;
1821 added : r, ;
1820 ##### revision "i-1" #####
1822 ##### revision "i-1" #####
1821 1 sidedata entries
1823 1 sidedata entries
1822 entry-0014 size 44
1824 entry-0014 size 44
1823 '\x00\x00\x00\x04\x0c\x00\x00\x00\x01\x00\x00\x00\x00\x06\x00\x00\x00\x02\x00\x00\x00\x00\x0c\x00\x00\x00\x03\x00\x00\x00\x00\x06\x00\x00\x00\x04\x00\x00\x00\x02acps'
1825 '\x00\x00\x00\x04\x0c\x00\x00\x00\x01\x00\x00\x00\x00\x06\x00\x00\x00\x02\x00\x00\x00\x00\x0c\x00\x00\x00\x03\x00\x00\x00\x00\x06\x00\x00\x00\x04\x00\x00\x00\x02acps'
1824 removed : a, ;
1826 removed : a, ;
1825 added p1: c, a;
1827 added p1: c, a;
1826 removed : p, ;
1828 removed : p, ;
1827 added p1: s, p;
1829 added p1: s, p;
1828 ##### revision "i-2" #####
1830 ##### revision "i-2" #####
1829 1 sidedata entries
1831 1 sidedata entries
1830 entry-0014 size 44
1832 entry-0014 size 44
1831 '\x00\x00\x00\x04\x0c\x00\x00\x00\x01\x00\x00\x00\x00\x06\x00\x00\x00\x02\x00\x00\x00\x00\x0c\x00\x00\x00\x03\x00\x00\x00\x00\x06\x00\x00\x00\x04\x00\x00\x00\x02cdst'
1833 '\x00\x00\x00\x04\x0c\x00\x00\x00\x01\x00\x00\x00\x00\x06\x00\x00\x00\x02\x00\x00\x00\x00\x0c\x00\x00\x00\x03\x00\x00\x00\x00\x06\x00\x00\x00\x04\x00\x00\x00\x02cdst'
1832 removed : c, ;
1834 removed : c, ;
1833 added p1: d, c;
1835 added p1: d, c;
1834 removed : s, ;
1836 removed : s, ;
1835 added p1: t, s;
1837 added p1: t, s;
1836 ##### revision "a-1" #####
1838 ##### revision "a-1" #####
1837 1 sidedata entries
1839 1 sidedata entries
1838 entry-0014 size 24
1840 entry-0014 size 24
1839 '\x00\x00\x00\x02\x0c\x00\x00\x00\x01\x00\x00\x00\x00\x06\x00\x00\x00\x02\x00\x00\x00\x00de'
1841 '\x00\x00\x00\x02\x0c\x00\x00\x00\x01\x00\x00\x00\x00\x06\x00\x00\x00\x02\x00\x00\x00\x00de'
1840 removed : d, ;
1842 removed : d, ;
1841 added p1: e, d;
1843 added p1: e, d;
1842 ##### revision "a-2" #####
1844 ##### revision "a-2" #####
1843 1 sidedata entries
1845 1 sidedata entries
1844 entry-0014 size 24
1846 entry-0014 size 24
1845 '\x00\x00\x00\x02\x0c\x00\x00\x00\x01\x00\x00\x00\x00\x06\x00\x00\x00\x02\x00\x00\x00\x00ef'
1847 '\x00\x00\x00\x02\x0c\x00\x00\x00\x01\x00\x00\x00\x00\x06\x00\x00\x00\x02\x00\x00\x00\x00ef'
1846 removed : e, ;
1848 removed : e, ;
1847 added p1: f, e;
1849 added p1: f, e;
1848 ##### revision "b-1" #####
1850 ##### revision "b-1" #####
1849 1 sidedata entries
1851 1 sidedata entries
1850 entry-0014 size 14
1852 entry-0014 size 14
1851 '\x00\x00\x00\x01\x14\x00\x00\x00\x01\x00\x00\x00\x00b'
1853 '\x00\x00\x00\x01\x14\x00\x00\x00\x01\x00\x00\x00\x00b'
1852 touched : b, ;
1854 touched : b, ;
1853 ##### revision "c-1 delete d" #####
1855 ##### revision "c-1 delete d" #####
1854 1 sidedata entries
1856 1 sidedata entries
1855 entry-0014 size 14
1857 entry-0014 size 14
1856 '\x00\x00\x00\x01\x0c\x00\x00\x00\x01\x00\x00\x00\x00d'
1858 '\x00\x00\x00\x01\x0c\x00\x00\x00\x01\x00\x00\x00\x00d'
1857 removed : d, ;
1859 removed : d, ;
1858 ##### revision "d-1 delete d" #####
1860 ##### revision "d-1 delete d" #####
1859 1 sidedata entries
1861 1 sidedata entries
1860 entry-0014 size 14
1862 entry-0014 size 14
1861 '\x00\x00\x00\x01\x0c\x00\x00\x00\x01\x00\x00\x00\x00d'
1863 '\x00\x00\x00\x01\x0c\x00\x00\x00\x01\x00\x00\x00\x00d'
1862 removed : d, ;
1864 removed : d, ;
1863 ##### revision "d-2 re-add d" #####
1865 ##### revision "d-2 re-add d" #####
1864 1 sidedata entries
1866 1 sidedata entries
1865 entry-0014 size 14
1867 entry-0014 size 14
1866 '\x00\x00\x00\x01\x04\x00\x00\x00\x01\x00\x00\x00\x00d'
1868 '\x00\x00\x00\x01\x04\x00\x00\x00\x01\x00\x00\x00\x00d'
1867 added : d, ;
1869 added : d, ;
1868 ##### revision "e-1 b -move-> g" #####
1870 ##### revision "e-1 b -move-> g" #####
1869 1 sidedata entries
1871 1 sidedata entries
1870 entry-0014 size 24
1872 entry-0014 size 24
1871 '\x00\x00\x00\x02\x0c\x00\x00\x00\x01\x00\x00\x00\x00\x06\x00\x00\x00\x02\x00\x00\x00\x00bg'
1873 '\x00\x00\x00\x02\x0c\x00\x00\x00\x01\x00\x00\x00\x00\x06\x00\x00\x00\x02\x00\x00\x00\x00bg'
1872 removed : b, ;
1874 removed : b, ;
1873 added p1: g, b;
1875 added p1: g, b;
1874 ##### revision "e-2 g -move-> f" #####
1876 ##### revision "e-2 g -move-> f" #####
1875 1 sidedata entries
1877 1 sidedata entries
1876 entry-0014 size 24
1878 entry-0014 size 24
1877 '\x00\x00\x00\x02\x06\x00\x00\x00\x01\x00\x00\x00\x01\x0c\x00\x00\x00\x02\x00\x00\x00\x00fg'
1879 '\x00\x00\x00\x02\x06\x00\x00\x00\x01\x00\x00\x00\x01\x0c\x00\x00\x00\x02\x00\x00\x00\x00fg'
1878 added p1: f, g;
1880 added p1: f, g;
1879 removed : g, ;
1881 removed : g, ;
1880 ##### revision "p-1" #####
1882 ##### revision "p-1" #####
1881 1 sidedata entries
1883 1 sidedata entries
1882 entry-0014 size 24
1884 entry-0014 size 24
1883 '\x00\x00\x00\x02\x0c\x00\x00\x00\x01\x00\x00\x00\x00\x06\x00\x00\x00\x02\x00\x00\x00\x00tu'
1885 '\x00\x00\x00\x02\x0c\x00\x00\x00\x01\x00\x00\x00\x00\x06\x00\x00\x00\x02\x00\x00\x00\x00tu'
1884 removed : t, ;
1886 removed : t, ;
1885 added p1: u, t;
1887 added p1: u, t;
1886 ##### revision "p-2" #####
1888 ##### revision "p-2" #####
1887 1 sidedata entries
1889 1 sidedata entries
1888 entry-0014 size 24
1890 entry-0014 size 24
1889 '\x00\x00\x00\x02\x0c\x00\x00\x00\x01\x00\x00\x00\x00\x06\x00\x00\x00\x02\x00\x00\x00\x00uv'
1891 '\x00\x00\x00\x02\x0c\x00\x00\x00\x01\x00\x00\x00\x00\x06\x00\x00\x00\x02\x00\x00\x00\x00uv'
1890 removed : u, ;
1892 removed : u, ;
1891 added p1: v, u;
1893 added p1: v, u;
1892 ##### revision "q-1 r -move-> w" #####
1894 ##### revision "q-1 r -move-> w" #####
1893 1 sidedata entries
1895 1 sidedata entries
1894 entry-0014 size 24
1896 entry-0014 size 24
1895 '\x00\x00\x00\x02\x0c\x00\x00\x00\x01\x00\x00\x00\x00\x06\x00\x00\x00\x02\x00\x00\x00\x00rw'
1897 '\x00\x00\x00\x02\x0c\x00\x00\x00\x01\x00\x00\x00\x00\x06\x00\x00\x00\x02\x00\x00\x00\x00rw'
1896 removed : r, ;
1898 removed : r, ;
1897 added p1: w, r;
1899 added p1: w, r;
1898 ##### revision "q-2 w -move-> v" #####
1900 ##### revision "q-2 w -move-> v" #####
1899 1 sidedata entries
1901 1 sidedata entries
1900 entry-0014 size 24
1902 entry-0014 size 24
1901 '\x00\x00\x00\x02\x06\x00\x00\x00\x01\x00\x00\x00\x01\x0c\x00\x00\x00\x02\x00\x00\x00\x00vw'
1903 '\x00\x00\x00\x02\x06\x00\x00\x00\x01\x00\x00\x00\x01\x0c\x00\x00\x00\x02\x00\x00\x00\x00vw'
1902 added p1: v, w;
1904 added p1: v, w;
1903 removed : w, ;
1905 removed : w, ;
1904 ##### revision "mBAm-0 simple merge - A side" #####
1906 ##### revision "mBAm-0 simple merge - A side" #####
1905 1 sidedata entries
1907 1 sidedata entries
1906 entry-0014 size 4
1908 entry-0014 size 4
1907 '\x00\x00\x00\x00'
1909 '\x00\x00\x00\x00'
1908 ##### revision "mABm-0 simple merge - A side" #####
1910 ##### revision "mABm-0 simple merge - A side" #####
1909 1 sidedata entries
1911 1 sidedata entries
1910 entry-0014 size 4
1912 entry-0014 size 4
1911 '\x00\x00\x00\x00'
1913 '\x00\x00\x00\x00'
1912 ##### revision "mBCm-0 simple merge - C side" #####
1914 ##### revision "mBCm-0 simple merge - C side" #####
1913 1 sidedata entries
1915 1 sidedata entries
1914 entry-0014 size 4
1916 entry-0014 size 4
1915 '\x00\x00\x00\x00'
1917 '\x00\x00\x00\x00'
1916 ##### revision "mBCm-1 re-add d" #####
1918 ##### revision "mBCm-1 re-add d" #####
1917 1 sidedata entries
1919 1 sidedata entries
1918 entry-0014 size 14
1920 entry-0014 size 14
1919 '\x00\x00\x00\x01\x04\x00\x00\x00\x01\x00\x00\x00\x00d'
1921 '\x00\x00\x00\x01\x04\x00\x00\x00\x01\x00\x00\x00\x00d'
1920 added : d, ;
1922 added : d, ;
1921 ##### revision "mCBm-0 simple merge - C side" #####
1923 ##### revision "mCBm-0 simple merge - C side" #####
1922 1 sidedata entries
1924 1 sidedata entries
1923 entry-0014 size 4
1925 entry-0014 size 4
1924 '\x00\x00\x00\x00'
1926 '\x00\x00\x00\x00'
1925 ##### revision "mCBm-1 re-add d" #####
1927 ##### revision "mCBm-1 re-add d" #####
1926 1 sidedata entries
1928 1 sidedata entries
1927 entry-0014 size 14
1929 entry-0014 size 14
1928 '\x00\x00\x00\x01\x04\x00\x00\x00\x01\x00\x00\x00\x00d'
1930 '\x00\x00\x00\x01\x04\x00\x00\x00\x01\x00\x00\x00\x00d'
1929 added : d, ;
1931 added : d, ;
1930 ##### revision "mBDm-0 simple merge - B side" #####
1932 ##### revision "mBDm-0 simple merge - B side" #####
1931 1 sidedata entries
1933 1 sidedata entries
1932 entry-0014 size 4
1934 entry-0014 size 4
1933 '\x00\x00\x00\x00'
1935 '\x00\x00\x00\x00'
1934 ##### revision "mDBm-0 simple merge - B side" #####
1936 ##### revision "mDBm-0 simple merge - B side" #####
1935 1 sidedata entries
1937 1 sidedata entries
1936 entry-0014 size 4
1938 entry-0014 size 4
1937 '\x00\x00\x00\x00'
1939 '\x00\x00\x00\x00'
1938 ##### revision "mAEm-0 merge with copies info on both side - A side" #####
1940 ##### revision "mAEm-0 merge with copies info on both side - A side" #####
1939 1 sidedata entries
1941 1 sidedata entries
1940 entry-0014 size 14
1942 entry-0014 size 14
1941 '\x00\x00\x00\x01\x08\x00\x00\x00\x01\x00\x00\x00\x00f'
1943 '\x00\x00\x00\x01\x08\x00\x00\x00\x01\x00\x00\x00\x00f'
1942 merged : f, ;
1944 merged : f, ;
1943 ##### revision "mEAm-0 merge with copies info on both side - A side" #####
1945 ##### revision "mEAm-0 merge with copies info on both side - A side" #####
1944 1 sidedata entries
1946 1 sidedata entries
1945 entry-0014 size 14
1947 entry-0014 size 14
1946 '\x00\x00\x00\x01\x08\x00\x00\x00\x01\x00\x00\x00\x00f'
1948 '\x00\x00\x00\x01\x08\x00\x00\x00\x01\x00\x00\x00\x00f'
1947 merged : f, ;
1949 merged : f, ;
1948 ##### revision "mPQm-0 merge with copies info on both side - P side" #####
1950 ##### revision "mPQm-0 merge with copies info on both side - P side" #####
1949 1 sidedata entries
1951 1 sidedata entries
1950 entry-0014 size 14
1952 entry-0014 size 14
1951 '\x00\x00\x00\x01\x08\x00\x00\x00\x01\x00\x00\x00\x00v'
1953 '\x00\x00\x00\x01\x08\x00\x00\x00\x01\x00\x00\x00\x00v'
1952 merged : v, ;
1954 merged : v, ;
1953 ##### revision "mQPm-0 merge with copies info on both side - P side" #####
1955 ##### revision "mQPm-0 merge with copies info on both side - P side" #####
1954 1 sidedata entries
1956 1 sidedata entries
1955 entry-0014 size 14
1957 entry-0014 size 14
1956 '\x00\x00\x00\x01\x08\x00\x00\x00\x01\x00\x00\x00\x00v'
1958 '\x00\x00\x00\x01\x08\x00\x00\x00\x01\x00\x00\x00\x00v'
1957 merged : v, ;
1959 merged : v, ;
1958 ##### revision "f-1" #####
1960 ##### revision "f-1" #####
1959 1 sidedata entries
1961 1 sidedata entries
1960 entry-0014 size 24
1962 entry-0014 size 24
1961 '\x00\x00\x00\x02\x0c\x00\x00\x00\x01\x00\x00\x00\x00\x06\x00\x00\x00\x02\x00\x00\x00\x00hi'
1963 '\x00\x00\x00\x02\x0c\x00\x00\x00\x01\x00\x00\x00\x00\x06\x00\x00\x00\x02\x00\x00\x00\x00hi'
1962 removed : h, ;
1964 removed : h, ;
1963 added p1: i, h;
1965 added p1: i, h;
1964 ##### revision "f-2" #####
1966 ##### revision "f-2" #####
1965 1 sidedata entries
1967 1 sidedata entries
1966 entry-0014 size 24
1968 entry-0014 size 24
1967 '\x00\x00\x00\x02\x16\x00\x00\x00\x01\x00\x00\x00\x01\x0c\x00\x00\x00\x02\x00\x00\x00\x00di'
1969 '\x00\x00\x00\x02\x16\x00\x00\x00\x01\x00\x00\x00\x01\x0c\x00\x00\x00\x02\x00\x00\x00\x00di'
1968 touched p1: d, i;
1970 touched p1: d, i;
1969 removed : i, ;
1971 removed : i, ;
1970 ##### revision "mBFm-0 simple merge - B side" #####
1972 ##### revision "mBFm-0 simple merge - B side" #####
1971 1 sidedata entries
1973 1 sidedata entries
1972 entry-0014 size 4
1974 entry-0014 size 4
1973 '\x00\x00\x00\x00'
1975 '\x00\x00\x00\x00'
1974 ##### revision "mFBm-0 simple merge - B side" #####
1976 ##### revision "mFBm-0 simple merge - B side" #####
1975 1 sidedata entries
1977 1 sidedata entries
1976 entry-0014 size 4
1978 entry-0014 size 4
1977 '\x00\x00\x00\x00'
1979 '\x00\x00\x00\x00'
1978 ##### revision "r-1" #####
1980 ##### revision "r-1" #####
1979 1 sidedata entries
1981 1 sidedata entries
1980 entry-0014 size 24
1982 entry-0014 size 24
1981 '\x00\x00\x00\x02\x0c\x00\x00\x00\x01\x00\x00\x00\x00\x06\x00\x00\x00\x02\x00\x00\x00\x00rx'
1983 '\x00\x00\x00\x02\x0c\x00\x00\x00\x01\x00\x00\x00\x00\x06\x00\x00\x00\x02\x00\x00\x00\x00rx'
1982 removed : r, ;
1984 removed : r, ;
1983 added p1: x, r;
1985 added p1: x, r;
1984 ##### revision "r-2" #####
1986 ##### revision "r-2" #####
1985 1 sidedata entries
1987 1 sidedata entries
1986 entry-0014 size 24
1988 entry-0014 size 24
1987 '\x00\x00\x00\x02\x16\x00\x00\x00\x01\x00\x00\x00\x01\x0c\x00\x00\x00\x02\x00\x00\x00\x00tx'
1989 '\x00\x00\x00\x02\x16\x00\x00\x00\x01\x00\x00\x00\x01\x0c\x00\x00\x00\x02\x00\x00\x00\x00tx'
1988 touched p1: t, x;
1990 touched p1: t, x;
1989 removed : x, ;
1991 removed : x, ;
1990 ##### revision "mBRm-0 simple merge - B side" #####
1992 ##### revision "mBRm-0 simple merge - B side" #####
1991 1 sidedata entries
1993 1 sidedata entries
1992 entry-0014 size 4
1994 entry-0014 size 4
1993 '\x00\x00\x00\x00'
1995 '\x00\x00\x00\x00'
1994 ##### revision "mRBm-0 simple merge - B side" #####
1996 ##### revision "mRBm-0 simple merge - B side" #####
1995 1 sidedata entries
1997 1 sidedata entries
1996 entry-0014 size 4
1998 entry-0014 size 4
1997 '\x00\x00\x00\x00'
1999 '\x00\x00\x00\x00'
1998 ##### revision "g-1" #####
2000 ##### revision "g-1" #####
1999 1 sidedata entries
2001 1 sidedata entries
2000 entry-0014 size 14
2002 entry-0014 size 14
2001 '\x00\x00\x00\x01\x14\x00\x00\x00\x01\x00\x00\x00\x00d'
2003 '\x00\x00\x00\x01\x14\x00\x00\x00\x01\x00\x00\x00\x00d'
2002 touched : d, ;
2004 touched : d, ;
2003 ##### revision "mDGm-0 actual content merge, copies on one side - D side" #####
2005 ##### revision "mDGm-0 actual content merge, copies on one side - D side" #####
2004 1 sidedata entries
2006 1 sidedata entries
2005 entry-0014 size 14
2007 entry-0014 size 14
2006 '\x00\x00\x00\x01\x08\x00\x00\x00\x01\x00\x00\x00\x00d'
2008 '\x00\x00\x00\x01\x08\x00\x00\x00\x01\x00\x00\x00\x00d'
2007 merged : d, ;
2009 merged : d, ;
2008 ##### revision "mGDm-0 actual content merge, copies on one side - D side" #####
2010 ##### revision "mGDm-0 actual content merge, copies on one side - D side" #####
2009 1 sidedata entries
2011 1 sidedata entries
2010 entry-0014 size 14
2012 entry-0014 size 14
2011 '\x00\x00\x00\x01\x08\x00\x00\x00\x01\x00\x00\x00\x00d'
2013 '\x00\x00\x00\x01\x08\x00\x00\x00\x01\x00\x00\x00\x00d'
2012 merged : d, ;
2014 merged : d, ;
2013 ##### revision "mFGm-0 merge - G side" #####
2015 ##### revision "mFGm-0 merge - G side" #####
2014 1 sidedata entries
2016 1 sidedata entries
2015 entry-0014 size 14
2017 entry-0014 size 14
2016 '\x00\x00\x00\x01\x08\x00\x00\x00\x01\x00\x00\x00\x00d'
2018 '\x00\x00\x00\x01\x08\x00\x00\x00\x01\x00\x00\x00\x00d'
2017 merged : d, ;
2019 merged : d, ;
2018 ##### revision "mGFm-0 merge - G side" #####
2020 ##### revision "mGFm-0 merge - G side" #####
2019 1 sidedata entries
2021 1 sidedata entries
2020 entry-0014 size 14
2022 entry-0014 size 14
2021 '\x00\x00\x00\x01\x08\x00\x00\x00\x01\x00\x00\x00\x00d'
2023 '\x00\x00\x00\x01\x08\x00\x00\x00\x01\x00\x00\x00\x00d'
2022 merged : d, ;
2024 merged : d, ;
2023 ##### revision "mCGm-0 merge updated/deleted - revive the file (updated content) - one way" #####
2025 ##### revision "mCGm-0 merge updated/deleted - revive the file (updated content) - one way" #####
2024 1 sidedata entries
2026 1 sidedata entries
2025 entry-0014 size 14
2027 entry-0014 size 14
2026 '\x00\x00\x00\x01\x10\x00\x00\x00\x01\x00\x00\x00\x00d'
2028 '\x00\x00\x00\x01\x10\x00\x00\x00\x01\x00\x00\x00\x00d'
2027 salvaged : d, ;
2029 salvaged : d, ;
2028 ##### revision "mGCm-0 merge updated/deleted - revive the file (updated content) - the other way" #####
2030 ##### revision "mGCm-0 merge updated/deleted - revive the file (updated content) - the other way" #####
2029 1 sidedata entries
2031 1 sidedata entries
2030 entry-0014 size 14
2032 entry-0014 size 14
2031 '\x00\x00\x00\x01\x10\x00\x00\x00\x01\x00\x00\x00\x00d'
2033 '\x00\x00\x00\x01\x10\x00\x00\x00\x01\x00\x00\x00\x00d'
2032 salvaged : d, ;
2034 salvaged : d, ;
2033 ##### revision "mCB-revert-m-0 merge explicitely revive deleted file - B side" #####
2035 ##### revision "mCB-revert-m-0 merge explicitely revive deleted file - B side" #####
2034 1 sidedata entries
2036 1 sidedata entries
2035 entry-0014 size 14
2037 entry-0014 size 14
2036 '\x00\x00\x00\x01\x10\x00\x00\x00\x01\x00\x00\x00\x00d'
2038 '\x00\x00\x00\x01\x10\x00\x00\x00\x01\x00\x00\x00\x00d'
2037 salvaged : d, ;
2039 salvaged : d, ;
2038 ##### revision "mBC-revert-m-0 merge explicitely revive deleted file - B side" #####
2040 ##### revision "mBC-revert-m-0 merge explicitely revive deleted file - B side" #####
2039 1 sidedata entries
2041 1 sidedata entries
2040 entry-0014 size 14
2042 entry-0014 size 14
2041 '\x00\x00\x00\x01\x10\x00\x00\x00\x01\x00\x00\x00\x00d'
2043 '\x00\x00\x00\x01\x10\x00\x00\x00\x01\x00\x00\x00\x00d'
2042 salvaged : d, ;
2044 salvaged : d, ;
2043 ##### revision "h-1" #####
2045 ##### revision "h-1" #####
2044 1 sidedata entries
2046 1 sidedata entries
2045 entry-0014 size 24
2047 entry-0014 size 24
2046 '\x00\x00\x00\x02\x0c\x00\x00\x00\x01\x00\x00\x00\x00\x06\x00\x00\x00\x02\x00\x00\x00\x00bd'
2048 '\x00\x00\x00\x02\x0c\x00\x00\x00\x01\x00\x00\x00\x00\x06\x00\x00\x00\x02\x00\x00\x00\x00bd'
2047 removed : b, ;
2049 removed : b, ;
2048 added p1: d, b;
2050 added p1: d, b;
2049 ##### revision "mCH-delete-before-conflict-m-0 simple merge - C side" #####
2051 ##### revision "mCH-delete-before-conflict-m-0 simple merge - C side" #####
2050 1 sidedata entries
2052 1 sidedata entries
2051 entry-0014 size 4
2053 entry-0014 size 4
2052 '\x00\x00\x00\x00'
2054 '\x00\x00\x00\x00'
2053 ##### revision "mHC-delete-before-conflict-m-0 simple merge - C side" #####
2055 ##### revision "mHC-delete-before-conflict-m-0 simple merge - C side" #####
2054 1 sidedata entries
2056 1 sidedata entries
2055 entry-0014 size 4
2057 entry-0014 size 4
2056 '\x00\x00\x00\x00'
2058 '\x00\x00\x00\x00'
2057 ##### revision "mAE-change-m-0 merge with file update and copies info on both side - A side" #####
2059 ##### revision "mAE-change-m-0 merge with file update and copies info on both side - A side" #####
2058 1 sidedata entries
2060 1 sidedata entries
2059 entry-0014 size 14
2061 entry-0014 size 14
2060 '\x00\x00\x00\x01\x08\x00\x00\x00\x01\x00\x00\x00\x00f'
2062 '\x00\x00\x00\x01\x08\x00\x00\x00\x01\x00\x00\x00\x00f'
2061 merged : f, ;
2063 merged : f, ;
2062 ##### revision "mEA-change-m-0 merge with file update and copies info on both side - A side" #####
2064 ##### revision "mEA-change-m-0 merge with file update and copies info on both side - A side" #####
2063 1 sidedata entries
2065 1 sidedata entries
2064 entry-0014 size 14
2066 entry-0014 size 14
2065 '\x00\x00\x00\x01\x08\x00\x00\x00\x01\x00\x00\x00\x00f'
2067 '\x00\x00\x00\x01\x08\x00\x00\x00\x01\x00\x00\x00\x00f'
2066 merged : f, ;
2068 merged : f, ;
2067 ##### revision "mBF-change-m-0 merge with extra change - B side" #####
2069 ##### revision "mBF-change-m-0 merge with extra change - B side" #####
2068 1 sidedata entries
2070 1 sidedata entries
2069 entry-0014 size 14
2071 entry-0014 size 14
2070 '\x00\x00\x00\x01\x14\x00\x00\x00\x01\x00\x00\x00\x00d'
2072 '\x00\x00\x00\x01\x14\x00\x00\x00\x01\x00\x00\x00\x00d'
2071 touched : d, ;
2073 touched : d, ;
2072 ##### revision "mFB-change-m-0 merge with extra change - B side" #####
2074 ##### revision "mFB-change-m-0 merge with extra change - B side" #####
2073 1 sidedata entries
2075 1 sidedata entries
2074 entry-0014 size 14
2076 entry-0014 size 14
2075 '\x00\x00\x00\x01\x14\x00\x00\x00\x01\x00\x00\x00\x00d'
2077 '\x00\x00\x00\x01\x14\x00\x00\x00\x01\x00\x00\x00\x00d'
2076 touched : d, ;
2078 touched : d, ;
2077 ##### revision "mCB-change-m-0 merge explicitely revive deleted file - B side" #####
2079 ##### revision "mCB-change-m-0 merge explicitely revive deleted file - B side" #####
2078 1 sidedata entries
2080 1 sidedata entries
2079 entry-0014 size 14
2081 entry-0014 size 14
2080 '\x00\x00\x00\x01\x10\x00\x00\x00\x01\x00\x00\x00\x00d'
2082 '\x00\x00\x00\x01\x10\x00\x00\x00\x01\x00\x00\x00\x00d'
2081 salvaged : d, ;
2083 salvaged : d, ;
2082 ##### revision "mBC-change-m-0 merge explicitely revive deleted file - B side" #####
2084 ##### revision "mBC-change-m-0 merge explicitely revive deleted file - B side" #####
2083 1 sidedata entries
2085 1 sidedata entries
2084 entry-0014 size 14
2086 entry-0014 size 14
2085 '\x00\x00\x00\x01\x10\x00\x00\x00\x01\x00\x00\x00\x00d'
2087 '\x00\x00\x00\x01\x10\x00\x00\x00\x01\x00\x00\x00\x00d'
2086 salvaged : d, ;
2088 salvaged : d, ;
2087 ##### revision "j-1" #####
2089 ##### revision "j-1" #####
2088 1 sidedata entries
2090 1 sidedata entries
2089 entry-0014 size 24
2091 entry-0014 size 24
2090 '\x00\x00\x00\x01\x04\x00\x00\x00\x0b\x00\x00\x00\x00unrelated-j'
2092 '\x00\x00\x00\x01\x04\x00\x00\x00\x0b\x00\x00\x00\x00unrelated-j'
2091 added : unrelated-j, ;
2093 added : unrelated-j, ;
2092 ##### revision "k-1" #####
2094 ##### revision "k-1" #####
2093 1 sidedata entries
2095 1 sidedata entries
2094 entry-0014 size 24
2096 entry-0014 size 24
2095 '\x00\x00\x00\x01\x04\x00\x00\x00\x0b\x00\x00\x00\x00unrelated-k'
2097 '\x00\x00\x00\x01\x04\x00\x00\x00\x0b\x00\x00\x00\x00unrelated-k'
2096 added : unrelated-k, ;
2098 added : unrelated-k, ;
2097 ##### revision "mAE,Km" #####
2099 ##### revision "mAE,Km" #####
2098 1 sidedata entries
2100 1 sidedata entries
2099 entry-0014 size 4
2101 entry-0014 size 4
2100 '\x00\x00\x00\x00'
2102 '\x00\x00\x00\x00'
2101 ##### revision "mK,AEm" #####
2103 ##### revision "mK,AEm" #####
2102 1 sidedata entries
2104 1 sidedata entries
2103 entry-0014 size 4
2105 entry-0014 size 4
2104 '\x00\x00\x00\x00'
2106 '\x00\x00\x00\x00'
2105 ##### revision "mEA,Jm" #####
2107 ##### revision "mEA,Jm" #####
2106 1 sidedata entries
2108 1 sidedata entries
2107 entry-0014 size 24
2109 entry-0014 size 24
2108 '\x00\x00\x00\x01\x14\x00\x00\x00\x0b\x00\x00\x00\x00unrelated-j'
2110 '\x00\x00\x00\x01\x14\x00\x00\x00\x0b\x00\x00\x00\x00unrelated-j'
2109 touched : unrelated-j, ;
2111 touched : unrelated-j, ;
2110 ##### revision "mJ,EAm" #####
2112 ##### revision "mJ,EAm" #####
2111 1 sidedata entries
2113 1 sidedata entries
2112 entry-0014 size 24
2114 entry-0014 size 24
2113 '\x00\x00\x00\x01\x14\x00\x00\x00\x0b\x00\x00\x00\x00unrelated-j'
2115 '\x00\x00\x00\x01\x14\x00\x00\x00\x0b\x00\x00\x00\x00unrelated-j'
2114 touched : unrelated-j, ;
2116 touched : unrelated-j, ;
2115 ##### revision "s-1" #####
2117 ##### revision "s-1" #####
2116 1 sidedata entries
2118 1 sidedata entries
2117 entry-0014 size 24
2119 entry-0014 size 24
2118 '\x00\x00\x00\x01\x04\x00\x00\x00\x0b\x00\x00\x00\x00unrelated-s'
2120 '\x00\x00\x00\x01\x04\x00\x00\x00\x0b\x00\x00\x00\x00unrelated-s'
2119 added : unrelated-s, ;
2121 added : unrelated-s, ;
2120 ##### revision "t-1" #####
2122 ##### revision "t-1" #####
2121 1 sidedata entries
2123 1 sidedata entries
2122 entry-0014 size 24
2124 entry-0014 size 24
2123 '\x00\x00\x00\x01\x04\x00\x00\x00\x0b\x00\x00\x00\x00unrelated-t'
2125 '\x00\x00\x00\x01\x04\x00\x00\x00\x0b\x00\x00\x00\x00unrelated-t'
2124 added : unrelated-t, ;
2126 added : unrelated-t, ;
2125 ##### revision "mPQ,Tm" #####
2127 ##### revision "mPQ,Tm" #####
2126 1 sidedata entries
2128 1 sidedata entries
2127 entry-0014 size 4
2129 entry-0014 size 4
2128 '\x00\x00\x00\x00'
2130 '\x00\x00\x00\x00'
2129 ##### revision "mT,PQm" #####
2131 ##### revision "mT,PQm" #####
2130 1 sidedata entries
2132 1 sidedata entries
2131 entry-0014 size 4
2133 entry-0014 size 4
2132 '\x00\x00\x00\x00'
2134 '\x00\x00\x00\x00'
2133 ##### revision "mQP,Sm" #####
2135 ##### revision "mQP,Sm" #####
2134 1 sidedata entries
2136 1 sidedata entries
2135 entry-0014 size 4
2137 entry-0014 size 4
2136 '\x00\x00\x00\x00'
2138 '\x00\x00\x00\x00'
2137 ##### revision "mS,QPm" #####
2139 ##### revision "mS,QPm" #####
2138 1 sidedata entries
2140 1 sidedata entries
2139 entry-0014 size 4
2141 entry-0014 size 4
2140 '\x00\x00\x00\x00'
2142 '\x00\x00\x00\x00'
2141 ##### revision "l-1" #####
2143 ##### revision "l-1" #####
2142 1 sidedata entries
2144 1 sidedata entries
2143 entry-0014 size 24
2145 entry-0014 size 24
2144 '\x00\x00\x00\x01\x04\x00\x00\x00\x0b\x00\x00\x00\x00unrelated-l'
2146 '\x00\x00\x00\x01\x04\x00\x00\x00\x0b\x00\x00\x00\x00unrelated-l'
2145 added : unrelated-l, ;
2147 added : unrelated-l, ;
2146 ##### revision "mBC+revert,Lm" #####
2148 ##### revision "mBC+revert,Lm" #####
2147 1 sidedata entries
2149 1 sidedata entries
2148 entry-0014 size 4
2150 entry-0014 size 4
2149 '\x00\x00\x00\x00'
2151 '\x00\x00\x00\x00'
2150 ##### revision "mCB+revert,Lm" #####
2152 ##### revision "mCB+revert,Lm" #####
2151 1 sidedata entries
2153 1 sidedata entries
2152 entry-0014 size 4
2154 entry-0014 size 4
2153 '\x00\x00\x00\x00'
2155 '\x00\x00\x00\x00'
2154 ##### revision "mL,BC+revertm" #####
2156 ##### revision "mL,BC+revertm" #####
2155 1 sidedata entries
2157 1 sidedata entries
2156 entry-0014 size 4
2158 entry-0014 size 4
2157 '\x00\x00\x00\x00'
2159 '\x00\x00\x00\x00'
2158 ##### revision "mL,CB+revertm" #####
2160 ##### revision "mL,CB+revertm" #####
2159 1 sidedata entries
2161 1 sidedata entries
2160 entry-0014 size 4
2162 entry-0014 size 4
2161 '\x00\x00\x00\x00'
2163 '\x00\x00\x00\x00'
2162 ##### revision "n-1" #####
2164 ##### revision "n-1" #####
2163 1 sidedata entries
2165 1 sidedata entries
2164 entry-0014 size 24
2166 entry-0014 size 24
2165 '\x00\x00\x00\x01\x04\x00\x00\x00\x0b\x00\x00\x00\x00unrelated-n'
2167 '\x00\x00\x00\x01\x04\x00\x00\x00\x0b\x00\x00\x00\x00unrelated-n'
2166 added : unrelated-n, ;
2168 added : unrelated-n, ;
2167 ##### revision "o-1" #####
2169 ##### revision "o-1" #####
2168 1 sidedata entries
2170 1 sidedata entries
2169 entry-0014 size 24
2171 entry-0014 size 24
2170 '\x00\x00\x00\x01\x04\x00\x00\x00\x0b\x00\x00\x00\x00unrelated-o'
2172 '\x00\x00\x00\x01\x04\x00\x00\x00\x0b\x00\x00\x00\x00unrelated-o'
2171 added : unrelated-o, ;
2173 added : unrelated-o, ;
2172 ##### revision "mFG,Om" #####
2174 ##### revision "mFG,Om" #####
2173 1 sidedata entries
2175 1 sidedata entries
2174 entry-0014 size 4
2176 entry-0014 size 4
2175 '\x00\x00\x00\x00'
2177 '\x00\x00\x00\x00'
2176 ##### revision "mO,FGm" #####
2178 ##### revision "mO,FGm" #####
2177 1 sidedata entries
2179 1 sidedata entries
2178 entry-0014 size 4
2180 entry-0014 size 4
2179 '\x00\x00\x00\x00'
2181 '\x00\x00\x00\x00'
2180 ##### revision "mGF,Nm" #####
2182 ##### revision "mGF,Nm" #####
2181 1 sidedata entries
2183 1 sidedata entries
2182 entry-0014 size 4
2184 entry-0014 size 4
2183 '\x00\x00\x00\x00'
2185 '\x00\x00\x00\x00'
2184 ##### revision "mN,GFm" #####
2186 ##### revision "mN,GFm" #####
2185 1 sidedata entries
2187 1 sidedata entries
2186 entry-0014 size 4
2188 entry-0014 size 4
2187 '\x00\x00\x00\x00'
2189 '\x00\x00\x00\x00'
2188 ##### revision "mAE-change,Km" #####
2190 ##### revision "mAE-change,Km" #####
2189 1 sidedata entries
2191 1 sidedata entries
2190 entry-0014 size 4
2192 entry-0014 size 4
2191 '\x00\x00\x00\x00'
2193 '\x00\x00\x00\x00'
2192 ##### revision "mK,AE-change-m" #####
2194 ##### revision "mK,AE-change-m" #####
2193 1 sidedata entries
2195 1 sidedata entries
2194 entry-0014 size 4
2196 entry-0014 size 4
2195 '\x00\x00\x00\x00'
2197 '\x00\x00\x00\x00'
2196 ##### revision "mEA-change,Jm" #####
2198 ##### revision "mEA-change,Jm" #####
2197 1 sidedata entries
2199 1 sidedata entries
2198 entry-0014 size 4
2200 entry-0014 size 4
2199 '\x00\x00\x00\x00'
2201 '\x00\x00\x00\x00'
2200 ##### revision "mJ,EA-change-m" #####
2202 ##### revision "mJ,EA-change-m" #####
2201 1 sidedata entries
2203 1 sidedata entries
2202 entry-0014 size 4
2204 entry-0014 size 4
2203 '\x00\x00\x00\x00'
2205 '\x00\x00\x00\x00'
2204
2206
2205 #endif
2207 #endif
2206
2208
2207
2209
2208 Test copy information chaining
2210 Test copy information chaining
2209 ==============================
2211 ==============================
2210
2212
2211 Check that matching only affect the destination and not intermediate path
2213 Check that matching only affect the destination and not intermediate path
2212 -------------------------------------------------------------------------
2214 -------------------------------------------------------------------------
2213
2215
2214 The two status call should give the same value for f
2216 The two status call should give the same value for f
2215
2217
2216 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("a-2")'
2218 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("a-2")'
2217 A f
2219 A f
2218 a
2220 a
2219 A t
2221 A t
2220 p
2222 p
2221 R a
2223 R a
2222 R p
2224 R p
2223 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("a-2")' f
2225 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("a-2")' f
2224 A f
2226 A f
2225 a (no-changeset no-compatibility !)
2227 a (no-changeset no-compatibility !)
2226
2228
2227 merging with unrelated change does not interfere with the renames
2229 merging with unrelated change does not interfere with the renames
2228 ---------------------------------------------------------------
2230 ---------------------------------------------------------------
2229
2231
2230 - rename on one side
2232 - rename on one side
2231 - unrelated change on the other side
2233 - unrelated change on the other side
2232
2234
2233 $ hg log -G --rev '::(desc("mABm")+desc("mBAm"))'
2235 $ hg log -G --rev '::(desc("mABm")+desc("mBAm"))'
2234 o mABm-0 simple merge - A side: multiple renames, B side: unrelated update - the other way
2236 o mABm-0 simple merge - A side: multiple renames, B side: unrelated update - the other way
2235 |\
2237 |\
2236 +---o mBAm-0 simple merge - A side: multiple renames, B side: unrelated update - one way
2238 +---o mBAm-0 simple merge - A side: multiple renames, B side: unrelated update - one way
2237 | |/
2239 | |/
2238 | o b-1: b update
2240 | o b-1: b update
2239 | |
2241 | |
2240 o | a-2: e -move-> f
2242 o | a-2: e -move-> f
2241 | |
2243 | |
2242 o | a-1: d -move-> e
2244 o | a-1: d -move-> e
2243 |/
2245 |/
2244 o i-2: c -move-> d, s -move-> t
2246 o i-2: c -move-> d, s -move-> t
2245 |
2247 |
2246 o i-1: a -move-> c, p -move-> s
2248 o i-1: a -move-> c, p -move-> s
2247 |
2249 |
2248 o i-0 initial commit: a b h p q r
2250 o i-0 initial commit: a b h p q r
2249
2251
2250
2252
2251 $ hg status --copies --rev 'desc("b-1")' --rev 'desc("mABm")'
2253 $ hg status --copies --rev 'desc("b-1")' --rev 'desc("mABm")'
2252 A f
2254 A f
2253 d
2255 d
2254 R d
2256 R d
2255 $ hg status --copies --rev 'desc("b-1")' --rev 'desc("mBAm")'
2257 $ hg status --copies --rev 'desc("b-1")' --rev 'desc("mBAm")'
2256 A f
2258 A f
2257 d
2259 d
2258 R d
2260 R d
2259 $ hg status --copies --rev 'desc("a-2")' --rev 'desc("mABm")'
2261 $ hg status --copies --rev 'desc("a-2")' --rev 'desc("mABm")'
2260 M b
2262 M b
2261 $ hg status --copies --rev 'desc("a-2")' --rev 'desc("mBAm")'
2263 $ hg status --copies --rev 'desc("a-2")' --rev 'desc("mBAm")'
2262 M b
2264 M b
2263 $ hg status --copies --rev 'desc("i-2")' --rev 'desc("mABm")'
2265 $ hg status --copies --rev 'desc("i-2")' --rev 'desc("mABm")'
2264 M b
2266 M b
2265 A f
2267 A f
2266 d
2268 d
2267 R d
2269 R d
2268 $ hg status --copies --rev 'desc("i-2")' --rev 'desc("mBAm")'
2270 $ hg status --copies --rev 'desc("i-2")' --rev 'desc("mBAm")'
2269 M b
2271 M b
2270 A f
2272 A f
2271 d
2273 d
2272 R d
2274 R d
2273 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mABm")'
2275 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mABm")'
2274 M b
2276 M b
2275 A f
2277 A f
2276 a
2278 a
2277 A t
2279 A t
2278 p
2280 p
2279 R a
2281 R a
2280 R p
2282 R p
2281 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mBAm")'
2283 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mBAm")'
2282 M b
2284 M b
2283 A f
2285 A f
2284 a
2286 a
2285 A t
2287 A t
2286 p
2288 p
2287 R a
2289 R a
2288 R p
2290 R p
2289
2291
2290 merging with the side having a delete
2292 merging with the side having a delete
2291 -------------------------------------
2293 -------------------------------------
2292
2294
2293 case summary:
2295 case summary:
2294 - one with change to an unrelated file
2296 - one with change to an unrelated file
2295 - one deleting the change
2297 - one deleting the change
2296 and recreate an unrelated file after the merge
2298 and recreate an unrelated file after the merge
2297
2299
2298 $ hg log -G --rev '::(desc("mCBm")+desc("mBCm"))'
2300 $ hg log -G --rev '::(desc("mCBm")+desc("mBCm"))'
2299 o mCBm-1 re-add d
2301 o mCBm-1 re-add d
2300 |
2302 |
2301 o mCBm-0 simple merge - C side: delete a file with copies history , B side: unrelated update - the other way
2303 o mCBm-0 simple merge - C side: delete a file with copies history , B side: unrelated update - the other way
2302 |\
2304 |\
2303 | | o mBCm-1 re-add d
2305 | | o mBCm-1 re-add d
2304 | | |
2306 | | |
2305 +---o mBCm-0 simple merge - C side: delete a file with copies history , B side: unrelated update - one way
2307 +---o mBCm-0 simple merge - C side: delete a file with copies history , B side: unrelated update - one way
2306 | |/
2308 | |/
2307 | o c-1 delete d
2309 | o c-1 delete d
2308 | |
2310 | |
2309 o | b-1: b update
2311 o | b-1: b update
2310 |/
2312 |/
2311 o i-2: c -move-> d, s -move-> t
2313 o i-2: c -move-> d, s -move-> t
2312 |
2314 |
2313 o i-1: a -move-> c, p -move-> s
2315 o i-1: a -move-> c, p -move-> s
2314 |
2316 |
2315 o i-0 initial commit: a b h p q r
2317 o i-0 initial commit: a b h p q r
2316
2318
2317 - comparing from the merge
2319 - comparing from the merge
2318
2320
2319 $ hg status --copies --rev 'desc("b-1")' --rev 'desc("mBCm-0")'
2321 $ hg status --copies --rev 'desc("b-1")' --rev 'desc("mBCm-0")'
2320 R d
2322 R d
2321 $ hg status --copies --rev 'desc("b-1")' --rev 'desc("mCBm-0")'
2323 $ hg status --copies --rev 'desc("b-1")' --rev 'desc("mCBm-0")'
2322 R d
2324 R d
2323 $ hg status --copies --rev 'desc("c-1")' --rev 'desc("mBCm-0")'
2325 $ hg status --copies --rev 'desc("c-1")' --rev 'desc("mBCm-0")'
2324 M b
2326 M b
2325 $ hg status --copies --rev 'desc("c-1")' --rev 'desc("mCBm-0")'
2327 $ hg status --copies --rev 'desc("c-1")' --rev 'desc("mCBm-0")'
2326 M b
2328 M b
2327 $ hg status --copies --rev 'desc("i-2")' --rev 'desc("mBCm-0")'
2329 $ hg status --copies --rev 'desc("i-2")' --rev 'desc("mBCm-0")'
2328 M b
2330 M b
2329 R d
2331 R d
2330 $ hg status --copies --rev 'desc("i-2")' --rev 'desc("mCBm-0")'
2332 $ hg status --copies --rev 'desc("i-2")' --rev 'desc("mCBm-0")'
2331 M b
2333 M b
2332 R d
2334 R d
2333 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mBCm-0")'
2335 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mBCm-0")'
2334 M b
2336 M b
2335 A t
2337 A t
2336 p
2338 p
2337 R a
2339 R a
2338 R p
2340 R p
2339 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mCBm-0")'
2341 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mCBm-0")'
2340 M b
2342 M b
2341 A t
2343 A t
2342 p
2344 p
2343 R a
2345 R a
2344 R p
2346 R p
2345
2347
2346 - comparing with the merge children re-adding the file
2348 - comparing with the merge children re-adding the file
2347
2349
2348 $ hg status --copies --rev 'desc("b-1")' --rev 'desc("mBCm-1")'
2350 $ hg status --copies --rev 'desc("b-1")' --rev 'desc("mBCm-1")'
2349 M d
2351 M d
2350 $ hg status --copies --rev 'desc("b-1")' --rev 'desc("mCBm-1")'
2352 $ hg status --copies --rev 'desc("b-1")' --rev 'desc("mCBm-1")'
2351 M d
2353 M d
2352 $ hg status --copies --rev 'desc("c-1")' --rev 'desc("mBCm-1")'
2354 $ hg status --copies --rev 'desc("c-1")' --rev 'desc("mBCm-1")'
2353 M b
2355 M b
2354 A d
2356 A d
2355 $ hg status --copies --rev 'desc("c-1")' --rev 'desc("mCBm-1")'
2357 $ hg status --copies --rev 'desc("c-1")' --rev 'desc("mCBm-1")'
2356 M b
2358 M b
2357 A d
2359 A d
2358 $ hg status --copies --rev 'desc("i-2")' --rev 'desc("mBCm-1")'
2360 $ hg status --copies --rev 'desc("i-2")' --rev 'desc("mBCm-1")'
2359 M b
2361 M b
2360 M d
2362 M d
2361 $ hg status --copies --rev 'desc("i-2")' --rev 'desc("mCBm-1")'
2363 $ hg status --copies --rev 'desc("i-2")' --rev 'desc("mCBm-1")'
2362 M b
2364 M b
2363 M d
2365 M d
2364 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mBCm-1")'
2366 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mBCm-1")'
2365 M b
2367 M b
2366 A d
2368 A d
2367 A t
2369 A t
2368 p
2370 p
2369 R a
2371 R a
2370 R p
2372 R p
2371 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mCBm-1")'
2373 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mCBm-1")'
2372 M b
2374 M b
2373 A d
2375 A d
2374 A t
2376 A t
2375 p
2377 p
2376 R a
2378 R a
2377 R p
2379 R p
2378
2380
2379 Comparing with a merge re-adding the file afterward
2381 Comparing with a merge re-adding the file afterward
2380 ---------------------------------------------------
2382 ---------------------------------------------------
2381
2383
2382 Merge:
2384 Merge:
2383 - one with change to an unrelated file
2385 - one with change to an unrelated file
2384 - one deleting and recreating the change
2386 - one deleting and recreating the change
2385
2387
2386 $ hg log -G --rev '::(desc("mDBm")+desc("mBDm"))'
2388 $ hg log -G --rev '::(desc("mDBm")+desc("mBDm"))'
2387 o mDBm-0 simple merge - B side: unrelated update, D side: delete and recreate a file (with different content) - the other way
2389 o mDBm-0 simple merge - B side: unrelated update, D side: delete and recreate a file (with different content) - the other way
2388 |\
2390 |\
2389 +---o mBDm-0 simple merge - B side: unrelated update, D side: delete and recreate a file (with different content) - one way
2391 +---o mBDm-0 simple merge - B side: unrelated update, D side: delete and recreate a file (with different content) - one way
2390 | |/
2392 | |/
2391 | o d-2 re-add d
2393 | o d-2 re-add d
2392 | |
2394 | |
2393 | o d-1 delete d
2395 | o d-1 delete d
2394 | |
2396 | |
2395 o | b-1: b update
2397 o | b-1: b update
2396 |/
2398 |/
2397 o i-2: c -move-> d, s -move-> t
2399 o i-2: c -move-> d, s -move-> t
2398 |
2400 |
2399 o i-1: a -move-> c, p -move-> s
2401 o i-1: a -move-> c, p -move-> s
2400 |
2402 |
2401 o i-0 initial commit: a b h p q r
2403 o i-0 initial commit: a b h p q r
2402
2404
2403 $ hg status --copies --rev 'desc("b-1")' --rev 'desc("mBDm-0")'
2405 $ hg status --copies --rev 'desc("b-1")' --rev 'desc("mBDm-0")'
2404 M d
2406 M d
2405 $ hg status --copies --rev 'desc("b-1")' --rev 'desc("mDBm-0")'
2407 $ hg status --copies --rev 'desc("b-1")' --rev 'desc("mDBm-0")'
2406 M d
2408 M d
2407 $ hg status --copies --rev 'desc("d-2")' --rev 'desc("mBDm-0")'
2409 $ hg status --copies --rev 'desc("d-2")' --rev 'desc("mBDm-0")'
2408 M b
2410 M b
2409 $ hg status --copies --rev 'desc("d-2")' --rev 'desc("mDBm-0")'
2411 $ hg status --copies --rev 'desc("d-2")' --rev 'desc("mDBm-0")'
2410 M b
2412 M b
2411 $ hg status --copies --rev 'desc("i-2")' --rev 'desc("mBDm-0")'
2413 $ hg status --copies --rev 'desc("i-2")' --rev 'desc("mBDm-0")'
2412 M b
2414 M b
2413 M d
2415 M d
2414 $ hg status --copies --rev 'desc("i-2")' --rev 'desc("mDBm-0")'
2416 $ hg status --copies --rev 'desc("i-2")' --rev 'desc("mDBm-0")'
2415 M b
2417 M b
2416 M d
2418 M d
2417
2419
2418 The bugs makes recorded copy is different depending of where we started the merge from since
2420 The bugs makes recorded copy is different depending of where we started the merge from since
2419
2421
2420 $ hg manifest --debug --rev 'desc("mBDm-0")' | grep '644 d'
2422 $ hg manifest --debug --rev 'desc("mBDm-0")' | grep '644 d'
2421 b004912a8510032a0350a74daa2803dadfb00e12 644 d
2423 b004912a8510032a0350a74daa2803dadfb00e12 644 d
2422 $ hg manifest --debug --rev 'desc("mDBm-0")' | grep '644 d'
2424 $ hg manifest --debug --rev 'desc("mDBm-0")' | grep '644 d'
2423 b004912a8510032a0350a74daa2803dadfb00e12 644 d
2425 b004912a8510032a0350a74daa2803dadfb00e12 644 d
2424
2426
2425 $ hg manifest --debug --rev 'desc("d-2")' | grep '644 d'
2427 $ hg manifest --debug --rev 'desc("d-2")' | grep '644 d'
2426 b004912a8510032a0350a74daa2803dadfb00e12 644 d
2428 b004912a8510032a0350a74daa2803dadfb00e12 644 d
2427 $ hg manifest --debug --rev 'desc("b-1")' | grep '644 d'
2429 $ hg manifest --debug --rev 'desc("b-1")' | grep '644 d'
2428 d8252ab2e760b0d4e5288fd44cbd15a0fa567e16 644 d (no-changeset !)
2430 d8252ab2e760b0d4e5288fd44cbd15a0fa567e16 644 d (no-changeset !)
2429 ae258f702dfeca05bf9b6a22a97a4b5645570f11 644 d (changeset !)
2431 ae258f702dfeca05bf9b6a22a97a4b5645570f11 644 d (changeset !)
2430 $ hg debugindex d | head -n 4 | "$PYTHON" ../no-linkrev
2432 $ hg debugindex d | head -n 4 | "$PYTHON" ../no-linkrev
2431 rev linkrev nodeid p1 p2
2433 rev linkrev nodeid p1 p2
2432 0 * d8252ab2e760 000000000000 000000000000 (no-changeset !)
2434 0 * d8252ab2e760 000000000000 000000000000 (no-changeset !)
2433 0 * ae258f702dfe 000000000000 000000000000 (changeset !)
2435 0 * ae258f702dfe 000000000000 000000000000 (changeset !)
2434 1 * b004912a8510 000000000000 000000000000
2436 1 * b004912a8510 000000000000 000000000000
2435 2 * 7b79e2fe0c89 000000000000 000000000000 (no-changeset !)
2437 2 * 7b79e2fe0c89 000000000000 000000000000 (no-changeset !)
2436 2 * 5cce88bf349f ae258f702dfe 000000000000 (changeset !)
2438 2 * 5cce88bf349f ae258f702dfe 000000000000 (changeset !)
2437
2439
2438 Log output should not include a merge commit as it did not happen
2440 Log output should not include a merge commit as it did not happen
2439
2441
2440 $ hg log -Gfr 'desc("mBDm-0")' d
2442 $ hg log -Gfr 'desc("mBDm-0")' d
2441 o d-2 re-add d
2443 o d-2 re-add d
2442 |
2444 |
2443 ~
2445 ~
2444
2446
2445 $ hg log -Gfr 'desc("mDBm-0")' d
2447 $ hg log -Gfr 'desc("mDBm-0")' d
2446 o d-2 re-add d
2448 o d-2 re-add d
2447 |
2449 |
2448 ~
2450 ~
2449
2451
2450 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mBDm-0")'
2452 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mBDm-0")'
2451 M b
2453 M b
2452 A d
2454 A d
2453 A t
2455 A t
2454 p
2456 p
2455 R a
2457 R a
2456 R p
2458 R p
2457 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mDBm-0")'
2459 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mDBm-0")'
2458 M b
2460 M b
2459 A d
2461 A d
2460 A t
2462 A t
2461 p
2463 p
2462 R a
2464 R a
2463 R p
2465 R p
2464
2466
2465
2467
2466 Comparing with a merge with colliding rename
2468 Comparing with a merge with colliding rename
2467 --------------------------------------------
2469 --------------------------------------------
2468
2470
2469 Subcase: new copy information on both side
2471 Subcase: new copy information on both side
2470 ``````````````````````````````````````````
2472 ``````````````````````````````````````````
2471
2473
2472 - the "e-" branch renaming b to f (through 'g')
2474 - the "e-" branch renaming b to f (through 'g')
2473 - the "a-" branch renaming d to f (through e)
2475 - the "a-" branch renaming d to f (through e)
2474
2476
2475 $ hg log -G --rev '::(desc("mAEm")+desc("mEAm"))'
2477 $ hg log -G --rev '::(desc("mAEm")+desc("mEAm"))'
2476 o mEAm-0 merge with copies info on both side - A side: rename d to f, E side: b to f, (same content for f) - the other way
2478 o mEAm-0 merge with copies info on both side - A side: rename d to f, E side: b to f, (same content for f) - the other way
2477 |\
2479 |\
2478 +---o mAEm-0 merge with copies info on both side - A side: rename d to f, E side: b to f, (same content for f) - one way
2480 +---o mAEm-0 merge with copies info on both side - A side: rename d to f, E side: b to f, (same content for f) - one way
2479 | |/
2481 | |/
2480 | o e-2 g -move-> f
2482 | o e-2 g -move-> f
2481 | |
2483 | |
2482 | o e-1 b -move-> g
2484 | o e-1 b -move-> g
2483 | |
2485 | |
2484 o | a-2: e -move-> f
2486 o | a-2: e -move-> f
2485 | |
2487 | |
2486 o | a-1: d -move-> e
2488 o | a-1: d -move-> e
2487 |/
2489 |/
2488 o i-2: c -move-> d, s -move-> t
2490 o i-2: c -move-> d, s -move-> t
2489 |
2491 |
2490 o i-1: a -move-> c, p -move-> s
2492 o i-1: a -move-> c, p -move-> s
2491 |
2493 |
2492 o i-0 initial commit: a b h p q r
2494 o i-0 initial commit: a b h p q r
2493
2495
2494 #if no-changeset
2496 #if no-changeset
2495 $ hg manifest --debug --rev 'desc("mAEm-0")' | grep '644 f'
2497 $ hg manifest --debug --rev 'desc("mAEm-0")' | grep '644 f'
2496 2ff93c643948464ee1f871867910ae43a45b0bea 644 f
2498 2ff93c643948464ee1f871867910ae43a45b0bea 644 f
2497 $ hg manifest --debug --rev 'desc("mEAm-0")' | grep '644 f'
2499 $ hg manifest --debug --rev 'desc("mEAm-0")' | grep '644 f'
2498 2ff93c643948464ee1f871867910ae43a45b0bea 644 f
2500 2ff93c643948464ee1f871867910ae43a45b0bea 644 f
2499 $ hg manifest --debug --rev 'desc("a-2")' | grep '644 f'
2501 $ hg manifest --debug --rev 'desc("a-2")' | grep '644 f'
2500 b76eb76580df486c3d51d63c5c210d4dd43a8ac7 644 f
2502 b76eb76580df486c3d51d63c5c210d4dd43a8ac7 644 f
2501 $ hg manifest --debug --rev 'desc("e-2")' | grep '644 f'
2503 $ hg manifest --debug --rev 'desc("e-2")' | grep '644 f'
2502 e8825b386367b29fec957283a80bb47b47483fe1 644 f
2504 e8825b386367b29fec957283a80bb47b47483fe1 644 f
2503 $ hg debugindex f | "$PYTHON" ../no-linkrev
2505 $ hg debugindex f | "$PYTHON" ../no-linkrev
2504 rev linkrev nodeid p1 p2
2506 rev linkrev nodeid p1 p2
2505 0 * b76eb76580df 000000000000 000000000000
2507 0 * b76eb76580df 000000000000 000000000000
2506 1 * e8825b386367 000000000000 000000000000
2508 1 * e8825b386367 000000000000 000000000000
2507 2 * 2ff93c643948 b76eb76580df e8825b386367
2509 2 * 2ff93c643948 b76eb76580df e8825b386367
2508 3 * 2f649fba7eb2 b76eb76580df e8825b386367
2510 3 * 2f649fba7eb2 b76eb76580df e8825b386367
2509 4 * 774e7c1637d5 e8825b386367 b76eb76580df
2511 4 * 774e7c1637d5 e8825b386367 b76eb76580df
2510 #else
2512 #else
2511 $ hg manifest --debug --rev 'desc("mAEm-0")' | grep '644 f'
2513 $ hg manifest --debug --rev 'desc("mAEm-0")' | grep '644 f'
2512 ae258f702dfeca05bf9b6a22a97a4b5645570f11 644 f
2514 ae258f702dfeca05bf9b6a22a97a4b5645570f11 644 f
2513 $ hg manifest --debug --rev 'desc("mEAm-0")' | grep '644 f'
2515 $ hg manifest --debug --rev 'desc("mEAm-0")' | grep '644 f'
2514 ae258f702dfeca05bf9b6a22a97a4b5645570f11 644 f
2516 ae258f702dfeca05bf9b6a22a97a4b5645570f11 644 f
2515 $ hg manifest --debug --rev 'desc("a-2")' | grep '644 f'
2517 $ hg manifest --debug --rev 'desc("a-2")' | grep '644 f'
2516 ae258f702dfeca05bf9b6a22a97a4b5645570f11 644 f
2518 ae258f702dfeca05bf9b6a22a97a4b5645570f11 644 f
2517 $ hg manifest --debug --rev 'desc("e-2")' | grep '644 f'
2519 $ hg manifest --debug --rev 'desc("e-2")' | grep '644 f'
2518 ae258f702dfeca05bf9b6a22a97a4b5645570f11 644 f
2520 ae258f702dfeca05bf9b6a22a97a4b5645570f11 644 f
2519 $ hg debugindex f | "$PYTHON" ../no-linkrev
2521 $ hg debugindex f | "$PYTHON" ../no-linkrev
2520 rev linkrev nodeid p1 p2
2522 rev linkrev nodeid p1 p2
2521 0 * ae258f702dfe 000000000000 000000000000
2523 0 * ae258f702dfe 000000000000 000000000000
2522 1 * d3613c1ec831 ae258f702dfe 000000000000
2524 1 * d3613c1ec831 ae258f702dfe 000000000000
2523 2 * 05e03c868bbc ae258f702dfe 000000000000
2525 2 * 05e03c868bbc ae258f702dfe 000000000000
2524 #endif
2526 #endif
2525
2527
2526 # Here the filelog based implementation is not looking at the rename
2528 # Here the filelog based implementation is not looking at the rename
2527 # information (because the file exist on both side). However the changelog
2529 # information (because the file exist on both side). However the changelog
2528 # based on works fine. We have different output.
2530 # based on works fine. We have different output.
2529
2531
2530 $ hg status --copies --rev 'desc("a-2")' --rev 'desc("mAEm-0")'
2532 $ hg status --copies --rev 'desc("a-2")' --rev 'desc("mAEm-0")'
2531 M f (no-changeset !)
2533 M f (no-changeset !)
2532 b (no-filelog no-changeset !)
2534 b (no-filelog no-changeset !)
2533 R b
2535 R b
2534 $ hg status --copies --rev 'desc("a-2")' --rev 'desc("mEAm-0")'
2536 $ hg status --copies --rev 'desc("a-2")' --rev 'desc("mEAm-0")'
2535 M f (no-changeset !)
2537 M f (no-changeset !)
2536 b (no-filelog no-changeset !)
2538 b (no-filelog no-changeset !)
2537 R b
2539 R b
2538 $ hg status --copies --rev 'desc("e-2")' --rev 'desc("mAEm-0")'
2540 $ hg status --copies --rev 'desc("e-2")' --rev 'desc("mAEm-0")'
2539 M f (no-changeset !)
2541 M f (no-changeset !)
2540 d (no-filelog no-changeset !)
2542 d (no-filelog no-changeset !)
2541 R d
2543 R d
2542 $ hg status --copies --rev 'desc("e-2")' --rev 'desc("mEAm-0")'
2544 $ hg status --copies --rev 'desc("e-2")' --rev 'desc("mEAm-0")'
2543 M f (no-changeset !)
2545 M f (no-changeset !)
2544 d (no-filelog no-changeset !)
2546 d (no-filelog no-changeset !)
2545 R d
2547 R d
2546 $ hg status --copies --rev 'desc("i-2")' --rev 'desc("a-2")'
2548 $ hg status --copies --rev 'desc("i-2")' --rev 'desc("a-2")'
2547 A f
2549 A f
2548 d
2550 d
2549 R d
2551 R d
2550 $ hg status --copies --rev 'desc("i-2")' --rev 'desc("e-2")'
2552 $ hg status --copies --rev 'desc("i-2")' --rev 'desc("e-2")'
2551 A f
2553 A f
2552 b
2554 b
2553 R b
2555 R b
2554
2556
2555 # From here, we run status against revision where both source file exists.
2557 # From here, we run status against revision where both source file exists.
2556 #
2558 #
2557 # The filelog based implementation picks an arbitrary side based on revision
2559 # The filelog based implementation picks an arbitrary side based on revision
2558 # numbers. So the same side "wins" whatever the parents order is. This is
2560 # numbers. So the same side "wins" whatever the parents order is. This is
2559 # sub-optimal because depending on revision numbers means the result can be
2561 # sub-optimal because depending on revision numbers means the result can be
2560 # different from one repository to the next.
2562 # different from one repository to the next.
2561 #
2563 #
2562 # The changeset based algorithm use the parent order to break tie on conflicting
2564 # The changeset based algorithm use the parent order to break tie on conflicting
2563 # information and will have a different order depending on who is p1 and p2.
2565 # information and will have a different order depending on who is p1 and p2.
2564 # That order is stable accross repositories. (data from p1 prevails)
2566 # That order is stable accross repositories. (data from p1 prevails)
2565
2567
2566 $ hg status --copies --rev 'desc("i-2")' --rev 'desc("mAEm-0")'
2568 $ hg status --copies --rev 'desc("i-2")' --rev 'desc("mAEm-0")'
2567 A f
2569 A f
2568 d
2570 d
2569 R b
2571 R b
2570 R d
2572 R d
2571 $ hg status --copies --rev 'desc("i-2")' --rev 'desc("mEAm-0")'
2573 $ hg status --copies --rev 'desc("i-2")' --rev 'desc("mEAm-0")'
2572 A f
2574 A f
2573 d (filelog !)
2575 d (filelog !)
2574 b (no-filelog !)
2576 b (no-filelog !)
2575 R b
2577 R b
2576 R d
2578 R d
2577 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mAEm-0")'
2579 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mAEm-0")'
2578 A f
2580 A f
2579 a
2581 a
2580 A t
2582 A t
2581 p
2583 p
2582 R a
2584 R a
2583 R b
2585 R b
2584 R p
2586 R p
2585 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mEAm-0")'
2587 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mEAm-0")'
2586 A f
2588 A f
2587 a (filelog !)
2589 a (filelog !)
2588 b (no-filelog !)
2590 b (no-filelog !)
2589 A t
2591 A t
2590 p
2592 p
2591 R a
2593 R a
2592 R b
2594 R b
2593 R p
2595 R p
2594
2596
2595
2597
2596 Subcase: existing copy information overwritten on one branch
2598 Subcase: existing copy information overwritten on one branch
2597 ````````````````````````````````````````````````````````````
2599 ````````````````````````````````````````````````````````````
2598
2600
2599 Note:
2601 Note:
2600 | In this case, one of the merge wrongly record a merge while there is none.
2602 | In this case, one of the merge wrongly record a merge while there is none.
2601 | This lead to bad copy tracing information to be dug up.
2603 | This lead to bad copy tracing information to be dug up.
2602
2604
2603
2605
2604 Merge:
2606 Merge:
2605 - one with change to an unrelated file (b)
2607 - one with change to an unrelated file (b)
2606 - one overwriting a file (d) with a rename (from h to i to d)
2608 - one overwriting a file (d) with a rename (from h to i to d)
2607
2609
2608 $ hg log -G --rev '::(desc("mBFm")+desc("mFBm"))'
2610 $ hg log -G --rev '::(desc("mBFm")+desc("mFBm"))'
2609 o mFBm-0 simple merge - B side: unrelated change, F side: overwrite d with a copy (from h->i->d) - the other way
2611 o mFBm-0 simple merge - B side: unrelated change, F side: overwrite d with a copy (from h->i->d) - the other way
2610 |\
2612 |\
2611 +---o mBFm-0 simple merge - B side: unrelated change, F side: overwrite d with a copy (from h->i->d) - one way
2613 +---o mBFm-0 simple merge - B side: unrelated change, F side: overwrite d with a copy (from h->i->d) - one way
2612 | |/
2614 | |/
2613 | o f-2: rename i -> d
2615 | o f-2: rename i -> d
2614 | |
2616 | |
2615 | o f-1: rename h -> i
2617 | o f-1: rename h -> i
2616 | |
2618 | |
2617 o | b-1: b update
2619 o | b-1: b update
2618 |/
2620 |/
2619 o i-2: c -move-> d, s -move-> t
2621 o i-2: c -move-> d, s -move-> t
2620 |
2622 |
2621 o i-1: a -move-> c, p -move-> s
2623 o i-1: a -move-> c, p -move-> s
2622 |
2624 |
2623 o i-0 initial commit: a b h p q r
2625 o i-0 initial commit: a b h p q r
2624
2626
2625 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mBFm-0")'
2627 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mBFm-0")'
2626 M b
2628 M b
2627 A d
2629 A d
2628 h
2630 h
2629 A t
2631 A t
2630 p
2632 p
2631 R a
2633 R a
2632 R h
2634 R h
2633 R p
2635 R p
2634 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mFBm-0")'
2636 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mFBm-0")'
2635 M b
2637 M b
2636 A d
2638 A d
2637 h
2639 h
2638 A t
2640 A t
2639 p
2641 p
2640 R a
2642 R a
2641 R h
2643 R h
2642 R p
2644 R p
2643 $ hg status --copies --rev 'desc("b-1")' --rev 'desc("mBFm-0")'
2645 $ hg status --copies --rev 'desc("b-1")' --rev 'desc("mBFm-0")'
2644 M d (no-changeset !)
2646 M d (no-changeset !)
2645 h (no-filelog no-changeset !)
2647 h (no-filelog no-changeset !)
2646 R h
2648 R h
2647 $ hg status --copies --rev 'desc("f-2")' --rev 'desc("mBFm-0")'
2649 $ hg status --copies --rev 'desc("f-2")' --rev 'desc("mBFm-0")'
2648 M b
2650 M b
2649 $ hg status --copies --rev 'desc("f-1")' --rev 'desc("mBFm-0")'
2651 $ hg status --copies --rev 'desc("f-1")' --rev 'desc("mBFm-0")'
2650 M b
2652 M b
2651 M d (no-changeset !)
2653 M d (no-changeset !)
2652 i (no-filelog no-changeset !)
2654 i (no-filelog no-changeset !)
2653 R i
2655 R i
2654 $ hg status --copies --rev 'desc("b-1")' --rev 'desc("mFBm-0")'
2656 $ hg status --copies --rev 'desc("b-1")' --rev 'desc("mFBm-0")'
2655 M d (no-changeset !)
2657 M d (no-changeset !)
2656 h (no-filelog no-changeset !)
2658 h (no-filelog no-changeset !)
2657 R h
2659 R h
2658 $ hg status --copies --rev 'desc("f-2")' --rev 'desc("mFBm-0")'
2660 $ hg status --copies --rev 'desc("f-2")' --rev 'desc("mFBm-0")'
2659 M b
2661 M b
2660 $ hg status --copies --rev 'desc("f-1")' --rev 'desc("mFBm-0")'
2662 $ hg status --copies --rev 'desc("f-1")' --rev 'desc("mFBm-0")'
2661 M b
2663 M b
2662 M d (no-changeset !)
2664 M d (no-changeset !)
2663 i (no-filelog no-changeset !)
2665 i (no-filelog no-changeset !)
2664 R i
2666 R i
2665
2667
2666 #if no-changeset
2668 #if no-changeset
2667 $ hg log -Gfr 'desc("mBFm-0")' d
2669 $ hg log -Gfr 'desc("mBFm-0")' d
2668 o f-2: rename i -> d
2670 o f-2: rename i -> d
2669 |
2671 |
2670 o f-1: rename h -> i
2672 o f-1: rename h -> i
2671 :
2673 :
2672 o i-0 initial commit: a b h p q r
2674 o i-0 initial commit: a b h p q r
2673
2675
2674 #else
2676 #else
2675 BROKEN: `hg log --follow <file>` relies on filelog metadata to work
2677 BROKEN: `hg log --follow <file>` relies on filelog metadata to work
2676 $ hg log -Gfr 'desc("mBFm-0")' d
2678 $ hg log -Gfr 'desc("mBFm-0")' d
2677 o i-2: c -move-> d, s -move-> t
2679 o i-2: c -move-> d, s -move-> t
2678 |
2680 |
2679 ~
2681 ~
2680 #endif
2682 #endif
2681
2683
2682 #if no-changeset
2684 #if no-changeset
2683 $ hg log -Gfr 'desc("mFBm-0")' d
2685 $ hg log -Gfr 'desc("mFBm-0")' d
2684 o f-2: rename i -> d
2686 o f-2: rename i -> d
2685 |
2687 |
2686 o f-1: rename h -> i
2688 o f-1: rename h -> i
2687 :
2689 :
2688 o i-0 initial commit: a b h p q r
2690 o i-0 initial commit: a b h p q r
2689
2691
2690 #else
2692 #else
2691 BROKEN: `hg log --follow <file>` relies on filelog metadata to work
2693 BROKEN: `hg log --follow <file>` relies on filelog metadata to work
2692 $ hg log -Gfr 'desc("mFBm-0")' d
2694 $ hg log -Gfr 'desc("mFBm-0")' d
2693 o i-2: c -move-> d, s -move-> t
2695 o i-2: c -move-> d, s -move-> t
2694 |
2696 |
2695 ~
2697 ~
2696 #endif
2698 #endif
2697
2699
2698
2700
2699 Subcase: existing copy information overwritten on one branch, with different content)
2701 Subcase: existing copy information overwritten on one branch, with different content)
2700 `````````````````````````````````````````````````````````````````````````````````````
2702 `````````````````````````````````````````````````````````````````````````````````````
2701
2703
2702 Merge:
2704 Merge:
2703 - one with change to an unrelated file (b)
2705 - one with change to an unrelated file (b)
2704 - one overwriting a file (t) with a rename (from r to x to t), v content is not the same as on the other branch
2706 - one overwriting a file (t) with a rename (from r to x to t), v content is not the same as on the other branch
2705
2707
2706 $ hg log -G --rev '::(desc("mBRm")+desc("mRBm"))'
2708 $ hg log -G --rev '::(desc("mBRm")+desc("mRBm"))'
2707 o mRBm-0 simple merge - B side: unrelated change, R side: overwrite d with a copy (from r->x->t) different content - the other way
2709 o mRBm-0 simple merge - B side: unrelated change, R side: overwrite d with a copy (from r->x->t) different content - the other way
2708 |\
2710 |\
2709 +---o mBRm-0 simple merge - B side: unrelated change, R side: overwrite d with a copy (from r->x->t) different content - one way
2711 +---o mBRm-0 simple merge - B side: unrelated change, R side: overwrite d with a copy (from r->x->t) different content - one way
2710 | |/
2712 | |/
2711 | o r-2: rename t -> x
2713 | o r-2: rename t -> x
2712 | |
2714 | |
2713 | o r-1: rename r -> x
2715 | o r-1: rename r -> x
2714 | |
2716 | |
2715 o | b-1: b update
2717 o | b-1: b update
2716 |/
2718 |/
2717 o i-2: c -move-> d, s -move-> t
2719 o i-2: c -move-> d, s -move-> t
2718 |
2720 |
2719 o i-1: a -move-> c, p -move-> s
2721 o i-1: a -move-> c, p -move-> s
2720 |
2722 |
2721 o i-0 initial commit: a b h p q r
2723 o i-0 initial commit: a b h p q r
2722
2724
2723 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mBRm-0")'
2725 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mBRm-0")'
2724 M b
2726 M b
2725 A d
2727 A d
2726 a
2728 a
2727 A t
2729 A t
2728 r
2730 r
2729 R a
2731 R a
2730 R p
2732 R p
2731 R r
2733 R r
2732 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mRBm-0")'
2734 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mRBm-0")'
2733 M b
2735 M b
2734 A d
2736 A d
2735 a
2737 a
2736 A t
2738 A t
2737 r
2739 r
2738 R a
2740 R a
2739 R p
2741 R p
2740 R r
2742 R r
2741 $ hg status --copies --rev 'desc("b-1")' --rev 'desc("mBRm-0")'
2743 $ hg status --copies --rev 'desc("b-1")' --rev 'desc("mBRm-0")'
2742 M t
2744 M t
2743 r (no-filelog !)
2745 r (no-filelog !)
2744 R r
2746 R r
2745 $ hg status --copies --rev 'desc("r-2")' --rev 'desc("mBRm-0")'
2747 $ hg status --copies --rev 'desc("r-2")' --rev 'desc("mBRm-0")'
2746 M b
2748 M b
2747 $ hg status --copies --rev 'desc("r-1")' --rev 'desc("mBRm-0")'
2749 $ hg status --copies --rev 'desc("r-1")' --rev 'desc("mBRm-0")'
2748 M b
2750 M b
2749 M t
2751 M t
2750 x (no-filelog !)
2752 x (no-filelog !)
2751 R x
2753 R x
2752 $ hg status --copies --rev 'desc("b-1")' --rev 'desc("mRBm-0")'
2754 $ hg status --copies --rev 'desc("b-1")' --rev 'desc("mRBm-0")'
2753 M t
2755 M t
2754 r (no-filelog !)
2756 r (no-filelog !)
2755 R r
2757 R r
2756 $ hg status --copies --rev 'desc("r-2")' --rev 'desc("mRBm-0")'
2758 $ hg status --copies --rev 'desc("r-2")' --rev 'desc("mRBm-0")'
2757 M b
2759 M b
2758 $ hg status --copies --rev 'desc("r-1")' --rev 'desc("mRBm-0")'
2760 $ hg status --copies --rev 'desc("r-1")' --rev 'desc("mRBm-0")'
2759 M b
2761 M b
2760 M t
2762 M t
2761 x (no-filelog !)
2763 x (no-filelog !)
2762 R x
2764 R x
2763
2765
2764 #if no-changeset
2766 #if no-changeset
2765 $ hg log -Gfr 'desc("mBRm-0")' d
2767 $ hg log -Gfr 'desc("mBRm-0")' d
2766 o i-2: c -move-> d, s -move-> t
2768 o i-2: c -move-> d, s -move-> t
2767 |
2769 |
2768 o i-1: a -move-> c, p -move-> s
2770 o i-1: a -move-> c, p -move-> s
2769 |
2771 |
2770 o i-0 initial commit: a b h p q r
2772 o i-0 initial commit: a b h p q r
2771
2773
2772 #else
2774 #else
2773 BROKEN: `hg log --follow <file>` relies on filelog metadata to work
2775 BROKEN: `hg log --follow <file>` relies on filelog metadata to work
2774 $ hg log -Gfr 'desc("mBRm-0")' d
2776 $ hg log -Gfr 'desc("mBRm-0")' d
2775 o i-2: c -move-> d, s -move-> t
2777 o i-2: c -move-> d, s -move-> t
2776 |
2778 |
2777 ~
2779 ~
2778 #endif
2780 #endif
2779
2781
2780 #if no-changeset
2782 #if no-changeset
2781 $ hg log -Gfr 'desc("mRBm-0")' d
2783 $ hg log -Gfr 'desc("mRBm-0")' d
2782 o i-2: c -move-> d, s -move-> t
2784 o i-2: c -move-> d, s -move-> t
2783 |
2785 |
2784 o i-1: a -move-> c, p -move-> s
2786 o i-1: a -move-> c, p -move-> s
2785 |
2787 |
2786 o i-0 initial commit: a b h p q r
2788 o i-0 initial commit: a b h p q r
2787
2789
2788 #else
2790 #else
2789 BROKEN: `hg log --follow <file>` relies on filelog metadata to work
2791 BROKEN: `hg log --follow <file>` relies on filelog metadata to work
2790 $ hg log -Gfr 'desc("mRBm-0")' d
2792 $ hg log -Gfr 'desc("mRBm-0")' d
2791 o i-2: c -move-> d, s -move-> t
2793 o i-2: c -move-> d, s -move-> t
2792 |
2794 |
2793 ~
2795 ~
2794 #endif
2796 #endif
2795
2797
2796 Subcase: reset of the copy history on one side
2798 Subcase: reset of the copy history on one side
2797 ``````````````````````````````````````````````
2799 ``````````````````````````````````````````````
2798
2800
2799 Merge:
2801 Merge:
2800 - one with change to a file
2802 - one with change to a file
2801 - one deleting and recreating the file
2803 - one deleting and recreating the file
2802
2804
2803 Unlike in the 'BD/DB' cases, an actual merge happened here. So we should
2805 Unlike in the 'BD/DB' cases, an actual merge happened here. So we should
2804 consider history and rename on both branch of the merge.
2806 consider history and rename on both branch of the merge.
2805
2807
2806 $ hg log -G --rev '::(desc("mDGm")+desc("mGDm"))'
2808 $ hg log -G --rev '::(desc("mDGm")+desc("mGDm"))'
2807 o mGDm-0 actual content merge, copies on one side - D side: delete and re-add (different content), G side: update content - the other way
2809 o mGDm-0 actual content merge, copies on one side - D side: delete and re-add (different content), G side: update content - the other way
2808 |\
2810 |\
2809 +---o mDGm-0 actual content merge, copies on one side - D side: delete and re-add (different content), G side: update content - one way
2811 +---o mDGm-0 actual content merge, copies on one side - D side: delete and re-add (different content), G side: update content - one way
2810 | |/
2812 | |/
2811 | o g-1: update d
2813 | o g-1: update d
2812 | |
2814 | |
2813 o | d-2 re-add d
2815 o | d-2 re-add d
2814 | |
2816 | |
2815 o | d-1 delete d
2817 o | d-1 delete d
2816 |/
2818 |/
2817 o i-2: c -move-> d, s -move-> t
2819 o i-2: c -move-> d, s -move-> t
2818 |
2820 |
2819 o i-1: a -move-> c, p -move-> s
2821 o i-1: a -move-> c, p -move-> s
2820 |
2822 |
2821 o i-0 initial commit: a b h p q r
2823 o i-0 initial commit: a b h p q r
2822
2824
2823 One side of the merge have a long history with rename. The other side of the
2825 One side of the merge have a long history with rename. The other side of the
2824 merge point to a new file with a smaller history. Each side is "valid".
2826 merge point to a new file with a smaller history. Each side is "valid".
2825
2827
2826 (and again the filelog based algorithm only explore one, with a pick based on
2828 (and again the filelog based algorithm only explore one, with a pick based on
2827 revision numbers)
2829 revision numbers)
2828
2830
2829 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mDGm-0")'
2831 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mDGm-0")'
2830 A d
2832 A d
2831 a (filelog !)
2833 a (filelog !)
2832 A t
2834 A t
2833 p
2835 p
2834 R a
2836 R a
2835 R p
2837 R p
2836 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mGDm-0")'
2838 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mGDm-0")'
2837 A d
2839 A d
2838 a
2840 a
2839 A t
2841 A t
2840 p
2842 p
2841 R a
2843 R a
2842 R p
2844 R p
2843 $ hg status --copies --rev 'desc("d-2")' --rev 'desc("mDGm-0")'
2845 $ hg status --copies --rev 'desc("d-2")' --rev 'desc("mDGm-0")'
2844 M d
2846 M d
2845 $ hg status --copies --rev 'desc("d-2")' --rev 'desc("mGDm-0")'
2847 $ hg status --copies --rev 'desc("d-2")' --rev 'desc("mGDm-0")'
2846 M d
2848 M d
2847 $ hg status --copies --rev 'desc("g-1")' --rev 'desc("mDGm-0")'
2849 $ hg status --copies --rev 'desc("g-1")' --rev 'desc("mDGm-0")'
2848 M d
2850 M d
2849 $ hg status --copies --rev 'desc("g-1")' --rev 'desc("mGDm-0")'
2851 $ hg status --copies --rev 'desc("g-1")' --rev 'desc("mGDm-0")'
2850 M d
2852 M d
2851
2853
2852 #if no-changeset
2854 #if no-changeset
2853 $ hg log -Gfr 'desc("mDGm-0")' d
2855 $ hg log -Gfr 'desc("mDGm-0")' d
2854 o mDGm-0 actual content merge, copies on one side - D side: delete and re-add (different content), G side: update content - one way
2856 o mDGm-0 actual content merge, copies on one side - D side: delete and re-add (different content), G side: update content - one way
2855 |\
2857 |\
2856 | o g-1: update d
2858 | o g-1: update d
2857 | |
2859 | |
2858 o | d-2 re-add d
2860 o | d-2 re-add d
2859 |/
2861 |/
2860 o i-2: c -move-> d, s -move-> t
2862 o i-2: c -move-> d, s -move-> t
2861 |
2863 |
2862 o i-1: a -move-> c, p -move-> s
2864 o i-1: a -move-> c, p -move-> s
2863 |
2865 |
2864 o i-0 initial commit: a b h p q r
2866 o i-0 initial commit: a b h p q r
2865
2867
2866 #else
2868 #else
2867 BROKEN: `hg log --follow <file>` relies on filelog metadata to work
2869 BROKEN: `hg log --follow <file>` relies on filelog metadata to work
2868 $ hg log -Gfr 'desc("mDGm-0")' d
2870 $ hg log -Gfr 'desc("mDGm-0")' d
2869 o mDGm-0 actual content merge, copies on one side - D side: delete and re-add (different content), G side: update content - one way
2871 o mDGm-0 actual content merge, copies on one side - D side: delete and re-add (different content), G side: update content - one way
2870 |\
2872 |\
2871 | o g-1: update d
2873 | o g-1: update d
2872 | |
2874 | |
2873 o | d-2 re-add d
2875 o | d-2 re-add d
2874 |/
2876 |/
2875 o i-2: c -move-> d, s -move-> t
2877 o i-2: c -move-> d, s -move-> t
2876 |
2878 |
2877 ~
2879 ~
2878 #endif
2880 #endif
2879
2881
2880
2882
2881 #if no-changeset
2883 #if no-changeset
2882 $ hg log -Gfr 'desc("mDGm-0")' d
2884 $ hg log -Gfr 'desc("mDGm-0")' d
2883 o mDGm-0 actual content merge, copies on one side - D side: delete and re-add (different content), G side: update content - one way
2885 o mDGm-0 actual content merge, copies on one side - D side: delete and re-add (different content), G side: update content - one way
2884 |\
2886 |\
2885 | o g-1: update d
2887 | o g-1: update d
2886 | |
2888 | |
2887 o | d-2 re-add d
2889 o | d-2 re-add d
2888 |/
2890 |/
2889 o i-2: c -move-> d, s -move-> t
2891 o i-2: c -move-> d, s -move-> t
2890 |
2892 |
2891 o i-1: a -move-> c, p -move-> s
2893 o i-1: a -move-> c, p -move-> s
2892 |
2894 |
2893 o i-0 initial commit: a b h p q r
2895 o i-0 initial commit: a b h p q r
2894
2896
2895 #else
2897 #else
2896 BROKEN: `hg log --follow <file>` relies on filelog metadata to work
2898 BROKEN: `hg log --follow <file>` relies on filelog metadata to work
2897 $ hg log -Gfr 'desc("mDGm-0")' d
2899 $ hg log -Gfr 'desc("mDGm-0")' d
2898 o mDGm-0 actual content merge, copies on one side - D side: delete and re-add (different content), G side: update content - one way
2900 o mDGm-0 actual content merge, copies on one side - D side: delete and re-add (different content), G side: update content - one way
2899 |\
2901 |\
2900 | o g-1: update d
2902 | o g-1: update d
2901 | |
2903 | |
2902 o | d-2 re-add d
2904 o | d-2 re-add d
2903 |/
2905 |/
2904 o i-2: c -move-> d, s -move-> t
2906 o i-2: c -move-> d, s -move-> t
2905 |
2907 |
2906 ~
2908 ~
2907 #endif
2909 #endif
2908
2910
2909 Subcase: merging a change to a file with a "copy overwrite" to that file from another branch
2911 Subcase: merging a change to a file with a "copy overwrite" to that file from another branch
2910 ````````````````````````````````````````````````````````````````````````````````````````````
2912 ````````````````````````````````````````````````````````````````````````````````````````````
2911
2913
2912 Merge:
2914 Merge:
2913 - one with change to a file (d)
2915 - one with change to a file (d)
2914 - one overwriting that file with a rename (from h to i, to d)
2916 - one overwriting that file with a rename (from h to i, to d)
2915
2917
2916 This case is similar to BF/FB, but an actual merge happens, so both side of the
2918 This case is similar to BF/FB, but an actual merge happens, so both side of the
2917 history are relevant.
2919 history are relevant.
2918
2920
2919
2921
2920 $ hg log -G --rev '::(desc("mGFm")+desc("mFGm"))'
2922 $ hg log -G --rev '::(desc("mGFm")+desc("mFGm"))'
2921 o mGFm-0 merge - G side: content change, F side: copy overwrite, no content change - the other way
2923 o mGFm-0 merge - G side: content change, F side: copy overwrite, no content change - the other way
2922 |\
2924 |\
2923 +---o mFGm-0 merge - G side: content change, F side: copy overwrite, no content change - one way
2925 +---o mFGm-0 merge - G side: content change, F side: copy overwrite, no content change - one way
2924 | |/
2926 | |/
2925 | o g-1: update d
2927 | o g-1: update d
2926 | |
2928 | |
2927 o | f-2: rename i -> d
2929 o | f-2: rename i -> d
2928 | |
2930 | |
2929 o | f-1: rename h -> i
2931 o | f-1: rename h -> i
2930 |/
2932 |/
2931 o i-2: c -move-> d, s -move-> t
2933 o i-2: c -move-> d, s -move-> t
2932 |
2934 |
2933 o i-1: a -move-> c, p -move-> s
2935 o i-1: a -move-> c, p -move-> s
2934 |
2936 |
2935 o i-0 initial commit: a b h p q r
2937 o i-0 initial commit: a b h p q r
2936
2938
2937
2939
2938 Note:
2940 Note:
2939 | In this case, the merge get conflicting information since on one side we have
2941 | In this case, the merge get conflicting information since on one side we have
2940 | "a -> c -> d". and one the other one we have "h -> i -> d".
2942 | "a -> c -> d". and one the other one we have "h -> i -> d".
2941 |
2943 |
2942 | The current code arbitrarily pick one side depending the ordering of the merged hash:
2944 | The current code arbitrarily pick one side depending the ordering of the merged hash:
2943
2945
2944 In this case, the file hash from "f-2" is lower, so it will be `p1` of the resulting filenode its copy tracing information will win (and trace back to "h"):
2946 In this case, the file hash from "f-2" is lower, so it will be `p1` of the resulting filenode its copy tracing information will win (and trace back to "h"):
2945
2947
2946 Details on this hash ordering pick:
2948 Details on this hash ordering pick:
2947
2949
2948 $ hg manifest --debug 'desc("g-1")' | egrep 'd$'
2950 $ hg manifest --debug 'desc("g-1")' | egrep 'd$'
2949 17ec97e605773eb44a117d1136b3849bcdc1924f 644 d (no-changeset !)
2951 17ec97e605773eb44a117d1136b3849bcdc1924f 644 d (no-changeset !)
2950 5cce88bf349f7c742bb440f2c53f81db9c294279 644 d (changeset !)
2952 5cce88bf349f7c742bb440f2c53f81db9c294279 644 d (changeset !)
2951 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("g-1")' d
2953 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("g-1")' d
2952 A d
2954 A d
2953 a (no-changeset no-compatibility !)
2955 a (no-changeset no-compatibility !)
2954
2956
2955 $ hg manifest --debug 'desc("f-2")' | egrep 'd$'
2957 $ hg manifest --debug 'desc("f-2")' | egrep 'd$'
2956 7b79e2fe0c8924e0e598a82f048a7b024afa4d96 644 d (no-changeset !)
2958 7b79e2fe0c8924e0e598a82f048a7b024afa4d96 644 d (no-changeset !)
2957 ae258f702dfeca05bf9b6a22a97a4b5645570f11 644 d (changeset !)
2959 ae258f702dfeca05bf9b6a22a97a4b5645570f11 644 d (changeset !)
2958 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("f-2")' d
2960 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("f-2")' d
2959 A d
2961 A d
2960 h (no-changeset no-compatibility !)
2962 h (no-changeset no-compatibility !)
2961
2963
2962 Copy tracing data on the resulting merge:
2964 Copy tracing data on the resulting merge:
2963
2965
2964 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mFGm-0")'
2966 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mFGm-0")'
2965 A d
2967 A d
2966 h (no-filelog !)
2968 h (no-filelog !)
2967 a (filelog !)
2969 a (filelog !)
2968 A t
2970 A t
2969 p
2971 p
2970 R a
2972 R a
2971 R h
2973 R h
2972 R p
2974 R p
2973 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mGFm-0")'
2975 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mGFm-0")'
2974 A d
2976 A d
2975 a (no-changeset !)
2977 a (no-changeset !)
2976 h (changeset !)
2978 h (changeset !)
2977 A t
2979 A t
2978 p
2980 p
2979 R a
2981 R a
2980 R h
2982 R h
2981 R p
2983 R p
2982 $ hg status --copies --rev 'desc("f-2")' --rev 'desc("mFGm-0")'
2984 $ hg status --copies --rev 'desc("f-2")' --rev 'desc("mFGm-0")'
2983 M d
2985 M d
2984 $ hg status --copies --rev 'desc("f-2")' --rev 'desc("mGFm-0")'
2986 $ hg status --copies --rev 'desc("f-2")' --rev 'desc("mGFm-0")'
2985 M d
2987 M d
2986 $ hg status --copies --rev 'desc("f-1")' --rev 'desc("mFGm-0")'
2988 $ hg status --copies --rev 'desc("f-1")' --rev 'desc("mFGm-0")'
2987 M d
2989 M d
2988 i (no-filelog !)
2990 i (no-filelog !)
2989 R i
2991 R i
2990 $ hg status --copies --rev 'desc("f-1")' --rev 'desc("mGFm-0")'
2992 $ hg status --copies --rev 'desc("f-1")' --rev 'desc("mGFm-0")'
2991 M d
2993 M d
2992 i (no-filelog !)
2994 i (no-filelog !)
2993 R i
2995 R i
2994 $ hg status --copies --rev 'desc("g-1")' --rev 'desc("mFGm-0")'
2996 $ hg status --copies --rev 'desc("g-1")' --rev 'desc("mFGm-0")'
2995 M d (no-changeset !)
2997 M d (no-changeset !)
2996 h (no-filelog no-changeset !)
2998 h (no-filelog no-changeset !)
2997 R h
2999 R h
2998 $ hg status --copies --rev 'desc("g-1")' --rev 'desc("mGFm-0")'
3000 $ hg status --copies --rev 'desc("g-1")' --rev 'desc("mGFm-0")'
2999 M d (no-changeset !)
3001 M d (no-changeset !)
3000 h (no-filelog no-changeset !)
3002 h (no-filelog no-changeset !)
3001 R h
3003 R h
3002
3004
3003 #if no-changeset
3005 #if no-changeset
3004 $ hg log -Gfr 'desc("mFGm-0")' d
3006 $ hg log -Gfr 'desc("mFGm-0")' d
3005 o mFGm-0 merge - G side: content change, F side: copy overwrite, no content change - one way
3007 o mFGm-0 merge - G side: content change, F side: copy overwrite, no content change - one way
3006 |\
3008 |\
3007 | o g-1: update d
3009 | o g-1: update d
3008 | |
3010 | |
3009 o | f-2: rename i -> d
3011 o | f-2: rename i -> d
3010 | |
3012 | |
3011 o | f-1: rename h -> i
3013 o | f-1: rename h -> i
3012 |/
3014 |/
3013 o i-2: c -move-> d, s -move-> t
3015 o i-2: c -move-> d, s -move-> t
3014 |
3016 |
3015 o i-1: a -move-> c, p -move-> s
3017 o i-1: a -move-> c, p -move-> s
3016 |
3018 |
3017 o i-0 initial commit: a b h p q r
3019 o i-0 initial commit: a b h p q r
3018
3020
3019 #else
3021 #else
3020 BROKEN: `hg log --follow <file>` relies on filelog metadata to work
3022 BROKEN: `hg log --follow <file>` relies on filelog metadata to work
3021 $ hg log -Gfr 'desc("mFGm-0")' d
3023 $ hg log -Gfr 'desc("mFGm-0")' d
3022 o g-1: update d
3024 o g-1: update d
3023 |
3025 |
3024 o i-2: c -move-> d, s -move-> t
3026 o i-2: c -move-> d, s -move-> t
3025 |
3027 |
3026 ~
3028 ~
3027 #endif
3029 #endif
3028
3030
3029 #if no-changeset
3031 #if no-changeset
3030 $ hg log -Gfr 'desc("mGFm-0")' d
3032 $ hg log -Gfr 'desc("mGFm-0")' d
3031 o mGFm-0 merge - G side: content change, F side: copy overwrite, no content change - the other way
3033 o mGFm-0 merge - G side: content change, F side: copy overwrite, no content change - the other way
3032 |\
3034 |\
3033 | o g-1: update d
3035 | o g-1: update d
3034 | |
3036 | |
3035 o | f-2: rename i -> d
3037 o | f-2: rename i -> d
3036 | |
3038 | |
3037 o | f-1: rename h -> i
3039 o | f-1: rename h -> i
3038 |/
3040 |/
3039 o i-2: c -move-> d, s -move-> t
3041 o i-2: c -move-> d, s -move-> t
3040 |
3042 |
3041 o i-1: a -move-> c, p -move-> s
3043 o i-1: a -move-> c, p -move-> s
3042 |
3044 |
3043 o i-0 initial commit: a b h p q r
3045 o i-0 initial commit: a b h p q r
3044
3046
3045 #else
3047 #else
3046 BROKEN: `hg log --follow <file>` relies on filelog metadata to work
3048 BROKEN: `hg log --follow <file>` relies on filelog metadata to work
3047 $ hg log -Gfr 'desc("mGFm-0")' d
3049 $ hg log -Gfr 'desc("mGFm-0")' d
3048 o g-1: update d
3050 o g-1: update d
3049 |
3051 |
3050 o i-2: c -move-> d, s -move-> t
3052 o i-2: c -move-> d, s -move-> t
3051 |
3053 |
3052 ~
3054 ~
3053 #endif
3055 #endif
3054
3056
3055 Subcase: new copy information on both side with an actual merge happening
3057 Subcase: new copy information on both side with an actual merge happening
3056 `````````````````````````````````````````````````````````````````````````
3058 `````````````````````````````````````````````````````````````````````````
3057
3059
3058 - the "p-" branch renaming 't' to 'v' (through 'u')
3060 - the "p-" branch renaming 't' to 'v' (through 'u')
3059 - the "q-" branch renaming 'r' to 'v' (through 'w')
3061 - the "q-" branch renaming 'r' to 'v' (through 'w')
3060
3062
3061
3063
3062 $ hg log -G --rev '::(desc("mPQm")+desc("mQPm"))'
3064 $ hg log -G --rev '::(desc("mPQm")+desc("mQPm"))'
3063 o mQPm-0 merge with copies info on both side - P side: rename t to v, Q side: r to v, (different content) - the other way
3065 o mQPm-0 merge with copies info on both side - P side: rename t to v, Q side: r to v, (different content) - the other way
3064 |\
3066 |\
3065 +---o mPQm-0 merge with copies info on both side - P side: rename t to v, Q side: r to v, (different content) - one way
3067 +---o mPQm-0 merge with copies info on both side - P side: rename t to v, Q side: r to v, (different content) - one way
3066 | |/
3068 | |/
3067 | o q-2 w -move-> v
3069 | o q-2 w -move-> v
3068 | |
3070 | |
3069 | o q-1 r -move-> w
3071 | o q-1 r -move-> w
3070 | |
3072 | |
3071 o | p-2: u -move-> v
3073 o | p-2: u -move-> v
3072 | |
3074 | |
3073 o | p-1: t -move-> u
3075 o | p-1: t -move-> u
3074 |/
3076 |/
3075 o i-2: c -move-> d, s -move-> t
3077 o i-2: c -move-> d, s -move-> t
3076 |
3078 |
3077 o i-1: a -move-> c, p -move-> s
3079 o i-1: a -move-> c, p -move-> s
3078 |
3080 |
3079 o i-0 initial commit: a b h p q r
3081 o i-0 initial commit: a b h p q r
3080
3082
3081
3083
3082 #if no-changeset
3084 #if no-changeset
3083 $ hg manifest --debug --rev 'desc("mPQm-0")' | grep '644 v'
3085 $ hg manifest --debug --rev 'desc("mPQm-0")' | grep '644 v'
3084 0946c662ef16e4e67397fd717389eb6693d41749 644 v
3086 0946c662ef16e4e67397fd717389eb6693d41749 644 v
3085 $ hg manifest --debug --rev 'desc("mQPm-0")' | grep '644 v'
3087 $ hg manifest --debug --rev 'desc("mQPm-0")' | grep '644 v'
3086 0db3aad7fcc1ec27fab57060e327b9e864ea0cc9 644 v
3088 0db3aad7fcc1ec27fab57060e327b9e864ea0cc9 644 v
3087 $ hg manifest --debug --rev 'desc("p-2")' | grep '644 v'
3089 $ hg manifest --debug --rev 'desc("p-2")' | grep '644 v'
3088 3f91841cd75cadc9a1f1b4e7c1aa6d411f76032e 644 v
3090 3f91841cd75cadc9a1f1b4e7c1aa6d411f76032e 644 v
3089 $ hg manifest --debug --rev 'desc("q-2")' | grep '644 v'
3091 $ hg manifest --debug --rev 'desc("q-2")' | grep '644 v'
3090 c43c088b811fd27983c0a9aadf44f3343cd4cd7e 644 v
3092 c43c088b811fd27983c0a9aadf44f3343cd4cd7e 644 v
3091 $ hg debugindex v | "$PYTHON" ../no-linkrev
3093 $ hg debugindex v | "$PYTHON" ../no-linkrev
3092 rev linkrev nodeid p1 p2
3094 rev linkrev nodeid p1 p2
3093 0 * 3f91841cd75c 000000000000 000000000000
3095 0 * 3f91841cd75c 000000000000 000000000000
3094 1 * c43c088b811f 000000000000 000000000000
3096 1 * c43c088b811f 000000000000 000000000000
3095 2 * 0946c662ef16 3f91841cd75c c43c088b811f
3097 2 * 0946c662ef16 3f91841cd75c c43c088b811f
3096 3 * 0db3aad7fcc1 c43c088b811f 3f91841cd75c
3098 3 * 0db3aad7fcc1 c43c088b811f 3f91841cd75c
3097 #else
3099 #else
3098 $ hg manifest --debug --rev 'desc("mPQm-0")' | grep '644 v'
3100 $ hg manifest --debug --rev 'desc("mPQm-0")' | grep '644 v'
3099 65fde9f6e4d4da23b3f610e07b53673ea9541d75 644 v
3101 65fde9f6e4d4da23b3f610e07b53673ea9541d75 644 v
3100 $ hg manifest --debug --rev 'desc("mQPm-0")' | grep '644 v'
3102 $ hg manifest --debug --rev 'desc("mQPm-0")' | grep '644 v'
3101 a098dda6413aecf154eefc976afc38b295acb7e5 644 v
3103 a098dda6413aecf154eefc976afc38b295acb7e5 644 v
3102 $ hg manifest --debug --rev 'desc("p-2")' | grep '644 v'
3104 $ hg manifest --debug --rev 'desc("p-2")' | grep '644 v'
3103 5aed6a8dbff0301328c08360d24354d3d064cf0d 644 v
3105 5aed6a8dbff0301328c08360d24354d3d064cf0d 644 v
3104 $ hg manifest --debug --rev 'desc("q-2")' | grep '644 v'
3106 $ hg manifest --debug --rev 'desc("q-2")' | grep '644 v'
3105 a38b2fa170219750dac9bc7d19df831f213ba708 644 v
3107 a38b2fa170219750dac9bc7d19df831f213ba708 644 v
3106 $ hg debugindex v | "$PYTHON" ../no-linkrev
3108 $ hg debugindex v | "$PYTHON" ../no-linkrev
3107 rev linkrev nodeid p1 p2
3109 rev linkrev nodeid p1 p2
3108 0 * 5aed6a8dbff0 000000000000 000000000000
3110 0 * 5aed6a8dbff0 000000000000 000000000000
3109 1 * a38b2fa17021 000000000000 000000000000
3111 1 * a38b2fa17021 000000000000 000000000000
3110 2 * 65fde9f6e4d4 5aed6a8dbff0 a38b2fa17021
3112 2 * 65fde9f6e4d4 5aed6a8dbff0 a38b2fa17021
3111 3 * a098dda6413a a38b2fa17021 5aed6a8dbff0
3113 3 * a098dda6413a a38b2fa17021 5aed6a8dbff0
3112 #endif
3114 #endif
3113
3115
3114 # Here the filelog based implementation is not looking at the rename
3116 # Here the filelog based implementation is not looking at the rename
3115 # information (because the file exist on both side). However the changelog
3117 # information (because the file exist on both side). However the changelog
3116 # based on works fine. We have different output.
3118 # based on works fine. We have different output.
3117
3119
3118 $ hg status --copies --rev 'desc("p-2")' --rev 'desc("mPQm-0")'
3120 $ hg status --copies --rev 'desc("p-2")' --rev 'desc("mPQm-0")'
3119 M v
3121 M v
3120 r (no-filelog !)
3122 r (no-filelog !)
3121 R r
3123 R r
3122 $ hg status --copies --rev 'desc("p-2")' --rev 'desc("mQPm-0")'
3124 $ hg status --copies --rev 'desc("p-2")' --rev 'desc("mQPm-0")'
3123 M v
3125 M v
3124 r (no-filelog !)
3126 r (no-filelog !)
3125 R r
3127 R r
3126 $ hg status --copies --rev 'desc("q-2")' --rev 'desc("mPQm-0")'
3128 $ hg status --copies --rev 'desc("q-2")' --rev 'desc("mPQm-0")'
3127 M v
3129 M v
3128 t (no-filelog !)
3130 t (no-filelog !)
3129 R t
3131 R t
3130 $ hg status --copies --rev 'desc("q-2")' --rev 'desc("mQPm-0")'
3132 $ hg status --copies --rev 'desc("q-2")' --rev 'desc("mQPm-0")'
3131 M v
3133 M v
3132 t (no-filelog !)
3134 t (no-filelog !)
3133 R t
3135 R t
3134 $ hg status --copies --rev 'desc("i-2")' --rev 'desc("p-2")'
3136 $ hg status --copies --rev 'desc("i-2")' --rev 'desc("p-2")'
3135 A v
3137 A v
3136 t
3138 t
3137 R t
3139 R t
3138 $ hg status --copies --rev 'desc("i-2")' --rev 'desc("q-2")'
3140 $ hg status --copies --rev 'desc("i-2")' --rev 'desc("q-2")'
3139 A v
3141 A v
3140 r
3142 r
3141 R r
3143 R r
3142
3144
3143 # From here, we run status against revision where both source file exists.
3145 # From here, we run status against revision where both source file exists.
3144 #
3146 #
3145 # The filelog based implementation picks an arbitrary side based on revision
3147 # The filelog based implementation picks an arbitrary side based on revision
3146 # numbers. So the same side "wins" whatever the parents order is. This is
3148 # numbers. So the same side "wins" whatever the parents order is. This is
3147 # sub-optimal because depending on revision numbers means the result can be
3149 # sub-optimal because depending on revision numbers means the result can be
3148 # different from one repository to the next.
3150 # different from one repository to the next.
3149 #
3151 #
3150 # The changeset based algorithm use the parent order to break tie on conflicting
3152 # The changeset based algorithm use the parent order to break tie on conflicting
3151 # information and will have a different order depending on who is p1 and p2.
3153 # information and will have a different order depending on who is p1 and p2.
3152 # That order is stable accross repositories. (data from p1 prevails)
3154 # That order is stable accross repositories. (data from p1 prevails)
3153
3155
3154 $ hg status --copies --rev 'desc("i-2")' --rev 'desc("mPQm-0")'
3156 $ hg status --copies --rev 'desc("i-2")' --rev 'desc("mPQm-0")'
3155 A v
3157 A v
3156 t
3158 t
3157 R r
3159 R r
3158 R t
3160 R t
3159 $ hg status --copies --rev 'desc("i-2")' --rev 'desc("mQPm-0")'
3161 $ hg status --copies --rev 'desc("i-2")' --rev 'desc("mQPm-0")'
3160 A v
3162 A v
3161 t (filelog !)
3163 t (filelog !)
3162 r (no-filelog !)
3164 r (no-filelog !)
3163 R r
3165 R r
3164 R t
3166 R t
3165 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mPQm-0")'
3167 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mPQm-0")'
3166 A d
3168 A d
3167 a
3169 a
3168 A v
3170 A v
3169 r (filelog !)
3171 r (filelog !)
3170 p (no-filelog !)
3172 p (no-filelog !)
3171 R a
3173 R a
3172 R p
3174 R p
3173 R r
3175 R r
3174 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mQPm-0")'
3176 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mQPm-0")'
3175 A d
3177 A d
3176 a
3178 a
3177 A v
3179 A v
3178 r
3180 r
3179 R a
3181 R a
3180 R p
3182 R p
3181 R r
3183 R r
3182
3184
3183
3185
3184 Comparing with merging with a deletion (and keeping the file)
3186 Comparing with merging with a deletion (and keeping the file)
3185 -------------------------------------------------------------
3187 -------------------------------------------------------------
3186
3188
3187 Merge:
3189 Merge:
3188 - one removing a file (d)
3190 - one removing a file (d)
3189 - one updating that file
3191 - one updating that file
3190 - the merge keep the modified version of the file (canceling the delete)
3192 - the merge keep the modified version of the file (canceling the delete)
3191
3193
3192 In this case, the file keep on living after the merge. So we should not drop its
3194 In this case, the file keep on living after the merge. So we should not drop its
3193 copy tracing chain.
3195 copy tracing chain.
3194
3196
3195 $ hg log -G --rev '::(desc("mCGm")+desc("mGCm"))'
3197 $ hg log -G --rev '::(desc("mCGm")+desc("mGCm"))'
3196 o mGCm-0 merge updated/deleted - revive the file (updated content) - the other way
3198 o mGCm-0 merge updated/deleted - revive the file (updated content) - the other way
3197 |\
3199 |\
3198 +---o mCGm-0 merge updated/deleted - revive the file (updated content) - one way
3200 +---o mCGm-0 merge updated/deleted - revive the file (updated content) - one way
3199 | |/
3201 | |/
3200 | o g-1: update d
3202 | o g-1: update d
3201 | |
3203 | |
3202 o | c-1 delete d
3204 o | c-1 delete d
3203 |/
3205 |/
3204 o i-2: c -move-> d, s -move-> t
3206 o i-2: c -move-> d, s -move-> t
3205 |
3207 |
3206 o i-1: a -move-> c, p -move-> s
3208 o i-1: a -move-> c, p -move-> s
3207 |
3209 |
3208 o i-0 initial commit: a b h p q r
3210 o i-0 initial commit: a b h p q r
3209
3211
3210
3212
3211 'a' is the copy source of 'd'
3213 'a' is the copy source of 'd'
3212
3214
3213 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mCGm-0")'
3215 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mCGm-0")'
3214 A d
3216 A d
3215 a (no-compatibility no-changeset !)
3217 a (no-compatibility no-changeset !)
3216 A t
3218 A t
3217 p
3219 p
3218 R a
3220 R a
3219 R p
3221 R p
3220 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mGCm-0")'
3222 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mGCm-0")'
3221 A d
3223 A d
3222 a (no-compatibility no-changeset !)
3224 a (no-compatibility no-changeset !)
3223 A t
3225 A t
3224 p
3226 p
3225 R a
3227 R a
3226 R p
3228 R p
3227 $ hg status --copies --rev 'desc("c-1")' --rev 'desc("mCGm-0")'
3229 $ hg status --copies --rev 'desc("c-1")' --rev 'desc("mCGm-0")'
3228 A d
3230 A d
3229 $ hg status --copies --rev 'desc("c-1")' --rev 'desc("mGCm-0")'
3231 $ hg status --copies --rev 'desc("c-1")' --rev 'desc("mGCm-0")'
3230 A d
3232 A d
3231 $ hg status --copies --rev 'desc("g-1")' --rev 'desc("mCGm-0")'
3233 $ hg status --copies --rev 'desc("g-1")' --rev 'desc("mCGm-0")'
3232 $ hg status --copies --rev 'desc("g-1")' --rev 'desc("mGCm-0")'
3234 $ hg status --copies --rev 'desc("g-1")' --rev 'desc("mGCm-0")'
3233
3235
3234
3236
3235 Comparing with merge restoring an untouched deleted file
3237 Comparing with merge restoring an untouched deleted file
3236 --------------------------------------------------------
3238 --------------------------------------------------------
3237
3239
3238 Merge:
3240 Merge:
3239 - one removing a file (d)
3241 - one removing a file (d)
3240 - one leaving the file untouched
3242 - one leaving the file untouched
3241 - the merge actively restore the file to the same content.
3243 - the merge actively restore the file to the same content.
3242
3244
3243 In this case, the file keep on living after the merge. So we should not drop its
3245 In this case, the file keep on living after the merge. So we should not drop its
3244 copy tracing chain.
3246 copy tracing chain.
3245
3247
3246 $ hg log -G --rev '::(desc("mCB-revert-m")+desc("mBC-revert-m"))'
3248 $ hg log -G --rev '::(desc("mCB-revert-m")+desc("mBC-revert-m"))'
3247 o mBC-revert-m-0 merge explicitely revive deleted file - B side: unrelated change, C side: delete d (restored by merge) - the other way
3249 o mBC-revert-m-0 merge explicitely revive deleted file - B side: unrelated change, C side: delete d (restored by merge) - the other way
3248 |\
3250 |\
3249 +---o mCB-revert-m-0 merge explicitely revive deleted file - B side: unrelated change, C side: delete d (restored by merge) - one way
3251 +---o mCB-revert-m-0 merge explicitely revive deleted file - B side: unrelated change, C side: delete d (restored by merge) - one way
3250 | |/
3252 | |/
3251 | o c-1 delete d
3253 | o c-1 delete d
3252 | |
3254 | |
3253 o | b-1: b update
3255 o | b-1: b update
3254 |/
3256 |/
3255 o i-2: c -move-> d, s -move-> t
3257 o i-2: c -move-> d, s -move-> t
3256 |
3258 |
3257 o i-1: a -move-> c, p -move-> s
3259 o i-1: a -move-> c, p -move-> s
3258 |
3260 |
3259 o i-0 initial commit: a b h p q r
3261 o i-0 initial commit: a b h p q r
3260
3262
3261
3263
3262 'a' is the the copy source of 'd'
3264 'a' is the the copy source of 'd'
3263
3265
3264 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mCB-revert-m-0")'
3266 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mCB-revert-m-0")'
3265 M b
3267 M b
3266 A d
3268 A d
3267 a (no-compatibility no-changeset !)
3269 a (no-compatibility no-changeset !)
3268 A t
3270 A t
3269 p
3271 p
3270 R a
3272 R a
3271 R p
3273 R p
3272 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mBC-revert-m-0")'
3274 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mBC-revert-m-0")'
3273 M b
3275 M b
3274 A d
3276 A d
3275 a (no-compatibility no-changeset !)
3277 a (no-compatibility no-changeset !)
3276 A t
3278 A t
3277 p
3279 p
3278 R a
3280 R a
3279 R p
3281 R p
3280 $ hg status --copies --rev 'desc("c-1")' --rev 'desc("mCB-revert-m-0")'
3282 $ hg status --copies --rev 'desc("c-1")' --rev 'desc("mCB-revert-m-0")'
3281 M b
3283 M b
3282 A d
3284 A d
3283 $ hg status --copies --rev 'desc("c-1")' --rev 'desc("mBC-revert-m-0")'
3285 $ hg status --copies --rev 'desc("c-1")' --rev 'desc("mBC-revert-m-0")'
3284 M b
3286 M b
3285 A d
3287 A d
3286 $ hg status --copies --rev 'desc("b-1")' --rev 'desc("mCB-revert-m-0")'
3288 $ hg status --copies --rev 'desc("b-1")' --rev 'desc("mCB-revert-m-0")'
3287 $ hg status --copies --rev 'desc("b-1")' --rev 'desc("mBC-revert-m-0")'
3289 $ hg status --copies --rev 'desc("b-1")' --rev 'desc("mBC-revert-m-0")'
3288
3290
3289
3291
3290 Merging a branch where a rename was deleted with a branch where the same file was renamed
3292 Merging a branch where a rename was deleted with a branch where the same file was renamed
3291 ------------------------------------------------------------------------------------------
3293 ------------------------------------------------------------------------------------------
3292
3294
3293 Create a "conflicting" merge where `d` get removed on one branch before its
3295 Create a "conflicting" merge where `d` get removed on one branch before its
3294 rename information actually conflict with the other branch.
3296 rename information actually conflict with the other branch.
3295
3297
3296 (the copy information from the branch that was not deleted should win).
3298 (the copy information from the branch that was not deleted should win).
3297
3299
3298 $ hg log -G --rev '::(desc("mCH-delete-before-conflict-m")+desc("mHC-delete-before-conflict-m"))'
3300 $ hg log -G --rev '::(desc("mCH-delete-before-conflict-m")+desc("mHC-delete-before-conflict-m"))'
3299 o mHC-delete-before-conflict-m-0 simple merge - C side: d is the results of renames then deleted, H side: d is result of another rename (same content as the other branch) - the other way
3301 o mHC-delete-before-conflict-m-0 simple merge - C side: d is the results of renames then deleted, H side: d is result of another rename (same content as the other branch) - the other way
3300 |\
3302 |\
3301 +---o mCH-delete-before-conflict-m-0 simple merge - C side: d is the results of renames then deleted, H side: d is result of another rename (same content as the other branch) - one way
3303 +---o mCH-delete-before-conflict-m-0 simple merge - C side: d is the results of renames then deleted, H side: d is result of another rename (same content as the other branch) - one way
3302 | |/
3304 | |/
3303 | o h-1: b -(move)-> d
3305 | o h-1: b -(move)-> d
3304 | |
3306 | |
3305 o | c-1 delete d
3307 o | c-1 delete d
3306 | |
3308 | |
3307 o | i-2: c -move-> d, s -move-> t
3309 o | i-2: c -move-> d, s -move-> t
3308 | |
3310 | |
3309 o | i-1: a -move-> c, p -move-> s
3311 o | i-1: a -move-> c, p -move-> s
3310 |/
3312 |/
3311 o i-0 initial commit: a b h p q r
3313 o i-0 initial commit: a b h p q r
3312
3314
3313
3315
3314 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mCH-delete-before-conflict-m")'
3316 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mCH-delete-before-conflict-m")'
3315 A d
3317 A d
3316 b (no-compatibility no-changeset !)
3318 b (no-compatibility no-changeset !)
3317 A t
3319 A t
3318 p
3320 p
3319 R a
3321 R a
3320 R b
3322 R b
3321 R p
3323 R p
3322 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mHC-delete-before-conflict-m")'
3324 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mHC-delete-before-conflict-m")'
3323 A d
3325 A d
3324 b
3326 b
3325 A t
3327 A t
3326 p
3328 p
3327 R a
3329 R a
3328 R b
3330 R b
3329 R p
3331 R p
3330 $ hg status --copies --rev 'desc("c-1")' --rev 'desc("mCH-delete-before-conflict-m")'
3332 $ hg status --copies --rev 'desc("c-1")' --rev 'desc("mCH-delete-before-conflict-m")'
3331 A d
3333 A d
3332 b
3334 b
3333 R b
3335 R b
3334 $ hg status --copies --rev 'desc("c-1")' --rev 'desc("mHC-delete-before-conflict-m")'
3336 $ hg status --copies --rev 'desc("c-1")' --rev 'desc("mHC-delete-before-conflict-m")'
3335 A d
3337 A d
3336 b
3338 b
3337 R b
3339 R b
3338 $ hg status --copies --rev 'desc("h-1")' --rev 'desc("mCH-delete-before-conflict-m")'
3340 $ hg status --copies --rev 'desc("h-1")' --rev 'desc("mCH-delete-before-conflict-m")'
3339 A t
3341 A t
3340 p
3342 p
3341 R a
3343 R a
3342 R p
3344 R p
3343 $ hg status --copies --rev 'desc("h-1")' --rev 'desc("mHC-delete-before-conflict-m")'
3345 $ hg status --copies --rev 'desc("h-1")' --rev 'desc("mHC-delete-before-conflict-m")'
3344 A t
3346 A t
3345 p
3347 p
3346 R a
3348 R a
3347 R p
3349 R p
3348
3350
3349 Variant of previous with extra changes introduced by the merge
3351 Variant of previous with extra changes introduced by the merge
3350 --------------------------------------------------------------
3352 --------------------------------------------------------------
3351
3353
3352 (see case declaration for details)
3354 (see case declaration for details)
3353
3355
3354 Subcase: merge has same initial content on both side, but merge introduced a change
3356 Subcase: merge has same initial content on both side, but merge introduced a change
3355 ```````````````````````````````````````````````````````````````````````````````````
3357 ```````````````````````````````````````````````````````````````````````````````````
3356
3358
3357 - the "e-" branch renaming b to f (through 'g')
3359 - the "e-" branch renaming b to f (through 'g')
3358 - the "a-" branch renaming d to f (through e)
3360 - the "a-" branch renaming d to f (through e)
3359 - the merge add new change to b
3361 - the merge add new change to b
3360
3362
3361 $ hg log -G --rev '::(desc("mAE-change-m")+desc("mEA-change-m"))'
3363 $ hg log -G --rev '::(desc("mAE-change-m")+desc("mEA-change-m"))'
3362 o mEA-change-m-0 merge with file update and copies info on both side - A side: rename d to f, E side: b to f, (same content for f in parent) - the other way
3364 o mEA-change-m-0 merge with file update and copies info on both side - A side: rename d to f, E side: b to f, (same content for f in parent) - the other way
3363 |\
3365 |\
3364 +---o mAE-change-m-0 merge with file update and copies info on both side - A side: rename d to f, E side: b to f, (same content for f in parent) - one way
3366 +---o mAE-change-m-0 merge with file update and copies info on both side - A side: rename d to f, E side: b to f, (same content for f in parent) - one way
3365 | |/
3367 | |/
3366 | o e-2 g -move-> f
3368 | o e-2 g -move-> f
3367 | |
3369 | |
3368 | o e-1 b -move-> g
3370 | o e-1 b -move-> g
3369 | |
3371 | |
3370 o | a-2: e -move-> f
3372 o | a-2: e -move-> f
3371 | |
3373 | |
3372 o | a-1: d -move-> e
3374 o | a-1: d -move-> e
3373 |/
3375 |/
3374 o i-2: c -move-> d, s -move-> t
3376 o i-2: c -move-> d, s -move-> t
3375 |
3377 |
3376 o i-1: a -move-> c, p -move-> s
3378 o i-1: a -move-> c, p -move-> s
3377 |
3379 |
3378 o i-0 initial commit: a b h p q r
3380 o i-0 initial commit: a b h p q r
3379
3381
3380 #if no-changeset
3382 #if no-changeset
3381 $ hg manifest --debug --rev 'desc("mAE-change-m-0")' | grep '644 f'
3383 $ hg manifest --debug --rev 'desc("mAE-change-m-0")' | grep '644 f'
3382 2f649fba7eb284e720d02b61f0546fcef694c045 644 f
3384 2f649fba7eb284e720d02b61f0546fcef694c045 644 f
3383 $ hg manifest --debug --rev 'desc("mEA-change-m-0")' | grep '644 f'
3385 $ hg manifest --debug --rev 'desc("mEA-change-m-0")' | grep '644 f'
3384 774e7c1637d536b99e2d8ef16fd731f87a82bd09 644 f
3386 774e7c1637d536b99e2d8ef16fd731f87a82bd09 644 f
3385 $ hg manifest --debug --rev 'desc("a-2")' | grep '644 f'
3387 $ hg manifest --debug --rev 'desc("a-2")' | grep '644 f'
3386 b76eb76580df486c3d51d63c5c210d4dd43a8ac7 644 f
3388 b76eb76580df486c3d51d63c5c210d4dd43a8ac7 644 f
3387 $ hg manifest --debug --rev 'desc("e-2")' | grep '644 f'
3389 $ hg manifest --debug --rev 'desc("e-2")' | grep '644 f'
3388 e8825b386367b29fec957283a80bb47b47483fe1 644 f
3390 e8825b386367b29fec957283a80bb47b47483fe1 644 f
3389 $ hg debugindex f | "$PYTHON" ../no-linkrev
3391 $ hg debugindex f | "$PYTHON" ../no-linkrev
3390 rev linkrev nodeid p1 p2
3392 rev linkrev nodeid p1 p2
3391 0 * b76eb76580df 000000000000 000000000000
3393 0 * b76eb76580df 000000000000 000000000000
3392 1 * e8825b386367 000000000000 000000000000
3394 1 * e8825b386367 000000000000 000000000000
3393 2 * 2ff93c643948 b76eb76580df e8825b386367
3395 2 * 2ff93c643948 b76eb76580df e8825b386367
3394 3 * 2f649fba7eb2 b76eb76580df e8825b386367
3396 3 * 2f649fba7eb2 b76eb76580df e8825b386367
3395 4 * 774e7c1637d5 e8825b386367 b76eb76580df
3397 4 * 774e7c1637d5 e8825b386367 b76eb76580df
3396 #else
3398 #else
3397 $ hg manifest --debug --rev 'desc("mAE-change-m-0")' | grep '644 f'
3399 $ hg manifest --debug --rev 'desc("mAE-change-m-0")' | grep '644 f'
3398 d3613c1ec8310a812ac4268fd853ac576b6caea5 644 f
3400 d3613c1ec8310a812ac4268fd853ac576b6caea5 644 f
3399 $ hg manifest --debug --rev 'desc("mEA-change-m-0")' | grep '644 f'
3401 $ hg manifest --debug --rev 'desc("mEA-change-m-0")' | grep '644 f'
3400 05e03c868bbcab4a649cb33a238d7aa07398a469 644 f
3402 05e03c868bbcab4a649cb33a238d7aa07398a469 644 f
3401 $ hg manifest --debug --rev 'desc("a-2")' | grep '644 f'
3403 $ hg manifest --debug --rev 'desc("a-2")' | grep '644 f'
3402 ae258f702dfeca05bf9b6a22a97a4b5645570f11 644 f
3404 ae258f702dfeca05bf9b6a22a97a4b5645570f11 644 f
3403 $ hg manifest --debug --rev 'desc("e-2")' | grep '644 f'
3405 $ hg manifest --debug --rev 'desc("e-2")' | grep '644 f'
3404 ae258f702dfeca05bf9b6a22a97a4b5645570f11 644 f
3406 ae258f702dfeca05bf9b6a22a97a4b5645570f11 644 f
3405 $ hg debugindex f | "$PYTHON" ../no-linkrev
3407 $ hg debugindex f | "$PYTHON" ../no-linkrev
3406 rev linkrev nodeid p1 p2
3408 rev linkrev nodeid p1 p2
3407 0 * ae258f702dfe 000000000000 000000000000
3409 0 * ae258f702dfe 000000000000 000000000000
3408 1 * d3613c1ec831 ae258f702dfe 000000000000
3410 1 * d3613c1ec831 ae258f702dfe 000000000000
3409 2 * 05e03c868bbc ae258f702dfe 000000000000
3411 2 * 05e03c868bbc ae258f702dfe 000000000000
3410 #endif
3412 #endif
3411
3413
3412 # Here the filelog based implementation is not looking at the rename
3414 # Here the filelog based implementation is not looking at the rename
3413 # information (because the file exist on both side). However the changelog
3415 # information (because the file exist on both side). However the changelog
3414 # based on works fine. We have different output.
3416 # based on works fine. We have different output.
3415
3417
3416 $ hg status --copies --rev 'desc("a-2")' --rev 'desc("mAE-change-m-0")'
3418 $ hg status --copies --rev 'desc("a-2")' --rev 'desc("mAE-change-m-0")'
3417 M f
3419 M f
3418 b (no-filelog !)
3420 b (no-filelog !)
3419 R b
3421 R b
3420 $ hg status --copies --rev 'desc("a-2")' --rev 'desc("mEA-change-m-0")'
3422 $ hg status --copies --rev 'desc("a-2")' --rev 'desc("mEA-change-m-0")'
3421 M f
3423 M f
3422 b (no-filelog !)
3424 b (no-filelog !)
3423 R b
3425 R b
3424 $ hg status --copies --rev 'desc("e-2")' --rev 'desc("mAE-change-m-0")'
3426 $ hg status --copies --rev 'desc("e-2")' --rev 'desc("mAE-change-m-0")'
3425 M f
3427 M f
3426 d (no-filelog !)
3428 d (no-filelog !)
3427 R d
3429 R d
3428 $ hg status --copies --rev 'desc("e-2")' --rev 'desc("mEA-change-m-0")'
3430 $ hg status --copies --rev 'desc("e-2")' --rev 'desc("mEA-change-m-0")'
3429 M f
3431 M f
3430 d (no-filelog !)
3432 d (no-filelog !)
3431 R d
3433 R d
3432 $ hg status --copies --rev 'desc("i-2")' --rev 'desc("a-2")'
3434 $ hg status --copies --rev 'desc("i-2")' --rev 'desc("a-2")'
3433 A f
3435 A f
3434 d
3436 d
3435 R d
3437 R d
3436 $ hg status --copies --rev 'desc("i-2")' --rev 'desc("e-2")'
3438 $ hg status --copies --rev 'desc("i-2")' --rev 'desc("e-2")'
3437 A f
3439 A f
3438 b
3440 b
3439 R b
3441 R b
3440
3442
3441 # From here, we run status against revision where both source file exists.
3443 # From here, we run status against revision where both source file exists.
3442 #
3444 #
3443 # The filelog based implementation picks an arbitrary side based on revision
3445 # The filelog based implementation picks an arbitrary side based on revision
3444 # numbers. So the same side "wins" whatever the parents order is. This is
3446 # numbers. So the same side "wins" whatever the parents order is. This is
3445 # sub-optimal because depending on revision numbers means the result can be
3447 # sub-optimal because depending on revision numbers means the result can be
3446 # different from one repository to the next.
3448 # different from one repository to the next.
3447 #
3449 #
3448 # The changeset based algorithm use the parent order to break tie on conflicting
3450 # The changeset based algorithm use the parent order to break tie on conflicting
3449 # information and will have a different order depending on who is p1 and p2.
3451 # information and will have a different order depending on who is p1 and p2.
3450 # That order is stable accross repositories. (data from p1 prevails)
3452 # That order is stable accross repositories. (data from p1 prevails)
3451
3453
3452 $ hg status --copies --rev 'desc("i-2")' --rev 'desc("mAE-change-m-0")'
3454 $ hg status --copies --rev 'desc("i-2")' --rev 'desc("mAE-change-m-0")'
3453 A f
3455 A f
3454 d
3456 d
3455 R b
3457 R b
3456 R d
3458 R d
3457 $ hg status --copies --rev 'desc("i-2")' --rev 'desc("mEA-change-m-0")'
3459 $ hg status --copies --rev 'desc("i-2")' --rev 'desc("mEA-change-m-0")'
3458 A f
3460 A f
3459 d (filelog !)
3461 d (filelog !)
3460 b (no-filelog !)
3462 b (no-filelog !)
3461 R b
3463 R b
3462 R d
3464 R d
3463 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mAE-change-m-0")'
3465 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mAE-change-m-0")'
3464 A f
3466 A f
3465 a
3467 a
3466 A t
3468 A t
3467 p
3469 p
3468 R a
3470 R a
3469 R b
3471 R b
3470 R p
3472 R p
3471 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mEA-change-m-0")'
3473 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mEA-change-m-0")'
3472 A f
3474 A f
3473 a (filelog !)
3475 a (filelog !)
3474 b (no-filelog !)
3476 b (no-filelog !)
3475 A t
3477 A t
3476 p
3478 p
3477 R a
3479 R a
3478 R b
3480 R b
3479 R p
3481 R p
3480
3482
3481
3483
3482 Subcase: merge overwrite common copy information, but with extra change during the merge
3484 Subcase: merge overwrite common copy information, but with extra change during the merge
3483 ```````````````````````````````````````````````````````````````````````````````````
3485 ```````````````````````````````````````````````````````````````````````````````````
3484
3486
3485 Merge:
3487 Merge:
3486 - one with change to an unrelated file (b)
3488 - one with change to an unrelated file (b)
3487 - one overwriting a file (d) with a rename (from h to i to d)
3489 - one overwriting a file (d) with a rename (from h to i to d)
3488
3490
3489 $ hg log -G --rev '::(desc("mBF-change-m")+desc("mFB-change-m"))'
3491 $ hg log -G --rev '::(desc("mBF-change-m")+desc("mFB-change-m"))'
3490 o mFB-change-m-0 merge with extra change - B side: unrelated change, F side: overwrite d with a copy (from h->i->d) - the other way
3492 o mFB-change-m-0 merge with extra change - B side: unrelated change, F side: overwrite d with a copy (from h->i->d) - the other way
3491 |\
3493 |\
3492 +---o mBF-change-m-0 merge with extra change - B side: unrelated change, F side: overwrite d with a copy (from h->i->d) - one way
3494 +---o mBF-change-m-0 merge with extra change - B side: unrelated change, F side: overwrite d with a copy (from h->i->d) - one way
3493 | |/
3495 | |/
3494 | o f-2: rename i -> d
3496 | o f-2: rename i -> d
3495 | |
3497 | |
3496 | o f-1: rename h -> i
3498 | o f-1: rename h -> i
3497 | |
3499 | |
3498 o | b-1: b update
3500 o | b-1: b update
3499 |/
3501 |/
3500 o i-2: c -move-> d, s -move-> t
3502 o i-2: c -move-> d, s -move-> t
3501 |
3503 |
3502 o i-1: a -move-> c, p -move-> s
3504 o i-1: a -move-> c, p -move-> s
3503 |
3505 |
3504 o i-0 initial commit: a b h p q r
3506 o i-0 initial commit: a b h p q r
3505
3507
3506 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mBF-change-m-0")'
3508 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mBF-change-m-0")'
3507 M b
3509 M b
3508 A d
3510 A d
3509 h
3511 h
3510 A t
3512 A t
3511 p
3513 p
3512 R a
3514 R a
3513 R h
3515 R h
3514 R p
3516 R p
3515 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mFB-change-m-0")'
3517 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mFB-change-m-0")'
3516 M b
3518 M b
3517 A d
3519 A d
3518 h
3520 h
3519 A t
3521 A t
3520 p
3522 p
3521 R a
3523 R a
3522 R h
3524 R h
3523 R p
3525 R p
3524 $ hg status --copies --rev 'desc("b-1")' --rev 'desc("mBF-change-m-0")'
3526 $ hg status --copies --rev 'desc("b-1")' --rev 'desc("mBF-change-m-0")'
3525 M d
3527 M d
3526 h (no-filelog !)
3528 h (no-filelog !)
3527 R h
3529 R h
3528 $ hg status --copies --rev 'desc("f-2")' --rev 'desc("mBF-change-m-0")'
3530 $ hg status --copies --rev 'desc("f-2")' --rev 'desc("mBF-change-m-0")'
3529 M b
3531 M b
3530 M d
3532 M d
3531 $ hg status --copies --rev 'desc("f-1")' --rev 'desc("mBF-change-m-0")'
3533 $ hg status --copies --rev 'desc("f-1")' --rev 'desc("mBF-change-m-0")'
3532 M b
3534 M b
3533 M d
3535 M d
3534 i (no-filelog !)
3536 i (no-filelog !)
3535 R i
3537 R i
3536 $ hg status --copies --rev 'desc("b-1")' --rev 'desc("mFB-change-m-0")'
3538 $ hg status --copies --rev 'desc("b-1")' --rev 'desc("mFB-change-m-0")'
3537 M d
3539 M d
3538 h (no-filelog !)
3540 h (no-filelog !)
3539 R h
3541 R h
3540 $ hg status --copies --rev 'desc("f-2")' --rev 'desc("mFB-change-m-0")'
3542 $ hg status --copies --rev 'desc("f-2")' --rev 'desc("mFB-change-m-0")'
3541 M b
3543 M b
3542 M d
3544 M d
3543 $ hg status --copies --rev 'desc("f-1")' --rev 'desc("mFB-change-m-0")'
3545 $ hg status --copies --rev 'desc("f-1")' --rev 'desc("mFB-change-m-0")'
3544 M b
3546 M b
3545 M d
3547 M d
3546 i (no-filelog !)
3548 i (no-filelog !)
3547 R i
3549 R i
3548
3550
3549 #if no-changeset
3551 #if no-changeset
3550 $ hg log -Gfr 'desc("mBF-change-m-0")' d
3552 $ hg log -Gfr 'desc("mBF-change-m-0")' d
3551 o mBF-change-m-0 merge with extra change - B side: unrelated change, F side: overwrite d with a copy (from h->i->d) - one way
3553 o mBF-change-m-0 merge with extra change - B side: unrelated change, F side: overwrite d with a copy (from h->i->d) - one way
3552 |\
3554 |\
3553 o : f-2: rename i -> d
3555 o : f-2: rename i -> d
3554 | :
3556 | :
3555 o : f-1: rename h -> i
3557 o : f-1: rename h -> i
3556 :/
3558 :/
3557 o i-0 initial commit: a b h p q r
3559 o i-0 initial commit: a b h p q r
3558
3560
3559 #else
3561 #else
3560 BROKEN: `hg log --follow <file>` relies on filelog metadata to work
3562 BROKEN: `hg log --follow <file>` relies on filelog metadata to work
3561 $ hg log -Gfr 'desc("mBF-change-m-0")' d
3563 $ hg log -Gfr 'desc("mBF-change-m-0")' d
3562 o mBF-change-m-0 merge with extra change - B side: unrelated change, F side: overwrite d with a copy (from h->i->d) - one way
3564 o mBF-change-m-0 merge with extra change - B side: unrelated change, F side: overwrite d with a copy (from h->i->d) - one way
3563 :
3565 :
3564 o i-2: c -move-> d, s -move-> t
3566 o i-2: c -move-> d, s -move-> t
3565 |
3567 |
3566 ~
3568 ~
3567 #endif
3569 #endif
3568
3570
3569 #if no-changeset
3571 #if no-changeset
3570 $ hg log -Gfr 'desc("mFB-change-m-0")' d
3572 $ hg log -Gfr 'desc("mFB-change-m-0")' d
3571 o mFB-change-m-0 merge with extra change - B side: unrelated change, F side: overwrite d with a copy (from h->i->d) - the other way
3573 o mFB-change-m-0 merge with extra change - B side: unrelated change, F side: overwrite d with a copy (from h->i->d) - the other way
3572 |\
3574 |\
3573 o : f-2: rename i -> d
3575 o : f-2: rename i -> d
3574 | :
3576 | :
3575 o : f-1: rename h -> i
3577 o : f-1: rename h -> i
3576 :/
3578 :/
3577 o i-0 initial commit: a b h p q r
3579 o i-0 initial commit: a b h p q r
3578
3580
3579 #else
3581 #else
3580 BROKEN: `hg log --follow <file>` relies on filelog metadata to work
3582 BROKEN: `hg log --follow <file>` relies on filelog metadata to work
3581 $ hg log -Gfr 'desc("mFB-change-m-0")' d
3583 $ hg log -Gfr 'desc("mFB-change-m-0")' d
3582 o mFB-change-m-0 merge with extra change - B side: unrelated change, F side: overwrite d with a copy (from h->i->d) - the other way
3584 o mFB-change-m-0 merge with extra change - B side: unrelated change, F side: overwrite d with a copy (from h->i->d) - the other way
3583 :
3585 :
3584 o i-2: c -move-> d, s -move-> t
3586 o i-2: c -move-> d, s -move-> t
3585 |
3587 |
3586 ~
3588 ~
3587 #endif
3589 #endif
3588
3590
3589
3591
3590 Subcase: restoring and untouched deleted file, while touching it
3592 Subcase: restoring and untouched deleted file, while touching it
3591 ````````````````````````````````````````````````````````````````
3593 ````````````````````````````````````````````````````````````````
3592
3594
3593 Merge:
3595 Merge:
3594 - one removing a file (d)
3596 - one removing a file (d)
3595 - one leaving the file untouched
3597 - one leaving the file untouched
3596 - the merge actively restore the file to the same content.
3598 - the merge actively restore the file to the same content.
3597
3599
3598 In this case, the file keep on living after the merge. So we should not drop its
3600 In this case, the file keep on living after the merge. So we should not drop its
3599 copy tracing chain.
3601 copy tracing chain.
3600
3602
3601 $ hg log -G --rev '::(desc("mCB-change-m")+desc("mBC-change-m"))'
3603 $ hg log -G --rev '::(desc("mCB-change-m")+desc("mBC-change-m"))'
3602 o mBC-change-m-0 merge explicitely revive deleted file - B side: unrelated change, C side: delete d (restored by merge) - the other way
3604 o mBC-change-m-0 merge explicitely revive deleted file - B side: unrelated change, C side: delete d (restored by merge) - the other way
3603 |\
3605 |\
3604 +---o mCB-change-m-0 merge explicitely revive deleted file - B side: unrelated change, C side: delete d (restored by merge) - one way
3606 +---o mCB-change-m-0 merge explicitely revive deleted file - B side: unrelated change, C side: delete d (restored by merge) - one way
3605 | |/
3607 | |/
3606 | o c-1 delete d
3608 | o c-1 delete d
3607 | |
3609 | |
3608 o | b-1: b update
3610 o | b-1: b update
3609 |/
3611 |/
3610 o i-2: c -move-> d, s -move-> t
3612 o i-2: c -move-> d, s -move-> t
3611 |
3613 |
3612 o i-1: a -move-> c, p -move-> s
3614 o i-1: a -move-> c, p -move-> s
3613 |
3615 |
3614 o i-0 initial commit: a b h p q r
3616 o i-0 initial commit: a b h p q r
3615
3617
3616
3618
3617 'a' is the the copy source of 'd'
3619 'a' is the the copy source of 'd'
3618
3620
3619 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mCB-change-m-0")'
3621 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mCB-change-m-0")'
3620 M b
3622 M b
3621 A d
3623 A d
3622 a (no-compatibility no-changeset !)
3624 a (no-compatibility no-changeset !)
3623 A t
3625 A t
3624 p
3626 p
3625 R a
3627 R a
3626 R p
3628 R p
3627 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mBC-change-m-0")'
3629 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mBC-change-m-0")'
3628 M b
3630 M b
3629 A d
3631 A d
3630 a (no-compatibility no-changeset !)
3632 a (no-compatibility no-changeset !)
3631 A t
3633 A t
3632 p
3634 p
3633 R a
3635 R a
3634 R p
3636 R p
3635 $ hg status --copies --rev 'desc("c-1")' --rev 'desc("mCB-change-m-0")'
3637 $ hg status --copies --rev 'desc("c-1")' --rev 'desc("mCB-change-m-0")'
3636 M b
3638 M b
3637 A d
3639 A d
3638 $ hg status --copies --rev 'desc("c-1")' --rev 'desc("mBC-change-m-0")'
3640 $ hg status --copies --rev 'desc("c-1")' --rev 'desc("mBC-change-m-0")'
3639 M b
3641 M b
3640 A d
3642 A d
3641 $ hg status --copies --rev 'desc("b-1")' --rev 'desc("mCB-change-m-0")'
3643 $ hg status --copies --rev 'desc("b-1")' --rev 'desc("mCB-change-m-0")'
3642 M d
3644 M d
3643 $ hg status --copies --rev 'desc("b-1")' --rev 'desc("mBC-change-m-0")'
3645 $ hg status --copies --rev 'desc("b-1")' --rev 'desc("mBC-change-m-0")'
3644 M d
3646 M d
3645
3647
3646
3648
3647 Decision from previous merge are properly chained with later merge
3649 Decision from previous merge are properly chained with later merge
3648 ------------------------------------------------------------------
3650 ------------------------------------------------------------------
3649
3651
3650
3652
3651 Subcase: chaining conflicting rename resolution
3653 Subcase: chaining conflicting rename resolution
3652 ```````````````````````````````````````````````
3654 ```````````````````````````````````````````````
3653
3655
3654 The "mAEm" and "mEAm" case create a rename tracking conflict on file 'f'. We
3656 The "mAEm" and "mEAm" case create a rename tracking conflict on file 'f'. We
3655 add more change on the respective branch and merge again. These second merge
3657 add more change on the respective branch and merge again. These second merge
3656 does not involve the file 'f' and the arbitration done within "mAEm" and "mEA"
3658 does not involve the file 'f' and the arbitration done within "mAEm" and "mEA"
3657 about that file should stay unchanged.
3659 about that file should stay unchanged.
3658
3660
3659 The result from mAEm is the same for the subsequent merge:
3661 The result from mAEm is the same for the subsequent merge:
3660
3662
3661 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mAEm")' f
3663 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mAEm")' f
3662 A f
3664 A f
3663 a (no-changeset no-compatibility !)
3665 a (no-changeset no-compatibility !)
3664
3666
3665 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mAE,Km")' f
3667 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mAE,Km")' f
3666 A f
3668 A f
3667 a (no-changeset no-compatibility !)
3669 a (no-changeset no-compatibility !)
3668
3670
3669 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mK,AEm")' f
3671 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mK,AEm")' f
3670 A f
3672 A f
3671 a (no-changeset no-compatibility !)
3673 a (no-changeset no-compatibility !)
3672
3674
3673
3675
3674 The result from mEAm is the same for the subsequent merge:
3676 The result from mEAm is the same for the subsequent merge:
3675
3677
3676 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mEAm")' f
3678 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mEAm")' f
3677 A f
3679 A f
3678 a (filelog !)
3680 a (filelog !)
3679 b (no-changeset no-compatibility no-filelog !)
3681 b (no-changeset no-compatibility no-filelog !)
3680
3682
3681 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mEA,Jm")' f
3683 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mEA,Jm")' f
3682 A f
3684 A f
3683 a (filelog !)
3685 a (filelog !)
3684 b (no-changeset no-compatibility no-filelog !)
3686 b (no-changeset no-compatibility no-filelog !)
3685
3687
3686 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mJ,EAm")' f
3688 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mJ,EAm")' f
3687 A f
3689 A f
3688 a (filelog !)
3690 a (filelog !)
3689 b (no-changeset no-compatibility no-filelog !)
3691 b (no-changeset no-compatibility no-filelog !)
3690
3692
3691 Subcase: chaining conflicting rename resolution
3693 Subcase: chaining conflicting rename resolution
3692 ```````````````````````````````````````````````
3694 ```````````````````````````````````````````````
3693
3695
3694 The "mPQm" and "mQPm" case create a rename tracking conflict on file 'v'. We
3696 The "mPQm" and "mQPm" case create a rename tracking conflict on file 'v'. We
3695 add more change on the respective branch and merge again. These second merge
3697 add more change on the respective branch and merge again. These second merge
3696 does not involve the file 'v' and the arbitration done within "mPQm" and "mQP"
3698 does not involve the file 'v' and the arbitration done within "mPQm" and "mQP"
3697 about that file should stay unchanged.
3699 about that file should stay unchanged.
3698
3700
3699 The result from mPQm is the same for the subsequent merge:
3701 The result from mPQm is the same for the subsequent merge:
3700
3702
3701 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mPQm")' v
3703 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mPQm")' v
3702 A v
3704 A v
3703 r (filelog !)
3705 r (filelog !)
3704 p (no-changeset no-compatibility no-filelog !)
3706 p (no-changeset no-compatibility no-filelog !)
3705
3707
3706 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mPQ,Tm")' v
3708 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mPQ,Tm")' v
3707 A v
3709 A v
3708 r (filelog !)
3710 r (filelog !)
3709 p (no-changeset no-compatibility no-filelog !)
3711 p (no-changeset no-compatibility no-filelog !)
3710
3712
3711 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mT,PQm")' v
3713 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mT,PQm")' v
3712 A v
3714 A v
3713 r (filelog !)
3715 r (filelog !)
3714 p (no-changeset no-compatibility no-filelog !)
3716 p (no-changeset no-compatibility no-filelog !)
3715
3717
3716 The result from mQPm is the same for the subsequent merge:
3718 The result from mQPm is the same for the subsequent merge:
3717
3719
3718 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mQPm")' v
3720 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mQPm")' v
3719 A v
3721 A v
3720 r (no-changeset no-compatibility !)
3722 r (no-changeset no-compatibility !)
3721
3723
3722 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mQP,Sm")' v
3724 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mQP,Sm")' v
3723 A v
3725 A v
3724 r (no-changeset no-compatibility !)
3726 r (no-changeset no-compatibility !)
3725
3727
3726 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mS,QPm")' v
3728 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mS,QPm")' v
3727 A v
3729 A v
3728 r (filelog !)
3730 r (filelog !)
3729 r (no-changeset no-compatibility no-filelog !)
3731 r (no-changeset no-compatibility no-filelog !)
3730
3732
3731
3733
3732 Subcase: chaining salvage information during a merge
3734 Subcase: chaining salvage information during a merge
3733 ````````````````````````````````````````````````````
3735 ````````````````````````````````````````````````````
3734
3736
3735 We add more change on the branch were the file was deleted. merging again
3737 We add more change on the branch were the file was deleted. merging again
3736 should preserve the fact eh file was salvaged.
3738 should preserve the fact eh file was salvaged.
3737
3739
3738 reference output:
3740 reference output:
3739
3741
3740 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mCB-revert-m-0")'
3742 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mCB-revert-m-0")'
3741 M b
3743 M b
3742 A d
3744 A d
3743 a (no-changeset no-compatibility !)
3745 a (no-changeset no-compatibility !)
3744 A t
3746 A t
3745 p
3747 p
3746 R a
3748 R a
3747 R p
3749 R p
3748 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mBC-revert-m-0")'
3750 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mBC-revert-m-0")'
3749 M b
3751 M b
3750 A d
3752 A d
3751 a (no-changeset no-compatibility !)
3753 a (no-changeset no-compatibility !)
3752 A t
3754 A t
3753 p
3755 p
3754 R a
3756 R a
3755 R p
3757 R p
3756
3758
3757 chained output
3759 chained output
3758 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mBC+revert,Lm")'
3760 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mBC+revert,Lm")'
3759 M b
3761 M b
3760 A d
3762 A d
3761 a (no-changeset no-compatibility !)
3763 a (no-changeset no-compatibility !)
3762 A t
3764 A t
3763 p
3765 p
3764 A unrelated-l
3766 A unrelated-l
3765 R a
3767 R a
3766 R p
3768 R p
3767 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mCB+revert,Lm")'
3769 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mCB+revert,Lm")'
3768 M b
3770 M b
3769 A d
3771 A d
3770 a (no-changeset no-compatibility !)
3772 a (no-changeset no-compatibility !)
3771 A t
3773 A t
3772 p
3774 p
3773 A unrelated-l
3775 A unrelated-l
3774 R a
3776 R a
3775 R p
3777 R p
3776 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mL,BC+revertm")'
3778 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mL,BC+revertm")'
3777 M b
3779 M b
3778 A d
3780 A d
3779 a (no-changeset no-compatibility !)
3781 a (no-changeset no-compatibility !)
3780 A t
3782 A t
3781 p
3783 p
3782 A unrelated-l
3784 A unrelated-l
3783 R a
3785 R a
3784 R p
3786 R p
3785 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mL,CB+revertm")'
3787 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mL,CB+revertm")'
3786 M b
3788 M b
3787 A d
3789 A d
3788 a (no-changeset no-compatibility !)
3790 a (no-changeset no-compatibility !)
3789 A t
3791 A t
3790 p
3792 p
3791 A unrelated-l
3793 A unrelated-l
3792 R a
3794 R a
3793 R p
3795 R p
3794
3796
3795 Subcase: chaining "merged" information during a merge
3797 Subcase: chaining "merged" information during a merge
3796 ``````````````````````````````````````````````````````
3798 ``````````````````````````````````````````````````````
3797
3799
3798 When a non-rename change are merged with a copy overwrite, the merge pick the copy source from (p1) as the reference. We should preserve this information in subsequent merges.
3800 When a non-rename change are merged with a copy overwrite, the merge pick the copy source from (p1) as the reference. We should preserve this information in subsequent merges.
3799
3801
3800
3802
3801 reference output:
3803 reference output:
3802
3804
3803 (for details about the filelog pick, check the mFGm/mGFm case)
3805 (for details about the filelog pick, check the mFGm/mGFm case)
3804
3806
3805 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mFGm")' d
3807 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mFGm")' d
3806 A d
3808 A d
3807 a (filelog !)
3809 a (filelog !)
3808 h (no-changeset no-compatibility no-filelog !)
3810 h (no-changeset no-compatibility no-filelog !)
3809 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mGFm")' d
3811 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mGFm")' d
3810 A d
3812 A d
3811 a (filelog !)
3813 a (filelog !)
3812 a (no-changeset no-compatibility no-filelog !)
3814 a (no-changeset no-compatibility no-filelog !)
3813
3815
3814 Chained output
3816 Chained output
3815
3817
3816 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mO,FGm")' d
3818 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mO,FGm")' d
3817 A d
3819 A d
3818 a (filelog !)
3820 a (filelog !)
3819 h (no-changeset no-compatibility no-filelog !)
3821 h (no-changeset no-compatibility no-filelog !)
3820 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mFG,Om")' d
3822 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mFG,Om")' d
3821 A d
3823 A d
3822 a (filelog !)
3824 a (filelog !)
3823 h (no-changeset no-compatibility no-filelog !)
3825 h (no-changeset no-compatibility no-filelog !)
3824
3826
3825
3827
3826 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mGF,Nm")' d
3828 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mGF,Nm")' d
3827 A d
3829 A d
3828 a (no-changeset no-compatibility !)
3830 a (no-changeset no-compatibility !)
3829 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mN,GFm")' d
3831 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mN,GFm")' d
3830 A d
3832 A d
3831 a (no-changeset no-compatibility !)
3833 a (no-changeset no-compatibility !)
3832
3834
3833
3835
3834 Subcase: chaining conflicting rename resolution, with extra change during the merge
3836 Subcase: chaining conflicting rename resolution, with extra change during the merge
3835 ```````````````````````````````````````````````````````````````````````````````````
3837 ```````````````````````````````````````````````````````````````````````````````````
3836
3838
3837 The "mAEm" and "mEAm" case create a rename tracking conflict on file 'f'. We
3839 The "mAEm" and "mEAm" case create a rename tracking conflict on file 'f'. We
3838 add more change on the respective branch and merge again. These second merge
3840 add more change on the respective branch and merge again. These second merge
3839 does not involve the file 'f' and the arbitration done within "mAEm" and "mEA"
3841 does not involve the file 'f' and the arbitration done within "mAEm" and "mEA"
3840 about that file should stay unchanged.
3842 about that file should stay unchanged.
3841
3843
3842 The result from mAEm is the same for the subsequent merge:
3844 The result from mAEm is the same for the subsequent merge:
3843
3845
3844 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mAE-change-m")' f
3846 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mAE-change-m")' f
3845 A f
3847 A f
3846 a (no-changeset no-compatibility !)
3848 a (no-changeset no-compatibility !)
3847
3849
3848 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mAE-change,Km")' f
3850 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mAE-change,Km")' f
3849 A f
3851 A f
3850 a (no-changeset no-compatibility !)
3852 a (no-changeset no-compatibility !)
3851
3853
3852 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mK,AE-change-m")' f
3854 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mK,AE-change-m")' f
3853 A f
3855 A f
3854 a (no-changeset no-compatibility !)
3856 a (no-changeset no-compatibility !)
3855
3857
3856
3858
3857 The result from mEAm is the same for the subsequent merge:
3859 The result from mEAm is the same for the subsequent merge:
3858
3860
3859 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mEA-change-m")' f
3861 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mEA-change-m")' f
3860 A f
3862 A f
3861 a (filelog !)
3863 a (filelog !)
3862 b (no-changeset no-compatibility no-filelog !)
3864 b (no-changeset no-compatibility no-filelog !)
3863
3865
3864 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mEA-change,Jm")' f
3866 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mEA-change,Jm")' f
3865 A f
3867 A f
3866 a (filelog !)
3868 a (filelog !)
3867 b (no-changeset no-compatibility no-filelog !)
3869 b (no-changeset no-compatibility no-filelog !)
3868
3870
3869 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mJ,EA-change-m")' f
3871 $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mJ,EA-change-m")' f
3870 A f
3872 A f
3871 a (filelog !)
3873 a (filelog !)
3872 b (no-changeset no-compatibility no-filelog !)
3874 b (no-changeset no-compatibility no-filelog !)
@@ -1,509 +1,514 b''
1 #testcases extra sidedata
1 #testcases extra sidedata
2
2
3 #if extra
3 #if extra
4 $ cat >> $HGRCPATH << EOF
4 $ cat >> $HGRCPATH << EOF
5 > [experimental]
5 > [experimental]
6 > copies.write-to=changeset-only
6 > copies.write-to=changeset-only
7 > copies.read-from=changeset-only
7 > copies.read-from=changeset-only
8 > [alias]
8 > [alias]
9 > changesetcopies = log -r . -T 'files: {files}
9 > changesetcopies = log -r . -T 'files: {files}
10 > {extras % "{ifcontains("files", key, "{key}: {value}\n")}"}
10 > {extras % "{ifcontains("files", key, "{key}: {value}\n")}"}
11 > {extras % "{ifcontains("copies", key, "{key}: {value}\n")}"}'
11 > {extras % "{ifcontains("copies", key, "{key}: {value}\n")}"}'
12 > EOF
12 > EOF
13 #endif
13 #endif
14
14
15 #if sidedata
15 #if sidedata
16 $ cat >> $HGRCPATH << EOF
16 $ cat >> $HGRCPATH << EOF
17 > [format]
17 > [format]
18 > exp-use-copies-side-data-changeset = yes
18 > exp-use-copies-side-data-changeset = yes
19 > EOF
19 > EOF
20 #endif
20 #endif
21
21
22 $ cat >> $HGRCPATH << EOF
22 $ cat >> $HGRCPATH << EOF
23 > [alias]
23 > [alias]
24 > showcopies = log -r . -T '{file_copies % "{source} -> {name}\n"}'
24 > showcopies = log -r . -T '{file_copies % "{source} -> {name}\n"}'
25 > [extensions]
25 > [extensions]
26 > rebase =
26 > rebase =
27 > split =
27 > split =
28 > EOF
28 > EOF
29
29
30 Check that copies are recorded correctly
30 Check that copies are recorded correctly
31
31
32 $ hg init repo
32 $ hg init repo
33 $ cd repo
33 $ cd repo
34 #if sidedata
34 #if sidedata
35 $ hg debugformat -v
35 $ hg debugformat -v
36 format-variant repo config default
36 format-variant repo config default
37 fncache: yes yes yes
37 fncache: yes yes yes
38 dirstate-v2: no no no
38 dotencode: yes yes yes
39 dotencode: yes yes yes
39 generaldelta: yes yes yes
40 generaldelta: yes yes yes
40 share-safe: no no no
41 share-safe: no no no
41 sparserevlog: yes yes yes
42 sparserevlog: yes yes yes
42 persistent-nodemap: no no no (no-rust !)
43 persistent-nodemap: no no no (no-rust !)
43 persistent-nodemap: yes yes no (rust !)
44 persistent-nodemap: yes yes no (rust !)
44 copies-sdc: yes yes no
45 copies-sdc: yes yes no
45 revlog-v2: no no no
46 revlog-v2: no no no
46 changelog-v2: yes yes no
47 changelog-v2: yes yes no
47 plain-cl-delta: yes yes yes
48 plain-cl-delta: yes yes yes
48 compression: zlib zlib zlib (no-zstd !)
49 compression: zlib zlib zlib (no-zstd !)
49 compression: zstd zstd zstd (zstd !)
50 compression: zstd zstd zstd (zstd !)
50 compression-level: default default default
51 compression-level: default default default
51 #else
52 #else
52 $ hg debugformat -v
53 $ hg debugformat -v
53 format-variant repo config default
54 format-variant repo config default
54 fncache: yes yes yes
55 fncache: yes yes yes
56 dirstate-v2: no no no
55 dotencode: yes yes yes
57 dotencode: yes yes yes
56 generaldelta: yes yes yes
58 generaldelta: yes yes yes
57 share-safe: no no no
59 share-safe: no no no
58 sparserevlog: yes yes yes
60 sparserevlog: yes yes yes
59 persistent-nodemap: no no no (no-rust !)
61 persistent-nodemap: no no no (no-rust !)
60 persistent-nodemap: yes yes no (rust !)
62 persistent-nodemap: yes yes no (rust !)
61 copies-sdc: no no no
63 copies-sdc: no no no
62 revlog-v2: no no no
64 revlog-v2: no no no
63 changelog-v2: no no no
65 changelog-v2: no no no
64 plain-cl-delta: yes yes yes
66 plain-cl-delta: yes yes yes
65 compression: zlib zlib zlib (no-zstd !)
67 compression: zlib zlib zlib (no-zstd !)
66 compression: zstd zstd zstd (zstd !)
68 compression: zstd zstd zstd (zstd !)
67 compression-level: default default default
69 compression-level: default default default
68 #endif
70 #endif
69 $ echo a > a
71 $ echo a > a
70 $ hg add a
72 $ hg add a
71 $ hg ci -m initial
73 $ hg ci -m initial
72 $ hg cp a b
74 $ hg cp a b
73 $ hg cp a c
75 $ hg cp a c
74 $ hg cp a d
76 $ hg cp a d
75 $ hg ci -m 'copy a to b, c, and d'
77 $ hg ci -m 'copy a to b, c, and d'
76
78
77 #if extra
79 #if extra
78
80
79 $ hg changesetcopies
81 $ hg changesetcopies
80 files: b c d
82 files: b c d
81 filesadded: 0
83 filesadded: 0
82 1
84 1
83 2
85 2
84
86
85 p1copies: 0\x00a (esc)
87 p1copies: 0\x00a (esc)
86 1\x00a (esc)
88 1\x00a (esc)
87 2\x00a (esc)
89 2\x00a (esc)
88 #else
90 #else
89 $ hg debugsidedata -c -v -- -1
91 $ hg debugsidedata -c -v -- -1
90 1 sidedata entries
92 1 sidedata entries
91 entry-0014 size 44
93 entry-0014 size 44
92 '\x00\x00\x00\x04\x00\x00\x00\x00\x01\x00\x00\x00\x00\x06\x00\x00\x00\x02\x00\x00\x00\x00\x06\x00\x00\x00\x03\x00\x00\x00\x00\x06\x00\x00\x00\x04\x00\x00\x00\x00abcd'
94 '\x00\x00\x00\x04\x00\x00\x00\x00\x01\x00\x00\x00\x00\x06\x00\x00\x00\x02\x00\x00\x00\x00\x06\x00\x00\x00\x03\x00\x00\x00\x00\x06\x00\x00\x00\x04\x00\x00\x00\x00abcd'
93 #endif
95 #endif
94
96
95 $ hg showcopies
97 $ hg showcopies
96 a -> b
98 a -> b
97 a -> c
99 a -> c
98 a -> d
100 a -> d
99
101
100 #if extra
102 #if extra
101
103
102 $ hg showcopies --config experimental.copies.read-from=compatibility
104 $ hg showcopies --config experimental.copies.read-from=compatibility
103 a -> b
105 a -> b
104 a -> c
106 a -> c
105 a -> d
107 a -> d
106 $ hg showcopies --config experimental.copies.read-from=filelog-only
108 $ hg showcopies --config experimental.copies.read-from=filelog-only
107
109
108 #endif
110 #endif
109
111
110 Check that renames are recorded correctly
112 Check that renames are recorded correctly
111
113
112 $ hg mv b b2
114 $ hg mv b b2
113 $ hg ci -m 'rename b to b2'
115 $ hg ci -m 'rename b to b2'
114
116
115 #if extra
117 #if extra
116
118
117 $ hg changesetcopies
119 $ hg changesetcopies
118 files: b b2
120 files: b b2
119 filesadded: 1
121 filesadded: 1
120 filesremoved: 0
122 filesremoved: 0
121
123
122 p1copies: 1\x00b (esc)
124 p1copies: 1\x00b (esc)
123
125
124 #else
126 #else
125 $ hg debugsidedata -c -v -- -1
127 $ hg debugsidedata -c -v -- -1
126 1 sidedata entries
128 1 sidedata entries
127 entry-0014 size 25
129 entry-0014 size 25
128 '\x00\x00\x00\x02\x0c\x00\x00\x00\x01\x00\x00\x00\x00\x06\x00\x00\x00\x03\x00\x00\x00\x00bb2'
130 '\x00\x00\x00\x02\x0c\x00\x00\x00\x01\x00\x00\x00\x00\x06\x00\x00\x00\x03\x00\x00\x00\x00bb2'
129 #endif
131 #endif
130
132
131 $ hg showcopies
133 $ hg showcopies
132 b -> b2
134 b -> b2
133
135
134
136
135 Rename onto existing file. This should get recorded in the changeset files list and in the extras,
137 Rename onto existing file. This should get recorded in the changeset files list and in the extras,
136 even though there is no filelog entry.
138 even though there is no filelog entry.
137
139
138 $ hg cp b2 c --force
140 $ hg cp b2 c --force
139 $ hg st --copies
141 $ hg st --copies
140 M c
142 M c
141 b2
143 b2
142
144
143 #if extra
145 #if extra
144
146
145 $ hg debugindex c
147 $ hg debugindex c
146 rev linkrev nodeid p1 p2
148 rev linkrev nodeid p1 p2
147 0 1 b789fdd96dc2 000000000000 000000000000
149 0 1 b789fdd96dc2 000000000000 000000000000
148
150
149 #else
151 #else
150
152
151 $ hg debugindex c
153 $ hg debugindex c
152 rev linkrev nodeid p1 p2
154 rev linkrev nodeid p1 p2
153 0 1 37d9b5d994ea 000000000000 000000000000
155 0 1 37d9b5d994ea 000000000000 000000000000
154
156
155 #endif
157 #endif
156
158
157
159
158 $ hg ci -m 'move b onto d'
160 $ hg ci -m 'move b onto d'
159
161
160 #if extra
162 #if extra
161
163
162 $ hg changesetcopies
164 $ hg changesetcopies
163 files: c
165 files: c
164
166
165 p1copies: 0\x00b2 (esc)
167 p1copies: 0\x00b2 (esc)
166
168
167 #else
169 #else
168 $ hg debugsidedata -c -v -- -1
170 $ hg debugsidedata -c -v -- -1
169 1 sidedata entries
171 1 sidedata entries
170 entry-0014 size 25
172 entry-0014 size 25
171 '\x00\x00\x00\x02\x00\x00\x00\x00\x02\x00\x00\x00\x00\x16\x00\x00\x00\x03\x00\x00\x00\x00b2c'
173 '\x00\x00\x00\x02\x00\x00\x00\x00\x02\x00\x00\x00\x00\x16\x00\x00\x00\x03\x00\x00\x00\x00b2c'
172 #endif
174 #endif
173
175
174 $ hg showcopies
176 $ hg showcopies
175 b2 -> c
177 b2 -> c
176
178
177 #if extra
179 #if extra
178
180
179 $ hg debugindex c
181 $ hg debugindex c
180 rev linkrev nodeid p1 p2
182 rev linkrev nodeid p1 p2
181 0 1 b789fdd96dc2 000000000000 000000000000
183 0 1 b789fdd96dc2 000000000000 000000000000
182
184
183 #else
185 #else
184
186
185 $ hg debugindex c
187 $ hg debugindex c
186 rev linkrev nodeid p1 p2
188 rev linkrev nodeid p1 p2
187 0 1 37d9b5d994ea 000000000000 000000000000
189 0 1 37d9b5d994ea 000000000000 000000000000
188 1 3 029625640347 000000000000 000000000000
190 1 3 029625640347 000000000000 000000000000
189
191
190 #endif
192 #endif
191
193
192 Create a merge commit with copying done during merge.
194 Create a merge commit with copying done during merge.
193
195
194 $ hg co 0
196 $ hg co 0
195 0 files updated, 0 files merged, 3 files removed, 0 files unresolved
197 0 files updated, 0 files merged, 3 files removed, 0 files unresolved
196 $ hg cp a e
198 $ hg cp a e
197 $ hg cp a f
199 $ hg cp a f
198 $ hg ci -m 'copy a to e and f'
200 $ hg ci -m 'copy a to e and f'
199 created new head
201 created new head
200 $ hg merge 3
202 $ hg merge 3
201 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
203 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
202 (branch merge, don't forget to commit)
204 (branch merge, don't forget to commit)
203 File 'a' exists on both sides, so 'g' could be recorded as being from p1 or p2, but we currently
205 File 'a' exists on both sides, so 'g' could be recorded as being from p1 or p2, but we currently
204 always record it as being from p1
206 always record it as being from p1
205 $ hg cp a g
207 $ hg cp a g
206 File 'd' exists only in p2, so 'h' should be from p2
208 File 'd' exists only in p2, so 'h' should be from p2
207 $ hg cp d h
209 $ hg cp d h
208 File 'f' exists only in p1, so 'i' should be from p1
210 File 'f' exists only in p1, so 'i' should be from p1
209 $ hg cp f i
211 $ hg cp f i
210 $ hg ci -m 'merge'
212 $ hg ci -m 'merge'
211
213
212 #if extra
214 #if extra
213
215
214 $ hg changesetcopies
216 $ hg changesetcopies
215 files: g h i
217 files: g h i
216 filesadded: 0
218 filesadded: 0
217 1
219 1
218 2
220 2
219
221
220 p1copies: 0\x00a (esc)
222 p1copies: 0\x00a (esc)
221 2\x00f (esc)
223 2\x00f (esc)
222 p2copies: 1\x00d (esc)
224 p2copies: 1\x00d (esc)
223
225
224 #else
226 #else
225 $ hg debugsidedata -c -v -- -1
227 $ hg debugsidedata -c -v -- -1
226 1 sidedata entries
228 1 sidedata entries
227 entry-0014 size 64
229 entry-0014 size 64
228 '\x00\x00\x00\x06\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\x00\x03\x00\x00\x00\x00\x06\x00\x00\x00\x04\x00\x00\x00\x00\x07\x00\x00\x00\x05\x00\x00\x00\x01\x06\x00\x00\x00\x06\x00\x00\x00\x02adfghi'
230 '\x00\x00\x00\x06\x00\x00\x00\x00\x01\x00\x00\x00\x00\x00\x00\x00\x00\x02\x00\x00\x00\x00\x00\x00\x00\x00\x03\x00\x00\x00\x00\x06\x00\x00\x00\x04\x00\x00\x00\x00\x07\x00\x00\x00\x05\x00\x00\x00\x01\x06\x00\x00\x00\x06\x00\x00\x00\x02adfghi'
229 #endif
231 #endif
230
232
231 $ hg showcopies
233 $ hg showcopies
232 a -> g
234 a -> g
233 d -> h
235 d -> h
234 f -> i
236 f -> i
235
237
236 Test writing to both changeset and filelog
238 Test writing to both changeset and filelog
237
239
238 $ hg cp a j
240 $ hg cp a j
239 #if extra
241 #if extra
240 $ hg ci -m 'copy a to j' --config experimental.copies.write-to=compatibility
242 $ hg ci -m 'copy a to j' --config experimental.copies.write-to=compatibility
241 $ hg changesetcopies
243 $ hg changesetcopies
242 files: j
244 files: j
243 filesadded: 0
245 filesadded: 0
244 filesremoved:
246 filesremoved:
245
247
246 p1copies: 0\x00a (esc)
248 p1copies: 0\x00a (esc)
247 p2copies:
249 p2copies:
248 #else
250 #else
249 $ hg ci -m 'copy a to j'
251 $ hg ci -m 'copy a to j'
250 $ hg debugsidedata -c -v -- -1
252 $ hg debugsidedata -c -v -- -1
251 1 sidedata entries
253 1 sidedata entries
252 entry-0014 size 24
254 entry-0014 size 24
253 '\x00\x00\x00\x02\x00\x00\x00\x00\x01\x00\x00\x00\x00\x06\x00\x00\x00\x02\x00\x00\x00\x00aj'
255 '\x00\x00\x00\x02\x00\x00\x00\x00\x01\x00\x00\x00\x00\x06\x00\x00\x00\x02\x00\x00\x00\x00aj'
254 #endif
256 #endif
255 $ hg debugdata j 0
257 $ hg debugdata j 0
256 \x01 (esc)
258 \x01 (esc)
257 copy: a
259 copy: a
258 copyrev: b789fdd96dc2f3bd229c1dd8eedf0fc60e2b68e3
260 copyrev: b789fdd96dc2f3bd229c1dd8eedf0fc60e2b68e3
259 \x01 (esc)
261 \x01 (esc)
260 a
262 a
261 $ hg showcopies
263 $ hg showcopies
262 a -> j
264 a -> j
263 $ hg showcopies --config experimental.copies.read-from=compatibility
265 $ hg showcopies --config experimental.copies.read-from=compatibility
264 a -> j
266 a -> j
265 $ hg showcopies --config experimental.copies.read-from=filelog-only
267 $ hg showcopies --config experimental.copies.read-from=filelog-only
266 a -> j
268 a -> j
267 Existing copy information in the changeset gets removed on amend and writing
269 Existing copy information in the changeset gets removed on amend and writing
268 copy information on to the filelog
270 copy information on to the filelog
269 #if extra
271 #if extra
270 $ hg ci --amend -m 'copy a to j, v2' \
272 $ hg ci --amend -m 'copy a to j, v2' \
271 > --config experimental.copies.write-to=filelog-only
273 > --config experimental.copies.write-to=filelog-only
272 saved backup bundle to $TESTTMP/repo/.hg/strip-backup/*-*-amend.hg (glob)
274 saved backup bundle to $TESTTMP/repo/.hg/strip-backup/*-*-amend.hg (glob)
273 $ hg changesetcopies
275 $ hg changesetcopies
274 files: j
276 files: j
275
277
276 #else
278 #else
277 $ hg ci --amend -m 'copy a to j, v2'
279 $ hg ci --amend -m 'copy a to j, v2'
278 saved backup bundle to $TESTTMP/repo/.hg/strip-backup/*-*-amend.hg (glob)
280 saved backup bundle to $TESTTMP/repo/.hg/strip-backup/*-*-amend.hg (glob)
279 $ hg debugsidedata -c -v -- -1
281 $ hg debugsidedata -c -v -- -1
280 1 sidedata entries
282 1 sidedata entries
281 entry-0014 size 24
283 entry-0014 size 24
282 '\x00\x00\x00\x02\x00\x00\x00\x00\x01\x00\x00\x00\x00\x06\x00\x00\x00\x02\x00\x00\x00\x00aj'
284 '\x00\x00\x00\x02\x00\x00\x00\x00\x01\x00\x00\x00\x00\x06\x00\x00\x00\x02\x00\x00\x00\x00aj'
283 #endif
285 #endif
284 $ hg showcopies --config experimental.copies.read-from=filelog-only
286 $ hg showcopies --config experimental.copies.read-from=filelog-only
285 a -> j
287 a -> j
286 The entries should be written to extras even if they're empty (so the client
288 The entries should be written to extras even if they're empty (so the client
287 won't have to fall back to reading from filelogs)
289 won't have to fall back to reading from filelogs)
288 $ echo x >> j
290 $ echo x >> j
289 #if extra
291 #if extra
290 $ hg ci -m 'modify j' --config experimental.copies.write-to=compatibility
292 $ hg ci -m 'modify j' --config experimental.copies.write-to=compatibility
291 $ hg changesetcopies
293 $ hg changesetcopies
292 files: j
294 files: j
293 filesadded:
295 filesadded:
294 filesremoved:
296 filesremoved:
295
297
296 p1copies:
298 p1copies:
297 p2copies:
299 p2copies:
298 #else
300 #else
299 $ hg ci -m 'modify j'
301 $ hg ci -m 'modify j'
300 $ hg debugsidedata -c -v -- -1
302 $ hg debugsidedata -c -v -- -1
301 1 sidedata entries
303 1 sidedata entries
302 entry-0014 size 14
304 entry-0014 size 14
303 '\x00\x00\x00\x01\x14\x00\x00\x00\x01\x00\x00\x00\x00j'
305 '\x00\x00\x00\x01\x14\x00\x00\x00\x01\x00\x00\x00\x00j'
304 #endif
306 #endif
305
307
306 Test writing only to filelog
308 Test writing only to filelog
307
309
308 $ hg cp a k
310 $ hg cp a k
309 #if extra
311 #if extra
310 $ hg ci -m 'copy a to k' --config experimental.copies.write-to=filelog-only
312 $ hg ci -m 'copy a to k' --config experimental.copies.write-to=filelog-only
311
313
312 $ hg changesetcopies
314 $ hg changesetcopies
313 files: k
315 files: k
314
316
315 #else
317 #else
316 $ hg ci -m 'copy a to k'
318 $ hg ci -m 'copy a to k'
317 $ hg debugsidedata -c -v -- -1
319 $ hg debugsidedata -c -v -- -1
318 1 sidedata entries
320 1 sidedata entries
319 entry-0014 size 24
321 entry-0014 size 24
320 '\x00\x00\x00\x02\x00\x00\x00\x00\x01\x00\x00\x00\x00\x06\x00\x00\x00\x02\x00\x00\x00\x00ak'
322 '\x00\x00\x00\x02\x00\x00\x00\x00\x01\x00\x00\x00\x00\x06\x00\x00\x00\x02\x00\x00\x00\x00ak'
321 #endif
323 #endif
322
324
323 $ hg debugdata k 0
325 $ hg debugdata k 0
324 \x01 (esc)
326 \x01 (esc)
325 copy: a
327 copy: a
326 copyrev: b789fdd96dc2f3bd229c1dd8eedf0fc60e2b68e3
328 copyrev: b789fdd96dc2f3bd229c1dd8eedf0fc60e2b68e3
327 \x01 (esc)
329 \x01 (esc)
328 a
330 a
329 #if extra
331 #if extra
330 $ hg showcopies
332 $ hg showcopies
331
333
332 $ hg showcopies --config experimental.copies.read-from=compatibility
334 $ hg showcopies --config experimental.copies.read-from=compatibility
333 a -> k
335 a -> k
334 $ hg showcopies --config experimental.copies.read-from=filelog-only
336 $ hg showcopies --config experimental.copies.read-from=filelog-only
335 a -> k
337 a -> k
336 #else
338 #else
337 $ hg showcopies
339 $ hg showcopies
338 a -> k
340 a -> k
339 #endif
341 #endif
340
342
341 $ cd ..
343 $ cd ..
342
344
343 Test rebasing a commit with copy information
345 Test rebasing a commit with copy information
344
346
345 $ hg init rebase-rename
347 $ hg init rebase-rename
346 $ cd rebase-rename
348 $ cd rebase-rename
347 $ echo a > a
349 $ echo a > a
348 $ hg ci -Aqm 'add a'
350 $ hg ci -Aqm 'add a'
349 $ echo a2 > a
351 $ echo a2 > a
350 $ hg ci -m 'modify a'
352 $ hg ci -m 'modify a'
351 $ hg co -q 0
353 $ hg co -q 0
352 $ hg mv a b
354 $ hg mv a b
353 $ hg ci -qm 'rename a to b'
355 $ hg ci -qm 'rename a to b'
354 Not only do we want this to run in-memory, it shouldn't fall back to
356 Not only do we want this to run in-memory, it shouldn't fall back to
355 on-disk merge (no conflicts), so we force it to be in-memory
357 on-disk merge (no conflicts), so we force it to be in-memory
356 with no fallback.
358 with no fallback.
357 $ hg rebase -d 1 --config rebase.experimental.inmemory=yes --config devel.rebase.force-in-memory-merge=yes
359 $ hg rebase -d 1 --config rebase.experimental.inmemory=yes --config devel.rebase.force-in-memory-merge=yes
358 rebasing 2:* tip "rename a to b" (glob)
360 rebasing 2:* tip "rename a to b" (glob)
359 merging a and b to b
361 merging a and b to b
360 saved backup bundle to $TESTTMP/rebase-rename/.hg/strip-backup/*-*-rebase.hg (glob)
362 saved backup bundle to $TESTTMP/rebase-rename/.hg/strip-backup/*-*-rebase.hg (glob)
361 $ hg st --change . --copies
363 $ hg st --change . --copies
362 A b
364 A b
363 a
365 a
364 R a
366 R a
365 $ cd ..
367 $ cd ..
366
368
367 Test splitting a commit
369 Test splitting a commit
368
370
369 $ hg init split
371 $ hg init split
370 $ cd split
372 $ cd split
371 $ echo a > a
373 $ echo a > a
372 $ echo b > b
374 $ echo b > b
373 $ hg ci -Aqm 'add a and b'
375 $ hg ci -Aqm 'add a and b'
374 $ echo a2 > a
376 $ echo a2 > a
375 $ hg mv b c
377 $ hg mv b c
376 $ hg ci -m 'modify a, move b to c'
378 $ hg ci -m 'modify a, move b to c'
377 $ hg --config ui.interactive=yes split <<EOF
379 $ hg --config ui.interactive=yes split <<EOF
378 > y
380 > y
379 > y
381 > y
380 > n
382 > n
381 > y
383 > y
382 > EOF
384 > EOF
383 diff --git a/a b/a
385 diff --git a/a b/a
384 1 hunks, 1 lines changed
386 1 hunks, 1 lines changed
385 examine changes to 'a'?
387 examine changes to 'a'?
386 (enter ? for help) [Ynesfdaq?] y
388 (enter ? for help) [Ynesfdaq?] y
387
389
388 @@ -1,1 +1,1 @@
390 @@ -1,1 +1,1 @@
389 -a
391 -a
390 +a2
392 +a2
391 record this change to 'a'?
393 record this change to 'a'?
392 (enter ? for help) [Ynesfdaq?] y
394 (enter ? for help) [Ynesfdaq?] y
393
395
394 diff --git a/b b/c
396 diff --git a/b b/c
395 rename from b
397 rename from b
396 rename to c
398 rename to c
397 examine changes to 'b' and 'c'?
399 examine changes to 'b' and 'c'?
398 (enter ? for help) [Ynesfdaq?] n
400 (enter ? for help) [Ynesfdaq?] n
399
401
400 created new head
402 created new head
401 diff --git a/b b/c
403 diff --git a/b b/c
402 rename from b
404 rename from b
403 rename to c
405 rename to c
404 examine changes to 'b' and 'c'?
406 examine changes to 'b' and 'c'?
405 (enter ? for help) [Ynesfdaq?] y
407 (enter ? for help) [Ynesfdaq?] y
406
408
407 saved backup bundle to $TESTTMP/split/.hg/strip-backup/*-*-split.hg (glob)
409 saved backup bundle to $TESTTMP/split/.hg/strip-backup/*-*-split.hg (glob)
408 $ cd ..
410 $ cd ..
409
411
410 Test committing half a rename
412 Test committing half a rename
411
413
412 $ hg init partial
414 $ hg init partial
413 $ cd partial
415 $ cd partial
414 $ echo a > a
416 $ echo a > a
415 $ hg ci -Aqm 'add a'
417 $ hg ci -Aqm 'add a'
416 $ hg mv a b
418 $ hg mv a b
417 $ hg ci -m 'remove a' a
419 $ hg ci -m 'remove a' a
418
420
419 #if sidedata
421 #if sidedata
420
422
421 Test upgrading/downgrading to sidedata storage
423 Test upgrading/downgrading to sidedata storage
422 ==============================================
424 ==============================================
423
425
424 downgrading
426 downgrading
425
427
426 $ hg debugformat -v
428 $ hg debugformat -v
427 format-variant repo config default
429 format-variant repo config default
428 fncache: yes yes yes
430 fncache: yes yes yes
431 dirstate-v2: no no no
429 dotencode: yes yes yes
432 dotencode: yes yes yes
430 generaldelta: yes yes yes
433 generaldelta: yes yes yes
431 share-safe: no no no
434 share-safe: no no no
432 sparserevlog: yes yes yes
435 sparserevlog: yes yes yes
433 persistent-nodemap: no no no (no-rust !)
436 persistent-nodemap: no no no (no-rust !)
434 persistent-nodemap: yes yes no (rust !)
437 persistent-nodemap: yes yes no (rust !)
435 copies-sdc: yes yes no
438 copies-sdc: yes yes no
436 revlog-v2: no no no
439 revlog-v2: no no no
437 changelog-v2: yes yes no
440 changelog-v2: yes yes no
438 plain-cl-delta: yes yes yes
441 plain-cl-delta: yes yes yes
439 compression: zlib zlib zlib (no-zstd !)
442 compression: zlib zlib zlib (no-zstd !)
440 compression: zstd zstd zstd (zstd !)
443 compression: zstd zstd zstd (zstd !)
441 compression-level: default default default
444 compression-level: default default default
442 $ hg debugsidedata -c -- 0
445 $ hg debugsidedata -c -- 0
443 1 sidedata entries
446 1 sidedata entries
444 entry-0014 size 14
447 entry-0014 size 14
445 $ hg debugsidedata -c -- 1
448 $ hg debugsidedata -c -- 1
446 1 sidedata entries
449 1 sidedata entries
447 entry-0014 size 14
450 entry-0014 size 14
448 $ hg debugsidedata -m -- 0
451 $ hg debugsidedata -m -- 0
449 $ cat << EOF > .hg/hgrc
452 $ cat << EOF > .hg/hgrc
450 > [format]
453 > [format]
451 > exp-use-copies-side-data-changeset = no
454 > exp-use-copies-side-data-changeset = no
452 > [experimental]
455 > [experimental]
453 > revlogv2 = enable-unstable-format-and-corrupt-my-data
456 > revlogv2 = enable-unstable-format-and-corrupt-my-data
454 > EOF
457 > EOF
455 $ hg debugupgraderepo --run --quiet --no-backup > /dev/null
458 $ hg debugupgraderepo --run --quiet --no-backup > /dev/null
456 $ hg debugformat -v
459 $ hg debugformat -v
457 format-variant repo config default
460 format-variant repo config default
458 fncache: yes yes yes
461 fncache: yes yes yes
462 dirstate-v2: no no no
459 dotencode: yes yes yes
463 dotencode: yes yes yes
460 generaldelta: yes yes yes
464 generaldelta: yes yes yes
461 share-safe: no no no
465 share-safe: no no no
462 sparserevlog: yes yes yes
466 sparserevlog: yes yes yes
463 persistent-nodemap: no no no (no-rust !)
467 persistent-nodemap: no no no (no-rust !)
464 persistent-nodemap: yes yes no (rust !)
468 persistent-nodemap: yes yes no (rust !)
465 copies-sdc: no no no
469 copies-sdc: no no no
466 revlog-v2: yes yes no
470 revlog-v2: yes yes no
467 changelog-v2: no no no
471 changelog-v2: no no no
468 plain-cl-delta: yes yes yes
472 plain-cl-delta: yes yes yes
469 compression: zlib zlib zlib (no-zstd !)
473 compression: zlib zlib zlib (no-zstd !)
470 compression: zstd zstd zstd (zstd !)
474 compression: zstd zstd zstd (zstd !)
471 compression-level: default default default
475 compression-level: default default default
472 $ hg debugsidedata -c -- 0
476 $ hg debugsidedata -c -- 0
473 $ hg debugsidedata -c -- 1
477 $ hg debugsidedata -c -- 1
474 $ hg debugsidedata -m -- 0
478 $ hg debugsidedata -m -- 0
475
479
476 upgrading
480 upgrading
477
481
478 $ cat << EOF > .hg/hgrc
482 $ cat << EOF > .hg/hgrc
479 > [format]
483 > [format]
480 > exp-use-copies-side-data-changeset = yes
484 > exp-use-copies-side-data-changeset = yes
481 > EOF
485 > EOF
482 $ hg debugupgraderepo --run --quiet --no-backup > /dev/null
486 $ hg debugupgraderepo --run --quiet --no-backup > /dev/null
483 $ hg debugformat -v
487 $ hg debugformat -v
484 format-variant repo config default
488 format-variant repo config default
485 fncache: yes yes yes
489 fncache: yes yes yes
490 dirstate-v2: no no no
486 dotencode: yes yes yes
491 dotencode: yes yes yes
487 generaldelta: yes yes yes
492 generaldelta: yes yes yes
488 share-safe: no no no
493 share-safe: no no no
489 sparserevlog: yes yes yes
494 sparserevlog: yes yes yes
490 persistent-nodemap: no no no (no-rust !)
495 persistent-nodemap: no no no (no-rust !)
491 persistent-nodemap: yes yes no (rust !)
496 persistent-nodemap: yes yes no (rust !)
492 copies-sdc: yes yes no
497 copies-sdc: yes yes no
493 revlog-v2: no no no
498 revlog-v2: no no no
494 changelog-v2: yes yes no
499 changelog-v2: yes yes no
495 plain-cl-delta: yes yes yes
500 plain-cl-delta: yes yes yes
496 compression: zlib zlib zlib (no-zstd !)
501 compression: zlib zlib zlib (no-zstd !)
497 compression: zstd zstd zstd (zstd !)
502 compression: zstd zstd zstd (zstd !)
498 compression-level: default default default
503 compression-level: default default default
499 $ hg debugsidedata -c -- 0
504 $ hg debugsidedata -c -- 0
500 1 sidedata entries
505 1 sidedata entries
501 entry-0014 size 14
506 entry-0014 size 14
502 $ hg debugsidedata -c -- 1
507 $ hg debugsidedata -c -- 1
503 1 sidedata entries
508 1 sidedata entries
504 entry-0014 size 14
509 entry-0014 size 14
505 $ hg debugsidedata -m -- 0
510 $ hg debugsidedata -m -- 0
506
511
507 #endif
512 #endif
508
513
509 $ cd ..
514 $ cd ..
@@ -1,1059 +1,1062 b''
1 ===================================
1 ===================================
2 Test the persistent on-disk nodemap
2 Test the persistent on-disk nodemap
3 ===================================
3 ===================================
4
4
5
5
6 #if no-rust
6 #if no-rust
7
7
8 $ cat << EOF >> $HGRCPATH
8 $ cat << EOF >> $HGRCPATH
9 > [format]
9 > [format]
10 > use-persistent-nodemap=yes
10 > use-persistent-nodemap=yes
11 > [devel]
11 > [devel]
12 > persistent-nodemap=yes
12 > persistent-nodemap=yes
13 > EOF
13 > EOF
14
14
15 #endif
15 #endif
16
16
17 $ hg init test-repo --config storage.revlog.persistent-nodemap.slow-path=allow
17 $ hg init test-repo --config storage.revlog.persistent-nodemap.slow-path=allow
18 $ cd test-repo
18 $ cd test-repo
19
19
20 Check handling of the default slow-path value
20 Check handling of the default slow-path value
21
21
22 #if no-pure no-rust
22 #if no-pure no-rust
23
23
24 $ hg id
24 $ hg id
25 abort: accessing `persistent-nodemap` repository without associated fast implementation.
25 abort: accessing `persistent-nodemap` repository without associated fast implementation.
26 (check `hg help config.format.use-persistent-nodemap` for details)
26 (check `hg help config.format.use-persistent-nodemap` for details)
27 [255]
27 [255]
28
28
29 Unlock further check (we are here to test the feature)
29 Unlock further check (we are here to test the feature)
30
30
31 $ cat << EOF >> $HGRCPATH
31 $ cat << EOF >> $HGRCPATH
32 > [storage]
32 > [storage]
33 > # to avoid spamming the test
33 > # to avoid spamming the test
34 > revlog.persistent-nodemap.slow-path=allow
34 > revlog.persistent-nodemap.slow-path=allow
35 > EOF
35 > EOF
36
36
37 #endif
37 #endif
38
38
39 #if rust
39 #if rust
40
40
41 Regression test for a previous bug in Rust/C FFI for the `Revlog_CAPI` capsule:
41 Regression test for a previous bug in Rust/C FFI for the `Revlog_CAPI` capsule:
42 in places where `mercurial/cext/revlog.c` function signatures use `Py_ssize_t`
42 in places where `mercurial/cext/revlog.c` function signatures use `Py_ssize_t`
43 (64 bits on Linux x86_64), corresponding declarations in `rust/hg-cpython/src/cindex.rs`
43 (64 bits on Linux x86_64), corresponding declarations in `rust/hg-cpython/src/cindex.rs`
44 incorrectly used `libc::c_int` (32 bits).
44 incorrectly used `libc::c_int` (32 bits).
45 As a result, -1 passed from Rust for the null revision became 4294967295 in C.
45 As a result, -1 passed from Rust for the null revision became 4294967295 in C.
46
46
47 $ hg log -r 00000000
47 $ hg log -r 00000000
48 changeset: -1:000000000000
48 changeset: -1:000000000000
49 tag: tip
49 tag: tip
50 user:
50 user:
51 date: Thu Jan 01 00:00:00 1970 +0000
51 date: Thu Jan 01 00:00:00 1970 +0000
52
52
53
53
54 #endif
54 #endif
55
55
56
56
57 $ hg debugformat
57 $ hg debugformat
58 format-variant repo
58 format-variant repo
59 fncache: yes
59 fncache: yes
60 dirstate-v2: no
60 dotencode: yes
61 dotencode: yes
61 generaldelta: yes
62 generaldelta: yes
62 share-safe: no
63 share-safe: no
63 sparserevlog: yes
64 sparserevlog: yes
64 persistent-nodemap: yes
65 persistent-nodemap: yes
65 copies-sdc: no
66 copies-sdc: no
66 revlog-v2: no
67 revlog-v2: no
67 changelog-v2: no
68 changelog-v2: no
68 plain-cl-delta: yes
69 plain-cl-delta: yes
69 compression: zlib (no-zstd !)
70 compression: zlib (no-zstd !)
70 compression: zstd (zstd !)
71 compression: zstd (zstd !)
71 compression-level: default
72 compression-level: default
72 $ hg debugbuilddag .+5000 --new-file
73 $ hg debugbuilddag .+5000 --new-file
73
74
74 $ hg debugnodemap --metadata
75 $ hg debugnodemap --metadata
75 uid: ???????? (glob)
76 uid: ???????? (glob)
76 tip-rev: 5000
77 tip-rev: 5000
77 tip-node: 6b02b8c7b96654c25e86ba69eda198d7e6ad8b3c
78 tip-node: 6b02b8c7b96654c25e86ba69eda198d7e6ad8b3c
78 data-length: 121088
79 data-length: 121088
79 data-unused: 0
80 data-unused: 0
80 data-unused: 0.000%
81 data-unused: 0.000%
81 $ f --size .hg/store/00changelog.n
82 $ f --size .hg/store/00changelog.n
82 .hg/store/00changelog.n: size=62
83 .hg/store/00changelog.n: size=62
83
84
84 Simple lookup works
85 Simple lookup works
85
86
86 $ ANYNODE=`hg log --template '{node|short}\n' --rev tip`
87 $ ANYNODE=`hg log --template '{node|short}\n' --rev tip`
87 $ hg log -r "$ANYNODE" --template '{rev}\n'
88 $ hg log -r "$ANYNODE" --template '{rev}\n'
88 5000
89 5000
89
90
90
91
91 #if rust
92 #if rust
92
93
93 $ f --sha256 .hg/store/00changelog-*.nd
94 $ f --sha256 .hg/store/00changelog-*.nd
94 .hg/store/00changelog-????????.nd: sha256=2e029d3200bd1a986b32784fc2ef1a3bd60dc331f025718bcf5ff44d93f026fd (glob)
95 .hg/store/00changelog-????????.nd: sha256=2e029d3200bd1a986b32784fc2ef1a3bd60dc331f025718bcf5ff44d93f026fd (glob)
95
96
96 $ f --sha256 .hg/store/00manifest-*.nd
97 $ f --sha256 .hg/store/00manifest-*.nd
97 .hg/store/00manifest-????????.nd: sha256=97117b1c064ea2f86664a124589e47db0e254e8d34739b5c5cc5bf31c9da2b51 (glob)
98 .hg/store/00manifest-????????.nd: sha256=97117b1c064ea2f86664a124589e47db0e254e8d34739b5c5cc5bf31c9da2b51 (glob)
98 $ hg debugnodemap --dump-new | f --sha256 --size
99 $ hg debugnodemap --dump-new | f --sha256 --size
99 size=121088, sha256=2e029d3200bd1a986b32784fc2ef1a3bd60dc331f025718bcf5ff44d93f026fd
100 size=121088, sha256=2e029d3200bd1a986b32784fc2ef1a3bd60dc331f025718bcf5ff44d93f026fd
100 $ hg debugnodemap --dump-disk | f --sha256 --bytes=256 --hexdump --size
101 $ hg debugnodemap --dump-disk | f --sha256 --bytes=256 --hexdump --size
101 size=121088, sha256=2e029d3200bd1a986b32784fc2ef1a3bd60dc331f025718bcf5ff44d93f026fd
102 size=121088, sha256=2e029d3200bd1a986b32784fc2ef1a3bd60dc331f025718bcf5ff44d93f026fd
102 0000: 00 00 00 91 00 00 00 20 00 00 00 bb 00 00 00 e7 |....... ........|
103 0000: 00 00 00 91 00 00 00 20 00 00 00 bb 00 00 00 e7 |....... ........|
103 0010: 00 00 00 66 00 00 00 a1 00 00 01 13 00 00 01 22 |...f..........."|
104 0010: 00 00 00 66 00 00 00 a1 00 00 01 13 00 00 01 22 |...f..........."|
104 0020: 00 00 00 23 00 00 00 fc 00 00 00 ba 00 00 00 5e |...#...........^|
105 0020: 00 00 00 23 00 00 00 fc 00 00 00 ba 00 00 00 5e |...#...........^|
105 0030: 00 00 00 df 00 00 01 4e 00 00 01 65 00 00 00 ab |.......N...e....|
106 0030: 00 00 00 df 00 00 01 4e 00 00 01 65 00 00 00 ab |.......N...e....|
106 0040: 00 00 00 a9 00 00 00 95 00 00 00 73 00 00 00 38 |...........s...8|
107 0040: 00 00 00 a9 00 00 00 95 00 00 00 73 00 00 00 38 |...........s...8|
107 0050: 00 00 00 cc 00 00 00 92 00 00 00 90 00 00 00 69 |...............i|
108 0050: 00 00 00 cc 00 00 00 92 00 00 00 90 00 00 00 69 |...............i|
108 0060: 00 00 00 ec 00 00 00 8d 00 00 01 4f 00 00 00 12 |...........O....|
109 0060: 00 00 00 ec 00 00 00 8d 00 00 01 4f 00 00 00 12 |...........O....|
109 0070: 00 00 02 0c 00 00 00 77 00 00 00 9c 00 00 00 8f |.......w........|
110 0070: 00 00 02 0c 00 00 00 77 00 00 00 9c 00 00 00 8f |.......w........|
110 0080: 00 00 00 d5 00 00 00 6b 00 00 00 48 00 00 00 b3 |.......k...H....|
111 0080: 00 00 00 d5 00 00 00 6b 00 00 00 48 00 00 00 b3 |.......k...H....|
111 0090: 00 00 00 e5 00 00 00 b5 00 00 00 8e 00 00 00 ad |................|
112 0090: 00 00 00 e5 00 00 00 b5 00 00 00 8e 00 00 00 ad |................|
112 00a0: 00 00 00 7b 00 00 00 7c 00 00 00 0b 00 00 00 2b |...{...|.......+|
113 00a0: 00 00 00 7b 00 00 00 7c 00 00 00 0b 00 00 00 2b |...{...|.......+|
113 00b0: 00 00 00 c6 00 00 00 1e 00 00 01 08 00 00 00 11 |................|
114 00b0: 00 00 00 c6 00 00 00 1e 00 00 01 08 00 00 00 11 |................|
114 00c0: 00 00 01 30 00 00 00 26 00 00 01 9c 00 00 00 35 |...0...&.......5|
115 00c0: 00 00 01 30 00 00 00 26 00 00 01 9c 00 00 00 35 |...0...&.......5|
115 00d0: 00 00 00 b8 00 00 01 31 00 00 00 2c 00 00 00 55 |.......1...,...U|
116 00d0: 00 00 00 b8 00 00 01 31 00 00 00 2c 00 00 00 55 |.......1...,...U|
116 00e0: 00 00 00 8a 00 00 00 9a 00 00 00 0c 00 00 01 1e |................|
117 00e0: 00 00 00 8a 00 00 00 9a 00 00 00 0c 00 00 01 1e |................|
117 00f0: 00 00 00 a4 00 00 00 83 00 00 00 c9 00 00 00 8c |................|
118 00f0: 00 00 00 a4 00 00 00 83 00 00 00 c9 00 00 00 8c |................|
118
119
119
120
120 #else
121 #else
121
122
122 $ f --sha256 .hg/store/00changelog-*.nd
123 $ f --sha256 .hg/store/00changelog-*.nd
123 .hg/store/00changelog-????????.nd: sha256=f544f5462ff46097432caf6d764091f6d8c46d6121be315ead8576d548c9dd79 (glob)
124 .hg/store/00changelog-????????.nd: sha256=f544f5462ff46097432caf6d764091f6d8c46d6121be315ead8576d548c9dd79 (glob)
124 $ hg debugnodemap --dump-new | f --sha256 --size
125 $ hg debugnodemap --dump-new | f --sha256 --size
125 size=121088, sha256=f544f5462ff46097432caf6d764091f6d8c46d6121be315ead8576d548c9dd79
126 size=121088, sha256=f544f5462ff46097432caf6d764091f6d8c46d6121be315ead8576d548c9dd79
126 $ hg debugnodemap --dump-disk | f --sha256 --bytes=256 --hexdump --size
127 $ hg debugnodemap --dump-disk | f --sha256 --bytes=256 --hexdump --size
127 size=121088, sha256=f544f5462ff46097432caf6d764091f6d8c46d6121be315ead8576d548c9dd79
128 size=121088, sha256=f544f5462ff46097432caf6d764091f6d8c46d6121be315ead8576d548c9dd79
128 0000: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
129 0000: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
129 0010: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
130 0010: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
130 0020: ff ff ff ff ff ff f5 06 ff ff ff ff ff ff f3 e7 |................|
131 0020: ff ff ff ff ff ff f5 06 ff ff ff ff ff ff f3 e7 |................|
131 0030: ff ff ef ca ff ff ff ff ff ff ff ff ff ff ff ff |................|
132 0030: ff ff ef ca ff ff ff ff ff ff ff ff ff ff ff ff |................|
132 0040: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
133 0040: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
133 0050: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ed 08 |................|
134 0050: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ed 08 |................|
134 0060: ff ff ed 66 ff ff ff ff ff ff ff ff ff ff ff ff |...f............|
135 0060: ff ff ed 66 ff ff ff ff ff ff ff ff ff ff ff ff |...f............|
135 0070: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
136 0070: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
136 0080: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
137 0080: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
137 0090: ff ff ff ff ff ff ff ff ff ff ff ff ff ff f6 ed |................|
138 0090: ff ff ff ff ff ff ff ff ff ff ff ff ff ff f6 ed |................|
138 00a0: ff ff ff ff ff ff fe 61 ff ff ff ff ff ff ff ff |.......a........|
139 00a0: ff ff ff ff ff ff fe 61 ff ff ff ff ff ff ff ff |.......a........|
139 00b0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
140 00b0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
140 00c0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
141 00c0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
141 00d0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
142 00d0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................|
142 00e0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff f1 02 |................|
143 00e0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff f1 02 |................|
143 00f0: ff ff ff ff ff ff ed 1b ff ff ff ff ff ff ff ff |................|
144 00f0: ff ff ff ff ff ff ed 1b ff ff ff ff ff ff ff ff |................|
144
145
145 #endif
146 #endif
146
147
147 $ hg debugnodemap --check
148 $ hg debugnodemap --check
148 revision in index: 5001
149 revision in index: 5001
149 revision in nodemap: 5001
150 revision in nodemap: 5001
150
151
151 add a new commit
152 add a new commit
152
153
153 $ hg up
154 $ hg up
154 5001 files updated, 0 files merged, 0 files removed, 0 files unresolved
155 5001 files updated, 0 files merged, 0 files removed, 0 files unresolved
155 $ echo foo > foo
156 $ echo foo > foo
156 $ hg add foo
157 $ hg add foo
157
158
158
159
159 Check slow-path config value handling
160 Check slow-path config value handling
160 -------------------------------------
161 -------------------------------------
161
162
162 #if no-pure no-rust
163 #if no-pure no-rust
163
164
164 $ hg id --config "storage.revlog.persistent-nodemap.slow-path=invalid-value"
165 $ hg id --config "storage.revlog.persistent-nodemap.slow-path=invalid-value"
165 unknown value for config "storage.revlog.persistent-nodemap.slow-path": "invalid-value"
166 unknown value for config "storage.revlog.persistent-nodemap.slow-path": "invalid-value"
166 falling back to default value: abort
167 falling back to default value: abort
167 abort: accessing `persistent-nodemap` repository without associated fast implementation.
168 abort: accessing `persistent-nodemap` repository without associated fast implementation.
168 (check `hg help config.format.use-persistent-nodemap` for details)
169 (check `hg help config.format.use-persistent-nodemap` for details)
169 [255]
170 [255]
170
171
171 $ hg log -r . --config "storage.revlog.persistent-nodemap.slow-path=warn"
172 $ hg log -r . --config "storage.revlog.persistent-nodemap.slow-path=warn"
172 warning: accessing `persistent-nodemap` repository without associated fast implementation.
173 warning: accessing `persistent-nodemap` repository without associated fast implementation.
173 (check `hg help config.format.use-persistent-nodemap` for details)
174 (check `hg help config.format.use-persistent-nodemap` for details)
174 changeset: 5000:6b02b8c7b966
175 changeset: 5000:6b02b8c7b966
175 tag: tip
176 tag: tip
176 user: debugbuilddag
177 user: debugbuilddag
177 date: Thu Jan 01 01:23:20 1970 +0000
178 date: Thu Jan 01 01:23:20 1970 +0000
178 summary: r5000
179 summary: r5000
179
180
180 $ hg ci -m 'foo' --config "storage.revlog.persistent-nodemap.slow-path=abort"
181 $ hg ci -m 'foo' --config "storage.revlog.persistent-nodemap.slow-path=abort"
181 abort: accessing `persistent-nodemap` repository without associated fast implementation.
182 abort: accessing `persistent-nodemap` repository without associated fast implementation.
182 (check `hg help config.format.use-persistent-nodemap` for details)
183 (check `hg help config.format.use-persistent-nodemap` for details)
183 [255]
184 [255]
184
185
185 #else
186 #else
186
187
187 $ hg id --config "storage.revlog.persistent-nodemap.slow-path=invalid-value"
188 $ hg id --config "storage.revlog.persistent-nodemap.slow-path=invalid-value"
188 unknown value for config "storage.revlog.persistent-nodemap.slow-path": "invalid-value"
189 unknown value for config "storage.revlog.persistent-nodemap.slow-path": "invalid-value"
189 falling back to default value: abort
190 falling back to default value: abort
190 6b02b8c7b966+ tip
191 6b02b8c7b966+ tip
191
192
192 #endif
193 #endif
193
194
194 $ hg ci -m 'foo'
195 $ hg ci -m 'foo'
195
196
196 #if no-pure no-rust
197 #if no-pure no-rust
197 $ hg debugnodemap --metadata
198 $ hg debugnodemap --metadata
198 uid: ???????? (glob)
199 uid: ???????? (glob)
199 tip-rev: 5001
200 tip-rev: 5001
200 tip-node: 16395c3cf7e231394735e6b1717823ada303fb0c
201 tip-node: 16395c3cf7e231394735e6b1717823ada303fb0c
201 data-length: 121088
202 data-length: 121088
202 data-unused: 0
203 data-unused: 0
203 data-unused: 0.000%
204 data-unused: 0.000%
204 #else
205 #else
205 $ hg debugnodemap --metadata
206 $ hg debugnodemap --metadata
206 uid: ???????? (glob)
207 uid: ???????? (glob)
207 tip-rev: 5001
208 tip-rev: 5001
208 tip-node: 16395c3cf7e231394735e6b1717823ada303fb0c
209 tip-node: 16395c3cf7e231394735e6b1717823ada303fb0c
209 data-length: 121344
210 data-length: 121344
210 data-unused: 256
211 data-unused: 256
211 data-unused: 0.211%
212 data-unused: 0.211%
212 #endif
213 #endif
213
214
214 $ f --size .hg/store/00changelog.n
215 $ f --size .hg/store/00changelog.n
215 .hg/store/00changelog.n: size=62
216 .hg/store/00changelog.n: size=62
216
217
217 (The pure code use the debug code that perform incremental update, the C code reencode from scratch)
218 (The pure code use the debug code that perform incremental update, the C code reencode from scratch)
218
219
219 #if pure
220 #if pure
220 $ f --sha256 .hg/store/00changelog-*.nd --size
221 $ f --sha256 .hg/store/00changelog-*.nd --size
221 .hg/store/00changelog-????????.nd: size=121344, sha256=cce54c5da5bde3ad72a4938673ed4064c86231b9c64376b082b163fdb20f8f66 (glob)
222 .hg/store/00changelog-????????.nd: size=121344, sha256=cce54c5da5bde3ad72a4938673ed4064c86231b9c64376b082b163fdb20f8f66 (glob)
222 #endif
223 #endif
223
224
224 #if rust
225 #if rust
225 $ f --sha256 .hg/store/00changelog-*.nd --size
226 $ f --sha256 .hg/store/00changelog-*.nd --size
226 .hg/store/00changelog-????????.nd: size=121344, sha256=952b042fcf614ceb37b542b1b723e04f18f83efe99bee4e0f5ccd232ef470e58 (glob)
227 .hg/store/00changelog-????????.nd: size=121344, sha256=952b042fcf614ceb37b542b1b723e04f18f83efe99bee4e0f5ccd232ef470e58 (glob)
227 #endif
228 #endif
228
229
229 #if no-pure no-rust
230 #if no-pure no-rust
230 $ f --sha256 .hg/store/00changelog-*.nd --size
231 $ f --sha256 .hg/store/00changelog-*.nd --size
231 .hg/store/00changelog-????????.nd: size=121088, sha256=df7c06a035b96cb28c7287d349d603baef43240be7736fe34eea419a49702e17 (glob)
232 .hg/store/00changelog-????????.nd: size=121088, sha256=df7c06a035b96cb28c7287d349d603baef43240be7736fe34eea419a49702e17 (glob)
232 #endif
233 #endif
233
234
234 $ hg debugnodemap --check
235 $ hg debugnodemap --check
235 revision in index: 5002
236 revision in index: 5002
236 revision in nodemap: 5002
237 revision in nodemap: 5002
237
238
238 Test code path without mmap
239 Test code path without mmap
239 ---------------------------
240 ---------------------------
240
241
241 $ echo bar > bar
242 $ echo bar > bar
242 $ hg add bar
243 $ hg add bar
243 $ hg ci -m 'bar' --config storage.revlog.persistent-nodemap.mmap=no
244 $ hg ci -m 'bar' --config storage.revlog.persistent-nodemap.mmap=no
244
245
245 $ hg debugnodemap --check --config storage.revlog.persistent-nodemap.mmap=yes
246 $ hg debugnodemap --check --config storage.revlog.persistent-nodemap.mmap=yes
246 revision in index: 5003
247 revision in index: 5003
247 revision in nodemap: 5003
248 revision in nodemap: 5003
248 $ hg debugnodemap --check --config storage.revlog.persistent-nodemap.mmap=no
249 $ hg debugnodemap --check --config storage.revlog.persistent-nodemap.mmap=no
249 revision in index: 5003
250 revision in index: 5003
250 revision in nodemap: 5003
251 revision in nodemap: 5003
251
252
252
253
253 #if pure
254 #if pure
254 $ hg debugnodemap --metadata
255 $ hg debugnodemap --metadata
255 uid: ???????? (glob)
256 uid: ???????? (glob)
256 tip-rev: 5002
257 tip-rev: 5002
257 tip-node: 880b18d239dfa9f632413a2071bfdbcc4806a4fd
258 tip-node: 880b18d239dfa9f632413a2071bfdbcc4806a4fd
258 data-length: 121600
259 data-length: 121600
259 data-unused: 512
260 data-unused: 512
260 data-unused: 0.421%
261 data-unused: 0.421%
261 $ f --sha256 .hg/store/00changelog-*.nd --size
262 $ f --sha256 .hg/store/00changelog-*.nd --size
262 .hg/store/00changelog-????????.nd: size=121600, sha256=def52503d049ccb823974af313a98a935319ba61f40f3aa06a8be4d35c215054 (glob)
263 .hg/store/00changelog-????????.nd: size=121600, sha256=def52503d049ccb823974af313a98a935319ba61f40f3aa06a8be4d35c215054 (glob)
263 #endif
264 #endif
264 #if rust
265 #if rust
265 $ hg debugnodemap --metadata
266 $ hg debugnodemap --metadata
266 uid: ???????? (glob)
267 uid: ???????? (glob)
267 tip-rev: 5002
268 tip-rev: 5002
268 tip-node: 880b18d239dfa9f632413a2071bfdbcc4806a4fd
269 tip-node: 880b18d239dfa9f632413a2071bfdbcc4806a4fd
269 data-length: 121600
270 data-length: 121600
270 data-unused: 512
271 data-unused: 512
271 data-unused: 0.421%
272 data-unused: 0.421%
272 $ f --sha256 .hg/store/00changelog-*.nd --size
273 $ f --sha256 .hg/store/00changelog-*.nd --size
273 .hg/store/00changelog-????????.nd: size=121600, sha256=dacf5b5f1d4585fee7527d0e67cad5b1ba0930e6a0928f650f779aefb04ce3fb (glob)
274 .hg/store/00changelog-????????.nd: size=121600, sha256=dacf5b5f1d4585fee7527d0e67cad5b1ba0930e6a0928f650f779aefb04ce3fb (glob)
274 #endif
275 #endif
275 #if no-pure no-rust
276 #if no-pure no-rust
276 $ hg debugnodemap --metadata
277 $ hg debugnodemap --metadata
277 uid: ???????? (glob)
278 uid: ???????? (glob)
278 tip-rev: 5002
279 tip-rev: 5002
279 tip-node: 880b18d239dfa9f632413a2071bfdbcc4806a4fd
280 tip-node: 880b18d239dfa9f632413a2071bfdbcc4806a4fd
280 data-length: 121088
281 data-length: 121088
281 data-unused: 0
282 data-unused: 0
282 data-unused: 0.000%
283 data-unused: 0.000%
283 $ f --sha256 .hg/store/00changelog-*.nd --size
284 $ f --sha256 .hg/store/00changelog-*.nd --size
284 .hg/store/00changelog-????????.nd: size=121088, sha256=59fcede3e3cc587755916ceed29e3c33748cd1aa7d2f91828ac83e7979d935e8 (glob)
285 .hg/store/00changelog-????????.nd: size=121088, sha256=59fcede3e3cc587755916ceed29e3c33748cd1aa7d2f91828ac83e7979d935e8 (glob)
285 #endif
286 #endif
286
287
287 Test force warming the cache
288 Test force warming the cache
288
289
289 $ rm .hg/store/00changelog.n
290 $ rm .hg/store/00changelog.n
290 $ hg debugnodemap --metadata
291 $ hg debugnodemap --metadata
291 $ hg debugupdatecache
292 $ hg debugupdatecache
292 #if pure
293 #if pure
293 $ hg debugnodemap --metadata
294 $ hg debugnodemap --metadata
294 uid: ???????? (glob)
295 uid: ???????? (glob)
295 tip-rev: 5002
296 tip-rev: 5002
296 tip-node: 880b18d239dfa9f632413a2071bfdbcc4806a4fd
297 tip-node: 880b18d239dfa9f632413a2071bfdbcc4806a4fd
297 data-length: 121088
298 data-length: 121088
298 data-unused: 0
299 data-unused: 0
299 data-unused: 0.000%
300 data-unused: 0.000%
300 #else
301 #else
301 $ hg debugnodemap --metadata
302 $ hg debugnodemap --metadata
302 uid: ???????? (glob)
303 uid: ???????? (glob)
303 tip-rev: 5002
304 tip-rev: 5002
304 tip-node: 880b18d239dfa9f632413a2071bfdbcc4806a4fd
305 tip-node: 880b18d239dfa9f632413a2071bfdbcc4806a4fd
305 data-length: 121088
306 data-length: 121088
306 data-unused: 0
307 data-unused: 0
307 data-unused: 0.000%
308 data-unused: 0.000%
308 #endif
309 #endif
309
310
310 Check out of sync nodemap
311 Check out of sync nodemap
311 =========================
312 =========================
312
313
313 First copy old data on the side.
314 First copy old data on the side.
314
315
315 $ mkdir ../tmp-copies
316 $ mkdir ../tmp-copies
316 $ cp .hg/store/00changelog-????????.nd .hg/store/00changelog.n ../tmp-copies
317 $ cp .hg/store/00changelog-????????.nd .hg/store/00changelog.n ../tmp-copies
317
318
318 Nodemap lagging behind
319 Nodemap lagging behind
319 ----------------------
320 ----------------------
320
321
321 make a new commit
322 make a new commit
322
323
323 $ echo bar2 > bar
324 $ echo bar2 > bar
324 $ hg ci -m 'bar2'
325 $ hg ci -m 'bar2'
325 $ NODE=`hg log -r tip -T '{node}\n'`
326 $ NODE=`hg log -r tip -T '{node}\n'`
326 $ hg log -r "$NODE" -T '{rev}\n'
327 $ hg log -r "$NODE" -T '{rev}\n'
327 5003
328 5003
328
329
329 If the nodemap is lagging behind, it can catch up fine
330 If the nodemap is lagging behind, it can catch up fine
330
331
331 $ hg debugnodemap --metadata
332 $ hg debugnodemap --metadata
332 uid: ???????? (glob)
333 uid: ???????? (glob)
333 tip-rev: 5003
334 tip-rev: 5003
334 tip-node: c9329770f979ade2d16912267c38ba5f82fd37b3
335 tip-node: c9329770f979ade2d16912267c38ba5f82fd37b3
335 data-length: 121344 (pure !)
336 data-length: 121344 (pure !)
336 data-length: 121344 (rust !)
337 data-length: 121344 (rust !)
337 data-length: 121152 (no-rust no-pure !)
338 data-length: 121152 (no-rust no-pure !)
338 data-unused: 192 (pure !)
339 data-unused: 192 (pure !)
339 data-unused: 192 (rust !)
340 data-unused: 192 (rust !)
340 data-unused: 0 (no-rust no-pure !)
341 data-unused: 0 (no-rust no-pure !)
341 data-unused: 0.158% (pure !)
342 data-unused: 0.158% (pure !)
342 data-unused: 0.158% (rust !)
343 data-unused: 0.158% (rust !)
343 data-unused: 0.000% (no-rust no-pure !)
344 data-unused: 0.000% (no-rust no-pure !)
344 $ cp -f ../tmp-copies/* .hg/store/
345 $ cp -f ../tmp-copies/* .hg/store/
345 $ hg debugnodemap --metadata
346 $ hg debugnodemap --metadata
346 uid: ???????? (glob)
347 uid: ???????? (glob)
347 tip-rev: 5002
348 tip-rev: 5002
348 tip-node: 880b18d239dfa9f632413a2071bfdbcc4806a4fd
349 tip-node: 880b18d239dfa9f632413a2071bfdbcc4806a4fd
349 data-length: 121088
350 data-length: 121088
350 data-unused: 0
351 data-unused: 0
351 data-unused: 0.000%
352 data-unused: 0.000%
352 $ hg log -r "$NODE" -T '{rev}\n'
353 $ hg log -r "$NODE" -T '{rev}\n'
353 5003
354 5003
354
355
355 changelog altered
356 changelog altered
356 -----------------
357 -----------------
357
358
358 If the nodemap is not gated behind a requirements, an unaware client can alter
359 If the nodemap is not gated behind a requirements, an unaware client can alter
359 the repository so the revlog used to generate the nodemap is not longer
360 the repository so the revlog used to generate the nodemap is not longer
360 compatible with the persistent nodemap. We need to detect that.
361 compatible with the persistent nodemap. We need to detect that.
361
362
362 $ hg up "$NODE~5"
363 $ hg up "$NODE~5"
363 0 files updated, 0 files merged, 4 files removed, 0 files unresolved
364 0 files updated, 0 files merged, 4 files removed, 0 files unresolved
364 $ echo bar > babar
365 $ echo bar > babar
365 $ hg add babar
366 $ hg add babar
366 $ hg ci -m 'babar'
367 $ hg ci -m 'babar'
367 created new head
368 created new head
368 $ OTHERNODE=`hg log -r tip -T '{node}\n'`
369 $ OTHERNODE=`hg log -r tip -T '{node}\n'`
369 $ hg log -r "$OTHERNODE" -T '{rev}\n'
370 $ hg log -r "$OTHERNODE" -T '{rev}\n'
370 5004
371 5004
371
372
372 $ hg --config extensions.strip= strip --rev "$NODE~1" --no-backup
373 $ hg --config extensions.strip= strip --rev "$NODE~1" --no-backup
373
374
374 the nodemap should detect the changelog have been tampered with and recover.
375 the nodemap should detect the changelog have been tampered with and recover.
375
376
376 $ hg debugnodemap --metadata
377 $ hg debugnodemap --metadata
377 uid: ???????? (glob)
378 uid: ???????? (glob)
378 tip-rev: 5002
379 tip-rev: 5002
379 tip-node: b355ef8adce0949b8bdf6afc72ca853740d65944
380 tip-node: b355ef8adce0949b8bdf6afc72ca853740d65944
380 data-length: 121536 (pure !)
381 data-length: 121536 (pure !)
381 data-length: 121088 (rust !)
382 data-length: 121088 (rust !)
382 data-length: 121088 (no-pure no-rust !)
383 data-length: 121088 (no-pure no-rust !)
383 data-unused: 448 (pure !)
384 data-unused: 448 (pure !)
384 data-unused: 0 (rust !)
385 data-unused: 0 (rust !)
385 data-unused: 0 (no-pure no-rust !)
386 data-unused: 0 (no-pure no-rust !)
386 data-unused: 0.000% (rust !)
387 data-unused: 0.000% (rust !)
387 data-unused: 0.369% (pure !)
388 data-unused: 0.369% (pure !)
388 data-unused: 0.000% (no-pure no-rust !)
389 data-unused: 0.000% (no-pure no-rust !)
389
390
390 $ cp -f ../tmp-copies/* .hg/store/
391 $ cp -f ../tmp-copies/* .hg/store/
391 $ hg debugnodemap --metadata
392 $ hg debugnodemap --metadata
392 uid: ???????? (glob)
393 uid: ???????? (glob)
393 tip-rev: 5002
394 tip-rev: 5002
394 tip-node: 880b18d239dfa9f632413a2071bfdbcc4806a4fd
395 tip-node: 880b18d239dfa9f632413a2071bfdbcc4806a4fd
395 data-length: 121088
396 data-length: 121088
396 data-unused: 0
397 data-unused: 0
397 data-unused: 0.000%
398 data-unused: 0.000%
398 $ hg log -r "$OTHERNODE" -T '{rev}\n'
399 $ hg log -r "$OTHERNODE" -T '{rev}\n'
399 5002
400 5002
400
401
401 missing data file
402 missing data file
402 -----------------
403 -----------------
403
404
404 $ UUID=`hg debugnodemap --metadata| grep 'uid:' | \
405 $ UUID=`hg debugnodemap --metadata| grep 'uid:' | \
405 > sed 's/uid: //'`
406 > sed 's/uid: //'`
406 $ FILE=.hg/store/00changelog-"${UUID}".nd
407 $ FILE=.hg/store/00changelog-"${UUID}".nd
407 $ mv $FILE ../tmp-data-file
408 $ mv $FILE ../tmp-data-file
408 $ cp .hg/store/00changelog.n ../tmp-docket
409 $ cp .hg/store/00changelog.n ../tmp-docket
409
410
410 mercurial don't crash
411 mercurial don't crash
411
412
412 $ hg log -r .
413 $ hg log -r .
413 changeset: 5002:b355ef8adce0
414 changeset: 5002:b355ef8adce0
414 tag: tip
415 tag: tip
415 parent: 4998:d918ad6d18d3
416 parent: 4998:d918ad6d18d3
416 user: test
417 user: test
417 date: Thu Jan 01 00:00:00 1970 +0000
418 date: Thu Jan 01 00:00:00 1970 +0000
418 summary: babar
419 summary: babar
419
420
420 $ hg debugnodemap --metadata
421 $ hg debugnodemap --metadata
421
422
422 $ hg debugupdatecache
423 $ hg debugupdatecache
423 $ hg debugnodemap --metadata
424 $ hg debugnodemap --metadata
424 uid: * (glob)
425 uid: * (glob)
425 tip-rev: 5002
426 tip-rev: 5002
426 tip-node: b355ef8adce0949b8bdf6afc72ca853740d65944
427 tip-node: b355ef8adce0949b8bdf6afc72ca853740d65944
427 data-length: 121088
428 data-length: 121088
428 data-unused: 0
429 data-unused: 0
429 data-unused: 0.000%
430 data-unused: 0.000%
430 $ mv ../tmp-data-file $FILE
431 $ mv ../tmp-data-file $FILE
431 $ mv ../tmp-docket .hg/store/00changelog.n
432 $ mv ../tmp-docket .hg/store/00changelog.n
432
433
433 Check transaction related property
434 Check transaction related property
434 ==================================
435 ==================================
435
436
436 An up to date nodemap should be available to shell hooks,
437 An up to date nodemap should be available to shell hooks,
437
438
438 $ echo dsljfl > a
439 $ echo dsljfl > a
439 $ hg add a
440 $ hg add a
440 $ hg ci -m a
441 $ hg ci -m a
441 $ hg debugnodemap --metadata
442 $ hg debugnodemap --metadata
442 uid: ???????? (glob)
443 uid: ???????? (glob)
443 tip-rev: 5003
444 tip-rev: 5003
444 tip-node: a52c5079765b5865d97b993b303a18740113bbb2
445 tip-node: a52c5079765b5865d97b993b303a18740113bbb2
445 data-length: 121088
446 data-length: 121088
446 data-unused: 0
447 data-unused: 0
447 data-unused: 0.000%
448 data-unused: 0.000%
448 $ echo babar2 > babar
449 $ echo babar2 > babar
449 $ hg ci -m 'babar2' --config "hooks.pretxnclose.nodemap-test=hg debugnodemap --metadata"
450 $ hg ci -m 'babar2' --config "hooks.pretxnclose.nodemap-test=hg debugnodemap --metadata"
450 uid: ???????? (glob)
451 uid: ???????? (glob)
451 tip-rev: 5004
452 tip-rev: 5004
452 tip-node: 2f5fb1c06a16834c5679d672e90da7c5f3b1a984
453 tip-node: 2f5fb1c06a16834c5679d672e90da7c5f3b1a984
453 data-length: 121280 (pure !)
454 data-length: 121280 (pure !)
454 data-length: 121280 (rust !)
455 data-length: 121280 (rust !)
455 data-length: 121088 (no-pure no-rust !)
456 data-length: 121088 (no-pure no-rust !)
456 data-unused: 192 (pure !)
457 data-unused: 192 (pure !)
457 data-unused: 192 (rust !)
458 data-unused: 192 (rust !)
458 data-unused: 0 (no-pure no-rust !)
459 data-unused: 0 (no-pure no-rust !)
459 data-unused: 0.158% (pure !)
460 data-unused: 0.158% (pure !)
460 data-unused: 0.158% (rust !)
461 data-unused: 0.158% (rust !)
461 data-unused: 0.000% (no-pure no-rust !)
462 data-unused: 0.000% (no-pure no-rust !)
462 $ hg debugnodemap --metadata
463 $ hg debugnodemap --metadata
463 uid: ???????? (glob)
464 uid: ???????? (glob)
464 tip-rev: 5004
465 tip-rev: 5004
465 tip-node: 2f5fb1c06a16834c5679d672e90da7c5f3b1a984
466 tip-node: 2f5fb1c06a16834c5679d672e90da7c5f3b1a984
466 data-length: 121280 (pure !)
467 data-length: 121280 (pure !)
467 data-length: 121280 (rust !)
468 data-length: 121280 (rust !)
468 data-length: 121088 (no-pure no-rust !)
469 data-length: 121088 (no-pure no-rust !)
469 data-unused: 192 (pure !)
470 data-unused: 192 (pure !)
470 data-unused: 192 (rust !)
471 data-unused: 192 (rust !)
471 data-unused: 0 (no-pure no-rust !)
472 data-unused: 0 (no-pure no-rust !)
472 data-unused: 0.158% (pure !)
473 data-unused: 0.158% (pure !)
473 data-unused: 0.158% (rust !)
474 data-unused: 0.158% (rust !)
474 data-unused: 0.000% (no-pure no-rust !)
475 data-unused: 0.000% (no-pure no-rust !)
475
476
476 Another process does not see the pending nodemap content during run.
477 Another process does not see the pending nodemap content during run.
477
478
478 $ echo qpoasp > a
479 $ echo qpoasp > a
479 $ hg ci -m a2 \
480 $ hg ci -m a2 \
480 > --config "hooks.pretxnclose=sh \"$RUNTESTDIR/testlib/wait-on-file\" 20 sync-repo-read sync-txn-pending" \
481 > --config "hooks.pretxnclose=sh \"$RUNTESTDIR/testlib/wait-on-file\" 20 sync-repo-read sync-txn-pending" \
481 > --config "hooks.txnclose=touch sync-txn-close" > output.txt 2>&1 &
482 > --config "hooks.txnclose=touch sync-txn-close" > output.txt 2>&1 &
482
483
483 (read the repository while the commit transaction is pending)
484 (read the repository while the commit transaction is pending)
484
485
485 $ sh "$RUNTESTDIR/testlib/wait-on-file" 20 sync-txn-pending && \
486 $ sh "$RUNTESTDIR/testlib/wait-on-file" 20 sync-txn-pending && \
486 > hg debugnodemap --metadata && \
487 > hg debugnodemap --metadata && \
487 > sh "$RUNTESTDIR/testlib/wait-on-file" 20 sync-txn-close sync-repo-read
488 > sh "$RUNTESTDIR/testlib/wait-on-file" 20 sync-txn-close sync-repo-read
488 uid: ???????? (glob)
489 uid: ???????? (glob)
489 tip-rev: 5004
490 tip-rev: 5004
490 tip-node: 2f5fb1c06a16834c5679d672e90da7c5f3b1a984
491 tip-node: 2f5fb1c06a16834c5679d672e90da7c5f3b1a984
491 data-length: 121280 (pure !)
492 data-length: 121280 (pure !)
492 data-length: 121280 (rust !)
493 data-length: 121280 (rust !)
493 data-length: 121088 (no-pure no-rust !)
494 data-length: 121088 (no-pure no-rust !)
494 data-unused: 192 (pure !)
495 data-unused: 192 (pure !)
495 data-unused: 192 (rust !)
496 data-unused: 192 (rust !)
496 data-unused: 0 (no-pure no-rust !)
497 data-unused: 0 (no-pure no-rust !)
497 data-unused: 0.158% (pure !)
498 data-unused: 0.158% (pure !)
498 data-unused: 0.158% (rust !)
499 data-unused: 0.158% (rust !)
499 data-unused: 0.000% (no-pure no-rust !)
500 data-unused: 0.000% (no-pure no-rust !)
500 $ hg debugnodemap --metadata
501 $ hg debugnodemap --metadata
501 uid: ???????? (glob)
502 uid: ???????? (glob)
502 tip-rev: 5005
503 tip-rev: 5005
503 tip-node: 90d5d3ba2fc47db50f712570487cb261a68c8ffe
504 tip-node: 90d5d3ba2fc47db50f712570487cb261a68c8ffe
504 data-length: 121536 (pure !)
505 data-length: 121536 (pure !)
505 data-length: 121536 (rust !)
506 data-length: 121536 (rust !)
506 data-length: 121088 (no-pure no-rust !)
507 data-length: 121088 (no-pure no-rust !)
507 data-unused: 448 (pure !)
508 data-unused: 448 (pure !)
508 data-unused: 448 (rust !)
509 data-unused: 448 (rust !)
509 data-unused: 0 (no-pure no-rust !)
510 data-unused: 0 (no-pure no-rust !)
510 data-unused: 0.369% (pure !)
511 data-unused: 0.369% (pure !)
511 data-unused: 0.369% (rust !)
512 data-unused: 0.369% (rust !)
512 data-unused: 0.000% (no-pure no-rust !)
513 data-unused: 0.000% (no-pure no-rust !)
513
514
514 $ cat output.txt
515 $ cat output.txt
515
516
516 Check that a failing transaction will properly revert the data
517 Check that a failing transaction will properly revert the data
517
518
518 $ echo plakfe > a
519 $ echo plakfe > a
519 $ f --size --sha256 .hg/store/00changelog-*.nd
520 $ f --size --sha256 .hg/store/00changelog-*.nd
520 .hg/store/00changelog-????????.nd: size=121536, sha256=bb414468d225cf52d69132e1237afba34d4346ee2eb81b505027e6197b107f03 (glob) (pure !)
521 .hg/store/00changelog-????????.nd: size=121536, sha256=bb414468d225cf52d69132e1237afba34d4346ee2eb81b505027e6197b107f03 (glob) (pure !)
521 .hg/store/00changelog-????????.nd: size=121536, sha256=909ac727bc4d1c0fda5f7bff3c620c98bd4a2967c143405a1503439e33b377da (glob) (rust !)
522 .hg/store/00changelog-????????.nd: size=121536, sha256=909ac727bc4d1c0fda5f7bff3c620c98bd4a2967c143405a1503439e33b377da (glob) (rust !)
522 .hg/store/00changelog-????????.nd: size=121088, sha256=342d36d30d86dde67d3cb6c002606c4a75bcad665595d941493845066d9c8ee0 (glob) (no-pure no-rust !)
523 .hg/store/00changelog-????????.nd: size=121088, sha256=342d36d30d86dde67d3cb6c002606c4a75bcad665595d941493845066d9c8ee0 (glob) (no-pure no-rust !)
523 $ hg ci -m a3 --config "extensions.abort=$RUNTESTDIR/testlib/crash_transaction_late.py"
524 $ hg ci -m a3 --config "extensions.abort=$RUNTESTDIR/testlib/crash_transaction_late.py"
524 transaction abort!
525 transaction abort!
525 rollback completed
526 rollback completed
526 abort: This is a late abort
527 abort: This is a late abort
527 [255]
528 [255]
528 $ hg debugnodemap --metadata
529 $ hg debugnodemap --metadata
529 uid: ???????? (glob)
530 uid: ???????? (glob)
530 tip-rev: 5005
531 tip-rev: 5005
531 tip-node: 90d5d3ba2fc47db50f712570487cb261a68c8ffe
532 tip-node: 90d5d3ba2fc47db50f712570487cb261a68c8ffe
532 data-length: 121536 (pure !)
533 data-length: 121536 (pure !)
533 data-length: 121536 (rust !)
534 data-length: 121536 (rust !)
534 data-length: 121088 (no-pure no-rust !)
535 data-length: 121088 (no-pure no-rust !)
535 data-unused: 448 (pure !)
536 data-unused: 448 (pure !)
536 data-unused: 448 (rust !)
537 data-unused: 448 (rust !)
537 data-unused: 0 (no-pure no-rust !)
538 data-unused: 0 (no-pure no-rust !)
538 data-unused: 0.369% (pure !)
539 data-unused: 0.369% (pure !)
539 data-unused: 0.369% (rust !)
540 data-unused: 0.369% (rust !)
540 data-unused: 0.000% (no-pure no-rust !)
541 data-unused: 0.000% (no-pure no-rust !)
541 $ f --size --sha256 .hg/store/00changelog-*.nd
542 $ f --size --sha256 .hg/store/00changelog-*.nd
542 .hg/store/00changelog-????????.nd: size=121536, sha256=bb414468d225cf52d69132e1237afba34d4346ee2eb81b505027e6197b107f03 (glob) (pure !)
543 .hg/store/00changelog-????????.nd: size=121536, sha256=bb414468d225cf52d69132e1237afba34d4346ee2eb81b505027e6197b107f03 (glob) (pure !)
543 .hg/store/00changelog-????????.nd: size=121536, sha256=909ac727bc4d1c0fda5f7bff3c620c98bd4a2967c143405a1503439e33b377da (glob) (rust !)
544 .hg/store/00changelog-????????.nd: size=121536, sha256=909ac727bc4d1c0fda5f7bff3c620c98bd4a2967c143405a1503439e33b377da (glob) (rust !)
544 .hg/store/00changelog-????????.nd: size=121088, sha256=342d36d30d86dde67d3cb6c002606c4a75bcad665595d941493845066d9c8ee0 (glob) (no-pure no-rust !)
545 .hg/store/00changelog-????????.nd: size=121088, sha256=342d36d30d86dde67d3cb6c002606c4a75bcad665595d941493845066d9c8ee0 (glob) (no-pure no-rust !)
545
546
546 Check that removing content does not confuse the nodemap
547 Check that removing content does not confuse the nodemap
547 --------------------------------------------------------
548 --------------------------------------------------------
548
549
549 removing data with rollback
550 removing data with rollback
550
551
551 $ echo aso > a
552 $ echo aso > a
552 $ hg ci -m a4
553 $ hg ci -m a4
553 $ hg rollback
554 $ hg rollback
554 repository tip rolled back to revision 5005 (undo commit)
555 repository tip rolled back to revision 5005 (undo commit)
555 working directory now based on revision 5005
556 working directory now based on revision 5005
556 $ hg id -r .
557 $ hg id -r .
557 90d5d3ba2fc4 tip
558 90d5d3ba2fc4 tip
558
559
559 roming data with strip
560 roming data with strip
560
561
561 $ echo aso > a
562 $ echo aso > a
562 $ hg ci -m a4
563 $ hg ci -m a4
563 $ hg --config extensions.strip= strip -r . --no-backup
564 $ hg --config extensions.strip= strip -r . --no-backup
564 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
565 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
565 $ hg id -r . --traceback
566 $ hg id -r . --traceback
566 90d5d3ba2fc4 tip
567 90d5d3ba2fc4 tip
567
568
568 Test upgrade / downgrade
569 Test upgrade / downgrade
569 ========================
570 ========================
570
571
571 downgrading
572 downgrading
572
573
573 $ cat << EOF >> .hg/hgrc
574 $ cat << EOF >> .hg/hgrc
574 > [format]
575 > [format]
575 > use-persistent-nodemap=no
576 > use-persistent-nodemap=no
576 > EOF
577 > EOF
577 $ hg debugformat -v
578 $ hg debugformat -v
578 format-variant repo config default
579 format-variant repo config default
579 fncache: yes yes yes
580 fncache: yes yes yes
581 dirstate-v2: no no no
580 dotencode: yes yes yes
582 dotencode: yes yes yes
581 generaldelta: yes yes yes
583 generaldelta: yes yes yes
582 share-safe: no no no
584 share-safe: no no no
583 sparserevlog: yes yes yes
585 sparserevlog: yes yes yes
584 persistent-nodemap: yes no no
586 persistent-nodemap: yes no no
585 copies-sdc: no no no
587 copies-sdc: no no no
586 revlog-v2: no no no
588 revlog-v2: no no no
587 changelog-v2: no no no
589 changelog-v2: no no no
588 plain-cl-delta: yes yes yes
590 plain-cl-delta: yes yes yes
589 compression: zlib zlib zlib (no-zstd !)
591 compression: zlib zlib zlib (no-zstd !)
590 compression: zstd zstd zstd (zstd !)
592 compression: zstd zstd zstd (zstd !)
591 compression-level: default default default
593 compression-level: default default default
592 $ hg debugupgraderepo --run --no-backup
594 $ hg debugupgraderepo --run --no-backup
593 upgrade will perform the following actions:
595 upgrade will perform the following actions:
594
596
595 requirements
597 requirements
596 preserved: dotencode, fncache, generaldelta, revlogv1, sparserevlog, store (no-zstd no-dirstate-v2 !)
598 preserved: dotencode, fncache, generaldelta, revlogv1, sparserevlog, store (no-zstd no-dirstate-v2 !)
597 preserved: dotencode, fncache, generaldelta, revlog-compression-zstd, revlogv1, sparserevlog, store (zstd no-dirstate-v2 !)
599 preserved: dotencode, fncache, generaldelta, revlog-compression-zstd, revlogv1, sparserevlog, store (zstd no-dirstate-v2 !)
598 preserved: dotencode, exp-dirstate-v2, fncache, generaldelta, revlog-compression-zstd, revlogv1, sparserevlog, store (zstd dirstate-v2 !)
600 preserved: dotencode, exp-dirstate-v2, fncache, generaldelta, revlog-compression-zstd, revlogv1, sparserevlog, store (zstd dirstate-v2 !)
599 removed: persistent-nodemap
601 removed: persistent-nodemap
600
602
601 processed revlogs:
603 processed revlogs:
602 - all-filelogs
604 - all-filelogs
603 - changelog
605 - changelog
604 - manifest
606 - manifest
605
607
606 beginning upgrade...
608 beginning upgrade...
607 repository locked and read-only
609 repository locked and read-only
608 creating temporary repository to stage upgraded data: $TESTTMP/test-repo/.hg/upgrade.* (glob)
610 creating temporary repository to stage upgraded data: $TESTTMP/test-repo/.hg/upgrade.* (glob)
609 (it is safe to interrupt this process any time before data migration completes)
611 (it is safe to interrupt this process any time before data migration completes)
610 downgrading repository to not use persistent nodemap feature
612 downgrading repository to not use persistent nodemap feature
611 removing temporary repository $TESTTMP/test-repo/.hg/upgrade.* (glob)
613 removing temporary repository $TESTTMP/test-repo/.hg/upgrade.* (glob)
612 $ ls -1 .hg/store/ | egrep '00(changelog|manifest)(\.n|-.*\.nd)'
614 $ ls -1 .hg/store/ | egrep '00(changelog|manifest)(\.n|-.*\.nd)'
613 00changelog-*.nd (glob)
615 00changelog-*.nd (glob)
614 00manifest-*.nd (glob)
616 00manifest-*.nd (glob)
615 undo.backup.00changelog.n
617 undo.backup.00changelog.n
616 undo.backup.00manifest.n
618 undo.backup.00manifest.n
617 $ hg debugnodemap --metadata
619 $ hg debugnodemap --metadata
618
620
619
621
620 upgrading
622 upgrading
621
623
622 $ cat << EOF >> .hg/hgrc
624 $ cat << EOF >> .hg/hgrc
623 > [format]
625 > [format]
624 > use-persistent-nodemap=yes
626 > use-persistent-nodemap=yes
625 > EOF
627 > EOF
626 $ hg debugformat -v
628 $ hg debugformat -v
627 format-variant repo config default
629 format-variant repo config default
628 fncache: yes yes yes
630 fncache: yes yes yes
631 dirstate-v2: no no no
629 dotencode: yes yes yes
632 dotencode: yes yes yes
630 generaldelta: yes yes yes
633 generaldelta: yes yes yes
631 share-safe: no no no
634 share-safe: no no no
632 sparserevlog: yes yes yes
635 sparserevlog: yes yes yes
633 persistent-nodemap: no yes no
636 persistent-nodemap: no yes no
634 copies-sdc: no no no
637 copies-sdc: no no no
635 revlog-v2: no no no
638 revlog-v2: no no no
636 changelog-v2: no no no
639 changelog-v2: no no no
637 plain-cl-delta: yes yes yes
640 plain-cl-delta: yes yes yes
638 compression: zlib zlib zlib (no-zstd !)
641 compression: zlib zlib zlib (no-zstd !)
639 compression: zstd zstd zstd (zstd !)
642 compression: zstd zstd zstd (zstd !)
640 compression-level: default default default
643 compression-level: default default default
641 $ hg debugupgraderepo --run --no-backup
644 $ hg debugupgraderepo --run --no-backup
642 upgrade will perform the following actions:
645 upgrade will perform the following actions:
643
646
644 requirements
647 requirements
645 preserved: dotencode, fncache, generaldelta, revlogv1, sparserevlog, store (no-zstd no-dirstate-v2 !)
648 preserved: dotencode, fncache, generaldelta, revlogv1, sparserevlog, store (no-zstd no-dirstate-v2 !)
646 preserved: dotencode, fncache, generaldelta, revlog-compression-zstd, revlogv1, sparserevlog, store (zstd no-dirstate-v2 !)
649 preserved: dotencode, fncache, generaldelta, revlog-compression-zstd, revlogv1, sparserevlog, store (zstd no-dirstate-v2 !)
647 preserved: dotencode, exp-dirstate-v2, fncache, generaldelta, revlog-compression-zstd, revlogv1, sparserevlog, store (zstd dirstate-v2 !)
650 preserved: dotencode, exp-dirstate-v2, fncache, generaldelta, revlog-compression-zstd, revlogv1, sparserevlog, store (zstd dirstate-v2 !)
648 added: persistent-nodemap
651 added: persistent-nodemap
649
652
650 persistent-nodemap
653 persistent-nodemap
651 Speedup revision lookup by node id.
654 Speedup revision lookup by node id.
652
655
653 processed revlogs:
656 processed revlogs:
654 - all-filelogs
657 - all-filelogs
655 - changelog
658 - changelog
656 - manifest
659 - manifest
657
660
658 beginning upgrade...
661 beginning upgrade...
659 repository locked and read-only
662 repository locked and read-only
660 creating temporary repository to stage upgraded data: $TESTTMP/test-repo/.hg/upgrade.* (glob)
663 creating temporary repository to stage upgraded data: $TESTTMP/test-repo/.hg/upgrade.* (glob)
661 (it is safe to interrupt this process any time before data migration completes)
664 (it is safe to interrupt this process any time before data migration completes)
662 upgrading repository to use persistent nodemap feature
665 upgrading repository to use persistent nodemap feature
663 removing temporary repository $TESTTMP/test-repo/.hg/upgrade.* (glob)
666 removing temporary repository $TESTTMP/test-repo/.hg/upgrade.* (glob)
664 $ ls -1 .hg/store/ | egrep '00(changelog|manifest)(\.n|-.*\.nd)'
667 $ ls -1 .hg/store/ | egrep '00(changelog|manifest)(\.n|-.*\.nd)'
665 00changelog-*.nd (glob)
668 00changelog-*.nd (glob)
666 00changelog.n
669 00changelog.n
667 00manifest-*.nd (glob)
670 00manifest-*.nd (glob)
668 00manifest.n
671 00manifest.n
669 undo.backup.00changelog.n
672 undo.backup.00changelog.n
670 undo.backup.00manifest.n
673 undo.backup.00manifest.n
671
674
672 $ hg debugnodemap --metadata
675 $ hg debugnodemap --metadata
673 uid: * (glob)
676 uid: * (glob)
674 tip-rev: 5005
677 tip-rev: 5005
675 tip-node: 90d5d3ba2fc47db50f712570487cb261a68c8ffe
678 tip-node: 90d5d3ba2fc47db50f712570487cb261a68c8ffe
676 data-length: 121088
679 data-length: 121088
677 data-unused: 0
680 data-unused: 0
678 data-unused: 0.000%
681 data-unused: 0.000%
679
682
680 Running unrelated upgrade
683 Running unrelated upgrade
681
684
682 $ hg debugupgraderepo --run --no-backup --quiet --optimize re-delta-all
685 $ hg debugupgraderepo --run --no-backup --quiet --optimize re-delta-all
683 upgrade will perform the following actions:
686 upgrade will perform the following actions:
684
687
685 requirements
688 requirements
686 preserved: dotencode, fncache, generaldelta, persistent-nodemap, revlogv1, sparserevlog, store (no-zstd no-dirstate-v2 !)
689 preserved: dotencode, fncache, generaldelta, persistent-nodemap, revlogv1, sparserevlog, store (no-zstd no-dirstate-v2 !)
687 preserved: dotencode, fncache, generaldelta, persistent-nodemap, revlog-compression-zstd, revlogv1, sparserevlog, store (zstd no-dirstate-v2 !)
690 preserved: dotencode, fncache, generaldelta, persistent-nodemap, revlog-compression-zstd, revlogv1, sparserevlog, store (zstd no-dirstate-v2 !)
688 preserved: dotencode, exp-dirstate-v2, fncache, generaldelta, persistent-nodemap, revlog-compression-zstd, revlogv1, sparserevlog, store (zstd dirstate-v2 !)
691 preserved: dotencode, exp-dirstate-v2, fncache, generaldelta, persistent-nodemap, revlog-compression-zstd, revlogv1, sparserevlog, store (zstd dirstate-v2 !)
689
692
690 optimisations: re-delta-all
693 optimisations: re-delta-all
691
694
692 processed revlogs:
695 processed revlogs:
693 - all-filelogs
696 - all-filelogs
694 - changelog
697 - changelog
695 - manifest
698 - manifest
696
699
697 $ ls -1 .hg/store/ | egrep '00(changelog|manifest)(\.n|-.*\.nd)'
700 $ ls -1 .hg/store/ | egrep '00(changelog|manifest)(\.n|-.*\.nd)'
698 00changelog-*.nd (glob)
701 00changelog-*.nd (glob)
699 00changelog.n
702 00changelog.n
700 00manifest-*.nd (glob)
703 00manifest-*.nd (glob)
701 00manifest.n
704 00manifest.n
702
705
703 $ hg debugnodemap --metadata
706 $ hg debugnodemap --metadata
704 uid: * (glob)
707 uid: * (glob)
705 tip-rev: 5005
708 tip-rev: 5005
706 tip-node: 90d5d3ba2fc47db50f712570487cb261a68c8ffe
709 tip-node: 90d5d3ba2fc47db50f712570487cb261a68c8ffe
707 data-length: 121088
710 data-length: 121088
708 data-unused: 0
711 data-unused: 0
709 data-unused: 0.000%
712 data-unused: 0.000%
710
713
711 Persistent nodemap and local/streaming clone
714 Persistent nodemap and local/streaming clone
712 ============================================
715 ============================================
713
716
714 $ cd ..
717 $ cd ..
715
718
716 standard clone
719 standard clone
717 --------------
720 --------------
718
721
719 The persistent nodemap should exist after a streaming clone
722 The persistent nodemap should exist after a streaming clone
720
723
721 $ hg clone --pull --quiet -U test-repo standard-clone
724 $ hg clone --pull --quiet -U test-repo standard-clone
722 $ ls -1 standard-clone/.hg/store/ | egrep '00(changelog|manifest)(\.n|-.*\.nd)'
725 $ ls -1 standard-clone/.hg/store/ | egrep '00(changelog|manifest)(\.n|-.*\.nd)'
723 00changelog-*.nd (glob)
726 00changelog-*.nd (glob)
724 00changelog.n
727 00changelog.n
725 00manifest-*.nd (glob)
728 00manifest-*.nd (glob)
726 00manifest.n
729 00manifest.n
727 $ hg -R standard-clone debugnodemap --metadata
730 $ hg -R standard-clone debugnodemap --metadata
728 uid: * (glob)
731 uid: * (glob)
729 tip-rev: 5005
732 tip-rev: 5005
730 tip-node: 90d5d3ba2fc47db50f712570487cb261a68c8ffe
733 tip-node: 90d5d3ba2fc47db50f712570487cb261a68c8ffe
731 data-length: 121088
734 data-length: 121088
732 data-unused: 0
735 data-unused: 0
733 data-unused: 0.000%
736 data-unused: 0.000%
734
737
735
738
736 local clone
739 local clone
737 ------------
740 ------------
738
741
739 The persistent nodemap should exist after a streaming clone
742 The persistent nodemap should exist after a streaming clone
740
743
741 $ hg clone -U test-repo local-clone
744 $ hg clone -U test-repo local-clone
742 $ ls -1 local-clone/.hg/store/ | egrep '00(changelog|manifest)(\.n|-.*\.nd)'
745 $ ls -1 local-clone/.hg/store/ | egrep '00(changelog|manifest)(\.n|-.*\.nd)'
743 00changelog-*.nd (glob)
746 00changelog-*.nd (glob)
744 00changelog.n
747 00changelog.n
745 00manifest-*.nd (glob)
748 00manifest-*.nd (glob)
746 00manifest.n
749 00manifest.n
747 $ hg -R local-clone debugnodemap --metadata
750 $ hg -R local-clone debugnodemap --metadata
748 uid: * (glob)
751 uid: * (glob)
749 tip-rev: 5005
752 tip-rev: 5005
750 tip-node: 90d5d3ba2fc47db50f712570487cb261a68c8ffe
753 tip-node: 90d5d3ba2fc47db50f712570487cb261a68c8ffe
751 data-length: 121088
754 data-length: 121088
752 data-unused: 0
755 data-unused: 0
753 data-unused: 0.000%
756 data-unused: 0.000%
754
757
755 Test various corruption case
758 Test various corruption case
756 ============================
759 ============================
757
760
758 Missing datafile
761 Missing datafile
759 ----------------
762 ----------------
760
763
761 Test behavior with a missing datafile
764 Test behavior with a missing datafile
762
765
763 $ hg clone --quiet --pull test-repo corruption-test-repo
766 $ hg clone --quiet --pull test-repo corruption-test-repo
764 $ ls -1 corruption-test-repo/.hg/store/00changelog*
767 $ ls -1 corruption-test-repo/.hg/store/00changelog*
765 corruption-test-repo/.hg/store/00changelog-*.nd (glob)
768 corruption-test-repo/.hg/store/00changelog-*.nd (glob)
766 corruption-test-repo/.hg/store/00changelog.d
769 corruption-test-repo/.hg/store/00changelog.d
767 corruption-test-repo/.hg/store/00changelog.i
770 corruption-test-repo/.hg/store/00changelog.i
768 corruption-test-repo/.hg/store/00changelog.n
771 corruption-test-repo/.hg/store/00changelog.n
769 $ rm corruption-test-repo/.hg/store/00changelog*.nd
772 $ rm corruption-test-repo/.hg/store/00changelog*.nd
770 $ hg log -R corruption-test-repo -r .
773 $ hg log -R corruption-test-repo -r .
771 changeset: 5005:90d5d3ba2fc4
774 changeset: 5005:90d5d3ba2fc4
772 tag: tip
775 tag: tip
773 user: test
776 user: test
774 date: Thu Jan 01 00:00:00 1970 +0000
777 date: Thu Jan 01 00:00:00 1970 +0000
775 summary: a2
778 summary: a2
776
779
777 $ ls -1 corruption-test-repo/.hg/store/00changelog*
780 $ ls -1 corruption-test-repo/.hg/store/00changelog*
778 corruption-test-repo/.hg/store/00changelog.d
781 corruption-test-repo/.hg/store/00changelog.d
779 corruption-test-repo/.hg/store/00changelog.i
782 corruption-test-repo/.hg/store/00changelog.i
780 corruption-test-repo/.hg/store/00changelog.n
783 corruption-test-repo/.hg/store/00changelog.n
781
784
782 Truncated data file
785 Truncated data file
783 -------------------
786 -------------------
784
787
785 Test behavior with a too short datafile
788 Test behavior with a too short datafile
786
789
787 rebuild the missing data
790 rebuild the missing data
788 $ hg -R corruption-test-repo debugupdatecache
791 $ hg -R corruption-test-repo debugupdatecache
789 $ ls -1 corruption-test-repo/.hg/store/00changelog*
792 $ ls -1 corruption-test-repo/.hg/store/00changelog*
790 corruption-test-repo/.hg/store/00changelog-*.nd (glob)
793 corruption-test-repo/.hg/store/00changelog-*.nd (glob)
791 corruption-test-repo/.hg/store/00changelog.d
794 corruption-test-repo/.hg/store/00changelog.d
792 corruption-test-repo/.hg/store/00changelog.i
795 corruption-test-repo/.hg/store/00changelog.i
793 corruption-test-repo/.hg/store/00changelog.n
796 corruption-test-repo/.hg/store/00changelog.n
794
797
795 truncate the file
798 truncate the file
796
799
797 $ datafilepath=`ls corruption-test-repo/.hg/store/00changelog*.nd`
800 $ datafilepath=`ls corruption-test-repo/.hg/store/00changelog*.nd`
798 $ f -s $datafilepath
801 $ f -s $datafilepath
799 corruption-test-repo/.hg/store/00changelog-*.nd: size=121088 (glob)
802 corruption-test-repo/.hg/store/00changelog-*.nd: size=121088 (glob)
800 $ dd if=$datafilepath bs=1000 count=10 of=$datafilepath-tmp status=noxfer
803 $ dd if=$datafilepath bs=1000 count=10 of=$datafilepath-tmp status=noxfer
801 10+0 records in
804 10+0 records in
802 10+0 records out
805 10+0 records out
803 $ mv $datafilepath-tmp $datafilepath
806 $ mv $datafilepath-tmp $datafilepath
804 $ f -s $datafilepath
807 $ f -s $datafilepath
805 corruption-test-repo/.hg/store/00changelog-*.nd: size=10000 (glob)
808 corruption-test-repo/.hg/store/00changelog-*.nd: size=10000 (glob)
806
809
807 Check that Mercurial reaction to this event
810 Check that Mercurial reaction to this event
808
811
809 $ hg -R corruption-test-repo log -r . --traceback
812 $ hg -R corruption-test-repo log -r . --traceback
810 changeset: 5005:90d5d3ba2fc4
813 changeset: 5005:90d5d3ba2fc4
811 tag: tip
814 tag: tip
812 user: test
815 user: test
813 date: Thu Jan 01 00:00:00 1970 +0000
816 date: Thu Jan 01 00:00:00 1970 +0000
814 summary: a2
817 summary: a2
815
818
816
819
817
820
818 stream clone
821 stream clone
819 ============
822 ============
820
823
821 The persistent nodemap should exist after a streaming clone
824 The persistent nodemap should exist after a streaming clone
822
825
823 Simple case
826 Simple case
824 -----------
827 -----------
825
828
826 No race condition
829 No race condition
827
830
828 $ hg clone -U --stream --config ui.ssh="\"$PYTHON\" \"$TESTDIR/dummyssh\"" ssh://user@dummy/test-repo stream-clone --debug | egrep '00(changelog|manifest)'
831 $ hg clone -U --stream --config ui.ssh="\"$PYTHON\" \"$TESTDIR/dummyssh\"" ssh://user@dummy/test-repo stream-clone --debug | egrep '00(changelog|manifest)'
829 adding [s] 00manifest.n (62 bytes)
832 adding [s] 00manifest.n (62 bytes)
830 adding [s] 00manifest-*.nd (118 KB) (glob)
833 adding [s] 00manifest-*.nd (118 KB) (glob)
831 adding [s] 00changelog.n (62 bytes)
834 adding [s] 00changelog.n (62 bytes)
832 adding [s] 00changelog-*.nd (118 KB) (glob)
835 adding [s] 00changelog-*.nd (118 KB) (glob)
833 adding [s] 00manifest.d (452 KB) (no-zstd !)
836 adding [s] 00manifest.d (452 KB) (no-zstd !)
834 adding [s] 00manifest.d (491 KB) (zstd !)
837 adding [s] 00manifest.d (491 KB) (zstd !)
835 adding [s] 00changelog.d (360 KB) (no-zstd !)
838 adding [s] 00changelog.d (360 KB) (no-zstd !)
836 adding [s] 00changelog.d (368 KB) (zstd !)
839 adding [s] 00changelog.d (368 KB) (zstd !)
837 adding [s] 00manifest.i (313 KB)
840 adding [s] 00manifest.i (313 KB)
838 adding [s] 00changelog.i (313 KB)
841 adding [s] 00changelog.i (313 KB)
839 $ ls -1 stream-clone/.hg/store/ | egrep '00(changelog|manifest)(\.n|-.*\.nd)'
842 $ ls -1 stream-clone/.hg/store/ | egrep '00(changelog|manifest)(\.n|-.*\.nd)'
840 00changelog-*.nd (glob)
843 00changelog-*.nd (glob)
841 00changelog.n
844 00changelog.n
842 00manifest-*.nd (glob)
845 00manifest-*.nd (glob)
843 00manifest.n
846 00manifest.n
844 $ hg -R stream-clone debugnodemap --metadata
847 $ hg -R stream-clone debugnodemap --metadata
845 uid: * (glob)
848 uid: * (glob)
846 tip-rev: 5005
849 tip-rev: 5005
847 tip-node: 90d5d3ba2fc47db50f712570487cb261a68c8ffe
850 tip-node: 90d5d3ba2fc47db50f712570487cb261a68c8ffe
848 data-length: 121088
851 data-length: 121088
849 data-unused: 0
852 data-unused: 0
850 data-unused: 0.000%
853 data-unused: 0.000%
851
854
852 new data appened
855 new data appened
853 -----------------
856 -----------------
854
857
855 Other commit happening on the server during the stream clone
858 Other commit happening on the server during the stream clone
856
859
857 setup the step-by-step stream cloning
860 setup the step-by-step stream cloning
858
861
859 $ HG_TEST_STREAM_WALKED_FILE_1="$TESTTMP/sync_file_walked_1"
862 $ HG_TEST_STREAM_WALKED_FILE_1="$TESTTMP/sync_file_walked_1"
860 $ export HG_TEST_STREAM_WALKED_FILE_1
863 $ export HG_TEST_STREAM_WALKED_FILE_1
861 $ HG_TEST_STREAM_WALKED_FILE_2="$TESTTMP/sync_file_walked_2"
864 $ HG_TEST_STREAM_WALKED_FILE_2="$TESTTMP/sync_file_walked_2"
862 $ export HG_TEST_STREAM_WALKED_FILE_2
865 $ export HG_TEST_STREAM_WALKED_FILE_2
863 $ HG_TEST_STREAM_WALKED_FILE_3="$TESTTMP/sync_file_walked_3"
866 $ HG_TEST_STREAM_WALKED_FILE_3="$TESTTMP/sync_file_walked_3"
864 $ export HG_TEST_STREAM_WALKED_FILE_3
867 $ export HG_TEST_STREAM_WALKED_FILE_3
865 $ cat << EOF >> test-repo/.hg/hgrc
868 $ cat << EOF >> test-repo/.hg/hgrc
866 > [extensions]
869 > [extensions]
867 > steps=$RUNTESTDIR/testlib/ext-stream-clone-steps.py
870 > steps=$RUNTESTDIR/testlib/ext-stream-clone-steps.py
868 > EOF
871 > EOF
869
872
870 Check and record file state beforehand
873 Check and record file state beforehand
871
874
872 $ f --size test-repo/.hg/store/00changelog*
875 $ f --size test-repo/.hg/store/00changelog*
873 test-repo/.hg/store/00changelog-*.nd: size=121088 (glob)
876 test-repo/.hg/store/00changelog-*.nd: size=121088 (glob)
874 test-repo/.hg/store/00changelog.d: size=376891 (zstd !)
877 test-repo/.hg/store/00changelog.d: size=376891 (zstd !)
875 test-repo/.hg/store/00changelog.d: size=368890 (no-zstd !)
878 test-repo/.hg/store/00changelog.d: size=368890 (no-zstd !)
876 test-repo/.hg/store/00changelog.i: size=320384
879 test-repo/.hg/store/00changelog.i: size=320384
877 test-repo/.hg/store/00changelog.n: size=62
880 test-repo/.hg/store/00changelog.n: size=62
878 $ hg -R test-repo debugnodemap --metadata | tee server-metadata.txt
881 $ hg -R test-repo debugnodemap --metadata | tee server-metadata.txt
879 uid: * (glob)
882 uid: * (glob)
880 tip-rev: 5005
883 tip-rev: 5005
881 tip-node: 90d5d3ba2fc47db50f712570487cb261a68c8ffe
884 tip-node: 90d5d3ba2fc47db50f712570487cb261a68c8ffe
882 data-length: 121088
885 data-length: 121088
883 data-unused: 0
886 data-unused: 0
884 data-unused: 0.000%
887 data-unused: 0.000%
885
888
886 Prepare a commit
889 Prepare a commit
887
890
888 $ echo foo >> test-repo/foo
891 $ echo foo >> test-repo/foo
889 $ hg -R test-repo/ add test-repo/foo
892 $ hg -R test-repo/ add test-repo/foo
890
893
891 Do a mix of clone and commit at the same time so that the file listed on disk differ at actual transfer time.
894 Do a mix of clone and commit at the same time so that the file listed on disk differ at actual transfer time.
892
895
893 $ (hg clone -U --stream --config ui.ssh="\"$PYTHON\" \"$TESTDIR/dummyssh\"" ssh://user@dummy/test-repo stream-clone-race-1 --debug 2>> clone-output | egrep '00(changelog|manifest)' >> clone-output; touch $HG_TEST_STREAM_WALKED_FILE_3) &
896 $ (hg clone -U --stream --config ui.ssh="\"$PYTHON\" \"$TESTDIR/dummyssh\"" ssh://user@dummy/test-repo stream-clone-race-1 --debug 2>> clone-output | egrep '00(changelog|manifest)' >> clone-output; touch $HG_TEST_STREAM_WALKED_FILE_3) &
894 $ $RUNTESTDIR/testlib/wait-on-file 10 $HG_TEST_STREAM_WALKED_FILE_1
897 $ $RUNTESTDIR/testlib/wait-on-file 10 $HG_TEST_STREAM_WALKED_FILE_1
895 $ hg -R test-repo/ commit -m foo
898 $ hg -R test-repo/ commit -m foo
896 $ touch $HG_TEST_STREAM_WALKED_FILE_2
899 $ touch $HG_TEST_STREAM_WALKED_FILE_2
897 $ $RUNTESTDIR/testlib/wait-on-file 10 $HG_TEST_STREAM_WALKED_FILE_3
900 $ $RUNTESTDIR/testlib/wait-on-file 10 $HG_TEST_STREAM_WALKED_FILE_3
898 $ cat clone-output
901 $ cat clone-output
899 adding [s] 00manifest.n (62 bytes)
902 adding [s] 00manifest.n (62 bytes)
900 adding [s] 00manifest-*.nd (118 KB) (glob)
903 adding [s] 00manifest-*.nd (118 KB) (glob)
901 adding [s] 00changelog.n (62 bytes)
904 adding [s] 00changelog.n (62 bytes)
902 adding [s] 00changelog-*.nd (118 KB) (glob)
905 adding [s] 00changelog-*.nd (118 KB) (glob)
903 adding [s] 00manifest.d (452 KB) (no-zstd !)
906 adding [s] 00manifest.d (452 KB) (no-zstd !)
904 adding [s] 00manifest.d (491 KB) (zstd !)
907 adding [s] 00manifest.d (491 KB) (zstd !)
905 adding [s] 00changelog.d (360 KB) (no-zstd !)
908 adding [s] 00changelog.d (360 KB) (no-zstd !)
906 adding [s] 00changelog.d (368 KB) (zstd !)
909 adding [s] 00changelog.d (368 KB) (zstd !)
907 adding [s] 00manifest.i (313 KB)
910 adding [s] 00manifest.i (313 KB)
908 adding [s] 00changelog.i (313 KB)
911 adding [s] 00changelog.i (313 KB)
909
912
910 Check the result state
913 Check the result state
911
914
912 $ f --size stream-clone-race-1/.hg/store/00changelog*
915 $ f --size stream-clone-race-1/.hg/store/00changelog*
913 stream-clone-race-1/.hg/store/00changelog-*.nd: size=121088 (glob)
916 stream-clone-race-1/.hg/store/00changelog-*.nd: size=121088 (glob)
914 stream-clone-race-1/.hg/store/00changelog.d: size=368890 (no-zstd !)
917 stream-clone-race-1/.hg/store/00changelog.d: size=368890 (no-zstd !)
915 stream-clone-race-1/.hg/store/00changelog.d: size=376891 (zstd !)
918 stream-clone-race-1/.hg/store/00changelog.d: size=376891 (zstd !)
916 stream-clone-race-1/.hg/store/00changelog.i: size=320384
919 stream-clone-race-1/.hg/store/00changelog.i: size=320384
917 stream-clone-race-1/.hg/store/00changelog.n: size=62
920 stream-clone-race-1/.hg/store/00changelog.n: size=62
918
921
919 $ hg -R stream-clone-race-1 debugnodemap --metadata | tee client-metadata.txt
922 $ hg -R stream-clone-race-1 debugnodemap --metadata | tee client-metadata.txt
920 uid: * (glob)
923 uid: * (glob)
921 tip-rev: 5005
924 tip-rev: 5005
922 tip-node: 90d5d3ba2fc47db50f712570487cb261a68c8ffe
925 tip-node: 90d5d3ba2fc47db50f712570487cb261a68c8ffe
923 data-length: 121088
926 data-length: 121088
924 data-unused: 0
927 data-unused: 0
925 data-unused: 0.000%
928 data-unused: 0.000%
926
929
927 We get a usable nodemap, so no rewrite would be needed and the metadata should be identical
930 We get a usable nodemap, so no rewrite would be needed and the metadata should be identical
928 (ie: the following diff should be empty)
931 (ie: the following diff should be empty)
929
932
930 This isn't the case for the `no-rust` `no-pure` implementation as it use a very minimal nodemap implementation that unconditionnaly rewrite the nodemap "all the time".
933 This isn't the case for the `no-rust` `no-pure` implementation as it use a very minimal nodemap implementation that unconditionnaly rewrite the nodemap "all the time".
931
934
932 #if no-rust no-pure
935 #if no-rust no-pure
933 $ diff -u server-metadata.txt client-metadata.txt
936 $ diff -u server-metadata.txt client-metadata.txt
934 --- server-metadata.txt * (glob)
937 --- server-metadata.txt * (glob)
935 +++ client-metadata.txt * (glob)
938 +++ client-metadata.txt * (glob)
936 @@ -1,4 +1,4 @@
939 @@ -1,4 +1,4 @@
937 -uid: * (glob)
940 -uid: * (glob)
938 +uid: * (glob)
941 +uid: * (glob)
939 tip-rev: 5005
942 tip-rev: 5005
940 tip-node: 90d5d3ba2fc47db50f712570487cb261a68c8ffe
943 tip-node: 90d5d3ba2fc47db50f712570487cb261a68c8ffe
941 data-length: 121088
944 data-length: 121088
942 [1]
945 [1]
943 #else
946 #else
944 $ diff -u server-metadata.txt client-metadata.txt
947 $ diff -u server-metadata.txt client-metadata.txt
945 #endif
948 #endif
946
949
947
950
948 Clean up after the test.
951 Clean up after the test.
949
952
950 $ rm -f "$HG_TEST_STREAM_WALKED_FILE_1"
953 $ rm -f "$HG_TEST_STREAM_WALKED_FILE_1"
951 $ rm -f "$HG_TEST_STREAM_WALKED_FILE_2"
954 $ rm -f "$HG_TEST_STREAM_WALKED_FILE_2"
952 $ rm -f "$HG_TEST_STREAM_WALKED_FILE_3"
955 $ rm -f "$HG_TEST_STREAM_WALKED_FILE_3"
953
956
954 full regeneration
957 full regeneration
955 -----------------
958 -----------------
956
959
957 A full nodemap is generated
960 A full nodemap is generated
958
961
959 (ideally this test would append enough data to make sure the nodemap data file
962 (ideally this test would append enough data to make sure the nodemap data file
960 get changed, however to make thing simpler we will force the regeneration for
963 get changed, however to make thing simpler we will force the regeneration for
961 this test.
964 this test.
962
965
963 Check the initial state
966 Check the initial state
964
967
965 $ f --size test-repo/.hg/store/00changelog*
968 $ f --size test-repo/.hg/store/00changelog*
966 test-repo/.hg/store/00changelog-*.nd: size=121344 (glob) (rust !)
969 test-repo/.hg/store/00changelog-*.nd: size=121344 (glob) (rust !)
967 test-repo/.hg/store/00changelog-*.nd: size=121344 (glob) (pure !)
970 test-repo/.hg/store/00changelog-*.nd: size=121344 (glob) (pure !)
968 test-repo/.hg/store/00changelog-*.nd: size=121152 (glob) (no-rust no-pure !)
971 test-repo/.hg/store/00changelog-*.nd: size=121152 (glob) (no-rust no-pure !)
969 test-repo/.hg/store/00changelog.d: size=376950 (zstd !)
972 test-repo/.hg/store/00changelog.d: size=376950 (zstd !)
970 test-repo/.hg/store/00changelog.d: size=368949 (no-zstd !)
973 test-repo/.hg/store/00changelog.d: size=368949 (no-zstd !)
971 test-repo/.hg/store/00changelog.i: size=320448
974 test-repo/.hg/store/00changelog.i: size=320448
972 test-repo/.hg/store/00changelog.n: size=62
975 test-repo/.hg/store/00changelog.n: size=62
973 $ hg -R test-repo debugnodemap --metadata | tee server-metadata-2.txt
976 $ hg -R test-repo debugnodemap --metadata | tee server-metadata-2.txt
974 uid: * (glob)
977 uid: * (glob)
975 tip-rev: 5006
978 tip-rev: 5006
976 tip-node: ed2ec1eef9aa2a0ec5057c51483bc148d03e810b
979 tip-node: ed2ec1eef9aa2a0ec5057c51483bc148d03e810b
977 data-length: 121344 (rust !)
980 data-length: 121344 (rust !)
978 data-length: 121344 (pure !)
981 data-length: 121344 (pure !)
979 data-length: 121152 (no-rust no-pure !)
982 data-length: 121152 (no-rust no-pure !)
980 data-unused: 192 (rust !)
983 data-unused: 192 (rust !)
981 data-unused: 192 (pure !)
984 data-unused: 192 (pure !)
982 data-unused: 0 (no-rust no-pure !)
985 data-unused: 0 (no-rust no-pure !)
983 data-unused: 0.158% (rust !)
986 data-unused: 0.158% (rust !)
984 data-unused: 0.158% (pure !)
987 data-unused: 0.158% (pure !)
985 data-unused: 0.000% (no-rust no-pure !)
988 data-unused: 0.000% (no-rust no-pure !)
986
989
987 Performe the mix of clone and full refresh of the nodemap, so that the files
990 Performe the mix of clone and full refresh of the nodemap, so that the files
988 (and filenames) are different between listing time and actual transfer time.
991 (and filenames) are different between listing time and actual transfer time.
989
992
990 $ (hg clone -U --stream --config ui.ssh="\"$PYTHON\" \"$TESTDIR/dummyssh\"" ssh://user@dummy/test-repo stream-clone-race-2 --debug 2>> clone-output-2 | egrep '00(changelog|manifest)' >> clone-output-2; touch $HG_TEST_STREAM_WALKED_FILE_3) &
993 $ (hg clone -U --stream --config ui.ssh="\"$PYTHON\" \"$TESTDIR/dummyssh\"" ssh://user@dummy/test-repo stream-clone-race-2 --debug 2>> clone-output-2 | egrep '00(changelog|manifest)' >> clone-output-2; touch $HG_TEST_STREAM_WALKED_FILE_3) &
991 $ $RUNTESTDIR/testlib/wait-on-file 10 $HG_TEST_STREAM_WALKED_FILE_1
994 $ $RUNTESTDIR/testlib/wait-on-file 10 $HG_TEST_STREAM_WALKED_FILE_1
992 $ rm test-repo/.hg/store/00changelog.n
995 $ rm test-repo/.hg/store/00changelog.n
993 $ rm test-repo/.hg/store/00changelog-*.nd
996 $ rm test-repo/.hg/store/00changelog-*.nd
994 $ hg -R test-repo/ debugupdatecache
997 $ hg -R test-repo/ debugupdatecache
995 $ touch $HG_TEST_STREAM_WALKED_FILE_2
998 $ touch $HG_TEST_STREAM_WALKED_FILE_2
996 $ $RUNTESTDIR/testlib/wait-on-file 10 $HG_TEST_STREAM_WALKED_FILE_3
999 $ $RUNTESTDIR/testlib/wait-on-file 10 $HG_TEST_STREAM_WALKED_FILE_3
997 $ cat clone-output-2
1000 $ cat clone-output-2
998 adding [s] 00manifest.n (62 bytes)
1001 adding [s] 00manifest.n (62 bytes)
999 adding [s] 00manifest-*.nd (118 KB) (glob)
1002 adding [s] 00manifest-*.nd (118 KB) (glob)
1000 adding [s] 00changelog.n (62 bytes)
1003 adding [s] 00changelog.n (62 bytes)
1001 adding [s] 00changelog-*.nd (118 KB) (glob)
1004 adding [s] 00changelog-*.nd (118 KB) (glob)
1002 adding [s] 00manifest.d (492 KB) (zstd !)
1005 adding [s] 00manifest.d (492 KB) (zstd !)
1003 adding [s] 00manifest.d (452 KB) (no-zstd !)
1006 adding [s] 00manifest.d (452 KB) (no-zstd !)
1004 adding [s] 00changelog.d (360 KB) (no-zstd !)
1007 adding [s] 00changelog.d (360 KB) (no-zstd !)
1005 adding [s] 00changelog.d (368 KB) (zstd !)
1008 adding [s] 00changelog.d (368 KB) (zstd !)
1006 adding [s] 00manifest.i (313 KB)
1009 adding [s] 00manifest.i (313 KB)
1007 adding [s] 00changelog.i (313 KB)
1010 adding [s] 00changelog.i (313 KB)
1008
1011
1009 Check the result.
1012 Check the result.
1010
1013
1011 $ f --size stream-clone-race-2/.hg/store/00changelog*
1014 $ f --size stream-clone-race-2/.hg/store/00changelog*
1012 stream-clone-race-2/.hg/store/00changelog-*.nd: size=121344 (glob) (rust !)
1015 stream-clone-race-2/.hg/store/00changelog-*.nd: size=121344 (glob) (rust !)
1013 stream-clone-race-2/.hg/store/00changelog-*.nd: size=121344 (glob) (pure !)
1016 stream-clone-race-2/.hg/store/00changelog-*.nd: size=121344 (glob) (pure !)
1014 stream-clone-race-2/.hg/store/00changelog-*.nd: size=121152 (glob) (no-rust no-pure !)
1017 stream-clone-race-2/.hg/store/00changelog-*.nd: size=121152 (glob) (no-rust no-pure !)
1015 stream-clone-race-2/.hg/store/00changelog.d: size=376950 (zstd !)
1018 stream-clone-race-2/.hg/store/00changelog.d: size=376950 (zstd !)
1016 stream-clone-race-2/.hg/store/00changelog.d: size=368949 (no-zstd !)
1019 stream-clone-race-2/.hg/store/00changelog.d: size=368949 (no-zstd !)
1017 stream-clone-race-2/.hg/store/00changelog.i: size=320448
1020 stream-clone-race-2/.hg/store/00changelog.i: size=320448
1018 stream-clone-race-2/.hg/store/00changelog.n: size=62
1021 stream-clone-race-2/.hg/store/00changelog.n: size=62
1019
1022
1020 $ hg -R stream-clone-race-2 debugnodemap --metadata | tee client-metadata-2.txt
1023 $ hg -R stream-clone-race-2 debugnodemap --metadata | tee client-metadata-2.txt
1021 uid: * (glob)
1024 uid: * (glob)
1022 tip-rev: 5006
1025 tip-rev: 5006
1023 tip-node: ed2ec1eef9aa2a0ec5057c51483bc148d03e810b
1026 tip-node: ed2ec1eef9aa2a0ec5057c51483bc148d03e810b
1024 data-length: 121344 (rust !)
1027 data-length: 121344 (rust !)
1025 data-unused: 192 (rust !)
1028 data-unused: 192 (rust !)
1026 data-unused: 0.158% (rust !)
1029 data-unused: 0.158% (rust !)
1027 data-length: 121152 (no-rust no-pure !)
1030 data-length: 121152 (no-rust no-pure !)
1028 data-unused: 0 (no-rust no-pure !)
1031 data-unused: 0 (no-rust no-pure !)
1029 data-unused: 0.000% (no-rust no-pure !)
1032 data-unused: 0.000% (no-rust no-pure !)
1030 data-length: 121344 (pure !)
1033 data-length: 121344 (pure !)
1031 data-unused: 192 (pure !)
1034 data-unused: 192 (pure !)
1032 data-unused: 0.158% (pure !)
1035 data-unused: 0.158% (pure !)
1033
1036
1034 We get a usable nodemap, so no rewrite would be needed and the metadata should be identical
1037 We get a usable nodemap, so no rewrite would be needed and the metadata should be identical
1035 (ie: the following diff should be empty)
1038 (ie: the following diff should be empty)
1036
1039
1037 This isn't the case for the `no-rust` `no-pure` implementation as it use a very minimal nodemap implementation that unconditionnaly rewrite the nodemap "all the time".
1040 This isn't the case for the `no-rust` `no-pure` implementation as it use a very minimal nodemap implementation that unconditionnaly rewrite the nodemap "all the time".
1038
1041
1039 #if no-rust no-pure
1042 #if no-rust no-pure
1040 $ diff -u server-metadata-2.txt client-metadata-2.txt
1043 $ diff -u server-metadata-2.txt client-metadata-2.txt
1041 --- server-metadata-2.txt * (glob)
1044 --- server-metadata-2.txt * (glob)
1042 +++ client-metadata-2.txt * (glob)
1045 +++ client-metadata-2.txt * (glob)
1043 @@ -1,4 +1,4 @@
1046 @@ -1,4 +1,4 @@
1044 -uid: * (glob)
1047 -uid: * (glob)
1045 +uid: * (glob)
1048 +uid: * (glob)
1046 tip-rev: 5006
1049 tip-rev: 5006
1047 tip-node: ed2ec1eef9aa2a0ec5057c51483bc148d03e810b
1050 tip-node: ed2ec1eef9aa2a0ec5057c51483bc148d03e810b
1048 data-length: 121152
1051 data-length: 121152
1049 [1]
1052 [1]
1050 #else
1053 #else
1051 $ diff -u server-metadata-2.txt client-metadata-2.txt
1054 $ diff -u server-metadata-2.txt client-metadata-2.txt
1052 #endif
1055 #endif
1053
1056
1054 Clean up after the test
1057 Clean up after the test
1055
1058
1056 $ rm -f $HG_TEST_STREAM_WALKED_FILE_1
1059 $ rm -f $HG_TEST_STREAM_WALKED_FILE_1
1057 $ rm -f $HG_TEST_STREAM_WALKED_FILE_2
1060 $ rm -f $HG_TEST_STREAM_WALKED_FILE_2
1058 $ rm -f $HG_TEST_STREAM_WALKED_FILE_3
1061 $ rm -f $HG_TEST_STREAM_WALKED_FILE_3
1059
1062
@@ -1,122 +1,126 b''
1 ==========================================================
1 ==========================================================
2 Test file dedicated to checking side-data related behavior
2 Test file dedicated to checking side-data related behavior
3 ==========================================================
3 ==========================================================
4
4
5 Check data can be written/read from sidedata
5 Check data can be written/read from sidedata
6 ============================================
6 ============================================
7
7
8 $ cat << EOF >> $HGRCPATH
8 $ cat << EOF >> $HGRCPATH
9 > [extensions]
9 > [extensions]
10 > testsidedata=$TESTDIR/testlib/ext-sidedata.py
10 > testsidedata=$TESTDIR/testlib/ext-sidedata.py
11 > EOF
11 > EOF
12
12
13 $ hg init test-sidedata --config experimental.revlogv2=enable-unstable-format-and-corrupt-my-data
13 $ hg init test-sidedata --config experimental.revlogv2=enable-unstable-format-and-corrupt-my-data
14 $ cd test-sidedata
14 $ cd test-sidedata
15 $ echo aaa > a
15 $ echo aaa > a
16 $ hg add a
16 $ hg add a
17 $ hg commit -m a --traceback
17 $ hg commit -m a --traceback
18 $ echo aaa > b
18 $ echo aaa > b
19 $ hg add b
19 $ hg add b
20 $ hg commit -m b
20 $ hg commit -m b
21 $ echo xxx >> a
21 $ echo xxx >> a
22 $ hg commit -m aa
22 $ hg commit -m aa
23
23
24 $ hg debugsidedata -c 0
24 $ hg debugsidedata -c 0
25 2 sidedata entries
25 2 sidedata entries
26 entry-0001 size 4
26 entry-0001 size 4
27 entry-0002 size 32
27 entry-0002 size 32
28 $ hg debugsidedata -c 1 -v
28 $ hg debugsidedata -c 1 -v
29 2 sidedata entries
29 2 sidedata entries
30 entry-0001 size 4
30 entry-0001 size 4
31 '\x00\x00\x006'
31 '\x00\x00\x006'
32 entry-0002 size 32
32 entry-0002 size 32
33 '\x98\t\xf9\xc4v\xf0\xc5P\x90\xf7wRf\xe8\xe27e\xfc\xc1\x93\xa4\x96\xd0\x1d\x97\xaaG\x1d\xd7t\xfa\xde'
33 '\x98\t\xf9\xc4v\xf0\xc5P\x90\xf7wRf\xe8\xe27e\xfc\xc1\x93\xa4\x96\xd0\x1d\x97\xaaG\x1d\xd7t\xfa\xde'
34 $ hg debugsidedata -m 2
34 $ hg debugsidedata -m 2
35 2 sidedata entries
35 2 sidedata entries
36 entry-0001 size 4
36 entry-0001 size 4
37 entry-0002 size 32
37 entry-0002 size 32
38 $ hg debugsidedata a 1
38 $ hg debugsidedata a 1
39 2 sidedata entries
39 2 sidedata entries
40 entry-0001 size 4
40 entry-0001 size 4
41 entry-0002 size 32
41 entry-0002 size 32
42
42
43 Check upgrade behavior
43 Check upgrade behavior
44 ======================
44 ======================
45
45
46 Right now, sidedata has not upgrade support
46 Right now, sidedata has not upgrade support
47
47
48 Check that we can upgrade to sidedata
48 Check that we can upgrade to sidedata
49 -------------------------------------
49 -------------------------------------
50
50
51 $ hg init up-no-side-data --config experimental.revlogv2=no
51 $ hg init up-no-side-data --config experimental.revlogv2=no
52 $ hg debugformat -v -R up-no-side-data
52 $ hg debugformat -v -R up-no-side-data
53 format-variant repo config default
53 format-variant repo config default
54 fncache: yes yes yes
54 fncache: yes yes yes
55 dirstate-v2: no no no
55 dotencode: yes yes yes
56 dotencode: yes yes yes
56 generaldelta: yes yes yes
57 generaldelta: yes yes yes
57 share-safe: no no no
58 share-safe: no no no
58 sparserevlog: yes yes yes
59 sparserevlog: yes yes yes
59 persistent-nodemap: no no no (no-rust !)
60 persistent-nodemap: no no no (no-rust !)
60 persistent-nodemap: yes yes no (rust !)
61 persistent-nodemap: yes yes no (rust !)
61 copies-sdc: no no no
62 copies-sdc: no no no
62 revlog-v2: no no no
63 revlog-v2: no no no
63 changelog-v2: no no no
64 changelog-v2: no no no
64 plain-cl-delta: yes yes yes
65 plain-cl-delta: yes yes yes
65 compression: zlib zlib zlib (no-zstd !)
66 compression: zlib zlib zlib (no-zstd !)
66 compression: zstd zstd zstd (zstd !)
67 compression: zstd zstd zstd (zstd !)
67 compression-level: default default default
68 compression-level: default default default
68 $ hg debugformat -v -R up-no-side-data --config experimental.revlogv2=enable-unstable-format-and-corrupt-my-data
69 $ hg debugformat -v -R up-no-side-data --config experimental.revlogv2=enable-unstable-format-and-corrupt-my-data
69 format-variant repo config default
70 format-variant repo config default
70 fncache: yes yes yes
71 fncache: yes yes yes
72 dirstate-v2: no no no
71 dotencode: yes yes yes
73 dotencode: yes yes yes
72 generaldelta: yes yes yes
74 generaldelta: yes yes yes
73 share-safe: no no no
75 share-safe: no no no
74 sparserevlog: yes yes yes
76 sparserevlog: yes yes yes
75 persistent-nodemap: no no no (no-rust !)
77 persistent-nodemap: no no no (no-rust !)
76 persistent-nodemap: yes yes no (rust !)
78 persistent-nodemap: yes yes no (rust !)
77 copies-sdc: no no no
79 copies-sdc: no no no
78 revlog-v2: no yes no
80 revlog-v2: no yes no
79 changelog-v2: no no no
81 changelog-v2: no no no
80 plain-cl-delta: yes yes yes
82 plain-cl-delta: yes yes yes
81 compression: zlib zlib zlib (no-zstd !)
83 compression: zlib zlib zlib (no-zstd !)
82 compression: zstd zstd zstd (zstd !)
84 compression: zstd zstd zstd (zstd !)
83 compression-level: default default default
85 compression-level: default default default
84 $ hg debugupgraderepo -R up-no-side-data --config experimental.revlogv2=enable-unstable-format-and-corrupt-my-data > /dev/null
86 $ hg debugupgraderepo -R up-no-side-data --config experimental.revlogv2=enable-unstable-format-and-corrupt-my-data > /dev/null
85
87
86 Check that we can downgrade from sidedata
88 Check that we can downgrade from sidedata
87 -----------------------------------------
89 -----------------------------------------
88
90
89 $ hg init up-side-data --config experimental.revlogv2=enable-unstable-format-and-corrupt-my-data
91 $ hg init up-side-data --config experimental.revlogv2=enable-unstable-format-and-corrupt-my-data
90 $ hg debugformat -v -R up-side-data
92 $ hg debugformat -v -R up-side-data
91 format-variant repo config default
93 format-variant repo config default
92 fncache: yes yes yes
94 fncache: yes yes yes
95 dirstate-v2: no no no
93 dotencode: yes yes yes
96 dotencode: yes yes yes
94 generaldelta: yes yes yes
97 generaldelta: yes yes yes
95 share-safe: no no no
98 share-safe: no no no
96 sparserevlog: yes yes yes
99 sparserevlog: yes yes yes
97 persistent-nodemap: no no no (no-rust !)
100 persistent-nodemap: no no no (no-rust !)
98 persistent-nodemap: yes yes no (rust !)
101 persistent-nodemap: yes yes no (rust !)
99 copies-sdc: no no no
102 copies-sdc: no no no
100 revlog-v2: yes no no
103 revlog-v2: yes no no
101 changelog-v2: no no no
104 changelog-v2: no no no
102 plain-cl-delta: yes yes yes
105 plain-cl-delta: yes yes yes
103 compression: zlib zlib zlib (no-zstd !)
106 compression: zlib zlib zlib (no-zstd !)
104 compression: zstd zstd zstd (zstd !)
107 compression: zstd zstd zstd (zstd !)
105 compression-level: default default default
108 compression-level: default default default
106 $ hg debugformat -v -R up-side-data --config experimental.revlogv2=no
109 $ hg debugformat -v -R up-side-data --config experimental.revlogv2=no
107 format-variant repo config default
110 format-variant repo config default
108 fncache: yes yes yes
111 fncache: yes yes yes
112 dirstate-v2: no no no
109 dotencode: yes yes yes
113 dotencode: yes yes yes
110 generaldelta: yes yes yes
114 generaldelta: yes yes yes
111 share-safe: no no no
115 share-safe: no no no
112 sparserevlog: yes yes yes
116 sparserevlog: yes yes yes
113 persistent-nodemap: no no no (no-rust !)
117 persistent-nodemap: no no no (no-rust !)
114 persistent-nodemap: yes yes no (rust !)
118 persistent-nodemap: yes yes no (rust !)
115 copies-sdc: no no no
119 copies-sdc: no no no
116 revlog-v2: yes no no
120 revlog-v2: yes no no
117 changelog-v2: no no no
121 changelog-v2: no no no
118 plain-cl-delta: yes yes yes
122 plain-cl-delta: yes yes yes
119 compression: zlib zlib zlib (no-zstd !)
123 compression: zlib zlib zlib (no-zstd !)
120 compression: zstd zstd zstd (zstd !)
124 compression: zstd zstd zstd (zstd !)
121 compression-level: default default default
125 compression-level: default default default
122 $ hg debugupgraderepo -R up-side-data --config experimental.revlogv2=no > /dev/null
126 $ hg debugupgraderepo -R up-side-data --config experimental.revlogv2=no > /dev/null
@@ -1,1615 +1,1737 b''
1 #require no-reposimplestore
1 #require no-reposimplestore
2
2
3 $ cat >> $HGRCPATH << EOF
3 $ cat >> $HGRCPATH << EOF
4 > [extensions]
4 > [extensions]
5 > share =
5 > share =
6 > [format]
6 > [format]
7 > # stabilize test accross variant
7 > # stabilize test accross variant
8 > revlog-compression=zlib
8 > revlog-compression=zlib
9 > EOF
9 > EOF
10
10
11 store and revlogv1 are required in source
11 store and revlogv1 are required in source
12
12
13 $ hg --config format.usestore=false init no-store
13 $ hg --config format.usestore=false init no-store
14 $ hg -R no-store debugupgraderepo
14 $ hg -R no-store debugupgraderepo
15 abort: cannot upgrade repository; requirement missing: store
15 abort: cannot upgrade repository; requirement missing: store
16 [255]
16 [255]
17
17
18 $ hg init no-revlogv1
18 $ hg init no-revlogv1
19 $ cat > no-revlogv1/.hg/requires << EOF
19 $ cat > no-revlogv1/.hg/requires << EOF
20 > dotencode
20 > dotencode
21 > fncache
21 > fncache
22 > generaldelta
22 > generaldelta
23 > store
23 > store
24 > EOF
24 > EOF
25
25
26 $ hg -R no-revlogv1 debugupgraderepo
26 $ hg -R no-revlogv1 debugupgraderepo
27 abort: cannot upgrade repository; missing a revlog version
27 abort: cannot upgrade repository; missing a revlog version
28 [255]
28 [255]
29
29
30 Cannot upgrade shared repositories
30 Cannot upgrade shared repositories
31
31
32 $ hg init share-parent
32 $ hg init share-parent
33 $ hg -q share share-parent share-child
33 $ hg -q share share-parent share-child
34
34
35 $ hg -R share-child debugupgraderepo
35 $ hg -R share-child debugupgraderepo
36 abort: cannot upgrade repository; unsupported source requirement: shared
36 abort: cannot upgrade repository; unsupported source requirement: shared
37 [255]
37 [255]
38
38
39 Do not yet support upgrading treemanifest repos
39 Do not yet support upgrading treemanifest repos
40
40
41 $ hg --config experimental.treemanifest=true init treemanifest
41 $ hg --config experimental.treemanifest=true init treemanifest
42 $ hg -R treemanifest debugupgraderepo
42 $ hg -R treemanifest debugupgraderepo
43 abort: cannot upgrade repository; unsupported source requirement: treemanifest
43 abort: cannot upgrade repository; unsupported source requirement: treemanifest
44 [255]
44 [255]
45
45
46 Cannot add treemanifest requirement during upgrade
46 Cannot add treemanifest requirement during upgrade
47
47
48 $ hg init disallowaddedreq
48 $ hg init disallowaddedreq
49 $ hg -R disallowaddedreq --config experimental.treemanifest=true debugupgraderepo
49 $ hg -R disallowaddedreq --config experimental.treemanifest=true debugupgraderepo
50 abort: cannot upgrade repository; do not support adding requirement: treemanifest
50 abort: cannot upgrade repository; do not support adding requirement: treemanifest
51 [255]
51 [255]
52
52
53 An upgrade of a repository created with recommended settings only suggests optimizations
53 An upgrade of a repository created with recommended settings only suggests optimizations
54
54
55 $ hg init empty
55 $ hg init empty
56 $ cd empty
56 $ cd empty
57 $ hg debugformat
57 $ hg debugformat
58 format-variant repo
58 format-variant repo
59 fncache: yes
59 fncache: yes
60 dirstate-v2: no
60 dotencode: yes
61 dotencode: yes
61 generaldelta: yes
62 generaldelta: yes
62 share-safe: no
63 share-safe: no
63 sparserevlog: yes
64 sparserevlog: yes
64 persistent-nodemap: no (no-rust !)
65 persistent-nodemap: no (no-rust !)
65 persistent-nodemap: yes (rust !)
66 persistent-nodemap: yes (rust !)
66 copies-sdc: no
67 copies-sdc: no
67 revlog-v2: no
68 revlog-v2: no
68 changelog-v2: no
69 changelog-v2: no
69 plain-cl-delta: yes
70 plain-cl-delta: yes
70 compression: zlib
71 compression: zlib
71 compression-level: default
72 compression-level: default
72 $ hg debugformat --verbose
73 $ hg debugformat --verbose
73 format-variant repo config default
74 format-variant repo config default
74 fncache: yes yes yes
75 fncache: yes yes yes
76 dirstate-v2: no no no
75 dotencode: yes yes yes
77 dotencode: yes yes yes
76 generaldelta: yes yes yes
78 generaldelta: yes yes yes
77 share-safe: no no no
79 share-safe: no no no
78 sparserevlog: yes yes yes
80 sparserevlog: yes yes yes
79 persistent-nodemap: no no no (no-rust !)
81 persistent-nodemap: no no no (no-rust !)
80 persistent-nodemap: yes yes no (rust !)
82 persistent-nodemap: yes yes no (rust !)
81 copies-sdc: no no no
83 copies-sdc: no no no
82 revlog-v2: no no no
84 revlog-v2: no no no
83 changelog-v2: no no no
85 changelog-v2: no no no
84 plain-cl-delta: yes yes yes
86 plain-cl-delta: yes yes yes
85 compression: zlib zlib zlib (no-zstd !)
87 compression: zlib zlib zlib (no-zstd !)
86 compression: zlib zlib zstd (zstd !)
88 compression: zlib zlib zstd (zstd !)
87 compression-level: default default default
89 compression-level: default default default
88 $ hg debugformat --verbose --config format.usefncache=no
90 $ hg debugformat --verbose --config format.usefncache=no
89 format-variant repo config default
91 format-variant repo config default
90 fncache: yes no yes
92 fncache: yes no yes
93 dirstate-v2: no no no
91 dotencode: yes no yes
94 dotencode: yes no yes
92 generaldelta: yes yes yes
95 generaldelta: yes yes yes
93 share-safe: no no no
96 share-safe: no no no
94 sparserevlog: yes yes yes
97 sparserevlog: yes yes yes
95 persistent-nodemap: no no no (no-rust !)
98 persistent-nodemap: no no no (no-rust !)
96 persistent-nodemap: yes yes no (rust !)
99 persistent-nodemap: yes yes no (rust !)
97 copies-sdc: no no no
100 copies-sdc: no no no
98 revlog-v2: no no no
101 revlog-v2: no no no
99 changelog-v2: no no no
102 changelog-v2: no no no
100 plain-cl-delta: yes yes yes
103 plain-cl-delta: yes yes yes
101 compression: zlib zlib zlib (no-zstd !)
104 compression: zlib zlib zlib (no-zstd !)
102 compression: zlib zlib zstd (zstd !)
105 compression: zlib zlib zstd (zstd !)
103 compression-level: default default default
106 compression-level: default default default
104 $ hg debugformat --verbose --config format.usefncache=no --color=debug
107 $ hg debugformat --verbose --config format.usefncache=no --color=debug
105 format-variant repo config default
108 format-variant repo config default
106 [formatvariant.name.mismatchconfig|fncache: ][formatvariant.repo.mismatchconfig| yes][formatvariant.config.special| no][formatvariant.default| yes]
109 [formatvariant.name.mismatchconfig|fncache: ][formatvariant.repo.mismatchconfig| yes][formatvariant.config.special| no][formatvariant.default| yes]
110 [formatvariant.name.uptodate|dirstate-v2: ][formatvariant.repo.uptodate| no][formatvariant.config.default| no][formatvariant.default| no]
107 [formatvariant.name.mismatchconfig|dotencode: ][formatvariant.repo.mismatchconfig| yes][formatvariant.config.special| no][formatvariant.default| yes]
111 [formatvariant.name.mismatchconfig|dotencode: ][formatvariant.repo.mismatchconfig| yes][formatvariant.config.special| no][formatvariant.default| yes]
108 [formatvariant.name.uptodate|generaldelta: ][formatvariant.repo.uptodate| yes][formatvariant.config.default| yes][formatvariant.default| yes]
112 [formatvariant.name.uptodate|generaldelta: ][formatvariant.repo.uptodate| yes][formatvariant.config.default| yes][formatvariant.default| yes]
109 [formatvariant.name.uptodate|share-safe: ][formatvariant.repo.uptodate| no][formatvariant.config.default| no][formatvariant.default| no]
113 [formatvariant.name.uptodate|share-safe: ][formatvariant.repo.uptodate| no][formatvariant.config.default| no][formatvariant.default| no]
110 [formatvariant.name.uptodate|sparserevlog: ][formatvariant.repo.uptodate| yes][formatvariant.config.default| yes][formatvariant.default| yes]
114 [formatvariant.name.uptodate|sparserevlog: ][formatvariant.repo.uptodate| yes][formatvariant.config.default| yes][formatvariant.default| yes]
111 [formatvariant.name.uptodate|persistent-nodemap:][formatvariant.repo.uptodate| no][formatvariant.config.default| no][formatvariant.default| no] (no-rust !)
115 [formatvariant.name.uptodate|persistent-nodemap:][formatvariant.repo.uptodate| no][formatvariant.config.default| no][formatvariant.default| no] (no-rust !)
112 [formatvariant.name.mismatchdefault|persistent-nodemap:][formatvariant.repo.mismatchdefault| yes][formatvariant.config.special| yes][formatvariant.default| no] (rust !)
116 [formatvariant.name.mismatchdefault|persistent-nodemap:][formatvariant.repo.mismatchdefault| yes][formatvariant.config.special| yes][formatvariant.default| no] (rust !)
113 [formatvariant.name.uptodate|copies-sdc: ][formatvariant.repo.uptodate| no][formatvariant.config.default| no][formatvariant.default| no]
117 [formatvariant.name.uptodate|copies-sdc: ][formatvariant.repo.uptodate| no][formatvariant.config.default| no][formatvariant.default| no]
114 [formatvariant.name.uptodate|revlog-v2: ][formatvariant.repo.uptodate| no][formatvariant.config.default| no][formatvariant.default| no]
118 [formatvariant.name.uptodate|revlog-v2: ][formatvariant.repo.uptodate| no][formatvariant.config.default| no][formatvariant.default| no]
115 [formatvariant.name.uptodate|changelog-v2: ][formatvariant.repo.uptodate| no][formatvariant.config.default| no][formatvariant.default| no]
119 [formatvariant.name.uptodate|changelog-v2: ][formatvariant.repo.uptodate| no][formatvariant.config.default| no][formatvariant.default| no]
116 [formatvariant.name.uptodate|plain-cl-delta: ][formatvariant.repo.uptodate| yes][formatvariant.config.default| yes][formatvariant.default| yes]
120 [formatvariant.name.uptodate|plain-cl-delta: ][formatvariant.repo.uptodate| yes][formatvariant.config.default| yes][formatvariant.default| yes]
117 [formatvariant.name.uptodate|compression: ][formatvariant.repo.uptodate| zlib][formatvariant.config.default| zlib][formatvariant.default| zlib] (no-zstd !)
121 [formatvariant.name.uptodate|compression: ][formatvariant.repo.uptodate| zlib][formatvariant.config.default| zlib][formatvariant.default| zlib] (no-zstd !)
118 [formatvariant.name.mismatchdefault|compression: ][formatvariant.repo.mismatchdefault| zlib][formatvariant.config.special| zlib][formatvariant.default| zstd] (zstd !)
122 [formatvariant.name.mismatchdefault|compression: ][formatvariant.repo.mismatchdefault| zlib][formatvariant.config.special| zlib][formatvariant.default| zstd] (zstd !)
119 [formatvariant.name.uptodate|compression-level: ][formatvariant.repo.uptodate| default][formatvariant.config.default| default][formatvariant.default| default]
123 [formatvariant.name.uptodate|compression-level: ][formatvariant.repo.uptodate| default][formatvariant.config.default| default][formatvariant.default| default]
120 $ hg debugformat -Tjson
124 $ hg debugformat -Tjson
121 [
125 [
122 {
126 {
123 "config": true,
127 "config": true,
124 "default": true,
128 "default": true,
125 "name": "fncache",
129 "name": "fncache",
126 "repo": true
130 "repo": true
127 },
131 },
128 {
132 {
133 "config": false,
134 "default": false,
135 "name": "dirstate-v2",
136 "repo": false
137 },
138 {
129 "config": true,
139 "config": true,
130 "default": true,
140 "default": true,
131 "name": "dotencode",
141 "name": "dotencode",
132 "repo": true
142 "repo": true
133 },
143 },
134 {
144 {
135 "config": true,
145 "config": true,
136 "default": true,
146 "default": true,
137 "name": "generaldelta",
147 "name": "generaldelta",
138 "repo": true
148 "repo": true
139 },
149 },
140 {
150 {
141 "config": false,
151 "config": false,
142 "default": false,
152 "default": false,
143 "name": "share-safe",
153 "name": "share-safe",
144 "repo": false
154 "repo": false
145 },
155 },
146 {
156 {
147 "config": true,
157 "config": true,
148 "default": true,
158 "default": true,
149 "name": "sparserevlog",
159 "name": "sparserevlog",
150 "repo": true
160 "repo": true
151 },
161 },
152 {
162 {
153 "config": false, (no-rust !)
163 "config": false, (no-rust !)
154 "config": true, (rust !)
164 "config": true, (rust !)
155 "default": false,
165 "default": false,
156 "name": "persistent-nodemap",
166 "name": "persistent-nodemap",
157 "repo": false (no-rust !)
167 "repo": false (no-rust !)
158 "repo": true (rust !)
168 "repo": true (rust !)
159 },
169 },
160 {
170 {
161 "config": false,
171 "config": false,
162 "default": false,
172 "default": false,
163 "name": "copies-sdc",
173 "name": "copies-sdc",
164 "repo": false
174 "repo": false
165 },
175 },
166 {
176 {
167 "config": false,
177 "config": false,
168 "default": false,
178 "default": false,
169 "name": "revlog-v2",
179 "name": "revlog-v2",
170 "repo": false
180 "repo": false
171 },
181 },
172 {
182 {
173 "config": false,
183 "config": false,
174 "default": false,
184 "default": false,
175 "name": "changelog-v2",
185 "name": "changelog-v2",
176 "repo": false
186 "repo": false
177 },
187 },
178 {
188 {
179 "config": true,
189 "config": true,
180 "default": true,
190 "default": true,
181 "name": "plain-cl-delta",
191 "name": "plain-cl-delta",
182 "repo": true
192 "repo": true
183 },
193 },
184 {
194 {
185 "config": "zlib",
195 "config": "zlib",
186 "default": "zlib", (no-zstd !)
196 "default": "zlib", (no-zstd !)
187 "default": "zstd", (zstd !)
197 "default": "zstd", (zstd !)
188 "name": "compression",
198 "name": "compression",
189 "repo": "zlib"
199 "repo": "zlib"
190 },
200 },
191 {
201 {
192 "config": "default",
202 "config": "default",
193 "default": "default",
203 "default": "default",
194 "name": "compression-level",
204 "name": "compression-level",
195 "repo": "default"
205 "repo": "default"
196 }
206 }
197 ]
207 ]
198 $ hg debugupgraderepo
208 $ hg debugupgraderepo
199 (no format upgrades found in existing repository)
209 (no format upgrades found in existing repository)
200 performing an upgrade with "--run" will make the following changes:
210 performing an upgrade with "--run" will make the following changes:
201
211
202 requirements
212 requirements
203 preserved: dotencode, fncache, generaldelta, revlogv1, sparserevlog, store (no-rust !)
213 preserved: dotencode, fncache, generaldelta, revlogv1, sparserevlog, store (no-rust !)
204 preserved: dotencode, fncache, generaldelta, persistent-nodemap, revlogv1, sparserevlog, store (rust !)
214 preserved: dotencode, fncache, generaldelta, persistent-nodemap, revlogv1, sparserevlog, store (rust !)
205
215
206 processed revlogs:
216 processed revlogs:
207 - all-filelogs
217 - all-filelogs
208 - changelog
218 - changelog
209 - manifest
219 - manifest
210
220
211 additional optimizations are available by specifying "--optimize <name>":
221 additional optimizations are available by specifying "--optimize <name>":
212
222
213 re-delta-parent
223 re-delta-parent
214 deltas within internal storage will be recalculated to choose an optimal base revision where this was not already done; the size of the repository may shrink and various operations may become faster; the first time this optimization is performed could slow down upgrade execution considerably; subsequent invocations should not run noticeably slower
224 deltas within internal storage will be recalculated to choose an optimal base revision where this was not already done; the size of the repository may shrink and various operations may become faster; the first time this optimization is performed could slow down upgrade execution considerably; subsequent invocations should not run noticeably slower
215
225
216 re-delta-multibase
226 re-delta-multibase
217 deltas within internal storage will be recalculated against multiple base revision and the smallest difference will be used; the size of the repository may shrink significantly when there are many merges; this optimization will slow down execution in proportion to the number of merges in the repository and the amount of files in the repository; this slow down should not be significant unless there are tens of thousands of files and thousands of merges
227 deltas within internal storage will be recalculated against multiple base revision and the smallest difference will be used; the size of the repository may shrink significantly when there are many merges; this optimization will slow down execution in proportion to the number of merges in the repository and the amount of files in the repository; this slow down should not be significant unless there are tens of thousands of files and thousands of merges
218
228
219 re-delta-all
229 re-delta-all
220 deltas within internal storage will always be recalculated without reusing prior deltas; this will likely make execution run several times slower; this optimization is typically not needed
230 deltas within internal storage will always be recalculated without reusing prior deltas; this will likely make execution run several times slower; this optimization is typically not needed
221
231
222 re-delta-fulladd
232 re-delta-fulladd
223 every revision will be re-added as if it was new content. It will go through the full storage mechanism giving extensions a chance to process it (eg. lfs). This is similar to "re-delta-all" but even slower since more logic is involved.
233 every revision will be re-added as if it was new content. It will go through the full storage mechanism giving extensions a chance to process it (eg. lfs). This is similar to "re-delta-all" but even slower since more logic is involved.
224
234
225
235
226 $ hg debugupgraderepo --quiet
236 $ hg debugupgraderepo --quiet
227 requirements
237 requirements
228 preserved: dotencode, fncache, generaldelta, revlogv1, sparserevlog, store (no-rust !)
238 preserved: dotencode, fncache, generaldelta, revlogv1, sparserevlog, store (no-rust !)
229 preserved: dotencode, fncache, generaldelta, persistent-nodemap, revlogv1, sparserevlog, store (rust !)
239 preserved: dotencode, fncache, generaldelta, persistent-nodemap, revlogv1, sparserevlog, store (rust !)
230
240
231 processed revlogs:
241 processed revlogs:
232 - all-filelogs
242 - all-filelogs
233 - changelog
243 - changelog
234 - manifest
244 - manifest
235
245
236
246
237 --optimize can be used to add optimizations
247 --optimize can be used to add optimizations
238
248
239 $ hg debugupgrade --optimize 're-delta-parent'
249 $ hg debugupgrade --optimize 're-delta-parent'
240 (no format upgrades found in existing repository)
250 (no format upgrades found in existing repository)
241 performing an upgrade with "--run" will make the following changes:
251 performing an upgrade with "--run" will make the following changes:
242
252
243 requirements
253 requirements
244 preserved: dotencode, fncache, generaldelta, revlogv1, sparserevlog, store (no-rust !)
254 preserved: dotencode, fncache, generaldelta, revlogv1, sparserevlog, store (no-rust !)
245 preserved: dotencode, fncache, generaldelta, persistent-nodemap, revlogv1, sparserevlog, store (rust !)
255 preserved: dotencode, fncache, generaldelta, persistent-nodemap, revlogv1, sparserevlog, store (rust !)
246
256
247 optimisations: re-delta-parent
257 optimisations: re-delta-parent
248
258
249 re-delta-parent
259 re-delta-parent
250 deltas within internal storage will choose a new base revision if needed
260 deltas within internal storage will choose a new base revision if needed
251
261
252 processed revlogs:
262 processed revlogs:
253 - all-filelogs
263 - all-filelogs
254 - changelog
264 - changelog
255 - manifest
265 - manifest
256
266
257 additional optimizations are available by specifying "--optimize <name>":
267 additional optimizations are available by specifying "--optimize <name>":
258
268
259 re-delta-multibase
269 re-delta-multibase
260 deltas within internal storage will be recalculated against multiple base revision and the smallest difference will be used; the size of the repository may shrink significantly when there are many merges; this optimization will slow down execution in proportion to the number of merges in the repository and the amount of files in the repository; this slow down should not be significant unless there are tens of thousands of files and thousands of merges
270 deltas within internal storage will be recalculated against multiple base revision and the smallest difference will be used; the size of the repository may shrink significantly when there are many merges; this optimization will slow down execution in proportion to the number of merges in the repository and the amount of files in the repository; this slow down should not be significant unless there are tens of thousands of files and thousands of merges
261
271
262 re-delta-all
272 re-delta-all
263 deltas within internal storage will always be recalculated without reusing prior deltas; this will likely make execution run several times slower; this optimization is typically not needed
273 deltas within internal storage will always be recalculated without reusing prior deltas; this will likely make execution run several times slower; this optimization is typically not needed
264
274
265 re-delta-fulladd
275 re-delta-fulladd
266 every revision will be re-added as if it was new content. It will go through the full storage mechanism giving extensions a chance to process it (eg. lfs). This is similar to "re-delta-all" but even slower since more logic is involved.
276 every revision will be re-added as if it was new content. It will go through the full storage mechanism giving extensions a chance to process it (eg. lfs). This is similar to "re-delta-all" but even slower since more logic is involved.
267
277
268
278
269 modern form of the option
279 modern form of the option
270
280
271 $ hg debugupgrade --optimize re-delta-parent
281 $ hg debugupgrade --optimize re-delta-parent
272 (no format upgrades found in existing repository)
282 (no format upgrades found in existing repository)
273 performing an upgrade with "--run" will make the following changes:
283 performing an upgrade with "--run" will make the following changes:
274
284
275 requirements
285 requirements
276 preserved: dotencode, fncache, generaldelta, revlogv1, sparserevlog, store (no-rust !)
286 preserved: dotencode, fncache, generaldelta, revlogv1, sparserevlog, store (no-rust !)
277 preserved: dotencode, fncache, generaldelta, persistent-nodemap, revlogv1, sparserevlog, store (rust !)
287 preserved: dotencode, fncache, generaldelta, persistent-nodemap, revlogv1, sparserevlog, store (rust !)
278
288
279 optimisations: re-delta-parent
289 optimisations: re-delta-parent
280
290
281 re-delta-parent
291 re-delta-parent
282 deltas within internal storage will choose a new base revision if needed
292 deltas within internal storage will choose a new base revision if needed
283
293
284 processed revlogs:
294 processed revlogs:
285 - all-filelogs
295 - all-filelogs
286 - changelog
296 - changelog
287 - manifest
297 - manifest
288
298
289 additional optimizations are available by specifying "--optimize <name>":
299 additional optimizations are available by specifying "--optimize <name>":
290
300
291 re-delta-multibase
301 re-delta-multibase
292 deltas within internal storage will be recalculated against multiple base revision and the smallest difference will be used; the size of the repository may shrink significantly when there are many merges; this optimization will slow down execution in proportion to the number of merges in the repository and the amount of files in the repository; this slow down should not be significant unless there are tens of thousands of files and thousands of merges
302 deltas within internal storage will be recalculated against multiple base revision and the smallest difference will be used; the size of the repository may shrink significantly when there are many merges; this optimization will slow down execution in proportion to the number of merges in the repository and the amount of files in the repository; this slow down should not be significant unless there are tens of thousands of files and thousands of merges
293
303
294 re-delta-all
304 re-delta-all
295 deltas within internal storage will always be recalculated without reusing prior deltas; this will likely make execution run several times slower; this optimization is typically not needed
305 deltas within internal storage will always be recalculated without reusing prior deltas; this will likely make execution run several times slower; this optimization is typically not needed
296
306
297 re-delta-fulladd
307 re-delta-fulladd
298 every revision will be re-added as if it was new content. It will go through the full storage mechanism giving extensions a chance to process it (eg. lfs). This is similar to "re-delta-all" but even slower since more logic is involved.
308 every revision will be re-added as if it was new content. It will go through the full storage mechanism giving extensions a chance to process it (eg. lfs). This is similar to "re-delta-all" but even slower since more logic is involved.
299
309
300 $ hg debugupgrade --optimize re-delta-parent --quiet
310 $ hg debugupgrade --optimize re-delta-parent --quiet
301 requirements
311 requirements
302 preserved: dotencode, fncache, generaldelta, revlogv1, sparserevlog, store (no-rust !)
312 preserved: dotencode, fncache, generaldelta, revlogv1, sparserevlog, store (no-rust !)
303 preserved: dotencode, fncache, generaldelta, persistent-nodemap, revlogv1, sparserevlog, store (rust !)
313 preserved: dotencode, fncache, generaldelta, persistent-nodemap, revlogv1, sparserevlog, store (rust !)
304
314
305 optimisations: re-delta-parent
315 optimisations: re-delta-parent
306
316
307 processed revlogs:
317 processed revlogs:
308 - all-filelogs
318 - all-filelogs
309 - changelog
319 - changelog
310 - manifest
320 - manifest
311
321
312
322
313 unknown optimization:
323 unknown optimization:
314
324
315 $ hg debugupgrade --optimize foobar
325 $ hg debugupgrade --optimize foobar
316 abort: unknown optimization action requested: foobar
326 abort: unknown optimization action requested: foobar
317 (run without arguments to see valid optimizations)
327 (run without arguments to see valid optimizations)
318 [255]
328 [255]
319
329
320 Various sub-optimal detections work
330 Various sub-optimal detections work
321
331
322 $ cat > .hg/requires << EOF
332 $ cat > .hg/requires << EOF
323 > revlogv1
333 > revlogv1
324 > store
334 > store
325 > EOF
335 > EOF
326
336
327 $ hg debugformat
337 $ hg debugformat
328 format-variant repo
338 format-variant repo
329 fncache: no
339 fncache: no
340 dirstate-v2: no
330 dotencode: no
341 dotencode: no
331 generaldelta: no
342 generaldelta: no
332 share-safe: no
343 share-safe: no
333 sparserevlog: no
344 sparserevlog: no
334 persistent-nodemap: no
345 persistent-nodemap: no
335 copies-sdc: no
346 copies-sdc: no
336 revlog-v2: no
347 revlog-v2: no
337 changelog-v2: no
348 changelog-v2: no
338 plain-cl-delta: yes
349 plain-cl-delta: yes
339 compression: zlib
350 compression: zlib
340 compression-level: default
351 compression-level: default
341 $ hg debugformat --verbose
352 $ hg debugformat --verbose
342 format-variant repo config default
353 format-variant repo config default
343 fncache: no yes yes
354 fncache: no yes yes
355 dirstate-v2: no no no
344 dotencode: no yes yes
356 dotencode: no yes yes
345 generaldelta: no yes yes
357 generaldelta: no yes yes
346 share-safe: no no no
358 share-safe: no no no
347 sparserevlog: no yes yes
359 sparserevlog: no yes yes
348 persistent-nodemap: no no no (no-rust !)
360 persistent-nodemap: no no no (no-rust !)
349 persistent-nodemap: no yes no (rust !)
361 persistent-nodemap: no yes no (rust !)
350 copies-sdc: no no no
362 copies-sdc: no no no
351 revlog-v2: no no no
363 revlog-v2: no no no
352 changelog-v2: no no no
364 changelog-v2: no no no
353 plain-cl-delta: yes yes yes
365 plain-cl-delta: yes yes yes
354 compression: zlib zlib zlib (no-zstd !)
366 compression: zlib zlib zlib (no-zstd !)
355 compression: zlib zlib zstd (zstd !)
367 compression: zlib zlib zstd (zstd !)
356 compression-level: default default default
368 compression-level: default default default
357 $ hg debugformat --verbose --config format.usegeneraldelta=no
369 $ hg debugformat --verbose --config format.usegeneraldelta=no
358 format-variant repo config default
370 format-variant repo config default
359 fncache: no yes yes
371 fncache: no yes yes
372 dirstate-v2: no no no
360 dotencode: no yes yes
373 dotencode: no yes yes
361 generaldelta: no no yes
374 generaldelta: no no yes
362 share-safe: no no no
375 share-safe: no no no
363 sparserevlog: no no yes
376 sparserevlog: no no yes
364 persistent-nodemap: no no no (no-rust !)
377 persistent-nodemap: no no no (no-rust !)
365 persistent-nodemap: no yes no (rust !)
378 persistent-nodemap: no yes no (rust !)
366 copies-sdc: no no no
379 copies-sdc: no no no
367 revlog-v2: no no no
380 revlog-v2: no no no
368 changelog-v2: no no no
381 changelog-v2: no no no
369 plain-cl-delta: yes yes yes
382 plain-cl-delta: yes yes yes
370 compression: zlib zlib zlib (no-zstd !)
383 compression: zlib zlib zlib (no-zstd !)
371 compression: zlib zlib zstd (zstd !)
384 compression: zlib zlib zstd (zstd !)
372 compression-level: default default default
385 compression-level: default default default
373 $ hg debugformat --verbose --config format.usegeneraldelta=no --color=debug
386 $ hg debugformat --verbose --config format.usegeneraldelta=no --color=debug
374 format-variant repo config default
387 format-variant repo config default
375 [formatvariant.name.mismatchconfig|fncache: ][formatvariant.repo.mismatchconfig| no][formatvariant.config.default| yes][formatvariant.default| yes]
388 [formatvariant.name.mismatchconfig|fncache: ][formatvariant.repo.mismatchconfig| no][formatvariant.config.default| yes][formatvariant.default| yes]
389 [formatvariant.name.uptodate|dirstate-v2: ][formatvariant.repo.uptodate| no][formatvariant.config.default| no][formatvariant.default| no]
376 [formatvariant.name.mismatchconfig|dotencode: ][formatvariant.repo.mismatchconfig| no][formatvariant.config.default| yes][formatvariant.default| yes]
390 [formatvariant.name.mismatchconfig|dotencode: ][formatvariant.repo.mismatchconfig| no][formatvariant.config.default| yes][formatvariant.default| yes]
377 [formatvariant.name.mismatchdefault|generaldelta: ][formatvariant.repo.mismatchdefault| no][formatvariant.config.special| no][formatvariant.default| yes]
391 [formatvariant.name.mismatchdefault|generaldelta: ][formatvariant.repo.mismatchdefault| no][formatvariant.config.special| no][formatvariant.default| yes]
378 [formatvariant.name.uptodate|share-safe: ][formatvariant.repo.uptodate| no][formatvariant.config.default| no][formatvariant.default| no]
392 [formatvariant.name.uptodate|share-safe: ][formatvariant.repo.uptodate| no][formatvariant.config.default| no][formatvariant.default| no]
379 [formatvariant.name.mismatchdefault|sparserevlog: ][formatvariant.repo.mismatchdefault| no][formatvariant.config.special| no][formatvariant.default| yes]
393 [formatvariant.name.mismatchdefault|sparserevlog: ][formatvariant.repo.mismatchdefault| no][formatvariant.config.special| no][formatvariant.default| yes]
380 [formatvariant.name.uptodate|persistent-nodemap:][formatvariant.repo.uptodate| no][formatvariant.config.default| no][formatvariant.default| no] (no-rust !)
394 [formatvariant.name.uptodate|persistent-nodemap:][formatvariant.repo.uptodate| no][formatvariant.config.default| no][formatvariant.default| no] (no-rust !)
381 [formatvariant.name.mismatchconfig|persistent-nodemap:][formatvariant.repo.mismatchconfig| no][formatvariant.config.special| yes][formatvariant.default| no] (rust !)
395 [formatvariant.name.mismatchconfig|persistent-nodemap:][formatvariant.repo.mismatchconfig| no][formatvariant.config.special| yes][formatvariant.default| no] (rust !)
382 [formatvariant.name.uptodate|copies-sdc: ][formatvariant.repo.uptodate| no][formatvariant.config.default| no][formatvariant.default| no]
396 [formatvariant.name.uptodate|copies-sdc: ][formatvariant.repo.uptodate| no][formatvariant.config.default| no][formatvariant.default| no]
383 [formatvariant.name.uptodate|revlog-v2: ][formatvariant.repo.uptodate| no][formatvariant.config.default| no][formatvariant.default| no]
397 [formatvariant.name.uptodate|revlog-v2: ][formatvariant.repo.uptodate| no][formatvariant.config.default| no][formatvariant.default| no]
384 [formatvariant.name.uptodate|changelog-v2: ][formatvariant.repo.uptodate| no][formatvariant.config.default| no][formatvariant.default| no]
398 [formatvariant.name.uptodate|changelog-v2: ][formatvariant.repo.uptodate| no][formatvariant.config.default| no][formatvariant.default| no]
385 [formatvariant.name.uptodate|plain-cl-delta: ][formatvariant.repo.uptodate| yes][formatvariant.config.default| yes][formatvariant.default| yes]
399 [formatvariant.name.uptodate|plain-cl-delta: ][formatvariant.repo.uptodate| yes][formatvariant.config.default| yes][formatvariant.default| yes]
386 [formatvariant.name.uptodate|compression: ][formatvariant.repo.uptodate| zlib][formatvariant.config.default| zlib][formatvariant.default| zlib] (no-zstd !)
400 [formatvariant.name.uptodate|compression: ][formatvariant.repo.uptodate| zlib][formatvariant.config.default| zlib][formatvariant.default| zlib] (no-zstd !)
387 [formatvariant.name.mismatchdefault|compression: ][formatvariant.repo.mismatchdefault| zlib][formatvariant.config.special| zlib][formatvariant.default| zstd] (zstd !)
401 [formatvariant.name.mismatchdefault|compression: ][formatvariant.repo.mismatchdefault| zlib][formatvariant.config.special| zlib][formatvariant.default| zstd] (zstd !)
388 [formatvariant.name.uptodate|compression-level: ][formatvariant.repo.uptodate| default][formatvariant.config.default| default][formatvariant.default| default]
402 [formatvariant.name.uptodate|compression-level: ][formatvariant.repo.uptodate| default][formatvariant.config.default| default][formatvariant.default| default]
389 $ hg debugupgraderepo
403 $ hg debugupgraderepo
390 repository lacks features recommended by current config options:
404 repository lacks features recommended by current config options:
391
405
392 fncache
406 fncache
393 long and reserved filenames may not work correctly; repository performance is sub-optimal
407 long and reserved filenames may not work correctly; repository performance is sub-optimal
394
408
395 dotencode
409 dotencode
396 storage of filenames beginning with a period or space may not work correctly
410 storage of filenames beginning with a period or space may not work correctly
397
411
398 generaldelta
412 generaldelta
399 deltas within internal storage are unable to choose optimal revisions; repository is larger and slower than it could be; interaction with other repositories may require extra network and CPU resources, making "hg push" and "hg pull" slower
413 deltas within internal storage are unable to choose optimal revisions; repository is larger and slower than it could be; interaction with other repositories may require extra network and CPU resources, making "hg push" and "hg pull" slower
400
414
401 sparserevlog
415 sparserevlog
402 in order to limit disk reading and memory usage on older version, the span of a delta chain from its root to its end is limited, whatever the relevant data in this span. This can severly limit Mercurial ability to build good chain of delta resulting is much more storage space being taken and limit reusability of on disk delta during exchange.
416 in order to limit disk reading and memory usage on older version, the span of a delta chain from its root to its end is limited, whatever the relevant data in this span. This can severly limit Mercurial ability to build good chain of delta resulting is much more storage space being taken and limit reusability of on disk delta during exchange.
403
417
404 persistent-nodemap (rust !)
418 persistent-nodemap (rust !)
405 persist the node -> rev mapping on disk to speedup lookup (rust !)
419 persist the node -> rev mapping on disk to speedup lookup (rust !)
406 (rust !)
420 (rust !)
407
421
408 performing an upgrade with "--run" will make the following changes:
422 performing an upgrade with "--run" will make the following changes:
409
423
410 requirements
424 requirements
411 preserved: revlogv1, store
425 preserved: revlogv1, store
412 added: dotencode, fncache, generaldelta, sparserevlog (no-rust !)
426 added: dotencode, fncache, generaldelta, sparserevlog (no-rust !)
413 added: dotencode, fncache, generaldelta, persistent-nodemap, sparserevlog (rust !)
427 added: dotencode, fncache, generaldelta, persistent-nodemap, sparserevlog (rust !)
414
428
415 fncache
429 fncache
416 repository will be more resilient to storing certain paths and performance of certain operations should be improved
430 repository will be more resilient to storing certain paths and performance of certain operations should be improved
417
431
418 dotencode
432 dotencode
419 repository will be better able to store files beginning with a space or period
433 repository will be better able to store files beginning with a space or period
420
434
421 generaldelta
435 generaldelta
422 repository storage will be able to create optimal deltas; new repository data will be smaller and read times should decrease; interacting with other repositories using this storage model should require less network and CPU resources, making "hg push" and "hg pull" faster
436 repository storage will be able to create optimal deltas; new repository data will be smaller and read times should decrease; interacting with other repositories using this storage model should require less network and CPU resources, making "hg push" and "hg pull" faster
423
437
424 sparserevlog
438 sparserevlog
425 Revlog supports delta chain with more unused data between payload. These gaps will be skipped at read time. This allows for better delta chains, making a better compression and faster exchange with server.
439 Revlog supports delta chain with more unused data between payload. These gaps will be skipped at read time. This allows for better delta chains, making a better compression and faster exchange with server.
426
440
427 persistent-nodemap (rust !)
441 persistent-nodemap (rust !)
428 Speedup revision lookup by node id. (rust !)
442 Speedup revision lookup by node id. (rust !)
429 (rust !)
443 (rust !)
430 processed revlogs:
444 processed revlogs:
431 - all-filelogs
445 - all-filelogs
432 - changelog
446 - changelog
433 - manifest
447 - manifest
434
448
435 additional optimizations are available by specifying "--optimize <name>":
449 additional optimizations are available by specifying "--optimize <name>":
436
450
437 re-delta-parent
451 re-delta-parent
438 deltas within internal storage will be recalculated to choose an optimal base revision where this was not already done; the size of the repository may shrink and various operations may become faster; the first time this optimization is performed could slow down upgrade execution considerably; subsequent invocations should not run noticeably slower
452 deltas within internal storage will be recalculated to choose an optimal base revision where this was not already done; the size of the repository may shrink and various operations may become faster; the first time this optimization is performed could slow down upgrade execution considerably; subsequent invocations should not run noticeably slower
439
453
440 re-delta-multibase
454 re-delta-multibase
441 deltas within internal storage will be recalculated against multiple base revision and the smallest difference will be used; the size of the repository may shrink significantly when there are many merges; this optimization will slow down execution in proportion to the number of merges in the repository and the amount of files in the repository; this slow down should not be significant unless there are tens of thousands of files and thousands of merges
455 deltas within internal storage will be recalculated against multiple base revision and the smallest difference will be used; the size of the repository may shrink significantly when there are many merges; this optimization will slow down execution in proportion to the number of merges in the repository and the amount of files in the repository; this slow down should not be significant unless there are tens of thousands of files and thousands of merges
442
456
443 re-delta-all
457 re-delta-all
444 deltas within internal storage will always be recalculated without reusing prior deltas; this will likely make execution run several times slower; this optimization is typically not needed
458 deltas within internal storage will always be recalculated without reusing prior deltas; this will likely make execution run several times slower; this optimization is typically not needed
445
459
446 re-delta-fulladd
460 re-delta-fulladd
447 every revision will be re-added as if it was new content. It will go through the full storage mechanism giving extensions a chance to process it (eg. lfs). This is similar to "re-delta-all" but even slower since more logic is involved.
461 every revision will be re-added as if it was new content. It will go through the full storage mechanism giving extensions a chance to process it (eg. lfs). This is similar to "re-delta-all" but even slower since more logic is involved.
448
462
449 $ hg debugupgraderepo --quiet
463 $ hg debugupgraderepo --quiet
450 requirements
464 requirements
451 preserved: revlogv1, store
465 preserved: revlogv1, store
452 added: dotencode, fncache, generaldelta, sparserevlog (no-rust !)
466 added: dotencode, fncache, generaldelta, sparserevlog (no-rust !)
453 added: dotencode, fncache, generaldelta, persistent-nodemap, sparserevlog (rust !)
467 added: dotencode, fncache, generaldelta, persistent-nodemap, sparserevlog (rust !)
454
468
455 processed revlogs:
469 processed revlogs:
456 - all-filelogs
470 - all-filelogs
457 - changelog
471 - changelog
458 - manifest
472 - manifest
459
473
460
474
461 $ hg --config format.dotencode=false debugupgraderepo
475 $ hg --config format.dotencode=false debugupgraderepo
462 repository lacks features recommended by current config options:
476 repository lacks features recommended by current config options:
463
477
464 fncache
478 fncache
465 long and reserved filenames may not work correctly; repository performance is sub-optimal
479 long and reserved filenames may not work correctly; repository performance is sub-optimal
466
480
467 generaldelta
481 generaldelta
468 deltas within internal storage are unable to choose optimal revisions; repository is larger and slower than it could be; interaction with other repositories may require extra network and CPU resources, making "hg push" and "hg pull" slower
482 deltas within internal storage are unable to choose optimal revisions; repository is larger and slower than it could be; interaction with other repositories may require extra network and CPU resources, making "hg push" and "hg pull" slower
469
483
470 sparserevlog
484 sparserevlog
471 in order to limit disk reading and memory usage on older version, the span of a delta chain from its root to its end is limited, whatever the relevant data in this span. This can severly limit Mercurial ability to build good chain of delta resulting is much more storage space being taken and limit reusability of on disk delta during exchange.
485 in order to limit disk reading and memory usage on older version, the span of a delta chain from its root to its end is limited, whatever the relevant data in this span. This can severly limit Mercurial ability to build good chain of delta resulting is much more storage space being taken and limit reusability of on disk delta during exchange.
472
486
473 persistent-nodemap (rust !)
487 persistent-nodemap (rust !)
474 persist the node -> rev mapping on disk to speedup lookup (rust !)
488 persist the node -> rev mapping on disk to speedup lookup (rust !)
475 (rust !)
489 (rust !)
476 repository lacks features used by the default config options:
490 repository lacks features used by the default config options:
477
491
478 dotencode
492 dotencode
479 storage of filenames beginning with a period or space may not work correctly
493 storage of filenames beginning with a period or space may not work correctly
480
494
481
495
482 performing an upgrade with "--run" will make the following changes:
496 performing an upgrade with "--run" will make the following changes:
483
497
484 requirements
498 requirements
485 preserved: revlogv1, store
499 preserved: revlogv1, store
486 added: fncache, generaldelta, sparserevlog (no-rust !)
500 added: fncache, generaldelta, sparserevlog (no-rust !)
487 added: fncache, generaldelta, persistent-nodemap, sparserevlog (rust !)
501 added: fncache, generaldelta, persistent-nodemap, sparserevlog (rust !)
488
502
489 fncache
503 fncache
490 repository will be more resilient to storing certain paths and performance of certain operations should be improved
504 repository will be more resilient to storing certain paths and performance of certain operations should be improved
491
505
492 generaldelta
506 generaldelta
493 repository storage will be able to create optimal deltas; new repository data will be smaller and read times should decrease; interacting with other repositories using this storage model should require less network and CPU resources, making "hg push" and "hg pull" faster
507 repository storage will be able to create optimal deltas; new repository data will be smaller and read times should decrease; interacting with other repositories using this storage model should require less network and CPU resources, making "hg push" and "hg pull" faster
494
508
495 sparserevlog
509 sparserevlog
496 Revlog supports delta chain with more unused data between payload. These gaps will be skipped at read time. This allows for better delta chains, making a better compression and faster exchange with server.
510 Revlog supports delta chain with more unused data between payload. These gaps will be skipped at read time. This allows for better delta chains, making a better compression and faster exchange with server.
497
511
498 persistent-nodemap (rust !)
512 persistent-nodemap (rust !)
499 Speedup revision lookup by node id. (rust !)
513 Speedup revision lookup by node id. (rust !)
500 (rust !)
514 (rust !)
501 processed revlogs:
515 processed revlogs:
502 - all-filelogs
516 - all-filelogs
503 - changelog
517 - changelog
504 - manifest
518 - manifest
505
519
506 additional optimizations are available by specifying "--optimize <name>":
520 additional optimizations are available by specifying "--optimize <name>":
507
521
508 re-delta-parent
522 re-delta-parent
509 deltas within internal storage will be recalculated to choose an optimal base revision where this was not already done; the size of the repository may shrink and various operations may become faster; the first time this optimization is performed could slow down upgrade execution considerably; subsequent invocations should not run noticeably slower
523 deltas within internal storage will be recalculated to choose an optimal base revision where this was not already done; the size of the repository may shrink and various operations may become faster; the first time this optimization is performed could slow down upgrade execution considerably; subsequent invocations should not run noticeably slower
510
524
511 re-delta-multibase
525 re-delta-multibase
512 deltas within internal storage will be recalculated against multiple base revision and the smallest difference will be used; the size of the repository may shrink significantly when there are many merges; this optimization will slow down execution in proportion to the number of merges in the repository and the amount of files in the repository; this slow down should not be significant unless there are tens of thousands of files and thousands of merges
526 deltas within internal storage will be recalculated against multiple base revision and the smallest difference will be used; the size of the repository may shrink significantly when there are many merges; this optimization will slow down execution in proportion to the number of merges in the repository and the amount of files in the repository; this slow down should not be significant unless there are tens of thousands of files and thousands of merges
513
527
514 re-delta-all
528 re-delta-all
515 deltas within internal storage will always be recalculated without reusing prior deltas; this will likely make execution run several times slower; this optimization is typically not needed
529 deltas within internal storage will always be recalculated without reusing prior deltas; this will likely make execution run several times slower; this optimization is typically not needed
516
530
517 re-delta-fulladd
531 re-delta-fulladd
518 every revision will be re-added as if it was new content. It will go through the full storage mechanism giving extensions a chance to process it (eg. lfs). This is similar to "re-delta-all" but even slower since more logic is involved.
532 every revision will be re-added as if it was new content. It will go through the full storage mechanism giving extensions a chance to process it (eg. lfs). This is similar to "re-delta-all" but even slower since more logic is involved.
519
533
520
534
521 $ cd ..
535 $ cd ..
522
536
523 Upgrading a repository that is already modern essentially no-ops
537 Upgrading a repository that is already modern essentially no-ops
524
538
525 $ hg init modern
539 $ hg init modern
526 $ hg -R modern debugupgraderepo --run
540 $ hg -R modern debugupgraderepo --run
527 nothing to do
541 nothing to do
528
542
529 Upgrading a repository to generaldelta works
543 Upgrading a repository to generaldelta works
530
544
531 $ hg --config format.usegeneraldelta=false init upgradegd
545 $ hg --config format.usegeneraldelta=false init upgradegd
532 $ cd upgradegd
546 $ cd upgradegd
533 $ touch f0
547 $ touch f0
534 $ hg -q commit -A -m initial
548 $ hg -q commit -A -m initial
535 $ mkdir FooBarDirectory.d
549 $ mkdir FooBarDirectory.d
536 $ touch FooBarDirectory.d/f1
550 $ touch FooBarDirectory.d/f1
537 $ hg -q commit -A -m 'add f1'
551 $ hg -q commit -A -m 'add f1'
538 $ hg -q up -r 0
552 $ hg -q up -r 0
539 >>> from __future__ import absolute_import, print_function
553 >>> from __future__ import absolute_import, print_function
540 >>> import random
554 >>> import random
541 >>> random.seed(0) # have a reproducible content
555 >>> random.seed(0) # have a reproducible content
542 >>> with open("f2", "wb") as f:
556 >>> with open("f2", "wb") as f:
543 ... for i in range(100000):
557 ... for i in range(100000):
544 ... f.write(b"%d\n" % random.randint(1000000000, 9999999999)) and None
558 ... f.write(b"%d\n" % random.randint(1000000000, 9999999999)) and None
545 $ hg -q commit -A -m 'add f2'
559 $ hg -q commit -A -m 'add f2'
546
560
547 make sure we have a .d file
561 make sure we have a .d file
548
562
549 $ ls -d .hg/store/data/*
563 $ ls -d .hg/store/data/*
550 .hg/store/data/_foo_bar_directory.d.hg
564 .hg/store/data/_foo_bar_directory.d.hg
551 .hg/store/data/f0.i
565 .hg/store/data/f0.i
552 .hg/store/data/f2.d
566 .hg/store/data/f2.d
553 .hg/store/data/f2.i
567 .hg/store/data/f2.i
554
568
555 $ hg debugupgraderepo --run --config format.sparse-revlog=false
569 $ hg debugupgraderepo --run --config format.sparse-revlog=false
556 upgrade will perform the following actions:
570 upgrade will perform the following actions:
557
571
558 requirements
572 requirements
559 preserved: dotencode, fncache, revlogv1, store (no-rust !)
573 preserved: dotencode, fncache, revlogv1, store (no-rust !)
560 preserved: dotencode, fncache, persistent-nodemap, revlogv1, store (rust !)
574 preserved: dotencode, fncache, persistent-nodemap, revlogv1, store (rust !)
561 added: generaldelta
575 added: generaldelta
562
576
563 generaldelta
577 generaldelta
564 repository storage will be able to create optimal deltas; new repository data will be smaller and read times should decrease; interacting with other repositories using this storage model should require less network and CPU resources, making "hg push" and "hg pull" faster
578 repository storage will be able to create optimal deltas; new repository data will be smaller and read times should decrease; interacting with other repositories using this storage model should require less network and CPU resources, making "hg push" and "hg pull" faster
565
579
566 processed revlogs:
580 processed revlogs:
567 - all-filelogs
581 - all-filelogs
568 - changelog
582 - changelog
569 - manifest
583 - manifest
570
584
571 beginning upgrade...
585 beginning upgrade...
572 repository locked and read-only
586 repository locked and read-only
573 creating temporary repository to stage upgraded data: $TESTTMP/upgradegd/.hg/upgrade.* (glob)
587 creating temporary repository to stage upgraded data: $TESTTMP/upgradegd/.hg/upgrade.* (glob)
574 (it is safe to interrupt this process any time before data migration completes)
588 (it is safe to interrupt this process any time before data migration completes)
575 migrating 9 total revisions (3 in filelogs, 3 in manifests, 3 in changelog)
589 migrating 9 total revisions (3 in filelogs, 3 in manifests, 3 in changelog)
576 migrating 519 KB in store; 1.05 MB tracked data
590 migrating 519 KB in store; 1.05 MB tracked data
577 migrating 3 filelogs containing 3 revisions (518 KB in store; 1.05 MB tracked data)
591 migrating 3 filelogs containing 3 revisions (518 KB in store; 1.05 MB tracked data)
578 finished migrating 3 filelog revisions across 3 filelogs; change in size: 0 bytes
592 finished migrating 3 filelog revisions across 3 filelogs; change in size: 0 bytes
579 migrating 1 manifests containing 3 revisions (384 bytes in store; 238 bytes tracked data)
593 migrating 1 manifests containing 3 revisions (384 bytes in store; 238 bytes tracked data)
580 finished migrating 3 manifest revisions across 1 manifests; change in size: -17 bytes
594 finished migrating 3 manifest revisions across 1 manifests; change in size: -17 bytes
581 migrating changelog containing 3 revisions (394 bytes in store; 199 bytes tracked data)
595 migrating changelog containing 3 revisions (394 bytes in store; 199 bytes tracked data)
582 finished migrating 3 changelog revisions; change in size: 0 bytes
596 finished migrating 3 changelog revisions; change in size: 0 bytes
583 finished migrating 9 total revisions; total change in store size: -17 bytes
597 finished migrating 9 total revisions; total change in store size: -17 bytes
584 copying phaseroots
598 copying phaseroots
585 data fully upgraded in a temporary repository
599 data fully upgraded in a temporary repository
586 marking source repository as being upgraded; clients will be unable to read from repository
600 marking source repository as being upgraded; clients will be unable to read from repository
587 starting in-place swap of repository data
601 starting in-place swap of repository data
588 replaced files will be backed up at $TESTTMP/upgradegd/.hg/upgradebackup.* (glob)
602 replaced files will be backed up at $TESTTMP/upgradegd/.hg/upgradebackup.* (glob)
589 replacing store...
603 replacing store...
590 store replacement complete; repository was inconsistent for *s (glob)
604 store replacement complete; repository was inconsistent for *s (glob)
591 finalizing requirements file and making repository readable again
605 finalizing requirements file and making repository readable again
592 removing temporary repository $TESTTMP/upgradegd/.hg/upgrade.* (glob)
606 removing temporary repository $TESTTMP/upgradegd/.hg/upgrade.* (glob)
593 copy of old repository backed up at $TESTTMP/upgradegd/.hg/upgradebackup.* (glob)
607 copy of old repository backed up at $TESTTMP/upgradegd/.hg/upgradebackup.* (glob)
594 the old repository will not be deleted; remove it to free up disk space once the upgraded repository is verified
608 the old repository will not be deleted; remove it to free up disk space once the upgraded repository is verified
595
609
596 Original requirements backed up
610 Original requirements backed up
597
611
598 $ cat .hg/upgradebackup.*/requires
612 $ cat .hg/upgradebackup.*/requires
599 dotencode
613 dotencode
600 fncache
614 fncache
601 persistent-nodemap (rust !)
615 persistent-nodemap (rust !)
602 revlogv1
616 revlogv1
603 store
617 store
604
618
605 generaldelta added to original requirements files
619 generaldelta added to original requirements files
606
620
607 $ cat .hg/requires
621 $ cat .hg/requires
608 dotencode
622 dotencode
609 fncache
623 fncache
610 generaldelta
624 generaldelta
611 persistent-nodemap (rust !)
625 persistent-nodemap (rust !)
612 revlogv1
626 revlogv1
613 store
627 store
614
628
615 store directory has files we expect
629 store directory has files we expect
616
630
617 $ ls .hg/store
631 $ ls .hg/store
618 00changelog.i
632 00changelog.i
619 00manifest.i
633 00manifest.i
620 data
634 data
621 fncache
635 fncache
622 phaseroots
636 phaseroots
623 undo
637 undo
624 undo.backupfiles
638 undo.backupfiles
625 undo.phaseroots
639 undo.phaseroots
626
640
627 manifest should be generaldelta
641 manifest should be generaldelta
628
642
629 $ hg debugrevlog -m | grep flags
643 $ hg debugrevlog -m | grep flags
630 flags : inline, generaldelta
644 flags : inline, generaldelta
631
645
632 verify should be happy
646 verify should be happy
633
647
634 $ hg verify
648 $ hg verify
635 checking changesets
649 checking changesets
636 checking manifests
650 checking manifests
637 crosschecking files in changesets and manifests
651 crosschecking files in changesets and manifests
638 checking files
652 checking files
639 checked 3 changesets with 3 changes to 3 files
653 checked 3 changesets with 3 changes to 3 files
640
654
641 old store should be backed up
655 old store should be backed up
642
656
643 $ ls -d .hg/upgradebackup.*/
657 $ ls -d .hg/upgradebackup.*/
644 .hg/upgradebackup.*/ (glob)
658 .hg/upgradebackup.*/ (glob)
645 $ ls .hg/upgradebackup.*/store
659 $ ls .hg/upgradebackup.*/store
646 00changelog.i
660 00changelog.i
647 00manifest.i
661 00manifest.i
648 data
662 data
649 fncache
663 fncache
650 phaseroots
664 phaseroots
651 undo
665 undo
652 undo.backup.fncache
666 undo.backup.fncache
653 undo.backupfiles
667 undo.backupfiles
654 undo.phaseroots
668 undo.phaseroots
655
669
656 unless --no-backup is passed
670 unless --no-backup is passed
657
671
658 $ rm -rf .hg/upgradebackup.*/
672 $ rm -rf .hg/upgradebackup.*/
659 $ hg debugupgraderepo --run --no-backup
673 $ hg debugupgraderepo --run --no-backup
660 upgrade will perform the following actions:
674 upgrade will perform the following actions:
661
675
662 requirements
676 requirements
663 preserved: dotencode, fncache, generaldelta, revlogv1, store (no-rust !)
677 preserved: dotencode, fncache, generaldelta, revlogv1, store (no-rust !)
664 preserved: dotencode, fncache, generaldelta, persistent-nodemap, revlogv1, store (rust !)
678 preserved: dotencode, fncache, generaldelta, persistent-nodemap, revlogv1, store (rust !)
665 added: sparserevlog
679 added: sparserevlog
666
680
667 sparserevlog
681 sparserevlog
668 Revlog supports delta chain with more unused data between payload. These gaps will be skipped at read time. This allows for better delta chains, making a better compression and faster exchange with server.
682 Revlog supports delta chain with more unused data between payload. These gaps will be skipped at read time. This allows for better delta chains, making a better compression and faster exchange with server.
669
683
670 processed revlogs:
684 processed revlogs:
671 - all-filelogs
685 - all-filelogs
672 - changelog
686 - changelog
673 - manifest
687 - manifest
674
688
675 beginning upgrade...
689 beginning upgrade...
676 repository locked and read-only
690 repository locked and read-only
677 creating temporary repository to stage upgraded data: $TESTTMP/upgradegd/.hg/upgrade.* (glob)
691 creating temporary repository to stage upgraded data: $TESTTMP/upgradegd/.hg/upgrade.* (glob)
678 (it is safe to interrupt this process any time before data migration completes)
692 (it is safe to interrupt this process any time before data migration completes)
679 migrating 9 total revisions (3 in filelogs, 3 in manifests, 3 in changelog)
693 migrating 9 total revisions (3 in filelogs, 3 in manifests, 3 in changelog)
680 migrating 519 KB in store; 1.05 MB tracked data
694 migrating 519 KB in store; 1.05 MB tracked data
681 migrating 3 filelogs containing 3 revisions (518 KB in store; 1.05 MB tracked data)
695 migrating 3 filelogs containing 3 revisions (518 KB in store; 1.05 MB tracked data)
682 finished migrating 3 filelog revisions across 3 filelogs; change in size: 0 bytes
696 finished migrating 3 filelog revisions across 3 filelogs; change in size: 0 bytes
683 migrating 1 manifests containing 3 revisions (367 bytes in store; 238 bytes tracked data)
697 migrating 1 manifests containing 3 revisions (367 bytes in store; 238 bytes tracked data)
684 finished migrating 3 manifest revisions across 1 manifests; change in size: 0 bytes
698 finished migrating 3 manifest revisions across 1 manifests; change in size: 0 bytes
685 migrating changelog containing 3 revisions (394 bytes in store; 199 bytes tracked data)
699 migrating changelog containing 3 revisions (394 bytes in store; 199 bytes tracked data)
686 finished migrating 3 changelog revisions; change in size: 0 bytes
700 finished migrating 3 changelog revisions; change in size: 0 bytes
687 finished migrating 9 total revisions; total change in store size: 0 bytes
701 finished migrating 9 total revisions; total change in store size: 0 bytes
688 copying phaseroots
702 copying phaseroots
689 data fully upgraded in a temporary repository
703 data fully upgraded in a temporary repository
690 marking source repository as being upgraded; clients will be unable to read from repository
704 marking source repository as being upgraded; clients will be unable to read from repository
691 starting in-place swap of repository data
705 starting in-place swap of repository data
692 replacing store...
706 replacing store...
693 store replacement complete; repository was inconsistent for * (glob)
707 store replacement complete; repository was inconsistent for * (glob)
694 finalizing requirements file and making repository readable again
708 finalizing requirements file and making repository readable again
695 removing temporary repository $TESTTMP/upgradegd/.hg/upgrade.* (glob)
709 removing temporary repository $TESTTMP/upgradegd/.hg/upgrade.* (glob)
696 $ ls -1 .hg/ | grep upgradebackup
710 $ ls -1 .hg/ | grep upgradebackup
697 [1]
711 [1]
698
712
699 We can restrict optimization to some revlog:
713 We can restrict optimization to some revlog:
700
714
701 $ hg debugupgrade --optimize re-delta-parent --run --manifest --no-backup --debug --traceback
715 $ hg debugupgrade --optimize re-delta-parent --run --manifest --no-backup --debug --traceback
702 upgrade will perform the following actions:
716 upgrade will perform the following actions:
703
717
704 requirements
718 requirements
705 preserved: dotencode, fncache, generaldelta, revlogv1, sparserevlog, store (no-rust !)
719 preserved: dotencode, fncache, generaldelta, revlogv1, sparserevlog, store (no-rust !)
706 preserved: dotencode, fncache, generaldelta, persistent-nodemap, revlogv1, sparserevlog, store (rust !)
720 preserved: dotencode, fncache, generaldelta, persistent-nodemap, revlogv1, sparserevlog, store (rust !)
707
721
708 optimisations: re-delta-parent
722 optimisations: re-delta-parent
709
723
710 re-delta-parent
724 re-delta-parent
711 deltas within internal storage will choose a new base revision if needed
725 deltas within internal storage will choose a new base revision if needed
712
726
713 processed revlogs:
727 processed revlogs:
714 - manifest
728 - manifest
715
729
716 beginning upgrade...
730 beginning upgrade...
717 repository locked and read-only
731 repository locked and read-only
718 creating temporary repository to stage upgraded data: $TESTTMP/upgradegd/.hg/upgrade.* (glob)
732 creating temporary repository to stage upgraded data: $TESTTMP/upgradegd/.hg/upgrade.* (glob)
719 (it is safe to interrupt this process any time before data migration completes)
733 (it is safe to interrupt this process any time before data migration completes)
720 migrating 9 total revisions (3 in filelogs, 3 in manifests, 3 in changelog)
734 migrating 9 total revisions (3 in filelogs, 3 in manifests, 3 in changelog)
721 migrating 519 KB in store; 1.05 MB tracked data
735 migrating 519 KB in store; 1.05 MB tracked data
722 migrating 3 filelogs containing 3 revisions (518 KB in store; 1.05 MB tracked data)
736 migrating 3 filelogs containing 3 revisions (518 KB in store; 1.05 MB tracked data)
723 blindly copying data/FooBarDirectory.d/f1.i containing 1 revisions
737 blindly copying data/FooBarDirectory.d/f1.i containing 1 revisions
724 blindly copying data/f0.i containing 1 revisions
738 blindly copying data/f0.i containing 1 revisions
725 blindly copying data/f2.i containing 1 revisions
739 blindly copying data/f2.i containing 1 revisions
726 finished migrating 3 filelog revisions across 3 filelogs; change in size: 0 bytes
740 finished migrating 3 filelog revisions across 3 filelogs; change in size: 0 bytes
727 migrating 1 manifests containing 3 revisions (367 bytes in store; 238 bytes tracked data)
741 migrating 1 manifests containing 3 revisions (367 bytes in store; 238 bytes tracked data)
728 cloning 3 revisions from 00manifest.i
742 cloning 3 revisions from 00manifest.i
729 finished migrating 3 manifest revisions across 1 manifests; change in size: 0 bytes
743 finished migrating 3 manifest revisions across 1 manifests; change in size: 0 bytes
730 migrating changelog containing 3 revisions (394 bytes in store; 199 bytes tracked data)
744 migrating changelog containing 3 revisions (394 bytes in store; 199 bytes tracked data)
731 blindly copying 00changelog.i containing 3 revisions
745 blindly copying 00changelog.i containing 3 revisions
732 finished migrating 3 changelog revisions; change in size: 0 bytes
746 finished migrating 3 changelog revisions; change in size: 0 bytes
733 finished migrating 9 total revisions; total change in store size: 0 bytes
747 finished migrating 9 total revisions; total change in store size: 0 bytes
734 copying phaseroots
748 copying phaseroots
735 data fully upgraded in a temporary repository
749 data fully upgraded in a temporary repository
736 marking source repository as being upgraded; clients will be unable to read from repository
750 marking source repository as being upgraded; clients will be unable to read from repository
737 starting in-place swap of repository data
751 starting in-place swap of repository data
738 replacing store...
752 replacing store...
739 store replacement complete; repository was inconsistent for *s (glob)
753 store replacement complete; repository was inconsistent for *s (glob)
740 finalizing requirements file and making repository readable again
754 finalizing requirements file and making repository readable again
741 removing temporary repository $TESTTMP/upgradegd/.hg/upgrade.* (glob)
755 removing temporary repository $TESTTMP/upgradegd/.hg/upgrade.* (glob)
742
756
743 Check that the repo still works fine
757 Check that the repo still works fine
744
758
745 $ hg log -G --stat
759 $ hg log -G --stat
746 @ changeset: 2:76d4395f5413 (no-py3 !)
760 @ changeset: 2:76d4395f5413 (no-py3 !)
747 @ changeset: 2:fca376863211 (py3 !)
761 @ changeset: 2:fca376863211 (py3 !)
748 | tag: tip
762 | tag: tip
749 | parent: 0:ba592bf28da2
763 | parent: 0:ba592bf28da2
750 | user: test
764 | user: test
751 | date: Thu Jan 01 00:00:00 1970 +0000
765 | date: Thu Jan 01 00:00:00 1970 +0000
752 | summary: add f2
766 | summary: add f2
753 |
767 |
754 | f2 | 100000 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
768 | f2 | 100000 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
755 | 1 files changed, 100000 insertions(+), 0 deletions(-)
769 | 1 files changed, 100000 insertions(+), 0 deletions(-)
756 |
770 |
757 | o changeset: 1:2029ce2354e2
771 | o changeset: 1:2029ce2354e2
758 |/ user: test
772 |/ user: test
759 | date: Thu Jan 01 00:00:00 1970 +0000
773 | date: Thu Jan 01 00:00:00 1970 +0000
760 | summary: add f1
774 | summary: add f1
761 |
775 |
762 |
776 |
763 o changeset: 0:ba592bf28da2
777 o changeset: 0:ba592bf28da2
764 user: test
778 user: test
765 date: Thu Jan 01 00:00:00 1970 +0000
779 date: Thu Jan 01 00:00:00 1970 +0000
766 summary: initial
780 summary: initial
767
781
768
782
769
783
770 $ hg verify
784 $ hg verify
771 checking changesets
785 checking changesets
772 checking manifests
786 checking manifests
773 crosschecking files in changesets and manifests
787 crosschecking files in changesets and manifests
774 checking files
788 checking files
775 checked 3 changesets with 3 changes to 3 files
789 checked 3 changesets with 3 changes to 3 files
776
790
777 Check we can select negatively
791 Check we can select negatively
778
792
779 $ hg debugupgrade --optimize re-delta-parent --run --no-manifest --no-backup --debug --traceback
793 $ hg debugupgrade --optimize re-delta-parent --run --no-manifest --no-backup --debug --traceback
780 upgrade will perform the following actions:
794 upgrade will perform the following actions:
781
795
782 requirements
796 requirements
783 preserved: dotencode, fncache, generaldelta, revlogv1, sparserevlog, store (no-rust !)
797 preserved: dotencode, fncache, generaldelta, revlogv1, sparserevlog, store (no-rust !)
784 preserved: dotencode, fncache, generaldelta, persistent-nodemap, revlogv1, sparserevlog, store (rust !)
798 preserved: dotencode, fncache, generaldelta, persistent-nodemap, revlogv1, sparserevlog, store (rust !)
785
799
786 optimisations: re-delta-parent
800 optimisations: re-delta-parent
787
801
788 re-delta-parent
802 re-delta-parent
789 deltas within internal storage will choose a new base revision if needed
803 deltas within internal storage will choose a new base revision if needed
790
804
791 processed revlogs:
805 processed revlogs:
792 - all-filelogs
806 - all-filelogs
793 - changelog
807 - changelog
794
808
795 beginning upgrade...
809 beginning upgrade...
796 repository locked and read-only
810 repository locked and read-only
797 creating temporary repository to stage upgraded data: $TESTTMP/upgradegd/.hg/upgrade.* (glob)
811 creating temporary repository to stage upgraded data: $TESTTMP/upgradegd/.hg/upgrade.* (glob)
798 (it is safe to interrupt this process any time before data migration completes)
812 (it is safe to interrupt this process any time before data migration completes)
799 migrating 9 total revisions (3 in filelogs, 3 in manifests, 3 in changelog)
813 migrating 9 total revisions (3 in filelogs, 3 in manifests, 3 in changelog)
800 migrating 519 KB in store; 1.05 MB tracked data
814 migrating 519 KB in store; 1.05 MB tracked data
801 migrating 3 filelogs containing 3 revisions (518 KB in store; 1.05 MB tracked data)
815 migrating 3 filelogs containing 3 revisions (518 KB in store; 1.05 MB tracked data)
802 cloning 1 revisions from data/FooBarDirectory.d/f1.i
816 cloning 1 revisions from data/FooBarDirectory.d/f1.i
803 cloning 1 revisions from data/f0.i
817 cloning 1 revisions from data/f0.i
804 cloning 1 revisions from data/f2.i
818 cloning 1 revisions from data/f2.i
805 finished migrating 3 filelog revisions across 3 filelogs; change in size: 0 bytes
819 finished migrating 3 filelog revisions across 3 filelogs; change in size: 0 bytes
806 migrating 1 manifests containing 3 revisions (367 bytes in store; 238 bytes tracked data)
820 migrating 1 manifests containing 3 revisions (367 bytes in store; 238 bytes tracked data)
807 blindly copying 00manifest.i containing 3 revisions
821 blindly copying 00manifest.i containing 3 revisions
808 finished migrating 3 manifest revisions across 1 manifests; change in size: 0 bytes
822 finished migrating 3 manifest revisions across 1 manifests; change in size: 0 bytes
809 migrating changelog containing 3 revisions (394 bytes in store; 199 bytes tracked data)
823 migrating changelog containing 3 revisions (394 bytes in store; 199 bytes tracked data)
810 cloning 3 revisions from 00changelog.i
824 cloning 3 revisions from 00changelog.i
811 finished migrating 3 changelog revisions; change in size: 0 bytes
825 finished migrating 3 changelog revisions; change in size: 0 bytes
812 finished migrating 9 total revisions; total change in store size: 0 bytes
826 finished migrating 9 total revisions; total change in store size: 0 bytes
813 copying phaseroots
827 copying phaseroots
814 data fully upgraded in a temporary repository
828 data fully upgraded in a temporary repository
815 marking source repository as being upgraded; clients will be unable to read from repository
829 marking source repository as being upgraded; clients will be unable to read from repository
816 starting in-place swap of repository data
830 starting in-place swap of repository data
817 replacing store...
831 replacing store...
818 store replacement complete; repository was inconsistent for *s (glob)
832 store replacement complete; repository was inconsistent for *s (glob)
819 finalizing requirements file and making repository readable again
833 finalizing requirements file and making repository readable again
820 removing temporary repository $TESTTMP/upgradegd/.hg/upgrade.* (glob)
834 removing temporary repository $TESTTMP/upgradegd/.hg/upgrade.* (glob)
821 $ hg verify
835 $ hg verify
822 checking changesets
836 checking changesets
823 checking manifests
837 checking manifests
824 crosschecking files in changesets and manifests
838 crosschecking files in changesets and manifests
825 checking files
839 checking files
826 checked 3 changesets with 3 changes to 3 files
840 checked 3 changesets with 3 changes to 3 files
827
841
828 Check that we can select changelog only
842 Check that we can select changelog only
829
843
830 $ hg debugupgrade --optimize re-delta-parent --run --changelog --no-backup --debug --traceback
844 $ hg debugupgrade --optimize re-delta-parent --run --changelog --no-backup --debug --traceback
831 upgrade will perform the following actions:
845 upgrade will perform the following actions:
832
846
833 requirements
847 requirements
834 preserved: dotencode, fncache, generaldelta, revlogv1, sparserevlog, store (no-rust !)
848 preserved: dotencode, fncache, generaldelta, revlogv1, sparserevlog, store (no-rust !)
835 preserved: dotencode, fncache, generaldelta, persistent-nodemap, revlogv1, sparserevlog, store (rust !)
849 preserved: dotencode, fncache, generaldelta, persistent-nodemap, revlogv1, sparserevlog, store (rust !)
836
850
837 optimisations: re-delta-parent
851 optimisations: re-delta-parent
838
852
839 re-delta-parent
853 re-delta-parent
840 deltas within internal storage will choose a new base revision if needed
854 deltas within internal storage will choose a new base revision if needed
841
855
842 processed revlogs:
856 processed revlogs:
843 - changelog
857 - changelog
844
858
845 beginning upgrade...
859 beginning upgrade...
846 repository locked and read-only
860 repository locked and read-only
847 creating temporary repository to stage upgraded data: $TESTTMP/upgradegd/.hg/upgrade.* (glob)
861 creating temporary repository to stage upgraded data: $TESTTMP/upgradegd/.hg/upgrade.* (glob)
848 (it is safe to interrupt this process any time before data migration completes)
862 (it is safe to interrupt this process any time before data migration completes)
849 migrating 9 total revisions (3 in filelogs, 3 in manifests, 3 in changelog)
863 migrating 9 total revisions (3 in filelogs, 3 in manifests, 3 in changelog)
850 migrating 519 KB in store; 1.05 MB tracked data
864 migrating 519 KB in store; 1.05 MB tracked data
851 migrating 3 filelogs containing 3 revisions (518 KB in store; 1.05 MB tracked data)
865 migrating 3 filelogs containing 3 revisions (518 KB in store; 1.05 MB tracked data)
852 blindly copying data/FooBarDirectory.d/f1.i containing 1 revisions
866 blindly copying data/FooBarDirectory.d/f1.i containing 1 revisions
853 blindly copying data/f0.i containing 1 revisions
867 blindly copying data/f0.i containing 1 revisions
854 blindly copying data/f2.i containing 1 revisions
868 blindly copying data/f2.i containing 1 revisions
855 finished migrating 3 filelog revisions across 3 filelogs; change in size: 0 bytes
869 finished migrating 3 filelog revisions across 3 filelogs; change in size: 0 bytes
856 migrating 1 manifests containing 3 revisions (367 bytes in store; 238 bytes tracked data)
870 migrating 1 manifests containing 3 revisions (367 bytes in store; 238 bytes tracked data)
857 blindly copying 00manifest.i containing 3 revisions
871 blindly copying 00manifest.i containing 3 revisions
858 finished migrating 3 manifest revisions across 1 manifests; change in size: 0 bytes
872 finished migrating 3 manifest revisions across 1 manifests; change in size: 0 bytes
859 migrating changelog containing 3 revisions (394 bytes in store; 199 bytes tracked data)
873 migrating changelog containing 3 revisions (394 bytes in store; 199 bytes tracked data)
860 cloning 3 revisions from 00changelog.i
874 cloning 3 revisions from 00changelog.i
861 finished migrating 3 changelog revisions; change in size: 0 bytes
875 finished migrating 3 changelog revisions; change in size: 0 bytes
862 finished migrating 9 total revisions; total change in store size: 0 bytes
876 finished migrating 9 total revisions; total change in store size: 0 bytes
863 copying phaseroots
877 copying phaseroots
864 data fully upgraded in a temporary repository
878 data fully upgraded in a temporary repository
865 marking source repository as being upgraded; clients will be unable to read from repository
879 marking source repository as being upgraded; clients will be unable to read from repository
866 starting in-place swap of repository data
880 starting in-place swap of repository data
867 replacing store...
881 replacing store...
868 store replacement complete; repository was inconsistent for *s (glob)
882 store replacement complete; repository was inconsistent for *s (glob)
869 finalizing requirements file and making repository readable again
883 finalizing requirements file and making repository readable again
870 removing temporary repository $TESTTMP/upgradegd/.hg/upgrade.* (glob)
884 removing temporary repository $TESTTMP/upgradegd/.hg/upgrade.* (glob)
871 $ hg verify
885 $ hg verify
872 checking changesets
886 checking changesets
873 checking manifests
887 checking manifests
874 crosschecking files in changesets and manifests
888 crosschecking files in changesets and manifests
875 checking files
889 checking files
876 checked 3 changesets with 3 changes to 3 files
890 checked 3 changesets with 3 changes to 3 files
877
891
878 Check that we can select filelog only
892 Check that we can select filelog only
879
893
880 $ hg debugupgrade --optimize re-delta-parent --run --no-changelog --no-manifest --no-backup --debug --traceback
894 $ hg debugupgrade --optimize re-delta-parent --run --no-changelog --no-manifest --no-backup --debug --traceback
881 upgrade will perform the following actions:
895 upgrade will perform the following actions:
882
896
883 requirements
897 requirements
884 preserved: dotencode, fncache, generaldelta, revlogv1, sparserevlog, store (no-rust !)
898 preserved: dotencode, fncache, generaldelta, revlogv1, sparserevlog, store (no-rust !)
885 preserved: dotencode, fncache, generaldelta, persistent-nodemap, revlogv1, sparserevlog, store (rust !)
899 preserved: dotencode, fncache, generaldelta, persistent-nodemap, revlogv1, sparserevlog, store (rust !)
886
900
887 optimisations: re-delta-parent
901 optimisations: re-delta-parent
888
902
889 re-delta-parent
903 re-delta-parent
890 deltas within internal storage will choose a new base revision if needed
904 deltas within internal storage will choose a new base revision if needed
891
905
892 processed revlogs:
906 processed revlogs:
893 - all-filelogs
907 - all-filelogs
894
908
895 beginning upgrade...
909 beginning upgrade...
896 repository locked and read-only
910 repository locked and read-only
897 creating temporary repository to stage upgraded data: $TESTTMP/upgradegd/.hg/upgrade.* (glob)
911 creating temporary repository to stage upgraded data: $TESTTMP/upgradegd/.hg/upgrade.* (glob)
898 (it is safe to interrupt this process any time before data migration completes)
912 (it is safe to interrupt this process any time before data migration completes)
899 migrating 9 total revisions (3 in filelogs, 3 in manifests, 3 in changelog)
913 migrating 9 total revisions (3 in filelogs, 3 in manifests, 3 in changelog)
900 migrating 519 KB in store; 1.05 MB tracked data
914 migrating 519 KB in store; 1.05 MB tracked data
901 migrating 3 filelogs containing 3 revisions (518 KB in store; 1.05 MB tracked data)
915 migrating 3 filelogs containing 3 revisions (518 KB in store; 1.05 MB tracked data)
902 cloning 1 revisions from data/FooBarDirectory.d/f1.i
916 cloning 1 revisions from data/FooBarDirectory.d/f1.i
903 cloning 1 revisions from data/f0.i
917 cloning 1 revisions from data/f0.i
904 cloning 1 revisions from data/f2.i
918 cloning 1 revisions from data/f2.i
905 finished migrating 3 filelog revisions across 3 filelogs; change in size: 0 bytes
919 finished migrating 3 filelog revisions across 3 filelogs; change in size: 0 bytes
906 migrating 1 manifests containing 3 revisions (367 bytes in store; 238 bytes tracked data)
920 migrating 1 manifests containing 3 revisions (367 bytes in store; 238 bytes tracked data)
907 blindly copying 00manifest.i containing 3 revisions
921 blindly copying 00manifest.i containing 3 revisions
908 finished migrating 3 manifest revisions across 1 manifests; change in size: 0 bytes
922 finished migrating 3 manifest revisions across 1 manifests; change in size: 0 bytes
909 migrating changelog containing 3 revisions (394 bytes in store; 199 bytes tracked data)
923 migrating changelog containing 3 revisions (394 bytes in store; 199 bytes tracked data)
910 blindly copying 00changelog.i containing 3 revisions
924 blindly copying 00changelog.i containing 3 revisions
911 finished migrating 3 changelog revisions; change in size: 0 bytes
925 finished migrating 3 changelog revisions; change in size: 0 bytes
912 finished migrating 9 total revisions; total change in store size: 0 bytes
926 finished migrating 9 total revisions; total change in store size: 0 bytes
913 copying phaseroots
927 copying phaseroots
914 data fully upgraded in a temporary repository
928 data fully upgraded in a temporary repository
915 marking source repository as being upgraded; clients will be unable to read from repository
929 marking source repository as being upgraded; clients will be unable to read from repository
916 starting in-place swap of repository data
930 starting in-place swap of repository data
917 replacing store...
931 replacing store...
918 store replacement complete; repository was inconsistent for *s (glob)
932 store replacement complete; repository was inconsistent for *s (glob)
919 finalizing requirements file and making repository readable again
933 finalizing requirements file and making repository readable again
920 removing temporary repository $TESTTMP/upgradegd/.hg/upgrade.* (glob)
934 removing temporary repository $TESTTMP/upgradegd/.hg/upgrade.* (glob)
921 $ hg verify
935 $ hg verify
922 checking changesets
936 checking changesets
923 checking manifests
937 checking manifests
924 crosschecking files in changesets and manifests
938 crosschecking files in changesets and manifests
925 checking files
939 checking files
926 checked 3 changesets with 3 changes to 3 files
940 checked 3 changesets with 3 changes to 3 files
927
941
928
942
929 Check you can't skip revlog clone during important format downgrade
943 Check you can't skip revlog clone during important format downgrade
930
944
931 $ echo "[format]" > .hg/hgrc
945 $ echo "[format]" > .hg/hgrc
932 $ echo "sparse-revlog=no" >> .hg/hgrc
946 $ echo "sparse-revlog=no" >> .hg/hgrc
933 $ hg debugupgrade --optimize re-delta-parent --run --manifest --no-backup --debug --traceback
947 $ hg debugupgrade --optimize re-delta-parent --run --manifest --no-backup --debug --traceback
934 ignoring revlogs selection flags, format requirements change: sparserevlog
948 ignoring revlogs selection flags, format requirements change: sparserevlog
935 upgrade will perform the following actions:
949 upgrade will perform the following actions:
936
950
937 requirements
951 requirements
938 preserved: dotencode, fncache, generaldelta, revlogv1, store (no-rust !)
952 preserved: dotencode, fncache, generaldelta, revlogv1, store (no-rust !)
939 preserved: dotencode, fncache, generaldelta, persistent-nodemap, revlogv1, store (rust !)
953 preserved: dotencode, fncache, generaldelta, persistent-nodemap, revlogv1, store (rust !)
940 removed: sparserevlog
954 removed: sparserevlog
941
955
942 optimisations: re-delta-parent
956 optimisations: re-delta-parent
943
957
944 re-delta-parent
958 re-delta-parent
945 deltas within internal storage will choose a new base revision if needed
959 deltas within internal storage will choose a new base revision if needed
946
960
947 processed revlogs:
961 processed revlogs:
948 - all-filelogs
962 - all-filelogs
949 - changelog
963 - changelog
950 - manifest
964 - manifest
951
965
952 beginning upgrade...
966 beginning upgrade...
953 repository locked and read-only
967 repository locked and read-only
954 creating temporary repository to stage upgraded data: $TESTTMP/upgradegd/.hg/upgrade.* (glob)
968 creating temporary repository to stage upgraded data: $TESTTMP/upgradegd/.hg/upgrade.* (glob)
955 (it is safe to interrupt this process any time before data migration completes)
969 (it is safe to interrupt this process any time before data migration completes)
956 migrating 9 total revisions (3 in filelogs, 3 in manifests, 3 in changelog)
970 migrating 9 total revisions (3 in filelogs, 3 in manifests, 3 in changelog)
957 migrating 519 KB in store; 1.05 MB tracked data
971 migrating 519 KB in store; 1.05 MB tracked data
958 migrating 3 filelogs containing 3 revisions (518 KB in store; 1.05 MB tracked data)
972 migrating 3 filelogs containing 3 revisions (518 KB in store; 1.05 MB tracked data)
959 cloning 1 revisions from data/FooBarDirectory.d/f1.i
973 cloning 1 revisions from data/FooBarDirectory.d/f1.i
960 cloning 1 revisions from data/f0.i
974 cloning 1 revisions from data/f0.i
961 cloning 1 revisions from data/f2.i
975 cloning 1 revisions from data/f2.i
962 finished migrating 3 filelog revisions across 3 filelogs; change in size: 0 bytes
976 finished migrating 3 filelog revisions across 3 filelogs; change in size: 0 bytes
963 migrating 1 manifests containing 3 revisions (367 bytes in store; 238 bytes tracked data)
977 migrating 1 manifests containing 3 revisions (367 bytes in store; 238 bytes tracked data)
964 cloning 3 revisions from 00manifest.i
978 cloning 3 revisions from 00manifest.i
965 finished migrating 3 manifest revisions across 1 manifests; change in size: 0 bytes
979 finished migrating 3 manifest revisions across 1 manifests; change in size: 0 bytes
966 migrating changelog containing 3 revisions (394 bytes in store; 199 bytes tracked data)
980 migrating changelog containing 3 revisions (394 bytes in store; 199 bytes tracked data)
967 cloning 3 revisions from 00changelog.i
981 cloning 3 revisions from 00changelog.i
968 finished migrating 3 changelog revisions; change in size: 0 bytes
982 finished migrating 3 changelog revisions; change in size: 0 bytes
969 finished migrating 9 total revisions; total change in store size: 0 bytes
983 finished migrating 9 total revisions; total change in store size: 0 bytes
970 copying phaseroots
984 copying phaseroots
971 data fully upgraded in a temporary repository
985 data fully upgraded in a temporary repository
972 marking source repository as being upgraded; clients will be unable to read from repository
986 marking source repository as being upgraded; clients will be unable to read from repository
973 starting in-place swap of repository data
987 starting in-place swap of repository data
974 replacing store...
988 replacing store...
975 store replacement complete; repository was inconsistent for *s (glob)
989 store replacement complete; repository was inconsistent for *s (glob)
976 finalizing requirements file and making repository readable again
990 finalizing requirements file and making repository readable again
977 removing temporary repository $TESTTMP/upgradegd/.hg/upgrade.* (glob)
991 removing temporary repository $TESTTMP/upgradegd/.hg/upgrade.* (glob)
978 $ hg verify
992 $ hg verify
979 checking changesets
993 checking changesets
980 checking manifests
994 checking manifests
981 crosschecking files in changesets and manifests
995 crosschecking files in changesets and manifests
982 checking files
996 checking files
983 checked 3 changesets with 3 changes to 3 files
997 checked 3 changesets with 3 changes to 3 files
984
998
985 Check you can't skip revlog clone during important format upgrade
999 Check you can't skip revlog clone during important format upgrade
986
1000
987 $ echo "sparse-revlog=yes" >> .hg/hgrc
1001 $ echo "sparse-revlog=yes" >> .hg/hgrc
988 $ hg debugupgrade --optimize re-delta-parent --run --manifest --no-backup --debug --traceback
1002 $ hg debugupgrade --optimize re-delta-parent --run --manifest --no-backup --debug --traceback
989 ignoring revlogs selection flags, format requirements change: sparserevlog
1003 ignoring revlogs selection flags, format requirements change: sparserevlog
990 upgrade will perform the following actions:
1004 upgrade will perform the following actions:
991
1005
992 requirements
1006 requirements
993 preserved: dotencode, fncache, generaldelta, revlogv1, store (no-rust !)
1007 preserved: dotencode, fncache, generaldelta, revlogv1, store (no-rust !)
994 preserved: dotencode, fncache, generaldelta, persistent-nodemap, revlogv1, store (rust !)
1008 preserved: dotencode, fncache, generaldelta, persistent-nodemap, revlogv1, store (rust !)
995 added: sparserevlog
1009 added: sparserevlog
996
1010
997 optimisations: re-delta-parent
1011 optimisations: re-delta-parent
998
1012
999 sparserevlog
1013 sparserevlog
1000 Revlog supports delta chain with more unused data between payload. These gaps will be skipped at read time. This allows for better delta chains, making a better compression and faster exchange with server.
1014 Revlog supports delta chain with more unused data between payload. These gaps will be skipped at read time. This allows for better delta chains, making a better compression and faster exchange with server.
1001
1015
1002 re-delta-parent
1016 re-delta-parent
1003 deltas within internal storage will choose a new base revision if needed
1017 deltas within internal storage will choose a new base revision if needed
1004
1018
1005 processed revlogs:
1019 processed revlogs:
1006 - all-filelogs
1020 - all-filelogs
1007 - changelog
1021 - changelog
1008 - manifest
1022 - manifest
1009
1023
1010 beginning upgrade...
1024 beginning upgrade...
1011 repository locked and read-only
1025 repository locked and read-only
1012 creating temporary repository to stage upgraded data: $TESTTMP/upgradegd/.hg/upgrade.* (glob)
1026 creating temporary repository to stage upgraded data: $TESTTMP/upgradegd/.hg/upgrade.* (glob)
1013 (it is safe to interrupt this process any time before data migration completes)
1027 (it is safe to interrupt this process any time before data migration completes)
1014 migrating 9 total revisions (3 in filelogs, 3 in manifests, 3 in changelog)
1028 migrating 9 total revisions (3 in filelogs, 3 in manifests, 3 in changelog)
1015 migrating 519 KB in store; 1.05 MB tracked data
1029 migrating 519 KB in store; 1.05 MB tracked data
1016 migrating 3 filelogs containing 3 revisions (518 KB in store; 1.05 MB tracked data)
1030 migrating 3 filelogs containing 3 revisions (518 KB in store; 1.05 MB tracked data)
1017 cloning 1 revisions from data/FooBarDirectory.d/f1.i
1031 cloning 1 revisions from data/FooBarDirectory.d/f1.i
1018 cloning 1 revisions from data/f0.i
1032 cloning 1 revisions from data/f0.i
1019 cloning 1 revisions from data/f2.i
1033 cloning 1 revisions from data/f2.i
1020 finished migrating 3 filelog revisions across 3 filelogs; change in size: 0 bytes
1034 finished migrating 3 filelog revisions across 3 filelogs; change in size: 0 bytes
1021 migrating 1 manifests containing 3 revisions (367 bytes in store; 238 bytes tracked data)
1035 migrating 1 manifests containing 3 revisions (367 bytes in store; 238 bytes tracked data)
1022 cloning 3 revisions from 00manifest.i
1036 cloning 3 revisions from 00manifest.i
1023 finished migrating 3 manifest revisions across 1 manifests; change in size: 0 bytes
1037 finished migrating 3 manifest revisions across 1 manifests; change in size: 0 bytes
1024 migrating changelog containing 3 revisions (394 bytes in store; 199 bytes tracked data)
1038 migrating changelog containing 3 revisions (394 bytes in store; 199 bytes tracked data)
1025 cloning 3 revisions from 00changelog.i
1039 cloning 3 revisions from 00changelog.i
1026 finished migrating 3 changelog revisions; change in size: 0 bytes
1040 finished migrating 3 changelog revisions; change in size: 0 bytes
1027 finished migrating 9 total revisions; total change in store size: 0 bytes
1041 finished migrating 9 total revisions; total change in store size: 0 bytes
1028 copying phaseroots
1042 copying phaseroots
1029 data fully upgraded in a temporary repository
1043 data fully upgraded in a temporary repository
1030 marking source repository as being upgraded; clients will be unable to read from repository
1044 marking source repository as being upgraded; clients will be unable to read from repository
1031 starting in-place swap of repository data
1045 starting in-place swap of repository data
1032 replacing store...
1046 replacing store...
1033 store replacement complete; repository was inconsistent for *s (glob)
1047 store replacement complete; repository was inconsistent for *s (glob)
1034 finalizing requirements file and making repository readable again
1048 finalizing requirements file and making repository readable again
1035 removing temporary repository $TESTTMP/upgradegd/.hg/upgrade.* (glob)
1049 removing temporary repository $TESTTMP/upgradegd/.hg/upgrade.* (glob)
1036 $ hg verify
1050 $ hg verify
1037 checking changesets
1051 checking changesets
1038 checking manifests
1052 checking manifests
1039 crosschecking files in changesets and manifests
1053 crosschecking files in changesets and manifests
1040 checking files
1054 checking files
1041 checked 3 changesets with 3 changes to 3 files
1055 checked 3 changesets with 3 changes to 3 files
1042
1056
1043 $ cd ..
1057 $ cd ..
1044
1058
1045 store files with special filenames aren't encoded during copy
1059 store files with special filenames aren't encoded during copy
1046
1060
1047 $ hg init store-filenames
1061 $ hg init store-filenames
1048 $ cd store-filenames
1062 $ cd store-filenames
1049 $ touch foo
1063 $ touch foo
1050 $ hg -q commit -A -m initial
1064 $ hg -q commit -A -m initial
1051 $ touch .hg/store/.XX_special_filename
1065 $ touch .hg/store/.XX_special_filename
1052
1066
1053 $ hg debugupgraderepo --run
1067 $ hg debugupgraderepo --run
1054 nothing to do
1068 nothing to do
1055 $ hg debugupgraderepo --run --optimize 're-delta-fulladd'
1069 $ hg debugupgraderepo --run --optimize 're-delta-fulladd'
1056 upgrade will perform the following actions:
1070 upgrade will perform the following actions:
1057
1071
1058 requirements
1072 requirements
1059 preserved: dotencode, fncache, generaldelta, revlogv1, sparserevlog, store (no-rust !)
1073 preserved: dotencode, fncache, generaldelta, revlogv1, sparserevlog, store (no-rust !)
1060 preserved: dotencode, fncache, generaldelta, persistent-nodemap, revlogv1, sparserevlog, store (rust !)
1074 preserved: dotencode, fncache, generaldelta, persistent-nodemap, revlogv1, sparserevlog, store (rust !)
1061
1075
1062 optimisations: re-delta-fulladd
1076 optimisations: re-delta-fulladd
1063
1077
1064 re-delta-fulladd
1078 re-delta-fulladd
1065 each revision will be added as new content to the internal storage; this will likely drastically slow down execution time, but some extensions might need it
1079 each revision will be added as new content to the internal storage; this will likely drastically slow down execution time, but some extensions might need it
1066
1080
1067 processed revlogs:
1081 processed revlogs:
1068 - all-filelogs
1082 - all-filelogs
1069 - changelog
1083 - changelog
1070 - manifest
1084 - manifest
1071
1085
1072 beginning upgrade...
1086 beginning upgrade...
1073 repository locked and read-only
1087 repository locked and read-only
1074 creating temporary repository to stage upgraded data: $TESTTMP/store-filenames/.hg/upgrade.* (glob)
1088 creating temporary repository to stage upgraded data: $TESTTMP/store-filenames/.hg/upgrade.* (glob)
1075 (it is safe to interrupt this process any time before data migration completes)
1089 (it is safe to interrupt this process any time before data migration completes)
1076 migrating 3 total revisions (1 in filelogs, 1 in manifests, 1 in changelog)
1090 migrating 3 total revisions (1 in filelogs, 1 in manifests, 1 in changelog)
1077 migrating 301 bytes in store; 107 bytes tracked data
1091 migrating 301 bytes in store; 107 bytes tracked data
1078 migrating 1 filelogs containing 1 revisions (64 bytes in store; 0 bytes tracked data)
1092 migrating 1 filelogs containing 1 revisions (64 bytes in store; 0 bytes tracked data)
1079 finished migrating 1 filelog revisions across 1 filelogs; change in size: 0 bytes
1093 finished migrating 1 filelog revisions across 1 filelogs; change in size: 0 bytes
1080 migrating 1 manifests containing 1 revisions (110 bytes in store; 45 bytes tracked data)
1094 migrating 1 manifests containing 1 revisions (110 bytes in store; 45 bytes tracked data)
1081 finished migrating 1 manifest revisions across 1 manifests; change in size: 0 bytes
1095 finished migrating 1 manifest revisions across 1 manifests; change in size: 0 bytes
1082 migrating changelog containing 1 revisions (127 bytes in store; 62 bytes tracked data)
1096 migrating changelog containing 1 revisions (127 bytes in store; 62 bytes tracked data)
1083 finished migrating 1 changelog revisions; change in size: 0 bytes
1097 finished migrating 1 changelog revisions; change in size: 0 bytes
1084 finished migrating 3 total revisions; total change in store size: 0 bytes
1098 finished migrating 3 total revisions; total change in store size: 0 bytes
1085 copying .XX_special_filename
1099 copying .XX_special_filename
1086 copying phaseroots
1100 copying phaseroots
1087 data fully upgraded in a temporary repository
1101 data fully upgraded in a temporary repository
1088 marking source repository as being upgraded; clients will be unable to read from repository
1102 marking source repository as being upgraded; clients will be unable to read from repository
1089 starting in-place swap of repository data
1103 starting in-place swap of repository data
1090 replaced files will be backed up at $TESTTMP/store-filenames/.hg/upgradebackup.* (glob)
1104 replaced files will be backed up at $TESTTMP/store-filenames/.hg/upgradebackup.* (glob)
1091 replacing store...
1105 replacing store...
1092 store replacement complete; repository was inconsistent for *s (glob)
1106 store replacement complete; repository was inconsistent for *s (glob)
1093 finalizing requirements file and making repository readable again
1107 finalizing requirements file and making repository readable again
1094 removing temporary repository $TESTTMP/store-filenames/.hg/upgrade.* (glob)
1108 removing temporary repository $TESTTMP/store-filenames/.hg/upgrade.* (glob)
1095 copy of old repository backed up at $TESTTMP/store-filenames/.hg/upgradebackup.* (glob)
1109 copy of old repository backed up at $TESTTMP/store-filenames/.hg/upgradebackup.* (glob)
1096 the old repository will not be deleted; remove it to free up disk space once the upgraded repository is verified
1110 the old repository will not be deleted; remove it to free up disk space once the upgraded repository is verified
1097
1111
1098 fncache is valid after upgrade
1112 fncache is valid after upgrade
1099
1113
1100 $ hg debugrebuildfncache
1114 $ hg debugrebuildfncache
1101 fncache already up to date
1115 fncache already up to date
1102
1116
1103 $ cd ..
1117 $ cd ..
1104
1118
1105 Check upgrading a large file repository
1119 Check upgrading a large file repository
1106 ---------------------------------------
1120 ---------------------------------------
1107
1121
1108 $ hg init largefilesrepo
1122 $ hg init largefilesrepo
1109 $ cat << EOF >> largefilesrepo/.hg/hgrc
1123 $ cat << EOF >> largefilesrepo/.hg/hgrc
1110 > [extensions]
1124 > [extensions]
1111 > largefiles =
1125 > largefiles =
1112 > EOF
1126 > EOF
1113
1127
1114 $ cd largefilesrepo
1128 $ cd largefilesrepo
1115 $ touch foo
1129 $ touch foo
1116 $ hg add --large foo
1130 $ hg add --large foo
1117 $ hg -q commit -m initial
1131 $ hg -q commit -m initial
1118 $ cat .hg/requires
1132 $ cat .hg/requires
1119 dotencode
1133 dotencode
1120 fncache
1134 fncache
1121 generaldelta
1135 generaldelta
1122 largefiles
1136 largefiles
1123 persistent-nodemap (rust !)
1137 persistent-nodemap (rust !)
1124 revlogv1
1138 revlogv1
1125 sparserevlog
1139 sparserevlog
1126 store
1140 store
1127
1141
1128 $ hg debugupgraderepo --run
1142 $ hg debugupgraderepo --run
1129 nothing to do
1143 nothing to do
1130 $ cat .hg/requires
1144 $ cat .hg/requires
1131 dotencode
1145 dotencode
1132 fncache
1146 fncache
1133 generaldelta
1147 generaldelta
1134 largefiles
1148 largefiles
1135 persistent-nodemap (rust !)
1149 persistent-nodemap (rust !)
1136 revlogv1
1150 revlogv1
1137 sparserevlog
1151 sparserevlog
1138 store
1152 store
1139
1153
1140 $ cat << EOF >> .hg/hgrc
1154 $ cat << EOF >> .hg/hgrc
1141 > [extensions]
1155 > [extensions]
1142 > lfs =
1156 > lfs =
1143 > [lfs]
1157 > [lfs]
1144 > threshold = 10
1158 > threshold = 10
1145 > EOF
1159 > EOF
1146 $ echo '123456789012345' > lfs.bin
1160 $ echo '123456789012345' > lfs.bin
1147 $ hg ci -Am 'lfs.bin'
1161 $ hg ci -Am 'lfs.bin'
1148 adding lfs.bin
1162 adding lfs.bin
1149 $ grep lfs .hg/requires
1163 $ grep lfs .hg/requires
1150 lfs
1164 lfs
1151 $ find .hg/store/lfs -type f
1165 $ find .hg/store/lfs -type f
1152 .hg/store/lfs/objects/d0/beab232adff5ba365880366ad30b1edb85c4c5372442b5d2fe27adc96d653f
1166 .hg/store/lfs/objects/d0/beab232adff5ba365880366ad30b1edb85c4c5372442b5d2fe27adc96d653f
1153
1167
1154 $ hg debugupgraderepo --run
1168 $ hg debugupgraderepo --run
1155 nothing to do
1169 nothing to do
1156
1170
1157 $ grep lfs .hg/requires
1171 $ grep lfs .hg/requires
1158 lfs
1172 lfs
1159 $ find .hg/store/lfs -type f
1173 $ find .hg/store/lfs -type f
1160 .hg/store/lfs/objects/d0/beab232adff5ba365880366ad30b1edb85c4c5372442b5d2fe27adc96d653f
1174 .hg/store/lfs/objects/d0/beab232adff5ba365880366ad30b1edb85c4c5372442b5d2fe27adc96d653f
1161 $ hg verify
1175 $ hg verify
1162 checking changesets
1176 checking changesets
1163 checking manifests
1177 checking manifests
1164 crosschecking files in changesets and manifests
1178 crosschecking files in changesets and manifests
1165 checking files
1179 checking files
1166 checked 2 changesets with 2 changes to 2 files
1180 checked 2 changesets with 2 changes to 2 files
1167 $ hg debugdata lfs.bin 0
1181 $ hg debugdata lfs.bin 0
1168 version https://git-lfs.github.com/spec/v1
1182 version https://git-lfs.github.com/spec/v1
1169 oid sha256:d0beab232adff5ba365880366ad30b1edb85c4c5372442b5d2fe27adc96d653f
1183 oid sha256:d0beab232adff5ba365880366ad30b1edb85c4c5372442b5d2fe27adc96d653f
1170 size 16
1184 size 16
1171 x-is-binary 0
1185 x-is-binary 0
1172
1186
1173 $ cd ..
1187 $ cd ..
1174
1188
1175 repository config is taken in account
1189 repository config is taken in account
1176 -------------------------------------
1190 -------------------------------------
1177
1191
1178 $ cat << EOF >> $HGRCPATH
1192 $ cat << EOF >> $HGRCPATH
1179 > [format]
1193 > [format]
1180 > maxchainlen = 1
1194 > maxchainlen = 1
1181 > EOF
1195 > EOF
1182
1196
1183 $ hg init localconfig
1197 $ hg init localconfig
1184 $ cd localconfig
1198 $ cd localconfig
1185 $ cat << EOF > file
1199 $ cat << EOF > file
1186 > some content
1200 > some content
1187 > with some length
1201 > with some length
1188 > to make sure we get a delta
1202 > to make sure we get a delta
1189 > after changes
1203 > after changes
1190 > very long
1204 > very long
1191 > very long
1205 > very long
1192 > very long
1206 > very long
1193 > very long
1207 > very long
1194 > very long
1208 > very long
1195 > very long
1209 > very long
1196 > very long
1210 > very long
1197 > very long
1211 > very long
1198 > very long
1212 > very long
1199 > very long
1213 > very long
1200 > very long
1214 > very long
1201 > EOF
1215 > EOF
1202 $ hg -q commit -A -m A
1216 $ hg -q commit -A -m A
1203 $ echo "new line" >> file
1217 $ echo "new line" >> file
1204 $ hg -q commit -m B
1218 $ hg -q commit -m B
1205 $ echo "new line" >> file
1219 $ echo "new line" >> file
1206 $ hg -q commit -m C
1220 $ hg -q commit -m C
1207
1221
1208 $ cat << EOF >> .hg/hgrc
1222 $ cat << EOF >> .hg/hgrc
1209 > [format]
1223 > [format]
1210 > maxchainlen = 9001
1224 > maxchainlen = 9001
1211 > EOF
1225 > EOF
1212 $ hg config format
1226 $ hg config format
1213 format.revlog-compression=$BUNDLE2_COMPRESSIONS$
1227 format.revlog-compression=$BUNDLE2_COMPRESSIONS$
1214 format.maxchainlen=9001
1228 format.maxchainlen=9001
1215 $ hg debugdeltachain file
1229 $ hg debugdeltachain file
1216 rev chain# chainlen prev delta size rawsize chainsize ratio lindist extradist extraratio readsize largestblk rddensity srchunks
1230 rev chain# chainlen prev delta size rawsize chainsize ratio lindist extradist extraratio readsize largestblk rddensity srchunks
1217 0 1 1 -1 base 77 182 77 0.42308 77 0 0.00000 77 77 1.00000 1
1231 0 1 1 -1 base 77 182 77 0.42308 77 0 0.00000 77 77 1.00000 1
1218 1 1 2 0 p1 21 191 98 0.51309 98 0 0.00000 98 98 1.00000 1
1232 1 1 2 0 p1 21 191 98 0.51309 98 0 0.00000 98 98 1.00000 1
1219 2 1 2 0 other 30 200 107 0.53500 128 21 0.19626 128 128 0.83594 1
1233 2 1 2 0 other 30 200 107 0.53500 128 21 0.19626 128 128 0.83594 1
1220
1234
1221 $ hg debugupgraderepo --run --optimize 're-delta-all'
1235 $ hg debugupgraderepo --run --optimize 're-delta-all'
1222 upgrade will perform the following actions:
1236 upgrade will perform the following actions:
1223
1237
1224 requirements
1238 requirements
1225 preserved: dotencode, fncache, generaldelta, revlogv1, sparserevlog, store (no-rust !)
1239 preserved: dotencode, fncache, generaldelta, revlogv1, sparserevlog, store (no-rust !)
1226 preserved: dotencode, fncache, generaldelta, persistent-nodemap, revlogv1, sparserevlog, store (rust !)
1240 preserved: dotencode, fncache, generaldelta, persistent-nodemap, revlogv1, sparserevlog, store (rust !)
1227
1241
1228 optimisations: re-delta-all
1242 optimisations: re-delta-all
1229
1243
1230 re-delta-all
1244 re-delta-all
1231 deltas within internal storage will be fully recomputed; this will likely drastically slow down execution time
1245 deltas within internal storage will be fully recomputed; this will likely drastically slow down execution time
1232
1246
1233 processed revlogs:
1247 processed revlogs:
1234 - all-filelogs
1248 - all-filelogs
1235 - changelog
1249 - changelog
1236 - manifest
1250 - manifest
1237
1251
1238 beginning upgrade...
1252 beginning upgrade...
1239 repository locked and read-only
1253 repository locked and read-only
1240 creating temporary repository to stage upgraded data: $TESTTMP/localconfig/.hg/upgrade.* (glob)
1254 creating temporary repository to stage upgraded data: $TESTTMP/localconfig/.hg/upgrade.* (glob)
1241 (it is safe to interrupt this process any time before data migration completes)
1255 (it is safe to interrupt this process any time before data migration completes)
1242 migrating 9 total revisions (3 in filelogs, 3 in manifests, 3 in changelog)
1256 migrating 9 total revisions (3 in filelogs, 3 in manifests, 3 in changelog)
1243 migrating 1019 bytes in store; 882 bytes tracked data
1257 migrating 1019 bytes in store; 882 bytes tracked data
1244 migrating 1 filelogs containing 3 revisions (320 bytes in store; 573 bytes tracked data)
1258 migrating 1 filelogs containing 3 revisions (320 bytes in store; 573 bytes tracked data)
1245 finished migrating 3 filelog revisions across 1 filelogs; change in size: -9 bytes
1259 finished migrating 3 filelog revisions across 1 filelogs; change in size: -9 bytes
1246 migrating 1 manifests containing 3 revisions (333 bytes in store; 138 bytes tracked data)
1260 migrating 1 manifests containing 3 revisions (333 bytes in store; 138 bytes tracked data)
1247 finished migrating 3 manifest revisions across 1 manifests; change in size: 0 bytes
1261 finished migrating 3 manifest revisions across 1 manifests; change in size: 0 bytes
1248 migrating changelog containing 3 revisions (366 bytes in store; 171 bytes tracked data)
1262 migrating changelog containing 3 revisions (366 bytes in store; 171 bytes tracked data)
1249 finished migrating 3 changelog revisions; change in size: 0 bytes
1263 finished migrating 3 changelog revisions; change in size: 0 bytes
1250 finished migrating 9 total revisions; total change in store size: -9 bytes
1264 finished migrating 9 total revisions; total change in store size: -9 bytes
1251 copying phaseroots
1265 copying phaseroots
1252 data fully upgraded in a temporary repository
1266 data fully upgraded in a temporary repository
1253 marking source repository as being upgraded; clients will be unable to read from repository
1267 marking source repository as being upgraded; clients will be unable to read from repository
1254 starting in-place swap of repository data
1268 starting in-place swap of repository data
1255 replaced files will be backed up at $TESTTMP/localconfig/.hg/upgradebackup.* (glob)
1269 replaced files will be backed up at $TESTTMP/localconfig/.hg/upgradebackup.* (glob)
1256 replacing store...
1270 replacing store...
1257 store replacement complete; repository was inconsistent for *s (glob)
1271 store replacement complete; repository was inconsistent for *s (glob)
1258 finalizing requirements file and making repository readable again
1272 finalizing requirements file and making repository readable again
1259 removing temporary repository $TESTTMP/localconfig/.hg/upgrade.* (glob)
1273 removing temporary repository $TESTTMP/localconfig/.hg/upgrade.* (glob)
1260 copy of old repository backed up at $TESTTMP/localconfig/.hg/upgradebackup.* (glob)
1274 copy of old repository backed up at $TESTTMP/localconfig/.hg/upgradebackup.* (glob)
1261 the old repository will not be deleted; remove it to free up disk space once the upgraded repository is verified
1275 the old repository will not be deleted; remove it to free up disk space once the upgraded repository is verified
1262 $ hg debugdeltachain file
1276 $ hg debugdeltachain file
1263 rev chain# chainlen prev delta size rawsize chainsize ratio lindist extradist extraratio readsize largestblk rddensity srchunks
1277 rev chain# chainlen prev delta size rawsize chainsize ratio lindist extradist extraratio readsize largestblk rddensity srchunks
1264 0 1 1 -1 base 77 182 77 0.42308 77 0 0.00000 77 77 1.00000 1
1278 0 1 1 -1 base 77 182 77 0.42308 77 0 0.00000 77 77 1.00000 1
1265 1 1 2 0 p1 21 191 98 0.51309 98 0 0.00000 98 98 1.00000 1
1279 1 1 2 0 p1 21 191 98 0.51309 98 0 0.00000 98 98 1.00000 1
1266 2 1 3 1 p1 21 200 119 0.59500 119 0 0.00000 119 119 1.00000 1
1280 2 1 3 1 p1 21 200 119 0.59500 119 0 0.00000 119 119 1.00000 1
1267 $ cd ..
1281 $ cd ..
1268
1282
1269 $ cat << EOF >> $HGRCPATH
1283 $ cat << EOF >> $HGRCPATH
1270 > [format]
1284 > [format]
1271 > maxchainlen = 9001
1285 > maxchainlen = 9001
1272 > EOF
1286 > EOF
1273
1287
1274 Check upgrading a sparse-revlog repository
1288 Check upgrading a sparse-revlog repository
1275 ---------------------------------------
1289 ---------------------------------------
1276
1290
1277 $ hg init sparserevlogrepo --config format.sparse-revlog=no
1291 $ hg init sparserevlogrepo --config format.sparse-revlog=no
1278 $ cd sparserevlogrepo
1292 $ cd sparserevlogrepo
1279 $ touch foo
1293 $ touch foo
1280 $ hg add foo
1294 $ hg add foo
1281 $ hg -q commit -m "foo"
1295 $ hg -q commit -m "foo"
1282 $ cat .hg/requires
1296 $ cat .hg/requires
1283 dotencode
1297 dotencode
1284 fncache
1298 fncache
1285 generaldelta
1299 generaldelta
1286 persistent-nodemap (rust !)
1300 persistent-nodemap (rust !)
1287 revlogv1
1301 revlogv1
1288 store
1302 store
1289
1303
1290 Check that we can add the sparse-revlog format requirement
1304 Check that we can add the sparse-revlog format requirement
1291 $ hg --config format.sparse-revlog=yes debugupgraderepo --run --quiet
1305 $ hg --config format.sparse-revlog=yes debugupgraderepo --run --quiet
1292 upgrade will perform the following actions:
1306 upgrade will perform the following actions:
1293
1307
1294 requirements
1308 requirements
1295 preserved: dotencode, fncache, generaldelta, revlogv1, store (no-rust !)
1309 preserved: dotencode, fncache, generaldelta, revlogv1, store (no-rust !)
1296 preserved: dotencode, fncache, generaldelta, persistent-nodemap, revlogv1, store (rust !)
1310 preserved: dotencode, fncache, generaldelta, persistent-nodemap, revlogv1, store (rust !)
1297 added: sparserevlog
1311 added: sparserevlog
1298
1312
1299 processed revlogs:
1313 processed revlogs:
1300 - all-filelogs
1314 - all-filelogs
1301 - changelog
1315 - changelog
1302 - manifest
1316 - manifest
1303
1317
1304 $ cat .hg/requires
1318 $ cat .hg/requires
1305 dotencode
1319 dotencode
1306 fncache
1320 fncache
1307 generaldelta
1321 generaldelta
1308 persistent-nodemap (rust !)
1322 persistent-nodemap (rust !)
1309 revlogv1
1323 revlogv1
1310 sparserevlog
1324 sparserevlog
1311 store
1325 store
1312
1326
1313 Check that we can remove the sparse-revlog format requirement
1327 Check that we can remove the sparse-revlog format requirement
1314 $ hg --config format.sparse-revlog=no debugupgraderepo --run --quiet
1328 $ hg --config format.sparse-revlog=no debugupgraderepo --run --quiet
1315 upgrade will perform the following actions:
1329 upgrade will perform the following actions:
1316
1330
1317 requirements
1331 requirements
1318 preserved: dotencode, fncache, generaldelta, revlogv1, store (no-rust !)
1332 preserved: dotencode, fncache, generaldelta, revlogv1, store (no-rust !)
1319 preserved: dotencode, fncache, generaldelta, persistent-nodemap, revlogv1, store (rust !)
1333 preserved: dotencode, fncache, generaldelta, persistent-nodemap, revlogv1, store (rust !)
1320 removed: sparserevlog
1334 removed: sparserevlog
1321
1335
1322 processed revlogs:
1336 processed revlogs:
1323 - all-filelogs
1337 - all-filelogs
1324 - changelog
1338 - changelog
1325 - manifest
1339 - manifest
1326
1340
1327 $ cat .hg/requires
1341 $ cat .hg/requires
1328 dotencode
1342 dotencode
1329 fncache
1343 fncache
1330 generaldelta
1344 generaldelta
1331 persistent-nodemap (rust !)
1345 persistent-nodemap (rust !)
1332 revlogv1
1346 revlogv1
1333 store
1347 store
1334
1348
1335 #if zstd
1349 #if zstd
1336
1350
1337 Check upgrading to a zstd revlog
1351 Check upgrading to a zstd revlog
1338 --------------------------------
1352 --------------------------------
1339
1353
1340 upgrade
1354 upgrade
1341
1355
1342 $ hg --config format.revlog-compression=zstd debugupgraderepo --run --no-backup --quiet
1356 $ hg --config format.revlog-compression=zstd debugupgraderepo --run --no-backup --quiet
1343 upgrade will perform the following actions:
1357 upgrade will perform the following actions:
1344
1358
1345 requirements
1359 requirements
1346 preserved: dotencode, fncache, generaldelta, revlogv1, store (no-rust !)
1360 preserved: dotencode, fncache, generaldelta, revlogv1, store (no-rust !)
1347 preserved: dotencode, fncache, generaldelta, persistent-nodemap, revlogv1, store (rust !)
1361 preserved: dotencode, fncache, generaldelta, persistent-nodemap, revlogv1, store (rust !)
1348 added: revlog-compression-zstd, sparserevlog
1362 added: revlog-compression-zstd, sparserevlog
1349
1363
1350 processed revlogs:
1364 processed revlogs:
1351 - all-filelogs
1365 - all-filelogs
1352 - changelog
1366 - changelog
1353 - manifest
1367 - manifest
1354
1368
1355 $ hg debugformat -v
1369 $ hg debugformat -v
1356 format-variant repo config default
1370 format-variant repo config default
1357 fncache: yes yes yes
1371 fncache: yes yes yes
1372 dirstate-v2: no no no
1358 dotencode: yes yes yes
1373 dotencode: yes yes yes
1359 generaldelta: yes yes yes
1374 generaldelta: yes yes yes
1360 share-safe: no no no
1375 share-safe: no no no
1361 sparserevlog: yes yes yes
1376 sparserevlog: yes yes yes
1362 persistent-nodemap: no no no (no-rust !)
1377 persistent-nodemap: no no no (no-rust !)
1363 persistent-nodemap: yes yes no (rust !)
1378 persistent-nodemap: yes yes no (rust !)
1364 copies-sdc: no no no
1379 copies-sdc: no no no
1365 revlog-v2: no no no
1380 revlog-v2: no no no
1366 changelog-v2: no no no
1381 changelog-v2: no no no
1367 plain-cl-delta: yes yes yes
1382 plain-cl-delta: yes yes yes
1368 compression: zlib zlib zlib (no-zstd !)
1383 compression: zlib zlib zlib (no-zstd !)
1369 compression: zstd zlib zstd (zstd !)
1384 compression: zstd zlib zstd (zstd !)
1370 compression-level: default default default
1385 compression-level: default default default
1371 $ cat .hg/requires
1386 $ cat .hg/requires
1372 dotencode
1387 dotencode
1373 fncache
1388 fncache
1374 generaldelta
1389 generaldelta
1375 persistent-nodemap (rust !)
1390 persistent-nodemap (rust !)
1376 revlog-compression-zstd
1391 revlog-compression-zstd
1377 revlogv1
1392 revlogv1
1378 sparserevlog
1393 sparserevlog
1379 store
1394 store
1380
1395
1381 downgrade
1396 downgrade
1382
1397
1383 $ hg debugupgraderepo --run --no-backup --quiet
1398 $ hg debugupgraderepo --run --no-backup --quiet
1384 upgrade will perform the following actions:
1399 upgrade will perform the following actions:
1385
1400
1386 requirements
1401 requirements
1387 preserved: dotencode, fncache, generaldelta, revlogv1, sparserevlog, store (no-rust !)
1402 preserved: dotencode, fncache, generaldelta, revlogv1, sparserevlog, store (no-rust !)
1388 preserved: dotencode, fncache, generaldelta, persistent-nodemap, revlogv1, sparserevlog, store (rust !)
1403 preserved: dotencode, fncache, generaldelta, persistent-nodemap, revlogv1, sparserevlog, store (rust !)
1389 removed: revlog-compression-zstd
1404 removed: revlog-compression-zstd
1390
1405
1391 processed revlogs:
1406 processed revlogs:
1392 - all-filelogs
1407 - all-filelogs
1393 - changelog
1408 - changelog
1394 - manifest
1409 - manifest
1395
1410
1396 $ hg debugformat -v
1411 $ hg debugformat -v
1397 format-variant repo config default
1412 format-variant repo config default
1398 fncache: yes yes yes
1413 fncache: yes yes yes
1414 dirstate-v2: no no no
1399 dotencode: yes yes yes
1415 dotencode: yes yes yes
1400 generaldelta: yes yes yes
1416 generaldelta: yes yes yes
1401 share-safe: no no no
1417 share-safe: no no no
1402 sparserevlog: yes yes yes
1418 sparserevlog: yes yes yes
1403 persistent-nodemap: no no no (no-rust !)
1419 persistent-nodemap: no no no (no-rust !)
1404 persistent-nodemap: yes yes no (rust !)
1420 persistent-nodemap: yes yes no (rust !)
1405 copies-sdc: no no no
1421 copies-sdc: no no no
1406 revlog-v2: no no no
1422 revlog-v2: no no no
1407 changelog-v2: no no no
1423 changelog-v2: no no no
1408 plain-cl-delta: yes yes yes
1424 plain-cl-delta: yes yes yes
1409 compression: zlib zlib zlib (no-zstd !)
1425 compression: zlib zlib zlib (no-zstd !)
1410 compression: zlib zlib zstd (zstd !)
1426 compression: zlib zlib zstd (zstd !)
1411 compression-level: default default default
1427 compression-level: default default default
1412 $ cat .hg/requires
1428 $ cat .hg/requires
1413 dotencode
1429 dotencode
1414 fncache
1430 fncache
1415 generaldelta
1431 generaldelta
1416 persistent-nodemap (rust !)
1432 persistent-nodemap (rust !)
1417 revlogv1
1433 revlogv1
1418 sparserevlog
1434 sparserevlog
1419 store
1435 store
1420
1436
1421 upgrade from hgrc
1437 upgrade from hgrc
1422
1438
1423 $ cat >> .hg/hgrc << EOF
1439 $ cat >> .hg/hgrc << EOF
1424 > [format]
1440 > [format]
1425 > revlog-compression=zstd
1441 > revlog-compression=zstd
1426 > EOF
1442 > EOF
1427 $ hg debugupgraderepo --run --no-backup --quiet
1443 $ hg debugupgraderepo --run --no-backup --quiet
1428 upgrade will perform the following actions:
1444 upgrade will perform the following actions:
1429
1445
1430 requirements
1446 requirements
1431 preserved: dotencode, fncache, generaldelta, revlogv1, sparserevlog, store (no-rust !)
1447 preserved: dotencode, fncache, generaldelta, revlogv1, sparserevlog, store (no-rust !)
1432 preserved: dotencode, fncache, generaldelta, persistent-nodemap, revlogv1, sparserevlog, store (rust !)
1448 preserved: dotencode, fncache, generaldelta, persistent-nodemap, revlogv1, sparserevlog, store (rust !)
1433 added: revlog-compression-zstd
1449 added: revlog-compression-zstd
1434
1450
1435 processed revlogs:
1451 processed revlogs:
1436 - all-filelogs
1452 - all-filelogs
1437 - changelog
1453 - changelog
1438 - manifest
1454 - manifest
1439
1455
1440 $ hg debugformat -v
1456 $ hg debugformat -v
1441 format-variant repo config default
1457 format-variant repo config default
1442 fncache: yes yes yes
1458 fncache: yes yes yes
1459 dirstate-v2: no no no
1443 dotencode: yes yes yes
1460 dotencode: yes yes yes
1444 generaldelta: yes yes yes
1461 generaldelta: yes yes yes
1445 share-safe: no no no
1462 share-safe: no no no
1446 sparserevlog: yes yes yes
1463 sparserevlog: yes yes yes
1447 persistent-nodemap: no no no (no-rust !)
1464 persistent-nodemap: no no no (no-rust !)
1448 persistent-nodemap: yes yes no (rust !)
1465 persistent-nodemap: yes yes no (rust !)
1449 copies-sdc: no no no
1466 copies-sdc: no no no
1450 revlog-v2: no no no
1467 revlog-v2: no no no
1451 changelog-v2: no no no
1468 changelog-v2: no no no
1452 plain-cl-delta: yes yes yes
1469 plain-cl-delta: yes yes yes
1453 compression: zlib zlib zlib (no-zstd !)
1470 compression: zlib zlib zlib (no-zstd !)
1454 compression: zstd zstd zstd (zstd !)
1471 compression: zstd zstd zstd (zstd !)
1455 compression-level: default default default
1472 compression-level: default default default
1456 $ cat .hg/requires
1473 $ cat .hg/requires
1457 dotencode
1474 dotencode
1458 fncache
1475 fncache
1459 generaldelta
1476 generaldelta
1460 persistent-nodemap (rust !)
1477 persistent-nodemap (rust !)
1461 revlog-compression-zstd
1478 revlog-compression-zstd
1462 revlogv1
1479 revlogv1
1463 sparserevlog
1480 sparserevlog
1464 store
1481 store
1465
1482
1466 #endif
1483 #endif
1467
1484
1468 Check upgrading to a revlog format supporting sidedata
1485 Check upgrading to a revlog format supporting sidedata
1469 ------------------------------------------------------
1486 ------------------------------------------------------
1470
1487
1471 upgrade
1488 upgrade
1472
1489
1473 $ hg debugsidedata -c 0
1490 $ hg debugsidedata -c 0
1474 $ hg --config experimental.revlogv2=enable-unstable-format-and-corrupt-my-data debugupgraderepo --run --no-backup --config "extensions.sidedata=$TESTDIR/testlib/ext-sidedata.py" --quiet
1491 $ hg --config experimental.revlogv2=enable-unstable-format-and-corrupt-my-data debugupgraderepo --run --no-backup --config "extensions.sidedata=$TESTDIR/testlib/ext-sidedata.py" --quiet
1475 upgrade will perform the following actions:
1492 upgrade will perform the following actions:
1476
1493
1477 requirements
1494 requirements
1478 preserved: dotencode, fncache, generaldelta, store (no-zstd !)
1495 preserved: dotencode, fncache, generaldelta, store (no-zstd !)
1479 preserved: dotencode, fncache, generaldelta, revlog-compression-zstd, sparserevlog, store (zstd no-rust !)
1496 preserved: dotencode, fncache, generaldelta, revlog-compression-zstd, sparserevlog, store (zstd no-rust !)
1480 preserved: dotencode, fncache, generaldelta, persistent-nodemap, revlog-compression-zstd, sparserevlog, store (rust !)
1497 preserved: dotencode, fncache, generaldelta, persistent-nodemap, revlog-compression-zstd, sparserevlog, store (rust !)
1481 removed: revlogv1
1498 removed: revlogv1
1482 added: exp-revlogv2.2 (zstd !)
1499 added: exp-revlogv2.2 (zstd !)
1483 added: exp-revlogv2.2, sparserevlog (no-zstd !)
1500 added: exp-revlogv2.2, sparserevlog (no-zstd !)
1484
1501
1485 processed revlogs:
1502 processed revlogs:
1486 - all-filelogs
1503 - all-filelogs
1487 - changelog
1504 - changelog
1488 - manifest
1505 - manifest
1489
1506
1490 $ hg debugformat -v
1507 $ hg debugformat -v
1491 format-variant repo config default
1508 format-variant repo config default
1492 fncache: yes yes yes
1509 fncache: yes yes yes
1510 dirstate-v2: no no no
1493 dotencode: yes yes yes
1511 dotencode: yes yes yes
1494 generaldelta: yes yes yes
1512 generaldelta: yes yes yes
1495 share-safe: no no no
1513 share-safe: no no no
1496 sparserevlog: yes yes yes
1514 sparserevlog: yes yes yes
1497 persistent-nodemap: no no no (no-rust !)
1515 persistent-nodemap: no no no (no-rust !)
1498 persistent-nodemap: yes yes no (rust !)
1516 persistent-nodemap: yes yes no (rust !)
1499 copies-sdc: no no no
1517 copies-sdc: no no no
1500 revlog-v2: yes no no
1518 revlog-v2: yes no no
1501 changelog-v2: no no no
1519 changelog-v2: no no no
1502 plain-cl-delta: yes yes yes
1520 plain-cl-delta: yes yes yes
1503 compression: zlib zlib zlib (no-zstd !)
1521 compression: zlib zlib zlib (no-zstd !)
1504 compression: zstd zstd zstd (zstd !)
1522 compression: zstd zstd zstd (zstd !)
1505 compression-level: default default default
1523 compression-level: default default default
1506 $ cat .hg/requires
1524 $ cat .hg/requires
1507 dotencode
1525 dotencode
1508 exp-revlogv2.2
1526 exp-revlogv2.2
1509 fncache
1527 fncache
1510 generaldelta
1528 generaldelta
1511 persistent-nodemap (rust !)
1529 persistent-nodemap (rust !)
1512 revlog-compression-zstd (zstd !)
1530 revlog-compression-zstd (zstd !)
1513 sparserevlog
1531 sparserevlog
1514 store
1532 store
1515 $ hg debugsidedata -c 0
1533 $ hg debugsidedata -c 0
1516 2 sidedata entries
1534 2 sidedata entries
1517 entry-0001 size 4
1535 entry-0001 size 4
1518 entry-0002 size 32
1536 entry-0002 size 32
1519
1537
1520 downgrade
1538 downgrade
1521
1539
1522 $ hg debugupgraderepo --config experimental.revlogv2=no --run --no-backup --quiet
1540 $ hg debugupgraderepo --config experimental.revlogv2=no --run --no-backup --quiet
1523 upgrade will perform the following actions:
1541 upgrade will perform the following actions:
1524
1542
1525 requirements
1543 requirements
1526 preserved: dotencode, fncache, generaldelta, sparserevlog, store (no-zstd !)
1544 preserved: dotencode, fncache, generaldelta, sparserevlog, store (no-zstd !)
1527 preserved: dotencode, fncache, generaldelta, revlog-compression-zstd, sparserevlog, store (zstd no-rust !)
1545 preserved: dotencode, fncache, generaldelta, revlog-compression-zstd, sparserevlog, store (zstd no-rust !)
1528 preserved: dotencode, fncache, generaldelta, persistent-nodemap, revlog-compression-zstd, sparserevlog, store (rust !)
1546 preserved: dotencode, fncache, generaldelta, persistent-nodemap, revlog-compression-zstd, sparserevlog, store (rust !)
1529 removed: exp-revlogv2.2
1547 removed: exp-revlogv2.2
1530 added: revlogv1
1548 added: revlogv1
1531
1549
1532 processed revlogs:
1550 processed revlogs:
1533 - all-filelogs
1551 - all-filelogs
1534 - changelog
1552 - changelog
1535 - manifest
1553 - manifest
1536
1554
1537 $ hg debugformat -v
1555 $ hg debugformat -v
1538 format-variant repo config default
1556 format-variant repo config default
1539 fncache: yes yes yes
1557 fncache: yes yes yes
1558 dirstate-v2: no no no
1540 dotencode: yes yes yes
1559 dotencode: yes yes yes
1541 generaldelta: yes yes yes
1560 generaldelta: yes yes yes
1542 share-safe: no no no
1561 share-safe: no no no
1543 sparserevlog: yes yes yes
1562 sparserevlog: yes yes yes
1544 persistent-nodemap: no no no (no-rust !)
1563 persistent-nodemap: no no no (no-rust !)
1545 persistent-nodemap: yes yes no (rust !)
1564 persistent-nodemap: yes yes no (rust !)
1546 copies-sdc: no no no
1565 copies-sdc: no no no
1547 revlog-v2: no no no
1566 revlog-v2: no no no
1548 changelog-v2: no no no
1567 changelog-v2: no no no
1549 plain-cl-delta: yes yes yes
1568 plain-cl-delta: yes yes yes
1550 compression: zlib zlib zlib (no-zstd !)
1569 compression: zlib zlib zlib (no-zstd !)
1551 compression: zstd zstd zstd (zstd !)
1570 compression: zstd zstd zstd (zstd !)
1552 compression-level: default default default
1571 compression-level: default default default
1553 $ cat .hg/requires
1572 $ cat .hg/requires
1554 dotencode
1573 dotencode
1555 fncache
1574 fncache
1556 generaldelta
1575 generaldelta
1557 persistent-nodemap (rust !)
1576 persistent-nodemap (rust !)
1558 revlog-compression-zstd (zstd !)
1577 revlog-compression-zstd (zstd !)
1559 revlogv1
1578 revlogv1
1560 sparserevlog
1579 sparserevlog
1561 store
1580 store
1562 $ hg debugsidedata -c 0
1581 $ hg debugsidedata -c 0
1563
1582
1564 upgrade from hgrc
1583 upgrade from hgrc
1565
1584
1566 $ cat >> .hg/hgrc << EOF
1585 $ cat >> .hg/hgrc << EOF
1567 > [experimental]
1586 > [experimental]
1568 > revlogv2=enable-unstable-format-and-corrupt-my-data
1587 > revlogv2=enable-unstable-format-and-corrupt-my-data
1569 > EOF
1588 > EOF
1570 $ hg debugupgraderepo --run --no-backup --quiet
1589 $ hg debugupgraderepo --run --no-backup --quiet
1571 upgrade will perform the following actions:
1590 upgrade will perform the following actions:
1572
1591
1573 requirements
1592 requirements
1574 preserved: dotencode, fncache, generaldelta, sparserevlog, store (no-zstd !)
1593 preserved: dotencode, fncache, generaldelta, sparserevlog, store (no-zstd !)
1575 preserved: dotencode, fncache, generaldelta, revlog-compression-zstd, sparserevlog, store (zstd no-rust !)
1594 preserved: dotencode, fncache, generaldelta, revlog-compression-zstd, sparserevlog, store (zstd no-rust !)
1576 preserved: dotencode, fncache, generaldelta, persistent-nodemap, revlog-compression-zstd, sparserevlog, store (rust !)
1595 preserved: dotencode, fncache, generaldelta, persistent-nodemap, revlog-compression-zstd, sparserevlog, store (rust !)
1577 removed: revlogv1
1596 removed: revlogv1
1578 added: exp-revlogv2.2
1597 added: exp-revlogv2.2
1579
1598
1580 processed revlogs:
1599 processed revlogs:
1581 - all-filelogs
1600 - all-filelogs
1582 - changelog
1601 - changelog
1583 - manifest
1602 - manifest
1584
1603
1585 $ hg debugformat -v
1604 $ hg debugformat -v
1586 format-variant repo config default
1605 format-variant repo config default
1587 fncache: yes yes yes
1606 fncache: yes yes yes
1607 dirstate-v2: no no no
1588 dotencode: yes yes yes
1608 dotencode: yes yes yes
1589 generaldelta: yes yes yes
1609 generaldelta: yes yes yes
1590 share-safe: no no no
1610 share-safe: no no no
1591 sparserevlog: yes yes yes
1611 sparserevlog: yes yes yes
1592 persistent-nodemap: no no no (no-rust !)
1612 persistent-nodemap: no no no (no-rust !)
1593 persistent-nodemap: yes yes no (rust !)
1613 persistent-nodemap: yes yes no (rust !)
1594 copies-sdc: no no no
1614 copies-sdc: no no no
1595 revlog-v2: yes yes no
1615 revlog-v2: yes yes no
1596 changelog-v2: no no no
1616 changelog-v2: no no no
1597 plain-cl-delta: yes yes yes
1617 plain-cl-delta: yes yes yes
1598 compression: zlib zlib zlib (no-zstd !)
1618 compression: zlib zlib zlib (no-zstd !)
1599 compression: zstd zstd zstd (zstd !)
1619 compression: zstd zstd zstd (zstd !)
1600 compression-level: default default default
1620 compression-level: default default default
1601 $ cat .hg/requires
1621 $ cat .hg/requires
1602 dotencode
1622 dotencode
1603 exp-revlogv2.2
1623 exp-revlogv2.2
1604 fncache
1624 fncache
1605 generaldelta
1625 generaldelta
1606 persistent-nodemap (rust !)
1626 persistent-nodemap (rust !)
1607 revlog-compression-zstd (zstd !)
1627 revlog-compression-zstd (zstd !)
1608 sparserevlog
1628 sparserevlog
1609 store
1629 store
1610 $ hg debugsidedata -c 0
1630 $ hg debugsidedata -c 0
1611
1631
1612 Demonstrate that nothing to perform upgrade will still run all the way through
1632 Demonstrate that nothing to perform upgrade will still run all the way through
1613
1633
1614 $ hg debugupgraderepo --run
1634 $ hg debugupgraderepo --run
1615 nothing to do
1635 nothing to do
1636
1637 #if rust
1638
1639 Upgrade to dirstate-v2
1640
1641 $ hg debugformat -v --config format.exp-dirstate-v2=1
1642 format-variant repo config default
1643 fncache: yes yes yes
1644 dirstate-v2: no yes no
1645 dotencode: yes yes yes
1646 generaldelta: yes yes yes
1647 share-safe: no no no
1648 sparserevlog: yes yes yes
1649 persistent-nodemap: yes yes no
1650 copies-sdc: no no no
1651 revlog-v2: yes yes no
1652 changelog-v2: no no no
1653 plain-cl-delta: yes yes yes
1654 compression: zstd zstd zstd
1655 compression-level: default default default
1656 $ hg debugupgraderepo --config format.exp-dirstate-v2=1 --run
1657 upgrade will perform the following actions:
1658
1659 requirements
1660 preserved: dotencode, exp-revlogv2.2, fncache, generaldelta, persistent-nodemap, revlog-compression-zstd, sparserevlog, store
1661 added: exp-dirstate-v2
1662
1663 dirstate-v2
1664 "hg status" will be faster
1665
1666 processed revlogs:
1667 - all-filelogs
1668 - changelog
1669 - manifest
1670
1671 beginning upgrade...
1672 repository locked and read-only
1673 creating temporary repository to stage upgraded data: $TESTTMP/sparserevlogrepo/.hg/upgrade.* (glob)
1674 (it is safe to interrupt this process any time before data migration completes)
1675 upgrading to dirstate-v2 from v1
1676 replaced files will be backed up at $TESTTMP/sparserevlogrepo/.hg/upgradebackup.* (glob)
1677 removing temporary repository $TESTTMP/sparserevlogrepo/.hg/upgrade.* (glob)
1678 $ ls .hg/upgradebackup.*/dirstate
1679 .hg/upgradebackup.*/dirstate (glob)
1680 $ hg debugformat -v
1681 format-variant repo config default
1682 fncache: yes yes yes
1683 dirstate-v2: yes no no
1684 dotencode: yes yes yes
1685 generaldelta: yes yes yes
1686 share-safe: no no no
1687 sparserevlog: yes yes yes
1688 persistent-nodemap: yes yes no
1689 copies-sdc: no no no
1690 revlog-v2: yes yes no
1691 changelog-v2: no no no
1692 plain-cl-delta: yes yes yes
1693 compression: zstd zstd zstd
1694 compression-level: default default default
1695 $ hg status
1696 $ dd status=none bs=12 count=1 if=.hg/dirstate
1697 dirstate-v2
1698
1699 Downgrade from dirstate-v2
1700
1701 $ hg debugupgraderepo --run
1702 upgrade will perform the following actions:
1703
1704 requirements
1705 preserved: dotencode, exp-revlogv2.2, fncache, generaldelta, persistent-nodemap, revlog-compression-zstd, sparserevlog, store
1706 removed: exp-dirstate-v2
1707
1708 processed revlogs:
1709 - all-filelogs
1710 - changelog
1711 - manifest
1712
1713 beginning upgrade...
1714 repository locked and read-only
1715 creating temporary repository to stage upgraded data: $TESTTMP/sparserevlogrepo/.hg/upgrade.* (glob)
1716 (it is safe to interrupt this process any time before data migration completes)
1717 downgrading from dirstate-v2 to v1
1718 replaced files will be backed up at $TESTTMP/sparserevlogrepo/.hg/upgradebackup.* (glob)
1719 removing temporary repository $TESTTMP/sparserevlogrepo/.hg/upgrade.* (glob)
1720 $ hg debugformat -v
1721 format-variant repo config default
1722 fncache: yes yes yes
1723 dirstate-v2: no no no
1724 dotencode: yes yes yes
1725 generaldelta: yes yes yes
1726 share-safe: no no no
1727 sparserevlog: yes yes yes
1728 persistent-nodemap: yes yes no
1729 copies-sdc: no no no
1730 revlog-v2: yes yes no
1731 changelog-v2: no no no
1732 plain-cl-delta: yes yes yes
1733 compression: zstd zstd zstd
1734 compression-level: default default default
1735 $ hg status
1736
1737 #endif
General Comments 0
You need to be logged in to leave comments. Login now