Fix multi-select ignore/exclude for tracked ranges

A range select that crosses a tracked directory boundary breaks
because `git rm -r --cached -- dir` removes its descendants from the
index, so a subsequent child-targeted call fails with pathspec errors.
Untracked nodes in a mixed range hit the same problem since they
aren't in the index at all. Filter the selection through
`normalisedSelectedNodes` and only unstage/rm the nodes that are
actually tracked.
This commit is contained in:
phanium 2026-07-26 00:23:43 +08:00
parent ffab5b6ac9
commit 6905d62af6
3 changed files with 63 additions and 6 deletions

View file

@ -974,15 +974,19 @@ func (self *FilesController) unstageFiles(node *filetree.FileNode) error {
func (self *FilesController) ignoreOrExcludeTracked(nodes []*filetree.FileNode, trAction string, f func([]string) error) error {
self.c.LogAction(trAction)
nodes = normalisedSelectedNodes(nodes)
paths := make([]string, 0, len(nodes))
for _, node := range nodes {
// not 100% sure if this is necessary but I'll assume it is
if err := self.unstageFiles(node); err != nil {
return err
}
if node.GetIsTracked() {
// not 100% sure if this is necessary but I'll assume it is
if err := self.unstageFiles(node); err != nil {
return err
}
if err := self.c.Git().WorkingTree.RemoveTrackedFiles(node.GetPath()); err != nil {
return err
if err := self.c.Git().WorkingTree.RemoveTrackedFiles(node.GetPath()); err != nil {
return err
}
}
paths = append(paths, node.GetPath())
@ -999,6 +1003,8 @@ func (self *FilesController) ignoreOrExcludeTracked(nodes []*filetree.FileNode,
func (self *FilesController) ignoreOrExcludeUntracked(nodes []*filetree.FileNode, trAction string, f func([]string) error) error {
self.c.LogAction(trAction)
nodes = normalisedSelectedNodes(nodes)
paths := make([]string, 0, len(nodes))
for _, node := range nodes {
paths = append(paths, node.GetPath())

View file

@ -0,0 +1,50 @@
package file
import (
"github.com/jesseduffield/lazygit/pkg/config"
. "github.com/jesseduffield/lazygit/pkg/integration/components"
)
var GitignoreTrackedRangeSelect = NewIntegrationTest(NewIntegrationTestArgs{
Description: "Range-select across a tracked directory and its children (parent+child case)",
ExtraCmdArgs: []string{},
Skip: false,
SetupConfig: func(config *config.AppConfig) {
},
SetupRepo: func(shell *Shell) {
shell.CreateFileAndAdd("dir-tracked/file-a", "x")
shell.CreateFileAndAdd("dir-tracked/file-b", "x")
shell.CreateFileAndAdd("tracked1", "x")
shell.Commit("initial")
shell.UpdateFile("dir-tracked/file-a", "y")
shell.UpdateFile("dir-tracked/file-b", "y")
shell.UpdateFile("tracked1", "y")
},
Run: func(t *TestDriver, keys config.KeybindingConfig) {
t.Views().Files().
IsFocused().
Lines(
Equals("▼ /").IsSelected(),
Equals(" ▼ dir-tracked"),
Equals(" M file-a"),
Equals(" M file-b"),
Equals(" M tracked1"),
).
NavigateToLine(Contains("dir-tracked")).
Press(keys.Universal.ToggleRangeSelect).
NavigateToLine(Contains("tracked1")).
Press(keys.Files.IgnoreFile).
Tap(func() {
t.ExpectPopup().Menu().Title(Equals("Ignore or exclude file")).
Select(Contains("Add to .gitignore")).
Confirm()
t.ExpectPopup().Confirmation().
Title(Equals("Ignore tracked file")).
Content(Contains("tracked file")).
Confirm()
t.FileSystem().FileContent(".gitignore", Equals("/dir-tracked\n/tracked1\n"))
})
},
})

View file

@ -242,6 +242,7 @@ var tests = []*components.IntegrationTest{
file.Gitignore,
file.GitignoreRangeSelect,
file.GitignoreSpecialCharacters,
file.GitignoreTrackedRangeSelect,
file.RememberCommitMessageAfterFail,
file.RenameSimilarityThresholdChange,
file.RenamedFiles,