Volume 31 Number 8
Commit to Git: Source Control in Visual Studio 2015
By Jonathan Waldman | August 2016
Since their 2013releases, Visual Studio and Team Foundation Server have offered out-of-the-box support for Git, the enormously popular source code management system that has upended many traditional options. To complement this source control option, Microsoft has added feature-rich front-end tooling for Git to Visual Studio. But how do you access and leverage these tools?
In this article, I’ll cover how Git differs from the source control technology that’s associated with Team Foundation Server (TFS), formally called Team Foundation Version Control (TFVC). Then I’ll delve into how to configure Git; how to create, connect to and work against a local repository (repo), including how to stage and commit changes; how to manage branches, including merging and viewing history; and how to connect to different types of remote repos, including how to sync changes.
I created the figures in this article from Visual Studio 2015 Update 2 Enterprise edition, but the items I discuss herein are available in all other Visual Studio 2015 versions, including the Community and Express editions. To preserve space, I’ve created figures that sometimes contain more than one screen image, and I make that clear in the text. Also, I use numbered markers to direct your attention to items within a figure. Once I refer to a figure, I generally mention just its markers. For instance, in the sentence, “See Figure 1, Marker 1 and then look at Marker 2,” I’m implying that Marker 2 is in Figure 1.
Figure 1 The Team Explorer Window Home Panel (Offline)
If you’ve been using Visual Studio for more than a few years, you might have the impression that TFVC is the right choice to make when developing solutions in a team environment. Often it is, especially if your projects are already using TFVC or if they need to store very large files, contain a great number of files (beyond what anyone would or could reasonably stream across a network) or must be able to lock files under source control. However, as developers more commonly work from disparate remote locations while contributing to a single collaborative software project, newer development teams have flocked to Git because it’s a decentralized version control system with broad, cross-platform appeal that lets you work productively offline as you commit or undo changes, manage branches and access history. Best of all, when you’re ready, you can go online and connect to the same remote repository that’s being updated by the rest of the team and synchronize your offline changes using a variety of methods.
The Visual Studio 2015 IDE relies on the LibGit2 API and the LibGit2Sharp communication layer to implement all of the Git features it exposes in its front-end tooling. LibGit2 is a zero-dependency, cross-platform, open source Git core engine written entirely in C. LibGit2Sharp is a library written in C# that runs as a managed process under the Microsoft .NET Framework. It serves as a .NET-friendly interface between Visual Studio and LibGit2 and it dramatically simplifies the programming effort required by the Visual Studio development team to establish a communication pipeline to and from the LibGit2 library. LibGit2Sharp is available to you, too, which means that you can use your favorite .NET language to write your own Git tools and utilities. Access more details about LibGit2 and LibGit2Sharp at libgit2.github.com.
In Visual Studio, Team Explorer is the primary GUI conduit through which you ultimately interact with LibGit2—the underlying Git engine. To open it, select the View | Team Explorer menu item or type Ctrl+\ followed by Ctrl+M. Along the top of the Team Explorer window is a toolbar containing blue Back/Forward navigation buttons followed by white Home, green Connect and blue Refresh buttons. Click the Home button and you’ll see a window similar to the one pictured in Figure 1.
Below the toolbar is the label “Home” (Marker 1). This label has a white down-arrow next to it (Marker 2), indicating that it’s connected to a dropdown menu. Click anywhere along the label to display the menu (Marker 4). Both the Team Explorer toolbar and this context menu let you conveniently switch among the various Team Explorer panels; it’s a different kind of tabbed-dialog metaphor: The panel type you’re currently viewing (in this case, Home) appears in both the panel label (Marker 1) and the Team Explorer title-bar caption (Marker 3).
Before using Git within Visual Studio, you should configure its global settings. To do that, navigate to Team Explorer’s Home panel. Its Project section contains a series of buttons for viewing pending changes, managing branches and synchronizing with remote repositories (Figure 1, Marker 5). Click Settings to open the Settings panel, and then click Global Settings under the Git section. This presents the Git Settings panel (Figure 2, Marker 1). These global settings aren’t tied to a particular Git repository; rather, they supply default values as you create new repos (you can later override those defaults on a per-repo basis). Specify your User Name (this should be your full name—spaces are allowed); your e-mail address and the default repo location, which is the default folder where you want newly created Git repos to be stored by Visual Studio (Marker 2).
Figure 2 The Team Explorer Git Settings Panel
Also, specify whether to associate TFS or Gravatar author images with Git activities. If you select Gravatar, be aware that the way this feature works is to send the e-mail address associated with each Git commit to Gravatar as a lookup-key. Gravatar then returns an image associated with that e-mail address. Thus, ultimately, this seemingly innocuous feature shares contact information about everyone on your team with a third-party entity—something you might want to prevent. Finally, select whether to commit changes after a merge by default (Marker 3). If you make any changes to these fields, click Update to save them (Marker 4).
In a separate section of the panel, you can set which Diff Tool and Merge Tool to use; currently, these values default to Visual Studio’s own tools. If you want to further customize these selections, then you might need to manually edit the configuration file to which this Window writes. That file is .gitconfig, and it’s located in your homepath folder.
Working Against a Local Repo
When you work on your own projects as a solo developer and you’ve made the good decision to place your code under source control, you can start by working offline against a local Git repo and then scale up to a connected, remote repo later, if warranted.
To create an empty repo, go to the Team Explorer Connect panel (Figure 3, Marker 1) and click New under Local Git Repositories (Marker 2; New is grayed out because I already clicked it). Enter a local path and repo name, such as your default source path followed by \MyNewestRepo (Marker 3), then click Create (Marker 4). This creates a folder called MyNewestRepo (this is your working directory) that contains a .git folder along with two files, .gitignore and .gitattributes. Although I show it in the screen image, .git is a hidden folder: It contains the actual Git repo (Git’s backing database and housekeeping files) and usually shouldn’t be touched. But because it contains your entire Git repo, you might want to back it up, so it’s important to know that it exists. The .gitattributes file specifies how Git should handle line endings and which programs to launch when diffing a file within the current repo; .gitignore specifies that Git shouldn’t track files with certain extensions or in certain folders (by default, it specifies .suo, .user, .pdb, and .tmp file extensions and all of the files in the debug and release folders). Add other file extensions and folders as needed to keep the size of your Git repo as small as possible.
Figure 3 The Team Explorer Connect Panel
After creating the new repository, you’ll see it appear under the Local Git Repositories section. Double-click any repo that appears in the list (Figure 3, Marker 6) to connect to it; this highlights the repo using a boldface font before taking you to the Home panel, which confirms that you successfully connected to the repo you selected (Figure 4, Marker 2).
Figure 4 The Team Explorer Home Panel, Connected to a Repo
If you click Settings now, you’ll see that you have access to repo-specific settings. Access those settings if you want to override the values inherited from Git’s global settings. For example, it’s quite common to customize the e-mail address for the current repo if you’re working on a project for a particular client and want to use a work-specific e-mail address. Additionally, you can click provided links to directly edit the .gitignore and .gitattribute files; specify which Diff & Merge tools to use; add remotes and view other attributes related to the current repo.
Recall that Git’s working directory is the parent folder that contains the .git directory. Once you’ve created and configured the empty repo, the way to add files to it is to first add files to the working directory. Git will see those files but won’t incorporate them into the Git repo until you stage and commit them. Armed with this knowledge, simply use the working directory as you want and engage in a Git-commit workflow once you’re ready.
While starting with an empty repo and then adding files is one option, you also can start with solution files. To create a new solution along with a Git repo, select the File | New Project menu item. You’ll see the New Project dialog that includes a “Create new Git repository” checkbox. If checked, Visual Studio creates a new solution and a new Git repo—along with the two .gitattributes and .gitignore configuration files—in the new project’s working directory. Alternatively, if you have an existing solution and you want to place it under Git source control, open the solution and then select the Visual Studio File | Add to the Source Control menu item. Both procedures create a new Git repo along with .gitattributes and .gitignore configuration files.
Whenever you open a solution that’s under Git source control, Visual Studio automatically connects to the repo in that solution’s working folder. Likewise, whenever you use the Team Explorer Connect panel to connect to an existing repo, Visual Studio dynamically scans all of the folders in that repo’s working directory for .sln files and lists them in the Home panel’s Solutions section. For example, if you connect to the MyNewestRepo repo, you might see a list of solutions that looks something like the callout image shown in Figure 4, Marker 4. When Visual Studio identifies such solutions associated with a repo, double-click an entry if you wish to open that solution within the IDE.
When you use Visual Studio to open a solution that’s under Git source control, Solution Explorer displays informative icons next to items in its treeview control. The icons indicate the state of items in your working directory as compared to items that exist in the Git repo to which you’re currently connected. For example, in Figure 5you can see a blue lock icon next to checked-in items (Marker 1), a red check mark next to changed items (Marker 2) and a green plus sign next to added items (Marker 3). If you encounter an icon you don’t recognize, hover the mouse directly over it to see a helpful tooltip. While these icons usually are accurate, if you make changes to items outside of the Visual Studio IDE, then it might be necessary to click the Solution Explorer Refresh toolbar button in order to update the view.
Figure 5 Solution Explorer with Icons Indicating Source Control States
After working with items in your solution, you’ll probably want to stage then commit changes to the Git repo, or possibly even undo some changes. To begin managing the changes you’ve made, navigate to Team Explorer | Home | Changes. In the Changes panel (Figure 6, Marker 1), you’ll see all detected changes (Marker 2). Click the plus icon (Marker 12) to stage all changed items or the minus icon to unstage all items (Marker 13). You can also drag and drop items between the Changes (Marker 2) and Staged Changes (Marker 3) sections.
Figure 6 The Team Explorer Changes Panel
Right-click a changed item to view a menu that lets you open the file, view its history, compare it with its unmodified version, open the source file and show an informative annotations pane adjacent to it, stage and undo its changes (Marker 14). If you want to compare a change with the unchanged version of the file, double-click a changed item to launch a diff window (Figure 7). The diff window has two panes: The left pane shows the unmodified version in the local Git repo and the right shows the version in your working directory; the right-most edge visually shows you where there are differences between the files (Marker 1)—red indicates a removal while green indicates an addition; the panes show a red highlight over the entire line of code that has a removal (Marker 2) and a green highlight over the entire line of code that has an addition (Marker 3), and the diff tool draws a red or green box within that line around removed or added text, respectively. Additionally, helpful dropdowns flank the top of each pane (Marker 4)—these let you navigate quickly to code sections.
Figure 7 The Visual Studio Default Diff Tool
When you’re ready to commit your changes, add a commit message (Figure 6, Marker 4), then click the multi-mode Commit button (Marker 5). This multi-mode button defaults to Commit Staged, but it also can push and sync (this makes sense only in the context of being connected to a remote repository). When the commit operation succeeds, Team Explorer reports the commit ID (Marker 15).
Notice that the Changes panel informs you that it’s working against a local branch called unit_test_project (Figure 6, Marker 6). The Visual Studio status bar also reports which branch you’re working on (Marker 10) and it displays other useful, real-time information related to the current Git repo. For instance, it shows the number of unpublished changes—that is, how many changes have not yet been pushed to a remote repo (Marker 7); the number of staged changes (Marker 8); the name of the current repo (Marker 9); and the name of the current branch (Marker 10). Furthermore, these status-bar sections act like buttons. For example, if you click the current repo, Visual Studio opens the Team Explorer Connect pane, showing you details regarding the current repo; if you click the current branch, a popup menu offers branching options.
As with any source control system, when you commit changes to the repo, you’re adding to the repo’s commit history. Those history entries include the user name and e-mail address you provided in Git Settings so that anyone who has access to the history data can view who did “what” and “when.” Not only that, when you push your local changes to a remote repo, the history goes along with it. When other members of the team synchronize their local repo with the remote, they’ll be able to see the history your changes generated.
Visual Studio supports basic and advanced Git branching features. When you want to manage branches, open the Branches panel by navigating to Team Explorer | Home | Branches (Figure 8, Marker 1). Along the top, you’ll see quick links to merge, rebase and other actions (Marker 2). Below that, you’ll see a section called Active Git Repositories (Marker 3) and a list of branches each contains; the current branch is in boldface type (Marker 4). To switch to another branch, double-click it. Visual Studio then performs a checkout on the selected branch.
Figure 8 The Team Explorer Branches Panel
Right-click a particular branch to see a menu of available actions (Marker 5). You can check out the selected branch, create a new local branch from an existing local branch, merge from an existing local branch into the selected branch, rebase from the selected local branch onto another existing local branch, perform a hard or mixed reset on the selected branch, cherry-pick the selected branch or delete the current branch. If you choose to merge, Visual Studio offers full support for detecting merge conflicts, and it presents a conflict editor you can use to manually resolve those conflicts.
You also can view the history for any listed branch and, from that history view, you can right-click an entry to see a menu that lets you view commit details, make a new branch, create tags, revert, reset, cherry-pick and navigate to parent/child branches. The history view shows the Commit ID, author, date and commit message.
Connecting to a Remote Repo
So far, I’ve limited my discussion to working offline against a local Git repo. A local repo is generally all you need if you’re working on your own and you have a reliable way to back up your working directory’s .git folder. However, when you want to work with other developers on a team project or when you want to use a hosted service as a backup, you’ll need to connect to a remote repo.
If you want to have full control of your repo or you’re a bit uncomfortable putting the code for the world’s next killer app on a hosted server, then you should consider hosting your repo using a file share on your own network. Next, you can increase reliability and file-transfer speeds to and from your repo by installing a Windows-based Git server, such as the Bonobo Git Server (bonobogitserver.com), which is free, or GitStack (gitstack.com), which is free for up to two users. Next, you can download and install Visual Studio Team Foundation Server Express 2015 on a server located on your network and support up to five named users for free; or, if you or anyone on your team has an active MSDN license, you can download and install the full version of Visual Studio Team Foundation Server 2015 on your own server and keep it there for eternity while supporting up to five named users for free. Finally, you can purchase and install Visual Studio Team Foundation Server 2015 along with the client-access licenses (CALs) you need for your team.
If you’re willing and able to use an off-site Git-hosting service, your options expand to include Visual Studio Team Services (previously called Visual Studio Online), as well as such popular options as GitHub, BitBucket and GitLab. The free hosting options always have some restrictions. The Git wiki Web site (bit.ly/1Oym3F9) strives to keep current with the many Git hosting options and features.
To show how to connect to remotes and clone repos they host, you’ll first clone a repo that’s hosted somewhere on your network. Next, you’ll connect to and clone a simple Visual Studio Team Services repo hosted on the Web. Finally, I’ll show how to connect to and clone a GitHub-hosted repo for a famous project.
To manage remotes, navigate to Team Explorer | Home | Connect (Figure 9, Marker 1). The Connect panel displays a blue Manage Connections link menu under the panel menu (Marker 2), followed by a section containing a vertical list of Hosted Service Providers (the individual Visual Studio Team Services and GitHub windows are called Service Invitations).
Figure 9 The Team Explorer Connect Panel Service Provider Options
If you happen to close a service invitation (by clicking its X, indicated by Marker 3), you won’t be able to get it back unless you modify the registry. If this happens, you can instead access the service using the Manage Connections dropdown menu (Marker 4). Other information within the Team Explorer Connect panel is also stored in the registry, such as recently used Git repository information. If you want to inspect that registry key, it’s located at HKCU\Software\Microsoft\VisualStudio\14.0\TeamFoundation (pay attention to the GitSourceControl and TeamExplorer branches below that).
Recall that one reason you can work offline so productively against a Git repo is that when you clone a remote repo to a local repo, you obtain that repo’s entire history, which includes the details for every commit, branch and merge operation. When you go back online, Git determines how your local repo has changed when compared to the remote repo and this is important when it comes to being able to successfully carry out fetch, pull, push and sync operations.
To clone a repo from a local network share, go to the Local Git Repositories section and click the Clone link. You’ll be asked to “Enter URL of a Git repo to clone,” but the process is actually far more forgiving. You can also enter any valid path to a location on your current workstation (such as c:\Repos\FinancialWizardApp), a UNC path to a network share (\\22.214.171.124\Repos\FinancialWizardApp) or a mapped-drive path (\\computername\Repos\FinancialWizardApp). Just be sure that there’s a .git folder at the specified location and that Visual Studio can read it.
In Figure 10 (Marker 1), I’ve entered a mapped-drive letter to refer to the location on my network that contains my remote repo, and other developers who work on my network can do the same. After providing the location of the remote repo, specify the local path for the cloned repo (Marker 2). Next, decide whether to recursively clone submodules, then click Clone.
Figure 10 Working with Various Remote Repo Locations
It’s important to note that when you connect to a remote repo on a file server, you won’t have the ability to issue pull requests. This feature requires a Git server (such as Team Foundation Server or GitHub). You can, however, create, merge and manage branches and view history and sync changes (by fetching, pulling and pushing).
When you want to clone a repo from Visual Studio Team Services, you first need to log onto a Team Foundation Server. To start, select the Visual Studio Team | Manage menu item, or go to Team Explorer’s Connect panel and click Manage Connections, then choose Connect to Team Project. You’ll see a Connection to Team Foundation Server dialog appear. Click Servers and you’ll see a dialog such as the one shown in Figure 10, Marker 4. Notice that you can use this dialog to connect to any available Team Foundation Server, but if you want to connect to a Visual Studio Team Services account, enter the URL for it. When you click OK, you’ll need to sign in; once you do that, your server will be listed and you can close the dialog. You’ll then see a dialog that shows you two panes: the left pane displays your Team Project Collections and the right pane displays Team Projects in that collection. Check the checkbox next to those team projects you want to appear in Visual Studio, then click Connect. Now navigate to the Team Explorer Connect panel and you’ll see your repos listed (Figure 10, Marker 3).
While GitHub offers only Git as a version control system (VCS), Visual Studio Team Services offers decentralized Git by default and centralized TFVC as an alternative. These two VCSes work quite differently and require different IDE tooling. Fortunately, the Team Explorer window was specifically designed to recognize and handle both VCS types. In fact, when you connect to your Visual Studio Team Services server and add projects, Team Explorer shows which projects are under Git version control by using a red Git icon (Figure 10, Marker 3); projects unadorned with the Git icon are under TFS version control.
So in order to clone a Visual Studio Team Services remote repo, it must be a Git repo. You can right-click any Git repo in the list and choose Clone. I chose to clone the GitProject project, which brought me to the Local Git Repositories section with the remote repo information populated, along with a default local repo path (Figure 10, Marker 5). Once cloned, the repo appears in the Local Git Repositories list. Double-click to open it and you’ll be taken to the Team Explorer Home panel. There you’ll see buttons designed to work with Visual Studio Team Services repos, such as Pull Requests, Work Items and Builds.
The process of cloning a remote repo is very similar if you’re cloning from GitHub. If you have a private repo hosted on GitHub, then you’ll need to log onto your GitHub account to clone it. Otherwise, you can clone public repos straightaway without having an account.
In general, you can clone a remote repo as long as it’s on a network share or available from an HTTP/HTTPS server. At this time, Visual Studio does not support SSH for communicating with remote Git repos.
Working with Remote Repos
Once you’re connected to a remote repo, you can go back to Team Explorer | Home | Settings and click its Repository Settings link. There, you can view information about the remotes your current repo is connected to (this is especially helpful if you’re working against more than one remote). Back on the Settings panel, you’ll also see new links if you’re connected to a service such as Team Foundation Server or GitHub. Those links let you configure security, group membership, portal settings and so on, for the service.
On the Team Explorer | Home panel, you’ll see new buttons related to options your remote service offers. If you’re connected to a remote repo hosted by Visual Studio Team Services, you’ll see buttons for Pull Requests, Work Items and Builds. If you click Sync, you’ll get to the Team Explorer Synchronization panel where you can choose to sync, fetch, pull, publish and push. If there are merge conflicts that can’t be resolved automatically, Visual Studio presents the selected Merge Tool so that you can manually choose how to resolve those conflicts.
To conclude, I’ll clone Microsoft’s open source TypeScript 3 project, which is located at bit.ly/1o2weYt. Because this is a public Git repo, I can clone it directly using the Local Git Repositories section Clone link (Figure 10, Marker 6). As of this writing, this repo is about 350MB, so it contains a lot of history and branches and might take a while to download.
Once the local repo has fully downloaded, you’ll see it listed under the Local Git Repositories section. If you double-click it, it will open in the Team Explorer Home panel (Figure 10, Marker 7). Under the Project section, you’ll see buttons designed to work with GitHub repos such as Pull Requests, Sync, Pulse and Graphs. Some of these buttons will take you to the GitHub Web site to complete the requested action.
If you click Branches, you’ll be taken to the Team Explorer Branches panel. Once there, you’ll see the master branch. If you right-click that, you can view history for the entire project, starting with the initial commit made on July 7, 2014, through to the current date. The view history window lets you view its data using a number of different presentations, depending on the options you choose in the window’s toolbar (Figure 11, Marker 1). The view I chose to show is referred to as the Detailed View. It shows a graph of branches (Marker 2)—merge commits are in gray (Marker 3) while non-merge commits are in blue (Marker 4)—including the commit ID, the author’s user ID, the date of the commit, the commit message and any tags that might be present.
Figure 11 Viewing History Provides Detail About Branches, Commits and Merges
This display makes it easy to navigate to the branch’s parent or child. Just select a commit and use the toolbar’s Go to Child/Go to Parent navigation buttons (the third and fourth buttons shown). In those cases, where a branch ends with an arrowhead (Marker 5), click that commit (see the highlighted row) and the line connecting parent and child will be drawn (Marker 6).
Visual Studio 2015 provides convenient GUI access to common and many advanced Git features, and is able to do so thanks to the underlying LibGit2 Git engine. Although it offers nearly full support for Git, there are still some less-popular operations, such as stashing, that require interaction with a Git command-line interface. Because the Visual Studio Git tooling is so extensive, it’s possible to remain shielded from Git’s command-line interface and yet accomplish most Git tasks with little friction. Curious or advanced Git users undoubtedly will, at some point, crave access to bare-metal Git. Those users can assuage themselves by launching a PowerShell Interactive Window and interacting with the official Git for Windows command-line interface, which also is included with Visual Studio. With GUI and command-line options, Visual Studio provides satisfying and ready access to Git, no matter what your skill level.
Jonathan Waldman is a Microsoft Certified Professional who specializes in Microsoft technologies and software ergonomics. He has worked with the Microsoft technology stack since its inception and has held lead roles on several highly visible institutional, government and private-sector projects. Waldman is a member of the Pluralsight technical team and authored its video training course on the commercial Wijmo library of enhanced JQuery UI widgets. He can be reached at email@example.com.
Thanks to the following technical experts for reviewing this article: Jeremy Epling (Microsoft) and Edward Thomson (GitHub)
Jeremy Epling is a Principal Program Manager at Microsoft working on the Visual Studio Team Services and Team Foundation Server team.
Edward Thomson is a Software Engineer at GitHub and the author of O'Reilly Media's Git for Visual Studio training (www.gitforvisualstudio.com).