--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/hgext/parentrevspec.py Fri Aug 17 17:33:27 2007 -0300
@@ -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 <alexis@cecm.usp.br>
+#
+# 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
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-parentrevspec Fri Aug 17 17:33:27 2007 -0300
@@ -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^
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/tests/test-parentrevspec.out Fri Aug 17 17:33:27 2007 -0300
@@ -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^'!