List <BranchCommit> GetMergeCommitsForBranch(Branch branch, Branch[] excludedBranches) { if (mergeBaseCommitsCache.ContainsKey(branch)) { Logger.WriteDebug($"Cache hit for getting merge commits for branch {branch.CanonicalName}."); return(mergeBaseCommitsCache[branch]); } var currentBranchConfig = configuration.GetConfigForBranch(branch.NameWithoutRemote()); var regexesToCheck = currentBranchConfig == null ? new[] { ".*" } // Match anything if we can't find a branch config : currentBranchConfig.SourceBranches.Select(sb => configuration.Branches[sb].Regex); var branchMergeBases = Repository.Branches .ExcludingBranches(excludedBranches) .Where(b => { if (b == branch) { return(false); } var branchCanBeMergeBase = regexesToCheck.Any(regex => Regex.IsMatch(b.FriendlyName, regex)); return(branchCanBeMergeBase); }) .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); }
/// <summary> /// Find the merge base of the two branches, i.e. the best common ancestor of the two branches' tips. /// </summary> public Commit FindMergeBase(Branch branch, Branch otherBranch) { var key = Tuple.Create(branch, otherBranch); if (mergeBaseCache.ContainsKey(key)) { Logger.WriteDebug($"Cache hit for merge base between '{branch.FriendlyName}' and '{otherBranch.FriendlyName}'."); return(mergeBaseCache[key].MergeBase); } using (Logger.IndentLog($"Finding merge base between '{branch.FriendlyName}' and '{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($"Found merge base of {findMergeBase.Sha}"); // We do not want to include merge base commits which got forward merged into the other branch Commit forwardMerge; do { // Now make sure that the merge base is not a forward merge forwardMerge = Repository.Commits .QueryBy(new CommitFilter { IncludeReachableFrom = commitToFindCommonBase, ExcludeReachableFrom = findMergeBase }) .FirstOrDefault(c => c.Parents.Contains(findMergeBase)); if (forwardMerge != null) { // TODO Fix the logging up in this section var second = forwardMerge.Parents.First(); Logger.WriteDebug("Second " + second.Sha); var mergeBase = Repository.ObjectDatabase.FindMergeBase(commit, second); if (mergeBase == null) { Logger.WriteWarning("Could not find mergbase for " + commit); } else { Logger.WriteDebug("New Merge base " + mergeBase.Sha); } if (mergeBase == findMergeBase) { Logger.WriteDebug("Breaking"); break; } findMergeBase = mergeBase; commitToFindCommonBase = second; Logger.WriteInfo($"Merge base was due to a forward merge, next merge base is {findMergeBase}"); } } while (forwardMerge != null); } // Store in cache. mergeBaseCache.Add(key, new MergeBaseData(branch, otherBranch, Repository, findMergeBase)); Logger.WriteInfo($"Merge base of {branch.FriendlyName}' and '{otherBranch.FriendlyName} is {findMergeBase}"); return(findMergeBase); } }
private static bool Log(LogLevel loglevel, Func <string> messagefunc, Exception exception, object[] formatparameters) { // Create the main message. Careful of string format errors. string message; if (messagefunc == null) { message = null; } else { if (formatparameters == null || formatparameters.Length == 0) { message = messagefunc(); } else { try { message = string.Format(messagefunc(), formatparameters); } catch (FormatException) { message = messagefunc(); Logger.WriteError(string.Format("LoggerWrapper.Log(): Incorrectly formatted string: message: '{0}'; formatparameters: {1}", message, string.Join(";", formatparameters))); } } } if (exception != null) { // Append the exception to the end of the message. message = string.IsNullOrEmpty(message) ? exception.ToString() : string.Format("{0}\n{1}", message, exception); } if (!string.IsNullOrEmpty(message)) { switch (loglevel) { case LogLevel.Trace: case LogLevel.Debug: Logger.WriteDebug(message); break; case LogLevel.Info: Logger.WriteInfo(message); break; case LogLevel.Warn: Logger.WriteWarning(message); break; case LogLevel.Error: case LogLevel.Fatal: Logger.WriteError(message); break; } } return(true); }