##// END OF EJS Templates
copies: do copy tracing based on ctx.p[12]copies() if configured...
Martin von Zweigbergk -
r41922:49ad315b default
parent child Browse files
Show More
@@ -1,1449 +1,1452 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 sorted(configtable.items()):
20 for section, items in sorted(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 baseitem = super(itemregister, self).get(key)
70 baseitem = super(itemregister, self).get(key)
71 if baseitem is not None and not baseitem.generic:
71 if baseitem is not None and not baseitem.generic:
72 return baseitem
72 return baseitem
73
73
74 # search for a matching generic item
74 # search for a matching generic item
75 generics = sorted(self._generics, key=(lambda x: (x.priority, x.name)))
75 generics = sorted(self._generics, key=(lambda x: (x.priority, x.name)))
76 for item in generics:
76 for item in generics:
77 # we use 'match' instead of 'search' to make the matching simpler
77 # we use 'match' instead of 'search' to make the matching simpler
78 # for people unfamiliar with regular expression. Having the match
78 # for people unfamiliar with regular expression. Having the match
79 # rooted to the start of the string will produce less surprising
79 # rooted to the start of the string will produce less surprising
80 # result for user writing simple regex for sub-attribute.
80 # result for user writing simple regex for sub-attribute.
81 #
81 #
82 # For example using "color\..*" match produces an unsurprising
82 # For example using "color\..*" match produces an unsurprising
83 # result, while using search could suddenly match apparently
83 # result, while using search could suddenly match apparently
84 # unrelated configuration that happens to contains "color."
84 # unrelated configuration that happens to contains "color."
85 # anywhere. This is a tradeoff where we favor requiring ".*" on
85 # anywhere. This is a tradeoff where we favor requiring ".*" on
86 # some match to avoid the need to prefix most pattern with "^".
86 # some match to avoid the need to prefix most pattern with "^".
87 # The "^" seems more error prone.
87 # The "^" seems more error prone.
88 if item._re.match(key):
88 if item._re.match(key):
89 return item
89 return item
90
90
91 return None
91 return None
92
92
93 coreitems = {}
93 coreitems = {}
94
94
95 def _register(configtable, *args, **kwargs):
95 def _register(configtable, *args, **kwargs):
96 item = configitem(*args, **kwargs)
96 item = configitem(*args, **kwargs)
97 section = configtable.setdefault(item.section, itemregister())
97 section = configtable.setdefault(item.section, itemregister())
98 if item.name in section:
98 if item.name in section:
99 msg = "duplicated config item registration for '%s.%s'"
99 msg = "duplicated config item registration for '%s.%s'"
100 raise error.ProgrammingError(msg % (item.section, item.name))
100 raise error.ProgrammingError(msg % (item.section, item.name))
101 section[item.name] = item
101 section[item.name] = item
102
102
103 # special value for case where the default is derived from other values
103 # special value for case where the default is derived from other values
104 dynamicdefault = object()
104 dynamicdefault = object()
105
105
106 # Registering actual config items
106 # Registering actual config items
107
107
108 def getitemregister(configtable):
108 def getitemregister(configtable):
109 f = functools.partial(_register, configtable)
109 f = functools.partial(_register, configtable)
110 # export pseudo enum as configitem.*
110 # export pseudo enum as configitem.*
111 f.dynamicdefault = dynamicdefault
111 f.dynamicdefault = dynamicdefault
112 return f
112 return f
113
113
114 coreconfigitem = getitemregister(coreitems)
114 coreconfigitem = getitemregister(coreitems)
115
115
116 def _registerdiffopts(section, configprefix=''):
116 def _registerdiffopts(section, configprefix=''):
117 coreconfigitem(section, configprefix + 'nodates',
117 coreconfigitem(section, configprefix + 'nodates',
118 default=False,
118 default=False,
119 )
119 )
120 coreconfigitem(section, configprefix + 'showfunc',
120 coreconfigitem(section, configprefix + 'showfunc',
121 default=False,
121 default=False,
122 )
122 )
123 coreconfigitem(section, configprefix + 'unified',
123 coreconfigitem(section, configprefix + 'unified',
124 default=None,
124 default=None,
125 )
125 )
126 coreconfigitem(section, configprefix + 'git',
126 coreconfigitem(section, configprefix + 'git',
127 default=False,
127 default=False,
128 )
128 )
129 coreconfigitem(section, configprefix + 'ignorews',
129 coreconfigitem(section, configprefix + 'ignorews',
130 default=False,
130 default=False,
131 )
131 )
132 coreconfigitem(section, configprefix + 'ignorewsamount',
132 coreconfigitem(section, configprefix + 'ignorewsamount',
133 default=False,
133 default=False,
134 )
134 )
135 coreconfigitem(section, configprefix + 'ignoreblanklines',
135 coreconfigitem(section, configprefix + 'ignoreblanklines',
136 default=False,
136 default=False,
137 )
137 )
138 coreconfigitem(section, configprefix + 'ignorewseol',
138 coreconfigitem(section, configprefix + 'ignorewseol',
139 default=False,
139 default=False,
140 )
140 )
141 coreconfigitem(section, configprefix + 'nobinary',
141 coreconfigitem(section, configprefix + 'nobinary',
142 default=False,
142 default=False,
143 )
143 )
144 coreconfigitem(section, configprefix + 'noprefix',
144 coreconfigitem(section, configprefix + 'noprefix',
145 default=False,
145 default=False,
146 )
146 )
147 coreconfigitem(section, configprefix + 'word-diff',
147 coreconfigitem(section, configprefix + 'word-diff',
148 default=False,
148 default=False,
149 )
149 )
150
150
151 coreconfigitem('alias', '.*',
151 coreconfigitem('alias', '.*',
152 default=dynamicdefault,
152 default=dynamicdefault,
153 generic=True,
153 generic=True,
154 )
154 )
155 coreconfigitem('auth', 'cookiefile',
155 coreconfigitem('auth', 'cookiefile',
156 default=None,
156 default=None,
157 )
157 )
158 _registerdiffopts(section='annotate')
158 _registerdiffopts(section='annotate')
159 # bookmarks.pushing: internal hack for discovery
159 # bookmarks.pushing: internal hack for discovery
160 coreconfigitem('bookmarks', 'pushing',
160 coreconfigitem('bookmarks', 'pushing',
161 default=list,
161 default=list,
162 )
162 )
163 # bundle.mainreporoot: internal hack for bundlerepo
163 # bundle.mainreporoot: internal hack for bundlerepo
164 coreconfigitem('bundle', 'mainreporoot',
164 coreconfigitem('bundle', 'mainreporoot',
165 default='',
165 default='',
166 )
166 )
167 coreconfigitem('censor', 'policy',
167 coreconfigitem('censor', 'policy',
168 default='abort',
168 default='abort',
169 )
169 )
170 coreconfigitem('chgserver', 'idletimeout',
170 coreconfigitem('chgserver', 'idletimeout',
171 default=3600,
171 default=3600,
172 )
172 )
173 coreconfigitem('chgserver', 'skiphash',
173 coreconfigitem('chgserver', 'skiphash',
174 default=False,
174 default=False,
175 )
175 )
176 coreconfigitem('cmdserver', 'log',
176 coreconfigitem('cmdserver', 'log',
177 default=None,
177 default=None,
178 )
178 )
179 coreconfigitem('cmdserver', 'max-log-files',
179 coreconfigitem('cmdserver', 'max-log-files',
180 default=7,
180 default=7,
181 )
181 )
182 coreconfigitem('cmdserver', 'max-log-size',
182 coreconfigitem('cmdserver', 'max-log-size',
183 default='1 MB',
183 default='1 MB',
184 )
184 )
185 coreconfigitem('cmdserver', 'max-repo-cache',
185 coreconfigitem('cmdserver', 'max-repo-cache',
186 default=0,
186 default=0,
187 )
187 )
188 coreconfigitem('cmdserver', 'message-encodings',
188 coreconfigitem('cmdserver', 'message-encodings',
189 default=list,
189 default=list,
190 )
190 )
191 coreconfigitem('cmdserver', 'track-log',
191 coreconfigitem('cmdserver', 'track-log',
192 default=lambda: ['chgserver', 'cmdserver', 'repocache'],
192 default=lambda: ['chgserver', 'cmdserver', 'repocache'],
193 )
193 )
194 coreconfigitem('color', '.*',
194 coreconfigitem('color', '.*',
195 default=None,
195 default=None,
196 generic=True,
196 generic=True,
197 )
197 )
198 coreconfigitem('color', 'mode',
198 coreconfigitem('color', 'mode',
199 default='auto',
199 default='auto',
200 )
200 )
201 coreconfigitem('color', 'pagermode',
201 coreconfigitem('color', 'pagermode',
202 default=dynamicdefault,
202 default=dynamicdefault,
203 )
203 )
204 _registerdiffopts(section='commands', configprefix='commit.interactive.')
204 _registerdiffopts(section='commands', configprefix='commit.interactive.')
205 coreconfigitem('commands', 'grep.all-files',
205 coreconfigitem('commands', 'grep.all-files',
206 default=False,
206 default=False,
207 )
207 )
208 coreconfigitem('commands', 'resolve.confirm',
208 coreconfigitem('commands', 'resolve.confirm',
209 default=False,
209 default=False,
210 )
210 )
211 coreconfigitem('commands', 'resolve.explicit-re-merge',
211 coreconfigitem('commands', 'resolve.explicit-re-merge',
212 default=False,
212 default=False,
213 )
213 )
214 coreconfigitem('commands', 'resolve.mark-check',
214 coreconfigitem('commands', 'resolve.mark-check',
215 default='none',
215 default='none',
216 )
216 )
217 _registerdiffopts(section='commands', configprefix='revert.interactive.')
217 _registerdiffopts(section='commands', configprefix='revert.interactive.')
218 coreconfigitem('commands', 'show.aliasprefix',
218 coreconfigitem('commands', 'show.aliasprefix',
219 default=list,
219 default=list,
220 )
220 )
221 coreconfigitem('commands', 'status.relative',
221 coreconfigitem('commands', 'status.relative',
222 default=False,
222 default=False,
223 )
223 )
224 coreconfigitem('commands', 'status.skipstates',
224 coreconfigitem('commands', 'status.skipstates',
225 default=[],
225 default=[],
226 )
226 )
227 coreconfigitem('commands', 'status.terse',
227 coreconfigitem('commands', 'status.terse',
228 default='',
228 default='',
229 )
229 )
230 coreconfigitem('commands', 'status.verbose',
230 coreconfigitem('commands', 'status.verbose',
231 default=False,
231 default=False,
232 )
232 )
233 coreconfigitem('commands', 'update.check',
233 coreconfigitem('commands', 'update.check',
234 default=None,
234 default=None,
235 )
235 )
236 coreconfigitem('commands', 'update.requiredest',
236 coreconfigitem('commands', 'update.requiredest',
237 default=False,
237 default=False,
238 )
238 )
239 coreconfigitem('committemplate', '.*',
239 coreconfigitem('committemplate', '.*',
240 default=None,
240 default=None,
241 generic=True,
241 generic=True,
242 )
242 )
243 coreconfigitem('convert', 'bzr.saverev',
243 coreconfigitem('convert', 'bzr.saverev',
244 default=True,
244 default=True,
245 )
245 )
246 coreconfigitem('convert', 'cvsps.cache',
246 coreconfigitem('convert', 'cvsps.cache',
247 default=True,
247 default=True,
248 )
248 )
249 coreconfigitem('convert', 'cvsps.fuzz',
249 coreconfigitem('convert', 'cvsps.fuzz',
250 default=60,
250 default=60,
251 )
251 )
252 coreconfigitem('convert', 'cvsps.logencoding',
252 coreconfigitem('convert', 'cvsps.logencoding',
253 default=None,
253 default=None,
254 )
254 )
255 coreconfigitem('convert', 'cvsps.mergefrom',
255 coreconfigitem('convert', 'cvsps.mergefrom',
256 default=None,
256 default=None,
257 )
257 )
258 coreconfigitem('convert', 'cvsps.mergeto',
258 coreconfigitem('convert', 'cvsps.mergeto',
259 default=None,
259 default=None,
260 )
260 )
261 coreconfigitem('convert', 'git.committeractions',
261 coreconfigitem('convert', 'git.committeractions',
262 default=lambda: ['messagedifferent'],
262 default=lambda: ['messagedifferent'],
263 )
263 )
264 coreconfigitem('convert', 'git.extrakeys',
264 coreconfigitem('convert', 'git.extrakeys',
265 default=list,
265 default=list,
266 )
266 )
267 coreconfigitem('convert', 'git.findcopiesharder',
267 coreconfigitem('convert', 'git.findcopiesharder',
268 default=False,
268 default=False,
269 )
269 )
270 coreconfigitem('convert', 'git.remoteprefix',
270 coreconfigitem('convert', 'git.remoteprefix',
271 default='remote',
271 default='remote',
272 )
272 )
273 coreconfigitem('convert', 'git.renamelimit',
273 coreconfigitem('convert', 'git.renamelimit',
274 default=400,
274 default=400,
275 )
275 )
276 coreconfigitem('convert', 'git.saverev',
276 coreconfigitem('convert', 'git.saverev',
277 default=True,
277 default=True,
278 )
278 )
279 coreconfigitem('convert', 'git.similarity',
279 coreconfigitem('convert', 'git.similarity',
280 default=50,
280 default=50,
281 )
281 )
282 coreconfigitem('convert', 'git.skipsubmodules',
282 coreconfigitem('convert', 'git.skipsubmodules',
283 default=False,
283 default=False,
284 )
284 )
285 coreconfigitem('convert', 'hg.clonebranches',
285 coreconfigitem('convert', 'hg.clonebranches',
286 default=False,
286 default=False,
287 )
287 )
288 coreconfigitem('convert', 'hg.ignoreerrors',
288 coreconfigitem('convert', 'hg.ignoreerrors',
289 default=False,
289 default=False,
290 )
290 )
291 coreconfigitem('convert', 'hg.revs',
291 coreconfigitem('convert', 'hg.revs',
292 default=None,
292 default=None,
293 )
293 )
294 coreconfigitem('convert', 'hg.saverev',
294 coreconfigitem('convert', 'hg.saverev',
295 default=False,
295 default=False,
296 )
296 )
297 coreconfigitem('convert', 'hg.sourcename',
297 coreconfigitem('convert', 'hg.sourcename',
298 default=None,
298 default=None,
299 )
299 )
300 coreconfigitem('convert', 'hg.startrev',
300 coreconfigitem('convert', 'hg.startrev',
301 default=None,
301 default=None,
302 )
302 )
303 coreconfigitem('convert', 'hg.tagsbranch',
303 coreconfigitem('convert', 'hg.tagsbranch',
304 default='default',
304 default='default',
305 )
305 )
306 coreconfigitem('convert', 'hg.usebranchnames',
306 coreconfigitem('convert', 'hg.usebranchnames',
307 default=True,
307 default=True,
308 )
308 )
309 coreconfigitem('convert', 'ignoreancestorcheck',
309 coreconfigitem('convert', 'ignoreancestorcheck',
310 default=False,
310 default=False,
311 )
311 )
312 coreconfigitem('convert', 'localtimezone',
312 coreconfigitem('convert', 'localtimezone',
313 default=False,
313 default=False,
314 )
314 )
315 coreconfigitem('convert', 'p4.encoding',
315 coreconfigitem('convert', 'p4.encoding',
316 default=dynamicdefault,
316 default=dynamicdefault,
317 )
317 )
318 coreconfigitem('convert', 'p4.startrev',
318 coreconfigitem('convert', 'p4.startrev',
319 default=0,
319 default=0,
320 )
320 )
321 coreconfigitem('convert', 'skiptags',
321 coreconfigitem('convert', 'skiptags',
322 default=False,
322 default=False,
323 )
323 )
324 coreconfigitem('convert', 'svn.debugsvnlog',
324 coreconfigitem('convert', 'svn.debugsvnlog',
325 default=True,
325 default=True,
326 )
326 )
327 coreconfigitem('convert', 'svn.trunk',
327 coreconfigitem('convert', 'svn.trunk',
328 default=None,
328 default=None,
329 )
329 )
330 coreconfigitem('convert', 'svn.tags',
330 coreconfigitem('convert', 'svn.tags',
331 default=None,
331 default=None,
332 )
332 )
333 coreconfigitem('convert', 'svn.branches',
333 coreconfigitem('convert', 'svn.branches',
334 default=None,
334 default=None,
335 )
335 )
336 coreconfigitem('convert', 'svn.startrev',
336 coreconfigitem('convert', 'svn.startrev',
337 default=0,
337 default=0,
338 )
338 )
339 coreconfigitem('debug', 'dirstate.delaywrite',
339 coreconfigitem('debug', 'dirstate.delaywrite',
340 default=0,
340 default=0,
341 )
341 )
342 coreconfigitem('defaults', '.*',
342 coreconfigitem('defaults', '.*',
343 default=None,
343 default=None,
344 generic=True,
344 generic=True,
345 )
345 )
346 coreconfigitem('devel', 'all-warnings',
346 coreconfigitem('devel', 'all-warnings',
347 default=False,
347 default=False,
348 )
348 )
349 coreconfigitem('devel', 'bundle2.debug',
349 coreconfigitem('devel', 'bundle2.debug',
350 default=False,
350 default=False,
351 )
351 )
352 coreconfigitem('devel', 'bundle.delta',
352 coreconfigitem('devel', 'bundle.delta',
353 default='',
353 default='',
354 )
354 )
355 coreconfigitem('devel', 'cache-vfs',
355 coreconfigitem('devel', 'cache-vfs',
356 default=None,
356 default=None,
357 )
357 )
358 coreconfigitem('devel', 'check-locks',
358 coreconfigitem('devel', 'check-locks',
359 default=False,
359 default=False,
360 )
360 )
361 coreconfigitem('devel', 'check-relroot',
361 coreconfigitem('devel', 'check-relroot',
362 default=False,
362 default=False,
363 )
363 )
364 coreconfigitem('devel', 'default-date',
364 coreconfigitem('devel', 'default-date',
365 default=None,
365 default=None,
366 )
366 )
367 coreconfigitem('devel', 'deprec-warn',
367 coreconfigitem('devel', 'deprec-warn',
368 default=False,
368 default=False,
369 )
369 )
370 coreconfigitem('devel', 'disableloaddefaultcerts',
370 coreconfigitem('devel', 'disableloaddefaultcerts',
371 default=False,
371 default=False,
372 )
372 )
373 coreconfigitem('devel', 'warn-empty-changegroup',
373 coreconfigitem('devel', 'warn-empty-changegroup',
374 default=False,
374 default=False,
375 )
375 )
376 coreconfigitem('devel', 'legacy.exchange',
376 coreconfigitem('devel', 'legacy.exchange',
377 default=list,
377 default=list,
378 )
378 )
379 coreconfigitem('devel', 'servercafile',
379 coreconfigitem('devel', 'servercafile',
380 default='',
380 default='',
381 )
381 )
382 coreconfigitem('devel', 'serverexactprotocol',
382 coreconfigitem('devel', 'serverexactprotocol',
383 default='',
383 default='',
384 )
384 )
385 coreconfigitem('devel', 'serverrequirecert',
385 coreconfigitem('devel', 'serverrequirecert',
386 default=False,
386 default=False,
387 )
387 )
388 coreconfigitem('devel', 'strip-obsmarkers',
388 coreconfigitem('devel', 'strip-obsmarkers',
389 default=True,
389 default=True,
390 )
390 )
391 coreconfigitem('devel', 'warn-config',
391 coreconfigitem('devel', 'warn-config',
392 default=None,
392 default=None,
393 )
393 )
394 coreconfigitem('devel', 'warn-config-default',
394 coreconfigitem('devel', 'warn-config-default',
395 default=None,
395 default=None,
396 )
396 )
397 coreconfigitem('devel', 'user.obsmarker',
397 coreconfigitem('devel', 'user.obsmarker',
398 default=None,
398 default=None,
399 )
399 )
400 coreconfigitem('devel', 'warn-config-unknown',
400 coreconfigitem('devel', 'warn-config-unknown',
401 default=None,
401 default=None,
402 )
402 )
403 coreconfigitem('devel', 'debug.copies',
403 coreconfigitem('devel', 'debug.copies',
404 default=False,
404 default=False,
405 )
405 )
406 coreconfigitem('devel', 'debug.extensions',
406 coreconfigitem('devel', 'debug.extensions',
407 default=False,
407 default=False,
408 )
408 )
409 coreconfigitem('devel', 'debug.peer-request',
409 coreconfigitem('devel', 'debug.peer-request',
410 default=False,
410 default=False,
411 )
411 )
412 _registerdiffopts(section='diff')
412 _registerdiffopts(section='diff')
413 coreconfigitem('email', 'bcc',
413 coreconfigitem('email', 'bcc',
414 default=None,
414 default=None,
415 )
415 )
416 coreconfigitem('email', 'cc',
416 coreconfigitem('email', 'cc',
417 default=None,
417 default=None,
418 )
418 )
419 coreconfigitem('email', 'charsets',
419 coreconfigitem('email', 'charsets',
420 default=list,
420 default=list,
421 )
421 )
422 coreconfigitem('email', 'from',
422 coreconfigitem('email', 'from',
423 default=None,
423 default=None,
424 )
424 )
425 coreconfigitem('email', 'method',
425 coreconfigitem('email', 'method',
426 default='smtp',
426 default='smtp',
427 )
427 )
428 coreconfigitem('email', 'reply-to',
428 coreconfigitem('email', 'reply-to',
429 default=None,
429 default=None,
430 )
430 )
431 coreconfigitem('email', 'to',
431 coreconfigitem('email', 'to',
432 default=None,
432 default=None,
433 )
433 )
434 coreconfigitem('experimental', 'archivemetatemplate',
434 coreconfigitem('experimental', 'archivemetatemplate',
435 default=dynamicdefault,
435 default=dynamicdefault,
436 )
436 )
437 coreconfigitem('experimental', 'auto-publish',
437 coreconfigitem('experimental', 'auto-publish',
438 default='publish',
438 default='publish',
439 )
439 )
440 coreconfigitem('experimental', 'bundle-phases',
440 coreconfigitem('experimental', 'bundle-phases',
441 default=False,
441 default=False,
442 )
442 )
443 coreconfigitem('experimental', 'bundle2-advertise',
443 coreconfigitem('experimental', 'bundle2-advertise',
444 default=True,
444 default=True,
445 )
445 )
446 coreconfigitem('experimental', 'bundle2-output-capture',
446 coreconfigitem('experimental', 'bundle2-output-capture',
447 default=False,
447 default=False,
448 )
448 )
449 coreconfigitem('experimental', 'bundle2.pushback',
449 coreconfigitem('experimental', 'bundle2.pushback',
450 default=False,
450 default=False,
451 )
451 )
452 coreconfigitem('experimental', 'bundle2lazylocking',
452 coreconfigitem('experimental', 'bundle2lazylocking',
453 default=False,
453 default=False,
454 )
454 )
455 coreconfigitem('experimental', 'bundlecomplevel',
455 coreconfigitem('experimental', 'bundlecomplevel',
456 default=None,
456 default=None,
457 )
457 )
458 coreconfigitem('experimental', 'bundlecomplevel.bzip2',
458 coreconfigitem('experimental', 'bundlecomplevel.bzip2',
459 default=None,
459 default=None,
460 )
460 )
461 coreconfigitem('experimental', 'bundlecomplevel.gzip',
461 coreconfigitem('experimental', 'bundlecomplevel.gzip',
462 default=None,
462 default=None,
463 )
463 )
464 coreconfigitem('experimental', 'bundlecomplevel.none',
464 coreconfigitem('experimental', 'bundlecomplevel.none',
465 default=None,
465 default=None,
466 )
466 )
467 coreconfigitem('experimental', 'bundlecomplevel.zstd',
467 coreconfigitem('experimental', 'bundlecomplevel.zstd',
468 default=None,
468 default=None,
469 )
469 )
470 coreconfigitem('experimental', 'changegroup3',
470 coreconfigitem('experimental', 'changegroup3',
471 default=False,
471 default=False,
472 )
472 )
473 coreconfigitem('experimental', 'clientcompressionengines',
473 coreconfigitem('experimental', 'clientcompressionengines',
474 default=list,
474 default=list,
475 )
475 )
476 coreconfigitem('experimental', 'copytrace',
476 coreconfigitem('experimental', 'copytrace',
477 default='on',
477 default='on',
478 )
478 )
479 coreconfigitem('experimental', 'copytrace.movecandidateslimit',
479 coreconfigitem('experimental', 'copytrace.movecandidateslimit',
480 default=100,
480 default=100,
481 )
481 )
482 coreconfigitem('experimental', 'copytrace.sourcecommitlimit',
482 coreconfigitem('experimental', 'copytrace.sourcecommitlimit',
483 default=100,
483 default=100,
484 )
484 )
485 coreconfigitem('experimental', 'copies.read-from',
486 default="filelog-only",
487 )
485 coreconfigitem('experimental', 'crecordtest',
488 coreconfigitem('experimental', 'crecordtest',
486 default=None,
489 default=None,
487 )
490 )
488 coreconfigitem('experimental', 'directaccess',
491 coreconfigitem('experimental', 'directaccess',
489 default=False,
492 default=False,
490 )
493 )
491 coreconfigitem('experimental', 'directaccess.revnums',
494 coreconfigitem('experimental', 'directaccess.revnums',
492 default=False,
495 default=False,
493 )
496 )
494 coreconfigitem('experimental', 'editortmpinhg',
497 coreconfigitem('experimental', 'editortmpinhg',
495 default=False,
498 default=False,
496 )
499 )
497 coreconfigitem('experimental', 'evolution',
500 coreconfigitem('experimental', 'evolution',
498 default=list,
501 default=list,
499 )
502 )
500 coreconfigitem('experimental', 'evolution.allowdivergence',
503 coreconfigitem('experimental', 'evolution.allowdivergence',
501 default=False,
504 default=False,
502 alias=[('experimental', 'allowdivergence')]
505 alias=[('experimental', 'allowdivergence')]
503 )
506 )
504 coreconfigitem('experimental', 'evolution.allowunstable',
507 coreconfigitem('experimental', 'evolution.allowunstable',
505 default=None,
508 default=None,
506 )
509 )
507 coreconfigitem('experimental', 'evolution.createmarkers',
510 coreconfigitem('experimental', 'evolution.createmarkers',
508 default=None,
511 default=None,
509 )
512 )
510 coreconfigitem('experimental', 'evolution.effect-flags',
513 coreconfigitem('experimental', 'evolution.effect-flags',
511 default=True,
514 default=True,
512 alias=[('experimental', 'effect-flags')]
515 alias=[('experimental', 'effect-flags')]
513 )
516 )
514 coreconfigitem('experimental', 'evolution.exchange',
517 coreconfigitem('experimental', 'evolution.exchange',
515 default=None,
518 default=None,
516 )
519 )
517 coreconfigitem('experimental', 'evolution.bundle-obsmarker',
520 coreconfigitem('experimental', 'evolution.bundle-obsmarker',
518 default=False,
521 default=False,
519 )
522 )
520 coreconfigitem('experimental', 'evolution.report-instabilities',
523 coreconfigitem('experimental', 'evolution.report-instabilities',
521 default=True,
524 default=True,
522 )
525 )
523 coreconfigitem('experimental', 'evolution.track-operation',
526 coreconfigitem('experimental', 'evolution.track-operation',
524 default=True,
527 default=True,
525 )
528 )
526 coreconfigitem('experimental', 'maxdeltachainspan',
529 coreconfigitem('experimental', 'maxdeltachainspan',
527 default=-1,
530 default=-1,
528 )
531 )
529 coreconfigitem('experimental', 'mergetempdirprefix',
532 coreconfigitem('experimental', 'mergetempdirprefix',
530 default=None,
533 default=None,
531 )
534 )
532 coreconfigitem('experimental', 'mmapindexthreshold',
535 coreconfigitem('experimental', 'mmapindexthreshold',
533 default=None,
536 default=None,
534 )
537 )
535 coreconfigitem('experimental', 'narrow',
538 coreconfigitem('experimental', 'narrow',
536 default=False,
539 default=False,
537 )
540 )
538 coreconfigitem('experimental', 'nonnormalparanoidcheck',
541 coreconfigitem('experimental', 'nonnormalparanoidcheck',
539 default=False,
542 default=False,
540 )
543 )
541 coreconfigitem('experimental', 'exportableenviron',
544 coreconfigitem('experimental', 'exportableenviron',
542 default=list,
545 default=list,
543 )
546 )
544 coreconfigitem('experimental', 'extendedheader.index',
547 coreconfigitem('experimental', 'extendedheader.index',
545 default=None,
548 default=None,
546 )
549 )
547 coreconfigitem('experimental', 'extendedheader.similarity',
550 coreconfigitem('experimental', 'extendedheader.similarity',
548 default=False,
551 default=False,
549 )
552 )
550 coreconfigitem('experimental', 'format.compression',
553 coreconfigitem('experimental', 'format.compression',
551 default='zlib',
554 default='zlib',
552 )
555 )
553 coreconfigitem('experimental', 'graphshorten',
556 coreconfigitem('experimental', 'graphshorten',
554 default=False,
557 default=False,
555 )
558 )
556 coreconfigitem('experimental', 'graphstyle.parent',
559 coreconfigitem('experimental', 'graphstyle.parent',
557 default=dynamicdefault,
560 default=dynamicdefault,
558 )
561 )
559 coreconfigitem('experimental', 'graphstyle.missing',
562 coreconfigitem('experimental', 'graphstyle.missing',
560 default=dynamicdefault,
563 default=dynamicdefault,
561 )
564 )
562 coreconfigitem('experimental', 'graphstyle.grandparent',
565 coreconfigitem('experimental', 'graphstyle.grandparent',
563 default=dynamicdefault,
566 default=dynamicdefault,
564 )
567 )
565 coreconfigitem('experimental', 'hook-track-tags',
568 coreconfigitem('experimental', 'hook-track-tags',
566 default=False,
569 default=False,
567 )
570 )
568 coreconfigitem('experimental', 'httppeer.advertise-v2',
571 coreconfigitem('experimental', 'httppeer.advertise-v2',
569 default=False,
572 default=False,
570 )
573 )
571 coreconfigitem('experimental', 'httppeer.v2-encoder-order',
574 coreconfigitem('experimental', 'httppeer.v2-encoder-order',
572 default=None,
575 default=None,
573 )
576 )
574 coreconfigitem('experimental', 'httppostargs',
577 coreconfigitem('experimental', 'httppostargs',
575 default=False,
578 default=False,
576 )
579 )
577 coreconfigitem('experimental', 'mergedriver',
580 coreconfigitem('experimental', 'mergedriver',
578 default=None,
581 default=None,
579 )
582 )
580 coreconfigitem('experimental', 'nointerrupt', default=False)
583 coreconfigitem('experimental', 'nointerrupt', default=False)
581 coreconfigitem('experimental', 'nointerrupt-interactiveonly', default=True)
584 coreconfigitem('experimental', 'nointerrupt-interactiveonly', default=True)
582
585
583 coreconfigitem('experimental', 'obsmarkers-exchange-debug',
586 coreconfigitem('experimental', 'obsmarkers-exchange-debug',
584 default=False,
587 default=False,
585 )
588 )
586 coreconfigitem('experimental', 'remotenames',
589 coreconfigitem('experimental', 'remotenames',
587 default=False,
590 default=False,
588 )
591 )
589 coreconfigitem('experimental', 'removeemptydirs',
592 coreconfigitem('experimental', 'removeemptydirs',
590 default=True,
593 default=True,
591 )
594 )
592 coreconfigitem('experimental', 'revisions.prefixhexnode',
595 coreconfigitem('experimental', 'revisions.prefixhexnode',
593 default=False,
596 default=False,
594 )
597 )
595 coreconfigitem('experimental', 'revlogv2',
598 coreconfigitem('experimental', 'revlogv2',
596 default=None,
599 default=None,
597 )
600 )
598 coreconfigitem('experimental', 'revisions.disambiguatewithin',
601 coreconfigitem('experimental', 'revisions.disambiguatewithin',
599 default=None,
602 default=None,
600 )
603 )
601 coreconfigitem('experimental', 'server.filesdata.recommended-batch-size',
604 coreconfigitem('experimental', 'server.filesdata.recommended-batch-size',
602 default=50000,
605 default=50000,
603 )
606 )
604 coreconfigitem('experimental', 'server.manifestdata.recommended-batch-size',
607 coreconfigitem('experimental', 'server.manifestdata.recommended-batch-size',
605 default=100000,
608 default=100000,
606 )
609 )
607 coreconfigitem('experimental', 'server.stream-narrow-clones',
610 coreconfigitem('experimental', 'server.stream-narrow-clones',
608 default=False,
611 default=False,
609 )
612 )
610 coreconfigitem('experimental', 'single-head-per-branch',
613 coreconfigitem('experimental', 'single-head-per-branch',
611 default=False,
614 default=False,
612 )
615 )
613 coreconfigitem('experimental', 'sshserver.support-v2',
616 coreconfigitem('experimental', 'sshserver.support-v2',
614 default=False,
617 default=False,
615 )
618 )
616 coreconfigitem('experimental', 'sparse-read',
619 coreconfigitem('experimental', 'sparse-read',
617 default=False,
620 default=False,
618 )
621 )
619 coreconfigitem('experimental', 'sparse-read.density-threshold',
622 coreconfigitem('experimental', 'sparse-read.density-threshold',
620 default=0.50,
623 default=0.50,
621 )
624 )
622 coreconfigitem('experimental', 'sparse-read.min-gap-size',
625 coreconfigitem('experimental', 'sparse-read.min-gap-size',
623 default='65K',
626 default='65K',
624 )
627 )
625 coreconfigitem('experimental', 'treemanifest',
628 coreconfigitem('experimental', 'treemanifest',
626 default=False,
629 default=False,
627 )
630 )
628 coreconfigitem('experimental', 'update.atomic-file',
631 coreconfigitem('experimental', 'update.atomic-file',
629 default=False,
632 default=False,
630 )
633 )
631 coreconfigitem('experimental', 'sshpeer.advertise-v2',
634 coreconfigitem('experimental', 'sshpeer.advertise-v2',
632 default=False,
635 default=False,
633 )
636 )
634 coreconfigitem('experimental', 'web.apiserver',
637 coreconfigitem('experimental', 'web.apiserver',
635 default=False,
638 default=False,
636 )
639 )
637 coreconfigitem('experimental', 'web.api.http-v2',
640 coreconfigitem('experimental', 'web.api.http-v2',
638 default=False,
641 default=False,
639 )
642 )
640 coreconfigitem('experimental', 'web.api.debugreflect',
643 coreconfigitem('experimental', 'web.api.debugreflect',
641 default=False,
644 default=False,
642 )
645 )
643 coreconfigitem('experimental', 'worker.wdir-get-thread-safe',
646 coreconfigitem('experimental', 'worker.wdir-get-thread-safe',
644 default=False,
647 default=False,
645 )
648 )
646 coreconfigitem('experimental', 'xdiff',
649 coreconfigitem('experimental', 'xdiff',
647 default=False,
650 default=False,
648 )
651 )
649 coreconfigitem('extensions', '.*',
652 coreconfigitem('extensions', '.*',
650 default=None,
653 default=None,
651 generic=True,
654 generic=True,
652 )
655 )
653 coreconfigitem('extdata', '.*',
656 coreconfigitem('extdata', '.*',
654 default=None,
657 default=None,
655 generic=True,
658 generic=True,
656 )
659 )
657 coreconfigitem('format', 'chunkcachesize',
660 coreconfigitem('format', 'chunkcachesize',
658 default=None,
661 default=None,
659 )
662 )
660 coreconfigitem('format', 'dotencode',
663 coreconfigitem('format', 'dotencode',
661 default=True,
664 default=True,
662 )
665 )
663 coreconfigitem('format', 'generaldelta',
666 coreconfigitem('format', 'generaldelta',
664 default=False,
667 default=False,
665 )
668 )
666 coreconfigitem('format', 'manifestcachesize',
669 coreconfigitem('format', 'manifestcachesize',
667 default=None,
670 default=None,
668 )
671 )
669 coreconfigitem('format', 'maxchainlen',
672 coreconfigitem('format', 'maxchainlen',
670 default=dynamicdefault,
673 default=dynamicdefault,
671 )
674 )
672 coreconfigitem('format', 'obsstore-version',
675 coreconfigitem('format', 'obsstore-version',
673 default=None,
676 default=None,
674 )
677 )
675 coreconfigitem('format', 'sparse-revlog',
678 coreconfigitem('format', 'sparse-revlog',
676 default=True,
679 default=True,
677 )
680 )
678 coreconfigitem('format', 'usefncache',
681 coreconfigitem('format', 'usefncache',
679 default=True,
682 default=True,
680 )
683 )
681 coreconfigitem('format', 'usegeneraldelta',
684 coreconfigitem('format', 'usegeneraldelta',
682 default=True,
685 default=True,
683 )
686 )
684 coreconfigitem('format', 'usestore',
687 coreconfigitem('format', 'usestore',
685 default=True,
688 default=True,
686 )
689 )
687 coreconfigitem('format', 'internal-phase',
690 coreconfigitem('format', 'internal-phase',
688 default=False,
691 default=False,
689 )
692 )
690 coreconfigitem('fsmonitor', 'warn_when_unused',
693 coreconfigitem('fsmonitor', 'warn_when_unused',
691 default=True,
694 default=True,
692 )
695 )
693 coreconfigitem('fsmonitor', 'warn_update_file_count',
696 coreconfigitem('fsmonitor', 'warn_update_file_count',
694 default=50000,
697 default=50000,
695 )
698 )
696 coreconfigitem('help', br'hidden-command\..*',
699 coreconfigitem('help', br'hidden-command\..*',
697 default=False,
700 default=False,
698 generic=True,
701 generic=True,
699 )
702 )
700 coreconfigitem('help', br'hidden-topic\..*',
703 coreconfigitem('help', br'hidden-topic\..*',
701 default=False,
704 default=False,
702 generic=True,
705 generic=True,
703 )
706 )
704 coreconfigitem('hooks', '.*',
707 coreconfigitem('hooks', '.*',
705 default=dynamicdefault,
708 default=dynamicdefault,
706 generic=True,
709 generic=True,
707 )
710 )
708 coreconfigitem('hgweb-paths', '.*',
711 coreconfigitem('hgweb-paths', '.*',
709 default=list,
712 default=list,
710 generic=True,
713 generic=True,
711 )
714 )
712 coreconfigitem('hostfingerprints', '.*',
715 coreconfigitem('hostfingerprints', '.*',
713 default=list,
716 default=list,
714 generic=True,
717 generic=True,
715 )
718 )
716 coreconfigitem('hostsecurity', 'ciphers',
719 coreconfigitem('hostsecurity', 'ciphers',
717 default=None,
720 default=None,
718 )
721 )
719 coreconfigitem('hostsecurity', 'disabletls10warning',
722 coreconfigitem('hostsecurity', 'disabletls10warning',
720 default=False,
723 default=False,
721 )
724 )
722 coreconfigitem('hostsecurity', 'minimumprotocol',
725 coreconfigitem('hostsecurity', 'minimumprotocol',
723 default=dynamicdefault,
726 default=dynamicdefault,
724 )
727 )
725 coreconfigitem('hostsecurity', '.*:minimumprotocol$',
728 coreconfigitem('hostsecurity', '.*:minimumprotocol$',
726 default=dynamicdefault,
729 default=dynamicdefault,
727 generic=True,
730 generic=True,
728 )
731 )
729 coreconfigitem('hostsecurity', '.*:ciphers$',
732 coreconfigitem('hostsecurity', '.*:ciphers$',
730 default=dynamicdefault,
733 default=dynamicdefault,
731 generic=True,
734 generic=True,
732 )
735 )
733 coreconfigitem('hostsecurity', '.*:fingerprints$',
736 coreconfigitem('hostsecurity', '.*:fingerprints$',
734 default=list,
737 default=list,
735 generic=True,
738 generic=True,
736 )
739 )
737 coreconfigitem('hostsecurity', '.*:verifycertsfile$',
740 coreconfigitem('hostsecurity', '.*:verifycertsfile$',
738 default=None,
741 default=None,
739 generic=True,
742 generic=True,
740 )
743 )
741
744
742 coreconfigitem('http_proxy', 'always',
745 coreconfigitem('http_proxy', 'always',
743 default=False,
746 default=False,
744 )
747 )
745 coreconfigitem('http_proxy', 'host',
748 coreconfigitem('http_proxy', 'host',
746 default=None,
749 default=None,
747 )
750 )
748 coreconfigitem('http_proxy', 'no',
751 coreconfigitem('http_proxy', 'no',
749 default=list,
752 default=list,
750 )
753 )
751 coreconfigitem('http_proxy', 'passwd',
754 coreconfigitem('http_proxy', 'passwd',
752 default=None,
755 default=None,
753 )
756 )
754 coreconfigitem('http_proxy', 'user',
757 coreconfigitem('http_proxy', 'user',
755 default=None,
758 default=None,
756 )
759 )
757
760
758 coreconfigitem('http', 'timeout',
761 coreconfigitem('http', 'timeout',
759 default=None,
762 default=None,
760 )
763 )
761
764
762 coreconfigitem('logtoprocess', 'commandexception',
765 coreconfigitem('logtoprocess', 'commandexception',
763 default=None,
766 default=None,
764 )
767 )
765 coreconfigitem('logtoprocess', 'commandfinish',
768 coreconfigitem('logtoprocess', 'commandfinish',
766 default=None,
769 default=None,
767 )
770 )
768 coreconfigitem('logtoprocess', 'command',
771 coreconfigitem('logtoprocess', 'command',
769 default=None,
772 default=None,
770 )
773 )
771 coreconfigitem('logtoprocess', 'develwarn',
774 coreconfigitem('logtoprocess', 'develwarn',
772 default=None,
775 default=None,
773 )
776 )
774 coreconfigitem('logtoprocess', 'uiblocked',
777 coreconfigitem('logtoprocess', 'uiblocked',
775 default=None,
778 default=None,
776 )
779 )
777 coreconfigitem('merge', 'checkunknown',
780 coreconfigitem('merge', 'checkunknown',
778 default='abort',
781 default='abort',
779 )
782 )
780 coreconfigitem('merge', 'checkignored',
783 coreconfigitem('merge', 'checkignored',
781 default='abort',
784 default='abort',
782 )
785 )
783 coreconfigitem('experimental', 'merge.checkpathconflicts',
786 coreconfigitem('experimental', 'merge.checkpathconflicts',
784 default=False,
787 default=False,
785 )
788 )
786 coreconfigitem('merge', 'followcopies',
789 coreconfigitem('merge', 'followcopies',
787 default=True,
790 default=True,
788 )
791 )
789 coreconfigitem('merge', 'on-failure',
792 coreconfigitem('merge', 'on-failure',
790 default='continue',
793 default='continue',
791 )
794 )
792 coreconfigitem('merge', 'preferancestor',
795 coreconfigitem('merge', 'preferancestor',
793 default=lambda: ['*'],
796 default=lambda: ['*'],
794 )
797 )
795 coreconfigitem('merge', 'strict-capability-check',
798 coreconfigitem('merge', 'strict-capability-check',
796 default=False,
799 default=False,
797 )
800 )
798 coreconfigitem('merge-tools', '.*',
801 coreconfigitem('merge-tools', '.*',
799 default=None,
802 default=None,
800 generic=True,
803 generic=True,
801 )
804 )
802 coreconfigitem('merge-tools', br'.*\.args$',
805 coreconfigitem('merge-tools', br'.*\.args$',
803 default="$local $base $other",
806 default="$local $base $other",
804 generic=True,
807 generic=True,
805 priority=-1,
808 priority=-1,
806 )
809 )
807 coreconfigitem('merge-tools', br'.*\.binary$',
810 coreconfigitem('merge-tools', br'.*\.binary$',
808 default=False,
811 default=False,
809 generic=True,
812 generic=True,
810 priority=-1,
813 priority=-1,
811 )
814 )
812 coreconfigitem('merge-tools', br'.*\.check$',
815 coreconfigitem('merge-tools', br'.*\.check$',
813 default=list,
816 default=list,
814 generic=True,
817 generic=True,
815 priority=-1,
818 priority=-1,
816 )
819 )
817 coreconfigitem('merge-tools', br'.*\.checkchanged$',
820 coreconfigitem('merge-tools', br'.*\.checkchanged$',
818 default=False,
821 default=False,
819 generic=True,
822 generic=True,
820 priority=-1,
823 priority=-1,
821 )
824 )
822 coreconfigitem('merge-tools', br'.*\.executable$',
825 coreconfigitem('merge-tools', br'.*\.executable$',
823 default=dynamicdefault,
826 default=dynamicdefault,
824 generic=True,
827 generic=True,
825 priority=-1,
828 priority=-1,
826 )
829 )
827 coreconfigitem('merge-tools', br'.*\.fixeol$',
830 coreconfigitem('merge-tools', br'.*\.fixeol$',
828 default=False,
831 default=False,
829 generic=True,
832 generic=True,
830 priority=-1,
833 priority=-1,
831 )
834 )
832 coreconfigitem('merge-tools', br'.*\.gui$',
835 coreconfigitem('merge-tools', br'.*\.gui$',
833 default=False,
836 default=False,
834 generic=True,
837 generic=True,
835 priority=-1,
838 priority=-1,
836 )
839 )
837 coreconfigitem('merge-tools', br'.*\.mergemarkers$',
840 coreconfigitem('merge-tools', br'.*\.mergemarkers$',
838 default='basic',
841 default='basic',
839 generic=True,
842 generic=True,
840 priority=-1,
843 priority=-1,
841 )
844 )
842 coreconfigitem('merge-tools', br'.*\.mergemarkertemplate$',
845 coreconfigitem('merge-tools', br'.*\.mergemarkertemplate$',
843 default=dynamicdefault, # take from ui.mergemarkertemplate
846 default=dynamicdefault, # take from ui.mergemarkertemplate
844 generic=True,
847 generic=True,
845 priority=-1,
848 priority=-1,
846 )
849 )
847 coreconfigitem('merge-tools', br'.*\.priority$',
850 coreconfigitem('merge-tools', br'.*\.priority$',
848 default=0,
851 default=0,
849 generic=True,
852 generic=True,
850 priority=-1,
853 priority=-1,
851 )
854 )
852 coreconfigitem('merge-tools', br'.*\.premerge$',
855 coreconfigitem('merge-tools', br'.*\.premerge$',
853 default=dynamicdefault,
856 default=dynamicdefault,
854 generic=True,
857 generic=True,
855 priority=-1,
858 priority=-1,
856 )
859 )
857 coreconfigitem('merge-tools', br'.*\.symlink$',
860 coreconfigitem('merge-tools', br'.*\.symlink$',
858 default=False,
861 default=False,
859 generic=True,
862 generic=True,
860 priority=-1,
863 priority=-1,
861 )
864 )
862 coreconfigitem('pager', 'attend-.*',
865 coreconfigitem('pager', 'attend-.*',
863 default=dynamicdefault,
866 default=dynamicdefault,
864 generic=True,
867 generic=True,
865 )
868 )
866 coreconfigitem('pager', 'ignore',
869 coreconfigitem('pager', 'ignore',
867 default=list,
870 default=list,
868 )
871 )
869 coreconfigitem('pager', 'pager',
872 coreconfigitem('pager', 'pager',
870 default=dynamicdefault,
873 default=dynamicdefault,
871 )
874 )
872 coreconfigitem('patch', 'eol',
875 coreconfigitem('patch', 'eol',
873 default='strict',
876 default='strict',
874 )
877 )
875 coreconfigitem('patch', 'fuzz',
878 coreconfigitem('patch', 'fuzz',
876 default=2,
879 default=2,
877 )
880 )
878 coreconfigitem('paths', 'default',
881 coreconfigitem('paths', 'default',
879 default=None,
882 default=None,
880 )
883 )
881 coreconfigitem('paths', 'default-push',
884 coreconfigitem('paths', 'default-push',
882 default=None,
885 default=None,
883 )
886 )
884 coreconfigitem('paths', '.*',
887 coreconfigitem('paths', '.*',
885 default=None,
888 default=None,
886 generic=True,
889 generic=True,
887 )
890 )
888 coreconfigitem('phases', 'checksubrepos',
891 coreconfigitem('phases', 'checksubrepos',
889 default='follow',
892 default='follow',
890 )
893 )
891 coreconfigitem('phases', 'new-commit',
894 coreconfigitem('phases', 'new-commit',
892 default='draft',
895 default='draft',
893 )
896 )
894 coreconfigitem('phases', 'publish',
897 coreconfigitem('phases', 'publish',
895 default=True,
898 default=True,
896 )
899 )
897 coreconfigitem('profiling', 'enabled',
900 coreconfigitem('profiling', 'enabled',
898 default=False,
901 default=False,
899 )
902 )
900 coreconfigitem('profiling', 'format',
903 coreconfigitem('profiling', 'format',
901 default='text',
904 default='text',
902 )
905 )
903 coreconfigitem('profiling', 'freq',
906 coreconfigitem('profiling', 'freq',
904 default=1000,
907 default=1000,
905 )
908 )
906 coreconfigitem('profiling', 'limit',
909 coreconfigitem('profiling', 'limit',
907 default=30,
910 default=30,
908 )
911 )
909 coreconfigitem('profiling', 'nested',
912 coreconfigitem('profiling', 'nested',
910 default=0,
913 default=0,
911 )
914 )
912 coreconfigitem('profiling', 'output',
915 coreconfigitem('profiling', 'output',
913 default=None,
916 default=None,
914 )
917 )
915 coreconfigitem('profiling', 'showmax',
918 coreconfigitem('profiling', 'showmax',
916 default=0.999,
919 default=0.999,
917 )
920 )
918 coreconfigitem('profiling', 'showmin',
921 coreconfigitem('profiling', 'showmin',
919 default=dynamicdefault,
922 default=dynamicdefault,
920 )
923 )
921 coreconfigitem('profiling', 'sort',
924 coreconfigitem('profiling', 'sort',
922 default='inlinetime',
925 default='inlinetime',
923 )
926 )
924 coreconfigitem('profiling', 'statformat',
927 coreconfigitem('profiling', 'statformat',
925 default='hotpath',
928 default='hotpath',
926 )
929 )
927 coreconfigitem('profiling', 'time-track',
930 coreconfigitem('profiling', 'time-track',
928 default=dynamicdefault,
931 default=dynamicdefault,
929 )
932 )
930 coreconfigitem('profiling', 'type',
933 coreconfigitem('profiling', 'type',
931 default='stat',
934 default='stat',
932 )
935 )
933 coreconfigitem('progress', 'assume-tty',
936 coreconfigitem('progress', 'assume-tty',
934 default=False,
937 default=False,
935 )
938 )
936 coreconfigitem('progress', 'changedelay',
939 coreconfigitem('progress', 'changedelay',
937 default=1,
940 default=1,
938 )
941 )
939 coreconfigitem('progress', 'clear-complete',
942 coreconfigitem('progress', 'clear-complete',
940 default=True,
943 default=True,
941 )
944 )
942 coreconfigitem('progress', 'debug',
945 coreconfigitem('progress', 'debug',
943 default=False,
946 default=False,
944 )
947 )
945 coreconfigitem('progress', 'delay',
948 coreconfigitem('progress', 'delay',
946 default=3,
949 default=3,
947 )
950 )
948 coreconfigitem('progress', 'disable',
951 coreconfigitem('progress', 'disable',
949 default=False,
952 default=False,
950 )
953 )
951 coreconfigitem('progress', 'estimateinterval',
954 coreconfigitem('progress', 'estimateinterval',
952 default=60.0,
955 default=60.0,
953 )
956 )
954 coreconfigitem('progress', 'format',
957 coreconfigitem('progress', 'format',
955 default=lambda: ['topic', 'bar', 'number', 'estimate'],
958 default=lambda: ['topic', 'bar', 'number', 'estimate'],
956 )
959 )
957 coreconfigitem('progress', 'refresh',
960 coreconfigitem('progress', 'refresh',
958 default=0.1,
961 default=0.1,
959 )
962 )
960 coreconfigitem('progress', 'width',
963 coreconfigitem('progress', 'width',
961 default=dynamicdefault,
964 default=dynamicdefault,
962 )
965 )
963 coreconfigitem('push', 'pushvars.server',
966 coreconfigitem('push', 'pushvars.server',
964 default=False,
967 default=False,
965 )
968 )
966 coreconfigitem('rewrite', 'backup-bundle',
969 coreconfigitem('rewrite', 'backup-bundle',
967 default=True,
970 default=True,
968 alias=[('ui', 'history-editing-backup')],
971 alias=[('ui', 'history-editing-backup')],
969 )
972 )
970 coreconfigitem('rewrite', 'update-timestamp',
973 coreconfigitem('rewrite', 'update-timestamp',
971 default=False,
974 default=False,
972 )
975 )
973 coreconfigitem('storage', 'new-repo-backend',
976 coreconfigitem('storage', 'new-repo-backend',
974 default='revlogv1',
977 default='revlogv1',
975 )
978 )
976 coreconfigitem('storage', 'revlog.optimize-delta-parent-choice',
979 coreconfigitem('storage', 'revlog.optimize-delta-parent-choice',
977 default=True,
980 default=True,
978 alias=[('format', 'aggressivemergedeltas')],
981 alias=[('format', 'aggressivemergedeltas')],
979 )
982 )
980 coreconfigitem('server', 'bookmarks-pushkey-compat',
983 coreconfigitem('server', 'bookmarks-pushkey-compat',
981 default=True,
984 default=True,
982 )
985 )
983 coreconfigitem('server', 'bundle1',
986 coreconfigitem('server', 'bundle1',
984 default=True,
987 default=True,
985 )
988 )
986 coreconfigitem('server', 'bundle1gd',
989 coreconfigitem('server', 'bundle1gd',
987 default=None,
990 default=None,
988 )
991 )
989 coreconfigitem('server', 'bundle1.pull',
992 coreconfigitem('server', 'bundle1.pull',
990 default=None,
993 default=None,
991 )
994 )
992 coreconfigitem('server', 'bundle1gd.pull',
995 coreconfigitem('server', 'bundle1gd.pull',
993 default=None,
996 default=None,
994 )
997 )
995 coreconfigitem('server', 'bundle1.push',
998 coreconfigitem('server', 'bundle1.push',
996 default=None,
999 default=None,
997 )
1000 )
998 coreconfigitem('server', 'bundle1gd.push',
1001 coreconfigitem('server', 'bundle1gd.push',
999 default=None,
1002 default=None,
1000 )
1003 )
1001 coreconfigitem('server', 'bundle2.stream',
1004 coreconfigitem('server', 'bundle2.stream',
1002 default=True,
1005 default=True,
1003 alias=[('experimental', 'bundle2.stream')]
1006 alias=[('experimental', 'bundle2.stream')]
1004 )
1007 )
1005 coreconfigitem('server', 'compressionengines',
1008 coreconfigitem('server', 'compressionengines',
1006 default=list,
1009 default=list,
1007 )
1010 )
1008 coreconfigitem('server', 'concurrent-push-mode',
1011 coreconfigitem('server', 'concurrent-push-mode',
1009 default='strict',
1012 default='strict',
1010 )
1013 )
1011 coreconfigitem('server', 'disablefullbundle',
1014 coreconfigitem('server', 'disablefullbundle',
1012 default=False,
1015 default=False,
1013 )
1016 )
1014 coreconfigitem('server', 'maxhttpheaderlen',
1017 coreconfigitem('server', 'maxhttpheaderlen',
1015 default=1024,
1018 default=1024,
1016 )
1019 )
1017 coreconfigitem('server', 'pullbundle',
1020 coreconfigitem('server', 'pullbundle',
1018 default=False,
1021 default=False,
1019 )
1022 )
1020 coreconfigitem('server', 'preferuncompressed',
1023 coreconfigitem('server', 'preferuncompressed',
1021 default=False,
1024 default=False,
1022 )
1025 )
1023 coreconfigitem('server', 'streamunbundle',
1026 coreconfigitem('server', 'streamunbundle',
1024 default=False,
1027 default=False,
1025 )
1028 )
1026 coreconfigitem('server', 'uncompressed',
1029 coreconfigitem('server', 'uncompressed',
1027 default=True,
1030 default=True,
1028 )
1031 )
1029 coreconfigitem('server', 'uncompressedallowsecret',
1032 coreconfigitem('server', 'uncompressedallowsecret',
1030 default=False,
1033 default=False,
1031 )
1034 )
1032 coreconfigitem('server', 'validate',
1035 coreconfigitem('server', 'validate',
1033 default=False,
1036 default=False,
1034 )
1037 )
1035 coreconfigitem('server', 'zliblevel',
1038 coreconfigitem('server', 'zliblevel',
1036 default=-1,
1039 default=-1,
1037 )
1040 )
1038 coreconfigitem('server', 'zstdlevel',
1041 coreconfigitem('server', 'zstdlevel',
1039 default=3,
1042 default=3,
1040 )
1043 )
1041 coreconfigitem('share', 'pool',
1044 coreconfigitem('share', 'pool',
1042 default=None,
1045 default=None,
1043 )
1046 )
1044 coreconfigitem('share', 'poolnaming',
1047 coreconfigitem('share', 'poolnaming',
1045 default='identity',
1048 default='identity',
1046 )
1049 )
1047 coreconfigitem('smtp', 'host',
1050 coreconfigitem('smtp', 'host',
1048 default=None,
1051 default=None,
1049 )
1052 )
1050 coreconfigitem('smtp', 'local_hostname',
1053 coreconfigitem('smtp', 'local_hostname',
1051 default=None,
1054 default=None,
1052 )
1055 )
1053 coreconfigitem('smtp', 'password',
1056 coreconfigitem('smtp', 'password',
1054 default=None,
1057 default=None,
1055 )
1058 )
1056 coreconfigitem('smtp', 'port',
1059 coreconfigitem('smtp', 'port',
1057 default=dynamicdefault,
1060 default=dynamicdefault,
1058 )
1061 )
1059 coreconfigitem('smtp', 'tls',
1062 coreconfigitem('smtp', 'tls',
1060 default='none',
1063 default='none',
1061 )
1064 )
1062 coreconfigitem('smtp', 'username',
1065 coreconfigitem('smtp', 'username',
1063 default=None,
1066 default=None,
1064 )
1067 )
1065 coreconfigitem('sparse', 'missingwarning',
1068 coreconfigitem('sparse', 'missingwarning',
1066 default=True,
1069 default=True,
1067 )
1070 )
1068 coreconfigitem('subrepos', 'allowed',
1071 coreconfigitem('subrepos', 'allowed',
1069 default=dynamicdefault, # to make backporting simpler
1072 default=dynamicdefault, # to make backporting simpler
1070 )
1073 )
1071 coreconfigitem('subrepos', 'hg:allowed',
1074 coreconfigitem('subrepos', 'hg:allowed',
1072 default=dynamicdefault,
1075 default=dynamicdefault,
1073 )
1076 )
1074 coreconfigitem('subrepos', 'git:allowed',
1077 coreconfigitem('subrepos', 'git:allowed',
1075 default=dynamicdefault,
1078 default=dynamicdefault,
1076 )
1079 )
1077 coreconfigitem('subrepos', 'svn:allowed',
1080 coreconfigitem('subrepos', 'svn:allowed',
1078 default=dynamicdefault,
1081 default=dynamicdefault,
1079 )
1082 )
1080 coreconfigitem('templates', '.*',
1083 coreconfigitem('templates', '.*',
1081 default=None,
1084 default=None,
1082 generic=True,
1085 generic=True,
1083 )
1086 )
1084 coreconfigitem('templateconfig', '.*',
1087 coreconfigitem('templateconfig', '.*',
1085 default=dynamicdefault,
1088 default=dynamicdefault,
1086 generic=True,
1089 generic=True,
1087 )
1090 )
1088 coreconfigitem('trusted', 'groups',
1091 coreconfigitem('trusted', 'groups',
1089 default=list,
1092 default=list,
1090 )
1093 )
1091 coreconfigitem('trusted', 'users',
1094 coreconfigitem('trusted', 'users',
1092 default=list,
1095 default=list,
1093 )
1096 )
1094 coreconfigitem('ui', '_usedassubrepo',
1097 coreconfigitem('ui', '_usedassubrepo',
1095 default=False,
1098 default=False,
1096 )
1099 )
1097 coreconfigitem('ui', 'allowemptycommit',
1100 coreconfigitem('ui', 'allowemptycommit',
1098 default=False,
1101 default=False,
1099 )
1102 )
1100 coreconfigitem('ui', 'archivemeta',
1103 coreconfigitem('ui', 'archivemeta',
1101 default=True,
1104 default=True,
1102 )
1105 )
1103 coreconfigitem('ui', 'askusername',
1106 coreconfigitem('ui', 'askusername',
1104 default=False,
1107 default=False,
1105 )
1108 )
1106 coreconfigitem('ui', 'clonebundlefallback',
1109 coreconfigitem('ui', 'clonebundlefallback',
1107 default=False,
1110 default=False,
1108 )
1111 )
1109 coreconfigitem('ui', 'clonebundleprefers',
1112 coreconfigitem('ui', 'clonebundleprefers',
1110 default=list,
1113 default=list,
1111 )
1114 )
1112 coreconfigitem('ui', 'clonebundles',
1115 coreconfigitem('ui', 'clonebundles',
1113 default=True,
1116 default=True,
1114 )
1117 )
1115 coreconfigitem('ui', 'color',
1118 coreconfigitem('ui', 'color',
1116 default='auto',
1119 default='auto',
1117 )
1120 )
1118 coreconfigitem('ui', 'commitsubrepos',
1121 coreconfigitem('ui', 'commitsubrepos',
1119 default=False,
1122 default=False,
1120 )
1123 )
1121 coreconfigitem('ui', 'debug',
1124 coreconfigitem('ui', 'debug',
1122 default=False,
1125 default=False,
1123 )
1126 )
1124 coreconfigitem('ui', 'debugger',
1127 coreconfigitem('ui', 'debugger',
1125 default=None,
1128 default=None,
1126 )
1129 )
1127 coreconfigitem('ui', 'editor',
1130 coreconfigitem('ui', 'editor',
1128 default=dynamicdefault,
1131 default=dynamicdefault,
1129 )
1132 )
1130 coreconfigitem('ui', 'fallbackencoding',
1133 coreconfigitem('ui', 'fallbackencoding',
1131 default=None,
1134 default=None,
1132 )
1135 )
1133 coreconfigitem('ui', 'forcecwd',
1136 coreconfigitem('ui', 'forcecwd',
1134 default=None,
1137 default=None,
1135 )
1138 )
1136 coreconfigitem('ui', 'forcemerge',
1139 coreconfigitem('ui', 'forcemerge',
1137 default=None,
1140 default=None,
1138 )
1141 )
1139 coreconfigitem('ui', 'formatdebug',
1142 coreconfigitem('ui', 'formatdebug',
1140 default=False,
1143 default=False,
1141 )
1144 )
1142 coreconfigitem('ui', 'formatjson',
1145 coreconfigitem('ui', 'formatjson',
1143 default=False,
1146 default=False,
1144 )
1147 )
1145 coreconfigitem('ui', 'formatted',
1148 coreconfigitem('ui', 'formatted',
1146 default=None,
1149 default=None,
1147 )
1150 )
1148 coreconfigitem('ui', 'graphnodetemplate',
1151 coreconfigitem('ui', 'graphnodetemplate',
1149 default=None,
1152 default=None,
1150 )
1153 )
1151 coreconfigitem('ui', 'interactive',
1154 coreconfigitem('ui', 'interactive',
1152 default=None,
1155 default=None,
1153 )
1156 )
1154 coreconfigitem('ui', 'interface',
1157 coreconfigitem('ui', 'interface',
1155 default=None,
1158 default=None,
1156 )
1159 )
1157 coreconfigitem('ui', 'interface.chunkselector',
1160 coreconfigitem('ui', 'interface.chunkselector',
1158 default=None,
1161 default=None,
1159 )
1162 )
1160 coreconfigitem('ui', 'large-file-limit',
1163 coreconfigitem('ui', 'large-file-limit',
1161 default=10000000,
1164 default=10000000,
1162 )
1165 )
1163 coreconfigitem('ui', 'logblockedtimes',
1166 coreconfigitem('ui', 'logblockedtimes',
1164 default=False,
1167 default=False,
1165 )
1168 )
1166 coreconfigitem('ui', 'logtemplate',
1169 coreconfigitem('ui', 'logtemplate',
1167 default=None,
1170 default=None,
1168 )
1171 )
1169 coreconfigitem('ui', 'merge',
1172 coreconfigitem('ui', 'merge',
1170 default=None,
1173 default=None,
1171 )
1174 )
1172 coreconfigitem('ui', 'mergemarkers',
1175 coreconfigitem('ui', 'mergemarkers',
1173 default='basic',
1176 default='basic',
1174 )
1177 )
1175 coreconfigitem('ui', 'mergemarkertemplate',
1178 coreconfigitem('ui', 'mergemarkertemplate',
1176 default=('{node|short} '
1179 default=('{node|short} '
1177 '{ifeq(tags, "tip", "", '
1180 '{ifeq(tags, "tip", "", '
1178 'ifeq(tags, "", "", "{tags} "))}'
1181 'ifeq(tags, "", "", "{tags} "))}'
1179 '{if(bookmarks, "{bookmarks} ")}'
1182 '{if(bookmarks, "{bookmarks} ")}'
1180 '{ifeq(branch, "default", "", "{branch} ")}'
1183 '{ifeq(branch, "default", "", "{branch} ")}'
1181 '- {author|user}: {desc|firstline}')
1184 '- {author|user}: {desc|firstline}')
1182 )
1185 )
1183 coreconfigitem('ui', 'message-output',
1186 coreconfigitem('ui', 'message-output',
1184 default='stdio',
1187 default='stdio',
1185 )
1188 )
1186 coreconfigitem('ui', 'nontty',
1189 coreconfigitem('ui', 'nontty',
1187 default=False,
1190 default=False,
1188 )
1191 )
1189 coreconfigitem('ui', 'origbackuppath',
1192 coreconfigitem('ui', 'origbackuppath',
1190 default=None,
1193 default=None,
1191 )
1194 )
1192 coreconfigitem('ui', 'paginate',
1195 coreconfigitem('ui', 'paginate',
1193 default=True,
1196 default=True,
1194 )
1197 )
1195 coreconfigitem('ui', 'patch',
1198 coreconfigitem('ui', 'patch',
1196 default=None,
1199 default=None,
1197 )
1200 )
1198 coreconfigitem('ui', 'pre-merge-tool-output-template',
1201 coreconfigitem('ui', 'pre-merge-tool-output-template',
1199 default=None,
1202 default=None,
1200 )
1203 )
1201 coreconfigitem('ui', 'portablefilenames',
1204 coreconfigitem('ui', 'portablefilenames',
1202 default='warn',
1205 default='warn',
1203 )
1206 )
1204 coreconfigitem('ui', 'promptecho',
1207 coreconfigitem('ui', 'promptecho',
1205 default=False,
1208 default=False,
1206 )
1209 )
1207 coreconfigitem('ui', 'quiet',
1210 coreconfigitem('ui', 'quiet',
1208 default=False,
1211 default=False,
1209 )
1212 )
1210 coreconfigitem('ui', 'quietbookmarkmove',
1213 coreconfigitem('ui', 'quietbookmarkmove',
1211 default=False,
1214 default=False,
1212 )
1215 )
1213 coreconfigitem('ui', 'relative-paths',
1216 coreconfigitem('ui', 'relative-paths',
1214 default='legacy',
1217 default='legacy',
1215 )
1218 )
1216 coreconfigitem('ui', 'remotecmd',
1219 coreconfigitem('ui', 'remotecmd',
1217 default='hg',
1220 default='hg',
1218 )
1221 )
1219 coreconfigitem('ui', 'report_untrusted',
1222 coreconfigitem('ui', 'report_untrusted',
1220 default=True,
1223 default=True,
1221 )
1224 )
1222 coreconfigitem('ui', 'rollback',
1225 coreconfigitem('ui', 'rollback',
1223 default=True,
1226 default=True,
1224 )
1227 )
1225 coreconfigitem('ui', 'signal-safe-lock',
1228 coreconfigitem('ui', 'signal-safe-lock',
1226 default=True,
1229 default=True,
1227 )
1230 )
1228 coreconfigitem('ui', 'slash',
1231 coreconfigitem('ui', 'slash',
1229 default=False,
1232 default=False,
1230 )
1233 )
1231 coreconfigitem('ui', 'ssh',
1234 coreconfigitem('ui', 'ssh',
1232 default='ssh',
1235 default='ssh',
1233 )
1236 )
1234 coreconfigitem('ui', 'ssherrorhint',
1237 coreconfigitem('ui', 'ssherrorhint',
1235 default=None,
1238 default=None,
1236 )
1239 )
1237 coreconfigitem('ui', 'statuscopies',
1240 coreconfigitem('ui', 'statuscopies',
1238 default=False,
1241 default=False,
1239 )
1242 )
1240 coreconfigitem('ui', 'strict',
1243 coreconfigitem('ui', 'strict',
1241 default=False,
1244 default=False,
1242 )
1245 )
1243 coreconfigitem('ui', 'style',
1246 coreconfigitem('ui', 'style',
1244 default='',
1247 default='',
1245 )
1248 )
1246 coreconfigitem('ui', 'supportcontact',
1249 coreconfigitem('ui', 'supportcontact',
1247 default=None,
1250 default=None,
1248 )
1251 )
1249 coreconfigitem('ui', 'textwidth',
1252 coreconfigitem('ui', 'textwidth',
1250 default=78,
1253 default=78,
1251 )
1254 )
1252 coreconfigitem('ui', 'timeout',
1255 coreconfigitem('ui', 'timeout',
1253 default='600',
1256 default='600',
1254 )
1257 )
1255 coreconfigitem('ui', 'timeout.warn',
1258 coreconfigitem('ui', 'timeout.warn',
1256 default=0,
1259 default=0,
1257 )
1260 )
1258 coreconfigitem('ui', 'traceback',
1261 coreconfigitem('ui', 'traceback',
1259 default=False,
1262 default=False,
1260 )
1263 )
1261 coreconfigitem('ui', 'tweakdefaults',
1264 coreconfigitem('ui', 'tweakdefaults',
1262 default=False,
1265 default=False,
1263 )
1266 )
1264 coreconfigitem('ui', 'username',
1267 coreconfigitem('ui', 'username',
1265 alias=[('ui', 'user')]
1268 alias=[('ui', 'user')]
1266 )
1269 )
1267 coreconfigitem('ui', 'verbose',
1270 coreconfigitem('ui', 'verbose',
1268 default=False,
1271 default=False,
1269 )
1272 )
1270 coreconfigitem('verify', 'skipflags',
1273 coreconfigitem('verify', 'skipflags',
1271 default=None,
1274 default=None,
1272 )
1275 )
1273 coreconfigitem('web', 'allowbz2',
1276 coreconfigitem('web', 'allowbz2',
1274 default=False,
1277 default=False,
1275 )
1278 )
1276 coreconfigitem('web', 'allowgz',
1279 coreconfigitem('web', 'allowgz',
1277 default=False,
1280 default=False,
1278 )
1281 )
1279 coreconfigitem('web', 'allow-pull',
1282 coreconfigitem('web', 'allow-pull',
1280 alias=[('web', 'allowpull')],
1283 alias=[('web', 'allowpull')],
1281 default=True,
1284 default=True,
1282 )
1285 )
1283 coreconfigitem('web', 'allow-push',
1286 coreconfigitem('web', 'allow-push',
1284 alias=[('web', 'allow_push')],
1287 alias=[('web', 'allow_push')],
1285 default=list,
1288 default=list,
1286 )
1289 )
1287 coreconfigitem('web', 'allowzip',
1290 coreconfigitem('web', 'allowzip',
1288 default=False,
1291 default=False,
1289 )
1292 )
1290 coreconfigitem('web', 'archivesubrepos',
1293 coreconfigitem('web', 'archivesubrepos',
1291 default=False,
1294 default=False,
1292 )
1295 )
1293 coreconfigitem('web', 'cache',
1296 coreconfigitem('web', 'cache',
1294 default=True,
1297 default=True,
1295 )
1298 )
1296 coreconfigitem('web', 'comparisoncontext',
1299 coreconfigitem('web', 'comparisoncontext',
1297 default=5,
1300 default=5,
1298 )
1301 )
1299 coreconfigitem('web', 'contact',
1302 coreconfigitem('web', 'contact',
1300 default=None,
1303 default=None,
1301 )
1304 )
1302 coreconfigitem('web', 'deny_push',
1305 coreconfigitem('web', 'deny_push',
1303 default=list,
1306 default=list,
1304 )
1307 )
1305 coreconfigitem('web', 'guessmime',
1308 coreconfigitem('web', 'guessmime',
1306 default=False,
1309 default=False,
1307 )
1310 )
1308 coreconfigitem('web', 'hidden',
1311 coreconfigitem('web', 'hidden',
1309 default=False,
1312 default=False,
1310 )
1313 )
1311 coreconfigitem('web', 'labels',
1314 coreconfigitem('web', 'labels',
1312 default=list,
1315 default=list,
1313 )
1316 )
1314 coreconfigitem('web', 'logoimg',
1317 coreconfigitem('web', 'logoimg',
1315 default='hglogo.png',
1318 default='hglogo.png',
1316 )
1319 )
1317 coreconfigitem('web', 'logourl',
1320 coreconfigitem('web', 'logourl',
1318 default='https://mercurial-scm.org/',
1321 default='https://mercurial-scm.org/',
1319 )
1322 )
1320 coreconfigitem('web', 'accesslog',
1323 coreconfigitem('web', 'accesslog',
1321 default='-',
1324 default='-',
1322 )
1325 )
1323 coreconfigitem('web', 'address',
1326 coreconfigitem('web', 'address',
1324 default='',
1327 default='',
1325 )
1328 )
1326 coreconfigitem('web', 'allow-archive',
1329 coreconfigitem('web', 'allow-archive',
1327 alias=[('web', 'allow_archive')],
1330 alias=[('web', 'allow_archive')],
1328 default=list,
1331 default=list,
1329 )
1332 )
1330 coreconfigitem('web', 'allow_read',
1333 coreconfigitem('web', 'allow_read',
1331 default=list,
1334 default=list,
1332 )
1335 )
1333 coreconfigitem('web', 'baseurl',
1336 coreconfigitem('web', 'baseurl',
1334 default=None,
1337 default=None,
1335 )
1338 )
1336 coreconfigitem('web', 'cacerts',
1339 coreconfigitem('web', 'cacerts',
1337 default=None,
1340 default=None,
1338 )
1341 )
1339 coreconfigitem('web', 'certificate',
1342 coreconfigitem('web', 'certificate',
1340 default=None,
1343 default=None,
1341 )
1344 )
1342 coreconfigitem('web', 'collapse',
1345 coreconfigitem('web', 'collapse',
1343 default=False,
1346 default=False,
1344 )
1347 )
1345 coreconfigitem('web', 'csp',
1348 coreconfigitem('web', 'csp',
1346 default=None,
1349 default=None,
1347 )
1350 )
1348 coreconfigitem('web', 'deny_read',
1351 coreconfigitem('web', 'deny_read',
1349 default=list,
1352 default=list,
1350 )
1353 )
1351 coreconfigitem('web', 'descend',
1354 coreconfigitem('web', 'descend',
1352 default=True,
1355 default=True,
1353 )
1356 )
1354 coreconfigitem('web', 'description',
1357 coreconfigitem('web', 'description',
1355 default="",
1358 default="",
1356 )
1359 )
1357 coreconfigitem('web', 'encoding',
1360 coreconfigitem('web', 'encoding',
1358 default=lambda: encoding.encoding,
1361 default=lambda: encoding.encoding,
1359 )
1362 )
1360 coreconfigitem('web', 'errorlog',
1363 coreconfigitem('web', 'errorlog',
1361 default='-',
1364 default='-',
1362 )
1365 )
1363 coreconfigitem('web', 'ipv6',
1366 coreconfigitem('web', 'ipv6',
1364 default=False,
1367 default=False,
1365 )
1368 )
1366 coreconfigitem('web', 'maxchanges',
1369 coreconfigitem('web', 'maxchanges',
1367 default=10,
1370 default=10,
1368 )
1371 )
1369 coreconfigitem('web', 'maxfiles',
1372 coreconfigitem('web', 'maxfiles',
1370 default=10,
1373 default=10,
1371 )
1374 )
1372 coreconfigitem('web', 'maxshortchanges',
1375 coreconfigitem('web', 'maxshortchanges',
1373 default=60,
1376 default=60,
1374 )
1377 )
1375 coreconfigitem('web', 'motd',
1378 coreconfigitem('web', 'motd',
1376 default='',
1379 default='',
1377 )
1380 )
1378 coreconfigitem('web', 'name',
1381 coreconfigitem('web', 'name',
1379 default=dynamicdefault,
1382 default=dynamicdefault,
1380 )
1383 )
1381 coreconfigitem('web', 'port',
1384 coreconfigitem('web', 'port',
1382 default=8000,
1385 default=8000,
1383 )
1386 )
1384 coreconfigitem('web', 'prefix',
1387 coreconfigitem('web', 'prefix',
1385 default='',
1388 default='',
1386 )
1389 )
1387 coreconfigitem('web', 'push_ssl',
1390 coreconfigitem('web', 'push_ssl',
1388 default=True,
1391 default=True,
1389 )
1392 )
1390 coreconfigitem('web', 'refreshinterval',
1393 coreconfigitem('web', 'refreshinterval',
1391 default=20,
1394 default=20,
1392 )
1395 )
1393 coreconfigitem('web', 'server-header',
1396 coreconfigitem('web', 'server-header',
1394 default=None,
1397 default=None,
1395 )
1398 )
1396 coreconfigitem('web', 'static',
1399 coreconfigitem('web', 'static',
1397 default=None,
1400 default=None,
1398 )
1401 )
1399 coreconfigitem('web', 'staticurl',
1402 coreconfigitem('web', 'staticurl',
1400 default=None,
1403 default=None,
1401 )
1404 )
1402 coreconfigitem('web', 'stripes',
1405 coreconfigitem('web', 'stripes',
1403 default=1,
1406 default=1,
1404 )
1407 )
1405 coreconfigitem('web', 'style',
1408 coreconfigitem('web', 'style',
1406 default='paper',
1409 default='paper',
1407 )
1410 )
1408 coreconfigitem('web', 'templates',
1411 coreconfigitem('web', 'templates',
1409 default=None,
1412 default=None,
1410 )
1413 )
1411 coreconfigitem('web', 'view',
1414 coreconfigitem('web', 'view',
1412 default='served',
1415 default='served',
1413 )
1416 )
1414 coreconfigitem('worker', 'backgroundclose',
1417 coreconfigitem('worker', 'backgroundclose',
1415 default=dynamicdefault,
1418 default=dynamicdefault,
1416 )
1419 )
1417 # Windows defaults to a limit of 512 open files. A buffer of 128
1420 # Windows defaults to a limit of 512 open files. A buffer of 128
1418 # should give us enough headway.
1421 # should give us enough headway.
1419 coreconfigitem('worker', 'backgroundclosemaxqueue',
1422 coreconfigitem('worker', 'backgroundclosemaxqueue',
1420 default=384,
1423 default=384,
1421 )
1424 )
1422 coreconfigitem('worker', 'backgroundcloseminfilecount',
1425 coreconfigitem('worker', 'backgroundcloseminfilecount',
1423 default=2048,
1426 default=2048,
1424 )
1427 )
1425 coreconfigitem('worker', 'backgroundclosethreadcount',
1428 coreconfigitem('worker', 'backgroundclosethreadcount',
1426 default=4,
1429 default=4,
1427 )
1430 )
1428 coreconfigitem('worker', 'enabled',
1431 coreconfigitem('worker', 'enabled',
1429 default=True,
1432 default=True,
1430 )
1433 )
1431 coreconfigitem('worker', 'numcpus',
1434 coreconfigitem('worker', 'numcpus',
1432 default=None,
1435 default=None,
1433 )
1436 )
1434
1437
1435 # Rebase related configuration moved to core because other extension are doing
1438 # Rebase related configuration moved to core because other extension are doing
1436 # strange things. For example, shelve import the extensions to reuse some bit
1439 # strange things. For example, shelve import the extensions to reuse some bit
1437 # without formally loading it.
1440 # without formally loading it.
1438 coreconfigitem('commands', 'rebase.requiredest',
1441 coreconfigitem('commands', 'rebase.requiredest',
1439 default=False,
1442 default=False,
1440 )
1443 )
1441 coreconfigitem('experimental', 'rebaseskipobsolete',
1444 coreconfigitem('experimental', 'rebaseskipobsolete',
1442 default=True,
1445 default=True,
1443 )
1446 )
1444 coreconfigitem('rebase', 'singletransaction',
1447 coreconfigitem('rebase', 'singletransaction',
1445 default=False,
1448 default=False,
1446 )
1449 )
1447 coreconfigitem('rebase', 'experimental.inmemory',
1450 coreconfigitem('rebase', 'experimental.inmemory',
1448 default=False,
1451 default=False,
1449 )
1452 )
@@ -1,927 +1,1001 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 _
14 from .i18n import _
15
15
16 from . import (
16 from . import (
17 match as matchmod,
17 match as matchmod,
18 node,
18 node,
19 pathutil,
19 pathutil,
20 scmutil,
20 scmutil,
21 util,
21 util,
22 )
22 )
23 from .utils import (
23 from .utils import (
24 stringutil,
24 stringutil,
25 )
25 )
26
26
27 def _findlimit(repo, ctxa, ctxb):
27 def _findlimit(repo, ctxa, ctxb):
28 """
28 """
29 Find the last revision that needs to be checked to ensure that a full
29 Find the last revision that needs to be checked to ensure that a full
30 transitive closure for file copies can be properly calculated.
30 transitive closure for file copies can be properly calculated.
31 Generally, this means finding the earliest revision number that's an
31 Generally, this means finding the earliest revision number that's an
32 ancestor of a or b but not both, except when a or b is a direct descendent
32 ancestor of a or b but not both, except when a or b is a direct descendent
33 of the other, in which case we can return the minimum revnum of a and b.
33 of the other, in which case we can return the minimum revnum of a and b.
34 """
34 """
35
35
36 # basic idea:
36 # basic idea:
37 # - mark a and b with different sides
37 # - mark a and b with different sides
38 # - if a parent's children are all on the same side, the parent is
38 # - if a parent's children are all on the same side, the parent is
39 # on that side, otherwise it is on no side
39 # on that side, otherwise it is on no side
40 # - walk the graph in topological order with the help of a heap;
40 # - walk the graph in topological order with the help of a heap;
41 # - add unseen parents to side map
41 # - add unseen parents to side map
42 # - clear side of any parent that has children on different sides
42 # - clear side of any parent that has children on different sides
43 # - track number of interesting revs that might still be on a side
43 # - track number of interesting revs that might still be on a side
44 # - track the lowest interesting rev seen
44 # - track the lowest interesting rev seen
45 # - quit when interesting revs is zero
45 # - quit when interesting revs is zero
46
46
47 cl = repo.changelog
47 cl = repo.changelog
48 wdirparents = None
48 wdirparents = None
49 a = ctxa.rev()
49 a = ctxa.rev()
50 b = ctxb.rev()
50 b = ctxb.rev()
51 if a is None:
51 if a is None:
52 wdirparents = (ctxa.p1(), ctxa.p2())
52 wdirparents = (ctxa.p1(), ctxa.p2())
53 a = node.wdirrev
53 a = node.wdirrev
54 if b is None:
54 if b is None:
55 assert not wdirparents
55 assert not wdirparents
56 wdirparents = (ctxb.p1(), ctxb.p2())
56 wdirparents = (ctxb.p1(), ctxb.p2())
57 b = node.wdirrev
57 b = node.wdirrev
58
58
59 side = {a: -1, b: 1}
59 side = {a: -1, b: 1}
60 visit = [-a, -b]
60 visit = [-a, -b]
61 heapq.heapify(visit)
61 heapq.heapify(visit)
62 interesting = len(visit)
62 interesting = len(visit)
63 limit = node.wdirrev
63 limit = node.wdirrev
64
64
65 while interesting:
65 while interesting:
66 r = -heapq.heappop(visit)
66 r = -heapq.heappop(visit)
67 if r == node.wdirrev:
67 if r == node.wdirrev:
68 parents = [pctx.rev() for pctx in wdirparents]
68 parents = [pctx.rev() for pctx in wdirparents]
69 else:
69 else:
70 parents = cl.parentrevs(r)
70 parents = cl.parentrevs(r)
71 if parents[1] == node.nullrev:
71 if parents[1] == node.nullrev:
72 parents = parents[:1]
72 parents = parents[:1]
73 for p in parents:
73 for p in parents:
74 if p not in side:
74 if p not in side:
75 # first time we see p; add it to visit
75 # first time we see p; add it to visit
76 side[p] = side[r]
76 side[p] = side[r]
77 if side[p]:
77 if side[p]:
78 interesting += 1
78 interesting += 1
79 heapq.heappush(visit, -p)
79 heapq.heappush(visit, -p)
80 elif side[p] and side[p] != side[r]:
80 elif side[p] and side[p] != side[r]:
81 # p was interesting but now we know better
81 # p was interesting but now we know better
82 side[p] = 0
82 side[p] = 0
83 interesting -= 1
83 interesting -= 1
84 if side[r]:
84 if side[r]:
85 limit = r # lowest rev visited
85 limit = r # lowest rev visited
86 interesting -= 1
86 interesting -= 1
87
87
88 # Consider the following flow (see test-commit-amend.t under issue4405):
88 # Consider the following flow (see test-commit-amend.t under issue4405):
89 # 1/ File 'a0' committed
89 # 1/ File 'a0' committed
90 # 2/ File renamed from 'a0' to 'a1' in a new commit (call it 'a1')
90 # 2/ File renamed from 'a0' to 'a1' in a new commit (call it 'a1')
91 # 3/ Move back to first commit
91 # 3/ Move back to first commit
92 # 4/ Create a new commit via revert to contents of 'a1' (call it 'a1-amend')
92 # 4/ Create a new commit via revert to contents of 'a1' (call it 'a1-amend')
93 # 5/ Rename file from 'a1' to 'a2' and commit --amend 'a1-msg'
93 # 5/ Rename file from 'a1' to 'a2' and commit --amend 'a1-msg'
94 #
94 #
95 # During the amend in step five, we will be in this state:
95 # During the amend in step five, we will be in this state:
96 #
96 #
97 # @ 3 temporary amend commit for a1-amend
97 # @ 3 temporary amend commit for a1-amend
98 # |
98 # |
99 # o 2 a1-amend
99 # o 2 a1-amend
100 # |
100 # |
101 # | o 1 a1
101 # | o 1 a1
102 # |/
102 # |/
103 # o 0 a0
103 # o 0 a0
104 #
104 #
105 # When _findlimit is called, a and b are revs 3 and 0, so limit will be 2,
105 # When _findlimit is called, a and b are revs 3 and 0, so limit will be 2,
106 # yet the filelog has the copy information in rev 1 and we will not look
106 # yet the filelog has the copy information in rev 1 and we will not look
107 # back far enough unless we also look at the a and b as candidates.
107 # back far enough unless we also look at the a and b as candidates.
108 # This only occurs when a is a descendent of b or visa-versa.
108 # This only occurs when a is a descendent of b or visa-versa.
109 return min(limit, a, b)
109 return min(limit, a, b)
110
110
111 def _chain(src, dst, a, b):
111 def _chain(src, dst, a, b):
112 """chain two sets of copies a->b"""
112 """chain two sets of copies a->b"""
113 t = a.copy()
113 t = a.copy()
114 for k, v in b.iteritems():
114 for k, v in b.iteritems():
115 if v in t:
115 if v in t:
116 # found a chain
116 # found a chain
117 if t[v] != k:
117 if t[v] != k:
118 # file wasn't renamed back to itself
118 # file wasn't renamed back to itself
119 t[k] = t[v]
119 t[k] = t[v]
120 if v not in dst:
120 if v not in dst:
121 # chain was a rename, not a copy
121 # chain was a rename, not a copy
122 del t[v]
122 del t[v]
123 if v in src:
123 if v in src:
124 # file is a copy of an existing file
124 # file is a copy of an existing file
125 t[k] = v
125 t[k] = v
126
126
127 for k, v in list(t.items()):
127 for k, v in list(t.items()):
128 # remove criss-crossed copies
128 # remove criss-crossed copies
129 if k in src and v in dst:
129 if k in src and v in dst:
130 del t[k]
130 del t[k]
131 # remove copies to files that were then removed
131 # remove copies to files that were then removed
132 elif k not in dst:
132 elif k not in dst:
133 del t[k]
133 del t[k]
134
134
135 return t
135 return t
136
136
137 def _tracefile(fctx, am, limit=node.nullrev):
137 def _tracefile(fctx, am, limit=node.nullrev):
138 """return file context that is the ancestor of fctx present in ancestor
138 """return file context that is the ancestor of fctx present in ancestor
139 manifest am, stopping after the first ancestor lower than limit"""
139 manifest am, stopping after the first ancestor lower than limit"""
140
140
141 for f in fctx.ancestors():
141 for f in fctx.ancestors():
142 if am.get(f.path(), None) == f.filenode():
142 if am.get(f.path(), None) == f.filenode():
143 return f
143 return f
144 if limit >= 0 and not f.isintroducedafter(limit):
144 if limit >= 0 and not f.isintroducedafter(limit):
145 return None
145 return None
146
146
147 def _dirstatecopies(repo, match=None):
147 def _dirstatecopies(repo, match=None):
148 ds = repo.dirstate
148 ds = repo.dirstate
149 c = ds.copies().copy()
149 c = ds.copies().copy()
150 for k in list(c):
150 for k in list(c):
151 if ds[k] not in 'anm' or (match and not match(k)):
151 if ds[k] not in 'anm' or (match and not match(k)):
152 del c[k]
152 del c[k]
153 return c
153 return c
154
154
155 def _computeforwardmissing(a, b, match=None):
155 def _computeforwardmissing(a, b, match=None):
156 """Computes which files are in b but not a.
156 """Computes which files are in b but not a.
157 This is its own function so extensions can easily wrap this call to see what
157 This is its own function so extensions can easily wrap this call to see what
158 files _forwardcopies is about to process.
158 files _forwardcopies is about to process.
159 """
159 """
160 ma = a.manifest()
160 ma = a.manifest()
161 mb = b.manifest()
161 mb = b.manifest()
162 return mb.filesnotin(ma, match=match)
162 return mb.filesnotin(ma, match=match)
163
163
164 def _committedforwardcopies(a, b, match):
164 def _committedforwardcopies(a, b, match):
165 """Like _forwardcopies(), but b.rev() cannot be None (working copy)"""
165 """Like _forwardcopies(), but b.rev() cannot be None (working copy)"""
166 # files might have to be traced back to the fctx parent of the last
166 # files might have to be traced back to the fctx parent of the last
167 # one-side-only changeset, but not further back than that
167 # one-side-only changeset, but not further back than that
168 repo = a._repo
168 repo = a._repo
169
170 if repo.ui.config('experimental', 'copies.read-from') == 'compatibility':
171 return _changesetforwardcopies(a, b, match)
172
169 debug = repo.ui.debugflag and repo.ui.configbool('devel', 'debug.copies')
173 debug = repo.ui.debugflag and repo.ui.configbool('devel', 'debug.copies')
170 dbg = repo.ui.debug
174 dbg = repo.ui.debug
171 if debug:
175 if debug:
172 dbg('debug.copies: looking into rename from %s to %s\n'
176 dbg('debug.copies: looking into rename from %s to %s\n'
173 % (a, b))
177 % (a, b))
174 limit = _findlimit(repo, a, b)
178 limit = _findlimit(repo, a, b)
175 if debug:
179 if debug:
176 dbg('debug.copies: search limit: %d\n' % limit)
180 dbg('debug.copies: search limit: %d\n' % limit)
177 am = a.manifest()
181 am = a.manifest()
178
182
179 # find where new files came from
183 # find where new files came from
180 # we currently don't try to find where old files went, too expensive
184 # we currently don't try to find where old files went, too expensive
181 # this means we can miss a case like 'hg rm b; hg cp a b'
185 # this means we can miss a case like 'hg rm b; hg cp a b'
182 cm = {}
186 cm = {}
183
187
184 # Computing the forward missing is quite expensive on large manifests, since
188 # Computing the forward missing is quite expensive on large manifests, since
185 # it compares the entire manifests. We can optimize it in the common use
189 # it compares the entire manifests. We can optimize it in the common use
186 # case of computing what copies are in a commit versus its parent (like
190 # case of computing what copies are in a commit versus its parent (like
187 # during a rebase or histedit). Note, we exclude merge commits from this
191 # during a rebase or histedit). Note, we exclude merge commits from this
188 # optimization, since the ctx.files() for a merge commit is not correct for
192 # optimization, since the ctx.files() for a merge commit is not correct for
189 # this comparison.
193 # this comparison.
190 forwardmissingmatch = match
194 forwardmissingmatch = match
191 if b.p1() == a and b.p2().node() == node.nullid:
195 if b.p1() == a and b.p2().node() == node.nullid:
192 filesmatcher = scmutil.matchfiles(a._repo, b.files())
196 filesmatcher = scmutil.matchfiles(a._repo, b.files())
193 forwardmissingmatch = matchmod.intersectmatchers(match, filesmatcher)
197 forwardmissingmatch = matchmod.intersectmatchers(match, filesmatcher)
194 missing = _computeforwardmissing(a, b, match=forwardmissingmatch)
198 missing = _computeforwardmissing(a, b, match=forwardmissingmatch)
195
199
196 ancestrycontext = a._repo.changelog.ancestors([b.rev()], inclusive=True)
200 ancestrycontext = a._repo.changelog.ancestors([b.rev()], inclusive=True)
197
201
198 if debug:
202 if debug:
199 dbg('debug.copies: missing file to search: %d\n' % len(missing))
203 dbg('debug.copies: missing file to search: %d\n' % len(missing))
200
204
201 for f in missing:
205 for f in missing:
202 if debug:
206 if debug:
203 dbg('debug.copies: tracing file: %s\n' % f)
207 dbg('debug.copies: tracing file: %s\n' % f)
204 fctx = b[f]
208 fctx = b[f]
205 fctx._ancestrycontext = ancestrycontext
209 fctx._ancestrycontext = ancestrycontext
206
210
207 if debug:
211 if debug:
208 start = util.timer()
212 start = util.timer()
209 ofctx = _tracefile(fctx, am, limit)
213 ofctx = _tracefile(fctx, am, limit)
210 if ofctx:
214 if ofctx:
211 if debug:
215 if debug:
212 dbg('debug.copies: rename of: %s\n' % ofctx._path)
216 dbg('debug.copies: rename of: %s\n' % ofctx._path)
213 cm[f] = ofctx.path()
217 cm[f] = ofctx.path()
214 if debug:
218 if debug:
215 dbg('debug.copies: time: %f seconds\n'
219 dbg('debug.copies: time: %f seconds\n'
216 % (util.timer() - start))
220 % (util.timer() - start))
217 return cm
221 return cm
218
222
223 def _changesetforwardcopies(a, b, match):
224 if a.rev() == node.nullrev:
225 return {}
226
227 repo = a.repo()
228 children = {}
229 cl = repo.changelog
230 missingrevs = cl.findmissingrevs(common=[a.rev()], heads=[b.rev()])
231 for r in missingrevs:
232 for p in cl.parentrevs(r):
233 if p == node.nullrev:
234 continue
235 if p not in children:
236 children[p] = [r]
237 else:
238 children[p].append(r)
239
240 roots = set(children) - set(missingrevs)
241 # 'work' contains 3-tuples of a (revision number, parent number, copies).
242 # The parent number is only used for knowing which parent the copies dict
243 # came from.
244 work = [(r, 1, {}) for r in roots]
245 heapq.heapify(work)
246 while work:
247 r, i1, copies1 = heapq.heappop(work)
248 if work and work[0][0] == r:
249 # We are tracing copies from both parents
250 r, i2, copies2 = heapq.heappop(work)
251 copies = {}
252 ctx = repo[r]
253 p1man, p2man = ctx.p1().manifest(), ctx.p2().manifest()
254 allcopies = set(copies1) | set(copies2)
255 # TODO: perhaps this filtering should be done as long as ctx
256 # is merge, whether or not we're tracing from both parent.
257 for dst in allcopies:
258 if not match(dst):
259 continue
260 if dst not in copies2:
261 # Copied on p1 side: mark as copy from p1 side if it didn't
262 # already exist on p2 side
263 if dst not in p2man:
264 copies[dst] = copies1[dst]
265 elif dst not in copies1:
266 # Copied on p2 side: mark as copy from p2 side if it didn't
267 # already exist on p1 side
268 if dst not in p1man:
269 copies[dst] = copies2[dst]
270 else:
271 # Copied on both sides: mark as copy from p1 side
272 copies[dst] = copies1[dst]
273 else:
274 copies = copies1
275 if r == b.rev():
276 return copies
277 for c in children[r]:
278 childctx = repo[c]
279 if r == childctx.p1().rev():
280 parent = 1
281 childcopies = childctx.p1copies()
282 else:
283 assert r == childctx.p2().rev()
284 parent = 2
285 childcopies = childctx.p2copies()
286 if not match.always():
287 childcopies = {dst: src for dst, src in childcopies.items()
288 if match(dst)}
289 childcopies = _chain(a, childctx, copies, childcopies)
290 heapq.heappush(work, (c, parent, childcopies))
291 assert False
292
219 def _forwardcopies(a, b, match=None):
293 def _forwardcopies(a, b, match=None):
220 """find {dst@b: src@a} copy mapping where a is an ancestor of b"""
294 """find {dst@b: src@a} copy mapping where a is an ancestor of b"""
221
295
222 match = a.repo().narrowmatch(match)
296 match = a.repo().narrowmatch(match)
223 # check for working copy
297 # check for working copy
224 if b.rev() is None:
298 if b.rev() is None:
225 if a == b.p1():
299 if a == b.p1():
226 # short-circuit to avoid issues with merge states
300 # short-circuit to avoid issues with merge states
227 return _dirstatecopies(b._repo, match)
301 return _dirstatecopies(b._repo, match)
228
302
229 cm = _committedforwardcopies(a, b.p1(), match)
303 cm = _committedforwardcopies(a, b.p1(), match)
230 # combine copies from dirstate if necessary
304 # combine copies from dirstate if necessary
231 return _chain(a, b, cm, _dirstatecopies(b._repo, match))
305 return _chain(a, b, cm, _dirstatecopies(b._repo, match))
232 return _committedforwardcopies(a, b, match)
306 return _committedforwardcopies(a, b, match)
233
307
234 def _backwardrenames(a, b, match):
308 def _backwardrenames(a, b, match):
235 if a._repo.ui.config('experimental', 'copytrace') == 'off':
309 if a._repo.ui.config('experimental', 'copytrace') == 'off':
236 return {}
310 return {}
237
311
238 # Even though we're not taking copies into account, 1:n rename situations
312 # Even though we're not taking copies into account, 1:n rename situations
239 # can still exist (e.g. hg cp a b; hg mv a c). In those cases we
313 # can still exist (e.g. hg cp a b; hg mv a c). In those cases we
240 # arbitrarily pick one of the renames.
314 # arbitrarily pick one of the renames.
241 # We don't want to pass in "match" here, since that would filter
315 # We don't want to pass in "match" here, since that would filter
242 # the destination by it. Since we're reversing the copies, we want
316 # the destination by it. Since we're reversing the copies, we want
243 # to filter the source instead.
317 # to filter the source instead.
244 f = _forwardcopies(b, a)
318 f = _forwardcopies(b, a)
245 r = {}
319 r = {}
246 for k, v in sorted(f.iteritems()):
320 for k, v in sorted(f.iteritems()):
247 if match and not match(v):
321 if match and not match(v):
248 continue
322 continue
249 # remove copies
323 # remove copies
250 if v in a:
324 if v in a:
251 continue
325 continue
252 r[v] = k
326 r[v] = k
253 return r
327 return r
254
328
255 def pathcopies(x, y, match=None):
329 def pathcopies(x, y, match=None):
256 """find {dst@y: src@x} copy mapping for directed compare"""
330 """find {dst@y: src@x} copy mapping for directed compare"""
257 repo = x._repo
331 repo = x._repo
258 debug = repo.ui.debugflag and repo.ui.configbool('devel', 'debug.copies')
332 debug = repo.ui.debugflag and repo.ui.configbool('devel', 'debug.copies')
259 if debug:
333 if debug:
260 repo.ui.debug('debug.copies: searching copies from %s to %s\n'
334 repo.ui.debug('debug.copies: searching copies from %s to %s\n'
261 % (x, y))
335 % (x, y))
262 if x == y or not x or not y:
336 if x == y or not x or not y:
263 return {}
337 return {}
264 a = y.ancestor(x)
338 a = y.ancestor(x)
265 if a == x:
339 if a == x:
266 if debug:
340 if debug:
267 repo.ui.debug('debug.copies: search mode: forward\n')
341 repo.ui.debug('debug.copies: search mode: forward\n')
268 return _forwardcopies(x, y, match=match)
342 return _forwardcopies(x, y, match=match)
269 if a == y:
343 if a == y:
270 if debug:
344 if debug:
271 repo.ui.debug('debug.copies: search mode: backward\n')
345 repo.ui.debug('debug.copies: search mode: backward\n')
272 return _backwardrenames(x, y, match=match)
346 return _backwardrenames(x, y, match=match)
273 if debug:
347 if debug:
274 repo.ui.debug('debug.copies: search mode: combined\n')
348 repo.ui.debug('debug.copies: search mode: combined\n')
275 return _chain(x, y, _backwardrenames(x, a, match=match),
349 return _chain(x, y, _backwardrenames(x, a, match=match),
276 _forwardcopies(a, y, match=match))
350 _forwardcopies(a, y, match=match))
277
351
278 def _computenonoverlap(repo, c1, c2, addedinm1, addedinm2, baselabel=''):
352 def _computenonoverlap(repo, c1, c2, addedinm1, addedinm2, baselabel=''):
279 """Computes, based on addedinm1 and addedinm2, the files exclusive to c1
353 """Computes, based on addedinm1 and addedinm2, the files exclusive to c1
280 and c2. This is its own function so extensions can easily wrap this call
354 and c2. This is its own function so extensions can easily wrap this call
281 to see what files mergecopies is about to process.
355 to see what files mergecopies is about to process.
282
356
283 Even though c1 and c2 are not used in this function, they are useful in
357 Even though c1 and c2 are not used in this function, they are useful in
284 other extensions for being able to read the file nodes of the changed files.
358 other extensions for being able to read the file nodes of the changed files.
285
359
286 "baselabel" can be passed to help distinguish the multiple computations
360 "baselabel" can be passed to help distinguish the multiple computations
287 done in the graft case.
361 done in the graft case.
288 """
362 """
289 u1 = sorted(addedinm1 - addedinm2)
363 u1 = sorted(addedinm1 - addedinm2)
290 u2 = sorted(addedinm2 - addedinm1)
364 u2 = sorted(addedinm2 - addedinm1)
291
365
292 header = " unmatched files in %s"
366 header = " unmatched files in %s"
293 if baselabel:
367 if baselabel:
294 header += ' (from %s)' % baselabel
368 header += ' (from %s)' % baselabel
295 if u1:
369 if u1:
296 repo.ui.debug("%s:\n %s\n" % (header % 'local', "\n ".join(u1)))
370 repo.ui.debug("%s:\n %s\n" % (header % 'local', "\n ".join(u1)))
297 if u2:
371 if u2:
298 repo.ui.debug("%s:\n %s\n" % (header % 'other', "\n ".join(u2)))
372 repo.ui.debug("%s:\n %s\n" % (header % 'other', "\n ".join(u2)))
299
373
300 return u1, u2
374 return u1, u2
301
375
302 def _makegetfctx(ctx):
376 def _makegetfctx(ctx):
303 """return a 'getfctx' function suitable for _checkcopies usage
377 """return a 'getfctx' function suitable for _checkcopies usage
304
378
305 We have to re-setup the function building 'filectx' for each
379 We have to re-setup the function building 'filectx' for each
306 '_checkcopies' to ensure the linkrev adjustment is properly setup for
380 '_checkcopies' to ensure the linkrev adjustment is properly setup for
307 each. Linkrev adjustment is important to avoid bug in rename
381 each. Linkrev adjustment is important to avoid bug in rename
308 detection. Moreover, having a proper '_ancestrycontext' setup ensures
382 detection. Moreover, having a proper '_ancestrycontext' setup ensures
309 the performance impact of this adjustment is kept limited. Without it,
383 the performance impact of this adjustment is kept limited. Without it,
310 each file could do a full dag traversal making the time complexity of
384 each file could do a full dag traversal making the time complexity of
311 the operation explode (see issue4537).
385 the operation explode (see issue4537).
312
386
313 This function exists here mostly to limit the impact on stable. Feel
387 This function exists here mostly to limit the impact on stable. Feel
314 free to refactor on default.
388 free to refactor on default.
315 """
389 """
316 rev = ctx.rev()
390 rev = ctx.rev()
317 repo = ctx._repo
391 repo = ctx._repo
318 ac = getattr(ctx, '_ancestrycontext', None)
392 ac = getattr(ctx, '_ancestrycontext', None)
319 if ac is None:
393 if ac is None:
320 revs = [rev]
394 revs = [rev]
321 if rev is None:
395 if rev is None:
322 revs = [p.rev() for p in ctx.parents()]
396 revs = [p.rev() for p in ctx.parents()]
323 ac = repo.changelog.ancestors(revs, inclusive=True)
397 ac = repo.changelog.ancestors(revs, inclusive=True)
324 ctx._ancestrycontext = ac
398 ctx._ancestrycontext = ac
325 def makectx(f, n):
399 def makectx(f, n):
326 if n in node.wdirfilenodeids: # in a working context?
400 if n in node.wdirfilenodeids: # in a working context?
327 if ctx.rev() is None:
401 if ctx.rev() is None:
328 return ctx.filectx(f)
402 return ctx.filectx(f)
329 return repo[None][f]
403 return repo[None][f]
330 fctx = repo.filectx(f, fileid=n)
404 fctx = repo.filectx(f, fileid=n)
331 # setup only needed for filectx not create from a changectx
405 # setup only needed for filectx not create from a changectx
332 fctx._ancestrycontext = ac
406 fctx._ancestrycontext = ac
333 fctx._descendantrev = rev
407 fctx._descendantrev = rev
334 return fctx
408 return fctx
335 return util.lrucachefunc(makectx)
409 return util.lrucachefunc(makectx)
336
410
337 def _combinecopies(copyfrom, copyto, finalcopy, diverge, incompletediverge):
411 def _combinecopies(copyfrom, copyto, finalcopy, diverge, incompletediverge):
338 """combine partial copy paths"""
412 """combine partial copy paths"""
339 remainder = {}
413 remainder = {}
340 for f in copyfrom:
414 for f in copyfrom:
341 if f in copyto:
415 if f in copyto:
342 finalcopy[copyto[f]] = copyfrom[f]
416 finalcopy[copyto[f]] = copyfrom[f]
343 del copyto[f]
417 del copyto[f]
344 for f in incompletediverge:
418 for f in incompletediverge:
345 assert f not in diverge
419 assert f not in diverge
346 ic = incompletediverge[f]
420 ic = incompletediverge[f]
347 if ic[0] in copyto:
421 if ic[0] in copyto:
348 diverge[f] = [copyto[ic[0]], ic[1]]
422 diverge[f] = [copyto[ic[0]], ic[1]]
349 else:
423 else:
350 remainder[f] = ic
424 remainder[f] = ic
351 return remainder
425 return remainder
352
426
353 def mergecopies(repo, c1, c2, base):
427 def mergecopies(repo, c1, c2, base):
354 """
428 """
355 The function calling different copytracing algorithms on the basis of config
429 The function calling different copytracing algorithms on the basis of config
356 which find moves and copies between context c1 and c2 that are relevant for
430 which find moves and copies between context c1 and c2 that are relevant for
357 merging. 'base' will be used as the merge base.
431 merging. 'base' will be used as the merge base.
358
432
359 Copytracing is used in commands like rebase, merge, unshelve, etc to merge
433 Copytracing is used in commands like rebase, merge, unshelve, etc to merge
360 files that were moved/ copied in one merge parent and modified in another.
434 files that were moved/ copied in one merge parent and modified in another.
361 For example:
435 For example:
362
436
363 o ---> 4 another commit
437 o ---> 4 another commit
364 |
438 |
365 | o ---> 3 commit that modifies a.txt
439 | o ---> 3 commit that modifies a.txt
366 | /
440 | /
367 o / ---> 2 commit that moves a.txt to b.txt
441 o / ---> 2 commit that moves a.txt to b.txt
368 |/
442 |/
369 o ---> 1 merge base
443 o ---> 1 merge base
370
444
371 If we try to rebase revision 3 on revision 4, since there is no a.txt in
445 If we try to rebase revision 3 on revision 4, since there is no a.txt in
372 revision 4, and if user have copytrace disabled, we prints the following
446 revision 4, and if user have copytrace disabled, we prints the following
373 message:
447 message:
374
448
375 ```other changed <file> which local deleted```
449 ```other changed <file> which local deleted```
376
450
377 Returns five dicts: "copy", "movewithdir", "diverge", "renamedelete" and
451 Returns five dicts: "copy", "movewithdir", "diverge", "renamedelete" and
378 "dirmove".
452 "dirmove".
379
453
380 "copy" is a mapping from destination name -> source name,
454 "copy" is a mapping from destination name -> source name,
381 where source is in c1 and destination is in c2 or vice-versa.
455 where source is in c1 and destination is in c2 or vice-versa.
382
456
383 "movewithdir" is a mapping from source name -> destination name,
457 "movewithdir" is a mapping from source name -> destination name,
384 where the file at source present in one context but not the other
458 where the file at source present in one context but not the other
385 needs to be moved to destination by the merge process, because the
459 needs to be moved to destination by the merge process, because the
386 other context moved the directory it is in.
460 other context moved the directory it is in.
387
461
388 "diverge" is a mapping of source name -> list of destination names
462 "diverge" is a mapping of source name -> list of destination names
389 for divergent renames.
463 for divergent renames.
390
464
391 "renamedelete" is a mapping of source name -> list of destination
465 "renamedelete" is a mapping of source name -> list of destination
392 names for files deleted in c1 that were renamed in c2 or vice-versa.
466 names for files deleted in c1 that were renamed in c2 or vice-versa.
393
467
394 "dirmove" is a mapping of detected source dir -> destination dir renames.
468 "dirmove" is a mapping of detected source dir -> destination dir renames.
395 This is needed for handling changes to new files previously grafted into
469 This is needed for handling changes to new files previously grafted into
396 renamed directories.
470 renamed directories.
397 """
471 """
398 # avoid silly behavior for update from empty dir
472 # avoid silly behavior for update from empty dir
399 if not c1 or not c2 or c1 == c2:
473 if not c1 or not c2 or c1 == c2:
400 return {}, {}, {}, {}, {}
474 return {}, {}, {}, {}, {}
401
475
402 narrowmatch = c1.repo().narrowmatch()
476 narrowmatch = c1.repo().narrowmatch()
403
477
404 # avoid silly behavior for parent -> working dir
478 # avoid silly behavior for parent -> working dir
405 if c2.node() is None and c1.node() == repo.dirstate.p1():
479 if c2.node() is None and c1.node() == repo.dirstate.p1():
406 return _dirstatecopies(repo, narrowmatch), {}, {}, {}, {}
480 return _dirstatecopies(repo, narrowmatch), {}, {}, {}, {}
407
481
408 copytracing = repo.ui.config('experimental', 'copytrace')
482 copytracing = repo.ui.config('experimental', 'copytrace')
409 boolctrace = stringutil.parsebool(copytracing)
483 boolctrace = stringutil.parsebool(copytracing)
410
484
411 # Copy trace disabling is explicitly below the node == p1 logic above
485 # Copy trace disabling is explicitly below the node == p1 logic above
412 # because the logic above is required for a simple copy to be kept across a
486 # because the logic above is required for a simple copy to be kept across a
413 # rebase.
487 # rebase.
414 if copytracing == 'heuristics':
488 if copytracing == 'heuristics':
415 # Do full copytracing if only non-public revisions are involved as
489 # Do full copytracing if only non-public revisions are involved as
416 # that will be fast enough and will also cover the copies which could
490 # that will be fast enough and will also cover the copies which could
417 # be missed by heuristics
491 # be missed by heuristics
418 if _isfullcopytraceable(repo, c1, base):
492 if _isfullcopytraceable(repo, c1, base):
419 return _fullcopytracing(repo, c1, c2, base)
493 return _fullcopytracing(repo, c1, c2, base)
420 return _heuristicscopytracing(repo, c1, c2, base)
494 return _heuristicscopytracing(repo, c1, c2, base)
421 elif boolctrace is False:
495 elif boolctrace is False:
422 # stringutil.parsebool() returns None when it is unable to parse the
496 # stringutil.parsebool() returns None when it is unable to parse the
423 # value, so we should rely on making sure copytracing is on such cases
497 # value, so we should rely on making sure copytracing is on such cases
424 return {}, {}, {}, {}, {}
498 return {}, {}, {}, {}, {}
425 else:
499 else:
426 return _fullcopytracing(repo, c1, c2, base)
500 return _fullcopytracing(repo, c1, c2, base)
427
501
428 def _isfullcopytraceable(repo, c1, base):
502 def _isfullcopytraceable(repo, c1, base):
429 """ Checks that if base, source and destination are all no-public branches,
503 """ Checks that if base, source and destination are all no-public branches,
430 if yes let's use the full copytrace algorithm for increased capabilities
504 if yes let's use the full copytrace algorithm for increased capabilities
431 since it will be fast enough.
505 since it will be fast enough.
432
506
433 `experimental.copytrace.sourcecommitlimit` can be used to set a limit for
507 `experimental.copytrace.sourcecommitlimit` can be used to set a limit for
434 number of changesets from c1 to base such that if number of changesets are
508 number of changesets from c1 to base such that if number of changesets are
435 more than the limit, full copytracing algorithm won't be used.
509 more than the limit, full copytracing algorithm won't be used.
436 """
510 """
437 if c1.rev() is None:
511 if c1.rev() is None:
438 c1 = c1.p1()
512 c1 = c1.p1()
439 if c1.mutable() and base.mutable():
513 if c1.mutable() and base.mutable():
440 sourcecommitlimit = repo.ui.configint('experimental',
514 sourcecommitlimit = repo.ui.configint('experimental',
441 'copytrace.sourcecommitlimit')
515 'copytrace.sourcecommitlimit')
442 commits = len(repo.revs('%d::%d', base.rev(), c1.rev()))
516 commits = len(repo.revs('%d::%d', base.rev(), c1.rev()))
443 return commits < sourcecommitlimit
517 return commits < sourcecommitlimit
444 return False
518 return False
445
519
446 def _fullcopytracing(repo, c1, c2, base):
520 def _fullcopytracing(repo, c1, c2, base):
447 """ The full copytracing algorithm which finds all the new files that were
521 """ The full copytracing algorithm which finds all the new files that were
448 added from merge base up to the top commit and for each file it checks if
522 added from merge base up to the top commit and for each file it checks if
449 this file was copied from another file.
523 this file was copied from another file.
450
524
451 This is pretty slow when a lot of changesets are involved but will track all
525 This is pretty slow when a lot of changesets are involved but will track all
452 the copies.
526 the copies.
453 """
527 """
454 # In certain scenarios (e.g. graft, update or rebase), base can be
528 # In certain scenarios (e.g. graft, update or rebase), base can be
455 # overridden We still need to know a real common ancestor in this case We
529 # overridden We still need to know a real common ancestor in this case We
456 # can't just compute _c1.ancestor(_c2) and compare it to ca, because there
530 # can't just compute _c1.ancestor(_c2) and compare it to ca, because there
457 # can be multiple common ancestors, e.g. in case of bidmerge. Because our
531 # can be multiple common ancestors, e.g. in case of bidmerge. Because our
458 # caller may not know if the revision passed in lieu of the CA is a genuine
532 # caller may not know if the revision passed in lieu of the CA is a genuine
459 # common ancestor or not without explicitly checking it, it's better to
533 # common ancestor or not without explicitly checking it, it's better to
460 # determine that here.
534 # determine that here.
461 #
535 #
462 # base.isancestorof(wc) is False, work around that
536 # base.isancestorof(wc) is False, work around that
463 _c1 = c1.p1() if c1.rev() is None else c1
537 _c1 = c1.p1() if c1.rev() is None else c1
464 _c2 = c2.p1() if c2.rev() is None else c2
538 _c2 = c2.p1() if c2.rev() is None else c2
465 # an endpoint is "dirty" if it isn't a descendant of the merge base
539 # an endpoint is "dirty" if it isn't a descendant of the merge base
466 # if we have a dirty endpoint, we need to trigger graft logic, and also
540 # if we have a dirty endpoint, we need to trigger graft logic, and also
467 # keep track of which endpoint is dirty
541 # keep track of which endpoint is dirty
468 dirtyc1 = not base.isancestorof(_c1)
542 dirtyc1 = not base.isancestorof(_c1)
469 dirtyc2 = not base.isancestorof(_c2)
543 dirtyc2 = not base.isancestorof(_c2)
470 graft = dirtyc1 or dirtyc2
544 graft = dirtyc1 or dirtyc2
471 tca = base
545 tca = base
472 if graft:
546 if graft:
473 tca = _c1.ancestor(_c2)
547 tca = _c1.ancestor(_c2)
474
548
475 limit = _findlimit(repo, c1, c2)
549 limit = _findlimit(repo, c1, c2)
476 repo.ui.debug(" searching for copies back to rev %d\n" % limit)
550 repo.ui.debug(" searching for copies back to rev %d\n" % limit)
477
551
478 m1 = c1.manifest()
552 m1 = c1.manifest()
479 m2 = c2.manifest()
553 m2 = c2.manifest()
480 mb = base.manifest()
554 mb = base.manifest()
481
555
482 # gather data from _checkcopies:
556 # gather data from _checkcopies:
483 # - diverge = record all diverges in this dict
557 # - diverge = record all diverges in this dict
484 # - copy = record all non-divergent copies in this dict
558 # - copy = record all non-divergent copies in this dict
485 # - fullcopy = record all copies in this dict
559 # - fullcopy = record all copies in this dict
486 # - incomplete = record non-divergent partial copies here
560 # - incomplete = record non-divergent partial copies here
487 # - incompletediverge = record divergent partial copies here
561 # - incompletediverge = record divergent partial copies here
488 diverge = {} # divergence data is shared
562 diverge = {} # divergence data is shared
489 incompletediverge = {}
563 incompletediverge = {}
490 data1 = {'copy': {},
564 data1 = {'copy': {},
491 'fullcopy': {},
565 'fullcopy': {},
492 'incomplete': {},
566 'incomplete': {},
493 'diverge': diverge,
567 'diverge': diverge,
494 'incompletediverge': incompletediverge,
568 'incompletediverge': incompletediverge,
495 }
569 }
496 data2 = {'copy': {},
570 data2 = {'copy': {},
497 'fullcopy': {},
571 'fullcopy': {},
498 'incomplete': {},
572 'incomplete': {},
499 'diverge': diverge,
573 'diverge': diverge,
500 'incompletediverge': incompletediverge,
574 'incompletediverge': incompletediverge,
501 }
575 }
502
576
503 # find interesting file sets from manifests
577 # find interesting file sets from manifests
504 addedinm1 = m1.filesnotin(mb, repo.narrowmatch())
578 addedinm1 = m1.filesnotin(mb, repo.narrowmatch())
505 addedinm2 = m2.filesnotin(mb, repo.narrowmatch())
579 addedinm2 = m2.filesnotin(mb, repo.narrowmatch())
506 bothnew = sorted(addedinm1 & addedinm2)
580 bothnew = sorted(addedinm1 & addedinm2)
507 if tca == base:
581 if tca == base:
508 # unmatched file from base
582 # unmatched file from base
509 u1r, u2r = _computenonoverlap(repo, c1, c2, addedinm1, addedinm2)
583 u1r, u2r = _computenonoverlap(repo, c1, c2, addedinm1, addedinm2)
510 u1u, u2u = u1r, u2r
584 u1u, u2u = u1r, u2r
511 else:
585 else:
512 # unmatched file from base (DAG rotation in the graft case)
586 # unmatched file from base (DAG rotation in the graft case)
513 u1r, u2r = _computenonoverlap(repo, c1, c2, addedinm1, addedinm2,
587 u1r, u2r = _computenonoverlap(repo, c1, c2, addedinm1, addedinm2,
514 baselabel='base')
588 baselabel='base')
515 # unmatched file from topological common ancestors (no DAG rotation)
589 # unmatched file from topological common ancestors (no DAG rotation)
516 # need to recompute this for directory move handling when grafting
590 # need to recompute this for directory move handling when grafting
517 mta = tca.manifest()
591 mta = tca.manifest()
518 u1u, u2u = _computenonoverlap(repo, c1, c2,
592 u1u, u2u = _computenonoverlap(repo, c1, c2,
519 m1.filesnotin(mta, repo.narrowmatch()),
593 m1.filesnotin(mta, repo.narrowmatch()),
520 m2.filesnotin(mta, repo.narrowmatch()),
594 m2.filesnotin(mta, repo.narrowmatch()),
521 baselabel='topological common ancestor')
595 baselabel='topological common ancestor')
522
596
523 for f in u1u:
597 for f in u1u:
524 _checkcopies(c1, c2, f, base, tca, dirtyc1, limit, data1)
598 _checkcopies(c1, c2, f, base, tca, dirtyc1, limit, data1)
525
599
526 for f in u2u:
600 for f in u2u:
527 _checkcopies(c2, c1, f, base, tca, dirtyc2, limit, data2)
601 _checkcopies(c2, c1, f, base, tca, dirtyc2, limit, data2)
528
602
529 copy = dict(data1['copy'])
603 copy = dict(data1['copy'])
530 copy.update(data2['copy'])
604 copy.update(data2['copy'])
531 fullcopy = dict(data1['fullcopy'])
605 fullcopy = dict(data1['fullcopy'])
532 fullcopy.update(data2['fullcopy'])
606 fullcopy.update(data2['fullcopy'])
533
607
534 if dirtyc1:
608 if dirtyc1:
535 _combinecopies(data2['incomplete'], data1['incomplete'], copy, diverge,
609 _combinecopies(data2['incomplete'], data1['incomplete'], copy, diverge,
536 incompletediverge)
610 incompletediverge)
537 else:
611 else:
538 _combinecopies(data1['incomplete'], data2['incomplete'], copy, diverge,
612 _combinecopies(data1['incomplete'], data2['incomplete'], copy, diverge,
539 incompletediverge)
613 incompletediverge)
540
614
541 renamedelete = {}
615 renamedelete = {}
542 renamedeleteset = set()
616 renamedeleteset = set()
543 divergeset = set()
617 divergeset = set()
544 for of, fl in list(diverge.items()):
618 for of, fl in list(diverge.items()):
545 if len(fl) == 1 or of in c1 or of in c2:
619 if len(fl) == 1 or of in c1 or of in c2:
546 del diverge[of] # not actually divergent, or not a rename
620 del diverge[of] # not actually divergent, or not a rename
547 if of not in c1 and of not in c2:
621 if of not in c1 and of not in c2:
548 # renamed on one side, deleted on the other side, but filter
622 # renamed on one side, deleted on the other side, but filter
549 # out files that have been renamed and then deleted
623 # out files that have been renamed and then deleted
550 renamedelete[of] = [f for f in fl if f in c1 or f in c2]
624 renamedelete[of] = [f for f in fl if f in c1 or f in c2]
551 renamedeleteset.update(fl) # reverse map for below
625 renamedeleteset.update(fl) # reverse map for below
552 else:
626 else:
553 divergeset.update(fl) # reverse map for below
627 divergeset.update(fl) # reverse map for below
554
628
555 if bothnew:
629 if bothnew:
556 repo.ui.debug(" unmatched files new in both:\n %s\n"
630 repo.ui.debug(" unmatched files new in both:\n %s\n"
557 % "\n ".join(bothnew))
631 % "\n ".join(bothnew))
558 bothdiverge = {}
632 bothdiverge = {}
559 bothincompletediverge = {}
633 bothincompletediverge = {}
560 remainder = {}
634 remainder = {}
561 both1 = {'copy': {},
635 both1 = {'copy': {},
562 'fullcopy': {},
636 'fullcopy': {},
563 'incomplete': {},
637 'incomplete': {},
564 'diverge': bothdiverge,
638 'diverge': bothdiverge,
565 'incompletediverge': bothincompletediverge
639 'incompletediverge': bothincompletediverge
566 }
640 }
567 both2 = {'copy': {},
641 both2 = {'copy': {},
568 'fullcopy': {},
642 'fullcopy': {},
569 'incomplete': {},
643 'incomplete': {},
570 'diverge': bothdiverge,
644 'diverge': bothdiverge,
571 'incompletediverge': bothincompletediverge
645 'incompletediverge': bothincompletediverge
572 }
646 }
573 for f in bothnew:
647 for f in bothnew:
574 _checkcopies(c1, c2, f, base, tca, dirtyc1, limit, both1)
648 _checkcopies(c1, c2, f, base, tca, dirtyc1, limit, both1)
575 _checkcopies(c2, c1, f, base, tca, dirtyc2, limit, both2)
649 _checkcopies(c2, c1, f, base, tca, dirtyc2, limit, both2)
576 if dirtyc1:
650 if dirtyc1:
577 # incomplete copies may only be found on the "dirty" side for bothnew
651 # incomplete copies may only be found on the "dirty" side for bothnew
578 assert not both2['incomplete']
652 assert not both2['incomplete']
579 remainder = _combinecopies({}, both1['incomplete'], copy, bothdiverge,
653 remainder = _combinecopies({}, both1['incomplete'], copy, bothdiverge,
580 bothincompletediverge)
654 bothincompletediverge)
581 elif dirtyc2:
655 elif dirtyc2:
582 assert not both1['incomplete']
656 assert not both1['incomplete']
583 remainder = _combinecopies({}, both2['incomplete'], copy, bothdiverge,
657 remainder = _combinecopies({}, both2['incomplete'], copy, bothdiverge,
584 bothincompletediverge)
658 bothincompletediverge)
585 else:
659 else:
586 # incomplete copies and divergences can't happen outside grafts
660 # incomplete copies and divergences can't happen outside grafts
587 assert not both1['incomplete']
661 assert not both1['incomplete']
588 assert not both2['incomplete']
662 assert not both2['incomplete']
589 assert not bothincompletediverge
663 assert not bothincompletediverge
590 for f in remainder:
664 for f in remainder:
591 assert f not in bothdiverge
665 assert f not in bothdiverge
592 ic = remainder[f]
666 ic = remainder[f]
593 if ic[0] in (m1 if dirtyc1 else m2):
667 if ic[0] in (m1 if dirtyc1 else m2):
594 # backed-out rename on one side, but watch out for deleted files
668 # backed-out rename on one side, but watch out for deleted files
595 bothdiverge[f] = ic
669 bothdiverge[f] = ic
596 for of, fl in bothdiverge.items():
670 for of, fl in bothdiverge.items():
597 if len(fl) == 2 and fl[0] == fl[1]:
671 if len(fl) == 2 and fl[0] == fl[1]:
598 copy[fl[0]] = of # not actually divergent, just matching renames
672 copy[fl[0]] = of # not actually divergent, just matching renames
599
673
600 if fullcopy and repo.ui.debugflag:
674 if fullcopy and repo.ui.debugflag:
601 repo.ui.debug(" all copies found (* = to merge, ! = divergent, "
675 repo.ui.debug(" all copies found (* = to merge, ! = divergent, "
602 "% = renamed and deleted):\n")
676 "% = renamed and deleted):\n")
603 for f in sorted(fullcopy):
677 for f in sorted(fullcopy):
604 note = ""
678 note = ""
605 if f in copy:
679 if f in copy:
606 note += "*"
680 note += "*"
607 if f in divergeset:
681 if f in divergeset:
608 note += "!"
682 note += "!"
609 if f in renamedeleteset:
683 if f in renamedeleteset:
610 note += "%"
684 note += "%"
611 repo.ui.debug(" src: '%s' -> dst: '%s' %s\n" % (fullcopy[f], f,
685 repo.ui.debug(" src: '%s' -> dst: '%s' %s\n" % (fullcopy[f], f,
612 note))
686 note))
613 del divergeset
687 del divergeset
614
688
615 if not fullcopy:
689 if not fullcopy:
616 return copy, {}, diverge, renamedelete, {}
690 return copy, {}, diverge, renamedelete, {}
617
691
618 repo.ui.debug(" checking for directory renames\n")
692 repo.ui.debug(" checking for directory renames\n")
619
693
620 # generate a directory move map
694 # generate a directory move map
621 d1, d2 = c1.dirs(), c2.dirs()
695 d1, d2 = c1.dirs(), c2.dirs()
622 # Hack for adding '', which is not otherwise added, to d1 and d2
696 # Hack for adding '', which is not otherwise added, to d1 and d2
623 d1.addpath('/')
697 d1.addpath('/')
624 d2.addpath('/')
698 d2.addpath('/')
625 invalid = set()
699 invalid = set()
626 dirmove = {}
700 dirmove = {}
627
701
628 # examine each file copy for a potential directory move, which is
702 # examine each file copy for a potential directory move, which is
629 # when all the files in a directory are moved to a new directory
703 # when all the files in a directory are moved to a new directory
630 for dst, src in fullcopy.iteritems():
704 for dst, src in fullcopy.iteritems():
631 dsrc, ddst = pathutil.dirname(src), pathutil.dirname(dst)
705 dsrc, ddst = pathutil.dirname(src), pathutil.dirname(dst)
632 if dsrc in invalid:
706 if dsrc in invalid:
633 # already seen to be uninteresting
707 # already seen to be uninteresting
634 continue
708 continue
635 elif dsrc in d1 and ddst in d1:
709 elif dsrc in d1 and ddst in d1:
636 # directory wasn't entirely moved locally
710 # directory wasn't entirely moved locally
637 invalid.add(dsrc)
711 invalid.add(dsrc)
638 elif dsrc in d2 and ddst in d2:
712 elif dsrc in d2 and ddst in d2:
639 # directory wasn't entirely moved remotely
713 # directory wasn't entirely moved remotely
640 invalid.add(dsrc)
714 invalid.add(dsrc)
641 elif dsrc in dirmove and dirmove[dsrc] != ddst:
715 elif dsrc in dirmove and dirmove[dsrc] != ddst:
642 # files from the same directory moved to two different places
716 # files from the same directory moved to two different places
643 invalid.add(dsrc)
717 invalid.add(dsrc)
644 else:
718 else:
645 # looks good so far
719 # looks good so far
646 dirmove[dsrc] = ddst
720 dirmove[dsrc] = ddst
647
721
648 for i in invalid:
722 for i in invalid:
649 if i in dirmove:
723 if i in dirmove:
650 del dirmove[i]
724 del dirmove[i]
651 del d1, d2, invalid
725 del d1, d2, invalid
652
726
653 if not dirmove:
727 if not dirmove:
654 return copy, {}, diverge, renamedelete, {}
728 return copy, {}, diverge, renamedelete, {}
655
729
656 dirmove = {k + "/": v + "/" for k, v in dirmove.iteritems()}
730 dirmove = {k + "/": v + "/" for k, v in dirmove.iteritems()}
657
731
658 for d in dirmove:
732 for d in dirmove:
659 repo.ui.debug(" discovered dir src: '%s' -> dst: '%s'\n" %
733 repo.ui.debug(" discovered dir src: '%s' -> dst: '%s'\n" %
660 (d, dirmove[d]))
734 (d, dirmove[d]))
661
735
662 movewithdir = {}
736 movewithdir = {}
663 # check unaccounted nonoverlapping files against directory moves
737 # check unaccounted nonoverlapping files against directory moves
664 for f in u1r + u2r:
738 for f in u1r + u2r:
665 if f not in fullcopy:
739 if f not in fullcopy:
666 for d in dirmove:
740 for d in dirmove:
667 if f.startswith(d):
741 if f.startswith(d):
668 # new file added in a directory that was moved, move it
742 # new file added in a directory that was moved, move it
669 df = dirmove[d] + f[len(d):]
743 df = dirmove[d] + f[len(d):]
670 if df not in copy:
744 if df not in copy:
671 movewithdir[f] = df
745 movewithdir[f] = df
672 repo.ui.debug((" pending file src: '%s' -> "
746 repo.ui.debug((" pending file src: '%s' -> "
673 "dst: '%s'\n") % (f, df))
747 "dst: '%s'\n") % (f, df))
674 break
748 break
675
749
676 return copy, movewithdir, diverge, renamedelete, dirmove
750 return copy, movewithdir, diverge, renamedelete, dirmove
677
751
678 def _heuristicscopytracing(repo, c1, c2, base):
752 def _heuristicscopytracing(repo, c1, c2, base):
679 """ Fast copytracing using filename heuristics
753 """ Fast copytracing using filename heuristics
680
754
681 Assumes that moves or renames are of following two types:
755 Assumes that moves or renames are of following two types:
682
756
683 1) Inside a directory only (same directory name but different filenames)
757 1) Inside a directory only (same directory name but different filenames)
684 2) Move from one directory to another
758 2) Move from one directory to another
685 (same filenames but different directory names)
759 (same filenames but different directory names)
686
760
687 Works only when there are no merge commits in the "source branch".
761 Works only when there are no merge commits in the "source branch".
688 Source branch is commits from base up to c2 not including base.
762 Source branch is commits from base up to c2 not including base.
689
763
690 If merge is involved it fallbacks to _fullcopytracing().
764 If merge is involved it fallbacks to _fullcopytracing().
691
765
692 Can be used by setting the following config:
766 Can be used by setting the following config:
693
767
694 [experimental]
768 [experimental]
695 copytrace = heuristics
769 copytrace = heuristics
696
770
697 In some cases the copy/move candidates found by heuristics can be very large
771 In some cases the copy/move candidates found by heuristics can be very large
698 in number and that will make the algorithm slow. The number of possible
772 in number and that will make the algorithm slow. The number of possible
699 candidates to check can be limited by using the config
773 candidates to check can be limited by using the config
700 `experimental.copytrace.movecandidateslimit` which defaults to 100.
774 `experimental.copytrace.movecandidateslimit` which defaults to 100.
701 """
775 """
702
776
703 if c1.rev() is None:
777 if c1.rev() is None:
704 c1 = c1.p1()
778 c1 = c1.p1()
705 if c2.rev() is None:
779 if c2.rev() is None:
706 c2 = c2.p1()
780 c2 = c2.p1()
707
781
708 copies = {}
782 copies = {}
709
783
710 changedfiles = set()
784 changedfiles = set()
711 m1 = c1.manifest()
785 m1 = c1.manifest()
712 if not repo.revs('%d::%d', base.rev(), c2.rev()):
786 if not repo.revs('%d::%d', base.rev(), c2.rev()):
713 # If base is not in c2 branch, we switch to fullcopytracing
787 # If base is not in c2 branch, we switch to fullcopytracing
714 repo.ui.debug("switching to full copytracing as base is not "
788 repo.ui.debug("switching to full copytracing as base is not "
715 "an ancestor of c2\n")
789 "an ancestor of c2\n")
716 return _fullcopytracing(repo, c1, c2, base)
790 return _fullcopytracing(repo, c1, c2, base)
717
791
718 ctx = c2
792 ctx = c2
719 while ctx != base:
793 while ctx != base:
720 if len(ctx.parents()) == 2:
794 if len(ctx.parents()) == 2:
721 # To keep things simple let's not handle merges
795 # To keep things simple let's not handle merges
722 repo.ui.debug("switching to full copytracing because of merges\n")
796 repo.ui.debug("switching to full copytracing because of merges\n")
723 return _fullcopytracing(repo, c1, c2, base)
797 return _fullcopytracing(repo, c1, c2, base)
724 changedfiles.update(ctx.files())
798 changedfiles.update(ctx.files())
725 ctx = ctx.p1()
799 ctx = ctx.p1()
726
800
727 cp = _forwardcopies(base, c2)
801 cp = _forwardcopies(base, c2)
728 for dst, src in cp.iteritems():
802 for dst, src in cp.iteritems():
729 if src in m1:
803 if src in m1:
730 copies[dst] = src
804 copies[dst] = src
731
805
732 # file is missing if it isn't present in the destination, but is present in
806 # file is missing if it isn't present in the destination, but is present in
733 # the base and present in the source.
807 # the base and present in the source.
734 # Presence in the base is important to exclude added files, presence in the
808 # Presence in the base is important to exclude added files, presence in the
735 # source is important to exclude removed files.
809 # source is important to exclude removed files.
736 filt = lambda f: f not in m1 and f in base and f in c2
810 filt = lambda f: f not in m1 and f in base and f in c2
737 missingfiles = [f for f in changedfiles if filt(f)]
811 missingfiles = [f for f in changedfiles if filt(f)]
738
812
739 if missingfiles:
813 if missingfiles:
740 basenametofilename = collections.defaultdict(list)
814 basenametofilename = collections.defaultdict(list)
741 dirnametofilename = collections.defaultdict(list)
815 dirnametofilename = collections.defaultdict(list)
742
816
743 for f in m1.filesnotin(base.manifest()):
817 for f in m1.filesnotin(base.manifest()):
744 basename = os.path.basename(f)
818 basename = os.path.basename(f)
745 dirname = os.path.dirname(f)
819 dirname = os.path.dirname(f)
746 basenametofilename[basename].append(f)
820 basenametofilename[basename].append(f)
747 dirnametofilename[dirname].append(f)
821 dirnametofilename[dirname].append(f)
748
822
749 for f in missingfiles:
823 for f in missingfiles:
750 basename = os.path.basename(f)
824 basename = os.path.basename(f)
751 dirname = os.path.dirname(f)
825 dirname = os.path.dirname(f)
752 samebasename = basenametofilename[basename]
826 samebasename = basenametofilename[basename]
753 samedirname = dirnametofilename[dirname]
827 samedirname = dirnametofilename[dirname]
754 movecandidates = samebasename + samedirname
828 movecandidates = samebasename + samedirname
755 # f is guaranteed to be present in c2, that's why
829 # f is guaranteed to be present in c2, that's why
756 # c2.filectx(f) won't fail
830 # c2.filectx(f) won't fail
757 f2 = c2.filectx(f)
831 f2 = c2.filectx(f)
758 # we can have a lot of candidates which can slow down the heuristics
832 # we can have a lot of candidates which can slow down the heuristics
759 # config value to limit the number of candidates moves to check
833 # config value to limit the number of candidates moves to check
760 maxcandidates = repo.ui.configint('experimental',
834 maxcandidates = repo.ui.configint('experimental',
761 'copytrace.movecandidateslimit')
835 'copytrace.movecandidateslimit')
762
836
763 if len(movecandidates) > maxcandidates:
837 if len(movecandidates) > maxcandidates:
764 repo.ui.status(_("skipping copytracing for '%s', more "
838 repo.ui.status(_("skipping copytracing for '%s', more "
765 "candidates than the limit: %d\n")
839 "candidates than the limit: %d\n")
766 % (f, len(movecandidates)))
840 % (f, len(movecandidates)))
767 continue
841 continue
768
842
769 for candidate in movecandidates:
843 for candidate in movecandidates:
770 f1 = c1.filectx(candidate)
844 f1 = c1.filectx(candidate)
771 if _related(f1, f2):
845 if _related(f1, f2):
772 # if there are a few related copies then we'll merge
846 # if there are a few related copies then we'll merge
773 # changes into all of them. This matches the behaviour
847 # changes into all of them. This matches the behaviour
774 # of upstream copytracing
848 # of upstream copytracing
775 copies[candidate] = f
849 copies[candidate] = f
776
850
777 return copies, {}, {}, {}, {}
851 return copies, {}, {}, {}, {}
778
852
779 def _related(f1, f2):
853 def _related(f1, f2):
780 """return True if f1 and f2 filectx have a common ancestor
854 """return True if f1 and f2 filectx have a common ancestor
781
855
782 Walk back to common ancestor to see if the two files originate
856 Walk back to common ancestor to see if the two files originate
783 from the same file. Since workingfilectx's rev() is None it messes
857 from the same file. Since workingfilectx's rev() is None it messes
784 up the integer comparison logic, hence the pre-step check for
858 up the integer comparison logic, hence the pre-step check for
785 None (f1 and f2 can only be workingfilectx's initially).
859 None (f1 and f2 can only be workingfilectx's initially).
786 """
860 """
787
861
788 if f1 == f2:
862 if f1 == f2:
789 return True # a match
863 return True # a match
790
864
791 g1, g2 = f1.ancestors(), f2.ancestors()
865 g1, g2 = f1.ancestors(), f2.ancestors()
792 try:
866 try:
793 f1r, f2r = f1.linkrev(), f2.linkrev()
867 f1r, f2r = f1.linkrev(), f2.linkrev()
794
868
795 if f1r is None:
869 if f1r is None:
796 f1 = next(g1)
870 f1 = next(g1)
797 if f2r is None:
871 if f2r is None:
798 f2 = next(g2)
872 f2 = next(g2)
799
873
800 while True:
874 while True:
801 f1r, f2r = f1.linkrev(), f2.linkrev()
875 f1r, f2r = f1.linkrev(), f2.linkrev()
802 if f1r > f2r:
876 if f1r > f2r:
803 f1 = next(g1)
877 f1 = next(g1)
804 elif f2r > f1r:
878 elif f2r > f1r:
805 f2 = next(g2)
879 f2 = next(g2)
806 else: # f1 and f2 point to files in the same linkrev
880 else: # f1 and f2 point to files in the same linkrev
807 return f1 == f2 # true if they point to the same file
881 return f1 == f2 # true if they point to the same file
808 except StopIteration:
882 except StopIteration:
809 return False
883 return False
810
884
811 def _checkcopies(srcctx, dstctx, f, base, tca, remotebase, limit, data):
885 def _checkcopies(srcctx, dstctx, f, base, tca, remotebase, limit, data):
812 """
886 """
813 check possible copies of f from msrc to mdst
887 check possible copies of f from msrc to mdst
814
888
815 srcctx = starting context for f in msrc
889 srcctx = starting context for f in msrc
816 dstctx = destination context for f in mdst
890 dstctx = destination context for f in mdst
817 f = the filename to check (as in msrc)
891 f = the filename to check (as in msrc)
818 base = the changectx used as a merge base
892 base = the changectx used as a merge base
819 tca = topological common ancestor for graft-like scenarios
893 tca = topological common ancestor for graft-like scenarios
820 remotebase = True if base is outside tca::srcctx, False otherwise
894 remotebase = True if base is outside tca::srcctx, False otherwise
821 limit = the rev number to not search beyond
895 limit = the rev number to not search beyond
822 data = dictionary of dictionary to store copy data. (see mergecopies)
896 data = dictionary of dictionary to store copy data. (see mergecopies)
823
897
824 note: limit is only an optimization, and provides no guarantee that
898 note: limit is only an optimization, and provides no guarantee that
825 irrelevant revisions will not be visited
899 irrelevant revisions will not be visited
826 there is no easy way to make this algorithm stop in a guaranteed way
900 there is no easy way to make this algorithm stop in a guaranteed way
827 once it "goes behind a certain revision".
901 once it "goes behind a certain revision".
828 """
902 """
829
903
830 msrc = srcctx.manifest()
904 msrc = srcctx.manifest()
831 mdst = dstctx.manifest()
905 mdst = dstctx.manifest()
832 mb = base.manifest()
906 mb = base.manifest()
833 mta = tca.manifest()
907 mta = tca.manifest()
834 # Might be true if this call is about finding backward renames,
908 # Might be true if this call is about finding backward renames,
835 # This happens in the case of grafts because the DAG is then rotated.
909 # This happens in the case of grafts because the DAG is then rotated.
836 # If the file exists in both the base and the source, we are not looking
910 # If the file exists in both the base and the source, we are not looking
837 # for a rename on the source side, but on the part of the DAG that is
911 # for a rename on the source side, but on the part of the DAG that is
838 # traversed backwards.
912 # traversed backwards.
839 #
913 #
840 # In the case there is both backward and forward renames (before and after
914 # In the case there is both backward and forward renames (before and after
841 # the base) this is more complicated as we must detect a divergence.
915 # the base) this is more complicated as we must detect a divergence.
842 # We use 'backwards = False' in that case.
916 # We use 'backwards = False' in that case.
843 backwards = not remotebase and base != tca and f in mb
917 backwards = not remotebase and base != tca and f in mb
844 getsrcfctx = _makegetfctx(srcctx)
918 getsrcfctx = _makegetfctx(srcctx)
845 getdstfctx = _makegetfctx(dstctx)
919 getdstfctx = _makegetfctx(dstctx)
846
920
847 if msrc[f] == mb.get(f) and not remotebase:
921 if msrc[f] == mb.get(f) and not remotebase:
848 # Nothing to merge
922 # Nothing to merge
849 return
923 return
850
924
851 of = None
925 of = None
852 seen = {f}
926 seen = {f}
853 for oc in getsrcfctx(f, msrc[f]).ancestors():
927 for oc in getsrcfctx(f, msrc[f]).ancestors():
854 of = oc.path()
928 of = oc.path()
855 if of in seen:
929 if of in seen:
856 # check limit late - grab last rename before
930 # check limit late - grab last rename before
857 if oc.linkrev() < limit:
931 if oc.linkrev() < limit:
858 break
932 break
859 continue
933 continue
860 seen.add(of)
934 seen.add(of)
861
935
862 # remember for dir rename detection
936 # remember for dir rename detection
863 if backwards:
937 if backwards:
864 data['fullcopy'][of] = f # grafting backwards through renames
938 data['fullcopy'][of] = f # grafting backwards through renames
865 else:
939 else:
866 data['fullcopy'][f] = of
940 data['fullcopy'][f] = of
867 if of not in mdst:
941 if of not in mdst:
868 continue # no match, keep looking
942 continue # no match, keep looking
869 if mdst[of] == mb.get(of):
943 if mdst[of] == mb.get(of):
870 return # no merge needed, quit early
944 return # no merge needed, quit early
871 c2 = getdstfctx(of, mdst[of])
945 c2 = getdstfctx(of, mdst[of])
872 # c2 might be a plain new file on added on destination side that is
946 # c2 might be a plain new file on added on destination side that is
873 # unrelated to the droids we are looking for.
947 # unrelated to the droids we are looking for.
874 cr = _related(oc, c2)
948 cr = _related(oc, c2)
875 if cr and (of == f or of == c2.path()): # non-divergent
949 if cr and (of == f or of == c2.path()): # non-divergent
876 if backwards:
950 if backwards:
877 data['copy'][of] = f
951 data['copy'][of] = f
878 elif of in mb:
952 elif of in mb:
879 data['copy'][f] = of
953 data['copy'][f] = of
880 elif remotebase: # special case: a <- b <- a -> b "ping-pong" rename
954 elif remotebase: # special case: a <- b <- a -> b "ping-pong" rename
881 data['copy'][of] = f
955 data['copy'][of] = f
882 del data['fullcopy'][f]
956 del data['fullcopy'][f]
883 data['fullcopy'][of] = f
957 data['fullcopy'][of] = f
884 else: # divergence w.r.t. graft CA on one side of topological CA
958 else: # divergence w.r.t. graft CA on one side of topological CA
885 for sf in seen:
959 for sf in seen:
886 if sf in mb:
960 if sf in mb:
887 assert sf not in data['diverge']
961 assert sf not in data['diverge']
888 data['diverge'][sf] = [f, of]
962 data['diverge'][sf] = [f, of]
889 break
963 break
890 return
964 return
891
965
892 if of in mta:
966 if of in mta:
893 if backwards or remotebase:
967 if backwards or remotebase:
894 data['incomplete'][of] = f
968 data['incomplete'][of] = f
895 else:
969 else:
896 for sf in seen:
970 for sf in seen:
897 if sf in mb:
971 if sf in mb:
898 if tca == base:
972 if tca == base:
899 data['diverge'].setdefault(sf, []).append(f)
973 data['diverge'].setdefault(sf, []).append(f)
900 else:
974 else:
901 data['incompletediverge'][sf] = [of, f]
975 data['incompletediverge'][sf] = [of, f]
902 return
976 return
903
977
904 def duplicatecopies(repo, wctx, rev, fromrev, skiprev=None):
978 def duplicatecopies(repo, wctx, rev, fromrev, skiprev=None):
905 """reproduce copies from fromrev to rev in the dirstate
979 """reproduce copies from fromrev to rev in the dirstate
906
980
907 If skiprev is specified, it's a revision that should be used to
981 If skiprev is specified, it's a revision that should be used to
908 filter copy records. Any copies that occur between fromrev and
982 filter copy records. Any copies that occur between fromrev and
909 skiprev will not be duplicated, even if they appear in the set of
983 skiprev will not be duplicated, even if they appear in the set of
910 copies between fromrev and rev.
984 copies between fromrev and rev.
911 """
985 """
912 exclude = {}
986 exclude = {}
913 ctraceconfig = repo.ui.config('experimental', 'copytrace')
987 ctraceconfig = repo.ui.config('experimental', 'copytrace')
914 bctrace = stringutil.parsebool(ctraceconfig)
988 bctrace = stringutil.parsebool(ctraceconfig)
915 if (skiprev is not None and
989 if (skiprev is not None and
916 (ctraceconfig == 'heuristics' or bctrace or bctrace is None)):
990 (ctraceconfig == 'heuristics' or bctrace or bctrace is None)):
917 # copytrace='off' skips this line, but not the entire function because
991 # copytrace='off' skips this line, but not the entire function because
918 # the line below is O(size of the repo) during a rebase, while the rest
992 # the line below is O(size of the repo) during a rebase, while the rest
919 # of the function is much faster (and is required for carrying copy
993 # of the function is much faster (and is required for carrying copy
920 # metadata across the rebase anyway).
994 # metadata across the rebase anyway).
921 exclude = pathcopies(repo[fromrev], repo[skiprev])
995 exclude = pathcopies(repo[fromrev], repo[skiprev])
922 for dst, src in pathcopies(repo[fromrev], repo[rev]).iteritems():
996 for dst, src in pathcopies(repo[fromrev], repo[rev]).iteritems():
923 # copies.pathcopies returns backward renames, so dst might not
997 # copies.pathcopies returns backward renames, so dst might not
924 # actually be in the dirstate
998 # actually be in the dirstate
925 if dst in exclude:
999 if dst in exclude:
926 continue
1000 continue
927 wctx[dst].markcopied(src)
1001 wctx[dst].markcopied(src)
@@ -1,484 +1,493 b''
1 #testcases filelog compatibility
1
2
2 $ cat >> $HGRCPATH << EOF
3 $ cat >> $HGRCPATH << EOF
3 > [alias]
4 > [alias]
4 > l = log -G -T '{rev} {desc}\n{files}\n'
5 > l = log -G -T '{rev} {desc}\n{files}\n'
5 > EOF
6 > EOF
6
7
8 #if compatibility
9 $ cat >> $HGRCPATH << EOF
10 > [experimental]
11 > copies.read-from = compatibility
12 > EOF
13 #endif
14
7 $ REPONUM=0
15 $ REPONUM=0
8 $ newrepo() {
16 $ newrepo() {
9 > cd $TESTTMP
17 > cd $TESTTMP
10 > REPONUM=`expr $REPONUM + 1`
18 > REPONUM=`expr $REPONUM + 1`
11 > hg init repo-$REPONUM
19 > hg init repo-$REPONUM
12 > cd repo-$REPONUM
20 > cd repo-$REPONUM
13 > }
21 > }
14
22
15 Simple rename case
23 Simple rename case
16 $ newrepo
24 $ newrepo
17 $ echo x > x
25 $ echo x > x
18 $ hg ci -Aqm 'add x'
26 $ hg ci -Aqm 'add x'
19 $ hg mv x y
27 $ hg mv x y
20 $ hg debugp1copies
28 $ hg debugp1copies
21 x -> y
29 x -> y
22 $ hg debugp2copies
30 $ hg debugp2copies
23 $ hg ci -m 'rename x to y'
31 $ hg ci -m 'rename x to y'
24 $ hg l
32 $ hg l
25 @ 1 rename x to y
33 @ 1 rename x to y
26 | x y
34 | x y
27 o 0 add x
35 o 0 add x
28 x
36 x
29 $ hg debugp1copies -r 1
37 $ hg debugp1copies -r 1
30 x -> y
38 x -> y
31 $ hg debugpathcopies 0 1
39 $ hg debugpathcopies 0 1
32 x -> y
40 x -> y
33 $ hg debugpathcopies 1 0
41 $ hg debugpathcopies 1 0
34 y -> x
42 y -> x
35 Test filtering copies by path. We do filtering by destination.
43 Test filtering copies by path. We do filtering by destination.
36 $ hg debugpathcopies 0 1 x
44 $ hg debugpathcopies 0 1 x
37 $ hg debugpathcopies 1 0 x
45 $ hg debugpathcopies 1 0 x
38 y -> x
46 y -> x
39 $ hg debugpathcopies 0 1 y
47 $ hg debugpathcopies 0 1 y
40 x -> y
48 x -> y
41 $ hg debugpathcopies 1 0 y
49 $ hg debugpathcopies 1 0 y
42
50
43 Copy a file onto another file
51 Copy a file onto another file
44 $ newrepo
52 $ newrepo
45 $ echo x > x
53 $ echo x > x
46 $ echo y > y
54 $ echo y > y
47 $ hg ci -Aqm 'add x and y'
55 $ hg ci -Aqm 'add x and y'
48 $ hg cp -f x y
56 $ hg cp -f x y
49 $ hg debugp1copies
57 $ hg debugp1copies
50 x -> y
58 x -> y
51 $ hg debugp2copies
59 $ hg debugp2copies
52 $ hg ci -m 'copy x onto y'
60 $ hg ci -m 'copy x onto y'
53 $ hg l
61 $ hg l
54 @ 1 copy x onto y
62 @ 1 copy x onto y
55 | y
63 | y
56 o 0 add x and y
64 o 0 add x and y
57 x y
65 x y
58 $ hg debugp1copies -r 1
66 $ hg debugp1copies -r 1
59 x -> y
67 x -> y
60 Incorrectly doesn't show the rename
68 Incorrectly doesn't show the rename
61 $ hg debugpathcopies 0 1
69 $ hg debugpathcopies 0 1
62
70
63 Copy a file onto another file with same content. If metadata is stored in changeset, this does not
71 Copy a file onto another file with same content. If metadata is stored in changeset, this does not
64 produce a new filelog entry. The changeset's "files" entry should still list the file.
72 produce a new filelog entry. The changeset's "files" entry should still list the file.
65 $ newrepo
73 $ newrepo
66 $ echo x > x
74 $ echo x > x
67 $ echo x > x2
75 $ echo x > x2
68 $ hg ci -Aqm 'add x and x2 with same content'
76 $ hg ci -Aqm 'add x and x2 with same content'
69 $ hg cp -f x x2
77 $ hg cp -f x x2
70 $ hg ci -m 'copy x onto x2'
78 $ hg ci -m 'copy x onto x2'
71 $ hg l
79 $ hg l
72 @ 1 copy x onto x2
80 @ 1 copy x onto x2
73 | x2
81 | x2
74 o 0 add x and x2 with same content
82 o 0 add x and x2 with same content
75 x x2
83 x x2
76 $ hg debugp1copies -r 1
84 $ hg debugp1copies -r 1
77 x -> x2
85 x -> x2
78 Incorrectly doesn't show the rename
86 Incorrectly doesn't show the rename
79 $ hg debugpathcopies 0 1
87 $ hg debugpathcopies 0 1
80
88
81 Copy a file, then delete destination, then copy again. This does not create a new filelog entry.
89 Copy a file, then delete destination, then copy again. This does not create a new filelog entry.
82 $ newrepo
90 $ newrepo
83 $ echo x > x
91 $ echo x > x
84 $ hg ci -Aqm 'add x'
92 $ hg ci -Aqm 'add x'
85 $ hg cp x y
93 $ hg cp x y
86 $ hg ci -m 'copy x to y'
94 $ hg ci -m 'copy x to y'
87 $ hg rm y
95 $ hg rm y
88 $ hg ci -m 'remove y'
96 $ hg ci -m 'remove y'
89 $ hg cp -f x y
97 $ hg cp -f x y
90 $ hg ci -m 'copy x onto y (again)'
98 $ hg ci -m 'copy x onto y (again)'
91 $ hg l
99 $ hg l
92 @ 3 copy x onto y (again)
100 @ 3 copy x onto y (again)
93 | y
101 | y
94 o 2 remove y
102 o 2 remove y
95 | y
103 | y
96 o 1 copy x to y
104 o 1 copy x to y
97 | y
105 | y
98 o 0 add x
106 o 0 add x
99 x
107 x
100 $ hg debugp1copies -r 3
108 $ hg debugp1copies -r 3
101 x -> y
109 x -> y
102 $ hg debugpathcopies 0 3
110 $ hg debugpathcopies 0 3
103 x -> y
111 x -> y
104
112
105 Rename file in a loop: x->y->z->x
113 Rename file in a loop: x->y->z->x
106 $ newrepo
114 $ newrepo
107 $ echo x > x
115 $ echo x > x
108 $ hg ci -Aqm 'add x'
116 $ hg ci -Aqm 'add x'
109 $ hg mv x y
117 $ hg mv x y
110 $ hg debugp1copies
118 $ hg debugp1copies
111 x -> y
119 x -> y
112 $ hg debugp2copies
120 $ hg debugp2copies
113 $ hg ci -m 'rename x to y'
121 $ hg ci -m 'rename x to y'
114 $ hg mv y z
122 $ hg mv y z
115 $ hg ci -m 'rename y to z'
123 $ hg ci -m 'rename y to z'
116 $ hg mv z x
124 $ hg mv z x
117 $ hg ci -m 'rename z to x'
125 $ hg ci -m 'rename z to x'
118 $ hg l
126 $ hg l
119 @ 3 rename z to x
127 @ 3 rename z to x
120 | x z
128 | x z
121 o 2 rename y to z
129 o 2 rename y to z
122 | y z
130 | y z
123 o 1 rename x to y
131 o 1 rename x to y
124 | x y
132 | x y
125 o 0 add x
133 o 0 add x
126 x
134 x
127 $ hg debugpathcopies 0 3
135 $ hg debugpathcopies 0 3
128
136
129 Copy x to y, then remove y, then add back y. With copy metadata in the changeset, this could easily
137 Copy x to y, then remove y, then add back y. With copy metadata in the changeset, this could easily
130 end up reporting y as copied from x (if we don't unmark it as a copy when it's removed).
138 end up reporting y as copied from x (if we don't unmark it as a copy when it's removed).
131 $ newrepo
139 $ newrepo
132 $ echo x > x
140 $ echo x > x
133 $ hg ci -Aqm 'add x'
141 $ hg ci -Aqm 'add x'
134 $ hg mv x y
142 $ hg mv x y
135 $ hg ci -m 'rename x to y'
143 $ hg ci -m 'rename x to y'
136 $ hg rm y
144 $ hg rm y
137 $ hg ci -qm 'remove y'
145 $ hg ci -qm 'remove y'
138 $ echo x > y
146 $ echo x > y
139 $ hg ci -Aqm 'add back y'
147 $ hg ci -Aqm 'add back y'
140 $ hg l
148 $ hg l
141 @ 3 add back y
149 @ 3 add back y
142 | y
150 | y
143 o 2 remove y
151 o 2 remove y
144 | y
152 | y
145 o 1 rename x to y
153 o 1 rename x to y
146 | x y
154 | x y
147 o 0 add x
155 o 0 add x
148 x
156 x
149 $ hg debugp1copies -r 3
157 $ hg debugp1copies -r 3
150 $ hg debugpathcopies 0 3
158 $ hg debugpathcopies 0 3
151
159
152 Copy x to z, then remove z, then copy x2 (same content as x) to z. With copy metadata in the
160 Copy x to z, then remove z, then copy x2 (same content as x) to z. With copy metadata in the
153 changeset, the two copies here will have the same filelog entry, so ctx['z'].introrev() might point
161 changeset, the two copies here will have the same filelog entry, so ctx['z'].introrev() might point
154 to the first commit that added the file. We should still report the copy as being from x2.
162 to the first commit that added the file. We should still report the copy as being from x2.
155 $ newrepo
163 $ newrepo
156 $ echo x > x
164 $ echo x > x
157 $ echo x > x2
165 $ echo x > x2
158 $ hg ci -Aqm 'add x and x2 with same content'
166 $ hg ci -Aqm 'add x and x2 with same content'
159 $ hg cp x z
167 $ hg cp x z
160 $ hg ci -qm 'copy x to z'
168 $ hg ci -qm 'copy x to z'
161 $ hg rm z
169 $ hg rm z
162 $ hg ci -m 'remove z'
170 $ hg ci -m 'remove z'
163 $ hg cp x2 z
171 $ hg cp x2 z
164 $ hg ci -m 'copy x2 to z'
172 $ hg ci -m 'copy x2 to z'
165 $ hg l
173 $ hg l
166 @ 3 copy x2 to z
174 @ 3 copy x2 to z
167 | z
175 | z
168 o 2 remove z
176 o 2 remove z
169 | z
177 | z
170 o 1 copy x to z
178 o 1 copy x to z
171 | z
179 | z
172 o 0 add x and x2 with same content
180 o 0 add x and x2 with same content
173 x x2
181 x x2
174 $ hg debugp1copies -r 3
182 $ hg debugp1copies -r 3
175 x2 -> z
183 x2 -> z
176 $ hg debugpathcopies 0 3
184 $ hg debugpathcopies 0 3
177 x2 -> z
185 x2 -> z
178
186
179 Create x and y, then rename them both to the same name, but on different sides of a fork
187 Create x and y, then rename them both to the same name, but on different sides of a fork
180 $ newrepo
188 $ newrepo
181 $ echo x > x
189 $ echo x > x
182 $ echo y > y
190 $ echo y > y
183 $ hg ci -Aqm 'add x and y'
191 $ hg ci -Aqm 'add x and y'
184 $ hg mv x z
192 $ hg mv x z
185 $ hg ci -qm 'rename x to z'
193 $ hg ci -qm 'rename x to z'
186 $ hg co -q 0
194 $ hg co -q 0
187 $ hg mv y z
195 $ hg mv y z
188 $ hg ci -qm 'rename y to z'
196 $ hg ci -qm 'rename y to z'
189 $ hg l
197 $ hg l
190 @ 2 rename y to z
198 @ 2 rename y to z
191 | y z
199 | y z
192 | o 1 rename x to z
200 | o 1 rename x to z
193 |/ x z
201 |/ x z
194 o 0 add x and y
202 o 0 add x and y
195 x y
203 x y
196 $ hg debugpathcopies 1 2
204 $ hg debugpathcopies 1 2
197 z -> x
205 z -> x
198 y -> z
206 y -> z
199
207
200 Fork renames x to y on one side and removes x on the other
208 Fork renames x to y on one side and removes x on the other
201 $ newrepo
209 $ newrepo
202 $ echo x > x
210 $ echo x > x
203 $ hg ci -Aqm 'add x'
211 $ hg ci -Aqm 'add x'
204 $ hg mv x y
212 $ hg mv x y
205 $ hg ci -m 'rename x to y'
213 $ hg ci -m 'rename x to y'
206 $ hg co -q 0
214 $ hg co -q 0
207 $ hg rm x
215 $ hg rm x
208 $ hg ci -m 'remove x'
216 $ hg ci -m 'remove x'
209 created new head
217 created new head
210 $ hg l
218 $ hg l
211 @ 2 remove x
219 @ 2 remove x
212 | x
220 | x
213 | o 1 rename x to y
221 | o 1 rename x to y
214 |/ x y
222 |/ x y
215 o 0 add x
223 o 0 add x
216 x
224 x
217 $ hg debugpathcopies 1 2
225 $ hg debugpathcopies 1 2
218
226
219 Copies via null revision (there shouldn't be any)
227 Copies via null revision (there shouldn't be any)
220 $ newrepo
228 $ newrepo
221 $ echo x > x
229 $ echo x > x
222 $ hg ci -Aqm 'add x'
230 $ hg ci -Aqm 'add x'
223 $ hg cp x y
231 $ hg cp x y
224 $ hg ci -m 'copy x to y'
232 $ hg ci -m 'copy x to y'
225 $ hg co -q null
233 $ hg co -q null
226 $ echo x > x
234 $ echo x > x
227 $ hg ci -Aqm 'add x (again)'
235 $ hg ci -Aqm 'add x (again)'
228 $ hg l
236 $ hg l
229 @ 2 add x (again)
237 @ 2 add x (again)
230 x
238 x
231 o 1 copy x to y
239 o 1 copy x to y
232 | y
240 | y
233 o 0 add x
241 o 0 add x
234 x
242 x
235 $ hg debugpathcopies 1 2
243 $ hg debugpathcopies 1 2
236 $ hg debugpathcopies 2 1
244 $ hg debugpathcopies 2 1
237
245
238 Merge rename from other branch
246 Merge rename from other branch
239 $ newrepo
247 $ newrepo
240 $ echo x > x
248 $ echo x > x
241 $ hg ci -Aqm 'add x'
249 $ hg ci -Aqm 'add x'
242 $ hg mv x y
250 $ hg mv x y
243 $ hg ci -m 'rename x to y'
251 $ hg ci -m 'rename x to y'
244 $ hg co -q 0
252 $ hg co -q 0
245 $ echo z > z
253 $ echo z > z
246 $ hg ci -Aqm 'add z'
254 $ hg ci -Aqm 'add z'
247 $ hg merge -q 1
255 $ hg merge -q 1
248 $ hg debugp1copies
256 $ hg debugp1copies
249 $ hg debugp2copies
257 $ hg debugp2copies
250 $ hg ci -m 'merge rename from p2'
258 $ hg ci -m 'merge rename from p2'
251 $ hg l
259 $ hg l
252 @ 3 merge rename from p2
260 @ 3 merge rename from p2
253 |\ x
261 |\ x
254 | o 2 add z
262 | o 2 add z
255 | | z
263 | | z
256 o | 1 rename x to y
264 o | 1 rename x to y
257 |/ x y
265 |/ x y
258 o 0 add x
266 o 0 add x
259 x
267 x
260 Perhaps we should indicate the rename here, but `hg status` is documented to be weird during
268 Perhaps we should indicate the rename here, but `hg status` is documented to be weird during
261 merges, so...
269 merges, so...
262 $ hg debugp1copies -r 3
270 $ hg debugp1copies -r 3
263 $ hg debugp2copies -r 3
271 $ hg debugp2copies -r 3
264 $ hg debugpathcopies 0 3
272 $ hg debugpathcopies 0 3
265 x -> y
273 x -> y
266 $ hg debugpathcopies 1 2
274 $ hg debugpathcopies 1 2
267 y -> x
275 y -> x
268 $ hg debugpathcopies 1 3
276 $ hg debugpathcopies 1 3
269 $ hg debugpathcopies 2 3
277 $ hg debugpathcopies 2 3
270 x -> y
278 x -> y
271
279
272 Copy file from either side in a merge
280 Copy file from either side in a merge
273 $ newrepo
281 $ newrepo
274 $ echo x > x
282 $ echo x > x
275 $ hg ci -Aqm 'add x'
283 $ hg ci -Aqm 'add x'
276 $ hg co -q null
284 $ hg co -q null
277 $ echo y > y
285 $ echo y > y
278 $ hg ci -Aqm 'add y'
286 $ hg ci -Aqm 'add y'
279 $ hg merge -q 0
287 $ hg merge -q 0
280 $ hg cp y z
288 $ hg cp y z
281 $ hg debugp1copies
289 $ hg debugp1copies
282 y -> z
290 y -> z
283 $ hg debugp2copies
291 $ hg debugp2copies
284 $ hg ci -m 'copy file from p1 in merge'
292 $ hg ci -m 'copy file from p1 in merge'
285 $ hg co -q 1
293 $ hg co -q 1
286 $ hg merge -q 0
294 $ hg merge -q 0
287 $ hg cp x z
295 $ hg cp x z
288 $ hg debugp1copies
296 $ hg debugp1copies
289 $ hg debugp2copies
297 $ hg debugp2copies
290 x -> z
298 x -> z
291 $ hg ci -qm 'copy file from p2 in merge'
299 $ hg ci -qm 'copy file from p2 in merge'
292 $ hg l
300 $ hg l
293 @ 3 copy file from p2 in merge
301 @ 3 copy file from p2 in merge
294 |\ z
302 |\ z
295 +---o 2 copy file from p1 in merge
303 +---o 2 copy file from p1 in merge
296 | |/ z
304 | |/ z
297 | o 1 add y
305 | o 1 add y
298 | y
306 | y
299 o 0 add x
307 o 0 add x
300 x
308 x
301 $ hg debugp1copies -r 2
309 $ hg debugp1copies -r 2
302 y -> z
310 y -> z
303 $ hg debugp2copies -r 2
311 $ hg debugp2copies -r 2
304 $ hg debugpathcopies 1 2
312 $ hg debugpathcopies 1 2
305 y -> z
313 y -> z
306 $ hg debugpathcopies 0 2
314 $ hg debugpathcopies 0 2
307 $ hg debugp1copies -r 3
315 $ hg debugp1copies -r 3
308 $ hg debugp2copies -r 3
316 $ hg debugp2copies -r 3
309 x -> z
317 x -> z
310 $ hg debugpathcopies 1 3
318 $ hg debugpathcopies 1 3
311 $ hg debugpathcopies 0 3
319 $ hg debugpathcopies 0 3
312 x -> z
320 x -> z
313
321
314 Copy file that exists on both sides of the merge, same content on both sides
322 Copy file that exists on both sides of the merge, same content on both sides
315 $ newrepo
323 $ newrepo
316 $ echo x > x
324 $ echo x > x
317 $ hg ci -Aqm 'add x on branch 1'
325 $ hg ci -Aqm 'add x on branch 1'
318 $ hg co -q null
326 $ hg co -q null
319 $ echo x > x
327 $ echo x > x
320 $ hg ci -Aqm 'add x on branch 2'
328 $ hg ci -Aqm 'add x on branch 2'
321 $ hg merge -q 0
329 $ hg merge -q 0
322 $ hg cp x z
330 $ hg cp x z
323 $ hg debugp1copies
331 $ hg debugp1copies
324 x -> z
332 x -> z
325 $ hg debugp2copies
333 $ hg debugp2copies
326 $ hg ci -qm 'merge'
334 $ hg ci -qm 'merge'
327 $ hg l
335 $ hg l
328 @ 2 merge
336 @ 2 merge
329 |\ z
337 |\ z
330 | o 1 add x on branch 2
338 | o 1 add x on branch 2
331 | x
339 | x
332 o 0 add x on branch 1
340 o 0 add x on branch 1
333 x
341 x
334 $ hg debugp1copies -r 2
342 $ hg debugp1copies -r 2
335 x -> z
343 x -> z
336 $ hg debugp2copies -r 2
344 $ hg debugp2copies -r 2
337 It's a little weird that it shows up on both sides
345 It's a little weird that it shows up on both sides
338 $ hg debugpathcopies 1 2
346 $ hg debugpathcopies 1 2
339 x -> z
347 x -> z
340 $ hg debugpathcopies 0 2
348 $ hg debugpathcopies 0 2
341 x -> z
349 x -> z (filelog !)
342
350
343 Copy file that exists on both sides of the merge, different content
351 Copy file that exists on both sides of the merge, different content
344 $ newrepo
352 $ newrepo
345 $ echo branch1 > x
353 $ echo branch1 > x
346 $ hg ci -Aqm 'add x on branch 1'
354 $ hg ci -Aqm 'add x on branch 1'
347 $ hg co -q null
355 $ hg co -q null
348 $ echo branch2 > x
356 $ echo branch2 > x
349 $ hg ci -Aqm 'add x on branch 2'
357 $ hg ci -Aqm 'add x on branch 2'
350 $ hg merge -q 0
358 $ hg merge -q 0
351 warning: conflicts while merging x! (edit, then use 'hg resolve --mark')
359 warning: conflicts while merging x! (edit, then use 'hg resolve --mark')
352 [1]
360 [1]
353 $ echo resolved > x
361 $ echo resolved > x
354 $ hg resolve -m x
362 $ hg resolve -m x
355 (no more unresolved files)
363 (no more unresolved files)
356 $ hg cp x z
364 $ hg cp x z
357 $ hg debugp1copies
365 $ hg debugp1copies
358 x -> z
366 x -> z
359 $ hg debugp2copies
367 $ hg debugp2copies
360 $ hg ci -qm 'merge'
368 $ hg ci -qm 'merge'
361 $ hg l
369 $ hg l
362 @ 2 merge
370 @ 2 merge
363 |\ x z
371 |\ x z
364 | o 1 add x on branch 2
372 | o 1 add x on branch 2
365 | x
373 | x
366 o 0 add x on branch 1
374 o 0 add x on branch 1
367 x
375 x
368 $ hg debugp1copies -r 2
376 $ hg debugp1copies -r 2
369 $ hg debugp2copies -r 2
377 $ hg debugp2copies -r 2
370 x -> z
378 x -> z
371 $ hg debugpathcopies 1 2
379 $ hg debugpathcopies 1 2
372 $ hg debugpathcopies 0 2
380 $ hg debugpathcopies 0 2
373 x -> z
381 x -> z
374
382
375 Copy x->y on one side of merge and copy x->z on the other side. Pathcopies from one parent
383 Copy x->y on one side of merge and copy x->z on the other side. Pathcopies from one parent
376 of the merge to the merge should include the copy from the other side.
384 of the merge to the merge should include the copy from the other side.
377 $ newrepo
385 $ newrepo
378 $ echo x > x
386 $ echo x > x
379 $ hg ci -Aqm 'add x'
387 $ hg ci -Aqm 'add x'
380 $ hg cp x y
388 $ hg cp x y
381 $ hg ci -qm 'copy x to y'
389 $ hg ci -qm 'copy x to y'
382 $ hg co -q 0
390 $ hg co -q 0
383 $ hg cp x z
391 $ hg cp x z
384 $ hg ci -qm 'copy x to z'
392 $ hg ci -qm 'copy x to z'
385 $ hg merge -q 1
393 $ hg merge -q 1
386 $ hg ci -m 'merge copy x->y and copy x->z'
394 $ hg ci -m 'merge copy x->y and copy x->z'
387 $ hg l
395 $ hg l
388 @ 3 merge copy x->y and copy x->z
396 @ 3 merge copy x->y and copy x->z
389 |\
397 |\
390 | o 2 copy x to z
398 | o 2 copy x to z
391 | | z
399 | | z
392 o | 1 copy x to y
400 o | 1 copy x to y
393 |/ y
401 |/ y
394 o 0 add x
402 o 0 add x
395 x
403 x
396 $ hg debugp1copies -r 3
404 $ hg debugp1copies -r 3
397 $ hg debugp2copies -r 3
405 $ hg debugp2copies -r 3
398 $ hg debugpathcopies 2 3
406 $ hg debugpathcopies 2 3
399 x -> y
407 x -> y
400 $ hg debugpathcopies 1 3
408 $ hg debugpathcopies 1 3
401 x -> z
409 x -> z
402
410
403 Copy x to y on one side of merge, create y and rename to z on the other side. Pathcopies from the
411 Copy x to y on one side of merge, create y and rename to z on the other side. Pathcopies from the
404 first side should not include the y->z rename since y didn't exist in the merge base.
412 first side should not include the y->z rename since y didn't exist in the merge base.
405 $ newrepo
413 $ newrepo
406 $ echo x > x
414 $ echo x > x
407 $ hg ci -Aqm 'add x'
415 $ hg ci -Aqm 'add x'
408 $ hg cp x y
416 $ hg cp x y
409 $ hg ci -qm 'copy x to y'
417 $ hg ci -qm 'copy x to y'
410 $ hg co -q 0
418 $ hg co -q 0
411 $ echo y > y
419 $ echo y > y
412 $ hg ci -Aqm 'add y'
420 $ hg ci -Aqm 'add y'
413 $ hg mv y z
421 $ hg mv y z
414 $ hg ci -m 'rename y to z'
422 $ hg ci -m 'rename y to z'
415 $ hg merge -q 1
423 $ hg merge -q 1
416 $ hg ci -m 'merge'
424 $ hg ci -m 'merge'
417 $ hg l
425 $ hg l
418 @ 4 merge
426 @ 4 merge
419 |\
427 |\
420 | o 3 rename y to z
428 | o 3 rename y to z
421 | | y z
429 | | y z
422 | o 2 add y
430 | o 2 add y
423 | | y
431 | | y
424 o | 1 copy x to y
432 o | 1 copy x to y
425 |/ y
433 |/ y
426 o 0 add x
434 o 0 add x
427 x
435 x
428 $ hg debugp1copies -r 3
436 $ hg debugp1copies -r 3
429 y -> z
437 y -> z
430 $ hg debugp2copies -r 3
438 $ hg debugp2copies -r 3
431 $ hg debugpathcopies 2 3
439 $ hg debugpathcopies 2 3
432 y -> z
440 y -> z
433 $ hg debugpathcopies 1 3
441 $ hg debugpathcopies 1 3
434
442
435 Create x and y, then rename x to z on one side of merge, and rename y to z and modify z on the
443 Create x and y, then rename x to z on one side of merge, and rename y to z and modify z on the
436 other side.
444 other side.
437 $ newrepo
445 $ newrepo
438 $ echo x > x
446 $ echo x > x
439 $ echo y > y
447 $ echo y > y
440 $ hg ci -Aqm 'add x and y'
448 $ hg ci -Aqm 'add x and y'
441 $ hg mv x z
449 $ hg mv x z
442 $ hg ci -qm 'rename x to z'
450 $ hg ci -qm 'rename x to z'
443 $ hg co -q 0
451 $ hg co -q 0
444 $ hg mv y z
452 $ hg mv y z
445 $ hg ci -qm 'rename y to z'
453 $ hg ci -qm 'rename y to z'
446 $ echo z >> z
454 $ echo z >> z
447 $ hg ci -m 'modify z'
455 $ hg ci -m 'modify z'
448 $ hg merge -q 1
456 $ hg merge -q 1
449 warning: conflicts while merging z! (edit, then use 'hg resolve --mark')
457 warning: conflicts while merging z! (edit, then use 'hg resolve --mark')
450 [1]
458 [1]
451 $ echo z > z
459 $ echo z > z
452 $ hg resolve -qm z
460 $ hg resolve -qm z
453 $ hg ci -m 'merge 1 into 3'
461 $ hg ci -m 'merge 1 into 3'
454 Try merging the other direction too
462 Try merging the other direction too
455 $ hg co -q 1
463 $ hg co -q 1
456 $ hg merge -q 3
464 $ hg merge -q 3
457 warning: conflicts while merging z! (edit, then use 'hg resolve --mark')
465 warning: conflicts while merging z! (edit, then use 'hg resolve --mark')
458 [1]
466 [1]
459 $ echo z > z
467 $ echo z > z
460 $ hg resolve -qm z
468 $ hg resolve -qm z
461 $ hg ci -m 'merge 3 into 1'
469 $ hg ci -m 'merge 3 into 1'
462 created new head
470 created new head
463 $ hg l
471 $ hg l
464 @ 5 merge 3 into 1
472 @ 5 merge 3 into 1
465 |\ y z
473 |\ y z
466 +---o 4 merge 1 into 3
474 +---o 4 merge 1 into 3
467 | |/ x z
475 | |/ x z
468 | o 3 modify z
476 | o 3 modify z
469 | | z
477 | | z
470 | o 2 rename y to z
478 | o 2 rename y to z
471 | | y z
479 | | y z
472 o | 1 rename x to z
480 o | 1 rename x to z
473 |/ x z
481 |/ x z
474 o 0 add x and y
482 o 0 add x and y
475 x y
483 x y
476 $ hg debugpathcopies 1 4
484 $ hg debugpathcopies 1 4
477 $ hg debugpathcopies 2 4
485 $ hg debugpathcopies 2 4
478 $ hg debugpathcopies 0 4
486 $ hg debugpathcopies 0 4
479 x -> z
487 x -> z (filelog !)
488 y -> z (compatibility !)
480 $ hg debugpathcopies 1 5
489 $ hg debugpathcopies 1 5
481 $ hg debugpathcopies 2 5
490 $ hg debugpathcopies 2 5
482 $ hg debugpathcopies 0 5
491 $ hg debugpathcopies 0 5
483 x -> z
492 x -> z
484
493
General Comments 0
You need to be logged in to leave comments. Login now