mirror of
https://github.com/jesseduffield/lazygit.git
synced 2026-09-10 07:36:27 -04:00
Merge 6905d62af6 into 8924bca76f
This commit is contained in:
commit
7add03f050
|
|
@ -367,19 +367,29 @@ func escapeFilename(filename string) string {
|
|||
return "/" + re.ReplaceAllString(filename, `\${0}`)
|
||||
}
|
||||
|
||||
// Ignore adds a file to the gitignore for the repo
|
||||
func (self *WorkingTreeCommands) Ignore(filename string) error {
|
||||
return self.os.AppendLineToFile(".gitignore", escapeFilename(filename))
|
||||
// Ignore adds the given files to the gitignore for the repo
|
||||
func (self *WorkingTreeCommands) Ignore(filenames []string) error {
|
||||
for _, filename := range filenames {
|
||||
if err := self.os.AppendLineToFile(".gitignore", escapeFilename(filename)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// Exclude adds a file to the .git/info/exclude for the repo
|
||||
func (self *WorkingTreeCommands) Exclude(filename string) error {
|
||||
// Exclude adds the given files to the .git/info/exclude for the repo
|
||||
func (self *WorkingTreeCommands) Exclude(filenames []string) error {
|
||||
infoDir := filepath.Join(self.repoPaths.repoGitDirPath, "info")
|
||||
if err := os.MkdirAll(infoDir, 0o755); err != nil {
|
||||
return err
|
||||
}
|
||||
excludeFile := filepath.Join(infoDir, "exclude")
|
||||
return self.os.AppendLineToFile(excludeFile, escapeFilename(filename))
|
||||
for _, filename := range filenames {
|
||||
if err := self.os.AppendLineToFile(excludeFile, escapeFilename(filename)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// WorktreeFileDiff returns the diff of a file
|
||||
|
|
|
|||
|
|
@ -105,8 +105,8 @@ func (self *FilesController) GetKeybindings(opts types.KeybindingsOpts) []*types
|
|||
},
|
||||
{
|
||||
Keys: opts.GetKeys(opts.Config.Files.IgnoreFile),
|
||||
Handler: self.withItem(self.ignoreOrExcludeMenu),
|
||||
GetDisabledReason: self.require(self.singleItemSelected()),
|
||||
Handler: self.withItems(self.ignoreOrExcludeMenu),
|
||||
GetDisabledReason: self.require(self.itemsSelected()),
|
||||
Description: self.c.Tr.Actions.IgnoreExcludeFile,
|
||||
OpensMenu: true,
|
||||
},
|
||||
|
|
@ -973,18 +973,28 @@ func (self *FilesController) unstageFiles(node *filetree.FileNode) error {
|
|||
})
|
||||
}
|
||||
|
||||
func (self *FilesController) ignoreOrExcludeTracked(node *filetree.FileNode, trAction string, f func(string) error) error {
|
||||
func (self *FilesController) ignoreOrExcludeTracked(nodes []*filetree.FileNode, trAction string, f func([]string) error) error {
|
||||
self.c.LogAction(trAction)
|
||||
// not 100% sure if this is necessary but I'll assume it is
|
||||
if err := self.unstageFiles(node); err != nil {
|
||||
return err
|
||||
|
||||
nodes = normalisedSelectedNodes(nodes)
|
||||
|
||||
paths := make([]string, 0, len(nodes))
|
||||
for _, node := range nodes {
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
paths = append(paths, node.GetPath())
|
||||
}
|
||||
|
||||
if err := self.c.Git().WorkingTree.RemoveTrackedFiles(node.GetPath()); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := f(node.GetPath()); err != nil {
|
||||
if err := f(paths); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
|
@ -992,10 +1002,17 @@ func (self *FilesController) ignoreOrExcludeTracked(node *filetree.FileNode, trA
|
|||
return nil
|
||||
}
|
||||
|
||||
func (self *FilesController) ignoreOrExcludeUntracked(node *filetree.FileNode, trAction string, f func(string) error) error {
|
||||
func (self *FilesController) ignoreOrExcludeUntracked(nodes []*filetree.FileNode, trAction string, f func([]string) error) error {
|
||||
self.c.LogAction(trAction)
|
||||
|
||||
if err := f(node.GetPath()); err != nil {
|
||||
nodes = normalisedSelectedNodes(nodes)
|
||||
|
||||
paths := make([]string, 0, len(nodes))
|
||||
for _, node := range nodes {
|
||||
paths = append(paths, node.GetPath())
|
||||
}
|
||||
|
||||
if err := f(paths); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
|
@ -1003,44 +1020,56 @@ func (self *FilesController) ignoreOrExcludeUntracked(node *filetree.FileNode, t
|
|||
return nil
|
||||
}
|
||||
|
||||
func (self *FilesController) ignoreOrExcludeFile(node *filetree.FileNode, trText string, trPrompt string, trAction string, f func(string) error) error {
|
||||
if node.GetIsTracked() {
|
||||
func (self *FilesController) ignoreOrExcludeFiles(nodes []*filetree.FileNode, trText string, trPrompt string, trAction string, f func([]string) error) error {
|
||||
hasTracked := false
|
||||
for _, node := range nodes {
|
||||
if node.GetIsTracked() {
|
||||
hasTracked = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if hasTracked {
|
||||
self.c.Confirm(types.ConfirmOpts{
|
||||
Title: trText,
|
||||
Prompt: trPrompt,
|
||||
HandleConfirm: func() error {
|
||||
return self.ignoreOrExcludeTracked(node, trAction, f)
|
||||
return self.ignoreOrExcludeTracked(nodes, trAction, f)
|
||||
},
|
||||
})
|
||||
|
||||
return nil
|
||||
}
|
||||
return self.ignoreOrExcludeUntracked(node, trAction, f)
|
||||
return self.ignoreOrExcludeUntracked(nodes, trAction, f)
|
||||
}
|
||||
|
||||
func (self *FilesController) ignore(node *filetree.FileNode) error {
|
||||
if node.GetPath() == ".gitignore" {
|
||||
return errors.New(self.c.Tr.Actions.IgnoreFileErr)
|
||||
func (self *FilesController) ignore(nodes []*filetree.FileNode) error {
|
||||
for _, node := range nodes {
|
||||
if node.GetPath() == ".gitignore" {
|
||||
return errors.New(self.c.Tr.Actions.IgnoreFileErr)
|
||||
}
|
||||
}
|
||||
return self.ignoreOrExcludeFile(node, self.c.Tr.IgnoreTracked, self.c.Tr.IgnoreTrackedPrompt, self.c.Tr.Actions.IgnoreExcludeFile, self.c.Git().WorkingTree.Ignore)
|
||||
return self.ignoreOrExcludeFiles(nodes, self.c.Tr.IgnoreTracked, self.c.Tr.IgnoreTrackedPrompt, self.c.Tr.Actions.IgnoreExcludeFile, self.c.Git().WorkingTree.Ignore)
|
||||
}
|
||||
|
||||
func (self *FilesController) exclude(node *filetree.FileNode) error {
|
||||
if node.GetPath() == ".gitignore" {
|
||||
return errors.New(self.c.Tr.Actions.ExcludeGitIgnoreErr)
|
||||
func (self *FilesController) exclude(nodes []*filetree.FileNode) error {
|
||||
for _, node := range nodes {
|
||||
if node.GetPath() == ".gitignore" {
|
||||
return errors.New(self.c.Tr.Actions.ExcludeGitIgnoreErr)
|
||||
}
|
||||
}
|
||||
|
||||
return self.ignoreOrExcludeFile(node, self.c.Tr.ExcludeTracked, self.c.Tr.ExcludeTrackedPrompt, self.c.Tr.Actions.ExcludeFile, self.c.Git().WorkingTree.Exclude)
|
||||
return self.ignoreOrExcludeFiles(nodes, self.c.Tr.ExcludeTracked, self.c.Tr.ExcludeTrackedPrompt, self.c.Tr.Actions.ExcludeFile, self.c.Git().WorkingTree.Exclude)
|
||||
}
|
||||
|
||||
func (self *FilesController) ignoreOrExcludeMenu(node *filetree.FileNode) error {
|
||||
func (self *FilesController) ignoreOrExcludeMenu(nodes []*filetree.FileNode) error {
|
||||
return self.c.Menu(types.CreateMenuOptions{
|
||||
Title: self.c.Tr.Actions.IgnoreExcludeFile,
|
||||
Items: []*types.MenuItem{
|
||||
{
|
||||
LabelColumns: []string{self.c.Tr.IgnoreFile},
|
||||
OnPress: func() error {
|
||||
if err := self.ignore(node); err != nil {
|
||||
if err := self.ignore(nodes); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
|
|
@ -1050,7 +1079,7 @@ func (self *FilesController) ignoreOrExcludeMenu(node *filetree.FileNode) error
|
|||
{
|
||||
LabelColumns: []string{self.c.Tr.ExcludeFile},
|
||||
OnPress: func() error {
|
||||
if err := self.exclude(node); err != nil {
|
||||
if err := self.exclude(nodes); err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
|
|
|
|||
65
pkg/integration/tests/file/gitignore_range_select.go
Normal file
65
pkg/integration/tests/file/gitignore_range_select.go
Normal file
|
|
@ -0,0 +1,65 @@
|
|||
package file
|
||||
|
||||
import (
|
||||
"github.com/jesseduffield/lazygit/pkg/config"
|
||||
. "github.com/jesseduffield/lazygit/pkg/integration/components"
|
||||
)
|
||||
|
||||
var GitignoreRangeSelect = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
Description: "Ignore and exclude multiple files at once via range select",
|
||||
ExtraCmdArgs: []string{},
|
||||
Skip: false,
|
||||
SetupConfig: func(config *config.AppConfig) {
|
||||
},
|
||||
SetupRepo: func(shell *Shell) {
|
||||
shell.CreateFile(".gitignore", "")
|
||||
shell.CreateFile("toIgnore1", "")
|
||||
shell.CreateFile("toIgnore2", "")
|
||||
shell.CreateFile("toIgnore3", "")
|
||||
shell.CreateFile("toExclude1", "")
|
||||
shell.CreateFile("toExclude2", "")
|
||||
shell.CreateFile("toExclude3", "")
|
||||
},
|
||||
Run: func(t *TestDriver, keys config.KeybindingConfig) {
|
||||
t.Views().Files().
|
||||
IsFocused().
|
||||
Lines(
|
||||
Equals("▼ /").IsSelected(),
|
||||
Equals(" ?? .gitignore"),
|
||||
Equals(" ?? toExclude1"),
|
||||
Equals(" ?? toExclude2"),
|
||||
Equals(" ?? toExclude3"),
|
||||
Equals(" ?? toIgnore1"),
|
||||
Equals(" ?? toIgnore2"),
|
||||
Equals(" ?? toIgnore3"),
|
||||
).
|
||||
// Select range from toIgnore1 to toIgnore3
|
||||
NavigateToLine(Contains("toIgnore1")).
|
||||
Press(keys.Universal.ToggleRangeSelect).
|
||||
NavigateToLine(Contains("toIgnore3")).
|
||||
Press(keys.Files.IgnoreFile).
|
||||
// Ignore all selected files
|
||||
Tap(func() {
|
||||
t.ExpectPopup().Menu().Title(Equals("Ignore or exclude file")).
|
||||
Select(Contains("Add to .gitignore")).
|
||||
Confirm()
|
||||
|
||||
t.FileSystem().FileContent(".gitignore", Equals("/toIgnore1\n/toIgnore2\n/toIgnore3\n"))
|
||||
}).
|
||||
// Dismiss the range select mode for the next set of steps
|
||||
Press(keys.Universal.ToggleRangeSelect).
|
||||
// Select range from toExclude1 to toExclude3
|
||||
NavigateToLine(Contains("toExclude1")).
|
||||
Press(keys.Universal.ToggleRangeSelect).
|
||||
NavigateToLine(Contains("toExclude3")).
|
||||
Press(keys.Files.IgnoreFile).
|
||||
// Exclude all selected files
|
||||
Tap(func() {
|
||||
t.ExpectPopup().Menu().Title(Equals("Ignore or exclude file")).
|
||||
Select(Contains("Add to .git/info/exclude")).
|
||||
Confirm()
|
||||
|
||||
t.FileSystem().FileContent(".git/info/exclude", Contains("/toExclude1\n/toExclude2\n/toExclude3\n"))
|
||||
})
|
||||
},
|
||||
})
|
||||
50
pkg/integration/tests/file/gitignore_tracked_range_select.go
Normal file
50
pkg/integration/tests/file/gitignore_tracked_range_select.go
Normal 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"))
|
||||
})
|
||||
},
|
||||
})
|
||||
|
|
@ -245,7 +245,9 @@ var tests = []*components.IntegrationTest{
|
|||
file.DiscardVariousChangesRangeSelect,
|
||||
file.ExcludeWithoutInfoDir,
|
||||
file.Gitignore,
|
||||
file.GitignoreRangeSelect,
|
||||
file.GitignoreSpecialCharacters,
|
||||
file.GitignoreTrackedRangeSelect,
|
||||
file.RememberCommitMessageAfterFail,
|
||||
file.RenameSimilarityThresholdChange,
|
||||
file.RenamedFiles,
|
||||
|
|
|
|||
Loading…
Reference in a new issue