/// <summary> /// Handles given branch, calculates BranchInfo object /// </summary> /// <param name="branch"></param> private void ProcessBranch(Branch branch) { var mergeBase = repo.ObjectDatabase.FindMergeBase(developHead.Tip, branch.Tip); var ret = new BranchInfo { Name = branch.FriendlyName, LastCommitDate = branch.Tip.Committer.When.DateTime, Merged = mergeBase == branch.Tip // Merge base for merged branches == to this branches }; if (!ret.Merged) { // Leave only 'branch' commits. Since branch is not merged, merge base is pointed to branch parent commit var branchCommits = repo.Commits.QueryBy( new CommitFilter { IncludeReachableFrom = branch.Tip, ExcludeReachableFrom = mergeBase }); ret.Author = GetMostFrequentContributor(branchCommits)?.ToString(); ret.ExclusiveCommits = branchCommits.Count(); } else { // Merged feature branch could have one or none ancestors var branchAncestors = developHead.Commits.Where(x => x.Parents.Contains(branch.Tip)).ToList(); if (branchAncestors.Count == 0 || // git merge feature --ff-only, result: develop == feature branchAncestors.First().Parents.Count() == 1) // git merge feature --ff-only, commit to develop, result:develop != feature { // There is no merge commit in such scenarios, branch pointer points to usual commit in develop. ret.Author = branch.Tip.Committer.ToString(); ret.ExclusiveCommits = 0; } else { // Find commit before merge commit. current branch must be inaccessible from this commit. Use it in filtering var mergeCommit = branchAncestors.First(); var oneCommitBeforeMerge = mergeCommit.Parents.First(x => x != branch.Tip); var branchCommits = repo.Commits.QueryBy( new CommitFilter { IncludeReachableFrom = branch.Tip, ExcludeReachableFrom = oneCommitBeforeMerge }); ret.Author = GetMostFrequentContributor(branchCommits)?.ToString(); ret.ExclusiveCommits = branchCommits.Count(); } } WriteObject(ret); }
/// <summary> /// Handles given branch, calculates BranchInfo object /// </summary> /// <param name="branch"></param> private void ProcessBranch(Branch branch) { var mergeBase = repo.ObjectDatabase.FindMergeBase(developHead.Tip, branch.Tip); var ret = new BranchInfo { Name = branch.FriendlyName, LastCommitDate = branch.Tip.Committer.When.DateTime, Merged = mergeBase == branch.Tip // Merge base for merged branches == to this branches }; if (!ret.Merged) { // Leave only 'branch' commits. Since branch is not merged, merge base is pointed to branch parent commit var branchCommits = repo.Commits.QueryBy( new CommitFilter { IncludeReachableFrom = branch.Tip, ExcludeReachableFrom = mergeBase }); ret.Author = GetMostFrequentContributor(branchCommits)?.ToString(); ret.ExclusiveCommits = branchCommits.Count(); } else { // Merge commit has two parents var mergeCommit = developHead.Commits.First(x => x.Parents.Contains(branch.Tip)); if (mergeCommit.Parents.Count() == 1) { // There is no merge commit, this branch possible was rebased or fastforwarded. // i.e. branch pointer points to usual commit in develop. ret.Author = branch.Tip.Committer.ToString(); ret.ExclusiveCommits = 0; } else { // Find commit before merge commit. current branch must be inaccessible from this commit. Use it in filtering var oneCommitBeforeMerge = mergeCommit.Parents.First(x => x != branch.Tip); var branchCommits = repo.Commits.QueryBy( new CommitFilter { IncludeReachableFrom = branch.Tip, ExcludeReachableFrom = oneCommitBeforeMerge }); ret.Author = GetMostFrequentContributor(branchCommits)?.ToString(); ret.ExclusiveCommits = branchCommits.Count(); } } WriteObject(ret); }