35

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.

jonrsharpe
  • 115,751
  • 26
  • 228
  • 437
Bernd Strehl
  • 2,852
  • 4
  • 24
  • 43
  • 2
    possible duplicate of [Git: removing selected commit log entries for a repository](http://stackoverflow.com/questions/495345/git-removing-selected-commit-log-entries-for-a-repository) – John Szakmeister Jul 16 '13 at 10:24
  • 1
    @jszakmeister: Not exactly the same, the linked post wants to squash commits, while the OP wants here to delete them – CharlesB Jul 16 '13 at 10:28
  • 1
    @CharlesB Not entirely true. Squashing B and C was a choice, and so was removing the commits in the OP's question. The answer contains directions on both. – John Szakmeister Jul 16 '13 at 10:30

8 Answers8

54

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.

BenLanc
  • 2,344
  • 1
  • 19
  • 24
  • 2
    This is much better explained here. This should be accepted answer. – Cyril CHAPON Dec 15 '16 at 14:53
  • 1
    @CyrilCHAPON - whilst I agree that this is a good answer (to the question title), IMO it's not necessarily the right answer to the stated question (in the body). IMO @ aib's answer is the preferred one, because rebasing is destructive (rewrites history - as noted in this answer, but not highlighted enough IMO). Sometimes it's the only answer, but IMO rebase should only ever be used on a master branch as the last resort. – Jeremy Davis Nov 02 '17 at 06:13
  • Awesome, interactive rebase is indeed friend. – legel Feb 13 '23 at 06:17
13

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.

aib
  • 45,516
  • 10
  • 73
  • 79
2

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.

elhadi dp ıpɐɥןǝ
  • 4,763
  • 2
  • 30
  • 34
1

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

Community
  • 1
  • 1
mnagel
  • 6,729
  • 4
  • 31
  • 66
1

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.

Andrew Aylett
  • 39,182
  • 5
  • 68
  • 95
1

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>
Tyler S. Loeper
  • 816
  • 11
  • 22
0

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

Aminah Nuraini
  • 18,120
  • 8
  • 90
  • 108
-1
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.

elhadi dp ıpɐɥןǝ
  • 4,763
  • 2
  • 30
  • 34