From 0148ecad4fc6d38a5a484a5839402bc092cff1d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Mart=C3=ADn=20Nieto?= Date: Mon, 7 Mar 2016 13:03:05 +0100 Subject: [PATCH 1/4] Remove the code we have just for mocking We make the constructors internal but then make sure we cave constructors with zero arity so mocking them via e.g. Moq is easier. With this we're making out code harder to mock, but then add ways to add another layer of mocking easier. We enforce this constructors for mocking in the tests, without regard for whether they make sense or not. Often it would make a lot more sense to expose a public constructor for types so an application can return fake results. --- LibGit2Sharp.Tests/EqualityFixture.cs | 9 +- LibGit2Sharp.Tests/LibGit2Sharp.Tests.csproj | 4 - LibGit2Sharp.Tests/MetaFixture.cs | 73 ------------ LibGit2Sharp.Tests/MockingFixture.cs | 110 ------------------- LibGit2Sharp.Tests/packages.config | 4 +- LibGit2Sharp/AfterRebaseStepInfo.cs | 6 - LibGit2Sharp/BeforeRebaseStepInfo.cs | 6 - LibGit2Sharp/BlameHunk.cs | 6 - LibGit2Sharp/BlameHunkCollection.cs | 5 - LibGit2Sharp/Blob.cs | 6 - LibGit2Sharp/Branch.cs | 6 - LibGit2Sharp/BranchCollection.cs | 6 - LibGit2Sharp/BranchTrackingDetails.cs | 6 - LibGit2Sharp/BranchUpdater.cs | 6 - LibGit2Sharp/CertificateSsh.cs | 6 - LibGit2Sharp/CertificateX509.cs | 7 -- LibGit2Sharp/CherryPickResult.cs | 6 - LibGit2Sharp/Commit.cs | 6 - LibGit2Sharp/Configuration.cs | 6 - LibGit2Sharp/ConfigurationEntry.cs | 6 - LibGit2Sharp/Conflict.cs | 6 - LibGit2Sharp/ConflictCollection.cs | 6 - LibGit2Sharp/ContentChangeStats.cs | 6 - LibGit2Sharp/ContentChanges.cs | 6 - LibGit2Sharp/Diff.cs | 6 - LibGit2Sharp/DirectReference.cs | 6 - LibGit2Sharp/FetchHead.cs | 6 - LibGit2Sharp/FilterSource.cs | 5 - LibGit2Sharp/GitLink.cs | 6 - LibGit2Sharp/GitObject.cs | 6 - LibGit2Sharp/HistoryDivergence.cs | 5 +- LibGit2Sharp/Ignore.cs | 6 - LibGit2Sharp/Index.cs | 6 - LibGit2Sharp/IndexNameEntry.cs | 6 - LibGit2Sharp/IndexNameEntryCollection.cs | 6 - LibGit2Sharp/IndexReucEntry.cs | 6 - LibGit2Sharp/IndexReucEntryCollection.cs | 6 - LibGit2Sharp/MergeHead.cs | 6 - LibGit2Sharp/MergeResult.cs | 6 - LibGit2Sharp/MergeTreeResult.cs | 6 - LibGit2Sharp/Network.cs | 6 - LibGit2Sharp/Note.cs | 6 - LibGit2Sharp/NoteCollection.cs | 6 - LibGit2Sharp/ObjectDatabase.cs | 6 - LibGit2Sharp/OdbBackendStream.cs | 9 -- LibGit2Sharp/Patch.cs | 6 - LibGit2Sharp/PatchEntryChanges.cs | 6 - LibGit2Sharp/PatchStats.cs | 6 - LibGit2Sharp/PushResult.cs | 6 - LibGit2Sharp/PushStatusError.cs | 6 - LibGit2Sharp/Rebase.cs | 6 - LibGit2Sharp/RebaseResult.cs | 6 - LibGit2Sharp/RebaseStepInfo.cs | 6 - LibGit2Sharp/RefSpec.cs | 6 - LibGit2Sharp/RefSpecCollection.cs | 6 - LibGit2Sharp/Reference.cs | 6 - LibGit2Sharp/ReferenceCollection.cs | 6 - LibGit2Sharp/ReferenceWrapper.cs | 6 - LibGit2Sharp/ReflogCollection.cs | 6 - LibGit2Sharp/ReflogEntry.cs | 6 - LibGit2Sharp/Remote.cs | 6 - LibGit2Sharp/RemoteCollection.cs | 6 - LibGit2Sharp/RemoteUpdater.cs | 6 - LibGit2Sharp/RenameDetails.cs | 6 - LibGit2Sharp/RepositoryInformation.cs | 6 - LibGit2Sharp/RepositoryOperationContext.cs | 6 - LibGit2Sharp/RepositoryStatus.cs | 6 - LibGit2Sharp/RevertResult.cs | 6 - LibGit2Sharp/SmartSubtransportStream.cs | 9 -- LibGit2Sharp/Stash.cs | 6 - LibGit2Sharp/StashCollection.cs | 6 - LibGit2Sharp/StatusEntry.cs | 6 - LibGit2Sharp/Submodule.cs | 6 - LibGit2Sharp/SubmoduleCollection.cs | 6 - LibGit2Sharp/SymbolicReference.cs | 6 - LibGit2Sharp/Tag.cs | 6 - LibGit2Sharp/TagAnnotation.cs | 6 - LibGit2Sharp/TagCollection.cs | 6 - LibGit2Sharp/Tree.cs | 6 - LibGit2Sharp/TreeChanges.cs | 6 - LibGit2Sharp/TreeEntry.cs | 6 - LibGit2Sharp/TreeEntryChanges.cs | 6 - LibGit2Sharp/TreeEntryDefinition.cs | 6 - LibGit2Sharp/Version.cs | 6 - 84 files changed, 3 insertions(+), 675 deletions(-) delete mode 100644 LibGit2Sharp.Tests/MockingFixture.cs diff --git a/LibGit2Sharp.Tests/EqualityFixture.cs b/LibGit2Sharp.Tests/EqualityFixture.cs index 168d5fb99..a671a822c 100644 --- a/LibGit2Sharp.Tests/EqualityFixture.cs +++ b/LibGit2Sharp.Tests/EqualityFixture.cs @@ -36,16 +36,9 @@ public void EqualityHelperCanTestNullInHashCode() private class ObjectWithEquality : GitObject { - private readonly ObjectId id; - public ObjectWithEquality(ObjectId id = null) + : base(null, id) { - this.id = id; - } - - public override ObjectId Id - { - get { return id; } } } } diff --git a/LibGit2Sharp.Tests/LibGit2Sharp.Tests.csproj b/LibGit2Sharp.Tests/LibGit2Sharp.Tests.csproj index 0be3440c6..c01f4cc6d 100644 --- a/LibGit2Sharp.Tests/LibGit2Sharp.Tests.csproj +++ b/LibGit2Sharp.Tests/LibGit2Sharp.Tests.csproj @@ -35,9 +35,6 @@ true - - ..\packages\Moq.4.2.1507.0118\lib\net40\Moq.dll - @@ -89,7 +86,6 @@ - diff --git a/LibGit2Sharp.Tests/MetaFixture.cs b/LibGit2Sharp.Tests/MetaFixture.cs index 057c9a1d4..e2fb36f2f 100644 --- a/LibGit2Sharp.Tests/MetaFixture.cs +++ b/LibGit2Sharp.Tests/MetaFixture.cs @@ -9,7 +9,6 @@ using LibGit2Sharp.Tests.TestHelpers; using Xunit; using Xunit.Extensions; -using Moq; namespace LibGit2Sharp.Tests { @@ -83,78 +82,6 @@ public void TypesInLibGit2DecoratedWithDebuggerDisplayMustFollowTheStandardImplP } } - // Related to https://github.com/libgit2/libgit2sharp/pull/185 - [Fact] - public void TypesInLibGit2SharpMustBeExtensibleInATestingContext() - { - var nonTestableTypes = new Dictionary>(); - - IEnumerable libGit2SharpTypes = Assembly.GetAssembly(typeof(IRepository)).GetExportedTypes() - .Where(t => MustBeMockable(t) && t.Namespace == typeof(IRepository).Namespace); - - foreach (Type type in libGit2SharpTypes) - { - if (type.IsInterface || type.IsEnum || IsStatic(type)) - continue; - - var nonVirtualMethodNamesForType = GetNonVirtualPublicMethodsNames(type).ToList(); - if (nonVirtualMethodNamesForType.Any()) - { - nonTestableTypes.Add(type, nonVirtualMethodNamesForType); - continue; - } - - if (!HasEmptyPublicOrProtectedConstructor(type)) - { - nonTestableTypes.Add(type, new List()); - } - - if (type.IsAbstract) - { - continue; - } - - try - { - if (type.ContainsGenericParameters) - { - var constructType = type.MakeGenericType(Enumerable.Repeat(typeof(object), type.GetGenericArguments().Length).ToArray()); - Activator.CreateInstance(constructType, true); - } - else - { - Activator.CreateInstance(type, true); - } - } - catch - { - nonTestableTypes.Add(type, new List()); - } - } - - if (nonTestableTypes.Any()) - { - Assert.True(false, Environment.NewLine + BuildNonTestableTypesMessage(nonTestableTypes)); - } - } - - private static bool MustBeMockable(Type type) - { - if (type.IsSealed) - { - return false; - } - - if (type.IsAbstract) - { - return !type.Assembly.GetExportedTypes() - .Where(t => t.IsSubclassOf(type)) - .All(t => t.IsAbstract || t.IsSealed); - } - - return true; - } - [Fact] public void LibGit2SharpPublicInterfacesCoverAllPublicMembers() { diff --git a/LibGit2Sharp.Tests/MockingFixture.cs b/LibGit2Sharp.Tests/MockingFixture.cs deleted file mode 100644 index 6db7dc645..000000000 --- a/LibGit2Sharp.Tests/MockingFixture.cs +++ /dev/null @@ -1,110 +0,0 @@ -using System; -using System.Collections.Generic; -using System.Linq; -using LibGit2Sharp.Tests.TestHelpers; -using Moq; -using Xunit; - -namespace LibGit2Sharp.Tests -{ - // This fixture shows how one can mock various LibGit2Sharp APIs. - public class MockingFixture : BaseFixture - { - // The application we want to test is simulated by the CommitCounter class (see below), which takes an IRepository, - // and whose role is to compute and return the number of commits in the given repository. - - // In this test, we pass to CommitCounter a concrete instance of the Repository. It means we will end up calling the concrete Repository - // during the test run. - [Fact] - public void CanCountCommitsWithConcreteRepository() - { - string path = SandboxBareTestRepo(); - using (var repo = new Repository(path)) - { - var commitCounter = new CommitCounter(repo); - Assert.Equal(7, commitCounter.NumberOfCommits); - } - } - - // This test shows that CommitCounter can take a mocked instance of IRepository. It means we can test CommitCounter without - // relying on the concrete repository. We are testing CommitCounter in isolation. - [Fact] - public void CanCountCommitsWithMockedRepository() - { - var commitLog = Mock.Of(cl => cl.GetEnumerator() == FakeCommitLog(17)); - var repo = Mock.Of(r => r.Commits == commitLog); - - var commitCounter = new CommitCounter(repo); - Assert.Equal(17, commitCounter.NumberOfCommits); - } - - private static IEnumerator FakeCommitLog(int size) - { - for (int i = 0; i < size; i++) - { - yield return FakeCommit(Guid.NewGuid().ToString()); - } - } - - private static Commit FakeCommit(string sha) - { - var commitMock = new Mock(); - commitMock.SetupGet(x => x.Sha).Returns(sha); - - return commitMock.Object; - } - - // Simulated external application ;) - private class CommitCounter - { - private readonly IRepository repo; - - public CommitCounter(IRepository repo) - { - this.repo = repo; - } - - public int NumberOfCommits - { - get { return repo.Commits.Count(); } - } - } - - [Fact] - public void CanFakeConfigurationBuildSignature() - { - const string name = "name"; - const string email = "email"; - var now = DateTimeOffset.UtcNow; - - var fakeConfig = new Mock(); - fakeConfig.Setup(c => c.BuildSignature(now)) - .Returns(t => new Signature(name, email, t)); - - var sig = fakeConfig.Object.BuildSignature(now); - Assert.Equal(name, sig.Name); - Assert.Equal(email, sig.Email); - Assert.Equal(now, sig.When); - } - - [Fact] - public void CanFakeEnumerationOfConfiguration() - { - var fakeConfig = new Mock(); - fakeConfig.Setup(c => c.GetEnumerator()).Returns(FakeEntries); - - Assert.Equal(2, fakeConfig.Object.Count()); - } - - private static IEnumerator> FakeEntries() - { - yield return FakeConfigurationEntry("foo", "bar", ConfigurationLevel.Local); - yield return FakeConfigurationEntry("baz", "quux", ConfigurationLevel.Global); - } - - private static ConfigurationEntry FakeConfigurationEntry(string key, string value, ConfigurationLevel level) - { - return new Mock>(key, value, level).Object; - } - } -} diff --git a/LibGit2Sharp.Tests/packages.config b/LibGit2Sharp.Tests/packages.config index 532dff7af..df97e2e87 100644 --- a/LibGit2Sharp.Tests/packages.config +++ b/LibGit2Sharp.Tests/packages.config @@ -1,7 +1,5 @@  - - - + diff --git a/LibGit2Sharp/AfterRebaseStepInfo.cs b/LibGit2Sharp/AfterRebaseStepInfo.cs index 8e6e78e2d..f80430198 100644 --- a/LibGit2Sharp/AfterRebaseStepInfo.cs +++ b/LibGit2Sharp/AfterRebaseStepInfo.cs @@ -5,12 +5,6 @@ /// public class AfterRebaseStepInfo { - /// - /// Needed for mocking. - /// - protected AfterRebaseStepInfo() - { } - internal AfterRebaseStepInfo(RebaseStepInfo stepInfo, Commit commit, long completedStepIndex, long totalStepCount) { StepInfo = stepInfo; diff --git a/LibGit2Sharp/BeforeRebaseStepInfo.cs b/LibGit2Sharp/BeforeRebaseStepInfo.cs index e01175c08..4f99ae91d 100644 --- a/LibGit2Sharp/BeforeRebaseStepInfo.cs +++ b/LibGit2Sharp/BeforeRebaseStepInfo.cs @@ -10,12 +10,6 @@ namespace LibGit2Sharp /// public class BeforeRebaseStepInfo { - /// - /// Needed for mocking. - /// - protected BeforeRebaseStepInfo() - { } - internal BeforeRebaseStepInfo(RebaseStepInfo stepInfo, long stepIndex, long totalStepCount) { StepInfo = stepInfo; diff --git a/LibGit2Sharp/BlameHunk.cs b/LibGit2Sharp/BlameHunk.cs index 7f05a0b30..14d2cf2bb 100644 --- a/LibGit2Sharp/BlameHunk.cs +++ b/LibGit2Sharp/BlameHunk.cs @@ -47,12 +47,6 @@ internal BlameHunk(IRepository repository, GitBlameHunk rawHunk) } } - /// - /// For easier mocking - /// - protected BlameHunk() - { } - /// /// Determine if this hunk contains a given line. /// diff --git a/LibGit2Sharp/BlameHunkCollection.cs b/LibGit2Sharp/BlameHunkCollection.cs index ef647eb37..4071bc160 100644 --- a/LibGit2Sharp/BlameHunkCollection.cs +++ b/LibGit2Sharp/BlameHunkCollection.cs @@ -15,11 +15,6 @@ public class BlameHunkCollection : IEnumerable private readonly IRepository repo; private readonly List hunks = new List(); - /// - /// For easy mocking - /// - protected BlameHunkCollection() { } - internal BlameHunkCollection(Repository repo, RepositorySafeHandle repoHandle, string path, BlameOptions options) { this.repo = repo; diff --git a/LibGit2Sharp/Blob.cs b/LibGit2Sharp/Blob.cs index 9b14cb50f..e52c19b87 100644 --- a/LibGit2Sharp/Blob.cs +++ b/LibGit2Sharp/Blob.cs @@ -13,12 +13,6 @@ public class Blob : GitObject private readonly ILazy lazySize; private readonly ILazy lazyIsBinary; - /// - /// Needed for mocking purposes. - /// - protected Blob() - { } - internal Blob(Repository repo, ObjectId id) : base(repo, id) { diff --git a/LibGit2Sharp/Branch.cs b/LibGit2Sharp/Branch.cs index 31fe33d89..b3a32a135 100644 --- a/LibGit2Sharp/Branch.cs +++ b/LibGit2Sharp/Branch.cs @@ -11,12 +11,6 @@ public class Branch : ReferenceWrapper { private readonly Lazy trackedBranch; - /// - /// Needed for mocking purposes. - /// - protected Branch() - { } - /// /// Initializes a new instance of the class. /// diff --git a/LibGit2Sharp/BranchCollection.cs b/LibGit2Sharp/BranchCollection.cs index 803e28d00..e7d4ea0c9 100644 --- a/LibGit2Sharp/BranchCollection.cs +++ b/LibGit2Sharp/BranchCollection.cs @@ -17,12 +17,6 @@ public class BranchCollection : IEnumerable { internal readonly Repository repo; - /// - /// Needed for mocking purposes. - /// - protected BranchCollection() - { } - /// /// Initializes a new instance of the class. /// diff --git a/LibGit2Sharp/BranchTrackingDetails.cs b/LibGit2Sharp/BranchTrackingDetails.cs index e3d99bd45..f8721af66 100644 --- a/LibGit2Sharp/BranchTrackingDetails.cs +++ b/LibGit2Sharp/BranchTrackingDetails.cs @@ -7,12 +7,6 @@ public class BranchTrackingDetails { private readonly HistoryDivergence historyDivergence; - /// - /// Needed for mocking purposes. - /// - protected BranchTrackingDetails() - { } - internal BranchTrackingDetails(Repository repo, Branch branch) { if (!branch.IsTracking || branch.Tip == null || branch.TrackedBranch.Tip == null) diff --git a/LibGit2Sharp/BranchUpdater.cs b/LibGit2Sharp/BranchUpdater.cs index 032bf6cf3..b533da828 100644 --- a/LibGit2Sharp/BranchUpdater.cs +++ b/LibGit2Sharp/BranchUpdater.cs @@ -12,12 +12,6 @@ public class BranchUpdater private readonly Repository repo; private readonly Branch branch; - /// - /// Needed for mocking purposes. - /// - protected BranchUpdater() - { } - internal BranchUpdater(Repository repo, Branch branch) { Ensure.ArgumentNotNull(repo, "repo"); diff --git a/LibGit2Sharp/CertificateSsh.cs b/LibGit2Sharp/CertificateSsh.cs index 763a9f0b4..c0455f4a4 100644 --- a/LibGit2Sharp/CertificateSsh.cs +++ b/LibGit2Sharp/CertificateSsh.cs @@ -9,12 +9,6 @@ namespace LibGit2Sharp /// public class CertificateSsh : Certificate { - /// - /// For mocking purposes - /// - protected CertificateSsh() - { } - /// /// The MD5 hash of the host. Meaningful if is true /// diff --git a/LibGit2Sharp/CertificateX509.cs b/LibGit2Sharp/CertificateX509.cs index 8c65cfa68..3e646c6b7 100644 --- a/LibGit2Sharp/CertificateX509.cs +++ b/LibGit2Sharp/CertificateX509.cs @@ -10,13 +10,6 @@ namespace LibGit2Sharp /// public class CertificateX509 : Certificate { - - /// - /// For mocking purposes - /// - protected CertificateX509() - { } - /// /// The certificate. /// diff --git a/LibGit2Sharp/CherryPickResult.cs b/LibGit2Sharp/CherryPickResult.cs index 7e944baf7..772491005 100644 --- a/LibGit2Sharp/CherryPickResult.cs +++ b/LibGit2Sharp/CherryPickResult.cs @@ -5,12 +5,6 @@ /// public class CherryPickResult { - /// - /// Needed for mocking purposes. - /// - protected CherryPickResult() - { } - internal CherryPickResult(CherryPickStatus status, Commit commit = null) { Commit = commit; diff --git a/LibGit2Sharp/Commit.cs b/LibGit2Sharp/Commit.cs index ea7844477..6a4e47454 100644 --- a/LibGit2Sharp/Commit.cs +++ b/LibGit2Sharp/Commit.cs @@ -27,12 +27,6 @@ public class Commit : GitObject private readonly ParentsCollection parents; private readonly Lazy> lazyNotes; - /// - /// Needed for mocking purposes. - /// - protected Commit() - { } - internal Commit(Repository repo, ObjectId id) : base(repo, id) { diff --git a/LibGit2Sharp/Configuration.cs b/LibGit2Sharp/Configuration.cs index 5a2f2be18..82708970c 100644 --- a/LibGit2Sharp/Configuration.cs +++ b/LibGit2Sharp/Configuration.cs @@ -22,12 +22,6 @@ public class Configuration : IDisposable, private ConfigurationSafeHandle configHandle; - /// - /// Needed for mocking purposes. - /// - protected Configuration() - { } - internal Configuration( Repository repository, string repositoryConfigurationFileLocation, diff --git a/LibGit2Sharp/ConfigurationEntry.cs b/LibGit2Sharp/ConfigurationEntry.cs index 13c153a2a..fb08a09f8 100644 --- a/LibGit2Sharp/ConfigurationEntry.cs +++ b/LibGit2Sharp/ConfigurationEntry.cs @@ -25,12 +25,6 @@ public class ConfigurationEntry /// public virtual ConfigurationLevel Level { get; private set; } - /// - /// Needed for mocking purposes. - /// - protected ConfigurationEntry() - { } - /// /// Initializes a new instance of the class with a given key and value /// diff --git a/LibGit2Sharp/Conflict.cs b/LibGit2Sharp/Conflict.cs index 252535af1..bb96bd71a 100644 --- a/LibGit2Sharp/Conflict.cs +++ b/LibGit2Sharp/Conflict.cs @@ -20,12 +20,6 @@ public class Conflict : IEquatable private static readonly LambdaEqualityHelper equalityHelper = new LambdaEqualityHelper(x => x.Ancestor, x => x.Ours, x => x.Theirs); - /// - /// Needed for mocking purposes. - /// - protected Conflict() - { } - internal Conflict(IndexEntry ancestor, IndexEntry ours, IndexEntry theirs) { this.ancestor = ancestor; diff --git a/LibGit2Sharp/ConflictCollection.cs b/LibGit2Sharp/ConflictCollection.cs index 90d48fa33..56235898d 100644 --- a/LibGit2Sharp/ConflictCollection.cs +++ b/LibGit2Sharp/ConflictCollection.cs @@ -15,12 +15,6 @@ public class ConflictCollection : IEnumerable { private readonly Index index; - /// - /// Needed for mocking purposes. - /// - protected ConflictCollection() - { } - internal ConflictCollection(Index index) { this.index = index; diff --git a/LibGit2Sharp/ContentChangeStats.cs b/LibGit2Sharp/ContentChangeStats.cs index 8314888a0..133c0de3a 100644 --- a/LibGit2Sharp/ContentChangeStats.cs +++ b/LibGit2Sharp/ContentChangeStats.cs @@ -15,12 +15,6 @@ public class ContentChangeStats /// public virtual int LinesDeleted { get; private set; } - /// - /// For mocking. - /// - protected ContentChangeStats() - { } - internal ContentChangeStats(int added, int deleted) { LinesAdded = added; diff --git a/LibGit2Sharp/ContentChanges.cs b/LibGit2Sharp/ContentChanges.cs index dee15abee..a8b855dd3 100644 --- a/LibGit2Sharp/ContentChanges.cs +++ b/LibGit2Sharp/ContentChanges.cs @@ -14,12 +14,6 @@ public class ContentChanges { private readonly StringBuilder patchBuilder = new StringBuilder(); - /// - /// Needed for mocking purposes. - /// - protected ContentChanges() - { } - internal ContentChanges(Repository repo, Blob oldBlob, Blob newBlob, GitDiffOptions options) { Proxy.git_diff_blobs(repo.Handle, diff --git a/LibGit2Sharp/Diff.cs b/LibGit2Sharp/Diff.cs index 88c1fdcfc..89867a706 100644 --- a/LibGit2Sharp/Diff.cs +++ b/LibGit2Sharp/Diff.cs @@ -76,12 +76,6 @@ private static GitDiffOptions BuildOptions(DiffModifiers diffOptions, FilePath[] return options; } - /// - /// Needed for mocking purposes. - /// - protected Diff() - { } - internal Diff(Repository repo) { this.repo = repo; diff --git a/LibGit2Sharp/DirectReference.cs b/LibGit2Sharp/DirectReference.cs index b9cc304b3..97e37c936 100644 --- a/LibGit2Sharp/DirectReference.cs +++ b/LibGit2Sharp/DirectReference.cs @@ -9,12 +9,6 @@ public class DirectReference : Reference { private readonly Lazy targetBuilder; - /// - /// Needed for mocking purposes. - /// - protected DirectReference() - { } - internal DirectReference(string canonicalName, IRepository repo, ObjectId targetId) : base(repo, canonicalName, targetId.Sha) { diff --git a/LibGit2Sharp/FetchHead.cs b/LibGit2Sharp/FetchHead.cs index 456abedc2..31c4d3df0 100644 --- a/LibGit2Sharp/FetchHead.cs +++ b/LibGit2Sharp/FetchHead.cs @@ -9,12 +9,6 @@ namespace LibGit2Sharp /// internal class FetchHead : ReferenceWrapper { - /// - /// Needed for mocking purposes. - /// - protected FetchHead() - { } - internal FetchHead( Repository repo, string remoteCanonicalName, diff --git a/LibGit2Sharp/FilterSource.cs b/LibGit2Sharp/FilterSource.cs index 0843e6221..e3a08a550 100644 --- a/LibGit2Sharp/FilterSource.cs +++ b/LibGit2Sharp/FilterSource.cs @@ -8,11 +8,6 @@ namespace LibGit2Sharp /// public class FilterSource { - /// - /// Needed for mocking purposes - /// - protected FilterSource() { } - internal FilterSource(FilePath path, FilterMode mode, GitFilterSource source) { SourceMode = mode; diff --git a/LibGit2Sharp/GitLink.cs b/LibGit2Sharp/GitLink.cs index f03b1d719..0bf500859 100644 --- a/LibGit2Sharp/GitLink.cs +++ b/LibGit2Sharp/GitLink.cs @@ -8,12 +8,6 @@ namespace LibGit2Sharp [DebuggerDisplay("{DebuggerDisplay,nq}")] public class GitLink : GitObject { - /// - /// Needed for mocking purposes. - /// - protected GitLink() - { } - internal GitLink(Repository repo, ObjectId id) : base(repo, id) { } diff --git a/LibGit2Sharp/GitObject.cs b/LibGit2Sharp/GitObject.cs index e2653ca0f..d5c0b9df9 100644 --- a/LibGit2Sharp/GitObject.cs +++ b/LibGit2Sharp/GitObject.cs @@ -30,12 +30,6 @@ public abstract class GitObject : IEquatable, IBelongToARepository /// protected readonly Repository repo; - /// - /// Needed for mocking purposes. - /// - protected GitObject() - { } - /// /// Initializes a new instance of the class. /// diff --git a/LibGit2Sharp/HistoryDivergence.cs b/LibGit2Sharp/HistoryDivergence.cs index 262c09c15..bae55ede3 100644 --- a/LibGit2Sharp/HistoryDivergence.cs +++ b/LibGit2Sharp/HistoryDivergence.cs @@ -11,10 +11,7 @@ public class HistoryDivergence { private readonly Lazy commonAncestor; - /// - /// Needed for mocking purposes. - /// - protected HistoryDivergence() + internal HistoryDivergence() { } internal HistoryDivergence(Repository repo, Commit one, Commit another) diff --git a/LibGit2Sharp/Ignore.cs b/LibGit2Sharp/Ignore.cs index 63ec6b264..4a2957dc6 100644 --- a/LibGit2Sharp/Ignore.cs +++ b/LibGit2Sharp/Ignore.cs @@ -13,12 +13,6 @@ public class Ignore { private readonly Repository repo; - /// - /// Needed for mocking purposes. - /// - protected Ignore() - { } - internal Ignore(Repository repo) { this.repo = repo; diff --git a/LibGit2Sharp/Index.cs b/LibGit2Sharp/Index.cs index f63c91d7c..ac5423ede 100644 --- a/LibGit2Sharp/Index.cs +++ b/LibGit2Sharp/Index.cs @@ -19,12 +19,6 @@ public class Index : IEnumerable private readonly Repository repo; private readonly ConflictCollection conflicts; - /// - /// Needed for mocking purposes. - /// - protected Index() - { } - internal Index(Repository repo) { this.repo = repo; diff --git a/LibGit2Sharp/IndexNameEntry.cs b/LibGit2Sharp/IndexNameEntry.cs index 5ba24f9c3..c958ce230 100644 --- a/LibGit2Sharp/IndexNameEntry.cs +++ b/LibGit2Sharp/IndexNameEntry.cs @@ -16,12 +16,6 @@ public class IndexNameEntry : IEquatable private static readonly LambdaEqualityHelper equalityHelper = new LambdaEqualityHelper(x => x.Ancestor, x => x.Ours, x => x.Theirs); - /// - /// Needed for mocking purposes. - /// - protected IndexNameEntry() - { } - internal static IndexNameEntry BuildFromPtr(IndexNameEntrySafeHandle handle) { if (handle == null || handle.IsZero) diff --git a/LibGit2Sharp/IndexNameEntryCollection.cs b/LibGit2Sharp/IndexNameEntryCollection.cs index 2896f9124..ff97ee76d 100644 --- a/LibGit2Sharp/IndexNameEntryCollection.cs +++ b/LibGit2Sharp/IndexNameEntryCollection.cs @@ -15,12 +15,6 @@ public class IndexNameEntryCollection : IEnumerable { private readonly Index index; - /// - /// Needed for mocking purposes. - /// - protected IndexNameEntryCollection() - { } - internal IndexNameEntryCollection(Index index) { this.index = index; diff --git a/LibGit2Sharp/IndexReucEntry.cs b/LibGit2Sharp/IndexReucEntry.cs index 144e5c3c9..e679d43de 100644 --- a/LibGit2Sharp/IndexReucEntry.cs +++ b/LibGit2Sharp/IndexReucEntry.cs @@ -19,12 +19,6 @@ public class IndexReucEntry : IEquatable x => x.OurId, x => x.OurMode, x => x.TheirId, x => x.TheirMode); - /// - /// Needed for mocking purposes. - /// - protected IndexReucEntry() - { } - internal static IndexReucEntry BuildFromPtr(IndexReucEntrySafeHandle handle) { if (handle == null || handle.IsZero) diff --git a/LibGit2Sharp/IndexReucEntryCollection.cs b/LibGit2Sharp/IndexReucEntryCollection.cs index 8402a285a..076df060c 100644 --- a/LibGit2Sharp/IndexReucEntryCollection.cs +++ b/LibGit2Sharp/IndexReucEntryCollection.cs @@ -15,12 +15,6 @@ public class IndexReucEntryCollection : IEnumerable { private readonly Index index; - /// - /// Needed for mocking purposes. - /// - protected IndexReucEntryCollection() - { } - internal IndexReucEntryCollection(Index index) { this.index = index; diff --git a/LibGit2Sharp/MergeHead.cs b/LibGit2Sharp/MergeHead.cs index b548b254a..160c60000 100644 --- a/LibGit2Sharp/MergeHead.cs +++ b/LibGit2Sharp/MergeHead.cs @@ -7,12 +7,6 @@ namespace LibGit2Sharp /// internal class MergeHead : ReferenceWrapper { - /// - /// Needed for mocking purposes. - /// - protected MergeHead() - { } - internal MergeHead(Repository repo, ObjectId targetId, int index) : base(repo, new DirectReference(string.Format(CultureInfo.InvariantCulture, "MERGE_HEAD[{0}]", index), repo, targetId), r => r.CanonicalName) { } diff --git a/LibGit2Sharp/MergeResult.cs b/LibGit2Sharp/MergeResult.cs index 6c850c639..326d00d0f 100644 --- a/LibGit2Sharp/MergeResult.cs +++ b/LibGit2Sharp/MergeResult.cs @@ -5,12 +5,6 @@ /// public class MergeResult { - /// - /// Needed for mocking purposes. - /// - protected MergeResult() - { } - internal MergeResult(MergeStatus status, Commit commit = null) { this.Status = status; diff --git a/LibGit2Sharp/MergeTreeResult.cs b/LibGit2Sharp/MergeTreeResult.cs index c871c6278..8c6927730 100644 --- a/LibGit2Sharp/MergeTreeResult.cs +++ b/LibGit2Sharp/MergeTreeResult.cs @@ -7,12 +7,6 @@ namespace LibGit2Sharp /// public class MergeTreeResult { - /// - /// Needed for mocking purposes. - /// - protected MergeTreeResult() - { } - internal MergeTreeResult(IEnumerable conflicts) { this.Status = MergeTreeStatus.Conflicts; diff --git a/LibGit2Sharp/Network.cs b/LibGit2Sharp/Network.cs index 231911ada..f354f3ff0 100644 --- a/LibGit2Sharp/Network.cs +++ b/LibGit2Sharp/Network.cs @@ -17,12 +17,6 @@ public class Network private readonly Repository repository; private readonly Lazy remotes; - /// - /// Needed for mocking purposes. - /// - protected Network() - { } - internal Network(Repository repository) { this.repository = repository; diff --git a/LibGit2Sharp/Note.cs b/LibGit2Sharp/Note.cs index e40bec67e..420aee486 100644 --- a/LibGit2Sharp/Note.cs +++ b/LibGit2Sharp/Note.cs @@ -15,12 +15,6 @@ public class Note : IEquatable private static readonly LambdaEqualityHelper equalityHelper = new LambdaEqualityHelper(x => x.BlobId, x => x.TargetObjectId, x => x.Namespace); - /// - /// Needed for mocking purposes. - /// - protected Note() - { } - private Note(ObjectId blobId, string message, ObjectId targetObjectId, string @namespace) { BlobId = blobId; diff --git a/LibGit2Sharp/NoteCollection.cs b/LibGit2Sharp/NoteCollection.cs index c9f083835..04354999e 100644 --- a/LibGit2Sharp/NoteCollection.cs +++ b/LibGit2Sharp/NoteCollection.cs @@ -18,12 +18,6 @@ public class NoteCollection : IEnumerable internal readonly Repository repo; private readonly Lazy defaultNamespace; - /// - /// Needed for mocking purposes. - /// - protected NoteCollection() - { } - internal NoteCollection(Repository repo) { this.repo = repo; diff --git a/LibGit2Sharp/ObjectDatabase.cs b/LibGit2Sharp/ObjectDatabase.cs index 9171e870c..f31a19d9a 100644 --- a/LibGit2Sharp/ObjectDatabase.cs +++ b/LibGit2Sharp/ObjectDatabase.cs @@ -19,12 +19,6 @@ public class ObjectDatabase : IEnumerable private readonly Repository repo; private readonly ObjectDatabaseSafeHandle handle; - /// - /// Needed for mocking purposes. - /// - protected ObjectDatabase() - { } - internal ObjectDatabase(Repository repo) { this.repo = repo; diff --git a/LibGit2Sharp/OdbBackendStream.cs b/LibGit2Sharp/OdbBackendStream.cs index 2889ac20b..7fbf3c0f0 100644 --- a/LibGit2Sharp/OdbBackendStream.cs +++ b/LibGit2Sharp/OdbBackendStream.cs @@ -11,15 +11,6 @@ namespace LibGit2Sharp /// public abstract class OdbBackendStream { - /// - /// This is to quiet the MetaFixture.TypesInLibGit2SharpMustBeExtensibleInATestingContext test. - /// Do not use this constructor. - /// - protected internal OdbBackendStream() - { - throw new InvalidOperationException(); - } - /// /// Base constructor for OdbBackendStream. Make sure that your derived class calls this base constructor. /// diff --git a/LibGit2Sharp/Patch.cs b/LibGit2Sharp/Patch.cs index fce96e105..5aacbb836 100644 --- a/LibGit2Sharp/Patch.cs +++ b/LibGit2Sharp/Patch.cs @@ -24,12 +24,6 @@ public class Patch : IEnumerable, IDiffResult private int linesAdded; private int linesDeleted; - /// - /// Needed for mocking purposes. - /// - protected Patch() - { } - internal Patch(DiffSafeHandle diff) { int count = Proxy.git_diff_num_deltas(diff); diff --git a/LibGit2Sharp/PatchEntryChanges.cs b/LibGit2Sharp/PatchEntryChanges.cs index 0a7d925b7..b4dcf3fba 100644 --- a/LibGit2Sharp/PatchEntryChanges.cs +++ b/LibGit2Sharp/PatchEntryChanges.cs @@ -7,12 +7,6 @@ public class PatchEntryChanges : ContentChanges { private readonly TreeEntryChanges treeEntryChanges; - /// - /// Needed for mocking purposes. - /// - protected PatchEntryChanges() - { } - internal PatchEntryChanges(bool isBinaryComparison, TreeEntryChanges treeEntryChanges) : base(isBinaryComparison) { diff --git a/LibGit2Sharp/PatchStats.cs b/LibGit2Sharp/PatchStats.cs index fc16d303d..e3d70d90d 100644 --- a/LibGit2Sharp/PatchStats.cs +++ b/LibGit2Sharp/PatchStats.cs @@ -19,12 +19,6 @@ public class PatchStats : IEnumerable, IDiffResult private readonly int totalLinesAdded; private readonly int totalLinesDeleted; - /// - /// For mocking. - /// - protected PatchStats() - { } - internal PatchStats(DiffSafeHandle diff) { int count = Proxy.git_diff_num_deltas(diff); diff --git a/LibGit2Sharp/PushResult.cs b/LibGit2Sharp/PushResult.cs index 713f13a55..54c8fb7d4 100644 --- a/LibGit2Sharp/PushResult.cs +++ b/LibGit2Sharp/PushResult.cs @@ -7,12 +7,6 @@ namespace LibGit2Sharp /// public class PushResult { - /// - /// Needed for mocking purposes. - /// - protected PushResult() - { } - /// /// s that failed to update. /// diff --git a/LibGit2Sharp/PushStatusError.cs b/LibGit2Sharp/PushStatusError.cs index 6675801a2..0c1687744 100644 --- a/LibGit2Sharp/PushStatusError.cs +++ b/LibGit2Sharp/PushStatusError.cs @@ -5,12 +5,6 @@ /// public class PushStatusError { - /// - /// Needed for mocking purposes. - /// - protected PushStatusError() - { } - /// /// The reference this status refers to. /// diff --git a/LibGit2Sharp/Rebase.cs b/LibGit2Sharp/Rebase.cs index c479f12ca..308d295a8 100644 --- a/LibGit2Sharp/Rebase.cs +++ b/LibGit2Sharp/Rebase.cs @@ -51,12 +51,6 @@ public class Rebase { internal readonly Repository repository; - /// - /// Needed for mocking purposes. - /// - protected Rebase() - { } - internal Rebase(Repository repo) { this.repository = repo; diff --git a/LibGit2Sharp/RebaseResult.cs b/LibGit2Sharp/RebaseResult.cs index bee2254af..556b8e05b 100644 --- a/LibGit2Sharp/RebaseResult.cs +++ b/LibGit2Sharp/RebaseResult.cs @@ -32,12 +32,6 @@ public enum RebaseStatus /// public class RebaseResult { - /// - /// Needed for mocking. - /// - protected RebaseResult() - { } - internal RebaseResult(RebaseStatus status, long stepNumber, long totalSteps, diff --git a/LibGit2Sharp/RebaseStepInfo.cs b/LibGit2Sharp/RebaseStepInfo.cs index 4e3557696..f648ed84e 100644 --- a/LibGit2Sharp/RebaseStepInfo.cs +++ b/LibGit2Sharp/RebaseStepInfo.cs @@ -5,12 +5,6 @@ /// public class RebaseStepInfo { - /// - /// Needed for mocking purposes. - /// - protected RebaseStepInfo() - { } - internal RebaseStepInfo(RebaseStepOperation type, Commit commit, string exec) { Type = type; diff --git a/LibGit2Sharp/RefSpec.cs b/LibGit2Sharp/RefSpec.cs index aeeabb75e..27fa50724 100644 --- a/LibGit2Sharp/RefSpec.cs +++ b/LibGit2Sharp/RefSpec.cs @@ -21,12 +21,6 @@ internal RefSpec(Remote remote, GitRefSpecHandle handle) this.handle = handle; } - /// - /// Needed for mocking purposes. - /// - protected RefSpec() - { } - /// /// Gets the pattern describing the mapping between remote and local references /// diff --git a/LibGit2Sharp/RefSpecCollection.cs b/LibGit2Sharp/RefSpecCollection.cs index 46b1c4360..3b0f8fa74 100644 --- a/LibGit2Sharp/RefSpecCollection.cs +++ b/LibGit2Sharp/RefSpecCollection.cs @@ -19,12 +19,6 @@ public class RefSpecCollection : IEnumerable readonly RemoteSafeHandle handle; readonly Lazy> refspecs; - /// - /// Needed for mocking purposes. - /// - protected RefSpecCollection() - { } - internal RefSpecCollection(Remote remote, RemoteSafeHandle handle) { Ensure.ArgumentNotNull(handle, "handle"); diff --git a/LibGit2Sharp/Reference.cs b/LibGit2Sharp/Reference.cs index fa6d9be9e..3d104aaaf 100644 --- a/LibGit2Sharp/Reference.cs +++ b/LibGit2Sharp/Reference.cs @@ -19,12 +19,6 @@ public abstract class Reference : IEquatable, IBelongToARepository private readonly string canonicalName; private readonly string targetIdentifier; - /// - /// Needed for mocking purposes. - /// - protected Reference() - { } - /// /// This would be protected+internal, were that supported by C#. /// Do not use except in subclasses. diff --git a/LibGit2Sharp/ReferenceCollection.cs b/LibGit2Sharp/ReferenceCollection.cs index e91115445..33de3393a 100644 --- a/LibGit2Sharp/ReferenceCollection.cs +++ b/LibGit2Sharp/ReferenceCollection.cs @@ -17,12 +17,6 @@ public class ReferenceCollection : IEnumerable { internal readonly Repository repo; - /// - /// Needed for mocking purposes. - /// - protected ReferenceCollection() - { } - /// /// Initializes a new instance of the class. /// diff --git a/LibGit2Sharp/ReferenceWrapper.cs b/LibGit2Sharp/ReferenceWrapper.cs index 9b5f151d3..56de0bf60 100644 --- a/LibGit2Sharp/ReferenceWrapper.cs +++ b/LibGit2Sharp/ReferenceWrapper.cs @@ -23,12 +23,6 @@ public abstract class ReferenceWrapper : IEquatable - /// Needed for mocking purposes. - /// - protected ReferenceWrapper() - { } - /// The repository. /// The reference. /// A function to construct the reference's canonical name. diff --git a/LibGit2Sharp/ReflogCollection.cs b/LibGit2Sharp/ReflogCollection.cs index a15339c57..08cd844f1 100644 --- a/LibGit2Sharp/ReflogCollection.cs +++ b/LibGit2Sharp/ReflogCollection.cs @@ -19,12 +19,6 @@ public class ReflogCollection : IEnumerable private readonly string canonicalName; - /// - /// Needed for mocking purposes. - /// - protected ReflogCollection() - { } - /// /// Initializes a new instance of the class. /// diff --git a/LibGit2Sharp/ReflogEntry.cs b/LibGit2Sharp/ReflogEntry.cs index 38387e1d7..1ef526a0f 100644 --- a/LibGit2Sharp/ReflogEntry.cs +++ b/LibGit2Sharp/ReflogEntry.cs @@ -15,12 +15,6 @@ public class ReflogEntry private readonly Signature _committer; private readonly string message; - /// - /// Needed for mocking purposes. - /// - protected ReflogEntry() - { } - /// /// Initializes a new instance of the class. /// diff --git a/LibGit2Sharp/Remote.cs b/LibGit2Sharp/Remote.cs index f92b4aa10..da5851ad9 100644 --- a/LibGit2Sharp/Remote.cs +++ b/LibGit2Sharp/Remote.cs @@ -24,12 +24,6 @@ public class Remote : IEquatable, IBelongToARepository, IDisposable readonly RemoteSafeHandle handle; - /// - /// Needed for mocking purposes. - /// - protected Remote() - { } - internal Remote(RemoteSafeHandle handle, Repository repository) { this.repository = repository; diff --git a/LibGit2Sharp/RemoteCollection.cs b/LibGit2Sharp/RemoteCollection.cs index 86bb41331..3e4f710ac 100644 --- a/LibGit2Sharp/RemoteCollection.cs +++ b/LibGit2Sharp/RemoteCollection.cs @@ -18,12 +18,6 @@ public class RemoteCollection : IEnumerable { private readonly Repository repository; - /// - /// Needed for mocking purposes. - /// - protected RemoteCollection() - { } - internal RemoteCollection(Repository repository) { this.repository = repository; diff --git a/LibGit2Sharp/RemoteUpdater.cs b/LibGit2Sharp/RemoteUpdater.cs index cb0e08b3c..2203c20e3 100644 --- a/LibGit2Sharp/RemoteUpdater.cs +++ b/LibGit2Sharp/RemoteUpdater.cs @@ -16,12 +16,6 @@ public class RemoteUpdater private readonly Repository repo; private readonly Remote remote; - /// - /// Needed for mocking purposes. - /// - protected RemoteUpdater() - { } - internal RemoteUpdater(Repository repo, Remote remote) { Ensure.ArgumentNotNull(repo, "repo"); diff --git a/LibGit2Sharp/RenameDetails.cs b/LibGit2Sharp/RenameDetails.cs index b866aac60..82b14a636 100644 --- a/LibGit2Sharp/RenameDetails.cs +++ b/LibGit2Sharp/RenameDetails.cs @@ -18,12 +18,6 @@ public class RenameDetails : IEquatable private static readonly LambdaEqualityHelper equalityHelper = new LambdaEqualityHelper(x => x.OldFilePath, x => x.NewFilePath, x => x.Similarity); - /// - /// Needed for mocking purposes. - /// - protected RenameDetails() - { } - internal RenameDetails(string oldFilePath, string newFilePath, int similarity) { this.oldFilePath = oldFilePath; diff --git a/LibGit2Sharp/RepositoryInformation.cs b/LibGit2Sharp/RepositoryInformation.cs index 9f9596617..9aacc0021 100644 --- a/LibGit2Sharp/RepositoryInformation.cs +++ b/LibGit2Sharp/RepositoryInformation.cs @@ -9,12 +9,6 @@ public class RepositoryInformation { private readonly Repository repo; - /// - /// Needed for mocking purposes. - /// - protected RepositoryInformation() - { } - internal RepositoryInformation(Repository repo, bool isBare) { this.repo = repo; diff --git a/LibGit2Sharp/RepositoryOperationContext.cs b/LibGit2Sharp/RepositoryOperationContext.cs index 5b67d7269..4aee3a4e7 100644 --- a/LibGit2Sharp/RepositoryOperationContext.cs +++ b/LibGit2Sharp/RepositoryOperationContext.cs @@ -6,12 +6,6 @@ /// public class RepositoryOperationContext { - /// - /// Needed for mocking. - /// - protected RepositoryOperationContext() - { } - /// /// Constructor suitable for use on the repository the main /// operation is being run on (i.e. the super project, not a submodule). diff --git a/LibGit2Sharp/RepositoryStatus.cs b/LibGit2Sharp/RepositoryStatus.cs index 8a6b2e0f6..5f7cf90f9 100644 --- a/LibGit2Sharp/RepositoryStatus.cs +++ b/LibGit2Sharp/RepositoryStatus.cs @@ -47,12 +47,6 @@ private static IDictionary> Bu }; } - /// - /// Needed for mocking purposes. - /// - protected RepositoryStatus() - { } - internal RepositoryStatus(Repository repo, StatusOptions options) { statusEntries = new List(); diff --git a/LibGit2Sharp/RevertResult.cs b/LibGit2Sharp/RevertResult.cs index da54046a4..472279d66 100644 --- a/LibGit2Sharp/RevertResult.cs +++ b/LibGit2Sharp/RevertResult.cs @@ -5,12 +5,6 @@ /// public class RevertResult { - /// - /// Needed for mocking purposes. - /// - protected RevertResult() - { } - internal RevertResult(RevertStatus status, Commit commit = null) { Commit = commit; diff --git a/LibGit2Sharp/SmartSubtransportStream.cs b/LibGit2Sharp/SmartSubtransportStream.cs index b5cb21c02..f0407de0d 100644 --- a/LibGit2Sharp/SmartSubtransportStream.cs +++ b/LibGit2Sharp/SmartSubtransportStream.cs @@ -10,15 +10,6 @@ namespace LibGit2Sharp /// public abstract class SmartSubtransportStream { - /// - /// This is to quiet the MetaFixture.TypesInLibGit2SharpMustBeExtensibleInATestingContext test. - /// Do not use this constructor. - /// - protected internal SmartSubtransportStream() - { - throw new InvalidOperationException(); - } - /// /// Base constructor for SmartTransportStream. Make sure that your derived class calls this base constructor. /// diff --git a/LibGit2Sharp/Stash.cs b/LibGit2Sharp/Stash.cs index 07bd6559c..8ccff2195 100644 --- a/LibGit2Sharp/Stash.cs +++ b/LibGit2Sharp/Stash.cs @@ -9,12 +9,6 @@ namespace LibGit2Sharp /// public class Stash : ReferenceWrapper { - /// - /// Needed for mocking purposes. - /// - protected Stash() - { } - internal Stash(Repository repo, ObjectId targetId, int index) : base(repo, new DirectReference(string.Format(CultureInfo.InvariantCulture, "stash@{{{0}}}", index), repo, targetId), r => r.CanonicalName) { } diff --git a/LibGit2Sharp/StashCollection.cs b/LibGit2Sharp/StashCollection.cs index 5fe775eba..2902e52de 100644 --- a/LibGit2Sharp/StashCollection.cs +++ b/LibGit2Sharp/StashCollection.cs @@ -16,12 +16,6 @@ public class StashCollection : IEnumerable { internal readonly Repository repo; - /// - /// Needed for mocking purposes. - /// - protected StashCollection() - { } - /// /// Initializes a new instance of the class. /// diff --git a/LibGit2Sharp/StatusEntry.cs b/LibGit2Sharp/StatusEntry.cs index 7008712c6..e06c84cb9 100644 --- a/LibGit2Sharp/StatusEntry.cs +++ b/LibGit2Sharp/StatusEntry.cs @@ -19,12 +19,6 @@ public class StatusEntry : IEquatable private static readonly LambdaEqualityHelper equalityHelper = new LambdaEqualityHelper(x => x.FilePath, x => x.State, x => x.HeadToIndexRenameDetails, x => x.IndexToWorkDirRenameDetails); - /// - /// Needed for mocking purposes. - /// - protected StatusEntry() - { } - internal StatusEntry(string filePath, FileStatus state, RenameDetails headToIndexRenameDetails = null, RenameDetails indexToWorkDirRenameDetails = null) { this.filePath = filePath; diff --git a/LibGit2Sharp/Submodule.cs b/LibGit2Sharp/Submodule.cs index ace995205..ecff6e425 100644 --- a/LibGit2Sharp/Submodule.cs +++ b/LibGit2Sharp/Submodule.cs @@ -25,12 +25,6 @@ public class Submodule : IEquatable, IBelongToARepository private readonly ILazy ignoreRule; private readonly ILazy updateRule; - /// - /// Needed for mocking purposes. - /// - protected Submodule() - { } - internal Submodule(Repository repo, string name, string path, string url) { this.repo = repo; diff --git a/LibGit2Sharp/SubmoduleCollection.cs b/LibGit2Sharp/SubmoduleCollection.cs index 2ad23f6df..a36adfe6f 100644 --- a/LibGit2Sharp/SubmoduleCollection.cs +++ b/LibGit2Sharp/SubmoduleCollection.cs @@ -17,12 +17,6 @@ public class SubmoduleCollection : IEnumerable { internal readonly Repository repo; - /// - /// Needed for mocking purposes. - /// - protected SubmoduleCollection() - { } - /// /// Initializes a new instance of the class. /// diff --git a/LibGit2Sharp/SymbolicReference.cs b/LibGit2Sharp/SymbolicReference.cs index 4615389e7..f56e4c13b 100644 --- a/LibGit2Sharp/SymbolicReference.cs +++ b/LibGit2Sharp/SymbolicReference.cs @@ -11,12 +11,6 @@ public class SymbolicReference : Reference { private readonly Reference target; - /// - /// Needed for mocking purposes. - /// - protected SymbolicReference() - { } - internal SymbolicReference(IRepository repo, string canonicalName, string targetIdentifier, Reference target) : base(repo, canonicalName, targetIdentifier) { diff --git a/LibGit2Sharp/Tag.cs b/LibGit2Sharp/Tag.cs index cb2436346..051cd0ff3 100644 --- a/LibGit2Sharp/Tag.cs +++ b/LibGit2Sharp/Tag.cs @@ -5,12 +5,6 @@ /// public class Tag : ReferenceWrapper { - /// - /// Needed for mocking purposes. - /// - protected Tag() - { } - internal Tag(Repository repo, Reference reference, string canonicalName) : base(repo, reference, _ => canonicalName) { } diff --git a/LibGit2Sharp/TagAnnotation.cs b/LibGit2Sharp/TagAnnotation.cs index 66a84d556..107c5a07e 100644 --- a/LibGit2Sharp/TagAnnotation.cs +++ b/LibGit2Sharp/TagAnnotation.cs @@ -13,12 +13,6 @@ public class TagAnnotation : GitObject private readonly ILazy lazyMessage; private readonly ILazy lazyTagger; - /// - /// Needed for mocking purposes. - /// - protected TagAnnotation() - { } - internal TagAnnotation(Repository repo, ObjectId id) : base(repo, id) { diff --git a/LibGit2Sharp/TagCollection.cs b/LibGit2Sharp/TagCollection.cs index 8bd9168b0..fd742e841 100644 --- a/LibGit2Sharp/TagCollection.cs +++ b/LibGit2Sharp/TagCollection.cs @@ -15,12 +15,6 @@ public class TagCollection : IEnumerable { internal readonly Repository repo; - /// - /// Needed for mocking purposes. - /// - protected TagCollection() - { } - /// /// Initializes a new instance of the class. /// diff --git a/LibGit2Sharp/Tree.cs b/LibGit2Sharp/Tree.cs index 08e867d84..0102073f6 100644 --- a/LibGit2Sharp/Tree.cs +++ b/LibGit2Sharp/Tree.cs @@ -18,12 +18,6 @@ public class Tree : GitObject, IEnumerable private readonly ILazy lazyCount; - /// - /// Needed for mocking purposes. - /// - protected Tree() - { } - internal Tree(Repository repo, ObjectId id, FilePath path) : base(repo, id) { diff --git a/LibGit2Sharp/TreeChanges.cs b/LibGit2Sharp/TreeChanges.cs index dcf788556..58859fd43 100644 --- a/LibGit2Sharp/TreeChanges.cs +++ b/LibGit2Sharp/TreeChanges.cs @@ -44,12 +44,6 @@ private static IDictionary> Bu }; } - /// - /// Needed for mocking purposes. - /// - protected TreeChanges() - { } - internal TreeChanges(DiffSafeHandle diff) { Proxy.git_diff_foreach(diff, FileCallback, null, null); diff --git a/LibGit2Sharp/TreeEntry.cs b/LibGit2Sharp/TreeEntry.cs index 30ced73c2..0580a58e9 100644 --- a/LibGit2Sharp/TreeEntry.cs +++ b/LibGit2Sharp/TreeEntry.cs @@ -21,12 +21,6 @@ public class TreeEntry : IEquatable private static readonly LambdaEqualityHelper equalityHelper = new LambdaEqualityHelper(x => x.Name, x => x.parentTreeId); - /// - /// Needed for mocking purposes. - /// - protected TreeEntry() - { } - internal TreeEntry(SafeHandle obj, ObjectId parentTreeId, Repository repo, FilePath parentPath) { this.parentTreeId = parentTreeId; diff --git a/LibGit2Sharp/TreeEntryChanges.cs b/LibGit2Sharp/TreeEntryChanges.cs index 4d57b8e50..98fd26a37 100644 --- a/LibGit2Sharp/TreeEntryChanges.cs +++ b/LibGit2Sharp/TreeEntryChanges.cs @@ -10,12 +10,6 @@ namespace LibGit2Sharp [DebuggerDisplay("{DebuggerDisplay,nq}")] public class TreeEntryChanges { - /// - /// Needed for mocking purposes. - /// - protected TreeEntryChanges() - { } - internal TreeEntryChanges(GitDiffDelta delta) { Path = LaxFilePathMarshaler.FromNative(delta.NewFile.Path).Native; diff --git a/LibGit2Sharp/TreeEntryDefinition.cs b/LibGit2Sharp/TreeEntryDefinition.cs index b89c59306..2a67cb62c 100644 --- a/LibGit2Sharp/TreeEntryDefinition.cs +++ b/LibGit2Sharp/TreeEntryDefinition.cs @@ -15,12 +15,6 @@ public class TreeEntryDefinition : IEquatable internal static readonly Enum[] BlobModes = new Enum[] { Mode.NonExecutableFile, Mode.ExecutableFile, Mode.NonExecutableGroupWritableFile, Mode.SymbolicLink }; - /// - /// Needed for mocking purposes. - /// - protected TreeEntryDefinition() - { } - /// /// Gets file mode. /// diff --git a/LibGit2Sharp/Version.cs b/LibGit2Sharp/Version.cs index 4a155dcba..24f54600c 100644 --- a/LibGit2Sharp/Version.cs +++ b/LibGit2Sharp/Version.cs @@ -13,12 +13,6 @@ public class Version { private readonly Assembly assembly = typeof(Repository).Assembly; - /// - /// Needed for mocking purposes. - /// - protected Version() - { } - internal static Version Build() { return new Version(); From 3109b5f68185197ccda7a227a8b9815b7430f625 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Mart=C3=ADn=20Nieto?= Date: Tue, 8 Mar 2016 10:32:40 +0100 Subject: [PATCH 2/4] Let users create our types Instead of hiding everything but making it virtual for mocking, let the users create their own objects with the data they want. --- LibGit2Sharp/CherryPickResult.cs | 10 ++----- LibGit2Sharp/Configuration.cs | 9 ++++-- LibGit2Sharp/ConfigurationEntry.cs | 19 ++---------- LibGit2Sharp/Core/Proxy.cs | 9 ++++-- LibGit2Sharp/FilterAttributeEntry.cs | 5 ---- LibGit2Sharp/IndexEntry.cs | 8 ++--- LibGit2Sharp/IndexNameEntry.cs | 6 ++-- LibGit2Sharp/IndexReucEntry.cs | 14 ++++----- LibGit2Sharp/LogEntry.cs | 4 +-- LibGit2Sharp/MergeResult.cs | 18 ++--------- LibGit2Sharp/MergeTreeResult.cs | 12 ++++++-- LibGit2Sharp/PushResult.cs | 5 +++- LibGit2Sharp/RebaseOperationImpl.cs | 21 +++++++------ LibGit2Sharp/RebaseResult.cs | 19 +++--------- LibGit2Sharp/ReflogEntry.cs | 45 +++++++++------------------- LibGit2Sharp/Repository.cs | 37 +++++++++++++++++------ LibGit2Sharp/RepositoryStatus.cs | 14 +++++++-- LibGit2Sharp/RevertResult.cs | 10 ++----- LibGit2Sharp/StatusEntry.cs | 33 +++----------------- LibGit2Sharp/TreeEntry.cs | 35 ++++++++++++++++++---- 20 files changed, 155 insertions(+), 178 deletions(-) diff --git a/LibGit2Sharp/CherryPickResult.cs b/LibGit2Sharp/CherryPickResult.cs index 772491005..931ea044c 100644 --- a/LibGit2Sharp/CherryPickResult.cs +++ b/LibGit2Sharp/CherryPickResult.cs @@ -5,12 +5,6 @@ /// public class CherryPickResult { - internal CherryPickResult(CherryPickStatus status, Commit commit = null) - { - Commit = commit; - Status = status; - } - /// /// The resulting commit of the cherry pick. /// @@ -20,12 +14,12 @@ internal CherryPickResult(CherryPickStatus status, Commit commit = null) /// 2) The option to not commit on success is set. /// /// - public virtual Commit Commit { get; private set; } + public virtual Commit Commit { get; set; } /// /// The status of the cherry pick. /// - public virtual CherryPickStatus Status { get; private set; } + public virtual CherryPickStatus Status { get; set; } } /// diff --git a/LibGit2Sharp/Configuration.cs b/LibGit2Sharp/Configuration.cs index 82708970c..225ce8571 100644 --- a/LibGit2Sharp/Configuration.cs +++ b/LibGit2Sharp/Configuration.cs @@ -700,9 +700,12 @@ private static ConfigurationEntry BuildConfigEntry(IntPtr entryPtr) { var entry = entryPtr.MarshalAs(); - return new ConfigurationEntry(LaxUtf8Marshaler.FromNative(entry.namePtr), - LaxUtf8Marshaler.FromNative(entry.valuePtr), - (ConfigurationLevel)entry.level); + return new ConfigurationEntry + { + Key = LaxUtf8Marshaler.FromNative(entry.namePtr), + Value = LaxUtf8Marshaler.FromNative(entry.valuePtr), + Level = (ConfigurationLevel)entry.level, + }; } /// diff --git a/LibGit2Sharp/ConfigurationEntry.cs b/LibGit2Sharp/ConfigurationEntry.cs index fb08a09f8..713ecb349 100644 --- a/LibGit2Sharp/ConfigurationEntry.cs +++ b/LibGit2Sharp/ConfigurationEntry.cs @@ -13,30 +13,17 @@ public class ConfigurationEntry /// /// The fully-qualified option name. /// - public virtual string Key { get; private set; } + public virtual string Key { get; set; } /// /// The option value. /// - public virtual T Value { get; private set; } + public virtual T Value { get; set; } /// /// The origin store. /// - public virtual ConfigurationLevel Level { get; private set; } - - /// - /// Initializes a new instance of the class with a given key and value - /// - /// The option name - /// The option value - /// The origin store - protected internal ConfigurationEntry(string key, T value, ConfigurationLevel level) - { - Key = key; - Value = value; - Level = level; - } + public virtual ConfigurationLevel Level { get; set; } private string DebuggerDisplay { diff --git a/LibGit2Sharp/Core/Proxy.cs b/LibGit2Sharp/Core/Proxy.cs index b19fa6499..6887628a3 100644 --- a/LibGit2Sharp/Core/Proxy.cs +++ b/LibGit2Sharp/Core/Proxy.cs @@ -506,9 +506,12 @@ public static ConfigurationEntry git_config_get_entry(ConfigurationSafeHan handle.SafeDispose(); } - return new ConfigurationEntry(LaxUtf8Marshaler.FromNative(entry.namePtr), - (T)configurationParser[typeof(T)](LaxUtf8Marshaler.FromNative(entry.valuePtr)), - (ConfigurationLevel)entry.level); + return new ConfigurationEntry + { + Key = LaxUtf8Marshaler.FromNative(entry.namePtr), + Value = (T)configurationParser[typeof(T)](LaxUtf8Marshaler.FromNative(entry.valuePtr)), + Level = (ConfigurationLevel)entry.level, + }; } public static ConfigurationSafeHandle git_config_new() diff --git a/LibGit2Sharp/FilterAttributeEntry.cs b/LibGit2Sharp/FilterAttributeEntry.cs index 117523d3e..f8baa9447 100644 --- a/LibGit2Sharp/FilterAttributeEntry.cs +++ b/LibGit2Sharp/FilterAttributeEntry.cs @@ -16,11 +16,6 @@ public class FilterAttributeEntry private readonly string filterDefinition; - /// - /// For testing purposes - /// - protected FilterAttributeEntry() { } - /// /// The name of the filter found in a .gitattributes file. /// diff --git a/LibGit2Sharp/IndexEntry.cs b/LibGit2Sharp/IndexEntry.cs index 501d12717..6d1e36f68 100644 --- a/LibGit2Sharp/IndexEntry.cs +++ b/LibGit2Sharp/IndexEntry.cs @@ -18,22 +18,22 @@ public class IndexEntry : IEquatable /// /// Gets the relative path to the file within the working directory. /// - public virtual string Path { get; private set; } + public virtual string Path { get; set; } /// /// Gets the file mode. /// - public virtual Mode Mode { get; private set; } + public virtual Mode Mode { get; set; } /// /// Gets the stage number. /// - public virtual StageLevel StageLevel { get; private set; } + public virtual StageLevel StageLevel { get; set; } /// /// Whether the file is marked as assume-unchanged /// - public virtual bool AssumeUnchanged { get; private set; } + public virtual bool AssumeUnchanged { get; set; } /// /// Gets the id of the pointed at by this index entry. diff --git a/LibGit2Sharp/IndexNameEntry.cs b/LibGit2Sharp/IndexNameEntry.cs index c958ce230..cfcc12035 100644 --- a/LibGit2Sharp/IndexNameEntry.cs +++ b/LibGit2Sharp/IndexNameEntry.cs @@ -46,17 +46,17 @@ internal static IndexNameEntry BuildFromPtr(IndexNameEntrySafeHandle handle) /// /// Gets the path of the ancestor side of the conflict. /// - public virtual string Ancestor { get; private set; } + public virtual string Ancestor { get; set; } /// /// Gets the path of the "ours" side of the conflict. /// - public virtual string Ours { get; private set; } + public virtual string Ours { get; set; } /// /// Gets the path of the "theirs" side of the conflict. /// - public virtual string Theirs { get; private set; } + public virtual string Theirs { get; set; } /// /// Determines whether the specified is equal to the current . diff --git a/LibGit2Sharp/IndexReucEntry.cs b/LibGit2Sharp/IndexReucEntry.cs index e679d43de..f2c2f3f84 100644 --- a/LibGit2Sharp/IndexReucEntry.cs +++ b/LibGit2Sharp/IndexReucEntry.cs @@ -45,43 +45,43 @@ internal static IndexReucEntry BuildFromPtr(IndexReucEntrySafeHandle handle) /// /// Gets the path of this conflict. /// - public virtual string Path { get; private set; } + public virtual string Path { get; set; } /// /// Gets the that was the ancestor of this /// conflict. /// - public virtual ObjectId AncestorId { get; private set; } + public virtual ObjectId AncestorId { get; set; } /// /// Gets the of the file that was the ancestor of /// conflict. /// - public virtual Mode AncestorMode { get; private set; } + public virtual Mode AncestorMode { get; set; } /// /// Gets the that was "our" side of this /// conflict. /// - public virtual ObjectId OurId { get; private set; } + public virtual ObjectId OurId { get; set; } /// /// Gets the of the file that was "our" side of /// the conflict. /// - public virtual Mode OurMode { get; private set; } + public virtual Mode OurMode { get; set; } /// /// Gets the that was "their" side of this /// conflict. /// - public virtual ObjectId TheirId { get; private set; } + public virtual ObjectId TheirId { get; set; } /// /// Gets the of the file that was "their" side of /// the conflict. /// - public virtual Mode TheirMode { get; private set; } + public virtual Mode TheirMode { get; set; } /// /// Determines whether the specified is equal to the current . diff --git a/LibGit2Sharp/LogEntry.cs b/LibGit2Sharp/LogEntry.cs index d7aadc06c..dfcfecba6 100644 --- a/LibGit2Sharp/LogEntry.cs +++ b/LibGit2Sharp/LogEntry.cs @@ -8,11 +8,11 @@ public sealed class LogEntry /// /// The file's path relative to the repository's root. /// - public string Path { get; internal set; } + public string Path { get; set; } /// /// The commit in which the file was created or changed. /// - public Commit Commit { get; internal set; } + public Commit Commit { get; set; } } } diff --git a/LibGit2Sharp/MergeResult.cs b/LibGit2Sharp/MergeResult.cs index 326d00d0f..d84c32de1 100644 --- a/LibGit2Sharp/MergeResult.cs +++ b/LibGit2Sharp/MergeResult.cs @@ -5,31 +5,17 @@ /// public class MergeResult { - internal MergeResult(MergeStatus status, Commit commit = null) - { - this.Status = status; - this.Commit = commit; - } - /// /// The status of the merge. /// - public virtual MergeStatus Status - { - get; - private set; - } + public virtual MergeStatus Status { get; set; } /// /// The resulting commit of the merge. For fast-forward merges, this is the /// commit that merge was fast forwarded to. /// This will return null if the merge has been unsuccessful due to conflicts. /// - public virtual Commit Commit - { - get; - private set; - } + public virtual Commit Commit { get; set; } } /// diff --git a/LibGit2Sharp/MergeTreeResult.cs b/LibGit2Sharp/MergeTreeResult.cs index 8c6927730..8e5488420 100644 --- a/LibGit2Sharp/MergeTreeResult.cs +++ b/LibGit2Sharp/MergeTreeResult.cs @@ -7,13 +7,21 @@ namespace LibGit2Sharp /// public class MergeTreeResult { - internal MergeTreeResult(IEnumerable conflicts) + /// + /// Create a which resulted in conflicts + /// + /// The list of conflicts from the merge + public MergeTreeResult(IEnumerable conflicts) { this.Status = MergeTreeStatus.Conflicts; this.Conflicts = conflicts; } - internal MergeTreeResult(Tree tree) + /// + /// Create a from a successful merge + /// + /// The resulting tree + public MergeTreeResult(Tree tree) { this.Status = MergeTreeStatus.Succeeded; this.Tree = tree; diff --git a/LibGit2Sharp/PushResult.cs b/LibGit2Sharp/PushResult.cs index 54c8fb7d4..116fe9985 100644 --- a/LibGit2Sharp/PushResult.cs +++ b/LibGit2Sharp/PushResult.cs @@ -24,7 +24,10 @@ public virtual bool HasErrors get { return failedPushUpdates.Count > 0; } } - internal PushResult(List failedPushUpdates) + /// + /// s that failed to update. + /// + public PushResult(List failedPushUpdates) { this.failedPushUpdates = failedPushUpdates ?? new List(); } diff --git a/LibGit2Sharp/RebaseOperationImpl.cs b/LibGit2Sharp/RebaseOperationImpl.cs index abb4537c3..b02a419d3 100644 --- a/LibGit2Sharp/RebaseOperationImpl.cs +++ b/LibGit2Sharp/RebaseOperationImpl.cs @@ -56,11 +56,12 @@ private static RebaseResult CompleteRebase(RebaseSafeHandle rebaseOperationHandl // Rebase is completed! Proxy.git_rebase_finish(rebaseOperationHandle, committer); - var rebaseResult = new RebaseResult(RebaseStatus.Complete, - totalStepCount, - totalStepCount, - null); - return rebaseResult; + return new RebaseResult + { + Status = RebaseStatus.Complete, + CompletedStepCount = totalStepCount, + TotalStepCount = totalStepCount, + }; } /// @@ -144,10 +145,12 @@ private static RebaseResult RunRebaseStep(RebaseSafeHandle rebaseOperationHandle // running the rebase sequence operations, then report the result. if (rebaseStepResult.Status == RebaseStepStatus.Conflicts) { - rebaseSequenceResult = new RebaseResult(RebaseStatus.Conflicts, - stepToApplyIndex, - totalStepCount, - null); + rebaseSequenceResult = new RebaseResult + { + Status = RebaseStatus.Conflicts, + CompletedStepCount = stepToApplyIndex, + TotalStepCount = totalStepCount, + }; } return rebaseSequenceResult; diff --git a/LibGit2Sharp/RebaseResult.cs b/LibGit2Sharp/RebaseResult.cs index 556b8e05b..d3a2a0d03 100644 --- a/LibGit2Sharp/RebaseResult.cs +++ b/LibGit2Sharp/RebaseResult.cs @@ -32,39 +32,28 @@ public enum RebaseStatus /// public class RebaseResult { - internal RebaseResult(RebaseStatus status, - long stepNumber, - long totalSteps, - RebaseStepInfo currentStepInfo) - { - Status = status; - CompletedStepCount = stepNumber; - TotalStepCount = totalSteps; - CurrentStepInfo = currentStepInfo; - } - /// /// Information on the operation to be performed in the current step. /// If the overall Rebase operation has completed successfully, this will /// be null. /// - public virtual RebaseStepInfo CurrentStepInfo { get; private set; } + public virtual RebaseStepInfo CurrentStepInfo { get; set; } /// /// Did the rebase operation run until it should stop /// (completed the rebase, or the operation for the current step /// is one that sequencing should stop. /// - public virtual RebaseStatus Status { get; protected set; } + public virtual RebaseStatus Status { get; set; } /// /// The number of completed steps. /// - public virtual long CompletedStepCount { get; protected set; } + public virtual long CompletedStepCount { get; set; } /// /// The total number of steps in the rebase. /// - public virtual long TotalStepCount { get; protected set; } + public virtual long TotalStepCount { get; set; } } } diff --git a/LibGit2Sharp/ReflogEntry.cs b/LibGit2Sharp/ReflogEntry.cs index 1ef526a0f..322c706eb 100644 --- a/LibGit2Sharp/ReflogEntry.cs +++ b/LibGit2Sharp/ReflogEntry.cs @@ -10,53 +10,36 @@ namespace LibGit2Sharp /// public class ReflogEntry { - private readonly ObjectId _from; - private readonly ObjectId _to; - private readonly Signature _committer; - private readonly string message; - - /// - /// 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); - _committer = 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; } - } + public ObjectId From { get; set; } /// /// targeted after the reference update described by this /// - public virtual ObjectId To - { - get { return _to; } - } + public ObjectId To { get; set; } /// /// of the committer of this reference update /// - public virtual Signature Committer - { - get { return _committer; } - } + public Signature Committer { get; set; } /// /// the message assiocated to this reference update /// - public virtual string Message + public string Message { get; set; } + + /// + /// Initializes a new instance of the class. + /// + /// a to the reflog entry + public ReflogEntry(SafeHandle entryHandle) { - get { return message; } + From = Proxy.git_reflog_entry_id_old(entryHandle); + To = Proxy.git_reflog_entry_id_new(entryHandle); + Committer = Proxy.git_reflog_entry_committer(entryHandle); + Message = Proxy.git_reflog_entry_message(entryHandle); } } } diff --git a/LibGit2Sharp/Repository.cs b/LibGit2Sharp/Repository.cs index bfb551f9f..0589d0112 100644 --- a/LibGit2Sharp/Repository.cs +++ b/LibGit2Sharp/Repository.cs @@ -1365,11 +1365,15 @@ public RevertResult Revert(Commit commit, Signature reverter, RevertOptions opti } } - result = new RevertResult(revertStatus, revertCommit); + result = new RevertResult + { + Status = revertStatus, + Commit = revertCommit + }; } else { - result = new RevertResult(RevertStatus.Conflicts); + result = new RevertResult { Status = RevertStatus.Conflicts }; } } @@ -1422,11 +1426,18 @@ public CherryPickResult CherryPick(Commit commit, Signature committer, CherryPic cherryPickCommit = this.Commit(Info.Message, commit.Author, committer, null); } - result = new CherryPickResult(CherryPickStatus.CherryPicked, cherryPickCommit); + result = new CherryPickResult + { + Status = CherryPickStatus.CherryPicked, + Commit = cherryPickCommit + }; } else { - result = new CherryPickResult(CherryPickStatus.Conflicts); + result = new CherryPickResult + { + Status = CherryPickStatus.Conflicts + }; } } @@ -1466,7 +1477,7 @@ private MergeResult Merge(GitAnnotatedCommitHandle[] annotatedCommits, Signature if ((mergeAnalysis & GitMergeAnalysis.GIT_MERGE_ANALYSIS_UP_TO_DATE) == GitMergeAnalysis.GIT_MERGE_ANALYSIS_UP_TO_DATE) { - return new MergeResult(MergeStatus.UpToDate); + return new MergeResult { Status = MergeStatus.UpToDate }; } FastForwardStrategy fastForwardStrategy = (options.FastForwardStrategy != FastForwardStrategy.Default) ? @@ -1570,7 +1581,7 @@ private MergeResult NormalMerge(GitAnnotatedCommitHandle[] annotatedCommits, Sig if (earlyStop) { - return new MergeResult(MergeStatus.Conflicts); + return new MergeResult { Status = MergeStatus.Conflicts }; } if (Index.IsFullyMerged) @@ -1582,11 +1593,15 @@ private MergeResult NormalMerge(GitAnnotatedCommitHandle[] annotatedCommits, Sig mergeCommit = Commit(Info.Message, author: merger, committer: merger, options: null); } - mergeResult = new MergeResult(MergeStatus.NonFastForward, mergeCommit); + mergeResult = new MergeResult + { + Status = MergeStatus.NonFastForward, + Commit = mergeCommit + }; } else { - mergeResult = new MergeResult(MergeStatus.Conflicts); + mergeResult = new MergeResult { Status = MergeStatus.Conflicts }; } return mergeResult; @@ -1623,7 +1638,11 @@ private MergeResult FastForwardMerge(GitAnnotatedCommitHandle annotatedCommit, M Refs.UpdateTarget(reference, fastForwardCommit.Id.Sha, refLogEntry); } - return new MergeResult(MergeStatus.FastForward, fastForwardCommit); + return new MergeResult + { + Status = MergeStatus.FastForward, + Commit = fastForwardCommit + }; } /// diff --git a/LibGit2Sharp/RepositoryStatus.cs b/LibGit2Sharp/RepositoryStatus.cs index 5f7cf90f9..27aa080e3 100644 --- a/LibGit2Sharp/RepositoryStatus.cs +++ b/LibGit2Sharp/RepositoryStatus.cs @@ -163,7 +163,13 @@ private void AddStatusEntryForDelta(FileStatus gitStatus, GitDiffDelta deltaHead ? LaxFilePathMarshaler.FromNative(deltaIndexToWorkDir.NewFile.Path).Native : LaxFilePathMarshaler.FromNative(deltaHeadToIndex.NewFile.Path).Native; - StatusEntry statusEntry = new StatusEntry(filePath, gitStatus, headToIndexRenameDetails, indexToWorkDirRenameDetails); + StatusEntry statusEntry = new StatusEntry + { + FilePath = filePath, + State = gitStatus, + HeadToIndexRenameDetails = headToIndexRenameDetails, + IndexToWorkDirRenameDetails = indexToWorkDirRenameDetails + }; if (gitStatus == FileStatus.Unaltered) { @@ -200,7 +206,11 @@ public virtual StatusEntry this[string path] if (entries.Count == 0) { - return new StatusEntry(path, FileStatus.Nonexistent); + return new StatusEntry + { + FilePath = path, + State = FileStatus.Nonexistent + }; } return entries.Single(); diff --git a/LibGit2Sharp/RevertResult.cs b/LibGit2Sharp/RevertResult.cs index 472279d66..580e5745f 100644 --- a/LibGit2Sharp/RevertResult.cs +++ b/LibGit2Sharp/RevertResult.cs @@ -5,12 +5,6 @@ /// public class RevertResult { - internal RevertResult(RevertStatus status, Commit commit = null) - { - Commit = commit; - Status = status; - } - /// /// The resulting commit of the revert. /// @@ -20,12 +14,12 @@ internal RevertResult(RevertStatus status, Commit commit = null) /// 2) The option to not commit on success is set. /// /// - public virtual Commit Commit { get; private set; } + public virtual Commit Commit { get; set; } /// /// The status of the revert. /// - public virtual RevertStatus Status { get; private set; } + public virtual RevertStatus Status { get; set; } } /// diff --git a/LibGit2Sharp/StatusEntry.cs b/LibGit2Sharp/StatusEntry.cs index e06c84cb9..f08938f4c 100644 --- a/LibGit2Sharp/StatusEntry.cs +++ b/LibGit2Sharp/StatusEntry.cs @@ -11,53 +11,28 @@ namespace LibGit2Sharp [DebuggerDisplay("{DebuggerDisplay,nq}")] public class StatusEntry : IEquatable { - private readonly string filePath; - private readonly FileStatus state; - private readonly RenameDetails headToIndexRenameDetails; - private readonly RenameDetails indexToWorkDirRenameDetails; - private static readonly LambdaEqualityHelper equalityHelper = new LambdaEqualityHelper(x => x.FilePath, x => x.State, x => x.HeadToIndexRenameDetails, x => x.IndexToWorkDirRenameDetails); - internal StatusEntry(string filePath, FileStatus state, RenameDetails headToIndexRenameDetails = null, RenameDetails indexToWorkDirRenameDetails = null) - { - this.filePath = filePath; - this.state = state; - this.headToIndexRenameDetails = headToIndexRenameDetails; - this.indexToWorkDirRenameDetails = indexToWorkDirRenameDetails; - } - /// /// Gets the of the file. /// - public virtual FileStatus State - { - get { return state; } - } + public virtual FileStatus State { get; set; } /// /// Gets the relative new filepath to the working directory of the file. /// - public virtual string FilePath - { - get { return filePath; } - } + public virtual string FilePath { get; set; } /// /// Gets the rename details from the HEAD to the Index, if this contains /// - public virtual RenameDetails HeadToIndexRenameDetails - { - get { return headToIndexRenameDetails; } - } + public virtual RenameDetails HeadToIndexRenameDetails { get; set; } /// /// Gets the rename details from the Index to the working directory, if this contains /// - public virtual RenameDetails IndexToWorkDirRenameDetails - { - get { return indexToWorkDirRenameDetails; } - } + public virtual RenameDetails IndexToWorkDirRenameDetails { get; set; } /// /// Determines whether the specified is equal to the current . diff --git a/LibGit2Sharp/TreeEntry.cs b/LibGit2Sharp/TreeEntry.cs index 0580a58e9..ee5a93dee 100644 --- a/LibGit2Sharp/TreeEntry.cs +++ b/LibGit2Sharp/TreeEntry.cs @@ -15,17 +15,42 @@ public class TreeEntry : IEquatable private readonly ObjectId parentTreeId; private readonly Repository repo; private readonly Lazy target; - private readonly ObjectId targetOid; + private readonly ObjectId targetId; private readonly Lazy path; private static readonly LambdaEqualityHelper equalityHelper = new LambdaEqualityHelper(x => x.Name, x => x.parentTreeId); + /// + /// Create a new . + /// + /// The repository in which the entry's tree lives + /// The filename + /// ID of the object being pointed at + /// The file mode + /// The type of target + /// The parent tree's ID + /// The parent tree's path + public TreeEntry(Repository repo, string name, ObjectId targetId, Mode mode, TreeEntryTargetType targetType, ObjectId parentTreeId, string parentPath) + { + this.parentTreeId = parentTreeId; + this.repo = repo; + this.targetId = targetId; + + TargetType = targetType; + + target = new Lazy(RetrieveTreeEntryTarget); + + Mode = mode; + Name = name; + path = new Lazy(() => System.IO.Path.Combine(parentPath, Name)); + } + internal TreeEntry(SafeHandle obj, ObjectId parentTreeId, Repository repo, FilePath parentPath) { this.parentTreeId = parentTreeId; this.repo = repo; - targetOid = Proxy.git_tree_entry_id(obj); + targetId = Proxy.git_tree_entry_id(obj); GitObjectType treeEntryTargetType = Proxy.git_tree_entry_type(obj); TargetType = treeEntryTargetType.ToTreeEntryTargetType(); @@ -60,7 +85,7 @@ internal TreeEntry(SafeHandle obj, ObjectId parentTreeId, Repository repo, FileP internal ObjectId TargetId { - get { return targetOid; } + get { return targetId; } } /// @@ -73,11 +98,11 @@ private GitObject RetrieveTreeEntryTarget() switch (TargetType) { case TreeEntryTargetType.GitLink: - return new GitLink(repo, targetOid); + return new GitLink(repo, targetId); case TreeEntryTargetType.Blob: case TreeEntryTargetType.Tree: - return GitObject.BuildFrom(repo, targetOid, TargetType.ToGitObjectType(), Path); + return GitObject.BuildFrom(repo, targetId, TargetType.ToGitObjectType(), Path); default: throw new InvalidOperationException(string.Format(CultureInfo.InvariantCulture, From 4f14bc3c41c99eb38b158384fdbec4f0cb48ccc9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Mart=C3=ADn=20Nieto?= Date: Tue, 8 Mar 2016 14:13:17 +0100 Subject: [PATCH 3/4] fixup! Remove the code we have just for mocking --- LibGit2Sharp.Tests/packages.config | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/LibGit2Sharp.Tests/packages.config b/LibGit2Sharp.Tests/packages.config index df97e2e87..a605b8daf 100644 --- a/LibGit2Sharp.Tests/packages.config +++ b/LibGit2Sharp.Tests/packages.config @@ -1,5 +1,6 @@  - + + From 62068d9e173421f474f9d2322accbf86d5293236 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Carlos=20Mart=C3=ADn=20Nieto?= Date: Tue, 15 Mar 2016 09:38:33 +0100 Subject: [PATCH 4/4] Fold RepositorExtensions into the type and interface We should not have extensions on our own types. Either we accept these convenience overloads as part of our interfaces or we shouldn't have them. While here unseal Repository and split up these methods into a few different files grouping them by area. --- LibGit2Sharp/IRepository.cs | 288 ++++++++ LibGit2Sharp/LibGit2Sharp.csproj | 6 +- LibGit2Sharp/Repository.Branch.cs | 40 ++ LibGit2Sharp/Repository.Checkout.cs | 256 +++++++ LibGit2Sharp/Repository.Lookup.cs | 157 +++++ LibGit2Sharp/Repository.Reset.cs | 71 ++ LibGit2Sharp/Repository.Workdir.cs | 601 +++++++++++++++++ LibGit2Sharp/Repository.cs | 972 +++++++-------------------- LibGit2Sharp/RepositoryExtensions.cs | 691 ------------------- 9 files changed, 1660 insertions(+), 1422 deletions(-) create mode 100644 LibGit2Sharp/Repository.Branch.cs create mode 100644 LibGit2Sharp/Repository.Checkout.cs create mode 100644 LibGit2Sharp/Repository.Lookup.cs create mode 100644 LibGit2Sharp/Repository.Reset.cs create mode 100644 LibGit2Sharp/Repository.Workdir.cs delete mode 100644 LibGit2Sharp/RepositoryExtensions.cs diff --git a/LibGit2Sharp/IRepository.cs b/LibGit2Sharp/IRepository.cs index 1bd921a51..fc9431146 100644 --- a/LibGit2Sharp/IRepository.cs +++ b/LibGit2Sharp/IRepository.cs @@ -69,6 +69,37 @@ public interface IRepository : IDisposable /// SubmoduleCollection Submodules { get; } + /// + /// Creates a lightweight tag with the specified name. This tag will point at the commit pointed at by the . + /// + /// The name of the tag to create. + Tag ApplyTag(string tagName); + + /// + /// Creates a lightweight tag with the specified name. This tag will point at the . + /// + /// The name of the tag to create. + /// The revparse spec for the target object. + Tag ApplyTag(string tagName, string objectish); + + /// + /// Creates an annotated tag with the specified name. This tag will point at the commit pointed at by the . + /// + /// The name of the tag to create. + /// The identity of the creator of this tag. + /// The annotation message. + Tag ApplyTag(string tagName, Signature tagger, string message); + + /// + /// Creates an annotated tag with the specified name. This tag will point at the . + /// + /// The name of the tag to create. + /// The revparse spec for the target object. + /// The identity of the creator of this tag. + /// The annotation message. + Tag ApplyTag(string tagName, string objectish, Signature tagger, string message); + + /// /// Checkout the commit pointed at by the tip of the specified . /// @@ -93,6 +124,33 @@ public interface IRepository : IDisposable /// The that was checked out. Branch Checkout(string committishOrBranchSpec, CheckoutOptions options); + /// + /// Checkout the specified , reference or SHA. + /// + /// A revparse spec for the commit or branch to checkout. + /// The that was checked out. + Branch Checkout(string commitOrBranchSpec); + + /// + /// Checkout the commit pointed at by the tip of the specified . + /// + /// If this commit is the current tip of the branch as it exists in the repository, the HEAD + /// will point to this branch. Otherwise, the HEAD will be detached, pointing at the commit sha. + /// + /// + /// The to check out. + /// The that was checked out. + Branch Checkout(Branch branch); + /// + /// Checkout the specified . + /// + /// Will detach the HEAD and make it point to this commit sha. + /// + /// + /// The to check out. + /// The that was checked out. + Branch Checkout(Commit commit); + /// /// Checkout the specified . /// @@ -115,6 +173,16 @@ public interface IRepository : IDisposable /// Collection of parameters controlling checkout behavior. void CheckoutPaths(string committishOrBranchSpec, IEnumerable paths, CheckoutOptions checkoutOptions); + /// + /// Updates specifed paths in the index and working directory with the versions from the specified branch, reference, or SHA. + /// + /// This method does not switch branches or update the current repository HEAD. + /// + /// + /// A revparse spec for the commit or branch to checkout paths from. + /// The paths to checkout. Will throw if null is passed in. Passing an empty enumeration results in nothing being checked out. + void CheckoutPaths(string committishOrBranchSpec, IEnumerable paths); + /// /// Try to lookup an object by its . If no matching object is found, null will be returned. /// @@ -145,6 +213,30 @@ public interface IRepository : IDisposable /// The or null if it was not found. GitObject Lookup(string objectish, ObjectType type); + /// + /// Try to lookup an object by its . + /// + /// The kind of to lookup. + /// The id. + /// The retrieved , or null if none was found. + T Lookup(ObjectId id) where T : GitObject; + + /// + /// Try to lookup an object by its sha or a reference name. + /// + /// The kind of to lookup. + /// The revparse spec for the object to lookup. + /// The retrieved , or null if none was found. + T Lookup(string objectish) where T : GitObject; + + /// + /// Find where each line of a file originated. + /// + /// Path of the file to blame. + /// The blame for the file. + BlameHunkCollection Blame(string path); + + /// /// Stores the content of the as a new into the repository. /// The tip of the will be used as the parent of this new Commit. @@ -157,6 +249,58 @@ public interface IRepository : IDisposable /// The generated . Commit Commit(string message, Signature author, Signature committer, CommitOptions options); + /// + /// Stores the content of the as a new into the repository. + /// The tip of the will be used as the parent of this new Commit. + /// Once the commit is created, the will move forward to point at it. + /// + /// The description of why a change was made to the repository. + /// The of who made the change. + /// The of who added the change to the repository. + /// The generated . + Commit Commit(string message, Signature author, Signature committer); + + /// + /// Cherry-picks the specified commit. + /// + /// The to cherry-pick. + /// The of who is performing the cherry pick. + /// The result of the cherry pick. + CherryPickResult CherryPick(Commit commit, Signature committer); + + /// + /// Creates a branch with the specified name. This branch will point at the commit pointed at by the . + /// + /// The name of the branch to create. + Branch CreateBranch(string branchName); + + /// + /// Creates a branch with the specified name. This branch will point at . + /// + /// The name of the branch to create. + /// The commit which should be pointed at by the Branch. + Branch CreateBranch(string branchName, Commit target); + + /// + /// Creates a branch with the specified name. This branch will point at the commit pointed at by the . + /// + /// The name of the branch to create. + /// The revparse spec for the target commit. + Branch CreateBranch( string branchName, string committish); + + /// + /// Fetch from the specified remote. + /// + /// The name of the to fetch from. + void Fetch(string remoteName); + + /// + /// Fetch from the specified remote. + /// + /// The name of the to fetch from. + /// controlling fetch behavior + void Fetch(string remoteName, FetchOptions options); + /// /// Sets the current to the specified commit and optionally resets the and /// the content of the working tree to match. @@ -165,6 +309,22 @@ public interface IRepository : IDisposable /// The target commit object. void Reset(ResetMode resetMode, Commit commit); + /// + /// Sets the current to the specified commitish and optionally resets the and + /// the content of the working tree to match. + /// + /// Flavor of reset operation to perform. + /// A revparse spec for the target commit object. + void Reset(ResetMode resetMode, string committish); + + + /// + /// Sets the current and resets the and + /// the content of the working tree to match. + /// + /// Flavor of reset operation to perform. + void Reset(ResetMode resetMode); + /// /// Sets to the specified commit and optionally resets the and /// the content of the working tree to match. @@ -179,6 +339,60 @@ public interface IRepository : IDisposable /// void RemoveUntrackedFiles(); + /// + /// Removes a file from the staging area, and optionally removes it from the working directory as well. + /// + /// If the file has already been deleted from the working directory, this method will only deal + /// with promoting the removal to the staging area. + /// + /// + /// The default behavior is to remove the file from the working directory as well. + /// + /// + /// The path of the file within the working directory. + void Remove(string path); + + /// + /// Removes a file from the staging area, and optionally removes it from the working directory as well. + /// + /// If the file has already been deleted from the working directory, this method will only deal + /// with promoting the removal to the staging area. + /// + /// + /// The default behavior is to remove the file from the working directory as well. + /// + /// + /// The path of the file within the working directory. + /// True to remove the file from the working directory, False otherwise. + void Remove(string path, bool removeFromWorkingDirectory); + + /// + /// Removes a collection of fileS from the staging, and optionally removes them from the working directory as well. + /// + /// If a file has already been deleted from the working directory, this method will only deal + /// with promoting the removal to the staging area. + /// + /// + /// The default behavior is to remove the files from the working directory as well. + /// + /// + /// The collection of paths of the files within the working directory. + void Remove(IEnumerable paths); + + /// + /// Removes a collection of fileS from the staging, and optionally removes them from the working directory as well. + /// + /// If a file has already been deleted from the working directory, this method will only deal + /// with promoting the removal to the staging area. + /// + /// + /// The default behavior is to remove the files from the working directory as well. + /// + /// + /// The collection of paths of the files within the working directory. + /// True to remove the files from the working directory, False otherwise. + void Remove(IEnumerable paths, bool removeFromWorkingDirectory); + /// /// Revert the specified commit. /// @@ -188,6 +402,14 @@ public interface IRepository : IDisposable /// The result of the revert. RevertResult Revert(Commit commit, Signature reverter, RevertOptions options); + /// + /// Revert the specified commit. + /// + /// The to revert. + /// The of who is performing the revert. + /// The result of the revert. + RevertResult Revert(Commit commit, Signature reverter); + /// /// Merge changes from commit into the branch pointed at by HEAD.. /// @@ -215,6 +437,30 @@ public interface IRepository : IDisposable /// The of the merge. MergeResult Merge(string committish, Signature merger, MergeOptions options); + /// + /// Merges changes from branch into the branch pointed at by HEAD. + /// + /// The branch to merge into the branch pointed at by HEAD. + /// The of who is performing the merge. + /// The of the merge. + MergeResult Merge(Branch branch, Signature merger); + + /// + /// Merges changes from the commit into the branch pointed at by HEAD. + /// + /// The commit to merge into the branch pointed at by HEAD. + /// The of who is performing the merge. + /// The of the merge. + MergeResult Merge(string committish, Signature merger); + + /// + /// Merges changes from commit into the branch pointed at by HEAD. + /// + /// The commit to merge into the branch pointed at by HEAD. + /// The of who is performing the merge. + /// The of the merge. + MergeResult Merge(Commit commit, Signature merger); + /// /// Access to Rebase functionality. /// @@ -273,6 +519,18 @@ public interface IRepository : IDisposable /// Determines how paths will be staged. void Stage(string path, StageOptions stageOptions); + /// + /// Promotes to the staging area the latest modifications of a file in the working directory (addition, updation or removal). + /// + /// The path of the file within the working directory. + void Stage(string path); + + /// + /// Promotes to the staging area the latest modifications of a collection of files in the working directory (addition, updation or removal). + /// + /// The collection of paths of the files within the working directory. + void Stage(IEnumerable paths); + /// /// Promotes to the staging area the latest modifications of a collection of files in the working directory (addition, updation or removal). /// @@ -302,6 +560,18 @@ public interface IRepository : IDisposable /// void Unstage(IEnumerable paths, ExplicitPathsOptions explicitPathsOptions); + /// + /// Removes from the staging area all the modifications of a file since the latest commit (addition, updation or removal). + /// + /// The path of the file within the working directory. + void Unstage(string path); + + /// + /// Removes from the staging area all the modifications of a collection of file since the latest commit (addition, updation or removal). + /// + /// The collection of paths of the files within the working directory. + void Unstage(IEnumerable paths); + /// /// Moves and/or renames a file in the working directory and promotes the change to the staging area. /// @@ -376,6 +646,12 @@ public interface IRepository : IDisposable /// A holding the state of all the files. RepositoryStatus RetrieveStatus(StatusOptions options); + /// + /// Retrieves the state of all files in the working directory, comparing them against the staging area and the latest commit. + /// + /// A holding the state of all the files. + RepositoryStatus RetrieveStatus(); + /// /// Finds the most recent annotated tag that is reachable from a commit. /// @@ -393,5 +669,17 @@ public interface IRepository : IDisposable /// Determines how the commit will be described. /// A descriptive identifier for the commit based on the nearest annotated tag. string Describe(Commit commit, DescribeOptions options); + + /// + /// Finds the most recent annotated tag that is reachable from a commit. + /// + /// If the tag points to the commit, then only the tag is shown. Otherwise, + /// it suffixes the tag name with the number of additional commits on top + /// of the tagged object and the abbreviated object name of the most recent commit. + /// + /// + /// The commit to be described. + /// A descriptive identifier for the commit based on the nearest annotated tag. + string Describe(Commit commit); } } diff --git a/LibGit2Sharp/LibGit2Sharp.csproj b/LibGit2Sharp/LibGit2Sharp.csproj index c9d8b2aac..22e15589a 100644 --- a/LibGit2Sharp/LibGit2Sharp.csproj +++ b/LibGit2Sharp/LibGit2Sharp.csproj @@ -352,7 +352,6 @@ Code - @@ -388,6 +387,11 @@ + + + + + diff --git a/LibGit2Sharp/Repository.Branch.cs b/LibGit2Sharp/Repository.Branch.cs new file mode 100644 index 000000000..008ec9fd6 --- /dev/null +++ b/LibGit2Sharp/Repository.Branch.cs @@ -0,0 +1,40 @@ +using System; + +namespace LibGit2Sharp +{ + public partial class Repository + { + /// + /// Creates a branch with the specified name. This branch will point at the commit pointed at by the . + /// + /// The name of the branch to create. + public Branch CreateBranch(string branchName) + { + var head = Head; + var reflogName = head is DetachedHead ? head.Tip.Sha : head.FriendlyName; + + return CreateBranch(branchName, reflogName); + } + + /// + /// Creates a branch with the specified name. This branch will point at . + /// + /// The name of the branch to create. + /// The commit which should be pointed at by the Branch. + public Branch CreateBranch(string branchName, Commit target) + { + return Branches.Add(branchName, target); + } + + /// + /// Creates a branch with the specified name. This branch will point at the commit pointed at by the . + /// + /// The name of the branch to create. + /// The revparse spec for the target commit. + public Branch CreateBranch( string branchName, string committish) + { + return Branches.Add(branchName, committish); + } + } +} + diff --git a/LibGit2Sharp/Repository.Checkout.cs b/LibGit2Sharp/Repository.Checkout.cs new file mode 100644 index 000000000..353981c6f --- /dev/null +++ b/LibGit2Sharp/Repository.Checkout.cs @@ -0,0 +1,256 @@ +using System; +using System.IO; +using System.Linq; +using System.Collections.Generic; +using System.Globalization; +using LibGit2Sharp.Core; + +namespace LibGit2Sharp +{ + public partial class Repository + { + /// + /// Checkout the specified , reference or SHA. + /// + /// If the committishOrBranchSpec parameter resolves to a branch name, then the checked out HEAD will + /// will point to the branch. Otherwise, the HEAD will be detached, pointing at the commit sha. + /// + /// + /// A revparse spec for the commit or branch to checkout. + /// controlling checkout behavior. + /// The that was checked out. + public Branch Checkout(string committishOrBranchSpec, CheckoutOptions options) + { + Ensure.ArgumentNotNullOrEmptyString(committishOrBranchSpec, "committishOrBranchSpec"); + Ensure.ArgumentNotNull(options, "options"); + + var handles = Proxy.git_revparse_ext(Handle, committishOrBranchSpec); + if (handles == null) + { + Ensure.GitObjectIsNotNull(null, committishOrBranchSpec); + } + + var objH = handles.Item1; + var refH = handles.Item2; + GitObject obj; + try + { + if (!refH.IsInvalid) + { + var reference = Reference.BuildFromPtr(refH, this); + if (reference.IsLocalBranch) + { + Branch branch = Branches[reference.CanonicalName]; + return Checkout(branch, options); + } + } + + obj = GitObject.BuildFrom(this, + Proxy.git_object_id(objH), + Proxy.git_object_type(objH), + PathFromRevparseSpec(committishOrBranchSpec)); + } + finally + { + objH.Dispose(); + refH.Dispose(); + } + + Commit commit = obj.DereferenceToCommit(true); + Checkout(commit.Tree, options, committishOrBranchSpec); + + return Head; + } + + /// + /// Checkout the tip commit of the specified object. If this commit is the + /// current tip of the branch, will checkout the named branch. Otherwise, will checkout the tip commit + /// as a detached HEAD. + /// + /// The to check out. + /// controlling checkout behavior. + /// The that was checked out. + public Branch Checkout(Branch branch, CheckoutOptions options) + { + Ensure.ArgumentNotNull(branch, "branch"); + Ensure.ArgumentNotNull(options, "options"); + + // Make sure this is not an unborn branch. + if (branch.Tip == null) + { + throw new UnbornBranchException("The tip of branch '{0}' is null. There's nothing to checkout.", + branch.FriendlyName); + } + + if (!branch.IsRemote && !(branch is DetachedHead) && + string.Equals(Refs[branch.CanonicalName].TargetIdentifier, branch.Tip.Id.Sha, + StringComparison.OrdinalIgnoreCase)) + { + Checkout(branch.Tip.Tree, options, branch.CanonicalName); + } + else + { + Checkout(branch.Tip.Tree, options, branch.Tip.Id.Sha); + } + + return Head; + } + + /// + /// Checkout the specified . + /// + /// Will detach the HEAD and make it point to this commit sha. + /// + /// + /// The to check out. + /// controlling checkout behavior. + /// The that was checked out. + public Branch Checkout(Commit commit, CheckoutOptions options) + { + Ensure.ArgumentNotNull(commit, "commit"); + Ensure.ArgumentNotNull(options, "options"); + + Checkout(commit.Tree, options, commit.Id.Sha); + + return Head; + } + + /// + /// Internal implementation of Checkout that expects the ID of the checkout target + /// to already be in the form of a canonical branch name or a commit ID. + /// + /// The to checkout. + /// controlling checkout behavior. + /// The spec which will be written as target in the reflog. + private void Checkout( + Tree tree, + CheckoutOptions checkoutOptions, + string refLogHeadSpec) + { + CheckoutTree(tree, null, checkoutOptions); + + Refs.MoveHeadTarget(refLogHeadSpec); + } + + /// + /// Checkout the specified tree. + /// + /// The to checkout. + /// The paths to checkout. + /// Collection of parameters controlling checkout behavior. + private void CheckoutTree( + Tree tree, + IList paths, + IConvertableToGitCheckoutOpts opts) + { + + using (GitCheckoutOptsWrapper checkoutOptionsWrapper = new GitCheckoutOptsWrapper(opts, ToFilePaths(paths))) + { + var options = checkoutOptionsWrapper.Options; + Proxy.git_checkout_tree(Handle, tree.Id, ref options); + } + } + + /// + /// Checkout the specified , reference or SHA. + /// + /// A revparse spec for the commit or branch to checkout. + /// The that was checked out. + public Branch Checkout(string commitOrBranchSpec) + { + CheckoutOptions options = new CheckoutOptions(); + return Checkout(commitOrBranchSpec, options); + } + + /// + /// Checkout the commit pointed at by the tip of the specified . + /// + /// If this commit is the current tip of the branch as it exists in the repository, the HEAD + /// will point to this branch. Otherwise, the HEAD will be detached, pointing at the commit sha. + /// + /// + /// The to check out. + /// The that was checked out. + public Branch Checkout(Branch branch) + { + CheckoutOptions options = new CheckoutOptions(); + return Checkout(branch, options); + } + + /// + /// Checkout the specified . + /// + /// Will detach the HEAD and make it point to this commit sha. + /// + /// + /// The to check out. + /// The that was checked out. + public Branch Checkout(Commit commit) + { + CheckoutOptions options = new CheckoutOptions(); + return Checkout(commit, options); + } + + /// + /// Updates specifed paths in the index and working directory with the versions from the specified branch, reference, or SHA. + /// + /// This method does not switch branches or update the current repository HEAD. + /// + /// + /// A revparse spec for the commit or branch to checkout paths from. + /// The paths to checkout. Will throw if null is passed in. Passing an empty enumeration results in nothing being checked out. + /// Collection of parameters controlling checkout behavior. + public void CheckoutPaths(string committishOrBranchSpec, IEnumerable paths, CheckoutOptions checkoutOptions) + { + Ensure.ArgumentNotNullOrEmptyString(committishOrBranchSpec, "committishOrBranchSpec"); + Ensure.ArgumentNotNull(paths, "paths"); + + var listOfPaths = paths.ToList(); + + // If there are no paths, then there is nothing to do. + if (listOfPaths.Count == 0) + { + return; + } + + Commit commit = LookupCommit(committishOrBranchSpec); + + CheckoutTree(commit.Tree, listOfPaths, checkoutOptions ?? new CheckoutOptions()); + } + + /// + /// Updates specifed paths in the index and working directory with the versions from the specified branch, reference, or SHA. + /// + /// This method does not switch branches or update the current repository HEAD. + /// + /// + /// A revparse spec for the commit or branch to checkout paths from. + /// The paths to checkout. Will throw if null is passed in. Passing an empty enumeration results in nothing being checked out. + public void CheckoutPaths(string committishOrBranchSpec, IEnumerable paths) + { + CheckoutPaths(committishOrBranchSpec, paths, null); + } + + internal string BuildRelativePathFrom(string path) + { + //TODO: To be removed when libgit2 natively implements this + if (!Path.IsPathRooted(path)) + { + return path; + } + + string normalizedPath = Path.GetFullPath(path); + + if (!PathStartsWith(normalizedPath, Info.WorkingDirectory)) + { + throw new ArgumentException(string.Format(CultureInfo.InvariantCulture, + "Unable to process file '{0}'. This file is not located under the working directory of the repository ('{1}').", + normalizedPath, + Info.WorkingDirectory)); + } + + return normalizedPath.Substring(Info.WorkingDirectory.Length); + } + } +} + diff --git a/LibGit2Sharp/Repository.Lookup.cs b/LibGit2Sharp/Repository.Lookup.cs new file mode 100644 index 000000000..94e4e1339 --- /dev/null +++ b/LibGit2Sharp/Repository.Lookup.cs @@ -0,0 +1,157 @@ +using System; +using LibGit2Sharp.Core; +using LibGit2Sharp.Core.Handles; + +namespace LibGit2Sharp +{ + public partial class Repository + { + internal GitObject Lookup(string objectish, GitObjectType type, LookUpOptions lookUpOptions) + { + Ensure.ArgumentNotNullOrEmptyString(objectish, "objectish"); + + GitObject obj; + using (GitObjectSafeHandle sh = Proxy.git_revparse_single(handle, objectish)) + { + if (sh == null) + { + if (lookUpOptions.HasFlag(LookUpOptions.ThrowWhenNoGitObjectHasBeenFound)) + { + Ensure.GitObjectIsNotNull(null, objectish); + } + + return null; + } + + GitObjectType objType = Proxy.git_object_type(sh); + + if (type != GitObjectType.Any && objType != type) + { + return null; + } + + obj = GitObject.BuildFrom(this, Proxy.git_object_id(sh), objType, PathFromRevparseSpec(objectish)); + } + + if (lookUpOptions.HasFlag(LookUpOptions.DereferenceResultToCommit)) + { + return obj.DereferenceToCommit(lookUpOptions.HasFlag(LookUpOptions.ThrowWhenCanNotBeDereferencedToACommit)); + } + + return obj; + } + + internal Commit LookupCommit(string committish) + { + return (Commit)Lookup(committish, + GitObjectType.Any, + LookUpOptions.ThrowWhenNoGitObjectHasBeenFound | + LookUpOptions.DereferenceResultToCommit | + LookUpOptions.ThrowWhenCanNotBeDereferencedToACommit); + } + + /// + /// Try to lookup an object by its sha or a reference name. + /// + /// The kind of to lookup. + /// The revparse spec for the object to lookup. + /// The retrieved , or null if none was found. + public T Lookup(string objectish) where T : GitObject + { + EnsureNoGitLink(); + + if (typeof (T) == typeof (GitObject)) + { + return (T)Lookup(objectish); + } + + return (T)Lookup(objectish, GitObject.TypeToKindMap[typeof(T)]); + } + + /// + /// Try to lookup an object by its . + /// + /// The kind of to lookup. + /// The id. + /// The retrieved , or null if none was found. + public T Lookup(ObjectId id) where T : GitObject + { + EnsureNoGitLink(); + + if (typeof(T) == typeof(GitObject)) + { + return (T)Lookup(id); + } + + return (T)Lookup(id, GitObject.TypeToKindMap[typeof(T)]); + } + + private void EnsureNoGitLink() where T : GitObject + { + if (typeof(T) != typeof(GitLink)) + { + return; + } + + throw new ArgumentException("A GitObject of type 'GitLink' cannot be looked up."); + } + + /// + /// Try to lookup an object by its . If no matching object is found, null will be returned. + /// + /// The id to lookup. + /// The or null if it was not found. + public GitObject Lookup(ObjectId id) + { + return LookupInternal(id, GitObjectType.Any, null); + } + + /// + /// Try to lookup an object by its sha or a reference canonical name. If no matching object is found, null will be returned. + /// + /// A revparse spec for the object to lookup. + /// The or null if it was not found. + public GitObject Lookup(string objectish) + { + return Lookup(objectish, GitObjectType.Any, LookUpOptions.None); + } + + /// + /// Try to lookup an object by its and . If no matching object is found, null will be returned. + /// + /// The id to lookup. + /// The kind of GitObject being looked up + /// The or null if it was not found. + public GitObject Lookup(ObjectId id, ObjectType type) + { + return LookupInternal(id, type.ToGitObjectType(), null); + } + + /// + /// Try to lookup an object by its sha or a reference canonical name and . If no matching object is found, null will be returned. + /// + /// A revparse spec for the object to lookup. + /// The kind of being looked up + /// The or null if it was not found. + public GitObject Lookup(string objectish, ObjectType type) + { + return Lookup(objectish, type.ToGitObjectType(), LookUpOptions.None); + } + + internal GitObject LookupInternal(ObjectId id, GitObjectType type, FilePath knownPath) + { + Ensure.ArgumentNotNull(id, "id"); + + using (GitObjectSafeHandle obj = Proxy.git_object_lookup(handle, id, type)) + { + if (obj == null || obj.IsInvalid) + { + return null; + } + + return GitObject.BuildFrom(this, id, Proxy.git_object_type(obj), knownPath); + } + } + } +} + diff --git a/LibGit2Sharp/Repository.Reset.cs b/LibGit2Sharp/Repository.Reset.cs new file mode 100644 index 000000000..d15cdc814 --- /dev/null +++ b/LibGit2Sharp/Repository.Reset.cs @@ -0,0 +1,71 @@ +using System; +using LibGit2Sharp.Core; + +namespace LibGit2Sharp +{ + public partial class Repository + { + /// + /// Sets the current and resets the and + /// the content of the working tree to match. + /// + /// Flavor of reset operation to perform. + public void Reset(ResetMode resetMode) + { + Reset(resetMode, "HEAD"); + } + + /// + /// Sets the current to the specified commitish and optionally resets the and + /// the content of the working tree to match. + /// + /// Flavor of reset operation to perform. + /// A revparse spec for the target commit object. + public void Reset(ResetMode resetMode, string committish) + { + Ensure.ArgumentNotNullOrEmptyString(committish, "committish"); + + Commit commit = LookUpCommit(this, committish); + + Reset(resetMode, commit); + } + + private Commit LookUpCommit(IRepository repository, string committish) + { + GitObject obj = repository.Lookup(committish); + Ensure.GitObjectIsNotNull(obj, committish); + return obj.DereferenceToCommit(true); + } + + /// + /// Sets the current to the specified commit and optionally resets the and + /// the content of the working tree to match. + /// + /// Flavor of reset operation to perform. + /// The target commit object. + public void Reset(ResetMode resetMode, Commit commit) + { + Reset(resetMode, commit, new CheckoutOptions()); + } + + /// + /// Sets to the specified commit and optionally resets the and + /// the content of the working tree to match. + /// + /// Flavor of reset operation to perform. + /// The target commit object. + /// Collection of parameters controlling checkout behavior. + public void Reset(ResetMode resetMode, Commit commit, CheckoutOptions opts) + { + Ensure.ArgumentNotNull(commit, "commit"); + Ensure.ArgumentNotNull(opts, "opts"); + + using (GitCheckoutOptsWrapper checkoutOptionsWrapper = new GitCheckoutOptsWrapper(opts)) + { + var options = checkoutOptionsWrapper.Options; + Proxy.git_reset(handle, commit.Id, resetMode, ref options); + } + } + } +} + diff --git a/LibGit2Sharp/Repository.Workdir.cs b/LibGit2Sharp/Repository.Workdir.cs new file mode 100644 index 000000000..a7c114fc1 --- /dev/null +++ b/LibGit2Sharp/Repository.Workdir.cs @@ -0,0 +1,601 @@ +using System; +using System.IO; +using System.Linq; +using System.Globalization; +using System.Collections.Generic; +using LibGit2Sharp.Core; +using LibGit2Sharp.Core.Handles; + +namespace LibGit2Sharp +{ + public partial class Repository + { + /// + /// Promotes to the staging area the latest modifications of a file in the working directory (addition, updation or removal). + /// + /// The path of the file within the working directory. + public void Stage(string path) + { + Stage(path, null); + } + + /// + /// Promotes to the staging area the latest modifications of a collection of files in the working directory (addition, updation or removal). + /// + /// The collection of paths of the files within the working directory. + public void Stage(IEnumerable paths) + { + Stage(paths, null); + } + + /// + /// Promotes to the staging area the latest modifications of a file in the working directory (addition, updation or removal). + /// + /// If this path is ignored by configuration then it will not be staged unless is unset. + /// + /// The path of the file within the working directory. + /// Determines how paths will be staged. + public void Stage(string path, StageOptions stageOptions) + { + Ensure.ArgumentNotNull(path, "path"); + + Stage(new[] { path }, stageOptions); + } + + /// + /// Promotes to the staging area the latest modifications of a collection of files in the working directory (addition, updation or removal). + /// + /// Any paths (even those listed explicitly) that are ignored by configuration will not be staged unless is unset. + /// + /// The collection of paths of the files within the working directory. + /// Determines how paths will be staged. + public void Stage(IEnumerable paths, StageOptions stageOptions) + { + Ensure.ArgumentNotNull(paths, "paths"); + + DiffModifiers diffModifiers = DiffModifiers.IncludeUntracked; + ExplicitPathsOptions explicitPathsOptions = stageOptions != null ? stageOptions.ExplicitPathsOptions : null; + + if (stageOptions != null && stageOptions.IncludeIgnored) + { + diffModifiers |= DiffModifiers.IncludeIgnored; + } + + var changes = Diff.Compare(diffModifiers, paths, explicitPathsOptions, + new CompareOptions { Similarity = SimilarityOptions.None }); + + var unexpectedTypesOfChanges = changes + .Where( + tec => tec.Status != ChangeKind.Added && + tec.Status != ChangeKind.Modified && + tec.Status != ChangeKind.Conflicted && + tec.Status != ChangeKind.Unmodified && + tec.Status != ChangeKind.Deleted).ToList(); + + if (unexpectedTypesOfChanges.Count > 0) + { + throw new InvalidOperationException( + string.Format(CultureInfo.InvariantCulture, + "Entry '{0}' bears an unexpected ChangeKind '{1}'", + unexpectedTypesOfChanges[0].Path, unexpectedTypesOfChanges[0].Status)); + } + + /* Remove files from the index that don't exist on disk */ + foreach (TreeEntryChanges treeEntryChanges in changes) + { + switch (treeEntryChanges.Status) + { + case ChangeKind.Conflicted: + if (!treeEntryChanges.Exists) + { + RemoveFromIndex(treeEntryChanges.Path); + } + break; + + case ChangeKind.Deleted: + RemoveFromIndex(treeEntryChanges.Path); + break; + + default: + continue; + } + } + + foreach (TreeEntryChanges treeEntryChanges in changes) + { + switch (treeEntryChanges.Status) + { + case ChangeKind.Added: + case ChangeKind.Modified: + AddToIndex(treeEntryChanges.Path); + break; + + case ChangeKind.Conflicted: + if (treeEntryChanges.Exists) + { + AddToIndex(treeEntryChanges.Path); + } + break; + + default: + continue; + } + } + + UpdatePhysicalIndex(); + } + + /// + /// Removes from the staging area all the modifications of a file since the latest commit (addition, updation or removal). + /// + /// The path of the file within the working directory. + public void Unstage(string path) + { + Unstage(path, null); + } + + /// + /// Removes from the staging area all the modifications of a collection of file since the latest commit (addition, updation or removal). + /// + /// The collection of paths of the files within the working directory. + public void Unstage(IEnumerable paths) + { + Unstage(paths, null); + } + + /// + /// Removes from the staging area all the modifications of a file since the latest commit (addition, updation or removal). + /// + /// The path of the file within the working directory. + /// + /// The passed will be treated as explicit paths. + /// Use these options to determine how unmatched explicit paths should be handled. + /// + public void Unstage(string path, ExplicitPathsOptions explicitPathsOptions) + { + Ensure.ArgumentNotNull(path, "path"); + + Unstage(new[] { path }, explicitPathsOptions); + } + + /// + /// Removes from the staging area all the modifications of a collection of file since the latest commit (addition, updation or removal). + /// + /// The collection of paths of the files within the working directory. + /// + /// The passed will be treated as explicit paths. + /// Use these options to determine how unmatched explicit paths should be handled. + /// + public void Unstage(IEnumerable paths, ExplicitPathsOptions explicitPathsOptions) + { + Ensure.ArgumentNotNull(paths, "paths"); + + if (Info.IsHeadUnborn) + { + var changes = Diff.Compare(null, DiffTargets.Index, paths, explicitPathsOptions, new CompareOptions { Similarity = SimilarityOptions.None }); + + Index.Replace(changes); + } + else + { + Index.Replace(Head.Tip, paths, explicitPathsOptions); + } + } + + /// + /// Removes a file from the staging area, and optionally removes it from the working directory as well. + /// + /// If the file has already been deleted from the working directory, this method will only deal + /// with promoting the removal to the staging area. + /// + /// + /// The default behavior is to remove the file from the working directory as well. + /// + /// + /// The path of the file within the working directory. + public void Remove(string path) + { + Remove(path, true, null); + } + + /// + /// Removes a file from the staging area, and optionally removes it from the working directory as well. + /// + /// If the file has already been deleted from the working directory, this method will only deal + /// with promoting the removal to the staging area. + /// + /// + /// The default behavior is to remove the file from the working directory as well. + /// + /// + /// The path of the file within the working directory. + /// True to remove the file from the working directory, False otherwise. + public void Remove(string path, bool removeFromWorkingDirectory) + { + Remove(path, removeFromWorkingDirectory, null); + } + + /// + /// Removes a collection of fileS from the staging, and optionally removes them from the working directory as well. + /// + /// If a file has already been deleted from the working directory, this method will only deal + /// with promoting the removal to the staging area. + /// + /// + /// The default behavior is to remove the files from the working directory as well. + /// + /// + /// The collection of paths of the files within the working directory. + public void Remove(IEnumerable paths) + { + Remove(paths, true, null); + } + + /// + /// Removes a collection of fileS from the staging, and optionally removes them from the working directory as well. + /// + /// If a file has already been deleted from the working directory, this method will only deal + /// with promoting the removal to the staging area. + /// + /// + /// The default behavior is to remove the files from the working directory as well. + /// + /// + /// The collection of paths of the files within the working directory. + /// True to remove the files from the working directory, False otherwise. + public void Remove(IEnumerable paths, bool removeFromWorkingDirectory) + { + Remove(paths, removeFromWorkingDirectory, null); + } + + /// + /// Retrieves the state of a file in the working directory, comparing it against the staging area and the latest commit. + /// + /// The relative path within the working directory to the file. + /// A representing the state of the parameter. + public FileStatus RetrieveStatus(string filePath) + { + Ensure.ArgumentNotNullOrEmptyString(filePath, "filePath"); + + string relativePath = this.BuildRelativePathFrom(filePath); + + return Proxy.git_status_file(Handle, relativePath); + } + + /// + /// Retrieves the state of all files in the working directory, comparing them against the staging area and the latest commit. + /// + /// A holding the state of all the files. + public RepositoryStatus RetrieveStatus() + { + Proxy.git_index_read(Index.Handle); + return new RepositoryStatus(this, null); + } + + /// + /// Retrieves the state of all files in the working directory, comparing them against the staging area and the latest commit. + /// + /// If set, the options that control the status investigation. + /// A holding the state of all the files. + public RepositoryStatus RetrieveStatus(StatusOptions options) + { + ReloadFromDisk(); + + return new RepositoryStatus(this, options); + } + + + /// + /// Moves and/or renames a file in the working directory and promotes the change to the staging area. + /// + /// The path of the file within the working directory which has to be moved/renamed. + /// The target path of the file within the working directory. + public void Move(string sourcePath, string destinationPath) + { + Move(new[] { sourcePath }, new[] { destinationPath }); + } + + /// + /// Moves and/or renames a collection of files in the working directory and promotes the changes to the staging area. + /// + /// The paths of the files within the working directory which have to be moved/renamed. + /// The target paths of the files within the working directory. + public void Move(IEnumerable sourcePaths, IEnumerable destinationPaths) + { + Ensure.ArgumentNotNull(sourcePaths, "sourcePaths"); + Ensure.ArgumentNotNull(destinationPaths, "destinationPaths"); + + //TODO: Move() should support following use cases: + // - Moving a file under a directory ('file' and 'dir' -> 'dir/file') + // - Moving a directory (and its content) under another directory ('dir1' and 'dir2' -> 'dir2/dir1/*') + + //TODO: Move() should throw when: + // - Moving a directory under a file + + IDictionary, Tuple> batch = PrepareBatch(sourcePaths, destinationPaths); + + if (batch.Count == 0) + { + throw new ArgumentNullException("sourcePaths"); + } + + foreach (KeyValuePair, Tuple> keyValuePair in batch) + { + string sourcePath = keyValuePair.Key.Item1; + string destPath = keyValuePair.Value.Item1; + + if (Directory.Exists(sourcePath) || Directory.Exists(destPath)) + { + throw new NotImplementedException(); + } + + FileStatus sourceStatus = keyValuePair.Key.Item2; + if (sourceStatus.HasAny(new Enum[] { FileStatus.Nonexistent, FileStatus.DeletedFromIndex, FileStatus.NewInWorkdir, FileStatus.DeletedFromWorkdir })) + { + throw new LibGit2SharpException("Unable to move file '{0}'. Its current status is '{1}'.", + sourcePath, + sourceStatus); + } + + FileStatus desStatus = keyValuePair.Value.Item2; + if (desStatus.HasAny(new Enum[] { FileStatus.Nonexistent, FileStatus.DeletedFromWorkdir })) + { + continue; + } + + throw new LibGit2SharpException("Unable to overwrite file '{0}'. Its current status is '{1}'.", + destPath, + desStatus); + } + + string wd = Info.WorkingDirectory; + foreach (KeyValuePair, Tuple> keyValuePair in batch) + { + string from = keyValuePair.Key.Item1; + string to = keyValuePair.Value.Item1; + + RemoveFromIndex(from); + File.Move(Path.Combine(wd, from), Path.Combine(wd, to)); + AddToIndex(to); + } + + UpdatePhysicalIndex(); + } + + /// + /// Removes a file from the staging area, and optionally removes it from the working directory as well. + /// + /// If the file has already been deleted from the working directory, this method will only deal + /// with promoting the removal to the staging area. + /// + /// + /// The default behavior is to remove the file from the working directory as well. + /// + /// + /// When not passing a , the passed path will be treated as + /// a pathspec. You can for example use it to pass the relative path to a folder inside the working directory, + /// so that all files beneath this folders, and the folder itself, will be removed. + /// + /// + /// The path of the file within the working directory. + /// True to remove the file from the working directory, False otherwise. + /// + /// The passed will be treated as an explicit path. + /// Use these options to determine how unmatched explicit paths should be handled. + /// + public void Remove(string path, bool removeFromWorkingDirectory, ExplicitPathsOptions explicitPathsOptions) + { + Ensure.ArgumentNotNull(path, "path"); + + Remove(new[] { path }, removeFromWorkingDirectory, explicitPathsOptions); + } + + /// + /// Removes a collection of fileS from the staging, and optionally removes them from the working directory as well. + /// + /// If a file has already been deleted from the working directory, this method will only deal + /// with promoting the removal to the staging area. + /// + /// + /// The default behavior is to remove the files from the working directory as well. + /// + /// + /// When not passing a , the passed paths will be treated as + /// a pathspec. You can for example use it to pass the relative paths to folders inside the working directory, + /// so that all files beneath these folders, and the folders themselves, will be removed. + /// + /// + /// The collection of paths of the files within the working directory. + /// True to remove the files from the working directory, False otherwise. + /// + /// The passed will be treated as explicit paths. + /// Use these options to determine how unmatched explicit paths should be handled. + /// + public void Remove(IEnumerable paths, bool removeFromWorkingDirectory, ExplicitPathsOptions explicitPathsOptions) + { + Ensure.ArgumentNotNullOrEmptyEnumerable(paths, "paths"); + + var pathsToDelete = paths.Where(p => Directory.Exists(Path.Combine(Info.WorkingDirectory, p))).ToList(); + var notConflictedPaths = new List(); + + foreach (var path in paths) + { + Ensure.ArgumentNotNullOrEmptyString(path, "path"); + + var conflict = Index.Conflicts[path]; + + if (conflict != null) + { + pathsToDelete.Add(RemoveFromIndex(path)); + } + else + { + notConflictedPaths.Add(path); + } + } + + if (notConflictedPaths.Count > 0) + { + pathsToDelete.AddRange(RemoveStagedItems(notConflictedPaths, removeFromWorkingDirectory, explicitPathsOptions)); + } + + if (removeFromWorkingDirectory) + { + RemoveFilesAndFolders(pathsToDelete); + } + + UpdatePhysicalIndex(); + } + + internal void ReloadFromDisk() + { + Proxy.git_index_read(Index.Handle); + } + + private void AddToIndex(string relativePath) + { + if (!Submodules.TryStage(relativePath, true)) + { + Proxy.git_index_add_bypath(Index.Handle, relativePath); + } + } + + private string RemoveFromIndex(string relativePath) + { + Proxy.git_index_remove_bypath(Index.Handle, relativePath); + + return relativePath; + } + + private void UpdatePhysicalIndex() + { + Proxy.git_index_write(Index.Handle); + } + + private Tuple BuildFrom(string path) + { + string relativePath = this.BuildRelativePathFrom(path); + return new Tuple(relativePath, RetrieveStatus(relativePath)); + } + + private static bool Enumerate(IEnumerator leftEnum, IEnumerator rightEnum) + { + bool isLeftEoF = leftEnum.MoveNext(); + bool isRightEoF = rightEnum.MoveNext(); + + if (isLeftEoF == isRightEoF) + { + return isLeftEoF; + } + + throw new ArgumentException("The collection of paths are of different lengths."); + } + + private IDictionary, Tuple> PrepareBatch(IEnumerable leftPaths, IEnumerable rightPaths) + { + IDictionary, Tuple> dic = new Dictionary, Tuple>(); + + IEnumerator leftEnum = leftPaths.GetEnumerator(); + IEnumerator rightEnum = rightPaths.GetEnumerator(); + + while (Enumerate(leftEnum, rightEnum)) + { + Tuple from = BuildFrom(leftEnum.Current); + Tuple to = BuildFrom(rightEnum.Current); + dic.Add(from, to); + } + + return dic; + } + + private void RemoveFilesAndFolders(IEnumerable pathsList) + { + string wd = Info.WorkingDirectory; + + foreach (string path in pathsList) + { + string fileName = Path.Combine(wd, path); + + if (Directory.Exists(fileName)) + { + Directory.Delete(fileName, true); + continue; + } + + if (!File.Exists(fileName)) + { + continue; + } + + File.Delete(fileName); + } + } + + private IEnumerable RemoveStagedItems(IEnumerable paths, bool removeFromWorkingDirectory = true, ExplicitPathsOptions explicitPathsOptions = null) + { + var removed = new List(); + var changes = Diff.Compare(DiffModifiers.IncludeUnmodified | DiffModifiers.IncludeUntracked, paths, explicitPathsOptions); + + foreach (var treeEntryChanges in changes) + { + var status = RetrieveStatus(treeEntryChanges.Path); + + switch (treeEntryChanges.Status) + { + case ChangeKind.Added: + case ChangeKind.Deleted: + removed.Add(RemoveFromIndex(treeEntryChanges.Path)); + break; + + case ChangeKind.Unmodified: + if (removeFromWorkingDirectory && ( + status.HasFlag(FileStatus.ModifiedInIndex) || + status.HasFlag(FileStatus.NewInIndex))) + { + throw new RemoveFromIndexException("Unable to remove file '{0}', as it has changes staged in the index. You can call the Remove() method with removeFromWorkingDirectory=false if you want to remove it from the index only.", + treeEntryChanges.Path); + } + removed.Add(RemoveFromIndex(treeEntryChanges.Path)); + continue; + + case ChangeKind.Modified: + if (status.HasFlag(FileStatus.ModifiedInWorkdir) && status.HasFlag(FileStatus.ModifiedInIndex)) + { + throw new RemoveFromIndexException("Unable to remove file '{0}', as it has staged content different from both the working directory and the HEAD.", + treeEntryChanges.Path); + } + if (removeFromWorkingDirectory) + { + throw new RemoveFromIndexException("Unable to remove file '{0}', as it has local modifications. You can call the Remove() method with removeFromWorkingDirectory=false if you want to remove it from the index only.", + treeEntryChanges.Path); + } + removed.Add(RemoveFromIndex(treeEntryChanges.Path)); + continue; + + default: + throw new RemoveFromIndexException("Unable to remove file '{0}'. Its current status is '{1}'.", + treeEntryChanges.Path, + treeEntryChanges.Status); + } + } + + return removed; + } + + /// + /// Clean the working tree by removing files that are not under version control. + /// + public void RemoveUntrackedFiles() + { + var options = new GitCheckoutOpts + { + version = 1, + checkout_strategy = CheckoutStrategy.GIT_CHECKOUT_REMOVE_UNTRACKED + | CheckoutStrategy.GIT_CHECKOUT_ALLOW_CONFLICTS, + }; + + Proxy.git_checkout_index(Handle, new NullGitObjectSafeHandle(), ref options); + } + } +} + diff --git a/LibGit2Sharp/Repository.cs b/LibGit2Sharp/Repository.cs index 0589d0112..87021670e 100644 --- a/LibGit2Sharp/Repository.cs +++ b/LibGit2Sharp/Repository.cs @@ -1,4 +1,5 @@ using System; +using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; @@ -15,7 +16,7 @@ namespace LibGit2Sharp /// A Repository is the primary interface into a git repository /// [DebuggerDisplay("{DebuggerDisplay,nq}")] - public sealed class Repository : IRepository + public partial class Repository : IRepository { private readonly bool isBare; private readonly BranchCollection branches; @@ -145,6 +146,57 @@ public Repository(string path, RepositoryOptions options) } } + private Commit RetrieveHeadCommit(IRepository repository) + { + Commit commit = repository.Head.Tip; + + Ensure.GitObjectIsNotNull(commit, "HEAD"); + + return commit; + } + + /// + /// Creates a lightweight tag with the specified name. This tag will point at the commit pointed at by the . + /// + /// The name of the tag to create. + public Tag ApplyTag(string tagName) + { + return Tags.Add(tagName, RetrieveHeadCommit(this)); + } + + /// + /// Creates a lightweight tag with the specified name. This tag will point at the . + /// + /// The name of the tag to create. + /// The revparse spec for the target object. + public Tag ApplyTag(string tagName, string objectish) + { + return Tags.Add(tagName, objectish); + } + + /// + /// Creates an annotated tag with the specified name. This tag will point at the commit pointed at by the . + /// + /// The name of the tag to create. + /// The identity of the creator of this tag. + /// The annotation message. + public Tag ApplyTag(string tagName, Signature tagger, string message) + { + return Tags.Add(tagName, RetrieveHeadCommit(this), tagger, message); + } + + /// + /// Creates an annotated tag with the specified name. This tag will point at the . + /// + /// The name of the tag to create. + /// The revparse spec for the target object. + /// The identity of the creator of this tag. + /// The annotation message. + public Tag ApplyTag(string tagName, string objectish, Signature tagger, string message) + { + return Tags.Add(tagName, objectish, tagger, message); + } + /// /// Check if parameter leads to a valid git repository. /// @@ -436,63 +488,6 @@ public static string Init(string workingDirectoryPath, string gitDirectoryPath) } } - /// - /// Try to lookup an object by its . If no matching object is found, null will be returned. - /// - /// The id to lookup. - /// The or null if it was not found. - public GitObject Lookup(ObjectId id) - { - return LookupInternal(id, GitObjectType.Any, null); - } - - /// - /// Try to lookup an object by its sha or a reference canonical name. If no matching object is found, null will be returned. - /// - /// A revparse spec for the object to lookup. - /// The or null if it was not found. - public GitObject Lookup(string objectish) - { - return Lookup(objectish, GitObjectType.Any, LookUpOptions.None); - } - - /// - /// Try to lookup an object by its and . If no matching object is found, null will be returned. - /// - /// The id to lookup. - /// The kind of GitObject being looked up - /// The or null if it was not found. - public GitObject Lookup(ObjectId id, ObjectType type) - { - return LookupInternal(id, type.ToGitObjectType(), null); - } - - /// - /// Try to lookup an object by its sha or a reference canonical name and . If no matching object is found, null will be returned. - /// - /// A revparse spec for the object to lookup. - /// The kind of being looked up - /// The or null if it was not found. - public GitObject Lookup(string objectish, ObjectType type) - { - return Lookup(objectish, type.ToGitObjectType(), LookUpOptions.None); - } - - internal GitObject LookupInternal(ObjectId id, GitObjectType type, FilePath knownPath) - { - Ensure.ArgumentNotNull(id, "id"); - - using (GitObjectSafeHandle obj = Proxy.git_object_lookup(handle, id, type)) - { - if (obj == null || obj.IsInvalid) - { - return null; - } - - return GitObject.BuildFrom(this, id, Proxy.git_object_type(obj), knownPath); - } - } - private static string PathFromRevparseSpec(string spec) { if (spec.StartsWith(":/", StringComparison.Ordinal)) @@ -509,50 +504,6 @@ private static string PathFromRevparseSpec(string spec) return (m.Groups.Count > 1) ? m.Groups[1].Value : null; } - internal GitObject Lookup(string objectish, GitObjectType type, LookUpOptions lookUpOptions) - { - Ensure.ArgumentNotNullOrEmptyString(objectish, "objectish"); - - GitObject obj; - using (GitObjectSafeHandle sh = Proxy.git_revparse_single(handle, objectish)) - { - if (sh == null) - { - if (lookUpOptions.HasFlag(LookUpOptions.ThrowWhenNoGitObjectHasBeenFound)) - { - Ensure.GitObjectIsNotNull(null, objectish); - } - - return null; - } - - GitObjectType objType = Proxy.git_object_type(sh); - - if (type != GitObjectType.Any && objType != type) - { - return null; - } - - obj = GitObject.BuildFrom(this, Proxy.git_object_id(sh), objType, PathFromRevparseSpec(objectish)); - } - - if (lookUpOptions.HasFlag(LookUpOptions.DereferenceResultToCommit)) - { - return obj.DereferenceToCommit(lookUpOptions.HasFlag(LookUpOptions.ThrowWhenCanNotBeDereferencedToACommit)); - } - - return obj; - } - - internal Commit LookupCommit(string committish) - { - return (Commit)Lookup(committish, - GitObjectType.Any, - LookUpOptions.ThrowWhenNoGitObjectHasBeenFound | - LookUpOptions.DereferenceResultToCommit | - LookUpOptions.ThrowWhenCanNotBeDereferencedToACommit); - } - /// /// Lists the Remote Repository References. /// @@ -617,6 +568,28 @@ public static string Discover(string startingPath) return discoveredPath.Native; } + /// + /// Fetch from the specified remote. + /// + /// The name of the to fetch from. + public void Fetch(string remoteName) + { + Fetch(remoteName, null); + } + + /// + /// Fetch from the specified remote. + /// + /// The name of the to fetch from. + /// controlling fetch behavior + public void Fetch(string remoteName, FetchOptions options) + { + Ensure.ArgumentNotNullOrEmptyString(remoteName, "remoteName"); + + Remote remote = Network.Remotes.RemoteForName(remoteName, true); + Network.Fetch(remote, options); + } + /// /// Clone using default options. /// @@ -820,6 +793,16 @@ private static void OnRepositoryOperationCompleted( } } + /// + /// Find where each line of a file originated. + /// + /// Path of the file to blame. + /// The blame for the file. + public BlameHunkCollection Blame(string path) + { + return Blame(path, null); + } + /// /// Find where each line of a file originated. /// @@ -831,203 +814,136 @@ public BlameHunkCollection Blame(string path, BlameOptions options) return new BlameHunkCollection(this, Handle, path, options ?? new BlameOptions()); } - /// - /// Checkout the specified , reference or SHA. - /// - /// If the committishOrBranchSpec parameter resolves to a branch name, then the checked out HEAD will - /// will point to the branch. Otherwise, the HEAD will be detached, pointing at the commit sha. - /// - /// - /// A revparse spec for the commit or branch to checkout. - /// controlling checkout behavior. - /// The that was checked out. - public Branch Checkout(string committishOrBranchSpec, CheckoutOptions options) + private ObjectId DereferenceToCommit(Repository repo, string identifier) { - Ensure.ArgumentNotNullOrEmptyString(committishOrBranchSpec, "committishOrBranchSpec"); - Ensure.ArgumentNotNull(options, "options"); + var options = LookUpOptions.DereferenceResultToCommit; - var handles = Proxy.git_revparse_ext(Handle, committishOrBranchSpec); - if (handles == null) + if (!AllowOrphanReference(repo, identifier)) { - Ensure.GitObjectIsNotNull(null, committishOrBranchSpec); + options |= LookUpOptions.ThrowWhenNoGitObjectHasBeenFound; } - var objH = handles.Item1; - var refH = handles.Item2; - GitObject obj; - try - { - if (!refH.IsInvalid) - { - var reference = Reference.BuildFromPtr(refH, this); - if (reference.IsLocalBranch) - { - Branch branch = Branches[reference.CanonicalName]; - return Checkout(branch, options); - } - } - - obj = GitObject.BuildFrom(this, - Proxy.git_object_id(objH), - Proxy.git_object_type(objH), - PathFromRevparseSpec(committishOrBranchSpec)); - } - finally - { - objH.Dispose(); - refH.Dispose(); - } + // TODO: Should we check the type? Git-log allows TagAnnotation oid as parameter. But what about Blobs and Trees? + GitObject commit = repo.Lookup(identifier, GitObjectType.Any, options); - Commit commit = obj.DereferenceToCommit(true); - Checkout(commit.Tree, options, committishOrBranchSpec); + return commit != null ? commit.Id : null; + } - return Head; + private bool AllowOrphanReference(IRepository repo, string identifier) + { + return string.Equals(identifier, "HEAD", StringComparison.Ordinal) + || string.Equals(identifier, repo.Head.CanonicalName, StringComparison.Ordinal); } - /// - /// Checkout the tip commit of the specified object. If this commit is the - /// current tip of the branch, will checkout the named branch. Otherwise, will checkout the tip commit - /// as a detached HEAD. - /// - /// The to check out. - /// controlling checkout behavior. - /// The that was checked out. - public Branch Checkout(Branch branch, CheckoutOptions options) + private ObjectId SingleCommittish(object identifier) { - Ensure.ArgumentNotNull(branch, "branch"); - Ensure.ArgumentNotNull(options, "options"); + if (ReferenceEquals(identifier, null)) + { + return null; + } - // Make sure this is not an unborn branch. - if (branch.Tip == null) + if (identifier is string) { - throw new UnbornBranchException("The tip of branch '{0}' is null. There's nothing to checkout.", - branch.FriendlyName); + return DereferenceToCommit(this, (string)identifier); } - if (!branch.IsRemote && !(branch is DetachedHead) && - string.Equals(Refs[branch.CanonicalName].TargetIdentifier, branch.Tip.Id.Sha, - StringComparison.OrdinalIgnoreCase)) + if (identifier is ObjectId) { - Checkout(branch.Tip.Tree, options, branch.CanonicalName); + return DereferenceToCommit(this, ((ObjectId)identifier).Sha); } - else + + if (identifier is Commit) { - Checkout(branch.Tip.Tree, options, branch.Tip.Id.Sha); + return ((Commit)identifier).Id; } - return Head; - } + if (identifier is TagAnnotation) + { + return DereferenceToCommit(this, ((TagAnnotation)identifier).Target.Id.Sha); + } - /// - /// Checkout the specified . - /// - /// Will detach the HEAD and make it point to this commit sha. - /// - /// - /// The to check out. - /// controlling checkout behavior. - /// The that was checked out. - public Branch Checkout(Commit commit, CheckoutOptions options) - { - Ensure.ArgumentNotNull(commit, "commit"); - Ensure.ArgumentNotNull(options, "options"); + if (identifier is Tag) + { + return DereferenceToCommit(this, ((Tag)identifier).Target.Id.Sha); + } + + var branch = identifier as Branch; + if (branch != null) + { + if (branch.Tip != null || !branch.IsCurrentRepositoryHead) + { + Ensure.GitObjectIsNotNull(branch.Tip, branch.CanonicalName); + return branch.Tip.Id; + } + } - Checkout(commit.Tree, options, commit.Id.Sha); + if (identifier is Reference) + { + return DereferenceToCommit(this, ((Reference)identifier).CanonicalName); + } - return Head; + return null; } /// - /// Internal implementation of Checkout that expects the ID of the checkout target - /// to already be in the form of a canonical branch name or a commit ID. + /// Dereferences the passed identifier to a commit. If the identifier is enumerable, all items are dereferenced. /// - /// The to checkout. - /// controlling checkout behavior. - /// The spec which will be written as target in the reflog. - private void Checkout( - Tree tree, - CheckoutOptions checkoutOptions, - string refLogHeadSpec) + /// Committish to dereference + /// If true, allow thrown exceptions to propagate. If false, exceptions will be swallowed and null returned. + /// A series of commit s which identify commit objects. + internal IEnumerable Committishes(object identifier, bool throwIfNotFound = false) { - CheckoutTree(tree, null, checkoutOptions); + var singleReturnValue = SingleCommittish(identifier); - Refs.MoveHeadTarget(refLogHeadSpec); - } + if (singleReturnValue != null) + { + yield return singleReturnValue; + yield break; + } - /// - /// Checkout the specified tree. - /// - /// The to checkout. - /// The paths to checkout. - /// Collection of parameters controlling checkout behavior. - private void CheckoutTree( - Tree tree, - IList paths, - IConvertableToGitCheckoutOpts opts) - { + if (identifier is IEnumerable) + { + foreach (object entry in (IEnumerable)identifier) + { + foreach (ObjectId oid in Committishes(entry)) + { + yield return oid; + } + } + + yield break; + } - using (GitCheckoutOptsWrapper checkoutOptionsWrapper = new GitCheckoutOptsWrapper(opts, ToFilePaths(paths))) + if (throwIfNotFound) { - var options = checkoutOptionsWrapper.Options; - Proxy.git_checkout_tree(Handle, tree.Id, ref options); + throw new LibGit2SharpException("Unexpected kind of identifier '{0}'.", identifier); } - } - /// - /// Sets the current to the specified commit and optionally resets the and - /// the content of the working tree to match. - /// - /// Flavor of reset operation to perform. - /// The target commit object. - public void Reset(ResetMode resetMode, Commit commit) - { - Reset(resetMode, commit, new CheckoutOptions()); + yield return null; } /// - /// Sets to the specified commit and optionally resets the and - /// the content of the working tree to match. + /// Dereference the identifier to a commit. If the identifier is enumerable, dereference the first element. /// - /// Flavor of reset operation to perform. - /// The target commit object. - /// Collection of parameters controlling checkout behavior. - public void Reset(ResetMode resetMode, Commit commit, CheckoutOptions opts) + /// Committish to dereference + /// An for a commit object. + internal ObjectId Committish(object identifier) { - Ensure.ArgumentNotNull(commit, "commit"); - Ensure.ArgumentNotNull(opts, "opts"); - - using (GitCheckoutOptsWrapper checkoutOptionsWrapper = new GitCheckoutOptsWrapper(opts)) - { - var options = checkoutOptionsWrapper.Options; - Proxy.git_reset(handle, commit.Id, resetMode, ref options); - } + return Committishes(identifier, true).First(); } /// - /// Updates specifed paths in the index and working directory with the versions from the specified branch, reference, or SHA. - /// - /// This method does not switch branches or update the current repository HEAD. - /// + /// Stores the content of the as a new into the repository. + /// The tip of the will be used as the parent of this new Commit. + /// Once the commit is created, the will move forward to point at it. /// - /// A revparse spec for the commit or branch to checkout paths from. - /// The paths to checkout. Will throw if null is passed in. Passing an empty enumeration results in nothing being checked out. - /// Collection of parameters controlling checkout behavior. - public void CheckoutPaths(string committishOrBranchSpec, IEnumerable paths, CheckoutOptions checkoutOptions) + /// The description of why a change was made to the repository. + /// The of who made the change. + /// The of who added the change to the repository. + /// The generated . + public Commit Commit(string message, Signature author, Signature committer) { - Ensure.ArgumentNotNullOrEmptyString(committishOrBranchSpec, "committishOrBranchSpec"); - Ensure.ArgumentNotNull(paths, "paths"); - - var listOfPaths = paths.ToList(); - - // If there are no paths, then there is nothing to do. - if (listOfPaths.Count == 0) - { - return; - } - - Commit commit = LookupCommit(committishOrBranchSpec); - - CheckoutTree(commit.Tree, listOfPaths, checkoutOptions ?? new CheckoutOptions()); + return Commit(message, author, committer, default(CommitOptions)); } /// @@ -1147,21 +1063,6 @@ private IEnumerable RetrieveParentsOfTheCommitBeingCreated(bool amendPre return parents; } - /// - /// Clean the working tree by removing files that are not under version control. - /// - public void RemoveUntrackedFiles() - { - var options = new GitCheckoutOpts - { - version = 1, - checkout_strategy = CheckoutStrategy.GIT_CHECKOUT_REMOVE_UNTRACKED - | CheckoutStrategy.GIT_CHECKOUT_ALLOW_CONFLICTS, - }; - - Proxy.git_checkout_index(Handle, new NullGitObjectSafeHandle(), ref options); - } - private void CleanupDisposableDependencies() { while (toCleanup.Count > 0) @@ -1176,6 +1077,39 @@ internal T RegisterForCleanup(T disposable) where T : IDisposable return disposable; } + /// + /// Merges changes from branch into the branch pointed at by HEAD. + /// + /// The branch to merge into the branch pointed at by HEAD. + /// The of who is performing the merge. + /// The of the merge. + public MergeResult Merge(Branch branch, Signature merger) + { + return Merge(branch, merger, null); + } + + /// + /// Merges changes from the commit into the branch pointed at by HEAD. + /// + /// The commit to merge into the branch pointed at by HEAD. + /// The of who is performing the merge. + /// The of the merge. + public MergeResult Merge(string committish, Signature merger) + { + return Merge(committish, merger, null); + } + + /// + /// Merges changes from commit into the branch pointed at by HEAD. + /// + /// The commit to merge into the branch pointed at by HEAD. + /// The of who is performing the merge. + /// The of the merge. + public MergeResult Merge(Commit commit, Signature merger) + { + return Merge(commit, merger, null); + } + /// /// Merges changes from commit into the branch pointed at by HEAD. /// @@ -1279,6 +1213,17 @@ public MergeResult MergeFetchedRefs(Signature merger, MergeOptions options) } } + /// + /// Revert the specified commit. + /// + /// The to revert. + /// The of who is performing the revert. + /// The result of the revert. + public RevertResult Revert(Commit commit, Signature reverter) + { + return Revert(commit, reverter, null); + } + /// /// Revert the specified commit. /// @@ -1380,6 +1325,17 @@ public RevertResult Revert(Commit commit, Signature reverter, RevertOptions opti return result; } + /// + /// Cherry-picks the specified commit. + /// + /// The to cherry-pick. + /// The of who is performing the cherry pick. + /// The result of the cherry pick. + public CherryPickResult CherryPick(Commit commit, Signature committer) + { + return CherryPick(commit, committer, null); + } + /// /// Cherry-picks the specified commit. /// @@ -1695,465 +1651,6 @@ internal FilePath[] ToFilePaths(IEnumerable paths) return filePaths.ToArray(); } - /// - /// Promotes to the staging area the latest modifications of a file in the working directory (addition, updation or removal). - /// - /// If this path is ignored by configuration then it will not be staged unless is unset. - /// - /// The path of the file within the working directory. - /// Determines how paths will be staged. - public void Stage(string path, StageOptions stageOptions) - { - Ensure.ArgumentNotNull(path, "path"); - - Stage(new[] { path }, stageOptions); - } - - /// - /// Promotes to the staging area the latest modifications of a collection of files in the working directory (addition, updation or removal). - /// - /// Any paths (even those listed explicitly) that are ignored by configuration will not be staged unless is unset. - /// - /// The collection of paths of the files within the working directory. - /// Determines how paths will be staged. - public void Stage(IEnumerable paths, StageOptions stageOptions) - { - Ensure.ArgumentNotNull(paths, "paths"); - - DiffModifiers diffModifiers = DiffModifiers.IncludeUntracked; - ExplicitPathsOptions explicitPathsOptions = stageOptions != null ? stageOptions.ExplicitPathsOptions : null; - - if (stageOptions != null && stageOptions.IncludeIgnored) - { - diffModifiers |= DiffModifiers.IncludeIgnored; - } - - var changes = Diff.Compare(diffModifiers, paths, explicitPathsOptions, - new CompareOptions { Similarity = SimilarityOptions.None }); - - var unexpectedTypesOfChanges = changes - .Where( - tec => tec.Status != ChangeKind.Added && - tec.Status != ChangeKind.Modified && - tec.Status != ChangeKind.Conflicted && - tec.Status != ChangeKind.Unmodified && - tec.Status != ChangeKind.Deleted).ToList(); - - if (unexpectedTypesOfChanges.Count > 0) - { - throw new InvalidOperationException( - string.Format(CultureInfo.InvariantCulture, - "Entry '{0}' bears an unexpected ChangeKind '{1}'", - unexpectedTypesOfChanges[0].Path, unexpectedTypesOfChanges[0].Status)); - } - - /* Remove files from the index that don't exist on disk */ - foreach (TreeEntryChanges treeEntryChanges in changes) - { - switch (treeEntryChanges.Status) - { - case ChangeKind.Conflicted: - if (!treeEntryChanges.Exists) - { - RemoveFromIndex(treeEntryChanges.Path); - } - break; - - case ChangeKind.Deleted: - RemoveFromIndex(treeEntryChanges.Path); - break; - - default: - continue; - } - } - - foreach (TreeEntryChanges treeEntryChanges in changes) - { - switch (treeEntryChanges.Status) - { - case ChangeKind.Added: - case ChangeKind.Modified: - AddToIndex(treeEntryChanges.Path); - break; - - case ChangeKind.Conflicted: - if (treeEntryChanges.Exists) - { - AddToIndex(treeEntryChanges.Path); - } - break; - - default: - continue; - } - } - - UpdatePhysicalIndex(); - } - - /// - /// Removes from the staging area all the modifications of a file since the latest commit (addition, updation or removal). - /// - /// The path of the file within the working directory. - /// - /// The passed will be treated as explicit paths. - /// Use these options to determine how unmatched explicit paths should be handled. - /// - public void Unstage(string path, ExplicitPathsOptions explicitPathsOptions) - { - Ensure.ArgumentNotNull(path, "path"); - - Unstage(new[] { path }, explicitPathsOptions); - } - - /// - /// Removes from the staging area all the modifications of a collection of file since the latest commit (addition, updation or removal). - /// - /// The collection of paths of the files within the working directory. - /// - /// The passed will be treated as explicit paths. - /// Use these options to determine how unmatched explicit paths should be handled. - /// - public void Unstage(IEnumerable paths, ExplicitPathsOptions explicitPathsOptions) - { - Ensure.ArgumentNotNull(paths, "paths"); - - if (Info.IsHeadUnborn) - { - var changes = Diff.Compare(null, DiffTargets.Index, paths, explicitPathsOptions, new CompareOptions { Similarity = SimilarityOptions.None }); - - Index.Replace(changes); - } - else - { - Index.Replace(Head.Tip, paths, explicitPathsOptions); - } - } - - /// - /// Moves and/or renames a file in the working directory and promotes the change to the staging area. - /// - /// The path of the file within the working directory which has to be moved/renamed. - /// The target path of the file within the working directory. - public void Move(string sourcePath, string destinationPath) - { - Move(new[] { sourcePath }, new[] { destinationPath }); - } - - /// - /// Moves and/or renames a collection of files in the working directory and promotes the changes to the staging area. - /// - /// The paths of the files within the working directory which have to be moved/renamed. - /// The target paths of the files within the working directory. - public void Move(IEnumerable sourcePaths, IEnumerable destinationPaths) - { - Ensure.ArgumentNotNull(sourcePaths, "sourcePaths"); - Ensure.ArgumentNotNull(destinationPaths, "destinationPaths"); - - //TODO: Move() should support following use cases: - // - Moving a file under a directory ('file' and 'dir' -> 'dir/file') - // - Moving a directory (and its content) under another directory ('dir1' and 'dir2' -> 'dir2/dir1/*') - - //TODO: Move() should throw when: - // - Moving a directory under a file - - IDictionary, Tuple> batch = PrepareBatch(sourcePaths, destinationPaths); - - if (batch.Count == 0) - { - throw new ArgumentNullException("sourcePaths"); - } - - foreach (KeyValuePair, Tuple> keyValuePair in batch) - { - string sourcePath = keyValuePair.Key.Item1; - string destPath = keyValuePair.Value.Item1; - - if (Directory.Exists(sourcePath) || Directory.Exists(destPath)) - { - throw new NotImplementedException(); - } - - FileStatus sourceStatus = keyValuePair.Key.Item2; - if (sourceStatus.HasAny(new Enum[] { FileStatus.Nonexistent, FileStatus.DeletedFromIndex, FileStatus.NewInWorkdir, FileStatus.DeletedFromWorkdir })) - { - throw new LibGit2SharpException("Unable to move file '{0}'. Its current status is '{1}'.", - sourcePath, - sourceStatus); - } - - FileStatus desStatus = keyValuePair.Value.Item2; - if (desStatus.HasAny(new Enum[] { FileStatus.Nonexistent, FileStatus.DeletedFromWorkdir })) - { - continue; - } - - throw new LibGit2SharpException("Unable to overwrite file '{0}'. Its current status is '{1}'.", - destPath, - desStatus); - } - - string wd = Info.WorkingDirectory; - foreach (KeyValuePair, Tuple> keyValuePair in batch) - { - string from = keyValuePair.Key.Item1; - string to = keyValuePair.Value.Item1; - - RemoveFromIndex(from); - File.Move(Path.Combine(wd, from), Path.Combine(wd, to)); - AddToIndex(to); - } - - UpdatePhysicalIndex(); - } - - /// - /// Removes a file from the staging area, and optionally removes it from the working directory as well. - /// - /// If the file has already been deleted from the working directory, this method will only deal - /// with promoting the removal to the staging area. - /// - /// - /// The default behavior is to remove the file from the working directory as well. - /// - /// - /// When not passing a , the passed path will be treated as - /// a pathspec. You can for example use it to pass the relative path to a folder inside the working directory, - /// so that all files beneath this folders, and the folder itself, will be removed. - /// - /// - /// The path of the file within the working directory. - /// True to remove the file from the working directory, False otherwise. - /// - /// The passed will be treated as an explicit path. - /// Use these options to determine how unmatched explicit paths should be handled. - /// - public void Remove(string path, bool removeFromWorkingDirectory, ExplicitPathsOptions explicitPathsOptions) - { - Ensure.ArgumentNotNull(path, "path"); - - Remove(new[] { path }, removeFromWorkingDirectory, explicitPathsOptions); - } - - /// - /// Removes a collection of fileS from the staging, and optionally removes them from the working directory as well. - /// - /// If a file has already been deleted from the working directory, this method will only deal - /// with promoting the removal to the staging area. - /// - /// - /// The default behavior is to remove the files from the working directory as well. - /// - /// - /// When not passing a , the passed paths will be treated as - /// a pathspec. You can for example use it to pass the relative paths to folders inside the working directory, - /// so that all files beneath these folders, and the folders themselves, will be removed. - /// - /// - /// The collection of paths of the files within the working directory. - /// True to remove the files from the working directory, False otherwise. - /// - /// The passed will be treated as explicit paths. - /// Use these options to determine how unmatched explicit paths should be handled. - /// - public void Remove(IEnumerable paths, bool removeFromWorkingDirectory, ExplicitPathsOptions explicitPathsOptions) - { - Ensure.ArgumentNotNullOrEmptyEnumerable(paths, "paths"); - - var pathsToDelete = paths.Where(p => Directory.Exists(Path.Combine(Info.WorkingDirectory, p))).ToList(); - var notConflictedPaths = new List(); - - foreach (var path in paths) - { - Ensure.ArgumentNotNullOrEmptyString(path, "path"); - - var conflict = Index.Conflicts[path]; - - if (conflict != null) - { - pathsToDelete.Add(RemoveFromIndex(path)); - } - else - { - notConflictedPaths.Add(path); - } - } - - if (notConflictedPaths.Count > 0) - { - pathsToDelete.AddRange(RemoveStagedItems(notConflictedPaths, removeFromWorkingDirectory, explicitPathsOptions)); - } - - if (removeFromWorkingDirectory) - { - RemoveFilesAndFolders(pathsToDelete); - } - - UpdatePhysicalIndex(); - } - - /// - /// Retrieves the state of a file in the working directory, comparing it against the staging area and the latest commit. - /// - /// The relative path within the working directory to the file. - /// A representing the state of the parameter. - public FileStatus RetrieveStatus(string filePath) - { - Ensure.ArgumentNotNullOrEmptyString(filePath, "filePath"); - - string relativePath = this.BuildRelativePathFrom(filePath); - - return Proxy.git_status_file(Handle, relativePath); - } - - /// - /// Retrieves the state of all files in the working directory, comparing them against the staging area and the latest commit. - /// - /// If set, the options that control the status investigation. - /// A holding the state of all the files. - public RepositoryStatus RetrieveStatus(StatusOptions options) - { - ReloadFromDisk(); - - return new RepositoryStatus(this, options); - } - - internal void ReloadFromDisk() - { - Proxy.git_index_read(Index.Handle); - } - - private void AddToIndex(string relativePath) - { - if (!Submodules.TryStage(relativePath, true)) - { - Proxy.git_index_add_bypath(Index.Handle, relativePath); - } - } - - private string RemoveFromIndex(string relativePath) - { - Proxy.git_index_remove_bypath(Index.Handle, relativePath); - - return relativePath; - } - - private void UpdatePhysicalIndex() - { - Proxy.git_index_write(Index.Handle); - } - - private Tuple BuildFrom(string path) - { - string relativePath = this.BuildRelativePathFrom(path); - return new Tuple(relativePath, RetrieveStatus(relativePath)); - } - - private static bool Enumerate(IEnumerator leftEnum, IEnumerator rightEnum) - { - bool isLeftEoF = leftEnum.MoveNext(); - bool isRightEoF = rightEnum.MoveNext(); - - if (isLeftEoF == isRightEoF) - { - return isLeftEoF; - } - - throw new ArgumentException("The collection of paths are of different lengths."); - } - - private IDictionary, Tuple> PrepareBatch(IEnumerable leftPaths, IEnumerable rightPaths) - { - IDictionary, Tuple> dic = new Dictionary, Tuple>(); - - IEnumerator leftEnum = leftPaths.GetEnumerator(); - IEnumerator rightEnum = rightPaths.GetEnumerator(); - - while (Enumerate(leftEnum, rightEnum)) - { - Tuple from = BuildFrom(leftEnum.Current); - Tuple to = BuildFrom(rightEnum.Current); - dic.Add(from, to); - } - - return dic; - } - - private void RemoveFilesAndFolders(IEnumerable pathsList) - { - string wd = Info.WorkingDirectory; - - foreach (string path in pathsList) - { - string fileName = Path.Combine(wd, path); - - if (Directory.Exists(fileName)) - { - Directory.Delete(fileName, true); - continue; - } - - if (!File.Exists(fileName)) - { - continue; - } - - File.Delete(fileName); - } - } - - private IEnumerable RemoveStagedItems(IEnumerable paths, bool removeFromWorkingDirectory = true, ExplicitPathsOptions explicitPathsOptions = null) - { - var removed = new List(); - var changes = Diff.Compare(DiffModifiers.IncludeUnmodified | DiffModifiers.IncludeUntracked, paths, explicitPathsOptions); - - foreach (var treeEntryChanges in changes) - { - var status = RetrieveStatus(treeEntryChanges.Path); - - switch (treeEntryChanges.Status) - { - case ChangeKind.Added: - case ChangeKind.Deleted: - removed.Add(RemoveFromIndex(treeEntryChanges.Path)); - break; - - case ChangeKind.Unmodified: - if (removeFromWorkingDirectory && ( - status.HasFlag(FileStatus.ModifiedInIndex) || - status.HasFlag(FileStatus.NewInIndex))) - { - throw new RemoveFromIndexException("Unable to remove file '{0}', as it has changes staged in the index. You can call the Remove() method with removeFromWorkingDirectory=false if you want to remove it from the index only.", - treeEntryChanges.Path); - } - removed.Add(RemoveFromIndex(treeEntryChanges.Path)); - continue; - - case ChangeKind.Modified: - if (status.HasFlag(FileStatus.ModifiedInWorkdir) && status.HasFlag(FileStatus.ModifiedInIndex)) - { - throw new RemoveFromIndexException("Unable to remove file '{0}', as it has staged content different from both the working directory and the HEAD.", - treeEntryChanges.Path); - } - if (removeFromWorkingDirectory) - { - throw new RemoveFromIndexException("Unable to remove file '{0}', as it has local modifications. You can call the Remove() method with removeFromWorkingDirectory=false if you want to remove it from the index only.", - treeEntryChanges.Path); - } - removed.Add(RemoveFromIndex(treeEntryChanges.Path)); - continue; - - default: - throw new RemoveFromIndexException("Unable to remove file '{0}'. Its current status is '{1}'.", - treeEntryChanges.Path, - treeEntryChanges.Status); - } - } - - return removed; - } - /// /// Finds the most recent annotated tag that is reachable from a commit. /// @@ -2178,6 +1675,21 @@ public string Describe(Commit commit, DescribeOptions options) return Proxy.git_describe_commit(handle, commit.Id, options); } + /// + /// Finds the most recent annotated tag that is reachable from a commit. + /// + /// If the tag points to the commit, then only the tag is shown. Otherwise, + /// it suffixes the tag name with the number of additional commits on top + /// of the tagged object and the abbreviated object name of the most recent commit. + /// + /// + /// The commit to be described. + /// A descriptive identifier for the commit based on the nearest annotated tag. + public string Describe(Commit commit) + { + return Describe(commit, new DescribeOptions()); + } + private string DebuggerDisplay { get diff --git a/LibGit2Sharp/RepositoryExtensions.cs b/LibGit2Sharp/RepositoryExtensions.cs deleted file mode 100644 index 447470bac..000000000 --- a/LibGit2Sharp/RepositoryExtensions.cs +++ /dev/null @@ -1,691 +0,0 @@ -using System; -using System.Collections; -using System.Collections.Generic; -using System.Globalization; -using System.IO; -using System.Linq; -using LibGit2Sharp.Core; - -namespace LibGit2Sharp -{ - /// - /// Provides helper overloads to a . - /// - public static class RepositoryExtensions - { - /// - /// Try to lookup an object by its sha or a reference name. - /// - /// The kind of to lookup. - /// The being looked up. - /// The revparse spec for the object to lookup. - /// The retrieved , or null if none was found. - public static T Lookup(this IRepository repository, string objectish) where T : GitObject - { - EnsureNoGitLink(); - - if (typeof (T) == typeof (GitObject)) - { - return (T)repository.Lookup(objectish); - } - - return (T)repository.Lookup(objectish, GitObject.TypeToKindMap[typeof(T)]); - } - - /// - /// Try to lookup an object by its . - /// - /// The kind of to lookup. - /// The being looked up. - /// The id. - /// The retrieved , or null if none was found. - public static T Lookup(this IRepository repository, ObjectId id) where T : GitObject - { - EnsureNoGitLink(); - - if (typeof(T) == typeof(GitObject)) - { - return (T)repository.Lookup(id); - } - - return (T)repository.Lookup(id, GitObject.TypeToKindMap[typeof(T)]); - } - - private static void EnsureNoGitLink() where T : GitObject - { - if (typeof(T) != typeof(GitLink)) - { - return; - } - - throw new ArgumentException("A GitObject of type 'GitLink' cannot be looked up."); - } - - /// - /// Creates a lightweight tag with the specified name. This tag will point at the commit pointed at by the . - /// - /// The being worked with. - /// The name of the tag to create. - public static Tag ApplyTag(this IRepository repository, string tagName) - { - return repository.Tags.Add(tagName, RetrieveHeadCommit(repository)); - } - - /// - /// Creates a lightweight tag with the specified name. This tag will point at the . - /// - /// The being worked with. - /// The name of the tag to create. - /// The revparse spec for the target object. - public static Tag ApplyTag(this IRepository repository, string tagName, string objectish) - { - return repository.Tags.Add(tagName, objectish); - } - - /// - /// Creates an annotated tag with the specified name. This tag will point at the commit pointed at by the . - /// - /// The being worked with. - /// The name of the tag to create. - /// The identity of the creator of this tag. - /// The annotation message. - public static Tag ApplyTag(this IRepository repository, string tagName, Signature tagger, string message) - { - return repository.Tags.Add(tagName, RetrieveHeadCommit(repository), tagger, message); - } - - private static Commit RetrieveHeadCommit(IRepository repository) - { - Commit commit = repository.Head.Tip; - - Ensure.GitObjectIsNotNull(commit, "HEAD"); - - return commit; - } - - /// - /// Creates an annotated tag with the specified name. This tag will point at the . - /// - /// The being worked with. - /// The name of the tag to create. - /// The revparse spec for the target object. - /// The identity of the creator of this tag. - /// The annotation message. - public static Tag ApplyTag(this IRepository repository, string tagName, string objectish, Signature tagger, string message) - { - return repository.Tags.Add(tagName, objectish, tagger, message); - } - - /// - /// Creates a branch with the specified name. This branch will point at the commit pointed at by the . - /// - /// The being worked with. - /// The name of the branch to create. - public static Branch CreateBranch(this IRepository repository, string branchName) - { - var head = repository.Head; - var reflogName = head is DetachedHead ? head.Tip.Sha : head.FriendlyName; - - return CreateBranch(repository, branchName, reflogName); - } - - /// - /// Creates a branch with the specified name. This branch will point at . - /// - /// The being worked with. - /// The name of the branch to create. - /// The commit which should be pointed at by the Branch. - public static Branch CreateBranch(this IRepository repository, string branchName, Commit target) - { - return repository.Branches.Add(branchName, target); - } - - /// - /// Creates a branch with the specified name. This branch will point at the commit pointed at by the . - /// - /// The being worked with. - /// The name of the branch to create. - /// The revparse spec for the target commit. - public static Branch CreateBranch(this IRepository repository, string branchName, string committish) - { - return repository.Branches.Add(branchName, committish); - } - - /// - /// Sets the current and resets the and - /// the content of the working tree to match. - /// - /// The being worked with. - /// Flavor of reset operation to perform. - public static void Reset(this IRepository repository, ResetMode resetMode) - { - repository.Reset(resetMode, "HEAD"); - } - - /// - /// Sets the current to the specified commitish and optionally resets the and - /// the content of the working tree to match. - /// - /// The being worked with. - /// Flavor of reset operation to perform. - /// A revparse spec for the target commit object. - public static void Reset(this IRepository repository, ResetMode resetMode, string committish) - { - Ensure.ArgumentNotNullOrEmptyString(committish, "committish"); - - Commit commit = LookUpCommit(repository, committish); - - repository.Reset(resetMode, commit); - } - - private static Commit LookUpCommit(IRepository repository, string committish) - { - GitObject obj = repository.Lookup(committish); - Ensure.GitObjectIsNotNull(obj, committish); - return obj.DereferenceToCommit(true); - } - - /// - /// Stores the content of the as a new into the repository. - /// The tip of the will be used as the parent of this new Commit. - /// Once the commit is created, the will move forward to point at it. - /// - /// The being worked with. - /// The description of why a change was made to the repository. - /// The of who made the change. - /// The of who added the change to the repository. - /// The generated . - public static Commit Commit(this IRepository repository, string message, Signature author, Signature committer) - { - return repository.Commit(message, author, committer, default(CommitOptions)); - } - - /// - /// Fetch from the specified remote. - /// - /// The being worked with. - /// The name of the to fetch from. - public static void Fetch(this IRepository repository, string remoteName) - { - repository.Fetch(remoteName, null); - } - - /// - /// Fetch from the specified remote. - /// - /// The being worked with. - /// The name of the to fetch from. - /// controlling fetch behavior - public static void Fetch(this IRepository repository, string remoteName, FetchOptions options) - { - Ensure.ArgumentNotNull(repository, "repository"); - Ensure.ArgumentNotNullOrEmptyString(remoteName, "remoteName"); - - Remote remote = repository.Network.Remotes.RemoteForName(remoteName, true); - repository.Network.Fetch(remote, options); - } - - /// - /// Checkout the specified , reference or SHA. - /// - /// The being worked with. - /// A revparse spec for the commit or branch to checkout. - /// The that was checked out. - public static Branch Checkout(this IRepository repository, string commitOrBranchSpec) - { - CheckoutOptions options = new CheckoutOptions(); - return repository.Checkout(commitOrBranchSpec, options); - } - - /// - /// Checkout the commit pointed at by the tip of the specified . - /// - /// If this commit is the current tip of the branch as it exists in the repository, the HEAD - /// will point to this branch. Otherwise, the HEAD will be detached, pointing at the commit sha. - /// - /// - /// The being worked with. - /// The to check out. - /// The that was checked out. - public static Branch Checkout(this IRepository repository, Branch branch) - { - CheckoutOptions options = new CheckoutOptions(); - return repository.Checkout(branch, options); - } - - /// - /// Checkout the specified . - /// - /// Will detach the HEAD and make it point to this commit sha. - /// - /// - /// The being worked with. - /// The to check out. - /// The that was checked out. - public static Branch Checkout(this IRepository repository, Commit commit) - { - CheckoutOptions options = new CheckoutOptions(); - return repository.Checkout(commit, options); - } - - internal static string BuildRelativePathFrom(this Repository repo, string path) - { - //TODO: To be removed when libgit2 natively implements this - if (!Path.IsPathRooted(path)) - { - return path; - } - - string normalizedPath = Path.GetFullPath(path); - - if (!repo.PathStartsWith(normalizedPath, repo.Info.WorkingDirectory)) - { - throw new ArgumentException(string.Format(CultureInfo.InvariantCulture, - "Unable to process file '{0}'. This file is not located under the working directory of the repository ('{1}').", - normalizedPath, - repo.Info.WorkingDirectory)); - } - - return normalizedPath.Substring(repo.Info.WorkingDirectory.Length); - } - - private static ObjectId DereferenceToCommit(Repository repo, string identifier) - { - var options = LookUpOptions.DereferenceResultToCommit; - - if (!AllowOrphanReference(repo, identifier)) - { - options |= LookUpOptions.ThrowWhenNoGitObjectHasBeenFound; - } - - // TODO: Should we check the type? Git-log allows TagAnnotation oid as parameter. But what about Blobs and Trees? - GitObject commit = repo.Lookup(identifier, GitObjectType.Any, options); - - return commit != null ? commit.Id : null; - } - - private static bool AllowOrphanReference(IRepository repo, string identifier) - { - return string.Equals(identifier, "HEAD", StringComparison.Ordinal) - || string.Equals(identifier, repo.Head.CanonicalName, StringComparison.Ordinal); - } - - private static ObjectId SingleCommittish(this Repository repo, object identifier) - { - if (ReferenceEquals(identifier, null)) - { - return null; - } - - if (identifier is string) - { - return DereferenceToCommit(repo, (string)identifier); - } - - if (identifier is ObjectId) - { - return DereferenceToCommit(repo, ((ObjectId)identifier).Sha); - } - - if (identifier is Commit) - { - return ((Commit)identifier).Id; - } - - if (identifier is TagAnnotation) - { - return DereferenceToCommit(repo, ((TagAnnotation)identifier).Target.Id.Sha); - } - - if (identifier is Tag) - { - return DereferenceToCommit(repo, ((Tag)identifier).Target.Id.Sha); - } - - var branch = identifier as Branch; - if (branch != null) - { - if (branch.Tip != null || !branch.IsCurrentRepositoryHead) - { - Ensure.GitObjectIsNotNull(branch.Tip, branch.CanonicalName); - return branch.Tip.Id; - } - } - - if (identifier is Reference) - { - return DereferenceToCommit(repo, ((Reference)identifier).CanonicalName); - } - - return null; - } - - /// - /// Dereferences the passed identifier to a commit. If the identifier is enumerable, all items are dereferenced. - /// - /// Repository to search - /// Committish to dereference - /// If true, allow thrown exceptions to propagate. If false, exceptions will be swallowed and null returned. - /// A series of commit s which identify commit objects. - internal static IEnumerable Committishes(this Repository repo, object identifier, bool throwIfNotFound = false) - { - var singleReturnValue = repo.SingleCommittish(identifier); - - if (singleReturnValue != null) - { - yield return singleReturnValue; - yield break; - } - - if (identifier is IEnumerable) - { - foreach (object entry in (IEnumerable)identifier) - { - foreach (ObjectId oid in Committishes(repo, entry)) - { - yield return oid; - } - } - - yield break; - } - - if (throwIfNotFound) - { - throw new LibGit2SharpException("Unexpected kind of identifier '{0}'.", identifier); - } - - yield return null; - } - - /// - /// Dereference the identifier to a commit. If the identifier is enumerable, dereference the first element. - /// - /// The to search - /// Committish to dereference - /// An for a commit object. - internal static ObjectId Committish(this Repository repo, object identifier) - { - return repo.Committishes(identifier, true).First(); - } - - /// - /// Merges changes from branch into the branch pointed at by HEAD. - /// - /// The being worked with. - /// The branch to merge into the branch pointed at by HEAD. - /// The of who is performing the merge. - /// The of the merge. - public static MergeResult Merge(this IRepository repository, Branch branch, Signature merger) - { - return repository.Merge(branch, merger, null); - } - - /// - /// Merges changes from the commit into the branch pointed at by HEAD. - /// - /// The being worked with. - /// The commit to merge into the branch pointed at by HEAD. - /// The of who is performing the merge. - /// The of the merge. - public static MergeResult Merge(this IRepository repository, string committish, Signature merger) - { - return repository.Merge(committish, merger, null); - } - - /// - /// Checkout the tip commit of the specified object. If this commit is the - /// current tip of the branch, will checkout the named branch. Otherwise, will checkout the tip commit - /// as a detached HEAD. - /// - /// The being worked with. - /// The to check out. - /// controlling checkout behavior. - /// The that was checked out. - public static Branch Checkout(this IRepository repository, Branch branch, CheckoutOptions options) - { - return repository.Checkout(branch, options); - } - - /// - /// Checkout the specified . - /// - /// Will detach the HEAD and make it point to this commit sha. - /// - /// - /// The being worked with. - /// The to check out. - /// controlling checkout behavior. - /// The that was checked out. - public static Branch Checkout(this IRepository repository, Commit commit, CheckoutOptions options) - { - return repository.Checkout(commit, options); - } - - /// - /// Checkout the specified , reference or SHA. - /// - /// If the committishOrBranchSpec parameter resolves to a branch name, then the checked out HEAD will - /// will point to the branch. Otherwise, the HEAD will be detached, pointing at the commit sha. - /// - /// - /// The being worked with. - /// A revparse spec for the commit or branch to checkout. - /// controlling checkout behavior. - /// The that was checked out. - public static Branch Checkout(this IRepository repository, string committishOrBranchSpec, CheckoutOptions options) - { - return repository.Checkout(committishOrBranchSpec, options); - } - - /// - /// Updates specifed paths in the index and working directory with the versions from the specified branch, reference, or SHA. - /// - /// This method does not switch branches or update the current repository HEAD. - /// - /// - /// The being worked with. - /// A revparse spec for the commit or branch to checkout paths from. - /// The paths to checkout. Will throw if null is passed in. Passing an empty enumeration results in nothing being checked out. - public static void CheckoutPaths(this IRepository repository, string committishOrBranchSpec, IEnumerable paths) - { - repository.CheckoutPaths(committishOrBranchSpec, paths, null); - } - - /// - /// Sets the current to the specified commit and optionally resets the and - /// the content of the working tree to match. - /// - /// The being worked with. - /// Flavor of reset operation to perform. - /// The target commit object. - public static void Reset(this IRepository repository, ResetMode resetMode, Commit commit) - { - repository.Reset(resetMode, commit); - } - - /// - /// Find where each line of a file originated. - /// - /// The being worked with. - /// Path of the file to blame. - /// The blame for the file. - public static BlameHunkCollection Blame(this IRepository repository, string path) - { - return repository.Blame(path, null); - } - - /// - /// Cherry-picks the specified commit. - /// - /// The being worked with. - /// The to cherry-pick. - /// The of who is performing the cherry pick. - /// The result of the cherry pick. - public static CherryPickResult CherryPick(this IRepository repository, Commit commit, Signature committer) - { - return repository.CherryPick(commit, committer, null); - } - - /// - /// Merges changes from commit into the branch pointed at by HEAD. - /// - /// The being worked with. - /// The commit to merge into the branch pointed at by HEAD. - /// The of who is performing the merge. - /// The of the merge. - public static MergeResult Merge(this IRepository repository, Commit commit, Signature merger) - { - return repository.Merge(commit, merger, null); - } - - /// - /// Revert the specified commit. - /// - /// The being worked with. - /// The to revert. - /// The of who is performing the revert. - /// The result of the revert. - public static RevertResult Revert(this IRepository repository, Commit commit, Signature reverter) - { - return repository.Revert(commit, reverter, null); - } - - /// - /// Promotes to the staging area the latest modifications of a file in the working directory (addition, updation or removal). - /// - /// The being worked with. - /// The path of the file within the working directory. - public static void Stage(this IRepository repository, string path) - { - repository.Stage(path, null); - } - - /// - /// Promotes to the staging area the latest modifications of a collection of files in the working directory (addition, updation or removal). - /// - /// The being worked with. - /// The collection of paths of the files within the working directory. - public static void Stage(this IRepository repository, IEnumerable paths) - { - repository.Stage(paths, null); - } - - /// - /// Removes from the staging area all the modifications of a file since the latest commit (addition, updation or removal). - /// - /// The being worked with. - /// The path of the file within the working directory. - public static void Unstage(this IRepository repository, string path) - { - repository.Unstage(path, null); - } - - /// - /// Removes from the staging area all the modifications of a collection of file since the latest commit (addition, updation or removal). - /// - /// The being worked with. - /// The collection of paths of the files within the working directory. - public static void Unstage(this IRepository repository, IEnumerable paths) - { - repository.Unstage(paths, null); - } - - /// - /// Removes a file from the staging area, and optionally removes it from the working directory as well. - /// - /// If the file has already been deleted from the working directory, this method will only deal - /// with promoting the removal to the staging area. - /// - /// - /// The default behavior is to remove the file from the working directory as well. - /// - /// - /// The being worked with. - /// The path of the file within the working directory. - public static void Remove(this IRepository repository, string path) - { - repository.Remove(path, true, null); - } - - /// - /// Removes a file from the staging area, and optionally removes it from the working directory as well. - /// - /// If the file has already been deleted from the working directory, this method will only deal - /// with promoting the removal to the staging area. - /// - /// - /// The default behavior is to remove the file from the working directory as well. - /// - /// - /// The being worked with. - /// The path of the file within the working directory. - /// True to remove the file from the working directory, False otherwise. - public static void Remove(this IRepository repository, string path, bool removeFromWorkingDirectory) - { - repository.Remove(path, removeFromWorkingDirectory, null); - } - - /// - /// Removes a collection of fileS from the staging, and optionally removes them from the working directory as well. - /// - /// If a file has already been deleted from the working directory, this method will only deal - /// with promoting the removal to the staging area. - /// - /// - /// The default behavior is to remove the files from the working directory as well. - /// - /// - /// The being worked with. - /// The collection of paths of the files within the working directory. - public static void Remove(this IRepository repository, IEnumerable paths) - { - repository.Remove(paths, true, null); - } - - /// - /// Removes a collection of fileS from the staging, and optionally removes them from the working directory as well. - /// - /// If a file has already been deleted from the working directory, this method will only deal - /// with promoting the removal to the staging area. - /// - /// - /// The default behavior is to remove the files from the working directory as well. - /// - /// - /// The being worked with. - /// The collection of paths of the files within the working directory. - /// True to remove the files from the working directory, False otherwise. - public static void Remove(this IRepository repository, IEnumerable paths, bool removeFromWorkingDirectory) - { - repository.Remove(paths, removeFromWorkingDirectory, null); - } - - /// - /// Retrieves the state of all files in the working directory, comparing them against the staging area and the latest commit. - /// - /// A holding the state of all the files. - /// The being worked with. - public static RepositoryStatus RetrieveStatus(this IRepository repository) - { - Proxy.git_index_read(repository.Index.Handle); - return new RepositoryStatus((Repository)repository, null); - } - - /// - /// Finds the most recent annotated tag that is reachable from a commit. - /// - /// If the tag points to the commit, then only the tag is shown. Otherwise, - /// it suffixes the tag name with the number of additional commits on top - /// of the tagged object and the abbreviated object name of the most recent commit. - /// - /// - /// The being worked with. - /// The commit to be described. - /// A descriptive identifier for the commit based on the nearest annotated tag. - public static string Describe(this IRepository repository, Commit commit) - { - return repository.Describe(commit, new DescribeOptions()); - } - } -}