Remove files from git history

This is how I proceed to remove files from a git history, no matter if this is about large files or sensitive data. Note: This is not supposed to be reliable in removing sensitive data. There are many pitfalls in removing sensitive data from git histories, so consult a more reliable source in case it really matters.

Rewriting commits

On one machine, use a fresh cloned copy of the git repository (or use --force) to rewrite the commits. I learned that git filter-repo, the recommended tool for this task, now provides an option --sensitive-data-removal, which makes removing files from the git history really easy. Use this syntax:

git-filter-repo --sensitive-data-removal --invert-paths --path <path>

Add additional --path arguments for each file to be removed from the history. If files were renamed across the git history, make sure to add --path options for each name the file had. It will give an output like this:

Parsed 481 commits
New history written in 0.02 seconds; now repacking/cleaning...
You rewrote 480 (of 481) commits.

NOTE: First Changed Commit(s) is/are:
  <commit-hash>
NOTE: LFS object orphaning not checked (LFS not in use)

Repacking your repo and cleaning out old unneeded objects
HEAD is now at <commit-hash> <commit-description>
Enumerating objects: 1833, done.
Counting objects: 100% (1833/1833), done.
Delta compression using up to 16 threads
Compressing objects: 100% (655/655), done.
Writing objects: 100% (1833/1833), done.
Total 1833 (delta 1123), reused 1833 (delta 1123), pack-reused 0 (from 0)
Completely finished after 0.10 seconds.

NEXT STEPS FOR YOUR SENSITIVE DATA REMOVAL:
[...]

Check that the files no longer exist in the local filesystem. Take note of the commit hash provided after First Changed Commit(s) is/are:. You will need this to check whether removal was successful later.

Updating upstream

As instructed under NEXT STEPS FOR YOUR SENSITIVE DATA REMOVAL, use

git push --force --mirror origin

to update upstream after all files are removed.

Update repository copies on other machines

If deleting the repository copies on other machines and cloning from scratch is not feasible, it is possible to manually update repository copies.

Remove any tags and execute

git fetch --prune  --tags

Now git status should show how many commits are diverged between upstream and the local copy. Use

git rebase origin/main

to rebase the local branch upon the changed upstream branch. Depending upon the number of rewritten commits, this may actually take a few seconds. Use

git cat-file -t <commit-hash>

with the commit hash previously noted to verify the commit is still there. It should say commit.

Use

git reflog expire --expire=now --all
git gc --prune=now

to delete commits no longer referenced on the branch. Verify with

git cat-file -t <commit-hash>

that the commit is now gone. It should output

fatal: git cat-file: could not get object info

Sources

There is actually a good GitHub article describing sensitive data removal. This also includes an option to automatically remove sensitive strings from all files.