Apr 3, 2010

Git & TFS Working Together – Version 2

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 git tfs workflowis 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.

Getting Started

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.

Clone TFS

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.

Fetching Updates

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

image

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:

image

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.

 

Kudos to Matt Burke (@spraints) for the great work in getting this together.  It’s a great solution!

17 comments:

  1. Is there a good place to ask questions about using the git-tfs project?

    ReplyDelete
  2. @Frank Go to http://github.com/spraints/git-tfs/issues and create an issue there (or on my branch). Alternatively ask @spraints via Twitter.

    ReplyDelete
  3. Why aren't you using rebase? It's better than merge, and it's easier to keep track of changes and commits.
    (See git-svn workflow)

    ReplyDelete
  4. @Bogdan Because I'm still a git n00b, and rebase is one of those things I keep forgetting (old habits die hard)

    ReplyDelete
  5. basically you do it like this:
    Assume that tfs remote is tfs/default

    git tfs fetch
    git checkout master
    git rebase tfs/default
    git checkout otherbranch
    git rebase master

    this will keep the history intact and linear

    ReplyDelete
  6. I am trying to use your fork of git-tfs and I am struggling to connect to our server (TFS 2010). Here is the screenshot of the connection dialog in VS: http://izevaka.posterous.com/tfs-dialog

    I tried "git tfs clone http://qf-au-vmptap3:8080 $/ GlobalPlatformTFS" and "git tfs clone http://qf-au-vmptap3:8080/tfs $/ GlobalPlatformTFS" to no avail. Also I couldn't work out how to connect to different project collections.

    Another thing is that I don't get "--username" option when I run "git tfs help clone". Is it possible that somehow I am building non-TFS2010 enabled version?

    ReplyDelete
  7. Oh and here is the error:

    System.Exception: Unable to locate git-tfs remote with id = default ---> Microso
    ft.TeamFoundation.TeamFoundationServiceUnavailableException: TF31002: Unable to
    connect to this Team Foundation Server: http://qf-au-vmptap3:8080/.
    Team Foundation Server Url: http://qf-au-vmptap3:8080/.

    Possible reasons for failure include:
    - The name, port number, or protocol for the Team Foundation Server is incorrect
    .
    - The Team Foundation Server is offline.
    - The password has expired or is incorrect.

    Technical information (for administrator):
    The request failed with HTTP status 404: Not Found. ---> System.Net.WebException
    : The request failed with HTTP status 404: Not Found.

    ReplyDelete
  8. Sorry to spam, just realised i posted without my email so i don't get notified of new replies.

    ReplyDelete
  9. @Igor To connect to a TFS2010 box try using http://qf-au-vmptap3:8080/tfs/TheCollectionName and use $/YourProjectName for the path to clone.

    ReplyDelete
  10. Thanks Richard, i finally figured it out - the collection name had spaces in it so they had to be url encoded. For the above TFS settings the URL I used was http://server:8080/tfs/global%20platform

    ReplyDelete
  11. forgive my ignorance, Richard: where to get your fork? Or has it been included in Matt's recent release (0.9.2)?

    ReplyDelete
  12. @anonymous Matt pulled the relevant changes into his version. His v0.9.2 release should be all you need.

    ReplyDelete
  13. In order to build the project from the spraints repository in VS2010, you need to have `git.exe` in your Windows PATH environment variable, otherwise the build will completely fail.

    ReplyDelete
  14. Is it possible to use git-tfs on linux?

    ReplyDelete
  15. @x3msk8er I haven't tried but it's unlikley to work as-is. If you have Team Explorer Everywhere installed then it may be possible however it would probably require some rework of git-tfs to work with TEE instead of the windows Team Explorer API, plus you'd need to have mono installed since git-tfs is a .NET app.

    ReplyDelete
  16. Where can I find your fork with --username option? I need binary.

    ReplyDelete
  17. @x3msk8er: two choices, I think:

    - install git-tfs on the TFS machine, run a scheduled job to sync things, then serve a git repository on the Windows machine and possibly clone it (and actually use it there!) on a real server (i.e., Non-Windows). Then push your changes to that git repository (or to the sole Windows git repo), then commit those git repo changes to the TFS upstream (either manually from time to time, or possibly even automated). Haven't tried this setup myself yet, but it might just work, and it provides the very obvious git workflow advantages.

    - git-tfs AFAIK is being worked on to be usable on Mac / Linux (requires Mono). If one's soul can live with the Mono tainting of libre platforms, then this is a good shortcut for direct git / tfs interfacing. HOWEVER, performance is surely going to be a lot worse than git-tfs syncing on the TFS machine directly (I know that request latency with a network involved is a large problem in the unrelated case of using a client-side SvnBridge to a TFS machine).

    ReplyDelete