revset: add destination() predicate
authorMatt Harbison <matt_harbison@yahoo.com>
Sat, 07 Jul 2012 00:47:55 -0400
changeset 17186 a3da6f298592
parent 17185 2c7c4824969e
child 17187 293dd81e4601
revset: add destination() predicate This predicate is used to find csets that were created because of a graft, transplant or rebase --keep. An optional revset can be supplied, in which case the result will be limited to those copies which specified one of the revs as the source for the command. hg log -r destination() # csets copied from anywhere hg log -r destination(branch(default)) # all csets copied from default hg log -r origin(x) or destination(origin(x)) # all instances of x This predicate will follow a cset through different types of copies. Given a repo with a cset 'S' that is grafted to create G(S), which itself is transplanted to become T(G(S)): o-S / o-o-G(S) \ o-T(G(S)) hg log -r destination( S ) # { G(S), T(G(S)) } hg log -r destination( G(S) ) # { T(G(S)) } The implementation differences between the three different copy commands (see the origin() predicate) are not intentionally exposed, however if the transplant was a graft instead: hg log -r destination( G(S) ) # {} because the 'extra' field in G(G(S)) is S, not G(S). The implementation cannot correct this by following sources before G(S) and then select the csets that reference those sources because the cset provided to the predicate would also end up selected. If there were more than two copies, sources of the argument would also get selected. Note that the convert extension does not currently update the 'extra' map in its destination csets, and therefore copies made prior to the convert will be missing from the resulting set. Instead of the loop over 'subset', the following almost works, but does not select a transplant of a transplant. That is, 'destination(S)' will only select T(S). dests = set([r for r in subset if _getrevsource(repo, r) in args])
mercurial/revset.py
tests/test-graft.t
tests/test-transplant.t
--- a/mercurial/revset.py	Sat Jul 07 00:47:30 2012 -0400
+++ b/mercurial/revset.py	Sat Jul 07 00:47:55 2012 -0400
@@ -561,6 +561,50 @@
     # Like ``descendants(set)`` but follows only the first parents.
     return _descendants(repo, subset, x, followfirst=True)
 
+def destination(repo, subset, x):
+    """``destination([set])``
+    Changesets that were created by a graft, transplant or rebase operation,
+    with the given revisions specified as the source.  Omitting the optional set
+    is the same as passing all().
+    """
+    if x is not None:
+        args = set(getset(repo, range(len(repo)), x))
+    else:
+        args = set(getall(repo, range(len(repo)), x))
+
+    dests = set()
+
+    # subset contains all of the possible destinations that can be returned, so
+    # iterate over them and see if their source(s) were provided in the args.
+    # Even if the immediate src of r is not in the args, src's source (or
+    # further back) may be.  Scanning back further than the immediate src allows
+    # transitive transplants and rebases to yield the same results as transitive
+    # grafts.
+    for r in subset:
+        src = _getrevsource(repo, r)
+        lineage = None
+
+        while src is not None:
+            if lineage is None:
+                lineage = list()
+
+            lineage.append(r)
+
+            # The visited lineage is a match if the current source is in the arg
+            # set.  Since every candidate dest is visited by way of iterating
+            # subset, any dests futher back in the lineage will be tested by a
+            # different iteration over subset.  Likewise, if the src was already
+            # selected, the current lineage can be selected without going back
+            # further.
+            if src in args or src in dests:
+                dests.update(lineage)
+                break
+
+            r = src
+            src = _getrevsource(repo, r)
+
+    return [r for r in subset if r in dests]
+
 def draft(repo, subset, x):
     """``draft()``
     Changeset in draft phase."""
@@ -1399,6 +1443,7 @@
     "desc": desc,
     "descendants": descendants,
     "_firstdescendants": _firstdescendants,
+    "destination": destination,
     "draft": draft,
     "extinct": extinct,
     "extra": extra,
--- a/tests/test-graft.t	Sat Jul 07 00:47:30 2012 -0400
+++ b/tests/test-graft.t	Sat Jul 07 00:47:55 2012 -0400
@@ -405,3 +405,131 @@
   date:        Thu Jan 01 00:00:00 1970 +0000
   summary:     2
   
