diff --git a/.gitignore b/.gitignore index 164c6cf73..ab4b90674 100644 --- a/.gitignore +++ b/.gitignore @@ -26,9 +26,10 @@ Thumbs.db obj/ [Rr]elease*/ _ReSharper*/ +*.ReSharper +*.ReSharper.user [Tt]est[Rr]esult* build/ *.pidb *.userprefs -*.swp -%temp% \ No newline at end of file +*.swp \ No newline at end of file diff --git a/LibGit2Sharp.Tests/BranchFixture.cs b/LibGit2Sharp.Tests/BranchFixture.cs index 9f35369b2..35f2afddd 100644 --- a/LibGit2Sharp.Tests/BranchFixture.cs +++ b/LibGit2Sharp.Tests/BranchFixture.cs @@ -11,6 +11,22 @@ public class BranchFixture { private readonly List expectedBranches = new List {"packed-test", "packed", "br2", "master", "test"}; + [Test] + public void CanCheckoutAnExistingBranch() + { + using (var path = new TemporaryCloneOfTestRepo()) + using (var repo = new Repository(path.RepositoryPath)) + { + var master = repo.Branches["master"]; + master.IsCurrentRepositoryHead.ShouldBeTrue(); + + var test = repo.Branches.Checkout("test"); + + test.IsCurrentRepositoryHead.ShouldBeTrue(); + master.IsCurrentRepositoryHead.ShouldBeFalse(); + } + } + [Test] public void CanCreateBranch() { @@ -26,7 +42,7 @@ public void CanCreateBranch() newBranch.Tip.Sha.ShouldEqual("be3563ae3f795b2b4353bcce3a527ad0a4f7f644"); repo.Branches.SingleOrDefault(p => p.Name == name).ShouldNotBeNull(); - repo.Refs.Delete(newBranch.CanonicalName); //TODO: To be replaced with repo.Branches.Delete(newBranch.Name) + repo.Refs.Delete(newBranch.CanonicalName); //TODO: To be replaced with repo.Branches.Delete(newBranch.Name) } } @@ -41,11 +57,12 @@ public void CanCreateBranchFromAnotherBranch() newBranch.ShouldNotBeNull(); newBranch.Name.ShouldEqual(name); newBranch.CanonicalName.ShouldEqual("refs/heads/" + name); + newBranch.IsCurrentRepositoryHead.ShouldBeFalse(); newBranch.Tip.ShouldNotBeNull(); newBranch.Tip.Sha.ShouldEqual("4c062a6361ae6959e06292c1fa5e2822d9c96345"); repo.Branches.SingleOrDefault(p => p.Name == name).ShouldNotBeNull(); - repo.Refs.Delete(newBranch.CanonicalName); //TODO: To be replaced with repo.Branches.Delete(newBranch.Name) + repo.Refs.Delete(newBranch.CanonicalName); //TODO: To be replaced with repo.Branches.Delete(newBranch.Name) } } @@ -63,20 +80,6 @@ public void CanListAllBranches() } } - [Test] - public void CanLookupLocalBranch() - { - using (var repo = new Repository(Constants.TestRepoPath)) - { - var master = repo.Branches["master"]; - master.ShouldNotBeNull(); - master.IsRemote.ShouldBeFalse(); - master.Name.ShouldEqual("master"); - master.CanonicalName.ShouldEqual("refs/heads/master"); - master.Tip.Sha.ShouldEqual("4c062a6361ae6959e06292c1fa5e2822d9c96345"); - } - } - [Test] public void CanLookupABranchByItsCanonicalName() { @@ -95,6 +98,21 @@ public void CanLookupABranchByItsCanonicalName() } } + [Test] + public void CanLookupLocalBranch() + { + using (var repo = new Repository(Constants.TestRepoPath)) + { + var master = repo.Branches["master"]; + master.ShouldNotBeNull(); + master.IsRemote.ShouldBeFalse(); + master.Name.ShouldEqual("master"); + master.CanonicalName.ShouldEqual("refs/heads/master"); + master.IsCurrentRepositoryHead.ShouldBeTrue(); + master.Tip.Sha.ShouldEqual("4c062a6361ae6959e06292c1fa5e2822d9c96345"); + } + } + [Test] public void CanWalkCommitsFromAnotherBranch() { @@ -115,6 +133,17 @@ public void CanWalkCommitsFromBranch() } } + [Test] + public void CheckoutBranchWithBadParamsThrows() + { + using (var path = new TemporaryCloneOfTestRepo()) + using (var repo = new Repository(path.RepositoryPath)) + { + Assert.Throws(() => repo.Branches.Checkout(string.Empty)); + Assert.Throws(() => repo.Branches.Checkout(null)); + } + } + [Test] public void CreatingBranchWithEmptyNameThrows() { @@ -151,5 +180,47 @@ public void CreatingBranchWithNullTargetThrows() Assert.Throws(() => repo.Branches.Create("bad_branch", (ObjectId) null)); } } + + [Test] + public void OnlyOneBranchIsTheHead() + { + using (var repo = new Repository(Constants.TestRepoPath)) + { + Branch head = null; + + foreach (var branch in repo.Branches) + { + bool isHead = branch.IsCurrentRepositoryHead; + + if (!isHead) + { + continue; + } + + if (head == null) + { + head = branch; + continue; + } + + Assert.Fail("Both '{0}' and '{1}' appear to be Head.", head.CanonicalName, branch.CanonicalName); + } + + head.ShouldNotBeNull(); + } + } + + [Test] + public void TwoBranchesPointingAtTheSameCommitAreNotBothCurrent() + { + using (var path = new TemporaryCloneOfTestRepo()) + using (var repo = new Repository(path.RepositoryPath)) + { + var master = repo.Branches["refs/heads/master"]; + + var newBranch = repo.Branches.Create("clone-of-master", master.Tip.Sha); + newBranch.IsCurrentRepositoryHead.ShouldBeFalse(); + } + } } } \ No newline at end of file diff --git a/LibGit2Sharp.Tests/ReferenceFixture.cs b/LibGit2Sharp.Tests/ReferenceFixture.cs index 2486df74a..82889f484 100644 --- a/LibGit2Sharp.Tests/ReferenceFixture.cs +++ b/LibGit2Sharp.Tests/ReferenceFixture.cs @@ -9,7 +9,7 @@ namespace LibGit2Sharp.Tests [TestFixture] public class ReferenceFixture { - private readonly List expectedRefs = new List { "refs/heads/packed-test", "refs/heads/packed", "refs/heads/br2", "refs/heads/master", "refs/heads/test", "refs/tags/test", "refs/tags/e90810b", "refs/tags/lw" }; + private readonly List expectedRefs = new List {"refs/heads/packed-test", "refs/heads/packed", "refs/heads/br2", "refs/heads/master", "refs/heads/test", "refs/tags/test", "refs/tags/e90810b", "refs/tags/lw"}; [Test] public void CanCreateReferenceFromSha() @@ -40,32 +40,13 @@ public void CanCreateReferenceFromSymbol() newRef.ShouldNotBeNull(); newRef.CanonicalName.ShouldEqual(name); newRef.Target.ShouldNotBeNull(); - ((DirectReference)newRef.Target).Target.Sha.ShouldEqual("4c062a6361ae6959e06292c1fa5e2822d9c96345"); + ((DirectReference) newRef.Target).Target.Sha.ShouldEqual("4c062a6361ae6959e06292c1fa5e2822d9c96345"); repo.Refs.SingleOrDefault(p => p.CanonicalName == name).ShouldNotBeNull(); repo.Refs.Delete(newRef.CanonicalName); } } - [Test] - public void DeleteWithNullNameThrows() - { - using (var repo = new Repository(Constants.TestRepoPath)) - { - Assert.Throws(() => repo.Refs.Delete(null)); - } - } - - [Test] - public void DeleteWithEmptyNameThrows() - { - using (var repo = new Repository(Constants.TestRepoPath)) - { - Assert.Throws(() => repo.Refs.Delete(string.Empty)); - } - } - - [Test] public void CanListAllReferences() { @@ -90,7 +71,7 @@ public void CanResolveHeadByName() head.CanonicalName.ShouldEqual("HEAD"); head.Target.ShouldNotBeNull(); head.Target.CanonicalName.ShouldEqual("refs/heads/master"); - ((DirectReference)head.Target).Target.Sha.ShouldEqual("4c062a6361ae6959e06292c1fa5e2822d9c96345"); + ((DirectReference) head.Target).Target.Sha.ShouldEqual("4c062a6361ae6959e06292c1fa5e2822d9c96345"); Assert.IsInstanceOf(((DirectReference) head.Target).Target); var head2 = (SymbolicReference) repo.Refs.Head; @@ -103,30 +84,30 @@ public void CanResolveHeadByName() } [Test] - public void CanResolveReferenceToAnAnnotatedTag() + public void CanResolveReferenceToALightweightTag() { using (var repo = new Repository(Constants.TestRepoPath)) { - var annTag = (DirectReference)repo.Refs["refs/tags/test"]; - annTag.ShouldNotBeNull(); - annTag.CanonicalName.ShouldEqual("refs/tags/test"); - annTag.Target.ShouldNotBeNull(); - annTag.Target.Sha.ShouldEqual("b25fa35b38051e4ae45d4222e795f9df2e43f1d1"); - Assert.IsInstanceOf(annTag.Target); + var lwTag = (DirectReference) repo.Refs["refs/tags/lw"]; + lwTag.ShouldNotBeNull(); + lwTag.CanonicalName.ShouldEqual("refs/tags/lw"); + lwTag.Target.ShouldNotBeNull(); + lwTag.Target.Sha.ShouldEqual("e90810b8df3e80c413d903f631643c716887138d"); + Assert.IsInstanceOf(lwTag.Target); } } [Test] - public void CanResolveReferenceToALightweightTag() + public void CanResolveReferenceToAnAnnotatedTag() { using (var repo = new Repository(Constants.TestRepoPath)) { - var lwTag = (DirectReference)repo.Refs["refs/tags/lw"]; - lwTag.ShouldNotBeNull(); - lwTag.CanonicalName.ShouldEqual("refs/tags/lw"); - lwTag.Target.ShouldNotBeNull(); - lwTag.Target.Sha.ShouldEqual("e90810b8df3e80c413d903f631643c716887138d"); - Assert.IsInstanceOf(lwTag.Target); + var annTag = (DirectReference) repo.Refs["refs/tags/test"]; + annTag.ShouldNotBeNull(); + annTag.CanonicalName.ShouldEqual("refs/tags/test"); + annTag.Target.ShouldNotBeNull(); + annTag.Target.Sha.ShouldEqual("b25fa35b38051e4ae45d4222e795f9df2e43f1d1"); + Assert.IsInstanceOf(annTag.Target); } } @@ -144,6 +125,43 @@ public void CanResolveRefsByName() } } + [Test] + public void CanUpdateTargetOnReference() + { + const string masterRef = "refs/heads/master"; + using (var path = new TemporaryCloneOfTestRepo()) + using (var repo = new Repository(path.RepositoryPath)) + { + var sha = repo.Refs["refs/heads/test"].ResolveToDirectReference().Target.Sha; + var master = repo.Refs[masterRef]; + master.ResolveToDirectReference().Target.Sha.ShouldNotEqual(sha); + + repo.Refs.UpdateTarget(masterRef, sha); + + master = repo.Refs[masterRef]; + master.ResolveToDirectReference().Target.Sha.ShouldEqual(sha); + } + } + + [Test] + public void CanUpdateTargetOnSymolicReference() + { + const string name = "refs/heads/unit_test"; + using (var path = new TemporaryCloneOfTestRepo()) + using (var repo = new Repository(path.RepositoryPath)) + { + var newRef = (SymbolicReference) repo.Refs.Create(name, "refs/heads/master"); + newRef.ShouldNotBeNull(); + + repo.Refs.UpdateTarget(newRef.CanonicalName, "refs/heads/test"); + + newRef = (SymbolicReference) repo.Refs[newRef.CanonicalName]; + newRef.ResolveToDirectReference().Target.ShouldEqual(repo.Refs["refs/heads/test"].ResolveToDirectReference().Target); + + repo.Refs.Delete(newRef.CanonicalName); + } + } + [Test] public void CreateWithEmptyStringForTargetThrows() { @@ -170,7 +188,7 @@ public void CreateWithNullForTargetThrows() using (var path = new TemporaryCloneOfTestRepo()) using (var repo = new Repository(path.RepositoryPath)) { - Assert.Throws(() => repo.Refs.Create("refs/heads/newref", (string)null)); + Assert.Throws(() => repo.Refs.Create("refs/heads/newref", (string) null)); } } @@ -184,6 +202,24 @@ public void CreateWithNullStringThrows() } } + [Test] + public void DeleteWithEmptyNameThrows() + { + using (var repo = new Repository(Constants.TestRepoPath)) + { + Assert.Throws(() => repo.Refs.Delete(string.Empty)); + } + } + + [Test] + public void DeleteWithNullNameThrows() + { + using (var repo = new Repository(Constants.TestRepoPath)) + { + Assert.Throws(() => repo.Refs.Delete(null)); + } + } + [Test] public void ResolvingWithEmptyStringThrows() { @@ -201,5 +237,46 @@ public void ResolvingWithNullThrows() Assert.Throws(() => { var head = repo.Refs[null]; }); } } + + [Test] + public void TryingToUpdateADirectRefWithSymbolFails() + { + const string name = "refs/heads/unit_test"; + using (var path = new TemporaryCloneOfTestRepo()) + using (var repo = new Repository(path.RepositoryPath)) + { + var newRef = (SymbolicReference) repo.Refs.Create(name, "refs/heads/master"); + newRef.ShouldNotBeNull(); + + Assert.Throws( + () => repo.Refs.UpdateTarget(newRef.CanonicalName, repo.Refs["refs/heads/test"].ResolveToDirectReference().Target.Sha)); + + repo.Refs.Delete(newRef.CanonicalName); + } + } + + [Test] + public void TryingToUpdateASymbolicRefWithOidFails() + { + const string masterRef = "refs/heads/master"; + using (var path = new TemporaryCloneOfTestRepo()) + using (var repo = new Repository(path.RepositoryPath)) + { + Assert.Throws(() => repo.Refs.UpdateTarget(masterRef, "refs/heads/test")); + } + } + + [Test] + public void UpdateReferenceTargetWithBadParametersFails() + { + using (var path = new TemporaryCloneOfTestRepo()) + using (var repo = new Repository(path.RepositoryPath)) + { + Assert.Throws(() => repo.Refs.UpdateTarget(string.Empty, "refs/heads/packed")); + Assert.Throws(() => repo.Refs.UpdateTarget("master", string.Empty)); + Assert.Throws(() => repo.Refs.UpdateTarget(null, "refs/heads/packed")); + Assert.Throws(() => repo.Refs.UpdateTarget("master", null)); + } + } } } \ No newline at end of file diff --git a/LibGit2Sharp/Branch.cs b/LibGit2Sharp/Branch.cs index d1c477652..4ad4839b4 100644 --- a/LibGit2Sharp/Branch.cs +++ b/LibGit2Sharp/Branch.cs @@ -8,17 +8,17 @@ namespace LibGit2Sharp /// public class Branch : IEquatable { - private readonly Repository repo; - private static readonly LambdaEqualityHelper equalityHelper = - new LambdaEqualityHelper(new Func[] { x => x.CanonicalName, x => x.Tip }); + new LambdaEqualityHelper(new Func[] {x => x.CanonicalName, x => x.Tip}); + + private readonly Repository repo; /// /// Initializes a new instance of the class. /// - /// The commit which is pointed at by this Branch + /// The commit which is pointed at by this Branch /// The repo. - /// The full name of the reference + /// The full name of the reference internal Branch(string canonicalName, Commit tip, Repository repo) { this.repo = repo; @@ -34,25 +34,31 @@ internal Branch(string canonicalName, Commit tip, Repository repo) /// /// Gets the name of this branch. /// - public string Name { get { return ShortenName(CanonicalName); } } + public string Name + { + get { return ShortenName(CanonicalName); } + } /// - /// Gets a value indicating whether this instance is a remote. + /// Gets a value indicating whether this instance is a remote. /// /// /// true if this instance is remote; otherwise, false. /// - public bool IsRemote { get { return IsRemoteBranch(CanonicalName); } } + public bool IsRemote + { + get { return IsRemoteBranch(CanonicalName); } + } /// - /// Gets a value indicating whether this instance is current branch (HEAD) in the repository. + /// Gets a value indicating whether this instance is current branch (HEAD) in the repository. /// /// - /// true if this instance is current branch; otherwise, false. + /// true if this instance is current branch; otherwise, false. /// - public bool IsCurrentBranch + public bool IsCurrentRepositoryHead { - get { return CanonicalName == repo.Refs.Head.ResolveToDirectReference().CanonicalName; } + get { return repo.Refs[CanonicalName] == repo.Refs.Head.ResolveToDirectReference(); } } /// @@ -68,6 +74,39 @@ public CommitCollection Commits get { return repo.Commits.StartingAt(this); } } + #region IEquatable Members + + /// + /// 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(Branch other) + { + return equalityHelper.Equals(this, other); + } + + #endregion + + /// + /// 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 Branch); + } + + /// + /// Returns the hash code for this instance. + /// + /// A 32-bit signed integer hash code. + public override int GetHashCode() + { + return equalityHelper.GetHashCode(this); + } + private static bool IsRemoteBranch(string canonicalName) { return canonicalName.StartsWith("refs/remotes/"); @@ -89,39 +128,10 @@ private static string ShortenName(string branchName) } /// - /// 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 Branch); - } - - /// - /// 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(Branch 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. + /// Tests if two are equal. /// - /// First to compare. - /// Second to compare. + /// First to compare. + /// Second to compare. /// True if the two objects are equal; false otherwise. public static bool operator ==(Branch left, Branch right) { @@ -129,10 +139,10 @@ public override int GetHashCode() } /// - /// Tests if two are different. + /// Tests if two are different. /// - /// First to compare. - /// Second to compare. + /// First to compare. + /// Second to compare. /// True if the two objects are different; false otherwise. public static bool operator !=(Branch left, Branch right) { diff --git a/LibGit2Sharp/BranchCollection.cs b/LibGit2Sharp/BranchCollection.cs index a8f0be2b2..56b63c18d 100644 --- a/LibGit2Sharp/BranchCollection.cs +++ b/LibGit2Sharp/BranchCollection.cs @@ -1,7 +1,6 @@ using System; using System.Collections; using System.Collections.Generic; -using System.Globalization; using System.Linq; using LibGit2Sharp.Core; @@ -48,6 +47,20 @@ IEnumerator IEnumerable.GetEnumerator() #endregion + /// + /// Checkout the branch with the specified by name. + /// + /// The name of the branch to checkout. + /// + public Branch Checkout(string name) + { + Ensure.ArgumentNotNullOrEmptyString(name, "name"); + + repo.Refs.UpdateTarget("HEAD", this[name].CanonicalName); + + return this[name]; + } + /// /// Create a new local branch with the specified name /// @@ -57,13 +70,13 @@ IEnumerator IEnumerable.GetEnumerator() public Branch Create(string name, string target) { ObjectId id = ObjectId.CreateFromMaybeSha(target); - if(id != null) + if (id != null) { return Create(name, id); } repo.Refs.Create(NormalizeToCanonicalName(name), NormalizeToCanonicalName(target)); - + return this[name]; } @@ -78,7 +91,7 @@ public Branch Create(string name, ObjectId target) Ensure.ArgumentNotNull(target, "target"); repo.Refs.Create(NormalizeToCanonicalName(name), target); - + return this[name]; } diff --git a/LibGit2Sharp/Core/NativeMethods.cs b/LibGit2Sharp/Core/NativeMethods.cs index e7756819b..3b0c60682 100644 --- a/LibGit2Sharp/Core/NativeMethods.cs +++ b/LibGit2Sharp/Core/NativeMethods.cs @@ -7,6 +7,12 @@ internal class NativeMethods { private const string libgit2 = "git2.dll"; + [DllImport(libgit2, SetLastError = true)] + public static extern IntPtr git_blob_rawcontent(IntPtr blob); + + [DllImport(libgit2, SetLastError = true)] + public static extern int git_blob_rawsize(IntPtr blob); + [DllImport(libgit2, SetLastError = true)] public static extern IntPtr git_commit_author(IntPtr commit); @@ -85,6 +91,12 @@ internal class NativeMethods [DllImport(libgit2)] public static extern int git_reference_resolve(out IntPtr resolvedReference, IntPtr reference); + [DllImport(libgit2, SetLastError = true)] + public static extern int git_reference_set_oid(IntPtr reference, ref GitOid id); + + [DllImport(libgit2, SetLastError = true)] + public static extern int git_reference_set_target(IntPtr reference, string target); + [DllImport(libgit2)] [return: MarshalAs(UnmanagedType.AnsiBStr)] public static extern string git_reference_target(IntPtr reference); @@ -107,7 +119,7 @@ internal class NativeMethods [DllImport(libgit2)] [return: MarshalAs(UnmanagedType.AnsiBStr)] public static extern string git_repository_path(RepositorySafeHandle repository); - + [DllImport(libgit2)] [return: MarshalAs(UnmanagedType.AnsiBStr)] public static extern string git_repository_workdir(RepositorySafeHandle repository); @@ -152,36 +164,27 @@ internal class NativeMethods [DllImport(libgit2, SetLastError = true)] public static extern IntPtr git_tag_target_oid(IntPtr tag); - - /* Blob */ - [DllImport(libgit2, SetLastError = true)] - public static extern int git_blob_rawsize(IntPtr blob); [DllImport(libgit2, SetLastError = true)] - public static extern IntPtr git_blob_rawcontent(IntPtr blob); - - /* Tree */ + public static extern int git_tree_entry_2object(out IntPtr obj, RepositorySafeHandle repo, IntPtr entry); [DllImport(libgit2, SetLastError = true)] - [return: MarshalAs(UnmanagedType.AnsiBStr)] - public static extern string git_tree_entry_name(IntPtr entry); - + public static extern int git_tree_entry_attributes(IntPtr entry); + [DllImport(libgit2, SetLastError = true)] public static extern IntPtr git_tree_entry_byindex(IntPtr tree, int idx); [DllImport(libgit2, SetLastError = true)] public static extern IntPtr git_tree_entry_byname(IntPtr tree, string filename); - - [DllImport(libgit2, SetLastError = true)] - public static extern int git_tree_entrycount(IntPtr tree); [DllImport(libgit2, SetLastError = true)] public static extern IntPtr git_tree_entry_id(IntPtr tree); [DllImport(libgit2, SetLastError = true)] - public static extern int git_tree_entry_2object(out IntPtr obj, RepositorySafeHandle repo, IntPtr entry); + [return: MarshalAs(UnmanagedType.AnsiBStr)] + public static extern string git_tree_entry_name(IntPtr entry); [DllImport(libgit2, SetLastError = true)] - public static extern int git_tree_entry_attributes(IntPtr entry); + public static extern int git_tree_entrycount(IntPtr tree); } } \ No newline at end of file diff --git a/LibGit2Sharp/ReferenceCollection.cs b/LibGit2Sharp/ReferenceCollection.cs index 6dc789c22..05b50d891 100644 --- a/LibGit2Sharp/ReferenceCollection.cs +++ b/LibGit2Sharp/ReferenceCollection.cs @@ -35,6 +35,15 @@ public Reference this[string name] get { return Resolve(name); } } + /// + /// Shortcut to return the reference to HEAD + /// + /// + public Reference Head + { + get { return this[headReferenceName]; } + } + #region IEnumerable Members public IEnumerator GetEnumerator() @@ -94,7 +103,7 @@ public Reference Create(string name, ObjectId target) } /// - /// Delete a reference with the specified name + /// Delete a reference with the specified name /// public void Delete(string name) { @@ -108,28 +117,51 @@ public void Delete(string name) } /// - /// Shortcut to return the reference to HEAD + /// Gets the with the specified name. /// + /// The name. /// - public Reference Head + internal T Resolve(string name) where T : class { - get { return this[headReferenceName]; } + Ensure.ArgumentNotNullOrEmptyString(name, "name"); + + IntPtr reference; + var res = NativeMethods.git_reference_lookup(out reference, repo.Handle, name); + Ensure.Success(res); + + return Reference.BuildFromPtr(reference, repo); } /// - /// Gets the with the specified name. + /// Updates the target on a reference. /// - /// The name. - /// - internal T Resolve(string name) where T : class + /// The name of the reference. + /// The target which can be either a sha or the name of another reference. + public void UpdateTarget(string name, string target) { Ensure.ArgumentNotNullOrEmptyString(name, "name"); + Ensure.ArgumentNotNullOrEmptyString(target, "target"); IntPtr reference; var res = NativeMethods.git_reference_lookup(out reference, repo.Handle, name); Ensure.Success(res); - return Reference.BuildFromPtr(reference, repo); + var id = ObjectId.CreateFromMaybeSha(target); + var type = NativeMethods.git_reference_type(reference); + switch (type) + { + case GitReferenceType.Oid: + if (id == null) throw new ArgumentException(String.Format("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("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; + } + + Ensure.Success(res); } } } \ No newline at end of file