This post outlines how to re-create a subversion repository after a total failure or loss (disk overwritten, disk crash, accidentally deleted, etc) when you have no repository backups and only developers’ working copies. If you’ve lost your SVN server and have no backups of your repository, and you don’t want to do manual per-file copying from the old working copy to a new working copy, this is your only option – you have no other choice.

Background:

At my current client’s site, we were using a makeshift Subversion repository (one of the best RCSs available) to overcome problems with Clear Case, aka THE WORST REVISION CONTROL SYSTEM EVER. God how I despise Clear Case, that eternally flawed disgusting dung substitute attempting to be an RCS. Just to be clear, in case you might have misunderstood me, I’ll restate: Subversion is amazing, Clear Case only wishes to approach the beneficial status of say, fungus on the wall of an abandoned Vietcong prison.

Anyway, we set up Subversion to use as our primary repository, but unfortunately, didn’t set up a nightly backup process to a different machine. That bastard Murphy struck: after only 2 weeks of using this box, the hard drive failed and we lost the repository in its entirety. Lesson learned – always always backup your SVN repo to another machine nightly. Continuing on…

Naturally the developers on the team all had our local working copies, so we still had all of our code and nothing was permanently lost. Now if the original problem were a mere disk failure and no one had changed their working copies since the last SVN update, this would be an easy problem to solve: just create a new SVN repository, import only one of the working copies, and everyone then does a fresh checkout of the new repository and continues on their merry way.

But as Murphy would have it of course, we all had modified our local working copies for about a day and a half after the hard drive crash. We couldn’t just kill productivity until the new one was rebuilt over the next two days. So we kept working and subsequently our working copies became out of sync with each other.

Solution (nearly identical to this email thread, but elaborated):

When the new Subversion server was back online, I performed an svn export of my existing local working copy, which produced a ‘clean’ directory tree. I then svn imported it into a brand new repository on the new Subversion server, creating version 1. At this point it is worth mentioning that my existing working copy before export was at version 395. After importing the clean ‘exported’ tree, the new repo will start with version 1. Forget about trying to recover revision history from your existing working copy after a total repo loss – its not possible – versioned changes related to the old repo are lost forever.

So although we had to start over at version 1 again (not as ideal), at least we had a proper repository again with no significant code loss.

But what about the other developers who had made changes the last two days? They need to get their changes into the new repository.

You CANNOT do this with say an ‘svn merge’ or ‘svn switch’ (even with –relocate – it won’t work). If you tried to even get the log from within a working copy from the old repository, you’d see something like this:

> svn log
svn: No such revision 396

So, how do you do a proper merge of your old-repository-but-latest-code-working-copy into the newly-checked-out-working-copy?

The only way is old-school diff and patch programs. Trust me, there is not another way, I researched for hours so you don’t have to. Anyway, here’s how to do it. Each developer had to run the following steps:

If you’re running Windows, you can still execute the following steps, but you’ll have to download and install GNU DiffUtils and Patch for Windows:

  1. Download and install GNU’s Windows DiffUtils
  2. Download and install GNU’s Windows Patch
  3. After you run both setup programs, they will be installed into C:\Program Files\GnuWin32\bin. Open up Start > Control Panel > System > (Advanced Tab) > Environment Variables. Add this directory to the front of your %PATH% environment variable. This will allow you to call diff and patch on the command line.

Ok, now for *nix users and Windows users who have completed the above 3 steps:

  1. Check out a new working copy of the brand new SVN repository to a directory different than your current working copy.

    For example, on my machine, my ‘old’ failed-repo-working-copy is in ~/projects/projectName-old/trunk. My new checkout was made to ~/projects/projectName-new/trunk.

  2. svn export the failed-repo-working-copy to a temp dir. When this was completed, I had the following directory:

    ~/projects/projectName-old-export/trunk

  3. svn export the new working copy that you just checked out a second ago. When I was done I had a directory:

    ~/projects/projectName-new-export/trunk

  4. cd to your new working copy (e.g. ~/projects/projectName-new/trunk) and diff and patch this working copy:
    > cd new_WC_dir
    > diff -ru new_WC_export_dir old_WC_export_dir | patch –p0

    For example, this is what I did:

    > cd ~/projects/projectName-new/trunk
    > diff –ru ~/projects/projectName-new-export/trunk ~/projects/projectName-old-export/trunk | patch -p0

    When this command was finished, I had a bunch of lines printed to the console patching file …

  5. Commit your new working copy back to the new subversion server. This is just a normal commit at the root of the new working copy e.g.
    > cd ~/projects/projectName-new/trunk
    > svn ci -m "Committing out-of-sync work resulting from hard drive crash"

    You can then check-out/commit as normal from this point onwards.

    I strongly recommend deleting all the other directories and renaming the existing ‘new’ directory to just the project name to avoid confusion moving forward:

    e.g.

    > cd ~/projects
    > mv projectName-new projectName
    > rm -rf projectName-new-export projectName-old-export projectName-old

    Cheers,

    Les