go-git ignores files inside un-ignored directory with wildcard pattern
Bug Description
When using a .gitignore file with a wildcard ignore * followed by a directory-only inclusion like !dir/, go-git fails to ignore files inside dir/, whereas standard Git ignores them.
In plumbing/format/gitignore/pattern.go, the simpleNameMatch function iterates over all components of a path. If any component matches the pattern, it returns true (matched), unless it's the last component and it's checking dirOnly.
For a path ["dir", "file.txt"] and pattern !dir/:
- Component
dirmatchesdir. - It is not the last component (
i == 0,len(path)-1 == 1). - The function returns
true(matched). - This causes the file to be included, overriding the
*pattern.
Effectively, !dir/ acts as !dir/** in go-git.
(I did use AI to generate a bug report with identifiers that avoid the non-public parts of my project, I edited it myself and ran the reproducer myself.)
go-git Version
488798e28afdf2a31fc6ce32fd3ec8023025f449
Steps to Reproduce
To reproduce:
Standard Git:
mkdir git-repro
cd git-repro
git init
echo '*' > .gitignore
echo '!my-dir/' >> .gitignore
mkdir -p my-dir/sub
echo 'test' > my-dir/sub/file.txt
git statusThis would say: nothing to commit (the file inside my-dir is ignored).
git based on go-git:
Run these commands to set up the environment and run the reproducer:
mkdir gogit-repro
cd gogit-repro
# Save the Go code below as repro.go
go mod init repro
go get github.com/go-git/go-git/v5
go run repro.go// repro.go
package main
import (
"fmt"
"os"
"github.com/go-git/go-git/v5"
)
func main() {
// Setup environment
os.MkdirAll("my-dir/sub", 0755)
os.WriteFile(".gitignore", []byte("*\n!my-dir/\n"), 0644)
os.WriteFile("my-dir/sub/file.txt", []byte("test"), 0644)
r, err := git.PlainInit(".", false)
if err != nil {
panic(err)
}
w, err := r.Worktree()
if err != nil {
panic(err)
}
status, err := w.Status()
if err != nil {
panic(err)
}
fmt.Println("Status:")
for path, s := range status {
fmt.Printf(" %s: %c\n", path, s.Worktree)
}
}Actual Output:
Status:
my-dir/sub/file.txt: ?(? indicates Untracked, meaning it was not ignored).
Additional Information
No response
Source: go-git/go-git