Summary
gitignore.New("") auto-loads patterns from the process working directory's .gitignore, .git/info/exclude, and the global excludes file. When callers only intend to use AddPatterns for programmatic rules, the filesystem-loaded patterns silently contaminate the matcher.
Reproduction
package main
import (
"fmt"
"os"
"github.com/git-pkgs/gitignore"
)
func main() {
// Create .gitignore in CWD that excludes *.exe
os.WriteFile(".gitignore", []byte("*.exe\n"), 0644)
defer os.Remove(".gitignore")
// Create matcher with ONLY *.tmp as a rule
m := gitignore.New("")
m.AddPatterns([]byte("*.tmp"), "")
// Expect false — we never added *.exe
fmt.Println(m.MatchPath("test.exe", false)) // prints: true
}
Expected behavior
When a caller passes root="" and only adds patterns via AddPatterns, the matcher should only match against the explicitly added patterns.
Actual behavior
New("") resolves "" as the CWD and loads:
- Global git excludes (
core.excludesfile)
.git/info/exclude from CWD
.gitignore from CWD
These filesystem-sourced patterns are invisible to the caller and cannot be distinguished from programmatic patterns.
Impact
In our project (SelectiveMirror), this caused the filter engine to silently inherit .gitignore rules from the repository, producing ~30 false-positive "excluded file" reports. Files that were correctly synced to a remote were misclassified as "leaks" and would have been deleted by the cleanup routine.
Suggested fix
Either:
- Skip filesystem loading when
root is empty — treat New("") as equivalent to &Matcher{} (no filesystem patterns)
- Add a constructor that skips filesystem loading — e.g.
NewEmpty() or NewProgrammatic() that only creates a bare matcher for AddPatterns use
Workaround
We replaced gitignore.New("") with &gitignore.Matcher{} (zero-value struct), which creates a matcher without loading any filesystem patterns. AddPatterns works correctly on this bare struct.
Version
github.com/git-pkgs/gitignore v1.1.1
Summary
gitignore.New("")auto-loads patterns from the process working directory's.gitignore,.git/info/exclude, and the global excludes file. When callers only intend to useAddPatternsfor programmatic rules, the filesystem-loaded patterns silently contaminate the matcher.Reproduction
Expected behavior
When a caller passes
root=""and only adds patterns viaAddPatterns, the matcher should only match against the explicitly added patterns.Actual behavior
New("")resolves""as the CWD and loads:core.excludesfile).git/info/excludefrom CWD.gitignorefrom CWDThese filesystem-sourced patterns are invisible to the caller and cannot be distinguished from programmatic patterns.
Impact
In our project (SelectiveMirror), this caused the filter engine to silently inherit
.gitignorerules from the repository, producing ~30 false-positive "excluded file" reports. Files that were correctly synced to a remote were misclassified as "leaks" and would have been deleted by the cleanup routine.Suggested fix
Either:
rootis empty — treatNew("")as equivalent to&Matcher{}(no filesystem patterns)NewEmpty()orNewProgrammatic()that only creates a bare matcher forAddPatternsuseWorkaround
We replaced
gitignore.New("")with&gitignore.Matcher{}(zero-value struct), which creates a matcher without loading any filesystem patterns.AddPatternsworks correctly on this bare struct.Version
github.com/git-pkgs/gitignore v1.1.1