From b0ab6529c15e7b12c5faff386318060b3bce8fb8 Mon Sep 17 00:00:00 2001 From: Stefan Haller Date: Wed, 9 Apr 2025 13:27:44 +0200 Subject: [PATCH] Escape special characters when git-ignoring files --- pkg/commands/git_commands/working_tree.go | 11 ++++++++-- .../file/gitignore_special_characters.go | 21 ------------------- 2 files changed, 9 insertions(+), 23 deletions(-) diff --git a/pkg/commands/git_commands/working_tree.go b/pkg/commands/git_commands/working_tree.go index c967ca576..6a4c2210d 100644 --- a/pkg/commands/git_commands/working_tree.go +++ b/pkg/commands/git_commands/working_tree.go @@ -4,6 +4,7 @@ import ( "fmt" "os" "path/filepath" + "regexp" "github.com/go-errors/errors" "github.com/jesseduffield/lazygit/pkg/commands/models" @@ -230,15 +231,21 @@ func (self *WorkingTreeCommands) DiscardUnstagedFileChanges(file *models.File) e return self.cmd.New(cmdArgs).Run() } +// Escapes special characters in a filename for gitignore and exclude files +func escapeFilename(filename string) string { + re := regexp.MustCompile(`^[!#]|[\[\]*]`) + 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", filename) + return self.os.AppendLineToFile(".gitignore", escapeFilename(filename)) } // Exclude adds a file to the .git/info/exclude for the repo func (self *WorkingTreeCommands) Exclude(filename string) error { excludeFile := filepath.Join(self.repoPaths.repoGitDirPath, "info", "exclude") - return self.os.AppendLineToFile(excludeFile, filename) + return self.os.AppendLineToFile(excludeFile, escapeFilename(filename)) } // WorktreeFileDiff returns the diff of a file diff --git a/pkg/integration/tests/file/gitignore_special_characters.go b/pkg/integration/tests/file/gitignore_special_characters.go index 81849fc0c..84aa57ec3 100644 --- a/pkg/integration/tests/file/gitignore_special_characters.go +++ b/pkg/integration/tests/file/gitignore_special_characters.go @@ -55,33 +55,12 @@ var GitignoreSpecialCharacters = NewIntegrationTest(NewIntegrationTestArgs{ excludeFile("file[x]") t.Views().Files(). - /* EXPECTED: Lines( Equals("▼ /"), Equals(" ?? .gitignore"), Equals(" ?? abc_def"), ) - ACTUAL: - As you can see, it did ignore the 'file!abc' and 'file#abc' files - correctly. Those don't need to be quoted because # and ! are only - special at the beginning. - Most of the other files are not ignored properly because their - special characters need to be escaped. For * it's the other way - round: while it does hide 'abc*def', it also hides 'abc_def', - which we don't want. - */ - Lines( - Equals("▼ /"), - Equals(" ?? !file"), - Equals(" ?? #file"), - Equals(" ?? .gitignore"), - Equals(" ?? file[x]"), - ) - - /* EXPECTED: t.FileSystem().FileContent(".gitignore", Equals("\\#file\nfile#abc\n\\!file\nfile!abc\nabc\\*def\nfile\\[x\\]\n")) - ACTUAL: */ - t.FileSystem().FileContent(".gitignore", Equals("#file\nfile#abc\n!file\nfile!abc\nabc*def\nfile[x]\n")) }, })