{"thread":{"id":"16676","subject":"[JGIT PATCH 0/3] Introduce AbbreviatedObjectId","startedAt":"2008-12-10T23:18:24Z","lastAt":"2008-12-10T23:18:27Z","messageCount":4,"participants":["Shawn O. Pearce"],"isPatch":true,"patchVersion":1,"patchTotal":3},"messages":[{"id":"97535","messageId":"1228951107-5546-1-git-send-email-spearce@spearce.org","threadId":"16676","inReplyTo":null,"subject":"[JGIT PATCH 0/3] Introduce AbbreviatedObjectId","fromName":"Shawn O. Pearce","fromEmail":"spearce@spearce.org","sentAt":"2008-12-10T23:18:24Z","receivedAt":"2008-12-10T23:18:24Z","isPatch":true,"sender":{"key":"spearce@spearce.org","avatar":"https://avatars.githubusercontent.com/u/34844?v=4"},"body":"I'm using this new type to handle the \"index\" line of a git patch\nfile, where object ids are generally shorter than 40 characters\nand thus aren't parsable by ObjectId.\n\nReading the short id is important because we can validate that a\npatch applies correctly by computing the SHA-1 of the result and\ntesting it against the abbreviated id read in the \"index\" line.\nIf the base object SHA-1 matches the abbreviated line then the\nresult of applying the patch must also match; if it doesn't the\npatch application logic is broken.\n\nShawn O. Pearce (3):\n  Define an abstraction for handling abbreviated SHA-1 strings\n  Add ObjectId.startsWith(AbbreviatedObjectId)\n  Change AnyObjectId.abbreviate() to return AbbreviatedObjectId\n\n .../ui/internal/components/RefContentProposal.java |    2 +-\n .../egit/ui/internal/fetch/FetchResultTable.java   |   12 +-\n .../egit/ui/internal/push/PushResultTable.java     |   21 +-\n .../src/org/spearce/jgit/pgm/Branch.java           |    2 +-\n .../src/org/spearce/jgit/pgm/Fetch.java            |    8 +-\n .../src/org/spearce/jgit/pgm/Push.java             |    5 +-\n .../spearce/jgit/lib/AbbreviatedObjectIdTest.java  |  285 ++++++++++++++++++++\n .../org/spearce/jgit/lib/AbbreviatedObjectId.java  |  262 ++++++++++++++++++\n .../src/org/spearce/jgit/lib/AnyObjectId.java      |   39 +++-\n 9 files changed, 608 insertions(+), 28 deletions(-)\n create mode 100644 org.spearce.jgit.test/tst/org/spearce/jgit/lib/AbbreviatedObjectIdTest.java\n create mode 100644 org.spearce.jgit/src/org/spearce/jgit/lib/AbbreviatedObjectId.java\n"},{"id":"97536","messageId":"1228951107-5546-2-git-send-email-spearce@spearce.org","threadId":"16676","inReplyTo":"1228951107-5546-1-git-send-email-spearce@spearce.org","subject":"[JGIT PATCH 1/3] Define an abstraction for handling abbreviated SHA-1 strings","fromName":"Shawn O. Pearce","fromEmail":"spearce@spearce.org","sentAt":"2008-12-10T23:18:25Z","receivedAt":"2008-12-10T23:18:25Z","isPatch":true,"sender":{"key":"spearce@spearce.org","avatar":"https://avatars.githubusercontent.com/u/34844?v=4"},"body":"The AbbreviatedObjectId class parses an abbreviated SHA-1 string\ninto a binary format, permitting it to be more efficiently matched\nagainst existing binary ObjectId fields.\n\nSigned-off-by: Shawn O. Pearce <spearce@spearce.org>\n---\n .../spearce/jgit/lib/AbbreviatedObjectIdTest.java  |  227 ++++++++++++++++++++\n .../org/spearce/jgit/lib/AbbreviatedObjectId.java  |  205 ++++++++++++++++++\n .../src/org/spearce/jgit/lib/AnyObjectId.java      |    2 +-\n 3 files changed, 433 insertions(+), 1 deletions(-)\n create mode 100644 org.spearce.jgit.test/tst/org/spearce/jgit/lib/AbbreviatedObjectIdTest.java\n create mode 100644 org.spearce.jgit/src/org/spearce/jgit/lib/AbbreviatedObjectId.java\n\ndiff --git a/org.spearce.jgit.test/tst/org/spearce/jgit/lib/AbbreviatedObjectIdTest.java b/org.spearce.jgit.test/tst/org/spearce/jgit/lib/AbbreviatedObjectIdTest.java\nnew file mode 100644\nindex 0000000..f540f49\n--- /dev/null\n+++ b/org.spearce.jgit.test/tst/org/spearce/jgit/lib/AbbreviatedObjectIdTest.java\n@@ -0,0 +1,227 @@\n+/*\n+ * Copyright (C) 2008, Google Inc.\n+ *\n+ * All rights reserved.\n+ *\n+ * Redistribution and use in source and binary forms, with or\n+ * without modification, are permitted provided that the following\n+ * conditions are met:\n+ *\n+ * - Redistributions of source code must retain the above copyright\n+ *   notice, this list of conditions and the following disclaimer.\n+ *\n+ * - Redistributions in binary form must reproduce the above\n+ *   copyright notice, this list of conditions and the following\n+ *   disclaimer in the documentation and/or other materials provided\n+ *   with the distribution.\n+ *\n+ * - Neither the name of the Git Development Community nor the\n+ *   names of its contributors may be used to endorse or promote\n+ *   products derived from this software without specific prior\n+ *   written permission.\n+ *\n+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND\n+ * CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES,\n+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES\n+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR\n+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT\n+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\n+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,\n+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\n+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF\n+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n+ */\n+\n+package org.spearce.jgit.lib;\n+\n+import junit.framework.TestCase;\n+\n+public class AbbreviatedObjectIdTest extends TestCase {\n+\tpublic void testEmpty_FromByteArray() {\n+\t\tfinal AbbreviatedObjectId i;\n+\t\ti = AbbreviatedObjectId.fromString(new byte[] {}, 0, 0);\n+\t\tassertNotNull(i);\n+\t\tassertEquals(0, i.length());\n+\t\tassertFalse(i.isComplete());\n+\t\tassertEquals(\"\", i.name());\n+\t}\n+\n+\tpublic void testEmpty_FromString() {\n+\t\tfinal AbbreviatedObjectId i = AbbreviatedObjectId.fromString(\"\");\n+\t\tassertNotNull(i);\n+\t\tassertEquals(0, i.length());\n+\t\tassertFalse(i.isComplete());\n+\t\tassertEquals(\"\", i.name());\n+\t}\n+\n+\tpublic void testFull_FromByteArray() {\n+\t\tfinal String s = \"7b6e8067ec96acef9a4184b43210d583b6d2f99a\";\n+\t\tfinal byte[] b = Constants.encodeASCII(s);\n+\t\tfinal AbbreviatedObjectId i = AbbreviatedObjectId.fromString(b, 0,\n+\t\t\t\tb.length);\n+\t\tassertNotNull(i);\n+\t\tassertEquals(s.length(), i.length());\n+\t\tassertTrue(i.isComplete());\n+\t\tassertEquals(s, i.name());\n+\n+\t\tfinal ObjectId f = i.toObjectId();\n+\t\tassertNotNull(f);\n+\t\tassertEquals(ObjectId.fromString(s), f);\n+\t\tassertEquals(f.hashCode(), i.hashCode());\n+\t}\n+\n+\tpublic void testFull_FromString() {\n+\t\tfinal String s = \"7b6e8067ec96acef9a4184b43210d583b6d2f99a\";\n+\t\tfinal AbbreviatedObjectId i = AbbreviatedObjectId.fromString(s);\n+\t\tassertNotNull(i);\n+\t\tassertEquals(s.length(), i.length());\n+\t\tassertTrue(i.isComplete());\n+\t\tassertEquals(s, i.name());\n+\n+\t\tfinal ObjectId f = i.toObjectId();\n+\t\tassertNotNull(f);\n+\t\tassertEquals(ObjectId.fromString(s), f);\n+\t\tassertEquals(f.hashCode(), i.hashCode());\n+\t}\n+\n+\tpublic void test1_FromString() {\n+\t\tfinal String s = \"7\";\n+\t\tfinal AbbreviatedObjectId i = AbbreviatedObjectId.fromString(s);\n+\t\tassertNotNull(i);\n+\t\tassertEquals(s.length(), i.length());\n+\t\tassertFalse(i.isComplete());\n+\t\tassertEquals(s, i.name());\n+\t\tassertNull(i.toObjectId());\n+\t}\n+\n+\tpublic void test2_FromString() {\n+\t\tfinal String s = \"7b\";\n+\t\tfinal AbbreviatedObjectId i = AbbreviatedObjectId.fromString(s);\n+\t\tassertNotNull(i);\n+\t\tassertEquals(s.length(), i.length());\n+\t\tassertFalse(i.isComplete());\n+\t\tassertEquals(s, i.name());\n+\t\tassertNull(i.toObjectId());\n+\t}\n+\n+\tpublic void test3_FromString() {\n+\t\tfinal String s = \"7b6\";\n+\t\tfinal AbbreviatedObjectId i = AbbreviatedObjectId.fromString(s);\n+\t\tassertNotNull(i);\n+\t\tassertEquals(s.length(), i.length());\n+\t\tassertFalse(i.isComplete());\n+\t\tassertEquals(s, i.name());\n+\t\tassertNull(i.toObjectId());\n+\t}\n+\n+\tpublic void test4_FromString() {\n+\t\tfinal String s = \"7b6e\";\n+\t\tfinal AbbreviatedObjectId i = AbbreviatedObjectId.fromString(s);\n+\t\tassertNotNull(i);\n+\t\tassertEquals(s.length(), i.length());\n+\t\tassertFalse(i.isComplete());\n+\t\tassertEquals(s, i.name());\n+\t\tassertNull(i.toObjectId());\n+\t}\n+\n+\tpublic void test5_FromString() {\n+\t\tfinal String s = \"7b6e8\";\n+\t\tfinal AbbreviatedObjectId i = AbbreviatedObjectId.fromString(s);\n+\t\tassertNotNull(i);\n+\t\tassertEquals(s.length(), i.length());\n+\t\tassertFalse(i.isComplete());\n+\t\tassertEquals(s, i.name());\n+\t\tassertNull(i.toObjectId());\n+\t}\n+\n+\tpublic void test6_FromString() {\n+\t\tfinal String s = \"7b6e80\";\n+\t\tfinal AbbreviatedObjectId i = AbbreviatedObjectId.fromString(s);\n+\t\tassertNotNull(i);\n+\t\tassertEquals(s.length(), i.length());\n+\t\tassertFalse(i.isComplete());\n+\t\tassertEquals(s, i.name());\n+\t\tassertNull(i.toObjectId());\n+\t}\n+\n+\tpublic void test7_FromString() {\n+\t\tfinal String s = \"7b6e806\";\n+\t\tfinal AbbreviatedObjectId i = AbbreviatedObjectId.fromString(s);\n+\t\tassertNotNull(i);\n+\t\tassertEquals(s.length(), i.length());\n+\t\tassertFalse(i.isComplete());\n+\t\tassertEquals(s, i.name());\n+\t\tassertNull(i.toObjectId());\n+\t}\n+\n+\tpublic void test8_FromString() {\n+\t\tfinal String s = \"7b6e8067\";\n+\t\tfinal AbbreviatedObjectId i = AbbreviatedObjectId.fromString(s);\n+\t\tassertNotNull(i);\n+\t\tassertEquals(s.length(), i.length());\n+\t\tassertFalse(i.isComplete());\n+\t\tassertEquals(s, i.name());\n+\t\tassertNull(i.toObjectId());\n+\t}\n+\n+\tpublic void test9_FromString() {\n+\t\tfinal String s = \"7b6e8067e\";\n+\t\tfinal AbbreviatedObjectId i = AbbreviatedObjectId.fromString(s);\n+\t\tassertNotNull(i);\n+\t\tassertEquals(s.length(), i.length());\n+\t\tassertFalse(i.isComplete());\n+\t\tassertEquals(s, i.name());\n+\t\tassertNull(i.toObjectId());\n+\t}\n+\n+\tpublic void test17_FromString() {\n+\t\tfinal String s = \"7b6e8067ec96acef9\";\n+\t\tfinal AbbreviatedObjectId i = AbbreviatedObjectId.fromString(s);\n+\t\tassertNotNull(i);\n+\t\tassertEquals(s.length(), i.length());\n+\t\tassertFalse(i.isComplete());\n+\t\tassertEquals(s, i.name());\n+\t\tassertNull(i.toObjectId());\n+\t}\n+\n+\tpublic void testEquals_Short() {\n+\t\tfinal String s = \"7b6e8067\";\n+\t\tfinal AbbreviatedObjectId a = AbbreviatedObjectId.fromString(s);\n+\t\tfinal AbbreviatedObjectId b = AbbreviatedObjectId.fromString(s);\n+\t\tassertNotSame(a, b);\n+\t\tassertTrue(a.hashCode() == b.hashCode());\n+\t\tassertTrue(a.equals(b));\n+\t\tassertTrue(b.equals(a));\n+\t}\n+\n+\tpublic void testEquals_Full() {\n+\t\tfinal String s = \"7b6e8067ec96acef9a4184b43210d583b6d2f99a\";\n+\t\tfinal AbbreviatedObjectId a = AbbreviatedObjectId.fromString(s);\n+\t\tfinal AbbreviatedObjectId b = AbbreviatedObjectId.fromString(s);\n+\t\tassertNotSame(a, b);\n+\t\tassertTrue(a.hashCode() == b.hashCode());\n+\t\tassertTrue(a.equals(b));\n+\t\tassertTrue(b.equals(a));\n+\t}\n+\n+\tpublic void testNotEquals_SameLength() {\n+\t\tfinal String sa = \"7b6e8067\";\n+\t\tfinal String sb = \"7b6e806e\";\n+\t\tfinal AbbreviatedObjectId a = AbbreviatedObjectId.fromString(sa);\n+\t\tfinal AbbreviatedObjectId b = AbbreviatedObjectId.fromString(sb);\n+\t\tassertFalse(a.equals(b));\n+\t\tassertFalse(b.equals(a));\n+\t}\n+\n+\tpublic void testNotEquals_DiffLength() {\n+\t\tfinal String sa = \"7b6e8067abcd\";\n+\t\tfinal String sb = \"7b6e8067\";\n+\t\tfinal AbbreviatedObjectId a = AbbreviatedObjectId.fromString(sa);\n+\t\tfinal AbbreviatedObjectId b = AbbreviatedObjectId.fromString(sb);\n+\t\tassertFalse(a.equals(b));\n+\t\tassertFalse(b.equals(a));\n+\t}\n+}\ndiff --git a/org.spearce.jgit/src/org/spearce/jgit/lib/AbbreviatedObjectId.java b/org.spearce.jgit/src/org/spearce/jgit/lib/AbbreviatedObjectId.java\nnew file mode 100644\nindex 0000000..1a8d296\n--- /dev/null\n+++ b/org.spearce.jgit/src/org/spearce/jgit/lib/AbbreviatedObjectId.java\n@@ -0,0 +1,205 @@\n+/*\n+ * Copyright (C) 2008, Google Inc.\n+ *\n+ * All rights reserved.\n+ *\n+ * Redistribution and use in source and binary forms, with or\n+ * without modification, are permitted provided that the following\n+ * conditions are met:\n+ *\n+ * - Redistributions of source code must retain the above copyright\n+ *   notice, this list of conditions and the following disclaimer.\n+ *\n+ * - Redistributions in binary form must reproduce the above\n+ *   copyright notice, this list of conditions and the following\n+ *   disclaimer in the documentation and/or other materials provided\n+ *   with the distribution.\n+ *\n+ * - Neither the name of the Git Development Community nor the\n+ *   names of its contributors may be used to endorse or promote\n+ *   products derived from this software without specific prior\n+ *   written permission.\n+ *\n+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND\n+ * CONTRIBUTORS \"AS IS\" AND ANY EXPRESS OR IMPLIED WARRANTIES,\n+ * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES\n+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE\n+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR\n+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,\n+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT\n+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;\n+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\n+ * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,\n+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)\n+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF\n+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n+ */\n+\n+package org.spearce.jgit.lib;\n+\n+import java.io.UnsupportedEncodingException;\n+\n+/**\n+ * A prefix abbreviation of an {@link ObjectId}.\n+ * <p>\n+ * Sometimes Git produces abbreviated SHA-1 strings, using sufficient leading\n+ * digits from the ObjectId name to still be unique within the repository the\n+ * string was generated from. These ids are likely to be unique for a useful\n+ * period of time, especially if they contain at least 6-10 hex digits.\n+ * <p>\n+ * This class converts the hex string into a binary form, to make it more\n+ * efficient for matching against an object.\n+ */\n+public class AbbreviatedObjectId {\n+\t/**\n+\t * Convert an AbbreviatedObjectId from hex characters (US-ASCII).\n+\t * \n+\t * @param buf\n+\t *            the US-ASCII buffer to read from.\n+\t * @param offset\n+\t *            position to read the first character from.\n+\t * @param end\n+\t *            one past the last position to read (<code>end-offset</code> is\n+\t *            the length of the string).\n+\t * @return the converted object id.\n+\t */\n+\tpublic static final AbbreviatedObjectId fromString(final byte[] buf,\n+\t\t\tfinal int offset, final int end) {\n+\t\tif (end - offset > AnyObjectId.STR_LEN)\n+\t\t\tthrow new IllegalArgumentException(\"Invalid id\");\n+\t\treturn fromHexString(buf, offset, end);\n+\t}\n+\n+\t/**\n+\t * Convert an AbbreviatedObjectId from hex characters.\n+\t * \n+\t * @param str\n+\t *            the string to read from. Must be &lt;= 40 characters.\n+\t * @return the converted object id.\n+\t */\n+\tpublic static final AbbreviatedObjectId fromString(final String str) {\n+\t\tif (str.length() > AnyObjectId.STR_LEN)\n+\t\t\tthrow new IllegalArgumentException(\"Invalid id: \" + str);\n+\t\tfinal byte[] b = Constants.encodeASCII(str);\n+\t\treturn fromHexString(b, 0, b.length);\n+\t}\n+\n+\tprivate static final AbbreviatedObjectId fromHexString(final byte[] bs,\n+\t\t\tint ptr, final int end) {\n+\t\ttry {\n+\t\t\tfinal int a = hexUInt32(bs, ptr, end);\n+\t\t\tfinal int b = hexUInt32(bs, ptr + 8, end);\n+\t\t\tfinal int c = hexUInt32(bs, ptr + 16, end);\n+\t\t\tfinal int d = hexUInt32(bs, ptr + 24, end);\n+\t\t\tfinal int e = hexUInt32(bs, ptr + 32, end);\n+\t\t\treturn new AbbreviatedObjectId(end - ptr, a, b, c, d, e);\n+\t\t} catch (ArrayIndexOutOfBoundsException e1) {\n+\t\t\ttry {\n+\t\t\t\tfinal String str = new String(bs, ptr, end - ptr, \"US-ASCII\");\n+\t\t\t\tthrow new IllegalArgumentException(\"Invalid id: \" + str);\n+\t\t\t} catch (UnsupportedEncodingException e2) {\n+\t\t\t\tthrow new IllegalArgumentException(\"Invalid id\");\n+\t\t\t}\n+\t\t}\n+\t}\n+\n+\tprivate static final int hexUInt32(final byte[] bs, int p, final int end) {\n+\t\tif (8 <= end - p)\n+\t\t\treturn AnyObjectId.hexUInt32(bs, p);\n+\n+\t\tint r = 0, n = 0;\n+\t\twhile (n < 8 && p < end) {\n+\t\t\tfinal int v = AnyObjectId.fromhex[bs[p++]];\n+\t\t\tif (v < 0)\n+\t\t\t\tthrow new ArrayIndexOutOfBoundsException();\n+\t\t\tr <<= 4;\n+\t\t\tr |= v;\n+\t\t\tn++;\n+\t\t}\n+\t\treturn r << (8 - n) * 4;\n+\t}\n+\n+\t/** Number of half-bytes used by this id. */\n+\tfinal int nibbles;\n+\n+\tfinal int w1;\n+\n+\tfinal int w2;\n+\n+\tfinal int w3;\n+\n+\tfinal int w4;\n+\n+\tfinal int w5;\n+\n+\tprivate AbbreviatedObjectId(final int n, final int new_1, final int new_2,\n+\t\t\tfinal int new_3, final int new_4, final int new_5) {\n+\t\tnibbles = n;\n+\t\tw1 = new_1;\n+\t\tw2 = new_2;\n+\t\tw3 = new_3;\n+\t\tw4 = new_4;\n+\t\tw5 = new_5;\n+\t}\n+\n+\t/** @return number of hex digits appearing in this id */\n+\tpublic int length() {\n+\t\treturn nibbles;\n+\t}\n+\n+\t/** @return true if this ObjectId is actually a complete id. */\n+\tpublic boolean isComplete() {\n+\t\treturn length() == AnyObjectId.RAW_LEN * 2;\n+\t}\n+\n+\t/** @return a complete ObjectId; null if {@link #isComplete()} is false */\n+\tpublic ObjectId toObjectId() {\n+\t\treturn isComplete() ? new ObjectId(w1, w2, w3, w4, w5) : null;\n+\t}\n+\n+\t@Override\n+\tpublic int hashCode() {\n+\t\treturn w2;\n+\t}\n+\n+\t@Override\n+\tpublic boolean equals(final Object o) {\n+\t\tif (o instanceof AbbreviatedObjectId) {\n+\t\t\tfinal AbbreviatedObjectId b = (AbbreviatedObjectId) o;\n+\t\t\treturn nibbles == b.nibbles && w1 == b.w1 && w2 == b.w2\n+\t\t\t\t\t&& w3 == b.w3 && w4 == b.w4 && w5 == b.w5;\n+\t\t}\n+\t\treturn false;\n+\t}\n+\n+\t/**\n+\t * @return string form of the abbreviation, in lower case hexadecimal.\n+\t */\n+\tpublic final String name() {\n+\t\tfinal char[] b = new char[AnyObjectId.STR_LEN];\n+\n+\t\tAnyObjectId.formatHexChar(b, 0, w1);\n+\t\tif (nibbles <= 8)\n+\t\t\treturn new String(b, 0, nibbles);\n+\n+\t\tAnyObjectId.formatHexChar(b, 8, w2);\n+\t\tif (nibbles <= 16)\n+\t\t\treturn new String(b, 0, nibbles);\n+\n+\t\tAnyObjectId.formatHexChar(b, 16, w3);\n+\t\tif (nibbles <= 24)\n+\t\t\treturn new String(b, 0, nibbles);\n+\n+\t\tAnyObjectId.formatHexChar(b, 24, w4);\n+\t\tif (nibbles <= 32)\n+\t\t\treturn new String(b, 0, nibbles);\n+\n+\t\tAnyObjectId.formatHexChar(b, 32, w5);\n+\t\treturn new String(b, 0, nibbles);\n+\t}\n+\n+\t@Override\n+\tpublic String toString() {\n+\t\treturn \"AbbreviatedObjectId[\" + name() + \"]\";\n+\t}\n+}\ndiff --git a/org.spearce.jgit/src/org/spearce/jgit/lib/AnyObjectId.java b/org.spearce.jgit/src/org/spearce/jgit/lib/AnyObjectId.java\nindex a534202..e88e09d 100644\n--- a/org.spearce.jgit/src/org/spearce/jgit/lib/AnyObjectId.java\n+++ b/org.spearce.jgit/src/org/spearce/jgit/lib/AnyObjectId.java\n@@ -396,7 +396,7 @@ private void toHexCharArray(final char[] dst) {\n \tprivate static final char[] hexchar = { '0', '1', '2', '3', '4', '5', '6',\n \t\t\t'7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };\n \n-\tprivate static void formatHexChar(final char[] dst, final int p, int w) {\n+\tstatic void formatHexChar(final char[] dst, final int p, int w) {\n \t\tint o = p + 7;\n \t\twhile (o >= p && w != 0) {\n \t\t\tdst[o--] = hexchar[w & 0xf];\n-- \n1.6.1.rc2.299.gead4c\n"},{"id":"97538","messageId":"1228951107-5546-3-git-send-email-spearce@spearce.org","threadId":"16676","inReplyTo":"1228951107-5546-2-git-send-email-spearce@spearce.org","subject":"[JGIT PATCH 2/3] Add ObjectId.startsWith(AbbreviatedObjectId)","fromName":"Shawn O. Pearce","fromEmail":"spearce@spearce.org","sentAt":"2008-12-10T23:18:26Z","receivedAt":"2008-12-10T23:18:26Z","isPatch":true,"sender":{"key":"spearce@spearce.org","avatar":"https://avatars.githubusercontent.com/u/34844?v=4"},"body":"This test can be useful to determine if the object id at least\nbegins with an abbreviated id.\n\nSigned-off-by: Shawn O. Pearce <spearce@spearce.org>\n---\n .../spearce/jgit/lib/AbbreviatedObjectIdTest.java  |   58 ++++++++++++++++++++\n .../org/spearce/jgit/lib/AbbreviatedObjectId.java  |   57 +++++++++++++++++++\n .../src/org/spearce/jgit/lib/AnyObjectId.java      |   11 ++++\n 3 files changed, 126 insertions(+), 0 deletions(-)\n\ndiff --git a/org.spearce.jgit.test/tst/org/spearce/jgit/lib/AbbreviatedObjectIdTest.java b/org.spearce.jgit.test/tst/org/spearce/jgit/lib/AbbreviatedObjectIdTest.java\nindex f540f49..3f82d50 100644\n--- a/org.spearce.jgit.test/tst/org/spearce/jgit/lib/AbbreviatedObjectIdTest.java\n+++ b/org.spearce.jgit.test/tst/org/spearce/jgit/lib/AbbreviatedObjectIdTest.java\n@@ -224,4 +224,62 @@ public void testNotEquals_DiffLength() {\n \t\tassertFalse(a.equals(b));\n \t\tassertFalse(b.equals(a));\n \t}\n+\n+\tpublic void testPrefixCompare_Full() {\n+\t\tfinal String s1 = \"7b6e8067ec96acef9a4184b43210d583b6d2f99a\";\n+\t\tfinal AbbreviatedObjectId a = AbbreviatedObjectId.fromString(s1);\n+\t\tfinal ObjectId i1 = ObjectId.fromString(s1);\n+\t\tassertEquals(0, a.prefixCompare(i1));\n+\t\tassertTrue(i1.startsWith(a));\n+\n+\t\tfinal String s2 = \"7b6e8067ec96acef9a4184b43210d583b6d2f99b\";\n+\t\tfinal ObjectId i2 = ObjectId.fromString(s2);\n+\t\tassertTrue(a.prefixCompare(i2) < 0);\n+\t\tassertFalse(i2.startsWith(a));\n+\n+\t\tfinal String s3 = \"7b6e8067ec96acef9a4184b43210d583b6d2f999\";\n+\t\tfinal ObjectId i3 = ObjectId.fromString(s3);\n+\t\tassertTrue(a.prefixCompare(i3) > 0);\n+\t\tassertFalse(i3.startsWith(a));\n+\t}\n+\n+\tpublic void testPrefixCompare_1() {\n+\t\tfinal String sa = \"7\";\n+\t\tfinal AbbreviatedObjectId a = AbbreviatedObjectId.fromString(sa);\n+\n+\t\tfinal String s1 = \"7b6e8067ec96acef9a4184b43210d583b6d2f99a\";\n+\t\tfinal ObjectId i1 = ObjectId.fromString(s1);\n+\t\tassertEquals(0, a.prefixCompare(i1));\n+\t\tassertTrue(i1.startsWith(a));\n+\n+\t\tfinal String s2 = \"8b6e8067ec96acef9a4184b43210d583b6d2f99a\";\n+\t\tfinal ObjectId i2 = ObjectId.fromString(s2);\n+\t\tassertTrue(a.prefixCompare(i2) < 0);\n+\t\tassertFalse(i2.startsWith(a));\n+\n+\t\tfinal String s3 = \"6b6e8067ec96acef9a4184b43210d583b6d2f99a\";\n+\t\tfinal ObjectId i3 = ObjectId.fromString(s3);\n+\t\tassertTrue(a.prefixCompare(i3) > 0);\n+\t\tassertFalse(i3.startsWith(a));\n+\t}\n+\n+\tpublic void testPrefixCompare_17() {\n+\t\tfinal String sa = \"7b6e8067ec96acef9\";\n+\t\tfinal AbbreviatedObjectId a = AbbreviatedObjectId.fromString(sa);\n+\n+\t\tfinal String s1 = \"7b6e8067ec96acef9a4184b43210d583b6d2f99a\";\n+\t\tfinal ObjectId i1 = ObjectId.fromString(s1);\n+\t\tassertEquals(0, a.prefixCompare(i1));\n+\t\tassertTrue(i1.startsWith(a));\n+\n+\t\tfinal String s2 = \"7b6e8067eca6acef9a4184b43210d583b6d2f99a\";\n+\t\tfinal ObjectId i2 = ObjectId.fromString(s2);\n+\t\tassertTrue(a.prefixCompare(i2) < 0);\n+\t\tassertFalse(i2.startsWith(a));\n+\n+\t\tfinal String s3 = \"7b6e8067ec86acef9a4184b43210d583b6d2f99a\";\n+\t\tfinal ObjectId i3 = ObjectId.fromString(s3);\n+\t\tassertTrue(a.prefixCompare(i3) > 0);\n+\t\tassertFalse(i3.startsWith(a));\n+\t}\n }\ndiff --git a/org.spearce.jgit/src/org/spearce/jgit/lib/AbbreviatedObjectId.java b/org.spearce.jgit/src/org/spearce/jgit/lib/AbbreviatedObjectId.java\nindex 1a8d296..206cc2f 100644\n--- a/org.spearce.jgit/src/org/spearce/jgit/lib/AbbreviatedObjectId.java\n+++ b/org.spearce.jgit/src/org/spearce/jgit/lib/AbbreviatedObjectId.java\n@@ -39,6 +39,8 @@\n \n import java.io.UnsupportedEncodingException;\n \n+import org.spearce.jgit.util.NB;\n+\n /**\n  * A prefix abbreviation of an {@link ObjectId}.\n  * <p>\n@@ -119,6 +121,24 @@ private static final int hexUInt32(final byte[] bs, int p, final int end) {\n \t\treturn r << (8 - n) * 4;\n \t}\n \n+\tstatic int mask(final int nibbles, final int word, final int v) {\n+\t\tfinal int b = (word - 1) * 8;\n+\t\tif (b + 8 <= nibbles) {\n+\t\t\t// We have all of the bits required for this word.\n+\t\t\t//\n+\t\t\treturn v;\n+\t\t}\n+\n+\t\tif (nibbles < b) {\n+\t\t\t// We have none of the bits required for this word.\n+\t\t\t//\n+\t\t\treturn 0;\n+\t\t}\n+\n+\t\tfinal int s = 32 - (nibbles - b) * 4;\n+\t\treturn (v >>> s) << s;\n+\t}\n+\n \t/** Number of half-bytes used by this id. */\n \tfinal int nibbles;\n \n@@ -157,6 +177,43 @@ public ObjectId toObjectId() {\n \t\treturn isComplete() ? new ObjectId(w1, w2, w3, w4, w5) : null;\n \t}\n \n+\t/**\n+\t * Compares this abbreviation to a full object id.\n+\t * \n+\t * @param other\n+\t *            the other object id.\n+\t * @return &lt;0 if this abbreviation names an object that is less than\n+\t *         <code>other</code>; 0 if this abbreviation exactly matches the\n+\t *         first {@link #length()} digits of <code>other.name()</code>;\n+\t *         &gt;0 if this abbreviation names an object that is after\n+\t *         <code>other</code>.\n+\t */\n+\tpublic int prefixCompare(final AnyObjectId other) {\n+\t\tint cmp;\n+\n+\t\tcmp = NB.compareUInt32(w1, mask(1, other.w1));\n+\t\tif (cmp != 0)\n+\t\t\treturn cmp;\n+\n+\t\tcmp = NB.compareUInt32(w2, mask(2, other.w2));\n+\t\tif (cmp != 0)\n+\t\t\treturn cmp;\n+\n+\t\tcmp = NB.compareUInt32(w3, mask(3, other.w3));\n+\t\tif (cmp != 0)\n+\t\t\treturn cmp;\n+\n+\t\tcmp = NB.compareUInt32(w4, mask(4, other.w4));\n+\t\tif (cmp != 0)\n+\t\t\treturn cmp;\n+\n+\t\treturn NB.compareUInt32(w5, mask(5, other.w5));\n+\t}\n+\n+\tprivate int mask(final int word, final int v) {\n+\t\treturn mask(nibbles, word, v);\n+\t}\n+\n \t@Override\n \tpublic int hashCode() {\n \t\treturn w2;\ndiff --git a/org.spearce.jgit/src/org/spearce/jgit/lib/AnyObjectId.java b/org.spearce.jgit/src/org/spearce/jgit/lib/AnyObjectId.java\nindex e88e09d..8872017 100644\n--- a/org.spearce.jgit/src/org/spearce/jgit/lib/AnyObjectId.java\n+++ b/org.spearce.jgit/src/org/spearce/jgit/lib/AnyObjectId.java\n@@ -226,6 +226,17 @@ int compareTo(final int[] bs, final int p) {\n \t\treturn NB.compareUInt32(w5, bs[p + 4]);\n \t}\n \n+\t/**\n+\t * Tests if this ObjectId starts with the given abbreviation.\n+\t * \n+\t * @param abbr\n+\t *            the abbreviation.\n+\t * @return true if this ObjectId begins with the abbreviation; else false.\n+\t */\n+\tpublic boolean startsWith(final AbbreviatedObjectId abbr) {\n+\t\treturn abbr.prefixCompare(this) == 0;\n+\t}\n+\n \tpublic int hashCode() {\n \t\treturn w2;\n \t}\n-- \n1.6.1.rc2.299.gead4c\n"},{"id":"97537","messageId":"1228951107-5546-4-git-send-email-spearce@spearce.org","threadId":"16676","inReplyTo":"1228951107-5546-3-git-send-email-spearce@spearce.org","subject":"[JGIT PATCH 3/3] Change AnyObjectId.abbreviate() to return AbbreviatedObjectId","fromName":"Shawn O. Pearce","fromEmail":"spearce@spearce.org","sentAt":"2008-12-10T23:18:27Z","receivedAt":"2008-12-10T23:18:27Z","isPatch":true,"sender":{"key":"spearce@spearce.org","avatar":"https://avatars.githubusercontent.com/u/34844?v=4"},"body":"By returning our abstraction type we can reuse the logic inside\nAbbreviatedObjectId to format the abbreviated string.  A result\ncan also be used to test against another ObjectId.\n\nSigned-off-by: Shawn O. Pearce <spearce@spearce.org>\n---\n .../ui/internal/components/RefContentProposal.java |    2 +-\n .../egit/ui/internal/fetch/FetchResultTable.java   |   12 ++++----\n .../egit/ui/internal/push/PushResultTable.java     |   21 ++++++++-------\n .../src/org/spearce/jgit/pgm/Branch.java           |    2 +-\n .../src/org/spearce/jgit/pgm/Fetch.java            |    8 +++---\n .../src/org/spearce/jgit/pgm/Push.java             |    5 ++-\n .../org/spearce/jgit/lib/AbbreviatedObjectId.java  |    4 +-\n .../src/org/spearce/jgit/lib/AnyObjectId.java      |   26 +++++++++++++++++--\n 8 files changed, 51 insertions(+), 29 deletions(-)\n\ndiff --git a/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/components/RefContentProposal.java b/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/components/RefContentProposal.java\nindex 60abaf3..b63c428 100644\n--- a/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/components/RefContentProposal.java\n+++ b/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/components/RefContentProposal.java\n@@ -111,7 +111,7 @@ public String getDescription() {\n \t\tfinal StringBuilder sb = new StringBuilder();\n \t\tsb.append(refName);\n \t\tsb.append('\\n');\n-\t\tsb.append(objectId.abbreviate(db));\n+\t\tsb.append(objectId.abbreviate(db).name());\n \t\tsb.append(\" - \");\n \t\tif (obj instanceof Commit) {\n \t\t\tfinal Commit c = ((Commit) obj);\ndiff --git a/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/fetch/FetchResultTable.java b/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/fetch/FetchResultTable.java\nindex 868ca94..f1169d1 100644\n--- a/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/fetch/FetchResultTable.java\n+++ b/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/fetch/FetchResultTable.java\n@@ -137,15 +137,15 @@ else if (tru.getLocalName().startsWith(Constants.R_TAGS))\n \t\t\t\t}\n \n \t\t\t\tif (r == RefUpdate.Result.FORCED) {\n-\t\t\t\t\tfinal String aOld = tru.getOldObjectId().abbreviate(db);\n-\t\t\t\t\tfinal String aNew = tru.getNewObjectId().abbreviate(db);\n-\t\t\t\t\treturn aOld + \"...\" + aNew; //$NON-NLS-1$\n+\t\t\t\t\tfinal String o = tru.getOldObjectId().abbreviate(db).name();\n+\t\t\t\t\tfinal String n = tru.getNewObjectId().abbreviate(db).name();\n+\t\t\t\t\treturn o + \"...\" + n; //$NON-NLS-1$\n \t\t\t\t}\n \n \t\t\t\tif (r == RefUpdate.Result.FAST_FORWARD) {\n-\t\t\t\t\tfinal String aOld = tru.getOldObjectId().abbreviate(db);\n-\t\t\t\t\tfinal String aNew = tru.getNewObjectId().abbreviate(db);\n-\t\t\t\t\treturn aOld + \"..\" + aNew; //$NON-NLS-1$\n+\t\t\t\t\tfinal String o = tru.getOldObjectId().abbreviate(db).name();\n+\t\t\t\t\tfinal String n = tru.getNewObjectId().abbreviate(db).name();\n+\t\t\t\t\treturn o + \"..\" + n; //$NON-NLS-1$\n \t\t\t\t}\n \n \t\t\t\tif (r == RefUpdate.Result.REJECTED)\ndiff --git a/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/push/PushResultTable.java b/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/push/PushResultTable.java\nindex c5e476b..6f460dc 100644\n--- a/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/push/PushResultTable.java\n+++ b/org.spearce.egit.ui/src/org/spearce/egit/ui/internal/push/PushResultTable.java\n@@ -233,9 +233,9 @@ public String getText(Object element) {\n \t\t\t\t\treturn UIText.PushResultTable_statusOkNewBranch;\n \t\t\t\t}\n \n-\t\t\t\treturn oldRef.getObjectId().abbreviate(localDb)\n+\t\t\t\treturn oldRef.getObjectId().abbreviate(localDb).name()\n \t\t\t\t\t\t+ (rru.isFastForward() ? \"..\" : \"...\")\n-\t\t\t\t\t\t+ rru.getNewObjectId().abbreviate(localDb);\n+\t\t\t\t\t\t+ rru.getNewObjectId().abbreviate(localDb).name();\n \t\t\tcase UP_TO_DATE:\n \t\t\t\treturn UIText.PushResultTable_statusUpToDate;\n \t\t\tcase NON_EXISTING:\n@@ -289,7 +289,7 @@ public String getToolTipText(Object element) {\n \t\t\tcase OK:\n \t\t\t\tif (rru.isDelete())\n \t\t\t\t\treturn NLS.bind(UIText.PushResultTable_statusDetailDeleted,\n-\t\t\t\t\t\t\toldRef.getObjectId().abbreviate(localDb));\n+\t\t\t\t\t\t\toldRef.getObjectId().abbreviate(localDb).name());\n \t\t\t\tif (oldRef == null)\n \t\t\t\t\treturn null;\n \t\t\t\tif (rru.isFastForward())\n@@ -305,20 +305,21 @@ public String getToolTipText(Object element) {\n \t\t\t\treturn UIText.PushResultTable_statusDetailNonFastForward;\n \t\t\tcase REJECTED_REMOTE_CHANGED:\n \t\t\t\tfinal Ref remoteRef = oldRef;\n-\t\t\t\tfinal String currentValue;\n+\t\t\t\tfinal String curVal;\n \t\t\t\tif (remoteRef == null)\n-\t\t\t\t\tcurrentValue = UIText.PushResultTable_refNonExisting;\n+\t\t\t\t\tcurVal = UIText.PushResultTable_refNonExisting;\n \t\t\t\telse\n-\t\t\t\t\tcurrentValue = remoteRef.getObjectId().abbreviate(localDb);\n+\t\t\t\t\tcurVal = remoteRef.getObjectId().abbreviate(localDb).name();\n+\n \t\t\t\tfinal ObjectId expectedOldObjectId = rru\n \t\t\t\t\t\t.getExpectedOldObjectId();\n-\t\t\t\tfinal String expectedValue;\n+\t\t\t\tfinal String expVal;\n \t\t\t\tif (expectedOldObjectId.equals(ObjectId.zeroId()))\n-\t\t\t\t\texpectedValue = UIText.PushResultTable_refNonExisting;\n+\t\t\t\t\texpVal = UIText.PushResultTable_refNonExisting;\n \t\t\t\telse\n-\t\t\t\t\texpectedValue = expectedOldObjectId.abbreviate(localDb);\n+\t\t\t\t\texpVal = expectedOldObjectId.abbreviate(localDb).name();\n \t\t\t\treturn NLS.bind(UIText.PushResultTable_statusDetailChanged,\n-\t\t\t\t\t\tcurrentValue, expectedValue);\n+\t\t\t\t\t\tcurVal, expVal);\n \t\t\tcase REJECTED_OTHER_REASON:\n \t\t\t\treturn rru.getMessage();\n \t\t\tdefault:\ndiff --git a/org.spearce.jgit.pgm/src/org/spearce/jgit/pgm/Branch.java b/org.spearce.jgit.pgm/src/org/spearce/jgit/pgm/Branch.java\nindex db0aab8..11002f0 100644\n--- a/org.spearce.jgit.pgm/src/org/spearce/jgit/pgm/Branch.java\n+++ b/org.spearce.jgit.pgm/src/org/spearce/jgit/pgm/Branch.java\n@@ -167,7 +167,7 @@ private void printHead(final String ref, final boolean isCurrent,\n \t\t\tfinal int spaces = maxNameLength - ref.length() + 1;\n \t\t\tout.print(String.format(\"%\" + spaces + \"s\", \"\"));\n \t\t\tfinal ObjectId objectId = refObj.getObjectId();\n-\t\t\tout.print(objectId.abbreviate(db));\n+\t\t\tout.print(objectId.abbreviate(db).name());\n \t\t\tout.print(' ');\n \t\t\tout.print(rw.parseCommit(objectId).getShortMessage());\n \t\t}\ndiff --git a/org.spearce.jgit.pgm/src/org/spearce/jgit/pgm/Fetch.java b/org.spearce.jgit.pgm/src/org/spearce/jgit/pgm/Fetch.java\nindex ad7e08f..e9d3260 100644\n--- a/org.spearce.jgit.pgm/src/org/spearce/jgit/pgm/Fetch.java\n+++ b/org.spearce.jgit.pgm/src/org/spearce/jgit/pgm/Fetch.java\n@@ -131,14 +131,14 @@ else if (u.getLocalName().startsWith(Constants.R_TAGS))\n \t\t}\n \n \t\tif (r == RefUpdate.Result.FORCED) {\n-\t\t\tfinal String aOld = u.getOldObjectId().abbreviate(db);\n-\t\t\tfinal String aNew = u.getNewObjectId().abbreviate(db);\n+\t\t\tfinal String aOld = u.getOldObjectId().abbreviate(db).name();\n+\t\t\tfinal String aNew = u.getNewObjectId().abbreviate(db).name();\n \t\t\treturn aOld + \"...\" + aNew;\n \t\t}\n \n \t\tif (r == RefUpdate.Result.FAST_FORWARD) {\n-\t\t\tfinal String aOld = u.getOldObjectId().abbreviate(db);\n-\t\t\tfinal String aNew = u.getNewObjectId().abbreviate(db);\n+\t\t\tfinal String aOld = u.getOldObjectId().abbreviate(db).name();\n+\t\t\tfinal String aNew = u.getNewObjectId().abbreviate(db).name();\n \t\t\treturn aOld + \"..\" + aNew;\n \t\t}\n \ndiff --git a/org.spearce.jgit.pgm/src/org/spearce/jgit/pgm/Push.java b/org.spearce.jgit.pgm/src/org/spearce/jgit/pgm/Push.java\nindex 53ad080..19d31a1 100644\n--- a/org.spearce.jgit.pgm/src/org/spearce/jgit/pgm/Push.java\n+++ b/org.spearce.jgit.pgm/src/org/spearce/jgit/pgm/Push.java\n@@ -181,8 +181,9 @@ private void printRefUpdateResult(final URIish uri,\n \t\t\t\t\tboolean fastForward = rru.isFastForward();\n \t\t\t\t\tfinal char flag = fastForward ? ' ' : '+';\n \t\t\t\t\tfinal String summary = oldRef.getObjectId().abbreviate(db)\n+\t\t\t\t\t\t\t.name()\n \t\t\t\t\t\t\t+ (fastForward ? \"..\" : \"...\")\n-\t\t\t\t\t\t\t+ rru.getNewObjectId().abbreviate(db);\n+\t\t\t\t\t\t\t+ rru.getNewObjectId().abbreviate(db).name();\n \t\t\t\t\tfinal String message = fastForward ? null : \"forced update\";\n \t\t\t\t\tprintUpdateLine(flag, summary, srcRef, remoteName, message);\n \t\t\t\t}\n@@ -205,7 +206,7 @@ printUpdateLine('!', \"[rejected]\", srcRef, remoteName,\n \n \t\tcase REJECTED_REMOTE_CHANGED:\n \t\t\tfinal String message = \"remote ref object changed - is not expected one \"\n-\t\t\t\t\t+ rru.getExpectedOldObjectId().abbreviate(db);\n+\t\t\t\t\t+ rru.getExpectedOldObjectId().abbreviate(db).name();\n \t\t\tprintUpdateLine('!', \"[rejected]\", srcRef, remoteName, message);\n \t\t\tbreak;\n \ndiff --git a/org.spearce.jgit/src/org/spearce/jgit/lib/AbbreviatedObjectId.java b/org.spearce.jgit/src/org/spearce/jgit/lib/AbbreviatedObjectId.java\nindex 206cc2f..33b62b9 100644\n--- a/org.spearce.jgit/src/org/spearce/jgit/lib/AbbreviatedObjectId.java\n+++ b/org.spearce.jgit/src/org/spearce/jgit/lib/AbbreviatedObjectId.java\n@@ -52,7 +52,7 @@\n  * This class converts the hex string into a binary form, to make it more\n  * efficient for matching against an object.\n  */\n-public class AbbreviatedObjectId {\n+public final class AbbreviatedObjectId {\n \t/**\n \t * Convert an AbbreviatedObjectId from hex characters (US-ASCII).\n \t * \n@@ -152,7 +152,7 @@ static int mask(final int nibbles, final int word, final int v) {\n \n \tfinal int w5;\n \n-\tprivate AbbreviatedObjectId(final int n, final int new_1, final int new_2,\n+\tAbbreviatedObjectId(final int n, final int new_1, final int new_2,\n \t\t\tfinal int new_3, final int new_4, final int new_5) {\n \t\tnibbles = n;\n \t\tw1 = new_1;\ndiff --git a/org.spearce.jgit/src/org/spearce/jgit/lib/AnyObjectId.java b/org.spearce.jgit/src/org/spearce/jgit/lib/AnyObjectId.java\nindex 8872017..7d7d61b 100644\n--- a/org.spearce.jgit/src/org/spearce/jgit/lib/AnyObjectId.java\n+++ b/org.spearce.jgit/src/org/spearce/jgit/lib/AnyObjectId.java\n@@ -432,16 +432,36 @@ public final String name() {\n \t/**\n \t * Return unique abbreviation (prefix) of this object SHA-1.\n \t * <p>\n+\t * This method is a utility for <code>abbreviate(repo, 8)</code>.\n+\t * \n+\t * @param repo\n+\t *            repository for checking uniqueness within.\n+\t * @return SHA-1 abbreviation.\n+\t */\n+\tpublic AbbreviatedObjectId abbreviate(final Repository repo) {\n+\t\treturn abbreviate(repo, 8);\n+\t}\n+\n+\t/**\n+\t * Return unique abbreviation (prefix) of this object SHA-1.\n+\t * <p>\n \t * Current implementation is not guaranteeing uniqueness, it just returns\n \t * fixed-length prefix of SHA-1 string.\n-\t *\n+\t * \n \t * @param repo\n \t *            repository for checking uniqueness within.\n+\t * @param len\n+\t *            minimum length of the abbreviated string.\n \t * @return SHA-1 abbreviation.\n \t */\n-\tpublic String abbreviate(final Repository repo) {\n+\tpublic AbbreviatedObjectId abbreviate(final Repository repo, final int len) {\n \t\t// TODO implement checking for uniqueness\n-\t\treturn name().substring(0, 7);\n+\t\tfinal int a = AbbreviatedObjectId.mask(len, 1, w1);\n+\t\tfinal int b = AbbreviatedObjectId.mask(len, 2, w2);\n+\t\tfinal int c = AbbreviatedObjectId.mask(len, 3, w3);\n+\t\tfinal int d = AbbreviatedObjectId.mask(len, 4, w4);\n+\t\tfinal int e = AbbreviatedObjectId.mask(len, 5, w5);\n+\t\treturn new AbbreviatedObjectId(len, a, b, c, d, e);\n \t}\n \n \t/**\n-- \n1.6.1.rc2.299.gead4c\n"}]}