Deleting Ignored Files Mistakenly Committed to a Git Repo
This is not a common situation, but occasionally you may find yourself having force-committed a bunch of things (usually a bad sign to begin with, but that’s a whole ’nother post) and a few files that should be ignored sneak into your repo. You might have dozens of commits from that point on and not be aware of it, because your .gitignore file dutifully doesn’t track those files anyway.
So: how to remove those files from the Git cache? My research led me to rewriting commits, which is usually filed in the “Contents Dangerous. Open With Caution.” section of Git. Here’s some links:
- Making Git ignore already-tracked files (The first comment on Aral’s post points to this useful gist by user atnan: git-clean-cached.sh)
- git: forever remove files or folders from history
- Permanently Delete Folders and Files from Git History (Uses the David Underhill script linked above.)
So here was my process:
- Remove the files from the Git cache. I used an rm -rf command because I was getting rid of directories. For example:
git filter-branch --index-filter 'git rm -rf --cached --ignore-unmatch <path to file or directory, from root level of your repo>' HEAD
- Prune Git. For example:
rm -rf .git/refs/original/ && git reflog expire --all && git gc --aggressive --prune
- Force-push your edits, otherwise they will be rejected because you’ve rewritten history. (Couldn’t figure this part out until I read Thomas Hunter’s post linked above.)
git push origin master --force
If you’ve got a bunch of files, I would suggest atnan’s gist linked above, or David Underhill’s script (second link). David’s script also prunes Git (my understanding is you can still have file references hanging around that need to be garbage-collected).
Ideally you would never end up in this situation, and hopefully you catch this before you’ve pushed changes to a remote and others have pulled the dirty repo down. In my case there didn’t seem to be ill effects introduced by rewriting commits and pushing to a remote, but it’s something I’d like to avoid as much as possible.