[PATCH] revset: introduce feature revset for tracking in-progress work (issue4968)

Augie Fackler raf at durin42.com
Mon Nov 30 16:31:36 CST 2015


On Thu, Nov 26, 2015 at 05:31:23PM -0500, Andrew Halberstadt wrote:
> # HG changeset patch
> # User Andrew Halberstadt <ahalberstadt at mozilla.com>
> # Date 1448490626 18000
> #      Wed Nov 25 17:30:26 2015 -0500
> # Node ID 3545b0234e4884f57dac44fd4e443deac5b9d673
> # Parent  61fbf5dc12b23e7a2a30cf04ebd9f096c42a1f61
> revset: introduce feature revset for tracking in-progress work (issue4968)

Interesting
work. https://www.mercurial-scm.org/wiki/FeatureBranchesStruggle would
probably like a brief summary of what you've done here.

Pierre-yves, Sean (both cc'ed), and I have been getting frustrated
about this feature gap in hg for a while. We're hoping to put some
spit and polish on our "topics" concept in the near future, would you
have interest in testing that and seeing how it behaves compared with
what you've got in bookbinder?

(Bookbinder for those not reading the bug is
https://bitbucket.org/halbersa/bookbinder, which is an interesting
notion of how to "assign" a changeset to be "part" of a bookmark.)

>
> The revset "only(<rev>) and not public()" is often used to track wip features.
> But this approach is simplistic and doesn't take things like merges,
> obsolescence and bookmarks into account. This change formalizes a 'feature()'
> revset that can turn a set of revision specifications into all the commits
> within their associated feature branches.
>
> A commit C is in the feature ending at revision R if all of the following
> conditions are true:
>
> 1. C is R or C is an ancestor of R
> 2. C is not public
> 3. C is not a merge commit
> 4. C is not obsolete
> 5. no bookmarks exist in [C, R) for C != R
> 6. all commits in (C, R) are also within R for C != R
>
> diff --git a/mercurial/revset.py b/mercurial/revset.py
> --- a/mercurial/revset.py
> +++ b/mercurial/revset.py
> @@ -3,16 +3,17 @@
>  # Copyright 2010 Matt Mackall <mpm at selenic.com>
>  #
>  # This software may be used and distributed according to the terms of the
>  # GNU General Public License version 2 or any later version.
>
>  from __future__ import absolute_import
>
>  import heapq
> +import itertools
>  import re
>
>  from .i18n import _
>  from . import (
>      destutil,
>      encoding,
>      error,
>      hbisect,
> @@ -926,16 +927,51 @@ def extra(repo, subset, x):
>          kind, value, matcher = util.stringmatcher(value)
>
>      def _matchvalue(r):
>          extra = repo[r].extra()
>          return label in extra and (value is None or matcher(extra[label]))
>
>      return subset.filter(lambda r: _matchvalue(r))
>
> +def feature(repo, subset, x):
> +    """``feature(set)``
> +    Changesets that are in a feature of a revision specification in set.
> +
> +    Changeset X is in Y's feature if X is an ancestor of Y and they don't have
> +    any merge commits, public changesets or changesets with a bookmark in
> +    between them.
> +    """
> +    args = getargs(x, 1, 1, _("feature takes one argument"))
> +    specs = getset(repo, fullreposet(repo), args[0])
> +    specs = [formatspec('rev(%d)', s) if isinstance(s, int) else s
> +             for s in specs]
> +
> +    m = matchany(repo.ui, specs, repo)
> +    l = m(repo)
> +
> +    feature = set()
> +    for i, root in enumerate(l):
> +        nodes = itertools.chain([root], repo[root].ancestors())
> +        for node in nodes:
> +            ctx = repo[node]
> +            # if public, a merge or obsolete, not in feature
> +            if ctx.phase() == 0 or len(ctx.parents()) == 2 or ctx.obsolete():
> +                break
> +
> +            # if a bookmark other than specs[i] exists, not in feature
> +            marks = set(ctx.bookmarks()) - set(repo[root].bookmarks())
> +            if specs[i] in marks:
> +                marks.remove(specs[i])
> +            if len(marks) > 0:
> +                break
> +            feature.add(ctx.rev())
> +
> +    return subset & feature
> +
>  def filelog(repo, subset, x):
>      """``filelog(pattern)``
>      Changesets connected to the specified filelog.
>
>      For performance reasons, visits only revisions mentioned in the file-level
>      filelog, rather than filtering through all changesets (much faster, but
>      doesn't include deletes or duplicate changes). For a slower, more accurate
>      result, use ``file()``.
> @@ -2123,16 +2159,17 @@ symbols = {
>      "desc": desc,
>      "descendants": descendants,
>      "_firstdescendants": _firstdescendants,
>      "destination": destination,
>      "divergent": divergent,
>      "draft": draft,
>      "extinct": extinct,
>      "extra": extra,
> +    "feature": feature,
>      "file": hasfile,
>      "filelog": filelog,
>      "first": first,
>      "follow": follow,
>      "_followfirst": _followfirst,
>      "grep": grep,
>      "head": head,
>      "heads": heads,
> @@ -2200,16 +2237,17 @@ safesymbols = set([
>      "desc",
>      "descendants",
>      "_firstdescendants",
>      "destination",
>      "divergent",
>      "draft",
>      "extinct",
>      "extra",
> +    "feature",
>      "file",
>      "filelog",
>      "first",
>      "follow",
>      "_followfirst",
>      "head",
>      "heads",
>      "hidden",
> diff --git a/tests/test-revset.t b/tests/test-revset.t
> --- a/tests/test-revset.t
> +++ b/tests/test-revset.t
> @@ -2006,16 +2006,38 @@ test or-ed indirect predicates (issue377
>    0
>    1
>    2
>    3
>    4
>    5
>    6
>
> +test feature
> +  $ log 'feature(7)'
> +  7
> +  $ log 'feature(only)'
> +  0
> +  1
> +  2
> +  4
> +  8
> +  9
> +  $ hg phase -f -p 8
> +  $ log 'feature(only)'
> +  9
> +  $ log 'feature(8)'
> +  $ hg phase -f -d 8
> +  $ hg bookmark -r 8 other
> +  $ log 'feature(only)'
> +  9
> +  $ log 'feature(only | 7)'
> +  7
> +  9
> +
>  tests for 'remote()' predicate:
>  #.  (csets in remote) (id)            (remote)
>  1.  less than local   current branch  "default"
>  2.  same with local   specified       "default"
>  3.  more than local   specified       specified
>
>    $ hg clone --quiet -U . ../remote3
>    $ cd ../remote3
> _______________________________________________
> Mercurial-devel mailing list
> Mercurial-devel at selenic.com
> https://selenic.com/mailman/listinfo/mercurial-devel


More information about the Mercurial-devel mailing list