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