/// <summary> /// Find the merge base of the two branches, i.e. the best common ancestor of the two branches' tips. /// </summary> public ICommit FindMergeBase(IBranch branch, IBranch otherBranch) { var key = Tuple.Create(branch, otherBranch); if (mergeBaseCache.ContainsKey(key)) { log.Debug($"Cache hit for merge base between '{branch.FriendlyName}' and '{otherBranch.FriendlyName}'."); return(mergeBaseCache[key].MergeBase); } using (log.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.FindMergeBase(commit, commitToFindCommonBase); if (findMergeBase != null) { log.Info($"Found merge base of {findMergeBase.Sha}"); // We do not want to include merge base commits which got forward merged into the other branch ICommit forwardMerge; do { // Now make sure that the merge base is not a forward merge forwardMerge = repository.GetForwardMerge(commitToFindCommonBase, findMergeBase); if (forwardMerge != null) { // TODO Fix the logging up in this section var second = forwardMerge.Parents.First(); log.Debug("Second " + second.Sha); var mergeBase = repository.FindMergeBase(commit, second); if (mergeBase == null) { log.Warning("Could not find mergbase for " + commit); } else { log.Debug("New Merge base " + mergeBase.Sha); } if (Equals(mergeBase, findMergeBase)) { log.Debug("Breaking"); break; } findMergeBase = mergeBase; commitToFindCommonBase = second; log.Info($"Merge base was due to a forward merge, next merge base is {findMergeBase}"); } } while (forwardMerge != null); } // Store in cache. mergeBaseCache.Add(key, new MergeBaseData(findMergeBase)); log.Info($"Merge base of {branch.FriendlyName}' and '{otherBranch.FriendlyName} is {findMergeBase}"); return(findMergeBase); } }