From 48a8a71d31640610c8e2d7c810d8172c3f68f8da Mon Sep 17 00:00:00 2001 From: Dawid Pietrykowski Date: Wed, 28 Jan 2026 11:44:32 +0100 Subject: [PATCH] Fix gitignore path collisions Paths added to ignore/exclude files need to be prefixed with a forward slash to point to a specific file in the directory tree. Without that prefix a file at root called `file` (added to `.gitignore` as `file`) would match with `./file` and `./src/file`. --- pkg/commands/git_commands/working_tree.go | 4 ++-- pkg/integration/tests/file/gitignore.go | 6 +++--- pkg/integration/tests/file/gitignore_special_characters.go | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/pkg/commands/git_commands/working_tree.go b/pkg/commands/git_commands/working_tree.go index e74ccf1e5..55159a7f9 100644 --- a/pkg/commands/git_commands/working_tree.go +++ b/pkg/commands/git_commands/working_tree.go @@ -233,10 +233,10 @@ 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 +// Escapes special characters in a filename for gitignore and exclude files, and prepends `/` func escapeFilename(filename string) string { re := regexp.MustCompile(`^[!#]|[\[\]*]`) - return re.ReplaceAllString(filename, `\${0}`) + return "/" + re.ReplaceAllString(filename, `\${0}`) } // Ignore adds a file to the gitignore for the repo diff --git a/pkg/integration/tests/file/gitignore.go b/pkg/integration/tests/file/gitignore.go index 0d7c1a019..6ba8ebf08 100644 --- a/pkg/integration/tests/file/gitignore.go +++ b/pkg/integration/tests/file/gitignore.go @@ -50,7 +50,7 @@ var Gitignore = NewIntegrationTest(NewIntegrationTestArgs{ t.ExpectPopup().Menu().Title(Equals("Ignore or exclude file")).Select(Contains("Add to .git/info/exclude")).Confirm() t.FileSystem().FileContent(".gitignore", Equals("")) - t.FileSystem().FileContent(".git/info/exclude", Contains("toExclude")) + t.FileSystem().FileContent(".git/info/exclude", Contains("/toExclude")) }). SelectNextItem(). Press(keys.Files.IgnoreFile). @@ -58,8 +58,8 @@ var Gitignore = NewIntegrationTest(NewIntegrationTestArgs{ Tap(func() { t.ExpectPopup().Menu().Title(Equals("Ignore or exclude file")).Select(Contains("Add to .gitignore")).Confirm() - t.FileSystem().FileContent(".gitignore", Equals("toIgnore\n")) - t.FileSystem().FileContent(".git/info/exclude", Contains("toExclude")) + t.FileSystem().FileContent(".gitignore", Equals("/toIgnore\n")) + t.FileSystem().FileContent(".git/info/exclude", Contains("/toExclude")) }) }, }) diff --git a/pkg/integration/tests/file/gitignore_special_characters.go b/pkg/integration/tests/file/gitignore_special_characters.go index 84aa57ec3..83e33a1d4 100644 --- a/pkg/integration/tests/file/gitignore_special_characters.go +++ b/pkg/integration/tests/file/gitignore_special_characters.go @@ -61,6 +61,6 @@ var GitignoreSpecialCharacters = NewIntegrationTest(NewIntegrationTestArgs{ Equals(" ?? abc_def"), ) - t.FileSystem().FileContent(".gitignore", Equals("\\#file\nfile#abc\n\\!file\nfile!abc\nabc\\*def\nfile\\[x\\]\n")) + t.FileSystem().FileContent(".gitignore", Equals("/\\#file\n/file#abc\n/\\!file\n/file!abc\n/abc\\*def\n/file\\[x\\]\n")) }, })