Skip to content
Innovialabs

.gitignore Guide: What to Ignore and How Patterns Work

Practice4 min

In short

.gitignore tells Git which untracked files to keep out of the repository, such as dependencies, builds, local settings and secrets; it does not affect files already committed — those must be removed with git rm --cached.

What .gitignore does

.gitignore is a text file with a list of patterns. Files that match are hidden from git status and skipped by git add ..

The key thing to remember: .gitignore only works for untracked files. If a file has already been committed, adding it to .gitignore changes nothing — Git keeps tracking it.

What people usually ignore:

  • dependencies: node_modules/, .venv/, Pods/;
  • build output: dist/, build/, caches;
  • local settings: IDE files, .DS_Store, Thumbs.db;
  • secrets: .env, keys, certificates, keystores.

What you do not ignore: source code, lock files (package-lock.json, poetry.lock) and sample configs such as .env.example.

Pattern syntax

PatternWhat it matches
debug.logA file or folder with that name at any level
*.logAll files ending in .log
build/Only directories named build (trailing slash)
/config.local.jsonOnly at the root, next to this .gitignore
docs/*.pdfPDFs directly in docs, not in subfolders
**/temptemp at any depth
logs/**Everything inside logs
a/**/ba/b, a/x/b, a/x/y/b
file?.txtExactly one character
[abc].txtOne character from the set

The rules people mix up most often:

  • * does not cross /. Use ** to reach nested folders.
  • A pattern with a slash at the start or in the middle is anchored to the folder containing the .gitignore. Without a slash it matches at any level.
  • Lines starting with # are comments. Blank lines are ignored.

Negation and nested files

An exclamation mark ! brings back a file that an earlier pattern excluded:

*.env
!example.env

The trap: you cannot re-include a file if its whole parent directory is excluded. Git simply does not look inside. This does not work:

logs/
!logs/.gitkeep

This does — exclude the contents, not the folder itself:

logs/*
!logs/.gitkeep

Nested .gitignore files. Any subfolder can have its own .gitignore. Its patterns are relative to that folder, and when rules conflict, the deeper file wins.

.git/info/exclude uses the same rules but is never committed. It suits personal exclusions in a single repository.

Global gitignore

Junk from your OS and editor is better ignored once for all projects than in every repository:

git config --global core.excludesFile ~/.gitignore_global

Good candidates: .DS_Store, Thumbs.db, .idea/, .vscode/, *.swp. The project .gitignore should hold what concerns the project itself and everyone working on it.

Ready templates

Node.js / frontend:

node_modules/
dist/
build/
.next/
coverage/
npm-debug.log*
.env
.env.*
!.env.example

Python:

__pycache__/
*.py[cod]
.venv/
venv/
*.egg-info/
dist/
build/
.pytest_cache/
.mypy_cache/
.env

Mobile (Android, iOS, Flutter):

# Android
.gradle/
build/
local.properties
*.jks
*.keystore
# iOS
xcuserdata/
DerivedData/
*.xcuserstate
# Flutter
.dart_tool/

Whether to commit Pods/ on iOS is a team decision; both approaches are common. GitHub maintains a large collection of templates in the github/gitignore repository.

Untracking files that are already committed

If a file is already tracked, add it to .gitignore and remove it from the index without deleting it from disk:

git rm --cached config.local.json
git rm -r --cached build/
git commit -m "Stop tracking local files"

To see which rule applies to a file: git check-ignore -v path/to/file.

This is not enough for secrets. git rm --cached only removes the file from future commits; it stays in history, and anyone with access to the repository can find it. The right order:

  1. Revoke and rotate the key, password or token right away. Treat it as compromised.
  2. Untrack the file and add it to .gitignore.
  3. If needed, rewrite history (git filter-repo or BFG Repo-Cleaner), force push and ask the team to re-clone.

Rewriting history without rotating the secret does not help: copies of the repository may already be out there.

The full syntax is described in the official Git documentation.

FAQ

Most likely Git is already tracking it. Run git rm --cached <file> and commit the change. You can also check the matching rule with git check-ignore -v.

We can help with this

If you'd rather get the result than figure it all out yourself — this is what we do every day.

Discuss a project

Read next

Have an idea or a task? Tell us about it

We'll reply within one business day and propose a solution. The consultation is free.