.gitignore

Course 1 · Ch 6
.gitignore — What Never to Commit
Secrets, build artifacts, and OS junk files — and how to stop them from ever being tracked in the first place

Not every file in a project folder belongs in git history. Some are generated automatically and can be recreated anytime; some are specific to your own machine; some are actively dangerous to publish. A .gitignore file tells git which files and folders to never even consider — they won't show up in git status, won't get staged by git add ., and won't accidentally end up in a commit.

What Should Never Be Tracked

🔐 Secrets & credentials
API keys, passwords, database connection strings, .env files. The single most important category — covered in detail below.
📦 Dependencies
node_modules/, Python's venv/, vendor folders. Huge, regenerable from a lockfile (package-lock.json, requirements.txt) — tracking them bloats the repo for no benefit.
🏗️ Build output
dist/, build/, compiled .class or .pyc files. Generated from source you already have tracked — committing the output as well just creates redundant, conflict-prone noise.
🖥️ OS & editor files
.DS_Store (macOS), Thumbs.db (Windows), .vscode/ or .idea/ personal editor settings. Specific to your machine, meaningless to anyone else cloning the repo.
📝 Logs & temp files
*.log, *.tmp, cache directories. Generated during normal operation, churn constantly, and add no value to history.
💾 Large binary/media files
Large video files, database dumps, disk images. Git handles these poorly by default — bloats repo size dramatically (Course 3, Chapter 7 covers Git LFS for cases where you genuinely need to track large files).

Creating a .gitignore File

A .gitignore file is plain text, placed at the root of your repository, with one pattern per line. Git reads it automatically — no command needed to "enable" it.

# .gitignore — one pattern per line
node_modules/
.env
dist/
*.log
.DS_Store

Pattern syntax

PatternMatches
node_modules/The folder named node_modules, anywhere in the project (trailing slash = directory only)
*.logAny file ending in .log, anywhere in the project
.envA file named exactly .env in the root (and in any subfolder, since no leading slash)
/buildA folder named build, but only at the project root — leading slash anchors it
temp/*Everything directly inside temp/, but not the temp/ folder itself
!important.logAn exception — un-ignores a file that an earlier pattern would otherwise have matched
Use gitignore.io or GitHub's templates instead of writing from scratch
gitignore.io generates a ready-made .gitignore for your exact stack (Node, Python, Java, VS Code, macOS, etc.) — paste in your tools and it builds the file for you. GitHub also offers starter templates when creating a new repository. Hand-writing one from memory is rarely necessary.

The .env File — Special Attention Required

Almost every modern project stores secrets (database passwords, API keys) in a .env file that gets loaded into environment variables at runtime. This file should always be in .gitignore — but the project still needs to communicate what variables are expected. The standard pattern:

.env.example ← tracked: shows variable names, no real values
.env ← ignored: contains your actual secrets
# .env.example — committed to the repo, safe to share
DATABASE_URL=postgres://user:password@localhost/dbname
API_KEY=your-api-key-here

# .env — never committed, real secrets, listed in .gitignore
DATABASE_URL=postgres://admin:Tr0ub4dor&3@prod-db.example.com/myapp
API_KEY=sk-live-a1b2c3d4e5f6g7h8i9j0

Anyone cloning the repo copies .env.example to .env and fills in their own real values — the structure is shared, the secrets never are.

.gitignore Only Works on Untracked Files

This catches almost everyone out at least once: adding a pattern to .gitignore does nothing for a file git is already tracking. If a file was committed before it was added to .gitignore, git keeps tracking it regardless.

$ # If config.json was already committed before being added to .gitignore:
$ git rm --cached config.json
rm 'config.json'
# Now it's untracked — .gitignore will take effect from here on
$ git commit -m "Stop tracking config.json"

git rm --cached removes the file from git's tracking without deleting it from your disk — exactly what you want when un-tracking a file you still need locally.

A secret committed in the past stays in history forever
git rm --cached stops tracking a file going forward, but every previous commit that included it still has it, fully recoverable by anyone with access to the repository's history — including a public repo that was briefly public, even if made private again later. If a real secret was ever committed, the correct response is to treat it as compromised: rotate/revoke the credential immediately. Rewriting history to remove it (covered in Course 3, Chapter 2) is good hygiene but does not undo the exposure on its own — assume it's been seen.

Command Reference

CommandWhat it does
.gitignoreA file listing patterns git should never track, untracked files only
git rm --cached <file>Stop tracking a file without deleting it from disk
git check-ignore -v <file>Debug which .gitignore rule is (or isn't) matching a specific file

Chapter 6 Quick Reference

  • Never track: secrets/.env, dependencies (node_modules), build output, OS/editor junk, logs, large binaries
  • .gitignore — plain text, one pattern per line, at the repo root, no command needed to enable it
  • Generate, don't hand-write — use gitignore.io or GitHub's templates for your stack
  • .env pattern: commit .env.example (no real values), ignore .env (real secrets)
  • .gitignore only affects untracked files — use git rm --cached to stop tracking something already committed
  • A committed secret is compromised the moment it's pushed — rotate the credential; don't rely on deleting it later to undo the exposure
  • Next chapter: pull requests 101 — making your first PR, getting reviewed, and merging on GitHub itself