comparison mercurial/revset.py @ 17186:a3da6f298592

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])
author Matt Harbison <matt_harbison@yahoo.com>
date Sat, 07 Jul 2012 00:47:55 -0400
parents 2c7c4824969e
children 483aa765f6c4
comparison
equal deleted inserted replaced
17185:2c7c4824969e 17186:a3da6f298592
559 def _firstdescendants(repo, subset, x): 559 def _firstdescendants(repo, subset, x):
560 # ``_firstdescendants(set)`` 560 # ``_firstdescendants(set)``
561 # Like ``descendants(set)`` but follows only the first parents. 561 # Like ``descendants(set)`` but follows only the first parents.
562 return _descendants(repo, subset, x, followfirst=True) 562 return _descendants(repo, subset, x, followfirst=True)
563 563
564 def destination(repo, subset, x):
565 """``destination([set])``
566 Changesets that were created by a graft, transplant or rebase operation,
567 with the given revisions specified as the source. Omitting the optional set
568 is the same as passing all().
569 """
570 if x is not None:
571 args = set(getset(repo, range(len(repo)), x))
572 else:
573 args = set(getall(repo, range(len(repo)), x))
574
575 dests = set()
576
577 # subset contains all of the possible destinations that can be returned, so
578 # iterate over them and see if their source(s) were provided in the args.
579 # Even if the immediate src of r is not in the args, src's source (or
580 # further back) may be. Scanning back further than the immediate src allows
581 # transitive transplants and rebases to yield the same results as transitive
582 # grafts.
583 for r in subset:
584 src = _getrevsource(repo, r)
585 lineage = None
586
587 while src is not None:
588 if lineage is None:
589 lineage = list()
590
591 lineage.append(r)
592
593 # The visited lineage is a match if the current source is in the arg
594 # set. Since every candidate dest is visited by way of iterating
595 # subset, any dests futher back in the lineage will be tested by a
596 # different iteration over subset. Likewise, if the src was already
597 # selected, the current lineage can be selected without going back
598 # further.
599 if src in args or src in dests:
600 dests.update(lineage)
601 break
602
603 r = src
604 src = _getrevsource(repo, r)
605
606 return [r for r in subset if r in dests]
607
564 def draft(repo, subset, x): 608 def draft(repo, subset, x):
565 """``draft()`` 609 """``draft()``
566 Changeset in draft phase.""" 610 Changeset in draft phase."""
567 getargs(x, 0, 0, _("draft takes no arguments")) 611 getargs(x, 0, 0, _("draft takes no arguments"))
568 pc = repo._phasecache 612 pc = repo._phasecache
1397 "converted": converted, 1441 "converted": converted,
1398 "date": date, 1442 "date": date,
1399 "desc": desc, 1443 "desc": desc,
1400 "descendants": descendants, 1444 "descendants": descendants,
1401 "_firstdescendants": _firstdescendants, 1445 "_firstdescendants": _firstdescendants,
1446 "destination": destination,
1402 "draft": draft, 1447 "draft": draft,
1403 "extinct": extinct, 1448 "extinct": extinct,
1404 "extra": extra, 1449 "extra": extra,
1405 "file": hasfile, 1450 "file": hasfile,
1406 "filelog": filelog, 1451 "filelog": filelog,