A brief summary of a (brief) talk I gave in the recent JJTV Tools Night:
In git, there are (at least) three types of reverts:
1. Casual Revert
You committed a bug, did a few commits on top on of that, and then found out the bug. To fix it, you simply
git revert <Bug's SHA1>
This creates a new commit with the reverse of the faulty commit. If needed (in case of changes in the same area), the new commit is merged with any conflicting changes.
After resolving any merge conflicts, you push out the new commit – problem solved.
2. “Secret Info” Revert
You accidentally committed & pushed something into the source repository that you never want anyone to see. This might be you cursing the boss, or, more likely, passwords to production servers that should never be in the source control (because it’s viewable by more people than you’re comfortable with).
The fix this time is rewriting history. In the simple case where your accidental commit is the last one, you simply
git reset --hard <SHA1 before the faulty commit>
Then, you’re in a special state – if you git pull, you’ll get the changes back from origin. The solution is to do
git push -f origin master:master
forcing your HEAD to overwrite origin’s master. Then, when people pull your changes, their own HEADs will be overwritten to the latest changes from master.
The case where the faulty commit is not the branch’s HEAD but rather stuck in the middle can be solved using
git rebase, and is left as an exercise to the reader.
3. Merge Revert
When you try to apply git revert on a commit that happens to be a merge point, you’ll get an error – git doesn’t have a single changeset/diff that leads to this commit, but rather two or more changes.
When reverting a merge, you will have to use the -m switch and manually choose which parent is the “correct” one to keep, and which parents are discarded. Note that sometimes the easiest way to revert a faulty merge, especially if it hasn’t been pushed, is to simply
git reset --hard to the correct point, and reattempt the merge. When using
git revert to revert a merge commit, the merge will still have happened, and any future invocations of git merge will only bring newer changes into your branch, but will not reattempt the merge.