fix(core): Preserve escaped characters in gitignore patterns (#11171)

Co-authored-by: Jacob Richman <jacob314@gmail.com>
This commit is contained in:
Eric Rahm
2025-10-20 10:03:22 -07:00
committed by GitHub
parent d52ec522f1
commit 518a9ca314
2 changed files with 23 additions and 6 deletions
@@ -234,4 +234,20 @@ src/*.tmp
); );
}); });
}); });
describe('Escaped Characters', () => {
beforeEach(async () => {
await setupGitRepo();
});
it('should correctly handle escaped characters in .gitignore', async () => {
await createTestFile('.gitignore', '\\#foo\n\\!bar');
// Create files with special characters in names
await createTestFile('bla/#foo', 'content');
await createTestFile('bla/!bar', 'content');
// These should be ignored based on the escaped patterns
expect(parser.isIgnored('bla/#foo')).toBe(true);
expect(parser.isIgnored('bla/!bar')).toBe(true);
});
});
}); });
+7 -6
View File
@@ -35,7 +35,10 @@ export class GitIgnoreParser implements GitIgnoreFilter {
const relativeBaseDir = isExcludeFile const relativeBaseDir = isExcludeFile
? '.' ? '.'
: path.dirname(path.relative(this.projectRoot, patternsFilePath)); : path
.dirname(path.relative(this.projectRoot, patternsFilePath))
.split(path.sep)
.join(path.posix.sep);
return content return content
.split('\n') .split('\n')
@@ -68,11 +71,11 @@ export class GitIgnoreParser implements GitIgnoreFilter {
if (!isAnchoredInFile && !p.includes('/')) { if (!isAnchoredInFile && !p.includes('/')) {
// If no slash and not anchored in file, it matches files in any // If no slash and not anchored in file, it matches files in any
// subdirectory. // subdirectory.
newPattern = path.join('**', p); newPattern = path.posix.join('**', p);
} }
// Prepend the .gitignore file's directory. // Prepend the .gitignore file's directory.
newPattern = path.join(relativeBaseDir, newPattern); newPattern = path.posix.join(relativeBaseDir, newPattern);
// Anchor the pattern to a nested gitignore directory. // Anchor the pattern to a nested gitignore directory.
if (!newPattern.startsWith('/')) { if (!newPattern.startsWith('/')) {
@@ -89,9 +92,6 @@ export class GitIgnoreParser implements GitIgnoreFilter {
newPattern = '!' + newPattern; newPattern = '!' + newPattern;
} }
// Even in windows, Ignore expects forward slashes.
newPattern = newPattern.replace(/\\/g, '/');
return newPattern; return newPattern;
}) })
.filter((p) => p !== ''); .filter((p) => p !== '');
@@ -173,6 +173,7 @@ export class GitIgnoreParser implements GitIgnoreFilter {
const gitignorePath = path.join(dir, '.gitignore'); const gitignorePath = path.join(dir, '.gitignore');
if (fs.existsSync(gitignorePath)) { if (fs.existsSync(gitignorePath)) {
const patterns = this.loadPatternsForFile(gitignorePath); const patterns = this.loadPatternsForFile(gitignorePath);
this.cache.set(dir, patterns); this.cache.set(dir, patterns);
ig.add(patterns); ig.add(patterns);
} else { } else {