##// END OF EJS Templates
upgrade: split actual upgrade code away from the main module...
upgrade: split actual upgrade code away from the main module The main module is getting big and hard to follow. So we are splitting all the logic to actually run an upgrade in a sub module. It nicely highlight that there are very few actual call point to the code we just moved. Differential Revision: https://phab.mercurial-scm.org/D9476

File last commit:

r46488:568c05d8 default
r46661:f105c49e default
Show More
split.py
191 lines | 6.0 KiB | text/x-python | PythonLexer
Jun Wu
split: new extension to split changesets...
r35471 # split.py - split a changeset into smaller ones
#
# Copyright 2015 Laurent Charignon <lcharignon@fb.com>
# Copyright 2017 Facebook, Inc.
#
# This software may be used and distributed according to the terms of the
# GNU General Public License version 2 or any later version.
"""command to split a changeset into smaller ones (EXPERIMENTAL)"""
from __future__ import absolute_import
from mercurial.i18n import _
from mercurial.node import (
nullid,
short,
)
from mercurial import (
bookmarks,
cmdutil,
commands,
error,
hg,
Pulkit Goyal
py3: fix handling of keyword arguments at more places...
r36418 pycompat,
Jun Wu
split: new extension to split changesets...
r35471 registrar,
revsetlang,
Martin von Zweigbergk
split: use rewriteutil.precheck() instead of reimplementing it...
r44387 rewriteutil,
Jun Wu
split: new extension to split changesets...
r35471 scmutil,
)
# allow people to use split without explicitly enabling rebase extension
Augie Fackler
formatting: blacken the codebase...
r43346 from . import rebase
Jun Wu
split: new extension to split changesets...
r35471
cmdtable = {}
command = registrar.command(cmdtable)
# Note for extension authors: ONLY specify testedwith = 'ships-with-hg-core' for
# extensions which SHIP WITH MERCURIAL. Non-mainline extensions should
# be specifying the version(s) of Mercurial they are tested with, or
# leave the attribute unspecified.
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 testedwith = b'ships-with-hg-core'
Jun Wu
split: new extension to split changesets...
r35471
Augie Fackler
formatting: blacken the codebase...
r43346
@command(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 b'split',
Augie Fackler
formatting: blacken the codebase...
r43346 [
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 (b'r', b'rev', b'', _(b"revision to split"), _(b'REV')),
(b'', b'rebase', True, _(b'rebase descendants after split')),
Augie Fackler
formatting: blacken the codebase...
r43346 ]
+ cmdutil.commitopts2,
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 _(b'hg split [--no-rebase] [[-r] REV]'),
Augie Fackler
formatting: blacken the codebase...
r43346 helpcategory=command.CATEGORY_CHANGE_MANAGEMENT,
helpbasic=True,
)
Jun Wu
split: new extension to split changesets...
r35471 def split(ui, repo, *revs, **opts):
"""split a changeset into smaller ones
Repeatedly prompt changes and commit message for new changesets until there
is nothing left in the original changeset.
If --rev was not given, split the working directory parent.
By default, rebase connected non-obsoleted descendants onto the new
changeset. Use --no-rebase to avoid the rebase.
"""
Pulkit Goyal
py3: fix kwargs handling in hgext/split.py...
r38080 opts = pycompat.byteskwargs(opts)
Jun Wu
split: new extension to split changesets...
r35471 revlist = []
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 if opts.get(b'rev'):
revlist.append(opts.get(b'rev'))
Jun Wu
split: new extension to split changesets...
r35471 revlist.extend(revs)
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 with repo.wlock(), repo.lock(), repo.transaction(b'split') as tr:
revs = scmutil.revrange(repo, revlist or [b'.'])
Jun Wu
split: new extension to split changesets...
r35471 if len(revs) > 1:
Martin von Zweigbergk
errors: raise InputError in `hg split`...
r46488 raise error.InputError(_(b'cannot split multiple revisions'))
Jun Wu
split: new extension to split changesets...
r35471
rev = revs.first()
ctx = repo[rev]
Martin von Zweigbergk
split: use rewriteutil.precheck() instead of reimplementing it...
r44387 # Handle nullid specially here (instead of leaving for precheck()
# below) so we get a nicer message and error code.
Jun Wu
split: new extension to split changesets...
r35471 if rev is None or ctx.node() == nullid:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 ui.status(_(b'nothing to split\n'))
Jun Wu
split: new extension to split changesets...
r35471 return 1
if ctx.node() is None:
Martin von Zweigbergk
errors: raise InputError in `hg split`...
r46488 raise error.InputError(_(b'cannot split working directory'))
Jun Wu
split: new extension to split changesets...
r35471
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 if opts.get(b'rebase'):
Jun Wu
split: new extension to split changesets...
r35471 # Skip obsoleted descendants and their descendants so the rebase
# won't cause conflicts for sure.
Martin von Zweigbergk
split: use rewriteutil.precheck() instead of reimplementing it...
r44387 descendants = list(repo.revs(b'(%d::) - (%d)', rev, rev))
Augie Fackler
formatting: blacken the codebase...
r43346 torebase = list(
repo.revs(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 b'%ld - (%ld & obsolete())::', descendants, descendants
Augie Fackler
formatting: blacken the codebase...
r43346 )
)
Jun Wu
split: new extension to split changesets...
r35471 else:
Martin von Zweigbergk
split: use rewriteutil.precheck() instead of reimplementing it...
r44387 torebase = []
rewriteutil.precheck(repo, [rev] + torebase, b'split')
Jun Wu
split: new extension to split changesets...
r35471
if len(ctx.parents()) > 1:
Martin von Zweigbergk
errors: raise InputError in `hg split`...
r46488 raise error.InputError(_(b'cannot split a merge changeset'))
Jun Wu
split: new extension to split changesets...
r35471
cmdutil.bailifchanged(repo)
# Deactivate bookmark temporarily so it won't get moved unintentionally
bname = repo._activebookmark
if bname and repo._bookmarks[bname] != ctx.node():
bookmarks.deactivate(repo)
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 wnode = repo[b'.'].node()
Jun Wu
split: new extension to split changesets...
r35471 top = None
try:
top = dosplit(ui, repo, tr, ctx, opts)
finally:
# top is None: split failed, need update --clean recovery.
# wnode == ctx.node(): wnode split, no need to update.
if top is None or wnode != ctx.node():
hg.clean(repo, wnode, show_stats=False)
if bname:
bookmarks.activate(repo, bname)
if torebase and top:
dorebase(ui, repo, torebase, top)
Augie Fackler
formatting: blacken the codebase...
r43346
Jun Wu
split: new extension to split changesets...
r35471 def dosplit(ui, repo, tr, ctx, opts):
Augie Fackler
formatting: blacken the codebase...
r43346 committed = [] # [ctx]
Jun Wu
split: new extension to split changesets...
r35471
# Set working parent to ctx.p1(), and keep working copy as ctx's content
Martin von Zweigbergk
split: use the new movedirstate() we now have in scmutil...
r42132 if ctx.node() != repo.dirstate.p1():
hg.clean(repo, ctx.node(), show_stats=False)
with repo.dirstate.parentchange():
scmutil.movedirstate(repo, ctx.p1())
Jun Wu
split: new extension to split changesets...
r35471
# Any modified, added, removed, deleted result means split is incomplete
Augie Fackler
split: use field names instead of field numbers on scmutil.status...
r44040 def incomplete(repo):
st = repo.status()
return any((st.modified, st.added, st.removed, st.deleted))
Jun Wu
split: new extension to split changesets...
r35471
# Main split loop
while incomplete(repo):
if committed:
Augie Fackler
formatting: blacken the codebase...
r43346 header = _(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 b'HG: Splitting %s. So far it has been split into:\n'
Augie Fackler
formatting: blacken the codebase...
r43346 ) % short(ctx.node())
Martin von Zweigbergk
split: disable color while rendering template for use in commit message...
r46460 # We don't want color codes in the commit message template, so
# disable the label() template function while we render it.
with ui.configoverride(
{(b'templatealias', b'label(l,x)'): b"x"}, b'split'
):
for c in committed:
summary = cmdutil.format_changeset_summary(ui, c, b'split')
header += _(b'HG: - %s\n') % summary
Augie Fackler
formatting: blacken the codebase...
r43346 header += _(
Martin von Zweigbergk
cleanup: join string literals that are already on one line...
r43387 b'HG: Write commit message for the next split changeset.\n'
Augie Fackler
formatting: blacken the codebase...
r43346 )
Jun Wu
split: new extension to split changesets...
r35471 else:
Augie Fackler
formatting: blacken the codebase...
r43346 header = _(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 b'HG: Splitting %s. Write commit message for the '
b'first split changeset.\n'
Augie Fackler
formatting: blacken the codebase...
r43346 ) % short(ctx.node())
opts.update(
{
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 b'edit': True,
b'interactive': True,
b'message': header + ctx.description(),
Augie Fackler
formatting: blacken the codebase...
r43346 }
)
Pulkit Goyal
py3: fix handling of keyword arguments at more places...
r36418 commands.commit(ui, repo, **pycompat.strkwargs(opts))
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 newctx = repo[b'.']
Jun Wu
split: new extension to split changesets...
r35471 committed.append(newctx)
if not committed:
Martin von Zweigbergk
errors: raise InputError in `hg split`...
r46488 raise error.InputError(_(b'cannot split an empty revision'))
Jun Wu
split: new extension to split changesets...
r35471
Augie Fackler
formatting: blacken the codebase...
r43346 scmutil.cleanupnodes(
repo,
{ctx.node(): [c.node() for c in committed]},
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 operation=b'split',
Augie Fackler
formatting: blacken the codebase...
r43346 fixphase=True,
)
Jun Wu
split: new extension to split changesets...
r35471
return committed[-1]
Augie Fackler
formatting: blacken the codebase...
r43346
Gregory Szorc
split: use ctx.rev() instead of %d % ctx...
r36426 def dorebase(ui, repo, src, destctx):
Augie Fackler
formatting: blacken the codebase...
r43346 rebase.rebase(
ui,
repo,
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 rev=[revsetlang.formatspec(b'%ld', src)],
dest=revsetlang.formatspec(b'%d', destctx.rev()),
Augie Fackler
formatting: blacken the codebase...
r43346 )