Fix range select -> stage failure when deleted file is already staged (#3631)

- **PR Description**

Fix range select -> stage failure when deleted file is already staged.

Fixes https://github.com/jesseduffield/lazygit/issues/3603

- **Please check if the PR fulfills these requirements**

* [ ] Cheatsheets are up-to-date (run `go generate ./...`)
* [x] Code has been formatted (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#code-formatting))
* [x] Tests have been added/updated (see
[here](https://github.com/jesseduffield/lazygit/blob/master/pkg/integration/README.md)
for the integration test guide)
* [ ] Text is internationalised (see
[here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#internationalisation))
* [ ] Docs have been updated if necessary
* [x] You've read through your own file changes for silly mistakes etc

<!--
Be sure to name your PR with an imperative e.g. 'Add worktrees view'
see https://github.com/jesseduffield/lazygit/releases/tag/v0.40.0 for
examples
-->
This commit is contained in:
Jesse Duffield 2024-08-24 10:31:46 +10:00 committed by GitHub
commit ca9e006cca
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 64 additions and 5 deletions

View file

@ -401,16 +401,18 @@ func (self *FilesController) pressWithLock(selectedNodes []*filetree.FileNode) e
selectedNodes = normalisedSelectedNodes(selectedNodes)
// If any node has unstaged changes, we'll stage all the selected nodes. Otherwise,
// we unstage all the selected nodes.
if someNodesHaveUnstagedChanges(selectedNodes) {
// If any node has unstaged changes, we'll stage all the selected unstaged nodes (staging already staged deleted files/folders would fail).
// Otherwise, we unstage all the selected nodes.
unstagedSelectedNodes := filterNodesHaveUnstagedChanges(selectedNodes)
if len(unstagedSelectedNodes) > 0 {
self.c.LogAction(self.c.Tr.Actions.StageFile)
if err := self.optimisticChange(selectedNodes, self.optimisticStage); err != nil {
if err := self.optimisticChange(unstagedSelectedNodes, self.optimisticStage); err != nil {
return err
}
if err := self.c.Git().WorkingTree.StageFiles(toPaths(selectedNodes)); err != nil {
if err := self.c.Git().WorkingTree.StageFiles(toPaths(unstagedSelectedNodes)); err != nil {
return err
}
} else {
@ -1031,6 +1033,12 @@ func someNodesHaveStagedChanges(nodes []*filetree.FileNode) bool {
return lo.SomeBy(nodes, (*filetree.FileNode).GetHasStagedChanges)
}
func filterNodesHaveUnstagedChanges(nodes []*filetree.FileNode) []*filetree.FileNode {
return lo.Filter(nodes, func(node *filetree.FileNode, _ int) bool {
return node.GetHasUnstagedChanges()
})
}
func (self *FilesController) canRemove(selectedNodes []*filetree.FileNode) *types.DisabledReason {
submodules := self.c.Model().Submodules
submoduleCount := lo.CountBy(selectedNodes, func(node *filetree.FileNode) bool {

View file

@ -0,0 +1,50 @@
package file
import (
"github.com/jesseduffield/lazygit/pkg/config"
. "github.com/jesseduffield/lazygit/pkg/integration/components"
)
var StageDeletedRangeSelect = NewIntegrationTest(NewIntegrationTestArgs{
Description: "Stage a range of deleted files using range select",
ExtraCmdArgs: []string{},
Skip: false,
SetupConfig: func(config *config.AppConfig) {
},
SetupRepo: func(shell *Shell) {
shell.CreateFileAndAdd("file-a", "")
shell.CreateFileAndAdd("file-b", "")
shell.Commit("first commit")
shell.DeleteFile("file-a")
shell.DeleteFile("file-b")
},
Run: func(t *TestDriver, keys config.KeybindingConfig) {
t.Views().Files().
IsFocused().
Lines(
Contains(" D").Contains("file-a").IsSelected(),
Contains(" D").Contains("file-b"),
).
// Stage a single deleted file
PressPrimaryAction().
Lines(
Contains("D ").Contains("file-a").IsSelected(),
Contains(" D").Contains("file-b"),
).
Press(keys.Universal.ToggleRangeSelect).
NavigateToLine(Contains("file-b")).
// Stage both files while a deleted file is already staged
PressPrimaryAction().
Lines(
Contains("D ").Contains("file-a").IsSelected(),
Contains("D ").Contains("file-b").IsSelected(),
).
// Unstage; back to everything being unstaged
PressPrimaryAction().
Lines(
Contains(" D").Contains("file-a").IsSelected(),
Contains(" D").Contains("file-b").IsSelected(),
)
},
})

View file

@ -163,6 +163,7 @@ var tests = []*components.IntegrationTest{
file.RememberCommitMessageAfterFail,
file.RenameSimilarityThresholdChange,
file.StageChildrenRangeSelect,
file.StageDeletedRangeSelect,
file.StageRangeSelect,
filter_and_search.FilterCommitFiles,
filter_and_search.FilterFiles,