Ignore a directory except for one subdirectory in Git

Use ordered .gitignore exceptions to keep one nested directory, diagnose matching rules, and distinguish ignored files from already tracked files.

Best practices
Illustration of Git history and collaboration

In a repository-root .gitignore, ignore the contents of the parent directory, then add an exception for the child you want to keep:

/main/*
!/main/subfolder2/

This ignores siblings such as main/subfolder1/ and main/subfolder3/, while allowing Git to discover files under main/subfolder2/. It assumes no other matching rule excludes those files.

Keep the parent directory accessible

This pair does not work:

/main/
!/main/subfolder2/

The first rule excludes the parent directory itself. Git does not descend into an excluded directory to find exceptions inside it. Using /main/* leaves main/ accessible while excluding its immediate contents. The leading slash anchors these examples to the directory containing this .gitignore, which is the repository root here.

For a deeper exception, reopen each parent and exclude its unwanted children:

/main/*
!/main/a/
/main/a/*
!/main/a/b/

This keeps files beneath main/a/b/, but excludes other children of main/ and main/a/. See the gitignore pattern rules.

Inspect the rule that matched

git check-ignore -v -- main/subfolder2/file.txt
git check-ignore -v -- main/subfolder1/file.txt
git status --short --ignored --untracked-files=all

Read the pattern in verbose output. A matching pattern that starts with ! is an inclusion exception: output from check-ignore -v does not always mean the file is ignored. No output can mean no rule matched; tracked files are also normally omitted by this diagnostic.

For an already tracked path, inspect the applicable ignore rules without consulting the index:

git check-ignore -v --no-index -- main/subfolder2/file.txt

This is a diagnostic option, not an instruction to stop tracking the file. The check-ignore reference explains its output format.

Handle files Git already tracks

Ignore rules govern untracked files. Adding a tracked file to .gitignore does not remove it from the index or stop future changes from appearing in diffs.

To deliberately stop tracking a file while keeping your local copy:

git rm --cached -- main/subfolder1/file.txt
git diff --cached

Review and commit the staged removal together with the ignore rule. This changes the repository for collaborators too; it is not a private local setting. For a whole directory, git rm -r --cached -- DIRECTORY applies the same operation recursively, so inspect the staged result carefully.

FAQ

Why does an exception still fail?

Check whether an ancestor is excluded, whether a later rule in the same file or a rule in a deeper .gitignore overrides your exception, and whether the directory contains a file. Git does not store empty directories. A placeholder file is sufficient; .gitkeep is only a naming convention, with no special Git behavior.

Can I ignore all log files except one?

Yes. Put the exception after the general rule:

*.log
!important.log

This allows files named important.log wherever these rules apply, provided their parent directories remain accessible. Use !/important.log to limit the exception to the .gitignore directory itself.

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