997 words
5 minutes

Gitignore Not Working? Check Tracked Files Before git rm --cached

2026-10-02
DevOps
Git
/
DevOps
/
Troubleshooting

If .gitignore contains your file but Git still reports changes to it, check whether the file is already tracked. An ignore rule does not remove a path from Git’s index. For a tracked file, git check-ignore can also print nothing even when the rule matches.

Use git ls-files to check tracking, then git check-ignore --no-index to inspect the rule independently. If the file should become local-only, remove that exact path from the index with git rm --cached and commit the removal with the ignore rule. Your local copy stays; a teammate pulling the commit can lose their previously tracked copy.

Separate tracking from rule matching#

Run these commands from the repository root, replacing local.env with the actual relative path:

Terminal window
git ls-files -- local.env
git check-ignore -v -- local.env
git check-ignore -v --no-index -- local.env

The commands answer different questions. Git’s ignore reference limits ignore rules to untracked files. The check-ignore manual explains that the default check skips tracked files, while --no-index bypasses index membership for the check.

With a tracked local.env and the rule /local.env, the first command prints the path, the second prints nothing, and the third identifies the rule:

.gitignore:1:/local.env local.env

The gap is diagnostic: the pattern matches, but the file is tracked. Rewriting the same pattern will not change that state.

ResultWhat to check next
ls-files lists the path; --no-index shows an excluding ruleStop tracking the path if it should be local-only
ls-files lists the path; neither rule check shows a matchAdd or correct the ignore rule before untracking
ls-files is empty; ordinary check-ignore shows an excluding ruleThe path is already untracked and ignored
A verbose result shows a pattern beginning with !That matching rule re-includes the path; inspect rule order

A verbose match alone is not proof of exclusion: negated patterns begin with !. To find other tracked paths that match ignore rules, use the read-only inventory documented by git ls-files:

Terminal window
git ls-files -ci --exclude-standard

Review that list as candidates. Do not pipe it directly into a removal command.

Remove one path from the index#

First inspect git status --short and preserve any unrelated staged work. Add an appropriate rule to the root .gitignore; for this example it is:

/local.env

Preview the exact removal, apply it, and inspect the staged result:

Terminal window
git rm -n --cached -- local.env
git rm --cached -- local.env
git add -- .gitignore
git diff --cached --name-status
git diff --cached -- .gitignore

The staged name summary for the example is:

A .gitignore
D local.env

An existing .gitignore would show M instead of A. The D records removal from the next committed tree; it does not mean the local working file was erased. According to the git rm manual, --cached leaves working files alone and -n previews the operation.

If the command refuses because the staged file differs from both HEAD and the working file, inspect git diff --cached -- local.env and git diff -- local.env. Resolve which content to retain before retrying; do not automatically add -f.

Before committing, confirm that the entire staged diff contains only the intended ignore-rule change and file removal. If unrelated work is staged, finish or separate that work first. Then commit the reviewed index:

Terminal window
git commit -m "Stop tracking local configuration"
git show --name-status --format= HEAD

The commit should include the D entry for local.env. Do not replace this with git commit --only -- .gitignore local.env: in an additional fixture on the same Git version, that command committed only the new ignore file and put the still-existing local.env back into the index. The removal was lost. The git commit reference explains that explicit paths select their working-tree contents rather than the already staged changes.

There is no need to rebuild the whole index or stage the entire repository for a one-file correction.

Verify the result in this working copy#

After the commit:

Terminal window
git ls-files -- local.env
git check-ignore -v -- local.env
git status --short --ignored -- local.env
test -f local.env && printf 'local file retained\n'

For the fixture below, ls-files prints nothing, check-ignore identifies /local.env, status prints !! local.env, and the last command confirms the local file remains. These checks establish three separate facts: untracked, ignored, and present on disk.

Ignoring a file in Git does not exclude it from a Docker build context. If the same configuration file must stay out of an image, inspect .dockerignore separately; the Docker build-context guide explains that boundary.

Reproduce what a teammate receives#

The following disposable two-clone fixture was executed during article verification on October 2, 2026, with git version 2.54.0 (Apple Git-157) on macOS. It uses dummy configuration, a local clone, and a clean teammate working tree. It does not test merge conflicts or locally modified teammate files.

Run it in Bash. Keep it separate from your project:

Terminal window
fixture_dir="$(mktemp -d)"
git init -q -b main "$fixture_dir/author"
cd "$fixture_dir/author"
git config user.name Fixture
git config user.email [email protected]
printf 'MODE=demo\n' > local.env
git add -- local.env
git commit -qm "Track fixture"
git clone -q . "$fixture_dir/teammate"
printf '/local.env\n' > .gitignore
printf 'MODE=changed\n' > local.env
git check-ignore -v --no-index -- local.env
git rm --cached -- local.env
git add -- .gitignore
git commit -qm "Stop tracking local config"
test -f local.env && printf 'author: present\n'
git -C "$fixture_dir/teammate" pull --ff-only
if test -f "$fixture_dir/teammate/local.env"; then
printf 'teammate: present\n'
else
printf 'teammate: absent\n'
fi
git show HEAD~1:local.env

The significant observed results were:

author: present
...
delete mode 100644 local.env
teammate: absent
MODE=demo

--cached preserved the author’s working file, but the commit contained a deletion. The clean teammate clone applied that deletion on its fast-forward pull. The final command also retrieved the original contents from the earlier commit: stopping tracking did not erase history.

Before sharing this change, have collaborators preserve needed local configuration outside the repository and provide a tracked template with dummy values. They can recreate their ignored local file after updating. Do not treat this clean-clone result as a prediction for every dirty working tree; local edits can affect whether an update proceeds.

If the committed file contained real credentials, follow GitHub’s sensitive-data guidance: revoke or rotate the secret first, then evaluate history cleanup separately. A successful ignore check only proves the current exclusion rule, not removal from old commits or other copies.

References:

Gitignore Not Working? Check Tracked Files Before git rm --cached
https://laplusda.com/en/posts/gitignore-tracked-files-rm-cached/
Author
Zero
Published at
2026-10-02
License
CC BY-NC-SA 4.0