diff --git a/GitCommands/Git/GitModule.cs b/GitCommands/Git/GitModule.cs index db639c0788f..82a0f5aaaa3 100644 --- a/GitCommands/Git/GitModule.cs +++ b/GitCommands/Git/GitModule.cs @@ -818,11 +818,11 @@ private IGitItem GetSubmoduleCommitHash(string filename, string refName) return null; } - public int? GetCommitDiffCount(string parentHash, string childHash) + public int? GetCommitDiffCount(ObjectId baseId, ObjectId parentId) { var args = new GitArgumentBuilder("rev-list") { - $"{parentHash}...{childHash}", + $"{baseId} {parentId}", "--count" }; var output = _gitExecutable.GetOutput(args); @@ -835,6 +835,25 @@ private IGitItem GetSubmoduleCommitHash(string filename, string refName) return null; } + public (int? first, int? second) GetCommitRangeDiffCount(ObjectId firstId, ObjectId secondId) + { + var args = new GitArgumentBuilder("rev-list") + { + $"{firstId}...{secondId}", + "--count", + "--left-right" + }; + var output = _gitExecutable.GetOutput(args); + + var counts = output.Split('\t'); + if (counts.Length == 2 && int.TryParse(counts[0], out var first) && int.TryParse(counts[1], out var second)) + { + return (first, second); + } + + return (null, null); + } + public string GetCommitCountString(string from, string to) { int? removed = GetCommitCount(from, to); diff --git a/GitUI/UserControls/FileStatusDiffCalculator.cs b/GitUI/UserControls/FileStatusDiffCalculator.cs index 7fa8069011f..660f79db869 100644 --- a/GitUI/UserControls/FileStatusDiffCalculator.cs +++ b/GitUI/UserControls/FileStatusDiffCalculator.cs @@ -168,12 +168,13 @@ public FileStatusDiffCalculator(Func getModule) statuses: commonBaseToAandB)); // Add rangeDiff as a separate group (range is not the same as diff with artificial commits) - List statuses = new List { new GitItemStatus { Name = Strings.DiffRange, IsRangeDiff = true } }; - - var desc = Strings.DiffRange + ": " + GetDescriptionForRevision(describeRevision, firstRevHead) + " -> " + - GetDescriptionForRevision(describeRevision, selectedRevHead); + var statuses = new List { new GitItemStatus { Name = Strings.DiffRange, IsRangeDiff = true } }; var first = firstRev.ObjectId == firstRevHead ? firstRev : new GitRevision(firstRevHead); var selected = selectedRev.ObjectId == selectedRevHead ? selectedRev : new GitRevision(selectedRevHead); + var (baseToFirstCount, baseToSecondCount) = module.GetCommitRangeDiffCount(first.ObjectId, selected.ObjectId); + const int rangeDiffCommitLimit = 100; + var desc = $"{Strings.DiffRange} {baseToFirstCount ?? rangeDiffCommitLimit}↓ {baseToSecondCount ?? rangeDiffCommitLimit}↑"; + var rangeDiff = new FileStatusWithDescription( firstRev: first, secondRev: selected, @@ -185,13 +186,12 @@ public FileStatusDiffCalculator(Func getModule) // Git range-diff has cubic runtime complexity and can be slow and memory consuming, so just skip if diff is large // to avoid that GE seem to hang when selecting the range diff - const int maxRangeDiffCommits = 100; int count = (baseA == null || baseB == null - ? module.GetCommitDiffCount(firstRevHead.ToString(), selectedRevHead.ToString()) - : module.GetCommitDiffCount(baseA.ToString(), firstRevHead.ToString()) - + module.GetCommitDiffCount(baseB.ToString(), selectedRevHead.ToString())) - ?? maxRangeDiffCommits + 1; - if (!GitVersion.Current.SupportRangeDiffTool || count > maxRangeDiffCommits) + ? baseToFirstCount + baseToSecondCount + : module.GetCommitDiffCount(baseA, firstRevHead) + + module.GetCommitDiffCount(baseB, selectedRevHead)) + ?? rangeDiffCommitLimit; + if (!GitVersion.Current.SupportRangeDiffTool || count >= rangeDiffCommitLimit) { var range = baseA is null || baseB is null ? $"{first.ObjectId}...{selected.ObjectId}" @@ -199,11 +199,12 @@ public FileStatusDiffCalculator(Func getModule) statuses[0].IsStatusOnly = true; // Message is not translated, considered as an error message - statuses[0].ErrorMessage = $"# The symmetric difference from {first.ObjectId.ToShortString()} to {selected.ObjectId.ToShortString()} is {count} which is higher than the limit {maxRangeDiffCommits}\n" + - "# Git range-diff may take a long time and Git Extensions seem to hang during execution, why the command is not executed\n" + - "# You can still run the command in a Git terminal\n" + - "# Remove '--no-patch' to see changes to files too\n" + - $"git range-diff {range} --no-patch"; + statuses[0].ErrorMessage = + $"# The symmetric difference from {first.ObjectId.ToShortString()} to {selected.ObjectId.ToShortString()} is {count} >= {rangeDiffCommitLimit}\n" + + "# Git range-diff may take a long time and Git Extensions seem to hang during execution, why the command is not executed.\n" + + "# You can still run the command in a Git terminal.\n" + + "# Remove '--no-patch' to see changes to files too.\n" + + $"git range-diff {range} --no-patch"; } return fileStatusDescs;