##// END OF EJS Templates
rebase: remove unused variable "release" and an extra blank line...
Sushil khanchi -
r38703:8eeed924 @82 default
parent child Browse files
Show More
@@ -1,1914 +1,1911
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 nullrev,
24 nullrev,
25 short,
25 short,
26 )
26 )
27 from mercurial import (
27 from mercurial import (
28 bookmarks,
28 bookmarks,
29 cmdutil,
29 cmdutil,
30 commands,
30 commands,
31 copies,
31 copies,
32 destutil,
32 destutil,
33 dirstateguard,
33 dirstateguard,
34 error,
34 error,
35 extensions,
35 extensions,
36 hg,
36 hg,
37 lock,
38 merge as mergemod,
37 merge as mergemod,
39 mergeutil,
38 mergeutil,
40 obsolete,
39 obsolete,
41 obsutil,
40 obsutil,
42 patch,
41 patch,
43 phases,
42 phases,
44 pycompat,
43 pycompat,
45 registrar,
44 registrar,
46 repair,
45 repair,
47 revset,
46 revset,
48 revsetlang,
47 revsetlang,
49 scmutil,
48 scmutil,
50 smartset,
49 smartset,
51 state as statemod,
50 state as statemod,
52 util,
51 util,
53 )
52 )
54
53
55 release = lock.release
56
57 # The following constants are used throughout the rebase module. The ordering of
54 # The following constants are used throughout the rebase module. The ordering of
58 # their values must be maintained.
55 # their values must be maintained.
59
56
60 # Indicates that a revision needs to be rebased
57 # Indicates that a revision needs to be rebased
61 revtodo = -1
58 revtodo = -1
62 revtodostr = '-1'
59 revtodostr = '-1'
63
60
64 # legacy revstates no longer needed in current code
61 # legacy revstates no longer needed in current code
65 # -2: nullmerge, -3: revignored, -4: revprecursor, -5: revpruned
62 # -2: nullmerge, -3: revignored, -4: revprecursor, -5: revpruned
66 legacystates = {'-2', '-3', '-4', '-5'}
63 legacystates = {'-2', '-3', '-4', '-5'}
67
64
68 cmdtable = {}
65 cmdtable = {}
69 command = registrar.command(cmdtable)
66 command = registrar.command(cmdtable)
70 # Note for extension authors: ONLY specify testedwith = 'ships-with-hg-core' for
67 # Note for extension authors: ONLY specify testedwith = 'ships-with-hg-core' for
71 # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should
68 # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should
72 # be specifying the version(s) of Mercurial they are tested with, or
69 # be specifying the version(s) of Mercurial they are tested with, or
73 # leave the attribute unspecified.
70 # leave the attribute unspecified.
74 testedwith = 'ships-with-hg-core'
71 testedwith = 'ships-with-hg-core'
75
72
76 def _nothingtorebase():
73 def _nothingtorebase():
77 return 1
74 return 1
78
75
79 def _savegraft(ctx, extra):
76 def _savegraft(ctx, extra):
80 s = ctx.extra().get('source', None)
77 s = ctx.extra().get('source', None)
81 if s is not None:
78 if s is not None:
82 extra['source'] = s
79 extra['source'] = s
83 s = ctx.extra().get('intermediate-source', None)
80 s = ctx.extra().get('intermediate-source', None)
84 if s is not None:
81 if s is not None:
85 extra['intermediate-source'] = s
82 extra['intermediate-source'] = s
86
83
87 def _savebranch(ctx, extra):
84 def _savebranch(ctx, extra):
88 extra['branch'] = ctx.branch()
85 extra['branch'] = ctx.branch()
89
86
90 def _destrebase(repo, sourceset, destspace=None):
87 def _destrebase(repo, sourceset, destspace=None):
91 """small wrapper around destmerge to pass the right extra args
88 """small wrapper around destmerge to pass the right extra args
92
89
93 Please wrap destutil.destmerge instead."""
90 Please wrap destutil.destmerge instead."""
94 return destutil.destmerge(repo, action='rebase', sourceset=sourceset,
91 return destutil.destmerge(repo, action='rebase', sourceset=sourceset,
95 onheadcheck=False, destspace=destspace)
92 onheadcheck=False, destspace=destspace)
96
93
97 revsetpredicate = registrar.revsetpredicate()
94 revsetpredicate = registrar.revsetpredicate()
98
95
99 @revsetpredicate('_destrebase')
96 @revsetpredicate('_destrebase')
100 def _revsetdestrebase(repo, subset, x):
97 def _revsetdestrebase(repo, subset, x):
101 # ``_rebasedefaultdest()``
98 # ``_rebasedefaultdest()``
102
99
103 # default destination for rebase.
100 # default destination for rebase.
104 # # XXX: Currently private because I expect the signature to change.
101 # # XXX: Currently private because I expect the signature to change.
105 # # XXX: - bailing out in case of ambiguity vs returning all data.
102 # # XXX: - bailing out in case of ambiguity vs returning all data.
106 # i18n: "_rebasedefaultdest" is a keyword
103 # i18n: "_rebasedefaultdest" is a keyword
107 sourceset = None
104 sourceset = None
108 if x is not None:
105 if x is not None:
109 sourceset = revset.getset(repo, smartset.fullreposet(repo), x)
106 sourceset = revset.getset(repo, smartset.fullreposet(repo), x)
110 return subset & smartset.baseset([_destrebase(repo, sourceset)])
107 return subset & smartset.baseset([_destrebase(repo, sourceset)])
111
108
112 @revsetpredicate('_destautoorphanrebase')
109 @revsetpredicate('_destautoorphanrebase')
113 def _revsetdestautoorphanrebase(repo, subset, x):
110 def _revsetdestautoorphanrebase(repo, subset, x):
114 """automatic rebase destination for a single orphan revision"""
111 """automatic rebase destination for a single orphan revision"""
115 unfi = repo.unfiltered()
112 unfi = repo.unfiltered()
116 obsoleted = unfi.revs('obsolete()')
113 obsoleted = unfi.revs('obsolete()')
117
114
118 src = revset.getset(repo, subset, x).first()
115 src = revset.getset(repo, subset, x).first()
119
116
120 # Empty src or already obsoleted - Do not return a destination
117 # Empty src or already obsoleted - Do not return a destination
121 if not src or src in obsoleted:
118 if not src or src in obsoleted:
122 return smartset.baseset()
119 return smartset.baseset()
123 dests = destutil.orphanpossibledestination(repo, src)
120 dests = destutil.orphanpossibledestination(repo, src)
124 if len(dests) > 1:
121 if len(dests) > 1:
125 raise error.Abort(
122 raise error.Abort(
126 _("ambiguous automatic rebase: %r could end up on any of %r") % (
123 _("ambiguous automatic rebase: %r could end up on any of %r") % (
127 src, dests))
124 src, dests))
128 # We have zero or one destination, so we can just return here.
125 # We have zero or one destination, so we can just return here.
129 return smartset.baseset(dests)
126 return smartset.baseset(dests)
130
127
131 def _ctxdesc(ctx):
128 def _ctxdesc(ctx):
132 """short description for a context"""
129 """short description for a context"""
133 desc = '%d:%s "%s"' % (ctx.rev(), ctx,
130 desc = '%d:%s "%s"' % (ctx.rev(), ctx,
134 ctx.description().split('\n', 1)[0])
131 ctx.description().split('\n', 1)[0])
135 repo = ctx.repo()
132 repo = ctx.repo()
136 names = []
133 names = []
137 for nsname, ns in repo.names.iteritems():
134 for nsname, ns in repo.names.iteritems():
138 if nsname == 'branches':
135 if nsname == 'branches':
139 continue
136 continue
140 names.extend(ns.names(repo, ctx.node()))
137 names.extend(ns.names(repo, ctx.node()))
141 if names:
138 if names:
142 desc += ' (%s)' % ' '.join(names)
139 desc += ' (%s)' % ' '.join(names)
143 return desc
140 return desc
144
141
145 class rebaseruntime(object):
142 class rebaseruntime(object):
146 """This class is a container for rebase runtime state"""
143 """This class is a container for rebase runtime state"""
147 def __init__(self, repo, ui, inmemory=False, opts=None):
144 def __init__(self, repo, ui, inmemory=False, opts=None):
148 if opts is None:
145 if opts is None:
149 opts = {}
146 opts = {}
150
147
151 # prepared: whether we have rebasestate prepared or not. Currently it
148 # prepared: whether we have rebasestate prepared or not. Currently it
152 # decides whether "self.repo" is unfiltered or not.
149 # decides whether "self.repo" is unfiltered or not.
153 # The rebasestate has explicit hash to hash instructions not depending
150 # The rebasestate has explicit hash to hash instructions not depending
154 # on visibility. If rebasestate exists (in-memory or on-disk), use
151 # on visibility. If rebasestate exists (in-memory or on-disk), use
155 # unfiltered repo to avoid visibility issues.
152 # unfiltered repo to avoid visibility issues.
156 # Before knowing rebasestate (i.e. when starting a new rebase (not
153 # Before knowing rebasestate (i.e. when starting a new rebase (not
157 # --continue or --abort)), the original repo should be used so
154 # --continue or --abort)), the original repo should be used so
158 # visibility-dependent revsets are correct.
155 # visibility-dependent revsets are correct.
159 self.prepared = False
156 self.prepared = False
160 self._repo = repo
157 self._repo = repo
161
158
162 self.ui = ui
159 self.ui = ui
163 self.opts = opts
160 self.opts = opts
164 self.originalwd = None
161 self.originalwd = None
165 self.external = nullrev
162 self.external = nullrev
166 # Mapping between the old revision id and either what is the new rebased
163 # Mapping between the old revision id and either what is the new rebased
167 # revision or what needs to be done with the old revision. The state
164 # revision or what needs to be done with the old revision. The state
168 # dict will be what contains most of the rebase progress state.
165 # dict will be what contains most of the rebase progress state.
169 self.state = {}
166 self.state = {}
170 self.activebookmark = None
167 self.activebookmark = None
171 self.destmap = {}
168 self.destmap = {}
172 self.skipped = set()
169 self.skipped = set()
173
170
174 self.collapsef = opts.get('collapse', False)
171 self.collapsef = opts.get('collapse', False)
175 self.collapsemsg = cmdutil.logmessage(ui, opts)
172 self.collapsemsg = cmdutil.logmessage(ui, opts)
176 self.date = opts.get('date', None)
173 self.date = opts.get('date', None)
177
174
178 e = opts.get('extrafn') # internal, used by e.g. hgsubversion
175 e = opts.get('extrafn') # internal, used by e.g. hgsubversion
179 self.extrafns = [_savegraft]
176 self.extrafns = [_savegraft]
180 if e:
177 if e:
181 self.extrafns = [e]
178 self.extrafns = [e]
182
179
183 self.keepf = opts.get('keep', False)
180 self.keepf = opts.get('keep', False)
184 self.keepbranchesf = opts.get('keepbranches', False)
181 self.keepbranchesf = opts.get('keepbranches', False)
185 self.obsoletenotrebased = {}
182 self.obsoletenotrebased = {}
186 self.obsoletewithoutsuccessorindestination = set()
183 self.obsoletewithoutsuccessorindestination = set()
187 self.inmemory = inmemory
184 self.inmemory = inmemory
188 self.stateobj = statemod.cmdstate(repo, 'rebasestate')
185 self.stateobj = statemod.cmdstate(repo, 'rebasestate')
189
186
190 @property
187 @property
191 def repo(self):
188 def repo(self):
192 if self.prepared:
189 if self.prepared:
193 return self._repo.unfiltered()
190 return self._repo.unfiltered()
194 else:
191 else:
195 return self._repo
192 return self._repo
196
193
197 def storestatus(self, tr=None):
194 def storestatus(self, tr=None):
198 """Store the current status to allow recovery"""
195 """Store the current status to allow recovery"""
199 if tr:
196 if tr:
200 tr.addfilegenerator('rebasestate', ('rebasestate',),
197 tr.addfilegenerator('rebasestate', ('rebasestate',),
201 self._writestatus, location='plain')
198 self._writestatus, location='plain')
202 else:
199 else:
203 with self.repo.vfs("rebasestate", "w") as f:
200 with self.repo.vfs("rebasestate", "w") as f:
204 self._writestatus(f)
201 self._writestatus(f)
205
202
206 def _writestatus(self, f):
203 def _writestatus(self, f):
207 repo = self.repo
204 repo = self.repo
208 assert repo.filtername is None
205 assert repo.filtername is None
209 f.write(repo[self.originalwd].hex() + '\n')
206 f.write(repo[self.originalwd].hex() + '\n')
210 # was "dest". we now write dest per src root below.
207 # was "dest". we now write dest per src root below.
211 f.write('\n')
208 f.write('\n')
212 f.write(repo[self.external].hex() + '\n')
209 f.write(repo[self.external].hex() + '\n')
213 f.write('%d\n' % int(self.collapsef))
210 f.write('%d\n' % int(self.collapsef))
214 f.write('%d\n' % int(self.keepf))
211 f.write('%d\n' % int(self.keepf))
215 f.write('%d\n' % int(self.keepbranchesf))
212 f.write('%d\n' % int(self.keepbranchesf))
216 f.write('%s\n' % (self.activebookmark or ''))
213 f.write('%s\n' % (self.activebookmark or ''))
217 destmap = self.destmap
214 destmap = self.destmap
218 for d, v in self.state.iteritems():
215 for d, v in self.state.iteritems():
219 oldrev = repo[d].hex()
216 oldrev = repo[d].hex()
220 if v >= 0:
217 if v >= 0:
221 newrev = repo[v].hex()
218 newrev = repo[v].hex()
222 else:
219 else:
223 newrev = "%d" % v
220 newrev = "%d" % v
224 destnode = repo[destmap[d]].hex()
221 destnode = repo[destmap[d]].hex()
225 f.write("%s:%s:%s\n" % (oldrev, newrev, destnode))
222 f.write("%s:%s:%s\n" % (oldrev, newrev, destnode))
226 repo.ui.debug('rebase status stored\n')
223 repo.ui.debug('rebase status stored\n')
227
224
228 def restorestatus(self):
225 def restorestatus(self):
229 """Restore a previously stored status"""
226 """Restore a previously stored status"""
230 if not self.stateobj.exists():
227 if not self.stateobj.exists():
231 cmdutil.wrongtooltocontinue(self.repo, _('rebase'))
228 cmdutil.wrongtooltocontinue(self.repo, _('rebase'))
232
229
233 data = self._read()
230 data = self._read()
234 self.repo.ui.debug('rebase status resumed\n')
231 self.repo.ui.debug('rebase status resumed\n')
235
232
236 self.originalwd = data['originalwd']
233 self.originalwd = data['originalwd']
237 self.destmap = data['destmap']
234 self.destmap = data['destmap']
238 self.state = data['state']
235 self.state = data['state']
239 self.skipped = data['skipped']
236 self.skipped = data['skipped']
240 self.collapsef = data['collapse']
237 self.collapsef = data['collapse']
241 self.keepf = data['keep']
238 self.keepf = data['keep']
242 self.keepbranchesf = data['keepbranches']
239 self.keepbranchesf = data['keepbranches']
243 self.external = data['external']
240 self.external = data['external']
244 self.activebookmark = data['activebookmark']
241 self.activebookmark = data['activebookmark']
245
242
246 def _read(self):
243 def _read(self):
247 self.prepared = True
244 self.prepared = True
248 repo = self.repo
245 repo = self.repo
249 assert repo.filtername is None
246 assert repo.filtername is None
250 data = {'keepbranches': None, 'collapse': None, 'activebookmark': None,
247 data = {'keepbranches': None, 'collapse': None, 'activebookmark': None,
251 'external': nullrev, 'keep': None, 'originalwd': None}
248 'external': nullrev, 'keep': None, 'originalwd': None}
252 legacydest = None
249 legacydest = None
253 state = {}
250 state = {}
254 destmap = {}
251 destmap = {}
255
252
256 if True:
253 if True:
257 f = repo.vfs("rebasestate")
254 f = repo.vfs("rebasestate")
258 for i, l in enumerate(f.read().splitlines()):
255 for i, l in enumerate(f.read().splitlines()):
259 if i == 0:
256 if i == 0:
260 data['originalwd'] = repo[l].rev()
257 data['originalwd'] = repo[l].rev()
261 elif i == 1:
258 elif i == 1:
262 # this line should be empty in newer version. but legacy
259 # this line should be empty in newer version. but legacy
263 # clients may still use it
260 # clients may still use it
264 if l:
261 if l:
265 legacydest = repo[l].rev()
262 legacydest = repo[l].rev()
266 elif i == 2:
263 elif i == 2:
267 data['external'] = repo[l].rev()
264 data['external'] = repo[l].rev()
268 elif i == 3:
265 elif i == 3:
269 data['collapse'] = bool(int(l))
266 data['collapse'] = bool(int(l))
270 elif i == 4:
267 elif i == 4:
271 data['keep'] = bool(int(l))
268 data['keep'] = bool(int(l))
272 elif i == 5:
269 elif i == 5:
273 data['keepbranches'] = bool(int(l))
270 data['keepbranches'] = bool(int(l))
274 elif i == 6 and not (len(l) == 81 and ':' in l):
271 elif i == 6 and not (len(l) == 81 and ':' in l):
275 # line 6 is a recent addition, so for backwards
272 # line 6 is a recent addition, so for backwards
276 # compatibility check that the line doesn't look like the
273 # compatibility check that the line doesn't look like the
277 # oldrev:newrev lines
274 # oldrev:newrev lines
278 data['activebookmark'] = l
275 data['activebookmark'] = l
279 else:
276 else:
280 args = l.split(':')
277 args = l.split(':')
281 oldrev = repo[args[0]].rev()
278 oldrev = repo[args[0]].rev()
282 newrev = args[1]
279 newrev = args[1]
283 if newrev in legacystates:
280 if newrev in legacystates:
284 continue
281 continue
285 if len(args) > 2:
282 if len(args) > 2:
286 destrev = repo[args[2]].rev()
283 destrev = repo[args[2]].rev()
287 else:
284 else:
288 destrev = legacydest
285 destrev = legacydest
289 destmap[oldrev] = destrev
286 destmap[oldrev] = destrev
290 if newrev == revtodostr:
287 if newrev == revtodostr:
291 state[oldrev] = revtodo
288 state[oldrev] = revtodo
292 # Legacy compat special case
289 # Legacy compat special case
293 else:
290 else:
294 state[oldrev] = repo[newrev].rev()
291 state[oldrev] = repo[newrev].rev()
295
292
296 if data['keepbranches'] is None:
293 if data['keepbranches'] is None:
297 raise error.Abort(_('.hg/rebasestate is incomplete'))
294 raise error.Abort(_('.hg/rebasestate is incomplete'))
298
295
299 data['destmap'] = destmap
296 data['destmap'] = destmap
300 data['state'] = state
297 data['state'] = state
301 skipped = set()
298 skipped = set()
302 # recompute the set of skipped revs
299 # recompute the set of skipped revs
303 if not data['collapse']:
300 if not data['collapse']:
304 seen = set(destmap.values())
301 seen = set(destmap.values())
305 for old, new in sorted(state.items()):
302 for old, new in sorted(state.items()):
306 if new != revtodo and new in seen:
303 if new != revtodo and new in seen:
307 skipped.add(old)
304 skipped.add(old)
308 seen.add(new)
305 seen.add(new)
309 data['skipped'] = skipped
306 data['skipped'] = skipped
310 repo.ui.debug('computed skipped revs: %s\n' %
307 repo.ui.debug('computed skipped revs: %s\n' %
311 (' '.join('%d' % r for r in sorted(skipped)) or ''))
308 (' '.join('%d' % r for r in sorted(skipped)) or ''))
312
309
313 return data
310 return data
314
311
315 def _handleskippingobsolete(self, obsoleterevs, destmap):
312 def _handleskippingobsolete(self, obsoleterevs, destmap):
316 """Compute structures necessary for skipping obsolete revisions
313 """Compute structures necessary for skipping obsolete revisions
317
314
318 obsoleterevs: iterable of all obsolete revisions in rebaseset
315 obsoleterevs: iterable of all obsolete revisions in rebaseset
319 destmap: {srcrev: destrev} destination revisions
316 destmap: {srcrev: destrev} destination revisions
320 """
317 """
321 self.obsoletenotrebased = {}
318 self.obsoletenotrebased = {}
322 if not self.ui.configbool('experimental', 'rebaseskipobsolete'):
319 if not self.ui.configbool('experimental', 'rebaseskipobsolete'):
323 return
320 return
324 obsoleteset = set(obsoleterevs)
321 obsoleteset = set(obsoleterevs)
325 (self.obsoletenotrebased,
322 (self.obsoletenotrebased,
326 self.obsoletewithoutsuccessorindestination,
323 self.obsoletewithoutsuccessorindestination,
327 obsoleteextinctsuccessors) = _computeobsoletenotrebased(
324 obsoleteextinctsuccessors) = _computeobsoletenotrebased(
328 self.repo, obsoleteset, destmap)
325 self.repo, obsoleteset, destmap)
329 skippedset = set(self.obsoletenotrebased)
326 skippedset = set(self.obsoletenotrebased)
330 skippedset.update(self.obsoletewithoutsuccessorindestination)
327 skippedset.update(self.obsoletewithoutsuccessorindestination)
331 skippedset.update(obsoleteextinctsuccessors)
328 skippedset.update(obsoleteextinctsuccessors)
332 _checkobsrebase(self.repo, self.ui, obsoleteset, skippedset)
329 _checkobsrebase(self.repo, self.ui, obsoleteset, skippedset)
333
330
334 def _prepareabortorcontinue(self, isabort, backup=True, suppwarns=False):
331 def _prepareabortorcontinue(self, isabort, backup=True, suppwarns=False):
335 try:
332 try:
336 self.restorestatus()
333 self.restorestatus()
337 self.collapsemsg = restorecollapsemsg(self.repo, isabort)
334 self.collapsemsg = restorecollapsemsg(self.repo, isabort)
338 except error.RepoLookupError:
335 except error.RepoLookupError:
339 if isabort:
336 if isabort:
340 clearstatus(self.repo)
337 clearstatus(self.repo)
341 clearcollapsemsg(self.repo)
338 clearcollapsemsg(self.repo)
342 self.repo.ui.warn(_('rebase aborted (no revision is removed,'
339 self.repo.ui.warn(_('rebase aborted (no revision is removed,'
343 ' only broken state is cleared)\n'))
340 ' only broken state is cleared)\n'))
344 return 0
341 return 0
345 else:
342 else:
346 msg = _('cannot continue inconsistent rebase')
343 msg = _('cannot continue inconsistent rebase')
347 hint = _('use "hg rebase --abort" to clear broken state')
344 hint = _('use "hg rebase --abort" to clear broken state')
348 raise error.Abort(msg, hint=hint)
345 raise error.Abort(msg, hint=hint)
349 if isabort:
346 if isabort:
350 return abort(self.repo, self.originalwd, self.destmap, self.state,
347 return abort(self.repo, self.originalwd, self.destmap, self.state,
351 activebookmark=self.activebookmark, backup=backup,
348 activebookmark=self.activebookmark, backup=backup,
352 suppwarns=suppwarns)
349 suppwarns=suppwarns)
353
350
354 def _preparenewrebase(self, destmap):
351 def _preparenewrebase(self, destmap):
355 if not destmap:
352 if not destmap:
356 return _nothingtorebase()
353 return _nothingtorebase()
357
354
358 rebaseset = destmap.keys()
355 rebaseset = destmap.keys()
359 allowunstable = obsolete.isenabled(self.repo, obsolete.allowunstableopt)
356 allowunstable = obsolete.isenabled(self.repo, obsolete.allowunstableopt)
360 if (not (self.keepf or allowunstable)
357 if (not (self.keepf or allowunstable)
361 and self.repo.revs('first(children(%ld) - %ld)',
358 and self.repo.revs('first(children(%ld) - %ld)',
362 rebaseset, rebaseset)):
359 rebaseset, rebaseset)):
363 raise error.Abort(
360 raise error.Abort(
364 _("can't remove original changesets with"
361 _("can't remove original changesets with"
365 " unrebased descendants"),
362 " unrebased descendants"),
366 hint=_('use --keep to keep original changesets'))
363 hint=_('use --keep to keep original changesets'))
367
364
368 result = buildstate(self.repo, destmap, self.collapsef)
365 result = buildstate(self.repo, destmap, self.collapsef)
369
366
370 if not result:
367 if not result:
371 # Empty state built, nothing to rebase
368 # Empty state built, nothing to rebase
372 self.ui.status(_('nothing to rebase\n'))
369 self.ui.status(_('nothing to rebase\n'))
373 return _nothingtorebase()
370 return _nothingtorebase()
374
371
375 for root in self.repo.set('roots(%ld)', rebaseset):
372 for root in self.repo.set('roots(%ld)', rebaseset):
376 if not self.keepf and not root.mutable():
373 if not self.keepf and not root.mutable():
377 raise error.Abort(_("can't rebase public changeset %s")
374 raise error.Abort(_("can't rebase public changeset %s")
378 % root,
375 % root,
379 hint=_("see 'hg help phases' for details"))
376 hint=_("see 'hg help phases' for details"))
380
377
381 (self.originalwd, self.destmap, self.state) = result
378 (self.originalwd, self.destmap, self.state) = result
382 if self.collapsef:
379 if self.collapsef:
383 dests = set(self.destmap.values())
380 dests = set(self.destmap.values())
384 if len(dests) != 1:
381 if len(dests) != 1:
385 raise error.Abort(
382 raise error.Abort(
386 _('--collapse does not work with multiple destinations'))
383 _('--collapse does not work with multiple destinations'))
387 destrev = next(iter(dests))
384 destrev = next(iter(dests))
388 destancestors = self.repo.changelog.ancestors([destrev],
385 destancestors = self.repo.changelog.ancestors([destrev],
389 inclusive=True)
386 inclusive=True)
390 self.external = externalparent(self.repo, self.state, destancestors)
387 self.external = externalparent(self.repo, self.state, destancestors)
391
388
392 for destrev in sorted(set(destmap.values())):
389 for destrev in sorted(set(destmap.values())):
393 dest = self.repo[destrev]
390 dest = self.repo[destrev]
394 if dest.closesbranch() and not self.keepbranchesf:
391 if dest.closesbranch() and not self.keepbranchesf:
395 self.ui.status(_('reopening closed branch head %s\n') % dest)
392 self.ui.status(_('reopening closed branch head %s\n') % dest)
396
393
397 self.prepared = True
394 self.prepared = True
398
395
399 def _assignworkingcopy(self):
396 def _assignworkingcopy(self):
400 if self.inmemory:
397 if self.inmemory:
401 from mercurial.context import overlayworkingctx
398 from mercurial.context import overlayworkingctx
402 self.wctx = overlayworkingctx(self.repo)
399 self.wctx = overlayworkingctx(self.repo)
403 self.repo.ui.debug("rebasing in-memory\n")
400 self.repo.ui.debug("rebasing in-memory\n")
404 else:
401 else:
405 self.wctx = self.repo[None]
402 self.wctx = self.repo[None]
406 self.repo.ui.debug("rebasing on disk\n")
403 self.repo.ui.debug("rebasing on disk\n")
407 self.repo.ui.log("rebase", "", rebase_imm_used=self.inmemory)
404 self.repo.ui.log("rebase", "", rebase_imm_used=self.inmemory)
408
405
409 def _performrebase(self, tr):
406 def _performrebase(self, tr):
410 self._assignworkingcopy()
407 self._assignworkingcopy()
411 repo, ui = self.repo, self.ui
408 repo, ui = self.repo, self.ui
412 if self.keepbranchesf:
409 if self.keepbranchesf:
413 # insert _savebranch at the start of extrafns so if
410 # insert _savebranch at the start of extrafns so if
414 # there's a user-provided extrafn it can clobber branch if
411 # there's a user-provided extrafn it can clobber branch if
415 # desired
412 # desired
416 self.extrafns.insert(0, _savebranch)
413 self.extrafns.insert(0, _savebranch)
417 if self.collapsef:
414 if self.collapsef:
418 branches = set()
415 branches = set()
419 for rev in self.state:
416 for rev in self.state:
420 branches.add(repo[rev].branch())
417 branches.add(repo[rev].branch())
421 if len(branches) > 1:
418 if len(branches) > 1:
422 raise error.Abort(_('cannot collapse multiple named '
419 raise error.Abort(_('cannot collapse multiple named '
423 'branches'))
420 'branches'))
424
421
425 # Calculate self.obsoletenotrebased
422 # Calculate self.obsoletenotrebased
426 obsrevs = _filterobsoleterevs(self.repo, self.state)
423 obsrevs = _filterobsoleterevs(self.repo, self.state)
427 self._handleskippingobsolete(obsrevs, self.destmap)
424 self._handleskippingobsolete(obsrevs, self.destmap)
428
425
429 # Keep track of the active bookmarks in order to reset them later
426 # Keep track of the active bookmarks in order to reset them later
430 self.activebookmark = self.activebookmark or repo._activebookmark
427 self.activebookmark = self.activebookmark or repo._activebookmark
431 if self.activebookmark:
428 if self.activebookmark:
432 bookmarks.deactivate(repo)
429 bookmarks.deactivate(repo)
433
430
434 # Store the state before we begin so users can run 'hg rebase --abort'
431 # Store the state before we begin so users can run 'hg rebase --abort'
435 # if we fail before the transaction closes.
432 # if we fail before the transaction closes.
436 self.storestatus()
433 self.storestatus()
437 if tr:
434 if tr:
438 # When using single transaction, store state when transaction
435 # When using single transaction, store state when transaction
439 # commits.
436 # commits.
440 self.storestatus(tr)
437 self.storestatus(tr)
441
438
442 cands = [k for k, v in self.state.iteritems() if v == revtodo]
439 cands = [k for k, v in self.state.iteritems() if v == revtodo]
443 p = repo.ui.makeprogress(_("rebasing"), unit=_('changesets'),
440 p = repo.ui.makeprogress(_("rebasing"), unit=_('changesets'),
444 total=len(cands))
441 total=len(cands))
445 def progress(ctx):
442 def progress(ctx):
446 p.increment(item=("%d:%s" % (ctx.rev(), ctx)))
443 p.increment(item=("%d:%s" % (ctx.rev(), ctx)))
447 allowdivergence = self.ui.configbool(
444 allowdivergence = self.ui.configbool(
448 'experimental', 'evolution.allowdivergence')
445 'experimental', 'evolution.allowdivergence')
449 for subset in sortsource(self.destmap):
446 for subset in sortsource(self.destmap):
450 sortedrevs = self.repo.revs('sort(%ld, -topo)', subset)
447 sortedrevs = self.repo.revs('sort(%ld, -topo)', subset)
451 if not allowdivergence:
448 if not allowdivergence:
452 sortedrevs -= self.repo.revs(
449 sortedrevs -= self.repo.revs(
453 'descendants(%ld) and not %ld',
450 'descendants(%ld) and not %ld',
454 self.obsoletewithoutsuccessorindestination,
451 self.obsoletewithoutsuccessorindestination,
455 self.obsoletewithoutsuccessorindestination,
452 self.obsoletewithoutsuccessorindestination,
456 )
453 )
457 for rev in sortedrevs:
454 for rev in sortedrevs:
458 self._rebasenode(tr, rev, allowdivergence, progress)
455 self._rebasenode(tr, rev, allowdivergence, progress)
459 p.complete()
456 p.complete()
460 ui.note(_('rebase merging completed\n'))
457 ui.note(_('rebase merging completed\n'))
461
458
462 def _concludenode(self, rev, p1, p2, editor, commitmsg=None):
459 def _concludenode(self, rev, p1, p2, editor, commitmsg=None):
463 '''Commit the wd changes with parents p1 and p2.
460 '''Commit the wd changes with parents p1 and p2.
464
461
465 Reuse commit info from rev but also store useful information in extra.
462 Reuse commit info from rev but also store useful information in extra.
466 Return node of committed revision.'''
463 Return node of committed revision.'''
467 repo = self.repo
464 repo = self.repo
468 ctx = repo[rev]
465 ctx = repo[rev]
469 if commitmsg is None:
466 if commitmsg is None:
470 commitmsg = ctx.description()
467 commitmsg = ctx.description()
471 date = self.date
468 date = self.date
472 if date is None:
469 if date is None:
473 date = ctx.date()
470 date = ctx.date()
474 extra = {'rebase_source': ctx.hex()}
471 extra = {'rebase_source': ctx.hex()}
475 for c in self.extrafns:
472 for c in self.extrafns:
476 c(ctx, extra)
473 c(ctx, extra)
477 keepbranch = self.keepbranchesf and repo[p1].branch() != ctx.branch()
474 keepbranch = self.keepbranchesf and repo[p1].branch() != ctx.branch()
478 destphase = max(ctx.phase(), phases.draft)
475 destphase = max(ctx.phase(), phases.draft)
479 overrides = {('phases', 'new-commit'): destphase}
476 overrides = {('phases', 'new-commit'): destphase}
480 if keepbranch:
477 if keepbranch:
481 overrides[('ui', 'allowemptycommit')] = True
478 overrides[('ui', 'allowemptycommit')] = True
482 with repo.ui.configoverride(overrides, 'rebase'):
479 with repo.ui.configoverride(overrides, 'rebase'):
483 if self.inmemory:
480 if self.inmemory:
484 newnode = commitmemorynode(repo, p1, p2,
481 newnode = commitmemorynode(repo, p1, p2,
485 wctx=self.wctx,
482 wctx=self.wctx,
486 extra=extra,
483 extra=extra,
487 commitmsg=commitmsg,
484 commitmsg=commitmsg,
488 editor=editor,
485 editor=editor,
489 user=ctx.user(),
486 user=ctx.user(),
490 date=date)
487 date=date)
491 mergemod.mergestate.clean(repo)
488 mergemod.mergestate.clean(repo)
492 else:
489 else:
493 newnode = commitnode(repo, p1, p2,
490 newnode = commitnode(repo, p1, p2,
494 extra=extra,
491 extra=extra,
495 commitmsg=commitmsg,
492 commitmsg=commitmsg,
496 editor=editor,
493 editor=editor,
497 user=ctx.user(),
494 user=ctx.user(),
498 date=date)
495 date=date)
499
496
500 if newnode is None:
497 if newnode is None:
501 # If it ended up being a no-op commit, then the normal
498 # If it ended up being a no-op commit, then the normal
502 # merge state clean-up path doesn't happen, so do it
499 # merge state clean-up path doesn't happen, so do it
503 # here. Fix issue5494
500 # here. Fix issue5494
504 mergemod.mergestate.clean(repo)
501 mergemod.mergestate.clean(repo)
505 return newnode
502 return newnode
506
503
507 def _rebasenode(self, tr, rev, allowdivergence, progressfn):
504 def _rebasenode(self, tr, rev, allowdivergence, progressfn):
508 repo, ui, opts = self.repo, self.ui, self.opts
505 repo, ui, opts = self.repo, self.ui, self.opts
509 dest = self.destmap[rev]
506 dest = self.destmap[rev]
510 ctx = repo[rev]
507 ctx = repo[rev]
511 desc = _ctxdesc(ctx)
508 desc = _ctxdesc(ctx)
512 if self.state[rev] == rev:
509 if self.state[rev] == rev:
513 ui.status(_('already rebased %s\n') % desc)
510 ui.status(_('already rebased %s\n') % desc)
514 elif (not allowdivergence
511 elif (not allowdivergence
515 and rev in self.obsoletewithoutsuccessorindestination):
512 and rev in self.obsoletewithoutsuccessorindestination):
516 msg = _('note: not rebasing %s and its descendants as '
513 msg = _('note: not rebasing %s and its descendants as '
517 'this would cause divergence\n') % desc
514 'this would cause divergence\n') % desc
518 repo.ui.status(msg)
515 repo.ui.status(msg)
519 self.skipped.add(rev)
516 self.skipped.add(rev)
520 elif rev in self.obsoletenotrebased:
517 elif rev in self.obsoletenotrebased:
521 succ = self.obsoletenotrebased[rev]
518 succ = self.obsoletenotrebased[rev]
522 if succ is None:
519 if succ is None:
523 msg = _('note: not rebasing %s, it has no '
520 msg = _('note: not rebasing %s, it has no '
524 'successor\n') % desc
521 'successor\n') % desc
525 else:
522 else:
526 succdesc = _ctxdesc(repo[succ])
523 succdesc = _ctxdesc(repo[succ])
527 msg = (_('note: not rebasing %s, already in '
524 msg = (_('note: not rebasing %s, already in '
528 'destination as %s\n') % (desc, succdesc))
525 'destination as %s\n') % (desc, succdesc))
529 repo.ui.status(msg)
526 repo.ui.status(msg)
530 # Make clearrebased aware state[rev] is not a true successor
527 # Make clearrebased aware state[rev] is not a true successor
531 self.skipped.add(rev)
528 self.skipped.add(rev)
532 # Record rev as moved to its desired destination in self.state.
529 # Record rev as moved to its desired destination in self.state.
533 # This helps bookmark and working parent movement.
530 # This helps bookmark and working parent movement.
534 dest = max(adjustdest(repo, rev, self.destmap, self.state,
531 dest = max(adjustdest(repo, rev, self.destmap, self.state,
535 self.skipped))
532 self.skipped))
536 self.state[rev] = dest
533 self.state[rev] = dest
537 elif self.state[rev] == revtodo:
534 elif self.state[rev] == revtodo:
538 ui.status(_('rebasing %s\n') % desc)
535 ui.status(_('rebasing %s\n') % desc)
539 progressfn(ctx)
536 progressfn(ctx)
540 p1, p2, base = defineparents(repo, rev, self.destmap,
537 p1, p2, base = defineparents(repo, rev, self.destmap,
541 self.state, self.skipped,
538 self.state, self.skipped,
542 self.obsoletenotrebased)
539 self.obsoletenotrebased)
543 if len(repo[None].parents()) == 2:
540 if len(repo[None].parents()) == 2:
544 repo.ui.debug('resuming interrupted rebase\n')
541 repo.ui.debug('resuming interrupted rebase\n')
545 else:
542 else:
546 overrides = {('ui', 'forcemerge'): opts.get('tool', '')}
543 overrides = {('ui', 'forcemerge'): opts.get('tool', '')}
547 with ui.configoverride(overrides, 'rebase'):
544 with ui.configoverride(overrides, 'rebase'):
548 stats = rebasenode(repo, rev, p1, base, self.collapsef,
545 stats = rebasenode(repo, rev, p1, base, self.collapsef,
549 dest, wctx=self.wctx)
546 dest, wctx=self.wctx)
550 if stats.unresolvedcount > 0:
547 if stats.unresolvedcount > 0:
551 if self.inmemory:
548 if self.inmemory:
552 raise error.InMemoryMergeConflictsError()
549 raise error.InMemoryMergeConflictsError()
553 else:
550 else:
554 raise error.InterventionRequired(
551 raise error.InterventionRequired(
555 _('unresolved conflicts (see hg '
552 _('unresolved conflicts (see hg '
556 'resolve, then hg rebase --continue)'))
553 'resolve, then hg rebase --continue)'))
557 if not self.collapsef:
554 if not self.collapsef:
558 merging = p2 != nullrev
555 merging = p2 != nullrev
559 editform = cmdutil.mergeeditform(merging, 'rebase')
556 editform = cmdutil.mergeeditform(merging, 'rebase')
560 editor = cmdutil.getcommiteditor(editform=editform,
557 editor = cmdutil.getcommiteditor(editform=editform,
561 **pycompat.strkwargs(opts))
558 **pycompat.strkwargs(opts))
562 newnode = self._concludenode(rev, p1, p2, editor)
559 newnode = self._concludenode(rev, p1, p2, editor)
563 else:
560 else:
564 # Skip commit if we are collapsing
561 # Skip commit if we are collapsing
565 if self.inmemory:
562 if self.inmemory:
566 self.wctx.setbase(repo[p1])
563 self.wctx.setbase(repo[p1])
567 else:
564 else:
568 repo.setparents(repo[p1].node())
565 repo.setparents(repo[p1].node())
569 newnode = None
566 newnode = None
570 # Update the state
567 # Update the state
571 if newnode is not None:
568 if newnode is not None:
572 self.state[rev] = repo[newnode].rev()
569 self.state[rev] = repo[newnode].rev()
573 ui.debug('rebased as %s\n' % short(newnode))
570 ui.debug('rebased as %s\n' % short(newnode))
574 else:
571 else:
575 if not self.collapsef:
572 if not self.collapsef:
576 ui.warn(_('note: rebase of %d:%s created no changes '
573 ui.warn(_('note: rebase of %d:%s created no changes '
577 'to commit\n') % (rev, ctx))
574 'to commit\n') % (rev, ctx))
578 self.skipped.add(rev)
575 self.skipped.add(rev)
579 self.state[rev] = p1
576 self.state[rev] = p1
580 ui.debug('next revision set to %d\n' % p1)
577 ui.debug('next revision set to %d\n' % p1)
581 else:
578 else:
582 ui.status(_('already rebased %s as %s\n') %
579 ui.status(_('already rebased %s as %s\n') %
583 (desc, repo[self.state[rev]]))
580 (desc, repo[self.state[rev]]))
584 if not tr:
581 if not tr:
585 # When not using single transaction, store state after each
582 # When not using single transaction, store state after each
586 # commit is completely done. On InterventionRequired, we thus
583 # commit is completely done. On InterventionRequired, we thus
587 # won't store the status. Instead, we'll hit the "len(parents) == 2"
584 # won't store the status. Instead, we'll hit the "len(parents) == 2"
588 # case and realize that the commit was in progress.
585 # case and realize that the commit was in progress.
589 self.storestatus()
586 self.storestatus()
590
587
591 def _finishrebase(self):
588 def _finishrebase(self):
592 repo, ui, opts = self.repo, self.ui, self.opts
589 repo, ui, opts = self.repo, self.ui, self.opts
593 fm = ui.formatter('rebase', opts)
590 fm = ui.formatter('rebase', opts)
594 fm.startitem()
591 fm.startitem()
595 if self.collapsef:
592 if self.collapsef:
596 p1, p2, _base = defineparents(repo, min(self.state), self.destmap,
593 p1, p2, _base = defineparents(repo, min(self.state), self.destmap,
597 self.state, self.skipped,
594 self.state, self.skipped,
598 self.obsoletenotrebased)
595 self.obsoletenotrebased)
599 editopt = opts.get('edit')
596 editopt = opts.get('edit')
600 editform = 'rebase.collapse'
597 editform = 'rebase.collapse'
601 if self.collapsemsg:
598 if self.collapsemsg:
602 commitmsg = self.collapsemsg
599 commitmsg = self.collapsemsg
603 else:
600 else:
604 commitmsg = 'Collapsed revision'
601 commitmsg = 'Collapsed revision'
605 for rebased in sorted(self.state):
602 for rebased in sorted(self.state):
606 if rebased not in self.skipped:
603 if rebased not in self.skipped:
607 commitmsg += '\n* %s' % repo[rebased].description()
604 commitmsg += '\n* %s' % repo[rebased].description()
608 editopt = True
605 editopt = True
609 editor = cmdutil.getcommiteditor(edit=editopt, editform=editform)
606 editor = cmdutil.getcommiteditor(edit=editopt, editform=editform)
610 revtoreuse = max(self.state)
607 revtoreuse = max(self.state)
611
608
612 newnode = self._concludenode(revtoreuse, p1, self.external,
609 newnode = self._concludenode(revtoreuse, p1, self.external,
613 editor, commitmsg=commitmsg)
610 editor, commitmsg=commitmsg)
614
611
615 if newnode is not None:
612 if newnode is not None:
616 newrev = repo[newnode].rev()
613 newrev = repo[newnode].rev()
617 for oldrev in self.state:
614 for oldrev in self.state:
618 self.state[oldrev] = newrev
615 self.state[oldrev] = newrev
619
616
620 if 'qtip' in repo.tags():
617 if 'qtip' in repo.tags():
621 updatemq(repo, self.state, self.skipped,
618 updatemq(repo, self.state, self.skipped,
622 **pycompat.strkwargs(opts))
619 **pycompat.strkwargs(opts))
623
620
624 # restore original working directory
621 # restore original working directory
625 # (we do this before stripping)
622 # (we do this before stripping)
626 newwd = self.state.get(self.originalwd, self.originalwd)
623 newwd = self.state.get(self.originalwd, self.originalwd)
627 if newwd < 0:
624 if newwd < 0:
628 # original directory is a parent of rebase set root or ignored
625 # original directory is a parent of rebase set root or ignored
629 newwd = self.originalwd
626 newwd = self.originalwd
630 if newwd not in [c.rev() for c in repo[None].parents()]:
627 if newwd not in [c.rev() for c in repo[None].parents()]:
631 ui.note(_("update back to initial working directory parent\n"))
628 ui.note(_("update back to initial working directory parent\n"))
632 hg.updaterepo(repo, newwd, overwrite=False)
629 hg.updaterepo(repo, newwd, overwrite=False)
633
630
634 collapsedas = None
631 collapsedas = None
635 if self.collapsef and not self.keepf:
632 if self.collapsef and not self.keepf:
636 collapsedas = newnode
633 collapsedas = newnode
637 clearrebased(ui, repo, self.destmap, self.state, self.skipped,
634 clearrebased(ui, repo, self.destmap, self.state, self.skipped,
638 collapsedas, self.keepf, fm=fm)
635 collapsedas, self.keepf, fm=fm)
639
636
640 clearstatus(repo)
637 clearstatus(repo)
641 clearcollapsemsg(repo)
638 clearcollapsemsg(repo)
642
639
643 ui.note(_("rebase completed\n"))
640 ui.note(_("rebase completed\n"))
644 util.unlinkpath(repo.sjoin('undo'), ignoremissing=True)
641 util.unlinkpath(repo.sjoin('undo'), ignoremissing=True)
645 if self.skipped:
642 if self.skipped:
646 skippedlen = len(self.skipped)
643 skippedlen = len(self.skipped)
647 ui.note(_("%d revisions have been skipped\n") % skippedlen)
644 ui.note(_("%d revisions have been skipped\n") % skippedlen)
648 fm.end()
645 fm.end()
649
646
650 if (self.activebookmark and self.activebookmark in repo._bookmarks and
647 if (self.activebookmark and self.activebookmark in repo._bookmarks and
651 repo['.'].node() == repo._bookmarks[self.activebookmark]):
648 repo['.'].node() == repo._bookmarks[self.activebookmark]):
652 bookmarks.activate(repo, self.activebookmark)
649 bookmarks.activate(repo, self.activebookmark)
653
650
654 @command('rebase',
651 @command('rebase',
655 [('s', 'source', '',
652 [('s', 'source', '',
656 _('rebase the specified changeset and descendants'), _('REV')),
653 _('rebase the specified changeset and descendants'), _('REV')),
657 ('b', 'base', '',
654 ('b', 'base', '',
658 _('rebase everything from branching point of specified changeset'),
655 _('rebase everything from branching point of specified changeset'),
659 _('REV')),
656 _('REV')),
660 ('r', 'rev', [],
657 ('r', 'rev', [],
661 _('rebase these revisions'),
658 _('rebase these revisions'),
662 _('REV')),
659 _('REV')),
663 ('d', 'dest', '',
660 ('d', 'dest', '',
664 _('rebase onto the specified changeset'), _('REV')),
661 _('rebase onto the specified changeset'), _('REV')),
665 ('', 'collapse', False, _('collapse the rebased changesets')),
662 ('', 'collapse', False, _('collapse the rebased changesets')),
666 ('m', 'message', '',
663 ('m', 'message', '',
667 _('use text as collapse commit message'), _('TEXT')),
664 _('use text as collapse commit message'), _('TEXT')),
668 ('e', 'edit', False, _('invoke editor on commit messages')),
665 ('e', 'edit', False, _('invoke editor on commit messages')),
669 ('l', 'logfile', '',
666 ('l', 'logfile', '',
670 _('read collapse commit message from file'), _('FILE')),
667 _('read collapse commit message from file'), _('FILE')),
671 ('k', 'keep', False, _('keep original changesets')),
668 ('k', 'keep', False, _('keep original changesets')),
672 ('', 'keepbranches', False, _('keep original branch names')),
669 ('', 'keepbranches', False, _('keep original branch names')),
673 ('D', 'detach', False, _('(DEPRECATED)')),
670 ('D', 'detach', False, _('(DEPRECATED)')),
674 ('i', 'interactive', False, _('(DEPRECATED)')),
671 ('i', 'interactive', False, _('(DEPRECATED)')),
675 ('t', 'tool', '', _('specify merge tool')),
672 ('t', 'tool', '', _('specify merge tool')),
676 ('c', 'continue', False, _('continue an interrupted rebase')),
673 ('c', 'continue', False, _('continue an interrupted rebase')),
677 ('a', 'abort', False, _('abort an interrupted rebase')),
674 ('a', 'abort', False, _('abort an interrupted rebase')),
678 ('', 'auto-orphans', '', _('automatically rebase orphan revisions '
675 ('', 'auto-orphans', '', _('automatically rebase orphan revisions '
679 'in the specified revset (EXPERIMENTAL)')),
676 'in the specified revset (EXPERIMENTAL)')),
680 ] + cmdutil.dryrunopts + cmdutil.formatteropts + cmdutil.confirmopts,
677 ] + cmdutil.dryrunopts + cmdutil.formatteropts + cmdutil.confirmopts,
681 _('[-s REV | -b REV] [-d REV] [OPTION]'))
678 _('[-s REV | -b REV] [-d REV] [OPTION]'))
682 def rebase(ui, repo, **opts):
679 def rebase(ui, repo, **opts):
683 """move changeset (and descendants) to a different branch
680 """move changeset (and descendants) to a different branch
684
681
685 Rebase uses repeated merging to graft changesets from one part of
682 Rebase uses repeated merging to graft changesets from one part of
686 history (the source) onto another (the destination). This can be
683 history (the source) onto another (the destination). This can be
687 useful for linearizing *local* changes relative to a master
684 useful for linearizing *local* changes relative to a master
688 development tree.
685 development tree.
689
686
690 Published commits cannot be rebased (see :hg:`help phases`).
687 Published commits cannot be rebased (see :hg:`help phases`).
691 To copy commits, see :hg:`help graft`.
688 To copy commits, see :hg:`help graft`.
692
689
693 If you don't specify a destination changeset (``-d/--dest``), rebase
690 If you don't specify a destination changeset (``-d/--dest``), rebase
694 will use the same logic as :hg:`merge` to pick a destination. if
691 will use the same logic as :hg:`merge` to pick a destination. if
695 the current branch contains exactly one other head, the other head
692 the current branch contains exactly one other head, the other head
696 is merged with by default. Otherwise, an explicit revision with
693 is merged with by default. Otherwise, an explicit revision with
697 which to merge with must be provided. (destination changeset is not
694 which to merge with must be provided. (destination changeset is not
698 modified by rebasing, but new changesets are added as its
695 modified by rebasing, but new changesets are added as its
699 descendants.)
696 descendants.)
700
697
701 Here are the ways to select changesets:
698 Here are the ways to select changesets:
702
699
703 1. Explicitly select them using ``--rev``.
700 1. Explicitly select them using ``--rev``.
704
701
705 2. Use ``--source`` to select a root changeset and include all of its
702 2. Use ``--source`` to select a root changeset and include all of its
706 descendants.
703 descendants.
707
704
708 3. Use ``--base`` to select a changeset; rebase will find ancestors
705 3. Use ``--base`` to select a changeset; rebase will find ancestors
709 and their descendants which are not also ancestors of the destination.
706 and their descendants which are not also ancestors of the destination.
710
707
711 4. If you do not specify any of ``--rev``, ``source``, or ``--base``,
708 4. If you do not specify any of ``--rev``, ``source``, or ``--base``,
712 rebase will use ``--base .`` as above.
709 rebase will use ``--base .`` as above.
713
710
714 If ``--source`` or ``--rev`` is used, special names ``SRC`` and ``ALLSRC``
711 If ``--source`` or ``--rev`` is used, special names ``SRC`` and ``ALLSRC``
715 can be used in ``--dest``. Destination would be calculated per source
712 can be used in ``--dest``. Destination would be calculated per source
716 revision with ``SRC`` substituted by that single source revision and
713 revision with ``SRC`` substituted by that single source revision and
717 ``ALLSRC`` substituted by all source revisions.
714 ``ALLSRC`` substituted by all source revisions.
718
715
719 Rebase will destroy original changesets unless you use ``--keep``.
716 Rebase will destroy original changesets unless you use ``--keep``.
720 It will also move your bookmarks (even if you do).
717 It will also move your bookmarks (even if you do).
721
718
722 Some changesets may be dropped if they do not contribute changes
719 Some changesets may be dropped if they do not contribute changes
723 (e.g. merges from the destination branch).
720 (e.g. merges from the destination branch).
724
721
725 Unlike ``merge``, rebase will do nothing if you are at the branch tip of
722 Unlike ``merge``, rebase will do nothing if you are at the branch tip of
726 a named branch with two heads. You will need to explicitly specify source
723 a named branch with two heads. You will need to explicitly specify source
727 and/or destination.
724 and/or destination.
728
725
729 If you need to use a tool to automate merge/conflict decisions, you
726 If you need to use a tool to automate merge/conflict decisions, you
730 can specify one with ``--tool``, see :hg:`help merge-tools`.
727 can specify one with ``--tool``, see :hg:`help merge-tools`.
731 As a caveat: the tool will not be used to mediate when a file was
728 As a caveat: the tool will not be used to mediate when a file was
732 deleted, there is no hook presently available for this.
729 deleted, there is no hook presently available for this.
733
730
734 If a rebase is interrupted to manually resolve a conflict, it can be
731 If a rebase is interrupted to manually resolve a conflict, it can be
735 continued with --continue/-c or aborted with --abort/-a.
732 continued with --continue/-c or aborted with --abort/-a.
736
733
737 .. container:: verbose
734 .. container:: verbose
738
735
739 Examples:
736 Examples:
740
737
741 - move "local changes" (current commit back to branching point)
738 - move "local changes" (current commit back to branching point)
742 to the current branch tip after a pull::
739 to the current branch tip after a pull::
743
740
744 hg rebase
741 hg rebase
745
742
746 - move a single changeset to the stable branch::
743 - move a single changeset to the stable branch::
747
744
748 hg rebase -r 5f493448 -d stable
745 hg rebase -r 5f493448 -d stable
749
746
750 - splice a commit and all its descendants onto another part of history::
747 - splice a commit and all its descendants onto another part of history::
751
748
752 hg rebase --source c0c3 --dest 4cf9
749 hg rebase --source c0c3 --dest 4cf9
753
750
754 - rebase everything on a branch marked by a bookmark onto the
751 - rebase everything on a branch marked by a bookmark onto the
755 default branch::
752 default branch::
756
753
757 hg rebase --base myfeature --dest default
754 hg rebase --base myfeature --dest default
758
755
759 - collapse a sequence of changes into a single commit::
756 - collapse a sequence of changes into a single commit::
760
757
761 hg rebase --collapse -r 1520:1525 -d .
758 hg rebase --collapse -r 1520:1525 -d .
762
759
763 - move a named branch while preserving its name::
760 - move a named branch while preserving its name::
764
761
765 hg rebase -r "branch(featureX)" -d 1.3 --keepbranches
762 hg rebase -r "branch(featureX)" -d 1.3 --keepbranches
766
763
767 - stabilize orphaned changesets so history looks linear::
764 - stabilize orphaned changesets so history looks linear::
768
765
769 hg rebase -r 'orphan()-obsolete()'\
766 hg rebase -r 'orphan()-obsolete()'\
770 -d 'first(max((successors(max(roots(ALLSRC) & ::SRC)^)-obsolete())::) +\
767 -d 'first(max((successors(max(roots(ALLSRC) & ::SRC)^)-obsolete())::) +\
771 max(::((roots(ALLSRC) & ::SRC)^)-obsolete()))'
768 max(::((roots(ALLSRC) & ::SRC)^)-obsolete()))'
772
769
773 Configuration Options:
770 Configuration Options:
774
771
775 You can make rebase require a destination if you set the following config
772 You can make rebase require a destination if you set the following config
776 option::
773 option::
777
774
778 [commands]
775 [commands]
779 rebase.requiredest = True
776 rebase.requiredest = True
780
777
781 By default, rebase will close the transaction after each commit. For
778 By default, rebase will close the transaction after each commit. For
782 performance purposes, you can configure rebase to use a single transaction
779 performance purposes, you can configure rebase to use a single transaction
783 across the entire rebase. WARNING: This setting introduces a significant
780 across the entire rebase. WARNING: This setting introduces a significant
784 risk of losing the work you've done in a rebase if the rebase aborts
781 risk of losing the work you've done in a rebase if the rebase aborts
785 unexpectedly::
782 unexpectedly::
786
783
787 [rebase]
784 [rebase]
788 singletransaction = True
785 singletransaction = True
789
786
790 By default, rebase writes to the working copy, but you can configure it to
787 By default, rebase writes to the working copy, but you can configure it to
791 run in-memory for for better performance, and to allow it to run if the
788 run in-memory for for better performance, and to allow it to run if the
792 working copy is dirty::
789 working copy is dirty::
793
790
794 [rebase]
791 [rebase]
795 experimental.inmemory = True
792 experimental.inmemory = True
796
793
797 Return Values:
794 Return Values:
798
795
799 Returns 0 on success, 1 if nothing to rebase or there are
796 Returns 0 on success, 1 if nothing to rebase or there are
800 unresolved conflicts.
797 unresolved conflicts.
801
798
802 """
799 """
803 opts = pycompat.byteskwargs(opts)
800 opts = pycompat.byteskwargs(opts)
804 inmemory = ui.configbool('rebase', 'experimental.inmemory')
801 inmemory = ui.configbool('rebase', 'experimental.inmemory')
805 dryrun = opts.get('dry_run')
802 dryrun = opts.get('dry_run')
806 if dryrun:
803 if dryrun:
807 if opts.get('abort'):
804 if opts.get('abort'):
808 raise error.Abort(_('cannot specify both --dry-run and --abort'))
805 raise error.Abort(_('cannot specify both --dry-run and --abort'))
809 if opts.get('continue'):
806 if opts.get('continue'):
810 raise error.Abort(_('cannot specify both --dry-run and --continue'))
807 raise error.Abort(_('cannot specify both --dry-run and --continue'))
811 if opts.get('confirm'):
808 if opts.get('confirm'):
812 dryrun = True
809 dryrun = True
813 if opts.get('dry_run'):
810 if opts.get('dry_run'):
814 raise error.Abort(_('cannot specify both --confirm and --dry-run'))
811 raise error.Abort(_('cannot specify both --confirm and --dry-run'))
815 if opts.get('abort'):
812 if opts.get('abort'):
816 raise error.Abort(_('cannot specify both --confirm and --abort'))
813 raise error.Abort(_('cannot specify both --confirm and --abort'))
817 if opts.get('continue'):
814 if opts.get('continue'):
818 raise error.Abort(_('cannot specify both --confirm and --continue'))
815 raise error.Abort(_('cannot specify both --confirm and --continue'))
819
816
820 if (opts.get('continue') or opts.get('abort') or
817 if (opts.get('continue') or opts.get('abort') or
821 repo.currenttransaction() is not None):
818 repo.currenttransaction() is not None):
822 # in-memory rebase is not compatible with resuming rebases.
819 # in-memory rebase is not compatible with resuming rebases.
823 # (Or if it is run within a transaction, since the restart logic can
820 # (Or if it is run within a transaction, since the restart logic can
824 # fail the entire transaction.)
821 # fail the entire transaction.)
825 inmemory = False
822 inmemory = False
826
823
827 if opts.get('auto_orphans'):
824 if opts.get('auto_orphans'):
828 for key in opts:
825 for key in opts:
829 if key != 'auto_orphans' and opts.get(key):
826 if key != 'auto_orphans' and opts.get(key):
830 raise error.Abort(_('--auto-orphans is incompatible with %s') %
827 raise error.Abort(_('--auto-orphans is incompatible with %s') %
831 ('--' + key))
828 ('--' + key))
832 userrevs = list(repo.revs(opts.get('auto_orphans')))
829 userrevs = list(repo.revs(opts.get('auto_orphans')))
833 opts['rev'] = [revsetlang.formatspec('%ld and orphan()', userrevs)]
830 opts['rev'] = [revsetlang.formatspec('%ld and orphan()', userrevs)]
834 opts['dest'] = '_destautoorphanrebase(SRC)'
831 opts['dest'] = '_destautoorphanrebase(SRC)'
835
832
836 if dryrun:
833 if dryrun:
837 return _dryrunrebase(ui, repo, opts)
834 return _dryrunrebase(ui, repo, opts)
838 elif inmemory:
835 elif inmemory:
839 try:
836 try:
840 # in-memory merge doesn't support conflicts, so if we hit any, abort
837 # in-memory merge doesn't support conflicts, so if we hit any, abort
841 # and re-run as an on-disk merge.
838 # and re-run as an on-disk merge.
842 overrides = {('rebase', 'singletransaction'): True}
839 overrides = {('rebase', 'singletransaction'): True}
843 with ui.configoverride(overrides, 'rebase'):
840 with ui.configoverride(overrides, 'rebase'):
844 return _dorebase(ui, repo, opts, inmemory=inmemory)
841 return _dorebase(ui, repo, opts, inmemory=inmemory)
845 except error.InMemoryMergeConflictsError:
842 except error.InMemoryMergeConflictsError:
846 ui.warn(_('hit merge conflicts; re-running rebase without in-memory'
843 ui.warn(_('hit merge conflicts; re-running rebase without in-memory'
847 ' merge\n'))
844 ' merge\n'))
848 _dorebase(ui, repo, {'abort': True})
845 _dorebase(ui, repo, {'abort': True})
849 return _dorebase(ui, repo, opts, inmemory=False)
846 return _dorebase(ui, repo, opts, inmemory=False)
850 else:
847 else:
851 return _dorebase(ui, repo, opts)
848 return _dorebase(ui, repo, opts)
852
849
853 def _dryrunrebase(ui, repo, opts):
850 def _dryrunrebase(ui, repo, opts):
854 rbsrt = rebaseruntime(repo, ui, inmemory=True, opts=opts)
851 rbsrt = rebaseruntime(repo, ui, inmemory=True, opts=opts)
855 confirm = opts.get('confirm')
852 confirm = opts.get('confirm')
856 if confirm:
853 if confirm:
857 ui.status(_('starting in-memory rebase\n'))
854 ui.status(_('starting in-memory rebase\n'))
858 else:
855 else:
859 ui.status(_('starting dry-run rebase; repository will not be '
856 ui.status(_('starting dry-run rebase; repository will not be '
860 'changed\n'))
857 'changed\n'))
861 with repo.wlock(), repo.lock():
858 with repo.wlock(), repo.lock():
862 needsabort = True
859 needsabort = True
863 try:
860 try:
864 overrides = {('rebase', 'singletransaction'): True}
861 overrides = {('rebase', 'singletransaction'): True}
865 with ui.configoverride(overrides, 'rebase'):
862 with ui.configoverride(overrides, 'rebase'):
866 _origrebase(ui, repo, opts, rbsrt, inmemory=True,
863 _origrebase(ui, repo, opts, rbsrt, inmemory=True,
867 leaveunfinished=True)
864 leaveunfinished=True)
868 except error.InMemoryMergeConflictsError:
865 except error.InMemoryMergeConflictsError:
869 ui.status(_('hit a merge conflict\n'))
866 ui.status(_('hit a merge conflict\n'))
870 return 1
867 return 1
871 else:
868 else:
872 if confirm:
869 if confirm:
873 ui.status(_('rebase completed successfully\n'))
870 ui.status(_('rebase completed successfully\n'))
874 if not ui.promptchoice(_(b'apply changes (yn)?'
871 if not ui.promptchoice(_(b'apply changes (yn)?'
875 b'$$ &Yes $$ &No')):
872 b'$$ &Yes $$ &No')):
876 # finish unfinished rebase
873 # finish unfinished rebase
877 rbsrt._finishrebase()
874 rbsrt._finishrebase()
878 else:
875 else:
879 rbsrt._prepareabortorcontinue(isabort=True, backup=False,
876 rbsrt._prepareabortorcontinue(isabort=True, backup=False,
880 suppwarns=True)
877 suppwarns=True)
881 needsabort = False
878 needsabort = False
882 else:
879 else:
883 ui.status(_('dry-run rebase completed successfully; run without'
880 ui.status(_('dry-run rebase completed successfully; run without'
884 ' -n/--dry-run to perform this rebase\n'))
881 ' -n/--dry-run to perform this rebase\n'))
885 return 0
882 return 0
886 finally:
883 finally:
887 if needsabort:
884 if needsabort:
888 # no need to store backup in case of dryrun
885 # no need to store backup in case of dryrun
889 rbsrt._prepareabortorcontinue(isabort=True, backup=False,
886 rbsrt._prepareabortorcontinue(isabort=True, backup=False,
890 suppwarns=True)
887 suppwarns=True)
891
888
892 def _dorebase(ui, repo, opts, inmemory=False):
889 def _dorebase(ui, repo, opts, inmemory=False):
893 rbsrt = rebaseruntime(repo, ui, inmemory, opts)
890 rbsrt = rebaseruntime(repo, ui, inmemory, opts)
894 return _origrebase(ui, repo, opts, rbsrt, inmemory=inmemory)
891 return _origrebase(ui, repo, opts, rbsrt, inmemory=inmemory)
895
892
896 def _origrebase(ui, repo, opts, rbsrt, inmemory=False, leaveunfinished=False):
893 def _origrebase(ui, repo, opts, rbsrt, inmemory=False, leaveunfinished=False):
897 with repo.wlock(), repo.lock():
894 with repo.wlock(), repo.lock():
898 # Validate input and define rebasing points
895 # Validate input and define rebasing points
899 destf = opts.get('dest', None)
896 destf = opts.get('dest', None)
900 srcf = opts.get('source', None)
897 srcf = opts.get('source', None)
901 basef = opts.get('base', None)
898 basef = opts.get('base', None)
902 revf = opts.get('rev', [])
899 revf = opts.get('rev', [])
903 # search default destination in this space
900 # search default destination in this space
904 # used in the 'hg pull --rebase' case, see issue 5214.
901 # used in the 'hg pull --rebase' case, see issue 5214.
905 destspace = opts.get('_destspace')
902 destspace = opts.get('_destspace')
906 contf = opts.get('continue')
903 contf = opts.get('continue')
907 abortf = opts.get('abort')
904 abortf = opts.get('abort')
908 if opts.get('interactive'):
905 if opts.get('interactive'):
909 try:
906 try:
910 if extensions.find('histedit'):
907 if extensions.find('histedit'):
911 enablehistedit = ''
908 enablehistedit = ''
912 except KeyError:
909 except KeyError:
913 enablehistedit = " --config extensions.histedit="
910 enablehistedit = " --config extensions.histedit="
914 help = "hg%s help -e histedit" % enablehistedit
911 help = "hg%s help -e histedit" % enablehistedit
915 msg = _("interactive history editing is supported by the "
912 msg = _("interactive history editing is supported by the "
916 "'histedit' extension (see \"%s\")") % help
913 "'histedit' extension (see \"%s\")") % help
917 raise error.Abort(msg)
914 raise error.Abort(msg)
918
915
919 if rbsrt.collapsemsg and not rbsrt.collapsef:
916 if rbsrt.collapsemsg and not rbsrt.collapsef:
920 raise error.Abort(
917 raise error.Abort(
921 _('message can only be specified with collapse'))
918 _('message can only be specified with collapse'))
922
919
923 if contf or abortf:
920 if contf or abortf:
924 if contf and abortf:
921 if contf and abortf:
925 raise error.Abort(_('cannot use both abort and continue'))
922 raise error.Abort(_('cannot use both abort and continue'))
926 if rbsrt.collapsef:
923 if rbsrt.collapsef:
927 raise error.Abort(
924 raise error.Abort(
928 _('cannot use collapse with continue or abort'))
925 _('cannot use collapse with continue or abort'))
929 if srcf or basef or destf:
926 if srcf or basef or destf:
930 raise error.Abort(
927 raise error.Abort(
931 _('abort and continue do not allow specifying revisions'))
928 _('abort and continue do not allow specifying revisions'))
932 if abortf and opts.get('tool', False):
929 if abortf and opts.get('tool', False):
933 ui.warn(_('tool option will be ignored\n'))
930 ui.warn(_('tool option will be ignored\n'))
934 if contf:
931 if contf:
935 ms = mergemod.mergestate.read(repo)
932 ms = mergemod.mergestate.read(repo)
936 mergeutil.checkunresolved(ms)
933 mergeutil.checkunresolved(ms)
937
934
938 retcode = rbsrt._prepareabortorcontinue(abortf)
935 retcode = rbsrt._prepareabortorcontinue(abortf)
939 if retcode is not None:
936 if retcode is not None:
940 return retcode
937 return retcode
941 else:
938 else:
942 destmap = _definedestmap(ui, repo, inmemory, destf, srcf, basef,
939 destmap = _definedestmap(ui, repo, inmemory, destf, srcf, basef,
943 revf, destspace=destspace)
940 revf, destspace=destspace)
944 retcode = rbsrt._preparenewrebase(destmap)
941 retcode = rbsrt._preparenewrebase(destmap)
945 if retcode is not None:
942 if retcode is not None:
946 return retcode
943 return retcode
947 storecollapsemsg(repo, rbsrt.collapsemsg)
944 storecollapsemsg(repo, rbsrt.collapsemsg)
948
945
949 tr = None
946 tr = None
950
947
951 singletr = ui.configbool('rebase', 'singletransaction')
948 singletr = ui.configbool('rebase', 'singletransaction')
952 if singletr:
949 if singletr:
953 tr = repo.transaction('rebase')
950 tr = repo.transaction('rebase')
954
951
955 # If `rebase.singletransaction` is enabled, wrap the entire operation in
952 # If `rebase.singletransaction` is enabled, wrap the entire operation in
956 # one transaction here. Otherwise, transactions are obtained when
953 # one transaction here. Otherwise, transactions are obtained when
957 # committing each node, which is slower but allows partial success.
954 # committing each node, which is slower but allows partial success.
958 with util.acceptintervention(tr):
955 with util.acceptintervention(tr):
959 # Same logic for the dirstate guard, except we don't create one when
956 # Same logic for the dirstate guard, except we don't create one when
960 # rebasing in-memory (it's not needed).
957 # rebasing in-memory (it's not needed).
961 dsguard = None
958 dsguard = None
962 if singletr and not inmemory:
959 if singletr and not inmemory:
963 dsguard = dirstateguard.dirstateguard(repo, 'rebase')
960 dsguard = dirstateguard.dirstateguard(repo, 'rebase')
964 with util.acceptintervention(dsguard):
961 with util.acceptintervention(dsguard):
965 rbsrt._performrebase(tr)
962 rbsrt._performrebase(tr)
966 if not leaveunfinished:
963 if not leaveunfinished:
967 rbsrt._finishrebase()
964 rbsrt._finishrebase()
968
965
969 def _definedestmap(ui, repo, inmemory, destf=None, srcf=None, basef=None,
966 def _definedestmap(ui, repo, inmemory, destf=None, srcf=None, basef=None,
970 revf=None, destspace=None):
967 revf=None, destspace=None):
971 """use revisions argument to define destmap {srcrev: destrev}"""
968 """use revisions argument to define destmap {srcrev: destrev}"""
972 if revf is None:
969 if revf is None:
973 revf = []
970 revf = []
974
971
975 # destspace is here to work around issues with `hg pull --rebase` see
972 # destspace is here to work around issues with `hg pull --rebase` see
976 # issue5214 for details
973 # issue5214 for details
977 if srcf and basef:
974 if srcf and basef:
978 raise error.Abort(_('cannot specify both a source and a base'))
975 raise error.Abort(_('cannot specify both a source and a base'))
979 if revf and basef:
976 if revf and basef:
980 raise error.Abort(_('cannot specify both a revision and a base'))
977 raise error.Abort(_('cannot specify both a revision and a base'))
981 if revf and srcf:
978 if revf and srcf:
982 raise error.Abort(_('cannot specify both a revision and a source'))
979 raise error.Abort(_('cannot specify both a revision and a source'))
983
980
984 if not inmemory:
981 if not inmemory:
985 cmdutil.checkunfinished(repo)
982 cmdutil.checkunfinished(repo)
986 cmdutil.bailifchanged(repo)
983 cmdutil.bailifchanged(repo)
987
984
988 if ui.configbool('commands', 'rebase.requiredest') and not destf:
985 if ui.configbool('commands', 'rebase.requiredest') and not destf:
989 raise error.Abort(_('you must specify a destination'),
986 raise error.Abort(_('you must specify a destination'),
990 hint=_('use: hg rebase -d REV'))
987 hint=_('use: hg rebase -d REV'))
991
988
992 dest = None
989 dest = None
993
990
994 if revf:
991 if revf:
995 rebaseset = scmutil.revrange(repo, revf)
992 rebaseset = scmutil.revrange(repo, revf)
996 if not rebaseset:
993 if not rebaseset:
997 ui.status(_('empty "rev" revision set - nothing to rebase\n'))
994 ui.status(_('empty "rev" revision set - nothing to rebase\n'))
998 return None
995 return None
999 elif srcf:
996 elif srcf:
1000 src = scmutil.revrange(repo, [srcf])
997 src = scmutil.revrange(repo, [srcf])
1001 if not src:
998 if not src:
1002 ui.status(_('empty "source" revision set - nothing to rebase\n'))
999 ui.status(_('empty "source" revision set - nothing to rebase\n'))
1003 return None
1000 return None
1004 rebaseset = repo.revs('(%ld)::', src)
1001 rebaseset = repo.revs('(%ld)::', src)
1005 assert rebaseset
1002 assert rebaseset
1006 else:
1003 else:
1007 base = scmutil.revrange(repo, [basef or '.'])
1004 base = scmutil.revrange(repo, [basef or '.'])
1008 if not base:
1005 if not base:
1009 ui.status(_('empty "base" revision set - '
1006 ui.status(_('empty "base" revision set - '
1010 "can't compute rebase set\n"))
1007 "can't compute rebase set\n"))
1011 return None
1008 return None
1012 if destf:
1009 if destf:
1013 # --base does not support multiple destinations
1010 # --base does not support multiple destinations
1014 dest = scmutil.revsingle(repo, destf)
1011 dest = scmutil.revsingle(repo, destf)
1015 else:
1012 else:
1016 dest = repo[_destrebase(repo, base, destspace=destspace)]
1013 dest = repo[_destrebase(repo, base, destspace=destspace)]
1017 destf = bytes(dest)
1014 destf = bytes(dest)
1018
1015
1019 roots = [] # selected children of branching points
1016 roots = [] # selected children of branching points
1020 bpbase = {} # {branchingpoint: [origbase]}
1017 bpbase = {} # {branchingpoint: [origbase]}
1021 for b in base: # group bases by branching points
1018 for b in base: # group bases by branching points
1022 bp = repo.revs('ancestor(%d, %d)', b, dest.rev()).first()
1019 bp = repo.revs('ancestor(%d, %d)', b, dest.rev()).first()
1023 bpbase[bp] = bpbase.get(bp, []) + [b]
1020 bpbase[bp] = bpbase.get(bp, []) + [b]
1024 if None in bpbase:
1021 if None in bpbase:
1025 # emulate the old behavior, showing "nothing to rebase" (a better
1022 # emulate the old behavior, showing "nothing to rebase" (a better
1026 # behavior may be abort with "cannot find branching point" error)
1023 # behavior may be abort with "cannot find branching point" error)
1027 bpbase.clear()
1024 bpbase.clear()
1028 for bp, bs in bpbase.iteritems(): # calculate roots
1025 for bp, bs in bpbase.iteritems(): # calculate roots
1029 roots += list(repo.revs('children(%d) & ancestors(%ld)', bp, bs))
1026 roots += list(repo.revs('children(%d) & ancestors(%ld)', bp, bs))
1030
1027
1031 rebaseset = repo.revs('%ld::', roots)
1028 rebaseset = repo.revs('%ld::', roots)
1032
1029
1033 if not rebaseset:
1030 if not rebaseset:
1034 # transform to list because smartsets are not comparable to
1031 # transform to list because smartsets are not comparable to
1035 # lists. This should be improved to honor laziness of
1032 # lists. This should be improved to honor laziness of
1036 # smartset.
1033 # smartset.
1037 if list(base) == [dest.rev()]:
1034 if list(base) == [dest.rev()]:
1038 if basef:
1035 if basef:
1039 ui.status(_('nothing to rebase - %s is both "base"'
1036 ui.status(_('nothing to rebase - %s is both "base"'
1040 ' and destination\n') % dest)
1037 ' and destination\n') % dest)
1041 else:
1038 else:
1042 ui.status(_('nothing to rebase - working directory '
1039 ui.status(_('nothing to rebase - working directory '
1043 'parent is also destination\n'))
1040 'parent is also destination\n'))
1044 elif not repo.revs('%ld - ::%d', base, dest.rev()):
1041 elif not repo.revs('%ld - ::%d', base, dest.rev()):
1045 if basef:
1042 if basef:
1046 ui.status(_('nothing to rebase - "base" %s is '
1043 ui.status(_('nothing to rebase - "base" %s is '
1047 'already an ancestor of destination '
1044 'already an ancestor of destination '
1048 '%s\n') %
1045 '%s\n') %
1049 ('+'.join(bytes(repo[r]) for r in base),
1046 ('+'.join(bytes(repo[r]) for r in base),
1050 dest))
1047 dest))
1051 else:
1048 else:
1052 ui.status(_('nothing to rebase - working '
1049 ui.status(_('nothing to rebase - working '
1053 'directory parent is already an '
1050 'directory parent is already an '
1054 'ancestor of destination %s\n') % dest)
1051 'ancestor of destination %s\n') % dest)
1055 else: # can it happen?
1052 else: # can it happen?
1056 ui.status(_('nothing to rebase from %s to %s\n') %
1053 ui.status(_('nothing to rebase from %s to %s\n') %
1057 ('+'.join(bytes(repo[r]) for r in base), dest))
1054 ('+'.join(bytes(repo[r]) for r in base), dest))
1058 return None
1055 return None
1059
1056
1060 rebasingwcp = repo['.'].rev() in rebaseset
1057 rebasingwcp = repo['.'].rev() in rebaseset
1061 ui.log("rebase", "", rebase_rebasing_wcp=rebasingwcp)
1058 ui.log("rebase", "", rebase_rebasing_wcp=rebasingwcp)
1062 if inmemory and rebasingwcp:
1059 if inmemory and rebasingwcp:
1063 # Check these since we did not before.
1060 # Check these since we did not before.
1064 cmdutil.checkunfinished(repo)
1061 cmdutil.checkunfinished(repo)
1065 cmdutil.bailifchanged(repo)
1062 cmdutil.bailifchanged(repo)
1066
1063
1067 if not destf:
1064 if not destf:
1068 dest = repo[_destrebase(repo, rebaseset, destspace=destspace)]
1065 dest = repo[_destrebase(repo, rebaseset, destspace=destspace)]
1069 destf = bytes(dest)
1066 destf = bytes(dest)
1070
1067
1071 allsrc = revsetlang.formatspec('%ld', rebaseset)
1068 allsrc = revsetlang.formatspec('%ld', rebaseset)
1072 alias = {'ALLSRC': allsrc}
1069 alias = {'ALLSRC': allsrc}
1073
1070
1074 if dest is None:
1071 if dest is None:
1075 try:
1072 try:
1076 # fast path: try to resolve dest without SRC alias
1073 # fast path: try to resolve dest without SRC alias
1077 dest = scmutil.revsingle(repo, destf, localalias=alias)
1074 dest = scmutil.revsingle(repo, destf, localalias=alias)
1078 except error.RepoLookupError:
1075 except error.RepoLookupError:
1079 # multi-dest path: resolve dest for each SRC separately
1076 # multi-dest path: resolve dest for each SRC separately
1080 destmap = {}
1077 destmap = {}
1081 for r in rebaseset:
1078 for r in rebaseset:
1082 alias['SRC'] = revsetlang.formatspec('%d', r)
1079 alias['SRC'] = revsetlang.formatspec('%d', r)
1083 # use repo.anyrevs instead of scmutil.revsingle because we
1080 # use repo.anyrevs instead of scmutil.revsingle because we
1084 # don't want to abort if destset is empty.
1081 # don't want to abort if destset is empty.
1085 destset = repo.anyrevs([destf], user=True, localalias=alias)
1082 destset = repo.anyrevs([destf], user=True, localalias=alias)
1086 size = len(destset)
1083 size = len(destset)
1087 if size == 1:
1084 if size == 1:
1088 destmap[r] = destset.first()
1085 destmap[r] = destset.first()
1089 elif size == 0:
1086 elif size == 0:
1090 ui.note(_('skipping %s - empty destination\n') % repo[r])
1087 ui.note(_('skipping %s - empty destination\n') % repo[r])
1091 else:
1088 else:
1092 raise error.Abort(_('rebase destination for %s is not '
1089 raise error.Abort(_('rebase destination for %s is not '
1093 'unique') % repo[r])
1090 'unique') % repo[r])
1094
1091
1095 if dest is not None:
1092 if dest is not None:
1096 # single-dest case: assign dest to each rev in rebaseset
1093 # single-dest case: assign dest to each rev in rebaseset
1097 destrev = dest.rev()
1094 destrev = dest.rev()
1098 destmap = {r: destrev for r in rebaseset} # {srcrev: destrev}
1095 destmap = {r: destrev for r in rebaseset} # {srcrev: destrev}
1099
1096
1100 if not destmap:
1097 if not destmap:
1101 ui.status(_('nothing to rebase - empty destination\n'))
1098 ui.status(_('nothing to rebase - empty destination\n'))
1102 return None
1099 return None
1103
1100
1104 return destmap
1101 return destmap
1105
1102
1106 def externalparent(repo, state, destancestors):
1103 def externalparent(repo, state, destancestors):
1107 """Return the revision that should be used as the second parent
1104 """Return the revision that should be used as the second parent
1108 when the revisions in state is collapsed on top of destancestors.
1105 when the revisions in state is collapsed on top of destancestors.
1109 Abort if there is more than one parent.
1106 Abort if there is more than one parent.
1110 """
1107 """
1111 parents = set()
1108 parents = set()
1112 source = min(state)
1109 source = min(state)
1113 for rev in state:
1110 for rev in state:
1114 if rev == source:
1111 if rev == source:
1115 continue
1112 continue
1116 for p in repo[rev].parents():
1113 for p in repo[rev].parents():
1117 if (p.rev() not in state
1114 if (p.rev() not in state
1118 and p.rev() not in destancestors):
1115 and p.rev() not in destancestors):
1119 parents.add(p.rev())
1116 parents.add(p.rev())
1120 if not parents:
1117 if not parents:
1121 return nullrev
1118 return nullrev
1122 if len(parents) == 1:
1119 if len(parents) == 1:
1123 return parents.pop()
1120 return parents.pop()
1124 raise error.Abort(_('unable to collapse on top of %d, there is more '
1121 raise error.Abort(_('unable to collapse on top of %d, there is more '
1125 'than one external parent: %s') %
1122 'than one external parent: %s') %
1126 (max(destancestors),
1123 (max(destancestors),
1127 ', '.join("%d" % p for p in sorted(parents))))
1124 ', '.join("%d" % p for p in sorted(parents))))
1128
1125
1129 def commitmemorynode(repo, p1, p2, wctx, editor, extra, user, date, commitmsg):
1126 def commitmemorynode(repo, p1, p2, wctx, editor, extra, user, date, commitmsg):
1130 '''Commit the memory changes with parents p1 and p2.
1127 '''Commit the memory changes with parents p1 and p2.
1131 Return node of committed revision.'''
1128 Return node of committed revision.'''
1132 # Replicates the empty check in ``repo.commit``.
1129 # Replicates the empty check in ``repo.commit``.
1133 if wctx.isempty() and not repo.ui.configbool('ui', 'allowemptycommit'):
1130 if wctx.isempty() and not repo.ui.configbool('ui', 'allowemptycommit'):
1134 return None
1131 return None
1135
1132
1136 # By convention, ``extra['branch']`` (set by extrafn) clobbers
1133 # By convention, ``extra['branch']`` (set by extrafn) clobbers
1137 # ``branch`` (used when passing ``--keepbranches``).
1134 # ``branch`` (used when passing ``--keepbranches``).
1138 branch = repo[p1].branch()
1135 branch = repo[p1].branch()
1139 if 'branch' in extra:
1136 if 'branch' in extra:
1140 branch = extra['branch']
1137 branch = extra['branch']
1141
1138
1142 memctx = wctx.tomemctx(commitmsg, parents=(p1, p2), date=date,
1139 memctx = wctx.tomemctx(commitmsg, parents=(p1, p2), date=date,
1143 extra=extra, user=user, branch=branch, editor=editor)
1140 extra=extra, user=user, branch=branch, editor=editor)
1144 commitres = repo.commitctx(memctx)
1141 commitres = repo.commitctx(memctx)
1145 wctx.clean() # Might be reused
1142 wctx.clean() # Might be reused
1146 return commitres
1143 return commitres
1147
1144
1148 def commitnode(repo, p1, p2, editor, extra, user, date, commitmsg):
1145 def commitnode(repo, p1, p2, editor, extra, user, date, commitmsg):
1149 '''Commit the wd changes with parents p1 and p2.
1146 '''Commit the wd changes with parents p1 and p2.
1150 Return node of committed revision.'''
1147 Return node of committed revision.'''
1151 dsguard = util.nullcontextmanager()
1148 dsguard = util.nullcontextmanager()
1152 if not repo.ui.configbool('rebase', 'singletransaction'):
1149 if not repo.ui.configbool('rebase', 'singletransaction'):
1153 dsguard = dirstateguard.dirstateguard(repo, 'rebase')
1150 dsguard = dirstateguard.dirstateguard(repo, 'rebase')
1154 with dsguard:
1151 with dsguard:
1155 repo.setparents(repo[p1].node(), repo[p2].node())
1152 repo.setparents(repo[p1].node(), repo[p2].node())
1156
1153
1157 # Commit might fail if unresolved files exist
1154 # Commit might fail if unresolved files exist
1158 newnode = repo.commit(text=commitmsg, user=user, date=date,
1155 newnode = repo.commit(text=commitmsg, user=user, date=date,
1159 extra=extra, editor=editor)
1156 extra=extra, editor=editor)
1160
1157
1161 repo.dirstate.setbranch(repo[newnode].branch())
1158 repo.dirstate.setbranch(repo[newnode].branch())
1162 return newnode
1159 return newnode
1163
1160
1164 def rebasenode(repo, rev, p1, base, collapse, dest, wctx):
1161 def rebasenode(repo, rev, p1, base, collapse, dest, wctx):
1165 'Rebase a single revision rev on top of p1 using base as merge ancestor'
1162 'Rebase a single revision rev on top of p1 using base as merge ancestor'
1166 # Merge phase
1163 # Merge phase
1167 # Update to destination and merge it with local
1164 # Update to destination and merge it with local
1168 if wctx.isinmemory():
1165 if wctx.isinmemory():
1169 wctx.setbase(repo[p1])
1166 wctx.setbase(repo[p1])
1170 else:
1167 else:
1171 if repo['.'].rev() != p1:
1168 if repo['.'].rev() != p1:
1172 repo.ui.debug(" update to %d:%s\n" % (p1, repo[p1]))
1169 repo.ui.debug(" update to %d:%s\n" % (p1, repo[p1]))
1173 mergemod.update(repo, p1, False, True)
1170 mergemod.update(repo, p1, False, True)
1174 else:
1171 else:
1175 repo.ui.debug(" already in destination\n")
1172 repo.ui.debug(" already in destination\n")
1176 # This is, alas, necessary to invalidate workingctx's manifest cache,
1173 # This is, alas, necessary to invalidate workingctx's manifest cache,
1177 # as well as other data we litter on it in other places.
1174 # as well as other data we litter on it in other places.
1178 wctx = repo[None]
1175 wctx = repo[None]
1179 repo.dirstate.write(repo.currenttransaction())
1176 repo.dirstate.write(repo.currenttransaction())
1180 repo.ui.debug(" merge against %d:%s\n" % (rev, repo[rev]))
1177 repo.ui.debug(" merge against %d:%s\n" % (rev, repo[rev]))
1181 if base is not None:
1178 if base is not None:
1182 repo.ui.debug(" detach base %d:%s\n" % (base, repo[base]))
1179 repo.ui.debug(" detach base %d:%s\n" % (base, repo[base]))
1183 # When collapsing in-place, the parent is the common ancestor, we
1180 # When collapsing in-place, the parent is the common ancestor, we
1184 # have to allow merging with it.
1181 # have to allow merging with it.
1185 stats = mergemod.update(repo, rev, True, True, base, collapse,
1182 stats = mergemod.update(repo, rev, True, True, base, collapse,
1186 labels=['dest', 'source'], wc=wctx)
1183 labels=['dest', 'source'], wc=wctx)
1187 if collapse:
1184 if collapse:
1188 copies.duplicatecopies(repo, wctx, rev, dest)
1185 copies.duplicatecopies(repo, wctx, rev, dest)
1189 else:
1186 else:
1190 # If we're not using --collapse, we need to
1187 # If we're not using --collapse, we need to
1191 # duplicate copies between the revision we're
1188 # duplicate copies between the revision we're
1192 # rebasing and its first parent, but *not*
1189 # rebasing and its first parent, but *not*
1193 # duplicate any copies that have already been
1190 # duplicate any copies that have already been
1194 # performed in the destination.
1191 # performed in the destination.
1195 p1rev = repo[rev].p1().rev()
1192 p1rev = repo[rev].p1().rev()
1196 copies.duplicatecopies(repo, wctx, rev, p1rev, skiprev=dest)
1193 copies.duplicatecopies(repo, wctx, rev, p1rev, skiprev=dest)
1197 return stats
1194 return stats
1198
1195
1199 def adjustdest(repo, rev, destmap, state, skipped):
1196 def adjustdest(repo, rev, destmap, state, skipped):
1200 """adjust rebase destination given the current rebase state
1197 """adjust rebase destination given the current rebase state
1201
1198
1202 rev is what is being rebased. Return a list of two revs, which are the
1199 rev is what is being rebased. Return a list of two revs, which are the
1203 adjusted destinations for rev's p1 and p2, respectively. If a parent is
1200 adjusted destinations for rev's p1 and p2, respectively. If a parent is
1204 nullrev, return dest without adjustment for it.
1201 nullrev, return dest without adjustment for it.
1205
1202
1206 For example, when doing rebasing B+E to F, C to G, rebase will first move B
1203 For example, when doing rebasing B+E to F, C to G, rebase will first move B
1207 to B1, and E's destination will be adjusted from F to B1.
1204 to B1, and E's destination will be adjusted from F to B1.
1208
1205
1209 B1 <- written during rebasing B
1206 B1 <- written during rebasing B
1210 |
1207 |
1211 F <- original destination of B, E
1208 F <- original destination of B, E
1212 |
1209 |
1213 | E <- rev, which is being rebased
1210 | E <- rev, which is being rebased
1214 | |
1211 | |
1215 | D <- prev, one parent of rev being checked
1212 | D <- prev, one parent of rev being checked
1216 | |
1213 | |
1217 | x <- skipped, ex. no successor or successor in (::dest)
1214 | x <- skipped, ex. no successor or successor in (::dest)
1218 | |
1215 | |
1219 | C <- rebased as C', different destination
1216 | C <- rebased as C', different destination
1220 | |
1217 | |
1221 | B <- rebased as B1 C'
1218 | B <- rebased as B1 C'
1222 |/ |
1219 |/ |
1223 A G <- destination of C, different
1220 A G <- destination of C, different
1224
1221
1225 Another example about merge changeset, rebase -r C+G+H -d K, rebase will
1222 Another example about merge changeset, rebase -r C+G+H -d K, rebase will
1226 first move C to C1, G to G1, and when it's checking H, the adjusted
1223 first move C to C1, G to G1, and when it's checking H, the adjusted
1227 destinations will be [C1, G1].
1224 destinations will be [C1, G1].
1228
1225
1229 H C1 G1
1226 H C1 G1
1230 /| | /
1227 /| | /
1231 F G |/
1228 F G |/
1232 K | | -> K
1229 K | | -> K
1233 | C D |
1230 | C D |
1234 | |/ |
1231 | |/ |
1235 | B | ...
1232 | B | ...
1236 |/ |/
1233 |/ |/
1237 A A
1234 A A
1238
1235
1239 Besides, adjust dest according to existing rebase information. For example,
1236 Besides, adjust dest according to existing rebase information. For example,
1240
1237
1241 B C D B needs to be rebased on top of C, C needs to be rebased on top
1238 B C D B needs to be rebased on top of C, C needs to be rebased on top
1242 \|/ of D. We will rebase C first.
1239 \|/ of D. We will rebase C first.
1243 A
1240 A
1244
1241
1245 C' After rebasing C, when considering B's destination, use C'
1242 C' After rebasing C, when considering B's destination, use C'
1246 | instead of the original C.
1243 | instead of the original C.
1247 B D
1244 B D
1248 \ /
1245 \ /
1249 A
1246 A
1250 """
1247 """
1251 # pick already rebased revs with same dest from state as interesting source
1248 # pick already rebased revs with same dest from state as interesting source
1252 dest = destmap[rev]
1249 dest = destmap[rev]
1253 source = [s for s, d in state.items()
1250 source = [s for s, d in state.items()
1254 if d > 0 and destmap[s] == dest and s not in skipped]
1251 if d > 0 and destmap[s] == dest and s not in skipped]
1255
1252
1256 result = []
1253 result = []
1257 for prev in repo.changelog.parentrevs(rev):
1254 for prev in repo.changelog.parentrevs(rev):
1258 adjusted = dest
1255 adjusted = dest
1259 if prev != nullrev:
1256 if prev != nullrev:
1260 candidate = repo.revs('max(%ld and (::%d))', source, prev).first()
1257 candidate = repo.revs('max(%ld and (::%d))', source, prev).first()
1261 if candidate is not None:
1258 if candidate is not None:
1262 adjusted = state[candidate]
1259 adjusted = state[candidate]
1263 if adjusted == dest and dest in state:
1260 if adjusted == dest and dest in state:
1264 adjusted = state[dest]
1261 adjusted = state[dest]
1265 if adjusted == revtodo:
1262 if adjusted == revtodo:
1266 # sortsource should produce an order that makes this impossible
1263 # sortsource should produce an order that makes this impossible
1267 raise error.ProgrammingError(
1264 raise error.ProgrammingError(
1268 'rev %d should be rebased already at this time' % dest)
1265 'rev %d should be rebased already at this time' % dest)
1269 result.append(adjusted)
1266 result.append(adjusted)
1270 return result
1267 return result
1271
1268
1272 def _checkobsrebase(repo, ui, rebaseobsrevs, rebaseobsskipped):
1269 def _checkobsrebase(repo, ui, rebaseobsrevs, rebaseobsskipped):
1273 """
1270 """
1274 Abort if rebase will create divergence or rebase is noop because of markers
1271 Abort if rebase will create divergence or rebase is noop because of markers
1275
1272
1276 `rebaseobsrevs`: set of obsolete revision in source
1273 `rebaseobsrevs`: set of obsolete revision in source
1277 `rebaseobsskipped`: set of revisions from source skipped because they have
1274 `rebaseobsskipped`: set of revisions from source skipped because they have
1278 successors in destination or no non-obsolete successor.
1275 successors in destination or no non-obsolete successor.
1279 """
1276 """
1280 # Obsolete node with successors not in dest leads to divergence
1277 # Obsolete node with successors not in dest leads to divergence
1281 divergenceok = ui.configbool('experimental',
1278 divergenceok = ui.configbool('experimental',
1282 'evolution.allowdivergence')
1279 'evolution.allowdivergence')
1283 divergencebasecandidates = rebaseobsrevs - rebaseobsskipped
1280 divergencebasecandidates = rebaseobsrevs - rebaseobsskipped
1284
1281
1285 if divergencebasecandidates and not divergenceok:
1282 if divergencebasecandidates and not divergenceok:
1286 divhashes = (bytes(repo[r])
1283 divhashes = (bytes(repo[r])
1287 for r in divergencebasecandidates)
1284 for r in divergencebasecandidates)
1288 msg = _("this rebase will cause "
1285 msg = _("this rebase will cause "
1289 "divergences from: %s")
1286 "divergences from: %s")
1290 h = _("to force the rebase please set "
1287 h = _("to force the rebase please set "
1291 "experimental.evolution.allowdivergence=True")
1288 "experimental.evolution.allowdivergence=True")
1292 raise error.Abort(msg % (",".join(divhashes),), hint=h)
1289 raise error.Abort(msg % (",".join(divhashes),), hint=h)
1293
1290
1294 def successorrevs(unfi, rev):
1291 def successorrevs(unfi, rev):
1295 """yield revision numbers for successors of rev"""
1292 """yield revision numbers for successors of rev"""
1296 assert unfi.filtername is None
1293 assert unfi.filtername is None
1297 nodemap = unfi.changelog.nodemap
1294 nodemap = unfi.changelog.nodemap
1298 for s in obsutil.allsuccessors(unfi.obsstore, [unfi[rev].node()]):
1295 for s in obsutil.allsuccessors(unfi.obsstore, [unfi[rev].node()]):
1299 if s in nodemap:
1296 if s in nodemap:
1300 yield nodemap[s]
1297 yield nodemap[s]
1301
1298
1302 def defineparents(repo, rev, destmap, state, skipped, obsskipped):
1299 def defineparents(repo, rev, destmap, state, skipped, obsskipped):
1303 """Return new parents and optionally a merge base for rev being rebased
1300 """Return new parents and optionally a merge base for rev being rebased
1304
1301
1305 The destination specified by "dest" cannot always be used directly because
1302 The destination specified by "dest" cannot always be used directly because
1306 previously rebase result could affect destination. For example,
1303 previously rebase result could affect destination. For example,
1307
1304
1308 D E rebase -r C+D+E -d B
1305 D E rebase -r C+D+E -d B
1309 |/ C will be rebased to C'
1306 |/ C will be rebased to C'
1310 B C D's new destination will be C' instead of B
1307 B C D's new destination will be C' instead of B
1311 |/ E's new destination will be C' instead of B
1308 |/ E's new destination will be C' instead of B
1312 A
1309 A
1313
1310
1314 The new parents of a merge is slightly more complicated. See the comment
1311 The new parents of a merge is slightly more complicated. See the comment
1315 block below.
1312 block below.
1316 """
1313 """
1317 # use unfiltered changelog since successorrevs may return filtered nodes
1314 # use unfiltered changelog since successorrevs may return filtered nodes
1318 assert repo.filtername is None
1315 assert repo.filtername is None
1319 cl = repo.changelog
1316 cl = repo.changelog
1320 isancestor = cl.isancestorrev
1317 isancestor = cl.isancestorrev
1321
1318
1322 dest = destmap[rev]
1319 dest = destmap[rev]
1323 oldps = repo.changelog.parentrevs(rev) # old parents
1320 oldps = repo.changelog.parentrevs(rev) # old parents
1324 newps = [nullrev, nullrev] # new parents
1321 newps = [nullrev, nullrev] # new parents
1325 dests = adjustdest(repo, rev, destmap, state, skipped)
1322 dests = adjustdest(repo, rev, destmap, state, skipped)
1326 bases = list(oldps) # merge base candidates, initially just old parents
1323 bases = list(oldps) # merge base candidates, initially just old parents
1327
1324
1328 if all(r == nullrev for r in oldps[1:]):
1325 if all(r == nullrev for r in oldps[1:]):
1329 # For non-merge changeset, just move p to adjusted dest as requested.
1326 # For non-merge changeset, just move p to adjusted dest as requested.
1330 newps[0] = dests[0]
1327 newps[0] = dests[0]
1331 else:
1328 else:
1332 # For merge changeset, if we move p to dests[i] unconditionally, both
1329 # For merge changeset, if we move p to dests[i] unconditionally, both
1333 # parents may change and the end result looks like "the merge loses a
1330 # parents may change and the end result looks like "the merge loses a
1334 # parent", which is a surprise. This is a limit because "--dest" only
1331 # parent", which is a surprise. This is a limit because "--dest" only
1335 # accepts one dest per src.
1332 # accepts one dest per src.
1336 #
1333 #
1337 # Therefore, only move p with reasonable conditions (in this order):
1334 # Therefore, only move p with reasonable conditions (in this order):
1338 # 1. use dest, if dest is a descendent of (p or one of p's successors)
1335 # 1. use dest, if dest is a descendent of (p or one of p's successors)
1339 # 2. use p's rebased result, if p is rebased (state[p] > 0)
1336 # 2. use p's rebased result, if p is rebased (state[p] > 0)
1340 #
1337 #
1341 # Comparing with adjustdest, the logic here does some additional work:
1338 # Comparing with adjustdest, the logic here does some additional work:
1342 # 1. decide which parents will not be moved towards dest
1339 # 1. decide which parents will not be moved towards dest
1343 # 2. if the above decision is "no", should a parent still be moved
1340 # 2. if the above decision is "no", should a parent still be moved
1344 # because it was rebased?
1341 # because it was rebased?
1345 #
1342 #
1346 # For example:
1343 # For example:
1347 #
1344 #
1348 # C # "rebase -r C -d D" is an error since none of the parents
1345 # C # "rebase -r C -d D" is an error since none of the parents
1349 # /| # can be moved. "rebase -r B+C -d D" will move C's parent
1346 # /| # can be moved. "rebase -r B+C -d D" will move C's parent
1350 # A B D # B (using rule "2."), since B will be rebased.
1347 # A B D # B (using rule "2."), since B will be rebased.
1351 #
1348 #
1352 # The loop tries to be not rely on the fact that a Mercurial node has
1349 # The loop tries to be not rely on the fact that a Mercurial node has
1353 # at most 2 parents.
1350 # at most 2 parents.
1354 for i, p in enumerate(oldps):
1351 for i, p in enumerate(oldps):
1355 np = p # new parent
1352 np = p # new parent
1356 if any(isancestor(x, dests[i]) for x in successorrevs(repo, p)):
1353 if any(isancestor(x, dests[i]) for x in successorrevs(repo, p)):
1357 np = dests[i]
1354 np = dests[i]
1358 elif p in state and state[p] > 0:
1355 elif p in state and state[p] > 0:
1359 np = state[p]
1356 np = state[p]
1360
1357
1361 # "bases" only record "special" merge bases that cannot be
1358 # "bases" only record "special" merge bases that cannot be
1362 # calculated from changelog DAG (i.e. isancestor(p, np) is False).
1359 # calculated from changelog DAG (i.e. isancestor(p, np) is False).
1363 # For example:
1360 # For example:
1364 #
1361 #
1365 # B' # rebase -s B -d D, when B was rebased to B'. dest for C
1362 # B' # rebase -s B -d D, when B was rebased to B'. dest for C
1366 # | C # is B', but merge base for C is B, instead of
1363 # | C # is B', but merge base for C is B, instead of
1367 # D | # changelog.ancestor(C, B') == A. If changelog DAG and
1364 # D | # changelog.ancestor(C, B') == A. If changelog DAG and
1368 # | B # "state" edges are merged (so there will be an edge from
1365 # | B # "state" edges are merged (so there will be an edge from
1369 # |/ # B to B'), the merge base is still ancestor(C, B') in
1366 # |/ # B to B'), the merge base is still ancestor(C, B') in
1370 # A # the merged graph.
1367 # A # the merged graph.
1371 #
1368 #
1372 # Also see https://bz.mercurial-scm.org/show_bug.cgi?id=1950#c8
1369 # Also see https://bz.mercurial-scm.org/show_bug.cgi?id=1950#c8
1373 # which uses "virtual null merge" to explain this situation.
1370 # which uses "virtual null merge" to explain this situation.
1374 if isancestor(p, np):
1371 if isancestor(p, np):
1375 bases[i] = nullrev
1372 bases[i] = nullrev
1376
1373
1377 # If one parent becomes an ancestor of the other, drop the ancestor
1374 # If one parent becomes an ancestor of the other, drop the ancestor
1378 for j, x in enumerate(newps[:i]):
1375 for j, x in enumerate(newps[:i]):
1379 if x == nullrev:
1376 if x == nullrev:
1380 continue
1377 continue
1381 if isancestor(np, x): # CASE-1
1378 if isancestor(np, x): # CASE-1
1382 np = nullrev
1379 np = nullrev
1383 elif isancestor(x, np): # CASE-2
1380 elif isancestor(x, np): # CASE-2
1384 newps[j] = np
1381 newps[j] = np
1385 np = nullrev
1382 np = nullrev
1386 # New parents forming an ancestor relationship does not
1383 # New parents forming an ancestor relationship does not
1387 # mean the old parents have a similar relationship. Do not
1384 # mean the old parents have a similar relationship. Do not
1388 # set bases[x] to nullrev.
1385 # set bases[x] to nullrev.
1389 bases[j], bases[i] = bases[i], bases[j]
1386 bases[j], bases[i] = bases[i], bases[j]
1390
1387
1391 newps[i] = np
1388 newps[i] = np
1392
1389
1393 # "rebasenode" updates to new p1, and the old p1 will be used as merge
1390 # "rebasenode" updates to new p1, and the old p1 will be used as merge
1394 # base. If only p2 changes, merging using unchanged p1 as merge base is
1391 # base. If only p2 changes, merging using unchanged p1 as merge base is
1395 # suboptimal. Therefore swap parents to make the merge sane.
1392 # suboptimal. Therefore swap parents to make the merge sane.
1396 if newps[1] != nullrev and oldps[0] == newps[0]:
1393 if newps[1] != nullrev and oldps[0] == newps[0]:
1397 assert len(newps) == 2 and len(oldps) == 2
1394 assert len(newps) == 2 and len(oldps) == 2
1398 newps.reverse()
1395 newps.reverse()
1399 bases.reverse()
1396 bases.reverse()
1400
1397
1401 # No parent change might be an error because we fail to make rev a
1398 # No parent change might be an error because we fail to make rev a
1402 # descendent of requested dest. This can happen, for example:
1399 # descendent of requested dest. This can happen, for example:
1403 #
1400 #
1404 # C # rebase -r C -d D
1401 # C # rebase -r C -d D
1405 # /| # None of A and B will be changed to D and rebase fails.
1402 # /| # None of A and B will be changed to D and rebase fails.
1406 # A B D
1403 # A B D
1407 if set(newps) == set(oldps) and dest not in newps:
1404 if set(newps) == set(oldps) and dest not in newps:
1408 raise error.Abort(_('cannot rebase %d:%s without '
1405 raise error.Abort(_('cannot rebase %d:%s without '
1409 'moving at least one of its parents')
1406 'moving at least one of its parents')
1410 % (rev, repo[rev]))
1407 % (rev, repo[rev]))
1411
1408
1412 # Source should not be ancestor of dest. The check here guarantees it's
1409 # Source should not be ancestor of dest. The check here guarantees it's
1413 # impossible. With multi-dest, the initial check does not cover complex
1410 # impossible. With multi-dest, the initial check does not cover complex
1414 # cases since we don't have abstractions to dry-run rebase cheaply.
1411 # cases since we don't have abstractions to dry-run rebase cheaply.
1415 if any(p != nullrev and isancestor(rev, p) for p in newps):
1412 if any(p != nullrev and isancestor(rev, p) for p in newps):
1416 raise error.Abort(_('source is ancestor of destination'))
1413 raise error.Abort(_('source is ancestor of destination'))
1417
1414
1418 # "rebasenode" updates to new p1, use the corresponding merge base.
1415 # "rebasenode" updates to new p1, use the corresponding merge base.
1419 if bases[0] != nullrev:
1416 if bases[0] != nullrev:
1420 base = bases[0]
1417 base = bases[0]
1421 else:
1418 else:
1422 base = None
1419 base = None
1423
1420
1424 # Check if the merge will contain unwanted changes. That may happen if
1421 # Check if the merge will contain unwanted changes. That may happen if
1425 # there are multiple special (non-changelog ancestor) merge bases, which
1422 # there are multiple special (non-changelog ancestor) merge bases, which
1426 # cannot be handled well by the 3-way merge algorithm. For example:
1423 # cannot be handled well by the 3-way merge algorithm. For example:
1427 #
1424 #
1428 # F
1425 # F
1429 # /|
1426 # /|
1430 # D E # "rebase -r D+E+F -d Z", when rebasing F, if "D" was chosen
1427 # D E # "rebase -r D+E+F -d Z", when rebasing F, if "D" was chosen
1431 # | | # as merge base, the difference between D and F will include
1428 # | | # as merge base, the difference between D and F will include
1432 # B C # C, so the rebased F will contain C surprisingly. If "E" was
1429 # B C # C, so the rebased F will contain C surprisingly. If "E" was
1433 # |/ # chosen, the rebased F will contain B.
1430 # |/ # chosen, the rebased F will contain B.
1434 # A Z
1431 # A Z
1435 #
1432 #
1436 # But our merge base candidates (D and E in above case) could still be
1433 # But our merge base candidates (D and E in above case) could still be
1437 # better than the default (ancestor(F, Z) == null). Therefore still
1434 # better than the default (ancestor(F, Z) == null). Therefore still
1438 # pick one (so choose p1 above).
1435 # pick one (so choose p1 above).
1439 if sum(1 for b in bases if b != nullrev) > 1:
1436 if sum(1 for b in bases if b != nullrev) > 1:
1440 unwanted = [None, None] # unwanted[i]: unwanted revs if choose bases[i]
1437 unwanted = [None, None] # unwanted[i]: unwanted revs if choose bases[i]
1441 for i, base in enumerate(bases):
1438 for i, base in enumerate(bases):
1442 if base == nullrev:
1439 if base == nullrev:
1443 continue
1440 continue
1444 # Revisions in the side (not chosen as merge base) branch that
1441 # Revisions in the side (not chosen as merge base) branch that
1445 # might contain "surprising" contents
1442 # might contain "surprising" contents
1446 siderevs = list(repo.revs('((%ld-%d) %% (%d+%d))',
1443 siderevs = list(repo.revs('((%ld-%d) %% (%d+%d))',
1447 bases, base, base, dest))
1444 bases, base, base, dest))
1448
1445
1449 # If those revisions are covered by rebaseset, the result is good.
1446 # If those revisions are covered by rebaseset, the result is good.
1450 # A merge in rebaseset would be considered to cover its ancestors.
1447 # A merge in rebaseset would be considered to cover its ancestors.
1451 if siderevs:
1448 if siderevs:
1452 rebaseset = [r for r, d in state.items()
1449 rebaseset = [r for r, d in state.items()
1453 if d > 0 and r not in obsskipped]
1450 if d > 0 and r not in obsskipped]
1454 merges = [r for r in rebaseset
1451 merges = [r for r in rebaseset
1455 if cl.parentrevs(r)[1] != nullrev]
1452 if cl.parentrevs(r)[1] != nullrev]
1456 unwanted[i] = list(repo.revs('%ld - (::%ld) - %ld',
1453 unwanted[i] = list(repo.revs('%ld - (::%ld) - %ld',
1457 siderevs, merges, rebaseset))
1454 siderevs, merges, rebaseset))
1458
1455
1459 # Choose a merge base that has a minimal number of unwanted revs.
1456 # Choose a merge base that has a minimal number of unwanted revs.
1460 l, i = min((len(revs), i)
1457 l, i = min((len(revs), i)
1461 for i, revs in enumerate(unwanted) if revs is not None)
1458 for i, revs in enumerate(unwanted) if revs is not None)
1462 base = bases[i]
1459 base = bases[i]
1463
1460
1464 # newps[0] should match merge base if possible. Currently, if newps[i]
1461 # newps[0] should match merge base if possible. Currently, if newps[i]
1465 # is nullrev, the only case is newps[i] and newps[j] (j < i), one is
1462 # is nullrev, the only case is newps[i] and newps[j] (j < i), one is
1466 # the other's ancestor. In that case, it's fine to not swap newps here.
1463 # the other's ancestor. In that case, it's fine to not swap newps here.
1467 # (see CASE-1 and CASE-2 above)
1464 # (see CASE-1 and CASE-2 above)
1468 if i != 0 and newps[i] != nullrev:
1465 if i != 0 and newps[i] != nullrev:
1469 newps[0], newps[i] = newps[i], newps[0]
1466 newps[0], newps[i] = newps[i], newps[0]
1470
1467
1471 # The merge will include unwanted revisions. Abort now. Revisit this if
1468 # The merge will include unwanted revisions. Abort now. Revisit this if
1472 # we have a more advanced merge algorithm that handles multiple bases.
1469 # we have a more advanced merge algorithm that handles multiple bases.
1473 if l > 0:
1470 if l > 0:
1474 unwanteddesc = _(' or ').join(
1471 unwanteddesc = _(' or ').join(
1475 (', '.join('%d:%s' % (r, repo[r]) for r in revs)
1472 (', '.join('%d:%s' % (r, repo[r]) for r in revs)
1476 for revs in unwanted if revs is not None))
1473 for revs in unwanted if revs is not None))
1477 raise error.Abort(
1474 raise error.Abort(
1478 _('rebasing %d:%s will include unwanted changes from %s')
1475 _('rebasing %d:%s will include unwanted changes from %s')
1479 % (rev, repo[rev], unwanteddesc))
1476 % (rev, repo[rev], unwanteddesc))
1480
1477
1481 repo.ui.debug(" future parents are %d and %d\n" % tuple(newps))
1478 repo.ui.debug(" future parents are %d and %d\n" % tuple(newps))
1482
1479
1483 return newps[0], newps[1], base
1480 return newps[0], newps[1], base
1484
1481
1485 def isagitpatch(repo, patchname):
1482 def isagitpatch(repo, patchname):
1486 'Return true if the given patch is in git format'
1483 'Return true if the given patch is in git format'
1487 mqpatch = os.path.join(repo.mq.path, patchname)
1484 mqpatch = os.path.join(repo.mq.path, patchname)
1488 for line in patch.linereader(open(mqpatch, 'rb')):
1485 for line in patch.linereader(open(mqpatch, 'rb')):
1489 if line.startswith('diff --git'):
1486 if line.startswith('diff --git'):
1490 return True
1487 return True
1491 return False
1488 return False
1492
1489
1493 def updatemq(repo, state, skipped, **opts):
1490 def updatemq(repo, state, skipped, **opts):
1494 'Update rebased mq patches - finalize and then import them'
1491 'Update rebased mq patches - finalize and then import them'
1495 mqrebase = {}
1492 mqrebase = {}
1496 mq = repo.mq
1493 mq = repo.mq
1497 original_series = mq.fullseries[:]
1494 original_series = mq.fullseries[:]
1498 skippedpatches = set()
1495 skippedpatches = set()
1499
1496
1500 for p in mq.applied:
1497 for p in mq.applied:
1501 rev = repo[p.node].rev()
1498 rev = repo[p.node].rev()
1502 if rev in state:
1499 if rev in state:
1503 repo.ui.debug('revision %d is an mq patch (%s), finalize it.\n' %
1500 repo.ui.debug('revision %d is an mq patch (%s), finalize it.\n' %
1504 (rev, p.name))
1501 (rev, p.name))
1505 mqrebase[rev] = (p.name, isagitpatch(repo, p.name))
1502 mqrebase[rev] = (p.name, isagitpatch(repo, p.name))
1506 else:
1503 else:
1507 # Applied but not rebased, not sure this should happen
1504 # Applied but not rebased, not sure this should happen
1508 skippedpatches.add(p.name)
1505 skippedpatches.add(p.name)
1509
1506
1510 if mqrebase:
1507 if mqrebase:
1511 mq.finish(repo, mqrebase.keys())
1508 mq.finish(repo, mqrebase.keys())
1512
1509
1513 # We must start import from the newest revision
1510 # We must start import from the newest revision
1514 for rev in sorted(mqrebase, reverse=True):
1511 for rev in sorted(mqrebase, reverse=True):
1515 if rev not in skipped:
1512 if rev not in skipped:
1516 name, isgit = mqrebase[rev]
1513 name, isgit = mqrebase[rev]
1517 repo.ui.note(_('updating mq patch %s to %d:%s\n') %
1514 repo.ui.note(_('updating mq patch %s to %d:%s\n') %
1518 (name, state[rev], repo[state[rev]]))
1515 (name, state[rev], repo[state[rev]]))
1519 mq.qimport(repo, (), patchname=name, git=isgit,
1516 mq.qimport(repo, (), patchname=name, git=isgit,
1520 rev=["%d" % state[rev]])
1517 rev=["%d" % state[rev]])
1521 else:
1518 else:
1522 # Rebased and skipped
1519 # Rebased and skipped
1523 skippedpatches.add(mqrebase[rev][0])
1520 skippedpatches.add(mqrebase[rev][0])
1524
1521
1525 # Patches were either applied and rebased and imported in
1522 # Patches were either applied and rebased and imported in
1526 # order, applied and removed or unapplied. Discard the removed
1523 # order, applied and removed or unapplied. Discard the removed
1527 # ones while preserving the original series order and guards.
1524 # ones while preserving the original series order and guards.
1528 newseries = [s for s in original_series
1525 newseries = [s for s in original_series
1529 if mq.guard_re.split(s, 1)[0] not in skippedpatches]
1526 if mq.guard_re.split(s, 1)[0] not in skippedpatches]
1530 mq.fullseries[:] = newseries
1527 mq.fullseries[:] = newseries
1531 mq.seriesdirty = True
1528 mq.seriesdirty = True
1532 mq.savedirty()
1529 mq.savedirty()
1533
1530
1534 def storecollapsemsg(repo, collapsemsg):
1531 def storecollapsemsg(repo, collapsemsg):
1535 'Store the collapse message to allow recovery'
1532 'Store the collapse message to allow recovery'
1536 collapsemsg = collapsemsg or ''
1533 collapsemsg = collapsemsg or ''
1537 f = repo.vfs("last-message.txt", "w")
1534 f = repo.vfs("last-message.txt", "w")
1538 f.write("%s\n" % collapsemsg)
1535 f.write("%s\n" % collapsemsg)
1539 f.close()
1536 f.close()
1540
1537
1541 def clearcollapsemsg(repo):
1538 def clearcollapsemsg(repo):
1542 'Remove collapse message file'
1539 'Remove collapse message file'
1543 repo.vfs.unlinkpath("last-message.txt", ignoremissing=True)
1540 repo.vfs.unlinkpath("last-message.txt", ignoremissing=True)
1544
1541
1545 def restorecollapsemsg(repo, isabort):
1542 def restorecollapsemsg(repo, isabort):
1546 'Restore previously stored collapse message'
1543 'Restore previously stored collapse message'
1547 try:
1544 try:
1548 f = repo.vfs("last-message.txt")
1545 f = repo.vfs("last-message.txt")
1549 collapsemsg = f.readline().strip()
1546 collapsemsg = f.readline().strip()
1550 f.close()
1547 f.close()
1551 except IOError as err:
1548 except IOError as err:
1552 if err.errno != errno.ENOENT:
1549 if err.errno != errno.ENOENT:
1553 raise
1550 raise
1554 if isabort:
1551 if isabort:
1555 # Oh well, just abort like normal
1552 # Oh well, just abort like normal
1556 collapsemsg = ''
1553 collapsemsg = ''
1557 else:
1554 else:
1558 raise error.Abort(_('missing .hg/last-message.txt for rebase'))
1555 raise error.Abort(_('missing .hg/last-message.txt for rebase'))
1559 return collapsemsg
1556 return collapsemsg
1560
1557
1561 def clearstatus(repo):
1558 def clearstatus(repo):
1562 'Remove the status files'
1559 'Remove the status files'
1563 # Make sure the active transaction won't write the state file
1560 # Make sure the active transaction won't write the state file
1564 tr = repo.currenttransaction()
1561 tr = repo.currenttransaction()
1565 if tr:
1562 if tr:
1566 tr.removefilegenerator('rebasestate')
1563 tr.removefilegenerator('rebasestate')
1567 repo.vfs.unlinkpath("rebasestate", ignoremissing=True)
1564 repo.vfs.unlinkpath("rebasestate", ignoremissing=True)
1568
1565
1569 def needupdate(repo, state):
1566 def needupdate(repo, state):
1570 '''check whether we should `update --clean` away from a merge, or if
1567 '''check whether we should `update --clean` away from a merge, or if
1571 somehow the working dir got forcibly updated, e.g. by older hg'''
1568 somehow the working dir got forcibly updated, e.g. by older hg'''
1572 parents = [p.rev() for p in repo[None].parents()]
1569 parents = [p.rev() for p in repo[None].parents()]
1573
1570
1574 # Are we in a merge state at all?
1571 # Are we in a merge state at all?
1575 if len(parents) < 2:
1572 if len(parents) < 2:
1576 return False
1573 return False
1577
1574
1578 # We should be standing on the first as-of-yet unrebased commit.
1575 # We should be standing on the first as-of-yet unrebased commit.
1579 firstunrebased = min([old for old, new in state.iteritems()
1576 firstunrebased = min([old for old, new in state.iteritems()
1580 if new == nullrev])
1577 if new == nullrev])
1581 if firstunrebased in parents:
1578 if firstunrebased in parents:
1582 return True
1579 return True
1583
1580
1584 return False
1581 return False
1585
1582
1586 def abort(repo, originalwd, destmap, state, activebookmark=None, backup=True,
1583 def abort(repo, originalwd, destmap, state, activebookmark=None, backup=True,
1587 suppwarns=False):
1584 suppwarns=False):
1588 '''Restore the repository to its original state. Additional args:
1585 '''Restore the repository to its original state. Additional args:
1589
1586
1590 activebookmark: the name of the bookmark that should be active after the
1587 activebookmark: the name of the bookmark that should be active after the
1591 restore'''
1588 restore'''
1592
1589
1593 try:
1590 try:
1594 # If the first commits in the rebased set get skipped during the rebase,
1591 # If the first commits in the rebased set get skipped during the rebase,
1595 # their values within the state mapping will be the dest rev id. The
1592 # their values within the state mapping will be the dest rev id. The
1596 # rebased list must must not contain the dest rev (issue4896)
1593 # rebased list must must not contain the dest rev (issue4896)
1597 rebased = [s for r, s in state.items()
1594 rebased = [s for r, s in state.items()
1598 if s >= 0 and s != r and s != destmap[r]]
1595 if s >= 0 and s != r and s != destmap[r]]
1599 immutable = [d for d in rebased if not repo[d].mutable()]
1596 immutable = [d for d in rebased if not repo[d].mutable()]
1600 cleanup = True
1597 cleanup = True
1601 if immutable:
1598 if immutable:
1602 repo.ui.warn(_("warning: can't clean up public changesets %s\n")
1599 repo.ui.warn(_("warning: can't clean up public changesets %s\n")
1603 % ', '.join(bytes(repo[r]) for r in immutable),
1600 % ', '.join(bytes(repo[r]) for r in immutable),
1604 hint=_("see 'hg help phases' for details"))
1601 hint=_("see 'hg help phases' for details"))
1605 cleanup = False
1602 cleanup = False
1606
1603
1607 descendants = set()
1604 descendants = set()
1608 if rebased:
1605 if rebased:
1609 descendants = set(repo.changelog.descendants(rebased))
1606 descendants = set(repo.changelog.descendants(rebased))
1610 if descendants - set(rebased):
1607 if descendants - set(rebased):
1611 repo.ui.warn(_("warning: new changesets detected on destination "
1608 repo.ui.warn(_("warning: new changesets detected on destination "
1612 "branch, can't strip\n"))
1609 "branch, can't strip\n"))
1613 cleanup = False
1610 cleanup = False
1614
1611
1615 if cleanup:
1612 if cleanup:
1616 shouldupdate = False
1613 shouldupdate = False
1617 if rebased:
1614 if rebased:
1618 strippoints = [
1615 strippoints = [
1619 c.node() for c in repo.set('roots(%ld)', rebased)]
1616 c.node() for c in repo.set('roots(%ld)', rebased)]
1620
1617
1621 updateifonnodes = set(rebased)
1618 updateifonnodes = set(rebased)
1622 updateifonnodes.update(destmap.values())
1619 updateifonnodes.update(destmap.values())
1623 updateifonnodes.add(originalwd)
1620 updateifonnodes.add(originalwd)
1624 shouldupdate = repo['.'].rev() in updateifonnodes
1621 shouldupdate = repo['.'].rev() in updateifonnodes
1625
1622
1626 # Update away from the rebase if necessary
1623 # Update away from the rebase if necessary
1627 if shouldupdate or needupdate(repo, state):
1624 if shouldupdate or needupdate(repo, state):
1628 mergemod.update(repo, originalwd, False, True)
1625 mergemod.update(repo, originalwd, False, True)
1629
1626
1630 # Strip from the first rebased revision
1627 # Strip from the first rebased revision
1631 if rebased:
1628 if rebased:
1632 repair.strip(repo.ui, repo, strippoints, backup=backup)
1629 repair.strip(repo.ui, repo, strippoints, backup=backup)
1633
1630
1634 if activebookmark and activebookmark in repo._bookmarks:
1631 if activebookmark and activebookmark in repo._bookmarks:
1635 bookmarks.activate(repo, activebookmark)
1632 bookmarks.activate(repo, activebookmark)
1636
1633
1637 finally:
1634 finally:
1638 clearstatus(repo)
1635 clearstatus(repo)
1639 clearcollapsemsg(repo)
1636 clearcollapsemsg(repo)
1640 if not suppwarns:
1637 if not suppwarns:
1641 repo.ui.warn(_('rebase aborted\n'))
1638 repo.ui.warn(_('rebase aborted\n'))
1642 return 0
1639 return 0
1643
1640
1644 def sortsource(destmap):
1641 def sortsource(destmap):
1645 """yield source revisions in an order that we only rebase things once
1642 """yield source revisions in an order that we only rebase things once
1646
1643
1647 If source and destination overlaps, we should filter out revisions
1644 If source and destination overlaps, we should filter out revisions
1648 depending on other revisions which hasn't been rebased yet.
1645 depending on other revisions which hasn't been rebased yet.
1649
1646
1650 Yield a sorted list of revisions each time.
1647 Yield a sorted list of revisions each time.
1651
1648
1652 For example, when rebasing A to B, B to C. This function yields [B], then
1649 For example, when rebasing A to B, B to C. This function yields [B], then
1653 [A], indicating B needs to be rebased first.
1650 [A], indicating B needs to be rebased first.
1654
1651
1655 Raise if there is a cycle so the rebase is impossible.
1652 Raise if there is a cycle so the rebase is impossible.
1656 """
1653 """
1657 srcset = set(destmap)
1654 srcset = set(destmap)
1658 while srcset:
1655 while srcset:
1659 srclist = sorted(srcset)
1656 srclist = sorted(srcset)
1660 result = []
1657 result = []
1661 for r in srclist:
1658 for r in srclist:
1662 if destmap[r] not in srcset:
1659 if destmap[r] not in srcset:
1663 result.append(r)
1660 result.append(r)
1664 if not result:
1661 if not result:
1665 raise error.Abort(_('source and destination form a cycle'))
1662 raise error.Abort(_('source and destination form a cycle'))
1666 srcset -= set(result)
1663 srcset -= set(result)
1667 yield result
1664 yield result
1668
1665
1669 def buildstate(repo, destmap, collapse):
1666 def buildstate(repo, destmap, collapse):
1670 '''Define which revisions are going to be rebased and where
1667 '''Define which revisions are going to be rebased and where
1671
1668
1672 repo: repo
1669 repo: repo
1673 destmap: {srcrev: destrev}
1670 destmap: {srcrev: destrev}
1674 '''
1671 '''
1675 rebaseset = destmap.keys()
1672 rebaseset = destmap.keys()
1676 originalwd = repo['.'].rev()
1673 originalwd = repo['.'].rev()
1677
1674
1678 # This check isn't strictly necessary, since mq detects commits over an
1675 # This check isn't strictly necessary, since mq detects commits over an
1679 # applied patch. But it prevents messing up the working directory when
1676 # applied patch. But it prevents messing up the working directory when
1680 # a partially completed rebase is blocked by mq.
1677 # a partially completed rebase is blocked by mq.
1681 if 'qtip' in repo.tags():
1678 if 'qtip' in repo.tags():
1682 mqapplied = set(repo[s.node].rev() for s in repo.mq.applied)
1679 mqapplied = set(repo[s.node].rev() for s in repo.mq.applied)
1683 if set(destmap.values()) & mqapplied:
1680 if set(destmap.values()) & mqapplied:
1684 raise error.Abort(_('cannot rebase onto an applied mq patch'))
1681 raise error.Abort(_('cannot rebase onto an applied mq patch'))
1685
1682
1686 # Get "cycle" error early by exhausting the generator.
1683 # Get "cycle" error early by exhausting the generator.
1687 sortedsrc = list(sortsource(destmap)) # a list of sorted revs
1684 sortedsrc = list(sortsource(destmap)) # a list of sorted revs
1688 if not sortedsrc:
1685 if not sortedsrc:
1689 raise error.Abort(_('no matching revisions'))
1686 raise error.Abort(_('no matching revisions'))
1690
1687
1691 # Only check the first batch of revisions to rebase not depending on other
1688 # Only check the first batch of revisions to rebase not depending on other
1692 # rebaseset. This means "source is ancestor of destination" for the second
1689 # rebaseset. This means "source is ancestor of destination" for the second
1693 # (and following) batches of revisions are not checked here. We rely on
1690 # (and following) batches of revisions are not checked here. We rely on
1694 # "defineparents" to do that check.
1691 # "defineparents" to do that check.
1695 roots = list(repo.set('roots(%ld)', sortedsrc[0]))
1692 roots = list(repo.set('roots(%ld)', sortedsrc[0]))
1696 if not roots:
1693 if not roots:
1697 raise error.Abort(_('no matching revisions'))
1694 raise error.Abort(_('no matching revisions'))
1698 def revof(r):
1695 def revof(r):
1699 return r.rev()
1696 return r.rev()
1700 roots = sorted(roots, key=revof)
1697 roots = sorted(roots, key=revof)
1701 state = dict.fromkeys(rebaseset, revtodo)
1698 state = dict.fromkeys(rebaseset, revtodo)
1702 emptyrebase = (len(sortedsrc) == 1)
1699 emptyrebase = (len(sortedsrc) == 1)
1703 for root in roots:
1700 for root in roots:
1704 dest = repo[destmap[root.rev()]]
1701 dest = repo[destmap[root.rev()]]
1705 commonbase = root.ancestor(dest)
1702 commonbase = root.ancestor(dest)
1706 if commonbase == root:
1703 if commonbase == root:
1707 raise error.Abort(_('source is ancestor of destination'))
1704 raise error.Abort(_('source is ancestor of destination'))
1708 if commonbase == dest:
1705 if commonbase == dest:
1709 wctx = repo[None]
1706 wctx = repo[None]
1710 if dest == wctx.p1():
1707 if dest == wctx.p1():
1711 # when rebasing to '.', it will use the current wd branch name
1708 # when rebasing to '.', it will use the current wd branch name
1712 samebranch = root.branch() == wctx.branch()
1709 samebranch = root.branch() == wctx.branch()
1713 else:
1710 else:
1714 samebranch = root.branch() == dest.branch()
1711 samebranch = root.branch() == dest.branch()
1715 if not collapse and samebranch and dest in root.parents():
1712 if not collapse and samebranch and dest in root.parents():
1716 # mark the revision as done by setting its new revision
1713 # mark the revision as done by setting its new revision
1717 # equal to its old (current) revisions
1714 # equal to its old (current) revisions
1718 state[root.rev()] = root.rev()
1715 state[root.rev()] = root.rev()
1719 repo.ui.debug('source is a child of destination\n')
1716 repo.ui.debug('source is a child of destination\n')
1720 continue
1717 continue
1721
1718
1722 emptyrebase = False
1719 emptyrebase = False
1723 repo.ui.debug('rebase onto %s starting from %s\n' % (dest, root))
1720 repo.ui.debug('rebase onto %s starting from %s\n' % (dest, root))
1724 if emptyrebase:
1721 if emptyrebase:
1725 return None
1722 return None
1726 for rev in sorted(state):
1723 for rev in sorted(state):
1727 parents = [p for p in repo.changelog.parentrevs(rev) if p != nullrev]
1724 parents = [p for p in repo.changelog.parentrevs(rev) if p != nullrev]
1728 # if all parents of this revision are done, then so is this revision
1725 # if all parents of this revision are done, then so is this revision
1729 if parents and all((state.get(p) == p for p in parents)):
1726 if parents and all((state.get(p) == p for p in parents)):
1730 state[rev] = rev
1727 state[rev] = rev
1731 return originalwd, destmap, state
1728 return originalwd, destmap, state
1732
1729
1733 def clearrebased(ui, repo, destmap, state, skipped, collapsedas=None,
1730 def clearrebased(ui, repo, destmap, state, skipped, collapsedas=None,
1734 keepf=False, fm=None):
1731 keepf=False, fm=None):
1735 """dispose of rebased revision at the end of the rebase
1732 """dispose of rebased revision at the end of the rebase
1736
1733
1737 If `collapsedas` is not None, the rebase was a collapse whose result if the
1734 If `collapsedas` is not None, the rebase was a collapse whose result if the
1738 `collapsedas` node.
1735 `collapsedas` node.
1739
1736
1740 If `keepf` is not True, the rebase has --keep set and no nodes should be
1737 If `keepf` is not True, the rebase has --keep set and no nodes should be
1741 removed (but bookmarks still need to be moved).
1738 removed (but bookmarks still need to be moved).
1742 """
1739 """
1743 tonode = repo.changelog.node
1740 tonode = repo.changelog.node
1744 replacements = {}
1741 replacements = {}
1745 moves = {}
1742 moves = {}
1746 for rev, newrev in sorted(state.items()):
1743 for rev, newrev in sorted(state.items()):
1747 if newrev >= 0 and newrev != rev:
1744 if newrev >= 0 and newrev != rev:
1748 oldnode = tonode(rev)
1745 oldnode = tonode(rev)
1749 newnode = collapsedas or tonode(newrev)
1746 newnode = collapsedas or tonode(newrev)
1750 moves[oldnode] = newnode
1747 moves[oldnode] = newnode
1751 if not keepf:
1748 if not keepf:
1752 if rev in skipped:
1749 if rev in skipped:
1753 succs = ()
1750 succs = ()
1754 else:
1751 else:
1755 succs = (newnode,)
1752 succs = (newnode,)
1756 replacements[oldnode] = succs
1753 replacements[oldnode] = succs
1757 scmutil.cleanupnodes(repo, replacements, 'rebase', moves)
1754 scmutil.cleanupnodes(repo, replacements, 'rebase', moves)
1758 if fm:
1755 if fm:
1759 hf = fm.hexfunc
1756 hf = fm.hexfunc
1760 fl = fm.formatlist
1757 fl = fm.formatlist
1761 fd = fm.formatdict
1758 fd = fm.formatdict
1762 nodechanges = fd({hf(oldn): fl([hf(n) for n in newn], name='node')
1759 nodechanges = fd({hf(oldn): fl([hf(n) for n in newn], name='node')
1763 for oldn, newn in replacements.iteritems()},
1760 for oldn, newn in replacements.iteritems()},
1764 key="oldnode", value="newnodes")
1761 key="oldnode", value="newnodes")
1765 fm.data(nodechanges=nodechanges)
1762 fm.data(nodechanges=nodechanges)
1766
1763
1767 def pullrebase(orig, ui, repo, *args, **opts):
1764 def pullrebase(orig, ui, repo, *args, **opts):
1768 'Call rebase after pull if the latter has been invoked with --rebase'
1765 'Call rebase after pull if the latter has been invoked with --rebase'
1769 ret = None
1766 ret = None
1770 if opts.get(r'rebase'):
1767 if opts.get(r'rebase'):
1771 if ui.configbool('commands', 'rebase.requiredest'):
1768 if ui.configbool('commands', 'rebase.requiredest'):
1772 msg = _('rebase destination required by configuration')
1769 msg = _('rebase destination required by configuration')
1773 hint = _('use hg pull followed by hg rebase -d DEST')
1770 hint = _('use hg pull followed by hg rebase -d DEST')
1774 raise error.Abort(msg, hint=hint)
1771 raise error.Abort(msg, hint=hint)
1775
1772
1776 with repo.wlock(), repo.lock():
1773 with repo.wlock(), repo.lock():
1777 if opts.get(r'update'):
1774 if opts.get(r'update'):
1778 del opts[r'update']
1775 del opts[r'update']
1779 ui.debug('--update and --rebase are not compatible, ignoring '
1776 ui.debug('--update and --rebase are not compatible, ignoring '
1780 'the update flag\n')
1777 'the update flag\n')
1781
1778
1782 cmdutil.checkunfinished(repo)
1779 cmdutil.checkunfinished(repo)
1783 cmdutil.bailifchanged(repo, hint=_('cannot pull with rebase: '
1780 cmdutil.bailifchanged(repo, hint=_('cannot pull with rebase: '
1784 'please commit or shelve your changes first'))
1781 'please commit or shelve your changes first'))
1785
1782
1786 revsprepull = len(repo)
1783 revsprepull = len(repo)
1787 origpostincoming = commands.postincoming
1784 origpostincoming = commands.postincoming
1788 def _dummy(*args, **kwargs):
1785 def _dummy(*args, **kwargs):
1789 pass
1786 pass
1790 commands.postincoming = _dummy
1787 commands.postincoming = _dummy
1791 try:
1788 try:
1792 ret = orig(ui, repo, *args, **opts)
1789 ret = orig(ui, repo, *args, **opts)
1793 finally:
1790 finally:
1794 commands.postincoming = origpostincoming
1791 commands.postincoming = origpostincoming
1795 revspostpull = len(repo)
1792 revspostpull = len(repo)
1796 if revspostpull > revsprepull:
1793 if revspostpull > revsprepull:
1797 # --rev option from pull conflict with rebase own --rev
1794 # --rev option from pull conflict with rebase own --rev
1798 # dropping it
1795 # dropping it
1799 if r'rev' in opts:
1796 if r'rev' in opts:
1800 del opts[r'rev']
1797 del opts[r'rev']
1801 # positional argument from pull conflicts with rebase's own
1798 # positional argument from pull conflicts with rebase's own
1802 # --source.
1799 # --source.
1803 if r'source' in opts:
1800 if r'source' in opts:
1804 del opts[r'source']
1801 del opts[r'source']
1805 # revsprepull is the len of the repo, not revnum of tip.
1802 # revsprepull is the len of the repo, not revnum of tip.
1806 destspace = list(repo.changelog.revs(start=revsprepull))
1803 destspace = list(repo.changelog.revs(start=revsprepull))
1807 opts[r'_destspace'] = destspace
1804 opts[r'_destspace'] = destspace
1808 try:
1805 try:
1809 rebase(ui, repo, **opts)
1806 rebase(ui, repo, **opts)
1810 except error.NoMergeDestAbort:
1807 except error.NoMergeDestAbort:
1811 # we can maybe update instead
1808 # we can maybe update instead
1812 rev, _a, _b = destutil.destupdate(repo)
1809 rev, _a, _b = destutil.destupdate(repo)
1813 if rev == repo['.'].rev():
1810 if rev == repo['.'].rev():
1814 ui.status(_('nothing to rebase\n'))
1811 ui.status(_('nothing to rebase\n'))
1815 else:
1812 else:
1816 ui.status(_('nothing to rebase - updating instead\n'))
1813 ui.status(_('nothing to rebase - updating instead\n'))
1817 # not passing argument to get the bare update behavior
1814 # not passing argument to get the bare update behavior
1818 # with warning and trumpets
1815 # with warning and trumpets
1819 commands.update(ui, repo)
1816 commands.update(ui, repo)
1820 else:
1817 else:
1821 if opts.get(r'tool'):
1818 if opts.get(r'tool'):
1822 raise error.Abort(_('--tool can only be used with --rebase'))
1819 raise error.Abort(_('--tool can only be used with --rebase'))
1823 ret = orig(ui, repo, *args, **opts)
1820 ret = orig(ui, repo, *args, **opts)
1824
1821
1825 return ret
1822 return ret
1826
1823
1827 def _filterobsoleterevs(repo, revs):
1824 def _filterobsoleterevs(repo, revs):
1828 """returns a set of the obsolete revisions in revs"""
1825 """returns a set of the obsolete revisions in revs"""
1829 return set(r for r in revs if repo[r].obsolete())
1826 return set(r for r in revs if repo[r].obsolete())
1830
1827
1831 def _computeobsoletenotrebased(repo, rebaseobsrevs, destmap):
1828 def _computeobsoletenotrebased(repo, rebaseobsrevs, destmap):
1832 """Return (obsoletenotrebased, obsoletewithoutsuccessorindestination).
1829 """Return (obsoletenotrebased, obsoletewithoutsuccessorindestination).
1833
1830
1834 `obsoletenotrebased` is a mapping mapping obsolete => successor for all
1831 `obsoletenotrebased` is a mapping mapping obsolete => successor for all
1835 obsolete nodes to be rebased given in `rebaseobsrevs`.
1832 obsolete nodes to be rebased given in `rebaseobsrevs`.
1836
1833
1837 `obsoletewithoutsuccessorindestination` is a set with obsolete revisions
1834 `obsoletewithoutsuccessorindestination` is a set with obsolete revisions
1838 without a successor in destination.
1835 without a successor in destination.
1839
1836
1840 `obsoleteextinctsuccessors` is a set of obsolete revisions with only
1837 `obsoleteextinctsuccessors` is a set of obsolete revisions with only
1841 obsolete successors.
1838 obsolete successors.
1842 """
1839 """
1843 obsoletenotrebased = {}
1840 obsoletenotrebased = {}
1844 obsoletewithoutsuccessorindestination = set([])
1841 obsoletewithoutsuccessorindestination = set([])
1845 obsoleteextinctsuccessors = set([])
1842 obsoleteextinctsuccessors = set([])
1846
1843
1847 assert repo.filtername is None
1844 assert repo.filtername is None
1848 cl = repo.changelog
1845 cl = repo.changelog
1849 nodemap = cl.nodemap
1846 nodemap = cl.nodemap
1850 extinctrevs = set(repo.revs('extinct()'))
1847 extinctrevs = set(repo.revs('extinct()'))
1851 for srcrev in rebaseobsrevs:
1848 for srcrev in rebaseobsrevs:
1852 srcnode = cl.node(srcrev)
1849 srcnode = cl.node(srcrev)
1853 # XXX: more advanced APIs are required to handle split correctly
1850 # XXX: more advanced APIs are required to handle split correctly
1854 successors = set(obsutil.allsuccessors(repo.obsstore, [srcnode]))
1851 successors = set(obsutil.allsuccessors(repo.obsstore, [srcnode]))
1855 # obsutil.allsuccessors includes node itself
1852 # obsutil.allsuccessors includes node itself
1856 successors.remove(srcnode)
1853 successors.remove(srcnode)
1857 succrevs = {nodemap[s] for s in successors if s in nodemap}
1854 succrevs = {nodemap[s] for s in successors if s in nodemap}
1858 if succrevs.issubset(extinctrevs):
1855 if succrevs.issubset(extinctrevs):
1859 # all successors are extinct
1856 # all successors are extinct
1860 obsoleteextinctsuccessors.add(srcrev)
1857 obsoleteextinctsuccessors.add(srcrev)
1861 if not successors:
1858 if not successors:
1862 # no successor
1859 # no successor
1863 obsoletenotrebased[srcrev] = None
1860 obsoletenotrebased[srcrev] = None
1864 else:
1861 else:
1865 dstrev = destmap[srcrev]
1862 dstrev = destmap[srcrev]
1866 for succrev in succrevs:
1863 for succrev in succrevs:
1867 if cl.isancestorrev(succrev, dstrev):
1864 if cl.isancestorrev(succrev, dstrev):
1868 obsoletenotrebased[srcrev] = succrev
1865 obsoletenotrebased[srcrev] = succrev
1869 break
1866 break
1870 else:
1867 else:
1871 # If 'srcrev' has a successor in rebase set but none in
1868 # If 'srcrev' has a successor in rebase set but none in
1872 # destination (which would be catched above), we shall skip it
1869 # destination (which would be catched above), we shall skip it
1873 # and its descendants to avoid divergence.
1870 # and its descendants to avoid divergence.
1874 if any(s in destmap for s in succrevs):
1871 if any(s in destmap for s in succrevs):
1875 obsoletewithoutsuccessorindestination.add(srcrev)
1872 obsoletewithoutsuccessorindestination.add(srcrev)
1876
1873
1877 return (
1874 return (
1878 obsoletenotrebased,
1875 obsoletenotrebased,
1879 obsoletewithoutsuccessorindestination,
1876 obsoletewithoutsuccessorindestination,
1880 obsoleteextinctsuccessors,
1877 obsoleteextinctsuccessors,
1881 )
1878 )
1882
1879
1883 def summaryhook(ui, repo):
1880 def summaryhook(ui, repo):
1884 if not repo.vfs.exists('rebasestate'):
1881 if not repo.vfs.exists('rebasestate'):
1885 return
1882 return
1886 try:
1883 try:
1887 rbsrt = rebaseruntime(repo, ui, {})
1884 rbsrt = rebaseruntime(repo, ui, {})
1888 rbsrt.restorestatus()
1885 rbsrt.restorestatus()
1889 state = rbsrt.state
1886 state = rbsrt.state
1890 except error.RepoLookupError:
1887 except error.RepoLookupError:
1891 # i18n: column positioning for "hg summary"
1888 # i18n: column positioning for "hg summary"
1892 msg = _('rebase: (use "hg rebase --abort" to clear broken state)\n')
1889 msg = _('rebase: (use "hg rebase --abort" to clear broken state)\n')
1893 ui.write(msg)
1890 ui.write(msg)
1894 return
1891 return
1895 numrebased = len([i for i in state.itervalues() if i >= 0])
1892 numrebased = len([i for i in state.itervalues() if i >= 0])
1896 # i18n: column positioning for "hg summary"
1893 # i18n: column positioning for "hg summary"
1897 ui.write(_('rebase: %s, %s (rebase --continue)\n') %
1894 ui.write(_('rebase: %s, %s (rebase --continue)\n') %
1898 (ui.label(_('%d rebased'), 'rebase.rebased') % numrebased,
1895 (ui.label(_('%d rebased'), 'rebase.rebased') % numrebased,
1899 ui.label(_('%d remaining'), 'rebase.remaining') %
1896 ui.label(_('%d remaining'), 'rebase.remaining') %
1900 (len(state) - numrebased)))
1897 (len(state) - numrebased)))
1901
1898
1902 def uisetup(ui):
1899 def uisetup(ui):
1903 #Replace pull with a decorator to provide --rebase option
1900 #Replace pull with a decorator to provide --rebase option
1904 entry = extensions.wrapcommand(commands.table, 'pull', pullrebase)
1901 entry = extensions.wrapcommand(commands.table, 'pull', pullrebase)
1905 entry[1].append(('', 'rebase', None,
1902 entry[1].append(('', 'rebase', None,
1906 _("rebase working directory to branch head")))
1903 _("rebase working directory to branch head")))
1907 entry[1].append(('t', 'tool', '',
1904 entry[1].append(('t', 'tool', '',
1908 _("specify merge tool for rebase")))
1905 _("specify merge tool for rebase")))
1909 cmdutil.summaryhooks.add('rebase', summaryhook)
1906 cmdutil.summaryhooks.add('rebase', summaryhook)
1910 cmdutil.unfinishedstates.append(
1907 cmdutil.unfinishedstates.append(
1911 ['rebasestate', False, False, _('rebase in progress'),
1908 ['rebasestate', False, False, _('rebase in progress'),
1912 _("use 'hg rebase --continue' or 'hg rebase --abort'")])
1909 _("use 'hg rebase --continue' or 'hg rebase --abort'")])
1913 cmdutil.afterresolvedstates.append(
1910 cmdutil.afterresolvedstates.append(
1914 ['rebasestate', _('hg rebase --continue')])
1911 ['rebasestate', _('hg rebase --continue')])
General Comments 0
You need to be logged in to leave comments. Login now