Recovering deleted branches in Subversion

If, like me, you delete a branch in Subversion (SVN) that later on you realise you actually still need, you don’t need to panic.

In my case, I deleted a couple of feature branches I thought had been merged into the release candidate but hadn’t.  Thanks to my friend and colleague Damian, I managed to get them back without waiting for hours of checking out the parent folder full of other feature branches.  Here’s how I did it using TortoiseSVN:

  1. Perform a sparse checkout of HEAD revision of the folder that used to contain your branch(es).  I.e. for svn://svn.mycompany.com/branches/features/case4321 you should checkout svn://svn.mycompany.com/branches/features.  To make it sparse, in the Checkout Dialog you should select “Immediate children, including folders” from the Checkout Depth dropdown.
  2. Use the Revision Log to find the revision immediately before the one where you deleted the branch.  Repeat step 1, but instead of HEAD, sparse checkout that revision.  For this example let’s call it revision 1024 because that’s a nice round number.
  3. In Windows Explorer you should now have two sparse working copies for same URL but different revisions.  One will contain the deleted branch (r1024), the other will not (HEAD).
  4. Right-click and drag the folders representing the branches you want back from the r1024 working copy to the HEAD one. You’ll get a context menu, from which you should choose SVN Copy Versioned Item(s) Here.
  5. Now commit the HEAD working copy and review in the Repository Browser.  All should be well!

Thanks again to Damian for sorting this out!

Getting data from a WinForms DataGridView

Now, I know this is out-of-date tech these days, but there’s a lot of it about (indeed, I’m working on it right now), so this may be of some use.

It’s tempting when getting data from a DataGridView to get the data from the cells, like so:

if (dataGridView1.SelectedRows.Count == 0) return;
string employeeName = (string)dataGridView1.SelectedRows[0].Cells[4].Value;

However, it’s far better to work with the data that is bound to the grid instead, like so:

if (dataGridView1.SelectedRows.Count == 0) return;
CrmDataSet.EmployeeRow selectedEmployeeRow = (CrmDataSet.EmployeeRow)((DataRowView)dataGridView1.SelectedRows[0].DataBoundItem).Row;
string employeeName = selectedEmployeeRow.EmployeeName;

Now you get the benefit of refactoring tools like Resharper, and you don’t need to worry about future layout changes (like adding/removing/rearranging columns) from breaking your code.

In fact, I’ve written this up as a little extension method, since it’s fairly common.  Let me know what you think in the comments:

using System.Data;

namespace System.Windows.Forms
{
    public static class DataGridViewExtensions
    {
        public static TRow GetSelectedRow<TRow>(this DataGridView grid, int index)
            where TRow : DataRow
        {
            var selectedRow = grid.SelectedRows[index];
            var selectedTypedRow = (TRow)((DataRowView)selectedRow.DataBoundItem).Row;
            return selectedTypedRow;
        }
    }
}

You’d use it like this:

var selectedEmployee = dataGridView1.GetSelectedRow<CrmDataSet.EmployeeRow>(0);