From f7b2063e8d13cbad2e48f422efa125f34619cbc1 Mon Sep 17 00:00:00 2001 From: leo Date: Mon, 7 Jul 2025 17:25:48 +0800 Subject: [PATCH] refactor: rewrite integration for `git branch` command Signed-off-by: leo --- src/Commands/Branch.cs | 65 +++++++++--------------- src/ViewModels/CreateBranch.cs | 4 +- src/ViewModels/DeleteBranch.cs | 28 ++++++++-- src/ViewModels/DeleteMultipleBranches.cs | 16 +++++- src/ViewModels/InitGitFlow.cs | 8 ++- src/ViewModels/RenameBranch.cs | 5 +- src/ViewModels/ResetWithoutCheckout.cs | 6 ++- src/ViewModels/SetUpstream.cs | 6 ++- 8 files changed, 83 insertions(+), 55 deletions(-) diff --git a/src/Commands/Branch.cs b/src/Commands/Branch.cs index a5e3208e..42a64d97 100644 --- a/src/Commands/Branch.cs +++ b/src/Commands/Branch.cs @@ -3,9 +3,15 @@ using System.Threading.Tasks; namespace SourceGit.Commands { - public static class Branch + public class Branch : Command { - public static async Task CreateAsync(string repo, string name, string basedOn, bool force, Models.ICommandLog log) + public Branch(string repo) + { + WorkingDirectory = repo; + Context = repo; + } + + public async Task CreateAsync(string name, string basedOn, bool force) { var builder = new StringBuilder(); builder.Append("branch "); @@ -15,61 +21,36 @@ namespace SourceGit.Commands builder.Append(" "); builder.Append(basedOn); - var cmd = new Command(); - cmd.WorkingDirectory = repo; - cmd.Context = repo; - cmd.Args = builder.ToString(); - cmd.Log = log; - return await cmd.ExecAsync().ConfigureAwait(false); + Args = builder.ToString(); + return await ExecAsync().ConfigureAwait(false); } - public static async Task RenameAsync(string repo, string name, string to, Models.ICommandLog log) + public async Task RenameAsync(string name, string to) { - var cmd = new Command(); - cmd.WorkingDirectory = repo; - cmd.Context = repo; - cmd.Args = $"branch -M {name} {to}"; - cmd.Log = log; - return await cmd.ExecAsync().ConfigureAwait(false); + Args = $"branch -M {name} {to}"; + return await ExecAsync().ConfigureAwait(false); } - public static async Task SetUpstreamAsync(string repo, string name, string upstream, Models.ICommandLog log) + public async Task SetUpstreamAsync(string name, string upstream) { - var cmd = new Command(); - cmd.WorkingDirectory = repo; - cmd.Context = repo; - cmd.Log = log; - if (string.IsNullOrEmpty(upstream)) - cmd.Args = $"branch {name} --unset-upstream"; + Args = $"branch {name} --unset-upstream"; else - cmd.Args = $"branch {name} -u {upstream}"; + Args = $"branch {name} -u {upstream}"; - return await cmd.ExecAsync().ConfigureAwait(false); + return await ExecAsync().ConfigureAwait(false); } - public static async Task DeleteLocalAsync(string repo, string name, Models.ICommandLog log) + public async Task DeleteLocalAsync(string name) { - var cmd = new Command(); - cmd.WorkingDirectory = repo; - cmd.Context = repo; - cmd.Args = $"branch -D {name}"; - cmd.Log = log; - return await cmd.ExecAsync().ConfigureAwait(false); + Args = $"branch -D {name}"; + return await ExecAsync().ConfigureAwait(false); } - public static async Task DeleteRemoteAsync(string repo, string remote, string name, Models.ICommandLog log) + public async Task DeleteRemoteAsync(string remote, string name) { - bool exists = await new Remote(repo).HasBranchAsync(remote, name).ConfigureAwait(false); - if (exists) - return await new Push(repo, remote, $"refs/heads/{name}", true) { Log = log }.RunAsync().ConfigureAwait(false); - - var cmd = new Command(); - cmd.WorkingDirectory = repo; - cmd.Context = repo; - cmd.Args = $"branch -D -r {remote}/{name}"; - cmd.Log = log; - return await cmd.ExecAsync().ConfigureAwait(false); + Args = $"branch -D -r {remote}/{name}"; + return await ExecAsync().ConfigureAwait(false); } } } diff --git a/src/ViewModels/CreateBranch.cs b/src/ViewModels/CreateBranch.cs index 07080d7e..537a8d79 100644 --- a/src/ViewModels/CreateBranch.cs +++ b/src/ViewModels/CreateBranch.cs @@ -187,7 +187,9 @@ namespace SourceGit.ViewModels } else { - succ = await Commands.Branch.CreateAsync(_repo.FullPath, fixedName, _baseOnRevision, _allowOverwrite, log); + succ = await new Commands.Branch(_repo.FullPath) + .Use(log) + .CreateAsync(fixedName, _baseOnRevision, _allowOverwrite); } log.Complete(); diff --git a/src/ViewModels/DeleteBranch.cs b/src/ViewModels/DeleteBranch.cs index 0c8ee154..a764c68d 100644 --- a/src/ViewModels/DeleteBranch.cs +++ b/src/ViewModels/DeleteBranch.cs @@ -49,22 +49,42 @@ namespace SourceGit.ViewModels if (Target.IsLocal) { - await Commands.Branch.DeleteLocalAsync(_repo.FullPath, Target.Name, log); + await new Commands.Branch(_repo.FullPath) + .Use(log) + .DeleteLocalAsync(Target.Name); + if (_alsoDeleteTrackingRemote && TrackingRemoteBranch != null) - await Commands.Branch.DeleteRemoteAsync(_repo.FullPath, TrackingRemoteBranch.Remote, TrackingRemoteBranch.Name, log); + await DeleteRemoteBranchAsync(TrackingRemoteBranch, log); } else { - await Commands.Branch.DeleteRemoteAsync(_repo.FullPath, Target.Remote, Target.Name, log); + await DeleteRemoteBranchAsync(Target, log); } log.Complete(); - _repo.MarkBranchesDirtyManually(); _repo.SetWatcherEnabled(true); return true; } + private async Task DeleteRemoteBranchAsync(Models.Branch branch, CommandLog log) + { + var exists = await new Commands.Remote(_repo.FullPath) + .HasBranchAsync(branch.Remote, branch.Name) + .ConfigureAwait(false); + + if (exists) + await new Commands.Push(_repo.FullPath, branch.Remote, $"refs/heads/{branch.Name}", true) + .Use(log) + .RunAsync() + .ConfigureAwait(false); + else + await new Commands.Branch(_repo.FullPath) + .Use(log) + .DeleteRemoteAsync(branch.Remote, branch.Name) + .ConfigureAwait(false); + } + private readonly Repository _repo = null; private bool _alsoDeleteTrackingRemote = false; } diff --git a/src/ViewModels/DeleteMultipleBranches.cs b/src/ViewModels/DeleteMultipleBranches.cs index e8ca45ab..ba6d774c 100644 --- a/src/ViewModels/DeleteMultipleBranches.cs +++ b/src/ViewModels/DeleteMultipleBranches.cs @@ -28,12 +28,24 @@ namespace SourceGit.ViewModels if (_isLocal) { foreach (var target in Targets) - await Commands.Branch.DeleteLocalAsync(_repo.FullPath, target.Name, log); + await new Commands.Branch(_repo.FullPath) + .Use(log) + .DeleteLocalAsync(target.Name); } else { foreach (var target in Targets) - await Commands.Branch.DeleteRemoteAsync(_repo.FullPath, target.Remote, target.Name, log); + { + var exists = await new Commands.Remote(_repo.FullPath).HasBranchAsync(target.Remote, target.Name); + if (exists) + await new Commands.Push(_repo.FullPath, target.Remote, $"refs/heads/{target.Name}", true) + .Use(log) + .RunAsync(); + else + await new Commands.Branch(_repo.FullPath) + .Use(log) + .DeleteRemoteAsync(target.Remote, target.Name); + } } log.Complete(); diff --git a/src/ViewModels/InitGitFlow.cs b/src/ViewModels/InitGitFlow.cs index e315fcf1..d179fee0 100644 --- a/src/ViewModels/InitGitFlow.cs +++ b/src/ViewModels/InitGitFlow.cs @@ -114,7 +114,9 @@ namespace SourceGit.ViewModels var masterBranch = _repo.Branches.Find(x => x.IsLocal && x.Name.Equals(_master, StringComparison.Ordinal)); if (masterBranch == null) { - succ = await Commands.Branch.CreateAsync(_repo.FullPath, _master, current.Head, true, log); + succ = await new Commands.Branch(_repo.FullPath) + .Use(log) + .CreateAsync(_master, current.Head, true); if (!succ) { log.Complete(); @@ -126,7 +128,9 @@ namespace SourceGit.ViewModels var developBranch = _repo.Branches.Find(x => x.IsLocal && x.Name.Equals(_develop, StringComparison.Ordinal)); if (developBranch == null) { - succ = await Commands.Branch.CreateAsync(_repo.FullPath, _develop, current.Head, true, log); + succ = await new Commands.Branch(_repo.FullPath) + .Use(log) + .CreateAsync(_develop, current.Head, true); if (!succ) { log.Complete(); diff --git a/src/ViewModels/RenameBranch.cs b/src/ViewModels/RenameBranch.cs index 655a2d0c..b93ee322 100644 --- a/src/ViewModels/RenameBranch.cs +++ b/src/ViewModels/RenameBranch.cs @@ -57,7 +57,10 @@ namespace SourceGit.ViewModels var isCurrent = Target.IsCurrent; var oldName = Target.FullName; - var succ = await Commands.Branch.RenameAsync(_repo.FullPath, Target.Name, fixedName, log); + var succ = await new Commands.Branch(_repo.FullPath) + .Use(log) + .RenameAsync(Target.Name, fixedName); + if (succ) { foreach (var filter in _repo.Settings.HistoriesFilters) diff --git a/src/ViewModels/ResetWithoutCheckout.cs b/src/ViewModels/ResetWithoutCheckout.cs index 2c6403d1..e1cfd730 100644 --- a/src/ViewModels/ResetWithoutCheckout.cs +++ b/src/ViewModels/ResetWithoutCheckout.cs @@ -38,8 +38,12 @@ namespace SourceGit.ViewModels var log = _repo.CreateLog($"Reset '{Target.Name}' to '{_revision}'"); Use(log); - var succ = await Commands.Branch.CreateAsync(_repo.FullPath, Target.Name, _revision, true, log); + var succ = await new Commands.Branch(_repo.FullPath) + .Use(log) + .CreateAsync(Target.Name, _revision, true); + log.Complete(); + _repo.MarkBranchesDirtyManually(); _repo.SetWatcherEnabled(true); return succ; } diff --git a/src/ViewModels/SetUpstream.cs b/src/ViewModels/SetUpstream.cs index c6208dbd..8a7611d1 100644 --- a/src/ViewModels/SetUpstream.cs +++ b/src/ViewModels/SetUpstream.cs @@ -61,9 +61,11 @@ namespace SourceGit.ViewModels var log = _repo.CreateLog("Set Upstream"); Use(log); - var succ = await Commands.Branch.SetUpstreamAsync(_repo.FullPath, Local.Name, upstream.Replace("refs/remotes/", ""), log); - log.Complete(); + var succ = await new Commands.Branch(_repo.FullPath) + .Use(log) + .SetUpstreamAsync(Local.Name, upstream.Replace("refs/remotes/", "")); + log.Complete(); if (succ) _repo.MarkBranchesDirtyManually(); return true;