##// END OF EJS Templates
ui: define (write|status|warn|note)noi18n aliases...
ui: define (write|status|warn|note)noi18n aliases We currently use `write(('...'))` to suppress check-code warnings about not using translated strings. However, when we run black, it will strip the `((...))`. In order to placate black, we'll need to use a different mechanism to pass untranslatable strings. This commit introduces a `writenoi18n` alias (and friends) to `write` for that purpose. Differential Revision: https://phab.mercurial-scm.org/D6994

File last commit:

r43347:687b865b default
r43349:5209fc94 default
Show More
split.py
204 lines | 6.5 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,
obsolete,
phases,
Pulkit Goyal
py3: fix handling of keyword arguments at more places...
r36418 pycompat,
Jun Wu
split: new extension to split changesets...
r35471 registrar,
revsetlang,
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:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 raise error.Abort(_(b'cannot split multiple revisions'))
Jun Wu
split: new extension to split changesets...
r35471
rev = revs.first()
ctx = repo[rev]
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:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 raise error.Abort(_(b'cannot split working directory'))
Jun Wu
split: new extension to split changesets...
r35471
# rewriteutil.precheck is not very useful here because:
# 1. null check is done above and it's more friendly to return 1
# instead of abort
# 2. mergestate check is done below by cmdutil.bailifchanged
# 3. unstable check is more complex here because of --rebase
#
# So only "public" check is useful and it's checked directly here.
if ctx.phase() == phases.public:
Augie Fackler
formatting: blacken the codebase...
r43346 raise error.Abort(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 _(b'cannot split public changeset'),
hint=_(b"see 'hg help phases' for details"),
Augie Fackler
formatting: blacken the codebase...
r43346 )
Jun Wu
split: new extension to split changesets...
r35471
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 descendants = list(repo.revs(b'(%d::) - (%d)', rev, rev))
Jun Wu
split: new extension to split changesets...
r35471 alloworphaned = obsolete.isenabled(repo, obsolete.allowunstableopt)
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.
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 if not alloworphaned and len(torebase) != len(descendants):
Augie Fackler
formatting: blacken the codebase...
r43346 raise error.Abort(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 _(b'split would leave orphaned changesets ' b'behind')
Augie Fackler
formatting: blacken the codebase...
r43346 )
Jun Wu
split: new extension to split changesets...
r35471 else:
if not alloworphaned and descendants:
raise error.Abort(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 _(b'cannot split changeset with children without rebase')
Augie Fackler
formatting: blacken the codebase...
r43346 )
Jun Wu
split: new extension to split changesets...
r35471 torebase = ()
if len(ctx.parents()) > 1:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 raise error.Abort(_(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
incomplete = lambda repo: any(repo.status()[:4])
# 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())
Jun Wu
split: new extension to split changesets...
r35471 for c in committed:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 firstline = c.description().split(b'\n', 1)[0]
header += _(b'HG: - %s: %s\n') % (short(c.node()), firstline)
Augie Fackler
formatting: blacken the codebase...
r43346 header += _(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 b'HG: Write commit message for the next split ' b'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:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 raise error.Abort(_(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 )