Git with Visual Studio 2015 and TFS 2015

Posted by Graham Smith on September 8, 20154 Comments (click here to comment)

If you work in an organisation that has a longstanding investment in TFS chances are that you haven't done much with Git. This is because when you create a new team project in TFS you have to choose the version control system you want to use and once chosen that's it -- no changing your mind. (This was correct when I first started writing this post but things are changing as I mention later.) If your projects were created a few years ago either Git wasn't an option back then since it only became available in early 2013 or you may have thought it was just too new and shiny to consider for use with TFS, and very likely these projects use Team Foundation Version Control (TFVC).

That has all changed now and Git is firmly embedded in TFS. In fact Git seems to be firmly embedded everywhere, not least at Microsoft where open source projects are being hosted on GitHub and internal teams are using Git via Visual Studio and TFS. Keen to understand what all the fuss is about I've been learning about and using Git over the past few months and the recent release of Visual Studio 2015 and TFS 2015 seemed like a good time to share some of my experiences. As always when learning something new I recommend taking some time to do some training and to that end I have a Getting Started blog post here where I've compiled what I think are the most useful resources for Visual Studio developers.

The Bigger Picture

Before getting in to the tooling I want to take a step back and say a few words about the big picture because if you want to start using Git and already have a team project based on TFVC you have some thinking to do. When I first started writing this post moving to Git would have meant creating a new Team Project based on Git and either starting from scratch or importing history and / or work items from the TFVC-based project. There are some resources that offer help in this regard and I've compiled a short list to help anyone contemplating a migration understand what's involved:

I haven't tried to perform a migration and with luck I won't have to, since Microsoft recently announced support for creating a Git repo in a TFVC project. It looks like this will ship with TFS 2015.1 although quite what we'll get in practice remains to be seen. If you want to know more there is some commentary here.

Trying this at Home

For this post I used TFS 2015.RTM and Visual Studio 2015.RTM. If you don't have access to TFS 2015 then you can follow along using VSO since features in TFS tend to appear first in VSO, although some of the screenshots in this post may be slightly different. If you are new to VSO I have a Getting Started post here, however be aware that a key difference compared with TFS is that you create a new team project in the VSO web portal.

Whilst writing this post I encountered what seemed to be a bug in Visual Studio and in my description of how I fixed it I talk about dropping to the command line. For this you'll need to have Git installed and the easiest route is probably to get it from Chocolatey. The Install and Configure Git video in this MVA series has a step-by-step walkthrough.

Getting Started

The first step to working with Git in TFS is to create a new Team Project based on Git. In Visual Studio connect to the Team Collection where you want to create the new project and in Team Explorer navigate to Home and then click on Home (or use the down arrow button) to display the Home menu. The ability to create a New Team Project is available under Projects and My Teams:


Navigate through the wizard and ensure you choose Git at the Specify Source Control Settings page:


With the new project created (I called mine ContosoUniversity and used the Scrum process template) you will need to clone the repository before you can do much else. Team Explorer helpfully prompts you to do this:

visual-studio-clone repository

Some people like to clone to a folder created off the root of a drive (possibly to avoid maximum path length issues?) but I accepted the offered default of C:\Users\Graham.ALM\Source\Repos\ContosoUniversity. If you examine the folder that is created you'll see that it is empty, although in reality there is a hidden .git folder. I don't like placing code files in my repo until it contains the .gitignore and .gitattributes files and Visual Studio has a neat feature for adding these. In Team Explorer navigate to Home and then choose Settings. In the lower Git panel choose Repository Settings. This pane allows you to add the the .gitignore and .gitattributes files as well as alter other aspects of the repo (not all details shown):

visual-studio-add gitignore-and-gitattributes-files

The great thing about the .gitignore file that Visual Studio adds is that it's tuned for Visual Studio development. It's the small things...

This is a good time perform a commit, so choose Changes from the Team Explorer menu bar and notice that you are requested to Configure your user name and email address before committing changes. Defaults are taken from the current TFS connection -- edit as required, optionally choose to Enable download of author images from 3rd party source and click Update. Now head back to Changes, enter a commit message and click Commit.


Bear in mind that at the moment we have only committed locally and the TFS knows nothing about the changes. Before pushing any changes to TFS let's get a Visual Studio solution added. I used my ContosoUniversity solution which you can download here. After unblocking and unzipping it copy the contents of the folder that contains the solution file and project folders to the root of your repo. Switching back to Visual Studio and the Team Explorer Home panel and you should see that the Contoso University solution file is listed under Solutions:


Now navigate to the Changes panel and notice that there are Untracked Files:


