Ignore everything except selected files in Git

Build a .gitignore allowlist with negated patterns, re-include parent directories, and check which rule controls a path.

Best practices
Illustration of Git branches and version history

Start with * to ignore untracked paths, then use patterns beginning with ! to keep selected files visible to Git. For nested files, also re-include each parent directory. Git does not search an excluded directory for possible exceptions inside it.

These rules affect untracked files. They do not remove files that are already tracked.

Keep a few root files and an entire source tree

In the repository's root .gitignore:

# Ignore by default.
*

# Keep these root files.
!/.gitignore
!/README.md
!/Makefile

# Keep the source directory and its descendants.
!/src/
!/src/**

The leading slash anchors these exceptions to the directory containing this .gitignore. The explicit directory exception lets Git enter src/; the recursive exception permits its contents.

Keep one nested file

For a root docs/guide.pdf, use:

*
!/.gitignore
!/docs/
/docs/*
!/docs/guide.pdf

For a deeper file, open the parent chain as well:

*
!/.gitignore
!/docs/
/docs/*
!/docs/manual/
/docs/manual/*
!/docs/manual/guide.pdf

Put comments on separate lines. A trailing # explanation is part of a .gitignore pattern, not a shell-style comment.

If you want every descendant of docs/, use !/docs/ followed by !/docs/**. A recursive file exception alone does not overcome an excluded parent.

Check the rule that applies

git check-ignore -v -- docs/guide.pdf
git status --ignored

Verbose check-ignore can print a matching negated rule, so output does not automatically mean the file is ignored. Read the pattern: a leading ! marks an exception. Ordinary tracked files are omitted from this check by default; use --no-index when diagnosing which ignore rules would match one:

git check-ignore -v --no-index -- docs/guide.pdf

Finally, use git status --short --untracked-files=all to verify the paths you expect to add.

FAQ

Why does !file.txt do nothing?

A parent directory may still be excluded. Re-include every required parent and place the exception after the rule it overrides. The applicable rule's location and precedence also matter when several ignore files exist.

When is an allowlist useful?

It can suit a minimal example repository or a directory where only selected release artifacts should be tracked. For everyday development, ignoring known generated files is often easier to maintain because new source files remain visible by default.

Can I preserve logs/.gitkeep while excluding logs?

Yes, keep the directory traversable and allow only the placeholder:

*
!/.gitignore
!/logs/
/logs/*
!/logs/.gitkeep

The placeholder is an ordinary tracked file; its name does not override ignore rules on its own.

See gitignore and git-check-ignore.

Get a tailored plan

Contact us

Join the community

Scan with WeChat
to join the community

Try Guance

Start online and pay only for what you use.

Get started

Choose a Guance plan

Code hosting