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