Важное замечание: очень нежелательно проводить такие операции, если потенциально затрагиваемые коммиты уже присутствуют в репозитории, с которым работают другие разработчики или от которого созданы форки.
Удаление файла выполняется следующей командой:
git filter-branch --tree-filter 'rm -f filename.txt' HEAD
Аналогичным образом возможно удаление целых директорий:
git filter-branch --tree-filter 'rm -rf dirname' HEAD
Git при выполнении этих команд пройдет по всей истории коммитов, один за другим изменит объекты в них и перепишет все дерево.
При желании можно указать диапазон коммитов, по которым необходимо пройтись (при этом первый коммит в диапазоне затронут не будет):
git filter-branch --tree-filter 'rm -f filename.txt' abcdef...HEAD
После завершения операции рекомендуется провести очистку от мусора:
git for-each-ref --format='delete %(refname)' refs/original | git update-ref --stdin
git reflog expire --expire=now --all
git gc --prune=now
Первая команда из этого списка удалит ссылки, которые указывают на уже несуществующие объекты. Вторая отметит всю историю всех веток как подлежающую обработке сборщиком мусора. Третья команда запускает сам сборщик.
После очистки можно отправить новую историю веток и тегов на сервер:
git push origin --force --all
git push origin --force --tags