Jan 27, 2010

How to get Git and TFS Working Together

Update: There's now a second approach for doing this that you may want to look at

TFS has a lot going for it and from a team perspective it’s a fantastic tool and something I wouldn’t pass up willingly.  That said it is a little lacking in some areas and one of those is the source control story.  For some time now I’ve been toying with writing a Git-TFS bridge but just haven’t had the time to really get stuck into it.  For that reason I decided to see if I can get Git talking to TFS via the TFS SvnBridge utility.  I know what you’re thinking and yes, it’s a 3-headed monster if ever I’ve seen one, but I’m a brave (or foolhardy) adventurer and I don’t mind the occasional challenge.

As a note I’m not going to go into a lot of detail on some of the Git commands.  This is more about how to get Git and TFS working together, not how to use Git.

Getting started

Download the SvnBridge client from http://svnbridge.codeplex.com/.  Extract the SvnBridge.exe from the zip file and run it.  It will appear in your system tray and will show you the base URL to use for your SVN commands when you mouse over it.

image

To make sure it’s all working try browsing the TFS server via TortoiseSVN (repo-browser). I found this to be a little slow, but it worked fine.  The URL I used in SVN was something like this http://localhost:8080/tfs.server.name/projectName/Trunk

Assuming that’s OK you can then create an empty folder, open a command prompt and set the new folder as your current directory. Now you can clone (i.e. copy) the TFS repository into Git using the command below (as a note I use msysgit for my git work and have the git bin folder in my path).

git svn clone http://localhost:8080/tfs.server.name/projectName/Trunk/SubFolder SubFolder

This admittedly did take quite a while to do.  It was a large source tree and the TFS server is in a remote location but even so, it’s a lot slower than just doing a full get latest from TFS.  Also, be aware that cloning a repository is making a copy of the whole repository, including history. If you just want the latest revisions and you’re not worried about history (it’s in TFS after all) then I’d recommend you use the –r option and supply a recent changeset number (or range).

I also noticed that failing to put the target folder name at the end (even when it’s the same) can result in errors like this so make sure you include it.

Invalid filesystem path syntax: REPORT request failed on '/tfs.server/!svn/vcc/default': Target path does not exist at c:\Program Files (x86)\Git/libexec/git-core/git-svn line 4567

Now go get a coffee and come back.  Once the download completes you should be able to browse your source folder and see everything is there.

We’re all set now, right?

OK, so now we have all the files from TFS locally, and because we used the SvnBridge we don’t have the annoying TFS read-only flag set on our files.  Nice.  We can start working on our project again, right?

Well not quite.  Visual Studio has this nasty “feature” where it puts source control binding information into the solution and project files.  It’s a major pain in the butt and is something you’ll have to work around if you’re in a team environment where not everyone is using this Git/Svn/TFS combo.  We’ll need to manually remove all that binding information from the solution, however we have to think of our team members.  We can’t just edit the solution file directly as other TFS users will/may be relying on it.

Also, before we make this change we’re going to do one other thing.  We’re going to create a local branch and use that as our working folder.

You can either use the Git Gui (see the branch menu) or you can do it via the command line using the git branch or git checkout –b NewBranch commands.  I’ll leave it up to you to choose the method you prefer.

So now we should have both a master and a local branch. Before we proceed just confirm that you are in the correct branch by doing a git branch command (no arguments) at the command line – the current branch should be highlighted.  If you’re using the GUI then the branch name is shown near the top.

Now, to remove the bindings open the solution file in notepad++ (or the text editor of your choice) and find the section that looks like this and simply remove it.

GlobalSection(TeamFoundationVersionControl) = preSolution
    SccNumberOfProjects = 15
    SccEnterpriseProvider = {4CA534B2-18FA-4F9D-95D4-32DDF27D184C}
    SccTeamFoundationServer = http://tfs.server:8080/
    SccLocalPath0 = .
EndGlobalSection

Save the file and then open it with Visual Studio.  When you do, you’ll be told that the source control provider can’t be installed and then presented with a choice.

image

Since you’re in your local branch you can take either option.  I prefer to choose to work uncontrolled so that visual studio doesn’t remove all the source bindings from the project files (which would break things for others on the team) and it means there’s one less thing to worry about when pushing changes back to TFS.  Regardless, once you make a choice the solution will open as expected and you can make the changes you need to.

P.S. If you haven’t already done so, you may want to create a .gitignore file to ignore those pesky artefacts that get created during development.  There’s an example of one here - http://gist.github.com/233903.  Just put it in the root of your source tree (the folder with the .git subfolder).  You may also want to commit it to your repository so you can track any changes.

Now we’re cooking! Let’s update TFS!

