You can't actually delete a commit. You can, however, stop using a commit. Once you do stop using a commit, Git may—or may not—eventually get around to deleting that commit, on Git's own, and you can sort of encourage Git to get around to it faster.
What exactly does this all mean? Well, you've covered the highlights in your own comment here. To stop using a commit, it has to vanish from history—but commits connect, backwards, to earlier commits, so the only way to kick a commit "off" some branch is to force the branch name to refer to some commit before the commit you want to "kick out", and that in turn kicks out all the subsequent commits.
That is, for a simple linear history, with earlier commits drawn on the left and later ones on the right, we get a picture like this:
... <-E <-F <-G <-H <-I <-J <-K <-- the-latest-commit
Commit K, where K stands in for some big ugly hash ID, is the most recent commit. Inside commit K itself, Git has stored all the files, along with some metadata saying that you (or whoever) made the commit, storing the date-and-time of when you made the commit, and so on. This metadata includes the raw hash ID of earlier commit J.
Commit J, being a commit, stores all the files and has metadata, and its metadata remembers the hash ID of still-earlier commit I. We say that K points to J and J points to I. Being a commit, I too points back, to H, which points back to G and so on.
If some large (or worthless or contains-a-password or whatever) file appears in commit H and is removed again in commit I and does not appear in J and K, and you want to kick commit H out of the repository entirely—well, you can't quite do that. But you can make the name the-latest-commit select commit G:
H--I--J--K ???
/
...--E--F--G <-- the-latest-commit
Commit H still exists, and still holds the unwanted file. Commits I-J-K likewise still exist. But no part of any existing commit can ever be changed, so we literally can't fix commit I to point backwards to commit G, even if that's what we'd like.
What we can do, instead, is copy commits I-J-K, assuming they're "good", skipping over H entirely. The result looks like this:
H--I--J--K ???
/
...--E--F--G--I'-J'-K' <-- the-latest-commit
Commits I', J', and K' are the new-and-improved versions of I-J-K. As long as commit K still exists, so will commits J and I and H, and there's no way to force them to stop existing, but the branch name only finds the new-and-improved commits, which don't include H. If no other names—branch names, tag names, and so on—allow you to find any of the hidden commits, that's when Git may eventually delete them. These commits are, in graph theory terms, unreachable, and cloning this repository won't copy them.1
The command to make Git throw them out is git gc, but when will it do that? The answer is: whenever Git thinks they're sufficiently old. But when is "sufficiently old"? That, too, is complicated:
Reflog entries act as extra references to commits, and keep them alive. Reflog entries expire, and git gc will, as one of its many sub-tasks, run git reflog expire. The lifetime entry of a reflog is configurable. The default for normal entries is either 30 or 90 days, with the number being selected based on "reachability", with this notion of reachable being different from that for commits in the commit graph in general, but as a rule of thumb, a "pseudo-deleted" commit like H in our example will fall into the 30 day category.
All objects get at least a 14-day grace period by default. This too is configurable. But 30 > 14 so the 30 day value supersedes this 14-day value.
The end result is that for booted-out commits like H, the default is likely to be 30 days: it will only live for 30 days after you either made it or last used it from a branch name or as the HEAD commit, if you manually run git gc.
If you don't run git gc yourself, Git runs git gc --auto now and then.2 Exactly when isn't documented, and git gc --auto first runs some cheap tests to decide whether git gc is a good idea. If not, it silently exits without doing anything. So until git gc thinks it's a good idea—using definitions never really described anywhere—the auto-gc doesn't really happen anyway. So "some time after 30 days after" is about all we get here.
It's also worth mentioning that some hosting sites—GitHub being a prominent case—never expire "stale, unused" commits like this. Once you've pushed a bad commit to GitHub, it stays out there until and unless you get the GitHub support folks involved. It can only be retrieved by raw hash ID, but if someone can find its hash ID, they can get it.
1There's no actual promise in Git that it won't, but in practice, it won't. Note that in graph theory we should add an answer to the question: unreachable from where? In this particular case, it means "from any labeled node", where the labels are branch and tag names and nodes are commits and annotated tag objects.
2Ideally, Git runs git gc --auto after every command that potentially makes new commits, but a very long-standing bug in Git failed to run git gc when it should have. This caused a sort of 6000-car-pileup-crash condition that made automatic git gc not work at all. This was fixed in Git 2.17, but that left a lot of repositories with Issues. I vaguely recall Git being improved to auto-fix these at some point but can't find anything in the release notes about that.
git reset. Then delete tags and branches (remote prune?branch -d,tag -d) and ultimatily rungc.git resetI would loose all subsequent commits.