##// END OF EJS Templates
copies: add a config to limit the number of candidates to check in heuristics...
Pulkit Goyal -
r34847:f05a6e01 default
parent child Browse files
Show More
@@ -1,1100 +1,1103 b''
1 # configitems.py - centralized declaration of configuration option
1 # configitems.py - centralized declaration of configuration option
2 #
2 #
3 # Copyright 2017 Pierre-Yves David <pierre-yves.david@octobus.net>
3 # Copyright 2017 Pierre-Yves David <pierre-yves.david@octobus.net>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 from __future__ import absolute_import
8 from __future__ import absolute_import
9
9
10 import functools
10 import functools
11 import re
11 import re
12
12
13 from . import (
13 from . import (
14 encoding,
14 encoding,
15 error,
15 error,
16 )
16 )
17
17
18 def loadconfigtable(ui, extname, configtable):
18 def loadconfigtable(ui, extname, configtable):
19 """update config item known to the ui with the extension ones"""
19 """update config item known to the ui with the extension ones"""
20 for section, items in configtable.items():
20 for section, items in configtable.items():
21 knownitems = ui._knownconfig.setdefault(section, itemregister())
21 knownitems = ui._knownconfig.setdefault(section, itemregister())
22 knownkeys = set(knownitems)
22 knownkeys = set(knownitems)
23 newkeys = set(items)
23 newkeys = set(items)
24 for key in sorted(knownkeys & newkeys):
24 for key in sorted(knownkeys & newkeys):
25 msg = "extension '%s' overwrite config item '%s.%s'"
25 msg = "extension '%s' overwrite config item '%s.%s'"
26 msg %= (extname, section, key)
26 msg %= (extname, section, key)
27 ui.develwarn(msg, config='warn-config')
27 ui.develwarn(msg, config='warn-config')
28
28
29 knownitems.update(items)
29 knownitems.update(items)
30
30
31 class configitem(object):
31 class configitem(object):
32 """represent a known config item
32 """represent a known config item
33
33
34 :section: the official config section where to find this item,
34 :section: the official config section where to find this item,
35 :name: the official name within the section,
35 :name: the official name within the section,
36 :default: default value for this item,
36 :default: default value for this item,
37 :alias: optional list of tuples as alternatives,
37 :alias: optional list of tuples as alternatives,
38 :generic: this is a generic definition, match name using regular expression.
38 :generic: this is a generic definition, match name using regular expression.
39 """
39 """
40
40
41 def __init__(self, section, name, default=None, alias=(),
41 def __init__(self, section, name, default=None, alias=(),
42 generic=False, priority=0):
42 generic=False, priority=0):
43 self.section = section
43 self.section = section
44 self.name = name
44 self.name = name
45 self.default = default
45 self.default = default
46 self.alias = list(alias)
46 self.alias = list(alias)
47 self.generic = generic
47 self.generic = generic
48 self.priority = priority
48 self.priority = priority
49 self._re = None
49 self._re = None
50 if generic:
50 if generic:
51 self._re = re.compile(self.name)
51 self._re = re.compile(self.name)
52
52
53 class itemregister(dict):
53 class itemregister(dict):
54 """A specialized dictionary that can handle wild-card selection"""
54 """A specialized dictionary that can handle wild-card selection"""
55
55
56 def __init__(self):
56 def __init__(self):
57 super(itemregister, self).__init__()
57 super(itemregister, self).__init__()
58 self._generics = set()
58 self._generics = set()
59
59
60 def update(self, other):
60 def update(self, other):
61 super(itemregister, self).update(other)
61 super(itemregister, self).update(other)
62 self._generics.update(other._generics)
62 self._generics.update(other._generics)
63
63
64 def __setitem__(self, key, item):
64 def __setitem__(self, key, item):
65 super(itemregister, self).__setitem__(key, item)
65 super(itemregister, self).__setitem__(key, item)
66 if item.generic:
66 if item.generic:
67 self._generics.add(item)
67 self._generics.add(item)
68
68
69 def get(self, key):
69 def get(self, key):
70 if key in self:
70 if key in self:
71 return self[key]
71 return self[key]
72
72
73 # search for a matching generic item
73 # search for a matching generic item
74 generics = sorted(self._generics, key=(lambda x: (x.priority, x.name)))
74 generics = sorted(self._generics, key=(lambda x: (x.priority, x.name)))
75 for item in generics:
75 for item in generics:
76 if item._re.match(key):
76 if item._re.match(key):
77 return item
77 return item
78
78
79 # fallback to dict get
79 # fallback to dict get
80 return super(itemregister, self).get(key)
80 return super(itemregister, self).get(key)
81
81
82 coreitems = {}
82 coreitems = {}
83
83
84 def _register(configtable, *args, **kwargs):
84 def _register(configtable, *args, **kwargs):
85 item = configitem(*args, **kwargs)
85 item = configitem(*args, **kwargs)
86 section = configtable.setdefault(item.section, itemregister())
86 section = configtable.setdefault(item.section, itemregister())
87 if item.name in section:
87 if item.name in section:
88 msg = "duplicated config item registration for '%s.%s'"
88 msg = "duplicated config item registration for '%s.%s'"
89 raise error.ProgrammingError(msg % (item.section, item.name))
89 raise error.ProgrammingError(msg % (item.section, item.name))
90 section[item.name] = item
90 section[item.name] = item
91
91
92 # special value for case where the default is derived from other values
92 # special value for case where the default is derived from other values
93 dynamicdefault = object()
93 dynamicdefault = object()
94
94
95 # Registering actual config items
95 # Registering actual config items
96
96
97 def getitemregister(configtable):
97 def getitemregister(configtable):
98 return functools.partial(_register, configtable)
98 return functools.partial(_register, configtable)
99
99
100 coreconfigitem = getitemregister(coreitems)
100 coreconfigitem = getitemregister(coreitems)
101
101
102 coreconfigitem('alias', '.*',
102 coreconfigitem('alias', '.*',
103 default=None,
103 default=None,
104 generic=True,
104 generic=True,
105 )
105 )
106 coreconfigitem('annotate', 'nodates',
106 coreconfigitem('annotate', 'nodates',
107 default=False,
107 default=False,
108 )
108 )
109 coreconfigitem('annotate', 'showfunc',
109 coreconfigitem('annotate', 'showfunc',
110 default=False,
110 default=False,
111 )
111 )
112 coreconfigitem('annotate', 'unified',
112 coreconfigitem('annotate', 'unified',
113 default=None,
113 default=None,
114 )
114 )
115 coreconfigitem('annotate', 'git',
115 coreconfigitem('annotate', 'git',
116 default=False,
116 default=False,
117 )
117 )
118 coreconfigitem('annotate', 'ignorews',
118 coreconfigitem('annotate', 'ignorews',
119 default=False,
119 default=False,
120 )
120 )
121 coreconfigitem('annotate', 'ignorewsamount',
121 coreconfigitem('annotate', 'ignorewsamount',
122 default=False,
122 default=False,
123 )
123 )
124 coreconfigitem('annotate', 'ignoreblanklines',
124 coreconfigitem('annotate', 'ignoreblanklines',
125 default=False,
125 default=False,
126 )
126 )
127 coreconfigitem('annotate', 'ignorewseol',
127 coreconfigitem('annotate', 'ignorewseol',
128 default=False,
128 default=False,
129 )
129 )
130 coreconfigitem('annotate', 'nobinary',
130 coreconfigitem('annotate', 'nobinary',
131 default=False,
131 default=False,
132 )
132 )
133 coreconfigitem('annotate', 'noprefix',
133 coreconfigitem('annotate', 'noprefix',
134 default=False,
134 default=False,
135 )
135 )
136 coreconfigitem('auth', 'cookiefile',
136 coreconfigitem('auth', 'cookiefile',
137 default=None,
137 default=None,
138 )
138 )
139 # bookmarks.pushing: internal hack for discovery
139 # bookmarks.pushing: internal hack for discovery
140 coreconfigitem('bookmarks', 'pushing',
140 coreconfigitem('bookmarks', 'pushing',
141 default=list,
141 default=list,
142 )
142 )
143 # bundle.mainreporoot: internal hack for bundlerepo
143 # bundle.mainreporoot: internal hack for bundlerepo
144 coreconfigitem('bundle', 'mainreporoot',
144 coreconfigitem('bundle', 'mainreporoot',
145 default='',
145 default='',
146 )
146 )
147 # bundle.reorder: experimental config
147 # bundle.reorder: experimental config
148 coreconfigitem('bundle', 'reorder',
148 coreconfigitem('bundle', 'reorder',
149 default='auto',
149 default='auto',
150 )
150 )
151 coreconfigitem('censor', 'policy',
151 coreconfigitem('censor', 'policy',
152 default='abort',
152 default='abort',
153 )
153 )
154 coreconfigitem('chgserver', 'idletimeout',
154 coreconfigitem('chgserver', 'idletimeout',
155 default=3600,
155 default=3600,
156 )
156 )
157 coreconfigitem('chgserver', 'skiphash',
157 coreconfigitem('chgserver', 'skiphash',
158 default=False,
158 default=False,
159 )
159 )
160 coreconfigitem('cmdserver', 'log',
160 coreconfigitem('cmdserver', 'log',
161 default=None,
161 default=None,
162 )
162 )
163 coreconfigitem('color', '.*',
163 coreconfigitem('color', '.*',
164 default=None,
164 default=None,
165 generic=True,
165 generic=True,
166 )
166 )
167 coreconfigitem('color', 'mode',
167 coreconfigitem('color', 'mode',
168 default='auto',
168 default='auto',
169 )
169 )
170 coreconfigitem('color', 'pagermode',
170 coreconfigitem('color', 'pagermode',
171 default=dynamicdefault,
171 default=dynamicdefault,
172 )
172 )
173 coreconfigitem('commands', 'status.relative',
173 coreconfigitem('commands', 'status.relative',
174 default=False,
174 default=False,
175 )
175 )
176 coreconfigitem('commands', 'status.skipstates',
176 coreconfigitem('commands', 'status.skipstates',
177 default=[],
177 default=[],
178 )
178 )
179 coreconfigitem('commands', 'status.verbose',
179 coreconfigitem('commands', 'status.verbose',
180 default=False,
180 default=False,
181 )
181 )
182 coreconfigitem('commands', 'update.check',
182 coreconfigitem('commands', 'update.check',
183 default=None,
183 default=None,
184 # Deprecated, remove after 4.4 release
184 # Deprecated, remove after 4.4 release
185 alias=[('experimental', 'updatecheck')]
185 alias=[('experimental', 'updatecheck')]
186 )
186 )
187 coreconfigitem('commands', 'update.requiredest',
187 coreconfigitem('commands', 'update.requiredest',
188 default=False,
188 default=False,
189 )
189 )
190 coreconfigitem('committemplate', '.*',
190 coreconfigitem('committemplate', '.*',
191 default=None,
191 default=None,
192 generic=True,
192 generic=True,
193 )
193 )
194 coreconfigitem('debug', 'dirstate.delaywrite',
194 coreconfigitem('debug', 'dirstate.delaywrite',
195 default=0,
195 default=0,
196 )
196 )
197 coreconfigitem('defaults', '.*',
197 coreconfigitem('defaults', '.*',
198 default=None,
198 default=None,
199 generic=True,
199 generic=True,
200 )
200 )
201 coreconfigitem('devel', 'all-warnings',
201 coreconfigitem('devel', 'all-warnings',
202 default=False,
202 default=False,
203 )
203 )
204 coreconfigitem('devel', 'bundle2.debug',
204 coreconfigitem('devel', 'bundle2.debug',
205 default=False,
205 default=False,
206 )
206 )
207 coreconfigitem('devel', 'cache-vfs',
207 coreconfigitem('devel', 'cache-vfs',
208 default=None,
208 default=None,
209 )
209 )
210 coreconfigitem('devel', 'check-locks',
210 coreconfigitem('devel', 'check-locks',
211 default=False,
211 default=False,
212 )
212 )
213 coreconfigitem('devel', 'check-relroot',
213 coreconfigitem('devel', 'check-relroot',
214 default=False,
214 default=False,
215 )
215 )
216 coreconfigitem('devel', 'default-date',
216 coreconfigitem('devel', 'default-date',
217 default=None,
217 default=None,
218 )
218 )
219 coreconfigitem('devel', 'deprec-warn',
219 coreconfigitem('devel', 'deprec-warn',
220 default=False,
220 default=False,
221 )
221 )
222 coreconfigitem('devel', 'disableloaddefaultcerts',
222 coreconfigitem('devel', 'disableloaddefaultcerts',
223 default=False,
223 default=False,
224 )
224 )
225 coreconfigitem('devel', 'warn-empty-changegroup',
225 coreconfigitem('devel', 'warn-empty-changegroup',
226 default=False,
226 default=False,
227 )
227 )
228 coreconfigitem('devel', 'legacy.exchange',
228 coreconfigitem('devel', 'legacy.exchange',
229 default=list,
229 default=list,
230 )
230 )
231 coreconfigitem('devel', 'servercafile',
231 coreconfigitem('devel', 'servercafile',
232 default='',
232 default='',
233 )
233 )
234 coreconfigitem('devel', 'serverexactprotocol',
234 coreconfigitem('devel', 'serverexactprotocol',
235 default='',
235 default='',
236 )
236 )
237 coreconfigitem('devel', 'serverrequirecert',
237 coreconfigitem('devel', 'serverrequirecert',
238 default=False,
238 default=False,
239 )
239 )
240 coreconfigitem('devel', 'strip-obsmarkers',
240 coreconfigitem('devel', 'strip-obsmarkers',
241 default=True,
241 default=True,
242 )
242 )
243 coreconfigitem('devel', 'warn-config',
243 coreconfigitem('devel', 'warn-config',
244 default=None,
244 default=None,
245 )
245 )
246 coreconfigitem('devel', 'warn-config-default',
246 coreconfigitem('devel', 'warn-config-default',
247 default=None,
247 default=None,
248 )
248 )
249 coreconfigitem('devel', 'user.obsmarker',
249 coreconfigitem('devel', 'user.obsmarker',
250 default=None,
250 default=None,
251 )
251 )
252 coreconfigitem('diff', 'nodates',
252 coreconfigitem('diff', 'nodates',
253 default=False,
253 default=False,
254 )
254 )
255 coreconfigitem('diff', 'showfunc',
255 coreconfigitem('diff', 'showfunc',
256 default=False,
256 default=False,
257 )
257 )
258 coreconfigitem('diff', 'unified',
258 coreconfigitem('diff', 'unified',
259 default=None,
259 default=None,
260 )
260 )
261 coreconfigitem('diff', 'git',
261 coreconfigitem('diff', 'git',
262 default=False,
262 default=False,
263 )
263 )
264 coreconfigitem('diff', 'ignorews',
264 coreconfigitem('diff', 'ignorews',
265 default=False,
265 default=False,
266 )
266 )
267 coreconfigitem('diff', 'ignorewsamount',
267 coreconfigitem('diff', 'ignorewsamount',
268 default=False,
268 default=False,
269 )
269 )
270 coreconfigitem('diff', 'ignoreblanklines',
270 coreconfigitem('diff', 'ignoreblanklines',
271 default=False,
271 default=False,
272 )
272 )
273 coreconfigitem('diff', 'ignorewseol',
273 coreconfigitem('diff', 'ignorewseol',
274 default=False,
274 default=False,
275 )
275 )
276 coreconfigitem('diff', 'nobinary',
276 coreconfigitem('diff', 'nobinary',
277 default=False,
277 default=False,
278 )
278 )
279 coreconfigitem('diff', 'noprefix',
279 coreconfigitem('diff', 'noprefix',
280 default=False,
280 default=False,
281 )
281 )
282 coreconfigitem('email', 'bcc',
282 coreconfigitem('email', 'bcc',
283 default=None,
283 default=None,
284 )
284 )
285 coreconfigitem('email', 'cc',
285 coreconfigitem('email', 'cc',
286 default=None,
286 default=None,
287 )
287 )
288 coreconfigitem('email', 'charsets',
288 coreconfigitem('email', 'charsets',
289 default=list,
289 default=list,
290 )
290 )
291 coreconfigitem('email', 'from',
291 coreconfigitem('email', 'from',
292 default=None,
292 default=None,
293 )
293 )
294 coreconfigitem('email', 'method',
294 coreconfigitem('email', 'method',
295 default='smtp',
295 default='smtp',
296 )
296 )
297 coreconfigitem('email', 'reply-to',
297 coreconfigitem('email', 'reply-to',
298 default=None,
298 default=None,
299 )
299 )
300 coreconfigitem('experimental', 'allowdivergence',
300 coreconfigitem('experimental', 'allowdivergence',
301 default=False,
301 default=False,
302 )
302 )
303 coreconfigitem('experimental', 'archivemetatemplate',
303 coreconfigitem('experimental', 'archivemetatemplate',
304 default=dynamicdefault,
304 default=dynamicdefault,
305 )
305 )
306 coreconfigitem('experimental', 'bundle-phases',
306 coreconfigitem('experimental', 'bundle-phases',
307 default=False,
307 default=False,
308 )
308 )
309 coreconfigitem('experimental', 'bundle2-advertise',
309 coreconfigitem('experimental', 'bundle2-advertise',
310 default=True,
310 default=True,
311 )
311 )
312 coreconfigitem('experimental', 'bundle2-output-capture',
312 coreconfigitem('experimental', 'bundle2-output-capture',
313 default=False,
313 default=False,
314 )
314 )
315 coreconfigitem('experimental', 'bundle2.pushback',
315 coreconfigitem('experimental', 'bundle2.pushback',
316 default=False,
316 default=False,
317 )
317 )
318 coreconfigitem('experimental', 'bundle2lazylocking',
318 coreconfigitem('experimental', 'bundle2lazylocking',
319 default=False,
319 default=False,
320 )
320 )
321 coreconfigitem('experimental', 'bundlecomplevel',
321 coreconfigitem('experimental', 'bundlecomplevel',
322 default=None,
322 default=None,
323 )
323 )
324 coreconfigitem('experimental', 'changegroup3',
324 coreconfigitem('experimental', 'changegroup3',
325 default=False,
325 default=False,
326 )
326 )
327 coreconfigitem('experimental', 'clientcompressionengines',
327 coreconfigitem('experimental', 'clientcompressionengines',
328 default=list,
328 default=list,
329 )
329 )
330 coreconfigitem('experimental', 'copytrace',
330 coreconfigitem('experimental', 'copytrace',
331 default='on',
331 default='on',
332 )
332 )
333 coreconfigitem('experimental', 'copytrace.movecandidateslimit',
334 default=100,
335 )
333 coreconfigitem('experimental', 'copytrace.sourcecommitlimit',
336 coreconfigitem('experimental', 'copytrace.sourcecommitlimit',
334 default=100,
337 default=100,
335 )
338 )
336 coreconfigitem('experimental', 'crecordtest',
339 coreconfigitem('experimental', 'crecordtest',
337 default=None,
340 default=None,
338 )
341 )
339 coreconfigitem('experimental', 'editortmpinhg',
342 coreconfigitem('experimental', 'editortmpinhg',
340 default=False,
343 default=False,
341 )
344 )
342 coreconfigitem('experimental', 'maxdeltachainspan',
345 coreconfigitem('experimental', 'maxdeltachainspan',
343 default=-1,
346 default=-1,
344 )
347 )
345 coreconfigitem('experimental', 'mmapindexthreshold',
348 coreconfigitem('experimental', 'mmapindexthreshold',
346 default=None,
349 default=None,
347 )
350 )
348 coreconfigitem('experimental', 'nonnormalparanoidcheck',
351 coreconfigitem('experimental', 'nonnormalparanoidcheck',
349 default=False,
352 default=False,
350 )
353 )
351 coreconfigitem('experimental', 'effect-flags',
354 coreconfigitem('experimental', 'effect-flags',
352 default=False,
355 default=False,
353 )
356 )
354 coreconfigitem('experimental', 'stabilization',
357 coreconfigitem('experimental', 'stabilization',
355 default=list,
358 default=list,
356 alias=[('experimental', 'evolution')],
359 alias=[('experimental', 'evolution')],
357 )
360 )
358 coreconfigitem('experimental', 'stabilization.bundle-obsmarker',
361 coreconfigitem('experimental', 'stabilization.bundle-obsmarker',
359 default=False,
362 default=False,
360 alias=[('experimental', 'evolution.bundle-obsmarker')],
363 alias=[('experimental', 'evolution.bundle-obsmarker')],
361 )
364 )
362 coreconfigitem('experimental', 'stabilization.track-operation',
365 coreconfigitem('experimental', 'stabilization.track-operation',
363 default=True,
366 default=True,
364 alias=[('experimental', 'evolution.track-operation')]
367 alias=[('experimental', 'evolution.track-operation')]
365 )
368 )
366 coreconfigitem('experimental', 'exportableenviron',
369 coreconfigitem('experimental', 'exportableenviron',
367 default=list,
370 default=list,
368 )
371 )
369 coreconfigitem('experimental', 'extendedheader.index',
372 coreconfigitem('experimental', 'extendedheader.index',
370 default=None,
373 default=None,
371 )
374 )
372 coreconfigitem('experimental', 'extendedheader.similarity',
375 coreconfigitem('experimental', 'extendedheader.similarity',
373 default=False,
376 default=False,
374 )
377 )
375 coreconfigitem('experimental', 'format.compression',
378 coreconfigitem('experimental', 'format.compression',
376 default='zlib',
379 default='zlib',
377 )
380 )
378 coreconfigitem('experimental', 'graphshorten',
381 coreconfigitem('experimental', 'graphshorten',
379 default=False,
382 default=False,
380 )
383 )
381 coreconfigitem('experimental', 'graphstyle.parent',
384 coreconfigitem('experimental', 'graphstyle.parent',
382 default=dynamicdefault,
385 default=dynamicdefault,
383 )
386 )
384 coreconfigitem('experimental', 'graphstyle.missing',
387 coreconfigitem('experimental', 'graphstyle.missing',
385 default=dynamicdefault,
388 default=dynamicdefault,
386 )
389 )
387 coreconfigitem('experimental', 'graphstyle.grandparent',
390 coreconfigitem('experimental', 'graphstyle.grandparent',
388 default=dynamicdefault,
391 default=dynamicdefault,
389 )
392 )
390 coreconfigitem('experimental', 'hook-track-tags',
393 coreconfigitem('experimental', 'hook-track-tags',
391 default=False,
394 default=False,
392 )
395 )
393 coreconfigitem('experimental', 'httppostargs',
396 coreconfigitem('experimental', 'httppostargs',
394 default=False,
397 default=False,
395 )
398 )
396 coreconfigitem('experimental', 'manifestv2',
399 coreconfigitem('experimental', 'manifestv2',
397 default=False,
400 default=False,
398 )
401 )
399 coreconfigitem('experimental', 'mergedriver',
402 coreconfigitem('experimental', 'mergedriver',
400 default=None,
403 default=None,
401 )
404 )
402 coreconfigitem('experimental', 'obsmarkers-exchange-debug',
405 coreconfigitem('experimental', 'obsmarkers-exchange-debug',
403 default=False,
406 default=False,
404 )
407 )
405 coreconfigitem('experimental', 'rebase.multidest',
408 coreconfigitem('experimental', 'rebase.multidest',
406 default=False,
409 default=False,
407 )
410 )
408 coreconfigitem('experimental', 'revertalternateinteractivemode',
411 coreconfigitem('experimental', 'revertalternateinteractivemode',
409 default=True,
412 default=True,
410 )
413 )
411 coreconfigitem('experimental', 'revlogv2',
414 coreconfigitem('experimental', 'revlogv2',
412 default=None,
415 default=None,
413 )
416 )
414 coreconfigitem('experimental', 'spacemovesdown',
417 coreconfigitem('experimental', 'spacemovesdown',
415 default=False,
418 default=False,
416 )
419 )
417 coreconfigitem('experimental', 'sparse-read',
420 coreconfigitem('experimental', 'sparse-read',
418 default=False,
421 default=False,
419 )
422 )
420 coreconfigitem('experimental', 'sparse-read.density-threshold',
423 coreconfigitem('experimental', 'sparse-read.density-threshold',
421 default=0.25,
424 default=0.25,
422 )
425 )
423 coreconfigitem('experimental', 'sparse-read.min-block-size',
426 coreconfigitem('experimental', 'sparse-read.min-block-size',
424 default='256K',
427 default='256K',
425 )
428 )
426 coreconfigitem('experimental', 'treemanifest',
429 coreconfigitem('experimental', 'treemanifest',
427 default=False,
430 default=False,
428 )
431 )
429 coreconfigitem('extensions', '.*',
432 coreconfigitem('extensions', '.*',
430 default=None,
433 default=None,
431 generic=True,
434 generic=True,
432 )
435 )
433 coreconfigitem('extdata', '.*',
436 coreconfigitem('extdata', '.*',
434 default=None,
437 default=None,
435 generic=True,
438 generic=True,
436 )
439 )
437 coreconfigitem('format', 'aggressivemergedeltas',
440 coreconfigitem('format', 'aggressivemergedeltas',
438 default=False,
441 default=False,
439 )
442 )
440 coreconfigitem('format', 'chunkcachesize',
443 coreconfigitem('format', 'chunkcachesize',
441 default=None,
444 default=None,
442 )
445 )
443 coreconfigitem('format', 'dotencode',
446 coreconfigitem('format', 'dotencode',
444 default=True,
447 default=True,
445 )
448 )
446 coreconfigitem('format', 'generaldelta',
449 coreconfigitem('format', 'generaldelta',
447 default=False,
450 default=False,
448 )
451 )
449 coreconfigitem('format', 'manifestcachesize',
452 coreconfigitem('format', 'manifestcachesize',
450 default=None,
453 default=None,
451 )
454 )
452 coreconfigitem('format', 'maxchainlen',
455 coreconfigitem('format', 'maxchainlen',
453 default=None,
456 default=None,
454 )
457 )
455 coreconfigitem('format', 'obsstore-version',
458 coreconfigitem('format', 'obsstore-version',
456 default=None,
459 default=None,
457 )
460 )
458 coreconfigitem('format', 'usefncache',
461 coreconfigitem('format', 'usefncache',
459 default=True,
462 default=True,
460 )
463 )
461 coreconfigitem('format', 'usegeneraldelta',
464 coreconfigitem('format', 'usegeneraldelta',
462 default=True,
465 default=True,
463 )
466 )
464 coreconfigitem('format', 'usestore',
467 coreconfigitem('format', 'usestore',
465 default=True,
468 default=True,
466 )
469 )
467 coreconfigitem('hooks', '.*',
470 coreconfigitem('hooks', '.*',
468 default=dynamicdefault,
471 default=dynamicdefault,
469 generic=True,
472 generic=True,
470 )
473 )
471 coreconfigitem('hgweb-paths', '.*',
474 coreconfigitem('hgweb-paths', '.*',
472 default=list,
475 default=list,
473 generic=True,
476 generic=True,
474 )
477 )
475 coreconfigitem('hostfingerprints', '.*',
478 coreconfigitem('hostfingerprints', '.*',
476 default=list,
479 default=list,
477 generic=True,
480 generic=True,
478 )
481 )
479 coreconfigitem('hostsecurity', 'ciphers',
482 coreconfigitem('hostsecurity', 'ciphers',
480 default=None,
483 default=None,
481 )
484 )
482 coreconfigitem('hostsecurity', 'disabletls10warning',
485 coreconfigitem('hostsecurity', 'disabletls10warning',
483 default=False,
486 default=False,
484 )
487 )
485 coreconfigitem('hostsecurity', 'minimumprotocol',
488 coreconfigitem('hostsecurity', 'minimumprotocol',
486 default=dynamicdefault,
489 default=dynamicdefault,
487 )
490 )
488 coreconfigitem('hostsecurity', '.*:minimumprotocol$',
491 coreconfigitem('hostsecurity', '.*:minimumprotocol$',
489 default=dynamicdefault,
492 default=dynamicdefault,
490 generic=True,
493 generic=True,
491 )
494 )
492 coreconfigitem('hostsecurity', '.*:ciphers$',
495 coreconfigitem('hostsecurity', '.*:ciphers$',
493 default=dynamicdefault,
496 default=dynamicdefault,
494 generic=True,
497 generic=True,
495 )
498 )
496 coreconfigitem('hostsecurity', '.*:fingerprints$',
499 coreconfigitem('hostsecurity', '.*:fingerprints$',
497 default=list,
500 default=list,
498 generic=True,
501 generic=True,
499 )
502 )
500 coreconfigitem('hostsecurity', '.*:verifycertsfile$',
503 coreconfigitem('hostsecurity', '.*:verifycertsfile$',
501 default=None,
504 default=None,
502 generic=True,
505 generic=True,
503 )
506 )
504
507
505 coreconfigitem('http_proxy', 'always',
508 coreconfigitem('http_proxy', 'always',
506 default=False,
509 default=False,
507 )
510 )
508 coreconfigitem('http_proxy', 'host',
511 coreconfigitem('http_proxy', 'host',
509 default=None,
512 default=None,
510 )
513 )
511 coreconfigitem('http_proxy', 'no',
514 coreconfigitem('http_proxy', 'no',
512 default=list,
515 default=list,
513 )
516 )
514 coreconfigitem('http_proxy', 'passwd',
517 coreconfigitem('http_proxy', 'passwd',
515 default=None,
518 default=None,
516 )
519 )
517 coreconfigitem('http_proxy', 'user',
520 coreconfigitem('http_proxy', 'user',
518 default=None,
521 default=None,
519 )
522 )
520 coreconfigitem('logtoprocess', 'commandexception',
523 coreconfigitem('logtoprocess', 'commandexception',
521 default=None,
524 default=None,
522 )
525 )
523 coreconfigitem('logtoprocess', 'commandfinish',
526 coreconfigitem('logtoprocess', 'commandfinish',
524 default=None,
527 default=None,
525 )
528 )
526 coreconfigitem('logtoprocess', 'command',
529 coreconfigitem('logtoprocess', 'command',
527 default=None,
530 default=None,
528 )
531 )
529 coreconfigitem('logtoprocess', 'develwarn',
532 coreconfigitem('logtoprocess', 'develwarn',
530 default=None,
533 default=None,
531 )
534 )
532 coreconfigitem('logtoprocess', 'uiblocked',
535 coreconfigitem('logtoprocess', 'uiblocked',
533 default=None,
536 default=None,
534 )
537 )
535 coreconfigitem('merge', 'checkunknown',
538 coreconfigitem('merge', 'checkunknown',
536 default='abort',
539 default='abort',
537 )
540 )
538 coreconfigitem('merge', 'checkignored',
541 coreconfigitem('merge', 'checkignored',
539 default='abort',
542 default='abort',
540 )
543 )
541 coreconfigitem('merge', 'followcopies',
544 coreconfigitem('merge', 'followcopies',
542 default=True,
545 default=True,
543 )
546 )
544 coreconfigitem('merge', 'on-failure',
547 coreconfigitem('merge', 'on-failure',
545 default='continue',
548 default='continue',
546 )
549 )
547 coreconfigitem('merge', 'preferancestor',
550 coreconfigitem('merge', 'preferancestor',
548 default=lambda: ['*'],
551 default=lambda: ['*'],
549 )
552 )
550 coreconfigitem('merge-tools', '.*',
553 coreconfigitem('merge-tools', '.*',
551 default=None,
554 default=None,
552 generic=True,
555 generic=True,
553 )
556 )
554 coreconfigitem('merge-tools', r'.*\.args$',
557 coreconfigitem('merge-tools', r'.*\.args$',
555 default="$local $base $other",
558 default="$local $base $other",
556 generic=True,
559 generic=True,
557 priority=-1,
560 priority=-1,
558 )
561 )
559 coreconfigitem('merge-tools', r'.*\.binary$',
562 coreconfigitem('merge-tools', r'.*\.binary$',
560 default=False,
563 default=False,
561 generic=True,
564 generic=True,
562 priority=-1,
565 priority=-1,
563 )
566 )
564 coreconfigitem('merge-tools', r'.*\.check$',
567 coreconfigitem('merge-tools', r'.*\.check$',
565 default=list,
568 default=list,
566 generic=True,
569 generic=True,
567 priority=-1,
570 priority=-1,
568 )
571 )
569 coreconfigitem('merge-tools', r'.*\.checkchanged$',
572 coreconfigitem('merge-tools', r'.*\.checkchanged$',
570 default=False,
573 default=False,
571 generic=True,
574 generic=True,
572 priority=-1,
575 priority=-1,
573 )
576 )
574 coreconfigitem('merge-tools', r'.*\.executable$',
577 coreconfigitem('merge-tools', r'.*\.executable$',
575 default=dynamicdefault,
578 default=dynamicdefault,
576 generic=True,
579 generic=True,
577 priority=-1,
580 priority=-1,
578 )
581 )
579 coreconfigitem('merge-tools', r'.*\.fixeol$',
582 coreconfigitem('merge-tools', r'.*\.fixeol$',
580 default=False,
583 default=False,
581 generic=True,
584 generic=True,
582 priority=-1,
585 priority=-1,
583 )
586 )
584 coreconfigitem('merge-tools', r'.*\.gui$',
587 coreconfigitem('merge-tools', r'.*\.gui$',
585 default=False,
588 default=False,
586 generic=True,
589 generic=True,
587 priority=-1,
590 priority=-1,
588 )
591 )
589 coreconfigitem('merge-tools', r'.*\.priority$',
592 coreconfigitem('merge-tools', r'.*\.priority$',
590 default=0,
593 default=0,
591 generic=True,
594 generic=True,
592 priority=-1,
595 priority=-1,
593 )
596 )
594 coreconfigitem('merge-tools', r'.*\.premerge$',
597 coreconfigitem('merge-tools', r'.*\.premerge$',
595 default=dynamicdefault,
598 default=dynamicdefault,
596 generic=True,
599 generic=True,
597 priority=-1,
600 priority=-1,
598 )
601 )
599 coreconfigitem('merge-tools', r'.*\.symlink$',
602 coreconfigitem('merge-tools', r'.*\.symlink$',
600 default=False,
603 default=False,
601 generic=True,
604 generic=True,
602 priority=-1,
605 priority=-1,
603 )
606 )
604 coreconfigitem('pager', 'attend-.*',
607 coreconfigitem('pager', 'attend-.*',
605 default=dynamicdefault,
608 default=dynamicdefault,
606 generic=True,
609 generic=True,
607 )
610 )
608 coreconfigitem('pager', 'ignore',
611 coreconfigitem('pager', 'ignore',
609 default=list,
612 default=list,
610 )
613 )
611 coreconfigitem('pager', 'pager',
614 coreconfigitem('pager', 'pager',
612 default=dynamicdefault,
615 default=dynamicdefault,
613 )
616 )
614 coreconfigitem('patch', 'eol',
617 coreconfigitem('patch', 'eol',
615 default='strict',
618 default='strict',
616 )
619 )
617 coreconfigitem('patch', 'fuzz',
620 coreconfigitem('patch', 'fuzz',
618 default=2,
621 default=2,
619 )
622 )
620 coreconfigitem('paths', 'default',
623 coreconfigitem('paths', 'default',
621 default=None,
624 default=None,
622 )
625 )
623 coreconfigitem('paths', 'default-push',
626 coreconfigitem('paths', 'default-push',
624 default=None,
627 default=None,
625 )
628 )
626 coreconfigitem('paths', '.*',
629 coreconfigitem('paths', '.*',
627 default=None,
630 default=None,
628 generic=True,
631 generic=True,
629 )
632 )
630 coreconfigitem('phases', 'checksubrepos',
633 coreconfigitem('phases', 'checksubrepos',
631 default='follow',
634 default='follow',
632 )
635 )
633 coreconfigitem('phases', 'new-commit',
636 coreconfigitem('phases', 'new-commit',
634 default='draft',
637 default='draft',
635 )
638 )
636 coreconfigitem('phases', 'publish',
639 coreconfigitem('phases', 'publish',
637 default=True,
640 default=True,
638 )
641 )
639 coreconfigitem('profiling', 'enabled',
642 coreconfigitem('profiling', 'enabled',
640 default=False,
643 default=False,
641 )
644 )
642 coreconfigitem('profiling', 'format',
645 coreconfigitem('profiling', 'format',
643 default='text',
646 default='text',
644 )
647 )
645 coreconfigitem('profiling', 'freq',
648 coreconfigitem('profiling', 'freq',
646 default=1000,
649 default=1000,
647 )
650 )
648 coreconfigitem('profiling', 'limit',
651 coreconfigitem('profiling', 'limit',
649 default=30,
652 default=30,
650 )
653 )
651 coreconfigitem('profiling', 'nested',
654 coreconfigitem('profiling', 'nested',
652 default=0,
655 default=0,
653 )
656 )
654 coreconfigitem('profiling', 'output',
657 coreconfigitem('profiling', 'output',
655 default=None,
658 default=None,
656 )
659 )
657 coreconfigitem('profiling', 'showmax',
660 coreconfigitem('profiling', 'showmax',
658 default=0.999,
661 default=0.999,
659 )
662 )
660 coreconfigitem('profiling', 'showmin',
663 coreconfigitem('profiling', 'showmin',
661 default=dynamicdefault,
664 default=dynamicdefault,
662 )
665 )
663 coreconfigitem('profiling', 'sort',
666 coreconfigitem('profiling', 'sort',
664 default='inlinetime',
667 default='inlinetime',
665 )
668 )
666 coreconfigitem('profiling', 'statformat',
669 coreconfigitem('profiling', 'statformat',
667 default='hotpath',
670 default='hotpath',
668 )
671 )
669 coreconfigitem('profiling', 'type',
672 coreconfigitem('profiling', 'type',
670 default='stat',
673 default='stat',
671 )
674 )
672 coreconfigitem('progress', 'assume-tty',
675 coreconfigitem('progress', 'assume-tty',
673 default=False,
676 default=False,
674 )
677 )
675 coreconfigitem('progress', 'changedelay',
678 coreconfigitem('progress', 'changedelay',
676 default=1,
679 default=1,
677 )
680 )
678 coreconfigitem('progress', 'clear-complete',
681 coreconfigitem('progress', 'clear-complete',
679 default=True,
682 default=True,
680 )
683 )
681 coreconfigitem('progress', 'debug',
684 coreconfigitem('progress', 'debug',
682 default=False,
685 default=False,
683 )
686 )
684 coreconfigitem('progress', 'delay',
687 coreconfigitem('progress', 'delay',
685 default=3,
688 default=3,
686 )
689 )
687 coreconfigitem('progress', 'disable',
690 coreconfigitem('progress', 'disable',
688 default=False,
691 default=False,
689 )
692 )
690 coreconfigitem('progress', 'estimateinterval',
693 coreconfigitem('progress', 'estimateinterval',
691 default=60.0,
694 default=60.0,
692 )
695 )
693 coreconfigitem('progress', 'format',
696 coreconfigitem('progress', 'format',
694 default=lambda: ['topic', 'bar', 'number', 'estimate'],
697 default=lambda: ['topic', 'bar', 'number', 'estimate'],
695 )
698 )
696 coreconfigitem('progress', 'refresh',
699 coreconfigitem('progress', 'refresh',
697 default=0.1,
700 default=0.1,
698 )
701 )
699 coreconfigitem('progress', 'width',
702 coreconfigitem('progress', 'width',
700 default=dynamicdefault,
703 default=dynamicdefault,
701 )
704 )
702 coreconfigitem('push', 'pushvars.server',
705 coreconfigitem('push', 'pushvars.server',
703 default=False,
706 default=False,
704 )
707 )
705 coreconfigitem('server', 'bundle1',
708 coreconfigitem('server', 'bundle1',
706 default=True,
709 default=True,
707 )
710 )
708 coreconfigitem('server', 'bundle1gd',
711 coreconfigitem('server', 'bundle1gd',
709 default=None,
712 default=None,
710 )
713 )
711 coreconfigitem('server', 'bundle1.pull',
714 coreconfigitem('server', 'bundle1.pull',
712 default=None,
715 default=None,
713 )
716 )
714 coreconfigitem('server', 'bundle1gd.pull',
717 coreconfigitem('server', 'bundle1gd.pull',
715 default=None,
718 default=None,
716 )
719 )
717 coreconfigitem('server', 'bundle1.push',
720 coreconfigitem('server', 'bundle1.push',
718 default=None,
721 default=None,
719 )
722 )
720 coreconfigitem('server', 'bundle1gd.push',
723 coreconfigitem('server', 'bundle1gd.push',
721 default=None,
724 default=None,
722 )
725 )
723 coreconfigitem('server', 'compressionengines',
726 coreconfigitem('server', 'compressionengines',
724 default=list,
727 default=list,
725 )
728 )
726 coreconfigitem('server', 'concurrent-push-mode',
729 coreconfigitem('server', 'concurrent-push-mode',
727 default='strict',
730 default='strict',
728 )
731 )
729 coreconfigitem('server', 'disablefullbundle',
732 coreconfigitem('server', 'disablefullbundle',
730 default=False,
733 default=False,
731 )
734 )
732 coreconfigitem('server', 'maxhttpheaderlen',
735 coreconfigitem('server', 'maxhttpheaderlen',
733 default=1024,
736 default=1024,
734 )
737 )
735 coreconfigitem('server', 'preferuncompressed',
738 coreconfigitem('server', 'preferuncompressed',
736 default=False,
739 default=False,
737 )
740 )
738 coreconfigitem('server', 'uncompressed',
741 coreconfigitem('server', 'uncompressed',
739 default=True,
742 default=True,
740 )
743 )
741 coreconfigitem('server', 'uncompressedallowsecret',
744 coreconfigitem('server', 'uncompressedallowsecret',
742 default=False,
745 default=False,
743 )
746 )
744 coreconfigitem('server', 'validate',
747 coreconfigitem('server', 'validate',
745 default=False,
748 default=False,
746 )
749 )
747 coreconfigitem('server', 'zliblevel',
750 coreconfigitem('server', 'zliblevel',
748 default=-1,
751 default=-1,
749 )
752 )
750 coreconfigitem('smtp', 'host',
753 coreconfigitem('smtp', 'host',
751 default=None,
754 default=None,
752 )
755 )
753 coreconfigitem('smtp', 'local_hostname',
756 coreconfigitem('smtp', 'local_hostname',
754 default=None,
757 default=None,
755 )
758 )
756 coreconfigitem('smtp', 'password',
759 coreconfigitem('smtp', 'password',
757 default=None,
760 default=None,
758 )
761 )
759 coreconfigitem('smtp', 'port',
762 coreconfigitem('smtp', 'port',
760 default=dynamicdefault,
763 default=dynamicdefault,
761 )
764 )
762 coreconfigitem('smtp', 'tls',
765 coreconfigitem('smtp', 'tls',
763 default='none',
766 default='none',
764 )
767 )
765 coreconfigitem('smtp', 'username',
768 coreconfigitem('smtp', 'username',
766 default=None,
769 default=None,
767 )
770 )
768 coreconfigitem('sparse', 'missingwarning',
771 coreconfigitem('sparse', 'missingwarning',
769 default=True,
772 default=True,
770 )
773 )
771 coreconfigitem('templates', '.*',
774 coreconfigitem('templates', '.*',
772 default=None,
775 default=None,
773 generic=True,
776 generic=True,
774 )
777 )
775 coreconfigitem('trusted', 'groups',
778 coreconfigitem('trusted', 'groups',
776 default=list,
779 default=list,
777 )
780 )
778 coreconfigitem('trusted', 'users',
781 coreconfigitem('trusted', 'users',
779 default=list,
782 default=list,
780 )
783 )
781 coreconfigitem('ui', '_usedassubrepo',
784 coreconfigitem('ui', '_usedassubrepo',
782 default=False,
785 default=False,
783 )
786 )
784 coreconfigitem('ui', 'allowemptycommit',
787 coreconfigitem('ui', 'allowemptycommit',
785 default=False,
788 default=False,
786 )
789 )
787 coreconfigitem('ui', 'archivemeta',
790 coreconfigitem('ui', 'archivemeta',
788 default=True,
791 default=True,
789 )
792 )
790 coreconfigitem('ui', 'askusername',
793 coreconfigitem('ui', 'askusername',
791 default=False,
794 default=False,
792 )
795 )
793 coreconfigitem('ui', 'clonebundlefallback',
796 coreconfigitem('ui', 'clonebundlefallback',
794 default=False,
797 default=False,
795 )
798 )
796 coreconfigitem('ui', 'clonebundleprefers',
799 coreconfigitem('ui', 'clonebundleprefers',
797 default=list,
800 default=list,
798 )
801 )
799 coreconfigitem('ui', 'clonebundles',
802 coreconfigitem('ui', 'clonebundles',
800 default=True,
803 default=True,
801 )
804 )
802 coreconfigitem('ui', 'color',
805 coreconfigitem('ui', 'color',
803 default='auto',
806 default='auto',
804 )
807 )
805 coreconfigitem('ui', 'commitsubrepos',
808 coreconfigitem('ui', 'commitsubrepos',
806 default=False,
809 default=False,
807 )
810 )
808 coreconfigitem('ui', 'debug',
811 coreconfigitem('ui', 'debug',
809 default=False,
812 default=False,
810 )
813 )
811 coreconfigitem('ui', 'debugger',
814 coreconfigitem('ui', 'debugger',
812 default=None,
815 default=None,
813 )
816 )
814 coreconfigitem('ui', 'fallbackencoding',
817 coreconfigitem('ui', 'fallbackencoding',
815 default=None,
818 default=None,
816 )
819 )
817 coreconfigitem('ui', 'forcecwd',
820 coreconfigitem('ui', 'forcecwd',
818 default=None,
821 default=None,
819 )
822 )
820 coreconfigitem('ui', 'forcemerge',
823 coreconfigitem('ui', 'forcemerge',
821 default=None,
824 default=None,
822 )
825 )
823 coreconfigitem('ui', 'formatdebug',
826 coreconfigitem('ui', 'formatdebug',
824 default=False,
827 default=False,
825 )
828 )
826 coreconfigitem('ui', 'formatjson',
829 coreconfigitem('ui', 'formatjson',
827 default=False,
830 default=False,
828 )
831 )
829 coreconfigitem('ui', 'formatted',
832 coreconfigitem('ui', 'formatted',
830 default=None,
833 default=None,
831 )
834 )
832 coreconfigitem('ui', 'graphnodetemplate',
835 coreconfigitem('ui', 'graphnodetemplate',
833 default=None,
836 default=None,
834 )
837 )
835 coreconfigitem('ui', 'http2debuglevel',
838 coreconfigitem('ui', 'http2debuglevel',
836 default=None,
839 default=None,
837 )
840 )
838 coreconfigitem('ui', 'interactive',
841 coreconfigitem('ui', 'interactive',
839 default=None,
842 default=None,
840 )
843 )
841 coreconfigitem('ui', 'interface',
844 coreconfigitem('ui', 'interface',
842 default=None,
845 default=None,
843 )
846 )
844 coreconfigitem('ui', 'interface.chunkselector',
847 coreconfigitem('ui', 'interface.chunkselector',
845 default=None,
848 default=None,
846 )
849 )
847 coreconfigitem('ui', 'logblockedtimes',
850 coreconfigitem('ui', 'logblockedtimes',
848 default=False,
851 default=False,
849 )
852 )
850 coreconfigitem('ui', 'logtemplate',
853 coreconfigitem('ui', 'logtemplate',
851 default=None,
854 default=None,
852 )
855 )
853 coreconfigitem('ui', 'merge',
856 coreconfigitem('ui', 'merge',
854 default=None,
857 default=None,
855 )
858 )
856 coreconfigitem('ui', 'mergemarkers',
859 coreconfigitem('ui', 'mergemarkers',
857 default='basic',
860 default='basic',
858 )
861 )
859 coreconfigitem('ui', 'mergemarkertemplate',
862 coreconfigitem('ui', 'mergemarkertemplate',
860 default=('{node|short} '
863 default=('{node|short} '
861 '{ifeq(tags, "tip", "", '
864 '{ifeq(tags, "tip", "", '
862 'ifeq(tags, "", "", "{tags} "))}'
865 'ifeq(tags, "", "", "{tags} "))}'
863 '{if(bookmarks, "{bookmarks} ")}'
866 '{if(bookmarks, "{bookmarks} ")}'
864 '{ifeq(branch, "default", "", "{branch} ")}'
867 '{ifeq(branch, "default", "", "{branch} ")}'
865 '- {author|user}: {desc|firstline}')
868 '- {author|user}: {desc|firstline}')
866 )
869 )
867 coreconfigitem('ui', 'nontty',
870 coreconfigitem('ui', 'nontty',
868 default=False,
871 default=False,
869 )
872 )
870 coreconfigitem('ui', 'origbackuppath',
873 coreconfigitem('ui', 'origbackuppath',
871 default=None,
874 default=None,
872 )
875 )
873 coreconfigitem('ui', 'paginate',
876 coreconfigitem('ui', 'paginate',
874 default=True,
877 default=True,
875 )
878 )
876 coreconfigitem('ui', 'patch',
879 coreconfigitem('ui', 'patch',
877 default=None,
880 default=None,
878 )
881 )
879 coreconfigitem('ui', 'portablefilenames',
882 coreconfigitem('ui', 'portablefilenames',
880 default='warn',
883 default='warn',
881 )
884 )
882 coreconfigitem('ui', 'promptecho',
885 coreconfigitem('ui', 'promptecho',
883 default=False,
886 default=False,
884 )
887 )
885 coreconfigitem('ui', 'quiet',
888 coreconfigitem('ui', 'quiet',
886 default=False,
889 default=False,
887 )
890 )
888 coreconfigitem('ui', 'quietbookmarkmove',
891 coreconfigitem('ui', 'quietbookmarkmove',
889 default=False,
892 default=False,
890 )
893 )
891 coreconfigitem('ui', 'remotecmd',
894 coreconfigitem('ui', 'remotecmd',
892 default='hg',
895 default='hg',
893 )
896 )
894 coreconfigitem('ui', 'report_untrusted',
897 coreconfigitem('ui', 'report_untrusted',
895 default=True,
898 default=True,
896 )
899 )
897 coreconfigitem('ui', 'rollback',
900 coreconfigitem('ui', 'rollback',
898 default=True,
901 default=True,
899 )
902 )
900 coreconfigitem('ui', 'slash',
903 coreconfigitem('ui', 'slash',
901 default=False,
904 default=False,
902 )
905 )
903 coreconfigitem('ui', 'ssh',
906 coreconfigitem('ui', 'ssh',
904 default='ssh',
907 default='ssh',
905 )
908 )
906 coreconfigitem('ui', 'statuscopies',
909 coreconfigitem('ui', 'statuscopies',
907 default=False,
910 default=False,
908 )
911 )
909 coreconfigitem('ui', 'strict',
912 coreconfigitem('ui', 'strict',
910 default=False,
913 default=False,
911 )
914 )
912 coreconfigitem('ui', 'style',
915 coreconfigitem('ui', 'style',
913 default='',
916 default='',
914 )
917 )
915 coreconfigitem('ui', 'supportcontact',
918 coreconfigitem('ui', 'supportcontact',
916 default=None,
919 default=None,
917 )
920 )
918 coreconfigitem('ui', 'textwidth',
921 coreconfigitem('ui', 'textwidth',
919 default=78,
922 default=78,
920 )
923 )
921 coreconfigitem('ui', 'timeout',
924 coreconfigitem('ui', 'timeout',
922 default='600',
925 default='600',
923 )
926 )
924 coreconfigitem('ui', 'traceback',
927 coreconfigitem('ui', 'traceback',
925 default=False,
928 default=False,
926 )
929 )
927 coreconfigitem('ui', 'tweakdefaults',
930 coreconfigitem('ui', 'tweakdefaults',
928 default=False,
931 default=False,
929 )
932 )
930 coreconfigitem('ui', 'usehttp2',
933 coreconfigitem('ui', 'usehttp2',
931 default=False,
934 default=False,
932 )
935 )
933 coreconfigitem('ui', 'username',
936 coreconfigitem('ui', 'username',
934 alias=[('ui', 'user')]
937 alias=[('ui', 'user')]
935 )
938 )
936 coreconfigitem('ui', 'verbose',
939 coreconfigitem('ui', 'verbose',
937 default=False,
940 default=False,
938 )
941 )
939 coreconfigitem('verify', 'skipflags',
942 coreconfigitem('verify', 'skipflags',
940 default=None,
943 default=None,
941 )
944 )
942 coreconfigitem('web', 'allowbz2',
945 coreconfigitem('web', 'allowbz2',
943 default=False,
946 default=False,
944 )
947 )
945 coreconfigitem('web', 'allowgz',
948 coreconfigitem('web', 'allowgz',
946 default=False,
949 default=False,
947 )
950 )
948 coreconfigitem('web', 'allowpull',
951 coreconfigitem('web', 'allowpull',
949 default=True,
952 default=True,
950 )
953 )
951 coreconfigitem('web', 'allow_push',
954 coreconfigitem('web', 'allow_push',
952 default=list,
955 default=list,
953 )
956 )
954 coreconfigitem('web', 'allowzip',
957 coreconfigitem('web', 'allowzip',
955 default=False,
958 default=False,
956 )
959 )
957 coreconfigitem('web', 'archivesubrepos',
960 coreconfigitem('web', 'archivesubrepos',
958 default=False,
961 default=False,
959 )
962 )
960 coreconfigitem('web', 'cache',
963 coreconfigitem('web', 'cache',
961 default=True,
964 default=True,
962 )
965 )
963 coreconfigitem('web', 'contact',
966 coreconfigitem('web', 'contact',
964 default=None,
967 default=None,
965 )
968 )
966 coreconfigitem('web', 'deny_push',
969 coreconfigitem('web', 'deny_push',
967 default=list,
970 default=list,
968 )
971 )
969 coreconfigitem('web', 'guessmime',
972 coreconfigitem('web', 'guessmime',
970 default=False,
973 default=False,
971 )
974 )
972 coreconfigitem('web', 'hidden',
975 coreconfigitem('web', 'hidden',
973 default=False,
976 default=False,
974 )
977 )
975 coreconfigitem('web', 'labels',
978 coreconfigitem('web', 'labels',
976 default=list,
979 default=list,
977 )
980 )
978 coreconfigitem('web', 'logoimg',
981 coreconfigitem('web', 'logoimg',
979 default='hglogo.png',
982 default='hglogo.png',
980 )
983 )
981 coreconfigitem('web', 'logourl',
984 coreconfigitem('web', 'logourl',
982 default='https://mercurial-scm.org/',
985 default='https://mercurial-scm.org/',
983 )
986 )
984 coreconfigitem('web', 'accesslog',
987 coreconfigitem('web', 'accesslog',
985 default='-',
988 default='-',
986 )
989 )
987 coreconfigitem('web', 'address',
990 coreconfigitem('web', 'address',
988 default='',
991 default='',
989 )
992 )
990 coreconfigitem('web', 'allow_archive',
993 coreconfigitem('web', 'allow_archive',
991 default=list,
994 default=list,
992 )
995 )
993 coreconfigitem('web', 'allow_read',
996 coreconfigitem('web', 'allow_read',
994 default=list,
997 default=list,
995 )
998 )
996 coreconfigitem('web', 'baseurl',
999 coreconfigitem('web', 'baseurl',
997 default=None,
1000 default=None,
998 )
1001 )
999 coreconfigitem('web', 'cacerts',
1002 coreconfigitem('web', 'cacerts',
1000 default=None,
1003 default=None,
1001 )
1004 )
1002 coreconfigitem('web', 'certificate',
1005 coreconfigitem('web', 'certificate',
1003 default=None,
1006 default=None,
1004 )
1007 )
1005 coreconfigitem('web', 'collapse',
1008 coreconfigitem('web', 'collapse',
1006 default=False,
1009 default=False,
1007 )
1010 )
1008 coreconfigitem('web', 'csp',
1011 coreconfigitem('web', 'csp',
1009 default=None,
1012 default=None,
1010 )
1013 )
1011 coreconfigitem('web', 'deny_read',
1014 coreconfigitem('web', 'deny_read',
1012 default=list,
1015 default=list,
1013 )
1016 )
1014 coreconfigitem('web', 'descend',
1017 coreconfigitem('web', 'descend',
1015 default=True,
1018 default=True,
1016 )
1019 )
1017 coreconfigitem('web', 'description',
1020 coreconfigitem('web', 'description',
1018 default="",
1021 default="",
1019 )
1022 )
1020 coreconfigitem('web', 'encoding',
1023 coreconfigitem('web', 'encoding',
1021 default=lambda: encoding.encoding,
1024 default=lambda: encoding.encoding,
1022 )
1025 )
1023 coreconfigitem('web', 'errorlog',
1026 coreconfigitem('web', 'errorlog',
1024 default='-',
1027 default='-',
1025 )
1028 )
1026 coreconfigitem('web', 'ipv6',
1029 coreconfigitem('web', 'ipv6',
1027 default=False,
1030 default=False,
1028 )
1031 )
1029 coreconfigitem('web', 'maxchanges',
1032 coreconfigitem('web', 'maxchanges',
1030 default=10,
1033 default=10,
1031 )
1034 )
1032 coreconfigitem('web', 'maxfiles',
1035 coreconfigitem('web', 'maxfiles',
1033 default=10,
1036 default=10,
1034 )
1037 )
1035 coreconfigitem('web', 'maxshortchanges',
1038 coreconfigitem('web', 'maxshortchanges',
1036 default=60,
1039 default=60,
1037 )
1040 )
1038 coreconfigitem('web', 'motd',
1041 coreconfigitem('web', 'motd',
1039 default='',
1042 default='',
1040 )
1043 )
1041 coreconfigitem('web', 'name',
1044 coreconfigitem('web', 'name',
1042 default=dynamicdefault,
1045 default=dynamicdefault,
1043 )
1046 )
1044 coreconfigitem('web', 'port',
1047 coreconfigitem('web', 'port',
1045 default=8000,
1048 default=8000,
1046 )
1049 )
1047 coreconfigitem('web', 'prefix',
1050 coreconfigitem('web', 'prefix',
1048 default='',
1051 default='',
1049 )
1052 )
1050 coreconfigitem('web', 'push_ssl',
1053 coreconfigitem('web', 'push_ssl',
1051 default=True,
1054 default=True,
1052 )
1055 )
1053 coreconfigitem('web', 'refreshinterval',
1056 coreconfigitem('web', 'refreshinterval',
1054 default=20,
1057 default=20,
1055 )
1058 )
1056 coreconfigitem('web', 'staticurl',
1059 coreconfigitem('web', 'staticurl',
1057 default=None,
1060 default=None,
1058 )
1061 )
1059 coreconfigitem('web', 'stripes',
1062 coreconfigitem('web', 'stripes',
1060 default=1,
1063 default=1,
1061 )
1064 )
1062 coreconfigitem('web', 'style',
1065 coreconfigitem('web', 'style',
1063 default='paper',
1066 default='paper',
1064 )
1067 )
1065 coreconfigitem('web', 'templates',
1068 coreconfigitem('web', 'templates',
1066 default=None,
1069 default=None,
1067 )
1070 )
1068 coreconfigitem('web', 'view',
1071 coreconfigitem('web', 'view',
1069 default='served',
1072 default='served',
1070 )
1073 )
1071 coreconfigitem('worker', 'backgroundclose',
1074 coreconfigitem('worker', 'backgroundclose',
1072 default=dynamicdefault,
1075 default=dynamicdefault,
1073 )
1076 )
1074 # Windows defaults to a limit of 512 open files. A buffer of 128
1077 # Windows defaults to a limit of 512 open files. A buffer of 128
1075 # should give us enough headway.
1078 # should give us enough headway.
1076 coreconfigitem('worker', 'backgroundclosemaxqueue',
1079 coreconfigitem('worker', 'backgroundclosemaxqueue',
1077 default=384,
1080 default=384,
1078 )
1081 )
1079 coreconfigitem('worker', 'backgroundcloseminfilecount',
1082 coreconfigitem('worker', 'backgroundcloseminfilecount',
1080 default=2048,
1083 default=2048,
1081 )
1084 )
1082 coreconfigitem('worker', 'backgroundclosethreadcount',
1085 coreconfigitem('worker', 'backgroundclosethreadcount',
1083 default=4,
1086 default=4,
1084 )
1087 )
1085 coreconfigitem('worker', 'numcpus',
1088 coreconfigitem('worker', 'numcpus',
1086 default=None,
1089 default=None,
1087 )
1090 )
1088
1091
1089 # Rebase related configuration moved to core because other extension are doing
1092 # Rebase related configuration moved to core because other extension are doing
1090 # strange things. For example, shelve import the extensions to reuse some bit
1093 # strange things. For example, shelve import the extensions to reuse some bit
1091 # without formally loading it.
1094 # without formally loading it.
1092 coreconfigitem('commands', 'rebase.requiredest',
1095 coreconfigitem('commands', 'rebase.requiredest',
1093 default=False,
1096 default=False,
1094 )
1097 )
1095 coreconfigitem('experimental', 'rebaseskipobsolete',
1098 coreconfigitem('experimental', 'rebaseskipobsolete',
1096 default=True,
1099 default=True,
1097 )
1100 )
1098 coreconfigitem('rebase', 'singletransaction',
1101 coreconfigitem('rebase', 'singletransaction',
1099 default=False,
1102 default=False,
1100 )
1103 )
@@ -1,866 +1,884 b''
1 # copies.py - copy detection for Mercurial
1 # copies.py - copy detection for Mercurial
2 #
2 #
3 # Copyright 2008 Matt Mackall <mpm@selenic.com>
3 # Copyright 2008 Matt Mackall <mpm@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 from __future__ import absolute_import
8 from __future__ import absolute_import
9
9
10 import collections
10 import collections
11 import heapq
11 import heapq
12 import os
12 import os
13
13
14 from .i18n import _
15
14 from . import (
16 from . import (
15 match as matchmod,
17 match as matchmod,
16 node,
18 node,
17 pathutil,
19 pathutil,
18 scmutil,
20 scmutil,
19 util,
21 util,
20 )
22 )
21
23
22 def _findlimit(repo, a, b):
24 def _findlimit(repo, a, b):
23 """
25 """
24 Find the last revision that needs to be checked to ensure that a full
26 Find the last revision that needs to be checked to ensure that a full
25 transitive closure for file copies can be properly calculated.
27 transitive closure for file copies can be properly calculated.
26 Generally, this means finding the earliest revision number that's an
28 Generally, this means finding the earliest revision number that's an
27 ancestor of a or b but not both, except when a or b is a direct descendent
29 ancestor of a or b but not both, except when a or b is a direct descendent
28 of the other, in which case we can return the minimum revnum of a and b.
30 of the other, in which case we can return the minimum revnum of a and b.
29 None if no such revision exists.
31 None if no such revision exists.
30 """
32 """
31
33
32 # basic idea:
34 # basic idea:
33 # - mark a and b with different sides
35 # - mark a and b with different sides
34 # - if a parent's children are all on the same side, the parent is
36 # - if a parent's children are all on the same side, the parent is
35 # on that side, otherwise it is on no side
37 # on that side, otherwise it is on no side
36 # - walk the graph in topological order with the help of a heap;
38 # - walk the graph in topological order with the help of a heap;
37 # - add unseen parents to side map
39 # - add unseen parents to side map
38 # - clear side of any parent that has children on different sides
40 # - clear side of any parent that has children on different sides
39 # - track number of interesting revs that might still be on a side
41 # - track number of interesting revs that might still be on a side
40 # - track the lowest interesting rev seen
42 # - track the lowest interesting rev seen
41 # - quit when interesting revs is zero
43 # - quit when interesting revs is zero
42
44
43 cl = repo.changelog
45 cl = repo.changelog
44 working = len(cl) # pseudo rev for the working directory
46 working = len(cl) # pseudo rev for the working directory
45 if a is None:
47 if a is None:
46 a = working
48 a = working
47 if b is None:
49 if b is None:
48 b = working
50 b = working
49
51
50 side = {a: -1, b: 1}
52 side = {a: -1, b: 1}
51 visit = [-a, -b]
53 visit = [-a, -b]
52 heapq.heapify(visit)
54 heapq.heapify(visit)
53 interesting = len(visit)
55 interesting = len(visit)
54 hascommonancestor = False
56 hascommonancestor = False
55 limit = working
57 limit = working
56
58
57 while interesting:
59 while interesting:
58 r = -heapq.heappop(visit)
60 r = -heapq.heappop(visit)
59 if r == working:
61 if r == working:
60 parents = [cl.rev(p) for p in repo.dirstate.parents()]
62 parents = [cl.rev(p) for p in repo.dirstate.parents()]
61 else:
63 else:
62 parents = cl.parentrevs(r)
64 parents = cl.parentrevs(r)
63 for p in parents:
65 for p in parents:
64 if p < 0:
66 if p < 0:
65 continue
67 continue
66 if p not in side:
68 if p not in side:
67 # first time we see p; add it to visit
69 # first time we see p; add it to visit
68 side[p] = side[r]
70 side[p] = side[r]
69 if side[p]:
71 if side[p]:
70 interesting += 1
72 interesting += 1
71 heapq.heappush(visit, -p)
73 heapq.heappush(visit, -p)
72 elif side[p] and side[p] != side[r]:
74 elif side[p] and side[p] != side[r]:
73 # p was interesting but now we know better
75 # p was interesting but now we know better
74 side[p] = 0
76 side[p] = 0
75 interesting -= 1
77 interesting -= 1
76 hascommonancestor = True
78 hascommonancestor = True
77 if side[r]:
79 if side[r]:
78 limit = r # lowest rev visited
80 limit = r # lowest rev visited
79 interesting -= 1
81 interesting -= 1
80
82
81 if not hascommonancestor:
83 if not hascommonancestor:
82 return None
84 return None
83
85
84 # Consider the following flow (see test-commit-amend.t under issue4405):
86 # Consider the following flow (see test-commit-amend.t under issue4405):
85 # 1/ File 'a0' committed
87 # 1/ File 'a0' committed
86 # 2/ File renamed from 'a0' to 'a1' in a new commit (call it 'a1')
88 # 2/ File renamed from 'a0' to 'a1' in a new commit (call it 'a1')
87 # 3/ Move back to first commit
89 # 3/ Move back to first commit
88 # 4/ Create a new commit via revert to contents of 'a1' (call it 'a1-amend')
90 # 4/ Create a new commit via revert to contents of 'a1' (call it 'a1-amend')
89 # 5/ Rename file from 'a1' to 'a2' and commit --amend 'a1-msg'
91 # 5/ Rename file from 'a1' to 'a2' and commit --amend 'a1-msg'
90 #
92 #
91 # During the amend in step five, we will be in this state:
93 # During the amend in step five, we will be in this state:
92 #
94 #
93 # @ 3 temporary amend commit for a1-amend
95 # @ 3 temporary amend commit for a1-amend
94 # |
96 # |
95 # o 2 a1-amend
97 # o 2 a1-amend
96 # |
98 # |
97 # | o 1 a1
99 # | o 1 a1
98 # |/
100 # |/
99 # o 0 a0
101 # o 0 a0
100 #
102 #
101 # When _findlimit is called, a and b are revs 3 and 0, so limit will be 2,
103 # When _findlimit is called, a and b are revs 3 and 0, so limit will be 2,
102 # yet the filelog has the copy information in rev 1 and we will not look
104 # yet the filelog has the copy information in rev 1 and we will not look
103 # back far enough unless we also look at the a and b as candidates.
105 # back far enough unless we also look at the a and b as candidates.
104 # This only occurs when a is a descendent of b or visa-versa.
106 # This only occurs when a is a descendent of b or visa-versa.
105 return min(limit, a, b)
107 return min(limit, a, b)
106
108
107 def _chain(src, dst, a, b):
109 def _chain(src, dst, a, b):
108 '''chain two sets of copies a->b'''
110 '''chain two sets of copies a->b'''
109 t = a.copy()
111 t = a.copy()
110 for k, v in b.iteritems():
112 for k, v in b.iteritems():
111 if v in t:
113 if v in t:
112 # found a chain
114 # found a chain
113 if t[v] != k:
115 if t[v] != k:
114 # file wasn't renamed back to itself
116 # file wasn't renamed back to itself
115 t[k] = t[v]
117 t[k] = t[v]
116 if v not in dst:
118 if v not in dst:
117 # chain was a rename, not a copy
119 # chain was a rename, not a copy
118 del t[v]
120 del t[v]
119 if v in src:
121 if v in src:
120 # file is a copy of an existing file
122 # file is a copy of an existing file
121 t[k] = v
123 t[k] = v
122
124
123 # remove criss-crossed copies
125 # remove criss-crossed copies
124 for k, v in t.items():
126 for k, v in t.items():
125 if k in src and v in dst:
127 if k in src and v in dst:
126 del t[k]
128 del t[k]
127
129
128 return t
130 return t
129
131
130 def _tracefile(fctx, am, limit=-1):
132 def _tracefile(fctx, am, limit=-1):
131 '''return file context that is the ancestor of fctx present in ancestor
133 '''return file context that is the ancestor of fctx present in ancestor
132 manifest am, stopping after the first ancestor lower than limit'''
134 manifest am, stopping after the first ancestor lower than limit'''
133
135
134 for f in fctx.ancestors():
136 for f in fctx.ancestors():
135 if am.get(f.path(), None) == f.filenode():
137 if am.get(f.path(), None) == f.filenode():
136 return f
138 return f
137 if limit >= 0 and f.linkrev() < limit and f.rev() < limit:
139 if limit >= 0 and f.linkrev() < limit and f.rev() < limit:
138 return None
140 return None
139
141
140 def _dirstatecopies(d):
142 def _dirstatecopies(d):
141 ds = d._repo.dirstate
143 ds = d._repo.dirstate
142 c = ds.copies().copy()
144 c = ds.copies().copy()
143 for k in list(c):
145 for k in list(c):
144 if ds[k] not in 'anm':
146 if ds[k] not in 'anm':
145 del c[k]
147 del c[k]
146 return c
148 return c
147
149
148 def _computeforwardmissing(a, b, match=None):
150 def _computeforwardmissing(a, b, match=None):
149 """Computes which files are in b but not a.
151 """Computes which files are in b but not a.
150 This is its own function so extensions can easily wrap this call to see what
152 This is its own function so extensions can easily wrap this call to see what
151 files _forwardcopies is about to process.
153 files _forwardcopies is about to process.
152 """
154 """
153 ma = a.manifest()
155 ma = a.manifest()
154 mb = b.manifest()
156 mb = b.manifest()
155 return mb.filesnotin(ma, match=match)
157 return mb.filesnotin(ma, match=match)
156
158
157 def _forwardcopies(a, b, match=None):
159 def _forwardcopies(a, b, match=None):
158 '''find {dst@b: src@a} copy mapping where a is an ancestor of b'''
160 '''find {dst@b: src@a} copy mapping where a is an ancestor of b'''
159
161
160 # check for working copy
162 # check for working copy
161 w = None
163 w = None
162 if b.rev() is None:
164 if b.rev() is None:
163 w = b
165 w = b
164 b = w.p1()
166 b = w.p1()
165 if a == b:
167 if a == b:
166 # short-circuit to avoid issues with merge states
168 # short-circuit to avoid issues with merge states
167 return _dirstatecopies(w)
169 return _dirstatecopies(w)
168
170
169 # files might have to be traced back to the fctx parent of the last
171 # files might have to be traced back to the fctx parent of the last
170 # one-side-only changeset, but not further back than that
172 # one-side-only changeset, but not further back than that
171 limit = _findlimit(a._repo, a.rev(), b.rev())
173 limit = _findlimit(a._repo, a.rev(), b.rev())
172 if limit is None:
174 if limit is None:
173 limit = -1
175 limit = -1
174 am = a.manifest()
176 am = a.manifest()
175
177
176 # find where new files came from
178 # find where new files came from
177 # we currently don't try to find where old files went, too expensive
179 # we currently don't try to find where old files went, too expensive
178 # this means we can miss a case like 'hg rm b; hg cp a b'
180 # this means we can miss a case like 'hg rm b; hg cp a b'
179 cm = {}
181 cm = {}
180
182
181 # Computing the forward missing is quite expensive on large manifests, since
183 # Computing the forward missing is quite expensive on large manifests, since
182 # it compares the entire manifests. We can optimize it in the common use
184 # it compares the entire manifests. We can optimize it in the common use
183 # case of computing what copies are in a commit versus its parent (like
185 # case of computing what copies are in a commit versus its parent (like
184 # during a rebase or histedit). Note, we exclude merge commits from this
186 # during a rebase or histedit). Note, we exclude merge commits from this
185 # optimization, since the ctx.files() for a merge commit is not correct for
187 # optimization, since the ctx.files() for a merge commit is not correct for
186 # this comparison.
188 # this comparison.
187 forwardmissingmatch = match
189 forwardmissingmatch = match
188 if b.p1() == a and b.p2().node() == node.nullid:
190 if b.p1() == a and b.p2().node() == node.nullid:
189 filesmatcher = scmutil.matchfiles(a._repo, b.files())
191 filesmatcher = scmutil.matchfiles(a._repo, b.files())
190 forwardmissingmatch = matchmod.intersectmatchers(match, filesmatcher)
192 forwardmissingmatch = matchmod.intersectmatchers(match, filesmatcher)
191 missing = _computeforwardmissing(a, b, match=forwardmissingmatch)
193 missing = _computeforwardmissing(a, b, match=forwardmissingmatch)
192
194
193 ancestrycontext = a._repo.changelog.ancestors([b.rev()], inclusive=True)
195 ancestrycontext = a._repo.changelog.ancestors([b.rev()], inclusive=True)
194 for f in missing:
196 for f in missing:
195 fctx = b[f]
197 fctx = b[f]
196 fctx._ancestrycontext = ancestrycontext
198 fctx._ancestrycontext = ancestrycontext
197 ofctx = _tracefile(fctx, am, limit)
199 ofctx = _tracefile(fctx, am, limit)
198 if ofctx:
200 if ofctx:
199 cm[f] = ofctx.path()
201 cm[f] = ofctx.path()
200
202
201 # combine copies from dirstate if necessary
203 # combine copies from dirstate if necessary
202 if w is not None:
204 if w is not None:
203 cm = _chain(a, w, cm, _dirstatecopies(w))
205 cm = _chain(a, w, cm, _dirstatecopies(w))
204
206
205 return cm
207 return cm
206
208
207 def _backwardrenames(a, b):
209 def _backwardrenames(a, b):
208 if a._repo.ui.config('experimental', 'copytrace') == 'off':
210 if a._repo.ui.config('experimental', 'copytrace') == 'off':
209 return {}
211 return {}
210
212
211 # Even though we're not taking copies into account, 1:n rename situations
213 # Even though we're not taking copies into account, 1:n rename situations
212 # can still exist (e.g. hg cp a b; hg mv a c). In those cases we
214 # can still exist (e.g. hg cp a b; hg mv a c). In those cases we
213 # arbitrarily pick one of the renames.
215 # arbitrarily pick one of the renames.
214 f = _forwardcopies(b, a)
216 f = _forwardcopies(b, a)
215 r = {}
217 r = {}
216 for k, v in sorted(f.iteritems()):
218 for k, v in sorted(f.iteritems()):
217 # remove copies
219 # remove copies
218 if v in a:
220 if v in a:
219 continue
221 continue
220 r[v] = k
222 r[v] = k
221 return r
223 return r
222
224
223 def pathcopies(x, y, match=None):
225 def pathcopies(x, y, match=None):
224 '''find {dst@y: src@x} copy mapping for directed compare'''
226 '''find {dst@y: src@x} copy mapping for directed compare'''
225 if x == y or not x or not y:
227 if x == y or not x or not y:
226 return {}
228 return {}
227 a = y.ancestor(x)
229 a = y.ancestor(x)
228 if a == x:
230 if a == x:
229 return _forwardcopies(x, y, match=match)
231 return _forwardcopies(x, y, match=match)
230 if a == y:
232 if a == y:
231 return _backwardrenames(x, y)
233 return _backwardrenames(x, y)
232 return _chain(x, y, _backwardrenames(x, a),
234 return _chain(x, y, _backwardrenames(x, a),
233 _forwardcopies(a, y, match=match))
235 _forwardcopies(a, y, match=match))
234
236
235 def _computenonoverlap(repo, c1, c2, addedinm1, addedinm2, baselabel=''):
237 def _computenonoverlap(repo, c1, c2, addedinm1, addedinm2, baselabel=''):
236 """Computes, based on addedinm1 and addedinm2, the files exclusive to c1
238 """Computes, based on addedinm1 and addedinm2, the files exclusive to c1
237 and c2. This is its own function so extensions can easily wrap this call
239 and c2. This is its own function so extensions can easily wrap this call
238 to see what files mergecopies is about to process.
240 to see what files mergecopies is about to process.
239
241
240 Even though c1 and c2 are not used in this function, they are useful in
242 Even though c1 and c2 are not used in this function, they are useful in
241 other extensions for being able to read the file nodes of the changed files.
243 other extensions for being able to read the file nodes of the changed files.
242
244
243 "baselabel" can be passed to help distinguish the multiple computations
245 "baselabel" can be passed to help distinguish the multiple computations
244 done in the graft case.
246 done in the graft case.
245 """
247 """
246 u1 = sorted(addedinm1 - addedinm2)
248 u1 = sorted(addedinm1 - addedinm2)
247 u2 = sorted(addedinm2 - addedinm1)
249 u2 = sorted(addedinm2 - addedinm1)
248
250
249 header = " unmatched files in %s"
251 header = " unmatched files in %s"
250 if baselabel:
252 if baselabel:
251 header += ' (from %s)' % baselabel
253 header += ' (from %s)' % baselabel
252 if u1:
254 if u1:
253 repo.ui.debug("%s:\n %s\n" % (header % 'local', "\n ".join(u1)))
255 repo.ui.debug("%s:\n %s\n" % (header % 'local', "\n ".join(u1)))
254 if u2:
256 if u2:
255 repo.ui.debug("%s:\n %s\n" % (header % 'other', "\n ".join(u2)))
257 repo.ui.debug("%s:\n %s\n" % (header % 'other', "\n ".join(u2)))
256 return u1, u2
258 return u1, u2
257
259
258 def _makegetfctx(ctx):
260 def _makegetfctx(ctx):
259 """return a 'getfctx' function suitable for _checkcopies usage
261 """return a 'getfctx' function suitable for _checkcopies usage
260
262
261 We have to re-setup the function building 'filectx' for each
263 We have to re-setup the function building 'filectx' for each
262 '_checkcopies' to ensure the linkrev adjustment is properly setup for
264 '_checkcopies' to ensure the linkrev adjustment is properly setup for
263 each. Linkrev adjustment is important to avoid bug in rename
265 each. Linkrev adjustment is important to avoid bug in rename
264 detection. Moreover, having a proper '_ancestrycontext' setup ensures
266 detection. Moreover, having a proper '_ancestrycontext' setup ensures
265 the performance impact of this adjustment is kept limited. Without it,
267 the performance impact of this adjustment is kept limited. Without it,
266 each file could do a full dag traversal making the time complexity of
268 each file could do a full dag traversal making the time complexity of
267 the operation explode (see issue4537).
269 the operation explode (see issue4537).
268
270
269 This function exists here mostly to limit the impact on stable. Feel
271 This function exists here mostly to limit the impact on stable. Feel
270 free to refactor on default.
272 free to refactor on default.
271 """
273 """
272 rev = ctx.rev()
274 rev = ctx.rev()
273 repo = ctx._repo
275 repo = ctx._repo
274 ac = getattr(ctx, '_ancestrycontext', None)
276 ac = getattr(ctx, '_ancestrycontext', None)
275 if ac is None:
277 if ac is None:
276 revs = [rev]
278 revs = [rev]
277 if rev is None:
279 if rev is None:
278 revs = [p.rev() for p in ctx.parents()]
280 revs = [p.rev() for p in ctx.parents()]
279 ac = repo.changelog.ancestors(revs, inclusive=True)
281 ac = repo.changelog.ancestors(revs, inclusive=True)
280 ctx._ancestrycontext = ac
282 ctx._ancestrycontext = ac
281 def makectx(f, n):
283 def makectx(f, n):
282 if n in node.wdirnodes: # in a working context?
284 if n in node.wdirnodes: # in a working context?
283 if ctx.rev() is None:
285 if ctx.rev() is None:
284 return ctx.filectx(f)
286 return ctx.filectx(f)
285 return repo[None][f]
287 return repo[None][f]
286 fctx = repo.filectx(f, fileid=n)
288 fctx = repo.filectx(f, fileid=n)
287 # setup only needed for filectx not create from a changectx
289 # setup only needed for filectx not create from a changectx
288 fctx._ancestrycontext = ac
290 fctx._ancestrycontext = ac
289 fctx._descendantrev = rev
291 fctx._descendantrev = rev
290 return fctx
292 return fctx
291 return util.lrucachefunc(makectx)
293 return util.lrucachefunc(makectx)
292
294
293 def _combinecopies(copyfrom, copyto, finalcopy, diverge, incompletediverge):
295 def _combinecopies(copyfrom, copyto, finalcopy, diverge, incompletediverge):
294 """combine partial copy paths"""
296 """combine partial copy paths"""
295 remainder = {}
297 remainder = {}
296 for f in copyfrom:
298 for f in copyfrom:
297 if f in copyto:
299 if f in copyto:
298 finalcopy[copyto[f]] = copyfrom[f]
300 finalcopy[copyto[f]] = copyfrom[f]
299 del copyto[f]
301 del copyto[f]
300 for f in incompletediverge:
302 for f in incompletediverge:
301 assert f not in diverge
303 assert f not in diverge
302 ic = incompletediverge[f]
304 ic = incompletediverge[f]
303 if ic[0] in copyto:
305 if ic[0] in copyto:
304 diverge[f] = [copyto[ic[0]], ic[1]]
306 diverge[f] = [copyto[ic[0]], ic[1]]
305 else:
307 else:
306 remainder[f] = ic
308 remainder[f] = ic
307 return remainder
309 return remainder
308
310
309 def mergecopies(repo, c1, c2, base):
311 def mergecopies(repo, c1, c2, base):
310 """
312 """
311 The function calling different copytracing algorithms on the basis of config
313 The function calling different copytracing algorithms on the basis of config
312 which find moves and copies between context c1 and c2 that are relevant for
314 which find moves and copies between context c1 and c2 that are relevant for
313 merging. 'base' will be used as the merge base.
315 merging. 'base' will be used as the merge base.
314
316
315 Copytracing is used in commands like rebase, merge, unshelve, etc to merge
317 Copytracing is used in commands like rebase, merge, unshelve, etc to merge
316 files that were moved/ copied in one merge parent and modified in another.
318 files that were moved/ copied in one merge parent and modified in another.
317 For example:
319 For example:
318
320
319 o ---> 4 another commit
321 o ---> 4 another commit
320 |
322 |
321 | o ---> 3 commit that modifies a.txt
323 | o ---> 3 commit that modifies a.txt
322 | /
324 | /
323 o / ---> 2 commit that moves a.txt to b.txt
325 o / ---> 2 commit that moves a.txt to b.txt
324 |/
326 |/
325 o ---> 1 merge base
327 o ---> 1 merge base
326
328
327 If we try to rebase revision 3 on revision 4, since there is no a.txt in
329 If we try to rebase revision 3 on revision 4, since there is no a.txt in
328 revision 4, and if user have copytrace disabled, we prints the following
330 revision 4, and if user have copytrace disabled, we prints the following
329 message:
331 message:
330
332
331 ```other changed <file> which local deleted```
333 ```other changed <file> which local deleted```
332
334
333 Returns five dicts: "copy", "movewithdir", "diverge", "renamedelete" and
335 Returns five dicts: "copy", "movewithdir", "diverge", "renamedelete" and
334 "dirmove".
336 "dirmove".
335
337
336 "copy" is a mapping from destination name -> source name,
338 "copy" is a mapping from destination name -> source name,
337 where source is in c1 and destination is in c2 or vice-versa.
339 where source is in c1 and destination is in c2 or vice-versa.
338
340
339 "movewithdir" is a mapping from source name -> destination name,
341 "movewithdir" is a mapping from source name -> destination name,
340 where the file at source present in one context but not the other
342 where the file at source present in one context but not the other
341 needs to be moved to destination by the merge process, because the
343 needs to be moved to destination by the merge process, because the
342 other context moved the directory it is in.
344 other context moved the directory it is in.
343
345
344 "diverge" is a mapping of source name -> list of destination names
346 "diverge" is a mapping of source name -> list of destination names
345 for divergent renames.
347 for divergent renames.
346
348
347 "renamedelete" is a mapping of source name -> list of destination
349 "renamedelete" is a mapping of source name -> list of destination
348 names for files deleted in c1 that were renamed in c2 or vice-versa.
350 names for files deleted in c1 that were renamed in c2 or vice-versa.
349
351
350 "dirmove" is a mapping of detected source dir -> destination dir renames.
352 "dirmove" is a mapping of detected source dir -> destination dir renames.
351 This is needed for handling changes to new files previously grafted into
353 This is needed for handling changes to new files previously grafted into
352 renamed directories.
354 renamed directories.
353 """
355 """
354 # avoid silly behavior for update from empty dir
356 # avoid silly behavior for update from empty dir
355 if not c1 or not c2 or c1 == c2:
357 if not c1 or not c2 or c1 == c2:
356 return {}, {}, {}, {}, {}
358 return {}, {}, {}, {}, {}
357
359
358 # avoid silly behavior for parent -> working dir
360 # avoid silly behavior for parent -> working dir
359 if c2.node() is None and c1.node() == repo.dirstate.p1():
361 if c2.node() is None and c1.node() == repo.dirstate.p1():
360 return repo.dirstate.copies(), {}, {}, {}, {}
362 return repo.dirstate.copies(), {}, {}, {}, {}
361
363
362 copytracing = repo.ui.config('experimental', 'copytrace')
364 copytracing = repo.ui.config('experimental', 'copytrace')
363
365
364 # Copy trace disabling is explicitly below the node == p1 logic above
366 # Copy trace disabling is explicitly below the node == p1 logic above
365 # because the logic above is required for a simple copy to be kept across a
367 # because the logic above is required for a simple copy to be kept across a
366 # rebase.
368 # rebase.
367 if copytracing == 'off':
369 if copytracing == 'off':
368 return {}, {}, {}, {}, {}
370 return {}, {}, {}, {}, {}
369 elif copytracing == 'heuristics':
371 elif copytracing == 'heuristics':
370 # Do full copytracing if only non-public revisions are involved as
372 # Do full copytracing if only non-public revisions are involved as
371 # that will be fast enough and will also cover the copies which could
373 # that will be fast enough and will also cover the copies which could
372 # be missed by heuristics
374 # be missed by heuristics
373 if _isfullcopytraceable(repo, c1, base):
375 if _isfullcopytraceable(repo, c1, base):
374 return _fullcopytracing(repo, c1, c2, base)
376 return _fullcopytracing(repo, c1, c2, base)
375 return _heuristicscopytracing(repo, c1, c2, base)
377 return _heuristicscopytracing(repo, c1, c2, base)
376 else:
378 else:
377 return _fullcopytracing(repo, c1, c2, base)
379 return _fullcopytracing(repo, c1, c2, base)
378
380
379 def _isfullcopytraceable(repo, c1, base):
381 def _isfullcopytraceable(repo, c1, base):
380 """ Checks that if base, source and destination are all no-public branches,
382 """ Checks that if base, source and destination are all no-public branches,
381 if yes let's use the full copytrace algorithm for increased capabilities
383 if yes let's use the full copytrace algorithm for increased capabilities
382 since it will be fast enough.
384 since it will be fast enough.
383
385
384 `experimental.copytrace.sourcecommitlimit` can be used to set a limit for
386 `experimental.copytrace.sourcecommitlimit` can be used to set a limit for
385 number of changesets from c1 to base such that if number of changesets are
387 number of changesets from c1 to base such that if number of changesets are
386 more than the limit, full copytracing algorithm won't be used.
388 more than the limit, full copytracing algorithm won't be used.
387 """
389 """
388 if c1.rev() is None:
390 if c1.rev() is None:
389 c1 = c1.p1()
391 c1 = c1.p1()
390 if c1.mutable() and base.mutable():
392 if c1.mutable() and base.mutable():
391 sourcecommitlimit = repo.ui.configint('experimental',
393 sourcecommitlimit = repo.ui.configint('experimental',
392 'copytrace.sourcecommitlimit')
394 'copytrace.sourcecommitlimit')
393 commits = len(repo.revs('%d::%d', base.rev(), c1.rev()))
395 commits = len(repo.revs('%d::%d', base.rev(), c1.rev()))
394 return commits < sourcecommitlimit
396 return commits < sourcecommitlimit
395 return False
397 return False
396
398
397 def _fullcopytracing(repo, c1, c2, base):
399 def _fullcopytracing(repo, c1, c2, base):
398 """ The full copytracing algorithm which finds all the new files that were
400 """ The full copytracing algorithm which finds all the new files that were
399 added from merge base up to the top commit and for each file it checks if
401 added from merge base up to the top commit and for each file it checks if
400 this file was copied from another file.
402 this file was copied from another file.
401
403
402 This is pretty slow when a lot of changesets are involved but will track all
404 This is pretty slow when a lot of changesets are involved but will track all
403 the copies.
405 the copies.
404 """
406 """
405 # In certain scenarios (e.g. graft, update or rebase), base can be
407 # In certain scenarios (e.g. graft, update or rebase), base can be
406 # overridden We still need to know a real common ancestor in this case We
408 # overridden We still need to know a real common ancestor in this case We
407 # can't just compute _c1.ancestor(_c2) and compare it to ca, because there
409 # can't just compute _c1.ancestor(_c2) and compare it to ca, because there
408 # can be multiple common ancestors, e.g. in case of bidmerge. Because our
410 # can be multiple common ancestors, e.g. in case of bidmerge. Because our
409 # caller may not know if the revision passed in lieu of the CA is a genuine
411 # caller may not know if the revision passed in lieu of the CA is a genuine
410 # common ancestor or not without explicitly checking it, it's better to
412 # common ancestor or not without explicitly checking it, it's better to
411 # determine that here.
413 # determine that here.
412 #
414 #
413 # base.descendant(wc) and base.descendant(base) are False, work around that
415 # base.descendant(wc) and base.descendant(base) are False, work around that
414 _c1 = c1.p1() if c1.rev() is None else c1
416 _c1 = c1.p1() if c1.rev() is None else c1
415 _c2 = c2.p1() if c2.rev() is None else c2
417 _c2 = c2.p1() if c2.rev() is None else c2
416 # an endpoint is "dirty" if it isn't a descendant of the merge base
418 # an endpoint is "dirty" if it isn't a descendant of the merge base
417 # if we have a dirty endpoint, we need to trigger graft logic, and also
419 # if we have a dirty endpoint, we need to trigger graft logic, and also
418 # keep track of which endpoint is dirty
420 # keep track of which endpoint is dirty
419 dirtyc1 = not (base == _c1 or base.descendant(_c1))
421 dirtyc1 = not (base == _c1 or base.descendant(_c1))
420 dirtyc2 = not (base == _c2 or base.descendant(_c2))
422 dirtyc2 = not (base == _c2 or base.descendant(_c2))
421 graft = dirtyc1 or dirtyc2
423 graft = dirtyc1 or dirtyc2
422 tca = base
424 tca = base
423 if graft:
425 if graft:
424 tca = _c1.ancestor(_c2)
426 tca = _c1.ancestor(_c2)
425
427
426 limit = _findlimit(repo, c1.rev(), c2.rev())
428 limit = _findlimit(repo, c1.rev(), c2.rev())
427 if limit is None:
429 if limit is None:
428 # no common ancestor, no copies
430 # no common ancestor, no copies
429 return {}, {}, {}, {}, {}
431 return {}, {}, {}, {}, {}
430 repo.ui.debug(" searching for copies back to rev %d\n" % limit)
432 repo.ui.debug(" searching for copies back to rev %d\n" % limit)
431
433
432 m1 = c1.manifest()
434 m1 = c1.manifest()
433 m2 = c2.manifest()
435 m2 = c2.manifest()
434 mb = base.manifest()
436 mb = base.manifest()
435
437
436 # gather data from _checkcopies:
438 # gather data from _checkcopies:
437 # - diverge = record all diverges in this dict
439 # - diverge = record all diverges in this dict
438 # - copy = record all non-divergent copies in this dict
440 # - copy = record all non-divergent copies in this dict
439 # - fullcopy = record all copies in this dict
441 # - fullcopy = record all copies in this dict
440 # - incomplete = record non-divergent partial copies here
442 # - incomplete = record non-divergent partial copies here
441 # - incompletediverge = record divergent partial copies here
443 # - incompletediverge = record divergent partial copies here
442 diverge = {} # divergence data is shared
444 diverge = {} # divergence data is shared
443 incompletediverge = {}
445 incompletediverge = {}
444 data1 = {'copy': {},
446 data1 = {'copy': {},
445 'fullcopy': {},
447 'fullcopy': {},
446 'incomplete': {},
448 'incomplete': {},
447 'diverge': diverge,
449 'diverge': diverge,
448 'incompletediverge': incompletediverge,
450 'incompletediverge': incompletediverge,
449 }
451 }
450 data2 = {'copy': {},
452 data2 = {'copy': {},
451 'fullcopy': {},
453 'fullcopy': {},
452 'incomplete': {},
454 'incomplete': {},
453 'diverge': diverge,
455 'diverge': diverge,
454 'incompletediverge': incompletediverge,
456 'incompletediverge': incompletediverge,
455 }
457 }
456
458
457 # find interesting file sets from manifests
459 # find interesting file sets from manifests
458 addedinm1 = m1.filesnotin(mb)
460 addedinm1 = m1.filesnotin(mb)
459 addedinm2 = m2.filesnotin(mb)
461 addedinm2 = m2.filesnotin(mb)
460 bothnew = sorted(addedinm1 & addedinm2)
462 bothnew = sorted(addedinm1 & addedinm2)
461 if tca == base:
463 if tca == base:
462 # unmatched file from base
464 # unmatched file from base
463 u1r, u2r = _computenonoverlap(repo, c1, c2, addedinm1, addedinm2)
465 u1r, u2r = _computenonoverlap(repo, c1, c2, addedinm1, addedinm2)
464 u1u, u2u = u1r, u2r
466 u1u, u2u = u1r, u2r
465 else:
467 else:
466 # unmatched file from base (DAG rotation in the graft case)
468 # unmatched file from base (DAG rotation in the graft case)
467 u1r, u2r = _computenonoverlap(repo, c1, c2, addedinm1, addedinm2,
469 u1r, u2r = _computenonoverlap(repo, c1, c2, addedinm1, addedinm2,
468 baselabel='base')
470 baselabel='base')
469 # unmatched file from topological common ancestors (no DAG rotation)
471 # unmatched file from topological common ancestors (no DAG rotation)
470 # need to recompute this for directory move handling when grafting
472 # need to recompute this for directory move handling when grafting
471 mta = tca.manifest()
473 mta = tca.manifest()
472 u1u, u2u = _computenonoverlap(repo, c1, c2, m1.filesnotin(mta),
474 u1u, u2u = _computenonoverlap(repo, c1, c2, m1.filesnotin(mta),
473 m2.filesnotin(mta),
475 m2.filesnotin(mta),
474 baselabel='topological common ancestor')
476 baselabel='topological common ancestor')
475
477
476 for f in u1u:
478 for f in u1u:
477 _checkcopies(c1, c2, f, base, tca, dirtyc1, limit, data1)
479 _checkcopies(c1, c2, f, base, tca, dirtyc1, limit, data1)
478
480
479 for f in u2u:
481 for f in u2u:
480 _checkcopies(c2, c1, f, base, tca, dirtyc2, limit, data2)
482 _checkcopies(c2, c1, f, base, tca, dirtyc2, limit, data2)
481
483
482 copy = dict(data1['copy'])
484 copy = dict(data1['copy'])
483 copy.update(data2['copy'])
485 copy.update(data2['copy'])
484 fullcopy = dict(data1['fullcopy'])
486 fullcopy = dict(data1['fullcopy'])
485 fullcopy.update(data2['fullcopy'])
487 fullcopy.update(data2['fullcopy'])
486
488
487 if dirtyc1:
489 if dirtyc1:
488 _combinecopies(data2['incomplete'], data1['incomplete'], copy, diverge,
490 _combinecopies(data2['incomplete'], data1['incomplete'], copy, diverge,
489 incompletediverge)
491 incompletediverge)
490 else:
492 else:
491 _combinecopies(data1['incomplete'], data2['incomplete'], copy, diverge,
493 _combinecopies(data1['incomplete'], data2['incomplete'], copy, diverge,
492 incompletediverge)
494 incompletediverge)
493
495
494 renamedelete = {}
496 renamedelete = {}
495 renamedeleteset = set()
497 renamedeleteset = set()
496 divergeset = set()
498 divergeset = set()
497 for of, fl in list(diverge.items()):
499 for of, fl in list(diverge.items()):
498 if len(fl) == 1 or of in c1 or of in c2:
500 if len(fl) == 1 or of in c1 or of in c2:
499 del diverge[of] # not actually divergent, or not a rename
501 del diverge[of] # not actually divergent, or not a rename
500 if of not in c1 and of not in c2:
502 if of not in c1 and of not in c2:
501 # renamed on one side, deleted on the other side, but filter
503 # renamed on one side, deleted on the other side, but filter
502 # out files that have been renamed and then deleted
504 # out files that have been renamed and then deleted
503 renamedelete[of] = [f for f in fl if f in c1 or f in c2]
505 renamedelete[of] = [f for f in fl if f in c1 or f in c2]
504 renamedeleteset.update(fl) # reverse map for below
506 renamedeleteset.update(fl) # reverse map for below
505 else:
507 else:
506 divergeset.update(fl) # reverse map for below
508 divergeset.update(fl) # reverse map for below
507
509
508 if bothnew:
510 if bothnew:
509 repo.ui.debug(" unmatched files new in both:\n %s\n"
511 repo.ui.debug(" unmatched files new in both:\n %s\n"
510 % "\n ".join(bothnew))
512 % "\n ".join(bothnew))
511 bothdiverge = {}
513 bothdiverge = {}
512 bothincompletediverge = {}
514 bothincompletediverge = {}
513 remainder = {}
515 remainder = {}
514 both1 = {'copy': {},
516 both1 = {'copy': {},
515 'fullcopy': {},
517 'fullcopy': {},
516 'incomplete': {},
518 'incomplete': {},
517 'diverge': bothdiverge,
519 'diverge': bothdiverge,
518 'incompletediverge': bothincompletediverge
520 'incompletediverge': bothincompletediverge
519 }
521 }
520 both2 = {'copy': {},
522 both2 = {'copy': {},
521 'fullcopy': {},
523 'fullcopy': {},
522 'incomplete': {},
524 'incomplete': {},
523 'diverge': bothdiverge,
525 'diverge': bothdiverge,
524 'incompletediverge': bothincompletediverge
526 'incompletediverge': bothincompletediverge
525 }
527 }
526 for f in bothnew:
528 for f in bothnew:
527 _checkcopies(c1, c2, f, base, tca, dirtyc1, limit, both1)
529 _checkcopies(c1, c2, f, base, tca, dirtyc1, limit, both1)
528 _checkcopies(c2, c1, f, base, tca, dirtyc2, limit, both2)
530 _checkcopies(c2, c1, f, base, tca, dirtyc2, limit, both2)
529 if dirtyc1:
531 if dirtyc1:
530 # incomplete copies may only be found on the "dirty" side for bothnew
532 # incomplete copies may only be found on the "dirty" side for bothnew
531 assert not both2['incomplete']
533 assert not both2['incomplete']
532 remainder = _combinecopies({}, both1['incomplete'], copy, bothdiverge,
534 remainder = _combinecopies({}, both1['incomplete'], copy, bothdiverge,
533 bothincompletediverge)
535 bothincompletediverge)
534 elif dirtyc2:
536 elif dirtyc2:
535 assert not both1['incomplete']
537 assert not both1['incomplete']
536 remainder = _combinecopies({}, both2['incomplete'], copy, bothdiverge,
538 remainder = _combinecopies({}, both2['incomplete'], copy, bothdiverge,
537 bothincompletediverge)
539 bothincompletediverge)
538 else:
540 else:
539 # incomplete copies and divergences can't happen outside grafts
541 # incomplete copies and divergences can't happen outside grafts
540 assert not both1['incomplete']
542 assert not both1['incomplete']
541 assert not both2['incomplete']
543 assert not both2['incomplete']
542 assert not bothincompletediverge
544 assert not bothincompletediverge
543 for f in remainder:
545 for f in remainder:
544 assert f not in bothdiverge
546 assert f not in bothdiverge
545 ic = remainder[f]
547 ic = remainder[f]
546 if ic[0] in (m1 if dirtyc1 else m2):
548 if ic[0] in (m1 if dirtyc1 else m2):
547 # backed-out rename on one side, but watch out for deleted files
549 # backed-out rename on one side, but watch out for deleted files
548 bothdiverge[f] = ic
550 bothdiverge[f] = ic
549 for of, fl in bothdiverge.items():
551 for of, fl in bothdiverge.items():
550 if len(fl) == 2 and fl[0] == fl[1]:
552 if len(fl) == 2 and fl[0] == fl[1]:
551 copy[fl[0]] = of # not actually divergent, just matching renames
553 copy[fl[0]] = of # not actually divergent, just matching renames
552
554
553 if fullcopy and repo.ui.debugflag:
555 if fullcopy and repo.ui.debugflag:
554 repo.ui.debug(" all copies found (* = to merge, ! = divergent, "
556 repo.ui.debug(" all copies found (* = to merge, ! = divergent, "
555 "% = renamed and deleted):\n")
557 "% = renamed and deleted):\n")
556 for f in sorted(fullcopy):
558 for f in sorted(fullcopy):
557 note = ""
559 note = ""
558 if f in copy:
560 if f in copy:
559 note += "*"
561 note += "*"
560 if f in divergeset:
562 if f in divergeset:
561 note += "!"
563 note += "!"
562 if f in renamedeleteset:
564 if f in renamedeleteset:
563 note += "%"
565 note += "%"
564 repo.ui.debug(" src: '%s' -> dst: '%s' %s\n" % (fullcopy[f], f,
566 repo.ui.debug(" src: '%s' -> dst: '%s' %s\n" % (fullcopy[f], f,
565 note))
567 note))
566 del divergeset
568 del divergeset
567
569
568 if not fullcopy:
570 if not fullcopy:
569 return copy, {}, diverge, renamedelete, {}
571 return copy, {}, diverge, renamedelete, {}
570
572
571 repo.ui.debug(" checking for directory renames\n")
573 repo.ui.debug(" checking for directory renames\n")
572
574
573 # generate a directory move map
575 # generate a directory move map
574 d1, d2 = c1.dirs(), c2.dirs()
576 d1, d2 = c1.dirs(), c2.dirs()
575 # Hack for adding '', which is not otherwise added, to d1 and d2
577 # Hack for adding '', which is not otherwise added, to d1 and d2
576 d1.addpath('/')
578 d1.addpath('/')
577 d2.addpath('/')
579 d2.addpath('/')
578 invalid = set()
580 invalid = set()
579 dirmove = {}
581 dirmove = {}
580
582
581 # examine each file copy for a potential directory move, which is
583 # examine each file copy for a potential directory move, which is
582 # when all the files in a directory are moved to a new directory
584 # when all the files in a directory are moved to a new directory
583 for dst, src in fullcopy.iteritems():
585 for dst, src in fullcopy.iteritems():
584 dsrc, ddst = pathutil.dirname(src), pathutil.dirname(dst)
586 dsrc, ddst = pathutil.dirname(src), pathutil.dirname(dst)
585 if dsrc in invalid:
587 if dsrc in invalid:
586 # already seen to be uninteresting
588 # already seen to be uninteresting
587 continue
589 continue
588 elif dsrc in d1 and ddst in d1:
590 elif dsrc in d1 and ddst in d1:
589 # directory wasn't entirely moved locally
591 # directory wasn't entirely moved locally
590 invalid.add(dsrc + "/")
592 invalid.add(dsrc + "/")
591 elif dsrc in d2 and ddst in d2:
593 elif dsrc in d2 and ddst in d2:
592 # directory wasn't entirely moved remotely
594 # directory wasn't entirely moved remotely
593 invalid.add(dsrc + "/")
595 invalid.add(dsrc + "/")
594 elif dsrc + "/" in dirmove and dirmove[dsrc + "/"] != ddst + "/":
596 elif dsrc + "/" in dirmove and dirmove[dsrc + "/"] != ddst + "/":
595 # files from the same directory moved to two different places
597 # files from the same directory moved to two different places
596 invalid.add(dsrc + "/")
598 invalid.add(dsrc + "/")
597 else:
599 else:
598 # looks good so far
600 # looks good so far
599 dirmove[dsrc + "/"] = ddst + "/"
601 dirmove[dsrc + "/"] = ddst + "/"
600
602
601 for i in invalid:
603 for i in invalid:
602 if i in dirmove:
604 if i in dirmove:
603 del dirmove[i]
605 del dirmove[i]
604 del d1, d2, invalid
606 del d1, d2, invalid
605
607
606 if not dirmove:
608 if not dirmove:
607 return copy, {}, diverge, renamedelete, {}
609 return copy, {}, diverge, renamedelete, {}
608
610
609 for d in dirmove:
611 for d in dirmove:
610 repo.ui.debug(" discovered dir src: '%s' -> dst: '%s'\n" %
612 repo.ui.debug(" discovered dir src: '%s' -> dst: '%s'\n" %
611 (d, dirmove[d]))
613 (d, dirmove[d]))
612
614
613 movewithdir = {}
615 movewithdir = {}
614 # check unaccounted nonoverlapping files against directory moves
616 # check unaccounted nonoverlapping files against directory moves
615 for f in u1r + u2r:
617 for f in u1r + u2r:
616 if f not in fullcopy:
618 if f not in fullcopy:
617 for d in dirmove:
619 for d in dirmove:
618 if f.startswith(d):
620 if f.startswith(d):
619 # new file added in a directory that was moved, move it
621 # new file added in a directory that was moved, move it
620 df = dirmove[d] + f[len(d):]
622 df = dirmove[d] + f[len(d):]
621 if df not in copy:
623 if df not in copy:
622 movewithdir[f] = df
624 movewithdir[f] = df
623 repo.ui.debug((" pending file src: '%s' -> "
625 repo.ui.debug((" pending file src: '%s' -> "
624 "dst: '%s'\n") % (f, df))
626 "dst: '%s'\n") % (f, df))
625 break
627 break
626
628
627 return copy, movewithdir, diverge, renamedelete, dirmove
629 return copy, movewithdir, diverge, renamedelete, dirmove
628
630
629 def _heuristicscopytracing(repo, c1, c2, base):
631 def _heuristicscopytracing(repo, c1, c2, base):
630 """ Fast copytracing using filename heuristics
632 """ Fast copytracing using filename heuristics
631
633
632 Assumes that moves or renames are of following two types:
634 Assumes that moves or renames are of following two types:
633
635
634 1) Inside a directory only (same directory name but different filenames)
636 1) Inside a directory only (same directory name but different filenames)
635 2) Move from one directory to another
637 2) Move from one directory to another
636 (same filenames but different directory names)
638 (same filenames but different directory names)
637
639
638 Works only when there are no merge commits in the "source branch".
640 Works only when there are no merge commits in the "source branch".
639 Source branch is commits from base up to c2 not including base.
641 Source branch is commits from base up to c2 not including base.
640
642
641 If merge is involved it fallbacks to _fullcopytracing().
643 If merge is involved it fallbacks to _fullcopytracing().
642
644
643 Can be used by setting the following config:
645 Can be used by setting the following config:
644
646
645 [experimental]
647 [experimental]
646 copytrace = heuristics
648 copytrace = heuristics
649
650 In some cases the copy/move candidates found by heuristics can be very large
651 in number and that will make the algorithm slow. The number of possible
652 candidates to check can be limited by using the config
653 `experimental.copytrace.movecandidateslimit` which defaults to 100.
647 """
654 """
648
655
649 if c1.rev() is None:
656 if c1.rev() is None:
650 c1 = c1.p1()
657 c1 = c1.p1()
651 if c2.rev() is None:
658 if c2.rev() is None:
652 c2 = c2.p1()
659 c2 = c2.p1()
653
660
654 copies = {}
661 copies = {}
655
662
656 changedfiles = set()
663 changedfiles = set()
657 m1 = c1.manifest()
664 m1 = c1.manifest()
658 if not repo.revs('%d::%d', base.rev(), c2.rev()):
665 if not repo.revs('%d::%d', base.rev(), c2.rev()):
659 # If base is not in c2 branch, we switch to fullcopytracing
666 # If base is not in c2 branch, we switch to fullcopytracing
660 repo.ui.debug("switching to full copytracing as base is not "
667 repo.ui.debug("switching to full copytracing as base is not "
661 "an ancestor of c2\n")
668 "an ancestor of c2\n")
662 return _fullcopytracing(repo, c1, c2, base)
669 return _fullcopytracing(repo, c1, c2, base)
663
670
664 ctx = c2
671 ctx = c2
665 while ctx != base:
672 while ctx != base:
666 if len(ctx.parents()) == 2:
673 if len(ctx.parents()) == 2:
667 # To keep things simple let's not handle merges
674 # To keep things simple let's not handle merges
668 repo.ui.debug("switching to full copytracing because of merges\n")
675 repo.ui.debug("switching to full copytracing because of merges\n")
669 return _fullcopytracing(repo, c1, c2, base)
676 return _fullcopytracing(repo, c1, c2, base)
670 changedfiles.update(ctx.files())
677 changedfiles.update(ctx.files())
671 ctx = ctx.p1()
678 ctx = ctx.p1()
672
679
673 cp = _forwardcopies(base, c2)
680 cp = _forwardcopies(base, c2)
674 for dst, src in cp.iteritems():
681 for dst, src in cp.iteritems():
675 if src in m1:
682 if src in m1:
676 copies[dst] = src
683 copies[dst] = src
677
684
678 # file is missing if it isn't present in the destination, but is present in
685 # file is missing if it isn't present in the destination, but is present in
679 # the base and present in the source.
686 # the base and present in the source.
680 # Presence in the base is important to exclude added files, presence in the
687 # Presence in the base is important to exclude added files, presence in the
681 # source is important to exclude removed files.
688 # source is important to exclude removed files.
682 missingfiles = filter(lambda f: f not in m1 and f in base and f in c2,
689 missingfiles = filter(lambda f: f not in m1 and f in base and f in c2,
683 changedfiles)
690 changedfiles)
684
691
685 if missingfiles:
692 if missingfiles:
686 basenametofilename = collections.defaultdict(list)
693 basenametofilename = collections.defaultdict(list)
687 dirnametofilename = collections.defaultdict(list)
694 dirnametofilename = collections.defaultdict(list)
688
695
689 for f in m1.filesnotin(base.manifest()):
696 for f in m1.filesnotin(base.manifest()):
690 basename = os.path.basename(f)
697 basename = os.path.basename(f)
691 dirname = os.path.dirname(f)
698 dirname = os.path.dirname(f)
692 basenametofilename[basename].append(f)
699 basenametofilename[basename].append(f)
693 dirnametofilename[dirname].append(f)
700 dirnametofilename[dirname].append(f)
694
701
695 # in case of a rebase/graft, base may not be a common ancestor
702 # in case of a rebase/graft, base may not be a common ancestor
696 anc = c1.ancestor(c2)
703 anc = c1.ancestor(c2)
697
704
698 for f in missingfiles:
705 for f in missingfiles:
699 basename = os.path.basename(f)
706 basename = os.path.basename(f)
700 dirname = os.path.dirname(f)
707 dirname = os.path.dirname(f)
701 samebasename = basenametofilename[basename]
708 samebasename = basenametofilename[basename]
702 samedirname = dirnametofilename[dirname]
709 samedirname = dirnametofilename[dirname]
703 movecandidates = samebasename + samedirname
710 movecandidates = samebasename + samedirname
704 # f is guaranteed to be present in c2, that's why
711 # f is guaranteed to be present in c2, that's why
705 # c2.filectx(f) won't fail
712 # c2.filectx(f) won't fail
706 f2 = c2.filectx(f)
713 f2 = c2.filectx(f)
714 # we can have a lot of candidates which can slow down the heuristics
715 # config value to limit the number of candidates moves to check
716 maxcandidates = repo.ui.configint('experimental',
717 'copytrace.movecandidateslimit')
718
719 if len(movecandidates) > maxcandidates:
720 repo.ui.status(_("skipping copytracing for '%s', more "
721 "candidates than the limit: %d\n")
722 % (f, len(movecandidates)))
723 continue
724
707 for candidate in movecandidates:
725 for candidate in movecandidates:
708 f1 = c1.filectx(candidate)
726 f1 = c1.filectx(candidate)
709 if _related(f1, f2, anc.rev()):
727 if _related(f1, f2, anc.rev()):
710 # if there are a few related copies then we'll merge
728 # if there are a few related copies then we'll merge
711 # changes into all of them. This matches the behaviour
729 # changes into all of them. This matches the behaviour
712 # of upstream copytracing
730 # of upstream copytracing
713 copies[candidate] = f
731 copies[candidate] = f
714
732
715 return copies, {}, {}, {}, {}
733 return copies, {}, {}, {}, {}
716
734
717 def _related(f1, f2, limit):
735 def _related(f1, f2, limit):
718 """return True if f1 and f2 filectx have a common ancestor
736 """return True if f1 and f2 filectx have a common ancestor
719
737
720 Walk back to common ancestor to see if the two files originate
738 Walk back to common ancestor to see if the two files originate
721 from the same file. Since workingfilectx's rev() is None it messes
739 from the same file. Since workingfilectx's rev() is None it messes
722 up the integer comparison logic, hence the pre-step check for
740 up the integer comparison logic, hence the pre-step check for
723 None (f1 and f2 can only be workingfilectx's initially).
741 None (f1 and f2 can only be workingfilectx's initially).
724 """
742 """
725
743
726 if f1 == f2:
744 if f1 == f2:
727 return f1 # a match
745 return f1 # a match
728
746
729 g1, g2 = f1.ancestors(), f2.ancestors()
747 g1, g2 = f1.ancestors(), f2.ancestors()
730 try:
748 try:
731 f1r, f2r = f1.linkrev(), f2.linkrev()
749 f1r, f2r = f1.linkrev(), f2.linkrev()
732
750
733 if f1r is None:
751 if f1r is None:
734 f1 = next(g1)
752 f1 = next(g1)
735 if f2r is None:
753 if f2r is None:
736 f2 = next(g2)
754 f2 = next(g2)
737
755
738 while True:
756 while True:
739 f1r, f2r = f1.linkrev(), f2.linkrev()
757 f1r, f2r = f1.linkrev(), f2.linkrev()
740 if f1r > f2r:
758 if f1r > f2r:
741 f1 = next(g1)
759 f1 = next(g1)
742 elif f2r > f1r:
760 elif f2r > f1r:
743 f2 = next(g2)
761 f2 = next(g2)
744 elif f1 == f2:
762 elif f1 == f2:
745 return f1 # a match
763 return f1 # a match
746 elif f1r == f2r or f1r < limit or f2r < limit:
764 elif f1r == f2r or f1r < limit or f2r < limit:
747 return False # copy no longer relevant
765 return False # copy no longer relevant
748 except StopIteration:
766 except StopIteration:
749 return False
767 return False
750
768
751 def _checkcopies(srcctx, dstctx, f, base, tca, remotebase, limit, data):
769 def _checkcopies(srcctx, dstctx, f, base, tca, remotebase, limit, data):
752 """
770 """
753 check possible copies of f from msrc to mdst
771 check possible copies of f from msrc to mdst
754
772
755 srcctx = starting context for f in msrc
773 srcctx = starting context for f in msrc
756 dstctx = destination context for f in mdst
774 dstctx = destination context for f in mdst
757 f = the filename to check (as in msrc)
775 f = the filename to check (as in msrc)
758 base = the changectx used as a merge base
776 base = the changectx used as a merge base
759 tca = topological common ancestor for graft-like scenarios
777 tca = topological common ancestor for graft-like scenarios
760 remotebase = True if base is outside tca::srcctx, False otherwise
778 remotebase = True if base is outside tca::srcctx, False otherwise
761 limit = the rev number to not search beyond
779 limit = the rev number to not search beyond
762 data = dictionary of dictionary to store copy data. (see mergecopies)
780 data = dictionary of dictionary to store copy data. (see mergecopies)
763
781
764 note: limit is only an optimization, and provides no guarantee that
782 note: limit is only an optimization, and provides no guarantee that
765 irrelevant revisions will not be visited
783 irrelevant revisions will not be visited
766 there is no easy way to make this algorithm stop in a guaranteed way
784 there is no easy way to make this algorithm stop in a guaranteed way
767 once it "goes behind a certain revision".
785 once it "goes behind a certain revision".
768 """
786 """
769
787
770 msrc = srcctx.manifest()
788 msrc = srcctx.manifest()
771 mdst = dstctx.manifest()
789 mdst = dstctx.manifest()
772 mb = base.manifest()
790 mb = base.manifest()
773 mta = tca.manifest()
791 mta = tca.manifest()
774 # Might be true if this call is about finding backward renames,
792 # Might be true if this call is about finding backward renames,
775 # This happens in the case of grafts because the DAG is then rotated.
793 # This happens in the case of grafts because the DAG is then rotated.
776 # If the file exists in both the base and the source, we are not looking
794 # If the file exists in both the base and the source, we are not looking
777 # for a rename on the source side, but on the part of the DAG that is
795 # for a rename on the source side, but on the part of the DAG that is
778 # traversed backwards.
796 # traversed backwards.
779 #
797 #
780 # In the case there is both backward and forward renames (before and after
798 # In the case there is both backward and forward renames (before and after
781 # the base) this is more complicated as we must detect a divergence.
799 # the base) this is more complicated as we must detect a divergence.
782 # We use 'backwards = False' in that case.
800 # We use 'backwards = False' in that case.
783 backwards = not remotebase and base != tca and f in mb
801 backwards = not remotebase and base != tca and f in mb
784 getsrcfctx = _makegetfctx(srcctx)
802 getsrcfctx = _makegetfctx(srcctx)
785 getdstfctx = _makegetfctx(dstctx)
803 getdstfctx = _makegetfctx(dstctx)
786
804
787 if msrc[f] == mb.get(f) and not remotebase:
805 if msrc[f] == mb.get(f) and not remotebase:
788 # Nothing to merge
806 # Nothing to merge
789 return
807 return
790
808
791 of = None
809 of = None
792 seen = {f}
810 seen = {f}
793 for oc in getsrcfctx(f, msrc[f]).ancestors():
811 for oc in getsrcfctx(f, msrc[f]).ancestors():
794 ocr = oc.linkrev()
812 ocr = oc.linkrev()
795 of = oc.path()
813 of = oc.path()
796 if of in seen:
814 if of in seen:
797 # check limit late - grab last rename before
815 # check limit late - grab last rename before
798 if ocr < limit:
816 if ocr < limit:
799 break
817 break
800 continue
818 continue
801 seen.add(of)
819 seen.add(of)
802
820
803 # remember for dir rename detection
821 # remember for dir rename detection
804 if backwards:
822 if backwards:
805 data['fullcopy'][of] = f # grafting backwards through renames
823 data['fullcopy'][of] = f # grafting backwards through renames
806 else:
824 else:
807 data['fullcopy'][f] = of
825 data['fullcopy'][f] = of
808 if of not in mdst:
826 if of not in mdst:
809 continue # no match, keep looking
827 continue # no match, keep looking
810 if mdst[of] == mb.get(of):
828 if mdst[of] == mb.get(of):
811 return # no merge needed, quit early
829 return # no merge needed, quit early
812 c2 = getdstfctx(of, mdst[of])
830 c2 = getdstfctx(of, mdst[of])
813 # c2 might be a plain new file on added on destination side that is
831 # c2 might be a plain new file on added on destination side that is
814 # unrelated to the droids we are looking for.
832 # unrelated to the droids we are looking for.
815 cr = _related(oc, c2, tca.rev())
833 cr = _related(oc, c2, tca.rev())
816 if cr and (of == f or of == c2.path()): # non-divergent
834 if cr and (of == f or of == c2.path()): # non-divergent
817 if backwards:
835 if backwards:
818 data['copy'][of] = f
836 data['copy'][of] = f
819 elif of in mb:
837 elif of in mb:
820 data['copy'][f] = of
838 data['copy'][f] = of
821 elif remotebase: # special case: a <- b <- a -> b "ping-pong" rename
839 elif remotebase: # special case: a <- b <- a -> b "ping-pong" rename
822 data['copy'][of] = f
840 data['copy'][of] = f
823 del data['fullcopy'][f]
841 del data['fullcopy'][f]
824 data['fullcopy'][of] = f
842 data['fullcopy'][of] = f
825 else: # divergence w.r.t. graft CA on one side of topological CA
843 else: # divergence w.r.t. graft CA on one side of topological CA
826 for sf in seen:
844 for sf in seen:
827 if sf in mb:
845 if sf in mb:
828 assert sf not in data['diverge']
846 assert sf not in data['diverge']
829 data['diverge'][sf] = [f, of]
847 data['diverge'][sf] = [f, of]
830 break
848 break
831 return
849 return
832
850
833 if of in mta:
851 if of in mta:
834 if backwards or remotebase:
852 if backwards or remotebase:
835 data['incomplete'][of] = f
853 data['incomplete'][of] = f
836 else:
854 else:
837 for sf in seen:
855 for sf in seen:
838 if sf in mb:
856 if sf in mb:
839 if tca == base:
857 if tca == base:
840 data['diverge'].setdefault(sf, []).append(f)
858 data['diverge'].setdefault(sf, []).append(f)
841 else:
859 else:
842 data['incompletediverge'][sf] = [of, f]
860 data['incompletediverge'][sf] = [of, f]
843 return
861 return
844
862
845 def duplicatecopies(repo, wctx, rev, fromrev, skiprev=None):
863 def duplicatecopies(repo, wctx, rev, fromrev, skiprev=None):
846 '''reproduce copies from fromrev to rev in the dirstate
864 '''reproduce copies from fromrev to rev in the dirstate
847
865
848 If skiprev is specified, it's a revision that should be used to
866 If skiprev is specified, it's a revision that should be used to
849 filter copy records. Any copies that occur between fromrev and
867 filter copy records. Any copies that occur between fromrev and
850 skiprev will not be duplicated, even if they appear in the set of
868 skiprev will not be duplicated, even if they appear in the set of
851 copies between fromrev and rev.
869 copies between fromrev and rev.
852 '''
870 '''
853 exclude = {}
871 exclude = {}
854 if (skiprev is not None and
872 if (skiprev is not None and
855 repo.ui.config('experimental', 'copytrace') != 'off'):
873 repo.ui.config('experimental', 'copytrace') != 'off'):
856 # copytrace='off' skips this line, but not the entire function because
874 # copytrace='off' skips this line, but not the entire function because
857 # the line below is O(size of the repo) during a rebase, while the rest
875 # the line below is O(size of the repo) during a rebase, while the rest
858 # of the function is much faster (and is required for carrying copy
876 # of the function is much faster (and is required for carrying copy
859 # metadata across the rebase anyway).
877 # metadata across the rebase anyway).
860 exclude = pathcopies(repo[fromrev], repo[skiprev])
878 exclude = pathcopies(repo[fromrev], repo[skiprev])
861 for dst, src in pathcopies(repo[fromrev], repo[rev]).iteritems():
879 for dst, src in pathcopies(repo[fromrev], repo[rev]).iteritems():
862 # copies.pathcopies returns backward renames, so dst might not
880 # copies.pathcopies returns backward renames, so dst might not
863 # actually be in the dirstate
881 # actually be in the dirstate
864 if dst in exclude:
882 if dst in exclude:
865 continue
883 continue
866 wctx[dst].markcopied(src)
884 wctx[dst].markcopied(src)
@@ -1,657 +1,716 b''
1 Test for the heuristic copytracing algorithm
1 Test for the heuristic copytracing algorithm
2 ============================================
2 ============================================
3
3
4 $ cat >> $TESTTMP/copytrace.sh << '__EOF__'
4 $ cat >> $TESTTMP/copytrace.sh << '__EOF__'
5 > initclient() {
5 > initclient() {
6 > cat >> $1/.hg/hgrc <<EOF
6 > cat >> $1/.hg/hgrc <<EOF
7 > [experimental]
7 > [experimental]
8 > copytrace = heuristics
8 > copytrace = heuristics
9 > copytrace.sourcecommitlimit = -1
9 > copytrace.sourcecommitlimit = -1
10 > EOF
10 > EOF
11 > }
11 > }
12 > __EOF__
12 > __EOF__
13 $ . "$TESTTMP/copytrace.sh"
13 $ . "$TESTTMP/copytrace.sh"
14
14
15 $ cat >> $HGRCPATH << EOF
15 $ cat >> $HGRCPATH << EOF
16 > [extensions]
16 > [extensions]
17 > rebase=
17 > rebase=
18 > shelve=
18 > shelve=
19 > EOF
19 > EOF
20
20
21 NOTE: calling initclient() set copytrace.sourcecommitlimit=-1 as we want to
21 NOTE: calling initclient() set copytrace.sourcecommitlimit=-1 as we want to
22 prevent the full copytrace algorithm to run and test the heuristic algorithm
22 prevent the full copytrace algorithm to run and test the heuristic algorithm
23 without complexing the test cases with public and draft commits.
23 without complexing the test cases with public and draft commits.
24
24
25 Check filename heuristics (same dirname and same basename)
25 Check filename heuristics (same dirname and same basename)
26 ----------------------------------------------------------
26 ----------------------------------------------------------
27
27
28 $ hg init repo
28 $ hg init repo
29 $ initclient repo
29 $ initclient repo
30 $ cd repo
30 $ cd repo
31 $ echo a > a
31 $ echo a > a
32 $ mkdir dir
32 $ mkdir dir
33 $ echo a > dir/file.txt
33 $ echo a > dir/file.txt
34 $ hg addremove
34 $ hg addremove
35 adding a
35 adding a
36 adding dir/file.txt
36 adding dir/file.txt
37 $ hg ci -m initial
37 $ hg ci -m initial
38 $ hg mv a b
38 $ hg mv a b
39 $ hg mv -q dir dir2
39 $ hg mv -q dir dir2
40 $ hg ci -m 'mv a b, mv dir/ dir2/'
40 $ hg ci -m 'mv a b, mv dir/ dir2/'
41 $ hg up -q 0
41 $ hg up -q 0
42 $ echo b > a
42 $ echo b > a
43 $ echo b > dir/file.txt
43 $ echo b > dir/file.txt
44 $ hg ci -qm 'mod a, mod dir/file.txt'
44 $ hg ci -qm 'mod a, mod dir/file.txt'
45
45
46 $ hg log -G -T 'changeset: {node}\n desc: {desc}\n'
46 $ hg log -G -T 'changeset: {node}\n desc: {desc}\n'
47 @ changeset: 557f403c0afd2a3cf15d7e2fb1f1001a8b85e081
47 @ changeset: 557f403c0afd2a3cf15d7e2fb1f1001a8b85e081
48 | desc: mod a, mod dir/file.txt
48 | desc: mod a, mod dir/file.txt
49 | o changeset: 928d74bc9110681920854d845c06959f6dfc9547
49 | o changeset: 928d74bc9110681920854d845c06959f6dfc9547
50 |/ desc: mv a b, mv dir/ dir2/
50 |/ desc: mv a b, mv dir/ dir2/
51 o changeset: 3c482b16e54596fed340d05ffaf155f156cda7ee
51 o changeset: 3c482b16e54596fed340d05ffaf155f156cda7ee
52 desc: initial
52 desc: initial
53
53
54 $ hg rebase -s . -d 1
54 $ hg rebase -s . -d 1
55 rebasing 2:557f403c0afd "mod a, mod dir/file.txt" (tip)
55 rebasing 2:557f403c0afd "mod a, mod dir/file.txt" (tip)
56 merging b and a to b
56 merging b and a to b
57 merging dir2/file.txt and dir/file.txt to dir2/file.txt
57 merging dir2/file.txt and dir/file.txt to dir2/file.txt
58 saved backup bundle to $TESTTMP/repo/.hg/strip-backup/557f403c0afd-9926eeff-rebase.hg (glob)
58 saved backup bundle to $TESTTMP/repo/.hg/strip-backup/557f403c0afd-9926eeff-rebase.hg (glob)
59 $ cd ..
59 $ cd ..
60 $ rm -rf repo
60 $ rm -rf repo
61
61
62 Make sure filename heuristics do not when they are not related
62 Make sure filename heuristics do not when they are not related
63 --------------------------------------------------------------
63 --------------------------------------------------------------
64
64
65 $ hg init repo
65 $ hg init repo
66 $ initclient repo
66 $ initclient repo
67 $ cd repo
67 $ cd repo
68 $ echo 'somecontent' > a
68 $ echo 'somecontent' > a
69 $ hg add a
69 $ hg add a
70 $ hg ci -m initial
70 $ hg ci -m initial
71 $ hg rm a
71 $ hg rm a
72 $ echo 'completelydifferentcontext' > b
72 $ echo 'completelydifferentcontext' > b
73 $ hg add b
73 $ hg add b
74 $ hg ci -m 'rm a, add b'
74 $ hg ci -m 'rm a, add b'
75 $ hg up -q 0
75 $ hg up -q 0
76 $ printf 'somecontent\nmoarcontent' > a
76 $ printf 'somecontent\nmoarcontent' > a
77 $ hg ci -qm 'mode a'
77 $ hg ci -qm 'mode a'
78
78
79 $ hg log -G -T 'changeset: {node}\n desc: {desc}\n'
79 $ hg log -G -T 'changeset: {node}\n desc: {desc}\n'
80 @ changeset: d526312210b9e8f795d576a77dc643796384d86e
80 @ changeset: d526312210b9e8f795d576a77dc643796384d86e
81 | desc: mode a
81 | desc: mode a
82 | o changeset: 46985f76c7e5e5123433527f5c8526806145650b
82 | o changeset: 46985f76c7e5e5123433527f5c8526806145650b
83 |/ desc: rm a, add b
83 |/ desc: rm a, add b
84 o changeset: e5b71fb099c29d9172ef4a23485aaffd497e4cc0
84 o changeset: e5b71fb099c29d9172ef4a23485aaffd497e4cc0
85 desc: initial
85 desc: initial
86
86
87 $ hg rebase -s . -d 1
87 $ hg rebase -s . -d 1
88 rebasing 2:d526312210b9 "mode a" (tip)
88 rebasing 2:d526312210b9 "mode a" (tip)
89 other [source] changed a which local [dest] deleted
89 other [source] changed a which local [dest] deleted
90 use (c)hanged version, leave (d)eleted, or leave (u)nresolved? u
90 use (c)hanged version, leave (d)eleted, or leave (u)nresolved? u
91 unresolved conflicts (see hg resolve, then hg rebase --continue)
91 unresolved conflicts (see hg resolve, then hg rebase --continue)
92 [1]
92 [1]
93
93
94 $ cd ..
94 $ cd ..
95 $ rm -rf repo
95 $ rm -rf repo
96
96
97 Test when lca didn't modified the file that was moved
97 Test when lca didn't modified the file that was moved
98 -----------------------------------------------------
98 -----------------------------------------------------
99
99
100 $ hg init repo
100 $ hg init repo
101 $ initclient repo
101 $ initclient repo
102 $ cd repo
102 $ cd repo
103 $ echo 'somecontent' > a
103 $ echo 'somecontent' > a
104 $ hg add a
104 $ hg add a
105 $ hg ci -m initial
105 $ hg ci -m initial
106 $ echo c > c
106 $ echo c > c
107 $ hg add c
107 $ hg add c
108 $ hg ci -m randomcommit
108 $ hg ci -m randomcommit
109 $ hg mv a b
109 $ hg mv a b
110 $ hg ci -m 'mv a b'
110 $ hg ci -m 'mv a b'
111 $ hg up -q 1
111 $ hg up -q 1
112 $ echo b > a
112 $ echo b > a
113 $ hg ci -qm 'mod a'
113 $ hg ci -qm 'mod a'
114
114
115 $ hg log -G -T 'changeset: {node}\n desc: {desc}, phase: {phase}\n'
115 $ hg log -G -T 'changeset: {node}\n desc: {desc}, phase: {phase}\n'
116 @ changeset: 9d5cf99c3d9f8e8b05ba55421f7f56530cfcf3bc
116 @ changeset: 9d5cf99c3d9f8e8b05ba55421f7f56530cfcf3bc
117 | desc: mod a, phase: draft
117 | desc: mod a, phase: draft
118 | o changeset: d760186dd240fc47b91eb9f0b58b0002aaeef95d
118 | o changeset: d760186dd240fc47b91eb9f0b58b0002aaeef95d
119 |/ desc: mv a b, phase: draft
119 |/ desc: mv a b, phase: draft
120 o changeset: 48e1b6ba639d5d7fb313fa7989eebabf99c9eb83
120 o changeset: 48e1b6ba639d5d7fb313fa7989eebabf99c9eb83
121 | desc: randomcommit, phase: draft
121 | desc: randomcommit, phase: draft
122 o changeset: e5b71fb099c29d9172ef4a23485aaffd497e4cc0
122 o changeset: e5b71fb099c29d9172ef4a23485aaffd497e4cc0
123 desc: initial, phase: draft
123 desc: initial, phase: draft
124
124
125 $ hg rebase -s . -d 2
125 $ hg rebase -s . -d 2
126 rebasing 3:9d5cf99c3d9f "mod a" (tip)
126 rebasing 3:9d5cf99c3d9f "mod a" (tip)
127 merging b and a to b
127 merging b and a to b
128 saved backup bundle to $TESTTMP/repo/.hg/strip-backup/9d5cf99c3d9f-f02358cc-rebase.hg (glob)
128 saved backup bundle to $TESTTMP/repo/.hg/strip-backup/9d5cf99c3d9f-f02358cc-rebase.hg (glob)
129 $ cd ..
129 $ cd ..
130 $ rm -rf repo
130 $ rm -rf repo
131
131
132 Rebase "backwards"
132 Rebase "backwards"
133 ------------------
133 ------------------
134
134
135 $ hg init repo
135 $ hg init repo
136 $ initclient repo
136 $ initclient repo
137 $ cd repo
137 $ cd repo
138 $ echo 'somecontent' > a
138 $ echo 'somecontent' > a
139 $ hg add a
139 $ hg add a
140 $ hg ci -m initial
140 $ hg ci -m initial
141 $ echo c > c
141 $ echo c > c
142 $ hg add c
142 $ hg add c
143 $ hg ci -m randomcommit
143 $ hg ci -m randomcommit
144 $ hg mv a b
144 $ hg mv a b
145 $ hg ci -m 'mv a b'
145 $ hg ci -m 'mv a b'
146 $ hg up -q 2
146 $ hg up -q 2
147 $ echo b > b
147 $ echo b > b
148 $ hg ci -qm 'mod b'
148 $ hg ci -qm 'mod b'
149
149
150 $ hg log -G -T 'changeset: {node}\n desc: {desc}\n'
150 $ hg log -G -T 'changeset: {node}\n desc: {desc}\n'
151 @ changeset: fbe97126b3969056795c462a67d93faf13e4d298
151 @ changeset: fbe97126b3969056795c462a67d93faf13e4d298
152 | desc: mod b
152 | desc: mod b
153 o changeset: d760186dd240fc47b91eb9f0b58b0002aaeef95d
153 o changeset: d760186dd240fc47b91eb9f0b58b0002aaeef95d
154 | desc: mv a b
154 | desc: mv a b
155 o changeset: 48e1b6ba639d5d7fb313fa7989eebabf99c9eb83
155 o changeset: 48e1b6ba639d5d7fb313fa7989eebabf99c9eb83
156 | desc: randomcommit
156 | desc: randomcommit
157 o changeset: e5b71fb099c29d9172ef4a23485aaffd497e4cc0
157 o changeset: e5b71fb099c29d9172ef4a23485aaffd497e4cc0
158 desc: initial
158 desc: initial
159
159
160 $ hg rebase -s . -d 0
160 $ hg rebase -s . -d 0
161 rebasing 3:fbe97126b396 "mod b" (tip)
161 rebasing 3:fbe97126b396 "mod b" (tip)
162 merging a and b to a
162 merging a and b to a
163 saved backup bundle to $TESTTMP/repo/.hg/strip-backup/fbe97126b396-cf5452a1-rebase.hg (glob)
163 saved backup bundle to $TESTTMP/repo/.hg/strip-backup/fbe97126b396-cf5452a1-rebase.hg (glob)
164 $ cd ..
164 $ cd ..
165 $ rm -rf repo
165 $ rm -rf repo
166
166
167 Check a few potential move candidates
167 Check a few potential move candidates
168 -------------------------------------
168 -------------------------------------
169
169
170 $ hg init repo
170 $ hg init repo
171 $ initclient repo
171 $ initclient repo
172 $ cd repo
172 $ cd repo
173 $ mkdir dir
173 $ mkdir dir
174 $ echo a > dir/a
174 $ echo a > dir/a
175 $ hg add dir/a
175 $ hg add dir/a
176 $ hg ci -qm initial
176 $ hg ci -qm initial
177 $ hg mv dir/a dir/b
177 $ hg mv dir/a dir/b
178 $ hg ci -qm 'mv dir/a dir/b'
178 $ hg ci -qm 'mv dir/a dir/b'
179 $ mkdir dir2
179 $ mkdir dir2
180 $ echo b > dir2/a
180 $ echo b > dir2/a
181 $ hg add dir2/a
181 $ hg add dir2/a
182 $ hg ci -qm 'create dir2/a'
182 $ hg ci -qm 'create dir2/a'
183 $ hg up -q 0
183 $ hg up -q 0
184 $ echo b > dir/a
184 $ echo b > dir/a
185 $ hg ci -qm 'mod dir/a'
185 $ hg ci -qm 'mod dir/a'
186
186
187 $ hg log -G -T 'changeset: {node}\n desc: {desc}\n'
187 $ hg log -G -T 'changeset: {node}\n desc: {desc}\n'
188 @ changeset: 6b2f4cece40fd320f41229f23821256ffc08efea
188 @ changeset: 6b2f4cece40fd320f41229f23821256ffc08efea
189 | desc: mod dir/a
189 | desc: mod dir/a
190 | o changeset: 4494bf7efd2e0dfdd388e767fb913a8a3731e3fa
190 | o changeset: 4494bf7efd2e0dfdd388e767fb913a8a3731e3fa
191 | | desc: create dir2/a
191 | | desc: create dir2/a
192 | o changeset: b1784dfab6ea6bfafeb11c0ac50a2981b0fe6ade
192 | o changeset: b1784dfab6ea6bfafeb11c0ac50a2981b0fe6ade
193 |/ desc: mv dir/a dir/b
193 |/ desc: mv dir/a dir/b
194 o changeset: 36859b8907c513a3a87ae34ba5b1e7eea8c20944
194 o changeset: 36859b8907c513a3a87ae34ba5b1e7eea8c20944
195 desc: initial
195 desc: initial
196
196
197 $ hg rebase -s . -d 2
197 $ hg rebase -s . -d 2
198 rebasing 3:6b2f4cece40f "mod dir/a" (tip)
198 rebasing 3:6b2f4cece40f "mod dir/a" (tip)
199 merging dir/b and dir/a to dir/b
199 merging dir/b and dir/a to dir/b
200 saved backup bundle to $TESTTMP/repo/.hg/strip-backup/6b2f4cece40f-503efe60-rebase.hg (glob)
200 saved backup bundle to $TESTTMP/repo/.hg/strip-backup/6b2f4cece40f-503efe60-rebase.hg (glob)
201 $ cd ..
201 $ cd ..
202 $ rm -rf repo
202 $ rm -rf repo
203
203
204 Test the copytrace.movecandidateslimit with many move candidates
205 ----------------------------------------------------------------
206
207 $ hg init repo
208 $ initclient repo
209 $ cd repo
210 $ echo a > a
211 $ hg add a
212 $ hg ci -m initial
213 $ hg mv a foo
214 $ echo a > b
215 $ echo a > c
216 $ echo a > d
217 $ echo a > e
218 $ echo a > f
219 $ echo a > g
220 $ hg add b
221 $ hg add c
222 $ hg add d
223 $ hg add e
224 $ hg add f
225 $ hg add g
226 $ hg ci -m 'mv a foo, add many files'
227 $ hg up -q ".^"
228 $ echo b > a
229 $ hg ci -m 'mod a'
230 created new head
231
232 $ hg log -G -T 'changeset: {node}\n desc: {desc}\n'
233 @ changeset: ef716627c70bf4ca0bdb623cfb0d6fe5b9acc51e
234 | desc: mod a
235 | o changeset: 8329d5c6bf479ec5ca59b9864f3f45d07213f5a4
236 |/ desc: mv a foo, add many files
237 o changeset: 1451231c87572a7d3f92fc210b4b35711c949a98
238 desc: initial
239
240 With small limit
241
242 $ hg rebase -s 2 -d 1 --config experimental.copytrace.movecandidateslimit=0
243 rebasing 2:ef716627c70b "mod a" (tip)
244 skipping copytracing for 'a', more candidates than the limit: 7
245 other [source] changed a which local [dest] deleted
246 use (c)hanged version, leave (d)eleted, or leave (u)nresolved? u
247 unresolved conflicts (see hg resolve, then hg rebase --continue)
248 [1]
249
250 $ hg rebase --abort
251 rebase aborted
252
253 With default limit which is 100
254
255 $ hg rebase -s 2 -d 1
256 rebasing 2:ef716627c70b "mod a" (tip)
257 merging foo and a to foo
258 saved backup bundle to $TESTTMP/repo/.hg/strip-backup/ef716627c70b-24681561-rebase.hg (glob)
259
260 $ cd ..
261 $ rm -rf repo
262
204 Move file in one branch and delete it in another
263 Move file in one branch and delete it in another
205 -----------------------------------------------
264 -----------------------------------------------
206
265
207 $ hg init repo
266 $ hg init repo
208 $ initclient repo
267 $ initclient repo
209 $ cd repo
268 $ cd repo
210 $ echo a > a
269 $ echo a > a
211 $ hg add a
270 $ hg add a
212 $ hg ci -m initial
271 $ hg ci -m initial
213 $ hg mv a b
272 $ hg mv a b
214 $ hg ci -m 'mv a b'
273 $ hg ci -m 'mv a b'
215 $ hg up -q ".^"
274 $ hg up -q ".^"
216 $ hg rm a
275 $ hg rm a
217 $ hg ci -m 'del a'
276 $ hg ci -m 'del a'
218 created new head
277 created new head
219
278
220 $ hg log -G -T 'changeset: {node}\n desc: {desc}, phase: {phase}\n'
279 $ hg log -G -T 'changeset: {node}\n desc: {desc}, phase: {phase}\n'
221 @ changeset: 7d61ee3b1e48577891a072024968428ba465c47b
280 @ changeset: 7d61ee3b1e48577891a072024968428ba465c47b
222 | desc: del a, phase: draft
281 | desc: del a, phase: draft
223 | o changeset: 472e38d57782172f6c6abed82a94ca0d998c3a22
282 | o changeset: 472e38d57782172f6c6abed82a94ca0d998c3a22
224 |/ desc: mv a b, phase: draft
283 |/ desc: mv a b, phase: draft
225 o changeset: 1451231c87572a7d3f92fc210b4b35711c949a98
284 o changeset: 1451231c87572a7d3f92fc210b4b35711c949a98
226 desc: initial, phase: draft
285 desc: initial, phase: draft
227
286
228 $ hg rebase -s 1 -d 2
287 $ hg rebase -s 1 -d 2
229 rebasing 1:472e38d57782 "mv a b"
288 rebasing 1:472e38d57782 "mv a b"
230 saved backup bundle to $TESTTMP/repo/.hg/strip-backup/472e38d57782-17d50e29-rebase.hg (glob)
289 saved backup bundle to $TESTTMP/repo/.hg/strip-backup/472e38d57782-17d50e29-rebase.hg (glob)
231 $ hg up -q c492ed3c7e35dcd1dc938053b8adf56e2cfbd062
290 $ hg up -q c492ed3c7e35dcd1dc938053b8adf56e2cfbd062
232 $ ls
291 $ ls
233 b
292 b
234 $ cd ..
293 $ cd ..
235 $ rm -rf repo
294 $ rm -rf repo
236
295
237 Move a directory in draft branch
296 Move a directory in draft branch
238 --------------------------------
297 --------------------------------
239
298
240 $ hg init repo
299 $ hg init repo
241 $ initclient repo
300 $ initclient repo
242 $ cd repo
301 $ cd repo
243 $ mkdir dir
302 $ mkdir dir
244 $ echo a > dir/a
303 $ echo a > dir/a
245 $ hg add dir/a
304 $ hg add dir/a
246 $ hg ci -qm initial
305 $ hg ci -qm initial
247 $ echo b > dir/a
306 $ echo b > dir/a
248 $ hg ci -qm 'mod dir/a'
307 $ hg ci -qm 'mod dir/a'
249 $ hg up -q ".^"
308 $ hg up -q ".^"
250 $ hg mv -q dir/ dir2
309 $ hg mv -q dir/ dir2
251 $ hg ci -qm 'mv dir/ dir2/'
310 $ hg ci -qm 'mv dir/ dir2/'
252
311
253 $ hg log -G -T 'changeset: {node}\n desc: {desc}\n'
312 $ hg log -G -T 'changeset: {node}\n desc: {desc}\n'
254 @ changeset: a33d80b6e352591dfd82784e1ad6cdd86b25a239
313 @ changeset: a33d80b6e352591dfd82784e1ad6cdd86b25a239
255 | desc: mv dir/ dir2/
314 | desc: mv dir/ dir2/
256 | o changeset: 6b2f4cece40fd320f41229f23821256ffc08efea
315 | o changeset: 6b2f4cece40fd320f41229f23821256ffc08efea
257 |/ desc: mod dir/a
316 |/ desc: mod dir/a
258 o changeset: 36859b8907c513a3a87ae34ba5b1e7eea8c20944
317 o changeset: 36859b8907c513a3a87ae34ba5b1e7eea8c20944
259 desc: initial
318 desc: initial
260
319
261 $ hg rebase -s . -d 1
320 $ hg rebase -s . -d 1
262 rebasing 2:a33d80b6e352 "mv dir/ dir2/" (tip)
321 rebasing 2:a33d80b6e352 "mv dir/ dir2/" (tip)
263 merging dir/a and dir2/a to dir2/a
322 merging dir/a and dir2/a to dir2/a
264 saved backup bundle to $TESTTMP/repo/.hg/strip-backup/a33d80b6e352-fecb9ada-rebase.hg (glob)
323 saved backup bundle to $TESTTMP/repo/.hg/strip-backup/a33d80b6e352-fecb9ada-rebase.hg (glob)
265 $ cd ..
324 $ cd ..
266 $ rm -rf server
325 $ rm -rf server
267 $ rm -rf repo
326 $ rm -rf repo
268
327
269 Move file twice and rebase mod on top of moves
328 Move file twice and rebase mod on top of moves
270 ----------------------------------------------
329 ----------------------------------------------
271
330
272 $ hg init repo
331 $ hg init repo
273 $ initclient repo
332 $ initclient repo
274 $ cd repo
333 $ cd repo
275 $ echo a > a
334 $ echo a > a
276 $ hg add a
335 $ hg add a
277 $ hg ci -m initial
336 $ hg ci -m initial
278 $ hg mv a b
337 $ hg mv a b
279 $ hg ci -m 'mv a b'
338 $ hg ci -m 'mv a b'
280 $ hg mv b c
339 $ hg mv b c
281 $ hg ci -m 'mv b c'
340 $ hg ci -m 'mv b c'
282 $ hg up -q 0
341 $ hg up -q 0
283 $ echo c > a
342 $ echo c > a
284 $ hg ci -m 'mod a'
343 $ hg ci -m 'mod a'
285 created new head
344 created new head
286
345
287 $ hg log -G -T 'changeset: {node}\n desc: {desc}\n'
346 $ hg log -G -T 'changeset: {node}\n desc: {desc}\n'
288 @ changeset: d413169422167a3fa5275fc5d71f7dea9f5775f3
347 @ changeset: d413169422167a3fa5275fc5d71f7dea9f5775f3
289 | desc: mod a
348 | desc: mod a
290 | o changeset: d3efd280421d24f9f229997c19e654761c942a71
349 | o changeset: d3efd280421d24f9f229997c19e654761c942a71
291 | | desc: mv b c
350 | | desc: mv b c
292 | o changeset: 472e38d57782172f6c6abed82a94ca0d998c3a22
351 | o changeset: 472e38d57782172f6c6abed82a94ca0d998c3a22
293 |/ desc: mv a b
352 |/ desc: mv a b
294 o changeset: 1451231c87572a7d3f92fc210b4b35711c949a98
353 o changeset: 1451231c87572a7d3f92fc210b4b35711c949a98
295 desc: initial
354 desc: initial
296 $ hg rebase -s . -d 2
355 $ hg rebase -s . -d 2
297 rebasing 3:d41316942216 "mod a" (tip)
356 rebasing 3:d41316942216 "mod a" (tip)
298 merging c and a to c
357 merging c and a to c
299 saved backup bundle to $TESTTMP/repo/.hg/strip-backup/d41316942216-2b5949bc-rebase.hg (glob)
358 saved backup bundle to $TESTTMP/repo/.hg/strip-backup/d41316942216-2b5949bc-rebase.hg (glob)
300
359
301 $ cd ..
360 $ cd ..
302 $ rm -rf repo
361 $ rm -rf repo
303
362
304 Move file twice and rebase moves on top of mods
363 Move file twice and rebase moves on top of mods
305 -----------------------------------------------
364 -----------------------------------------------
306
365
307 $ hg init repo
366 $ hg init repo
308 $ initclient repo
367 $ initclient repo
309 $ cd repo
368 $ cd repo
310 $ echo a > a
369 $ echo a > a
311 $ hg add a
370 $ hg add a
312 $ hg ci -m initial
371 $ hg ci -m initial
313 $ hg mv a b
372 $ hg mv a b
314 $ hg ci -m 'mv a b'
373 $ hg ci -m 'mv a b'
315 $ hg mv b c
374 $ hg mv b c
316 $ hg ci -m 'mv b c'
375 $ hg ci -m 'mv b c'
317 $ hg up -q 0
376 $ hg up -q 0
318 $ echo c > a
377 $ echo c > a
319 $ hg ci -m 'mod a'
378 $ hg ci -m 'mod a'
320 created new head
379 created new head
321 $ hg log -G -T 'changeset: {node}\n desc: {desc}\n'
380 $ hg log -G -T 'changeset: {node}\n desc: {desc}\n'
322 @ changeset: d413169422167a3fa5275fc5d71f7dea9f5775f3
381 @ changeset: d413169422167a3fa5275fc5d71f7dea9f5775f3
323 | desc: mod a
382 | desc: mod a
324 | o changeset: d3efd280421d24f9f229997c19e654761c942a71
383 | o changeset: d3efd280421d24f9f229997c19e654761c942a71
325 | | desc: mv b c
384 | | desc: mv b c
326 | o changeset: 472e38d57782172f6c6abed82a94ca0d998c3a22
385 | o changeset: 472e38d57782172f6c6abed82a94ca0d998c3a22
327 |/ desc: mv a b
386 |/ desc: mv a b
328 o changeset: 1451231c87572a7d3f92fc210b4b35711c949a98
387 o changeset: 1451231c87572a7d3f92fc210b4b35711c949a98
329 desc: initial
388 desc: initial
330 $ hg rebase -s 1 -d .
389 $ hg rebase -s 1 -d .
331 rebasing 1:472e38d57782 "mv a b"
390 rebasing 1:472e38d57782 "mv a b"
332 merging a and b to b
391 merging a and b to b
333 rebasing 2:d3efd280421d "mv b c"
392 rebasing 2:d3efd280421d "mv b c"
334 merging b and c to c
393 merging b and c to c
335 saved backup bundle to $TESTTMP/repo/.hg/strip-backup/472e38d57782-ab8d3c58-rebase.hg (glob)
394 saved backup bundle to $TESTTMP/repo/.hg/strip-backup/472e38d57782-ab8d3c58-rebase.hg (glob)
336
395
337 $ cd ..
396 $ cd ..
338 $ rm -rf repo
397 $ rm -rf repo
339
398
340 Move one file and add another file in the same folder in one branch, modify file in another branch
399 Move one file and add another file in the same folder in one branch, modify file in another branch
341 --------------------------------------------------------------------------------------------------
400 --------------------------------------------------------------------------------------------------
342
401
343 $ hg init repo
402 $ hg init repo
344 $ initclient repo
403 $ initclient repo
345 $ cd repo
404 $ cd repo
346 $ echo a > a
405 $ echo a > a
347 $ hg add a
406 $ hg add a
348 $ hg ci -m initial
407 $ hg ci -m initial
349 $ hg mv a b
408 $ hg mv a b
350 $ hg ci -m 'mv a b'
409 $ hg ci -m 'mv a b'
351 $ echo c > c
410 $ echo c > c
352 $ hg add c
411 $ hg add c
353 $ hg ci -m 'add c'
412 $ hg ci -m 'add c'
354 $ hg up -q 0
413 $ hg up -q 0
355 $ echo b > a
414 $ echo b > a
356 $ hg ci -m 'mod a'
415 $ hg ci -m 'mod a'
357 created new head
416 created new head
358
417
359 $ hg log -G -T 'changeset: {node}\n desc: {desc}\n'
418 $ hg log -G -T 'changeset: {node}\n desc: {desc}\n'
360 @ changeset: ef716627c70bf4ca0bdb623cfb0d6fe5b9acc51e
419 @ changeset: ef716627c70bf4ca0bdb623cfb0d6fe5b9acc51e
361 | desc: mod a
420 | desc: mod a
362 | o changeset: b1a6187e79fbce851bb584eadcb0cc4a80290fd9
421 | o changeset: b1a6187e79fbce851bb584eadcb0cc4a80290fd9
363 | | desc: add c
422 | | desc: add c
364 | o changeset: 472e38d57782172f6c6abed82a94ca0d998c3a22
423 | o changeset: 472e38d57782172f6c6abed82a94ca0d998c3a22
365 |/ desc: mv a b
424 |/ desc: mv a b
366 o changeset: 1451231c87572a7d3f92fc210b4b35711c949a98
425 o changeset: 1451231c87572a7d3f92fc210b4b35711c949a98
367 desc: initial
426 desc: initial
368
427
369 $ hg rebase -s . -d 2
428 $ hg rebase -s . -d 2
370 rebasing 3:ef716627c70b "mod a" (tip)
429 rebasing 3:ef716627c70b "mod a" (tip)
371 merging b and a to b
430 merging b and a to b
372 saved backup bundle to $TESTTMP/repo/.hg/strip-backup/ef716627c70b-24681561-rebase.hg (glob)
431 saved backup bundle to $TESTTMP/repo/.hg/strip-backup/ef716627c70b-24681561-rebase.hg (glob)
373 $ ls
432 $ ls
374 b
433 b
375 c
434 c
376 $ cat b
435 $ cat b
377 b
436 b
378 $ rm -rf repo
437 $ rm -rf repo
379
438
380 Merge test
439 Merge test
381 ----------
440 ----------
382
441
383 $ hg init repo
442 $ hg init repo
384 $ initclient repo
443 $ initclient repo
385 $ cd repo
444 $ cd repo
386 $ echo a > a
445 $ echo a > a
387 $ hg add a
446 $ hg add a
388 $ hg ci -m initial
447 $ hg ci -m initial
389 $ echo b > a
448 $ echo b > a
390 $ hg ci -m 'modify a'
449 $ hg ci -m 'modify a'
391 $ hg up -q 0
450 $ hg up -q 0
392 $ hg mv a b
451 $ hg mv a b
393 $ hg ci -m 'mv a b'
452 $ hg ci -m 'mv a b'
394 created new head
453 created new head
395 $ hg up -q 2
454 $ hg up -q 2
396
455
397 $ hg log -G -T 'changeset: {node}\n desc: {desc}\n'
456 $ hg log -G -T 'changeset: {node}\n desc: {desc}\n'
398 @ changeset: 472e38d57782172f6c6abed82a94ca0d998c3a22
457 @ changeset: 472e38d57782172f6c6abed82a94ca0d998c3a22
399 | desc: mv a b
458 | desc: mv a b
400 | o changeset: b0357b07f79129a3d08a68621271ca1352ae8a09
459 | o changeset: b0357b07f79129a3d08a68621271ca1352ae8a09
401 |/ desc: modify a
460 |/ desc: modify a
402 o changeset: 1451231c87572a7d3f92fc210b4b35711c949a98
461 o changeset: 1451231c87572a7d3f92fc210b4b35711c949a98
403 desc: initial
462 desc: initial
404
463
405 $ hg merge 1
464 $ hg merge 1
406 merging b and a to b
465 merging b and a to b
407 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
466 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
408 (branch merge, don't forget to commit)
467 (branch merge, don't forget to commit)
409 $ hg ci -m merge
468 $ hg ci -m merge
410 $ ls
469 $ ls
411 b
470 b
412 $ cd ..
471 $ cd ..
413 $ rm -rf repo
472 $ rm -rf repo
414
473
415 Copy and move file
474 Copy and move file
416 ------------------
475 ------------------
417
476
418 $ hg init repo
477 $ hg init repo
419 $ initclient repo
478 $ initclient repo
420 $ cd repo
479 $ cd repo
421 $ echo a > a
480 $ echo a > a
422 $ hg add a
481 $ hg add a
423 $ hg ci -m initial
482 $ hg ci -m initial
424 $ hg cp a c
483 $ hg cp a c
425 $ hg mv a b
484 $ hg mv a b
426 $ hg ci -m 'cp a c, mv a b'
485 $ hg ci -m 'cp a c, mv a b'
427 $ hg up -q 0
486 $ hg up -q 0
428 $ echo b > a
487 $ echo b > a
429 $ hg ci -m 'mod a'
488 $ hg ci -m 'mod a'
430 created new head
489 created new head
431
490
432 $ hg log -G -T 'changeset: {node}\n desc: {desc}\n'
491 $ hg log -G -T 'changeset: {node}\n desc: {desc}\n'
433 @ changeset: ef716627c70bf4ca0bdb623cfb0d6fe5b9acc51e
492 @ changeset: ef716627c70bf4ca0bdb623cfb0d6fe5b9acc51e
434 | desc: mod a
493 | desc: mod a
435 | o changeset: 4fc3fd13fbdb89ada6b75bfcef3911a689a0dde8
494 | o changeset: 4fc3fd13fbdb89ada6b75bfcef3911a689a0dde8
436 |/ desc: cp a c, mv a b
495 |/ desc: cp a c, mv a b
437 o changeset: 1451231c87572a7d3f92fc210b4b35711c949a98
496 o changeset: 1451231c87572a7d3f92fc210b4b35711c949a98
438 desc: initial
497 desc: initial
439
498
440 $ hg rebase -s . -d 1
499 $ hg rebase -s . -d 1
441 rebasing 2:ef716627c70b "mod a" (tip)
500 rebasing 2:ef716627c70b "mod a" (tip)
442 merging b and a to b
501 merging b and a to b
443 merging c and a to c
502 merging c and a to c
444 saved backup bundle to $TESTTMP/repo/repo/.hg/strip-backup/ef716627c70b-24681561-rebase.hg (glob)
503 saved backup bundle to $TESTTMP/repo/repo/.hg/strip-backup/ef716627c70b-24681561-rebase.hg (glob)
445 $ ls
504 $ ls
446 b
505 b
447 c
506 c
448 $ cat b
507 $ cat b
449 b
508 b
450 $ cat c
509 $ cat c
451 b
510 b
452 $ cd ..
511 $ cd ..
453 $ rm -rf repo
512 $ rm -rf repo
454
513
455 Do a merge commit with many consequent moves in one branch
514 Do a merge commit with many consequent moves in one branch
456 ----------------------------------------------------------
515 ----------------------------------------------------------
457
516
458 $ hg init repo
517 $ hg init repo
459 $ initclient repo
518 $ initclient repo
460 $ cd repo
519 $ cd repo
461 $ echo a > a
520 $ echo a > a
462 $ hg add a
521 $ hg add a
463 $ hg ci -m initial
522 $ hg ci -m initial
464 $ echo b > a
523 $ echo b > a
465 $ hg ci -qm 'mod a'
524 $ hg ci -qm 'mod a'
466 $ hg up -q ".^"
525 $ hg up -q ".^"
467 $ hg mv a b
526 $ hg mv a b
468 $ hg ci -qm 'mv a b'
527 $ hg ci -qm 'mv a b'
469 $ hg mv b c
528 $ hg mv b c
470 $ hg ci -qm 'mv b c'
529 $ hg ci -qm 'mv b c'
471 $ hg up -q 1
530 $ hg up -q 1
472 $ hg log -G -T 'changeset: {node}\n desc: {desc}\n'
531 $ hg log -G -T 'changeset: {node}\n desc: {desc}\n'
473 o changeset: d3efd280421d24f9f229997c19e654761c942a71
532 o changeset: d3efd280421d24f9f229997c19e654761c942a71
474 | desc: mv b c
533 | desc: mv b c
475 o changeset: 472e38d57782172f6c6abed82a94ca0d998c3a22
534 o changeset: 472e38d57782172f6c6abed82a94ca0d998c3a22
476 | desc: mv a b
535 | desc: mv a b
477 | @ changeset: ef716627c70bf4ca0bdb623cfb0d6fe5b9acc51e
536 | @ changeset: ef716627c70bf4ca0bdb623cfb0d6fe5b9acc51e
478 |/ desc: mod a
537 |/ desc: mod a
479 o changeset: 1451231c87572a7d3f92fc210b4b35711c949a98
538 o changeset: 1451231c87572a7d3f92fc210b4b35711c949a98
480 desc: initial
539 desc: initial
481
540
482 $ hg merge 3
541 $ hg merge 3
483 merging a and c to c
542 merging a and c to c
484 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
543 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
485 (branch merge, don't forget to commit)
544 (branch merge, don't forget to commit)
486 $ hg ci -qm 'merge'
545 $ hg ci -qm 'merge'
487 $ hg log -G -T 'changeset: {node}\n desc: {desc}, phase: {phase}\n'
546 $ hg log -G -T 'changeset: {node}\n desc: {desc}, phase: {phase}\n'
488 @ changeset: cd29b0d08c0f39bfed4cde1b40e30f419db0c825
547 @ changeset: cd29b0d08c0f39bfed4cde1b40e30f419db0c825
489 |\ desc: merge, phase: draft
548 |\ desc: merge, phase: draft
490 | o changeset: d3efd280421d24f9f229997c19e654761c942a71
549 | o changeset: d3efd280421d24f9f229997c19e654761c942a71
491 | | desc: mv b c, phase: draft
550 | | desc: mv b c, phase: draft
492 | o changeset: 472e38d57782172f6c6abed82a94ca0d998c3a22
551 | o changeset: 472e38d57782172f6c6abed82a94ca0d998c3a22
493 | | desc: mv a b, phase: draft
552 | | desc: mv a b, phase: draft
494 o | changeset: ef716627c70bf4ca0bdb623cfb0d6fe5b9acc51e
553 o | changeset: ef716627c70bf4ca0bdb623cfb0d6fe5b9acc51e
495 |/ desc: mod a, phase: draft
554 |/ desc: mod a, phase: draft
496 o changeset: 1451231c87572a7d3f92fc210b4b35711c949a98
555 o changeset: 1451231c87572a7d3f92fc210b4b35711c949a98
497 desc: initial, phase: draft
556 desc: initial, phase: draft
498 $ ls
557 $ ls
499 c
558 c
500 $ cd ..
559 $ cd ..
501 $ rm -rf repo
560 $ rm -rf repo
502
561
503 Test shelve/unshelve
562 Test shelve/unshelve
504 -------------------
563 -------------------
505
564
506 $ hg init repo
565 $ hg init repo
507 $ initclient repo
566 $ initclient repo
508 $ cd repo
567 $ cd repo
509 $ echo a > a
568 $ echo a > a
510 $ hg add a
569 $ hg add a
511 $ hg ci -m initial
570 $ hg ci -m initial
512 $ echo b > a
571 $ echo b > a
513 $ hg shelve
572 $ hg shelve
514 shelved as default
573 shelved as default
515 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
574 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
516 $ hg mv a b
575 $ hg mv a b
517 $ hg ci -m 'mv a b'
576 $ hg ci -m 'mv a b'
518
577
519 $ hg log -G -T 'changeset: {node}\n desc: {desc}\n'
578 $ hg log -G -T 'changeset: {node}\n desc: {desc}\n'
520 @ changeset: 472e38d57782172f6c6abed82a94ca0d998c3a22
579 @ changeset: 472e38d57782172f6c6abed82a94ca0d998c3a22
521 | desc: mv a b
580 | desc: mv a b
522 o changeset: 1451231c87572a7d3f92fc210b4b35711c949a98
581 o changeset: 1451231c87572a7d3f92fc210b4b35711c949a98
523 desc: initial
582 desc: initial
524 $ hg unshelve
583 $ hg unshelve
525 unshelving change 'default'
584 unshelving change 'default'
526 rebasing shelved changes
585 rebasing shelved changes
527 rebasing 2:45f63161acea "changes to: initial" (tip)
586 rebasing 2:45f63161acea "changes to: initial" (tip)
528 merging b and a to b
587 merging b and a to b
529 $ ls
588 $ ls
530 b
589 b
531 $ cat b
590 $ cat b
532 b
591 b
533 $ cd ..
592 $ cd ..
534 $ rm -rf repo
593 $ rm -rf repo
535
594
536 Test full copytrace ability on draft branch
595 Test full copytrace ability on draft branch
537 -------------------------------------------
596 -------------------------------------------
538
597
539 File directory and base name changed in same move
598 File directory and base name changed in same move
540 $ hg init repo
599 $ hg init repo
541 $ initclient repo
600 $ initclient repo
542 $ mkdir repo/dir1
601 $ mkdir repo/dir1
543 $ cd repo/dir1
602 $ cd repo/dir1
544 $ echo a > a
603 $ echo a > a
545 $ hg add a
604 $ hg add a
546 $ hg ci -qm initial
605 $ hg ci -qm initial
547 $ cd ..
606 $ cd ..
548 $ hg mv -q dir1 dir2
607 $ hg mv -q dir1 dir2
549 $ hg mv dir2/a dir2/b
608 $ hg mv dir2/a dir2/b
550 $ hg ci -qm 'mv a b; mv dir1 dir2'
609 $ hg ci -qm 'mv a b; mv dir1 dir2'
551 $ hg up -q '.^'
610 $ hg up -q '.^'
552 $ cd dir1
611 $ cd dir1
553 $ echo b >> a
612 $ echo b >> a
554 $ cd ..
613 $ cd ..
555 $ hg ci -qm 'mod a'
614 $ hg ci -qm 'mod a'
556
615
557 $ hg log -G -T 'changeset {node}\n desc {desc}, phase: {phase}\n'
616 $ hg log -G -T 'changeset {node}\n desc {desc}, phase: {phase}\n'
558 @ changeset 6207d2d318e710b882e3d5ada2a89770efc42c96
617 @ changeset 6207d2d318e710b882e3d5ada2a89770efc42c96
559 | desc mod a, phase: draft
618 | desc mod a, phase: draft
560 | o changeset abffdd4e3dfc04bc375034b970299b2a309a1cce
619 | o changeset abffdd4e3dfc04bc375034b970299b2a309a1cce
561 |/ desc mv a b; mv dir1 dir2, phase: draft
620 |/ desc mv a b; mv dir1 dir2, phase: draft
562 o changeset 81973cd24b58db2fdf18ce3d64fb2cc3284e9ab3
621 o changeset 81973cd24b58db2fdf18ce3d64fb2cc3284e9ab3
563 desc initial, phase: draft
622 desc initial, phase: draft
564
623
565 $ hg rebase -s . -d 1 --config experimental.copytrace.sourcecommitlimit=100
624 $ hg rebase -s . -d 1 --config experimental.copytrace.sourcecommitlimit=100
566 rebasing 2:6207d2d318e7 "mod a" (tip)
625 rebasing 2:6207d2d318e7 "mod a" (tip)
567 merging dir2/b and dir1/a to dir2/b
626 merging dir2/b and dir1/a to dir2/b
568 saved backup bundle to $TESTTMP/repo/repo/.hg/strip-backup/6207d2d318e7-1c9779ad-rebase.hg (glob)
627 saved backup bundle to $TESTTMP/repo/repo/.hg/strip-backup/6207d2d318e7-1c9779ad-rebase.hg (glob)
569 $ cat dir2/b
628 $ cat dir2/b
570 a
629 a
571 b
630 b
572 $ cd ..
631 $ cd ..
573 $ rm -rf repo
632 $ rm -rf repo
574
633
575 Move directory in one merge parent, while adding file to original directory
634 Move directory in one merge parent, while adding file to original directory
576 in other merge parent. File moved on rebase.
635 in other merge parent. File moved on rebase.
577
636
578 $ hg init repo
637 $ hg init repo
579 $ initclient repo
638 $ initclient repo
580 $ mkdir repo/dir1
639 $ mkdir repo/dir1
581 $ cd repo/dir1
640 $ cd repo/dir1
582 $ echo dummy > dummy
641 $ echo dummy > dummy
583 $ hg add dummy
642 $ hg add dummy
584 $ cd ..
643 $ cd ..
585 $ hg ci -qm initial
644 $ hg ci -qm initial
586 $ cd dir1
645 $ cd dir1
587 $ echo a > a
646 $ echo a > a
588 $ hg add a
647 $ hg add a
589 $ cd ..
648 $ cd ..
590 $ hg ci -qm 'hg add dir1/a'
649 $ hg ci -qm 'hg add dir1/a'
591 $ hg up -q '.^'
650 $ hg up -q '.^'
592 $ hg mv -q dir1 dir2
651 $ hg mv -q dir1 dir2
593 $ hg ci -qm 'mv dir1 dir2'
652 $ hg ci -qm 'mv dir1 dir2'
594
653
595 $ hg log -G -T 'changeset {node}\n desc {desc}, phase: {phase}\n'
654 $ hg log -G -T 'changeset {node}\n desc {desc}, phase: {phase}\n'
596 @ changeset e8919e7df8d036e07b906045eddcd4a42ff1915f
655 @ changeset e8919e7df8d036e07b906045eddcd4a42ff1915f
597 | desc mv dir1 dir2, phase: draft
656 | desc mv dir1 dir2, phase: draft
598 | o changeset 7c7c6f339be00f849c3cb2df738ca91db78b32c8
657 | o changeset 7c7c6f339be00f849c3cb2df738ca91db78b32c8
599 |/ desc hg add dir1/a, phase: draft
658 |/ desc hg add dir1/a, phase: draft
600 o changeset a235dcce55dcf42034c4e374cb200662d0bb4a13
659 o changeset a235dcce55dcf42034c4e374cb200662d0bb4a13
601 desc initial, phase: draft
660 desc initial, phase: draft
602
661
603 $ hg rebase -s . -d 1 --config experimental.copytrace.sourcecommitlimit=100
662 $ hg rebase -s . -d 1 --config experimental.copytrace.sourcecommitlimit=100
604 rebasing 2:e8919e7df8d0 "mv dir1 dir2" (tip)
663 rebasing 2:e8919e7df8d0 "mv dir1 dir2" (tip)
605 saved backup bundle to $TESTTMP/repo/repo/.hg/strip-backup/e8919e7df8d0-f62fab62-rebase.hg (glob)
664 saved backup bundle to $TESTTMP/repo/repo/.hg/strip-backup/e8919e7df8d0-f62fab62-rebase.hg (glob)
606 $ ls dir2
665 $ ls dir2
607 a
666 a
608 dummy
667 dummy
609 $ rm -rf repo
668 $ rm -rf repo
610
669
611 Testing the sourcecommitlimit config
670 Testing the sourcecommitlimit config
612 -----------------------------------
671 -----------------------------------
613
672
614 $ hg init repo
673 $ hg init repo
615 $ initclient repo
674 $ initclient repo
616 $ cd repo
675 $ cd repo
617 $ echo a > a
676 $ echo a > a
618 $ hg ci -Aqm "added a"
677 $ hg ci -Aqm "added a"
619 $ echo "more things" >> a
678 $ echo "more things" >> a
620 $ hg ci -qm "added more things to a"
679 $ hg ci -qm "added more things to a"
621 $ hg up 0
680 $ hg up 0
622 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
681 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
623 $ echo b > b
682 $ echo b > b
624 $ hg ci -Aqm "added b"
683 $ hg ci -Aqm "added b"
625 $ mkdir foo
684 $ mkdir foo
626 $ hg mv a foo/bar
685 $ hg mv a foo/bar
627 $ hg ci -m "Moved a to foo/bar"
686 $ hg ci -m "Moved a to foo/bar"
628 $ hg log -G -T 'changeset {node}\n desc {desc}, phase: {phase}\n'
687 $ hg log -G -T 'changeset {node}\n desc {desc}, phase: {phase}\n'
629 @ changeset b4b0f7880e500b5c364a5f07b4a2b167de7a6fb0
688 @ changeset b4b0f7880e500b5c364a5f07b4a2b167de7a6fb0
630 | desc Moved a to foo/bar, phase: draft
689 | desc Moved a to foo/bar, phase: draft
631 o changeset 5f6d8a4bf34ab274ccc9f631c2536964b8a3666d
690 o changeset 5f6d8a4bf34ab274ccc9f631c2536964b8a3666d
632 | desc added b, phase: draft
691 | desc added b, phase: draft
633 | o changeset 8b6e13696c38e8445a759516474640c2f8dddef6
692 | o changeset 8b6e13696c38e8445a759516474640c2f8dddef6
634 |/ desc added more things to a, phase: draft
693 |/ desc added more things to a, phase: draft
635 o changeset 9092f1db7931481f93b37d5c9fbcfc341bcd7318
694 o changeset 9092f1db7931481f93b37d5c9fbcfc341bcd7318
636 desc added a, phase: draft
695 desc added a, phase: draft
637
696
638 When the sourcecommitlimit is small and we have more drafts, we use heuristics only
697 When the sourcecommitlimit is small and we have more drafts, we use heuristics only
639
698
640 $ hg rebase -s 8b6e13696 -d .
699 $ hg rebase -s 8b6e13696 -d .
641 rebasing 1:8b6e13696c38 "added more things to a"
700 rebasing 1:8b6e13696c38 "added more things to a"
642 other [source] changed a which local [dest] deleted
701 other [source] changed a which local [dest] deleted
643 use (c)hanged version, leave (d)eleted, or leave (u)nresolved? u
702 use (c)hanged version, leave (d)eleted, or leave (u)nresolved? u
644 unresolved conflicts (see hg resolve, then hg rebase --continue)
703 unresolved conflicts (see hg resolve, then hg rebase --continue)
645 [1]
704 [1]
646
705
647 But when we have "sourcecommitlimit > (no. of drafts from base to c1)", we do
706 But when we have "sourcecommitlimit > (no. of drafts from base to c1)", we do
648 fullcopytracing
707 fullcopytracing
649
708
650 $ hg rebase --abort
709 $ hg rebase --abort
651 rebase aborted
710 rebase aborted
652 $ hg rebase -s 8b6e13696 -d . --config experimental.copytrace.sourcecommitlimit=100
711 $ hg rebase -s 8b6e13696 -d . --config experimental.copytrace.sourcecommitlimit=100
653 rebasing 1:8b6e13696c38 "added more things to a"
712 rebasing 1:8b6e13696c38 "added more things to a"
654 merging foo/bar and a to foo/bar
713 merging foo/bar and a to foo/bar
655 saved backup bundle to $TESTTMP/repo/repo/repo/.hg/strip-backup/8b6e13696c38-fc14ac83-rebase.hg (glob)
714 saved backup bundle to $TESTTMP/repo/repo/repo/.hg/strip-backup/8b6e13696c38-fc14ac83-rebase.hg (glob)
656 $ cd ..
715 $ cd ..
657 $ rm -rf repo
716 $ rm -rf repo
General Comments 0
You need to be logged in to leave comments. Login now