A simple way to drop a commit

Today at work, a coworker asked me over Slack how to delete a commit:

So I need to exclude a previous commit



Do I git cherry-pick and then the commit string?



and then the commit string? So git cherry-drop abc123



Something like that?



Telling him that git cherry-drop doesn't exist, I walked him through how to drop the commit with git rebase -i . But it got me thinking... why not have a git cherry-drop command? A single command is always nicer than going through the whole interactive process.

I use git inject a lot in my workflow, so I thought I'd copy a bit of logic from that to create the cherry-drop alias. As I got going, I realized there was enough code that it was probably cleaner to split it out into a function in ~/.githelpers , and have the alias load that.

After reviewing the --onto option which I rarely use (Pivotal had a very helpful guide), here's what I ended up with:

Added to ~/.githelpers:

cherry_drop () { set -e REF_TO_DROP = ` git show $1 --pretty = format:%H -q ` HEAD = ` git show HEAD --pretty = format:%H -q ` shift # Stash changes if they exist if ! git diff-index --quiet HEAD --; then git stash && DIRTY = 1 fi if [[ $REF_TO_DROP == $HEAD ]] ; then # Easy way to undo the last commit: git reset --hard HEAD else # Rebase the commit out: git rebase --keep-empty --onto $REF_TO_DROP ~1 $REF_TO_DROP fi # Unstash changes if they were stashed: [ -n " $DIRTY " ] && git stash pop # Great success: exit 0 }

The alias:

[ alias ] .. cherry-drop = "!. ~/.githelpers && cherry_drop"

In action

Say you're on a branch called foo , and your history looks like this:

$ git log --graph --abbrev-commit --pretty = format: '%h - %d %s' -n4 * 5b5fa7ecf0 - ( HEAD -> foo ) Great commit * 205cf5cf76 - Accidentally commit 1,000 node_modules * 01f02a3d6a - Another good commit * 0f0c83af7e - Good commit

To remove 205cf5cf76 , it's a single command:

$ git cherry-drop 205cf5cf76 First, rewinding head to replay your work on top of it... [ detached HEAD 4e798f3011] Great commit Date: Thu Sep 28 16:54:51 2017 -0600 $ git log --graph --abbrev-commit --pretty = format: '%h - %d %s' -n4 * 4e798f3011 - ( HEAD -> foo ) Great commit * 01f02a3d6a - Another good commit * 0f0c83af7e - Good commit * 077f18f7b3 - Some old Change

Warning

cherry-pick should work to slice out simple commits that don't touch anything else, but...

- If you want to remove a commit that other commits depend on, you'll probably want to avoid this alias and rebase it the usual way.

- If you want to remove multiple commits, it's probably also better to rebase them all out in one go instead of cherry-drop ing them one-by-one.

Closing

I've added that alias to my dotfiles.

I'll push any future cleanups/fixes there.

Enjoy!