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