diff --git a/pkg/gui/controllers/helpers/merge_and_rebase_helper.go b/pkg/gui/controllers/helpers/merge_and_rebase_helper.go index 7d4f0a96a..7f51bc35d 100644 --- a/pkg/gui/controllers/helpers/merge_and_rebase_helper.go +++ b/pkg/gui/controllers/helpers/merge_and_rebase_helper.go @@ -237,14 +237,14 @@ func (self *MergeAndRebaseHelper) PromptToContinueRebase() error { Mode: types.SYNC, Scope: []types.RefreshableView{types.FILES}, }) - root := self.c.Contexts().Files.FileTreeViewModel.GetRoot() - if root.GetHasUnstagedChanges() { + unstagedFiles := GetUnstagedFilesExceptSubmodules(self.c.Model().Files, self.c.Model().Submodules) + if len(unstagedFiles) > 0 { 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(true); err != nil { + if err := self.c.Git().WorkingTree.StageFiles(unstagedFiles, []string{}); err != nil { return err } diff --git a/pkg/gui/controllers/helpers/working_tree_helper.go b/pkg/gui/controllers/helpers/working_tree_helper.go index 94a24e5ee..d6289537b 100644 --- a/pkg/gui/controllers/helpers/working_tree_helper.go +++ b/pkg/gui/controllers/helpers/working_tree_helper.go @@ -97,6 +97,12 @@ func IsWorkingTreeDirtyExceptSubmodules(files []*models.File, submoduleConfigs [ return AnyStagedFilesExceptSubmodules(files, submoduleConfigs) || AnyTrackedFilesExceptSubmodules(files, submoduleConfigs) } +func GetUnstagedFilesExceptSubmodules(files []*models.File, submoduleConfigs []*models.SubmoduleConfig) []string { + return lo.FilterMap(files, func(f *models.File, _ int) (string, bool) { + return f.Path, f.HasUnstagedChanges && f.Tracked && !f.IsSubmodule(submoduleConfigs) + }) +} + func (self *WorkingTreeHelper) FileForSubmodule(submodule *models.SubmoduleConfig) *models.File { for _, file := range self.c.Model().Files { if file.IsSubmodule([]*models.SubmoduleConfig{submodule}) { diff --git a/pkg/integration/tests/branch/rebase_conflicts_fix_build_errors_with_out_of_date_submodule.go b/pkg/integration/tests/branch/rebase_conflicts_fix_build_errors_with_out_of_date_submodule.go new file mode 100644 index 000000000..1b95fd316 --- /dev/null +++ b/pkg/integration/tests/branch/rebase_conflicts_fix_build_errors_with_out_of_date_submodule.go @@ -0,0 +1,112 @@ +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 RebaseConflictsFixBuildErrorsWithOutOfDateSubmodule = NewIntegrationTest(NewIntegrationTestArgs{ + Description: "Rebase onto another branch, deal with the conflicts. While continue prompt is showing, fix build errors; get another prompt when continuing. Check that we don't stage submodules here.", + ExtraCmdArgs: []string{}, + Skip: false, + SetupConfig: func(config *config.AppConfig) { + config.GetUserConfig().Git.LocalBranchSortOrder = "recency" + }, + SetupRepo: func(shell *Shell) { + // Create an out-of-date submodule to verify that we don't try to stage it + shell. + EmptyCommit("Initial commit"). + CloneIntoSubmodule("submodule", "submodule"). + Commit("Add submodule"). + AddFileInWorktreeOrSubmodule("submodule", "file", "content"). + CommitInWorktreeOrSubmodule("submodule", "add file in submodule") + + shared.MergeConflictsSetup(shell) + + // Create an untracked file to verify that we don't try to stage it either + shell.UpdateFile("untracked-file", "some untracked file") + }, + 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"), + Contains("master"), + ). + 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 the rebase?")) + + // While the popup is showing, fix some build errors + t.Shell().UpdateFile("file", "make it compile again") + + // Continue + popup.Confirm() + + t.Views().Files(). + Lines( + Equals("▼ /").IsSelected(), + Equals(" MM file"), + Equals(" M submodule (submodule)"), + Equals(" ?? untracked-file"), + ) + + 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().Files(). + Lines( + Equals("▼ /").IsSelected(), + Equals(" M submodule (submodule)"), + Equals(" ?? untracked-file"), + ) + + t.Views().Commits(). + Focus(). + TopLines( + Contains("first change").IsSelected(), + Contains("second-change-branch unrelated change"), + Contains("second change"), + Contains("original"), + ) + + t.Views().Main(). + Content( + DoesNotContain("submodule").DoesNotContain("untracked-file"), + ) + }, +}) diff --git a/pkg/integration/tests/test_list.go b/pkg/integration/tests/test_list.go index 3d8edfb56..7f228635a 100644 --- a/pkg/integration/tests/test_list.go +++ b/pkg/integration/tests/test_list.go @@ -69,6 +69,7 @@ var tests = []*components.IntegrationTest{ branch.RebaseAndDrop, branch.RebaseCancelOnConflict, branch.RebaseConflictsFixBuildErrors, + branch.RebaseConflictsFixBuildErrorsWithOutOfDateSubmodule, branch.RebaseCopiedBranch, branch.RebaseDoesNotAutosquash, branch.RebaseFromMarkedBase,