##// END OF EJS Templates
configitems: move rebase config into core...
Boris Feld -
r34832:44c4ed4a default
parent child Browse files
Show More
@@ -1,1683 +1,1669 b''
1 # rebase.py - rebasing feature for mercurial
1 # rebase.py - rebasing feature for mercurial
2 #
2 #
3 # Copyright 2008 Stefano Tortarolo <stefano.tortarolo at gmail dot com>
3 # Copyright 2008 Stefano Tortarolo <stefano.tortarolo at gmail dot 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 '''command to move sets of revisions to a different ancestor
8 '''command to move sets of revisions to a different ancestor
9
9
10 This extension lets you rebase changesets in an existing Mercurial
10 This extension lets you rebase changesets in an existing Mercurial
11 repository.
11 repository.
12
12
13 For more information:
13 For more information:
14 https://mercurial-scm.org/wiki/RebaseExtension
14 https://mercurial-scm.org/wiki/RebaseExtension
15 '''
15 '''
16
16
17 from __future__ import absolute_import
17 from __future__ import absolute_import
18
18
19 import errno
19 import errno
20 import os
20 import os
21
21
22 from mercurial.i18n import _
22 from mercurial.i18n import _
23 from mercurial.node import (
23 from mercurial.node import (
24 nullid,
24 nullid,
25 nullrev,
25 nullrev,
26 short,
26 short,
27 )
27 )
28 from mercurial import (
28 from mercurial import (
29 bookmarks,
29 bookmarks,
30 cmdutil,
30 cmdutil,
31 commands,
31 commands,
32 copies,
32 copies,
33 destutil,
33 destutil,
34 dirstateguard,
34 dirstateguard,
35 error,
35 error,
36 extensions,
36 extensions,
37 hg,
37 hg,
38 lock,
38 lock,
39 merge as mergemod,
39 merge as mergemod,
40 mergeutil,
40 mergeutil,
41 obsolete,
41 obsolete,
42 obsutil,
42 obsutil,
43 patch,
43 patch,
44 phases,
44 phases,
45 registrar,
45 registrar,
46 repair,
46 repair,
47 revset,
47 revset,
48 revsetlang,
48 revsetlang,
49 scmutil,
49 scmutil,
50 smartset,
50 smartset,
51 util,
51 util,
52 )
52 )
53
53
54 release = lock.release
54 release = lock.release
55 templateopts = cmdutil.templateopts
55 templateopts = cmdutil.templateopts
56
56
57 # The following constants are used throughout the rebase module. The ordering of
57 # The following constants are used throughout the rebase module. The ordering of
58 # their values must be maintained.
58 # their values must be maintained.
59
59
60 # Indicates that a revision needs to be rebased
60 # Indicates that a revision needs to be rebased
61 revtodo = -1
61 revtodo = -1
62 revtodostr = '-1'
62 revtodostr = '-1'
63
63
64 # legacy revstates no longer needed in current code
64 # legacy revstates no longer needed in current code
65 # -2: nullmerge, -3: revignored, -4: revprecursor, -5: revpruned
65 # -2: nullmerge, -3: revignored, -4: revprecursor, -5: revpruned
66 legacystates = {'-2', '-3', '-4', '-5'}
66 legacystates = {'-2', '-3', '-4', '-5'}
67
67
68 cmdtable = {}
68 cmdtable = {}
69 command = registrar.command(cmdtable)
69 command = registrar.command(cmdtable)
70 # Note for extension authors: ONLY specify testedwith = 'ships-with-hg-core' for
70 # Note for extension authors: ONLY specify testedwith = 'ships-with-hg-core' for
71 # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should
71 # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should
72 # be specifying the version(s) of Mercurial they are tested with, or
72 # be specifying the version(s) of Mercurial they are tested with, or
73 # leave the attribute unspecified.
73 # leave the attribute unspecified.
74 testedwith = 'ships-with-hg-core'
74 testedwith = 'ships-with-hg-core'
75
75
76 configtable = {}
77 configitem = registrar.configitem(configtable)
78
79 configitem('commands', 'rebase.requiredest',
80 default=False,
81 )
82
83 configitem('experimental', 'rebaseskipobsolete',
84 default=True,
85 )
86 configitem('rebase', 'singletransaction',
87 default=False,
88 )
89
90 def _nothingtorebase():
76 def _nothingtorebase():
91 return 1
77 return 1
92
78
93 def _savegraft(ctx, extra):
79 def _savegraft(ctx, extra):
94 s = ctx.extra().get('source', None)
80 s = ctx.extra().get('source', None)
95 if s is not None:
81 if s is not None:
96 extra['source'] = s
82 extra['source'] = s
97 s = ctx.extra().get('intermediate-source', None)
83 s = ctx.extra().get('intermediate-source', None)
98 if s is not None:
84 if s is not None:
99 extra['intermediate-source'] = s
85 extra['intermediate-source'] = s
100
86
101 def _savebranch(ctx, extra):
87 def _savebranch(ctx, extra):
102 extra['branch'] = ctx.branch()
88 extra['branch'] = ctx.branch()
103
89
104 def _makeextrafn(copiers):
90 def _makeextrafn(copiers):
105 """make an extrafn out of the given copy-functions.
91 """make an extrafn out of the given copy-functions.
106
92
107 A copy function takes a context and an extra dict, and mutates the
93 A copy function takes a context and an extra dict, and mutates the
108 extra dict as needed based on the given context.
94 extra dict as needed based on the given context.
109 """
95 """
110 def extrafn(ctx, extra):
96 def extrafn(ctx, extra):
111 for c in copiers:
97 for c in copiers:
112 c(ctx, extra)
98 c(ctx, extra)
113 return extrafn
99 return extrafn
114
100
115 def _destrebase(repo, sourceset, destspace=None):
101 def _destrebase(repo, sourceset, destspace=None):
116 """small wrapper around destmerge to pass the right extra args
102 """small wrapper around destmerge to pass the right extra args
117
103
118 Please wrap destutil.destmerge instead."""
104 Please wrap destutil.destmerge instead."""
119 return destutil.destmerge(repo, action='rebase', sourceset=sourceset,
105 return destutil.destmerge(repo, action='rebase', sourceset=sourceset,
120 onheadcheck=False, destspace=destspace)
106 onheadcheck=False, destspace=destspace)
121
107
122 revsetpredicate = registrar.revsetpredicate()
108 revsetpredicate = registrar.revsetpredicate()
123
109
124 @revsetpredicate('_destrebase')
110 @revsetpredicate('_destrebase')
125 def _revsetdestrebase(repo, subset, x):
111 def _revsetdestrebase(repo, subset, x):
126 # ``_rebasedefaultdest()``
112 # ``_rebasedefaultdest()``
127
113
128 # default destination for rebase.
114 # default destination for rebase.
129 # # XXX: Currently private because I expect the signature to change.
115 # # XXX: Currently private because I expect the signature to change.
130 # # XXX: - bailing out in case of ambiguity vs returning all data.
116 # # XXX: - bailing out in case of ambiguity vs returning all data.
131 # i18n: "_rebasedefaultdest" is a keyword
117 # i18n: "_rebasedefaultdest" is a keyword
132 sourceset = None
118 sourceset = None
133 if x is not None:
119 if x is not None:
134 sourceset = revset.getset(repo, smartset.fullreposet(repo), x)
120 sourceset = revset.getset(repo, smartset.fullreposet(repo), x)
135 return subset & smartset.baseset([_destrebase(repo, sourceset)])
121 return subset & smartset.baseset([_destrebase(repo, sourceset)])
136
122
137 def _ctxdesc(ctx):
123 def _ctxdesc(ctx):
138 """short description for a context"""
124 """short description for a context"""
139 desc = '%d:%s "%s"' % (ctx.rev(), ctx,
125 desc = '%d:%s "%s"' % (ctx.rev(), ctx,
140 ctx.description().split('\n', 1)[0])
126 ctx.description().split('\n', 1)[0])
141 repo = ctx.repo()
127 repo = ctx.repo()
142 names = []
128 names = []
143 for nsname, ns in repo.names.iteritems():
129 for nsname, ns in repo.names.iteritems():
144 if nsname == 'branches':
130 if nsname == 'branches':
145 continue
131 continue
146 names.extend(ns.names(repo, ctx.node()))
132 names.extend(ns.names(repo, ctx.node()))
147 if names:
133 if names:
148 desc += ' (%s)' % ' '.join(names)
134 desc += ' (%s)' % ' '.join(names)
149 return desc
135 return desc
150
136
151 class rebaseruntime(object):
137 class rebaseruntime(object):
152 """This class is a container for rebase runtime state"""
138 """This class is a container for rebase runtime state"""
153 def __init__(self, repo, ui, opts=None):
139 def __init__(self, repo, ui, opts=None):
154 if opts is None:
140 if opts is None:
155 opts = {}
141 opts = {}
156
142
157 # prepared: whether we have rebasestate prepared or not. Currently it
143 # prepared: whether we have rebasestate prepared or not. Currently it
158 # decides whether "self.repo" is unfiltered or not.
144 # decides whether "self.repo" is unfiltered or not.
159 # The rebasestate has explicit hash to hash instructions not depending
145 # The rebasestate has explicit hash to hash instructions not depending
160 # on visibility. If rebasestate exists (in-memory or on-disk), use
146 # on visibility. If rebasestate exists (in-memory or on-disk), use
161 # unfiltered repo to avoid visibility issues.
147 # unfiltered repo to avoid visibility issues.
162 # Before knowing rebasestate (i.e. when starting a new rebase (not
148 # Before knowing rebasestate (i.e. when starting a new rebase (not
163 # --continue or --abort)), the original repo should be used so
149 # --continue or --abort)), the original repo should be used so
164 # visibility-dependent revsets are correct.
150 # visibility-dependent revsets are correct.
165 self.prepared = False
151 self.prepared = False
166 self._repo = repo
152 self._repo = repo
167
153
168 self.ui = ui
154 self.ui = ui
169 self.opts = opts
155 self.opts = opts
170 self.originalwd = None
156 self.originalwd = None
171 self.external = nullrev
157 self.external = nullrev
172 # Mapping between the old revision id and either what is the new rebased
158 # Mapping between the old revision id and either what is the new rebased
173 # revision or what needs to be done with the old revision. The state
159 # revision or what needs to be done with the old revision. The state
174 # dict will be what contains most of the rebase progress state.
160 # dict will be what contains most of the rebase progress state.
175 self.state = {}
161 self.state = {}
176 self.activebookmark = None
162 self.activebookmark = None
177 self.destmap = {}
163 self.destmap = {}
178 self.skipped = set()
164 self.skipped = set()
179
165
180 self.collapsef = opts.get('collapse', False)
166 self.collapsef = opts.get('collapse', False)
181 self.collapsemsg = cmdutil.logmessage(ui, opts)
167 self.collapsemsg = cmdutil.logmessage(ui, opts)
182 self.date = opts.get('date', None)
168 self.date = opts.get('date', None)
183
169
184 e = opts.get('extrafn') # internal, used by e.g. hgsubversion
170 e = opts.get('extrafn') # internal, used by e.g. hgsubversion
185 self.extrafns = [_savegraft]
171 self.extrafns = [_savegraft]
186 if e:
172 if e:
187 self.extrafns = [e]
173 self.extrafns = [e]
188
174
189 self.keepf = opts.get('keep', False)
175 self.keepf = opts.get('keep', False)
190 self.keepbranchesf = opts.get('keepbranches', False)
176 self.keepbranchesf = opts.get('keepbranches', False)
191 # keepopen is not meant for use on the command line, but by
177 # keepopen is not meant for use on the command line, but by
192 # other extensions
178 # other extensions
193 self.keepopen = opts.get('keepopen', False)
179 self.keepopen = opts.get('keepopen', False)
194 self.obsoletenotrebased = {}
180 self.obsoletenotrebased = {}
195
181
196 @property
182 @property
197 def repo(self):
183 def repo(self):
198 if self.prepared:
184 if self.prepared:
199 return self._repo.unfiltered()
185 return self._repo.unfiltered()
200 else:
186 else:
201 return self._repo
187 return self._repo
202
188
203 def storestatus(self, tr=None):
189 def storestatus(self, tr=None):
204 """Store the current status to allow recovery"""
190 """Store the current status to allow recovery"""
205 if tr:
191 if tr:
206 tr.addfilegenerator('rebasestate', ('rebasestate',),
192 tr.addfilegenerator('rebasestate', ('rebasestate',),
207 self._writestatus, location='plain')
193 self._writestatus, location='plain')
208 else:
194 else:
209 with self.repo.vfs("rebasestate", "w") as f:
195 with self.repo.vfs("rebasestate", "w") as f:
210 self._writestatus(f)
196 self._writestatus(f)
211
197
212 def _writestatus(self, f):
198 def _writestatus(self, f):
213 repo = self.repo
199 repo = self.repo
214 assert repo.filtername is None
200 assert repo.filtername is None
215 f.write(repo[self.originalwd].hex() + '\n')
201 f.write(repo[self.originalwd].hex() + '\n')
216 # was "dest". we now write dest per src root below.
202 # was "dest". we now write dest per src root below.
217 f.write('\n')
203 f.write('\n')
218 f.write(repo[self.external].hex() + '\n')
204 f.write(repo[self.external].hex() + '\n')
219 f.write('%d\n' % int(self.collapsef))
205 f.write('%d\n' % int(self.collapsef))
220 f.write('%d\n' % int(self.keepf))
206 f.write('%d\n' % int(self.keepf))
221 f.write('%d\n' % int(self.keepbranchesf))
207 f.write('%d\n' % int(self.keepbranchesf))
222 f.write('%s\n' % (self.activebookmark or ''))
208 f.write('%s\n' % (self.activebookmark or ''))
223 destmap = self.destmap
209 destmap = self.destmap
224 for d, v in self.state.iteritems():
210 for d, v in self.state.iteritems():
225 oldrev = repo[d].hex()
211 oldrev = repo[d].hex()
226 if v >= 0:
212 if v >= 0:
227 newrev = repo[v].hex()
213 newrev = repo[v].hex()
228 else:
214 else:
229 newrev = v
215 newrev = v
230 destnode = repo[destmap[d]].hex()
216 destnode = repo[destmap[d]].hex()
231 f.write("%s:%s:%s\n" % (oldrev, newrev, destnode))
217 f.write("%s:%s:%s\n" % (oldrev, newrev, destnode))
232 repo.ui.debug('rebase status stored\n')
218 repo.ui.debug('rebase status stored\n')
233
219
234 def restorestatus(self):
220 def restorestatus(self):
235 """Restore a previously stored status"""
221 """Restore a previously stored status"""
236 self.prepared = True
222 self.prepared = True
237 repo = self.repo
223 repo = self.repo
238 assert repo.filtername is None
224 assert repo.filtername is None
239 keepbranches = None
225 keepbranches = None
240 legacydest = None
226 legacydest = None
241 collapse = False
227 collapse = False
242 external = nullrev
228 external = nullrev
243 activebookmark = None
229 activebookmark = None
244 state = {}
230 state = {}
245 destmap = {}
231 destmap = {}
246
232
247 try:
233 try:
248 f = repo.vfs("rebasestate")
234 f = repo.vfs("rebasestate")
249 for i, l in enumerate(f.read().splitlines()):
235 for i, l in enumerate(f.read().splitlines()):
250 if i == 0:
236 if i == 0:
251 originalwd = repo[l].rev()
237 originalwd = repo[l].rev()
252 elif i == 1:
238 elif i == 1:
253 # this line should be empty in newer version. but legacy
239 # this line should be empty in newer version. but legacy
254 # clients may still use it
240 # clients may still use it
255 if l:
241 if l:
256 legacydest = repo[l].rev()
242 legacydest = repo[l].rev()
257 elif i == 2:
243 elif i == 2:
258 external = repo[l].rev()
244 external = repo[l].rev()
259 elif i == 3:
245 elif i == 3:
260 collapse = bool(int(l))
246 collapse = bool(int(l))
261 elif i == 4:
247 elif i == 4:
262 keep = bool(int(l))
248 keep = bool(int(l))
263 elif i == 5:
249 elif i == 5:
264 keepbranches = bool(int(l))
250 keepbranches = bool(int(l))
265 elif i == 6 and not (len(l) == 81 and ':' in l):
251 elif i == 6 and not (len(l) == 81 and ':' in l):
266 # line 6 is a recent addition, so for backwards
252 # line 6 is a recent addition, so for backwards
267 # compatibility check that the line doesn't look like the
253 # compatibility check that the line doesn't look like the
268 # oldrev:newrev lines
254 # oldrev:newrev lines
269 activebookmark = l
255 activebookmark = l
270 else:
256 else:
271 args = l.split(':')
257 args = l.split(':')
272 oldrev = args[0]
258 oldrev = args[0]
273 newrev = args[1]
259 newrev = args[1]
274 if newrev in legacystates:
260 if newrev in legacystates:
275 continue
261 continue
276 if len(args) > 2:
262 if len(args) > 2:
277 destnode = args[2]
263 destnode = args[2]
278 else:
264 else:
279 destnode = legacydest
265 destnode = legacydest
280 destmap[repo[oldrev].rev()] = repo[destnode].rev()
266 destmap[repo[oldrev].rev()] = repo[destnode].rev()
281 if newrev in (nullid, revtodostr):
267 if newrev in (nullid, revtodostr):
282 state[repo[oldrev].rev()] = revtodo
268 state[repo[oldrev].rev()] = revtodo
283 # Legacy compat special case
269 # Legacy compat special case
284 else:
270 else:
285 state[repo[oldrev].rev()] = repo[newrev].rev()
271 state[repo[oldrev].rev()] = repo[newrev].rev()
286
272
287 except IOError as err:
273 except IOError as err:
288 if err.errno != errno.ENOENT:
274 if err.errno != errno.ENOENT:
289 raise
275 raise
290 cmdutil.wrongtooltocontinue(repo, _('rebase'))
276 cmdutil.wrongtooltocontinue(repo, _('rebase'))
291
277
292 if keepbranches is None:
278 if keepbranches is None:
293 raise error.Abort(_('.hg/rebasestate is incomplete'))
279 raise error.Abort(_('.hg/rebasestate is incomplete'))
294
280
295 skipped = set()
281 skipped = set()
296 # recompute the set of skipped revs
282 # recompute the set of skipped revs
297 if not collapse:
283 if not collapse:
298 seen = set(destmap.values())
284 seen = set(destmap.values())
299 for old, new in sorted(state.items()):
285 for old, new in sorted(state.items()):
300 if new != revtodo and new in seen:
286 if new != revtodo and new in seen:
301 skipped.add(old)
287 skipped.add(old)
302 seen.add(new)
288 seen.add(new)
303 repo.ui.debug('computed skipped revs: %s\n' %
289 repo.ui.debug('computed skipped revs: %s\n' %
304 (' '.join(str(r) for r in sorted(skipped)) or None))
290 (' '.join(str(r) for r in sorted(skipped)) or None))
305 repo.ui.debug('rebase status resumed\n')
291 repo.ui.debug('rebase status resumed\n')
306
292
307 self.originalwd = originalwd
293 self.originalwd = originalwd
308 self.destmap = destmap
294 self.destmap = destmap
309 self.state = state
295 self.state = state
310 self.skipped = skipped
296 self.skipped = skipped
311 self.collapsef = collapse
297 self.collapsef = collapse
312 self.keepf = keep
298 self.keepf = keep
313 self.keepbranchesf = keepbranches
299 self.keepbranchesf = keepbranches
314 self.external = external
300 self.external = external
315 self.activebookmark = activebookmark
301 self.activebookmark = activebookmark
316
302
317 def _handleskippingobsolete(self, obsoleterevs, destmap):
303 def _handleskippingobsolete(self, obsoleterevs, destmap):
318 """Compute structures necessary for skipping obsolete revisions
304 """Compute structures necessary for skipping obsolete revisions
319
305
320 obsoleterevs: iterable of all obsolete revisions in rebaseset
306 obsoleterevs: iterable of all obsolete revisions in rebaseset
321 destmap: {srcrev: destrev} destination revisions
307 destmap: {srcrev: destrev} destination revisions
322 """
308 """
323 self.obsoletenotrebased = {}
309 self.obsoletenotrebased = {}
324 if not self.ui.configbool('experimental', 'rebaseskipobsolete'):
310 if not self.ui.configbool('experimental', 'rebaseskipobsolete'):
325 return
311 return
326 obsoleteset = set(obsoleterevs)
312 obsoleteset = set(obsoleterevs)
327 self.obsoletenotrebased = _computeobsoletenotrebased(self.repo,
313 self.obsoletenotrebased = _computeobsoletenotrebased(self.repo,
328 obsoleteset, destmap)
314 obsoleteset, destmap)
329 skippedset = set(self.obsoletenotrebased)
315 skippedset = set(self.obsoletenotrebased)
330 _checkobsrebase(self.repo, self.ui, obsoleteset, skippedset)
316 _checkobsrebase(self.repo, self.ui, obsoleteset, skippedset)
331
317
332 def _prepareabortorcontinue(self, isabort):
318 def _prepareabortorcontinue(self, isabort):
333 try:
319 try:
334 self.restorestatus()
320 self.restorestatus()
335 self.collapsemsg = restorecollapsemsg(self.repo, isabort)
321 self.collapsemsg = restorecollapsemsg(self.repo, isabort)
336 except error.RepoLookupError:
322 except error.RepoLookupError:
337 if isabort:
323 if isabort:
338 clearstatus(self.repo)
324 clearstatus(self.repo)
339 clearcollapsemsg(self.repo)
325 clearcollapsemsg(self.repo)
340 self.repo.ui.warn(_('rebase aborted (no revision is removed,'
326 self.repo.ui.warn(_('rebase aborted (no revision is removed,'
341 ' only broken state is cleared)\n'))
327 ' only broken state is cleared)\n'))
342 return 0
328 return 0
343 else:
329 else:
344 msg = _('cannot continue inconsistent rebase')
330 msg = _('cannot continue inconsistent rebase')
345 hint = _('use "hg rebase --abort" to clear broken state')
331 hint = _('use "hg rebase --abort" to clear broken state')
346 raise error.Abort(msg, hint=hint)
332 raise error.Abort(msg, hint=hint)
347 if isabort:
333 if isabort:
348 return abort(self.repo, self.originalwd, self.destmap,
334 return abort(self.repo, self.originalwd, self.destmap,
349 self.state, activebookmark=self.activebookmark)
335 self.state, activebookmark=self.activebookmark)
350
336
351 def _preparenewrebase(self, destmap):
337 def _preparenewrebase(self, destmap):
352 if not destmap:
338 if not destmap:
353 return _nothingtorebase()
339 return _nothingtorebase()
354
340
355 rebaseset = destmap.keys()
341 rebaseset = destmap.keys()
356 allowunstable = obsolete.isenabled(self.repo, obsolete.allowunstableopt)
342 allowunstable = obsolete.isenabled(self.repo, obsolete.allowunstableopt)
357 if (not (self.keepf or allowunstable)
343 if (not (self.keepf or allowunstable)
358 and self.repo.revs('first(children(%ld) - %ld)',
344 and self.repo.revs('first(children(%ld) - %ld)',
359 rebaseset, rebaseset)):
345 rebaseset, rebaseset)):
360 raise error.Abort(
346 raise error.Abort(
361 _("can't remove original changesets with"
347 _("can't remove original changesets with"
362 " unrebased descendants"),
348 " unrebased descendants"),
363 hint=_('use --keep to keep original changesets'))
349 hint=_('use --keep to keep original changesets'))
364
350
365 result = buildstate(self.repo, destmap, self.collapsef)
351 result = buildstate(self.repo, destmap, self.collapsef)
366
352
367 if not result:
353 if not result:
368 # Empty state built, nothing to rebase
354 # Empty state built, nothing to rebase
369 self.ui.status(_('nothing to rebase\n'))
355 self.ui.status(_('nothing to rebase\n'))
370 return _nothingtorebase()
356 return _nothingtorebase()
371
357
372 for root in self.repo.set('roots(%ld)', rebaseset):
358 for root in self.repo.set('roots(%ld)', rebaseset):
373 if not self.keepf and not root.mutable():
359 if not self.keepf and not root.mutable():
374 raise error.Abort(_("can't rebase public changeset %s")
360 raise error.Abort(_("can't rebase public changeset %s")
375 % root,
361 % root,
376 hint=_("see 'hg help phases' for details"))
362 hint=_("see 'hg help phases' for details"))
377
363
378 (self.originalwd, self.destmap, self.state) = result
364 (self.originalwd, self.destmap, self.state) = result
379 if self.collapsef:
365 if self.collapsef:
380 dests = set(self.destmap.values())
366 dests = set(self.destmap.values())
381 if len(dests) != 1:
367 if len(dests) != 1:
382 raise error.Abort(
368 raise error.Abort(
383 _('--collapse does not work with multiple destinations'))
369 _('--collapse does not work with multiple destinations'))
384 destrev = next(iter(dests))
370 destrev = next(iter(dests))
385 destancestors = self.repo.changelog.ancestors([destrev],
371 destancestors = self.repo.changelog.ancestors([destrev],
386 inclusive=True)
372 inclusive=True)
387 self.external = externalparent(self.repo, self.state, destancestors)
373 self.external = externalparent(self.repo, self.state, destancestors)
388
374
389 for destrev in sorted(set(destmap.values())):
375 for destrev in sorted(set(destmap.values())):
390 dest = self.repo[destrev]
376 dest = self.repo[destrev]
391 if dest.closesbranch() and not self.keepbranchesf:
377 if dest.closesbranch() and not self.keepbranchesf:
392 self.ui.status(_('reopening closed branch head %s\n') % dest)
378 self.ui.status(_('reopening closed branch head %s\n') % dest)
393
379
394 self.prepared = True
380 self.prepared = True
395
381
396 def _performrebase(self, tr):
382 def _performrebase(self, tr):
397 repo, ui = self.repo, self.ui
383 repo, ui = self.repo, self.ui
398 if self.keepbranchesf:
384 if self.keepbranchesf:
399 # insert _savebranch at the start of extrafns so if
385 # insert _savebranch at the start of extrafns so if
400 # there's a user-provided extrafn it can clobber branch if
386 # there's a user-provided extrafn it can clobber branch if
401 # desired
387 # desired
402 self.extrafns.insert(0, _savebranch)
388 self.extrafns.insert(0, _savebranch)
403 if self.collapsef:
389 if self.collapsef:
404 branches = set()
390 branches = set()
405 for rev in self.state:
391 for rev in self.state:
406 branches.add(repo[rev].branch())
392 branches.add(repo[rev].branch())
407 if len(branches) > 1:
393 if len(branches) > 1:
408 raise error.Abort(_('cannot collapse multiple named '
394 raise error.Abort(_('cannot collapse multiple named '
409 'branches'))
395 'branches'))
410
396
411 # Calculate self.obsoletenotrebased
397 # Calculate self.obsoletenotrebased
412 obsrevs = _filterobsoleterevs(self.repo, self.state)
398 obsrevs = _filterobsoleterevs(self.repo, self.state)
413 self._handleskippingobsolete(obsrevs, self.destmap)
399 self._handleskippingobsolete(obsrevs, self.destmap)
414
400
415 # Keep track of the active bookmarks in order to reset them later
401 # Keep track of the active bookmarks in order to reset them later
416 self.activebookmark = self.activebookmark or repo._activebookmark
402 self.activebookmark = self.activebookmark or repo._activebookmark
417 if self.activebookmark:
403 if self.activebookmark:
418 bookmarks.deactivate(repo)
404 bookmarks.deactivate(repo)
419
405
420 # Store the state before we begin so users can run 'hg rebase --abort'
406 # Store the state before we begin so users can run 'hg rebase --abort'
421 # if we fail before the transaction closes.
407 # if we fail before the transaction closes.
422 self.storestatus()
408 self.storestatus()
423
409
424 cands = [k for k, v in self.state.iteritems() if v == revtodo]
410 cands = [k for k, v in self.state.iteritems() if v == revtodo]
425 total = len(cands)
411 total = len(cands)
426 pos = 0
412 pos = 0
427 for subset in sortsource(self.destmap):
413 for subset in sortsource(self.destmap):
428 pos = self._performrebasesubset(tr, subset, pos, total)
414 pos = self._performrebasesubset(tr, subset, pos, total)
429 ui.progress(_('rebasing'), None)
415 ui.progress(_('rebasing'), None)
430 ui.note(_('rebase merging completed\n'))
416 ui.note(_('rebase merging completed\n'))
431
417
432 def _performrebasesubset(self, tr, subset, pos, total):
418 def _performrebasesubset(self, tr, subset, pos, total):
433 repo, ui, opts = self.repo, self.ui, self.opts
419 repo, ui, opts = self.repo, self.ui, self.opts
434 sortedrevs = repo.revs('sort(%ld, -topo)', subset)
420 sortedrevs = repo.revs('sort(%ld, -topo)', subset)
435 for rev in sortedrevs:
421 for rev in sortedrevs:
436 dest = self.destmap[rev]
422 dest = self.destmap[rev]
437 ctx = repo[rev]
423 ctx = repo[rev]
438 desc = _ctxdesc(ctx)
424 desc = _ctxdesc(ctx)
439 if self.state[rev] == rev:
425 if self.state[rev] == rev:
440 ui.status(_('already rebased %s\n') % desc)
426 ui.status(_('already rebased %s\n') % desc)
441 elif rev in self.obsoletenotrebased:
427 elif rev in self.obsoletenotrebased:
442 succ = self.obsoletenotrebased[rev]
428 succ = self.obsoletenotrebased[rev]
443 if succ is None:
429 if succ is None:
444 msg = _('note: not rebasing %s, it has no '
430 msg = _('note: not rebasing %s, it has no '
445 'successor\n') % desc
431 'successor\n') % desc
446 else:
432 else:
447 succdesc = _ctxdesc(repo[succ])
433 succdesc = _ctxdesc(repo[succ])
448 msg = (_('note: not rebasing %s, already in '
434 msg = (_('note: not rebasing %s, already in '
449 'destination as %s\n') % (desc, succdesc))
435 'destination as %s\n') % (desc, succdesc))
450 repo.ui.status(msg)
436 repo.ui.status(msg)
451 # Make clearrebased aware state[rev] is not a true successor
437 # Make clearrebased aware state[rev] is not a true successor
452 self.skipped.add(rev)
438 self.skipped.add(rev)
453 # Record rev as moved to its desired destination in self.state.
439 # Record rev as moved to its desired destination in self.state.
454 # This helps bookmark and working parent movement.
440 # This helps bookmark and working parent movement.
455 dest = max(adjustdest(repo, rev, self.destmap, self.state,
441 dest = max(adjustdest(repo, rev, self.destmap, self.state,
456 self.skipped))
442 self.skipped))
457 self.state[rev] = dest
443 self.state[rev] = dest
458 elif self.state[rev] == revtodo:
444 elif self.state[rev] == revtodo:
459 pos += 1
445 pos += 1
460 ui.status(_('rebasing %s\n') % desc)
446 ui.status(_('rebasing %s\n') % desc)
461 ui.progress(_("rebasing"), pos, ("%d:%s" % (rev, ctx)),
447 ui.progress(_("rebasing"), pos, ("%d:%s" % (rev, ctx)),
462 _('changesets'), total)
448 _('changesets'), total)
463 p1, p2, base = defineparents(repo, rev, self.destmap,
449 p1, p2, base = defineparents(repo, rev, self.destmap,
464 self.state, self.skipped,
450 self.state, self.skipped,
465 self.obsoletenotrebased)
451 self.obsoletenotrebased)
466 self.storestatus(tr=tr)
452 self.storestatus(tr=tr)
467 storecollapsemsg(repo, self.collapsemsg)
453 storecollapsemsg(repo, self.collapsemsg)
468 if len(repo[None].parents()) == 2:
454 if len(repo[None].parents()) == 2:
469 repo.ui.debug('resuming interrupted rebase\n')
455 repo.ui.debug('resuming interrupted rebase\n')
470 else:
456 else:
471 try:
457 try:
472 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
458 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
473 'rebase')
459 'rebase')
474 stats = rebasenode(repo, rev, p1, base, self.state,
460 stats = rebasenode(repo, rev, p1, base, self.state,
475 self.collapsef, dest)
461 self.collapsef, dest)
476 if stats and stats[3] > 0:
462 if stats and stats[3] > 0:
477 raise error.InterventionRequired(
463 raise error.InterventionRequired(
478 _('unresolved conflicts (see hg '
464 _('unresolved conflicts (see hg '
479 'resolve, then hg rebase --continue)'))
465 'resolve, then hg rebase --continue)'))
480 finally:
466 finally:
481 ui.setconfig('ui', 'forcemerge', '', 'rebase')
467 ui.setconfig('ui', 'forcemerge', '', 'rebase')
482 if not self.collapsef:
468 if not self.collapsef:
483 merging = p2 != nullrev
469 merging = p2 != nullrev
484 editform = cmdutil.mergeeditform(merging, 'rebase')
470 editform = cmdutil.mergeeditform(merging, 'rebase')
485 editor = cmdutil.getcommiteditor(editform=editform, **opts)
471 editor = cmdutil.getcommiteditor(editform=editform, **opts)
486 newnode = concludenode(repo, rev, p1, p2,
472 newnode = concludenode(repo, rev, p1, p2,
487 extrafn=_makeextrafn(self.extrafns),
473 extrafn=_makeextrafn(self.extrafns),
488 editor=editor,
474 editor=editor,
489 keepbranches=self.keepbranchesf,
475 keepbranches=self.keepbranchesf,
490 date=self.date)
476 date=self.date)
491 if newnode is None:
477 if newnode is None:
492 # If it ended up being a no-op commit, then the normal
478 # If it ended up being a no-op commit, then the normal
493 # merge state clean-up path doesn't happen, so do it
479 # merge state clean-up path doesn't happen, so do it
494 # here. Fix issue5494
480 # here. Fix issue5494
495 mergemod.mergestate.clean(repo)
481 mergemod.mergestate.clean(repo)
496 else:
482 else:
497 # Skip commit if we are collapsing
483 # Skip commit if we are collapsing
498 repo.setparents(repo[p1].node())
484 repo.setparents(repo[p1].node())
499 newnode = None
485 newnode = None
500 # Update the state
486 # Update the state
501 if newnode is not None:
487 if newnode is not None:
502 self.state[rev] = repo[newnode].rev()
488 self.state[rev] = repo[newnode].rev()
503 ui.debug('rebased as %s\n' % short(newnode))
489 ui.debug('rebased as %s\n' % short(newnode))
504 else:
490 else:
505 if not self.collapsef:
491 if not self.collapsef:
506 ui.warn(_('note: rebase of %d:%s created no changes '
492 ui.warn(_('note: rebase of %d:%s created no changes '
507 'to commit\n') % (rev, ctx))
493 'to commit\n') % (rev, ctx))
508 self.skipped.add(rev)
494 self.skipped.add(rev)
509 self.state[rev] = p1
495 self.state[rev] = p1
510 ui.debug('next revision set to %s\n' % p1)
496 ui.debug('next revision set to %s\n' % p1)
511 else:
497 else:
512 ui.status(_('already rebased %s as %s\n') %
498 ui.status(_('already rebased %s as %s\n') %
513 (desc, repo[self.state[rev]]))
499 (desc, repo[self.state[rev]]))
514 return pos
500 return pos
515
501
516 def _finishrebase(self):
502 def _finishrebase(self):
517 repo, ui, opts = self.repo, self.ui, self.opts
503 repo, ui, opts = self.repo, self.ui, self.opts
518 if self.collapsef and not self.keepopen:
504 if self.collapsef and not self.keepopen:
519 p1, p2, _base = defineparents(repo, min(self.state), self.destmap,
505 p1, p2, _base = defineparents(repo, min(self.state), self.destmap,
520 self.state, self.skipped,
506 self.state, self.skipped,
521 self.obsoletenotrebased)
507 self.obsoletenotrebased)
522 editopt = opts.get('edit')
508 editopt = opts.get('edit')
523 editform = 'rebase.collapse'
509 editform = 'rebase.collapse'
524 if self.collapsemsg:
510 if self.collapsemsg:
525 commitmsg = self.collapsemsg
511 commitmsg = self.collapsemsg
526 else:
512 else:
527 commitmsg = 'Collapsed revision'
513 commitmsg = 'Collapsed revision'
528 for rebased in sorted(self.state):
514 for rebased in sorted(self.state):
529 if rebased not in self.skipped:
515 if rebased not in self.skipped:
530 commitmsg += '\n* %s' % repo[rebased].description()
516 commitmsg += '\n* %s' % repo[rebased].description()
531 editopt = True
517 editopt = True
532 editor = cmdutil.getcommiteditor(edit=editopt, editform=editform)
518 editor = cmdutil.getcommiteditor(edit=editopt, editform=editform)
533 revtoreuse = max(self.state)
519 revtoreuse = max(self.state)
534
520
535 dsguard = None
521 dsguard = None
536 if ui.configbool('rebase', 'singletransaction'):
522 if ui.configbool('rebase', 'singletransaction'):
537 dsguard = dirstateguard.dirstateguard(repo, 'rebase')
523 dsguard = dirstateguard.dirstateguard(repo, 'rebase')
538 with util.acceptintervention(dsguard):
524 with util.acceptintervention(dsguard):
539 newnode = concludenode(repo, revtoreuse, p1, self.external,
525 newnode = concludenode(repo, revtoreuse, p1, self.external,
540 commitmsg=commitmsg,
526 commitmsg=commitmsg,
541 extrafn=_makeextrafn(self.extrafns),
527 extrafn=_makeextrafn(self.extrafns),
542 editor=editor,
528 editor=editor,
543 keepbranches=self.keepbranchesf,
529 keepbranches=self.keepbranchesf,
544 date=self.date)
530 date=self.date)
545 if newnode is not None:
531 if newnode is not None:
546 newrev = repo[newnode].rev()
532 newrev = repo[newnode].rev()
547 for oldrev in self.state.iterkeys():
533 for oldrev in self.state.iterkeys():
548 self.state[oldrev] = newrev
534 self.state[oldrev] = newrev
549
535
550 if 'qtip' in repo.tags():
536 if 'qtip' in repo.tags():
551 updatemq(repo, self.state, self.skipped, **opts)
537 updatemq(repo, self.state, self.skipped, **opts)
552
538
553 # restore original working directory
539 # restore original working directory
554 # (we do this before stripping)
540 # (we do this before stripping)
555 newwd = self.state.get(self.originalwd, self.originalwd)
541 newwd = self.state.get(self.originalwd, self.originalwd)
556 if newwd < 0:
542 if newwd < 0:
557 # original directory is a parent of rebase set root or ignored
543 # original directory is a parent of rebase set root or ignored
558 newwd = self.originalwd
544 newwd = self.originalwd
559 if newwd not in [c.rev() for c in repo[None].parents()]:
545 if newwd not in [c.rev() for c in repo[None].parents()]:
560 ui.note(_("update back to initial working directory parent\n"))
546 ui.note(_("update back to initial working directory parent\n"))
561 hg.updaterepo(repo, newwd, False)
547 hg.updaterepo(repo, newwd, False)
562
548
563 collapsedas = None
549 collapsedas = None
564 if not self.keepf:
550 if not self.keepf:
565 if self.collapsef:
551 if self.collapsef:
566 collapsedas = newnode
552 collapsedas = newnode
567 clearrebased(ui, repo, self.destmap, self.state, self.skipped,
553 clearrebased(ui, repo, self.destmap, self.state, self.skipped,
568 collapsedas, self.keepf)
554 collapsedas, self.keepf)
569
555
570 clearstatus(repo)
556 clearstatus(repo)
571 clearcollapsemsg(repo)
557 clearcollapsemsg(repo)
572
558
573 ui.note(_("rebase completed\n"))
559 ui.note(_("rebase completed\n"))
574 util.unlinkpath(repo.sjoin('undo'), ignoremissing=True)
560 util.unlinkpath(repo.sjoin('undo'), ignoremissing=True)
575 if self.skipped:
561 if self.skipped:
576 skippedlen = len(self.skipped)
562 skippedlen = len(self.skipped)
577 ui.note(_("%d revisions have been skipped\n") % skippedlen)
563 ui.note(_("%d revisions have been skipped\n") % skippedlen)
578
564
579 if (self.activebookmark and self.activebookmark in repo._bookmarks and
565 if (self.activebookmark and self.activebookmark in repo._bookmarks and
580 repo['.'].node() == repo._bookmarks[self.activebookmark]):
566 repo['.'].node() == repo._bookmarks[self.activebookmark]):
581 bookmarks.activate(repo, self.activebookmark)
567 bookmarks.activate(repo, self.activebookmark)
582
568
583 @command('rebase',
569 @command('rebase',
584 [('s', 'source', '',
570 [('s', 'source', '',
585 _('rebase the specified changeset and descendants'), _('REV')),
571 _('rebase the specified changeset and descendants'), _('REV')),
586 ('b', 'base', '',
572 ('b', 'base', '',
587 _('rebase everything from branching point of specified changeset'),
573 _('rebase everything from branching point of specified changeset'),
588 _('REV')),
574 _('REV')),
589 ('r', 'rev', [],
575 ('r', 'rev', [],
590 _('rebase these revisions'),
576 _('rebase these revisions'),
591 _('REV')),
577 _('REV')),
592 ('d', 'dest', '',
578 ('d', 'dest', '',
593 _('rebase onto the specified changeset'), _('REV')),
579 _('rebase onto the specified changeset'), _('REV')),
594 ('', 'collapse', False, _('collapse the rebased changesets')),
580 ('', 'collapse', False, _('collapse the rebased changesets')),
595 ('m', 'message', '',
581 ('m', 'message', '',
596 _('use text as collapse commit message'), _('TEXT')),
582 _('use text as collapse commit message'), _('TEXT')),
597 ('e', 'edit', False, _('invoke editor on commit messages')),
583 ('e', 'edit', False, _('invoke editor on commit messages')),
598 ('l', 'logfile', '',
584 ('l', 'logfile', '',
599 _('read collapse commit message from file'), _('FILE')),
585 _('read collapse commit message from file'), _('FILE')),
600 ('k', 'keep', False, _('keep original changesets')),
586 ('k', 'keep', False, _('keep original changesets')),
601 ('', 'keepbranches', False, _('keep original branch names')),
587 ('', 'keepbranches', False, _('keep original branch names')),
602 ('D', 'detach', False, _('(DEPRECATED)')),
588 ('D', 'detach', False, _('(DEPRECATED)')),
603 ('i', 'interactive', False, _('(DEPRECATED)')),
589 ('i', 'interactive', False, _('(DEPRECATED)')),
604 ('t', 'tool', '', _('specify merge tool')),
590 ('t', 'tool', '', _('specify merge tool')),
605 ('c', 'continue', False, _('continue an interrupted rebase')),
591 ('c', 'continue', False, _('continue an interrupted rebase')),
606 ('a', 'abort', False, _('abort an interrupted rebase'))] +
592 ('a', 'abort', False, _('abort an interrupted rebase'))] +
607 templateopts,
593 templateopts,
608 _('[-s REV | -b REV] [-d REV] [OPTION]'))
594 _('[-s REV | -b REV] [-d REV] [OPTION]'))
609 def rebase(ui, repo, **opts):
595 def rebase(ui, repo, **opts):
610 """move changeset (and descendants) to a different branch
596 """move changeset (and descendants) to a different branch
611
597
612 Rebase uses repeated merging to graft changesets from one part of
598 Rebase uses repeated merging to graft changesets from one part of
613 history (the source) onto another (the destination). This can be
599 history (the source) onto another (the destination). This can be
614 useful for linearizing *local* changes relative to a master
600 useful for linearizing *local* changes relative to a master
615 development tree.
601 development tree.
616
602
617 Published commits cannot be rebased (see :hg:`help phases`).
603 Published commits cannot be rebased (see :hg:`help phases`).
618 To copy commits, see :hg:`help graft`.
604 To copy commits, see :hg:`help graft`.
619
605
620 If you don't specify a destination changeset (``-d/--dest``), rebase
606 If you don't specify a destination changeset (``-d/--dest``), rebase
621 will use the same logic as :hg:`merge` to pick a destination. if
607 will use the same logic as :hg:`merge` to pick a destination. if
622 the current branch contains exactly one other head, the other head
608 the current branch contains exactly one other head, the other head
623 is merged with by default. Otherwise, an explicit revision with
609 is merged with by default. Otherwise, an explicit revision with
624 which to merge with must be provided. (destination changeset is not
610 which to merge with must be provided. (destination changeset is not
625 modified by rebasing, but new changesets are added as its
611 modified by rebasing, but new changesets are added as its
626 descendants.)
612 descendants.)
627
613
628 Here are the ways to select changesets:
614 Here are the ways to select changesets:
629
615
630 1. Explicitly select them using ``--rev``.
616 1. Explicitly select them using ``--rev``.
631
617
632 2. Use ``--source`` to select a root changeset and include all of its
618 2. Use ``--source`` to select a root changeset and include all of its
633 descendants.
619 descendants.
634
620
635 3. Use ``--base`` to select a changeset; rebase will find ancestors
621 3. Use ``--base`` to select a changeset; rebase will find ancestors
636 and their descendants which are not also ancestors of the destination.
622 and their descendants which are not also ancestors of the destination.
637
623
638 4. If you do not specify any of ``--rev``, ``source``, or ``--base``,
624 4. If you do not specify any of ``--rev``, ``source``, or ``--base``,
639 rebase will use ``--base .`` as above.
625 rebase will use ``--base .`` as above.
640
626
641 Rebase will destroy original changesets unless you use ``--keep``.
627 Rebase will destroy original changesets unless you use ``--keep``.
642 It will also move your bookmarks (even if you do).
628 It will also move your bookmarks (even if you do).
643
629
644 Some changesets may be dropped if they do not contribute changes
630 Some changesets may be dropped if they do not contribute changes
645 (e.g. merges from the destination branch).
631 (e.g. merges from the destination branch).
646
632
647 Unlike ``merge``, rebase will do nothing if you are at the branch tip of
633 Unlike ``merge``, rebase will do nothing if you are at the branch tip of
648 a named branch with two heads. You will need to explicitly specify source
634 a named branch with two heads. You will need to explicitly specify source
649 and/or destination.
635 and/or destination.
650
636
651 If you need to use a tool to automate merge/conflict decisions, you
637 If you need to use a tool to automate merge/conflict decisions, you
652 can specify one with ``--tool``, see :hg:`help merge-tools`.
638 can specify one with ``--tool``, see :hg:`help merge-tools`.
653 As a caveat: the tool will not be used to mediate when a file was
639 As a caveat: the tool will not be used to mediate when a file was
654 deleted, there is no hook presently available for this.
640 deleted, there is no hook presently available for this.
655
641
656 If a rebase is interrupted to manually resolve a conflict, it can be
642 If a rebase is interrupted to manually resolve a conflict, it can be
657 continued with --continue/-c or aborted with --abort/-a.
643 continued with --continue/-c or aborted with --abort/-a.
658
644
659 .. container:: verbose
645 .. container:: verbose
660
646
661 Examples:
647 Examples:
662
648
663 - move "local changes" (current commit back to branching point)
649 - move "local changes" (current commit back to branching point)
664 to the current branch tip after a pull::
650 to the current branch tip after a pull::
665
651
666 hg rebase
652 hg rebase
667
653
668 - move a single changeset to the stable branch::
654 - move a single changeset to the stable branch::
669
655
670 hg rebase -r 5f493448 -d stable
656 hg rebase -r 5f493448 -d stable
671
657
672 - splice a commit and all its descendants onto another part of history::
658 - splice a commit and all its descendants onto another part of history::
673
659
674 hg rebase --source c0c3 --dest 4cf9
660 hg rebase --source c0c3 --dest 4cf9
675
661
676 - rebase everything on a branch marked by a bookmark onto the
662 - rebase everything on a branch marked by a bookmark onto the
677 default branch::
663 default branch::
678
664
679 hg rebase --base myfeature --dest default
665 hg rebase --base myfeature --dest default
680
666
681 - collapse a sequence of changes into a single commit::
667 - collapse a sequence of changes into a single commit::
682
668
683 hg rebase --collapse -r 1520:1525 -d .
669 hg rebase --collapse -r 1520:1525 -d .
684
670
685 - move a named branch while preserving its name::
671 - move a named branch while preserving its name::
686
672
687 hg rebase -r "branch(featureX)" -d 1.3 --keepbranches
673 hg rebase -r "branch(featureX)" -d 1.3 --keepbranches
688
674
689 Configuration Options:
675 Configuration Options:
690
676
691 You can make rebase require a destination if you set the following config
677 You can make rebase require a destination if you set the following config
692 option::
678 option::
693
679
694 [commands]
680 [commands]
695 rebase.requiredest = True
681 rebase.requiredest = True
696
682
697 By default, rebase will close the transaction after each commit. For
683 By default, rebase will close the transaction after each commit. For
698 performance purposes, you can configure rebase to use a single transaction
684 performance purposes, you can configure rebase to use a single transaction
699 across the entire rebase. WARNING: This setting introduces a significant
685 across the entire rebase. WARNING: This setting introduces a significant
700 risk of losing the work you've done in a rebase if the rebase aborts
686 risk of losing the work you've done in a rebase if the rebase aborts
701 unexpectedly::
687 unexpectedly::
702
688
703 [rebase]
689 [rebase]
704 singletransaction = True
690 singletransaction = True
705
691
706 Return Values:
692 Return Values:
707
693
708 Returns 0 on success, 1 if nothing to rebase or there are
694 Returns 0 on success, 1 if nothing to rebase or there are
709 unresolved conflicts.
695 unresolved conflicts.
710
696
711 """
697 """
712 rbsrt = rebaseruntime(repo, ui, opts)
698 rbsrt = rebaseruntime(repo, ui, opts)
713
699
714 with repo.wlock(), repo.lock():
700 with repo.wlock(), repo.lock():
715 # Validate input and define rebasing points
701 # Validate input and define rebasing points
716 destf = opts.get('dest', None)
702 destf = opts.get('dest', None)
717 srcf = opts.get('source', None)
703 srcf = opts.get('source', None)
718 basef = opts.get('base', None)
704 basef = opts.get('base', None)
719 revf = opts.get('rev', [])
705 revf = opts.get('rev', [])
720 # search default destination in this space
706 # search default destination in this space
721 # used in the 'hg pull --rebase' case, see issue 5214.
707 # used in the 'hg pull --rebase' case, see issue 5214.
722 destspace = opts.get('_destspace')
708 destspace = opts.get('_destspace')
723 contf = opts.get('continue')
709 contf = opts.get('continue')
724 abortf = opts.get('abort')
710 abortf = opts.get('abort')
725 if opts.get('interactive'):
711 if opts.get('interactive'):
726 try:
712 try:
727 if extensions.find('histedit'):
713 if extensions.find('histedit'):
728 enablehistedit = ''
714 enablehistedit = ''
729 except KeyError:
715 except KeyError:
730 enablehistedit = " --config extensions.histedit="
716 enablehistedit = " --config extensions.histedit="
731 help = "hg%s help -e histedit" % enablehistedit
717 help = "hg%s help -e histedit" % enablehistedit
732 msg = _("interactive history editing is supported by the "
718 msg = _("interactive history editing is supported by the "
733 "'histedit' extension (see \"%s\")") % help
719 "'histedit' extension (see \"%s\")") % help
734 raise error.Abort(msg)
720 raise error.Abort(msg)
735
721
736 if rbsrt.collapsemsg and not rbsrt.collapsef:
722 if rbsrt.collapsemsg and not rbsrt.collapsef:
737 raise error.Abort(
723 raise error.Abort(
738 _('message can only be specified with collapse'))
724 _('message can only be specified with collapse'))
739
725
740 if contf or abortf:
726 if contf or abortf:
741 if contf and abortf:
727 if contf and abortf:
742 raise error.Abort(_('cannot use both abort and continue'))
728 raise error.Abort(_('cannot use both abort and continue'))
743 if rbsrt.collapsef:
729 if rbsrt.collapsef:
744 raise error.Abort(
730 raise error.Abort(
745 _('cannot use collapse with continue or abort'))
731 _('cannot use collapse with continue or abort'))
746 if srcf or basef or destf:
732 if srcf or basef or destf:
747 raise error.Abort(
733 raise error.Abort(
748 _('abort and continue do not allow specifying revisions'))
734 _('abort and continue do not allow specifying revisions'))
749 if abortf and opts.get('tool', False):
735 if abortf and opts.get('tool', False):
750 ui.warn(_('tool option will be ignored\n'))
736 ui.warn(_('tool option will be ignored\n'))
751 if contf:
737 if contf:
752 ms = mergemod.mergestate.read(repo)
738 ms = mergemod.mergestate.read(repo)
753 mergeutil.checkunresolved(ms)
739 mergeutil.checkunresolved(ms)
754
740
755 retcode = rbsrt._prepareabortorcontinue(abortf)
741 retcode = rbsrt._prepareabortorcontinue(abortf)
756 if retcode is not None:
742 if retcode is not None:
757 return retcode
743 return retcode
758 else:
744 else:
759 destmap = _definedestmap(ui, repo, destf, srcf, basef, revf,
745 destmap = _definedestmap(ui, repo, destf, srcf, basef, revf,
760 destspace=destspace)
746 destspace=destspace)
761 retcode = rbsrt._preparenewrebase(destmap)
747 retcode = rbsrt._preparenewrebase(destmap)
762 if retcode is not None:
748 if retcode is not None:
763 return retcode
749 return retcode
764
750
765 tr = None
751 tr = None
766 dsguard = None
752 dsguard = None
767
753
768 singletr = ui.configbool('rebase', 'singletransaction')
754 singletr = ui.configbool('rebase', 'singletransaction')
769 if singletr:
755 if singletr:
770 tr = repo.transaction('rebase')
756 tr = repo.transaction('rebase')
771 with util.acceptintervention(tr):
757 with util.acceptintervention(tr):
772 if singletr:
758 if singletr:
773 dsguard = dirstateguard.dirstateguard(repo, 'rebase')
759 dsguard = dirstateguard.dirstateguard(repo, 'rebase')
774 with util.acceptintervention(dsguard):
760 with util.acceptintervention(dsguard):
775 rbsrt._performrebase(tr)
761 rbsrt._performrebase(tr)
776
762
777 rbsrt._finishrebase()
763 rbsrt._finishrebase()
778
764
779 def _definedestmap(ui, repo, destf=None, srcf=None, basef=None, revf=None,
765 def _definedestmap(ui, repo, destf=None, srcf=None, basef=None, revf=None,
780 destspace=None):
766 destspace=None):
781 """use revisions argument to define destmap {srcrev: destrev}"""
767 """use revisions argument to define destmap {srcrev: destrev}"""
782 if revf is None:
768 if revf is None:
783 revf = []
769 revf = []
784
770
785 # destspace is here to work around issues with `hg pull --rebase` see
771 # destspace is here to work around issues with `hg pull --rebase` see
786 # issue5214 for details
772 # issue5214 for details
787 if srcf and basef:
773 if srcf and basef:
788 raise error.Abort(_('cannot specify both a source and a base'))
774 raise error.Abort(_('cannot specify both a source and a base'))
789 if revf and basef:
775 if revf and basef:
790 raise error.Abort(_('cannot specify both a revision and a base'))
776 raise error.Abort(_('cannot specify both a revision and a base'))
791 if revf and srcf:
777 if revf and srcf:
792 raise error.Abort(_('cannot specify both a revision and a source'))
778 raise error.Abort(_('cannot specify both a revision and a source'))
793
779
794 cmdutil.checkunfinished(repo)
780 cmdutil.checkunfinished(repo)
795 cmdutil.bailifchanged(repo)
781 cmdutil.bailifchanged(repo)
796
782
797 if ui.configbool('commands', 'rebase.requiredest') and not destf:
783 if ui.configbool('commands', 'rebase.requiredest') and not destf:
798 raise error.Abort(_('you must specify a destination'),
784 raise error.Abort(_('you must specify a destination'),
799 hint=_('use: hg rebase -d REV'))
785 hint=_('use: hg rebase -d REV'))
800
786
801 dest = None
787 dest = None
802
788
803 if revf:
789 if revf:
804 rebaseset = scmutil.revrange(repo, revf)
790 rebaseset = scmutil.revrange(repo, revf)
805 if not rebaseset:
791 if not rebaseset:
806 ui.status(_('empty "rev" revision set - nothing to rebase\n'))
792 ui.status(_('empty "rev" revision set - nothing to rebase\n'))
807 return None
793 return None
808 elif srcf:
794 elif srcf:
809 src = scmutil.revrange(repo, [srcf])
795 src = scmutil.revrange(repo, [srcf])
810 if not src:
796 if not src:
811 ui.status(_('empty "source" revision set - nothing to rebase\n'))
797 ui.status(_('empty "source" revision set - nothing to rebase\n'))
812 return None
798 return None
813 rebaseset = repo.revs('(%ld)::', src)
799 rebaseset = repo.revs('(%ld)::', src)
814 assert rebaseset
800 assert rebaseset
815 else:
801 else:
816 base = scmutil.revrange(repo, [basef or '.'])
802 base = scmutil.revrange(repo, [basef or '.'])
817 if not base:
803 if not base:
818 ui.status(_('empty "base" revision set - '
804 ui.status(_('empty "base" revision set - '
819 "can't compute rebase set\n"))
805 "can't compute rebase set\n"))
820 return None
806 return None
821 if destf:
807 if destf:
822 # --base does not support multiple destinations
808 # --base does not support multiple destinations
823 dest = scmutil.revsingle(repo, destf)
809 dest = scmutil.revsingle(repo, destf)
824 else:
810 else:
825 dest = repo[_destrebase(repo, base, destspace=destspace)]
811 dest = repo[_destrebase(repo, base, destspace=destspace)]
826 destf = str(dest)
812 destf = str(dest)
827
813
828 roots = [] # selected children of branching points
814 roots = [] # selected children of branching points
829 bpbase = {} # {branchingpoint: [origbase]}
815 bpbase = {} # {branchingpoint: [origbase]}
830 for b in base: # group bases by branching points
816 for b in base: # group bases by branching points
831 bp = repo.revs('ancestor(%d, %d)', b, dest).first()
817 bp = repo.revs('ancestor(%d, %d)', b, dest).first()
832 bpbase[bp] = bpbase.get(bp, []) + [b]
818 bpbase[bp] = bpbase.get(bp, []) + [b]
833 if None in bpbase:
819 if None in bpbase:
834 # emulate the old behavior, showing "nothing to rebase" (a better
820 # emulate the old behavior, showing "nothing to rebase" (a better
835 # behavior may be abort with "cannot find branching point" error)
821 # behavior may be abort with "cannot find branching point" error)
836 bpbase.clear()
822 bpbase.clear()
837 for bp, bs in bpbase.iteritems(): # calculate roots
823 for bp, bs in bpbase.iteritems(): # calculate roots
838 roots += list(repo.revs('children(%d) & ancestors(%ld)', bp, bs))
824 roots += list(repo.revs('children(%d) & ancestors(%ld)', bp, bs))
839
825
840 rebaseset = repo.revs('%ld::', roots)
826 rebaseset = repo.revs('%ld::', roots)
841
827
842 if not rebaseset:
828 if not rebaseset:
843 # transform to list because smartsets are not comparable to
829 # transform to list because smartsets are not comparable to
844 # lists. This should be improved to honor laziness of
830 # lists. This should be improved to honor laziness of
845 # smartset.
831 # smartset.
846 if list(base) == [dest.rev()]:
832 if list(base) == [dest.rev()]:
847 if basef:
833 if basef:
848 ui.status(_('nothing to rebase - %s is both "base"'
834 ui.status(_('nothing to rebase - %s is both "base"'
849 ' and destination\n') % dest)
835 ' and destination\n') % dest)
850 else:
836 else:
851 ui.status(_('nothing to rebase - working directory '
837 ui.status(_('nothing to rebase - working directory '
852 'parent is also destination\n'))
838 'parent is also destination\n'))
853 elif not repo.revs('%ld - ::%d', base, dest):
839 elif not repo.revs('%ld - ::%d', base, dest):
854 if basef:
840 if basef:
855 ui.status(_('nothing to rebase - "base" %s is '
841 ui.status(_('nothing to rebase - "base" %s is '
856 'already an ancestor of destination '
842 'already an ancestor of destination '
857 '%s\n') %
843 '%s\n') %
858 ('+'.join(str(repo[r]) for r in base),
844 ('+'.join(str(repo[r]) for r in base),
859 dest))
845 dest))
860 else:
846 else:
861 ui.status(_('nothing to rebase - working '
847 ui.status(_('nothing to rebase - working '
862 'directory parent is already an '
848 'directory parent is already an '
863 'ancestor of destination %s\n') % dest)
849 'ancestor of destination %s\n') % dest)
864 else: # can it happen?
850 else: # can it happen?
865 ui.status(_('nothing to rebase from %s to %s\n') %
851 ui.status(_('nothing to rebase from %s to %s\n') %
866 ('+'.join(str(repo[r]) for r in base), dest))
852 ('+'.join(str(repo[r]) for r in base), dest))
867 return None
853 return None
868
854
869 if not destf:
855 if not destf:
870 dest = repo[_destrebase(repo, rebaseset, destspace=destspace)]
856 dest = repo[_destrebase(repo, rebaseset, destspace=destspace)]
871 destf = str(dest)
857 destf = str(dest)
872
858
873 allsrc = revsetlang.formatspec('%ld', rebaseset)
859 allsrc = revsetlang.formatspec('%ld', rebaseset)
874 alias = {'ALLSRC': allsrc}
860 alias = {'ALLSRC': allsrc}
875
861
876 if dest is None:
862 if dest is None:
877 try:
863 try:
878 # fast path: try to resolve dest without SRC alias
864 # fast path: try to resolve dest without SRC alias
879 dest = scmutil.revsingle(repo, destf, localalias=alias)
865 dest = scmutil.revsingle(repo, destf, localalias=alias)
880 except error.RepoLookupError:
866 except error.RepoLookupError:
881 if not ui.configbool('experimental', 'rebase.multidest'):
867 if not ui.configbool('experimental', 'rebase.multidest'):
882 raise
868 raise
883 # multi-dest path: resolve dest for each SRC separately
869 # multi-dest path: resolve dest for each SRC separately
884 destmap = {}
870 destmap = {}
885 for r in rebaseset:
871 for r in rebaseset:
886 alias['SRC'] = revsetlang.formatspec('%d', r)
872 alias['SRC'] = revsetlang.formatspec('%d', r)
887 # use repo.anyrevs instead of scmutil.revsingle because we
873 # use repo.anyrevs instead of scmutil.revsingle because we
888 # don't want to abort if destset is empty.
874 # don't want to abort if destset is empty.
889 destset = repo.anyrevs([destf], user=True, localalias=alias)
875 destset = repo.anyrevs([destf], user=True, localalias=alias)
890 size = len(destset)
876 size = len(destset)
891 if size == 1:
877 if size == 1:
892 destmap[r] = destset.first()
878 destmap[r] = destset.first()
893 elif size == 0:
879 elif size == 0:
894 ui.note(_('skipping %s - empty destination\n') % repo[r])
880 ui.note(_('skipping %s - empty destination\n') % repo[r])
895 else:
881 else:
896 raise error.Abort(_('rebase destination for %s is not '
882 raise error.Abort(_('rebase destination for %s is not '
897 'unique') % repo[r])
883 'unique') % repo[r])
898
884
899 if dest is not None:
885 if dest is not None:
900 # single-dest case: assign dest to each rev in rebaseset
886 # single-dest case: assign dest to each rev in rebaseset
901 destrev = dest.rev()
887 destrev = dest.rev()
902 destmap = {r: destrev for r in rebaseset} # {srcrev: destrev}
888 destmap = {r: destrev for r in rebaseset} # {srcrev: destrev}
903
889
904 if not destmap:
890 if not destmap:
905 ui.status(_('nothing to rebase - empty destination\n'))
891 ui.status(_('nothing to rebase - empty destination\n'))
906 return None
892 return None
907
893
908 return destmap
894 return destmap
909
895
910 def externalparent(repo, state, destancestors):
896 def externalparent(repo, state, destancestors):
911 """Return the revision that should be used as the second parent
897 """Return the revision that should be used as the second parent
912 when the revisions in state is collapsed on top of destancestors.
898 when the revisions in state is collapsed on top of destancestors.
913 Abort if there is more than one parent.
899 Abort if there is more than one parent.
914 """
900 """
915 parents = set()
901 parents = set()
916 source = min(state)
902 source = min(state)
917 for rev in state:
903 for rev in state:
918 if rev == source:
904 if rev == source:
919 continue
905 continue
920 for p in repo[rev].parents():
906 for p in repo[rev].parents():
921 if (p.rev() not in state
907 if (p.rev() not in state
922 and p.rev() not in destancestors):
908 and p.rev() not in destancestors):
923 parents.add(p.rev())
909 parents.add(p.rev())
924 if not parents:
910 if not parents:
925 return nullrev
911 return nullrev
926 if len(parents) == 1:
912 if len(parents) == 1:
927 return parents.pop()
913 return parents.pop()
928 raise error.Abort(_('unable to collapse on top of %s, there is more '
914 raise error.Abort(_('unable to collapse on top of %s, there is more '
929 'than one external parent: %s') %
915 'than one external parent: %s') %
930 (max(destancestors),
916 (max(destancestors),
931 ', '.join(str(p) for p in sorted(parents))))
917 ', '.join(str(p) for p in sorted(parents))))
932
918
933 def concludenode(repo, rev, p1, p2, commitmsg=None, editor=None, extrafn=None,
919 def concludenode(repo, rev, p1, p2, commitmsg=None, editor=None, extrafn=None,
934 keepbranches=False, date=None):
920 keepbranches=False, date=None):
935 '''Commit the wd changes with parents p1 and p2. Reuse commit info from rev
921 '''Commit the wd changes with parents p1 and p2. Reuse commit info from rev
936 but also store useful information in extra.
922 but also store useful information in extra.
937 Return node of committed revision.'''
923 Return node of committed revision.'''
938 dsguard = util.nullcontextmanager()
924 dsguard = util.nullcontextmanager()
939 if not repo.ui.configbool('rebase', 'singletransaction'):
925 if not repo.ui.configbool('rebase', 'singletransaction'):
940 dsguard = dirstateguard.dirstateguard(repo, 'rebase')
926 dsguard = dirstateguard.dirstateguard(repo, 'rebase')
941 with dsguard:
927 with dsguard:
942 repo.setparents(repo[p1].node(), repo[p2].node())
928 repo.setparents(repo[p1].node(), repo[p2].node())
943 ctx = repo[rev]
929 ctx = repo[rev]
944 if commitmsg is None:
930 if commitmsg is None:
945 commitmsg = ctx.description()
931 commitmsg = ctx.description()
946 keepbranch = keepbranches and repo[p1].branch() != ctx.branch()
932 keepbranch = keepbranches and repo[p1].branch() != ctx.branch()
947 extra = {'rebase_source': ctx.hex()}
933 extra = {'rebase_source': ctx.hex()}
948 if extrafn:
934 if extrafn:
949 extrafn(ctx, extra)
935 extrafn(ctx, extra)
950
936
951 destphase = max(ctx.phase(), phases.draft)
937 destphase = max(ctx.phase(), phases.draft)
952 overrides = {('phases', 'new-commit'): destphase}
938 overrides = {('phases', 'new-commit'): destphase}
953 with repo.ui.configoverride(overrides, 'rebase'):
939 with repo.ui.configoverride(overrides, 'rebase'):
954 if keepbranch:
940 if keepbranch:
955 repo.ui.setconfig('ui', 'allowemptycommit', True)
941 repo.ui.setconfig('ui', 'allowemptycommit', True)
956 # Commit might fail if unresolved files exist
942 # Commit might fail if unresolved files exist
957 if date is None:
943 if date is None:
958 date = ctx.date()
944 date = ctx.date()
959 newnode = repo.commit(text=commitmsg, user=ctx.user(),
945 newnode = repo.commit(text=commitmsg, user=ctx.user(),
960 date=date, extra=extra, editor=editor)
946 date=date, extra=extra, editor=editor)
961
947
962 repo.dirstate.setbranch(repo[newnode].branch())
948 repo.dirstate.setbranch(repo[newnode].branch())
963 return newnode
949 return newnode
964
950
965 def rebasenode(repo, rev, p1, base, state, collapse, dest):
951 def rebasenode(repo, rev, p1, base, state, collapse, dest):
966 'Rebase a single revision rev on top of p1 using base as merge ancestor'
952 'Rebase a single revision rev on top of p1 using base as merge ancestor'
967 # Merge phase
953 # Merge phase
968 # Update to destination and merge it with local
954 # Update to destination and merge it with local
969 if repo['.'].rev() != p1:
955 if repo['.'].rev() != p1:
970 repo.ui.debug(" update to %d:%s\n" % (p1, repo[p1]))
956 repo.ui.debug(" update to %d:%s\n" % (p1, repo[p1]))
971 mergemod.update(repo, p1, False, True)
957 mergemod.update(repo, p1, False, True)
972 else:
958 else:
973 repo.ui.debug(" already in destination\n")
959 repo.ui.debug(" already in destination\n")
974 repo.dirstate.write(repo.currenttransaction())
960 repo.dirstate.write(repo.currenttransaction())
975 repo.ui.debug(" merge against %d:%s\n" % (rev, repo[rev]))
961 repo.ui.debug(" merge against %d:%s\n" % (rev, repo[rev]))
976 if base is not None:
962 if base is not None:
977 repo.ui.debug(" detach base %d:%s\n" % (base, repo[base]))
963 repo.ui.debug(" detach base %d:%s\n" % (base, repo[base]))
978 # When collapsing in-place, the parent is the common ancestor, we
964 # When collapsing in-place, the parent is the common ancestor, we
979 # have to allow merging with it.
965 # have to allow merging with it.
980 wctx = repo[None]
966 wctx = repo[None]
981 stats = mergemod.update(repo, rev, True, True, base, collapse,
967 stats = mergemod.update(repo, rev, True, True, base, collapse,
982 labels=['dest', 'source'])
968 labels=['dest', 'source'])
983 if collapse:
969 if collapse:
984 copies.duplicatecopies(repo, wctx, rev, dest)
970 copies.duplicatecopies(repo, wctx, rev, dest)
985 else:
971 else:
986 # If we're not using --collapse, we need to
972 # If we're not using --collapse, we need to
987 # duplicate copies between the revision we're
973 # duplicate copies between the revision we're
988 # rebasing and its first parent, but *not*
974 # rebasing and its first parent, but *not*
989 # duplicate any copies that have already been
975 # duplicate any copies that have already been
990 # performed in the destination.
976 # performed in the destination.
991 p1rev = repo[rev].p1().rev()
977 p1rev = repo[rev].p1().rev()
992 copies.duplicatecopies(repo, wctx, rev, p1rev, skiprev=dest)
978 copies.duplicatecopies(repo, wctx, rev, p1rev, skiprev=dest)
993 return stats
979 return stats
994
980
995 def adjustdest(repo, rev, destmap, state, skipped):
981 def adjustdest(repo, rev, destmap, state, skipped):
996 """adjust rebase destination given the current rebase state
982 """adjust rebase destination given the current rebase state
997
983
998 rev is what is being rebased. Return a list of two revs, which are the
984 rev is what is being rebased. Return a list of two revs, which are the
999 adjusted destinations for rev's p1 and p2, respectively. If a parent is
985 adjusted destinations for rev's p1 and p2, respectively. If a parent is
1000 nullrev, return dest without adjustment for it.
986 nullrev, return dest without adjustment for it.
1001
987
1002 For example, when doing rebasing B+E to F, C to G, rebase will first move B
988 For example, when doing rebasing B+E to F, C to G, rebase will first move B
1003 to B1, and E's destination will be adjusted from F to B1.
989 to B1, and E's destination will be adjusted from F to B1.
1004
990
1005 B1 <- written during rebasing B
991 B1 <- written during rebasing B
1006 |
992 |
1007 F <- original destination of B, E
993 F <- original destination of B, E
1008 |
994 |
1009 | E <- rev, which is being rebased
995 | E <- rev, which is being rebased
1010 | |
996 | |
1011 | D <- prev, one parent of rev being checked
997 | D <- prev, one parent of rev being checked
1012 | |
998 | |
1013 | x <- skipped, ex. no successor or successor in (::dest)
999 | x <- skipped, ex. no successor or successor in (::dest)
1014 | |
1000 | |
1015 | C <- rebased as C', different destination
1001 | C <- rebased as C', different destination
1016 | |
1002 | |
1017 | B <- rebased as B1 C'
1003 | B <- rebased as B1 C'
1018 |/ |
1004 |/ |
1019 A G <- destination of C, different
1005 A G <- destination of C, different
1020
1006
1021 Another example about merge changeset, rebase -r C+G+H -d K, rebase will
1007 Another example about merge changeset, rebase -r C+G+H -d K, rebase will
1022 first move C to C1, G to G1, and when it's checking H, the adjusted
1008 first move C to C1, G to G1, and when it's checking H, the adjusted
1023 destinations will be [C1, G1].
1009 destinations will be [C1, G1].
1024
1010
1025 H C1 G1
1011 H C1 G1
1026 /| | /
1012 /| | /
1027 F G |/
1013 F G |/
1028 K | | -> K
1014 K | | -> K
1029 | C D |
1015 | C D |
1030 | |/ |
1016 | |/ |
1031 | B | ...
1017 | B | ...
1032 |/ |/
1018 |/ |/
1033 A A
1019 A A
1034
1020
1035 Besides, adjust dest according to existing rebase information. For example,
1021 Besides, adjust dest according to existing rebase information. For example,
1036
1022
1037 B C D B needs to be rebased on top of C, C needs to be rebased on top
1023 B C D B needs to be rebased on top of C, C needs to be rebased on top
1038 \|/ of D. We will rebase C first.
1024 \|/ of D. We will rebase C first.
1039 A
1025 A
1040
1026
1041 C' After rebasing C, when considering B's destination, use C'
1027 C' After rebasing C, when considering B's destination, use C'
1042 | instead of the original C.
1028 | instead of the original C.
1043 B D
1029 B D
1044 \ /
1030 \ /
1045 A
1031 A
1046 """
1032 """
1047 # pick already rebased revs with same dest from state as interesting source
1033 # pick already rebased revs with same dest from state as interesting source
1048 dest = destmap[rev]
1034 dest = destmap[rev]
1049 source = [s for s, d in state.items()
1035 source = [s for s, d in state.items()
1050 if d > 0 and destmap[s] == dest and s not in skipped]
1036 if d > 0 and destmap[s] == dest and s not in skipped]
1051
1037
1052 result = []
1038 result = []
1053 for prev in repo.changelog.parentrevs(rev):
1039 for prev in repo.changelog.parentrevs(rev):
1054 adjusted = dest
1040 adjusted = dest
1055 if prev != nullrev:
1041 if prev != nullrev:
1056 candidate = repo.revs('max(%ld and (::%d))', source, prev).first()
1042 candidate = repo.revs('max(%ld and (::%d))', source, prev).first()
1057 if candidate is not None:
1043 if candidate is not None:
1058 adjusted = state[candidate]
1044 adjusted = state[candidate]
1059 if adjusted == dest and dest in state:
1045 if adjusted == dest and dest in state:
1060 adjusted = state[dest]
1046 adjusted = state[dest]
1061 if adjusted == revtodo:
1047 if adjusted == revtodo:
1062 # sortsource should produce an order that makes this impossible
1048 # sortsource should produce an order that makes this impossible
1063 raise error.ProgrammingError(
1049 raise error.ProgrammingError(
1064 'rev %d should be rebased already at this time' % dest)
1050 'rev %d should be rebased already at this time' % dest)
1065 result.append(adjusted)
1051 result.append(adjusted)
1066 return result
1052 return result
1067
1053
1068 def _checkobsrebase(repo, ui, rebaseobsrevs, rebaseobsskipped):
1054 def _checkobsrebase(repo, ui, rebaseobsrevs, rebaseobsskipped):
1069 """
1055 """
1070 Abort if rebase will create divergence or rebase is noop because of markers
1056 Abort if rebase will create divergence or rebase is noop because of markers
1071
1057
1072 `rebaseobsrevs`: set of obsolete revision in source
1058 `rebaseobsrevs`: set of obsolete revision in source
1073 `rebaseobsskipped`: set of revisions from source skipped because they have
1059 `rebaseobsskipped`: set of revisions from source skipped because they have
1074 successors in destination
1060 successors in destination
1075 """
1061 """
1076 # Obsolete node with successors not in dest leads to divergence
1062 # Obsolete node with successors not in dest leads to divergence
1077 divergenceok = ui.configbool('experimental',
1063 divergenceok = ui.configbool('experimental',
1078 'allowdivergence')
1064 'allowdivergence')
1079 divergencebasecandidates = rebaseobsrevs - rebaseobsskipped
1065 divergencebasecandidates = rebaseobsrevs - rebaseobsskipped
1080
1066
1081 if divergencebasecandidates and not divergenceok:
1067 if divergencebasecandidates and not divergenceok:
1082 divhashes = (str(repo[r])
1068 divhashes = (str(repo[r])
1083 for r in divergencebasecandidates)
1069 for r in divergencebasecandidates)
1084 msg = _("this rebase will cause "
1070 msg = _("this rebase will cause "
1085 "divergences from: %s")
1071 "divergences from: %s")
1086 h = _("to force the rebase please set "
1072 h = _("to force the rebase please set "
1087 "experimental.allowdivergence=True")
1073 "experimental.allowdivergence=True")
1088 raise error.Abort(msg % (",".join(divhashes),), hint=h)
1074 raise error.Abort(msg % (",".join(divhashes),), hint=h)
1089
1075
1090 def successorrevs(unfi, rev):
1076 def successorrevs(unfi, rev):
1091 """yield revision numbers for successors of rev"""
1077 """yield revision numbers for successors of rev"""
1092 assert unfi.filtername is None
1078 assert unfi.filtername is None
1093 nodemap = unfi.changelog.nodemap
1079 nodemap = unfi.changelog.nodemap
1094 for s in obsutil.allsuccessors(unfi.obsstore, [unfi[rev].node()]):
1080 for s in obsutil.allsuccessors(unfi.obsstore, [unfi[rev].node()]):
1095 if s in nodemap:
1081 if s in nodemap:
1096 yield nodemap[s]
1082 yield nodemap[s]
1097
1083
1098 def defineparents(repo, rev, destmap, state, skipped, obsskipped):
1084 def defineparents(repo, rev, destmap, state, skipped, obsskipped):
1099 """Return new parents and optionally a merge base for rev being rebased
1085 """Return new parents and optionally a merge base for rev being rebased
1100
1086
1101 The destination specified by "dest" cannot always be used directly because
1087 The destination specified by "dest" cannot always be used directly because
1102 previously rebase result could affect destination. For example,
1088 previously rebase result could affect destination. For example,
1103
1089
1104 D E rebase -r C+D+E -d B
1090 D E rebase -r C+D+E -d B
1105 |/ C will be rebased to C'
1091 |/ C will be rebased to C'
1106 B C D's new destination will be C' instead of B
1092 B C D's new destination will be C' instead of B
1107 |/ E's new destination will be C' instead of B
1093 |/ E's new destination will be C' instead of B
1108 A
1094 A
1109
1095
1110 The new parents of a merge is slightly more complicated. See the comment
1096 The new parents of a merge is slightly more complicated. See the comment
1111 block below.
1097 block below.
1112 """
1098 """
1113 # use unfiltered changelog since successorrevs may return filtered nodes
1099 # use unfiltered changelog since successorrevs may return filtered nodes
1114 assert repo.filtername is None
1100 assert repo.filtername is None
1115 cl = repo.changelog
1101 cl = repo.changelog
1116 def isancestor(a, b):
1102 def isancestor(a, b):
1117 # take revision numbers instead of nodes
1103 # take revision numbers instead of nodes
1118 if a == b:
1104 if a == b:
1119 return True
1105 return True
1120 elif a > b:
1106 elif a > b:
1121 return False
1107 return False
1122 return cl.isancestor(cl.node(a), cl.node(b))
1108 return cl.isancestor(cl.node(a), cl.node(b))
1123
1109
1124 dest = destmap[rev]
1110 dest = destmap[rev]
1125 oldps = repo.changelog.parentrevs(rev) # old parents
1111 oldps = repo.changelog.parentrevs(rev) # old parents
1126 newps = [nullrev, nullrev] # new parents
1112 newps = [nullrev, nullrev] # new parents
1127 dests = adjustdest(repo, rev, destmap, state, skipped)
1113 dests = adjustdest(repo, rev, destmap, state, skipped)
1128 bases = list(oldps) # merge base candidates, initially just old parents
1114 bases = list(oldps) # merge base candidates, initially just old parents
1129
1115
1130 if all(r == nullrev for r in oldps[1:]):
1116 if all(r == nullrev for r in oldps[1:]):
1131 # For non-merge changeset, just move p to adjusted dest as requested.
1117 # For non-merge changeset, just move p to adjusted dest as requested.
1132 newps[0] = dests[0]
1118 newps[0] = dests[0]
1133 else:
1119 else:
1134 # For merge changeset, if we move p to dests[i] unconditionally, both
1120 # For merge changeset, if we move p to dests[i] unconditionally, both
1135 # parents may change and the end result looks like "the merge loses a
1121 # parents may change and the end result looks like "the merge loses a
1136 # parent", which is a surprise. This is a limit because "--dest" only
1122 # parent", which is a surprise. This is a limit because "--dest" only
1137 # accepts one dest per src.
1123 # accepts one dest per src.
1138 #
1124 #
1139 # Therefore, only move p with reasonable conditions (in this order):
1125 # Therefore, only move p with reasonable conditions (in this order):
1140 # 1. use dest, if dest is a descendent of (p or one of p's successors)
1126 # 1. use dest, if dest is a descendent of (p or one of p's successors)
1141 # 2. use p's rebased result, if p is rebased (state[p] > 0)
1127 # 2. use p's rebased result, if p is rebased (state[p] > 0)
1142 #
1128 #
1143 # Comparing with adjustdest, the logic here does some additional work:
1129 # Comparing with adjustdest, the logic here does some additional work:
1144 # 1. decide which parents will not be moved towards dest
1130 # 1. decide which parents will not be moved towards dest
1145 # 2. if the above decision is "no", should a parent still be moved
1131 # 2. if the above decision is "no", should a parent still be moved
1146 # because it was rebased?
1132 # because it was rebased?
1147 #
1133 #
1148 # For example:
1134 # For example:
1149 #
1135 #
1150 # C # "rebase -r C -d D" is an error since none of the parents
1136 # C # "rebase -r C -d D" is an error since none of the parents
1151 # /| # can be moved. "rebase -r B+C -d D" will move C's parent
1137 # /| # can be moved. "rebase -r B+C -d D" will move C's parent
1152 # A B D # B (using rule "2."), since B will be rebased.
1138 # A B D # B (using rule "2."), since B will be rebased.
1153 #
1139 #
1154 # The loop tries to be not rely on the fact that a Mercurial node has
1140 # The loop tries to be not rely on the fact that a Mercurial node has
1155 # at most 2 parents.
1141 # at most 2 parents.
1156 for i, p in enumerate(oldps):
1142 for i, p in enumerate(oldps):
1157 np = p # new parent
1143 np = p # new parent
1158 if any(isancestor(x, dests[i]) for x in successorrevs(repo, p)):
1144 if any(isancestor(x, dests[i]) for x in successorrevs(repo, p)):
1159 np = dests[i]
1145 np = dests[i]
1160 elif p in state and state[p] > 0:
1146 elif p in state and state[p] > 0:
1161 np = state[p]
1147 np = state[p]
1162
1148
1163 # "bases" only record "special" merge bases that cannot be
1149 # "bases" only record "special" merge bases that cannot be
1164 # calculated from changelog DAG (i.e. isancestor(p, np) is False).
1150 # calculated from changelog DAG (i.e. isancestor(p, np) is False).
1165 # For example:
1151 # For example:
1166 #
1152 #
1167 # B' # rebase -s B -d D, when B was rebased to B'. dest for C
1153 # B' # rebase -s B -d D, when B was rebased to B'. dest for C
1168 # | C # is B', but merge base for C is B, instead of
1154 # | C # is B', but merge base for C is B, instead of
1169 # D | # changelog.ancestor(C, B') == A. If changelog DAG and
1155 # D | # changelog.ancestor(C, B') == A. If changelog DAG and
1170 # | B # "state" edges are merged (so there will be an edge from
1156 # | B # "state" edges are merged (so there will be an edge from
1171 # |/ # B to B'), the merge base is still ancestor(C, B') in
1157 # |/ # B to B'), the merge base is still ancestor(C, B') in
1172 # A # the merged graph.
1158 # A # the merged graph.
1173 #
1159 #
1174 # Also see https://bz.mercurial-scm.org/show_bug.cgi?id=1950#c8
1160 # Also see https://bz.mercurial-scm.org/show_bug.cgi?id=1950#c8
1175 # which uses "virtual null merge" to explain this situation.
1161 # which uses "virtual null merge" to explain this situation.
1176 if isancestor(p, np):
1162 if isancestor(p, np):
1177 bases[i] = nullrev
1163 bases[i] = nullrev
1178
1164
1179 # If one parent becomes an ancestor of the other, drop the ancestor
1165 # If one parent becomes an ancestor of the other, drop the ancestor
1180 for j, x in enumerate(newps[:i]):
1166 for j, x in enumerate(newps[:i]):
1181 if x == nullrev:
1167 if x == nullrev:
1182 continue
1168 continue
1183 if isancestor(np, x): # CASE-1
1169 if isancestor(np, x): # CASE-1
1184 np = nullrev
1170 np = nullrev
1185 elif isancestor(x, np): # CASE-2
1171 elif isancestor(x, np): # CASE-2
1186 newps[j] = np
1172 newps[j] = np
1187 np = nullrev
1173 np = nullrev
1188 # New parents forming an ancestor relationship does not
1174 # New parents forming an ancestor relationship does not
1189 # mean the old parents have a similar relationship. Do not
1175 # mean the old parents have a similar relationship. Do not
1190 # set bases[x] to nullrev.
1176 # set bases[x] to nullrev.
1191 bases[j], bases[i] = bases[i], bases[j]
1177 bases[j], bases[i] = bases[i], bases[j]
1192
1178
1193 newps[i] = np
1179 newps[i] = np
1194
1180
1195 # "rebasenode" updates to new p1, and the old p1 will be used as merge
1181 # "rebasenode" updates to new p1, and the old p1 will be used as merge
1196 # base. If only p2 changes, merging using unchanged p1 as merge base is
1182 # base. If only p2 changes, merging using unchanged p1 as merge base is
1197 # suboptimal. Therefore swap parents to make the merge sane.
1183 # suboptimal. Therefore swap parents to make the merge sane.
1198 if newps[1] != nullrev and oldps[0] == newps[0]:
1184 if newps[1] != nullrev and oldps[0] == newps[0]:
1199 assert len(newps) == 2 and len(oldps) == 2
1185 assert len(newps) == 2 and len(oldps) == 2
1200 newps.reverse()
1186 newps.reverse()
1201 bases.reverse()
1187 bases.reverse()
1202
1188
1203 # No parent change might be an error because we fail to make rev a
1189 # No parent change might be an error because we fail to make rev a
1204 # descendent of requested dest. This can happen, for example:
1190 # descendent of requested dest. This can happen, for example:
1205 #
1191 #
1206 # C # rebase -r C -d D
1192 # C # rebase -r C -d D
1207 # /| # None of A and B will be changed to D and rebase fails.
1193 # /| # None of A and B will be changed to D and rebase fails.
1208 # A B D
1194 # A B D
1209 if set(newps) == set(oldps) and dest not in newps:
1195 if set(newps) == set(oldps) and dest not in newps:
1210 raise error.Abort(_('cannot rebase %d:%s without '
1196 raise error.Abort(_('cannot rebase %d:%s without '
1211 'moving at least one of its parents')
1197 'moving at least one of its parents')
1212 % (rev, repo[rev]))
1198 % (rev, repo[rev]))
1213
1199
1214 # Source should not be ancestor of dest. The check here guarantees it's
1200 # Source should not be ancestor of dest. The check here guarantees it's
1215 # impossible. With multi-dest, the initial check does not cover complex
1201 # impossible. With multi-dest, the initial check does not cover complex
1216 # cases since we don't have abstractions to dry-run rebase cheaply.
1202 # cases since we don't have abstractions to dry-run rebase cheaply.
1217 if any(p != nullrev and isancestor(rev, p) for p in newps):
1203 if any(p != nullrev and isancestor(rev, p) for p in newps):
1218 raise error.Abort(_('source is ancestor of destination'))
1204 raise error.Abort(_('source is ancestor of destination'))
1219
1205
1220 # "rebasenode" updates to new p1, use the corresponding merge base.
1206 # "rebasenode" updates to new p1, use the corresponding merge base.
1221 if bases[0] != nullrev:
1207 if bases[0] != nullrev:
1222 base = bases[0]
1208 base = bases[0]
1223 else:
1209 else:
1224 base = None
1210 base = None
1225
1211
1226 # Check if the merge will contain unwanted changes. That may happen if
1212 # Check if the merge will contain unwanted changes. That may happen if
1227 # there are multiple special (non-changelog ancestor) merge bases, which
1213 # there are multiple special (non-changelog ancestor) merge bases, which
1228 # cannot be handled well by the 3-way merge algorithm. For example:
1214 # cannot be handled well by the 3-way merge algorithm. For example:
1229 #
1215 #
1230 # F
1216 # F
1231 # /|
1217 # /|
1232 # D E # "rebase -r D+E+F -d Z", when rebasing F, if "D" was chosen
1218 # D E # "rebase -r D+E+F -d Z", when rebasing F, if "D" was chosen
1233 # | | # as merge base, the difference between D and F will include
1219 # | | # as merge base, the difference between D and F will include
1234 # B C # C, so the rebased F will contain C surprisingly. If "E" was
1220 # B C # C, so the rebased F will contain C surprisingly. If "E" was
1235 # |/ # chosen, the rebased F will contain B.
1221 # |/ # chosen, the rebased F will contain B.
1236 # A Z
1222 # A Z
1237 #
1223 #
1238 # But our merge base candidates (D and E in above case) could still be
1224 # But our merge base candidates (D and E in above case) could still be
1239 # better than the default (ancestor(F, Z) == null). Therefore still
1225 # better than the default (ancestor(F, Z) == null). Therefore still
1240 # pick one (so choose p1 above).
1226 # pick one (so choose p1 above).
1241 if sum(1 for b in bases if b != nullrev) > 1:
1227 if sum(1 for b in bases if b != nullrev) > 1:
1242 unwanted = [None, None] # unwanted[i]: unwanted revs if choose bases[i]
1228 unwanted = [None, None] # unwanted[i]: unwanted revs if choose bases[i]
1243 for i, base in enumerate(bases):
1229 for i, base in enumerate(bases):
1244 if base == nullrev:
1230 if base == nullrev:
1245 continue
1231 continue
1246 # Revisions in the side (not chosen as merge base) branch that
1232 # Revisions in the side (not chosen as merge base) branch that
1247 # might contain "surprising" contents
1233 # might contain "surprising" contents
1248 siderevs = list(repo.revs('((%ld-%d) %% (%d+%d))',
1234 siderevs = list(repo.revs('((%ld-%d) %% (%d+%d))',
1249 bases, base, base, dest))
1235 bases, base, base, dest))
1250
1236
1251 # If those revisions are covered by rebaseset, the result is good.
1237 # If those revisions are covered by rebaseset, the result is good.
1252 # A merge in rebaseset would be considered to cover its ancestors.
1238 # A merge in rebaseset would be considered to cover its ancestors.
1253 if siderevs:
1239 if siderevs:
1254 rebaseset = [r for r, d in state.items()
1240 rebaseset = [r for r, d in state.items()
1255 if d > 0 and r not in obsskipped]
1241 if d > 0 and r not in obsskipped]
1256 merges = [r for r in rebaseset
1242 merges = [r for r in rebaseset
1257 if cl.parentrevs(r)[1] != nullrev]
1243 if cl.parentrevs(r)[1] != nullrev]
1258 unwanted[i] = list(repo.revs('%ld - (::%ld) - %ld',
1244 unwanted[i] = list(repo.revs('%ld - (::%ld) - %ld',
1259 siderevs, merges, rebaseset))
1245 siderevs, merges, rebaseset))
1260
1246
1261 # Choose a merge base that has a minimal number of unwanted revs.
1247 # Choose a merge base that has a minimal number of unwanted revs.
1262 l, i = min((len(revs), i)
1248 l, i = min((len(revs), i)
1263 for i, revs in enumerate(unwanted) if revs is not None)
1249 for i, revs in enumerate(unwanted) if revs is not None)
1264 base = bases[i]
1250 base = bases[i]
1265
1251
1266 # newps[0] should match merge base if possible. Currently, if newps[i]
1252 # newps[0] should match merge base if possible. Currently, if newps[i]
1267 # is nullrev, the only case is newps[i] and newps[j] (j < i), one is
1253 # is nullrev, the only case is newps[i] and newps[j] (j < i), one is
1268 # the other's ancestor. In that case, it's fine to not swap newps here.
1254 # the other's ancestor. In that case, it's fine to not swap newps here.
1269 # (see CASE-1 and CASE-2 above)
1255 # (see CASE-1 and CASE-2 above)
1270 if i != 0 and newps[i] != nullrev:
1256 if i != 0 and newps[i] != nullrev:
1271 newps[0], newps[i] = newps[i], newps[0]
1257 newps[0], newps[i] = newps[i], newps[0]
1272
1258
1273 # The merge will include unwanted revisions. Abort now. Revisit this if
1259 # The merge will include unwanted revisions. Abort now. Revisit this if
1274 # we have a more advanced merge algorithm that handles multiple bases.
1260 # we have a more advanced merge algorithm that handles multiple bases.
1275 if l > 0:
1261 if l > 0:
1276 unwanteddesc = _(' or ').join(
1262 unwanteddesc = _(' or ').join(
1277 (', '.join('%d:%s' % (r, repo[r]) for r in revs)
1263 (', '.join('%d:%s' % (r, repo[r]) for r in revs)
1278 for revs in unwanted if revs is not None))
1264 for revs in unwanted if revs is not None))
1279 raise error.Abort(
1265 raise error.Abort(
1280 _('rebasing %d:%s will include unwanted changes from %s')
1266 _('rebasing %d:%s will include unwanted changes from %s')
1281 % (rev, repo[rev], unwanteddesc))
1267 % (rev, repo[rev], unwanteddesc))
1282
1268
1283 repo.ui.debug(" future parents are %d and %d\n" % tuple(newps))
1269 repo.ui.debug(" future parents are %d and %d\n" % tuple(newps))
1284
1270
1285 return newps[0], newps[1], base
1271 return newps[0], newps[1], base
1286
1272
1287 def isagitpatch(repo, patchname):
1273 def isagitpatch(repo, patchname):
1288 'Return true if the given patch is in git format'
1274 'Return true if the given patch is in git format'
1289 mqpatch = os.path.join(repo.mq.path, patchname)
1275 mqpatch = os.path.join(repo.mq.path, patchname)
1290 for line in patch.linereader(file(mqpatch, 'rb')):
1276 for line in patch.linereader(file(mqpatch, 'rb')):
1291 if line.startswith('diff --git'):
1277 if line.startswith('diff --git'):
1292 return True
1278 return True
1293 return False
1279 return False
1294
1280
1295 def updatemq(repo, state, skipped, **opts):
1281 def updatemq(repo, state, skipped, **opts):
1296 'Update rebased mq patches - finalize and then import them'
1282 'Update rebased mq patches - finalize and then import them'
1297 mqrebase = {}
1283 mqrebase = {}
1298 mq = repo.mq
1284 mq = repo.mq
1299 original_series = mq.fullseries[:]
1285 original_series = mq.fullseries[:]
1300 skippedpatches = set()
1286 skippedpatches = set()
1301
1287
1302 for p in mq.applied:
1288 for p in mq.applied:
1303 rev = repo[p.node].rev()
1289 rev = repo[p.node].rev()
1304 if rev in state:
1290 if rev in state:
1305 repo.ui.debug('revision %d is an mq patch (%s), finalize it.\n' %
1291 repo.ui.debug('revision %d is an mq patch (%s), finalize it.\n' %
1306 (rev, p.name))
1292 (rev, p.name))
1307 mqrebase[rev] = (p.name, isagitpatch(repo, p.name))
1293 mqrebase[rev] = (p.name, isagitpatch(repo, p.name))
1308 else:
1294 else:
1309 # Applied but not rebased, not sure this should happen
1295 # Applied but not rebased, not sure this should happen
1310 skippedpatches.add(p.name)
1296 skippedpatches.add(p.name)
1311
1297
1312 if mqrebase:
1298 if mqrebase:
1313 mq.finish(repo, mqrebase.keys())
1299 mq.finish(repo, mqrebase.keys())
1314
1300
1315 # We must start import from the newest revision
1301 # We must start import from the newest revision
1316 for rev in sorted(mqrebase, reverse=True):
1302 for rev in sorted(mqrebase, reverse=True):
1317 if rev not in skipped:
1303 if rev not in skipped:
1318 name, isgit = mqrebase[rev]
1304 name, isgit = mqrebase[rev]
1319 repo.ui.note(_('updating mq patch %s to %s:%s\n') %
1305 repo.ui.note(_('updating mq patch %s to %s:%s\n') %
1320 (name, state[rev], repo[state[rev]]))
1306 (name, state[rev], repo[state[rev]]))
1321 mq.qimport(repo, (), patchname=name, git=isgit,
1307 mq.qimport(repo, (), patchname=name, git=isgit,
1322 rev=[str(state[rev])])
1308 rev=[str(state[rev])])
1323 else:
1309 else:
1324 # Rebased and skipped
1310 # Rebased and skipped
1325 skippedpatches.add(mqrebase[rev][0])
1311 skippedpatches.add(mqrebase[rev][0])
1326
1312
1327 # Patches were either applied and rebased and imported in
1313 # Patches were either applied and rebased and imported in
1328 # order, applied and removed or unapplied. Discard the removed
1314 # order, applied and removed or unapplied. Discard the removed
1329 # ones while preserving the original series order and guards.
1315 # ones while preserving the original series order and guards.
1330 newseries = [s for s in original_series
1316 newseries = [s for s in original_series
1331 if mq.guard_re.split(s, 1)[0] not in skippedpatches]
1317 if mq.guard_re.split(s, 1)[0] not in skippedpatches]
1332 mq.fullseries[:] = newseries
1318 mq.fullseries[:] = newseries
1333 mq.seriesdirty = True
1319 mq.seriesdirty = True
1334 mq.savedirty()
1320 mq.savedirty()
1335
1321
1336 def storecollapsemsg(repo, collapsemsg):
1322 def storecollapsemsg(repo, collapsemsg):
1337 'Store the collapse message to allow recovery'
1323 'Store the collapse message to allow recovery'
1338 collapsemsg = collapsemsg or ''
1324 collapsemsg = collapsemsg or ''
1339 f = repo.vfs("last-message.txt", "w")
1325 f = repo.vfs("last-message.txt", "w")
1340 f.write("%s\n" % collapsemsg)
1326 f.write("%s\n" % collapsemsg)
1341 f.close()
1327 f.close()
1342
1328
1343 def clearcollapsemsg(repo):
1329 def clearcollapsemsg(repo):
1344 'Remove collapse message file'
1330 'Remove collapse message file'
1345 repo.vfs.unlinkpath("last-message.txt", ignoremissing=True)
1331 repo.vfs.unlinkpath("last-message.txt", ignoremissing=True)
1346
1332
1347 def restorecollapsemsg(repo, isabort):
1333 def restorecollapsemsg(repo, isabort):
1348 'Restore previously stored collapse message'
1334 'Restore previously stored collapse message'
1349 try:
1335 try:
1350 f = repo.vfs("last-message.txt")
1336 f = repo.vfs("last-message.txt")
1351 collapsemsg = f.readline().strip()
1337 collapsemsg = f.readline().strip()
1352 f.close()
1338 f.close()
1353 except IOError as err:
1339 except IOError as err:
1354 if err.errno != errno.ENOENT:
1340 if err.errno != errno.ENOENT:
1355 raise
1341 raise
1356 if isabort:
1342 if isabort:
1357 # Oh well, just abort like normal
1343 # Oh well, just abort like normal
1358 collapsemsg = ''
1344 collapsemsg = ''
1359 else:
1345 else:
1360 raise error.Abort(_('missing .hg/last-message.txt for rebase'))
1346 raise error.Abort(_('missing .hg/last-message.txt for rebase'))
1361 return collapsemsg
1347 return collapsemsg
1362
1348
1363 def clearstatus(repo):
1349 def clearstatus(repo):
1364 'Remove the status files'
1350 'Remove the status files'
1365 # Make sure the active transaction won't write the state file
1351 # Make sure the active transaction won't write the state file
1366 tr = repo.currenttransaction()
1352 tr = repo.currenttransaction()
1367 if tr:
1353 if tr:
1368 tr.removefilegenerator('rebasestate')
1354 tr.removefilegenerator('rebasestate')
1369 repo.vfs.unlinkpath("rebasestate", ignoremissing=True)
1355 repo.vfs.unlinkpath("rebasestate", ignoremissing=True)
1370
1356
1371 def needupdate(repo, state):
1357 def needupdate(repo, state):
1372 '''check whether we should `update --clean` away from a merge, or if
1358 '''check whether we should `update --clean` away from a merge, or if
1373 somehow the working dir got forcibly updated, e.g. by older hg'''
1359 somehow the working dir got forcibly updated, e.g. by older hg'''
1374 parents = [p.rev() for p in repo[None].parents()]
1360 parents = [p.rev() for p in repo[None].parents()]
1375
1361
1376 # Are we in a merge state at all?
1362 # Are we in a merge state at all?
1377 if len(parents) < 2:
1363 if len(parents) < 2:
1378 return False
1364 return False
1379
1365
1380 # We should be standing on the first as-of-yet unrebased commit.
1366 # We should be standing on the first as-of-yet unrebased commit.
1381 firstunrebased = min([old for old, new in state.iteritems()
1367 firstunrebased = min([old for old, new in state.iteritems()
1382 if new == nullrev])
1368 if new == nullrev])
1383 if firstunrebased in parents:
1369 if firstunrebased in parents:
1384 return True
1370 return True
1385
1371
1386 return False
1372 return False
1387
1373
1388 def abort(repo, originalwd, destmap, state, activebookmark=None):
1374 def abort(repo, originalwd, destmap, state, activebookmark=None):
1389 '''Restore the repository to its original state. Additional args:
1375 '''Restore the repository to its original state. Additional args:
1390
1376
1391 activebookmark: the name of the bookmark that should be active after the
1377 activebookmark: the name of the bookmark that should be active after the
1392 restore'''
1378 restore'''
1393
1379
1394 try:
1380 try:
1395 # If the first commits in the rebased set get skipped during the rebase,
1381 # If the first commits in the rebased set get skipped during the rebase,
1396 # their values within the state mapping will be the dest rev id. The
1382 # their values within the state mapping will be the dest rev id. The
1397 # dstates list must must not contain the dest rev (issue4896)
1383 # dstates list must must not contain the dest rev (issue4896)
1398 dstates = [s for r, s in state.items() if s >= 0 and s != destmap[r]]
1384 dstates = [s for r, s in state.items() if s >= 0 and s != destmap[r]]
1399 immutable = [d for d in dstates if not repo[d].mutable()]
1385 immutable = [d for d in dstates if not repo[d].mutable()]
1400 cleanup = True
1386 cleanup = True
1401 if immutable:
1387 if immutable:
1402 repo.ui.warn(_("warning: can't clean up public changesets %s\n")
1388 repo.ui.warn(_("warning: can't clean up public changesets %s\n")
1403 % ', '.join(str(repo[r]) for r in immutable),
1389 % ', '.join(str(repo[r]) for r in immutable),
1404 hint=_("see 'hg help phases' for details"))
1390 hint=_("see 'hg help phases' for details"))
1405 cleanup = False
1391 cleanup = False
1406
1392
1407 descendants = set()
1393 descendants = set()
1408 if dstates:
1394 if dstates:
1409 descendants = set(repo.changelog.descendants(dstates))
1395 descendants = set(repo.changelog.descendants(dstates))
1410 if descendants - set(dstates):
1396 if descendants - set(dstates):
1411 repo.ui.warn(_("warning: new changesets detected on destination "
1397 repo.ui.warn(_("warning: new changesets detected on destination "
1412 "branch, can't strip\n"))
1398 "branch, can't strip\n"))
1413 cleanup = False
1399 cleanup = False
1414
1400
1415 if cleanup:
1401 if cleanup:
1416 shouldupdate = False
1402 shouldupdate = False
1417 rebased = [s for r, s in state.items()
1403 rebased = [s for r, s in state.items()
1418 if s >= 0 and s != destmap[r]]
1404 if s >= 0 and s != destmap[r]]
1419 if rebased:
1405 if rebased:
1420 strippoints = [
1406 strippoints = [
1421 c.node() for c in repo.set('roots(%ld)', rebased)]
1407 c.node() for c in repo.set('roots(%ld)', rebased)]
1422
1408
1423 updateifonnodes = set(rebased)
1409 updateifonnodes = set(rebased)
1424 updateifonnodes.update(destmap.values())
1410 updateifonnodes.update(destmap.values())
1425 updateifonnodes.add(originalwd)
1411 updateifonnodes.add(originalwd)
1426 shouldupdate = repo['.'].rev() in updateifonnodes
1412 shouldupdate = repo['.'].rev() in updateifonnodes
1427
1413
1428 # Update away from the rebase if necessary
1414 # Update away from the rebase if necessary
1429 if shouldupdate or needupdate(repo, state):
1415 if shouldupdate or needupdate(repo, state):
1430 mergemod.update(repo, originalwd, False, True)
1416 mergemod.update(repo, originalwd, False, True)
1431
1417
1432 # Strip from the first rebased revision
1418 # Strip from the first rebased revision
1433 if rebased:
1419 if rebased:
1434 # no backup of rebased cset versions needed
1420 # no backup of rebased cset versions needed
1435 repair.strip(repo.ui, repo, strippoints)
1421 repair.strip(repo.ui, repo, strippoints)
1436
1422
1437 if activebookmark and activebookmark in repo._bookmarks:
1423 if activebookmark and activebookmark in repo._bookmarks:
1438 bookmarks.activate(repo, activebookmark)
1424 bookmarks.activate(repo, activebookmark)
1439
1425
1440 finally:
1426 finally:
1441 clearstatus(repo)
1427 clearstatus(repo)
1442 clearcollapsemsg(repo)
1428 clearcollapsemsg(repo)
1443 repo.ui.warn(_('rebase aborted\n'))
1429 repo.ui.warn(_('rebase aborted\n'))
1444 return 0
1430 return 0
1445
1431
1446 def sortsource(destmap):
1432 def sortsource(destmap):
1447 """yield source revisions in an order that we only rebase things once
1433 """yield source revisions in an order that we only rebase things once
1448
1434
1449 If source and destination overlaps, we should filter out revisions
1435 If source and destination overlaps, we should filter out revisions
1450 depending on other revisions which hasn't been rebased yet.
1436 depending on other revisions which hasn't been rebased yet.
1451
1437
1452 Yield a sorted list of revisions each time.
1438 Yield a sorted list of revisions each time.
1453
1439
1454 For example, when rebasing A to B, B to C. This function yields [B], then
1440 For example, when rebasing A to B, B to C. This function yields [B], then
1455 [A], indicating B needs to be rebased first.
1441 [A], indicating B needs to be rebased first.
1456
1442
1457 Raise if there is a cycle so the rebase is impossible.
1443 Raise if there is a cycle so the rebase is impossible.
1458 """
1444 """
1459 srcset = set(destmap)
1445 srcset = set(destmap)
1460 while srcset:
1446 while srcset:
1461 srclist = sorted(srcset)
1447 srclist = sorted(srcset)
1462 result = []
1448 result = []
1463 for r in srclist:
1449 for r in srclist:
1464 if destmap[r] not in srcset:
1450 if destmap[r] not in srcset:
1465 result.append(r)
1451 result.append(r)
1466 if not result:
1452 if not result:
1467 raise error.Abort(_('source and destination form a cycle'))
1453 raise error.Abort(_('source and destination form a cycle'))
1468 srcset -= set(result)
1454 srcset -= set(result)
1469 yield result
1455 yield result
1470
1456
1471 def buildstate(repo, destmap, collapse):
1457 def buildstate(repo, destmap, collapse):
1472 '''Define which revisions are going to be rebased and where
1458 '''Define which revisions are going to be rebased and where
1473
1459
1474 repo: repo
1460 repo: repo
1475 destmap: {srcrev: destrev}
1461 destmap: {srcrev: destrev}
1476 '''
1462 '''
1477 rebaseset = destmap.keys()
1463 rebaseset = destmap.keys()
1478 originalwd = repo['.'].rev()
1464 originalwd = repo['.'].rev()
1479
1465
1480 # This check isn't strictly necessary, since mq detects commits over an
1466 # This check isn't strictly necessary, since mq detects commits over an
1481 # applied patch. But it prevents messing up the working directory when
1467 # applied patch. But it prevents messing up the working directory when
1482 # a partially completed rebase is blocked by mq.
1468 # a partially completed rebase is blocked by mq.
1483 if 'qtip' in repo.tags():
1469 if 'qtip' in repo.tags():
1484 mqapplied = set(repo[s.node].rev() for s in repo.mq.applied)
1470 mqapplied = set(repo[s.node].rev() for s in repo.mq.applied)
1485 if set(destmap.values()) & mqapplied:
1471 if set(destmap.values()) & mqapplied:
1486 raise error.Abort(_('cannot rebase onto an applied mq patch'))
1472 raise error.Abort(_('cannot rebase onto an applied mq patch'))
1487
1473
1488 # Get "cycle" error early by exhausting the generator.
1474 # Get "cycle" error early by exhausting the generator.
1489 sortedsrc = list(sortsource(destmap)) # a list of sorted revs
1475 sortedsrc = list(sortsource(destmap)) # a list of sorted revs
1490 if not sortedsrc:
1476 if not sortedsrc:
1491 raise error.Abort(_('no matching revisions'))
1477 raise error.Abort(_('no matching revisions'))
1492
1478
1493 # Only check the first batch of revisions to rebase not depending on other
1479 # Only check the first batch of revisions to rebase not depending on other
1494 # rebaseset. This means "source is ancestor of destination" for the second
1480 # rebaseset. This means "source is ancestor of destination" for the second
1495 # (and following) batches of revisions are not checked here. We rely on
1481 # (and following) batches of revisions are not checked here. We rely on
1496 # "defineparents" to do that check.
1482 # "defineparents" to do that check.
1497 roots = list(repo.set('roots(%ld)', sortedsrc[0]))
1483 roots = list(repo.set('roots(%ld)', sortedsrc[0]))
1498 if not roots:
1484 if not roots:
1499 raise error.Abort(_('no matching revisions'))
1485 raise error.Abort(_('no matching revisions'))
1500 roots.sort()
1486 roots.sort()
1501 state = dict.fromkeys(rebaseset, revtodo)
1487 state = dict.fromkeys(rebaseset, revtodo)
1502 emptyrebase = (len(sortedsrc) == 1)
1488 emptyrebase = (len(sortedsrc) == 1)
1503 for root in roots:
1489 for root in roots:
1504 dest = repo[destmap[root.rev()]]
1490 dest = repo[destmap[root.rev()]]
1505 commonbase = root.ancestor(dest)
1491 commonbase = root.ancestor(dest)
1506 if commonbase == root:
1492 if commonbase == root:
1507 raise error.Abort(_('source is ancestor of destination'))
1493 raise error.Abort(_('source is ancestor of destination'))
1508 if commonbase == dest:
1494 if commonbase == dest:
1509 wctx = repo[None]
1495 wctx = repo[None]
1510 if dest == wctx.p1():
1496 if dest == wctx.p1():
1511 # when rebasing to '.', it will use the current wd branch name
1497 # when rebasing to '.', it will use the current wd branch name
1512 samebranch = root.branch() == wctx.branch()
1498 samebranch = root.branch() == wctx.branch()
1513 else:
1499 else:
1514 samebranch = root.branch() == dest.branch()
1500 samebranch = root.branch() == dest.branch()
1515 if not collapse and samebranch and dest in root.parents():
1501 if not collapse and samebranch and dest in root.parents():
1516 # mark the revision as done by setting its new revision
1502 # mark the revision as done by setting its new revision
1517 # equal to its old (current) revisions
1503 # equal to its old (current) revisions
1518 state[root.rev()] = root.rev()
1504 state[root.rev()] = root.rev()
1519 repo.ui.debug('source is a child of destination\n')
1505 repo.ui.debug('source is a child of destination\n')
1520 continue
1506 continue
1521
1507
1522 emptyrebase = False
1508 emptyrebase = False
1523 repo.ui.debug('rebase onto %s starting from %s\n' % (dest, root))
1509 repo.ui.debug('rebase onto %s starting from %s\n' % (dest, root))
1524 if emptyrebase:
1510 if emptyrebase:
1525 return None
1511 return None
1526 for rev in sorted(state):
1512 for rev in sorted(state):
1527 parents = [p for p in repo.changelog.parentrevs(rev) if p != nullrev]
1513 parents = [p for p in repo.changelog.parentrevs(rev) if p != nullrev]
1528 # if all parents of this revision are done, then so is this revision
1514 # if all parents of this revision are done, then so is this revision
1529 if parents and all((state.get(p) == p for p in parents)):
1515 if parents and all((state.get(p) == p for p in parents)):
1530 state[rev] = rev
1516 state[rev] = rev
1531 return originalwd, destmap, state
1517 return originalwd, destmap, state
1532
1518
1533 def clearrebased(ui, repo, destmap, state, skipped, collapsedas=None,
1519 def clearrebased(ui, repo, destmap, state, skipped, collapsedas=None,
1534 keepf=False):
1520 keepf=False):
1535 """dispose of rebased revision at the end of the rebase
1521 """dispose of rebased revision at the end of the rebase
1536
1522
1537 If `collapsedas` is not None, the rebase was a collapse whose result if the
1523 If `collapsedas` is not None, the rebase was a collapse whose result if the
1538 `collapsedas` node.
1524 `collapsedas` node.
1539
1525
1540 If `keepf` is not True, the rebase has --keep set and no nodes should be
1526 If `keepf` is not True, the rebase has --keep set and no nodes should be
1541 removed (but bookmarks still need to be moved).
1527 removed (but bookmarks still need to be moved).
1542 """
1528 """
1543 tonode = repo.changelog.node
1529 tonode = repo.changelog.node
1544 replacements = {}
1530 replacements = {}
1545 moves = {}
1531 moves = {}
1546 for rev, newrev in sorted(state.items()):
1532 for rev, newrev in sorted(state.items()):
1547 if newrev >= 0 and newrev != rev:
1533 if newrev >= 0 and newrev != rev:
1548 oldnode = tonode(rev)
1534 oldnode = tonode(rev)
1549 newnode = collapsedas or tonode(newrev)
1535 newnode = collapsedas or tonode(newrev)
1550 moves[oldnode] = newnode
1536 moves[oldnode] = newnode
1551 if not keepf:
1537 if not keepf:
1552 if rev in skipped:
1538 if rev in skipped:
1553 succs = ()
1539 succs = ()
1554 else:
1540 else:
1555 succs = (newnode,)
1541 succs = (newnode,)
1556 replacements[oldnode] = succs
1542 replacements[oldnode] = succs
1557 scmutil.cleanupnodes(repo, replacements, 'rebase', moves)
1543 scmutil.cleanupnodes(repo, replacements, 'rebase', moves)
1558
1544
1559 def pullrebase(orig, ui, repo, *args, **opts):
1545 def pullrebase(orig, ui, repo, *args, **opts):
1560 'Call rebase after pull if the latter has been invoked with --rebase'
1546 'Call rebase after pull if the latter has been invoked with --rebase'
1561 ret = None
1547 ret = None
1562 if opts.get('rebase'):
1548 if opts.get('rebase'):
1563 if ui.configbool('commands', 'rebase.requiredest'):
1549 if ui.configbool('commands', 'rebase.requiredest'):
1564 msg = _('rebase destination required by configuration')
1550 msg = _('rebase destination required by configuration')
1565 hint = _('use hg pull followed by hg rebase -d DEST')
1551 hint = _('use hg pull followed by hg rebase -d DEST')
1566 raise error.Abort(msg, hint=hint)
1552 raise error.Abort(msg, hint=hint)
1567
1553
1568 with repo.wlock(), repo.lock():
1554 with repo.wlock(), repo.lock():
1569 if opts.get('update'):
1555 if opts.get('update'):
1570 del opts['update']
1556 del opts['update']
1571 ui.debug('--update and --rebase are not compatible, ignoring '
1557 ui.debug('--update and --rebase are not compatible, ignoring '
1572 'the update flag\n')
1558 'the update flag\n')
1573
1559
1574 cmdutil.checkunfinished(repo)
1560 cmdutil.checkunfinished(repo)
1575 cmdutil.bailifchanged(repo, hint=_('cannot pull with rebase: '
1561 cmdutil.bailifchanged(repo, hint=_('cannot pull with rebase: '
1576 'please commit or shelve your changes first'))
1562 'please commit or shelve your changes first'))
1577
1563
1578 revsprepull = len(repo)
1564 revsprepull = len(repo)
1579 origpostincoming = commands.postincoming
1565 origpostincoming = commands.postincoming
1580 def _dummy(*args, **kwargs):
1566 def _dummy(*args, **kwargs):
1581 pass
1567 pass
1582 commands.postincoming = _dummy
1568 commands.postincoming = _dummy
1583 try:
1569 try:
1584 ret = orig(ui, repo, *args, **opts)
1570 ret = orig(ui, repo, *args, **opts)
1585 finally:
1571 finally:
1586 commands.postincoming = origpostincoming
1572 commands.postincoming = origpostincoming
1587 revspostpull = len(repo)
1573 revspostpull = len(repo)
1588 if revspostpull > revsprepull:
1574 if revspostpull > revsprepull:
1589 # --rev option from pull conflict with rebase own --rev
1575 # --rev option from pull conflict with rebase own --rev
1590 # dropping it
1576 # dropping it
1591 if 'rev' in opts:
1577 if 'rev' in opts:
1592 del opts['rev']
1578 del opts['rev']
1593 # positional argument from pull conflicts with rebase's own
1579 # positional argument from pull conflicts with rebase's own
1594 # --source.
1580 # --source.
1595 if 'source' in opts:
1581 if 'source' in opts:
1596 del opts['source']
1582 del opts['source']
1597 # revsprepull is the len of the repo, not revnum of tip.
1583 # revsprepull is the len of the repo, not revnum of tip.
1598 destspace = list(repo.changelog.revs(start=revsprepull))
1584 destspace = list(repo.changelog.revs(start=revsprepull))
1599 opts['_destspace'] = destspace
1585 opts['_destspace'] = destspace
1600 try:
1586 try:
1601 rebase(ui, repo, **opts)
1587 rebase(ui, repo, **opts)
1602 except error.NoMergeDestAbort:
1588 except error.NoMergeDestAbort:
1603 # we can maybe update instead
1589 # we can maybe update instead
1604 rev, _a, _b = destutil.destupdate(repo)
1590 rev, _a, _b = destutil.destupdate(repo)
1605 if rev == repo['.'].rev():
1591 if rev == repo['.'].rev():
1606 ui.status(_('nothing to rebase\n'))
1592 ui.status(_('nothing to rebase\n'))
1607 else:
1593 else:
1608 ui.status(_('nothing to rebase - updating instead\n'))
1594 ui.status(_('nothing to rebase - updating instead\n'))
1609 # not passing argument to get the bare update behavior
1595 # not passing argument to get the bare update behavior
1610 # with warning and trumpets
1596 # with warning and trumpets
1611 commands.update(ui, repo)
1597 commands.update(ui, repo)
1612 else:
1598 else:
1613 if opts.get('tool'):
1599 if opts.get('tool'):
1614 raise error.Abort(_('--tool can only be used with --rebase'))
1600 raise error.Abort(_('--tool can only be used with --rebase'))
1615 ret = orig(ui, repo, *args, **opts)
1601 ret = orig(ui, repo, *args, **opts)
1616
1602
1617 return ret
1603 return ret
1618
1604
1619 def _filterobsoleterevs(repo, revs):
1605 def _filterobsoleterevs(repo, revs):
1620 """returns a set of the obsolete revisions in revs"""
1606 """returns a set of the obsolete revisions in revs"""
1621 return set(r for r in revs if repo[r].obsolete())
1607 return set(r for r in revs if repo[r].obsolete())
1622
1608
1623 def _computeobsoletenotrebased(repo, rebaseobsrevs, destmap):
1609 def _computeobsoletenotrebased(repo, rebaseobsrevs, destmap):
1624 """return a mapping obsolete => successor for all obsolete nodes to be
1610 """return a mapping obsolete => successor for all obsolete nodes to be
1625 rebased that have a successors in the destination
1611 rebased that have a successors in the destination
1626
1612
1627 obsolete => None entries in the mapping indicate nodes with no successor"""
1613 obsolete => None entries in the mapping indicate nodes with no successor"""
1628 obsoletenotrebased = {}
1614 obsoletenotrebased = {}
1629
1615
1630 assert repo.filtername is None
1616 assert repo.filtername is None
1631 cl = repo.changelog
1617 cl = repo.changelog
1632 nodemap = cl.nodemap
1618 nodemap = cl.nodemap
1633 for srcrev in rebaseobsrevs:
1619 for srcrev in rebaseobsrevs:
1634 srcnode = cl.node(srcrev)
1620 srcnode = cl.node(srcrev)
1635 destnode = cl.node(destmap[srcrev])
1621 destnode = cl.node(destmap[srcrev])
1636 # XXX: more advanced APIs are required to handle split correctly
1622 # XXX: more advanced APIs are required to handle split correctly
1637 successors = list(obsutil.allsuccessors(repo.obsstore, [srcnode]))
1623 successors = list(obsutil.allsuccessors(repo.obsstore, [srcnode]))
1638 if len(successors) == 1:
1624 if len(successors) == 1:
1639 # obsutil.allsuccessors includes node itself. When the list only
1625 # obsutil.allsuccessors includes node itself. When the list only
1640 # contains one element, it means there are no successors.
1626 # contains one element, it means there are no successors.
1641 obsoletenotrebased[srcrev] = None
1627 obsoletenotrebased[srcrev] = None
1642 else:
1628 else:
1643 for succnode in successors:
1629 for succnode in successors:
1644 if succnode == srcnode or succnode not in nodemap:
1630 if succnode == srcnode or succnode not in nodemap:
1645 continue
1631 continue
1646 if cl.isancestor(succnode, destnode):
1632 if cl.isancestor(succnode, destnode):
1647 obsoletenotrebased[srcrev] = nodemap[succnode]
1633 obsoletenotrebased[srcrev] = nodemap[succnode]
1648 break
1634 break
1649
1635
1650 return obsoletenotrebased
1636 return obsoletenotrebased
1651
1637
1652 def summaryhook(ui, repo):
1638 def summaryhook(ui, repo):
1653 if not repo.vfs.exists('rebasestate'):
1639 if not repo.vfs.exists('rebasestate'):
1654 return
1640 return
1655 try:
1641 try:
1656 rbsrt = rebaseruntime(repo, ui, {})
1642 rbsrt = rebaseruntime(repo, ui, {})
1657 rbsrt.restorestatus()
1643 rbsrt.restorestatus()
1658 state = rbsrt.state
1644 state = rbsrt.state
1659 except error.RepoLookupError:
1645 except error.RepoLookupError:
1660 # i18n: column positioning for "hg summary"
1646 # i18n: column positioning for "hg summary"
1661 msg = _('rebase: (use "hg rebase --abort" to clear broken state)\n')
1647 msg = _('rebase: (use "hg rebase --abort" to clear broken state)\n')
1662 ui.write(msg)
1648 ui.write(msg)
1663 return
1649 return
1664 numrebased = len([i for i in state.itervalues() if i >= 0])
1650 numrebased = len([i for i in state.itervalues() if i >= 0])
1665 # i18n: column positioning for "hg summary"
1651 # i18n: column positioning for "hg summary"
1666 ui.write(_('rebase: %s, %s (rebase --continue)\n') %
1652 ui.write(_('rebase: %s, %s (rebase --continue)\n') %
1667 (ui.label(_('%d rebased'), 'rebase.rebased') % numrebased,
1653 (ui.label(_('%d rebased'), 'rebase.rebased') % numrebased,
1668 ui.label(_('%d remaining'), 'rebase.remaining') %
1654 ui.label(_('%d remaining'), 'rebase.remaining') %
1669 (len(state) - numrebased)))
1655 (len(state) - numrebased)))
1670
1656
1671 def uisetup(ui):
1657 def uisetup(ui):
1672 #Replace pull with a decorator to provide --rebase option
1658 #Replace pull with a decorator to provide --rebase option
1673 entry = extensions.wrapcommand(commands.table, 'pull', pullrebase)
1659 entry = extensions.wrapcommand(commands.table, 'pull', pullrebase)
1674 entry[1].append(('', 'rebase', None,
1660 entry[1].append(('', 'rebase', None,
1675 _("rebase working directory to branch head")))
1661 _("rebase working directory to branch head")))
1676 entry[1].append(('t', 'tool', '',
1662 entry[1].append(('t', 'tool', '',
1677 _("specify merge tool for rebase")))
1663 _("specify merge tool for rebase")))
1678 cmdutil.summaryhooks.add('rebase', summaryhook)
1664 cmdutil.summaryhooks.add('rebase', summaryhook)
1679 cmdutil.unfinishedstates.append(
1665 cmdutil.unfinishedstates.append(
1680 ['rebasestate', False, False, _('rebase in progress'),
1666 ['rebasestate', False, False, _('rebase in progress'),
1681 _("use 'hg rebase --continue' or 'hg rebase --abort'")])
1667 _("use 'hg rebase --continue' or 'hg rebase --abort'")])
1682 cmdutil.afterresolvedstates.append(
1668 cmdutil.afterresolvedstates.append(
1683 ['rebasestate', _('hg rebase --continue')])
1669 ['rebasestate', _('hg rebase --continue')])
@@ -1,1087 +1,1100 b''
1 # configitems.py - centralized declaration of configuration option
1 # configitems.py - centralized declaration of configuration option
2 #
2 #
3 # Copyright 2017 Pierre-Yves David <pierre-yves.david@octobus.net>
3 # Copyright 2017 Pierre-Yves David <pierre-yves.david@octobus.net>
4 #
4 #
5 # This software may be used and distributed according to the terms of the
5 # This software may be used and distributed according to the terms of the
6 # GNU General Public License version 2 or any later version.
6 # GNU General Public License version 2 or any later version.
7
7
8 from __future__ import absolute_import
8 from __future__ import absolute_import
9
9
10 import functools
10 import functools
11 import re
11 import re
12
12
13 from . import (
13 from . import (
14 encoding,
14 encoding,
15 error,
15 error,
16 )
16 )
17
17
18 def loadconfigtable(ui, extname, configtable):
18 def loadconfigtable(ui, extname, configtable):
19 """update config item known to the ui with the extension ones"""
19 """update config item known to the ui with the extension ones"""
20 for section, items in configtable.items():
20 for section, items in configtable.items():
21 knownitems = ui._knownconfig.setdefault(section, itemregister())
21 knownitems = ui._knownconfig.setdefault(section, itemregister())
22 knownkeys = set(knownitems)
22 knownkeys = set(knownitems)
23 newkeys = set(items)
23 newkeys = set(items)
24 for key in sorted(knownkeys & newkeys):
24 for key in sorted(knownkeys & newkeys):
25 msg = "extension '%s' overwrite config item '%s.%s'"
25 msg = "extension '%s' overwrite config item '%s.%s'"
26 msg %= (extname, section, key)
26 msg %= (extname, section, key)
27 ui.develwarn(msg, config='warn-config')
27 ui.develwarn(msg, config='warn-config')
28
28
29 knownitems.update(items)
29 knownitems.update(items)
30
30
31 class configitem(object):
31 class configitem(object):
32 """represent a known config item
32 """represent a known config item
33
33
34 :section: the official config section where to find this item,
34 :section: the official config section where to find this item,
35 :name: the official name within the section,
35 :name: the official name within the section,
36 :default: default value for this item,
36 :default: default value for this item,
37 :alias: optional list of tuples as alternatives,
37 :alias: optional list of tuples as alternatives,
38 :generic: this is a generic definition, match name using regular expression.
38 :generic: this is a generic definition, match name using regular expression.
39 """
39 """
40
40
41 def __init__(self, section, name, default=None, alias=(),
41 def __init__(self, section, name, default=None, alias=(),
42 generic=False, priority=0):
42 generic=False, priority=0):
43 self.section = section
43 self.section = section
44 self.name = name
44 self.name = name
45 self.default = default
45 self.default = default
46 self.alias = list(alias)
46 self.alias = list(alias)
47 self.generic = generic
47 self.generic = generic
48 self.priority = priority
48 self.priority = priority
49 self._re = None
49 self._re = None
50 if generic:
50 if generic:
51 self._re = re.compile(self.name)
51 self._re = re.compile(self.name)
52
52
53 class itemregister(dict):
53 class itemregister(dict):
54 """A specialized dictionary that can handle wild-card selection"""
54 """A specialized dictionary that can handle wild-card selection"""
55
55
56 def __init__(self):
56 def __init__(self):
57 super(itemregister, self).__init__()
57 super(itemregister, self).__init__()
58 self._generics = set()
58 self._generics = set()
59
59
60 def update(self, other):
60 def update(self, other):
61 super(itemregister, self).update(other)
61 super(itemregister, self).update(other)
62 self._generics.update(other._generics)
62 self._generics.update(other._generics)
63
63
64 def __setitem__(self, key, item):
64 def __setitem__(self, key, item):
65 super(itemregister, self).__setitem__(key, item)
65 super(itemregister, self).__setitem__(key, item)
66 if item.generic:
66 if item.generic:
67 self._generics.add(item)
67 self._generics.add(item)
68
68
69 def get(self, key):
69 def get(self, key):
70 if key in self:
70 if key in self:
71 return self[key]
71 return self[key]
72
72
73 # search for a matching generic item
73 # search for a matching generic item
74 generics = sorted(self._generics, key=(lambda x: (x.priority, x.name)))
74 generics = sorted(self._generics, key=(lambda x: (x.priority, x.name)))
75 for item in generics:
75 for item in generics:
76 if item._re.match(key):
76 if item._re.match(key):
77 return item
77 return item
78
78
79 # fallback to dict get
79 # fallback to dict get
80 return super(itemregister, self).get(key)
80 return super(itemregister, self).get(key)
81
81
82 coreitems = {}
82 coreitems = {}
83
83
84 def _register(configtable, *args, **kwargs):
84 def _register(configtable, *args, **kwargs):
85 item = configitem(*args, **kwargs)
85 item = configitem(*args, **kwargs)
86 section = configtable.setdefault(item.section, itemregister())
86 section = configtable.setdefault(item.section, itemregister())
87 if item.name in section:
87 if item.name in section:
88 msg = "duplicated config item registration for '%s.%s'"
88 msg = "duplicated config item registration for '%s.%s'"
89 raise error.ProgrammingError(msg % (item.section, item.name))
89 raise error.ProgrammingError(msg % (item.section, item.name))
90 section[item.name] = item
90 section[item.name] = item
91
91
92 # special value for case where the default is derived from other values
92 # special value for case where the default is derived from other values
93 dynamicdefault = object()
93 dynamicdefault = object()
94
94
95 # Registering actual config items
95 # Registering actual config items
96
96
97 def getitemregister(configtable):
97 def getitemregister(configtable):
98 return functools.partial(_register, configtable)
98 return functools.partial(_register, configtable)
99
99
100 coreconfigitem = getitemregister(coreitems)
100 coreconfigitem = getitemregister(coreitems)
101
101
102 coreconfigitem('alias', '.*',
102 coreconfigitem('alias', '.*',
103 default=None,
103 default=None,
104 generic=True,
104 generic=True,
105 )
105 )
106 coreconfigitem('annotate', 'nodates',
106 coreconfigitem('annotate', 'nodates',
107 default=False,
107 default=False,
108 )
108 )
109 coreconfigitem('annotate', 'showfunc',
109 coreconfigitem('annotate', 'showfunc',
110 default=False,
110 default=False,
111 )
111 )
112 coreconfigitem('annotate', 'unified',
112 coreconfigitem('annotate', 'unified',
113 default=None,
113 default=None,
114 )
114 )
115 coreconfigitem('annotate', 'git',
115 coreconfigitem('annotate', 'git',
116 default=False,
116 default=False,
117 )
117 )
118 coreconfigitem('annotate', 'ignorews',
118 coreconfigitem('annotate', 'ignorews',
119 default=False,
119 default=False,
120 )
120 )
121 coreconfigitem('annotate', 'ignorewsamount',
121 coreconfigitem('annotate', 'ignorewsamount',
122 default=False,
122 default=False,
123 )
123 )
124 coreconfigitem('annotate', 'ignoreblanklines',
124 coreconfigitem('annotate', 'ignoreblanklines',
125 default=False,
125 default=False,
126 )
126 )
127 coreconfigitem('annotate', 'ignorewseol',
127 coreconfigitem('annotate', 'ignorewseol',
128 default=False,
128 default=False,
129 )
129 )
130 coreconfigitem('annotate', 'nobinary',
130 coreconfigitem('annotate', 'nobinary',
131 default=False,
131 default=False,
132 )
132 )
133 coreconfigitem('annotate', 'noprefix',
133 coreconfigitem('annotate', 'noprefix',
134 default=False,
134 default=False,
135 )
135 )
136 coreconfigitem('auth', 'cookiefile',
136 coreconfigitem('auth', 'cookiefile',
137 default=None,
137 default=None,
138 )
138 )
139 # bookmarks.pushing: internal hack for discovery
139 # bookmarks.pushing: internal hack for discovery
140 coreconfigitem('bookmarks', 'pushing',
140 coreconfigitem('bookmarks', 'pushing',
141 default=list,
141 default=list,
142 )
142 )
143 # bundle.mainreporoot: internal hack for bundlerepo
143 # bundle.mainreporoot: internal hack for bundlerepo
144 coreconfigitem('bundle', 'mainreporoot',
144 coreconfigitem('bundle', 'mainreporoot',
145 default='',
145 default='',
146 )
146 )
147 # bundle.reorder: experimental config
147 # bundle.reorder: experimental config
148 coreconfigitem('bundle', 'reorder',
148 coreconfigitem('bundle', 'reorder',
149 default='auto',
149 default='auto',
150 )
150 )
151 coreconfigitem('censor', 'policy',
151 coreconfigitem('censor', 'policy',
152 default='abort',
152 default='abort',
153 )
153 )
154 coreconfigitem('chgserver', 'idletimeout',
154 coreconfigitem('chgserver', 'idletimeout',
155 default=3600,
155 default=3600,
156 )
156 )
157 coreconfigitem('chgserver', 'skiphash',
157 coreconfigitem('chgserver', 'skiphash',
158 default=False,
158 default=False,
159 )
159 )
160 coreconfigitem('cmdserver', 'log',
160 coreconfigitem('cmdserver', 'log',
161 default=None,
161 default=None,
162 )
162 )
163 coreconfigitem('color', '.*',
163 coreconfigitem('color', '.*',
164 default=None,
164 default=None,
165 generic=True,
165 generic=True,
166 )
166 )
167 coreconfigitem('color', 'mode',
167 coreconfigitem('color', 'mode',
168 default='auto',
168 default='auto',
169 )
169 )
170 coreconfigitem('color', 'pagermode',
170 coreconfigitem('color', 'pagermode',
171 default=dynamicdefault,
171 default=dynamicdefault,
172 )
172 )
173 coreconfigitem('commands', 'status.relative',
173 coreconfigitem('commands', 'status.relative',
174 default=False,
174 default=False,
175 )
175 )
176 coreconfigitem('commands', 'status.skipstates',
176 coreconfigitem('commands', 'status.skipstates',
177 default=[],
177 default=[],
178 )
178 )
179 coreconfigitem('commands', 'status.verbose',
179 coreconfigitem('commands', 'status.verbose',
180 default=False,
180 default=False,
181 )
181 )
182 coreconfigitem('commands', 'update.check',
182 coreconfigitem('commands', 'update.check',
183 default=None,
183 default=None,
184 # Deprecated, remove after 4.4 release
184 # Deprecated, remove after 4.4 release
185 alias=[('experimental', 'updatecheck')]
185 alias=[('experimental', 'updatecheck')]
186 )
186 )
187 coreconfigitem('commands', 'update.requiredest',
187 coreconfigitem('commands', 'update.requiredest',
188 default=False,
188 default=False,
189 )
189 )
190 coreconfigitem('committemplate', '.*',
190 coreconfigitem('committemplate', '.*',
191 default=None,
191 default=None,
192 generic=True,
192 generic=True,
193 )
193 )
194 coreconfigitem('debug', 'dirstate.delaywrite',
194 coreconfigitem('debug', 'dirstate.delaywrite',
195 default=0,
195 default=0,
196 )
196 )
197 coreconfigitem('defaults', '.*',
197 coreconfigitem('defaults', '.*',
198 default=None,
198 default=None,
199 generic=True,
199 generic=True,
200 )
200 )
201 coreconfigitem('devel', 'all-warnings',
201 coreconfigitem('devel', 'all-warnings',
202 default=False,
202 default=False,
203 )
203 )
204 coreconfigitem('devel', 'bundle2.debug',
204 coreconfigitem('devel', 'bundle2.debug',
205 default=False,
205 default=False,
206 )
206 )
207 coreconfigitem('devel', 'cache-vfs',
207 coreconfigitem('devel', 'cache-vfs',
208 default=None,
208 default=None,
209 )
209 )
210 coreconfigitem('devel', 'check-locks',
210 coreconfigitem('devel', 'check-locks',
211 default=False,
211 default=False,
212 )
212 )
213 coreconfigitem('devel', 'check-relroot',
213 coreconfigitem('devel', 'check-relroot',
214 default=False,
214 default=False,
215 )
215 )
216 coreconfigitem('devel', 'default-date',
216 coreconfigitem('devel', 'default-date',
217 default=None,
217 default=None,
218 )
218 )
219 coreconfigitem('devel', 'deprec-warn',
219 coreconfigitem('devel', 'deprec-warn',
220 default=False,
220 default=False,
221 )
221 )
222 coreconfigitem('devel', 'disableloaddefaultcerts',
222 coreconfigitem('devel', 'disableloaddefaultcerts',
223 default=False,
223 default=False,
224 )
224 )
225 coreconfigitem('devel', 'warn-empty-changegroup',
225 coreconfigitem('devel', 'warn-empty-changegroup',
226 default=False,
226 default=False,
227 )
227 )
228 coreconfigitem('devel', 'legacy.exchange',
228 coreconfigitem('devel', 'legacy.exchange',
229 default=list,
229 default=list,
230 )
230 )
231 coreconfigitem('devel', 'servercafile',
231 coreconfigitem('devel', 'servercafile',
232 default='',
232 default='',
233 )
233 )
234 coreconfigitem('devel', 'serverexactprotocol',
234 coreconfigitem('devel', 'serverexactprotocol',
235 default='',
235 default='',
236 )
236 )
237 coreconfigitem('devel', 'serverrequirecert',
237 coreconfigitem('devel', 'serverrequirecert',
238 default=False,
238 default=False,
239 )
239 )
240 coreconfigitem('devel', 'strip-obsmarkers',
240 coreconfigitem('devel', 'strip-obsmarkers',
241 default=True,
241 default=True,
242 )
242 )
243 coreconfigitem('devel', 'warn-config',
243 coreconfigitem('devel', 'warn-config',
244 default=None,
244 default=None,
245 )
245 )
246 coreconfigitem('devel', 'warn-config-default',
246 coreconfigitem('devel', 'warn-config-default',
247 default=None,
247 default=None,
248 )
248 )
249 coreconfigitem('devel', 'user.obsmarker',
249 coreconfigitem('devel', 'user.obsmarker',
250 default=None,
250 default=None,
251 )
251 )
252 coreconfigitem('diff', 'nodates',
252 coreconfigitem('diff', 'nodates',
253 default=False,
253 default=False,
254 )
254 )
255 coreconfigitem('diff', 'showfunc',
255 coreconfigitem('diff', 'showfunc',
256 default=False,
256 default=False,
257 )
257 )
258 coreconfigitem('diff', 'unified',
258 coreconfigitem('diff', 'unified',
259 default=None,
259 default=None,
260 )
260 )
261 coreconfigitem('diff', 'git',
261 coreconfigitem('diff', 'git',
262 default=False,
262 default=False,
263 )
263 )
264 coreconfigitem('diff', 'ignorews',
264 coreconfigitem('diff', 'ignorews',
265 default=False,
265 default=False,
266 )
266 )
267 coreconfigitem('diff', 'ignorewsamount',
267 coreconfigitem('diff', 'ignorewsamount',
268 default=False,
268 default=False,
269 )
269 )
270 coreconfigitem('diff', 'ignoreblanklines',
270 coreconfigitem('diff', 'ignoreblanklines',
271 default=False,
271 default=False,
272 )
272 )
273 coreconfigitem('diff', 'ignorewseol',
273 coreconfigitem('diff', 'ignorewseol',
274 default=False,
274 default=False,
275 )
275 )
276 coreconfigitem('diff', 'nobinary',
276 coreconfigitem('diff', 'nobinary',
277 default=False,
277 default=False,
278 )
278 )
279 coreconfigitem('diff', 'noprefix',
279 coreconfigitem('diff', 'noprefix',
280 default=False,
280 default=False,
281 )
281 )
282 coreconfigitem('email', 'bcc',
282 coreconfigitem('email', 'bcc',
283 default=None,
283 default=None,
284 )
284 )
285 coreconfigitem('email', 'cc',
285 coreconfigitem('email', 'cc',
286 default=None,
286 default=None,
287 )
287 )
288 coreconfigitem('email', 'charsets',
288 coreconfigitem('email', 'charsets',
289 default=list,
289 default=list,
290 )
290 )
291 coreconfigitem('email', 'from',
291 coreconfigitem('email', 'from',
292 default=None,
292 default=None,
293 )
293 )
294 coreconfigitem('email', 'method',
294 coreconfigitem('email', 'method',
295 default='smtp',
295 default='smtp',
296 )
296 )
297 coreconfigitem('email', 'reply-to',
297 coreconfigitem('email', 'reply-to',
298 default=None,
298 default=None,
299 )
299 )
300 coreconfigitem('experimental', 'allowdivergence',
300 coreconfigitem('experimental', 'allowdivergence',
301 default=False,
301 default=False,
302 )
302 )
303 coreconfigitem('experimental', 'archivemetatemplate',
303 coreconfigitem('experimental', 'archivemetatemplate',
304 default=dynamicdefault,
304 default=dynamicdefault,
305 )
305 )
306 coreconfigitem('experimental', 'bundle-phases',
306 coreconfigitem('experimental', 'bundle-phases',
307 default=False,
307 default=False,
308 )
308 )
309 coreconfigitem('experimental', 'bundle2-advertise',
309 coreconfigitem('experimental', 'bundle2-advertise',
310 default=True,
310 default=True,
311 )
311 )
312 coreconfigitem('experimental', 'bundle2-output-capture',
312 coreconfigitem('experimental', 'bundle2-output-capture',
313 default=False,
313 default=False,
314 )
314 )
315 coreconfigitem('experimental', 'bundle2.pushback',
315 coreconfigitem('experimental', 'bundle2.pushback',
316 default=False,
316 default=False,
317 )
317 )
318 coreconfigitem('experimental', 'bundle2lazylocking',
318 coreconfigitem('experimental', 'bundle2lazylocking',
319 default=False,
319 default=False,
320 )
320 )
321 coreconfigitem('experimental', 'bundlecomplevel',
321 coreconfigitem('experimental', 'bundlecomplevel',
322 default=None,
322 default=None,
323 )
323 )
324 coreconfigitem('experimental', 'changegroup3',
324 coreconfigitem('experimental', 'changegroup3',
325 default=False,
325 default=False,
326 )
326 )
327 coreconfigitem('experimental', 'clientcompressionengines',
327 coreconfigitem('experimental', 'clientcompressionengines',
328 default=list,
328 default=list,
329 )
329 )
330 coreconfigitem('experimental', 'copytrace',
330 coreconfigitem('experimental', 'copytrace',
331 default='on',
331 default='on',
332 )
332 )
333 coreconfigitem('experimental', 'copytrace.sourcecommitlimit',
333 coreconfigitem('experimental', 'copytrace.sourcecommitlimit',
334 default=100,
334 default=100,
335 )
335 )
336 coreconfigitem('experimental', 'crecordtest',
336 coreconfigitem('experimental', 'crecordtest',
337 default=None,
337 default=None,
338 )
338 )
339 coreconfigitem('experimental', 'editortmpinhg',
339 coreconfigitem('experimental', 'editortmpinhg',
340 default=False,
340 default=False,
341 )
341 )
342 coreconfigitem('experimental', 'maxdeltachainspan',
342 coreconfigitem('experimental', 'maxdeltachainspan',
343 default=-1,
343 default=-1,
344 )
344 )
345 coreconfigitem('experimental', 'mmapindexthreshold',
345 coreconfigitem('experimental', 'mmapindexthreshold',
346 default=None,
346 default=None,
347 )
347 )
348 coreconfigitem('experimental', 'nonnormalparanoidcheck',
348 coreconfigitem('experimental', 'nonnormalparanoidcheck',
349 default=False,
349 default=False,
350 )
350 )
351 coreconfigitem('experimental', 'effect-flags',
351 coreconfigitem('experimental', 'effect-flags',
352 default=False,
352 default=False,
353 )
353 )
354 coreconfigitem('experimental', 'stabilization',
354 coreconfigitem('experimental', 'stabilization',
355 default=list,
355 default=list,
356 alias=[('experimental', 'evolution')],
356 alias=[('experimental', 'evolution')],
357 )
357 )
358 coreconfigitem('experimental', 'stabilization.bundle-obsmarker',
358 coreconfigitem('experimental', 'stabilization.bundle-obsmarker',
359 default=False,
359 default=False,
360 alias=[('experimental', 'evolution.bundle-obsmarker')],
360 alias=[('experimental', 'evolution.bundle-obsmarker')],
361 )
361 )
362 coreconfigitem('experimental', 'stabilization.track-operation',
362 coreconfigitem('experimental', 'stabilization.track-operation',
363 default=True,
363 default=True,
364 alias=[('experimental', 'evolution.track-operation')]
364 alias=[('experimental', 'evolution.track-operation')]
365 )
365 )
366 coreconfigitem('experimental', 'exportableenviron',
366 coreconfigitem('experimental', 'exportableenviron',
367 default=list,
367 default=list,
368 )
368 )
369 coreconfigitem('experimental', 'extendedheader.index',
369 coreconfigitem('experimental', 'extendedheader.index',
370 default=None,
370 default=None,
371 )
371 )
372 coreconfigitem('experimental', 'extendedheader.similarity',
372 coreconfigitem('experimental', 'extendedheader.similarity',
373 default=False,
373 default=False,
374 )
374 )
375 coreconfigitem('experimental', 'format.compression',
375 coreconfigitem('experimental', 'format.compression',
376 default='zlib',
376 default='zlib',
377 )
377 )
378 coreconfigitem('experimental', 'graphshorten',
378 coreconfigitem('experimental', 'graphshorten',
379 default=False,
379 default=False,
380 )
380 )
381 coreconfigitem('experimental', 'graphstyle.parent',
381 coreconfigitem('experimental', 'graphstyle.parent',
382 default=dynamicdefault,
382 default=dynamicdefault,
383 )
383 )
384 coreconfigitem('experimental', 'graphstyle.missing',
384 coreconfigitem('experimental', 'graphstyle.missing',
385 default=dynamicdefault,
385 default=dynamicdefault,
386 )
386 )
387 coreconfigitem('experimental', 'graphstyle.grandparent',
387 coreconfigitem('experimental', 'graphstyle.grandparent',
388 default=dynamicdefault,
388 default=dynamicdefault,
389 )
389 )
390 coreconfigitem('experimental', 'hook-track-tags',
390 coreconfigitem('experimental', 'hook-track-tags',
391 default=False,
391 default=False,
392 )
392 )
393 coreconfigitem('experimental', 'httppostargs',
393 coreconfigitem('experimental', 'httppostargs',
394 default=False,
394 default=False,
395 )
395 )
396 coreconfigitem('experimental', 'manifestv2',
396 coreconfigitem('experimental', 'manifestv2',
397 default=False,
397 default=False,
398 )
398 )
399 coreconfigitem('experimental', 'mergedriver',
399 coreconfigitem('experimental', 'mergedriver',
400 default=None,
400 default=None,
401 )
401 )
402 coreconfigitem('experimental', 'obsmarkers-exchange-debug',
402 coreconfigitem('experimental', 'obsmarkers-exchange-debug',
403 default=False,
403 default=False,
404 )
404 )
405 coreconfigitem('experimental', 'rebase.multidest',
405 coreconfigitem('experimental', 'rebase.multidest',
406 default=False,
406 default=False,
407 )
407 )
408 coreconfigitem('experimental', 'revertalternateinteractivemode',
408 coreconfigitem('experimental', 'revertalternateinteractivemode',
409 default=True,
409 default=True,
410 )
410 )
411 coreconfigitem('experimental', 'revlogv2',
411 coreconfigitem('experimental', 'revlogv2',
412 default=None,
412 default=None,
413 )
413 )
414 coreconfigitem('experimental', 'spacemovesdown',
414 coreconfigitem('experimental', 'spacemovesdown',
415 default=False,
415 default=False,
416 )
416 )
417 coreconfigitem('experimental', 'sparse-read',
417 coreconfigitem('experimental', 'sparse-read',
418 default=False,
418 default=False,
419 )
419 )
420 coreconfigitem('experimental', 'sparse-read.density-threshold',
420 coreconfigitem('experimental', 'sparse-read.density-threshold',
421 default=0.25,
421 default=0.25,
422 )
422 )
423 coreconfigitem('experimental', 'sparse-read.min-block-size',
423 coreconfigitem('experimental', 'sparse-read.min-block-size',
424 default='256K',
424 default='256K',
425 )
425 )
426 coreconfigitem('experimental', 'treemanifest',
426 coreconfigitem('experimental', 'treemanifest',
427 default=False,
427 default=False,
428 )
428 )
429 coreconfigitem('extensions', '.*',
429 coreconfigitem('extensions', '.*',
430 default=None,
430 default=None,
431 generic=True,
431 generic=True,
432 )
432 )
433 coreconfigitem('extdata', '.*',
433 coreconfigitem('extdata', '.*',
434 default=None,
434 default=None,
435 generic=True,
435 generic=True,
436 )
436 )
437 coreconfigitem('format', 'aggressivemergedeltas',
437 coreconfigitem('format', 'aggressivemergedeltas',
438 default=False,
438 default=False,
439 )
439 )
440 coreconfigitem('format', 'chunkcachesize',
440 coreconfigitem('format', 'chunkcachesize',
441 default=None,
441 default=None,
442 )
442 )
443 coreconfigitem('format', 'dotencode',
443 coreconfigitem('format', 'dotencode',
444 default=True,
444 default=True,
445 )
445 )
446 coreconfigitem('format', 'generaldelta',
446 coreconfigitem('format', 'generaldelta',
447 default=False,
447 default=False,
448 )
448 )
449 coreconfigitem('format', 'manifestcachesize',
449 coreconfigitem('format', 'manifestcachesize',
450 default=None,
450 default=None,
451 )
451 )
452 coreconfigitem('format', 'maxchainlen',
452 coreconfigitem('format', 'maxchainlen',
453 default=None,
453 default=None,
454 )
454 )
455 coreconfigitem('format', 'obsstore-version',
455 coreconfigitem('format', 'obsstore-version',
456 default=None,
456 default=None,
457 )
457 )
458 coreconfigitem('format', 'usefncache',
458 coreconfigitem('format', 'usefncache',
459 default=True,
459 default=True,
460 )
460 )
461 coreconfigitem('format', 'usegeneraldelta',
461 coreconfigitem('format', 'usegeneraldelta',
462 default=True,
462 default=True,
463 )
463 )
464 coreconfigitem('format', 'usestore',
464 coreconfigitem('format', 'usestore',
465 default=True,
465 default=True,
466 )
466 )
467 coreconfigitem('hooks', '.*',
467 coreconfigitem('hooks', '.*',
468 default=dynamicdefault,
468 default=dynamicdefault,
469 generic=True,
469 generic=True,
470 )
470 )
471 coreconfigitem('hgweb-paths', '.*',
471 coreconfigitem('hgweb-paths', '.*',
472 default=list,
472 default=list,
473 generic=True,
473 generic=True,
474 )
474 )
475 coreconfigitem('hostfingerprints', '.*',
475 coreconfigitem('hostfingerprints', '.*',
476 default=list,
476 default=list,
477 generic=True,
477 generic=True,
478 )
478 )
479 coreconfigitem('hostsecurity', 'ciphers',
479 coreconfigitem('hostsecurity', 'ciphers',
480 default=None,
480 default=None,
481 )
481 )
482 coreconfigitem('hostsecurity', 'disabletls10warning',
482 coreconfigitem('hostsecurity', 'disabletls10warning',
483 default=False,
483 default=False,
484 )
484 )
485 coreconfigitem('hostsecurity', 'minimumprotocol',
485 coreconfigitem('hostsecurity', 'minimumprotocol',
486 default=dynamicdefault,
486 default=dynamicdefault,
487 )
487 )
488 coreconfigitem('hostsecurity', '.*:minimumprotocol$',
488 coreconfigitem('hostsecurity', '.*:minimumprotocol$',
489 default=dynamicdefault,
489 default=dynamicdefault,
490 generic=True,
490 generic=True,
491 )
491 )
492 coreconfigitem('hostsecurity', '.*:ciphers$',
492 coreconfigitem('hostsecurity', '.*:ciphers$',
493 default=dynamicdefault,
493 default=dynamicdefault,
494 generic=True,
494 generic=True,
495 )
495 )
496 coreconfigitem('hostsecurity', '.*:fingerprints$',
496 coreconfigitem('hostsecurity', '.*:fingerprints$',
497 default=list,
497 default=list,
498 generic=True,
498 generic=True,
499 )
499 )
500 coreconfigitem('hostsecurity', '.*:verifycertsfile$',
500 coreconfigitem('hostsecurity', '.*:verifycertsfile$',
501 default=None,
501 default=None,
502 generic=True,
502 generic=True,
503 )
503 )
504
504
505 coreconfigitem('http_proxy', 'always',
505 coreconfigitem('http_proxy', 'always',
506 default=False,
506 default=False,
507 )
507 )
508 coreconfigitem('http_proxy', 'host',
508 coreconfigitem('http_proxy', 'host',
509 default=None,
509 default=None,
510 )
510 )
511 coreconfigitem('http_proxy', 'no',
511 coreconfigitem('http_proxy', 'no',
512 default=list,
512 default=list,
513 )
513 )
514 coreconfigitem('http_proxy', 'passwd',
514 coreconfigitem('http_proxy', 'passwd',
515 default=None,
515 default=None,
516 )
516 )
517 coreconfigitem('http_proxy', 'user',
517 coreconfigitem('http_proxy', 'user',
518 default=None,
518 default=None,
519 )
519 )
520 coreconfigitem('logtoprocess', 'commandexception',
520 coreconfigitem('logtoprocess', 'commandexception',
521 default=None,
521 default=None,
522 )
522 )
523 coreconfigitem('logtoprocess', 'commandfinish',
523 coreconfigitem('logtoprocess', 'commandfinish',
524 default=None,
524 default=None,
525 )
525 )
526 coreconfigitem('logtoprocess', 'command',
526 coreconfigitem('logtoprocess', 'command',
527 default=None,
527 default=None,
528 )
528 )
529 coreconfigitem('logtoprocess', 'develwarn',
529 coreconfigitem('logtoprocess', 'develwarn',
530 default=None,
530 default=None,
531 )
531 )
532 coreconfigitem('logtoprocess', 'uiblocked',
532 coreconfigitem('logtoprocess', 'uiblocked',
533 default=None,
533 default=None,
534 )
534 )
535 coreconfigitem('merge', 'checkunknown',
535 coreconfigitem('merge', 'checkunknown',
536 default='abort',
536 default='abort',
537 )
537 )
538 coreconfigitem('merge', 'checkignored',
538 coreconfigitem('merge', 'checkignored',
539 default='abort',
539 default='abort',
540 )
540 )
541 coreconfigitem('merge', 'followcopies',
541 coreconfigitem('merge', 'followcopies',
542 default=True,
542 default=True,
543 )
543 )
544 coreconfigitem('merge', 'on-failure',
544 coreconfigitem('merge', 'on-failure',
545 default='continue',
545 default='continue',
546 )
546 )
547 coreconfigitem('merge', 'preferancestor',
547 coreconfigitem('merge', 'preferancestor',
548 default=lambda: ['*'],
548 default=lambda: ['*'],
549 )
549 )
550 coreconfigitem('merge-tools', '.*',
550 coreconfigitem('merge-tools', '.*',
551 default=None,
551 default=None,
552 generic=True,
552 generic=True,
553 )
553 )
554 coreconfigitem('merge-tools', r'.*\.args$',
554 coreconfigitem('merge-tools', r'.*\.args$',
555 default="$local $base $other",
555 default="$local $base $other",
556 generic=True,
556 generic=True,
557 priority=-1,
557 priority=-1,
558 )
558 )
559 coreconfigitem('merge-tools', r'.*\.binary$',
559 coreconfigitem('merge-tools', r'.*\.binary$',
560 default=False,
560 default=False,
561 generic=True,
561 generic=True,
562 priority=-1,
562 priority=-1,
563 )
563 )
564 coreconfigitem('merge-tools', r'.*\.check$',
564 coreconfigitem('merge-tools', r'.*\.check$',
565 default=list,
565 default=list,
566 generic=True,
566 generic=True,
567 priority=-1,
567 priority=-1,
568 )
568 )
569 coreconfigitem('merge-tools', r'.*\.checkchanged$',
569 coreconfigitem('merge-tools', r'.*\.checkchanged$',
570 default=False,
570 default=False,
571 generic=True,
571 generic=True,
572 priority=-1,
572 priority=-1,
573 )
573 )
574 coreconfigitem('merge-tools', r'.*\.executable$',
574 coreconfigitem('merge-tools', r'.*\.executable$',
575 default=dynamicdefault,
575 default=dynamicdefault,
576 generic=True,
576 generic=True,
577 priority=-1,
577 priority=-1,
578 )
578 )
579 coreconfigitem('merge-tools', r'.*\.fixeol$',
579 coreconfigitem('merge-tools', r'.*\.fixeol$',
580 default=False,
580 default=False,
581 generic=True,
581 generic=True,
582 priority=-1,
582 priority=-1,
583 )
583 )
584 coreconfigitem('merge-tools', r'.*\.gui$',
584 coreconfigitem('merge-tools', r'.*\.gui$',
585 default=False,
585 default=False,
586 generic=True,
586 generic=True,
587 priority=-1,
587 priority=-1,
588 )
588 )
589 coreconfigitem('merge-tools', r'.*\.priority$',
589 coreconfigitem('merge-tools', r'.*\.priority$',
590 default=0,
590 default=0,
591 generic=True,
591 generic=True,
592 priority=-1,
592 priority=-1,
593 )
593 )
594 coreconfigitem('merge-tools', r'.*\.premerge$',
594 coreconfigitem('merge-tools', r'.*\.premerge$',
595 default=dynamicdefault,
595 default=dynamicdefault,
596 generic=True,
596 generic=True,
597 priority=-1,
597 priority=-1,
598 )
598 )
599 coreconfigitem('merge-tools', r'.*\.symlink$',
599 coreconfigitem('merge-tools', r'.*\.symlink$',
600 default=False,
600 default=False,
601 generic=True,
601 generic=True,
602 priority=-1,
602 priority=-1,
603 )
603 )
604 coreconfigitem('pager', 'attend-.*',
604 coreconfigitem('pager', 'attend-.*',
605 default=dynamicdefault,
605 default=dynamicdefault,
606 generic=True,
606 generic=True,
607 )
607 )
608 coreconfigitem('pager', 'ignore',
608 coreconfigitem('pager', 'ignore',
609 default=list,
609 default=list,
610 )
610 )
611 coreconfigitem('pager', 'pager',
611 coreconfigitem('pager', 'pager',
612 default=dynamicdefault,
612 default=dynamicdefault,
613 )
613 )
614 coreconfigitem('patch', 'eol',
614 coreconfigitem('patch', 'eol',
615 default='strict',
615 default='strict',
616 )
616 )
617 coreconfigitem('patch', 'fuzz',
617 coreconfigitem('patch', 'fuzz',
618 default=2,
618 default=2,
619 )
619 )
620 coreconfigitem('paths', 'default',
620 coreconfigitem('paths', 'default',
621 default=None,
621 default=None,
622 )
622 )
623 coreconfigitem('paths', 'default-push',
623 coreconfigitem('paths', 'default-push',
624 default=None,
624 default=None,
625 )
625 )
626 coreconfigitem('paths', '.*',
626 coreconfigitem('paths', '.*',
627 default=None,
627 default=None,
628 generic=True,
628 generic=True,
629 )
629 )
630 coreconfigitem('phases', 'checksubrepos',
630 coreconfigitem('phases', 'checksubrepos',
631 default='follow',
631 default='follow',
632 )
632 )
633 coreconfigitem('phases', 'new-commit',
633 coreconfigitem('phases', 'new-commit',
634 default='draft',
634 default='draft',
635 )
635 )
636 coreconfigitem('phases', 'publish',
636 coreconfigitem('phases', 'publish',
637 default=True,
637 default=True,
638 )
638 )
639 coreconfigitem('profiling', 'enabled',
639 coreconfigitem('profiling', 'enabled',
640 default=False,
640 default=False,
641 )
641 )
642 coreconfigitem('profiling', 'format',
642 coreconfigitem('profiling', 'format',
643 default='text',
643 default='text',
644 )
644 )
645 coreconfigitem('profiling', 'freq',
645 coreconfigitem('profiling', 'freq',
646 default=1000,
646 default=1000,
647 )
647 )
648 coreconfigitem('profiling', 'limit',
648 coreconfigitem('profiling', 'limit',
649 default=30,
649 default=30,
650 )
650 )
651 coreconfigitem('profiling', 'nested',
651 coreconfigitem('profiling', 'nested',
652 default=0,
652 default=0,
653 )
653 )
654 coreconfigitem('profiling', 'output',
654 coreconfigitem('profiling', 'output',
655 default=None,
655 default=None,
656 )
656 )
657 coreconfigitem('profiling', 'showmax',
657 coreconfigitem('profiling', 'showmax',
658 default=0.999,
658 default=0.999,
659 )
659 )
660 coreconfigitem('profiling', 'showmin',
660 coreconfigitem('profiling', 'showmin',
661 default=dynamicdefault,
661 default=dynamicdefault,
662 )
662 )
663 coreconfigitem('profiling', 'sort',
663 coreconfigitem('profiling', 'sort',
664 default='inlinetime',
664 default='inlinetime',
665 )
665 )
666 coreconfigitem('profiling', 'statformat',
666 coreconfigitem('profiling', 'statformat',
667 default='hotpath',
667 default='hotpath',
668 )
668 )
669 coreconfigitem('profiling', 'type',
669 coreconfigitem('profiling', 'type',
670 default='stat',
670 default='stat',
671 )
671 )
672 coreconfigitem('progress', 'assume-tty',
672 coreconfigitem('progress', 'assume-tty',
673 default=False,
673 default=False,
674 )
674 )
675 coreconfigitem('progress', 'changedelay',
675 coreconfigitem('progress', 'changedelay',
676 default=1,
676 default=1,
677 )
677 )
678 coreconfigitem('progress', 'clear-complete',
678 coreconfigitem('progress', 'clear-complete',
679 default=True,
679 default=True,
680 )
680 )
681 coreconfigitem('progress', 'debug',
681 coreconfigitem('progress', 'debug',
682 default=False,
682 default=False,
683 )
683 )
684 coreconfigitem('progress', 'delay',
684 coreconfigitem('progress', 'delay',
685 default=3,
685 default=3,
686 )
686 )
687 coreconfigitem('progress', 'disable',
687 coreconfigitem('progress', 'disable',
688 default=False,
688 default=False,
689 )
689 )
690 coreconfigitem('progress', 'estimateinterval',
690 coreconfigitem('progress', 'estimateinterval',
691 default=60.0,
691 default=60.0,
692 )
692 )
693 coreconfigitem('progress', 'format',
693 coreconfigitem('progress', 'format',
694 default=lambda: ['topic', 'bar', 'number', 'estimate'],
694 default=lambda: ['topic', 'bar', 'number', 'estimate'],
695 )
695 )
696 coreconfigitem('progress', 'refresh',
696 coreconfigitem('progress', 'refresh',
697 default=0.1,
697 default=0.1,
698 )
698 )
699 coreconfigitem('progress', 'width',
699 coreconfigitem('progress', 'width',
700 default=dynamicdefault,
700 default=dynamicdefault,
701 )
701 )
702 coreconfigitem('push', 'pushvars.server',
702 coreconfigitem('push', 'pushvars.server',
703 default=False,
703 default=False,
704 )
704 )
705 coreconfigitem('server', 'bundle1',
705 coreconfigitem('server', 'bundle1',
706 default=True,
706 default=True,
707 )
707 )
708 coreconfigitem('server', 'bundle1gd',
708 coreconfigitem('server', 'bundle1gd',
709 default=None,
709 default=None,
710 )
710 )
711 coreconfigitem('server', 'bundle1.pull',
711 coreconfigitem('server', 'bundle1.pull',
712 default=None,
712 default=None,
713 )
713 )
714 coreconfigitem('server', 'bundle1gd.pull',
714 coreconfigitem('server', 'bundle1gd.pull',
715 default=None,
715 default=None,
716 )
716 )
717 coreconfigitem('server', 'bundle1.push',
717 coreconfigitem('server', 'bundle1.push',
718 default=None,
718 default=None,
719 )
719 )
720 coreconfigitem('server', 'bundle1gd.push',
720 coreconfigitem('server', 'bundle1gd.push',
721 default=None,
721 default=None,
722 )
722 )
723 coreconfigitem('server', 'compressionengines',
723 coreconfigitem('server', 'compressionengines',
724 default=list,
724 default=list,
725 )
725 )
726 coreconfigitem('server', 'concurrent-push-mode',
726 coreconfigitem('server', 'concurrent-push-mode',
727 default='strict',
727 default='strict',
728 )
728 )
729 coreconfigitem('server', 'disablefullbundle',
729 coreconfigitem('server', 'disablefullbundle',
730 default=False,
730 default=False,
731 )
731 )
732 coreconfigitem('server', 'maxhttpheaderlen',
732 coreconfigitem('server', 'maxhttpheaderlen',
733 default=1024,
733 default=1024,
734 )
734 )
735 coreconfigitem('server', 'preferuncompressed',
735 coreconfigitem('server', 'preferuncompressed',
736 default=False,
736 default=False,
737 )
737 )
738 coreconfigitem('server', 'uncompressed',
738 coreconfigitem('server', 'uncompressed',
739 default=True,
739 default=True,
740 )
740 )
741 coreconfigitem('server', 'uncompressedallowsecret',
741 coreconfigitem('server', 'uncompressedallowsecret',
742 default=False,
742 default=False,
743 )
743 )
744 coreconfigitem('server', 'validate',
744 coreconfigitem('server', 'validate',
745 default=False,
745 default=False,
746 )
746 )
747 coreconfigitem('server', 'zliblevel',
747 coreconfigitem('server', 'zliblevel',
748 default=-1,
748 default=-1,
749 )
749 )
750 coreconfigitem('smtp', 'host',
750 coreconfigitem('smtp', 'host',
751 default=None,
751 default=None,
752 )
752 )
753 coreconfigitem('smtp', 'local_hostname',
753 coreconfigitem('smtp', 'local_hostname',
754 default=None,
754 default=None,
755 )
755 )
756 coreconfigitem('smtp', 'password',
756 coreconfigitem('smtp', 'password',
757 default=None,
757 default=None,
758 )
758 )
759 coreconfigitem('smtp', 'port',
759 coreconfigitem('smtp', 'port',
760 default=dynamicdefault,
760 default=dynamicdefault,
761 )
761 )
762 coreconfigitem('smtp', 'tls',
762 coreconfigitem('smtp', 'tls',
763 default='none',
763 default='none',
764 )
764 )
765 coreconfigitem('smtp', 'username',
765 coreconfigitem('smtp', 'username',
766 default=None,
766 default=None,
767 )
767 )
768 coreconfigitem('sparse', 'missingwarning',
768 coreconfigitem('sparse', 'missingwarning',
769 default=True,
769 default=True,
770 )
770 )
771 coreconfigitem('templates', '.*',
771 coreconfigitem('templates', '.*',
772 default=None,
772 default=None,
773 generic=True,
773 generic=True,
774 )
774 )
775 coreconfigitem('trusted', 'groups',
775 coreconfigitem('trusted', 'groups',
776 default=list,
776 default=list,
777 )
777 )
778 coreconfigitem('trusted', 'users',
778 coreconfigitem('trusted', 'users',
779 default=list,
779 default=list,
780 )
780 )
781 coreconfigitem('ui', '_usedassubrepo',
781 coreconfigitem('ui', '_usedassubrepo',
782 default=False,
782 default=False,
783 )
783 )
784 coreconfigitem('ui', 'allowemptycommit',
784 coreconfigitem('ui', 'allowemptycommit',
785 default=False,
785 default=False,
786 )
786 )
787 coreconfigitem('ui', 'archivemeta',
787 coreconfigitem('ui', 'archivemeta',
788 default=True,
788 default=True,
789 )
789 )
790 coreconfigitem('ui', 'askusername',
790 coreconfigitem('ui', 'askusername',
791 default=False,
791 default=False,
792 )
792 )
793 coreconfigitem('ui', 'clonebundlefallback',
793 coreconfigitem('ui', 'clonebundlefallback',
794 default=False,
794 default=False,
795 )
795 )
796 coreconfigitem('ui', 'clonebundleprefers',
796 coreconfigitem('ui', 'clonebundleprefers',
797 default=list,
797 default=list,
798 )
798 )
799 coreconfigitem('ui', 'clonebundles',
799 coreconfigitem('ui', 'clonebundles',
800 default=True,
800 default=True,
801 )
801 )
802 coreconfigitem('ui', 'color',
802 coreconfigitem('ui', 'color',
803 default='auto',
803 default='auto',
804 )
804 )
805 coreconfigitem('ui', 'commitsubrepos',
805 coreconfigitem('ui', 'commitsubrepos',
806 default=False,
806 default=False,
807 )
807 )
808 coreconfigitem('ui', 'debug',
808 coreconfigitem('ui', 'debug',
809 default=False,
809 default=False,
810 )
810 )
811 coreconfigitem('ui', 'debugger',
811 coreconfigitem('ui', 'debugger',
812 default=None,
812 default=None,
813 )
813 )
814 coreconfigitem('ui', 'fallbackencoding',
814 coreconfigitem('ui', 'fallbackencoding',
815 default=None,
815 default=None,
816 )
816 )
817 coreconfigitem('ui', 'forcecwd',
817 coreconfigitem('ui', 'forcecwd',
818 default=None,
818 default=None,
819 )
819 )
820 coreconfigitem('ui', 'forcemerge',
820 coreconfigitem('ui', 'forcemerge',
821 default=None,
821 default=None,
822 )
822 )
823 coreconfigitem('ui', 'formatdebug',
823 coreconfigitem('ui', 'formatdebug',
824 default=False,
824 default=False,
825 )
825 )
826 coreconfigitem('ui', 'formatjson',
826 coreconfigitem('ui', 'formatjson',
827 default=False,
827 default=False,
828 )
828 )
829 coreconfigitem('ui', 'formatted',
829 coreconfigitem('ui', 'formatted',
830 default=None,
830 default=None,
831 )
831 )
832 coreconfigitem('ui', 'graphnodetemplate',
832 coreconfigitem('ui', 'graphnodetemplate',
833 default=None,
833 default=None,
834 )
834 )
835 coreconfigitem('ui', 'http2debuglevel',
835 coreconfigitem('ui', 'http2debuglevel',
836 default=None,
836 default=None,
837 )
837 )
838 coreconfigitem('ui', 'interactive',
838 coreconfigitem('ui', 'interactive',
839 default=None,
839 default=None,
840 )
840 )
841 coreconfigitem('ui', 'interface',
841 coreconfigitem('ui', 'interface',
842 default=None,
842 default=None,
843 )
843 )
844 coreconfigitem('ui', 'interface.chunkselector',
844 coreconfigitem('ui', 'interface.chunkselector',
845 default=None,
845 default=None,
846 )
846 )
847 coreconfigitem('ui', 'logblockedtimes',
847 coreconfigitem('ui', 'logblockedtimes',
848 default=False,
848 default=False,
849 )
849 )
850 coreconfigitem('ui', 'logtemplate',
850 coreconfigitem('ui', 'logtemplate',
851 default=None,
851 default=None,
852 )
852 )
853 coreconfigitem('ui', 'merge',
853 coreconfigitem('ui', 'merge',
854 default=None,
854 default=None,
855 )
855 )
856 coreconfigitem('ui', 'mergemarkers',
856 coreconfigitem('ui', 'mergemarkers',
857 default='basic',
857 default='basic',
858 )
858 )
859 coreconfigitem('ui', 'mergemarkertemplate',
859 coreconfigitem('ui', 'mergemarkertemplate',
860 default=('{node|short} '
860 default=('{node|short} '
861 '{ifeq(tags, "tip", "", '
861 '{ifeq(tags, "tip", "", '
862 'ifeq(tags, "", "", "{tags} "))}'
862 'ifeq(tags, "", "", "{tags} "))}'
863 '{if(bookmarks, "{bookmarks} ")}'
863 '{if(bookmarks, "{bookmarks} ")}'
864 '{ifeq(branch, "default", "", "{branch} ")}'
864 '{ifeq(branch, "default", "", "{branch} ")}'
865 '- {author|user}: {desc|firstline}')
865 '- {author|user}: {desc|firstline}')
866 )
866 )
867 coreconfigitem('ui', 'nontty',
867 coreconfigitem('ui', 'nontty',
868 default=False,
868 default=False,
869 )
869 )
870 coreconfigitem('ui', 'origbackuppath',
870 coreconfigitem('ui', 'origbackuppath',
871 default=None,
871 default=None,
872 )
872 )
873 coreconfigitem('ui', 'paginate',
873 coreconfigitem('ui', 'paginate',
874 default=True,
874 default=True,
875 )
875 )
876 coreconfigitem('ui', 'patch',
876 coreconfigitem('ui', 'patch',
877 default=None,
877 default=None,
878 )
878 )
879 coreconfigitem('ui', 'portablefilenames',
879 coreconfigitem('ui', 'portablefilenames',
880 default='warn',
880 default='warn',
881 )
881 )
882 coreconfigitem('ui', 'promptecho',
882 coreconfigitem('ui', 'promptecho',
883 default=False,
883 default=False,
884 )
884 )
885 coreconfigitem('ui', 'quiet',
885 coreconfigitem('ui', 'quiet',
886 default=False,
886 default=False,
887 )
887 )
888 coreconfigitem('ui', 'quietbookmarkmove',
888 coreconfigitem('ui', 'quietbookmarkmove',
889 default=False,
889 default=False,
890 )
890 )
891 coreconfigitem('ui', 'remotecmd',
891 coreconfigitem('ui', 'remotecmd',
892 default='hg',
892 default='hg',
893 )
893 )
894 coreconfigitem('ui', 'report_untrusted',
894 coreconfigitem('ui', 'report_untrusted',
895 default=True,
895 default=True,
896 )
896 )
897 coreconfigitem('ui', 'rollback',
897 coreconfigitem('ui', 'rollback',
898 default=True,
898 default=True,
899 )
899 )
900 coreconfigitem('ui', 'slash',
900 coreconfigitem('ui', 'slash',
901 default=False,
901 default=False,
902 )
902 )
903 coreconfigitem('ui', 'ssh',
903 coreconfigitem('ui', 'ssh',
904 default='ssh',
904 default='ssh',
905 )
905 )
906 coreconfigitem('ui', 'statuscopies',
906 coreconfigitem('ui', 'statuscopies',
907 default=False,
907 default=False,
908 )
908 )
909 coreconfigitem('ui', 'strict',
909 coreconfigitem('ui', 'strict',
910 default=False,
910 default=False,
911 )
911 )
912 coreconfigitem('ui', 'style',
912 coreconfigitem('ui', 'style',
913 default='',
913 default='',
914 )
914 )
915 coreconfigitem('ui', 'supportcontact',
915 coreconfigitem('ui', 'supportcontact',
916 default=None,
916 default=None,
917 )
917 )
918 coreconfigitem('ui', 'textwidth',
918 coreconfigitem('ui', 'textwidth',
919 default=78,
919 default=78,
920 )
920 )
921 coreconfigitem('ui', 'timeout',
921 coreconfigitem('ui', 'timeout',
922 default='600',
922 default='600',
923 )
923 )
924 coreconfigitem('ui', 'traceback',
924 coreconfigitem('ui', 'traceback',
925 default=False,
925 default=False,
926 )
926 )
927 coreconfigitem('ui', 'tweakdefaults',
927 coreconfigitem('ui', 'tweakdefaults',
928 default=False,
928 default=False,
929 )
929 )
930 coreconfigitem('ui', 'usehttp2',
930 coreconfigitem('ui', 'usehttp2',
931 default=False,
931 default=False,
932 )
932 )
933 coreconfigitem('ui', 'username',
933 coreconfigitem('ui', 'username',
934 alias=[('ui', 'user')]
934 alias=[('ui', 'user')]
935 )
935 )
936 coreconfigitem('ui', 'verbose',
936 coreconfigitem('ui', 'verbose',
937 default=False,
937 default=False,
938 )
938 )
939 coreconfigitem('verify', 'skipflags',
939 coreconfigitem('verify', 'skipflags',
940 default=None,
940 default=None,
941 )
941 )
942 coreconfigitem('web', 'allowbz2',
942 coreconfigitem('web', 'allowbz2',
943 default=False,
943 default=False,
944 )
944 )
945 coreconfigitem('web', 'allowgz',
945 coreconfigitem('web', 'allowgz',
946 default=False,
946 default=False,
947 )
947 )
948 coreconfigitem('web', 'allowpull',
948 coreconfigitem('web', 'allowpull',
949 default=True,
949 default=True,
950 )
950 )
951 coreconfigitem('web', 'allow_push',
951 coreconfigitem('web', 'allow_push',
952 default=list,
952 default=list,
953 )
953 )
954 coreconfigitem('web', 'allowzip',
954 coreconfigitem('web', 'allowzip',
955 default=False,
955 default=False,
956 )
956 )
957 coreconfigitem('web', 'archivesubrepos',
957 coreconfigitem('web', 'archivesubrepos',
958 default=False,
958 default=False,
959 )
959 )
960 coreconfigitem('web', 'cache',
960 coreconfigitem('web', 'cache',
961 default=True,
961 default=True,
962 )
962 )
963 coreconfigitem('web', 'contact',
963 coreconfigitem('web', 'contact',
964 default=None,
964 default=None,
965 )
965 )
966 coreconfigitem('web', 'deny_push',
966 coreconfigitem('web', 'deny_push',
967 default=list,
967 default=list,
968 )
968 )
969 coreconfigitem('web', 'guessmime',
969 coreconfigitem('web', 'guessmime',
970 default=False,
970 default=False,
971 )
971 )
972 coreconfigitem('web', 'hidden',
972 coreconfigitem('web', 'hidden',
973 default=False,
973 default=False,
974 )
974 )
975 coreconfigitem('web', 'labels',
975 coreconfigitem('web', 'labels',
976 default=list,
976 default=list,
977 )
977 )
978 coreconfigitem('web', 'logoimg',
978 coreconfigitem('web', 'logoimg',
979 default='hglogo.png',
979 default='hglogo.png',
980 )
980 )
981 coreconfigitem('web', 'logourl',
981 coreconfigitem('web', 'logourl',
982 default='https://mercurial-scm.org/',
982 default='https://mercurial-scm.org/',
983 )
983 )
984 coreconfigitem('web', 'accesslog',
984 coreconfigitem('web', 'accesslog',
985 default='-',
985 default='-',
986 )
986 )
987 coreconfigitem('web', 'address',
987 coreconfigitem('web', 'address',
988 default='',
988 default='',
989 )
989 )
990 coreconfigitem('web', 'allow_archive',
990 coreconfigitem('web', 'allow_archive',
991 default=list,
991 default=list,
992 )
992 )
993 coreconfigitem('web', 'allow_read',
993 coreconfigitem('web', 'allow_read',
994 default=list,
994 default=list,
995 )
995 )
996 coreconfigitem('web', 'baseurl',
996 coreconfigitem('web', 'baseurl',
997 default=None,
997 default=None,
998 )
998 )
999 coreconfigitem('web', 'cacerts',
999 coreconfigitem('web', 'cacerts',
1000 default=None,
1000 default=None,
1001 )
1001 )
1002 coreconfigitem('web', 'certificate',
1002 coreconfigitem('web', 'certificate',
1003 default=None,
1003 default=None,
1004 )
1004 )
1005 coreconfigitem('web', 'collapse',
1005 coreconfigitem('web', 'collapse',
1006 default=False,
1006 default=False,
1007 )
1007 )
1008 coreconfigitem('web', 'csp',
1008 coreconfigitem('web', 'csp',
1009 default=None,
1009 default=None,
1010 )
1010 )
1011 coreconfigitem('web', 'deny_read',
1011 coreconfigitem('web', 'deny_read',
1012 default=list,
1012 default=list,
1013 )
1013 )
1014 coreconfigitem('web', 'descend',
1014 coreconfigitem('web', 'descend',
1015 default=True,
1015 default=True,
1016 )
1016 )
1017 coreconfigitem('web', 'description',
1017 coreconfigitem('web', 'description',
1018 default="",
1018 default="",
1019 )
1019 )
1020 coreconfigitem('web', 'encoding',
1020 coreconfigitem('web', 'encoding',
1021 default=lambda: encoding.encoding,
1021 default=lambda: encoding.encoding,
1022 )
1022 )
1023 coreconfigitem('web', 'errorlog',
1023 coreconfigitem('web', 'errorlog',
1024 default='-',
1024 default='-',
1025 )
1025 )
1026 coreconfigitem('web', 'ipv6',
1026 coreconfigitem('web', 'ipv6',
1027 default=False,
1027 default=False,
1028 )
1028 )
1029 coreconfigitem('web', 'maxchanges',
1029 coreconfigitem('web', 'maxchanges',
1030 default=10,
1030 default=10,
1031 )
1031 )
1032 coreconfigitem('web', 'maxfiles',
1032 coreconfigitem('web', 'maxfiles',
1033 default=10,
1033 default=10,
1034 )
1034 )
1035 coreconfigitem('web', 'maxshortchanges',
1035 coreconfigitem('web', 'maxshortchanges',
1036 default=60,
1036 default=60,
1037 )
1037 )
1038 coreconfigitem('web', 'motd',
1038 coreconfigitem('web', 'motd',
1039 default='',
1039 default='',
1040 )
1040 )
1041 coreconfigitem('web', 'name',
1041 coreconfigitem('web', 'name',
1042 default=dynamicdefault,
1042 default=dynamicdefault,
1043 )
1043 )
1044 coreconfigitem('web', 'port',
1044 coreconfigitem('web', 'port',
1045 default=8000,
1045 default=8000,
1046 )
1046 )
1047 coreconfigitem('web', 'prefix',
1047 coreconfigitem('web', 'prefix',
1048 default='',
1048 default='',
1049 )
1049 )
1050 coreconfigitem('web', 'push_ssl',
1050 coreconfigitem('web', 'push_ssl',
1051 default=True,
1051 default=True,
1052 )
1052 )
1053 coreconfigitem('web', 'refreshinterval',
1053 coreconfigitem('web', 'refreshinterval',
1054 default=20,
1054 default=20,
1055 )
1055 )
1056 coreconfigitem('web', 'staticurl',
1056 coreconfigitem('web', 'staticurl',
1057 default=None,
1057 default=None,
1058 )
1058 )
1059 coreconfigitem('web', 'stripes',
1059 coreconfigitem('web', 'stripes',
1060 default=1,
1060 default=1,
1061 )
1061 )
1062 coreconfigitem('web', 'style',
1062 coreconfigitem('web', 'style',
1063 default='paper',
1063 default='paper',
1064 )
1064 )
1065 coreconfigitem('web', 'templates',
1065 coreconfigitem('web', 'templates',
1066 default=None,
1066 default=None,
1067 )
1067 )
1068 coreconfigitem('web', 'view',
1068 coreconfigitem('web', 'view',
1069 default='served',
1069 default='served',
1070 )
1070 )
1071 coreconfigitem('worker', 'backgroundclose',
1071 coreconfigitem('worker', 'backgroundclose',
1072 default=dynamicdefault,
1072 default=dynamicdefault,
1073 )
1073 )
1074 # Windows defaults to a limit of 512 open files. A buffer of 128
1074 # Windows defaults to a limit of 512 open files. A buffer of 128
1075 # should give us enough headway.
1075 # should give us enough headway.
1076 coreconfigitem('worker', 'backgroundclosemaxqueue',
1076 coreconfigitem('worker', 'backgroundclosemaxqueue',
1077 default=384,
1077 default=384,
1078 )
1078 )
1079 coreconfigitem('worker', 'backgroundcloseminfilecount',
1079 coreconfigitem('worker', 'backgroundcloseminfilecount',
1080 default=2048,
1080 default=2048,
1081 )
1081 )
1082 coreconfigitem('worker', 'backgroundclosethreadcount',
1082 coreconfigitem('worker', 'backgroundclosethreadcount',
1083 default=4,
1083 default=4,
1084 )
1084 )
1085 coreconfigitem('worker', 'numcpus',
1085 coreconfigitem('worker', 'numcpus',
1086 default=None,
1086 default=None,
1087 )
1087 )
1088
1089 # Rebase related configuration moved to core because other extension are doing
1090 # strange things. For example, shelve import the extensions to reuse some bit
1091 # without formally loading it.
1092 coreconfigitem('commands', 'rebase.requiredest',
1093 default=False,
1094 )
1095 coreconfigitem('experimental', 'rebaseskipobsolete',
1096 default=True,
1097 )
1098 coreconfigitem('rebase', 'singletransaction',
1099 default=False,
1100 )
General Comments 0
You need to be logged in to leave comments. Login now