Ignoring Files

Every project produces files that shouldn't be in version control: build output, downloaded dependencies, log files, editor settings, and secrets such as passwords and API keys. A .gitignore file lists them, so Git stops reporting them as untracked and git add . never picks them up.

The problem

Sam's online shop project has generated folders, logs, a secrets file and a stray system file lying around:

$
git status -s
Output
?? .DS_Store
?? .env
?? debug.log
?? dist/
?? logs/
?? node_modules/

None of these belong in history. The dependencies can be reinstalled, the build can be rebuilt, the logs are noise — and the .env file contains a live API key that must never be committed.

Creating .gitignore

Create a file called .gitignore in the top folder of the repository, with one pattern per line:

$
cat > .gitignore <<'EOF'
# Dependencies and build output
node_modules/
dist/

# Logs
*.log

# Secrets
.env

# Operating system files
.DS_Store
EOF
git status -s
Output
?? .gitignore

Only .gitignore itself is left. Commit it — the rules then apply to everyone who works on the project:

$
git add .gitignore
git commit -m "Ignore dependencies, build output, logs and secrets"
Output
[main 1f7c5de] Ignore dependencies, build output, logs and secrets
 1 file changed, 12 insertions(+)
 create mode 100644 .gitignore

Pattern rules

PatternIgnores
debug.logA file (or folder) called debug.log in any folder
*.logEvery file ending in .log, anywhere
build/Folders called build (the trailing slash means "folders only")
/todo.txtOnly todo.txt in the top folder (a leading slash anchors the pattern)
docs/*.pdfPDF files directly inside docs, not in its subfolders
docs/**/*.pdfPDF files anywhere under docs
!keep.logException: don't ignore keep.log, even though *.log matched it
# commentNothing — lines starting with # are comments

One catch with !: you can't re-include a file if its parent folder is ignored, because Git doesn't look inside ignored folders at all. Ignore the folder's contents (logs/*) instead of the folder itself (logs/) when you need exceptions.

$
cat >> .gitignore <<'EOF'
!logs/README.log
EOF
echo "Logs are written here" > logs/README.log
git status -s
Output
 M .gitignore
?? logs/

logs/ shows up as untracked again because of the exception: README.log is no longer ignored, while server.log next to it still is. This worked because only the files were ignored (by *.log). Had the rule been logs/, the exception would have had no effect.

Why is this file ignored?

git check-ignore -v reports the file and line number of the matching rule:

$
git check-ignore -v debug.log node_modules/express/index.js
Output
.gitignore:6:*.log	debug.log
.gitignore:2:node_modules/	node_modules/express/index.js

A file that isn't ignored produces no output. To list every ignored file in the project, use git status --ignored -s (ignored files are marked !!).

Ignoring a file that's already tracked

.gitignore only affects untracked files. If a file was committed before you added the rule, Git keeps tracking it. Remove it from the repository — but not from your disk — with git rm --cached:

$
echo "settings.local.ini" >> .gitignore
git rm --cached settings.local.ini
Output
rm 'settings.local.ini'
$
git add .gitignore
git commit -m "Stop tracking local settings"
Output
[main 6e030c2] Stop tracking local settings
 2 files changed, 2 insertions(+), 1 deletion(-)
 delete mode 100644 settings.local.ini
$
ls settings.local.ini
Output
settings.local.ini

The file still exists locally, and Git now ignores it. (The old versions remain in history — which is why secrets need extra care, as described below.)

Other places for ignore rules

LocationUse it forShared?
.gitignore (any folder)Project rules: build output, dependencies. A .gitignore in a subfolder applies to that folder.Yes — committed
.git/info/excludeYour own files in one repository, like a personal notes fileNo
Global ignore fileThings your computer or editor creates in every project: .DS_Store, Thumbs.db, .idea/, *.swpNo
$
git config --global core.excludesFile ~/.gitignore_global

Starting points

You don't have to write rules for common tools from scratch. GitHub offers a choice of ready-made .gitignore files when you create a repository, and maintains a public collection of templates for most languages and frameworks (the github/gitignore repository). Start from one and adjust it.

If you commit a secret

Treat any password or key that reached a commit as leaked — especially once it's been pushed. First revoke or rotate the key at the service that issued it; that's the only real fix. Removing it from the latest commit doesn't remove it from history. Tools such as git filter-repo can rewrite history to delete it, but anyone who already cloned the repository still has a copy. GitHub scans public repositories for known key formats and may warn you or the provider.

The habit that prevents all of this: keep secrets in an ignored file such as .env, and commit a .env.example with the variable names and fake values so others know what to set.

Try it yourself

In a test repository, create a build folder, a notes.tmp file and an important.tmp file. Write a .gitignore that ignores the folder and all .tmp files except important.tmp, and confirm with git status -s and git check-ignore -v.