From 8354e49e8dd264ad3825143bc10da85aefba7c85 Mon Sep 17 00:00:00 2001 From: Lamparter <71598437+Lamparter@users.noreply.github.com> Date: Wed, 29 Apr 2026 18:29:19 +0100 Subject: [PATCH] Initial move --- src/Files.App/Utils/Git/GitHelpers.cs | 36 ++---------- src/Files.App/Utils/Git/IVersionControl.cs | 2 +- src/Files.App/Utils/Git/LibGit2.cs | 67 ++++++++++++++++++++++ 3 files changed, 72 insertions(+), 33 deletions(-) diff --git a/src/Files.App/Utils/Git/GitHelpers.cs b/src/Files.App/Utils/Git/GitHelpers.cs index 3fca3c798e87..985122ae0c5d 100644 --- a/src/Files.App/Utils/Git/GitHelpers.cs +++ b/src/Files.App/Utils/Git/GitHelpers.cs @@ -22,6 +22,9 @@ internal static partial class GitHelpers /// public static string GetOriginRepositoryName(string? path) => _implementation.GetOriginRepositoryName(path); + /// + public static Task GetBranchNames(string? path) => _implementation.GetBranchNames(path); + #region Legacy implementation private static readonly StatusCenterViewModel StatusCenterViewModel = Ioc.Default.GetRequiredService(); @@ -71,38 +74,6 @@ private set public static event EventHandler? GitFetchCompleted; - public static async Task GetBranchesNames(string? path) - { - if (string.IsNullOrWhiteSpace(path) || !IsRepoValid(path)) - return []; - - var (result, returnValue) = await DoGitOperationAsync<(GitOperationResult, BranchItem[])>(() => - { - var branches = Array.Empty(); - var result = GitOperationResult.Success; - try - { - using var repository = new Repository(path); - - branches = GetValidBranches(repository.Branches) - .OrderByDescending(b => b.Tip?.Committer.When) - .GroupBy(b => b.IsRemote) - .SelectMany(g => g.Take(MAX_NUMBER_OF_BRANCHES)) - .OrderByDescending(b => b.IsCurrentRepositoryHead) - .Select(b => new BranchItem(b.FriendlyName, b.IsCurrentRepositoryHead, b.IsRemote, TryGetTrackingDetails(b)?.AheadBy ?? 0, TryGetTrackingDetails(b)?.BehindBy ?? 0)) - .ToArray(); - } - catch (Exception) - { - result = GitOperationResult.GenericError; - } - - return (result, branches); - }); - - return returnValue; - } - public static async Task GetRepositoryHead(string? path) { if (string.IsNullOrWhiteSpace(path) || !IsRepoValid(path)) @@ -821,6 +792,7 @@ private static bool IsAuthorizationException(Exception ex) ex.Message.Contains("authentication replays", StringComparison.OrdinalIgnoreCase); } + // Method already moved into abstraction private static async Task DoGitOperationAsync(Func payload, bool useSemaphore = false) { if (useSemaphore) diff --git a/src/Files.App/Utils/Git/IVersionControl.cs b/src/Files.App/Utils/Git/IVersionControl.cs index b1e21f0403a7..80161a631177 100644 --- a/src/Files.App/Utils/Git/IVersionControl.cs +++ b/src/Files.App/Utils/Git/IVersionControl.cs @@ -44,7 +44,7 @@ internal interface IVersionControl /// /// A task producing an array of branches; returns an empty array when the repository is invalid or unavailable. /// - Task GetBranchesNames(string? path); + Task GetBranchNames(string? path); /// /// Gets the current repository HEAD reference. diff --git a/src/Files.App/Utils/Git/LibGit2.cs b/src/Files.App/Utils/Git/LibGit2.cs index 0581c628f9cf..46c9d0fc1982 100644 --- a/src/Files.App/Utils/Git/LibGit2.cs +++ b/src/Files.App/Utils/Git/LibGit2.cs @@ -62,8 +62,75 @@ public string GetOriginRepositoryName(string? path) return repositoryName[..repositoryName.LastIndexOf(".git")]; } + public async Task GetBranchNames(string? path) + { + if (string.IsNullOrWhiteSpace(path) || !IsRepoValid(path)) + return []; + + var (result, returnValue) = await DoGitOperationAsync<(GitOperationResult, BranchItem[])>(() => + { + var branches = Array.Empty(); + var result = GitOperationResult.Success; + try + { + using var repository = new Repository(path); + + branches = GetValidBranches(repository.Branches) + .OrderByDescending(b => b.Tip?.Committer.When) + .GroupBy(b => b.IsRemote) + .SelectMany(g => g.Take(MAX_NUMBER_OF_BRANCHES)) + .OrderByDescending(b => b.IsCurrentRepositoryHead) + .Select(b => new BranchItem(b.FriendlyName, b.IsCurrentRepositoryHead, b.IsRemote, TryGetTrackingDetails(b)?.AheadBy ?? 0, TryGetTrackingDetails(b)?.BehindBy ?? 0)) + .ToArray(); + } + catch (Exception) + { + result = GitOperationResult.GenericError; + } + + return (result, branches); + }); + + return returnValue; + } + private static bool IsRepoValid(string path) { return SafetyExtensions.IgnoreExceptions(() => Repository.IsValid(path)); } + + private static async Task DoGitOperationAsync(Func payload, bool useSemaphore = false) + { + if (useSemaphore) + await GitOperationSemaphore.WaitAsync(); + else + await Task.Yield(); + + try + { + return (T)payload(); + } + finally + { + if (useSemaphore) + GitOperationSemaphore.Release(); + } + } + + private static IEnumerable GetValidBranches(BranchCollection branches) + { + foreach (var branch in branches) + { + try + { + var throwIfInvalid = branch.IsCurrentRepositoryHead; + } + catch (LibGit2SharpException) + { + continue; + } + + yield return branch; + } + } }