.gitignore not working? Stop tracking a file and keep it locally
Git still tracking a file in .gitignore? Check the rule, keep your local copy and review the removal, with clear advice for teammates and exposed secrets.
You add a file to .gitignore, save it, and Git still lists it as modified. Adding the same filename again does nothing. Neither does restarting your editor.
If Git already tracks the file, an ignore rule will not stop that tracking. The usual fix is to add the right ignore rule and use git rm --cached -- path to remove that path from the index while keeping your working copy. Git’s FAQ on tracked files and ignore rules describes this distinction.
There are two consequences to understand first. The removal becomes part of your next commit, so sharing it can remove a teammate’s unchanged tracked copy when they pull. It also leaves earlier commits intact, including any secrets they contain.
This guide walks through one ordinary file, config.local.json, from diagnosis to a checked commit. Use your own filename in its place. The commands are for an existing repository with at least one commit; run them from its top-level folder, using a terminal with Git installed. Finish any merge or rebase before starting.
Check whether Git is already tracking the file
Start with these read-only checks:
git status --short
git ls-files -- config.local.json If the second command prints config.local.json, the path is in Git’s index: the staging area that defines the next commit’s contents. If it prints nothing and reports no error, that exact path is absent from the index. Check the spelling and your current folder before drawing a conclusion. The git-ls-files manual documents this default listing.
Now inspect the rule:
git check-ignore -v --no-index -- config.local.json The --no-index option lets this diagnostic examine ignore rules even for a tracked path. Without it, git check-ignore normally leaves tracked files out of its results. A matching rule therefore does not prove that Git has stopped tracking the file.
For a rule on the first line of a root .gitignore, an illustrative result is:
.gitignore:1:/config.local.json config.local.json This identifies the rule’s file, line number, pattern and the path being checked. If the reported pattern starts with !, it is an exception that includes the path again. Read the pattern, not just whether the command printed a line. These output rules are documented in git-check-ignore .
| What you find | What to do next |
|---|---|
| The file is tracked and should become local-only | Follow the removal workflow below. |
| The file is untracked but the rule does not exclude it | Correct the ignore pattern; there is no tracked entry to remove. |
| The file is tracked and everyone still needs a shared copy | Keep tracking it. Consider a separate local configuration file. |
Remove one file from tracking while keeping your copy
Suppose config.local.json was committed earlier, but it now contains settings that should stay on each developer’s computer.
Before changing a shared project, agree on that change and have collaborators back up any local settings they need outside the repository. --cached preserves the file in the checkout where you run the command. It does not promise preservation in everyone else’s checkout. Applying the resulting commit updates their repository and working files; local changes can also cause a conflict or refusal. See Git’s merge behaviour and pre-merge checks .
1. Add the ignore rule
Open the existing .gitignore at the repository root, or create one there if needed. If the diagnostic already confirmed a suitable rule, keep it. Otherwise, add this line without replacing the existing rules:
/config.local.json In this location, the leading slash restricts the rule to the root-level file. Save the file, then run the earlier git check-ignore -v --no-index command again to confirm the expected pattern.
2. Preview the removal, then apply it
git rm --cached --dry-run -- config.local.json Check that the preview names only the intended file. Then run:
git rm --cached -- config.local.json
git add -- .gitignore The --cached option is essential: it removes the index entry and leaves the working file alone. Ordinary git rm also removes the working file. The -- separates options from filenames. Git documents these behaviours in the git-rm manual .
Open config.local.json in your editor or file manager and confirm it is still there with the contents you need. Seeing rm 'config.local.json' in the terminal is not evidence that the local file vanished; that is also the command’s normal message for an index-only removal.
3. Review the next commit
git diff --cached --name-status If .gitignore is new and these are the only staged changes, the result should resemble:
A .gitignore
D config.local.json If .gitignore was already tracked and you changed it, expect M instead of A. If the required rule was already committed, .gitignore may not appear in this listing.
The D is expected. The next repository snapshot will omit the configuration file, while your local copy remains. Review the whole listing: a normal commit also includes unrelated changes that were already staged. Git’s diff documentation explains that --cached compares staged contents with the current commit.
Inspect the staged ignore-file change too:
git diff --cached -- .gitignore Confirm that you added the intended rule without removing useful existing rules.
4. Commit and confirm the result
Once the staged changes are the ones you intend to record:
git commit -m "Stop tracking local configuration"
git ls-files -- config.local.json
git status --short --ignored -- config.local.json The ls-files command should print nothing. The final status check should show:
!! config.local.json Git’s status reference identifies !! as an ignored path. Together with the file still opening locally, these checks establish the result you wanted: your working copy exists, the index no longer contains it, and an ignore rule applies.
Share the commit through your project’s normal review process after coordinating the configuration change.
If the ignore rule still does not match
Check the filename first: it should be .gitignore, not .gitignore.txt. Then check its location. Patterns are interpreted relative to the directory containing that ignore file.
In a root .gitignore:
/build/excludes the root-level build directory.build/also matches directories with that name further down the tree.*.logmatches names ending in.log.
Exceptions need care. This does not bring back the file inside the excluded directory:
logs/
!logs/keep.log For this direct-child example, use:
logs/*
!logs/keep.log The second form excludes the directory’s contents while leaving the parent available for the exception. It lets logs/keep.log remain eligible for tracking. Git’s pattern rules explain both slash handling and the excluded-parent limitation.
Rerun git check-ignore -v --no-index -- path with your actual path after editing a rule. Its source and line number can reveal a rule from another ignore file. Do not keep adding duplicate patterns without checking which one wins.
What if Git refuses to remove the file?
A refusal about staged content can mean that the version in the index differs from both the last commit and the file on disk. Preserve anything you need before changing that staged version.
Inspect both comparisons privately:
git diff --cached -- config.local.json
git diff -- config.local.json These commands display file contents. Do not paste their output into a public issue if the configuration contains credentials.
If the file exists in the current commit, and you have saved any staged-only content you need, you can reset just its index entry:
git restore --staged -- config.local.json This restores the index entry from HEAD, meaning the current commit, while leaving the working file untouched. It does replace any distinct staged version. You can then retry the scoped git rm --cached step. The behaviour is documented in git-restore .
The same git restore --staged command can undo an accidental staged removal before you commit it, for a path present in HEAD. It does not undo edits to .gitignore.
Ignore a directory without rebuilding the whole index
For a root-level generated directory, add /build/ to the root .gitignore, then preview the tracked paths involved:
git rm -r --cached --dry-run -- build/ If every listed file should stop being tracked:
git rm -r --cached -- build/
git add -- .gitignore
git diff --cached --name-status Review and commit as before. Here, -r allows the directory’s tracked contents to be removed recursively; --cached preserves the working files.
For a broader audit, this read-only command lists tracked paths that match active ignore rules:
git ls-files -ci --exclude-standard The active rules include personal exclusions as well as project .gitignore files. Treat the output as a review list, not permission to remove everything it names.
For one troublesome file or folder, there is no need to remove the entire repository from the index and add it all again. A named path makes the proposed change easier to inspect.
If the team still needs the configuration file
Sometimes the real requirement is to keep shared defaults while allowing each developer to change local settings. Removing the only configuration file can leave a fresh clone unable to run.
Git’s FAQ recommends a tracked template or defaults file alongside a separate ignored local file. For example:
- Commit
config.example.jsonwith usable dummy values. - Ignore
config.local.json. - Document how to create the local file and which values to supply.
Your application must actually load that local file; renaming a file alone will not teach the application a new configuration convention.
The same FAQ advises against using assume-unchanged or skip-worktree as a general way to hide edits to tracked files. Keep the distinction visible in the project’s structure instead.
If the file contained a secret
Ignoring or untracking a file does not erase its earlier commits. If a password, API key or access token was exposed, revoke or rotate that credential first, then assess whether coordinated history cleanup is needed.
GitHub’s sensitive-data removal guidance explains why copies can remain in other clones and references. Its October 2024 guidance on compromised personal access tokens also covers revocation and the need to consider dependent workflows.
Review the configuration template before committing it. A file named “example” can still leak a real credential.
For an ordinary local configuration file, finish by checking the three observable results: the file still opens on your computer, git ls-files no longer lists it, and git status --short --ignored marks it !!. That is a useful stopping point; rebuilding the rest of the repository is unnecessary.