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