##// END OF EJS Templates
rebase: change "result would have 3 parent" error message (BC)...
Jun Wu -
r33786:19f495fe default
parent child Browse files
Show More
@@ -1,1601 +1,1600 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 hex,
24 hex,
25 nullid,
25 nullid,
26 nullrev,
26 nullrev,
27 short,
27 short,
28 )
28 )
29 from mercurial import (
29 from mercurial import (
30 bookmarks,
30 bookmarks,
31 cmdutil,
31 cmdutil,
32 commands,
32 commands,
33 copies,
33 copies,
34 destutil,
34 destutil,
35 dirstateguard,
35 dirstateguard,
36 error,
36 error,
37 extensions,
37 extensions,
38 hg,
38 hg,
39 lock,
39 lock,
40 merge as mergemod,
40 merge as mergemod,
41 mergeutil,
41 mergeutil,
42 obsolete,
42 obsolete,
43 obsutil,
43 obsutil,
44 patch,
44 patch,
45 phases,
45 phases,
46 registrar,
46 registrar,
47 repair,
47 repair,
48 repoview,
48 repoview,
49 revset,
49 revset,
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 templateopts = cmdutil.templateopts
56 templateopts = cmdutil.templateopts
57
57
58 # The following constants are used throughout the rebase module. The ordering of
58 # The following constants are used throughout the rebase module. The ordering of
59 # their values must be maintained.
59 # their values must be maintained.
60
60
61 # Indicates that a revision needs to be rebased
61 # Indicates that a revision needs to be rebased
62 revtodo = -1
62 revtodo = -1
63 nullmerge = -2
63 nullmerge = -2
64 revignored = -3
64 revignored = -3
65 # successor in rebase destination
65 # successor in rebase destination
66 revprecursor = -4
66 revprecursor = -4
67 # plain prune (no successor)
67 # plain prune (no successor)
68 revpruned = -5
68 revpruned = -5
69
69
70 cmdtable = {}
70 cmdtable = {}
71 command = registrar.command(cmdtable)
71 command = registrar.command(cmdtable)
72 # Note for extension authors: ONLY specify testedwith = 'ships-with-hg-core' for
72 # Note for extension authors: ONLY specify testedwith = 'ships-with-hg-core' for
73 # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should
73 # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should
74 # be specifying the version(s) of Mercurial they are tested with, or
74 # be specifying the version(s) of Mercurial they are tested with, or
75 # leave the attribute unspecified.
75 # leave the attribute unspecified.
76 testedwith = 'ships-with-hg-core'
76 testedwith = 'ships-with-hg-core'
77
77
78 def _nothingtorebase():
78 def _nothingtorebase():
79 return 1
79 return 1
80
80
81 def _savegraft(ctx, extra):
81 def _savegraft(ctx, extra):
82 s = ctx.extra().get('source', None)
82 s = ctx.extra().get('source', None)
83 if s is not None:
83 if s is not None:
84 extra['source'] = s
84 extra['source'] = s
85 s = ctx.extra().get('intermediate-source', None)
85 s = ctx.extra().get('intermediate-source', None)
86 if s is not None:
86 if s is not None:
87 extra['intermediate-source'] = s
87 extra['intermediate-source'] = s
88
88
89 def _savebranch(ctx, extra):
89 def _savebranch(ctx, extra):
90 extra['branch'] = ctx.branch()
90 extra['branch'] = ctx.branch()
91
91
92 def _makeextrafn(copiers):
92 def _makeextrafn(copiers):
93 """make an extrafn out of the given copy-functions.
93 """make an extrafn out of the given copy-functions.
94
94
95 A copy function takes a context and an extra dict, and mutates the
95 A copy function takes a context and an extra dict, and mutates the
96 extra dict as needed based on the given context.
96 extra dict as needed based on the given context.
97 """
97 """
98 def extrafn(ctx, extra):
98 def extrafn(ctx, extra):
99 for c in copiers:
99 for c in copiers:
100 c(ctx, extra)
100 c(ctx, extra)
101 return extrafn
101 return extrafn
102
102
103 def _destrebase(repo, sourceset, destspace=None):
103 def _destrebase(repo, sourceset, destspace=None):
104 """small wrapper around destmerge to pass the right extra args
104 """small wrapper around destmerge to pass the right extra args
105
105
106 Please wrap destutil.destmerge instead."""
106 Please wrap destutil.destmerge instead."""
107 return destutil.destmerge(repo, action='rebase', sourceset=sourceset,
107 return destutil.destmerge(repo, action='rebase', sourceset=sourceset,
108 onheadcheck=False, destspace=destspace)
108 onheadcheck=False, destspace=destspace)
109
109
110 revsetpredicate = registrar.revsetpredicate()
110 revsetpredicate = registrar.revsetpredicate()
111
111
112 @revsetpredicate('_destrebase')
112 @revsetpredicate('_destrebase')
113 def _revsetdestrebase(repo, subset, x):
113 def _revsetdestrebase(repo, subset, x):
114 # ``_rebasedefaultdest()``
114 # ``_rebasedefaultdest()``
115
115
116 # default destination for rebase.
116 # default destination for rebase.
117 # # XXX: Currently private because I expect the signature to change.
117 # # XXX: Currently private because I expect the signature to change.
118 # # XXX: - bailing out in case of ambiguity vs returning all data.
118 # # XXX: - bailing out in case of ambiguity vs returning all data.
119 # i18n: "_rebasedefaultdest" is a keyword
119 # i18n: "_rebasedefaultdest" is a keyword
120 sourceset = None
120 sourceset = None
121 if x is not None:
121 if x is not None:
122 sourceset = revset.getset(repo, smartset.fullreposet(repo), x)
122 sourceset = revset.getset(repo, smartset.fullreposet(repo), x)
123 return subset & smartset.baseset([_destrebase(repo, sourceset)])
123 return subset & smartset.baseset([_destrebase(repo, sourceset)])
124
124
125 class rebaseruntime(object):
125 class rebaseruntime(object):
126 """This class is a container for rebase runtime state"""
126 """This class is a container for rebase runtime state"""
127 def __init__(self, repo, ui, opts=None):
127 def __init__(self, repo, ui, opts=None):
128 if opts is None:
128 if opts is None:
129 opts = {}
129 opts = {}
130
130
131 self.repo = repo
131 self.repo = repo
132 self.ui = ui
132 self.ui = ui
133 self.opts = opts
133 self.opts = opts
134 self.originalwd = None
134 self.originalwd = None
135 self.external = nullrev
135 self.external = nullrev
136 # Mapping between the old revision id and either what is the new rebased
136 # Mapping between the old revision id and either what is the new rebased
137 # revision or what needs to be done with the old revision. The state
137 # revision or what needs to be done with the old revision. The state
138 # dict will be what contains most of the rebase progress state.
138 # dict will be what contains most of the rebase progress state.
139 self.state = {}
139 self.state = {}
140 self.activebookmark = None
140 self.activebookmark = None
141 self.dest = None
141 self.dest = None
142 self.skipped = set()
142 self.skipped = set()
143 self.destancestors = set()
143 self.destancestors = set()
144
144
145 self.collapsef = opts.get('collapse', False)
145 self.collapsef = opts.get('collapse', False)
146 self.collapsemsg = cmdutil.logmessage(ui, opts)
146 self.collapsemsg = cmdutil.logmessage(ui, opts)
147 self.date = opts.get('date', None)
147 self.date = opts.get('date', None)
148
148
149 e = opts.get('extrafn') # internal, used by e.g. hgsubversion
149 e = opts.get('extrafn') # internal, used by e.g. hgsubversion
150 self.extrafns = [_savegraft]
150 self.extrafns = [_savegraft]
151 if e:
151 if e:
152 self.extrafns = [e]
152 self.extrafns = [e]
153
153
154 self.keepf = opts.get('keep', False)
154 self.keepf = opts.get('keep', False)
155 self.keepbranchesf = opts.get('keepbranches', False)
155 self.keepbranchesf = opts.get('keepbranches', False)
156 # keepopen is not meant for use on the command line, but by
156 # keepopen is not meant for use on the command line, but by
157 # other extensions
157 # other extensions
158 self.keepopen = opts.get('keepopen', False)
158 self.keepopen = opts.get('keepopen', False)
159 self.obsoletenotrebased = {}
159 self.obsoletenotrebased = {}
160
160
161 def storestatus(self, tr=None):
161 def storestatus(self, tr=None):
162 """Store the current status to allow recovery"""
162 """Store the current status to allow recovery"""
163 if tr:
163 if tr:
164 tr.addfilegenerator('rebasestate', ('rebasestate',),
164 tr.addfilegenerator('rebasestate', ('rebasestate',),
165 self._writestatus, location='plain')
165 self._writestatus, location='plain')
166 else:
166 else:
167 with self.repo.vfs("rebasestate", "w") as f:
167 with self.repo.vfs("rebasestate", "w") as f:
168 self._writestatus(f)
168 self._writestatus(f)
169
169
170 def _writestatus(self, f):
170 def _writestatus(self, f):
171 repo = self.repo.unfiltered()
171 repo = self.repo.unfiltered()
172 f.write(repo[self.originalwd].hex() + '\n')
172 f.write(repo[self.originalwd].hex() + '\n')
173 f.write(repo[self.dest].hex() + '\n')
173 f.write(repo[self.dest].hex() + '\n')
174 f.write(repo[self.external].hex() + '\n')
174 f.write(repo[self.external].hex() + '\n')
175 f.write('%d\n' % int(self.collapsef))
175 f.write('%d\n' % int(self.collapsef))
176 f.write('%d\n' % int(self.keepf))
176 f.write('%d\n' % int(self.keepf))
177 f.write('%d\n' % int(self.keepbranchesf))
177 f.write('%d\n' % int(self.keepbranchesf))
178 f.write('%s\n' % (self.activebookmark or ''))
178 f.write('%s\n' % (self.activebookmark or ''))
179 for d, v in self.state.iteritems():
179 for d, v in self.state.iteritems():
180 oldrev = repo[d].hex()
180 oldrev = repo[d].hex()
181 if v >= 0:
181 if v >= 0:
182 newrev = repo[v].hex()
182 newrev = repo[v].hex()
183 elif v == revtodo:
183 elif v == revtodo:
184 # To maintain format compatibility, we have to use nullid.
184 # To maintain format compatibility, we have to use nullid.
185 # Please do remove this special case when upgrading the format.
185 # Please do remove this special case when upgrading the format.
186 newrev = hex(nullid)
186 newrev = hex(nullid)
187 else:
187 else:
188 newrev = v
188 newrev = v
189 f.write("%s:%s\n" % (oldrev, newrev))
189 f.write("%s:%s\n" % (oldrev, newrev))
190 repo.ui.debug('rebase status stored\n')
190 repo.ui.debug('rebase status stored\n')
191
191
192 def restorestatus(self):
192 def restorestatus(self):
193 """Restore a previously stored status"""
193 """Restore a previously stored status"""
194 repo = self.repo
194 repo = self.repo
195 keepbranches = None
195 keepbranches = None
196 dest = None
196 dest = None
197 collapse = False
197 collapse = False
198 external = nullrev
198 external = nullrev
199 activebookmark = None
199 activebookmark = None
200 state = {}
200 state = {}
201
201
202 try:
202 try:
203 f = repo.vfs("rebasestate")
203 f = repo.vfs("rebasestate")
204 for i, l in enumerate(f.read().splitlines()):
204 for i, l in enumerate(f.read().splitlines()):
205 if i == 0:
205 if i == 0:
206 originalwd = repo[l].rev()
206 originalwd = repo[l].rev()
207 elif i == 1:
207 elif i == 1:
208 dest = repo[l].rev()
208 dest = repo[l].rev()
209 elif i == 2:
209 elif i == 2:
210 external = repo[l].rev()
210 external = repo[l].rev()
211 elif i == 3:
211 elif i == 3:
212 collapse = bool(int(l))
212 collapse = bool(int(l))
213 elif i == 4:
213 elif i == 4:
214 keep = bool(int(l))
214 keep = bool(int(l))
215 elif i == 5:
215 elif i == 5:
216 keepbranches = bool(int(l))
216 keepbranches = bool(int(l))
217 elif i == 6 and not (len(l) == 81 and ':' in l):
217 elif i == 6 and not (len(l) == 81 and ':' in l):
218 # line 6 is a recent addition, so for backwards
218 # line 6 is a recent addition, so for backwards
219 # compatibility check that the line doesn't look like the
219 # compatibility check that the line doesn't look like the
220 # oldrev:newrev lines
220 # oldrev:newrev lines
221 activebookmark = l
221 activebookmark = l
222 else:
222 else:
223 oldrev, newrev = l.split(':')
223 oldrev, newrev = l.split(':')
224 if newrev in (str(nullmerge), str(revignored),
224 if newrev in (str(nullmerge), str(revignored),
225 str(revprecursor), str(revpruned)):
225 str(revprecursor), str(revpruned)):
226 state[repo[oldrev].rev()] = int(newrev)
226 state[repo[oldrev].rev()] = int(newrev)
227 elif newrev == nullid:
227 elif newrev == nullid:
228 state[repo[oldrev].rev()] = revtodo
228 state[repo[oldrev].rev()] = revtodo
229 # Legacy compat special case
229 # Legacy compat special case
230 else:
230 else:
231 state[repo[oldrev].rev()] = repo[newrev].rev()
231 state[repo[oldrev].rev()] = repo[newrev].rev()
232
232
233 except IOError as err:
233 except IOError as err:
234 if err.errno != errno.ENOENT:
234 if err.errno != errno.ENOENT:
235 raise
235 raise
236 cmdutil.wrongtooltocontinue(repo, _('rebase'))
236 cmdutil.wrongtooltocontinue(repo, _('rebase'))
237
237
238 if keepbranches is None:
238 if keepbranches is None:
239 raise error.Abort(_('.hg/rebasestate is incomplete'))
239 raise error.Abort(_('.hg/rebasestate is incomplete'))
240
240
241 skipped = set()
241 skipped = set()
242 # recompute the set of skipped revs
242 # recompute the set of skipped revs
243 if not collapse:
243 if not collapse:
244 seen = {dest}
244 seen = {dest}
245 for old, new in sorted(state.items()):
245 for old, new in sorted(state.items()):
246 if new != revtodo and new in seen:
246 if new != revtodo and new in seen:
247 skipped.add(old)
247 skipped.add(old)
248 seen.add(new)
248 seen.add(new)
249 repo.ui.debug('computed skipped revs: %s\n' %
249 repo.ui.debug('computed skipped revs: %s\n' %
250 (' '.join(str(r) for r in sorted(skipped)) or None))
250 (' '.join(str(r) for r in sorted(skipped)) or None))
251 repo.ui.debug('rebase status resumed\n')
251 repo.ui.debug('rebase status resumed\n')
252 _setrebasesetvisibility(repo, set(state.keys()) | {originalwd})
252 _setrebasesetvisibility(repo, set(state.keys()) | {originalwd})
253
253
254 self.originalwd = originalwd
254 self.originalwd = originalwd
255 self.dest = dest
255 self.dest = dest
256 self.state = state
256 self.state = state
257 self.skipped = skipped
257 self.skipped = skipped
258 self.collapsef = collapse
258 self.collapsef = collapse
259 self.keepf = keep
259 self.keepf = keep
260 self.keepbranchesf = keepbranches
260 self.keepbranchesf = keepbranches
261 self.external = external
261 self.external = external
262 self.activebookmark = activebookmark
262 self.activebookmark = activebookmark
263
263
264 def _handleskippingobsolete(self, rebaserevs, obsoleterevs, dest):
264 def _handleskippingobsolete(self, rebaserevs, obsoleterevs, dest):
265 """Compute structures necessary for skipping obsolete revisions
265 """Compute structures necessary for skipping obsolete revisions
266
266
267 rebaserevs: iterable of all revisions that are to be rebased
267 rebaserevs: iterable of all revisions that are to be rebased
268 obsoleterevs: iterable of all obsolete revisions in rebaseset
268 obsoleterevs: iterable of all obsolete revisions in rebaseset
269 dest: a destination revision for the rebase operation
269 dest: a destination revision for the rebase operation
270 """
270 """
271 self.obsoletenotrebased = {}
271 self.obsoletenotrebased = {}
272 if not self.ui.configbool('experimental', 'rebaseskipobsolete',
272 if not self.ui.configbool('experimental', 'rebaseskipobsolete',
273 default=True):
273 default=True):
274 return
274 return
275 rebaseset = set(rebaserevs)
275 rebaseset = set(rebaserevs)
276 obsoleteset = set(obsoleterevs)
276 obsoleteset = set(obsoleterevs)
277 self.obsoletenotrebased = _computeobsoletenotrebased(self.repo,
277 self.obsoletenotrebased = _computeobsoletenotrebased(self.repo,
278 obsoleteset, dest)
278 obsoleteset, dest)
279 skippedset = set(self.obsoletenotrebased)
279 skippedset = set(self.obsoletenotrebased)
280 _checkobsrebase(self.repo, self.ui, obsoleteset, rebaseset, skippedset)
280 _checkobsrebase(self.repo, self.ui, obsoleteset, rebaseset, skippedset)
281
281
282 def _prepareabortorcontinue(self, isabort):
282 def _prepareabortorcontinue(self, isabort):
283 try:
283 try:
284 self.restorestatus()
284 self.restorestatus()
285 self.collapsemsg = restorecollapsemsg(self.repo, isabort)
285 self.collapsemsg = restorecollapsemsg(self.repo, isabort)
286 except error.RepoLookupError:
286 except error.RepoLookupError:
287 if isabort:
287 if isabort:
288 clearstatus(self.repo)
288 clearstatus(self.repo)
289 clearcollapsemsg(self.repo)
289 clearcollapsemsg(self.repo)
290 self.repo.ui.warn(_('rebase aborted (no revision is removed,'
290 self.repo.ui.warn(_('rebase aborted (no revision is removed,'
291 ' only broken state is cleared)\n'))
291 ' only broken state is cleared)\n'))
292 return 0
292 return 0
293 else:
293 else:
294 msg = _('cannot continue inconsistent rebase')
294 msg = _('cannot continue inconsistent rebase')
295 hint = _('use "hg rebase --abort" to clear broken state')
295 hint = _('use "hg rebase --abort" to clear broken state')
296 raise error.Abort(msg, hint=hint)
296 raise error.Abort(msg, hint=hint)
297 if isabort:
297 if isabort:
298 return abort(self.repo, self.originalwd, self.dest,
298 return abort(self.repo, self.originalwd, self.dest,
299 self.state, activebookmark=self.activebookmark)
299 self.state, activebookmark=self.activebookmark)
300
300
301 obsrevs = (r for r, st in self.state.items() if st == revprecursor)
301 obsrevs = (r for r, st in self.state.items() if st == revprecursor)
302 self._handleskippingobsolete(self.state.keys(), obsrevs, self.dest)
302 self._handleskippingobsolete(self.state.keys(), obsrevs, self.dest)
303
303
304 def _preparenewrebase(self, dest, rebaseset):
304 def _preparenewrebase(self, dest, rebaseset):
305 if dest is None:
305 if dest is None:
306 return _nothingtorebase()
306 return _nothingtorebase()
307
307
308 allowunstable = obsolete.isenabled(self.repo, obsolete.allowunstableopt)
308 allowunstable = obsolete.isenabled(self.repo, obsolete.allowunstableopt)
309 if (not (self.keepf or allowunstable)
309 if (not (self.keepf or allowunstable)
310 and self.repo.revs('first(children(%ld) - %ld)',
310 and self.repo.revs('first(children(%ld) - %ld)',
311 rebaseset, rebaseset)):
311 rebaseset, rebaseset)):
312 raise error.Abort(
312 raise error.Abort(
313 _("can't remove original changesets with"
313 _("can't remove original changesets with"
314 " unrebased descendants"),
314 " unrebased descendants"),
315 hint=_('use --keep to keep original changesets'))
315 hint=_('use --keep to keep original changesets'))
316
316
317 obsrevs = _filterobsoleterevs(self.repo, set(rebaseset))
317 obsrevs = _filterobsoleterevs(self.repo, set(rebaseset))
318 self._handleskippingobsolete(rebaseset, obsrevs, dest.rev())
318 self._handleskippingobsolete(rebaseset, obsrevs, dest.rev())
319
319
320 result = buildstate(self.repo, dest, rebaseset, self.collapsef,
320 result = buildstate(self.repo, dest, rebaseset, self.collapsef,
321 self.obsoletenotrebased)
321 self.obsoletenotrebased)
322
322
323 if not result:
323 if not result:
324 # Empty state built, nothing to rebase
324 # Empty state built, nothing to rebase
325 self.ui.status(_('nothing to rebase\n'))
325 self.ui.status(_('nothing to rebase\n'))
326 return _nothingtorebase()
326 return _nothingtorebase()
327
327
328 for root in self.repo.set('roots(%ld)', rebaseset):
328 for root in self.repo.set('roots(%ld)', rebaseset):
329 if not self.keepf and not root.mutable():
329 if not self.keepf and not root.mutable():
330 raise error.Abort(_("can't rebase public changeset %s")
330 raise error.Abort(_("can't rebase public changeset %s")
331 % root,
331 % root,
332 hint=_("see 'hg help phases' for details"))
332 hint=_("see 'hg help phases' for details"))
333
333
334 (self.originalwd, self.dest, self.state) = result
334 (self.originalwd, self.dest, self.state) = result
335 if self.collapsef:
335 if self.collapsef:
336 self.destancestors = self.repo.changelog.ancestors(
336 self.destancestors = self.repo.changelog.ancestors(
337 [self.dest],
337 [self.dest],
338 inclusive=True)
338 inclusive=True)
339 self.external = externalparent(self.repo, self.state,
339 self.external = externalparent(self.repo, self.state,
340 self.destancestors)
340 self.destancestors)
341
341
342 if dest.closesbranch() and not self.keepbranchesf:
342 if dest.closesbranch() and not self.keepbranchesf:
343 self.ui.status(_('reopening closed branch head %s\n') % dest)
343 self.ui.status(_('reopening closed branch head %s\n') % dest)
344
344
345 def _performrebase(self, tr):
345 def _performrebase(self, tr):
346 repo, ui, opts = self.repo, self.ui, self.opts
346 repo, ui, opts = self.repo, self.ui, self.opts
347 if self.keepbranchesf:
347 if self.keepbranchesf:
348 # insert _savebranch at the start of extrafns so if
348 # insert _savebranch at the start of extrafns so if
349 # there's a user-provided extrafn it can clobber branch if
349 # there's a user-provided extrafn it can clobber branch if
350 # desired
350 # desired
351 self.extrafns.insert(0, _savebranch)
351 self.extrafns.insert(0, _savebranch)
352 if self.collapsef:
352 if self.collapsef:
353 branches = set()
353 branches = set()
354 for rev in self.state:
354 for rev in self.state:
355 branches.add(repo[rev].branch())
355 branches.add(repo[rev].branch())
356 if len(branches) > 1:
356 if len(branches) > 1:
357 raise error.Abort(_('cannot collapse multiple named '
357 raise error.Abort(_('cannot collapse multiple named '
358 'branches'))
358 'branches'))
359
359
360 # Rebase
360 # Rebase
361 if not self.destancestors:
361 if not self.destancestors:
362 self.destancestors = repo.changelog.ancestors([self.dest],
362 self.destancestors = repo.changelog.ancestors([self.dest],
363 inclusive=True)
363 inclusive=True)
364
364
365 # Keep track of the active bookmarks in order to reset them later
365 # Keep track of the active bookmarks in order to reset them later
366 self.activebookmark = self.activebookmark or repo._activebookmark
366 self.activebookmark = self.activebookmark or repo._activebookmark
367 if self.activebookmark:
367 if self.activebookmark:
368 bookmarks.deactivate(repo)
368 bookmarks.deactivate(repo)
369
369
370 # Store the state before we begin so users can run 'hg rebase --abort'
370 # Store the state before we begin so users can run 'hg rebase --abort'
371 # if we fail before the transaction closes.
371 # if we fail before the transaction closes.
372 self.storestatus()
372 self.storestatus()
373
373
374 sortedrevs = repo.revs('sort(%ld, -topo)', self.state)
374 sortedrevs = repo.revs('sort(%ld, -topo)', self.state)
375 cands = [k for k, v in self.state.iteritems() if v == revtodo]
375 cands = [k for k, v in self.state.iteritems() if v == revtodo]
376 total = len(cands)
376 total = len(cands)
377 pos = 0
377 pos = 0
378 for rev in sortedrevs:
378 for rev in sortedrevs:
379 ctx = repo[rev]
379 ctx = repo[rev]
380 desc = '%d:%s "%s"' % (ctx.rev(), ctx,
380 desc = '%d:%s "%s"' % (ctx.rev(), ctx,
381 ctx.description().split('\n', 1)[0])
381 ctx.description().split('\n', 1)[0])
382 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
382 names = repo.nodetags(ctx.node()) + repo.nodebookmarks(ctx.node())
383 if names:
383 if names:
384 desc += ' (%s)' % ' '.join(names)
384 desc += ' (%s)' % ' '.join(names)
385 if self.state[rev] == rev:
385 if self.state[rev] == rev:
386 ui.status(_('already rebased %s\n') % desc)
386 ui.status(_('already rebased %s\n') % desc)
387 elif self.state[rev] == revtodo:
387 elif self.state[rev] == revtodo:
388 pos += 1
388 pos += 1
389 ui.status(_('rebasing %s\n') % desc)
389 ui.status(_('rebasing %s\n') % desc)
390 ui.progress(_("rebasing"), pos, ("%d:%s" % (rev, ctx)),
390 ui.progress(_("rebasing"), pos, ("%d:%s" % (rev, ctx)),
391 _('changesets'), total)
391 _('changesets'), total)
392 p1, p2, base = defineparents(repo, rev, self.dest, self.state)
392 p1, p2, base = defineparents(repo, rev, self.dest, self.state)
393 self.storestatus(tr=tr)
393 self.storestatus(tr=tr)
394 storecollapsemsg(repo, self.collapsemsg)
394 storecollapsemsg(repo, self.collapsemsg)
395 if len(repo[None].parents()) == 2:
395 if len(repo[None].parents()) == 2:
396 repo.ui.debug('resuming interrupted rebase\n')
396 repo.ui.debug('resuming interrupted rebase\n')
397 else:
397 else:
398 try:
398 try:
399 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
399 ui.setconfig('ui', 'forcemerge', opts.get('tool', ''),
400 'rebase')
400 'rebase')
401 stats = rebasenode(repo, rev, p1, base, self.state,
401 stats = rebasenode(repo, rev, p1, base, self.state,
402 self.collapsef, self.dest)
402 self.collapsef, self.dest)
403 if stats and stats[3] > 0:
403 if stats and stats[3] > 0:
404 raise error.InterventionRequired(
404 raise error.InterventionRequired(
405 _('unresolved conflicts (see hg '
405 _('unresolved conflicts (see hg '
406 'resolve, then hg rebase --continue)'))
406 'resolve, then hg rebase --continue)'))
407 finally:
407 finally:
408 ui.setconfig('ui', 'forcemerge', '', 'rebase')
408 ui.setconfig('ui', 'forcemerge', '', 'rebase')
409 if not self.collapsef:
409 if not self.collapsef:
410 merging = p2 != nullrev
410 merging = p2 != nullrev
411 editform = cmdutil.mergeeditform(merging, 'rebase')
411 editform = cmdutil.mergeeditform(merging, 'rebase')
412 editor = cmdutil.getcommiteditor(editform=editform, **opts)
412 editor = cmdutil.getcommiteditor(editform=editform, **opts)
413 newnode = concludenode(repo, rev, p1, p2,
413 newnode = concludenode(repo, rev, p1, p2,
414 extrafn=_makeextrafn(self.extrafns),
414 extrafn=_makeextrafn(self.extrafns),
415 editor=editor,
415 editor=editor,
416 keepbranches=self.keepbranchesf,
416 keepbranches=self.keepbranchesf,
417 date=self.date)
417 date=self.date)
418 if newnode is None:
418 if newnode is None:
419 # If it ended up being a no-op commit, then the normal
419 # If it ended up being a no-op commit, then the normal
420 # merge state clean-up path doesn't happen, so do it
420 # merge state clean-up path doesn't happen, so do it
421 # here. Fix issue5494
421 # here. Fix issue5494
422 mergemod.mergestate.clean(repo)
422 mergemod.mergestate.clean(repo)
423 else:
423 else:
424 # Skip commit if we are collapsing
424 # Skip commit if we are collapsing
425 repo.setparents(repo[p1].node())
425 repo.setparents(repo[p1].node())
426 newnode = None
426 newnode = None
427 # Update the state
427 # Update the state
428 if newnode is not None:
428 if newnode is not None:
429 self.state[rev] = repo[newnode].rev()
429 self.state[rev] = repo[newnode].rev()
430 ui.debug('rebased as %s\n' % short(newnode))
430 ui.debug('rebased as %s\n' % short(newnode))
431 else:
431 else:
432 if not self.collapsef:
432 if not self.collapsef:
433 ui.warn(_('note: rebase of %d:%s created no changes '
433 ui.warn(_('note: rebase of %d:%s created no changes '
434 'to commit\n') % (rev, ctx))
434 'to commit\n') % (rev, ctx))
435 self.skipped.add(rev)
435 self.skipped.add(rev)
436 self.state[rev] = p1
436 self.state[rev] = p1
437 ui.debug('next revision set to %s\n' % p1)
437 ui.debug('next revision set to %s\n' % p1)
438 elif self.state[rev] == nullmerge:
438 elif self.state[rev] == nullmerge:
439 ui.debug('ignoring null merge rebase of %s\n' % rev)
439 ui.debug('ignoring null merge rebase of %s\n' % rev)
440 elif self.state[rev] == revignored:
440 elif self.state[rev] == revignored:
441 ui.status(_('not rebasing ignored %s\n') % desc)
441 ui.status(_('not rebasing ignored %s\n') % desc)
442 elif self.state[rev] == revprecursor:
442 elif self.state[rev] == revprecursor:
443 destctx = repo[self.obsoletenotrebased[rev]]
443 destctx = repo[self.obsoletenotrebased[rev]]
444 descdest = '%d:%s "%s"' % (destctx.rev(), destctx,
444 descdest = '%d:%s "%s"' % (destctx.rev(), destctx,
445 destctx.description().split('\n', 1)[0])
445 destctx.description().split('\n', 1)[0])
446 msg = _('note: not rebasing %s, already in destination as %s\n')
446 msg = _('note: not rebasing %s, already in destination as %s\n')
447 ui.status(msg % (desc, descdest))
447 ui.status(msg % (desc, descdest))
448 elif self.state[rev] == revpruned:
448 elif self.state[rev] == revpruned:
449 msg = _('note: not rebasing %s, it has no successor\n')
449 msg = _('note: not rebasing %s, it has no successor\n')
450 ui.status(msg % desc)
450 ui.status(msg % desc)
451 else:
451 else:
452 ui.status(_('already rebased %s as %s\n') %
452 ui.status(_('already rebased %s as %s\n') %
453 (desc, repo[self.state[rev]]))
453 (desc, repo[self.state[rev]]))
454
454
455 ui.progress(_('rebasing'), None)
455 ui.progress(_('rebasing'), None)
456 ui.note(_('rebase merging completed\n'))
456 ui.note(_('rebase merging completed\n'))
457
457
458 def _finishrebase(self):
458 def _finishrebase(self):
459 repo, ui, opts = self.repo, self.ui, self.opts
459 repo, ui, opts = self.repo, self.ui, self.opts
460 if self.collapsef and not self.keepopen:
460 if self.collapsef and not self.keepopen:
461 p1, p2, _base = defineparents(repo, min(self.state),
461 p1, p2, _base = defineparents(repo, min(self.state),
462 self.dest, self.state)
462 self.dest, self.state)
463 editopt = opts.get('edit')
463 editopt = opts.get('edit')
464 editform = 'rebase.collapse'
464 editform = 'rebase.collapse'
465 if self.collapsemsg:
465 if self.collapsemsg:
466 commitmsg = self.collapsemsg
466 commitmsg = self.collapsemsg
467 else:
467 else:
468 commitmsg = 'Collapsed revision'
468 commitmsg = 'Collapsed revision'
469 for rebased in sorted(self.state):
469 for rebased in sorted(self.state):
470 if rebased not in self.skipped and\
470 if rebased not in self.skipped and\
471 self.state[rebased] > nullmerge:
471 self.state[rebased] > nullmerge:
472 commitmsg += '\n* %s' % repo[rebased].description()
472 commitmsg += '\n* %s' % repo[rebased].description()
473 editopt = True
473 editopt = True
474 editor = cmdutil.getcommiteditor(edit=editopt, editform=editform)
474 editor = cmdutil.getcommiteditor(edit=editopt, editform=editform)
475 revtoreuse = max(self.state)
475 revtoreuse = max(self.state)
476
476
477 dsguard = None
477 dsguard = None
478 if ui.configbool('rebase', 'singletransaction'):
478 if ui.configbool('rebase', 'singletransaction'):
479 dsguard = dirstateguard.dirstateguard(repo, 'rebase')
479 dsguard = dirstateguard.dirstateguard(repo, 'rebase')
480 with util.acceptintervention(dsguard):
480 with util.acceptintervention(dsguard):
481 newnode = concludenode(repo, revtoreuse, p1, self.external,
481 newnode = concludenode(repo, revtoreuse, p1, self.external,
482 commitmsg=commitmsg,
482 commitmsg=commitmsg,
483 extrafn=_makeextrafn(self.extrafns),
483 extrafn=_makeextrafn(self.extrafns),
484 editor=editor,
484 editor=editor,
485 keepbranches=self.keepbranchesf,
485 keepbranches=self.keepbranchesf,
486 date=self.date)
486 date=self.date)
487 if newnode is None:
487 if newnode is None:
488 newrev = self.dest
488 newrev = self.dest
489 else:
489 else:
490 newrev = repo[newnode].rev()
490 newrev = repo[newnode].rev()
491 for oldrev in self.state.iterkeys():
491 for oldrev in self.state.iterkeys():
492 if self.state[oldrev] > nullmerge:
492 if self.state[oldrev] > nullmerge:
493 self.state[oldrev] = newrev
493 self.state[oldrev] = newrev
494
494
495 if 'qtip' in repo.tags():
495 if 'qtip' in repo.tags():
496 updatemq(repo, self.state, self.skipped, **opts)
496 updatemq(repo, self.state, self.skipped, **opts)
497
497
498 # restore original working directory
498 # restore original working directory
499 # (we do this before stripping)
499 # (we do this before stripping)
500 newwd = self.state.get(self.originalwd, self.originalwd)
500 newwd = self.state.get(self.originalwd, self.originalwd)
501 if newwd == revprecursor:
501 if newwd == revprecursor:
502 newwd = self.obsoletenotrebased[self.originalwd]
502 newwd = self.obsoletenotrebased[self.originalwd]
503 elif newwd < 0:
503 elif newwd < 0:
504 # original directory is a parent of rebase set root or ignored
504 # original directory is a parent of rebase set root or ignored
505 newwd = self.originalwd
505 newwd = self.originalwd
506 if newwd not in [c.rev() for c in repo[None].parents()]:
506 if newwd not in [c.rev() for c in repo[None].parents()]:
507 ui.note(_("update back to initial working directory parent\n"))
507 ui.note(_("update back to initial working directory parent\n"))
508 hg.updaterepo(repo, newwd, False)
508 hg.updaterepo(repo, newwd, False)
509
509
510 if not self.keepf:
510 if not self.keepf:
511 collapsedas = None
511 collapsedas = None
512 if self.collapsef:
512 if self.collapsef:
513 collapsedas = newnode
513 collapsedas = newnode
514 clearrebased(ui, repo, self.dest, self.state, self.skipped,
514 clearrebased(ui, repo, self.dest, self.state, self.skipped,
515 collapsedas)
515 collapsedas)
516
516
517 clearstatus(repo)
517 clearstatus(repo)
518 clearcollapsemsg(repo)
518 clearcollapsemsg(repo)
519
519
520 ui.note(_("rebase completed\n"))
520 ui.note(_("rebase completed\n"))
521 util.unlinkpath(repo.sjoin('undo'), ignoremissing=True)
521 util.unlinkpath(repo.sjoin('undo'), ignoremissing=True)
522 if self.skipped:
522 if self.skipped:
523 skippedlen = len(self.skipped)
523 skippedlen = len(self.skipped)
524 ui.note(_("%d revisions have been skipped\n") % skippedlen)
524 ui.note(_("%d revisions have been skipped\n") % skippedlen)
525
525
526 if (self.activebookmark and self.activebookmark in repo._bookmarks and
526 if (self.activebookmark and self.activebookmark in repo._bookmarks and
527 repo['.'].node() == repo._bookmarks[self.activebookmark]):
527 repo['.'].node() == repo._bookmarks[self.activebookmark]):
528 bookmarks.activate(repo, self.activebookmark)
528 bookmarks.activate(repo, self.activebookmark)
529
529
530 @command('rebase',
530 @command('rebase',
531 [('s', 'source', '',
531 [('s', 'source', '',
532 _('rebase the specified changeset and descendants'), _('REV')),
532 _('rebase the specified changeset and descendants'), _('REV')),
533 ('b', 'base', '',
533 ('b', 'base', '',
534 _('rebase everything from branching point of specified changeset'),
534 _('rebase everything from branching point of specified changeset'),
535 _('REV')),
535 _('REV')),
536 ('r', 'rev', [],
536 ('r', 'rev', [],
537 _('rebase these revisions'),
537 _('rebase these revisions'),
538 _('REV')),
538 _('REV')),
539 ('d', 'dest', '',
539 ('d', 'dest', '',
540 _('rebase onto the specified changeset'), _('REV')),
540 _('rebase onto the specified changeset'), _('REV')),
541 ('', 'collapse', False, _('collapse the rebased changesets')),
541 ('', 'collapse', False, _('collapse the rebased changesets')),
542 ('m', 'message', '',
542 ('m', 'message', '',
543 _('use text as collapse commit message'), _('TEXT')),
543 _('use text as collapse commit message'), _('TEXT')),
544 ('e', 'edit', False, _('invoke editor on commit messages')),
544 ('e', 'edit', False, _('invoke editor on commit messages')),
545 ('l', 'logfile', '',
545 ('l', 'logfile', '',
546 _('read collapse commit message from file'), _('FILE')),
546 _('read collapse commit message from file'), _('FILE')),
547 ('k', 'keep', False, _('keep original changesets')),
547 ('k', 'keep', False, _('keep original changesets')),
548 ('', 'keepbranches', False, _('keep original branch names')),
548 ('', 'keepbranches', False, _('keep original branch names')),
549 ('D', 'detach', False, _('(DEPRECATED)')),
549 ('D', 'detach', False, _('(DEPRECATED)')),
550 ('i', 'interactive', False, _('(DEPRECATED)')),
550 ('i', 'interactive', False, _('(DEPRECATED)')),
551 ('t', 'tool', '', _('specify merge tool')),
551 ('t', 'tool', '', _('specify merge tool')),
552 ('c', 'continue', False, _('continue an interrupted rebase')),
552 ('c', 'continue', False, _('continue an interrupted rebase')),
553 ('a', 'abort', False, _('abort an interrupted rebase'))] +
553 ('a', 'abort', False, _('abort an interrupted rebase'))] +
554 templateopts,
554 templateopts,
555 _('[-s REV | -b REV] [-d REV] [OPTION]'))
555 _('[-s REV | -b REV] [-d REV] [OPTION]'))
556 def rebase(ui, repo, **opts):
556 def rebase(ui, repo, **opts):
557 """move changeset (and descendants) to a different branch
557 """move changeset (and descendants) to a different branch
558
558
559 Rebase uses repeated merging to graft changesets from one part of
559 Rebase uses repeated merging to graft changesets from one part of
560 history (the source) onto another (the destination). This can be
560 history (the source) onto another (the destination). This can be
561 useful for linearizing *local* changes relative to a master
561 useful for linearizing *local* changes relative to a master
562 development tree.
562 development tree.
563
563
564 Published commits cannot be rebased (see :hg:`help phases`).
564 Published commits cannot be rebased (see :hg:`help phases`).
565 To copy commits, see :hg:`help graft`.
565 To copy commits, see :hg:`help graft`.
566
566
567 If you don't specify a destination changeset (``-d/--dest``), rebase
567 If you don't specify a destination changeset (``-d/--dest``), rebase
568 will use the same logic as :hg:`merge` to pick a destination. if
568 will use the same logic as :hg:`merge` to pick a destination. if
569 the current branch contains exactly one other head, the other head
569 the current branch contains exactly one other head, the other head
570 is merged with by default. Otherwise, an explicit revision with
570 is merged with by default. Otherwise, an explicit revision with
571 which to merge with must be provided. (destination changeset is not
571 which to merge with must be provided. (destination changeset is not
572 modified by rebasing, but new changesets are added as its
572 modified by rebasing, but new changesets are added as its
573 descendants.)
573 descendants.)
574
574
575 Here are the ways to select changesets:
575 Here are the ways to select changesets:
576
576
577 1. Explicitly select them using ``--rev``.
577 1. Explicitly select them using ``--rev``.
578
578
579 2. Use ``--source`` to select a root changeset and include all of its
579 2. Use ``--source`` to select a root changeset and include all of its
580 descendants.
580 descendants.
581
581
582 3. Use ``--base`` to select a changeset; rebase will find ancestors
582 3. Use ``--base`` to select a changeset; rebase will find ancestors
583 and their descendants which are not also ancestors of the destination.
583 and their descendants which are not also ancestors of the destination.
584
584
585 4. If you do not specify any of ``--rev``, ``source``, or ``--base``,
585 4. If you do not specify any of ``--rev``, ``source``, or ``--base``,
586 rebase will use ``--base .`` as above.
586 rebase will use ``--base .`` as above.
587
587
588 Rebase will destroy original changesets unless you use ``--keep``.
588 Rebase will destroy original changesets unless you use ``--keep``.
589 It will also move your bookmarks (even if you do).
589 It will also move your bookmarks (even if you do).
590
590
591 Some changesets may be dropped if they do not contribute changes
591 Some changesets may be dropped if they do not contribute changes
592 (e.g. merges from the destination branch).
592 (e.g. merges from the destination branch).
593
593
594 Unlike ``merge``, rebase will do nothing if you are at the branch tip of
594 Unlike ``merge``, rebase will do nothing if you are at the branch tip of
595 a named branch with two heads. You will need to explicitly specify source
595 a named branch with two heads. You will need to explicitly specify source
596 and/or destination.
596 and/or destination.
597
597
598 If you need to use a tool to automate merge/conflict decisions, you
598 If you need to use a tool to automate merge/conflict decisions, you
599 can specify one with ``--tool``, see :hg:`help merge-tools`.
599 can specify one with ``--tool``, see :hg:`help merge-tools`.
600 As a caveat: the tool will not be used to mediate when a file was
600 As a caveat: the tool will not be used to mediate when a file was
601 deleted, there is no hook presently available for this.
601 deleted, there is no hook presently available for this.
602
602
603 If a rebase is interrupted to manually resolve a conflict, it can be
603 If a rebase is interrupted to manually resolve a conflict, it can be
604 continued with --continue/-c or aborted with --abort/-a.
604 continued with --continue/-c or aborted with --abort/-a.
605
605
606 .. container:: verbose
606 .. container:: verbose
607
607
608 Examples:
608 Examples:
609
609
610 - move "local changes" (current commit back to branching point)
610 - move "local changes" (current commit back to branching point)
611 to the current branch tip after a pull::
611 to the current branch tip after a pull::
612
612
613 hg rebase
613 hg rebase
614
614
615 - move a single changeset to the stable branch::
615 - move a single changeset to the stable branch::
616
616
617 hg rebase -r 5f493448 -d stable
617 hg rebase -r 5f493448 -d stable
618
618
619 - splice a commit and all its descendants onto another part of history::
619 - splice a commit and all its descendants onto another part of history::
620
620
621 hg rebase --source c0c3 --dest 4cf9
621 hg rebase --source c0c3 --dest 4cf9
622
622
623 - rebase everything on a branch marked by a bookmark onto the
623 - rebase everything on a branch marked by a bookmark onto the
624 default branch::
624 default branch::
625
625
626 hg rebase --base myfeature --dest default
626 hg rebase --base myfeature --dest default
627
627
628 - collapse a sequence of changes into a single commit::
628 - collapse a sequence of changes into a single commit::
629
629
630 hg rebase --collapse -r 1520:1525 -d .
630 hg rebase --collapse -r 1520:1525 -d .
631
631
632 - move a named branch while preserving its name::
632 - move a named branch while preserving its name::
633
633
634 hg rebase -r "branch(featureX)" -d 1.3 --keepbranches
634 hg rebase -r "branch(featureX)" -d 1.3 --keepbranches
635
635
636 Configuration Options:
636 Configuration Options:
637
637
638 You can make rebase require a destination if you set the following config
638 You can make rebase require a destination if you set the following config
639 option::
639 option::
640
640
641 [commands]
641 [commands]
642 rebase.requiredest = True
642 rebase.requiredest = True
643
643
644 By default, rebase will close the transaction after each commit. For
644 By default, rebase will close the transaction after each commit. For
645 performance purposes, you can configure rebase to use a single transaction
645 performance purposes, you can configure rebase to use a single transaction
646 across the entire rebase. WARNING: This setting introduces a significant
646 across the entire rebase. WARNING: This setting introduces a significant
647 risk of losing the work you've done in a rebase if the rebase aborts
647 risk of losing the work you've done in a rebase if the rebase aborts
648 unexpectedly::
648 unexpectedly::
649
649
650 [rebase]
650 [rebase]
651 singletransaction = True
651 singletransaction = True
652
652
653 Return Values:
653 Return Values:
654
654
655 Returns 0 on success, 1 if nothing to rebase or there are
655 Returns 0 on success, 1 if nothing to rebase or there are
656 unresolved conflicts.
656 unresolved conflicts.
657
657
658 """
658 """
659 rbsrt = rebaseruntime(repo, ui, opts)
659 rbsrt = rebaseruntime(repo, ui, opts)
660
660
661 with repo.wlock(), repo.lock():
661 with repo.wlock(), repo.lock():
662 # Validate input and define rebasing points
662 # Validate input and define rebasing points
663 destf = opts.get('dest', None)
663 destf = opts.get('dest', None)
664 srcf = opts.get('source', None)
664 srcf = opts.get('source', None)
665 basef = opts.get('base', None)
665 basef = opts.get('base', None)
666 revf = opts.get('rev', [])
666 revf = opts.get('rev', [])
667 # search default destination in this space
667 # search default destination in this space
668 # used in the 'hg pull --rebase' case, see issue 5214.
668 # used in the 'hg pull --rebase' case, see issue 5214.
669 destspace = opts.get('_destspace')
669 destspace = opts.get('_destspace')
670 contf = opts.get('continue')
670 contf = opts.get('continue')
671 abortf = opts.get('abort')
671 abortf = opts.get('abort')
672 if opts.get('interactive'):
672 if opts.get('interactive'):
673 try:
673 try:
674 if extensions.find('histedit'):
674 if extensions.find('histedit'):
675 enablehistedit = ''
675 enablehistedit = ''
676 except KeyError:
676 except KeyError:
677 enablehistedit = " --config extensions.histedit="
677 enablehistedit = " --config extensions.histedit="
678 help = "hg%s help -e histedit" % enablehistedit
678 help = "hg%s help -e histedit" % enablehistedit
679 msg = _("interactive history editing is supported by the "
679 msg = _("interactive history editing is supported by the "
680 "'histedit' extension (see \"%s\")") % help
680 "'histedit' extension (see \"%s\")") % help
681 raise error.Abort(msg)
681 raise error.Abort(msg)
682
682
683 if rbsrt.collapsemsg and not rbsrt.collapsef:
683 if rbsrt.collapsemsg and not rbsrt.collapsef:
684 raise error.Abort(
684 raise error.Abort(
685 _('message can only be specified with collapse'))
685 _('message can only be specified with collapse'))
686
686
687 if contf or abortf:
687 if contf or abortf:
688 if contf and abortf:
688 if contf and abortf:
689 raise error.Abort(_('cannot use both abort and continue'))
689 raise error.Abort(_('cannot use both abort and continue'))
690 if rbsrt.collapsef:
690 if rbsrt.collapsef:
691 raise error.Abort(
691 raise error.Abort(
692 _('cannot use collapse with continue or abort'))
692 _('cannot use collapse with continue or abort'))
693 if srcf or basef or destf:
693 if srcf or basef or destf:
694 raise error.Abort(
694 raise error.Abort(
695 _('abort and continue do not allow specifying revisions'))
695 _('abort and continue do not allow specifying revisions'))
696 if abortf and opts.get('tool', False):
696 if abortf and opts.get('tool', False):
697 ui.warn(_('tool option will be ignored\n'))
697 ui.warn(_('tool option will be ignored\n'))
698 if contf:
698 if contf:
699 ms = mergemod.mergestate.read(repo)
699 ms = mergemod.mergestate.read(repo)
700 mergeutil.checkunresolved(ms)
700 mergeutil.checkunresolved(ms)
701
701
702 retcode = rbsrt._prepareabortorcontinue(abortf)
702 retcode = rbsrt._prepareabortorcontinue(abortf)
703 if retcode is not None:
703 if retcode is not None:
704 return retcode
704 return retcode
705 else:
705 else:
706 dest, rebaseset = _definesets(ui, repo, destf, srcf, basef, revf,
706 dest, rebaseset = _definesets(ui, repo, destf, srcf, basef, revf,
707 destspace=destspace)
707 destspace=destspace)
708 retcode = rbsrt._preparenewrebase(dest, rebaseset)
708 retcode = rbsrt._preparenewrebase(dest, rebaseset)
709 if retcode is not None:
709 if retcode is not None:
710 return retcode
710 return retcode
711
711
712 tr = None
712 tr = None
713 dsguard = None
713 dsguard = None
714
714
715 singletr = ui.configbool('rebase', 'singletransaction')
715 singletr = ui.configbool('rebase', 'singletransaction')
716 if singletr:
716 if singletr:
717 tr = repo.transaction('rebase')
717 tr = repo.transaction('rebase')
718 with util.acceptintervention(tr):
718 with util.acceptintervention(tr):
719 if singletr:
719 if singletr:
720 dsguard = dirstateguard.dirstateguard(repo, 'rebase')
720 dsguard = dirstateguard.dirstateguard(repo, 'rebase')
721 with util.acceptintervention(dsguard):
721 with util.acceptintervention(dsguard):
722 rbsrt._performrebase(tr)
722 rbsrt._performrebase(tr)
723
723
724 rbsrt._finishrebase()
724 rbsrt._finishrebase()
725
725
726 def _definesets(ui, repo, destf=None, srcf=None, basef=None, revf=None,
726 def _definesets(ui, repo, destf=None, srcf=None, basef=None, revf=None,
727 destspace=None):
727 destspace=None):
728 """use revisions argument to define destination and rebase set
728 """use revisions argument to define destination and rebase set
729 """
729 """
730 if revf is None:
730 if revf is None:
731 revf = []
731 revf = []
732
732
733 # destspace is here to work around issues with `hg pull --rebase` see
733 # destspace is here to work around issues with `hg pull --rebase` see
734 # issue5214 for details
734 # issue5214 for details
735 if srcf and basef:
735 if srcf and basef:
736 raise error.Abort(_('cannot specify both a source and a base'))
736 raise error.Abort(_('cannot specify both a source and a base'))
737 if revf and basef:
737 if revf and basef:
738 raise error.Abort(_('cannot specify both a revision and a base'))
738 raise error.Abort(_('cannot specify both a revision and a base'))
739 if revf and srcf:
739 if revf and srcf:
740 raise error.Abort(_('cannot specify both a revision and a source'))
740 raise error.Abort(_('cannot specify both a revision and a source'))
741
741
742 cmdutil.checkunfinished(repo)
742 cmdutil.checkunfinished(repo)
743 cmdutil.bailifchanged(repo)
743 cmdutil.bailifchanged(repo)
744
744
745 if ui.configbool('commands', 'rebase.requiredest') and not destf:
745 if ui.configbool('commands', 'rebase.requiredest') and not destf:
746 raise error.Abort(_('you must specify a destination'),
746 raise error.Abort(_('you must specify a destination'),
747 hint=_('use: hg rebase -d REV'))
747 hint=_('use: hg rebase -d REV'))
748
748
749 if destf:
749 if destf:
750 dest = scmutil.revsingle(repo, destf)
750 dest = scmutil.revsingle(repo, destf)
751
751
752 if revf:
752 if revf:
753 rebaseset = scmutil.revrange(repo, revf)
753 rebaseset = scmutil.revrange(repo, revf)
754 if not rebaseset:
754 if not rebaseset:
755 ui.status(_('empty "rev" revision set - nothing to rebase\n'))
755 ui.status(_('empty "rev" revision set - nothing to rebase\n'))
756 return None, None
756 return None, None
757 elif srcf:
757 elif srcf:
758 src = scmutil.revrange(repo, [srcf])
758 src = scmutil.revrange(repo, [srcf])
759 if not src:
759 if not src:
760 ui.status(_('empty "source" revision set - nothing to rebase\n'))
760 ui.status(_('empty "source" revision set - nothing to rebase\n'))
761 return None, None
761 return None, None
762 rebaseset = repo.revs('(%ld)::', src)
762 rebaseset = repo.revs('(%ld)::', src)
763 assert rebaseset
763 assert rebaseset
764 else:
764 else:
765 base = scmutil.revrange(repo, [basef or '.'])
765 base = scmutil.revrange(repo, [basef or '.'])
766 if not base:
766 if not base:
767 ui.status(_('empty "base" revision set - '
767 ui.status(_('empty "base" revision set - '
768 "can't compute rebase set\n"))
768 "can't compute rebase set\n"))
769 return None, None
769 return None, None
770 if not destf:
770 if not destf:
771 dest = repo[_destrebase(repo, base, destspace=destspace)]
771 dest = repo[_destrebase(repo, base, destspace=destspace)]
772 destf = str(dest)
772 destf = str(dest)
773
773
774 roots = [] # selected children of branching points
774 roots = [] # selected children of branching points
775 bpbase = {} # {branchingpoint: [origbase]}
775 bpbase = {} # {branchingpoint: [origbase]}
776 for b in base: # group bases by branching points
776 for b in base: # group bases by branching points
777 bp = repo.revs('ancestor(%d, %d)', b, dest).first()
777 bp = repo.revs('ancestor(%d, %d)', b, dest).first()
778 bpbase[bp] = bpbase.get(bp, []) + [b]
778 bpbase[bp] = bpbase.get(bp, []) + [b]
779 if None in bpbase:
779 if None in bpbase:
780 # emulate the old behavior, showing "nothing to rebase" (a better
780 # emulate the old behavior, showing "nothing to rebase" (a better
781 # behavior may be abort with "cannot find branching point" error)
781 # behavior may be abort with "cannot find branching point" error)
782 bpbase.clear()
782 bpbase.clear()
783 for bp, bs in bpbase.iteritems(): # calculate roots
783 for bp, bs in bpbase.iteritems(): # calculate roots
784 roots += list(repo.revs('children(%d) & ancestors(%ld)', bp, bs))
784 roots += list(repo.revs('children(%d) & ancestors(%ld)', bp, bs))
785
785
786 rebaseset = repo.revs('%ld::', roots)
786 rebaseset = repo.revs('%ld::', roots)
787
787
788 if not rebaseset:
788 if not rebaseset:
789 # transform to list because smartsets are not comparable to
789 # transform to list because smartsets are not comparable to
790 # lists. This should be improved to honor laziness of
790 # lists. This should be improved to honor laziness of
791 # smartset.
791 # smartset.
792 if list(base) == [dest.rev()]:
792 if list(base) == [dest.rev()]:
793 if basef:
793 if basef:
794 ui.status(_('nothing to rebase - %s is both "base"'
794 ui.status(_('nothing to rebase - %s is both "base"'
795 ' and destination\n') % dest)
795 ' and destination\n') % dest)
796 else:
796 else:
797 ui.status(_('nothing to rebase - working directory '
797 ui.status(_('nothing to rebase - working directory '
798 'parent is also destination\n'))
798 'parent is also destination\n'))
799 elif not repo.revs('%ld - ::%d', base, dest):
799 elif not repo.revs('%ld - ::%d', base, dest):
800 if basef:
800 if basef:
801 ui.status(_('nothing to rebase - "base" %s is '
801 ui.status(_('nothing to rebase - "base" %s is '
802 'already an ancestor of destination '
802 'already an ancestor of destination '
803 '%s\n') %
803 '%s\n') %
804 ('+'.join(str(repo[r]) for r in base),
804 ('+'.join(str(repo[r]) for r in base),
805 dest))
805 dest))
806 else:
806 else:
807 ui.status(_('nothing to rebase - working '
807 ui.status(_('nothing to rebase - working '
808 'directory parent is already an '
808 'directory parent is already an '
809 'ancestor of destination %s\n') % dest)
809 'ancestor of destination %s\n') % dest)
810 else: # can it happen?
810 else: # can it happen?
811 ui.status(_('nothing to rebase from %s to %s\n') %
811 ui.status(_('nothing to rebase from %s to %s\n') %
812 ('+'.join(str(repo[r]) for r in base), dest))
812 ('+'.join(str(repo[r]) for r in base), dest))
813 return None, None
813 return None, None
814
814
815 if not destf:
815 if not destf:
816 dest = repo[_destrebase(repo, rebaseset, destspace=destspace)]
816 dest = repo[_destrebase(repo, rebaseset, destspace=destspace)]
817 destf = str(dest)
817 destf = str(dest)
818
818
819 return dest, rebaseset
819 return dest, rebaseset
820
820
821 def externalparent(repo, state, destancestors):
821 def externalparent(repo, state, destancestors):
822 """Return the revision that should be used as the second parent
822 """Return the revision that should be used as the second parent
823 when the revisions in state is collapsed on top of destancestors.
823 when the revisions in state is collapsed on top of destancestors.
824 Abort if there is more than one parent.
824 Abort if there is more than one parent.
825 """
825 """
826 parents = set()
826 parents = set()
827 source = min(state)
827 source = min(state)
828 for rev in state:
828 for rev in state:
829 if rev == source:
829 if rev == source:
830 continue
830 continue
831 for p in repo[rev].parents():
831 for p in repo[rev].parents():
832 if (p.rev() not in state
832 if (p.rev() not in state
833 and p.rev() not in destancestors):
833 and p.rev() not in destancestors):
834 parents.add(p.rev())
834 parents.add(p.rev())
835 if not parents:
835 if not parents:
836 return nullrev
836 return nullrev
837 if len(parents) == 1:
837 if len(parents) == 1:
838 return parents.pop()
838 return parents.pop()
839 raise error.Abort(_('unable to collapse on top of %s, there is more '
839 raise error.Abort(_('unable to collapse on top of %s, there is more '
840 'than one external parent: %s') %
840 'than one external parent: %s') %
841 (max(destancestors),
841 (max(destancestors),
842 ', '.join(str(p) for p in sorted(parents))))
842 ', '.join(str(p) for p in sorted(parents))))
843
843
844 def concludenode(repo, rev, p1, p2, commitmsg=None, editor=None, extrafn=None,
844 def concludenode(repo, rev, p1, p2, commitmsg=None, editor=None, extrafn=None,
845 keepbranches=False, date=None):
845 keepbranches=False, date=None):
846 '''Commit the wd changes with parents p1 and p2. Reuse commit info from rev
846 '''Commit the wd changes with parents p1 and p2. Reuse commit info from rev
847 but also store useful information in extra.
847 but also store useful information in extra.
848 Return node of committed revision.'''
848 Return node of committed revision.'''
849 dsguard = util.nullcontextmanager()
849 dsguard = util.nullcontextmanager()
850 if not repo.ui.configbool('rebase', 'singletransaction'):
850 if not repo.ui.configbool('rebase', 'singletransaction'):
851 dsguard = dirstateguard.dirstateguard(repo, 'rebase')
851 dsguard = dirstateguard.dirstateguard(repo, 'rebase')
852 with dsguard:
852 with dsguard:
853 repo.setparents(repo[p1].node(), repo[p2].node())
853 repo.setparents(repo[p1].node(), repo[p2].node())
854 ctx = repo[rev]
854 ctx = repo[rev]
855 if commitmsg is None:
855 if commitmsg is None:
856 commitmsg = ctx.description()
856 commitmsg = ctx.description()
857 keepbranch = keepbranches and repo[p1].branch() != ctx.branch()
857 keepbranch = keepbranches and repo[p1].branch() != ctx.branch()
858 extra = {'rebase_source': ctx.hex()}
858 extra = {'rebase_source': ctx.hex()}
859 if extrafn:
859 if extrafn:
860 extrafn(ctx, extra)
860 extrafn(ctx, extra)
861
861
862 destphase = max(ctx.phase(), phases.draft)
862 destphase = max(ctx.phase(), phases.draft)
863 overrides = {('phases', 'new-commit'): destphase}
863 overrides = {('phases', 'new-commit'): destphase}
864 with repo.ui.configoverride(overrides, 'rebase'):
864 with repo.ui.configoverride(overrides, 'rebase'):
865 if keepbranch:
865 if keepbranch:
866 repo.ui.setconfig('ui', 'allowemptycommit', True)
866 repo.ui.setconfig('ui', 'allowemptycommit', True)
867 # Commit might fail if unresolved files exist
867 # Commit might fail if unresolved files exist
868 if date is None:
868 if date is None:
869 date = ctx.date()
869 date = ctx.date()
870 newnode = repo.commit(text=commitmsg, user=ctx.user(),
870 newnode = repo.commit(text=commitmsg, user=ctx.user(),
871 date=date, extra=extra, editor=editor)
871 date=date, extra=extra, editor=editor)
872
872
873 repo.dirstate.setbranch(repo[newnode].branch())
873 repo.dirstate.setbranch(repo[newnode].branch())
874 return newnode
874 return newnode
875
875
876 def rebasenode(repo, rev, p1, base, state, collapse, dest):
876 def rebasenode(repo, rev, p1, base, state, collapse, dest):
877 'Rebase a single revision rev on top of p1 using base as merge ancestor'
877 'Rebase a single revision rev on top of p1 using base as merge ancestor'
878 # Merge phase
878 # Merge phase
879 # Update to destination and merge it with local
879 # Update to destination and merge it with local
880 if repo['.'].rev() != p1:
880 if repo['.'].rev() != p1:
881 repo.ui.debug(" update to %d:%s\n" % (p1, repo[p1]))
881 repo.ui.debug(" update to %d:%s\n" % (p1, repo[p1]))
882 mergemod.update(repo, p1, False, True)
882 mergemod.update(repo, p1, False, True)
883 else:
883 else:
884 repo.ui.debug(" already in destination\n")
884 repo.ui.debug(" already in destination\n")
885 repo.dirstate.write(repo.currenttransaction())
885 repo.dirstate.write(repo.currenttransaction())
886 repo.ui.debug(" merge against %d:%s\n" % (rev, repo[rev]))
886 repo.ui.debug(" merge against %d:%s\n" % (rev, repo[rev]))
887 if base is not None:
887 if base is not None:
888 repo.ui.debug(" detach base %d:%s\n" % (base, repo[base]))
888 repo.ui.debug(" detach base %d:%s\n" % (base, repo[base]))
889 # When collapsing in-place, the parent is the common ancestor, we
889 # When collapsing in-place, the parent is the common ancestor, we
890 # have to allow merging with it.
890 # have to allow merging with it.
891 stats = mergemod.update(repo, rev, True, True, base, collapse,
891 stats = mergemod.update(repo, rev, True, True, base, collapse,
892 labels=['dest', 'source'])
892 labels=['dest', 'source'])
893 if collapse:
893 if collapse:
894 copies.duplicatecopies(repo, rev, dest)
894 copies.duplicatecopies(repo, rev, dest)
895 else:
895 else:
896 # If we're not using --collapse, we need to
896 # If we're not using --collapse, we need to
897 # duplicate copies between the revision we're
897 # duplicate copies between the revision we're
898 # rebasing and its first parent, but *not*
898 # rebasing and its first parent, but *not*
899 # duplicate any copies that have already been
899 # duplicate any copies that have already been
900 # performed in the destination.
900 # performed in the destination.
901 p1rev = repo[rev].p1().rev()
901 p1rev = repo[rev].p1().rev()
902 copies.duplicatecopies(repo, rev, p1rev, skiprev=dest)
902 copies.duplicatecopies(repo, rev, p1rev, skiprev=dest)
903 return stats
903 return stats
904
904
905 def adjustdest(repo, rev, dest, state):
905 def adjustdest(repo, rev, dest, state):
906 """adjust rebase destination given the current rebase state
906 """adjust rebase destination given the current rebase state
907
907
908 rev is what is being rebased. Return a list of two revs, which are the
908 rev is what is being rebased. Return a list of two revs, which are the
909 adjusted destinations for rev's p1 and p2, respectively. If a parent is
909 adjusted destinations for rev's p1 and p2, respectively. If a parent is
910 nullrev, return dest without adjustment for it.
910 nullrev, return dest without adjustment for it.
911
911
912 For example, when doing rebase -r B+E -d F, rebase will first move B to B1,
912 For example, when doing rebase -r B+E -d F, rebase will first move B to B1,
913 and E's destination will be adjusted from F to B1.
913 and E's destination will be adjusted from F to B1.
914
914
915 B1 <- written during rebasing B
915 B1 <- written during rebasing B
916 |
916 |
917 F <- original destination of B, E
917 F <- original destination of B, E
918 |
918 |
919 | E <- rev, which is being rebased
919 | E <- rev, which is being rebased
920 | |
920 | |
921 | D <- prev, one parent of rev being checked
921 | D <- prev, one parent of rev being checked
922 | |
922 | |
923 | x <- skipped, ex. no successor or successor in (::dest)
923 | x <- skipped, ex. no successor or successor in (::dest)
924 | |
924 | |
925 | C
925 | C
926 | |
926 | |
927 | B <- rebased as B1
927 | B <- rebased as B1
928 |/
928 |/
929 A
929 A
930
930
931 Another example about merge changeset, rebase -r C+G+H -d K, rebase will
931 Another example about merge changeset, rebase -r C+G+H -d K, rebase will
932 first move C to C1, G to G1, and when it's checking H, the adjusted
932 first move C to C1, G to G1, and when it's checking H, the adjusted
933 destinations will be [C1, G1].
933 destinations will be [C1, G1].
934
934
935 H C1 G1
935 H C1 G1
936 /| | /
936 /| | /
937 F G |/
937 F G |/
938 K | | -> K
938 K | | -> K
939 | C D |
939 | C D |
940 | |/ |
940 | |/ |
941 | B | ...
941 | B | ...
942 |/ |/
942 |/ |/
943 A A
943 A A
944 """
944 """
945 result = []
945 result = []
946 for prev in repo.changelog.parentrevs(rev):
946 for prev in repo.changelog.parentrevs(rev):
947 adjusted = dest
947 adjusted = dest
948 if prev != nullrev:
948 if prev != nullrev:
949 # pick already rebased revs from state
949 # pick already rebased revs from state
950 source = [s for s, d in state.items() if d > 0]
950 source = [s for s, d in state.items() if d > 0]
951 candidate = repo.revs('max(%ld and (::%d))', source, prev).first()
951 candidate = repo.revs('max(%ld and (::%d))', source, prev).first()
952 if candidate is not None:
952 if candidate is not None:
953 adjusted = state[candidate]
953 adjusted = state[candidate]
954 result.append(adjusted)
954 result.append(adjusted)
955 return result
955 return result
956
956
957 def _checkobsrebase(repo, ui, rebaseobsrevs, rebasesetrevs, rebaseobsskipped):
957 def _checkobsrebase(repo, ui, rebaseobsrevs, rebasesetrevs, rebaseobsskipped):
958 """
958 """
959 Abort if rebase will create divergence or rebase is noop because of markers
959 Abort if rebase will create divergence or rebase is noop because of markers
960
960
961 `rebaseobsrevs`: set of obsolete revision in source
961 `rebaseobsrevs`: set of obsolete revision in source
962 `rebasesetrevs`: set of revisions to be rebased from source
962 `rebasesetrevs`: set of revisions to be rebased from source
963 `rebaseobsskipped`: set of revisions from source skipped because they have
963 `rebaseobsskipped`: set of revisions from source skipped because they have
964 successors in destination
964 successors in destination
965 """
965 """
966 # Obsolete node with successors not in dest leads to divergence
966 # Obsolete node with successors not in dest leads to divergence
967 divergenceok = ui.configbool('experimental',
967 divergenceok = ui.configbool('experimental',
968 'allowdivergence')
968 'allowdivergence')
969 divergencebasecandidates = rebaseobsrevs - rebaseobsskipped
969 divergencebasecandidates = rebaseobsrevs - rebaseobsskipped
970
970
971 if divergencebasecandidates and not divergenceok:
971 if divergencebasecandidates and not divergenceok:
972 divhashes = (str(repo[r])
972 divhashes = (str(repo[r])
973 for r in divergencebasecandidates)
973 for r in divergencebasecandidates)
974 msg = _("this rebase will cause "
974 msg = _("this rebase will cause "
975 "divergences from: %s")
975 "divergences from: %s")
976 h = _("to force the rebase please set "
976 h = _("to force the rebase please set "
977 "experimental.allowdivergence=True")
977 "experimental.allowdivergence=True")
978 raise error.Abort(msg % (",".join(divhashes),), hint=h)
978 raise error.Abort(msg % (",".join(divhashes),), hint=h)
979
979
980 def successorrevs(repo, rev):
980 def successorrevs(repo, rev):
981 """yield revision numbers for successors of rev"""
981 """yield revision numbers for successors of rev"""
982 unfi = repo.unfiltered()
982 unfi = repo.unfiltered()
983 nodemap = unfi.changelog.nodemap
983 nodemap = unfi.changelog.nodemap
984 for s in obsutil.allsuccessors(unfi.obsstore, [unfi[rev].node()]):
984 for s in obsutil.allsuccessors(unfi.obsstore, [unfi[rev].node()]):
985 if s in nodemap:
985 if s in nodemap:
986 yield nodemap[s]
986 yield nodemap[s]
987
987
988 def defineparents(repo, rev, dest, state):
988 def defineparents(repo, rev, dest, state):
989 """Return new parents and optionally a merge base for rev being rebased
989 """Return new parents and optionally a merge base for rev being rebased
990
990
991 The destination specified by "dest" cannot always be used directly because
991 The destination specified by "dest" cannot always be used directly because
992 previously rebase result could affect destination. For example,
992 previously rebase result could affect destination. For example,
993
993
994 D E rebase -r C+D+E -d B
994 D E rebase -r C+D+E -d B
995 |/ C will be rebased to C'
995 |/ C will be rebased to C'
996 B C D's new destination will be C' instead of B
996 B C D's new destination will be C' instead of B
997 |/ E's new destination will be C' instead of B
997 |/ E's new destination will be C' instead of B
998 A
998 A
999
999
1000 The new parents of a merge is slightly more complicated. See the comment
1000 The new parents of a merge is slightly more complicated. See the comment
1001 block below.
1001 block below.
1002 """
1002 """
1003 cl = repo.changelog
1003 cl = repo.changelog
1004 def isancestor(a, b):
1004 def isancestor(a, b):
1005 # take revision numbers instead of nodes
1005 # take revision numbers instead of nodes
1006 if a == b:
1006 if a == b:
1007 return True
1007 return True
1008 elif a > b:
1008 elif a > b:
1009 return False
1009 return False
1010 return cl.isancestor(cl.node(a), cl.node(b))
1010 return cl.isancestor(cl.node(a), cl.node(b))
1011
1011
1012 oldps = repo.changelog.parentrevs(rev) # old parents
1012 oldps = repo.changelog.parentrevs(rev) # old parents
1013 newps = [nullrev, nullrev] # new parents
1013 newps = [nullrev, nullrev] # new parents
1014 dests = adjustdest(repo, rev, dest, state) # adjusted destinations
1014 dests = adjustdest(repo, rev, dest, state) # adjusted destinations
1015 bases = list(oldps) # merge base candidates, initially just old parents
1015 bases = list(oldps) # merge base candidates, initially just old parents
1016
1016
1017 if all(r == nullrev for r in oldps[1:]):
1017 if all(r == nullrev for r in oldps[1:]):
1018 # For non-merge changeset, just move p to adjusted dest as requested.
1018 # For non-merge changeset, just move p to adjusted dest as requested.
1019 newps[0] = dests[0]
1019 newps[0] = dests[0]
1020 else:
1020 else:
1021 # For merge changeset, if we move p to dests[i] unconditionally, both
1021 # For merge changeset, if we move p to dests[i] unconditionally, both
1022 # parents may change and the end result looks like "the merge loses a
1022 # parents may change and the end result looks like "the merge loses a
1023 # parent", which is a surprise. This is a limit because "--dest" only
1023 # parent", which is a surprise. This is a limit because "--dest" only
1024 # accepts one dest per src.
1024 # accepts one dest per src.
1025 #
1025 #
1026 # Therefore, only move p with reasonable conditions (in this order):
1026 # Therefore, only move p with reasonable conditions (in this order):
1027 # 1. use dest, if dest is a descendent of (p or one of p's successors)
1027 # 1. use dest, if dest is a descendent of (p or one of p's successors)
1028 # 2. use p's rebased result, if p is rebased (state[p] > 0)
1028 # 2. use p's rebased result, if p is rebased (state[p] > 0)
1029 #
1029 #
1030 # Comparing with adjustdest, the logic here does some additional work:
1030 # Comparing with adjustdest, the logic here does some additional work:
1031 # 1. decide which parents will not be moved towards dest
1031 # 1. decide which parents will not be moved towards dest
1032 # 2. if the above decision is "no", should a parent still be moved
1032 # 2. if the above decision is "no", should a parent still be moved
1033 # because it was rebased?
1033 # because it was rebased?
1034 #
1034 #
1035 # For example:
1035 # For example:
1036 #
1036 #
1037 # C # "rebase -r C -d D" is an error since none of the parents
1037 # C # "rebase -r C -d D" is an error since none of the parents
1038 # /| # can be moved. "rebase -r B+C -d D" will move C's parent
1038 # /| # can be moved. "rebase -r B+C -d D" will move C's parent
1039 # A B D # B (using rule "2."), since B will be rebased.
1039 # A B D # B (using rule "2."), since B will be rebased.
1040 #
1040 #
1041 # The loop tries to be not rely on the fact that a Mercurial node has
1041 # The loop tries to be not rely on the fact that a Mercurial node has
1042 # at most 2 parents.
1042 # at most 2 parents.
1043 for i, p in enumerate(oldps):
1043 for i, p in enumerate(oldps):
1044 np = p # new parent
1044 np = p # new parent
1045 if any(isancestor(x, dests[i]) for x in successorrevs(repo, p)):
1045 if any(isancestor(x, dests[i]) for x in successorrevs(repo, p)):
1046 np = dests[i]
1046 np = dests[i]
1047 elif p in state and state[p] > 0:
1047 elif p in state and state[p] > 0:
1048 np = state[p]
1048 np = state[p]
1049
1049
1050 # "bases" only record "special" merge bases that cannot be
1050 # "bases" only record "special" merge bases that cannot be
1051 # calculated from changelog DAG (i.e. isancestor(p, np) is False).
1051 # calculated from changelog DAG (i.e. isancestor(p, np) is False).
1052 # For example:
1052 # For example:
1053 #
1053 #
1054 # B' # rebase -s B -d D, when B was rebased to B'. dest for C
1054 # B' # rebase -s B -d D, when B was rebased to B'. dest for C
1055 # | C # is B', but merge base for C is B, instead of
1055 # | C # is B', but merge base for C is B, instead of
1056 # D | # changelog.ancestor(C, B') == A. If changelog DAG and
1056 # D | # changelog.ancestor(C, B') == A. If changelog DAG and
1057 # | B # "state" edges are merged (so there will be an edge from
1057 # | B # "state" edges are merged (so there will be an edge from
1058 # |/ # B to B'), the merge base is still ancestor(C, B') in
1058 # |/ # B to B'), the merge base is still ancestor(C, B') in
1059 # A # the merged graph.
1059 # A # the merged graph.
1060 #
1060 #
1061 # Also see https://bz.mercurial-scm.org/show_bug.cgi?id=1950#c8
1061 # Also see https://bz.mercurial-scm.org/show_bug.cgi?id=1950#c8
1062 # which uses "virtual null merge" to explain this situation.
1062 # which uses "virtual null merge" to explain this situation.
1063 if isancestor(p, np):
1063 if isancestor(p, np):
1064 bases[i] = nullrev
1064 bases[i] = nullrev
1065
1065
1066 # If one parent becomes an ancestor of the other, drop the ancestor
1066 # If one parent becomes an ancestor of the other, drop the ancestor
1067 for j, x in enumerate(newps[:i]):
1067 for j, x in enumerate(newps[:i]):
1068 if x == nullrev:
1068 if x == nullrev:
1069 continue
1069 continue
1070 if isancestor(np, x):
1070 if isancestor(np, x):
1071 np = nullrev
1071 np = nullrev
1072 elif isancestor(x, np):
1072 elif isancestor(x, np):
1073 newps[j] = np
1073 newps[j] = np
1074 np = nullrev
1074 np = nullrev
1075 bases[j], bases[i] = bases[i], bases[j]
1075 bases[j], bases[i] = bases[i], bases[j]
1076
1076
1077 newps[i] = np
1077 newps[i] = np
1078
1078
1079 # "rebasenode" updates to new p1, and the old p1 will be used as merge
1079 # "rebasenode" updates to new p1, and the old p1 will be used as merge
1080 # base. If only p2 changes, merging using unchanged p1 as merge base is
1080 # base. If only p2 changes, merging using unchanged p1 as merge base is
1081 # suboptimal. Therefore swap parents to make the merge sane.
1081 # suboptimal. Therefore swap parents to make the merge sane.
1082 if newps[1] != nullrev and oldps[0] == newps[0]:
1082 if newps[1] != nullrev and oldps[0] == newps[0]:
1083 assert len(newps) == 2 and len(oldps) == 2
1083 assert len(newps) == 2 and len(oldps) == 2
1084 newps.reverse()
1084 newps.reverse()
1085 bases.reverse()
1085 bases.reverse()
1086
1086
1087 # No parent change might be an error because we fail to make rev a
1087 # No parent change might be an error because we fail to make rev a
1088 # descendent of requested dest. This can happen, for example:
1088 # descendent of requested dest. This can happen, for example:
1089 #
1089 #
1090 # C # rebase -r C -d D
1090 # C # rebase -r C -d D
1091 # /| # None of A and B will be changed to D and rebase fails.
1091 # /| # None of A and B will be changed to D and rebase fails.
1092 # A B D
1092 # A B D
1093 if set(newps) == set(oldps) and dest not in newps:
1093 if set(newps) == set(oldps) and dest not in newps:
1094 # The error message is for compatibility. It's a bit misleading
1094 raise error.Abort(_('cannot rebase %d:%s without '
1095 # since rebase is not supposed to add new parents.
1095 'moving at least one of its parents')
1096 raise error.Abort(_('cannot use revision %d as base, '
1096 % (rev, repo[rev]))
1097 'result would have 3 parents') % rev)
1098
1097
1099 repo.ui.debug(" future parents are %d and %d\n" % tuple(newps))
1098 repo.ui.debug(" future parents are %d and %d\n" % tuple(newps))
1100
1099
1101 # "rebasenode" updates to new p1, use the corresponding merge base.
1100 # "rebasenode" updates to new p1, use the corresponding merge base.
1102 if bases[0] != nullrev:
1101 if bases[0] != nullrev:
1103 base = bases[0]
1102 base = bases[0]
1104 else:
1103 else:
1105 base = None
1104 base = None
1106
1105
1107 # Check if the merge will contain unwanted changes. That may happen if
1106 # Check if the merge will contain unwanted changes. That may happen if
1108 # there are multiple special (non-changelog ancestor) merge bases, which
1107 # there are multiple special (non-changelog ancestor) merge bases, which
1109 # cannot be handled well by the 3-way merge algorithm. For example:
1108 # cannot be handled well by the 3-way merge algorithm. For example:
1110 #
1109 #
1111 # F
1110 # F
1112 # /|
1111 # /|
1113 # D E # "rebase -r D+E+F -d Z", when rebasing F, if "D" was chosen
1112 # D E # "rebase -r D+E+F -d Z", when rebasing F, if "D" was chosen
1114 # | | # as merge base, the difference between D and F will include
1113 # | | # as merge base, the difference between D and F will include
1115 # B C # C, so the rebased F will contain C surprisingly. If "E" was
1114 # B C # C, so the rebased F will contain C surprisingly. If "E" was
1116 # |/ # chosen, the rebased F will contain B.
1115 # |/ # chosen, the rebased F will contain B.
1117 # A Z
1116 # A Z
1118 #
1117 #
1119 # But our merge base candidates (D and E in above case) could still be
1118 # But our merge base candidates (D and E in above case) could still be
1120 # better than the default (ancestor(F, Z) == null). Therefore still
1119 # better than the default (ancestor(F, Z) == null). Therefore still
1121 # pick one (so choose p1 above).
1120 # pick one (so choose p1 above).
1122 if sum(1 for b in bases if b != nullrev) > 1:
1121 if sum(1 for b in bases if b != nullrev) > 1:
1123 assert base is not None
1122 assert base is not None
1124
1123
1125 # Revisions in the side (not chosen as merge base) branch that might
1124 # Revisions in the side (not chosen as merge base) branch that might
1126 # contain "surprising" contents
1125 # contain "surprising" contents
1127 siderevs = list(repo.revs('((%ld-%d) %% (%d+%d))',
1126 siderevs = list(repo.revs('((%ld-%d) %% (%d+%d))',
1128 bases, base, base, dest))
1127 bases, base, base, dest))
1129
1128
1130 # If those revisions are covered by rebaseset, the result is good.
1129 # If those revisions are covered by rebaseset, the result is good.
1131 # A merge in rebaseset would be considered to cover its ancestors.
1130 # A merge in rebaseset would be considered to cover its ancestors.
1132 if siderevs:
1131 if siderevs:
1133 rebaseset = [r for r, d in state.items() if d > 0]
1132 rebaseset = [r for r, d in state.items() if d > 0]
1134 merges = [r for r in rebaseset if cl.parentrevs(r)[1] != nullrev]
1133 merges = [r for r in rebaseset if cl.parentrevs(r)[1] != nullrev]
1135 unwantedrevs = list(repo.revs('%ld - (::%ld) - %ld',
1134 unwantedrevs = list(repo.revs('%ld - (::%ld) - %ld',
1136 siderevs, merges, rebaseset))
1135 siderevs, merges, rebaseset))
1137
1136
1138 # For revs not covered, it is worth a warning.
1137 # For revs not covered, it is worth a warning.
1139 if unwantedrevs:
1138 if unwantedrevs:
1140 repo.ui.warn(
1139 repo.ui.warn(
1141 _('warning: rebasing %d:%s may include unwanted changes '
1140 _('warning: rebasing %d:%s may include unwanted changes '
1142 'from %s\n')
1141 'from %s\n')
1143 % (rev, repo[rev], ', '.join('%d:%s' % (r, repo[r])
1142 % (rev, repo[rev], ', '.join('%d:%s' % (r, repo[r])
1144 for r in unwantedrevs)))
1143 for r in unwantedrevs)))
1145
1144
1146 return newps[0], newps[1], base
1145 return newps[0], newps[1], base
1147
1146
1148 def isagitpatch(repo, patchname):
1147 def isagitpatch(repo, patchname):
1149 'Return true if the given patch is in git format'
1148 'Return true if the given patch is in git format'
1150 mqpatch = os.path.join(repo.mq.path, patchname)
1149 mqpatch = os.path.join(repo.mq.path, patchname)
1151 for line in patch.linereader(file(mqpatch, 'rb')):
1150 for line in patch.linereader(file(mqpatch, 'rb')):
1152 if line.startswith('diff --git'):
1151 if line.startswith('diff --git'):
1153 return True
1152 return True
1154 return False
1153 return False
1155
1154
1156 def updatemq(repo, state, skipped, **opts):
1155 def updatemq(repo, state, skipped, **opts):
1157 'Update rebased mq patches - finalize and then import them'
1156 'Update rebased mq patches - finalize and then import them'
1158 mqrebase = {}
1157 mqrebase = {}
1159 mq = repo.mq
1158 mq = repo.mq
1160 original_series = mq.fullseries[:]
1159 original_series = mq.fullseries[:]
1161 skippedpatches = set()
1160 skippedpatches = set()
1162
1161
1163 for p in mq.applied:
1162 for p in mq.applied:
1164 rev = repo[p.node].rev()
1163 rev = repo[p.node].rev()
1165 if rev in state:
1164 if rev in state:
1166 repo.ui.debug('revision %d is an mq patch (%s), finalize it.\n' %
1165 repo.ui.debug('revision %d is an mq patch (%s), finalize it.\n' %
1167 (rev, p.name))
1166 (rev, p.name))
1168 mqrebase[rev] = (p.name, isagitpatch(repo, p.name))
1167 mqrebase[rev] = (p.name, isagitpatch(repo, p.name))
1169 else:
1168 else:
1170 # Applied but not rebased, not sure this should happen
1169 # Applied but not rebased, not sure this should happen
1171 skippedpatches.add(p.name)
1170 skippedpatches.add(p.name)
1172
1171
1173 if mqrebase:
1172 if mqrebase:
1174 mq.finish(repo, mqrebase.keys())
1173 mq.finish(repo, mqrebase.keys())
1175
1174
1176 # We must start import from the newest revision
1175 # We must start import from the newest revision
1177 for rev in sorted(mqrebase, reverse=True):
1176 for rev in sorted(mqrebase, reverse=True):
1178 if rev not in skipped:
1177 if rev not in skipped:
1179 name, isgit = mqrebase[rev]
1178 name, isgit = mqrebase[rev]
1180 repo.ui.note(_('updating mq patch %s to %s:%s\n') %
1179 repo.ui.note(_('updating mq patch %s to %s:%s\n') %
1181 (name, state[rev], repo[state[rev]]))
1180 (name, state[rev], repo[state[rev]]))
1182 mq.qimport(repo, (), patchname=name, git=isgit,
1181 mq.qimport(repo, (), patchname=name, git=isgit,
1183 rev=[str(state[rev])])
1182 rev=[str(state[rev])])
1184 else:
1183 else:
1185 # Rebased and skipped
1184 # Rebased and skipped
1186 skippedpatches.add(mqrebase[rev][0])
1185 skippedpatches.add(mqrebase[rev][0])
1187
1186
1188 # Patches were either applied and rebased and imported in
1187 # Patches were either applied and rebased and imported in
1189 # order, applied and removed or unapplied. Discard the removed
1188 # order, applied and removed or unapplied. Discard the removed
1190 # ones while preserving the original series order and guards.
1189 # ones while preserving the original series order and guards.
1191 newseries = [s for s in original_series
1190 newseries = [s for s in original_series
1192 if mq.guard_re.split(s, 1)[0] not in skippedpatches]
1191 if mq.guard_re.split(s, 1)[0] not in skippedpatches]
1193 mq.fullseries[:] = newseries
1192 mq.fullseries[:] = newseries
1194 mq.seriesdirty = True
1193 mq.seriesdirty = True
1195 mq.savedirty()
1194 mq.savedirty()
1196
1195
1197 def storecollapsemsg(repo, collapsemsg):
1196 def storecollapsemsg(repo, collapsemsg):
1198 'Store the collapse message to allow recovery'
1197 'Store the collapse message to allow recovery'
1199 collapsemsg = collapsemsg or ''
1198 collapsemsg = collapsemsg or ''
1200 f = repo.vfs("last-message.txt", "w")
1199 f = repo.vfs("last-message.txt", "w")
1201 f.write("%s\n" % collapsemsg)
1200 f.write("%s\n" % collapsemsg)
1202 f.close()
1201 f.close()
1203
1202
1204 def clearcollapsemsg(repo):
1203 def clearcollapsemsg(repo):
1205 'Remove collapse message file'
1204 'Remove collapse message file'
1206 repo.vfs.unlinkpath("last-message.txt", ignoremissing=True)
1205 repo.vfs.unlinkpath("last-message.txt", ignoremissing=True)
1207
1206
1208 def restorecollapsemsg(repo, isabort):
1207 def restorecollapsemsg(repo, isabort):
1209 'Restore previously stored collapse message'
1208 'Restore previously stored collapse message'
1210 try:
1209 try:
1211 f = repo.vfs("last-message.txt")
1210 f = repo.vfs("last-message.txt")
1212 collapsemsg = f.readline().strip()
1211 collapsemsg = f.readline().strip()
1213 f.close()
1212 f.close()
1214 except IOError as err:
1213 except IOError as err:
1215 if err.errno != errno.ENOENT:
1214 if err.errno != errno.ENOENT:
1216 raise
1215 raise
1217 if isabort:
1216 if isabort:
1218 # Oh well, just abort like normal
1217 # Oh well, just abort like normal
1219 collapsemsg = ''
1218 collapsemsg = ''
1220 else:
1219 else:
1221 raise error.Abort(_('missing .hg/last-message.txt for rebase'))
1220 raise error.Abort(_('missing .hg/last-message.txt for rebase'))
1222 return collapsemsg
1221 return collapsemsg
1223
1222
1224 def clearstatus(repo):
1223 def clearstatus(repo):
1225 'Remove the status files'
1224 'Remove the status files'
1226 _clearrebasesetvisibiliy(repo)
1225 _clearrebasesetvisibiliy(repo)
1227 # Make sure the active transaction won't write the state file
1226 # Make sure the active transaction won't write the state file
1228 tr = repo.currenttransaction()
1227 tr = repo.currenttransaction()
1229 if tr:
1228 if tr:
1230 tr.removefilegenerator('rebasestate')
1229 tr.removefilegenerator('rebasestate')
1231 repo.vfs.unlinkpath("rebasestate", ignoremissing=True)
1230 repo.vfs.unlinkpath("rebasestate", ignoremissing=True)
1232
1231
1233 def needupdate(repo, state):
1232 def needupdate(repo, state):
1234 '''check whether we should `update --clean` away from a merge, or if
1233 '''check whether we should `update --clean` away from a merge, or if
1235 somehow the working dir got forcibly updated, e.g. by older hg'''
1234 somehow the working dir got forcibly updated, e.g. by older hg'''
1236 parents = [p.rev() for p in repo[None].parents()]
1235 parents = [p.rev() for p in repo[None].parents()]
1237
1236
1238 # Are we in a merge state at all?
1237 # Are we in a merge state at all?
1239 if len(parents) < 2:
1238 if len(parents) < 2:
1240 return False
1239 return False
1241
1240
1242 # We should be standing on the first as-of-yet unrebased commit.
1241 # We should be standing on the first as-of-yet unrebased commit.
1243 firstunrebased = min([old for old, new in state.iteritems()
1242 firstunrebased = min([old for old, new in state.iteritems()
1244 if new == nullrev])
1243 if new == nullrev])
1245 if firstunrebased in parents:
1244 if firstunrebased in parents:
1246 return True
1245 return True
1247
1246
1248 return False
1247 return False
1249
1248
1250 def abort(repo, originalwd, dest, state, activebookmark=None):
1249 def abort(repo, originalwd, dest, state, activebookmark=None):
1251 '''Restore the repository to its original state. Additional args:
1250 '''Restore the repository to its original state. Additional args:
1252
1251
1253 activebookmark: the name of the bookmark that should be active after the
1252 activebookmark: the name of the bookmark that should be active after the
1254 restore'''
1253 restore'''
1255
1254
1256 try:
1255 try:
1257 # If the first commits in the rebased set get skipped during the rebase,
1256 # If the first commits in the rebased set get skipped during the rebase,
1258 # their values within the state mapping will be the dest rev id. The
1257 # their values within the state mapping will be the dest rev id. The
1259 # dstates list must must not contain the dest rev (issue4896)
1258 # dstates list must must not contain the dest rev (issue4896)
1260 dstates = [s for s in state.values() if s >= 0 and s != dest]
1259 dstates = [s for s in state.values() if s >= 0 and s != dest]
1261 immutable = [d for d in dstates if not repo[d].mutable()]
1260 immutable = [d for d in dstates if not repo[d].mutable()]
1262 cleanup = True
1261 cleanup = True
1263 if immutable:
1262 if immutable:
1264 repo.ui.warn(_("warning: can't clean up public changesets %s\n")
1263 repo.ui.warn(_("warning: can't clean up public changesets %s\n")
1265 % ', '.join(str(repo[r]) for r in immutable),
1264 % ', '.join(str(repo[r]) for r in immutable),
1266 hint=_("see 'hg help phases' for details"))
1265 hint=_("see 'hg help phases' for details"))
1267 cleanup = False
1266 cleanup = False
1268
1267
1269 descendants = set()
1268 descendants = set()
1270 if dstates:
1269 if dstates:
1271 descendants = set(repo.changelog.descendants(dstates))
1270 descendants = set(repo.changelog.descendants(dstates))
1272 if descendants - set(dstates):
1271 if descendants - set(dstates):
1273 repo.ui.warn(_("warning: new changesets detected on destination "
1272 repo.ui.warn(_("warning: new changesets detected on destination "
1274 "branch, can't strip\n"))
1273 "branch, can't strip\n"))
1275 cleanup = False
1274 cleanup = False
1276
1275
1277 if cleanup:
1276 if cleanup:
1278 shouldupdate = False
1277 shouldupdate = False
1279 rebased = filter(lambda x: x >= 0 and x != dest, state.values())
1278 rebased = filter(lambda x: x >= 0 and x != dest, state.values())
1280 if rebased:
1279 if rebased:
1281 strippoints = [
1280 strippoints = [
1282 c.node() for c in repo.set('roots(%ld)', rebased)]
1281 c.node() for c in repo.set('roots(%ld)', rebased)]
1283
1282
1284 updateifonnodes = set(rebased)
1283 updateifonnodes = set(rebased)
1285 updateifonnodes.add(dest)
1284 updateifonnodes.add(dest)
1286 updateifonnodes.add(originalwd)
1285 updateifonnodes.add(originalwd)
1287 shouldupdate = repo['.'].rev() in updateifonnodes
1286 shouldupdate = repo['.'].rev() in updateifonnodes
1288
1287
1289 # Update away from the rebase if necessary
1288 # Update away from the rebase if necessary
1290 if shouldupdate or needupdate(repo, state):
1289 if shouldupdate or needupdate(repo, state):
1291 mergemod.update(repo, originalwd, False, True)
1290 mergemod.update(repo, originalwd, False, True)
1292
1291
1293 # Strip from the first rebased revision
1292 # Strip from the first rebased revision
1294 if rebased:
1293 if rebased:
1295 # no backup of rebased cset versions needed
1294 # no backup of rebased cset versions needed
1296 repair.strip(repo.ui, repo, strippoints)
1295 repair.strip(repo.ui, repo, strippoints)
1297
1296
1298 if activebookmark and activebookmark in repo._bookmarks:
1297 if activebookmark and activebookmark in repo._bookmarks:
1299 bookmarks.activate(repo, activebookmark)
1298 bookmarks.activate(repo, activebookmark)
1300
1299
1301 finally:
1300 finally:
1302 clearstatus(repo)
1301 clearstatus(repo)
1303 clearcollapsemsg(repo)
1302 clearcollapsemsg(repo)
1304 repo.ui.warn(_('rebase aborted\n'))
1303 repo.ui.warn(_('rebase aborted\n'))
1305 return 0
1304 return 0
1306
1305
1307 def buildstate(repo, dest, rebaseset, collapse, obsoletenotrebased):
1306 def buildstate(repo, dest, rebaseset, collapse, obsoletenotrebased):
1308 '''Define which revisions are going to be rebased and where
1307 '''Define which revisions are going to be rebased and where
1309
1308
1310 repo: repo
1309 repo: repo
1311 dest: context
1310 dest: context
1312 rebaseset: set of rev
1311 rebaseset: set of rev
1313 '''
1312 '''
1314 originalwd = repo['.'].rev()
1313 originalwd = repo['.'].rev()
1315 _setrebasesetvisibility(repo, set(rebaseset) | {originalwd})
1314 _setrebasesetvisibility(repo, set(rebaseset) | {originalwd})
1316
1315
1317 # This check isn't strictly necessary, since mq detects commits over an
1316 # This check isn't strictly necessary, since mq detects commits over an
1318 # applied patch. But it prevents messing up the working directory when
1317 # applied patch. But it prevents messing up the working directory when
1319 # a partially completed rebase is blocked by mq.
1318 # a partially completed rebase is blocked by mq.
1320 if 'qtip' in repo.tags() and (dest.node() in
1319 if 'qtip' in repo.tags() and (dest.node() in
1321 [s.node for s in repo.mq.applied]):
1320 [s.node for s in repo.mq.applied]):
1322 raise error.Abort(_('cannot rebase onto an applied mq patch'))
1321 raise error.Abort(_('cannot rebase onto an applied mq patch'))
1323
1322
1324 roots = list(repo.set('roots(%ld)', rebaseset))
1323 roots = list(repo.set('roots(%ld)', rebaseset))
1325 if not roots:
1324 if not roots:
1326 raise error.Abort(_('no matching revisions'))
1325 raise error.Abort(_('no matching revisions'))
1327 roots.sort()
1326 roots.sort()
1328 state = dict.fromkeys(rebaseset, revtodo)
1327 state = dict.fromkeys(rebaseset, revtodo)
1329 detachset = set()
1328 detachset = set()
1330 emptyrebase = True
1329 emptyrebase = True
1331 for root in roots:
1330 for root in roots:
1332 commonbase = root.ancestor(dest)
1331 commonbase = root.ancestor(dest)
1333 if commonbase == root:
1332 if commonbase == root:
1334 raise error.Abort(_('source is ancestor of destination'))
1333 raise error.Abort(_('source is ancestor of destination'))
1335 if commonbase == dest:
1334 if commonbase == dest:
1336 wctx = repo[None]
1335 wctx = repo[None]
1337 if dest == wctx.p1():
1336 if dest == wctx.p1():
1338 # when rebasing to '.', it will use the current wd branch name
1337 # when rebasing to '.', it will use the current wd branch name
1339 samebranch = root.branch() == wctx.branch()
1338 samebranch = root.branch() == wctx.branch()
1340 else:
1339 else:
1341 samebranch = root.branch() == dest.branch()
1340 samebranch = root.branch() == dest.branch()
1342 if not collapse and samebranch and dest in root.parents():
1341 if not collapse and samebranch and dest in root.parents():
1343 # mark the revision as done by setting its new revision
1342 # mark the revision as done by setting its new revision
1344 # equal to its old (current) revisions
1343 # equal to its old (current) revisions
1345 state[root.rev()] = root.rev()
1344 state[root.rev()] = root.rev()
1346 repo.ui.debug('source is a child of destination\n')
1345 repo.ui.debug('source is a child of destination\n')
1347 continue
1346 continue
1348
1347
1349 emptyrebase = False
1348 emptyrebase = False
1350 repo.ui.debug('rebase onto %s starting from %s\n' % (dest, root))
1349 repo.ui.debug('rebase onto %s starting from %s\n' % (dest, root))
1351 # Rebase tries to turn <dest> into a parent of <root> while
1350 # Rebase tries to turn <dest> into a parent of <root> while
1352 # preserving the number of parents of rebased changesets:
1351 # preserving the number of parents of rebased changesets:
1353 #
1352 #
1354 # - A changeset with a single parent will always be rebased as a
1353 # - A changeset with a single parent will always be rebased as a
1355 # changeset with a single parent.
1354 # changeset with a single parent.
1356 #
1355 #
1357 # - A merge will be rebased as merge unless its parents are both
1356 # - A merge will be rebased as merge unless its parents are both
1358 # ancestors of <dest> or are themselves in the rebased set and
1357 # ancestors of <dest> or are themselves in the rebased set and
1359 # pruned while rebased.
1358 # pruned while rebased.
1360 #
1359 #
1361 # If one parent of <root> is an ancestor of <dest>, the rebased
1360 # If one parent of <root> is an ancestor of <dest>, the rebased
1362 # version of this parent will be <dest>. This is always true with
1361 # version of this parent will be <dest>. This is always true with
1363 # --base option.
1362 # --base option.
1364 #
1363 #
1365 # Otherwise, we need to *replace* the original parents with
1364 # Otherwise, we need to *replace* the original parents with
1366 # <dest>. This "detaches" the rebased set from its former location
1365 # <dest>. This "detaches" the rebased set from its former location
1367 # and rebases it onto <dest>. Changes introduced by ancestors of
1366 # and rebases it onto <dest>. Changes introduced by ancestors of
1368 # <root> not common with <dest> (the detachset, marked as
1367 # <root> not common with <dest> (the detachset, marked as
1369 # nullmerge) are "removed" from the rebased changesets.
1368 # nullmerge) are "removed" from the rebased changesets.
1370 #
1369 #
1371 # - If <root> has a single parent, set it to <dest>.
1370 # - If <root> has a single parent, set it to <dest>.
1372 #
1371 #
1373 # - If <root> is a merge, we cannot decide which parent to
1372 # - If <root> is a merge, we cannot decide which parent to
1374 # replace, the rebase operation is not clearly defined.
1373 # replace, the rebase operation is not clearly defined.
1375 #
1374 #
1376 # The table below sums up this behavior:
1375 # The table below sums up this behavior:
1377 #
1376 #
1378 # +------------------+----------------------+-------------------------+
1377 # +------------------+----------------------+-------------------------+
1379 # | | one parent | merge |
1378 # | | one parent | merge |
1380 # +------------------+----------------------+-------------------------+
1379 # +------------------+----------------------+-------------------------+
1381 # | parent in | new parent is <dest> | parents in ::<dest> are |
1380 # | parent in | new parent is <dest> | parents in ::<dest> are |
1382 # | ::<dest> | | remapped to <dest> |
1381 # | ::<dest> | | remapped to <dest> |
1383 # +------------------+----------------------+-------------------------+
1382 # +------------------+----------------------+-------------------------+
1384 # | unrelated source | new parent is <dest> | ambiguous, abort |
1383 # | unrelated source | new parent is <dest> | ambiguous, abort |
1385 # +------------------+----------------------+-------------------------+
1384 # +------------------+----------------------+-------------------------+
1386 #
1385 #
1387 # The actual abort is handled by `defineparents`
1386 # The actual abort is handled by `defineparents`
1388 if len(root.parents()) <= 1:
1387 if len(root.parents()) <= 1:
1389 # ancestors of <root> not ancestors of <dest>
1388 # ancestors of <root> not ancestors of <dest>
1390 detachset.update(repo.changelog.findmissingrevs([commonbase.rev()],
1389 detachset.update(repo.changelog.findmissingrevs([commonbase.rev()],
1391 [root.rev()]))
1390 [root.rev()]))
1392 if emptyrebase:
1391 if emptyrebase:
1393 return None
1392 return None
1394 for rev in sorted(state):
1393 for rev in sorted(state):
1395 parents = [p for p in repo.changelog.parentrevs(rev) if p != nullrev]
1394 parents = [p for p in repo.changelog.parentrevs(rev) if p != nullrev]
1396 # if all parents of this revision are done, then so is this revision
1395 # if all parents of this revision are done, then so is this revision
1397 if parents and all((state.get(p) == p for p in parents)):
1396 if parents and all((state.get(p) == p for p in parents)):
1398 state[rev] = rev
1397 state[rev] = rev
1399 for r in detachset:
1398 for r in detachset:
1400 if r not in state:
1399 if r not in state:
1401 state[r] = nullmerge
1400 state[r] = nullmerge
1402 if len(roots) > 1:
1401 if len(roots) > 1:
1403 # If we have multiple roots, we may have "hole" in the rebase set.
1402 # If we have multiple roots, we may have "hole" in the rebase set.
1404 # Rebase roots that descend from those "hole" should not be detached as
1403 # Rebase roots that descend from those "hole" should not be detached as
1405 # other root are. We use the special `revignored` to inform rebase that
1404 # other root are. We use the special `revignored` to inform rebase that
1406 # the revision should be ignored but that `defineparents` should search
1405 # the revision should be ignored but that `defineparents` should search
1407 # a rebase destination that make sense regarding rebased topology.
1406 # a rebase destination that make sense regarding rebased topology.
1408 rebasedomain = set(repo.revs('%ld::%ld', rebaseset, rebaseset))
1407 rebasedomain = set(repo.revs('%ld::%ld', rebaseset, rebaseset))
1409 for ignored in set(rebasedomain) - set(rebaseset):
1408 for ignored in set(rebasedomain) - set(rebaseset):
1410 state[ignored] = revignored
1409 state[ignored] = revignored
1411 for r in obsoletenotrebased:
1410 for r in obsoletenotrebased:
1412 if obsoletenotrebased[r] is None:
1411 if obsoletenotrebased[r] is None:
1413 state[r] = revpruned
1412 state[r] = revpruned
1414 else:
1413 else:
1415 state[r] = revprecursor
1414 state[r] = revprecursor
1416 return originalwd, dest.rev(), state
1415 return originalwd, dest.rev(), state
1417
1416
1418 def clearrebased(ui, repo, dest, state, skipped, collapsedas=None):
1417 def clearrebased(ui, repo, dest, state, skipped, collapsedas=None):
1419 """dispose of rebased revision at the end of the rebase
1418 """dispose of rebased revision at the end of the rebase
1420
1419
1421 If `collapsedas` is not None, the rebase was a collapse whose result if the
1420 If `collapsedas` is not None, the rebase was a collapse whose result if the
1422 `collapsedas` node."""
1421 `collapsedas` node."""
1423 tonode = repo.changelog.node
1422 tonode = repo.changelog.node
1424 # Move bookmark of skipped nodes to destination. This cannot be handled
1423 # Move bookmark of skipped nodes to destination. This cannot be handled
1425 # by scmutil.cleanupnodes since it will treat rev as removed (no successor)
1424 # by scmutil.cleanupnodes since it will treat rev as removed (no successor)
1426 # and move bookmark backwards.
1425 # and move bookmark backwards.
1427 bmchanges = [(name, tonode(max(adjustdest(repo, rev, dest, state))))
1426 bmchanges = [(name, tonode(max(adjustdest(repo, rev, dest, state))))
1428 for rev in skipped
1427 for rev in skipped
1429 for name in repo.nodebookmarks(tonode(rev))]
1428 for name in repo.nodebookmarks(tonode(rev))]
1430 if bmchanges:
1429 if bmchanges:
1431 with repo.transaction('rebase') as tr:
1430 with repo.transaction('rebase') as tr:
1432 repo._bookmarks.applychanges(repo, tr, bmchanges)
1431 repo._bookmarks.applychanges(repo, tr, bmchanges)
1433 mapping = {}
1432 mapping = {}
1434 for rev, newrev in sorted(state.items()):
1433 for rev, newrev in sorted(state.items()):
1435 if newrev >= 0 and newrev != rev:
1434 if newrev >= 0 and newrev != rev:
1436 if rev in skipped:
1435 if rev in skipped:
1437 succs = ()
1436 succs = ()
1438 elif collapsedas is not None:
1437 elif collapsedas is not None:
1439 succs = (collapsedas,)
1438 succs = (collapsedas,)
1440 else:
1439 else:
1441 succs = (tonode(newrev),)
1440 succs = (tonode(newrev),)
1442 mapping[tonode(rev)] = succs
1441 mapping[tonode(rev)] = succs
1443 scmutil.cleanupnodes(repo, mapping, 'rebase')
1442 scmutil.cleanupnodes(repo, mapping, 'rebase')
1444
1443
1445 def pullrebase(orig, ui, repo, *args, **opts):
1444 def pullrebase(orig, ui, repo, *args, **opts):
1446 'Call rebase after pull if the latter has been invoked with --rebase'
1445 'Call rebase after pull if the latter has been invoked with --rebase'
1447 ret = None
1446 ret = None
1448 if opts.get('rebase'):
1447 if opts.get('rebase'):
1449 if ui.configbool('commands', 'rebase.requiredest'):
1448 if ui.configbool('commands', 'rebase.requiredest'):
1450 msg = _('rebase destination required by configuration')
1449 msg = _('rebase destination required by configuration')
1451 hint = _('use hg pull followed by hg rebase -d DEST')
1450 hint = _('use hg pull followed by hg rebase -d DEST')
1452 raise error.Abort(msg, hint=hint)
1451 raise error.Abort(msg, hint=hint)
1453
1452
1454 with repo.wlock(), repo.lock():
1453 with repo.wlock(), repo.lock():
1455 if opts.get('update'):
1454 if opts.get('update'):
1456 del opts['update']
1455 del opts['update']
1457 ui.debug('--update and --rebase are not compatible, ignoring '
1456 ui.debug('--update and --rebase are not compatible, ignoring '
1458 'the update flag\n')
1457 'the update flag\n')
1459
1458
1460 cmdutil.checkunfinished(repo)
1459 cmdutil.checkunfinished(repo)
1461 cmdutil.bailifchanged(repo, hint=_('cannot pull with rebase: '
1460 cmdutil.bailifchanged(repo, hint=_('cannot pull with rebase: '
1462 'please commit or shelve your changes first'))
1461 'please commit or shelve your changes first'))
1463
1462
1464 revsprepull = len(repo)
1463 revsprepull = len(repo)
1465 origpostincoming = commands.postincoming
1464 origpostincoming = commands.postincoming
1466 def _dummy(*args, **kwargs):
1465 def _dummy(*args, **kwargs):
1467 pass
1466 pass
1468 commands.postincoming = _dummy
1467 commands.postincoming = _dummy
1469 try:
1468 try:
1470 ret = orig(ui, repo, *args, **opts)
1469 ret = orig(ui, repo, *args, **opts)
1471 finally:
1470 finally:
1472 commands.postincoming = origpostincoming
1471 commands.postincoming = origpostincoming
1473 revspostpull = len(repo)
1472 revspostpull = len(repo)
1474 if revspostpull > revsprepull:
1473 if revspostpull > revsprepull:
1475 # --rev option from pull conflict with rebase own --rev
1474 # --rev option from pull conflict with rebase own --rev
1476 # dropping it
1475 # dropping it
1477 if 'rev' in opts:
1476 if 'rev' in opts:
1478 del opts['rev']
1477 del opts['rev']
1479 # positional argument from pull conflicts with rebase's own
1478 # positional argument from pull conflicts with rebase's own
1480 # --source.
1479 # --source.
1481 if 'source' in opts:
1480 if 'source' in opts:
1482 del opts['source']
1481 del opts['source']
1483 # revsprepull is the len of the repo, not revnum of tip.
1482 # revsprepull is the len of the repo, not revnum of tip.
1484 destspace = list(repo.changelog.revs(start=revsprepull))
1483 destspace = list(repo.changelog.revs(start=revsprepull))
1485 opts['_destspace'] = destspace
1484 opts['_destspace'] = destspace
1486 try:
1485 try:
1487 rebase(ui, repo, **opts)
1486 rebase(ui, repo, **opts)
1488 except error.NoMergeDestAbort:
1487 except error.NoMergeDestAbort:
1489 # we can maybe update instead
1488 # we can maybe update instead
1490 rev, _a, _b = destutil.destupdate(repo)
1489 rev, _a, _b = destutil.destupdate(repo)
1491 if rev == repo['.'].rev():
1490 if rev == repo['.'].rev():
1492 ui.status(_('nothing to rebase\n'))
1491 ui.status(_('nothing to rebase\n'))
1493 else:
1492 else:
1494 ui.status(_('nothing to rebase - updating instead\n'))
1493 ui.status(_('nothing to rebase - updating instead\n'))
1495 # not passing argument to get the bare update behavior
1494 # not passing argument to get the bare update behavior
1496 # with warning and trumpets
1495 # with warning and trumpets
1497 commands.update(ui, repo)
1496 commands.update(ui, repo)
1498 else:
1497 else:
1499 if opts.get('tool'):
1498 if opts.get('tool'):
1500 raise error.Abort(_('--tool can only be used with --rebase'))
1499 raise error.Abort(_('--tool can only be used with --rebase'))
1501 ret = orig(ui, repo, *args, **opts)
1500 ret = orig(ui, repo, *args, **opts)
1502
1501
1503 return ret
1502 return ret
1504
1503
1505 def _setrebasesetvisibility(repo, revs):
1504 def _setrebasesetvisibility(repo, revs):
1506 """store the currently rebased set on the repo object
1505 """store the currently rebased set on the repo object
1507
1506
1508 This is used by another function to prevent rebased revision to because
1507 This is used by another function to prevent rebased revision to because
1509 hidden (see issue4504)"""
1508 hidden (see issue4504)"""
1510 repo = repo.unfiltered()
1509 repo = repo.unfiltered()
1511 repo._rebaseset = revs
1510 repo._rebaseset = revs
1512 # invalidate cache if visibility changes
1511 # invalidate cache if visibility changes
1513 hiddens = repo.filteredrevcache.get('visible', set())
1512 hiddens = repo.filteredrevcache.get('visible', set())
1514 if revs & hiddens:
1513 if revs & hiddens:
1515 repo.invalidatevolatilesets()
1514 repo.invalidatevolatilesets()
1516
1515
1517 def _clearrebasesetvisibiliy(repo):
1516 def _clearrebasesetvisibiliy(repo):
1518 """remove rebaseset data from the repo"""
1517 """remove rebaseset data from the repo"""
1519 repo = repo.unfiltered()
1518 repo = repo.unfiltered()
1520 if '_rebaseset' in vars(repo):
1519 if '_rebaseset' in vars(repo):
1521 del repo._rebaseset
1520 del repo._rebaseset
1522
1521
1523 def _rebasedvisible(orig, repo):
1522 def _rebasedvisible(orig, repo):
1524 """ensure rebased revs stay visible (see issue4504)"""
1523 """ensure rebased revs stay visible (see issue4504)"""
1525 blockers = orig(repo)
1524 blockers = orig(repo)
1526 blockers.update(getattr(repo, '_rebaseset', ()))
1525 blockers.update(getattr(repo, '_rebaseset', ()))
1527 return blockers
1526 return blockers
1528
1527
1529 def _filterobsoleterevs(repo, revs):
1528 def _filterobsoleterevs(repo, revs):
1530 """returns a set of the obsolete revisions in revs"""
1529 """returns a set of the obsolete revisions in revs"""
1531 return set(r for r in revs if repo[r].obsolete())
1530 return set(r for r in revs if repo[r].obsolete())
1532
1531
1533 def _computeobsoletenotrebased(repo, rebaseobsrevs, dest):
1532 def _computeobsoletenotrebased(repo, rebaseobsrevs, dest):
1534 """return a mapping obsolete => successor for all obsolete nodes to be
1533 """return a mapping obsolete => successor for all obsolete nodes to be
1535 rebased that have a successors in the destination
1534 rebased that have a successors in the destination
1536
1535
1537 obsolete => None entries in the mapping indicate nodes with no successor"""
1536 obsolete => None entries in the mapping indicate nodes with no successor"""
1538 obsoletenotrebased = {}
1537 obsoletenotrebased = {}
1539
1538
1540 # Build a mapping successor => obsolete nodes for the obsolete
1539 # Build a mapping successor => obsolete nodes for the obsolete
1541 # nodes to be rebased
1540 # nodes to be rebased
1542 allsuccessors = {}
1541 allsuccessors = {}
1543 cl = repo.changelog
1542 cl = repo.changelog
1544 for r in rebaseobsrevs:
1543 for r in rebaseobsrevs:
1545 node = cl.node(r)
1544 node = cl.node(r)
1546 for s in obsutil.allsuccessors(repo.obsstore, [node]):
1545 for s in obsutil.allsuccessors(repo.obsstore, [node]):
1547 try:
1546 try:
1548 allsuccessors[cl.rev(s)] = cl.rev(node)
1547 allsuccessors[cl.rev(s)] = cl.rev(node)
1549 except LookupError:
1548 except LookupError:
1550 pass
1549 pass
1551
1550
1552 if allsuccessors:
1551 if allsuccessors:
1553 # Look for successors of obsolete nodes to be rebased among
1552 # Look for successors of obsolete nodes to be rebased among
1554 # the ancestors of dest
1553 # the ancestors of dest
1555 ancs = cl.ancestors([dest],
1554 ancs = cl.ancestors([dest],
1556 stoprev=min(allsuccessors),
1555 stoprev=min(allsuccessors),
1557 inclusive=True)
1556 inclusive=True)
1558 for s in allsuccessors:
1557 for s in allsuccessors:
1559 if s in ancs:
1558 if s in ancs:
1560 obsoletenotrebased[allsuccessors[s]] = s
1559 obsoletenotrebased[allsuccessors[s]] = s
1561 elif (s == allsuccessors[s] and
1560 elif (s == allsuccessors[s] and
1562 allsuccessors.values().count(s) == 1):
1561 allsuccessors.values().count(s) == 1):
1563 # plain prune
1562 # plain prune
1564 obsoletenotrebased[s] = None
1563 obsoletenotrebased[s] = None
1565
1564
1566 return obsoletenotrebased
1565 return obsoletenotrebased
1567
1566
1568 def summaryhook(ui, repo):
1567 def summaryhook(ui, repo):
1569 if not repo.vfs.exists('rebasestate'):
1568 if not repo.vfs.exists('rebasestate'):
1570 return
1569 return
1571 try:
1570 try:
1572 rbsrt = rebaseruntime(repo, ui, {})
1571 rbsrt = rebaseruntime(repo, ui, {})
1573 rbsrt.restorestatus()
1572 rbsrt.restorestatus()
1574 state = rbsrt.state
1573 state = rbsrt.state
1575 except error.RepoLookupError:
1574 except error.RepoLookupError:
1576 # i18n: column positioning for "hg summary"
1575 # i18n: column positioning for "hg summary"
1577 msg = _('rebase: (use "hg rebase --abort" to clear broken state)\n')
1576 msg = _('rebase: (use "hg rebase --abort" to clear broken state)\n')
1578 ui.write(msg)
1577 ui.write(msg)
1579 return
1578 return
1580 numrebased = len([i for i in state.itervalues() if i >= 0])
1579 numrebased = len([i for i in state.itervalues() if i >= 0])
1581 # i18n: column positioning for "hg summary"
1580 # i18n: column positioning for "hg summary"
1582 ui.write(_('rebase: %s, %s (rebase --continue)\n') %
1581 ui.write(_('rebase: %s, %s (rebase --continue)\n') %
1583 (ui.label(_('%d rebased'), 'rebase.rebased') % numrebased,
1582 (ui.label(_('%d rebased'), 'rebase.rebased') % numrebased,
1584 ui.label(_('%d remaining'), 'rebase.remaining') %
1583 ui.label(_('%d remaining'), 'rebase.remaining') %
1585 (len(state) - numrebased)))
1584 (len(state) - numrebased)))
1586
1585
1587 def uisetup(ui):
1586 def uisetup(ui):
1588 #Replace pull with a decorator to provide --rebase option
1587 #Replace pull with a decorator to provide --rebase option
1589 entry = extensions.wrapcommand(commands.table, 'pull', pullrebase)
1588 entry = extensions.wrapcommand(commands.table, 'pull', pullrebase)
1590 entry[1].append(('', 'rebase', None,
1589 entry[1].append(('', 'rebase', None,
1591 _("rebase working directory to branch head")))
1590 _("rebase working directory to branch head")))
1592 entry[1].append(('t', 'tool', '',
1591 entry[1].append(('t', 'tool', '',
1593 _("specify merge tool for rebase")))
1592 _("specify merge tool for rebase")))
1594 cmdutil.summaryhooks.add('rebase', summaryhook)
1593 cmdutil.summaryhooks.add('rebase', summaryhook)
1595 cmdutil.unfinishedstates.append(
1594 cmdutil.unfinishedstates.append(
1596 ['rebasestate', False, False, _('rebase in progress'),
1595 ['rebasestate', False, False, _('rebase in progress'),
1597 _("use 'hg rebase --continue' or 'hg rebase --abort'")])
1596 _("use 'hg rebase --continue' or 'hg rebase --abort'")])
1598 cmdutil.afterresolvedstates.append(
1597 cmdutil.afterresolvedstates.append(
1599 ['rebasestate', _('hg rebase --continue')])
1598 ['rebasestate', _('hg rebase --continue')])
1600 # ensure rebased rev are not hidden
1599 # ensure rebased rev are not hidden
1601 extensions.wrapfunction(repoview, 'pinnedrevs', _rebasedvisible)
1600 extensions.wrapfunction(repoview, 'pinnedrevs', _rebasedvisible)
@@ -1,55 +1,55 b''
1 $ cat >> $HGRCPATH <<EOF
1 $ cat >> $HGRCPATH <<EOF
2 > [extensions]
2 > [extensions]
3 > drawdag=$TESTDIR/drawdag.py
3 > drawdag=$TESTDIR/drawdag.py
4 > bruterebase=$TESTDIR/bruterebase.py
4 > bruterebase=$TESTDIR/bruterebase.py
5 > [experimental]
5 > [experimental]
6 > evolution=createmarkers,allowunstable
6 > evolution=createmarkers,allowunstable
7 > EOF
7 > EOF
8 $ init() {
8 $ init() {
9 > N=`expr ${N:-0} + 1`
9 > N=`expr ${N:-0} + 1`
10 > cd $TESTTMP && hg init repo$N && cd repo$N
10 > cd $TESTTMP && hg init repo$N && cd repo$N
11 > hg debugdrawdag
11 > hg debugdrawdag
12 > }
12 > }
13
13
14 Source looks like "N"
14 Source looks like "N"
15
15
16 $ init <<'EOS'
16 $ init <<'EOS'
17 > C D
17 > C D
18 > |\|
18 > |\|
19 > A B Z
19 > A B Z
20 > EOS
20 > EOS
21
21
22 $ hg debugbruterebase 'all()-Z' Z
22 $ hg debugbruterebase 'all()-Z' Z
23 A: A':Z
23 A: A':Z
24 B: B':Z
24 B: B':Z
25 AB: A':Z B':Z
25 AB: A':Z B':Z
26 C: ABORT: cannot use revision 3 as base, result would have 3 parents
26 C: ABORT: cannot rebase 3:a35c07e8a2a4 without moving at least one of its parents
27 AC: A':Z C':A'B
27 AC: A':Z C':A'B
28 BC: B':Z C':B'A
28 BC: B':Z C':B'A
29 ABC: A':Z B':Z C':A'B'
29 ABC: A':Z B':Z C':A'B'
30 D: D':Z
30 D: D':Z
31 AD: A':Z D':Z
31 AD: A':Z D':Z
32 BD: B':Z D':B'
32 BD: B':Z D':B'
33 ABD: A':Z B':Z D':B'
33 ABD: A':Z B':Z D':B'
34 CD: ABORT: cannot use revision 3 as base, result would have 3 parents
34 CD: ABORT: cannot rebase 3:a35c07e8a2a4 without moving at least one of its parents
35 ACD: A':Z C':A'B D':Z
35 ACD: A':Z C':A'B D':Z
36 BCD: B':Z C':B'A D':B'
36 BCD: B':Z C':B'A D':B'
37 ABCD: A':Z B':Z C':A'B' D':B'
37 ABCD: A':Z B':Z C':A'B' D':B'
38
38
39 Moving backwards
39 Moving backwards
40
40
41 $ init <<'EOS'
41 $ init <<'EOS'
42 > C
42 > C
43 > |\
43 > |\
44 > A B
44 > A B
45 > |
45 > |
46 > Z
46 > Z
47 > EOS
47 > EOS
48 $ hg debugbruterebase 'all()-Z' Z
48 $ hg debugbruterebase 'all()-Z' Z
49 B: B':Z
49 B: B':Z
50 A:
50 A:
51 BA: B':Z
51 BA: B':Z
52 C: ABORT: cannot use revision 3 as base, result would have 3 parents
52 C: ABORT: cannot rebase 3:b8d7149b562b without moving at least one of its parents
53 BC: B':Z C':B'A
53 BC: B':Z C':B'A
54 AC:
54 AC:
55 BAC: B':Z C':B'A
55 BAC: B':Z C':B'A
@@ -1,1168 +1,1168 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}
9 > logtemplate= {rev}:{node|short} {desc|firstline}
10 > [experimental]
10 > [experimental]
11 > stabilization=createmarkers,allowunstable
11 > stabilization=createmarkers,allowunstable
12 > [phases]
12 > [phases]
13 > publish=False
13 > publish=False
14 > [extensions]
14 > [extensions]
15 > rebase=
15 > rebase=
16 > drawdag=$TESTDIR/drawdag.py
16 > drawdag=$TESTDIR/drawdag.py
17 > EOF
17 > EOF
18
18
19 Setup rebase canonical repo
19 Setup rebase canonical repo
20
20
21 $ hg init base
21 $ hg init base
22 $ cd base
22 $ cd base
23 $ hg unbundle "$TESTDIR/bundles/rebase.hg"
23 $ hg unbundle "$TESTDIR/bundles/rebase.hg"
24 adding changesets
24 adding changesets
25 adding manifests
25 adding manifests
26 adding file changes
26 adding file changes
27 added 8 changesets with 7 changes to 7 files (+2 heads)
27 added 8 changesets with 7 changes to 7 files (+2 heads)
28 (run 'hg heads' to see heads, 'hg merge' to merge)
28 (run 'hg heads' to see heads, 'hg merge' to merge)
29 $ hg up tip
29 $ hg up tip
30 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
30 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
31 $ hg log -G
31 $ hg log -G
32 @ 7:02de42196ebe H
32 @ 7:02de42196ebe H
33 |
33 |
34 | o 6:eea13746799a G
34 | o 6:eea13746799a G
35 |/|
35 |/|
36 o | 5:24b6387c8c8c F
36 o | 5:24b6387c8c8c F
37 | |
37 | |
38 | o 4:9520eea781bc E
38 | o 4:9520eea781bc E
39 |/
39 |/
40 | o 3:32af7686d403 D
40 | o 3:32af7686d403 D
41 | |
41 | |
42 | o 2:5fddd98957c8 C
42 | o 2:5fddd98957c8 C
43 | |
43 | |
44 | o 1:42ccdea3bb16 B
44 | o 1:42ccdea3bb16 B
45 |/
45 |/
46 o 0:cd010b8cd998 A
46 o 0:cd010b8cd998 A
47
47
48 $ cd ..
48 $ cd ..
49
49
50 simple rebase
50 simple rebase
51 ---------------------------------
51 ---------------------------------
52
52
53 $ hg clone base simple
53 $ hg clone base simple
54 updating to branch default
54 updating to branch default
55 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
55 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
56 $ cd simple
56 $ cd simple
57 $ hg up 32af7686d403
57 $ hg up 32af7686d403
58 3 files updated, 0 files merged, 2 files removed, 0 files unresolved
58 3 files updated, 0 files merged, 2 files removed, 0 files unresolved
59 $ hg rebase -d eea13746799a
59 $ hg rebase -d eea13746799a
60 rebasing 1:42ccdea3bb16 "B"
60 rebasing 1:42ccdea3bb16 "B"
61 rebasing 2:5fddd98957c8 "C"
61 rebasing 2:5fddd98957c8 "C"
62 rebasing 3:32af7686d403 "D"
62 rebasing 3:32af7686d403 "D"
63 $ hg log -G
63 $ hg log -G
64 @ 10:8eeb3c33ad33 D
64 @ 10:8eeb3c33ad33 D
65 |
65 |
66 o 9:2327fea05063 C
66 o 9:2327fea05063 C
67 |
67 |
68 o 8:e4e5be0395b2 B
68 o 8:e4e5be0395b2 B
69 |
69 |
70 | o 7:02de42196ebe H
70 | o 7:02de42196ebe H
71 | |
71 | |
72 o | 6:eea13746799a G
72 o | 6:eea13746799a G
73 |\|
73 |\|
74 | o 5:24b6387c8c8c F
74 | o 5:24b6387c8c8c F
75 | |
75 | |
76 o | 4:9520eea781bc E
76 o | 4:9520eea781bc E
77 |/
77 |/
78 o 0:cd010b8cd998 A
78 o 0:cd010b8cd998 A
79
79
80 $ hg log --hidden -G
80 $ hg log --hidden -G
81 @ 10:8eeb3c33ad33 D
81 @ 10:8eeb3c33ad33 D
82 |
82 |
83 o 9:2327fea05063 C
83 o 9:2327fea05063 C
84 |
84 |
85 o 8:e4e5be0395b2 B
85 o 8:e4e5be0395b2 B
86 |
86 |
87 | o 7:02de42196ebe H
87 | o 7:02de42196ebe H
88 | |
88 | |
89 o | 6:eea13746799a G
89 o | 6:eea13746799a G
90 |\|
90 |\|
91 | o 5:24b6387c8c8c F
91 | o 5:24b6387c8c8c F
92 | |
92 | |
93 o | 4:9520eea781bc E
93 o | 4:9520eea781bc E
94 |/
94 |/
95 | x 3:32af7686d403 D
95 | x 3:32af7686d403 D
96 | |
96 | |
97 | x 2:5fddd98957c8 C
97 | x 2:5fddd98957c8 C
98 | |
98 | |
99 | x 1:42ccdea3bb16 B
99 | x 1:42ccdea3bb16 B
100 |/
100 |/
101 o 0:cd010b8cd998 A
101 o 0:cd010b8cd998 A
102
102
103 $ hg debugobsolete
103 $ hg debugobsolete
104 42ccdea3bb16d28e1848c95fe2e44c000f3f21b1 e4e5be0395b2cbd471ed22a26b1b6a1a0658a794 0 (*) {'user': 'test'} (glob)
104 42ccdea3bb16d28e1848c95fe2e44c000f3f21b1 e4e5be0395b2cbd471ed22a26b1b6a1a0658a794 0 (*) {'user': 'test'} (glob)
105 5fddd98957c8a54a4d436dfe1da9d87f21a1b97b 2327fea05063f39961b14cb69435a9898dc9a245 0 (*) {'user': 'test'} (glob)
105 5fddd98957c8a54a4d436dfe1da9d87f21a1b97b 2327fea05063f39961b14cb69435a9898dc9a245 0 (*) {'user': 'test'} (glob)
106 32af7686d403cf45b5d95f2d70cebea587ac806a 8eeb3c33ad33d452c89e5dcf611c347f978fb42b 0 (*) {'user': 'test'} (glob)
106 32af7686d403cf45b5d95f2d70cebea587ac806a 8eeb3c33ad33d452c89e5dcf611c347f978fb42b 0 (*) {'user': 'test'} (glob)
107
107
108
108
109 $ cd ..
109 $ cd ..
110
110
111 empty changeset
111 empty changeset
112 ---------------------------------
112 ---------------------------------
113
113
114 $ hg clone base empty
114 $ hg clone base empty
115 updating to branch default
115 updating to branch default
116 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
116 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
117 $ cd empty
117 $ cd empty
118 $ hg up eea13746799a
118 $ hg up eea13746799a
119 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
119 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
120
120
121 We make a copy of both the first changeset in the rebased and some other in the
121 We make a copy of both the first changeset in the rebased and some other in the
122 set.
122 set.
123
123
124 $ hg graft 42ccdea3bb16 32af7686d403
124 $ hg graft 42ccdea3bb16 32af7686d403
125 grafting 1:42ccdea3bb16 "B"
125 grafting 1:42ccdea3bb16 "B"
126 grafting 3:32af7686d403 "D"
126 grafting 3:32af7686d403 "D"
127 $ hg rebase -s 42ccdea3bb16 -d .
127 $ hg rebase -s 42ccdea3bb16 -d .
128 rebasing 1:42ccdea3bb16 "B"
128 rebasing 1:42ccdea3bb16 "B"
129 note: rebase of 1:42ccdea3bb16 created no changes to commit
129 note: rebase of 1:42ccdea3bb16 created no changes to commit
130 rebasing 2:5fddd98957c8 "C"
130 rebasing 2:5fddd98957c8 "C"
131 rebasing 3:32af7686d403 "D"
131 rebasing 3:32af7686d403 "D"
132 note: rebase of 3:32af7686d403 created no changes to commit
132 note: rebase of 3:32af7686d403 created no changes to commit
133 $ hg log -G
133 $ hg log -G
134 o 10:5ae4c968c6ac C
134 o 10:5ae4c968c6ac C
135 |
135 |
136 @ 9:08483444fef9 D
136 @ 9:08483444fef9 D
137 |
137 |
138 o 8:8877864f1edb B
138 o 8:8877864f1edb B
139 |
139 |
140 | o 7:02de42196ebe H
140 | o 7:02de42196ebe H
141 | |
141 | |
142 o | 6:eea13746799a G
142 o | 6:eea13746799a G
143 |\|
143 |\|
144 | o 5:24b6387c8c8c F
144 | o 5:24b6387c8c8c F
145 | |
145 | |
146 o | 4:9520eea781bc E
146 o | 4:9520eea781bc E
147 |/
147 |/
148 o 0:cd010b8cd998 A
148 o 0:cd010b8cd998 A
149
149
150 $ hg log --hidden -G
150 $ hg log --hidden -G
151 o 10:5ae4c968c6ac C
151 o 10:5ae4c968c6ac C
152 |
152 |
153 @ 9:08483444fef9 D
153 @ 9:08483444fef9 D
154 |
154 |
155 o 8:8877864f1edb B
155 o 8:8877864f1edb B
156 |
156 |
157 | o 7:02de42196ebe H
157 | o 7:02de42196ebe H
158 | |
158 | |
159 o | 6:eea13746799a G
159 o | 6:eea13746799a G
160 |\|
160 |\|
161 | o 5:24b6387c8c8c F
161 | o 5:24b6387c8c8c F
162 | |
162 | |
163 o | 4:9520eea781bc E
163 o | 4:9520eea781bc E
164 |/
164 |/
165 | x 3:32af7686d403 D
165 | x 3:32af7686d403 D
166 | |
166 | |
167 | x 2:5fddd98957c8 C
167 | x 2:5fddd98957c8 C
168 | |
168 | |
169 | x 1:42ccdea3bb16 B
169 | x 1:42ccdea3bb16 B
170 |/
170 |/
171 o 0:cd010b8cd998 A
171 o 0:cd010b8cd998 A
172
172
173 $ hg debugobsolete
173 $ hg debugobsolete
174 42ccdea3bb16d28e1848c95fe2e44c000f3f21b1 0 {cd010b8cd998f3981a5a8115f94f8da4ab506089} (*) {'user': 'test'} (glob)
174 42ccdea3bb16d28e1848c95fe2e44c000f3f21b1 0 {cd010b8cd998f3981a5a8115f94f8da4ab506089} (*) {'user': 'test'} (glob)
175 5fddd98957c8a54a4d436dfe1da9d87f21a1b97b 5ae4c968c6aca831df823664e706c9d4aa34473d 0 (*) {'user': 'test'} (glob)
175 5fddd98957c8a54a4d436dfe1da9d87f21a1b97b 5ae4c968c6aca831df823664e706c9d4aa34473d 0 (*) {'user': 'test'} (glob)
176 32af7686d403cf45b5d95f2d70cebea587ac806a 0 {5fddd98957c8a54a4d436dfe1da9d87f21a1b97b} (*) {'user': 'test'} (glob)
176 32af7686d403cf45b5d95f2d70cebea587ac806a 0 {5fddd98957c8a54a4d436dfe1da9d87f21a1b97b} (*) {'user': 'test'} (glob)
177
177
178
178
179 More complex case where part of the rebase set were already rebased
179 More complex case where part of the rebase set were already rebased
180
180
181 $ hg rebase --rev 'desc(D)' --dest 'desc(H)'
181 $ hg rebase --rev 'desc(D)' --dest 'desc(H)'
182 rebasing 9:08483444fef9 "D"
182 rebasing 9:08483444fef9 "D"
183 $ hg debugobsolete
183 $ hg debugobsolete
184 42ccdea3bb16d28e1848c95fe2e44c000f3f21b1 0 {cd010b8cd998f3981a5a8115f94f8da4ab506089} (*) {'user': 'test'} (glob)
184 42ccdea3bb16d28e1848c95fe2e44c000f3f21b1 0 {cd010b8cd998f3981a5a8115f94f8da4ab506089} (*) {'user': 'test'} (glob)
185 5fddd98957c8a54a4d436dfe1da9d87f21a1b97b 5ae4c968c6aca831df823664e706c9d4aa34473d 0 (*) {'user': 'test'} (glob)
185 5fddd98957c8a54a4d436dfe1da9d87f21a1b97b 5ae4c968c6aca831df823664e706c9d4aa34473d 0 (*) {'user': 'test'} (glob)
186 32af7686d403cf45b5d95f2d70cebea587ac806a 0 {5fddd98957c8a54a4d436dfe1da9d87f21a1b97b} (*) {'user': 'test'} (glob)
186 32af7686d403cf45b5d95f2d70cebea587ac806a 0 {5fddd98957c8a54a4d436dfe1da9d87f21a1b97b} (*) {'user': 'test'} (glob)
187 08483444fef91d6224f6655ee586a65d263ad34c 4596109a6a4328c398bde3a4a3b6737cfade3003 0 (*) {'user': 'test'} (glob)
187 08483444fef91d6224f6655ee586a65d263ad34c 4596109a6a4328c398bde3a4a3b6737cfade3003 0 (*) {'user': 'test'} (glob)
188 $ hg log -G
188 $ hg log -G
189 @ 11:4596109a6a43 D
189 @ 11:4596109a6a43 D
190 |
190 |
191 | o 10:5ae4c968c6ac C
191 | o 10:5ae4c968c6ac C
192 | |
192 | |
193 | x 9:08483444fef9 D
193 | x 9:08483444fef9 D
194 | |
194 | |
195 | o 8:8877864f1edb B
195 | o 8:8877864f1edb B
196 | |
196 | |
197 o | 7:02de42196ebe H
197 o | 7:02de42196ebe H
198 | |
198 | |
199 | o 6:eea13746799a G
199 | o 6:eea13746799a G
200 |/|
200 |/|
201 o | 5:24b6387c8c8c F
201 o | 5:24b6387c8c8c F
202 | |
202 | |
203 | o 4:9520eea781bc E
203 | o 4:9520eea781bc E
204 |/
204 |/
205 o 0:cd010b8cd998 A
205 o 0:cd010b8cd998 A
206
206
207 $ hg rebase --source 'desc(B)' --dest 'tip' --config experimental.rebaseskipobsolete=True
207 $ hg rebase --source 'desc(B)' --dest 'tip' --config experimental.rebaseskipobsolete=True
208 rebasing 8:8877864f1edb "B"
208 rebasing 8:8877864f1edb "B"
209 note: not rebasing 9:08483444fef9 "D", already in destination as 11:4596109a6a43 "D"
209 note: not rebasing 9:08483444fef9 "D", already in destination as 11:4596109a6a43 "D"
210 rebasing 10:5ae4c968c6ac "C"
210 rebasing 10:5ae4c968c6ac "C"
211 $ hg debugobsolete
211 $ hg debugobsolete
212 42ccdea3bb16d28e1848c95fe2e44c000f3f21b1 0 {cd010b8cd998f3981a5a8115f94f8da4ab506089} (*) {'user': 'test'} (glob)
212 42ccdea3bb16d28e1848c95fe2e44c000f3f21b1 0 {cd010b8cd998f3981a5a8115f94f8da4ab506089} (*) {'user': 'test'} (glob)
213 5fddd98957c8a54a4d436dfe1da9d87f21a1b97b 5ae4c968c6aca831df823664e706c9d4aa34473d 0 (*) {'user': 'test'} (glob)
213 5fddd98957c8a54a4d436dfe1da9d87f21a1b97b 5ae4c968c6aca831df823664e706c9d4aa34473d 0 (*) {'user': 'test'} (glob)
214 32af7686d403cf45b5d95f2d70cebea587ac806a 0 {5fddd98957c8a54a4d436dfe1da9d87f21a1b97b} (*) {'user': 'test'} (glob)
214 32af7686d403cf45b5d95f2d70cebea587ac806a 0 {5fddd98957c8a54a4d436dfe1da9d87f21a1b97b} (*) {'user': 'test'} (glob)
215 08483444fef91d6224f6655ee586a65d263ad34c 4596109a6a4328c398bde3a4a3b6737cfade3003 0 (*) {'user': 'test'} (glob)
215 08483444fef91d6224f6655ee586a65d263ad34c 4596109a6a4328c398bde3a4a3b6737cfade3003 0 (*) {'user': 'test'} (glob)
216 8877864f1edb05d0e07dc4ba77b67a80a7b86672 462a34d07e599b87ea08676a449373fe4e2e1347 0 (*) {'user': 'test'} (glob)
216 8877864f1edb05d0e07dc4ba77b67a80a7b86672 462a34d07e599b87ea08676a449373fe4e2e1347 0 (*) {'user': 'test'} (glob)
217 5ae4c968c6aca831df823664e706c9d4aa34473d 98f6af4ee9539e14da4465128f894c274900b6e5 0 (*) {'user': 'test'} (glob)
217 5ae4c968c6aca831df823664e706c9d4aa34473d 98f6af4ee9539e14da4465128f894c274900b6e5 0 (*) {'user': 'test'} (glob)
218 $ hg log --rev 'contentdivergent()'
218 $ hg log --rev 'contentdivergent()'
219 $ hg log -G
219 $ hg log -G
220 o 13:98f6af4ee953 C
220 o 13:98f6af4ee953 C
221 |
221 |
222 o 12:462a34d07e59 B
222 o 12:462a34d07e59 B
223 |
223 |
224 @ 11:4596109a6a43 D
224 @ 11:4596109a6a43 D
225 |
225 |
226 o 7:02de42196ebe H
226 o 7:02de42196ebe H
227 |
227 |
228 | o 6:eea13746799a G
228 | o 6:eea13746799a G
229 |/|
229 |/|
230 o | 5:24b6387c8c8c F
230 o | 5:24b6387c8c8c F
231 | |
231 | |
232 | o 4:9520eea781bc E
232 | o 4:9520eea781bc E
233 |/
233 |/
234 o 0:cd010b8cd998 A
234 o 0:cd010b8cd998 A
235
235
236 $ hg log --style default --debug -r 4596109a6a4328c398bde3a4a3b6737cfade3003
236 $ hg log --style default --debug -r 4596109a6a4328c398bde3a4a3b6737cfade3003
237 changeset: 11:4596109a6a4328c398bde3a4a3b6737cfade3003
237 changeset: 11:4596109a6a4328c398bde3a4a3b6737cfade3003
238 phase: draft
238 phase: draft
239 parent: 7:02de42196ebee42ef284b6780a87cdc96e8eaab6
239 parent: 7:02de42196ebee42ef284b6780a87cdc96e8eaab6
240 parent: -1:0000000000000000000000000000000000000000
240 parent: -1:0000000000000000000000000000000000000000
241 manifest: 11:a91006e3a02f1edf631f7018e6e5684cf27dd905
241 manifest: 11:a91006e3a02f1edf631f7018e6e5684cf27dd905
242 user: Nicolas Dumazet <nicdumz.commits@gmail.com>
242 user: Nicolas Dumazet <nicdumz.commits@gmail.com>
243 date: Sat Apr 30 15:24:48 2011 +0200
243 date: Sat Apr 30 15:24:48 2011 +0200
244 files+: D
244 files+: D
245 extra: branch=default
245 extra: branch=default
246 extra: rebase_source=08483444fef91d6224f6655ee586a65d263ad34c
246 extra: rebase_source=08483444fef91d6224f6655ee586a65d263ad34c
247 extra: source=32af7686d403cf45b5d95f2d70cebea587ac806a
247 extra: source=32af7686d403cf45b5d95f2d70cebea587ac806a
248 description:
248 description:
249 D
249 D
250
250
251
251
252 $ hg up -qr 'desc(G)'
252 $ hg up -qr 'desc(G)'
253 $ hg graft 4596109a6a4328c398bde3a4a3b6737cfade3003
253 $ hg graft 4596109a6a4328c398bde3a4a3b6737cfade3003
254 grafting 11:4596109a6a43 "D"
254 grafting 11:4596109a6a43 "D"
255 $ hg up -qr 'desc(E)'
255 $ hg up -qr 'desc(E)'
256 $ hg rebase -s tip -d .
256 $ hg rebase -s tip -d .
257 rebasing 14:9e36056a46e3 "D" (tip)
257 rebasing 14:9e36056a46e3 "D" (tip)
258 $ hg log --style default --debug -r tip
258 $ hg log --style default --debug -r tip
259 changeset: 15:627d4614809036ba22b9e7cb31638ddc06ab99ab
259 changeset: 15:627d4614809036ba22b9e7cb31638ddc06ab99ab
260 tag: tip
260 tag: tip
261 phase: draft
261 phase: draft
262 parent: 4:9520eea781bcca16c1e15acc0ba14335a0e8e5ba
262 parent: 4:9520eea781bcca16c1e15acc0ba14335a0e8e5ba
263 parent: -1:0000000000000000000000000000000000000000
263 parent: -1:0000000000000000000000000000000000000000
264 manifest: 15:648e8ede73ae3e497d093d3a4c8fcc2daa864f42
264 manifest: 15:648e8ede73ae3e497d093d3a4c8fcc2daa864f42
265 user: Nicolas Dumazet <nicdumz.commits@gmail.com>
265 user: Nicolas Dumazet <nicdumz.commits@gmail.com>
266 date: Sat Apr 30 15:24:48 2011 +0200
266 date: Sat Apr 30 15:24:48 2011 +0200
267 files+: D
267 files+: D
268 extra: branch=default
268 extra: branch=default
269 extra: intermediate-source=4596109a6a4328c398bde3a4a3b6737cfade3003
269 extra: intermediate-source=4596109a6a4328c398bde3a4a3b6737cfade3003
270 extra: rebase_source=9e36056a46e37c9776168c7375734eebc70e294f
270 extra: rebase_source=9e36056a46e37c9776168c7375734eebc70e294f
271 extra: source=32af7686d403cf45b5d95f2d70cebea587ac806a
271 extra: source=32af7686d403cf45b5d95f2d70cebea587ac806a
272 description:
272 description:
273 D
273 D
274
274
275
275
276 Start rebase from a commit that is obsolete but not hidden only because it's
276 Start rebase from a commit that is obsolete but not hidden only because it's
277 a working copy parent. We should be moved back to the starting commit as usual
277 a working copy parent. We should be moved back to the starting commit as usual
278 even though it is hidden (until we're moved there).
278 even though it is hidden (until we're moved there).
279
279
280 $ hg --hidden up -qr 'first(hidden())'
280 $ hg --hidden up -qr 'first(hidden())'
281 $ hg rebase --rev 13 --dest 15
281 $ hg rebase --rev 13 --dest 15
282 rebasing 13:98f6af4ee953 "C"
282 rebasing 13:98f6af4ee953 "C"
283 $ hg log -G
283 $ hg log -G
284 o 16:294a2b93eb4d C
284 o 16:294a2b93eb4d C
285 |
285 |
286 o 15:627d46148090 D
286 o 15:627d46148090 D
287 |
287 |
288 | o 12:462a34d07e59 B
288 | o 12:462a34d07e59 B
289 | |
289 | |
290 | o 11:4596109a6a43 D
290 | o 11:4596109a6a43 D
291 | |
291 | |
292 | o 7:02de42196ebe H
292 | o 7:02de42196ebe H
293 | |
293 | |
294 +---o 6:eea13746799a G
294 +---o 6:eea13746799a G
295 | |/
295 | |/
296 | o 5:24b6387c8c8c F
296 | o 5:24b6387c8c8c F
297 | |
297 | |
298 o | 4:9520eea781bc E
298 o | 4:9520eea781bc E
299 |/
299 |/
300 | @ 1:42ccdea3bb16 B
300 | @ 1:42ccdea3bb16 B
301 |/
301 |/
302 o 0:cd010b8cd998 A
302 o 0:cd010b8cd998 A
303
303
304
304
305 $ cd ..
305 $ cd ..
306
306
307 collapse rebase
307 collapse rebase
308 ---------------------------------
308 ---------------------------------
309
309
310 $ hg clone base collapse
310 $ hg clone base collapse
311 updating to branch default
311 updating to branch default
312 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
312 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
313 $ cd collapse
313 $ cd collapse
314 $ hg rebase -s 42ccdea3bb16 -d eea13746799a --collapse
314 $ hg rebase -s 42ccdea3bb16 -d eea13746799a --collapse
315 rebasing 1:42ccdea3bb16 "B"
315 rebasing 1:42ccdea3bb16 "B"
316 rebasing 2:5fddd98957c8 "C"
316 rebasing 2:5fddd98957c8 "C"
317 rebasing 3:32af7686d403 "D"
317 rebasing 3:32af7686d403 "D"
318 $ hg log -G
318 $ hg log -G
319 o 8:4dc2197e807b Collapsed revision
319 o 8:4dc2197e807b Collapsed revision
320 |
320 |
321 | @ 7:02de42196ebe H
321 | @ 7:02de42196ebe H
322 | |
322 | |
323 o | 6:eea13746799a G
323 o | 6:eea13746799a G
324 |\|
324 |\|
325 | o 5:24b6387c8c8c F
325 | o 5:24b6387c8c8c F
326 | |
326 | |
327 o | 4:9520eea781bc E
327 o | 4:9520eea781bc E
328 |/
328 |/
329 o 0:cd010b8cd998 A
329 o 0:cd010b8cd998 A
330
330
331 $ hg log --hidden -G
331 $ hg log --hidden -G
332 o 8:4dc2197e807b Collapsed revision
332 o 8:4dc2197e807b Collapsed revision
333 |
333 |
334 | @ 7:02de42196ebe H
334 | @ 7:02de42196ebe H
335 | |
335 | |
336 o | 6:eea13746799a G
336 o | 6:eea13746799a G
337 |\|
337 |\|
338 | o 5:24b6387c8c8c F
338 | o 5:24b6387c8c8c F
339 | |
339 | |
340 o | 4:9520eea781bc E
340 o | 4:9520eea781bc E
341 |/
341 |/
342 | x 3:32af7686d403 D
342 | x 3:32af7686d403 D
343 | |
343 | |
344 | x 2:5fddd98957c8 C
344 | x 2:5fddd98957c8 C
345 | |
345 | |
346 | x 1:42ccdea3bb16 B
346 | x 1:42ccdea3bb16 B
347 |/
347 |/
348 o 0:cd010b8cd998 A
348 o 0:cd010b8cd998 A
349
349
350 $ hg id --debug -r tip
350 $ hg id --debug -r tip
351 4dc2197e807bae9817f09905b50ab288be2dbbcf tip
351 4dc2197e807bae9817f09905b50ab288be2dbbcf tip
352 $ hg debugobsolete
352 $ hg debugobsolete
353 42ccdea3bb16d28e1848c95fe2e44c000f3f21b1 4dc2197e807bae9817f09905b50ab288be2dbbcf 0 (*) {'user': 'test'} (glob)
353 42ccdea3bb16d28e1848c95fe2e44c000f3f21b1 4dc2197e807bae9817f09905b50ab288be2dbbcf 0 (*) {'user': 'test'} (glob)
354 5fddd98957c8a54a4d436dfe1da9d87f21a1b97b 4dc2197e807bae9817f09905b50ab288be2dbbcf 0 (*) {'user': 'test'} (glob)
354 5fddd98957c8a54a4d436dfe1da9d87f21a1b97b 4dc2197e807bae9817f09905b50ab288be2dbbcf 0 (*) {'user': 'test'} (glob)
355 32af7686d403cf45b5d95f2d70cebea587ac806a 4dc2197e807bae9817f09905b50ab288be2dbbcf 0 (*) {'user': 'test'} (glob)
355 32af7686d403cf45b5d95f2d70cebea587ac806a 4dc2197e807bae9817f09905b50ab288be2dbbcf 0 (*) {'user': 'test'} (glob)
356
356
357 $ cd ..
357 $ cd ..
358
358
359 Rebase set has hidden descendants
359 Rebase set has hidden descendants
360 ---------------------------------
360 ---------------------------------
361
361
362 We rebase a changeset which has a hidden changeset. The hidden changeset must
362 We rebase a changeset which has a hidden changeset. The hidden changeset must
363 not be rebased.
363 not be rebased.
364
364
365 $ hg clone base hidden
365 $ hg clone base hidden
366 updating to branch default
366 updating to branch default
367 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
367 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
368 $ cd hidden
368 $ cd hidden
369 $ hg rebase -s 5fddd98957c8 -d eea13746799a
369 $ hg rebase -s 5fddd98957c8 -d eea13746799a
370 rebasing 2:5fddd98957c8 "C"
370 rebasing 2:5fddd98957c8 "C"
371 rebasing 3:32af7686d403 "D"
371 rebasing 3:32af7686d403 "D"
372 $ hg rebase -s 42ccdea3bb16 -d 02de42196ebe
372 $ hg rebase -s 42ccdea3bb16 -d 02de42196ebe
373 rebasing 1:42ccdea3bb16 "B"
373 rebasing 1:42ccdea3bb16 "B"
374 $ hg log -G
374 $ hg log -G
375 o 10:7c6027df6a99 B
375 o 10:7c6027df6a99 B
376 |
376 |
377 | o 9:cf44d2f5a9f4 D
377 | o 9:cf44d2f5a9f4 D
378 | |
378 | |
379 | o 8:e273c5e7d2d2 C
379 | o 8:e273c5e7d2d2 C
380 | |
380 | |
381 @ | 7:02de42196ebe H
381 @ | 7:02de42196ebe H
382 | |
382 | |
383 | o 6:eea13746799a G
383 | o 6:eea13746799a G
384 |/|
384 |/|
385 o | 5:24b6387c8c8c F
385 o | 5:24b6387c8c8c F
386 | |
386 | |
387 | o 4:9520eea781bc E
387 | o 4:9520eea781bc E
388 |/
388 |/
389 o 0:cd010b8cd998 A
389 o 0:cd010b8cd998 A
390
390
391 $ hg log --hidden -G
391 $ hg log --hidden -G
392 o 10:7c6027df6a99 B
392 o 10:7c6027df6a99 B
393 |
393 |
394 | o 9:cf44d2f5a9f4 D
394 | o 9:cf44d2f5a9f4 D
395 | |
395 | |
396 | o 8:e273c5e7d2d2 C
396 | o 8:e273c5e7d2d2 C
397 | |
397 | |
398 @ | 7:02de42196ebe H
398 @ | 7:02de42196ebe H
399 | |
399 | |
400 | o 6:eea13746799a G
400 | o 6:eea13746799a G
401 |/|
401 |/|
402 o | 5:24b6387c8c8c F
402 o | 5:24b6387c8c8c F
403 | |
403 | |
404 | o 4:9520eea781bc E
404 | o 4:9520eea781bc E
405 |/
405 |/
406 | x 3:32af7686d403 D
406 | x 3:32af7686d403 D
407 | |
407 | |
408 | x 2:5fddd98957c8 C
408 | x 2:5fddd98957c8 C
409 | |
409 | |
410 | x 1:42ccdea3bb16 B
410 | x 1:42ccdea3bb16 B
411 |/
411 |/
412 o 0:cd010b8cd998 A
412 o 0:cd010b8cd998 A
413
413
414 $ hg debugobsolete
414 $ hg debugobsolete
415 5fddd98957c8a54a4d436dfe1da9d87f21a1b97b e273c5e7d2d29df783dce9f9eaa3ac4adc69c15d 0 (*) {'user': 'test'} (glob)
415 5fddd98957c8a54a4d436dfe1da9d87f21a1b97b e273c5e7d2d29df783dce9f9eaa3ac4adc69c15d 0 (*) {'user': 'test'} (glob)
416 32af7686d403cf45b5d95f2d70cebea587ac806a cf44d2f5a9f4297a62be94cbdd3dff7c7dc54258 0 (*) {'user': 'test'} (glob)
416 32af7686d403cf45b5d95f2d70cebea587ac806a cf44d2f5a9f4297a62be94cbdd3dff7c7dc54258 0 (*) {'user': 'test'} (glob)
417 42ccdea3bb16d28e1848c95fe2e44c000f3f21b1 7c6027df6a99d93f461868e5433f63bde20b6dfb 0 (*) {'user': 'test'} (glob)
417 42ccdea3bb16d28e1848c95fe2e44c000f3f21b1 7c6027df6a99d93f461868e5433f63bde20b6dfb 0 (*) {'user': 'test'} (glob)
418
418
419 Test that rewriting leaving instability behind is allowed
419 Test that rewriting leaving instability behind is allowed
420 ---------------------------------------------------------------------
420 ---------------------------------------------------------------------
421
421
422 $ hg log -r 'children(8)'
422 $ hg log -r 'children(8)'
423 9:cf44d2f5a9f4 D (no-eol)
423 9:cf44d2f5a9f4 D (no-eol)
424 $ hg rebase -r 8
424 $ hg rebase -r 8
425 rebasing 8:e273c5e7d2d2 "C"
425 rebasing 8:e273c5e7d2d2 "C"
426 $ hg log -G
426 $ hg log -G
427 o 11:0d8f238b634c C
427 o 11:0d8f238b634c C
428 |
428 |
429 o 10:7c6027df6a99 B
429 o 10:7c6027df6a99 B
430 |
430 |
431 | o 9:cf44d2f5a9f4 D
431 | o 9:cf44d2f5a9f4 D
432 | |
432 | |
433 | x 8:e273c5e7d2d2 C
433 | x 8:e273c5e7d2d2 C
434 | |
434 | |
435 @ | 7:02de42196ebe H
435 @ | 7:02de42196ebe H
436 | |
436 | |
437 | o 6:eea13746799a G
437 | o 6:eea13746799a G
438 |/|
438 |/|
439 o | 5:24b6387c8c8c F
439 o | 5:24b6387c8c8c F
440 | |
440 | |
441 | o 4:9520eea781bc E
441 | o 4:9520eea781bc E
442 |/
442 |/
443 o 0:cd010b8cd998 A
443 o 0:cd010b8cd998 A
444
444
445
445
446
446
447 Test multiple root handling
447 Test multiple root handling
448 ------------------------------------
448 ------------------------------------
449
449
450 $ hg rebase --dest 4 --rev '7+11+9'
450 $ hg rebase --dest 4 --rev '7+11+9'
451 rebasing 9:cf44d2f5a9f4 "D"
451 rebasing 9:cf44d2f5a9f4 "D"
452 rebasing 7:02de42196ebe "H"
452 rebasing 7:02de42196ebe "H"
453 not rebasing ignored 10:7c6027df6a99 "B"
453 not rebasing ignored 10:7c6027df6a99 "B"
454 rebasing 11:0d8f238b634c "C" (tip)
454 rebasing 11:0d8f238b634c "C" (tip)
455 $ hg log -G
455 $ hg log -G
456 o 14:1e8370e38cca C
456 o 14:1e8370e38cca C
457 |
457 |
458 @ 13:bfe264faf697 H
458 @ 13:bfe264faf697 H
459 |
459 |
460 | o 12:102b4c1d889b D
460 | o 12:102b4c1d889b D
461 |/
461 |/
462 | o 10:7c6027df6a99 B
462 | o 10:7c6027df6a99 B
463 | |
463 | |
464 | x 7:02de42196ebe H
464 | x 7:02de42196ebe H
465 | |
465 | |
466 +---o 6:eea13746799a G
466 +---o 6:eea13746799a G
467 | |/
467 | |/
468 | o 5:24b6387c8c8c F
468 | o 5:24b6387c8c8c F
469 | |
469 | |
470 o | 4:9520eea781bc E
470 o | 4:9520eea781bc E
471 |/
471 |/
472 o 0:cd010b8cd998 A
472 o 0:cd010b8cd998 A
473
473
474 $ cd ..
474 $ cd ..
475
475
476 Detach both parents
476 Detach both parents
477
477
478 $ hg init double-detach
478 $ hg init double-detach
479 $ cd double-detach
479 $ cd double-detach
480
480
481 $ hg debugdrawdag <<EOF
481 $ hg debugdrawdag <<EOF
482 > F
482 > F
483 > /|
483 > /|
484 > C E
484 > C E
485 > | |
485 > | |
486 > B D G
486 > B D G
487 > \|/
487 > \|/
488 > A
488 > A
489 > EOF
489 > EOF
490
490
491 $ hg rebase -d G -r 'B + D + F'
491 $ hg rebase -d G -r 'B + D + F'
492 rebasing 1:112478962961 "B" (B)
492 rebasing 1:112478962961 "B" (B)
493 rebasing 2:b18e25de2cf5 "D" (D)
493 rebasing 2:b18e25de2cf5 "D" (D)
494 not rebasing ignored 4:26805aba1e60 "C" (C)
494 not rebasing ignored 4:26805aba1e60 "C" (C)
495 not rebasing ignored 5:4b61ff5c62e2 "E" (E)
495 not rebasing ignored 5:4b61ff5c62e2 "E" (E)
496 rebasing 6:f15c3adaf214 "F" (F tip)
496 rebasing 6:f15c3adaf214 "F" (F tip)
497 abort: cannot use revision 6 as base, result would have 3 parents
497 abort: cannot rebase 6:f15c3adaf214 without moving at least one of its parents
498 [255]
498 [255]
499
499
500 $ cd ..
500 $ cd ..
501
501
502 test on rebase dropping a merge
502 test on rebase dropping a merge
503
503
504 (setup)
504 (setup)
505
505
506 $ hg init dropmerge
506 $ hg init dropmerge
507 $ cd dropmerge
507 $ cd dropmerge
508 $ hg unbundle "$TESTDIR/bundles/rebase.hg"
508 $ hg unbundle "$TESTDIR/bundles/rebase.hg"
509 adding changesets
509 adding changesets
510 adding manifests
510 adding manifests
511 adding file changes
511 adding file changes
512 added 8 changesets with 7 changes to 7 files (+2 heads)
512 added 8 changesets with 7 changes to 7 files (+2 heads)
513 (run 'hg heads' to see heads, 'hg merge' to merge)
513 (run 'hg heads' to see heads, 'hg merge' to merge)
514 $ hg up 3
514 $ hg up 3
515 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
515 4 files updated, 0 files merged, 0 files removed, 0 files unresolved
516 $ hg merge 7
516 $ hg merge 7
517 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
517 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
518 (branch merge, don't forget to commit)
518 (branch merge, don't forget to commit)
519 $ hg ci -m 'M'
519 $ hg ci -m 'M'
520 $ echo I > I
520 $ echo I > I
521 $ hg add I
521 $ hg add I
522 $ hg ci -m I
522 $ hg ci -m I
523 $ hg log -G
523 $ hg log -G
524 @ 9:4bde274eefcf I
524 @ 9:4bde274eefcf I
525 |
525 |
526 o 8:53a6a128b2b7 M
526 o 8:53a6a128b2b7 M
527 |\
527 |\
528 | o 7:02de42196ebe H
528 | o 7:02de42196ebe H
529 | |
529 | |
530 | | o 6:eea13746799a G
530 | | o 6:eea13746799a G
531 | |/|
531 | |/|
532 | o | 5:24b6387c8c8c F
532 | o | 5:24b6387c8c8c F
533 | | |
533 | | |
534 | | o 4:9520eea781bc E
534 | | o 4:9520eea781bc E
535 | |/
535 | |/
536 o | 3:32af7686d403 D
536 o | 3:32af7686d403 D
537 | |
537 | |
538 o | 2:5fddd98957c8 C
538 o | 2:5fddd98957c8 C
539 | |
539 | |
540 o | 1:42ccdea3bb16 B
540 o | 1:42ccdea3bb16 B
541 |/
541 |/
542 o 0:cd010b8cd998 A
542 o 0:cd010b8cd998 A
543
543
544 (actual test)
544 (actual test)
545
545
546 $ hg rebase --dest 6 --rev '((desc(H) + desc(D))::) - desc(M)'
546 $ hg rebase --dest 6 --rev '((desc(H) + desc(D))::) - desc(M)'
547 rebasing 3:32af7686d403 "D"
547 rebasing 3:32af7686d403 "D"
548 rebasing 7:02de42196ebe "H"
548 rebasing 7:02de42196ebe "H"
549 not rebasing ignored 8:53a6a128b2b7 "M"
549 not rebasing ignored 8:53a6a128b2b7 "M"
550 rebasing 9:4bde274eefcf "I" (tip)
550 rebasing 9:4bde274eefcf "I" (tip)
551 $ hg log -G
551 $ hg log -G
552 @ 12:acd174b7ab39 I
552 @ 12:acd174b7ab39 I
553 |
553 |
554 o 11:6c11a6218c97 H
554 o 11:6c11a6218c97 H
555 |
555 |
556 | o 10:b5313c85b22e D
556 | o 10:b5313c85b22e D
557 |/
557 |/
558 | o 8:53a6a128b2b7 M
558 | o 8:53a6a128b2b7 M
559 | |\
559 | |\
560 | | x 7:02de42196ebe H
560 | | x 7:02de42196ebe H
561 | | |
561 | | |
562 o---+ 6:eea13746799a G
562 o---+ 6:eea13746799a G
563 | | |
563 | | |
564 | | o 5:24b6387c8c8c F
564 | | o 5:24b6387c8c8c F
565 | | |
565 | | |
566 o---+ 4:9520eea781bc E
566 o---+ 4:9520eea781bc E
567 / /
567 / /
568 x | 3:32af7686d403 D
568 x | 3:32af7686d403 D
569 | |
569 | |
570 o | 2:5fddd98957c8 C
570 o | 2:5fddd98957c8 C
571 | |
571 | |
572 o | 1:42ccdea3bb16 B
572 o | 1:42ccdea3bb16 B
573 |/
573 |/
574 o 0:cd010b8cd998 A
574 o 0:cd010b8cd998 A
575
575
576
576
577 Test hidden changesets in the rebase set (issue4504)
577 Test hidden changesets in the rebase set (issue4504)
578
578
579 $ hg up --hidden 9
579 $ hg up --hidden 9
580 3 files updated, 0 files merged, 1 files removed, 0 files unresolved
580 3 files updated, 0 files merged, 1 files removed, 0 files unresolved
581 $ echo J > J
581 $ echo J > J
582 $ hg add J
582 $ hg add J
583 $ hg commit -m J
583 $ hg commit -m J
584 $ hg debugobsolete `hg log --rev . -T '{node}'`
584 $ hg debugobsolete `hg log --rev . -T '{node}'`
585 obsoleted 1 changesets
585 obsoleted 1 changesets
586
586
587 $ hg rebase --rev .~1::. --dest 'max(desc(D))' --traceback --config experimental.rebaseskipobsolete=off
587 $ hg rebase --rev .~1::. --dest 'max(desc(D))' --traceback --config experimental.rebaseskipobsolete=off
588 rebasing 9:4bde274eefcf "I"
588 rebasing 9:4bde274eefcf "I"
589 rebasing 13:06edfc82198f "J" (tip)
589 rebasing 13:06edfc82198f "J" (tip)
590 $ hg log -G
590 $ hg log -G
591 @ 15:5ae8a643467b J
591 @ 15:5ae8a643467b J
592 |
592 |
593 o 14:9ad579b4a5de I
593 o 14:9ad579b4a5de I
594 |
594 |
595 | o 12:acd174b7ab39 I
595 | o 12:acd174b7ab39 I
596 | |
596 | |
597 | o 11:6c11a6218c97 H
597 | o 11:6c11a6218c97 H
598 | |
598 | |
599 o | 10:b5313c85b22e D
599 o | 10:b5313c85b22e D
600 |/
600 |/
601 | o 8:53a6a128b2b7 M
601 | o 8:53a6a128b2b7 M
602 | |\
602 | |\
603 | | x 7:02de42196ebe H
603 | | x 7:02de42196ebe H
604 | | |
604 | | |
605 o---+ 6:eea13746799a G
605 o---+ 6:eea13746799a G
606 | | |
606 | | |
607 | | o 5:24b6387c8c8c F
607 | | o 5:24b6387c8c8c F
608 | | |
608 | | |
609 o---+ 4:9520eea781bc E
609 o---+ 4:9520eea781bc E
610 / /
610 / /
611 x | 3:32af7686d403 D
611 x | 3:32af7686d403 D
612 | |
612 | |
613 o | 2:5fddd98957c8 C
613 o | 2:5fddd98957c8 C
614 | |
614 | |
615 o | 1:42ccdea3bb16 B
615 o | 1:42ccdea3bb16 B
616 |/
616 |/
617 o 0:cd010b8cd998 A
617 o 0:cd010b8cd998 A
618
618
619 $ hg up 14 -C
619 $ hg up 14 -C
620 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
620 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
621 $ echo "K" > K
621 $ echo "K" > K
622 $ hg add K
622 $ hg add K
623 $ hg commit --amend -m "K"
623 $ hg commit --amend -m "K"
624 $ echo "L" > L
624 $ echo "L" > L
625 $ hg add L
625 $ hg add L
626 $ hg commit -m "L"
626 $ hg commit -m "L"
627 $ hg up '.^'
627 $ hg up '.^'
628 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
628 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
629 $ echo "M" > M
629 $ echo "M" > M
630 $ hg add M
630 $ hg add M
631 $ hg commit --amend -m "M"
631 $ hg commit --amend -m "M"
632 $ hg log -G
632 $ hg log -G
633 @ 20:bfaedf8eb73b M
633 @ 20:bfaedf8eb73b M
634 |
634 |
635 | o 18:97219452e4bd L
635 | o 18:97219452e4bd L
636 | |
636 | |
637 | x 17:fc37a630c901 K
637 | x 17:fc37a630c901 K
638 |/
638 |/
639 | o 15:5ae8a643467b J
639 | o 15:5ae8a643467b J
640 | |
640 | |
641 | x 14:9ad579b4a5de I
641 | x 14:9ad579b4a5de I
642 |/
642 |/
643 | o 12:acd174b7ab39 I
643 | o 12:acd174b7ab39 I
644 | |
644 | |
645 | o 11:6c11a6218c97 H
645 | o 11:6c11a6218c97 H
646 | |
646 | |
647 o | 10:b5313c85b22e D
647 o | 10:b5313c85b22e D
648 |/
648 |/
649 | o 8:53a6a128b2b7 M
649 | o 8:53a6a128b2b7 M
650 | |\
650 | |\
651 | | x 7:02de42196ebe H
651 | | x 7:02de42196ebe H
652 | | |
652 | | |
653 o---+ 6:eea13746799a G
653 o---+ 6:eea13746799a G
654 | | |
654 | | |
655 | | o 5:24b6387c8c8c F
655 | | o 5:24b6387c8c8c F
656 | | |
656 | | |
657 o---+ 4:9520eea781bc E
657 o---+ 4:9520eea781bc E
658 / /
658 / /
659 x | 3:32af7686d403 D
659 x | 3:32af7686d403 D
660 | |
660 | |
661 o | 2:5fddd98957c8 C
661 o | 2:5fddd98957c8 C
662 | |
662 | |
663 o | 1:42ccdea3bb16 B
663 o | 1:42ccdea3bb16 B
664 |/
664 |/
665 o 0:cd010b8cd998 A
665 o 0:cd010b8cd998 A
666
666
667 $ hg rebase -s 14 -d 18 --config experimental.rebaseskipobsolete=True
667 $ hg rebase -s 14 -d 18 --config experimental.rebaseskipobsolete=True
668 note: not rebasing 14:9ad579b4a5de "I", already in destination as 17:fc37a630c901 "K"
668 note: not rebasing 14:9ad579b4a5de "I", already in destination as 17:fc37a630c901 "K"
669 rebasing 15:5ae8a643467b "J"
669 rebasing 15:5ae8a643467b "J"
670
670
671 $ cd ..
671 $ cd ..
672
672
673 Skip obsolete changeset even with multiple hops
673 Skip obsolete changeset even with multiple hops
674 -----------------------------------------------
674 -----------------------------------------------
675
675
676 setup
676 setup
677
677
678 $ hg init obsskip
678 $ hg init obsskip
679 $ cd obsskip
679 $ cd obsskip
680 $ cat << EOF >> .hg/hgrc
680 $ cat << EOF >> .hg/hgrc
681 > [experimental]
681 > [experimental]
682 > rebaseskipobsolete = True
682 > rebaseskipobsolete = True
683 > [extensions]
683 > [extensions]
684 > strip =
684 > strip =
685 > EOF
685 > EOF
686 $ echo A > A
686 $ echo A > A
687 $ hg add A
687 $ hg add A
688 $ hg commit -m A
688 $ hg commit -m A
689 $ echo B > B
689 $ echo B > B
690 $ hg add B
690 $ hg add B
691 $ hg commit -m B0
691 $ hg commit -m B0
692 $ hg commit --amend -m B1
692 $ hg commit --amend -m B1
693 $ hg commit --amend -m B2
693 $ hg commit --amend -m B2
694 $ hg up --hidden 'desc(B0)'
694 $ hg up --hidden 'desc(B0)'
695 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
695 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
696 $ echo C > C
696 $ echo C > C
697 $ hg add C
697 $ hg add C
698 $ hg commit -m C
698 $ hg commit -m C
699
699
700 Rebase finds its way in a chain of marker
700 Rebase finds its way in a chain of marker
701
701
702 $ hg rebase -d 'desc(B2)'
702 $ hg rebase -d 'desc(B2)'
703 note: not rebasing 1:a8b11f55fb19 "B0", already in destination as 3:261e70097290 "B2"
703 note: not rebasing 1:a8b11f55fb19 "B0", already in destination as 3:261e70097290 "B2"
704 rebasing 4:212cb178bcbb "C" (tip)
704 rebasing 4:212cb178bcbb "C" (tip)
705
705
706 Even when the chain include missing node
706 Even when the chain include missing node
707
707
708 $ hg up --hidden 'desc(B0)'
708 $ hg up --hidden 'desc(B0)'
709 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
709 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
710 $ echo D > D
710 $ echo D > D
711 $ hg add D
711 $ hg add D
712 $ hg commit -m D
712 $ hg commit -m D
713 $ hg --hidden strip -r 'desc(B1)'
713 $ hg --hidden strip -r 'desc(B1)'
714 saved backup bundle to $TESTTMP/obsskip/.hg/strip-backup/86f6414ccda7-b1c452ee-backup.hg (glob)
714 saved backup bundle to $TESTTMP/obsskip/.hg/strip-backup/86f6414ccda7-b1c452ee-backup.hg (glob)
715
715
716 $ hg rebase -d 'desc(B2)'
716 $ hg rebase -d 'desc(B2)'
717 note: not rebasing 1:a8b11f55fb19 "B0", already in destination as 2:261e70097290 "B2"
717 note: not rebasing 1:a8b11f55fb19 "B0", already in destination as 2:261e70097290 "B2"
718 rebasing 5:1a79b7535141 "D" (tip)
718 rebasing 5:1a79b7535141 "D" (tip)
719 $ hg up 4
719 $ hg up 4
720 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
720 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
721 $ echo "O" > O
721 $ echo "O" > O
722 $ hg add O
722 $ hg add O
723 $ hg commit -m O
723 $ hg commit -m O
724 $ echo "P" > P
724 $ echo "P" > P
725 $ hg add P
725 $ hg add P
726 $ hg commit -m P
726 $ hg commit -m P
727 $ hg log -G
727 $ hg log -G
728 @ 8:8d47583e023f P
728 @ 8:8d47583e023f P
729 |
729 |
730 o 7:360bbaa7d3ce O
730 o 7:360bbaa7d3ce O
731 |
731 |
732 | o 6:9c48361117de D
732 | o 6:9c48361117de D
733 | |
733 | |
734 o | 4:ff2c4d47b71d C
734 o | 4:ff2c4d47b71d C
735 |/
735 |/
736 o 2:261e70097290 B2
736 o 2:261e70097290 B2
737 |
737 |
738 o 0:4a2df7238c3b A
738 o 0:4a2df7238c3b A
739
739
740 $ hg debugobsolete `hg log -r 7 -T '{node}\n'` --config experimental.stabilization=all
740 $ hg debugobsolete `hg log -r 7 -T '{node}\n'` --config experimental.stabilization=all
741 obsoleted 1 changesets
741 obsoleted 1 changesets
742 $ hg rebase -d 6 -r "4::"
742 $ hg rebase -d 6 -r "4::"
743 rebasing 4:ff2c4d47b71d "C"
743 rebasing 4:ff2c4d47b71d "C"
744 note: not rebasing 7:360bbaa7d3ce "O", it has no successor
744 note: not rebasing 7:360bbaa7d3ce "O", it has no successor
745 rebasing 8:8d47583e023f "P" (tip)
745 rebasing 8:8d47583e023f "P" (tip)
746
746
747 If all the changeset to be rebased are obsolete and present in the destination, we
747 If all the changeset to be rebased are obsolete and present in the destination, we
748 should display a friendly error message
748 should display a friendly error message
749
749
750 $ hg log -G
750 $ hg log -G
751 @ 10:121d9e3bc4c6 P
751 @ 10:121d9e3bc4c6 P
752 |
752 |
753 o 9:4be60e099a77 C
753 o 9:4be60e099a77 C
754 |
754 |
755 o 6:9c48361117de D
755 o 6:9c48361117de D
756 |
756 |
757 o 2:261e70097290 B2
757 o 2:261e70097290 B2
758 |
758 |
759 o 0:4a2df7238c3b A
759 o 0:4a2df7238c3b A
760
760
761
761
762 $ hg up 9
762 $ hg up 9
763 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
763 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
764 $ echo "non-relevant change" > nonrelevant
764 $ echo "non-relevant change" > nonrelevant
765 $ hg add nonrelevant
765 $ hg add nonrelevant
766 $ hg commit -m nonrelevant
766 $ hg commit -m nonrelevant
767 created new head
767 created new head
768 $ hg debugobsolete `hg log -r 11 -T '{node}\n'` --config experimental.stabilization=all
768 $ hg debugobsolete `hg log -r 11 -T '{node}\n'` --config experimental.stabilization=all
769 obsoleted 1 changesets
769 obsoleted 1 changesets
770 $ hg rebase -r . -d 10
770 $ hg rebase -r . -d 10
771 note: not rebasing 11:f44da1f4954c "nonrelevant" (tip), it has no successor
771 note: not rebasing 11:f44da1f4954c "nonrelevant" (tip), it has no successor
772
772
773 If a rebase is going to create divergence, it should abort
773 If a rebase is going to create divergence, it should abort
774
774
775 $ hg log -G
775 $ hg log -G
776 @ 11:f44da1f4954c nonrelevant
776 @ 11:f44da1f4954c nonrelevant
777 |
777 |
778 | o 10:121d9e3bc4c6 P
778 | o 10:121d9e3bc4c6 P
779 |/
779 |/
780 o 9:4be60e099a77 C
780 o 9:4be60e099a77 C
781 |
781 |
782 o 6:9c48361117de D
782 o 6:9c48361117de D
783 |
783 |
784 o 2:261e70097290 B2
784 o 2:261e70097290 B2
785 |
785 |
786 o 0:4a2df7238c3b A
786 o 0:4a2df7238c3b A
787
787
788
788
789 $ hg up 9
789 $ hg up 9
790 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
790 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
791 $ echo "john" > doe
791 $ echo "john" > doe
792 $ hg add doe
792 $ hg add doe
793 $ hg commit -m "john doe"
793 $ hg commit -m "john doe"
794 created new head
794 created new head
795 $ hg up 10
795 $ hg up 10
796 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
796 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
797 $ echo "foo" > bar
797 $ echo "foo" > bar
798 $ hg add bar
798 $ hg add bar
799 $ hg commit --amend -m "10'"
799 $ hg commit --amend -m "10'"
800 $ hg up 10 --hidden
800 $ hg up 10 --hidden
801 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
801 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
802 $ echo "bar" > foo
802 $ echo "bar" > foo
803 $ hg add foo
803 $ hg add foo
804 $ hg commit -m "bar foo"
804 $ hg commit -m "bar foo"
805 $ hg log -G
805 $ hg log -G
806 @ 15:73568ab6879d bar foo
806 @ 15:73568ab6879d bar foo
807 |
807 |
808 | o 14:77d874d096a2 10'
808 | o 14:77d874d096a2 10'
809 | |
809 | |
810 | | o 12:3eb461388009 john doe
810 | | o 12:3eb461388009 john doe
811 | |/
811 | |/
812 x | 10:121d9e3bc4c6 P
812 x | 10:121d9e3bc4c6 P
813 |/
813 |/
814 o 9:4be60e099a77 C
814 o 9:4be60e099a77 C
815 |
815 |
816 o 6:9c48361117de D
816 o 6:9c48361117de D
817 |
817 |
818 o 2:261e70097290 B2
818 o 2:261e70097290 B2
819 |
819 |
820 o 0:4a2df7238c3b A
820 o 0:4a2df7238c3b A
821
821
822 $ hg summary
822 $ hg summary
823 parent: 15:73568ab6879d tip (orphan)
823 parent: 15:73568ab6879d tip (orphan)
824 bar foo
824 bar foo
825 branch: default
825 branch: default
826 commit: (clean)
826 commit: (clean)
827 update: 2 new changesets, 3 branch heads (merge)
827 update: 2 new changesets, 3 branch heads (merge)
828 phases: 8 draft
828 phases: 8 draft
829 orphan: 1 changesets
829 orphan: 1 changesets
830 $ hg rebase -s 10 -d 12
830 $ hg rebase -s 10 -d 12
831 abort: this rebase will cause divergences from: 121d9e3bc4c6
831 abort: this rebase will cause divergences from: 121d9e3bc4c6
832 (to force the rebase please set experimental.allowdivergence=True)
832 (to force the rebase please set experimental.allowdivergence=True)
833 [255]
833 [255]
834 $ hg log -G
834 $ hg log -G
835 @ 15:73568ab6879d bar foo
835 @ 15:73568ab6879d bar foo
836 |
836 |
837 | o 14:77d874d096a2 10'
837 | o 14:77d874d096a2 10'
838 | |
838 | |
839 | | o 12:3eb461388009 john doe
839 | | o 12:3eb461388009 john doe
840 | |/
840 | |/
841 x | 10:121d9e3bc4c6 P
841 x | 10:121d9e3bc4c6 P
842 |/
842 |/
843 o 9:4be60e099a77 C
843 o 9:4be60e099a77 C
844 |
844 |
845 o 6:9c48361117de D
845 o 6:9c48361117de D
846 |
846 |
847 o 2:261e70097290 B2
847 o 2:261e70097290 B2
848 |
848 |
849 o 0:4a2df7238c3b A
849 o 0:4a2df7238c3b A
850
850
851 With experimental.allowdivergence=True, rebase can create divergence
851 With experimental.allowdivergence=True, rebase can create divergence
852
852
853 $ hg rebase -s 10 -d 12 --config experimental.allowdivergence=True
853 $ hg rebase -s 10 -d 12 --config experimental.allowdivergence=True
854 rebasing 10:121d9e3bc4c6 "P"
854 rebasing 10:121d9e3bc4c6 "P"
855 rebasing 15:73568ab6879d "bar foo" (tip)
855 rebasing 15:73568ab6879d "bar foo" (tip)
856 $ hg summary
856 $ hg summary
857 parent: 17:61bd55f69bc4 tip
857 parent: 17:61bd55f69bc4 tip
858 bar foo
858 bar foo
859 branch: default
859 branch: default
860 commit: (clean)
860 commit: (clean)
861 update: 1 new changesets, 2 branch heads (merge)
861 update: 1 new changesets, 2 branch heads (merge)
862 phases: 8 draft
862 phases: 8 draft
863 content-divergent: 2 changesets
863 content-divergent: 2 changesets
864
864
865 rebase --continue + skipped rev because their successors are in destination
865 rebase --continue + skipped rev because their successors are in destination
866 we make a change in trunk and work on conflicting changes to make rebase abort.
866 we make a change in trunk and work on conflicting changes to make rebase abort.
867
867
868 $ hg log -G -r 17::
868 $ hg log -G -r 17::
869 @ 17:61bd55f69bc4 bar foo
869 @ 17:61bd55f69bc4 bar foo
870 |
870 |
871 ~
871 ~
872
872
873 Create the two changes in trunk
873 Create the two changes in trunk
874 $ printf "a" > willconflict
874 $ printf "a" > willconflict
875 $ hg add willconflict
875 $ hg add willconflict
876 $ hg commit -m "willconflict first version"
876 $ hg commit -m "willconflict first version"
877
877
878 $ printf "dummy" > C
878 $ printf "dummy" > C
879 $ hg commit -m "dummy change successor"
879 $ hg commit -m "dummy change successor"
880
880
881 Create the changes that we will rebase
881 Create the changes that we will rebase
882 $ hg update -C 17 -q
882 $ hg update -C 17 -q
883 $ printf "b" > willconflict
883 $ printf "b" > willconflict
884 $ hg add willconflict
884 $ hg add willconflict
885 $ hg commit -m "willconflict second version"
885 $ hg commit -m "willconflict second version"
886 created new head
886 created new head
887 $ printf "dummy" > K
887 $ printf "dummy" > K
888 $ hg add K
888 $ hg add K
889 $ hg commit -m "dummy change"
889 $ hg commit -m "dummy change"
890 $ printf "dummy" > L
890 $ printf "dummy" > L
891 $ hg add L
891 $ hg add L
892 $ hg commit -m "dummy change"
892 $ hg commit -m "dummy change"
893 $ hg debugobsolete `hg log -r ".^" -T '{node}'` `hg log -r 19 -T '{node}'` --config experimental.stabilization=all
893 $ hg debugobsolete `hg log -r ".^" -T '{node}'` `hg log -r 19 -T '{node}'` --config experimental.stabilization=all
894 obsoleted 1 changesets
894 obsoleted 1 changesets
895
895
896 $ hg log -G -r 17::
896 $ hg log -G -r 17::
897 @ 22:7bdc8a87673d dummy change
897 @ 22:7bdc8a87673d dummy change
898 |
898 |
899 x 21:8b31da3c4919 dummy change
899 x 21:8b31da3c4919 dummy change
900 |
900 |
901 o 20:b82fb57ea638 willconflict second version
901 o 20:b82fb57ea638 willconflict second version
902 |
902 |
903 | o 19:601db7a18f51 dummy change successor
903 | o 19:601db7a18f51 dummy change successor
904 | |
904 | |
905 | o 18:357ddf1602d5 willconflict first version
905 | o 18:357ddf1602d5 willconflict first version
906 |/
906 |/
907 o 17:61bd55f69bc4 bar foo
907 o 17:61bd55f69bc4 bar foo
908 |
908 |
909 ~
909 ~
910 $ hg rebase -r ".^^ + .^ + ." -d 19
910 $ hg rebase -r ".^^ + .^ + ." -d 19
911 rebasing 20:b82fb57ea638 "willconflict second version"
911 rebasing 20:b82fb57ea638 "willconflict second version"
912 merging willconflict
912 merging willconflict
913 warning: conflicts while merging willconflict! (edit, then use 'hg resolve --mark')
913 warning: conflicts while merging willconflict! (edit, then use 'hg resolve --mark')
914 unresolved conflicts (see hg resolve, then hg rebase --continue)
914 unresolved conflicts (see hg resolve, then hg rebase --continue)
915 [1]
915 [1]
916
916
917 $ hg resolve --mark willconflict
917 $ hg resolve --mark willconflict
918 (no more unresolved files)
918 (no more unresolved files)
919 continue: hg rebase --continue
919 continue: hg rebase --continue
920 $ hg rebase --continue
920 $ hg rebase --continue
921 rebasing 20:b82fb57ea638 "willconflict second version"
921 rebasing 20:b82fb57ea638 "willconflict second version"
922 note: not rebasing 21:8b31da3c4919 "dummy change", already in destination as 19:601db7a18f51 "dummy change successor"
922 note: not rebasing 21:8b31da3c4919 "dummy change", already in destination as 19:601db7a18f51 "dummy change successor"
923 rebasing 22:7bdc8a87673d "dummy change" (tip)
923 rebasing 22:7bdc8a87673d "dummy change" (tip)
924 $ cd ..
924 $ cd ..
925
925
926 Rebase merge where successor of one parent is equal to destination (issue5198)
926 Rebase merge where successor of one parent is equal to destination (issue5198)
927
927
928 $ hg init p1-succ-is-dest
928 $ hg init p1-succ-is-dest
929 $ cd p1-succ-is-dest
929 $ cd p1-succ-is-dest
930
930
931 $ hg debugdrawdag <<EOF
931 $ hg debugdrawdag <<EOF
932 > F
932 > F
933 > /|
933 > /|
934 > E D B # replace: D -> B
934 > E D B # replace: D -> B
935 > \|/
935 > \|/
936 > A
936 > A
937 > EOF
937 > EOF
938
938
939 $ hg rebase -d B -s D
939 $ hg rebase -d B -s D
940 note: not rebasing 2:b18e25de2cf5 "D" (D), already in destination as 1:112478962961 "B"
940 note: not rebasing 2:b18e25de2cf5 "D" (D), already in destination as 1:112478962961 "B"
941 rebasing 4:66f1a38021c9 "F" (F tip)
941 rebasing 4:66f1a38021c9 "F" (F tip)
942 $ hg log -G
942 $ hg log -G
943 o 5:50e9d60b99c6 F
943 o 5:50e9d60b99c6 F
944 |\
944 |\
945 | | x 4:66f1a38021c9 F
945 | | x 4:66f1a38021c9 F
946 | |/|
946 | |/|
947 | o | 3:7fb047a69f22 E
947 | o | 3:7fb047a69f22 E
948 | | |
948 | | |
949 | | x 2:b18e25de2cf5 D
949 | | x 2:b18e25de2cf5 D
950 | |/
950 | |/
951 o | 1:112478962961 B
951 o | 1:112478962961 B
952 |/
952 |/
953 o 0:426bada5c675 A
953 o 0:426bada5c675 A
954
954
955 $ cd ..
955 $ cd ..
956
956
957 Rebase merge where successor of other parent is equal to destination
957 Rebase merge where successor of other parent is equal to destination
958
958
959 $ hg init p2-succ-is-dest
959 $ hg init p2-succ-is-dest
960 $ cd p2-succ-is-dest
960 $ cd p2-succ-is-dest
961
961
962 $ hg debugdrawdag <<EOF
962 $ hg debugdrawdag <<EOF
963 > F
963 > F
964 > /|
964 > /|
965 > E D B # replace: E -> B
965 > E D B # replace: E -> B
966 > \|/
966 > \|/
967 > A
967 > A
968 > EOF
968 > EOF
969
969
970 $ hg rebase -d B -s E
970 $ hg rebase -d B -s E
971 note: not rebasing 3:7fb047a69f22 "E" (E), already in destination as 1:112478962961 "B"
971 note: not rebasing 3:7fb047a69f22 "E" (E), already in destination as 1:112478962961 "B"
972 rebasing 4:66f1a38021c9 "F" (F tip)
972 rebasing 4:66f1a38021c9 "F" (F tip)
973 $ hg log -G
973 $ hg log -G
974 o 5:aae1787dacee F
974 o 5:aae1787dacee F
975 |\
975 |\
976 | | x 4:66f1a38021c9 F
976 | | x 4:66f1a38021c9 F
977 | |/|
977 | |/|
978 | | x 3:7fb047a69f22 E
978 | | x 3:7fb047a69f22 E
979 | | |
979 | | |
980 | o | 2:b18e25de2cf5 D
980 | o | 2:b18e25de2cf5 D
981 | |/
981 | |/
982 o / 1:112478962961 B
982 o / 1:112478962961 B
983 |/
983 |/
984 o 0:426bada5c675 A
984 o 0:426bada5c675 A
985
985
986 $ cd ..
986 $ cd ..
987
987
988 Rebase merge where successor of one parent is ancestor of destination
988 Rebase merge where successor of one parent is ancestor of destination
989
989
990 $ hg init p1-succ-in-dest
990 $ hg init p1-succ-in-dest
991 $ cd p1-succ-in-dest
991 $ cd p1-succ-in-dest
992
992
993 $ hg debugdrawdag <<EOF
993 $ hg debugdrawdag <<EOF
994 > F C
994 > F C
995 > /| |
995 > /| |
996 > E D B # replace: D -> B
996 > E D B # replace: D -> B
997 > \|/
997 > \|/
998 > A
998 > A
999 > EOF
999 > EOF
1000
1000
1001 $ hg rebase -d C -s D
1001 $ hg rebase -d C -s D
1002 note: not rebasing 2:b18e25de2cf5 "D" (D), already in destination as 1:112478962961 "B"
1002 note: not rebasing 2:b18e25de2cf5 "D" (D), already in destination as 1:112478962961 "B"
1003 rebasing 5:66f1a38021c9 "F" (F tip)
1003 rebasing 5:66f1a38021c9 "F" (F tip)
1004
1004
1005 $ hg log -G
1005 $ hg log -G
1006 o 6:0913febf6439 F
1006 o 6:0913febf6439 F
1007 |\
1007 |\
1008 +---x 5:66f1a38021c9 F
1008 +---x 5:66f1a38021c9 F
1009 | | |
1009 | | |
1010 | o | 4:26805aba1e60 C
1010 | o | 4:26805aba1e60 C
1011 | | |
1011 | | |
1012 o | | 3:7fb047a69f22 E
1012 o | | 3:7fb047a69f22 E
1013 | | |
1013 | | |
1014 +---x 2:b18e25de2cf5 D
1014 +---x 2:b18e25de2cf5 D
1015 | |
1015 | |
1016 | o 1:112478962961 B
1016 | o 1:112478962961 B
1017 |/
1017 |/
1018 o 0:426bada5c675 A
1018 o 0:426bada5c675 A
1019
1019
1020 $ cd ..
1020 $ cd ..
1021
1021
1022 Rebase merge where successor of other parent is ancestor of destination
1022 Rebase merge where successor of other parent is ancestor of destination
1023
1023
1024 $ hg init p2-succ-in-dest
1024 $ hg init p2-succ-in-dest
1025 $ cd p2-succ-in-dest
1025 $ cd p2-succ-in-dest
1026
1026
1027 $ hg debugdrawdag <<EOF
1027 $ hg debugdrawdag <<EOF
1028 > F C
1028 > F C
1029 > /| |
1029 > /| |
1030 > E D B # replace: E -> B
1030 > E D B # replace: E -> B
1031 > \|/
1031 > \|/
1032 > A
1032 > A
1033 > EOF
1033 > EOF
1034
1034
1035 $ hg rebase -d C -s E
1035 $ hg rebase -d C -s E
1036 note: not rebasing 3:7fb047a69f22 "E" (E), already in destination as 1:112478962961 "B"
1036 note: not rebasing 3:7fb047a69f22 "E" (E), already in destination as 1:112478962961 "B"
1037 rebasing 5:66f1a38021c9 "F" (F tip)
1037 rebasing 5:66f1a38021c9 "F" (F tip)
1038 $ hg log -G
1038 $ hg log -G
1039 o 6:c6ab0cc6d220 F
1039 o 6:c6ab0cc6d220 F
1040 |\
1040 |\
1041 +---x 5:66f1a38021c9 F
1041 +---x 5:66f1a38021c9 F
1042 | | |
1042 | | |
1043 | o | 4:26805aba1e60 C
1043 | o | 4:26805aba1e60 C
1044 | | |
1044 | | |
1045 | | x 3:7fb047a69f22 E
1045 | | x 3:7fb047a69f22 E
1046 | | |
1046 | | |
1047 o---+ 2:b18e25de2cf5 D
1047 o---+ 2:b18e25de2cf5 D
1048 / /
1048 / /
1049 o / 1:112478962961 B
1049 o / 1:112478962961 B
1050 |/
1050 |/
1051 o 0:426bada5c675 A
1051 o 0:426bada5c675 A
1052
1052
1053 $ cd ..
1053 $ cd ..
1054
1054
1055 Rebase merge where successor of one parent is ancestor of destination
1055 Rebase merge where successor of one parent is ancestor of destination
1056
1056
1057 $ hg init p1-succ-in-dest-b
1057 $ hg init p1-succ-in-dest-b
1058 $ cd p1-succ-in-dest-b
1058 $ cd p1-succ-in-dest-b
1059
1059
1060 $ hg debugdrawdag <<EOF
1060 $ hg debugdrawdag <<EOF
1061 > F C
1061 > F C
1062 > /| |
1062 > /| |
1063 > E D B # replace: E -> B
1063 > E D B # replace: E -> B
1064 > \|/
1064 > \|/
1065 > A
1065 > A
1066 > EOF
1066 > EOF
1067
1067
1068 $ hg rebase -d C -b F
1068 $ hg rebase -d C -b F
1069 rebasing 2:b18e25de2cf5 "D" (D)
1069 rebasing 2:b18e25de2cf5 "D" (D)
1070 note: not rebasing 3:7fb047a69f22 "E" (E), already in destination as 1:112478962961 "B"
1070 note: not rebasing 3:7fb047a69f22 "E" (E), already in destination as 1:112478962961 "B"
1071 rebasing 5:66f1a38021c9 "F" (F tip)
1071 rebasing 5:66f1a38021c9 "F" (F tip)
1072 warning: rebasing 5:66f1a38021c9 may include unwanted changes from 3:7fb047a69f22
1072 warning: rebasing 5:66f1a38021c9 may include unwanted changes from 3:7fb047a69f22
1073 $ hg log -G
1073 $ hg log -G
1074 o 7:9ed45af61fa0 F
1074 o 7:9ed45af61fa0 F
1075 |
1075 |
1076 o 6:8f47515dda15 D
1076 o 6:8f47515dda15 D
1077 |
1077 |
1078 | x 5:66f1a38021c9 F
1078 | x 5:66f1a38021c9 F
1079 | |\
1079 | |\
1080 o | | 4:26805aba1e60 C
1080 o | | 4:26805aba1e60 C
1081 | | |
1081 | | |
1082 | | x 3:7fb047a69f22 E
1082 | | x 3:7fb047a69f22 E
1083 | | |
1083 | | |
1084 | x | 2:b18e25de2cf5 D
1084 | x | 2:b18e25de2cf5 D
1085 | |/
1085 | |/
1086 o / 1:112478962961 B
1086 o / 1:112478962961 B
1087 |/
1087 |/
1088 o 0:426bada5c675 A
1088 o 0:426bada5c675 A
1089
1089
1090 $ cd ..
1090 $ cd ..
1091
1091
1092 Rebase merge where successor of other parent is ancestor of destination
1092 Rebase merge where successor of other parent is ancestor of destination
1093
1093
1094 $ hg init p2-succ-in-dest-b
1094 $ hg init p2-succ-in-dest-b
1095 $ cd p2-succ-in-dest-b
1095 $ cd p2-succ-in-dest-b
1096
1096
1097 $ hg debugdrawdag <<EOF
1097 $ hg debugdrawdag <<EOF
1098 > F C
1098 > F C
1099 > /| |
1099 > /| |
1100 > E D B # replace: D -> B
1100 > E D B # replace: D -> B
1101 > \|/
1101 > \|/
1102 > A
1102 > A
1103 > EOF
1103 > EOF
1104
1104
1105 $ hg rebase -d C -b F
1105 $ hg rebase -d C -b F
1106 note: not rebasing 2:b18e25de2cf5 "D" (D), already in destination as 1:112478962961 "B"
1106 note: not rebasing 2:b18e25de2cf5 "D" (D), already in destination as 1:112478962961 "B"
1107 rebasing 3:7fb047a69f22 "E" (E)
1107 rebasing 3:7fb047a69f22 "E" (E)
1108 rebasing 5:66f1a38021c9 "F" (F tip)
1108 rebasing 5:66f1a38021c9 "F" (F tip)
1109 warning: rebasing 5:66f1a38021c9 may include unwanted changes from 2:b18e25de2cf5
1109 warning: rebasing 5:66f1a38021c9 may include unwanted changes from 2:b18e25de2cf5
1110
1110
1111 $ hg log -G
1111 $ hg log -G
1112 o 7:502540f44880 F
1112 o 7:502540f44880 F
1113 |
1113 |
1114 o 6:533690786a86 E
1114 o 6:533690786a86 E
1115 |
1115 |
1116 | x 5:66f1a38021c9 F
1116 | x 5:66f1a38021c9 F
1117 | |\
1117 | |\
1118 o | | 4:26805aba1e60 C
1118 o | | 4:26805aba1e60 C
1119 | | |
1119 | | |
1120 | | x 3:7fb047a69f22 E
1120 | | x 3:7fb047a69f22 E
1121 | | |
1121 | | |
1122 | x | 2:b18e25de2cf5 D
1122 | x | 2:b18e25de2cf5 D
1123 | |/
1123 | |/
1124 o / 1:112478962961 B
1124 o / 1:112478962961 B
1125 |/
1125 |/
1126 o 0:426bada5c675 A
1126 o 0:426bada5c675 A
1127
1127
1128 $ cd ..
1128 $ cd ..
1129
1129
1130 Test that bookmark is moved and working dir is updated when all changesets have
1130 Test that bookmark is moved and working dir is updated when all changesets have
1131 equivalents in destination
1131 equivalents in destination
1132 $ hg init rbsrepo && cd rbsrepo
1132 $ hg init rbsrepo && cd rbsrepo
1133 $ echo "[experimental]" > .hg/hgrc
1133 $ echo "[experimental]" > .hg/hgrc
1134 $ echo "stabilization=all" >> .hg/hgrc
1134 $ echo "stabilization=all" >> .hg/hgrc
1135 $ echo "rebaseskipobsolete=on" >> .hg/hgrc
1135 $ echo "rebaseskipobsolete=on" >> .hg/hgrc
1136 $ echo root > root && hg ci -Am root
1136 $ echo root > root && hg ci -Am root
1137 adding root
1137 adding root
1138 $ echo a > a && hg ci -Am a
1138 $ echo a > a && hg ci -Am a
1139 adding a
1139 adding a
1140 $ hg up 0
1140 $ hg up 0
1141 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
1141 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
1142 $ echo b > b && hg ci -Am b
1142 $ echo b > b && hg ci -Am b
1143 adding b
1143 adding b
1144 created new head
1144 created new head
1145 $ hg rebase -r 2 -d 1
1145 $ hg rebase -r 2 -d 1
1146 rebasing 2:1e9a3c00cbe9 "b" (tip)
1146 rebasing 2:1e9a3c00cbe9 "b" (tip)
1147 $ hg log -r . # working dir is at rev 3 (successor of 2)
1147 $ hg log -r . # working dir is at rev 3 (successor of 2)
1148 3:be1832deae9a b (no-eol)
1148 3:be1832deae9a b (no-eol)
1149 $ hg book -r 2 mybook --hidden # rev 2 has a bookmark on it now
1149 $ hg book -r 2 mybook --hidden # rev 2 has a bookmark on it now
1150 $ hg up 2 && hg log -r . # working dir is at rev 2 again
1150 $ hg up 2 && hg log -r . # working dir is at rev 2 again
1151 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
1151 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
1152 2:1e9a3c00cbe9 b (no-eol)
1152 2:1e9a3c00cbe9 b (no-eol)
1153 $ hg rebase -r 2 -d 3 --config experimental.stabilization.track-operation=1
1153 $ hg rebase -r 2 -d 3 --config experimental.stabilization.track-operation=1
1154 note: not rebasing 2:1e9a3c00cbe9 "b" (mybook), already in destination as 3:be1832deae9a "b"
1154 note: not rebasing 2:1e9a3c00cbe9 "b" (mybook), already in destination as 3:be1832deae9a "b"
1155 Check that working directory was updated to rev 3 although rev 2 was skipped
1155 Check that working directory was updated to rev 3 although rev 2 was skipped
1156 during the rebase operation
1156 during the rebase operation
1157 $ hg log -r .
1157 $ hg log -r .
1158 3:be1832deae9a b (no-eol)
1158 3:be1832deae9a b (no-eol)
1159
1159
1160 Check that bookmark was not moved to rev 3 if rev 2 was skipped during the
1160 Check that bookmark was not moved to rev 3 if rev 2 was skipped during the
1161 rebase operation. This makes sense because if rev 2 has a successor, the
1161 rebase operation. This makes sense because if rev 2 has a successor, the
1162 operation generating that successor (ex. rebase) should be responsible for
1162 operation generating that successor (ex. rebase) should be responsible for
1163 moving bookmarks. If the bookmark is on a precursor, like rev 2, that means the
1163 moving bookmarks. If the bookmark is on a precursor, like rev 2, that means the
1164 user manually moved it back. In that case we should not move it again.
1164 user manually moved it back. In that case we should not move it again.
1165 $ hg bookmarks
1165 $ hg bookmarks
1166 mybook 2:1e9a3c00cbe9
1166 mybook 2:1e9a3c00cbe9
1167 $ hg debugobsolete --rev tip
1167 $ hg debugobsolete --rev tip
1168 1e9a3c00cbe90d236ac05ef61efcc5e40b7412bc be1832deae9ac531caa7438b8dcf6055a122cd8e 0 (*) {'user': 'test'} (glob)
1168 1e9a3c00cbe90d236ac05ef61efcc5e40b7412bc be1832deae9ac531caa7438b8dcf6055a122cd8e 0 (*) {'user': 'test'} (glob)
@@ -1,949 +1,949 b''
1 $ cat >> $HGRCPATH <<EOF
1 $ cat >> $HGRCPATH <<EOF
2 > [extensions]
2 > [extensions]
3 > rebase=
3 > rebase=
4 > drawdag=$TESTDIR/drawdag.py
4 > drawdag=$TESTDIR/drawdag.py
5 >
5 >
6 > [phases]
6 > [phases]
7 > publish=False
7 > publish=False
8 >
8 >
9 > [alias]
9 > [alias]
10 > tglog = log -G --template "{rev}: '{desc}' {branches}\n"
10 > tglog = log -G --template "{rev}: '{desc}' {branches}\n"
11 > EOF
11 > EOF
12
12
13
13
14 $ hg init a
14 $ hg init a
15 $ cd a
15 $ cd a
16 $ hg unbundle "$TESTDIR/bundles/rebase.hg"
16 $ hg unbundle "$TESTDIR/bundles/rebase.hg"
17 adding changesets
17 adding changesets
18 adding manifests
18 adding manifests
19 adding file changes
19 adding file changes
20 added 8 changesets with 7 changes to 7 files (+2 heads)
20 added 8 changesets with 7 changes to 7 files (+2 heads)
21 (run 'hg heads' to see heads, 'hg merge' to merge)
21 (run 'hg heads' to see heads, 'hg merge' to merge)
22 $ hg up tip
22 $ hg up tip
23 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
23 3 files updated, 0 files merged, 0 files removed, 0 files unresolved
24 $ cd ..
24 $ cd ..
25
25
26
26
27 Rebasing
27 Rebasing
28 D onto H - simple rebase:
28 D onto H - simple rebase:
29 (this also tests that editor is invoked if '--edit' is specified, and that we
29 (this also tests that editor is invoked if '--edit' is specified, and that we
30 can abort or warn for colliding untracked files)
30 can abort or warn for colliding untracked files)
31
31
32 $ hg clone -q -u . a a1
32 $ hg clone -q -u . a a1
33 $ cd a1
33 $ cd a1
34
34
35 $ hg tglog
35 $ hg tglog
36 @ 7: 'H'
36 @ 7: 'H'
37 |
37 |
38 | o 6: 'G'
38 | o 6: 'G'
39 |/|
39 |/|
40 o | 5: 'F'
40 o | 5: 'F'
41 | |
41 | |
42 | o 4: 'E'
42 | o 4: 'E'
43 |/
43 |/
44 | o 3: 'D'
44 | o 3: 'D'
45 | |
45 | |
46 | o 2: 'C'
46 | o 2: 'C'
47 | |
47 | |
48 | o 1: 'B'
48 | o 1: 'B'
49 |/
49 |/
50 o 0: 'A'
50 o 0: 'A'
51
51
52
52
53 $ hg status --rev "3^1" --rev 3
53 $ hg status --rev "3^1" --rev 3
54 A D
54 A D
55 $ echo collide > D
55 $ echo collide > D
56 $ HGEDITOR=cat hg rebase -s 3 -d 7 --edit --config merge.checkunknown=warn
56 $ HGEDITOR=cat hg rebase -s 3 -d 7 --edit --config merge.checkunknown=warn
57 rebasing 3:32af7686d403 "D"
57 rebasing 3:32af7686d403 "D"
58 D: replacing untracked file
58 D: replacing untracked file
59 D
59 D
60
60
61
61
62 HG: Enter commit message. Lines beginning with 'HG:' are removed.
62 HG: Enter commit message. Lines beginning with 'HG:' are removed.
63 HG: Leave message empty to abort commit.
63 HG: Leave message empty to abort commit.
64 HG: --
64 HG: --
65 HG: user: Nicolas Dumazet <nicdumz.commits@gmail.com>
65 HG: user: Nicolas Dumazet <nicdumz.commits@gmail.com>
66 HG: branch 'default'
66 HG: branch 'default'
67 HG: added D
67 HG: added D
68 saved backup bundle to $TESTTMP/a1/.hg/strip-backup/32af7686d403-6f7dface-rebase.hg (glob)
68 saved backup bundle to $TESTTMP/a1/.hg/strip-backup/32af7686d403-6f7dface-rebase.hg (glob)
69 $ cat D.orig
69 $ cat D.orig
70 collide
70 collide
71 $ rm D.orig
71 $ rm D.orig
72
72
73 $ hg tglog
73 $ hg tglog
74 o 7: 'D'
74 o 7: 'D'
75 |
75 |
76 @ 6: 'H'
76 @ 6: 'H'
77 |
77 |
78 | o 5: 'G'
78 | o 5: 'G'
79 |/|
79 |/|
80 o | 4: 'F'
80 o | 4: 'F'
81 | |
81 | |
82 | o 3: 'E'
82 | o 3: 'E'
83 |/
83 |/
84 | o 2: 'C'
84 | o 2: 'C'
85 | |
85 | |
86 | o 1: 'B'
86 | o 1: 'B'
87 |/
87 |/
88 o 0: 'A'
88 o 0: 'A'
89
89
90 $ cd ..
90 $ cd ..
91
91
92
92
93 D onto F - intermediate point:
93 D onto F - intermediate point:
94 (this also tests that editor is not invoked if '--edit' is not specified, and
94 (this also tests that editor is not invoked if '--edit' is not specified, and
95 that we can ignore for colliding untracked files)
95 that we can ignore for colliding untracked files)
96
96
97 $ hg clone -q -u . a a2
97 $ hg clone -q -u . a a2
98 $ cd a2
98 $ cd a2
99 $ echo collide > D
99 $ echo collide > D
100
100
101 $ HGEDITOR=cat hg rebase -s 3 -d 5 --config merge.checkunknown=ignore
101 $ HGEDITOR=cat hg rebase -s 3 -d 5 --config merge.checkunknown=ignore
102 rebasing 3:32af7686d403 "D"
102 rebasing 3:32af7686d403 "D"
103 saved backup bundle to $TESTTMP/a2/.hg/strip-backup/32af7686d403-6f7dface-rebase.hg (glob)
103 saved backup bundle to $TESTTMP/a2/.hg/strip-backup/32af7686d403-6f7dface-rebase.hg (glob)
104 $ cat D.orig
104 $ cat D.orig
105 collide
105 collide
106 $ rm D.orig
106 $ rm D.orig
107
107
108 $ hg tglog
108 $ hg tglog
109 o 7: 'D'
109 o 7: 'D'
110 |
110 |
111 | @ 6: 'H'
111 | @ 6: 'H'
112 |/
112 |/
113 | o 5: 'G'
113 | o 5: 'G'
114 |/|
114 |/|
115 o | 4: 'F'
115 o | 4: 'F'
116 | |
116 | |
117 | o 3: 'E'
117 | o 3: 'E'
118 |/
118 |/
119 | o 2: 'C'
119 | o 2: 'C'
120 | |
120 | |
121 | o 1: 'B'
121 | o 1: 'B'
122 |/
122 |/
123 o 0: 'A'
123 o 0: 'A'
124
124
125 $ cd ..
125 $ cd ..
126
126
127
127
128 E onto H - skip of G:
128 E onto H - skip of G:
129 (this also tests that we can overwrite untracked files and don't create backups
129 (this also tests that we can overwrite untracked files and don't create backups
130 if they have the same contents)
130 if they have the same contents)
131
131
132 $ hg clone -q -u . a a3
132 $ hg clone -q -u . a a3
133 $ cd a3
133 $ cd a3
134 $ hg cat -r 4 E | tee E
134 $ hg cat -r 4 E | tee E
135 E
135 E
136
136
137 $ hg rebase -s 4 -d 7
137 $ hg rebase -s 4 -d 7
138 rebasing 4:9520eea781bc "E"
138 rebasing 4:9520eea781bc "E"
139 rebasing 6:eea13746799a "G"
139 rebasing 6:eea13746799a "G"
140 note: rebase of 6:eea13746799a created no changes to commit
140 note: rebase of 6:eea13746799a created no changes to commit
141 saved backup bundle to $TESTTMP/a3/.hg/strip-backup/9520eea781bc-fcd8edd4-rebase.hg (glob)
141 saved backup bundle to $TESTTMP/a3/.hg/strip-backup/9520eea781bc-fcd8edd4-rebase.hg (glob)
142 $ f E.orig
142 $ f E.orig
143 E.orig: file not found
143 E.orig: file not found
144
144
145 $ hg tglog
145 $ hg tglog
146 o 6: 'E'
146 o 6: 'E'
147 |
147 |
148 @ 5: 'H'
148 @ 5: 'H'
149 |
149 |
150 o 4: 'F'
150 o 4: 'F'
151 |
151 |
152 | o 3: 'D'
152 | o 3: 'D'
153 | |
153 | |
154 | o 2: 'C'
154 | o 2: 'C'
155 | |
155 | |
156 | o 1: 'B'
156 | o 1: 'B'
157 |/
157 |/
158 o 0: 'A'
158 o 0: 'A'
159
159
160 $ cd ..
160 $ cd ..
161
161
162
162
163 F onto E - rebase of a branching point (skip G):
163 F onto E - rebase of a branching point (skip G):
164
164
165 $ hg clone -q -u . a a4
165 $ hg clone -q -u . a a4
166 $ cd a4
166 $ cd a4
167
167
168 $ hg rebase -s 5 -d 4
168 $ hg rebase -s 5 -d 4
169 rebasing 5:24b6387c8c8c "F"
169 rebasing 5:24b6387c8c8c "F"
170 rebasing 6:eea13746799a "G"
170 rebasing 6:eea13746799a "G"
171 note: rebase of 6:eea13746799a created no changes to commit
171 note: rebase of 6:eea13746799a created no changes to commit
172 rebasing 7:02de42196ebe "H" (tip)
172 rebasing 7:02de42196ebe "H" (tip)
173 saved backup bundle to $TESTTMP/a4/.hg/strip-backup/24b6387c8c8c-c3fe765d-rebase.hg (glob)
173 saved backup bundle to $TESTTMP/a4/.hg/strip-backup/24b6387c8c8c-c3fe765d-rebase.hg (glob)
174
174
175 $ hg tglog
175 $ hg tglog
176 @ 6: 'H'
176 @ 6: 'H'
177 |
177 |
178 o 5: 'F'
178 o 5: 'F'
179 |
179 |
180 o 4: 'E'
180 o 4: 'E'
181 |
181 |
182 | o 3: 'D'
182 | o 3: 'D'
183 | |
183 | |
184 | o 2: 'C'
184 | o 2: 'C'
185 | |
185 | |
186 | o 1: 'B'
186 | o 1: 'B'
187 |/
187 |/
188 o 0: 'A'
188 o 0: 'A'
189
189
190 $ cd ..
190 $ cd ..
191
191
192
192
193 G onto H - merged revision having a parent in ancestors of target:
193 G onto H - merged revision having a parent in ancestors of target:
194
194
195 $ hg clone -q -u . a a5
195 $ hg clone -q -u . a a5
196 $ cd a5
196 $ cd a5
197
197
198 $ hg rebase -s 6 -d 7
198 $ hg rebase -s 6 -d 7
199 rebasing 6:eea13746799a "G"
199 rebasing 6:eea13746799a "G"
200 saved backup bundle to $TESTTMP/a5/.hg/strip-backup/eea13746799a-883828ed-rebase.hg (glob)
200 saved backup bundle to $TESTTMP/a5/.hg/strip-backup/eea13746799a-883828ed-rebase.hg (glob)
201
201
202 $ hg tglog
202 $ hg tglog
203 o 7: 'G'
203 o 7: 'G'
204 |\
204 |\
205 | @ 6: 'H'
205 | @ 6: 'H'
206 | |
206 | |
207 | o 5: 'F'
207 | o 5: 'F'
208 | |
208 | |
209 o | 4: 'E'
209 o | 4: 'E'
210 |/
210 |/
211 | o 3: 'D'
211 | o 3: 'D'
212 | |
212 | |
213 | o 2: 'C'
213 | o 2: 'C'
214 | |
214 | |
215 | o 1: 'B'
215 | o 1: 'B'
216 |/
216 |/
217 o 0: 'A'
217 o 0: 'A'
218
218
219 $ cd ..
219 $ cd ..
220
220
221
221
222 F onto B - G maintains E as parent:
222 F onto B - G maintains E as parent:
223
223
224 $ hg clone -q -u . a a6
224 $ hg clone -q -u . a a6
225 $ cd a6
225 $ cd a6
226
226
227 $ hg rebase -s 5 -d 1
227 $ hg rebase -s 5 -d 1
228 rebasing 5:24b6387c8c8c "F"
228 rebasing 5:24b6387c8c8c "F"
229 rebasing 6:eea13746799a "G"
229 rebasing 6:eea13746799a "G"
230 rebasing 7:02de42196ebe "H" (tip)
230 rebasing 7:02de42196ebe "H" (tip)
231 saved backup bundle to $TESTTMP/a6/.hg/strip-backup/24b6387c8c8c-c3fe765d-rebase.hg (glob)
231 saved backup bundle to $TESTTMP/a6/.hg/strip-backup/24b6387c8c8c-c3fe765d-rebase.hg (glob)
232
232
233 $ hg tglog
233 $ hg tglog
234 @ 7: 'H'
234 @ 7: 'H'
235 |
235 |
236 | o 6: 'G'
236 | o 6: 'G'
237 |/|
237 |/|
238 o | 5: 'F'
238 o | 5: 'F'
239 | |
239 | |
240 | o 4: 'E'
240 | o 4: 'E'
241 | |
241 | |
242 | | o 3: 'D'
242 | | o 3: 'D'
243 | | |
243 | | |
244 +---o 2: 'C'
244 +---o 2: 'C'
245 | |
245 | |
246 o | 1: 'B'
246 o | 1: 'B'
247 |/
247 |/
248 o 0: 'A'
248 o 0: 'A'
249
249
250 $ cd ..
250 $ cd ..
251
251
252
252
253 These will fail (using --source):
253 These will fail (using --source):
254
254
255 G onto F - rebase onto an ancestor:
255 G onto F - rebase onto an ancestor:
256
256
257 $ hg clone -q -u . a a7
257 $ hg clone -q -u . a a7
258 $ cd a7
258 $ cd a7
259
259
260 $ hg rebase -s 6 -d 5
260 $ hg rebase -s 6 -d 5
261 nothing to rebase
261 nothing to rebase
262 [1]
262 [1]
263
263
264 F onto G - rebase onto a descendant:
264 F onto G - rebase onto a descendant:
265
265
266 $ hg rebase -s 5 -d 6
266 $ hg rebase -s 5 -d 6
267 abort: source is ancestor of destination
267 abort: source is ancestor of destination
268 [255]
268 [255]
269
269
270 G onto B - merge revision with both parents not in ancestors of target:
270 G onto B - merge revision with both parents not in ancestors of target:
271
271
272 $ hg rebase -s 6 -d 1
272 $ hg rebase -s 6 -d 1
273 rebasing 6:eea13746799a "G"
273 rebasing 6:eea13746799a "G"
274 abort: cannot use revision 6 as base, result would have 3 parents
274 abort: cannot rebase 6:eea13746799a without moving at least one of its parents
275 [255]
275 [255]
276 $ hg rebase --abort
276 $ hg rebase --abort
277 rebase aborted
277 rebase aborted
278
278
279 These will abort gracefully (using --base):
279 These will abort gracefully (using --base):
280
280
281 G onto G - rebase onto same changeset:
281 G onto G - rebase onto same changeset:
282
282
283 $ hg rebase -b 6 -d 6
283 $ hg rebase -b 6 -d 6
284 nothing to rebase - eea13746799a is both "base" and destination
284 nothing to rebase - eea13746799a is both "base" and destination
285 [1]
285 [1]
286
286
287 G onto F - rebase onto an ancestor:
287 G onto F - rebase onto an ancestor:
288
288
289 $ hg rebase -b 6 -d 5
289 $ hg rebase -b 6 -d 5
290 nothing to rebase
290 nothing to rebase
291 [1]
291 [1]
292
292
293 F onto G - rebase onto a descendant:
293 F onto G - rebase onto a descendant:
294
294
295 $ hg rebase -b 5 -d 6
295 $ hg rebase -b 5 -d 6
296 nothing to rebase - "base" 24b6387c8c8c is already an ancestor of destination eea13746799a
296 nothing to rebase - "base" 24b6387c8c8c is already an ancestor of destination eea13746799a
297 [1]
297 [1]
298
298
299 C onto A - rebase onto an ancestor:
299 C onto A - rebase onto an ancestor:
300
300
301 $ hg rebase -d 0 -s 2
301 $ hg rebase -d 0 -s 2
302 rebasing 2:5fddd98957c8 "C"
302 rebasing 2:5fddd98957c8 "C"
303 rebasing 3:32af7686d403 "D"
303 rebasing 3:32af7686d403 "D"
304 saved backup bundle to $TESTTMP/a7/.hg/strip-backup/5fddd98957c8-f9244fa1-rebase.hg (glob)
304 saved backup bundle to $TESTTMP/a7/.hg/strip-backup/5fddd98957c8-f9244fa1-rebase.hg (glob)
305 $ hg tglog
305 $ hg tglog
306 o 7: 'D'
306 o 7: 'D'
307 |
307 |
308 o 6: 'C'
308 o 6: 'C'
309 |
309 |
310 | @ 5: 'H'
310 | @ 5: 'H'
311 | |
311 | |
312 | | o 4: 'G'
312 | | o 4: 'G'
313 | |/|
313 | |/|
314 | o | 3: 'F'
314 | o | 3: 'F'
315 |/ /
315 |/ /
316 | o 2: 'E'
316 | o 2: 'E'
317 |/
317 |/
318 | o 1: 'B'
318 | o 1: 'B'
319 |/
319 |/
320 o 0: 'A'
320 o 0: 'A'
321
321
322
322
323 Check rebasing public changeset
323 Check rebasing public changeset
324
324
325 $ hg pull --config phases.publish=True -q -r 6 . # update phase of 6
325 $ hg pull --config phases.publish=True -q -r 6 . # update phase of 6
326 $ hg rebase -d 0 -b 6
326 $ hg rebase -d 0 -b 6
327 nothing to rebase
327 nothing to rebase
328 [1]
328 [1]
329 $ hg rebase -d 5 -b 6
329 $ hg rebase -d 5 -b 6
330 abort: can't rebase public changeset e1c4361dd923
330 abort: can't rebase public changeset e1c4361dd923
331 (see 'hg help phases' for details)
331 (see 'hg help phases' for details)
332 [255]
332 [255]
333 $ hg rebase -d 5 -r '1 + (6::)'
333 $ hg rebase -d 5 -r '1 + (6::)'
334 abort: can't rebase public changeset e1c4361dd923
334 abort: can't rebase public changeset e1c4361dd923
335 (see 'hg help phases' for details)
335 (see 'hg help phases' for details)
336 [255]
336 [255]
337
337
338 $ hg rebase -d 5 -b 6 --keep
338 $ hg rebase -d 5 -b 6 --keep
339 rebasing 6:e1c4361dd923 "C"
339 rebasing 6:e1c4361dd923 "C"
340 rebasing 7:c9659aac0000 "D" (tip)
340 rebasing 7:c9659aac0000 "D" (tip)
341
341
342 Check rebasing mutable changeset
342 Check rebasing mutable changeset
343 Source phase greater or equal to destination phase: new changeset get the phase of source:
343 Source phase greater or equal to destination phase: new changeset get the phase of source:
344 $ hg id -n
344 $ hg id -n
345 5
345 5
346 $ hg rebase -s9 -d0
346 $ hg rebase -s9 -d0
347 rebasing 9:2b23e52411f4 "D" (tip)
347 rebasing 9:2b23e52411f4 "D" (tip)
348 saved backup bundle to $TESTTMP/a7/.hg/strip-backup/2b23e52411f4-f942decf-rebase.hg (glob)
348 saved backup bundle to $TESTTMP/a7/.hg/strip-backup/2b23e52411f4-f942decf-rebase.hg (glob)
349 $ hg id -n # check we updated back to parent
349 $ hg id -n # check we updated back to parent
350 5
350 5
351 $ hg log --template "{phase}\n" -r 9
351 $ hg log --template "{phase}\n" -r 9
352 draft
352 draft
353 $ hg rebase -s9 -d1
353 $ hg rebase -s9 -d1
354 rebasing 9:2cb10d0cfc6c "D" (tip)
354 rebasing 9:2cb10d0cfc6c "D" (tip)
355 saved backup bundle to $TESTTMP/a7/.hg/strip-backup/2cb10d0cfc6c-ddb0f256-rebase.hg (glob)
355 saved backup bundle to $TESTTMP/a7/.hg/strip-backup/2cb10d0cfc6c-ddb0f256-rebase.hg (glob)
356 $ hg log --template "{phase}\n" -r 9
356 $ hg log --template "{phase}\n" -r 9
357 draft
357 draft
358 $ hg phase --force --secret 9
358 $ hg phase --force --secret 9
359 $ hg rebase -s9 -d0
359 $ hg rebase -s9 -d0
360 rebasing 9:c5b12b67163a "D" (tip)
360 rebasing 9:c5b12b67163a "D" (tip)
361 saved backup bundle to $TESTTMP/a7/.hg/strip-backup/c5b12b67163a-4e372053-rebase.hg (glob)
361 saved backup bundle to $TESTTMP/a7/.hg/strip-backup/c5b12b67163a-4e372053-rebase.hg (glob)
362 $ hg log --template "{phase}\n" -r 9
362 $ hg log --template "{phase}\n" -r 9
363 secret
363 secret
364 $ hg rebase -s9 -d1
364 $ hg rebase -s9 -d1
365 rebasing 9:2a0524f868ac "D" (tip)
365 rebasing 9:2a0524f868ac "D" (tip)
366 saved backup bundle to $TESTTMP/a7/.hg/strip-backup/2a0524f868ac-cefd8574-rebase.hg (glob)
366 saved backup bundle to $TESTTMP/a7/.hg/strip-backup/2a0524f868ac-cefd8574-rebase.hg (glob)
367 $ hg log --template "{phase}\n" -r 9
367 $ hg log --template "{phase}\n" -r 9
368 secret
368 secret
369 Source phase lower than destination phase: new changeset get the phase of destination:
369 Source phase lower than destination phase: new changeset get the phase of destination:
370 $ hg rebase -s8 -d9
370 $ hg rebase -s8 -d9
371 rebasing 8:6d4f22462821 "C"
371 rebasing 8:6d4f22462821 "C"
372 saved backup bundle to $TESTTMP/a7/.hg/strip-backup/6d4f22462821-3441f70b-rebase.hg (glob)
372 saved backup bundle to $TESTTMP/a7/.hg/strip-backup/6d4f22462821-3441f70b-rebase.hg (glob)
373 $ hg log --template "{phase}\n" -r 'rev(9)'
373 $ hg log --template "{phase}\n" -r 'rev(9)'
374 secret
374 secret
375
375
376 $ cd ..
376 $ cd ..
377
377
378 Test for revset
378 Test for revset
379
379
380 We need a bit different graph
380 We need a bit different graph
381 All destination are B
381 All destination are B
382
382
383 $ hg init ah
383 $ hg init ah
384 $ cd ah
384 $ cd ah
385 $ hg unbundle "$TESTDIR/bundles/rebase-revset.hg"
385 $ hg unbundle "$TESTDIR/bundles/rebase-revset.hg"
386 adding changesets
386 adding changesets
387 adding manifests
387 adding manifests
388 adding file changes
388 adding file changes
389 added 9 changesets with 9 changes to 9 files (+2 heads)
389 added 9 changesets with 9 changes to 9 files (+2 heads)
390 (run 'hg heads' to see heads, 'hg merge' to merge)
390 (run 'hg heads' to see heads, 'hg merge' to merge)
391 $ hg tglog
391 $ hg tglog
392 o 8: 'I'
392 o 8: 'I'
393 |
393 |
394 o 7: 'H'
394 o 7: 'H'
395 |
395 |
396 o 6: 'G'
396 o 6: 'G'
397 |
397 |
398 | o 5: 'F'
398 | o 5: 'F'
399 | |
399 | |
400 | o 4: 'E'
400 | o 4: 'E'
401 |/
401 |/
402 o 3: 'D'
402 o 3: 'D'
403 |
403 |
404 o 2: 'C'
404 o 2: 'C'
405 |
405 |
406 | o 1: 'B'
406 | o 1: 'B'
407 |/
407 |/
408 o 0: 'A'
408 o 0: 'A'
409
409
410 $ cd ..
410 $ cd ..
411
411
412
412
413 Simple case with keep:
413 Simple case with keep:
414
414
415 Source on have two descendant heads but ask for one
415 Source on have two descendant heads but ask for one
416
416
417 $ hg clone -q -u . ah ah1
417 $ hg clone -q -u . ah ah1
418 $ cd ah1
418 $ cd ah1
419 $ hg rebase -r '2::8' -d 1
419 $ hg rebase -r '2::8' -d 1
420 abort: can't remove original changesets with unrebased descendants
420 abort: can't remove original changesets with unrebased descendants
421 (use --keep to keep original changesets)
421 (use --keep to keep original changesets)
422 [255]
422 [255]
423 $ hg rebase -r '2::8' -d 1 -k
423 $ hg rebase -r '2::8' -d 1 -k
424 rebasing 2:c9e50f6cdc55 "C"
424 rebasing 2:c9e50f6cdc55 "C"
425 rebasing 3:ffd453c31098 "D"
425 rebasing 3:ffd453c31098 "D"
426 rebasing 6:3d8a618087a7 "G"
426 rebasing 6:3d8a618087a7 "G"
427 rebasing 7:72434a4e60b0 "H"
427 rebasing 7:72434a4e60b0 "H"
428 rebasing 8:479ddb54a924 "I" (tip)
428 rebasing 8:479ddb54a924 "I" (tip)
429 $ hg tglog
429 $ hg tglog
430 o 13: 'I'
430 o 13: 'I'
431 |
431 |
432 o 12: 'H'
432 o 12: 'H'
433 |
433 |
434 o 11: 'G'
434 o 11: 'G'
435 |
435 |
436 o 10: 'D'
436 o 10: 'D'
437 |
437 |
438 o 9: 'C'
438 o 9: 'C'
439 |
439 |
440 | o 8: 'I'
440 | o 8: 'I'
441 | |
441 | |
442 | o 7: 'H'
442 | o 7: 'H'
443 | |
443 | |
444 | o 6: 'G'
444 | o 6: 'G'
445 | |
445 | |
446 | | o 5: 'F'
446 | | o 5: 'F'
447 | | |
447 | | |
448 | | o 4: 'E'
448 | | o 4: 'E'
449 | |/
449 | |/
450 | o 3: 'D'
450 | o 3: 'D'
451 | |
451 | |
452 | o 2: 'C'
452 | o 2: 'C'
453 | |
453 | |
454 o | 1: 'B'
454 o | 1: 'B'
455 |/
455 |/
456 o 0: 'A'
456 o 0: 'A'
457
457
458
458
459 $ cd ..
459 $ cd ..
460
460
461 Base on have one descendant heads we ask for but common ancestor have two
461 Base on have one descendant heads we ask for but common ancestor have two
462
462
463 $ hg clone -q -u . ah ah2
463 $ hg clone -q -u . ah ah2
464 $ cd ah2
464 $ cd ah2
465 $ hg rebase -r '3::8' -d 1
465 $ hg rebase -r '3::8' -d 1
466 abort: can't remove original changesets with unrebased descendants
466 abort: can't remove original changesets with unrebased descendants
467 (use --keep to keep original changesets)
467 (use --keep to keep original changesets)
468 [255]
468 [255]
469 $ hg rebase -r '3::8' -d 1 --keep
469 $ hg rebase -r '3::8' -d 1 --keep
470 rebasing 3:ffd453c31098 "D"
470 rebasing 3:ffd453c31098 "D"
471 rebasing 6:3d8a618087a7 "G"
471 rebasing 6:3d8a618087a7 "G"
472 rebasing 7:72434a4e60b0 "H"
472 rebasing 7:72434a4e60b0 "H"
473 rebasing 8:479ddb54a924 "I" (tip)
473 rebasing 8:479ddb54a924 "I" (tip)
474 $ hg tglog
474 $ hg tglog
475 o 12: 'I'
475 o 12: 'I'
476 |
476 |
477 o 11: 'H'
477 o 11: 'H'
478 |
478 |
479 o 10: 'G'
479 o 10: 'G'
480 |
480 |
481 o 9: 'D'
481 o 9: 'D'
482 |
482 |
483 | o 8: 'I'
483 | o 8: 'I'
484 | |
484 | |
485 | o 7: 'H'
485 | o 7: 'H'
486 | |
486 | |
487 | o 6: 'G'
487 | o 6: 'G'
488 | |
488 | |
489 | | o 5: 'F'
489 | | o 5: 'F'
490 | | |
490 | | |
491 | | o 4: 'E'
491 | | o 4: 'E'
492 | |/
492 | |/
493 | o 3: 'D'
493 | o 3: 'D'
494 | |
494 | |
495 | o 2: 'C'
495 | o 2: 'C'
496 | |
496 | |
497 o | 1: 'B'
497 o | 1: 'B'
498 |/
498 |/
499 o 0: 'A'
499 o 0: 'A'
500
500
501
501
502 $ cd ..
502 $ cd ..
503
503
504 rebase subset
504 rebase subset
505
505
506 $ hg clone -q -u . ah ah3
506 $ hg clone -q -u . ah ah3
507 $ cd ah3
507 $ cd ah3
508 $ hg rebase -r '3::7' -d 1
508 $ hg rebase -r '3::7' -d 1
509 abort: can't remove original changesets with unrebased descendants
509 abort: can't remove original changesets with unrebased descendants
510 (use --keep to keep original changesets)
510 (use --keep to keep original changesets)
511 [255]
511 [255]
512 $ hg rebase -r '3::7' -d 1 --keep
512 $ hg rebase -r '3::7' -d 1 --keep
513 rebasing 3:ffd453c31098 "D"
513 rebasing 3:ffd453c31098 "D"
514 rebasing 6:3d8a618087a7 "G"
514 rebasing 6:3d8a618087a7 "G"
515 rebasing 7:72434a4e60b0 "H"
515 rebasing 7:72434a4e60b0 "H"
516 $ hg tglog
516 $ hg tglog
517 o 11: 'H'
517 o 11: 'H'
518 |
518 |
519 o 10: 'G'
519 o 10: 'G'
520 |
520 |
521 o 9: 'D'
521 o 9: 'D'
522 |
522 |
523 | o 8: 'I'
523 | o 8: 'I'
524 | |
524 | |
525 | o 7: 'H'
525 | o 7: 'H'
526 | |
526 | |
527 | o 6: 'G'
527 | o 6: 'G'
528 | |
528 | |
529 | | o 5: 'F'
529 | | o 5: 'F'
530 | | |
530 | | |
531 | | o 4: 'E'
531 | | o 4: 'E'
532 | |/
532 | |/
533 | o 3: 'D'
533 | o 3: 'D'
534 | |
534 | |
535 | o 2: 'C'
535 | o 2: 'C'
536 | |
536 | |
537 o | 1: 'B'
537 o | 1: 'B'
538 |/
538 |/
539 o 0: 'A'
539 o 0: 'A'
540
540
541
541
542 $ cd ..
542 $ cd ..
543
543
544 rebase subset with multiple head
544 rebase subset with multiple head
545
545
546 $ hg clone -q -u . ah ah4
546 $ hg clone -q -u . ah ah4
547 $ cd ah4
547 $ cd ah4
548 $ hg rebase -r '3::(7+5)' -d 1
548 $ hg rebase -r '3::(7+5)' -d 1
549 abort: can't remove original changesets with unrebased descendants
549 abort: can't remove original changesets with unrebased descendants
550 (use --keep to keep original changesets)
550 (use --keep to keep original changesets)
551 [255]
551 [255]
552 $ hg rebase -r '3::(7+5)' -d 1 --keep
552 $ hg rebase -r '3::(7+5)' -d 1 --keep
553 rebasing 3:ffd453c31098 "D"
553 rebasing 3:ffd453c31098 "D"
554 rebasing 4:c01897464e7f "E"
554 rebasing 4:c01897464e7f "E"
555 rebasing 5:41bfcc75ed73 "F"
555 rebasing 5:41bfcc75ed73 "F"
556 rebasing 6:3d8a618087a7 "G"
556 rebasing 6:3d8a618087a7 "G"
557 rebasing 7:72434a4e60b0 "H"
557 rebasing 7:72434a4e60b0 "H"
558 $ hg tglog
558 $ hg tglog
559 o 13: 'H'
559 o 13: 'H'
560 |
560 |
561 o 12: 'G'
561 o 12: 'G'
562 |
562 |
563 | o 11: 'F'
563 | o 11: 'F'
564 | |
564 | |
565 | o 10: 'E'
565 | o 10: 'E'
566 |/
566 |/
567 o 9: 'D'
567 o 9: 'D'
568 |
568 |
569 | o 8: 'I'
569 | o 8: 'I'
570 | |
570 | |
571 | o 7: 'H'
571 | o 7: 'H'
572 | |
572 | |
573 | o 6: 'G'
573 | o 6: 'G'
574 | |
574 | |
575 | | o 5: 'F'
575 | | o 5: 'F'
576 | | |
576 | | |
577 | | o 4: 'E'
577 | | o 4: 'E'
578 | |/
578 | |/
579 | o 3: 'D'
579 | o 3: 'D'
580 | |
580 | |
581 | o 2: 'C'
581 | o 2: 'C'
582 | |
582 | |
583 o | 1: 'B'
583 o | 1: 'B'
584 |/
584 |/
585 o 0: 'A'
585 o 0: 'A'
586
586
587
587
588 $ cd ..
588 $ cd ..
589
589
590 More advanced tests
590 More advanced tests
591
591
592 rebase on ancestor with revset
592 rebase on ancestor with revset
593
593
594 $ hg clone -q -u . ah ah5
594 $ hg clone -q -u . ah ah5
595 $ cd ah5
595 $ cd ah5
596 $ hg rebase -r '6::' -d 2
596 $ hg rebase -r '6::' -d 2
597 rebasing 6:3d8a618087a7 "G"
597 rebasing 6:3d8a618087a7 "G"
598 rebasing 7:72434a4e60b0 "H"
598 rebasing 7:72434a4e60b0 "H"
599 rebasing 8:479ddb54a924 "I" (tip)
599 rebasing 8:479ddb54a924 "I" (tip)
600 saved backup bundle to $TESTTMP/ah5/.hg/strip-backup/3d8a618087a7-b4f73f31-rebase.hg (glob)
600 saved backup bundle to $TESTTMP/ah5/.hg/strip-backup/3d8a618087a7-b4f73f31-rebase.hg (glob)
601 $ hg tglog
601 $ hg tglog
602 o 8: 'I'
602 o 8: 'I'
603 |
603 |
604 o 7: 'H'
604 o 7: 'H'
605 |
605 |
606 o 6: 'G'
606 o 6: 'G'
607 |
607 |
608 | o 5: 'F'
608 | o 5: 'F'
609 | |
609 | |
610 | o 4: 'E'
610 | o 4: 'E'
611 | |
611 | |
612 | o 3: 'D'
612 | o 3: 'D'
613 |/
613 |/
614 o 2: 'C'
614 o 2: 'C'
615 |
615 |
616 | o 1: 'B'
616 | o 1: 'B'
617 |/
617 |/
618 o 0: 'A'
618 o 0: 'A'
619
619
620 $ cd ..
620 $ cd ..
621
621
622
622
623 rebase with multiple root.
623 rebase with multiple root.
624 We rebase E and G on B
624 We rebase E and G on B
625 We would expect heads are I, F if it was supported
625 We would expect heads are I, F if it was supported
626
626
627 $ hg clone -q -u . ah ah6
627 $ hg clone -q -u . ah ah6
628 $ cd ah6
628 $ cd ah6
629 $ hg rebase -r '(4+6)::' -d 1
629 $ hg rebase -r '(4+6)::' -d 1
630 rebasing 4:c01897464e7f "E"
630 rebasing 4:c01897464e7f "E"
631 rebasing 5:41bfcc75ed73 "F"
631 rebasing 5:41bfcc75ed73 "F"
632 rebasing 6:3d8a618087a7 "G"
632 rebasing 6:3d8a618087a7 "G"
633 rebasing 7:72434a4e60b0 "H"
633 rebasing 7:72434a4e60b0 "H"
634 rebasing 8:479ddb54a924 "I" (tip)
634 rebasing 8:479ddb54a924 "I" (tip)
635 saved backup bundle to $TESTTMP/ah6/.hg/strip-backup/3d8a618087a7-aae93a24-rebase.hg (glob)
635 saved backup bundle to $TESTTMP/ah6/.hg/strip-backup/3d8a618087a7-aae93a24-rebase.hg (glob)
636 $ hg tglog
636 $ hg tglog
637 o 8: 'I'
637 o 8: 'I'
638 |
638 |
639 o 7: 'H'
639 o 7: 'H'
640 |
640 |
641 o 6: 'G'
641 o 6: 'G'
642 |
642 |
643 | o 5: 'F'
643 | o 5: 'F'
644 | |
644 | |
645 | o 4: 'E'
645 | o 4: 'E'
646 |/
646 |/
647 | o 3: 'D'
647 | o 3: 'D'
648 | |
648 | |
649 | o 2: 'C'
649 | o 2: 'C'
650 | |
650 | |
651 o | 1: 'B'
651 o | 1: 'B'
652 |/
652 |/
653 o 0: 'A'
653 o 0: 'A'
654
654
655 $ cd ..
655 $ cd ..
656
656
657 More complex rebase with multiple roots
657 More complex rebase with multiple roots
658 each root have a different common ancestor with the destination and this is a detach
658 each root have a different common ancestor with the destination and this is a detach
659
659
660 (setup)
660 (setup)
661
661
662 $ hg clone -q -u . a a8
662 $ hg clone -q -u . a a8
663 $ cd a8
663 $ cd a8
664 $ echo I > I
664 $ echo I > I
665 $ hg add I
665 $ hg add I
666 $ hg commit -m I
666 $ hg commit -m I
667 $ hg up 4
667 $ hg up 4
668 1 files updated, 0 files merged, 3 files removed, 0 files unresolved
668 1 files updated, 0 files merged, 3 files removed, 0 files unresolved
669 $ echo I > J
669 $ echo I > J
670 $ hg add J
670 $ hg add J
671 $ hg commit -m J
671 $ hg commit -m J
672 created new head
672 created new head
673 $ echo I > K
673 $ echo I > K
674 $ hg add K
674 $ hg add K
675 $ hg commit -m K
675 $ hg commit -m K
676 $ hg tglog
676 $ hg tglog
677 @ 10: 'K'
677 @ 10: 'K'
678 |
678 |
679 o 9: 'J'
679 o 9: 'J'
680 |
680 |
681 | o 8: 'I'
681 | o 8: 'I'
682 | |
682 | |
683 | o 7: 'H'
683 | o 7: 'H'
684 | |
684 | |
685 +---o 6: 'G'
685 +---o 6: 'G'
686 | |/
686 | |/
687 | o 5: 'F'
687 | o 5: 'F'
688 | |
688 | |
689 o | 4: 'E'
689 o | 4: 'E'
690 |/
690 |/
691 | o 3: 'D'
691 | o 3: 'D'
692 | |
692 | |
693 | o 2: 'C'
693 | o 2: 'C'
694 | |
694 | |
695 | o 1: 'B'
695 | o 1: 'B'
696 |/
696 |/
697 o 0: 'A'
697 o 0: 'A'
698
698
699 (actual test)
699 (actual test)
700
700
701 $ hg rebase --dest 'desc(G)' --rev 'desc(K) + desc(I)'
701 $ hg rebase --dest 'desc(G)' --rev 'desc(K) + desc(I)'
702 rebasing 8:e7ec4e813ba6 "I"
702 rebasing 8:e7ec4e813ba6 "I"
703 rebasing 10:23a4ace37988 "K" (tip)
703 rebasing 10:23a4ace37988 "K" (tip)
704 saved backup bundle to $TESTTMP/a8/.hg/strip-backup/23a4ace37988-b06984b3-rebase.hg (glob)
704 saved backup bundle to $TESTTMP/a8/.hg/strip-backup/23a4ace37988-b06984b3-rebase.hg (glob)
705 $ hg log --rev 'children(desc(G))'
705 $ hg log --rev 'children(desc(G))'
706 changeset: 9:adb617877056
706 changeset: 9:adb617877056
707 parent: 6:eea13746799a
707 parent: 6:eea13746799a
708 user: test
708 user: test
709 date: Thu Jan 01 00:00:00 1970 +0000
709 date: Thu Jan 01 00:00:00 1970 +0000
710 summary: I
710 summary: I
711
711
712 changeset: 10:882431a34a0e
712 changeset: 10:882431a34a0e
713 tag: tip
713 tag: tip
714 parent: 6:eea13746799a
714 parent: 6:eea13746799a
715 user: test
715 user: test
716 date: Thu Jan 01 00:00:00 1970 +0000
716 date: Thu Jan 01 00:00:00 1970 +0000
717 summary: K
717 summary: K
718
718
719 $ hg tglog
719 $ hg tglog
720 @ 10: 'K'
720 @ 10: 'K'
721 |
721 |
722 | o 9: 'I'
722 | o 9: 'I'
723 |/
723 |/
724 | o 8: 'J'
724 | o 8: 'J'
725 | |
725 | |
726 | | o 7: 'H'
726 | | o 7: 'H'
727 | | |
727 | | |
728 o---+ 6: 'G'
728 o---+ 6: 'G'
729 |/ /
729 |/ /
730 | o 5: 'F'
730 | o 5: 'F'
731 | |
731 | |
732 o | 4: 'E'
732 o | 4: 'E'
733 |/
733 |/
734 | o 3: 'D'
734 | o 3: 'D'
735 | |
735 | |
736 | o 2: 'C'
736 | o 2: 'C'
737 | |
737 | |
738 | o 1: 'B'
738 | o 1: 'B'
739 |/
739 |/
740 o 0: 'A'
740 o 0: 'A'
741
741
742
742
743 Test that rebase is not confused by $CWD disappearing during rebase (issue4121)
743 Test that rebase is not confused by $CWD disappearing during rebase (issue4121)
744
744
745 $ cd ..
745 $ cd ..
746 $ hg init cwd-vanish
746 $ hg init cwd-vanish
747 $ cd cwd-vanish
747 $ cd cwd-vanish
748 $ touch initial-file
748 $ touch initial-file
749 $ hg add initial-file
749 $ hg add initial-file
750 $ hg commit -m 'initial commit'
750 $ hg commit -m 'initial commit'
751 $ touch dest-file
751 $ touch dest-file
752 $ hg add dest-file
752 $ hg add dest-file
753 $ hg commit -m 'dest commit'
753 $ hg commit -m 'dest commit'
754 $ hg up 0
754 $ hg up 0
755 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
755 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
756 $ touch other-file
756 $ touch other-file
757 $ hg add other-file
757 $ hg add other-file
758 $ hg commit -m 'first source commit'
758 $ hg commit -m 'first source commit'
759 created new head
759 created new head
760 $ mkdir subdir
760 $ mkdir subdir
761 $ cd subdir
761 $ cd subdir
762 $ touch subfile
762 $ touch subfile
763 $ hg add subfile
763 $ hg add subfile
764 $ hg commit -m 'second source with subdir'
764 $ hg commit -m 'second source with subdir'
765
765
766 $ hg rebase -b . -d 1 --traceback
766 $ hg rebase -b . -d 1 --traceback
767 rebasing 2:779a07b1b7a0 "first source commit"
767 rebasing 2:779a07b1b7a0 "first source commit"
768 current directory was removed (rmcwd !)
768 current directory was removed (rmcwd !)
769 (consider changing to repo root: $TESTTMP/cwd-vanish) (rmcwd !)
769 (consider changing to repo root: $TESTTMP/cwd-vanish) (rmcwd !)
770 rebasing 3:a7d6f3a00bf3 "second source with subdir" (tip)
770 rebasing 3:a7d6f3a00bf3 "second source with subdir" (tip)
771 saved backup bundle to $TESTTMP/cwd-vanish/.hg/strip-backup/779a07b1b7a0-853e0073-rebase.hg (glob)
771 saved backup bundle to $TESTTMP/cwd-vanish/.hg/strip-backup/779a07b1b7a0-853e0073-rebase.hg (glob)
772
772
773 Get back to the root of cwd-vanish. Note that even though `cd ..`
773 Get back to the root of cwd-vanish. Note that even though `cd ..`
774 works on most systems, it does not work on FreeBSD 10, so we use an
774 works on most systems, it does not work on FreeBSD 10, so we use an
775 absolute path to get back to the repository.
775 absolute path to get back to the repository.
776 $ cd $TESTTMP
776 $ cd $TESTTMP
777
777
778 Test that rebase is done in topo order (issue5370)
778 Test that rebase is done in topo order (issue5370)
779
779
780 $ hg init order
780 $ hg init order
781 $ cd order
781 $ cd order
782 $ touch a && hg add a && hg ci -m A
782 $ touch a && hg add a && hg ci -m A
783 $ touch b && hg add b && hg ci -m B
783 $ touch b && hg add b && hg ci -m B
784 $ touch c && hg add c && hg ci -m C
784 $ touch c && hg add c && hg ci -m C
785 $ hg up 1
785 $ hg up 1
786 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
786 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
787 $ touch d && hg add d && hg ci -m D
787 $ touch d && hg add d && hg ci -m D
788 created new head
788 created new head
789 $ hg up 2
789 $ hg up 2
790 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
790 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
791 $ touch e && hg add e && hg ci -m E
791 $ touch e && hg add e && hg ci -m E
792 $ hg up 3
792 $ hg up 3
793 1 files updated, 0 files merged, 2 files removed, 0 files unresolved
793 1 files updated, 0 files merged, 2 files removed, 0 files unresolved
794 $ touch f && hg add f && hg ci -m F
794 $ touch f && hg add f && hg ci -m F
795 $ hg up 0
795 $ hg up 0
796 0 files updated, 0 files merged, 3 files removed, 0 files unresolved
796 0 files updated, 0 files merged, 3 files removed, 0 files unresolved
797 $ touch g && hg add g && hg ci -m G
797 $ touch g && hg add g && hg ci -m G
798 created new head
798 created new head
799
799
800 $ hg tglog
800 $ hg tglog
801 @ 6: 'G'
801 @ 6: 'G'
802 |
802 |
803 | o 5: 'F'
803 | o 5: 'F'
804 | |
804 | |
805 | | o 4: 'E'
805 | | o 4: 'E'
806 | | |
806 | | |
807 | o | 3: 'D'
807 | o | 3: 'D'
808 | | |
808 | | |
809 | | o 2: 'C'
809 | | o 2: 'C'
810 | |/
810 | |/
811 | o 1: 'B'
811 | o 1: 'B'
812 |/
812 |/
813 o 0: 'A'
813 o 0: 'A'
814
814
815
815
816 $ hg rebase -s 1 -d 6
816 $ hg rebase -s 1 -d 6
817 rebasing 1:76035bbd54bd "B"
817 rebasing 1:76035bbd54bd "B"
818 rebasing 2:d84f5cfaaf14 "C"
818 rebasing 2:d84f5cfaaf14 "C"
819 rebasing 4:82ae8dc7a9b7 "E"
819 rebasing 4:82ae8dc7a9b7 "E"
820 rebasing 3:ab709c9f7171 "D"
820 rebasing 3:ab709c9f7171 "D"
821 rebasing 5:412b391de760 "F"
821 rebasing 5:412b391de760 "F"
822 saved backup bundle to $TESTTMP/order/.hg/strip-backup/76035bbd54bd-e341bc99-rebase.hg (glob)
822 saved backup bundle to $TESTTMP/order/.hg/strip-backup/76035bbd54bd-e341bc99-rebase.hg (glob)
823
823
824 $ hg tglog
824 $ hg tglog
825 o 6: 'F'
825 o 6: 'F'
826 |
826 |
827 o 5: 'D'
827 o 5: 'D'
828 |
828 |
829 | o 4: 'E'
829 | o 4: 'E'
830 | |
830 | |
831 | o 3: 'C'
831 | o 3: 'C'
832 |/
832 |/
833 o 2: 'B'
833 o 2: 'B'
834 |
834 |
835 @ 1: 'G'
835 @ 1: 'G'
836 |
836 |
837 o 0: 'A'
837 o 0: 'A'
838
838
839
839
840 Test experimental revset
840 Test experimental revset
841 ========================
841 ========================
842
842
843 $ cd ../cwd-vanish
843 $ cd ../cwd-vanish
844
844
845 Make the repo a bit more interesting
845 Make the repo a bit more interesting
846
846
847 $ hg up 1
847 $ hg up 1
848 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
848 0 files updated, 0 files merged, 2 files removed, 0 files unresolved
849 $ echo aaa > aaa
849 $ echo aaa > aaa
850 $ hg add aaa
850 $ hg add aaa
851 $ hg commit -m aaa
851 $ hg commit -m aaa
852 created new head
852 created new head
853 $ hg log -G
853 $ hg log -G
854 @ changeset: 4:5f7bc9025ed2
854 @ changeset: 4:5f7bc9025ed2
855 | tag: tip
855 | tag: tip
856 | parent: 1:58d79cc1cf43
856 | parent: 1:58d79cc1cf43
857 | user: test
857 | user: test
858 | date: Thu Jan 01 00:00:00 1970 +0000
858 | date: Thu Jan 01 00:00:00 1970 +0000
859 | summary: aaa
859 | summary: aaa
860 |
860 |
861 | o changeset: 3:1910d5ff34ea
861 | o changeset: 3:1910d5ff34ea
862 | | user: test
862 | | user: test
863 | | date: Thu Jan 01 00:00:00 1970 +0000
863 | | date: Thu Jan 01 00:00:00 1970 +0000
864 | | summary: second source with subdir
864 | | summary: second source with subdir
865 | |
865 | |
866 | o changeset: 2:82901330b6ef
866 | o changeset: 2:82901330b6ef
867 |/ user: test
867 |/ user: test
868 | date: Thu Jan 01 00:00:00 1970 +0000
868 | date: Thu Jan 01 00:00:00 1970 +0000
869 | summary: first source commit
869 | summary: first source commit
870 |
870 |
871 o changeset: 1:58d79cc1cf43
871 o changeset: 1:58d79cc1cf43
872 | user: test
872 | user: test
873 | date: Thu Jan 01 00:00:00 1970 +0000
873 | date: Thu Jan 01 00:00:00 1970 +0000
874 | summary: dest commit
874 | summary: dest commit
875 |
875 |
876 o changeset: 0:e94b687f7da3
876 o changeset: 0:e94b687f7da3
877 user: test
877 user: test
878 date: Thu Jan 01 00:00:00 1970 +0000
878 date: Thu Jan 01 00:00:00 1970 +0000
879 summary: initial commit
879 summary: initial commit
880
880
881
881
882 Testing from lower head
882 Testing from lower head
883
883
884 $ hg up 3
884 $ hg up 3
885 2 files updated, 0 files merged, 1 files removed, 0 files unresolved
885 2 files updated, 0 files merged, 1 files removed, 0 files unresolved
886 $ hg log -r '_destrebase()'
886 $ hg log -r '_destrebase()'
887 changeset: 4:5f7bc9025ed2
887 changeset: 4:5f7bc9025ed2
888 tag: tip
888 tag: tip
889 parent: 1:58d79cc1cf43
889 parent: 1:58d79cc1cf43
890 user: test
890 user: test
891 date: Thu Jan 01 00:00:00 1970 +0000
891 date: Thu Jan 01 00:00:00 1970 +0000
892 summary: aaa
892 summary: aaa
893
893
894
894
895 Testing from upper head
895 Testing from upper head
896
896
897 $ hg log -r '_destrebase(4)'
897 $ hg log -r '_destrebase(4)'
898 changeset: 3:1910d5ff34ea
898 changeset: 3:1910d5ff34ea
899 user: test
899 user: test
900 date: Thu Jan 01 00:00:00 1970 +0000
900 date: Thu Jan 01 00:00:00 1970 +0000
901 summary: second source with subdir
901 summary: second source with subdir
902
902
903 $ hg up 4
903 $ hg up 4
904 1 files updated, 0 files merged, 2 files removed, 0 files unresolved
904 1 files updated, 0 files merged, 2 files removed, 0 files unresolved
905 $ hg log -r '_destrebase()'
905 $ hg log -r '_destrebase()'
906 changeset: 3:1910d5ff34ea
906 changeset: 3:1910d5ff34ea
907 user: test
907 user: test
908 date: Thu Jan 01 00:00:00 1970 +0000
908 date: Thu Jan 01 00:00:00 1970 +0000
909 summary: second source with subdir
909 summary: second source with subdir
910
910
911 Testing rebase being called inside another transaction
911 Testing rebase being called inside another transaction
912
912
913 $ cd $TESTTMP
913 $ cd $TESTTMP
914 $ hg init tr-state
914 $ hg init tr-state
915 $ cd tr-state
915 $ cd tr-state
916 $ cat > $TESTTMP/wraprebase.py <<EOF
916 $ cat > $TESTTMP/wraprebase.py <<EOF
917 > from __future__ import absolute_import
917 > from __future__ import absolute_import
918 > from mercurial import extensions
918 > from mercurial import extensions
919 > def _rebase(orig, ui, repo, *args, **kwargs):
919 > def _rebase(orig, ui, repo, *args, **kwargs):
920 > with repo.wlock():
920 > with repo.wlock():
921 > with repo.lock():
921 > with repo.lock():
922 > with repo.transaction('wrappedrebase'):
922 > with repo.transaction('wrappedrebase'):
923 > return orig(ui, repo, *args, **kwargs)
923 > return orig(ui, repo, *args, **kwargs)
924 > def wraprebase(loaded):
924 > def wraprebase(loaded):
925 > assert loaded
925 > assert loaded
926 > rebasemod = extensions.find('rebase')
926 > rebasemod = extensions.find('rebase')
927 > extensions.wrapcommand(rebasemod.cmdtable, 'rebase', _rebase)
927 > extensions.wrapcommand(rebasemod.cmdtable, 'rebase', _rebase)
928 > def extsetup(ui):
928 > def extsetup(ui):
929 > extensions.afterloaded('rebase', wraprebase)
929 > extensions.afterloaded('rebase', wraprebase)
930 > EOF
930 > EOF
931
931
932 $ cat >> .hg/hgrc <<EOF
932 $ cat >> .hg/hgrc <<EOF
933 > [extensions]
933 > [extensions]
934 > wraprebase=$TESTTMP/wraprebase.py
934 > wraprebase=$TESTTMP/wraprebase.py
935 > [experimental]
935 > [experimental]
936 > stabilization=all
936 > stabilization=all
937 > EOF
937 > EOF
938
938
939 $ hg debugdrawdag <<'EOS'
939 $ hg debugdrawdag <<'EOS'
940 > B C
940 > B C
941 > |/
941 > |/
942 > A
942 > A
943 > EOS
943 > EOS
944
944
945 $ hg rebase -s C -d B
945 $ hg rebase -s C -d B
946 rebasing 2:dc0947a82db8 "C" (C tip)
946 rebasing 2:dc0947a82db8 "C" (C tip)
947
947
948 $ [ -f .hg/rebasestate ] && echo 'WRONG: rebasestate should not exist'
948 $ [ -f .hg/rebasestate ] && echo 'WRONG: rebasestate should not exist'
949 [1]
949 [1]
General Comments 0
You need to be logged in to leave comments. Login now