diff --git a/src/GitVersionCore.Tests/ConfigProviderTests.cs b/src/GitVersionCore.Tests/ConfigProviderTests.cs
index 008862d405..e4dfdd5710 100644
--- a/src/GitVersionCore.Tests/ConfigProviderTests.cs
+++ b/src/GitVersionCore.Tests/ConfigProviderTests.cs
@@ -322,7 +322,7 @@ public void WarnOnObsoleteIsDevelopBranchConfigurationSetting()
LegacyConfigNotifier.Notify(new StringReader(text));
});
- var expecedMessage = string.Format("'is-develop' is deprecated, use 'track-release-branches' instead.");
- exception.Message.ShouldContain(expecedMessage);
+ const string expectedMessage = @"'is-develop' is deprecated, use 'track-release-branches' instead.";
+ exception.Message.ShouldContain(expectedMessage);
}
}
diff --git a/src/GitVersionCore.Tests/IntegrationTests/FeatureBranchScenarios.cs b/src/GitVersionCore.Tests/IntegrationTests/FeatureBranchScenarios.cs
index 5e65ab2c53..1867740b0c 100644
--- a/src/GitVersionCore.Tests/IntegrationTests/FeatureBranchScenarios.cs
+++ b/src/GitVersionCore.Tests/IntegrationTests/FeatureBranchScenarios.cs
@@ -514,9 +514,8 @@ public void PickUpVersionFromMasterMarkedWithIsTracksReleaseBranches()
fixture.AssertFullSemver(config, "0.10.1-pre.1+1");
// create a feature branch from master and verify the version
- // TODO this will pass once default becomes inherit
- //fixture.BranchTo("MyFeatureD");
- //fixture.AssertFullSemver(config, "0.10.1-MyFeatureD.1+1");
+ fixture.BranchTo("MyFeatureD");
+ fixture.AssertFullSemver(config, "0.10.1-MyFeatureD.1+1");
}
}
}
diff --git a/src/GitVersionCore/BranchConfigurationCalculator.cs b/src/GitVersionCore/BranchConfigurationCalculator.cs
index 14f314cf94..e6e05d3489 100644
--- a/src/GitVersionCore/BranchConfigurationCalculator.cs
+++ b/src/GitVersionCore/BranchConfigurationCalculator.cs
@@ -12,9 +12,9 @@ public class BranchConfigurationCalculator
///
/// Gets the for the current commit.
///
- public static BranchConfig GetBranchConfiguration(Commit currentCommit, IRepository repository, bool onlyEvaluateTrackedBranches, Config config, Branch currentBranch, IList excludedInheritBranches = null)
+ public static BranchConfig GetBranchConfiguration(GitVersionContext context, Branch targetBranch, IList excludedInheritBranches = null)
{
- var matchingBranches = LookupBranchConfiguration(config, currentBranch).ToArray();
+ var matchingBranches = LookupBranchConfiguration(context.FullConfiguration, targetBranch).ToArray();
BranchConfig branchConfiguration;
if (matchingBranches.Length > 0)
@@ -25,7 +25,7 @@ public static BranchConfig GetBranchConfiguration(Commit currentCommit, IReposit
{
Logger.WriteWarning(string.Format(
"Multiple branch configurations match the current branch branchName of '{0}'. Using the first matching configuration, '{1}'. Matching configurations include: '{2}'",
- currentBranch.FriendlyName,
+ targetBranch.FriendlyName,
branchConfiguration.Name,
string.Join("', '", matchingBranches.Select(b => b.Name))));
}
@@ -34,14 +34,14 @@ public static BranchConfig GetBranchConfiguration(Commit currentCommit, IReposit
{
Logger.WriteInfo(string.Format(
"No branch configuration found for branch {0}, falling back to default configuration",
- currentBranch.FriendlyName));
+ targetBranch.FriendlyName));
branchConfiguration = new BranchConfig { Name = string.Empty };
- ConfigurationProvider.ApplyBranchDefaults(config, branchConfiguration, "");
+ ConfigurationProvider.ApplyBranchDefaults(context.FullConfiguration, branchConfiguration, "");
}
return branchConfiguration.Increment == IncrementStrategy.Inherit ?
- InheritBranchConfiguration(onlyEvaluateTrackedBranches, repository, currentCommit, currentBranch, branchConfiguration, config, excludedInheritBranches) :
+ InheritBranchConfiguration(context, targetBranch, branchConfiguration, excludedInheritBranches) :
branchConfiguration;
}
@@ -60,16 +60,18 @@ static IEnumerable LookupBranchConfiguration([NotNull] Config conf
return config.Branches.Where(b => Regex.IsMatch(currentBranch.FriendlyName, "^" + b.Value.Regex, RegexOptions.IgnoreCase)).Select(kvp => kvp.Value);
}
- static BranchConfig InheritBranchConfiguration(bool onlyEvaluateTrackedBranches, IRepository repository, Commit currentCommit, Branch currentBranch, BranchConfig branchConfiguration, Config config, IList excludedInheritBranches)
+ static BranchConfig InheritBranchConfiguration(GitVersionContext context, Branch targetBranch, BranchConfig branchConfiguration, IList excludedInheritBranches)
{
+ var repository = context.Repository;
+ var config = context.FullConfiguration;
using (Logger.IndentLog("Attempting to inherit branch configuration from parent branch"))
{
- var excludedBranches = new[] { currentBranch };
+ var excludedBranches = new[] { targetBranch };
// Check if we are a merge commit. If so likely we are a pull request
- var parentCount = currentCommit.Parents.Count();
+ var parentCount = context.CurrentCommit.Parents.Count();
if (parentCount == 2)
{
- excludedBranches = CalculateWhenMultipleParents(repository, currentCommit, ref currentBranch, excludedBranches);
+ excludedBranches = CalculateWhenMultipleParents(repository, context.CurrentCommit, ref targetBranch, excludedBranches);
}
if (excludedInheritBranches == null)
@@ -83,14 +85,19 @@ static BranchConfig InheritBranchConfiguration(bool onlyEvaluateTrackedBranches,
return (branchConfig.Length != 1) || (branchConfig.Length == 1 && branchConfig[0].Increment == IncrementStrategy.Inherit);
}).ToList();
}
- excludedBranches.ToList().ForEach(excludedInheritBranches.Add);
+ // Add new excluded branches.
+ foreach (var excludedBranch in excludedBranches.ExcludingBranches(excludedInheritBranches))
+ {
+ excludedInheritBranches.Add(excludedBranch);
+ }
var branchesToEvaluate = repository.Branches.Except(excludedInheritBranches).ToList();
- var branchPoint = currentBranch.FindCommitBranchWasBranchedFrom(repository, excludedInheritBranches.ToArray());
+ var branchPoint = context.RepositoryMetadataProvider
+ .FindCommitBranchWasBranchedFrom(targetBranch, excludedInheritBranches.ToArray());
List possibleParents;
if (branchPoint == BranchCommit.Empty)
{
- possibleParents = currentCommit.GetBranchesContainingCommit(repository, branchesToEvaluate, true)
+ possibleParents = context.RepositoryMetadataProvider.GetBranchesContainingCommit(context.CurrentCommit, branchesToEvaluate, true)
// It fails to inherit Increment branch configuration if more than 1 parent;
// therefore no point to get more than 2 parents
.Take(2)
@@ -98,10 +105,12 @@ static BranchConfig InheritBranchConfiguration(bool onlyEvaluateTrackedBranches,
}
else
{
- var branches = branchPoint.Commit.GetBranchesContainingCommit(repository, branchesToEvaluate, true).ToList();
+ var branches = context.RepositoryMetadataProvider
+ .GetBranchesContainingCommit(branchPoint.Commit, branchesToEvaluate, true).ToList();
if (branches.Count > 1)
{
- var currentTipBranches = currentCommit.GetBranchesContainingCommit(repository, branchesToEvaluate, true).ToList();
+ var currentTipBranches = context.RepositoryMetadataProvider
+ .GetBranchesContainingCommit(context.CurrentCommit, branchesToEvaluate, true).ToList();
possibleParents = branches.Except(currentTipBranches).ToList();
}
else
@@ -114,7 +123,7 @@ static BranchConfig InheritBranchConfiguration(bool onlyEvaluateTrackedBranches,
if (possibleParents.Count == 1)
{
- var branchConfig = GetBranchConfiguration(currentCommit, repository, onlyEvaluateTrackedBranches, config, possibleParents[0], excludedInheritBranches);
+ var branchConfig = GetBranchConfiguration(context, possibleParents[0], excludedInheritBranches);
return new BranchConfig(branchConfiguration)
{
Increment = branchConfig.Increment,
@@ -144,7 +153,17 @@ static BranchConfig InheritBranchConfiguration(bool onlyEvaluateTrackedBranches,
var branchName = chosenBranch.FriendlyName;
Logger.WriteWarning(errorMessage + Environment.NewLine + Environment.NewLine + "Falling back to " + branchName + " branch config");
- var inheritingBranchConfig = GetBranchConfiguration(currentCommit, repository, onlyEvaluateTrackedBranches, config, chosenBranch);
+ // To prevent infinite loops, make sure that a new branch was chosen.
+ if (targetBranch.IsSameBranch(chosenBranch))
+ {
+ Logger.WriteWarning("Fallback branch wants to inherit Increment branch configuration from itself. Using patch increment instead.");
+ return new BranchConfig(branchConfiguration)
+ {
+ Increment = IncrementStrategy.Patch
+ };
+ }
+
+ var inheritingBranchConfig = GetBranchConfiguration(context, chosenBranch, excludedInheritBranches);
return new BranchConfig(branchConfiguration)
{
Increment = inheritingBranchConfig.Increment,
diff --git a/src/GitVersionCore/Configuration/ConfigurationProvider.cs b/src/GitVersionCore/Configuration/ConfigurationProvider.cs
index 4801c7d879..3d803d3fd3 100644
--- a/src/GitVersionCore/Configuration/ConfigurationProvider.cs
+++ b/src/GitVersionCore/Configuration/ConfigurationProvider.cs
@@ -2,7 +2,6 @@ namespace GitVersion
{
using Configuration.Init.Wizard;
using GitVersion.Helpers;
- using System;
using System.IO;
using System.Linq;
using System.Text;
diff --git a/src/GitVersionCore/GitRepoMetadataProvider.cs b/src/GitVersionCore/GitRepoMetadataProvider.cs
new file mode 100644
index 0000000000..4f329e22f9
--- /dev/null
+++ b/src/GitVersionCore/GitRepoMetadataProvider.cs
@@ -0,0 +1,231 @@
+using JetBrains.Annotations;
+using LibGit2Sharp;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+namespace GitVersion
+{
+ public class GitRepoMetadataProvider
+ {
+ private Dictionary> mergeBaseCommitsCache;
+ private Dictionary, MergeBaseData> mergeBaseCache;
+ private Dictionary> semanticVersionTagsOnBranchCache;
+ private IRepository Repository { get; set; }
+ const string missingTipFormat = "{0} has no tip. Please see http://example.com/docs for information on how to fix this.";
+
+ public GitRepoMetadataProvider(IRepository repository)
+ {
+ mergeBaseCache = new Dictionary, MergeBaseData>();
+ mergeBaseCommitsCache = new Dictionary>();
+ semanticVersionTagsOnBranchCache = new Dictionary>();
+ this.Repository = repository;
+ }
+
+ public IEnumerable GetVersionTagsOnBranch(Branch branch, string tagPrefixRegex)
+ {
+ if (semanticVersionTagsOnBranchCache.ContainsKey(branch))
+ {
+ Logger.WriteDebug(string.Format("Cache hit for version tags on branch '{0}", branch.CanonicalName));
+ return semanticVersionTagsOnBranchCache[branch];
+ }
+
+ using (Logger.IndentLog(string.Format("Getting version tags from branch '{0}'.", branch.CanonicalName)))
+ {
+ var tags = this.Repository.Tags.Select(t => t).ToList();
+
+ var versionTags = this.Repository.Commits.QueryBy(new CommitFilter
+ {
+ IncludeReachableFrom = branch.Tip
+ })
+ .SelectMany(c => tags.Where(t => c.Sha == t.Target.Sha).SelectMany(t =>
+ {
+ SemanticVersion semver;
+ if (SemanticVersion.TryParse(t.FriendlyName, tagPrefixRegex, out semver))
+ return new[] { semver };
+ return new SemanticVersion[0];
+ })).ToList();
+
+ semanticVersionTagsOnBranchCache.Add(branch, versionTags);
+ return versionTags;
+ }
+ }
+
+ // TODO Should we cache this?
+ public IEnumerable GetBranchesContainingCommit([NotNull] Commit commit, IList branches, bool onlyTrackedBranches)
+ {
+ if (commit == null)
+ {
+ throw new ArgumentNullException("commit");
+ }
+
+ using (Logger.IndentLog(string.Format("Getting branches containing the commit '{0}'.", commit.Id)))
+ {
+ var directBranchHasBeenFound = false;
+ Logger.WriteInfo("Trying to find direct branches.");
+ // TODO: It looks wasteful looping through the branches twice. Can't these loops be merged somehow? @asbjornu
+ foreach (var branch in branches)
+ {
+ if (branch.Tip != null && branch.Tip.Sha != commit.Sha || (onlyTrackedBranches && !branch.IsTracking))
+ {
+ continue;
+ }
+
+ directBranchHasBeenFound = true;
+ Logger.WriteInfo(string.Format("Direct branch found: '{0}'.", branch.FriendlyName));
+ yield return branch;
+ }
+
+ if (directBranchHasBeenFound)
+ {
+ yield break;
+ }
+
+ Logger.WriteInfo(string.Format("No direct branches found, searching through {0} branches.", onlyTrackedBranches ? "tracked" : "all"));
+ foreach (var branch in branches.Where(b => onlyTrackedBranches && !b.IsTracking))
+ {
+ Logger.WriteInfo(string.Format("Searching for commits reachable from '{0}'.", branch.FriendlyName));
+
+ var commits = this.Repository.Commits.QueryBy(new CommitFilter
+ {
+ IncludeReachableFrom = branch
+ }).Where(c => c.Sha == commit.Sha);
+
+ if (!commits.Any())
+ {
+ Logger.WriteInfo(string.Format("The branch '{0}' has no matching commits.", branch.FriendlyName));
+ continue;
+ }
+
+ Logger.WriteInfo(string.Format("The branch '{0}' has a matching commit.", branch.FriendlyName));
+ yield return branch;
+ }
+ }
+ }
+
+ ///
+ /// Find the merge base of the two branches, i.e. the best common ancestor of the two branches' tips.
+ ///
+ public Commit FindMergeBase(Branch branch, Branch otherBranch)
+ {
+ var key = Tuple.Create(branch, otherBranch);
+
+ if (mergeBaseCache.ContainsKey(key))
+ {
+ Logger.WriteDebug(string.Format(
+ "Cache hit for merge base between '{0}' and '{1}'.",
+ branch.FriendlyName, otherBranch.FriendlyName));
+ return mergeBaseCache[key].MergeBase;
+ }
+
+ using (Logger.IndentLog(string.Format("Finding merge base between '{0}' and '{1}'.", branch.FriendlyName, otherBranch.FriendlyName)))
+ {
+ // Otherbranch tip is a forward merge
+ var commitToFindCommonBase = otherBranch.Tip;
+ var commit = branch.Tip;
+ if (otherBranch.Tip.Parents.Contains(commit))
+ {
+ commitToFindCommonBase = otherBranch.Tip.Parents.First();
+ }
+
+ var findMergeBase = this.Repository.ObjectDatabase.FindMergeBase(commit, commitToFindCommonBase);
+ if (findMergeBase != null)
+ {
+ Logger.WriteInfo(string.Format("Found merge base of {0}", findMergeBase.Sha));
+ // We do not want to include merge base commits which got forward merged into the other branch
+ bool mergeBaseWasForwardMerge;
+ do
+ {
+ // Now make sure that the merge base is not a forward merge
+ mergeBaseWasForwardMerge = otherBranch.Commits
+ .SkipWhile(c => c != commitToFindCommonBase)
+ .TakeWhile(c => c != findMergeBase)
+ .Any(c => c.Parents.Contains(findMergeBase));
+ if (mergeBaseWasForwardMerge)
+ {
+ var second = commitToFindCommonBase.Parents.First();
+ var mergeBase = this.Repository.ObjectDatabase.FindMergeBase(commit, second);
+ if (mergeBase == findMergeBase)
+ {
+ break;
+ }
+ findMergeBase = mergeBase;
+ Logger.WriteInfo(string.Format("Merge base was due to a forward merge, next merge base is {0}", findMergeBase));
+ }
+ } while (mergeBaseWasForwardMerge);
+ }
+
+ // Store in cache.
+ mergeBaseCache.Add(key, new MergeBaseData(branch, otherBranch, this.Repository, findMergeBase));
+
+ return findMergeBase;
+ }
+ }
+
+ ///
+ /// Find the commit where the given branch was branched from another branch.
+ /// If there are multiple such commits and branches, returns the newest commit.
+ ///
+ public BranchCommit FindCommitBranchWasBranchedFrom([NotNull] Branch branch, params Branch[] excludedBranches)
+ {
+ if (branch == null)
+ {
+ throw new ArgumentNullException("branch");
+ }
+
+ using (Logger.IndentLog(string.Format("Finding branch source of '{0}'", branch.FriendlyName)))
+ {
+ if (branch.Tip == null)
+ {
+ Logger.WriteWarning(string.Format(missingTipFormat, branch.FriendlyName));
+ return BranchCommit.Empty;
+ }
+
+ return GetMergeCommitsForBranch(branch).ExcludingBranches(excludedBranches).FirstOrDefault(b => !branch.IsSameBranch(b.Branch));
+ }
+ }
+
+ List GetMergeCommitsForBranch(Branch branch)
+ {
+ if (mergeBaseCommitsCache.ContainsKey(branch))
+ {
+ Logger.WriteDebug(string.Format(
+ "Cache hit for getting merge commits for branch {0}.",
+ branch.CanonicalName));
+ return mergeBaseCommitsCache[branch];
+ }
+
+ var branchMergeBases = Repository.Branches.Select(otherBranch =>
+ {
+ if (otherBranch.Tip == null)
+ {
+ Logger.WriteWarning(string.Format(missingTipFormat, otherBranch.FriendlyName));
+ return BranchCommit.Empty;
+ }
+
+ var findMergeBase = FindMergeBase(branch, otherBranch);
+ return new BranchCommit(findMergeBase, otherBranch);
+ }).Where(b => b.Commit != null).OrderByDescending(b => b.Commit.Committer.When).ToList();
+ mergeBaseCommitsCache.Add(branch, branchMergeBases);
+
+ return branchMergeBases;
+ }
+
+ private class MergeBaseData
+ {
+ public Branch Branch { get; private set; }
+ public Branch OtherBranch { get; private set; }
+ public IRepository Repository { get; private set; }
+
+ public Commit MergeBase { get; private set; }
+
+ public MergeBaseData(Branch branch, Branch otherBranch, IRepository repository, Commit mergeBase)
+ {
+ Branch = branch;
+ OtherBranch = otherBranch;
+ Repository = repository;
+ MergeBase = mergeBase;
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/GitVersionCore/GitVersionCacheKeyFactory.cs b/src/GitVersionCore/GitVersionCacheKeyFactory.cs
index f81dea37ee..a918d67001 100644
--- a/src/GitVersionCore/GitVersionCacheKeyFactory.cs
+++ b/src/GitVersionCore/GitVersionCacheKeyFactory.cs
@@ -123,7 +123,15 @@ static List CalculateDirectoryContents(string root)
private static string GetRepositorySnapshotHash(GitPreparer gitPreparer)
{
- var repositorySnapshot = gitPreparer.WithRepository(repo => string.Join(":", repo.Head.CanonicalName, repo.Head.Tip.Sha));
+ var repositorySnapshot = gitPreparer.WithRepository(repo => {
+ var head = repo.Head;
+ if (head.Tip == null)
+ {
+ return head.CanonicalName;
+ }
+ var hash = string.Join(":", head.CanonicalName, head.Tip.Sha);
+ return hash;
+ });
return GetHash(repositorySnapshot);
}
diff --git a/src/GitVersionCore/GitVersionContext.cs b/src/GitVersionCore/GitVersionContext.cs
index 1e8c869866..1b5f57e195 100644
--- a/src/GitVersionCore/GitVersionContext.cs
+++ b/src/GitVersionCore/GitVersionContext.cs
@@ -17,6 +17,7 @@ public GitVersionContext(IRepository repository, Config configuration, bool isFo
public GitVersionContext(IRepository repository, Branch currentBranch, Config configuration, bool onlyEvaluateTrackedBranches = true, string commitId = null)
{
Repository = repository;
+ RepositoryMetadataProvider = new GitRepoMetadataProvider(repository);
FullConfiguration = configuration;
OnlyEvaluateTrackedBranches = onlyEvaluateTrackedBranches;
@@ -46,7 +47,7 @@ public GitVersionContext(IRepository repository, Branch currentBranch, Config co
if (currentBranch.IsDetachedHead())
{
- CurrentBranch = CurrentCommit.GetBranchesContainingCommit(repository, repository.Branches.ToList(), OnlyEvaluateTrackedBranches).OnlyOrDefault() ?? currentBranch;
+ CurrentBranch = RepositoryMetadataProvider.GetBranchesContainingCommit(CurrentCommit, repository.Branches.ToList(), OnlyEvaluateTrackedBranches).OnlyOrDefault() ?? currentBranch;
}
else
{
@@ -78,10 +79,11 @@ public GitVersionContext(IRepository repository, Branch currentBranch, Config co
public Branch CurrentBranch { get; private set; }
public Commit CurrentCommit { get; private set; }
public bool IsCurrentCommitTagged { get; private set; }
+ public GitRepoMetadataProvider RepositoryMetadataProvider { get; private set; }
void CalculateEffectiveConfiguration()
{
- var currentBranchConfig = BranchConfigurationCalculator.GetBranchConfiguration(CurrentCommit, Repository, OnlyEvaluateTrackedBranches, FullConfiguration, CurrentBranch);
+ var currentBranchConfig = BranchConfigurationCalculator.GetBranchConfiguration(this, CurrentBranch);
if (!currentBranchConfig.VersioningMode.HasValue)
throw new Exception(string.Format("Configuration value for 'Versioning mode' for branch {0} has no value. (this should not happen, please report an issue)", currentBranchConfig.Name));
diff --git a/src/GitVersionCore/GitVersionCore.csproj b/src/GitVersionCore/GitVersionCore.csproj
index 57d35345e1..ef715fea33 100644
--- a/src/GitVersionCore/GitVersionCore.csproj
+++ b/src/GitVersionCore/GitVersionCore.csproj
@@ -122,6 +122,7 @@
+
diff --git a/src/GitVersionCore/GitVersionFinder.cs b/src/GitVersionCore/GitVersionFinder.cs
index 926a421933..4163d23a62 100644
--- a/src/GitVersionCore/GitVersionFinder.cs
+++ b/src/GitVersionCore/GitVersionFinder.cs
@@ -8,7 +8,10 @@ public class GitVersionFinder
{
public SemanticVersion FindVersion(GitVersionContext context)
{
- Logger.WriteInfo(string.Format("Running against branch: {0} ({1})", context.CurrentBranch.FriendlyName, context.CurrentCommit.Sha));
+ Logger.WriteInfo(string.Format(
+ "Running against branch: {0} ({1})",
+ context.CurrentBranch.FriendlyName,
+ context.CurrentCommit == null ? "-" : context.CurrentCommit.Sha));
EnsureMainTopologyConstraints(context);
var filePath = Path.Combine(context.Repository.GetRepositoryDirectory(), "NextVersion.txt");
diff --git a/src/GitVersionCore/LibGitExtensions.cs b/src/GitVersionCore/LibGitExtensions.cs
index 130cc91c76..3f009112f0 100644
--- a/src/GitVersionCore/LibGitExtensions.cs
+++ b/src/GitVersionCore/LibGitExtensions.cs
@@ -15,112 +15,10 @@ public static DateTimeOffset When(this Commit commit)
return commit.Committer.When;
}
- public static IEnumerable GetVersionTagsOnBranch(this Branch branch, IRepository repository, string tagPrefixRegex)
- {
- var tags = repository.Tags.Select(t => t).ToList();
-
- return repository.Commits.QueryBy(new CommitFilter
- {
- IncludeReachableFrom = branch.Tip
- })
- .SelectMany(c => tags.Where(t => c.Sha == t.Target.Sha).SelectMany(t =>
- {
- SemanticVersion semver;
- if (SemanticVersion.TryParse(t.FriendlyName, tagPrefixRegex, out semver))
- return new [] { semver };
- return new SemanticVersion[0];
- }));
- }
-
- ///
- /// Find the commit where the given branch was branched from another branch.
- /// If there are multiple such commits and branches, returns the newest commit.
- ///
- public static BranchCommit FindCommitBranchWasBranchedFrom([NotNull] this Branch branch, IRepository repository, params Branch[] excludedBranches)
- {
- const string missingTipFormat = "{0} has no tip. Please see http://example.com/docs for information on how to fix this.";
-
- if (branch == null)
- {
- throw new ArgumentNullException("branch");
- }
-
- using (Logger.IndentLog(string.Format("Finding branch source of '{0}'", branch.FriendlyName)))
- {
- if (branch.Tip == null)
- {
- Logger.WriteWarning(string.Format(missingTipFormat, branch.FriendlyName));
- return BranchCommit.Empty;
- }
-
- var otherBranches = repository.Branches
- .ExcludingBranches(excludedBranches)
- .Where(b => !IsSameBranch(branch, b));
- var mergeBases = otherBranches.Select(otherBranch =>
- {
- if (otherBranch.Tip == null)
- {
- Logger.WriteWarning(string.Format(missingTipFormat, otherBranch.FriendlyName));
- return BranchCommit.Empty;
- }
-
- var findMergeBase = FindMergeBase(branch, otherBranch, repository);
- return new BranchCommit(findMergeBase,otherBranch);
- }).Where(b => b.Commit != null).OrderByDescending(b => b.Commit.Committer.When);
-
- return mergeBases.FirstOrDefault();
- }
- }
-
- ///
- /// Find the merge base of the two branches, i.e. the best common ancestor of the two branches' tips.
- ///
- public static Commit FindMergeBase(this Branch branch, Branch otherBranch, IRepository repository)
- {
- using (Logger.IndentLog(string.Format("Finding merge base between '{0}' and '{1}'.", branch.FriendlyName, otherBranch.FriendlyName)))
- {
- // Otherbranch tip is a forward merge
- var commitToFindCommonBase = otherBranch.Tip;
- var commit = branch.Tip;
- if (otherBranch.Tip.Parents.Contains(commit))
- {
- commitToFindCommonBase = otherBranch.Tip.Parents.First();
- }
-
- var findMergeBase = repository.ObjectDatabase.FindMergeBase(commit, commitToFindCommonBase);
- if (findMergeBase != null)
- {
- Logger.WriteInfo(string.Format("Found merge base of {0}", findMergeBase.Sha));
- // We do not want to include merge base commits which got forward merged into the other branch
- bool mergeBaseWasForwardMerge;
- do
- {
- // Now make sure that the merge base is not a forward merge
- mergeBaseWasForwardMerge = otherBranch.Commits
- .SkipWhile(c => c != commitToFindCommonBase)
- .TakeWhile(c => c != findMergeBase)
- .Any(c => c.Parents.Contains(findMergeBase));
- if (mergeBaseWasForwardMerge)
- {
- var second = commitToFindCommonBase.Parents.First();
- var mergeBase = repository.ObjectDatabase.FindMergeBase(commit, second);
- if (mergeBase == findMergeBase)
- {
- break;
- }
- findMergeBase = mergeBase;
- Logger.WriteInfo(string.Format("Merge base was due to a forward merge, next merge base is {0}", findMergeBase));
- }
- } while (mergeBaseWasForwardMerge);
- }
- return findMergeBase;
- }
- }
-
///
/// Checks if the two branch objects refer to the same branch (have the same friendly name).
///
- public static bool IsSameBranch(Branch branch, Branch otherBranch)
+ public static bool IsSameBranch(this Branch branch, Branch otherBranch)
{
// For each branch, fixup the friendly name if the branch is remote.
var otherBranchFriendlyName = otherBranch.IsRemote ?
@@ -136,78 +34,27 @@ public static bool IsSameBranch(Branch branch, Branch otherBranch)
///
/// Exclude the given branches (by value equality according to friendly name).
///
- public static IEnumerable ExcludingBranches([NotNull] this IEnumerable branches, [NotNull] IEnumerable branchesToExclude)
+ public static IEnumerable ExcludingBranches([NotNull] this IEnumerable branches, [NotNull] IEnumerable branchesToExclude)
{
- return branches.Where(b => branchesToExclude.All(bte => !IsSameBranch(b, bte)));
+ return branches.Where(b => branchesToExclude.All(bte => !IsSameBranch(b.Branch, bte)));
}
- public static IEnumerable GetBranchesContainingCommit([NotNull] this Commit commit, IRepository repository, IList branches, bool onlyTrackedBranches)
+ ///
+ /// Exclude the given branches (by value equality according to friendly name).
+ ///
+ public static IEnumerable ExcludingBranches([NotNull] this IEnumerable branches, [NotNull] IEnumerable branchesToExclude)
{
- if (commit == null)
- {
- throw new ArgumentNullException("commit");
- }
-
- using (Logger.IndentLog(string.Format("Getting branches containing the commit '{0}'.", commit.Id)))
- {
- var directBranchHasBeenFound = false;
- Logger.WriteInfo("Trying to find direct branches.");
- // TODO: It looks wasteful looping through the branches twice. Can't these loops be merged somehow? @asbjornu
- foreach (var branch in branches)
- {
- if (branch.Tip != null && branch.Tip.Sha != commit.Sha || (onlyTrackedBranches && !branch.IsTracking))
- {
- continue;
- }
-
- directBranchHasBeenFound = true;
- Logger.WriteInfo(string.Format("Direct branch found: '{0}'.", branch.FriendlyName));
- yield return branch;
- }
-
- if (directBranchHasBeenFound)
- {
- yield break;
- }
-
- Logger.WriteInfo(string.Format("No direct branches found, searching through {0} branches.", onlyTrackedBranches ? "tracked" : "all"));
- foreach (var branch in branches.Where(b => onlyTrackedBranches && !b.IsTracking))
- {
- Logger.WriteInfo(string.Format("Searching for commits reachable from '{0}'.", branch.FriendlyName));
-
- var commits = repository.Commits.QueryBy(new CommitFilter
- {
- IncludeReachableFrom = branch
- }).Where(c => c.Sha == commit.Sha);
-
- if (!commits.Any())
- {
- Logger.WriteInfo(string.Format("The branch '{0}' has no matching commits.", branch.FriendlyName));
- continue;
- }
-
- Logger.WriteInfo(string.Format("The branch '{0}' has a matching commit.", branch.FriendlyName));
- yield return branch;
- }
- }
+ return branches.Where(b => branchesToExclude.All(bte => !IsSameBranch(b, bte)));
}
- private static Dictionary _cachedPeeledTarget = new Dictionary();
-
public static GitObject PeeledTarget(this Tag tag)
{
- GitObject cachedTarget;
- if(_cachedPeeledTarget.TryGetValue(tag.Target.Sha, out cachedTarget))
- {
- return cachedTarget;
- }
var target = tag.Target;
while (target is TagAnnotation)
{
target = ((TagAnnotation)(target)).Target;
}
- _cachedPeeledTarget.Add(tag.Target.Sha, target);
return target;
}
@@ -261,7 +108,7 @@ public static void CheckoutFilesIfExist(this IRepository repository, params stri
}
var fullPath = Path.Combine(repository.GetRepositoryDirectory(), fileName);
- using (var stream = ((Blob) treeEntry.Target).GetContentStream())
+ using (var stream = ((Blob)treeEntry.Target).GetContentStream())
{
using (var streamReader = new BinaryReader(stream))
{
diff --git a/src/GitVersionCore/VersionCalculation/BaseVersionCalculators/VersionInBranchNameBaseVersionStrategy.cs b/src/GitVersionCore/VersionCalculation/BaseVersionCalculators/VersionInBranchNameBaseVersionStrategy.cs
index 89a6ff7cf8..db2546e06a 100644
--- a/src/GitVersionCore/VersionCalculation/BaseVersionCalculators/VersionInBranchNameBaseVersionStrategy.cs
+++ b/src/GitVersionCore/VersionCalculation/BaseVersionCalculators/VersionInBranchNameBaseVersionStrategy.cs
@@ -25,7 +25,7 @@ public IEnumerable GetVersions(GitVersionContext context, string ta
var versionInBranch = GetVersionInBranch(branchName, tagPrefixRegex);
if (versionInBranch != null)
{
- var commitBranchWasBranchedFrom = currentBranch.FindCommitBranchWasBranchedFrom(repository);
+ var commitBranchWasBranchedFrom = context.RepositoryMetadataProvider.FindCommitBranchWasBranchedFrom(currentBranch);
var branchNameOverride = branchName.RegexReplace("[-/]" + versionInBranch.Item1, string.Empty);
yield return new BaseVersion(context, "Version in branch name", false, versionInBranch.Item2, commitBranchWasBranchedFrom.Commit, branchNameOverride);
}
diff --git a/src/GitVersionCore/VersionCalculation/DevelopVersionStrategy.cs b/src/GitVersionCore/VersionCalculation/DevelopVersionStrategy.cs
index 71e1591bb5..99cea3298d 100644
--- a/src/GitVersionCore/VersionCalculation/DevelopVersionStrategy.cs
+++ b/src/GitVersionCore/VersionCalculation/DevelopVersionStrategy.cs
@@ -66,7 +66,7 @@ private IEnumerable ReleaseBranchBaseVersions(GitVersionContext con
// Need to drop branch overrides and give a bit more context about
// where this version came from
var source1 = "Release branch exists -> " + baseVersion.Source;
- return new BaseVersion(context,
+ return new BaseVersion(context,
source1,
baseVersion.ShouldIncrement,
baseVersion.SemanticVersion,
@@ -84,7 +84,7 @@ IEnumerable GetReleaseVersion(GitVersionContext context, Branch rel
var repository = context.Repository;
// Find the commit where the child branch was created.
- var baseSource = releaseBranch.FindMergeBase(context.CurrentBranch, repository);
+ var baseSource = context.RepositoryMetadataProvider.FindMergeBase(releaseBranch, context.CurrentBranch);
if (baseSource == context.CurrentCommit)
{
// Ignore the branch if it has no commits.
diff --git a/src/GitVersionCore/VersionCalculation/NextVersionCalculator.cs b/src/GitVersionCore/VersionCalculation/NextVersionCalculator.cs
index 03ac5325eb..d06bbeb358 100644
--- a/src/GitVersionCore/VersionCalculation/NextVersionCalculator.cs
+++ b/src/GitVersionCore/VersionCalculation/NextVersionCalculator.cs
@@ -258,8 +258,8 @@ void UpdatePreReleaseTag(GitVersionContext context, SemanticVersion semanticVers
int? number = null;
- var lastTag = context.CurrentBranch
- .GetVersionTagsOnBranch(context.Repository, context.Configuration.GitTagPrefix)
+ var lastTag = context.RepositoryMetadataProvider
+ .GetVersionTagsOnBranch(context.CurrentBranch, context.Configuration.GitTagPrefix)
.FirstOrDefault(v => v.PreReleaseTag.Name == tagToUse);
if (lastTag != null &&
diff --git a/src/GitVersionTask.Tests/GitVersionTaskDirectoryTests.cs b/src/GitVersionTask.Tests/GitVersionTaskDirectoryTests.cs
index 497b59526d..9ba0c96cfc 100644
--- a/src/GitVersionTask.Tests/GitVersionTaskDirectoryTests.cs
+++ b/src/GitVersionTask.Tests/GitVersionTaskDirectoryTests.cs
@@ -61,6 +61,7 @@ public void Finds_GitDirectory_In_Parent()
}
catch (Exception ex)
{
+ // TODO I think this test is wrong.. It throws a different exception
// `RepositoryNotFoundException` means that it couldn't find the .git directory,
// any other exception means that the .git was found but there was some other issue that this test doesn't care about.
Assert.IsNotAssignableFrom(ex);