Git Course 0%

.gitignore

Beginner Git CLI VS Code UI IntelliJ UI GitLab UI GitHub UI ≈ 10 min

What you will learn

  • The categories of files that never belong in a repository
  • The pattern syntax of .gitignore, with the six patterns that cover almost everything
  • Global ignores, check-ignore, and the "already tracked" trap

After this lesson you can

  • I can write or extend a .gitignore for a project and prove it works
  • I can remove a wrongly committed generated file without losing it from disk

Why this matters

git add . is convenient and dangerous: it stages every untracked file, including the 200 MB of installed packages, the editor's settings folder, the file with your API key. .gitignore is the list of things Git must never offer for staging. A good one makes git status quiet and honest; a missing one is how secrets and junk enter history.

What to ignore

Category Examples Why
Generated files build/, dist/, __pycache__/, *.pyc, *.class, node_modules/ Regenerated from source; huge; change on every build
Dependencies node_modules/, .venv/, vendor/ Installed by the package manager from the manifest
Secrets and local configuration .env, *.pem, secrets.yml, config.local.* Must never leave your machine
Editor and OS noise .vscode/, .idea/, .DS_Store, Thumbs.db, *.swp Personal, not part of the project
Logs and temporary files *.log, tmp/, *.tmp Noise

Never ignore: source, tests, documentation, data the project needs, manifests, lock files, the pipeline definition, .gitignore itself.

The file

.gitignore is a plain text file at the root of the repository (extra ones can sit in subfolders). One pattern per line; # starts a comment. The playground's:

.gitignore
# Python
__pycache__/
*.pyc
.venv/

# Secrets and local settings — never commit these
.env
*.local

# Editors and operating systems
.DS_Store
Thumbs.db
.idea/
.vscode/

The six pattern shapes that cover almost every case:

Pattern Matches
name any file or folder called name, in any folder
name/ only folders called name (and everything inside)
*.log any file ending in .log, in any folder
/build only build at the root of the repository
docs/*.tmp .tmp files directly inside docs
!keep.log an exception: do not ignore this even if an earlier pattern matches

Patterns apply to untracked files only; a file already in history is unaffected (see the trap below).

Templates

Every language has a standard list. GitLab and GitHub both offer templates when creating a project (.gitignore template dropdown), and github.com/github/gitignore is the shared source: Python.gitignore, Node.gitignore and so on. Start from the template for your language and add the secrets and editor lines.

Check whether a file is ignored

Terminal
$ git check-ignore -v .env src/__pycache__/trailguide.cpython-313.pyc
.gitignore:7:.env	.env
.gitignore:2:__pycache__/	src/__pycache__/trailguide.cpython-313.pyc

Each line names the file, the line number and the pattern that matched. No output means "not ignored". git status --ignored lists all ignored files at the end of the status:

Terminal
$ git status --ignored
Ignored files:
  (use "git add -f <file>..." to include in what will be committed)
	.env
	src/__pycache__/

nothing to commit, working tree clean

And if you try to add an ignored file, Git refuses and tells you why:

Terminal
$ git add .env
The following paths are ignored by one of your .gitignore files:
.env
hint: Use -f if you really want to add them.
hint: Disable this message with "git config set advice.addIgnoredFile false"

Take that refusal as a gift. -f exists for the rare legitimate case; a secret is never one.

The trap: already tracked

Ignore rules do not apply to files Git already tracks. If todo.txt was committed and you then add it to .gitignore, it keeps showing as modified. Untrack it once, keeping the file on disk:

Terminal
$ git rm --cached todo.txt
rm 'todo.txt'
Terminal
$ git status -s
 M .gitignore
D  todo.txt

Commit both: the file is removed from history going forward, stays on your disk, and the pattern keeps it out from now on. (The file remains in old commits; for secrets that is not enough — lesson 8.7.)

A global ignore for your own noise

Editor folders and .DS_Store are about your machine, not the project. Keep them in a personal, global ignore file so that every repository ignores them, even ones whose .gitignore forgot:

Terminal
$ git config --global core.excludesFile ~/.gitignore_global
$ printf '.DS_Store\nThumbs.db\n.idea/\n.vscode/\n*.swp\n' > ~/.gitignore_global

Project-specific ignores still belong in the project's .gitignore, so colleagues get them too.

In the tools

Edit .gitignore with any editor, then git status to confirm the file disappeared from the list, git check-ignore -v <file> to see which rule matched.

Common mistakes

  • Ignoring after committing. Untrack with git rm --cached once.
  • Ignoring too much. A pattern like *.md in a docs project hides the documentation. Test with git check-ignore -v.
  • Putting personal editor folders into the project's .gitignore and nothing else. Fine, but the global ignore file protects you everywhere.
  • Committing .env "just for now". Git remembers forever. Use .env.example.

Try it yourself

Goal: add an ignore rule, prove it works, and fix a file that was committed before being ignored.

  1. In the playground, create tmp/scratch.log (make the folder first) and run git status -s.
  2. Append *.log to .gitignore; run git status -s and git check-ignore -v tmp/scratch.log.
  3. Create todo.txt, add and commit it; then add todo.txt to .gitignore, edit the file, and run git status -s.
  4. Untrack it with git rm --cached todo.txt, run git status -s, and commit.

Expected result: step 2 shows only M .gitignore and check-ignore names the *.log rule; step 3 shows todo.txt still modified despite the rule; after step 4 it shows D todo.txt staged and the file still exists on disk.

Show solution

The .log file vanished from status as soon as the pattern existed because it was untracked. todo.txt was tracked, so the pattern did nothing until git rm --cached removed it from the index. After the commit, ls todo.txt still finds the file; Git simply no longer looks at it.

Check yourself

1. You added secrets.yml to .gitignore but git status still shows it as modified. Why?
2. Which pattern ignores a folder named build only at the repository root?
3. git add .env prints "The following paths are ignored". What should you do?

Key terms

.gitignore Ignored Untracked Tracked