For single Files

git rm --cached <filepath>

Will in fact remove the file from the repo, but its still in the history.

git filter-branch --tree-filter 'rm -f <filepath>' HEAD;
git filter-branch --index-filter 'git rm --cached --ignore-unmatch <filename>' HEAD;

This will instead remove the file from history.

Once satisfied with changes to history, you’ll have to force push.

Note: this will likely cause issues for anyone with unfinished work (e.g. in branches)

git push -f;

For entire directories

Taken from: https://stackoverflow.com/a/17824718

_WARNING: git filter-branch is [no longer officially recommended](https://git-scm.com/docs/> git-filter-branch#warning). The official recommendation is to use [git-filter-repo](https://github.com/> newren/git-filter-repo/).

git filter-branch --tree-filter "rm -rf <filepath>" --prune-empty HEAD
git for-each-ref --format="%(refname)" refs/original/ | xargs -n 1 git update-ref -d
echo <filepath>/ >> .gitignore
git add .gitignore
git commit -m 'Removing <filepath> from git history'
git gc
git push origin main --force

What git actually does:

The first line iterates through all references on the same tree (--tree-filter) as HEAD (your current > branch), running the command rm -rf <filepath>. This command deletes the <filepath> folder (-r, > without -rrm won’t delete folders), with no prompt given to the user (-f). The > added --prune-empty deletes useless (not changing anything) commits recursively.

The second line deletes the reference to that old branch.

The rest of the commands are relatively straightforward.

If actually running these commands, note that the first filter-branch on the directory, will take a while.

Verify that it worked correctly

You can also use this command to find all commits where the file is present.

git log --follow -- <filepath>

Once you run the filter command, this above command will return nothing.