.gitignore rule tester
Developer tools
Loading
Loading tool
The tool is loaded only when you open it.
All processing for this tool happens in your browser. Your input is not sent to a server.
About this tool
Paste one root .gitignore and a newline-separated list of sample paths to inspect the effect of your rules without opening a repository. The result distinguishes ignored paths, explicit exceptions, paths with no matching rule and invalid path input. Rule-line evidence helps explain the decision, including exclusions inherited from a parent directory. Matching runs locally with pinned ignore 7.0.12, case sensitivity enabled and UTF-8 byte matching. The tool neither reads your filesystem nor runs Git.
Common uses
- Check whether generated files, logs and temporary directories are excluded while intended exception files remain visible.
- Explain why a ! exception fails beneath an ignored parent before editing a shared root .gitignore.
- Compare a small set of representative paths before and after a rule change and save a plain-text review report.
How to use it
- 1.Paste the root .gitignore rules and one root-relative sample path per line, or load the example. Use / separators. End a sample directory with /; otherwise the sample is a file. Keep meaningful spaces and do not add quotes.
- 2.Run the test and inspect each state and its rule-line evidence. ignored means excluded; unignored means an explicit ! exception applies; unmatched means no effective pattern matched; invalid means the path failed input checks. An excluded parent can determine a child’s result. Use the state filter to focus the review; results display 25 paths per page.
- 3.Review the privacy warning before copying or downloading the text report: it contains raw paths and patterns. Edit either input and test again to replace the result; the previous report is cleared when inputs or the interface language change.
Executable rule and path examples
Ordered exclusions and explicit exceptions
{
"rules": "*.log\n!important.log\nprivate/*.log",
"paths": "debug.log\nimportant.log\nprivate/important.log\nREADME.md"
}{
"statuses": [
"ignored",
"unignored",
"ignored",
"unmatched"
]
}The output lists states in the same order as the sample paths. important.log is an explicit exception, but the later private/*.log excludes private/important.log again. README.md has no matching rule. The JSON input documents the two text fields; paste each string’s decoded value into its field.
An excluded parent blocks a child exception
{
"rules": "build/\n!build/keep.txt",
"paths": "build/\nbuild/keep.txt\nbuild/output.js\nsrc/main.js"
}{
"statuses": [
"ignored",
"ignored",
"ignored",
"unmatched"
]
}build/ excludes the parent and its descendants. The later child exception cannot reopen the parent, so build/keep.txt stays ignored. src/main.js is unmatched. Parent rule evidence explains this result without claiming to inspect any real files.
Root anchoring and case sensitivity
{
"rules": "/cache/\n*.tmp",
"paths": "cache/\ncache/data.json\napp/cache/data.json\napp/draft.tmp\nDRAFT.TMP"
}{
"statuses": [
"ignored",
"ignored",
"unmatched",
"ignored",
"unmatched"
]
}/cache/ applies to the root cache directory, not app/cache. The *.tmp rule applies below the root too, but DRAFT.TMP does not match the lowercase extension because matching is case-sensitive.
Zero or more directories with **
{
"rules": "docs/**/draft?.md",
"paths": "docs/draft1.md\ndocs/a/b/draft2.md\ndocs/draft10.md\nother/docs/draft1.md"
}{
"statuses": [
"ignored",
"ignored",
"unmatched",
"unmatched"
]
}The standalone ** segment admits zero or multiple intermediate directories. ? accepts exactly one byte here, so draft10.md fails the filename shape. The slash inside the rule keeps this pattern relative to the root docs directory.
Literal markers and preserved trailing spaces
{
"rules": "# comment\n\\#draft\n\\!todo\nnote\\ ",
"paths": "#draft\n!todo\nnote \nnote\n note"
}{
"statuses": [
"ignored",
"ignored",
"ignored",
"unmatched",
"unmatched"
]
}The first line is a comment; escaped # and ! match literal filename characters. note\ followed by a space matches note with one final space. Neither note without that space nor note with a leading space matches. JSON makes the significant spaces and backslashes reviewable.
A directory query is not a file query
{
"rules": "a/*",
"paths": "a/\na\na/file.txt"
}{
"statuses": [
"ignored",
"unmatched",
"ignored"
]
}The trailing slash declares a directory query. The explicit a/ query can match a/* with an empty final basename, as git check-ignore does; the file sample a remains unmatched. Do not read this result as a directory-traversal simulation.
Wildcards count UTF-8 bytes
{
"rules": "x?y\nx??y",
"paths": "xay\nxéy\nx😀y"
}{
"statuses": [
"ignored",
"ignored",
"unmatched"
]
}xay matches x?y. UTF-8 encodes é as two bytes, so xéy matches x??y. The emoji needs four bytes and matches neither pattern. The length caps use UTF-16 code units separately from this byte-based matching behavior.
Reject ambiguous or non-relative paths
{
"rules": "*.tmp",
"paths": "/tmp/cache.tmp\nC:/cache.tmp\nsrc\\cache.tmp\n./cache.tmp\n../cache.tmp\nsrc//cache.tmp\nsrc/../cache.tmp\nsrc/cache.tmp"
}{
"statuses": [
"invalid",
"invalid",
"invalid",
"invalid",
"invalid",
"invalid",
"invalid",
"ignored"
]
}Absolute, drive-prefixed, backslash-separated, dot-segment and double-separator paths are invalid rather than silently normalized. The final root-relative POSIX path is valid and matches *.tmp. Invalid rows remain distinct from valid paths that simply have no match.
Common ignore-testing mistakes
- Using shell globs, a regular expression or Windows backslashes as if they were .gitignore path syntax.
- Expecting !child/path to reopen an excluded parent directory, or reading unmatched as an explicit exception.
- Trimming sample paths, quoting them, or forgetting the trailing / when the sample is a directory.
- Assuming ? counts visible Unicode characters, or using *** and embedded ** where a standalone ** path segment is required.
- Treating an ignored result as proof that a tracked file or secret has been removed, or sharing an unredacted report without review.
Limits and notes
- Only the pasted root .gitignore is evaluated. Nested .gitignore files, .git/info/exclude, global excludes, repository configuration and tracked-file state are not read. An ignored result cannot remove an already tracked file or prove that a secret is absent from Git history. Symlink samples are treated as files; links are not followed and no directory traversal occurs.
- Input uses case-sensitive POSIX-style / paths. Absolute paths, drive prefixes, backslashes, . or .. segments, empty internal segments, NUL, ASCII control characters and malformed Unicode are rejected. Leading and trailing spaces in sample paths are preserved exactly; empty lines are skipped. LF and CRLF are accepted. Rules support comments, escaped leading # or !, negation, *, ?, character classes and standalone ** path segments. Ambiguous runs such as *** or non-segment ** are rejected rather than guessed; ASCII control characters and malformed Unicode are rejected in rules too.
- Rules are limited to 32 KiB of UTF-8 text, 200 physical lines and 256 UTF-16 code units per line. Sample paths are limited to 32 KiB total, 100 physical lines and 512 UTF-16 code units per path. Blank lines and rule comments count toward line caps; a final newline does not add a line. Overall limits or unsupported rules stop the test; individual invalid paths remain visible as invalid rows. Matching is capped at 2,000,000 work steps. Complex rule/path combinations may reach this cap before the input-size limits; reduce the input and retry. No partial results are kept.
- Matching uses UTF-8 bytes, not displayed character count: é takes two ? wildcards and many emoji take four. A trailing / requests directory-query semantics like git check-ignore path/, not a full traversal: a/* may match a/ itself, whereas a/*/ and a/**/ require a descendant directory. A later child negation cannot override an excluded parent; reopen the parent first.
- Processing stays in the loaded browser page; no repository, filesystem or network request is used to evaluate input. Reports are plain text and include raw paths and patterns without secret redaction, including invalid path text. Every row is exported regardless of the current filter or page; quoted strings preserve spaces and escape line breaks. Review project names, private filenames and credentials before copying, downloading or sharing. A saved or copied report is outside the page’s control.
Frequently asked questions
Why does !build/keep.txt fail after build/?
The parent build directory is excluded, so a rule for a child cannot make that child reachable again. To keep selected descendants, leave the relevant parents available and test rules such as build/* followed by !build/keep.txt against your actual sample paths. A later negation is not an unconditional override of parent exclusion.
How do /cache, cache/ and a plain cache pattern differ?
A leading / anchors the pattern to the root represented by this input. A trailing / restricts a rule to directories; the sample also needs a trailing / to identify a directory. A plain name can affect files or directories below the root. Explicit directory queries have the special trailing-slash behavior described in the limits, so test both the directory and its intended child paths.
Why are spaces or a leading # or ! changing my result?
A rule beginning with # is a comment and one beginning with ! is an exception. Escape the first character with a backslash to match it literally. Unescaped trailing spaces in rules are ignored, while escaped trailing spaces are meaningful. Sample paths are not trimmed: note, note with a final space and note with an initial space are different inputs.
Does ignored mean Git will stop tracking or protect the file?
No. This page evaluates text rules against hypothetical paths. It never checks the Git index, removes tracked files, redacts exports or audits history. Use your repository’s own status and ignore diagnostics when validating a change; an ignore pattern is not a secret-management control.
- Git documentation: .gitignore pattern rules
- Git documentation: git check-ignore diagnostics
- node-ignore: matching engine and documented behavior