Reputation: 71961
On a local repo, I've just executed git cherry-pick SHA
without any conflicts or problems. I then realized I didn't want to do what I just did. I have not pushed this anywhere.
How can I remove just this cherry pick?
I'd like to know if there's a way to do this:
Preferably with one command for both cases if possible.
Upvotes: 197
Views: 348440
Reputation: 4870
I just did 3 git cherry-pick
s. To keep my first 2 cherry picks but delete my 3rd, the simplest answer is git cherry-pick --abort
Upvotes: 1
Reputation: 142004
git reflog
can come to your rescue.
Type it in your console and you will get a list of your git history along with SHA-1 representing them.
Simply checkout any SHA-1 that you wish to revert to
Before answering let's add some background, explaining what is this HEAD
.
First of all what is HEAD?
HEAD
is simply a reference to the current commit (latest) on the current branch.
There can only be a single HEAD
at any given time. (excluding git worktree
)
The content of HEAD
is stored inside .git/HEAD
and it contains the 40 bytes SHA-1 of the current commit.
detached HEAD
If you are not on the latest commit - meaning that HEAD
is pointing to a prior commit in history its called detached HEAD
.
On the command line, it will look like this- SHA-1 instead of the branch name since the HEAD
is not pointing to the tip of the current branch
git checkout
git checkout <commit_id>
git checkout -b <new branch> <commit_id>
git checkout HEAD~X // x is the number of commits t go back
This will checkout new branch pointing to the desired commit.
This command will checkout to a given commit.
At this point, you can create a branch and start to work from this point on.
# Checkout a given commit.
# Doing so will result in a `detached HEAD` which mean that the `HEAD`
# is not pointing to the latest so you will need to checkout branch
# in order to be able to update the code.
git checkout <commit-id>
# create a new branch forked to the given commit
git checkout -b <branch name>
git reflog
You can always use the reflog
as well.
git reflog
will display any change which updated the HEAD
and checking out the desired reflog entry will set the HEAD
back to this commit.
Every time the HEAD is modified there will be a new entry in the reflog
git reflog
git checkout HEAD@{...}
This will get you back to your desired commit
git reset --hard <commit_id>
"Move" your HEAD back to the desired commit.
# This will destroy any local modifications.
# Don't do it if you have uncommitted work you want to keep.
git reset --hard 0d1d7fc32
# Alternatively, if there's work to keep:
git stash
git reset --hard 0d1d7fc32
git stash pop
# This saves the modifications, then reapplies that patch after resetting.
# You could get merge conflicts if you've modified things which were
# changed since the commit you reset to.
git rebase --no-autostash
as well.git revert <sha-1>
"Undo" the given commit or commit range.
The reset command will "undo" any changes made in the given commit.
A new commit with the undo patch will be committed while the original commit will remain in the history as well.
# add new commit with the undo of the original one.
# the <sha-1> can be any commit(s) or commit range
git revert <sha-1>
This schema illustrates which command does what.
As you can see there reset && checkout
modify the HEAD
.
Upvotes: 28
Reputation: 864
Faced with this same problem, I discovered if you have committed and/or pushed to remote since your successful cherry-pick, and you want to remove it, you can find the cherry-pick's SHA by running:
git log --graph --decorate --oneline
Then, (after using :wq
to exit the log) you can remove the cherry-pick using
git rebase -p --onto YOUR_SHA_HERE^ YOUR_SHA_HERE
where YOUR_SHA_HERE
equals the cherry-picked commit's 40- or abbreviated 7-character SHA.
At first, you won't be able to push your changes because your remote repo and your local repo will have different commit histories. You can force your local commits to replace what's on your remote by using
git push --force origin YOUR_REPO_NAME
(I adapted this solution from Seth Robertson: See "Removing an entire commit.")
Upvotes: 6
Reputation: 3929
If possible, avoid hard resets. Hard resets are one of the very few destructive operations in git. Luckily, you can undo a cherry-pick without resets and avoid anything destructive.
Note the hash of the cherry-pick you want to undo, say it is ${bad_cherrypick}
. Do a git revert ${bad_cherrypick}
. Now the contents of your working tree are as they were before your bad cherry-pick.
Repeat your git cherry-pick ${wanted_commit}
, and when you're happy with the new cherry-pick, do a git rebase -i ${bad_cherrypick}~1
. During the rebase, delete both ${bad_cherrypick}
and its corresponding revert.
The branch you are working on will only have the good cherry-pick. No resets needed!
Upvotes: 23
Reputation: 19025
To undo your last commit, simply do git reset --hard HEAD~
.
Edit: this answer applied to an earlier version of the question that did not mention preserving local changes; the accepted answer from Tim is indeed the correct one. Thanks to qwertzguy for the heads up.
Upvotes: 51
Reputation: 17707
One command and does not use the destructive git reset
command:
GIT_SEQUENCE_EDITOR="sed -i 's/pick/d/'" git rebase -i HEAD~ --autostash
It simply drops the commit, putting you back exactly in the state before the cherry-pick even if you had local changes.
Upvotes: 3
Reputation: 43314
A cherry-pick is basically a commit, so if you want to undo it, you just undo the commit.
when I have other local changes
Stash your current changes so you can reapply them after resetting the commit.
$ git stash
$ git reset --hard HEAD^
$ git stash pop # or `git stash apply`, if you want to keep the changeset in the stash
when I have no other local changes
$ git reset --hard HEAD^
Upvotes: 283