diff --git a/GitUI/UserControls/RevisionGrid/Graph/LaneInfoProvider.cs b/GitUI/UserControls/RevisionGrid/Graph/LaneInfoProvider.cs index b2647ccad6a..a50cdc91bc5 100644 --- a/GitUI/UserControls/RevisionGrid/Graph/LaneInfoProvider.cs +++ b/GitUI/UserControls/RevisionGrid/Graph/LaneInfoProvider.cs @@ -46,7 +46,6 @@ public string GetLaneInfo(int rowIndex, int lane) laneInfoText.AppendLine(node.GitRevision.Guid); -#if false var branch = new BranchFinder(node); if (branch.CommittedTo.IsNotNullOrWhitespace()) { @@ -56,7 +55,6 @@ public string GetLaneInfo(int rowIndex, int lane) laneInfoText.AppendFormat(" (merged with {0})", branch.MergedWith); } } -#endif laneInfoText.AppendLine(); } @@ -77,55 +75,36 @@ public string GetLaneInfo(int rowIndex, int lane) return laneInfoText.ToString(); } -#if false private class BranchFinder { private static readonly Regex MergeRegex = new Regex("(?i)^merged? (pull request (.*) from )?(.*branch |tag )?'?([^ ']*[^ '.])'?( of [^ ]*[^ .])?( into (.*[^.]))?\\.?$", RegexOptions.Compiled | RegexOptions.CultureInvariant); - private readonly HashSet _visitedNodes = new HashSet(); + private readonly HashSet _visitedMergeNodes = new HashSet(); - internal BranchFinder([NotNull] Node node) + internal BranchFinder([NotNull] RevisionGraphRevision node) { - FindBranchRecursively(node, previousDescJunction: null); + FindBranchRecursively(node, parent: null); } internal string CommittedTo { get; private set; } internal string MergedWith { get; private set; } - private bool FindBranchRecursively([NotNull] Node node, [CanBeNull] Junction previousDescJunction) + private bool FindBranchRecursively([NotNull] RevisionGraphRevision node, [CanBeNull] RevisionGraphRevision parent) { - if (!_visitedNodes.Add(node)) + if (node.StartSegments.Count > 1 && !_visitedMergeNodes.Add(node)) { return false; } - if (CheckForMerge(node, previousDescJunction) || FindBranch(node)) + if (CheckForMerge(node, parent) || FindBranch(node)) { return true; } - foreach (var descJunction in node.Descendants) + foreach (var childSegment in node.EndSegments) { - // iterate the inner nodes (i.e. excluding the youngest) beginning with the oldest - bool nodeFound = false; - for (int nodeIndex = descJunction.NodeCount - 1; nodeIndex > 0; --nodeIndex) - { - var innerNode = descJunction[nodeIndex]; - if (nodeFound) - { - if (CheckForMerge(innerNode, descJunction) || FindBranch(innerNode)) - { - return true; - } - } - else - { - nodeFound = innerNode == node; - } - } - - // handle the youngest and its descendants - if (FindBranchRecursively(descJunction.Youngest, descJunction)) + // handle the child and its children + if (FindBranchRecursively(childSegment.Child, childSegment.Parent)) { return true; } @@ -134,9 +113,9 @@ private bool FindBranchRecursively([NotNull] Node node, [CanBeNull] Junction pre return false; } - private bool FindBranch([NotNull] Node node) + private bool FindBranch([NotNull] RevisionGraphRevision node) { - foreach (var gitReference in node.Revision.Refs) + foreach (var gitReference in node.GitRevision.Refs) { if (gitReference.IsHead || gitReference.IsRemote || gitReference.IsStash) { @@ -157,16 +136,16 @@ private bool FindBranch([NotNull] Node node) /// First/second branch does not matter because it is the message of the current node. /// /// the node of the revision to evaluate - /// - /// the descending junction the node is part of - /// (used for the decision whether the node belongs the first or second branch of the merge) + /// + /// the node's parent in the branch which is currently descended + /// (used for the decision whether the node belongs to the first or second branch of the merge) /// - private bool CheckForMerge([NotNull] Node node, [CanBeNull] Junction descJunction) + private bool CheckForMerge([NotNull] RevisionGraphRevision node, [CanBeNull] RevisionGraphRevision parent) { - bool isTheFirstBranch = descJunction == null || node.Ancestors.Count == 0 || node.Ancestors.First() == descJunction; + bool isTheFirstBranch = parent == null || node.Parents.Count == 0 || node.Parents.First() == parent; string mergedInto; string mergedWith; - (mergedInto, mergedWith) = ParseMergeMessage(node.Revision.Subject, appendPullRequest: isTheFirstBranch); + (mergedInto, mergedWith) = ParseMergeMessage(node.GitRevision.Subject, appendPullRequest: isTheFirstBranch); if (mergedInto != null) { @@ -202,6 +181,5 @@ private static (string into, string with) ParseMergeMessage([NotNull] string com return (into, with); } } -#endif } } \ No newline at end of file diff --git a/GitUI/UserControls/RevisionGrid/Graph/LaneNodeLocator.cs b/GitUI/UserControls/RevisionGrid/Graph/LaneNodeLocator.cs index 30a8b640da4..a6a59cce88a 100644 --- a/GitUI/UserControls/RevisionGrid/Graph/LaneNodeLocator.cs +++ b/GitUI/UserControls/RevisionGrid/Graph/LaneNodeLocator.cs @@ -27,11 +27,21 @@ public LaneNodeLocator(IRevisionGraphRowProvider laneRowProvider) } var segmentsForLane = row.GetSegmentsForIndex(lane); - switch (segmentsForLane.Count()) + if (segmentsForLane.Count() > 0) { - case 0: break; // empty lane - case 1: return (segmentsForLane.First().Parent, isAtNode: false); // crossing lane (should not be the end of a branch) - default: throw new System.Exception("only the current revision can have multiple segments and should have been handled above"); +#if DEBUG + var firstParent = segmentsForLane.First().Parent; + foreach (var segment in segmentsForLane) + { + if (segment.Parent != firstParent) + { + throw new System.Exception(string.Format("All segments for a lane should have the same parent.\n" + + "Not fulfilled for rowIndex {0} lane {1} with {2} segments.", + rowIndex, lane, segmentsForLane.Count())); + } + } +#endif + return (segmentsForLane.First().Parent, isAtNode: false); } } diff --git a/GitUI/UserControls/RevisionGrid/Graph/RevisionGraphRevision.cs b/GitUI/UserControls/RevisionGrid/Graph/RevisionGraphRevision.cs index 81396b3e055..5066ad2db95 100644 --- a/GitUI/UserControls/RevisionGrid/Graph/RevisionGraphRevision.cs +++ b/GitUI/UserControls/RevisionGrid/Graph/RevisionGraphRevision.cs @@ -8,9 +8,9 @@ namespace GitUI.UserControls.RevisionGrid.Graph { // This class represents a revision, or node. - // * <- revision + // * <- child revision // | - // * <- revision + // * <- parent revision public class RevisionGraphRevision { public RevisionGraphRevision(ObjectId objectId, int guessScore) diff --git a/GitUI/UserControls/RevisionGrid/Graph/RevisionGraphSegment.cs b/GitUI/UserControls/RevisionGrid/Graph/RevisionGraphSegment.cs index 7c941ca4ff4..c4cd94058cb 100644 --- a/GitUI/UserControls/RevisionGrid/Graph/RevisionGraphSegment.cs +++ b/GitUI/UserControls/RevisionGrid/Graph/RevisionGraphSegment.cs @@ -1,20 +1,20 @@ namespace GitUI.UserControls.RevisionGrid.Graph { // This class represents the connection between 2 revisions. - // * - // | <- segment connects two commits - // * + // * <- Child + // | <- segment connects two commits + // * <- Parent // A segment can span multiple rows when rendered as a graph. // Example: This graph has 6 segements. - // * - // / | \ + // * <- Child + // / | \ <- Child.StartSegments ("start" although they are merged here) // | * | // | | | // | * | // \ | | // * | - // | / - // * + // | / <- Parent.EndSegments ("end" although they are branched here) + // * <- Parent public class RevisionGraphSegment { public RevisionGraphSegment(RevisionGraphRevision parent, RevisionGraphRevision child)