Documentation
¶
Overview ¶
Package ignore provides gitignore pattern matching for file paths.
This is a minimal, zero-dependency library for matching file paths against .gitignore patterns. It supports the common gitignore syntax including wildcards (*), double-star (**), negation (!), and directory-only patterns.
Basic Usage ¶
m := ignore.New()
// Add .git/ explicitly if you want Git-like behavior
m.AddPatterns("", []byte(".git/\n"))
// Load .gitignore content
content, _ := os.ReadFile(".gitignore")
m.AddPatterns("", content)
// Check if a path should be ignored
if m.Match("node_modules/foo.js", false) {
// path is ignored
}
Nested .gitignore Files ¶
For repositories with nested .gitignore files, specify the base path:
// Root .gitignore
m.AddPatterns("", rootContent)
// Nested src/.gitignore
m.AddPatterns("src", srcContent)
Thread Safety ¶
Matcher is safe for concurrent use. Multiple goroutines can call Match simultaneously. AddPatterns can also be called concurrently, though for best performance, batch all AddPatterns calls before concurrent Match calls.
Supported Syntax ¶
The following gitignore patterns are supported:
- Plain names: "debug.log" matches anywhere in tree
- Leading /: "/debug.log" matches only at base path
- Trailing /: "build/" matches directories only
- Single star: "*.log" matches any .log file
- Question mark: "?.txt" matches any single byte (not Unicode code point)
- Double star: "**/logs" matches at any depth
- Negation: "!important.log" re-includes a file
- Character classes: "[abc]" matches one byte: a, b, or c
- Ranges: "[a-z]", "[0-9]" match character ranges
- Negated classes: "[!abc]" matches any character except a, b, or c
- POSIX classes: "[[:alpha:]]", "[[:digit:]]" and 10 more
- Escapes: "\*", "\?", "\#", "\!" for literal matching
Note: ? and [...] operate on raw bytes, not Unicode code points, consistent with Git's behavior.
The backtrack iteration budget (MaxBacktrackIterations, default 10,000) is shared across all rules within a single Match call. This prevents pathological patterns distributed across many rules from causing excessive CPU usage.
Global Gitignore ¶
Load the user's global gitignore file (core.excludesFile or ~/.config/git/ignore) with a single call:
m := ignore.New()
if err := m.AddGlobalPatterns(); err != nil {
log.Fatal(err)
}
Repository Exclude File ¶
Load the repository's .git/info/exclude file:
if err := m.AddExcludePatterns(".git"); err != nil {
log.Fatal(err)
}
Path Normalization ¶
Input paths are automatically normalized:
- Backslashes converted to forward slashes (Windows only)
- Leading ./ removed
- Trailing / removed
- Consecutive slashes collapsed
On Windows, backslash paths work transparently:
m.Match("src\\main.go", false) // works on Windows
On Linux/macOS, backslashes are valid filename characters and are not converted. Always use forward slashes for portable code.
Package ignore provides gitignore pattern matching for file paths.
Index ¶
- Constants
- type MatchResult
- type Matcher
- func (m *Matcher) AddExcludePatterns(gitDir string) error
- func (m *Matcher) AddGlobalPatterns() error
- func (m *Matcher) AddPatterns(basePath string, content []byte) []ParseWarning
- func (m *Matcher) Match(path string, isDir bool) bool
- func (m *Matcher) MatchWithReason(path string, isDir bool) MatchResult
- func (m *Matcher) RuleCount() int
- func (m *Matcher) SetWarningHandler(fn WarningHandler)
- func (m *Matcher) Warnings() []ParseWarning
- type MatcherOptions
- type ParseWarning
- type WarningHandler
Examples ¶
Constants ¶
const ( // DefaultMaxPatterns is the maximum number of rules a Matcher will hold. // Excess rules are silently dropped with a warning. // Set MaxPatterns to 0 to use this default, or -1 for unlimited. DefaultMaxPatterns = 100_000 // DefaultMaxPatternLength is the maximum length of a single pattern line. // Lines exceeding this are skipped with a warning. // Set MaxPatternLength to 0 to use this default, or -1 for unlimited. DefaultMaxPatternLength = 4096 )
Default resource limits for pattern parsing.
const DefaultMaxBacktrackIterations = 10000
DefaultMaxBacktrackIterations is the default limit for pattern matching iterations. This prevents pathological patterns from causing excessive CPU usage. The budget is shared across all rules for a single Match call and covers both segment-level ** matching and character-level glob matching (*, ?). Can be overridden via MatcherOptions.
Variables ¶
This section is empty.
Functions ¶
This section is empty.
Types ¶
type MatchResult ¶
type MatchResult struct {
// Rule is the pattern string of the last matching rule (empty if Matched == false).
// If multiple rules matched, this is the final decisive rule.
Rule string
// BasePath is the directory containing the .gitignore that had the matching rule.
// Empty string means the root .gitignore.
BasePath string
// Line is the line number (1-indexed) in the .gitignore file.
// Zero if Matched == false.
Line int
// Ignored indicates the final decision: true if the path should be ignored.
// This accounts for negation rules.
Ignored bool
// Matched indicates whether any rule matched the path (regardless of negation).
// If false, no rules matched and the path is not ignored (default behavior).
// If true, at least one rule matched (including negation rules); check Ignored for the final result.
Matched bool
// Negated indicates whether the matching rule was a negation (started with !).
// When Negated == true and Matched == true, the path was re-included.
Negated bool
}
MatchResult provides detailed information about a match decision.
type Matcher ¶
type Matcher struct {
// contains filtered or unexported fields
}
Matcher holds compiled gitignore rules.
Thread Safety: Matcher is safe for concurrent use. Concurrent calls to AddPatterns and Match are logically safe and will never cause data races or corruption. However, interleaving AddPatterns with many concurrent Match calls introduces lock contention and may reduce throughput. For best performance, batch all AddPatterns calls before starting concurrent Match operations.
func New ¶
func New() *Matcher
New creates an empty Matcher with default options.
Example ¶
package main
import (
"fmt"
ignore "github.com/Sriram-PR/go-ignore"
)
func main() {
m := ignore.New()
m.AddPatterns("", []byte("*.log\nbuild/\n!important.log\n"))
fmt.Println(m.Match("debug.log", false))
fmt.Println(m.Match("src/main.go", false))
fmt.Println(m.Match("important.log", false))
fmt.Println(m.Match("build/output.js", false))
}
Output: true false false true
func NewWithOptions ¶
func NewWithOptions(opts MatcherOptions) *Matcher
NewWithOptions creates a Matcher with custom options.
Example ¶
package main
import (
"fmt"
ignore "github.com/Sriram-PR/go-ignore"
)
func main() {
m := ignore.NewWithOptions(ignore.MatcherOptions{
CaseInsensitive: true,
})
m.AddPatterns("", []byte("*.LOG\n"))
fmt.Println(m.Match("debug.log", false))
fmt.Println(m.Match("DEBUG.LOG", false))
}
Output: true true
func (*Matcher) AddExcludePatterns ¶ added in v0.3.1
AddExcludePatterns loads patterns from the repository's .git/info/exclude file and adds them to the matcher. The gitDir parameter is the path to the .git directory (e.g., ".git" or an absolute path).
If the exclude file does not exist, AddExcludePatterns returns nil (no error). Only real read failures are returned as errors.
Patterns are added with an empty basePath (root scope), matching Git's behavior where exclude patterns apply to all paths.
Parse warnings are reported through the standard warning mechanism: via the WarningHandler callback if set, otherwise collected and available through Warnings().
Trust model: this function trusts the caller-provided gitDir path and reads the file at gitDir/info/exclude. Callers should ensure gitDir points to a trusted .git directory.
Thread-safe: can be called concurrently with Match.
func (*Matcher) AddGlobalPatterns ¶ added in v0.2.5
AddGlobalPatterns loads the user's global gitignore file and adds its patterns to the matcher. The global gitignore path is resolved in order:
- git config --global core.excludesFile (if git is available)
- $XDG_CONFIG_HOME/git/ignore (if XDG_CONFIG_HOME is set)
- ~/.config/git/ignore (default fallback)
If the resolved file does not exist, AddGlobalPatterns returns nil (no error). Only real read failures are returned as errors.
Patterns are added with an empty basePath (root scope), matching Git's behavior where global patterns apply to all paths.
Parse warnings are reported through the standard warning mechanism: via the WarningHandler callback if set, otherwise collected and available through Warnings().
Trust model: this function trusts the file path returned by "git config" and reads its contents. It should only be called in environments where the git configuration is trusted.
Thread-safe: can be called concurrently with Match.
Example ¶
package main
import (
"fmt"
ignore "github.com/Sriram-PR/go-ignore"
)
func main() {
m := ignore.New()
if err := m.AddGlobalPatterns(); err != nil {
fmt.Println("error:", err)
return
}
fmt.Println("loaded:", m.RuleCount() >= 0)
}
Output: loaded: true
func (*Matcher) AddPatterns ¶
func (m *Matcher) AddPatterns(basePath string, content []byte) []ParseWarning
AddPatterns parses gitignore content and adds rules. basePath is the directory containing the .gitignore (empty string for root).
Input normalization (applied automatically):
- UTF-8 BOM is stripped if present
- CRLF and CR line endings are normalized to LF
- Trailing whitespace on each line is trimmed
Both nil and empty content produce no rules. Nil content returns immediately without acquiring locks; empty content goes through parsing (which yields nothing).
Returns warnings for malformed patterns. Warnings are only returned if no WarningHandler was set via SetWarningHandler; otherwise warnings go to the handler.
Thread-safe: can be called concurrently with Match. Performance note: For best performance when loading many .gitignore files, batch AddPatterns calls before starting concurrent Match operations to reduce lock contention.
func (*Matcher) Match ¶
Match returns true if the path should be ignored. path should be relative to repository root using forward slashes. On Windows, backslashes are automatically normalized to forward slashes. On Linux/macOS, backslashes are treated as literal filename characters (matching Git's behavior). isDir indicates whether the path is a directory. Thread-safe: can be called concurrently.
func (*Matcher) MatchWithReason ¶
func (m *Matcher) MatchWithReason(path string, isDir bool) MatchResult
MatchWithReason returns detailed information about why a path matches. Useful for debugging complex .gitignore setups. Thread-safe: can be called concurrently.
Result interpretation:
- Matched == false: No rules matched; path is not ignored (default)
- Matched == true, Ignored == true: Path is ignored by Rule
- Matched == true, Ignored == false: Path was ignored but re-included by negation Rule
Example ¶
package main
import (
"fmt"
ignore "github.com/Sriram-PR/go-ignore"
)
func main() {
m := ignore.New()
m.AddPatterns("", []byte("*.log\n!important.log\n"))
result := m.MatchWithReason("debug.log", false)
fmt.Printf("ignored=%v rule=%q\n", result.Ignored, result.Rule)
result = m.MatchWithReason("important.log", false)
fmt.Printf("ignored=%v negated=%v rule=%q\n", result.Ignored, result.Negated, result.Rule)
}
Output: ignored=true rule="*.log" ignored=false negated=true rule="!important.log"
func (*Matcher) RuleCount ¶
RuleCount returns the number of rules currently loaded. Useful for debugging and testing.
func (*Matcher) SetWarningHandler ¶
func (m *Matcher) SetWarningHandler(fn WarningHandler)
SetWarningHandler sets a callback for parse warnings. If set, warnings are reported via callback instead of being collected. Passing nil resets to collection mode (warnings available via Warnings()). IMPORTANT: Must be called before AddPatterns for the handler to receive warnings. If called after AddPatterns, only subsequent AddPatterns calls will use the handler.
Example ¶
package main
import (
"fmt"
ignore "github.com/Sriram-PR/go-ignore"
)
func main() {
m := ignore.New()
m.SetWarningHandler(func(basePath string, w ignore.ParseWarning) {
fmt.Printf("line %d: %s\n", w.Line, w.Message)
})
m.AddPatterns("", []byte("*.log\n!\n"))
}
Output: line 2: pattern is empty after processing
func (*Matcher) Warnings ¶
func (m *Matcher) Warnings() []ParseWarning
Warnings returns all collected parse warnings. Only populated if no WarningHandler was set.
type MatcherOptions ¶
type MatcherOptions struct {
// MaxBacktrackIterations limits ** pattern matching iterations.
// Default: DefaultMaxBacktrackIterations (10000).
// Set to 0 to use default. Set to -1 for unlimited (not recommended).
MaxBacktrackIterations int
// CaseInsensitive enables case-insensitive matching.
// Default: false (case-sensitive, matching Git's default behavior).
// Note: This affects pattern matching only, not filesystem behavior.
CaseInsensitive bool
// MaxPatterns limits the total number of rules a Matcher can hold.
// Default: DefaultMaxPatterns (100000). Set to -1 for unlimited.
MaxPatterns int
// MaxPatternLength limits the length of individual pattern lines.
// Lines exceeding this limit are skipped with a parse warning.
// Default: DefaultMaxPatternLength (4096). Set to -1 for unlimited.
MaxPatternLength int
}
MatcherOptions configures Matcher behavior.
type ParseWarning ¶
type ParseWarning struct {
Pattern string // The problematic pattern
Message string // Human-readable warning message
Line int // Line number (1-indexed)
BasePath string // Directory containing the .gitignore (empty for root)
}
ParseWarning represents a warning from parsing a .gitignore line. Warnings are generated for malformed patterns that are skipped during parsing.
type WarningHandler ¶
type WarningHandler func(basePath string, warning ParseWarning)
WarningHandler is called for each parse warning if set.