Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/mono/libgit2sharp.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authornulltoken <emeric.fermas@gmail.com>2011-06-20 13:49:30 +0400
committernulltoken <emeric.fermas@gmail.com>2011-06-20 22:53:55 +0400
commit87879f34a2939107d0c2df598b675f1d7ad148f7 (patch)
treece17dbc7e55a2bf938eab6e1b9052a423574e8e7
parent0c61d1de2886346134377cc35f4d69bf6c6af121 (diff)
Add handling of abbreviated sha to Repository.Lookup() and ObjectId.ToString()
-rw-r--r--LibGit2Sharp.Tests/ObjectIdFixture.cs61
-rw-r--r--LibGit2Sharp.Tests/RepositoryFixture.cs31
-rw-r--r--LibGit2Sharp/BranchCollection.cs6
-rw-r--r--LibGit2Sharp/Core/NativeMethods.cs9
-rw-r--r--LibGit2Sharp/GitObject.cs2
-rw-r--r--LibGit2Sharp/LibGit2Sharp.csproj1
-rw-r--r--LibGit2Sharp/ObjectId.cs202
-rw-r--r--LibGit2Sharp/ReferenceCollection.cs14
-rw-r--r--LibGit2Sharp/Repository.cs24
-rw-r--r--libgit2sharp/AbbreviatedObjectId.cs22
10 files changed, 303 insertions, 69 deletions
diff --git a/LibGit2Sharp.Tests/ObjectIdFixture.cs b/LibGit2Sharp.Tests/ObjectIdFixture.cs
index 3fa62696..05a107df 100644
--- a/LibGit2Sharp.Tests/ObjectIdFixture.cs
+++ b/LibGit2Sharp.Tests/ObjectIdFixture.cs
@@ -7,11 +7,14 @@ namespace LibGit2Sharp.Tests
[TestFixture]
public class ObjectIdFixture
{
+ private const string validSha1 = "ce08fe4884650f067bd5703b6a59a8b3b3c99a09";
+ private const string validSha2 = "de08fe4884650f067bd5703b6a59a8b3b3c99a09";
+
[TestCase("Dummy", typeof(ArgumentException))]
[TestCase("", typeof(ArgumentException))]
[TestCase("8e", typeof(ArgumentException))]
[TestCase(null, typeof(ArgumentNullException))]
- [TestCase("ce08fe4884650f067bd5703b6a59a8b3b3c99a09dd", typeof(ArgumentException))]
+ [TestCase(validSha1 + "dd", typeof(ArgumentException))]
public void PreventsFromBuildingWithAnInvalidSha(string malformedSha, Type expectedExceptionType)
{
Assert.Throws(expectedExceptionType, () => new ObjectId(malformedSha));
@@ -24,14 +27,15 @@ namespace LibGit2Sharp.Tests
var id = new ObjectId(bytes);
- id.Sha.ShouldEqual("ce08fe4884650f067bd5703b6a59a8b3b3c99a09");
- id.ToString().ShouldEqual("ce08fe4884650f067bd5703b6a59a8b3b3c99a09");
+ id.Sha.ShouldEqual(validSha1);
+ id.ToString().ShouldEqual(validSha1);
}
[Test]
public void CanConvertShaToOid()
{
- var id = new ObjectId("ce08fe4884650f067bd5703b6a59a8b3b3c99a09");
+ var id = new ObjectId(validSha1);
+
id.RawId.ShouldEqual(new byte[] { 206, 8, 254, 72, 132, 101, 15, 6, 123, 213, 112, 59, 106, 89, 168, 179, 179, 201, 154, 9 });
}
@@ -46,10 +50,12 @@ namespace LibGit2Sharp.Tests
[Test]
public void DifferentObjectIdsAreEqual()
{
- var a = new ObjectId("ce08fe4884650f067bd5703b6a59a8b3b3c99a09");
- var b = new ObjectId("de08fe4884650f067bd5703b6a59a8b3b3c99a09");
+ var a = new ObjectId(validSha1);
+ var b = new ObjectId(validSha2);
+
(a.Equals(b)).ShouldBeFalse();
(b.Equals(a)).ShouldBeFalse();
+
(a == b).ShouldBeFalse();
(a != b).ShouldBeTrue();
}
@@ -57,18 +63,21 @@ namespace LibGit2Sharp.Tests
[Test]
public void DifferentObjectIdsDoesNotHaveSameHashCode()
{
- var a = new ObjectId("ce08fe4884650f067bd5703b6a59a8b3b3c99a09");
- var b = new ObjectId("de08fe4884650f067bd5703b6a59a8b3b3c99a09");
+ var a = new ObjectId(validSha1);
+ var b = new ObjectId(validSha2);
+
a.GetHashCode().ShouldNotEqual(b.GetHashCode());
}
[Test]
public void SimilarObjectIdsAreEqual()
{
- var a = new ObjectId("ce08fe4884650f067bd5703b6a59a8b3b3c99a09");
- var b = new ObjectId("ce08fe4884650f067bd5703b6a59a8b3b3c99a09");
+ var a = new ObjectId(validSha1);
+ var b = new ObjectId(validSha1);
+
(a.Equals(b)).ShouldBeTrue();
(b.Equals(a)).ShouldBeTrue();
+
(a == b).ShouldBeTrue();
(a != b).ShouldBeFalse();
}
@@ -76,9 +85,37 @@ namespace LibGit2Sharp.Tests
[Test]
public void SimilarObjectIdsHaveSameHashCode()
{
- var a = new ObjectId("ce08fe4884650f067bd5703b6a59a8b3b3c99a09");
- var b = new ObjectId("ce08fe4884650f067bd5703b6a59a8b3b3c99a09");
+ var a = new ObjectId(validSha1);
+ var b = new ObjectId(validSha1);
+
a.GetHashCode().ShouldEqual(b.GetHashCode());
}
+
+ [TestCase("Dummy", false)]
+ [TestCase(null, false)]
+ [TestCase("", false)]
+ [TestCase("0", false)]
+ [TestCase("01", false)]
+ [TestCase("012", false)]
+ [TestCase("0123", true)]
+ [TestCase("0123456", true)]
+ [TestCase(validSha1 + "d", false)]
+ [TestCase(validSha1, true)]
+ public void TryParse(string maybeSha, bool isValidSha)
+ {
+ ObjectId parsedObjectId;
+ bool result = ObjectId.TryParse(maybeSha, out parsedObjectId);
+ result.ShouldEqual(isValidSha);
+
+ if (!result)
+ {
+ return;
+ }
+
+ parsedObjectId.ShouldNotBeNull();
+ parsedObjectId.Sha.ShouldEqual(maybeSha);
+ maybeSha.StartsWith(parsedObjectId.ToString(3)).ShouldBeTrue();
+ parsedObjectId.ToString(42).ShouldEqual(maybeSha);
+ }
}
} \ No newline at end of file
diff --git a/LibGit2Sharp.Tests/RepositoryFixture.cs b/LibGit2Sharp.Tests/RepositoryFixture.cs
index 937df05a..68d3318a 100644
--- a/LibGit2Sharp.Tests/RepositoryFixture.cs
+++ b/LibGit2Sharp.Tests/RepositoryFixture.cs
@@ -218,6 +218,37 @@ namespace LibGit2Sharp.Tests
}
[Test]
+ public void CanLookupWhithShortIdentifers()
+ {
+ const string expectedAbbrevSha = "edfecad";
+ const string expectedSha = expectedAbbrevSha + "02d96c9dbf64f6e238c45ddcfa762eef0";
+
+ using (var scd = new SelfCleaningDirectory())
+ {
+ var dir = Repository.Init(scd.DirectoryPath);
+
+ using (var repo = new Repository(dir))
+ {
+ string filePath = Path.Combine(repo.Info.WorkingDirectory, "new.txt");
+
+ File.WriteAllText(filePath, "one ");
+ repo.Index.Stage(filePath);
+
+ var author = Constants.Signature;
+ var commit = repo.Commit(author, author, "Initial commit");
+
+ commit.Sha.ShouldEqual(expectedSha);
+
+ var lookedUp1 = repo.Lookup(expectedSha);
+ lookedUp1.ShouldEqual(commit);
+
+ var lookedUp2 = repo.Lookup(expectedAbbrevSha);
+ lookedUp2.ShouldEqual(commit);
+ }
+ }
+ }
+
+ [Test]
public void LookingUpWithBadParamsThrows()
{
using (var repo = new Repository(Constants.BareTestRepoPath))
diff --git a/LibGit2Sharp/BranchCollection.cs b/LibGit2Sharp/BranchCollection.cs
index 833db24d..c02a7c3c 100644
--- a/LibGit2Sharp/BranchCollection.cs
+++ b/LibGit2Sharp/BranchCollection.cs
@@ -79,9 +79,9 @@ namespace LibGit2Sharp
/// <returns></returns>
public Branch Create(string name, string target)
{
- ObjectId id = ObjectId.CreateFromMaybeSha(target);
-
- if (id == null)
+ ObjectId id;
+
+ if (!ObjectId.TryParse(target, out id))
{
var reference = repo.Refs[NormalizeToCanonicalName(target)].ResolveToDirectReference();
target = reference.TargetIdentifier;
diff --git a/LibGit2Sharp/Core/NativeMethods.cs b/LibGit2Sharp/Core/NativeMethods.cs
index b48d37a3..a756d608 100644
--- a/LibGit2Sharp/Core/NativeMethods.cs
+++ b/LibGit2Sharp/Core/NativeMethods.cs
@@ -78,6 +78,9 @@ namespace LibGit2Sharp.Core
public static extern int git_object_lookup(out IntPtr obj, RepositorySafeHandle repo, ref GitOid id, GitObjectType type);
[DllImport(libgit2)]
+ public static extern int git_object_lookup_prefix(out IntPtr obj, RepositorySafeHandle repo, ref GitOid id, uint len, GitObjectType type);
+
+ [DllImport(libgit2)]
public static extern GitObjectType git_object_type(IntPtr obj);
[DllImport(libgit2)]
@@ -91,12 +94,6 @@ namespace LibGit2Sharp.Core
public static extern int git_oid_cmp(ref GitOid a, ref GitOid b);
[DllImport(libgit2)]
- public static extern void git_oid_fmt(byte[] str, ref GitOid oid);
-
- [DllImport(libgit2)]
- public static extern int git_oid_fromstr(out GitOid oid, string str);
-
- [DllImport(libgit2)]
public static extern int git_reference_create_oid(out IntPtr reference, RepositorySafeHandle repo, string name, ref GitOid oid);
[DllImport(libgit2)]
diff --git a/LibGit2Sharp/GitObject.cs b/LibGit2Sharp/GitObject.cs
index c0714380..2ed16916 100644
--- a/LibGit2Sharp/GitObject.cs
+++ b/LibGit2Sharp/GitObject.cs
@@ -60,7 +60,7 @@ namespace LibGit2Sharp
case GitObjectType.Blob:
return Blob.BuildFromPtr(obj, id, repo);
default:
- return new GitObject(id);
+ throw new InvalidOperationException(string.Format("Unexpected type '{0}' for object '{1}'.", type, id));
}
}
finally
diff --git a/LibGit2Sharp/LibGit2Sharp.csproj b/LibGit2Sharp/LibGit2Sharp.csproj
index 43ac7496..dedb29d5 100644
--- a/LibGit2Sharp/LibGit2Sharp.csproj
+++ b/LibGit2Sharp/LibGit2Sharp.csproj
@@ -44,6 +44,7 @@
<Reference Include="System.Core" />
</ItemGroup>
<ItemGroup>
+ <Compile Include="AbbreviatedObjectId.cs" />
<Compile Include="Blob.cs" />
<Compile Include="Branch.cs" />
<Compile Include="BranchCollection.cs" />
diff --git a/LibGit2Sharp/ObjectId.cs b/LibGit2Sharp/ObjectId.cs
index c26d8bbf..af6fd8c6 100644
--- a/LibGit2Sharp/ObjectId.cs
+++ b/LibGit2Sharp/ObjectId.cs
@@ -1,6 +1,5 @@
using System;
-using System.Globalization;
-using System.Text;
+using System.Linq;
using LibGit2Sharp.Core;
namespace LibGit2Sharp
@@ -12,7 +11,14 @@ namespace LibGit2Sharp
{
private readonly GitOid oid;
private const int rawSize = 20;
- private const int hexSize = rawSize * 2;
+ private readonly string sha;
+
+ protected const int HexSize = rawSize * 2;
+ protected const int MinHexSize = 4;
+
+ private const string hexDigits = "0123456789abcdef";
+ private static readonly byte[] reverseHexDigits = BuildReverseHexDigits();
+ private static readonly Func<int, byte> byteConverter = i => reverseHexDigits[i - '0'];
private static readonly LambdaEqualityHelper<ObjectId> equalityHelper =
new LambdaEqualityHelper<ObjectId>(new Func<ObjectId, object>[] { x => x.Sha });
@@ -24,7 +30,7 @@ namespace LibGit2Sharp
internal ObjectId(GitOid oid)
{
this.oid = oid;
- Sha = Stringify(this.oid);
+ sha = ToString(oid.Id);
}
/// <summary>
@@ -44,8 +50,15 @@ namespace LibGit2Sharp
/// <param name="sha">The sha.</param>
public ObjectId(string sha)
{
- oid = CreateFromSha(sha, true).GetValueOrDefault();
- Sha = sha;
+ GitOid? parsedOid = BuildOidFrom(sha, true, false);
+
+ if (!parsedOid.HasValue)
+ {
+ throw new ArgumentException(string.Format("'{0}' is not a valid Sha-1.", sha));
+ }
+
+ oid = parsedOid.Value;
+ this.sha = sha;
}
internal GitOid Oid
@@ -64,51 +77,48 @@ namespace LibGit2Sharp
/// <summary>
/// Gets the sha.
/// </summary>
- public string Sha { get; private set; }
+ public virtual string Sha { get { return sha; } }
- internal static ObjectId CreateFromMaybeSha(string sha)
+ /// <summary>
+ /// Converts the specified string representation of a Sha-1 to its <see cref="ObjectId"/> equivalent and returns a value that indicates whether the conversion succeeded.
+ /// </summary>
+ /// <param name="sha">A string containing a Sha-1 to convert. </param>
+ /// <param name="result">When this method returns, contains the <see cref="ObjectId"/> value equivalent to the Sha-1 contained in <paramref name="sha"/>, if the conversion succeeded, or <code>null</code> if the conversion failed.</param>
+ /// <returns>true if the <paramref name="sha"/> parameter was converted successfully; otherwise, false.</returns>
+ public static bool TryParse(string sha, out ObjectId result)
{
- GitOid? oid = CreateFromSha(sha, false);
+ return TryParseInternal(sha, true, out result);
+ }
- if (!oid.HasValue)
- {
- return null;
- }
+ internal static bool TryParseInternal(string sha, bool allowShortIdentifier, out ObjectId result)
+ {
+ result = BuildFrom(sha, false, allowShortIdentifier);
- return new ObjectId(oid.Value);
+ return (result == null) ? false : true;
}
- private static GitOid? CreateFromSha(string sha, bool shouldThrow)
+ private static GitOid? BuildOidFrom(string sha, bool shouldThrowIfInvalid, bool allowShortIdentifier)
{
- Ensure.ArgumentNotNullOrEmptyString(sha, "sha");
-
- if (sha.Length != hexSize)
+ if (!LooksValid(sha, shouldThrowIfInvalid, allowShortIdentifier))
{
- if (!shouldThrow)
- {
- return null;
- }
-
- throw new ArgumentException(string.Format(CultureInfo.InvariantCulture, "'{0}' is not a valid sha. Expected length should equal {1}.", sha, hexSize));
+ return null;
}
- GitOid oid;
- var result = NativeMethods.git_oid_fromstr(out oid, sha);
+ return ToOid(sha);
+ }
- if (!shouldThrow && result != (int)GitErrorCode.GIT_SUCCESS)
+ private static ObjectId BuildFrom(string sha, bool shouldThrowIfInvalid, bool allowShortIdentifier)
+ {
+ GitOid? oid = BuildOidFrom(sha, shouldThrowIfInvalid, allowShortIdentifier);
+
+ if (!oid.HasValue)
{
return null;
}
- Ensure.Success(result);
- return oid;
- }
+ ObjectId objectId = sha.Length == HexSize ? new ObjectId(oid.Value) : new AbbreviatedObjectId(oid.Value, sha.Length);
- private static string Stringify(GitOid oid)
- {
- var hex = new byte[hexSize];
- NativeMethods.git_oid_fmt(hex, ref oid);
- return Encoding.ASCII.GetString(hex);
+ return objectId;
}
/// <summary>
@@ -150,6 +160,32 @@ namespace LibGit2Sharp
}
/// <summary>
+ /// Returns the <see cref="Sha"/>, a <see cref="String"/> representation of the current <see cref="ObjectId"/>.
+ /// </summary>
+ /// <param name="prefixLength">The number of chars the <see cref="Sha"/> should be truncated to.</param>
+ /// <returns>The <see cref="Sha"/> that represents the current <see cref="ObjectId"/>.</returns>
+ public string ToString(int prefixLength)
+ {
+ int normalizedLength = NormalizeLength(prefixLength);
+ return Sha.Substring(0, Math.Min(Sha.Length, normalizedLength));
+ }
+
+ private static int NormalizeLength(int prefixLength)
+ {
+ if (prefixLength < MinHexSize)
+ {
+ return MinHexSize;
+ }
+
+ if (prefixLength > HexSize)
+ {
+ return HexSize;
+ }
+
+ return prefixLength;
+ }
+
+ /// <summary>
/// Tests if two <see cref="ObjectId"/> are equal.
/// </summary>
/// <param name="left">First <see cref="ObjectId"/> to compare.</param>
@@ -170,5 +206,99 @@ namespace LibGit2Sharp
{
return !Equals(left, right);
}
+
+ private static byte[] BuildReverseHexDigits()
+ {
+ var bytes = new byte['f' - '0' + 1];
+
+ for (int i = 0; i < 10; i++)
+ {
+ bytes[i] = (byte)i;
+ }
+
+ for (int i = 10; i < 16; i++)
+ {
+ bytes[i + 'a' - '0' - 0x0a] = (byte)(i);
+ }
+
+ return bytes;
+ }
+
+ private static string ToString(byte[] id)
+ {
+ if (id == null || id.Length != rawSize)
+ {
+ throw new ArgumentException("id");
+ }
+
+ // Inspired from http://stackoverflow.com/questions/623104/c-byte-to-hex-string/3974535#3974535
+
+ var c = new char[HexSize];
+
+ for (int i = 0; i < HexSize; i++)
+ {
+ int index0 = i >> 1;
+ var b = ((byte)(id[index0] >> 4));
+ c[i++] = hexDigits[b];
+
+ b = ((byte)(id[index0] & 0x0F));
+ c[i] = hexDigits[b];
+ }
+
+ return new string(c);
+ }
+
+ private static GitOid ToOid(string sha)
+ {
+ var bytes = new byte[rawSize];
+
+ if ((sha.Length & 1) == 1)
+ {
+ sha += "0";
+ }
+
+ for (int i = 0; i < sha.Length; i++)
+ {
+ int c1 = byteConverter(sha[i++]) << 4;
+ int c2 = byteConverter(sha[i]);
+
+ bytes[i >> 1] = (byte)(c1 + c2);
+ }
+
+ var oid = new GitOid{Id = bytes};
+ return oid;
+ }
+
+ private static bool LooksValid(string objectId, bool throwIfInvalid, bool allowShortIdentifier)
+ {
+ if (objectId == null)
+ {
+ if (!throwIfInvalid)
+ {
+ return false;
+ }
+
+ throw new ArgumentNullException(objectId);
+ }
+
+ if (objectId.Length < MinHexSize || objectId.Length > HexSize)
+ {
+ if (!throwIfInvalid)
+ {
+ return false;
+ }
+
+ string additionalErrorInformation =
+ !allowShortIdentifier ?
+ string.Format("Its length should be {0}", HexSize) :
+ string.Format("Its length should be comprised between {0} and {1}", MinHexSize, HexSize);
+
+ throw new ArgumentException(
+ string.Format("'{0}' is not a valid object identifier. {1}.", objectId, additionalErrorInformation),
+ "objectId");
+ }
+
+ return objectId.All(c => hexDigits.Contains(c.ToString()));
+ }
}
-} \ No newline at end of file
+}
diff --git a/LibGit2Sharp/ReferenceCollection.cs b/LibGit2Sharp/ReferenceCollection.cs
index 0fadbc48..6207ce37 100644
--- a/LibGit2Sharp/ReferenceCollection.cs
+++ b/LibGit2Sharp/ReferenceCollection.cs
@@ -68,13 +68,14 @@ namespace LibGit2Sharp
public Reference Create(string name, string target, bool allowOverwrite = false)
{
Ensure.ArgumentNotNullOrEmptyString(name, "name");
+ Ensure.ArgumentNotNullOrEmptyString(target, "target");
- ObjectId id = ObjectId.CreateFromMaybeSha(target);
-
+ ObjectId id;
+
IntPtr reference;
int res;
- if (id != null)
+ if (ObjectId.TryParse(target, out id))
{
res = CreateDirectReference(name, id, allowOverwrite, out reference);
}
@@ -175,17 +176,18 @@ namespace LibGit2Sharp
IntPtr reference = RetrieveReferencePtr(name);
int res;
- var id = ObjectId.CreateFromMaybeSha(target);
+ ObjectId id;
+ bool isObjectIdentifier = ObjectId.TryParse(target, out id);
var type = NativeMethods.git_reference_type(reference);
switch (type)
{
case GitReferenceType.Oid:
- if (id == null) throw new ArgumentException(String.Format(CultureInfo.InvariantCulture, "The reference specified by {0} is an Oid reference, you must provide a sha as the target.", name), "target");
+ if (!isObjectIdentifier) throw new ArgumentException(String.Format(CultureInfo.InvariantCulture, "The reference specified by {0} is an Oid reference, you must provide a sha as the target.", name), "target");
var oid = id.Oid;
res = NativeMethods.git_reference_set_oid(reference, ref oid);
break;
case GitReferenceType.Symbolic:
- if (id != null) throw new ArgumentException(String.Format(CultureInfo.InvariantCulture, "The reference specified by {0} is an Symbolic reference, you must provide a symbol as the target.", name), "target");
+ if (isObjectIdentifier) throw new ArgumentException(String.Format(CultureInfo.InvariantCulture, "The reference specified by {0} is an Symbolic reference, you must provide a symbol as the target.", name), "target");
res = NativeMethods.git_reference_set_target(reference, target);
break;
default:
diff --git a/LibGit2Sharp/Repository.cs b/LibGit2Sharp/Repository.cs
index bc3a4bf1..ef80c7f7 100644
--- a/LibGit2Sharp/Repository.cs
+++ b/LibGit2Sharp/Repository.cs
@@ -156,8 +156,6 @@ namespace LibGit2Sharp
/// <returns></returns>
public bool HasObject(string sha) //TODO: To be removed from front facing API (maybe should we create an Repository.Advanced to hold those kind of functions)?
{
- Ensure.ArgumentNotNullOrEmptyString(sha, "sha");
-
var id = new ObjectId(sha);
var odb = NativeMethods.git_repository_database(handle);
@@ -197,7 +195,17 @@ namespace LibGit2Sharp
var oid = id.Oid;
IntPtr obj;
- var res = NativeMethods.git_object_lookup(out obj, handle, ref oid, type);
+ int res;
+
+ if (id is AbbreviatedObjectId)
+ {
+ res = NativeMethods.git_object_lookup_prefix(out obj, handle, ref oid, (uint)((AbbreviatedObjectId)id).Length, type);
+ }
+ else
+ {
+ res = NativeMethods.git_object_lookup(out obj, handle, ref oid, type);
+ }
+
if (res == (int)GitErrorCode.GIT_ENOTFOUND || res == (int)GitErrorCode.GIT_EINVALIDTYPE)
{
return null;
@@ -205,6 +213,11 @@ namespace LibGit2Sharp
Ensure.Success(res);
+ if (id is AbbreviatedObjectId)
+ {
+ id = GitObject.ObjectIdOf(obj);
+ }
+
return GitObject.CreateFromPtr(obj, id, this);
}
@@ -216,8 +229,9 @@ namespace LibGit2Sharp
/// <returns>The <see cref = "GitObject" /> or null if it was not found.</returns>
public GitObject Lookup(string shaOrReferenceName, GitObjectType type = GitObjectType.Any)
{
- ObjectId id = ObjectId.CreateFromMaybeSha(shaOrReferenceName);
- if (id != null)
+ ObjectId id;
+
+ if (ObjectId.TryParse(shaOrReferenceName, out id))
{
return Lookup(id, type);
}
diff --git a/libgit2sharp/AbbreviatedObjectId.cs b/libgit2sharp/AbbreviatedObjectId.cs
new file mode 100644
index 00000000..cda12616
--- /dev/null
+++ b/libgit2sharp/AbbreviatedObjectId.cs
@@ -0,0 +1,22 @@
+using System;
+using LibGit2Sharp.Core;
+
+namespace LibGit2Sharp
+{
+ internal class AbbreviatedObjectId : ObjectId
+ {
+ internal AbbreviatedObjectId(GitOid oid, int length) : base(oid)
+ {
+ if (length < MinHexSize || length > HexSize)
+ {
+ throw new ArgumentException(string.Format("Expected length should be comprised between {0} and {1}.", MinHexSize, HexSize), "length");
+ }
+
+ Length = length;
+ }
+
+ public int Length { get; private set; }
+
+ public override string Sha { get { return base.Sha.Substring(0, Length); } }
+ }
+} \ No newline at end of file