Developer Drain Brain

November 27, 2009

Gated Checkins Revisited

Filed under: Development — Tags: , , , — rcomian @ 4:31 pm

So I’ve had a play with gated checkins in 2010 and I have to say I’m reasonably impressed. Not massively impressed, but reasonably.

I can finally see how the implementation may actually help. It pushes a lot of the problems back to the developer in a way that’s offline, so that the problems aren’t sorted out by mashing trunk, you just have to mash your workspace instead. And mash it you may.

First and foremost, the thing that wasn’t clear to me, is that the checkin process is properly separated into 2 stages. 2 things normally happen on checkin:

  1. Your changes are collated and sent to the server.
  2. Your workspace is updated to mark your files as no-longer changed by updating the ‘base’ revisions of the files in your workspace.

This second part is basically like a get operation on your changes and is what is delayed when gated checkins are used. With gated checkins, the process is much more complex:

  1. Your changes are collated and shelved.
  2. A build job is queued against the shelveset.
  3. The shelveset is merged onto trunk.
  4. The merged result is built.
  5. The shelveset is merged with trunk again (it could have moved on whilst the build was going on) and committed.
  6. An agent on the client machine notices the commit and runs around your working copy marking files as being at the new revision. No changes appear to be made to your code during this step.

It was step 6 that was the missing part of the story for me. The obvious way to do it is just to hold open the commit, but 2010 makes it a separate job with its own monitoring process. After commit, whilst the build is going on, by default your workspace still shows all your files as having been changed. You can continue to work and it looks like your coding on top of the changes you just sent up. When the commit completes, you get the option to reconcile and all the relevant changes disappear and diffs suddenly show the changes since the commit, instead of the changes including the commit.

Obviously, since there’s more steps, there’s more opportunity for failure. Failure at any point leaves the shelveset in tact and you’re notified via the daemon that watches the build on your workstation. Failures include anything other than a truly trivial merge in steps 3 or 5, and of course, any failures you define in the build.

Things can get a little messy on failure. Your first option is to simply ignore it. If you’ve carried on working, your workspace still shows the pending changes from the commit plus the changes you’ve made since so you can just push up a larger commit next time. Your other option is to try to fix the actual problem, to do this it feels like you’d typically shelve your current changes and revert them, then unshelve the failed commit. Fix it as you normally would and commit again. At which point you can switch back to the shelveset you originally made and carry on where you left of. Do this, however, and reconciliation will fail and you’ll be left to sort out the mess manually.

The second option gets quite messy, since the code you committed has diverged from the code you’re working on. It can’t be resolved by the reconciliation process, and you need to sort it out yourself with a get latest. This leaves you to resolve the merges in the normal way. Now, your merging fixed code with unfixed code, so it’s up to you to remember where the fixes where and ensure that they get merged in properly. Good luck.

By default the commits are queued sequentially, but I can see it would work just as well by building everything in parallel as well, since any merge conflict at any point will cause a commit failure (and the related heart-strain). I still maintain that this will be a major issue if anything makes the queue length build, but I’m generally more optimistic that it could work. I did get into a bit of a mess trying to fix shelveset in some scenarios, especially when the reconciliation failed.

Essentially, you really need to excerice the 3rd option and stop work and wait for the build to complete before you carry on working. In reality, that’s what tends to happen with CI anyway. Most CI’s work in what TFS calls Rolling Builds – which means that there’s no queue, so you have to wait a maximum of 2x the build time to see if your commit is good, unlike gated checkin. Also remember that even though you’ve resolved conflicts before commit, if something was queued up before you, that may still conflict and your otherwise perfectly good change will get rejected anyway.

So keep your builds quick and your queues short and gated checkin works quite nicely.

 

Advertisements

Leave a Comment »

No comments yet.

RSS feed for comments on this post. TrackBack URI

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Create a free website or blog at WordPress.com.

%d bloggers like this: