diff --git a/LibGit2Sharp.Tests/BranchFixture.cs b/LibGit2Sharp.Tests/BranchFixture.cs index bb5d6b5e8..3290f7523 100644 --- a/LibGit2Sharp.Tests/BranchFixture.cs +++ b/LibGit2Sharp.Tests/BranchFixture.cs @@ -20,15 +20,25 @@ public void CanCreateBranch(string name) string path = CloneBareTestRepo(); using (var repo = new Repository(path)) { - Branch newBranch = repo.CreateBranch(name, "be3563ae3f795b2b4353bcce3a527ad0a4f7f644"); + EnableRefLog(repo); + + const string committish = "be3563ae3f795b2b4353bcce3a527ad0a4f7f644"; + + Branch newBranch = repo.CreateBranch(name, committish); Assert.NotNull(newBranch); Assert.Equal(name, newBranch.Name); Assert.Equal("refs/heads/" + name, newBranch.CanonicalName); Assert.NotNull(newBranch.Tip); - Assert.Equal("be3563ae3f795b2b4353bcce3a527ad0a4f7f644", newBranch.Tip.Sha); + Assert.Equal(committish, newBranch.Tip.Sha); Assert.NotNull(repo.Branches.SingleOrDefault(p => p.Name == name)); + AssertRefLogEntry(repo, newBranch.CanonicalName, + newBranch.Tip.Id, + "branch: Created from " + committish, + committer: newBranch.Tip.Committer); + repo.Branches.Remove(newBranch.Name); + Assert.Null(repo.Branches[name]); } } @@ -38,19 +48,34 @@ public void CanCreateBranchUsingAbbreviatedSha() string path = CloneBareTestRepo(); using (var repo = new Repository(path)) { + EnableRefLog(repo); + const string name = "unit_test"; - Branch newBranch = repo.CreateBranch(name, "be3563a"); + const string committish = "be3563a"; + + Branch newBranch = repo.CreateBranch(name, committish); Assert.Equal("refs/heads/" + name, newBranch.CanonicalName); Assert.Equal("be3563ae3f795b2b4353bcce3a527ad0a4f7f644", newBranch.Tip.Sha); + + AssertRefLogEntry(repo, newBranch.CanonicalName, + newBranch.Tip.Id, + "branch: Created from " + committish, + committer: newBranch.Tip.Committer); } } - [Fact] - public void CanCreateBranchFromImplicitHead() + [Theory] + [InlineData("32eab9cb1f450b5fe7ab663462b77d7f4b703344")] + [InlineData("master")] + public void CanCreateBranchFromImplicitHead(string headCommitOrBranchSpec) { - string path = CloneBareTestRepo(); + string path = CloneStandardTestRepo(); using (var repo = new Repository(path)) { + EnableRefLog(repo); + + repo.Checkout(headCommitOrBranchSpec); + const string name = "unit_test"; Branch newBranch = repo.CreateBranch(name); Assert.NotNull(newBranch); @@ -58,21 +83,37 @@ public void CanCreateBranchFromImplicitHead() Assert.Equal("refs/heads/" + name, newBranch.CanonicalName); Assert.False(newBranch.IsCurrentRepositoryHead); Assert.NotNull(newBranch.Tip); - Assert.Equal("4c062a6361ae6959e06292c1fa5e2822d9c96345", newBranch.Tip.Sha); + Assert.Equal("32eab9cb1f450b5fe7ab663462b77d7f4b703344", newBranch.Tip.Sha); Assert.NotNull(repo.Branches.SingleOrDefault(p => p.Name == name)); + + AssertRefLogEntry(repo, newBranch.CanonicalName, + newBranch.Tip.Id, + "branch: Created from " + headCommitOrBranchSpec, + committer: newBranch.Tip.Committer); } } - [Fact] - public void CanCreateBranchFromExplicitHead() + [Theory] + [InlineData("32eab9cb1f450b5fe7ab663462b77d7f4b703344")] + [InlineData("master")] + public void CanCreateBranchFromExplicitHead(string headCommitOrBranchSpec) { - string path = CloneBareTestRepo(); + string path = CloneStandardTestRepo(); using (var repo = new Repository(path)) { + EnableRefLog(repo); + + repo.Checkout(headCommitOrBranchSpec); + const string name = "unit_test"; Branch newBranch = repo.CreateBranch(name, "HEAD"); Assert.NotNull(newBranch); - Assert.Equal("4c062a6361ae6959e06292c1fa5e2822d9c96345", newBranch.Tip.Sha); + Assert.Equal("32eab9cb1f450b5fe7ab663462b77d7f4b703344", newBranch.Tip.Sha); + + AssertRefLogEntry(repo, newBranch.CanonicalName, + newBranch.Tip.Id, + "branch: Created from " + headCommitOrBranchSpec, + committer: newBranch.Tip.Committer); } } @@ -82,11 +123,18 @@ public void CanCreateBranchFromCommit() string path = CloneBareTestRepo(); using (var repo = new Repository(path)) { + EnableRefLog(repo); + const string name = "unit_test"; var commit = repo.Lookup("HEAD"); Branch newBranch = repo.CreateBranch(name, commit); Assert.NotNull(newBranch); Assert.Equal("4c062a6361ae6959e06292c1fa5e2822d9c96345", newBranch.Tip.Sha); + + AssertRefLogEntry(repo, newBranch.CanonicalName, + newBranch.Tip.Id, + "branch: Created from " + newBranch.Tip.Sha, + committer: newBranch.Tip.Committer); } } @@ -96,24 +144,42 @@ public void CanCreateBranchFromRevparseSpec() string path = CloneBareTestRepo(); using (var repo = new Repository(path)) { + EnableRefLog(repo); + const string name = "revparse_branch"; - var target = repo.Lookup("master~2"); - Branch newBranch = repo.CreateBranch(name, target); + const string committish = "master~2"; + + Branch newBranch = repo.CreateBranch(name, committish); Assert.NotNull(newBranch); Assert.Equal("9fd738e8f7967c078dceed8190330fc8648ee56a", newBranch.Tip.Sha); + + AssertRefLogEntry(repo, newBranch.CanonicalName, + newBranch.Tip.Id, + "branch: Created from " + committish, + committer: newBranch.Tip.Committer); } } - [Fact] - public void CreatingABranchFromATagPeelsToTheCommit() + [Theory] + [InlineData("test")] + [InlineData("refs/tags/test")] + public void CreatingABranchFromATagPeelsToTheCommit(string committish) { string path = CloneBareTestRepo(); using (var repo = new Repository(path)) { + EnableRefLog(repo); + const string name = "i-peel-tag"; - Branch newBranch = repo.CreateBranch(name, "refs/tags/test"); + + Branch newBranch = repo.CreateBranch(name, committish); Assert.NotNull(newBranch); Assert.Equal("e90810b8df3e80c413d903f631643c716887138d", newBranch.Tip.Sha); + + AssertRefLogEntry(repo, newBranch.CanonicalName, + newBranch.Tip.Id, + "branch: Created from " + committish, + committer: newBranch.Tip.Committer); } } @@ -725,13 +791,23 @@ public void CanMoveABranch() string path = CloneBareTestRepo(); using (var repo = new Repository(path)) { + EnableRefLog(repo); + Assert.Null(repo.Branches["br3"]); + var br2 = repo.Branches["br2"]; + Assert.NotNull(br2); Branch newBranch = repo.Branches.Move("br2", "br3"); + Assert.Equal("br3", newBranch.Name); Assert.Null(repo.Branches["br2"]); Assert.NotNull(repo.Branches["br3"]); + + AssertRefLogEntry(repo, newBranch.CanonicalName, + newBranch.Tip.Id, + string.Format("Branch: renamed {0} to {1}", br2.CanonicalName, newBranch.CanonicalName), + committer: newBranch.Tip.Committer); } } @@ -750,6 +826,8 @@ public void CanMoveABranchWhileOverwritingAnExistingOne() string path = CloneBareTestRepo(); using (var repo = new Repository(path)) { + EnableRefLog(repo); + Branch test = repo.Branches["test"]; Assert.NotNull(test); @@ -766,6 +844,11 @@ public void CanMoveABranchWhileOverwritingAnExistingOne() Assert.Equal(newBranch, newTest); Assert.Equal(br2.Tip, newTest.Tip); + + AssertRefLogEntry(repo, newBranch.CanonicalName, + newBranch.Tip.Id, + string.Format("Branch: renamed {0} to {1}", br2.CanonicalName, newBranch.CanonicalName), + committer: newBranch.Tip.Committer); } } diff --git a/LibGit2Sharp.Tests/CommitFixture.cs b/LibGit2Sharp.Tests/CommitFixture.cs index 48ea69c36..a465ae36b 100644 --- a/LibGit2Sharp.Tests/CommitFixture.cs +++ b/LibGit2Sharp.Tests/CommitFixture.cs @@ -773,11 +773,11 @@ public void CanAmendACommitWithMoreThanOneParent() 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); + AssertRefLogEntry(repo, "HEAD", + amendedCommit.Id, + string.Format("commit (amend): {0}", commitMessage), + mergedCommit.Id, + amendedCommit.Committer); } } diff --git a/LibGit2Sharp.Tests/ConfigurationFixture.cs b/LibGit2Sharp.Tests/ConfigurationFixture.cs index e51c05760..8783cc4be 100644 --- a/LibGit2Sharp.Tests/ConfigurationFixture.cs +++ b/LibGit2Sharp.Tests/ConfigurationFixture.cs @@ -110,6 +110,11 @@ public void CanReadBooleanValue() using (var repo = new Repository(StandardTestRepoPath)) { Assert.True(repo.Config.Get("core.ignorecase").Value); + Assert.True(repo.Config.GetValueOrDefault("core.ignorecase")); + + Assert.Equal(false, repo.Config.GetValueOrDefault("missing.key")); + Assert.Equal(true, repo.Config.GetValueOrDefault("missing.key", true)); + Assert.Equal(true, repo.Config.GetValueOrDefault("missing.key", () => true)); } } @@ -119,6 +124,12 @@ public void CanReadIntValue() using (var repo = new Repository(StandardTestRepoPath)) { Assert.Equal(2, repo.Config.Get("unittests.intsetting").Value); + Assert.Equal(2, repo.Config.GetValueOrDefault("unittests.intsetting")); + Assert.Equal(2, repo.Config.GetValueOrDefault("unittests.intsetting", ConfigurationLevel.Local)); + + Assert.Equal(0, repo.Config.GetValueOrDefault("missing.key")); + Assert.Equal(4, repo.Config.GetValueOrDefault("missing.key", 4)); + Assert.Equal(4, repo.Config.GetValueOrDefault("missing.key", () => 4)); } } @@ -128,6 +139,11 @@ public void CanReadLongValue() using (var repo = new Repository(StandardTestRepoPath)) { Assert.Equal(15234, repo.Config.Get("unittests.longsetting").Value); + Assert.Equal(15234, repo.Config.GetValueOrDefault("unittests.longsetting")); + + Assert.Equal(0, repo.Config.GetValueOrDefault("missing.key")); + Assert.Equal(4, repo.Config.GetValueOrDefault("missing.key", 4)); + Assert.Equal(4, repo.Config.GetValueOrDefault("missing.key", () => 4)); } } @@ -138,6 +154,35 @@ public void CanReadStringValue() { Assert.Equal("+refs/heads/*:refs/remotes/origin/*", repo.Config.Get("remote.origin.fetch").Value); Assert.Equal("+refs/heads/*:refs/remotes/origin/*", repo.Config.Get("remote", "origin", "fetch").Value); + + Assert.Equal("+refs/heads/*:refs/remotes/origin/*", repo.Config.GetValueOrDefault("remote.origin.fetch")); + Assert.Equal("+refs/heads/*:refs/remotes/origin/*", repo.Config.GetValueOrDefault("remote.origin.fetch", ConfigurationLevel.Local)); + Assert.Equal("+refs/heads/*:refs/remotes/origin/*", repo.Config.GetValueOrDefault("remote", "origin", "fetch")); + Assert.Equal("+refs/heads/*:refs/remotes/origin/*", repo.Config.GetValueOrDefault(new[] { "remote", "origin", "fetch" })); + + Assert.Equal(null, repo.Config.GetValueOrDefault("missing.key")); + Assert.Equal(null, repo.Config.GetValueOrDefault("missing.key", default(string))); + Assert.Throws(() => repo.Config.GetValueOrDefault("missing.key", default(Func))); + Assert.Equal("value", repo.Config.GetValueOrDefault("missing.key", "value")); + Assert.Equal("value", repo.Config.GetValueOrDefault("missing.key", () => "value")); + + Assert.Equal(null, repo.Config.GetValueOrDefault("missing.key", ConfigurationLevel.Local)); + Assert.Equal(null, repo.Config.GetValueOrDefault("missing.key", ConfigurationLevel.Local, default(string))); + Assert.Throws(() => repo.Config.GetValueOrDefault("missing.key", ConfigurationLevel.Local, default(Func))); + Assert.Equal("value", repo.Config.GetValueOrDefault("missing.key", ConfigurationLevel.Local, "value")); + Assert.Equal("value", repo.Config.GetValueOrDefault("missing.key", ConfigurationLevel.Local, () => "value")); + + Assert.Equal(null, repo.Config.GetValueOrDefault("missing", "config", "key")); + Assert.Equal(null, repo.Config.GetValueOrDefault("missing", "config", "key", default(string))); + Assert.Throws(() => repo.Config.GetValueOrDefault("missing", "config", "key", default(Func))); + Assert.Equal("value", repo.Config.GetValueOrDefault("missing", "config", "key", "value")); + Assert.Equal("value", repo.Config.GetValueOrDefault("missing", "config", "key", () => "value")); + + Assert.Equal(null, repo.Config.GetValueOrDefault(new[] { "missing", "key" })); + Assert.Equal(null, repo.Config.GetValueOrDefault(new[] { "missing", "key" }, default(string))); + Assert.Throws(() => repo.Config.GetValueOrDefault(new[] { "missing", "key" }, default(Func))); + Assert.Equal("value", repo.Config.GetValueOrDefault(new[] { "missing", "key" }, "value")); + Assert.Equal("value", repo.Config.GetValueOrDefault(new[] { "missing", "key" }, () => "value")); } } diff --git a/LibGit2Sharp.Tests/FilterBranchFixture.cs b/LibGit2Sharp.Tests/FilterBranchFixture.cs index dd2ac4778..5e662000a 100644 --- a/LibGit2Sharp.Tests/FilterBranchFixture.cs +++ b/LibGit2Sharp.Tests/FilterBranchFixture.cs @@ -474,6 +474,8 @@ public void CanRewriteParentWithRewrittenCommit() [Fact] public void WritesCorrectReflogMessagesForSimpleRewrites() { + EnableRefLog(repo); + repo.Refs.RewriteHistory(new RewriteHistoryOptions { CommitHeaderRewriter = diff --git a/LibGit2Sharp.Tests/ReferenceFixture.cs b/LibGit2Sharp.Tests/ReferenceFixture.cs index 308908aac..e499e129d 100644 --- a/LibGit2Sharp.Tests/ReferenceFixture.cs +++ b/LibGit2Sharp.Tests/ReferenceFixture.cs @@ -43,6 +43,8 @@ public void CanAddADirectReferenceFromRevParseSpec() string path = CloneBareTestRepo(); using (var repo = new Repository(path)) { + EnableRefLog(repo); + var newRef = (DirectReference)repo.Refs.Add(name, "master^1^2", logMessage: logMessage); Assert.NotNull(newRef); Assert.Equal(name, newRef.CanonicalName); @@ -51,11 +53,9 @@ public void CanAddADirectReferenceFromRevParseSpec() Assert.Equal(newRef.Target.Sha, newRef.TargetIdentifier); Assert.NotNull(repo.Refs[name]); - AssertReflogEntryIsCreated( - repo.Refs.Log(newRef), - newRef.ResolveToDirectReference().Target.Sha, - logMessage, - ObjectId.Zero.Sha); + AssertRefLogEntry(repo, name, + newRef.ResolveToDirectReference().Target.Id, + logMessage); } } @@ -96,17 +96,17 @@ public void CanAddASymbolicReferenceFromTheTargetReference() string path = CloneBareTestRepo(); using (var repo = new Repository(path)) { + EnableRefLog(repo); + var targetRef = repo.Refs[target]; var newRef = repo.Refs.Add(name, targetRef, logMessage: logMessage); AssertSymbolicRef(newRef, repo, target, name); - AssertReflogEntryIsCreated( - repo.Refs.Log(newRef), - newRef.ResolveToDirectReference().Target.Sha, - logMessage, - ObjectId.Zero.Sha); + AssertRefLogEntry(repo, name, + newRef.ResolveToDirectReference().Target.Id, + logMessage); } } @@ -150,6 +150,8 @@ public void CanAddAndOverwriteADirectReference() string path = CloneBareTestRepo(); using (var repo = new Repository(path)) { + EnableRefLog(repo); + var newRef = (DirectReference)repo.Refs.Add(name, target, true, logMessage); Assert.NotNull(newRef); Assert.Equal(name, newRef.CanonicalName); @@ -157,11 +159,9 @@ public void CanAddAndOverwriteADirectReference() Assert.Equal(target, newRef.Target.Sha); Assert.Equal(target, ((DirectReference)repo.Refs[name]).Target.Sha); - AssertReflogEntryIsCreated( - repo.Refs.Log(newRef), - newRef.ResolveToDirectReference().Target.Sha, - logMessage, - ObjectId.Zero.Sha); + AssertRefLogEntry(repo, name, + newRef.ResolveToDirectReference().Target.Id, + logMessage); } } @@ -175,6 +175,8 @@ public void CanAddAndOverwriteASymbolicReference() string path = CloneBareTestRepo(); using (var repo = new Repository(path)) { + EnableRefLog(repo); + var newRef = (SymbolicReference)repo.Refs.Add(name, target, true, logMessage); Assert.NotNull(newRef); Assert.Equal(name, newRef.CanonicalName); @@ -182,11 +184,9 @@ public void CanAddAndOverwriteASymbolicReference() Assert.Equal("a4a7dce85cf63874e984719f4fdd239f5145052f", newRef.ResolveToDirectReference().Target.Sha); Assert.Equal(target, ((SymbolicReference)repo.Refs.Head).Target.CanonicalName); - AssertReflogEntryIsCreated( - repo.Refs.Log(newRef), - newRef.ResolveToDirectReference().Target.Sha, - logMessage, - ObjectId.Zero.Sha); + AssertRefLogEntry(repo, name, + newRef.ResolveToDirectReference().Target.Id, + logMessage); } } @@ -481,6 +481,8 @@ public void CanUpdateHeadWithEitherAnObjectIdOrAReference() string path = CloneBareTestRepo(); using (var repo = new Repository(path)) { + EnableRefLog(repo); + Reference head = repo.Refs.Head; Reference test = repo.Refs["refs/heads/test"]; @@ -490,11 +492,10 @@ public void CanUpdateHeadWithEitherAnObjectIdOrAReference() Assert.Equal(test.TargetIdentifier, direct.TargetIdentifier); Assert.Equal(repo.Refs.Head, direct); - String testTargetSha = test.ResolveToDirectReference().Target.Sha; - AssertReflogEntryIsCreated( - repo.Refs.Log(repo.Refs.Head), - testTargetSha, - firstLogMessage); + var testTargetId = test.ResolveToDirectReference().Target.Id; + AssertRefLogEntry(repo, "HEAD", + testTargetId, + firstLogMessage); const string secondLogMessage = "second update target message"; Reference symref = repo.Refs.UpdateTarget(head, test, secondLogMessage); @@ -502,11 +503,10 @@ public void CanUpdateHeadWithEitherAnObjectIdOrAReference() Assert.Equal(test.CanonicalName, symref.TargetIdentifier); Assert.Equal(repo.Refs.Head, symref); - AssertReflogEntryIsCreated( - repo.Refs.Log(repo.Refs.Head), - testTargetSha, - secondLogMessage, - testTargetSha); + AssertRefLogEntry(repo, "HEAD", + testTargetId, + secondLogMessage, + testTargetId); } } @@ -516,6 +516,8 @@ public void CanUpdateTargetOfADirectReferenceWithARevparseSpec() string path = CloneBareTestRepo(); using (var repo = new Repository(path)) { + EnableRefLog(repo); + const string name = "refs/heads/master"; var master = (DirectReference) repo.Refs[name]; @@ -529,10 +531,9 @@ public void CanUpdateTargetOfADirectReferenceWithARevparseSpec() Assert.Equal(newRef.Target.Sha, newRef.TargetIdentifier); Assert.NotNull(repo.Refs[name]); - AssertReflogEntryIsCreated( - repo.Refs.Log(master), - newRef.Target.Sha, - logMessage); + AssertRefLogEntry(repo, name, + newRef.Target.Id, + logMessage); } } diff --git a/LibGit2Sharp.Tests/ReflogFixture.cs b/LibGit2Sharp.Tests/ReflogFixture.cs index 7f4093bea..b73333fc7 100644 --- a/LibGit2Sharp.Tests/ReflogFixture.cs +++ b/LibGit2Sharp.Tests/ReflogFixture.cs @@ -1,6 +1,8 @@ -using System.Linq; +using System.IO; +using System.Linq; using LibGit2Sharp.Tests.TestHelpers; using Xunit; +using Xunit.Extensions; namespace LibGit2Sharp.Tests { @@ -126,5 +128,35 @@ public void CommitOnDetachedHeadShouldInsertReflogEntry() Assert.Equal(string.Format("commit: {0}", commitMessage), repo.Refs.Log("HEAD").First().Message); } } + + [Theory] + [InlineData(false, null, true)] + [InlineData(false, false, false)] + [InlineData(false, true, true)] + [InlineData(true, null, false)] + [InlineData(true, false, false)] + [InlineData(true, true, true)] + public void AppendingToReflogDependsOnCoreLogAllRefUpdatesSetting(bool isBare, bool? setting, bool expectAppend) + { + var repoPath = InitNewRepository(isBare); + + using (var repo = new Repository(repoPath)) + { + if (setting != null) + { + EnableRefLog(repo, setting.Value); + } + + var blob = repo.ObjectDatabase.CreateBlob(Stream.Null); + var tree = repo.ObjectDatabase.CreateTree(new TreeDefinition().Add("yoink", blob, Mode.NonExecutableFile)); + var commit = repo.ObjectDatabase.CreateCommit("yoink", Constants.Signature, Constants.Signature, + tree, Enumerable.Empty()); + + var branch = repo.CreateBranch("yoink", commit); + var log = repo.Refs.Log(branch.CanonicalName); + + Assert.Equal(expectAppend ? 1 : 0, log.Count()); + } + } } } diff --git a/LibGit2Sharp.Tests/ResetHeadFixture.cs b/LibGit2Sharp.Tests/ResetHeadFixture.cs index e6c8e88d5..641c6b483 100644 --- a/LibGit2Sharp.Tests/ResetHeadFixture.cs +++ b/LibGit2Sharp.Tests/ResetHeadFixture.cs @@ -102,7 +102,7 @@ private void AssertSoftReset(Func branchIdentifierRetriever, boo string branchIdentifier = branchIdentifierRetriever(branch); repo.Checkout(branchIdentifier); - var oldHeadSha = repo.Head.Tip.Sha; + var oldHeadId = repo.Head.Tip.Id; Assert.Equal(shouldHeadBeDetached, repo.Info.IsHeadDetached); string expectedHeadName = expectedHeadNameRetriever(branch); @@ -116,7 +116,10 @@ private void AssertSoftReset(Func branchIdentifierRetriever, boo Assert.Equal(FileStatus.Staged, repo.Index.RetrieveStatus("a.txt")); - AssertReflogEntryIsCreated(repo.Refs.Log(repo.Refs.Head), tag.Target.Sha, string.Format("reset: moving to {0}", tag.Target.Sha), oldHeadSha); + AssertRefLogEntry(repo, "HEAD", + tag.Target.Id, + string.Format("reset: moving to {0}", tag.Target.Sha), + oldHeadId); /* Reset --soft the Head to a commit through its sha */ repo.Reset(ResetOptions.Soft, branch.Tip.Sha); @@ -125,7 +128,10 @@ private void AssertSoftReset(Func branchIdentifierRetriever, boo Assert.Equal(FileStatus.Unaltered, repo.Index.RetrieveStatus("a.txt")); - AssertReflogEntryIsCreated(repo.Refs.Log(repo.Refs.Head), branch.Tip.Sha, string.Format("reset: moving to {0}", branch.Tip.Sha), tag.Target.Sha); + AssertRefLogEntry(repo, "HEAD", + branch.Tip.Id, + string.Format("reset: moving to {0}", branch.Tip.Sha), + tag.Target.Id); } } @@ -157,14 +163,18 @@ public void MixedResetRefreshesTheIndex() { FeedTheRepository(repo); + var oldHeadId = repo.Head.Tip.Id; + Tag tag = repo.Tags["mytag"]; repo.Reset(ResetOptions.Mixed, tag.CanonicalName); Assert.Equal(FileStatus.Modified, repo.Index.RetrieveStatus("a.txt")); - AssertReflogEntryIsCreated(repo.Refs.Log(repo.Refs.Head), tag.Target.Sha, string.Format("reset: moving to {0}", tag.Target.Sha)); - + AssertRefLogEntry(repo, "HEAD", + tag.Target.Id, + string.Format("reset: moving to {0}", tag.Target.Sha), + oldHeadId); } } diff --git a/LibGit2Sharp.Tests/ResetIndexFixture.cs b/LibGit2Sharp.Tests/ResetIndexFixture.cs index 0232ae0c7..121da8c74 100644 --- a/LibGit2Sharp.Tests/ResetIndexFixture.cs +++ b/LibGit2Sharp.Tests/ResetIndexFixture.cs @@ -80,7 +80,7 @@ public void ResetTheIndexWithTheHeadUnstagesEverything() } [Fact] - public void CanResetTheIndexToTheContentOfACommitWithCommitishAsArgument() + public void CanResetTheIndexToTheContentOfACommitWithCommittishAsArgument() { string path = CloneStandardTestRepo(); using (var repo = new Repository(path)) @@ -116,7 +116,7 @@ public void CanResetTheIndexToTheContentOfACommitWithCommitAsArgument() } [Fact] - public void CanResetTheIndexToASubsetOfTheContentOfACommitWithCommitishAsArgument() + public void CanResetTheIndexToASubsetOfTheContentOfACommitWithCommittishAsArgument() { string path = CloneStandardTestRepo(); using (var repo = new Repository(path)) diff --git a/LibGit2Sharp.Tests/TestHelpers/BaseFixture.cs b/LibGit2Sharp.Tests/TestHelpers/BaseFixture.cs index 1fb023e74..1a7d42d00 100644 --- a/LibGit2Sharp.Tests/TestHelpers/BaseFixture.cs +++ b/LibGit2Sharp.Tests/TestHelpers/BaseFixture.cs @@ -231,22 +231,6 @@ protected static string Touch(string parent, string file, string content = null, return filePath; } - protected static void AssertReflogEntryIsCreated(IEnumerable reflog, string targetSha, - string logMessage, string fromSha = null) - { - var reflogEntry = reflog.First(); - - if (!string.IsNullOrEmpty(fromSha)) - { - Assert.Equal(fromSha, reflogEntry.From.Sha); - } - - Assert.Equal(targetSha, reflogEntry.To.Sha); - Assert.NotNull(reflogEntry.Commiter.Email); - Assert.NotNull(reflogEntry.Commiter.Name); - Assert.Equal(logMessage, reflogEntry.Message); - } - protected string Expected(string filename) { return File.ReadAllText(Path.Combine(ResourcesDirectory.FullName, "expected/" + filename)); @@ -256,5 +240,31 @@ protected string Expected(string filenameFormat, params object[] args) { return Expected(string.Format(CultureInfo.InvariantCulture, filenameFormat, args)); } + + protected static void AssertRefLogEntry(Repository repo, string canonicalName, + ObjectId to, string message, ObjectId @from = null, + Signature committer = null) + { + var reflogEntry = repo.Refs.Log(canonicalName).First(); + + Assert.Equal(to, reflogEntry.To); + Assert.Equal(message, reflogEntry.Message); + Assert.Equal(@from ?? ObjectId.Zero, reflogEntry.From); + + if (committer == null) + { + Assert.NotNull(reflogEntry.Commiter.Email); + Assert.NotNull(reflogEntry.Commiter.Name); + } + else + { + Assert.Equal(committer, reflogEntry.Commiter); + } + } + + protected static void EnableRefLog(Repository repository, bool enable = true) + { + repository.Config.Set("core.logAllRefUpdates", enable); + } } } diff --git a/LibGit2Sharp/BranchCollection.cs b/LibGit2Sharp/BranchCollection.cs index 611a3e0e7..575bc2b59 100644 --- a/LibGit2Sharp/BranchCollection.cs +++ b/LibGit2Sharp/BranchCollection.cs @@ -119,9 +119,18 @@ public virtual Branch Add(string name, Commit commit, bool allowOverwrite = fals Ensure.ArgumentNotNullOrEmptyString(name, "name"); Ensure.ArgumentNotNull(commit, "commit"); + return Add(name, commit, allowOverwrite, "branch: Created from " + commit.Id); + } + + internal Branch Add(string name, Commit commit, bool allowOverwrite, string logMessage) + { + Ensure.ArgumentNotNull(commit, "commit"); + using (Proxy.git_branch_create(repo.Handle, name, commit.Id, allowOverwrite)) {} - return this[ShortToLocalName(name)]; + var branch = this[ShortToLocalName(name)]; + LogBranch(branch, logMessage); + return branch; } /// @@ -164,7 +173,9 @@ public virtual Branch Move(Branch branch, string newName, bool allowOverwrite = } } - return this[newName]; + var newBranch = this[newName]; + LogBranch(newBranch, "Branch: renamed " + branch.CanonicalName + " to " + newBranch.CanonicalName); + return newBranch; } /// @@ -215,5 +226,15 @@ private string DebuggerDisplay "Count = {0}", this.Count()); } } + + private void LogBranch(Branch branch, string logMessage) + { + if (string.IsNullOrEmpty(logMessage)) + { + return; + } + + repo.Refs.Log(branch.CanonicalName).Append(branch.Tip.Id, logMessage, branch.Tip.Committer); + } } } diff --git a/LibGit2Sharp/BranchCollectionExtensions.cs b/LibGit2Sharp/BranchCollectionExtensions.cs index 6459c7385..070614300 100644 --- a/LibGit2Sharp/BranchCollectionExtensions.cs +++ b/LibGit2Sharp/BranchCollectionExtensions.cs @@ -22,7 +22,13 @@ public static Branch Add(this BranchCollection branches, string name, string com var commit = branches.repo.LookupCommit(committish); - return branches.Add(name, commit, allowOverwrite); + var createdFrom = committish != "HEAD" + ? committish + : branches.repo.Info.IsHeadDetached + ? commit.Sha + : branches.repo.Head.Name; + + return branches.Add(name, commit, allowOverwrite, "branch: Created from " + createdFrom); } /// diff --git a/LibGit2Sharp/ConfigurationExtensions.cs b/LibGit2Sharp/ConfigurationExtensions.cs index a84a7f9df..6aa676b72 100644 --- a/LibGit2Sharp/ConfigurationExtensions.cs +++ b/LibGit2Sharp/ConfigurationExtensions.cs @@ -1,3 +1,4 @@ +using System; using LibGit2Sharp.Core; namespace LibGit2Sharp @@ -66,5 +67,141 @@ public static ConfigurationEntry Get(this Configuration config, string fir return config.Get(new[] { firstKeyPart, secondKeyPart, thirdKeyPart }); } + + /// + /// Get a configuration value for the given key, + /// or if the key is not set. + /// + /// The configuration value type. + /// The configuration being worked with. + /// The key + /// The default value if the key is not set. + /// The configuration value, or the default. + public static T GetValueOrDefault(this Configuration config, string key, T defaultValue = default(T)) + { + return ValueOrDefault(config.Get(key), defaultValue); + } + + /// + /// Get a configuration value for the given key, + /// or if the key is not set. + /// + /// The configuration value type. + /// The configuration being worked with. + /// The key. + /// The configuration file into which the key should be searched for. + /// The selector used to generate a default value if the key is not set. + /// The configuration value, or the default. + public static T GetValueOrDefault(this Configuration config, string key, ConfigurationLevel level, T defaultValue = default(T)) + { + return ValueOrDefault(config.Get(key, level), defaultValue); + } + + /// + /// Get a configuration value for the given key parts, + /// or if the key is not set. + /// + /// The configuration value type. + /// The configuration being worked with. + /// The key parts. + /// The default value if the key is not set. + /// The configuration value, or the default. + public static T GetValueOrDefault(this Configuration config, string[] keyParts, T defaultValue = default(T)) + { + return ValueOrDefault(config.Get(keyParts), defaultValue); + } + + /// + /// Get a configuration value for the given key parts, + /// or if the key is not set. + /// + /// The configuration value type. + /// The configuration being worked with. + /// The first key part. + /// The second key part. + /// The third key part. + /// The default value if the key is not set. + /// The configuration value, or the default. + public static T GetValueOrDefault(this Configuration config, string firstKeyPart, string secondKeyPart, string thirdKeyPart, T defaultValue = default(T)) + { + return ValueOrDefault(config.Get(firstKeyPart, secondKeyPart, thirdKeyPart), defaultValue); + } + + /// + /// Get a configuration value for the given key, + /// or a value generated by + /// if the key is not set. + /// + /// The configuration value type. + /// The configuration being worked with. + /// The key + /// The selector used to generate a default value if the key is not set. + /// The configuration value, or a generated default. + public static T GetValueOrDefault(this Configuration config, string key, Func defaultValueSelector) + { + return ValueOrDefault(config.Get(key), defaultValueSelector); + } + + /// + /// Get a configuration value for the given key, + /// or a value generated by + /// if the key is not set. + /// + /// The configuration value type. + /// The configuration being worked with. + /// The key. + /// The configuration file into which the key should be searched for. + /// The selector used to generate a default value if the key is not set. + /// The configuration value, or a generated default. + public static T GetValueOrDefault(this Configuration config, string key, ConfigurationLevel level, Func defaultValueSelector) + { + return ValueOrDefault(config.Get(key, level), defaultValueSelector); + } + + /// + /// Get a configuration value for the given key parts, + /// or a value generated by + /// if the key is not set. + /// + /// The configuration value type. + /// The configuration being worked with. + /// The key parts. + /// The selector used to generate a default value if the key is not set. + /// The configuration value, or a generated default. + public static T GetValueOrDefault(this Configuration config, string[] keyParts, Func defaultValueSelector) + { + return ValueOrDefault(config.Get(keyParts), defaultValueSelector); + } + + /// + /// Get a configuration value for the given key parts, + /// or a value generated by + /// if the key is not set. + /// + /// The configuration value type. + /// The configuration being worked with. + /// The first key part. + /// The second key part. + /// The third key part. + /// The selector used to generate a default value if the key is not set. + /// The configuration value, or a generated default. + public static T GetValueOrDefault(this Configuration config, string firstKeyPart, string secondKeyPart, string thirdKeyPart, Func defaultValueSelector) + { + return ValueOrDefault(config.Get(firstKeyPart, secondKeyPart, thirdKeyPart), defaultValueSelector); + } + + private static T ValueOrDefault(ConfigurationEntry value, T defaultValue) + { + return value == null ? defaultValue : value.Value; + } + + private static T ValueOrDefault(ConfigurationEntry value, Func defaultValueSelector) + { + Ensure.ArgumentNotNull(defaultValueSelector, "defaultValueSelector"); + + return value == null + ? defaultValueSelector() + : value.Value; + } } } diff --git a/LibGit2Sharp/ReflogCollection.cs b/LibGit2Sharp/ReflogCollection.cs index f9f9516b5..03c178cc4 100644 --- a/LibGit2Sharp/ReflogCollection.cs +++ b/LibGit2Sharp/ReflogCollection.cs @@ -97,6 +97,12 @@ private string DebuggerDisplay /// of the comitter. internal virtual void Append(ObjectId target, string reflogMessage, Signature committer) { + var logAllRefUpdates = repo.Config.GetValueOrDefault("core.logAllRefUpdates", false); + if (!logAllRefUpdates) + { + return; + } + using (ReferenceSafeHandle reference = Proxy.git_reference_lookup(repo.Handle, canonicalName, true)) using (ReflogSafeHandle reflog = Proxy.git_reflog_read(reference)) { diff --git a/LibGit2Sharp/RepositoryExtensions.cs b/LibGit2Sharp/RepositoryExtensions.cs index a1c8461a5..f00e69719 100644 --- a/LibGit2Sharp/RepositoryExtensions.cs +++ b/LibGit2Sharp/RepositoryExtensions.cs @@ -113,7 +113,7 @@ public static Tag ApplyTag(this IRepository repository, string tagName, string o /// The name of the branch to create. public static Branch CreateBranch(this IRepository repository, string branchName) { - return CreateBranch(repository, branchName, repository.Head.Tip); + return CreateBranch(repository, branchName, "HEAD"); } /// diff --git a/LibGit2Sharp/Signature.cs b/LibGit2Sharp/Signature.cs index 0827698e1..ae3566961 100644 --- a/LibGit2Sharp/Signature.cs +++ b/LibGit2Sharp/Signature.cs @@ -119,5 +119,14 @@ public override int GetHashCode() { return !Equals(left, right); } + + /// + /// Returns " <>" for the current . + /// + /// The and of the current . + public override string ToString() + { + return string.Format("{0} <{1}>", Name, Email); + } } }