Skip to content
Syntax & Mechanics6 min readVerified Git 2.40+

.gitignore Syntax & Pattern Matching Guide

Git pattern matching is based on Unix globbing with specialized rules for directories, recursive filepaths, and negation. Understanding these rules ensures your project excludes unintended files without inadvertently ignoring essential source code.

1. Basic Formatting: Comments & Blank Lines

Every line in a .gitignore file represents an independent pattern, with two core exceptions:

  • Blank lines are ignored and serve as visual separators to keep files readable.
  • Lines beginning with # are comments and have no effect on file tracking.
  • Trailing spaces are ignored unless escaped with a backslash (\ ).
# Ignore Python compiled bytecode
__pycache__/
*.py[cod]

# Ignore local secret configurations
.env
.env.local

2. Wildcard Globbing (*, ?, [ ])

Git supports standard shell globbing wildcards within a single directory level:

* (Asterisk)

Matches zero or more characters in a single path segment. *.log matches error.log, but not nested/error.log if anchored.

? (Question Mark)

Matches exactly one single character. test?.js matches test1.js and testA.js, but not test12.js.

[abc] (Range)

Matches any single character within the bracket set. *.[oa] matches object files ending in .o or archive files in .a.

3. Leading, Trailing, and Middle Slashes

The placement of forward slashes (/) completely alters how Git interprets patterns:

Trailing Slash: logs/

Forces the pattern to match only directories. It will ignore a directory named logs/, but will not ignore a regular file named logs.

Leading Slash: /config.json

Anchors the match to the root level where .gitignore resides. It ignores /config.json, but allows /packages/app/config.json to remain tracked.

Middle Slash: docs/*.html

A slash anywhere in the middle also anchors relative to the directory containing the .gitignore file.

4. Recursive Double Asterisk (**)

The double asterisk matches across multiple directory hierarchies:

  • **/cache: Matches any folder or file named cache anywhere in the repository (cache, src/cache, a/b/c/cache).
  • logs/**: Matches all files and subdirectories inside the logs/ directory, no matter how deeply nested.
  • a/**/b: Matches a/b, a/x/b, a/x/y/b, etc.

5. Negation (!) and the Critical Directory Trap

An exclamation mark (!) negates a rule, telling Git to track a file even if an earlier pattern would have ignored it.

The Git Directory Trap (Why !file.txt Fails)

For performance reasons, Git stops traversing directories as soon as a directory is ignored. If a parent directory is excluded with build/, Git will never re-include a file inside it using !build/important.txt!

To properly un-ignore a file inside an ignored folder, you must un-ignore the folder structure while ignoring contents:

# INCORRECT: Will NOT work because parent directory is skipped
node_modules/
!node_modules/my-local-package

# CORRECT: Ignore contents of directory, then whitelist the specific target
node_modules/*
!node_modules/my-local-package/

Generate a Conflict-Free .gitignore

Don't wrestle with manual globbing conflicts. DotGitIgnore combines verified templates for your languages, frameworks, and developer tools deterministically.

Open Interactive Generator