1
0
mirror of https://github.com/jesseduffield/lazygit.git synced 2026-06-20 01:19:23 +02:00

Don't stage out-of-date submodules when asking user to auto-stage after resolving conflicts (#5440)

When you rebase a branch and there are conflicts, lazygit asks you to
continue the rebase when it detects that all conflicts have been
resolved. However, it is common to make additional changes beyond just
fixing the conflicts (e.g. to fix build failures), and when doing that
while the "Continue the rebase?" prompt is showing, lazygit detects that
too and asks you if you want to stage those newly modified files too.
This is all well and good (and can be disabled for those who don't like
it); however, lazygit would treat out-of-date submodules as unstaged
changes and would offer to stage those as well, and this is pretty bad
and almost never what you want. Fix this by excluding submodules from
that second check.
This commit is contained in:
Stefan Haller
2026-03-30 17:50:02 +02:00
committed by GitHub
4 changed files with 122 additions and 3 deletions
@@ -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
}
@@ -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}) {
@@ -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"),
)
},
})
+1
View File
@@ -69,6 +69,7 @@ var tests = []*components.IntegrationTest{
branch.RebaseAndDrop,
branch.RebaseCancelOnConflict,
branch.RebaseConflictsFixBuildErrors,
branch.RebaseConflictsFixBuildErrorsWithOutOfDateSubmodule,
branch.RebaseCopiedBranch,
branch.RebaseDoesNotAutosquash,
branch.RebaseFromMarkedBase,