tags:

views:

116

answers:

4

Assume we have a repository and 5 commits:

  • commit 1
  • commit 2
  • commit 3
  • commit 4
  • commit 5

And now I realize commits 4 and 5 are a bad idea. I want to completely remove all changes committed in commit 4 and 5. How to do it?

A: 

Possible duplicate of this.

thelost
+1  A: 

git revert commit_hash

It reverts given commit. Note that revert is another commit which discards changes from commit_hash, not removing given commit from repository.

skalee
+2  A: 

I'd probably create a new branch from commit 3.

git checkout -b commit3

and then rebase master from that commit

http://www.kernel.org/pub/software/scm/git/docs/git-rebase.html

of course, you are using topic branches to keep your dev branches separate until you know they are a good idea, right?

Jed Schneider
+2  A: 

If commits 4 and 5 are in your repository only and haven't been pushed to or pulled by any other repository you can simply:

git reset --hard SHA1_HASH_OF_COMMIT_3

You can find out the SHA1 hash of a commit by using git log or you could use more advanced naming techniques, see git help rev-parse in particular the section 'SPECIFYING REVISIONS'.

Using this command will leave commits 4 and 5 unreachable from the tip of the branch. The commits will, however, not be lost as those commits are kept in the branch's reflog. You can use git reflog to identify an unreachable commit. Restoring can then be done with another git reset --hard. This page here describes it all pretty well.

It is recommended that you run git gc on a regular basis; some commands also do this for you automatically. This essentially performs 'housekeeping' on the repository, such as "compressing file revisions (to reduce disk space and increase performance) and removing unreachable objects". Unreachable objects are pruned from the repository after (a default of) 30 days. This can be changed using the configuration option gc.reflogExpireUnreachable.

Greg Sexton
"until you run `git gc`" is misleading - it invokes itself automatically, and the user doesn't generally ever need to run it. The commit also won't be considered unreachable as long as it's in the reflogs, which take 90 days to expire. Even if you delete the branch (and with it its reflogs) the default is only to prune objects older than 30 days. Upshot: it's not going away anytime soon.
Jefromi
@Jefromi I agree, it is misleading. Apologies for a fairly rushed answer. I've updated my answer with a bit more detail.
Greg Sexton