gitignore

package module
v1.3.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 13, 2026 License: MIT Imports: 9 Imported by: 2

README

gitignore

A Go library for matching paths against gitignore rules. Pattern matching uses a direct wildmatch implementation (two-pointer backtracking, same algorithm as git's wildmatch.c) rather than compiling patterns to regexes or delegating to filepath.Match

  • Wildmatch engine modeled on git's own wildmatch.c, tested against git's wildmatch test suite
  • Bracket expressions with ranges, negation, backslash escapes, and all 12 POSIX character classes ([:alnum:], [:alpha:], etc.)
  • Proper ** handling (zero or more directories, only when standalone between separators)
  • core.excludesfile support with XDG fallback
  • Automatic nested .gitignore discovery via NewFromDirectory and Walk
  • Negation patterns with correct last-match-wins semantics
  • Directory-only patterns (trailing /) with descendant matching
  • Match provenance via MatchDetail (which pattern, file, and line number matched)
  • Invalid pattern surfacing via Errors()
  • Fast rejection for literal names and suffix patterns like *.log
import "github.com/git-pkgs/gitignore"

Loading patterns

New reads the user's global excludes file, .git/info/exclude, and the root .gitignore:

m := gitignore.New("/path/to/repo")
m.Match("vendor/lib.go")  // true if matched
m.Match("vendor/")        // trailing slash tests as directory

For repos with nested .gitignore files, NewFromDirectory walks the tree and loads them all, scoped to their containing directory:

m := gitignore.NewFromDirectory("/path/to/repo")

To create a matcher with only programmatic patterns (no filesystem loading), pass an empty root:

m := gitignore.New("")
m.AddPatterns([]byte("*.tmp\n"), "")

You can also add patterns to any matcher manually:

m.AddFromFile("/path/to/repo/src/.gitignore", "src")
m.AddPatterns([]byte("*.log\nbuild/\n"), "")

To limit the bytes read from each ignore file, pass MaxIgnoreFileSize to any constructor or walk function:

m := gitignore.NewFromDirectory("/path/to/repo", gitignore.MaxIgnoreFileSize(1<<20))

The limit applies to global excludes, .git/info/exclude, and .gitignore files, including later AddFromFile calls. Oversized files are skipped entirely and recorded in Errors() with their source path and line zero. Nonpositive limits are unlimited. AddPatterns is unaffected, and the limit does not cap total memory across files.

Matching

Match uses the trailing-slash convention to distinguish files from directories. If you already know whether the path is a directory, MatchPath avoids that:

m.Match("vendor/")             // directory
m.MatchPath("vendor", true)    // same thing, no trailing slash needed

To find out which pattern matched (useful for debugging), use MatchDetail:

r := m.MatchDetail("app.log")
if r.Matched {
    fmt.Printf("ignored by %s (line %d of %s)\n", r.Pattern, r.Line, r.Source)
}

Walking a directory tree

Walk traverses the repo, loading .gitignore files as it descends and skipping ignored entries. It never descends into .git or ignored directories.

gitignore.Walk("/path/to/repo", func(path string, d fs.DirEntry) error {
    fmt.Println(path)
    return nil
})

WalkFrom walks a subdirectory while still respecting root-level rules. It loads global excludes, .git/info/exclude, the root .gitignore, and every .gitignore between the root and the start directory before walking, so patterns scoped above the start still apply. Paths passed to fn are relative to the root.

gitignore.WalkFrom("/path/to/repo", "src/pkg", func(path string, d fs.DirEntry) error {
    fmt.Println(path) // e.g. "src/pkg/lib.go"
    return nil
})

Walk and WalkFrom accept the same options as trailing arguments. With MaxIgnoreFileSize set they stop and return an *IgnoreFileSizeError when an oversized file is encountered. Its Path and Limit fields identify the file and configured byte limit; use errors.As to inspect it. Callbacks may already have run for earlier entries.

Error handling

Invalid patterns (like unknown POSIX character classes) are silently skipped during matching. To inspect them:

for _, err := range m.Errors() {
    fmt.Println(err) // includes source file, line number, and reason
}

Thread safety

A Matcher is safe for concurrent Match/MatchPath/MatchDetail calls once construction is complete. Don't call AddPatterns or AddFromFile concurrently with matching.

Match semantics

Paths should use forward slashes and be relative to the repository root. An ignored parent directory excludes all its descendants; otherwise, the last matching rule for the path wins.

Benchmarks

Run benchmarks on an otherwise idle machine, using the same Go toolchain for both revisions. Record repeated samples and memory allocations:

go test -run '^$' -bench . -benchmem -count=10 -cpu=1

BenchmarkCompile and BenchmarkWalkTree include filesystem reads and a Git subprocess through New; BenchmarkAddPatterns measures parsing without filesystem access. Compare samples with benchstat and check the timing spread before quoting speed changes.

License

MIT

Documentation

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func Walk added in v1.1.0

func Walk(root string, fn func(path string, d fs.DirEntry) error, opts ...Option) error

Walk walks the directory tree rooted at root, calling fn for each file and directory that is not ignored by gitignore rules. It loads .gitignore files as it descends, so patterns from deeper directories take effect for their subtrees. The .git directory is always skipped.

Paths passed to fn are relative to root and use the OS path separator. The root directory itself is not passed to fn.

With MaxIgnoreFileSize set, an oversized ignore file stops the walk and is returned as an *IgnoreFileSizeError.

func WalkFrom added in v1.2.0

func WalkFrom(root, start string, fn func(path string, d fs.DirEntry) error, opts ...Option) error

WalkFrom walks the directory tree starting at a subdirectory of root, calling fn for each file and directory that is not ignored by gitignore rules. Unlike Walk, it separates the repository root (used to find .git/info/exclude and the root .gitignore) from the directory where the walk begins. Any .gitignore files between root and start are loaded before the walk begins, so their patterns apply correctly.

The start parameter is a path relative to root (e.g. "src/pkg"), using either forward slashes or the OS path separator. Paths passed to fn are relative to root (not to start) and use the OS path separator. The start directory itself is passed to fn.

With MaxIgnoreFileSize set, an oversized ignore file stops the walk and is returned as an *IgnoreFileSizeError.

Types

type IgnoreFileSizeError added in v1.3.0

type IgnoreFileSizeError struct {
	Path  string
	Limit int64
}

IgnoreFileSizeError reports an ignore file that exceeded its byte limit.

func (*IgnoreFileSizeError) Error added in v1.3.0

func (e *IgnoreFileSizeError) Error() string

type MatchResult added in v1.1.0

type MatchResult struct {
	Ignored bool   // true if the path should be ignored
	Matched bool   // true if any pattern matched (false means no pattern applied)
	Pattern string // original pattern text (empty if no match)
	Source  string // file the pattern came from (empty for programmatic patterns)
	Line    int    // 1-based line number in Source (0 if no match)
	Negate  bool   // true if the matching pattern was a negation (!)
}

MatchResult describes which pattern matched a path and whether the path is ignored.

type Matcher

type Matcher struct {
	// contains filtered or unexported fields
}

Matcher checks paths against gitignore rules collected from .gitignore files, .git/info/exclude, and any additional patterns. Patterns from subdirectory .gitignore files are scoped to paths within that directory.

Paths passed to Match should use forward slashes. Directory paths must have a trailing slash (e.g. "vendor/") so that directory-only patterns (those written with a trailing slash in .gitignore) match correctly.

A Matcher is safe for concurrent use by multiple goroutines once construction is complete (after New, NewFromDirectory, or the last AddPatterns/AddFromFile call). Do not call AddPatterns or AddFromFile concurrently with Match.

func New

func New(root string, opts ...Option) *Matcher

New creates a Matcher that reads patterns from the user's global excludes file (core.excludesfile), the repository's .git/info/exclude, and the root .gitignore. Patterns are loaded in priority order: global excludes first (lowest priority), then .git/info/exclude, then .gitignore (highest priority). Last-match-wins semantics means later patterns override earlier ones.

The root parameter should be the repository working directory (containing .git/). If root is empty, no filesystem patterns are loaded and the returned Matcher is empty. Use AddPatterns or AddFromFile to add patterns programmatically.

Options such as MaxIgnoreFileSize apply to files loaded here and to later AddFromFile calls; oversized files are skipped and recorded in Errors with Line set to zero.

func NewFromDirectory added in v1.1.0

func NewFromDirectory(root string, opts ...Option) *Matcher

NewFromDirectory creates a Matcher by walking the directory tree rooted at root, loading every .gitignore file found along the way. Each nested .gitignore is scoped to its containing directory. The .git directory is skipped. Oversized files under MaxIgnoreFileSize are skipped and recorded in Errors.

func (*Matcher) AddFromFile

func (m *Matcher) AddFromFile(absPath, relDir string)

AddFromFile reads a .gitignore file at the given absolute path and scopes its patterns to the given relative directory. It uses the matcher's file-size limit, if set, and records oversized files in Errors without applying any rules.

func (*Matcher) AddPatterns

func (m *Matcher) AddPatterns(data []byte, dir string)

AddPatterns parses gitignore pattern lines from data and scopes them to the given relative directory. Pass an empty dir for root-level patterns.

func (*Matcher) Errors added in v1.1.0

func (m *Matcher) Errors() []PatternError

Errors returns pattern compilation errors and skipped oversized files. File-size errors have a source path and a zero line number.

func (*Matcher) Match

func (m *Matcher) Match(relPath string) bool

Match returns true if the given path should be ignored. The path should be slash-separated and relative to the repository root. For directories, append a trailing slash (e.g. "vendor/"). An ignored parent directory makes its descendants ignored. Otherwise, the last matching rule determines whether the path is ignored.

func (*Matcher) MatchDetail added in v1.1.0

func (m *Matcher) MatchDetail(relPath string) MatchResult

MatchDetail returns detailed information about which pattern matched the given path. If no pattern matches, Matched is false and Ignored is false. The path uses the same trailing-slash convention as Match.

func (*Matcher) MatchPath added in v1.1.0

func (m *Matcher) MatchPath(relPath string, isDir bool) bool

MatchPath returns true if the given path should be ignored. Unlike Match, it takes an explicit isDir flag instead of requiring a trailing slash convention. The path should be slash-separated, relative to the repository root, and should not have a trailing slash.

type Option added in v1.3.0

type Option func(*Matcher)

Option configures a Matcher at construction time.

func MaxIgnoreFileSize added in v1.3.0

func MaxIgnoreFileSize(n int64) Option

MaxIgnoreFileSize limits the bytes read from each ignore file. Nonpositive values are unlimited. AddPatterns is unaffected because its data is already in memory.

type PatternError added in v1.1.0

type PatternError struct {
	Pattern string // the original pattern text
	Source  string // file path, empty for programmatic patterns
	Line    int    // 1-based line number; zero for a file-size error
	Message string
}

PatternError records a pattern compilation error or a skipped oversized file.

func (PatternError) Error added in v1.1.0

func (e PatternError) Error() string

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL