diff --git a/pkg/gui/controllers/files_controller.go b/pkg/gui/controllers/files_controller.go index ac72565ad..00317f4cf 100644 --- a/pkg/gui/controllers/files_controller.go +++ b/pkg/gui/controllers/files_controller.go @@ -690,23 +690,68 @@ func (self *FilesController) refresh() error { } func (self *FilesController) handleAmendCommitPress() error { - self.c.Confirm(types.ConfirmOpts{ - Title: self.c.Tr.AmendLastCommitTitle, - Prompt: self.c.Tr.SureToAmend, - HandleConfirm: func() error { - return self.c.Helpers().WorkingTree.WithEnsureCommittableFiles(func() error { - if len(self.c.Model().Commits) == 0 { - return errors.New(self.c.Tr.NoCommitToAmend) - } + doAmend := func() error { + return self.c.Helpers().WorkingTree.WithEnsureCommittableFiles(func() error { + if len(self.c.Model().Commits) == 0 { + return errors.New(self.c.Tr.NoCommitToAmend) + } - return self.c.Helpers().AmendHelper.AmendHead() - }) - }, - }) + return self.c.Helpers().AmendHelper.AmendHead() + }) + } + + if self.isResolvingConflicts() { + return self.c.Menu(types.CreateMenuOptions{ + Title: self.c.Tr.AmendCommitTitle, + Prompt: self.c.Tr.AmendCommitWithConflictsMenuPrompt, + HideCancel: true, // We want the cancel item first, so we add one manually + Items: []*types.MenuItem{ + { + Label: self.c.Tr.Cancel, + OnPress: func() error { + return nil + }, + }, + { + Label: self.c.Tr.AmendCommitWithConflictsContinue, + OnPress: func() error { + return self.c.Helpers().MergeAndRebase.ContinueRebase() + }, + }, + { + Label: self.c.Tr.AmendCommitWithConflictsAmend, + OnPress: func() error { + return doAmend() + }, + }, + }, + }) + } else { + self.c.Confirm(types.ConfirmOpts{ + Title: self.c.Tr.AmendLastCommitTitle, + Prompt: self.c.Tr.SureToAmend, + HandleConfirm: func() error { + return doAmend() + }, + }) + } return nil } +func (self *FilesController) isResolvingConflicts() bool { + commits := self.c.Model().Commits + for _, c := range commits { + if c.Status != models.StatusRebasing { + break + } + if c.Action == models.ActionConflict { + return true + } + } + return false +} + func (self *FilesController) handleStatusFilterPressed() error { return self.c.Menu(types.CreateMenuOptions{ Title: self.c.Tr.FilteringMenuTitle, diff --git a/pkg/gui/controllers/helpers/merge_and_rebase_helper.go b/pkg/gui/controllers/helpers/merge_and_rebase_helper.go index 2fb30372b..40d9e6df2 100644 --- a/pkg/gui/controllers/helpers/merge_and_rebase_helper.go +++ b/pkg/gui/controllers/helpers/merge_and_rebase_helper.go @@ -77,6 +77,10 @@ func (self *MergeAndRebaseHelper) CreateRebaseOptionsMenu() error { return self.c.Menu(types.CreateMenuOptions{Title: title, Items: menuItems}) } +func (self *MergeAndRebaseHelper) ContinueRebase() error { + return self.genericMergeCommand(REBASE_OPTION_CONTINUE) +} + func (self *MergeAndRebaseHelper) genericMergeCommand(command string) error { status := self.c.Git().Status.WorkingTreeState() diff --git a/pkg/i18n/english.go b/pkg/i18n/english.go index 87744f24d..28e126356 100644 --- a/pkg/i18n/english.go +++ b/pkg/i18n/english.go @@ -353,6 +353,9 @@ type TranslationSet struct { ScrollDownMainWindow string AmendCommitTitle string AmendCommitPrompt string + AmendCommitWithConflictsMenuPrompt string + AmendCommitWithConflictsContinue string + AmendCommitWithConflictsAmend string DropCommitTitle string DropCommitPrompt string DropUpdateRefPrompt string @@ -1375,6 +1378,9 @@ func EnglishTranslationSet() *TranslationSet { ScrollDownMainWindow: "Scroll down main window", AmendCommitTitle: "Amend commit", AmendCommitPrompt: "Are you sure you want to amend this commit with your staged files?", + AmendCommitWithConflictsMenuPrompt: "WARNING: you are about to amend the last finished commit with your resolved conflicts. This is very unlikely to be what you want at this point. More likely, you simply want to continue the rebase instead.\n\nDo you still want to amend the previous commit?", + AmendCommitWithConflictsContinue: "No, continue rebase", + AmendCommitWithConflictsAmend: "Yes, amend previous commit", DropCommitTitle: "Drop commit", DropCommitPrompt: "Are you sure you want to drop the selected commit(s)?", DropMergeCommitPrompt: "Are you sure you want to drop the selected merge commit? Note that it will also drop all the commits that were merged in by it.", diff --git a/pkg/integration/tests/commit/amend_when_there_are_conflicts_and_amend.go b/pkg/integration/tests/commit/amend_when_there_are_conflicts_and_amend.go new file mode 100644 index 000000000..8541310f0 --- /dev/null +++ b/pkg/integration/tests/commit/amend_when_there_are_conflicts_and_amend.go @@ -0,0 +1,41 @@ +package commit + +import ( + "github.com/jesseduffield/lazygit/pkg/config" + . "github.com/jesseduffield/lazygit/pkg/integration/components" +) + +var AmendWhenThereAreConflictsAndAmend = NewIntegrationTest(NewIntegrationTestArgs{ + Description: "Amends the last commit from the files panel while a rebase is stopped due to conflicts, and amends the commit", + ExtraCmdArgs: []string{}, + Skip: false, + SetupConfig: func(config *config.AppConfig) {}, + SetupRepo: func(shell *Shell) { + setupForAmendTests(shell) + }, + Run: func(t *TestDriver, keys config.KeybindingConfig) { + doTheRebaseForAmendTests(t, keys) + + t.Views().Files(). + Press(keys.Commits.AmendToCommit) + + t.ExpectPopup().Menu(). + Title(Equals("Amend commit")). + Select(Equals("Yes, amend previous commit")). + Confirm() + + t.Views().Files().IsEmpty() + + t.Views().Commits(). + Focus(). + Lines( + Contains("pick").Contains("commit three"), + Contains("conflict").Contains("<-- YOU ARE HERE --- file1 changed in branch"), + Contains("commit two"), + Contains("file1 changed in master"), + Contains("base commit"), + ) + + checkCommitContainsChange(t, "commit two", "+branch") + }, +}) diff --git a/pkg/integration/tests/commit/amend_when_there_are_conflicts_and_cancel.go b/pkg/integration/tests/commit/amend_when_there_are_conflicts_and_cancel.go new file mode 100644 index 000000000..2f16fdf80 --- /dev/null +++ b/pkg/integration/tests/commit/amend_when_there_are_conflicts_and_cancel.go @@ -0,0 +1,43 @@ +package commit + +import ( + "github.com/jesseduffield/lazygit/pkg/config" + . "github.com/jesseduffield/lazygit/pkg/integration/components" +) + +var AmendWhenThereAreConflictsAndCancel = NewIntegrationTest(NewIntegrationTestArgs{ + Description: "Amends the last commit from the files panel while a rebase is stopped due to conflicts, and cancels the confirmation", + ExtraCmdArgs: []string{}, + Skip: false, + SetupConfig: func(config *config.AppConfig) {}, + SetupRepo: func(shell *Shell) { + setupForAmendTests(shell) + }, + Run: func(t *TestDriver, keys config.KeybindingConfig) { + doTheRebaseForAmendTests(t, keys) + + t.Views().Files(). + Press(keys.Commits.AmendToCommit) + + t.ExpectPopup().Menu(). + Title(Equals("Amend commit")). + Select(Equals("Cancel")). + Confirm() + + // Check that nothing happened: + t.Views().Files(). + Lines( + Contains("M file1"), + ) + + t.Views().Commits(). + Focus(). + Lines( + Contains("pick").Contains("commit three"), + Contains("conflict").Contains("<-- YOU ARE HERE --- file1 changed in branch"), + Contains("commit two"), + Contains("file1 changed in master"), + Contains("base commit"), + ) + }, +}) diff --git a/pkg/integration/tests/commit/amend_when_there_are_conflicts_and_continue.go b/pkg/integration/tests/commit/amend_when_there_are_conflicts_and_continue.go new file mode 100644 index 000000000..8f679ba6d --- /dev/null +++ b/pkg/integration/tests/commit/amend_when_there_are_conflicts_and_continue.go @@ -0,0 +1,41 @@ +package commit + +import ( + "github.com/jesseduffield/lazygit/pkg/config" + . "github.com/jesseduffield/lazygit/pkg/integration/components" +) + +var AmendWhenThereAreConflictsAndContinue = NewIntegrationTest(NewIntegrationTestArgs{ + Description: "Amends the last commit from the files panel while a rebase is stopped due to conflicts, and continues the rebase", + ExtraCmdArgs: []string{}, + Skip: false, + SetupConfig: func(config *config.AppConfig) {}, + SetupRepo: func(shell *Shell) { + setupForAmendTests(shell) + }, + Run: func(t *TestDriver, keys config.KeybindingConfig) { + doTheRebaseForAmendTests(t, keys) + + t.Views().Files(). + Press(keys.Commits.AmendToCommit) + + t.ExpectPopup().Menu(). + Title(Equals("Amend commit")). + Select(Equals("No, continue rebase")). + Confirm() + + t.Views().Files().IsEmpty() + + t.Views().Commits(). + Focus(). + Lines( + Contains("commit three"), + Contains("file1 changed in branch"), + Contains("commit two"), + Contains("file1 changed in master"), + Contains("base commit"), + ) + + checkCommitContainsChange(t, "file1 changed in branch", "+branch") + }, +}) diff --git a/pkg/integration/tests/commit/shared.go b/pkg/integration/tests/commit/shared.go new file mode 100644 index 000000000..ee1d3e093 --- /dev/null +++ b/pkg/integration/tests/commit/shared.go @@ -0,0 +1,74 @@ +package commit + +import ( + "github.com/jesseduffield/lazygit/pkg/config" + . "github.com/jesseduffield/lazygit/pkg/integration/components" +) + +func setupForAmendTests(shell *Shell) { + shell.EmptyCommit("base commit") + shell.NewBranch("branch") + shell.Checkout("master") + shell.CreateFileAndAdd("file1", "master") + shell.Commit("file1 changed in master") + shell.Checkout("branch") + shell.UpdateFileAndAdd("file2", "two") + shell.Commit("commit two") + shell.CreateFileAndAdd("file1", "branch") + shell.Commit("file1 changed in branch") + shell.UpdateFileAndAdd("file3", "three") + shell.Commit("commit three") +} + +func doTheRebaseForAmendTests(t *TestDriver, keys config.KeybindingConfig) { + t.Views().Commits(). + Focus(). + Lines( + Contains("commit three").IsSelected(), + Contains("file1 changed in branch"), + Contains("commit two"), + Contains("base commit"), + ) + t.Views().Branches(). + Focus(). + NavigateToLine(Contains("master")). + Press(keys.Branches.RebaseBranch). + Tap(func() { + t.ExpectPopup().Menu(). + Title(Equals("Rebase 'branch'")). + Select(Contains("Simple rebase")). + Confirm() + t.Common().AcknowledgeConflicts() + }) + + t.Views().Commits(). + Lines( + Contains("pick").Contains("commit three"), + Contains("conflict").Contains("<-- YOU ARE HERE --- file1 changed in branch"), + Contains("commit two"), + Contains("file1 changed in master"), + Contains("base commit"), + ) + + t.Views().Files(). + Focus(). + PressEnter() + + t.Views().MergeConflicts(). + IsFocused(). + SelectNextItem(). // choose "incoming" + PressPrimaryAction() + + t.ExpectPopup().Confirmation(). + Title(Equals("Continue")). + Content(Contains("All merge conflicts resolved. Continue?")). + Cancel() +} + +func checkCommitContainsChange(t *TestDriver, commitSubject string, change string) { + t.Views().Commits(). + Focus(). + NavigateToLine(Contains(commitSubject)) + t.Views().Main(). + Content(Contains(change)) +} diff --git a/pkg/integration/tests/test_list.go b/pkg/integration/tests/test_list.go index 54a78bd1e..c28ab0cdb 100644 --- a/pkg/integration/tests/test_list.go +++ b/pkg/integration/tests/test_list.go @@ -83,6 +83,9 @@ var tests = []*components.IntegrationTest{ commit.AddCoAuthorRange, commit.AddCoAuthorWhileCommitting, commit.Amend, + commit.AmendWhenThereAreConflictsAndAmend, + commit.AmendWhenThereAreConflictsAndCancel, + commit.AmendWhenThereAreConflictsAndContinue, commit.AutoWrapMessage, commit.Checkout, commit.Commit,