650
votes

I'm not clear on how git revert works. For example, I want to revert to a commit six commits behind the head, reverting all the changes in the intermediary commits in between.

Say its SHA hash is 56e05fced214c44a37759efa2dfc25a65d8ae98d. Then why can't I just do something like:

git revert 56e05fced214c44a37759efa2dfc25a65d8ae98d
9
Even though this question is actually older than the one it's now marked as a duplicate of, that one has a better answer. meta.stackexchange.com/questions/147643/…GS - Apologise to Monica
This question and the top answer here may confuse git users. Just to help understand the terminology, you don't revert to a commit. You can either reset to a commit (which is like going back in time using time machine) or revert a commit (which is like pulling out a commit as if it never existed - however it does preserve the revert info in history, allowing you to revert a revert if you wanted to) Note also that you shouldn't use the m flag and type a commit message if you get conflicts in the process. The auto message git provides is more informative when looking back in history.alexrogers
This is very good feedback. Thanks @alexroginsJP Silvashy
@alexrogins what does pulling out a commit as if it never existed mean? Not sure what 'revert a revert' refers to either - appreciate the comment though, good info, just looking for more detail on your perspective.Joe
@Joe as in if you add a line of code then commit that line, if you were to revert it you would be undoing that line of code (wherever it was first written in history, doesn't have to be the last commit). That then makes a revert commit. If you revert that revert commit then you're essentially undoing the undo (i.e. redoing the original line again)alexrogers

9 Answers

1224
votes

If you want to commit on top of the current HEAD with the exact state at a different commit, undoing all the intermediate commits, then you can use reset to create the correct state of the index to make the commit.

# Reset the index and working tree to the desired tree
# Ensure you have no uncommitted changes that you want to keep
git reset --hard 56e05fced

# Move the branch pointer back to the previous HEAD
git reset --soft "HEAD@{1}"

git commit -m "Revert to 56e05fced"
153
votes

What git-revert does is create a commit which undoes changes made in a given commit, creating a commit which is reverse (well, reciprocal) of a given commit. Therefore

git revert <SHA-1>

should and does work.

If you want to rewind back to a specified commit, and you can do this because this part of history was not yet published, you need to use git-reset, not git-revert:

git reset --hard <SHA-1>

(Note that --hard would make you lose any non-committed changes in the working directory).

Additional Notes

By the way, perhaps it is not obvious, but everywhere where documentation says <commit> or <commit-ish> (or <object>), you can put an SHA-1 identifier (full or shortened) of commit.

90
votes

It reverts the said commit, that is, adds the commit opposite to it. If you want to checkout an earlier revision, you do:

git checkout 56e05fced214c44a37759efa2dfc25a65d8ae98d
74
votes

The best way to rollback to a specific commit is:

git reset --hard <commit-id>

Then:

git push <reponame> -f
71
votes

If your changes have already been pushed to a public, shared remote, and you want to revert all commits between HEAD and <sha-id>, then you can pass a commit range to git revert,

git revert 56e05f..HEAD

and it will revert all commits between 56e05f and HEAD (excluding the start point of the range, 56e05f).

23
votes

Updated:

This answer is simpler than my answer: https://stackoverflow.com/a/21718540/541862

Original answer:

# Create a backup of master branch
git branch backup_master

# Point master to '56e05fce' and
# make working directory the same with '56e05fce'
git reset --hard 56e05fce

# Point master back to 'backup_master' and
# leave working directory the same with '56e05fce'.
git reset --soft backup_master

# Now working directory is the same '56e05fce' and
# master points to the original revision. Then we create a commit.
git commit -a -m "Revert to 56e05fce"

# Delete unused branch
git branch -d backup_master

The two commands git reset --hard and git reset --soft are magic here. The first one changes the working directory, but it also changes head (the current branch) too. We fix the head by the second one.

4
votes

This is more understandable:

git checkout 56e05fced -- .
git add .
git commit -m 'Revert to 56e05fced'

And to prove that it worked:

git diff 56e05fced
1
votes

Should be as simple as:

git reset --hard 56e05f

That'll get you back to that specific point in time.

-2
votes

This might work:

git checkout 56e05f
echo ref: refs/heads/master > .git/HEAD
git commit