--- a/hgext/evolve.py Wed Dec 30 03:48:11 2015 +0530
+++ b/hgext/evolve.py Sun Jan 03 15:51:36 2016 +0100
@@ -147,8 +147,8 @@
class exthelper(object):
"""Helper for modular extension setup
- A single helper should be instanciated for each extension. Helper
- methods are then used as decorator for various purpose.
+ A single helper should be instantiated for each extension. Helper
+ methods are then used as decorators for various purpose.
All decorators return the original function and may be chained.
"""
@@ -678,16 +678,19 @@
# This section take care of issue warning to the user when troubles appear
+
+def _warnobsoletewc(ui, repo):
+ if repo['.'].obsolete():
+ ui.warn(_('working directory parent is obsolete!\n'))
+ if (not ui.quiet) and obsolete.isenabled(repo, commandopt):
+ ui.warn(_('(use "hg evolve" to update to its successor)\n'))
+
@eh.wrapcommand("update")
-@eh.wrapcommand("parents")
@eh.wrapcommand("pull")
def wrapmayobsoletewc(origfn, ui, repo, *args, **opts):
"""Warn that the working directory parent is an obsolete changeset"""
def warnobsolete():
- if repo['.'].obsolete():
- ui.warn(_('working directory parent is obsolete!\n'))
- if (not ui.quiet) and obsolete.isenabled(repo, commandopt):
- ui.warn(_('(use "hg evolve" to update to its successor)\n'))
+ _warnobsoletewc(ui, repo)
wlock = None
try:
wlock = repo.wlock()
@@ -697,6 +700,12 @@
lockmod.release(wlock)
return res
+@eh.wrapcommand("parents")
+def wrapparents(origfn, ui, repo, *args, **opts):
+ res = origfn(ui, repo, *args, **opts)
+ _warnobsoletewc(ui, repo)
+ return res
+
# XXX this could wrap transaction code
# XXX (but this is a bit a layer violation)
@eh.wrapcommand("commit")
@@ -786,7 +795,7 @@
if histedit:
extensions.wrapcommand(histedit.cmdtable, 'histedit', warnobserrors)
except KeyError:
- pass # rebase not found
+ pass # histedit not found
#####################################################################
### Old Evolve extension content ###
@@ -1119,11 +1128,12 @@
@command('debugrecordpruneparents', [], '')
def cmddebugrecordpruneparents(ui, repo):
- """add parents data to prune markers when possible
-
- This commands search the repo for prune markers without parent information.
- If the pruned node is locally known, a new markers with parent data is
- created."""
+ """add parent data to prune markers when possible
+
+ This command searches the repo for prune markers without parent information.
+ If the pruned node is locally known, it creates a new marker with parent
+ data.
+ """
pgop = 'reading markers'
# lock from the beginning to prevent race
@@ -1155,6 +1165,7 @@
@command('debugobsstorestat', [], '')
def cmddebugobsstorestat(ui, repo):
+ """print statistics about obsolescence markers in the repo"""
def _updateclustermap(nodes, mark, clustersmap):
c = (set(nodes), set([mark]))
toproceed = set(nodes)
@@ -1172,7 +1183,6 @@
c = other
clustersmap[n] = c
- """print statistic about obsolescence markers in the repo"""
store = repo.obsstore
unfi = repo.unfiltered()
nm = unfi.changelog.nodemap
@@ -1384,7 +1394,7 @@
ui.status(_('working directory is now at %s\n') % repo['.'])
class MultipleSuccessorsError(RuntimeError):
- """Exception raised by _singlesuccessor when multiple sucessors sets exists
+ """Exception raised by _singlesuccessor when multiple successor sets exists
The object contains the list of successorssets in its 'successorssets'
attribute to call to easily recover.
@@ -1487,14 +1497,14 @@
def _orderrevs(repo, revs):
"""Compute an ordering to solve instability for the given revs
- - Takes revs a list of instable revisions
-
- - Returns the same revisions ordered to solve their instability from the
+ revs is a list of unstable revisions.
+
+ Returns the same revisions ordered to solve their instability from the
bottom to the top of the stack that the stabilization process will produce
eventually.
- This ensure the minimal number of stabilization as we can stabilize each
- revision on its final, stabilized, destination.
+ This ensures the minimal number of stabilizations, as we can stabilize each
+ revision on its final stabilized destination.
"""
# Step 1: Build the dependency graph
dependencies, rdependencies = builddependencies(repo, revs)
@@ -1535,38 +1545,66 @@
] + mergetoolopts,
_('[OPTIONS]...'))
def evolve(ui, repo, **opts):
- """solve troubles in your repository
-
- - rebase unstable changesets to make them stable again,
- - create proper diffs from bumped changesets,
- - fuse divergent changesets back together,
- - update to a successor if the working directory parent is
- obsolete
-
- If no argument are passed and the current working copy parent is obsolete,
- :hg:`evolve` will update the working copy to the successors of this working
- copy parent. If the working copy parent is not obsolete (and still no
- argument passed) each invocation of :hg:`evolve` will evolve a single
- unstable changeset, It will only select a changeset to be evolved if it
- will result in a new children for the current working copy parent or its
- descendants. The working copy will be updated on the result
- (this last behavior will most likely to change in the future).
- You can evolve all the unstable changesets that will be evolved on the
- parent of the working copy and all its descendants recursively by using
- :hg:`evolve` --all.
-
- You can decide to evolve other categories of trouble using the --divergent
- and --bumped flags. If no other option are specified, this will try to
- solve the specified troubles for the working copy parent.
-
- You can also evolve changesets affected by troubles of the selected
- category using the --rev options. You can pick the next one anywhere in the
- repo using --any.
-
- You can evolve all the changesets affected by troubles of the selected
- category using --all --any.
-
- The working directory is updated to the newly created revision.
+ """solve troubled changesets in your repository
+
+ Modifying history can lead to various types of troubled changesets: unstable,
+ bumped, or divergent. The evolve command resolves your troubles by executing one
+ of the following actions:
+
+ - update working copy to a successor
+ - rebase an unstable changeset
+ - extract the desired changes from a bumped changeset
+ - fuse divergent changesets back together
+
+ If you pass no arguments, evolve works in automatic mode: it will execute a
+ single action to reduce instability related to your working copy. There are two
+ cases for this action. First, if the parent of your working copy is obsolete,
+ evolve updates to the parent's successor. Second, if the working copy parent is
+ not obsolete but has obsolete predecessors, then evolve determines if there is an
+ unstable changeset that can be rebased onto the working copy parent in order to
+ reduce instability. If so, evolve rebases that changeset. If not, evolve refuses
+ to guess your intention, and gives a hint about what you might want to do next.
+
+ Any time evolve creates a changeset, it updates the working copy to the new
+ changeset. (Currently, every successful evolve operation involves an update as
+ well; this may change in future.)
+
+ Automatic mode only handles common use cases. For example, it avoids taking
+ action in the case of ambiguity, and it ignores unstable changesets that are not
+ related to your working copy. It also refuses to solve bumped or divergent
+ changesets unless you explicity request such behavior (see below).
+
+ Eliminating all instability around your working copy may require multiple
+ invocations of :hg:`evolve`. Alternately, use ``--all`` to recursively select and
+ evolve all unstable changesets that can be rebased onto the working copy parent.
+ This is more powerful than successive invocations, since ``--all`` handles
+ ambiguous cases (e.g. unstable changesets with multiple children) by evolving all
+ branches.
+
+ When your repository cannot be handled by automatic mode, you might need to use
+ ``--rev`` to specify a changeset to evolve. For example, if you have an unstable
+ changeset that is not related to the working copy parent, you could use ``--rev``
+ to evolve it. Or, if some changeset has multiple unstable children, evolve in
+ automatic mode refuses to guess which one to evolve; you have to use ``--rev``
+ in that case.
+
+ Alternately, ``--any`` makes evolve search for the next evolvable changeset
+ regardless of whether it is related to the working copy parent.
+
+ You can supply multiple revisions to evolve multiple troubled changesets in a
+ single invocation. In revset terms, ``--any`` is equivalent to ``--rev
+ first(unstable())``. ``--rev`` and ``--all`` are mutually exclusive, as are
+ ``--rev`` and ``--any``.
+
+ ``hg evolve --any --all`` is useful for cleaning up instability across all
+ branches, letting evolve figure out the appropriate order and destination.
+
+ When you have troubled changesets that are not unstable, :hg:`evolve` refuses to
+ consider them unless you specify the category of trouble you wish to resolve,
+ with ``--bumped`` or ``--divergent``. These options are currently mutually
+ exclusive with each other and with ``--unstable`` (the default). You can combine
+ ``--bumped`` or ``--divergent`` with ``--rev``, ``--all``, or ``--any``.
+
"""
# Options
@@ -1710,7 +1748,7 @@
def _solveunstable(ui, repo, orig, dryrun=False, confirm=False,
progresscb=None):
- """Stabilize a unstable changeset"""
+ """Stabilize an unstable changeset"""
obs = orig.parents()[0]
if not obs.obsolete() and len(orig.parents()) == 2:
obs = orig.parents()[1] # second parent is obsolete ?
@@ -2017,7 +2055,9 @@
('n', 'dry-run', False, _('do not perform actions, just print what would be done'))],
'[OPTION]...')
def cmdprevious(ui, repo, **opts):
- """update to parent and display summary lines"""
+ """update to parent revision
+
+ Displays the summary line of the destination for clarity."""
wkctx = repo[None]
wparents = wkctx.parents()
dryrunopt = opts['dry_run']
@@ -2068,11 +2108,12 @@
('n', 'dry-run', False, _('do not perform actions, just print what would be done'))],
'[OPTION]...')
def cmdnext(ui, repo, **opts):
- """update to next child
-
- You can use the --evolve flag to get unstable children evolved on demand.
-
- The summary line of the destination is displayed for clarity"""
+ """update to next child revision
+
+ Use the ``--evolve`` flag to evolve unstable children on demand.
+
+ Displays the summary line of the destination for clarity.
+ """
wkctx = repo[None]
wparents = wkctx.parents()
dryrunopt = opts['dry_run']
@@ -2211,25 +2252,26 @@
def cmdprune(ui, repo, *revs, **opts):
"""hide changesets by marking them obsolete
- Obsolete changesets becomes invisible to all commands.
-
- Unpruned descendants of pruned changesets becomes "unstable". Use the
- :hg:`evolve` to handle such situation.
-
- When the working directory parent is pruned, the repository is updated to a
- non-obsolete parent.
-
- You can use the ``--succ`` option to inform mercurial that a newer version
- of the pruned changeset exists.
-
- You can use the ``--biject`` option to specify a 1-1 (bijection) between
- revisions to prune and successor changesets. This option may be removed in
- a future release (with the functionality absorbed automatically).
-
- If you specify multiple revisions in --succ, you are recording a "split"
- and have to acknowledge it by usng --split. The same logic apply when you
- prune multiple changesets with a single successors, this will record a
- "fold" requires a --fold flag.
+ Pruned changesets are obsolete with no successors. If they also have no
+ descendants, they are hidden (invisible to all commands).
+
+ Non-obsolete descendants of pruned changesets become "unstable". Use :hg:`evolve`
+ to handle this situation.
+
+ When you prune the parent of your working copy, Mercurial updates the working
+ copy to a non-obsolete parent.
+
+ You can use ``--succ`` to tell Mercurial that a newer version (successor) of the
+ pruned changeset exists. Mercurial records successor revisions in obsolescence
+ markers.
+
+ You can use the ``--biject`` option to specify a 1-1 mapping (bijection) between
+ revisions to pruned (precursor) and successor changesets. This option may be
+ removed in a future release (with the functionality provided automatically).
+
+ If you specify multiple revisions in ``--succ``, you are recording a "split" and
+ must acknowledge it by passing ``--split``. Similarly, when you prune multiple
+ changesets with a single successor, you must pass the ``--fold`` option.
"""
revs = scmutil.revrange(repo, list(revs) + opts.get('rev'))
succs = opts['new'] + opts['succ']
@@ -2624,12 +2666,12 @@
] + commitopts + commitopts2,
_('hg split [OPTION]... [-r] REV'))
def cmdsplit(ui, repo, *revs, **opts):
- """Split the current commit using interactive selection (EXPERIMENTAL)
-
- By default, split the current revision by prompting for all its hunk to be
+ """split a changeset into smaller changesets (EXPERIMENTAL)
+
+ By default, split the current revision by prompting for all its hunks to be
redistributed into new changesets.
- Use --rev for splitting a given changeset instead.
+ Use --rev to split a given changeset instead.
"""
tr = wlock = lock = None
newcommits = []