By now, chances are good you've at least heard of Git. It's been making a big splash among developers for the past few years, and now it's a first-class citizen in TFS 2013. You're probably wondering what all the hubbub is about and if you and your team should make the switch. In this blog post, I'll lay out all the facts for you and let you know a little bit about Git works, how it relates to Team Foundation Server 2013, and how it integrates with Visual Studio 2013.
What is Git?
Git is a source control tool, created by Linus Torvalds (the creator of Linux) in order to manage the source code for the Linux kernel. He evaluated the other source control tools available at the time and found nothing out there that met his exact requirements, which were:
- It needed support developers distributed across a wide area (in his case, the entire world)
- It needed to be very fast for large projects
- It needed to support very complex source control workflows
How is Git different from Team Foundation Server Version Control (TFVC)?
In order to meet Linus's needs for version control, Git's structure and basic workflow is very different from Team Foundation Server's. TFVC is a centralized version control tool, whereas Git is a distributed version control tool. What's the difference between centralized and distributed, you ask?
In Centralized version control, there is one single server that acts as the code repository. All operations (branching, merging, commiting changesets, and so on) take place on the server, and require a connection to that server. When you grab code from Team Foundation Server, it grabs a copy of the workspace you defined and downloads it to your local machine. Then as you work on your code, Visual Studio is in frequent communication with the server. When you check files out, when you check them in, when you pull down the latest code that other folks have been working on, all of that involves reaching out to the server. There are different types of TFS workspaces that can reduce the amount of server communication, but a discussion on those is a topic for another day. You can read more about workspaces on MSDN.
In Distributed version control, there is no central repository! You define a "master" repository by convention within your organization or team. If you're using TFS (and you should be!), then your TFS server will be your master Git repository. Then you perform an operation called a clone on it. The clone actually reaches out to the repository and makes an exact copy of it on your local PC. This clone contains all of the data in the repository -- all of the branches, all of the commit history, everything. From then on, you can pull your network cable out, turn off your wireless connection, and work in a plane, in a submarine, whatever! No further connection to the master repository is necessary.
Git is very heavy on branching and merging, but it's designed so that branches and merges are fast and painless operations. So you'd typically make a branch on your local repository, start working on it (confusingly, called a checkout in Git-speak, which is nothing at all like a checkout in TFVC. You check out a branch in Git, but you check out a file in TFVC). Anyway, once you're done working on your local repository, you need to sync your changes back to the master repository. So wait for your plane to land, your submarine to surface, plug your network cable back in, and reconnect to the Git server. You can then pull any changes that have been made to the repository while you were working, merge them with your changes, and then push everything back up to the master repository.
Now, the real power of Git starts to come out when you take advantage of its distributed nature. Let's say Ann and Bob are working on a new feature together. If Bob needs some code that Ann has been working on, Ann can commit it to her local repository, Bob can set up Ann's repository as a pull location, and then Bob can pull down Ann's code into his repository, without Ann or Bob ever having to commit half-finished work to the master repository. When they're done with the feature, one of them can push the completed code back up to the master repository. Since Bob and Ann have both been doing frequent commits, when they push their change up, all of their commits and attached notes will be synched as well, so the history of their work is preserved.
So, all of this sounds pretty great, right? Well, some things to keep in mind:
- Git was originally written as a command-line tool. Visual Studio provides a nice GUI wrapped around a lot of Git functionality, but if you don't like command lines, Git isn't the tool for you. Not everything Git does is expressed in the Visual Studio GUI yet, although the VS team is doing a great job. Even so, you're going to land at a command line eventually.
- Git doesn't just have a learning curve, it has a learning cliff. You'll be able to master the basic workflow (clone, pull, push, branch, merge, etc) in no time, but the more advanced workflows (things like rebasing, cherry-picking, etc) can be very difficult to conceptually grasp and execute in practice.
Git in TFS has a few limitations, although Microsoft has indicated that they intend to address these limitations in the future:
- The built in TFS Code Review tool does not work with Git yet.
- You cannot use Gated Check-in builds with a Git repository
- Due to design decisions, Git's performance suffers when dealing with repositories that have large files, or large numbers of files. If you're storing binaries in source control, or have hundreds of thousands of files, Git might not be a good choice.
If you want to get a better feel for how Git works, there's a great interactive tutorial available at http://pcottle.github.io/learnGitBranching/
Using Git with Visual Studio
Now that we have a better grasp of Git, let's look at how we'd use it from within Visual Studio. First off, I'm going to make a new team project for myself, called AwesomeApplication. When I make my Team Project, I'm choosing "Git" as the source control option. Once my Team Project is up and running and I'm connected to it, I see the Git Team Explorer.
You'll note that it's different than the TFVC Team Explorer, because of Git's different workflow. We'll go through everything as we need to, don't worry! First off, I have a notice telling me I need to clone my repository to get started. So I guess I'll do that first! Now I need to choose what Git repo I'm cloning, and where I'm cloning it to. You see that the Git repo is exposed via the standard TFS URL scheme, so I can connect any Git tool I want to it. Of course I'm going to keep using Visual Studio, because Visual Studio is the best. :)
Once that's done, you'll see that I'm on the "master" branch, and that no solutions were found in my repo. No surprise there, it's a brand new repo!
So, let's get some code into source control. I won't include a bunch of boring screenshots of me making a new project -- I'm just going to make a Console application. Once I have that, I need to make a local commit. So I just click over to "Changes" in Team Explorer, and I can see all of my new files:
I enter a comment for my changes, click "Commit", and I get a local commit created. Keep in mind, that commit is created locally, not on the server!
Now I want to get my "master" branch with the baseline code for my application pushed up to TFS. I can go to the "Branches" section of Team Explorer, and see the branches that are on the server, and the ones that are local. For the time being, I just have one local branch: master. I just right click on my branch, choose "Publish", and poof! It gets pushed up to my master repository!
Now I can start really working on my application... The rule in Git is "branch early, branch often!", so I'm going to do that... I'll go ahead and make a "dev" branch for myself to go and play around in. From my "Branches" tab, I'm just going to click "New Branch". It asks me to name my new branch, which branch I'm going to use as my starting point, and to choose whether I should switch over to start working in ("Checkout") my new dev branch.
Now you can see that my new branch has been created, it's checked out (which is why the text is bold), and it's unpublished, which means it exists only on my local machine. If I went and wiped my hard drive now, anything in that "dev" branch would be gone forever. Now I'm going to work on my dev branch for a while. Another Git rule is to make frequent commits -- it's all local, and you can perform all sorts of command line wizardry to combine commits later, anyway. So I'm going to make a bunch of commits. I can see those commits under the "Unsynced Commits" tab. They still exist only on my local machine.
Now, to get these up to the master, I have to do a few things:
- Merge the changes from dev -> master
- Pull down the latest code from master, just in case something changed
- Resolve any conflicts
- Push my changes up to the TFS server
So I'll jump over to the "Branches" tab again. First, I'm going to checkout the master branch so that it's my current working branch. Then, I can just right click on my dev branch and choose "Merge".
Clicking the "Merge" button will go ahead and take the contents of my "dev" branch and merge it into my "master" branch. The code is still only local -- I've merged it to my local master branch, but I haven't pushed it to the server yet. Next, I want to pull down the latest code from the "master" branch so I can make sure everything merges correctly. I can jump over to my "Unsynced Commits" tab. We have two options here: Fetch and Pull. Fetch will just pull down the latest changes. Pull will pull them down and try to automatically merge them for me. I'm going to go with "Pull"!
which results in this:
Aw, someone else changed something, and I have a conflict that can't be automatically resolved. I have to merge manually. Clicking "Resolve the conflicts" takes me to a standard merge tool:
I resolve the conflicts:
and click "Accept Merge". Now I can click "Commit Merge", and then it gives me one last chance to change the commit message and review my merged code:
That's all fine with me, so I just click "Commit", and jump back over to my "Unsynced Commits" tab, where I now have an extra commit for my merge:
Now I can click "Sync", and have everything pushed to TFS:
And that's the basic Git workflow in a nutshell! The TFS web portal has some nifty tools for Git, as well. If you open up TFS Web Access and navigate to the "CODE" section, you can see:
- The source code contained in your branches
- Your commit history for a branch
- A view of all of your branches
- Comparisons of your branches
One thing I didn't talk about that's very important: TFS Team Build fully supports Git, so you can still leverage the great build and release management capabilities of Visual Studio and Team Foundation Server. I'm not going to talk about builds today... we'll cover that in a future blog post!