52

git cherry-drop - Justin Aiken

 6 years ago
source link: https://justinaiken.com/2017/09/28/git-cherry-drop/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

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?
  • 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-droping them one-by-one.

Closing

I've added that alias to my dotfiles.

I'll push any future cleanups/fixes there.

Enjoy!


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK