Topic 1.4
.gitignore & Ignoring Files Properly
In one line
A .gitignore file tells Git which files to never track in the first place — genuinely essential for keeping build output, dependencies, and secrets out of a repository from day one.
Think of it like this
A 'do not pack' list taped to a moving box — items on the list never even get considered for packing, saving time and preventing genuinely useless (or sensitive) items from ending up somewhere they shouldn't. .gitignore is exactly this list, checked automatically every time you run git add or git status.
Key ideas
- 01
A
.gitignorefile, placed at the root of a repository (or in any subdirectory, for more localized rules), lists PATTERNS — file names, extensions, or folders — that Git should never track. A plainnode_modulesline ignores that folder anywhere it appears;*.logignores every file ending in.log, anywhere in the project. - 02
Files that are ALREADY tracked before being added to
.gitignoreare NOT automatically ignored —.gitignoreonly prevents NEW, previously-untracked files from being picked up. Removing an already-tracked file requiresgit rm --cached <file>(removes it from tracking without deleting it from disk) in addition to adding it to.gitignore. - 03
What genuinely belongs in
.gitignore, universally: dependency folders (node_modules/, virtualenv folders), build output (target/,dist/,build/), IDE-specific config (.idea/,.vscode/— though some teams deliberately commit shared VS Code settings), OS-generated files (.DS_Storeon Mac), and — critically — anything containing real secrets (.envfiles with actual credentials, Phase 5's Linux course covered this exact point). - 04
GitHub maintains a well-known collection of language/framework-specific
.gitignoretemplates (github.com/github/gitignore) — starting a new project by copying the right template for your stack (Java/Maven, Node, Python) is standard practice and covers the vast majority of genuinely universal exclusions for that ecosystem immediately. - 05
A GLOBAL
.gitignore(git config --global core.excludesfile ~/.gitignore_global) applies to EVERY repository on your machine — genuinely useful for personal, machine-specific junk (your editor's swap files, OS clutter) that has nothing to do with any specific project and shouldn't need to be re-declared in every single repo's own.gitignore.
In your stack
- →
A Java project's
.gitignoreshould always includetarget/(Maven) orbuild/(Gradle) — the compiled output — plus*.classfiles and.idea/(IntelliJ's project-specific config), none of which belong in version control since they're either regenerated from source or specific to one developer's local setup.
Code & diagrams
A realistic starting point — trim to what your actual stack needs.
# Dependencies (regenerable from a lock file)
node_modules/
venv/
.venv/
# Build output
target/
build/
dist/
# Compiled artifacts
*.class
__pycache__/
*.pyc
# Secrets — NEVER commit these
.env
.env.local
*.pem
# Editor / OS clutter
.idea/
.vscode/
.DS_StoreAdding .gitignore AFTER a file is already tracked needs one extra step.
cd ~/scratch/my-first-repo
# Create the ignore file
cat > .gitignore << 'EOF'
*.log
node_modules/
.env
EOF
git add .gitignore
git commit -m "Add .gitignore"
# New matching files are now genuinely invisible to git status
touch debug.log
git status
# debug.log does NOT appear — .gitignore is working
# But a file tracked BEFORE being ignored needs explicit untracking
echo "already tracked" > secrets.env
git add secrets.env
git commit -m "Oops, committed a file that should've been ignored"
echo "secrets.env" >> .gitignore
git status
# secrets.env is STILL tracked — .gitignore alone doesn't fix this
git rm --cached secrets.env
git commit -m "Stop tracking secrets.env"
git status
# NOW it's genuinely ignored going forwardExplain it without notes
You add a file to .gitignore, but git status still shows it as tracked and changed. Why didn't .gitignore work, and what's the fix?
Why should node_modules (or a language's equivalent dependency folder) almost always be gitignored rather than committed?
Practice
Create a .gitignore with a pattern like *.log, create a matching file, and confirm with git status that it never shows up as untracked.
Deliberately commit a file first, THEN add it to .gitignore, and walk through the full git rm --cached fix to actually stop tracking it.
Trade-offs
- ↔
A very broad
.gitignore(ignoring entire folders liberally) is simple and safe against accidentally committing junk, but an overly aggressive pattern can occasionally ignore a file you genuinely DID want tracked without realizing it —git status --ignored(which lists ignored files explicitly) andgit check-ignore -v <file>(which shows exactly which rule is ignoring a specific file) are the tools for catching this kind of mistake before it causes real confusion.
Done when you can
I can write a .gitignore covering dependencies, build output, and secrets for my stack.
I know .gitignore has no effect on files already tracked, and I know the git rm --cached fix.
I understand why dependency folders should almost never be committed to a repository.