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

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.

Mark Phippard

Engineering manager for several teams at CollabNet, including CloudForge, Subversion, Subversion Edge, Git and our Desktops and Integrations. Project owner for the Subclipse project, which provides Subversion support in Eclipse. Also a full committer for the Subversion project. Product owner for GitEye, Subversion Edge and the CollabNet Desktops and Integrations.

Tagged with: , , , , , , , , ,
Posted in Subversion
10 comments on “Second Chances and Subversion
  1. sb says:

    svn only allows you to go back in time if you know how to access the old revision. And @ is probably the least discoverable feature of subversion. How on earth is the user supposed to know that -rB won’t work but @B will? I have a friend who failed to figure this out and just gave up trying to recover his old files… Not sure he’ll ever trust svn again, even now that I’ve explained the arbitrary difference between @ and -r. This comes up once a month on IRC too. It’s not an uncommon problem.
    So, while you may feel comfortable that you can recover anything at any time, I’m not sure everyone shares that opinion. Any chance this will fixed? Just need to make -rN work the way everyone would expect.

  2. Thanks for taking the time to comment. I disagree with you that this need to be fixed. The @REV syntax was actually added after Subversion 1.0, I believe in the 1.1 or 1.2 timeframe. It is referred to as the “peg revision”. It is a very necessary concept to remove ambiguity from the process. Unfortunately, since it came after the 1.0 release, it is not mentioned at all in the original Subversion book that a lot of people refer to. The book is going to be re-printed soon, and the current text does a good job explaining why peg revisions are needed. See:
    Finally, I lied a bit in this post. The svn copy command as of the 1.4 release still does not require the peg revision. So the command I listed in the post actually works fine without the @2980. However, this has been fixed for the next release, and with 1.5 the command would not work unless you added the peg revision.

  3. Toby says:

    sb, to use reverse merge (which *is* well described in the online book) you don’t need to use ‘@’ syntax anyway. Mark was just showing off šŸ™‚

  4. Daniel Luna says:

    “So to recover the folder, all I had to do was copy it as it existed in revision 2980.”
    This is not strictly true. The new “branches” folder behaves differently when using the –stop-on-copy flag.

  5. How is it not true? I never said that the repository has not been changed by the fact that you did these actions. The point is that your content has been recovered.

  6. John says:

    I did have the same problem but now is fine, working like a charm.

  7. Victor Odusote says:

    You said, “Fortunately when you are using Subversion you can always correct a mistake”. Can I test the validity of this statement?
    You add a directory using svn add mydir
    You did not put the -N so it adds recursively. This is not what you wanted.
    Then you do svn –force remove mydir and this is only supposed to remove the files and directory from version control. You now look for your private copy of the directory and the files under it, alas they are gone, ZAPPED by subversion. Can you please tell how these files can be recovered since they never even made it as committed items.

  8. I think it is pretty clear that my blog post was referring to changes made to the repository. There are plenty of scenarios where you can lose work that has not been committed. For example, you can make a bunch of changes in your working copy and then accidentally revert those changes. Subversion tries to always protect your unversioned data and is very careful about losing your data.
    If there is a feature that you think ought to behave differently in Subversion, then the proper channel to build support for your request is the mailing list.

  9. Victor says:

    Reverting to an older revision is your choice and although it’s regretable, at least you know you made a mistake. Subversion zapping your private copy from your private folder is something else, especially when it doesn’t have it in the repository to restore. Yes I should be visiting the mailing list.

  10. AJ Lewis says:

    What I want to know is how this was handled by ‘svn merge’ for anyone that had created a branch that included the removed directory, and then subsequently modified contents of that directory. Based on a similar situation at my work (with svn 1.5) anyone that then merges will get their changes overwritten by the “new” copied in directory. The scenario we ran into was slightly differently, in that it was a file that needed to be copied in, but any branch based on the branch that got the file copied into it, now gets the file clobbered on merge.
    Any suggestions?

Leave a Reply

Your email address will not be published. Required fields are marked *