templater: do not use index.partialmatch() directly to calculate shortest()
cl.index.partialmatch() isn't a drop-in replacement for cl._partialmatch().
It has no knowledge about hidden revisions, and it raises ValueError if a node
shorter than 4 chars is given. Instead, use index.partialmatch() through
cl._partialmatch(), which has no such problems and gives the identical result
with/without --pure.
The test output was sampled with --pure without this patch, which shows the
most correct result. However, we'll need to switch to using an unfiltered
changelog because _partialmatch() of a filtered changelog can be an order of
magnitude slower.
(with hidden revisions)
% hg log -R hg-committed -r0:20000 -T '{node|shortest}\n' --time > /dev/null
(.^) time: real 1.530 secs (user 1.480+0.000 sys 0.040+0.000)
(.) time: real 43.080 secs (user 43.060+0.000 sys 0.030+0.000)
--- a/mercurial/templater.py Wed Oct 26 22:50:06 2016 +0900
+++ b/mercurial/templater.py Sun Oct 23 14:05:23 2016 +0900
@@ -840,13 +840,8 @@
cl = mapping['ctx']._repo.changelog
def isvalid(test):
try:
- try:
- cl.index.partialmatch(test)
- except AttributeError:
- # Pure mercurial doesn't support partialmatch on the index.
- # Fallback to the slow way.
- if cl._partialmatch(test) is None:
- return False
+ if cl._partialmatch(test) is None:
+ return False
try:
i = int(test)
--- a/tests/test-command-template.t Wed Oct 26 22:50:06 2016 +0900
+++ b/tests/test-command-template.t Sun Oct 23 14:05:23 2016 +0900
@@ -3413,8 +3413,76 @@
hg: parse error: shortest() expects an integer minlength
[255]
+ $ cd ..
+
+Test shortest(node) with the repo having short hash collision:
+
+ $ hg init hashcollision
+ $ cd hashcollision
+ $ cat <<EOF >> .hg/hgrc
+ > [experimental]
+ > evolution = createmarkers
+ > EOF
+ $ echo 0 > a
+ $ hg ci -qAm 0
+ $ for i in 17 129 248 242 480 580 617 1057 2857 4025; do
+ > hg up -q 0
+ > echo $i > a
+ > hg ci -qm $i
+ > done
+ $ hg up -q null
+ $ hg log -r0: -T '{rev}:{node}\n'
+ 0:b4e73ffab476aa0ee32ed81ca51e07169844bc6a
+ 1:11424df6dc1dd4ea255eae2b58eaca7831973bbc
+ 2:11407b3f1b9c3e76a79c1ec5373924df096f0499
+ 3:11dd92fe0f39dfdaacdaa5f3997edc533875cfc4
+ 4:10776689e627b465361ad5c296a20a487e153ca4
+ 5:a00be79088084cb3aff086ab799f8790e01a976b
+ 6:a0b0acd79b4498d0052993d35a6a748dd51d13e6
+ 7:a0457b3450b8e1b778f1163b31a435802987fe5d
+ 8:c56256a09cd28e5764f32e8e2810d0f01e2e357a
+ 9:c5623987d205cd6d9d8389bfc40fff9dbb670b48
+ 10:c562ddd9c94164376c20b86b0b4991636a3bf84f
+ $ hg debugobsolete a00be79088084cb3aff086ab799f8790e01a976b
+ $ hg debugobsolete c5623987d205cd6d9d8389bfc40fff9dbb670b48
+ $ hg debugobsolete c562ddd9c94164376c20b86b0b4991636a3bf84f
+
+ nodes starting with '11' (we don't have the revision number '11' though)
+
+ $ hg log -r 1:3 -T '{rev}:{shortest(node, 0)}\n'
+ 1:1142
+ 2:1140
+ 3:11d
+
+ '5:a00' is hidden, but still we have two nodes starting with 'a0'
+
+ $ hg log -r 6:7 -T '{rev}:{shortest(node, 0)}\n'
+ 6:a0b
+ 7:a04
+
+ node '10' conflicts with the revision number '10' even if it is hidden
+ (we could exclude hidden revision numbers, but currently we don't)
+
+ $ hg log -r 4 -T '{rev}:{shortest(node, 0)}\n'
+ 4:107
+ $ hg log -r 4 -T '{rev}:{shortest(node, 0)}\n' --hidden
+ 4:107
+
+ node 'c562' should be unique if the other 'c562' nodes are hidden
+
+ $ hg log -r 8 -T '{rev}:{node|shortest}\n'
+ 8:c562
+ $ hg log -r 8:10 -T '{rev}:{node|shortest}\n' --hidden
+ 8:c5625
+ 9:c5623
+ 10:c562d
+
+ $ cd ..
+
Test pad function
+ $ cd r
+
$ hg log --template '{pad(rev, 20)} {author|user}\n'
2 test
1 {node|short}