From 39db45966cffc3070c055cf944b7015dffc9902a Mon Sep 17 00:00:00 2001 From: Saravanan Ganapathi Date: Fri, 21 Nov 2025 13:16:14 +0530 Subject: [PATCH] Fix: Fixed crash when switching git branches during merge conflict --- .../Data/Enums/GitCheckoutOptions.cs | 5 ++ .../Helpers/Dialog/DynamicDialogFactory.cs | 47 +++++++++++++++++++ src/Files.App/Strings/en-US/Resources.resw | 9 ++++ src/Files.App/Utils/Git/GitHelpers.cs | 23 ++++++++- 4 files changed, 83 insertions(+), 1 deletion(-) diff --git a/src/Files.App/Data/Enums/GitCheckoutOptions.cs b/src/Files.App/Data/Enums/GitCheckoutOptions.cs index 646235b73cc1..9a2abdcdef55 100644 --- a/src/Files.App/Data/Enums/GitCheckoutOptions.cs +++ b/src/Files.App/Data/Enums/GitCheckoutOptions.cs @@ -23,6 +23,11 @@ public enum GitCheckoutOptions /// DiscardChanges, + /// + /// Abort merge and check out to the branch. + /// + AbortMerge, + /// /// No operation to perform. /// diff --git a/src/Files.App/Helpers/Dialog/DynamicDialogFactory.cs b/src/Files.App/Helpers/Dialog/DynamicDialogFactory.cs index a6468fbafaa9..f2ff8cd29a27 100644 --- a/src/Files.App/Helpers/Dialog/DynamicDialogFactory.cs +++ b/src/Files.App/Helpers/Dialog/DynamicDialogFactory.cs @@ -266,6 +266,53 @@ public static DynamicDialog GetFor_GitCheckoutConflicts(string checkoutBranchNam return dialog; } + public static DynamicDialog GetFor_GitMergeConflicts(string checkoutBranchName, string headBranchName) + { + DynamicDialog dialog = null!; + + var optionsListView = new ListView() + { + ItemsSource = new string[] + { + string.Format(Strings.AbortMergeAndSwitch.GetLocalizedResource(), checkoutBranchName), + string.Format(Strings.StayAndResolveConflicts.GetLocalizedResource(), headBranchName) + }, + SelectionMode = ListViewSelectionMode.Single + }; + optionsListView.SelectedIndex = 0; + + optionsListView.SelectionChanged += (listView, args) => + { + dialog.ViewModel.AdditionalData = optionsListView.SelectedIndex == 0 + ? GitCheckoutOptions.AbortMerge + : GitCheckoutOptions.None; + }; + + dialog = new DynamicDialog(new DynamicDialogViewModel() + { + TitleText = Strings.SwitchBranch.GetLocalizedResource(), + PrimaryButtonText = Strings.OK.GetLocalizedResource(), + CloseButtonText = Strings.Cancel.GetLocalizedResource(), + SubtitleText = Strings.MergeInProgress.GetLocalizedResource(), + DisplayControl = new Grid() + { + MinWidth = 250d, + Children = + { + optionsListView + } + }, + AdditionalData = GitCheckoutOptions.AbortMerge, + CloseButtonAction = (vm, e) => + { + dialog.ViewModel.AdditionalData = GitCheckoutOptions.None; + vm.HideDialog(); + } + }); + + return dialog; + } + public static DynamicDialog GetFor_GitHubConnectionError() { DynamicDialog dialog = new DynamicDialog(new DynamicDialogViewModel() diff --git a/src/Files.App/Strings/en-US/Resources.resw b/src/Files.App/Strings/en-US/Resources.resw index 22062780d1e3..ad2041f1e3b0 100644 --- a/src/Files.App/Strings/en-US/Resources.resw +++ b/src/Files.App/Strings/en-US/Resources.resw @@ -3132,6 +3132,15 @@ You have uncommitted changes on this branch. What would you like to do with them? + + You have an ongoing merge with unresolved conflicts. You must resolve or abort the merge before switching branches. + + + Abort merge and switch to '{0}' + + + Stay on '{0}' and resolve conflicts + Switch branch diff --git a/src/Files.App/Utils/Git/GitHelpers.cs b/src/Files.App/Utils/Git/GitHelpers.cs index befa53cf1780..e49032fa77fc 100644 --- a/src/Files.App/Utils/Git/GitHelpers.cs +++ b/src/Files.App/Utils/Git/GitHelpers.cs @@ -194,7 +194,24 @@ public static async Task Checkout(string? repositoryPath, string? branch) IsExecutingGitAction = true; - if (repository.RetrieveStatus().IsDirty) + if (repository.Index.Conflicts.Any()) + { + var dialog = DynamicDialogFactory.GetFor_GitMergeConflicts(checkoutBranch.FriendlyName, repository.Head.FriendlyName); + await dialog.ShowAsync(); + + var resolveConflictOption = (GitCheckoutOptions)dialog.ViewModel.AdditionalData; + + switch (resolveConflictOption) + { + case GitCheckoutOptions.None: + IsExecutingGitAction = false; + return false; + case GitCheckoutOptions.AbortMerge: + repository.Reset(ResetMode.Hard); + break; + } + } + else if (repository.RetrieveStatus().IsDirty) { var dialog = DynamicDialogFactory.GetFor_GitCheckoutConflicts(checkoutBranch.FriendlyName, repository.Head.FriendlyName); await dialog.ShowAsync(); @@ -204,6 +221,7 @@ public static async Task Checkout(string? repositoryPath, string? branch) switch (resolveConflictOption) { case GitCheckoutOptions.None: + IsExecutingGitAction = false; return false; case GitCheckoutOptions.DiscardChanges: options.CheckoutModifiers = CheckoutModifiers.Force; @@ -212,7 +230,10 @@ public static async Task Checkout(string? repositoryPath, string? branch) case GitCheckoutOptions.StashChanges: var signature = repository.Config.BuildSignature(DateTimeOffset.Now); if (signature is null) + { + IsExecutingGitAction = false; return false; + } repository.Stashes.Add(signature);