Second Chances and Subversion
We all make mistakes. Wouldn’t it be great if life always gave you a second chance or an opportunity to correct those mistakes? Fortunately when you are using Subversion you can always correct a mistake, in most cases, you can correct those mistakes quite easily.
So let’s start with one mistake that Subversion does not allow you to do easily, and that is remove all traces that something ever happened. Subversion records the way your repository exists at a point in time, and that history is immutable, which means it can never be changed. Unfortunately this means that if you accidentally commit your password in a configuration file, you can edit the file and commit it again, but Subversion will forever retain that original commit, including your password. The only way to truly remove something from a repository is to dump the repository to a file, carefully remove the parts you do not want from the dump file, and then reload the repository. This is not for the faint of heart, but it can be done. It is worth pointing out that most Subversion installations use a commit hook to send email messages with the details of each commit. Even if Subversion made it easy to remove traces of something from a repository, in the case of something like a password, there is no way to undo the fact that it might have been emailed all over the world.
A common mistake that Subversion can easily fix is the recovery of something that you deleted. I hate to admit it but a few months ago I accidentally deleted the entire branches folder in the Subclipse repository. You can see the gory details of the commit in ViewVC here. Fortunately, I knew that I could easily get it back. If you looked at the previous link, you would see that I committed the deletion of the branches folder in revision 2981. So to recover the folder, all I had to do was copy it as it existed in revision 2980.
svn copy -r2980 http://subclipse.tigris.org/svn/subclipse/branches@2980
This command says, "Copy the branches folder as it existed at revision 2980 to a folder named branches (which does not currently exist)." You have to add the @2980 to the first URL to help Subversion’s history tracing algorithm find the folder. If you leave off that parameter then Subversion would look in the HEAD revision of the repository to find the folder, but we know that it does not exist any more at HEAD. You can see the results of this commit in the ViewVC history here. Notice that it shows the item was added by copying it from revision 2980.
So that is how you can recover something you deleted. What about something more subtle like changes to a set of files that was valid, but now you have decided you no longer want those changes. You essentially want to "undo the commit" that made those changes. This is actually very easy to do in Subversion, even if there have been subsequent changes made to the same file, by doing something called a "reverse merge". Essentially, you use the svn merge command with the revisions flipped around so that the merge command undoes the changes in the selected revisions. For command-line users, the process to do this is explained well in the Subversion book. See this section on undoing changes. There are also a couple of other cases covered in that same section of the book so it is worth checking out.
Subclipse and TortoiseSVN provide an easy way to do this using their graphical interface. I wrote a similar post to this one on my personal blog back in January. It includes details on doing these same things using the Subclipse GUI. Please refer to that post if you want to see how to do this using a GUI.
If there is something to take away from this post, I want it to be an increased confidence in Subversion and the safety of your data. Go ahead and make changes and commit them, that is what Subversion is for. If you make a mistake, do not worry, Subversion is always there to give you a second chance.