Tuesday, December 30, 2014

Getting Used to Git in Visual Studio: Branches

I started working with Git not too long ago (here's how I got started). Soon after, I discovered the built-in support for Git in Visual Studio 2013. I've been working with Git and Visual Studio quite a bit over the last several days, so it's time for an update to show the things I really like.

I started by primarily using the command line. But as I've become more comfortable with the features in Visual Studio, I find myself using the VS GUI more and more. This is based on the project that I've been building for Exploring Task, Await and Asynchronous Methods (the GitHub project is at https://github.com/jeremybytes/using-task).

I've been using branches to document the various stages of the code, so I've had a chance to play with the branching and syncing functionality in Visual Studio. Let's take a look.

[Note: Git articles are collected here: Learning Git. And a video is also available: Git Basics for Visual Studio Developers.]

Creating Branches
The Team Explorer window has everything we need. To get back to the "Home" screen, just click the little house icon on the top of the window. This gives us a quick way to get back to the main menu for our source control:

From here, we can select "Branches" to see all of our current branches:

In addition to having a list of the branches, the bolded entry lets us know which branch we are currently on. In this case, we are on "master".

To create a new branch, we just click the "New Branch" item (it's sort of a cross between a link and a drop-down). It gives us the following options:

Now we can type in our new branch name, select which branch we want to base this on (in this case "master"), and we can also checkout the branch after it's created.

Here's what we get:

We can see a couple of things here. First, our new branch is bolded; this is the current branch. In addition, it is listed in the "Unpublished Branches" section. This means that this branch is on our local system, but it has not been published to our server.

Publishing Branches
Publishing our branch is very simple. We simply right-click on it and choose "Publish". This will push it to the GitHub repository that we have set up. And we can see that here:

Now the first time that we "Publish" a branch from our local repository, we'll need to enter the information for our server-based repository. For this project, we're already configured to go against the "using-task" repo on GitHub.

Changing Branches
It's very easy to switch between branches. Here's our "MainWindow.xaml.cs" file, and as we can see, this is on the "07-TestBranch" that we just created:

From here, we can double-click on a different branch, or we can select from the "Branch" drop-down at the top of the "Branches" window. If we choose the "03-Await" branch, we see that our source code updates automatically:

And if we have uncommitted changes, we'll get a warning that we need to deal with them before changing to a different branch -- by either committing the changes or discarding them.

I have found that this makes it very easy to jump among the branches. For my articles that use this solution, I wrote (and published) all of the code ahead of time. This let me work out what my code samples would look like for the article.

Then when it came time to write the article, I could switch to the various branches to take screen shots, run the application, and show the changes for each step along the way.

Now in production applications, I generally have very short-lived branches -- usually just long enough to create a new feature and then merge the changes back into the main branch. But if I did run into a situation where I needed to manage multiple branches, this would be a very convenient way to jump among them.

Comparing Branches
It's really easy to see the changes between branches as well. For example, we can right-click on "MainWindow.xaml.cs" in the Solution Explorer and choose "View History...". This gives us all of the commits that affect this file:

Notice that in addition to the commits, we can also see the various branches in our repository. So we can make selections based on individual commits or based on the state of a particular branch.

We can also easily do comparisons. If we select both the "07-TestBranch" and the "03-Await" items, right click and choose "Compare...", we get the difference window that we saw in a previous article:

This makes it really easy to see what was added or removed.

Syncing with GitHub
So let's say that we've made some changes to our "07-TestBranch". It's really easy to commit those changes locally and then sync them with GitHub.

After changing the file, we go to the "Changes" section in Team Explorer:

This shows that we have one file that has been changed. So we can add our message and click "Commit".

After we do this, we'll get a message that the changes have been committed, but we still need to sync them with the server. For this, we'll go to the "Unsynced Commits" section. (Remember, we can click the "Home" icon at any time to get back to the menu):

This shows that we have some local commits that need to be pushed up to the server. The great thing here is that we just need to click on "Push", and it handles everything else for us.

Merging and Clean Up
So let's say that we're done with this branch. We just want to merge this back to "master" and remove the branch from our repository.

Merging is very easy. We just go back to the "Branches" section and select "Merge". This gives us drop-downs to fill in:

In this case we want to merge from our "07-TestBranch" back to "master". This is especially nice since merging from the command-line is a bit more involved (first by switching to the branch you want to merge to, then entering the "merge" command with the name of the branch to merge from).

I'm not sure what happens if there are any merge conflicts. Quite honestly, I try to avoid those as much as possible, so I hope that I never have to find out.

It turns out that I changed my mind about publishing the branch. I really don't want this branch in the local repository or on the server repository. To unpublish a branch from the server, we just have to right-click on the branch and select "Unpublish branch".

The message at the top tells us this was successful, and our branch is now listed under "Unpublished Branches". And if we check GitHub, we'll see that the branch is now gone:

To delete the branch, we just need to switch to another branch first (we'll use "master"). Then we can right-click on the branch and select "Delete".

Note: the "Delete" option is disabled (grayed-out) for the active branch. So, you must switch to another branch before the delete option will be available.

And with that, our branch is gone:

I think I'm beginning to really like this.

Wrap Up
I started out learning Git with the command line, and I'm really glad that I did that. It gave me a good idea of how Git works, and how distributed source control behaves differently from centralized source control. And as I've used it over the last few weeks, I'm liking it more and more.

And I'm really impressed with how well Visual Studio works with Git. The built-in tools are top-notch. The thing that I like most so far is that it makes it much easier to interact with the remote repository (GitHub in this case). I see myself using the Visual Studio tools as my primary method of interacting with Git repositories. But I'll still use the command line from time to time to make sure that I don't forget how things work.

Happy Coding!


  1. Thanks Jeremy, your explanation helped!

  2. Awesome Jeremy, but u know how i can push to a diferent branch?

    1. I would look into "stashing" your changes and then restoring them to another branch. This article may help: http://jeremybytes.blogspot.com/2015/01/git-stash-saving-stuff-for-later.html

  3. Hey Jeremy, in VS2013 is it possible to customize the sync button? I would like for sync to rebase instead of merge.

    1. No, it's not possible to customize the buttons. If you want to take more control, I'd recommend using the command-line tools. I use a mixture of command-line and VS tools when I'm working with Git. This lets me use commands like "stash" that aren't available from within Visual Studio.

    2. I do use command line a good bit. It's just that some team members find rebase and command line in general to be "complicated." It's been a drag getting them to implement some tasks. Thanks for the quick response.

  4. What is the difference between Sync and Push?

  5. Jeremy,
    Nice article. Got a good understanding about Code Merging.
    Thanks! for posting.

  6. Nice Article Jeremy...Great Help...So what do you suggest...use sync or command line pull, do changes and command line push to be safer side?

    1. Honestly, I find myself going back and forth. The Git tools in Visual Studio are quite a bit better than they were -- a bit more directly related to the underlying Git commands. For me, understanding the Git CLI was important to get a good feel for how Git did things (and expected me to do things). These days, I'll usually create the repository from the command line, but I'll do pretty much everything else from inside Visual Studio.

  7. I'm a long-time TFS user trying Git for the first time, so it's probably down to me not understanding the concept of local branches...

    In VS2017 I've created a new *local* branch (right-click "master" -> "New local branch from..."). The new branch appears in bold, presumably meaning that I'm now "working" in that branch, so I make a change to a file in my solution. Next, I double-click the master branch - at this point I was expecting the solution to somehow "reload" to show me the source in this branch, but I'm still seeing the modified version of the file (with a status of "pending edit"). What am I missing, and if this is the expected behaviour then what purpose do local branches serve?

    1. You need to commit (or discard) the changes on your local branch before you can move to another branch. After committing the changes, you can move to the master branch to see those files.