using System; using System.Collections; using System.Collections.Generic; using System.Globalization; using System.Linq; using LibGit2Sharp.Core; using LibGit2Sharp.Core.Handles; namespace LibGit2Sharp { /// /// A log of commits in a /// public sealed class CommitLog : IQueryableCommitLog { private readonly Repository repo; private readonly CommitFilter queryFilter; /// /// Initializes a new instance of the class. /// The commits will be enumerated according in reverse chronological order. /// /// The repository. internal CommitLog(Repository repo) : this(repo, new CommitFilter()) { } /// /// Initializes a new instance of the class. /// /// The repository. /// The filter to use in querying commits internal CommitLog(Repository repo, CommitFilter queryFilter) { this.repo = repo; this.queryFilter = queryFilter; } /// /// Gets the current sorting strategy applied when enumerating the log /// public CommitSortStrategies SortedBy { get { return queryFilter.SortBy; } } #region IEnumerable Members /// /// Returns an enumerator that iterates through the log. /// /// An object that can be used to iterate through the log. public IEnumerator GetEnumerator() { return new CommitEnumerator(repo, queryFilter); } /// /// Returns an enumerator that iterates through the log. /// /// An object that can be used to iterate through the log. IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } #endregion /// /// Returns the list of commits of the repository matching the specified . /// /// The options used to control which commits will be returned. /// A list of commits, ready to be enumerated. public ICommitLog QueryBy(CommitFilter filter) { Ensure.ArgumentNotNull(filter, "filter"); Ensure.ArgumentNotNull(filter.Since, "filter.Since"); Ensure.ArgumentNotNullOrEmptyString(filter.Since.ToString(), "filter.Since"); return new CommitLog(repo, filter); } /// /// Find the best possible merge base given two s. /// /// The first . /// The second . /// The merge base or null if none found. [Obsolete("This method will be removed in the next release. Please use ObjectDatabase.FindMergeBase() instead.")] public Commit FindMergeBase(Commit first, Commit second) { return repo.ObjectDatabase.FindMergeBase(first, second); } /// /// Find the best possible merge base given two or more according to the . /// /// The s for which to find the merge base. /// The strategy to leverage in order to find the merge base. /// The merge base or null if none found. [Obsolete("This method will be removed in the next release. Please use ObjectDatabase.FindMergeBase() instead.")] public Commit FindMergeBase(IEnumerable commits, MergeBaseFindingStrategy strategy) { return repo.ObjectDatabase.FindMergeBase(commits, strategy); } private class CommitEnumerator : IEnumerator { private readonly Repository repo; private readonly RevWalkerSafeHandle handle; private ObjectId currentOid; public CommitEnumerator(Repository repo, CommitFilter filter) { this.repo = repo; handle = Proxy.git_revwalk_new(repo.Handle); repo.RegisterForCleanup(handle); Sort(filter.SortBy); Push(filter.SinceList); Hide(filter.UntilList); FirstParentOnly(filter.FirstParentOnly); } #region IEnumerator Members public Commit Current { get { return repo.Lookup(currentOid); } } object IEnumerator.Current { get { return Current; } } public bool MoveNext() { ObjectId id = Proxy.git_revwalk_next(handle); if (id == null) { return false; } currentOid = id; return true; } public void Reset() { Proxy.git_revwalk_reset(handle); } #endregion public void Dispose() { Dispose(true); GC.SuppressFinalize(this); } private void Dispose(bool disposing) { handle.SafeDispose(); } private delegate void HidePushSignature(RevWalkerSafeHandle handle, ObjectId id); private void InternalHidePush(IList identifier, HidePushSignature hidePush) { IEnumerable oids = repo.Committishes(identifier).TakeWhile(o => o != null); foreach (ObjectId actedOn in oids) { hidePush(handle, actedOn); } } private void Push(IList identifier) { InternalHidePush(identifier, Proxy.git_revwalk_push); } private void Hide(IList identifier) { if (identifier == null) { return; } InternalHidePush(identifier, Proxy.git_revwalk_hide); } private void Sort(CommitSortStrategies options) { Proxy.git_revwalk_sorting(handle, options); } private void FirstParentOnly(bool firstParent) { if (firstParent) { Proxy.git_revwalk_simplify_first_parent(handle); } } } } /// /// Determines the finding strategy of merge base. /// public enum MergeBaseFindingStrategy { /// /// Compute the best common ancestor between some commits to use in a three-way merge. /// /// When more than two commits are provided, the computation is performed between the first commit and a hypothetical merge commit across all the remaining commits. /// /// Standard, /// /// Compute the best common ancestor of all supplied commits, in preparation for an n-way merge. /// Octopus, } }