+Test simple destination
+  $ hg log -r 'destination()'
+  changeset:   7:ef0ef43d49e7
+  parent:      0:68795b066622
+  user:        foo
+  date:        Thu Jan 01 00:00:00 1970 +0000
+  summary:     2
+  
+  changeset:   8:6b9e5368ca4e
+  user:        bar
+  date:        Thu Jan 01 00:00:00 1970 +0000
+  summary:     1
+  
+  changeset:   9:1905859650ec
+  user:        test
+  date:        Thu Jan 01 00:00:00 1970 +0000
+  summary:     5
+  
+  changeset:   10:52dc0b4c6907
+  user:        test
+  date:        Thu Jan 01 00:00:00 1970 +0000
+  summary:     4
+  
+  changeset:   11:882b35362a6b
+  user:        test
+  date:        Thu Jan 01 00:00:00 1970 +0000
+  summary:     3
+  
+  changeset:   13:9db0f28fd374
+  user:        foo
+  date:        Thu Jan 01 00:00:00 1970 +0000
+  summary:     2
+  
+  changeset:   14:f64defefacee
+  parent:      1:5d205f8b35b6
+  user:        foo
+  date:        Thu Jan 01 00:00:00 1970 +0000
+  summary:     3
+  
+  changeset:   17:64ecd9071ce8
+  user:        bar
+  date:        Thu Jan 01 00:00:00 1970 +0000
+  summary:     1
+  
+  changeset:   19:2e80e1351d6e
+  user:        test
+  date:        Thu Jan 01 00:00:00 1970 +0000
+  summary:     2
+  
+  changeset:   21:7e61b508e709
+  branch:      dev
+  tag:         tip
+  user:        foo
+  date:        Thu Jan 01 00:00:00 1970 +0000
+  summary:     2
+  
+  $ hg log -r 'destination(2)'
+  changeset:   7:ef0ef43d49e7
+  parent:      0:68795b066622
+  user:        foo
+  date:        Thu Jan 01 00:00:00 1970 +0000
+  summary:     2
+  
+  changeset:   13:9db0f28fd374
+  user:        foo
+  date:        Thu Jan 01 00:00:00 1970 +0000
+  summary:     2
+  
+  changeset:   19:2e80e1351d6e
+  user:        test
+  date:        Thu Jan 01 00:00:00 1970 +0000
+  summary:     2
+  
+  changeset:   21:7e61b508e709
+  branch:      dev
+  tag:         tip
+  user:        foo
+  date:        Thu Jan 01 00:00:00 1970 +0000
+  summary:     2
+  
+Transplants of grafts can find a destination...
+  $ hg log -r 'destination(7)'
+  changeset:   21:7e61b508e709
+  branch:      dev
+  tag:         tip
+  user:        foo
+  date:        Thu Jan 01 00:00:00 1970 +0000
+  summary:     2
+  
+... grafts of grafts unfortunately can't
+  $ hg graft -q 13
+  $ hg log -r 'destination(13)'
+All copies of a cset
+  $ hg log -r 'origin(13) or destination(origin(13))'
+  changeset:   2:5c095ad7e90f
+  user:        test
+  date:        Thu Jan 01 00:00:00 1970 +0000
+  summary:     2
+  
+  changeset:   7:ef0ef43d49e7
+  parent:      0:68795b066622
+  user:        foo
+  date:        Thu Jan 01 00:00:00 1970 +0000
+  summary:     2
+  
+  changeset:   13:9db0f28fd374
+  user:        foo
+  date:        Thu Jan 01 00:00:00 1970 +0000
+  summary:     2
+  
+  changeset:   19:2e80e1351d6e
+  user:        test
+  date:        Thu Jan 01 00:00:00 1970 +0000
+  summary:     2
+  
+  changeset:   21:7e61b508e709
+  branch:      dev
+  user:        foo
+  date:        Thu Jan 01 00:00:00 1970 +0000
+  summary:     2
+  
+  changeset:   22:1313d0a825e2
+  branch:      dev
+  tag:         tip
+  user:        foo
+  date:        Thu Jan 01 00:00:00 1970 +0000
+  summary:     2
+  
--- a/tests/test-transplant.t	Sat Jul 07 00:47:30 2012 -0400
+++ b/tests/test-transplant.t	Sat Jul 07 00:47:55 2012 -0400
@@ -83,6 +83,74 @@
   1 
   0 
 
+test destination() revset predicate with a transplant of a transplant; new
+clone so subsequent rollback isn't affected
+  $ hg clone -q . ../destination
+  $ cd ../destination
+  $ hg up -Cq 0
+  $ hg branch -q b4
+  $ hg ci -qm "b4"
+  $ hg transplant 7
+  applying ffd6818a3975
+  ffd6818a3975 transplanted to 502236fa76bb
+
+
+  $ hg log -r 'destination()'
+  changeset:   5:e234d668f844
+  parent:      1:d11e3596cc1a
+  user:        test
+  date:        Thu Jan 01 00:00:00 1970 +0000
+  summary:     b1
+  
+  changeset:   6:539f377d78df
+  user:        test
+  date:        Thu Jan 01 00:00:01 1970 +0000
+  summary:     b2
+  
+  changeset:   7:ffd6818a3975
+  user:        test
+  date:        Thu Jan 01 00:00:02 1970 +0000
+  summary:     b3
+  
+  changeset:   9:502236fa76bb
+  branch:      b4
+  tag:         tip
+  user:        test
+  date:        Thu Jan 01 00:00:02 1970 +0000
+  summary:     b3
+  
+  $ hg log -r 'destination(a53251cdf717)'
+  changeset:   7:ffd6818a3975
+  user:        test
+  date:        Thu Jan 01 00:00:02 1970 +0000
+  summary:     b3
+  
+  changeset:   9:502236fa76bb
+  branch:      b4
+  tag:         tip
+  user:        test
+  date:        Thu Jan 01 00:00:02 1970 +0000
+  summary:     b3
+  
+
+test subset parameter in reverse order
+  $ hg log -r 'reverse(all()) and destination(a53251cdf717)'
+  changeset:   9:502236fa76bb
+  branch:      b4
+  tag:         tip
+  user:        test
+  date:        Thu Jan 01 00:00:02 1970 +0000
+  summary:     b3
+  
+  changeset:   7:ffd6818a3975
+  user:        test
+  date:        Thu Jan 01 00:00:02 1970 +0000
+  summary:     b3
+  
+
+back to the original dir
+  $ cd ../rebase
+
 rollback the transplant
   $ hg rollback
   repository tip rolled back to revision 4 (undo transplant)