Usually when I need to delete a commit from a local git repo I use:

This starts an interactive rebase session for all commits from HEAD..@{u}. Once I’m in the git rebase editor I put a drop on the line that has the commit I want to delete and save the file. Magic. Commit gone.

This is fine if you’re there to drive an editor for an interactive rebase.

The problem with interactivity

The problem with interactive rebase is you can’t easily script it.

At work I help to maintain our “beta cluster” which is a bunch of virtual machines that is supposed to mirror the setup of production. The extent to which production is actually mirrored is debatable; however, it is true that we use the same puppet repository as production. Further, this puppet repository resides on a virtual machine within the cluster that acts as the beta cluster’s puppetmaster.

Often, to test a patch for production puppet, folks will apply patches on top of beta’s local copy of the production puppet repo.

The problem here is that a lot of these commits are old and busted.

It’d be nice to have a script that periodically cleans up these patches based on some criteria. This script would have to potentially be able to remove, say, 59b7377 while leaving all the others in-tact, and it would have to do so without any access to git rebase -i or any user input.

Non-interactive commit deletion

The way to do this is with git rebase --onto.

Selective quoting of man git-rebase

The commits we want are all the commits surrounding 59b7377 without 59b7377.

So we really want to take the commits 59b7377..HEAD and rebase them onto the commit before 59b7377 (which is 59b7377^)

Tada! Commit gone.