Merge pull request #351 from jaens/fix-gitignore-parsing

Fix gitignore parsing for anchored patterns and escaped characters
This commit is contained in:
Michael Panchenko authored and GitHub committed 2025-07-25 12:54:28 +02:00
commit 3748c7e3fc
2 files changed
+39 -9

No files matched your search

+6 -8
View File
@@ -185,10 +185,6 @@ class GitignoreParser:
if not line or line.lstrip().startswith("#"):
continue
# Handle escaped characters at the beginning
if line.startswith(("\\#", "\\!")):
line = line[1:]
# Store whether this is a negation pattern
is_negation = line.startswith("!")
if is_negation:
@@ -200,11 +196,13 @@ class GitignoreParser:
if not line:
continue
# Determine if pattern is anchored to the gitignore directory
is_anchored = "/" in line[:-1] or line.startswith("/")
# Handle escaped characters at the beginning
if line.startswith(("\\#", "\\!")):
line = line[1:]
# Remove leading slash for processing
if line.startswith("/"):
# Determine if pattern is anchored to the gitignore directory and remove leading slash for processing
is_anchored = line.startswith("/")
if is_anchored:
line = line[1:]
# Adjust pattern based on gitignore file location
+33 -1
View File
@@ -369,7 +369,7 @@ debug.log
assert "*.log" in patterns
assert "!important.log" in patterns
assert "!/src/keep.log" in patterns
assert "!src/keep.log" in patterns
def test_comments_and_empty_lines(self):
"""Test that comments and empty lines are ignored."""
@@ -419,6 +419,38 @@ build/
assert "#not-a-comment.txt" in patterns
assert "!not-negation.txt" in patterns
def test_escaped_negation_patterns(self):
test_dir = self.repo_path / "test_escaped_negation"
test_dir.mkdir()
gitignore = test_dir / ".gitignore"
gitignore.write_text(
"""*.log
\\!not-negation.log
!actual-negation.log
"""
)
parser = GitignoreParser(str(test_dir))
specs = parser.get_ignore_specs()
assert len(specs) == 1
patterns = specs[0].patterns
# Key assertions: escaped exclamation becomes literal, real negation preserved
assert "!not-negation.log" in patterns # escaped -> literal
assert "!actual-negation.log" in patterns # real negation preserved
# Test the actual behavioral difference between escaped and real negation:
# *.log pattern should ignore test.log
assert parser.should_ignore("test.log")
# Escaped negation file should still be ignored by *.log pattern
assert parser.should_ignore("!not-negation.log")
# Actual negation should override the *.log pattern
assert not parser.should_ignore("actual-negation.log")
def test_glob_patterns(self):
"""Test various glob patterns work correctly."""
test_dir = self.repo_path / "test_glob"