Skip to content

Releases: linkwithjoydeep/go-dotignore

v2.3.0

Choose a tag to compare

@linkwithjoydeep linkwithjoydeep released this 30 Aug 17:40
v2.3.0
829f6dd

v2.3.0 - 2026-08-30

Added

  • Feature: RepositoryMatcher.Walk(fn WalkFunc) error, an ignore-aware directory traversal.
    • Mirrors filepath.WalkDir's callback shape (fs.SkipDir/fs.SkipAll control flow, filesystem errors delivered via the err parameter).
    • Adds an ignored bool reporting whether each entry is excluded by .gitignore rules or RepositoryConfig.SkipFolders.
    • A directory excluded either way is reported once with ignored=true and never descended into.
    • Honors the same MaxDepth and FollowSymlinks settings the RepositoryMatcher was constructed with.

Performance

  • Removed all hot-path allocations from PatternMatcher matching: 34184 ns/op, 3762 B/op, 148 allocs/op → 25317 ns/op, 0 B/op, 0 allocs/op.
  • Removed hot-path allocations from RepositoryMatcher.Matches: 48 allocs/op, 3065 B/op → 21 allocs/op, 2044 B/op.

Changed

  • Corrected doc.go's Performance section, which claimed "no allocations during regex matching" before that was actually true.

Source

  • Commits: 618c474..7493de0

v2.2.0

Choose a tag to compare

@linkwithjoydeep linkwithjoydeep released this 03 May 11:45
d9b4c21

v2.2.0 - 2026-05-03

