/// <summary> /// Find the commit where the given branch was branched from another branch. /// If there are multiple such commits and branches, tries to guess based on commit histories. /// </summary> public BranchCommit FindCommitBranchWasBranchedFrom(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); } var possibleBranches = GetMergeCommitsForBranch(branch, excludedBranches) .Where(b => !branch.IsSameBranch(b.Branch)) .ToList(); if (possibleBranches.Count > 1) { var first = possibleBranches.First(); Logger.WriteInfo($"Multiple source branches have been found, picking the first one ({first.Branch.FriendlyName}).\n" + "This may result in incorrect commit counting.\nOptions were:\n " + string.Join(", ", possibleBranches.Select(b => b.Branch.FriendlyName))); return(first); } return(possibleBranches.SingleOrDefault()); } }
/// <summary> /// Find the commit where the given branch was branched from another branch. /// If there are multiple such commits and branches, tries to guess based on commit histories. /// </summary> public BranchCommit FindCommitBranchWasBranchedFrom(Branch branch, params Branch[] excludedBranches) { if (branch == null) { throw new ArgumentNullException(nameof(branch)); } using (log.IndentLog($"Finding branch source of '{branch.FriendlyName}'")) { if (branch.Tip == null) { log.Warning(string.Format(MissingTipFormat, branch.FriendlyName)); return(BranchCommit.Empty); } var possibleBranches = GetMergeCommitsForBranch(branch, excludedBranches) .Where(b => !branch.IsSameBranch(b.Branch)) .ToList(); if (possibleBranches.Count > 1) { var first = possibleBranches.First(); log.Info($"Multiple source branches have been found, picking the first one ({first.Branch.FriendlyName}).{System.Environment.NewLine}" + $"This may result in incorrect commit counting.{System.Environment.NewLine}Options were:{System.Environment.NewLine}" + string.Join(", ", possibleBranches.Select(b => b.Branch.FriendlyName))); return(first); } return(possibleBranches.SingleOrDefault()); } }
/// <summary> /// Find the commit where the given branch was branched from another branch. /// If there are multiple such commits and branches, returns the newest commit. /// </summary> 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))); } }
static BranchConfig InheritBranchConfiguration(GitVersionContext context, Branch targetBranch, BranchConfig branchConfiguration, IList <Branch> excludedInheritBranches) { var repository = context.Repository; var config = context.FullConfiguration; using (Logger.IndentLog("Attempting to inherit branch configuration from parent branch")) { var excludedBranches = new[] { targetBranch }; // Check if we are a merge commit. If so likely we are a pull request var parentCount = context.CurrentCommit.Parents.Count(); if (parentCount == 2) { excludedBranches = CalculateWhenMultipleParents(repository, context.CurrentCommit, ref targetBranch, excludedBranches); } if (excludedInheritBranches == null) { excludedInheritBranches = repository.Branches.Where(b => { var branchConfig = config.GetConfigForBranch(b.FriendlyName); return(branchConfig != null && branchConfig.Increment == IncrementStrategy.Inherit); }).ToList(); } // Add new excluded branches. foreach (var excludedBranch in excludedBranches.ExcludingBranches(excludedInheritBranches)) { excludedInheritBranches.Add(excludedBranch); } var branchesToEvaluate = repository.Branches.Except(excludedInheritBranches).ToList(); var branchPoint = context.RepositoryMetadataProvider .FindCommitBranchWasBranchedFrom(targetBranch, excludedInheritBranches.ToArray()); List <Branch> possibleParents; if (branchPoint == BranchCommit.Empty) { 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) .ToList(); } else { var branches = context.RepositoryMetadataProvider .GetBranchesContainingCommit(branchPoint.Commit, branchesToEvaluate, true).ToList(); if (branches.Count > 1) { var currentTipBranches = context.RepositoryMetadataProvider .GetBranchesContainingCommit(context.CurrentCommit, branchesToEvaluate, true).ToList(); possibleParents = branches.Except(currentTipBranches).ToList(); } else { possibleParents = branches; } } Logger.WriteInfo("Found possible parent branches: " + string.Join(", ", possibleParents.Select(p => p.FriendlyName))); if (possibleParents.Count == 1) { var branchConfig = GetBranchConfiguration(context, possibleParents[0], excludedInheritBranches); return(new BranchConfig(branchConfiguration) { Increment = branchConfig.Increment, PreventIncrementOfMergedBranchVersion = branchConfig.PreventIncrementOfMergedBranchVersion, // If we are inheriting from develop then we should behave like develop TracksReleaseBranches = branchConfig.TracksReleaseBranches }); } // If we fail to inherit it is probably because the branch has been merged and we can't do much. So we will fall back to develop's config // if develop exists and master if not string errorMessage; if (possibleParents.Count == 0) { errorMessage = "Failed to inherit Increment branch configuration, no branches found."; } else { errorMessage = "Failed to inherit Increment branch configuration, ended up with: " + string.Join(", ", possibleParents.Select(p => p.FriendlyName)); } var developBranchRegex = config.Branches[ConfigurationProvider.DevelopBranchKey].Regex; var masterBranchRegex = config.Branches[ConfigurationProvider.MasterBranchKey].Regex; var chosenBranch = repository.Branches.FirstOrDefault(b => Regex.IsMatch(b.FriendlyName, developBranchRegex, RegexOptions.IgnoreCase) || Regex.IsMatch(b.FriendlyName, masterBranchRegex, RegexOptions.IgnoreCase)); if (chosenBranch == null) { // TODO We should call the build server to generate this exception, each build server works differently // for fetch issues and we could give better warnings. throw new InvalidOperationException("Could not find a 'develop' or 'master' branch, neither locally nor remotely."); } var branchName = chosenBranch.FriendlyName; Logger.WriteWarning(errorMessage + Environment.NewLine + Environment.NewLine + "Falling back to " + branchName + " branch config"); // 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, PreventIncrementOfMergedBranchVersion = inheritingBranchConfig.PreventIncrementOfMergedBranchVersion, // If we are inheriting from develop then we should behave like develop TracksReleaseBranches = inheritingBranchConfig.TracksReleaseBranches }); } }