Git Undo Commit
Yesterday I made a mistake by git pushing a bad commit to a remote repository. Without going into details of how bad that commit was (or how bad I was), I want to present the situation focusing on git and how it can be fixed.
1. What is that mistake aka what did I do wrong?
Here is the situation. I have a remote repository name
heroku I make
git commit -m "some comment" then
git push heroku master to push the change to branch master on the heroku remote repository. Of course, I realize I made a bad commit and I want to undo it. Oh no, the change was already in the remote repository. So how am I gonna fixed it?
2. How am I going to fix it?
Option 1: The first thing I can think of is to manually correct my mistake and make a new commit. This works fine but it is rather tedious as I have to go through all the file I change and correct by hand. The bad commit is still there but now harmless.
Option 2: Well if I want to undo the entire commit, then what I can do is
git revert 183adf3
It will revert the commit
183adf3 by making another commit on top of it. In other word, here is how thing looks like:
The history before revert: commit_1 --> 183adf3 The history after revert: commit_1 --> '183adf3 ---> commit_3
The state of the files after commit_3 is the same as commit_1. Just as in the previous case, the not-very-nice commit is out there but cannot do any effect to me. After the commit, I can push to the remote repository as usual.
Option 3: This is the fun part where I did learn something: Using
git reset. This command can actually help you rewrite your history so that it will be clean. Suppose I have a remote repository name heroku with branch master that already has the bad code. The HEAD (the pointer that points to the last commit in my current branch) is now pointing to commit_3
commit_1 ---> commit_2 ---> commit_3 (HEAD)
First way: If I do a
git reset --hard HEAD~1
It will become:
commit_1 ---> commit_2 (HEAD)
~1 means it moves HEAD back one commit. After the above command,
commit_3 is discarded and you will never see it again in your commit history. Now I can push to the remote repository:
git push heroku -f master.
-f is needed to force the remote repository to accept the commit. Done 🙂
Second way: If I just run
git reset HEAD~1
it won’t remove the commit_3 but move HEAD one commit back and remove the change from the index. This way is the opposite of
git add . Here is how things look like:
commit_1 ---> commit_2 (HEAD) ---> commit_3
I can now re-do the commit by running
git add . git commit -m "blablabla"
If, instead of doing it –hard, I do –soft:
git reset --soft HEAD~1
It will still undo the commit but leave the change in the index, so if I decide that I don’t want to undo the commit anymore, I redo the commit by running:
git commit -m "Oh I just repeat myself!?"
In order to push to the git repository remote, do the same as in the first way :-). Further reading on Git can be found here: http://git-scm.com/documentation