Added

  • Feature (#6): RepositoryConfig.SkipFolders to skip selected directories while discovering nested ignore files.
  • Internal Contains() helper used by repository traversal skip checks.
  • Godoc coverage for Contains().

Changed

  • Dropped slices dependency usage for skip-folder checks in repository scanning path.

Credits

Source

  • Commit: fe7feef51cd11cd936088946265aeee8d7230c49
  • Title: feat(repository-matcher): Add skipfolders, to skip scanning these folders (#6)

v2.1.0 - Hierarchical .gitignore Support

Choose a tag to compare

@linkwithjoydeep linkwithjoydeep released this 09 Feb 18:17
437bed2

Release v2.1.0 - Hierarchical .gitignore Support

Release Date: 2026-02-09

🎉 What's New

Nested .gitignore Support (Issue #4)

The most requested feature is finally here! go-dotignore now supports hierarchical .gitignore matching for real-world repositories with nested .gitignore files - just like Git does!

The Problem

Previously, go-dotignore (like go-gitignore) could only process a single .gitignore file. This made it impractical for real-world repositories, especially monorepos, where different subdirectories have their own .gitignore files.

The Solution

New RepositoryMatcher API that:

  • ✅ Automatically discovers all .gitignore files in your repository
  • ✅ Applies patterns hierarchically (parent → child)
  • ✅ Supports pattern overrides via negation
  • ✅ Mirrors Git's exact behavior

Quick Example

// Before: Only single file support
matcher, err := dotignore.NewPatternMatcherFromFile(".gitignore")

// After: Full repository support with nested .gitignore files
matcher, err := dotignore.NewRepositoryMatcher("/path/to/repo")

// Automatically handles:
// - .gitignore (root)
// - frontend/.gitignore
// - backend/.gitignore
// - docs/.gitignore
// And applies them correctly, just like Git!

ignored, err := matcher.Matches("frontend/node_modules/package.json")

📦 New API

RepositoryMatcher

type RepositoryMatcher struct { ... }

// Create a new repository matcher
func NewRepositoryMatcher(rootDir string) (*RepositoryMatcher, error)

// Create with custom configuration
func NewRepositoryMatcherWithConfig(rootDir string, config *RepositoryConfig) (*RepositoryMatcher, error)

// Check if a file should be ignored
func (rm *RepositoryMatcher) Matches(path string) (bool, error)

// Helper methods
func (rm *RepositoryMatcher) RootDir() string
func (rm *RepositoryMatcher) IgnoreFileCount() int
func (rm *RepositoryMatcher) IgnoreFilePaths() []string

RepositoryConfig

type RepositoryConfig struct {
    IgnoreFileName string  // Default: ".gitignore"
    MaxDepth       int     // Default: 0 (unlimited)
    FollowSymlinks bool    // Default: false
}

🏗️ Use Cases

Perfect for:

  • Monorepo projects with multiple subprojects
  • Build tools that need to respect .gitignore rules
  • File walkers and code analyzers
  • Git-aware tools and utilities
  • Migration from go-gitignore (drop-in replacement + more features)

📊 Real-World Example: Monorepo

// Repository structure:
// project/
//   .gitignore              # Global: *.log, .env, .DS_Store
//   frontend/
//     .gitignore            # Frontend: node_modules/, dist/, .cache/
//     node_modules/         # ← Ignored by frontend/.gitignore
//     src/                  # ← Not ignored
//   backend/
//     .gitignore            # Backend: target/, *.class, logs/
//     target/               # ← Ignored by backend/.gitignore
//     src/                  # ← Not ignored
//   docs/
//     .gitignore            # Docs: _build/, *.pyc
//     _build/               # ← Ignored by docs/.gitignore

matcher, err := dotignore.NewRepositoryMatcher("/path/to/project")

// Global patterns apply everywhere
matcher.Matches("app.log")                    // true (root .gitignore)
matcher.Matches("frontend/debug.log")         // true (root .gitignore)
matcher.Matches(".DS_Store")                  // true (root .gitignore)

// Subproject-specific patterns
matcher.Matches("frontend/node_modules/...")  // true (frontend/.gitignore)
matcher.Matches("backend/target/...")         // true (backend/.gitignore)
matcher.Matches("docs/_build/...")            // true (docs/.gitignore)

// Source files are NOT ignored
matcher.Matches("frontend/src/App.js")        // false
matcher.Matches("backend/src/Main.java")      // false
matcher.Matches("docs/index.rst")             // false

🔄 Pattern Override Example

Child .gitignore files can override parent patterns:

// project/
//   .gitignore              # *.txt (ignore all .txt files)
//   important/
//     .gitignore            # !critical.txt (but keep this one)

matcher.Matches("file.txt")                   // true (ignored by root)
matcher.Matches("important/file.txt")         // true (still ignored)
matcher.Matches("important/critical.txt")     // false (un-ignored by child!)

⚙️ Configuration

config := &dotignore.RepositoryConfig{
    IgnoreFileName: ".ignore",     // Use custom ignore file names
    MaxDepth:       5,              // Only search 5 levels deep
    FollowSymlinks: false,          // Don't follow symbolic links
}

matcher, err := dotignore.NewRepositoryMatcherWithConfig("/path/to/repo", config)
fmt.Printf("Found %d ignore files\n", matcher.IgnoreFileCount())

// Get list of all loaded ignore files
for _, path := range matcher.IgnoreFilePaths() {
    fmt.Printf("Loaded: %s\n", path)
}

📈 Comparison with Other Libraries

vs. go-gitignore

Feature go-dotignore v2.1+ go-gitignore
Nested .gitignore support ✅ Yes ❌ No
Root-relative patterns ✅ Fully compliant ⚠️ Issues
Negation patterns ✅ Full support ⚠️ Limited
Escaped negation ✅ Yes ❌ No
Active maintenance ✅ Yes ⚠️ Unmaintained
Full gitignore spec ✅ v2.0+ compliant ⚠️ Partial

go-dotignore is now a complete, drop-in replacement for go-gitignore with significantly more features!

🧪 Testing

Comprehensive test suite with 15+ new test cases:

  • ✅ Simple hierarchy matching
  • ✅ Pattern negation across levels
  • ✅ Monorepo scenarios (frontend/backend/docs)
  • ✅ Pattern override with negation
  • ✅ Root-relative patterns in nested files
  • ✅ Absolute path handling
  • ✅ Configuration options (MaxDepth, custom file names)
  • ✅ Edge cases and error handling

All tests passing!

📚 Documentation

  • ✅ Updated README with nested .gitignore section
  • ✅ Comparison table with go-gitignore
  • ✅ Migration guide from go-gitignore
  • ✅ Example code and usage patterns
  • ✅ Detailed API documentation

🚀 Installation

go get github.com/codeglyph/go-dotignore/v2@v2.1.0

Or update your go.mod:

require github.com/codeglyph/go-dotignore/v2 v2.1.0

🔧 Migration from go-gitignore

// Old (go-gitignore) - single file only
gitignore, err := ignore.CompileIgnoreFile(".gitignore")
if gitignore.MatchesPath("file.txt") {
    // file is ignored
}

// New (go-dotignore) - single file
matcher, err := dotignore.NewPatternMatcherFromFile(".gitignore")
if ignored, _ := matcher.Matches("file.txt"); ignored {
    // file is ignored
}

// New (go-dotignore) - nested files (NEW!)
matcher, err := dotignore.NewRepositoryMatcher("/path/to/repo")
if ignored, _ := matcher.Matches("frontend/node_modules/pkg.json"); ignored {
    // file is ignored
}

⚡ Performance

  • No performance regression for single-file usage (PatternMatcher)
  • Efficient pattern caching per directory level
  • Lazy evaluation of patterns
  • Minimal memory overhead

🎯 What's Next?

This release completes the core feature set for hierarchical gitignore support. Future releases will focus on:

  • Performance optimizations
  • Additional pattern syntax features
  • Community-requested enhancements

📝 Full Changelog

See CHANGELOG.md for complete details.

🙏 Acknowledgments

Thanks to the community for requesting this feature and providing valuable feedback!

Special mention to the Reddit discussion that highlighted the need for nested .gitignore support in Go libraries.


Upgrading? This is a minor version bump with no breaking changes. Simply update your dependency and start using RepositoryMatcher for repositories with nested .gitignore files!

v2.0.1 - Correct Module Path for Go v2+

Choose a tag to compare

@linkwithjoydeep linkwithjoydeep released this 09 Feb 17:46
ef6715b

v2.0.1 - Correct Module Path for Go v2+

🎯 Important Update

This release corrects the module path to include the /v2 suffix as required by Go's semantic import versioning specification.

⚠️ IMPORTANT: v2.0.0 was released with incorrect module path. All users should use v2.0.1 or later.

📦 Installation

go get github.com/codeglyph/go-dotignore/v2@latest

📝 Import Statement

import "github.com/codeglyph/go-dotignore/v2"

✨ Features (from v2.0.0)

All v2.0.0 features and bug fixes are included:

  • ✅ Root-relative patterns work correctly (Issue #5)
  • ✅ Fixed substring matching bug
  • ✅ Added escaped negation support
  • ✅ Full gitignore specification compliance

🔄 Migration from v1.x

Update import path:

// Before:
import "github.com/codeglyph/go-dotignore"

// After:
import "github.com/codeglyph/go-dotignore/v2"

Update go.mod:

go get github.com/codeglyph/go-dotignore/v2@latest

📖 Documentation

🙏 Thank You

Thanks to all users for adopting this library! Your feedback has been invaluable.

v2.0.0 - Full gitignore Specification Support

Choose a tag to compare

@linkwithjoydeep linkwithjoydeep released this 09 Feb 17:22
70575a8

v2.0.0 - Full gitignore Specification Support

🎉 Major Update

This release fixes three critical bugs and adds full support for root-relative patterns, achieving complete gitignore specification compliance!


🐛 Critical Bug Fixes

1. Root-Relative Patterns Now Work! (Issue #5) ⭐

Finally! Patterns starting with / now correctly match only at the repository root.

// Pattern: /build/
matcher.Matches("build/")          // ✅ true (root level)
matcher.Matches("src/build/")      // ✅ false (not at root)

// Pattern: logs/ (no slash - matches anywhere)
matcher.Matches("logs/")           // ✅ true
matcher.Matches("src/logs/")       // ✅ true

Before: /build/ didn't match anything ❌
After: /build/ matches only root-level build/ ✅

2. Fixed Substring Matching Bug

Pattern src/test no longer incorrectly matches mysrc/test or src/test2.

3. Added Escaped Negation Support

Pattern \!important.txt now matches files literally named !important.txt.


✨ What's New

  • Root-relative patterns: /pattern matches only at root
  • Full gitignore spec compliance: All standard gitignore features now work
  • 14 new tests: Unicode, deep paths, wildcards, and edge cases
  • 61 total tests (was 47) - all passing ✅

📊 Testing Improvements

  • ✅ Unicode support: Japanese, Russian, Emoji filenames
  • ✅ Deep paths: 100+ directory levels tested
  • ✅ Long patterns: 1000+ characters tested
  • ✅ No race conditions detected
  • ✅ No performance regressions (~34µs per match)

🔄 Migration

Most users: No changes needed! The bugs are fixed and features now work correctly.

If you worked around Issue #5:

// BEFORE (workaround):
patterns := []string{
    "mydir/",
    "!example/mydir/",  // Had to manually exclude
}

// AFTER (proper solution):
patterns := []string{
    "/mydir/",  // Automatically matches only at root
}

📦 Installation

go get github.com/codeglyph/go-dotignore@v2.0.0

🎯 Why v2.0.0?

  • Major new feature: root-relative pattern support
  • Three critical bug fixes that change behavior
  • Full gitignore specification compliance
  • Users with workarounds may need minor updates

⚡ Performance

No regressions:

  • ~34µs per match operation
  • Thread-safe, production-ready
  • Same memory footprint

📋 Full Details

See RELEASE_NOTES_v2.0.0.md for complete changelog, migration guide, and test script.

Closes: #5

v1.1.1

Choose a tag to compare

@linkwithjoydeep linkwithjoydeep released this 03 Jun 17:46

Summary

Comprehensive overhaul of the go-dotignore library with significant bug fixes,
performance improvements, and enhanced cross-platform compatibility.

Key Changes

🐛 Bug Fixes

  • Fix inefficient pattern matching logic that was calling both filepath.Match and regex
  • Fix Windows path handling - backslashes now properly converted to forward slashes
  • Fix directory pattern matching (patterns ending with /)
  • Fix regex building for character classes and escaped characters
  • Fix parent directory matching logic that was overly complex and buggy
  • Fix UTF-8 BOM handling in file reading

⚡ Performance Improvements

  • Pre-compile regex patterns during initialization instead of repeated compilation
  • Optimize pattern matching from O(n*m) to O(n) complexity in many cases
  • Streamline matching logic with clear separation of concerns

🔧 Architecture Improvements

  • Restructure matching logic with focused, single-purpose functions
  • Add comprehensive input validation with descriptive error messages
  • Enhance error handling throughout with proper error wrapping
  • Improve path normalization for consistent cross-platform behavior

✅ Testing Enhancements

  • Expand test coverage from 11 to 25+ test functions
  • Add edge case testing (empty patterns, nil readers, malformed paths)
  • Add performance benchmarks
  • Add cross-platform path testing
  • Add comprehensive error condition testing
  • Fix all existing test issues and add new test scenarios

📚 Documentation

  • Improve README with better examples and comprehensive usage patterns
  • Add detailed godoc comments throughout
  • Add real-world usage examples in tests
  • Document performance characteristics and best practices

API Compatibility

  • ✅ Maintains full backward compatibility
  • ✅ No breaking changes to public API
  • ✅ Enhanced error messages provide better debugging information

Platform Support

  • ✅ Windows: Full support for backslash path separators
  • ✅ macOS/Linux: Consistent forward slash handling
  • ✅ Cross-platform: Automatic path normalization

Pattern Support Improvements

  • ✅ Enhanced wildcard support (*, ?, **)
  • ✅ Proper character class handling ([a-z])
  • ✅ Correct escaped character handling (\*, \?)
  • ✅ Robust directory pattern support (dir/)
  • ✅ Complex negation pattern handling (!pattern)

Breaking Changes

None - all changes are backward compatible.

Migration Guide

No migration required. Existing code will work unchanged with improved reliability.

Closes: #1
Closes: #2
Closes: #3

v1.0.2

Choose a tag to compare

@linkwithjoydeep linkwithjoydeep released this 19 Mar 05:27

Full Changelog: v1.0.1...v1.0.2

v1.0.1

Choose a tag to compare

@linkwithjoydeep linkwithjoydeep released this 19 Jan 12:10

Full Changelog: v1.0.0...v1.0.1

fix: negation patterns not working
doc: add examples and go docs

v1.0.0

Choose a tag to compare

@linkwithjoydeep linkwithjoydeep released this 19 Jan 07:45