Git & GitHub · lesson 6 of 12
Ignoring Files with .gitignore
Watch .gitignore actually hide matching files from git status, see it fail to hide a file already tracked, and debug pattern matches with git check-ignore.
By SkillByExample · Published
.gitignore only affects files Git hasn’t started tracking yet. This lesson shows both
halves of that rule: files it successfully hides, and one it doesn’t.
1) Ignored files vanish from status — before they’re tracked
$ printf 'node_modules/\n*.log\n.env\n' > .gitignore
$ mkdir node_modules && echo '{}' > node_modules/pkg.json
$ echo "run 1" > app.log
$ printf 'DEBUG=1\nSECRET=xyz\n' > .env
$ git status -s
?? .gitignore
Three new files exist — node_modules/pkg.json, app.log, .env — but only
.gitignore itself shows up as untracked. The other three match a pattern and are
invisible to status, add -A, and diff alike.
2) A pattern added after tracking starts does nothing
$ echo "CACHE=on" >> config.py
$ echo "config.py" >> .gitignore
$ git status -s
M config.py
?? .gitignore
config.py was already tracked from an earlier lesson. Adding it to .gitignore now
doesn’t retroactively hide it — Git still reports the modification, because ignore
rules only decide whether to start tracking a file, not whether to keep watching one
it already tracks.
3) Debug which rule matched, with check-ignore
$ git check-ignore -v .env app.log node_modules/pkg.json
.gitignore:3:.env .env
.gitignore:2:*.log app.log
.gitignore:1:node_modules/ node_modules/pkg.json
Each line shows <file>:<line-number>:<pattern> followed by the path it matched —
exactly which rule is responsible, useful when a file is unexpectedly missing (or
unexpectedly present) and the .gitignore has grown past a few lines.
4) Commit the .gitignore itself
$ git checkout -- config.py
$ git add .gitignore
$ git commit -m "Add .gitignore"
$ git log --oneline -1
39e53d1 Add .gitignore
config.py’s stray edit from step 2 is discarded (it was only there to demonstrate
the “already tracked” case) — only .gitignore itself, now four lines, is committed.
.env, app.log, and node_modules/ stay untracked exactly as designed.
Practice
-
Run
git status -s --ignoredto list ignored files explicitly, instead of the default behavior of hiding them completely.Solution
!! .env !! app.log !! node_modules/!!marks an ignored path — a different marker from??(untracked) orM(modified). -
Untrack
config.pyproperly withgit rm --cached config.py, commit that, then confirmgit statusgoes quiet on further edits to it. -
Add a negation pattern (
!important.log) after a broader*.logrule in.gitignore, createimportant.log, and confirmgit statusshows it despite the earlier blanket rule. -
Create a nested
node_modules/inside a subdirectory and confirm the same top-levelnode_modules/pattern still matches it —.gitignorepatterns apply recursively from the directory they’re in unless anchored with a leading/. -
Add a leading slash (
/config.py) to anchor a pattern to the repo root, then create a same-named file in a subdirectory and confirm the anchored pattern does not match it there.