Which files should Git leave alone?
Most project folders hold files that should never be in history. The bird club folder has three kinds. .env holds an API key for the sightings map. .DS_Store is a file macOS writes into every folder you open in Finder. drafts/ holds half-written walk notes that only one volunteer needs.
Other common examples: node_modules/ (packages you can reinstall from package.json), build output such as dist/, log files, editor settings like .vscode/, and anything with passwords, tokens or customer data.
A useful test for each file: could someone recreate it from the rest of the project, or is it private to you or your machine? If either answer is yes, ignore it.
ls
git statusHow does a .gitignore file work?
.gitignore is a plain text file in the top folder of the project, with one pattern per line. Git reads it whenever it looks for new files. A file that matches a pattern is left out of git status, skipped by git add . and git add -A, and refused by git add <name> unless you force it.
Write the file in the editor tab, or from the terminal with echo. Then run git status again: the matched files disappear from the untracked list. That is the quickest check that a pattern does what you meant.
Commit .gitignore like any other file. It belongs to the project, and everyone who clones the repository gets the same rules.
echo ".env" > .gitignore
echo ".DS_Store" >> .gitignore
echo "drafts/" >> .gitignore
cat .gitignore
git status

.gitignore is a pattern. Files that match drop out of git status and git add ., while everything else, including .gitignore itself, is committed as usual.What do the patterns mean?
Patterns are matched against paths relative to the folder that holds .gitignore. Spelling and case matter on Linux servers even when your Mac or Windows laptop treats Notes.txt and notes.txt as the same name.
.envmatches a file or folder named.envanywhere in the project.drafts/with a trailing slash matches only a folder named drafts, and everything inside it.*.logmatches any name ending in .log.*stands for any run of characters inside one folder name./notes.txtwith a leading slash matches only the notes.txt in the top folder, leaving a notes.txt in a subfolder alone.images/**/*.psdmatches .psd files at any depth underimages/.**crosses folder boundaries.!keep.logafter*.logun-ignores one file. Later lines win over earlier ones.- Lines starting with
#are comments. Blank lines are ignored.
Why doesn't ignoring a committed file work?
.gitignore only affects files Git is not already tracking. Once a file is in a commit, Git keeps watching it, whatever .gitignore says. This catches nearly everyone once: you add .env to .gitignore, run git status, and the edited .env still appears.
To stop tracking it, run git rm --cached .env. The --cached part means "remove it from the staging area only". The file stays on your disk. Commit that removal together with the .gitignore change, and from then on Git leaves the file alone.
The file is still inside every older commit. For a harmless file that is fine. For a real secret, assume it has leaked once it has been pushed: change the password or key at the service that issued it. The secrets lesson covers removing it from history.
How do you check whether a file is ignored?
The everyday check is git status: ignored files are missing from it. If you expected a file to vanish and it did not, either the pattern is wrong or the file is already tracked. git ls-files (real Git) lists tracked files, which settles the second question.
Real Git also has git check-ignore -v <path>, which prints the exact line in .gitignore that matched. It is the fastest way to debug a pattern. The practice terminal does not have it, so use git status and the Files view, where ignored files carry no mark.
Another check: git add <file> on an ignored file stops with "The following paths are ignored". That message is good news when the file is a secret.
echo ".env" > .gitignore
git add .env # fails on purpose
git statusWhen should you force-add an ignored file?
Rarely. git add -f <file> adds a file even though a pattern matches it. A typical honest case is an example config: you ignore *.env but want to commit example.env with placeholder values. A cleaner answer is a negation line, !example.env, so the exception is written down where everyone can see it.
If you find yourself forcing a real secret, stop. That is exactly what .gitignore is protecting you from.
Once a force-added file is tracked, Git watches its changes like any other file, regardless of the pattern.
Where else can ignore rules live?
A .gitignore can sit in any subfolder, and its patterns then apply relative to that folder. Most small sites need only the top-level one.
Rules that are about your machine rather than the project belong in a global ignore file, set up with git config --global core.excludesFile ~/.gitignore_global. .DS_Store and editor folders are good candidates. Then every repository on your laptop skips them, and the project's file stays focused on the project.
For a one-off private rule in a single repository, real Git reads .git/info/exclude, which is never committed. The practice terminal only reads the top-level .gitignore.
What do AI tools get wrong about .gitignore?
Assistants often generate long template files covering ten languages you do not use. That is harmless but noisy. A short file you understand is easier to keep right.
A more serious slip: the assistant adds .env to .gitignore after you already committed it and tells you the problem is solved. Check with git status and git log --stat whether the file is tracked, and use git rm --cached if it is.
Also watch for patterns that ignore too much, such as *.html added to hide one generated file. Run git status after every change to .gitignore and confirm the files you care about are still listed or committed.
Field notes
.gitignoreis a plain text file with one pattern per line.- A pattern ending in
/matches a folder and everything inside it. - Ignoring only affects files Git is not already tracking.
- Write
.gitignorebefore staging, so files like.envnever get committed.
Easy to get wrong
Git keeps tracking any file that is already committed. .gitignore only affects untracked files.
Patterns match the name exactly. One extra letter means the rule never matches your log files.
Without --cached, Git also deletes the file from your folder, and the app loses its configuration.
Questions people ask
Should .gitignore itself be committed?
Yes. It is part of the project and keeps everyone's repository consistent.
Does .gitignore remove files from GitHub?
No. It only stops new files from being added. Anything already pushed stays until you remove it with git rm --cached and push, and older commits still hold it.
Can I ignore an empty folder?
Git does not track empty folders at all. People often add a placeholder such as .gitkeep to commit an empty folder on purpose.
Why is .DS_Store everywhere?
macOS Finder writes it to store view settings for each folder. It has nothing to do with your site, so ignore it, ideally in your global ignore file.