Repository navigation
Handle backslash escapes in gitignore bracket expressions - #157
Merged
Merged
Conversation
Owner
|
Thanks for finding and fixing this! |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
A backslash inside a gitignore bracket expression escapes the next character in git, the same as it does outside one. pathspec treats it as a literal backslash instead, so several valid patterns match the wrong files:
[a\-c]a,-,ca,b,c,\,],^(read as the range\-c)[\]]]\][\]a]],a[!\]]]]][\n]nn,\The git column comes from
git ls-files -o -i --exclude-standardin a scratch repo withcore.ignorecase=false(git 2.50.1).ignoreon npm agrees with git on all of these.Cause
_translate_segment_glob()had two problems with escapes inside[...]:]didn't skip escaped characters, so[\]]ended at the escaped].pattern[i:j].replace('\\', '\\\\'), which turned every backslash into a literal backslash member of the set.Fix
\and the character after it.re.escape(char). The existing_translate_posix_class()still handles classes. Because escapes are consumed in the same pass,[\[:alpha:]]is the literal set[,:,a,l,p,hfollowed by], which is what git does too.This lives in the shared base translator, so it applies to both
GitIgnoreSpecPatternandGitIgnoreBasicPattern.Tests
Added
test_13_bracket_escapetotests/test_04_gitignore_spec.pyandtest_14_bracket_escapetotests/test_03_gitignore_basic.py. Every expected result was checked against git first.Without the fix, 32 subtests fail. With it, both tests pass.
The full suite passes with
python -m unitteston Python 3.13 withhyperscanandgoogle-re2installed (243 tests, 1 skipped). I also ran[a\-c],[\]],[!\]],[\[:alpha:]],[\#x]and[\ a]throughGitIgnoreSpecandPathSpec('gitignore')on thesimple,re2andhyperscanbackends, and all three give git's answers.mypyandpyrightoutput is unchanged frommaster.Out of scope: reversed ranges such as
[z-a]or[a-\]]are still discarded the same way as onmaster. git matches the start character in that case, which is a separate difference.