From 3818634bf425d5c6c8e4894bbc1e9eb11b9f0533 Mon Sep 17 00:00:00 2001 From: Metalrom Date: Wed, 10 Apr 2013 18:23:02 +0200 Subject: [PATCH 1/3] Allow update of the target of a symbolic reference with another symbolic reference --- LibGit2Sharp.Tests/ReferenceFixture.cs | 15 +++++++++++++++ LibGit2Sharp/ReferenceCollection.cs | 5 +++++ 2 files changed, 20 insertions(+) diff --git a/LibGit2Sharp.Tests/ReferenceFixture.cs b/LibGit2Sharp.Tests/ReferenceFixture.cs index 38a0d9b54..860cec7ca 100644 --- a/LibGit2Sharp.Tests/ReferenceFixture.cs +++ b/LibGit2Sharp.Tests/ReferenceFixture.cs @@ -686,6 +686,21 @@ public void CanTellIfAReferenceIsValid(string refname, bool expectedResult) } } + [Fact] + public void CanUpdateTheTargetOfASymbolicReferenceWithAnotherSymbolicReference() + { + SelfCleaningDirectory scd = BuildSelfCleaningDirectory(); + + using (var repo = Repository.Init(scd.DirectoryPath)) + { + Reference symbolicRef = repo.Refs.Add("refs/heads/unit_test", "refs/heads/master"); + + Reference newHead = repo.Refs.UpdateTarget(repo.Refs.Head, symbolicRef); + Assert.IsType(newHead); + Assert.Equal(symbolicRef.CanonicalName, newHead.TargetIdentifier); + } + } + private static T[] SortedRefs(IRepository repo, Func selector) { return repo.Refs.OrderBy(r => r.CanonicalName, StringComparer.Ordinal).Select(selector).ToArray(); diff --git a/LibGit2Sharp/ReferenceCollection.cs b/LibGit2Sharp/ReferenceCollection.cs index 3c19e02b2..5d0956ed4 100644 --- a/LibGit2Sharp/ReferenceCollection.cs +++ b/LibGit2Sharp/ReferenceCollection.cs @@ -191,6 +191,11 @@ private Reference UpdateTarget(Reference reference, T target, Func Date: Thu, 28 Mar 2013 11:48:01 +0100 Subject: [PATCH 2/3] Introduce Repository.Refs.Log() returns the reflog of the reference given as parameter --- LibGit2Sharp.Tests/LibGit2Sharp.Tests.csproj | 1 + LibGit2Sharp.Tests/ReflogFixture.cs | 41 +++++++++ .../Core/Handles/ReflogEntrySafeHandle.cs | 6 ++ LibGit2Sharp/Core/Handles/ReflogSafeHandle.cs | 11 +++ LibGit2Sharp/Core/NativeMethods.cs | 34 +++++++ LibGit2Sharp/Core/Proxy.cs | 52 +++++++++++ LibGit2Sharp/LibGit2Sharp.csproj | 4 + LibGit2Sharp/ReferenceCollection.cs | 24 +++++ LibGit2Sharp/ReflogCollection.cs | 91 +++++++++++++++++++ LibGit2Sharp/ReflogEntry.cs | 67 ++++++++++++++ 10 files changed, 331 insertions(+) create mode 100644 LibGit2Sharp.Tests/ReflogFixture.cs create mode 100644 LibGit2Sharp/Core/Handles/ReflogEntrySafeHandle.cs create mode 100644 LibGit2Sharp/Core/Handles/ReflogSafeHandle.cs create mode 100644 LibGit2Sharp/ReflogCollection.cs create mode 100644 LibGit2Sharp/ReflogEntry.cs diff --git a/LibGit2Sharp.Tests/LibGit2Sharp.Tests.csproj b/LibGit2Sharp.Tests/LibGit2Sharp.Tests.csproj index f2568f2cd..a6b9b20fc 100644 --- a/LibGit2Sharp.Tests/LibGit2Sharp.Tests.csproj +++ b/LibGit2Sharp.Tests/LibGit2Sharp.Tests.csproj @@ -61,6 +61,7 @@ + diff --git a/LibGit2Sharp.Tests/ReflogFixture.cs b/LibGit2Sharp.Tests/ReflogFixture.cs new file mode 100644 index 000000000..3811ed32c --- /dev/null +++ b/LibGit2Sharp.Tests/ReflogFixture.cs @@ -0,0 +1,41 @@ +using LibGit2Sharp.Tests.TestHelpers; +using System.Linq; +using Xunit; + +namespace LibGit2Sharp.Tests +{ + public class ReflogFixture : BaseFixture + { + [Fact] + public void CanReadReflog() + { + const int expectedReflogEntriesCount = 3; + + + using (var repo = new Repository(StandardTestRepoWorkingDirPath)) + { + var reflog = repo.Refs.Log(repo.Refs.Head); + + Assert.Equal(expectedReflogEntriesCount, reflog.Count()); + + // Initial commit assertions + Assert.Equal("timothy.clem@gmail.com", reflog.Last().Commiter.Email); + Assert.True(reflog.Last().Message.StartsWith("clone: from")); + Assert.Equal(ObjectId.Zero, reflog.Last().From); + + // second commit assertions + Assert.Equal("4c062a6361ae6959e06292c1fa5e2822d9c96345", reflog.ElementAt(expectedReflogEntriesCount - 2).From.Sha); + Assert.Equal("592d3c869dbc4127fc57c189cb94f2794fa84e7e", reflog.ElementAt(expectedReflogEntriesCount - 2).To.Sha); + } + } + + [Fact] + public void CannotReadReflogOnUnknownReference() + { + using (var repo = new Repository(StandardTestRepoWorkingDirPath)) + { + Assert.Throws(() => repo.Refs.Log("toto").Count()); + } + } + } +} diff --git a/LibGit2Sharp/Core/Handles/ReflogEntrySafeHandle.cs b/LibGit2Sharp/Core/Handles/ReflogEntrySafeHandle.cs new file mode 100644 index 000000000..1739ccac3 --- /dev/null +++ b/LibGit2Sharp/Core/Handles/ReflogEntrySafeHandle.cs @@ -0,0 +1,6 @@ +namespace LibGit2Sharp.Core.Handles +{ + internal class ReflogEntrySafeHandle : NotOwnedSafeHandleBase + { + } +} diff --git a/LibGit2Sharp/Core/Handles/ReflogSafeHandle.cs b/LibGit2Sharp/Core/Handles/ReflogSafeHandle.cs new file mode 100644 index 000000000..a75deabea --- /dev/null +++ b/LibGit2Sharp/Core/Handles/ReflogSafeHandle.cs @@ -0,0 +1,11 @@ +namespace LibGit2Sharp.Core.Handles +{ + internal class ReflogSafeHandle : SafeHandleBase + { + protected override bool ReleaseHandleImpl() + { + Proxy.git_reflog_free(handle); + return true; + } + } +} diff --git a/LibGit2Sharp/Core/NativeMethods.cs b/LibGit2Sharp/Core/NativeMethods.cs index d6ffd2891..e8db98a4a 100644 --- a/LibGit2Sharp/Core/NativeMethods.cs +++ b/LibGit2Sharp/Core/NativeMethods.cs @@ -699,6 +699,40 @@ internal static extern int git_reference_symbolic_set_target( [DllImport(libgit2)] internal static extern GitReferenceType git_reference_type(ReferenceSafeHandle reference); + [DllImport(libgit2)] + internal static extern void git_reflog_free( + IntPtr reflog); + + [DllImport(libgit2)] + internal static extern int git_reflog_read( + out ReflogSafeHandle ref_out, + ReferenceSafeHandle reference); + + [DllImport(libgit2)] + internal static extern UIntPtr git_reflog_entrycount + (ReflogSafeHandle reflog); + + [DllImport(libgit2)] + internal static extern ReflogEntrySafeHandle git_reflog_entry_byindex( + ReflogSafeHandle reflog, + UIntPtr idx); + + [DllImport(libgit2)] + internal static extern OidSafeHandle git_reflog_entry_id_old( + SafeHandle entry); + + [DllImport(libgit2)] + internal static extern OidSafeHandle git_reflog_entry_id_new( + SafeHandle entry); + + [DllImport(libgit2)] + internal static extern IntPtr git_reflog_entry_committer( + SafeHandle entry); + + [DllImport(libgit2)] + [return: MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(Utf8NoCleanupMarshaler))] + internal static extern string git_reflog_entry_message(SafeHandle entry); + [DllImport(libgit2)] internal static extern int git_refspec_rtransform( byte[] target, diff --git a/LibGit2Sharp/Core/Proxy.cs b/LibGit2Sharp/Core/Proxy.cs index 68226c20f..962f60ad0 100644 --- a/LibGit2Sharp/Core/Proxy.cs +++ b/LibGit2Sharp/Core/Proxy.cs @@ -1267,6 +1267,58 @@ public static GitReferenceType git_reference_type(ReferenceSafeHandle reference) #endregion + #region git_reflog_ + + public static void git_reflog_free(IntPtr reflog) + { + NativeMethods.git_reflog_free(reflog); + } + + public static ReflogSafeHandle git_reflog_read(ReferenceSafeHandle reference) + { + using (ThreadAffinity()) + { + ReflogSafeHandle reflog_out; + + int res = NativeMethods.git_reflog_read(out reflog_out, reference); + Ensure.ZeroResult(res); + + return reflog_out; + } + } + + public static int git_reflog_entrycount(ReflogSafeHandle reflog) + { + return (int)NativeMethods.git_reflog_entrycount(reflog); + } + + public static ReflogEntrySafeHandle git_reflog_entry_byindex(ReflogSafeHandle reflog, int idx) + { + return NativeMethods.git_reflog_entry_byindex(reflog, (UIntPtr)idx); + } + + public static ObjectId git_reflog_entry_id_old(SafeHandle entry) + { + return NativeMethods.git_reflog_entry_id_old(entry).MarshalAsObjectId(); + } + + public static ObjectId git_reflog_entry_id_new(SafeHandle entry) + { + return NativeMethods.git_reflog_entry_id_new(entry).MarshalAsObjectId(); + } + + public static Signature git_reflog_entry_committer(SafeHandle entry) + { + return new Signature(NativeMethods.git_reflog_entry_committer(entry)); + } + + public static string git_reflog_entry_message(SafeHandle entry) + { + return NativeMethods.git_reflog_entry_message(entry); + } + + #endregion + #region git_refspec public static string git_refspec_rtransform(GitRefSpecHandle refSpecPtr, string name) diff --git a/LibGit2Sharp/LibGit2Sharp.csproj b/LibGit2Sharp/LibGit2Sharp.csproj index 28fee9413..b88853e12 100644 --- a/LibGit2Sharp/LibGit2Sharp.csproj +++ b/LibGit2Sharp/LibGit2Sharp.csproj @@ -71,10 +71,14 @@ + + + + diff --git a/LibGit2Sharp/ReferenceCollection.cs b/LibGit2Sharp/ReferenceCollection.cs index 5d0956ed4..43a2e4b2c 100644 --- a/LibGit2Sharp/ReferenceCollection.cs +++ b/LibGit2Sharp/ReferenceCollection.cs @@ -267,5 +267,29 @@ private string DebuggerDisplay "Count = {0}", this.Count()); } } + + /// + /// Returns as a the reflog of the named + /// + /// The canonical name of the reference + /// a , enumerable of + public virtual ReflogCollection Log(string canonicalName) + { + Ensure.ArgumentNotNullOrEmptyString(canonicalName, "canonicalName"); + + return new ReflogCollection(repo, canonicalName); + } + + /// + /// Returns as a the reflog of the + /// + /// The reference + /// a , enumerable of + public virtual ReflogCollection Log(Reference reference) + { + Ensure.ArgumentNotNull(reference, "reference"); + + return new ReflogCollection(repo, reference.CanonicalName); + } } } diff --git a/LibGit2Sharp/ReflogCollection.cs b/LibGit2Sharp/ReflogCollection.cs new file mode 100644 index 000000000..9fef28c3f --- /dev/null +++ b/LibGit2Sharp/ReflogCollection.cs @@ -0,0 +1,91 @@ +using System; +using System.Collections; +using System.Collections.Generic; +using System.Diagnostics; +using System.Globalization; +using System.Linq; +using LibGit2Sharp.Core; +using LibGit2Sharp.Core.Handles; + +namespace LibGit2Sharp +{ + /// + /// The is the reflog of a given , as a enumerable of . + /// Reflog is a mechanism to record when the tip of a is updated. + /// + [DebuggerDisplay("{DebuggerDisplay,nq}")] + public class ReflogCollection : IEnumerable + { + internal readonly Repository repo; + + private readonly string canonicalName; + + /// + /// Needed for mocking purposes. + /// + protected ReflogCollection() + { } + + /// + /// Initializes a new instance of the class. + /// + /// The repo. + /// the canonical name of the to retrieve reflog entries on. + internal ReflogCollection(Repository repo, string canonicalName) + { + Ensure.ArgumentNotNullOrEmptyString(canonicalName, "canonicalName"); + Ensure.ArgumentNotNull(repo, "repo"); + + this.repo = repo; + this.canonicalName = canonicalName; + } + + #region Implementation of IEnumerable + + /// + /// Returns an enumerator that iterates through the collection. + /// + /// The enumerator returns the by descending order (last reflog entry is returned first). + /// + /// + /// An object that can be used to iterate through the collection. + public IEnumerator GetEnumerator() + { + var entries = new List(); + + using (ReferenceSafeHandle reference = Proxy.git_reference_lookup(repo.Handle, canonicalName, true)) + using (ReflogSafeHandle reflog = Proxy.git_reflog_read(reference)) + { + var entriesCount = Proxy.git_reflog_entrycount(reflog); + + for (int i = 0; i < entriesCount; i++) + { + ReflogEntrySafeHandle handle = Proxy.git_reflog_entry_byindex(reflog, i); + entries.Add(new ReflogEntry(handle)); + } + } + + return entries.GetEnumerator(); + } + + /// + /// Returns an enumerator that iterates through the collection. + /// + /// An object that can be used to iterate through the collection. + IEnumerator IEnumerable.GetEnumerator() + { + return GetEnumerator(); + } + + #endregion + + private string DebuggerDisplay + { + get + { + return string.Format(CultureInfo.InvariantCulture, + "Count = {0}", this.Count()); + } + } + } +} diff --git a/LibGit2Sharp/ReflogEntry.cs b/LibGit2Sharp/ReflogEntry.cs new file mode 100644 index 000000000..d9f53170f --- /dev/null +++ b/LibGit2Sharp/ReflogEntry.cs @@ -0,0 +1,67 @@ +using System.Runtime.InteropServices; +using LibGit2Sharp.Core; + +namespace LibGit2Sharp +{ + /// + /// As single entry of a + /// a describes one single update on a particular reference + /// + public class ReflogEntry + { + private readonly ObjectId _from; + private readonly ObjectId _to; + private readonly Signature _commiter; + private readonly string message; + + /// + /// Needed for mocking purposes. + /// + protected ReflogEntry() + { } + + /// + /// Initializes a new instance of the class. + /// + /// a to the reflog entry + public ReflogEntry(SafeHandle entryHandle) + { + _from = Proxy.git_reflog_entry_id_old(entryHandle); + _to = Proxy.git_reflog_entry_id_new(entryHandle); + _commiter = Proxy.git_reflog_entry_committer(entryHandle); + message = Proxy.git_reflog_entry_message(entryHandle); + } + + /// + /// targeted before the reference update described by this + /// + public virtual ObjectId From + { + get { return _from; } + } + + /// + /// targeted after the reference update described by this + /// + public virtual ObjectId To + { + get { return _to; } + } + + /// + /// of the commiter of this reference update + /// + public virtual Signature Commiter + { + get { return _commiter; } + } + + /// + /// the message assiocated to this reference update + /// + public virtual string Message + { + get { return message; } + } + } +} From 90c9b202758bbfba105b8602584ca4ee27f42da1 Mon Sep 17 00:00:00 2001 From: Metalrom Date: Mon, 8 Apr 2013 17:29:26 +0200 Subject: [PATCH 3/3] Insert new reflog entry on commit Fix #371 Insert entry on HEAD and target direct reference on commit Tag as initial the first commit --- LibGit2Sharp.Tests/CommitFixture.cs | 24 ++++++++++- LibGit2Sharp.Tests/ReflogFixture.cs | 67 ++++++++++++++++++++++++++++- LibGit2Sharp/Core/NativeMethods.cs | 10 +++++ LibGit2Sharp/Core/Proxy.cs | 15 +++++++ LibGit2Sharp/ReflogCollection.cs | 20 ++++++++- LibGit2Sharp/Repository.cs | 30 +++++++++++++ 6 files changed, 161 insertions(+), 5 deletions(-) diff --git a/LibGit2Sharp.Tests/CommitFixture.cs b/LibGit2Sharp.Tests/CommitFixture.cs index 4b4db8ec7..1d302023c 100644 --- a/LibGit2Sharp.Tests/CommitFixture.cs +++ b/LibGit2Sharp.Tests/CommitFixture.cs @@ -614,7 +614,8 @@ public void CanCommitALittleBit() Assert.Null(repo.Head[relativeFilepath]); var author = DummySignature; - Commit commit = repo.Commit("Initial egotistic commit", author, author); + const string commitMessage = "Initial egotistic commit"; + Commit commit = repo.Commit(commitMessage, author, author); AssertBlobContent(repo.Head[relativeFilepath], "nulltoken\n"); AssertBlobContent(commit[relativeFilepath], "nulltoken\n"); @@ -622,6 +623,14 @@ public void CanCommitALittleBit() Assert.Equal(0, commit.Parents.Count()); Assert.False(repo.Info.IsHeadOrphaned); + // Assert a reflog entry is created + Assert.Equal(1, repo.Refs.Log("HEAD").Count()); + var reflogEntry = repo.Refs.Log("HEAD").First(); + Assert.Equal(author, reflogEntry.Commiter); + Assert.Equal(commit.Id, reflogEntry.To); + Assert.Equal(ObjectId.Zero, reflogEntry.From); + Assert.Equal(string.Format("commit (initial): {0}", commitMessage), reflogEntry.Message); + File.WriteAllText(filePath, "nulltoken commits!\n"); repo.Index.Stage(relativeFilepath); @@ -634,6 +643,10 @@ public void CanCommitALittleBit() Assert.Equal(1, commit2.Parents.Count()); Assert.Equal(commit.Id, commit2.Parents.First().Id); + // Assert the reflog is shifted + Assert.Equal(2, repo.Refs.Log("HEAD").Count()); + Assert.Equal(reflogEntry.To, repo.Refs.Log("HEAD").First().From); + Branch firstCommitBranch = repo.CreateBranch("davidfowl-rules", commit); repo.Checkout(firstCommitBranch); @@ -731,10 +744,17 @@ public void CanAmendACommitWithMoreThanOneParent() repo.Reset(ResetOptions.Soft, mergedCommit.Sha); CreateAndStageANewFile(repo); + const string commitMessage = "I'm rewriting the history!"; - Commit amendedCommit = repo.Commit("I'm rewriting the history!", DummySignature, DummySignature, true); + Commit amendedCommit = repo.Commit(commitMessage, DummySignature, DummySignature, true); AssertCommitHasBeenAmended(repo, amendedCommit, mergedCommit); + + // Assert a reflog entry is created + var reflogEntry = repo.Refs.Log("HEAD").First(); + Assert.Equal(amendedCommit.Committer, reflogEntry.Commiter); + Assert.Equal(amendedCommit.Id, reflogEntry.To); + Assert.Equal(string.Format("commit (amend): {0}", commitMessage), reflogEntry.Message); } } diff --git a/LibGit2Sharp.Tests/ReflogFixture.cs b/LibGit2Sharp.Tests/ReflogFixture.cs index 3811ed32c..a5f287f4c 100644 --- a/LibGit2Sharp.Tests/ReflogFixture.cs +++ b/LibGit2Sharp.Tests/ReflogFixture.cs @@ -1,4 +1,5 @@ -using LibGit2Sharp.Tests.TestHelpers; +using System.IO; +using LibGit2Sharp.Tests.TestHelpers; using System.Linq; using Xunit; @@ -37,5 +38,69 @@ public void CannotReadReflogOnUnknownReference() Assert.Throws(() => repo.Refs.Log("toto").Count()); } } + + [Fact] + public void CommitShouldCreateReflogEntryOnHeadandOnTargetedDirectReference() + { + SelfCleaningDirectory scd = BuildSelfCleaningDirectory(); + + using (var repo = Repository.Init(scd.DirectoryPath)) + { + // setup refs as HEAD => unit_test => master + var newRef = repo.Refs.Add("refs/heads/unit_test", "refs/heads/master"); + Assert.NotNull(newRef); + repo.Refs.UpdateTarget(repo.Refs.Head, newRef); + + const string relativeFilepath = "new.txt"; + string filePath = Path.Combine(repo.Info.WorkingDirectory, relativeFilepath); + + File.WriteAllText(filePath, "content\n"); + repo.Index.Stage(relativeFilepath); + + var author = DummySignature; + const string commitMessage = "Hope reflog behaves as it should"; + Commit commit = repo.Commit(commitMessage, author, author); + + // Assert a reflog entry is created on HEAD + Assert.Equal(1, repo.Refs.Log("HEAD").Count()); + var reflogEntry = repo.Refs.Log("HEAD").First(); + Assert.Equal(author, reflogEntry.Commiter); + Assert.Equal(commit.Id, reflogEntry.To); + Assert.Equal(ObjectId.Zero, reflogEntry.From); + + // Assert the same reflog entry is created on refs/heads/master + Assert.Equal(1, repo.Refs.Log("refs/heads/master").Count()); + reflogEntry = repo.Refs.Log("HEAD").First(); + Assert.Equal(author, reflogEntry.Commiter); + Assert.Equal(commit.Id, reflogEntry.To); + Assert.Equal(ObjectId.Zero, reflogEntry.From); + + // Assert no reflog entry is created on refs/heads/unit_test + Assert.Equal(0, repo.Refs.Log("refs/heads/unit_test").Count()); + } + } + + [Fact] + public void CommitOnUnbornReferenceShouldCreateReflogEntryWithInitialTag() + { + SelfCleaningDirectory scd = BuildSelfCleaningDirectory(); + + using (var repo = Repository.Init(scd.DirectoryPath)) + { + const string relativeFilepath = "new.txt"; + string filePath = Path.Combine(repo.Info.WorkingDirectory, relativeFilepath); + + File.WriteAllText(filePath, "content\n"); + repo.Index.Stage(relativeFilepath); + + var author = DummySignature; + const string commitMessage = "First commit should be logged as initial"; + repo.Commit(commitMessage, author, author); + + // Assert the reflog entry message is correct + Assert.Equal(1, repo.Refs.Log("HEAD").Count()); + Assert.Equal(string.Format("commit (initial): {0}", commitMessage), repo.Refs.Log("HEAD").First().Message); + } + } } } diff --git a/LibGit2Sharp/Core/NativeMethods.cs b/LibGit2Sharp/Core/NativeMethods.cs index e8db98a4a..227f22e4b 100644 --- a/LibGit2Sharp/Core/NativeMethods.cs +++ b/LibGit2Sharp/Core/NativeMethods.cs @@ -729,6 +729,16 @@ internal static extern OidSafeHandle git_reflog_entry_id_new( internal static extern IntPtr git_reflog_entry_committer( SafeHandle entry); + [DllImport(libgit2)] + internal static extern int git_reflog_append( + ReflogSafeHandle reflog, + ref GitOid id, + SignatureSafeHandle committer, + [MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(Utf8Marshaler))] string msg); + + [DllImport(libgit2)] + internal static extern int git_reflog_write(ReflogSafeHandle reflog); + [DllImport(libgit2)] [return: MarshalAs(UnmanagedType.CustomMarshaler, MarshalTypeRef = typeof(Utf8NoCleanupMarshaler))] internal static extern string git_reflog_entry_message(SafeHandle entry); diff --git a/LibGit2Sharp/Core/Proxy.cs b/LibGit2Sharp/Core/Proxy.cs index 962f60ad0..c6c2975e1 100644 --- a/LibGit2Sharp/Core/Proxy.cs +++ b/LibGit2Sharp/Core/Proxy.cs @@ -1317,6 +1317,21 @@ public static string git_reflog_entry_message(SafeHandle entry) return NativeMethods.git_reflog_entry_message(entry); } + public static void git_reflog_append(ReflogSafeHandle reflog, ObjectId commit_id, Signature committer, string message) + { + using (ThreadAffinity()) + using (SignatureSafeHandle committerHandle = committer.BuildHandle()) + { + var oid = commit_id.Oid; + + int res = NativeMethods.git_reflog_append(reflog, ref oid, committerHandle, message); + Ensure.ZeroResult(res); + + res = NativeMethods.git_reflog_write(reflog); + Ensure.ZeroResult(res); + } + } + #endregion #region git_refspec diff --git a/LibGit2Sharp/ReflogCollection.cs b/LibGit2Sharp/ReflogCollection.cs index 9fef28c3f..1cd50af1b 100644 --- a/LibGit2Sharp/ReflogCollection.cs +++ b/LibGit2Sharp/ReflogCollection.cs @@ -1,5 +1,4 @@ -using System; -using System.Collections; +using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; @@ -87,5 +86,22 @@ private string DebuggerDisplay "Count = {0}", this.Count()); } } + + /// + /// Add a new to the current . It will be created as first item of the collection + /// The native reflog object will be saved right after inserting the entry. + /// + /// the of the new commit the will point out. + /// of the author of the new commit. + /// the message associated with the new . + internal virtual void Append(ObjectId objectId, Signature committer, string message) + { + using (ReferenceSafeHandle reference = Proxy.git_reference_lookup(repo.Handle, canonicalName, true)) + using (ReflogSafeHandle reflog = Proxy.git_reflog_read(reference)) + { + string prettifiedMessage = Proxy.git_message_prettify(message); + Proxy.git_reflog_append(reflog, objectId, committer, prettifiedMessage); + } + } } } diff --git a/LibGit2Sharp/Repository.cs b/LibGit2Sharp/Repository.cs index 32768a470..b6532070d 100644 --- a/LibGit2Sharp/Repository.cs +++ b/LibGit2Sharp/Repository.cs @@ -684,9 +684,39 @@ public Commit Commit(string message, Signature author, Signature committer, bool Proxy.git_repository_merge_cleanup(handle); + // Insert reflog entry + LogCommit(result, amendPreviousCommit, parents.Count() == 0); + return result; } + private void LogCommit(Commit commit, bool amendPreviousCommit, bool isInitialCommit) + { + // Compute reflog message + string reflogMessage = "commit"; + if (isInitialCommit) + { + reflogMessage += " (initial)"; + } + else if(amendPreviousCommit) + { + reflogMessage += " (amend)"; + } + + reflogMessage = string.Format("{0}: {1}", reflogMessage, commit.Message); + + var headRef = Refs.Head; + + // in case HEAD targets a symbolic reference, log commit on the targeted direct reference + if(headRef is SymbolicReference) + { + Refs.Log(headRef.ResolveToDirectReference()).Append(commit.Id, commit.Committer, reflogMessage); + } + + // Log commit on HEAD + Refs.Log(headRef).Append(commit.Id, commit.Committer, reflogMessage); + } + private IEnumerable RetrieveParentsOfTheCommitBeingCreated(bool amendPreviousCommit) { if (amendPreviousCommit)