From ba21d4e65141397659a0a3f6ef7b303bd5f6797d Mon Sep 17 00:00:00 2001 From: Stefan Haller Date: Sat, 31 Aug 2024 17:39:56 +0200 Subject: [PATCH] Ask to auto-stage unstaged files when continuing a rebase after resolving conflicts --- .../helpers/merge_and_rebase_helper.go | 30 ++++++++ pkg/i18n/english.go | 2 + .../rebase_conflicts_fix_build_errors.go | 76 +++++++++++++++++++ .../tests/file/discard_all_dir_changes.go | 9 +++ pkg/integration/tests/test_list.go | 1 + 5 files changed, 118 insertions(+) create mode 100644 pkg/integration/tests/branch/rebase_conflicts_fix_build_errors.go diff --git a/pkg/gui/controllers/helpers/merge_and_rebase_helper.go b/pkg/gui/controllers/helpers/merge_and_rebase_helper.go index 7ce60701d..21284201c 100644 --- a/pkg/gui/controllers/helpers/merge_and_rebase_helper.go +++ b/pkg/gui/controllers/helpers/merge_and_rebase_helper.go @@ -247,6 +247,36 @@ func (self *MergeAndRebaseHelper) PromptToContinueRebase() error { Title: self.c.Tr.Continue, Prompt: self.c.Tr.ConflictsResolved, HandleConfirm: func() error { + // By the time we get here, we might have unstaged changes again, + // e.g. if the user had to fix build errors after resolving the + // conflicts, but after lazygit opened the prompt already. Ask again + // to auto-stage these. + + // Need to refresh the files to be really sure if this is the case. + // We would otherwise be relying on lazygit's auto-refresh on focus, + // but this is not supported by all terminals or on all platforms. + if err := self.c.Refresh(types.RefreshOptions{ + Mode: types.SYNC, Scope: []types.RefreshableView{types.FILES}, + }); err != nil { + return err + } + + root := self.c.Contexts().Files.FileTreeViewModel.GetRoot() + if root.GetHasUnstagedChanges() { + return self.c.Confirm(types.ConfirmOpts{ + Title: self.c.Tr.Continue, + Prompt: self.c.Tr.UnstagedFilesAfterConflictsResolved, + HandleConfirm: func() error { + self.c.LogAction(self.c.Tr.Actions.StageAllFiles) + if err := self.c.Git().WorkingTree.StageAll(); err != nil { + return err + } + + return self.genericMergeCommand(REBASE_OPTION_CONTINUE) + }, + }) + } + return self.genericMergeCommand(REBASE_OPTION_CONTINUE) }, }) diff --git a/pkg/i18n/english.go b/pkg/i18n/english.go index b09a14d79..2e8efda34 100644 --- a/pkg/i18n/english.go +++ b/pkg/i18n/english.go @@ -296,6 +296,7 @@ type TranslationSet struct { ReflogCommitsTitle string ConflictsResolved string Continue string + UnstagedFilesAfterConflictsResolved string RebasingTitle string RebasingFromBaseCommitTitle string SimpleRebase string @@ -1278,6 +1279,7 @@ func EnglishTranslationSet() *TranslationSet { GlobalTitle: "Global keybindings", ConflictsResolved: "All merge conflicts resolved. Continue?", Continue: "Continue", + UnstagedFilesAfterConflictsResolved: "Files have been modified since conflicts were resolved. Auto-stage them and continue?", Keybindings: "Keybindings", KeybindingsMenuSectionLocal: "Local", KeybindingsMenuSectionGlobal: "Global", diff --git a/pkg/integration/tests/branch/rebase_conflicts_fix_build_errors.go b/pkg/integration/tests/branch/rebase_conflicts_fix_build_errors.go new file mode 100644 index 000000000..9cd42cd2e --- /dev/null +++ b/pkg/integration/tests/branch/rebase_conflicts_fix_build_errors.go @@ -0,0 +1,76 @@ +package branch + +import ( + "github.com/jesseduffield/lazygit/pkg/config" + . "github.com/jesseduffield/lazygit/pkg/integration/components" + "github.com/jesseduffield/lazygit/pkg/integration/tests/shared" +) + +var RebaseConflictsFixBuildErrors = NewIntegrationTest(NewIntegrationTestArgs{ + Description: "Rebase onto another branch, deal with the conflicts. While continue prompt is showing, fix build errors; get another prompt when continuing.", + ExtraCmdArgs: []string{}, + Skip: false, + SetupConfig: func(config *config.AppConfig) {}, + SetupRepo: func(shell *Shell) { + shared.MergeConflictsSetup(shell) + }, + Run: func(t *TestDriver, keys config.KeybindingConfig) { + t.Views().Commits().TopLines( + Contains("first change"), + Contains("original"), + ) + + t.Views().Branches(). + Focus(). + Lines( + Contains("first-change-branch"), + Contains("second-change-branch"), + Contains("original-branch"), + ). + SelectNextItem(). + Press(keys.Branches.RebaseBranch) + + t.ExpectPopup().Menu(). + Title(Equals("Rebase 'first-change-branch'")). + Select(Contains("Simple rebase")). + Confirm() + + t.Common().AcknowledgeConflicts() + + t.Views().Files(). + IsFocused(). + SelectedLine(Contains("file")). + PressEnter() + + t.Views().MergeConflicts(). + IsFocused(). + SelectNextItem(). + PressPrimaryAction() + + t.Views().Information().Content(Contains("Rebasing")) + + popup := t.ExpectPopup().Confirmation(). + Title(Equals("Continue")). + Content(Contains("All merge conflicts resolved. Continue?")) + + // While the popup is showing, fix some build errors + t.Shell().UpdateFile("file", "make it compile again") + + // Continue + popup.Confirm() + + t.ExpectPopup().Confirmation(). + Title(Equals("Continue")). + Content(Contains("Files have been modified since conflicts were resolved. Auto-stage them and continue?")). + Confirm() + + t.Views().Information().Content(DoesNotContain("Rebasing")) + + t.Views().Commits().TopLines( + Contains("first change"), + Contains("second-change-branch unrelated change"), + Contains("second change"), + Contains("original"), + ) + }, +}) diff --git a/pkg/integration/tests/file/discard_all_dir_changes.go b/pkg/integration/tests/file/discard_all_dir_changes.go index 3eb4cabdf..e03818534 100644 --- a/pkg/integration/tests/file/discard_all_dir_changes.go +++ b/pkg/integration/tests/file/discard_all_dir_changes.go @@ -94,6 +94,15 @@ var DiscardAllDirChanges = NewIntegrationTest(NewIntegrationTestArgs{ }). Tap(func() { t.Common().ContinueOnConflictsResolved() + t.ExpectPopup().Confirmation(). + Title(Equals("Continue")). + Content(Contains("Files have been modified since conflicts were resolved. Auto-stage them and continue?")). + Cancel() + t.GlobalPress(keys.Universal.CreateRebaseOptionsMenu) + t.ExpectPopup().Menu(). + Title(Equals("Merge options")). + Select(Contains("continue")). + Confirm() }). Lines( Contains("dir").IsSelected(), diff --git a/pkg/integration/tests/test_list.go b/pkg/integration/tests/test_list.go index d12d4c95f..268420648 100644 --- a/pkg/integration/tests/test_list.go +++ b/pkg/integration/tests/test_list.go @@ -51,6 +51,7 @@ var tests = []*components.IntegrationTest{ branch.RebaseAbortOnConflict, branch.RebaseAndDrop, branch.RebaseCancelOnConflict, + branch.RebaseConflictsFixBuildErrors, branch.RebaseCopiedBranch, branch.RebaseDoesNotAutosquash, branch.RebaseFromMarkedBase,