From 2d7e0c66c511ef321e7536d5199b0450c852f622 Mon Sep 17 00:00:00 2001 From: Canon Date: Tue, 10 Feb 2026 18:10:54 +0800 Subject: [PATCH] Improve Checking out older commits --- Services/GitService.cs | 10 ++++++ Services/IGitService.cs | 1 + UI/InteractiveMenu.cs | 67 ++++++++++++++++++++++++++++++++--------- 3 files changed, 63 insertions(+), 15 deletions(-) diff --git a/Services/GitService.cs b/Services/GitService.cs index ca81af6..ae5b4fe 100644 --- a/Services/GitService.cs +++ b/Services/GitService.cs @@ -174,6 +174,16 @@ public partial class GitService : IGitService return true; } + public async Task ResetToCommitAsync(string path, string commitHash, CancellationToken ct = default) + { + var (exitCode, _, _) = await RunGitCommandAsync(path, $"reset --hard \"{commitHash}\"", ct); + if (exitCode != 0) + return false; + + await RunGitCommandAsync(path, "submodule update --init --recursive", ct); + return true; + } + public async Task HasLocalChangesAsync(string path, CancellationToken ct = default) { var (exitCode, output, _) = await RunGitCommandAsync(path, "status --porcelain", ct); diff --git a/Services/IGitService.cs b/Services/IGitService.cs index bc1b172..b7f7cf5 100644 --- a/Services/IGitService.cs +++ b/Services/IGitService.cs @@ -15,6 +15,7 @@ public interface IGitService Task CloneAsync(string url, string targetPath, IProgress? progress = null, IProgress? percentProgress = null, CancellationToken ct = default); Task> GetRemoteBranchesAsync(string path, CancellationToken ct = default); Task CheckoutAsync(string path, string branchOrCommit, CancellationToken ct = default); + Task ResetToCommitAsync(string path, string commitHash, CancellationToken ct = default); Task HasLocalChangesAsync(string path, CancellationToken ct = default); Task> GetCommitHistoryAsync(string path, int limit = 20, CancellationToken ct = default); } diff --git a/UI/InteractiveMenu.cs b/UI/InteractiveMenu.cs index 83f824e..cd6d734 100644 --- a/UI/InteractiveMenu.cs +++ b/UI/InteractiveMenu.cs @@ -467,26 +467,63 @@ public class InteractiveMenu return; } - GitCommitInfo commit = AnsiConsole.Prompt( - new SelectionPrompt() - .Title("Select commit:") - .PageSize(15) - .UseConverter(c => - $"[yellow]{c.ShortHash}[/] [grey]{c.Date.ToLocalTime():yyyy-MM-dd}[/] {Markup.Escape(Truncate(c.Message, 50))}") - .AddChoices(commits)); + var method = AnsiConsole.Prompt( + new SelectionPrompt() + .Title("How would you like to select a commit?") + .AddChoices( + "Pick from history", + "Enter commit hash manually" + )); - var success = await ProgressReporter.WithStatusAsync( - $"Checking out {commit.ShortHash}...", - async () => await _gitService.CheckoutAsync(mod.Path, commit.Hash, ct)); - - if (success) + if (method == "Enter commit hash manually") { - AnsiConsole.MarkupLine($"[green]Checked out commit {commit.ShortHash}[/]"); - AnsiConsole.MarkupLine("[yellow]Note: You are now in 'detached HEAD' state.[/]"); + var manualHash = AnsiConsole.Ask("Enter commit hash:").Trim(); + if (string.IsNullOrEmpty(manualHash)) + { + AnsiConsole.MarkupLine("[yellow]No commit hash provided.[/]"); + WaitForKey(); + return; + } + + var label = manualHash.Length > 7 ? manualHash[..7] : manualHash; + + var success = await ProgressReporter.WithStatusAsync( + $"Checking out {label}...", + async () => await _gitService.CheckoutAsync(mod.Path, manualHash, ct)); + + if (success) + { + AnsiConsole.MarkupLine($"[green]Checked out commit {label}[/]"); + AnsiConsole.MarkupLine("[yellow]Note: You are now in 'detached HEAD' state.[/]"); + } + else + { + AnsiConsole.MarkupLine($"[red]Failed to checkout commit {label}[/]"); + } } else { - AnsiConsole.MarkupLine($"[red]Failed to checkout commit {commit.ShortHash}[/]"); + GitCommitInfo commit = AnsiConsole.Prompt( + new SelectionPrompt() + .Title("Select commit:") + .PageSize(15) + .UseConverter(c => + $"[yellow]{c.ShortHash}[/] [grey]{c.Date.ToLocalTime():yyyy-MM-dd}[/] {Markup.Escape(Truncate(c.Message, 50))}") + .AddChoices(commits)); + + var currentBranch = mod.Branch ?? "HEAD"; + var success = await ProgressReporter.WithStatusAsync( + $"Resetting {currentBranch} to {commit.ShortHash}...", + async () => await _gitService.ResetToCommitAsync(mod.Path, commit.Hash, ct)); + + if (success) + { + AnsiConsole.MarkupLine($"[green]Reset branch '{currentBranch}' to commit {commit.ShortHash}[/]"); + } + else + { + AnsiConsole.MarkupLine($"[red]Failed to reset to commit {commit.ShortHash}[/]"); + } } WaitForKey();