using System; using System.Globalization; using LibGit2Sharp.Core; using LibGit2Sharp.Core.Compat; namespace LibGit2Sharp { /// /// A Reference to another git object /// public abstract class Reference : IEquatable { private static readonly LambdaEqualityHelper equalityHelper = new LambdaEqualityHelper(new Func[] { x => x.CanonicalName, x => x.TargetIdentifier }); /// /// Gets the full name of this reference. /// public string CanonicalName { get; protected set; } internal static T BuildFromPtrAndRelease(IntPtr ptr, Repository repo) where T : Reference { var reference = BuildFromPtr(ptr, repo); NativeMethods.git_reference_free(ptr); return reference; } private static T BuildFromPtr(IntPtr ptr, Repository repo) where T : Reference { if (ptr == IntPtr.Zero) { return default(T); } string name = NativeMethods.git_reference_name(ptr); GitReferenceType type = NativeMethods.git_reference_type(ptr); Reference reference; switch (type) { case GitReferenceType.Symbolic: IntPtr resolveRef; var targetIdentifier = NativeMethods.git_reference_target(ptr); int res = NativeMethods.git_reference_resolve(out resolveRef, ptr); if (res == (int)GitErrorCode.GIT_ENOTFOUND) { reference = new SymbolicReference { CanonicalName = name, Target = null, TargetIdentifier = targetIdentifier }; break; } Ensure.Success(res); var targetRef = BuildFromPtrAndRelease(resolveRef, repo); reference = new SymbolicReference { CanonicalName = name, Target = targetRef, TargetIdentifier = targetIdentifier }; break; case GitReferenceType.Oid: IntPtr oidPtr = NativeMethods.git_reference_oid(ptr); var targetOid = new ObjectId(oidPtr.MarshalAsOid()); var targetBuilder = new Lazy(() => repo.Lookup(targetOid)); reference = new DirectReference(targetBuilder) { CanonicalName = name, TargetIdentifier = targetOid.Sha }; break; default: throw new LibGit2Exception(String.Format(CultureInfo.InvariantCulture, "Unable to build a new reference from a type '{0}'.", Enum.GetName(typeof(GitReferenceType), type))); } return reference as T; } /// /// Recursively peels the target of the reference until a direct reference is encountered. /// /// The this points to. public abstract DirectReference ResolveToDirectReference(); /// /// Gets the target declared by the reference. /// /// If this reference is a , returns the canonical name of the target. /// Otherwise, if this reference is a , returns the sha of the target. /// /// // TODO: Maybe find a better name for this property. public string TargetIdentifier { get; private set; } /// /// Determines whether the specified is equal to the current . /// /// The to compare with the current . /// True if the specified is equal to the current ; otherwise, false. public override bool Equals(object obj) { return Equals(obj as Reference); } /// /// Determines whether the specified is equal to the current . /// /// The to compare with the current . /// True if the specified is equal to the current ; otherwise, false. public bool Equals(Reference other) { return equalityHelper.Equals(this, other); } /// /// Returns the hash code for this instance. /// /// A 32-bit signed integer hash code. public override int GetHashCode() { return equalityHelper.GetHashCode(this); } /// /// Tests if two are equal. /// /// First to compare. /// Second to compare. /// True if the two objects are equal; false otherwise. public static bool operator ==(Reference left, Reference right) { return Equals(left, right); } /// /// Tests if two are different. /// /// First to compare. /// Second to compare. /// True if the two objects are different; false otherwise. public static bool operator !=(Reference left, Reference right) { return !Equals(left, right); } /// /// Returns the , a representation of the current . /// /// The that represents the current . public override string ToString() { return CanonicalName; } } }