# HG changeset patch # User Alexis S. L. Carvalho # Date 1187382807 10800 # Node ID b111e9a907b100a7aafcb30e5bb9c9bdc5617a35 # Parent da1658d6364721c8bccc6303d100c14b358ecfd9 Add parentrevspec extension diff --git a/hgext/parentrevspec.py b/hgext/parentrevspec.py new file mode 100644 --- /dev/null +++ b/hgext/parentrevspec.py @@ -0,0 +1,96 @@ +# Mercurial extension to make it easy to refer to the parent of a revision +# +# Copyright (C) 2007 Alexis S. L. Carvalho +# +# This software may be used and distributed according to the terms +# of the GNU General Public License, incorporated herein by reference. +'''\ +use suffixes to refer to ancestor revisions + +This extension allows you to use git-style suffixes to refer to +the ancestors of a specific revision. + +For example, if you can refer to a revision as "foo", then: + +- foo^N = Nth parent of foo: + foo^0 = foo + foo^1 = first parent of foo + foo^2 = second parent of foo + foo^ = foo^1 + +- foo~N = Nth first grandparent of foo + foo~0 = foo + foo~1 = foo^1 = foo^ = first parent of foo + foo~2 = foo^1^1 = foo^^ = first parent of first parent of foo +''' +import mercurial.repo + +def reposetup(ui, repo): + if not repo.local(): + return + + class parentrevspecrepo(repo.__class__): + def lookup(self, key): + try: + _super = super(parentrevspecrepo, self) + return _super.lookup(key) + except mercurial.repo.RepoError: + pass + + circ = key.find('^') + tilde = key.find('~') + if circ < 0 and tilde < 0: + raise + elif circ >= 0 and tilde >= 0: + end = min(circ, tilde) + else: + end = max(circ, tilde) + + cl = self.changelog + base = key[:end] + try: + node = _super.lookup(base) + except mercurial.repo.RepoError: + # eek - reraise the first error + return _super.lookup(key) + + rev = cl.rev(node) + suffix = key[end:] + i = 0 + while i < len(suffix): + # foo^N => Nth parent of foo + # foo^0 == foo + # foo^1 == foo^ == 1st parent of foo + # foo^2 == 2nd parent of foo + if suffix[i] == '^': + j = i + 1 + p = cl.parentrevs(rev) + if j < len(suffix) and suffix[j].isdigit(): + j += 1 + n = int(suffix[i+1:j]) + if n > 2 or n == 2 and p[1] == -1: + raise + else: + n = 1 + if n: + rev = p[n - 1] + i = j + # foo~N => Nth first grandparent of foo + # foo~0 = foo + # foo~1 = foo^1 == foo^ == 1st parent of foo + # foo~2 = foo^1^1 == foo^^ == 1st parent of 1st parent of foo + elif suffix[i] == '~': + j = i + 1 + while j < len(suffix) and suffix[j].isdigit(): + j += 1 + if j == i + 1: + raise + n = int(suffix[i+1:j]) + for k in xrange(n): + rev = cl.parentrevs(rev)[0] + i = j + else: + raise + return cl.node(rev) + + repo.__class__ = parentrevspecrepo diff --git a/tests/test-parentrevspec b/tests/test-parentrevspec new file mode 100755 --- /dev/null +++ b/tests/test-parentrevspec @@ -0,0 +1,69 @@ +#!/bin/sh + +commit() +{ + msg=$1 + p1=$2 + p2=$3 + + if [ "$p1" ]; then + hg up -qC $p1 + fi + + if [ "$p2" ]; then + HGMERGE=true hg merge -q $p2 + fi + + echo >> foo + + hg commit -d '0 0' -qAm "$msg" foo +} + +hg init repo +cd repo + +echo '[extensions]' > .hg/hgrc +echo 'hgext.parentrevspec =' >> .hg/hgrc + +commit '0: add foo' +commit '1: change foo 1' +commit '2: change foo 2a' +commit '3: change foo 3a' +commit '4: change foo 2b' 1 +commit '5: merge' 3 4 +commit '6: change foo again' + +hg log --template '#rev#:#node|short# #parents#\n' +echo + +lookup() +{ + for rev in "$@"; do + printf "$rev: " + hg id -nr $rev + done + true +} + +tipnode=`hg id -ir tip` + +echo 'should work with tag/branch/node/rev' +for r in tip default $tipnode 6; do + lookup $r^ +done +echo + +echo 'some random lookups' +lookup 6^^ 6^^^ 6^^^^ 6^^^^^ 6^^^^^^ 6^1 6^2 6^^2 6^1^2 6^^3 +lookup 6~ 6~1 6~2 6~3 6~4 6~5 6~42 6~1^2 6~1^2~2 +echo + +echo 'with a tag "6^" pointing to rev 1' +hg tag -l -r 1 6^ +lookup 6^ 6^1 6~1 6^^ +echo + +echo 'with a tag "foo^bar" pointing to rev 2' +hg tag -l -r 2 foo^bar +lookup foo^bar foo^bar^ + diff --git a/tests/test-parentrevspec.out b/tests/test-parentrevspec.out new file mode 100644 --- /dev/null +++ b/tests/test-parentrevspec.out @@ -0,0 +1,44 @@ +6:755d1e0d79e9 +5:9ce2ce29723a 3:a3e00c7dbf11 4:bb4475edb621 +4:bb4475edb621 1:5d953a1917d1 +3:a3e00c7dbf11 +2:befc7d89d081 +1:5d953a1917d1 +0:837088b6e1d9 + +should work with tag/branch/node/rev +tip^: 5 +default^: 5 +755d1e0d79e9^: 5 +6^: 5 + +some random lookups +6^^: 3 +6^^^: 2 +6^^^^: 1 +6^^^^^: 0 +6^^^^^^: -1 +6^1: 5 +6^2: abort: unknown revision '6^2'! +6^^2: 4 +6^1^2: 4 +6^^3: abort: unknown revision '6^^3'! +6~: abort: unknown revision '6~'! +6~1: 5 +6~2: 3 +6~3: 2 +6~4: 1 +6~5: 0 +6~42: -1 +6~1^2: 4 +6~1^2~2: 0 + +with a tag "6^" pointing to rev 1 +6^: 1 +6^1: 5 +6~1: 5 +6^^: 3 + +with a tag "foo^bar" pointing to rev 2 +foo^bar: 2 +foo^bar^: abort: unknown revision 'foo^bar^'!