UPDATE: Recent changes mean that the shelveset approach to checking in changes is no longer required. See Git-TFS Recent Improvements for more information
I posted a while ago on how to get Git and TFS version control working together, however there are some limitations with that approach that reduces it’s usefulness for some people, specifically that checking in doesn’t deal with check-in policies or being able to associate work items with a changeset.
Well, recently on the Australian Alt.Net mailing list the discussion came up again in reference to getting Mercurial working with TFS, and during the conversation we were pointed to the git-tfs project which I was unaware of before then. Curiosity appropriately piqued, I went and grabbed the code to see how it worked, and I’m pleased to say that the approach is much better that the previous approach I blogged about, though the issues with solution files still exist, though it’s somewhat alleviated with this approach.
What is This git-tfs Thingy Anyway?
OK, introduction time, the git-tfs project is a git plug-in, much like git-svn, and it defines some git commands that let git work against TFS source control. The nice thing about the approach it takes is that instead of trying to commit directly to TFS and having to deal with check in policies and all that jazz it creates a shelveset instead. You can then switch to Team Explorer and do an unshelve and check in using the normal TFS practices. The normal development workflow follows the path shown in the diagram on the left.
First up, you’ll need a version of git installed. I’ve tested using msysgit and it works well, so grab a copy of that if you haven’t already. Then either download git-tfs or go grab yourself a copy of the source either from Matt Burke’s (@spraints) repository or from my own fork. My fork includes changes to make it work with TFS2010 and alternate user accounts, and hopefully Matt will take those onboard for his next release.
Remember, if you download the source you’ll need the Visual Studio SDK in order to build it.
Also you’ll need to add the folder where the compiled output to your path, so that git knows where to look for the “git tfs” commands you are going to use.
You should now be able to get the source from TFS via git using the “git tfs clone” command, as shown here
git tfs clone http://tfs2008-vm:8080 $/TeamProject0 local_git_folder
Just pass in the source control folder you want to clone and the local folder you want the repository created in and wait for the code to download. If you need to supply non-default credentials as I do when working with my virtual machines, then you’ll need to supply the –username option, for example:
git tfs clone --username tfs2008-vm\tfssetup http://tfs2008-vm:8080 $/TeamProject0 local_git_folder
Note that the –username option only works if you grab my fork (at least until the changes are merged back into spraints version). When you use that option you’ll be prompted with the usual TFS credentials dialog box so you can enter your password every time you do a git tfs command.
Oh! Be aware that the folder you check out your git source to should be different than the folder used for your normal TFS workspace controlled work.
Yes, this means you’ll have 2 copies of the source. One workspace/tfs controlled copy and one git controlled copy.
What About Those Solution Files?
Yes, I know, those pesky solution files with their inbuilt source control links that force you to connect to TFS when you open the solution. They’re enough to drive a person to drink!
So, here’s the easy way to deal with it. After cloning your repository, pull out the network cable from your PC or turn off wireless and then open the solution. When prompted to go into offline mode, simply say “Yes! Of course I want to go offline you great lump!" and watch the solution open normally. You can then plug your network cable back in and carry on as if nothing had ever happened. Visual Studio will keep the solution in offline mode until such time as you tell it otherwise, and considering we’re using git for source control, that means we never will.
Option Two? Create a local branch of your code and remove the source control bindings from the solution in your local branch. It’s a little more work, and you’ll have some more merging to do between your master and local branches, but it is just that tiny bit safer.
The choice is up to you, though I’d probably lean towards the first option for now.
Shelve Your Changes
OK, so now go make some changes in your git version of the code and commit them to the repository. Once you’ve finished we can think about pushing them up to the TFS server.
The way this works is that all local changes you make are aggregated into a shelveset and placed on the server. This way you don’t need to worry about rewriting local history or having multiple shelvesets on the server that you would have to process in chronological order.
Push your changes using “git tfs shelve” as follows:
git tfs shelve "my shelveset name"
Now switch to the TFS controlled version of the project, go to the pending changes window and Unshelve your newly created shelveset. Check that everything is OK and do your normal TFS check in, with all the normal policies and association with work items applied that you need to.
Nice! OK, so now we have our local changes in TFS. What about the reverse? What if we now want to get updates from TFS down to update our local git repository?
All we need to do is a “git tfs fetch”. When we do, git-tfs will go off and grab the latest changesets from the server and bring them down as tagged objects. They won’t get directly applied to the master copy, so it’s up to you to bring those changesets in yourself.
This is where you need to do a local “git merge” to take those tagged objects and merge them into your working copy. You can do this via the command line or using the Git Gui as shown here
Once the merge is done you should be able to see all the changes from TFS, and visualise it using the git gui tools, for example:
And that’s it, we have a workable approach to using git with TFS. Obviously there’s room for improvement with the possibility of committing directly to TFS, but for now this approach works well and I think it’s much better than the svn-bridge based approach I was using earlier.