How to Remove a File from Git Without Deleting It Locally
If you’ve ever accidentally committed a config file, secret, or environment-specific file to Git, you’ve probably run into this situation:
“I want Git to stop tracking this file — but I don’t want it deleted from my machine.”
This guide covers both:
- How to stop Git from tracking a file while keeping it locally.
- How to completely remove it from Git history if it ever contained secrets.
The common case: stop tracking, keep local copy
You have a file that:
- is already tracked by Git
- is still useful locally
- should not live in the repository
Common examples:
terraform.tfvars.envsecrets.yaml- local kubeconfig files
Solution: git rm --cached
git rm --cached path/to/file
git commit -m "Remove file from version control"
This tells Git:
- ❌ stop tracking the file
- ✅ keep the file on disk
Your local copy remains untouched.
Don’t forget to ignore it
After removing the file from Git, add it to .gitignore so it doesn’t get added again later:
echo "terraform.tfvars" >> .gitignore
git add .gitignore
git commit -m "Ignore terraform.tfvars"
Removing multiple files
git rm --cached *.tfvars
git commit -m "Stop tracking tfvars files"
Or remove an entire directory:
git rm --cached -r secrets/
git commit -m "Remove secrets directory from repo"
Verify the file is no longer tracked
git status
git ls-files | grep terraform.tfvars
If nothing is returned, Git is no longer tracking the file.
⚠️ Important: this does NOT remove it from history
If the file was committed in the past, it still exists in:
- commit history
- pull requests
- forks and clones
If the file contained secrets, assume they are compromised.
Fully remove a file from Git history (recommended for secrets)
To permanently remove a file from all commits, use git filter-repo
(the modern replacement for git filter-branch).
Step 1: Install git filter-repo
brew install git-filter-repo # macOS
# or
pip install git-filter-repo
Step 2: Rewrite history to remove the file
git filter-repo --path terraform.tfvars --invert-paths
This:
- removes the file from every commit
- rewrites repository history
Step 3: Force-push the cleaned history
git push --force --all
git push --force --tags
⚠️ This is a breaking change:
- collaborators must re-clone or reset
- old commit hashes will no longer exist
After rewriting history (checklist)
- 🔁 Rotate all affected secrets immediately
- 📣 Notify collaborators
- 🧹 Ask others to re-clone:
or hard-reset:git clone <repo>git fetch --all git reset --hard origin/main
When you should rewrite history
✅ Do this if:
- secrets were committed
- credentials were public even briefly
- compliance or security matters
❌ Skip it if:
- the file never contained sensitive data
- the repo is very large and widely cloned
- risk is low and acceptable
TL;DR
- Stop tracking a file (keep local copy):
git rm --cached <file> - Prevent it from coming back:
echo "<file>" >> .gitignore - Completely erase it from history:
git filter-repo --path <file> --invert-paths git push --force --all
This is an essential Git pattern for Terraform, Kubernetes, and any repo that evolves from local experimentation into real infrastructure.