Skip to content

Commit

Permalink
gitextensions#5125 RevisionGrid Graph: Nearest branch in tooltip (2a …
Browse files Browse the repository at this point in the history
…of 3)

Adapt and activate BranchFinder
Solve regression in LaneNodeLocator
  • Loading branch information
mstv committed Oct 29, 2018
1 parent c4be921 commit 69f6917
Show file tree
Hide file tree
Showing 4 changed files with 40 additions and 52 deletions.
56 changes: 17 additions & 39 deletions GitUI/UserControls/RevisionGrid/Graph/LaneInfoProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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())
{
Expand All @@ -56,7 +55,6 @@ public string GetLaneInfo(int rowIndex, int lane)
laneInfoText.AppendFormat(" (merged with {0})", branch.MergedWith);
}
}
#endif

laneInfoText.AppendLine();
}
Expand All @@ -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<Node> _visitedNodes = new HashSet<Node>();
private readonly HashSet<RevisionGraphRevision> _visitedMergeNodes = new HashSet<RevisionGraphRevision>();

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;
}
Expand All @@ -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)
{
Expand All @@ -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.
/// </summary>
/// <param name="node">the node of the revision to evaluate</param>
/// <param name="descJunction">
/// the descending junction the node is part of
/// (used for the decision whether the node belongs the first or second branch of the merge)
/// <param name="parent">
/// 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)
/// </param>
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)
{
Expand Down Expand Up @@ -202,6 +181,5 @@ private static (string into, string with) ParseMergeMessage([NotNull] string com
return (into, with);
}
}
#endif
}
}
18 changes: 14 additions & 4 deletions GitUI/UserControls/RevisionGrid/Graph/LaneNodeLocator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
14 changes: 7 additions & 7 deletions GitUI/UserControls/RevisionGrid/Graph/RevisionGraphSegment.cs
Original file line number Diff line number Diff line change
@@ -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)
Expand Down

0 comments on commit 69f6917

Please sign in to comment.