What is the .gitignore file and how does it work?
Quick Answer
.gitignore is a text file that tells Git which files and directories to exclude from tracking. It uses glob patterns to match paths, and any matching file won't appear in git status or be staged by git add unless explicitly forced.
Detailed Answer
Think of .gitignore like a bouncer at a club with a guest list. The bouncer (Git) checks every file trying to enter the staging area against the .gitignore rules. If a file matches a pattern in .gitignore, it's turned away and Git pretends it doesn't exist. But if a file already got in before the bouncer started checking (was already tracked), the bouncer can't kick it out without explicit action.
.gitignore is a plain text file typically placed in the root of your repository, though you can have additional .gitignore files in subdirectories. Each line contains a pattern that Git uses to determine whether to ignore a file. Patterns use glob syntax: * matches any sequence of characters, ? matches a single character, ** matches nested directories, and a leading / anchors the pattern to the directory containing the .gitignore. Lines starting with # are comments, and a leading ! negates a pattern to un-ignore a previously ignored file.
Internally, Git processes .gitignore rules in a specific order of precedence. Patterns in the command line (via --exclude) have the highest priority, followed by patterns in .gitignore files in the same or parent directories (closer directories take precedence), then patterns in .git/info/exclude (local-only exclusions not shared with the team), and finally patterns in the file specified by core.excludesFile in git config (typically ~/.gitignore_global for user-wide rules like OS-specific files). When Git checks whether to ignore a file, it evaluates all applicable patterns and the last matching pattern wins.
In production projects, a well-crafted .gitignore is critical for security and repository health. Common entries include: build output directories (dist/, build/, target/), dependency directories (node_modules/, vendor/, .venv/), environment files (.env, .env.local) containing secrets, IDE configuration (.idea/, .vscode/settings.json), OS files (.DS_Store, Thumbs.db), and compiled artifacts (*.pyc, *.class, *.o). GitHub maintains an excellent collection of .gitignore templates at github.com/github/gitignore organized by language and framework.
A critical gotcha: .gitignore only affects untracked files. If a file was already committed to the repository and you later add it to .gitignore, Git will continue tracking it. To fix this, you must explicitly remove it from tracking with git rm --cached filename. This removes the file from the index but keeps it on disk. Another trap: adding node_modules/ to .gitignore after you've already committed it doesn't remove the 50,000 files from history. You'd need tools like git filter-branch or BFG Repo-Cleaner for that. Always set up .gitignore as the very first step in a new project.