OK so now we’re all set.  Sweet! Go ahead and do your normal development work.  It’s OK.  You’re allowed to :-)

When you’ve made changes you can commit them to Git using either the command line or the Git Gui (which I tend to use) and do any of the other normal things you would do when using Git.

When you’re ready we can now push your changes up to the TFS server.  First we’ll want to push our local branch changes to the master branch (remember to be aware of changes in the solution file).  You may also want to do a git rebase (example) on your local branch to consolidate all your small changes into a single commit before merging to master in preparation for pushing to TFS.

The workflow is basically: git rebase (optional) –> git checkout master  –> git merge –> push to TFS

And the command to commit to TFS is simply

git svn dcommit

Git will push all your local changes to the server and if everything is OK you should be able to switch to team explorer and see the changes in there.  Nice :-)

How do I do a “Get Latest”?

I almost forgot, you will no doubt want to do a “get latest” at some point.  From the command prompt simply do this:

git svn fetch

And it will get the latest changes for you and update your local git repository.  Note that git won’t just get the latest change, it will actually get all the individual changesets from TFS so that the local Git history is up to date.  This is slightly different from TFS where the local workspace is just being brought up to the current changeset.

Pros and Cons?

So, what are the benefits and where do things fall over?

Well, obviously the biggest benefit is that you are now able to use git and work in a truly offline manner from TFS.  You can branch locally and make changes in isolation of others without messing things up for anyone other than yourself, and the speed when working locally is blindingly fast (no over the wire communication with TFS)

On the downside SvnBridge is quite slow and the process to get code in and out of TFS involves more steps than clicking a few buttons in Visual Studio. 

Also, with Git holding all the history, you’ll chew up quite a bit more disk space locally.  I know disk is cheap but in many organisations developers are forced to work with puny boxes and miniscule amounts of space so it may be an issue.

Caveat Emptor:  I haven’t done a lot of work this way as yet and there are many things I haven’t come across as yet (check in policies blocking a commit for instance) so your mileage may vary. You have been warned :-)

If you do try this, I’d be keen to hear how you get along with it.  Good luck!

8 comments:

  1. How is this approach working out for you? Have you given up on it due to the extra friction? Any updates on things you have needed to do?

    ReplyDelete
  2. I use SvnBridge with Tortiose to connect to TFS. But, it doesn't offer the second repository for branching and committing to, which sounds nice so I'm going to give it a shot.

    Mario, the things that are more difficult with this are:
    1. SvnBridge is really slow; it's mapping the svn commands across to TFS and building the history.
    2. Solutions and bindings that you create are not considered to be under source control by TFS (because of the stupid bindings put in the files). You can get around this by having a friend change the source control in the Team Explorer, or install the "standalone" Team Explorer which will immediately take over VS, then uninstall it or disable it when you're done.

    That said, it's well worth it to me. Updates / commits take a bit longer than they should, but it's not too big of a deal.

    ReplyDelete
  3. Nice article. You did not mention if it was using TFS 2008 or TFS 2010, also, what type of limitations in TFS (if 2010) version control made you think about achieving this?

    Also, was it worth giving up Check-in policies/Gated Check-ins (again if TFS 2010) for using Git especially if used in heavy check-ins and build load where build breaks cannot be afforded?

    Thanks

    ReplyDelete
  4. @anonymous Check out the follow up post (linked to at the top of this post) that shows a better way of doing this, and one that still lets you follow check in policies and gated check ins.

    As for the downsides of TFS source control - it comes down to a lack of a decent offline mode and the fact that all source control operations require communication with the central TFS server. Git usage solves both of these problems.

    ReplyDelete
  5. Thanks for pointing to the follow up post. So you used TFS 2010 or TFS 2008 for Version Control?

    As far as I know TFS 2010 solves this offline mode and slow/wan link issue with TFS Proxy Servers. Did you try that in TFS 2010? What was your experience?

    ReplyDelete
  6. TFS Proxy server (in 2008 & 2010) helps with the speed of source control over slow connections by caching everything in a local proxy. It can also help when the main TFS server is under load by farming off the source control operations to a separate box.

    It doesn't help with offline mode at all, as you still need to be able to connect to your proxy. And you still have latency with all the network calls to/from the proxy server.

    And I've used this approach with TFS2008. I haven't tried against 2010 as yet. I know that the API calls are slightly different so the new approach (in the other post) will need some slight changes. The approach outlined here should work, though I don't do it this way any more.

    ReplyDelete
  7. Do you know if it is possible to use TFS Check-in policies with Git or some other SCM tool?

    ReplyDelete
  8. @Anonymous Have a look at the second approach which uses shelve sets instead of direct updates to the source repository. It works around the problems of check in policies and makes the process somewhat easier

    ReplyDelete