Bernd Strehl
Bernd Strehl

Reputation: 2920

Remove earlier commit but keep recent changes

I have some commits in my repository like:

A - Added Feature A
B - Removed Feature B
C - Redesigned Feature C
D - Added Feature D
E - Added Feature D

Where E is the most recent commit I made. Now I want to get rid of the changes I made with feature C but I want to keep the changes added with D and E.

Upvotes: 39

Views: 35312

Answers (8)

Tyler S. Loeper
Tyler S. Loeper

Reputation: 836

Use git revert

By far the best solution is to use git revert. This will make a new commit that undoes the changes in a specific SHA. This is a very safe way to remove a commit, and can be easily merge with other or remote branches.

How to use Git Revert

git revert <insert bad commit hash here>

Upvotes: 2

Aminah Nuraini
Aminah Nuraini

Reputation: 19146

If you use TortoiseGit in Windows, you can right-click on the Git folder then click TortoiseGit > Show log. You can view all of the commits done before and then check the commit you'd want to revert to.

Click on the commit and you can see the changed files below. Click right on the files to be reverted and then click revert to parent revision.

How to revert commits

Upvotes: 0

elhadi dp ıpɐɥןǝ
elhadi dp ıpɐɥןǝ

Reputation: 5201

git reabse -i HEAD~3

you will have the list of your 3 last commit messages

C - Redesigned Feature C
D - Added Feature D
E - Added Feature D

you just insert x git reset HEAD^ before the commit you want to undo, you want to undo commit C, so it will be like this

    C - Redesigned Feature C
x git reset HEAD^
    D - Added Feature D
    E - Added Feature D

exit rebase console, you will see that your commit is no more in the log and their files are staged.

Upvotes: -1

aib
aib

Reputation: 46921

If you only want to "get rid of the changes" (as specified in your question body) as opposed to actually "removing a commit" (as specified in the title), an easy option is adding a new commit, doing exactly the opposite of what the earlier commit did.

It's not foolproof and it can result in conflicts due to changes done since, but it doesn't alter history, allows you to document the reversal and its reasons, and plays well with other working copies.

git revert is the tool used to make such evil twins of a set of commits.

Upvotes: 14

Andrew Aylett
Andrew Aylett

Reputation: 40690

If you only have changes locally, you're probably best off following a rebasing answer. If you've published the changes anywhere then you don't want to rebase because that will change history, meaning that everyone else will also have to rebase or you'll get your offending commit merged back in again.

If other people have your commits, the cleanest thing to do is to revert the offending change, not to excise it altogether. Use git revert COMMIT_ID to create a new commit that undoes the changes you applied in COMMIT_ID.

Upvotes: 1

BenLanc
BenLanc

Reputation: 2434

Interactive rebase is your friend!

As others have said:

$ git rebase -i HEAD~5

...where -i is the interactive flag, and HEAD~5 means include the last 5 commits in the interactive rebase.

When you get editor up as a result of issuing the above, take a look at the comment in the opened file:

# Commands:
#  p, pick = use commit
#  r, reword = use commit, but edit the commit message
#  e, edit = use commit, but stop for amending
#  s, squash = use commit, but meld into previous commit
#  f, fixup = like "squash", but discard this commit's log message
#  x, exec = run command (the rest of the line) using shell
#
# These lines can be re-ordered; they are executed from top to bottom.
#
# If you remove a line here THAT COMMIT WILL BE LOST.
#
# However, if you remove everything, the rebase will be aborted.
#
# Note that empty commits are commented out

The key bit for you is If you remove a line here THAT COMMIT WILL BE LOST.

So, delete the lines that reference the commits you want to be rid of, save and close, and git will handle the rest (you may have to fix some conflicts depending on the nature of the commit and the revert you're trying to delete).

It's important to note that if you have already pushed your code and others have pulled it, the above will not work as the commits will find their way back in there the next time someone who has your branch checked out does a push. The interactive rebase deletes the commits to the extent that there is no record of them, so the other clones do not know they have been deleted. Next time they push, they'll try and re-instate them as the local clones "see" that the origin does not have the objects (commits) that you have deleted.

Upvotes: 62

elhadi dp ıpɐɥןǝ
elhadi dp ıpɐɥןǝ

Reputation: 5201

to do that, follow these steps:

git rebase -i HEAD~3

then move commit C to be the first at the bottom, you will have

D - Added Feature D
E - Added Feature D
C - Redesigned Feature C

you save and exit, then

git reset HEAD^

this will undo commit C.

Upvotes: 2

mnagel
mnagel

Reputation: 6854

this is called rebasing: you want the -i switch.

read: https://www.atlassian.com/git/tutorial/rewriting-git-history#!rebase-i

for a similar question/answer see: https://stackoverflow.com/a/2938393/2536029

Upvotes: 1

Related Questions