##// END OF EJS Templates
filemerge: add support for partial conflict resolution by external tool...
Martin von Zweigbergk -
r49838:f3aafd78 default
parent child Browse files
Show More
@@ -0,0 +1,209 b''
1 Test support for partial-resolution tools
2
3 Create a tool that resolves conflicts after line 5 by simply dropping those
4 lines (even if there are no conflicts there)
5 $ cat >> "$TESTTMP/head.sh" <<'EOF'
6 > #!/bin/sh
7 > for f in "$@"; do
8 > head -5 $f > tmp
9 > mv -f tmp $f
10 > done
11 > EOF
12 $ chmod +x "$TESTTMP/head.sh"
13 ...and another tool that keeps only the last 5 lines instead of the first 5.
14 $ cat >> "$TESTTMP/tail.sh" <<'EOF'
15 > #!/bin/sh
16 > for f in "$@"; do
17 > tail -5 $f > tmp
18 > mv -f tmp $f
19 > done
20 > EOF
21 $ chmod +x "$TESTTMP/tail.sh"
22
23 Set up both tools to run on all patterns (the default), and let the `tail` tool
24 run after the `head` tool, which means it will have no effect (we'll override it
25 to test order later)
26 $ cat >> "$HGRCPATH" <<EOF
27 > [partial-merge-tools]
28 > head.executable=$TESTTMP/head.sh
29 > tail.executable=$TESTTMP/tail.sh
30 > tail.order=1
31 > EOF
32
33 $ make_commit() {
34 > echo "$@" | xargs -n1 > file
35 > hg add file 2> /dev/null
36 > hg ci -m "$*"
37 > }
38
39
40 Let a partial-resolution tool resolve some conflicts and leave other conflicts
41 for the regular merge tool (:merge3 here)
42
43 $ hg init repo
44 $ cd repo
45 $ make_commit a b c d e f
46 $ make_commit a b2 c d e f2
47 $ hg up 0
48 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
49 $ make_commit a b3 c d e f3
50 created new head
51 $ hg merge 1 -t :merge3
52 merging file
53 warning: conflicts while merging file! (edit, then use 'hg resolve --mark')
54 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
55 use 'hg resolve' to retry unresolved file merges or 'hg merge --abort' to abandon
56 [1]
57 $ cat file
58 a
59 <<<<<<< working copy: e11a49d4b620 - test: a b3 c d e f3
60 b3
61 ||||||| common ancestor: 8ae8bb9cc43a - test: a b c d e f
62 b
63 =======
64 b2
65 >>>>>>> merge rev: fbc096a40cc5 - test: a b2 c d e f2
66 c
67 d
68 e
69
70
71 With premerge=keep, the partial-resolution tools runs before and doesn't see
72 the conflict markers
73
74 $ hg up -C 2
75 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
76 $ cat >> .hg/hgrc <<EOF
77 > [merge-tools]
78 > my-local.executable = cat
79 > my-local.args = $local
80 > my-local.premerge = keep-merge3
81 > EOF
82 $ hg merge 1 -t my-local
83 merging file
84 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
85 (branch merge, don't forget to commit)
86 $ cat file
87 a
88 <<<<<<< working copy: e11a49d4b620 - test: a b3 c d e f3
89 b3
90 ||||||| common ancestor: 8ae8bb9cc43a - test: a b c d e f
91 b
92 =======
93 b2
94 >>>>>>> merge rev: fbc096a40cc5 - test: a b2 c d e f2
95 c
96 d
97 e
98
99
100 When a partial-resolution tool resolves all conflicts, the resolution should
101 be recorded and the regular merge tool should not be invoked for the file.
102
103 $ hg up -C 0
104 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
105 $ make_commit a b c d e f2
106 created new head
107 $ hg up 0
108 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
109 $ make_commit a b c d e f3
110 created new head
111 $ hg merge 3 -t false
112 merging file
113 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
114 (branch merge, don't forget to commit)
115 $ cat file
116 a
117 b
118 c
119 d
120 e
121
122
123 Only tools whose patterns match are run. We make `head` not match here, so
124 only `tail` should run
125
126 $ hg up -C 4
127 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
128 $ hg merge 3 -t :merge3 --config partial-merge-tools.head.patterns=other
129 merging file
130 warning: conflicts while merging file! (edit, then use 'hg resolve --mark')
131 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
132 use 'hg resolve' to retry unresolved file merges or 'hg merge --abort' to abandon
133 [1]
134 $ cat file
135 b
136 c
137 d
138 e
139 <<<<<<< working copy: d57edaa6e21a - test: a b c d e f3
140 f3
141 ||||||| common ancestor: 8ae8bb9cc43a - test: a b c d e f
142 f
143 =======
144 f2
145 >>>>>>> merge rev: 8c217da987be - test: a b c d e f2
146
147
148 If there are several matching tools, they are run in requested order. We move
149 `head` after `tail` in order here so it has no effect (the conflict in "f" thus
150 remains).
151
152 $ hg up -C 4
153 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
154 $ hg merge 3 -t :merge3 --config partial-merge-tools.head.order=2
155 merging file
156 warning: conflicts while merging file! (edit, then use 'hg resolve --mark')
157 0 files updated, 0 files merged, 0 files removed, 1 files unresolved
158 use 'hg resolve' to retry unresolved file merges or 'hg merge --abort' to abandon
159 [1]
160 $ cat file
161 b
162 c
163 d
164 e
165 <<<<<<< working copy: d57edaa6e21a - test: a b c d e f3
166 f3
167 ||||||| common ancestor: 8ae8bb9cc43a - test: a b c d e f
168 f
169 =======
170 f2
171 >>>>>>> merge rev: 8c217da987be - test: a b c d e f2
172
173
174 When using "nomerge" tools (e.g. `:other`), the partial-resolution tools
175 should not be run.
176
177 $ hg up -C 4
178 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
179 $ hg merge 3 -t :other
180 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
181 (branch merge, don't forget to commit)
182 $ cat file
183 a
184 b
185 c
186 d
187 e
188 f2
189
190
191 If a partial-resolution tool resolved some conflict and simplemerge can
192 merge the rest, then the regular merge tool should not be used. Here we merge
193 "a b c d e3 f3" with "a b2 c d e f2". The `head` tool resolves the conflict in
194 "f" and the internal simplemerge merges the remaining changes in "b" and "e".
195
196 $ hg up -C 0
197 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
198 $ make_commit a b c d e3 f3
199 created new head
200 $ hg merge 1 -t false
201 merging file
202 0 files updated, 1 files merged, 0 files removed, 0 files unresolved
203 (branch merge, don't forget to commit)
204 $ cat file
205 a
206 b2
207 c
208 d
209 e3
@@ -1,2709 +1,2740 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
8
9 import functools
9 import functools
10 import re
10 import re
11
11
12 from . import (
12 from . import (
13 encoding,
13 encoding,
14 error,
14 error,
15 )
15 )
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 = b"extension '%s' overwrite config item '%s.%s'"
25 msg = b"extension '%s' overwrite config item '%s.%s'"
26 msg %= (extname, section, key)
26 msg %= (extname, section, key)
27 ui.develwarn(msg, config=b'warn-config')
27 ui.develwarn(msg, config=b'warn-config')
28
28
29 knownitems.update(items)
29 knownitems.update(items)
30
30
31
31
32 class configitem:
32 class configitem:
33 """represent a known config item
33 """represent a known config item
34
34
35 :section: the official config section where to find this item,
35 :section: the official config section where to find this item,
36 :name: the official name within the section,
36 :name: the official name within the section,
37 :default: default value for this item,
37 :default: default value for this item,
38 :alias: optional list of tuples as alternatives,
38 :alias: optional list of tuples as alternatives,
39 :generic: this is a generic definition, match name using regular expression.
39 :generic: this is a generic definition, match name using regular expression.
40 """
40 """
41
41
42 def __init__(
42 def __init__(
43 self,
43 self,
44 section,
44 section,
45 name,
45 name,
46 default=None,
46 default=None,
47 alias=(),
47 alias=(),
48 generic=False,
48 generic=False,
49 priority=0,
49 priority=0,
50 experimental=False,
50 experimental=False,
51 ):
51 ):
52 self.section = section
52 self.section = section
53 self.name = name
53 self.name = name
54 self.default = default
54 self.default = default
55 self.alias = list(alias)
55 self.alias = list(alias)
56 self.generic = generic
56 self.generic = generic
57 self.priority = priority
57 self.priority = priority
58 self.experimental = experimental
58 self.experimental = experimental
59 self._re = None
59 self._re = None
60 if generic:
60 if generic:
61 self._re = re.compile(self.name)
61 self._re = re.compile(self.name)
62
62
63
63
64 class itemregister(dict):
64 class itemregister(dict):
65 """A specialized dictionary that can handle wild-card selection"""
65 """A specialized dictionary that can handle wild-card selection"""
66
66
67 def __init__(self):
67 def __init__(self):
68 super(itemregister, self).__init__()
68 super(itemregister, self).__init__()
69 self._generics = set()
69 self._generics = set()
70
70
71 def update(self, other):
71 def update(self, other):
72 super(itemregister, self).update(other)
72 super(itemregister, self).update(other)
73 self._generics.update(other._generics)
73 self._generics.update(other._generics)
74
74
75 def __setitem__(self, key, item):
75 def __setitem__(self, key, item):
76 super(itemregister, self).__setitem__(key, item)
76 super(itemregister, self).__setitem__(key, item)
77 if item.generic:
77 if item.generic:
78 self._generics.add(item)
78 self._generics.add(item)
79
79
80 def get(self, key):
80 def get(self, key):
81 baseitem = super(itemregister, self).get(key)
81 baseitem = super(itemregister, self).get(key)
82 if baseitem is not None and not baseitem.generic:
82 if baseitem is not None and not baseitem.generic:
83 return baseitem
83 return baseitem
84
84
85 # search for a matching generic item
85 # search for a matching generic item
86 generics = sorted(self._generics, key=(lambda x: (x.priority, x.name)))
86 generics = sorted(self._generics, key=(lambda x: (x.priority, x.name)))
87 for item in generics:
87 for item in generics:
88 # we use 'match' instead of 'search' to make the matching simpler
88 # we use 'match' instead of 'search' to make the matching simpler
89 # for people unfamiliar with regular expression. Having the match
89 # for people unfamiliar with regular expression. Having the match
90 # rooted to the start of the string will produce less surprising
90 # rooted to the start of the string will produce less surprising
91 # result for user writing simple regex for sub-attribute.
91 # result for user writing simple regex for sub-attribute.
92 #
92 #
93 # For example using "color\..*" match produces an unsurprising
93 # For example using "color\..*" match produces an unsurprising
94 # result, while using search could suddenly match apparently
94 # result, while using search could suddenly match apparently
95 # unrelated configuration that happens to contains "color."
95 # unrelated configuration that happens to contains "color."
96 # anywhere. This is a tradeoff where we favor requiring ".*" on
96 # anywhere. This is a tradeoff where we favor requiring ".*" on
97 # some match to avoid the need to prefix most pattern with "^".
97 # some match to avoid the need to prefix most pattern with "^".
98 # The "^" seems more error prone.
98 # The "^" seems more error prone.
99 if item._re.match(key):
99 if item._re.match(key):
100 return item
100 return item
101
101
102 return None
102 return None
103
103
104
104
105 coreitems = {}
105 coreitems = {}
106
106
107
107
108 def _register(configtable, *args, **kwargs):
108 def _register(configtable, *args, **kwargs):
109 item = configitem(*args, **kwargs)
109 item = configitem(*args, **kwargs)
110 section = configtable.setdefault(item.section, itemregister())
110 section = configtable.setdefault(item.section, itemregister())
111 if item.name in section:
111 if item.name in section:
112 msg = b"duplicated config item registration for '%s.%s'"
112 msg = b"duplicated config item registration for '%s.%s'"
113 raise error.ProgrammingError(msg % (item.section, item.name))
113 raise error.ProgrammingError(msg % (item.section, item.name))
114 section[item.name] = item
114 section[item.name] = item
115
115
116
116
117 # special value for case where the default is derived from other values
117 # special value for case where the default is derived from other values
118 dynamicdefault = object()
118 dynamicdefault = object()
119
119
120 # Registering actual config items
120 # Registering actual config items
121
121
122
122
123 def getitemregister(configtable):
123 def getitemregister(configtable):
124 f = functools.partial(_register, configtable)
124 f = functools.partial(_register, configtable)
125 # export pseudo enum as configitem.*
125 # export pseudo enum as configitem.*
126 f.dynamicdefault = dynamicdefault
126 f.dynamicdefault = dynamicdefault
127 return f
127 return f
128
128
129
129
130 coreconfigitem = getitemregister(coreitems)
130 coreconfigitem = getitemregister(coreitems)
131
131
132
132
133 def _registerdiffopts(section, configprefix=b''):
133 def _registerdiffopts(section, configprefix=b''):
134 coreconfigitem(
134 coreconfigitem(
135 section,
135 section,
136 configprefix + b'nodates',
136 configprefix + b'nodates',
137 default=False,
137 default=False,
138 )
138 )
139 coreconfigitem(
139 coreconfigitem(
140 section,
140 section,
141 configprefix + b'showfunc',
141 configprefix + b'showfunc',
142 default=False,
142 default=False,
143 )
143 )
144 coreconfigitem(
144 coreconfigitem(
145 section,
145 section,
146 configprefix + b'unified',
146 configprefix + b'unified',
147 default=None,
147 default=None,
148 )
148 )
149 coreconfigitem(
149 coreconfigitem(
150 section,
150 section,
151 configprefix + b'git',
151 configprefix + b'git',
152 default=False,
152 default=False,
153 )
153 )
154 coreconfigitem(
154 coreconfigitem(
155 section,
155 section,
156 configprefix + b'ignorews',
156 configprefix + b'ignorews',
157 default=False,
157 default=False,
158 )
158 )
159 coreconfigitem(
159 coreconfigitem(
160 section,
160 section,
161 configprefix + b'ignorewsamount',
161 configprefix + b'ignorewsamount',
162 default=False,
162 default=False,
163 )
163 )
164 coreconfigitem(
164 coreconfigitem(
165 section,
165 section,
166 configprefix + b'ignoreblanklines',
166 configprefix + b'ignoreblanklines',
167 default=False,
167 default=False,
168 )
168 )
169 coreconfigitem(
169 coreconfigitem(
170 section,
170 section,
171 configprefix + b'ignorewseol',
171 configprefix + b'ignorewseol',
172 default=False,
172 default=False,
173 )
173 )
174 coreconfigitem(
174 coreconfigitem(
175 section,
175 section,
176 configprefix + b'nobinary',
176 configprefix + b'nobinary',
177 default=False,
177 default=False,
178 )
178 )
179 coreconfigitem(
179 coreconfigitem(
180 section,
180 section,
181 configprefix + b'noprefix',
181 configprefix + b'noprefix',
182 default=False,
182 default=False,
183 )
183 )
184 coreconfigitem(
184 coreconfigitem(
185 section,
185 section,
186 configprefix + b'word-diff',
186 configprefix + b'word-diff',
187 default=False,
187 default=False,
188 )
188 )
189
189
190
190
191 coreconfigitem(
191 coreconfigitem(
192 b'alias',
192 b'alias',
193 b'.*',
193 b'.*',
194 default=dynamicdefault,
194 default=dynamicdefault,
195 generic=True,
195 generic=True,
196 )
196 )
197 coreconfigitem(
197 coreconfigitem(
198 b'auth',
198 b'auth',
199 b'cookiefile',
199 b'cookiefile',
200 default=None,
200 default=None,
201 )
201 )
202 _registerdiffopts(section=b'annotate')
202 _registerdiffopts(section=b'annotate')
203 # bookmarks.pushing: internal hack for discovery
203 # bookmarks.pushing: internal hack for discovery
204 coreconfigitem(
204 coreconfigitem(
205 b'bookmarks',
205 b'bookmarks',
206 b'pushing',
206 b'pushing',
207 default=list,
207 default=list,
208 )
208 )
209 # bundle.mainreporoot: internal hack for bundlerepo
209 # bundle.mainreporoot: internal hack for bundlerepo
210 coreconfigitem(
210 coreconfigitem(
211 b'bundle',
211 b'bundle',
212 b'mainreporoot',
212 b'mainreporoot',
213 default=b'',
213 default=b'',
214 )
214 )
215 coreconfigitem(
215 coreconfigitem(
216 b'censor',
216 b'censor',
217 b'policy',
217 b'policy',
218 default=b'abort',
218 default=b'abort',
219 experimental=True,
219 experimental=True,
220 )
220 )
221 coreconfigitem(
221 coreconfigitem(
222 b'chgserver',
222 b'chgserver',
223 b'idletimeout',
223 b'idletimeout',
224 default=3600,
224 default=3600,
225 )
225 )
226 coreconfigitem(
226 coreconfigitem(
227 b'chgserver',
227 b'chgserver',
228 b'skiphash',
228 b'skiphash',
229 default=False,
229 default=False,
230 )
230 )
231 coreconfigitem(
231 coreconfigitem(
232 b'cmdserver',
232 b'cmdserver',
233 b'log',
233 b'log',
234 default=None,
234 default=None,
235 )
235 )
236 coreconfigitem(
236 coreconfigitem(
237 b'cmdserver',
237 b'cmdserver',
238 b'max-log-files',
238 b'max-log-files',
239 default=7,
239 default=7,
240 )
240 )
241 coreconfigitem(
241 coreconfigitem(
242 b'cmdserver',
242 b'cmdserver',
243 b'max-log-size',
243 b'max-log-size',
244 default=b'1 MB',
244 default=b'1 MB',
245 )
245 )
246 coreconfigitem(
246 coreconfigitem(
247 b'cmdserver',
247 b'cmdserver',
248 b'max-repo-cache',
248 b'max-repo-cache',
249 default=0,
249 default=0,
250 experimental=True,
250 experimental=True,
251 )
251 )
252 coreconfigitem(
252 coreconfigitem(
253 b'cmdserver',
253 b'cmdserver',
254 b'message-encodings',
254 b'message-encodings',
255 default=list,
255 default=list,
256 )
256 )
257 coreconfigitem(
257 coreconfigitem(
258 b'cmdserver',
258 b'cmdserver',
259 b'track-log',
259 b'track-log',
260 default=lambda: [b'chgserver', b'cmdserver', b'repocache'],
260 default=lambda: [b'chgserver', b'cmdserver', b'repocache'],
261 )
261 )
262 coreconfigitem(
262 coreconfigitem(
263 b'cmdserver',
263 b'cmdserver',
264 b'shutdown-on-interrupt',
264 b'shutdown-on-interrupt',
265 default=True,
265 default=True,
266 )
266 )
267 coreconfigitem(
267 coreconfigitem(
268 b'color',
268 b'color',
269 b'.*',
269 b'.*',
270 default=None,
270 default=None,
271 generic=True,
271 generic=True,
272 )
272 )
273 coreconfigitem(
273 coreconfigitem(
274 b'color',
274 b'color',
275 b'mode',
275 b'mode',
276 default=b'auto',
276 default=b'auto',
277 )
277 )
278 coreconfigitem(
278 coreconfigitem(
279 b'color',
279 b'color',
280 b'pagermode',
280 b'pagermode',
281 default=dynamicdefault,
281 default=dynamicdefault,
282 )
282 )
283 coreconfigitem(
283 coreconfigitem(
284 b'command-templates',
284 b'command-templates',
285 b'graphnode',
285 b'graphnode',
286 default=None,
286 default=None,
287 alias=[(b'ui', b'graphnodetemplate')],
287 alias=[(b'ui', b'graphnodetemplate')],
288 )
288 )
289 coreconfigitem(
289 coreconfigitem(
290 b'command-templates',
290 b'command-templates',
291 b'log',
291 b'log',
292 default=None,
292 default=None,
293 alias=[(b'ui', b'logtemplate')],
293 alias=[(b'ui', b'logtemplate')],
294 )
294 )
295 coreconfigitem(
295 coreconfigitem(
296 b'command-templates',
296 b'command-templates',
297 b'mergemarker',
297 b'mergemarker',
298 default=(
298 default=(
299 b'{node|short} '
299 b'{node|short} '
300 b'{ifeq(tags, "tip", "", '
300 b'{ifeq(tags, "tip", "", '
301 b'ifeq(tags, "", "", "{tags} "))}'
301 b'ifeq(tags, "", "", "{tags} "))}'
302 b'{if(bookmarks, "{bookmarks} ")}'
302 b'{if(bookmarks, "{bookmarks} ")}'
303 b'{ifeq(branch, "default", "", "{branch} ")}'
303 b'{ifeq(branch, "default", "", "{branch} ")}'
304 b'- {author|user}: {desc|firstline}'
304 b'- {author|user}: {desc|firstline}'
305 ),
305 ),
306 alias=[(b'ui', b'mergemarkertemplate')],
306 alias=[(b'ui', b'mergemarkertemplate')],
307 )
307 )
308 coreconfigitem(
308 coreconfigitem(
309 b'command-templates',
309 b'command-templates',
310 b'pre-merge-tool-output',
310 b'pre-merge-tool-output',
311 default=None,
311 default=None,
312 alias=[(b'ui', b'pre-merge-tool-output-template')],
312 alias=[(b'ui', b'pre-merge-tool-output-template')],
313 )
313 )
314 coreconfigitem(
314 coreconfigitem(
315 b'command-templates',
315 b'command-templates',
316 b'oneline-summary',
316 b'oneline-summary',
317 default=None,
317 default=None,
318 )
318 )
319 coreconfigitem(
319 coreconfigitem(
320 b'command-templates',
320 b'command-templates',
321 b'oneline-summary.*',
321 b'oneline-summary.*',
322 default=dynamicdefault,
322 default=dynamicdefault,
323 generic=True,
323 generic=True,
324 )
324 )
325 _registerdiffopts(section=b'commands', configprefix=b'commit.interactive.')
325 _registerdiffopts(section=b'commands', configprefix=b'commit.interactive.')
326 coreconfigitem(
326 coreconfigitem(
327 b'commands',
327 b'commands',
328 b'commit.post-status',
328 b'commit.post-status',
329 default=False,
329 default=False,
330 )
330 )
331 coreconfigitem(
331 coreconfigitem(
332 b'commands',
332 b'commands',
333 b'grep.all-files',
333 b'grep.all-files',
334 default=False,
334 default=False,
335 experimental=True,
335 experimental=True,
336 )
336 )
337 coreconfigitem(
337 coreconfigitem(
338 b'commands',
338 b'commands',
339 b'merge.require-rev',
339 b'merge.require-rev',
340 default=False,
340 default=False,
341 )
341 )
342 coreconfigitem(
342 coreconfigitem(
343 b'commands',
343 b'commands',
344 b'push.require-revs',
344 b'push.require-revs',
345 default=False,
345 default=False,
346 )
346 )
347 coreconfigitem(
347 coreconfigitem(
348 b'commands',
348 b'commands',
349 b'resolve.confirm',
349 b'resolve.confirm',
350 default=False,
350 default=False,
351 )
351 )
352 coreconfigitem(
352 coreconfigitem(
353 b'commands',
353 b'commands',
354 b'resolve.explicit-re-merge',
354 b'resolve.explicit-re-merge',
355 default=False,
355 default=False,
356 )
356 )
357 coreconfigitem(
357 coreconfigitem(
358 b'commands',
358 b'commands',
359 b'resolve.mark-check',
359 b'resolve.mark-check',
360 default=b'none',
360 default=b'none',
361 )
361 )
362 _registerdiffopts(section=b'commands', configprefix=b'revert.interactive.')
362 _registerdiffopts(section=b'commands', configprefix=b'revert.interactive.')
363 coreconfigitem(
363 coreconfigitem(
364 b'commands',
364 b'commands',
365 b'show.aliasprefix',
365 b'show.aliasprefix',
366 default=list,
366 default=list,
367 )
367 )
368 coreconfigitem(
368 coreconfigitem(
369 b'commands',
369 b'commands',
370 b'status.relative',
370 b'status.relative',
371 default=False,
371 default=False,
372 )
372 )
373 coreconfigitem(
373 coreconfigitem(
374 b'commands',
374 b'commands',
375 b'status.skipstates',
375 b'status.skipstates',
376 default=[],
376 default=[],
377 experimental=True,
377 experimental=True,
378 )
378 )
379 coreconfigitem(
379 coreconfigitem(
380 b'commands',
380 b'commands',
381 b'status.terse',
381 b'status.terse',
382 default=b'',
382 default=b'',
383 )
383 )
384 coreconfigitem(
384 coreconfigitem(
385 b'commands',
385 b'commands',
386 b'status.verbose',
386 b'status.verbose',
387 default=False,
387 default=False,
388 )
388 )
389 coreconfigitem(
389 coreconfigitem(
390 b'commands',
390 b'commands',
391 b'update.check',
391 b'update.check',
392 default=None,
392 default=None,
393 )
393 )
394 coreconfigitem(
394 coreconfigitem(
395 b'commands',
395 b'commands',
396 b'update.requiredest',
396 b'update.requiredest',
397 default=False,
397 default=False,
398 )
398 )
399 coreconfigitem(
399 coreconfigitem(
400 b'committemplate',
400 b'committemplate',
401 b'.*',
401 b'.*',
402 default=None,
402 default=None,
403 generic=True,
403 generic=True,
404 )
404 )
405 coreconfigitem(
405 coreconfigitem(
406 b'convert',
406 b'convert',
407 b'bzr.saverev',
407 b'bzr.saverev',
408 default=True,
408 default=True,
409 )
409 )
410 coreconfigitem(
410 coreconfigitem(
411 b'convert',
411 b'convert',
412 b'cvsps.cache',
412 b'cvsps.cache',
413 default=True,
413 default=True,
414 )
414 )
415 coreconfigitem(
415 coreconfigitem(
416 b'convert',
416 b'convert',
417 b'cvsps.fuzz',
417 b'cvsps.fuzz',
418 default=60,
418 default=60,
419 )
419 )
420 coreconfigitem(
420 coreconfigitem(
421 b'convert',
421 b'convert',
422 b'cvsps.logencoding',
422 b'cvsps.logencoding',
423 default=None,
423 default=None,
424 )
424 )
425 coreconfigitem(
425 coreconfigitem(
426 b'convert',
426 b'convert',
427 b'cvsps.mergefrom',
427 b'cvsps.mergefrom',
428 default=None,
428 default=None,
429 )
429 )
430 coreconfigitem(
430 coreconfigitem(
431 b'convert',
431 b'convert',
432 b'cvsps.mergeto',
432 b'cvsps.mergeto',
433 default=None,
433 default=None,
434 )
434 )
435 coreconfigitem(
435 coreconfigitem(
436 b'convert',
436 b'convert',
437 b'git.committeractions',
437 b'git.committeractions',
438 default=lambda: [b'messagedifferent'],
438 default=lambda: [b'messagedifferent'],
439 )
439 )
440 coreconfigitem(
440 coreconfigitem(
441 b'convert',
441 b'convert',
442 b'git.extrakeys',
442 b'git.extrakeys',
443 default=list,
443 default=list,
444 )
444 )
445 coreconfigitem(
445 coreconfigitem(
446 b'convert',
446 b'convert',
447 b'git.findcopiesharder',
447 b'git.findcopiesharder',
448 default=False,
448 default=False,
449 )
449 )
450 coreconfigitem(
450 coreconfigitem(
451 b'convert',
451 b'convert',
452 b'git.remoteprefix',
452 b'git.remoteprefix',
453 default=b'remote',
453 default=b'remote',
454 )
454 )
455 coreconfigitem(
455 coreconfigitem(
456 b'convert',
456 b'convert',
457 b'git.renamelimit',
457 b'git.renamelimit',
458 default=400,
458 default=400,
459 )
459 )
460 coreconfigitem(
460 coreconfigitem(
461 b'convert',
461 b'convert',
462 b'git.saverev',
462 b'git.saverev',
463 default=True,
463 default=True,
464 )
464 )
465 coreconfigitem(
465 coreconfigitem(
466 b'convert',
466 b'convert',
467 b'git.similarity',
467 b'git.similarity',
468 default=50,
468 default=50,
469 )
469 )
470 coreconfigitem(
470 coreconfigitem(
471 b'convert',
471 b'convert',
472 b'git.skipsubmodules',
472 b'git.skipsubmodules',
473 default=False,
473 default=False,
474 )
474 )
475 coreconfigitem(
475 coreconfigitem(
476 b'convert',
476 b'convert',
477 b'hg.clonebranches',
477 b'hg.clonebranches',
478 default=False,
478 default=False,
479 )
479 )
480 coreconfigitem(
480 coreconfigitem(
481 b'convert',
481 b'convert',
482 b'hg.ignoreerrors',
482 b'hg.ignoreerrors',
483 default=False,
483 default=False,
484 )
484 )
485 coreconfigitem(
485 coreconfigitem(
486 b'convert',
486 b'convert',
487 b'hg.preserve-hash',
487 b'hg.preserve-hash',
488 default=False,
488 default=False,
489 )
489 )
490 coreconfigitem(
490 coreconfigitem(
491 b'convert',
491 b'convert',
492 b'hg.revs',
492 b'hg.revs',
493 default=None,
493 default=None,
494 )
494 )
495 coreconfigitem(
495 coreconfigitem(
496 b'convert',
496 b'convert',
497 b'hg.saverev',
497 b'hg.saverev',
498 default=False,
498 default=False,
499 )
499 )
500 coreconfigitem(
500 coreconfigitem(
501 b'convert',
501 b'convert',
502 b'hg.sourcename',
502 b'hg.sourcename',
503 default=None,
503 default=None,
504 )
504 )
505 coreconfigitem(
505 coreconfigitem(
506 b'convert',
506 b'convert',
507 b'hg.startrev',
507 b'hg.startrev',
508 default=None,
508 default=None,
509 )
509 )
510 coreconfigitem(
510 coreconfigitem(
511 b'convert',
511 b'convert',
512 b'hg.tagsbranch',
512 b'hg.tagsbranch',
513 default=b'default',
513 default=b'default',
514 )
514 )
515 coreconfigitem(
515 coreconfigitem(
516 b'convert',
516 b'convert',
517 b'hg.usebranchnames',
517 b'hg.usebranchnames',
518 default=True,
518 default=True,
519 )
519 )
520 coreconfigitem(
520 coreconfigitem(
521 b'convert',
521 b'convert',
522 b'ignoreancestorcheck',
522 b'ignoreancestorcheck',
523 default=False,
523 default=False,
524 experimental=True,
524 experimental=True,
525 )
525 )
526 coreconfigitem(
526 coreconfigitem(
527 b'convert',
527 b'convert',
528 b'localtimezone',
528 b'localtimezone',
529 default=False,
529 default=False,
530 )
530 )
531 coreconfigitem(
531 coreconfigitem(
532 b'convert',
532 b'convert',
533 b'p4.encoding',
533 b'p4.encoding',
534 default=dynamicdefault,
534 default=dynamicdefault,
535 )
535 )
536 coreconfigitem(
536 coreconfigitem(
537 b'convert',
537 b'convert',
538 b'p4.startrev',
538 b'p4.startrev',
539 default=0,
539 default=0,
540 )
540 )
541 coreconfigitem(
541 coreconfigitem(
542 b'convert',
542 b'convert',
543 b'skiptags',
543 b'skiptags',
544 default=False,
544 default=False,
545 )
545 )
546 coreconfigitem(
546 coreconfigitem(
547 b'convert',
547 b'convert',
548 b'svn.debugsvnlog',
548 b'svn.debugsvnlog',
549 default=True,
549 default=True,
550 )
550 )
551 coreconfigitem(
551 coreconfigitem(
552 b'convert',
552 b'convert',
553 b'svn.trunk',
553 b'svn.trunk',
554 default=None,
554 default=None,
555 )
555 )
556 coreconfigitem(
556 coreconfigitem(
557 b'convert',
557 b'convert',
558 b'svn.tags',
558 b'svn.tags',
559 default=None,
559 default=None,
560 )
560 )
561 coreconfigitem(
561 coreconfigitem(
562 b'convert',
562 b'convert',
563 b'svn.branches',
563 b'svn.branches',
564 default=None,
564 default=None,
565 )
565 )
566 coreconfigitem(
566 coreconfigitem(
567 b'convert',
567 b'convert',
568 b'svn.startrev',
568 b'svn.startrev',
569 default=0,
569 default=0,
570 )
570 )
571 coreconfigitem(
571 coreconfigitem(
572 b'convert',
572 b'convert',
573 b'svn.dangerous-set-commit-dates',
573 b'svn.dangerous-set-commit-dates',
574 default=False,
574 default=False,
575 )
575 )
576 coreconfigitem(
576 coreconfigitem(
577 b'debug',
577 b'debug',
578 b'dirstate.delaywrite',
578 b'dirstate.delaywrite',
579 default=0,
579 default=0,
580 )
580 )
581 coreconfigitem(
581 coreconfigitem(
582 b'debug',
582 b'debug',
583 b'revlog.verifyposition.changelog',
583 b'revlog.verifyposition.changelog',
584 default=b'',
584 default=b'',
585 )
585 )
586 coreconfigitem(
586 coreconfigitem(
587 b'defaults',
587 b'defaults',
588 b'.*',
588 b'.*',
589 default=None,
589 default=None,
590 generic=True,
590 generic=True,
591 )
591 )
592 coreconfigitem(
592 coreconfigitem(
593 b'devel',
593 b'devel',
594 b'all-warnings',
594 b'all-warnings',
595 default=False,
595 default=False,
596 )
596 )
597 coreconfigitem(
597 coreconfigitem(
598 b'devel',
598 b'devel',
599 b'bundle2.debug',
599 b'bundle2.debug',
600 default=False,
600 default=False,
601 )
601 )
602 coreconfigitem(
602 coreconfigitem(
603 b'devel',
603 b'devel',
604 b'bundle.delta',
604 b'bundle.delta',
605 default=b'',
605 default=b'',
606 )
606 )
607 coreconfigitem(
607 coreconfigitem(
608 b'devel',
608 b'devel',
609 b'cache-vfs',
609 b'cache-vfs',
610 default=None,
610 default=None,
611 )
611 )
612 coreconfigitem(
612 coreconfigitem(
613 b'devel',
613 b'devel',
614 b'check-locks',
614 b'check-locks',
615 default=False,
615 default=False,
616 )
616 )
617 coreconfigitem(
617 coreconfigitem(
618 b'devel',
618 b'devel',
619 b'check-relroot',
619 b'check-relroot',
620 default=False,
620 default=False,
621 )
621 )
622 # Track copy information for all file, not just "added" one (very slow)
622 # Track copy information for all file, not just "added" one (very slow)
623 coreconfigitem(
623 coreconfigitem(
624 b'devel',
624 b'devel',
625 b'copy-tracing.trace-all-files',
625 b'copy-tracing.trace-all-files',
626 default=False,
626 default=False,
627 )
627 )
628 coreconfigitem(
628 coreconfigitem(
629 b'devel',
629 b'devel',
630 b'default-date',
630 b'default-date',
631 default=None,
631 default=None,
632 )
632 )
633 coreconfigitem(
633 coreconfigitem(
634 b'devel',
634 b'devel',
635 b'deprec-warn',
635 b'deprec-warn',
636 default=False,
636 default=False,
637 )
637 )
638 coreconfigitem(
638 coreconfigitem(
639 b'devel',
639 b'devel',
640 b'disableloaddefaultcerts',
640 b'disableloaddefaultcerts',
641 default=False,
641 default=False,
642 )
642 )
643 coreconfigitem(
643 coreconfigitem(
644 b'devel',
644 b'devel',
645 b'warn-empty-changegroup',
645 b'warn-empty-changegroup',
646 default=False,
646 default=False,
647 )
647 )
648 coreconfigitem(
648 coreconfigitem(
649 b'devel',
649 b'devel',
650 b'legacy.exchange',
650 b'legacy.exchange',
651 default=list,
651 default=list,
652 )
652 )
653 # When True, revlogs use a special reference version of the nodemap, that is not
653 # When True, revlogs use a special reference version of the nodemap, that is not
654 # performant but is "known" to behave properly.
654 # performant but is "known" to behave properly.
655 coreconfigitem(
655 coreconfigitem(
656 b'devel',
656 b'devel',
657 b'persistent-nodemap',
657 b'persistent-nodemap',
658 default=False,
658 default=False,
659 )
659 )
660 coreconfigitem(
660 coreconfigitem(
661 b'devel',
661 b'devel',
662 b'servercafile',
662 b'servercafile',
663 default=b'',
663 default=b'',
664 )
664 )
665 coreconfigitem(
665 coreconfigitem(
666 b'devel',
666 b'devel',
667 b'serverexactprotocol',
667 b'serverexactprotocol',
668 default=b'',
668 default=b'',
669 )
669 )
670 coreconfigitem(
670 coreconfigitem(
671 b'devel',
671 b'devel',
672 b'serverrequirecert',
672 b'serverrequirecert',
673 default=False,
673 default=False,
674 )
674 )
675 coreconfigitem(
675 coreconfigitem(
676 b'devel',
676 b'devel',
677 b'strip-obsmarkers',
677 b'strip-obsmarkers',
678 default=True,
678 default=True,
679 )
679 )
680 coreconfigitem(
680 coreconfigitem(
681 b'devel',
681 b'devel',
682 b'warn-config',
682 b'warn-config',
683 default=None,
683 default=None,
684 )
684 )
685 coreconfigitem(
685 coreconfigitem(
686 b'devel',
686 b'devel',
687 b'warn-config-default',
687 b'warn-config-default',
688 default=None,
688 default=None,
689 )
689 )
690 coreconfigitem(
690 coreconfigitem(
691 b'devel',
691 b'devel',
692 b'user.obsmarker',
692 b'user.obsmarker',
693 default=None,
693 default=None,
694 )
694 )
695 coreconfigitem(
695 coreconfigitem(
696 b'devel',
696 b'devel',
697 b'warn-config-unknown',
697 b'warn-config-unknown',
698 default=None,
698 default=None,
699 )
699 )
700 coreconfigitem(
700 coreconfigitem(
701 b'devel',
701 b'devel',
702 b'debug.copies',
702 b'debug.copies',
703 default=False,
703 default=False,
704 )
704 )
705 coreconfigitem(
705 coreconfigitem(
706 b'devel',
706 b'devel',
707 b'copy-tracing.multi-thread',
707 b'copy-tracing.multi-thread',
708 default=True,
708 default=True,
709 )
709 )
710 coreconfigitem(
710 coreconfigitem(
711 b'devel',
711 b'devel',
712 b'debug.extensions',
712 b'debug.extensions',
713 default=False,
713 default=False,
714 )
714 )
715 coreconfigitem(
715 coreconfigitem(
716 b'devel',
716 b'devel',
717 b'debug.repo-filters',
717 b'debug.repo-filters',
718 default=False,
718 default=False,
719 )
719 )
720 coreconfigitem(
720 coreconfigitem(
721 b'devel',
721 b'devel',
722 b'debug.peer-request',
722 b'debug.peer-request',
723 default=False,
723 default=False,
724 )
724 )
725 # If discovery.exchange-heads is False, the discovery will not start with
725 # If discovery.exchange-heads is False, the discovery will not start with
726 # remote head fetching and local head querying.
726 # remote head fetching and local head querying.
727 coreconfigitem(
727 coreconfigitem(
728 b'devel',
728 b'devel',
729 b'discovery.exchange-heads',
729 b'discovery.exchange-heads',
730 default=True,
730 default=True,
731 )
731 )
732 # If discovery.grow-sample is False, the sample size used in set discovery will
732 # If discovery.grow-sample is False, the sample size used in set discovery will
733 # not be increased through the process
733 # not be increased through the process
734 coreconfigitem(
734 coreconfigitem(
735 b'devel',
735 b'devel',
736 b'discovery.grow-sample',
736 b'discovery.grow-sample',
737 default=True,
737 default=True,
738 )
738 )
739 # When discovery.grow-sample.dynamic is True, the default, the sample size is
739 # When discovery.grow-sample.dynamic is True, the default, the sample size is
740 # adapted to the shape of the undecided set (it is set to the max of:
740 # adapted to the shape of the undecided set (it is set to the max of:
741 # <target-size>, len(roots(undecided)), len(heads(undecided)
741 # <target-size>, len(roots(undecided)), len(heads(undecided)
742 coreconfigitem(
742 coreconfigitem(
743 b'devel',
743 b'devel',
744 b'discovery.grow-sample.dynamic',
744 b'discovery.grow-sample.dynamic',
745 default=True,
745 default=True,
746 )
746 )
747 # discovery.grow-sample.rate control the rate at which the sample grow
747 # discovery.grow-sample.rate control the rate at which the sample grow
748 coreconfigitem(
748 coreconfigitem(
749 b'devel',
749 b'devel',
750 b'discovery.grow-sample.rate',
750 b'discovery.grow-sample.rate',
751 default=1.05,
751 default=1.05,
752 )
752 )
753 # If discovery.randomize is False, random sampling during discovery are
753 # If discovery.randomize is False, random sampling during discovery are
754 # deterministic. It is meant for integration tests.
754 # deterministic. It is meant for integration tests.
755 coreconfigitem(
755 coreconfigitem(
756 b'devel',
756 b'devel',
757 b'discovery.randomize',
757 b'discovery.randomize',
758 default=True,
758 default=True,
759 )
759 )
760 # Control the initial size of the discovery sample
760 # Control the initial size of the discovery sample
761 coreconfigitem(
761 coreconfigitem(
762 b'devel',
762 b'devel',
763 b'discovery.sample-size',
763 b'discovery.sample-size',
764 default=200,
764 default=200,
765 )
765 )
766 # Control the initial size of the discovery for initial change
766 # Control the initial size of the discovery for initial change
767 coreconfigitem(
767 coreconfigitem(
768 b'devel',
768 b'devel',
769 b'discovery.sample-size.initial',
769 b'discovery.sample-size.initial',
770 default=100,
770 default=100,
771 )
771 )
772 _registerdiffopts(section=b'diff')
772 _registerdiffopts(section=b'diff')
773 coreconfigitem(
773 coreconfigitem(
774 b'diff',
774 b'diff',
775 b'merge',
775 b'merge',
776 default=False,
776 default=False,
777 experimental=True,
777 experimental=True,
778 )
778 )
779 coreconfigitem(
779 coreconfigitem(
780 b'email',
780 b'email',
781 b'bcc',
781 b'bcc',
782 default=None,
782 default=None,
783 )
783 )
784 coreconfigitem(
784 coreconfigitem(
785 b'email',
785 b'email',
786 b'cc',
786 b'cc',
787 default=None,
787 default=None,
788 )
788 )
789 coreconfigitem(
789 coreconfigitem(
790 b'email',
790 b'email',
791 b'charsets',
791 b'charsets',
792 default=list,
792 default=list,
793 )
793 )
794 coreconfigitem(
794 coreconfigitem(
795 b'email',
795 b'email',
796 b'from',
796 b'from',
797 default=None,
797 default=None,
798 )
798 )
799 coreconfigitem(
799 coreconfigitem(
800 b'email',
800 b'email',
801 b'method',
801 b'method',
802 default=b'smtp',
802 default=b'smtp',
803 )
803 )
804 coreconfigitem(
804 coreconfigitem(
805 b'email',
805 b'email',
806 b'reply-to',
806 b'reply-to',
807 default=None,
807 default=None,
808 )
808 )
809 coreconfigitem(
809 coreconfigitem(
810 b'email',
810 b'email',
811 b'to',
811 b'to',
812 default=None,
812 default=None,
813 )
813 )
814 coreconfigitem(
814 coreconfigitem(
815 b'experimental',
815 b'experimental',
816 b'archivemetatemplate',
816 b'archivemetatemplate',
817 default=dynamicdefault,
817 default=dynamicdefault,
818 )
818 )
819 coreconfigitem(
819 coreconfigitem(
820 b'experimental',
820 b'experimental',
821 b'auto-publish',
821 b'auto-publish',
822 default=b'publish',
822 default=b'publish',
823 )
823 )
824 coreconfigitem(
824 coreconfigitem(
825 b'experimental',
825 b'experimental',
826 b'bundle-phases',
826 b'bundle-phases',
827 default=False,
827 default=False,
828 )
828 )
829 coreconfigitem(
829 coreconfigitem(
830 b'experimental',
830 b'experimental',
831 b'bundle2-advertise',
831 b'bundle2-advertise',
832 default=True,
832 default=True,
833 )
833 )
834 coreconfigitem(
834 coreconfigitem(
835 b'experimental',
835 b'experimental',
836 b'bundle2-output-capture',
836 b'bundle2-output-capture',
837 default=False,
837 default=False,
838 )
838 )
839 coreconfigitem(
839 coreconfigitem(
840 b'experimental',
840 b'experimental',
841 b'bundle2.pushback',
841 b'bundle2.pushback',
842 default=False,
842 default=False,
843 )
843 )
844 coreconfigitem(
844 coreconfigitem(
845 b'experimental',
845 b'experimental',
846 b'bundle2lazylocking',
846 b'bundle2lazylocking',
847 default=False,
847 default=False,
848 )
848 )
849 coreconfigitem(
849 coreconfigitem(
850 b'experimental',
850 b'experimental',
851 b'bundlecomplevel',
851 b'bundlecomplevel',
852 default=None,
852 default=None,
853 )
853 )
854 coreconfigitem(
854 coreconfigitem(
855 b'experimental',
855 b'experimental',
856 b'bundlecomplevel.bzip2',
856 b'bundlecomplevel.bzip2',
857 default=None,
857 default=None,
858 )
858 )
859 coreconfigitem(
859 coreconfigitem(
860 b'experimental',
860 b'experimental',
861 b'bundlecomplevel.gzip',
861 b'bundlecomplevel.gzip',
862 default=None,
862 default=None,
863 )
863 )
864 coreconfigitem(
864 coreconfigitem(
865 b'experimental',
865 b'experimental',
866 b'bundlecomplevel.none',
866 b'bundlecomplevel.none',
867 default=None,
867 default=None,
868 )
868 )
869 coreconfigitem(
869 coreconfigitem(
870 b'experimental',
870 b'experimental',
871 b'bundlecomplevel.zstd',
871 b'bundlecomplevel.zstd',
872 default=None,
872 default=None,
873 )
873 )
874 coreconfigitem(
874 coreconfigitem(
875 b'experimental',
875 b'experimental',
876 b'bundlecompthreads',
876 b'bundlecompthreads',
877 default=None,
877 default=None,
878 )
878 )
879 coreconfigitem(
879 coreconfigitem(
880 b'experimental',
880 b'experimental',
881 b'bundlecompthreads.bzip2',
881 b'bundlecompthreads.bzip2',
882 default=None,
882 default=None,
883 )
883 )
884 coreconfigitem(
884 coreconfigitem(
885 b'experimental',
885 b'experimental',
886 b'bundlecompthreads.gzip',
886 b'bundlecompthreads.gzip',
887 default=None,
887 default=None,
888 )
888 )
889 coreconfigitem(
889 coreconfigitem(
890 b'experimental',
890 b'experimental',
891 b'bundlecompthreads.none',
891 b'bundlecompthreads.none',
892 default=None,
892 default=None,
893 )
893 )
894 coreconfigitem(
894 coreconfigitem(
895 b'experimental',
895 b'experimental',
896 b'bundlecompthreads.zstd',
896 b'bundlecompthreads.zstd',
897 default=None,
897 default=None,
898 )
898 )
899 coreconfigitem(
899 coreconfigitem(
900 b'experimental',
900 b'experimental',
901 b'changegroup3',
901 b'changegroup3',
902 default=False,
902 default=False,
903 )
903 )
904 coreconfigitem(
904 coreconfigitem(
905 b'experimental',
905 b'experimental',
906 b'changegroup4',
906 b'changegroup4',
907 default=False,
907 default=False,
908 )
908 )
909 coreconfigitem(
909 coreconfigitem(
910 b'experimental',
910 b'experimental',
911 b'cleanup-as-archived',
911 b'cleanup-as-archived',
912 default=False,
912 default=False,
913 )
913 )
914 coreconfigitem(
914 coreconfigitem(
915 b'experimental',
915 b'experimental',
916 b'clientcompressionengines',
916 b'clientcompressionengines',
917 default=list,
917 default=list,
918 )
918 )
919 coreconfigitem(
919 coreconfigitem(
920 b'experimental',
920 b'experimental',
921 b'copytrace',
921 b'copytrace',
922 default=b'on',
922 default=b'on',
923 )
923 )
924 coreconfigitem(
924 coreconfigitem(
925 b'experimental',
925 b'experimental',
926 b'copytrace.movecandidateslimit',
926 b'copytrace.movecandidateslimit',
927 default=100,
927 default=100,
928 )
928 )
929 coreconfigitem(
929 coreconfigitem(
930 b'experimental',
930 b'experimental',
931 b'copytrace.sourcecommitlimit',
931 b'copytrace.sourcecommitlimit',
932 default=100,
932 default=100,
933 )
933 )
934 coreconfigitem(
934 coreconfigitem(
935 b'experimental',
935 b'experimental',
936 b'copies.read-from',
936 b'copies.read-from',
937 default=b"filelog-only",
937 default=b"filelog-only",
938 )
938 )
939 coreconfigitem(
939 coreconfigitem(
940 b'experimental',
940 b'experimental',
941 b'copies.write-to',
941 b'copies.write-to',
942 default=b'filelog-only',
942 default=b'filelog-only',
943 )
943 )
944 coreconfigitem(
944 coreconfigitem(
945 b'experimental',
945 b'experimental',
946 b'crecordtest',
946 b'crecordtest',
947 default=None,
947 default=None,
948 )
948 )
949 coreconfigitem(
949 coreconfigitem(
950 b'experimental',
950 b'experimental',
951 b'directaccess',
951 b'directaccess',
952 default=False,
952 default=False,
953 )
953 )
954 coreconfigitem(
954 coreconfigitem(
955 b'experimental',
955 b'experimental',
956 b'directaccess.revnums',
956 b'directaccess.revnums',
957 default=False,
957 default=False,
958 )
958 )
959 coreconfigitem(
959 coreconfigitem(
960 b'experimental',
960 b'experimental',
961 b'editortmpinhg',
961 b'editortmpinhg',
962 default=False,
962 default=False,
963 )
963 )
964 coreconfigitem(
964 coreconfigitem(
965 b'experimental',
965 b'experimental',
966 b'evolution',
966 b'evolution',
967 default=list,
967 default=list,
968 )
968 )
969 coreconfigitem(
969 coreconfigitem(
970 b'experimental',
970 b'experimental',
971 b'evolution.allowdivergence',
971 b'evolution.allowdivergence',
972 default=False,
972 default=False,
973 alias=[(b'experimental', b'allowdivergence')],
973 alias=[(b'experimental', b'allowdivergence')],
974 )
974 )
975 coreconfigitem(
975 coreconfigitem(
976 b'experimental',
976 b'experimental',
977 b'evolution.allowunstable',
977 b'evolution.allowunstable',
978 default=None,
978 default=None,
979 )
979 )
980 coreconfigitem(
980 coreconfigitem(
981 b'experimental',
981 b'experimental',
982 b'evolution.createmarkers',
982 b'evolution.createmarkers',
983 default=None,
983 default=None,
984 )
984 )
985 coreconfigitem(
985 coreconfigitem(
986 b'experimental',
986 b'experimental',
987 b'evolution.effect-flags',
987 b'evolution.effect-flags',
988 default=True,
988 default=True,
989 alias=[(b'experimental', b'effect-flags')],
989 alias=[(b'experimental', b'effect-flags')],
990 )
990 )
991 coreconfigitem(
991 coreconfigitem(
992 b'experimental',
992 b'experimental',
993 b'evolution.exchange',
993 b'evolution.exchange',
994 default=None,
994 default=None,
995 )
995 )
996 coreconfigitem(
996 coreconfigitem(
997 b'experimental',
997 b'experimental',
998 b'evolution.bundle-obsmarker',
998 b'evolution.bundle-obsmarker',
999 default=False,
999 default=False,
1000 )
1000 )
1001 coreconfigitem(
1001 coreconfigitem(
1002 b'experimental',
1002 b'experimental',
1003 b'evolution.bundle-obsmarker:mandatory',
1003 b'evolution.bundle-obsmarker:mandatory',
1004 default=True,
1004 default=True,
1005 )
1005 )
1006 coreconfigitem(
1006 coreconfigitem(
1007 b'experimental',
1007 b'experimental',
1008 b'log.topo',
1008 b'log.topo',
1009 default=False,
1009 default=False,
1010 )
1010 )
1011 coreconfigitem(
1011 coreconfigitem(
1012 b'experimental',
1012 b'experimental',
1013 b'evolution.report-instabilities',
1013 b'evolution.report-instabilities',
1014 default=True,
1014 default=True,
1015 )
1015 )
1016 coreconfigitem(
1016 coreconfigitem(
1017 b'experimental',
1017 b'experimental',
1018 b'evolution.track-operation',
1018 b'evolution.track-operation',
1019 default=True,
1019 default=True,
1020 )
1020 )
1021 # repo-level config to exclude a revset visibility
1021 # repo-level config to exclude a revset visibility
1022 #
1022 #
1023 # The target use case is to use `share` to expose different subset of the same
1023 # The target use case is to use `share` to expose different subset of the same
1024 # repository, especially server side. See also `server.view`.
1024 # repository, especially server side. See also `server.view`.
1025 coreconfigitem(
1025 coreconfigitem(
1026 b'experimental',
1026 b'experimental',
1027 b'extra-filter-revs',
1027 b'extra-filter-revs',
1028 default=None,
1028 default=None,
1029 )
1029 )
1030 coreconfigitem(
1030 coreconfigitem(
1031 b'experimental',
1031 b'experimental',
1032 b'maxdeltachainspan',
1032 b'maxdeltachainspan',
1033 default=-1,
1033 default=-1,
1034 )
1034 )
1035 # tracks files which were undeleted (merge might delete them but we explicitly
1035 # tracks files which were undeleted (merge might delete them but we explicitly
1036 # kept/undeleted them) and creates new filenodes for them
1036 # kept/undeleted them) and creates new filenodes for them
1037 coreconfigitem(
1037 coreconfigitem(
1038 b'experimental',
1038 b'experimental',
1039 b'merge-track-salvaged',
1039 b'merge-track-salvaged',
1040 default=False,
1040 default=False,
1041 )
1041 )
1042 coreconfigitem(
1042 coreconfigitem(
1043 b'experimental',
1043 b'experimental',
1044 b'mmapindexthreshold',
1044 b'mmapindexthreshold',
1045 default=None,
1045 default=None,
1046 )
1046 )
1047 coreconfigitem(
1047 coreconfigitem(
1048 b'experimental',
1048 b'experimental',
1049 b'narrow',
1049 b'narrow',
1050 default=False,
1050 default=False,
1051 )
1051 )
1052 coreconfigitem(
1052 coreconfigitem(
1053 b'experimental',
1053 b'experimental',
1054 b'nonnormalparanoidcheck',
1054 b'nonnormalparanoidcheck',
1055 default=False,
1055 default=False,
1056 )
1056 )
1057 coreconfigitem(
1057 coreconfigitem(
1058 b'experimental',
1058 b'experimental',
1059 b'exportableenviron',
1059 b'exportableenviron',
1060 default=list,
1060 default=list,
1061 )
1061 )
1062 coreconfigitem(
1062 coreconfigitem(
1063 b'experimental',
1063 b'experimental',
1064 b'extendedheader.index',
1064 b'extendedheader.index',
1065 default=None,
1065 default=None,
1066 )
1066 )
1067 coreconfigitem(
1067 coreconfigitem(
1068 b'experimental',
1068 b'experimental',
1069 b'extendedheader.similarity',
1069 b'extendedheader.similarity',
1070 default=False,
1070 default=False,
1071 )
1071 )
1072 coreconfigitem(
1072 coreconfigitem(
1073 b'experimental',
1073 b'experimental',
1074 b'graphshorten',
1074 b'graphshorten',
1075 default=False,
1075 default=False,
1076 )
1076 )
1077 coreconfigitem(
1077 coreconfigitem(
1078 b'experimental',
1078 b'experimental',
1079 b'graphstyle.parent',
1079 b'graphstyle.parent',
1080 default=dynamicdefault,
1080 default=dynamicdefault,
1081 )
1081 )
1082 coreconfigitem(
1082 coreconfigitem(
1083 b'experimental',
1083 b'experimental',
1084 b'graphstyle.missing',
1084 b'graphstyle.missing',
1085 default=dynamicdefault,
1085 default=dynamicdefault,
1086 )
1086 )
1087 coreconfigitem(
1087 coreconfigitem(
1088 b'experimental',
1088 b'experimental',
1089 b'graphstyle.grandparent',
1089 b'graphstyle.grandparent',
1090 default=dynamicdefault,
1090 default=dynamicdefault,
1091 )
1091 )
1092 coreconfigitem(
1092 coreconfigitem(
1093 b'experimental',
1093 b'experimental',
1094 b'hook-track-tags',
1094 b'hook-track-tags',
1095 default=False,
1095 default=False,
1096 )
1096 )
1097 coreconfigitem(
1097 coreconfigitem(
1098 b'experimental',
1098 b'experimental',
1099 b'httppostargs',
1099 b'httppostargs',
1100 default=False,
1100 default=False,
1101 )
1101 )
1102 coreconfigitem(b'experimental', b'nointerrupt', default=False)
1102 coreconfigitem(b'experimental', b'nointerrupt', default=False)
1103 coreconfigitem(b'experimental', b'nointerrupt-interactiveonly', default=True)
1103 coreconfigitem(b'experimental', b'nointerrupt-interactiveonly', default=True)
1104
1104
1105 coreconfigitem(
1105 coreconfigitem(
1106 b'experimental',
1106 b'experimental',
1107 b'obsmarkers-exchange-debug',
1107 b'obsmarkers-exchange-debug',
1108 default=False,
1108 default=False,
1109 )
1109 )
1110 coreconfigitem(
1110 coreconfigitem(
1111 b'experimental',
1111 b'experimental',
1112 b'remotenames',
1112 b'remotenames',
1113 default=False,
1113 default=False,
1114 )
1114 )
1115 coreconfigitem(
1115 coreconfigitem(
1116 b'experimental',
1116 b'experimental',
1117 b'removeemptydirs',
1117 b'removeemptydirs',
1118 default=True,
1118 default=True,
1119 )
1119 )
1120 coreconfigitem(
1120 coreconfigitem(
1121 b'experimental',
1121 b'experimental',
1122 b'revert.interactive.select-to-keep',
1122 b'revert.interactive.select-to-keep',
1123 default=False,
1123 default=False,
1124 )
1124 )
1125 coreconfigitem(
1125 coreconfigitem(
1126 b'experimental',
1126 b'experimental',
1127 b'revisions.prefixhexnode',
1127 b'revisions.prefixhexnode',
1128 default=False,
1128 default=False,
1129 )
1129 )
1130 # "out of experimental" todo list.
1130 # "out of experimental" todo list.
1131 #
1131 #
1132 # * include management of a persistent nodemap in the main docket
1132 # * include management of a persistent nodemap in the main docket
1133 # * enforce a "no-truncate" policy for mmap safety
1133 # * enforce a "no-truncate" policy for mmap safety
1134 # - for censoring operation
1134 # - for censoring operation
1135 # - for stripping operation
1135 # - for stripping operation
1136 # - for rollback operation
1136 # - for rollback operation
1137 # * proper streaming (race free) of the docket file
1137 # * proper streaming (race free) of the docket file
1138 # * track garbage data to evemtually allow rewriting -existing- sidedata.
1138 # * track garbage data to evemtually allow rewriting -existing- sidedata.
1139 # * Exchange-wise, we will also need to do something more efficient than
1139 # * Exchange-wise, we will also need to do something more efficient than
1140 # keeping references to the affected revlogs, especially memory-wise when
1140 # keeping references to the affected revlogs, especially memory-wise when
1141 # rewriting sidedata.
1141 # rewriting sidedata.
1142 # * introduce a proper solution to reduce the number of filelog related files.
1142 # * introduce a proper solution to reduce the number of filelog related files.
1143 # * use caching for reading sidedata (similar to what we do for data).
1143 # * use caching for reading sidedata (similar to what we do for data).
1144 # * no longer set offset=0 if sidedata_size=0 (simplify cutoff computation).
1144 # * no longer set offset=0 if sidedata_size=0 (simplify cutoff computation).
1145 # * Improvement to consider
1145 # * Improvement to consider
1146 # - avoid compression header in chunk using the default compression?
1146 # - avoid compression header in chunk using the default compression?
1147 # - forbid "inline" compression mode entirely?
1147 # - forbid "inline" compression mode entirely?
1148 # - split the data offset and flag field (the 2 bytes save are mostly trouble)
1148 # - split the data offset and flag field (the 2 bytes save are mostly trouble)
1149 # - keep track of uncompressed -chunk- size (to preallocate memory better)
1149 # - keep track of uncompressed -chunk- size (to preallocate memory better)
1150 # - keep track of chain base or size (probably not that useful anymore)
1150 # - keep track of chain base or size (probably not that useful anymore)
1151 coreconfigitem(
1151 coreconfigitem(
1152 b'experimental',
1152 b'experimental',
1153 b'revlogv2',
1153 b'revlogv2',
1154 default=None,
1154 default=None,
1155 )
1155 )
1156 coreconfigitem(
1156 coreconfigitem(
1157 b'experimental',
1157 b'experimental',
1158 b'revisions.disambiguatewithin',
1158 b'revisions.disambiguatewithin',
1159 default=None,
1159 default=None,
1160 )
1160 )
1161 coreconfigitem(
1161 coreconfigitem(
1162 b'experimental',
1162 b'experimental',
1163 b'rust.index',
1163 b'rust.index',
1164 default=False,
1164 default=False,
1165 )
1165 )
1166 coreconfigitem(
1166 coreconfigitem(
1167 b'experimental',
1167 b'experimental',
1168 b'server.filesdata.recommended-batch-size',
1168 b'server.filesdata.recommended-batch-size',
1169 default=50000,
1169 default=50000,
1170 )
1170 )
1171 coreconfigitem(
1171 coreconfigitem(
1172 b'experimental',
1172 b'experimental',
1173 b'server.manifestdata.recommended-batch-size',
1173 b'server.manifestdata.recommended-batch-size',
1174 default=100000,
1174 default=100000,
1175 )
1175 )
1176 coreconfigitem(
1176 coreconfigitem(
1177 b'experimental',
1177 b'experimental',
1178 b'server.stream-narrow-clones',
1178 b'server.stream-narrow-clones',
1179 default=False,
1179 default=False,
1180 )
1180 )
1181 coreconfigitem(
1181 coreconfigitem(
1182 b'experimental',
1182 b'experimental',
1183 b'single-head-per-branch',
1183 b'single-head-per-branch',
1184 default=False,
1184 default=False,
1185 )
1185 )
1186 coreconfigitem(
1186 coreconfigitem(
1187 b'experimental',
1187 b'experimental',
1188 b'single-head-per-branch:account-closed-heads',
1188 b'single-head-per-branch:account-closed-heads',
1189 default=False,
1189 default=False,
1190 )
1190 )
1191 coreconfigitem(
1191 coreconfigitem(
1192 b'experimental',
1192 b'experimental',
1193 b'single-head-per-branch:public-changes-only',
1193 b'single-head-per-branch:public-changes-only',
1194 default=False,
1194 default=False,
1195 )
1195 )
1196 coreconfigitem(
1196 coreconfigitem(
1197 b'experimental',
1197 b'experimental',
1198 b'sparse-read',
1198 b'sparse-read',
1199 default=False,
1199 default=False,
1200 )
1200 )
1201 coreconfigitem(
1201 coreconfigitem(
1202 b'experimental',
1202 b'experimental',
1203 b'sparse-read.density-threshold',
1203 b'sparse-read.density-threshold',
1204 default=0.50,
1204 default=0.50,
1205 )
1205 )
1206 coreconfigitem(
1206 coreconfigitem(
1207 b'experimental',
1207 b'experimental',
1208 b'sparse-read.min-gap-size',
1208 b'sparse-read.min-gap-size',
1209 default=b'65K',
1209 default=b'65K',
1210 )
1210 )
1211 coreconfigitem(
1211 coreconfigitem(
1212 b'experimental',
1212 b'experimental',
1213 b'treemanifest',
1213 b'treemanifest',
1214 default=False,
1214 default=False,
1215 )
1215 )
1216 coreconfigitem(
1216 coreconfigitem(
1217 b'experimental',
1217 b'experimental',
1218 b'update.atomic-file',
1218 b'update.atomic-file',
1219 default=False,
1219 default=False,
1220 )
1220 )
1221 coreconfigitem(
1221 coreconfigitem(
1222 b'experimental',
1222 b'experimental',
1223 b'web.full-garbage-collection-rate',
1223 b'web.full-garbage-collection-rate',
1224 default=1, # still forcing a full collection on each request
1224 default=1, # still forcing a full collection on each request
1225 )
1225 )
1226 coreconfigitem(
1226 coreconfigitem(
1227 b'experimental',
1227 b'experimental',
1228 b'worker.wdir-get-thread-safe',
1228 b'worker.wdir-get-thread-safe',
1229 default=False,
1229 default=False,
1230 )
1230 )
1231 coreconfigitem(
1231 coreconfigitem(
1232 b'experimental',
1232 b'experimental',
1233 b'worker.repository-upgrade',
1233 b'worker.repository-upgrade',
1234 default=False,
1234 default=False,
1235 )
1235 )
1236 coreconfigitem(
1236 coreconfigitem(
1237 b'experimental',
1237 b'experimental',
1238 b'xdiff',
1238 b'xdiff',
1239 default=False,
1239 default=False,
1240 )
1240 )
1241 coreconfigitem(
1241 coreconfigitem(
1242 b'extensions',
1242 b'extensions',
1243 b'[^:]*',
1243 b'[^:]*',
1244 default=None,
1244 default=None,
1245 generic=True,
1245 generic=True,
1246 )
1246 )
1247 coreconfigitem(
1247 coreconfigitem(
1248 b'extensions',
1248 b'extensions',
1249 b'[^:]*:required',
1249 b'[^:]*:required',
1250 default=False,
1250 default=False,
1251 generic=True,
1251 generic=True,
1252 )
1252 )
1253 coreconfigitem(
1253 coreconfigitem(
1254 b'extdata',
1254 b'extdata',
1255 b'.*',
1255 b'.*',
1256 default=None,
1256 default=None,
1257 generic=True,
1257 generic=True,
1258 )
1258 )
1259 coreconfigitem(
1259 coreconfigitem(
1260 b'format',
1260 b'format',
1261 b'bookmarks-in-store',
1261 b'bookmarks-in-store',
1262 default=False,
1262 default=False,
1263 )
1263 )
1264 coreconfigitem(
1264 coreconfigitem(
1265 b'format',
1265 b'format',
1266 b'chunkcachesize',
1266 b'chunkcachesize',
1267 default=None,
1267 default=None,
1268 experimental=True,
1268 experimental=True,
1269 )
1269 )
1270 coreconfigitem(
1270 coreconfigitem(
1271 # Enable this dirstate format *when creating a new repository*.
1271 # Enable this dirstate format *when creating a new repository*.
1272 # Which format to use for existing repos is controlled by .hg/requires
1272 # Which format to use for existing repos is controlled by .hg/requires
1273 b'format',
1273 b'format',
1274 b'use-dirstate-v2',
1274 b'use-dirstate-v2',
1275 default=False,
1275 default=False,
1276 experimental=True,
1276 experimental=True,
1277 alias=[(b'format', b'exp-rc-dirstate-v2')],
1277 alias=[(b'format', b'exp-rc-dirstate-v2')],
1278 )
1278 )
1279 coreconfigitem(
1279 coreconfigitem(
1280 b'format',
1280 b'format',
1281 b'use-dirstate-tracked-hint',
1281 b'use-dirstate-tracked-hint',
1282 default=False,
1282 default=False,
1283 experimental=True,
1283 experimental=True,
1284 )
1284 )
1285 coreconfigitem(
1285 coreconfigitem(
1286 b'format',
1286 b'format',
1287 b'use-dirstate-tracked-hint.version',
1287 b'use-dirstate-tracked-hint.version',
1288 default=1,
1288 default=1,
1289 experimental=True,
1289 experimental=True,
1290 )
1290 )
1291 coreconfigitem(
1291 coreconfigitem(
1292 b'format',
1292 b'format',
1293 b'dotencode',
1293 b'dotencode',
1294 default=True,
1294 default=True,
1295 )
1295 )
1296 coreconfigitem(
1296 coreconfigitem(
1297 b'format',
1297 b'format',
1298 b'generaldelta',
1298 b'generaldelta',
1299 default=False,
1299 default=False,
1300 experimental=True,
1300 experimental=True,
1301 )
1301 )
1302 coreconfigitem(
1302 coreconfigitem(
1303 b'format',
1303 b'format',
1304 b'manifestcachesize',
1304 b'manifestcachesize',
1305 default=None,
1305 default=None,
1306 experimental=True,
1306 experimental=True,
1307 )
1307 )
1308 coreconfigitem(
1308 coreconfigitem(
1309 b'format',
1309 b'format',
1310 b'maxchainlen',
1310 b'maxchainlen',
1311 default=dynamicdefault,
1311 default=dynamicdefault,
1312 experimental=True,
1312 experimental=True,
1313 )
1313 )
1314 coreconfigitem(
1314 coreconfigitem(
1315 b'format',
1315 b'format',
1316 b'obsstore-version',
1316 b'obsstore-version',
1317 default=None,
1317 default=None,
1318 )
1318 )
1319 coreconfigitem(
1319 coreconfigitem(
1320 b'format',
1320 b'format',
1321 b'sparse-revlog',
1321 b'sparse-revlog',
1322 default=True,
1322 default=True,
1323 )
1323 )
1324 coreconfigitem(
1324 coreconfigitem(
1325 b'format',
1325 b'format',
1326 b'revlog-compression',
1326 b'revlog-compression',
1327 default=lambda: [b'zstd', b'zlib'],
1327 default=lambda: [b'zstd', b'zlib'],
1328 alias=[(b'experimental', b'format.compression')],
1328 alias=[(b'experimental', b'format.compression')],
1329 )
1329 )
1330 # Experimental TODOs:
1330 # Experimental TODOs:
1331 #
1331 #
1332 # * Same as for revlogv2 (but for the reduction of the number of files)
1332 # * Same as for revlogv2 (but for the reduction of the number of files)
1333 # * Actually computing the rank of changesets
1333 # * Actually computing the rank of changesets
1334 # * Improvement to investigate
1334 # * Improvement to investigate
1335 # - storing .hgtags fnode
1335 # - storing .hgtags fnode
1336 # - storing branch related identifier
1336 # - storing branch related identifier
1337
1337
1338 coreconfigitem(
1338 coreconfigitem(
1339 b'format',
1339 b'format',
1340 b'exp-use-changelog-v2',
1340 b'exp-use-changelog-v2',
1341 default=None,
1341 default=None,
1342 experimental=True,
1342 experimental=True,
1343 )
1343 )
1344 coreconfigitem(
1344 coreconfigitem(
1345 b'format',
1345 b'format',
1346 b'usefncache',
1346 b'usefncache',
1347 default=True,
1347 default=True,
1348 )
1348 )
1349 coreconfigitem(
1349 coreconfigitem(
1350 b'format',
1350 b'format',
1351 b'usegeneraldelta',
1351 b'usegeneraldelta',
1352 default=True,
1352 default=True,
1353 )
1353 )
1354 coreconfigitem(
1354 coreconfigitem(
1355 b'format',
1355 b'format',
1356 b'usestore',
1356 b'usestore',
1357 default=True,
1357 default=True,
1358 )
1358 )
1359
1359
1360
1360
1361 def _persistent_nodemap_default():
1361 def _persistent_nodemap_default():
1362 """compute `use-persistent-nodemap` default value
1362 """compute `use-persistent-nodemap` default value
1363
1363
1364 The feature is disabled unless a fast implementation is available.
1364 The feature is disabled unless a fast implementation is available.
1365 """
1365 """
1366 from . import policy
1366 from . import policy
1367
1367
1368 return policy.importrust('revlog') is not None
1368 return policy.importrust('revlog') is not None
1369
1369
1370
1370
1371 coreconfigitem(
1371 coreconfigitem(
1372 b'format',
1372 b'format',
1373 b'use-persistent-nodemap',
1373 b'use-persistent-nodemap',
1374 default=_persistent_nodemap_default,
1374 default=_persistent_nodemap_default,
1375 )
1375 )
1376 coreconfigitem(
1376 coreconfigitem(
1377 b'format',
1377 b'format',
1378 b'exp-use-copies-side-data-changeset',
1378 b'exp-use-copies-side-data-changeset',
1379 default=False,
1379 default=False,
1380 experimental=True,
1380 experimental=True,
1381 )
1381 )
1382 coreconfigitem(
1382 coreconfigitem(
1383 b'format',
1383 b'format',
1384 b'use-share-safe',
1384 b'use-share-safe',
1385 default=True,
1385 default=True,
1386 )
1386 )
1387 coreconfigitem(
1387 coreconfigitem(
1388 b'format',
1388 b'format',
1389 b'internal-phase',
1389 b'internal-phase',
1390 default=False,
1390 default=False,
1391 experimental=True,
1391 experimental=True,
1392 )
1392 )
1393 coreconfigitem(
1393 coreconfigitem(
1394 b'fsmonitor',
1394 b'fsmonitor',
1395 b'warn_when_unused',
1395 b'warn_when_unused',
1396 default=True,
1396 default=True,
1397 )
1397 )
1398 coreconfigitem(
1398 coreconfigitem(
1399 b'fsmonitor',
1399 b'fsmonitor',
1400 b'warn_update_file_count',
1400 b'warn_update_file_count',
1401 default=50000,
1401 default=50000,
1402 )
1402 )
1403 coreconfigitem(
1403 coreconfigitem(
1404 b'fsmonitor',
1404 b'fsmonitor',
1405 b'warn_update_file_count_rust',
1405 b'warn_update_file_count_rust',
1406 default=400000,
1406 default=400000,
1407 )
1407 )
1408 coreconfigitem(
1408 coreconfigitem(
1409 b'help',
1409 b'help',
1410 br'hidden-command\..*',
1410 br'hidden-command\..*',
1411 default=False,
1411 default=False,
1412 generic=True,
1412 generic=True,
1413 )
1413 )
1414 coreconfigitem(
1414 coreconfigitem(
1415 b'help',
1415 b'help',
1416 br'hidden-topic\..*',
1416 br'hidden-topic\..*',
1417 default=False,
1417 default=False,
1418 generic=True,
1418 generic=True,
1419 )
1419 )
1420 coreconfigitem(
1420 coreconfigitem(
1421 b'hooks',
1421 b'hooks',
1422 b'[^:]*',
1422 b'[^:]*',
1423 default=dynamicdefault,
1423 default=dynamicdefault,
1424 generic=True,
1424 generic=True,
1425 )
1425 )
1426 coreconfigitem(
1426 coreconfigitem(
1427 b'hooks',
1427 b'hooks',
1428 b'.*:run-with-plain',
1428 b'.*:run-with-plain',
1429 default=True,
1429 default=True,
1430 generic=True,
1430 generic=True,
1431 )
1431 )
1432 coreconfigitem(
1432 coreconfigitem(
1433 b'hgweb-paths',
1433 b'hgweb-paths',
1434 b'.*',
1434 b'.*',
1435 default=list,
1435 default=list,
1436 generic=True,
1436 generic=True,
1437 )
1437 )
1438 coreconfigitem(
1438 coreconfigitem(
1439 b'hostfingerprints',
1439 b'hostfingerprints',
1440 b'.*',
1440 b'.*',
1441 default=list,
1441 default=list,
1442 generic=True,
1442 generic=True,
1443 )
1443 )
1444 coreconfigitem(
1444 coreconfigitem(
1445 b'hostsecurity',
1445 b'hostsecurity',
1446 b'ciphers',
1446 b'ciphers',
1447 default=None,
1447 default=None,
1448 )
1448 )
1449 coreconfigitem(
1449 coreconfigitem(
1450 b'hostsecurity',
1450 b'hostsecurity',
1451 b'minimumprotocol',
1451 b'minimumprotocol',
1452 default=dynamicdefault,
1452 default=dynamicdefault,
1453 )
1453 )
1454 coreconfigitem(
1454 coreconfigitem(
1455 b'hostsecurity',
1455 b'hostsecurity',
1456 b'.*:minimumprotocol$',
1456 b'.*:minimumprotocol$',
1457 default=dynamicdefault,
1457 default=dynamicdefault,
1458 generic=True,
1458 generic=True,
1459 )
1459 )
1460 coreconfigitem(
1460 coreconfigitem(
1461 b'hostsecurity',
1461 b'hostsecurity',
1462 b'.*:ciphers$',
1462 b'.*:ciphers$',
1463 default=dynamicdefault,
1463 default=dynamicdefault,
1464 generic=True,
1464 generic=True,
1465 )
1465 )
1466 coreconfigitem(
1466 coreconfigitem(
1467 b'hostsecurity',
1467 b'hostsecurity',
1468 b'.*:fingerprints$',
1468 b'.*:fingerprints$',
1469 default=list,
1469 default=list,
1470 generic=True,
1470 generic=True,
1471 )
1471 )
1472 coreconfigitem(
1472 coreconfigitem(
1473 b'hostsecurity',
1473 b'hostsecurity',
1474 b'.*:verifycertsfile$',
1474 b'.*:verifycertsfile$',
1475 default=None,
1475 default=None,
1476 generic=True,
1476 generic=True,
1477 )
1477 )
1478
1478
1479 coreconfigitem(
1479 coreconfigitem(
1480 b'http_proxy',
1480 b'http_proxy',
1481 b'always',
1481 b'always',
1482 default=False,
1482 default=False,
1483 )
1483 )
1484 coreconfigitem(
1484 coreconfigitem(
1485 b'http_proxy',
1485 b'http_proxy',
1486 b'host',
1486 b'host',
1487 default=None,
1487 default=None,
1488 )
1488 )
1489 coreconfigitem(
1489 coreconfigitem(
1490 b'http_proxy',
1490 b'http_proxy',
1491 b'no',
1491 b'no',
1492 default=list,
1492 default=list,
1493 )
1493 )
1494 coreconfigitem(
1494 coreconfigitem(
1495 b'http_proxy',
1495 b'http_proxy',
1496 b'passwd',
1496 b'passwd',
1497 default=None,
1497 default=None,
1498 )
1498 )
1499 coreconfigitem(
1499 coreconfigitem(
1500 b'http_proxy',
1500 b'http_proxy',
1501 b'user',
1501 b'user',
1502 default=None,
1502 default=None,
1503 )
1503 )
1504
1504
1505 coreconfigitem(
1505 coreconfigitem(
1506 b'http',
1506 b'http',
1507 b'timeout',
1507 b'timeout',
1508 default=None,
1508 default=None,
1509 )
1509 )
1510
1510
1511 coreconfigitem(
1511 coreconfigitem(
1512 b'logtoprocess',
1512 b'logtoprocess',
1513 b'commandexception',
1513 b'commandexception',
1514 default=None,
1514 default=None,
1515 )
1515 )
1516 coreconfigitem(
1516 coreconfigitem(
1517 b'logtoprocess',
1517 b'logtoprocess',
1518 b'commandfinish',
1518 b'commandfinish',
1519 default=None,
1519 default=None,
1520 )
1520 )
1521 coreconfigitem(
1521 coreconfigitem(
1522 b'logtoprocess',
1522 b'logtoprocess',
1523 b'command',
1523 b'command',
1524 default=None,
1524 default=None,
1525 )
1525 )
1526 coreconfigitem(
1526 coreconfigitem(
1527 b'logtoprocess',
1527 b'logtoprocess',
1528 b'develwarn',
1528 b'develwarn',
1529 default=None,
1529 default=None,
1530 )
1530 )
1531 coreconfigitem(
1531 coreconfigitem(
1532 b'logtoprocess',
1532 b'logtoprocess',
1533 b'uiblocked',
1533 b'uiblocked',
1534 default=None,
1534 default=None,
1535 )
1535 )
1536 coreconfigitem(
1536 coreconfigitem(
1537 b'merge',
1537 b'merge',
1538 b'checkunknown',
1538 b'checkunknown',
1539 default=b'abort',
1539 default=b'abort',
1540 )
1540 )
1541 coreconfigitem(
1541 coreconfigitem(
1542 b'merge',
1542 b'merge',
1543 b'checkignored',
1543 b'checkignored',
1544 default=b'abort',
1544 default=b'abort',
1545 )
1545 )
1546 coreconfigitem(
1546 coreconfigitem(
1547 b'experimental',
1547 b'experimental',
1548 b'merge.checkpathconflicts',
1548 b'merge.checkpathconflicts',
1549 default=False,
1549 default=False,
1550 )
1550 )
1551 coreconfigitem(
1551 coreconfigitem(
1552 b'merge',
1552 b'merge',
1553 b'followcopies',
1553 b'followcopies',
1554 default=True,
1554 default=True,
1555 )
1555 )
1556 coreconfigitem(
1556 coreconfigitem(
1557 b'merge',
1557 b'merge',
1558 b'on-failure',
1558 b'on-failure',
1559 default=b'continue',
1559 default=b'continue',
1560 )
1560 )
1561 coreconfigitem(
1561 coreconfigitem(
1562 b'merge',
1562 b'merge',
1563 b'preferancestor',
1563 b'preferancestor',
1564 default=lambda: [b'*'],
1564 default=lambda: [b'*'],
1565 experimental=True,
1565 experimental=True,
1566 )
1566 )
1567 coreconfigitem(
1567 coreconfigitem(
1568 b'merge',
1568 b'merge',
1569 b'strict-capability-check',
1569 b'strict-capability-check',
1570 default=False,
1570 default=False,
1571 )
1571 )
1572 coreconfigitem(
1572 coreconfigitem(
1573 b'partial-merge-tools',
1574 b'.*',
1575 default=None,
1576 generic=True,
1577 experimental=True,
1578 )
1579 coreconfigitem(
1580 b'partial-merge-tools',
1581 br'.*\.patterns',
1582 default=dynamicdefault,
1583 generic=True,
1584 priority=-1,
1585 experimental=True,
1586 )
1587 coreconfigitem(
1588 b'partial-merge-tools',
1589 br'.*\.executable$',
1590 default=dynamicdefault,
1591 generic=True,
1592 priority=-1,
1593 experimental=True,
1594 )
1595 coreconfigitem(
1596 b'partial-merge-tools',
1597 br'.*\.order',
1598 default=0,
1599 generic=True,
1600 priority=-1,
1601 experimental=True,
1602 )
1603 coreconfigitem(
1573 b'merge-tools',
1604 b'merge-tools',
1574 b'.*',
1605 b'.*',
1575 default=None,
1606 default=None,
1576 generic=True,
1607 generic=True,
1577 )
1608 )
1578 coreconfigitem(
1609 coreconfigitem(
1579 b'merge-tools',
1610 b'merge-tools',
1580 br'.*\.args$',
1611 br'.*\.args$',
1581 default=b"$local $base $other",
1612 default=b"$local $base $other",
1582 generic=True,
1613 generic=True,
1583 priority=-1,
1614 priority=-1,
1584 )
1615 )
1585 coreconfigitem(
1616 coreconfigitem(
1586 b'merge-tools',
1617 b'merge-tools',
1587 br'.*\.binary$',
1618 br'.*\.binary$',
1588 default=False,
1619 default=False,
1589 generic=True,
1620 generic=True,
1590 priority=-1,
1621 priority=-1,
1591 )
1622 )
1592 coreconfigitem(
1623 coreconfigitem(
1593 b'merge-tools',
1624 b'merge-tools',
1594 br'.*\.check$',
1625 br'.*\.check$',
1595 default=list,
1626 default=list,
1596 generic=True,
1627 generic=True,
1597 priority=-1,
1628 priority=-1,
1598 )
1629 )
1599 coreconfigitem(
1630 coreconfigitem(
1600 b'merge-tools',
1631 b'merge-tools',
1601 br'.*\.checkchanged$',
1632 br'.*\.checkchanged$',
1602 default=False,
1633 default=False,
1603 generic=True,
1634 generic=True,
1604 priority=-1,
1635 priority=-1,
1605 )
1636 )
1606 coreconfigitem(
1637 coreconfigitem(
1607 b'merge-tools',
1638 b'merge-tools',
1608 br'.*\.executable$',
1639 br'.*\.executable$',
1609 default=dynamicdefault,
1640 default=dynamicdefault,
1610 generic=True,
1641 generic=True,
1611 priority=-1,
1642 priority=-1,
1612 )
1643 )
1613 coreconfigitem(
1644 coreconfigitem(
1614 b'merge-tools',
1645 b'merge-tools',
1615 br'.*\.fixeol$',
1646 br'.*\.fixeol$',
1616 default=False,
1647 default=False,
1617 generic=True,
1648 generic=True,
1618 priority=-1,
1649 priority=-1,
1619 )
1650 )
1620 coreconfigitem(
1651 coreconfigitem(
1621 b'merge-tools',
1652 b'merge-tools',
1622 br'.*\.gui$',
1653 br'.*\.gui$',
1623 default=False,
1654 default=False,
1624 generic=True,
1655 generic=True,
1625 priority=-1,
1656 priority=-1,
1626 )
1657 )
1627 coreconfigitem(
1658 coreconfigitem(
1628 b'merge-tools',
1659 b'merge-tools',
1629 br'.*\.mergemarkers$',
1660 br'.*\.mergemarkers$',
1630 default=b'basic',
1661 default=b'basic',
1631 generic=True,
1662 generic=True,
1632 priority=-1,
1663 priority=-1,
1633 )
1664 )
1634 coreconfigitem(
1665 coreconfigitem(
1635 b'merge-tools',
1666 b'merge-tools',
1636 br'.*\.mergemarkertemplate$',
1667 br'.*\.mergemarkertemplate$',
1637 default=dynamicdefault, # take from command-templates.mergemarker
1668 default=dynamicdefault, # take from command-templates.mergemarker
1638 generic=True,
1669 generic=True,
1639 priority=-1,
1670 priority=-1,
1640 )
1671 )
1641 coreconfigitem(
1672 coreconfigitem(
1642 b'merge-tools',
1673 b'merge-tools',
1643 br'.*\.priority$',
1674 br'.*\.priority$',
1644 default=0,
1675 default=0,
1645 generic=True,
1676 generic=True,
1646 priority=-1,
1677 priority=-1,
1647 )
1678 )
1648 coreconfigitem(
1679 coreconfigitem(
1649 b'merge-tools',
1680 b'merge-tools',
1650 br'.*\.premerge$',
1681 br'.*\.premerge$',
1651 default=dynamicdefault,
1682 default=dynamicdefault,
1652 generic=True,
1683 generic=True,
1653 priority=-1,
1684 priority=-1,
1654 )
1685 )
1655 coreconfigitem(
1686 coreconfigitem(
1656 b'merge-tools',
1687 b'merge-tools',
1657 br'.*\.symlink$',
1688 br'.*\.symlink$',
1658 default=False,
1689 default=False,
1659 generic=True,
1690 generic=True,
1660 priority=-1,
1691 priority=-1,
1661 )
1692 )
1662 coreconfigitem(
1693 coreconfigitem(
1663 b'pager',
1694 b'pager',
1664 b'attend-.*',
1695 b'attend-.*',
1665 default=dynamicdefault,
1696 default=dynamicdefault,
1666 generic=True,
1697 generic=True,
1667 )
1698 )
1668 coreconfigitem(
1699 coreconfigitem(
1669 b'pager',
1700 b'pager',
1670 b'ignore',
1701 b'ignore',
1671 default=list,
1702 default=list,
1672 )
1703 )
1673 coreconfigitem(
1704 coreconfigitem(
1674 b'pager',
1705 b'pager',
1675 b'pager',
1706 b'pager',
1676 default=dynamicdefault,
1707 default=dynamicdefault,
1677 )
1708 )
1678 coreconfigitem(
1709 coreconfigitem(
1679 b'patch',
1710 b'patch',
1680 b'eol',
1711 b'eol',
1681 default=b'strict',
1712 default=b'strict',
1682 )
1713 )
1683 coreconfigitem(
1714 coreconfigitem(
1684 b'patch',
1715 b'patch',
1685 b'fuzz',
1716 b'fuzz',
1686 default=2,
1717 default=2,
1687 )
1718 )
1688 coreconfigitem(
1719 coreconfigitem(
1689 b'paths',
1720 b'paths',
1690 b'default',
1721 b'default',
1691 default=None,
1722 default=None,
1692 )
1723 )
1693 coreconfigitem(
1724 coreconfigitem(
1694 b'paths',
1725 b'paths',
1695 b'default-push',
1726 b'default-push',
1696 default=None,
1727 default=None,
1697 )
1728 )
1698 coreconfigitem(
1729 coreconfigitem(
1699 b'paths',
1730 b'paths',
1700 b'.*',
1731 b'.*',
1701 default=None,
1732 default=None,
1702 generic=True,
1733 generic=True,
1703 )
1734 )
1704 coreconfigitem(
1735 coreconfigitem(
1705 b'phases',
1736 b'phases',
1706 b'checksubrepos',
1737 b'checksubrepos',
1707 default=b'follow',
1738 default=b'follow',
1708 )
1739 )
1709 coreconfigitem(
1740 coreconfigitem(
1710 b'phases',
1741 b'phases',
1711 b'new-commit',
1742 b'new-commit',
1712 default=b'draft',
1743 default=b'draft',
1713 )
1744 )
1714 coreconfigitem(
1745 coreconfigitem(
1715 b'phases',
1746 b'phases',
1716 b'publish',
1747 b'publish',
1717 default=True,
1748 default=True,
1718 )
1749 )
1719 coreconfigitem(
1750 coreconfigitem(
1720 b'profiling',
1751 b'profiling',
1721 b'enabled',
1752 b'enabled',
1722 default=False,
1753 default=False,
1723 )
1754 )
1724 coreconfigitem(
1755 coreconfigitem(
1725 b'profiling',
1756 b'profiling',
1726 b'format',
1757 b'format',
1727 default=b'text',
1758 default=b'text',
1728 )
1759 )
1729 coreconfigitem(
1760 coreconfigitem(
1730 b'profiling',
1761 b'profiling',
1731 b'freq',
1762 b'freq',
1732 default=1000,
1763 default=1000,
1733 )
1764 )
1734 coreconfigitem(
1765 coreconfigitem(
1735 b'profiling',
1766 b'profiling',
1736 b'limit',
1767 b'limit',
1737 default=30,
1768 default=30,
1738 )
1769 )
1739 coreconfigitem(
1770 coreconfigitem(
1740 b'profiling',
1771 b'profiling',
1741 b'nested',
1772 b'nested',
1742 default=0,
1773 default=0,
1743 )
1774 )
1744 coreconfigitem(
1775 coreconfigitem(
1745 b'profiling',
1776 b'profiling',
1746 b'output',
1777 b'output',
1747 default=None,
1778 default=None,
1748 )
1779 )
1749 coreconfigitem(
1780 coreconfigitem(
1750 b'profiling',
1781 b'profiling',
1751 b'showmax',
1782 b'showmax',
1752 default=0.999,
1783 default=0.999,
1753 )
1784 )
1754 coreconfigitem(
1785 coreconfigitem(
1755 b'profiling',
1786 b'profiling',
1756 b'showmin',
1787 b'showmin',
1757 default=dynamicdefault,
1788 default=dynamicdefault,
1758 )
1789 )
1759 coreconfigitem(
1790 coreconfigitem(
1760 b'profiling',
1791 b'profiling',
1761 b'showtime',
1792 b'showtime',
1762 default=True,
1793 default=True,
1763 )
1794 )
1764 coreconfigitem(
1795 coreconfigitem(
1765 b'profiling',
1796 b'profiling',
1766 b'sort',
1797 b'sort',
1767 default=b'inlinetime',
1798 default=b'inlinetime',
1768 )
1799 )
1769 coreconfigitem(
1800 coreconfigitem(
1770 b'profiling',
1801 b'profiling',
1771 b'statformat',
1802 b'statformat',
1772 default=b'hotpath',
1803 default=b'hotpath',
1773 )
1804 )
1774 coreconfigitem(
1805 coreconfigitem(
1775 b'profiling',
1806 b'profiling',
1776 b'time-track',
1807 b'time-track',
1777 default=dynamicdefault,
1808 default=dynamicdefault,
1778 )
1809 )
1779 coreconfigitem(
1810 coreconfigitem(
1780 b'profiling',
1811 b'profiling',
1781 b'type',
1812 b'type',
1782 default=b'stat',
1813 default=b'stat',
1783 )
1814 )
1784 coreconfigitem(
1815 coreconfigitem(
1785 b'progress',
1816 b'progress',
1786 b'assume-tty',
1817 b'assume-tty',
1787 default=False,
1818 default=False,
1788 )
1819 )
1789 coreconfigitem(
1820 coreconfigitem(
1790 b'progress',
1821 b'progress',
1791 b'changedelay',
1822 b'changedelay',
1792 default=1,
1823 default=1,
1793 )
1824 )
1794 coreconfigitem(
1825 coreconfigitem(
1795 b'progress',
1826 b'progress',
1796 b'clear-complete',
1827 b'clear-complete',
1797 default=True,
1828 default=True,
1798 )
1829 )
1799 coreconfigitem(
1830 coreconfigitem(
1800 b'progress',
1831 b'progress',
1801 b'debug',
1832 b'debug',
1802 default=False,
1833 default=False,
1803 )
1834 )
1804 coreconfigitem(
1835 coreconfigitem(
1805 b'progress',
1836 b'progress',
1806 b'delay',
1837 b'delay',
1807 default=3,
1838 default=3,
1808 )
1839 )
1809 coreconfigitem(
1840 coreconfigitem(
1810 b'progress',
1841 b'progress',
1811 b'disable',
1842 b'disable',
1812 default=False,
1843 default=False,
1813 )
1844 )
1814 coreconfigitem(
1845 coreconfigitem(
1815 b'progress',
1846 b'progress',
1816 b'estimateinterval',
1847 b'estimateinterval',
1817 default=60.0,
1848 default=60.0,
1818 )
1849 )
1819 coreconfigitem(
1850 coreconfigitem(
1820 b'progress',
1851 b'progress',
1821 b'format',
1852 b'format',
1822 default=lambda: [b'topic', b'bar', b'number', b'estimate'],
1853 default=lambda: [b'topic', b'bar', b'number', b'estimate'],
1823 )
1854 )
1824 coreconfigitem(
1855 coreconfigitem(
1825 b'progress',
1856 b'progress',
1826 b'refresh',
1857 b'refresh',
1827 default=0.1,
1858 default=0.1,
1828 )
1859 )
1829 coreconfigitem(
1860 coreconfigitem(
1830 b'progress',
1861 b'progress',
1831 b'width',
1862 b'width',
1832 default=dynamicdefault,
1863 default=dynamicdefault,
1833 )
1864 )
1834 coreconfigitem(
1865 coreconfigitem(
1835 b'pull',
1866 b'pull',
1836 b'confirm',
1867 b'confirm',
1837 default=False,
1868 default=False,
1838 )
1869 )
1839 coreconfigitem(
1870 coreconfigitem(
1840 b'push',
1871 b'push',
1841 b'pushvars.server',
1872 b'pushvars.server',
1842 default=False,
1873 default=False,
1843 )
1874 )
1844 coreconfigitem(
1875 coreconfigitem(
1845 b'rewrite',
1876 b'rewrite',
1846 b'backup-bundle',
1877 b'backup-bundle',
1847 default=True,
1878 default=True,
1848 alias=[(b'ui', b'history-editing-backup')],
1879 alias=[(b'ui', b'history-editing-backup')],
1849 )
1880 )
1850 coreconfigitem(
1881 coreconfigitem(
1851 b'rewrite',
1882 b'rewrite',
1852 b'update-timestamp',
1883 b'update-timestamp',
1853 default=False,
1884 default=False,
1854 )
1885 )
1855 coreconfigitem(
1886 coreconfigitem(
1856 b'rewrite',
1887 b'rewrite',
1857 b'empty-successor',
1888 b'empty-successor',
1858 default=b'skip',
1889 default=b'skip',
1859 experimental=True,
1890 experimental=True,
1860 )
1891 )
1861 # experimental as long as format.use-dirstate-v2 is.
1892 # experimental as long as format.use-dirstate-v2 is.
1862 coreconfigitem(
1893 coreconfigitem(
1863 b'storage',
1894 b'storage',
1864 b'dirstate-v2.slow-path',
1895 b'dirstate-v2.slow-path',
1865 default=b"abort",
1896 default=b"abort",
1866 experimental=True,
1897 experimental=True,
1867 )
1898 )
1868 coreconfigitem(
1899 coreconfigitem(
1869 b'storage',
1900 b'storage',
1870 b'new-repo-backend',
1901 b'new-repo-backend',
1871 default=b'revlogv1',
1902 default=b'revlogv1',
1872 experimental=True,
1903 experimental=True,
1873 )
1904 )
1874 coreconfigitem(
1905 coreconfigitem(
1875 b'storage',
1906 b'storage',
1876 b'revlog.optimize-delta-parent-choice',
1907 b'revlog.optimize-delta-parent-choice',
1877 default=True,
1908 default=True,
1878 alias=[(b'format', b'aggressivemergedeltas')],
1909 alias=[(b'format', b'aggressivemergedeltas')],
1879 )
1910 )
1880 coreconfigitem(
1911 coreconfigitem(
1881 b'storage',
1912 b'storage',
1882 b'revlog.issue6528.fix-incoming',
1913 b'revlog.issue6528.fix-incoming',
1883 default=True,
1914 default=True,
1884 )
1915 )
1885 # experimental as long as rust is experimental (or a C version is implemented)
1916 # experimental as long as rust is experimental (or a C version is implemented)
1886 coreconfigitem(
1917 coreconfigitem(
1887 b'storage',
1918 b'storage',
1888 b'revlog.persistent-nodemap.mmap',
1919 b'revlog.persistent-nodemap.mmap',
1889 default=True,
1920 default=True,
1890 )
1921 )
1891 # experimental as long as format.use-persistent-nodemap is.
1922 # experimental as long as format.use-persistent-nodemap is.
1892 coreconfigitem(
1923 coreconfigitem(
1893 b'storage',
1924 b'storage',
1894 b'revlog.persistent-nodemap.slow-path',
1925 b'revlog.persistent-nodemap.slow-path',
1895 default=b"abort",
1926 default=b"abort",
1896 )
1927 )
1897
1928
1898 coreconfigitem(
1929 coreconfigitem(
1899 b'storage',
1930 b'storage',
1900 b'revlog.reuse-external-delta',
1931 b'revlog.reuse-external-delta',
1901 default=True,
1932 default=True,
1902 )
1933 )
1903 coreconfigitem(
1934 coreconfigitem(
1904 b'storage',
1935 b'storage',
1905 b'revlog.reuse-external-delta-parent',
1936 b'revlog.reuse-external-delta-parent',
1906 default=None,
1937 default=None,
1907 )
1938 )
1908 coreconfigitem(
1939 coreconfigitem(
1909 b'storage',
1940 b'storage',
1910 b'revlog.zlib.level',
1941 b'revlog.zlib.level',
1911 default=None,
1942 default=None,
1912 )
1943 )
1913 coreconfigitem(
1944 coreconfigitem(
1914 b'storage',
1945 b'storage',
1915 b'revlog.zstd.level',
1946 b'revlog.zstd.level',
1916 default=None,
1947 default=None,
1917 )
1948 )
1918 coreconfigitem(
1949 coreconfigitem(
1919 b'server',
1950 b'server',
1920 b'bookmarks-pushkey-compat',
1951 b'bookmarks-pushkey-compat',
1921 default=True,
1952 default=True,
1922 )
1953 )
1923 coreconfigitem(
1954 coreconfigitem(
1924 b'server',
1955 b'server',
1925 b'bundle1',
1956 b'bundle1',
1926 default=True,
1957 default=True,
1927 )
1958 )
1928 coreconfigitem(
1959 coreconfigitem(
1929 b'server',
1960 b'server',
1930 b'bundle1gd',
1961 b'bundle1gd',
1931 default=None,
1962 default=None,
1932 )
1963 )
1933 coreconfigitem(
1964 coreconfigitem(
1934 b'server',
1965 b'server',
1935 b'bundle1.pull',
1966 b'bundle1.pull',
1936 default=None,
1967 default=None,
1937 )
1968 )
1938 coreconfigitem(
1969 coreconfigitem(
1939 b'server',
1970 b'server',
1940 b'bundle1gd.pull',
1971 b'bundle1gd.pull',
1941 default=None,
1972 default=None,
1942 )
1973 )
1943 coreconfigitem(
1974 coreconfigitem(
1944 b'server',
1975 b'server',
1945 b'bundle1.push',
1976 b'bundle1.push',
1946 default=None,
1977 default=None,
1947 )
1978 )
1948 coreconfigitem(
1979 coreconfigitem(
1949 b'server',
1980 b'server',
1950 b'bundle1gd.push',
1981 b'bundle1gd.push',
1951 default=None,
1982 default=None,
1952 )
1983 )
1953 coreconfigitem(
1984 coreconfigitem(
1954 b'server',
1985 b'server',
1955 b'bundle2.stream',
1986 b'bundle2.stream',
1956 default=True,
1987 default=True,
1957 alias=[(b'experimental', b'bundle2.stream')],
1988 alias=[(b'experimental', b'bundle2.stream')],
1958 )
1989 )
1959 coreconfigitem(
1990 coreconfigitem(
1960 b'server',
1991 b'server',
1961 b'compressionengines',
1992 b'compressionengines',
1962 default=list,
1993 default=list,
1963 )
1994 )
1964 coreconfigitem(
1995 coreconfigitem(
1965 b'server',
1996 b'server',
1966 b'concurrent-push-mode',
1997 b'concurrent-push-mode',
1967 default=b'check-related',
1998 default=b'check-related',
1968 )
1999 )
1969 coreconfigitem(
2000 coreconfigitem(
1970 b'server',
2001 b'server',
1971 b'disablefullbundle',
2002 b'disablefullbundle',
1972 default=False,
2003 default=False,
1973 )
2004 )
1974 coreconfigitem(
2005 coreconfigitem(
1975 b'server',
2006 b'server',
1976 b'maxhttpheaderlen',
2007 b'maxhttpheaderlen',
1977 default=1024,
2008 default=1024,
1978 )
2009 )
1979 coreconfigitem(
2010 coreconfigitem(
1980 b'server',
2011 b'server',
1981 b'pullbundle',
2012 b'pullbundle',
1982 default=False,
2013 default=False,
1983 )
2014 )
1984 coreconfigitem(
2015 coreconfigitem(
1985 b'server',
2016 b'server',
1986 b'preferuncompressed',
2017 b'preferuncompressed',
1987 default=False,
2018 default=False,
1988 )
2019 )
1989 coreconfigitem(
2020 coreconfigitem(
1990 b'server',
2021 b'server',
1991 b'streamunbundle',
2022 b'streamunbundle',
1992 default=False,
2023 default=False,
1993 )
2024 )
1994 coreconfigitem(
2025 coreconfigitem(
1995 b'server',
2026 b'server',
1996 b'uncompressed',
2027 b'uncompressed',
1997 default=True,
2028 default=True,
1998 )
2029 )
1999 coreconfigitem(
2030 coreconfigitem(
2000 b'server',
2031 b'server',
2001 b'uncompressedallowsecret',
2032 b'uncompressedallowsecret',
2002 default=False,
2033 default=False,
2003 )
2034 )
2004 coreconfigitem(
2035 coreconfigitem(
2005 b'server',
2036 b'server',
2006 b'view',
2037 b'view',
2007 default=b'served',
2038 default=b'served',
2008 )
2039 )
2009 coreconfigitem(
2040 coreconfigitem(
2010 b'server',
2041 b'server',
2011 b'validate',
2042 b'validate',
2012 default=False,
2043 default=False,
2013 )
2044 )
2014 coreconfigitem(
2045 coreconfigitem(
2015 b'server',
2046 b'server',
2016 b'zliblevel',
2047 b'zliblevel',
2017 default=-1,
2048 default=-1,
2018 )
2049 )
2019 coreconfigitem(
2050 coreconfigitem(
2020 b'server',
2051 b'server',
2021 b'zstdlevel',
2052 b'zstdlevel',
2022 default=3,
2053 default=3,
2023 )
2054 )
2024 coreconfigitem(
2055 coreconfigitem(
2025 b'share',
2056 b'share',
2026 b'pool',
2057 b'pool',
2027 default=None,
2058 default=None,
2028 )
2059 )
2029 coreconfigitem(
2060 coreconfigitem(
2030 b'share',
2061 b'share',
2031 b'poolnaming',
2062 b'poolnaming',
2032 default=b'identity',
2063 default=b'identity',
2033 )
2064 )
2034 coreconfigitem(
2065 coreconfigitem(
2035 b'share',
2066 b'share',
2036 b'safe-mismatch.source-not-safe',
2067 b'safe-mismatch.source-not-safe',
2037 default=b'abort',
2068 default=b'abort',
2038 )
2069 )
2039 coreconfigitem(
2070 coreconfigitem(
2040 b'share',
2071 b'share',
2041 b'safe-mismatch.source-safe',
2072 b'safe-mismatch.source-safe',
2042 default=b'abort',
2073 default=b'abort',
2043 )
2074 )
2044 coreconfigitem(
2075 coreconfigitem(
2045 b'share',
2076 b'share',
2046 b'safe-mismatch.source-not-safe.warn',
2077 b'safe-mismatch.source-not-safe.warn',
2047 default=True,
2078 default=True,
2048 )
2079 )
2049 coreconfigitem(
2080 coreconfigitem(
2050 b'share',
2081 b'share',
2051 b'safe-mismatch.source-safe.warn',
2082 b'safe-mismatch.source-safe.warn',
2052 default=True,
2083 default=True,
2053 )
2084 )
2054 coreconfigitem(
2085 coreconfigitem(
2055 b'shelve',
2086 b'shelve',
2056 b'maxbackups',
2087 b'maxbackups',
2057 default=10,
2088 default=10,
2058 )
2089 )
2059 coreconfigitem(
2090 coreconfigitem(
2060 b'smtp',
2091 b'smtp',
2061 b'host',
2092 b'host',
2062 default=None,
2093 default=None,
2063 )
2094 )
2064 coreconfigitem(
2095 coreconfigitem(
2065 b'smtp',
2096 b'smtp',
2066 b'local_hostname',
2097 b'local_hostname',
2067 default=None,
2098 default=None,
2068 )
2099 )
2069 coreconfigitem(
2100 coreconfigitem(
2070 b'smtp',
2101 b'smtp',
2071 b'password',
2102 b'password',
2072 default=None,
2103 default=None,
2073 )
2104 )
2074 coreconfigitem(
2105 coreconfigitem(
2075 b'smtp',
2106 b'smtp',
2076 b'port',
2107 b'port',
2077 default=dynamicdefault,
2108 default=dynamicdefault,
2078 )
2109 )
2079 coreconfigitem(
2110 coreconfigitem(
2080 b'smtp',
2111 b'smtp',
2081 b'tls',
2112 b'tls',
2082 default=b'none',
2113 default=b'none',
2083 )
2114 )
2084 coreconfigitem(
2115 coreconfigitem(
2085 b'smtp',
2116 b'smtp',
2086 b'username',
2117 b'username',
2087 default=None,
2118 default=None,
2088 )
2119 )
2089 coreconfigitem(
2120 coreconfigitem(
2090 b'sparse',
2121 b'sparse',
2091 b'missingwarning',
2122 b'missingwarning',
2092 default=True,
2123 default=True,
2093 experimental=True,
2124 experimental=True,
2094 )
2125 )
2095 coreconfigitem(
2126 coreconfigitem(
2096 b'subrepos',
2127 b'subrepos',
2097 b'allowed',
2128 b'allowed',
2098 default=dynamicdefault, # to make backporting simpler
2129 default=dynamicdefault, # to make backporting simpler
2099 )
2130 )
2100 coreconfigitem(
2131 coreconfigitem(
2101 b'subrepos',
2132 b'subrepos',
2102 b'hg:allowed',
2133 b'hg:allowed',
2103 default=dynamicdefault,
2134 default=dynamicdefault,
2104 )
2135 )
2105 coreconfigitem(
2136 coreconfigitem(
2106 b'subrepos',
2137 b'subrepos',
2107 b'git:allowed',
2138 b'git:allowed',
2108 default=dynamicdefault,
2139 default=dynamicdefault,
2109 )
2140 )
2110 coreconfigitem(
2141 coreconfigitem(
2111 b'subrepos',
2142 b'subrepos',
2112 b'svn:allowed',
2143 b'svn:allowed',
2113 default=dynamicdefault,
2144 default=dynamicdefault,
2114 )
2145 )
2115 coreconfigitem(
2146 coreconfigitem(
2116 b'templates',
2147 b'templates',
2117 b'.*',
2148 b'.*',
2118 default=None,
2149 default=None,
2119 generic=True,
2150 generic=True,
2120 )
2151 )
2121 coreconfigitem(
2152 coreconfigitem(
2122 b'templateconfig',
2153 b'templateconfig',
2123 b'.*',
2154 b'.*',
2124 default=dynamicdefault,
2155 default=dynamicdefault,
2125 generic=True,
2156 generic=True,
2126 )
2157 )
2127 coreconfigitem(
2158 coreconfigitem(
2128 b'trusted',
2159 b'trusted',
2129 b'groups',
2160 b'groups',
2130 default=list,
2161 default=list,
2131 )
2162 )
2132 coreconfigitem(
2163 coreconfigitem(
2133 b'trusted',
2164 b'trusted',
2134 b'users',
2165 b'users',
2135 default=list,
2166 default=list,
2136 )
2167 )
2137 coreconfigitem(
2168 coreconfigitem(
2138 b'ui',
2169 b'ui',
2139 b'_usedassubrepo',
2170 b'_usedassubrepo',
2140 default=False,
2171 default=False,
2141 )
2172 )
2142 coreconfigitem(
2173 coreconfigitem(
2143 b'ui',
2174 b'ui',
2144 b'allowemptycommit',
2175 b'allowemptycommit',
2145 default=False,
2176 default=False,
2146 )
2177 )
2147 coreconfigitem(
2178 coreconfigitem(
2148 b'ui',
2179 b'ui',
2149 b'archivemeta',
2180 b'archivemeta',
2150 default=True,
2181 default=True,
2151 )
2182 )
2152 coreconfigitem(
2183 coreconfigitem(
2153 b'ui',
2184 b'ui',
2154 b'askusername',
2185 b'askusername',
2155 default=False,
2186 default=False,
2156 )
2187 )
2157 coreconfigitem(
2188 coreconfigitem(
2158 b'ui',
2189 b'ui',
2159 b'available-memory',
2190 b'available-memory',
2160 default=None,
2191 default=None,
2161 )
2192 )
2162
2193
2163 coreconfigitem(
2194 coreconfigitem(
2164 b'ui',
2195 b'ui',
2165 b'clonebundlefallback',
2196 b'clonebundlefallback',
2166 default=False,
2197 default=False,
2167 )
2198 )
2168 coreconfigitem(
2199 coreconfigitem(
2169 b'ui',
2200 b'ui',
2170 b'clonebundleprefers',
2201 b'clonebundleprefers',
2171 default=list,
2202 default=list,
2172 )
2203 )
2173 coreconfigitem(
2204 coreconfigitem(
2174 b'ui',
2205 b'ui',
2175 b'clonebundles',
2206 b'clonebundles',
2176 default=True,
2207 default=True,
2177 )
2208 )
2178 coreconfigitem(
2209 coreconfigitem(
2179 b'ui',
2210 b'ui',
2180 b'color',
2211 b'color',
2181 default=b'auto',
2212 default=b'auto',
2182 )
2213 )
2183 coreconfigitem(
2214 coreconfigitem(
2184 b'ui',
2215 b'ui',
2185 b'commitsubrepos',
2216 b'commitsubrepos',
2186 default=False,
2217 default=False,
2187 )
2218 )
2188 coreconfigitem(
2219 coreconfigitem(
2189 b'ui',
2220 b'ui',
2190 b'debug',
2221 b'debug',
2191 default=False,
2222 default=False,
2192 )
2223 )
2193 coreconfigitem(
2224 coreconfigitem(
2194 b'ui',
2225 b'ui',
2195 b'debugger',
2226 b'debugger',
2196 default=None,
2227 default=None,
2197 )
2228 )
2198 coreconfigitem(
2229 coreconfigitem(
2199 b'ui',
2230 b'ui',
2200 b'editor',
2231 b'editor',
2201 default=dynamicdefault,
2232 default=dynamicdefault,
2202 )
2233 )
2203 coreconfigitem(
2234 coreconfigitem(
2204 b'ui',
2235 b'ui',
2205 b'detailed-exit-code',
2236 b'detailed-exit-code',
2206 default=False,
2237 default=False,
2207 experimental=True,
2238 experimental=True,
2208 )
2239 )
2209 coreconfigitem(
2240 coreconfigitem(
2210 b'ui',
2241 b'ui',
2211 b'fallbackencoding',
2242 b'fallbackencoding',
2212 default=None,
2243 default=None,
2213 )
2244 )
2214 coreconfigitem(
2245 coreconfigitem(
2215 b'ui',
2246 b'ui',
2216 b'forcecwd',
2247 b'forcecwd',
2217 default=None,
2248 default=None,
2218 )
2249 )
2219 coreconfigitem(
2250 coreconfigitem(
2220 b'ui',
2251 b'ui',
2221 b'forcemerge',
2252 b'forcemerge',
2222 default=None,
2253 default=None,
2223 )
2254 )
2224 coreconfigitem(
2255 coreconfigitem(
2225 b'ui',
2256 b'ui',
2226 b'formatdebug',
2257 b'formatdebug',
2227 default=False,
2258 default=False,
2228 )
2259 )
2229 coreconfigitem(
2260 coreconfigitem(
2230 b'ui',
2261 b'ui',
2231 b'formatjson',
2262 b'formatjson',
2232 default=False,
2263 default=False,
2233 )
2264 )
2234 coreconfigitem(
2265 coreconfigitem(
2235 b'ui',
2266 b'ui',
2236 b'formatted',
2267 b'formatted',
2237 default=None,
2268 default=None,
2238 )
2269 )
2239 coreconfigitem(
2270 coreconfigitem(
2240 b'ui',
2271 b'ui',
2241 b'interactive',
2272 b'interactive',
2242 default=None,
2273 default=None,
2243 )
2274 )
2244 coreconfigitem(
2275 coreconfigitem(
2245 b'ui',
2276 b'ui',
2246 b'interface',
2277 b'interface',
2247 default=None,
2278 default=None,
2248 )
2279 )
2249 coreconfigitem(
2280 coreconfigitem(
2250 b'ui',
2281 b'ui',
2251 b'interface.chunkselector',
2282 b'interface.chunkselector',
2252 default=None,
2283 default=None,
2253 )
2284 )
2254 coreconfigitem(
2285 coreconfigitem(
2255 b'ui',
2286 b'ui',
2256 b'large-file-limit',
2287 b'large-file-limit',
2257 default=10000000,
2288 default=10000000,
2258 )
2289 )
2259 coreconfigitem(
2290 coreconfigitem(
2260 b'ui',
2291 b'ui',
2261 b'logblockedtimes',
2292 b'logblockedtimes',
2262 default=False,
2293 default=False,
2263 )
2294 )
2264 coreconfigitem(
2295 coreconfigitem(
2265 b'ui',
2296 b'ui',
2266 b'merge',
2297 b'merge',
2267 default=None,
2298 default=None,
2268 )
2299 )
2269 coreconfigitem(
2300 coreconfigitem(
2270 b'ui',
2301 b'ui',
2271 b'mergemarkers',
2302 b'mergemarkers',
2272 default=b'basic',
2303 default=b'basic',
2273 )
2304 )
2274 coreconfigitem(
2305 coreconfigitem(
2275 b'ui',
2306 b'ui',
2276 b'message-output',
2307 b'message-output',
2277 default=b'stdio',
2308 default=b'stdio',
2278 )
2309 )
2279 coreconfigitem(
2310 coreconfigitem(
2280 b'ui',
2311 b'ui',
2281 b'nontty',
2312 b'nontty',
2282 default=False,
2313 default=False,
2283 )
2314 )
2284 coreconfigitem(
2315 coreconfigitem(
2285 b'ui',
2316 b'ui',
2286 b'origbackuppath',
2317 b'origbackuppath',
2287 default=None,
2318 default=None,
2288 )
2319 )
2289 coreconfigitem(
2320 coreconfigitem(
2290 b'ui',
2321 b'ui',
2291 b'paginate',
2322 b'paginate',
2292 default=True,
2323 default=True,
2293 )
2324 )
2294 coreconfigitem(
2325 coreconfigitem(
2295 b'ui',
2326 b'ui',
2296 b'patch',
2327 b'patch',
2297 default=None,
2328 default=None,
2298 )
2329 )
2299 coreconfigitem(
2330 coreconfigitem(
2300 b'ui',
2331 b'ui',
2301 b'portablefilenames',
2332 b'portablefilenames',
2302 default=b'warn',
2333 default=b'warn',
2303 )
2334 )
2304 coreconfigitem(
2335 coreconfigitem(
2305 b'ui',
2336 b'ui',
2306 b'promptecho',
2337 b'promptecho',
2307 default=False,
2338 default=False,
2308 )
2339 )
2309 coreconfigitem(
2340 coreconfigitem(
2310 b'ui',
2341 b'ui',
2311 b'quiet',
2342 b'quiet',
2312 default=False,
2343 default=False,
2313 )
2344 )
2314 coreconfigitem(
2345 coreconfigitem(
2315 b'ui',
2346 b'ui',
2316 b'quietbookmarkmove',
2347 b'quietbookmarkmove',
2317 default=False,
2348 default=False,
2318 )
2349 )
2319 coreconfigitem(
2350 coreconfigitem(
2320 b'ui',
2351 b'ui',
2321 b'relative-paths',
2352 b'relative-paths',
2322 default=b'legacy',
2353 default=b'legacy',
2323 )
2354 )
2324 coreconfigitem(
2355 coreconfigitem(
2325 b'ui',
2356 b'ui',
2326 b'remotecmd',
2357 b'remotecmd',
2327 default=b'hg',
2358 default=b'hg',
2328 )
2359 )
2329 coreconfigitem(
2360 coreconfigitem(
2330 b'ui',
2361 b'ui',
2331 b'report_untrusted',
2362 b'report_untrusted',
2332 default=True,
2363 default=True,
2333 )
2364 )
2334 coreconfigitem(
2365 coreconfigitem(
2335 b'ui',
2366 b'ui',
2336 b'rollback',
2367 b'rollback',
2337 default=True,
2368 default=True,
2338 )
2369 )
2339 coreconfigitem(
2370 coreconfigitem(
2340 b'ui',
2371 b'ui',
2341 b'signal-safe-lock',
2372 b'signal-safe-lock',
2342 default=True,
2373 default=True,
2343 )
2374 )
2344 coreconfigitem(
2375 coreconfigitem(
2345 b'ui',
2376 b'ui',
2346 b'slash',
2377 b'slash',
2347 default=False,
2378 default=False,
2348 )
2379 )
2349 coreconfigitem(
2380 coreconfigitem(
2350 b'ui',
2381 b'ui',
2351 b'ssh',
2382 b'ssh',
2352 default=b'ssh',
2383 default=b'ssh',
2353 )
2384 )
2354 coreconfigitem(
2385 coreconfigitem(
2355 b'ui',
2386 b'ui',
2356 b'ssherrorhint',
2387 b'ssherrorhint',
2357 default=None,
2388 default=None,
2358 )
2389 )
2359 coreconfigitem(
2390 coreconfigitem(
2360 b'ui',
2391 b'ui',
2361 b'statuscopies',
2392 b'statuscopies',
2362 default=False,
2393 default=False,
2363 )
2394 )
2364 coreconfigitem(
2395 coreconfigitem(
2365 b'ui',
2396 b'ui',
2366 b'strict',
2397 b'strict',
2367 default=False,
2398 default=False,
2368 )
2399 )
2369 coreconfigitem(
2400 coreconfigitem(
2370 b'ui',
2401 b'ui',
2371 b'style',
2402 b'style',
2372 default=b'',
2403 default=b'',
2373 )
2404 )
2374 coreconfigitem(
2405 coreconfigitem(
2375 b'ui',
2406 b'ui',
2376 b'supportcontact',
2407 b'supportcontact',
2377 default=None,
2408 default=None,
2378 )
2409 )
2379 coreconfigitem(
2410 coreconfigitem(
2380 b'ui',
2411 b'ui',
2381 b'textwidth',
2412 b'textwidth',
2382 default=78,
2413 default=78,
2383 )
2414 )
2384 coreconfigitem(
2415 coreconfigitem(
2385 b'ui',
2416 b'ui',
2386 b'timeout',
2417 b'timeout',
2387 default=b'600',
2418 default=b'600',
2388 )
2419 )
2389 coreconfigitem(
2420 coreconfigitem(
2390 b'ui',
2421 b'ui',
2391 b'timeout.warn',
2422 b'timeout.warn',
2392 default=0,
2423 default=0,
2393 )
2424 )
2394 coreconfigitem(
2425 coreconfigitem(
2395 b'ui',
2426 b'ui',
2396 b'timestamp-output',
2427 b'timestamp-output',
2397 default=False,
2428 default=False,
2398 )
2429 )
2399 coreconfigitem(
2430 coreconfigitem(
2400 b'ui',
2431 b'ui',
2401 b'traceback',
2432 b'traceback',
2402 default=False,
2433 default=False,
2403 )
2434 )
2404 coreconfigitem(
2435 coreconfigitem(
2405 b'ui',
2436 b'ui',
2406 b'tweakdefaults',
2437 b'tweakdefaults',
2407 default=False,
2438 default=False,
2408 )
2439 )
2409 coreconfigitem(b'ui', b'username', alias=[(b'ui', b'user')])
2440 coreconfigitem(b'ui', b'username', alias=[(b'ui', b'user')])
2410 coreconfigitem(
2441 coreconfigitem(
2411 b'ui',
2442 b'ui',
2412 b'verbose',
2443 b'verbose',
2413 default=False,
2444 default=False,
2414 )
2445 )
2415 coreconfigitem(
2446 coreconfigitem(
2416 b'verify',
2447 b'verify',
2417 b'skipflags',
2448 b'skipflags',
2418 default=None,
2449 default=None,
2419 )
2450 )
2420 coreconfigitem(
2451 coreconfigitem(
2421 b'web',
2452 b'web',
2422 b'allowbz2',
2453 b'allowbz2',
2423 default=False,
2454 default=False,
2424 )
2455 )
2425 coreconfigitem(
2456 coreconfigitem(
2426 b'web',
2457 b'web',
2427 b'allowgz',
2458 b'allowgz',
2428 default=False,
2459 default=False,
2429 )
2460 )
2430 coreconfigitem(
2461 coreconfigitem(
2431 b'web',
2462 b'web',
2432 b'allow-pull',
2463 b'allow-pull',
2433 alias=[(b'web', b'allowpull')],
2464 alias=[(b'web', b'allowpull')],
2434 default=True,
2465 default=True,
2435 )
2466 )
2436 coreconfigitem(
2467 coreconfigitem(
2437 b'web',
2468 b'web',
2438 b'allow-push',
2469 b'allow-push',
2439 alias=[(b'web', b'allow_push')],
2470 alias=[(b'web', b'allow_push')],
2440 default=list,
2471 default=list,
2441 )
2472 )
2442 coreconfigitem(
2473 coreconfigitem(
2443 b'web',
2474 b'web',
2444 b'allowzip',
2475 b'allowzip',
2445 default=False,
2476 default=False,
2446 )
2477 )
2447 coreconfigitem(
2478 coreconfigitem(
2448 b'web',
2479 b'web',
2449 b'archivesubrepos',
2480 b'archivesubrepos',
2450 default=False,
2481 default=False,
2451 )
2482 )
2452 coreconfigitem(
2483 coreconfigitem(
2453 b'web',
2484 b'web',
2454 b'cache',
2485 b'cache',
2455 default=True,
2486 default=True,
2456 )
2487 )
2457 coreconfigitem(
2488 coreconfigitem(
2458 b'web',
2489 b'web',
2459 b'comparisoncontext',
2490 b'comparisoncontext',
2460 default=5,
2491 default=5,
2461 )
2492 )
2462 coreconfigitem(
2493 coreconfigitem(
2463 b'web',
2494 b'web',
2464 b'contact',
2495 b'contact',
2465 default=None,
2496 default=None,
2466 )
2497 )
2467 coreconfigitem(
2498 coreconfigitem(
2468 b'web',
2499 b'web',
2469 b'deny_push',
2500 b'deny_push',
2470 default=list,
2501 default=list,
2471 )
2502 )
2472 coreconfigitem(
2503 coreconfigitem(
2473 b'web',
2504 b'web',
2474 b'guessmime',
2505 b'guessmime',
2475 default=False,
2506 default=False,
2476 )
2507 )
2477 coreconfigitem(
2508 coreconfigitem(
2478 b'web',
2509 b'web',
2479 b'hidden',
2510 b'hidden',
2480 default=False,
2511 default=False,
2481 )
2512 )
2482 coreconfigitem(
2513 coreconfigitem(
2483 b'web',
2514 b'web',
2484 b'labels',
2515 b'labels',
2485 default=list,
2516 default=list,
2486 )
2517 )
2487 coreconfigitem(
2518 coreconfigitem(
2488 b'web',
2519 b'web',
2489 b'logoimg',
2520 b'logoimg',
2490 default=b'hglogo.png',
2521 default=b'hglogo.png',
2491 )
2522 )
2492 coreconfigitem(
2523 coreconfigitem(
2493 b'web',
2524 b'web',
2494 b'logourl',
2525 b'logourl',
2495 default=b'https://mercurial-scm.org/',
2526 default=b'https://mercurial-scm.org/',
2496 )
2527 )
2497 coreconfigitem(
2528 coreconfigitem(
2498 b'web',
2529 b'web',
2499 b'accesslog',
2530 b'accesslog',
2500 default=b'-',
2531 default=b'-',
2501 )
2532 )
2502 coreconfigitem(
2533 coreconfigitem(
2503 b'web',
2534 b'web',
2504 b'address',
2535 b'address',
2505 default=b'',
2536 default=b'',
2506 )
2537 )
2507 coreconfigitem(
2538 coreconfigitem(
2508 b'web',
2539 b'web',
2509 b'allow-archive',
2540 b'allow-archive',
2510 alias=[(b'web', b'allow_archive')],
2541 alias=[(b'web', b'allow_archive')],
2511 default=list,
2542 default=list,
2512 )
2543 )
2513 coreconfigitem(
2544 coreconfigitem(
2514 b'web',
2545 b'web',
2515 b'allow_read',
2546 b'allow_read',
2516 default=list,
2547 default=list,
2517 )
2548 )
2518 coreconfigitem(
2549 coreconfigitem(
2519 b'web',
2550 b'web',
2520 b'baseurl',
2551 b'baseurl',
2521 default=None,
2552 default=None,
2522 )
2553 )
2523 coreconfigitem(
2554 coreconfigitem(
2524 b'web',
2555 b'web',
2525 b'cacerts',
2556 b'cacerts',
2526 default=None,
2557 default=None,
2527 )
2558 )
2528 coreconfigitem(
2559 coreconfigitem(
2529 b'web',
2560 b'web',
2530 b'certificate',
2561 b'certificate',
2531 default=None,
2562 default=None,
2532 )
2563 )
2533 coreconfigitem(
2564 coreconfigitem(
2534 b'web',
2565 b'web',
2535 b'collapse',
2566 b'collapse',
2536 default=False,
2567 default=False,
2537 )
2568 )
2538 coreconfigitem(
2569 coreconfigitem(
2539 b'web',
2570 b'web',
2540 b'csp',
2571 b'csp',
2541 default=None,
2572 default=None,
2542 )
2573 )
2543 coreconfigitem(
2574 coreconfigitem(
2544 b'web',
2575 b'web',
2545 b'deny_read',
2576 b'deny_read',
2546 default=list,
2577 default=list,
2547 )
2578 )
2548 coreconfigitem(
2579 coreconfigitem(
2549 b'web',
2580 b'web',
2550 b'descend',
2581 b'descend',
2551 default=True,
2582 default=True,
2552 )
2583 )
2553 coreconfigitem(
2584 coreconfigitem(
2554 b'web',
2585 b'web',
2555 b'description',
2586 b'description',
2556 default=b"",
2587 default=b"",
2557 )
2588 )
2558 coreconfigitem(
2589 coreconfigitem(
2559 b'web',
2590 b'web',
2560 b'encoding',
2591 b'encoding',
2561 default=lambda: encoding.encoding,
2592 default=lambda: encoding.encoding,
2562 )
2593 )
2563 coreconfigitem(
2594 coreconfigitem(
2564 b'web',
2595 b'web',
2565 b'errorlog',
2596 b'errorlog',
2566 default=b'-',
2597 default=b'-',
2567 )
2598 )
2568 coreconfigitem(
2599 coreconfigitem(
2569 b'web',
2600 b'web',
2570 b'ipv6',
2601 b'ipv6',
2571 default=False,
2602 default=False,
2572 )
2603 )
2573 coreconfigitem(
2604 coreconfigitem(
2574 b'web',
2605 b'web',
2575 b'maxchanges',
2606 b'maxchanges',
2576 default=10,
2607 default=10,
2577 )
2608 )
2578 coreconfigitem(
2609 coreconfigitem(
2579 b'web',
2610 b'web',
2580 b'maxfiles',
2611 b'maxfiles',
2581 default=10,
2612 default=10,
2582 )
2613 )
2583 coreconfigitem(
2614 coreconfigitem(
2584 b'web',
2615 b'web',
2585 b'maxshortchanges',
2616 b'maxshortchanges',
2586 default=60,
2617 default=60,
2587 )
2618 )
2588 coreconfigitem(
2619 coreconfigitem(
2589 b'web',
2620 b'web',
2590 b'motd',
2621 b'motd',
2591 default=b'',
2622 default=b'',
2592 )
2623 )
2593 coreconfigitem(
2624 coreconfigitem(
2594 b'web',
2625 b'web',
2595 b'name',
2626 b'name',
2596 default=dynamicdefault,
2627 default=dynamicdefault,
2597 )
2628 )
2598 coreconfigitem(
2629 coreconfigitem(
2599 b'web',
2630 b'web',
2600 b'port',
2631 b'port',
2601 default=8000,
2632 default=8000,
2602 )
2633 )
2603 coreconfigitem(
2634 coreconfigitem(
2604 b'web',
2635 b'web',
2605 b'prefix',
2636 b'prefix',
2606 default=b'',
2637 default=b'',
2607 )
2638 )
2608 coreconfigitem(
2639 coreconfigitem(
2609 b'web',
2640 b'web',
2610 b'push_ssl',
2641 b'push_ssl',
2611 default=True,
2642 default=True,
2612 )
2643 )
2613 coreconfigitem(
2644 coreconfigitem(
2614 b'web',
2645 b'web',
2615 b'refreshinterval',
2646 b'refreshinterval',
2616 default=20,
2647 default=20,
2617 )
2648 )
2618 coreconfigitem(
2649 coreconfigitem(
2619 b'web',
2650 b'web',
2620 b'server-header',
2651 b'server-header',
2621 default=None,
2652 default=None,
2622 )
2653 )
2623 coreconfigitem(
2654 coreconfigitem(
2624 b'web',
2655 b'web',
2625 b'static',
2656 b'static',
2626 default=None,
2657 default=None,
2627 )
2658 )
2628 coreconfigitem(
2659 coreconfigitem(
2629 b'web',
2660 b'web',
2630 b'staticurl',
2661 b'staticurl',
2631 default=None,
2662 default=None,
2632 )
2663 )
2633 coreconfigitem(
2664 coreconfigitem(
2634 b'web',
2665 b'web',
2635 b'stripes',
2666 b'stripes',
2636 default=1,
2667 default=1,
2637 )
2668 )
2638 coreconfigitem(
2669 coreconfigitem(
2639 b'web',
2670 b'web',
2640 b'style',
2671 b'style',
2641 default=b'paper',
2672 default=b'paper',
2642 )
2673 )
2643 coreconfigitem(
2674 coreconfigitem(
2644 b'web',
2675 b'web',
2645 b'templates',
2676 b'templates',
2646 default=None,
2677 default=None,
2647 )
2678 )
2648 coreconfigitem(
2679 coreconfigitem(
2649 b'web',
2680 b'web',
2650 b'view',
2681 b'view',
2651 default=b'served',
2682 default=b'served',
2652 experimental=True,
2683 experimental=True,
2653 )
2684 )
2654 coreconfigitem(
2685 coreconfigitem(
2655 b'worker',
2686 b'worker',
2656 b'backgroundclose',
2687 b'backgroundclose',
2657 default=dynamicdefault,
2688 default=dynamicdefault,
2658 )
2689 )
2659 # Windows defaults to a limit of 512 open files. A buffer of 128
2690 # Windows defaults to a limit of 512 open files. A buffer of 128
2660 # should give us enough headway.
2691 # should give us enough headway.
2661 coreconfigitem(
2692 coreconfigitem(
2662 b'worker',
2693 b'worker',
2663 b'backgroundclosemaxqueue',
2694 b'backgroundclosemaxqueue',
2664 default=384,
2695 default=384,
2665 )
2696 )
2666 coreconfigitem(
2697 coreconfigitem(
2667 b'worker',
2698 b'worker',
2668 b'backgroundcloseminfilecount',
2699 b'backgroundcloseminfilecount',
2669 default=2048,
2700 default=2048,
2670 )
2701 )
2671 coreconfigitem(
2702 coreconfigitem(
2672 b'worker',
2703 b'worker',
2673 b'backgroundclosethreadcount',
2704 b'backgroundclosethreadcount',
2674 default=4,
2705 default=4,
2675 )
2706 )
2676 coreconfigitem(
2707 coreconfigitem(
2677 b'worker',
2708 b'worker',
2678 b'enabled',
2709 b'enabled',
2679 default=True,
2710 default=True,
2680 )
2711 )
2681 coreconfigitem(
2712 coreconfigitem(
2682 b'worker',
2713 b'worker',
2683 b'numcpus',
2714 b'numcpus',
2684 default=None,
2715 default=None,
2685 )
2716 )
2686
2717
2687 # Rebase related configuration moved to core because other extension are doing
2718 # Rebase related configuration moved to core because other extension are doing
2688 # strange things. For example, shelve import the extensions to reuse some bit
2719 # strange things. For example, shelve import the extensions to reuse some bit
2689 # without formally loading it.
2720 # without formally loading it.
2690 coreconfigitem(
2721 coreconfigitem(
2691 b'commands',
2722 b'commands',
2692 b'rebase.requiredest',
2723 b'rebase.requiredest',
2693 default=False,
2724 default=False,
2694 )
2725 )
2695 coreconfigitem(
2726 coreconfigitem(
2696 b'experimental',
2727 b'experimental',
2697 b'rebaseskipobsolete',
2728 b'rebaseskipobsolete',
2698 default=True,
2729 default=True,
2699 )
2730 )
2700 coreconfigitem(
2731 coreconfigitem(
2701 b'rebase',
2732 b'rebase',
2702 b'singletransaction',
2733 b'singletransaction',
2703 default=False,
2734 default=False,
2704 )
2735 )
2705 coreconfigitem(
2736 coreconfigitem(
2706 b'rebase',
2737 b'rebase',
2707 b'experimental.inmemory',
2738 b'experimental.inmemory',
2708 default=False,
2739 default=False,
2709 )
2740 )
@@ -1,1231 +1,1288 b''
1 # filemerge.py - file-level merge handling for Mercurial
1 # filemerge.py - file-level merge handling for Mercurial
2 #
2 #
3 # Copyright 2006, 2007, 2008 Olivia Mackall <olivia@selenic.com>
3 # Copyright 2006, 2007, 2008 Olivia Mackall <olivia@selenic.com>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8
8
9 import contextlib
9 import contextlib
10 import os
10 import os
11 import re
11 import re
12 import shutil
12 import shutil
13
13
14 from .i18n import _
14 from .i18n import _
15 from .node import (
15 from .node import (
16 hex,
16 hex,
17 short,
17 short,
18 )
18 )
19 from .pycompat import (
19 from .pycompat import (
20 getattr,
20 getattr,
21 )
21 )
22
22
23 from . import (
23 from . import (
24 encoding,
24 encoding,
25 error,
25 error,
26 formatter,
26 formatter,
27 match,
27 match,
28 pycompat,
28 pycompat,
29 registrar,
29 registrar,
30 scmutil,
30 scmutil,
31 simplemerge,
31 simplemerge,
32 tagmerge,
32 tagmerge,
33 templatekw,
33 templatekw,
34 templater,
34 templater,
35 templateutil,
35 templateutil,
36 util,
36 util,
37 )
37 )
38
38
39 from .utils import (
39 from .utils import (
40 procutil,
40 procutil,
41 stringutil,
41 stringutil,
42 )
42 )
43
43
44
44
45 def _toolstr(ui, tool, part, *args):
45 def _toolstr(ui, tool, part, *args):
46 return ui.config(b"merge-tools", tool + b"." + part, *args)
46 return ui.config(b"merge-tools", tool + b"." + part, *args)
47
47
48
48
49 def _toolbool(ui, tool, part, *args):
49 def _toolbool(ui, tool, part, *args):
50 return ui.configbool(b"merge-tools", tool + b"." + part, *args)
50 return ui.configbool(b"merge-tools", tool + b"." + part, *args)
51
51
52
52
53 def _toollist(ui, tool, part):
53 def _toollist(ui, tool, part):
54 return ui.configlist(b"merge-tools", tool + b"." + part)
54 return ui.configlist(b"merge-tools", tool + b"." + part)
55
55
56
56
57 internals = {}
57 internals = {}
58 # Merge tools to document.
58 # Merge tools to document.
59 internalsdoc = {}
59 internalsdoc = {}
60
60
61 internaltool = registrar.internalmerge()
61 internaltool = registrar.internalmerge()
62
62
63 # internal tool merge types
63 # internal tool merge types
64 nomerge = internaltool.nomerge
64 nomerge = internaltool.nomerge
65 mergeonly = internaltool.mergeonly # just the full merge, no premerge
65 mergeonly = internaltool.mergeonly # just the full merge, no premerge
66 fullmerge = internaltool.fullmerge # both premerge and merge
66 fullmerge = internaltool.fullmerge # both premerge and merge
67
67
68 # IMPORTANT: keep the last line of this prompt very short ("What do you want to
68 # IMPORTANT: keep the last line of this prompt very short ("What do you want to
69 # do?") because of issue6158, ideally to <40 English characters (to allow other
69 # do?") because of issue6158, ideally to <40 English characters (to allow other
70 # languages that may take more columns to still have a chance to fit in an
70 # languages that may take more columns to still have a chance to fit in an
71 # 80-column screen).
71 # 80-column screen).
72 _localchangedotherdeletedmsg = _(
72 _localchangedotherdeletedmsg = _(
73 b"file '%(fd)s' was deleted in other%(o)s but was modified in local%(l)s.\n"
73 b"file '%(fd)s' was deleted in other%(o)s but was modified in local%(l)s.\n"
74 b"You can use (c)hanged version, (d)elete, or leave (u)nresolved.\n"
74 b"You can use (c)hanged version, (d)elete, or leave (u)nresolved.\n"
75 b"What do you want to do?"
75 b"What do you want to do?"
76 b"$$ &Changed $$ &Delete $$ &Unresolved"
76 b"$$ &Changed $$ &Delete $$ &Unresolved"
77 )
77 )
78
78
79 _otherchangedlocaldeletedmsg = _(
79 _otherchangedlocaldeletedmsg = _(
80 b"file '%(fd)s' was deleted in local%(l)s but was modified in other%(o)s.\n"
80 b"file '%(fd)s' was deleted in local%(l)s but was modified in other%(o)s.\n"
81 b"You can use (c)hanged version, leave (d)eleted, or leave (u)nresolved.\n"
81 b"You can use (c)hanged version, leave (d)eleted, or leave (u)nresolved.\n"
82 b"What do you want to do?"
82 b"What do you want to do?"
83 b"$$ &Changed $$ &Deleted $$ &Unresolved"
83 b"$$ &Changed $$ &Deleted $$ &Unresolved"
84 )
84 )
85
85
86
86
87 class absentfilectx:
87 class absentfilectx:
88 """Represents a file that's ostensibly in a context but is actually not
88 """Represents a file that's ostensibly in a context but is actually not
89 present in it.
89 present in it.
90
90
91 This is here because it's very specific to the filemerge code for now --
91 This is here because it's very specific to the filemerge code for now --
92 other code is likely going to break with the values this returns."""
92 other code is likely going to break with the values this returns."""
93
93
94 def __init__(self, ctx, f):
94 def __init__(self, ctx, f):
95 self._ctx = ctx
95 self._ctx = ctx
96 self._f = f
96 self._f = f
97
97
98 def __bytes__(self):
98 def __bytes__(self):
99 return b'absent file %s@%s' % (self._f, self._ctx)
99 return b'absent file %s@%s' % (self._f, self._ctx)
100
100
101 def path(self):
101 def path(self):
102 return self._f
102 return self._f
103
103
104 def size(self):
104 def size(self):
105 return None
105 return None
106
106
107 def data(self):
107 def data(self):
108 return None
108 return None
109
109
110 def filenode(self):
110 def filenode(self):
111 return self._ctx.repo().nullid
111 return self._ctx.repo().nullid
112
112
113 _customcmp = True
113 _customcmp = True
114
114
115 def cmp(self, fctx):
115 def cmp(self, fctx):
116 """compare with other file context
116 """compare with other file context
117
117
118 returns True if different from fctx.
118 returns True if different from fctx.
119 """
119 """
120 return not (
120 return not (
121 fctx.isabsent()
121 fctx.isabsent()
122 and fctx.changectx() == self.changectx()
122 and fctx.changectx() == self.changectx()
123 and fctx.path() == self.path()
123 and fctx.path() == self.path()
124 )
124 )
125
125
126 def flags(self):
126 def flags(self):
127 return b''
127 return b''
128
128
129 def changectx(self):
129 def changectx(self):
130 return self._ctx
130 return self._ctx
131
131
132 def isbinary(self):
132 def isbinary(self):
133 return False
133 return False
134
134
135 def isabsent(self):
135 def isabsent(self):
136 return True
136 return True
137
137
138
138
139 def _findtool(ui, tool):
139 def _findtool(ui, tool):
140 if tool in internals:
140 if tool in internals:
141 return tool
141 return tool
142 cmd = _toolstr(ui, tool, b"executable", tool)
142 cmd = _toolstr(ui, tool, b"executable", tool)
143 if cmd.startswith(b'python:'):
143 if cmd.startswith(b'python:'):
144 return cmd
144 return cmd
145 return findexternaltool(ui, tool)
145 return findexternaltool(ui, tool)
146
146
147
147
148 def _quotetoolpath(cmd):
148 def _quotetoolpath(cmd):
149 if cmd.startswith(b'python:'):
149 if cmd.startswith(b'python:'):
150 return cmd
150 return cmd
151 return procutil.shellquote(cmd)
151 return procutil.shellquote(cmd)
152
152
153
153
154 def findexternaltool(ui, tool):
154 def findexternaltool(ui, tool):
155 for kn in (b"regkey", b"regkeyalt"):
155 for kn in (b"regkey", b"regkeyalt"):
156 k = _toolstr(ui, tool, kn)
156 k = _toolstr(ui, tool, kn)
157 if not k:
157 if not k:
158 continue
158 continue
159 p = util.lookupreg(k, _toolstr(ui, tool, b"regname"))
159 p = util.lookupreg(k, _toolstr(ui, tool, b"regname"))
160 if p:
160 if p:
161 p = procutil.findexe(p + _toolstr(ui, tool, b"regappend", b""))
161 p = procutil.findexe(p + _toolstr(ui, tool, b"regappend", b""))
162 if p:
162 if p:
163 return p
163 return p
164 exe = _toolstr(ui, tool, b"executable", tool)
164 exe = _toolstr(ui, tool, b"executable", tool)
165 return procutil.findexe(util.expandpath(exe))
165 return procutil.findexe(util.expandpath(exe))
166
166
167
167
168 def _picktool(repo, ui, path, binary, symlink, changedelete):
168 def _picktool(repo, ui, path, binary, symlink, changedelete):
169 strictcheck = ui.configbool(b'merge', b'strict-capability-check')
169 strictcheck = ui.configbool(b'merge', b'strict-capability-check')
170
170
171 def hascapability(tool, capability, strict=False):
171 def hascapability(tool, capability, strict=False):
172 if tool in internals:
172 if tool in internals:
173 return strict and internals[tool].capabilities.get(capability)
173 return strict and internals[tool].capabilities.get(capability)
174 return _toolbool(ui, tool, capability)
174 return _toolbool(ui, tool, capability)
175
175
176 def supportscd(tool):
176 def supportscd(tool):
177 return tool in internals and internals[tool].mergetype == nomerge
177 return tool in internals and internals[tool].mergetype == nomerge
178
178
179 def check(tool, pat, symlink, binary, changedelete):
179 def check(tool, pat, symlink, binary, changedelete):
180 tmsg = tool
180 tmsg = tool
181 if pat:
181 if pat:
182 tmsg = _(b"%s (for pattern %s)") % (tool, pat)
182 tmsg = _(b"%s (for pattern %s)") % (tool, pat)
183 if not _findtool(ui, tool):
183 if not _findtool(ui, tool):
184 if pat: # explicitly requested tool deserves a warning
184 if pat: # explicitly requested tool deserves a warning
185 ui.warn(_(b"couldn't find merge tool %s\n") % tmsg)
185 ui.warn(_(b"couldn't find merge tool %s\n") % tmsg)
186 else: # configured but non-existing tools are more silent
186 else: # configured but non-existing tools are more silent
187 ui.note(_(b"couldn't find merge tool %s\n") % tmsg)
187 ui.note(_(b"couldn't find merge tool %s\n") % tmsg)
188 elif symlink and not hascapability(tool, b"symlink", strictcheck):
188 elif symlink and not hascapability(tool, b"symlink", strictcheck):
189 ui.warn(_(b"tool %s can't handle symlinks\n") % tmsg)
189 ui.warn(_(b"tool %s can't handle symlinks\n") % tmsg)
190 elif binary and not hascapability(tool, b"binary", strictcheck):
190 elif binary and not hascapability(tool, b"binary", strictcheck):
191 ui.warn(_(b"tool %s can't handle binary\n") % tmsg)
191 ui.warn(_(b"tool %s can't handle binary\n") % tmsg)
192 elif changedelete and not supportscd(tool):
192 elif changedelete and not supportscd(tool):
193 # the nomerge tools are the only tools that support change/delete
193 # the nomerge tools are the only tools that support change/delete
194 # conflicts
194 # conflicts
195 pass
195 pass
196 elif not procutil.gui() and _toolbool(ui, tool, b"gui"):
196 elif not procutil.gui() and _toolbool(ui, tool, b"gui"):
197 ui.warn(_(b"tool %s requires a GUI\n") % tmsg)
197 ui.warn(_(b"tool %s requires a GUI\n") % tmsg)
198 else:
198 else:
199 return True
199 return True
200 return False
200 return False
201
201
202 # internal config: ui.forcemerge
202 # internal config: ui.forcemerge
203 # forcemerge comes from command line arguments, highest priority
203 # forcemerge comes from command line arguments, highest priority
204 force = ui.config(b'ui', b'forcemerge')
204 force = ui.config(b'ui', b'forcemerge')
205 if force:
205 if force:
206 toolpath = _findtool(ui, force)
206 toolpath = _findtool(ui, force)
207 if changedelete and not supportscd(toolpath):
207 if changedelete and not supportscd(toolpath):
208 return b":prompt", None
208 return b":prompt", None
209 else:
209 else:
210 if toolpath:
210 if toolpath:
211 return (force, _quotetoolpath(toolpath))
211 return (force, _quotetoolpath(toolpath))
212 else:
212 else:
213 # mimic HGMERGE if given tool not found
213 # mimic HGMERGE if given tool not found
214 return (force, force)
214 return (force, force)
215
215
216 # HGMERGE takes next precedence
216 # HGMERGE takes next precedence
217 hgmerge = encoding.environ.get(b"HGMERGE")
217 hgmerge = encoding.environ.get(b"HGMERGE")
218 if hgmerge:
218 if hgmerge:
219 if changedelete and not supportscd(hgmerge):
219 if changedelete and not supportscd(hgmerge):
220 return b":prompt", None
220 return b":prompt", None
221 else:
221 else:
222 return (hgmerge, hgmerge)
222 return (hgmerge, hgmerge)
223
223
224 # then patterns
224 # then patterns
225
225
226 # whether binary capability should be checked strictly
226 # whether binary capability should be checked strictly
227 binarycap = binary and strictcheck
227 binarycap = binary and strictcheck
228
228
229 for pat, tool in ui.configitems(b"merge-patterns"):
229 for pat, tool in ui.configitems(b"merge-patterns"):
230 mf = match.match(repo.root, b'', [pat])
230 mf = match.match(repo.root, b'', [pat])
231 if mf(path) and check(tool, pat, symlink, binarycap, changedelete):
231 if mf(path) and check(tool, pat, symlink, binarycap, changedelete):
232 if binary and not hascapability(tool, b"binary", strict=True):
232 if binary and not hascapability(tool, b"binary", strict=True):
233 ui.warn(
233 ui.warn(
234 _(
234 _(
235 b"warning: check merge-patterns configurations,"
235 b"warning: check merge-patterns configurations,"
236 b" if %r for binary file %r is unintentional\n"
236 b" if %r for binary file %r is unintentional\n"
237 b"(see 'hg help merge-tools'"
237 b"(see 'hg help merge-tools'"
238 b" for binary files capability)\n"
238 b" for binary files capability)\n"
239 )
239 )
240 % (pycompat.bytestr(tool), pycompat.bytestr(path))
240 % (pycompat.bytestr(tool), pycompat.bytestr(path))
241 )
241 )
242 toolpath = _findtool(ui, tool)
242 toolpath = _findtool(ui, tool)
243 return (tool, _quotetoolpath(toolpath))
243 return (tool, _quotetoolpath(toolpath))
244
244
245 # then merge tools
245 # then merge tools
246 tools = {}
246 tools = {}
247 disabled = set()
247 disabled = set()
248 for k, v in ui.configitems(b"merge-tools"):
248 for k, v in ui.configitems(b"merge-tools"):
249 t = k.split(b'.')[0]
249 t = k.split(b'.')[0]
250 if t not in tools:
250 if t not in tools:
251 tools[t] = int(_toolstr(ui, t, b"priority"))
251 tools[t] = int(_toolstr(ui, t, b"priority"))
252 if _toolbool(ui, t, b"disabled"):
252 if _toolbool(ui, t, b"disabled"):
253 disabled.add(t)
253 disabled.add(t)
254 names = tools.keys()
254 names = tools.keys()
255 tools = sorted(
255 tools = sorted(
256 [(-p, tool) for tool, p in tools.items() if tool not in disabled]
256 [(-p, tool) for tool, p in tools.items() if tool not in disabled]
257 )
257 )
258 uimerge = ui.config(b"ui", b"merge")
258 uimerge = ui.config(b"ui", b"merge")
259 if uimerge:
259 if uimerge:
260 # external tools defined in uimerge won't be able to handle
260 # external tools defined in uimerge won't be able to handle
261 # change/delete conflicts
261 # change/delete conflicts
262 if check(uimerge, path, symlink, binary, changedelete):
262 if check(uimerge, path, symlink, binary, changedelete):
263 if uimerge not in names and not changedelete:
263 if uimerge not in names and not changedelete:
264 return (uimerge, uimerge)
264 return (uimerge, uimerge)
265 tools.insert(0, (None, uimerge)) # highest priority
265 tools.insert(0, (None, uimerge)) # highest priority
266 tools.append((None, b"hgmerge")) # the old default, if found
266 tools.append((None, b"hgmerge")) # the old default, if found
267 for p, t in tools:
267 for p, t in tools:
268 if check(t, None, symlink, binary, changedelete):
268 if check(t, None, symlink, binary, changedelete):
269 toolpath = _findtool(ui, t)
269 toolpath = _findtool(ui, t)
270 return (t, _quotetoolpath(toolpath))
270 return (t, _quotetoolpath(toolpath))
271
271
272 # internal merge or prompt as last resort
272 # internal merge or prompt as last resort
273 if symlink or binary or changedelete:
273 if symlink or binary or changedelete:
274 if not changedelete and len(tools):
274 if not changedelete and len(tools):
275 # any tool is rejected by capability for symlink or binary
275 # any tool is rejected by capability for symlink or binary
276 ui.warn(_(b"no tool found to merge %s\n") % path)
276 ui.warn(_(b"no tool found to merge %s\n") % path)
277 return b":prompt", None
277 return b":prompt", None
278 return b":merge", None
278 return b":merge", None
279
279
280
280
281 def _eoltype(data):
281 def _eoltype(data):
282 """Guess the EOL type of a file"""
282 """Guess the EOL type of a file"""
283 if b'\0' in data: # binary
283 if b'\0' in data: # binary
284 return None
284 return None
285 if b'\r\n' in data: # Windows
285 if b'\r\n' in data: # Windows
286 return b'\r\n'
286 return b'\r\n'
287 if b'\r' in data: # Old Mac
287 if b'\r' in data: # Old Mac
288 return b'\r'
288 return b'\r'
289 if b'\n' in data: # UNIX
289 if b'\n' in data: # UNIX
290 return b'\n'
290 return b'\n'
291 return None # unknown
291 return None # unknown
292
292
293
293
294 def _matcheol(file, backup):
294 def _matcheol(file, backup):
295 """Convert EOL markers in a file to match origfile"""
295 """Convert EOL markers in a file to match origfile"""
296 tostyle = _eoltype(backup.data()) # No repo.wread filters?
296 tostyle = _eoltype(backup.data()) # No repo.wread filters?
297 if tostyle:
297 if tostyle:
298 data = util.readfile(file)
298 data = util.readfile(file)
299 style = _eoltype(data)
299 style = _eoltype(data)
300 if style:
300 if style:
301 newdata = data.replace(style, tostyle)
301 newdata = data.replace(style, tostyle)
302 if newdata != data:
302 if newdata != data:
303 util.writefile(file, newdata)
303 util.writefile(file, newdata)
304
304
305
305
306 @internaltool(b'prompt', nomerge)
306 @internaltool(b'prompt', nomerge)
307 def _iprompt(repo, mynode, local, other, base, toolconf):
307 def _iprompt(repo, mynode, local, other, base, toolconf):
308 """Asks the user which of the local `p1()` or the other `p2()` version to
308 """Asks the user which of the local `p1()` or the other `p2()` version to
309 keep as the merged version."""
309 keep as the merged version."""
310 ui = repo.ui
310 ui = repo.ui
311 fd = local.fctx.path()
311 fd = local.fctx.path()
312 uipathfn = scmutil.getuipathfn(repo)
312 uipathfn = scmutil.getuipathfn(repo)
313
313
314 # Avoid prompting during an in-memory merge since it doesn't support merge
314 # Avoid prompting during an in-memory merge since it doesn't support merge
315 # conflicts.
315 # conflicts.
316 if local.fctx.changectx().isinmemory():
316 if local.fctx.changectx().isinmemory():
317 raise error.InMemoryMergeConflictsError(
317 raise error.InMemoryMergeConflictsError(
318 b'in-memory merge does not support file conflicts'
318 b'in-memory merge does not support file conflicts'
319 )
319 )
320
320
321 prompts = partextras([local.label, other.label])
321 prompts = partextras([local.label, other.label])
322 prompts[b'fd'] = uipathfn(fd)
322 prompts[b'fd'] = uipathfn(fd)
323 try:
323 try:
324 if other.fctx.isabsent():
324 if other.fctx.isabsent():
325 index = ui.promptchoice(_localchangedotherdeletedmsg % prompts, 2)
325 index = ui.promptchoice(_localchangedotherdeletedmsg % prompts, 2)
326 choice = [b'local', b'other', b'unresolved'][index]
326 choice = [b'local', b'other', b'unresolved'][index]
327 elif local.fctx.isabsent():
327 elif local.fctx.isabsent():
328 index = ui.promptchoice(_otherchangedlocaldeletedmsg % prompts, 2)
328 index = ui.promptchoice(_otherchangedlocaldeletedmsg % prompts, 2)
329 choice = [b'other', b'local', b'unresolved'][index]
329 choice = [b'other', b'local', b'unresolved'][index]
330 else:
330 else:
331 # IMPORTANT: keep the last line of this prompt ("What do you want to
331 # IMPORTANT: keep the last line of this prompt ("What do you want to
332 # do?") very short, see comment next to _localchangedotherdeletedmsg
332 # do?") very short, see comment next to _localchangedotherdeletedmsg
333 # at the top of the file for details.
333 # at the top of the file for details.
334 index = ui.promptchoice(
334 index = ui.promptchoice(
335 _(
335 _(
336 b"file '%(fd)s' needs to be resolved.\n"
336 b"file '%(fd)s' needs to be resolved.\n"
337 b"You can keep (l)ocal%(l)s, take (o)ther%(o)s, or leave "
337 b"You can keep (l)ocal%(l)s, take (o)ther%(o)s, or leave "
338 b"(u)nresolved.\n"
338 b"(u)nresolved.\n"
339 b"What do you want to do?"
339 b"What do you want to do?"
340 b"$$ &Local $$ &Other $$ &Unresolved"
340 b"$$ &Local $$ &Other $$ &Unresolved"
341 )
341 )
342 % prompts,
342 % prompts,
343 2,
343 2,
344 )
344 )
345 choice = [b'local', b'other', b'unresolved'][index]
345 choice = [b'local', b'other', b'unresolved'][index]
346
346
347 if choice == b'other':
347 if choice == b'other':
348 return _iother(repo, mynode, local, other, base, toolconf)
348 return _iother(repo, mynode, local, other, base, toolconf)
349 elif choice == b'local':
349 elif choice == b'local':
350 return _ilocal(repo, mynode, local, other, base, toolconf)
350 return _ilocal(repo, mynode, local, other, base, toolconf)
351 elif choice == b'unresolved':
351 elif choice == b'unresolved':
352 return _ifail(repo, mynode, local, other, base, toolconf)
352 return _ifail(repo, mynode, local, other, base, toolconf)
353 except error.ResponseExpected:
353 except error.ResponseExpected:
354 ui.write(b"\n")
354 ui.write(b"\n")
355 return _ifail(repo, mynode, local, other, base, toolconf)
355 return _ifail(repo, mynode, local, other, base, toolconf)
356
356
357
357
358 @internaltool(b'local', nomerge)
358 @internaltool(b'local', nomerge)
359 def _ilocal(repo, mynode, local, other, base, toolconf):
359 def _ilocal(repo, mynode, local, other, base, toolconf):
360 """Uses the local `p1()` version of files as the merged version."""
360 """Uses the local `p1()` version of files as the merged version."""
361 return 0, local.fctx.isabsent()
361 return 0, local.fctx.isabsent()
362
362
363
363
364 @internaltool(b'other', nomerge)
364 @internaltool(b'other', nomerge)
365 def _iother(repo, mynode, local, other, base, toolconf):
365 def _iother(repo, mynode, local, other, base, toolconf):
366 """Uses the other `p2()` version of files as the merged version."""
366 """Uses the other `p2()` version of files as the merged version."""
367 if other.fctx.isabsent():
367 if other.fctx.isabsent():
368 # local changed, remote deleted -- 'deleted' picked
368 # local changed, remote deleted -- 'deleted' picked
369 _underlyingfctxifabsent(local.fctx).remove()
369 _underlyingfctxifabsent(local.fctx).remove()
370 deleted = True
370 deleted = True
371 else:
371 else:
372 _underlyingfctxifabsent(local.fctx).write(
372 _underlyingfctxifabsent(local.fctx).write(
373 other.fctx.data(), other.fctx.flags()
373 other.fctx.data(), other.fctx.flags()
374 )
374 )
375 deleted = False
375 deleted = False
376 return 0, deleted
376 return 0, deleted
377
377
378
378
379 @internaltool(b'fail', nomerge)
379 @internaltool(b'fail', nomerge)
380 def _ifail(repo, mynode, local, other, base, toolconf):
380 def _ifail(repo, mynode, local, other, base, toolconf):
381 """
381 """
382 Rather than attempting to merge files that were modified on both
382 Rather than attempting to merge files that were modified on both
383 branches, it marks them as unresolved. The resolve command must be
383 branches, it marks them as unresolved. The resolve command must be
384 used to resolve these conflicts."""
384 used to resolve these conflicts."""
385 # for change/delete conflicts write out the changed version, then fail
385 # for change/delete conflicts write out the changed version, then fail
386 if local.fctx.isabsent():
386 if local.fctx.isabsent():
387 _underlyingfctxifabsent(local.fctx).write(
387 _underlyingfctxifabsent(local.fctx).write(
388 other.fctx.data(), other.fctx.flags()
388 other.fctx.data(), other.fctx.flags()
389 )
389 )
390 return 1, False
390 return 1, False
391
391
392
392
393 def _underlyingfctxifabsent(filectx):
393 def _underlyingfctxifabsent(filectx):
394 """Sometimes when resolving, our fcd is actually an absentfilectx, but
394 """Sometimes when resolving, our fcd is actually an absentfilectx, but
395 we want to write to it (to do the resolve). This helper returns the
395 we want to write to it (to do the resolve). This helper returns the
396 underyling workingfilectx in that case.
396 underyling workingfilectx in that case.
397 """
397 """
398 if filectx.isabsent():
398 if filectx.isabsent():
399 return filectx.changectx()[filectx.path()]
399 return filectx.changectx()[filectx.path()]
400 else:
400 else:
401 return filectx
401 return filectx
402
402
403
403
404 def _verifytext(input, ui):
404 def _verifytext(input, ui):
405 """verifies that text is non-binary"""
405 """verifies that text is non-binary"""
406 if stringutil.binary(input.text()):
406 if stringutil.binary(input.text()):
407 msg = _(b"%s looks like a binary file.") % input.fctx.path()
407 msg = _(b"%s looks like a binary file.") % input.fctx.path()
408 ui.warn(_(b'warning: %s\n') % msg)
408 ui.warn(_(b'warning: %s\n') % msg)
409 raise error.Abort(msg)
409 raise error.Abort(msg)
410
410
411
411
412 def _premerge(repo, local, other, base, toolconf):
412 def _premerge(repo, local, other, base, toolconf):
413 tool, toolpath, binary, symlink, scriptfn = toolconf
413 tool, toolpath, binary, symlink, scriptfn = toolconf
414 if symlink or local.fctx.isabsent() or other.fctx.isabsent():
414 if symlink or local.fctx.isabsent() or other.fctx.isabsent():
415 return 1
415 return 1
416
416
417 ui = repo.ui
417 ui = repo.ui
418
418
419 validkeep = [b'keep', b'keep-merge3', b'keep-mergediff']
419 validkeep = [b'keep', b'keep-merge3', b'keep-mergediff']
420
420
421 # do we attempt to simplemerge first?
421 # do we attempt to simplemerge first?
422 try:
422 try:
423 premerge = _toolbool(ui, tool, b"premerge", not binary)
423 premerge = _toolbool(ui, tool, b"premerge", not binary)
424 except error.ConfigError:
424 except error.ConfigError:
425 premerge = _toolstr(ui, tool, b"premerge", b"").lower()
425 premerge = _toolstr(ui, tool, b"premerge", b"").lower()
426 if premerge not in validkeep:
426 if premerge not in validkeep:
427 _valid = b', '.join([b"'" + v + b"'" for v in validkeep])
427 _valid = b', '.join([b"'" + v + b"'" for v in validkeep])
428 raise error.ConfigError(
428 raise error.ConfigError(
429 _(b"%s.premerge not valid ('%s' is neither boolean nor %s)")
429 _(b"%s.premerge not valid ('%s' is neither boolean nor %s)")
430 % (tool, premerge, _valid)
430 % (tool, premerge, _valid)
431 )
431 )
432
432
433 if premerge:
433 if premerge:
434 mode = b'merge'
434 mode = b'merge'
435 if premerge == b'keep-mergediff':
435 if premerge == b'keep-mergediff':
436 mode = b'mergediff'
436 mode = b'mergediff'
437 elif premerge == b'keep-merge3':
437 elif premerge == b'keep-merge3':
438 mode = b'merge3'
438 mode = b'merge3'
439 if any(
439 if any(
440 stringutil.binary(input.text()) for input in (local, base, other)
440 stringutil.binary(input.text()) for input in (local, base, other)
441 ):
441 ):
442 return 1 # continue merging
442 return 1 # continue merging
443 merged_text, conflicts = simplemerge.simplemerge(
443 merged_text, conflicts = simplemerge.simplemerge(
444 local, base, other, mode=mode
444 local, base, other, mode=mode
445 )
445 )
446 if not conflicts or premerge in validkeep:
446 if not conflicts or premerge in validkeep:
447 # fcd.flags() already has the merged flags (done in
447 # fcd.flags() already has the merged flags (done in
448 # mergestate.resolve())
448 # mergestate.resolve())
449 local.fctx.write(merged_text, local.fctx.flags())
449 local.fctx.write(merged_text, local.fctx.flags())
450 if not conflicts:
450 if not conflicts:
451 ui.debug(b" premerge successful\n")
451 ui.debug(b" premerge successful\n")
452 return 0
452 return 0
453 return 1 # continue merging
453 return 1 # continue merging
454
454
455
455
456 def _mergecheck(repo, mynode, fcd, fco, fca, toolconf):
456 def _mergecheck(repo, mynode, fcd, fco, fca, toolconf):
457 tool, toolpath, binary, symlink, scriptfn = toolconf
457 tool, toolpath, binary, symlink, scriptfn = toolconf
458 uipathfn = scmutil.getuipathfn(repo)
458 uipathfn = scmutil.getuipathfn(repo)
459 if symlink:
459 if symlink:
460 repo.ui.warn(
460 repo.ui.warn(
461 _(b'warning: internal %s cannot merge symlinks for %s\n')
461 _(b'warning: internal %s cannot merge symlinks for %s\n')
462 % (tool, uipathfn(fcd.path()))
462 % (tool, uipathfn(fcd.path()))
463 )
463 )
464 return False
464 return False
465 if fcd.isabsent() or fco.isabsent():
465 if fcd.isabsent() or fco.isabsent():
466 repo.ui.warn(
466 repo.ui.warn(
467 _(
467 _(
468 b'warning: internal %s cannot merge change/delete '
468 b'warning: internal %s cannot merge change/delete '
469 b'conflict for %s\n'
469 b'conflict for %s\n'
470 )
470 )
471 % (tool, uipathfn(fcd.path()))
471 % (tool, uipathfn(fcd.path()))
472 )
472 )
473 return False
473 return False
474 return True
474 return True
475
475
476
476
477 def _merge(repo, local, other, base, mode):
477 def _merge(repo, local, other, base, mode):
478 """
478 """
479 Uses the internal non-interactive simple merge algorithm for merging
479 Uses the internal non-interactive simple merge algorithm for merging
480 files. It will fail if there are any conflicts and leave markers in
480 files. It will fail if there are any conflicts and leave markers in
481 the partially merged file. Markers will have two sections, one for each side
481 the partially merged file. Markers will have two sections, one for each side
482 of merge, unless mode equals 'union' which suppresses the markers."""
482 of merge, unless mode equals 'union' which suppresses the markers."""
483 ui = repo.ui
483 ui = repo.ui
484
484
485 try:
485 try:
486 _verifytext(local, ui)
486 _verifytext(local, ui)
487 _verifytext(base, ui)
487 _verifytext(base, ui)
488 _verifytext(other, ui)
488 _verifytext(other, ui)
489 except error.Abort:
489 except error.Abort:
490 return True, True, False
490 return True, True, False
491 else:
491 else:
492 merged_text, conflicts = simplemerge.simplemerge(
492 merged_text, conflicts = simplemerge.simplemerge(
493 local, base, other, mode=mode
493 local, base, other, mode=mode
494 )
494 )
495 # fcd.flags() already has the merged flags (done in
495 # fcd.flags() already has the merged flags (done in
496 # mergestate.resolve())
496 # mergestate.resolve())
497 local.fctx.write(merged_text, local.fctx.flags())
497 local.fctx.write(merged_text, local.fctx.flags())
498 return True, conflicts, False
498 return True, conflicts, False
499
499
500
500
501 @internaltool(
501 @internaltool(
502 b'union',
502 b'union',
503 fullmerge,
503 fullmerge,
504 _(
504 _(
505 b"warning: conflicts while merging %s! "
505 b"warning: conflicts while merging %s! "
506 b"(edit, then use 'hg resolve --mark')\n"
506 b"(edit, then use 'hg resolve --mark')\n"
507 ),
507 ),
508 precheck=_mergecheck,
508 precheck=_mergecheck,
509 )
509 )
510 def _iunion(repo, mynode, local, other, base, toolconf, backup):
510 def _iunion(repo, mynode, local, other, base, toolconf, backup):
511 """
511 """
512 Uses the internal non-interactive simple merge algorithm for merging
512 Uses the internal non-interactive simple merge algorithm for merging
513 files. It will use both left and right sides for conflict regions.
513 files. It will use both left and right sides for conflict regions.
514 No markers are inserted."""
514 No markers are inserted."""
515 return _merge(repo, local, other, base, b'union')
515 return _merge(repo, local, other, base, b'union')
516
516
517
517
518 @internaltool(
518 @internaltool(
519 b'merge',
519 b'merge',
520 fullmerge,
520 fullmerge,
521 _(
521 _(
522 b"warning: conflicts while merging %s! "
522 b"warning: conflicts while merging %s! "
523 b"(edit, then use 'hg resolve --mark')\n"
523 b"(edit, then use 'hg resolve --mark')\n"
524 ),
524 ),
525 precheck=_mergecheck,
525 precheck=_mergecheck,
526 )
526 )
527 def _imerge(repo, mynode, local, other, base, toolconf, backup):
527 def _imerge(repo, mynode, local, other, base, toolconf, backup):
528 """
528 """
529 Uses the internal non-interactive simple merge algorithm for merging
529 Uses the internal non-interactive simple merge algorithm for merging
530 files. It will fail if there are any conflicts and leave markers in
530 files. It will fail if there are any conflicts and leave markers in
531 the partially merged file. Markers will have two sections, one for each side
531 the partially merged file. Markers will have two sections, one for each side
532 of merge."""
532 of merge."""
533 return _merge(repo, local, other, base, b'merge')
533 return _merge(repo, local, other, base, b'merge')
534
534
535
535
536 @internaltool(
536 @internaltool(
537 b'merge3',
537 b'merge3',
538 fullmerge,
538 fullmerge,
539 _(
539 _(
540 b"warning: conflicts while merging %s! "
540 b"warning: conflicts while merging %s! "
541 b"(edit, then use 'hg resolve --mark')\n"
541 b"(edit, then use 'hg resolve --mark')\n"
542 ),
542 ),
543 precheck=_mergecheck,
543 precheck=_mergecheck,
544 )
544 )
545 def _imerge3(repo, mynode, local, other, base, toolconf, backup):
545 def _imerge3(repo, mynode, local, other, base, toolconf, backup):
546 """
546 """
547 Uses the internal non-interactive simple merge algorithm for merging
547 Uses the internal non-interactive simple merge algorithm for merging
548 files. It will fail if there are any conflicts and leave markers in
548 files. It will fail if there are any conflicts and leave markers in
549 the partially merged file. Marker will have three sections, one from each
549 the partially merged file. Marker will have three sections, one from each
550 side of the merge and one for the base content."""
550 side of the merge and one for the base content."""
551 return _merge(repo, local, other, base, b'merge3')
551 return _merge(repo, local, other, base, b'merge3')
552
552
553
553
554 @internaltool(
554 @internaltool(
555 b'merge3-lie-about-conflicts',
555 b'merge3-lie-about-conflicts',
556 fullmerge,
556 fullmerge,
557 b'',
557 b'',
558 precheck=_mergecheck,
558 precheck=_mergecheck,
559 )
559 )
560 def _imerge3alwaysgood(*args, **kwargs):
560 def _imerge3alwaysgood(*args, **kwargs):
561 # Like merge3, but record conflicts as resolved with markers in place.
561 # Like merge3, but record conflicts as resolved with markers in place.
562 #
562 #
563 # This is used for `diff.merge` to show the differences between
563 # This is used for `diff.merge` to show the differences between
564 # the auto-merge state and the committed merge state. It may be
564 # the auto-merge state and the committed merge state. It may be
565 # useful for other things.
565 # useful for other things.
566 b1, junk, b2 = _imerge3(*args, **kwargs)
566 b1, junk, b2 = _imerge3(*args, **kwargs)
567 # TODO is this right? I'm not sure what these return values mean,
567 # TODO is this right? I'm not sure what these return values mean,
568 # but as far as I can tell this will indicate to callers tha the
568 # but as far as I can tell this will indicate to callers tha the
569 # merge succeeded.
569 # merge succeeded.
570 return b1, False, b2
570 return b1, False, b2
571
571
572
572
573 @internaltool(
573 @internaltool(
574 b'mergediff',
574 b'mergediff',
575 fullmerge,
575 fullmerge,
576 _(
576 _(
577 b"warning: conflicts while merging %s! "
577 b"warning: conflicts while merging %s! "
578 b"(edit, then use 'hg resolve --mark')\n"
578 b"(edit, then use 'hg resolve --mark')\n"
579 ),
579 ),
580 precheck=_mergecheck,
580 precheck=_mergecheck,
581 )
581 )
582 def _imerge_diff(repo, mynode, local, other, base, toolconf, backup):
582 def _imerge_diff(repo, mynode, local, other, base, toolconf, backup):
583 """
583 """
584 Uses the internal non-interactive simple merge algorithm for merging
584 Uses the internal non-interactive simple merge algorithm for merging
585 files. It will fail if there are any conflicts and leave markers in
585 files. It will fail if there are any conflicts and leave markers in
586 the partially merged file. The marker will have two sections, one with the
586 the partially merged file. The marker will have two sections, one with the
587 content from one side of the merge, and one with a diff from the base
587 content from one side of the merge, and one with a diff from the base
588 content to the content on the other side. (experimental)"""
588 content to the content on the other side. (experimental)"""
589 return _merge(repo, local, other, base, b'mergediff')
589 return _merge(repo, local, other, base, b'mergediff')
590
590
591
591
592 @internaltool(b'merge-local', mergeonly, precheck=_mergecheck)
592 @internaltool(b'merge-local', mergeonly, precheck=_mergecheck)
593 def _imergelocal(repo, mynode, local, other, base, toolconf, backup):
593 def _imergelocal(repo, mynode, local, other, base, toolconf, backup):
594 """
594 """
595 Like :merge, but resolve all conflicts non-interactively in favor
595 Like :merge, but resolve all conflicts non-interactively in favor
596 of the local `p1()` changes."""
596 of the local `p1()` changes."""
597 return _merge(repo, local, other, base, b'local')
597 return _merge(repo, local, other, base, b'local')
598
598
599
599
600 @internaltool(b'merge-other', mergeonly, precheck=_mergecheck)
600 @internaltool(b'merge-other', mergeonly, precheck=_mergecheck)
601 def _imergeother(repo, mynode, local, other, base, toolconf, backup):
601 def _imergeother(repo, mynode, local, other, base, toolconf, backup):
602 """
602 """
603 Like :merge, but resolve all conflicts non-interactively in favor
603 Like :merge, but resolve all conflicts non-interactively in favor
604 of the other `p2()` changes."""
604 of the other `p2()` changes."""
605 return _merge(repo, local, other, base, b'other')
605 return _merge(repo, local, other, base, b'other')
606
606
607
607
608 @internaltool(
608 @internaltool(
609 b'tagmerge',
609 b'tagmerge',
610 mergeonly,
610 mergeonly,
611 _(
611 _(
612 b"automatic tag merging of %s failed! "
612 b"automatic tag merging of %s failed! "
613 b"(use 'hg resolve --tool :merge' or another merge "
613 b"(use 'hg resolve --tool :merge' or another merge "
614 b"tool of your choice)\n"
614 b"tool of your choice)\n"
615 ),
615 ),
616 )
616 )
617 def _itagmerge(repo, mynode, local, other, base, toolconf, backup):
617 def _itagmerge(repo, mynode, local, other, base, toolconf, backup):
618 """
618 """
619 Uses the internal tag merge algorithm (experimental).
619 Uses the internal tag merge algorithm (experimental).
620 """
620 """
621 success, status = tagmerge.merge(repo, local.fctx, other.fctx, base.fctx)
621 success, status = tagmerge.merge(repo, local.fctx, other.fctx, base.fctx)
622 return success, status, False
622 return success, status, False
623
623
624
624
625 @internaltool(b'dump', fullmerge, binary=True, symlink=True)
625 @internaltool(b'dump', fullmerge, binary=True, symlink=True)
626 def _idump(repo, mynode, local, other, base, toolconf, backup):
626 def _idump(repo, mynode, local, other, base, toolconf, backup):
627 """
627 """
628 Creates three versions of the files to merge, containing the
628 Creates three versions of the files to merge, containing the
629 contents of local, other and base. These files can then be used to
629 contents of local, other and base. These files can then be used to
630 perform a merge manually. If the file to be merged is named
630 perform a merge manually. If the file to be merged is named
631 ``a.txt``, these files will accordingly be named ``a.txt.local``,
631 ``a.txt``, these files will accordingly be named ``a.txt.local``,
632 ``a.txt.other`` and ``a.txt.base`` and they will be placed in the
632 ``a.txt.other`` and ``a.txt.base`` and they will be placed in the
633 same directory as ``a.txt``.
633 same directory as ``a.txt``.
634
634
635 This implies premerge. Therefore, files aren't dumped, if premerge
635 This implies premerge. Therefore, files aren't dumped, if premerge
636 runs successfully. Use :forcedump to forcibly write files out.
636 runs successfully. Use :forcedump to forcibly write files out.
637 """
637 """
638 a = _workingpath(repo, local.fctx)
638 a = _workingpath(repo, local.fctx)
639 fd = local.fctx.path()
639 fd = local.fctx.path()
640
640
641 from . import context
641 from . import context
642
642
643 if isinstance(local.fctx, context.overlayworkingfilectx):
643 if isinstance(local.fctx, context.overlayworkingfilectx):
644 raise error.InMemoryMergeConflictsError(
644 raise error.InMemoryMergeConflictsError(
645 b'in-memory merge does not support the :dump tool.'
645 b'in-memory merge does not support the :dump tool.'
646 )
646 )
647
647
648 util.writefile(a + b".local", local.fctx.decodeddata())
648 util.writefile(a + b".local", local.fctx.decodeddata())
649 repo.wwrite(fd + b".other", other.fctx.data(), other.fctx.flags())
649 repo.wwrite(fd + b".other", other.fctx.data(), other.fctx.flags())
650 repo.wwrite(fd + b".base", base.fctx.data(), base.fctx.flags())
650 repo.wwrite(fd + b".base", base.fctx.data(), base.fctx.flags())
651 return False, 1, False
651 return False, 1, False
652
652
653
653
654 @internaltool(b'forcedump', mergeonly, binary=True, symlink=True)
654 @internaltool(b'forcedump', mergeonly, binary=True, symlink=True)
655 def _forcedump(repo, mynode, local, other, base, toolconf, backup):
655 def _forcedump(repo, mynode, local, other, base, toolconf, backup):
656 """
656 """
657 Creates three versions of the files as same as :dump, but omits premerge.
657 Creates three versions of the files as same as :dump, but omits premerge.
658 """
658 """
659 return _idump(repo, mynode, local, other, base, toolconf, backup)
659 return _idump(repo, mynode, local, other, base, toolconf, backup)
660
660
661
661
662 def _xmergeimm(repo, mynode, local, other, base, toolconf, backup):
662 def _xmergeimm(repo, mynode, local, other, base, toolconf, backup):
663 # In-memory merge simply raises an exception on all external merge tools,
663 # In-memory merge simply raises an exception on all external merge tools,
664 # for now.
664 # for now.
665 #
665 #
666 # It would be possible to run most tools with temporary files, but this
666 # It would be possible to run most tools with temporary files, but this
667 # raises the question of what to do if the user only partially resolves the
667 # raises the question of what to do if the user only partially resolves the
668 # file -- we can't leave a merge state. (Copy to somewhere in the .hg/
668 # file -- we can't leave a merge state. (Copy to somewhere in the .hg/
669 # directory and tell the user how to get it is my best idea, but it's
669 # directory and tell the user how to get it is my best idea, but it's
670 # clunky.)
670 # clunky.)
671 raise error.InMemoryMergeConflictsError(
671 raise error.InMemoryMergeConflictsError(
672 b'in-memory merge does not support external merge tools'
672 b'in-memory merge does not support external merge tools'
673 )
673 )
674
674
675
675
676 def _describemerge(ui, repo, mynode, fcl, fcb, fco, env, toolpath, args):
676 def _describemerge(ui, repo, mynode, fcl, fcb, fco, env, toolpath, args):
677 tmpl = ui.config(b'command-templates', b'pre-merge-tool-output')
677 tmpl = ui.config(b'command-templates', b'pre-merge-tool-output')
678 if not tmpl:
678 if not tmpl:
679 return
679 return
680
680
681 mappingdict = templateutil.mappingdict
681 mappingdict = templateutil.mappingdict
682 props = {
682 props = {
683 b'ctx': fcl.changectx(),
683 b'ctx': fcl.changectx(),
684 b'node': hex(mynode),
684 b'node': hex(mynode),
685 b'path': fcl.path(),
685 b'path': fcl.path(),
686 b'local': mappingdict(
686 b'local': mappingdict(
687 {
687 {
688 b'ctx': fcl.changectx(),
688 b'ctx': fcl.changectx(),
689 b'fctx': fcl,
689 b'fctx': fcl,
690 b'node': hex(mynode),
690 b'node': hex(mynode),
691 b'name': _(b'local'),
691 b'name': _(b'local'),
692 b'islink': b'l' in fcl.flags(),
692 b'islink': b'l' in fcl.flags(),
693 b'label': env[b'HG_MY_LABEL'],
693 b'label': env[b'HG_MY_LABEL'],
694 }
694 }
695 ),
695 ),
696 b'base': mappingdict(
696 b'base': mappingdict(
697 {
697 {
698 b'ctx': fcb.changectx(),
698 b'ctx': fcb.changectx(),
699 b'fctx': fcb,
699 b'fctx': fcb,
700 b'name': _(b'base'),
700 b'name': _(b'base'),
701 b'islink': b'l' in fcb.flags(),
701 b'islink': b'l' in fcb.flags(),
702 b'label': env[b'HG_BASE_LABEL'],
702 b'label': env[b'HG_BASE_LABEL'],
703 }
703 }
704 ),
704 ),
705 b'other': mappingdict(
705 b'other': mappingdict(
706 {
706 {
707 b'ctx': fco.changectx(),
707 b'ctx': fco.changectx(),
708 b'fctx': fco,
708 b'fctx': fco,
709 b'name': _(b'other'),
709 b'name': _(b'other'),
710 b'islink': b'l' in fco.flags(),
710 b'islink': b'l' in fco.flags(),
711 b'label': env[b'HG_OTHER_LABEL'],
711 b'label': env[b'HG_OTHER_LABEL'],
712 }
712 }
713 ),
713 ),
714 b'toolpath': toolpath,
714 b'toolpath': toolpath,
715 b'toolargs': args,
715 b'toolargs': args,
716 }
716 }
717
717
718 # TODO: make all of this something that can be specified on a per-tool basis
718 # TODO: make all of this something that can be specified on a per-tool basis
719 tmpl = templater.unquotestring(tmpl)
719 tmpl = templater.unquotestring(tmpl)
720
720
721 # Not using cmdutil.rendertemplate here since it causes errors importing
721 # Not using cmdutil.rendertemplate here since it causes errors importing
722 # things for us to import cmdutil.
722 # things for us to import cmdutil.
723 tres = formatter.templateresources(ui, repo)
723 tres = formatter.templateresources(ui, repo)
724 t = formatter.maketemplater(
724 t = formatter.maketemplater(
725 ui, tmpl, defaults=templatekw.keywords, resources=tres
725 ui, tmpl, defaults=templatekw.keywords, resources=tres
726 )
726 )
727 ui.status(t.renderdefault(props))
727 ui.status(t.renderdefault(props))
728
728
729
729
730 def _xmerge(repo, mynode, local, other, base, toolconf, backup):
730 def _xmerge(repo, mynode, local, other, base, toolconf, backup):
731 fcd = local.fctx
731 fcd = local.fctx
732 fco = other.fctx
732 fco = other.fctx
733 fca = base.fctx
733 fca = base.fctx
734 tool, toolpath, binary, symlink, scriptfn = toolconf
734 tool, toolpath, binary, symlink, scriptfn = toolconf
735 uipathfn = scmutil.getuipathfn(repo)
735 uipathfn = scmutil.getuipathfn(repo)
736 if fcd.isabsent() or fco.isabsent():
736 if fcd.isabsent() or fco.isabsent():
737 repo.ui.warn(
737 repo.ui.warn(
738 _(b'warning: %s cannot merge change/delete conflict for %s\n')
738 _(b'warning: %s cannot merge change/delete conflict for %s\n')
739 % (tool, uipathfn(fcd.path()))
739 % (tool, uipathfn(fcd.path()))
740 )
740 )
741 return False, 1, None
741 return False, 1, None
742 localpath = _workingpath(repo, fcd)
742 localpath = _workingpath(repo, fcd)
743 args = _toolstr(repo.ui, tool, b"args")
743 args = _toolstr(repo.ui, tool, b"args")
744
744
745 files = [
745 files = [
746 (b"base", fca.path(), fca.decodeddata()),
746 (b"base", fca.path(), fca.decodeddata()),
747 (b"other", fco.path(), fco.decodeddata()),
747 (b"other", fco.path(), fco.decodeddata()),
748 ]
748 ]
749 outpath = b""
749 outpath = b""
750 if b"$output" in args:
750 if b"$output" in args:
751 # read input from backup, write to original
751 # read input from backup, write to original
752 outpath = localpath
752 outpath = localpath
753 localoutputpath = backup.path()
753 localoutputpath = backup.path()
754 # Remove the .orig to make syntax-highlighting more likely.
754 # Remove the .orig to make syntax-highlighting more likely.
755 if localoutputpath.endswith(b'.orig'):
755 if localoutputpath.endswith(b'.orig'):
756 localoutputpath, ext = os.path.splitext(localoutputpath)
756 localoutputpath, ext = os.path.splitext(localoutputpath)
757 files.append((b"local", localoutputpath, backup.data()))
757 files.append((b"local", localoutputpath, backup.data()))
758
758
759 with _maketempfiles(files) as temppaths:
759 with _maketempfiles(files) as temppaths:
760 basepath, otherpath = temppaths[:2]
760 basepath, otherpath = temppaths[:2]
761 if len(temppaths) == 3:
761 if len(temppaths) == 3:
762 localpath = temppaths[2]
762 localpath = temppaths[2]
763
763
764 def format_label(input):
764 def format_label(input):
765 if input.label_detail:
765 if input.label_detail:
766 return b'%s: %s' % (input.label, input.label_detail)
766 return b'%s: %s' % (input.label, input.label_detail)
767 else:
767 else:
768 return input.label
768 return input.label
769
769
770 env = {
770 env = {
771 b'HG_FILE': fcd.path(),
771 b'HG_FILE': fcd.path(),
772 b'HG_MY_NODE': short(mynode),
772 b'HG_MY_NODE': short(mynode),
773 b'HG_OTHER_NODE': short(fco.changectx().node()),
773 b'HG_OTHER_NODE': short(fco.changectx().node()),
774 b'HG_BASE_NODE': short(fca.changectx().node()),
774 b'HG_BASE_NODE': short(fca.changectx().node()),
775 b'HG_MY_ISLINK': b'l' in fcd.flags(),
775 b'HG_MY_ISLINK': b'l' in fcd.flags(),
776 b'HG_OTHER_ISLINK': b'l' in fco.flags(),
776 b'HG_OTHER_ISLINK': b'l' in fco.flags(),
777 b'HG_BASE_ISLINK': b'l' in fca.flags(),
777 b'HG_BASE_ISLINK': b'l' in fca.flags(),
778 b'HG_MY_LABEL': format_label(local),
778 b'HG_MY_LABEL': format_label(local),
779 b'HG_OTHER_LABEL': format_label(other),
779 b'HG_OTHER_LABEL': format_label(other),
780 b'HG_BASE_LABEL': format_label(base),
780 b'HG_BASE_LABEL': format_label(base),
781 }
781 }
782 ui = repo.ui
782 ui = repo.ui
783
783
784 replace = {
784 replace = {
785 b'local': localpath,
785 b'local': localpath,
786 b'base': basepath,
786 b'base': basepath,
787 b'other': otherpath,
787 b'other': otherpath,
788 b'output': outpath,
788 b'output': outpath,
789 b'labellocal': format_label(local),
789 b'labellocal': format_label(local),
790 b'labelother': format_label(other),
790 b'labelother': format_label(other),
791 b'labelbase': format_label(base),
791 b'labelbase': format_label(base),
792 }
792 }
793 args = util.interpolate(
793 args = util.interpolate(
794 br'\$',
794 br'\$',
795 replace,
795 replace,
796 args,
796 args,
797 lambda s: procutil.shellquote(util.localpath(s)),
797 lambda s: procutil.shellquote(util.localpath(s)),
798 )
798 )
799 if _toolbool(ui, tool, b"gui"):
799 if _toolbool(ui, tool, b"gui"):
800 repo.ui.status(
800 repo.ui.status(
801 _(b'running merge tool %s for file %s\n')
801 _(b'running merge tool %s for file %s\n')
802 % (tool, uipathfn(fcd.path()))
802 % (tool, uipathfn(fcd.path()))
803 )
803 )
804 if scriptfn is None:
804 if scriptfn is None:
805 cmd = toolpath + b' ' + args
805 cmd = toolpath + b' ' + args
806 repo.ui.debug(b'launching merge tool: %s\n' % cmd)
806 repo.ui.debug(b'launching merge tool: %s\n' % cmd)
807 _describemerge(ui, repo, mynode, fcd, fca, fco, env, toolpath, args)
807 _describemerge(ui, repo, mynode, fcd, fca, fco, env, toolpath, args)
808 r = ui.system(
808 r = ui.system(
809 cmd, cwd=repo.root, environ=env, blockedtag=b'mergetool'
809 cmd, cwd=repo.root, environ=env, blockedtag=b'mergetool'
810 )
810 )
811 else:
811 else:
812 repo.ui.debug(
812 repo.ui.debug(
813 b'launching python merge script: %s:%s\n' % (toolpath, scriptfn)
813 b'launching python merge script: %s:%s\n' % (toolpath, scriptfn)
814 )
814 )
815 r = 0
815 r = 0
816 try:
816 try:
817 # avoid cycle cmdutil->merge->filemerge->extensions->cmdutil
817 # avoid cycle cmdutil->merge->filemerge->extensions->cmdutil
818 from . import extensions
818 from . import extensions
819
819
820 mod = extensions.loadpath(toolpath, b'hgmerge.%s' % tool)
820 mod = extensions.loadpath(toolpath, b'hgmerge.%s' % tool)
821 except Exception:
821 except Exception:
822 raise error.Abort(
822 raise error.Abort(
823 _(b"loading python merge script failed: %s") % toolpath
823 _(b"loading python merge script failed: %s") % toolpath
824 )
824 )
825 mergefn = getattr(mod, scriptfn, None)
825 mergefn = getattr(mod, scriptfn, None)
826 if mergefn is None:
826 if mergefn is None:
827 raise error.Abort(
827 raise error.Abort(
828 _(b"%s does not have function: %s") % (toolpath, scriptfn)
828 _(b"%s does not have function: %s") % (toolpath, scriptfn)
829 )
829 )
830 argslist = procutil.shellsplit(args)
830 argslist = procutil.shellsplit(args)
831 # avoid cycle cmdutil->merge->filemerge->hook->extensions->cmdutil
831 # avoid cycle cmdutil->merge->filemerge->hook->extensions->cmdutil
832 from . import hook
832 from . import hook
833
833
834 ret, raised = hook.pythonhook(
834 ret, raised = hook.pythonhook(
835 ui, repo, b"merge", toolpath, mergefn, {b'args': argslist}, True
835 ui, repo, b"merge", toolpath, mergefn, {b'args': argslist}, True
836 )
836 )
837 if raised:
837 if raised:
838 r = 1
838 r = 1
839 repo.ui.debug(b'merge tool returned: %d\n' % r)
839 repo.ui.debug(b'merge tool returned: %d\n' % r)
840 return True, r, False
840 return True, r, False
841
841
842
842
843 def _populate_label_detail(input, template):
843 def _populate_label_detail(input, template):
844 """Applies the given template to the ctx and stores it in the input."""
844 """Applies the given template to the ctx and stores it in the input."""
845 ctx = input.fctx.changectx()
845 ctx = input.fctx.changectx()
846 if ctx.node() is None:
846 if ctx.node() is None:
847 ctx = ctx.p1()
847 ctx = ctx.p1()
848
848
849 props = {b'ctx': ctx}
849 props = {b'ctx': ctx}
850 templateresult = template.renderdefault(props)
850 templateresult = template.renderdefault(props)
851 input.label_detail = templateresult.splitlines()[0] # split for safety
851 input.label_detail = templateresult.splitlines()[0] # split for safety
852
852
853
853
854 def _populate_label_details(repo, inputs, tool=None):
854 def _populate_label_details(repo, inputs, tool=None):
855 """Populates the label details using the conflict marker template."""
855 """Populates the label details using the conflict marker template."""
856 ui = repo.ui
856 ui = repo.ui
857 template = ui.config(b'command-templates', b'mergemarker')
857 template = ui.config(b'command-templates', b'mergemarker')
858 if tool is not None:
858 if tool is not None:
859 template = _toolstr(ui, tool, b'mergemarkertemplate', template)
859 template = _toolstr(ui, tool, b'mergemarkertemplate', template)
860 template = templater.unquotestring(template)
860 template = templater.unquotestring(template)
861 tres = formatter.templateresources(ui, repo)
861 tres = formatter.templateresources(ui, repo)
862 tmpl = formatter.maketemplater(
862 tmpl = formatter.maketemplater(
863 ui, template, defaults=templatekw.keywords, resources=tres
863 ui, template, defaults=templatekw.keywords, resources=tres
864 )
864 )
865
865
866 for input in inputs:
866 for input in inputs:
867 _populate_label_detail(input, tmpl)
867 _populate_label_detail(input, tmpl)
868
868
869
869
870 def partextras(labels):
870 def partextras(labels):
871 """Return a dictionary of extra labels for use in prompts to the user
871 """Return a dictionary of extra labels for use in prompts to the user
872
872
873 Intended use is in strings of the form "(l)ocal%(l)s".
873 Intended use is in strings of the form "(l)ocal%(l)s".
874 """
874 """
875 if labels is None:
875 if labels is None:
876 return {
876 return {
877 b"l": b"",
877 b"l": b"",
878 b"o": b"",
878 b"o": b"",
879 }
879 }
880
880
881 return {
881 return {
882 b"l": b" [%s]" % labels[0],
882 b"l": b" [%s]" % labels[0],
883 b"o": b" [%s]" % labels[1],
883 b"o": b" [%s]" % labels[1],
884 }
884 }
885
885
886
886
887 def _makebackup(repo, ui, fcd):
887 def _makebackup(repo, ui, fcd):
888 """Makes and returns a filectx-like object for ``fcd``'s backup file.
888 """Makes and returns a filectx-like object for ``fcd``'s backup file.
889
889
890 In addition to preserving the user's pre-existing modifications to `fcd`
890 In addition to preserving the user's pre-existing modifications to `fcd`
891 (if any), the backup is used to undo certain premerges, confirm whether a
891 (if any), the backup is used to undo certain premerges, confirm whether a
892 merge changed anything, and determine what line endings the new file should
892 merge changed anything, and determine what line endings the new file should
893 have.
893 have.
894
894
895 Backups only need to be written once since their content doesn't change
895 Backups only need to be written once since their content doesn't change
896 afterwards.
896 afterwards.
897 """
897 """
898 if fcd.isabsent():
898 if fcd.isabsent():
899 return None
899 return None
900 # TODO: Break this import cycle somehow. (filectx -> ctx -> fileset ->
900 # TODO: Break this import cycle somehow. (filectx -> ctx -> fileset ->
901 # merge -> filemerge). (I suspect the fileset import is the weakest link)
901 # merge -> filemerge). (I suspect the fileset import is the weakest link)
902 from . import context
902 from . import context
903
903
904 if isinstance(fcd, context.overlayworkingfilectx):
904 if isinstance(fcd, context.overlayworkingfilectx):
905 # If we're merging in-memory, we're free to put the backup anywhere.
905 # If we're merging in-memory, we're free to put the backup anywhere.
906 fd, backup = pycompat.mkstemp(b'hg-merge-backup')
906 fd, backup = pycompat.mkstemp(b'hg-merge-backup')
907 with os.fdopen(fd, 'wb') as f:
907 with os.fdopen(fd, 'wb') as f:
908 f.write(fcd.data())
908 f.write(fcd.data())
909 else:
909 else:
910 backup = scmutil.backuppath(ui, repo, fcd.path())
910 backup = scmutil.backuppath(ui, repo, fcd.path())
911 a = _workingpath(repo, fcd)
911 a = _workingpath(repo, fcd)
912 util.copyfile(a, backup)
912 util.copyfile(a, backup)
913
913
914 return context.arbitraryfilectx(backup, repo=repo)
914 return context.arbitraryfilectx(backup, repo=repo)
915
915
916
916
917 @contextlib.contextmanager
917 @contextlib.contextmanager
918 def _maketempfiles(files):
918 def _maketempfiles(files):
919 """Creates a temporary file for each (prefix, path, data) tuple in `files`,
919 """Creates a temporary file for each (prefix, path, data) tuple in `files`,
920 so an external merge tool may use them.
920 so an external merge tool may use them.
921 """
921 """
922 tmproot = pycompat.mkdtemp(prefix=b'hgmerge-')
922 tmproot = pycompat.mkdtemp(prefix=b'hgmerge-')
923
923
924 def maketempfrompath(prefix, path, data):
924 def maketempfrompath(prefix, path, data):
925 fullbase, ext = os.path.splitext(path)
925 fullbase, ext = os.path.splitext(path)
926 pre = b"%s~%s" % (os.path.basename(fullbase), prefix)
926 pre = b"%s~%s" % (os.path.basename(fullbase), prefix)
927 name = os.path.join(tmproot, pre)
927 name = os.path.join(tmproot, pre)
928 if ext:
928 if ext:
929 name += ext
929 name += ext
930 util.writefile(name, data)
930 util.writefile(name, data)
931 return name
931 return name
932
932
933 temp_files = []
933 temp_files = []
934 for prefix, path, data in files:
934 for prefix, path, data in files:
935 temp_files.append(maketempfrompath(prefix, path, data))
935 temp_files.append(maketempfrompath(prefix, path, data))
936 try:
936 try:
937 yield temp_files
937 yield temp_files
938 finally:
938 finally:
939 shutil.rmtree(tmproot)
939 shutil.rmtree(tmproot)
940
940
941
941
942 def filemerge(repo, wctx, mynode, orig, fcd, fco, fca, labels=None):
942 def filemerge(repo, wctx, mynode, orig, fcd, fco, fca, labels=None):
943 """perform a 3-way merge in the working directory
943 """perform a 3-way merge in the working directory
944
944
945 mynode = parent node before merge
945 mynode = parent node before merge
946 orig = original local filename before merge
946 orig = original local filename before merge
947 fco = other file context
947 fco = other file context
948 fca = ancestor file context
948 fca = ancestor file context
949 fcd = local file context for current/destination file
949 fcd = local file context for current/destination file
950
950
951 Returns whether the merge is complete, the return value of the merge, and
951 Returns whether the merge is complete, the return value of the merge, and
952 a boolean indicating whether the file was deleted from disk."""
952 a boolean indicating whether the file was deleted from disk."""
953 ui = repo.ui
953 ui = repo.ui
954 fd = fcd.path()
954 fd = fcd.path()
955 uipathfn = scmutil.getuipathfn(repo)
955 uipathfn = scmutil.getuipathfn(repo)
956 fduipath = uipathfn(fd)
956 fduipath = uipathfn(fd)
957 binary = fcd.isbinary() or fco.isbinary() or fca.isbinary()
957 binary = fcd.isbinary() or fco.isbinary() or fca.isbinary()
958 symlink = b'l' in fcd.flags() + fco.flags()
958 symlink = b'l' in fcd.flags() + fco.flags()
959 changedelete = fcd.isabsent() or fco.isabsent()
959 changedelete = fcd.isabsent() or fco.isabsent()
960 tool, toolpath = _picktool(repo, ui, fd, binary, symlink, changedelete)
960 tool, toolpath = _picktool(repo, ui, fd, binary, symlink, changedelete)
961 scriptfn = None
961 scriptfn = None
962 if tool in internals and tool.startswith(b'internal:'):
962 if tool in internals and tool.startswith(b'internal:'):
963 # normalize to new-style names (':merge' etc)
963 # normalize to new-style names (':merge' etc)
964 tool = tool[len(b'internal') :]
964 tool = tool[len(b'internal') :]
965 if toolpath and toolpath.startswith(b'python:'):
965 if toolpath and toolpath.startswith(b'python:'):
966 invalidsyntax = False
966 invalidsyntax = False
967 if toolpath.count(b':') >= 2:
967 if toolpath.count(b':') >= 2:
968 script, scriptfn = toolpath[7:].rsplit(b':', 1)
968 script, scriptfn = toolpath[7:].rsplit(b':', 1)
969 if not scriptfn:
969 if not scriptfn:
970 invalidsyntax = True
970 invalidsyntax = True
971 # missing :callable can lead to spliting on windows drive letter
971 # missing :callable can lead to spliting on windows drive letter
972 if b'\\' in scriptfn or b'/' in scriptfn:
972 if b'\\' in scriptfn or b'/' in scriptfn:
973 invalidsyntax = True
973 invalidsyntax = True
974 else:
974 else:
975 invalidsyntax = True
975 invalidsyntax = True
976 if invalidsyntax:
976 if invalidsyntax:
977 raise error.Abort(_(b"invalid 'python:' syntax: %s") % toolpath)
977 raise error.Abort(_(b"invalid 'python:' syntax: %s") % toolpath)
978 toolpath = script
978 toolpath = script
979 ui.debug(
979 ui.debug(
980 b"picked tool '%s' for %s (binary %s symlink %s changedelete %s)\n"
980 b"picked tool '%s' for %s (binary %s symlink %s changedelete %s)\n"
981 % (
981 % (
982 tool,
982 tool,
983 fduipath,
983 fduipath,
984 pycompat.bytestr(binary),
984 pycompat.bytestr(binary),
985 pycompat.bytestr(symlink),
985 pycompat.bytestr(symlink),
986 pycompat.bytestr(changedelete),
986 pycompat.bytestr(changedelete),
987 )
987 )
988 )
988 )
989
989
990 if tool in internals:
990 if tool in internals:
991 func = internals[tool]
991 func = internals[tool]
992 mergetype = func.mergetype
992 mergetype = func.mergetype
993 onfailure = func.onfailure
993 onfailure = func.onfailure
994 precheck = func.precheck
994 precheck = func.precheck
995 isexternal = False
995 isexternal = False
996 else:
996 else:
997 if wctx.isinmemory():
997 if wctx.isinmemory():
998 func = _xmergeimm
998 func = _xmergeimm
999 else:
999 else:
1000 func = _xmerge
1000 func = _xmerge
1001 mergetype = fullmerge
1001 mergetype = fullmerge
1002 onfailure = _(b"merging %s failed!\n")
1002 onfailure = _(b"merging %s failed!\n")
1003 precheck = None
1003 precheck = None
1004 isexternal = True
1004 isexternal = True
1005
1005
1006 toolconf = tool, toolpath, binary, symlink, scriptfn
1006 toolconf = tool, toolpath, binary, symlink, scriptfn
1007
1007
1008 if not labels:
1008 if not labels:
1009 labels = [b'local', b'other']
1009 labels = [b'local', b'other']
1010 if len(labels) < 3:
1010 if len(labels) < 3:
1011 labels.append(b'base')
1011 labels.append(b'base')
1012 local = simplemerge.MergeInput(fcd, labels[0])
1012 local = simplemerge.MergeInput(fcd, labels[0])
1013 other = simplemerge.MergeInput(fco, labels[1])
1013 other = simplemerge.MergeInput(fco, labels[1])
1014 base = simplemerge.MergeInput(fca, labels[2])
1014 base = simplemerge.MergeInput(fca, labels[2])
1015 if mergetype == nomerge:
1015 if mergetype == nomerge:
1016 return func(
1016 return func(
1017 repo,
1017 repo,
1018 mynode,
1018 mynode,
1019 local,
1019 local,
1020 other,
1020 other,
1021 base,
1021 base,
1022 toolconf,
1022 toolconf,
1023 )
1023 )
1024
1024
1025 if orig != fco.path():
1025 if orig != fco.path():
1026 ui.status(
1026 ui.status(
1027 _(b"merging %s and %s to %s\n")
1027 _(b"merging %s and %s to %s\n")
1028 % (uipathfn(orig), uipathfn(fco.path()), fduipath)
1028 % (uipathfn(orig), uipathfn(fco.path()), fduipath)
1029 )
1029 )
1030 else:
1030 else:
1031 ui.status(_(b"merging %s\n") % fduipath)
1031 ui.status(_(b"merging %s\n") % fduipath)
1032
1032
1033 ui.debug(b"my %s other %s ancestor %s\n" % (fcd, fco, fca))
1033 ui.debug(b"my %s other %s ancestor %s\n" % (fcd, fco, fca))
1034
1034
1035 if precheck and not precheck(repo, mynode, fcd, fco, fca, toolconf):
1035 if precheck and not precheck(repo, mynode, fcd, fco, fca, toolconf):
1036 if onfailure:
1036 if onfailure:
1037 if wctx.isinmemory():
1037 if wctx.isinmemory():
1038 raise error.InMemoryMergeConflictsError(
1038 raise error.InMemoryMergeConflictsError(
1039 b'in-memory merge does not support merge conflicts'
1039 b'in-memory merge does not support merge conflicts'
1040 )
1040 )
1041 ui.warn(onfailure % fduipath)
1041 ui.warn(onfailure % fduipath)
1042 return 1, False
1042 return 1, False
1043
1043
1044 backup = _makebackup(repo, ui, fcd)
1044 backup = _makebackup(repo, ui, fcd)
1045 r = 1
1045 r = 1
1046 try:
1046 try:
1047 internalmarkerstyle = ui.config(b'ui', b'mergemarkers')
1047 internalmarkerstyle = ui.config(b'ui', b'mergemarkers')
1048 if isexternal:
1048 if isexternal:
1049 markerstyle = _toolstr(ui, tool, b'mergemarkers')
1049 markerstyle = _toolstr(ui, tool, b'mergemarkers')
1050 else:
1050 else:
1051 markerstyle = internalmarkerstyle
1051 markerstyle = internalmarkerstyle
1052
1052
1053 if mergetype == fullmerge:
1053 if mergetype == fullmerge:
1054 _run_partial_resolution_tools(repo, local, other, base)
1054 # conflict markers generated by premerge will use 'detailed'
1055 # conflict markers generated by premerge will use 'detailed'
1055 # settings if either ui.mergemarkers or the tool's mergemarkers
1056 # settings if either ui.mergemarkers or the tool's mergemarkers
1056 # setting is 'detailed'. This way tools can have basic labels in
1057 # setting is 'detailed'. This way tools can have basic labels in
1057 # space-constrained areas of the UI, but still get full information
1058 # space-constrained areas of the UI, but still get full information
1058 # in conflict markers if premerge is 'keep' or 'keep-merge3'.
1059 # in conflict markers if premerge is 'keep' or 'keep-merge3'.
1059 labeltool = None
1060 labeltool = None
1060 if markerstyle != b'basic':
1061 if markerstyle != b'basic':
1061 # respect 'tool's mergemarkertemplate (which defaults to
1062 # respect 'tool's mergemarkertemplate (which defaults to
1062 # command-templates.mergemarker)
1063 # command-templates.mergemarker)
1063 labeltool = tool
1064 labeltool = tool
1064 if internalmarkerstyle != b'basic' or markerstyle != b'basic':
1065 if internalmarkerstyle != b'basic' or markerstyle != b'basic':
1065 _populate_label_details(
1066 _populate_label_details(
1066 repo, [local, other, base], tool=labeltool
1067 repo, [local, other, base], tool=labeltool
1067 )
1068 )
1068
1069
1069 r = _premerge(
1070 r = _premerge(
1070 repo,
1071 repo,
1071 local,
1072 local,
1072 other,
1073 other,
1073 base,
1074 base,
1074 toolconf,
1075 toolconf,
1075 )
1076 )
1076 # we're done if premerge was successful (r is 0)
1077 # we're done if premerge was successful (r is 0)
1077 if not r:
1078 if not r:
1078 return r, False
1079 return r, False
1079
1080
1080 # Reset to basic labels
1081 # Reset to basic labels
1081 local.label_detail = None
1082 local.label_detail = None
1082 other.label_detail = None
1083 other.label_detail = None
1083 base.label_detail = None
1084 base.label_detail = None
1084
1085
1085 if markerstyle != b'basic':
1086 if markerstyle != b'basic':
1086 _populate_label_details(repo, [local, other, base], tool=tool)
1087 _populate_label_details(repo, [local, other, base], tool=tool)
1087
1088
1088 needcheck, r, deleted = func(
1089 needcheck, r, deleted = func(
1089 repo,
1090 repo,
1090 mynode,
1091 mynode,
1091 local,
1092 local,
1092 other,
1093 other,
1093 base,
1094 base,
1094 toolconf,
1095 toolconf,
1095 backup,
1096 backup,
1096 )
1097 )
1097
1098
1098 if needcheck:
1099 if needcheck:
1099 r = _check(repo, r, ui, tool, fcd, backup)
1100 r = _check(repo, r, ui, tool, fcd, backup)
1100
1101
1101 if r:
1102 if r:
1102 if onfailure:
1103 if onfailure:
1103 if wctx.isinmemory():
1104 if wctx.isinmemory():
1104 raise error.InMemoryMergeConflictsError(
1105 raise error.InMemoryMergeConflictsError(
1105 b'in-memory merge '
1106 b'in-memory merge '
1106 b'does not support '
1107 b'does not support '
1107 b'merge conflicts'
1108 b'merge conflicts'
1108 )
1109 )
1109 ui.warn(onfailure % fduipath)
1110 ui.warn(onfailure % fduipath)
1110 _onfilemergefailure(ui)
1111 _onfilemergefailure(ui)
1111
1112
1112 return r, deleted
1113 return r, deleted
1113 finally:
1114 finally:
1114 if not r and backup is not None:
1115 if not r and backup is not None:
1115 backup.remove()
1116 backup.remove()
1116
1117
1117
1118
1119 def _run_partial_resolution_tools(repo, local, other, base):
1120 """Runs partial-resolution tools on the three inputs and updates them."""
1121 ui = repo.ui
1122 # Tuples of (order, name, executable path)
1123 tools = []
1124 seen = set()
1125 section = b"partial-merge-tools"
1126 for k, v in ui.configitems(section):
1127 name = k.split(b'.')[0]
1128 if name in seen:
1129 continue
1130 patterns = ui.configlist(section, b'%s.patterns' % name, [])
1131 is_match = True
1132 if patterns:
1133 m = match.match(repo.root, b'', patterns)
1134 is_match = m(local.fctx.path())
1135 if is_match:
1136 order = ui.configint(section, b'%s.order' % name, 0)
1137 executable = ui.config(section, b'%s.executable' % name, name)
1138 tools.append((order, name, executable))
1139
1140 if not tools:
1141 return
1142 # Sort in configured order (first in tuple)
1143 tools.sort()
1144
1145 files = [
1146 (b"local", local.fctx.path(), local.text()),
1147 (b"base", base.fctx.path(), base.text()),
1148 (b"other", other.fctx.path(), other.text()),
1149 ]
1150
1151 with _maketempfiles(files) as temppaths:
1152 localpath, basepath, otherpath = temppaths
1153
1154 for order, name, executable in tools:
1155 cmd = procutil.shellquote(executable)
1156 # TODO: Allow the user to configure the command line using
1157 # $local, $base, $other.
1158 cmd = b'%s %s %s %s' % (cmd, localpath, basepath, otherpath)
1159 r = ui.system(cmd, cwd=repo.root, blockedtag=b'partial-mergetool')
1160 if r:
1161 raise error.StateError(
1162 b'partial merge tool %s exited with code %d' % (name, r)
1163 )
1164 local_text = util.readfile(localpath)
1165 other_text = util.readfile(otherpath)
1166 if local_text == other_text:
1167 # No need to run other tools if all conflicts have been resolved
1168 break
1169
1170 local.set_text(local_text)
1171 base.set_text(util.readfile(basepath))
1172 other.set_text(other_text)
1173
1174
1118 def _haltmerge():
1175 def _haltmerge():
1119 msg = _(b'merge halted after failed merge (see hg resolve)')
1176 msg = _(b'merge halted after failed merge (see hg resolve)')
1120 raise error.InterventionRequired(msg)
1177 raise error.InterventionRequired(msg)
1121
1178
1122
1179
1123 def _onfilemergefailure(ui):
1180 def _onfilemergefailure(ui):
1124 action = ui.config(b'merge', b'on-failure')
1181 action = ui.config(b'merge', b'on-failure')
1125 if action == b'prompt':
1182 if action == b'prompt':
1126 msg = _(b'continue merge operation (yn)?$$ &Yes $$ &No')
1183 msg = _(b'continue merge operation (yn)?$$ &Yes $$ &No')
1127 if ui.promptchoice(msg, 0) == 1:
1184 if ui.promptchoice(msg, 0) == 1:
1128 _haltmerge()
1185 _haltmerge()
1129 if action == b'halt':
1186 if action == b'halt':
1130 _haltmerge()
1187 _haltmerge()
1131 # default action is 'continue', in which case we neither prompt nor halt
1188 # default action is 'continue', in which case we neither prompt nor halt
1132
1189
1133
1190
1134 def hasconflictmarkers(data):
1191 def hasconflictmarkers(data):
1135 # Detect lines starting with a string of 7 identical characters from the
1192 # Detect lines starting with a string of 7 identical characters from the
1136 # subset Mercurial uses for conflict markers, followed by either the end of
1193 # subset Mercurial uses for conflict markers, followed by either the end of
1137 # line or a space and some text. Note that using [<>=+|-]{7} would detect
1194 # line or a space and some text. Note that using [<>=+|-]{7} would detect
1138 # `<><><><><` as a conflict marker, which we don't want.
1195 # `<><><><><` as a conflict marker, which we don't want.
1139 return bool(
1196 return bool(
1140 re.search(
1197 re.search(
1141 br"^([<>=+|-])\1{6}( .*)$",
1198 br"^([<>=+|-])\1{6}( .*)$",
1142 data,
1199 data,
1143 re.MULTILINE,
1200 re.MULTILINE,
1144 )
1201 )
1145 )
1202 )
1146
1203
1147
1204
1148 def _check(repo, r, ui, tool, fcd, backup):
1205 def _check(repo, r, ui, tool, fcd, backup):
1149 fd = fcd.path()
1206 fd = fcd.path()
1150 uipathfn = scmutil.getuipathfn(repo)
1207 uipathfn = scmutil.getuipathfn(repo)
1151
1208
1152 if not r and (
1209 if not r and (
1153 _toolbool(ui, tool, b"checkconflicts")
1210 _toolbool(ui, tool, b"checkconflicts")
1154 or b'conflicts' in _toollist(ui, tool, b"check")
1211 or b'conflicts' in _toollist(ui, tool, b"check")
1155 ):
1212 ):
1156 if hasconflictmarkers(fcd.data()):
1213 if hasconflictmarkers(fcd.data()):
1157 r = 1
1214 r = 1
1158
1215
1159 checked = False
1216 checked = False
1160 if b'prompt' in _toollist(ui, tool, b"check"):
1217 if b'prompt' in _toollist(ui, tool, b"check"):
1161 checked = True
1218 checked = True
1162 if ui.promptchoice(
1219 if ui.promptchoice(
1163 _(b"was merge of '%s' successful (yn)?$$ &Yes $$ &No")
1220 _(b"was merge of '%s' successful (yn)?$$ &Yes $$ &No")
1164 % uipathfn(fd),
1221 % uipathfn(fd),
1165 1,
1222 1,
1166 ):
1223 ):
1167 r = 1
1224 r = 1
1168
1225
1169 if (
1226 if (
1170 not r
1227 not r
1171 and not checked
1228 and not checked
1172 and (
1229 and (
1173 _toolbool(ui, tool, b"checkchanged")
1230 _toolbool(ui, tool, b"checkchanged")
1174 or b'changed' in _toollist(ui, tool, b"check")
1231 or b'changed' in _toollist(ui, tool, b"check")
1175 )
1232 )
1176 ):
1233 ):
1177 if backup is not None and not fcd.cmp(backup):
1234 if backup is not None and not fcd.cmp(backup):
1178 if ui.promptchoice(
1235 if ui.promptchoice(
1179 _(
1236 _(
1180 b" output file %s appears unchanged\n"
1237 b" output file %s appears unchanged\n"
1181 b"was merge successful (yn)?"
1238 b"was merge successful (yn)?"
1182 b"$$ &Yes $$ &No"
1239 b"$$ &Yes $$ &No"
1183 )
1240 )
1184 % uipathfn(fd),
1241 % uipathfn(fd),
1185 1,
1242 1,
1186 ):
1243 ):
1187 r = 1
1244 r = 1
1188
1245
1189 if backup is not None and _toolbool(ui, tool, b"fixeol"):
1246 if backup is not None and _toolbool(ui, tool, b"fixeol"):
1190 _matcheol(_workingpath(repo, fcd), backup)
1247 _matcheol(_workingpath(repo, fcd), backup)
1191
1248
1192 return r
1249 return r
1193
1250
1194
1251
1195 def _workingpath(repo, ctx):
1252 def _workingpath(repo, ctx):
1196 return repo.wjoin(ctx.path())
1253 return repo.wjoin(ctx.path())
1197
1254
1198
1255
1199 def loadinternalmerge(ui, extname, registrarobj):
1256 def loadinternalmerge(ui, extname, registrarobj):
1200 """Load internal merge tool from specified registrarobj"""
1257 """Load internal merge tool from specified registrarobj"""
1201 for name, func in registrarobj._table.items():
1258 for name, func in registrarobj._table.items():
1202 fullname = b':' + name
1259 fullname = b':' + name
1203 internals[fullname] = func
1260 internals[fullname] = func
1204 internals[b'internal:' + name] = func
1261 internals[b'internal:' + name] = func
1205 internalsdoc[fullname] = func
1262 internalsdoc[fullname] = func
1206
1263
1207 capabilities = sorted([k for k, v in func.capabilities.items() if v])
1264 capabilities = sorted([k for k, v in func.capabilities.items() if v])
1208 if capabilities:
1265 if capabilities:
1209 capdesc = b" (actual capabilities: %s)" % b', '.join(
1266 capdesc = b" (actual capabilities: %s)" % b', '.join(
1210 capabilities
1267 capabilities
1211 )
1268 )
1212 func.__doc__ = func.__doc__ + pycompat.sysstr(b"\n\n%s" % capdesc)
1269 func.__doc__ = func.__doc__ + pycompat.sysstr(b"\n\n%s" % capdesc)
1213
1270
1214 # to put i18n comments into hg.pot for automatically generated texts
1271 # to put i18n comments into hg.pot for automatically generated texts
1215
1272
1216 # i18n: "binary" and "symlink" are keywords
1273 # i18n: "binary" and "symlink" are keywords
1217 # i18n: this text is added automatically
1274 # i18n: this text is added automatically
1218 _(b" (actual capabilities: binary, symlink)")
1275 _(b" (actual capabilities: binary, symlink)")
1219 # i18n: "binary" is keyword
1276 # i18n: "binary" is keyword
1220 # i18n: this text is added automatically
1277 # i18n: this text is added automatically
1221 _(b" (actual capabilities: binary)")
1278 _(b" (actual capabilities: binary)")
1222 # i18n: "symlink" is keyword
1279 # i18n: "symlink" is keyword
1223 # i18n: this text is added automatically
1280 # i18n: this text is added automatically
1224 _(b" (actual capabilities: symlink)")
1281 _(b" (actual capabilities: symlink)")
1225
1282
1226
1283
1227 # load built-in merge tools explicitly to setup internalsdoc
1284 # load built-in merge tools explicitly to setup internalsdoc
1228 loadinternalmerge(None, None, internaltool)
1285 loadinternalmerge(None, None, internaltool)
1229
1286
1230 # tell hggettext to extract docstrings from these functions:
1287 # tell hggettext to extract docstrings from these functions:
1231 i18nfunctions = internals.values()
1288 i18nfunctions = internals.values()
@@ -1,531 +1,534 b''
1 # Copyright (C) 2004, 2005 Canonical Ltd
1 # Copyright (C) 2004, 2005 Canonical Ltd
2 #
2 #
3 # This program is free software; you can redistribute it and/or modify
3 # This program is free software; you can redistribute it and/or modify
4 # it under the terms of the GNU General Public License as published by
4 # it under the terms of the GNU General Public License as published by
5 # the Free Software Foundation; either version 2 of the License, or
5 # the Free Software Foundation; either version 2 of the License, or
6 # (at your option) any later version.
6 # (at your option) any later version.
7 #
7 #
8 # This program is distributed in the hope that it will be useful,
8 # This program is distributed in the hope that it will be useful,
9 # but WITHOUT ANY WARRANTY; without even the implied warranty of
9 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # GNU General Public License for more details.
11 # GNU General Public License for more details.
12 #
12 #
13 # You should have received a copy of the GNU General Public License
13 # You should have received a copy of the GNU General Public License
14 # along with this program; if not, see <http://www.gnu.org/licenses/>.
14 # along with this program; if not, see <http://www.gnu.org/licenses/>.
15
15
16 # mbp: "you know that thing where cvs gives you conflict markers?"
16 # mbp: "you know that thing where cvs gives you conflict markers?"
17 # s: "i hate that."
17 # s: "i hate that."
18
18
19
19
20 from .i18n import _
20 from .i18n import _
21 from . import (
21 from . import (
22 error,
22 error,
23 mdiff,
23 mdiff,
24 pycompat,
24 pycompat,
25 )
25 )
26 from .utils import stringutil
26 from .utils import stringutil
27
27
28
28
29 def intersect(ra, rb):
29 def intersect(ra, rb):
30 """Given two ranges return the range where they intersect or None.
30 """Given two ranges return the range where they intersect or None.
31
31
32 >>> intersect((0, 10), (0, 6))
32 >>> intersect((0, 10), (0, 6))
33 (0, 6)
33 (0, 6)
34 >>> intersect((0, 10), (5, 15))
34 >>> intersect((0, 10), (5, 15))
35 (5, 10)
35 (5, 10)
36 >>> intersect((0, 10), (10, 15))
36 >>> intersect((0, 10), (10, 15))
37 >>> intersect((0, 9), (10, 15))
37 >>> intersect((0, 9), (10, 15))
38 >>> intersect((0, 9), (7, 15))
38 >>> intersect((0, 9), (7, 15))
39 (7, 9)
39 (7, 9)
40 """
40 """
41 assert ra[0] <= ra[1]
41 assert ra[0] <= ra[1]
42 assert rb[0] <= rb[1]
42 assert rb[0] <= rb[1]
43
43
44 sa = max(ra[0], rb[0])
44 sa = max(ra[0], rb[0])
45 sb = min(ra[1], rb[1])
45 sb = min(ra[1], rb[1])
46 if sa < sb:
46 if sa < sb:
47 return sa, sb
47 return sa, sb
48 else:
48 else:
49 return None
49 return None
50
50
51
51
52 def compare_range(a, astart, aend, b, bstart, bend):
52 def compare_range(a, astart, aend, b, bstart, bend):
53 """Compare a[astart:aend] == b[bstart:bend], without slicing."""
53 """Compare a[astart:aend] == b[bstart:bend], without slicing."""
54 if (aend - astart) != (bend - bstart):
54 if (aend - astart) != (bend - bstart):
55 return False
55 return False
56 for ia, ib in zip(
56 for ia, ib in zip(
57 pycompat.xrange(astart, aend), pycompat.xrange(bstart, bend)
57 pycompat.xrange(astart, aend), pycompat.xrange(bstart, bend)
58 ):
58 ):
59 if a[ia] != b[ib]:
59 if a[ia] != b[ib]:
60 return False
60 return False
61 else:
61 else:
62 return True
62 return True
63
63
64
64
65 class Merge3Text:
65 class Merge3Text:
66 """3-way merge of texts.
66 """3-way merge of texts.
67
67
68 Given strings BASE, OTHER, THIS, tries to produce a combined text
68 Given strings BASE, OTHER, THIS, tries to produce a combined text
69 incorporating the changes from both BASE->OTHER and BASE->THIS."""
69 incorporating the changes from both BASE->OTHER and BASE->THIS."""
70
70
71 def __init__(self, basetext, atext, btext, base=None, a=None, b=None):
71 def __init__(self, basetext, atext, btext, base=None, a=None, b=None):
72 self.basetext = basetext
72 self.basetext = basetext
73 self.atext = atext
73 self.atext = atext
74 self.btext = btext
74 self.btext = btext
75 if base is None:
75 if base is None:
76 base = mdiff.splitnewlines(basetext)
76 base = mdiff.splitnewlines(basetext)
77 if a is None:
77 if a is None:
78 a = mdiff.splitnewlines(atext)
78 a = mdiff.splitnewlines(atext)
79 if b is None:
79 if b is None:
80 b = mdiff.splitnewlines(btext)
80 b = mdiff.splitnewlines(btext)
81 self.base = base
81 self.base = base
82 self.a = a
82 self.a = a
83 self.b = b
83 self.b = b
84
84
85 def merge_groups(self):
85 def merge_groups(self):
86 """Yield sequence of line groups. Each one is a tuple:
86 """Yield sequence of line groups. Each one is a tuple:
87
87
88 'unchanged', lines
88 'unchanged', lines
89 Lines unchanged from base
89 Lines unchanged from base
90
90
91 'a', lines
91 'a', lines
92 Lines taken from a
92 Lines taken from a
93
93
94 'same', lines
94 'same', lines
95 Lines taken from a (and equal to b)
95 Lines taken from a (and equal to b)
96
96
97 'b', lines
97 'b', lines
98 Lines taken from b
98 Lines taken from b
99
99
100 'conflict', (base_lines, a_lines, b_lines)
100 'conflict', (base_lines, a_lines, b_lines)
101 Lines from base were changed to either a or b and conflict.
101 Lines from base were changed to either a or b and conflict.
102 """
102 """
103 for t in self.merge_regions():
103 for t in self.merge_regions():
104 what = t[0]
104 what = t[0]
105 if what == b'unchanged':
105 if what == b'unchanged':
106 yield what, self.base[t[1] : t[2]]
106 yield what, self.base[t[1] : t[2]]
107 elif what == b'a' or what == b'same':
107 elif what == b'a' or what == b'same':
108 yield what, self.a[t[1] : t[2]]
108 yield what, self.a[t[1] : t[2]]
109 elif what == b'b':
109 elif what == b'b':
110 yield what, self.b[t[1] : t[2]]
110 yield what, self.b[t[1] : t[2]]
111 elif what == b'conflict':
111 elif what == b'conflict':
112 yield (
112 yield (
113 what,
113 what,
114 (
114 (
115 self.base[t[1] : t[2]],
115 self.base[t[1] : t[2]],
116 self.a[t[3] : t[4]],
116 self.a[t[3] : t[4]],
117 self.b[t[5] : t[6]],
117 self.b[t[5] : t[6]],
118 ),
118 ),
119 )
119 )
120 else:
120 else:
121 raise ValueError(what)
121 raise ValueError(what)
122
122
123 def merge_regions(self):
123 def merge_regions(self):
124 """Return sequences of matching and conflicting regions.
124 """Return sequences of matching and conflicting regions.
125
125
126 This returns tuples, where the first value says what kind we
126 This returns tuples, where the first value says what kind we
127 have:
127 have:
128
128
129 'unchanged', start, end
129 'unchanged', start, end
130 Take a region of base[start:end]
130 Take a region of base[start:end]
131
131
132 'same', astart, aend
132 'same', astart, aend
133 b and a are different from base but give the same result
133 b and a are different from base but give the same result
134
134
135 'a', start, end
135 'a', start, end
136 Non-clashing insertion from a[start:end]
136 Non-clashing insertion from a[start:end]
137
137
138 'conflict', zstart, zend, astart, aend, bstart, bend
138 'conflict', zstart, zend, astart, aend, bstart, bend
139 Conflict between a and b, with z as common ancestor
139 Conflict between a and b, with z as common ancestor
140
140
141 Method is as follows:
141 Method is as follows:
142
142
143 The two sequences align only on regions which match the base
143 The two sequences align only on regions which match the base
144 and both descendants. These are found by doing a two-way diff
144 and both descendants. These are found by doing a two-way diff
145 of each one against the base, and then finding the
145 of each one against the base, and then finding the
146 intersections between those regions. These "sync regions"
146 intersections between those regions. These "sync regions"
147 are by definition unchanged in both and easily dealt with.
147 are by definition unchanged in both and easily dealt with.
148
148
149 The regions in between can be in any of three cases:
149 The regions in between can be in any of three cases:
150 conflicted, or changed on only one side.
150 conflicted, or changed on only one side.
151 """
151 """
152
152
153 # section a[0:ia] has been disposed of, etc
153 # section a[0:ia] has been disposed of, etc
154 iz = ia = ib = 0
154 iz = ia = ib = 0
155
155
156 for region in self.find_sync_regions():
156 for region in self.find_sync_regions():
157 zmatch, zend, amatch, aend, bmatch, bend = region
157 zmatch, zend, amatch, aend, bmatch, bend = region
158 # print 'match base [%d:%d]' % (zmatch, zend)
158 # print 'match base [%d:%d]' % (zmatch, zend)
159
159
160 matchlen = zend - zmatch
160 matchlen = zend - zmatch
161 assert matchlen >= 0
161 assert matchlen >= 0
162 assert matchlen == (aend - amatch)
162 assert matchlen == (aend - amatch)
163 assert matchlen == (bend - bmatch)
163 assert matchlen == (bend - bmatch)
164
164
165 len_a = amatch - ia
165 len_a = amatch - ia
166 len_b = bmatch - ib
166 len_b = bmatch - ib
167 len_base = zmatch - iz
167 len_base = zmatch - iz
168 assert len_a >= 0
168 assert len_a >= 0
169 assert len_b >= 0
169 assert len_b >= 0
170 assert len_base >= 0
170 assert len_base >= 0
171
171
172 # print 'unmatched a=%d, b=%d' % (len_a, len_b)
172 # print 'unmatched a=%d, b=%d' % (len_a, len_b)
173
173
174 if len_a or len_b:
174 if len_a or len_b:
175 # try to avoid actually slicing the lists
175 # try to avoid actually slicing the lists
176 equal_a = compare_range(
176 equal_a = compare_range(
177 self.a, ia, amatch, self.base, iz, zmatch
177 self.a, ia, amatch, self.base, iz, zmatch
178 )
178 )
179 equal_b = compare_range(
179 equal_b = compare_range(
180 self.b, ib, bmatch, self.base, iz, zmatch
180 self.b, ib, bmatch, self.base, iz, zmatch
181 )
181 )
182 same = compare_range(self.a, ia, amatch, self.b, ib, bmatch)
182 same = compare_range(self.a, ia, amatch, self.b, ib, bmatch)
183
183
184 if same:
184 if same:
185 yield b'same', ia, amatch
185 yield b'same', ia, amatch
186 elif equal_a and not equal_b:
186 elif equal_a and not equal_b:
187 yield b'b', ib, bmatch
187 yield b'b', ib, bmatch
188 elif equal_b and not equal_a:
188 elif equal_b and not equal_a:
189 yield b'a', ia, amatch
189 yield b'a', ia, amatch
190 elif not equal_a and not equal_b:
190 elif not equal_a and not equal_b:
191 yield b'conflict', iz, zmatch, ia, amatch, ib, bmatch
191 yield b'conflict', iz, zmatch, ia, amatch, ib, bmatch
192 else:
192 else:
193 raise AssertionError(b"can't handle a=b=base but unmatched")
193 raise AssertionError(b"can't handle a=b=base but unmatched")
194
194
195 ia = amatch
195 ia = amatch
196 ib = bmatch
196 ib = bmatch
197 iz = zmatch
197 iz = zmatch
198
198
199 # if the same part of the base was deleted on both sides
199 # if the same part of the base was deleted on both sides
200 # that's OK, we can just skip it.
200 # that's OK, we can just skip it.
201
201
202 if matchlen > 0:
202 if matchlen > 0:
203 assert ia == amatch
203 assert ia == amatch
204 assert ib == bmatch
204 assert ib == bmatch
205 assert iz == zmatch
205 assert iz == zmatch
206
206
207 yield b'unchanged', zmatch, zend
207 yield b'unchanged', zmatch, zend
208 iz = zend
208 iz = zend
209 ia = aend
209 ia = aend
210 ib = bend
210 ib = bend
211
211
212 def find_sync_regions(self):
212 def find_sync_regions(self):
213 """Return a list of sync regions, where both descendants match the base.
213 """Return a list of sync regions, where both descendants match the base.
214
214
215 Generates a list of (base1, base2, a1, a2, b1, b2). There is
215 Generates a list of (base1, base2, a1, a2, b1, b2). There is
216 always a zero-length sync region at the end of all the files.
216 always a zero-length sync region at the end of all the files.
217 """
217 """
218
218
219 ia = ib = 0
219 ia = ib = 0
220 amatches = mdiff.get_matching_blocks(self.basetext, self.atext)
220 amatches = mdiff.get_matching_blocks(self.basetext, self.atext)
221 bmatches = mdiff.get_matching_blocks(self.basetext, self.btext)
221 bmatches = mdiff.get_matching_blocks(self.basetext, self.btext)
222 len_a = len(amatches)
222 len_a = len(amatches)
223 len_b = len(bmatches)
223 len_b = len(bmatches)
224
224
225 sl = []
225 sl = []
226
226
227 while ia < len_a and ib < len_b:
227 while ia < len_a and ib < len_b:
228 abase, amatch, alen = amatches[ia]
228 abase, amatch, alen = amatches[ia]
229 bbase, bmatch, blen = bmatches[ib]
229 bbase, bmatch, blen = bmatches[ib]
230
230
231 # there is an unconflicted block at i; how long does it
231 # there is an unconflicted block at i; how long does it
232 # extend? until whichever one ends earlier.
232 # extend? until whichever one ends earlier.
233 i = intersect((abase, abase + alen), (bbase, bbase + blen))
233 i = intersect((abase, abase + alen), (bbase, bbase + blen))
234 if i:
234 if i:
235 intbase = i[0]
235 intbase = i[0]
236 intend = i[1]
236 intend = i[1]
237 intlen = intend - intbase
237 intlen = intend - intbase
238
238
239 # found a match of base[i[0], i[1]]; this may be less than
239 # found a match of base[i[0], i[1]]; this may be less than
240 # the region that matches in either one
240 # the region that matches in either one
241 assert intlen <= alen
241 assert intlen <= alen
242 assert intlen <= blen
242 assert intlen <= blen
243 assert abase <= intbase
243 assert abase <= intbase
244 assert bbase <= intbase
244 assert bbase <= intbase
245
245
246 asub = amatch + (intbase - abase)
246 asub = amatch + (intbase - abase)
247 bsub = bmatch + (intbase - bbase)
247 bsub = bmatch + (intbase - bbase)
248 aend = asub + intlen
248 aend = asub + intlen
249 bend = bsub + intlen
249 bend = bsub + intlen
250
250
251 assert self.base[intbase:intend] == self.a[asub:aend], (
251 assert self.base[intbase:intend] == self.a[asub:aend], (
252 self.base[intbase:intend],
252 self.base[intbase:intend],
253 self.a[asub:aend],
253 self.a[asub:aend],
254 )
254 )
255
255
256 assert self.base[intbase:intend] == self.b[bsub:bend]
256 assert self.base[intbase:intend] == self.b[bsub:bend]
257
257
258 sl.append((intbase, intend, asub, aend, bsub, bend))
258 sl.append((intbase, intend, asub, aend, bsub, bend))
259
259
260 # advance whichever one ends first in the base text
260 # advance whichever one ends first in the base text
261 if (abase + alen) < (bbase + blen):
261 if (abase + alen) < (bbase + blen):
262 ia += 1
262 ia += 1
263 else:
263 else:
264 ib += 1
264 ib += 1
265
265
266 intbase = len(self.base)
266 intbase = len(self.base)
267 abase = len(self.a)
267 abase = len(self.a)
268 bbase = len(self.b)
268 bbase = len(self.b)
269 sl.append((intbase, intbase, abase, abase, bbase, bbase))
269 sl.append((intbase, intbase, abase, abase, bbase, bbase))
270
270
271 return sl
271 return sl
272
272
273
273
274 def _verifytext(input):
274 def _verifytext(input):
275 """verifies that text is non-binary (unless opts[text] is passed,
275 """verifies that text is non-binary (unless opts[text] is passed,
276 then we just warn)"""
276 then we just warn)"""
277 if stringutil.binary(input.text()):
277 if stringutil.binary(input.text()):
278 msg = _(b"%s looks like a binary file.") % input.fctx.path()
278 msg = _(b"%s looks like a binary file.") % input.fctx.path()
279 raise error.Abort(msg)
279 raise error.Abort(msg)
280
280
281
281
282 def _format_labels(*inputs):
282 def _format_labels(*inputs):
283 pad = max(len(input.label) if input.label else 0 for input in inputs)
283 pad = max(len(input.label) if input.label else 0 for input in inputs)
284 labels = []
284 labels = []
285 for input in inputs:
285 for input in inputs:
286 if input.label:
286 if input.label:
287 if input.label_detail:
287 if input.label_detail:
288 label = (
288 label = (
289 (input.label + b':').ljust(pad + 1)
289 (input.label + b':').ljust(pad + 1)
290 + b' '
290 + b' '
291 + input.label_detail
291 + input.label_detail
292 )
292 )
293 else:
293 else:
294 label = input.label
294 label = input.label
295 # 8 for the prefix of conflict marker lines (e.g. '<<<<<<< ')
295 # 8 for the prefix of conflict marker lines (e.g. '<<<<<<< ')
296 labels.append(stringutil.ellipsis(label, 80 - 8))
296 labels.append(stringutil.ellipsis(label, 80 - 8))
297 else:
297 else:
298 labels.append(None)
298 labels.append(None)
299 return labels
299 return labels
300
300
301
301
302 def _detect_newline(m3):
302 def _detect_newline(m3):
303 if len(m3.a) > 0:
303 if len(m3.a) > 0:
304 if m3.a[0].endswith(b'\r\n'):
304 if m3.a[0].endswith(b'\r\n'):
305 return b'\r\n'
305 return b'\r\n'
306 elif m3.a[0].endswith(b'\r'):
306 elif m3.a[0].endswith(b'\r'):
307 return b'\r'
307 return b'\r'
308 return b'\n'
308 return b'\n'
309
309
310
310
311 def _minimize(a_lines, b_lines):
311 def _minimize(a_lines, b_lines):
312 """Trim conflict regions of lines where A and B sides match.
312 """Trim conflict regions of lines where A and B sides match.
313
313
314 Lines where both A and B have made the same changes at the beginning
314 Lines where both A and B have made the same changes at the beginning
315 or the end of each merge region are eliminated from the conflict
315 or the end of each merge region are eliminated from the conflict
316 region and are instead considered the same.
316 region and are instead considered the same.
317 """
317 """
318 alen = len(a_lines)
318 alen = len(a_lines)
319 blen = len(b_lines)
319 blen = len(b_lines)
320
320
321 # find matches at the front
321 # find matches at the front
322 ii = 0
322 ii = 0
323 while ii < alen and ii < blen and a_lines[ii] == b_lines[ii]:
323 while ii < alen and ii < blen and a_lines[ii] == b_lines[ii]:
324 ii += 1
324 ii += 1
325 startmatches = ii
325 startmatches = ii
326
326
327 # find matches at the end
327 # find matches at the end
328 ii = 0
328 ii = 0
329 while ii < alen and ii < blen and a_lines[-ii - 1] == b_lines[-ii - 1]:
329 while ii < alen and ii < blen and a_lines[-ii - 1] == b_lines[-ii - 1]:
330 ii += 1
330 ii += 1
331 endmatches = ii
331 endmatches = ii
332
332
333 lines_before = a_lines[:startmatches]
333 lines_before = a_lines[:startmatches]
334 new_a_lines = a_lines[startmatches : alen - endmatches]
334 new_a_lines = a_lines[startmatches : alen - endmatches]
335 new_b_lines = b_lines[startmatches : blen - endmatches]
335 new_b_lines = b_lines[startmatches : blen - endmatches]
336 lines_after = a_lines[alen - endmatches :]
336 lines_after = a_lines[alen - endmatches :]
337 return lines_before, new_a_lines, new_b_lines, lines_after
337 return lines_before, new_a_lines, new_b_lines, lines_after
338
338
339
339
340 def render_minimized(
340 def render_minimized(
341 m3,
341 m3,
342 name_a=None,
342 name_a=None,
343 name_b=None,
343 name_b=None,
344 start_marker=b'<<<<<<<',
344 start_marker=b'<<<<<<<',
345 mid_marker=b'=======',
345 mid_marker=b'=======',
346 end_marker=b'>>>>>>>',
346 end_marker=b'>>>>>>>',
347 ):
347 ):
348 """Return merge in cvs-like form."""
348 """Return merge in cvs-like form."""
349 newline = _detect_newline(m3)
349 newline = _detect_newline(m3)
350 conflicts = False
350 conflicts = False
351 if name_a:
351 if name_a:
352 start_marker = start_marker + b' ' + name_a
352 start_marker = start_marker + b' ' + name_a
353 if name_b:
353 if name_b:
354 end_marker = end_marker + b' ' + name_b
354 end_marker = end_marker + b' ' + name_b
355 merge_groups = m3.merge_groups()
355 merge_groups = m3.merge_groups()
356 lines = []
356 lines = []
357 for what, group_lines in merge_groups:
357 for what, group_lines in merge_groups:
358 if what == b'conflict':
358 if what == b'conflict':
359 conflicts = True
359 conflicts = True
360 base_lines, a_lines, b_lines = group_lines
360 base_lines, a_lines, b_lines = group_lines
361 minimized = _minimize(a_lines, b_lines)
361 minimized = _minimize(a_lines, b_lines)
362 lines_before, a_lines, b_lines, lines_after = minimized
362 lines_before, a_lines, b_lines, lines_after = minimized
363 lines.extend(lines_before)
363 lines.extend(lines_before)
364 lines.append(start_marker + newline)
364 lines.append(start_marker + newline)
365 lines.extend(a_lines)
365 lines.extend(a_lines)
366 lines.append(mid_marker + newline)
366 lines.append(mid_marker + newline)
367 lines.extend(b_lines)
367 lines.extend(b_lines)
368 lines.append(end_marker + newline)
368 lines.append(end_marker + newline)
369 lines.extend(lines_after)
369 lines.extend(lines_after)
370 else:
370 else:
371 lines.extend(group_lines)
371 lines.extend(group_lines)
372 return lines, conflicts
372 return lines, conflicts
373
373
374
374
375 def render_merge3(m3, name_a, name_b, name_base):
375 def render_merge3(m3, name_a, name_b, name_base):
376 """Render conflicts as 3-way conflict markers."""
376 """Render conflicts as 3-way conflict markers."""
377 newline = _detect_newline(m3)
377 newline = _detect_newline(m3)
378 conflicts = False
378 conflicts = False
379 lines = []
379 lines = []
380 for what, group_lines in m3.merge_groups():
380 for what, group_lines in m3.merge_groups():
381 if what == b'conflict':
381 if what == b'conflict':
382 base_lines, a_lines, b_lines = group_lines
382 base_lines, a_lines, b_lines = group_lines
383 conflicts = True
383 conflicts = True
384 lines.append(b'<<<<<<< ' + name_a + newline)
384 lines.append(b'<<<<<<< ' + name_a + newline)
385 lines.extend(a_lines)
385 lines.extend(a_lines)
386 lines.append(b'||||||| ' + name_base + newline)
386 lines.append(b'||||||| ' + name_base + newline)
387 lines.extend(base_lines)
387 lines.extend(base_lines)
388 lines.append(b'=======' + newline)
388 lines.append(b'=======' + newline)
389 lines.extend(b_lines)
389 lines.extend(b_lines)
390 lines.append(b'>>>>>>> ' + name_b + newline)
390 lines.append(b'>>>>>>> ' + name_b + newline)
391 else:
391 else:
392 lines.extend(group_lines)
392 lines.extend(group_lines)
393 return lines, conflicts
393 return lines, conflicts
394
394
395
395
396 def render_mergediff(m3, name_a, name_b, name_base):
396 def render_mergediff(m3, name_a, name_b, name_base):
397 """Render conflicts as conflict markers with one snapshot and one diff."""
397 """Render conflicts as conflict markers with one snapshot and one diff."""
398 newline = _detect_newline(m3)
398 newline = _detect_newline(m3)
399 lines = []
399 lines = []
400 conflicts = False
400 conflicts = False
401 for what, group_lines in m3.merge_groups():
401 for what, group_lines in m3.merge_groups():
402 if what == b'conflict':
402 if what == b'conflict':
403 base_lines, a_lines, b_lines = group_lines
403 base_lines, a_lines, b_lines = group_lines
404 base_text = b''.join(base_lines)
404 base_text = b''.join(base_lines)
405 b_blocks = list(
405 b_blocks = list(
406 mdiff.allblocks(
406 mdiff.allblocks(
407 base_text,
407 base_text,
408 b''.join(b_lines),
408 b''.join(b_lines),
409 lines1=base_lines,
409 lines1=base_lines,
410 lines2=b_lines,
410 lines2=b_lines,
411 )
411 )
412 )
412 )
413 a_blocks = list(
413 a_blocks = list(
414 mdiff.allblocks(
414 mdiff.allblocks(
415 base_text,
415 base_text,
416 b''.join(a_lines),
416 b''.join(a_lines),
417 lines1=base_lines,
417 lines1=base_lines,
418 lines2=b_lines,
418 lines2=b_lines,
419 )
419 )
420 )
420 )
421
421
422 def matching_lines(blocks):
422 def matching_lines(blocks):
423 return sum(
423 return sum(
424 block[1] - block[0]
424 block[1] - block[0]
425 for block, kind in blocks
425 for block, kind in blocks
426 if kind == b'='
426 if kind == b'='
427 )
427 )
428
428
429 def diff_lines(blocks, lines1, lines2):
429 def diff_lines(blocks, lines1, lines2):
430 for block, kind in blocks:
430 for block, kind in blocks:
431 if kind == b'=':
431 if kind == b'=':
432 for line in lines1[block[0] : block[1]]:
432 for line in lines1[block[0] : block[1]]:
433 yield b' ' + line
433 yield b' ' + line
434 else:
434 else:
435 for line in lines1[block[0] : block[1]]:
435 for line in lines1[block[0] : block[1]]:
436 yield b'-' + line
436 yield b'-' + line
437 for line in lines2[block[2] : block[3]]:
437 for line in lines2[block[2] : block[3]]:
438 yield b'+' + line
438 yield b'+' + line
439
439
440 lines.append(b"<<<<<<<" + newline)
440 lines.append(b"<<<<<<<" + newline)
441 if matching_lines(a_blocks) < matching_lines(b_blocks):
441 if matching_lines(a_blocks) < matching_lines(b_blocks):
442 lines.append(b"======= " + name_a + newline)
442 lines.append(b"======= " + name_a + newline)
443 lines.extend(a_lines)
443 lines.extend(a_lines)
444 lines.append(b"------- " + name_base + newline)
444 lines.append(b"------- " + name_base + newline)
445 lines.append(b"+++++++ " + name_b + newline)
445 lines.append(b"+++++++ " + name_b + newline)
446 lines.extend(diff_lines(b_blocks, base_lines, b_lines))
446 lines.extend(diff_lines(b_blocks, base_lines, b_lines))
447 else:
447 else:
448 lines.append(b"------- " + name_base + newline)
448 lines.append(b"------- " + name_base + newline)
449 lines.append(b"+++++++ " + name_a + newline)
449 lines.append(b"+++++++ " + name_a + newline)
450 lines.extend(diff_lines(a_blocks, base_lines, a_lines))
450 lines.extend(diff_lines(a_blocks, base_lines, a_lines))
451 lines.append(b"======= " + name_b + newline)
451 lines.append(b"======= " + name_b + newline)
452 lines.extend(b_lines)
452 lines.extend(b_lines)
453 lines.append(b">>>>>>>" + newline)
453 lines.append(b">>>>>>>" + newline)
454 conflicts = True
454 conflicts = True
455 else:
455 else:
456 lines.extend(group_lines)
456 lines.extend(group_lines)
457 return lines, conflicts
457 return lines, conflicts
458
458
459
459
460 def _resolve(m3, sides):
460 def _resolve(m3, sides):
461 lines = []
461 lines = []
462 for what, group_lines in m3.merge_groups():
462 for what, group_lines in m3.merge_groups():
463 if what == b'conflict':
463 if what == b'conflict':
464 for side in sides:
464 for side in sides:
465 lines.extend(group_lines[side])
465 lines.extend(group_lines[side])
466 else:
466 else:
467 lines.extend(group_lines)
467 lines.extend(group_lines)
468 return lines
468 return lines
469
469
470
470
471 class MergeInput:
471 class MergeInput:
472 def __init__(self, fctx, label=None, label_detail=None):
472 def __init__(self, fctx, label=None, label_detail=None):
473 self.fctx = fctx
473 self.fctx = fctx
474 self.label = label
474 self.label = label
475 # If the "detail" part is set, then that is rendered after the label and
475 # If the "detail" part is set, then that is rendered after the label and
476 # separated by a ':'. The label is padded to make the ':' aligned among
476 # separated by a ':'. The label is padded to make the ':' aligned among
477 # all merge inputs.
477 # all merge inputs.
478 self.label_detail = label_detail
478 self.label_detail = label_detail
479 self._text = None
479 self._text = None
480
480
481 def text(self):
481 def text(self):
482 if self._text is None:
482 if self._text is None:
483 # Merges were always run in the working copy before, which means
483 # Merges were always run in the working copy before, which means
484 # they used decoded data, if the user defined any repository
484 # they used decoded data, if the user defined any repository
485 # filters.
485 # filters.
486 #
486 #
487 # Maintain that behavior today for BC, though perhaps in the future
487 # Maintain that behavior today for BC, though perhaps in the future
488 # it'd be worth considering whether merging encoded data (what the
488 # it'd be worth considering whether merging encoded data (what the
489 # repository usually sees) might be more useful.
489 # repository usually sees) might be more useful.
490 self._text = self.fctx.decodeddata()
490 self._text = self.fctx.decodeddata()
491 return self._text
491 return self._text
492
492
493 def set_text(self, text):
494 self._text = text
495
493
496
494 def simplemerge(
497 def simplemerge(
495 local,
498 local,
496 base,
499 base,
497 other,
500 other,
498 mode=b'merge',
501 mode=b'merge',
499 allow_binary=False,
502 allow_binary=False,
500 ):
503 ):
501 """Performs the simplemerge algorithm.
504 """Performs the simplemerge algorithm.
502
505
503 The merged result is written into `localctx`.
506 The merged result is written into `localctx`.
504 """
507 """
505
508
506 if not allow_binary:
509 if not allow_binary:
507 _verifytext(local)
510 _verifytext(local)
508 _verifytext(base)
511 _verifytext(base)
509 _verifytext(other)
512 _verifytext(other)
510
513
511 m3 = Merge3Text(base.text(), local.text(), other.text())
514 m3 = Merge3Text(base.text(), local.text(), other.text())
512 conflicts = False
515 conflicts = False
513 if mode == b'union':
516 if mode == b'union':
514 lines = _resolve(m3, (1, 2))
517 lines = _resolve(m3, (1, 2))
515 elif mode == b'local':
518 elif mode == b'local':
516 lines = _resolve(m3, (1,))
519 lines = _resolve(m3, (1,))
517 elif mode == b'other':
520 elif mode == b'other':
518 lines = _resolve(m3, (2,))
521 lines = _resolve(m3, (2,))
519 else:
522 else:
520 if mode == b'mergediff':
523 if mode == b'mergediff':
521 labels = _format_labels(local, other, base)
524 labels = _format_labels(local, other, base)
522 lines, conflicts = render_mergediff(m3, *labels)
525 lines, conflicts = render_mergediff(m3, *labels)
523 elif mode == b'merge3':
526 elif mode == b'merge3':
524 labels = _format_labels(local, other, base)
527 labels = _format_labels(local, other, base)
525 lines, conflicts = render_merge3(m3, *labels)
528 lines, conflicts = render_merge3(m3, *labels)
526 else:
529 else:
527 labels = _format_labels(local, other)
530 labels = _format_labels(local, other)
528 lines, conflicts = render_minimized(m3, *labels)
531 lines, conflicts = render_minimized(m3, *labels)
529
532
530 mergedtext = b''.join(lines)
533 mergedtext = b''.join(lines)
531 return mergedtext, conflicts
534 return mergedtext, conflicts
General Comments 0
You need to be logged in to leave comments. Login now