Show More
@@ -1,1979 +1,1980 | |||
|
1 | 1 | # dirstate.py - working directory tracking for mercurial |
|
2 | 2 | # |
|
3 | 3 | # Copyright 2005-2007 Olivia Mackall <olivia@selenic.com> |
|
4 | 4 | # |
|
5 | 5 | # This software may be used and distributed according to the terms of the |
|
6 | 6 | # GNU General Public License version 2 or any later version. |
|
7 | 7 | |
|
8 | 8 | from __future__ import absolute_import |
|
9 | 9 | |
|
10 | 10 | import collections |
|
11 | 11 | import contextlib |
|
12 | 12 | import errno |
|
13 | 13 | import os |
|
14 | 14 | import stat |
|
15 | 15 | |
|
16 | 16 | from .i18n import _ |
|
17 | 17 | from .pycompat import delattr |
|
18 | 18 | |
|
19 | 19 | from hgdemandimport import tracing |
|
20 | 20 | |
|
21 | 21 | from . import ( |
|
22 | 22 | encoding, |
|
23 | 23 | error, |
|
24 | 24 | match as matchmod, |
|
25 | 25 | pathutil, |
|
26 | 26 | policy, |
|
27 | 27 | pycompat, |
|
28 | 28 | scmutil, |
|
29 | 29 | sparse, |
|
30 | 30 | txnutil, |
|
31 | 31 | util, |
|
32 | 32 | ) |
|
33 | 33 | |
|
34 | 34 | from .interfaces import ( |
|
35 | 35 | dirstate as intdirstate, |
|
36 | 36 | util as interfaceutil, |
|
37 | 37 | ) |
|
38 | 38 | |
|
39 | 39 | parsers = policy.importmod('parsers') |
|
40 | 40 | rustmod = policy.importrust('dirstate') |
|
41 | 41 | |
|
42 | 42 | SUPPORTS_DIRSTATE_V2 = rustmod is not None |
|
43 | 43 | |
|
44 | 44 | propertycache = util.propertycache |
|
45 | 45 | filecache = scmutil.filecache |
|
46 | 46 | _rangemask = 0x7FFFFFFF |
|
47 | 47 | |
|
48 | 48 | dirstatetuple = parsers.dirstatetuple |
|
49 | 49 | |
|
50 | 50 | |
|
51 | 51 | class repocache(filecache): |
|
52 | 52 | """filecache for files in .hg/""" |
|
53 | 53 | |
|
54 | 54 | def join(self, obj, fname): |
|
55 | 55 | return obj._opener.join(fname) |
|
56 | 56 | |
|
57 | 57 | |
|
58 | 58 | class rootcache(filecache): |
|
59 | 59 | """filecache for files in the repository root""" |
|
60 | 60 | |
|
61 | 61 | def join(self, obj, fname): |
|
62 | 62 | return obj._join(fname) |
|
63 | 63 | |
|
64 | 64 | |
|
65 | 65 | def _getfsnow(vfs): |
|
66 | 66 | '''Get "now" timestamp on filesystem''' |
|
67 | 67 | tmpfd, tmpname = vfs.mkstemp() |
|
68 | 68 | try: |
|
69 | 69 | return os.fstat(tmpfd)[stat.ST_MTIME] |
|
70 | 70 | finally: |
|
71 | 71 | os.close(tmpfd) |
|
72 | 72 | vfs.unlink(tmpname) |
|
73 | 73 | |
|
74 | 74 | |
|
75 | 75 | @interfaceutil.implementer(intdirstate.idirstate) |
|
76 | 76 | class dirstate(object): |
|
77 | 77 | def __init__( |
|
78 | 78 | self, |
|
79 | 79 | opener, |
|
80 | 80 | ui, |
|
81 | 81 | root, |
|
82 | 82 | validate, |
|
83 | 83 | sparsematchfn, |
|
84 | 84 | nodeconstants, |
|
85 | 85 | use_dirstate_v2, |
|
86 | 86 | ): |
|
87 | 87 | """Create a new dirstate object. |
|
88 | 88 | |
|
89 | 89 | opener is an open()-like callable that can be used to open the |
|
90 | 90 | dirstate file; root is the root of the directory tracked by |
|
91 | 91 | the dirstate. |
|
92 | 92 | """ |
|
93 | 93 | self._use_dirstate_v2 = use_dirstate_v2 |
|
94 | 94 | self._nodeconstants = nodeconstants |
|
95 | 95 | self._opener = opener |
|
96 | 96 | self._validate = validate |
|
97 | 97 | self._root = root |
|
98 | 98 | self._sparsematchfn = sparsematchfn |
|
99 | 99 | # ntpath.join(root, '') of Python 2.7.9 does not add sep if root is |
|
100 | 100 | # UNC path pointing to root share (issue4557) |
|
101 | 101 | self._rootdir = pathutil.normasprefix(root) |
|
102 | 102 | self._dirty = False |
|
103 | 103 | self._lastnormaltime = 0 |
|
104 | 104 | self._ui = ui |
|
105 | 105 | self._filecache = {} |
|
106 | 106 | self._parentwriters = 0 |
|
107 | 107 | self._filename = b'dirstate' |
|
108 | 108 | self._pendingfilename = b'%s.pending' % self._filename |
|
109 | 109 | self._plchangecallbacks = {} |
|
110 | 110 | self._origpl = None |
|
111 | 111 | self._updatedfiles = set() |
|
112 | 112 | self._mapcls = dirstatemap |
|
113 | 113 | # Access and cache cwd early, so we don't access it for the first time |
|
114 | 114 | # after a working-copy update caused it to not exist (accessing it then |
|
115 | 115 | # raises an exception). |
|
116 | 116 | self._cwd |
|
117 | 117 | |
|
118 | 118 | def prefetch_parents(self): |
|
119 | 119 | """make sure the parents are loaded |
|
120 | 120 | |
|
121 | 121 | Used to avoid a race condition. |
|
122 | 122 | """ |
|
123 | 123 | self._pl |
|
124 | 124 | |
|
125 | 125 | @contextlib.contextmanager |
|
126 | 126 | def parentchange(self): |
|
127 | 127 | """Context manager for handling dirstate parents. |
|
128 | 128 | |
|
129 | 129 | If an exception occurs in the scope of the context manager, |
|
130 | 130 | the incoherent dirstate won't be written when wlock is |
|
131 | 131 | released. |
|
132 | 132 | """ |
|
133 | 133 | self._parentwriters += 1 |
|
134 | 134 | yield |
|
135 | 135 | # Typically we want the "undo" step of a context manager in a |
|
136 | 136 | # finally block so it happens even when an exception |
|
137 | 137 | # occurs. In this case, however, we only want to decrement |
|
138 | 138 | # parentwriters if the code in the with statement exits |
|
139 | 139 | # normally, so we don't have a try/finally here on purpose. |
|
140 | 140 | self._parentwriters -= 1 |
|
141 | 141 | |
|
142 | 142 | def pendingparentchange(self): |
|
143 | 143 | """Returns true if the dirstate is in the middle of a set of changes |
|
144 | 144 | that modify the dirstate parent. |
|
145 | 145 | """ |
|
146 | 146 | return self._parentwriters > 0 |
|
147 | 147 | |
|
148 | 148 | @propertycache |
|
149 | 149 | def _map(self): |
|
150 | 150 | """Return the dirstate contents (see documentation for dirstatemap).""" |
|
151 | 151 | self._map = self._mapcls( |
|
152 | 152 | self._ui, |
|
153 | 153 | self._opener, |
|
154 | 154 | self._root, |
|
155 | 155 | self._nodeconstants, |
|
156 | 156 | self._use_dirstate_v2, |
|
157 | 157 | ) |
|
158 | 158 | return self._map |
|
159 | 159 | |
|
160 | 160 | @property |
|
161 | 161 | def _sparsematcher(self): |
|
162 | 162 | """The matcher for the sparse checkout. |
|
163 | 163 | |
|
164 | 164 | The working directory may not include every file from a manifest. The |
|
165 | 165 | matcher obtained by this property will match a path if it is to be |
|
166 | 166 | included in the working directory. |
|
167 | 167 | """ |
|
168 | 168 | # TODO there is potential to cache this property. For now, the matcher |
|
169 | 169 | # is resolved on every access. (But the called function does use a |
|
170 | 170 | # cache to keep the lookup fast.) |
|
171 | 171 | return self._sparsematchfn() |
|
172 | 172 | |
|
173 | 173 | @repocache(b'branch') |
|
174 | 174 | def _branch(self): |
|
175 | 175 | try: |
|
176 | 176 | return self._opener.read(b"branch").strip() or b"default" |
|
177 | 177 | except IOError as inst: |
|
178 | 178 | if inst.errno != errno.ENOENT: |
|
179 | 179 | raise |
|
180 | 180 | return b"default" |
|
181 | 181 | |
|
182 | 182 | @property |
|
183 | 183 | def _pl(self): |
|
184 | 184 | return self._map.parents() |
|
185 | 185 | |
|
186 | 186 | def hasdir(self, d): |
|
187 | 187 | return self._map.hastrackeddir(d) |
|
188 | 188 | |
|
189 | 189 | @rootcache(b'.hgignore') |
|
190 | 190 | def _ignore(self): |
|
191 | 191 | files = self._ignorefiles() |
|
192 | 192 | if not files: |
|
193 | 193 | return matchmod.never() |
|
194 | 194 | |
|
195 | 195 | pats = [b'include:%s' % f for f in files] |
|
196 | 196 | return matchmod.match(self._root, b'', [], pats, warn=self._ui.warn) |
|
197 | 197 | |
|
198 | 198 | @propertycache |
|
199 | 199 | def _slash(self): |
|
200 | 200 | return self._ui.configbool(b'ui', b'slash') and pycompat.ossep != b'/' |
|
201 | 201 | |
|
202 | 202 | @propertycache |
|
203 | 203 | def _checklink(self): |
|
204 | 204 | return util.checklink(self._root) |
|
205 | 205 | |
|
206 | 206 | @propertycache |
|
207 | 207 | def _checkexec(self): |
|
208 | 208 | return bool(util.checkexec(self._root)) |
|
209 | 209 | |
|
210 | 210 | @propertycache |
|
211 | 211 | def _checkcase(self): |
|
212 | 212 | return not util.fscasesensitive(self._join(b'.hg')) |
|
213 | 213 | |
|
214 | 214 | def _join(self, f): |
|
215 | 215 | # much faster than os.path.join() |
|
216 | 216 | # it's safe because f is always a relative path |
|
217 | 217 | return self._rootdir + f |
|
218 | 218 | |
|
219 | 219 | def flagfunc(self, buildfallback): |
|
220 | 220 | if self._checklink and self._checkexec: |
|
221 | 221 | |
|
222 | 222 | def f(x): |
|
223 | 223 | try: |
|
224 | 224 | st = os.lstat(self._join(x)) |
|
225 | 225 | if util.statislink(st): |
|
226 | 226 | return b'l' |
|
227 | 227 | if util.statisexec(st): |
|
228 | 228 | return b'x' |
|
229 | 229 | except OSError: |
|
230 | 230 | pass |
|
231 | 231 | return b'' |
|
232 | 232 | |
|
233 | 233 | return f |
|
234 | 234 | |
|
235 | 235 | fallback = buildfallback() |
|
236 | 236 | if self._checklink: |
|
237 | 237 | |
|
238 | 238 | def f(x): |
|
239 | 239 | if os.path.islink(self._join(x)): |
|
240 | 240 | return b'l' |
|
241 | 241 | if b'x' in fallback(x): |
|
242 | 242 | return b'x' |
|
243 | 243 | return b'' |
|
244 | 244 | |
|
245 | 245 | return f |
|
246 | 246 | if self._checkexec: |
|
247 | 247 | |
|
248 | 248 | def f(x): |
|
249 | 249 | if b'l' in fallback(x): |
|
250 | 250 | return b'l' |
|
251 | 251 | if util.isexec(self._join(x)): |
|
252 | 252 | return b'x' |
|
253 | 253 | return b'' |
|
254 | 254 | |
|
255 | 255 | return f |
|
256 | 256 | else: |
|
257 | 257 | return fallback |
|
258 | 258 | |
|
259 | 259 | @propertycache |
|
260 | 260 | def _cwd(self): |
|
261 | 261 | # internal config: ui.forcecwd |
|
262 | 262 | forcecwd = self._ui.config(b'ui', b'forcecwd') |
|
263 | 263 | if forcecwd: |
|
264 | 264 | return forcecwd |
|
265 | 265 | return encoding.getcwd() |
|
266 | 266 | |
|
267 | 267 | def getcwd(self): |
|
268 | 268 | """Return the path from which a canonical path is calculated. |
|
269 | 269 | |
|
270 | 270 | This path should be used to resolve file patterns or to convert |
|
271 | 271 | canonical paths back to file paths for display. It shouldn't be |
|
272 | 272 | used to get real file paths. Use vfs functions instead. |
|
273 | 273 | """ |
|
274 | 274 | cwd = self._cwd |
|
275 | 275 | if cwd == self._root: |
|
276 | 276 | return b'' |
|
277 | 277 | # self._root ends with a path separator if self._root is '/' or 'C:\' |
|
278 | 278 | rootsep = self._root |
|
279 | 279 | if not util.endswithsep(rootsep): |
|
280 | 280 | rootsep += pycompat.ossep |
|
281 | 281 | if cwd.startswith(rootsep): |
|
282 | 282 | return cwd[len(rootsep) :] |
|
283 | 283 | else: |
|
284 | 284 | # we're outside the repo. return an absolute path. |
|
285 | 285 | return cwd |
|
286 | 286 | |
|
287 | 287 | def pathto(self, f, cwd=None): |
|
288 | 288 | if cwd is None: |
|
289 | 289 | cwd = self.getcwd() |
|
290 | 290 | path = util.pathto(self._root, cwd, f) |
|
291 | 291 | if self._slash: |
|
292 | 292 | return util.pconvert(path) |
|
293 | 293 | return path |
|
294 | 294 | |
|
295 | 295 | def __getitem__(self, key): |
|
296 | 296 | """Return the current state of key (a filename) in the dirstate. |
|
297 | 297 | |
|
298 | 298 | States are: |
|
299 | 299 | n normal |
|
300 | 300 | m needs merging |
|
301 | 301 | r marked for removal |
|
302 | 302 | a marked for addition |
|
303 | 303 | ? not tracked |
|
304 | 304 | """ |
|
305 | 305 | return self._map.get(key, (b"?",))[0] |
|
306 | 306 | |
|
307 | 307 | def __contains__(self, key): |
|
308 | 308 | return key in self._map |
|
309 | 309 | |
|
310 | 310 | def __iter__(self): |
|
311 | 311 | return iter(sorted(self._map)) |
|
312 | 312 | |
|
313 | 313 | def items(self): |
|
314 | 314 | return pycompat.iteritems(self._map) |
|
315 | 315 | |
|
316 | 316 | iteritems = items |
|
317 | 317 | |
|
318 | 318 | def parents(self): |
|
319 | 319 | return [self._validate(p) for p in self._pl] |
|
320 | 320 | |
|
321 | 321 | def p1(self): |
|
322 | 322 | return self._validate(self._pl[0]) |
|
323 | 323 | |
|
324 | 324 | def p2(self): |
|
325 | 325 | return self._validate(self._pl[1]) |
|
326 | 326 | |
|
327 | 327 | def branch(self): |
|
328 | 328 | return encoding.tolocal(self._branch) |
|
329 | 329 | |
|
330 | 330 | def setparents(self, p1, p2=None): |
|
331 | 331 | """Set dirstate parents to p1 and p2. |
|
332 | 332 | |
|
333 | 333 | When moving from two parents to one, 'm' merged entries a |
|
334 | 334 | adjusted to normal and previous copy records discarded and |
|
335 | 335 | returned by the call. |
|
336 | 336 | |
|
337 | 337 | See localrepo.setparents() |
|
338 | 338 | """ |
|
339 | 339 | if p2 is None: |
|
340 | 340 | p2 = self._nodeconstants.nullid |
|
341 | 341 | if self._parentwriters == 0: |
|
342 | 342 | raise ValueError( |
|
343 | 343 | b"cannot set dirstate parent outside of " |
|
344 | 344 | b"dirstate.parentchange context manager" |
|
345 | 345 | ) |
|
346 | 346 | |
|
347 | 347 | self._dirty = True |
|
348 | 348 | oldp2 = self._pl[1] |
|
349 | 349 | if self._origpl is None: |
|
350 | 350 | self._origpl = self._pl |
|
351 | 351 | self._map.setparents(p1, p2) |
|
352 | 352 | copies = {} |
|
353 | 353 | if ( |
|
354 | 354 | oldp2 != self._nodeconstants.nullid |
|
355 | 355 | and p2 == self._nodeconstants.nullid |
|
356 | 356 | ): |
|
357 | 357 | candidatefiles = self._map.non_normal_or_other_parent_paths() |
|
358 | 358 | |
|
359 | 359 | for f in candidatefiles: |
|
360 | 360 | s = self._map.get(f) |
|
361 | 361 | if s is None: |
|
362 | 362 | continue |
|
363 | 363 | |
|
364 | 364 | # Discard 'm' markers when moving away from a merge state |
|
365 | 365 | if s[0] == b'm': |
|
366 | 366 | source = self._map.copymap.get(f) |
|
367 | 367 | if source: |
|
368 | 368 | copies[f] = source |
|
369 | 369 | self.normallookup(f) |
|
370 | 370 | # Also fix up otherparent markers |
|
371 | 371 | elif s[0] == b'n' and s[2] == -2: |
|
372 | 372 | source = self._map.copymap.get(f) |
|
373 | 373 | if source: |
|
374 | 374 | copies[f] = source |
|
375 | 375 | self.add(f) |
|
376 | 376 | return copies |
|
377 | 377 | |
|
378 | 378 | def setbranch(self, branch): |
|
379 | 379 | self.__class__._branch.set(self, encoding.fromlocal(branch)) |
|
380 | 380 | f = self._opener(b'branch', b'w', atomictemp=True, checkambig=True) |
|
381 | 381 | try: |
|
382 | 382 | f.write(self._branch + b'\n') |
|
383 | 383 | f.close() |
|
384 | 384 | |
|
385 | 385 | # make sure filecache has the correct stat info for _branch after |
|
386 | 386 | # replacing the underlying file |
|
387 | 387 | ce = self._filecache[b'_branch'] |
|
388 | 388 | if ce: |
|
389 | 389 | ce.refresh() |
|
390 | 390 | except: # re-raises |
|
391 | 391 | f.discard() |
|
392 | 392 | raise |
|
393 | 393 | |
|
394 | 394 | def invalidate(self): |
|
395 | 395 | """Causes the next access to reread the dirstate. |
|
396 | 396 | |
|
397 | 397 | This is different from localrepo.invalidatedirstate() because it always |
|
398 | 398 | rereads the dirstate. Use localrepo.invalidatedirstate() if you want to |
|
399 | 399 | check whether the dirstate has changed before rereading it.""" |
|
400 | 400 | |
|
401 | 401 | for a in ("_map", "_branch", "_ignore"): |
|
402 | 402 | if a in self.__dict__: |
|
403 | 403 | delattr(self, a) |
|
404 | 404 | self._lastnormaltime = 0 |
|
405 | 405 | self._dirty = False |
|
406 | 406 | self._updatedfiles.clear() |
|
407 | 407 | self._parentwriters = 0 |
|
408 | 408 | self._origpl = None |
|
409 | 409 | |
|
410 | 410 | def copy(self, source, dest): |
|
411 | 411 | """Mark dest as a copy of source. Unmark dest if source is None.""" |
|
412 | 412 | if source == dest: |
|
413 | 413 | return |
|
414 | 414 | self._dirty = True |
|
415 | 415 | if source is not None: |
|
416 | 416 | self._map.copymap[dest] = source |
|
417 | 417 | self._updatedfiles.add(source) |
|
418 | 418 | self._updatedfiles.add(dest) |
|
419 | 419 | elif self._map.copymap.pop(dest, None): |
|
420 | 420 | self._updatedfiles.add(dest) |
|
421 | 421 | |
|
422 | 422 | def copied(self, file): |
|
423 | 423 | return self._map.copymap.get(file, None) |
|
424 | 424 | |
|
425 | 425 | def copies(self): |
|
426 | 426 | return self._map.copymap |
|
427 | 427 | |
|
428 | 428 | def _addpath(self, f, state, mode, size, mtime): |
|
429 | 429 | oldstate = self[f] |
|
430 | 430 | if state == b'a' or oldstate == b'r': |
|
431 | 431 | scmutil.checkfilename(f) |
|
432 | 432 | if self._map.hastrackeddir(f): |
|
433 | 433 | raise error.Abort( |
|
434 | 434 | _(b'directory %r already in dirstate') % pycompat.bytestr(f) |
|
435 | 435 | ) |
|
436 | 436 | # shadows |
|
437 | 437 | for d in pathutil.finddirs(f): |
|
438 | 438 | if self._map.hastrackeddir(d): |
|
439 | 439 | break |
|
440 | 440 | entry = self._map.get(d) |
|
441 | 441 | if entry is not None and entry[0] != b'r': |
|
442 | 442 | raise error.Abort( |
|
443 | 443 | _(b'file %r in dirstate clashes with %r') |
|
444 | 444 | % (pycompat.bytestr(d), pycompat.bytestr(f)) |
|
445 | 445 | ) |
|
446 | 446 | self._dirty = True |
|
447 | 447 | self._updatedfiles.add(f) |
|
448 | 448 | self._map.addfile(f, oldstate, state, mode, size, mtime) |
|
449 | 449 | |
|
450 | 450 | def normal(self, f, parentfiledata=None): |
|
451 | 451 | """Mark a file normal and clean. |
|
452 | 452 | |
|
453 | 453 | parentfiledata: (mode, size, mtime) of the clean file |
|
454 | 454 | |
|
455 | 455 | parentfiledata should be computed from memory (for mode, |
|
456 | 456 | size), as or close as possible from the point where we |
|
457 | 457 | determined the file was clean, to limit the risk of the |
|
458 | 458 | file having been changed by an external process between the |
|
459 | 459 | moment where the file was determined to be clean and now.""" |
|
460 | 460 | if parentfiledata: |
|
461 | 461 | (mode, size, mtime) = parentfiledata |
|
462 | 462 | else: |
|
463 | 463 | s = os.lstat(self._join(f)) |
|
464 | 464 | mode = s.st_mode |
|
465 | 465 | size = s.st_size |
|
466 | 466 | mtime = s[stat.ST_MTIME] |
|
467 | 467 | self._addpath(f, b'n', mode, size & _rangemask, mtime & _rangemask) |
|
468 | 468 | self._map.copymap.pop(f, None) |
|
469 | 469 | if f in self._map.nonnormalset: |
|
470 | 470 | self._map.nonnormalset.remove(f) |
|
471 | 471 | if mtime > self._lastnormaltime: |
|
472 | 472 | # Remember the most recent modification timeslot for status(), |
|
473 | 473 | # to make sure we won't miss future size-preserving file content |
|
474 | 474 | # modifications that happen within the same timeslot. |
|
475 | 475 | self._lastnormaltime = mtime |
|
476 | 476 | |
|
477 | 477 | def normallookup(self, f): |
|
478 | 478 | '''Mark a file normal, but possibly dirty.''' |
|
479 | 479 | if self._pl[1] != self._nodeconstants.nullid: |
|
480 | 480 | # if there is a merge going on and the file was either |
|
481 | 481 | # in state 'm' (-1) or coming from other parent (-2) before |
|
482 | 482 | # being removed, restore that state. |
|
483 | 483 | entry = self._map.get(f) |
|
484 | 484 | if entry is not None: |
|
485 | 485 | if entry[0] == b'r' and entry[2] in (-1, -2): |
|
486 | 486 | source = self._map.copymap.get(f) |
|
487 | 487 | if entry[2] == -1: |
|
488 | 488 | self.merge(f) |
|
489 | 489 | elif entry[2] == -2: |
|
490 | 490 | self.otherparent(f) |
|
491 | 491 | if source: |
|
492 | 492 | self.copy(source, f) |
|
493 | 493 | return |
|
494 | 494 | if entry[0] == b'm' or entry[0] == b'n' and entry[2] == -2: |
|
495 | 495 | return |
|
496 | 496 | self._addpath(f, b'n', 0, -1, -1) |
|
497 | 497 | self._map.copymap.pop(f, None) |
|
498 | 498 | |
|
499 | 499 | def otherparent(self, f): |
|
500 | 500 | '''Mark as coming from the other parent, always dirty.''' |
|
501 | 501 | if self._pl[1] == self._nodeconstants.nullid: |
|
502 | 502 | raise error.Abort( |
|
503 | 503 | _(b"setting %r to other parent only allowed in merges") % f |
|
504 | 504 | ) |
|
505 | 505 | if f in self and self[f] == b'n': |
|
506 | 506 | # merge-like |
|
507 | 507 | self._addpath(f, b'm', 0, -2, -1) |
|
508 | 508 | else: |
|
509 | 509 | # add-like |
|
510 | 510 | self._addpath(f, b'n', 0, -2, -1) |
|
511 | 511 | self._map.copymap.pop(f, None) |
|
512 | 512 | |
|
513 | 513 | def add(self, f): |
|
514 | 514 | '''Mark a file added.''' |
|
515 | 515 | self._addpath(f, b'a', 0, -1, -1) |
|
516 | 516 | self._map.copymap.pop(f, None) |
|
517 | 517 | |
|
518 | 518 | def remove(self, f): |
|
519 | 519 | '''Mark a file removed.''' |
|
520 | 520 | self._dirty = True |
|
521 | 521 | oldstate = self[f] |
|
522 | 522 | size = 0 |
|
523 | 523 | if self._pl[1] != self._nodeconstants.nullid: |
|
524 | 524 | entry = self._map.get(f) |
|
525 | 525 | if entry is not None: |
|
526 | 526 | # backup the previous state |
|
527 | 527 | if entry[0] == b'm': # merge |
|
528 | 528 | size = -1 |
|
529 | 529 | elif entry[0] == b'n' and entry[2] == -2: # other parent |
|
530 | 530 | size = -2 |
|
531 | 531 | self._map.otherparentset.add(f) |
|
532 | 532 | self._updatedfiles.add(f) |
|
533 | 533 | self._map.removefile(f, oldstate, size) |
|
534 | 534 | if size == 0: |
|
535 | 535 | self._map.copymap.pop(f, None) |
|
536 | 536 | |
|
537 | 537 | def merge(self, f): |
|
538 | 538 | '''Mark a file merged.''' |
|
539 | 539 | if self._pl[1] == self._nodeconstants.nullid: |
|
540 | 540 | return self.normallookup(f) |
|
541 | 541 | return self.otherparent(f) |
|
542 | 542 | |
|
543 | 543 | def drop(self, f): |
|
544 | 544 | '''Drop a file from the dirstate''' |
|
545 | 545 | oldstate = self[f] |
|
546 | 546 | if self._map.dropfile(f, oldstate): |
|
547 | 547 | self._dirty = True |
|
548 | 548 | self._updatedfiles.add(f) |
|
549 | 549 | self._map.copymap.pop(f, None) |
|
550 | 550 | |
|
551 | 551 | def _discoverpath(self, path, normed, ignoremissing, exists, storemap): |
|
552 | 552 | if exists is None: |
|
553 | 553 | exists = os.path.lexists(os.path.join(self._root, path)) |
|
554 | 554 | if not exists: |
|
555 | 555 | # Maybe a path component exists |
|
556 | 556 | if not ignoremissing and b'/' in path: |
|
557 | 557 | d, f = path.rsplit(b'/', 1) |
|
558 | 558 | d = self._normalize(d, False, ignoremissing, None) |
|
559 | 559 | folded = d + b"/" + f |
|
560 | 560 | else: |
|
561 | 561 | # No path components, preserve original case |
|
562 | 562 | folded = path |
|
563 | 563 | else: |
|
564 | 564 | # recursively normalize leading directory components |
|
565 | 565 | # against dirstate |
|
566 | 566 | if b'/' in normed: |
|
567 | 567 | d, f = normed.rsplit(b'/', 1) |
|
568 | 568 | d = self._normalize(d, False, ignoremissing, True) |
|
569 | 569 | r = self._root + b"/" + d |
|
570 | 570 | folded = d + b"/" + util.fspath(f, r) |
|
571 | 571 | else: |
|
572 | 572 | folded = util.fspath(normed, self._root) |
|
573 | 573 | storemap[normed] = folded |
|
574 | 574 | |
|
575 | 575 | return folded |
|
576 | 576 | |
|
577 | 577 | def _normalizefile(self, path, isknown, ignoremissing=False, exists=None): |
|
578 | 578 | normed = util.normcase(path) |
|
579 | 579 | folded = self._map.filefoldmap.get(normed, None) |
|
580 | 580 | if folded is None: |
|
581 | 581 | if isknown: |
|
582 | 582 | folded = path |
|
583 | 583 | else: |
|
584 | 584 | folded = self._discoverpath( |
|
585 | 585 | path, normed, ignoremissing, exists, self._map.filefoldmap |
|
586 | 586 | ) |
|
587 | 587 | return folded |
|
588 | 588 | |
|
589 | 589 | def _normalize(self, path, isknown, ignoremissing=False, exists=None): |
|
590 | 590 | normed = util.normcase(path) |
|
591 | 591 | folded = self._map.filefoldmap.get(normed, None) |
|
592 | 592 | if folded is None: |
|
593 | 593 | folded = self._map.dirfoldmap.get(normed, None) |
|
594 | 594 | if folded is None: |
|
595 | 595 | if isknown: |
|
596 | 596 | folded = path |
|
597 | 597 | else: |
|
598 | 598 | # store discovered result in dirfoldmap so that future |
|
599 | 599 | # normalizefile calls don't start matching directories |
|
600 | 600 | folded = self._discoverpath( |
|
601 | 601 | path, normed, ignoremissing, exists, self._map.dirfoldmap |
|
602 | 602 | ) |
|
603 | 603 | return folded |
|
604 | 604 | |
|
605 | 605 | def normalize(self, path, isknown=False, ignoremissing=False): |
|
606 | 606 | """ |
|
607 | 607 | normalize the case of a pathname when on a casefolding filesystem |
|
608 | 608 | |
|
609 | 609 | isknown specifies whether the filename came from walking the |
|
610 | 610 | disk, to avoid extra filesystem access. |
|
611 | 611 | |
|
612 | 612 | If ignoremissing is True, missing path are returned |
|
613 | 613 | unchanged. Otherwise, we try harder to normalize possibly |
|
614 | 614 | existing path components. |
|
615 | 615 | |
|
616 | 616 | The normalized case is determined based on the following precedence: |
|
617 | 617 | |
|
618 | 618 | - version of name already stored in the dirstate |
|
619 | 619 | - version of name stored on disk |
|
620 | 620 | - version provided via command arguments |
|
621 | 621 | """ |
|
622 | 622 | |
|
623 | 623 | if self._checkcase: |
|
624 | 624 | return self._normalize(path, isknown, ignoremissing) |
|
625 | 625 | return path |
|
626 | 626 | |
|
627 | 627 | def clear(self): |
|
628 | 628 | self._map.clear() |
|
629 | 629 | self._lastnormaltime = 0 |
|
630 | 630 | self._updatedfiles.clear() |
|
631 | 631 | self._dirty = True |
|
632 | 632 | |
|
633 | 633 | def rebuild(self, parent, allfiles, changedfiles=None): |
|
634 | 634 | if changedfiles is None: |
|
635 | 635 | # Rebuild entire dirstate |
|
636 | 636 | to_lookup = allfiles |
|
637 | 637 | to_drop = [] |
|
638 | 638 | lastnormaltime = self._lastnormaltime |
|
639 | 639 | self.clear() |
|
640 | 640 | self._lastnormaltime = lastnormaltime |
|
641 | 641 | elif len(changedfiles) < 10: |
|
642 | 642 | # Avoid turning allfiles into a set, which can be expensive if it's |
|
643 | 643 | # large. |
|
644 | 644 | to_lookup = [] |
|
645 | 645 | to_drop = [] |
|
646 | 646 | for f in changedfiles: |
|
647 | 647 | if f in allfiles: |
|
648 | 648 | to_lookup.append(f) |
|
649 | 649 | else: |
|
650 | 650 | to_drop.append(f) |
|
651 | 651 | else: |
|
652 | 652 | changedfilesset = set(changedfiles) |
|
653 | 653 | to_lookup = changedfilesset & set(allfiles) |
|
654 | 654 | to_drop = changedfilesset - to_lookup |
|
655 | 655 | |
|
656 | 656 | if self._origpl is None: |
|
657 | 657 | self._origpl = self._pl |
|
658 | 658 | self._map.setparents(parent, self._nodeconstants.nullid) |
|
659 | 659 | |
|
660 | 660 | for f in to_lookup: |
|
661 | 661 | self.normallookup(f) |
|
662 | 662 | for f in to_drop: |
|
663 | 663 | self.drop(f) |
|
664 | 664 | |
|
665 | 665 | self._dirty = True |
|
666 | 666 | |
|
667 | 667 | def identity(self): |
|
668 | 668 | """Return identity of dirstate itself to detect changing in storage |
|
669 | 669 | |
|
670 | 670 | If identity of previous dirstate is equal to this, writing |
|
671 | 671 | changes based on the former dirstate out can keep consistency. |
|
672 | 672 | """ |
|
673 | 673 | return self._map.identity |
|
674 | 674 | |
|
675 | 675 | def write(self, tr): |
|
676 | 676 | if not self._dirty: |
|
677 | 677 | return |
|
678 | 678 | |
|
679 | 679 | filename = self._filename |
|
680 | 680 | if tr: |
|
681 | 681 | # 'dirstate.write()' is not only for writing in-memory |
|
682 | 682 | # changes out, but also for dropping ambiguous timestamp. |
|
683 | 683 | # delayed writing re-raise "ambiguous timestamp issue". |
|
684 | 684 | # See also the wiki page below for detail: |
|
685 | 685 | # https://www.mercurial-scm.org/wiki/DirstateTransactionPlan |
|
686 | 686 | |
|
687 | 687 | # emulate dropping timestamp in 'parsers.pack_dirstate' |
|
688 | 688 | now = _getfsnow(self._opener) |
|
689 | 689 | self._map.clearambiguoustimes(self._updatedfiles, now) |
|
690 | 690 | |
|
691 | 691 | # emulate that all 'dirstate.normal' results are written out |
|
692 | 692 | self._lastnormaltime = 0 |
|
693 | 693 | self._updatedfiles.clear() |
|
694 | 694 | |
|
695 | 695 | # delay writing in-memory changes out |
|
696 | 696 | tr.addfilegenerator( |
|
697 | 697 | b'dirstate', |
|
698 | 698 | (self._filename,), |
|
699 | 699 | self._writedirstate, |
|
700 | 700 | location=b'plain', |
|
701 | 701 | ) |
|
702 | 702 | return |
|
703 | 703 | |
|
704 | 704 | st = self._opener(filename, b"w", atomictemp=True, checkambig=True) |
|
705 | 705 | self._writedirstate(st) |
|
706 | 706 | |
|
707 | 707 | def addparentchangecallback(self, category, callback): |
|
708 | 708 | """add a callback to be called when the wd parents are changed |
|
709 | 709 | |
|
710 | 710 | Callback will be called with the following arguments: |
|
711 | 711 | dirstate, (oldp1, oldp2), (newp1, newp2) |
|
712 | 712 | |
|
713 | 713 | Category is a unique identifier to allow overwriting an old callback |
|
714 | 714 | with a newer callback. |
|
715 | 715 | """ |
|
716 | 716 | self._plchangecallbacks[category] = callback |
|
717 | 717 | |
|
718 | 718 | def _writedirstate(self, st): |
|
719 | 719 | # notify callbacks about parents change |
|
720 | 720 | if self._origpl is not None and self._origpl != self._pl: |
|
721 | 721 | for c, callback in sorted( |
|
722 | 722 | pycompat.iteritems(self._plchangecallbacks) |
|
723 | 723 | ): |
|
724 | 724 | callback(self, self._origpl, self._pl) |
|
725 | 725 | self._origpl = None |
|
726 | 726 | # use the modification time of the newly created temporary file as the |
|
727 | 727 | # filesystem's notion of 'now' |
|
728 | 728 | now = util.fstat(st)[stat.ST_MTIME] & _rangemask |
|
729 | 729 | |
|
730 | 730 | # enough 'delaywrite' prevents 'pack_dirstate' from dropping |
|
731 | 731 | # timestamp of each entries in dirstate, because of 'now > mtime' |
|
732 | 732 | delaywrite = self._ui.configint(b'debug', b'dirstate.delaywrite') |
|
733 | 733 | if delaywrite > 0: |
|
734 | 734 | # do we have any files to delay for? |
|
735 | 735 | for f, e in pycompat.iteritems(self._map): |
|
736 | 736 | if e[0] == b'n' and e[3] == now: |
|
737 | 737 | import time # to avoid useless import |
|
738 | 738 | |
|
739 | 739 | # rather than sleep n seconds, sleep until the next |
|
740 | 740 | # multiple of n seconds |
|
741 | 741 | clock = time.time() |
|
742 | 742 | start = int(clock) - (int(clock) % delaywrite) |
|
743 | 743 | end = start + delaywrite |
|
744 | 744 | time.sleep(end - clock) |
|
745 | 745 | now = end # trust our estimate that the end is near now |
|
746 | 746 | break |
|
747 | 747 | |
|
748 | 748 | self._map.write(st, now) |
|
749 | 749 | self._lastnormaltime = 0 |
|
750 | 750 | self._dirty = False |
|
751 | 751 | |
|
752 | 752 | def _dirignore(self, f): |
|
753 | 753 | if self._ignore(f): |
|
754 | 754 | return True |
|
755 | 755 | for p in pathutil.finddirs(f): |
|
756 | 756 | if self._ignore(p): |
|
757 | 757 | return True |
|
758 | 758 | return False |
|
759 | 759 | |
|
760 | 760 | def _ignorefiles(self): |
|
761 | 761 | files = [] |
|
762 | 762 | if os.path.exists(self._join(b'.hgignore')): |
|
763 | 763 | files.append(self._join(b'.hgignore')) |
|
764 | 764 | for name, path in self._ui.configitems(b"ui"): |
|
765 | 765 | if name == b'ignore' or name.startswith(b'ignore.'): |
|
766 | 766 | # we need to use os.path.join here rather than self._join |
|
767 | 767 | # because path is arbitrary and user-specified |
|
768 | 768 | files.append(os.path.join(self._rootdir, util.expandpath(path))) |
|
769 | 769 | return files |
|
770 | 770 | |
|
771 | 771 | def _ignorefileandline(self, f): |
|
772 | 772 | files = collections.deque(self._ignorefiles()) |
|
773 | 773 | visited = set() |
|
774 | 774 | while files: |
|
775 | 775 | i = files.popleft() |
|
776 | 776 | patterns = matchmod.readpatternfile( |
|
777 | 777 | i, self._ui.warn, sourceinfo=True |
|
778 | 778 | ) |
|
779 | 779 | for pattern, lineno, line in patterns: |
|
780 | 780 | kind, p = matchmod._patsplit(pattern, b'glob') |
|
781 | 781 | if kind == b"subinclude": |
|
782 | 782 | if p not in visited: |
|
783 | 783 | files.append(p) |
|
784 | 784 | continue |
|
785 | 785 | m = matchmod.match( |
|
786 | 786 | self._root, b'', [], [pattern], warn=self._ui.warn |
|
787 | 787 | ) |
|
788 | 788 | if m(f): |
|
789 | 789 | return (i, lineno, line) |
|
790 | 790 | visited.add(i) |
|
791 | 791 | return (None, -1, b"") |
|
792 | 792 | |
|
793 | 793 | def _walkexplicit(self, match, subrepos): |
|
794 | 794 | """Get stat data about the files explicitly specified by match. |
|
795 | 795 | |
|
796 | 796 | Return a triple (results, dirsfound, dirsnotfound). |
|
797 | 797 | - results is a mapping from filename to stat result. It also contains |
|
798 | 798 | listings mapping subrepos and .hg to None. |
|
799 | 799 | - dirsfound is a list of files found to be directories. |
|
800 | 800 | - dirsnotfound is a list of files that the dirstate thinks are |
|
801 | 801 | directories and that were not found.""" |
|
802 | 802 | |
|
803 | 803 | def badtype(mode): |
|
804 | 804 | kind = _(b'unknown') |
|
805 | 805 | if stat.S_ISCHR(mode): |
|
806 | 806 | kind = _(b'character device') |
|
807 | 807 | elif stat.S_ISBLK(mode): |
|
808 | 808 | kind = _(b'block device') |
|
809 | 809 | elif stat.S_ISFIFO(mode): |
|
810 | 810 | kind = _(b'fifo') |
|
811 | 811 | elif stat.S_ISSOCK(mode): |
|
812 | 812 | kind = _(b'socket') |
|
813 | 813 | elif stat.S_ISDIR(mode): |
|
814 | 814 | kind = _(b'directory') |
|
815 | 815 | return _(b'unsupported file type (type is %s)') % kind |
|
816 | 816 | |
|
817 | 817 | badfn = match.bad |
|
818 | 818 | dmap = self._map |
|
819 | 819 | lstat = os.lstat |
|
820 | 820 | getkind = stat.S_IFMT |
|
821 | 821 | dirkind = stat.S_IFDIR |
|
822 | 822 | regkind = stat.S_IFREG |
|
823 | 823 | lnkkind = stat.S_IFLNK |
|
824 | 824 | join = self._join |
|
825 | 825 | dirsfound = [] |
|
826 | 826 | foundadd = dirsfound.append |
|
827 | 827 | dirsnotfound = [] |
|
828 | 828 | notfoundadd = dirsnotfound.append |
|
829 | 829 | |
|
830 | 830 | if not match.isexact() and self._checkcase: |
|
831 | 831 | normalize = self._normalize |
|
832 | 832 | else: |
|
833 | 833 | normalize = None |
|
834 | 834 | |
|
835 | 835 | files = sorted(match.files()) |
|
836 | 836 | subrepos.sort() |
|
837 | 837 | i, j = 0, 0 |
|
838 | 838 | while i < len(files) and j < len(subrepos): |
|
839 | 839 | subpath = subrepos[j] + b"/" |
|
840 | 840 | if files[i] < subpath: |
|
841 | 841 | i += 1 |
|
842 | 842 | continue |
|
843 | 843 | while i < len(files) and files[i].startswith(subpath): |
|
844 | 844 | del files[i] |
|
845 | 845 | j += 1 |
|
846 | 846 | |
|
847 | 847 | if not files or b'' in files: |
|
848 | 848 | files = [b''] |
|
849 | 849 | # constructing the foldmap is expensive, so don't do it for the |
|
850 | 850 | # common case where files is [''] |
|
851 | 851 | normalize = None |
|
852 | 852 | results = dict.fromkeys(subrepos) |
|
853 | 853 | results[b'.hg'] = None |
|
854 | 854 | |
|
855 | 855 | for ff in files: |
|
856 | 856 | if normalize: |
|
857 | 857 | nf = normalize(ff, False, True) |
|
858 | 858 | else: |
|
859 | 859 | nf = ff |
|
860 | 860 | if nf in results: |
|
861 | 861 | continue |
|
862 | 862 | |
|
863 | 863 | try: |
|
864 | 864 | st = lstat(join(nf)) |
|
865 | 865 | kind = getkind(st.st_mode) |
|
866 | 866 | if kind == dirkind: |
|
867 | 867 | if nf in dmap: |
|
868 | 868 | # file replaced by dir on disk but still in dirstate |
|
869 | 869 | results[nf] = None |
|
870 | 870 | foundadd((nf, ff)) |
|
871 | 871 | elif kind == regkind or kind == lnkkind: |
|
872 | 872 | results[nf] = st |
|
873 | 873 | else: |
|
874 | 874 | badfn(ff, badtype(kind)) |
|
875 | 875 | if nf in dmap: |
|
876 | 876 | results[nf] = None |
|
877 | 877 | except OSError as inst: # nf not found on disk - it is dirstate only |
|
878 | 878 | if nf in dmap: # does it exactly match a missing file? |
|
879 | 879 | results[nf] = None |
|
880 | 880 | else: # does it match a missing directory? |
|
881 | 881 | if self._map.hasdir(nf): |
|
882 | 882 | notfoundadd(nf) |
|
883 | 883 | else: |
|
884 | 884 | badfn(ff, encoding.strtolocal(inst.strerror)) |
|
885 | 885 | |
|
886 | 886 | # match.files() may contain explicitly-specified paths that shouldn't |
|
887 | 887 | # be taken; drop them from the list of files found. dirsfound/notfound |
|
888 | 888 | # aren't filtered here because they will be tested later. |
|
889 | 889 | if match.anypats(): |
|
890 | 890 | for f in list(results): |
|
891 | 891 | if f == b'.hg' or f in subrepos: |
|
892 | 892 | # keep sentinel to disable further out-of-repo walks |
|
893 | 893 | continue |
|
894 | 894 | if not match(f): |
|
895 | 895 | del results[f] |
|
896 | 896 | |
|
897 | 897 | # Case insensitive filesystems cannot rely on lstat() failing to detect |
|
898 | 898 | # a case-only rename. Prune the stat object for any file that does not |
|
899 | 899 | # match the case in the filesystem, if there are multiple files that |
|
900 | 900 | # normalize to the same path. |
|
901 | 901 | if match.isexact() and self._checkcase: |
|
902 | 902 | normed = {} |
|
903 | 903 | |
|
904 | 904 | for f, st in pycompat.iteritems(results): |
|
905 | 905 | if st is None: |
|
906 | 906 | continue |
|
907 | 907 | |
|
908 | 908 | nc = util.normcase(f) |
|
909 | 909 | paths = normed.get(nc) |
|
910 | 910 | |
|
911 | 911 | if paths is None: |
|
912 | 912 | paths = set() |
|
913 | 913 | normed[nc] = paths |
|
914 | 914 | |
|
915 | 915 | paths.add(f) |
|
916 | 916 | |
|
917 | 917 | for norm, paths in pycompat.iteritems(normed): |
|
918 | 918 | if len(paths) > 1: |
|
919 | 919 | for path in paths: |
|
920 | 920 | folded = self._discoverpath( |
|
921 | 921 | path, norm, True, None, self._map.dirfoldmap |
|
922 | 922 | ) |
|
923 | 923 | if path != folded: |
|
924 | 924 | results[path] = None |
|
925 | 925 | |
|
926 | 926 | return results, dirsfound, dirsnotfound |
|
927 | 927 | |
|
928 | 928 | def walk(self, match, subrepos, unknown, ignored, full=True): |
|
929 | 929 | """ |
|
930 | 930 | Walk recursively through the directory tree, finding all files |
|
931 | 931 | matched by match. |
|
932 | 932 | |
|
933 | 933 | If full is False, maybe skip some known-clean files. |
|
934 | 934 | |
|
935 | 935 | Return a dict mapping filename to stat-like object (either |
|
936 | 936 | mercurial.osutil.stat instance or return value of os.stat()). |
|
937 | 937 | |
|
938 | 938 | """ |
|
939 | 939 | # full is a flag that extensions that hook into walk can use -- this |
|
940 | 940 | # implementation doesn't use it at all. This satisfies the contract |
|
941 | 941 | # because we only guarantee a "maybe". |
|
942 | 942 | |
|
943 | 943 | if ignored: |
|
944 | 944 | ignore = util.never |
|
945 | 945 | dirignore = util.never |
|
946 | 946 | elif unknown: |
|
947 | 947 | ignore = self._ignore |
|
948 | 948 | dirignore = self._dirignore |
|
949 | 949 | else: |
|
950 | 950 | # if not unknown and not ignored, drop dir recursion and step 2 |
|
951 | 951 | ignore = util.always |
|
952 | 952 | dirignore = util.always |
|
953 | 953 | |
|
954 | 954 | matchfn = match.matchfn |
|
955 | 955 | matchalways = match.always() |
|
956 | 956 | matchtdir = match.traversedir |
|
957 | 957 | dmap = self._map |
|
958 | 958 | listdir = util.listdir |
|
959 | 959 | lstat = os.lstat |
|
960 | 960 | dirkind = stat.S_IFDIR |
|
961 | 961 | regkind = stat.S_IFREG |
|
962 | 962 | lnkkind = stat.S_IFLNK |
|
963 | 963 | join = self._join |
|
964 | 964 | |
|
965 | 965 | exact = skipstep3 = False |
|
966 | 966 | if match.isexact(): # match.exact |
|
967 | 967 | exact = True |
|
968 | 968 | dirignore = util.always # skip step 2 |
|
969 | 969 | elif match.prefix(): # match.match, no patterns |
|
970 | 970 | skipstep3 = True |
|
971 | 971 | |
|
972 | 972 | if not exact and self._checkcase: |
|
973 | 973 | normalize = self._normalize |
|
974 | 974 | normalizefile = self._normalizefile |
|
975 | 975 | skipstep3 = False |
|
976 | 976 | else: |
|
977 | 977 | normalize = self._normalize |
|
978 | 978 | normalizefile = None |
|
979 | 979 | |
|
980 | 980 | # step 1: find all explicit files |
|
981 | 981 | results, work, dirsnotfound = self._walkexplicit(match, subrepos) |
|
982 | 982 | if matchtdir: |
|
983 | 983 | for d in work: |
|
984 | 984 | matchtdir(d[0]) |
|
985 | 985 | for d in dirsnotfound: |
|
986 | 986 | matchtdir(d) |
|
987 | 987 | |
|
988 | 988 | skipstep3 = skipstep3 and not (work or dirsnotfound) |
|
989 | 989 | work = [d for d in work if not dirignore(d[0])] |
|
990 | 990 | |
|
991 | 991 | # step 2: visit subdirectories |
|
992 | 992 | def traverse(work, alreadynormed): |
|
993 | 993 | wadd = work.append |
|
994 | 994 | while work: |
|
995 | 995 | tracing.counter('dirstate.walk work', len(work)) |
|
996 | 996 | nd = work.pop() |
|
997 | 997 | visitentries = match.visitchildrenset(nd) |
|
998 | 998 | if not visitentries: |
|
999 | 999 | continue |
|
1000 | 1000 | if visitentries == b'this' or visitentries == b'all': |
|
1001 | 1001 | visitentries = None |
|
1002 | 1002 | skip = None |
|
1003 | 1003 | if nd != b'': |
|
1004 | 1004 | skip = b'.hg' |
|
1005 | 1005 | try: |
|
1006 | 1006 | with tracing.log('dirstate.walk.traverse listdir %s', nd): |
|
1007 | 1007 | entries = listdir(join(nd), stat=True, skip=skip) |
|
1008 | 1008 | except OSError as inst: |
|
1009 | 1009 | if inst.errno in (errno.EACCES, errno.ENOENT): |
|
1010 | 1010 | match.bad( |
|
1011 | 1011 | self.pathto(nd), encoding.strtolocal(inst.strerror) |
|
1012 | 1012 | ) |
|
1013 | 1013 | continue |
|
1014 | 1014 | raise |
|
1015 | 1015 | for f, kind, st in entries: |
|
1016 | 1016 | # Some matchers may return files in the visitentries set, |
|
1017 | 1017 | # instead of 'this', if the matcher explicitly mentions them |
|
1018 | 1018 | # and is not an exactmatcher. This is acceptable; we do not |
|
1019 | 1019 | # make any hard assumptions about file-or-directory below |
|
1020 | 1020 | # based on the presence of `f` in visitentries. If |
|
1021 | 1021 | # visitchildrenset returned a set, we can always skip the |
|
1022 | 1022 | # entries *not* in the set it provided regardless of whether |
|
1023 | 1023 | # they're actually a file or a directory. |
|
1024 | 1024 | if visitentries and f not in visitentries: |
|
1025 | 1025 | continue |
|
1026 | 1026 | if normalizefile: |
|
1027 | 1027 | # even though f might be a directory, we're only |
|
1028 | 1028 | # interested in comparing it to files currently in the |
|
1029 | 1029 | # dmap -- therefore normalizefile is enough |
|
1030 | 1030 | nf = normalizefile( |
|
1031 | 1031 | nd and (nd + b"/" + f) or f, True, True |
|
1032 | 1032 | ) |
|
1033 | 1033 | else: |
|
1034 | 1034 | nf = nd and (nd + b"/" + f) or f |
|
1035 | 1035 | if nf not in results: |
|
1036 | 1036 | if kind == dirkind: |
|
1037 | 1037 | if not ignore(nf): |
|
1038 | 1038 | if matchtdir: |
|
1039 | 1039 | matchtdir(nf) |
|
1040 | 1040 | wadd(nf) |
|
1041 | 1041 | if nf in dmap and (matchalways or matchfn(nf)): |
|
1042 | 1042 | results[nf] = None |
|
1043 | 1043 | elif kind == regkind or kind == lnkkind: |
|
1044 | 1044 | if nf in dmap: |
|
1045 | 1045 | if matchalways or matchfn(nf): |
|
1046 | 1046 | results[nf] = st |
|
1047 | 1047 | elif (matchalways or matchfn(nf)) and not ignore( |
|
1048 | 1048 | nf |
|
1049 | 1049 | ): |
|
1050 | 1050 | # unknown file -- normalize if necessary |
|
1051 | 1051 | if not alreadynormed: |
|
1052 | 1052 | nf = normalize(nf, False, True) |
|
1053 | 1053 | results[nf] = st |
|
1054 | 1054 | elif nf in dmap and (matchalways or matchfn(nf)): |
|
1055 | 1055 | results[nf] = None |
|
1056 | 1056 | |
|
1057 | 1057 | for nd, d in work: |
|
1058 | 1058 | # alreadynormed means that processwork doesn't have to do any |
|
1059 | 1059 | # expensive directory normalization |
|
1060 | 1060 | alreadynormed = not normalize or nd == d |
|
1061 | 1061 | traverse([d], alreadynormed) |
|
1062 | 1062 | |
|
1063 | 1063 | for s in subrepos: |
|
1064 | 1064 | del results[s] |
|
1065 | 1065 | del results[b'.hg'] |
|
1066 | 1066 | |
|
1067 | 1067 | # step 3: visit remaining files from dmap |
|
1068 | 1068 | if not skipstep3 and not exact: |
|
1069 | 1069 | # If a dmap file is not in results yet, it was either |
|
1070 | 1070 | # a) not matching matchfn b) ignored, c) missing, or d) under a |
|
1071 | 1071 | # symlink directory. |
|
1072 | 1072 | if not results and matchalways: |
|
1073 | 1073 | visit = [f for f in dmap] |
|
1074 | 1074 | else: |
|
1075 | 1075 | visit = [f for f in dmap if f not in results and matchfn(f)] |
|
1076 | 1076 | visit.sort() |
|
1077 | 1077 | |
|
1078 | 1078 | if unknown: |
|
1079 | 1079 | # unknown == True means we walked all dirs under the roots |
|
1080 | 1080 | # that wasn't ignored, and everything that matched was stat'ed |
|
1081 | 1081 | # and is already in results. |
|
1082 | 1082 | # The rest must thus be ignored or under a symlink. |
|
1083 | 1083 | audit_path = pathutil.pathauditor(self._root, cached=True) |
|
1084 | 1084 | |
|
1085 | 1085 | for nf in iter(visit): |
|
1086 | 1086 | # If a stat for the same file was already added with a |
|
1087 | 1087 | # different case, don't add one for this, since that would |
|
1088 | 1088 | # make it appear as if the file exists under both names |
|
1089 | 1089 | # on disk. |
|
1090 | 1090 | if ( |
|
1091 | 1091 | normalizefile |
|
1092 | 1092 | and normalizefile(nf, True, True) in results |
|
1093 | 1093 | ): |
|
1094 | 1094 | results[nf] = None |
|
1095 | 1095 | # Report ignored items in the dmap as long as they are not |
|
1096 | 1096 | # under a symlink directory. |
|
1097 | 1097 | elif audit_path.check(nf): |
|
1098 | 1098 | try: |
|
1099 | 1099 | results[nf] = lstat(join(nf)) |
|
1100 | 1100 | # file was just ignored, no links, and exists |
|
1101 | 1101 | except OSError: |
|
1102 | 1102 | # file doesn't exist |
|
1103 | 1103 | results[nf] = None |
|
1104 | 1104 | else: |
|
1105 | 1105 | # It's either missing or under a symlink directory |
|
1106 | 1106 | # which we in this case report as missing |
|
1107 | 1107 | results[nf] = None |
|
1108 | 1108 | else: |
|
1109 | 1109 | # We may not have walked the full directory tree above, |
|
1110 | 1110 | # so stat and check everything we missed. |
|
1111 | 1111 | iv = iter(visit) |
|
1112 | 1112 | for st in util.statfiles([join(i) for i in visit]): |
|
1113 | 1113 | results[next(iv)] = st |
|
1114 | 1114 | return results |
|
1115 | 1115 | |
|
1116 | 1116 | def _rust_status(self, matcher, list_clean, list_ignored, list_unknown): |
|
1117 | 1117 | # Force Rayon (Rust parallelism library) to respect the number of |
|
1118 | 1118 | # workers. This is a temporary workaround until Rust code knows |
|
1119 | 1119 | # how to read the config file. |
|
1120 | 1120 | numcpus = self._ui.configint(b"worker", b"numcpus") |
|
1121 | 1121 | if numcpus is not None: |
|
1122 | 1122 | encoding.environ.setdefault(b'RAYON_NUM_THREADS', b'%d' % numcpus) |
|
1123 | 1123 | |
|
1124 | 1124 | workers_enabled = self._ui.configbool(b"worker", b"enabled", True) |
|
1125 | 1125 | if not workers_enabled: |
|
1126 | 1126 | encoding.environ[b"RAYON_NUM_THREADS"] = b"1" |
|
1127 | 1127 | |
|
1128 | 1128 | ( |
|
1129 | 1129 | lookup, |
|
1130 | 1130 | modified, |
|
1131 | 1131 | added, |
|
1132 | 1132 | removed, |
|
1133 | 1133 | deleted, |
|
1134 | 1134 | clean, |
|
1135 | 1135 | ignored, |
|
1136 | 1136 | unknown, |
|
1137 | 1137 | warnings, |
|
1138 | 1138 | bad, |
|
1139 | 1139 | traversed, |
|
1140 | 1140 | ) = rustmod.status( |
|
1141 | 1141 | self._map._rustmap, |
|
1142 | 1142 | matcher, |
|
1143 | 1143 | self._rootdir, |
|
1144 | 1144 | self._ignorefiles(), |
|
1145 | 1145 | self._checkexec, |
|
1146 | 1146 | self._lastnormaltime, |
|
1147 | 1147 | bool(list_clean), |
|
1148 | 1148 | bool(list_ignored), |
|
1149 | 1149 | bool(list_unknown), |
|
1150 | 1150 | bool(matcher.traversedir), |
|
1151 | 1151 | ) |
|
1152 | 1152 | |
|
1153 | 1153 | if matcher.traversedir: |
|
1154 | 1154 | for dir in traversed: |
|
1155 | 1155 | matcher.traversedir(dir) |
|
1156 | 1156 | |
|
1157 | 1157 | if self._ui.warn: |
|
1158 | 1158 | for item in warnings: |
|
1159 | 1159 | if isinstance(item, tuple): |
|
1160 | 1160 | file_path, syntax = item |
|
1161 | 1161 | msg = _(b"%s: ignoring invalid syntax '%s'\n") % ( |
|
1162 | 1162 | file_path, |
|
1163 | 1163 | syntax, |
|
1164 | 1164 | ) |
|
1165 | 1165 | self._ui.warn(msg) |
|
1166 | 1166 | else: |
|
1167 | 1167 | msg = _(b"skipping unreadable pattern file '%s': %s\n") |
|
1168 | 1168 | self._ui.warn( |
|
1169 | 1169 | msg |
|
1170 | 1170 | % ( |
|
1171 | 1171 | pathutil.canonpath( |
|
1172 | 1172 | self._rootdir, self._rootdir, item |
|
1173 | 1173 | ), |
|
1174 | 1174 | b"No such file or directory", |
|
1175 | 1175 | ) |
|
1176 | 1176 | ) |
|
1177 | 1177 | |
|
1178 | 1178 | for (fn, message) in bad: |
|
1179 | 1179 | matcher.bad(fn, encoding.strtolocal(message)) |
|
1180 | 1180 | |
|
1181 | 1181 | status = scmutil.status( |
|
1182 | 1182 | modified=modified, |
|
1183 | 1183 | added=added, |
|
1184 | 1184 | removed=removed, |
|
1185 | 1185 | deleted=deleted, |
|
1186 | 1186 | unknown=unknown, |
|
1187 | 1187 | ignored=ignored, |
|
1188 | 1188 | clean=clean, |
|
1189 | 1189 | ) |
|
1190 | 1190 | return (lookup, status) |
|
1191 | 1191 | |
|
1192 | 1192 | def status(self, match, subrepos, ignored, clean, unknown): |
|
1193 | 1193 | """Determine the status of the working copy relative to the |
|
1194 | 1194 | dirstate and return a pair of (unsure, status), where status is of type |
|
1195 | 1195 | scmutil.status and: |
|
1196 | 1196 | |
|
1197 | 1197 | unsure: |
|
1198 | 1198 | files that might have been modified since the dirstate was |
|
1199 | 1199 | written, but need to be read to be sure (size is the same |
|
1200 | 1200 | but mtime differs) |
|
1201 | 1201 | status.modified: |
|
1202 | 1202 | files that have definitely been modified since the dirstate |
|
1203 | 1203 | was written (different size or mode) |
|
1204 | 1204 | status.clean: |
|
1205 | 1205 | files that have definitely not been modified since the |
|
1206 | 1206 | dirstate was written |
|
1207 | 1207 | """ |
|
1208 | 1208 | listignored, listclean, listunknown = ignored, clean, unknown |
|
1209 | 1209 | lookup, modified, added, unknown, ignored = [], [], [], [], [] |
|
1210 | 1210 | removed, deleted, clean = [], [], [] |
|
1211 | 1211 | |
|
1212 | 1212 | dmap = self._map |
|
1213 | 1213 | dmap.preload() |
|
1214 | 1214 | |
|
1215 | 1215 | use_rust = True |
|
1216 | 1216 | |
|
1217 | 1217 | allowed_matchers = ( |
|
1218 | 1218 | matchmod.alwaysmatcher, |
|
1219 | 1219 | matchmod.exactmatcher, |
|
1220 | 1220 | matchmod.includematcher, |
|
1221 | 1221 | ) |
|
1222 | 1222 | |
|
1223 | 1223 | if rustmod is None: |
|
1224 | 1224 | use_rust = False |
|
1225 | 1225 | elif self._checkcase: |
|
1226 | 1226 | # Case-insensitive filesystems are not handled yet |
|
1227 | 1227 | use_rust = False |
|
1228 | 1228 | elif subrepos: |
|
1229 | 1229 | use_rust = False |
|
1230 | 1230 | elif sparse.enabled: |
|
1231 | 1231 | use_rust = False |
|
1232 | 1232 | elif not isinstance(match, allowed_matchers): |
|
1233 | 1233 | # Some matchers have yet to be implemented |
|
1234 | 1234 | use_rust = False |
|
1235 | 1235 | |
|
1236 | 1236 | if use_rust: |
|
1237 | 1237 | try: |
|
1238 | 1238 | return self._rust_status( |
|
1239 | 1239 | match, listclean, listignored, listunknown |
|
1240 | 1240 | ) |
|
1241 | 1241 | except rustmod.FallbackError: |
|
1242 | 1242 | pass |
|
1243 | 1243 | |
|
1244 | 1244 | def noop(f): |
|
1245 | 1245 | pass |
|
1246 | 1246 | |
|
1247 | 1247 | dcontains = dmap.__contains__ |
|
1248 | 1248 | dget = dmap.__getitem__ |
|
1249 | 1249 | ladd = lookup.append # aka "unsure" |
|
1250 | 1250 | madd = modified.append |
|
1251 | 1251 | aadd = added.append |
|
1252 | 1252 | uadd = unknown.append if listunknown else noop |
|
1253 | 1253 | iadd = ignored.append if listignored else noop |
|
1254 | 1254 | radd = removed.append |
|
1255 | 1255 | dadd = deleted.append |
|
1256 | 1256 | cadd = clean.append if listclean else noop |
|
1257 | 1257 | mexact = match.exact |
|
1258 | 1258 | dirignore = self._dirignore |
|
1259 | 1259 | checkexec = self._checkexec |
|
1260 | 1260 | copymap = self._map.copymap |
|
1261 | 1261 | lastnormaltime = self._lastnormaltime |
|
1262 | 1262 | |
|
1263 | 1263 | # We need to do full walks when either |
|
1264 | 1264 | # - we're listing all clean files, or |
|
1265 | 1265 | # - match.traversedir does something, because match.traversedir should |
|
1266 | 1266 | # be called for every dir in the working dir |
|
1267 | 1267 | full = listclean or match.traversedir is not None |
|
1268 | 1268 | for fn, st in pycompat.iteritems( |
|
1269 | 1269 | self.walk(match, subrepos, listunknown, listignored, full=full) |
|
1270 | 1270 | ): |
|
1271 | 1271 | if not dcontains(fn): |
|
1272 | 1272 | if (listignored or mexact(fn)) and dirignore(fn): |
|
1273 | 1273 | if listignored: |
|
1274 | 1274 | iadd(fn) |
|
1275 | 1275 | else: |
|
1276 | 1276 | uadd(fn) |
|
1277 | 1277 | continue |
|
1278 | 1278 | |
|
1279 | 1279 | # This is equivalent to 'state, mode, size, time = dmap[fn]' but not |
|
1280 | 1280 | # written like that for performance reasons. dmap[fn] is not a |
|
1281 | 1281 | # Python tuple in compiled builds. The CPython UNPACK_SEQUENCE |
|
1282 | 1282 | # opcode has fast paths when the value to be unpacked is a tuple or |
|
1283 | 1283 | # a list, but falls back to creating a full-fledged iterator in |
|
1284 | 1284 | # general. That is much slower than simply accessing and storing the |
|
1285 | 1285 | # tuple members one by one. |
|
1286 | 1286 | t = dget(fn) |
|
1287 | 1287 | state = t[0] |
|
1288 | 1288 | mode = t[1] |
|
1289 | 1289 | size = t[2] |
|
1290 | 1290 | time = t[3] |
|
1291 | 1291 | |
|
1292 | 1292 | if not st and state in b"nma": |
|
1293 | 1293 | dadd(fn) |
|
1294 | 1294 | elif state == b'n': |
|
1295 | 1295 | if ( |
|
1296 | 1296 | size >= 0 |
|
1297 | 1297 | and ( |
|
1298 | 1298 | (size != st.st_size and size != st.st_size & _rangemask) |
|
1299 | 1299 | or ((mode ^ st.st_mode) & 0o100 and checkexec) |
|
1300 | 1300 | ) |
|
1301 | 1301 | or size == -2 # other parent |
|
1302 | 1302 | or fn in copymap |
|
1303 | 1303 | ): |
|
1304 | 1304 | if stat.S_ISLNK(st.st_mode) and size != st.st_size: |
|
1305 | 1305 | # issue6456: Size returned may be longer due to |
|
1306 | 1306 | # encryption on EXT-4 fscrypt, undecided. |
|
1307 | 1307 | ladd(fn) |
|
1308 | 1308 | else: |
|
1309 | 1309 | madd(fn) |
|
1310 | 1310 | elif ( |
|
1311 | 1311 | time != st[stat.ST_MTIME] |
|
1312 | 1312 | and time != st[stat.ST_MTIME] & _rangemask |
|
1313 | 1313 | ): |
|
1314 | 1314 | ladd(fn) |
|
1315 | 1315 | elif st[stat.ST_MTIME] == lastnormaltime: |
|
1316 | 1316 | # fn may have just been marked as normal and it may have |
|
1317 | 1317 | # changed in the same second without changing its size. |
|
1318 | 1318 | # This can happen if we quickly do multiple commits. |
|
1319 | 1319 | # Force lookup, so we don't miss such a racy file change. |
|
1320 | 1320 | ladd(fn) |
|
1321 | 1321 | elif listclean: |
|
1322 | 1322 | cadd(fn) |
|
1323 | 1323 | elif state == b'm': |
|
1324 | 1324 | madd(fn) |
|
1325 | 1325 | elif state == b'a': |
|
1326 | 1326 | aadd(fn) |
|
1327 | 1327 | elif state == b'r': |
|
1328 | 1328 | radd(fn) |
|
1329 | 1329 | status = scmutil.status( |
|
1330 | 1330 | modified, added, removed, deleted, unknown, ignored, clean |
|
1331 | 1331 | ) |
|
1332 | 1332 | return (lookup, status) |
|
1333 | 1333 | |
|
1334 | 1334 | def matches(self, match): |
|
1335 | 1335 | """ |
|
1336 | 1336 | return files in the dirstate (in whatever state) filtered by match |
|
1337 | 1337 | """ |
|
1338 | 1338 | dmap = self._map |
|
1339 | 1339 | if rustmod is not None: |
|
1340 | 1340 | dmap = self._map._rustmap |
|
1341 | 1341 | |
|
1342 | 1342 | if match.always(): |
|
1343 | 1343 | return dmap.keys() |
|
1344 | 1344 | files = match.files() |
|
1345 | 1345 | if match.isexact(): |
|
1346 | 1346 | # fast path -- filter the other way around, since typically files is |
|
1347 | 1347 | # much smaller than dmap |
|
1348 | 1348 | return [f for f in files if f in dmap] |
|
1349 | 1349 | if match.prefix() and all(fn in dmap for fn in files): |
|
1350 | 1350 | # fast path -- all the values are known to be files, so just return |
|
1351 | 1351 | # that |
|
1352 | 1352 | return list(files) |
|
1353 | 1353 | return [f for f in dmap if match(f)] |
|
1354 | 1354 | |
|
1355 | 1355 | def _actualfilename(self, tr): |
|
1356 | 1356 | if tr: |
|
1357 | 1357 | return self._pendingfilename |
|
1358 | 1358 | else: |
|
1359 | 1359 | return self._filename |
|
1360 | 1360 | |
|
1361 | 1361 | def savebackup(self, tr, backupname): |
|
1362 | 1362 | '''Save current dirstate into backup file''' |
|
1363 | 1363 | filename = self._actualfilename(tr) |
|
1364 | 1364 | assert backupname != filename |
|
1365 | 1365 | |
|
1366 | 1366 | # use '_writedirstate' instead of 'write' to write changes certainly, |
|
1367 | 1367 | # because the latter omits writing out if transaction is running. |
|
1368 | 1368 | # output file will be used to create backup of dirstate at this point. |
|
1369 | 1369 | if self._dirty or not self._opener.exists(filename): |
|
1370 | 1370 | self._writedirstate( |
|
1371 | 1371 | self._opener(filename, b"w", atomictemp=True, checkambig=True) |
|
1372 | 1372 | ) |
|
1373 | 1373 | |
|
1374 | 1374 | if tr: |
|
1375 | 1375 | # ensure that subsequent tr.writepending returns True for |
|
1376 | 1376 | # changes written out above, even if dirstate is never |
|
1377 | 1377 | # changed after this |
|
1378 | 1378 | tr.addfilegenerator( |
|
1379 | 1379 | b'dirstate', |
|
1380 | 1380 | (self._filename,), |
|
1381 | 1381 | self._writedirstate, |
|
1382 | 1382 | location=b'plain', |
|
1383 | 1383 | ) |
|
1384 | 1384 | |
|
1385 | 1385 | # ensure that pending file written above is unlinked at |
|
1386 | 1386 | # failure, even if tr.writepending isn't invoked until the |
|
1387 | 1387 | # end of this transaction |
|
1388 | 1388 | tr.registertmp(filename, location=b'plain') |
|
1389 | 1389 | |
|
1390 | 1390 | self._opener.tryunlink(backupname) |
|
1391 | 1391 | # hardlink backup is okay because _writedirstate is always called |
|
1392 | 1392 | # with an "atomictemp=True" file. |
|
1393 | 1393 | util.copyfile( |
|
1394 | 1394 | self._opener.join(filename), |
|
1395 | 1395 | self._opener.join(backupname), |
|
1396 | 1396 | hardlink=True, |
|
1397 | 1397 | ) |
|
1398 | 1398 | |
|
1399 | 1399 | def restorebackup(self, tr, backupname): |
|
1400 | 1400 | '''Restore dirstate by backup file''' |
|
1401 | 1401 | # this "invalidate()" prevents "wlock.release()" from writing |
|
1402 | 1402 | # changes of dirstate out after restoring from backup file |
|
1403 | 1403 | self.invalidate() |
|
1404 | 1404 | filename = self._actualfilename(tr) |
|
1405 | 1405 | o = self._opener |
|
1406 | 1406 | if util.samefile(o.join(backupname), o.join(filename)): |
|
1407 | 1407 | o.unlink(backupname) |
|
1408 | 1408 | else: |
|
1409 | 1409 | o.rename(backupname, filename, checkambig=True) |
|
1410 | 1410 | |
|
1411 | 1411 | def clearbackup(self, tr, backupname): |
|
1412 | 1412 | '''Clear backup file''' |
|
1413 | 1413 | self._opener.unlink(backupname) |
|
1414 | 1414 | |
|
1415 | 1415 | |
|
1416 | 1416 | class dirstatemap(object): |
|
1417 | 1417 | """Map encapsulating the dirstate's contents. |
|
1418 | 1418 | |
|
1419 | 1419 | The dirstate contains the following state: |
|
1420 | 1420 | |
|
1421 | 1421 | - `identity` is the identity of the dirstate file, which can be used to |
|
1422 | 1422 | detect when changes have occurred to the dirstate file. |
|
1423 | 1423 | |
|
1424 | 1424 | - `parents` is a pair containing the parents of the working copy. The |
|
1425 | 1425 | parents are updated by calling `setparents`. |
|
1426 | 1426 | |
|
1427 | 1427 | - the state map maps filenames to tuples of (state, mode, size, mtime), |
|
1428 | 1428 | where state is a single character representing 'normal', 'added', |
|
1429 | 1429 | 'removed', or 'merged'. It is read by treating the dirstate as a |
|
1430 | 1430 | dict. File state is updated by calling the `addfile`, `removefile` and |
|
1431 | 1431 | `dropfile` methods. |
|
1432 | 1432 | |
|
1433 | 1433 | - `copymap` maps destination filenames to their source filename. |
|
1434 | 1434 | |
|
1435 | 1435 | The dirstate also provides the following views onto the state: |
|
1436 | 1436 | |
|
1437 | 1437 | - `nonnormalset` is a set of the filenames that have state other |
|
1438 | 1438 | than 'normal', or are normal but have an mtime of -1 ('normallookup'). |
|
1439 | 1439 | |
|
1440 | 1440 | - `otherparentset` is a set of the filenames that are marked as coming |
|
1441 | 1441 | from the second parent when the dirstate is currently being merged. |
|
1442 | 1442 | |
|
1443 | 1443 | - `filefoldmap` is a dict mapping normalized filenames to the denormalized |
|
1444 | 1444 | form that they appear as in the dirstate. |
|
1445 | 1445 | |
|
1446 | 1446 | - `dirfoldmap` is a dict mapping normalized directory names to the |
|
1447 | 1447 | denormalized form that they appear as in the dirstate. |
|
1448 | 1448 | """ |
|
1449 | 1449 | |
|
1450 | 1450 | def __init__(self, ui, opener, root, nodeconstants, use_dirstate_v2): |
|
1451 | 1451 | self._ui = ui |
|
1452 | 1452 | self._opener = opener |
|
1453 | 1453 | self._root = root |
|
1454 | 1454 | self._filename = b'dirstate' |
|
1455 | 1455 | self._nodelen = 20 |
|
1456 | 1456 | self._nodeconstants = nodeconstants |
|
1457 | 1457 | assert ( |
|
1458 | 1458 | not use_dirstate_v2 |
|
1459 | 1459 | ), "should have detected unsupported requirement" |
|
1460 | 1460 | |
|
1461 | 1461 | self._parents = None |
|
1462 | 1462 | self._dirtyparents = False |
|
1463 | 1463 | |
|
1464 | 1464 | # for consistent view between _pl() and _read() invocations |
|
1465 | 1465 | self._pendingmode = None |
|
1466 | 1466 | |
|
1467 | 1467 | @propertycache |
|
1468 | 1468 | def _map(self): |
|
1469 | 1469 | self._map = {} |
|
1470 | 1470 | self.read() |
|
1471 | 1471 | return self._map |
|
1472 | 1472 | |
|
1473 | 1473 | @propertycache |
|
1474 | 1474 | def copymap(self): |
|
1475 | 1475 | self.copymap = {} |
|
1476 | 1476 | self._map |
|
1477 | 1477 | return self.copymap |
|
1478 | 1478 | |
|
1479 | 1479 | def clear(self): |
|
1480 | 1480 | self._map.clear() |
|
1481 | 1481 | self.copymap.clear() |
|
1482 | 1482 | self.setparents(self._nodeconstants.nullid, self._nodeconstants.nullid) |
|
1483 | 1483 | util.clearcachedproperty(self, b"_dirs") |
|
1484 | 1484 | util.clearcachedproperty(self, b"_alldirs") |
|
1485 | 1485 | util.clearcachedproperty(self, b"filefoldmap") |
|
1486 | 1486 | util.clearcachedproperty(self, b"dirfoldmap") |
|
1487 | 1487 | util.clearcachedproperty(self, b"nonnormalset") |
|
1488 | 1488 | util.clearcachedproperty(self, b"otherparentset") |
|
1489 | 1489 | |
|
1490 | 1490 | def items(self): |
|
1491 | 1491 | return pycompat.iteritems(self._map) |
|
1492 | 1492 | |
|
1493 | 1493 | # forward for python2,3 compat |
|
1494 | 1494 | iteritems = items |
|
1495 | 1495 | |
|
1496 | 1496 | def __len__(self): |
|
1497 | 1497 | return len(self._map) |
|
1498 | 1498 | |
|
1499 | 1499 | def __iter__(self): |
|
1500 | 1500 | return iter(self._map) |
|
1501 | 1501 | |
|
1502 | 1502 | def get(self, key, default=None): |
|
1503 | 1503 | return self._map.get(key, default) |
|
1504 | 1504 | |
|
1505 | 1505 | def __contains__(self, key): |
|
1506 | 1506 | return key in self._map |
|
1507 | 1507 | |
|
1508 | 1508 | def __getitem__(self, key): |
|
1509 | 1509 | return self._map[key] |
|
1510 | 1510 | |
|
1511 | 1511 | def keys(self): |
|
1512 | 1512 | return self._map.keys() |
|
1513 | 1513 | |
|
1514 | 1514 | def preload(self): |
|
1515 | 1515 | """Loads the underlying data, if it's not already loaded""" |
|
1516 | 1516 | self._map |
|
1517 | 1517 | |
|
1518 | 1518 | def addfile(self, f, oldstate, state, mode, size, mtime): |
|
1519 | 1519 | """Add a tracked file to the dirstate.""" |
|
1520 | 1520 | if oldstate in b"?r" and "_dirs" in self.__dict__: |
|
1521 | 1521 | self._dirs.addpath(f) |
|
1522 | 1522 | if oldstate == b"?" and "_alldirs" in self.__dict__: |
|
1523 | 1523 | self._alldirs.addpath(f) |
|
1524 | 1524 | self._map[f] = dirstatetuple(state, mode, size, mtime) |
|
1525 | 1525 | if state != b'n' or mtime == -1: |
|
1526 | 1526 | self.nonnormalset.add(f) |
|
1527 | 1527 | if size == -2: |
|
1528 | 1528 | self.otherparentset.add(f) |
|
1529 | 1529 | |
|
1530 | 1530 | def removefile(self, f, oldstate, size): |
|
1531 | 1531 | """ |
|
1532 | 1532 | Mark a file as removed in the dirstate. |
|
1533 | 1533 | |
|
1534 | 1534 | The `size` parameter is used to store sentinel values that indicate |
|
1535 | 1535 | the file's previous state. In the future, we should refactor this |
|
1536 | 1536 | to be more explicit about what that state is. |
|
1537 | 1537 | """ |
|
1538 | 1538 | if oldstate not in b"?r" and "_dirs" in self.__dict__: |
|
1539 | 1539 | self._dirs.delpath(f) |
|
1540 | 1540 | if oldstate == b"?" and "_alldirs" in self.__dict__: |
|
1541 | 1541 | self._alldirs.addpath(f) |
|
1542 | 1542 | if "filefoldmap" in self.__dict__: |
|
1543 | 1543 | normed = util.normcase(f) |
|
1544 | 1544 | self.filefoldmap.pop(normed, None) |
|
1545 | 1545 | self._map[f] = dirstatetuple(b'r', 0, size, 0) |
|
1546 | 1546 | self.nonnormalset.add(f) |
|
1547 | 1547 | |
|
1548 | 1548 | def dropfile(self, f, oldstate): |
|
1549 | 1549 | """ |
|
1550 | 1550 | Remove a file from the dirstate. Returns True if the file was |
|
1551 | 1551 | previously recorded. |
|
1552 | 1552 | """ |
|
1553 | 1553 | exists = self._map.pop(f, None) is not None |
|
1554 | 1554 | if exists: |
|
1555 | 1555 | if oldstate != b"r" and "_dirs" in self.__dict__: |
|
1556 | 1556 | self._dirs.delpath(f) |
|
1557 | 1557 | if "_alldirs" in self.__dict__: |
|
1558 | 1558 | self._alldirs.delpath(f) |
|
1559 | 1559 | if "filefoldmap" in self.__dict__: |
|
1560 | 1560 | normed = util.normcase(f) |
|
1561 | 1561 | self.filefoldmap.pop(normed, None) |
|
1562 | 1562 | self.nonnormalset.discard(f) |
|
1563 | 1563 | return exists |
|
1564 | 1564 | |
|
1565 | 1565 | def clearambiguoustimes(self, files, now): |
|
1566 | 1566 | for f in files: |
|
1567 | 1567 | e = self.get(f) |
|
1568 | 1568 | if e is not None and e[0] == b'n' and e[3] == now: |
|
1569 | 1569 | self._map[f] = dirstatetuple(e[0], e[1], e[2], -1) |
|
1570 | 1570 | self.nonnormalset.add(f) |
|
1571 | 1571 | |
|
1572 | 1572 | def nonnormalentries(self): |
|
1573 | 1573 | '''Compute the nonnormal dirstate entries from the dmap''' |
|
1574 | 1574 | try: |
|
1575 | 1575 | return parsers.nonnormalotherparententries(self._map) |
|
1576 | 1576 | except AttributeError: |
|
1577 | 1577 | nonnorm = set() |
|
1578 | 1578 | otherparent = set() |
|
1579 | 1579 | for fname, e in pycompat.iteritems(self._map): |
|
1580 | 1580 | if e[0] != b'n' or e[3] == -1: |
|
1581 | 1581 | nonnorm.add(fname) |
|
1582 | 1582 | if e[0] == b'n' and e[2] == -2: |
|
1583 | 1583 | otherparent.add(fname) |
|
1584 | 1584 | return nonnorm, otherparent |
|
1585 | 1585 | |
|
1586 | 1586 | @propertycache |
|
1587 | 1587 | def filefoldmap(self): |
|
1588 | 1588 | """Returns a dictionary mapping normalized case paths to their |
|
1589 | 1589 | non-normalized versions. |
|
1590 | 1590 | """ |
|
1591 | 1591 | try: |
|
1592 | 1592 | makefilefoldmap = parsers.make_file_foldmap |
|
1593 | 1593 | except AttributeError: |
|
1594 | 1594 | pass |
|
1595 | 1595 | else: |
|
1596 | 1596 | return makefilefoldmap( |
|
1597 | 1597 | self._map, util.normcasespec, util.normcasefallback |
|
1598 | 1598 | ) |
|
1599 | 1599 | |
|
1600 | 1600 | f = {} |
|
1601 | 1601 | normcase = util.normcase |
|
1602 | 1602 | for name, s in pycompat.iteritems(self._map): |
|
1603 | 1603 | if s[0] != b'r': |
|
1604 | 1604 | f[normcase(name)] = name |
|
1605 | 1605 | f[b'.'] = b'.' # prevents useless util.fspath() invocation |
|
1606 | 1606 | return f |
|
1607 | 1607 | |
|
1608 | 1608 | def hastrackeddir(self, d): |
|
1609 | 1609 | """ |
|
1610 | 1610 | Returns True if the dirstate contains a tracked (not removed) file |
|
1611 | 1611 | in this directory. |
|
1612 | 1612 | """ |
|
1613 | 1613 | return d in self._dirs |
|
1614 | 1614 | |
|
1615 | 1615 | def hasdir(self, d): |
|
1616 | 1616 | """ |
|
1617 | 1617 | Returns True if the dirstate contains a file (tracked or removed) |
|
1618 | 1618 | in this directory. |
|
1619 | 1619 | """ |
|
1620 | 1620 | return d in self._alldirs |
|
1621 | 1621 | |
|
1622 | 1622 | @propertycache |
|
1623 | 1623 | def _dirs(self): |
|
1624 | 1624 | return pathutil.dirs(self._map, b'r') |
|
1625 | 1625 | |
|
1626 | 1626 | @propertycache |
|
1627 | 1627 | def _alldirs(self): |
|
1628 | 1628 | return pathutil.dirs(self._map) |
|
1629 | 1629 | |
|
1630 | 1630 | def _opendirstatefile(self): |
|
1631 | 1631 | fp, mode = txnutil.trypending(self._root, self._opener, self._filename) |
|
1632 | 1632 | if self._pendingmode is not None and self._pendingmode != mode: |
|
1633 | 1633 | fp.close() |
|
1634 | 1634 | raise error.Abort( |
|
1635 | 1635 | _(b'working directory state may be changed parallelly') |
|
1636 | 1636 | ) |
|
1637 | 1637 | self._pendingmode = mode |
|
1638 | 1638 | return fp |
|
1639 | 1639 | |
|
1640 | 1640 | def parents(self): |
|
1641 | 1641 | if not self._parents: |
|
1642 | 1642 | try: |
|
1643 | 1643 | fp = self._opendirstatefile() |
|
1644 | 1644 | st = fp.read(2 * self._nodelen) |
|
1645 | 1645 | fp.close() |
|
1646 | 1646 | except IOError as err: |
|
1647 | 1647 | if err.errno != errno.ENOENT: |
|
1648 | 1648 | raise |
|
1649 | 1649 | # File doesn't exist, so the current state is empty |
|
1650 | 1650 | st = b'' |
|
1651 | 1651 | |
|
1652 | 1652 | l = len(st) |
|
1653 | 1653 | if l == self._nodelen * 2: |
|
1654 | 1654 | self._parents = ( |
|
1655 | 1655 | st[: self._nodelen], |
|
1656 | 1656 | st[self._nodelen : 2 * self._nodelen], |
|
1657 | 1657 | ) |
|
1658 | 1658 | elif l == 0: |
|
1659 | 1659 | self._parents = ( |
|
1660 | 1660 | self._nodeconstants.nullid, |
|
1661 | 1661 | self._nodeconstants.nullid, |
|
1662 | 1662 | ) |
|
1663 | 1663 | else: |
|
1664 | 1664 | raise error.Abort( |
|
1665 | 1665 | _(b'working directory state appears damaged!') |
|
1666 | 1666 | ) |
|
1667 | 1667 | |
|
1668 | 1668 | return self._parents |
|
1669 | 1669 | |
|
1670 | 1670 | def setparents(self, p1, p2): |
|
1671 | 1671 | self._parents = (p1, p2) |
|
1672 | 1672 | self._dirtyparents = True |
|
1673 | 1673 | |
|
1674 | 1674 | def read(self): |
|
1675 | 1675 | # ignore HG_PENDING because identity is used only for writing |
|
1676 | 1676 | self.identity = util.filestat.frompath( |
|
1677 | 1677 | self._opener.join(self._filename) |
|
1678 | 1678 | ) |
|
1679 | 1679 | |
|
1680 | 1680 | try: |
|
1681 | 1681 | fp = self._opendirstatefile() |
|
1682 | 1682 | try: |
|
1683 | 1683 | st = fp.read() |
|
1684 | 1684 | finally: |
|
1685 | 1685 | fp.close() |
|
1686 | 1686 | except IOError as err: |
|
1687 | 1687 | if err.errno != errno.ENOENT: |
|
1688 | 1688 | raise |
|
1689 | 1689 | return |
|
1690 | 1690 | if not st: |
|
1691 | 1691 | return |
|
1692 | 1692 | |
|
1693 | 1693 | if util.safehasattr(parsers, b'dict_new_presized'): |
|
1694 | 1694 | # Make an estimate of the number of files in the dirstate based on |
|
1695 | 1695 | # its size. This trades wasting some memory for avoiding costly |
|
1696 | 1696 | # resizes. Each entry have a prefix of 17 bytes followed by one or |
|
1697 | 1697 | # two path names. Studies on various large-scale real-world repositories |
|
1698 | 1698 | # found 54 bytes a reasonable upper limit for the average path names. |
|
1699 | 1699 | # Copy entries are ignored for the sake of this estimate. |
|
1700 | 1700 | self._map = parsers.dict_new_presized(len(st) // 71) |
|
1701 | 1701 | |
|
1702 | 1702 | # Python's garbage collector triggers a GC each time a certain number |
|
1703 | 1703 | # of container objects (the number being defined by |
|
1704 | 1704 | # gc.get_threshold()) are allocated. parse_dirstate creates a tuple |
|
1705 | 1705 | # for each file in the dirstate. The C version then immediately marks |
|
1706 | 1706 | # them as not to be tracked by the collector. However, this has no |
|
1707 | 1707 | # effect on when GCs are triggered, only on what objects the GC looks |
|
1708 | 1708 | # into. This means that O(number of files) GCs are unavoidable. |
|
1709 | 1709 | # Depending on when in the process's lifetime the dirstate is parsed, |
|
1710 | 1710 | # this can get very expensive. As a workaround, disable GC while |
|
1711 | 1711 | # parsing the dirstate. |
|
1712 | 1712 | # |
|
1713 | 1713 | # (we cannot decorate the function directly since it is in a C module) |
|
1714 | 1714 | parse_dirstate = util.nogc(parsers.parse_dirstate) |
|
1715 | 1715 | p = parse_dirstate(self._map, self.copymap, st) |
|
1716 | 1716 | if not self._dirtyparents: |
|
1717 | 1717 | self.setparents(*p) |
|
1718 | 1718 | |
|
1719 | 1719 | # Avoid excess attribute lookups by fast pathing certain checks |
|
1720 | 1720 | self.__contains__ = self._map.__contains__ |
|
1721 | 1721 | self.__getitem__ = self._map.__getitem__ |
|
1722 | 1722 | self.get = self._map.get |
|
1723 | 1723 | |
|
1724 | 1724 | def write(self, st, now): |
|
1725 | 1725 | st.write( |
|
1726 | 1726 | parsers.pack_dirstate(self._map, self.copymap, self.parents(), now) |
|
1727 | 1727 | ) |
|
1728 | 1728 | st.close() |
|
1729 | 1729 | self._dirtyparents = False |
|
1730 | 1730 | self.nonnormalset, self.otherparentset = self.nonnormalentries() |
|
1731 | 1731 | |
|
1732 | 1732 | @propertycache |
|
1733 | 1733 | def nonnormalset(self): |
|
1734 | 1734 | nonnorm, otherparents = self.nonnormalentries() |
|
1735 | 1735 | self.otherparentset = otherparents |
|
1736 | 1736 | return nonnorm |
|
1737 | 1737 | |
|
1738 | 1738 | @propertycache |
|
1739 | 1739 | def otherparentset(self): |
|
1740 | 1740 | nonnorm, otherparents = self.nonnormalentries() |
|
1741 | 1741 | self.nonnormalset = nonnorm |
|
1742 | 1742 | return otherparents |
|
1743 | 1743 | |
|
1744 | 1744 | def non_normal_or_other_parent_paths(self): |
|
1745 | 1745 | return self.nonnormalset.union(self.otherparentset) |
|
1746 | 1746 | |
|
1747 | 1747 | @propertycache |
|
1748 | 1748 | def identity(self): |
|
1749 | 1749 | self._map |
|
1750 | 1750 | return self.identity |
|
1751 | 1751 | |
|
1752 | 1752 | @propertycache |
|
1753 | 1753 | def dirfoldmap(self): |
|
1754 | 1754 | f = {} |
|
1755 | 1755 | normcase = util.normcase |
|
1756 | 1756 | for name in self._dirs: |
|
1757 | 1757 | f[normcase(name)] = name |
|
1758 | 1758 | return f |
|
1759 | 1759 | |
|
1760 | 1760 | |
|
1761 | 1761 | if rustmod is not None: |
|
1762 | 1762 | |
|
1763 | 1763 | class dirstatemap(object): |
|
1764 | 1764 | def __init__(self, ui, opener, root, nodeconstants, use_dirstate_v2): |
|
1765 | 1765 | self._use_dirstate_v2 = use_dirstate_v2 |
|
1766 | 1766 | self._nodeconstants = nodeconstants |
|
1767 | 1767 | self._ui = ui |
|
1768 | 1768 | self._opener = opener |
|
1769 | 1769 | self._root = root |
|
1770 | 1770 | self._filename = b'dirstate' |
|
1771 | 1771 | self._nodelen = 20 # Also update Rust code when changing this! |
|
1772 | 1772 | self._parents = None |
|
1773 | 1773 | self._dirtyparents = False |
|
1774 | 1774 | |
|
1775 | 1775 | # for consistent view between _pl() and _read() invocations |
|
1776 | 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 | 1784 | def addfile(self, *args, **kwargs): |
|
1779 | 1785 | return self._rustmap.addfile(*args, **kwargs) |
|
1780 | 1786 | |
|
1781 | 1787 | def removefile(self, *args, **kwargs): |
|
1782 | 1788 | return self._rustmap.removefile(*args, **kwargs) |
|
1783 | 1789 | |
|
1784 | 1790 | def dropfile(self, *args, **kwargs): |
|
1785 | 1791 | return self._rustmap.dropfile(*args, **kwargs) |
|
1786 | 1792 | |
|
1787 | 1793 | def clearambiguoustimes(self, *args, **kwargs): |
|
1788 | 1794 | return self._rustmap.clearambiguoustimes(*args, **kwargs) |
|
1789 | 1795 | |
|
1790 | 1796 | def nonnormalentries(self): |
|
1791 | 1797 | return self._rustmap.nonnormalentries() |
|
1792 | 1798 | |
|
1793 | 1799 | def get(self, *args, **kwargs): |
|
1794 | 1800 | return self._rustmap.get(*args, **kwargs) |
|
1795 | 1801 | |
|
1796 | 1802 | @property |
|
1797 | 1803 | def copymap(self): |
|
1798 | 1804 | return self._rustmap.copymap() |
|
1799 | 1805 | |
|
1800 | 1806 | def preload(self): |
|
1801 | 1807 | self._rustmap |
|
1802 | 1808 | |
|
1803 | 1809 | def clear(self): |
|
1804 | 1810 | self._rustmap.clear() |
|
1805 | 1811 | self.setparents( |
|
1806 | 1812 | self._nodeconstants.nullid, self._nodeconstants.nullid |
|
1807 | 1813 | ) |
|
1808 | 1814 | util.clearcachedproperty(self, b"_dirs") |
|
1809 | 1815 | util.clearcachedproperty(self, b"_alldirs") |
|
1810 | 1816 | util.clearcachedproperty(self, b"dirfoldmap") |
|
1811 | 1817 | |
|
1812 | 1818 | def items(self): |
|
1813 | 1819 | return self._rustmap.items() |
|
1814 | 1820 | |
|
1815 | 1821 | def keys(self): |
|
1816 | 1822 | return iter(self._rustmap) |
|
1817 | 1823 | |
|
1818 | 1824 | def __contains__(self, key): |
|
1819 | 1825 | return key in self._rustmap |
|
1820 | 1826 | |
|
1821 | 1827 | def __getitem__(self, item): |
|
1822 | 1828 | return self._rustmap[item] |
|
1823 | 1829 | |
|
1824 | 1830 | def __len__(self): |
|
1825 | 1831 | return len(self._rustmap) |
|
1826 | 1832 | |
|
1827 | 1833 | def __iter__(self): |
|
1828 | 1834 | return iter(self._rustmap) |
|
1829 | 1835 | |
|
1830 | 1836 | # forward for python2,3 compat |
|
1831 | 1837 | iteritems = items |
|
1832 | 1838 | |
|
1833 | 1839 | def _opendirstatefile(self): |
|
1834 | 1840 | fp, mode = txnutil.trypending( |
|
1835 | 1841 | self._root, self._opener, self._filename |
|
1836 | 1842 | ) |
|
1837 | 1843 | if self._pendingmode is not None and self._pendingmode != mode: |
|
1838 | 1844 | fp.close() |
|
1839 | 1845 | raise error.Abort( |
|
1840 | 1846 | _(b'working directory state may be changed parallelly') |
|
1841 | 1847 | ) |
|
1842 | 1848 | self._pendingmode = mode |
|
1843 | 1849 | return fp |
|
1844 | 1850 | |
|
1845 | 1851 | def setparents(self, p1, p2): |
|
1846 | 1852 | self._parents = (p1, p2) |
|
1847 | 1853 | self._dirtyparents = True |
|
1848 | 1854 | |
|
1849 | 1855 | def parents(self): |
|
1850 | 1856 | if not self._parents: |
|
1851 | 1857 | if self._use_dirstate_v2: |
|
1852 | 1858 | offset = len(rustmod.V2_FORMAT_MARKER) |
|
1853 | 1859 | else: |
|
1854 | 1860 | offset = 0 |
|
1855 | 1861 | read_len = offset + self._nodelen * 2 |
|
1856 | 1862 | try: |
|
1857 | 1863 | fp = self._opendirstatefile() |
|
1858 | 1864 | st = fp.read(read_len) |
|
1859 | 1865 | fp.close() |
|
1860 | 1866 | except IOError as err: |
|
1861 | 1867 | if err.errno != errno.ENOENT: |
|
1862 | 1868 | raise |
|
1863 | 1869 | # File doesn't exist, so the current state is empty |
|
1864 | 1870 | st = b'' |
|
1865 | 1871 | |
|
1866 | 1872 | l = len(st) |
|
1867 | 1873 | if l == read_len: |
|
1868 | 1874 | st = st[offset:] |
|
1869 | 1875 | self._parents = ( |
|
1870 | 1876 | st[: self._nodelen], |
|
1871 | 1877 | st[self._nodelen : 2 * self._nodelen], |
|
1872 | 1878 | ) |
|
1873 | 1879 | elif l == 0: |
|
1874 | 1880 | self._parents = ( |
|
1875 | 1881 | self._nodeconstants.nullid, |
|
1876 | 1882 | self._nodeconstants.nullid, |
|
1877 | 1883 | ) |
|
1878 | 1884 | else: |
|
1879 | 1885 | raise error.Abort( |
|
1880 | 1886 | _(b'working directory state appears damaged!') |
|
1881 | 1887 | ) |
|
1882 | 1888 | |
|
1883 | 1889 | return self._parents |
|
1884 | 1890 | |
|
1885 | 1891 | @propertycache |
|
1886 | 1892 | def _rustmap(self): |
|
1887 | 1893 | """ |
|
1888 | 1894 | Fills the Dirstatemap when called. |
|
1889 | 1895 | """ |
|
1890 | 1896 | # ignore HG_PENDING because identity is used only for writing |
|
1891 | 1897 | self.identity = util.filestat.frompath( |
|
1892 | 1898 | self._opener.join(self._filename) |
|
1893 | 1899 | ) |
|
1894 | 1900 | |
|
1895 | 1901 | try: |
|
1896 | 1902 | fp = self._opendirstatefile() |
|
1897 | 1903 | try: |
|
1898 | 1904 | st = fp.read() |
|
1899 | 1905 | finally: |
|
1900 | 1906 | fp.close() |
|
1901 | 1907 | except IOError as err: |
|
1902 | 1908 | if err.errno != errno.ENOENT: |
|
1903 | 1909 | raise |
|
1904 | 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 | 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 | 1916 | if parents and not self._dirtyparents: |
|
1916 | 1917 | self.setparents(*parents) |
|
1917 | 1918 | |
|
1918 | 1919 | self.__contains__ = self._rustmap.__contains__ |
|
1919 | 1920 | self.__getitem__ = self._rustmap.__getitem__ |
|
1920 | 1921 | self.get = self._rustmap.get |
|
1921 | 1922 | return self._rustmap |
|
1922 | 1923 | |
|
1923 | 1924 | def write(self, st, now): |
|
1924 | 1925 | parents = self.parents() |
|
1925 | 1926 | packed = self._rustmap.write( |
|
1926 | 1927 | self._use_dirstate_v2, parents[0], parents[1], now |
|
1927 | 1928 | ) |
|
1928 | 1929 | st.write(packed) |
|
1929 | 1930 | st.close() |
|
1930 | 1931 | self._dirtyparents = False |
|
1931 | 1932 | |
|
1932 | 1933 | @propertycache |
|
1933 | 1934 | def filefoldmap(self): |
|
1934 | 1935 | """Returns a dictionary mapping normalized case paths to their |
|
1935 | 1936 | non-normalized versions. |
|
1936 | 1937 | """ |
|
1937 | 1938 | return self._rustmap.filefoldmapasdict() |
|
1938 | 1939 | |
|
1939 | 1940 | def hastrackeddir(self, d): |
|
1940 | 1941 | self._dirs # Trigger Python's propertycache |
|
1941 | 1942 | return self._rustmap.hastrackeddir(d) |
|
1942 | 1943 | |
|
1943 | 1944 | def hasdir(self, d): |
|
1944 | 1945 | self._dirs # Trigger Python's propertycache |
|
1945 | 1946 | return self._rustmap.hasdir(d) |
|
1946 | 1947 | |
|
1947 | 1948 | @propertycache |
|
1948 | 1949 | def _dirs(self): |
|
1949 | 1950 | return self._rustmap.getdirs() |
|
1950 | 1951 | |
|
1951 | 1952 | @propertycache |
|
1952 | 1953 | def _alldirs(self): |
|
1953 | 1954 | return self._rustmap.getalldirs() |
|
1954 | 1955 | |
|
1955 | 1956 | @propertycache |
|
1956 | 1957 | def identity(self): |
|
1957 | 1958 | self._rustmap |
|
1958 | 1959 | return self.identity |
|
1959 | 1960 | |
|
1960 | 1961 | @property |
|
1961 | 1962 | def nonnormalset(self): |
|
1962 | 1963 | nonnorm = self._rustmap.non_normal_entries() |
|
1963 | 1964 | return nonnorm |
|
1964 | 1965 | |
|
1965 | 1966 | @propertycache |
|
1966 | 1967 | def otherparentset(self): |
|
1967 | 1968 | otherparents = self._rustmap.other_parent_entries() |
|
1968 | 1969 | return otherparents |
|
1969 | 1970 | |
|
1970 | 1971 | def non_normal_or_other_parent_paths(self): |
|
1971 | 1972 | return self._rustmap.non_normal_or_other_parent_paths() |
|
1972 | 1973 | |
|
1973 | 1974 | @propertycache |
|
1974 | 1975 | def dirfoldmap(self): |
|
1975 | 1976 | f = {} |
|
1976 | 1977 | normcase = util.normcase |
|
1977 | 1978 | for name in self._dirs: |
|
1978 | 1979 | f[normcase(name)] = name |
|
1979 | 1980 | return f |
@@ -1,1008 +1,1049 | |||
|
1 | 1 | # upgrade.py - functions for in place upgrade of Mercurial repository |
|
2 | 2 | # |
|
3 | 3 | # Copyright (c) 2016-present, Gregory Szorc |
|
4 | 4 | # |
|
5 | 5 | # This software may be used and distributed according to the terms of the |
|
6 | 6 | # GNU General Public License version 2 or any later version. |
|
7 | 7 | |
|
8 | 8 | from __future__ import absolute_import |
|
9 | 9 | |
|
10 | 10 | from ..i18n import _ |
|
11 | 11 | from .. import ( |
|
12 | 12 | error, |
|
13 | 13 | localrepo, |
|
14 | 14 | pycompat, |
|
15 | 15 | requirements, |
|
16 | 16 | revlog, |
|
17 | 17 | util, |
|
18 | 18 | ) |
|
19 | 19 | |
|
20 | 20 | from ..utils import compression |
|
21 | 21 | |
|
22 | 22 | if pycompat.TYPE_CHECKING: |
|
23 | 23 | from typing import ( |
|
24 | 24 | List, |
|
25 | 25 | Type, |
|
26 | 26 | ) |
|
27 | 27 | |
|
28 | 28 | |
|
29 | 29 | # list of requirements that request a clone of all revlog if added/removed |
|
30 | 30 | RECLONES_REQUIREMENTS = { |
|
31 | 31 | requirements.GENERALDELTA_REQUIREMENT, |
|
32 | 32 | requirements.SPARSEREVLOG_REQUIREMENT, |
|
33 | 33 | requirements.REVLOGV2_REQUIREMENT, |
|
34 | 34 | requirements.CHANGELOGV2_REQUIREMENT, |
|
35 | 35 | } |
|
36 | 36 | |
|
37 | 37 | |
|
38 | 38 | def preservedrequirements(repo): |
|
39 | 39 | return set() |
|
40 | 40 | |
|
41 | 41 | |
|
42 | 42 | FORMAT_VARIANT = b'deficiency' |
|
43 | 43 | OPTIMISATION = b'optimization' |
|
44 | 44 | |
|
45 | 45 | |
|
46 | 46 | class improvement(object): |
|
47 | 47 | """Represents an improvement that can be made as part of an upgrade.""" |
|
48 | 48 | |
|
49 | 49 | ### The following attributes should be defined for each subclass: |
|
50 | 50 | |
|
51 | 51 | # Either ``FORMAT_VARIANT`` or ``OPTIMISATION``. |
|
52 | 52 | # A format variant is where we change the storage format. Not all format |
|
53 | 53 | # variant changes are an obvious problem. |
|
54 | 54 | # An optimization is an action (sometimes optional) that |
|
55 | 55 | # can be taken to further improve the state of the repository. |
|
56 | 56 | type = None |
|
57 | 57 | |
|
58 | 58 | # machine-readable string uniquely identifying this improvement. it will be |
|
59 | 59 | # mapped to an action later in the upgrade process. |
|
60 | 60 | name = None |
|
61 | 61 | |
|
62 | 62 | # message intended for humans explaining the improvement in more detail, |
|
63 | 63 | # including the implications of it ``FORMAT_VARIANT`` types, should be |
|
64 | 64 | # worded |
|
65 | 65 | # in the present tense. |
|
66 | 66 | description = None |
|
67 | 67 | |
|
68 | 68 | # message intended for humans explaining what an upgrade addressing this |
|
69 | 69 | # issue will do. should be worded in the future tense. |
|
70 | 70 | upgrademessage = None |
|
71 | 71 | |
|
72 | 72 | # value of current Mercurial default for new repository |
|
73 | 73 | default = None |
|
74 | 74 | |
|
75 | 75 | # Message intended for humans which will be shown post an upgrade |
|
76 | 76 | # operation when the improvement will be added |
|
77 | 77 | postupgrademessage = None |
|
78 | 78 | |
|
79 | 79 | # Message intended for humans which will be shown post an upgrade |
|
80 | 80 | # operation in which this improvement was removed |
|
81 | 81 | postdowngrademessage = None |
|
82 | 82 | |
|
83 |
# By default |
|
|
83 | # By default we assume that every improvement touches requirements and all revlogs | |
|
84 | 84 | |
|
85 | 85 | # Whether this improvement touches filelogs |
|
86 | 86 | touches_filelogs = True |
|
87 | 87 | |
|
88 | 88 | # Whether this improvement touches manifests |
|
89 | 89 | touches_manifests = True |
|
90 | 90 | |
|
91 | 91 | # Whether this improvement touches changelog |
|
92 | 92 | touches_changelog = True |
|
93 | 93 | |
|
94 | 94 | # Whether this improvement changes repository requirements |
|
95 | 95 | touches_requirements = True |
|
96 | 96 | |
|
97 | # Whether this improvement touches the dirstate | |
|
98 | touches_dirstate = False | |
|
99 | ||
|
97 | 100 | |
|
98 | 101 | allformatvariant = [] # type: List[Type['formatvariant']] |
|
99 | 102 | |
|
100 | 103 | |
|
101 | 104 | def registerformatvariant(cls): |
|
102 | 105 | allformatvariant.append(cls) |
|
103 | 106 | return cls |
|
104 | 107 | |
|
105 | 108 | |
|
106 | 109 | class formatvariant(improvement): |
|
107 | 110 | """an improvement subclass dedicated to repository format""" |
|
108 | 111 | |
|
109 | 112 | type = FORMAT_VARIANT |
|
110 | 113 | |
|
111 | 114 | @staticmethod |
|
112 | 115 | def fromrepo(repo): |
|
113 | 116 | """current value of the variant in the repository""" |
|
114 | 117 | raise NotImplementedError() |
|
115 | 118 | |
|
116 | 119 | @staticmethod |
|
117 | 120 | def fromconfig(repo): |
|
118 | 121 | """current value of the variant in the configuration""" |
|
119 | 122 | raise NotImplementedError() |
|
120 | 123 | |
|
121 | 124 | |
|
122 | 125 | class requirementformatvariant(formatvariant): |
|
123 | 126 | """formatvariant based on a 'requirement' name. |
|
124 | 127 | |
|
125 | 128 | Many format variant are controlled by a 'requirement'. We define a small |
|
126 | 129 | subclass to factor the code. |
|
127 | 130 | """ |
|
128 | 131 | |
|
129 | 132 | # the requirement that control this format variant |
|
130 | 133 | _requirement = None |
|
131 | 134 | |
|
132 | 135 | @staticmethod |
|
133 | 136 | def _newreporequirements(ui): |
|
134 | 137 | return localrepo.newreporequirements( |
|
135 | 138 | ui, localrepo.defaultcreateopts(ui) |
|
136 | 139 | ) |
|
137 | 140 | |
|
138 | 141 | @classmethod |
|
139 | 142 | def fromrepo(cls, repo): |
|
140 | 143 | assert cls._requirement is not None |
|
141 | 144 | return cls._requirement in repo.requirements |
|
142 | 145 | |
|
143 | 146 | @classmethod |
|
144 | 147 | def fromconfig(cls, repo): |
|
145 | 148 | assert cls._requirement is not None |
|
146 | 149 | return cls._requirement in cls._newreporequirements(repo.ui) |
|
147 | 150 | |
|
148 | 151 | |
|
149 | 152 | @registerformatvariant |
|
150 | 153 | class fncache(requirementformatvariant): |
|
151 | 154 | name = b'fncache' |
|
152 | 155 | |
|
153 | 156 | _requirement = requirements.FNCACHE_REQUIREMENT |
|
154 | 157 | |
|
155 | 158 | default = True |
|
156 | 159 | |
|
157 | 160 | description = _( |
|
158 | 161 | b'long and reserved filenames may not work correctly; ' |
|
159 | 162 | b'repository performance is sub-optimal' |
|
160 | 163 | ) |
|
161 | 164 | |
|
162 | 165 | upgrademessage = _( |
|
163 | 166 | b'repository will be more resilient to storing ' |
|
164 | 167 | b'certain paths and performance of certain ' |
|
165 | 168 | b'operations should be improved' |
|
166 | 169 | ) |
|
167 | 170 | |
|
168 | 171 | |
|
169 | 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 | 194 | class dotencode(requirementformatvariant): |
|
171 | 195 | name = b'dotencode' |
|
172 | 196 | |
|
173 | 197 | _requirement = requirements.DOTENCODE_REQUIREMENT |
|
174 | 198 | |
|
175 | 199 | default = True |
|
176 | 200 | |
|
177 | 201 | description = _( |
|
178 | 202 | b'storage of filenames beginning with a period or ' |
|
179 | 203 | b'space may not work correctly' |
|
180 | 204 | ) |
|
181 | 205 | |
|
182 | 206 | upgrademessage = _( |
|
183 | 207 | b'repository will be better able to store files ' |
|
184 | 208 | b'beginning with a space or period' |
|
185 | 209 | ) |
|
186 | 210 | |
|
187 | 211 | |
|
188 | 212 | @registerformatvariant |
|
189 | 213 | class generaldelta(requirementformatvariant): |
|
190 | 214 | name = b'generaldelta' |
|
191 | 215 | |
|
192 | 216 | _requirement = requirements.GENERALDELTA_REQUIREMENT |
|
193 | 217 | |
|
194 | 218 | default = True |
|
195 | 219 | |
|
196 | 220 | description = _( |
|
197 | 221 | b'deltas within internal storage are unable to ' |
|
198 | 222 | b'choose optimal revisions; repository is larger and ' |
|
199 | 223 | b'slower than it could be; interaction with other ' |
|
200 | 224 | b'repositories may require extra network and CPU ' |
|
201 | 225 | b'resources, making "hg push" and "hg pull" slower' |
|
202 | 226 | ) |
|
203 | 227 | |
|
204 | 228 | upgrademessage = _( |
|
205 | 229 | b'repository storage will be able to create ' |
|
206 | 230 | b'optimal deltas; new repository data will be ' |
|
207 | 231 | b'smaller and read times should decrease; ' |
|
208 | 232 | b'interacting with other repositories using this ' |
|
209 | 233 | b'storage model should require less network and ' |
|
210 | 234 | b'CPU resources, making "hg push" and "hg pull" ' |
|
211 | 235 | b'faster' |
|
212 | 236 | ) |
|
213 | 237 | |
|
214 | 238 | |
|
215 | 239 | @registerformatvariant |
|
216 | 240 | class sharesafe(requirementformatvariant): |
|
217 | 241 | name = b'share-safe' |
|
218 | 242 | _requirement = requirements.SHARESAFE_REQUIREMENT |
|
219 | 243 | |
|
220 | 244 | default = False |
|
221 | 245 | |
|
222 | 246 | description = _( |
|
223 | 247 | b'old shared repositories do not share source repository ' |
|
224 | 248 | b'requirements and config. This leads to various problems ' |
|
225 | 249 | b'when the source repository format is upgraded or some new ' |
|
226 | 250 | b'extensions are enabled.' |
|
227 | 251 | ) |
|
228 | 252 | |
|
229 | 253 | upgrademessage = _( |
|
230 | 254 | b'Upgrades a repository to share-safe format so that future ' |
|
231 | 255 | b'shares of this repository share its requirements and configs.' |
|
232 | 256 | ) |
|
233 | 257 | |
|
234 | 258 | postdowngrademessage = _( |
|
235 | 259 | b'repository downgraded to not use share safe mode, ' |
|
236 | 260 | b'existing shares will not work and needs to' |
|
237 | 261 | b' be reshared.' |
|
238 | 262 | ) |
|
239 | 263 | |
|
240 | 264 | postupgrademessage = _( |
|
241 | 265 | b'repository upgraded to share safe mode, existing' |
|
242 | 266 | b' shares will still work in old non-safe mode. ' |
|
243 | 267 | b'Re-share existing shares to use them in safe mode' |
|
244 | 268 | b' New shares will be created in safe mode.' |
|
245 | 269 | ) |
|
246 | 270 | |
|
247 | 271 | # upgrade only needs to change the requirements |
|
248 | 272 | touches_filelogs = False |
|
249 | 273 | touches_manifests = False |
|
250 | 274 | touches_changelog = False |
|
251 | 275 | touches_requirements = True |
|
252 | 276 | |
|
253 | 277 | |
|
254 | 278 | @registerformatvariant |
|
255 | 279 | class sparserevlog(requirementformatvariant): |
|
256 | 280 | name = b'sparserevlog' |
|
257 | 281 | |
|
258 | 282 | _requirement = requirements.SPARSEREVLOG_REQUIREMENT |
|
259 | 283 | |
|
260 | 284 | default = True |
|
261 | 285 | |
|
262 | 286 | description = _( |
|
263 | 287 | b'in order to limit disk reading and memory usage on older ' |
|
264 | 288 | b'version, the span of a delta chain from its root to its ' |
|
265 | 289 | b'end is limited, whatever the relevant data in this span. ' |
|
266 | 290 | b'This can severly limit Mercurial ability to build good ' |
|
267 | 291 | b'chain of delta resulting is much more storage space being ' |
|
268 | 292 | b'taken and limit reusability of on disk delta during ' |
|
269 | 293 | b'exchange.' |
|
270 | 294 | ) |
|
271 | 295 | |
|
272 | 296 | upgrademessage = _( |
|
273 | 297 | b'Revlog supports delta chain with more unused data ' |
|
274 | 298 | b'between payload. These gaps will be skipped at read ' |
|
275 | 299 | b'time. This allows for better delta chains, making a ' |
|
276 | 300 | b'better compression and faster exchange with server.' |
|
277 | 301 | ) |
|
278 | 302 | |
|
279 | 303 | |
|
280 | 304 | @registerformatvariant |
|
281 | 305 | class persistentnodemap(requirementformatvariant): |
|
282 | 306 | name = b'persistent-nodemap' |
|
283 | 307 | |
|
284 | 308 | _requirement = requirements.NODEMAP_REQUIREMENT |
|
285 | 309 | |
|
286 | 310 | default = False |
|
287 | 311 | |
|
288 | 312 | description = _( |
|
289 | 313 | b'persist the node -> rev mapping on disk to speedup lookup' |
|
290 | 314 | ) |
|
291 | 315 | |
|
292 | 316 | upgrademessage = _(b'Speedup revision lookup by node id.') |
|
293 | 317 | |
|
294 | 318 | |
|
295 | 319 | @registerformatvariant |
|
296 | 320 | class copiessdc(requirementformatvariant): |
|
297 | 321 | name = b'copies-sdc' |
|
298 | 322 | |
|
299 | 323 | _requirement = requirements.COPIESSDC_REQUIREMENT |
|
300 | 324 | |
|
301 | 325 | default = False |
|
302 | 326 | |
|
303 | 327 | description = _(b'Stores copies information alongside changesets.') |
|
304 | 328 | |
|
305 | 329 | upgrademessage = _( |
|
306 | 330 | b'Allows to use more efficient algorithm to deal with ' b'copy tracing.' |
|
307 | 331 | ) |
|
308 | 332 | |
|
309 | 333 | |
|
310 | 334 | @registerformatvariant |
|
311 | 335 | class revlogv2(requirementformatvariant): |
|
312 | 336 | name = b'revlog-v2' |
|
313 | 337 | _requirement = requirements.REVLOGV2_REQUIREMENT |
|
314 | 338 | default = False |
|
315 | 339 | description = _(b'Version 2 of the revlog.') |
|
316 | 340 | upgrademessage = _(b'very experimental') |
|
317 | 341 | |
|
318 | 342 | |
|
319 | 343 | @registerformatvariant |
|
320 | 344 | class changelogv2(requirementformatvariant): |
|
321 | 345 | name = b'changelog-v2' |
|
322 | 346 | _requirement = requirements.CHANGELOGV2_REQUIREMENT |
|
323 | 347 | default = False |
|
324 | 348 | description = _(b'An iteration of the revlog focussed on changelog needs.') |
|
325 | 349 | upgrademessage = _(b'quite experimental') |
|
326 | 350 | |
|
327 | 351 | |
|
328 | 352 | @registerformatvariant |
|
329 | 353 | class removecldeltachain(formatvariant): |
|
330 | 354 | name = b'plain-cl-delta' |
|
331 | 355 | |
|
332 | 356 | default = True |
|
333 | 357 | |
|
334 | 358 | description = _( |
|
335 | 359 | b'changelog storage is using deltas instead of ' |
|
336 | 360 | b'raw entries; changelog reading and any ' |
|
337 | 361 | b'operation relying on changelog data are slower ' |
|
338 | 362 | b'than they could be' |
|
339 | 363 | ) |
|
340 | 364 | |
|
341 | 365 | upgrademessage = _( |
|
342 | 366 | b'changelog storage will be reformated to ' |
|
343 | 367 | b'store raw entries; changelog reading will be ' |
|
344 | 368 | b'faster; changelog size may be reduced' |
|
345 | 369 | ) |
|
346 | 370 | |
|
347 | 371 | @staticmethod |
|
348 | 372 | def fromrepo(repo): |
|
349 | 373 | # Mercurial 4.0 changed changelogs to not use delta chains. Search for |
|
350 | 374 | # changelogs with deltas. |
|
351 | 375 | cl = repo.changelog |
|
352 | 376 | chainbase = cl.chainbase |
|
353 | 377 | return all(rev == chainbase(rev) for rev in cl) |
|
354 | 378 | |
|
355 | 379 | @staticmethod |
|
356 | 380 | def fromconfig(repo): |
|
357 | 381 | return True |
|
358 | 382 | |
|
359 | 383 | |
|
360 | 384 | _has_zstd = ( |
|
361 | 385 | b'zstd' in util.compengines |
|
362 | 386 | and util.compengines[b'zstd'].available() |
|
363 | 387 | and util.compengines[b'zstd'].revlogheader() |
|
364 | 388 | ) |
|
365 | 389 | |
|
366 | 390 | |
|
367 | 391 | @registerformatvariant |
|
368 | 392 | class compressionengine(formatvariant): |
|
369 | 393 | name = b'compression' |
|
370 | 394 | |
|
371 | 395 | if _has_zstd: |
|
372 | 396 | default = b'zstd' |
|
373 | 397 | else: |
|
374 | 398 | default = b'zlib' |
|
375 | 399 | |
|
376 | 400 | description = _( |
|
377 | 401 | b'Compresion algorithm used to compress data. ' |
|
378 | 402 | b'Some engine are faster than other' |
|
379 | 403 | ) |
|
380 | 404 | |
|
381 | 405 | upgrademessage = _( |
|
382 | 406 | b'revlog content will be recompressed with the new algorithm.' |
|
383 | 407 | ) |
|
384 | 408 | |
|
385 | 409 | @classmethod |
|
386 | 410 | def fromrepo(cls, repo): |
|
387 | 411 | # we allow multiple compression engine requirement to co-exist because |
|
388 | 412 | # strickly speaking, revlog seems to support mixed compression style. |
|
389 | 413 | # |
|
390 | 414 | # The compression used for new entries will be "the last one" |
|
391 | 415 | compression = b'zlib' |
|
392 | 416 | for req in repo.requirements: |
|
393 | 417 | prefix = req.startswith |
|
394 | 418 | if prefix(b'revlog-compression-') or prefix(b'exp-compression-'): |
|
395 | 419 | compression = req.split(b'-', 2)[2] |
|
396 | 420 | return compression |
|
397 | 421 | |
|
398 | 422 | @classmethod |
|
399 | 423 | def fromconfig(cls, repo): |
|
400 | 424 | compengines = repo.ui.configlist(b'format', b'revlog-compression') |
|
401 | 425 | # return the first valid value as the selection code would do |
|
402 | 426 | for comp in compengines: |
|
403 | 427 | if comp in util.compengines: |
|
404 | 428 | e = util.compengines[comp] |
|
405 | 429 | if e.available() and e.revlogheader(): |
|
406 | 430 | return comp |
|
407 | 431 | |
|
408 | 432 | # no valide compression found lets display it all for clarity |
|
409 | 433 | return b','.join(compengines) |
|
410 | 434 | |
|
411 | 435 | |
|
412 | 436 | @registerformatvariant |
|
413 | 437 | class compressionlevel(formatvariant): |
|
414 | 438 | name = b'compression-level' |
|
415 | 439 | default = b'default' |
|
416 | 440 | |
|
417 | 441 | description = _(b'compression level') |
|
418 | 442 | |
|
419 | 443 | upgrademessage = _(b'revlog content will be recompressed') |
|
420 | 444 | |
|
421 | 445 | @classmethod |
|
422 | 446 | def fromrepo(cls, repo): |
|
423 | 447 | comp = compressionengine.fromrepo(repo) |
|
424 | 448 | level = None |
|
425 | 449 | if comp == b'zlib': |
|
426 | 450 | level = repo.ui.configint(b'storage', b'revlog.zlib.level') |
|
427 | 451 | elif comp == b'zstd': |
|
428 | 452 | level = repo.ui.configint(b'storage', b'revlog.zstd.level') |
|
429 | 453 | if level is None: |
|
430 | 454 | return b'default' |
|
431 | 455 | return bytes(level) |
|
432 | 456 | |
|
433 | 457 | @classmethod |
|
434 | 458 | def fromconfig(cls, repo): |
|
435 | 459 | comp = compressionengine.fromconfig(repo) |
|
436 | 460 | level = None |
|
437 | 461 | if comp == b'zlib': |
|
438 | 462 | level = repo.ui.configint(b'storage', b'revlog.zlib.level') |
|
439 | 463 | elif comp == b'zstd': |
|
440 | 464 | level = repo.ui.configint(b'storage', b'revlog.zstd.level') |
|
441 | 465 | if level is None: |
|
442 | 466 | return b'default' |
|
443 | 467 | return bytes(level) |
|
444 | 468 | |
|
445 | 469 | |
|
446 | 470 | def find_format_upgrades(repo): |
|
447 | 471 | """returns a list of format upgrades which can be perform on the repo""" |
|
448 | 472 | upgrades = [] |
|
449 | 473 | |
|
450 | 474 | # We could detect lack of revlogv1 and store here, but they were added |
|
451 | 475 | # in 0.9.2 and we don't support upgrading repos without these |
|
452 | 476 | # requirements, so let's not bother. |
|
453 | 477 | |
|
454 | 478 | for fv in allformatvariant: |
|
455 | 479 | if not fv.fromrepo(repo): |
|
456 | 480 | upgrades.append(fv) |
|
457 | 481 | |
|
458 | 482 | return upgrades |
|
459 | 483 | |
|
460 | 484 | |
|
461 | 485 | def find_format_downgrades(repo): |
|
462 | 486 | """returns a list of format downgrades which will be performed on the repo |
|
463 | 487 | because of disabled config option for them""" |
|
464 | 488 | |
|
465 | 489 | downgrades = [] |
|
466 | 490 | |
|
467 | 491 | for fv in allformatvariant: |
|
468 | 492 | if fv.name == b'compression': |
|
469 | 493 | # If there is a compression change between repository |
|
470 | 494 | # and config, destination repository compression will change |
|
471 | 495 | # and current compression will be removed. |
|
472 | 496 | if fv.fromrepo(repo) != fv.fromconfig(repo): |
|
473 | 497 | downgrades.append(fv) |
|
474 | 498 | continue |
|
475 | 499 | # format variant exist in repo but does not exist in new repository |
|
476 | 500 | # config |
|
477 | 501 | if fv.fromrepo(repo) and not fv.fromconfig(repo): |
|
478 | 502 | downgrades.append(fv) |
|
479 | 503 | |
|
480 | 504 | return downgrades |
|
481 | 505 | |
|
482 | 506 | |
|
483 | 507 | ALL_OPTIMISATIONS = [] |
|
484 | 508 | |
|
485 | 509 | |
|
486 | 510 | def register_optimization(obj): |
|
487 | 511 | ALL_OPTIMISATIONS.append(obj) |
|
488 | 512 | return obj |
|
489 | 513 | |
|
490 | 514 | |
|
491 | 515 | class optimization(improvement): |
|
492 | 516 | """an improvement subclass dedicated to optimizations""" |
|
493 | 517 | |
|
494 | 518 | type = OPTIMISATION |
|
495 | 519 | |
|
496 | 520 | |
|
497 | 521 | @register_optimization |
|
498 | 522 | class redeltaparents(optimization): |
|
499 | 523 | name = b're-delta-parent' |
|
500 | 524 | |
|
501 | 525 | type = OPTIMISATION |
|
502 | 526 | |
|
503 | 527 | description = _( |
|
504 | 528 | b'deltas within internal storage will be recalculated to ' |
|
505 | 529 | b'choose an optimal base revision where this was not ' |
|
506 | 530 | b'already done; the size of the repository may shrink and ' |
|
507 | 531 | b'various operations may become faster; the first time ' |
|
508 | 532 | b'this optimization is performed could slow down upgrade ' |
|
509 | 533 | b'execution considerably; subsequent invocations should ' |
|
510 | 534 | b'not run noticeably slower' |
|
511 | 535 | ) |
|
512 | 536 | |
|
513 | 537 | upgrademessage = _( |
|
514 | 538 | b'deltas within internal storage will choose a new ' |
|
515 | 539 | b'base revision if needed' |
|
516 | 540 | ) |
|
517 | 541 | |
|
518 | 542 | |
|
519 | 543 | @register_optimization |
|
520 | 544 | class redeltamultibase(optimization): |
|
521 | 545 | name = b're-delta-multibase' |
|
522 | 546 | |
|
523 | 547 | type = OPTIMISATION |
|
524 | 548 | |
|
525 | 549 | description = _( |
|
526 | 550 | b'deltas within internal storage will be recalculated ' |
|
527 | 551 | b'against multiple base revision and the smallest ' |
|
528 | 552 | b'difference will be used; the size of the repository may ' |
|
529 | 553 | b'shrink significantly when there are many merges; this ' |
|
530 | 554 | b'optimization will slow down execution in proportion to ' |
|
531 | 555 | b'the number of merges in the repository and the amount ' |
|
532 | 556 | b'of files in the repository; this slow down should not ' |
|
533 | 557 | b'be significant unless there are tens of thousands of ' |
|
534 | 558 | b'files and thousands of merges' |
|
535 | 559 | ) |
|
536 | 560 | |
|
537 | 561 | upgrademessage = _( |
|
538 | 562 | b'deltas within internal storage will choose an ' |
|
539 | 563 | b'optimal delta by computing deltas against multiple ' |
|
540 | 564 | b'parents; may slow down execution time ' |
|
541 | 565 | b'significantly' |
|
542 | 566 | ) |
|
543 | 567 | |
|
544 | 568 | |
|
545 | 569 | @register_optimization |
|
546 | 570 | class redeltaall(optimization): |
|
547 | 571 | name = b're-delta-all' |
|
548 | 572 | |
|
549 | 573 | type = OPTIMISATION |
|
550 | 574 | |
|
551 | 575 | description = _( |
|
552 | 576 | b'deltas within internal storage will always be ' |
|
553 | 577 | b'recalculated without reusing prior deltas; this will ' |
|
554 | 578 | b'likely make execution run several times slower; this ' |
|
555 | 579 | b'optimization is typically not needed' |
|
556 | 580 | ) |
|
557 | 581 | |
|
558 | 582 | upgrademessage = _( |
|
559 | 583 | b'deltas within internal storage will be fully ' |
|
560 | 584 | b'recomputed; this will likely drastically slow down ' |
|
561 | 585 | b'execution time' |
|
562 | 586 | ) |
|
563 | 587 | |
|
564 | 588 | |
|
565 | 589 | @register_optimization |
|
566 | 590 | class redeltafulladd(optimization): |
|
567 | 591 | name = b're-delta-fulladd' |
|
568 | 592 | |
|
569 | 593 | type = OPTIMISATION |
|
570 | 594 | |
|
571 | 595 | description = _( |
|
572 | 596 | b'every revision will be re-added as if it was new ' |
|
573 | 597 | b'content. It will go through the full storage ' |
|
574 | 598 | b'mechanism giving extensions a chance to process it ' |
|
575 | 599 | b'(eg. lfs). This is similar to "re-delta-all" but even ' |
|
576 | 600 | b'slower since more logic is involved.' |
|
577 | 601 | ) |
|
578 | 602 | |
|
579 | 603 | upgrademessage = _( |
|
580 | 604 | b'each revision will be added as new content to the ' |
|
581 | 605 | b'internal storage; this will likely drastically slow ' |
|
582 | 606 | b'down execution time, but some extensions might need ' |
|
583 | 607 | b'it' |
|
584 | 608 | ) |
|
585 | 609 | |
|
586 | 610 | |
|
587 | 611 | def findoptimizations(repo): |
|
588 | 612 | """Determine optimisation that could be used during upgrade""" |
|
589 | 613 | # These are unconditionally added. There is logic later that figures out |
|
590 | 614 | # which ones to apply. |
|
591 | 615 | return list(ALL_OPTIMISATIONS) |
|
592 | 616 | |
|
593 | 617 | |
|
594 | 618 | def determine_upgrade_actions( |
|
595 | 619 | repo, format_upgrades, optimizations, sourcereqs, destreqs |
|
596 | 620 | ): |
|
597 | 621 | """Determine upgrade actions that will be performed. |
|
598 | 622 | |
|
599 | 623 | Given a list of improvements as returned by ``find_format_upgrades`` and |
|
600 | 624 | ``findoptimizations``, determine the list of upgrade actions that |
|
601 | 625 | will be performed. |
|
602 | 626 | |
|
603 | 627 | The role of this function is to filter improvements if needed, apply |
|
604 | 628 | recommended optimizations from the improvements list that make sense, |
|
605 | 629 | etc. |
|
606 | 630 | |
|
607 | 631 | Returns a list of action names. |
|
608 | 632 | """ |
|
609 | 633 | newactions = [] |
|
610 | 634 | |
|
611 | 635 | for d in format_upgrades: |
|
612 | 636 | name = d._requirement |
|
613 | 637 | |
|
614 | 638 | # If the action is a requirement that doesn't show up in the |
|
615 | 639 | # destination requirements, prune the action. |
|
616 | 640 | if name is not None and name not in destreqs: |
|
617 | 641 | continue |
|
618 | 642 | |
|
619 | 643 | newactions.append(d) |
|
620 | 644 | |
|
621 | 645 | newactions.extend(o for o in sorted(optimizations) if o not in newactions) |
|
622 | 646 | |
|
623 | 647 | # FUTURE consider adding some optimizations here for certain transitions. |
|
624 | 648 | # e.g. adding generaldelta could schedule parent redeltas. |
|
625 | 649 | |
|
626 | 650 | return newactions |
|
627 | 651 | |
|
628 | 652 | |
|
629 | 653 | class UpgradeOperation(object): |
|
630 | 654 | """represent the work to be done during an upgrade""" |
|
631 | 655 | |
|
632 | 656 | def __init__( |
|
633 | 657 | self, |
|
634 | 658 | ui, |
|
635 | 659 | new_requirements, |
|
636 | 660 | current_requirements, |
|
637 | 661 | upgrade_actions, |
|
638 | 662 | removed_actions, |
|
639 | 663 | revlogs_to_process, |
|
640 | 664 | backup_store, |
|
641 | 665 | ): |
|
642 | 666 | self.ui = ui |
|
643 | 667 | self.new_requirements = new_requirements |
|
644 | 668 | self.current_requirements = current_requirements |
|
645 | 669 | # list of upgrade actions the operation will perform |
|
646 | 670 | self.upgrade_actions = upgrade_actions |
|
647 | self._upgrade_actions_names = set([a.name for a in upgrade_actions]) | |
|
648 | 671 | self.removed_actions = removed_actions |
|
649 | 672 | self.revlogs_to_process = revlogs_to_process |
|
650 | 673 | # requirements which will be added by the operation |
|
651 | 674 | self._added_requirements = ( |
|
652 | 675 | self.new_requirements - self.current_requirements |
|
653 | 676 | ) |
|
654 | 677 | # requirements which will be removed by the operation |
|
655 | 678 | self._removed_requirements = ( |
|
656 | 679 | self.current_requirements - self.new_requirements |
|
657 | 680 | ) |
|
658 | 681 | # requirements which will be preserved by the operation |
|
659 | 682 | self._preserved_requirements = ( |
|
660 | 683 | self.current_requirements & self.new_requirements |
|
661 | 684 | ) |
|
662 | 685 | # optimizations which are not used and it's recommended that they |
|
663 | 686 | # should use them |
|
664 | 687 | all_optimizations = findoptimizations(None) |
|
665 | 688 | self.unused_optimizations = [ |
|
666 | 689 | i for i in all_optimizations if i not in self.upgrade_actions |
|
667 | 690 | ] |
|
668 | 691 | |
|
669 | 692 | # delta reuse mode of this upgrade operation |
|
693 | upgrade_actions_names = self.upgrade_actions_names | |
|
670 | 694 | self.delta_reuse_mode = revlog.revlog.DELTAREUSEALWAYS |
|
671 |
if b're-delta-all' in |
|
|
695 | if b're-delta-all' in upgrade_actions_names: | |
|
672 | 696 | self.delta_reuse_mode = revlog.revlog.DELTAREUSENEVER |
|
673 |
elif b're-delta-parent' in |
|
|
697 | elif b're-delta-parent' in upgrade_actions_names: | |
|
674 | 698 | self.delta_reuse_mode = revlog.revlog.DELTAREUSESAMEREVS |
|
675 |
elif b're-delta-multibase' in |
|
|
699 | elif b're-delta-multibase' in upgrade_actions_names: | |
|
676 | 700 | self.delta_reuse_mode = revlog.revlog.DELTAREUSESAMEREVS |
|
677 |
elif b're-delta-fulladd' in |
|
|
701 | elif b're-delta-fulladd' in upgrade_actions_names: | |
|
678 | 702 | self.delta_reuse_mode = revlog.revlog.DELTAREUSEFULLADD |
|
679 | 703 | |
|
680 | 704 | # should this operation force re-delta of both parents |
|
681 | 705 | self.force_re_delta_both_parents = ( |
|
682 |
b're-delta-multibase' in |
|
|
706 | b're-delta-multibase' in upgrade_actions_names | |
|
683 | 707 | ) |
|
684 | 708 | |
|
685 | 709 | # should this operation create a backup of the store |
|
686 | 710 | self.backup_store = backup_store |
|
687 | 711 | |
|
688 | # whether the operation touches different revlogs at all or not | |
|
689 | self.touches_filelogs = self._touches_filelogs() | |
|
690 | self.touches_manifests = self._touches_manifests() | |
|
691 | self.touches_changelog = self._touches_changelog() | |
|
692 | # whether the operation touches requirements file or not | |
|
693 | self.touches_requirements = self._touches_requirements() | |
|
694 | self.touches_store = ( | |
|
695 | self.touches_filelogs | |
|
696 | or self.touches_manifests | |
|
697 | or self.touches_changelog | |
|
698 | ) | |
|
712 | @property | |
|
713 | def upgrade_actions_names(self): | |
|
714 | return set([a.name for a in self.upgrade_actions]) | |
|
715 | ||
|
716 | @property | |
|
717 | def requirements_only(self): | |
|
699 | 718 | # does the operation only touches repository requirement |
|
700 |
|
|
|
701 |
self.touches_requirements |
|
|
719 | return ( | |
|
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 | 729 | for a in self.upgrade_actions: |
|
706 | 730 | # in optimisations, we re-process the revlogs again |
|
707 | 731 | if a.type == OPTIMISATION: |
|
708 | 732 | return True |
|
709 | 733 | elif a.touches_filelogs: |
|
710 | 734 | return True |
|
711 | 735 | for a in self.removed_actions: |
|
712 | 736 | if a.touches_filelogs: |
|
713 | 737 | return True |
|
714 | 738 | return False |
|
715 | 739 | |
|
716 | def _touches_manifests(self): | |
|
740 | @property | |
|
741 | def touches_manifests(self): | |
|
717 | 742 | for a in self.upgrade_actions: |
|
718 | 743 | # in optimisations, we re-process the revlogs again |
|
719 | 744 | if a.type == OPTIMISATION: |
|
720 | 745 | return True |
|
721 | 746 | elif a.touches_manifests: |
|
722 | 747 | return True |
|
723 | 748 | for a in self.removed_actions: |
|
724 | 749 | if a.touches_manifests: |
|
725 | 750 | return True |
|
726 | 751 | return False |
|
727 | 752 | |
|
728 | def _touches_changelog(self): | |
|
753 | @property | |
|
754 | def touches_changelog(self): | |
|
729 | 755 | for a in self.upgrade_actions: |
|
730 | 756 | # in optimisations, we re-process the revlogs again |
|
731 | 757 | if a.type == OPTIMISATION: |
|
732 | 758 | return True |
|
733 | 759 | elif a.touches_changelog: |
|
734 | 760 | return True |
|
735 | 761 | for a in self.removed_actions: |
|
736 | 762 | if a.touches_changelog: |
|
737 | 763 | return True |
|
738 | 764 | return False |
|
739 | 765 | |
|
740 | def _touches_requirements(self): | |
|
766 | @property | |
|
767 | def touches_requirements(self): | |
|
741 | 768 | for a in self.upgrade_actions: |
|
742 | 769 | # optimisations are used to re-process revlogs and does not result |
|
743 | 770 | # in a requirement being added or removed |
|
744 | 771 | if a.type == OPTIMISATION: |
|
745 | 772 | pass |
|
746 | 773 | elif a.touches_requirements: |
|
747 | 774 | return True |
|
748 | 775 | for a in self.removed_actions: |
|
749 | 776 | if a.touches_requirements: |
|
750 | 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 | 791 | return False |
|
753 | 792 | |
|
754 | 793 | def _write_labeled(self, l, label): |
|
755 | 794 | """ |
|
756 | 795 | Utility function to aid writing of a list under one label |
|
757 | 796 | """ |
|
758 | 797 | first = True |
|
759 | 798 | for r in sorted(l): |
|
760 | 799 | if not first: |
|
761 | 800 | self.ui.write(b', ') |
|
762 | 801 | self.ui.write(r, label=label) |
|
763 | 802 | first = False |
|
764 | 803 | |
|
765 | 804 | def print_requirements(self): |
|
766 | 805 | self.ui.write(_(b'requirements\n')) |
|
767 | 806 | self.ui.write(_(b' preserved: ')) |
|
768 | 807 | self._write_labeled( |
|
769 | 808 | self._preserved_requirements, "upgrade-repo.requirement.preserved" |
|
770 | 809 | ) |
|
771 | 810 | self.ui.write((b'\n')) |
|
772 | 811 | if self._removed_requirements: |
|
773 | 812 | self.ui.write(_(b' removed: ')) |
|
774 | 813 | self._write_labeled( |
|
775 | 814 | self._removed_requirements, "upgrade-repo.requirement.removed" |
|
776 | 815 | ) |
|
777 | 816 | self.ui.write((b'\n')) |
|
778 | 817 | if self._added_requirements: |
|
779 | 818 | self.ui.write(_(b' added: ')) |
|
780 | 819 | self._write_labeled( |
|
781 | 820 | self._added_requirements, "upgrade-repo.requirement.added" |
|
782 | 821 | ) |
|
783 | 822 | self.ui.write((b'\n')) |
|
784 | 823 | self.ui.write(b'\n') |
|
785 | 824 | |
|
786 | 825 | def print_optimisations(self): |
|
787 | 826 | optimisations = [ |
|
788 | 827 | a for a in self.upgrade_actions if a.type == OPTIMISATION |
|
789 | 828 | ] |
|
790 | 829 | optimisations.sort(key=lambda a: a.name) |
|
791 | 830 | if optimisations: |
|
792 | 831 | self.ui.write(_(b'optimisations: ')) |
|
793 | 832 | self._write_labeled( |
|
794 | 833 | [a.name for a in optimisations], |
|
795 | 834 | "upgrade-repo.optimisation.performed", |
|
796 | 835 | ) |
|
797 | 836 | self.ui.write(b'\n\n') |
|
798 | 837 | |
|
799 | 838 | def print_upgrade_actions(self): |
|
800 | 839 | for a in self.upgrade_actions: |
|
801 | 840 | self.ui.status(b'%s\n %s\n\n' % (a.name, a.upgrademessage)) |
|
802 | 841 | |
|
803 | 842 | def print_affected_revlogs(self): |
|
804 | 843 | if not self.revlogs_to_process: |
|
805 | 844 | self.ui.write((b'no revlogs to process\n')) |
|
806 | 845 | else: |
|
807 | 846 | self.ui.write((b'processed revlogs:\n')) |
|
808 | 847 | for r in sorted(self.revlogs_to_process): |
|
809 | 848 | self.ui.write((b' - %s\n' % r)) |
|
810 | 849 | self.ui.write((b'\n')) |
|
811 | 850 | |
|
812 | 851 | def print_unused_optimizations(self): |
|
813 | 852 | for i in self.unused_optimizations: |
|
814 | 853 | self.ui.status(_(b'%s\n %s\n\n') % (i.name, i.description)) |
|
815 | 854 | |
|
816 | 855 | def has_upgrade_action(self, name): |
|
817 | 856 | """Check whether the upgrade operation will perform this action""" |
|
818 | 857 | return name in self._upgrade_actions_names |
|
819 | 858 | |
|
820 | 859 | def print_post_op_messages(self): |
|
821 | 860 | """print post upgrade operation warning messages""" |
|
822 | 861 | for a in self.upgrade_actions: |
|
823 | 862 | if a.postupgrademessage is not None: |
|
824 | 863 | self.ui.warn(b'%s\n' % a.postupgrademessage) |
|
825 | 864 | for a in self.removed_actions: |
|
826 | 865 | if a.postdowngrademessage is not None: |
|
827 | 866 | self.ui.warn(b'%s\n' % a.postdowngrademessage) |
|
828 | 867 | |
|
829 | 868 | |
|
830 | 869 | ### Code checking if a repository can got through the upgrade process at all. # |
|
831 | 870 | |
|
832 | 871 | |
|
833 | 872 | def requiredsourcerequirements(repo): |
|
834 | 873 | """Obtain requirements required to be present to upgrade a repo. |
|
835 | 874 | |
|
836 | 875 | An upgrade will not be allowed if the repository doesn't have the |
|
837 | 876 | requirements returned by this function. |
|
838 | 877 | """ |
|
839 | 878 | return { |
|
840 | 879 | # Introduced in Mercurial 0.9.2. |
|
841 | 880 | requirements.STORE_REQUIREMENT, |
|
842 | 881 | } |
|
843 | 882 | |
|
844 | 883 | |
|
845 | 884 | def blocksourcerequirements(repo): |
|
846 | 885 | """Obtain requirements that will prevent an upgrade from occurring. |
|
847 | 886 | |
|
848 | 887 | An upgrade cannot be performed if the source repository contains a |
|
849 | 888 | requirements in the returned set. |
|
850 | 889 | """ |
|
851 | 890 | return { |
|
852 | 891 | # The upgrade code does not yet support these experimental features. |
|
853 | 892 | # This is an artificial limitation. |
|
854 | 893 | requirements.TREEMANIFEST_REQUIREMENT, |
|
855 | 894 | # This was a precursor to generaldelta and was never enabled by default. |
|
856 | 895 | # It should (hopefully) not exist in the wild. |
|
857 | 896 | b'parentdelta', |
|
858 | 897 | # Upgrade should operate on the actual store, not the shared link. |
|
859 | 898 | requirements.SHARED_REQUIREMENT, |
|
860 | 899 | } |
|
861 | 900 | |
|
862 | 901 | |
|
863 | 902 | def check_revlog_version(reqs): |
|
864 | 903 | """Check that the requirements contain at least one Revlog version""" |
|
865 | 904 | all_revlogs = { |
|
866 | 905 | requirements.REVLOGV1_REQUIREMENT, |
|
867 | 906 | requirements.REVLOGV2_REQUIREMENT, |
|
868 | 907 | } |
|
869 | 908 | if not all_revlogs.intersection(reqs): |
|
870 | 909 | msg = _(b'cannot upgrade repository; missing a revlog version') |
|
871 | 910 | raise error.Abort(msg) |
|
872 | 911 | |
|
873 | 912 | |
|
874 | 913 | def check_source_requirements(repo): |
|
875 | 914 | """Ensure that no existing requirements prevent the repository upgrade""" |
|
876 | 915 | |
|
877 | 916 | check_revlog_version(repo.requirements) |
|
878 | 917 | required = requiredsourcerequirements(repo) |
|
879 | 918 | missingreqs = required - repo.requirements |
|
880 | 919 | if missingreqs: |
|
881 | 920 | msg = _(b'cannot upgrade repository; requirement missing: %s') |
|
882 | 921 | missingreqs = b', '.join(sorted(missingreqs)) |
|
883 | 922 | raise error.Abort(msg % missingreqs) |
|
884 | 923 | |
|
885 | 924 | blocking = blocksourcerequirements(repo) |
|
886 | 925 | blockingreqs = blocking & repo.requirements |
|
887 | 926 | if blockingreqs: |
|
888 | 927 | m = _(b'cannot upgrade repository; unsupported source requirement: %s') |
|
889 | 928 | blockingreqs = b', '.join(sorted(blockingreqs)) |
|
890 | 929 | raise error.Abort(m % blockingreqs) |
|
891 | 930 | |
|
892 | 931 | |
|
893 | 932 | ### Verify the validity of the planned requirement changes #################### |
|
894 | 933 | |
|
895 | 934 | |
|
896 | 935 | def supportremovedrequirements(repo): |
|
897 | 936 | """Obtain requirements that can be removed during an upgrade. |
|
898 | 937 | |
|
899 | 938 | If an upgrade were to create a repository that dropped a requirement, |
|
900 | 939 | the dropped requirement must appear in the returned set for the upgrade |
|
901 | 940 | to be allowed. |
|
902 | 941 | """ |
|
903 | 942 | supported = { |
|
904 | 943 | requirements.SPARSEREVLOG_REQUIREMENT, |
|
905 | 944 | requirements.COPIESSDC_REQUIREMENT, |
|
906 | 945 | requirements.NODEMAP_REQUIREMENT, |
|
907 | 946 | requirements.SHARESAFE_REQUIREMENT, |
|
908 | 947 | requirements.REVLOGV2_REQUIREMENT, |
|
909 | 948 | requirements.CHANGELOGV2_REQUIREMENT, |
|
910 | 949 | requirements.REVLOGV1_REQUIREMENT, |
|
950 | requirements.DIRSTATE_V2_REQUIREMENT, | |
|
911 | 951 | } |
|
912 | 952 | for name in compression.compengines: |
|
913 | 953 | engine = compression.compengines[name] |
|
914 | 954 | if engine.available() and engine.revlogheader(): |
|
915 | 955 | supported.add(b'exp-compression-%s' % name) |
|
916 | 956 | if engine.name() == b'zstd': |
|
917 | 957 | supported.add(b'revlog-compression-zstd') |
|
918 | 958 | return supported |
|
919 | 959 | |
|
920 | 960 | |
|
921 | 961 | def supporteddestrequirements(repo): |
|
922 | 962 | """Obtain requirements that upgrade supports in the destination. |
|
923 | 963 | |
|
924 | 964 | If the result of the upgrade would create requirements not in this set, |
|
925 | 965 | the upgrade is disallowed. |
|
926 | 966 | |
|
927 | 967 | Extensions should monkeypatch this to add their custom requirements. |
|
928 | 968 | """ |
|
929 | 969 | supported = { |
|
930 | 970 | requirements.DOTENCODE_REQUIREMENT, |
|
931 | 971 | requirements.FNCACHE_REQUIREMENT, |
|
932 | 972 | requirements.GENERALDELTA_REQUIREMENT, |
|
933 | 973 | requirements.REVLOGV1_REQUIREMENT, # allowed in case of downgrade |
|
934 | 974 | requirements.STORE_REQUIREMENT, |
|
935 | 975 | requirements.SPARSEREVLOG_REQUIREMENT, |
|
936 | 976 | requirements.COPIESSDC_REQUIREMENT, |
|
937 | 977 | requirements.NODEMAP_REQUIREMENT, |
|
938 | 978 | requirements.SHARESAFE_REQUIREMENT, |
|
939 | 979 | requirements.REVLOGV2_REQUIREMENT, |
|
940 | 980 | requirements.CHANGELOGV2_REQUIREMENT, |
|
941 | 981 | requirements.DIRSTATE_V2_REQUIREMENT, |
|
942 | 982 | } |
|
943 | 983 | for name in compression.compengines: |
|
944 | 984 | engine = compression.compengines[name] |
|
945 | 985 | if engine.available() and engine.revlogheader(): |
|
946 | 986 | supported.add(b'exp-compression-%s' % name) |
|
947 | 987 | if engine.name() == b'zstd': |
|
948 | 988 | supported.add(b'revlog-compression-zstd') |
|
949 | 989 | return supported |
|
950 | 990 | |
|
951 | 991 | |
|
952 | 992 | def allowednewrequirements(repo): |
|
953 | 993 | """Obtain requirements that can be added to a repository during upgrade. |
|
954 | 994 | |
|
955 | 995 | This is used to disallow proposed requirements from being added when |
|
956 | 996 | they weren't present before. |
|
957 | 997 | |
|
958 | 998 | We use a list of allowed requirement additions instead of a list of known |
|
959 | 999 | bad additions because the whitelist approach is safer and will prevent |
|
960 | 1000 | future, unknown requirements from accidentally being added. |
|
961 | 1001 | """ |
|
962 | 1002 | supported = { |
|
963 | 1003 | requirements.DOTENCODE_REQUIREMENT, |
|
964 | 1004 | requirements.FNCACHE_REQUIREMENT, |
|
965 | 1005 | requirements.GENERALDELTA_REQUIREMENT, |
|
966 | 1006 | requirements.SPARSEREVLOG_REQUIREMENT, |
|
967 | 1007 | requirements.COPIESSDC_REQUIREMENT, |
|
968 | 1008 | requirements.NODEMAP_REQUIREMENT, |
|
969 | 1009 | requirements.SHARESAFE_REQUIREMENT, |
|
970 | 1010 | requirements.REVLOGV1_REQUIREMENT, |
|
971 | 1011 | requirements.REVLOGV2_REQUIREMENT, |
|
972 | 1012 | requirements.CHANGELOGV2_REQUIREMENT, |
|
1013 | requirements.DIRSTATE_V2_REQUIREMENT, | |
|
973 | 1014 | } |
|
974 | 1015 | for name in compression.compengines: |
|
975 | 1016 | engine = compression.compengines[name] |
|
976 | 1017 | if engine.available() and engine.revlogheader(): |
|
977 | 1018 | supported.add(b'exp-compression-%s' % name) |
|
978 | 1019 | if engine.name() == b'zstd': |
|
979 | 1020 | supported.add(b'revlog-compression-zstd') |
|
980 | 1021 | return supported |
|
981 | 1022 | |
|
982 | 1023 | |
|
983 | 1024 | def check_requirements_changes(repo, new_reqs): |
|
984 | 1025 | old_reqs = repo.requirements |
|
985 | 1026 | check_revlog_version(repo.requirements) |
|
986 | 1027 | support_removal = supportremovedrequirements(repo) |
|
987 | 1028 | no_remove_reqs = old_reqs - new_reqs - support_removal |
|
988 | 1029 | if no_remove_reqs: |
|
989 | 1030 | msg = _(b'cannot upgrade repository; requirement would be removed: %s') |
|
990 | 1031 | no_remove_reqs = b', '.join(sorted(no_remove_reqs)) |
|
991 | 1032 | raise error.Abort(msg % no_remove_reqs) |
|
992 | 1033 | |
|
993 | 1034 | support_addition = allowednewrequirements(repo) |
|
994 | 1035 | no_add_reqs = new_reqs - old_reqs - support_addition |
|
995 | 1036 | if no_add_reqs: |
|
996 | 1037 | m = _(b'cannot upgrade repository; do not support adding requirement: ') |
|
997 | 1038 | no_add_reqs = b', '.join(sorted(no_add_reqs)) |
|
998 | 1039 | raise error.Abort(m + no_add_reqs) |
|
999 | 1040 | |
|
1000 | 1041 | supported = supporteddestrequirements(repo) |
|
1001 | 1042 | unsupported_reqs = new_reqs - supported |
|
1002 | 1043 | if unsupported_reqs: |
|
1003 | 1044 | msg = _( |
|
1004 | 1045 | b'cannot upgrade repository; do not support destination ' |
|
1005 | 1046 | b'requirement: %s' |
|
1006 | 1047 | ) |
|
1007 | 1048 | unsupported_reqs = b', '.join(sorted(unsupported_reqs)) |
|
1008 | 1049 | raise error.Abort(msg % unsupported_reqs) |
@@ -1,593 +1,632 | |||
|
1 | 1 | # upgrade.py - functions for in place upgrade of Mercurial repository |
|
2 | 2 | # |
|
3 | 3 | # Copyright (c) 2016-present, Gregory Szorc |
|
4 | 4 | # |
|
5 | 5 | # This software may be used and distributed according to the terms of the |
|
6 | 6 | # GNU General Public License version 2 or any later version. |
|
7 | 7 | |
|
8 | 8 | from __future__ import absolute_import |
|
9 | 9 | |
|
10 | 10 | import stat |
|
11 | 11 | |
|
12 | 12 | from ..i18n import _ |
|
13 | 13 | from ..pycompat import getattr |
|
14 | 14 | from .. import ( |
|
15 | 15 | changelog, |
|
16 | 16 | error, |
|
17 | 17 | filelog, |
|
18 | 18 | manifest, |
|
19 | 19 | metadata, |
|
20 | 20 | pycompat, |
|
21 | 21 | requirements, |
|
22 | 22 | scmutil, |
|
23 | 23 | store, |
|
24 | 24 | util, |
|
25 | 25 | vfs as vfsmod, |
|
26 | 26 | ) |
|
27 | 27 | from ..revlogutils import ( |
|
28 | 28 | constants as revlogconst, |
|
29 | 29 | flagutil, |
|
30 | 30 | nodemap, |
|
31 | 31 | sidedata as sidedatamod, |
|
32 | 32 | ) |
|
33 | from . import actions as upgrade_actions | |
|
33 | 34 | |
|
34 | 35 | |
|
35 | 36 | def get_sidedata_helpers(srcrepo, dstrepo): |
|
36 | 37 | use_w = srcrepo.ui.configbool(b'experimental', b'worker.repository-upgrade') |
|
37 | 38 | sequential = pycompat.iswindows or not use_w |
|
38 | 39 | if not sequential: |
|
39 | 40 | srcrepo.register_sidedata_computer( |
|
40 | 41 | revlogconst.KIND_CHANGELOG, |
|
41 | 42 | sidedatamod.SD_FILES, |
|
42 | 43 | (sidedatamod.SD_FILES,), |
|
43 | 44 | metadata._get_worker_sidedata_adder(srcrepo, dstrepo), |
|
44 | 45 | flagutil.REVIDX_HASCOPIESINFO, |
|
45 | 46 | replace=True, |
|
46 | 47 | ) |
|
47 | 48 | return sidedatamod.get_sidedata_helpers(srcrepo, dstrepo._wanted_sidedata) |
|
48 | 49 | |
|
49 | 50 | |
|
50 | 51 | def _revlogfrompath(repo, rl_type, path): |
|
51 | 52 | """Obtain a revlog from a repo path. |
|
52 | 53 | |
|
53 | 54 | An instance of the appropriate class is returned. |
|
54 | 55 | """ |
|
55 | 56 | if rl_type & store.FILEFLAGS_CHANGELOG: |
|
56 | 57 | return changelog.changelog(repo.svfs) |
|
57 | 58 | elif rl_type & store.FILEFLAGS_MANIFESTLOG: |
|
58 | 59 | mandir = b'' |
|
59 | 60 | if b'/' in path: |
|
60 | 61 | mandir = path.rsplit(b'/', 1)[0] |
|
61 | 62 | return manifest.manifestrevlog( |
|
62 | 63 | repo.nodeconstants, repo.svfs, tree=mandir |
|
63 | 64 | ) |
|
64 | 65 | else: |
|
65 | 66 | # drop the extension and the `data/` prefix |
|
66 | 67 | path = path.rsplit(b'.', 1)[0].split(b'/', 1)[1] |
|
67 | 68 | return filelog.filelog(repo.svfs, path) |
|
68 | 69 | |
|
69 | 70 | |
|
70 | 71 | def _copyrevlog(tr, destrepo, oldrl, rl_type, unencodedname): |
|
71 | 72 | """copy all relevant files for `oldrl` into `destrepo` store |
|
72 | 73 | |
|
73 | 74 | Files are copied "as is" without any transformation. The copy is performed |
|
74 | 75 | without extra checks. Callers are responsible for making sure the copied |
|
75 | 76 | content is compatible with format of the destination repository. |
|
76 | 77 | """ |
|
77 | 78 | oldrl = getattr(oldrl, '_revlog', oldrl) |
|
78 | 79 | newrl = _revlogfrompath(destrepo, rl_type, unencodedname) |
|
79 | 80 | newrl = getattr(newrl, '_revlog', newrl) |
|
80 | 81 | |
|
81 | 82 | oldvfs = oldrl.opener |
|
82 | 83 | newvfs = newrl.opener |
|
83 | 84 | oldindex = oldvfs.join(oldrl._indexfile) |
|
84 | 85 | newindex = newvfs.join(newrl._indexfile) |
|
85 | 86 | olddata = oldvfs.join(oldrl._datafile) |
|
86 | 87 | newdata = newvfs.join(newrl._datafile) |
|
87 | 88 | |
|
88 | 89 | with newvfs(newrl._indexfile, b'w'): |
|
89 | 90 | pass # create all the directories |
|
90 | 91 | |
|
91 | 92 | util.copyfile(oldindex, newindex) |
|
92 | 93 | copydata = oldrl.opener.exists(oldrl._datafile) |
|
93 | 94 | if copydata: |
|
94 | 95 | util.copyfile(olddata, newdata) |
|
95 | 96 | |
|
96 | 97 | if rl_type & store.FILEFLAGS_FILELOG: |
|
97 | 98 | destrepo.svfs.fncache.add(unencodedname) |
|
98 | 99 | if copydata: |
|
99 | 100 | destrepo.svfs.fncache.add(unencodedname[:-2] + b'.d') |
|
100 | 101 | |
|
101 | 102 | |
|
102 | 103 | UPGRADE_CHANGELOG = b"changelog" |
|
103 | 104 | UPGRADE_MANIFEST = b"manifest" |
|
104 | 105 | UPGRADE_FILELOGS = b"all-filelogs" |
|
105 | 106 | |
|
106 | 107 | UPGRADE_ALL_REVLOGS = frozenset( |
|
107 | 108 | [UPGRADE_CHANGELOG, UPGRADE_MANIFEST, UPGRADE_FILELOGS] |
|
108 | 109 | ) |
|
109 | 110 | |
|
110 | 111 | |
|
111 | 112 | def matchrevlog(revlogfilter, rl_type): |
|
112 | 113 | """check if a revlog is selected for cloning. |
|
113 | 114 | |
|
114 | 115 | In other words, are there any updates which need to be done on revlog |
|
115 | 116 | or it can be blindly copied. |
|
116 | 117 | |
|
117 | 118 | The store entry is checked against the passed filter""" |
|
118 | 119 | if rl_type & store.FILEFLAGS_CHANGELOG: |
|
119 | 120 | return UPGRADE_CHANGELOG in revlogfilter |
|
120 | 121 | elif rl_type & store.FILEFLAGS_MANIFESTLOG: |
|
121 | 122 | return UPGRADE_MANIFEST in revlogfilter |
|
122 | 123 | assert rl_type & store.FILEFLAGS_FILELOG |
|
123 | 124 | return UPGRADE_FILELOGS in revlogfilter |
|
124 | 125 | |
|
125 | 126 | |
|
126 | 127 | def _perform_clone( |
|
127 | 128 | ui, |
|
128 | 129 | dstrepo, |
|
129 | 130 | tr, |
|
130 | 131 | old_revlog, |
|
131 | 132 | rl_type, |
|
132 | 133 | unencoded, |
|
133 | 134 | upgrade_op, |
|
134 | 135 | sidedata_helpers, |
|
135 | 136 | oncopiedrevision, |
|
136 | 137 | ): |
|
137 | 138 | """returns the new revlog object created""" |
|
138 | 139 | newrl = None |
|
139 | 140 | if matchrevlog(upgrade_op.revlogs_to_process, rl_type): |
|
140 | 141 | ui.note( |
|
141 | 142 | _(b'cloning %d revisions from %s\n') % (len(old_revlog), unencoded) |
|
142 | 143 | ) |
|
143 | 144 | newrl = _revlogfrompath(dstrepo, rl_type, unencoded) |
|
144 | 145 | old_revlog.clone( |
|
145 | 146 | tr, |
|
146 | 147 | newrl, |
|
147 | 148 | addrevisioncb=oncopiedrevision, |
|
148 | 149 | deltareuse=upgrade_op.delta_reuse_mode, |
|
149 | 150 | forcedeltabothparents=upgrade_op.force_re_delta_both_parents, |
|
150 | 151 | sidedata_helpers=sidedata_helpers, |
|
151 | 152 | ) |
|
152 | 153 | else: |
|
153 | 154 | msg = _(b'blindly copying %s containing %i revisions\n') |
|
154 | 155 | ui.note(msg % (unencoded, len(old_revlog))) |
|
155 | 156 | _copyrevlog(tr, dstrepo, old_revlog, rl_type, unencoded) |
|
156 | 157 | |
|
157 | 158 | newrl = _revlogfrompath(dstrepo, rl_type, unencoded) |
|
158 | 159 | return newrl |
|
159 | 160 | |
|
160 | 161 | |
|
161 | 162 | def _clonerevlogs( |
|
162 | 163 | ui, |
|
163 | 164 | srcrepo, |
|
164 | 165 | dstrepo, |
|
165 | 166 | tr, |
|
166 | 167 | upgrade_op, |
|
167 | 168 | ): |
|
168 | 169 | """Copy revlogs between 2 repos.""" |
|
169 | 170 | revcount = 0 |
|
170 | 171 | srcsize = 0 |
|
171 | 172 | srcrawsize = 0 |
|
172 | 173 | dstsize = 0 |
|
173 | 174 | fcount = 0 |
|
174 | 175 | frevcount = 0 |
|
175 | 176 | fsrcsize = 0 |
|
176 | 177 | frawsize = 0 |
|
177 | 178 | fdstsize = 0 |
|
178 | 179 | mcount = 0 |
|
179 | 180 | mrevcount = 0 |
|
180 | 181 | msrcsize = 0 |
|
181 | 182 | mrawsize = 0 |
|
182 | 183 | mdstsize = 0 |
|
183 | 184 | crevcount = 0 |
|
184 | 185 | csrcsize = 0 |
|
185 | 186 | crawsize = 0 |
|
186 | 187 | cdstsize = 0 |
|
187 | 188 | |
|
188 | 189 | alldatafiles = list(srcrepo.store.walk()) |
|
189 | 190 | # mapping of data files which needs to be cloned |
|
190 | 191 | # key is unencoded filename |
|
191 | 192 | # value is revlog_object_from_srcrepo |
|
192 | 193 | manifests = {} |
|
193 | 194 | changelogs = {} |
|
194 | 195 | filelogs = {} |
|
195 | 196 | |
|
196 | 197 | # Perform a pass to collect metadata. This validates we can open all |
|
197 | 198 | # source files and allows a unified progress bar to be displayed. |
|
198 | 199 | for rl_type, unencoded, encoded, size in alldatafiles: |
|
199 | 200 | if not rl_type & store.FILEFLAGS_REVLOG_MAIN: |
|
200 | 201 | continue |
|
201 | 202 | |
|
202 | 203 | rl = _revlogfrompath(srcrepo, rl_type, unencoded) |
|
203 | 204 | |
|
204 | 205 | info = rl.storageinfo( |
|
205 | 206 | exclusivefiles=True, |
|
206 | 207 | revisionscount=True, |
|
207 | 208 | trackedsize=True, |
|
208 | 209 | storedsize=True, |
|
209 | 210 | ) |
|
210 | 211 | |
|
211 | 212 | revcount += info[b'revisionscount'] or 0 |
|
212 | 213 | datasize = info[b'storedsize'] or 0 |
|
213 | 214 | rawsize = info[b'trackedsize'] or 0 |
|
214 | 215 | |
|
215 | 216 | srcsize += datasize |
|
216 | 217 | srcrawsize += rawsize |
|
217 | 218 | |
|
218 | 219 | # This is for the separate progress bars. |
|
219 | 220 | if rl_type & store.FILEFLAGS_CHANGELOG: |
|
220 | 221 | changelogs[unencoded] = (rl_type, rl) |
|
221 | 222 | crevcount += len(rl) |
|
222 | 223 | csrcsize += datasize |
|
223 | 224 | crawsize += rawsize |
|
224 | 225 | elif rl_type & store.FILEFLAGS_MANIFESTLOG: |
|
225 | 226 | manifests[unencoded] = (rl_type, rl) |
|
226 | 227 | mcount += 1 |
|
227 | 228 | mrevcount += len(rl) |
|
228 | 229 | msrcsize += datasize |
|
229 | 230 | mrawsize += rawsize |
|
230 | 231 | elif rl_type & store.FILEFLAGS_FILELOG: |
|
231 | 232 | filelogs[unencoded] = (rl_type, rl) |
|
232 | 233 | fcount += 1 |
|
233 | 234 | frevcount += len(rl) |
|
234 | 235 | fsrcsize += datasize |
|
235 | 236 | frawsize += rawsize |
|
236 | 237 | else: |
|
237 | 238 | error.ProgrammingError(b'unknown revlog type') |
|
238 | 239 | |
|
239 | 240 | if not revcount: |
|
240 | 241 | return |
|
241 | 242 | |
|
242 | 243 | ui.status( |
|
243 | 244 | _( |
|
244 | 245 | b'migrating %d total revisions (%d in filelogs, %d in manifests, ' |
|
245 | 246 | b'%d in changelog)\n' |
|
246 | 247 | ) |
|
247 | 248 | % (revcount, frevcount, mrevcount, crevcount) |
|
248 | 249 | ) |
|
249 | 250 | ui.status( |
|
250 | 251 | _(b'migrating %s in store; %s tracked data\n') |
|
251 | 252 | % ((util.bytecount(srcsize), util.bytecount(srcrawsize))) |
|
252 | 253 | ) |
|
253 | 254 | |
|
254 | 255 | # Used to keep track of progress. |
|
255 | 256 | progress = None |
|
256 | 257 | |
|
257 | 258 | def oncopiedrevision(rl, rev, node): |
|
258 | 259 | progress.increment() |
|
259 | 260 | |
|
260 | 261 | sidedata_helpers = get_sidedata_helpers(srcrepo, dstrepo) |
|
261 | 262 | |
|
262 | 263 | # Migrating filelogs |
|
263 | 264 | ui.status( |
|
264 | 265 | _( |
|
265 | 266 | b'migrating %d filelogs containing %d revisions ' |
|
266 | 267 | b'(%s in store; %s tracked data)\n' |
|
267 | 268 | ) |
|
268 | 269 | % ( |
|
269 | 270 | fcount, |
|
270 | 271 | frevcount, |
|
271 | 272 | util.bytecount(fsrcsize), |
|
272 | 273 | util.bytecount(frawsize), |
|
273 | 274 | ) |
|
274 | 275 | ) |
|
275 | 276 | progress = srcrepo.ui.makeprogress(_(b'file revisions'), total=frevcount) |
|
276 | 277 | for unencoded, (rl_type, oldrl) in sorted(filelogs.items()): |
|
277 | 278 | newrl = _perform_clone( |
|
278 | 279 | ui, |
|
279 | 280 | dstrepo, |
|
280 | 281 | tr, |
|
281 | 282 | oldrl, |
|
282 | 283 | rl_type, |
|
283 | 284 | unencoded, |
|
284 | 285 | upgrade_op, |
|
285 | 286 | sidedata_helpers, |
|
286 | 287 | oncopiedrevision, |
|
287 | 288 | ) |
|
288 | 289 | info = newrl.storageinfo(storedsize=True) |
|
289 | 290 | fdstsize += info[b'storedsize'] or 0 |
|
290 | 291 | ui.status( |
|
291 | 292 | _( |
|
292 | 293 | b'finished migrating %d filelog revisions across %d ' |
|
293 | 294 | b'filelogs; change in size: %s\n' |
|
294 | 295 | ) |
|
295 | 296 | % (frevcount, fcount, util.bytecount(fdstsize - fsrcsize)) |
|
296 | 297 | ) |
|
297 | 298 | |
|
298 | 299 | # Migrating manifests |
|
299 | 300 | ui.status( |
|
300 | 301 | _( |
|
301 | 302 | b'migrating %d manifests containing %d revisions ' |
|
302 | 303 | b'(%s in store; %s tracked data)\n' |
|
303 | 304 | ) |
|
304 | 305 | % ( |
|
305 | 306 | mcount, |
|
306 | 307 | mrevcount, |
|
307 | 308 | util.bytecount(msrcsize), |
|
308 | 309 | util.bytecount(mrawsize), |
|
309 | 310 | ) |
|
310 | 311 | ) |
|
311 | 312 | if progress: |
|
312 | 313 | progress.complete() |
|
313 | 314 | progress = srcrepo.ui.makeprogress( |
|
314 | 315 | _(b'manifest revisions'), total=mrevcount |
|
315 | 316 | ) |
|
316 | 317 | for unencoded, (rl_type, oldrl) in sorted(manifests.items()): |
|
317 | 318 | newrl = _perform_clone( |
|
318 | 319 | ui, |
|
319 | 320 | dstrepo, |
|
320 | 321 | tr, |
|
321 | 322 | oldrl, |
|
322 | 323 | rl_type, |
|
323 | 324 | unencoded, |
|
324 | 325 | upgrade_op, |
|
325 | 326 | sidedata_helpers, |
|
326 | 327 | oncopiedrevision, |
|
327 | 328 | ) |
|
328 | 329 | info = newrl.storageinfo(storedsize=True) |
|
329 | 330 | mdstsize += info[b'storedsize'] or 0 |
|
330 | 331 | ui.status( |
|
331 | 332 | _( |
|
332 | 333 | b'finished migrating %d manifest revisions across %d ' |
|
333 | 334 | b'manifests; change in size: %s\n' |
|
334 | 335 | ) |
|
335 | 336 | % (mrevcount, mcount, util.bytecount(mdstsize - msrcsize)) |
|
336 | 337 | ) |
|
337 | 338 | |
|
338 | 339 | # Migrating changelog |
|
339 | 340 | ui.status( |
|
340 | 341 | _( |
|
341 | 342 | b'migrating changelog containing %d revisions ' |
|
342 | 343 | b'(%s in store; %s tracked data)\n' |
|
343 | 344 | ) |
|
344 | 345 | % ( |
|
345 | 346 | crevcount, |
|
346 | 347 | util.bytecount(csrcsize), |
|
347 | 348 | util.bytecount(crawsize), |
|
348 | 349 | ) |
|
349 | 350 | ) |
|
350 | 351 | if progress: |
|
351 | 352 | progress.complete() |
|
352 | 353 | progress = srcrepo.ui.makeprogress( |
|
353 | 354 | _(b'changelog revisions'), total=crevcount |
|
354 | 355 | ) |
|
355 | 356 | for unencoded, (rl_type, oldrl) in sorted(changelogs.items()): |
|
356 | 357 | newrl = _perform_clone( |
|
357 | 358 | ui, |
|
358 | 359 | dstrepo, |
|
359 | 360 | tr, |
|
360 | 361 | oldrl, |
|
361 | 362 | rl_type, |
|
362 | 363 | unencoded, |
|
363 | 364 | upgrade_op, |
|
364 | 365 | sidedata_helpers, |
|
365 | 366 | oncopiedrevision, |
|
366 | 367 | ) |
|
367 | 368 | info = newrl.storageinfo(storedsize=True) |
|
368 | 369 | cdstsize += info[b'storedsize'] or 0 |
|
369 | 370 | progress.complete() |
|
370 | 371 | ui.status( |
|
371 | 372 | _( |
|
372 | 373 | b'finished migrating %d changelog revisions; change in size: ' |
|
373 | 374 | b'%s\n' |
|
374 | 375 | ) |
|
375 | 376 | % (crevcount, util.bytecount(cdstsize - csrcsize)) |
|
376 | 377 | ) |
|
377 | 378 | |
|
378 | 379 | dstsize = fdstsize + mdstsize + cdstsize |
|
379 | 380 | ui.status( |
|
380 | 381 | _( |
|
381 | 382 | b'finished migrating %d total revisions; total change in store ' |
|
382 | 383 | b'size: %s\n' |
|
383 | 384 | ) |
|
384 | 385 | % (revcount, util.bytecount(dstsize - srcsize)) |
|
385 | 386 | ) |
|
386 | 387 | |
|
387 | 388 | |
|
388 | 389 | def _files_to_copy_post_revlog_clone(srcrepo): |
|
389 | 390 | """yields files which should be copied to destination after revlogs |
|
390 | 391 | are cloned""" |
|
391 | 392 | for path, kind, st in sorted(srcrepo.store.vfs.readdir(b'', stat=True)): |
|
392 | 393 | # don't copy revlogs as they are already cloned |
|
393 | 394 | if store.revlog_type(path) is not None: |
|
394 | 395 | continue |
|
395 | 396 | # Skip transaction related files. |
|
396 | 397 | if path.startswith(b'undo'): |
|
397 | 398 | continue |
|
398 | 399 | # Only copy regular files. |
|
399 | 400 | if kind != stat.S_IFREG: |
|
400 | 401 | continue |
|
401 | 402 | # Skip other skipped files. |
|
402 | 403 | if path in (b'lock', b'fncache'): |
|
403 | 404 | continue |
|
404 | 405 | # TODO: should we skip cache too? |
|
405 | 406 | |
|
406 | 407 | yield path |
|
407 | 408 | |
|
408 | 409 | |
|
409 | 410 | def _replacestores(currentrepo, upgradedrepo, backupvfs, upgrade_op): |
|
410 | 411 | """Replace the stores after current repository is upgraded |
|
411 | 412 | |
|
412 | 413 | Creates a backup of current repository store at backup path |
|
413 | 414 | Replaces upgraded store files in current repo from upgraded one |
|
414 | 415 | |
|
415 | 416 | Arguments: |
|
416 | 417 | currentrepo: repo object of current repository |
|
417 | 418 | upgradedrepo: repo object of the upgraded data |
|
418 | 419 | backupvfs: vfs object for the backup path |
|
419 | 420 | upgrade_op: upgrade operation object |
|
420 | 421 | to be used to decide what all is upgraded |
|
421 | 422 | """ |
|
422 | 423 | # TODO: don't blindly rename everything in store |
|
423 | 424 | # There can be upgrades where store is not touched at all |
|
424 | 425 | if upgrade_op.backup_store: |
|
425 | 426 | util.rename(currentrepo.spath, backupvfs.join(b'store')) |
|
426 | 427 | else: |
|
427 | 428 | currentrepo.vfs.rmtree(b'store', forcibly=True) |
|
428 | 429 | util.rename(upgradedrepo.spath, currentrepo.spath) |
|
429 | 430 | |
|
430 | 431 | |
|
431 | 432 | def finishdatamigration(ui, srcrepo, dstrepo, requirements): |
|
432 | 433 | """Hook point for extensions to perform additional actions during upgrade. |
|
433 | 434 | |
|
434 | 435 | This function is called after revlogs and store files have been copied but |
|
435 | 436 | before the new store is swapped into the original location. |
|
436 | 437 | """ |
|
437 | 438 | |
|
438 | 439 | |
|
439 | 440 | def upgrade(ui, srcrepo, dstrepo, upgrade_op): |
|
440 | 441 | """Do the low-level work of upgrading a repository. |
|
441 | 442 | |
|
442 | 443 | The upgrade is effectively performed as a copy between a source |
|
443 | 444 | repository and a temporary destination repository. |
|
444 | 445 | |
|
445 | 446 | The source repository is unmodified for as long as possible so the |
|
446 | 447 | upgrade can abort at any time without causing loss of service for |
|
447 | 448 | readers and without corrupting the source repository. |
|
448 | 449 | """ |
|
449 | 450 | assert srcrepo.currentwlock() |
|
450 | 451 | assert dstrepo.currentwlock() |
|
451 | 452 | backuppath = None |
|
452 | 453 | backupvfs = None |
|
453 | 454 | |
|
454 | 455 | ui.status( |
|
455 | 456 | _( |
|
456 | 457 | b'(it is safe to interrupt this process any time before ' |
|
457 | 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 | 475 | if upgrade_op.requirements_only: |
|
462 | 476 | ui.status(_(b'upgrading repository requirements\n')) |
|
463 | 477 | scmutil.writereporequirements(srcrepo, upgrade_op.new_requirements) |
|
464 | 478 | # if there is only one action and that is persistent nodemap upgrade |
|
465 | 479 | # directly write the nodemap file and update requirements instead of going |
|
466 | 480 | # through the whole cloning process |
|
467 | 481 | elif ( |
|
468 | 482 | len(upgrade_op.upgrade_actions) == 1 |
|
469 |
and b'persistent-nodemap' in upgrade_op. |
|
|
483 | and b'persistent-nodemap' in upgrade_op.upgrade_actions_names | |
|
470 | 484 | and not upgrade_op.removed_actions |
|
471 | 485 | ): |
|
472 | 486 | ui.status( |
|
473 | 487 | _(b'upgrading repository to use persistent nodemap feature\n') |
|
474 | 488 | ) |
|
475 | 489 | with srcrepo.transaction(b'upgrade') as tr: |
|
476 | 490 | unfi = srcrepo.unfiltered() |
|
477 | 491 | cl = unfi.changelog |
|
478 | 492 | nodemap.persist_nodemap(tr, cl, force=True) |
|
479 | 493 | # we want to directly operate on the underlying revlog to force |
|
480 | 494 | # create a nodemap file. This is fine since this is upgrade code |
|
481 | 495 | # and it heavily relies on repository being revlog based |
|
482 | 496 | # hence accessing private attributes can be justified |
|
483 | 497 | nodemap.persist_nodemap( |
|
484 | 498 | tr, unfi.manifestlog._rootstore._revlog, force=True |
|
485 | 499 | ) |
|
486 | 500 | scmutil.writereporequirements(srcrepo, upgrade_op.new_requirements) |
|
487 | 501 | elif ( |
|
488 | 502 | len(upgrade_op.removed_actions) == 1 |
|
489 | 503 | and [ |
|
490 | 504 | x |
|
491 | 505 | for x in upgrade_op.removed_actions |
|
492 | 506 | if x.name == b'persistent-nodemap' |
|
493 | 507 | ] |
|
494 | 508 | and not upgrade_op.upgrade_actions |
|
495 | 509 | ): |
|
496 | 510 | ui.status( |
|
497 | 511 | _(b'downgrading repository to not use persistent nodemap feature\n') |
|
498 | 512 | ) |
|
499 | 513 | with srcrepo.transaction(b'upgrade') as tr: |
|
500 | 514 | unfi = srcrepo.unfiltered() |
|
501 | 515 | cl = unfi.changelog |
|
502 | 516 | nodemap.delete_nodemap(tr, srcrepo, cl) |
|
503 | 517 | # check comment 20 lines above for accessing private attributes |
|
504 | 518 | nodemap.delete_nodemap( |
|
505 | 519 | tr, srcrepo, unfi.manifestlog._rootstore._revlog |
|
506 | 520 | ) |
|
507 | 521 | scmutil.writereporequirements(srcrepo, upgrade_op.new_requirements) |
|
508 | 522 | else: |
|
509 | 523 | with dstrepo.transaction(b'upgrade') as tr: |
|
510 | 524 | _clonerevlogs( |
|
511 | 525 | ui, |
|
512 | 526 | srcrepo, |
|
513 | 527 | dstrepo, |
|
514 | 528 | tr, |
|
515 | 529 | upgrade_op, |
|
516 | 530 | ) |
|
517 | 531 | |
|
518 | 532 | # Now copy other files in the store directory. |
|
519 | 533 | for p in _files_to_copy_post_revlog_clone(srcrepo): |
|
520 | 534 | srcrepo.ui.status(_(b'copying %s\n') % p) |
|
521 | 535 | src = srcrepo.store.rawvfs.join(p) |
|
522 | 536 | dst = dstrepo.store.rawvfs.join(p) |
|
523 | 537 | util.copyfile(src, dst, copystat=True) |
|
524 | 538 | |
|
525 | 539 | finishdatamigration(ui, srcrepo, dstrepo, requirements) |
|
526 | 540 | |
|
527 | 541 | ui.status(_(b'data fully upgraded in a temporary repository\n')) |
|
528 | 542 | |
|
529 | 543 | if upgrade_op.backup_store: |
|
530 | 544 | backuppath = pycompat.mkdtemp( |
|
531 | 545 | prefix=b'upgradebackup.', dir=srcrepo.path |
|
532 | 546 | ) |
|
533 | 547 | backupvfs = vfsmod.vfs(backuppath) |
|
534 | 548 | |
|
535 | 549 | # Make a backup of requires file first, as it is the first to be modified. |
|
536 | 550 | util.copyfile( |
|
537 | 551 | srcrepo.vfs.join(b'requires'), backupvfs.join(b'requires') |
|
538 | 552 | ) |
|
539 | 553 | |
|
540 | 554 | # We install an arbitrary requirement that clients must not support |
|
541 | 555 | # as a mechanism to lock out new clients during the data swap. This is |
|
542 | 556 | # better than allowing a client to continue while the repository is in |
|
543 | 557 | # an inconsistent state. |
|
544 | 558 | ui.status( |
|
545 | 559 | _( |
|
546 | 560 | b'marking source repository as being upgraded; clients will be ' |
|
547 | 561 | b'unable to read from repository\n' |
|
548 | 562 | ) |
|
549 | 563 | ) |
|
550 | 564 | scmutil.writereporequirements( |
|
551 | 565 | srcrepo, srcrepo.requirements | {b'upgradeinprogress'} |
|
552 | 566 | ) |
|
553 | 567 | |
|
554 | 568 | ui.status(_(b'starting in-place swap of repository data\n')) |
|
555 | 569 | if upgrade_op.backup_store: |
|
556 | 570 | ui.status( |
|
557 | 571 | _(b'replaced files will be backed up at %s\n') % backuppath |
|
558 | 572 | ) |
|
559 | 573 | |
|
560 | 574 | # Now swap in the new store directory. Doing it as a rename should make |
|
561 | 575 | # the operation nearly instantaneous and atomic (at least in well-behaved |
|
562 | 576 | # environments). |
|
563 | 577 | ui.status(_(b'replacing store...\n')) |
|
564 | 578 | tstart = util.timer() |
|
565 | 579 | _replacestores(srcrepo, dstrepo, backupvfs, upgrade_op) |
|
566 | 580 | elapsed = util.timer() - tstart |
|
567 | 581 | ui.status( |
|
568 | 582 | _( |
|
569 | 583 | b'store replacement complete; repository was inconsistent for ' |
|
570 | 584 | b'%0.1fs\n' |
|
571 | 585 | ) |
|
572 | 586 | % elapsed |
|
573 | 587 | ) |
|
574 | 588 | |
|
575 | 589 | # We first write the requirements file. Any new requirements will lock |
|
576 | 590 | # out legacy clients. |
|
577 | 591 | ui.status( |
|
578 | 592 | _( |
|
579 | 593 | b'finalizing requirements file and making repository readable ' |
|
580 | 594 | b'again\n' |
|
581 | 595 | ) |
|
582 | 596 | ) |
|
583 | 597 | scmutil.writereporequirements(srcrepo, upgrade_op.new_requirements) |
|
584 | 598 | |
|
585 | 599 | if upgrade_op.backup_store: |
|
586 | 600 | # The lock file from the old store won't be removed because nothing has a |
|
587 | 601 | # reference to its new location. So clean it up manually. Alternatively, we |
|
588 | 602 | # could update srcrepo.svfs and other variables to point to the new |
|
589 | 603 | # location. This is simpler. |
|
590 | 604 | assert backupvfs is not None # help pytype |
|
591 | 605 | backupvfs.unlink(b'store/lock') |
|
592 | 606 | |
|
593 | 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 | |||
|
1 | 1 | #testcases filelog compatibility changeset sidedata upgraded upgraded-parallel pull push pull-upgrade push-upgrade |
|
2 | 2 | |
|
3 | 3 | ===================================================== |
|
4 | 4 | Test Copy tracing for chain of copies involving merge |
|
5 | 5 | ===================================================== |
|
6 | 6 | |
|
7 | 7 | This test files covers copies/rename case for a chains of commit where merges |
|
8 | 8 | are involved. It cheks we do not have unwanted update of behavior and that the |
|
9 | 9 | different options to retrieve copies behave correctly. |
|
10 | 10 | |
|
11 | 11 | |
|
12 | 12 | Setup |
|
13 | 13 | ===== |
|
14 | 14 | |
|
15 | 15 | use git diff to see rename |
|
16 | 16 | |
|
17 | 17 | $ cat << EOF >> ./no-linkrev |
|
18 | 18 | > #!$PYTHON |
|
19 | 19 | > # filter out linkrev part of the debugindex command |
|
20 | 20 | > import sys |
|
21 | 21 | > for line in sys.stdin: |
|
22 | 22 | > if " linkrev " in line: |
|
23 | 23 | > print(line.rstrip()) |
|
24 | 24 | > else: |
|
25 | 25 | > l = "%s *%s" % (line[:6], line[14:].rstrip()) |
|
26 | 26 | > print(l) |
|
27 | 27 | > EOF |
|
28 | 28 | |
|
29 | 29 | $ cat << EOF >> $HGRCPATH |
|
30 | 30 | > [diff] |
|
31 | 31 | > git=yes |
|
32 | 32 | > [command-templates] |
|
33 | 33 | > log={desc}\n |
|
34 | 34 | > EOF |
|
35 | 35 | |
|
36 | 36 | #if compatibility |
|
37 | 37 | $ cat >> $HGRCPATH << EOF |
|
38 | 38 | > [experimental] |
|
39 | 39 | > copies.read-from = compatibility |
|
40 | 40 | > EOF |
|
41 | 41 | #endif |
|
42 | 42 | |
|
43 | 43 | #if changeset |
|
44 | 44 | $ cat >> $HGRCPATH << EOF |
|
45 | 45 | > [experimental] |
|
46 | 46 | > copies.read-from = changeset-only |
|
47 | 47 | > copies.write-to = changeset-only |
|
48 | 48 | > EOF |
|
49 | 49 | #endif |
|
50 | 50 | |
|
51 | 51 | #if sidedata |
|
52 | 52 | $ cat >> $HGRCPATH << EOF |
|
53 | 53 | > [format] |
|
54 | 54 | > exp-use-copies-side-data-changeset = yes |
|
55 | 55 | > EOF |
|
56 | 56 | #endif |
|
57 | 57 | |
|
58 | 58 | #if pull |
|
59 | 59 | $ cat >> $HGRCPATH << EOF |
|
60 | 60 | > [format] |
|
61 | 61 | > exp-use-copies-side-data-changeset = yes |
|
62 | 62 | > EOF |
|
63 | 63 | #endif |
|
64 | 64 | |
|
65 | 65 | #if push |
|
66 | 66 | $ cat >> $HGRCPATH << EOF |
|
67 | 67 | > [format] |
|
68 | 68 | > exp-use-copies-side-data-changeset = yes |
|
69 | 69 | > EOF |
|
70 | 70 | #endif |
|
71 | 71 | |
|
72 | 72 | #if pull-upgrade |
|
73 | 73 | $ cat >> $HGRCPATH << EOF |
|
74 | 74 | > [format] |
|
75 | 75 | > exp-use-copies-side-data-changeset = no |
|
76 | 76 | > [experimental] |
|
77 | 77 | > changegroup4 = yes |
|
78 | 78 | > EOF |
|
79 | 79 | #endif |
|
80 | 80 | |
|
81 | 81 | #if push-upgrade |
|
82 | 82 | $ cat >> $HGRCPATH << EOF |
|
83 | 83 | > [format] |
|
84 | 84 | > exp-use-copies-side-data-changeset = no |
|
85 | 85 | > [experimental] |
|
86 | 86 | > changegroup4 = yes |
|
87 | 87 | > EOF |
|
88 | 88 | #endif |
|
89 | 89 | |
|
90 | 90 | $ cat > same-content.txt << EOF |
|
91 | 91 | > Here is some content that will be the same accros multiple file. |
|
92 | 92 | > |
|
93 | 93 | > This is done on purpose so that we end up in some merge situation, were the |
|
94 | 94 | > resulting content is the same as in the parent(s), but a new filenodes still |
|
95 | 95 | > need to be created to record some file history information (especially |
|
96 | 96 | > about copies). |
|
97 | 97 | > EOF |
|
98 | 98 | |
|
99 | 99 | $ hg init repo-chain |
|
100 | 100 | $ cd repo-chain |
|
101 | 101 | |
|
102 | 102 | Add some linear rename initialy |
|
103 | 103 | |
|
104 | 104 | $ cp ../same-content.txt a |
|
105 | 105 | $ cp ../same-content.txt b |
|
106 | 106 | $ cp ../same-content.txt h |
|
107 | 107 | $ echo "original content for P" > p |
|
108 | 108 | $ echo "original content for Q" > q |
|
109 | 109 | $ echo "original content for R" > r |
|
110 | 110 | $ hg ci -Am 'i-0 initial commit: a b h p q r' |
|
111 | 111 | adding a |
|
112 | 112 | adding b |
|
113 | 113 | adding h |
|
114 | 114 | adding p |
|
115 | 115 | adding q |
|
116 | 116 | adding r |
|
117 | 117 | $ hg mv a c |
|
118 | 118 | $ hg mv p s |
|
119 | 119 | $ hg ci -Am 'i-1: a -move-> c, p -move-> s' |
|
120 | 120 | $ hg mv c d |
|
121 | 121 | $ hg mv s t |
|
122 | 122 | $ hg ci -Am 'i-2: c -move-> d, s -move-> t' |
|
123 | 123 | $ hg log -G |
|
124 | 124 | @ i-2: c -move-> d, s -move-> t |
|
125 | 125 | | |
|
126 | 126 | o i-1: a -move-> c, p -move-> s |
|
127 | 127 | | |
|
128 | 128 | o i-0 initial commit: a b h p q r |
|
129 | 129 | |
|
130 | 130 | |
|
131 | 131 | And having another branch with renames on the other side |
|
132 | 132 | |
|
133 | 133 | $ hg mv d e |
|
134 | 134 | $ hg ci -Am 'a-1: d -move-> e' |
|
135 | 135 | $ hg mv e f |
|
136 | 136 | $ hg ci -Am 'a-2: e -move-> f' |
|
137 | 137 | $ hg log -G --rev '::.' |
|
138 | 138 | @ a-2: e -move-> f |
|
139 | 139 | | |
|
140 | 140 | o a-1: d -move-> e |
|
141 | 141 | | |
|
142 | 142 | o i-2: c -move-> d, s -move-> t |
|
143 | 143 | | |
|
144 | 144 | o i-1: a -move-> c, p -move-> s |
|
145 | 145 | | |
|
146 | 146 | o i-0 initial commit: a b h p q r |
|
147 | 147 | |
|
148 | 148 | |
|
149 | 149 | Have a branching with nothing on one side |
|
150 | 150 | |
|
151 | 151 | $ hg up 'desc("i-2")' |
|
152 | 152 | 1 files updated, 0 files merged, 1 files removed, 0 files unresolved |
|
153 | 153 | $ echo foo > b |
|
154 | 154 | $ hg ci -m 'b-1: b update' |
|
155 | 155 | created new head |
|
156 | 156 | $ hg log -G --rev '::.' |
|
157 | 157 | @ b-1: b update |
|
158 | 158 | | |
|
159 | 159 | o i-2: c -move-> d, s -move-> t |
|
160 | 160 | | |
|
161 | 161 | o i-1: a -move-> c, p -move-> s |
|
162 | 162 | | |
|
163 | 163 | o i-0 initial commit: a b h p q r |
|
164 | 164 | |
|
165 | 165 | |
|
166 | 166 | Create a branch that delete a file previous renamed |
|
167 | 167 | |
|
168 | 168 | $ hg up 'desc("i-2")' |
|
169 | 169 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
170 | 170 | $ hg rm d |
|
171 | 171 | $ hg ci -m 'c-1 delete d' |
|
172 | 172 | created new head |
|
173 | 173 | $ hg log -G --rev '::.' |
|
174 | 174 | @ c-1 delete d |
|
175 | 175 | | |
|
176 | 176 | o i-2: c -move-> d, s -move-> t |
|
177 | 177 | | |
|
178 | 178 | o i-1: a -move-> c, p -move-> s |
|
179 | 179 | | |
|
180 | 180 | o i-0 initial commit: a b h p q r |
|
181 | 181 | |
|
182 | 182 | |
|
183 | 183 | Create a branch that delete a file previous renamed and recreate it |
|
184 | 184 | |
|
185 | 185 | $ hg up 'desc("i-2")' |
|
186 | 186 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
187 | 187 | $ hg rm d |
|
188 | 188 | $ hg ci -m 'd-1 delete d' |
|
189 | 189 | created new head |
|
190 | 190 | $ echo bar > d |
|
191 | 191 | $ hg add d |
|
192 | 192 | $ hg ci -m 'd-2 re-add d' |
|
193 | 193 | $ hg log -G --rev '::.' |
|
194 | 194 | @ d-2 re-add d |
|
195 | 195 | | |
|
196 | 196 | o d-1 delete d |
|
197 | 197 | | |
|
198 | 198 | o i-2: c -move-> d, s -move-> t |
|
199 | 199 | | |
|
200 | 200 | o i-1: a -move-> c, p -move-> s |
|
201 | 201 | | |
|
202 | 202 | o i-0 initial commit: a b h p q r |
|
203 | 203 | |
|
204 | 204 | |
|
205 | 205 | Having another branch renaming a different file to the same filename as another |
|
206 | 206 | |
|
207 | 207 | $ hg up 'desc("i-2")' |
|
208 | 208 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
209 | 209 | $ hg mv b g |
|
210 | 210 | $ hg ci -m 'e-1 b -move-> g' |
|
211 | 211 | created new head |
|
212 | 212 | $ hg mv g f |
|
213 | 213 | $ hg ci -m 'e-2 g -move-> f' |
|
214 | 214 | $ hg log -G --rev '::.' |
|
215 | 215 | @ e-2 g -move-> f |
|
216 | 216 | | |
|
217 | 217 | o e-1 b -move-> g |
|
218 | 218 | | |
|
219 | 219 | o i-2: c -move-> d, s -move-> t |
|
220 | 220 | | |
|
221 | 221 | o i-1: a -move-> c, p -move-> s |
|
222 | 222 | | |
|
223 | 223 | o i-0 initial commit: a b h p q r |
|
224 | 224 | |
|
225 | 225 | $ hg up -q null |
|
226 | 226 | |
|
227 | 227 | Having a branch similar to the 'a' one, but moving the 'p' file around. |
|
228 | 228 | |
|
229 | 229 | $ hg up 'desc("i-2")' |
|
230 | 230 | 6 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
231 | 231 | $ hg mv t u |
|
232 | 232 | $ hg ci -Am 'p-1: t -move-> u' |
|
233 | 233 | created new head |
|
234 | 234 | $ hg mv u v |
|
235 | 235 | $ hg ci -Am 'p-2: u -move-> v' |
|
236 | 236 | $ hg log -G --rev '::.' |
|
237 | 237 | @ p-2: u -move-> v |
|
238 | 238 | | |
|
239 | 239 | o p-1: t -move-> u |
|
240 | 240 | | |
|
241 | 241 | o i-2: c -move-> d, s -move-> t |
|
242 | 242 | | |
|
243 | 243 | o i-1: a -move-> c, p -move-> s |
|
244 | 244 | | |
|
245 | 245 | o i-0 initial commit: a b h p q r |
|
246 | 246 | |
|
247 | 247 | $ hg up -q null |
|
248 | 248 | |
|
249 | 249 | Having another branch renaming a different file to the same filename as another |
|
250 | 250 | |
|
251 | 251 | $ hg up 'desc("i-2")' |
|
252 | 252 | 6 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
253 | 253 | $ hg mv r w |
|
254 | 254 | $ hg ci -m 'q-1 r -move-> w' |
|
255 | 255 | created new head |
|
256 | 256 | $ hg mv w v |
|
257 | 257 | $ hg ci -m 'q-2 w -move-> v' |
|
258 | 258 | $ hg log -G --rev '::.' |
|
259 | 259 | @ q-2 w -move-> v |
|
260 | 260 | | |
|
261 | 261 | o q-1 r -move-> w |
|
262 | 262 | | |
|
263 | 263 | o i-2: c -move-> d, s -move-> t |
|
264 | 264 | | |
|
265 | 265 | o i-1: a -move-> c, p -move-> s |
|
266 | 266 | | |
|
267 | 267 | o i-0 initial commit: a b h p q r |
|
268 | 268 | |
|
269 | 269 | $ hg up -q null |
|
270 | 270 | |
|
271 | 271 | Setup all merge |
|
272 | 272 | =============== |
|
273 | 273 | |
|
274 | 274 | This is done beforehand to validate that the upgrade process creates valid copy |
|
275 | 275 | information. |
|
276 | 276 | |
|
277 | 277 | merging with unrelated change does not interfere with the renames |
|
278 | 278 | --------------------------------------------------------------- |
|
279 | 279 | |
|
280 | 280 | - rename on one side |
|
281 | 281 | - unrelated change on the other side |
|
282 | 282 | |
|
283 | 283 | $ case_desc="simple merge - A side: multiple renames, B side: unrelated update" |
|
284 | 284 | |
|
285 | 285 | $ hg up 'desc("b-1")' |
|
286 | 286 | 6 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
287 | 287 | $ hg merge 'desc("a-2")' |
|
288 | 288 | 1 files updated, 0 files merged, 1 files removed, 0 files unresolved |
|
289 | 289 | (branch merge, don't forget to commit) |
|
290 | 290 | $ hg ci -m "mBAm-0 $case_desc - one way" |
|
291 | 291 | $ hg up 'desc("a-2")' |
|
292 | 292 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
293 | 293 | $ hg merge 'desc("b-1")' |
|
294 | 294 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
295 | 295 | (branch merge, don't forget to commit) |
|
296 | 296 | $ hg ci -m "mABm-0 $case_desc - the other way" |
|
297 | 297 | created new head |
|
298 | 298 | $ hg log -G --rev '::(desc("mABm")+desc("mBAm"))' |
|
299 | 299 | @ mABm-0 simple merge - A side: multiple renames, B side: unrelated update - the other way |
|
300 | 300 | |\ |
|
301 | 301 | +---o mBAm-0 simple merge - A side: multiple renames, B side: unrelated update - one way |
|
302 | 302 | | |/ |
|
303 | 303 | | o b-1: b update |
|
304 | 304 | | | |
|
305 | 305 | o | a-2: e -move-> f |
|
306 | 306 | | | |
|
307 | 307 | o | a-1: d -move-> e |
|
308 | 308 | |/ |
|
309 | 309 | o i-2: c -move-> d, s -move-> t |
|
310 | 310 | | |
|
311 | 311 | o i-1: a -move-> c, p -move-> s |
|
312 | 312 | | |
|
313 | 313 | o i-0 initial commit: a b h p q r |
|
314 | 314 | |
|
315 | 315 | |
|
316 | 316 | |
|
317 | 317 | merging with the side having a delete |
|
318 | 318 | ------------------------------------- |
|
319 | 319 | |
|
320 | 320 | case summary: |
|
321 | 321 | - one with change to an unrelated file |
|
322 | 322 | - one deleting the change |
|
323 | 323 | and recreate an unrelated file after the merge |
|
324 | 324 | |
|
325 | 325 | $ case_desc="simple merge - C side: delete a file with copies history , B side: unrelated update" |
|
326 | 326 | |
|
327 | 327 | $ hg up 'desc("b-1")' |
|
328 | 328 | 1 files updated, 0 files merged, 1 files removed, 0 files unresolved |
|
329 | 329 | $ hg merge 'desc("c-1")' |
|
330 | 330 | 0 files updated, 0 files merged, 1 files removed, 0 files unresolved |
|
331 | 331 | (branch merge, don't forget to commit) |
|
332 | 332 | $ hg ci -m "mBCm-0 $case_desc - one way" |
|
333 | 333 | $ echo bar > d |
|
334 | 334 | $ hg add d |
|
335 | 335 | $ hg ci -m 'mBCm-1 re-add d' |
|
336 | 336 | $ hg up 'desc("c-1")' |
|
337 | 337 | 1 files updated, 0 files merged, 1 files removed, 0 files unresolved |
|
338 | 338 | $ hg merge 'desc("b-1")' |
|
339 | 339 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
340 | 340 | (branch merge, don't forget to commit) |
|
341 | 341 | $ hg ci -m "mCBm-0 $case_desc - the other way" |
|
342 | 342 | created new head |
|
343 | 343 | $ echo bar > d |
|
344 | 344 | $ hg add d |
|
345 | 345 | $ hg ci -m 'mCBm-1 re-add d' |
|
346 | 346 | $ hg log -G --rev '::(desc("mCBm")+desc("mBCm"))' |
|
347 | 347 | @ mCBm-1 re-add d |
|
348 | 348 | | |
|
349 | 349 | o mCBm-0 simple merge - C side: delete a file with copies history , B side: unrelated update - the other way |
|
350 | 350 | |\ |
|
351 | 351 | | | o mBCm-1 re-add d |
|
352 | 352 | | | | |
|
353 | 353 | +---o mBCm-0 simple merge - C side: delete a file with copies history , B side: unrelated update - one way |
|
354 | 354 | | |/ |
|
355 | 355 | | o c-1 delete d |
|
356 | 356 | | | |
|
357 | 357 | o | b-1: b update |
|
358 | 358 | |/ |
|
359 | 359 | o i-2: c -move-> d, s -move-> t |
|
360 | 360 | | |
|
361 | 361 | o i-1: a -move-> c, p -move-> s |
|
362 | 362 | | |
|
363 | 363 | o i-0 initial commit: a b h p q r |
|
364 | 364 | |
|
365 | 365 | |
|
366 | 366 | Comparing with a merge re-adding the file afterward |
|
367 | 367 | --------------------------------------------------- |
|
368 | 368 | |
|
369 | 369 | Merge: |
|
370 | 370 | - one with change to an unrelated file |
|
371 | 371 | - one deleting and recreating the change |
|
372 | 372 | |
|
373 | 373 | $ case_desc="simple merge - B side: unrelated update, D side: delete and recreate a file (with different content)" |
|
374 | 374 | |
|
375 | 375 | $ hg up 'desc("b-1")' |
|
376 | 376 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
377 | 377 | $ hg merge 'desc("d-2")' |
|
378 | 378 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
379 | 379 | (branch merge, don't forget to commit) |
|
380 | 380 | $ hg ci -m "mBDm-0 $case_desc - one way" |
|
381 | 381 | $ hg up 'desc("d-2")' |
|
382 | 382 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
383 | 383 | $ hg merge 'desc("b-1")' |
|
384 | 384 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
385 | 385 | (branch merge, don't forget to commit) |
|
386 | 386 | $ hg ci -m "mDBm-0 $case_desc - the other way" |
|
387 | 387 | created new head |
|
388 | 388 | $ hg log -G --rev '::(desc("mDBm")+desc("mBDm"))' |
|
389 | 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 | 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 | 393 | | o d-2 re-add d |
|
394 | 394 | | | |
|
395 | 395 | | o d-1 delete d |
|
396 | 396 | | | |
|
397 | 397 | o | b-1: b update |
|
398 | 398 | |/ |
|
399 | 399 | o i-2: c -move-> d, s -move-> t |
|
400 | 400 | | |
|
401 | 401 | o i-1: a -move-> c, p -move-> s |
|
402 | 402 | | |
|
403 | 403 | o i-0 initial commit: a b h p q r |
|
404 | 404 | |
|
405 | 405 | |
|
406 | 406 | |
|
407 | 407 | Comparing with a merge with colliding rename |
|
408 | 408 | -------------------------------------------- |
|
409 | 409 | |
|
410 | 410 | Subcase: new copy information on both side |
|
411 | 411 | `````````````````````````````````````````` |
|
412 | 412 | |
|
413 | 413 | - the "e-" branch renaming b to f (through 'g') |
|
414 | 414 | - the "a-" branch renaming d to f (through e) |
|
415 | 415 | |
|
416 | 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 | 418 | $ hg up 'desc("a-2")' |
|
419 | 419 | 2 files updated, 0 files merged, 1 files removed, 0 files unresolved |
|
420 | 420 | $ hg merge 'desc("e-2")' |
|
421 | 421 | 1 files updated, 0 files merged, 1 files removed, 0 files unresolved (no-changeset !) |
|
422 | 422 | 0 files updated, 0 files merged, 1 files removed, 0 files unresolved (changeset !) |
|
423 | 423 | (branch merge, don't forget to commit) |
|
424 | 424 | $ hg ci -m "mAEm-0 $case_desc - one way" |
|
425 | 425 | $ hg up 'desc("e-2")' |
|
426 | 426 | 2 files updated, 0 files merged, 0 files removed, 0 files unresolved (no-changeset !) |
|
427 | 427 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved (changeset !) |
|
428 | 428 | $ hg merge 'desc("a-2")' |
|
429 | 429 | 1 files updated, 0 files merged, 1 files removed, 0 files unresolved (no-changeset !) |
|
430 | 430 | 0 files updated, 0 files merged, 1 files removed, 0 files unresolved (changeset !) |
|
431 | 431 | (branch merge, don't forget to commit) |
|
432 | 432 | $ hg ci -m "mEAm-0 $case_desc - the other way" |
|
433 | 433 | created new head |
|
434 | 434 | $ hg log -G --rev '::(desc("mAEm")+desc("mEAm"))' |
|
435 | 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 | 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 | 439 | | o e-2 g -move-> f |
|
440 | 440 | | | |
|
441 | 441 | | o e-1 b -move-> g |
|
442 | 442 | | | |
|
443 | 443 | o | a-2: e -move-> f |
|
444 | 444 | | | |
|
445 | 445 | o | a-1: d -move-> e |
|
446 | 446 | |/ |
|
447 | 447 | o i-2: c -move-> d, s -move-> t |
|
448 | 448 | | |
|
449 | 449 | o i-1: a -move-> c, p -move-> s |
|
450 | 450 | | |
|
451 | 451 | o i-0 initial commit: a b h p q r |
|
452 | 452 | |
|
453 | 453 | |
|
454 | 454 | Subcase: new copy information on both side with an actual merge happening |
|
455 | 455 | ````````````````````````````````````````````````````````````````````````` |
|
456 | 456 | |
|
457 | 457 | - the "p-" branch renaming 't' to 'v' (through 'u') |
|
458 | 458 | - the "q-" branch renaming 'r' to 'v' (through 'w') |
|
459 | 459 | |
|
460 | 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 | 462 | $ hg up 'desc("p-2")' |
|
463 | 463 | 3 files updated, 0 files merged, 2 files removed, 0 files unresolved |
|
464 | 464 | $ hg merge 'desc("q-2")' --tool ':union' |
|
465 | 465 | merging v |
|
466 | 466 | 1 files updated, 0 files merged, 1 files removed, 0 files unresolved |
|
467 | 467 | (branch merge, don't forget to commit) |
|
468 | 468 | $ hg ci -m "mPQm-0 $case_desc - one way" |
|
469 | 469 | $ hg up 'desc("q-2")' |
|
470 | 470 | 2 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
471 | 471 | $ hg merge 'desc("p-2")' --tool ':union' |
|
472 | 472 | merging v |
|
473 | 473 | 1 files updated, 0 files merged, 1 files removed, 0 files unresolved |
|
474 | 474 | (branch merge, don't forget to commit) |
|
475 | 475 | $ hg ci -m "mQPm-0 $case_desc - the other way" |
|
476 | 476 | created new head |
|
477 | 477 | $ hg log -G --rev '::(desc("mAEm")+desc("mEAm"))' |
|
478 | 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 | 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 | 482 | | o e-2 g -move-> f |
|
483 | 483 | | | |
|
484 | 484 | | o e-1 b -move-> g |
|
485 | 485 | | | |
|
486 | 486 | o | a-2: e -move-> f |
|
487 | 487 | | | |
|
488 | 488 | o | a-1: d -move-> e |
|
489 | 489 | |/ |
|
490 | 490 | o i-2: c -move-> d, s -move-> t |
|
491 | 491 | | |
|
492 | 492 | o i-1: a -move-> c, p -move-> s |
|
493 | 493 | | |
|
494 | 494 | o i-0 initial commit: a b h p q r |
|
495 | 495 | |
|
496 | 496 | |
|
497 | 497 | Subcase: existing copy information overwritten on one branch |
|
498 | 498 | ```````````````````````````````````````````````````````````` |
|
499 | 499 | |
|
500 | 500 | Merge: |
|
501 | 501 | - one with change to an unrelated file (b) |
|
502 | 502 | - one overwriting a file (d) with a rename (from h to i to d) |
|
503 | 503 | |
|
504 | 504 | $ case_desc="simple merge - B side: unrelated change, F side: overwrite d with a copy (from h->i->d)" |
|
505 | 505 | |
|
506 | 506 | $ hg up 'desc("i-2")' |
|
507 | 507 | 2 files updated, 0 files merged, 1 files removed, 0 files unresolved |
|
508 | 508 | $ hg mv h i |
|
509 | 509 | $ hg commit -m "f-1: rename h -> i" |
|
510 | 510 | created new head |
|
511 | 511 | $ hg mv --force i d |
|
512 | 512 | $ hg commit -m "f-2: rename i -> d" |
|
513 | 513 | $ hg debugindex d | "$PYTHON" ../no-linkrev |
|
514 | 514 | rev linkrev nodeid p1 p2 |
|
515 | 515 | 0 * d8252ab2e760 000000000000 000000000000 (no-changeset !) |
|
516 | 516 | 0 * ae258f702dfe 000000000000 000000000000 (changeset !) |
|
517 | 517 | 1 * b004912a8510 000000000000 000000000000 |
|
518 | 518 | 2 * 7b79e2fe0c89 000000000000 000000000000 (no-changeset !) |
|
519 | 519 | $ hg up 'desc("b-1")' |
|
520 | 520 | 3 files updated, 0 files merged, 0 files removed, 0 files unresolved (no-changeset !) |
|
521 | 521 | 2 files updated, 0 files merged, 0 files removed, 0 files unresolved (changeset !) |
|
522 | 522 | $ hg merge 'desc("f-2")' |
|
523 | 523 | 1 files updated, 0 files merged, 1 files removed, 0 files unresolved (no-changeset !) |
|
524 | 524 | 0 files updated, 0 files merged, 1 files removed, 0 files unresolved (changeset !) |
|
525 | 525 | (branch merge, don't forget to commit) |
|
526 | 526 | $ hg ci -m "mBFm-0 $case_desc - one way" |
|
527 | 527 | $ hg up 'desc("f-2")' |
|
528 | 528 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
529 | 529 | $ hg merge 'desc("b-1")' |
|
530 | 530 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
531 | 531 | (branch merge, don't forget to commit) |
|
532 | 532 | $ hg ci -m "mFBm-0 $case_desc - the other way" |
|
533 | 533 | created new head |
|
534 | 534 | $ hg up null --quiet |
|
535 | 535 | $ hg log -G --rev '::(desc("mBFm")+desc("mFBm"))' |
|
536 | 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 | 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 | 540 | | o f-2: rename i -> d |
|
541 | 541 | | | |
|
542 | 542 | | o f-1: rename h -> i |
|
543 | 543 | | | |
|
544 | 544 | o | b-1: b update |
|
545 | 545 | |/ |
|
546 | 546 | o i-2: c -move-> d, s -move-> t |
|
547 | 547 | | |
|
548 | 548 | o i-1: a -move-> c, p -move-> s |
|
549 | 549 | | |
|
550 | 550 | o i-0 initial commit: a b h p q r |
|
551 | 551 | |
|
552 | 552 | |
|
553 | 553 | Subcase: existing copy information overwritten on one branch, with different content) |
|
554 | 554 | ````````````````````````````````````````````````````````````````````````````````````` |
|
555 | 555 | |
|
556 | 556 | Merge: |
|
557 | 557 | - one with change to an unrelated file (b) |
|
558 | 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 | 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 | 562 | $ hg up 'desc("i-2")' |
|
563 | 563 | 6 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
564 | 564 | $ hg mv r x |
|
565 | 565 | $ hg commit -m "r-1: rename r -> x" |
|
566 | 566 | created new head |
|
567 | 567 | $ hg mv --force x t |
|
568 | 568 | $ hg commit -m "r-2: rename t -> x" |
|
569 | 569 | $ hg debugindex t | "$PYTHON" ../no-linkrev |
|
570 | 570 | rev linkrev nodeid p1 p2 |
|
571 | 571 | 0 * d74efbf65309 000000000000 000000000000 (no-changeset !) |
|
572 | 572 | 1 * 02a930b9d7ad 000000000000 000000000000 (no-changeset !) |
|
573 | 573 | 0 * 5aed6a8dbff0 000000000000 000000000000 (changeset !) |
|
574 | 574 | 1 * a38b2fa17021 000000000000 000000000000 (changeset !) |
|
575 | 575 | $ hg up 'desc("b-1")' |
|
576 | 576 | 3 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
577 | 577 | $ hg merge 'desc("r-2")' |
|
578 | 578 | 1 files updated, 0 files merged, 1 files removed, 0 files unresolved |
|
579 | 579 | (branch merge, don't forget to commit) |
|
580 | 580 | $ hg ci -m "mBRm-0 $case_desc - one way" |
|
581 | 581 | $ hg up 'desc("r-2")' |
|
582 | 582 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
583 | 583 | $ hg merge 'desc("b-1")' |
|
584 | 584 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
585 | 585 | (branch merge, don't forget to commit) |
|
586 | 586 | $ hg ci -m "mRBm-0 $case_desc - the other way" |
|
587 | 587 | created new head |
|
588 | 588 | $ hg up null --quiet |
|
589 | 589 | $ hg log -G --rev '::(desc("mBRm")+desc("mRBm"))' |
|
590 | 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 | 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 | 594 | | o r-2: rename t -> x |
|
595 | 595 | | | |
|
596 | 596 | | o r-1: rename r -> x |
|
597 | 597 | | | |
|
598 | 598 | o | b-1: b update |
|
599 | 599 | |/ |
|
600 | 600 | o i-2: c -move-> d, s -move-> t |
|
601 | 601 | | |
|
602 | 602 | o i-1: a -move-> c, p -move-> s |
|
603 | 603 | | |
|
604 | 604 | o i-0 initial commit: a b h p q r |
|
605 | 605 | |
|
606 | 606 | |
|
607 | 607 | |
|
608 | 608 | Subcase: reset of the copy history on one side |
|
609 | 609 | `````````````````````````````````````````````` |
|
610 | 610 | |
|
611 | 611 | Merge: |
|
612 | 612 | - one with change to a file |
|
613 | 613 | - one deleting and recreating the file |
|
614 | 614 | |
|
615 | 615 | Unlike in the 'BD/DB' cases, an actual merge happened here. So we should |
|
616 | 616 | consider history and rename on both branch of the merge. |
|
617 | 617 | |
|
618 | 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 | 620 | $ hg up 'desc("i-2")' |
|
621 | 621 | 6 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
622 | 622 | $ echo "some update" >> d |
|
623 | 623 | $ hg commit -m "g-1: update d" |
|
624 | 624 | created new head |
|
625 | 625 | $ hg up 'desc("d-2")' |
|
626 | 626 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
627 | 627 | $ hg merge 'desc("g-1")' --tool :union |
|
628 | 628 | merging d |
|
629 | 629 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
630 | 630 | (branch merge, don't forget to commit) |
|
631 | 631 | $ hg ci -m "mDGm-0 $case_desc - one way" |
|
632 | 632 | $ hg up 'desc("g-1")' |
|
633 | 633 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
634 | 634 | $ hg merge 'desc("d-2")' --tool :union |
|
635 | 635 | merging d |
|
636 | 636 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
637 | 637 | (branch merge, don't forget to commit) |
|
638 | 638 | $ hg ci -m "mGDm-0 $case_desc - the other way" |
|
639 | 639 | created new head |
|
640 | 640 | $ hg log -G --rev '::(desc("mDGm")+desc("mGDm"))' |
|
641 | 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 | 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 | 645 | | o g-1: update d |
|
646 | 646 | | | |
|
647 | 647 | o | d-2 re-add d |
|
648 | 648 | | | |
|
649 | 649 | o | d-1 delete d |
|
650 | 650 | |/ |
|
651 | 651 | o i-2: c -move-> d, s -move-> t |
|
652 | 652 | | |
|
653 | 653 | o i-1: a -move-> c, p -move-> s |
|
654 | 654 | | |
|
655 | 655 | o i-0 initial commit: a b h p q r |
|
656 | 656 | |
|
657 | 657 | |
|
658 | 658 | Subcase: merging a change to a file with a "copy overwrite" to that file from another branch |
|
659 | 659 | ```````````````````````````````````````````````````````````````````````````````````````````` |
|
660 | 660 | |
|
661 | 661 | Merge: |
|
662 | 662 | - one with change to a file (d) |
|
663 | 663 | - one overwriting that file with a rename (from h to i, to d) |
|
664 | 664 | |
|
665 | 665 | This case is similar to BF/FB, but an actual merge happens, so both side of the |
|
666 | 666 | history are relevant. |
|
667 | 667 | |
|
668 | 668 | Note: |
|
669 | 669 | | In this case, the merge get conflicting information since on one side we have |
|
670 | 670 | | "a -> c -> d". and one the other one we have "h -> i -> d". |
|
671 | 671 | | |
|
672 | 672 | | The current code arbitrarily pick one side |
|
673 | 673 | |
|
674 | 674 | $ case_desc="merge - G side: content change, F side: copy overwrite, no content change" |
|
675 | 675 | |
|
676 | 676 | $ hg up 'desc("f-2")' |
|
677 | 677 | 1 files updated, 0 files merged, 1 files removed, 0 files unresolved |
|
678 | 678 | $ hg merge 'desc("g-1")' --tool :union |
|
679 | 679 | merging d (no-changeset !) |
|
680 | 680 | 0 files updated, 1 files merged, 0 files removed, 0 files unresolved (no-changeset !) |
|
681 | 681 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved (changeset !) |
|
682 | 682 | (branch merge, don't forget to commit) |
|
683 | 683 | $ hg ci -m "mFGm-0 $case_desc - one way" |
|
684 | 684 | created new head |
|
685 | 685 | $ hg up 'desc("g-1")' |
|
686 | 686 | 2 files updated, 0 files merged, 0 files removed, 0 files unresolved (no-changeset !) |
|
687 | 687 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved (changeset !) |
|
688 | 688 | $ hg merge 'desc("f-2")' --tool :union |
|
689 | 689 | merging d (no-changeset !) |
|
690 | 690 | 0 files updated, 1 files merged, 1 files removed, 0 files unresolved (no-changeset !) |
|
691 | 691 | 0 files updated, 0 files merged, 1 files removed, 0 files unresolved (changeset !) |
|
692 | 692 | (branch merge, don't forget to commit) |
|
693 | 693 | $ hg ci -m "mGFm-0 $case_desc - the other way" |
|
694 | 694 | created new head |
|
695 | 695 | $ hg log -G --rev '::(desc("mGFm")+desc("mFGm"))' |
|
696 | 696 | @ mGFm-0 merge - G side: content change, F side: copy overwrite, no content change - the other way |
|
697 | 697 | |\ |
|
698 | 698 | +---o mFGm-0 merge - G side: content change, F side: copy overwrite, no content change - one way |
|
699 | 699 | | |/ |
|
700 | 700 | | o g-1: update d |
|
701 | 701 | | | |
|
702 | 702 | o | f-2: rename i -> d |
|
703 | 703 | | | |
|
704 | 704 | o | f-1: rename h -> i |
|
705 | 705 | |/ |
|
706 | 706 | o i-2: c -move-> d, s -move-> t |
|
707 | 707 | | |
|
708 | 708 | o i-1: a -move-> c, p -move-> s |
|
709 | 709 | | |
|
710 | 710 | o i-0 initial commit: a b h p q r |
|
711 | 711 | |
|
712 | 712 | |
|
713 | 713 | |
|
714 | 714 | Comparing with merging with a deletion (and keeping the file) |
|
715 | 715 | ------------------------------------------------------------- |
|
716 | 716 | |
|
717 | 717 | Merge: |
|
718 | 718 | - one removing a file (d) |
|
719 | 719 | - one updating that file |
|
720 | 720 | - the merge keep the modified version of the file (canceling the delete) |
|
721 | 721 | |
|
722 | 722 | In this case, the file keep on living after the merge. So we should not drop its |
|
723 | 723 | copy tracing chain. |
|
724 | 724 | |
|
725 | 725 | $ case_desc="merge updated/deleted - revive the file (updated content)" |
|
726 | 726 | |
|
727 | 727 | $ hg up 'desc("c-1")' |
|
728 | 728 | 1 files updated, 0 files merged, 1 files removed, 0 files unresolved |
|
729 | 729 | $ hg merge 'desc("g-1")' |
|
730 | 730 | file 'd' was deleted in local [working copy] but was modified in other [merge rev]. |
|
731 | 731 | You can use (c)hanged version, leave (d)eleted, or leave (u)nresolved. |
|
732 | 732 | What do you want to do? u |
|
733 | 733 | 0 files updated, 0 files merged, 0 files removed, 1 files unresolved |
|
734 | 734 | use 'hg resolve' to retry unresolved file merges or 'hg merge --abort' to abandon |
|
735 | 735 | [1] |
|
736 | 736 | $ hg resolve -t :other d |
|
737 | 737 | (no more unresolved files) |
|
738 | 738 | $ hg ci -m "mCGm-0 $case_desc - one way" |
|
739 | 739 | created new head |
|
740 | 740 | |
|
741 | 741 | $ hg up 'desc("g-1")' |
|
742 | 742 | 0 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
743 | 743 | $ hg merge 'desc("c-1")' |
|
744 | 744 | file 'd' was deleted in other [merge rev] but was modified in local [working copy]. |
|
745 | 745 | You can use (c)hanged version, (d)elete, or leave (u)nresolved. |
|
746 | 746 | What do you want to do? u |
|
747 | 747 | 0 files updated, 0 files merged, 0 files removed, 1 files unresolved |
|
748 | 748 | use 'hg resolve' to retry unresolved file merges or 'hg merge --abort' to abandon |
|
749 | 749 | [1] |
|
750 | 750 | $ hg resolve -t :local d |
|
751 | 751 | (no more unresolved files) |
|
752 | 752 | $ hg ci -m "mGCm-0 $case_desc - the other way" |
|
753 | 753 | created new head |
|
754 | 754 | |
|
755 | 755 | $ hg log -G --rev '::(desc("mCGm")+desc("mGCm"))' |
|
756 | 756 | @ mGCm-0 merge updated/deleted - revive the file (updated content) - the other way |
|
757 | 757 | |\ |
|
758 | 758 | +---o mCGm-0 merge updated/deleted - revive the file (updated content) - one way |
|
759 | 759 | | |/ |
|
760 | 760 | | o g-1: update d |
|
761 | 761 | | | |
|
762 | 762 | o | c-1 delete d |
|
763 | 763 | |/ |
|
764 | 764 | o i-2: c -move-> d, s -move-> t |
|
765 | 765 | | |
|
766 | 766 | o i-1: a -move-> c, p -move-> s |
|
767 | 767 | | |
|
768 | 768 | o i-0 initial commit: a b h p q r |
|
769 | 769 | |
|
770 | 770 | |
|
771 | 771 | |
|
772 | 772 | |
|
773 | 773 | Comparing with merge restoring an untouched deleted file |
|
774 | 774 | -------------------------------------------------------- |
|
775 | 775 | |
|
776 | 776 | Merge: |
|
777 | 777 | - one removing a file (d) |
|
778 | 778 | - one leaving the file untouched |
|
779 | 779 | - the merge actively restore the file to the same content. |
|
780 | 780 | |
|
781 | 781 | In this case, the file keep on living after the merge. So we should not drop its |
|
782 | 782 | copy tracing chain. |
|
783 | 783 | |
|
784 | 784 | $ case_desc="merge explicitely revive deleted file - B side: unrelated change, C side: delete d (restored by merge)" |
|
785 | 785 | |
|
786 | 786 | $ hg up 'desc("c-1")' |
|
787 | 787 | 0 files updated, 0 files merged, 1 files removed, 0 files unresolved |
|
788 | 788 | $ hg merge 'desc("b-1")' |
|
789 | 789 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
790 | 790 | (branch merge, don't forget to commit) |
|
791 | 791 | $ hg revert --rev 'desc("b-1")' d |
|
792 | 792 | $ hg ci -m "mCB-revert-m-0 $case_desc - one way" |
|
793 | 793 | created new head |
|
794 | 794 | |
|
795 | 795 | $ hg up 'desc("b-1")' |
|
796 | 796 | 0 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
797 | 797 | $ hg merge 'desc("c-1")' |
|
798 | 798 | 0 files updated, 0 files merged, 1 files removed, 0 files unresolved |
|
799 | 799 | (branch merge, don't forget to commit) |
|
800 | 800 | $ hg revert --rev 'desc("b-1")' d |
|
801 | 801 | $ hg ci -m "mBC-revert-m-0 $case_desc - the other way" |
|
802 | 802 | created new head |
|
803 | 803 | |
|
804 | 804 | $ hg log -G --rev '::(desc("mCB-revert-m")+desc("mBC-revert-m"))' |
|
805 | 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 | 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 | 809 | | o c-1 delete d |
|
810 | 810 | | | |
|
811 | 811 | o | b-1: b update |
|
812 | 812 | |/ |
|
813 | 813 | o i-2: c -move-> d, s -move-> t |
|
814 | 814 | | |
|
815 | 815 | o i-1: a -move-> c, p -move-> s |
|
816 | 816 | | |
|
817 | 817 | o i-0 initial commit: a b h p q r |
|
818 | 818 | |
|
819 | 819 | |
|
820 | 820 | |
|
821 | 821 | $ hg up null --quiet |
|
822 | 822 | |
|
823 | 823 | Merging a branch where a rename was deleted with a branch where the same file was renamed |
|
824 | 824 | ------------------------------------------------------------------------------------------ |
|
825 | 825 | |
|
826 | 826 | Create a "conflicting" merge where `d` get removed on one branch before its |
|
827 | 827 | rename information actually conflict with the other branch. |
|
828 | 828 | |
|
829 | 829 | (the copy information from the branch that was not deleted should win). |
|
830 | 830 | |
|
831 | 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 | 833 | $ hg up 'desc("i-0")' |
|
834 | 834 | 6 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
835 | 835 | $ hg mv b d |
|
836 | 836 | $ hg ci -m "h-1: b -(move)-> d" |
|
837 | 837 | created new head |
|
838 | 838 | |
|
839 | 839 | $ hg up 'desc("c-1")' |
|
840 | 840 | 2 files updated, 0 files merged, 3 files removed, 0 files unresolved |
|
841 | 841 | $ hg merge 'desc("h-1")' |
|
842 | 842 | 1 files updated, 0 files merged, 1 files removed, 0 files unresolved |
|
843 | 843 | (branch merge, don't forget to commit) |
|
844 | 844 | $ hg ci -m "mCH-delete-before-conflict-m-0 $case_desc - one way" |
|
845 | 845 | |
|
846 | 846 | $ hg up 'desc("h-1")' |
|
847 | 847 | 2 files updated, 0 files merged, 1 files removed, 0 files unresolved |
|
848 | 848 | $ hg merge 'desc("c-1")' |
|
849 | 849 | 1 files updated, 0 files merged, 2 files removed, 0 files unresolved |
|
850 | 850 | (branch merge, don't forget to commit) |
|
851 | 851 | $ hg ci -m "mHC-delete-before-conflict-m-0 $case_desc - the other way" |
|
852 | 852 | created new head |
|
853 | 853 | $ hg log -G --rev '::(desc("mCH-delete-before-conflict-m")+desc("mHC-delete-before-conflict-m"))' |
|
854 | 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 | 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 | 858 | | o h-1: b -(move)-> d |
|
859 | 859 | | | |
|
860 | 860 | o | c-1 delete d |
|
861 | 861 | | | |
|
862 | 862 | o | i-2: c -move-> d, s -move-> t |
|
863 | 863 | | | |
|
864 | 864 | o | i-1: a -move-> c, p -move-> s |
|
865 | 865 | |/ |
|
866 | 866 | o i-0 initial commit: a b h p q r |
|
867 | 867 | |
|
868 | 868 | |
|
869 | 869 | Variant of previous with extra changes introduced by the merge |
|
870 | 870 | -------------------------------------------------------------- |
|
871 | 871 | |
|
872 | 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 | 875 | Subcase: merge has same initial content on both side, but merge introduced a change |
|
876 | 876 | ``````````````````````````````````````````````````````````````````````````````````` |
|
877 | 877 | |
|
878 | 878 | Same as `mAEm` and `mEAm` but with extra change to the file before commiting |
|
879 | 879 | |
|
880 | 880 | - the "e-" branch renaming b to f (through 'g') |
|
881 | 881 | - the "a-" branch renaming d to f (through e) |
|
882 | 882 | |
|
883 | 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 | 885 | $ hg up 'desc("a-2")' |
|
886 | 886 | 2 files updated, 0 files merged, 1 files removed, 0 files unresolved |
|
887 | 887 | $ hg merge 'desc("e-2")' |
|
888 | 888 | 1 files updated, 0 files merged, 1 files removed, 0 files unresolved (no-changeset !) |
|
889 | 889 | 0 files updated, 0 files merged, 1 files removed, 0 files unresolved (changeset !) |
|
890 | 890 | (branch merge, don't forget to commit) |
|
891 | 891 | $ echo "content change for mAE-change-m" > f |
|
892 | 892 | $ hg ci -m "mAE-change-m-0 $case_desc - one way" |
|
893 | 893 | created new head |
|
894 | 894 | $ hg up 'desc("e-2")' |
|
895 | 895 | 2 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
896 | 896 | $ hg merge 'desc("a-2")' |
|
897 | 897 | 1 files updated, 0 files merged, 1 files removed, 0 files unresolved (no-changeset !) |
|
898 | 898 | 0 files updated, 0 files merged, 1 files removed, 0 files unresolved (changeset !) |
|
899 | 899 | (branch merge, don't forget to commit) |
|
900 | 900 | $ echo "content change for mEA-change-m" > f |
|
901 | 901 | $ hg ci -m "mEA-change-m-0 $case_desc - the other way" |
|
902 | 902 | created new head |
|
903 | 903 | $ hg log -G --rev '::(desc("mAE-change-m")+desc("mEA-change-m"))' |
|
904 | 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 | 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 | 908 | | o e-2 g -move-> f |
|
909 | 909 | | | |
|
910 | 910 | | o e-1 b -move-> g |
|
911 | 911 | | | |
|
912 | 912 | o | a-2: e -move-> f |
|
913 | 913 | | | |
|
914 | 914 | o | a-1: d -move-> e |
|
915 | 915 | |/ |
|
916 | 916 | o i-2: c -move-> d, s -move-> t |
|
917 | 917 | | |
|
918 | 918 | o i-1: a -move-> c, p -move-> s |
|
919 | 919 | | |
|
920 | 920 | o i-0 initial commit: a b h p q r |
|
921 | 921 | |
|
922 | 922 | |
|
923 | 923 | Subcase: merge overwrite common copy information, but with extra change during the merge |
|
924 | 924 | ```````````````````````````````````````````````````````````````````````````````````````` |
|
925 | 925 | |
|
926 | 926 | Merge: |
|
927 | 927 | - one with change to an unrelated file (b) |
|
928 | 928 | - one overwriting a file (d) with a rename (from h to i to d) |
|
929 | 929 | - the merge update f content |
|
930 | 930 | |
|
931 | 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 | 933 | $ hg up 'desc("f-2")' |
|
934 | 934 | 2 files updated, 0 files merged, 2 files removed, 0 files unresolved |
|
935 | 935 | #if no-changeset |
|
936 | 936 | $ hg debugindex d | "$PYTHON" ../no-linkrev |
|
937 | 937 | rev linkrev nodeid p1 p2 |
|
938 | 938 | 0 * d8252ab2e760 000000000000 000000000000 |
|
939 | 939 | 1 * b004912a8510 000000000000 000000000000 |
|
940 | 940 | 2 * 7b79e2fe0c89 000000000000 000000000000 |
|
941 | 941 | 3 * 17ec97e60577 d8252ab2e760 000000000000 |
|
942 | 942 | 4 * 06dabf50734c b004912a8510 17ec97e60577 |
|
943 | 943 | 5 * 19c0e3924691 17ec97e60577 b004912a8510 |
|
944 | 944 | 6 * 89c873a01d97 7b79e2fe0c89 17ec97e60577 |
|
945 | 945 | 7 * d55cb4e9ef57 000000000000 000000000000 |
|
946 | 946 | #else |
|
947 | 947 | $ hg debugindex d | "$PYTHON" ../no-linkrev |
|
948 | 948 | rev linkrev nodeid p1 p2 |
|
949 | 949 | 0 * ae258f702dfe 000000000000 000000000000 |
|
950 | 950 | 1 * b004912a8510 000000000000 000000000000 |
|
951 | 951 | 2 * 5cce88bf349f ae258f702dfe 000000000000 |
|
952 | 952 | 3 * cc269dd788c8 b004912a8510 5cce88bf349f |
|
953 | 953 | 4 * 51c91a115080 5cce88bf349f b004912a8510 |
|
954 | 954 | #endif |
|
955 | 955 | $ hg up 'desc("b-1")' |
|
956 | 956 | 3 files updated, 0 files merged, 0 files removed, 0 files unresolved (no-changeset !) |
|
957 | 957 | 2 files updated, 0 files merged, 0 files removed, 0 files unresolved (changeset !) |
|
958 | 958 | $ hg merge 'desc("f-2")' |
|
959 | 959 | 1 files updated, 0 files merged, 1 files removed, 0 files unresolved (no-changeset !) |
|
960 | 960 | 0 files updated, 0 files merged, 1 files removed, 0 files unresolved (changeset !) |
|
961 | 961 | (branch merge, don't forget to commit) |
|
962 | 962 | $ echo "extra-change to (formelly h) during the merge" > d |
|
963 | 963 | $ hg ci -m "mBF-change-m-0 $case_desc - one way" |
|
964 | 964 | created new head |
|
965 | 965 | $ hg manifest --rev . --debug | grep " d" |
|
966 | 966 | 1c334238bd42ec85c6a0d83fd1b2a898a6a3215d 644 d (no-changeset !) |
|
967 | 967 | cea2d99c0fde64672ef61953786fdff34f16e230 644 d (changeset !) |
|
968 | 968 | |
|
969 | 969 | $ hg up 'desc("f-2")' |
|
970 | 970 | 2 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
971 | 971 | $ hg merge 'desc("b-1")' |
|
972 | 972 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
973 | 973 | (branch merge, don't forget to commit) |
|
974 | 974 | $ echo "extra-change to (formelly h) during the merge" > d |
|
975 | 975 | $ hg ci -m "mFB-change-m-0 $case_desc - the other way" |
|
976 | 976 | created new head |
|
977 | 977 | $ hg manifest --rev . --debug | grep " d" |
|
978 | 978 | 1c334238bd42ec85c6a0d83fd1b2a898a6a3215d 644 d (no-changeset !) |
|
979 | 979 | cea2d99c0fde64672ef61953786fdff34f16e230 644 d (changeset !) |
|
980 | 980 | #if no-changeset |
|
981 | 981 | $ hg debugindex d | "$PYTHON" ../no-linkrev |
|
982 | 982 | rev linkrev nodeid p1 p2 |
|
983 | 983 | 0 * d8252ab2e760 000000000000 000000000000 |
|
984 | 984 | 1 * b004912a8510 000000000000 000000000000 |
|
985 | 985 | 2 * 7b79e2fe0c89 000000000000 000000000000 |
|
986 | 986 | 3 * 17ec97e60577 d8252ab2e760 000000000000 |
|
987 | 987 | 4 * 06dabf50734c b004912a8510 17ec97e60577 |
|
988 | 988 | 5 * 19c0e3924691 17ec97e60577 b004912a8510 |
|
989 | 989 | 6 * 89c873a01d97 7b79e2fe0c89 17ec97e60577 |
|
990 | 990 | 7 * d55cb4e9ef57 000000000000 000000000000 |
|
991 | 991 | 8 * 1c334238bd42 7b79e2fe0c89 000000000000 |
|
992 | 992 | #else |
|
993 | 993 | $ hg debugindex d | "$PYTHON" ../no-linkrev |
|
994 | 994 | rev linkrev nodeid p1 p2 |
|
995 | 995 | 0 * ae258f702dfe 000000000000 000000000000 |
|
996 | 996 | 1 * b004912a8510 000000000000 000000000000 |
|
997 | 997 | 2 * 5cce88bf349f ae258f702dfe 000000000000 |
|
998 | 998 | 3 * cc269dd788c8 b004912a8510 5cce88bf349f |
|
999 | 999 | 4 * 51c91a115080 5cce88bf349f b004912a8510 |
|
1000 | 1000 | 5 * cea2d99c0fde ae258f702dfe 000000000000 |
|
1001 | 1001 | #endif |
|
1002 | 1002 | $ hg log -G --rev '::(desc("mBF-change-m")+desc("mFB-change-m"))' |
|
1003 | 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 | 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 | 1007 | | o f-2: rename i -> d |
|
1008 | 1008 | | | |
|
1009 | 1009 | | o f-1: rename h -> i |
|
1010 | 1010 | | | |
|
1011 | 1011 | o | b-1: b update |
|
1012 | 1012 | |/ |
|
1013 | 1013 | o i-2: c -move-> d, s -move-> t |
|
1014 | 1014 | | |
|
1015 | 1015 | o i-1: a -move-> c, p -move-> s |
|
1016 | 1016 | | |
|
1017 | 1017 | o i-0 initial commit: a b h p q r |
|
1018 | 1018 | |
|
1019 | 1019 | |
|
1020 | 1020 | Subcase: restoring and untouched deleted file, while touching it |
|
1021 | 1021 | ```````````````````````````````````````````````````````````````` |
|
1022 | 1022 | |
|
1023 | 1023 | Merge: |
|
1024 | 1024 | - one removing a file (d) |
|
1025 | 1025 | - one leaving the file untouched |
|
1026 | 1026 | - the merge actively restore the file to the same content. |
|
1027 | 1027 | |
|
1028 | 1028 | In this case, the file keep on living after the merge. So we should not drop its |
|
1029 | 1029 | copy tracing chain. |
|
1030 | 1030 | |
|
1031 | 1031 | $ case_desc="merge explicitely revive deleted file - B side: unrelated change, C side: delete d (restored by merge)" |
|
1032 | 1032 | |
|
1033 | 1033 | $ hg up 'desc("c-1")' |
|
1034 | 1034 | 2 files updated, 0 files merged, 1 files removed, 0 files unresolved |
|
1035 | 1035 | $ hg merge 'desc("b-1")' |
|
1036 | 1036 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
1037 | 1037 | (branch merge, don't forget to commit) |
|
1038 | 1038 | $ hg revert --rev 'desc("b-1")' d |
|
1039 | 1039 | $ echo "new content for d after the revert" > d |
|
1040 | 1040 | $ hg ci -m "mCB-change-m-0 $case_desc - one way" |
|
1041 | 1041 | created new head |
|
1042 | 1042 | $ hg manifest --rev . --debug | grep " d" |
|
1043 | 1043 | e333780c17752a3b0dd15e3ad48aa4e5c745f621 644 d (no-changeset !) |
|
1044 | 1044 | 4b540a18ad699234b2b2aa18cb69555ac9c4b1df 644 d (changeset !) |
|
1045 | 1045 | |
|
1046 | 1046 | $ hg up 'desc("b-1")' |
|
1047 | 1047 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
1048 | 1048 | $ hg merge 'desc("c-1")' |
|
1049 | 1049 | 0 files updated, 0 files merged, 1 files removed, 0 files unresolved |
|
1050 | 1050 | (branch merge, don't forget to commit) |
|
1051 | 1051 | $ hg revert --rev 'desc("b-1")' d |
|
1052 | 1052 | $ echo "new content for d after the revert" > d |
|
1053 | 1053 | $ hg ci -m "mBC-change-m-0 $case_desc - the other way" |
|
1054 | 1054 | created new head |
|
1055 | 1055 | $ hg manifest --rev . --debug | grep " d" |
|
1056 | 1056 | e333780c17752a3b0dd15e3ad48aa4e5c745f621 644 d (no-changeset !) |
|
1057 | 1057 | 4b540a18ad699234b2b2aa18cb69555ac9c4b1df 644 d (changeset !) |
|
1058 | 1058 | |
|
1059 | 1059 | |
|
1060 | 1060 | $ hg up null --quiet |
|
1061 | 1061 | $ hg log -G --rev '::(desc("mCB-change-m")+desc("mBC-change-m"))' |
|
1062 | 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 | 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 | 1066 | | o c-1 delete d |
|
1067 | 1067 | | | |
|
1068 | 1068 | o | b-1: b update |
|
1069 | 1069 | |/ |
|
1070 | 1070 | o i-2: c -move-> d, s -move-> t |
|
1071 | 1071 | | |
|
1072 | 1072 | o i-1: a -move-> c, p -move-> s |
|
1073 | 1073 | | |
|
1074 | 1074 | o i-0 initial commit: a b h p q r |
|
1075 | 1075 | |
|
1076 | 1076 | |
|
1077 | 1077 | Decision from previous merge are properly chained with later merge |
|
1078 | 1078 | ------------------------------------------------------------------ |
|
1079 | 1079 | |
|
1080 | 1080 | Subcase: chaining conflicting rename resolution |
|
1081 | 1081 | ``````````````````````````````````````````````` |
|
1082 | 1082 | |
|
1083 | 1083 | The "mAEm" and "mEAm" case create a rename tracking conflict on file 'f'. We |
|
1084 | 1084 | add more change on the respective branch and merge again. These second merge |
|
1085 | 1085 | does not involve the file 'f' and the arbitration done within "mAEm" and "mEA" |
|
1086 | 1086 | about that file should stay unchanged. |
|
1087 | 1087 | |
|
1088 | 1088 | We also touch J during some of the merge to check for unrelated change to new file during merge. |
|
1089 | 1089 | |
|
1090 | 1090 | $ case_desc="chained merges (conflict -> simple) - same content everywhere" |
|
1091 | 1091 | |
|
1092 | 1092 | (extra unrelated changes) |
|
1093 | 1093 | |
|
1094 | 1094 | $ hg up 'desc("a-2")' |
|
1095 | 1095 | 6 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
1096 | 1096 | $ echo j > unrelated-j |
|
1097 | 1097 | $ hg add unrelated-j |
|
1098 | 1098 | $ hg ci -m 'j-1: unrelated changes (based on the "a" series of changes)' |
|
1099 | 1099 | created new head |
|
1100 | 1100 | |
|
1101 | 1101 | $ hg up 'desc("e-2")' |
|
1102 | 1102 | 2 files updated, 0 files merged, 2 files removed, 0 files unresolved (no-changeset !) |
|
1103 | 1103 | 1 files updated, 0 files merged, 2 files removed, 0 files unresolved (changeset !) |
|
1104 | 1104 | $ echo k > unrelated-k |
|
1105 | 1105 | $ hg add unrelated-k |
|
1106 | 1106 | $ hg ci -m 'k-1: unrelated changes (based on "e" changes)' |
|
1107 | 1107 | created new head |
|
1108 | 1108 | |
|
1109 | 1109 | (merge variant 1) |
|
1110 | 1110 | |
|
1111 | 1111 | $ hg up 'desc("mAEm")' |
|
1112 | 1112 | 1 files updated, 0 files merged, 2 files removed, 0 files unresolved (no-changeset !) |
|
1113 | 1113 | 0 files updated, 0 files merged, 2 files removed, 0 files unresolved (changeset !) |
|
1114 | 1114 | $ hg merge 'desc("k-1")' |
|
1115 | 1115 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
1116 | 1116 | (branch merge, don't forget to commit) |
|
1117 | 1117 | $ hg ci -m "mAE,Km: $case_desc" |
|
1118 | 1118 | |
|
1119 | 1119 | (merge variant 2) |
|
1120 | 1120 | |
|
1121 | 1121 | $ hg up 'desc("k-1")' |
|
1122 | 1122 | 2 files updated, 0 files merged, 0 files removed, 0 files unresolved (no-changeset !) |
|
1123 | 1123 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved (changeset !) |
|
1124 | 1124 | |
|
1125 | 1125 | $ hg merge 'desc("mAEm")' |
|
1126 | 1126 | 1 files updated, 0 files merged, 1 files removed, 0 files unresolved (no-changeset !) |
|
1127 | 1127 | 0 files updated, 0 files merged, 1 files removed, 0 files unresolved (changeset !) |
|
1128 | 1128 | (branch merge, don't forget to commit) |
|
1129 | 1129 | $ hg ci -m "mK,AEm: $case_desc" |
|
1130 | 1130 | created new head |
|
1131 | 1131 | |
|
1132 | 1132 | (merge variant 3) |
|
1133 | 1133 | |
|
1134 | 1134 | $ hg up 'desc("mEAm")' |
|
1135 | 1135 | 0 files updated, 0 files merged, 1 files removed, 0 files unresolved |
|
1136 | 1136 | $ hg merge 'desc("j-1")' |
|
1137 | 1137 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
1138 | 1138 | (branch merge, don't forget to commit) |
|
1139 | 1139 | $ echo jj > unrelated-j |
|
1140 | 1140 | $ hg ci -m "mEA,Jm: $case_desc" |
|
1141 | 1141 | |
|
1142 | 1142 | (merge variant 4) |
|
1143 | 1143 | |
|
1144 | 1144 | $ hg up 'desc("j-1")' |
|
1145 | 1145 | 3 files updated, 0 files merged, 0 files removed, 0 files unresolved (no-changeset !) |
|
1146 | 1146 | 2 files updated, 0 files merged, 0 files removed, 0 files unresolved (changeset !) |
|
1147 | 1147 | $ hg merge 'desc("mEAm")' |
|
1148 | 1148 | 1 files updated, 0 files merged, 1 files removed, 0 files unresolved (no-changeset !) |
|
1149 | 1149 | 0 files updated, 0 files merged, 1 files removed, 0 files unresolved (changeset !) |
|
1150 | 1150 | (branch merge, don't forget to commit) |
|
1151 | 1151 | $ echo jj > unrelated-j |
|
1152 | 1152 | $ hg ci -m "mJ,EAm: $case_desc" |
|
1153 | 1153 | created new head |
|
1154 | 1154 | |
|
1155 | 1155 | |
|
1156 | 1156 | $ hg log -G --rev '::(desc("mAE,Km") + desc("mK,AEm") + desc("mEA,Jm") + desc("mJ,EAm"))' |
|
1157 | 1157 | @ mJ,EAm: chained merges (conflict -> simple) - same content everywhere |
|
1158 | 1158 | |\ |
|
1159 | 1159 | +---o mEA,Jm: chained merges (conflict -> simple) - same content everywhere |
|
1160 | 1160 | | |/ |
|
1161 | 1161 | | | o mK,AEm: chained merges (conflict -> simple) - same content everywhere |
|
1162 | 1162 | | | |\ |
|
1163 | 1163 | | | +---o mAE,Km: chained merges (conflict -> simple) - same content everywhere |
|
1164 | 1164 | | | | |/ |
|
1165 | 1165 | | | | o k-1: unrelated changes (based on "e" changes) |
|
1166 | 1166 | | | | | |
|
1167 | 1167 | | o | | j-1: unrelated changes (based on the "a" series of changes) |
|
1168 | 1168 | | | | | |
|
1169 | 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 | 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 | 1173 | | o e-2 g -move-> f |
|
1174 | 1174 | | | |
|
1175 | 1175 | | o e-1 b -move-> g |
|
1176 | 1176 | | | |
|
1177 | 1177 | o | a-2: e -move-> f |
|
1178 | 1178 | | | |
|
1179 | 1179 | o | a-1: d -move-> e |
|
1180 | 1180 | |/ |
|
1181 | 1181 | o i-2: c -move-> d, s -move-> t |
|
1182 | 1182 | | |
|
1183 | 1183 | o i-1: a -move-> c, p -move-> s |
|
1184 | 1184 | | |
|
1185 | 1185 | o i-0 initial commit: a b h p q r |
|
1186 | 1186 | |
|
1187 | 1187 | |
|
1188 | 1188 | Subcase: chaining conflicting rename resolution, with actual merging happening |
|
1189 | 1189 | `````````````````````````````````````````````````````````````````````````````` |
|
1190 | 1190 | |
|
1191 | 1191 | The "mPQm" and "mQPm" case create a rename tracking conflict on file 't'. We |
|
1192 | 1192 | add more change on the respective branch and merge again. These second merge |
|
1193 | 1193 | does not involve the file 't' and the arbitration done within "mPQm" and "mQP" |
|
1194 | 1194 | about that file should stay unchanged. |
|
1195 | 1195 | |
|
1196 | 1196 | $ case_desc="chained merges (conflict -> simple) - different content" |
|
1197 | 1197 | |
|
1198 | 1198 | (extra unrelated changes) |
|
1199 | 1199 | |
|
1200 | 1200 | $ hg up 'desc("p-2")' |
|
1201 | 1201 | 3 files updated, 0 files merged, 3 files removed, 0 files unresolved |
|
1202 | 1202 | $ echo s > unrelated-s |
|
1203 | 1203 | $ hg add unrelated-s |
|
1204 | 1204 | $ hg ci -m 's-1: unrelated changes (based on the "p" series of changes)' |
|
1205 | 1205 | created new head |
|
1206 | 1206 | |
|
1207 | 1207 | $ hg up 'desc("q-2")' |
|
1208 | 1208 | 2 files updated, 0 files merged, 2 files removed, 0 files unresolved |
|
1209 | 1209 | $ echo t > unrelated-t |
|
1210 | 1210 | $ hg add unrelated-t |
|
1211 | 1211 | $ hg ci -m 't-1: unrelated changes (based on "q" changes)' |
|
1212 | 1212 | created new head |
|
1213 | 1213 | |
|
1214 | 1214 | (merge variant 1) |
|
1215 | 1215 | |
|
1216 | 1216 | $ hg up 'desc("mPQm")' |
|
1217 | 1217 | 1 files updated, 0 files merged, 2 files removed, 0 files unresolved |
|
1218 | 1218 | $ hg merge 'desc("t-1")' |
|
1219 | 1219 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
1220 | 1220 | (branch merge, don't forget to commit) |
|
1221 | 1221 | $ hg ci -m "mPQ,Tm: $case_desc" |
|
1222 | 1222 | |
|
1223 | 1223 | (merge variant 2) |
|
1224 | 1224 | |
|
1225 | 1225 | $ hg up 'desc("t-1")' |
|
1226 | 1226 | 2 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
1227 | 1227 | |
|
1228 | 1228 | $ hg merge 'desc("mPQm")' |
|
1229 | 1229 | 1 files updated, 0 files merged, 1 files removed, 0 files unresolved |
|
1230 | 1230 | (branch merge, don't forget to commit) |
|
1231 | 1231 | $ hg ci -m "mT,PQm: $case_desc" |
|
1232 | 1232 | created new head |
|
1233 | 1233 | |
|
1234 | 1234 | (merge variant 3) |
|
1235 | 1235 | |
|
1236 | 1236 | $ hg up 'desc("mQPm")' |
|
1237 | 1237 | 1 files updated, 0 files merged, 1 files removed, 0 files unresolved |
|
1238 | 1238 | $ hg merge 'desc("s-1")' |
|
1239 | 1239 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
1240 | 1240 | (branch merge, don't forget to commit) |
|
1241 | 1241 | $ hg ci -m "mQP,Sm: $case_desc" |
|
1242 | 1242 | |
|
1243 | 1243 | (merge variant 4) |
|
1244 | 1244 | |
|
1245 | 1245 | $ hg up 'desc("s-1")' |
|
1246 | 1246 | 2 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
1247 | 1247 | $ hg merge 'desc("mQPm")' |
|
1248 | 1248 | 1 files updated, 0 files merged, 1 files removed, 0 files unresolved |
|
1249 | 1249 | (branch merge, don't forget to commit) |
|
1250 | 1250 | $ hg ci -m "mS,QPm: $case_desc" |
|
1251 | 1251 | created new head |
|
1252 | 1252 | $ hg up null --quiet |
|
1253 | 1253 | |
|
1254 | 1254 | |
|
1255 | 1255 | $ hg log -G --rev '::(desc("mPQ,Tm") + desc("mT,PQm") + desc("mQP,Sm") + desc("mS,QPm"))' |
|
1256 | 1256 | o mS,QPm: chained merges (conflict -> simple) - different content |
|
1257 | 1257 | |\ |
|
1258 | 1258 | +---o mQP,Sm: chained merges (conflict -> simple) - different content |
|
1259 | 1259 | | |/ |
|
1260 | 1260 | | | o mT,PQm: chained merges (conflict -> simple) - different content |
|
1261 | 1261 | | | |\ |
|
1262 | 1262 | | | +---o mPQ,Tm: chained merges (conflict -> simple) - different content |
|
1263 | 1263 | | | | |/ |
|
1264 | 1264 | | | | o t-1: unrelated changes (based on "q" changes) |
|
1265 | 1265 | | | | | |
|
1266 | 1266 | | o | | s-1: unrelated changes (based on the "p" series of changes) |
|
1267 | 1267 | | | | | |
|
1268 | 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 | 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 | 1272 | | o q-2 w -move-> v |
|
1273 | 1273 | | | |
|
1274 | 1274 | | o q-1 r -move-> w |
|
1275 | 1275 | | | |
|
1276 | 1276 | o | p-2: u -move-> v |
|
1277 | 1277 | | | |
|
1278 | 1278 | o | p-1: t -move-> u |
|
1279 | 1279 | |/ |
|
1280 | 1280 | o i-2: c -move-> d, s -move-> t |
|
1281 | 1281 | | |
|
1282 | 1282 | o i-1: a -move-> c, p -move-> s |
|
1283 | 1283 | | |
|
1284 | 1284 | o i-0 initial commit: a b h p q r |
|
1285 | 1285 | |
|
1286 | 1286 | |
|
1287 | 1287 | Subcase: chaining salvage information during a merge |
|
1288 | 1288 | ```````````````````````````````````````````````````` |
|
1289 | 1289 | |
|
1290 | 1290 | We add more change on the branch were the file was deleted. merging again |
|
1291 | 1291 | should preserve the fact eh file was salvaged. |
|
1292 | 1292 | |
|
1293 | 1293 | $ case_desc="chained merges (salvaged -> simple) - same content (when the file exists)" |
|
1294 | 1294 | |
|
1295 | 1295 | (creating the change) |
|
1296 | 1296 | |
|
1297 | 1297 | $ hg up 'desc("c-1")' |
|
1298 | 1298 | 5 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
1299 | 1299 | $ echo l > unrelated-l |
|
1300 | 1300 | $ hg add unrelated-l |
|
1301 | 1301 | $ hg ci -m 'l-1: unrelated changes (based on "c" changes)' |
|
1302 | 1302 | created new head |
|
1303 | 1303 | |
|
1304 | 1304 | (Merge variant 1) |
|
1305 | 1305 | |
|
1306 | 1306 | $ hg up 'desc("mBC-revert-m")' |
|
1307 | 1307 | 2 files updated, 0 files merged, 1 files removed, 0 files unresolved |
|
1308 | 1308 | $ hg merge 'desc("l-1")' |
|
1309 | 1309 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
1310 | 1310 | (branch merge, don't forget to commit) |
|
1311 | 1311 | $ hg ci -m "mBC+revert,Lm: $case_desc" |
|
1312 | 1312 | |
|
1313 | 1313 | (Merge variant 2) |
|
1314 | 1314 | |
|
1315 | 1315 | $ hg up 'desc("mCB-revert-m")' |
|
1316 | 1316 | 0 files updated, 0 files merged, 1 files removed, 0 files unresolved |
|
1317 | 1317 | $ hg merge 'desc("l-1")' |
|
1318 | 1318 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
1319 | 1319 | (branch merge, don't forget to commit) |
|
1320 | 1320 | $ hg ci -m "mCB+revert,Lm: $case_desc" |
|
1321 | 1321 | |
|
1322 | 1322 | (Merge variant 3) |
|
1323 | 1323 | |
|
1324 | 1324 | $ hg up 'desc("l-1")' |
|
1325 | 1325 | 1 files updated, 0 files merged, 1 files removed, 0 files unresolved |
|
1326 | 1326 | |
|
1327 | 1327 | $ hg merge 'desc("mBC-revert-m")' |
|
1328 | 1328 | 2 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
1329 | 1329 | (branch merge, don't forget to commit) |
|
1330 | 1330 | $ hg ci -m "mL,BC+revertm: $case_desc" |
|
1331 | 1331 | created new head |
|
1332 | 1332 | |
|
1333 | 1333 | (Merge variant 4) |
|
1334 | 1334 | |
|
1335 | 1335 | $ hg up 'desc("l-1")' |
|
1336 | 1336 | 1 files updated, 0 files merged, 1 files removed, 0 files unresolved |
|
1337 | 1337 | |
|
1338 | 1338 | $ hg merge 'desc("mCB-revert-m")' |
|
1339 | 1339 | 2 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
1340 | 1340 | (branch merge, don't forget to commit) |
|
1341 | 1341 | $ hg ci -m "mL,CB+revertm: $case_desc" |
|
1342 | 1342 | created new head |
|
1343 | 1343 | |
|
1344 | 1344 | $ hg log -G --rev '::(desc("mBC+revert,Lm") + desc("mCB+revert,Lm") + desc("mL,BC+revertm") + desc("mL,CB+revertm"))' |
|
1345 | 1345 | @ mL,CB+revertm: chained merges (salvaged -> simple) - same content (when the file exists) |
|
1346 | 1346 | |\ |
|
1347 | 1347 | | | o mL,BC+revertm: chained merges (salvaged -> simple) - same content (when the file exists) |
|
1348 | 1348 | | |/| |
|
1349 | 1349 | +-+---o mCB+revert,Lm: chained merges (salvaged -> simple) - same content (when the file exists) |
|
1350 | 1350 | | | | |
|
1351 | 1351 | | +---o mBC+revert,Lm: chained merges (salvaged -> simple) - same content (when the file exists) |
|
1352 | 1352 | | | |/ |
|
1353 | 1353 | | o | l-1: unrelated changes (based on "c" changes) |
|
1354 | 1354 | | | | |
|
1355 | 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 | 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 | 1359 | o | c-1 delete d |
|
1360 | 1360 | | | |
|
1361 | 1361 | | o b-1: b update |
|
1362 | 1362 | |/ |
|
1363 | 1363 | o i-2: c -move-> d, s -move-> t |
|
1364 | 1364 | | |
|
1365 | 1365 | o i-1: a -move-> c, p -move-> s |
|
1366 | 1366 | | |
|
1367 | 1367 | o i-0 initial commit: a b h p q r |
|
1368 | 1368 | |
|
1369 | 1369 | |
|
1370 | 1370 | |
|
1371 | 1371 | Subcase: chaining "merged" information during a merge |
|
1372 | 1372 | `````````````````````````````````````````````````````` |
|
1373 | 1373 | |
|
1374 | 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 | 1376 | $ case_desc="chained merges (copy-overwrite -> simple) - same content" |
|
1377 | 1377 | |
|
1378 | 1378 | (extra unrelated changes) |
|
1379 | 1379 | |
|
1380 | 1380 | $ hg up 'desc("f-2")' |
|
1381 | 1381 | 2 files updated, 0 files merged, 2 files removed, 0 files unresolved (no-changeset !) |
|
1382 | 1382 | 1 files updated, 0 files merged, 2 files removed, 0 files unresolved (changeset !) |
|
1383 | 1383 | $ echo n > unrelated-n |
|
1384 | 1384 | $ hg add unrelated-n |
|
1385 | 1385 | $ hg ci -m 'n-1: unrelated changes (based on the "f" series of changes)' |
|
1386 | 1386 | created new head |
|
1387 | 1387 | |
|
1388 | 1388 | $ hg up 'desc("g-1")' |
|
1389 | 1389 | 2 files updated, 0 files merged, 1 files removed, 0 files unresolved |
|
1390 | 1390 | $ echo o > unrelated-o |
|
1391 | 1391 | $ hg add unrelated-o |
|
1392 | 1392 | $ hg ci -m 'o-1: unrelated changes (based on "g" changes)' |
|
1393 | 1393 | created new head |
|
1394 | 1394 | |
|
1395 | 1395 | (merge variant 1) |
|
1396 | 1396 | |
|
1397 | 1397 | $ hg up 'desc("mFGm")' |
|
1398 | 1398 | 1 files updated, 0 files merged, 2 files removed, 0 files unresolved (no-changeset !) |
|
1399 | 1399 | 0 files updated, 0 files merged, 2 files removed, 0 files unresolved (changeset !) |
|
1400 | 1400 | $ hg merge 'desc("o-1")' |
|
1401 | 1401 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
1402 | 1402 | (branch merge, don't forget to commit) |
|
1403 | 1403 | $ hg ci -m "mFG,Om: $case_desc" |
|
1404 | 1404 | |
|
1405 | 1405 | (merge variant 2) |
|
1406 | 1406 | |
|
1407 | 1407 | $ hg up 'desc("o-1")' |
|
1408 | 1408 | 2 files updated, 0 files merged, 0 files removed, 0 files unresolved (no-changeset !) |
|
1409 | 1409 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved (changeset !) |
|
1410 | 1410 | $ hg merge 'desc("FGm")' |
|
1411 | 1411 | 1 files updated, 0 files merged, 1 files removed, 0 files unresolved (no-changeset !) |
|
1412 | 1412 | 0 files updated, 0 files merged, 1 files removed, 0 files unresolved (changeset !) |
|
1413 | 1413 | (branch merge, don't forget to commit) |
|
1414 | 1414 | $ hg ci -m "mO,FGm: $case_desc" |
|
1415 | 1415 | created new head |
|
1416 | 1416 | |
|
1417 | 1417 | (merge variant 3) |
|
1418 | 1418 | |
|
1419 | 1419 | $ hg up 'desc("mGFm")' |
|
1420 | 1420 | 0 files updated, 0 files merged, 1 files removed, 0 files unresolved |
|
1421 | 1421 | $ hg merge 'desc("n-1")' |
|
1422 | 1422 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
1423 | 1423 | (branch merge, don't forget to commit) |
|
1424 | 1424 | $ hg ci -m "mGF,Nm: $case_desc" |
|
1425 | 1425 | |
|
1426 | 1426 | (merge variant 4) |
|
1427 | 1427 | |
|
1428 | 1428 | $ hg up 'desc("n-1")' |
|
1429 | 1429 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
1430 | 1430 | $ hg merge 'desc("mGFm")' |
|
1431 | 1431 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
1432 | 1432 | (branch merge, don't forget to commit) |
|
1433 | 1433 | $ hg ci -m "mN,GFm: $case_desc" |
|
1434 | 1434 | created new head |
|
1435 | 1435 | |
|
1436 | 1436 | $ hg log -G --rev '::(desc("mFG,Om") + desc("mO,FGm") + desc("mGF,Nm") + desc("mN,GFm"))' |
|
1437 | 1437 | @ mN,GFm: chained merges (copy-overwrite -> simple) - same content |
|
1438 | 1438 | |\ |
|
1439 | 1439 | +---o mGF,Nm: chained merges (copy-overwrite -> simple) - same content |
|
1440 | 1440 | | |/ |
|
1441 | 1441 | | | o mO,FGm: chained merges (copy-overwrite -> simple) - same content |
|
1442 | 1442 | | | |\ |
|
1443 | 1443 | | | +---o mFG,Om: chained merges (copy-overwrite -> simple) - same content |
|
1444 | 1444 | | | | |/ |
|
1445 | 1445 | | | | o o-1: unrelated changes (based on "g" changes) |
|
1446 | 1446 | | | | | |
|
1447 | 1447 | | o | | n-1: unrelated changes (based on the "f" series of changes) |
|
1448 | 1448 | | | | | |
|
1449 | 1449 | o-----+ mGFm-0 merge - G side: content change, F side: copy overwrite, no content change - the other way |
|
1450 | 1450 | |/ / / |
|
1451 | 1451 | | o / mFGm-0 merge - G side: content change, F side: copy overwrite, no content change - one way |
|
1452 | 1452 | |/|/ |
|
1453 | 1453 | | o g-1: update d |
|
1454 | 1454 | | | |
|
1455 | 1455 | o | f-2: rename i -> d |
|
1456 | 1456 | | | |
|
1457 | 1457 | o | f-1: rename h -> i |
|
1458 | 1458 | |/ |
|
1459 | 1459 | o i-2: c -move-> d, s -move-> t |
|
1460 | 1460 | | |
|
1461 | 1461 | o i-1: a -move-> c, p -move-> s |
|
1462 | 1462 | | |
|
1463 | 1463 | o i-0 initial commit: a b h p q r |
|
1464 | 1464 | |
|
1465 | 1465 | |
|
1466 | 1466 | Subcase: chaining conflicting rename resolution, with extra change during the merge |
|
1467 | 1467 | ``````````````````````````````````````````````````````````````````````````````````` |
|
1468 | 1468 | |
|
1469 | 1469 | The "mEA-change-m-0" and "mAE-change-m-0" case create a rename tracking conflict on file 'f'. We |
|
1470 | 1470 | add more change on the respective branch and merge again. These second merge |
|
1471 | 1471 | does not involve the file 'f' and the arbitration done within "mAEm" and "mEA" |
|
1472 | 1472 | about that file should stay unchanged. |
|
1473 | 1473 | |
|
1474 | 1474 | $ case_desc="chained merges (conflict+change -> simple) - same content on both branch in the initial merge" |
|
1475 | 1475 | |
|
1476 | 1476 | |
|
1477 | 1477 | (merge variant 1) |
|
1478 | 1478 | |
|
1479 | 1479 | $ hg up 'desc("mAE-change-m")' |
|
1480 | 1480 | 2 files updated, 0 files merged, 3 files removed, 0 files unresolved |
|
1481 | 1481 | $ hg merge 'desc("k-1")' |
|
1482 | 1482 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
1483 | 1483 | (branch merge, don't forget to commit) |
|
1484 | 1484 | $ hg ci -m "mAE-change,Km: $case_desc" |
|
1485 | 1485 | |
|
1486 | 1486 | (merge variant 2) |
|
1487 | 1487 | |
|
1488 | 1488 | $ hg up 'desc("k-1")' |
|
1489 | 1489 | 2 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
1490 | 1490 | |
|
1491 | 1491 | $ hg merge 'desc("mAE-change-m")' |
|
1492 | 1492 | 1 files updated, 0 files merged, 1 files removed, 0 files unresolved |
|
1493 | 1493 | (branch merge, don't forget to commit) |
|
1494 | 1494 | $ hg ci -m "mK,AE-change-m: $case_desc" |
|
1495 | 1495 | created new head |
|
1496 | 1496 | |
|
1497 | 1497 | (merge variant 3) |
|
1498 | 1498 | |
|
1499 | 1499 | $ hg up 'desc("mEA-change-m")' |
|
1500 | 1500 | 1 files updated, 0 files merged, 1 files removed, 0 files unresolved |
|
1501 | 1501 | $ hg merge 'desc("j-1")' |
|
1502 | 1502 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
1503 | 1503 | (branch merge, don't forget to commit) |
|
1504 | 1504 | $ hg ci -m "mEA-change,Jm: $case_desc" |
|
1505 | 1505 | |
|
1506 | 1506 | (merge variant 4) |
|
1507 | 1507 | |
|
1508 | 1508 | $ hg up 'desc("j-1")' |
|
1509 | 1509 | 2 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
1510 | 1510 | $ hg merge 'desc("mEA-change-m")' |
|
1511 | 1511 | 1 files updated, 0 files merged, 1 files removed, 0 files unresolved |
|
1512 | 1512 | (branch merge, don't forget to commit) |
|
1513 | 1513 | $ hg ci -m "mJ,EA-change-m: $case_desc" |
|
1514 | 1514 | created new head |
|
1515 | 1515 | |
|
1516 | 1516 | |
|
1517 | 1517 | $ hg log -G --rev '::(desc("mAE-change,Km") + desc("mK,AE-change-m") + desc("mEA-change,Jm") + desc("mJ,EA-change-m"))' |
|
1518 | 1518 | @ mJ,EA-change-m: chained merges (conflict+change -> simple) - same content on both branch in the initial merge |
|
1519 | 1519 | |\ |
|
1520 | 1520 | +---o mEA-change,Jm: chained merges (conflict+change -> simple) - same content on both branch in the initial merge |
|
1521 | 1521 | | |/ |
|
1522 | 1522 | | | o mK,AE-change-m: chained merges (conflict+change -> simple) - same content on both branch in the initial merge |
|
1523 | 1523 | | | |\ |
|
1524 | 1524 | | | +---o mAE-change,Km: chained merges (conflict+change -> simple) - same content on both branch in the initial merge |
|
1525 | 1525 | | | | |/ |
|
1526 | 1526 | | | | o k-1: unrelated changes (based on "e" changes) |
|
1527 | 1527 | | | | | |
|
1528 | 1528 | | o | | j-1: unrelated changes (based on the "a" series of changes) |
|
1529 | 1529 | | | | | |
|
1530 | 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 | 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 | 1534 | | o e-2 g -move-> f |
|
1535 | 1535 | | | |
|
1536 | 1536 | | o e-1 b -move-> g |
|
1537 | 1537 | | | |
|
1538 | 1538 | o | a-2: e -move-> f |
|
1539 | 1539 | | | |
|
1540 | 1540 | o | a-1: d -move-> e |
|
1541 | 1541 | |/ |
|
1542 | 1542 | o i-2: c -move-> d, s -move-> t |
|
1543 | 1543 | | |
|
1544 | 1544 | o i-1: a -move-> c, p -move-> s |
|
1545 | 1545 | | |
|
1546 | 1546 | o i-0 initial commit: a b h p q r |
|
1547 | 1547 | |
|
1548 | 1548 | |
|
1549 | 1549 | Summary of all created cases |
|
1550 | 1550 | ---------------------------- |
|
1551 | 1551 | |
|
1552 | 1552 | $ hg up --quiet null |
|
1553 | 1553 | |
|
1554 | 1554 | (This exists to help keeping a compact list of the various cases we have built) |
|
1555 | 1555 | |
|
1556 | 1556 | $ hg log -T '{desc|firstline}\n'| sort |
|
1557 | 1557 | a-1: d -move-> e |
|
1558 | 1558 | a-2: e -move-> f |
|
1559 | 1559 | b-1: b update |
|
1560 | 1560 | c-1 delete d |
|
1561 | 1561 | d-1 delete d |
|
1562 | 1562 | d-2 re-add d |
|
1563 | 1563 | e-1 b -move-> g |
|
1564 | 1564 | e-2 g -move-> f |
|
1565 | 1565 | f-1: rename h -> i |
|
1566 | 1566 | f-2: rename i -> d |
|
1567 | 1567 | g-1: update d |
|
1568 | 1568 | h-1: b -(move)-> d |
|
1569 | 1569 | i-0 initial commit: a b h p q r |
|
1570 | 1570 | i-1: a -move-> c, p -move-> s |
|
1571 | 1571 | i-2: c -move-> d, s -move-> t |
|
1572 | 1572 | j-1: unrelated changes (based on the "a" series of changes) |
|
1573 | 1573 | k-1: unrelated changes (based on "e" changes) |
|
1574 | 1574 | l-1: unrelated changes (based on "c" changes) |
|
1575 | 1575 | mABm-0 simple merge - A side: multiple renames, B side: unrelated update - the other way |
|
1576 | 1576 | mAE,Km: chained merges (conflict -> simple) - same content everywhere |
|
1577 | 1577 | mAE-change,Km: chained merges (conflict+change -> simple) - same content on both branch in the initial merge |
|
1578 | 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 | 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 | 1580 | mBAm-0 simple merge - A side: multiple renames, B side: unrelated update - one way |
|
1581 | 1581 | mBC+revert,Lm: chained merges (salvaged -> simple) - same content (when the file exists) |
|
1582 | 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 | 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 | 1584 | mBCm-0 simple merge - C side: delete a file with copies history , B side: unrelated update - one way |
|
1585 | 1585 | mBCm-1 re-add d |
|
1586 | 1586 | mBDm-0 simple merge - B side: unrelated update, D side: delete and recreate a file (with different content) - one way |
|
1587 | 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 | 1588 | mBFm-0 simple merge - B side: unrelated change, F side: overwrite d with a copy (from h->i->d) - one way |
|
1589 | 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 | 1590 | mCB+revert,Lm: chained merges (salvaged -> simple) - same content (when the file exists) |
|
1591 | 1591 | mCB-change-m-0 merge explicitely revive deleted file - B side: unrelated change, C side: delete d (restored by merge) - one way |
|
1592 | 1592 | mCB-revert-m-0 merge explicitely revive deleted file - B side: unrelated change, C side: delete d (restored by merge) - one way |
|
1593 | 1593 | mCBm-0 simple merge - C side: delete a file with copies history , B side: unrelated update - the other way |
|
1594 | 1594 | mCBm-1 re-add d |
|
1595 | 1595 | mCGm-0 merge updated/deleted - revive the file (updated content) - one way |
|
1596 | 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 | 1597 | mDBm-0 simple merge - B side: unrelated update, D side: delete and recreate a file (with different content) - the other way |
|
1598 | 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 | 1599 | mEA,Jm: chained merges (conflict -> simple) - same content everywhere |
|
1600 | 1600 | mEA-change,Jm: chained merges (conflict+change -> simple) - same content on both branch in the initial merge |
|
1601 | 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 | 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 | 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 | 1604 | mFBm-0 simple merge - B side: unrelated change, F side: overwrite d with a copy (from h->i->d) - the other way |
|
1605 | 1605 | mFG,Om: chained merges (copy-overwrite -> simple) - same content |
|
1606 | 1606 | mFGm-0 merge - G side: content change, F side: copy overwrite, no content change - one way |
|
1607 | 1607 | mGCm-0 merge updated/deleted - revive the file (updated content) - the other way |
|
1608 | 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 | 1609 | mGF,Nm: chained merges (copy-overwrite -> simple) - same content |
|
1610 | 1610 | mGFm-0 merge - G side: content change, F side: copy overwrite, no content change - the other way |
|
1611 | 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 | 1612 | mJ,EA-change-m: chained merges (conflict+change -> simple) - same content on both branch in the initial merge |
|
1613 | 1613 | mJ,EAm: chained merges (conflict -> simple) - same content everywhere |
|
1614 | 1614 | mK,AE-change-m: chained merges (conflict+change -> simple) - same content on both branch in the initial merge |
|
1615 | 1615 | mK,AEm: chained merges (conflict -> simple) - same content everywhere |
|
1616 | 1616 | mL,BC+revertm: chained merges (salvaged -> simple) - same content (when the file exists) |
|
1617 | 1617 | mL,CB+revertm: chained merges (salvaged -> simple) - same content (when the file exists) |
|
1618 | 1618 | mN,GFm: chained merges (copy-overwrite -> simple) - same content |
|
1619 | 1619 | mO,FGm: chained merges (copy-overwrite -> simple) - same content |
|
1620 | 1620 | mPQ,Tm: chained merges (conflict -> simple) - different content |
|
1621 | 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 | 1622 | mQP,Sm: chained merges (conflict -> simple) - different content |
|
1623 | 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 | 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 | 1625 | mS,QPm: chained merges (conflict -> simple) - different content |
|
1626 | 1626 | mT,PQm: chained merges (conflict -> simple) - different content |
|
1627 | 1627 | n-1: unrelated changes (based on the "f" series of changes) |
|
1628 | 1628 | o-1: unrelated changes (based on "g" changes) |
|
1629 | 1629 | p-1: t -move-> u |
|
1630 | 1630 | p-2: u -move-> v |
|
1631 | 1631 | q-1 r -move-> w |
|
1632 | 1632 | q-2 w -move-> v |
|
1633 | 1633 | r-1: rename r -> x |
|
1634 | 1634 | r-2: rename t -> x |
|
1635 | 1635 | s-1: unrelated changes (based on the "p" series of changes) |
|
1636 | 1636 | t-1: unrelated changes (based on "q" changes) |
|
1637 | 1637 | |
|
1638 | 1638 | |
|
1639 | 1639 | Test that sidedata computations during upgrades are correct |
|
1640 | 1640 | =========================================================== |
|
1641 | 1641 | |
|
1642 | 1642 | We upgrade a repository that is not using sidedata (the filelog case) and |
|
1643 | 1643 | check that the same side data have been generated as if they were computed at |
|
1644 | 1644 | commit time. |
|
1645 | 1645 | |
|
1646 | 1646 | |
|
1647 | 1647 | #if upgraded |
|
1648 | 1648 | $ cat >> $HGRCPATH << EOF |
|
1649 | 1649 | > [format] |
|
1650 | 1650 | > exp-use-copies-side-data-changeset = yes |
|
1651 | 1651 | > EOF |
|
1652 | 1652 | $ hg debugformat -v |
|
1653 | 1653 | format-variant repo config default |
|
1654 | 1654 | fncache: yes yes yes |
|
1655 | dirstate-v2: no no no | |
|
1655 | 1656 | dotencode: yes yes yes |
|
1656 | 1657 | generaldelta: yes yes yes |
|
1657 | 1658 | share-safe: no no no |
|
1658 | 1659 | sparserevlog: yes yes yes |
|
1659 | 1660 | persistent-nodemap: no no no (no-rust !) |
|
1660 | 1661 | persistent-nodemap: yes yes no (rust !) |
|
1661 | 1662 | copies-sdc: no yes no |
|
1662 | 1663 | revlog-v2: no no no |
|
1663 | 1664 | changelog-v2: no yes no |
|
1664 | 1665 | plain-cl-delta: yes yes yes |
|
1665 | 1666 | compression: * (glob) |
|
1666 | 1667 | compression-level: default default default |
|
1667 | 1668 | $ hg debugupgraderepo --run --quiet |
|
1668 | 1669 | upgrade will perform the following actions: |
|
1669 | 1670 | |
|
1670 | 1671 | requirements |
|
1671 | 1672 | preserved: * (glob) |
|
1672 | 1673 | added: exp-changelog-v2, exp-copies-sidedata-changeset |
|
1673 | 1674 | |
|
1674 | 1675 | processed revlogs: |
|
1675 | 1676 | - all-filelogs |
|
1676 | 1677 | - changelog |
|
1677 | 1678 | - manifest |
|
1678 | 1679 | |
|
1679 | 1680 | #endif |
|
1680 | 1681 | |
|
1681 | 1682 | #if upgraded-parallel |
|
1682 | 1683 | $ cat >> $HGRCPATH << EOF |
|
1683 | 1684 | > [format] |
|
1684 | 1685 | > exp-use-copies-side-data-changeset = yes |
|
1685 | 1686 | > [experimental] |
|
1686 | 1687 | > worker.repository-upgrade=yes |
|
1687 | 1688 | > [worker] |
|
1688 | 1689 | > enabled=yes |
|
1689 | 1690 | > numcpus=8 |
|
1690 | 1691 | > EOF |
|
1691 | 1692 | $ hg debugformat -v |
|
1692 | 1693 | format-variant repo config default |
|
1693 | 1694 | fncache: yes yes yes |
|
1695 | dirstate-v2: no no no | |
|
1694 | 1696 | dotencode: yes yes yes |
|
1695 | 1697 | generaldelta: yes yes yes |
|
1696 | 1698 | share-safe: no no no |
|
1697 | 1699 | sparserevlog: yes yes yes |
|
1698 | 1700 | persistent-nodemap: no no no (no-rust !) |
|
1699 | 1701 | persistent-nodemap: yes yes no (rust !) |
|
1700 | 1702 | copies-sdc: no yes no |
|
1701 | 1703 | revlog-v2: no no no |
|
1702 | 1704 | changelog-v2: no yes no |
|
1703 | 1705 | plain-cl-delta: yes yes yes |
|
1704 | 1706 | compression: * (glob) |
|
1705 | 1707 | compression-level: default default default |
|
1706 | 1708 | $ hg debugupgraderepo --run --quiet |
|
1707 | 1709 | upgrade will perform the following actions: |
|
1708 | 1710 | |
|
1709 | 1711 | requirements |
|
1710 | 1712 | preserved: * (glob) |
|
1711 | 1713 | added: exp-changelog-v2, exp-copies-sidedata-changeset |
|
1712 | 1714 | |
|
1713 | 1715 | processed revlogs: |
|
1714 | 1716 | - all-filelogs |
|
1715 | 1717 | - changelog |
|
1716 | 1718 | - manifest |
|
1717 | 1719 | |
|
1718 | 1720 | #endif |
|
1719 | 1721 | |
|
1720 | 1722 | #if pull |
|
1721 | 1723 | $ cd .. |
|
1722 | 1724 | $ mv repo-chain repo-source |
|
1723 | 1725 | $ hg init repo-chain |
|
1724 | 1726 | $ cd repo-chain |
|
1725 | 1727 | $ hg pull ../repo-source |
|
1726 | 1728 | pulling from ../repo-source |
|
1727 | 1729 | requesting all changes |
|
1728 | 1730 | adding changesets |
|
1729 | 1731 | adding manifests |
|
1730 | 1732 | adding file changes |
|
1731 | 1733 | added 80 changesets with 44 changes to 25 files (+39 heads) |
|
1732 | 1734 | new changesets a3a31bbefea6:908ce9259ffa |
|
1733 | 1735 | (run 'hg heads' to see heads, 'hg merge' to merge) |
|
1734 | 1736 | #endif |
|
1735 | 1737 | |
|
1736 | 1738 | #if pull-upgrade |
|
1737 | 1739 | $ cat >> $HGRCPATH << EOF |
|
1738 | 1740 | > [format] |
|
1739 | 1741 | > exp-use-copies-side-data-changeset = yes |
|
1740 | 1742 | > [experimental] |
|
1741 | 1743 | > changegroup4 = yes |
|
1742 | 1744 | > EOF |
|
1743 | 1745 | $ cd .. |
|
1744 | 1746 | $ mv repo-chain repo-source |
|
1745 | 1747 | $ hg init repo-chain |
|
1746 | 1748 | $ cd repo-chain |
|
1747 | 1749 | $ hg pull ../repo-source |
|
1748 | 1750 | pulling from ../repo-source |
|
1749 | 1751 | requesting all changes |
|
1750 | 1752 | adding changesets |
|
1751 | 1753 | adding manifests |
|
1752 | 1754 | adding file changes |
|
1753 | 1755 | added 80 changesets with 44 changes to 25 files (+39 heads) |
|
1754 | 1756 | new changesets a3a31bbefea6:908ce9259ffa |
|
1755 | 1757 | (run 'hg heads' to see heads, 'hg merge' to merge) |
|
1756 | 1758 | #endif |
|
1757 | 1759 | |
|
1758 | 1760 | #if push |
|
1759 | 1761 | $ cd .. |
|
1760 | 1762 | $ mv repo-chain repo-source |
|
1761 | 1763 | $ hg init repo-chain |
|
1762 | 1764 | $ cd repo-source |
|
1763 | 1765 | $ hg push ../repo-chain |
|
1764 | 1766 | pushing to ../repo-chain |
|
1765 | 1767 | searching for changes |
|
1766 | 1768 | adding changesets |
|
1767 | 1769 | adding manifests |
|
1768 | 1770 | adding file changes |
|
1769 | 1771 | added 80 changesets with 44 changes to 25 files (+39 heads) |
|
1770 | 1772 | $ cd ../repo-chain |
|
1771 | 1773 | #endif |
|
1772 | 1774 | |
|
1773 | 1775 | #if push-upgrade |
|
1774 | 1776 | $ cat >> $HGRCPATH << EOF |
|
1775 | 1777 | > [format] |
|
1776 | 1778 | > exp-use-copies-side-data-changeset = yes |
|
1777 | 1779 | > [experimental] |
|
1778 | 1780 | > changegroup4 = yes |
|
1779 | 1781 | > EOF |
|
1780 | 1782 | $ cd .. |
|
1781 | 1783 | $ mv repo-chain repo-source |
|
1782 | 1784 | $ hg init repo-chain |
|
1783 | 1785 | $ cd repo-source |
|
1784 | 1786 | $ hg push ../repo-chain |
|
1785 | 1787 | pushing to ../repo-chain |
|
1786 | 1788 | searching for changes |
|
1787 | 1789 | adding changesets |
|
1788 | 1790 | adding manifests |
|
1789 | 1791 | adding file changes |
|
1790 | 1792 | added 80 changesets with 44 changes to 25 files (+39 heads) |
|
1791 | 1793 | $ cd ../repo-chain |
|
1792 | 1794 | #endif |
|
1793 | 1795 | |
|
1794 | 1796 | #if no-compatibility no-filelog no-changeset |
|
1795 | 1797 | |
|
1796 | 1798 | $ hg debugchangedfiles --compute 0 |
|
1797 | 1799 | added : a, ; |
|
1798 | 1800 | added : b, ; |
|
1799 | 1801 | added : h, ; |
|
1800 | 1802 | added : p, ; |
|
1801 | 1803 | added : q, ; |
|
1802 | 1804 | added : r, ; |
|
1803 | 1805 | |
|
1804 | 1806 | $ for rev in `hg log --rev 'all()' -T '{rev}\n'`; do |
|
1805 | 1807 | > case_id=`hg log -r $rev -T '{word(0, desc, ":")}\n'` |
|
1806 | 1808 | > echo "##### revision \"$case_id\" #####" |
|
1807 | 1809 | > hg debugsidedata -c -v -- $rev |
|
1808 | 1810 | > hg debugchangedfiles $rev |
|
1809 | 1811 | > done |
|
1810 | 1812 | ##### revision "i-0 initial commit" ##### |
|
1811 | 1813 | 1 sidedata entries |
|
1812 | 1814 | entry-0014 size 64 |
|
1813 | 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 | 1816 | added : a, ; |
|
1815 | 1817 | added : b, ; |
|
1816 | 1818 | added : h, ; |
|
1817 | 1819 | added : p, ; |
|
1818 | 1820 | added : q, ; |
|
1819 | 1821 | added : r, ; |
|
1820 | 1822 | ##### revision "i-1" ##### |
|
1821 | 1823 | 1 sidedata entries |
|
1822 | 1824 | entry-0014 size 44 |
|
1823 | 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 | 1826 | removed : a, ; |
|
1825 | 1827 | added p1: c, a; |
|
1826 | 1828 | removed : p, ; |
|
1827 | 1829 | added p1: s, p; |
|
1828 | 1830 | ##### revision "i-2" ##### |
|
1829 | 1831 | 1 sidedata entries |
|
1830 | 1832 | entry-0014 size 44 |
|
1831 | 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 | 1834 | removed : c, ; |
|
1833 | 1835 | added p1: d, c; |
|
1834 | 1836 | removed : s, ; |
|
1835 | 1837 | added p1: t, s; |
|
1836 | 1838 | ##### revision "a-1" ##### |
|
1837 | 1839 | 1 sidedata entries |
|
1838 | 1840 | entry-0014 size 24 |
|
1839 | 1841 | '\x00\x00\x00\x02\x0c\x00\x00\x00\x01\x00\x00\x00\x00\x06\x00\x00\x00\x02\x00\x00\x00\x00de' |
|
1840 | 1842 | removed : d, ; |
|
1841 | 1843 | added p1: e, d; |
|
1842 | 1844 | ##### revision "a-2" ##### |
|
1843 | 1845 | 1 sidedata entries |
|
1844 | 1846 | entry-0014 size 24 |
|
1845 | 1847 | '\x00\x00\x00\x02\x0c\x00\x00\x00\x01\x00\x00\x00\x00\x06\x00\x00\x00\x02\x00\x00\x00\x00ef' |
|
1846 | 1848 | removed : e, ; |
|
1847 | 1849 | added p1: f, e; |
|
1848 | 1850 | ##### revision "b-1" ##### |
|
1849 | 1851 | 1 sidedata entries |
|
1850 | 1852 | entry-0014 size 14 |
|
1851 | 1853 | '\x00\x00\x00\x01\x14\x00\x00\x00\x01\x00\x00\x00\x00b' |
|
1852 | 1854 | touched : b, ; |
|
1853 | 1855 | ##### revision "c-1 delete d" ##### |
|
1854 | 1856 | 1 sidedata entries |
|
1855 | 1857 | entry-0014 size 14 |
|
1856 | 1858 | '\x00\x00\x00\x01\x0c\x00\x00\x00\x01\x00\x00\x00\x00d' |
|
1857 | 1859 | removed : d, ; |
|
1858 | 1860 | ##### revision "d-1 delete d" ##### |
|
1859 | 1861 | 1 sidedata entries |
|
1860 | 1862 | entry-0014 size 14 |
|
1861 | 1863 | '\x00\x00\x00\x01\x0c\x00\x00\x00\x01\x00\x00\x00\x00d' |
|
1862 | 1864 | removed : d, ; |
|
1863 | 1865 | ##### revision "d-2 re-add d" ##### |
|
1864 | 1866 | 1 sidedata entries |
|
1865 | 1867 | entry-0014 size 14 |
|
1866 | 1868 | '\x00\x00\x00\x01\x04\x00\x00\x00\x01\x00\x00\x00\x00d' |
|
1867 | 1869 | added : d, ; |
|
1868 | 1870 | ##### revision "e-1 b -move-> g" ##### |
|
1869 | 1871 | 1 sidedata entries |
|
1870 | 1872 | entry-0014 size 24 |
|
1871 | 1873 | '\x00\x00\x00\x02\x0c\x00\x00\x00\x01\x00\x00\x00\x00\x06\x00\x00\x00\x02\x00\x00\x00\x00bg' |
|
1872 | 1874 | removed : b, ; |
|
1873 | 1875 | added p1: g, b; |
|
1874 | 1876 | ##### revision "e-2 g -move-> f" ##### |
|
1875 | 1877 | 1 sidedata entries |
|
1876 | 1878 | entry-0014 size 24 |
|
1877 | 1879 | '\x00\x00\x00\x02\x06\x00\x00\x00\x01\x00\x00\x00\x01\x0c\x00\x00\x00\x02\x00\x00\x00\x00fg' |
|
1878 | 1880 | added p1: f, g; |
|
1879 | 1881 | removed : g, ; |
|
1880 | 1882 | ##### revision "p-1" ##### |
|
1881 | 1883 | 1 sidedata entries |
|
1882 | 1884 | entry-0014 size 24 |
|
1883 | 1885 | '\x00\x00\x00\x02\x0c\x00\x00\x00\x01\x00\x00\x00\x00\x06\x00\x00\x00\x02\x00\x00\x00\x00tu' |
|
1884 | 1886 | removed : t, ; |
|
1885 | 1887 | added p1: u, t; |
|
1886 | 1888 | ##### revision "p-2" ##### |
|
1887 | 1889 | 1 sidedata entries |
|
1888 | 1890 | entry-0014 size 24 |
|
1889 | 1891 | '\x00\x00\x00\x02\x0c\x00\x00\x00\x01\x00\x00\x00\x00\x06\x00\x00\x00\x02\x00\x00\x00\x00uv' |
|
1890 | 1892 | removed : u, ; |
|
1891 | 1893 | added p1: v, u; |
|
1892 | 1894 | ##### revision "q-1 r -move-> w" ##### |
|
1893 | 1895 | 1 sidedata entries |
|
1894 | 1896 | entry-0014 size 24 |
|
1895 | 1897 | '\x00\x00\x00\x02\x0c\x00\x00\x00\x01\x00\x00\x00\x00\x06\x00\x00\x00\x02\x00\x00\x00\x00rw' |
|
1896 | 1898 | removed : r, ; |
|
1897 | 1899 | added p1: w, r; |
|
1898 | 1900 | ##### revision "q-2 w -move-> v" ##### |
|
1899 | 1901 | 1 sidedata entries |
|
1900 | 1902 | entry-0014 size 24 |
|
1901 | 1903 | '\x00\x00\x00\x02\x06\x00\x00\x00\x01\x00\x00\x00\x01\x0c\x00\x00\x00\x02\x00\x00\x00\x00vw' |
|
1902 | 1904 | added p1: v, w; |
|
1903 | 1905 | removed : w, ; |
|
1904 | 1906 | ##### revision "mBAm-0 simple merge - A side" ##### |
|
1905 | 1907 | 1 sidedata entries |
|
1906 | 1908 | entry-0014 size 4 |
|
1907 | 1909 | '\x00\x00\x00\x00' |
|
1908 | 1910 | ##### revision "mABm-0 simple merge - A side" ##### |
|
1909 | 1911 | 1 sidedata entries |
|
1910 | 1912 | entry-0014 size 4 |
|
1911 | 1913 | '\x00\x00\x00\x00' |
|
1912 | 1914 | ##### revision "mBCm-0 simple merge - C side" ##### |
|
1913 | 1915 | 1 sidedata entries |
|
1914 | 1916 | entry-0014 size 4 |
|
1915 | 1917 | '\x00\x00\x00\x00' |
|
1916 | 1918 | ##### revision "mBCm-1 re-add d" ##### |
|
1917 | 1919 | 1 sidedata entries |
|
1918 | 1920 | entry-0014 size 14 |
|
1919 | 1921 | '\x00\x00\x00\x01\x04\x00\x00\x00\x01\x00\x00\x00\x00d' |
|
1920 | 1922 | added : d, ; |
|
1921 | 1923 | ##### revision "mCBm-0 simple merge - C side" ##### |
|
1922 | 1924 | 1 sidedata entries |
|
1923 | 1925 | entry-0014 size 4 |
|
1924 | 1926 | '\x00\x00\x00\x00' |
|
1925 | 1927 | ##### revision "mCBm-1 re-add d" ##### |
|
1926 | 1928 | 1 sidedata entries |
|
1927 | 1929 | entry-0014 size 14 |
|
1928 | 1930 | '\x00\x00\x00\x01\x04\x00\x00\x00\x01\x00\x00\x00\x00d' |
|
1929 | 1931 | added : d, ; |
|
1930 | 1932 | ##### revision "mBDm-0 simple merge - B side" ##### |
|
1931 | 1933 | 1 sidedata entries |
|
1932 | 1934 | entry-0014 size 4 |
|
1933 | 1935 | '\x00\x00\x00\x00' |
|
1934 | 1936 | ##### revision "mDBm-0 simple merge - B side" ##### |
|
1935 | 1937 | 1 sidedata entries |
|
1936 | 1938 | entry-0014 size 4 |
|
1937 | 1939 | '\x00\x00\x00\x00' |
|
1938 | 1940 | ##### revision "mAEm-0 merge with copies info on both side - A side" ##### |
|
1939 | 1941 | 1 sidedata entries |
|
1940 | 1942 | entry-0014 size 14 |
|
1941 | 1943 | '\x00\x00\x00\x01\x08\x00\x00\x00\x01\x00\x00\x00\x00f' |
|
1942 | 1944 | merged : f, ; |
|
1943 | 1945 | ##### revision "mEAm-0 merge with copies info on both side - A side" ##### |
|
1944 | 1946 | 1 sidedata entries |
|
1945 | 1947 | entry-0014 size 14 |
|
1946 | 1948 | '\x00\x00\x00\x01\x08\x00\x00\x00\x01\x00\x00\x00\x00f' |
|
1947 | 1949 | merged : f, ; |
|
1948 | 1950 | ##### revision "mPQm-0 merge with copies info on both side - P side" ##### |
|
1949 | 1951 | 1 sidedata entries |
|
1950 | 1952 | entry-0014 size 14 |
|
1951 | 1953 | '\x00\x00\x00\x01\x08\x00\x00\x00\x01\x00\x00\x00\x00v' |
|
1952 | 1954 | merged : v, ; |
|
1953 | 1955 | ##### revision "mQPm-0 merge with copies info on both side - P side" ##### |
|
1954 | 1956 | 1 sidedata entries |
|
1955 | 1957 | entry-0014 size 14 |
|
1956 | 1958 | '\x00\x00\x00\x01\x08\x00\x00\x00\x01\x00\x00\x00\x00v' |
|
1957 | 1959 | merged : v, ; |
|
1958 | 1960 | ##### revision "f-1" ##### |
|
1959 | 1961 | 1 sidedata entries |
|
1960 | 1962 | entry-0014 size 24 |
|
1961 | 1963 | '\x00\x00\x00\x02\x0c\x00\x00\x00\x01\x00\x00\x00\x00\x06\x00\x00\x00\x02\x00\x00\x00\x00hi' |
|
1962 | 1964 | removed : h, ; |
|
1963 | 1965 | added p1: i, h; |
|
1964 | 1966 | ##### revision "f-2" ##### |
|
1965 | 1967 | 1 sidedata entries |
|
1966 | 1968 | entry-0014 size 24 |
|
1967 | 1969 | '\x00\x00\x00\x02\x16\x00\x00\x00\x01\x00\x00\x00\x01\x0c\x00\x00\x00\x02\x00\x00\x00\x00di' |
|
1968 | 1970 | touched p1: d, i; |
|
1969 | 1971 | removed : i, ; |
|
1970 | 1972 | ##### revision "mBFm-0 simple merge - B side" ##### |
|
1971 | 1973 | 1 sidedata entries |
|
1972 | 1974 | entry-0014 size 4 |
|
1973 | 1975 | '\x00\x00\x00\x00' |
|
1974 | 1976 | ##### revision "mFBm-0 simple merge - B side" ##### |
|
1975 | 1977 | 1 sidedata entries |
|
1976 | 1978 | entry-0014 size 4 |
|
1977 | 1979 | '\x00\x00\x00\x00' |
|
1978 | 1980 | ##### revision "r-1" ##### |
|
1979 | 1981 | 1 sidedata entries |
|
1980 | 1982 | entry-0014 size 24 |
|
1981 | 1983 | '\x00\x00\x00\x02\x0c\x00\x00\x00\x01\x00\x00\x00\x00\x06\x00\x00\x00\x02\x00\x00\x00\x00rx' |
|
1982 | 1984 | removed : r, ; |
|
1983 | 1985 | added p1: x, r; |
|
1984 | 1986 | ##### revision "r-2" ##### |
|
1985 | 1987 | 1 sidedata entries |
|
1986 | 1988 | entry-0014 size 24 |
|
1987 | 1989 | '\x00\x00\x00\x02\x16\x00\x00\x00\x01\x00\x00\x00\x01\x0c\x00\x00\x00\x02\x00\x00\x00\x00tx' |
|
1988 | 1990 | touched p1: t, x; |
|
1989 | 1991 | removed : x, ; |
|
1990 | 1992 | ##### revision "mBRm-0 simple merge - B side" ##### |
|
1991 | 1993 | 1 sidedata entries |
|
1992 | 1994 | entry-0014 size 4 |
|
1993 | 1995 | '\x00\x00\x00\x00' |
|
1994 | 1996 | ##### revision "mRBm-0 simple merge - B side" ##### |
|
1995 | 1997 | 1 sidedata entries |
|
1996 | 1998 | entry-0014 size 4 |
|
1997 | 1999 | '\x00\x00\x00\x00' |
|
1998 | 2000 | ##### revision "g-1" ##### |
|
1999 | 2001 | 1 sidedata entries |
|
2000 | 2002 | entry-0014 size 14 |
|
2001 | 2003 | '\x00\x00\x00\x01\x14\x00\x00\x00\x01\x00\x00\x00\x00d' |
|
2002 | 2004 | touched : d, ; |
|
2003 | 2005 | ##### revision "mDGm-0 actual content merge, copies on one side - D side" ##### |
|
2004 | 2006 | 1 sidedata entries |
|
2005 | 2007 | entry-0014 size 14 |
|
2006 | 2008 | '\x00\x00\x00\x01\x08\x00\x00\x00\x01\x00\x00\x00\x00d' |
|
2007 | 2009 | merged : d, ; |
|
2008 | 2010 | ##### revision "mGDm-0 actual content merge, copies on one side - D side" ##### |
|
2009 | 2011 | 1 sidedata entries |
|
2010 | 2012 | entry-0014 size 14 |
|
2011 | 2013 | '\x00\x00\x00\x01\x08\x00\x00\x00\x01\x00\x00\x00\x00d' |
|
2012 | 2014 | merged : d, ; |
|
2013 | 2015 | ##### revision "mFGm-0 merge - G side" ##### |
|
2014 | 2016 | 1 sidedata entries |
|
2015 | 2017 | entry-0014 size 14 |
|
2016 | 2018 | '\x00\x00\x00\x01\x08\x00\x00\x00\x01\x00\x00\x00\x00d' |
|
2017 | 2019 | merged : d, ; |
|
2018 | 2020 | ##### revision "mGFm-0 merge - G side" ##### |
|
2019 | 2021 | 1 sidedata entries |
|
2020 | 2022 | entry-0014 size 14 |
|
2021 | 2023 | '\x00\x00\x00\x01\x08\x00\x00\x00\x01\x00\x00\x00\x00d' |
|
2022 | 2024 | merged : d, ; |
|
2023 | 2025 | ##### revision "mCGm-0 merge updated/deleted - revive the file (updated content) - one way" ##### |
|
2024 | 2026 | 1 sidedata entries |
|
2025 | 2027 | entry-0014 size 14 |
|
2026 | 2028 | '\x00\x00\x00\x01\x10\x00\x00\x00\x01\x00\x00\x00\x00d' |
|
2027 | 2029 | salvaged : d, ; |
|
2028 | 2030 | ##### revision "mGCm-0 merge updated/deleted - revive the file (updated content) - the other way" ##### |
|
2029 | 2031 | 1 sidedata entries |
|
2030 | 2032 | entry-0014 size 14 |
|
2031 | 2033 | '\x00\x00\x00\x01\x10\x00\x00\x00\x01\x00\x00\x00\x00d' |
|
2032 | 2034 | salvaged : d, ; |
|
2033 | 2035 | ##### revision "mCB-revert-m-0 merge explicitely revive deleted file - B side" ##### |
|
2034 | 2036 | 1 sidedata entries |
|
2035 | 2037 | entry-0014 size 14 |
|
2036 | 2038 | '\x00\x00\x00\x01\x10\x00\x00\x00\x01\x00\x00\x00\x00d' |
|
2037 | 2039 | salvaged : d, ; |
|
2038 | 2040 | ##### revision "mBC-revert-m-0 merge explicitely revive deleted file - B side" ##### |
|
2039 | 2041 | 1 sidedata entries |
|
2040 | 2042 | entry-0014 size 14 |
|
2041 | 2043 | '\x00\x00\x00\x01\x10\x00\x00\x00\x01\x00\x00\x00\x00d' |
|
2042 | 2044 | salvaged : d, ; |
|
2043 | 2045 | ##### revision "h-1" ##### |
|
2044 | 2046 | 1 sidedata entries |
|
2045 | 2047 | entry-0014 size 24 |
|
2046 | 2048 | '\x00\x00\x00\x02\x0c\x00\x00\x00\x01\x00\x00\x00\x00\x06\x00\x00\x00\x02\x00\x00\x00\x00bd' |
|
2047 | 2049 | removed : b, ; |
|
2048 | 2050 | added p1: d, b; |
|
2049 | 2051 | ##### revision "mCH-delete-before-conflict-m-0 simple merge - C side" ##### |
|
2050 | 2052 | 1 sidedata entries |
|
2051 | 2053 | entry-0014 size 4 |
|
2052 | 2054 | '\x00\x00\x00\x00' |
|
2053 | 2055 | ##### revision "mHC-delete-before-conflict-m-0 simple merge - C side" ##### |
|
2054 | 2056 | 1 sidedata entries |
|
2055 | 2057 | entry-0014 size 4 |
|
2056 | 2058 | '\x00\x00\x00\x00' |
|
2057 | 2059 | ##### revision "mAE-change-m-0 merge with file update and copies info on both side - A side" ##### |
|
2058 | 2060 | 1 sidedata entries |
|
2059 | 2061 | entry-0014 size 14 |
|
2060 | 2062 | '\x00\x00\x00\x01\x08\x00\x00\x00\x01\x00\x00\x00\x00f' |
|
2061 | 2063 | merged : f, ; |
|
2062 | 2064 | ##### revision "mEA-change-m-0 merge with file update and copies info on both side - A side" ##### |
|
2063 | 2065 | 1 sidedata entries |
|
2064 | 2066 | entry-0014 size 14 |
|
2065 | 2067 | '\x00\x00\x00\x01\x08\x00\x00\x00\x01\x00\x00\x00\x00f' |
|
2066 | 2068 | merged : f, ; |
|
2067 | 2069 | ##### revision "mBF-change-m-0 merge with extra change - B side" ##### |
|
2068 | 2070 | 1 sidedata entries |
|
2069 | 2071 | entry-0014 size 14 |
|
2070 | 2072 | '\x00\x00\x00\x01\x14\x00\x00\x00\x01\x00\x00\x00\x00d' |
|
2071 | 2073 | touched : d, ; |
|
2072 | 2074 | ##### revision "mFB-change-m-0 merge with extra change - B side" ##### |
|
2073 | 2075 | 1 sidedata entries |
|
2074 | 2076 | entry-0014 size 14 |
|
2075 | 2077 | '\x00\x00\x00\x01\x14\x00\x00\x00\x01\x00\x00\x00\x00d' |
|
2076 | 2078 | touched : d, ; |
|
2077 | 2079 | ##### revision "mCB-change-m-0 merge explicitely revive deleted file - B side" ##### |
|
2078 | 2080 | 1 sidedata entries |
|
2079 | 2081 | entry-0014 size 14 |
|
2080 | 2082 | '\x00\x00\x00\x01\x10\x00\x00\x00\x01\x00\x00\x00\x00d' |
|
2081 | 2083 | salvaged : d, ; |
|
2082 | 2084 | ##### revision "mBC-change-m-0 merge explicitely revive deleted file - B side" ##### |
|
2083 | 2085 | 1 sidedata entries |
|
2084 | 2086 | entry-0014 size 14 |
|
2085 | 2087 | '\x00\x00\x00\x01\x10\x00\x00\x00\x01\x00\x00\x00\x00d' |
|
2086 | 2088 | salvaged : d, ; |
|
2087 | 2089 | ##### revision "j-1" ##### |
|
2088 | 2090 | 1 sidedata entries |
|
2089 | 2091 | entry-0014 size 24 |
|
2090 | 2092 | '\x00\x00\x00\x01\x04\x00\x00\x00\x0b\x00\x00\x00\x00unrelated-j' |
|
2091 | 2093 | added : unrelated-j, ; |
|
2092 | 2094 | ##### revision "k-1" ##### |
|
2093 | 2095 | 1 sidedata entries |
|
2094 | 2096 | entry-0014 size 24 |
|
2095 | 2097 | '\x00\x00\x00\x01\x04\x00\x00\x00\x0b\x00\x00\x00\x00unrelated-k' |
|
2096 | 2098 | added : unrelated-k, ; |
|
2097 | 2099 | ##### revision "mAE,Km" ##### |
|
2098 | 2100 | 1 sidedata entries |
|
2099 | 2101 | entry-0014 size 4 |
|
2100 | 2102 | '\x00\x00\x00\x00' |
|
2101 | 2103 | ##### revision "mK,AEm" ##### |
|
2102 | 2104 | 1 sidedata entries |
|
2103 | 2105 | entry-0014 size 4 |
|
2104 | 2106 | '\x00\x00\x00\x00' |
|
2105 | 2107 | ##### revision "mEA,Jm" ##### |
|
2106 | 2108 | 1 sidedata entries |
|
2107 | 2109 | entry-0014 size 24 |
|
2108 | 2110 | '\x00\x00\x00\x01\x14\x00\x00\x00\x0b\x00\x00\x00\x00unrelated-j' |
|
2109 | 2111 | touched : unrelated-j, ; |
|
2110 | 2112 | ##### revision "mJ,EAm" ##### |
|
2111 | 2113 | 1 sidedata entries |
|
2112 | 2114 | entry-0014 size 24 |
|
2113 | 2115 | '\x00\x00\x00\x01\x14\x00\x00\x00\x0b\x00\x00\x00\x00unrelated-j' |
|
2114 | 2116 | touched : unrelated-j, ; |
|
2115 | 2117 | ##### revision "s-1" ##### |
|
2116 | 2118 | 1 sidedata entries |
|
2117 | 2119 | entry-0014 size 24 |
|
2118 | 2120 | '\x00\x00\x00\x01\x04\x00\x00\x00\x0b\x00\x00\x00\x00unrelated-s' |
|
2119 | 2121 | added : unrelated-s, ; |
|
2120 | 2122 | ##### revision "t-1" ##### |
|
2121 | 2123 | 1 sidedata entries |
|
2122 | 2124 | entry-0014 size 24 |
|
2123 | 2125 | '\x00\x00\x00\x01\x04\x00\x00\x00\x0b\x00\x00\x00\x00unrelated-t' |
|
2124 | 2126 | added : unrelated-t, ; |
|
2125 | 2127 | ##### revision "mPQ,Tm" ##### |
|
2126 | 2128 | 1 sidedata entries |
|
2127 | 2129 | entry-0014 size 4 |
|
2128 | 2130 | '\x00\x00\x00\x00' |
|
2129 | 2131 | ##### revision "mT,PQm" ##### |
|
2130 | 2132 | 1 sidedata entries |
|
2131 | 2133 | entry-0014 size 4 |
|
2132 | 2134 | '\x00\x00\x00\x00' |
|
2133 | 2135 | ##### revision "mQP,Sm" ##### |
|
2134 | 2136 | 1 sidedata entries |
|
2135 | 2137 | entry-0014 size 4 |
|
2136 | 2138 | '\x00\x00\x00\x00' |
|
2137 | 2139 | ##### revision "mS,QPm" ##### |
|
2138 | 2140 | 1 sidedata entries |
|
2139 | 2141 | entry-0014 size 4 |
|
2140 | 2142 | '\x00\x00\x00\x00' |
|
2141 | 2143 | ##### revision "l-1" ##### |
|
2142 | 2144 | 1 sidedata entries |
|
2143 | 2145 | entry-0014 size 24 |
|
2144 | 2146 | '\x00\x00\x00\x01\x04\x00\x00\x00\x0b\x00\x00\x00\x00unrelated-l' |
|
2145 | 2147 | added : unrelated-l, ; |
|
2146 | 2148 | ##### revision "mBC+revert,Lm" ##### |
|
2147 | 2149 | 1 sidedata entries |
|
2148 | 2150 | entry-0014 size 4 |
|
2149 | 2151 | '\x00\x00\x00\x00' |
|
2150 | 2152 | ##### revision "mCB+revert,Lm" ##### |
|
2151 | 2153 | 1 sidedata entries |
|
2152 | 2154 | entry-0014 size 4 |
|
2153 | 2155 | '\x00\x00\x00\x00' |
|
2154 | 2156 | ##### revision "mL,BC+revertm" ##### |
|
2155 | 2157 | 1 sidedata entries |
|
2156 | 2158 | entry-0014 size 4 |
|
2157 | 2159 | '\x00\x00\x00\x00' |
|
2158 | 2160 | ##### revision "mL,CB+revertm" ##### |
|
2159 | 2161 | 1 sidedata entries |
|
2160 | 2162 | entry-0014 size 4 |
|
2161 | 2163 | '\x00\x00\x00\x00' |
|
2162 | 2164 | ##### revision "n-1" ##### |
|
2163 | 2165 | 1 sidedata entries |
|
2164 | 2166 | entry-0014 size 24 |
|
2165 | 2167 | '\x00\x00\x00\x01\x04\x00\x00\x00\x0b\x00\x00\x00\x00unrelated-n' |
|
2166 | 2168 | added : unrelated-n, ; |
|
2167 | 2169 | ##### revision "o-1" ##### |
|
2168 | 2170 | 1 sidedata entries |
|
2169 | 2171 | entry-0014 size 24 |
|
2170 | 2172 | '\x00\x00\x00\x01\x04\x00\x00\x00\x0b\x00\x00\x00\x00unrelated-o' |
|
2171 | 2173 | added : unrelated-o, ; |
|
2172 | 2174 | ##### revision "mFG,Om" ##### |
|
2173 | 2175 | 1 sidedata entries |
|
2174 | 2176 | entry-0014 size 4 |
|
2175 | 2177 | '\x00\x00\x00\x00' |
|
2176 | 2178 | ##### revision "mO,FGm" ##### |
|
2177 | 2179 | 1 sidedata entries |
|
2178 | 2180 | entry-0014 size 4 |
|
2179 | 2181 | '\x00\x00\x00\x00' |
|
2180 | 2182 | ##### revision "mGF,Nm" ##### |
|
2181 | 2183 | 1 sidedata entries |
|
2182 | 2184 | entry-0014 size 4 |
|
2183 | 2185 | '\x00\x00\x00\x00' |
|
2184 | 2186 | ##### revision "mN,GFm" ##### |
|
2185 | 2187 | 1 sidedata entries |
|
2186 | 2188 | entry-0014 size 4 |
|
2187 | 2189 | '\x00\x00\x00\x00' |
|
2188 | 2190 | ##### revision "mAE-change,Km" ##### |
|
2189 | 2191 | 1 sidedata entries |
|
2190 | 2192 | entry-0014 size 4 |
|
2191 | 2193 | '\x00\x00\x00\x00' |
|
2192 | 2194 | ##### revision "mK,AE-change-m" ##### |
|
2193 | 2195 | 1 sidedata entries |
|
2194 | 2196 | entry-0014 size 4 |
|
2195 | 2197 | '\x00\x00\x00\x00' |
|
2196 | 2198 | ##### revision "mEA-change,Jm" ##### |
|
2197 | 2199 | 1 sidedata entries |
|
2198 | 2200 | entry-0014 size 4 |
|
2199 | 2201 | '\x00\x00\x00\x00' |
|
2200 | 2202 | ##### revision "mJ,EA-change-m" ##### |
|
2201 | 2203 | 1 sidedata entries |
|
2202 | 2204 | entry-0014 size 4 |
|
2203 | 2205 | '\x00\x00\x00\x00' |
|
2204 | 2206 | |
|
2205 | 2207 | #endif |
|
2206 | 2208 | |
|
2207 | 2209 | |
|
2208 | 2210 | Test copy information chaining |
|
2209 | 2211 | ============================== |
|
2210 | 2212 | |
|
2211 | 2213 | Check that matching only affect the destination and not intermediate path |
|
2212 | 2214 | ------------------------------------------------------------------------- |
|
2213 | 2215 | |
|
2214 | 2216 | The two status call should give the same value for f |
|
2215 | 2217 | |
|
2216 | 2218 | $ hg status --copies --rev 'desc("i-0")' --rev 'desc("a-2")' |
|
2217 | 2219 | A f |
|
2218 | 2220 | a |
|
2219 | 2221 | A t |
|
2220 | 2222 | p |
|
2221 | 2223 | R a |
|
2222 | 2224 | R p |
|
2223 | 2225 | $ hg status --copies --rev 'desc("i-0")' --rev 'desc("a-2")' f |
|
2224 | 2226 | A f |
|
2225 | 2227 | a (no-changeset no-compatibility !) |
|
2226 | 2228 | |
|
2227 | 2229 | merging with unrelated change does not interfere with the renames |
|
2228 | 2230 | --------------------------------------------------------------- |
|
2229 | 2231 | |
|
2230 | 2232 | - rename on one side |
|
2231 | 2233 | - unrelated change on the other side |
|
2232 | 2234 | |
|
2233 | 2235 | $ hg log -G --rev '::(desc("mABm")+desc("mBAm"))' |
|
2234 | 2236 | o mABm-0 simple merge - A side: multiple renames, B side: unrelated update - the other way |
|
2235 | 2237 | |\ |
|
2236 | 2238 | +---o mBAm-0 simple merge - A side: multiple renames, B side: unrelated update - one way |
|
2237 | 2239 | | |/ |
|
2238 | 2240 | | o b-1: b update |
|
2239 | 2241 | | | |
|
2240 | 2242 | o | a-2: e -move-> f |
|
2241 | 2243 | | | |
|
2242 | 2244 | o | a-1: d -move-> e |
|
2243 | 2245 | |/ |
|
2244 | 2246 | o i-2: c -move-> d, s -move-> t |
|
2245 | 2247 | | |
|
2246 | 2248 | o i-1: a -move-> c, p -move-> s |
|
2247 | 2249 | | |
|
2248 | 2250 | o i-0 initial commit: a b h p q r |
|
2249 | 2251 | |
|
2250 | 2252 | |
|
2251 | 2253 | $ hg status --copies --rev 'desc("b-1")' --rev 'desc("mABm")' |
|
2252 | 2254 | A f |
|
2253 | 2255 | d |
|
2254 | 2256 | R d |
|
2255 | 2257 | $ hg status --copies --rev 'desc("b-1")' --rev 'desc("mBAm")' |
|
2256 | 2258 | A f |
|
2257 | 2259 | d |
|
2258 | 2260 | R d |
|
2259 | 2261 | $ hg status --copies --rev 'desc("a-2")' --rev 'desc("mABm")' |
|
2260 | 2262 | M b |
|
2261 | 2263 | $ hg status --copies --rev 'desc("a-2")' --rev 'desc("mBAm")' |
|
2262 | 2264 | M b |
|
2263 | 2265 | $ hg status --copies --rev 'desc("i-2")' --rev 'desc("mABm")' |
|
2264 | 2266 | M b |
|
2265 | 2267 | A f |
|
2266 | 2268 | d |
|
2267 | 2269 | R d |
|
2268 | 2270 | $ hg status --copies --rev 'desc("i-2")' --rev 'desc("mBAm")' |
|
2269 | 2271 | M b |
|
2270 | 2272 | A f |
|
2271 | 2273 | d |
|
2272 | 2274 | R d |
|
2273 | 2275 | $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mABm")' |
|
2274 | 2276 | M b |
|
2275 | 2277 | A f |
|
2276 | 2278 | a |
|
2277 | 2279 | A t |
|
2278 | 2280 | p |
|
2279 | 2281 | R a |
|
2280 | 2282 | R p |
|
2281 | 2283 | $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mBAm")' |
|
2282 | 2284 | M b |
|
2283 | 2285 | A f |
|
2284 | 2286 | a |
|
2285 | 2287 | A t |
|
2286 | 2288 | p |
|
2287 | 2289 | R a |
|
2288 | 2290 | R p |
|
2289 | 2291 | |
|
2290 | 2292 | merging with the side having a delete |
|
2291 | 2293 | ------------------------------------- |
|
2292 | 2294 | |
|
2293 | 2295 | case summary: |
|
2294 | 2296 | - one with change to an unrelated file |
|
2295 | 2297 | - one deleting the change |
|
2296 | 2298 | and recreate an unrelated file after the merge |
|
2297 | 2299 | |
|
2298 | 2300 | $ hg log -G --rev '::(desc("mCBm")+desc("mBCm"))' |
|
2299 | 2301 | o mCBm-1 re-add d |
|
2300 | 2302 | | |
|
2301 | 2303 | o mCBm-0 simple merge - C side: delete a file with copies history , B side: unrelated update - the other way |
|
2302 | 2304 | |\ |
|
2303 | 2305 | | | o mBCm-1 re-add d |
|
2304 | 2306 | | | | |
|
2305 | 2307 | +---o mBCm-0 simple merge - C side: delete a file with copies history , B side: unrelated update - one way |
|
2306 | 2308 | | |/ |
|
2307 | 2309 | | o c-1 delete d |
|
2308 | 2310 | | | |
|
2309 | 2311 | o | b-1: b update |
|
2310 | 2312 | |/ |
|
2311 | 2313 | o i-2: c -move-> d, s -move-> t |
|
2312 | 2314 | | |
|
2313 | 2315 | o i-1: a -move-> c, p -move-> s |
|
2314 | 2316 | | |
|
2315 | 2317 | o i-0 initial commit: a b h p q r |
|
2316 | 2318 | |
|
2317 | 2319 | - comparing from the merge |
|
2318 | 2320 | |
|
2319 | 2321 | $ hg status --copies --rev 'desc("b-1")' --rev 'desc("mBCm-0")' |
|
2320 | 2322 | R d |
|
2321 | 2323 | $ hg status --copies --rev 'desc("b-1")' --rev 'desc("mCBm-0")' |
|
2322 | 2324 | R d |
|
2323 | 2325 | $ hg status --copies --rev 'desc("c-1")' --rev 'desc("mBCm-0")' |
|
2324 | 2326 | M b |
|
2325 | 2327 | $ hg status --copies --rev 'desc("c-1")' --rev 'desc("mCBm-0")' |
|
2326 | 2328 | M b |
|
2327 | 2329 | $ hg status --copies --rev 'desc("i-2")' --rev 'desc("mBCm-0")' |
|
2328 | 2330 | M b |
|
2329 | 2331 | R d |
|
2330 | 2332 | $ hg status --copies --rev 'desc("i-2")' --rev 'desc("mCBm-0")' |
|
2331 | 2333 | M b |
|
2332 | 2334 | R d |
|
2333 | 2335 | $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mBCm-0")' |
|
2334 | 2336 | M b |
|
2335 | 2337 | A t |
|
2336 | 2338 | p |
|
2337 | 2339 | R a |
|
2338 | 2340 | R p |
|
2339 | 2341 | $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mCBm-0")' |
|
2340 | 2342 | M b |
|
2341 | 2343 | A t |
|
2342 | 2344 | p |
|
2343 | 2345 | R a |
|
2344 | 2346 | R p |
|
2345 | 2347 | |
|
2346 | 2348 | - comparing with the merge children re-adding the file |
|
2347 | 2349 | |
|
2348 | 2350 | $ hg status --copies --rev 'desc("b-1")' --rev 'desc("mBCm-1")' |
|
2349 | 2351 | M d |
|
2350 | 2352 | $ hg status --copies --rev 'desc("b-1")' --rev 'desc("mCBm-1")' |
|
2351 | 2353 | M d |
|
2352 | 2354 | $ hg status --copies --rev 'desc("c-1")' --rev 'desc("mBCm-1")' |
|
2353 | 2355 | M b |
|
2354 | 2356 | A d |
|
2355 | 2357 | $ hg status --copies --rev 'desc("c-1")' --rev 'desc("mCBm-1")' |
|
2356 | 2358 | M b |
|
2357 | 2359 | A d |
|
2358 | 2360 | $ hg status --copies --rev 'desc("i-2")' --rev 'desc("mBCm-1")' |
|
2359 | 2361 | M b |
|
2360 | 2362 | M d |
|
2361 | 2363 | $ hg status --copies --rev 'desc("i-2")' --rev 'desc("mCBm-1")' |
|
2362 | 2364 | M b |
|
2363 | 2365 | M d |
|
2364 | 2366 | $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mBCm-1")' |
|
2365 | 2367 | M b |
|
2366 | 2368 | A d |
|
2367 | 2369 | A t |
|
2368 | 2370 | p |
|
2369 | 2371 | R a |
|
2370 | 2372 | R p |
|
2371 | 2373 | $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mCBm-1")' |
|
2372 | 2374 | M b |
|
2373 | 2375 | A d |
|
2374 | 2376 | A t |
|
2375 | 2377 | p |
|
2376 | 2378 | R a |
|
2377 | 2379 | R p |
|
2378 | 2380 | |
|
2379 | 2381 | Comparing with a merge re-adding the file afterward |
|
2380 | 2382 | --------------------------------------------------- |
|
2381 | 2383 | |
|
2382 | 2384 | Merge: |
|
2383 | 2385 | - one with change to an unrelated file |
|
2384 | 2386 | - one deleting and recreating the change |
|
2385 | 2387 | |
|
2386 | 2388 | $ hg log -G --rev '::(desc("mDBm")+desc("mBDm"))' |
|
2387 | 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 | 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 | 2393 | | o d-2 re-add d |
|
2392 | 2394 | | | |
|
2393 | 2395 | | o d-1 delete d |
|
2394 | 2396 | | | |
|
2395 | 2397 | o | b-1: b update |
|
2396 | 2398 | |/ |
|
2397 | 2399 | o i-2: c -move-> d, s -move-> t |
|
2398 | 2400 | | |
|
2399 | 2401 | o i-1: a -move-> c, p -move-> s |
|
2400 | 2402 | | |
|
2401 | 2403 | o i-0 initial commit: a b h p q r |
|
2402 | 2404 | |
|
2403 | 2405 | $ hg status --copies --rev 'desc("b-1")' --rev 'desc("mBDm-0")' |
|
2404 | 2406 | M d |
|
2405 | 2407 | $ hg status --copies --rev 'desc("b-1")' --rev 'desc("mDBm-0")' |
|
2406 | 2408 | M d |
|
2407 | 2409 | $ hg status --copies --rev 'desc("d-2")' --rev 'desc("mBDm-0")' |
|
2408 | 2410 | M b |
|
2409 | 2411 | $ hg status --copies --rev 'desc("d-2")' --rev 'desc("mDBm-0")' |
|
2410 | 2412 | M b |
|
2411 | 2413 | $ hg status --copies --rev 'desc("i-2")' --rev 'desc("mBDm-0")' |
|
2412 | 2414 | M b |
|
2413 | 2415 | M d |
|
2414 | 2416 | $ hg status --copies --rev 'desc("i-2")' --rev 'desc("mDBm-0")' |
|
2415 | 2417 | M b |
|
2416 | 2418 | M d |
|
2417 | 2419 | |
|
2418 | 2420 | The bugs makes recorded copy is different depending of where we started the merge from since |
|
2419 | 2421 | |
|
2420 | 2422 | $ hg manifest --debug --rev 'desc("mBDm-0")' | grep '644 d' |
|
2421 | 2423 | b004912a8510032a0350a74daa2803dadfb00e12 644 d |
|
2422 | 2424 | $ hg manifest --debug --rev 'desc("mDBm-0")' | grep '644 d' |
|
2423 | 2425 | b004912a8510032a0350a74daa2803dadfb00e12 644 d |
|
2424 | 2426 | |
|
2425 | 2427 | $ hg manifest --debug --rev 'desc("d-2")' | grep '644 d' |
|
2426 | 2428 | b004912a8510032a0350a74daa2803dadfb00e12 644 d |
|
2427 | 2429 | $ hg manifest --debug --rev 'desc("b-1")' | grep '644 d' |
|
2428 | 2430 | d8252ab2e760b0d4e5288fd44cbd15a0fa567e16 644 d (no-changeset !) |
|
2429 | 2431 | ae258f702dfeca05bf9b6a22a97a4b5645570f11 644 d (changeset !) |
|
2430 | 2432 | $ hg debugindex d | head -n 4 | "$PYTHON" ../no-linkrev |
|
2431 | 2433 | rev linkrev nodeid p1 p2 |
|
2432 | 2434 | 0 * d8252ab2e760 000000000000 000000000000 (no-changeset !) |
|
2433 | 2435 | 0 * ae258f702dfe 000000000000 000000000000 (changeset !) |
|
2434 | 2436 | 1 * b004912a8510 000000000000 000000000000 |
|
2435 | 2437 | 2 * 7b79e2fe0c89 000000000000 000000000000 (no-changeset !) |
|
2436 | 2438 | 2 * 5cce88bf349f ae258f702dfe 000000000000 (changeset !) |
|
2437 | 2439 | |
|
2438 | 2440 | Log output should not include a merge commit as it did not happen |
|
2439 | 2441 | |
|
2440 | 2442 | $ hg log -Gfr 'desc("mBDm-0")' d |
|
2441 | 2443 | o d-2 re-add d |
|
2442 | 2444 | | |
|
2443 | 2445 | ~ |
|
2444 | 2446 | |
|
2445 | 2447 | $ hg log -Gfr 'desc("mDBm-0")' d |
|
2446 | 2448 | o d-2 re-add d |
|
2447 | 2449 | | |
|
2448 | 2450 | ~ |
|
2449 | 2451 | |
|
2450 | 2452 | $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mBDm-0")' |
|
2451 | 2453 | M b |
|
2452 | 2454 | A d |
|
2453 | 2455 | A t |
|
2454 | 2456 | p |
|
2455 | 2457 | R a |
|
2456 | 2458 | R p |
|
2457 | 2459 | $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mDBm-0")' |
|
2458 | 2460 | M b |
|
2459 | 2461 | A d |
|
2460 | 2462 | A t |
|
2461 | 2463 | p |
|
2462 | 2464 | R a |
|
2463 | 2465 | R p |
|
2464 | 2466 | |
|
2465 | 2467 | |
|
2466 | 2468 | Comparing with a merge with colliding rename |
|
2467 | 2469 | -------------------------------------------- |
|
2468 | 2470 | |
|
2469 | 2471 | Subcase: new copy information on both side |
|
2470 | 2472 | `````````````````````````````````````````` |
|
2471 | 2473 | |
|
2472 | 2474 | - the "e-" branch renaming b to f (through 'g') |
|
2473 | 2475 | - the "a-" branch renaming d to f (through e) |
|
2474 | 2476 | |
|
2475 | 2477 | $ hg log -G --rev '::(desc("mAEm")+desc("mEAm"))' |
|
2476 | 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 | 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 | 2482 | | o e-2 g -move-> f |
|
2481 | 2483 | | | |
|
2482 | 2484 | | o e-1 b -move-> g |
|
2483 | 2485 | | | |
|
2484 | 2486 | o | a-2: e -move-> f |
|
2485 | 2487 | | | |
|
2486 | 2488 | o | a-1: d -move-> e |
|
2487 | 2489 | |/ |
|
2488 | 2490 | o i-2: c -move-> d, s -move-> t |
|
2489 | 2491 | | |
|
2490 | 2492 | o i-1: a -move-> c, p -move-> s |
|
2491 | 2493 | | |
|
2492 | 2494 | o i-0 initial commit: a b h p q r |
|
2493 | 2495 | |
|
2494 | 2496 | #if no-changeset |
|
2495 | 2497 | $ hg manifest --debug --rev 'desc("mAEm-0")' | grep '644 f' |
|
2496 | 2498 | 2ff93c643948464ee1f871867910ae43a45b0bea 644 f |
|
2497 | 2499 | $ hg manifest --debug --rev 'desc("mEAm-0")' | grep '644 f' |
|
2498 | 2500 | 2ff93c643948464ee1f871867910ae43a45b0bea 644 f |
|
2499 | 2501 | $ hg manifest --debug --rev 'desc("a-2")' | grep '644 f' |
|
2500 | 2502 | b76eb76580df486c3d51d63c5c210d4dd43a8ac7 644 f |
|
2501 | 2503 | $ hg manifest --debug --rev 'desc("e-2")' | grep '644 f' |
|
2502 | 2504 | e8825b386367b29fec957283a80bb47b47483fe1 644 f |
|
2503 | 2505 | $ hg debugindex f | "$PYTHON" ../no-linkrev |
|
2504 | 2506 | rev linkrev nodeid p1 p2 |
|
2505 | 2507 | 0 * b76eb76580df 000000000000 000000000000 |
|
2506 | 2508 | 1 * e8825b386367 000000000000 000000000000 |
|
2507 | 2509 | 2 * 2ff93c643948 b76eb76580df e8825b386367 |
|
2508 | 2510 | 3 * 2f649fba7eb2 b76eb76580df e8825b386367 |
|
2509 | 2511 | 4 * 774e7c1637d5 e8825b386367 b76eb76580df |
|
2510 | 2512 | #else |
|
2511 | 2513 | $ hg manifest --debug --rev 'desc("mAEm-0")' | grep '644 f' |
|
2512 | 2514 | ae258f702dfeca05bf9b6a22a97a4b5645570f11 644 f |
|
2513 | 2515 | $ hg manifest --debug --rev 'desc("mEAm-0")' | grep '644 f' |
|
2514 | 2516 | ae258f702dfeca05bf9b6a22a97a4b5645570f11 644 f |
|
2515 | 2517 | $ hg manifest --debug --rev 'desc("a-2")' | grep '644 f' |
|
2516 | 2518 | ae258f702dfeca05bf9b6a22a97a4b5645570f11 644 f |
|
2517 | 2519 | $ hg manifest --debug --rev 'desc("e-2")' | grep '644 f' |
|
2518 | 2520 | ae258f702dfeca05bf9b6a22a97a4b5645570f11 644 f |
|
2519 | 2521 | $ hg debugindex f | "$PYTHON" ../no-linkrev |
|
2520 | 2522 | rev linkrev nodeid p1 p2 |
|
2521 | 2523 | 0 * ae258f702dfe 000000000000 000000000000 |
|
2522 | 2524 | 1 * d3613c1ec831 ae258f702dfe 000000000000 |
|
2523 | 2525 | 2 * 05e03c868bbc ae258f702dfe 000000000000 |
|
2524 | 2526 | #endif |
|
2525 | 2527 | |
|
2526 | 2528 | # Here the filelog based implementation is not looking at the rename |
|
2527 | 2529 | # information (because the file exist on both side). However the changelog |
|
2528 | 2530 | # based on works fine. We have different output. |
|
2529 | 2531 | |
|
2530 | 2532 | $ hg status --copies --rev 'desc("a-2")' --rev 'desc("mAEm-0")' |
|
2531 | 2533 | M f (no-changeset !) |
|
2532 | 2534 | b (no-filelog no-changeset !) |
|
2533 | 2535 | R b |
|
2534 | 2536 | $ hg status --copies --rev 'desc("a-2")' --rev 'desc("mEAm-0")' |
|
2535 | 2537 | M f (no-changeset !) |
|
2536 | 2538 | b (no-filelog no-changeset !) |
|
2537 | 2539 | R b |
|
2538 | 2540 | $ hg status --copies --rev 'desc("e-2")' --rev 'desc("mAEm-0")' |
|
2539 | 2541 | M f (no-changeset !) |
|
2540 | 2542 | d (no-filelog no-changeset !) |
|
2541 | 2543 | R d |
|
2542 | 2544 | $ hg status --copies --rev 'desc("e-2")' --rev 'desc("mEAm-0")' |
|
2543 | 2545 | M f (no-changeset !) |
|
2544 | 2546 | d (no-filelog no-changeset !) |
|
2545 | 2547 | R d |
|
2546 | 2548 | $ hg status --copies --rev 'desc("i-2")' --rev 'desc("a-2")' |
|
2547 | 2549 | A f |
|
2548 | 2550 | d |
|
2549 | 2551 | R d |
|
2550 | 2552 | $ hg status --copies --rev 'desc("i-2")' --rev 'desc("e-2")' |
|
2551 | 2553 | A f |
|
2552 | 2554 | b |
|
2553 | 2555 | R b |
|
2554 | 2556 | |
|
2555 | 2557 | # From here, we run status against revision where both source file exists. |
|
2556 | 2558 | # |
|
2557 | 2559 | # The filelog based implementation picks an arbitrary side based on revision |
|
2558 | 2560 | # numbers. So the same side "wins" whatever the parents order is. This is |
|
2559 | 2561 | # sub-optimal because depending on revision numbers means the result can be |
|
2560 | 2562 | # different from one repository to the next. |
|
2561 | 2563 | # |
|
2562 | 2564 | # The changeset based algorithm use the parent order to break tie on conflicting |
|
2563 | 2565 | # information and will have a different order depending on who is p1 and p2. |
|
2564 | 2566 | # That order is stable accross repositories. (data from p1 prevails) |
|
2565 | 2567 | |
|
2566 | 2568 | $ hg status --copies --rev 'desc("i-2")' --rev 'desc("mAEm-0")' |
|
2567 | 2569 | A f |
|
2568 | 2570 | d |
|
2569 | 2571 | R b |
|
2570 | 2572 | R d |
|
2571 | 2573 | $ hg status --copies --rev 'desc("i-2")' --rev 'desc("mEAm-0")' |
|
2572 | 2574 | A f |
|
2573 | 2575 | d (filelog !) |
|
2574 | 2576 | b (no-filelog !) |
|
2575 | 2577 | R b |
|
2576 | 2578 | R d |
|
2577 | 2579 | $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mAEm-0")' |
|
2578 | 2580 | A f |
|
2579 | 2581 | a |
|
2580 | 2582 | A t |
|
2581 | 2583 | p |
|
2582 | 2584 | R a |
|
2583 | 2585 | R b |
|
2584 | 2586 | R p |
|
2585 | 2587 | $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mEAm-0")' |
|
2586 | 2588 | A f |
|
2587 | 2589 | a (filelog !) |
|
2588 | 2590 | b (no-filelog !) |
|
2589 | 2591 | A t |
|
2590 | 2592 | p |
|
2591 | 2593 | R a |
|
2592 | 2594 | R b |
|
2593 | 2595 | R p |
|
2594 | 2596 | |
|
2595 | 2597 | |
|
2596 | 2598 | Subcase: existing copy information overwritten on one branch |
|
2597 | 2599 | ```````````````````````````````````````````````````````````` |
|
2598 | 2600 | |
|
2599 | 2601 | Note: |
|
2600 | 2602 | | In this case, one of the merge wrongly record a merge while there is none. |
|
2601 | 2603 | | This lead to bad copy tracing information to be dug up. |
|
2602 | 2604 | |
|
2603 | 2605 | |
|
2604 | 2606 | Merge: |
|
2605 | 2607 | - one with change to an unrelated file (b) |
|
2606 | 2608 | - one overwriting a file (d) with a rename (from h to i to d) |
|
2607 | 2609 | |
|
2608 | 2610 | $ hg log -G --rev '::(desc("mBFm")+desc("mFBm"))' |
|
2609 | 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 | 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 | 2615 | | o f-2: rename i -> d |
|
2614 | 2616 | | | |
|
2615 | 2617 | | o f-1: rename h -> i |
|
2616 | 2618 | | | |
|
2617 | 2619 | o | b-1: b update |
|
2618 | 2620 | |/ |
|
2619 | 2621 | o i-2: c -move-> d, s -move-> t |
|
2620 | 2622 | | |
|
2621 | 2623 | o i-1: a -move-> c, p -move-> s |
|
2622 | 2624 | | |
|
2623 | 2625 | o i-0 initial commit: a b h p q r |
|
2624 | 2626 | |
|
2625 | 2627 | $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mBFm-0")' |
|
2626 | 2628 | M b |
|
2627 | 2629 | A d |
|
2628 | 2630 | h |
|
2629 | 2631 | A t |
|
2630 | 2632 | p |
|
2631 | 2633 | R a |
|
2632 | 2634 | R h |
|
2633 | 2635 | R p |
|
2634 | 2636 | $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mFBm-0")' |
|
2635 | 2637 | M b |
|
2636 | 2638 | A d |
|
2637 | 2639 | h |
|
2638 | 2640 | A t |
|
2639 | 2641 | p |
|
2640 | 2642 | R a |
|
2641 | 2643 | R h |
|
2642 | 2644 | R p |
|
2643 | 2645 | $ hg status --copies --rev 'desc("b-1")' --rev 'desc("mBFm-0")' |
|
2644 | 2646 | M d (no-changeset !) |
|
2645 | 2647 | h (no-filelog no-changeset !) |
|
2646 | 2648 | R h |
|
2647 | 2649 | $ hg status --copies --rev 'desc("f-2")' --rev 'desc("mBFm-0")' |
|
2648 | 2650 | M b |
|
2649 | 2651 | $ hg status --copies --rev 'desc("f-1")' --rev 'desc("mBFm-0")' |
|
2650 | 2652 | M b |
|
2651 | 2653 | M d (no-changeset !) |
|
2652 | 2654 | i (no-filelog no-changeset !) |
|
2653 | 2655 | R i |
|
2654 | 2656 | $ hg status --copies --rev 'desc("b-1")' --rev 'desc("mFBm-0")' |
|
2655 | 2657 | M d (no-changeset !) |
|
2656 | 2658 | h (no-filelog no-changeset !) |
|
2657 | 2659 | R h |
|
2658 | 2660 | $ hg status --copies --rev 'desc("f-2")' --rev 'desc("mFBm-0")' |
|
2659 | 2661 | M b |
|
2660 | 2662 | $ hg status --copies --rev 'desc("f-1")' --rev 'desc("mFBm-0")' |
|
2661 | 2663 | M b |
|
2662 | 2664 | M d (no-changeset !) |
|
2663 | 2665 | i (no-filelog no-changeset !) |
|
2664 | 2666 | R i |
|
2665 | 2667 | |
|
2666 | 2668 | #if no-changeset |
|
2667 | 2669 | $ hg log -Gfr 'desc("mBFm-0")' d |
|
2668 | 2670 | o f-2: rename i -> d |
|
2669 | 2671 | | |
|
2670 | 2672 | o f-1: rename h -> i |
|
2671 | 2673 | : |
|
2672 | 2674 | o i-0 initial commit: a b h p q r |
|
2673 | 2675 | |
|
2674 | 2676 | #else |
|
2675 | 2677 | BROKEN: `hg log --follow <file>` relies on filelog metadata to work |
|
2676 | 2678 | $ hg log -Gfr 'desc("mBFm-0")' d |
|
2677 | 2679 | o i-2: c -move-> d, s -move-> t |
|
2678 | 2680 | | |
|
2679 | 2681 | ~ |
|
2680 | 2682 | #endif |
|
2681 | 2683 | |
|
2682 | 2684 | #if no-changeset |
|
2683 | 2685 | $ hg log -Gfr 'desc("mFBm-0")' d |
|
2684 | 2686 | o f-2: rename i -> d |
|
2685 | 2687 | | |
|
2686 | 2688 | o f-1: rename h -> i |
|
2687 | 2689 | : |
|
2688 | 2690 | o i-0 initial commit: a b h p q r |
|
2689 | 2691 | |
|
2690 | 2692 | #else |
|
2691 | 2693 | BROKEN: `hg log --follow <file>` relies on filelog metadata to work |
|
2692 | 2694 | $ hg log -Gfr 'desc("mFBm-0")' d |
|
2693 | 2695 | o i-2: c -move-> d, s -move-> t |
|
2694 | 2696 | | |
|
2695 | 2697 | ~ |
|
2696 | 2698 | #endif |
|
2697 | 2699 | |
|
2698 | 2700 | |
|
2699 | 2701 | Subcase: existing copy information overwritten on one branch, with different content) |
|
2700 | 2702 | ````````````````````````````````````````````````````````````````````````````````````` |
|
2701 | 2703 | |
|
2702 | 2704 | Merge: |
|
2703 | 2705 | - one with change to an unrelated file (b) |
|
2704 | 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 | 2708 | $ hg log -G --rev '::(desc("mBRm")+desc("mRBm"))' |
|
2707 | 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 | 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 | 2713 | | o r-2: rename t -> x |
|
2712 | 2714 | | | |
|
2713 | 2715 | | o r-1: rename r -> x |
|
2714 | 2716 | | | |
|
2715 | 2717 | o | b-1: b update |
|
2716 | 2718 | |/ |
|
2717 | 2719 | o i-2: c -move-> d, s -move-> t |
|
2718 | 2720 | | |
|
2719 | 2721 | o i-1: a -move-> c, p -move-> s |
|
2720 | 2722 | | |
|
2721 | 2723 | o i-0 initial commit: a b h p q r |
|
2722 | 2724 | |
|
2723 | 2725 | $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mBRm-0")' |
|
2724 | 2726 | M b |
|
2725 | 2727 | A d |
|
2726 | 2728 | a |
|
2727 | 2729 | A t |
|
2728 | 2730 | r |
|
2729 | 2731 | R a |
|
2730 | 2732 | R p |
|
2731 | 2733 | R r |
|
2732 | 2734 | $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mRBm-0")' |
|
2733 | 2735 | M b |
|
2734 | 2736 | A d |
|
2735 | 2737 | a |
|
2736 | 2738 | A t |
|
2737 | 2739 | r |
|
2738 | 2740 | R a |
|
2739 | 2741 | R p |
|
2740 | 2742 | R r |
|
2741 | 2743 | $ hg status --copies --rev 'desc("b-1")' --rev 'desc("mBRm-0")' |
|
2742 | 2744 | M t |
|
2743 | 2745 | r (no-filelog !) |
|
2744 | 2746 | R r |
|
2745 | 2747 | $ hg status --copies --rev 'desc("r-2")' --rev 'desc("mBRm-0")' |
|
2746 | 2748 | M b |
|
2747 | 2749 | $ hg status --copies --rev 'desc("r-1")' --rev 'desc("mBRm-0")' |
|
2748 | 2750 | M b |
|
2749 | 2751 | M t |
|
2750 | 2752 | x (no-filelog !) |
|
2751 | 2753 | R x |
|
2752 | 2754 | $ hg status --copies --rev 'desc("b-1")' --rev 'desc("mRBm-0")' |
|
2753 | 2755 | M t |
|
2754 | 2756 | r (no-filelog !) |
|
2755 | 2757 | R r |
|
2756 | 2758 | $ hg status --copies --rev 'desc("r-2")' --rev 'desc("mRBm-0")' |
|
2757 | 2759 | M b |
|
2758 | 2760 | $ hg status --copies --rev 'desc("r-1")' --rev 'desc("mRBm-0")' |
|
2759 | 2761 | M b |
|
2760 | 2762 | M t |
|
2761 | 2763 | x (no-filelog !) |
|
2762 | 2764 | R x |
|
2763 | 2765 | |
|
2764 | 2766 | #if no-changeset |
|
2765 | 2767 | $ hg log -Gfr 'desc("mBRm-0")' d |
|
2766 | 2768 | o i-2: c -move-> d, s -move-> t |
|
2767 | 2769 | | |
|
2768 | 2770 | o i-1: a -move-> c, p -move-> s |
|
2769 | 2771 | | |
|
2770 | 2772 | o i-0 initial commit: a b h p q r |
|
2771 | 2773 | |
|
2772 | 2774 | #else |
|
2773 | 2775 | BROKEN: `hg log --follow <file>` relies on filelog metadata to work |
|
2774 | 2776 | $ hg log -Gfr 'desc("mBRm-0")' d |
|
2775 | 2777 | o i-2: c -move-> d, s -move-> t |
|
2776 | 2778 | | |
|
2777 | 2779 | ~ |
|
2778 | 2780 | #endif |
|
2779 | 2781 | |
|
2780 | 2782 | #if no-changeset |
|
2781 | 2783 | $ hg log -Gfr 'desc("mRBm-0")' d |
|
2782 | 2784 | o i-2: c -move-> d, s -move-> t |
|
2783 | 2785 | | |
|
2784 | 2786 | o i-1: a -move-> c, p -move-> s |
|
2785 | 2787 | | |
|
2786 | 2788 | o i-0 initial commit: a b h p q r |
|
2787 | 2789 | |
|
2788 | 2790 | #else |
|
2789 | 2791 | BROKEN: `hg log --follow <file>` relies on filelog metadata to work |
|
2790 | 2792 | $ hg log -Gfr 'desc("mRBm-0")' d |
|
2791 | 2793 | o i-2: c -move-> d, s -move-> t |
|
2792 | 2794 | | |
|
2793 | 2795 | ~ |
|
2794 | 2796 | #endif |
|
2795 | 2797 | |
|
2796 | 2798 | Subcase: reset of the copy history on one side |
|
2797 | 2799 | `````````````````````````````````````````````` |
|
2798 | 2800 | |
|
2799 | 2801 | Merge: |
|
2800 | 2802 | - one with change to a file |
|
2801 | 2803 | - one deleting and recreating the file |
|
2802 | 2804 | |
|
2803 | 2805 | Unlike in the 'BD/DB' cases, an actual merge happened here. So we should |
|
2804 | 2806 | consider history and rename on both branch of the merge. |
|
2805 | 2807 | |
|
2806 | 2808 | $ hg log -G --rev '::(desc("mDGm")+desc("mGDm"))' |
|
2807 | 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 | 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 | 2813 | | o g-1: update d |
|
2812 | 2814 | | | |
|
2813 | 2815 | o | d-2 re-add d |
|
2814 | 2816 | | | |
|
2815 | 2817 | o | d-1 delete d |
|
2816 | 2818 | |/ |
|
2817 | 2819 | o i-2: c -move-> d, s -move-> t |
|
2818 | 2820 | | |
|
2819 | 2821 | o i-1: a -move-> c, p -move-> s |
|
2820 | 2822 | | |
|
2821 | 2823 | o i-0 initial commit: a b h p q r |
|
2822 | 2824 | |
|
2823 | 2825 | One side of the merge have a long history with rename. The other side of the |
|
2824 | 2826 | merge point to a new file with a smaller history. Each side is "valid". |
|
2825 | 2827 | |
|
2826 | 2828 | (and again the filelog based algorithm only explore one, with a pick based on |
|
2827 | 2829 | revision numbers) |
|
2828 | 2830 | |
|
2829 | 2831 | $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mDGm-0")' |
|
2830 | 2832 | A d |
|
2831 | 2833 | a (filelog !) |
|
2832 | 2834 | A t |
|
2833 | 2835 | p |
|
2834 | 2836 | R a |
|
2835 | 2837 | R p |
|
2836 | 2838 | $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mGDm-0")' |
|
2837 | 2839 | A d |
|
2838 | 2840 | a |
|
2839 | 2841 | A t |
|
2840 | 2842 | p |
|
2841 | 2843 | R a |
|
2842 | 2844 | R p |
|
2843 | 2845 | $ hg status --copies --rev 'desc("d-2")' --rev 'desc("mDGm-0")' |
|
2844 | 2846 | M d |
|
2845 | 2847 | $ hg status --copies --rev 'desc("d-2")' --rev 'desc("mGDm-0")' |
|
2846 | 2848 | M d |
|
2847 | 2849 | $ hg status --copies --rev 'desc("g-1")' --rev 'desc("mDGm-0")' |
|
2848 | 2850 | M d |
|
2849 | 2851 | $ hg status --copies --rev 'desc("g-1")' --rev 'desc("mGDm-0")' |
|
2850 | 2852 | M d |
|
2851 | 2853 | |
|
2852 | 2854 | #if no-changeset |
|
2853 | 2855 | $ hg log -Gfr 'desc("mDGm-0")' d |
|
2854 | 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 | 2858 | | o g-1: update d |
|
2857 | 2859 | | | |
|
2858 | 2860 | o | d-2 re-add d |
|
2859 | 2861 | |/ |
|
2860 | 2862 | o i-2: c -move-> d, s -move-> t |
|
2861 | 2863 | | |
|
2862 | 2864 | o i-1: a -move-> c, p -move-> s |
|
2863 | 2865 | | |
|
2864 | 2866 | o i-0 initial commit: a b h p q r |
|
2865 | 2867 | |
|
2866 | 2868 | #else |
|
2867 | 2869 | BROKEN: `hg log --follow <file>` relies on filelog metadata to work |
|
2868 | 2870 | $ hg log -Gfr 'desc("mDGm-0")' d |
|
2869 | 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 | 2873 | | o g-1: update d |
|
2872 | 2874 | | | |
|
2873 | 2875 | o | d-2 re-add d |
|
2874 | 2876 | |/ |
|
2875 | 2877 | o i-2: c -move-> d, s -move-> t |
|
2876 | 2878 | | |
|
2877 | 2879 | ~ |
|
2878 | 2880 | #endif |
|
2879 | 2881 | |
|
2880 | 2882 | |
|
2881 | 2883 | #if no-changeset |
|
2882 | 2884 | $ hg log -Gfr 'desc("mDGm-0")' d |
|
2883 | 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 | 2887 | | o g-1: update d |
|
2886 | 2888 | | | |
|
2887 | 2889 | o | d-2 re-add d |
|
2888 | 2890 | |/ |
|
2889 | 2891 | o i-2: c -move-> d, s -move-> t |
|
2890 | 2892 | | |
|
2891 | 2893 | o i-1: a -move-> c, p -move-> s |
|
2892 | 2894 | | |
|
2893 | 2895 | o i-0 initial commit: a b h p q r |
|
2894 | 2896 | |
|
2895 | 2897 | #else |
|
2896 | 2898 | BROKEN: `hg log --follow <file>` relies on filelog metadata to work |
|
2897 | 2899 | $ hg log -Gfr 'desc("mDGm-0")' d |
|
2898 | 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 | 2902 | | o g-1: update d |
|
2901 | 2903 | | | |
|
2902 | 2904 | o | d-2 re-add d |
|
2903 | 2905 | |/ |
|
2904 | 2906 | o i-2: c -move-> d, s -move-> t |
|
2905 | 2907 | | |
|
2906 | 2908 | ~ |
|
2907 | 2909 | #endif |
|
2908 | 2910 | |
|
2909 | 2911 | Subcase: merging a change to a file with a "copy overwrite" to that file from another branch |
|
2910 | 2912 | ```````````````````````````````````````````````````````````````````````````````````````````` |
|
2911 | 2913 | |
|
2912 | 2914 | Merge: |
|
2913 | 2915 | - one with change to a file (d) |
|
2914 | 2916 | - one overwriting that file with a rename (from h to i, to d) |
|
2915 | 2917 | |
|
2916 | 2918 | This case is similar to BF/FB, but an actual merge happens, so both side of the |
|
2917 | 2919 | history are relevant. |
|
2918 | 2920 | |
|
2919 | 2921 | |
|
2920 | 2922 | $ hg log -G --rev '::(desc("mGFm")+desc("mFGm"))' |
|
2921 | 2923 | o mGFm-0 merge - G side: content change, F side: copy overwrite, no content change - the other way |
|
2922 | 2924 | |\ |
|
2923 | 2925 | +---o mFGm-0 merge - G side: content change, F side: copy overwrite, no content change - one way |
|
2924 | 2926 | | |/ |
|
2925 | 2927 | | o g-1: update d |
|
2926 | 2928 | | | |
|
2927 | 2929 | o | f-2: rename i -> d |
|
2928 | 2930 | | | |
|
2929 | 2931 | o | f-1: rename h -> i |
|
2930 | 2932 | |/ |
|
2931 | 2933 | o i-2: c -move-> d, s -move-> t |
|
2932 | 2934 | | |
|
2933 | 2935 | o i-1: a -move-> c, p -move-> s |
|
2934 | 2936 | | |
|
2935 | 2937 | o i-0 initial commit: a b h p q r |
|
2936 | 2938 | |
|
2937 | 2939 | |
|
2938 | 2940 | Note: |
|
2939 | 2941 | | In this case, the merge get conflicting information since on one side we have |
|
2940 | 2942 | | "a -> c -> d". and one the other one we have "h -> i -> d". |
|
2941 | 2943 | | |
|
2942 | 2944 | | The current code arbitrarily pick one side depending the ordering of the merged hash: |
|
2943 | 2945 | |
|
2944 | 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 | 2948 | Details on this hash ordering pick: |
|
2947 | 2949 | |
|
2948 | 2950 | $ hg manifest --debug 'desc("g-1")' | egrep 'd$' |
|
2949 | 2951 | 17ec97e605773eb44a117d1136b3849bcdc1924f 644 d (no-changeset !) |
|
2950 | 2952 | 5cce88bf349f7c742bb440f2c53f81db9c294279 644 d (changeset !) |
|
2951 | 2953 | $ hg status --copies --rev 'desc("i-0")' --rev 'desc("g-1")' d |
|
2952 | 2954 | A d |
|
2953 | 2955 | a (no-changeset no-compatibility !) |
|
2954 | 2956 | |
|
2955 | 2957 | $ hg manifest --debug 'desc("f-2")' | egrep 'd$' |
|
2956 | 2958 | 7b79e2fe0c8924e0e598a82f048a7b024afa4d96 644 d (no-changeset !) |
|
2957 | 2959 | ae258f702dfeca05bf9b6a22a97a4b5645570f11 644 d (changeset !) |
|
2958 | 2960 | $ hg status --copies --rev 'desc("i-0")' --rev 'desc("f-2")' d |
|
2959 | 2961 | A d |
|
2960 | 2962 | h (no-changeset no-compatibility !) |
|
2961 | 2963 | |
|
2962 | 2964 | Copy tracing data on the resulting merge: |
|
2963 | 2965 | |
|
2964 | 2966 | $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mFGm-0")' |
|
2965 | 2967 | A d |
|
2966 | 2968 | h (no-filelog !) |
|
2967 | 2969 | a (filelog !) |
|
2968 | 2970 | A t |
|
2969 | 2971 | p |
|
2970 | 2972 | R a |
|
2971 | 2973 | R h |
|
2972 | 2974 | R p |
|
2973 | 2975 | $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mGFm-0")' |
|
2974 | 2976 | A d |
|
2975 | 2977 | a (no-changeset !) |
|
2976 | 2978 | h (changeset !) |
|
2977 | 2979 | A t |
|
2978 | 2980 | p |
|
2979 | 2981 | R a |
|
2980 | 2982 | R h |
|
2981 | 2983 | R p |
|
2982 | 2984 | $ hg status --copies --rev 'desc("f-2")' --rev 'desc("mFGm-0")' |
|
2983 | 2985 | M d |
|
2984 | 2986 | $ hg status --copies --rev 'desc("f-2")' --rev 'desc("mGFm-0")' |
|
2985 | 2987 | M d |
|
2986 | 2988 | $ hg status --copies --rev 'desc("f-1")' --rev 'desc("mFGm-0")' |
|
2987 | 2989 | M d |
|
2988 | 2990 | i (no-filelog !) |
|
2989 | 2991 | R i |
|
2990 | 2992 | $ hg status --copies --rev 'desc("f-1")' --rev 'desc("mGFm-0")' |
|
2991 | 2993 | M d |
|
2992 | 2994 | i (no-filelog !) |
|
2993 | 2995 | R i |
|
2994 | 2996 | $ hg status --copies --rev 'desc("g-1")' --rev 'desc("mFGm-0")' |
|
2995 | 2997 | M d (no-changeset !) |
|
2996 | 2998 | h (no-filelog no-changeset !) |
|
2997 | 2999 | R h |
|
2998 | 3000 | $ hg status --copies --rev 'desc("g-1")' --rev 'desc("mGFm-0")' |
|
2999 | 3001 | M d (no-changeset !) |
|
3000 | 3002 | h (no-filelog no-changeset !) |
|
3001 | 3003 | R h |
|
3002 | 3004 | |
|
3003 | 3005 | #if no-changeset |
|
3004 | 3006 | $ hg log -Gfr 'desc("mFGm-0")' d |
|
3005 | 3007 | o mFGm-0 merge - G side: content change, F side: copy overwrite, no content change - one way |
|
3006 | 3008 | |\ |
|
3007 | 3009 | | o g-1: update d |
|
3008 | 3010 | | | |
|
3009 | 3011 | o | f-2: rename i -> d |
|
3010 | 3012 | | | |
|
3011 | 3013 | o | f-1: rename h -> i |
|
3012 | 3014 | |/ |
|
3013 | 3015 | o i-2: c -move-> d, s -move-> t |
|
3014 | 3016 | | |
|
3015 | 3017 | o i-1: a -move-> c, p -move-> s |
|
3016 | 3018 | | |
|
3017 | 3019 | o i-0 initial commit: a b h p q r |
|
3018 | 3020 | |
|
3019 | 3021 | #else |
|
3020 | 3022 | BROKEN: `hg log --follow <file>` relies on filelog metadata to work |
|
3021 | 3023 | $ hg log -Gfr 'desc("mFGm-0")' d |
|
3022 | 3024 | o g-1: update d |
|
3023 | 3025 | | |
|
3024 | 3026 | o i-2: c -move-> d, s -move-> t |
|
3025 | 3027 | | |
|
3026 | 3028 | ~ |
|
3027 | 3029 | #endif |
|
3028 | 3030 | |
|
3029 | 3031 | #if no-changeset |
|
3030 | 3032 | $ hg log -Gfr 'desc("mGFm-0")' d |
|
3031 | 3033 | o mGFm-0 merge - G side: content change, F side: copy overwrite, no content change - the other way |
|
3032 | 3034 | |\ |
|
3033 | 3035 | | o g-1: update d |
|
3034 | 3036 | | | |
|
3035 | 3037 | o | f-2: rename i -> d |
|
3036 | 3038 | | | |
|
3037 | 3039 | o | f-1: rename h -> i |
|
3038 | 3040 | |/ |
|
3039 | 3041 | o i-2: c -move-> d, s -move-> t |
|
3040 | 3042 | | |
|
3041 | 3043 | o i-1: a -move-> c, p -move-> s |
|
3042 | 3044 | | |
|
3043 | 3045 | o i-0 initial commit: a b h p q r |
|
3044 | 3046 | |
|
3045 | 3047 | #else |
|
3046 | 3048 | BROKEN: `hg log --follow <file>` relies on filelog metadata to work |
|
3047 | 3049 | $ hg log -Gfr 'desc("mGFm-0")' d |
|
3048 | 3050 | o g-1: update d |
|
3049 | 3051 | | |
|
3050 | 3052 | o i-2: c -move-> d, s -move-> t |
|
3051 | 3053 | | |
|
3052 | 3054 | ~ |
|
3053 | 3055 | #endif |
|
3054 | 3056 | |
|
3055 | 3057 | Subcase: new copy information on both side with an actual merge happening |
|
3056 | 3058 | ````````````````````````````````````````````````````````````````````````` |
|
3057 | 3059 | |
|
3058 | 3060 | - the "p-" branch renaming 't' to 'v' (through 'u') |
|
3059 | 3061 | - the "q-" branch renaming 'r' to 'v' (through 'w') |
|
3060 | 3062 | |
|
3061 | 3063 | |
|
3062 | 3064 | $ hg log -G --rev '::(desc("mPQm")+desc("mQPm"))' |
|
3063 | 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 | 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 | 3069 | | o q-2 w -move-> v |
|
3068 | 3070 | | | |
|
3069 | 3071 | | o q-1 r -move-> w |
|
3070 | 3072 | | | |
|
3071 | 3073 | o | p-2: u -move-> v |
|
3072 | 3074 | | | |
|
3073 | 3075 | o | p-1: t -move-> u |
|
3074 | 3076 | |/ |
|
3075 | 3077 | o i-2: c -move-> d, s -move-> t |
|
3076 | 3078 | | |
|
3077 | 3079 | o i-1: a -move-> c, p -move-> s |
|
3078 | 3080 | | |
|
3079 | 3081 | o i-0 initial commit: a b h p q r |
|
3080 | 3082 | |
|
3081 | 3083 | |
|
3082 | 3084 | #if no-changeset |
|
3083 | 3085 | $ hg manifest --debug --rev 'desc("mPQm-0")' | grep '644 v' |
|
3084 | 3086 | 0946c662ef16e4e67397fd717389eb6693d41749 644 v |
|
3085 | 3087 | $ hg manifest --debug --rev 'desc("mQPm-0")' | grep '644 v' |
|
3086 | 3088 | 0db3aad7fcc1ec27fab57060e327b9e864ea0cc9 644 v |
|
3087 | 3089 | $ hg manifest --debug --rev 'desc("p-2")' | grep '644 v' |
|
3088 | 3090 | 3f91841cd75cadc9a1f1b4e7c1aa6d411f76032e 644 v |
|
3089 | 3091 | $ hg manifest --debug --rev 'desc("q-2")' | grep '644 v' |
|
3090 | 3092 | c43c088b811fd27983c0a9aadf44f3343cd4cd7e 644 v |
|
3091 | 3093 | $ hg debugindex v | "$PYTHON" ../no-linkrev |
|
3092 | 3094 | rev linkrev nodeid p1 p2 |
|
3093 | 3095 | 0 * 3f91841cd75c 000000000000 000000000000 |
|
3094 | 3096 | 1 * c43c088b811f 000000000000 000000000000 |
|
3095 | 3097 | 2 * 0946c662ef16 3f91841cd75c c43c088b811f |
|
3096 | 3098 | 3 * 0db3aad7fcc1 c43c088b811f 3f91841cd75c |
|
3097 | 3099 | #else |
|
3098 | 3100 | $ hg manifest --debug --rev 'desc("mPQm-0")' | grep '644 v' |
|
3099 | 3101 | 65fde9f6e4d4da23b3f610e07b53673ea9541d75 644 v |
|
3100 | 3102 | $ hg manifest --debug --rev 'desc("mQPm-0")' | grep '644 v' |
|
3101 | 3103 | a098dda6413aecf154eefc976afc38b295acb7e5 644 v |
|
3102 | 3104 | $ hg manifest --debug --rev 'desc("p-2")' | grep '644 v' |
|
3103 | 3105 | 5aed6a8dbff0301328c08360d24354d3d064cf0d 644 v |
|
3104 | 3106 | $ hg manifest --debug --rev 'desc("q-2")' | grep '644 v' |
|
3105 | 3107 | a38b2fa170219750dac9bc7d19df831f213ba708 644 v |
|
3106 | 3108 | $ hg debugindex v | "$PYTHON" ../no-linkrev |
|
3107 | 3109 | rev linkrev nodeid p1 p2 |
|
3108 | 3110 | 0 * 5aed6a8dbff0 000000000000 000000000000 |
|
3109 | 3111 | 1 * a38b2fa17021 000000000000 000000000000 |
|
3110 | 3112 | 2 * 65fde9f6e4d4 5aed6a8dbff0 a38b2fa17021 |
|
3111 | 3113 | 3 * a098dda6413a a38b2fa17021 5aed6a8dbff0 |
|
3112 | 3114 | #endif |
|
3113 | 3115 | |
|
3114 | 3116 | # Here the filelog based implementation is not looking at the rename |
|
3115 | 3117 | # information (because the file exist on both side). However the changelog |
|
3116 | 3118 | # based on works fine. We have different output. |
|
3117 | 3119 | |
|
3118 | 3120 | $ hg status --copies --rev 'desc("p-2")' --rev 'desc("mPQm-0")' |
|
3119 | 3121 | M v |
|
3120 | 3122 | r (no-filelog !) |
|
3121 | 3123 | R r |
|
3122 | 3124 | $ hg status --copies --rev 'desc("p-2")' --rev 'desc("mQPm-0")' |
|
3123 | 3125 | M v |
|
3124 | 3126 | r (no-filelog !) |
|
3125 | 3127 | R r |
|
3126 | 3128 | $ hg status --copies --rev 'desc("q-2")' --rev 'desc("mPQm-0")' |
|
3127 | 3129 | M v |
|
3128 | 3130 | t (no-filelog !) |
|
3129 | 3131 | R t |
|
3130 | 3132 | $ hg status --copies --rev 'desc("q-2")' --rev 'desc("mQPm-0")' |
|
3131 | 3133 | M v |
|
3132 | 3134 | t (no-filelog !) |
|
3133 | 3135 | R t |
|
3134 | 3136 | $ hg status --copies --rev 'desc("i-2")' --rev 'desc("p-2")' |
|
3135 | 3137 | A v |
|
3136 | 3138 | t |
|
3137 | 3139 | R t |
|
3138 | 3140 | $ hg status --copies --rev 'desc("i-2")' --rev 'desc("q-2")' |
|
3139 | 3141 | A v |
|
3140 | 3142 | r |
|
3141 | 3143 | R r |
|
3142 | 3144 | |
|
3143 | 3145 | # From here, we run status against revision where both source file exists. |
|
3144 | 3146 | # |
|
3145 | 3147 | # The filelog based implementation picks an arbitrary side based on revision |
|
3146 | 3148 | # numbers. So the same side "wins" whatever the parents order is. This is |
|
3147 | 3149 | # sub-optimal because depending on revision numbers means the result can be |
|
3148 | 3150 | # different from one repository to the next. |
|
3149 | 3151 | # |
|
3150 | 3152 | # The changeset based algorithm use the parent order to break tie on conflicting |
|
3151 | 3153 | # information and will have a different order depending on who is p1 and p2. |
|
3152 | 3154 | # That order is stable accross repositories. (data from p1 prevails) |
|
3153 | 3155 | |
|
3154 | 3156 | $ hg status --copies --rev 'desc("i-2")' --rev 'desc("mPQm-0")' |
|
3155 | 3157 | A v |
|
3156 | 3158 | t |
|
3157 | 3159 | R r |
|
3158 | 3160 | R t |
|
3159 | 3161 | $ hg status --copies --rev 'desc("i-2")' --rev 'desc("mQPm-0")' |
|
3160 | 3162 | A v |
|
3161 | 3163 | t (filelog !) |
|
3162 | 3164 | r (no-filelog !) |
|
3163 | 3165 | R r |
|
3164 | 3166 | R t |
|
3165 | 3167 | $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mPQm-0")' |
|
3166 | 3168 | A d |
|
3167 | 3169 | a |
|
3168 | 3170 | A v |
|
3169 | 3171 | r (filelog !) |
|
3170 | 3172 | p (no-filelog !) |
|
3171 | 3173 | R a |
|
3172 | 3174 | R p |
|
3173 | 3175 | R r |
|
3174 | 3176 | $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mQPm-0")' |
|
3175 | 3177 | A d |
|
3176 | 3178 | a |
|
3177 | 3179 | A v |
|
3178 | 3180 | r |
|
3179 | 3181 | R a |
|
3180 | 3182 | R p |
|
3181 | 3183 | R r |
|
3182 | 3184 | |
|
3183 | 3185 | |
|
3184 | 3186 | Comparing with merging with a deletion (and keeping the file) |
|
3185 | 3187 | ------------------------------------------------------------- |
|
3186 | 3188 | |
|
3187 | 3189 | Merge: |
|
3188 | 3190 | - one removing a file (d) |
|
3189 | 3191 | - one updating that file |
|
3190 | 3192 | - the merge keep the modified version of the file (canceling the delete) |
|
3191 | 3193 | |
|
3192 | 3194 | In this case, the file keep on living after the merge. So we should not drop its |
|
3193 | 3195 | copy tracing chain. |
|
3194 | 3196 | |
|
3195 | 3197 | $ hg log -G --rev '::(desc("mCGm")+desc("mGCm"))' |
|
3196 | 3198 | o mGCm-0 merge updated/deleted - revive the file (updated content) - the other way |
|
3197 | 3199 | |\ |
|
3198 | 3200 | +---o mCGm-0 merge updated/deleted - revive the file (updated content) - one way |
|
3199 | 3201 | | |/ |
|
3200 | 3202 | | o g-1: update d |
|
3201 | 3203 | | | |
|
3202 | 3204 | o | c-1 delete d |
|
3203 | 3205 | |/ |
|
3204 | 3206 | o i-2: c -move-> d, s -move-> t |
|
3205 | 3207 | | |
|
3206 | 3208 | o i-1: a -move-> c, p -move-> s |
|
3207 | 3209 | | |
|
3208 | 3210 | o i-0 initial commit: a b h p q r |
|
3209 | 3211 | |
|
3210 | 3212 | |
|
3211 | 3213 | 'a' is the copy source of 'd' |
|
3212 | 3214 | |
|
3213 | 3215 | $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mCGm-0")' |
|
3214 | 3216 | A d |
|
3215 | 3217 | a (no-compatibility no-changeset !) |
|
3216 | 3218 | A t |
|
3217 | 3219 | p |
|
3218 | 3220 | R a |
|
3219 | 3221 | R p |
|
3220 | 3222 | $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mGCm-0")' |
|
3221 | 3223 | A d |
|
3222 | 3224 | a (no-compatibility no-changeset !) |
|
3223 | 3225 | A t |
|
3224 | 3226 | p |
|
3225 | 3227 | R a |
|
3226 | 3228 | R p |
|
3227 | 3229 | $ hg status --copies --rev 'desc("c-1")' --rev 'desc("mCGm-0")' |
|
3228 | 3230 | A d |
|
3229 | 3231 | $ hg status --copies --rev 'desc("c-1")' --rev 'desc("mGCm-0")' |
|
3230 | 3232 | A d |
|
3231 | 3233 | $ hg status --copies --rev 'desc("g-1")' --rev 'desc("mCGm-0")' |
|
3232 | 3234 | $ hg status --copies --rev 'desc("g-1")' --rev 'desc("mGCm-0")' |
|
3233 | 3235 | |
|
3234 | 3236 | |
|
3235 | 3237 | Comparing with merge restoring an untouched deleted file |
|
3236 | 3238 | -------------------------------------------------------- |
|
3237 | 3239 | |
|
3238 | 3240 | Merge: |
|
3239 | 3241 | - one removing a file (d) |
|
3240 | 3242 | - one leaving the file untouched |
|
3241 | 3243 | - the merge actively restore the file to the same content. |
|
3242 | 3244 | |
|
3243 | 3245 | In this case, the file keep on living after the merge. So we should not drop its |
|
3244 | 3246 | copy tracing chain. |
|
3245 | 3247 | |
|
3246 | 3248 | $ hg log -G --rev '::(desc("mCB-revert-m")+desc("mBC-revert-m"))' |
|
3247 | 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 | 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 | 3253 | | o c-1 delete d |
|
3252 | 3254 | | | |
|
3253 | 3255 | o | b-1: b update |
|
3254 | 3256 | |/ |
|
3255 | 3257 | o i-2: c -move-> d, s -move-> t |
|
3256 | 3258 | | |
|
3257 | 3259 | o i-1: a -move-> c, p -move-> s |
|
3258 | 3260 | | |
|
3259 | 3261 | o i-0 initial commit: a b h p q r |
|
3260 | 3262 | |
|
3261 | 3263 | |
|
3262 | 3264 | 'a' is the the copy source of 'd' |
|
3263 | 3265 | |
|
3264 | 3266 | $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mCB-revert-m-0")' |
|
3265 | 3267 | M b |
|
3266 | 3268 | A d |
|
3267 | 3269 | a (no-compatibility no-changeset !) |
|
3268 | 3270 | A t |
|
3269 | 3271 | p |
|
3270 | 3272 | R a |
|
3271 | 3273 | R p |
|
3272 | 3274 | $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mBC-revert-m-0")' |
|
3273 | 3275 | M b |
|
3274 | 3276 | A d |
|
3275 | 3277 | a (no-compatibility no-changeset !) |
|
3276 | 3278 | A t |
|
3277 | 3279 | p |
|
3278 | 3280 | R a |
|
3279 | 3281 | R p |
|
3280 | 3282 | $ hg status --copies --rev 'desc("c-1")' --rev 'desc("mCB-revert-m-0")' |
|
3281 | 3283 | M b |
|
3282 | 3284 | A d |
|
3283 | 3285 | $ hg status --copies --rev 'desc("c-1")' --rev 'desc("mBC-revert-m-0")' |
|
3284 | 3286 | M b |
|
3285 | 3287 | A d |
|
3286 | 3288 | $ hg status --copies --rev 'desc("b-1")' --rev 'desc("mCB-revert-m-0")' |
|
3287 | 3289 | $ hg status --copies --rev 'desc("b-1")' --rev 'desc("mBC-revert-m-0")' |
|
3288 | 3290 | |
|
3289 | 3291 | |
|
3290 | 3292 | Merging a branch where a rename was deleted with a branch where the same file was renamed |
|
3291 | 3293 | ------------------------------------------------------------------------------------------ |
|
3292 | 3294 | |
|
3293 | 3295 | Create a "conflicting" merge where `d` get removed on one branch before its |
|
3294 | 3296 | rename information actually conflict with the other branch. |
|
3295 | 3297 | |
|
3296 | 3298 | (the copy information from the branch that was not deleted should win). |
|
3297 | 3299 | |
|
3298 | 3300 | $ hg log -G --rev '::(desc("mCH-delete-before-conflict-m")+desc("mHC-delete-before-conflict-m"))' |
|
3299 | 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 | 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 | 3305 | | o h-1: b -(move)-> d |
|
3304 | 3306 | | | |
|
3305 | 3307 | o | c-1 delete d |
|
3306 | 3308 | | | |
|
3307 | 3309 | o | i-2: c -move-> d, s -move-> t |
|
3308 | 3310 | | | |
|
3309 | 3311 | o | i-1: a -move-> c, p -move-> s |
|
3310 | 3312 | |/ |
|
3311 | 3313 | o i-0 initial commit: a b h p q r |
|
3312 | 3314 | |
|
3313 | 3315 | |
|
3314 | 3316 | $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mCH-delete-before-conflict-m")' |
|
3315 | 3317 | A d |
|
3316 | 3318 | b (no-compatibility no-changeset !) |
|
3317 | 3319 | A t |
|
3318 | 3320 | p |
|
3319 | 3321 | R a |
|
3320 | 3322 | R b |
|
3321 | 3323 | R p |
|
3322 | 3324 | $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mHC-delete-before-conflict-m")' |
|
3323 | 3325 | A d |
|
3324 | 3326 | b |
|
3325 | 3327 | A t |
|
3326 | 3328 | p |
|
3327 | 3329 | R a |
|
3328 | 3330 | R b |
|
3329 | 3331 | R p |
|
3330 | 3332 | $ hg status --copies --rev 'desc("c-1")' --rev 'desc("mCH-delete-before-conflict-m")' |
|
3331 | 3333 | A d |
|
3332 | 3334 | b |
|
3333 | 3335 | R b |
|
3334 | 3336 | $ hg status --copies --rev 'desc("c-1")' --rev 'desc("mHC-delete-before-conflict-m")' |
|
3335 | 3337 | A d |
|
3336 | 3338 | b |
|
3337 | 3339 | R b |
|
3338 | 3340 | $ hg status --copies --rev 'desc("h-1")' --rev 'desc("mCH-delete-before-conflict-m")' |
|
3339 | 3341 | A t |
|
3340 | 3342 | p |
|
3341 | 3343 | R a |
|
3342 | 3344 | R p |
|
3343 | 3345 | $ hg status --copies --rev 'desc("h-1")' --rev 'desc("mHC-delete-before-conflict-m")' |
|
3344 | 3346 | A t |
|
3345 | 3347 | p |
|
3346 | 3348 | R a |
|
3347 | 3349 | R p |
|
3348 | 3350 | |
|
3349 | 3351 | Variant of previous with extra changes introduced by the merge |
|
3350 | 3352 | -------------------------------------------------------------- |
|
3351 | 3353 | |
|
3352 | 3354 | (see case declaration for details) |
|
3353 | 3355 | |
|
3354 | 3356 | Subcase: merge has same initial content on both side, but merge introduced a change |
|
3355 | 3357 | ``````````````````````````````````````````````````````````````````````````````````` |
|
3356 | 3358 | |
|
3357 | 3359 | - the "e-" branch renaming b to f (through 'g') |
|
3358 | 3360 | - the "a-" branch renaming d to f (through e) |
|
3359 | 3361 | - the merge add new change to b |
|
3360 | 3362 | |
|
3361 | 3363 | $ hg log -G --rev '::(desc("mAE-change-m")+desc("mEA-change-m"))' |
|
3362 | 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 | 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 | 3368 | | o e-2 g -move-> f |
|
3367 | 3369 | | | |
|
3368 | 3370 | | o e-1 b -move-> g |
|
3369 | 3371 | | | |
|
3370 | 3372 | o | a-2: e -move-> f |
|
3371 | 3373 | | | |
|
3372 | 3374 | o | a-1: d -move-> e |
|
3373 | 3375 | |/ |
|
3374 | 3376 | o i-2: c -move-> d, s -move-> t |
|
3375 | 3377 | | |
|
3376 | 3378 | o i-1: a -move-> c, p -move-> s |
|
3377 | 3379 | | |
|
3378 | 3380 | o i-0 initial commit: a b h p q r |
|
3379 | 3381 | |
|
3380 | 3382 | #if no-changeset |
|
3381 | 3383 | $ hg manifest --debug --rev 'desc("mAE-change-m-0")' | grep '644 f' |
|
3382 | 3384 | 2f649fba7eb284e720d02b61f0546fcef694c045 644 f |
|
3383 | 3385 | $ hg manifest --debug --rev 'desc("mEA-change-m-0")' | grep '644 f' |
|
3384 | 3386 | 774e7c1637d536b99e2d8ef16fd731f87a82bd09 644 f |
|
3385 | 3387 | $ hg manifest --debug --rev 'desc("a-2")' | grep '644 f' |
|
3386 | 3388 | b76eb76580df486c3d51d63c5c210d4dd43a8ac7 644 f |
|
3387 | 3389 | $ hg manifest --debug --rev 'desc("e-2")' | grep '644 f' |
|
3388 | 3390 | e8825b386367b29fec957283a80bb47b47483fe1 644 f |
|
3389 | 3391 | $ hg debugindex f | "$PYTHON" ../no-linkrev |
|
3390 | 3392 | rev linkrev nodeid p1 p2 |
|
3391 | 3393 | 0 * b76eb76580df 000000000000 000000000000 |
|
3392 | 3394 | 1 * e8825b386367 000000000000 000000000000 |
|
3393 | 3395 | 2 * 2ff93c643948 b76eb76580df e8825b386367 |
|
3394 | 3396 | 3 * 2f649fba7eb2 b76eb76580df e8825b386367 |
|
3395 | 3397 | 4 * 774e7c1637d5 e8825b386367 b76eb76580df |
|
3396 | 3398 | #else |
|
3397 | 3399 | $ hg manifest --debug --rev 'desc("mAE-change-m-0")' | grep '644 f' |
|
3398 | 3400 | d3613c1ec8310a812ac4268fd853ac576b6caea5 644 f |
|
3399 | 3401 | $ hg manifest --debug --rev 'desc("mEA-change-m-0")' | grep '644 f' |
|
3400 | 3402 | 05e03c868bbcab4a649cb33a238d7aa07398a469 644 f |
|
3401 | 3403 | $ hg manifest --debug --rev 'desc("a-2")' | grep '644 f' |
|
3402 | 3404 | ae258f702dfeca05bf9b6a22a97a4b5645570f11 644 f |
|
3403 | 3405 | $ hg manifest --debug --rev 'desc("e-2")' | grep '644 f' |
|
3404 | 3406 | ae258f702dfeca05bf9b6a22a97a4b5645570f11 644 f |
|
3405 | 3407 | $ hg debugindex f | "$PYTHON" ../no-linkrev |
|
3406 | 3408 | rev linkrev nodeid p1 p2 |
|
3407 | 3409 | 0 * ae258f702dfe 000000000000 000000000000 |
|
3408 | 3410 | 1 * d3613c1ec831 ae258f702dfe 000000000000 |
|
3409 | 3411 | 2 * 05e03c868bbc ae258f702dfe 000000000000 |
|
3410 | 3412 | #endif |
|
3411 | 3413 | |
|
3412 | 3414 | # Here the filelog based implementation is not looking at the rename |
|
3413 | 3415 | # information (because the file exist on both side). However the changelog |
|
3414 | 3416 | # based on works fine. We have different output. |
|
3415 | 3417 | |
|
3416 | 3418 | $ hg status --copies --rev 'desc("a-2")' --rev 'desc("mAE-change-m-0")' |
|
3417 | 3419 | M f |
|
3418 | 3420 | b (no-filelog !) |
|
3419 | 3421 | R b |
|
3420 | 3422 | $ hg status --copies --rev 'desc("a-2")' --rev 'desc("mEA-change-m-0")' |
|
3421 | 3423 | M f |
|
3422 | 3424 | b (no-filelog !) |
|
3423 | 3425 | R b |
|
3424 | 3426 | $ hg status --copies --rev 'desc("e-2")' --rev 'desc("mAE-change-m-0")' |
|
3425 | 3427 | M f |
|
3426 | 3428 | d (no-filelog !) |
|
3427 | 3429 | R d |
|
3428 | 3430 | $ hg status --copies --rev 'desc("e-2")' --rev 'desc("mEA-change-m-0")' |
|
3429 | 3431 | M f |
|
3430 | 3432 | d (no-filelog !) |
|
3431 | 3433 | R d |
|
3432 | 3434 | $ hg status --copies --rev 'desc("i-2")' --rev 'desc("a-2")' |
|
3433 | 3435 | A f |
|
3434 | 3436 | d |
|
3435 | 3437 | R d |
|
3436 | 3438 | $ hg status --copies --rev 'desc("i-2")' --rev 'desc("e-2")' |
|
3437 | 3439 | A f |
|
3438 | 3440 | b |
|
3439 | 3441 | R b |
|
3440 | 3442 | |
|
3441 | 3443 | # From here, we run status against revision where both source file exists. |
|
3442 | 3444 | # |
|
3443 | 3445 | # The filelog based implementation picks an arbitrary side based on revision |
|
3444 | 3446 | # numbers. So the same side "wins" whatever the parents order is. This is |
|
3445 | 3447 | # sub-optimal because depending on revision numbers means the result can be |
|
3446 | 3448 | # different from one repository to the next. |
|
3447 | 3449 | # |
|
3448 | 3450 | # The changeset based algorithm use the parent order to break tie on conflicting |
|
3449 | 3451 | # information and will have a different order depending on who is p1 and p2. |
|
3450 | 3452 | # That order is stable accross repositories. (data from p1 prevails) |
|
3451 | 3453 | |
|
3452 | 3454 | $ hg status --copies --rev 'desc("i-2")' --rev 'desc("mAE-change-m-0")' |
|
3453 | 3455 | A f |
|
3454 | 3456 | d |
|
3455 | 3457 | R b |
|
3456 | 3458 | R d |
|
3457 | 3459 | $ hg status --copies --rev 'desc("i-2")' --rev 'desc("mEA-change-m-0")' |
|
3458 | 3460 | A f |
|
3459 | 3461 | d (filelog !) |
|
3460 | 3462 | b (no-filelog !) |
|
3461 | 3463 | R b |
|
3462 | 3464 | R d |
|
3463 | 3465 | $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mAE-change-m-0")' |
|
3464 | 3466 | A f |
|
3465 | 3467 | a |
|
3466 | 3468 | A t |
|
3467 | 3469 | p |
|
3468 | 3470 | R a |
|
3469 | 3471 | R b |
|
3470 | 3472 | R p |
|
3471 | 3473 | $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mEA-change-m-0")' |
|
3472 | 3474 | A f |
|
3473 | 3475 | a (filelog !) |
|
3474 | 3476 | b (no-filelog !) |
|
3475 | 3477 | A t |
|
3476 | 3478 | p |
|
3477 | 3479 | R a |
|
3478 | 3480 | R b |
|
3479 | 3481 | R p |
|
3480 | 3482 | |
|
3481 | 3483 | |
|
3482 | 3484 | Subcase: merge overwrite common copy information, but with extra change during the merge |
|
3483 | 3485 | ``````````````````````````````````````````````````````````````````````````````````` |
|
3484 | 3486 | |
|
3485 | 3487 | Merge: |
|
3486 | 3488 | - one with change to an unrelated file (b) |
|
3487 | 3489 | - one overwriting a file (d) with a rename (from h to i to d) |
|
3488 | 3490 | |
|
3489 | 3491 | $ hg log -G --rev '::(desc("mBF-change-m")+desc("mFB-change-m"))' |
|
3490 | 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 | 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 | 3496 | | o f-2: rename i -> d |
|
3495 | 3497 | | | |
|
3496 | 3498 | | o f-1: rename h -> i |
|
3497 | 3499 | | | |
|
3498 | 3500 | o | b-1: b update |
|
3499 | 3501 | |/ |
|
3500 | 3502 | o i-2: c -move-> d, s -move-> t |
|
3501 | 3503 | | |
|
3502 | 3504 | o i-1: a -move-> c, p -move-> s |
|
3503 | 3505 | | |
|
3504 | 3506 | o i-0 initial commit: a b h p q r |
|
3505 | 3507 | |
|
3506 | 3508 | $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mBF-change-m-0")' |
|
3507 | 3509 | M b |
|
3508 | 3510 | A d |
|
3509 | 3511 | h |
|
3510 | 3512 | A t |
|
3511 | 3513 | p |
|
3512 | 3514 | R a |
|
3513 | 3515 | R h |
|
3514 | 3516 | R p |
|
3515 | 3517 | $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mFB-change-m-0")' |
|
3516 | 3518 | M b |
|
3517 | 3519 | A d |
|
3518 | 3520 | h |
|
3519 | 3521 | A t |
|
3520 | 3522 | p |
|
3521 | 3523 | R a |
|
3522 | 3524 | R h |
|
3523 | 3525 | R p |
|
3524 | 3526 | $ hg status --copies --rev 'desc("b-1")' --rev 'desc("mBF-change-m-0")' |
|
3525 | 3527 | M d |
|
3526 | 3528 | h (no-filelog !) |
|
3527 | 3529 | R h |
|
3528 | 3530 | $ hg status --copies --rev 'desc("f-2")' --rev 'desc("mBF-change-m-0")' |
|
3529 | 3531 | M b |
|
3530 | 3532 | M d |
|
3531 | 3533 | $ hg status --copies --rev 'desc("f-1")' --rev 'desc("mBF-change-m-0")' |
|
3532 | 3534 | M b |
|
3533 | 3535 | M d |
|
3534 | 3536 | i (no-filelog !) |
|
3535 | 3537 | R i |
|
3536 | 3538 | $ hg status --copies --rev 'desc("b-1")' --rev 'desc("mFB-change-m-0")' |
|
3537 | 3539 | M d |
|
3538 | 3540 | h (no-filelog !) |
|
3539 | 3541 | R h |
|
3540 | 3542 | $ hg status --copies --rev 'desc("f-2")' --rev 'desc("mFB-change-m-0")' |
|
3541 | 3543 | M b |
|
3542 | 3544 | M d |
|
3543 | 3545 | $ hg status --copies --rev 'desc("f-1")' --rev 'desc("mFB-change-m-0")' |
|
3544 | 3546 | M b |
|
3545 | 3547 | M d |
|
3546 | 3548 | i (no-filelog !) |
|
3547 | 3549 | R i |
|
3548 | 3550 | |
|
3549 | 3551 | #if no-changeset |
|
3550 | 3552 | $ hg log -Gfr 'desc("mBF-change-m-0")' d |
|
3551 | 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 | 3555 | o : f-2: rename i -> d |
|
3554 | 3556 | | : |
|
3555 | 3557 | o : f-1: rename h -> i |
|
3556 | 3558 | :/ |
|
3557 | 3559 | o i-0 initial commit: a b h p q r |
|
3558 | 3560 | |
|
3559 | 3561 | #else |
|
3560 | 3562 | BROKEN: `hg log --follow <file>` relies on filelog metadata to work |
|
3561 | 3563 | $ hg log -Gfr 'desc("mBF-change-m-0")' d |
|
3562 | 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 | 3566 | o i-2: c -move-> d, s -move-> t |
|
3565 | 3567 | | |
|
3566 | 3568 | ~ |
|
3567 | 3569 | #endif |
|
3568 | 3570 | |
|
3569 | 3571 | #if no-changeset |
|
3570 | 3572 | $ hg log -Gfr 'desc("mFB-change-m-0")' d |
|
3571 | 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 | 3575 | o : f-2: rename i -> d |
|
3574 | 3576 | | : |
|
3575 | 3577 | o : f-1: rename h -> i |
|
3576 | 3578 | :/ |
|
3577 | 3579 | o i-0 initial commit: a b h p q r |
|
3578 | 3580 | |
|
3579 | 3581 | #else |
|
3580 | 3582 | BROKEN: `hg log --follow <file>` relies on filelog metadata to work |
|
3581 | 3583 | $ hg log -Gfr 'desc("mFB-change-m-0")' d |
|
3582 | 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 | 3586 | o i-2: c -move-> d, s -move-> t |
|
3585 | 3587 | | |
|
3586 | 3588 | ~ |
|
3587 | 3589 | #endif |
|
3588 | 3590 | |
|
3589 | 3591 | |
|
3590 | 3592 | Subcase: restoring and untouched deleted file, while touching it |
|
3591 | 3593 | ```````````````````````````````````````````````````````````````` |
|
3592 | 3594 | |
|
3593 | 3595 | Merge: |
|
3594 | 3596 | - one removing a file (d) |
|
3595 | 3597 | - one leaving the file untouched |
|
3596 | 3598 | - the merge actively restore the file to the same content. |
|
3597 | 3599 | |
|
3598 | 3600 | In this case, the file keep on living after the merge. So we should not drop its |
|
3599 | 3601 | copy tracing chain. |
|
3600 | 3602 | |
|
3601 | 3603 | $ hg log -G --rev '::(desc("mCB-change-m")+desc("mBC-change-m"))' |
|
3602 | 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 | 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 | 3608 | | o c-1 delete d |
|
3607 | 3609 | | | |
|
3608 | 3610 | o | b-1: b update |
|
3609 | 3611 | |/ |
|
3610 | 3612 | o i-2: c -move-> d, s -move-> t |
|
3611 | 3613 | | |
|
3612 | 3614 | o i-1: a -move-> c, p -move-> s |
|
3613 | 3615 | | |
|
3614 | 3616 | o i-0 initial commit: a b h p q r |
|
3615 | 3617 | |
|
3616 | 3618 | |
|
3617 | 3619 | 'a' is the the copy source of 'd' |
|
3618 | 3620 | |
|
3619 | 3621 | $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mCB-change-m-0")' |
|
3620 | 3622 | M b |
|
3621 | 3623 | A d |
|
3622 | 3624 | a (no-compatibility no-changeset !) |
|
3623 | 3625 | A t |
|
3624 | 3626 | p |
|
3625 | 3627 | R a |
|
3626 | 3628 | R p |
|
3627 | 3629 | $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mBC-change-m-0")' |
|
3628 | 3630 | M b |
|
3629 | 3631 | A d |
|
3630 | 3632 | a (no-compatibility no-changeset !) |
|
3631 | 3633 | A t |
|
3632 | 3634 | p |
|
3633 | 3635 | R a |
|
3634 | 3636 | R p |
|
3635 | 3637 | $ hg status --copies --rev 'desc("c-1")' --rev 'desc("mCB-change-m-0")' |
|
3636 | 3638 | M b |
|
3637 | 3639 | A d |
|
3638 | 3640 | $ hg status --copies --rev 'desc("c-1")' --rev 'desc("mBC-change-m-0")' |
|
3639 | 3641 | M b |
|
3640 | 3642 | A d |
|
3641 | 3643 | $ hg status --copies --rev 'desc("b-1")' --rev 'desc("mCB-change-m-0")' |
|
3642 | 3644 | M d |
|
3643 | 3645 | $ hg status --copies --rev 'desc("b-1")' --rev 'desc("mBC-change-m-0")' |
|
3644 | 3646 | M d |
|
3645 | 3647 | |
|
3646 | 3648 | |
|
3647 | 3649 | Decision from previous merge are properly chained with later merge |
|
3648 | 3650 | ------------------------------------------------------------------ |
|
3649 | 3651 | |
|
3650 | 3652 | |
|
3651 | 3653 | Subcase: chaining conflicting rename resolution |
|
3652 | 3654 | ``````````````````````````````````````````````` |
|
3653 | 3655 | |
|
3654 | 3656 | The "mAEm" and "mEAm" case create a rename tracking conflict on file 'f'. We |
|
3655 | 3657 | add more change on the respective branch and merge again. These second merge |
|
3656 | 3658 | does not involve the file 'f' and the arbitration done within "mAEm" and "mEA" |
|
3657 | 3659 | about that file should stay unchanged. |
|
3658 | 3660 | |
|
3659 | 3661 | The result from mAEm is the same for the subsequent merge: |
|
3660 | 3662 | |
|
3661 | 3663 | $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mAEm")' f |
|
3662 | 3664 | A f |
|
3663 | 3665 | a (no-changeset no-compatibility !) |
|
3664 | 3666 | |
|
3665 | 3667 | $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mAE,Km")' f |
|
3666 | 3668 | A f |
|
3667 | 3669 | a (no-changeset no-compatibility !) |
|
3668 | 3670 | |
|
3669 | 3671 | $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mK,AEm")' f |
|
3670 | 3672 | A f |
|
3671 | 3673 | a (no-changeset no-compatibility !) |
|
3672 | 3674 | |
|
3673 | 3675 | |
|
3674 | 3676 | The result from mEAm is the same for the subsequent merge: |
|
3675 | 3677 | |
|
3676 | 3678 | $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mEAm")' f |
|
3677 | 3679 | A f |
|
3678 | 3680 | a (filelog !) |
|
3679 | 3681 | b (no-changeset no-compatibility no-filelog !) |
|
3680 | 3682 | |
|
3681 | 3683 | $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mEA,Jm")' f |
|
3682 | 3684 | A f |
|
3683 | 3685 | a (filelog !) |
|
3684 | 3686 | b (no-changeset no-compatibility no-filelog !) |
|
3685 | 3687 | |
|
3686 | 3688 | $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mJ,EAm")' f |
|
3687 | 3689 | A f |
|
3688 | 3690 | a (filelog !) |
|
3689 | 3691 | b (no-changeset no-compatibility no-filelog !) |
|
3690 | 3692 | |
|
3691 | 3693 | Subcase: chaining conflicting rename resolution |
|
3692 | 3694 | ``````````````````````````````````````````````` |
|
3693 | 3695 | |
|
3694 | 3696 | The "mPQm" and "mQPm" case create a rename tracking conflict on file 'v'. We |
|
3695 | 3697 | add more change on the respective branch and merge again. These second merge |
|
3696 | 3698 | does not involve the file 'v' and the arbitration done within "mPQm" and "mQP" |
|
3697 | 3699 | about that file should stay unchanged. |
|
3698 | 3700 | |
|
3699 | 3701 | The result from mPQm is the same for the subsequent merge: |
|
3700 | 3702 | |
|
3701 | 3703 | $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mPQm")' v |
|
3702 | 3704 | A v |
|
3703 | 3705 | r (filelog !) |
|
3704 | 3706 | p (no-changeset no-compatibility no-filelog !) |
|
3705 | 3707 | |
|
3706 | 3708 | $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mPQ,Tm")' v |
|
3707 | 3709 | A v |
|
3708 | 3710 | r (filelog !) |
|
3709 | 3711 | p (no-changeset no-compatibility no-filelog !) |
|
3710 | 3712 | |
|
3711 | 3713 | $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mT,PQm")' v |
|
3712 | 3714 | A v |
|
3713 | 3715 | r (filelog !) |
|
3714 | 3716 | p (no-changeset no-compatibility no-filelog !) |
|
3715 | 3717 | |
|
3716 | 3718 | The result from mQPm is the same for the subsequent merge: |
|
3717 | 3719 | |
|
3718 | 3720 | $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mQPm")' v |
|
3719 | 3721 | A v |
|
3720 | 3722 | r (no-changeset no-compatibility !) |
|
3721 | 3723 | |
|
3722 | 3724 | $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mQP,Sm")' v |
|
3723 | 3725 | A v |
|
3724 | 3726 | r (no-changeset no-compatibility !) |
|
3725 | 3727 | |
|
3726 | 3728 | $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mS,QPm")' v |
|
3727 | 3729 | A v |
|
3728 | 3730 | r (filelog !) |
|
3729 | 3731 | r (no-changeset no-compatibility no-filelog !) |
|
3730 | 3732 | |
|
3731 | 3733 | |
|
3732 | 3734 | Subcase: chaining salvage information during a merge |
|
3733 | 3735 | ```````````````````````````````````````````````````` |
|
3734 | 3736 | |
|
3735 | 3737 | We add more change on the branch were the file was deleted. merging again |
|
3736 | 3738 | should preserve the fact eh file was salvaged. |
|
3737 | 3739 | |
|
3738 | 3740 | reference output: |
|
3739 | 3741 | |
|
3740 | 3742 | $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mCB-revert-m-0")' |
|
3741 | 3743 | M b |
|
3742 | 3744 | A d |
|
3743 | 3745 | a (no-changeset no-compatibility !) |
|
3744 | 3746 | A t |
|
3745 | 3747 | p |
|
3746 | 3748 | R a |
|
3747 | 3749 | R p |
|
3748 | 3750 | $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mBC-revert-m-0")' |
|
3749 | 3751 | M b |
|
3750 | 3752 | A d |
|
3751 | 3753 | a (no-changeset no-compatibility !) |
|
3752 | 3754 | A t |
|
3753 | 3755 | p |
|
3754 | 3756 | R a |
|
3755 | 3757 | R p |
|
3756 | 3758 | |
|
3757 | 3759 | chained output |
|
3758 | 3760 | $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mBC+revert,Lm")' |
|
3759 | 3761 | M b |
|
3760 | 3762 | A d |
|
3761 | 3763 | a (no-changeset no-compatibility !) |
|
3762 | 3764 | A t |
|
3763 | 3765 | p |
|
3764 | 3766 | A unrelated-l |
|
3765 | 3767 | R a |
|
3766 | 3768 | R p |
|
3767 | 3769 | $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mCB+revert,Lm")' |
|
3768 | 3770 | M b |
|
3769 | 3771 | A d |
|
3770 | 3772 | a (no-changeset no-compatibility !) |
|
3771 | 3773 | A t |
|
3772 | 3774 | p |
|
3773 | 3775 | A unrelated-l |
|
3774 | 3776 | R a |
|
3775 | 3777 | R p |
|
3776 | 3778 | $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mL,BC+revertm")' |
|
3777 | 3779 | M b |
|
3778 | 3780 | A d |
|
3779 | 3781 | a (no-changeset no-compatibility !) |
|
3780 | 3782 | A t |
|
3781 | 3783 | p |
|
3782 | 3784 | A unrelated-l |
|
3783 | 3785 | R a |
|
3784 | 3786 | R p |
|
3785 | 3787 | $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mL,CB+revertm")' |
|
3786 | 3788 | M b |
|
3787 | 3789 | A d |
|
3788 | 3790 | a (no-changeset no-compatibility !) |
|
3789 | 3791 | A t |
|
3790 | 3792 | p |
|
3791 | 3793 | A unrelated-l |
|
3792 | 3794 | R a |
|
3793 | 3795 | R p |
|
3794 | 3796 | |
|
3795 | 3797 | Subcase: chaining "merged" information during a merge |
|
3796 | 3798 | `````````````````````````````````````````````````````` |
|
3797 | 3799 | |
|
3798 | 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 | 3803 | reference output: |
|
3802 | 3804 | |
|
3803 | 3805 | (for details about the filelog pick, check the mFGm/mGFm case) |
|
3804 | 3806 | |
|
3805 | 3807 | $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mFGm")' d |
|
3806 | 3808 | A d |
|
3807 | 3809 | a (filelog !) |
|
3808 | 3810 | h (no-changeset no-compatibility no-filelog !) |
|
3809 | 3811 | $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mGFm")' d |
|
3810 | 3812 | A d |
|
3811 | 3813 | a (filelog !) |
|
3812 | 3814 | a (no-changeset no-compatibility no-filelog !) |
|
3813 | 3815 | |
|
3814 | 3816 | Chained output |
|
3815 | 3817 | |
|
3816 | 3818 | $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mO,FGm")' d |
|
3817 | 3819 | A d |
|
3818 | 3820 | a (filelog !) |
|
3819 | 3821 | h (no-changeset no-compatibility no-filelog !) |
|
3820 | 3822 | $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mFG,Om")' d |
|
3821 | 3823 | A d |
|
3822 | 3824 | a (filelog !) |
|
3823 | 3825 | h (no-changeset no-compatibility no-filelog !) |
|
3824 | 3826 | |
|
3825 | 3827 | |
|
3826 | 3828 | $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mGF,Nm")' d |
|
3827 | 3829 | A d |
|
3828 | 3830 | a (no-changeset no-compatibility !) |
|
3829 | 3831 | $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mN,GFm")' d |
|
3830 | 3832 | A d |
|
3831 | 3833 | a (no-changeset no-compatibility !) |
|
3832 | 3834 | |
|
3833 | 3835 | |
|
3834 | 3836 | Subcase: chaining conflicting rename resolution, with extra change during the merge |
|
3835 | 3837 | ``````````````````````````````````````````````````````````````````````````````````` |
|
3836 | 3838 | |
|
3837 | 3839 | The "mAEm" and "mEAm" case create a rename tracking conflict on file 'f'. We |
|
3838 | 3840 | add more change on the respective branch and merge again. These second merge |
|
3839 | 3841 | does not involve the file 'f' and the arbitration done within "mAEm" and "mEA" |
|
3840 | 3842 | about that file should stay unchanged. |
|
3841 | 3843 | |
|
3842 | 3844 | The result from mAEm is the same for the subsequent merge: |
|
3843 | 3845 | |
|
3844 | 3846 | $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mAE-change-m")' f |
|
3845 | 3847 | A f |
|
3846 | 3848 | a (no-changeset no-compatibility !) |
|
3847 | 3849 | |
|
3848 | 3850 | $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mAE-change,Km")' f |
|
3849 | 3851 | A f |
|
3850 | 3852 | a (no-changeset no-compatibility !) |
|
3851 | 3853 | |
|
3852 | 3854 | $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mK,AE-change-m")' f |
|
3853 | 3855 | A f |
|
3854 | 3856 | a (no-changeset no-compatibility !) |
|
3855 | 3857 | |
|
3856 | 3858 | |
|
3857 | 3859 | The result from mEAm is the same for the subsequent merge: |
|
3858 | 3860 | |
|
3859 | 3861 | $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mEA-change-m")' f |
|
3860 | 3862 | A f |
|
3861 | 3863 | a (filelog !) |
|
3862 | 3864 | b (no-changeset no-compatibility no-filelog !) |
|
3863 | 3865 | |
|
3864 | 3866 | $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mEA-change,Jm")' f |
|
3865 | 3867 | A f |
|
3866 | 3868 | a (filelog !) |
|
3867 | 3869 | b (no-changeset no-compatibility no-filelog !) |
|
3868 | 3870 | |
|
3869 | 3871 | $ hg status --copies --rev 'desc("i-0")' --rev 'desc("mJ,EA-change-m")' f |
|
3870 | 3872 | A f |
|
3871 | 3873 | a (filelog !) |
|
3872 | 3874 | b (no-changeset no-compatibility no-filelog !) |
@@ -1,509 +1,514 | |||
|
1 | 1 | #testcases extra sidedata |
|
2 | 2 | |
|
3 | 3 | #if extra |
|
4 | 4 | $ cat >> $HGRCPATH << EOF |
|
5 | 5 | > [experimental] |
|
6 | 6 | > copies.write-to=changeset-only |
|
7 | 7 | > copies.read-from=changeset-only |
|
8 | 8 | > [alias] |
|
9 | 9 | > changesetcopies = log -r . -T 'files: {files} |
|
10 | 10 | > {extras % "{ifcontains("files", key, "{key}: {value}\n")}"} |
|
11 | 11 | > {extras % "{ifcontains("copies", key, "{key}: {value}\n")}"}' |
|
12 | 12 | > EOF |
|
13 | 13 | #endif |
|
14 | 14 | |
|
15 | 15 | #if sidedata |
|
16 | 16 | $ cat >> $HGRCPATH << EOF |
|
17 | 17 | > [format] |
|
18 | 18 | > exp-use-copies-side-data-changeset = yes |
|
19 | 19 | > EOF |
|
20 | 20 | #endif |
|
21 | 21 | |
|
22 | 22 | $ cat >> $HGRCPATH << EOF |
|
23 | 23 | > [alias] |
|
24 | 24 | > showcopies = log -r . -T '{file_copies % "{source} -> {name}\n"}' |
|
25 | 25 | > [extensions] |
|
26 | 26 | > rebase = |
|
27 | 27 | > split = |
|
28 | 28 | > EOF |
|
29 | 29 | |
|
30 | 30 | Check that copies are recorded correctly |
|
31 | 31 | |
|
32 | 32 | $ hg init repo |
|
33 | 33 | $ cd repo |
|
34 | 34 | #if sidedata |
|
35 | 35 | $ hg debugformat -v |
|
36 | 36 | format-variant repo config default |
|
37 | 37 | fncache: yes yes yes |
|
38 | dirstate-v2: no no no | |
|
38 | 39 | dotencode: yes yes yes |
|
39 | 40 | generaldelta: yes yes yes |
|
40 | 41 | share-safe: no no no |
|
41 | 42 | sparserevlog: yes yes yes |
|
42 | 43 | persistent-nodemap: no no no (no-rust !) |
|
43 | 44 | persistent-nodemap: yes yes no (rust !) |
|
44 | 45 | copies-sdc: yes yes no |
|
45 | 46 | revlog-v2: no no no |
|
46 | 47 | changelog-v2: yes yes no |
|
47 | 48 | plain-cl-delta: yes yes yes |
|
48 | 49 | compression: zlib zlib zlib (no-zstd !) |
|
49 | 50 | compression: zstd zstd zstd (zstd !) |
|
50 | 51 | compression-level: default default default |
|
51 | 52 | #else |
|
52 | 53 | $ hg debugformat -v |
|
53 | 54 | format-variant repo config default |
|
54 | 55 | fncache: yes yes yes |
|
56 | dirstate-v2: no no no | |
|
55 | 57 | dotencode: yes yes yes |
|
56 | 58 | generaldelta: yes yes yes |
|
57 | 59 | share-safe: no no no |
|
58 | 60 | sparserevlog: yes yes yes |
|
59 | 61 | persistent-nodemap: no no no (no-rust !) |
|
60 | 62 | persistent-nodemap: yes yes no (rust !) |
|
61 | 63 | copies-sdc: no no no |
|
62 | 64 | revlog-v2: no no no |
|
63 | 65 | changelog-v2: no no no |
|
64 | 66 | plain-cl-delta: yes yes yes |
|
65 | 67 | compression: zlib zlib zlib (no-zstd !) |
|
66 | 68 | compression: zstd zstd zstd (zstd !) |
|
67 | 69 | compression-level: default default default |
|
68 | 70 | #endif |
|
69 | 71 | $ echo a > a |
|
70 | 72 | $ hg add a |
|
71 | 73 | $ hg ci -m initial |
|
72 | 74 | $ hg cp a b |
|
73 | 75 | $ hg cp a c |
|
74 | 76 | $ hg cp a d |
|
75 | 77 | $ hg ci -m 'copy a to b, c, and d' |
|
76 | 78 | |
|
77 | 79 | #if extra |
|
78 | 80 | |
|
79 | 81 | $ hg changesetcopies |
|
80 | 82 | files: b c d |
|
81 | 83 | filesadded: 0 |
|
82 | 84 | 1 |
|
83 | 85 | 2 |
|
84 | 86 | |
|
85 | 87 | p1copies: 0\x00a (esc) |
|
86 | 88 | 1\x00a (esc) |
|
87 | 89 | 2\x00a (esc) |
|
88 | 90 | #else |
|
89 | 91 | $ hg debugsidedata -c -v -- -1 |
|
90 | 92 | 1 sidedata entries |
|
91 | 93 | entry-0014 size 44 |
|
92 | 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 | 95 | #endif |
|
94 | 96 | |
|
95 | 97 | $ hg showcopies |
|
96 | 98 | a -> b |
|
97 | 99 | a -> c |
|
98 | 100 | a -> d |
|
99 | 101 | |
|
100 | 102 | #if extra |
|
101 | 103 | |
|
102 | 104 | $ hg showcopies --config experimental.copies.read-from=compatibility |
|
103 | 105 | a -> b |
|
104 | 106 | a -> c |
|
105 | 107 | a -> d |
|
106 | 108 | $ hg showcopies --config experimental.copies.read-from=filelog-only |
|
107 | 109 | |
|
108 | 110 | #endif |
|
109 | 111 | |
|
110 | 112 | Check that renames are recorded correctly |
|
111 | 113 | |
|
112 | 114 | $ hg mv b b2 |
|
113 | 115 | $ hg ci -m 'rename b to b2' |
|
114 | 116 | |
|
115 | 117 | #if extra |
|
116 | 118 | |
|
117 | 119 | $ hg changesetcopies |
|
118 | 120 | files: b b2 |
|
119 | 121 | filesadded: 1 |
|
120 | 122 | filesremoved: 0 |
|
121 | 123 | |
|
122 | 124 | p1copies: 1\x00b (esc) |
|
123 | 125 | |
|
124 | 126 | #else |
|
125 | 127 | $ hg debugsidedata -c -v -- -1 |
|
126 | 128 | 1 sidedata entries |
|
127 | 129 | entry-0014 size 25 |
|
128 | 130 | '\x00\x00\x00\x02\x0c\x00\x00\x00\x01\x00\x00\x00\x00\x06\x00\x00\x00\x03\x00\x00\x00\x00bb2' |
|
129 | 131 | #endif |
|
130 | 132 | |
|
131 | 133 | $ hg showcopies |
|
132 | 134 | b -> b2 |
|
133 | 135 | |
|
134 | 136 | |
|
135 | 137 | Rename onto existing file. This should get recorded in the changeset files list and in the extras, |
|
136 | 138 | even though there is no filelog entry. |
|
137 | 139 | |
|
138 | 140 | $ hg cp b2 c --force |
|
139 | 141 | $ hg st --copies |
|
140 | 142 | M c |
|
141 | 143 | b2 |
|
142 | 144 | |
|
143 | 145 | #if extra |
|
144 | 146 | |
|
145 | 147 | $ hg debugindex c |
|
146 | 148 | rev linkrev nodeid p1 p2 |
|
147 | 149 | 0 1 b789fdd96dc2 000000000000 000000000000 |
|
148 | 150 | |
|
149 | 151 | #else |
|
150 | 152 | |
|
151 | 153 | $ hg debugindex c |
|
152 | 154 | rev linkrev nodeid p1 p2 |
|
153 | 155 | 0 1 37d9b5d994ea 000000000000 000000000000 |
|
154 | 156 | |
|
155 | 157 | #endif |
|
156 | 158 | |
|
157 | 159 | |
|
158 | 160 | $ hg ci -m 'move b onto d' |
|
159 | 161 | |
|
160 | 162 | #if extra |
|
161 | 163 | |
|
162 | 164 | $ hg changesetcopies |
|
163 | 165 | files: c |
|
164 | 166 | |
|
165 | 167 | p1copies: 0\x00b2 (esc) |
|
166 | 168 | |
|
167 | 169 | #else |
|
168 | 170 | $ hg debugsidedata -c -v -- -1 |
|
169 | 171 | 1 sidedata entries |
|
170 | 172 | entry-0014 size 25 |
|
171 | 173 | '\x00\x00\x00\x02\x00\x00\x00\x00\x02\x00\x00\x00\x00\x16\x00\x00\x00\x03\x00\x00\x00\x00b2c' |
|
172 | 174 | #endif |
|
173 | 175 | |
|
174 | 176 | $ hg showcopies |
|
175 | 177 | b2 -> c |
|
176 | 178 | |
|
177 | 179 | #if extra |
|
178 | 180 | |
|
179 | 181 | $ hg debugindex c |
|
180 | 182 | rev linkrev nodeid p1 p2 |
|
181 | 183 | 0 1 b789fdd96dc2 000000000000 000000000000 |
|
182 | 184 | |
|
183 | 185 | #else |
|
184 | 186 | |
|
185 | 187 | $ hg debugindex c |
|
186 | 188 | rev linkrev nodeid p1 p2 |
|
187 | 189 | 0 1 37d9b5d994ea 000000000000 000000000000 |
|
188 | 190 | 1 3 029625640347 000000000000 000000000000 |
|
189 | 191 | |
|
190 | 192 | #endif |
|
191 | 193 | |
|
192 | 194 | Create a merge commit with copying done during merge. |
|
193 | 195 | |
|
194 | 196 | $ hg co 0 |
|
195 | 197 | 0 files updated, 0 files merged, 3 files removed, 0 files unresolved |
|
196 | 198 | $ hg cp a e |
|
197 | 199 | $ hg cp a f |
|
198 | 200 | $ hg ci -m 'copy a to e and f' |
|
199 | 201 | created new head |
|
200 | 202 | $ hg merge 3 |
|
201 | 203 | 3 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
202 | 204 | (branch merge, don't forget to commit) |
|
203 | 205 | File 'a' exists on both sides, so 'g' could be recorded as being from p1 or p2, but we currently |
|
204 | 206 | always record it as being from p1 |
|
205 | 207 | $ hg cp a g |
|
206 | 208 | File 'd' exists only in p2, so 'h' should be from p2 |
|
207 | 209 | $ hg cp d h |
|
208 | 210 | File 'f' exists only in p1, so 'i' should be from p1 |
|
209 | 211 | $ hg cp f i |
|
210 | 212 | $ hg ci -m 'merge' |
|
211 | 213 | |
|
212 | 214 | #if extra |
|
213 | 215 | |
|
214 | 216 | $ hg changesetcopies |
|
215 | 217 | files: g h i |
|
216 | 218 | filesadded: 0 |
|
217 | 219 | 1 |
|
218 | 220 | 2 |
|
219 | 221 | |
|
220 | 222 | p1copies: 0\x00a (esc) |
|
221 | 223 | 2\x00f (esc) |
|
222 | 224 | p2copies: 1\x00d (esc) |
|
223 | 225 | |
|
224 | 226 | #else |
|
225 | 227 | $ hg debugsidedata -c -v -- -1 |
|
226 | 228 | 1 sidedata entries |
|
227 | 229 | entry-0014 size 64 |
|
228 | 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 | 231 | #endif |
|
230 | 232 | |
|
231 | 233 | $ hg showcopies |
|
232 | 234 | a -> g |
|
233 | 235 | d -> h |
|
234 | 236 | f -> i |
|
235 | 237 | |
|
236 | 238 | Test writing to both changeset and filelog |
|
237 | 239 | |
|
238 | 240 | $ hg cp a j |
|
239 | 241 | #if extra |
|
240 | 242 | $ hg ci -m 'copy a to j' --config experimental.copies.write-to=compatibility |
|
241 | 243 | $ hg changesetcopies |
|
242 | 244 | files: j |
|
243 | 245 | filesadded: 0 |
|
244 | 246 | filesremoved: |
|
245 | 247 | |
|
246 | 248 | p1copies: 0\x00a (esc) |
|
247 | 249 | p2copies: |
|
248 | 250 | #else |
|
249 | 251 | $ hg ci -m 'copy a to j' |
|
250 | 252 | $ hg debugsidedata -c -v -- -1 |
|
251 | 253 | 1 sidedata entries |
|
252 | 254 | entry-0014 size 24 |
|
253 | 255 | '\x00\x00\x00\x02\x00\x00\x00\x00\x01\x00\x00\x00\x00\x06\x00\x00\x00\x02\x00\x00\x00\x00aj' |
|
254 | 256 | #endif |
|
255 | 257 | $ hg debugdata j 0 |
|
256 | 258 | \x01 (esc) |
|
257 | 259 | copy: a |
|
258 | 260 | copyrev: b789fdd96dc2f3bd229c1dd8eedf0fc60e2b68e3 |
|
259 | 261 | \x01 (esc) |
|
260 | 262 | a |
|
261 | 263 | $ hg showcopies |
|
262 | 264 | a -> j |
|
263 | 265 | $ hg showcopies --config experimental.copies.read-from=compatibility |
|
264 | 266 | a -> j |
|
265 | 267 | $ hg showcopies --config experimental.copies.read-from=filelog-only |
|
266 | 268 | a -> j |
|
267 | 269 | Existing copy information in the changeset gets removed on amend and writing |
|
268 | 270 | copy information on to the filelog |
|
269 | 271 | #if extra |
|
270 | 272 | $ hg ci --amend -m 'copy a to j, v2' \ |
|
271 | 273 | > --config experimental.copies.write-to=filelog-only |
|
272 | 274 | saved backup bundle to $TESTTMP/repo/.hg/strip-backup/*-*-amend.hg (glob) |
|
273 | 275 | $ hg changesetcopies |
|
274 | 276 | files: j |
|
275 | 277 | |
|
276 | 278 | #else |
|
277 | 279 | $ hg ci --amend -m 'copy a to j, v2' |
|
278 | 280 | saved backup bundle to $TESTTMP/repo/.hg/strip-backup/*-*-amend.hg (glob) |
|
279 | 281 | $ hg debugsidedata -c -v -- -1 |
|
280 | 282 | 1 sidedata entries |
|
281 | 283 | entry-0014 size 24 |
|
282 | 284 | '\x00\x00\x00\x02\x00\x00\x00\x00\x01\x00\x00\x00\x00\x06\x00\x00\x00\x02\x00\x00\x00\x00aj' |
|
283 | 285 | #endif |
|
284 | 286 | $ hg showcopies --config experimental.copies.read-from=filelog-only |
|
285 | 287 | a -> j |
|
286 | 288 | The entries should be written to extras even if they're empty (so the client |
|
287 | 289 | won't have to fall back to reading from filelogs) |
|
288 | 290 | $ echo x >> j |
|
289 | 291 | #if extra |
|
290 | 292 | $ hg ci -m 'modify j' --config experimental.copies.write-to=compatibility |
|
291 | 293 | $ hg changesetcopies |
|
292 | 294 | files: j |
|
293 | 295 | filesadded: |
|
294 | 296 | filesremoved: |
|
295 | 297 | |
|
296 | 298 | p1copies: |
|
297 | 299 | p2copies: |
|
298 | 300 | #else |
|
299 | 301 | $ hg ci -m 'modify j' |
|
300 | 302 | $ hg debugsidedata -c -v -- -1 |
|
301 | 303 | 1 sidedata entries |
|
302 | 304 | entry-0014 size 14 |
|
303 | 305 | '\x00\x00\x00\x01\x14\x00\x00\x00\x01\x00\x00\x00\x00j' |
|
304 | 306 | #endif |
|
305 | 307 | |
|
306 | 308 | Test writing only to filelog |
|
307 | 309 | |
|
308 | 310 | $ hg cp a k |
|
309 | 311 | #if extra |
|
310 | 312 | $ hg ci -m 'copy a to k' --config experimental.copies.write-to=filelog-only |
|
311 | 313 | |
|
312 | 314 | $ hg changesetcopies |
|
313 | 315 | files: k |
|
314 | 316 | |
|
315 | 317 | #else |
|
316 | 318 | $ hg ci -m 'copy a to k' |
|
317 | 319 | $ hg debugsidedata -c -v -- -1 |
|
318 | 320 | 1 sidedata entries |
|
319 | 321 | entry-0014 size 24 |
|
320 | 322 | '\x00\x00\x00\x02\x00\x00\x00\x00\x01\x00\x00\x00\x00\x06\x00\x00\x00\x02\x00\x00\x00\x00ak' |
|
321 | 323 | #endif |
|
322 | 324 | |
|
323 | 325 | $ hg debugdata k 0 |
|
324 | 326 | \x01 (esc) |
|
325 | 327 | copy: a |
|
326 | 328 | copyrev: b789fdd96dc2f3bd229c1dd8eedf0fc60e2b68e3 |
|
327 | 329 | \x01 (esc) |
|
328 | 330 | a |
|
329 | 331 | #if extra |
|
330 | 332 | $ hg showcopies |
|
331 | 333 | |
|
332 | 334 | $ hg showcopies --config experimental.copies.read-from=compatibility |
|
333 | 335 | a -> k |
|
334 | 336 | $ hg showcopies --config experimental.copies.read-from=filelog-only |
|
335 | 337 | a -> k |
|
336 | 338 | #else |
|
337 | 339 | $ hg showcopies |
|
338 | 340 | a -> k |
|
339 | 341 | #endif |
|
340 | 342 | |
|
341 | 343 | $ cd .. |
|
342 | 344 | |
|
343 | 345 | Test rebasing a commit with copy information |
|
344 | 346 | |
|
345 | 347 | $ hg init rebase-rename |
|
346 | 348 | $ cd rebase-rename |
|
347 | 349 | $ echo a > a |
|
348 | 350 | $ hg ci -Aqm 'add a' |
|
349 | 351 | $ echo a2 > a |
|
350 | 352 | $ hg ci -m 'modify a' |
|
351 | 353 | $ hg co -q 0 |
|
352 | 354 | $ hg mv a b |
|
353 | 355 | $ hg ci -qm 'rename a to b' |
|
354 | 356 | Not only do we want this to run in-memory, it shouldn't fall back to |
|
355 | 357 | on-disk merge (no conflicts), so we force it to be in-memory |
|
356 | 358 | with no fallback. |
|
357 | 359 | $ hg rebase -d 1 --config rebase.experimental.inmemory=yes --config devel.rebase.force-in-memory-merge=yes |
|
358 | 360 | rebasing 2:* tip "rename a to b" (glob) |
|
359 | 361 | merging a and b to b |
|
360 | 362 | saved backup bundle to $TESTTMP/rebase-rename/.hg/strip-backup/*-*-rebase.hg (glob) |
|
361 | 363 | $ hg st --change . --copies |
|
362 | 364 | A b |
|
363 | 365 | a |
|
364 | 366 | R a |
|
365 | 367 | $ cd .. |
|
366 | 368 | |
|
367 | 369 | Test splitting a commit |
|
368 | 370 | |
|
369 | 371 | $ hg init split |
|
370 | 372 | $ cd split |
|
371 | 373 | $ echo a > a |
|
372 | 374 | $ echo b > b |
|
373 | 375 | $ hg ci -Aqm 'add a and b' |
|
374 | 376 | $ echo a2 > a |
|
375 | 377 | $ hg mv b c |
|
376 | 378 | $ hg ci -m 'modify a, move b to c' |
|
377 | 379 | $ hg --config ui.interactive=yes split <<EOF |
|
378 | 380 | > y |
|
379 | 381 | > y |
|
380 | 382 | > n |
|
381 | 383 | > y |
|
382 | 384 | > EOF |
|
383 | 385 | diff --git a/a b/a |
|
384 | 386 | 1 hunks, 1 lines changed |
|
385 | 387 | examine changes to 'a'? |
|
386 | 388 | (enter ? for help) [Ynesfdaq?] y |
|
387 | 389 | |
|
388 | 390 | @@ -1,1 +1,1 @@ |
|
389 | 391 | -a |
|
390 | 392 | +a2 |
|
391 | 393 | record this change to 'a'? |
|
392 | 394 | (enter ? for help) [Ynesfdaq?] y |
|
393 | 395 | |
|
394 | 396 | diff --git a/b b/c |
|
395 | 397 | rename from b |
|
396 | 398 | rename to c |
|
397 | 399 | examine changes to 'b' and 'c'? |
|
398 | 400 | (enter ? for help) [Ynesfdaq?] n |
|
399 | 401 | |
|
400 | 402 | created new head |
|
401 | 403 | diff --git a/b b/c |
|
402 | 404 | rename from b |
|
403 | 405 | rename to c |
|
404 | 406 | examine changes to 'b' and 'c'? |
|
405 | 407 | (enter ? for help) [Ynesfdaq?] y |
|
406 | 408 | |
|
407 | 409 | saved backup bundle to $TESTTMP/split/.hg/strip-backup/*-*-split.hg (glob) |
|
408 | 410 | $ cd .. |
|
409 | 411 | |
|
410 | 412 | Test committing half a rename |
|
411 | 413 | |
|
412 | 414 | $ hg init partial |
|
413 | 415 | $ cd partial |
|
414 | 416 | $ echo a > a |
|
415 | 417 | $ hg ci -Aqm 'add a' |
|
416 | 418 | $ hg mv a b |
|
417 | 419 | $ hg ci -m 'remove a' a |
|
418 | 420 | |
|
419 | 421 | #if sidedata |
|
420 | 422 | |
|
421 | 423 | Test upgrading/downgrading to sidedata storage |
|
422 | 424 | ============================================== |
|
423 | 425 | |
|
424 | 426 | downgrading |
|
425 | 427 | |
|
426 | 428 | $ hg debugformat -v |
|
427 | 429 | format-variant repo config default |
|
428 | 430 | fncache: yes yes yes |
|
431 | dirstate-v2: no no no | |
|
429 | 432 | dotencode: yes yes yes |
|
430 | 433 | generaldelta: yes yes yes |
|
431 | 434 | share-safe: no no no |
|
432 | 435 | sparserevlog: yes yes yes |
|
433 | 436 | persistent-nodemap: no no no (no-rust !) |
|
434 | 437 | persistent-nodemap: yes yes no (rust !) |
|
435 | 438 | copies-sdc: yes yes no |
|
436 | 439 | revlog-v2: no no no |
|
437 | 440 | changelog-v2: yes yes no |
|
438 | 441 | plain-cl-delta: yes yes yes |
|
439 | 442 | compression: zlib zlib zlib (no-zstd !) |
|
440 | 443 | compression: zstd zstd zstd (zstd !) |
|
441 | 444 | compression-level: default default default |
|
442 | 445 | $ hg debugsidedata -c -- 0 |
|
443 | 446 | 1 sidedata entries |
|
444 | 447 | entry-0014 size 14 |
|
445 | 448 | $ hg debugsidedata -c -- 1 |
|
446 | 449 | 1 sidedata entries |
|
447 | 450 | entry-0014 size 14 |
|
448 | 451 | $ hg debugsidedata -m -- 0 |
|
449 | 452 | $ cat << EOF > .hg/hgrc |
|
450 | 453 | > [format] |
|
451 | 454 | > exp-use-copies-side-data-changeset = no |
|
452 | 455 | > [experimental] |
|
453 | 456 | > revlogv2 = enable-unstable-format-and-corrupt-my-data |
|
454 | 457 | > EOF |
|
455 | 458 | $ hg debugupgraderepo --run --quiet --no-backup > /dev/null |
|
456 | 459 | $ hg debugformat -v |
|
457 | 460 | format-variant repo config default |
|
458 | 461 | fncache: yes yes yes |
|
462 | dirstate-v2: no no no | |
|
459 | 463 | dotencode: yes yes yes |
|
460 | 464 | generaldelta: yes yes yes |
|
461 | 465 | share-safe: no no no |
|
462 | 466 | sparserevlog: yes yes yes |
|
463 | 467 | persistent-nodemap: no no no (no-rust !) |
|
464 | 468 | persistent-nodemap: yes yes no (rust !) |
|
465 | 469 | copies-sdc: no no no |
|
466 | 470 | revlog-v2: yes yes no |
|
467 | 471 | changelog-v2: no no no |
|
468 | 472 | plain-cl-delta: yes yes yes |
|
469 | 473 | compression: zlib zlib zlib (no-zstd !) |
|
470 | 474 | compression: zstd zstd zstd (zstd !) |
|
471 | 475 | compression-level: default default default |
|
472 | 476 | $ hg debugsidedata -c -- 0 |
|
473 | 477 | $ hg debugsidedata -c -- 1 |
|
474 | 478 | $ hg debugsidedata -m -- 0 |
|
475 | 479 | |
|
476 | 480 | upgrading |
|
477 | 481 | |
|
478 | 482 | $ cat << EOF > .hg/hgrc |
|
479 | 483 | > [format] |
|
480 | 484 | > exp-use-copies-side-data-changeset = yes |
|
481 | 485 | > EOF |
|
482 | 486 | $ hg debugupgraderepo --run --quiet --no-backup > /dev/null |
|
483 | 487 | $ hg debugformat -v |
|
484 | 488 | format-variant repo config default |
|
485 | 489 | fncache: yes yes yes |
|
490 | dirstate-v2: no no no | |
|
486 | 491 | dotencode: yes yes yes |
|
487 | 492 | generaldelta: yes yes yes |
|
488 | 493 | share-safe: no no no |
|
489 | 494 | sparserevlog: yes yes yes |
|
490 | 495 | persistent-nodemap: no no no (no-rust !) |
|
491 | 496 | persistent-nodemap: yes yes no (rust !) |
|
492 | 497 | copies-sdc: yes yes no |
|
493 | 498 | revlog-v2: no no no |
|
494 | 499 | changelog-v2: yes yes no |
|
495 | 500 | plain-cl-delta: yes yes yes |
|
496 | 501 | compression: zlib zlib zlib (no-zstd !) |
|
497 | 502 | compression: zstd zstd zstd (zstd !) |
|
498 | 503 | compression-level: default default default |
|
499 | 504 | $ hg debugsidedata -c -- 0 |
|
500 | 505 | 1 sidedata entries |
|
501 | 506 | entry-0014 size 14 |
|
502 | 507 | $ hg debugsidedata -c -- 1 |
|
503 | 508 | 1 sidedata entries |
|
504 | 509 | entry-0014 size 14 |
|
505 | 510 | $ hg debugsidedata -m -- 0 |
|
506 | 511 | |
|
507 | 512 | #endif |
|
508 | 513 | |
|
509 | 514 | $ cd .. |
@@ -1,1059 +1,1062 | |||
|
1 | 1 | =================================== |
|
2 | 2 | Test the persistent on-disk nodemap |
|
3 | 3 | =================================== |
|
4 | 4 | |
|
5 | 5 | |
|
6 | 6 | #if no-rust |
|
7 | 7 | |
|
8 | 8 | $ cat << EOF >> $HGRCPATH |
|
9 | 9 | > [format] |
|
10 | 10 | > use-persistent-nodemap=yes |
|
11 | 11 | > [devel] |
|
12 | 12 | > persistent-nodemap=yes |
|
13 | 13 | > EOF |
|
14 | 14 | |
|
15 | 15 | #endif |
|
16 | 16 | |
|
17 | 17 | $ hg init test-repo --config storage.revlog.persistent-nodemap.slow-path=allow |
|
18 | 18 | $ cd test-repo |
|
19 | 19 | |
|
20 | 20 | Check handling of the default slow-path value |
|
21 | 21 | |
|
22 | 22 | #if no-pure no-rust |
|
23 | 23 | |
|
24 | 24 | $ hg id |
|
25 | 25 | abort: accessing `persistent-nodemap` repository without associated fast implementation. |
|
26 | 26 | (check `hg help config.format.use-persistent-nodemap` for details) |
|
27 | 27 | [255] |
|
28 | 28 | |
|
29 | 29 | Unlock further check (we are here to test the feature) |
|
30 | 30 | |
|
31 | 31 | $ cat << EOF >> $HGRCPATH |
|
32 | 32 | > [storage] |
|
33 | 33 | > # to avoid spamming the test |
|
34 | 34 | > revlog.persistent-nodemap.slow-path=allow |
|
35 | 35 | > EOF |
|
36 | 36 | |
|
37 | 37 | #endif |
|
38 | 38 | |
|
39 | 39 | #if rust |
|
40 | 40 | |
|
41 | 41 | Regression test for a previous bug in Rust/C FFI for the `Revlog_CAPI` capsule: |
|
42 | 42 | in places where `mercurial/cext/revlog.c` function signatures use `Py_ssize_t` |
|
43 | 43 | (64 bits on Linux x86_64), corresponding declarations in `rust/hg-cpython/src/cindex.rs` |
|
44 | 44 | incorrectly used `libc::c_int` (32 bits). |
|
45 | 45 | As a result, -1 passed from Rust for the null revision became 4294967295 in C. |
|
46 | 46 | |
|
47 | 47 | $ hg log -r 00000000 |
|
48 | 48 | changeset: -1:000000000000 |
|
49 | 49 | tag: tip |
|
50 | 50 | user: |
|
51 | 51 | date: Thu Jan 01 00:00:00 1970 +0000 |
|
52 | 52 | |
|
53 | 53 | |
|
54 | 54 | #endif |
|
55 | 55 | |
|
56 | 56 | |
|
57 | 57 | $ hg debugformat |
|
58 | 58 | format-variant repo |
|
59 | 59 | fncache: yes |
|
60 | dirstate-v2: no | |
|
60 | 61 | dotencode: yes |
|
61 | 62 | generaldelta: yes |
|
62 | 63 | share-safe: no |
|
63 | 64 | sparserevlog: yes |
|
64 | 65 | persistent-nodemap: yes |
|
65 | 66 | copies-sdc: no |
|
66 | 67 | revlog-v2: no |
|
67 | 68 | changelog-v2: no |
|
68 | 69 | plain-cl-delta: yes |
|
69 | 70 | compression: zlib (no-zstd !) |
|
70 | 71 | compression: zstd (zstd !) |
|
71 | 72 | compression-level: default |
|
72 | 73 | $ hg debugbuilddag .+5000 --new-file |
|
73 | 74 | |
|
74 | 75 | $ hg debugnodemap --metadata |
|
75 | 76 | uid: ???????? (glob) |
|
76 | 77 | tip-rev: 5000 |
|
77 | 78 | tip-node: 6b02b8c7b96654c25e86ba69eda198d7e6ad8b3c |
|
78 | 79 | data-length: 121088 |
|
79 | 80 | data-unused: 0 |
|
80 | 81 | data-unused: 0.000% |
|
81 | 82 | $ f --size .hg/store/00changelog.n |
|
82 | 83 | .hg/store/00changelog.n: size=62 |
|
83 | 84 | |
|
84 | 85 | Simple lookup works |
|
85 | 86 | |
|
86 | 87 | $ ANYNODE=`hg log --template '{node|short}\n' --rev tip` |
|
87 | 88 | $ hg log -r "$ANYNODE" --template '{rev}\n' |
|
88 | 89 | 5000 |
|
89 | 90 | |
|
90 | 91 | |
|
91 | 92 | #if rust |
|
92 | 93 | |
|
93 | 94 | $ f --sha256 .hg/store/00changelog-*.nd |
|
94 | 95 | .hg/store/00changelog-????????.nd: sha256=2e029d3200bd1a986b32784fc2ef1a3bd60dc331f025718bcf5ff44d93f026fd (glob) |
|
95 | 96 | |
|
96 | 97 | $ f --sha256 .hg/store/00manifest-*.nd |
|
97 | 98 | .hg/store/00manifest-????????.nd: sha256=97117b1c064ea2f86664a124589e47db0e254e8d34739b5c5cc5bf31c9da2b51 (glob) |
|
98 | 99 | $ hg debugnodemap --dump-new | f --sha256 --size |
|
99 | 100 | size=121088, sha256=2e029d3200bd1a986b32784fc2ef1a3bd60dc331f025718bcf5ff44d93f026fd |
|
100 | 101 | $ hg debugnodemap --dump-disk | f --sha256 --bytes=256 --hexdump --size |
|
101 | 102 | size=121088, sha256=2e029d3200bd1a986b32784fc2ef1a3bd60dc331f025718bcf5ff44d93f026fd |
|
102 | 103 | 0000: 00 00 00 91 00 00 00 20 00 00 00 bb 00 00 00 e7 |....... ........| |
|
103 | 104 | 0010: 00 00 00 66 00 00 00 a1 00 00 01 13 00 00 01 22 |...f..........."| |
|
104 | 105 | 0020: 00 00 00 23 00 00 00 fc 00 00 00 ba 00 00 00 5e |...#...........^| |
|
105 | 106 | 0030: 00 00 00 df 00 00 01 4e 00 00 01 65 00 00 00 ab |.......N...e....| |
|
106 | 107 | 0040: 00 00 00 a9 00 00 00 95 00 00 00 73 00 00 00 38 |...........s...8| |
|
107 | 108 | 0050: 00 00 00 cc 00 00 00 92 00 00 00 90 00 00 00 69 |...............i| |
|
108 | 109 | 0060: 00 00 00 ec 00 00 00 8d 00 00 01 4f 00 00 00 12 |...........O....| |
|
109 | 110 | 0070: 00 00 02 0c 00 00 00 77 00 00 00 9c 00 00 00 8f |.......w........| |
|
110 | 111 | 0080: 00 00 00 d5 00 00 00 6b 00 00 00 48 00 00 00 b3 |.......k...H....| |
|
111 | 112 | 0090: 00 00 00 e5 00 00 00 b5 00 00 00 8e 00 00 00 ad |................| |
|
112 | 113 | 00a0: 00 00 00 7b 00 00 00 7c 00 00 00 0b 00 00 00 2b |...{...|.......+| |
|
113 | 114 | 00b0: 00 00 00 c6 00 00 00 1e 00 00 01 08 00 00 00 11 |................| |
|
114 | 115 | 00c0: 00 00 01 30 00 00 00 26 00 00 01 9c 00 00 00 35 |...0...&.......5| |
|
115 | 116 | 00d0: 00 00 00 b8 00 00 01 31 00 00 00 2c 00 00 00 55 |.......1...,...U| |
|
116 | 117 | 00e0: 00 00 00 8a 00 00 00 9a 00 00 00 0c 00 00 01 1e |................| |
|
117 | 118 | 00f0: 00 00 00 a4 00 00 00 83 00 00 00 c9 00 00 00 8c |................| |
|
118 | 119 | |
|
119 | 120 | |
|
120 | 121 | #else |
|
121 | 122 | |
|
122 | 123 | $ f --sha256 .hg/store/00changelog-*.nd |
|
123 | 124 | .hg/store/00changelog-????????.nd: sha256=f544f5462ff46097432caf6d764091f6d8c46d6121be315ead8576d548c9dd79 (glob) |
|
124 | 125 | $ hg debugnodemap --dump-new | f --sha256 --size |
|
125 | 126 | size=121088, sha256=f544f5462ff46097432caf6d764091f6d8c46d6121be315ead8576d548c9dd79 |
|
126 | 127 | $ hg debugnodemap --dump-disk | f --sha256 --bytes=256 --hexdump --size |
|
127 | 128 | size=121088, sha256=f544f5462ff46097432caf6d764091f6d8c46d6121be315ead8576d548c9dd79 |
|
128 | 129 | 0000: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................| |
|
129 | 130 | 0010: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................| |
|
130 | 131 | 0020: ff ff ff ff ff ff f5 06 ff ff ff ff ff ff f3 e7 |................| |
|
131 | 132 | 0030: ff ff ef ca ff ff ff ff ff ff ff ff ff ff ff ff |................| |
|
132 | 133 | 0040: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................| |
|
133 | 134 | 0050: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ed 08 |................| |
|
134 | 135 | 0060: ff ff ed 66 ff ff ff ff ff ff ff ff ff ff ff ff |...f............| |
|
135 | 136 | 0070: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................| |
|
136 | 137 | 0080: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................| |
|
137 | 138 | 0090: ff ff ff ff ff ff ff ff ff ff ff ff ff ff f6 ed |................| |
|
138 | 139 | 00a0: ff ff ff ff ff ff fe 61 ff ff ff ff ff ff ff ff |.......a........| |
|
139 | 140 | 00b0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................| |
|
140 | 141 | 00c0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................| |
|
141 | 142 | 00d0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff ff |................| |
|
142 | 143 | 00e0: ff ff ff ff ff ff ff ff ff ff ff ff ff ff f1 02 |................| |
|
143 | 144 | 00f0: ff ff ff ff ff ff ed 1b ff ff ff ff ff ff ff ff |................| |
|
144 | 145 | |
|
145 | 146 | #endif |
|
146 | 147 | |
|
147 | 148 | $ hg debugnodemap --check |
|
148 | 149 | revision in index: 5001 |
|
149 | 150 | revision in nodemap: 5001 |
|
150 | 151 | |
|
151 | 152 | add a new commit |
|
152 | 153 | |
|
153 | 154 | $ hg up |
|
154 | 155 | 5001 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
155 | 156 | $ echo foo > foo |
|
156 | 157 | $ hg add foo |
|
157 | 158 | |
|
158 | 159 | |
|
159 | 160 | Check slow-path config value handling |
|
160 | 161 | ------------------------------------- |
|
161 | 162 | |
|
162 | 163 | #if no-pure no-rust |
|
163 | 164 | |
|
164 | 165 | $ hg id --config "storage.revlog.persistent-nodemap.slow-path=invalid-value" |
|
165 | 166 | unknown value for config "storage.revlog.persistent-nodemap.slow-path": "invalid-value" |
|
166 | 167 | falling back to default value: abort |
|
167 | 168 | abort: accessing `persistent-nodemap` repository without associated fast implementation. |
|
168 | 169 | (check `hg help config.format.use-persistent-nodemap` for details) |
|
169 | 170 | [255] |
|
170 | 171 | |
|
171 | 172 | $ hg log -r . --config "storage.revlog.persistent-nodemap.slow-path=warn" |
|
172 | 173 | warning: accessing `persistent-nodemap` repository without associated fast implementation. |
|
173 | 174 | (check `hg help config.format.use-persistent-nodemap` for details) |
|
174 | 175 | changeset: 5000:6b02b8c7b966 |
|
175 | 176 | tag: tip |
|
176 | 177 | user: debugbuilddag |
|
177 | 178 | date: Thu Jan 01 01:23:20 1970 +0000 |
|
178 | 179 | summary: r5000 |
|
179 | 180 | |
|
180 | 181 | $ hg ci -m 'foo' --config "storage.revlog.persistent-nodemap.slow-path=abort" |
|
181 | 182 | abort: accessing `persistent-nodemap` repository without associated fast implementation. |
|
182 | 183 | (check `hg help config.format.use-persistent-nodemap` for details) |
|
183 | 184 | [255] |
|
184 | 185 | |
|
185 | 186 | #else |
|
186 | 187 | |
|
187 | 188 | $ hg id --config "storage.revlog.persistent-nodemap.slow-path=invalid-value" |
|
188 | 189 | unknown value for config "storage.revlog.persistent-nodemap.slow-path": "invalid-value" |
|
189 | 190 | falling back to default value: abort |
|
190 | 191 | 6b02b8c7b966+ tip |
|
191 | 192 | |
|
192 | 193 | #endif |
|
193 | 194 | |
|
194 | 195 | $ hg ci -m 'foo' |
|
195 | 196 | |
|
196 | 197 | #if no-pure no-rust |
|
197 | 198 | $ hg debugnodemap --metadata |
|
198 | 199 | uid: ???????? (glob) |
|
199 | 200 | tip-rev: 5001 |
|
200 | 201 | tip-node: 16395c3cf7e231394735e6b1717823ada303fb0c |
|
201 | 202 | data-length: 121088 |
|
202 | 203 | data-unused: 0 |
|
203 | 204 | data-unused: 0.000% |
|
204 | 205 | #else |
|
205 | 206 | $ hg debugnodemap --metadata |
|
206 | 207 | uid: ???????? (glob) |
|
207 | 208 | tip-rev: 5001 |
|
208 | 209 | tip-node: 16395c3cf7e231394735e6b1717823ada303fb0c |
|
209 | 210 | data-length: 121344 |
|
210 | 211 | data-unused: 256 |
|
211 | 212 | data-unused: 0.211% |
|
212 | 213 | #endif |
|
213 | 214 | |
|
214 | 215 | $ f --size .hg/store/00changelog.n |
|
215 | 216 | .hg/store/00changelog.n: size=62 |
|
216 | 217 | |
|
217 | 218 | (The pure code use the debug code that perform incremental update, the C code reencode from scratch) |
|
218 | 219 | |
|
219 | 220 | #if pure |
|
220 | 221 | $ f --sha256 .hg/store/00changelog-*.nd --size |
|
221 | 222 | .hg/store/00changelog-????????.nd: size=121344, sha256=cce54c5da5bde3ad72a4938673ed4064c86231b9c64376b082b163fdb20f8f66 (glob) |
|
222 | 223 | #endif |
|
223 | 224 | |
|
224 | 225 | #if rust |
|
225 | 226 | $ f --sha256 .hg/store/00changelog-*.nd --size |
|
226 | 227 | .hg/store/00changelog-????????.nd: size=121344, sha256=952b042fcf614ceb37b542b1b723e04f18f83efe99bee4e0f5ccd232ef470e58 (glob) |
|
227 | 228 | #endif |
|
228 | 229 | |
|
229 | 230 | #if no-pure no-rust |
|
230 | 231 | $ f --sha256 .hg/store/00changelog-*.nd --size |
|
231 | 232 | .hg/store/00changelog-????????.nd: size=121088, sha256=df7c06a035b96cb28c7287d349d603baef43240be7736fe34eea419a49702e17 (glob) |
|
232 | 233 | #endif |
|
233 | 234 | |
|
234 | 235 | $ hg debugnodemap --check |
|
235 | 236 | revision in index: 5002 |
|
236 | 237 | revision in nodemap: 5002 |
|
237 | 238 | |
|
238 | 239 | Test code path without mmap |
|
239 | 240 | --------------------------- |
|
240 | 241 | |
|
241 | 242 | $ echo bar > bar |
|
242 | 243 | $ hg add bar |
|
243 | 244 | $ hg ci -m 'bar' --config storage.revlog.persistent-nodemap.mmap=no |
|
244 | 245 | |
|
245 | 246 | $ hg debugnodemap --check --config storage.revlog.persistent-nodemap.mmap=yes |
|
246 | 247 | revision in index: 5003 |
|
247 | 248 | revision in nodemap: 5003 |
|
248 | 249 | $ hg debugnodemap --check --config storage.revlog.persistent-nodemap.mmap=no |
|
249 | 250 | revision in index: 5003 |
|
250 | 251 | revision in nodemap: 5003 |
|
251 | 252 | |
|
252 | 253 | |
|
253 | 254 | #if pure |
|
254 | 255 | $ hg debugnodemap --metadata |
|
255 | 256 | uid: ???????? (glob) |
|
256 | 257 | tip-rev: 5002 |
|
257 | 258 | tip-node: 880b18d239dfa9f632413a2071bfdbcc4806a4fd |
|
258 | 259 | data-length: 121600 |
|
259 | 260 | data-unused: 512 |
|
260 | 261 | data-unused: 0.421% |
|
261 | 262 | $ f --sha256 .hg/store/00changelog-*.nd --size |
|
262 | 263 | .hg/store/00changelog-????????.nd: size=121600, sha256=def52503d049ccb823974af313a98a935319ba61f40f3aa06a8be4d35c215054 (glob) |
|
263 | 264 | #endif |
|
264 | 265 | #if rust |
|
265 | 266 | $ hg debugnodemap --metadata |
|
266 | 267 | uid: ???????? (glob) |
|
267 | 268 | tip-rev: 5002 |
|
268 | 269 | tip-node: 880b18d239dfa9f632413a2071bfdbcc4806a4fd |
|
269 | 270 | data-length: 121600 |
|
270 | 271 | data-unused: 512 |
|
271 | 272 | data-unused: 0.421% |
|
272 | 273 | $ f --sha256 .hg/store/00changelog-*.nd --size |
|
273 | 274 | .hg/store/00changelog-????????.nd: size=121600, sha256=dacf5b5f1d4585fee7527d0e67cad5b1ba0930e6a0928f650f779aefb04ce3fb (glob) |
|
274 | 275 | #endif |
|
275 | 276 | #if no-pure no-rust |
|
276 | 277 | $ hg debugnodemap --metadata |
|
277 | 278 | uid: ???????? (glob) |
|
278 | 279 | tip-rev: 5002 |
|
279 | 280 | tip-node: 880b18d239dfa9f632413a2071bfdbcc4806a4fd |
|
280 | 281 | data-length: 121088 |
|
281 | 282 | data-unused: 0 |
|
282 | 283 | data-unused: 0.000% |
|
283 | 284 | $ f --sha256 .hg/store/00changelog-*.nd --size |
|
284 | 285 | .hg/store/00changelog-????????.nd: size=121088, sha256=59fcede3e3cc587755916ceed29e3c33748cd1aa7d2f91828ac83e7979d935e8 (glob) |
|
285 | 286 | #endif |
|
286 | 287 | |
|
287 | 288 | Test force warming the cache |
|
288 | 289 | |
|
289 | 290 | $ rm .hg/store/00changelog.n |
|
290 | 291 | $ hg debugnodemap --metadata |
|
291 | 292 | $ hg debugupdatecache |
|
292 | 293 | #if pure |
|
293 | 294 | $ hg debugnodemap --metadata |
|
294 | 295 | uid: ???????? (glob) |
|
295 | 296 | tip-rev: 5002 |
|
296 | 297 | tip-node: 880b18d239dfa9f632413a2071bfdbcc4806a4fd |
|
297 | 298 | data-length: 121088 |
|
298 | 299 | data-unused: 0 |
|
299 | 300 | data-unused: 0.000% |
|
300 | 301 | #else |
|
301 | 302 | $ hg debugnodemap --metadata |
|
302 | 303 | uid: ???????? (glob) |
|
303 | 304 | tip-rev: 5002 |
|
304 | 305 | tip-node: 880b18d239dfa9f632413a2071bfdbcc4806a4fd |
|
305 | 306 | data-length: 121088 |
|
306 | 307 | data-unused: 0 |
|
307 | 308 | data-unused: 0.000% |
|
308 | 309 | #endif |
|
309 | 310 | |
|
310 | 311 | Check out of sync nodemap |
|
311 | 312 | ========================= |
|
312 | 313 | |
|
313 | 314 | First copy old data on the side. |
|
314 | 315 | |
|
315 | 316 | $ mkdir ../tmp-copies |
|
316 | 317 | $ cp .hg/store/00changelog-????????.nd .hg/store/00changelog.n ../tmp-copies |
|
317 | 318 | |
|
318 | 319 | Nodemap lagging behind |
|
319 | 320 | ---------------------- |
|
320 | 321 | |
|
321 | 322 | make a new commit |
|
322 | 323 | |
|
323 | 324 | $ echo bar2 > bar |
|
324 | 325 | $ hg ci -m 'bar2' |
|
325 | 326 | $ NODE=`hg log -r tip -T '{node}\n'` |
|
326 | 327 | $ hg log -r "$NODE" -T '{rev}\n' |
|
327 | 328 | 5003 |
|
328 | 329 | |
|
329 | 330 | If the nodemap is lagging behind, it can catch up fine |
|
330 | 331 | |
|
331 | 332 | $ hg debugnodemap --metadata |
|
332 | 333 | uid: ???????? (glob) |
|
333 | 334 | tip-rev: 5003 |
|
334 | 335 | tip-node: c9329770f979ade2d16912267c38ba5f82fd37b3 |
|
335 | 336 | data-length: 121344 (pure !) |
|
336 | 337 | data-length: 121344 (rust !) |
|
337 | 338 | data-length: 121152 (no-rust no-pure !) |
|
338 | 339 | data-unused: 192 (pure !) |
|
339 | 340 | data-unused: 192 (rust !) |
|
340 | 341 | data-unused: 0 (no-rust no-pure !) |
|
341 | 342 | data-unused: 0.158% (pure !) |
|
342 | 343 | data-unused: 0.158% (rust !) |
|
343 | 344 | data-unused: 0.000% (no-rust no-pure !) |
|
344 | 345 | $ cp -f ../tmp-copies/* .hg/store/ |
|
345 | 346 | $ hg debugnodemap --metadata |
|
346 | 347 | uid: ???????? (glob) |
|
347 | 348 | tip-rev: 5002 |
|
348 | 349 | tip-node: 880b18d239dfa9f632413a2071bfdbcc4806a4fd |
|
349 | 350 | data-length: 121088 |
|
350 | 351 | data-unused: 0 |
|
351 | 352 | data-unused: 0.000% |
|
352 | 353 | $ hg log -r "$NODE" -T '{rev}\n' |
|
353 | 354 | 5003 |
|
354 | 355 | |
|
355 | 356 | changelog altered |
|
356 | 357 | ----------------- |
|
357 | 358 | |
|
358 | 359 | If the nodemap is not gated behind a requirements, an unaware client can alter |
|
359 | 360 | the repository so the revlog used to generate the nodemap is not longer |
|
360 | 361 | compatible with the persistent nodemap. We need to detect that. |
|
361 | 362 | |
|
362 | 363 | $ hg up "$NODE~5" |
|
363 | 364 | 0 files updated, 0 files merged, 4 files removed, 0 files unresolved |
|
364 | 365 | $ echo bar > babar |
|
365 | 366 | $ hg add babar |
|
366 | 367 | $ hg ci -m 'babar' |
|
367 | 368 | created new head |
|
368 | 369 | $ OTHERNODE=`hg log -r tip -T '{node}\n'` |
|
369 | 370 | $ hg log -r "$OTHERNODE" -T '{rev}\n' |
|
370 | 371 | 5004 |
|
371 | 372 | |
|
372 | 373 | $ hg --config extensions.strip= strip --rev "$NODE~1" --no-backup |
|
373 | 374 | |
|
374 | 375 | the nodemap should detect the changelog have been tampered with and recover. |
|
375 | 376 | |
|
376 | 377 | $ hg debugnodemap --metadata |
|
377 | 378 | uid: ???????? (glob) |
|
378 | 379 | tip-rev: 5002 |
|
379 | 380 | tip-node: b355ef8adce0949b8bdf6afc72ca853740d65944 |
|
380 | 381 | data-length: 121536 (pure !) |
|
381 | 382 | data-length: 121088 (rust !) |
|
382 | 383 | data-length: 121088 (no-pure no-rust !) |
|
383 | 384 | data-unused: 448 (pure !) |
|
384 | 385 | data-unused: 0 (rust !) |
|
385 | 386 | data-unused: 0 (no-pure no-rust !) |
|
386 | 387 | data-unused: 0.000% (rust !) |
|
387 | 388 | data-unused: 0.369% (pure !) |
|
388 | 389 | data-unused: 0.000% (no-pure no-rust !) |
|
389 | 390 | |
|
390 | 391 | $ cp -f ../tmp-copies/* .hg/store/ |
|
391 | 392 | $ hg debugnodemap --metadata |
|
392 | 393 | uid: ???????? (glob) |
|
393 | 394 | tip-rev: 5002 |
|
394 | 395 | tip-node: 880b18d239dfa9f632413a2071bfdbcc4806a4fd |
|
395 | 396 | data-length: 121088 |
|
396 | 397 | data-unused: 0 |
|
397 | 398 | data-unused: 0.000% |
|
398 | 399 | $ hg log -r "$OTHERNODE" -T '{rev}\n' |
|
399 | 400 | 5002 |
|
400 | 401 | |
|
401 | 402 | missing data file |
|
402 | 403 | ----------------- |
|
403 | 404 | |
|
404 | 405 | $ UUID=`hg debugnodemap --metadata| grep 'uid:' | \ |
|
405 | 406 | > sed 's/uid: //'` |
|
406 | 407 | $ FILE=.hg/store/00changelog-"${UUID}".nd |
|
407 | 408 | $ mv $FILE ../tmp-data-file |
|
408 | 409 | $ cp .hg/store/00changelog.n ../tmp-docket |
|
409 | 410 | |
|
410 | 411 | mercurial don't crash |
|
411 | 412 | |
|
412 | 413 | $ hg log -r . |
|
413 | 414 | changeset: 5002:b355ef8adce0 |
|
414 | 415 | tag: tip |
|
415 | 416 | parent: 4998:d918ad6d18d3 |
|
416 | 417 | user: test |
|
417 | 418 | date: Thu Jan 01 00:00:00 1970 +0000 |
|
418 | 419 | summary: babar |
|
419 | 420 | |
|
420 | 421 | $ hg debugnodemap --metadata |
|
421 | 422 | |
|
422 | 423 | $ hg debugupdatecache |
|
423 | 424 | $ hg debugnodemap --metadata |
|
424 | 425 | uid: * (glob) |
|
425 | 426 | tip-rev: 5002 |
|
426 | 427 | tip-node: b355ef8adce0949b8bdf6afc72ca853740d65944 |
|
427 | 428 | data-length: 121088 |
|
428 | 429 | data-unused: 0 |
|
429 | 430 | data-unused: 0.000% |
|
430 | 431 | $ mv ../tmp-data-file $FILE |
|
431 | 432 | $ mv ../tmp-docket .hg/store/00changelog.n |
|
432 | 433 | |
|
433 | 434 | Check transaction related property |
|
434 | 435 | ================================== |
|
435 | 436 | |
|
436 | 437 | An up to date nodemap should be available to shell hooks, |
|
437 | 438 | |
|
438 | 439 | $ echo dsljfl > a |
|
439 | 440 | $ hg add a |
|
440 | 441 | $ hg ci -m a |
|
441 | 442 | $ hg debugnodemap --metadata |
|
442 | 443 | uid: ???????? (glob) |
|
443 | 444 | tip-rev: 5003 |
|
444 | 445 | tip-node: a52c5079765b5865d97b993b303a18740113bbb2 |
|
445 | 446 | data-length: 121088 |
|
446 | 447 | data-unused: 0 |
|
447 | 448 | data-unused: 0.000% |
|
448 | 449 | $ echo babar2 > babar |
|
449 | 450 | $ hg ci -m 'babar2' --config "hooks.pretxnclose.nodemap-test=hg debugnodemap --metadata" |
|
450 | 451 | uid: ???????? (glob) |
|
451 | 452 | tip-rev: 5004 |
|
452 | 453 | tip-node: 2f5fb1c06a16834c5679d672e90da7c5f3b1a984 |
|
453 | 454 | data-length: 121280 (pure !) |
|
454 | 455 | data-length: 121280 (rust !) |
|
455 | 456 | data-length: 121088 (no-pure no-rust !) |
|
456 | 457 | data-unused: 192 (pure !) |
|
457 | 458 | data-unused: 192 (rust !) |
|
458 | 459 | data-unused: 0 (no-pure no-rust !) |
|
459 | 460 | data-unused: 0.158% (pure !) |
|
460 | 461 | data-unused: 0.158% (rust !) |
|
461 | 462 | data-unused: 0.000% (no-pure no-rust !) |
|
462 | 463 | $ hg debugnodemap --metadata |
|
463 | 464 | uid: ???????? (glob) |
|
464 | 465 | tip-rev: 5004 |
|
465 | 466 | tip-node: 2f5fb1c06a16834c5679d672e90da7c5f3b1a984 |
|
466 | 467 | data-length: 121280 (pure !) |
|
467 | 468 | data-length: 121280 (rust !) |
|
468 | 469 | data-length: 121088 (no-pure no-rust !) |
|
469 | 470 | data-unused: 192 (pure !) |
|
470 | 471 | data-unused: 192 (rust !) |
|
471 | 472 | data-unused: 0 (no-pure no-rust !) |
|
472 | 473 | data-unused: 0.158% (pure !) |
|
473 | 474 | data-unused: 0.158% (rust !) |
|
474 | 475 | data-unused: 0.000% (no-pure no-rust !) |
|
475 | 476 | |
|
476 | 477 | Another process does not see the pending nodemap content during run. |
|
477 | 478 | |
|
478 | 479 | $ echo qpoasp > a |
|
479 | 480 | $ hg ci -m a2 \ |
|
480 | 481 | > --config "hooks.pretxnclose=sh \"$RUNTESTDIR/testlib/wait-on-file\" 20 sync-repo-read sync-txn-pending" \ |
|
481 | 482 | > --config "hooks.txnclose=touch sync-txn-close" > output.txt 2>&1 & |
|
482 | 483 | |
|
483 | 484 | (read the repository while the commit transaction is pending) |
|
484 | 485 | |
|
485 | 486 | $ sh "$RUNTESTDIR/testlib/wait-on-file" 20 sync-txn-pending && \ |
|
486 | 487 | > hg debugnodemap --metadata && \ |
|
487 | 488 | > sh "$RUNTESTDIR/testlib/wait-on-file" 20 sync-txn-close sync-repo-read |
|
488 | 489 | uid: ???????? (glob) |
|
489 | 490 | tip-rev: 5004 |
|
490 | 491 | tip-node: 2f5fb1c06a16834c5679d672e90da7c5f3b1a984 |
|
491 | 492 | data-length: 121280 (pure !) |
|
492 | 493 | data-length: 121280 (rust !) |
|
493 | 494 | data-length: 121088 (no-pure no-rust !) |
|
494 | 495 | data-unused: 192 (pure !) |
|
495 | 496 | data-unused: 192 (rust !) |
|
496 | 497 | data-unused: 0 (no-pure no-rust !) |
|
497 | 498 | data-unused: 0.158% (pure !) |
|
498 | 499 | data-unused: 0.158% (rust !) |
|
499 | 500 | data-unused: 0.000% (no-pure no-rust !) |
|
500 | 501 | $ hg debugnodemap --metadata |
|
501 | 502 | uid: ???????? (glob) |
|
502 | 503 | tip-rev: 5005 |
|
503 | 504 | tip-node: 90d5d3ba2fc47db50f712570487cb261a68c8ffe |
|
504 | 505 | data-length: 121536 (pure !) |
|
505 | 506 | data-length: 121536 (rust !) |
|
506 | 507 | data-length: 121088 (no-pure no-rust !) |
|
507 | 508 | data-unused: 448 (pure !) |
|
508 | 509 | data-unused: 448 (rust !) |
|
509 | 510 | data-unused: 0 (no-pure no-rust !) |
|
510 | 511 | data-unused: 0.369% (pure !) |
|
511 | 512 | data-unused: 0.369% (rust !) |
|
512 | 513 | data-unused: 0.000% (no-pure no-rust !) |
|
513 | 514 | |
|
514 | 515 | $ cat output.txt |
|
515 | 516 | |
|
516 | 517 | Check that a failing transaction will properly revert the data |
|
517 | 518 | |
|
518 | 519 | $ echo plakfe > a |
|
519 | 520 | $ f --size --sha256 .hg/store/00changelog-*.nd |
|
520 | 521 | .hg/store/00changelog-????????.nd: size=121536, sha256=bb414468d225cf52d69132e1237afba34d4346ee2eb81b505027e6197b107f03 (glob) (pure !) |
|
521 | 522 | .hg/store/00changelog-????????.nd: size=121536, sha256=909ac727bc4d1c0fda5f7bff3c620c98bd4a2967c143405a1503439e33b377da (glob) (rust !) |
|
522 | 523 | .hg/store/00changelog-????????.nd: size=121088, sha256=342d36d30d86dde67d3cb6c002606c4a75bcad665595d941493845066d9c8ee0 (glob) (no-pure no-rust !) |
|
523 | 524 | $ hg ci -m a3 --config "extensions.abort=$RUNTESTDIR/testlib/crash_transaction_late.py" |
|
524 | 525 | transaction abort! |
|
525 | 526 | rollback completed |
|
526 | 527 | abort: This is a late abort |
|
527 | 528 | [255] |
|
528 | 529 | $ hg debugnodemap --metadata |
|
529 | 530 | uid: ???????? (glob) |
|
530 | 531 | tip-rev: 5005 |
|
531 | 532 | tip-node: 90d5d3ba2fc47db50f712570487cb261a68c8ffe |
|
532 | 533 | data-length: 121536 (pure !) |
|
533 | 534 | data-length: 121536 (rust !) |
|
534 | 535 | data-length: 121088 (no-pure no-rust !) |
|
535 | 536 | data-unused: 448 (pure !) |
|
536 | 537 | data-unused: 448 (rust !) |
|
537 | 538 | data-unused: 0 (no-pure no-rust !) |
|
538 | 539 | data-unused: 0.369% (pure !) |
|
539 | 540 | data-unused: 0.369% (rust !) |
|
540 | 541 | data-unused: 0.000% (no-pure no-rust !) |
|
541 | 542 | $ f --size --sha256 .hg/store/00changelog-*.nd |
|
542 | 543 | .hg/store/00changelog-????????.nd: size=121536, sha256=bb414468d225cf52d69132e1237afba34d4346ee2eb81b505027e6197b107f03 (glob) (pure !) |
|
543 | 544 | .hg/store/00changelog-????????.nd: size=121536, sha256=909ac727bc4d1c0fda5f7bff3c620c98bd4a2967c143405a1503439e33b377da (glob) (rust !) |
|
544 | 545 | .hg/store/00changelog-????????.nd: size=121088, sha256=342d36d30d86dde67d3cb6c002606c4a75bcad665595d941493845066d9c8ee0 (glob) (no-pure no-rust !) |
|
545 | 546 | |
|
546 | 547 | Check that removing content does not confuse the nodemap |
|
547 | 548 | -------------------------------------------------------- |
|
548 | 549 | |
|
549 | 550 | removing data with rollback |
|
550 | 551 | |
|
551 | 552 | $ echo aso > a |
|
552 | 553 | $ hg ci -m a4 |
|
553 | 554 | $ hg rollback |
|
554 | 555 | repository tip rolled back to revision 5005 (undo commit) |
|
555 | 556 | working directory now based on revision 5005 |
|
556 | 557 | $ hg id -r . |
|
557 | 558 | 90d5d3ba2fc4 tip |
|
558 | 559 | |
|
559 | 560 | roming data with strip |
|
560 | 561 | |
|
561 | 562 | $ echo aso > a |
|
562 | 563 | $ hg ci -m a4 |
|
563 | 564 | $ hg --config extensions.strip= strip -r . --no-backup |
|
564 | 565 | 1 files updated, 0 files merged, 0 files removed, 0 files unresolved |
|
565 | 566 | $ hg id -r . --traceback |
|
566 | 567 | 90d5d3ba2fc4 tip |
|
567 | 568 | |
|
568 | 569 | Test upgrade / downgrade |
|
569 | 570 | ======================== |
|
570 | 571 | |
|
571 | 572 | downgrading |
|
572 | 573 | |
|
573 | 574 | $ cat << EOF >> .hg/hgrc |
|
574 | 575 | > [format] |
|
575 | 576 | > use-persistent-nodemap=no |
|
576 | 577 | > EOF |
|
577 | 578 | $ hg debugformat -v |
|
578 | 579 | format-variant repo config default |
|
579 | 580 | fncache: yes yes yes |
|
581 | dirstate-v2: no no no | |
|
580 | 582 | dotencode: yes yes yes |
|
581 | 583 | generaldelta: yes yes yes |
|
582 | 584 | share-safe: no no no |
|
583 | 585 | sparserevlog: yes yes yes |
|
584 | 586 | persistent-nodemap: yes no no |
|
585 | 587 | copies-sdc: no no no |
|
586 | 588 | revlog-v2: no no no |
|
587 | 589 | changelog-v2: no no no |
|
588 | 590 | plain-cl-delta: yes yes yes |
|
589 | 591 | compression: zlib zlib zlib (no-zstd !) |
|
590 | 592 | compression: zstd zstd zstd (zstd !) |
|
591 | 593 | compression-level: default default default |
|
592 | 594 | $ hg debugupgraderepo --run --no-backup |
|
593 | 595 | upgrade will perform the following actions: |
|
594 | 596 | |
|
595 | 597 | requirements |
|
596 | 598 | preserved: dotencode, fncache, generaldelta, revlogv1, sparserevlog, store (no-zstd no-dirstate-v2 !) |
|
597 | 599 | preserved: dotencode, fncache, generaldelta, revlog-compression-zstd, revlogv1, sparserevlog, store (zstd no-dirstate-v2 !) |
|
598 | 600 | preserved: dotencode, exp-dirstate-v2, fncache, generaldelta, revlog-compression-zstd, revlogv1, sparserevlog, store (zstd dirstate-v2 !) |
|
599 | 601 | removed: persistent-nodemap |
|
600 | 602 | |
|
601 | 603 | processed revlogs: |
|
602 | 604 | - all-filelogs |
|
603 | 605 | - changelog |
|
604 | 606 | - manifest |
|
605 | 607 | |
|
606 | 608 | beginning upgrade... |
|
607 | 609 | repository locked and read-only |
|
608 | 610 | creating temporary repository to stage upgraded data: $TESTTMP/test-repo/.hg/upgrade.* (glob) |
|
609 | 611 | (it is safe to interrupt this process any time before data migration completes) |
|
610 | 612 | downgrading repository to not use persistent nodemap feature |
|
611 | 613 | removing temporary repository $TESTTMP/test-repo/.hg/upgrade.* (glob) |
|
612 | 614 | $ ls -1 .hg/store/ | egrep '00(changelog|manifest)(\.n|-.*\.nd)' |
|
613 | 615 | 00changelog-*.nd (glob) |
|
614 | 616 | 00manifest-*.nd (glob) |
|
615 | 617 | undo.backup.00changelog.n |
|
616 | 618 | undo.backup.00manifest.n |
|
617 | 619 | $ hg debugnodemap --metadata |
|
618 | 620 | |
|
619 | 621 | |
|
620 | 622 | upgrading |
|
621 | 623 | |
|
622 | 624 | $ cat << EOF >> .hg/hgrc |
|
623 | 625 | > [format] |
|
624 | 626 | > use-persistent-nodemap=yes |
|
625 | 627 | > EOF |
|
626 | 628 | $ hg debugformat -v |
|
627 | 629 | format-variant repo config default |
|
628 | 630 | fncache: yes yes yes |
|
631 | dirstate-v2: no no no | |
|
629 | 632 | dotencode: yes yes yes |
|
630 | 633 | generaldelta: yes yes yes |
|
631 | 634 | share-safe: no no no |
|
632 | 635 | sparserevlog: yes yes yes |
|
633 | 636 | persistent-nodemap: no yes no |
|
634 | 637 | copies-sdc: no no no |
|
635 | 638 | revlog-v2: no no no |
|
636 | 639 | changelog-v2: no no no |
|
637 | 640 | plain-cl-delta: yes yes yes |
|
638 | 641 | compression: zlib zlib zlib (no-zstd !) |
|
639 | 642 | compression: zstd zstd zstd (zstd !) |
|
640 | 643 | compression-level: default default default |
|
641 | 644 | $ hg debugupgraderepo --run --no-backup |
|
642 | 645 | upgrade will perform the following actions: |
|
643 | 646 | |
|
644 | 647 | requirements |
|
645 | 648 | preserved: dotencode, fncache, generaldelta, revlogv1, sparserevlog, store (no-zstd no-dirstate-v2 !) |
|
646 | 649 | preserved: dotencode, fncache, generaldelta, revlog-compression-zstd, revlogv1, sparserevlog, store (zstd no-dirstate-v2 !) |
|
647 | 650 | preserved: dotencode, exp-dirstate-v2, fncache, generaldelta, revlog-compression-zstd, revlogv1, sparserevlog, store (zstd dirstate-v2 !) |
|
648 | 651 | added: persistent-nodemap |
|
649 | 652 | |
|
650 | 653 | persistent-nodemap |
|
651 | 654 | Speedup revision lookup by node id. |
|
652 | 655 | |
|
653 | 656 | processed revlogs: |
|
654 | 657 | - all-filelogs |
|
655 | 658 | - changelog |
|
656 | 659 | - manifest |
|
657 | 660 | |
|
658 | 661 | beginning upgrade... |
|
659 | 662 | repository locked and read-only |
|
660 | 663 | creating temporary repository to stage upgraded data: $TESTTMP/test-repo/.hg/upgrade.* (glob) |
|
661 | 664 | (it is safe to interrupt this process any time before data migration completes) |
|
662 | 665 | upgrading repository to use persistent nodemap feature |
|
663 | 666 | removing temporary repository $TESTTMP/test-repo/.hg/upgrade.* (glob) |
|
664 | 667 | $ ls -1 .hg/store/ | egrep '00(changelog|manifest)(\.n|-.*\.nd)' |
|
665 | 668 | 00changelog-*.nd (glob) |
|
666 | 669 | 00changelog.n |
|
667 | 670 | 00manifest-*.nd (glob) |
|
668 | 671 | 00manifest.n |
|
669 | 672 | undo.backup.00changelog.n |
|
670 | 673 | undo.backup.00manifest.n |
|
671 | 674 | |
|
672 | 675 | $ hg debugnodemap --metadata |
|
673 | 676 | uid: * (glob) |
|
674 | 677 | tip-rev: 5005 |
|
675 | 678 | tip-node: 90d5d3ba2fc47db50f712570487cb261a68c8ffe |
|
676 | 679 | data-length: 121088 |
|
677 | 680 | data-unused: 0 |
|
678 | 681 | data-unused: 0.000% |
|
679 | 682 | |
|
680 | 683 | Running unrelated upgrade |
|
681 | 684 | |
|
682 | 685 | $ hg debugupgraderepo --run --no-backup --quiet --optimize re-delta-all |
|
683 | 686 | upgrade will perform the following actions: |
|
684 | 687 | |
|
685 | 688 | requirements |
|
686 | 689 | preserved: dotencode, fncache, generaldelta, persistent-nodemap, revlogv1, sparserevlog, store (no-zstd no-dirstate-v2 !) |
|
687 | 690 | preserved: dotencode, fncache, generaldelta, persistent-nodemap, revlog-compression-zstd, revlogv1, sparserevlog, store (zstd no-dirstate-v2 !) |
|
688 | 691 | preserved: dotencode, exp-dirstate-v2, fncache, generaldelta, persistent-nodemap, revlog-compression-zstd, revlogv1, sparserevlog, store (zstd dirstate-v2 !) |
|
689 | 692 | |
|
690 | 693 | optimisations: re-delta-all |
|
691 | 694 | |
|
692 | 695 | processed revlogs: |
|
693 | 696 | - all-filelogs |
|
694 | 697 | - changelog |
|
695 | 698 | - manifest |
|
696 | 699 | |
|
697 | 700 | $ ls -1 .hg/store/ | egrep '00(changelog|manifest)(\.n|-.*\.nd)' |
|
698 | 701 | 00changelog-*.nd (glob) |
|
699 | 702 | 00changelog.n |
|
700 | 703 | 00manifest-*.nd (glob) |
|
701 | 704 | 00manifest.n |
|
702 | 705 | |
|
703 | 706 | $ hg debugnodemap --metadata |
|
704 | 707 | uid: * (glob) |
|
705 | 708 | tip-rev: 5005 |
|
706 | 709 | tip-node: 90d5d3ba2fc47db50f712570487cb261a68c8ffe |
|
707 | 710 | data-length: 121088 |
|
708 | 711 | data-unused: 0 |
|
709 | 712 | data-unused: 0.000% |
|
710 | 713 | |
|
711 | 714 | Persistent nodemap and local/streaming clone |
|
712 | 715 | ============================================ |
|
713 | 716 | |
|
714 | 717 | $ cd .. |
|
715 | 718 | |
|
716 | 719 | standard clone |
|
717 | 720 | -------------- |
|
718 | 721 | |
|
719 | 722 | The persistent nodemap should exist after a streaming clone |
|
720 | 723 | |
|
721 | 724 | $ hg clone --pull --quiet -U test-repo standard-clone |
|
722 | 725 | $ ls -1 standard-clone/.hg/store/ | egrep '00(changelog|manifest)(\.n|-.*\.nd)' |
|
723 | 726 | 00changelog-*.nd (glob) |
|
724 | 727 | 00changelog.n |
|
725 | 728 | 00manifest-*.nd (glob) |
|
726 | 729 | 00manifest.n |
|
727 | 730 | $ hg -R standard-clone debugnodemap --metadata |
|
728 | 731 | uid: * (glob) |
|
729 | 732 | tip-rev: 5005 |
|
730 | 733 | tip-node: 90d5d3ba2fc47db50f712570487cb261a68c8ffe |
|
731 | 734 | data-length: 121088 |
|
732 | 735 | data-unused: 0 |
|
733 | 736 | data-unused: 0.000% |
|
734 | 737 | |
|
735 | 738 | |
|
736 | 739 | local clone |
|
737 | 740 | ------------ |
|
738 | 741 | |
|
739 | 742 | The persistent nodemap should exist after a streaming clone |
|
740 | 743 | |
|
741 | 744 | $ hg clone -U test-repo local-clone |
|
742 | 745 | $ ls -1 local-clone/.hg/store/ | egrep '00(changelog|manifest)(\.n|-.*\.nd)' |
|
743 | 746 | 00changelog-*.nd (glob) |
|
744 | 747 | 00changelog.n |
|
745 | 748 | 00manifest-*.nd (glob) |
|
746 | 749 | 00manifest.n |
|
747 | 750 | $ hg -R local-clone debugnodemap --metadata |
|
748 | 751 | uid: * (glob) |
|
749 | 752 | tip-rev: 5005 |
|
750 | 753 | tip-node: 90d5d3ba2fc47db50f712570487cb261a68c8ffe |
|
751 | 754 | data-length: 121088 |
|
752 | 755 | data-unused: 0 |
|
753 | 756 | data-unused: 0.000% |
|
754 | 757 | |
|
755 | 758 | Test various corruption case |
|
756 | 759 | ============================ |
|
757 | 760 | |
|
758 | 761 | Missing datafile |
|
759 | 762 | ---------------- |
|
760 | 763 | |
|
761 | 764 | Test behavior with a missing datafile |
|
762 | 765 | |
|
763 | 766 | $ hg clone --quiet --pull test-repo corruption-test-repo |
|
764 | 767 | $ ls -1 corruption-test-repo/.hg/store/00changelog* |
|
765 | 768 | corruption-test-repo/.hg/store/00changelog-*.nd (glob) |
|
766 | 769 | corruption-test-repo/.hg/store/00changelog.d |
|
767 | 770 | corruption-test-repo/.hg/store/00changelog.i |
|
768 | 771 | corruption-test-repo/.hg/store/00changelog.n |
|
769 | 772 | $ rm corruption-test-repo/.hg/store/00changelog*.nd |
|
770 | 773 | $ hg log -R corruption-test-repo -r . |
|
771 | 774 | changeset: 5005:90d5d3ba2fc4 |
|
772 | 775 | tag: tip |
|
773 | 776 | user: test |
|
774 | 777 | date: Thu Jan 01 00:00:00 1970 +0000 |
|
775 | 778 | summary: a2 |
|
776 | 779 | |
|
777 | 780 | $ ls -1 corruption-test-repo/.hg/store/00changelog* |
|
778 | 781 | corruption-test-repo/.hg/store/00changelog.d |
|
779 | 782 | corruption-test-repo/.hg/store/00changelog.i |
|
780 | 783 | corruption-test-repo/.hg/store/00changelog.n |
|
781 | 784 | |
|
782 | 785 | Truncated data file |
|
783 | 786 | ------------------- |
|
784 | 787 | |
|
785 | 788 | Test behavior with a too short datafile |
|
786 | 789 | |
|
787 | 790 | rebuild the missing data |
|
788 | 791 | $ hg -R corruption-test-repo debugupdatecache |
|
789 | 792 | $ ls -1 corruption-test-repo/.hg/store/00changelog* |
|
790 | 793 | corruption-test-repo/.hg/store/00changelog-*.nd (glob) |
|
791 | 794 | corruption-test-repo/.hg/store/00changelog.d |
|
792 | 795 | corruption-test-repo/.hg/store/00changelog.i |
|
793 | 796 | corruption-test-repo/.hg/store/00changelog.n |
|
794 | 797 | |
|
795 | 798 | truncate the file |
|
796 | 799 | |
|
797 | 800 | $ datafilepath=`ls corruption-test-repo/.hg/store/00changelog*.nd` |
|
798 | 801 | $ f -s $datafilepath |
|
799 | 802 | corruption-test-repo/.hg/store/00changelog-*.nd: size=121088 (glob) |
|
800 | 803 | $ dd if=$datafilepath bs=1000 count=10 of=$datafilepath-tmp status=noxfer |
|
801 | 804 | 10+0 records in |
|
802 | 805 | 10+0 records out |
|
803 | 806 | $ mv $datafilepath-tmp $datafilepath |
|
804 | 807 | $ f -s $datafilepath |
|
805 | 808 | corruption-test-repo/.hg/store/00changelog-*.nd: size=10000 (glob) |
|
806 | 809 | |
|
807 | 810 | Check that Mercurial reaction to this event |
|
808 | 811 | |
|
809 | 812 | $ hg -R corruption-test-repo log -r . --traceback |
|
810 | 813 | changeset: 5005:90d5d3ba2fc4 |
|
811 | 814 | tag: tip |
|
812 | 815 | user: test |
|
813 | 816 | date: Thu Jan 01 00:00:00 1970 +0000 |
|
814 | 817 | summary: a2 |
|
815 | 818 | |
|
816 | 819 | |
|
817 | 820 | |
|
818 | 821 | stream clone |
|
819 | 822 | ============ |
|
820 | 823 | |
|
821 | 824 | The persistent nodemap should exist after a streaming clone |
|
822 | 825 | |
|
823 | 826 | Simple case |
|
824 | 827 | ----------- |
|
825 | 828 | |
|
826 | 829 | No race condition |
|
827 | 830 | |
|
828 | 831 | $ hg clone -U --stream --config ui.ssh="\"$PYTHON\" \"$TESTDIR/dummyssh\"" ssh://user@dummy/test-repo stream-clone --debug | egrep '00(changelog|manifest)' |
|
829 | 832 | adding [s] 00manifest.n (62 bytes) |
|
830 | 833 | adding [s] 00manifest-*.nd (118 KB) (glob) |
|
831 | 834 | adding [s] 00changelog.n (62 bytes) |
|
832 | 835 | adding [s] 00changelog-*.nd (118 KB) (glob) |
|
833 | 836 | adding [s] 00manifest.d (452 KB) (no-zstd !) |
|
834 | 837 | adding [s] 00manifest.d (491 KB) (zstd !) |
|
835 | 838 | adding [s] 00changelog.d (360 KB) (no-zstd !) |
|
836 | 839 | adding [s] 00changelog.d (368 KB) (zstd !) |
|
837 | 840 | adding [s] 00manifest.i (313 KB) |
|
838 | 841 | adding [s] 00changelog.i (313 KB) |
|
839 | 842 | $ ls -1 stream-clone/.hg/store/ | egrep '00(changelog|manifest)(\.n|-.*\.nd)' |
|
840 | 843 | 00changelog-*.nd (glob) |
|
841 | 844 | 00changelog.n |
|
842 | 845 | 00manifest-*.nd (glob) |
|
843 | 846 | 00manifest.n |
|
844 | 847 | $ hg -R stream-clone debugnodemap --metadata |
|
845 | 848 | uid: * (glob) |
|
846 | 849 | tip-rev: 5005 |
|
847 | 850 | tip-node: 90d5d3ba2fc47db50f712570487cb261a68c8ffe |
|
848 | 851 | data-length: 121088 |
|
849 | 852 | data-unused: 0 |
|
850 | 853 | data-unused: 0.000% |
|
851 | 854 | |
|
852 | 855 | new data appened |
|
853 | 856 | ----------------- |
|
854 | 857 | |
|
855 | 858 | Other commit happening on the server during the stream clone |
|
856 | 859 | |
|
857 | 860 | setup the step-by-step stream cloning |
|
858 | 861 | |
|
859 | 862 | $ HG_TEST_STREAM_WALKED_FILE_1="$TESTTMP/sync_file_walked_1" |
|
860 | 863 | $ export HG_TEST_STREAM_WALKED_FILE_1 |
|
861 | 864 | $ HG_TEST_STREAM_WALKED_FILE_2="$TESTTMP/sync_file_walked_2" |
|
862 | 865 | $ export HG_TEST_STREAM_WALKED_FILE_2 |
|
863 | 866 | $ HG_TEST_STREAM_WALKED_FILE_3="$TESTTMP/sync_file_walked_3" |
|
864 | 867 | $ export HG_TEST_STREAM_WALKED_FILE_3 |
|
865 | 868 | $ cat << EOF >> test-repo/.hg/hgrc |
|
866 | 869 | > [extensions] |
|
867 | 870 | > steps=$RUNTESTDIR/testlib/ext-stream-clone-steps.py |
|
868 | 871 | > EOF |
|
869 | 872 | |
|
870 | 873 | Check and record file state beforehand |
|
871 | 874 | |
|
872 | 875 | $ f --size test-repo/.hg/store/00changelog* |
|
873 | 876 | test-repo/.hg/store/00changelog-*.nd: size=121088 (glob) |
|
874 | 877 | test-repo/.hg/store/00changelog.d: size=376891 (zstd !) |
|
875 | 878 | test-repo/.hg/store/00changelog.d: size=368890 (no-zstd !) |
|
876 | 879 | test-repo/.hg/store/00changelog.i: size=320384 |
|
877 | 880 | test-repo/.hg/store/00changelog.n: size=62 |
|
878 | 881 | $ hg -R test-repo debugnodemap --metadata | tee server-metadata.txt |
|
879 | 882 | uid: * (glob) |
|
880 | 883 | tip-rev: 5005 |
|
881 | 884 | tip-node: 90d5d3ba2fc47db50f712570487cb261a68c8ffe |
|
882 | 885 | data-length: 121088 |
|
883 | 886 | data-unused: 0 |
|
884 | 887 | data-unused: 0.000% |
|
885 | 888 | |
|
886 | 889 | Prepare a commit |
|
887 | 890 | |
|
888 | 891 | $ echo foo >> test-repo/foo |
|
889 | 892 | $ hg -R test-repo/ add test-repo/foo |
|
890 | 893 | |
|
891 | 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 | 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 | 897 | $ $RUNTESTDIR/testlib/wait-on-file 10 $HG_TEST_STREAM_WALKED_FILE_1 |
|
895 | 898 | $ hg -R test-repo/ commit -m foo |
|
896 | 899 | $ touch $HG_TEST_STREAM_WALKED_FILE_2 |
|
897 | 900 | $ $RUNTESTDIR/testlib/wait-on-file 10 $HG_TEST_STREAM_WALKED_FILE_3 |
|
898 | 901 | $ cat clone-output |
|
899 | 902 | adding [s] 00manifest.n (62 bytes) |
|
900 | 903 | adding [s] 00manifest-*.nd (118 KB) (glob) |
|
901 | 904 | adding [s] 00changelog.n (62 bytes) |
|
902 | 905 | adding [s] 00changelog-*.nd (118 KB) (glob) |
|
903 | 906 | adding [s] 00manifest.d (452 KB) (no-zstd !) |
|
904 | 907 | adding [s] 00manifest.d (491 KB) (zstd !) |
|
905 | 908 | adding [s] 00changelog.d (360 KB) (no-zstd !) |
|
906 | 909 | adding [s] 00changelog.d (368 KB) (zstd !) |
|
907 | 910 | adding [s] 00manifest.i (313 KB) |
|
908 | 911 | adding [s] 00changelog.i (313 KB) |
|
909 | 912 | |
|
910 | 913 | Check the result state |
|
911 | 914 | |
|
912 | 915 | $ f --size stream-clone-race-1/.hg/store/00changelog* |
|
913 | 916 | stream-clone-race-1/.hg/store/00changelog-*.nd: size=121088 (glob) |
|
914 | 917 | stream-clone-race-1/.hg/store/00changelog.d: size=368890 (no-zstd !) |
|
915 | 918 | stream-clone-race-1/.hg/store/00changelog.d: size=376891 (zstd !) |
|
916 | 919 | stream-clone-race-1/.hg/store/00changelog.i: size=320384 |
|
917 | 920 | stream-clone-race-1/.hg/store/00changelog.n: size=62 |
|
918 | 921 | |
|
919 | 922 | $ hg -R stream-clone-race-1 debugnodemap --metadata | tee client-metadata.txt |
|
920 | 923 | uid: * (glob) |
|
921 | 924 | tip-rev: 5005 |
|
922 | 925 | tip-node: 90d5d3ba2fc47db50f712570487cb261a68c8ffe |
|
923 | 926 | data-length: 121088 |
|
924 | 927 | data-unused: 0 |
|
925 | 928 | data-unused: 0.000% |
|
926 | 929 | |
|
927 | 930 | We get a usable nodemap, so no rewrite would be needed and the metadata should be identical |
|
928 | 931 | (ie: the following diff should be empty) |
|
929 | 932 | |
|
930 | 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 | 935 | #if no-rust no-pure |
|
933 | 936 | $ diff -u server-metadata.txt client-metadata.txt |
|
934 | 937 | --- server-metadata.txt * (glob) |
|
935 | 938 | +++ client-metadata.txt * (glob) |
|
936 | 939 | @@ -1,4 +1,4 @@ |
|
937 | 940 | -uid: * (glob) |
|
938 | 941 | +uid: * (glob) |
|
939 | 942 | tip-rev: 5005 |
|
940 | 943 | tip-node: 90d5d3ba2fc47db50f712570487cb261a68c8ffe |
|
941 | 944 | data-length: 121088 |
|
942 | 945 | [1] |
|
943 | 946 | #else |
|
944 | 947 | $ diff -u server-metadata.txt client-metadata.txt |
|
945 | 948 | #endif |
|
946 | 949 | |
|
947 | 950 | |
|
948 | 951 | Clean up after the test. |
|
949 | 952 | |
|
950 | 953 | $ rm -f "$HG_TEST_STREAM_WALKED_FILE_1" |
|
951 | 954 | $ rm -f "$HG_TEST_STREAM_WALKED_FILE_2" |
|
952 | 955 | $ rm -f "$HG_TEST_STREAM_WALKED_FILE_3" |
|
953 | 956 | |
|
954 | 957 | full regeneration |
|
955 | 958 | ----------------- |
|
956 | 959 | |
|
957 | 960 | A full nodemap is generated |
|
958 | 961 | |
|
959 | 962 | (ideally this test would append enough data to make sure the nodemap data file |
|
960 | 963 | get changed, however to make thing simpler we will force the regeneration for |
|
961 | 964 | this test. |
|
962 | 965 | |
|
963 | 966 | Check the initial state |
|
964 | 967 | |
|
965 | 968 | $ f --size test-repo/.hg/store/00changelog* |
|
966 | 969 | test-repo/.hg/store/00changelog-*.nd: size=121344 (glob) (rust !) |
|
967 | 970 | test-repo/.hg/store/00changelog-*.nd: size=121344 (glob) (pure !) |
|
968 | 971 | test-repo/.hg/store/00changelog-*.nd: size=121152 (glob) (no-rust no-pure !) |
|
969 | 972 | test-repo/.hg/store/00changelog.d: size=376950 (zstd !) |
|
970 | 973 | test-repo/.hg/store/00changelog.d: size=368949 (no-zstd !) |
|
971 | 974 | test-repo/.hg/store/00changelog.i: size=320448 |
|
972 | 975 | test-repo/.hg/store/00changelog.n: size=62 |
|
973 | 976 | $ hg -R test-repo debugnodemap --metadata | tee server-metadata-2.txt |
|
974 | 977 | uid: * (glob) |
|
975 | 978 | tip-rev: 5006 |
|
976 | 979 | tip-node: ed2ec1eef9aa2a0ec5057c51483bc148d03e810b |
|
977 | 980 | data-length: 121344 (rust !) |
|
978 | 981 | data-length: 121344 (pure !) |
|
979 | 982 | data-length: 121152 (no-rust no-pure !) |
|
980 | 983 | data-unused: 192 (rust !) |
|
981 | 984 | data-unused: 192 (pure !) |
|
982 | 985 | data-unused: 0 (no-rust no-pure !) |
|
983 | 986 | data-unused: 0.158% (rust !) |
|
984 | 987 | data-unused: 0.158% (pure !) |
|
985 | 988 | data-unused: 0.000% (no-rust no-pure !) |
|
986 | 989 | |
|
987 | 990 | Performe the mix of clone and full refresh of the nodemap, so that the files |
|
988 | 991 | (and filenames) are different between listing time and actual transfer time. |
|
989 | 992 | |
|
990 | 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 | 994 | $ $RUNTESTDIR/testlib/wait-on-file 10 $HG_TEST_STREAM_WALKED_FILE_1 |
|
992 | 995 | $ rm test-repo/.hg/store/00changelog.n |
|
993 | 996 | $ rm test-repo/.hg/store/00changelog-*.nd |
|
994 | 997 | $ hg -R test-repo/ debugupdatecache |
|
995 | 998 | $ touch $HG_TEST_STREAM_WALKED_FILE_2 |
|
996 | 999 | $ $RUNTESTDIR/testlib/wait-on-file 10 $HG_TEST_STREAM_WALKED_FILE_3 |
|
997 | 1000 | $ cat clone-output-2 |
|
998 | 1001 | adding [s] 00manifest.n (62 bytes) |
|
999 | 1002 | adding [s] 00manifest-*.nd (118 KB) (glob) |
|
1000 | 1003 | adding [s] 00changelog.n (62 bytes) |
|
1001 | 1004 | adding [s] 00changelog-*.nd (118 KB) (glob) |
|
1002 | 1005 | adding [s] 00manifest.d (492 KB) (zstd !) |
|
1003 | 1006 | adding [s] 00manifest.d (452 KB) (no-zstd !) |
|
1004 | 1007 | adding [s] 00changelog.d (360 KB) (no-zstd !) |
|
1005 | 1008 | adding [s] 00changelog.d (368 KB) (zstd !) |
|
1006 | 1009 | adding [s] 00manifest.i (313 KB) |
|
1007 | 1010 | adding [s] 00changelog.i (313 KB) |
|
1008 | 1011 | |
|
1009 | 1012 | Check the result. |
|
1010 | 1013 | |
|
1011 | 1014 | $ f --size stream-clone-race-2/.hg/store/00changelog* |
|
1012 | 1015 | stream-clone-race-2/.hg/store/00changelog-*.nd: size=121344 (glob) (rust !) |
|
1013 | 1016 | stream-clone-race-2/.hg/store/00changelog-*.nd: size=121344 (glob) (pure !) |
|
1014 | 1017 | stream-clone-race-2/.hg/store/00changelog-*.nd: size=121152 (glob) (no-rust no-pure !) |
|
1015 | 1018 | stream-clone-race-2/.hg/store/00changelog.d: size=376950 (zstd !) |
|
1016 | 1019 | stream-clone-race-2/.hg/store/00changelog.d: size=368949 (no-zstd !) |
|
1017 | 1020 | stream-clone-race-2/.hg/store/00changelog.i: size=320448 |
|
1018 | 1021 | stream-clone-race-2/.hg/store/00changelog.n: size=62 |
|
1019 | 1022 | |
|
1020 | 1023 | $ hg -R stream-clone-race-2 debugnodemap --metadata | tee client-metadata-2.txt |
|
1021 | 1024 | uid: * (glob) |
|
1022 | 1025 | tip-rev: 5006 |
|
1023 | 1026 | tip-node: ed2ec1eef9aa2a0ec5057c51483bc148d03e810b |
|
1024 | 1027 | data-length: 121344 (rust !) |
|
1025 | 1028 | data-unused: 192 (rust !) |
|
1026 | 1029 | data-unused: 0.158% (rust !) |
|
1027 | 1030 | data-length: 121152 (no-rust no-pure !) |
|
1028 | 1031 | data-unused: 0 (no-rust no-pure !) |
|
1029 | 1032 | data-unused: 0.000% (no-rust no-pure !) |
|
1030 | 1033 | data-length: 121344 (pure !) |
|
1031 | 1034 | data-unused: 192 (pure !) |
|
1032 | 1035 | data-unused: 0.158% (pure !) |
|
1033 | 1036 | |
|
1034 | 1037 | We get a usable nodemap, so no rewrite would be needed and the metadata should be identical |
|
1035 | 1038 | (ie: the following diff should be empty) |
|
1036 | 1039 | |
|
1037 | 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 | 1042 | #if no-rust no-pure |
|
1040 | 1043 | $ diff -u server-metadata-2.txt client-metadata-2.txt |
|
1041 | 1044 | --- server-metadata-2.txt * (glob) |
|
1042 | 1045 | +++ client-metadata-2.txt * (glob) |
|
1043 | 1046 | @@ -1,4 +1,4 @@ |
|
1044 | 1047 | -uid: * (glob) |
|
1045 | 1048 | +uid: * (glob) |
|
1046 | 1049 | tip-rev: 5006 |
|
1047 | 1050 | tip-node: ed2ec1eef9aa2a0ec5057c51483bc148d03e810b |
|
1048 | 1051 | data-length: 121152 |
|
1049 | 1052 | [1] |
|
1050 | 1053 | #else |
|
1051 | 1054 | $ diff -u server-metadata-2.txt client-metadata-2.txt |
|
1052 | 1055 | #endif |
|
1053 | 1056 | |
|
1054 | 1057 | Clean up after the test |
|
1055 | 1058 | |
|
1056 | 1059 | $ rm -f $HG_TEST_STREAM_WALKED_FILE_1 |
|
1057 | 1060 | $ rm -f $HG_TEST_STREAM_WALKED_FILE_2 |
|
1058 | 1061 | $ rm -f $HG_TEST_STREAM_WALKED_FILE_3 |
|
1059 | 1062 |
@@ -1,122 +1,126 | |||
|
1 | 1 | ========================================================== |
|
2 | 2 | Test file dedicated to checking side-data related behavior |
|
3 | 3 | ========================================================== |
|
4 | 4 | |
|
5 | 5 | Check data can be written/read from sidedata |
|
6 | 6 | ============================================ |
|
7 | 7 | |
|
8 | 8 | $ cat << EOF >> $HGRCPATH |
|
9 | 9 | > [extensions] |
|
10 | 10 | > testsidedata=$TESTDIR/testlib/ext-sidedata.py |
|
11 | 11 | > EOF |
|
12 | 12 | |
|
13 | 13 | $ hg init test-sidedata --config experimental.revlogv2=enable-unstable-format-and-corrupt-my-data |
|
14 | 14 | $ cd test-sidedata |
|
15 | 15 | $ echo aaa > a |
|
16 | 16 | $ hg add a |
|
17 | 17 | $ hg commit -m a --traceback |
|
18 | 18 | $ echo aaa > b |
|
19 | 19 | $ hg add b |
|
20 | 20 | $ hg commit -m b |
|
21 | 21 | $ echo xxx >> a |
|
22 | 22 | $ hg commit -m aa |
|
23 | 23 | |
|
24 | 24 | $ hg debugsidedata -c 0 |
|
25 | 25 | 2 sidedata entries |
|
26 | 26 | entry-0001 size 4 |
|
27 | 27 | entry-0002 size 32 |
|
28 | 28 | $ hg debugsidedata -c 1 -v |
|
29 | 29 | 2 sidedata entries |
|
30 | 30 | entry-0001 size 4 |
|
31 | 31 | '\x00\x00\x006' |
|
32 | 32 | entry-0002 size 32 |
|
33 | 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 | 34 | $ hg debugsidedata -m 2 |
|
35 | 35 | 2 sidedata entries |
|
36 | 36 | entry-0001 size 4 |
|
37 | 37 | entry-0002 size 32 |
|
38 | 38 | $ hg debugsidedata a 1 |
|
39 | 39 | 2 sidedata entries |
|
40 | 40 | entry-0001 size 4 |
|
41 | 41 | entry-0002 size 32 |
|
42 | 42 | |
|
43 | 43 | Check upgrade behavior |
|
44 | 44 | ====================== |
|
45 | 45 | |
|
46 | 46 | Right now, sidedata has not upgrade support |
|
47 | 47 | |
|
48 | 48 | Check that we can upgrade to sidedata |
|
49 | 49 | ------------------------------------- |
|
50 | 50 | |
|
51 | 51 | $ hg init up-no-side-data --config experimental.revlogv2=no |
|
52 | 52 | $ hg debugformat -v -R up-no-side-data |
|
53 | 53 | format-variant repo config default |
|
54 | 54 | fncache: yes yes yes |
|
55 | dirstate-v2: no no no | |
|
55 | 56 | dotencode: yes yes yes |
|
56 | 57 | generaldelta: yes yes yes |
|
57 | 58 | share-safe: no no no |
|
58 | 59 | sparserevlog: yes yes yes |
|
59 | 60 | persistent-nodemap: no no no (no-rust !) |
|
60 | 61 | persistent-nodemap: yes yes no (rust !) |
|
61 | 62 | copies-sdc: no no no |
|
62 | 63 | revlog-v2: no no no |
|
63 | 64 | changelog-v2: no no no |
|
64 | 65 | plain-cl-delta: yes yes yes |
|
65 | 66 | compression: zlib zlib zlib (no-zstd !) |
|
66 | 67 | compression: zstd zstd zstd (zstd !) |
|
67 | 68 | compression-level: default default default |
|
68 | 69 | $ hg debugformat -v -R up-no-side-data --config experimental.revlogv2=enable-unstable-format-and-corrupt-my-data |
|
69 | 70 | format-variant repo config default |
|
70 | 71 | fncache: yes yes yes |
|
72 | dirstate-v2: no no no | |
|
71 | 73 | dotencode: yes yes yes |
|
72 | 74 | generaldelta: yes yes yes |
|
73 | 75 | share-safe: no no no |
|
74 | 76 | sparserevlog: yes yes yes |
|
75 | 77 | persistent-nodemap: no no no (no-rust !) |
|
76 | 78 | persistent-nodemap: yes yes no (rust !) |
|
77 | 79 | copies-sdc: no no no |
|
78 | 80 | revlog-v2: no yes no |
|
79 | 81 | changelog-v2: no no no |
|
80 | 82 | plain-cl-delta: yes yes yes |
|
81 | 83 | compression: zlib zlib zlib (no-zstd !) |
|
82 | 84 | compression: zstd zstd zstd (zstd !) |
|
83 | 85 | compression-level: default default default |
|
84 | 86 | $ hg debugupgraderepo -R up-no-side-data --config experimental.revlogv2=enable-unstable-format-and-corrupt-my-data > /dev/null |
|
85 | 87 | |
|
86 | 88 | Check that we can downgrade from sidedata |
|
87 | 89 | ----------------------------------------- |
|
88 | 90 | |
|
89 | 91 | $ hg init up-side-data --config experimental.revlogv2=enable-unstable-format-and-corrupt-my-data |
|
90 | 92 | $ hg debugformat -v -R up-side-data |
|
91 | 93 | format-variant repo config default |
|
92 | 94 | fncache: yes yes yes |
|
95 | dirstate-v2: no no no | |
|
93 | 96 | dotencode: yes yes yes |
|
94 | 97 | generaldelta: yes yes yes |
|
95 | 98 | share-safe: no no no |
|
96 | 99 | sparserevlog: yes yes yes |
|
97 | 100 | persistent-nodemap: no no no (no-rust !) |
|
98 | 101 | persistent-nodemap: yes yes no (rust !) |
|
99 | 102 | copies-sdc: no no no |
|
100 | 103 | revlog-v2: yes no no |
|
101 | 104 | changelog-v2: no no no |
|
102 | 105 | plain-cl-delta: yes yes yes |
|
103 | 106 | compression: zlib zlib zlib (no-zstd !) |
|
104 | 107 | compression: zstd zstd zstd (zstd !) |
|
105 | 108 | compression-level: default default default |
|
106 | 109 | $ hg debugformat -v -R up-side-data --config experimental.revlogv2=no |
|
107 | 110 | format-variant repo config default |
|
108 | 111 | fncache: yes yes yes |
|
112 | dirstate-v2: no no no | |
|
109 | 113 | dotencode: yes yes yes |
|
110 | 114 | generaldelta: yes yes yes |
|
111 | 115 | share-safe: no no no |
|
112 | 116 | sparserevlog: yes yes yes |
|
113 | 117 | persistent-nodemap: no no no (no-rust !) |
|
114 | 118 | persistent-nodemap: yes yes no (rust !) |
|
115 | 119 | copies-sdc: no no no |
|
116 | 120 | revlog-v2: yes no no |
|
117 | 121 | changelog-v2: no no no |
|
118 | 122 | plain-cl-delta: yes yes yes |
|
119 | 123 | compression: zlib zlib zlib (no-zstd !) |
|
120 | 124 | compression: zstd zstd zstd (zstd !) |
|
121 | 125 | compression-level: default default default |
|
122 | 126 | $ hg debugupgraderepo -R up-side-data --config experimental.revlogv2=no > /dev/null |
@@ -1,1615 +1,1737 | |||
|
1 | 1 | #require no-reposimplestore |
|
2 | 2 | |
|
3 | 3 | $ cat >> $HGRCPATH << EOF |
|
4 | 4 | > [extensions] |
|
5 | 5 | > share = |
|
6 | 6 | > [format] |
|
7 | 7 | > # stabilize test accross variant |
|
8 | 8 | > revlog-compression=zlib |
|
9 | 9 | > EOF |
|
10 | 10 | |
|
11 | 11 | store and revlogv1 are required in source |
|
12 | 12 | |
|
13 | 13 | $ hg --config format.usestore=false init no-store |
|
14 | 14 | $ hg -R no-store debugupgraderepo |
|
15 | 15 | abort: cannot upgrade repository; requirement missing: store |
|
16 | 16 | [255] |
|
17 | 17 | |
|
18 | 18 | $ hg init no-revlogv1 |
|
19 | 19 | $ cat > no-revlogv1/.hg/requires << EOF |
|
20 | 20 | > dotencode |
|
21 | 21 | > fncache |
|
22 | 22 | > generaldelta |
|
23 | 23 | > store |
|
24 | 24 | > EOF |
|
25 | 25 | |
|
26 | 26 | $ hg -R no-revlogv1 debugupgraderepo |
|
27 | 27 | abort: cannot upgrade repository; missing a revlog version |
|
28 | 28 | [255] |
|
29 | 29 | |
|
30 | 30 | Cannot upgrade shared repositories |
|
31 | 31 | |
|
32 | 32 | $ hg init share-parent |
|
33 | 33 | $ hg -q share share-parent share-child |
|
34 | 34 | |
|
35 | 35 | $ hg -R share-child debugupgraderepo |
|
36 | 36 | abort: cannot upgrade repository; unsupported source requirement: shared |
|
37 | 37 | [255] |
|
38 | 38 | |
|
39 | 39 | Do not yet support upgrading treemanifest repos |
|
40 | 40 | |
|
41 | 41 | $ hg --config experimental.treemanifest=true init treemanifest |
|
42 | 42 | $ hg -R treemanifest debugupgraderepo |
|
43 | 43 | abort: cannot upgrade repository; unsupported source requirement: treemanifest |
|
44 | 44 | [255] |
|
45 | 45 | |
|
46 | 46 | Cannot add treemanifest requirement during upgrade |
|
47 | 47 | |
|
48 | 48 | $ hg init disallowaddedreq |
|
49 | 49 | $ hg -R disallowaddedreq --config experimental.treemanifest=true debugupgraderepo |
|
50 | 50 | abort: cannot upgrade repository; do not support adding requirement: treemanifest |
|
51 | 51 | [255] |
|
52 | 52 | |
|
53 | 53 | An upgrade of a repository created with recommended settings only suggests optimizations |
|
54 | 54 | |
|
55 | 55 | $ hg init empty |
|
56 | 56 | $ cd empty |
|
57 | 57 | $ hg debugformat |
|
58 | 58 | format-variant repo |
|
59 | 59 | fncache: yes |
|
60 | dirstate-v2: no | |
|
60 | 61 | dotencode: yes |
|
61 | 62 | generaldelta: yes |
|
62 | 63 | share-safe: no |
|
63 | 64 | sparserevlog: yes |
|
64 | 65 | persistent-nodemap: no (no-rust !) |
|
65 | 66 | persistent-nodemap: yes (rust !) |
|
66 | 67 | copies-sdc: no |
|
67 | 68 | revlog-v2: no |
|
68 | 69 | changelog-v2: no |
|
69 | 70 | plain-cl-delta: yes |
|
70 | 71 | compression: zlib |
|
71 | 72 | compression-level: default |
|
72 | 73 | $ hg debugformat --verbose |
|
73 | 74 | format-variant repo config default |
|
74 | 75 | fncache: yes yes yes |
|
76 | dirstate-v2: no no no | |
|
75 | 77 | dotencode: yes yes yes |
|
76 | 78 | generaldelta: yes yes yes |
|
77 | 79 | share-safe: no no no |
|
78 | 80 | sparserevlog: yes yes yes |
|
79 | 81 | persistent-nodemap: no no no (no-rust !) |
|
80 | 82 | persistent-nodemap: yes yes no (rust !) |
|
81 | 83 | copies-sdc: no no no |
|
82 | 84 | revlog-v2: no no no |
|
83 | 85 | changelog-v2: no no no |
|
84 | 86 | plain-cl-delta: yes yes yes |
|
85 | 87 | compression: zlib zlib zlib (no-zstd !) |
|
86 | 88 | compression: zlib zlib zstd (zstd !) |
|
87 | 89 | compression-level: default default default |
|
88 | 90 | $ hg debugformat --verbose --config format.usefncache=no |
|
89 | 91 | format-variant repo config default |
|
90 | 92 | fncache: yes no yes |
|
93 | dirstate-v2: no no no | |
|
91 | 94 | dotencode: yes no yes |
|
92 | 95 | generaldelta: yes yes yes |
|
93 | 96 | share-safe: no no no |
|
94 | 97 | sparserevlog: yes yes yes |
|
95 | 98 | persistent-nodemap: no no no (no-rust !) |
|
96 | 99 | persistent-nodemap: yes yes no (rust !) |
|
97 | 100 | copies-sdc: no no no |
|
98 | 101 | revlog-v2: no no no |
|
99 | 102 | changelog-v2: no no no |
|
100 | 103 | plain-cl-delta: yes yes yes |
|
101 | 104 | compression: zlib zlib zlib (no-zstd !) |
|
102 | 105 | compression: zlib zlib zstd (zstd !) |
|
103 | 106 | compression-level: default default default |
|
104 | 107 | $ hg debugformat --verbose --config format.usefncache=no --color=debug |
|
105 | 108 | format-variant repo config default |
|
106 | 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 | 111 | [formatvariant.name.mismatchconfig|dotencode: ][formatvariant.repo.mismatchconfig| yes][formatvariant.config.special| no][formatvariant.default| yes] |
|
108 | 112 | [formatvariant.name.uptodate|generaldelta: ][formatvariant.repo.uptodate| yes][formatvariant.config.default| yes][formatvariant.default| yes] |
|
109 | 113 | [formatvariant.name.uptodate|share-safe: ][formatvariant.repo.uptodate| no][formatvariant.config.default| no][formatvariant.default| no] |
|
110 | 114 | [formatvariant.name.uptodate|sparserevlog: ][formatvariant.repo.uptodate| yes][formatvariant.config.default| yes][formatvariant.default| yes] |
|
111 | 115 | [formatvariant.name.uptodate|persistent-nodemap:][formatvariant.repo.uptodate| no][formatvariant.config.default| no][formatvariant.default| no] (no-rust !) |
|
112 | 116 | [formatvariant.name.mismatchdefault|persistent-nodemap:][formatvariant.repo.mismatchdefault| yes][formatvariant.config.special| yes][formatvariant.default| no] (rust !) |
|
113 | 117 | [formatvariant.name.uptodate|copies-sdc: ][formatvariant.repo.uptodate| no][formatvariant.config.default| no][formatvariant.default| no] |
|
114 | 118 | [formatvariant.name.uptodate|revlog-v2: ][formatvariant.repo.uptodate| no][formatvariant.config.default| no][formatvariant.default| no] |
|
115 | 119 | [formatvariant.name.uptodate|changelog-v2: ][formatvariant.repo.uptodate| no][formatvariant.config.default| no][formatvariant.default| no] |
|
116 | 120 | [formatvariant.name.uptodate|plain-cl-delta: ][formatvariant.repo.uptodate| yes][formatvariant.config.default| yes][formatvariant.default| yes] |
|
117 | 121 | [formatvariant.name.uptodate|compression: ][formatvariant.repo.uptodate| zlib][formatvariant.config.default| zlib][formatvariant.default| zlib] (no-zstd !) |
|
118 | 122 | [formatvariant.name.mismatchdefault|compression: ][formatvariant.repo.mismatchdefault| zlib][formatvariant.config.special| zlib][formatvariant.default| zstd] (zstd !) |
|
119 | 123 | [formatvariant.name.uptodate|compression-level: ][formatvariant.repo.uptodate| default][formatvariant.config.default| default][formatvariant.default| default] |
|
120 | 124 | $ hg debugformat -Tjson |
|
121 | 125 | [ |
|
122 | 126 | { |
|
123 | 127 | "config": true, |
|
124 | 128 | "default": true, |
|
125 | 129 | "name": "fncache", |
|
126 | 130 | "repo": true |
|
127 | 131 | }, |
|
128 | 132 | { |
|
133 | "config": false, | |
|
134 | "default": false, | |
|
135 | "name": "dirstate-v2", | |
|
136 | "repo": false | |
|
137 | }, | |
|
138 | { | |
|
129 | 139 | "config": true, |
|
130 | 140 | "default": true, |
|
131 | 141 | "name": "dotencode", |
|
132 | 142 | "repo": true |
|
133 | 143 | }, |
|
134 | 144 | { |
|
135 | 145 | "config": true, |
|
136 | 146 | "default": true, |
|
137 | 147 | "name": "generaldelta", |
|
138 | 148 | "repo": true |
|
139 | 149 | }, |
|
140 | 150 | { |
|
141 | 151 | "config": false, |
|
142 | 152 | "default": false, |
|
143 | 153 | "name": "share-safe", |
|
144 | 154 | "repo": false |
|
145 | 155 | }, |
|
146 | 156 | { |
|
147 | 157 | "config": true, |
|
148 | 158 | "default": true, |
|
149 | 159 | "name": "sparserevlog", |
|
150 | 160 | "repo": true |
|
151 | 161 | }, |
|
152 | 162 | { |
|
153 | 163 | "config": false, (no-rust !) |
|
154 | 164 | "config": true, (rust !) |
|
155 | 165 | "default": false, |
|
156 | 166 | "name": "persistent-nodemap", |
|
157 | 167 | "repo": false (no-rust !) |
|
158 | 168 | "repo": true (rust !) |
|
159 | 169 | }, |
|
160 | 170 | { |
|
161 | 171 | "config": false, |
|
162 | 172 | "default": false, |
|
163 | 173 | "name": "copies-sdc", |
|
164 | 174 | "repo": false |
|
165 | 175 | }, |
|
166 | 176 | { |
|
167 | 177 | "config": false, |
|
168 | 178 | "default": false, |
|
169 | 179 | "name": "revlog-v2", |
|
170 | 180 | "repo": false |
|
171 | 181 | }, |
|
172 | 182 | { |
|
173 | 183 | "config": false, |
|
174 | 184 | "default": false, |
|
175 | 185 | "name": "changelog-v2", |
|
176 | 186 | "repo": false |
|
177 | 187 | }, |
|
178 | 188 | { |
|
179 | 189 | "config": true, |
|
180 | 190 | "default": true, |
|
181 | 191 | "name": "plain-cl-delta", |
|
182 | 192 | "repo": true |
|
183 | 193 | }, |
|
184 | 194 | { |
|
185 | 195 | "config": "zlib", |
|
186 | 196 | "default": "zlib", (no-zstd !) |
|
187 | 197 | "default": "zstd", (zstd !) |
|
188 | 198 | "name": "compression", |
|
189 | 199 | "repo": "zlib" |
|
190 | 200 | }, |
|
191 | 201 | { |
|
192 | 202 | "config": "default", |
|
193 | 203 | "default": "default", |
|
194 | 204 | "name": "compression-level", |
|
195 | 205 | "repo": "default" |
|
196 | 206 | } |
|
197 | 207 | ] |
|
198 | 208 | $ hg debugupgraderepo |
|
199 | 209 | (no format upgrades found in existing repository) |
|
200 | 210 | performing an upgrade with "--run" will make the following changes: |
|
201 | 211 | |
|
202 | 212 | requirements |
|
203 | 213 | preserved: dotencode, fncache, generaldelta, revlogv1, sparserevlog, store (no-rust !) |
|
204 | 214 | preserved: dotencode, fncache, generaldelta, persistent-nodemap, revlogv1, sparserevlog, store (rust !) |
|
205 | 215 | |
|
206 | 216 | processed revlogs: |
|
207 | 217 | - all-filelogs |
|
208 | 218 | - changelog |
|
209 | 219 | - manifest |
|
210 | 220 | |
|
211 | 221 | additional optimizations are available by specifying "--optimize <name>": |
|
212 | 222 | |
|
213 | 223 | re-delta-parent |
|
214 | 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 | 226 | re-delta-multibase |
|
217 | 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 | 229 | re-delta-all |
|
220 | 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 | 232 | re-delta-fulladd |
|
223 | 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 | 236 | $ hg debugupgraderepo --quiet |
|
227 | 237 | requirements |
|
228 | 238 | preserved: dotencode, fncache, generaldelta, revlogv1, sparserevlog, store (no-rust !) |
|
229 | 239 | preserved: dotencode, fncache, generaldelta, persistent-nodemap, revlogv1, sparserevlog, store (rust !) |
|
230 | 240 | |
|
231 | 241 | processed revlogs: |
|
232 | 242 | - all-filelogs |
|
233 | 243 | - changelog |
|
234 | 244 | - manifest |
|
235 | 245 | |
|
236 | 246 | |
|
237 | 247 | --optimize can be used to add optimizations |
|
238 | 248 | |
|
239 | 249 | $ hg debugupgrade --optimize 're-delta-parent' |
|
240 | 250 | (no format upgrades found in existing repository) |
|
241 | 251 | performing an upgrade with "--run" will make the following changes: |
|
242 | 252 | |
|
243 | 253 | requirements |
|
244 | 254 | preserved: dotencode, fncache, generaldelta, revlogv1, sparserevlog, store (no-rust !) |
|
245 | 255 | preserved: dotencode, fncache, generaldelta, persistent-nodemap, revlogv1, sparserevlog, store (rust !) |
|
246 | 256 | |
|
247 | 257 | optimisations: re-delta-parent |
|
248 | 258 | |
|
249 | 259 | re-delta-parent |
|
250 | 260 | deltas within internal storage will choose a new base revision if needed |
|
251 | 261 | |
|
252 | 262 | processed revlogs: |
|
253 | 263 | - all-filelogs |
|
254 | 264 | - changelog |
|
255 | 265 | - manifest |
|
256 | 266 | |
|
257 | 267 | additional optimizations are available by specifying "--optimize <name>": |
|
258 | 268 | |
|
259 | 269 | re-delta-multibase |
|
260 | 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 | 272 | re-delta-all |
|
263 | 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 | 275 | re-delta-fulladd |
|
266 | 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 | 279 | modern form of the option |
|
270 | 280 | |
|
271 | 281 | $ hg debugupgrade --optimize re-delta-parent |
|
272 | 282 | (no format upgrades found in existing repository) |
|
273 | 283 | performing an upgrade with "--run" will make the following changes: |
|
274 | 284 | |
|
275 | 285 | requirements |
|
276 | 286 | preserved: dotencode, fncache, generaldelta, revlogv1, sparserevlog, store (no-rust !) |
|
277 | 287 | preserved: dotencode, fncache, generaldelta, persistent-nodemap, revlogv1, sparserevlog, store (rust !) |
|
278 | 288 | |
|
279 | 289 | optimisations: re-delta-parent |
|
280 | 290 | |
|
281 | 291 | re-delta-parent |
|
282 | 292 | deltas within internal storage will choose a new base revision if needed |
|
283 | 293 | |
|
284 | 294 | processed revlogs: |
|
285 | 295 | - all-filelogs |
|
286 | 296 | - changelog |
|
287 | 297 | - manifest |
|
288 | 298 | |
|
289 | 299 | additional optimizations are available by specifying "--optimize <name>": |
|
290 | 300 | |
|
291 | 301 | re-delta-multibase |
|
292 | 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 | 304 | re-delta-all |
|
295 | 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 | 307 | re-delta-fulladd |
|
298 | 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 | 310 | $ hg debugupgrade --optimize re-delta-parent --quiet |
|
301 | 311 | requirements |
|
302 | 312 | preserved: dotencode, fncache, generaldelta, revlogv1, sparserevlog, store (no-rust !) |
|
303 | 313 | preserved: dotencode, fncache, generaldelta, persistent-nodemap, revlogv1, sparserevlog, store (rust !) |
|
304 | 314 | |
|
305 | 315 | optimisations: re-delta-parent |
|
306 | 316 | |
|
307 | 317 | processed revlogs: |
|
308 | 318 | - all-filelogs |
|
309 | 319 | - changelog |
|
310 | 320 | - manifest |
|
311 | 321 | |
|
312 | 322 | |
|
313 | 323 | unknown optimization: |
|
314 | 324 | |
|
315 | 325 | $ hg debugupgrade --optimize foobar |
|
316 | 326 | abort: unknown optimization action requested: foobar |
|
317 | 327 | (run without arguments to see valid optimizations) |
|
318 | 328 | [255] |
|
319 | 329 | |
|
320 | 330 | Various sub-optimal detections work |
|
321 | 331 | |
|
322 | 332 | $ cat > .hg/requires << EOF |
|
323 | 333 | > revlogv1 |
|
324 | 334 | > store |
|
325 | 335 | > EOF |
|
326 | 336 | |
|
327 | 337 | $ hg debugformat |
|
328 | 338 | format-variant repo |
|
329 | 339 | fncache: no |
|
340 | dirstate-v2: no | |
|
330 | 341 | dotencode: no |
|
331 | 342 | generaldelta: no |
|
332 | 343 | share-safe: no |
|
333 | 344 | sparserevlog: no |
|
334 | 345 | persistent-nodemap: no |
|
335 | 346 | copies-sdc: no |
|
336 | 347 | revlog-v2: no |
|
337 | 348 | changelog-v2: no |
|
338 | 349 | plain-cl-delta: yes |
|
339 | 350 | compression: zlib |
|
340 | 351 | compression-level: default |
|
341 | 352 | $ hg debugformat --verbose |
|
342 | 353 | format-variant repo config default |
|
343 | 354 | fncache: no yes yes |
|
355 | dirstate-v2: no no no | |
|
344 | 356 | dotencode: no yes yes |
|
345 | 357 | generaldelta: no yes yes |
|
346 | 358 | share-safe: no no no |
|
347 | 359 | sparserevlog: no yes yes |
|
348 | 360 | persistent-nodemap: no no no (no-rust !) |
|
349 | 361 | persistent-nodemap: no yes no (rust !) |
|
350 | 362 | copies-sdc: no no no |
|
351 | 363 | revlog-v2: no no no |
|
352 | 364 | changelog-v2: no no no |
|
353 | 365 | plain-cl-delta: yes yes yes |
|
354 | 366 | compression: zlib zlib zlib (no-zstd !) |
|
355 | 367 | compression: zlib zlib zstd (zstd !) |
|
356 | 368 | compression-level: default default default |
|
357 | 369 | $ hg debugformat --verbose --config format.usegeneraldelta=no |
|
358 | 370 | format-variant repo config default |
|
359 | 371 | fncache: no yes yes |
|
372 | dirstate-v2: no no no | |
|
360 | 373 | dotencode: no yes yes |
|
361 | 374 | generaldelta: no no yes |
|
362 | 375 | share-safe: no no no |
|
363 | 376 | sparserevlog: no no yes |
|
364 | 377 | persistent-nodemap: no no no (no-rust !) |
|
365 | 378 | persistent-nodemap: no yes no (rust !) |
|
366 | 379 | copies-sdc: no no no |
|
367 | 380 | revlog-v2: no no no |
|
368 | 381 | changelog-v2: no no no |
|
369 | 382 | plain-cl-delta: yes yes yes |
|
370 | 383 | compression: zlib zlib zlib (no-zstd !) |
|
371 | 384 | compression: zlib zlib zstd (zstd !) |
|
372 | 385 | compression-level: default default default |
|
373 | 386 | $ hg debugformat --verbose --config format.usegeneraldelta=no --color=debug |
|
374 | 387 | format-variant repo config default |
|
375 | 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 | 390 | [formatvariant.name.mismatchconfig|dotencode: ][formatvariant.repo.mismatchconfig| no][formatvariant.config.default| yes][formatvariant.default| yes] |
|
377 | 391 | [formatvariant.name.mismatchdefault|generaldelta: ][formatvariant.repo.mismatchdefault| no][formatvariant.config.special| no][formatvariant.default| yes] |
|
378 | 392 | [formatvariant.name.uptodate|share-safe: ][formatvariant.repo.uptodate| no][formatvariant.config.default| no][formatvariant.default| no] |
|
379 | 393 | [formatvariant.name.mismatchdefault|sparserevlog: ][formatvariant.repo.mismatchdefault| no][formatvariant.config.special| no][formatvariant.default| yes] |
|
380 | 394 | [formatvariant.name.uptodate|persistent-nodemap:][formatvariant.repo.uptodate| no][formatvariant.config.default| no][formatvariant.default| no] (no-rust !) |
|
381 | 395 | [formatvariant.name.mismatchconfig|persistent-nodemap:][formatvariant.repo.mismatchconfig| no][formatvariant.config.special| yes][formatvariant.default| no] (rust !) |
|
382 | 396 | [formatvariant.name.uptodate|copies-sdc: ][formatvariant.repo.uptodate| no][formatvariant.config.default| no][formatvariant.default| no] |
|
383 | 397 | [formatvariant.name.uptodate|revlog-v2: ][formatvariant.repo.uptodate| no][formatvariant.config.default| no][formatvariant.default| no] |
|
384 | 398 | [formatvariant.name.uptodate|changelog-v2: ][formatvariant.repo.uptodate| no][formatvariant.config.default| no][formatvariant.default| no] |
|
385 | 399 | [formatvariant.name.uptodate|plain-cl-delta: ][formatvariant.repo.uptodate| yes][formatvariant.config.default| yes][formatvariant.default| yes] |
|
386 | 400 | [formatvariant.name.uptodate|compression: ][formatvariant.repo.uptodate| zlib][formatvariant.config.default| zlib][formatvariant.default| zlib] (no-zstd !) |
|
387 | 401 | [formatvariant.name.mismatchdefault|compression: ][formatvariant.repo.mismatchdefault| zlib][formatvariant.config.special| zlib][formatvariant.default| zstd] (zstd !) |
|
388 | 402 | [formatvariant.name.uptodate|compression-level: ][formatvariant.repo.uptodate| default][formatvariant.config.default| default][formatvariant.default| default] |
|
389 | 403 | $ hg debugupgraderepo |
|
390 | 404 | repository lacks features recommended by current config options: |
|
391 | 405 | |
|
392 | 406 | fncache |
|
393 | 407 | long and reserved filenames may not work correctly; repository performance is sub-optimal |
|
394 | 408 | |
|
395 | 409 | dotencode |
|
396 | 410 | storage of filenames beginning with a period or space may not work correctly |
|
397 | 411 | |
|
398 | 412 | generaldelta |
|
399 | 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 | 415 | sparserevlog |
|
402 | 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 | 418 | persistent-nodemap (rust !) |
|
405 | 419 | persist the node -> rev mapping on disk to speedup lookup (rust !) |
|
406 | 420 | (rust !) |
|
407 | 421 | |
|
408 | 422 | performing an upgrade with "--run" will make the following changes: |
|
409 | 423 | |
|
410 | 424 | requirements |
|
411 | 425 | preserved: revlogv1, store |
|
412 | 426 | added: dotencode, fncache, generaldelta, sparserevlog (no-rust !) |
|
413 | 427 | added: dotencode, fncache, generaldelta, persistent-nodemap, sparserevlog (rust !) |
|
414 | 428 | |
|
415 | 429 | fncache |
|
416 | 430 | repository will be more resilient to storing certain paths and performance of certain operations should be improved |
|
417 | 431 | |
|
418 | 432 | dotencode |
|
419 | 433 | repository will be better able to store files beginning with a space or period |
|
420 | 434 | |
|
421 | 435 | generaldelta |
|
422 | 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 | 438 | sparserevlog |
|
425 | 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 | 441 | persistent-nodemap (rust !) |
|
428 | 442 | Speedup revision lookup by node id. (rust !) |
|
429 | 443 | (rust !) |
|
430 | 444 | processed revlogs: |
|
431 | 445 | - all-filelogs |
|
432 | 446 | - changelog |
|
433 | 447 | - manifest |
|
434 | 448 | |
|
435 | 449 | additional optimizations are available by specifying "--optimize <name>": |
|
436 | 450 | |
|
437 | 451 | re-delta-parent |
|
438 | 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 | 454 | re-delta-multibase |
|
441 | 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 | 457 | re-delta-all |
|
444 | 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 | 460 | re-delta-fulladd |
|
447 | 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 | 463 | $ hg debugupgraderepo --quiet |
|
450 | 464 | requirements |
|
451 | 465 | preserved: revlogv1, store |
|
452 | 466 | added: dotencode, fncache, generaldelta, sparserevlog (no-rust !) |
|
453 | 467 | added: dotencode, fncache, generaldelta, persistent-nodemap, sparserevlog (rust !) |
|
454 | 468 | |
|
455 | 469 | processed revlogs: |
|
456 | 470 | - all-filelogs |
|
457 | 471 | - changelog |
|
458 | 472 | - manifest |
|
459 | 473 | |
|
460 | 474 | |
|
461 | 475 | $ hg --config format.dotencode=false debugupgraderepo |
|
462 | 476 | repository lacks features recommended by current config options: |
|
463 | 477 | |
|
464 | 478 | fncache |
|
465 | 479 | long and reserved filenames may not work correctly; repository performance is sub-optimal |
|
466 | 480 | |
|
467 | 481 | generaldelta |
|
468 | 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 | 484 | sparserevlog |
|
471 | 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 | 487 | persistent-nodemap (rust !) |
|
474 | 488 | persist the node -> rev mapping on disk to speedup lookup (rust !) |
|
475 | 489 | (rust !) |
|
476 | 490 | repository lacks features used by the default config options: |
|
477 | 491 | |
|
478 | 492 | dotencode |
|
479 | 493 | storage of filenames beginning with a period or space may not work correctly |
|
480 | 494 | |
|
481 | 495 | |
|
482 | 496 | performing an upgrade with "--run" will make the following changes: |
|
483 | 497 | |
|
484 | 498 | requirements |
|
485 | 499 | preserved: revlogv1, store |
|
486 | 500 | added: fncache, generaldelta, sparserevlog (no-rust !) |
|
487 | 501 | added: fncache, generaldelta, persistent-nodemap, sparserevlog (rust !) |
|
488 | 502 | |
|
489 | 503 | fncache |
|
490 | 504 | repository will be more resilient to storing certain paths and performance of certain operations should be improved |
|
491 | 505 | |
|
492 | 506 | generaldelta |
|
493 | 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 | 509 | sparserevlog |
|
496 | 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 | 512 | persistent-nodemap (rust !) |
|
499 | 513 | Speedup revision lookup by node id. (rust !) |
|
500 | 514 | (rust !) |
|
501 | 515 | processed revlogs: |
|
502 | 516 | - all-filelogs |
|
503 | 517 | - changelog |
|
504 | 518 | - manifest |
|
505 | 519 | |
|
506 | 520 | additional optimizations are available by specifying "--optimize <name>": |
|
507 | 521 | |
|
508 | 522 | re-delta-parent |
|
509 | 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 | 525 | re-delta-multibase |
|
512 | 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 | 528 | re-delta-all |
|
515 | 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 | 531 | re-delta-fulladd |
|
518 | 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 | 535 | $ cd .. |
|
522 | 536 | |
|
523 | 537 | Upgrading a repository that is already modern essentially no-ops |
|
524 | 538 | |
|
525 | 539 | $ hg init modern |
|
526 | 540 | $ hg -R modern debugupgraderepo --run |
|
527 | 541 | nothing to do |
|
528 | 542 | |
|
529 | 543 | Upgrading a repository to generaldelta works |
|
530 | 544 | |
|
531 | 545 | $ hg --config format.usegeneraldelta=false init upgradegd |
|
532 | 546 | $ cd upgradegd |
|
533 | 547 | $ touch f0 |
|
534 | 548 | $ hg -q commit -A -m initial |
|
535 | 549 | $ mkdir FooBarDirectory.d |
|
536 | 550 | $ touch FooBarDirectory.d/f1 |
|
537 | 551 | $ hg -q commit -A -m 'add f1' |
|
538 | 552 | $ hg -q up -r 0 |
|
539 | 553 | >>> from __future__ import absolute_import, print_function |
|
540 | 554 | >>> import random |
|
541 | 555 | >>> random.seed(0) # have a reproducible content |
|
542 | 556 | >>> with open("f2", "wb") as f: |
|
543 | 557 | ... for i in range(100000): |
|
544 | 558 | ... f.write(b"%d\n" % random.randint(1000000000, 9999999999)) and None |
|
545 | 559 | $ hg -q commit -A -m 'add f2' |
|
546 | 560 | |
|
547 | 561 | make sure we have a .d file |
|
548 | 562 | |
|
549 | 563 | $ ls -d .hg/store/data/* |
|
550 | 564 | .hg/store/data/_foo_bar_directory.d.hg |
|
551 | 565 | .hg/store/data/f0.i |
|
552 | 566 | .hg/store/data/f2.d |
|
553 | 567 | .hg/store/data/f2.i |
|
554 | 568 | |
|
555 | 569 | $ hg debugupgraderepo --run --config format.sparse-revlog=false |
|
556 | 570 | upgrade will perform the following actions: |
|
557 | 571 | |
|
558 | 572 | requirements |
|
559 | 573 | preserved: dotencode, fncache, revlogv1, store (no-rust !) |
|
560 | 574 | preserved: dotencode, fncache, persistent-nodemap, revlogv1, store (rust !) |
|
561 | 575 | added: generaldelta |
|
562 | 576 | |
|
563 | 577 | generaldelta |
|
564 | 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 | 580 | processed revlogs: |
|
567 | 581 | - all-filelogs |
|
568 | 582 | - changelog |
|
569 | 583 | - manifest |
|
570 | 584 | |
|
571 | 585 | beginning upgrade... |
|
572 | 586 | repository locked and read-only |
|
573 | 587 | creating temporary repository to stage upgraded data: $TESTTMP/upgradegd/.hg/upgrade.* (glob) |
|
574 | 588 | (it is safe to interrupt this process any time before data migration completes) |
|
575 | 589 | migrating 9 total revisions (3 in filelogs, 3 in manifests, 3 in changelog) |
|
576 | 590 | migrating 519 KB in store; 1.05 MB tracked data |
|
577 | 591 | migrating 3 filelogs containing 3 revisions (518 KB in store; 1.05 MB tracked data) |
|
578 | 592 | finished migrating 3 filelog revisions across 3 filelogs; change in size: 0 bytes |
|
579 | 593 | migrating 1 manifests containing 3 revisions (384 bytes in store; 238 bytes tracked data) |
|
580 | 594 | finished migrating 3 manifest revisions across 1 manifests; change in size: -17 bytes |
|
581 | 595 | migrating changelog containing 3 revisions (394 bytes in store; 199 bytes tracked data) |
|
582 | 596 | finished migrating 3 changelog revisions; change in size: 0 bytes |
|
583 | 597 | finished migrating 9 total revisions; total change in store size: -17 bytes |
|
584 | 598 | copying phaseroots |
|
585 | 599 | data fully upgraded in a temporary repository |
|
586 | 600 | marking source repository as being upgraded; clients will be unable to read from repository |
|
587 | 601 | starting in-place swap of repository data |
|
588 | 602 | replaced files will be backed up at $TESTTMP/upgradegd/.hg/upgradebackup.* (glob) |
|
589 | 603 | replacing store... |
|
590 | 604 | store replacement complete; repository was inconsistent for *s (glob) |
|
591 | 605 | finalizing requirements file and making repository readable again |
|
592 | 606 | removing temporary repository $TESTTMP/upgradegd/.hg/upgrade.* (glob) |
|
593 | 607 | copy of old repository backed up at $TESTTMP/upgradegd/.hg/upgradebackup.* (glob) |
|
594 | 608 | the old repository will not be deleted; remove it to free up disk space once the upgraded repository is verified |
|
595 | 609 | |
|
596 | 610 | Original requirements backed up |
|
597 | 611 | |
|
598 | 612 | $ cat .hg/upgradebackup.*/requires |
|
599 | 613 | dotencode |
|
600 | 614 | fncache |
|
601 | 615 | persistent-nodemap (rust !) |
|
602 | 616 | revlogv1 |
|
603 | 617 | store |
|
604 | 618 | |
|
605 | 619 | generaldelta added to original requirements files |
|
606 | 620 | |
|
607 | 621 | $ cat .hg/requires |
|
608 | 622 | dotencode |
|
609 | 623 | fncache |
|
610 | 624 | generaldelta |
|
611 | 625 | persistent-nodemap (rust !) |
|
612 | 626 | revlogv1 |
|
613 | 627 | store |
|
614 | 628 | |
|
615 | 629 | store directory has files we expect |
|
616 | 630 | |
|
617 | 631 | $ ls .hg/store |
|
618 | 632 | 00changelog.i |
|
619 | 633 | 00manifest.i |
|
620 | 634 | data |
|
621 | 635 | fncache |
|
622 | 636 | phaseroots |
|
623 | 637 | undo |
|
624 | 638 | undo.backupfiles |
|
625 | 639 | undo.phaseroots |
|
626 | 640 | |
|
627 | 641 | manifest should be generaldelta |
|
628 | 642 | |
|
629 | 643 | $ hg debugrevlog -m | grep flags |
|
630 | 644 | flags : inline, generaldelta |
|
631 | 645 | |
|
632 | 646 | verify should be happy |
|
633 | 647 | |
|
634 | 648 | $ hg verify |
|
635 | 649 | checking changesets |
|
636 | 650 | checking manifests |
|
637 | 651 | crosschecking files in changesets and manifests |
|
638 | 652 | checking files |
|
639 | 653 | checked 3 changesets with 3 changes to 3 files |
|
640 | 654 | |
|
641 | 655 | old store should be backed up |
|
642 | 656 | |
|
643 | 657 | $ ls -d .hg/upgradebackup.*/ |
|
644 | 658 | .hg/upgradebackup.*/ (glob) |
|
645 | 659 | $ ls .hg/upgradebackup.*/store |
|
646 | 660 | 00changelog.i |
|
647 | 661 | 00manifest.i |
|
648 | 662 | data |
|
649 | 663 | fncache |
|
650 | 664 | phaseroots |
|
651 | 665 | undo |
|
652 | 666 | undo.backup.fncache |
|
653 | 667 | undo.backupfiles |
|
654 | 668 | undo.phaseroots |
|
655 | 669 | |
|
656 | 670 | unless --no-backup is passed |
|
657 | 671 | |
|
658 | 672 | $ rm -rf .hg/upgradebackup.*/ |
|
659 | 673 | $ hg debugupgraderepo --run --no-backup |
|
660 | 674 | upgrade will perform the following actions: |
|
661 | 675 | |
|
662 | 676 | requirements |
|
663 | 677 | preserved: dotencode, fncache, generaldelta, revlogv1, store (no-rust !) |
|
664 | 678 | preserved: dotencode, fncache, generaldelta, persistent-nodemap, revlogv1, store (rust !) |
|
665 | 679 | added: sparserevlog |
|
666 | 680 | |
|
667 | 681 | sparserevlog |
|
668 | 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 | 684 | processed revlogs: |
|
671 | 685 | - all-filelogs |
|
672 | 686 | - changelog |
|
673 | 687 | - manifest |
|
674 | 688 | |
|
675 | 689 | beginning upgrade... |
|
676 | 690 | repository locked and read-only |
|
677 | 691 | creating temporary repository to stage upgraded data: $TESTTMP/upgradegd/.hg/upgrade.* (glob) |
|
678 | 692 | (it is safe to interrupt this process any time before data migration completes) |
|
679 | 693 | migrating 9 total revisions (3 in filelogs, 3 in manifests, 3 in changelog) |
|
680 | 694 | migrating 519 KB in store; 1.05 MB tracked data |
|
681 | 695 | migrating 3 filelogs containing 3 revisions (518 KB in store; 1.05 MB tracked data) |
|
682 | 696 | finished migrating 3 filelog revisions across 3 filelogs; change in size: 0 bytes |
|
683 | 697 | migrating 1 manifests containing 3 revisions (367 bytes in store; 238 bytes tracked data) |
|
684 | 698 | finished migrating 3 manifest revisions across 1 manifests; change in size: 0 bytes |
|
685 | 699 | migrating changelog containing 3 revisions (394 bytes in store; 199 bytes tracked data) |
|
686 | 700 | finished migrating 3 changelog revisions; change in size: 0 bytes |
|
687 | 701 | finished migrating 9 total revisions; total change in store size: 0 bytes |
|
688 | 702 | copying phaseroots |
|
689 | 703 | data fully upgraded in a temporary repository |
|
690 | 704 | marking source repository as being upgraded; clients will be unable to read from repository |
|
691 | 705 | starting in-place swap of repository data |
|
692 | 706 | replacing store... |
|
693 | 707 | store replacement complete; repository was inconsistent for * (glob) |
|
694 | 708 | finalizing requirements file and making repository readable again |
|
695 | 709 | removing temporary repository $TESTTMP/upgradegd/.hg/upgrade.* (glob) |
|
696 | 710 | $ ls -1 .hg/ | grep upgradebackup |
|
697 | 711 | [1] |
|
698 | 712 | |
|
699 | 713 | We can restrict optimization to some revlog: |
|
700 | 714 | |
|
701 | 715 | $ hg debugupgrade --optimize re-delta-parent --run --manifest --no-backup --debug --traceback |
|
702 | 716 | upgrade will perform the following actions: |
|
703 | 717 | |
|
704 | 718 | requirements |
|
705 | 719 | preserved: dotencode, fncache, generaldelta, revlogv1, sparserevlog, store (no-rust !) |
|
706 | 720 | preserved: dotencode, fncache, generaldelta, persistent-nodemap, revlogv1, sparserevlog, store (rust !) |
|
707 | 721 | |
|
708 | 722 | optimisations: re-delta-parent |
|
709 | 723 | |
|
710 | 724 | re-delta-parent |
|
711 | 725 | deltas within internal storage will choose a new base revision if needed |
|
712 | 726 | |
|
713 | 727 | processed revlogs: |
|
714 | 728 | - manifest |
|
715 | 729 | |
|
716 | 730 | beginning upgrade... |
|
717 | 731 | repository locked and read-only |
|
718 | 732 | creating temporary repository to stage upgraded data: $TESTTMP/upgradegd/.hg/upgrade.* (glob) |
|
719 | 733 | (it is safe to interrupt this process any time before data migration completes) |
|
720 | 734 | migrating 9 total revisions (3 in filelogs, 3 in manifests, 3 in changelog) |
|
721 | 735 | migrating 519 KB in store; 1.05 MB tracked data |
|
722 | 736 | migrating 3 filelogs containing 3 revisions (518 KB in store; 1.05 MB tracked data) |
|
723 | 737 | blindly copying data/FooBarDirectory.d/f1.i containing 1 revisions |
|
724 | 738 | blindly copying data/f0.i containing 1 revisions |
|
725 | 739 | blindly copying data/f2.i containing 1 revisions |
|
726 | 740 | finished migrating 3 filelog revisions across 3 filelogs; change in size: 0 bytes |
|
727 | 741 | migrating 1 manifests containing 3 revisions (367 bytes in store; 238 bytes tracked data) |
|
728 | 742 | cloning 3 revisions from 00manifest.i |
|
729 | 743 | finished migrating 3 manifest revisions across 1 manifests; change in size: 0 bytes |
|
730 | 744 | migrating changelog containing 3 revisions (394 bytes in store; 199 bytes tracked data) |
|
731 | 745 | blindly copying 00changelog.i containing 3 revisions |
|
732 | 746 | finished migrating 3 changelog revisions; change in size: 0 bytes |
|
733 | 747 | finished migrating 9 total revisions; total change in store size: 0 bytes |
|
734 | 748 | copying phaseroots |
|
735 | 749 | data fully upgraded in a temporary repository |
|
736 | 750 | marking source repository as being upgraded; clients will be unable to read from repository |
|
737 | 751 | starting in-place swap of repository data |
|
738 | 752 | replacing store... |
|
739 | 753 | store replacement complete; repository was inconsistent for *s (glob) |
|
740 | 754 | finalizing requirements file and making repository readable again |
|
741 | 755 | removing temporary repository $TESTTMP/upgradegd/.hg/upgrade.* (glob) |
|
742 | 756 | |
|
743 | 757 | Check that the repo still works fine |
|
744 | 758 | |
|
745 | 759 | $ hg log -G --stat |
|
746 | 760 | @ changeset: 2:76d4395f5413 (no-py3 !) |
|
747 | 761 | @ changeset: 2:fca376863211 (py3 !) |
|
748 | 762 | | tag: tip |
|
749 | 763 | | parent: 0:ba592bf28da2 |
|
750 | 764 | | user: test |
|
751 | 765 | | date: Thu Jan 01 00:00:00 1970 +0000 |
|
752 | 766 | | summary: add f2 |
|
753 | 767 | | |
|
754 | 768 | | f2 | 100000 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ |
|
755 | 769 | | 1 files changed, 100000 insertions(+), 0 deletions(-) |
|
756 | 770 | | |
|
757 | 771 | | o changeset: 1:2029ce2354e2 |
|
758 | 772 | |/ user: test |
|
759 | 773 | | date: Thu Jan 01 00:00:00 1970 +0000 |
|
760 | 774 | | summary: add f1 |
|
761 | 775 | | |
|
762 | 776 | | |
|
763 | 777 | o changeset: 0:ba592bf28da2 |
|
764 | 778 | user: test |
|
765 | 779 | date: Thu Jan 01 00:00:00 1970 +0000 |
|
766 | 780 | summary: initial |
|
767 | 781 | |
|
768 | 782 | |
|
769 | 783 | |
|
770 | 784 | $ hg verify |
|
771 | 785 | checking changesets |
|
772 | 786 | checking manifests |
|
773 | 787 | crosschecking files in changesets and manifests |
|
774 | 788 | checking files |
|
775 | 789 | checked 3 changesets with 3 changes to 3 files |
|
776 | 790 | |
|
777 | 791 | Check we can select negatively |
|
778 | 792 | |
|
779 | 793 | $ hg debugupgrade --optimize re-delta-parent --run --no-manifest --no-backup --debug --traceback |
|
780 | 794 | upgrade will perform the following actions: |
|
781 | 795 | |
|
782 | 796 | requirements |
|
783 | 797 | preserved: dotencode, fncache, generaldelta, revlogv1, sparserevlog, store (no-rust !) |
|
784 | 798 | preserved: dotencode, fncache, generaldelta, persistent-nodemap, revlogv1, sparserevlog, store (rust !) |
|
785 | 799 | |
|
786 | 800 | optimisations: re-delta-parent |
|
787 | 801 | |
|
788 | 802 | re-delta-parent |
|
789 | 803 | deltas within internal storage will choose a new base revision if needed |
|
790 | 804 | |
|
791 | 805 | processed revlogs: |
|
792 | 806 | - all-filelogs |
|
793 | 807 | - changelog |
|
794 | 808 | |
|
795 | 809 | beginning upgrade... |
|
796 | 810 | repository locked and read-only |
|
797 | 811 | creating temporary repository to stage upgraded data: $TESTTMP/upgradegd/.hg/upgrade.* (glob) |
|
798 | 812 | (it is safe to interrupt this process any time before data migration completes) |
|
799 | 813 | migrating 9 total revisions (3 in filelogs, 3 in manifests, 3 in changelog) |
|
800 | 814 | migrating 519 KB in store; 1.05 MB tracked data |
|
801 | 815 | migrating 3 filelogs containing 3 revisions (518 KB in store; 1.05 MB tracked data) |
|
802 | 816 | cloning 1 revisions from data/FooBarDirectory.d/f1.i |
|
803 | 817 | cloning 1 revisions from data/f0.i |
|
804 | 818 | cloning 1 revisions from data/f2.i |
|
805 | 819 | finished migrating 3 filelog revisions across 3 filelogs; change in size: 0 bytes |
|
806 | 820 | migrating 1 manifests containing 3 revisions (367 bytes in store; 238 bytes tracked data) |
|
807 | 821 | blindly copying 00manifest.i containing 3 revisions |
|
808 | 822 | finished migrating 3 manifest revisions across 1 manifests; change in size: 0 bytes |
|
809 | 823 | migrating changelog containing 3 revisions (394 bytes in store; 199 bytes tracked data) |
|
810 | 824 | cloning 3 revisions from 00changelog.i |
|
811 | 825 | finished migrating 3 changelog revisions; change in size: 0 bytes |
|
812 | 826 | finished migrating 9 total revisions; total change in store size: 0 bytes |
|
813 | 827 | copying phaseroots |
|
814 | 828 | data fully upgraded in a temporary repository |
|
815 | 829 | marking source repository as being upgraded; clients will be unable to read from repository |
|
816 | 830 | starting in-place swap of repository data |
|
817 | 831 | replacing store... |
|
818 | 832 | store replacement complete; repository was inconsistent for *s (glob) |
|
819 | 833 | finalizing requirements file and making repository readable again |
|
820 | 834 | removing temporary repository $TESTTMP/upgradegd/.hg/upgrade.* (glob) |
|
821 | 835 | $ hg verify |
|
822 | 836 | checking changesets |
|
823 | 837 | checking manifests |
|
824 | 838 | crosschecking files in changesets and manifests |
|
825 | 839 | checking files |
|
826 | 840 | checked 3 changesets with 3 changes to 3 files |
|
827 | 841 | |
|
828 | 842 | Check that we can select changelog only |
|
829 | 843 | |
|
830 | 844 | $ hg debugupgrade --optimize re-delta-parent --run --changelog --no-backup --debug --traceback |
|
831 | 845 | upgrade will perform the following actions: |
|
832 | 846 | |
|
833 | 847 | requirements |
|
834 | 848 | preserved: dotencode, fncache, generaldelta, revlogv1, sparserevlog, store (no-rust !) |
|
835 | 849 | preserved: dotencode, fncache, generaldelta, persistent-nodemap, revlogv1, sparserevlog, store (rust !) |
|
836 | 850 | |
|
837 | 851 | optimisations: re-delta-parent |
|
838 | 852 | |
|
839 | 853 | re-delta-parent |
|
840 | 854 | deltas within internal storage will choose a new base revision if needed |
|
841 | 855 | |
|
842 | 856 | processed revlogs: |
|
843 | 857 | - changelog |
|
844 | 858 | |
|
845 | 859 | beginning upgrade... |
|
846 | 860 | repository locked and read-only |
|
847 | 861 | creating temporary repository to stage upgraded data: $TESTTMP/upgradegd/.hg/upgrade.* (glob) |
|
848 | 862 | (it is safe to interrupt this process any time before data migration completes) |
|
849 | 863 | migrating 9 total revisions (3 in filelogs, 3 in manifests, 3 in changelog) |
|
850 | 864 | migrating 519 KB in store; 1.05 MB tracked data |
|
851 | 865 | migrating 3 filelogs containing 3 revisions (518 KB in store; 1.05 MB tracked data) |
|
852 | 866 | blindly copying data/FooBarDirectory.d/f1.i containing 1 revisions |
|
853 | 867 | blindly copying data/f0.i containing 1 revisions |
|
854 | 868 | blindly copying data/f2.i containing 1 revisions |
|
855 | 869 | finished migrating 3 filelog revisions across 3 filelogs; change in size: 0 bytes |
|
856 | 870 | migrating 1 manifests containing 3 revisions (367 bytes in store; 238 bytes tracked data) |
|
857 | 871 | blindly copying 00manifest.i containing 3 revisions |
|
858 | 872 | finished migrating 3 manifest revisions across 1 manifests; change in size: 0 bytes |
|
859 | 873 | migrating changelog containing 3 revisions (394 bytes in store; 199 bytes tracked data) |
|
860 | 874 | cloning 3 revisions from 00changelog.i |
|
861 | 875 | finished migrating 3 changelog revisions; change in size: 0 bytes |
|
862 | 876 | finished migrating 9 total revisions; total change in store size: 0 bytes |
|
863 | 877 | copying phaseroots |
|
864 | 878 | data fully upgraded in a temporary repository |
|
865 | 879 | marking source repository as being upgraded; clients will be unable to read from repository |
|
866 | 880 | starting in-place swap of repository data |
|
867 | 881 | replacing store... |
|
868 | 882 | store replacement complete; repository was inconsistent for *s (glob) |
|
869 | 883 | finalizing requirements file and making repository readable again |
|
870 | 884 | removing temporary repository $TESTTMP/upgradegd/.hg/upgrade.* (glob) |
|
871 | 885 | $ hg verify |
|
872 | 886 | checking changesets |
|
873 | 887 | checking manifests |
|
874 | 888 | crosschecking files in changesets and manifests |
|
875 | 889 | checking files |
|
876 | 890 | checked 3 changesets with 3 changes to 3 files |
|
877 | 891 | |
|
878 | 892 | Check that we can select filelog only |
|
879 | 893 | |
|
880 | 894 | $ hg debugupgrade --optimize re-delta-parent --run --no-changelog --no-manifest --no-backup --debug --traceback |
|
881 | 895 | upgrade will perform the following actions: |
|
882 | 896 | |
|
883 | 897 | requirements |
|
884 | 898 | preserved: dotencode, fncache, generaldelta, revlogv1, sparserevlog, store (no-rust !) |
|
885 | 899 | preserved: dotencode, fncache, generaldelta, persistent-nodemap, revlogv1, sparserevlog, store (rust !) |
|
886 | 900 | |
|
887 | 901 | optimisations: re-delta-parent |
|
888 | 902 | |
|
889 | 903 | re-delta-parent |
|
890 | 904 | deltas within internal storage will choose a new base revision if needed |
|
891 | 905 | |
|
892 | 906 | processed revlogs: |
|
893 | 907 | - all-filelogs |
|
894 | 908 | |
|
895 | 909 | beginning upgrade... |
|
896 | 910 | repository locked and read-only |
|
897 | 911 | creating temporary repository to stage upgraded data: $TESTTMP/upgradegd/.hg/upgrade.* (glob) |
|
898 | 912 | (it is safe to interrupt this process any time before data migration completes) |
|
899 | 913 | migrating 9 total revisions (3 in filelogs, 3 in manifests, 3 in changelog) |
|
900 | 914 | migrating 519 KB in store; 1.05 MB tracked data |
|
901 | 915 | migrating 3 filelogs containing 3 revisions (518 KB in store; 1.05 MB tracked data) |
|
902 | 916 | cloning 1 revisions from data/FooBarDirectory.d/f1.i |
|
903 | 917 | cloning 1 revisions from data/f0.i |
|
904 | 918 | cloning 1 revisions from data/f2.i |
|
905 | 919 | finished migrating 3 filelog revisions across 3 filelogs; change in size: 0 bytes |
|
906 | 920 | migrating 1 manifests containing 3 revisions (367 bytes in store; 238 bytes tracked data) |
|
907 | 921 | blindly copying 00manifest.i containing 3 revisions |
|
908 | 922 | finished migrating 3 manifest revisions across 1 manifests; change in size: 0 bytes |
|
909 | 923 | migrating changelog containing 3 revisions (394 bytes in store; 199 bytes tracked data) |
|
910 | 924 | blindly copying 00changelog.i containing 3 revisions |
|
911 | 925 | finished migrating 3 changelog revisions; change in size: 0 bytes |
|
912 | 926 | finished migrating 9 total revisions; total change in store size: 0 bytes |
|
913 | 927 | copying phaseroots |
|
914 | 928 | data fully upgraded in a temporary repository |
|
915 | 929 | marking source repository as being upgraded; clients will be unable to read from repository |
|
916 | 930 | starting in-place swap of repository data |
|
917 | 931 | replacing store... |
|
918 | 932 | store replacement complete; repository was inconsistent for *s (glob) |
|
919 | 933 | finalizing requirements file and making repository readable again |
|
920 | 934 | removing temporary repository $TESTTMP/upgradegd/.hg/upgrade.* (glob) |
|
921 | 935 | $ hg verify |
|
922 | 936 | checking changesets |
|
923 | 937 | checking manifests |
|
924 | 938 | crosschecking files in changesets and manifests |
|
925 | 939 | checking files |
|
926 | 940 | checked 3 changesets with 3 changes to 3 files |
|
927 | 941 | |
|
928 | 942 | |
|
929 | 943 | Check you can't skip revlog clone during important format downgrade |
|
930 | 944 | |
|
931 | 945 | $ echo "[format]" > .hg/hgrc |
|
932 | 946 | $ echo "sparse-revlog=no" >> .hg/hgrc |
|
933 | 947 | $ hg debugupgrade --optimize re-delta-parent --run --manifest --no-backup --debug --traceback |
|
934 | 948 | ignoring revlogs selection flags, format requirements change: sparserevlog |
|
935 | 949 | upgrade will perform the following actions: |
|
936 | 950 | |
|
937 | 951 | requirements |
|
938 | 952 | preserved: dotencode, fncache, generaldelta, revlogv1, store (no-rust !) |
|
939 | 953 | preserved: dotencode, fncache, generaldelta, persistent-nodemap, revlogv1, store (rust !) |
|
940 | 954 | removed: sparserevlog |
|
941 | 955 | |
|
942 | 956 | optimisations: re-delta-parent |
|
943 | 957 | |
|
944 | 958 | re-delta-parent |
|
945 | 959 | deltas within internal storage will choose a new base revision if needed |
|
946 | 960 | |
|
947 | 961 | processed revlogs: |
|
948 | 962 | - all-filelogs |
|
949 | 963 | - changelog |
|
950 | 964 | - manifest |
|
951 | 965 | |
|
952 | 966 | beginning upgrade... |
|
953 | 967 | repository locked and read-only |
|
954 | 968 | creating temporary repository to stage upgraded data: $TESTTMP/upgradegd/.hg/upgrade.* (glob) |
|
955 | 969 | (it is safe to interrupt this process any time before data migration completes) |
|
956 | 970 | migrating 9 total revisions (3 in filelogs, 3 in manifests, 3 in changelog) |
|
957 | 971 | migrating 519 KB in store; 1.05 MB tracked data |
|
958 | 972 | migrating 3 filelogs containing 3 revisions (518 KB in store; 1.05 MB tracked data) |
|
959 | 973 | cloning 1 revisions from data/FooBarDirectory.d/f1.i |
|
960 | 974 | cloning 1 revisions from data/f0.i |
|
961 | 975 | cloning 1 revisions from data/f2.i |
|
962 | 976 | finished migrating 3 filelog revisions across 3 filelogs; change in size: 0 bytes |
|
963 | 977 | migrating 1 manifests containing 3 revisions (367 bytes in store; 238 bytes tracked data) |
|
964 | 978 | cloning 3 revisions from 00manifest.i |
|
965 | 979 | finished migrating 3 manifest revisions across 1 manifests; change in size: 0 bytes |
|
966 | 980 | migrating changelog containing 3 revisions (394 bytes in store; 199 bytes tracked data) |
|
967 | 981 | cloning 3 revisions from 00changelog.i |
|
968 | 982 | finished migrating 3 changelog revisions; change in size: 0 bytes |
|
969 | 983 | finished migrating 9 total revisions; total change in store size: 0 bytes |
|
970 | 984 | copying phaseroots |
|
971 | 985 | data fully upgraded in a temporary repository |
|
972 | 986 | marking source repository as being upgraded; clients will be unable to read from repository |
|
973 | 987 | starting in-place swap of repository data |
|
974 | 988 | replacing store... |
|
975 | 989 | store replacement complete; repository was inconsistent for *s (glob) |
|
976 | 990 | finalizing requirements file and making repository readable again |
|
977 | 991 | removing temporary repository $TESTTMP/upgradegd/.hg/upgrade.* (glob) |
|
978 | 992 | $ hg verify |
|
979 | 993 | checking changesets |
|
980 | 994 | checking manifests |
|
981 | 995 | crosschecking files in changesets and manifests |
|
982 | 996 | checking files |
|
983 | 997 | checked 3 changesets with 3 changes to 3 files |
|
984 | 998 | |
|
985 | 999 | Check you can't skip revlog clone during important format upgrade |
|
986 | 1000 | |
|
987 | 1001 | $ echo "sparse-revlog=yes" >> .hg/hgrc |
|
988 | 1002 | $ hg debugupgrade --optimize re-delta-parent --run --manifest --no-backup --debug --traceback |
|
989 | 1003 | ignoring revlogs selection flags, format requirements change: sparserevlog |
|
990 | 1004 | upgrade will perform the following actions: |
|
991 | 1005 | |
|
992 | 1006 | requirements |
|
993 | 1007 | preserved: dotencode, fncache, generaldelta, revlogv1, store (no-rust !) |
|
994 | 1008 | preserved: dotencode, fncache, generaldelta, persistent-nodemap, revlogv1, store (rust !) |
|
995 | 1009 | added: sparserevlog |
|
996 | 1010 | |
|
997 | 1011 | optimisations: re-delta-parent |
|
998 | 1012 | |
|
999 | 1013 | sparserevlog |
|
1000 | 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 | 1016 | re-delta-parent |
|
1003 | 1017 | deltas within internal storage will choose a new base revision if needed |
|
1004 | 1018 | |
|
1005 | 1019 | processed revlogs: |
|
1006 | 1020 | - all-filelogs |
|
1007 | 1021 | - changelog |
|
1008 | 1022 | - manifest |
|
1009 | 1023 | |
|
1010 | 1024 | beginning upgrade... |
|
1011 | 1025 | repository locked and read-only |
|
1012 | 1026 | creating temporary repository to stage upgraded data: $TESTTMP/upgradegd/.hg/upgrade.* (glob) |
|
1013 | 1027 | (it is safe to interrupt this process any time before data migration completes) |
|
1014 | 1028 | migrating 9 total revisions (3 in filelogs, 3 in manifests, 3 in changelog) |
|
1015 | 1029 | migrating 519 KB in store; 1.05 MB tracked data |
|
1016 | 1030 | migrating 3 filelogs containing 3 revisions (518 KB in store; 1.05 MB tracked data) |
|
1017 | 1031 | cloning 1 revisions from data/FooBarDirectory.d/f1.i |
|
1018 | 1032 | cloning 1 revisions from data/f0.i |
|
1019 | 1033 | cloning 1 revisions from data/f2.i |
|
1020 | 1034 | finished migrating 3 filelog revisions across 3 filelogs; change in size: 0 bytes |
|
1021 | 1035 | migrating 1 manifests containing 3 revisions (367 bytes in store; 238 bytes tracked data) |
|
1022 | 1036 | cloning 3 revisions from 00manifest.i |
|
1023 | 1037 | finished migrating 3 manifest revisions across 1 manifests; change in size: 0 bytes |
|
1024 | 1038 | migrating changelog containing 3 revisions (394 bytes in store; 199 bytes tracked data) |
|
1025 | 1039 | cloning 3 revisions from 00changelog.i |
|
1026 | 1040 | finished migrating 3 changelog revisions; change in size: 0 bytes |
|
1027 | 1041 | finished migrating 9 total revisions; total change in store size: 0 bytes |
|
1028 | 1042 | copying phaseroots |
|
1029 | 1043 | data fully upgraded in a temporary repository |
|
1030 | 1044 | marking source repository as being upgraded; clients will be unable to read from repository |
|
1031 | 1045 | starting in-place swap of repository data |
|
1032 | 1046 | replacing store... |
|
1033 | 1047 | store replacement complete; repository was inconsistent for *s (glob) |
|
1034 | 1048 | finalizing requirements file and making repository readable again |
|
1035 | 1049 | removing temporary repository $TESTTMP/upgradegd/.hg/upgrade.* (glob) |
|
1036 | 1050 | $ hg verify |
|
1037 | 1051 | checking changesets |
|
1038 | 1052 | checking manifests |
|
1039 | 1053 | crosschecking files in changesets and manifests |
|
1040 | 1054 | checking files |
|
1041 | 1055 | checked 3 changesets with 3 changes to 3 files |
|
1042 | 1056 | |
|
1043 | 1057 | $ cd .. |
|
1044 | 1058 | |
|
1045 | 1059 | store files with special filenames aren't encoded during copy |
|
1046 | 1060 | |
|
1047 | 1061 | $ hg init store-filenames |
|
1048 | 1062 | $ cd store-filenames |
|
1049 | 1063 | $ touch foo |
|
1050 | 1064 | $ hg -q commit -A -m initial |
|
1051 | 1065 | $ touch .hg/store/.XX_special_filename |
|
1052 | 1066 | |
|
1053 | 1067 | $ hg debugupgraderepo --run |
|
1054 | 1068 | nothing to do |
|
1055 | 1069 | $ hg debugupgraderepo --run --optimize 're-delta-fulladd' |
|
1056 | 1070 | upgrade will perform the following actions: |
|
1057 | 1071 | |
|
1058 | 1072 | requirements |
|
1059 | 1073 | preserved: dotencode, fncache, generaldelta, revlogv1, sparserevlog, store (no-rust !) |
|
1060 | 1074 | preserved: dotencode, fncache, generaldelta, persistent-nodemap, revlogv1, sparserevlog, store (rust !) |
|
1061 | 1075 | |
|
1062 | 1076 | optimisations: re-delta-fulladd |
|
1063 | 1077 | |
|
1064 | 1078 | re-delta-fulladd |
|
1065 | 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 | 1081 | processed revlogs: |
|
1068 | 1082 | - all-filelogs |
|
1069 | 1083 | - changelog |
|
1070 | 1084 | - manifest |
|
1071 | 1085 | |
|
1072 | 1086 | beginning upgrade... |
|
1073 | 1087 | repository locked and read-only |
|
1074 | 1088 | creating temporary repository to stage upgraded data: $TESTTMP/store-filenames/.hg/upgrade.* (glob) |
|
1075 | 1089 | (it is safe to interrupt this process any time before data migration completes) |
|
1076 | 1090 | migrating 3 total revisions (1 in filelogs, 1 in manifests, 1 in changelog) |
|
1077 | 1091 | migrating 301 bytes in store; 107 bytes tracked data |
|
1078 | 1092 | migrating 1 filelogs containing 1 revisions (64 bytes in store; 0 bytes tracked data) |
|
1079 | 1093 | finished migrating 1 filelog revisions across 1 filelogs; change in size: 0 bytes |
|
1080 | 1094 | migrating 1 manifests containing 1 revisions (110 bytes in store; 45 bytes tracked data) |
|
1081 | 1095 | finished migrating 1 manifest revisions across 1 manifests; change in size: 0 bytes |
|
1082 | 1096 | migrating changelog containing 1 revisions (127 bytes in store; 62 bytes tracked data) |
|
1083 | 1097 | finished migrating 1 changelog revisions; change in size: 0 bytes |
|
1084 | 1098 | finished migrating 3 total revisions; total change in store size: 0 bytes |
|
1085 | 1099 | copying .XX_special_filename |
|
1086 | 1100 | copying phaseroots |
|
1087 | 1101 | data fully upgraded in a temporary repository |
|
1088 | 1102 | marking source repository as being upgraded; clients will be unable to read from repository |
|
1089 | 1103 | starting in-place swap of repository data |
|
1090 | 1104 | replaced files will be backed up at $TESTTMP/store-filenames/.hg/upgradebackup.* (glob) |
|
1091 | 1105 | replacing store... |
|
1092 | 1106 | store replacement complete; repository was inconsistent for *s (glob) |
|
1093 | 1107 | finalizing requirements file and making repository readable again |
|
1094 | 1108 | removing temporary repository $TESTTMP/store-filenames/.hg/upgrade.* (glob) |
|
1095 | 1109 | copy of old repository backed up at $TESTTMP/store-filenames/.hg/upgradebackup.* (glob) |
|
1096 | 1110 | the old repository will not be deleted; remove it to free up disk space once the upgraded repository is verified |
|
1097 | 1111 | |
|
1098 | 1112 | fncache is valid after upgrade |
|
1099 | 1113 | |
|
1100 | 1114 | $ hg debugrebuildfncache |
|
1101 | 1115 | fncache already up to date |
|
1102 | 1116 | |
|
1103 | 1117 | $ cd .. |
|
1104 | 1118 | |
|
1105 | 1119 | Check upgrading a large file repository |
|
1106 | 1120 | --------------------------------------- |
|
1107 | 1121 | |
|
1108 | 1122 | $ hg init largefilesrepo |
|
1109 | 1123 | $ cat << EOF >> largefilesrepo/.hg/hgrc |
|
1110 | 1124 | > [extensions] |
|
1111 | 1125 | > largefiles = |
|
1112 | 1126 | > EOF |
|
1113 | 1127 | |
|
1114 | 1128 | $ cd largefilesrepo |
|
1115 | 1129 | $ touch foo |
|
1116 | 1130 | $ hg add --large foo |
|
1117 | 1131 | $ hg -q commit -m initial |
|
1118 | 1132 | $ cat .hg/requires |
|
1119 | 1133 | dotencode |
|
1120 | 1134 | fncache |
|
1121 | 1135 | generaldelta |
|
1122 | 1136 | largefiles |
|
1123 | 1137 | persistent-nodemap (rust !) |
|
1124 | 1138 | revlogv1 |
|
1125 | 1139 | sparserevlog |
|
1126 | 1140 | store |
|
1127 | 1141 | |
|
1128 | 1142 | $ hg debugupgraderepo --run |
|
1129 | 1143 | nothing to do |
|
1130 | 1144 | $ cat .hg/requires |
|
1131 | 1145 | dotencode |
|
1132 | 1146 | fncache |
|
1133 | 1147 | generaldelta |
|
1134 | 1148 | largefiles |
|
1135 | 1149 | persistent-nodemap (rust !) |
|
1136 | 1150 | revlogv1 |
|
1137 | 1151 | sparserevlog |
|
1138 | 1152 | store |
|
1139 | 1153 | |
|
1140 | 1154 | $ cat << EOF >> .hg/hgrc |
|
1141 | 1155 | > [extensions] |
|
1142 | 1156 | > lfs = |
|
1143 | 1157 | > [lfs] |
|
1144 | 1158 | > threshold = 10 |
|
1145 | 1159 | > EOF |
|
1146 | 1160 | $ echo '123456789012345' > lfs.bin |
|
1147 | 1161 | $ hg ci -Am 'lfs.bin' |
|
1148 | 1162 | adding lfs.bin |
|
1149 | 1163 | $ grep lfs .hg/requires |
|
1150 | 1164 | lfs |
|
1151 | 1165 | $ find .hg/store/lfs -type f |
|
1152 | 1166 | .hg/store/lfs/objects/d0/beab232adff5ba365880366ad30b1edb85c4c5372442b5d2fe27adc96d653f |
|
1153 | 1167 | |
|
1154 | 1168 | $ hg debugupgraderepo --run |
|
1155 | 1169 | nothing to do |
|
1156 | 1170 | |
|
1157 | 1171 | $ grep lfs .hg/requires |
|
1158 | 1172 | lfs |
|
1159 | 1173 | $ find .hg/store/lfs -type f |
|
1160 | 1174 | .hg/store/lfs/objects/d0/beab232adff5ba365880366ad30b1edb85c4c5372442b5d2fe27adc96d653f |
|
1161 | 1175 | $ hg verify |
|
1162 | 1176 | checking changesets |
|
1163 | 1177 | checking manifests |
|
1164 | 1178 | crosschecking files in changesets and manifests |
|
1165 | 1179 | checking files |
|
1166 | 1180 | checked 2 changesets with 2 changes to 2 files |
|
1167 | 1181 | $ hg debugdata lfs.bin 0 |
|
1168 | 1182 | version https://git-lfs.github.com/spec/v1 |
|
1169 | 1183 | oid sha256:d0beab232adff5ba365880366ad30b1edb85c4c5372442b5d2fe27adc96d653f |
|
1170 | 1184 | size 16 |
|
1171 | 1185 | x-is-binary 0 |
|
1172 | 1186 | |
|
1173 | 1187 | $ cd .. |
|
1174 | 1188 | |
|
1175 | 1189 | repository config is taken in account |
|
1176 | 1190 | ------------------------------------- |
|
1177 | 1191 | |
|
1178 | 1192 | $ cat << EOF >> $HGRCPATH |
|
1179 | 1193 | > [format] |
|
1180 | 1194 | > maxchainlen = 1 |
|
1181 | 1195 | > EOF |
|
1182 | 1196 | |
|
1183 | 1197 | $ hg init localconfig |
|
1184 | 1198 | $ cd localconfig |
|
1185 | 1199 | $ cat << EOF > file |
|
1186 | 1200 | > some content |
|
1187 | 1201 | > with some length |
|
1188 | 1202 | > to make sure we get a delta |
|
1189 | 1203 | > after changes |
|
1190 | 1204 | > very long |
|
1191 | 1205 | > very long |
|
1192 | 1206 | > very long |
|
1193 | 1207 | > very long |
|
1194 | 1208 | > very long |
|
1195 | 1209 | > very long |
|
1196 | 1210 | > very long |
|
1197 | 1211 | > very long |
|
1198 | 1212 | > very long |
|
1199 | 1213 | > very long |
|
1200 | 1214 | > very long |
|
1201 | 1215 | > EOF |
|
1202 | 1216 | $ hg -q commit -A -m A |
|
1203 | 1217 | $ echo "new line" >> file |
|
1204 | 1218 | $ hg -q commit -m B |
|
1205 | 1219 | $ echo "new line" >> file |
|
1206 | 1220 | $ hg -q commit -m C |
|
1207 | 1221 | |
|
1208 | 1222 | $ cat << EOF >> .hg/hgrc |
|
1209 | 1223 | > [format] |
|
1210 | 1224 | > maxchainlen = 9001 |
|
1211 | 1225 | > EOF |
|
1212 | 1226 | $ hg config format |
|
1213 | 1227 | format.revlog-compression=$BUNDLE2_COMPRESSIONS$ |
|
1214 | 1228 | format.maxchainlen=9001 |
|
1215 | 1229 | $ hg debugdeltachain file |
|
1216 | 1230 | rev chain# chainlen prev delta size rawsize chainsize ratio lindist extradist extraratio readsize largestblk rddensity srchunks |
|
1217 | 1231 | 0 1 1 -1 base 77 182 77 0.42308 77 0 0.00000 77 77 1.00000 1 |
|
1218 | 1232 | 1 1 2 0 p1 21 191 98 0.51309 98 0 0.00000 98 98 1.00000 1 |
|
1219 | 1233 | 2 1 2 0 other 30 200 107 0.53500 128 21 0.19626 128 128 0.83594 1 |
|
1220 | 1234 | |
|
1221 | 1235 | $ hg debugupgraderepo --run --optimize 're-delta-all' |
|
1222 | 1236 | upgrade will perform the following actions: |
|
1223 | 1237 | |
|
1224 | 1238 | requirements |
|
1225 | 1239 | preserved: dotencode, fncache, generaldelta, revlogv1, sparserevlog, store (no-rust !) |
|
1226 | 1240 | preserved: dotencode, fncache, generaldelta, persistent-nodemap, revlogv1, sparserevlog, store (rust !) |
|
1227 | 1241 | |
|
1228 | 1242 | optimisations: re-delta-all |
|
1229 | 1243 | |
|
1230 | 1244 | re-delta-all |
|
1231 | 1245 | deltas within internal storage will be fully recomputed; this will likely drastically slow down execution time |
|
1232 | 1246 | |
|
1233 | 1247 | processed revlogs: |
|
1234 | 1248 | - all-filelogs |
|
1235 | 1249 | - changelog |
|
1236 | 1250 | - manifest |
|
1237 | 1251 | |
|
1238 | 1252 | beginning upgrade... |
|
1239 | 1253 | repository locked and read-only |
|
1240 | 1254 | creating temporary repository to stage upgraded data: $TESTTMP/localconfig/.hg/upgrade.* (glob) |
|
1241 | 1255 | (it is safe to interrupt this process any time before data migration completes) |
|
1242 | 1256 | migrating 9 total revisions (3 in filelogs, 3 in manifests, 3 in changelog) |
|
1243 | 1257 | migrating 1019 bytes in store; 882 bytes tracked data |
|
1244 | 1258 | migrating 1 filelogs containing 3 revisions (320 bytes in store; 573 bytes tracked data) |
|
1245 | 1259 | finished migrating 3 filelog revisions across 1 filelogs; change in size: -9 bytes |
|
1246 | 1260 | migrating 1 manifests containing 3 revisions (333 bytes in store; 138 bytes tracked data) |
|
1247 | 1261 | finished migrating 3 manifest revisions across 1 manifests; change in size: 0 bytes |
|
1248 | 1262 | migrating changelog containing 3 revisions (366 bytes in store; 171 bytes tracked data) |
|
1249 | 1263 | finished migrating 3 changelog revisions; change in size: 0 bytes |
|
1250 | 1264 | finished migrating 9 total revisions; total change in store size: -9 bytes |
|
1251 | 1265 | copying phaseroots |
|
1252 | 1266 | data fully upgraded in a temporary repository |
|
1253 | 1267 | marking source repository as being upgraded; clients will be unable to read from repository |
|
1254 | 1268 | starting in-place swap of repository data |
|
1255 | 1269 | replaced files will be backed up at $TESTTMP/localconfig/.hg/upgradebackup.* (glob) |
|
1256 | 1270 | replacing store... |
|
1257 | 1271 | store replacement complete; repository was inconsistent for *s (glob) |
|
1258 | 1272 | finalizing requirements file and making repository readable again |
|
1259 | 1273 | removing temporary repository $TESTTMP/localconfig/.hg/upgrade.* (glob) |
|
1260 | 1274 | copy of old repository backed up at $TESTTMP/localconfig/.hg/upgradebackup.* (glob) |
|
1261 | 1275 | the old repository will not be deleted; remove it to free up disk space once the upgraded repository is verified |
|
1262 | 1276 | $ hg debugdeltachain file |
|
1263 | 1277 | rev chain# chainlen prev delta size rawsize chainsize ratio lindist extradist extraratio readsize largestblk rddensity srchunks |
|
1264 | 1278 | 0 1 1 -1 base 77 182 77 0.42308 77 0 0.00000 77 77 1.00000 1 |
|
1265 | 1279 | 1 1 2 0 p1 21 191 98 0.51309 98 0 0.00000 98 98 1.00000 1 |
|
1266 | 1280 | 2 1 3 1 p1 21 200 119 0.59500 119 0 0.00000 119 119 1.00000 1 |
|
1267 | 1281 | $ cd .. |
|
1268 | 1282 | |
|
1269 | 1283 | $ cat << EOF >> $HGRCPATH |
|
1270 | 1284 | > [format] |
|
1271 | 1285 | > maxchainlen = 9001 |
|
1272 | 1286 | > EOF |
|
1273 | 1287 | |
|
1274 | 1288 | Check upgrading a sparse-revlog repository |
|
1275 | 1289 | --------------------------------------- |
|
1276 | 1290 | |
|
1277 | 1291 | $ hg init sparserevlogrepo --config format.sparse-revlog=no |
|
1278 | 1292 | $ cd sparserevlogrepo |
|
1279 | 1293 | $ touch foo |
|
1280 | 1294 | $ hg add foo |
|
1281 | 1295 | $ hg -q commit -m "foo" |
|
1282 | 1296 | $ cat .hg/requires |
|
1283 | 1297 | dotencode |
|
1284 | 1298 | fncache |
|
1285 | 1299 | generaldelta |
|
1286 | 1300 | persistent-nodemap (rust !) |
|
1287 | 1301 | revlogv1 |
|
1288 | 1302 | store |
|
1289 | 1303 | |
|
1290 | 1304 | Check that we can add the sparse-revlog format requirement |
|
1291 | 1305 | $ hg --config format.sparse-revlog=yes debugupgraderepo --run --quiet |
|
1292 | 1306 | upgrade will perform the following actions: |
|
1293 | 1307 | |
|
1294 | 1308 | requirements |
|
1295 | 1309 | preserved: dotencode, fncache, generaldelta, revlogv1, store (no-rust !) |
|
1296 | 1310 | preserved: dotencode, fncache, generaldelta, persistent-nodemap, revlogv1, store (rust !) |
|
1297 | 1311 | added: sparserevlog |
|
1298 | 1312 | |
|
1299 | 1313 | processed revlogs: |
|
1300 | 1314 | - all-filelogs |
|
1301 | 1315 | - changelog |
|
1302 | 1316 | - manifest |
|
1303 | 1317 | |
|
1304 | 1318 | $ cat .hg/requires |
|
1305 | 1319 | dotencode |
|
1306 | 1320 | fncache |
|
1307 | 1321 | generaldelta |
|
1308 | 1322 | persistent-nodemap (rust !) |
|
1309 | 1323 | revlogv1 |
|
1310 | 1324 | sparserevlog |
|
1311 | 1325 | store |
|
1312 | 1326 | |
|
1313 | 1327 | Check that we can remove the sparse-revlog format requirement |
|
1314 | 1328 | $ hg --config format.sparse-revlog=no debugupgraderepo --run --quiet |
|
1315 | 1329 | upgrade will perform the following actions: |
|
1316 | 1330 | |
|
1317 | 1331 | requirements |
|
1318 | 1332 | preserved: dotencode, fncache, generaldelta, revlogv1, store (no-rust !) |
|
1319 | 1333 | preserved: dotencode, fncache, generaldelta, persistent-nodemap, revlogv1, store (rust !) |
|
1320 | 1334 | removed: sparserevlog |
|
1321 | 1335 | |
|
1322 | 1336 | processed revlogs: |
|
1323 | 1337 | - all-filelogs |
|
1324 | 1338 | - changelog |
|
1325 | 1339 | - manifest |
|
1326 | 1340 | |
|
1327 | 1341 | $ cat .hg/requires |
|
1328 | 1342 | dotencode |
|
1329 | 1343 | fncache |
|
1330 | 1344 | generaldelta |
|
1331 | 1345 | persistent-nodemap (rust !) |
|
1332 | 1346 | revlogv1 |
|
1333 | 1347 | store |
|
1334 | 1348 | |
|
1335 | 1349 | #if zstd |
|
1336 | 1350 | |
|
1337 | 1351 | Check upgrading to a zstd revlog |
|
1338 | 1352 | -------------------------------- |
|
1339 | 1353 | |
|
1340 | 1354 | upgrade |
|
1341 | 1355 | |
|
1342 | 1356 | $ hg --config format.revlog-compression=zstd debugupgraderepo --run --no-backup --quiet |
|
1343 | 1357 | upgrade will perform the following actions: |
|
1344 | 1358 | |
|
1345 | 1359 | requirements |
|
1346 | 1360 | preserved: dotencode, fncache, generaldelta, revlogv1, store (no-rust !) |
|
1347 | 1361 | preserved: dotencode, fncache, generaldelta, persistent-nodemap, revlogv1, store (rust !) |
|
1348 | 1362 | added: revlog-compression-zstd, sparserevlog |
|
1349 | 1363 | |
|
1350 | 1364 | processed revlogs: |
|
1351 | 1365 | - all-filelogs |
|
1352 | 1366 | - changelog |
|
1353 | 1367 | - manifest |
|
1354 | 1368 | |
|
1355 | 1369 | $ hg debugformat -v |
|
1356 | 1370 | format-variant repo config default |
|
1357 | 1371 | fncache: yes yes yes |
|
1372 | dirstate-v2: no no no | |
|
1358 | 1373 | dotencode: yes yes yes |
|
1359 | 1374 | generaldelta: yes yes yes |
|
1360 | 1375 | share-safe: no no no |
|
1361 | 1376 | sparserevlog: yes yes yes |
|
1362 | 1377 | persistent-nodemap: no no no (no-rust !) |
|
1363 | 1378 | persistent-nodemap: yes yes no (rust !) |
|
1364 | 1379 | copies-sdc: no no no |
|
1365 | 1380 | revlog-v2: no no no |
|
1366 | 1381 | changelog-v2: no no no |
|
1367 | 1382 | plain-cl-delta: yes yes yes |
|
1368 | 1383 | compression: zlib zlib zlib (no-zstd !) |
|
1369 | 1384 | compression: zstd zlib zstd (zstd !) |
|
1370 | 1385 | compression-level: default default default |
|
1371 | 1386 | $ cat .hg/requires |
|
1372 | 1387 | dotencode |
|
1373 | 1388 | fncache |
|
1374 | 1389 | generaldelta |
|
1375 | 1390 | persistent-nodemap (rust !) |
|
1376 | 1391 | revlog-compression-zstd |
|
1377 | 1392 | revlogv1 |
|
1378 | 1393 | sparserevlog |
|
1379 | 1394 | store |
|
1380 | 1395 | |
|
1381 | 1396 | downgrade |
|
1382 | 1397 | |
|
1383 | 1398 | $ hg debugupgraderepo --run --no-backup --quiet |
|
1384 | 1399 | upgrade will perform the following actions: |
|
1385 | 1400 | |
|
1386 | 1401 | requirements |
|
1387 | 1402 | preserved: dotencode, fncache, generaldelta, revlogv1, sparserevlog, store (no-rust !) |
|
1388 | 1403 | preserved: dotencode, fncache, generaldelta, persistent-nodemap, revlogv1, sparserevlog, store (rust !) |
|
1389 | 1404 | removed: revlog-compression-zstd |
|
1390 | 1405 | |
|
1391 | 1406 | processed revlogs: |
|
1392 | 1407 | - all-filelogs |
|
1393 | 1408 | - changelog |
|
1394 | 1409 | - manifest |
|
1395 | 1410 | |
|
1396 | 1411 | $ hg debugformat -v |
|
1397 | 1412 | format-variant repo config default |
|
1398 | 1413 | fncache: yes yes yes |
|
1414 | dirstate-v2: no no no | |
|
1399 | 1415 | dotencode: yes yes yes |
|
1400 | 1416 | generaldelta: yes yes yes |
|
1401 | 1417 | share-safe: no no no |
|
1402 | 1418 | sparserevlog: yes yes yes |
|
1403 | 1419 | persistent-nodemap: no no no (no-rust !) |
|
1404 | 1420 | persistent-nodemap: yes yes no (rust !) |
|
1405 | 1421 | copies-sdc: no no no |
|
1406 | 1422 | revlog-v2: no no no |
|
1407 | 1423 | changelog-v2: no no no |
|
1408 | 1424 | plain-cl-delta: yes yes yes |
|
1409 | 1425 | compression: zlib zlib zlib (no-zstd !) |
|
1410 | 1426 | compression: zlib zlib zstd (zstd !) |
|
1411 | 1427 | compression-level: default default default |
|
1412 | 1428 | $ cat .hg/requires |
|
1413 | 1429 | dotencode |
|
1414 | 1430 | fncache |
|
1415 | 1431 | generaldelta |
|
1416 | 1432 | persistent-nodemap (rust !) |
|
1417 | 1433 | revlogv1 |
|
1418 | 1434 | sparserevlog |
|
1419 | 1435 | store |
|
1420 | 1436 | |
|
1421 | 1437 | upgrade from hgrc |
|
1422 | 1438 | |
|
1423 | 1439 | $ cat >> .hg/hgrc << EOF |
|
1424 | 1440 | > [format] |
|
1425 | 1441 | > revlog-compression=zstd |
|
1426 | 1442 | > EOF |
|
1427 | 1443 | $ hg debugupgraderepo --run --no-backup --quiet |
|
1428 | 1444 | upgrade will perform the following actions: |
|
1429 | 1445 | |
|
1430 | 1446 | requirements |
|
1431 | 1447 | preserved: dotencode, fncache, generaldelta, revlogv1, sparserevlog, store (no-rust !) |
|
1432 | 1448 | preserved: dotencode, fncache, generaldelta, persistent-nodemap, revlogv1, sparserevlog, store (rust !) |
|
1433 | 1449 | added: revlog-compression-zstd |
|
1434 | 1450 | |
|
1435 | 1451 | processed revlogs: |
|
1436 | 1452 | - all-filelogs |
|
1437 | 1453 | - changelog |
|
1438 | 1454 | - manifest |
|
1439 | 1455 | |
|
1440 | 1456 | $ hg debugformat -v |
|
1441 | 1457 | format-variant repo config default |
|
1442 | 1458 | fncache: yes yes yes |
|
1459 | dirstate-v2: no no no | |
|
1443 | 1460 | dotencode: yes yes yes |
|
1444 | 1461 | generaldelta: yes yes yes |
|
1445 | 1462 | share-safe: no no no |
|
1446 | 1463 | sparserevlog: yes yes yes |
|
1447 | 1464 | persistent-nodemap: no no no (no-rust !) |
|
1448 | 1465 | persistent-nodemap: yes yes no (rust !) |
|
1449 | 1466 | copies-sdc: no no no |
|
1450 | 1467 | revlog-v2: no no no |
|
1451 | 1468 | changelog-v2: no no no |
|
1452 | 1469 | plain-cl-delta: yes yes yes |
|
1453 | 1470 | compression: zlib zlib zlib (no-zstd !) |
|
1454 | 1471 | compression: zstd zstd zstd (zstd !) |
|
1455 | 1472 | compression-level: default default default |
|
1456 | 1473 | $ cat .hg/requires |
|
1457 | 1474 | dotencode |
|
1458 | 1475 | fncache |
|
1459 | 1476 | generaldelta |
|
1460 | 1477 | persistent-nodemap (rust !) |
|
1461 | 1478 | revlog-compression-zstd |
|
1462 | 1479 | revlogv1 |
|
1463 | 1480 | sparserevlog |
|
1464 | 1481 | store |
|
1465 | 1482 | |
|
1466 | 1483 | #endif |
|
1467 | 1484 | |
|
1468 | 1485 | Check upgrading to a revlog format supporting sidedata |
|
1469 | 1486 | ------------------------------------------------------ |
|
1470 | 1487 | |
|
1471 | 1488 | upgrade |
|
1472 | 1489 | |
|
1473 | 1490 | $ hg debugsidedata -c 0 |
|
1474 | 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 | 1492 | upgrade will perform the following actions: |
|
1476 | 1493 | |
|
1477 | 1494 | requirements |
|
1478 | 1495 | preserved: dotencode, fncache, generaldelta, store (no-zstd !) |
|
1479 | 1496 | preserved: dotencode, fncache, generaldelta, revlog-compression-zstd, sparserevlog, store (zstd no-rust !) |
|
1480 | 1497 | preserved: dotencode, fncache, generaldelta, persistent-nodemap, revlog-compression-zstd, sparserevlog, store (rust !) |
|
1481 | 1498 | removed: revlogv1 |
|
1482 | 1499 | added: exp-revlogv2.2 (zstd !) |
|
1483 | 1500 | added: exp-revlogv2.2, sparserevlog (no-zstd !) |
|
1484 | 1501 | |
|
1485 | 1502 | processed revlogs: |
|
1486 | 1503 | - all-filelogs |
|
1487 | 1504 | - changelog |
|
1488 | 1505 | - manifest |
|
1489 | 1506 | |
|
1490 | 1507 | $ hg debugformat -v |
|
1491 | 1508 | format-variant repo config default |
|
1492 | 1509 | fncache: yes yes yes |
|
1510 | dirstate-v2: no no no | |
|
1493 | 1511 | dotencode: yes yes yes |
|
1494 | 1512 | generaldelta: yes yes yes |
|
1495 | 1513 | share-safe: no no no |
|
1496 | 1514 | sparserevlog: yes yes yes |
|
1497 | 1515 | persistent-nodemap: no no no (no-rust !) |
|
1498 | 1516 | persistent-nodemap: yes yes no (rust !) |
|
1499 | 1517 | copies-sdc: no no no |
|
1500 | 1518 | revlog-v2: yes no no |
|
1501 | 1519 | changelog-v2: no no no |
|
1502 | 1520 | plain-cl-delta: yes yes yes |
|
1503 | 1521 | compression: zlib zlib zlib (no-zstd !) |
|
1504 | 1522 | compression: zstd zstd zstd (zstd !) |
|
1505 | 1523 | compression-level: default default default |
|
1506 | 1524 | $ cat .hg/requires |
|
1507 | 1525 | dotencode |
|
1508 | 1526 | exp-revlogv2.2 |
|
1509 | 1527 | fncache |
|
1510 | 1528 | generaldelta |
|
1511 | 1529 | persistent-nodemap (rust !) |
|
1512 | 1530 | revlog-compression-zstd (zstd !) |
|
1513 | 1531 | sparserevlog |
|
1514 | 1532 | store |
|
1515 | 1533 | $ hg debugsidedata -c 0 |
|
1516 | 1534 | 2 sidedata entries |
|
1517 | 1535 | entry-0001 size 4 |
|
1518 | 1536 | entry-0002 size 32 |
|
1519 | 1537 | |
|
1520 | 1538 | downgrade |
|
1521 | 1539 | |
|
1522 | 1540 | $ hg debugupgraderepo --config experimental.revlogv2=no --run --no-backup --quiet |
|
1523 | 1541 | upgrade will perform the following actions: |
|
1524 | 1542 | |
|
1525 | 1543 | requirements |
|
1526 | 1544 | preserved: dotencode, fncache, generaldelta, sparserevlog, store (no-zstd !) |
|
1527 | 1545 | preserved: dotencode, fncache, generaldelta, revlog-compression-zstd, sparserevlog, store (zstd no-rust !) |
|
1528 | 1546 | preserved: dotencode, fncache, generaldelta, persistent-nodemap, revlog-compression-zstd, sparserevlog, store (rust !) |
|
1529 | 1547 | removed: exp-revlogv2.2 |
|
1530 | 1548 | added: revlogv1 |
|
1531 | 1549 | |
|
1532 | 1550 | processed revlogs: |
|
1533 | 1551 | - all-filelogs |
|
1534 | 1552 | - changelog |
|
1535 | 1553 | - manifest |
|
1536 | 1554 | |
|
1537 | 1555 | $ hg debugformat -v |
|
1538 | 1556 | format-variant repo config default |
|
1539 | 1557 | fncache: yes yes yes |
|
1558 | dirstate-v2: no no no | |
|
1540 | 1559 | dotencode: yes yes yes |
|
1541 | 1560 | generaldelta: yes yes yes |
|
1542 | 1561 | share-safe: no no no |
|
1543 | 1562 | sparserevlog: yes yes yes |
|
1544 | 1563 | persistent-nodemap: no no no (no-rust !) |
|
1545 | 1564 | persistent-nodemap: yes yes no (rust !) |
|
1546 | 1565 | copies-sdc: no no no |
|
1547 | 1566 | revlog-v2: no no no |
|
1548 | 1567 | changelog-v2: no no no |
|
1549 | 1568 | plain-cl-delta: yes yes yes |
|
1550 | 1569 | compression: zlib zlib zlib (no-zstd !) |
|
1551 | 1570 | compression: zstd zstd zstd (zstd !) |
|
1552 | 1571 | compression-level: default default default |
|
1553 | 1572 | $ cat .hg/requires |
|
1554 | 1573 | dotencode |
|
1555 | 1574 | fncache |
|
1556 | 1575 | generaldelta |
|
1557 | 1576 | persistent-nodemap (rust !) |
|
1558 | 1577 | revlog-compression-zstd (zstd !) |
|
1559 | 1578 | revlogv1 |
|
1560 | 1579 | sparserevlog |
|
1561 | 1580 | store |
|
1562 | 1581 | $ hg debugsidedata -c 0 |
|
1563 | 1582 | |
|
1564 | 1583 | upgrade from hgrc |
|
1565 | 1584 | |
|
1566 | 1585 | $ cat >> .hg/hgrc << EOF |
|
1567 | 1586 | > [experimental] |
|
1568 | 1587 | > revlogv2=enable-unstable-format-and-corrupt-my-data |
|
1569 | 1588 | > EOF |
|
1570 | 1589 | $ hg debugupgraderepo --run --no-backup --quiet |
|
1571 | 1590 | upgrade will perform the following actions: |
|
1572 | 1591 | |
|
1573 | 1592 | requirements |
|
1574 | 1593 | preserved: dotencode, fncache, generaldelta, sparserevlog, store (no-zstd !) |
|
1575 | 1594 | preserved: dotencode, fncache, generaldelta, revlog-compression-zstd, sparserevlog, store (zstd no-rust !) |
|
1576 | 1595 | preserved: dotencode, fncache, generaldelta, persistent-nodemap, revlog-compression-zstd, sparserevlog, store (rust !) |
|
1577 | 1596 | removed: revlogv1 |
|
1578 | 1597 | added: exp-revlogv2.2 |
|
1579 | 1598 | |
|
1580 | 1599 | processed revlogs: |
|
1581 | 1600 | - all-filelogs |
|
1582 | 1601 | - changelog |
|
1583 | 1602 | - manifest |
|
1584 | 1603 | |
|
1585 | 1604 | $ hg debugformat -v |
|
1586 | 1605 | format-variant repo config default |
|
1587 | 1606 | fncache: yes yes yes |
|
1607 | dirstate-v2: no no no | |
|
1588 | 1608 | dotencode: yes yes yes |
|
1589 | 1609 | generaldelta: yes yes yes |
|
1590 | 1610 | share-safe: no no no |
|
1591 | 1611 | sparserevlog: yes yes yes |
|
1592 | 1612 | persistent-nodemap: no no no (no-rust !) |
|
1593 | 1613 | persistent-nodemap: yes yes no (rust !) |
|
1594 | 1614 | copies-sdc: no no no |
|
1595 | 1615 | revlog-v2: yes yes no |
|
1596 | 1616 | changelog-v2: no no no |
|
1597 | 1617 | plain-cl-delta: yes yes yes |
|
1598 | 1618 | compression: zlib zlib zlib (no-zstd !) |
|
1599 | 1619 | compression: zstd zstd zstd (zstd !) |
|
1600 | 1620 | compression-level: default default default |
|
1601 | 1621 | $ cat .hg/requires |
|
1602 | 1622 | dotencode |
|
1603 | 1623 | exp-revlogv2.2 |
|
1604 | 1624 | fncache |
|
1605 | 1625 | generaldelta |
|
1606 | 1626 | persistent-nodemap (rust !) |
|
1607 | 1627 | revlog-compression-zstd (zstd !) |
|
1608 | 1628 | sparserevlog |
|
1609 | 1629 | store |
|
1610 | 1630 | $ hg debugsidedata -c 0 |
|
1611 | 1631 | |
|
1612 | 1632 | Demonstrate that nothing to perform upgrade will still run all the way through |
|
1613 | 1633 | |
|
1614 | 1634 | $ hg debugupgraderepo --run |
|
1615 | 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