7

Uh oh... I mistakenly committed a pretty complex change (including subdirectory and files renames) without really knowing what I am doing (or what Git would be doing).

I now want to undo everything such that:

  1. commit is completely reversed (as if it has never been done, perhaps removing it from history as well)
  2. Restore current working directory (where .git is) to a certain branch (last one will do for now).

I found references to git reset --soft and git reset --hard but I have already proven to myself that I can do real damage by prematurely using a command without fully understanding it. :)

I found the git reset man page but I am still confused as to:

  1. What is HEAD?
  2. What is the difference between HEAD and * master?
  3. In my situation (see above) do I need to use --soft, --hard or other (3 more options)?
  4. Do I need to run another command (after doing git reset) to "finalize" the reversal?

UPDATE: After reading the answer below:

  1. Do I understand correctly that all I need to do in my situation is issue a single command git reset --hard HEAD^?
  2. How do I verify that reversal was performed correctly?
Community
  • 1
  • 1
WinWin
  • 7,493
  • 10
  • 44
  • 53
  • 2
    Since you are learning git, let me recommend two books to you: [git community book](http://book.git-scm.com/index.html) and [pro git](http://progit.org/book/), which are both completely online. – shelhamer Jul 08 '11 at 13:26

2 Answers2

7
  1. HEAD is the latest commit of the checked-out branch.
  2. master is a branch (the main branch, by convention) whereas HEAD is a location in history for the checked-out branch. HEAD is relative to the branch you are on.
  3. git reset --soft will leave your changes in the working tree, uncommitted for you to do whatever you like with. git reset --hard will restore the working tree to the state it was in at the commit you reset to.
  4. No other command is needed.

First, to keep the commit in case you want to inspect it later, make a branch:

git checkout -b my_bad_commit

(or alternatively do git branch my_bad_commit as mentioned in larsman's comment.)

Then return to master or whatever branch you were on and reset:

git checkout branch_with_bad_commit
git reset --hard HEAD^

HEAD^ translates to "the parent of HEAD," which you can even stack for HEAD^^ = 2 commits back. For more on this topic, check the git community book chapter on undo in git

shelhamer
  • 29,752
  • 2
  • 30
  • 33
  • 1
    The `checkout -b; checkout` sequence can be done using a single `branch` command. – Fred Foo Jul 08 '11 at 13:27
  • Good point to mention that. I have so many aliases I just do `git cob new_branch_name` that I forget the real ones sometimes. – shelhamer Jul 08 '11 at 13:28
  • @Shelhamer Performing both `git checkout master` **and** `git reset --hard HEAD^` took me **two** commits back. This is not what I wanted. I only needed to go one backward. Something must have not been clear in my question. – WinWin Jul 08 '11 at 17:02
  • 1
    @WinWin, there may have been some miscommunication if your master branch did not contain the bad commit (which is why I said "...or whatever branch you were on," meaning to checkout that branch. If you have lost a bit of history you need back, use `git reflog` to recover it. It will list previous `HEAD`s which you can checkout or reset. – shelhamer Jul 08 '11 at 17:15
  • @Shelhamer Thanks for the `git reflog` tip. The links to the books are invaluable. It will take me time to gobble them though. I am still unsure why `git reset --hard HEAD^` alone won't suffice (as I don't really want to keep the commit. That's the point). – WinWin Jul 08 '11 at 17:50
  • @WinWin, in your question you mentioned wanting the option of keeping the commit somewhere (perhaps removing it history or not). If you truly don't care about the commit, you can just do `git reset --hard HEAD^` on the branch with the bad commit to point HEAD at the commit before the bad one, as if the bad one never existed. – shelhamer Jul 08 '11 at 18:26
1
  1. HEAD is the tip of the current branch.
  2. The difference between HEAD and master is that HEAD changes when you checkout a branch (or commit).
  3. --soft will leave the changes around, so you can re-add/commit them or undo them by doing git checkout on the changed files. --hard will reset the working area to the state of the commit you are resetting to.
  4. Not if you reset --hard. You might have to git push --force to remote repos (although, if the changes you made are already on a remote, rewriting history is strongly discouraged).
Community
  • 1
  • 1
Fred Foo
  • 355,277
  • 75
  • 744
  • 836
  • Thanks +1. Fortunately, I haven't pushed anything yet. So, `git reset --hard HEAD^` alone do the trick for me? – WinWin Jul 08 '11 at 13:20
  • 2
    If you want to undo only the last commit, yes. To be on the safe side, you can also do `git branch mistake` before the `git reset --hard`; if anything goes wrong, you can then `git merge mistake` to get the mistaken commit back. – Fred Foo Jul 08 '11 at 13:23
  • OMG after using CVS for so many years, I feel like a total rookie in this world of git. :) – WinWin Jul 08 '11 at 13:24
  • Oddly, I could never wrap my head around CVS or SVN, but switching to Git felt like coming home ;) – Fred Foo Jul 08 '11 at 13:25