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