| Tested on | RHEL 10.2 (Coughlan) |
|---|---|
| Package | git 2.52.0 |
| Applies to | Any host with Git installed |
| Privilege | Normal user |
| Scope | Write .gitignore patterns, ignore folders and wildcards, un-ignore with !, debug with git check-ignore, fix already-tracked files with git rm --cached, and use local or global exclude files. Not a full git clean or untrack tutorial. |
| Related guides | Remove file from tracking Git clean Git remove untracked files Git init Git tutorial |
.gitignore tells Git which paths to leave alone. Ignored files do not show up as untracked in git status, and git add . skips them unless you force-add a path. That keeps logs, build output, and local env files out of commits — but it does not untrack files Git already recorded, and it does not erase content from history.
Four jobs this article covers:
- write root patterns that hide common junk;
- match files, folders, and exceptions with wildcards;
- fix rules when a file was committed before you ignored it;
- debug matches with
git check-ignoreand use local or global exclude files.
Pick your goal in the table below, then jump to that section.
Choose the Right Tool
| Your goal | What to use |
|---|---|
| Hide new build artifacts or logs | Patterns in .gitignore |
| See which rule matched a path | git check-ignore -v <path> |
| Stop tracking a file that is already committed | git rm --cached <path> — see remove file from tracking |
| Ignore files only on your machine | .git/info/exclude |
| Ignore OS or editor junk in every repo | ~/.config/git/ignore or core.excludesfile |
| Delete untracked files from disk | git clean — see Git clean |
.gitignore affects untracked paths only. It is not a substitute for removing files Git already tracks.
Create a Root .gitignore
Scenario: your repository contains debug.log, secrets.env, and a build/ directory you do not want Git to track.
Add these lines to the root .gitignore:
*.log
*.env
build/Check short status:
git status -sb## main
?? .gitignoreOnly .gitignore appears. Git hid debug.log, secrets.env, and build/ because the patterns matched — you can commit the ignore file without staging those paths.
Match Files, Folders, and Exceptions
Patterns are relative to the .gitignore file that contains them — not always from the repository root. A leading slash anchors the pattern to that directory:
| Pattern | Matches |
|---|---|
build/ |
Any directory named build below the ignore file |
/build/ |
build/ only in the directory that holds this .gitignore |
*.log |
Any path ending in .log under that ignore file |
logs/*.log |
.log files directly inside logs/, not deeper subfolders |
**/cache/ |
Any directory named cache at any depth |
A trailing slash on a directory name such as build/ tells Git to treat the match as a folder. Comments start with #. Blank lines are ignored.
Un-ignore one path with !
Sometimes you ignore a group but need one file tracked — for example all logs except a sample file you ship in the repo.
*.log
!important.logAssume important.log and error.log both exist. After those rules, check status:
git status -sb## main
?? .gitignore
?? important.logimportant.log is listed because !important.log cancels the earlier *.log rule. error.log stays ignored and does not appear.
To see which rule matched an ignored file:
git check-ignore -v error.log.gitignore:1:*.log error.log! works only when Git can still traverse the parent directory. If the parent directory itself is ignored, you must first un-ignore the directory before re-including a file inside it. This pattern does not work the way many beginners expect:
build/
!build/keep.txtGit cannot re-include keep.txt while build/ excludes the whole directory. Un-ignore the directory first, then the file — see References for the full negation rules in Git's documentation.
Debug Rules With git check-ignore
Scenario: a path is missing from git status and you want to know whether Git ignored it or the file does not exist.
Ask Git which rule matched:
git check-ignore -v debug.log.gitignore:1:*.log debug.logThe columns are the ignore file, line number, pattern, and path. When nothing matches, the command prints nothing and exits with status 1 — that path is not ignored.
For a directory rule:
git check-ignore -v build/output.bin.gitignore:3:build/ build/output.binUse this before editing patterns when several .gitignore files or a global exclude file might apply.
Fix .gitignore When a File Is Already Tracked
Scenario: config.local is already tracked and you later add this rule:
config.localThe rule does nothing for that path yet — Git keeps tracking files already in the repository. git add . continues to stage changes to tracked paths even when they match .gitignore.
Adding a secret to .gitignore does not remove it from existing Git history; it only prevents future untracked copies from being added normally.
Remove the file from Git's tracked set while keeping the actual file on disk:
git rm --cached config.localGit calls that tracked record the index.
rm 'config.local'Short status shows the staged removal:
git status -sb## main
D config.localCommit when you are ready. After that commit, config.local behaves like any other ignored path. For folders or bulk untracking, see remove file from tracking.
Local and Global Exclude Files
Not every ignore rule belongs in the committed .gitignore. Git can get ignore rules from several places:
.gitignorefiles in the repository.git/info/excludefor repo-specific personal rules- the file configured by
core.excludesfilefor your personal global rules
A .gitignore closer to the file can override rules from a parent .gitignore.
Personal rules in .git/info/exclude
Add patterns to .git/info/exclude inside .git/ — same syntax as .gitignore, never pushed to teammates. Use this for scratch files you want ignored only on your machine:
scratch.tmp
local-notes.txtGlobal ignore across repositories
Git can also use a personal ignore file for patterns you want in every repo. The default is normally ~/.config/git/ignore (or $XDG_CONFIG_HOME/git/ignore when that variable is set). Alternatively, point Git at another file:
git config --global core.excludesfile ~/.gitignore_globalTypical global patterns include OS and editor junk:
.DS_Store
Thumbs.db
*.swpKeep project-specific rules in the committed .gitignore so the team shares them.
Nested .gitignore in Subdirectories
Scenario: ignore logs/ under src/ but not a root-level logs/ directory.
# src/.gitignore
logs/Because this .gitignore sits inside src/, logs/ means src/logs/, not ./logs/ at the repository root. The same applies to /logs/ in that file — a leading / anchors to src/, so it still matches src/logs/ only.
Confirm which rule matched a path inside that tree:
git check-ignore -v src/logs/app.logsrc/.gitignore:1:logs/ src/logs/app.logRoot patterns still apply elsewhere — a root *.log rule would ignore src/debug.log, while logs/ in src/.gitignore covers only src/logs/.
Starter Templates for Common Stacks
Copy and trim these blocks into your root .gitignore. They are starting points — adjust for your build tool and team rules.
Node.js:
node_modules/
npm-debug.log*
.env
.env.local
dist/
build/
coverage/Python:
__pycache__/
*.py[cod]
.venv/
.env
dist/
build/
*.egg-info/Java / Maven:
target/
*.classFor a minimal public repo that tracks only source, some teams use:
*
!.gitignore
!README.md
!src/
!src/**That ignores everything at the root except the listed paths — useful for homework repos, easy to get wrong in production projects.
Troubleshooting
| Symptom | Likely cause | Fix |
|---|---|---|
File still tracked after adding to .gitignore |
Path was committed before the rule | git rm --cached <path>, commit, keep local file |
| Pattern seems ignored but file still in status | Wrong path or negation order | git check-ignore -v <path>; put ! exceptions after the ignore rule |
.gitignore pattern exists but git add . still stages the file |
File is already tracked, or the pattern does not match | Check with git ls-files <path> and git check-ignore -v <path>; use git rm --cached when it should stop being tracked |
| Teammate sees ignored file you do not | Their global exclude differs | Align on repo .gitignore; avoid personal-only rules for shared artifacts |
| Nested rule does not match | Leading / or path is relative to that .gitignore directory |
A leading / anchors the pattern to the directory containing that .gitignore. For example, /logs/ inside src/.gitignore matches src/logs/ only |
| Want to delete ignored untracked files | .gitignore does not delete disk files |
Preview with git clean -ndX, then git clean -fdX — see Git clean for -x and other options |
References
Summary
.gitignore keeps untracked paths out of git status and normal commits. Root patterns such as *.log, *.env, and build/ hide common noise, and git check-ignore -v shows which file and line matched when a path disappears from status.
Patterns are relative to the ignore file that contains them — build/ and /build/ behave differently. Wildcards and trailing slashes cover file types and whole directories; ! carves out exceptions, but not inside a directory you already excluded. Those rules only apply to untracked paths — if you already committed a file, add the pattern and run git rm --cached before the ignore rule takes effect.
Use .git/info/exclude for machine-only scratch files and ~/.config/git/ignore (or core.excludesfile) for OS or editor junk across every repo. Nested .gitignore files scope rules to subtrees without affecting the rest of the project. When you need to remove untracked files from disk or bulk-untrack committed paths, reach for Git clean and remove file from tracking instead of stacking more ignore patterns.

