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