comparison hgext/rebase.py @ 43077:687b865b95ad

formatting: byteify all mercurial/ and hgext/ string literals Done with python3.7 contrib/byteify-strings.py -i $(hg files 'set:mercurial/**.py - mercurial/thirdparty/** + hgext/**.py - hgext/fsmonitor/pywatchman/** - mercurial/__init__.py') black -l 80 -t py33 -S $(hg files 'set:**.py - mercurial/thirdparty/** - "contrib/python-zstandard/**" - hgext/fsmonitor/pywatchman/**') # skip-blame mass-reformatting only Differential Revision: https://phab.mercurial-scm.org/D6972
author Augie Fackler <augie@google.com>
date Sun, 06 Oct 2019 09:48:39 -0400
parents 2372284d9457
children eef9a2d67051
comparison
equal deleted inserted replaced
43076:2372284d9457 43077:687b865b95ad
54 # The following constants are used throughout the rebase module. The ordering of 54 # The following constants are used throughout the rebase module. The ordering of
55 # their values must be maintained. 55 # their values must be maintained.
56 56
57 # Indicates that a revision needs to be rebased 57 # Indicates that a revision needs to be rebased
58 revtodo = -1 58 revtodo = -1
59 revtodostr = '-1' 59 revtodostr = b'-1'
60 60
61 # legacy revstates no longer needed in current code 61 # legacy revstates no longer needed in current code
62 # -2: nullmerge, -3: revignored, -4: revprecursor, -5: revpruned 62 # -2: nullmerge, -3: revignored, -4: revprecursor, -5: revpruned
63 legacystates = {'-2', '-3', '-4', '-5'} 63 legacystates = {b'-2', b'-3', b'-4', b'-5'}
64 64
65 cmdtable = {} 65 cmdtable = {}
66 command = registrar.command(cmdtable) 66 command = registrar.command(cmdtable)
67 # Note for extension authors: ONLY specify testedwith = 'ships-with-hg-core' for 67 # Note for extension authors: ONLY specify testedwith = 'ships-with-hg-core' for
68 # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should 68 # extensions which SHIP WITH MERCURIAL. Non-mainline extensions should
69 # be specifying the version(s) of Mercurial they are tested with, or 69 # be specifying the version(s) of Mercurial they are tested with, or
70 # leave the attribute unspecified. 70 # leave the attribute unspecified.
71 testedwith = 'ships-with-hg-core' 71 testedwith = b'ships-with-hg-core'
72 72
73 73
74 def _nothingtorebase(): 74 def _nothingtorebase():
75 return 1 75 return 1
76 76
77 77
78 def _savegraft(ctx, extra): 78 def _savegraft(ctx, extra):
79 s = ctx.extra().get('source', None) 79 s = ctx.extra().get(b'source', None)
80 if s is not None: 80 if s is not None:
81 extra['source'] = s 81 extra[b'source'] = s
82 s = ctx.extra().get('intermediate-source', None) 82 s = ctx.extra().get(b'intermediate-source', None)
83 if s is not None: 83 if s is not None:
84 extra['intermediate-source'] = s 84 extra[b'intermediate-source'] = s
85 85
86 86
87 def _savebranch(ctx, extra): 87 def _savebranch(ctx, extra):
88 extra['branch'] = ctx.branch() 88 extra[b'branch'] = ctx.branch()
89 89
90 90
91 def _destrebase(repo, sourceset, destspace=None): 91 def _destrebase(repo, sourceset, destspace=None):
92 """small wrapper around destmerge to pass the right extra args 92 """small wrapper around destmerge to pass the right extra args
93 93
94 Please wrap destutil.destmerge instead.""" 94 Please wrap destutil.destmerge instead."""
95 return destutil.destmerge( 95 return destutil.destmerge(
96 repo, 96 repo,
97 action='rebase', 97 action=b'rebase',
98 sourceset=sourceset, 98 sourceset=sourceset,
99 onheadcheck=False, 99 onheadcheck=False,
100 destspace=destspace, 100 destspace=destspace,
101 ) 101 )
102 102
103 103
104 revsetpredicate = registrar.revsetpredicate() 104 revsetpredicate = registrar.revsetpredicate()
105 105
106 106
107 @revsetpredicate('_destrebase') 107 @revsetpredicate(b'_destrebase')
108 def _revsetdestrebase(repo, subset, x): 108 def _revsetdestrebase(repo, subset, x):
109 # ``_rebasedefaultdest()`` 109 # ``_rebasedefaultdest()``
110 110
111 # default destination for rebase. 111 # default destination for rebase.
112 # # XXX: Currently private because I expect the signature to change. 112 # # XXX: Currently private because I expect the signature to change.
116 if x is not None: 116 if x is not None:
117 sourceset = revset.getset(repo, smartset.fullreposet(repo), x) 117 sourceset = revset.getset(repo, smartset.fullreposet(repo), x)
118 return subset & smartset.baseset([_destrebase(repo, sourceset)]) 118 return subset & smartset.baseset([_destrebase(repo, sourceset)])
119 119
120 120
121 @revsetpredicate('_destautoorphanrebase') 121 @revsetpredicate(b'_destautoorphanrebase')
122 def _revsetdestautoorphanrebase(repo, subset, x): 122 def _revsetdestautoorphanrebase(repo, subset, x):
123 # ``_destautoorphanrebase()`` 123 # ``_destautoorphanrebase()``
124 124
125 # automatic rebase destination for a single orphan revision. 125 # automatic rebase destination for a single orphan revision.
126 unfi = repo.unfiltered() 126 unfi = repo.unfiltered()
127 obsoleted = unfi.revs('obsolete()') 127 obsoleted = unfi.revs(b'obsolete()')
128 128
129 src = revset.getset(repo, subset, x).first() 129 src = revset.getset(repo, subset, x).first()
130 130
131 # Empty src or already obsoleted - Do not return a destination 131 # Empty src or already obsoleted - Do not return a destination
132 if not src or src in obsoleted: 132 if not src or src in obsoleted:
133 return smartset.baseset() 133 return smartset.baseset()
134 dests = destutil.orphanpossibledestination(repo, src) 134 dests = destutil.orphanpossibledestination(repo, src)
135 if len(dests) > 1: 135 if len(dests) > 1:
136 raise error.Abort( 136 raise error.Abort(
137 _("ambiguous automatic rebase: %r could end up on any of %r") 137 _(b"ambiguous automatic rebase: %r could end up on any of %r")
138 % (src, dests) 138 % (src, dests)
139 ) 139 )
140 # We have zero or one destination, so we can just return here. 140 # We have zero or one destination, so we can just return here.
141 return smartset.baseset(dests) 141 return smartset.baseset(dests)
142 142
143 143
144 def _ctxdesc(ctx): 144 def _ctxdesc(ctx):
145 """short description for a context""" 145 """short description for a context"""
146 desc = '%d:%s "%s"' % (ctx.rev(), ctx, ctx.description().split('\n', 1)[0]) 146 desc = b'%d:%s "%s"' % (
147 ctx.rev(),
148 ctx,
149 ctx.description().split(b'\n', 1)[0],
150 )
147 repo = ctx.repo() 151 repo = ctx.repo()
148 names = [] 152 names = []
149 for nsname, ns in repo.names.iteritems(): 153 for nsname, ns in repo.names.iteritems():
150 if nsname == 'branches': 154 if nsname == b'branches':
151 continue 155 continue
152 names.extend(ns.names(repo, ctx.node())) 156 names.extend(ns.names(repo, ctx.node()))
153 if names: 157 if names:
154 desc += ' (%s)' % ' '.join(names) 158 desc += b' (%s)' % b' '.join(names)
155 return desc 159 return desc
156 160
157 161
158 class rebaseruntime(object): 162 class rebaseruntime(object):
159 """This class is a container for rebase runtime state""" 163 """This class is a container for rebase runtime state"""
183 self.state = {} 187 self.state = {}
184 self.activebookmark = None 188 self.activebookmark = None
185 self.destmap = {} 189 self.destmap = {}
186 self.skipped = set() 190 self.skipped = set()
187 191
188 self.collapsef = opts.get('collapse', False) 192 self.collapsef = opts.get(b'collapse', False)
189 self.collapsemsg = cmdutil.logmessage(ui, opts) 193 self.collapsemsg = cmdutil.logmessage(ui, opts)
190 self.date = opts.get('date', None) 194 self.date = opts.get(b'date', None)
191 195
192 e = opts.get('extrafn') # internal, used by e.g. hgsubversion 196 e = opts.get(b'extrafn') # internal, used by e.g. hgsubversion
193 self.extrafns = [_savegraft] 197 self.extrafns = [_savegraft]
194 if e: 198 if e:
195 self.extrafns = [e] 199 self.extrafns = [e]
196 200
197 self.backupf = ui.configbool('rewrite', 'backup-bundle') 201 self.backupf = ui.configbool(b'rewrite', b'backup-bundle')
198 self.keepf = opts.get('keep', False) 202 self.keepf = opts.get(b'keep', False)
199 self.keepbranchesf = opts.get('keepbranches', False) 203 self.keepbranchesf = opts.get(b'keepbranches', False)
200 self.obsoletenotrebased = {} 204 self.obsoletenotrebased = {}
201 self.obsoletewithoutsuccessorindestination = set() 205 self.obsoletewithoutsuccessorindestination = set()
202 self.inmemory = inmemory 206 self.inmemory = inmemory
203 self.stateobj = statemod.cmdstate(repo, 'rebasestate') 207 self.stateobj = statemod.cmdstate(repo, b'rebasestate')
204 208
205 @property 209 @property
206 def repo(self): 210 def repo(self):
207 if self.prepared: 211 if self.prepared:
208 return self._repo.unfiltered() 212 return self._repo.unfiltered()
211 215
212 def storestatus(self, tr=None): 216 def storestatus(self, tr=None):
213 """Store the current status to allow recovery""" 217 """Store the current status to allow recovery"""
214 if tr: 218 if tr:
215 tr.addfilegenerator( 219 tr.addfilegenerator(
216 'rebasestate', 220 b'rebasestate',
217 ('rebasestate',), 221 (b'rebasestate',),
218 self._writestatus, 222 self._writestatus,
219 location='plain', 223 location=b'plain',
220 ) 224 )
221 else: 225 else:
222 with self.repo.vfs("rebasestate", "w") as f: 226 with self.repo.vfs(b"rebasestate", b"w") as f:
223 self._writestatus(f) 227 self._writestatus(f)
224 228
225 def _writestatus(self, f): 229 def _writestatus(self, f):
226 repo = self.repo 230 repo = self.repo
227 assert repo.filtername is None 231 assert repo.filtername is None
228 f.write(repo[self.originalwd].hex() + '\n') 232 f.write(repo[self.originalwd].hex() + b'\n')
229 # was "dest". we now write dest per src root below. 233 # was "dest". we now write dest per src root below.
230 f.write('\n') 234 f.write(b'\n')
231 f.write(repo[self.external].hex() + '\n') 235 f.write(repo[self.external].hex() + b'\n')
232 f.write('%d\n' % int(self.collapsef)) 236 f.write(b'%d\n' % int(self.collapsef))
233 f.write('%d\n' % int(self.keepf)) 237 f.write(b'%d\n' % int(self.keepf))
234 f.write('%d\n' % int(self.keepbranchesf)) 238 f.write(b'%d\n' % int(self.keepbranchesf))
235 f.write('%s\n' % (self.activebookmark or '')) 239 f.write(b'%s\n' % (self.activebookmark or b''))
236 destmap = self.destmap 240 destmap = self.destmap
237 for d, v in self.state.iteritems(): 241 for d, v in self.state.iteritems():
238 oldrev = repo[d].hex() 242 oldrev = repo[d].hex()
239 if v >= 0: 243 if v >= 0:
240 newrev = repo[v].hex() 244 newrev = repo[v].hex()
241 else: 245 else:
242 newrev = "%d" % v 246 newrev = b"%d" % v
243 destnode = repo[destmap[d]].hex() 247 destnode = repo[destmap[d]].hex()
244 f.write("%s:%s:%s\n" % (oldrev, newrev, destnode)) 248 f.write(b"%s:%s:%s\n" % (oldrev, newrev, destnode))
245 repo.ui.debug('rebase status stored\n') 249 repo.ui.debug(b'rebase status stored\n')
246 250
247 def restorestatus(self): 251 def restorestatus(self):
248 """Restore a previously stored status""" 252 """Restore a previously stored status"""
249 if not self.stateobj.exists(): 253 if not self.stateobj.exists():
250 cmdutil.wrongtooltocontinue(self.repo, _('rebase')) 254 cmdutil.wrongtooltocontinue(self.repo, _(b'rebase'))
251 255
252 data = self._read() 256 data = self._read()
253 self.repo.ui.debug('rebase status resumed\n') 257 self.repo.ui.debug(b'rebase status resumed\n')
254 258
255 self.originalwd = data['originalwd'] 259 self.originalwd = data[b'originalwd']
256 self.destmap = data['destmap'] 260 self.destmap = data[b'destmap']
257 self.state = data['state'] 261 self.state = data[b'state']
258 self.skipped = data['skipped'] 262 self.skipped = data[b'skipped']
259 self.collapsef = data['collapse'] 263 self.collapsef = data[b'collapse']
260 self.keepf = data['keep'] 264 self.keepf = data[b'keep']
261 self.keepbranchesf = data['keepbranches'] 265 self.keepbranchesf = data[b'keepbranches']
262 self.external = data['external'] 266 self.external = data[b'external']
263 self.activebookmark = data['activebookmark'] 267 self.activebookmark = data[b'activebookmark']
264 268
265 def _read(self): 269 def _read(self):
266 self.prepared = True 270 self.prepared = True
267 repo = self.repo 271 repo = self.repo
268 assert repo.filtername is None 272 assert repo.filtername is None
269 data = { 273 data = {
270 'keepbranches': None, 274 b'keepbranches': None,
271 'collapse': None, 275 b'collapse': None,
272 'activebookmark': None, 276 b'activebookmark': None,
273 'external': nullrev, 277 b'external': nullrev,
274 'keep': None, 278 b'keep': None,
275 'originalwd': None, 279 b'originalwd': None,
276 } 280 }
277 legacydest = None 281 legacydest = None
278 state = {} 282 state = {}
279 destmap = {} 283 destmap = {}
280 284
281 if True: 285 if True:
282 f = repo.vfs("rebasestate") 286 f = repo.vfs(b"rebasestate")
283 for i, l in enumerate(f.read().splitlines()): 287 for i, l in enumerate(f.read().splitlines()):
284 if i == 0: 288 if i == 0:
285 data['originalwd'] = repo[l].rev() 289 data[b'originalwd'] = repo[l].rev()
286 elif i == 1: 290 elif i == 1:
287 # this line should be empty in newer version. but legacy 291 # this line should be empty in newer version. but legacy
288 # clients may still use it 292 # clients may still use it
289 if l: 293 if l:
290 legacydest = repo[l].rev() 294 legacydest = repo[l].rev()
291 elif i == 2: 295 elif i == 2:
292 data['external'] = repo[l].rev() 296 data[b'external'] = repo[l].rev()
293 elif i == 3: 297 elif i == 3:
294 data['collapse'] = bool(int(l)) 298 data[b'collapse'] = bool(int(l))
295 elif i == 4: 299 elif i == 4:
296 data['keep'] = bool(int(l)) 300 data[b'keep'] = bool(int(l))
297 elif i == 5: 301 elif i == 5:
298 data['keepbranches'] = bool(int(l)) 302 data[b'keepbranches'] = bool(int(l))
299 elif i == 6 and not (len(l) == 81 and ':' in l): 303 elif i == 6 and not (len(l) == 81 and b':' in l):
300 # line 6 is a recent addition, so for backwards 304 # line 6 is a recent addition, so for backwards
301 # compatibility check that the line doesn't look like the 305 # compatibility check that the line doesn't look like the
302 # oldrev:newrev lines 306 # oldrev:newrev lines
303 data['activebookmark'] = l 307 data[b'activebookmark'] = l
304 else: 308 else:
305 args = l.split(':') 309 args = l.split(b':')
306 oldrev = repo[args[0]].rev() 310 oldrev = repo[args[0]].rev()
307 newrev = args[1] 311 newrev = args[1]
308 if newrev in legacystates: 312 if newrev in legacystates:
309 continue 313 continue
310 if len(args) > 2: 314 if len(args) > 2:
316 state[oldrev] = revtodo 320 state[oldrev] = revtodo
317 # Legacy compat special case 321 # Legacy compat special case
318 else: 322 else:
319 state[oldrev] = repo[newrev].rev() 323 state[oldrev] = repo[newrev].rev()
320 324
321 if data['keepbranches'] is None: 325 if data[b'keepbranches'] is None:
322 raise error.Abort(_('.hg/rebasestate is incomplete')) 326 raise error.Abort(_(b'.hg/rebasestate is incomplete'))
323 327
324 data['destmap'] = destmap 328 data[b'destmap'] = destmap
325 data['state'] = state 329 data[b'state'] = state
326 skipped = set() 330 skipped = set()
327 # recompute the set of skipped revs 331 # recompute the set of skipped revs
328 if not data['collapse']: 332 if not data[b'collapse']:
329 seen = set(destmap.values()) 333 seen = set(destmap.values())
330 for old, new in sorted(state.items()): 334 for old, new in sorted(state.items()):
331 if new != revtodo and new in seen: 335 if new != revtodo and new in seen:
332 skipped.add(old) 336 skipped.add(old)
333 seen.add(new) 337 seen.add(new)
334 data['skipped'] = skipped 338 data[b'skipped'] = skipped
335 repo.ui.debug( 339 repo.ui.debug(
336 'computed skipped revs: %s\n' 340 b'computed skipped revs: %s\n'
337 % (' '.join('%d' % r for r in sorted(skipped)) or '') 341 % (b' '.join(b'%d' % r for r in sorted(skipped)) or b'')
338 ) 342 )
339 343
340 return data 344 return data
341 345
342 def _handleskippingobsolete(self, obsoleterevs, destmap): 346 def _handleskippingobsolete(self, obsoleterevs, destmap):
344 348
345 obsoleterevs: iterable of all obsolete revisions in rebaseset 349 obsoleterevs: iterable of all obsolete revisions in rebaseset
346 destmap: {srcrev: destrev} destination revisions 350 destmap: {srcrev: destrev} destination revisions
347 """ 351 """
348 self.obsoletenotrebased = {} 352 self.obsoletenotrebased = {}
349 if not self.ui.configbool('experimental', 'rebaseskipobsolete'): 353 if not self.ui.configbool(b'experimental', b'rebaseskipobsolete'):
350 return 354 return
351 obsoleteset = set(obsoleterevs) 355 obsoleteset = set(obsoleterevs)
352 ( 356 (
353 self.obsoletenotrebased, 357 self.obsoletenotrebased,
354 self.obsoletewithoutsuccessorindestination, 358 self.obsoletewithoutsuccessorindestination,
367 if isabort: 371 if isabort:
368 clearstatus(self.repo) 372 clearstatus(self.repo)
369 clearcollapsemsg(self.repo) 373 clearcollapsemsg(self.repo)
370 self.repo.ui.warn( 374 self.repo.ui.warn(
371 _( 375 _(
372 'rebase aborted (no revision is removed,' 376 b'rebase aborted (no revision is removed,'
373 ' only broken state is cleared)\n' 377 b' only broken state is cleared)\n'
374 ) 378 )
375 ) 379 )
376 return 0 380 return 0
377 else: 381 else:
378 msg = _('cannot continue inconsistent rebase') 382 msg = _(b'cannot continue inconsistent rebase')
379 hint = _('use "hg rebase --abort" to clear broken state') 383 hint = _(b'use "hg rebase --abort" to clear broken state')
380 raise error.Abort(msg, hint=hint) 384 raise error.Abort(msg, hint=hint)
381 385
382 if isabort: 386 if isabort:
383 backup = backup and self.backupf 387 backup = backup and self.backupf
384 return self._abort(backup=backup, suppwarns=suppwarns) 388 return self._abort(backup=backup, suppwarns=suppwarns)
388 return _nothingtorebase() 392 return _nothingtorebase()
389 393
390 rebaseset = destmap.keys() 394 rebaseset = destmap.keys()
391 allowunstable = obsolete.isenabled(self.repo, obsolete.allowunstableopt) 395 allowunstable = obsolete.isenabled(self.repo, obsolete.allowunstableopt)
392 if not (self.keepf or allowunstable) and self.repo.revs( 396 if not (self.keepf or allowunstable) and self.repo.revs(
393 'first(children(%ld) - %ld)', rebaseset, rebaseset 397 b'first(children(%ld) - %ld)', rebaseset, rebaseset
394 ): 398 ):
395 raise error.Abort( 399 raise error.Abort(
396 _( 400 _(
397 "can't remove original changesets with" 401 b"can't remove original changesets with"
398 " unrebased descendants" 402 b" unrebased descendants"
399 ), 403 ),
400 hint=_('use --keep to keep original changesets'), 404 hint=_(b'use --keep to keep original changesets'),
401 ) 405 )
402 406
403 result = buildstate(self.repo, destmap, self.collapsef) 407 result = buildstate(self.repo, destmap, self.collapsef)
404 408
405 if not result: 409 if not result:
406 # Empty state built, nothing to rebase 410 # Empty state built, nothing to rebase
407 self.ui.status(_('nothing to rebase\n')) 411 self.ui.status(_(b'nothing to rebase\n'))
408 return _nothingtorebase() 412 return _nothingtorebase()
409 413
410 for root in self.repo.set('roots(%ld)', rebaseset): 414 for root in self.repo.set(b'roots(%ld)', rebaseset):
411 if not self.keepf and not root.mutable(): 415 if not self.keepf and not root.mutable():
412 raise error.Abort( 416 raise error.Abort(
413 _("can't rebase public changeset %s") % root, 417 _(b"can't rebase public changeset %s") % root,
414 hint=_("see 'hg help phases' for details"), 418 hint=_(b"see 'hg help phases' for details"),
415 ) 419 )
416 420
417 (self.originalwd, self.destmap, self.state) = result 421 (self.originalwd, self.destmap, self.state) = result
418 if self.collapsef: 422 if self.collapsef:
419 dests = set(self.destmap.values()) 423 dests = set(self.destmap.values())
420 if len(dests) != 1: 424 if len(dests) != 1:
421 raise error.Abort( 425 raise error.Abort(
422 _('--collapse does not work with multiple destinations') 426 _(b'--collapse does not work with multiple destinations')
423 ) 427 )
424 destrev = next(iter(dests)) 428 destrev = next(iter(dests))
425 destancestors = self.repo.changelog.ancestors( 429 destancestors = self.repo.changelog.ancestors(
426 [destrev], inclusive=True 430 [destrev], inclusive=True
427 ) 431 )
428 self.external = externalparent(self.repo, self.state, destancestors) 432 self.external = externalparent(self.repo, self.state, destancestors)
429 433
430 for destrev in sorted(set(destmap.values())): 434 for destrev in sorted(set(destmap.values())):
431 dest = self.repo[destrev] 435 dest = self.repo[destrev]
432 if dest.closesbranch() and not self.keepbranchesf: 436 if dest.closesbranch() and not self.keepbranchesf:
433 self.ui.status(_('reopening closed branch head %s\n') % dest) 437 self.ui.status(_(b'reopening closed branch head %s\n') % dest)
434 438
435 self.prepared = True 439 self.prepared = True
436 440
437 def _assignworkingcopy(self): 441 def _assignworkingcopy(self):
438 if self.inmemory: 442 if self.inmemory:
439 from mercurial.context import overlayworkingctx 443 from mercurial.context import overlayworkingctx
440 444
441 self.wctx = overlayworkingctx(self.repo) 445 self.wctx = overlayworkingctx(self.repo)
442 self.repo.ui.debug("rebasing in-memory\n") 446 self.repo.ui.debug(b"rebasing in-memory\n")
443 else: 447 else:
444 self.wctx = self.repo[None] 448 self.wctx = self.repo[None]
445 self.repo.ui.debug("rebasing on disk\n") 449 self.repo.ui.debug(b"rebasing on disk\n")
446 self.repo.ui.log( 450 self.repo.ui.log(
447 "rebase", 451 b"rebase",
448 "using in-memory rebase: %r\n", 452 b"using in-memory rebase: %r\n",
449 self.inmemory, 453 self.inmemory,
450 rebase_imm_used=self.inmemory, 454 rebase_imm_used=self.inmemory,
451 ) 455 )
452 456
453 def _performrebase(self, tr): 457 def _performrebase(self, tr):
462 branches = set() 466 branches = set()
463 for rev in self.state: 467 for rev in self.state:
464 branches.add(repo[rev].branch()) 468 branches.add(repo[rev].branch())
465 if len(branches) > 1: 469 if len(branches) > 1:
466 raise error.Abort( 470 raise error.Abort(
467 _('cannot collapse multiple named ' 'branches') 471 _(b'cannot collapse multiple named ' b'branches')
468 ) 472 )
469 473
470 # Calculate self.obsoletenotrebased 474 # Calculate self.obsoletenotrebased
471 obsrevs = _filterobsoleterevs(self.repo, self.state) 475 obsrevs = _filterobsoleterevs(self.repo, self.state)
472 self._handleskippingobsolete(obsrevs, self.destmap) 476 self._handleskippingobsolete(obsrevs, self.destmap)
484 # commits. 488 # commits.
485 self.storestatus(tr) 489 self.storestatus(tr)
486 490
487 cands = [k for k, v in self.state.iteritems() if v == revtodo] 491 cands = [k for k, v in self.state.iteritems() if v == revtodo]
488 p = repo.ui.makeprogress( 492 p = repo.ui.makeprogress(
489 _("rebasing"), unit=_('changesets'), total=len(cands) 493 _(b"rebasing"), unit=_(b'changesets'), total=len(cands)
490 ) 494 )
491 495
492 def progress(ctx): 496 def progress(ctx):
493 p.increment(item=("%d:%s" % (ctx.rev(), ctx))) 497 p.increment(item=(b"%d:%s" % (ctx.rev(), ctx)))
494 498
495 allowdivergence = self.ui.configbool( 499 allowdivergence = self.ui.configbool(
496 'experimental', 'evolution.allowdivergence' 500 b'experimental', b'evolution.allowdivergence'
497 ) 501 )
498 for subset in sortsource(self.destmap): 502 for subset in sortsource(self.destmap):
499 sortedrevs = self.repo.revs('sort(%ld, -topo)', subset) 503 sortedrevs = self.repo.revs(b'sort(%ld, -topo)', subset)
500 if not allowdivergence: 504 if not allowdivergence:
501 sortedrevs -= self.repo.revs( 505 sortedrevs -= self.repo.revs(
502 'descendants(%ld) and not %ld', 506 b'descendants(%ld) and not %ld',
503 self.obsoletewithoutsuccessorindestination, 507 self.obsoletewithoutsuccessorindestination,
504 self.obsoletewithoutsuccessorindestination, 508 self.obsoletewithoutsuccessorindestination,
505 ) 509 )
506 for rev in sortedrevs: 510 for rev in sortedrevs:
507 self._rebasenode(tr, rev, allowdivergence, progress) 511 self._rebasenode(tr, rev, allowdivergence, progress)
508 p.complete() 512 p.complete()
509 ui.note(_('rebase merging completed\n')) 513 ui.note(_(b'rebase merging completed\n'))
510 514
511 def _concludenode(self, rev, p1, p2, editor, commitmsg=None): 515 def _concludenode(self, rev, p1, p2, editor, commitmsg=None):
512 '''Commit the wd changes with parents p1 and p2. 516 '''Commit the wd changes with parents p1 and p2.
513 517
514 Reuse commit info from rev but also store useful information in extra. 518 Reuse commit info from rev but also store useful information in extra.
518 if commitmsg is None: 522 if commitmsg is None:
519 commitmsg = ctx.description() 523 commitmsg = ctx.description()
520 date = self.date 524 date = self.date
521 if date is None: 525 if date is None:
522 date = ctx.date() 526 date = ctx.date()
523 extra = {'rebase_source': ctx.hex()} 527 extra = {b'rebase_source': ctx.hex()}
524 for c in self.extrafns: 528 for c in self.extrafns:
525 c(ctx, extra) 529 c(ctx, extra)
526 keepbranch = self.keepbranchesf and repo[p1].branch() != ctx.branch() 530 keepbranch = self.keepbranchesf and repo[p1].branch() != ctx.branch()
527 destphase = max(ctx.phase(), phases.draft) 531 destphase = max(ctx.phase(), phases.draft)
528 overrides = {('phases', 'new-commit'): destphase} 532 overrides = {(b'phases', b'new-commit'): destphase}
529 if keepbranch: 533 if keepbranch:
530 overrides[('ui', 'allowemptycommit')] = True 534 overrides[(b'ui', b'allowemptycommit')] = True
531 with repo.ui.configoverride(overrides, 'rebase'): 535 with repo.ui.configoverride(overrides, b'rebase'):
532 if self.inmemory: 536 if self.inmemory:
533 newnode = commitmemorynode( 537 newnode = commitmemorynode(
534 repo, 538 repo,
535 p1, 539 p1,
536 p2, 540 p2,
565 repo, ui, opts = self.repo, self.ui, self.opts 569 repo, ui, opts = self.repo, self.ui, self.opts
566 dest = self.destmap[rev] 570 dest = self.destmap[rev]
567 ctx = repo[rev] 571 ctx = repo[rev]
568 desc = _ctxdesc(ctx) 572 desc = _ctxdesc(ctx)
569 if self.state[rev] == rev: 573 if self.state[rev] == rev:
570 ui.status(_('already rebased %s\n') % desc) 574 ui.status(_(b'already rebased %s\n') % desc)
571 elif ( 575 elif (
572 not allowdivergence 576 not allowdivergence
573 and rev in self.obsoletewithoutsuccessorindestination 577 and rev in self.obsoletewithoutsuccessorindestination
574 ): 578 ):
575 msg = ( 579 msg = (
576 _( 580 _(
577 'note: not rebasing %s and its descendants as ' 581 b'note: not rebasing %s and its descendants as '
578 'this would cause divergence\n' 582 b'this would cause divergence\n'
579 ) 583 )
580 % desc 584 % desc
581 ) 585 )
582 repo.ui.status(msg) 586 repo.ui.status(msg)
583 self.skipped.add(rev) 587 self.skipped.add(rev)
584 elif rev in self.obsoletenotrebased: 588 elif rev in self.obsoletenotrebased:
585 succ = self.obsoletenotrebased[rev] 589 succ = self.obsoletenotrebased[rev]
586 if succ is None: 590 if succ is None:
587 msg = ( 591 msg = (
588 _('note: not rebasing %s, it has no ' 'successor\n') % desc 592 _(b'note: not rebasing %s, it has no ' b'successor\n')
593 % desc
589 ) 594 )
590 else: 595 else:
591 succdesc = _ctxdesc(repo[succ]) 596 succdesc = _ctxdesc(repo[succ])
592 msg = _( 597 msg = _(
593 'note: not rebasing %s, already in ' 'destination as %s\n' 598 b'note: not rebasing %s, already in ' b'destination as %s\n'
594 ) % (desc, succdesc) 599 ) % (desc, succdesc)
595 repo.ui.status(msg) 600 repo.ui.status(msg)
596 # Make clearrebased aware state[rev] is not a true successor 601 # Make clearrebased aware state[rev] is not a true successor
597 self.skipped.add(rev) 602 self.skipped.add(rev)
598 # Record rev as moved to its desired destination in self.state. 603 # Record rev as moved to its desired destination in self.state.
600 dest = max( 605 dest = max(
601 adjustdest(repo, rev, self.destmap, self.state, self.skipped) 606 adjustdest(repo, rev, self.destmap, self.state, self.skipped)
602 ) 607 )
603 self.state[rev] = dest 608 self.state[rev] = dest
604 elif self.state[rev] == revtodo: 609 elif self.state[rev] == revtodo:
605 ui.status(_('rebasing %s\n') % desc) 610 ui.status(_(b'rebasing %s\n') % desc)
606 progressfn(ctx) 611 progressfn(ctx)
607 p1, p2, base = defineparents( 612 p1, p2, base = defineparents(
608 repo, 613 repo,
609 rev, 614 rev,
610 self.destmap, 615 self.destmap,
611 self.state, 616 self.state,
612 self.skipped, 617 self.skipped,
613 self.obsoletenotrebased, 618 self.obsoletenotrebased,
614 ) 619 )
615 if not self.inmemory and len(repo[None].parents()) == 2: 620 if not self.inmemory and len(repo[None].parents()) == 2:
616 repo.ui.debug('resuming interrupted rebase\n') 621 repo.ui.debug(b'resuming interrupted rebase\n')
617 else: 622 else:
618 overrides = {('ui', 'forcemerge'): opts.get('tool', '')} 623 overrides = {(b'ui', b'forcemerge'): opts.get(b'tool', b'')}
619 with ui.configoverride(overrides, 'rebase'): 624 with ui.configoverride(overrides, b'rebase'):
620 stats = rebasenode( 625 stats = rebasenode(
621 repo, 626 repo,
622 rev, 627 rev,
623 p1, 628 p1,
624 base, 629 base,
630 if self.inmemory: 635 if self.inmemory:
631 raise error.InMemoryMergeConflictsError() 636 raise error.InMemoryMergeConflictsError()
632 else: 637 else:
633 raise error.InterventionRequired( 638 raise error.InterventionRequired(
634 _( 639 _(
635 'unresolved conflicts (see hg ' 640 b'unresolved conflicts (see hg '
636 'resolve, then hg rebase --continue)' 641 b'resolve, then hg rebase --continue)'
637 ) 642 )
638 ) 643 )
639 if not self.collapsef: 644 if not self.collapsef:
640 merging = p2 != nullrev 645 merging = p2 != nullrev
641 editform = cmdutil.mergeeditform(merging, 'rebase') 646 editform = cmdutil.mergeeditform(merging, b'rebase')
642 editor = cmdutil.getcommiteditor( 647 editor = cmdutil.getcommiteditor(
643 editform=editform, **pycompat.strkwargs(opts) 648 editform=editform, **pycompat.strkwargs(opts)
644 ) 649 )
645 newnode = self._concludenode(rev, p1, p2, editor) 650 newnode = self._concludenode(rev, p1, p2, editor)
646 else: 651 else:
651 repo.setparents(repo[p1].node()) 656 repo.setparents(repo[p1].node())
652 newnode = None 657 newnode = None
653 # Update the state 658 # Update the state
654 if newnode is not None: 659 if newnode is not None:
655 self.state[rev] = repo[newnode].rev() 660 self.state[rev] = repo[newnode].rev()
656 ui.debug('rebased as %s\n' % short(newnode)) 661 ui.debug(b'rebased as %s\n' % short(newnode))
657 else: 662 else:
658 if not self.collapsef: 663 if not self.collapsef:
659 ui.warn( 664 ui.warn(
660 _( 665 _(
661 'note: not rebasing %s, its destination already ' 666 b'note: not rebasing %s, its destination already '
662 'has all its changes\n' 667 b'has all its changes\n'
663 ) 668 )
664 % desc 669 % desc
665 ) 670 )
666 self.skipped.add(rev) 671 self.skipped.add(rev)
667 self.state[rev] = p1 672 self.state[rev] = p1
668 ui.debug('next revision set to %d\n' % p1) 673 ui.debug(b'next revision set to %d\n' % p1)
669 else: 674 else:
670 ui.status( 675 ui.status(
671 _('already rebased %s as %s\n') % (desc, repo[self.state[rev]]) 676 _(b'already rebased %s as %s\n') % (desc, repo[self.state[rev]])
672 ) 677 )
673 if not tr: 678 if not tr:
674 # When not using single transaction, store state after each 679 # When not using single transaction, store state after each
675 # commit is completely done. On InterventionRequired, we thus 680 # commit is completely done. On InterventionRequired, we thus
676 # won't store the status. Instead, we'll hit the "len(parents) == 2" 681 # won't store the status. Instead, we'll hit the "len(parents) == 2"
677 # case and realize that the commit was in progress. 682 # case and realize that the commit was in progress.
678 self.storestatus() 683 self.storestatus()
679 684
680 def _finishrebase(self): 685 def _finishrebase(self):
681 repo, ui, opts = self.repo, self.ui, self.opts 686 repo, ui, opts = self.repo, self.ui, self.opts
682 fm = ui.formatter('rebase', opts) 687 fm = ui.formatter(b'rebase', opts)
683 fm.startitem() 688 fm.startitem()
684 if self.collapsef: 689 if self.collapsef:
685 p1, p2, _base = defineparents( 690 p1, p2, _base = defineparents(
686 repo, 691 repo,
687 min(self.state), 692 min(self.state),
688 self.destmap, 693 self.destmap,
689 self.state, 694 self.state,
690 self.skipped, 695 self.skipped,
691 self.obsoletenotrebased, 696 self.obsoletenotrebased,
692 ) 697 )
693 editopt = opts.get('edit') 698 editopt = opts.get(b'edit')
694 editform = 'rebase.collapse' 699 editform = b'rebase.collapse'
695 if self.collapsemsg: 700 if self.collapsemsg:
696 commitmsg = self.collapsemsg 701 commitmsg = self.collapsemsg
697 else: 702 else:
698 commitmsg = 'Collapsed revision' 703 commitmsg = b'Collapsed revision'
699 for rebased in sorted(self.state): 704 for rebased in sorted(self.state):
700 if rebased not in self.skipped: 705 if rebased not in self.skipped:
701 commitmsg += '\n* %s' % repo[rebased].description() 706 commitmsg += b'\n* %s' % repo[rebased].description()
702 editopt = True 707 editopt = True
703 editor = cmdutil.getcommiteditor(edit=editopt, editform=editform) 708 editor = cmdutil.getcommiteditor(edit=editopt, editform=editform)
704 revtoreuse = max(self.state) 709 revtoreuse = max(self.state)
705 710
706 newnode = self._concludenode( 711 newnode = self._concludenode(
710 if newnode is not None: 715 if newnode is not None:
711 newrev = repo[newnode].rev() 716 newrev = repo[newnode].rev()
712 for oldrev in self.state: 717 for oldrev in self.state:
713 self.state[oldrev] = newrev 718 self.state[oldrev] = newrev
714 719
715 if 'qtip' in repo.tags(): 720 if b'qtip' in repo.tags():
716 updatemq(repo, self.state, self.skipped, **pycompat.strkwargs(opts)) 721 updatemq(repo, self.state, self.skipped, **pycompat.strkwargs(opts))
717 722
718 # restore original working directory 723 # restore original working directory
719 # (we do this before stripping) 724 # (we do this before stripping)
720 newwd = self.state.get(self.originalwd, self.originalwd) 725 newwd = self.state.get(self.originalwd, self.originalwd)
721 if newwd < 0: 726 if newwd < 0:
722 # original directory is a parent of rebase set root or ignored 727 # original directory is a parent of rebase set root or ignored
723 newwd = self.originalwd 728 newwd = self.originalwd
724 if newwd not in [c.rev() for c in repo[None].parents()]: 729 if newwd not in [c.rev() for c in repo[None].parents()]:
725 ui.note(_("update back to initial working directory parent\n")) 730 ui.note(_(b"update back to initial working directory parent\n"))
726 hg.updaterepo(repo, newwd, overwrite=False) 731 hg.updaterepo(repo, newwd, overwrite=False)
727 732
728 collapsedas = None 733 collapsedas = None
729 if self.collapsef and not self.keepf: 734 if self.collapsef and not self.keepf:
730 collapsedas = newnode 735 collapsedas = newnode
741 ) 746 )
742 747
743 clearstatus(repo) 748 clearstatus(repo)
744 clearcollapsemsg(repo) 749 clearcollapsemsg(repo)
745 750
746 ui.note(_("rebase completed\n")) 751 ui.note(_(b"rebase completed\n"))
747 util.unlinkpath(repo.sjoin('undo'), ignoremissing=True) 752 util.unlinkpath(repo.sjoin(b'undo'), ignoremissing=True)
748 if self.skipped: 753 if self.skipped:
749 skippedlen = len(self.skipped) 754 skippedlen = len(self.skipped)
750 ui.note(_("%d revisions have been skipped\n") % skippedlen) 755 ui.note(_(b"%d revisions have been skipped\n") % skippedlen)
751 fm.end() 756 fm.end()
752 757
753 if ( 758 if (
754 self.activebookmark 759 self.activebookmark
755 and self.activebookmark in repo._bookmarks 760 and self.activebookmark in repo._bookmarks
756 and repo['.'].node() == repo._bookmarks[self.activebookmark] 761 and repo[b'.'].node() == repo._bookmarks[self.activebookmark]
757 ): 762 ):
758 bookmarks.activate(repo, self.activebookmark) 763 bookmarks.activate(repo, self.activebookmark)
759 764
760 def _abort(self, backup=True, suppwarns=False): 765 def _abort(self, backup=True, suppwarns=False):
761 '''Restore the repository to its original state.''' 766 '''Restore the repository to its original state.'''
773 ] 778 ]
774 immutable = [d for d in rebased if not repo[d].mutable()] 779 immutable = [d for d in rebased if not repo[d].mutable()]
775 cleanup = True 780 cleanup = True
776 if immutable: 781 if immutable:
777 repo.ui.warn( 782 repo.ui.warn(
778 _("warning: can't clean up public changesets %s\n") 783 _(b"warning: can't clean up public changesets %s\n")
779 % ', '.join(bytes(repo[r]) for r in immutable), 784 % b', '.join(bytes(repo[r]) for r in immutable),
780 hint=_("see 'hg help phases' for details"), 785 hint=_(b"see 'hg help phases' for details"),
781 ) 786 )
782 cleanup = False 787 cleanup = False
783 788
784 descendants = set() 789 descendants = set()
785 if rebased: 790 if rebased:
786 descendants = set(repo.changelog.descendants(rebased)) 791 descendants = set(repo.changelog.descendants(rebased))
787 if descendants - set(rebased): 792 if descendants - set(rebased):
788 repo.ui.warn( 793 repo.ui.warn(
789 _( 794 _(
790 "warning: new changesets detected on " 795 b"warning: new changesets detected on "
791 "destination branch, can't strip\n" 796 b"destination branch, can't strip\n"
792 ) 797 )
793 ) 798 )
794 cleanup = False 799 cleanup = False
795 800
796 if cleanup: 801 if cleanup:
797 shouldupdate = False 802 shouldupdate = False
798 if rebased: 803 if rebased:
799 strippoints = [ 804 strippoints = [
800 c.node() for c in repo.set('roots(%ld)', rebased) 805 c.node() for c in repo.set(b'roots(%ld)', rebased)
801 ] 806 ]
802 807
803 updateifonnodes = set(rebased) 808 updateifonnodes = set(rebased)
804 updateifonnodes.update(self.destmap.values()) 809 updateifonnodes.update(self.destmap.values())
805 updateifonnodes.add(self.originalwd) 810 updateifonnodes.add(self.originalwd)
806 shouldupdate = repo['.'].rev() in updateifonnodes 811 shouldupdate = repo[b'.'].rev() in updateifonnodes
807 812
808 # Update away from the rebase if necessary 813 # Update away from the rebase if necessary
809 if shouldupdate or needupdate(repo, self.state): 814 if shouldupdate or needupdate(repo, self.state):
810 mergemod.update( 815 mergemod.update(
811 repo, self.originalwd, branchmerge=False, force=True 816 repo, self.originalwd, branchmerge=False, force=True
820 825
821 finally: 826 finally:
822 clearstatus(repo) 827 clearstatus(repo)
823 clearcollapsemsg(repo) 828 clearcollapsemsg(repo)
824 if not suppwarns: 829 if not suppwarns:
825 repo.ui.warn(_('rebase aborted\n')) 830 repo.ui.warn(_(b'rebase aborted\n'))
826 return 0 831 return 0
827 832
828 833
829 @command( 834 @command(
830 'rebase', 835 b'rebase',
831 [ 836 [
832 ( 837 (
833 's', 838 b's',
834 'source', 839 b'source',
835 '', 840 b'',
836 _('rebase the specified changeset and descendants'), 841 _(b'rebase the specified changeset and descendants'),
837 _('REV'), 842 _(b'REV'),
838 ), 843 ),
839 ( 844 (
840 'b', 845 b'b',
841 'base', 846 b'base',
842 '', 847 b'',
843 _('rebase everything from branching point of specified changeset'), 848 _(b'rebase everything from branching point of specified changeset'),
844 _('REV'), 849 _(b'REV'),
845 ), 850 ),
846 ('r', 'rev', [], _('rebase these revisions'), _('REV')), 851 (b'r', b'rev', [], _(b'rebase these revisions'), _(b'REV')),
847 ('d', 'dest', '', _('rebase onto the specified changeset'), _('REV')),
848 ('', 'collapse', False, _('collapse the rebased changesets')),
849 ( 852 (
850 'm', 853 b'd',
851 'message', 854 b'dest',
852 '', 855 b'',
853 _('use text as collapse commit message'), 856 _(b'rebase onto the specified changeset'),
854 _('TEXT'), 857 _(b'REV'),
855 ), 858 ),
856 ('e', 'edit', False, _('invoke editor on commit messages')), 859 (b'', b'collapse', False, _(b'collapse the rebased changesets')),
857 ( 860 (
858 'l', 861 b'm',
859 'logfile', 862 b'message',
860 '', 863 b'',
861 _('read collapse commit message from file'), 864 _(b'use text as collapse commit message'),
862 _('FILE'), 865 _(b'TEXT'),
863 ), 866 ),
864 ('k', 'keep', False, _('keep original changesets')), 867 (b'e', b'edit', False, _(b'invoke editor on commit messages')),
865 ('', 'keepbranches', False, _('keep original branch names')),
866 ('D', 'detach', False, _('(DEPRECATED)')),
867 ('i', 'interactive', False, _('(DEPRECATED)')),
868 ('t', 'tool', '', _('specify merge tool')),
869 ('', 'stop', False, _('stop interrupted rebase')),
870 ('c', 'continue', False, _('continue an interrupted rebase')),
871 ('a', 'abort', False, _('abort an interrupted rebase')),
872 ( 868 (
873 '', 869 b'l',
874 'auto-orphans', 870 b'logfile',
875 '', 871 b'',
872 _(b'read collapse commit message from file'),
873 _(b'FILE'),
874 ),
875 (b'k', b'keep', False, _(b'keep original changesets')),
876 (b'', b'keepbranches', False, _(b'keep original branch names')),
877 (b'D', b'detach', False, _(b'(DEPRECATED)')),
878 (b'i', b'interactive', False, _(b'(DEPRECATED)')),
879 (b't', b'tool', b'', _(b'specify merge tool')),
880 (b'', b'stop', False, _(b'stop interrupted rebase')),
881 (b'c', b'continue', False, _(b'continue an interrupted rebase')),
882 (b'a', b'abort', False, _(b'abort an interrupted rebase')),
883 (
884 b'',
885 b'auto-orphans',
886 b'',
876 _( 887 _(
877 'automatically rebase orphan revisions ' 888 b'automatically rebase orphan revisions '
878 'in the specified revset (EXPERIMENTAL)' 889 b'in the specified revset (EXPERIMENTAL)'
879 ), 890 ),
880 ), 891 ),
881 ] 892 ]
882 + cmdutil.dryrunopts 893 + cmdutil.dryrunopts
883 + cmdutil.formatteropts 894 + cmdutil.formatteropts
884 + cmdutil.confirmopts, 895 + cmdutil.confirmopts,
885 _('[-s REV | -b REV] [-d REV] [OPTION]'), 896 _(b'[-s REV | -b REV] [-d REV] [OPTION]'),
886 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT, 897 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
887 ) 898 )
888 def rebase(ui, repo, **opts): 899 def rebase(ui, repo, **opts):
889 """move changeset (and descendants) to a different branch 900 """move changeset (and descendants) to a different branch
890 901
1007 Returns 0 on success, 1 if nothing to rebase or there are 1018 Returns 0 on success, 1 if nothing to rebase or there are
1008 unresolved conflicts. 1019 unresolved conflicts.
1009 1020
1010 """ 1021 """
1011 opts = pycompat.byteskwargs(opts) 1022 opts = pycompat.byteskwargs(opts)
1012 inmemory = ui.configbool('rebase', 'experimental.inmemory') 1023 inmemory = ui.configbool(b'rebase', b'experimental.inmemory')
1013 dryrun = opts.get('dry_run') 1024 dryrun = opts.get(b'dry_run')
1014 confirm = opts.get('confirm') 1025 confirm = opts.get(b'confirm')
1015 selactions = [k for k in ['abort', 'stop', 'continue'] if opts.get(k)] 1026 selactions = [k for k in [b'abort', b'stop', b'continue'] if opts.get(k)]
1016 if len(selactions) > 1: 1027 if len(selactions) > 1:
1017 raise error.Abort( 1028 raise error.Abort(
1018 _('cannot use --%s with --%s') % tuple(selactions[:2]) 1029 _(b'cannot use --%s with --%s') % tuple(selactions[:2])
1019 ) 1030 )
1020 action = selactions[0] if selactions else None 1031 action = selactions[0] if selactions else None
1021 if dryrun and action: 1032 if dryrun and action:
1022 raise error.Abort(_('cannot specify both --dry-run and --%s') % action) 1033 raise error.Abort(_(b'cannot specify both --dry-run and --%s') % action)
1023 if confirm and action: 1034 if confirm and action:
1024 raise error.Abort(_('cannot specify both --confirm and --%s') % action) 1035 raise error.Abort(_(b'cannot specify both --confirm and --%s') % action)
1025 if dryrun and confirm: 1036 if dryrun and confirm:
1026 raise error.Abort(_('cannot specify both --confirm and --dry-run')) 1037 raise error.Abort(_(b'cannot specify both --confirm and --dry-run'))
1027 1038
1028 if action or repo.currenttransaction() is not None: 1039 if action or repo.currenttransaction() is not None:
1029 # in-memory rebase is not compatible with resuming rebases. 1040 # in-memory rebase is not compatible with resuming rebases.
1030 # (Or if it is run within a transaction, since the restart logic can 1041 # (Or if it is run within a transaction, since the restart logic can
1031 # fail the entire transaction.) 1042 # fail the entire transaction.)
1032 inmemory = False 1043 inmemory = False
1033 1044
1034 if opts.get('auto_orphans'): 1045 if opts.get(b'auto_orphans'):
1035 for key in opts: 1046 for key in opts:
1036 if key != 'auto_orphans' and opts.get(key): 1047 if key != b'auto_orphans' and opts.get(key):
1037 raise error.Abort( 1048 raise error.Abort(
1038 _('--auto-orphans is incompatible with %s') % ('--' + key) 1049 _(b'--auto-orphans is incompatible with %s') % (b'--' + key)
1039 ) 1050 )
1040 userrevs = list(repo.revs(opts.get('auto_orphans'))) 1051 userrevs = list(repo.revs(opts.get(b'auto_orphans')))
1041 opts['rev'] = [revsetlang.formatspec('%ld and orphan()', userrevs)] 1052 opts[b'rev'] = [revsetlang.formatspec(b'%ld and orphan()', userrevs)]
1042 opts['dest'] = '_destautoorphanrebase(SRC)' 1053 opts[b'dest'] = b'_destautoorphanrebase(SRC)'
1043 1054
1044 if dryrun or confirm: 1055 if dryrun or confirm:
1045 return _dryrunrebase(ui, repo, action, opts) 1056 return _dryrunrebase(ui, repo, action, opts)
1046 elif action == 'stop': 1057 elif action == b'stop':
1047 rbsrt = rebaseruntime(repo, ui) 1058 rbsrt = rebaseruntime(repo, ui)
1048 with repo.wlock(), repo.lock(): 1059 with repo.wlock(), repo.lock():
1049 rbsrt.restorestatus() 1060 rbsrt.restorestatus()
1050 if rbsrt.collapsef: 1061 if rbsrt.collapsef:
1051 raise error.Abort(_("cannot stop in --collapse session")) 1062 raise error.Abort(_(b"cannot stop in --collapse session"))
1052 allowunstable = obsolete.isenabled(repo, obsolete.allowunstableopt) 1063 allowunstable = obsolete.isenabled(repo, obsolete.allowunstableopt)
1053 if not (rbsrt.keepf or allowunstable): 1064 if not (rbsrt.keepf or allowunstable):
1054 raise error.Abort( 1065 raise error.Abort(
1055 _( 1066 _(
1056 "cannot remove original changesets with" 1067 b"cannot remove original changesets with"
1057 " unrebased descendants" 1068 b" unrebased descendants"
1058 ), 1069 ),
1059 hint=_( 1070 hint=_(
1060 'either enable obsmarkers to allow unstable ' 1071 b'either enable obsmarkers to allow unstable '
1061 'revisions or use --keep to keep original ' 1072 b'revisions or use --keep to keep original '
1062 'changesets' 1073 b'changesets'
1063 ), 1074 ),
1064 ) 1075 )
1065 if needupdate(repo, rbsrt.state): 1076 if needupdate(repo, rbsrt.state):
1066 # update to the current working revision 1077 # update to the current working revision
1067 # to clear interrupted merge 1078 # to clear interrupted merge
1070 return 0 1081 return 0
1071 elif inmemory: 1082 elif inmemory:
1072 try: 1083 try:
1073 # in-memory merge doesn't support conflicts, so if we hit any, abort 1084 # in-memory merge doesn't support conflicts, so if we hit any, abort
1074 # and re-run as an on-disk merge. 1085 # and re-run as an on-disk merge.
1075 overrides = {('rebase', 'singletransaction'): True} 1086 overrides = {(b'rebase', b'singletransaction'): True}
1076 with ui.configoverride(overrides, 'rebase'): 1087 with ui.configoverride(overrides, b'rebase'):
1077 return _dorebase(ui, repo, action, opts, inmemory=inmemory) 1088 return _dorebase(ui, repo, action, opts, inmemory=inmemory)
1078 except error.InMemoryMergeConflictsError: 1089 except error.InMemoryMergeConflictsError:
1079 ui.warn( 1090 ui.warn(
1080 _( 1091 _(
1081 'hit merge conflicts; re-running rebase without in-memory' 1092 b'hit merge conflicts; re-running rebase without in-memory'
1082 ' merge\n' 1093 b' merge\n'
1083 ) 1094 )
1084 ) 1095 )
1085 # TODO: Make in-memory merge not use the on-disk merge state, so 1096 # TODO: Make in-memory merge not use the on-disk merge state, so
1086 # we don't have to clean it here 1097 # we don't have to clean it here
1087 mergemod.mergestate.clean(repo) 1098 mergemod.mergestate.clean(repo)
1092 return _dorebase(ui, repo, action, opts) 1103 return _dorebase(ui, repo, action, opts)
1093 1104
1094 1105
1095 def _dryrunrebase(ui, repo, action, opts): 1106 def _dryrunrebase(ui, repo, action, opts):
1096 rbsrt = rebaseruntime(repo, ui, inmemory=True, opts=opts) 1107 rbsrt = rebaseruntime(repo, ui, inmemory=True, opts=opts)
1097 confirm = opts.get('confirm') 1108 confirm = opts.get(b'confirm')
1098 if confirm: 1109 if confirm:
1099 ui.status(_('starting in-memory rebase\n')) 1110 ui.status(_(b'starting in-memory rebase\n'))
1100 else: 1111 else:
1101 ui.status( 1112 ui.status(
1102 _('starting dry-run rebase; repository will not be ' 'changed\n') 1113 _(b'starting dry-run rebase; repository will not be ' b'changed\n')
1103 ) 1114 )
1104 with repo.wlock(), repo.lock(): 1115 with repo.wlock(), repo.lock():
1105 needsabort = True 1116 needsabort = True
1106 try: 1117 try:
1107 overrides = {('rebase', 'singletransaction'): True} 1118 overrides = {(b'rebase', b'singletransaction'): True}
1108 with ui.configoverride(overrides, 'rebase'): 1119 with ui.configoverride(overrides, b'rebase'):
1109 _origrebase( 1120 _origrebase(
1110 ui, 1121 ui,
1111 repo, 1122 repo,
1112 action, 1123 action,
1113 opts, 1124 opts,
1114 rbsrt, 1125 rbsrt,
1115 inmemory=True, 1126 inmemory=True,
1116 leaveunfinished=True, 1127 leaveunfinished=True,
1117 ) 1128 )
1118 except error.InMemoryMergeConflictsError: 1129 except error.InMemoryMergeConflictsError:
1119 ui.status(_('hit a merge conflict\n')) 1130 ui.status(_(b'hit a merge conflict\n'))
1120 return 1 1131 return 1
1121 except error.Abort: 1132 except error.Abort:
1122 needsabort = False 1133 needsabort = False
1123 raise 1134 raise
1124 else: 1135 else:
1125 if confirm: 1136 if confirm:
1126 ui.status(_('rebase completed successfully\n')) 1137 ui.status(_(b'rebase completed successfully\n'))
1127 if not ui.promptchoice( 1138 if not ui.promptchoice(
1128 _(b'apply changes (yn)?' b'$$ &Yes $$ &No') 1139 _(b'apply changes (yn)?' b'$$ &Yes $$ &No')
1129 ): 1140 ):
1130 # finish unfinished rebase 1141 # finish unfinished rebase
1131 rbsrt._finishrebase() 1142 rbsrt._finishrebase()
1135 ) 1146 )
1136 needsabort = False 1147 needsabort = False
1137 else: 1148 else:
1138 ui.status( 1149 ui.status(
1139 _( 1150 _(
1140 'dry-run rebase completed successfully; run without' 1151 b'dry-run rebase completed successfully; run without'
1141 ' -n/--dry-run to perform this rebase\n' 1152 b' -n/--dry-run to perform this rebase\n'
1142 ) 1153 )
1143 ) 1154 )
1144 return 0 1155 return 0
1145 finally: 1156 finally:
1146 if needsabort: 1157 if needsabort:
1156 1167
1157 1168
1158 def _origrebase( 1169 def _origrebase(
1159 ui, repo, action, opts, rbsrt, inmemory=False, leaveunfinished=False 1170 ui, repo, action, opts, rbsrt, inmemory=False, leaveunfinished=False
1160 ): 1171 ):
1161 assert action != 'stop' 1172 assert action != b'stop'
1162 with repo.wlock(), repo.lock(): 1173 with repo.wlock(), repo.lock():
1163 # Validate input and define rebasing points 1174 # Validate input and define rebasing points
1164 destf = opts.get('dest', None) 1175 destf = opts.get(b'dest', None)
1165 srcf = opts.get('source', None) 1176 srcf = opts.get(b'source', None)
1166 basef = opts.get('base', None) 1177 basef = opts.get(b'base', None)
1167 revf = opts.get('rev', []) 1178 revf = opts.get(b'rev', [])
1168 # search default destination in this space 1179 # search default destination in this space
1169 # used in the 'hg pull --rebase' case, see issue 5214. 1180 # used in the 'hg pull --rebase' case, see issue 5214.
1170 destspace = opts.get('_destspace') 1181 destspace = opts.get(b'_destspace')
1171 if opts.get('interactive'): 1182 if opts.get(b'interactive'):
1172 try: 1183 try:
1173 if extensions.find('histedit'): 1184 if extensions.find(b'histedit'):
1174 enablehistedit = '' 1185 enablehistedit = b''
1175 except KeyError: 1186 except KeyError:
1176 enablehistedit = " --config extensions.histedit=" 1187 enablehistedit = b" --config extensions.histedit="
1177 help = "hg%s help -e histedit" % enablehistedit 1188 help = b"hg%s help -e histedit" % enablehistedit
1178 msg = ( 1189 msg = (
1179 _( 1190 _(
1180 "interactive history editing is supported by the " 1191 b"interactive history editing is supported by the "
1181 "'histedit' extension (see \"%s\")" 1192 b"'histedit' extension (see \"%s\")"
1182 ) 1193 )
1183 % help 1194 % help
1184 ) 1195 )
1185 raise error.Abort(msg) 1196 raise error.Abort(msg)
1186 1197
1187 if rbsrt.collapsemsg and not rbsrt.collapsef: 1198 if rbsrt.collapsemsg and not rbsrt.collapsef:
1188 raise error.Abort(_('message can only be specified with collapse')) 1199 raise error.Abort(_(b'message can only be specified with collapse'))
1189 1200
1190 if action: 1201 if action:
1191 if rbsrt.collapsef: 1202 if rbsrt.collapsef:
1192 raise error.Abort( 1203 raise error.Abort(
1193 _('cannot use collapse with continue or abort') 1204 _(b'cannot use collapse with continue or abort')
1194 ) 1205 )
1195 if srcf or basef or destf: 1206 if srcf or basef or destf:
1196 raise error.Abort( 1207 raise error.Abort(
1197 _('abort and continue do not allow specifying revisions') 1208 _(b'abort and continue do not allow specifying revisions')
1198 ) 1209 )
1199 if action == 'abort' and opts.get('tool', False): 1210 if action == b'abort' and opts.get(b'tool', False):
1200 ui.warn(_('tool option will be ignored\n')) 1211 ui.warn(_(b'tool option will be ignored\n'))
1201 if action == 'continue': 1212 if action == b'continue':
1202 ms = mergemod.mergestate.read(repo) 1213 ms = mergemod.mergestate.read(repo)
1203 mergeutil.checkunresolved(ms) 1214 mergeutil.checkunresolved(ms)
1204 1215
1205 retcode = rbsrt._prepareabortorcontinue(isabort=(action == 'abort')) 1216 retcode = rbsrt._prepareabortorcontinue(
1217 isabort=(action == b'abort')
1218 )
1206 if retcode is not None: 1219 if retcode is not None:
1207 return retcode 1220 return retcode
1208 else: 1221 else:
1209 destmap = _definedestmap( 1222 destmap = _definedestmap(
1210 ui, 1223 ui,
1221 return retcode 1234 return retcode
1222 storecollapsemsg(repo, rbsrt.collapsemsg) 1235 storecollapsemsg(repo, rbsrt.collapsemsg)
1223 1236
1224 tr = None 1237 tr = None
1225 1238
1226 singletr = ui.configbool('rebase', 'singletransaction') 1239 singletr = ui.configbool(b'rebase', b'singletransaction')
1227 if singletr: 1240 if singletr:
1228 tr = repo.transaction('rebase') 1241 tr = repo.transaction(b'rebase')
1229 1242
1230 # If `rebase.singletransaction` is enabled, wrap the entire operation in 1243 # If `rebase.singletransaction` is enabled, wrap the entire operation in
1231 # one transaction here. Otherwise, transactions are obtained when 1244 # one transaction here. Otherwise, transactions are obtained when
1232 # committing each node, which is slower but allows partial success. 1245 # committing each node, which is slower but allows partial success.
1233 with util.acceptintervention(tr): 1246 with util.acceptintervention(tr):
1234 # Same logic for the dirstate guard, except we don't create one when 1247 # Same logic for the dirstate guard, except we don't create one when
1235 # rebasing in-memory (it's not needed). 1248 # rebasing in-memory (it's not needed).
1236 dsguard = None 1249 dsguard = None
1237 if singletr and not inmemory: 1250 if singletr and not inmemory:
1238 dsguard = dirstateguard.dirstateguard(repo, 'rebase') 1251 dsguard = dirstateguard.dirstateguard(repo, b'rebase')
1239 with util.acceptintervention(dsguard): 1252 with util.acceptintervention(dsguard):
1240 rbsrt._performrebase(tr) 1253 rbsrt._performrebase(tr)
1241 if not leaveunfinished: 1254 if not leaveunfinished:
1242 rbsrt._finishrebase() 1255 rbsrt._finishrebase()
1243 1256
1257 revf = [] 1270 revf = []
1258 1271
1259 # destspace is here to work around issues with `hg pull --rebase` see 1272 # destspace is here to work around issues with `hg pull --rebase` see
1260 # issue5214 for details 1273 # issue5214 for details
1261 if srcf and basef: 1274 if srcf and basef:
1262 raise error.Abort(_('cannot specify both a source and a base')) 1275 raise error.Abort(_(b'cannot specify both a source and a base'))
1263 if revf and basef: 1276 if revf and basef:
1264 raise error.Abort(_('cannot specify both a revision and a base')) 1277 raise error.Abort(_(b'cannot specify both a revision and a base'))
1265 if revf and srcf: 1278 if revf and srcf:
1266 raise error.Abort(_('cannot specify both a revision and a source')) 1279 raise error.Abort(_(b'cannot specify both a revision and a source'))
1267 1280
1268 if not inmemory: 1281 if not inmemory:
1269 cmdutil.checkunfinished(repo) 1282 cmdutil.checkunfinished(repo)
1270 cmdutil.bailifchanged(repo) 1283 cmdutil.bailifchanged(repo)
1271 1284
1272 if ui.configbool('commands', 'rebase.requiredest') and not destf: 1285 if ui.configbool(b'commands', b'rebase.requiredest') and not destf:
1273 raise error.Abort( 1286 raise error.Abort(
1274 _('you must specify a destination'), hint=_('use: hg rebase -d REV') 1287 _(b'you must specify a destination'),
1288 hint=_(b'use: hg rebase -d REV'),
1275 ) 1289 )
1276 1290
1277 dest = None 1291 dest = None
1278 1292
1279 if revf: 1293 if revf:
1280 rebaseset = scmutil.revrange(repo, revf) 1294 rebaseset = scmutil.revrange(repo, revf)
1281 if not rebaseset: 1295 if not rebaseset:
1282 ui.status(_('empty "rev" revision set - nothing to rebase\n')) 1296 ui.status(_(b'empty "rev" revision set - nothing to rebase\n'))
1283 return None 1297 return None
1284 elif srcf: 1298 elif srcf:
1285 src = scmutil.revrange(repo, [srcf]) 1299 src = scmutil.revrange(repo, [srcf])
1286 if not src: 1300 if not src:
1287 ui.status(_('empty "source" revision set - nothing to rebase\n')) 1301 ui.status(_(b'empty "source" revision set - nothing to rebase\n'))
1288 return None 1302 return None
1289 rebaseset = repo.revs('(%ld)::', src) 1303 rebaseset = repo.revs(b'(%ld)::', src)
1290 assert rebaseset 1304 assert rebaseset
1291 else: 1305 else:
1292 base = scmutil.revrange(repo, [basef or '.']) 1306 base = scmutil.revrange(repo, [basef or b'.'])
1293 if not base: 1307 if not base:
1294 ui.status( 1308 ui.status(
1295 _('empty "base" revision set - ' "can't compute rebase set\n") 1309 _(b'empty "base" revision set - ' b"can't compute rebase set\n")
1296 ) 1310 )
1297 return None 1311 return None
1298 if destf: 1312 if destf:
1299 # --base does not support multiple destinations 1313 # --base does not support multiple destinations
1300 dest = scmutil.revsingle(repo, destf) 1314 dest = scmutil.revsingle(repo, destf)
1303 destf = bytes(dest) 1317 destf = bytes(dest)
1304 1318
1305 roots = [] # selected children of branching points 1319 roots = [] # selected children of branching points
1306 bpbase = {} # {branchingpoint: [origbase]} 1320 bpbase = {} # {branchingpoint: [origbase]}
1307 for b in base: # group bases by branching points 1321 for b in base: # group bases by branching points
1308 bp = repo.revs('ancestor(%d, %d)', b, dest.rev()).first() 1322 bp = repo.revs(b'ancestor(%d, %d)', b, dest.rev()).first()
1309 bpbase[bp] = bpbase.get(bp, []) + [b] 1323 bpbase[bp] = bpbase.get(bp, []) + [b]
1310 if None in bpbase: 1324 if None in bpbase:
1311 # emulate the old behavior, showing "nothing to rebase" (a better 1325 # emulate the old behavior, showing "nothing to rebase" (a better
1312 # behavior may be abort with "cannot find branching point" error) 1326 # behavior may be abort with "cannot find branching point" error)
1313 bpbase.clear() 1327 bpbase.clear()
1314 for bp, bs in bpbase.iteritems(): # calculate roots 1328 for bp, bs in bpbase.iteritems(): # calculate roots
1315 roots += list(repo.revs('children(%d) & ancestors(%ld)', bp, bs)) 1329 roots += list(repo.revs(b'children(%d) & ancestors(%ld)', bp, bs))
1316 1330
1317 rebaseset = repo.revs('%ld::', roots) 1331 rebaseset = repo.revs(b'%ld::', roots)
1318 1332
1319 if not rebaseset: 1333 if not rebaseset:
1320 # transform to list because smartsets are not comparable to 1334 # transform to list because smartsets are not comparable to
1321 # lists. This should be improved to honor laziness of 1335 # lists. This should be improved to honor laziness of
1322 # smartset. 1336 # smartset.
1323 if list(base) == [dest.rev()]: 1337 if list(base) == [dest.rev()]:
1324 if basef: 1338 if basef:
1325 ui.status( 1339 ui.status(
1326 _( 1340 _(
1327 'nothing to rebase - %s is both "base"' 1341 b'nothing to rebase - %s is both "base"'
1328 ' and destination\n' 1342 b' and destination\n'
1329 ) 1343 )
1330 % dest 1344 % dest
1331 ) 1345 )
1332 else: 1346 else:
1333 ui.status( 1347 ui.status(
1334 _( 1348 _(
1335 'nothing to rebase - working directory ' 1349 b'nothing to rebase - working directory '
1336 'parent is also destination\n' 1350 b'parent is also destination\n'
1337 ) 1351 )
1338 ) 1352 )
1339 elif not repo.revs('%ld - ::%d', base, dest.rev()): 1353 elif not repo.revs(b'%ld - ::%d', base, dest.rev()):
1340 if basef: 1354 if basef:
1341 ui.status( 1355 ui.status(
1342 _( 1356 _(
1343 'nothing to rebase - "base" %s is ' 1357 b'nothing to rebase - "base" %s is '
1344 'already an ancestor of destination ' 1358 b'already an ancestor of destination '
1345 '%s\n' 1359 b'%s\n'
1346 ) 1360 )
1347 % ('+'.join(bytes(repo[r]) for r in base), dest) 1361 % (b'+'.join(bytes(repo[r]) for r in base), dest)
1348 ) 1362 )
1349 else: 1363 else:
1350 ui.status( 1364 ui.status(
1351 _( 1365 _(
1352 'nothing to rebase - working ' 1366 b'nothing to rebase - working '
1353 'directory parent is already an ' 1367 b'directory parent is already an '
1354 'ancestor of destination %s\n' 1368 b'ancestor of destination %s\n'
1355 ) 1369 )
1356 % dest 1370 % dest
1357 ) 1371 )
1358 else: # can it happen? 1372 else: # can it happen?
1359 ui.status( 1373 ui.status(
1360 _('nothing to rebase from %s to %s\n') 1374 _(b'nothing to rebase from %s to %s\n')
1361 % ('+'.join(bytes(repo[r]) for r in base), dest) 1375 % (b'+'.join(bytes(repo[r]) for r in base), dest)
1362 ) 1376 )
1363 return None 1377 return None
1364 1378
1365 rebasingwcp = repo['.'].rev() in rebaseset 1379 rebasingwcp = repo[b'.'].rev() in rebaseset
1366 ui.log( 1380 ui.log(
1367 "rebase", 1381 b"rebase",
1368 "rebasing working copy parent: %r\n", 1382 b"rebasing working copy parent: %r\n",
1369 rebasingwcp, 1383 rebasingwcp,
1370 rebase_rebasing_wcp=rebasingwcp, 1384 rebase_rebasing_wcp=rebasingwcp,
1371 ) 1385 )
1372 if inmemory and rebasingwcp: 1386 if inmemory and rebasingwcp:
1373 # Check these since we did not before. 1387 # Check these since we did not before.
1376 1390
1377 if not destf: 1391 if not destf:
1378 dest = repo[_destrebase(repo, rebaseset, destspace=destspace)] 1392 dest = repo[_destrebase(repo, rebaseset, destspace=destspace)]
1379 destf = bytes(dest) 1393 destf = bytes(dest)
1380 1394
1381 allsrc = revsetlang.formatspec('%ld', rebaseset) 1395 allsrc = revsetlang.formatspec(b'%ld', rebaseset)
1382 alias = {'ALLSRC': allsrc} 1396 alias = {b'ALLSRC': allsrc}
1383 1397
1384 if dest is None: 1398 if dest is None:
1385 try: 1399 try:
1386 # fast path: try to resolve dest without SRC alias 1400 # fast path: try to resolve dest without SRC alias
1387 dest = scmutil.revsingle(repo, destf, localalias=alias) 1401 dest = scmutil.revsingle(repo, destf, localalias=alias)
1388 except error.RepoLookupError: 1402 except error.RepoLookupError:
1389 # multi-dest path: resolve dest for each SRC separately 1403 # multi-dest path: resolve dest for each SRC separately
1390 destmap = {} 1404 destmap = {}
1391 for r in rebaseset: 1405 for r in rebaseset:
1392 alias['SRC'] = revsetlang.formatspec('%d', r) 1406 alias[b'SRC'] = revsetlang.formatspec(b'%d', r)
1393 # use repo.anyrevs instead of scmutil.revsingle because we 1407 # use repo.anyrevs instead of scmutil.revsingle because we
1394 # don't want to abort if destset is empty. 1408 # don't want to abort if destset is empty.
1395 destset = repo.anyrevs([destf], user=True, localalias=alias) 1409 destset = repo.anyrevs([destf], user=True, localalias=alias)
1396 size = len(destset) 1410 size = len(destset)
1397 if size == 1: 1411 if size == 1:
1398 destmap[r] = destset.first() 1412 destmap[r] = destset.first()
1399 elif size == 0: 1413 elif size == 0:
1400 ui.note(_('skipping %s - empty destination\n') % repo[r]) 1414 ui.note(_(b'skipping %s - empty destination\n') % repo[r])
1401 else: 1415 else:
1402 raise error.Abort( 1416 raise error.Abort(
1403 _('rebase destination for %s is not ' 'unique') 1417 _(b'rebase destination for %s is not ' b'unique')
1404 % repo[r] 1418 % repo[r]
1405 ) 1419 )
1406 1420
1407 if dest is not None: 1421 if dest is not None:
1408 # single-dest case: assign dest to each rev in rebaseset 1422 # single-dest case: assign dest to each rev in rebaseset
1409 destrev = dest.rev() 1423 destrev = dest.rev()
1410 destmap = {r: destrev for r in rebaseset} # {srcrev: destrev} 1424 destmap = {r: destrev for r in rebaseset} # {srcrev: destrev}
1411 1425
1412 if not destmap: 1426 if not destmap:
1413 ui.status(_('nothing to rebase - empty destination\n')) 1427 ui.status(_(b'nothing to rebase - empty destination\n'))
1414 return None 1428 return None
1415 1429
1416 return destmap 1430 return destmap
1417 1431
1418 1432
1433 return nullrev 1447 return nullrev
1434 if len(parents) == 1: 1448 if len(parents) == 1:
1435 return parents.pop() 1449 return parents.pop()
1436 raise error.Abort( 1450 raise error.Abort(
1437 _( 1451 _(
1438 'unable to collapse on top of %d, there is more ' 1452 b'unable to collapse on top of %d, there is more '
1439 'than one external parent: %s' 1453 b'than one external parent: %s'
1440 ) 1454 )
1441 % (max(destancestors), ', '.join("%d" % p for p in sorted(parents))) 1455 % (max(destancestors), b', '.join(b"%d" % p for p in sorted(parents)))
1442 ) 1456 )
1443 1457
1444 1458
1445 def commitmemorynode(repo, p1, p2, wctx, editor, extra, user, date, commitmsg): 1459 def commitmemorynode(repo, p1, p2, wctx, editor, extra, user, date, commitmsg):
1446 '''Commit the memory changes with parents p1 and p2. 1460 '''Commit the memory changes with parents p1 and p2.
1447 Return node of committed revision.''' 1461 Return node of committed revision.'''
1448 # Replicates the empty check in ``repo.commit``. 1462 # Replicates the empty check in ``repo.commit``.
1449 if wctx.isempty() and not repo.ui.configbool('ui', 'allowemptycommit'): 1463 if wctx.isempty() and not repo.ui.configbool(b'ui', b'allowemptycommit'):
1450 return None 1464 return None
1451 1465
1452 # By convention, ``extra['branch']`` (set by extrafn) clobbers 1466 # By convention, ``extra['branch']`` (set by extrafn) clobbers
1453 # ``branch`` (used when passing ``--keepbranches``). 1467 # ``branch`` (used when passing ``--keepbranches``).
1454 branch = repo[p1].branch() 1468 branch = repo[p1].branch()
1455 if 'branch' in extra: 1469 if b'branch' in extra:
1456 branch = extra['branch'] 1470 branch = extra[b'branch']
1457 1471
1458 memctx = wctx.tomemctx( 1472 memctx = wctx.tomemctx(
1459 commitmsg, 1473 commitmsg,
1460 parents=(p1, p2), 1474 parents=(p1, p2),
1461 date=date, 1475 date=date,
1471 1485
1472 def commitnode(repo, p1, p2, editor, extra, user, date, commitmsg): 1486 def commitnode(repo, p1, p2, editor, extra, user, date, commitmsg):
1473 '''Commit the wd changes with parents p1 and p2. 1487 '''Commit the wd changes with parents p1 and p2.
1474 Return node of committed revision.''' 1488 Return node of committed revision.'''
1475 dsguard = util.nullcontextmanager() 1489 dsguard = util.nullcontextmanager()
1476 if not repo.ui.configbool('rebase', 'singletransaction'): 1490 if not repo.ui.configbool(b'rebase', b'singletransaction'):
1477 dsguard = dirstateguard.dirstateguard(repo, 'rebase') 1491 dsguard = dirstateguard.dirstateguard(repo, b'rebase')
1478 with dsguard: 1492 with dsguard:
1479 repo.setparents(repo[p1].node(), repo[p2].node()) 1493 repo.setparents(repo[p1].node(), repo[p2].node())
1480 1494
1481 # Commit might fail if unresolved files exist 1495 # Commit might fail if unresolved files exist
1482 newnode = repo.commit( 1496 newnode = repo.commit(
1486 repo.dirstate.setbranch(repo[newnode].branch()) 1500 repo.dirstate.setbranch(repo[newnode].branch())
1487 return newnode 1501 return newnode
1488 1502
1489 1503
1490 def rebasenode(repo, rev, p1, base, collapse, dest, wctx): 1504 def rebasenode(repo, rev, p1, base, collapse, dest, wctx):
1491 'Rebase a single revision rev on top of p1 using base as merge ancestor' 1505 b'Rebase a single revision rev on top of p1 using base as merge ancestor'
1492 # Merge phase 1506 # Merge phase
1493 # Update to destination and merge it with local 1507 # Update to destination and merge it with local
1494 if wctx.isinmemory(): 1508 if wctx.isinmemory():
1495 wctx.setbase(repo[p1]) 1509 wctx.setbase(repo[p1])
1496 else: 1510 else:
1497 if repo['.'].rev() != p1: 1511 if repo[b'.'].rev() != p1:
1498 repo.ui.debug(" update to %d:%s\n" % (p1, repo[p1])) 1512 repo.ui.debug(b" update to %d:%s\n" % (p1, repo[p1]))
1499 mergemod.update(repo, p1, branchmerge=False, force=True) 1513 mergemod.update(repo, p1, branchmerge=False, force=True)
1500 else: 1514 else:
1501 repo.ui.debug(" already in destination\n") 1515 repo.ui.debug(b" already in destination\n")
1502 # This is, alas, necessary to invalidate workingctx's manifest cache, 1516 # This is, alas, necessary to invalidate workingctx's manifest cache,
1503 # as well as other data we litter on it in other places. 1517 # as well as other data we litter on it in other places.
1504 wctx = repo[None] 1518 wctx = repo[None]
1505 repo.dirstate.write(repo.currenttransaction()) 1519 repo.dirstate.write(repo.currenttransaction())
1506 repo.ui.debug(" merge against %d:%s\n" % (rev, repo[rev])) 1520 repo.ui.debug(b" merge against %d:%s\n" % (rev, repo[rev]))
1507 if base is not None: 1521 if base is not None:
1508 repo.ui.debug(" detach base %d:%s\n" % (base, repo[base])) 1522 repo.ui.debug(b" detach base %d:%s\n" % (base, repo[base]))
1509 # When collapsing in-place, the parent is the common ancestor, we 1523 # When collapsing in-place, the parent is the common ancestor, we
1510 # have to allow merging with it. 1524 # have to allow merging with it.
1511 stats = mergemod.update( 1525 stats = mergemod.update(
1512 repo, 1526 repo,
1513 rev, 1527 rev,
1514 branchmerge=True, 1528 branchmerge=True,
1515 force=True, 1529 force=True,
1516 ancestor=base, 1530 ancestor=base,
1517 mergeancestor=collapse, 1531 mergeancestor=collapse,
1518 labels=['dest', 'source'], 1532 labels=[b'dest', b'source'],
1519 wc=wctx, 1533 wc=wctx,
1520 ) 1534 )
1521 if collapse: 1535 if collapse:
1522 copies.duplicatecopies(repo, wctx, rev, dest) 1536 copies.duplicatecopies(repo, wctx, rev, dest)
1523 else: 1537 else:
1593 1607
1594 result = [] 1608 result = []
1595 for prev in repo.changelog.parentrevs(rev): 1609 for prev in repo.changelog.parentrevs(rev):
1596 adjusted = dest 1610 adjusted = dest
1597 if prev != nullrev: 1611 if prev != nullrev:
1598 candidate = repo.revs('max(%ld and (::%d))', source, prev).first() 1612 candidate = repo.revs(b'max(%ld and (::%d))', source, prev).first()
1599 if candidate is not None: 1613 if candidate is not None:
1600 adjusted = state[candidate] 1614 adjusted = state[candidate]
1601 if adjusted == dest and dest in state: 1615 if adjusted == dest and dest in state:
1602 adjusted = state[dest] 1616 adjusted = state[dest]
1603 if adjusted == revtodo: 1617 if adjusted == revtodo:
1604 # sortsource should produce an order that makes this impossible 1618 # sortsource should produce an order that makes this impossible
1605 raise error.ProgrammingError( 1619 raise error.ProgrammingError(
1606 'rev %d should be rebased already at this time' % dest 1620 b'rev %d should be rebased already at this time' % dest
1607 ) 1621 )
1608 result.append(adjusted) 1622 result.append(adjusted)
1609 return result 1623 return result
1610 1624
1611 1625
1616 `rebaseobsrevs`: set of obsolete revision in source 1630 `rebaseobsrevs`: set of obsolete revision in source
1617 `rebaseobsskipped`: set of revisions from source skipped because they have 1631 `rebaseobsskipped`: set of revisions from source skipped because they have
1618 successors in destination or no non-obsolete successor. 1632 successors in destination or no non-obsolete successor.
1619 """ 1633 """
1620 # Obsolete node with successors not in dest leads to divergence 1634 # Obsolete node with successors not in dest leads to divergence
1621 divergenceok = ui.configbool('experimental', 'evolution.allowdivergence') 1635 divergenceok = ui.configbool(b'experimental', b'evolution.allowdivergence')
1622 divergencebasecandidates = rebaseobsrevs - rebaseobsskipped 1636 divergencebasecandidates = rebaseobsrevs - rebaseobsskipped
1623 1637
1624 if divergencebasecandidates and not divergenceok: 1638 if divergencebasecandidates and not divergenceok:
1625 divhashes = (bytes(repo[r]) for r in divergencebasecandidates) 1639 divhashes = (bytes(repo[r]) for r in divergencebasecandidates)
1626 msg = _("this rebase will cause " "divergences from: %s") 1640 msg = _(b"this rebase will cause " b"divergences from: %s")
1627 h = _( 1641 h = _(
1628 "to force the rebase please set " 1642 b"to force the rebase please set "
1629 "experimental.evolution.allowdivergence=True" 1643 b"experimental.evolution.allowdivergence=True"
1630 ) 1644 )
1631 raise error.Abort(msg % (",".join(divhashes),), hint=h) 1645 raise error.Abort(msg % (b",".join(divhashes),), hint=h)
1632 1646
1633 1647
1634 def successorrevs(unfi, rev): 1648 def successorrevs(unfi, rev):
1635 """yield revision numbers for successors of rev""" 1649 """yield revision numbers for successors of rev"""
1636 assert unfi.filtername is None 1650 assert unfi.filtername is None
1746 # /| # None of A and B will be changed to D and rebase fails. 1760 # /| # None of A and B will be changed to D and rebase fails.
1747 # A B D 1761 # A B D
1748 if set(newps) == set(oldps) and dest not in newps: 1762 if set(newps) == set(oldps) and dest not in newps:
1749 raise error.Abort( 1763 raise error.Abort(
1750 _( 1764 _(
1751 'cannot rebase %d:%s without ' 1765 b'cannot rebase %d:%s without '
1752 'moving at least one of its parents' 1766 b'moving at least one of its parents'
1753 ) 1767 )
1754 % (rev, repo[rev]) 1768 % (rev, repo[rev])
1755 ) 1769 )
1756 1770
1757 # Source should not be ancestor of dest. The check here guarantees it's 1771 # Source should not be ancestor of dest. The check here guarantees it's
1758 # impossible. With multi-dest, the initial check does not cover complex 1772 # impossible. With multi-dest, the initial check does not cover complex
1759 # cases since we don't have abstractions to dry-run rebase cheaply. 1773 # cases since we don't have abstractions to dry-run rebase cheaply.
1760 if any(p != nullrev and isancestor(rev, p) for p in newps): 1774 if any(p != nullrev and isancestor(rev, p) for p in newps):
1761 raise error.Abort(_('source is ancestor of destination')) 1775 raise error.Abort(_(b'source is ancestor of destination'))
1762 1776
1763 # "rebasenode" updates to new p1, use the corresponding merge base. 1777 # "rebasenode" updates to new p1, use the corresponding merge base.
1764 if bases[0] != nullrev: 1778 if bases[0] != nullrev:
1765 base = bases[0] 1779 base = bases[0]
1766 else: 1780 else:
1787 if base == nullrev: 1801 if base == nullrev:
1788 continue 1802 continue
1789 # Revisions in the side (not chosen as merge base) branch that 1803 # Revisions in the side (not chosen as merge base) branch that
1790 # might contain "surprising" contents 1804 # might contain "surprising" contents
1791 siderevs = list( 1805 siderevs = list(
1792 repo.revs('((%ld-%d) %% (%d+%d))', bases, base, base, dest) 1806 repo.revs(b'((%ld-%d) %% (%d+%d))', bases, base, base, dest)
1793 ) 1807 )
1794 1808
1795 # If those revisions are covered by rebaseset, the result is good. 1809 # If those revisions are covered by rebaseset, the result is good.
1796 # A merge in rebaseset would be considered to cover its ancestors. 1810 # A merge in rebaseset would be considered to cover its ancestors.
1797 if siderevs: 1811 if siderevs:
1801 merges = [ 1815 merges = [
1802 r for r in rebaseset if cl.parentrevs(r)[1] != nullrev 1816 r for r in rebaseset if cl.parentrevs(r)[1] != nullrev
1803 ] 1817 ]
1804 unwanted[i] = list( 1818 unwanted[i] = list(
1805 repo.revs( 1819 repo.revs(
1806 '%ld - (::%ld) - %ld', siderevs, merges, rebaseset 1820 b'%ld - (::%ld) - %ld', siderevs, merges, rebaseset
1807 ) 1821 )
1808 ) 1822 )
1809 1823
1810 # Choose a merge base that has a minimal number of unwanted revs. 1824 # Choose a merge base that has a minimal number of unwanted revs.
1811 l, i = min( 1825 l, i = min(
1823 newps[0], newps[i] = newps[i], newps[0] 1837 newps[0], newps[i] = newps[i], newps[0]
1824 1838
1825 # The merge will include unwanted revisions. Abort now. Revisit this if 1839 # The merge will include unwanted revisions. Abort now. Revisit this if
1826 # we have a more advanced merge algorithm that handles multiple bases. 1840 # we have a more advanced merge algorithm that handles multiple bases.
1827 if l > 0: 1841 if l > 0:
1828 unwanteddesc = _(' or ').join( 1842 unwanteddesc = _(b' or ').join(
1829 ( 1843 (
1830 ', '.join('%d:%s' % (r, repo[r]) for r in revs) 1844 b', '.join(b'%d:%s' % (r, repo[r]) for r in revs)
1831 for revs in unwanted 1845 for revs in unwanted
1832 if revs is not None 1846 if revs is not None
1833 ) 1847 )
1834 ) 1848 )
1835 raise error.Abort( 1849 raise error.Abort(
1836 _('rebasing %d:%s will include unwanted changes from %s') 1850 _(b'rebasing %d:%s will include unwanted changes from %s')
1837 % (rev, repo[rev], unwanteddesc) 1851 % (rev, repo[rev], unwanteddesc)
1838 ) 1852 )
1839 1853
1840 repo.ui.debug(" future parents are %d and %d\n" % tuple(newps)) 1854 repo.ui.debug(b" future parents are %d and %d\n" % tuple(newps))
1841 1855
1842 return newps[0], newps[1], base 1856 return newps[0], newps[1], base
1843 1857
1844 1858
1845 def isagitpatch(repo, patchname): 1859 def isagitpatch(repo, patchname):
1846 'Return true if the given patch is in git format' 1860 b'Return true if the given patch is in git format'
1847 mqpatch = os.path.join(repo.mq.path, patchname) 1861 mqpatch = os.path.join(repo.mq.path, patchname)
1848 for line in patch.linereader(open(mqpatch, 'rb')): 1862 for line in patch.linereader(open(mqpatch, b'rb')):
1849 if line.startswith('diff --git'): 1863 if line.startswith(b'diff --git'):
1850 return True 1864 return True
1851 return False 1865 return False
1852 1866
1853 1867
1854 def updatemq(repo, state, skipped, **opts): 1868 def updatemq(repo, state, skipped, **opts):
1855 'Update rebased mq patches - finalize and then import them' 1869 b'Update rebased mq patches - finalize and then import them'
1856 mqrebase = {} 1870 mqrebase = {}
1857 mq = repo.mq 1871 mq = repo.mq
1858 original_series = mq.fullseries[:] 1872 original_series = mq.fullseries[:]
1859 skippedpatches = set() 1873 skippedpatches = set()
1860 1874
1861 for p in mq.applied: 1875 for p in mq.applied:
1862 rev = repo[p.node].rev() 1876 rev = repo[p.node].rev()
1863 if rev in state: 1877 if rev in state:
1864 repo.ui.debug( 1878 repo.ui.debug(
1865 'revision %d is an mq patch (%s), finalize it.\n' 1879 b'revision %d is an mq patch (%s), finalize it.\n'
1866 % (rev, p.name) 1880 % (rev, p.name)
1867 ) 1881 )
1868 mqrebase[rev] = (p.name, isagitpatch(repo, p.name)) 1882 mqrebase[rev] = (p.name, isagitpatch(repo, p.name))
1869 else: 1883 else:
1870 # Applied but not rebased, not sure this should happen 1884 # Applied but not rebased, not sure this should happen
1876 # We must start import from the newest revision 1890 # We must start import from the newest revision
1877 for rev in sorted(mqrebase, reverse=True): 1891 for rev in sorted(mqrebase, reverse=True):
1878 if rev not in skipped: 1892 if rev not in skipped:
1879 name, isgit = mqrebase[rev] 1893 name, isgit = mqrebase[rev]
1880 repo.ui.note( 1894 repo.ui.note(
1881 _('updating mq patch %s to %d:%s\n') 1895 _(b'updating mq patch %s to %d:%s\n')
1882 % (name, state[rev], repo[state[rev]]) 1896 % (name, state[rev], repo[state[rev]])
1883 ) 1897 )
1884 mq.qimport( 1898 mq.qimport(
1885 repo, (), patchname=name, git=isgit, rev=["%d" % state[rev]] 1899 repo,
1900 (),
1901 patchname=name,
1902 git=isgit,
1903 rev=[b"%d" % state[rev]],
1886 ) 1904 )
1887 else: 1905 else:
1888 # Rebased and skipped 1906 # Rebased and skipped
1889 skippedpatches.add(mqrebase[rev][0]) 1907 skippedpatches.add(mqrebase[rev][0])
1890 1908
1900 mq.seriesdirty = True 1918 mq.seriesdirty = True
1901 mq.savedirty() 1919 mq.savedirty()
1902 1920
1903 1921
1904 def storecollapsemsg(repo, collapsemsg): 1922 def storecollapsemsg(repo, collapsemsg):
1905 'Store the collapse message to allow recovery' 1923 b'Store the collapse message to allow recovery'
1906 collapsemsg = collapsemsg or '' 1924 collapsemsg = collapsemsg or b''
1907 f = repo.vfs("last-message.txt", "w") 1925 f = repo.vfs(b"last-message.txt", b"w")
1908 f.write("%s\n" % collapsemsg) 1926 f.write(b"%s\n" % collapsemsg)
1909 f.close() 1927 f.close()
1910 1928
1911 1929
1912 def clearcollapsemsg(repo): 1930 def clearcollapsemsg(repo):
1913 'Remove collapse message file' 1931 b'Remove collapse message file'
1914 repo.vfs.unlinkpath("last-message.txt", ignoremissing=True) 1932 repo.vfs.unlinkpath(b"last-message.txt", ignoremissing=True)
1915 1933
1916 1934
1917 def restorecollapsemsg(repo, isabort): 1935 def restorecollapsemsg(repo, isabort):
1918 'Restore previously stored collapse message' 1936 b'Restore previously stored collapse message'
1919 try: 1937 try:
1920 f = repo.vfs("last-message.txt") 1938 f = repo.vfs(b"last-message.txt")
1921 collapsemsg = f.readline().strip() 1939 collapsemsg = f.readline().strip()
1922 f.close() 1940 f.close()
1923 except IOError as err: 1941 except IOError as err:
1924 if err.errno != errno.ENOENT: 1942 if err.errno != errno.ENOENT:
1925 raise 1943 raise
1926 if isabort: 1944 if isabort:
1927 # Oh well, just abort like normal 1945 # Oh well, just abort like normal
1928 collapsemsg = '' 1946 collapsemsg = b''
1929 else: 1947 else:
1930 raise error.Abort(_('missing .hg/last-message.txt for rebase')) 1948 raise error.Abort(_(b'missing .hg/last-message.txt for rebase'))
1931 return collapsemsg 1949 return collapsemsg
1932 1950
1933 1951
1934 def clearstatus(repo): 1952 def clearstatus(repo):
1935 'Remove the status files' 1953 b'Remove the status files'
1936 # Make sure the active transaction won't write the state file 1954 # Make sure the active transaction won't write the state file
1937 tr = repo.currenttransaction() 1955 tr = repo.currenttransaction()
1938 if tr: 1956 if tr:
1939 tr.removefilegenerator('rebasestate') 1957 tr.removefilegenerator(b'rebasestate')
1940 repo.vfs.unlinkpath("rebasestate", ignoremissing=True) 1958 repo.vfs.unlinkpath(b"rebasestate", ignoremissing=True)
1941 1959
1942 1960
1943 def needupdate(repo, state): 1961 def needupdate(repo, state):
1944 '''check whether we should `update --clean` away from a merge, or if 1962 '''check whether we should `update --clean` away from a merge, or if
1945 somehow the working dir got forcibly updated, e.g. by older hg''' 1963 somehow the working dir got forcibly updated, e.g. by older hg'''
1978 result = [] 1996 result = []
1979 for r in srclist: 1997 for r in srclist:
1980 if destmap[r] not in srcset: 1998 if destmap[r] not in srcset:
1981 result.append(r) 1999 result.append(r)
1982 if not result: 2000 if not result:
1983 raise error.Abort(_('source and destination form a cycle')) 2001 raise error.Abort(_(b'source and destination form a cycle'))
1984 srcset -= set(result) 2002 srcset -= set(result)
1985 yield result 2003 yield result
1986 2004
1987 2005
1988 def buildstate(repo, destmap, collapse): 2006 def buildstate(repo, destmap, collapse):
1990 2008
1991 repo: repo 2009 repo: repo
1992 destmap: {srcrev: destrev} 2010 destmap: {srcrev: destrev}
1993 ''' 2011 '''
1994 rebaseset = destmap.keys() 2012 rebaseset = destmap.keys()
1995 originalwd = repo['.'].rev() 2013 originalwd = repo[b'.'].rev()
1996 2014
1997 # This check isn't strictly necessary, since mq detects commits over an 2015 # This check isn't strictly necessary, since mq detects commits over an
1998 # applied patch. But it prevents messing up the working directory when 2016 # applied patch. But it prevents messing up the working directory when
1999 # a partially completed rebase is blocked by mq. 2017 # a partially completed rebase is blocked by mq.
2000 if 'qtip' in repo.tags(): 2018 if b'qtip' in repo.tags():
2001 mqapplied = set(repo[s.node].rev() for s in repo.mq.applied) 2019 mqapplied = set(repo[s.node].rev() for s in repo.mq.applied)
2002 if set(destmap.values()) & mqapplied: 2020 if set(destmap.values()) & mqapplied:
2003 raise error.Abort(_('cannot rebase onto an applied mq patch')) 2021 raise error.Abort(_(b'cannot rebase onto an applied mq patch'))
2004 2022
2005 # Get "cycle" error early by exhausting the generator. 2023 # Get "cycle" error early by exhausting the generator.
2006 sortedsrc = list(sortsource(destmap)) # a list of sorted revs 2024 sortedsrc = list(sortsource(destmap)) # a list of sorted revs
2007 if not sortedsrc: 2025 if not sortedsrc:
2008 raise error.Abort(_('no matching revisions')) 2026 raise error.Abort(_(b'no matching revisions'))
2009 2027
2010 # Only check the first batch of revisions to rebase not depending on other 2028 # Only check the first batch of revisions to rebase not depending on other
2011 # rebaseset. This means "source is ancestor of destination" for the second 2029 # rebaseset. This means "source is ancestor of destination" for the second
2012 # (and following) batches of revisions are not checked here. We rely on 2030 # (and following) batches of revisions are not checked here. We rely on
2013 # "defineparents" to do that check. 2031 # "defineparents" to do that check.
2014 roots = list(repo.set('roots(%ld)', sortedsrc[0])) 2032 roots = list(repo.set(b'roots(%ld)', sortedsrc[0]))
2015 if not roots: 2033 if not roots:
2016 raise error.Abort(_('no matching revisions')) 2034 raise error.Abort(_(b'no matching revisions'))
2017 2035
2018 def revof(r): 2036 def revof(r):
2019 return r.rev() 2037 return r.rev()
2020 2038
2021 roots = sorted(roots, key=revof) 2039 roots = sorted(roots, key=revof)
2023 emptyrebase = len(sortedsrc) == 1 2041 emptyrebase = len(sortedsrc) == 1
2024 for root in roots: 2042 for root in roots:
2025 dest = repo[destmap[root.rev()]] 2043 dest = repo[destmap[root.rev()]]
2026 commonbase = root.ancestor(dest) 2044 commonbase = root.ancestor(dest)
2027 if commonbase == root: 2045 if commonbase == root:
2028 raise error.Abort(_('source is ancestor of destination')) 2046 raise error.Abort(_(b'source is ancestor of destination'))
2029 if commonbase == dest: 2047 if commonbase == dest:
2030 wctx = repo[None] 2048 wctx = repo[None]
2031 if dest == wctx.p1(): 2049 if dest == wctx.p1():
2032 # when rebasing to '.', it will use the current wd branch name 2050 # when rebasing to '.', it will use the current wd branch name
2033 samebranch = root.branch() == wctx.branch() 2051 samebranch = root.branch() == wctx.branch()
2035 samebranch = root.branch() == dest.branch() 2053 samebranch = root.branch() == dest.branch()
2036 if not collapse and samebranch and dest in root.parents(): 2054 if not collapse and samebranch and dest in root.parents():
2037 # mark the revision as done by setting its new revision 2055 # mark the revision as done by setting its new revision
2038 # equal to its old (current) revisions 2056 # equal to its old (current) revisions
2039 state[root.rev()] = root.rev() 2057 state[root.rev()] = root.rev()
2040 repo.ui.debug('source is a child of destination\n') 2058 repo.ui.debug(b'source is a child of destination\n')
2041 continue 2059 continue
2042 2060
2043 emptyrebase = False 2061 emptyrebase = False
2044 repo.ui.debug('rebase onto %s starting from %s\n' % (dest, root)) 2062 repo.ui.debug(b'rebase onto %s starting from %s\n' % (dest, root))
2045 if emptyrebase: 2063 if emptyrebase:
2046 return None 2064 return None
2047 for rev in sorted(state): 2065 for rev in sorted(state):
2048 parents = [p for p in repo.changelog.parentrevs(rev) if p != nullrev] 2066 parents = [p for p in repo.changelog.parentrevs(rev) if p != nullrev]
2049 # if all parents of this revision are done, then so is this revision 2067 # if all parents of this revision are done, then so is this revision
2102 fl = fm.formatlist 2120 fl = fm.formatlist
2103 fd = fm.formatdict 2121 fd = fm.formatdict
2104 changes = {} 2122 changes = {}
2105 for oldns, newn in replacements.iteritems(): 2123 for oldns, newn in replacements.iteritems():
2106 for oldn in oldns: 2124 for oldn in oldns:
2107 changes[hf(oldn)] = fl([hf(n) for n in newn], name='node') 2125 changes[hf(oldn)] = fl([hf(n) for n in newn], name=b'node')
2108 nodechanges = fd(changes, key="oldnode", value="newnodes") 2126 nodechanges = fd(changes, key=b"oldnode", value=b"newnodes")
2109 fm.data(nodechanges=nodechanges) 2127 fm.data(nodechanges=nodechanges)
2110 if keepf: 2128 if keepf:
2111 replacements = {} 2129 replacements = {}
2112 scmutil.cleanupnodes(repo, replacements, 'rebase', moves, backup=backup) 2130 scmutil.cleanupnodes(repo, replacements, b'rebase', moves, backup=backup)
2113 2131
2114 2132
2115 def pullrebase(orig, ui, repo, *args, **opts): 2133 def pullrebase(orig, ui, repo, *args, **opts):
2116 'Call rebase after pull if the latter has been invoked with --rebase' 2134 b'Call rebase after pull if the latter has been invoked with --rebase'
2117 if opts.get(r'rebase'): 2135 if opts.get(r'rebase'):
2118 if ui.configbool('commands', 'rebase.requiredest'): 2136 if ui.configbool(b'commands', b'rebase.requiredest'):
2119 msg = _('rebase destination required by configuration') 2137 msg = _(b'rebase destination required by configuration')
2120 hint = _('use hg pull followed by hg rebase -d DEST') 2138 hint = _(b'use hg pull followed by hg rebase -d DEST')
2121 raise error.Abort(msg, hint=hint) 2139 raise error.Abort(msg, hint=hint)
2122 2140
2123 with repo.wlock(), repo.lock(): 2141 with repo.wlock(), repo.lock():
2124 if opts.get(r'update'): 2142 if opts.get(r'update'):
2125 del opts[r'update'] 2143 del opts[r'update']
2126 ui.debug( 2144 ui.debug(
2127 '--update and --rebase are not compatible, ignoring ' 2145 b'--update and --rebase are not compatible, ignoring '
2128 'the update flag\n' 2146 b'the update flag\n'
2129 ) 2147 )
2130 2148
2131 cmdutil.checkunfinished(repo, skipmerge=True) 2149 cmdutil.checkunfinished(repo, skipmerge=True)
2132 cmdutil.bailifchanged( 2150 cmdutil.bailifchanged(
2133 repo, 2151 repo,
2134 hint=_( 2152 hint=_(
2135 'cannot pull with rebase: ' 2153 b'cannot pull with rebase: '
2136 'please commit or shelve your changes first' 2154 b'please commit or shelve your changes first'
2137 ), 2155 ),
2138 ) 2156 )
2139 2157
2140 revsprepull = len(repo) 2158 revsprepull = len(repo)
2141 origpostincoming = commands.postincoming 2159 origpostincoming = commands.postincoming
2164 try: 2182 try:
2165 rebase(ui, repo, **opts) 2183 rebase(ui, repo, **opts)
2166 except error.NoMergeDestAbort: 2184 except error.NoMergeDestAbort:
2167 # we can maybe update instead 2185 # we can maybe update instead
2168 rev, _a, _b = destutil.destupdate(repo) 2186 rev, _a, _b = destutil.destupdate(repo)
2169 if rev == repo['.'].rev(): 2187 if rev == repo[b'.'].rev():
2170 ui.status(_('nothing to rebase\n')) 2188 ui.status(_(b'nothing to rebase\n'))
2171 else: 2189 else:
2172 ui.status(_('nothing to rebase - updating instead\n')) 2190 ui.status(_(b'nothing to rebase - updating instead\n'))
2173 # not passing argument to get the bare update behavior 2191 # not passing argument to get the bare update behavior
2174 # with warning and trumpets 2192 # with warning and trumpets
2175 commands.update(ui, repo) 2193 commands.update(ui, repo)
2176 else: 2194 else:
2177 if opts.get(r'tool'): 2195 if opts.get(r'tool'):
2178 raise error.Abort(_('--tool can only be used with --rebase')) 2196 raise error.Abort(_(b'--tool can only be used with --rebase'))
2179 ret = orig(ui, repo, *args, **opts) 2197 ret = orig(ui, repo, *args, **opts)
2180 2198
2181 return ret 2199 return ret
2182 2200
2183 2201
2203 obsoleteextinctsuccessors = set() 2221 obsoleteextinctsuccessors = set()
2204 2222
2205 assert repo.filtername is None 2223 assert repo.filtername is None
2206 cl = repo.changelog 2224 cl = repo.changelog
2207 nodemap = cl.nodemap 2225 nodemap = cl.nodemap
2208 extinctrevs = set(repo.revs('extinct()')) 2226 extinctrevs = set(repo.revs(b'extinct()'))
2209 for srcrev in rebaseobsrevs: 2227 for srcrev in rebaseobsrevs:
2210 srcnode = cl.node(srcrev) 2228 srcnode = cl.node(srcrev)
2211 # XXX: more advanced APIs are required to handle split correctly 2229 # XXX: more advanced APIs are required to handle split correctly
2212 successors = set(obsutil.allsuccessors(repo.obsstore, [srcnode])) 2230 successors = set(obsutil.allsuccessors(repo.obsstore, [srcnode]))
2213 # obsutil.allsuccessors includes node itself 2231 # obsutil.allsuccessors includes node itself
2256 rbsrt._performrebase(None) 2274 rbsrt._performrebase(None)
2257 rbsrt._finishrebase() 2275 rbsrt._finishrebase()
2258 2276
2259 2277
2260 def summaryhook(ui, repo): 2278 def summaryhook(ui, repo):
2261 if not repo.vfs.exists('rebasestate'): 2279 if not repo.vfs.exists(b'rebasestate'):
2262 return 2280 return
2263 try: 2281 try:
2264 rbsrt = rebaseruntime(repo, ui, {}) 2282 rbsrt = rebaseruntime(repo, ui, {})
2265 rbsrt.restorestatus() 2283 rbsrt.restorestatus()
2266 state = rbsrt.state 2284 state = rbsrt.state
2267 except error.RepoLookupError: 2285 except error.RepoLookupError:
2268 # i18n: column positioning for "hg summary" 2286 # i18n: column positioning for "hg summary"
2269 msg = _('rebase: (use "hg rebase --abort" to clear broken state)\n') 2287 msg = _(b'rebase: (use "hg rebase --abort" to clear broken state)\n')
2270 ui.write(msg) 2288 ui.write(msg)
2271 return 2289 return
2272 numrebased = len([i for i in state.itervalues() if i >= 0]) 2290 numrebased = len([i for i in state.itervalues() if i >= 0])
2273 # i18n: column positioning for "hg summary" 2291 # i18n: column positioning for "hg summary"
2274 ui.write( 2292 ui.write(
2275 _('rebase: %s, %s (rebase --continue)\n') 2293 _(b'rebase: %s, %s (rebase --continue)\n')
2276 % ( 2294 % (
2277 ui.label(_('%d rebased'), 'rebase.rebased') % numrebased, 2295 ui.label(_(b'%d rebased'), b'rebase.rebased') % numrebased,
2278 ui.label(_('%d remaining'), 'rebase.remaining') 2296 ui.label(_(b'%d remaining'), b'rebase.remaining')
2279 % (len(state) - numrebased), 2297 % (len(state) - numrebased),
2280 ) 2298 )
2281 ) 2299 )
2282 2300
2283 2301
2284 def uisetup(ui): 2302 def uisetup(ui):
2285 # Replace pull with a decorator to provide --rebase option 2303 # Replace pull with a decorator to provide --rebase option
2286 entry = extensions.wrapcommand(commands.table, 'pull', pullrebase) 2304 entry = extensions.wrapcommand(commands.table, b'pull', pullrebase)
2287 entry[1].append( 2305 entry[1].append(
2288 ('', 'rebase', None, _("rebase working directory to branch head")) 2306 (b'', b'rebase', None, _(b"rebase working directory to branch head"))
2289 ) 2307 )
2290 entry[1].append(('t', 'tool', '', _("specify merge tool for rebase"))) 2308 entry[1].append((b't', b'tool', b'', _(b"specify merge tool for rebase")))
2291 cmdutil.summaryhooks.add('rebase', summaryhook) 2309 cmdutil.summaryhooks.add(b'rebase', summaryhook)
2292 statemod.addunfinished( 2310 statemod.addunfinished(
2293 'rebase', 2311 b'rebase',
2294 fname='rebasestate', 2312 fname=b'rebasestate',
2295 stopflag=True, 2313 stopflag=True,
2296 continueflag=True, 2314 continueflag=True,
2297 abortfunc=abortrebase, 2315 abortfunc=abortrebase,
2298 continuefunc=continuerebase, 2316 continuefunc=continuerebase,
2299 ) 2317 )