This post will introduce you to using Git using Visual Studio Online. This is the first post in a series.
- Git for Team Foundation Developers – (this post)
- Git for Team Foundation Developers – Branches
- Git for Team Foundation Developers – Merging
This series is targeted towards easing the Git learning curve for developers familiar with Team Foundation Version Control.
I joined the Azure Modern Apps Center of Excellence in Microsoft around 6 months ago and have been working on a project that uses Git for source control with Visual Studio Online. It has been frustrating to say the least. I have been working with TFS source control since 2004, and SourceSafe prior to that, Git was like a foreign language to me.
To work with the source code, my boss tells me to go clone the repo and create a published branch. Finally, 6 months later, I can tell you what that means. No, it did not take me 6 solid months to learn this, but it did take me 6 months to find the time to read, watch videos, and keep trying things for myself until the lightbulb went off.
This post is to help reduce that time to a single blog post.
You can still use TFS source control. When you create a project, you have a choice between TFS or Git. I am going to challenge you to create a project using Git and become familiar with it.
TFS Source Control
I am used to using TFS for source control. In that model, every developer works with the source control all at once.
TFS source control is a centralized version control system. When TFS first came out, I remember work with customers with geo-dispersed development teams who were concerned about performance because it required a connection to the central repository, so we added the TFS proxy to address those issues. If I didn’t have access to TFS (I was at a conference with crappy wireless or on a plane), I was kind of out of luck for checking in changes.
Using TFS, I would create a new team project, which creates a repository for my source code. TFS manages the deltas between files as part of a change set. Those deltas are managed on TFS itself. Each time I modify the source code and check that into TFS, the changeset is stored within TFS, allowing me to roll back to a previous version.
If I were going to work on a new version release using TFS source control, I would create a branch. The new branch would be mapped to a completely new directory on my hard drive, and all of the source code in that branch would be downloaded to that new directory. I would have an entire new copy of the source code on my hard drive.
At the same time that I was working on a new feature, bug fixes occur in the main trunk for the source code, so I have to eventually merge those bug fixes into my branch. I check in code very frequently, often with comments as simple as “added UI for feature”, resulting in many individual changesets for the feature I am working on.
Git is a distributed version control system, which provides several layers of abstraction. The first layer of abstraction is that every developer has both the central repository as well as a local repository.
This allows you to make lots and lots of changes locally, then finally take those changes as a feature and add them to the central repository. It took me a LONG time to come around to this conclusion: it’s a better model. I can make changes to the local repository and, when the feature is complete, I can push the changes from the local repository to the central repository. This allows me to work offline and with distributed teams.
Taking that a step further, you only work with a single repository at a time, and you can push your changes from the local repository to a remote repository somewhere else. I loved how Jessica Kerr (@jessitron) explains this in her video (at the end of this post), think of this as putting a bunch of stuff on a palette. Once you are done putting things on a pallet (the wooden structure you’d pile stuff on to be lifted by a forklift), you then put them in a truck to be driven somewhere else.
Another abstraction layer is the separation of the working directory, staging area (also called the index), and the repository.
Checking in code is a two-stage process: you first stage the changes that you want and then you commit the changes. There is a tremendous amount of power in this abstraction.
These two concepts (the local repository and staged commits) were the things that took me so long to grok. The rest of this post will walk through a few simple examples.
The .git Folder
Let’s start with a very simple example. I am going to open Git Bash, which opens a command window.
The very first thing you should do is know where to find help. Type “git help”.
The next thing you will want to know is how to clear the screen. Type “clear”.
To interact with Git using Git Bash, you will use Unix syntax commands. You can use “cd c/” to change directory to the C: drive, and then use “ls” to list all of the files and folders.
Let’s make a directory, “GitDemo”. Use the command “mkdir GitDemo”, then “cd GitDemo” to navigate to that directory.
Now we have some basic directory navigation out of the way, let’s use Git. Let’s see if our new folder is a Git repository using the command “git status”.
This is not a Git repository. We can tell that just by looking at the directory structure, there is no .git folder.
Let’s turn this folder into a Git repository. We use the command “git init”.
That creates an empty Git repository, which is the .git folder.
Open that guy up, and you can now see what just happened. A few folders are created for us, namely objects and refs, as well as a config file.
Now we check to see if this is a repository again using “git status”.
We initialized the repository, which creates the .git folder and its contents. Let’s delete the .git folder.
Now try “git status” again and see what happens.
We see that this is not a repository because we deleted the .git folder and its contents. We can create a new repository using “git init” again.
Lesson 1: the .git folder is the “database” for your repository, everything is contained within that folder.
Cloning a Repository
You would typically start by creating a new team project in Visual Studio Online, choosing Git as the source control provider.
This creates that central “origin” repository, but you don’t yet have a local repository. Once the project is created, click the link to open the project in Visual Studio 2013, and you’ll see a message in the Team Explorer node telling you to clone the repository.
Click that link, and you’ll see something like this:
That link tells you to create a local copy of the central repository. I prefer to change the destination path to something other than the default so I can find it easier. Click “clone”. Go to that directory, and notice that you have a .git subdirectory.
Go back to Git Bash and navigate to the directory using “cd /c/gitlearning”. Now try “git status” again.
Lesson 2: Cloning the repository does nothing more than downloading the files and the .git subdirectory.
Checking in Source Code
I’m going to do something a little bizarre here, so bear with me. Let’s go to that folder that Visual Studio just created and add a file. I am going to use “echo” to echo some text to output, and redirect the output to a file called “hello.txt”.
That added a file to the directory. We talked before about the concept of staging changes first. Let me demonstrate what I mean, we’ll use “git status” to see the status of the repository.
This is an “untracked file”, meaning it exists in the working directory but has not been added to the index yet. To do this, let’s use “git add hello.txt” to add the file to the index, then use “git status” to check the status again.
We can see now that there is a change to be committed. Let’s go inspect the folder structure in the .git subdirectory to see what happened there.
This is a SHA-1 hash of the change information. Let’s commit the change using “git commit hello.txt” –m “My initial check-in”.
When we used “git commit hello.txt”, we provided the check-in comment “My initial check-in”. Now let’s inspect the folder structure again.
A few new folders and files. This is how Git is tracking the changes, using the SHA-1 hash of the change.
Let’s go edit our hello.txt file and change the contents.
Save, then use “git status” again.
Git knows that the SHA-1 hash of the file is different than what it is tracking, so it reports the file has been changed. If we want to commit that change, remember we first have to stage it using “git add”, and then commit using “git commit”.
Now let’s see the status so far. Use “git log”.
We see our two check-ins that have been committed, and each one is identified by a SHA-1 hash.
Lesson 3: Checking in source code stages changes to the local repository, and those changes must be committed.
Pushing to Visual Studio Online
So far, we cloned the repository and showed how to stage and commit changes to the local repository. To understand this, go to your Visual Studio Online page and notice that there’s nothing in there.
There are instructions to enabling basic authentication for your profile. After enabling alternate credentials, we can now go back to the command line and push our changes from the local repository to Visual Studio Online using “git push –u origin –all".
Now that we’ve pushed changes, let’s look at Visual Studio Online again.
We now see that our code has been pushed to the remote repository. Let’s look at the history.
OK, that is seriously cool. Not only did the source code get copied from my local repository, but it also copied the change history. This is the most powerful part of Git, the fact that I can push the entire change history, I can cherry pick a few changes, or I can push all of the changes but squash them all into the latest commit. This allows you to tell a story about what’s in your feature without having a ton of chatty check-in comments in the central repository.
Lesson 4 – Changes are committed to the local repository and then pushed to the remote repository.
Using Visual Studio Git Integration
Now that we’ve seen how to do everything from command line, let’s use Visual Studio instead. Create a new project and use the same folder. Check the option to add to source control.
The result is a new project in Visual Studio.
We can go to the Changes tab to see the changes.
Notice that it looks like the changes are staged. However, that’s really not the case, Visual Studio is trying to make things easier for us by hiding the low-level details. Let’s go look at the repository real quick to see the status.
Everything Visual Studio just created is untracked as far as Git is concerned. Visual Studio is going to make things easy for us, instead of having to know anything about staging and committing, we just commit. Go back to the Changes tab and enter a check-in comment, the Commit button is enabled.
You can see there are three different options for committing changes: Commit, Commit and Push, and Commit and Sync.
We will just use Commit to commit the changes to the local repository, just like we did with the command line before.
Click that button, “Unsynced Commits” to see the commits that exist in the local repository but have not yet been pushed to the remote repository.
We see the commit that we just created in our local repository. We click Push to push the changes to Visual Studio Online. Once that is complete, go back to the browser for your project, we can see the changes.
Now let’s go see if the source is actually there.
Our source code is there, just as we expect.
Lesson 5 – Visual Studio tries to simplify the interactions with Git, but it will help you tremendously if you familiarize yourself with how Git works.
For More Information
Jessica Kerr did a great presentation that helped me tremendously to understand the benefits of Git.