Tuesday, November 11, 2008

Version control that scales down: Mercurial

Version control that scales down: Mercurial
 
When working on a small software project for myself, I still want version control, but I don't want the overhead of, say, TFS.
 
I decided to give Mercurial a try, and it seems to scale down very well.  Here's what I have done:
 
  1. Install TortioseHG
  2. Open a PowerShell Prompt
  3. Go to the directory that contains my source
  4. hg init # create a new "repository"
  5. hg addremove # add all files in the current directory
  6. hg revert # avoid adding files you don't want
  7. hg commit
 
A good idea is to create a .hgignore file to tell it what files you don't want to add, if there are some.  For a small C#/NUnit project, mine looks like this right now:
syntax:glob
*.suo
*.user
bin\
obj\
TestResult.xml
NUnit.VisualState.xml
 
Then, to add this file, do hg addremove, then hg commit.
 
Then, you just edit your files as needed.  When you're ready to commit, you do hg addremove, hg commit.
 
I don't have to worry about keeping my filesystem and my project in sync with my source control.  It just does it.
 
In another directory I have some PowerShell scripts.  Since I already had Mercurial installed, it was easy: hg init, hg addremove, hg commit.  Tada, it's under version control. 
 
Things I like about Mercurial:
 
  • No server setup
  • No need to decide where on the server your files should live
  • No need to "check out" a file before you can edit it - adding version control doesn't interrupt your existing workflow.
  • Works offline just as well as online
 
Mercurial has a lot more power if you want to scale up, with rich branching & merging.  You can create a branch for an experiment or a 1-off bug fix release, all offline.  That's cool, but right now that's not important for me: I really just want to track my changes.
 
The main thing I wish for, and it's pretty minor, is PowerShell cmdlets.  They're really nice to work with.  I don't expect them to appear any time soon.
 
People often look to version control software to provide backups of their source code.  I only have Mercurial on one machine right now, and standard guidance says I should put the small Mercurial server on another machine (my Windows Home Server seems like a good choice), and "push" my changes on to it regularly.  I'm not doing that, because my changes are backed up in other ways:
 
  • The directory that contains all my source code projects is in a Windows Live Mesh folder.  That means it's backed up, even the full history, unless I accidentally delete the whole thing.
  • Every night my computer is backed up to my Windows Home Server.  Even if I delete by accident, I won't lose much.
 
I'm not sure how well mesh & Mercurial will get along.  If I sit make edits on computer A, and Mesh syncs to computer B, I could commit from B, and that will get synced back to A.  That isn't what Mercurial is intended to do, but I can't think of a reason it wouldn't work.  The idea of being able to go computer hopping without having to first commit, push or pull, merge, commit each time seems attractive.
 

Backup up your pending changes (TFS)

More than once I have destroyed my data by accident. I've certainly lost more data this way than any other. Version control is great for a lot of reasons; having a backup is just one of them. But if I have changes that aren't checked in, they are at risk. When I was working with TFS for version control, I wrote this PowerShell script to back up all my changes to shelvesets. TFS has the ability to enumerate all workspaces, so it's easy: you just run it once and it will back them all up. The shelveset names begin with "ZZZ" to sort them to the end of the shelveset list. It makes sense to run this as a nightly scheduled task. The script is also interesting as an example of how to manipulate TFS from PowerShell, via the TFS APIs, instead of trying to parse textual output:
[void][System.Reflection.Assembly]::LoadWithPartialName("Microsoft.TeamFoundation.Client")
[void][System.Reflection.Assembly]::LoadWithPartialName("Microsoft.TeamFoundation.VersionControl.Client")

$localWorkspaceInfos = [Microsoft.TeamFoundation.VersionControl.Client.Workstation]::Current.GetAllLocalWorkspaceInfo() | where { $_.Computer -eq $env:COMPUTERNAME }

"Found {0} workspaces to back up" -f $localWorkspaceInfos.Count | Write-Verbose

Download:

Warning: it has been a year+ since I last ran this script, and I don't have access to TFS these days to test it. I think it works, but YMMV.