revpair: restrict odd-range handling to top-level x:y expression (issue4774)
The odd-range hack was introduced by 2a0efa1112ac for backward compatibility,
but it was too widely applied. I've checked cmdutil.revpair() at 1.6, and
found that ".:", ":0" and ":" are also handled as pairs. So let's enable the
hack only for "x:y", "x:", "y:" and ":".
test-revset.t is updated because "tip^::tip^ or tip^" shouldn't be taken as
an odd range. This patch adds "tip^:tip^" instead.
This patch is written for the default branch because parse() of the stable
branch lacks compatibility hack for "foo+bar" tag. If we want to mitigate the
issue in stable, we can add something like "and '::' in revs[0]".
--- a/mercurial/scmutil.py Thu Aug 13 16:27:32 2015 +0900
+++ b/mercurial/scmutil.py Thu Aug 13 16:15:43 2015 +0900
@@ -690,6 +690,11 @@
raise util.Abort(_('empty revision set'))
return repo[l.last()]
+def _pairspec(revspec):
+ tree = revset.parse(revspec)
+ tree = revset.optimize(tree, True)[1] # fix up "x^:y" -> "(x^):y"
+ return tree and tree[0] in ('range', 'rangepre', 'rangepost', 'rangeall')
+
def revpair(repo, revs):
if not revs:
return repo.dirstate.p1(), None
@@ -711,13 +716,12 @@
if first is None:
raise util.Abort(_('empty revision range'))
- if first == second and len(revs) == 1 and _revrangesep not in revs[0]:
+ # if top-level is range expression, the result must always be a pair
+ if first == second and len(revs) == 1 and not _pairspec(revs[0]):
return repo.lookup(first), None
return repo.lookup(first), repo.lookup(second)
-_revrangesep = ':'
-
def revrange(repo, revs):
"""Yield revision as strings from a list of revision specifications."""
allspecs = []
--- a/tests/test-diff-change.t Thu Aug 13 16:27:32 2015 +0900
+++ b/tests/test-diff-change.t Thu Aug 13 16:15:43 2015 +0900
@@ -31,19 +31,53 @@
$ cd ..
-Test dumb revspecs (issue3474)
+Test dumb revspecs: top-level "x:y", "x:", ":y" and ":" ranges should be handled
+as pairs even if x == y, but not for "f(x:y)" nor "x::y" (issue3474, issue4774)
$ hg clone -q a dumbspec
$ cd dumbspec
$ echo "wdir" > file.txt
$ hg diff -r 2:2
+ $ hg diff -r 2:.
+ $ hg diff -r 2:
+ $ hg diff -r :0
+ $ hg diff -r '2:first(2:2)'
+ $ hg diff -r 'first(2:2)' --nodates
+ diff -r bf5ff72eb7e0 file.txt
+ --- a/file.txt
+ +++ b/file.txt
+ @@ -1,1 +1,1 @@
+ -third
+ +wdir
+ $ hg diff -r 2::2 --nodates
+ diff -r bf5ff72eb7e0 file.txt
+ --- a/file.txt
+ +++ b/file.txt
+ @@ -1,1 +1,1 @@
+ -third
+ +wdir
$ hg diff -r "2 and 1"
abort: empty revision range
[255]
$ cd ..
+ $ hg clone -qr0 a dumbspec-rev0
+ $ cd dumbspec-rev0
+ $ echo "wdir" > file.txt
+
+ $ hg diff -r :
+ $ hg diff -r 'first(:)' --nodates
+ diff -r 4bb65dda5db4 file.txt
+ --- a/file.txt
+ +++ b/file.txt
+ @@ -1,1 +1,1 @@
+ -first
+ +wdir
+
+ $ cd ..
+
Testing diff --change when merge:
$ cd a
--- a/tests/test-revset.t Thu Aug 13 16:27:32 2015 +0900
+++ b/tests/test-revset.t Thu Aug 13 16:15:43 2015 +0900
@@ -1515,10 +1515,16 @@
(single rev)
$ hg diff -r 'tip^' -r 'tip^'
- $ hg diff -r 'tip^::tip^ or tip^'
+ $ hg diff -r 'tip^:tip^'
(single rev that does not looks like a range)
+ $ hg diff -r 'tip^::tip^ or tip^'
+ diff -r d5d0dcbdc4d9 .hgtags
+ --- /dev/null Thu Jan 01 00:00:00 1970 +0000
+ +++ b/.hgtags * (glob)
+ @@ -0,0 +1,1 @@
+ +e0cc66ef77e8b6f711815af4e001a6594fde3ba5 1.0
$ hg diff -r 'tip^ or tip^'
diff -r d5d0dcbdc4d9 .hgtags
--- /dev/null Thu Jan 01 00:00:00 1970 +0000