Click on Add All to move these files to Included Changes, add a suitable comment and Commit the change. Back at the Home panel you can now open the solution. If you are opening the solution on a machine with only Visual Studio 2015 installed you might get a warning about LocalDB versions. You can ignore this but if you want to run the application do update the connection strings in CU-DEV.publish.xml in ContoUniversity.Database and Web.config in ContosoUniversity.Web with (localdb)\MSSQLLocalDB as per this post.

Whilst editing CU-DEV.publish.xml you will likely see that it is being ignored by Git. We do want this file to be included in version control as it's how new developers can quickly publish the database to LocalDB. Right-clicking the file shows Add Ignored File to Source Control which looks promising so let's try that. Navigating to Team Explorer -- Changes you'll see that there is a change and you can add a commit message and commit the change. Except you can't, or at least I couldn't:


The situation here seems to be a standoff between .gitignore which is indicating that CU-DEV.publish.xml should be ignored and Visual Studio which is honoring our desire to add the file. The fix was to drop to the command line and to open a command prompt at the root of the repo and run git add ContosoUniversity.Database\CU-DEV.publish.xml -f. This forces the file to be added against .gitignore's wishes. Presumably the problem is that Visual Studio is not using the -f switch. One to report...

The final task for this section is to publish the local changes to TFS. If you want proof that no code has been pushed to TFS yet you can open the project in the TFS Web Portal and navigate to the Code tab. You'll see something like this:


In Visual Studio Team Explorer -- Synchronization you use the Push link to publish Outgoing Commits to TFS:


I've not shown it here but refreshing the Code tab of the TFS Web Portal will now display your code along with the latest comment for each file and folder.

Pull Request Workflow

One aspect of the Git integration with Visual Studio and TFS that I particularly like is the pull request workflow since it lends itself very well for code reviews. To evaluate this for yourself the first step is to set up a branch policy to ensure that the pull request workflow cannot be circumvented. From the TFS Web Portal make sure you are somewhere in your team project and open the Control Panel (cog icon on the right of the blue bar). Navigate to the Version Control tab and then in the Git repositories panel expand the tree until the required branch is highlighted -- master in my case. Now click on Branch Policies in the right-hand panel and as a minimum check Require code reviews using pull request. You'll probably also want to check Allow users to approve their own changes if you are only using one account for the evaluation.


As you can see from the screenshot there are more options and you can find details here. I'm keeping things simple and with the changes saved it's time to head back to Visual Studio to see what's different. As a quick test, make a simple change to a file and commit to master (remember this is just your local copy). Now try and push the change to TFS. You should get an Errors encountered during push. See the Output window for details. message. In the Output window you should see a The following errors were reported during push: refs/heads/master, TF402455: Pushes to this branch are not permitted; you must use pull requests to commit changes. message.

The starting point to create a pull request is to create a branch from master. In Team Explorer -- Branches right click master and select New Local Branch From. In the panel that is now displayed type a name for the branch and click Create Branch.

This new branch is now shown in bold and is considered checked out. Make another simple change to a file and commit it and then in Team Explorer -- Synchronization click Publish to publish the branch and push both the change that was just made to the new branch and the earlier change to master.

The workflow now switches back to TFS Web Portal and in either Code > Explorer or Code > Pull Requests there should be a button to Create Pull Request:


Slightly confusingly this button doesn't do what it says but rather displays the Pull Requests panel with options to configure aspects of this pull request. In particular there is a more options link that does give you more options:


The changes you can make are all fairly obvious although I didn't make any. (Do note the existence of the New Pull Request link which allows you to configure your own pull request.) From this panel the Create Pull Request link does what you expect it to do.

The pull request as created above will sit in the Assigned to the team list of pull requests:


When a particular pull request is selected the panel allows comments to be made as a Discussion, right in the Files that have changed or against Commits. It's quite a busy window and there's a lot going on since it's also the place where Reviewers are selected and can indicate their approval decision:


In my case above there were no merge conflicts so once I'd marked my approval I could click the Complete pull request button. This then morphs in to a Delete source branch button to allow you to get rid of the source branch which for most teams is probably the right thing to do since you want these to be short lived.

Back in Visual Studio and your local repo, master hasn't got the latest changes and the short-lived branch created for the pull request is still hanging around. To fix all this up, in Team Explorer -- Branches double-click master so it's checked-out. Then navigate to Team Explorer -- Synchronization and use the Pull link to bring the changes to down to master. Finally back in Team Explorer -- Branches right-click the short-lived branch and delete it.

Tour Finishes Here

That's as far as I'm planning to cover in this post but obviously there's lots more I could have covered -- resolving merge conflicts for example. Whilst I like the pull request workflow a colleague pointed out that it could lead to Scrum team members working in silos and a presentation at this year's Agile on the Beach conference made the point that pull request workflows can have a negative effect on effective continuous integration. Whilst important and valid points these are probably people and process problems and if they are going to happen with Git they are probably already happening with TFVC shelvesets.

Cheers -- Graham