Don't stage nested repositories

If you staged the directory of a removed submodule, a nested repository
or a worktree inside the repo, git added it as an embedded repository: a
gitlink without an entry in .gitmodules. For a removed submodule, this
brings it back in a broken state. git warns about it, but lazygit didn't
show the warning. Staging all files did the same to every such
directory.

Disable staging a selection that contains one of these, and disable
staging all files if that would stage one. The disabled reason tells you
how to get rid of it.

Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Stefan Haller
2026-10-15 20:51:34 +02:00
co-authored by Claude Opus 5.5
parent d2675b7dea
commit a2cf915f8d
6 changed files with 109 additions and 2 deletions
@@ -0,0 +1,51 @@
package file
import (
"github.com/jesseduffield/lazygit/pkg/config"
. "github.com/jesseduffield/lazygit/pkg/integration/components"
)
var StageNestedRepository = NewIntegrationTest(NewIntegrationTestArgs{
Description: "Staging a nested repository, or all files while there is one, is not supported, because git would add it as an embedded repository",
ExtraCmdArgs: []string{},
Skip: false,
SetupConfig: func(config *config.AppConfig) {
config.GetUserConfig().Gui.ShowFileTree = false
},
SetupRepo: func(shell *Shell) {
shell.EmptyCommit("first commit")
shell.CloneIntoSubmodule("sub", "modules/sub")
shell.Commit("add submodule")
shell.RunCommand([]string{"git", "rm", "--cached", "modules/sub"})
shell.RunCommand([]string{"git", "rm", ".gitmodules"})
shell.Commit("remove submodule")
shell.CreateFile("file", "content")
},
Run: func(t *TestDriver, keys config.KeybindingConfig) {
t.Views().Files().
IsFocused().
Lines(
Equals("?? file").IsSelected(),
Equals("?? modules/sub (removed submodule)"),
).
Press(keys.Files.ToggleStagedAll).
Tap(func() {
t.ExpectToast(Equals("Disabled: Can't stage 'modules/sub' because it is a git repository of its own. Discard it with d, or ignore it with i."))
}).
NavigateToLine(Contains("modules/sub")).
PressPrimaryAction().
Tap(func() {
t.ExpectToast(Equals("Disabled: Can't stage 'modules/sub' because it is a git repository of its own. Discard it with d, or ignore it with i."))
}).
// Staging all files works if the nested repository is filtered out
FilterOrSearch("file").
Lines(
Equals("?? file").IsSelected(),
).
Press(keys.Files.ToggleStagedAll).
Lines(
Equals("A file").IsSelected(),
)
},
})
+1
View File
@@ -266,6 +266,7 @@ var tests = []*components.IntegrationTest{
file.StageAllWithoutChangedFiles,
file.StageChildrenRangeSelect,
file.StageDeletedRangeSelect,
file.StageNestedRepository,
file.StageRangeSelect,
file.StagedChangesInLowerPane,
filter_and_search.FilterByFileStatus,