One of my current responsibilities is to merge a branch within Subversion to the main code line (trunk). Usually, this doesn't require a lot of effort in order to complete. For this merge, since there were relatively few changes, I decided to perform the merge using the command line.
I specified my range of revisions that I would like merged down to the trunk, resolved all of the conflicts, and then committed the merge to Subversion. Later, I realized that I did not specify the correct range of revisions, and therefore, the merge was incomplete. I was just about to revert my changes in the Subversion repository, when I realized that there had been some commits done to the trunk after my merge. Doh!!!
Why is this such a problem? Well, it is a problem because if I was to roll back the Subversion repository to the point right before the incomplete merge that I performed, then I would also be removing the commits of my teammates. That would not make me too popular amongst my co-workers.
At this point, what could I do? One option would be to take the commit that occurred after my incomplete merge and save it off somehow using a patch tool, then roll back the subversion repository, then reapply those changes. Another option would be to figure out all of the changes that I made as part of my incomplete merge, and roll each file back one by one to the previous version. Both of these options sounded horrible and time consuming. Luckily, I could use Git in order to solve this problem.
Git Revert to the Rescue
Git has a great feature called revert. In a nutshell, the revert feature of Git allows you to specify any commit, create a reverse-patch for that commit, and commit it to the repository using one command. In other words, it backs out the changes of a commit. For example, let's say that your repository has the following 4 commits:
You realize that there is a bug in the commit titled 'B', and you would like to roll the code back. You can do that using Git by typing
git revert B
which would change your repository to:
The commit titled 'E', is actually a reversal of the commit B.
Needless to say, this little trick saved me a lot of time and effort. All I did was revert the merge commit, and attempted the merge again, this time making sure that I specified the correct range of revisions. For this little feature alone, I am grateful that I am using git.