Repository navigation
Replace the Rust gitignore handling with a clean-room implementation - #2705
Conversation
Read .gitignore-style files (comments, blank lines, escapes, trailing spaces, CRLF, a byte order mark, negation, folder-only and anchored patterns) and decide about paths as git does: a file in an ignored folder stays ignored, and otherwise the last matching pattern decides. Paths are matched by their raw bytes on Unix, ignoring ASCII case. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QjLhVH1NnUc7MzCSYLd8Yn Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QjLhVH1NnUc7MzCSYLd8Yn
Split glob matching into compile_glob, which parses a pattern once, and compiled_glob_matches, which matches a compiled pattern against a text. IgnoreFile now stores compiled patterns, dropping any that can never match. Matching stops as soon as no text position is reachable, and updates one position list in place instead of allocating one per token. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QjLhVH1NnUc7MzCSYLd8Yn Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QjLhVH1NnUc7MzCSYLd8Yn
Add glob-vectors.json, 756 cases recorded from git's own glob matcher covering each feature and the surprising corners (class detection, unknown classes, backwards ranges with case folding, ** around escaped slashes, [:space:], malformed brackets), and an integration test that checks glob_matches against them. glob_matches and GlobOptions become public so the test can reach them. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QjLhVH1NnUc7MzCSYLd8Yn Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QjLhVH1NnUc7MzCSYLd8Yn
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QjLhVH1NnUc7MzCSYLd8Yn
🦋 Changeset detectedLatest commit: b0439e4 The changes in this PR will be included in the next version bump. This PR includes changesets to release 0 packagesWhen changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
Bundle ReportBundle size has no change ✅ |
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## claude/jolly-galileo-72zesp-cleanroom-glob #2705 +/- ##
=============================================================================
Coverage 100.00% 100.00%
=============================================================================
Files 106 111 +5
Lines 3633 3830 +197
Branches 2840 3038 +198
=============================================================================
+ Hits 3633 3830 +197
Flags with carried forward coverage won't be shown. Click here to find out more.
Continue to review full report in Codecov by Harness.
🚀 New features to boost your workflow:
|
git drops only a carriage return directly before the line feed, so for a line like `a\r\0x` the pattern stays `a\r`. Drop the carriage return first and then cut at the NUL, and pin the order with tests. Also pin how a leading slash combines with `**`. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QjLhVH1NnUc7MzCSYLd8Yn Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QjLhVH1NnUc7MzCSYLd8Yn
Nothing outside the crate uses the glob matcher, so check the vectors from a unit test of compiled_glob_matches instead of an integration test, make GlobOptions crate-private again, and remove glob_matches, which only that integration test used. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QjLhVH1NnUc7MzCSYLd8Yn Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QjLhVH1NnUc7MzCSYLd8Yn
Collect the mismatching cases with a filter that runs on every case, rather than formatting them in a closure that only runs on a mismatch. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QjLhVH1NnUc7MzCSYLd8Yn Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QjLhVH1NnUc7MzCSYLd8Yn
gitignore_last_match finds the last name in a path once and passes it to gitignore_pattern_matches, instead of every unanchored pattern finding it again. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QjLhVH1NnUc7MzCSYLd8Yn Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QjLhVH1NnUc7MzCSYLd8Yn
Show each mismatching glob vector's expected result, share one vector table loader, wrap an over-long doc comment, and check in debug builds that gitignore_pattern_matches gets the path's real last name. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QjLhVH1NnUc7MzCSYLd8Yn Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QjLhVH1NnUc7MzCSYLd8Yn
Stacked on #2704. This finishes removing the Rust code that was ported from git.
read_gitignore_patterns.rs,parse_gitignore_pattern.rs,trim_gitignore_trailing_spaces.rs,gitignore_pattern_matches.rsand the matching logic inIgnoreFilewere line-for-line ports of functions from git'sdir.c, which is GPL v2.The same clean-room agent that wrote the glob matcher wrote the replacement behind
IgnoreFile's unchanged public API. It worked only from the documented gitignore behaviour, our own code and tests, and git 2.56 run as a black box.IgnoreFile:gitignore_parseandgitignore_parse_lineread the file. They handle comments, escapes, trailing spaces, CRLF, a BOM, NUL bytes, negation, and folder-only and anchored patterns.gitignore_decide_pathdecides as git does: a file inside an ignored folder stays ignored, and otherwise the last matching pattern decides.Speed: each pattern is compiled once with
compile_globand stored. Matching then:These address the review of Replace the Rust glob matcher with a clean-room implementation #2704.
glob_matchesis gone, since nothing outside the tests called it.Pinned to git:
__conformance__/glob-vectors.jsonholds 756 cases with git's answers. A test inside the crate checks the compiled matcher against every case. Nothing new is public.Part of #2615.
Test plan
IgnoreFileAPI, with files on disk, and 500,000 glob cases. Every one agreed.ignore-vectors.jsonand theIgnoreFileandis_allowed_by_ignore_filestests still pass.🤖 Generated with Claude Code
https://claude.ai/code/session_01QjLhVH1NnUc7MzCSYLd8Yn