Kristofer's Blog

Random Developer information from a Senior Program Manager at Microsoft DX

The Git Command Line 101 for Windows Users

The Git Command Line 101 for Windows Users

  • Comments 4

I'm currently working on a project using Git as source control system and I thought it would be useful to write down some notes and questions that have been answered during this project.

Git, GitHub and TFS, what's what?

So, here is a really good start if you are new to Git. Let's straighten out some facts first:

  1. Git is a distributed version control system
  2. GitHub is a service to host your Git repository
  3. TFS (Team Foundation Server/Service) is a Application Lifecycle Management, ALM, Server developed by Microsoft and also available as a service at http://tfs.visualstudio.com . TFS can handle your source code through a traditional TFS Source Control Repository or as a Git repository, i.e. you can use both TFS (as ALM Server) together with Git as Source Control system.

So, let it be clear. Git is NOT GitHub. Git doesn't have to be used with GitHub (even though you can). Git CAN be used together with Team Foundation Service, TFS.

How can I install Git on my Windows machine?

There are several ways of installing Git including just going off to http://gitscm.com/ and downloading the installer for Windows. I do like to keep my dependencies up to date using a packet manager called Chocolatey though, so If you are anything like me, then install Chocolatey and then use the command:

> cinst git

Make sure you have Git.exe in your path by just executing "git" from PowerShell or your traditional Command Prompt. If it's not, make sure you find Git.exe and add that folder to your path. That's it!

There are special Git shells that you can use, but I like the original PowerShell one the best with the addition of Posh-Git that can be installed directly from the website or by using Chocolatey:

> cinst poshgit

Posh-Git (abbreviation for PowerShell Git) is a set of PowerShell scripts that adds additional functionality to PowerShell users using Git. It's simple but good, try it out!

I want to start working on someone else's project, how do I connect to that source control server?

Git is a distributed Source Control system, i.e. you can and will communicate with a remote server, but only when you think you are ready to do so. I.e. you don't have a constant connection to a remote server like with TFS or other Source Control systems.

In order to start working on someone else's repository you need to clone it. To clone a repository is precisely what it sounds like, i.e. you create an exact replica/copy of that other repository on your computer. That "clone" contains all information that is available on the remote server, including: source code with history, comments, etc. So after a repository is cloned you'll have all information needed locally.

The repositories you want to clone are often (but not always) hosted on some public service out on the Internet and you'll need the URL to the repository you want to clone, for example (https://github.com/username/yourproject or https://username.visualstudio.com/DefaultCollection/_git/yourproject). You can get those URL's from the respective service that are hosting them. Go to your favorite command line shell (mine is PowerShell), change folder to one of your choice, i.e. c:\dev\repos\ and enter:

> git clone [put your url here] [put name of project here]

You don't need to put in a project name if you don't want to but it can be useful to do so if the default project name is long, contains strange characters (HttpUrlEncoded) or if you just want a different name on your computer.

I want to start a new project on my machine that has no connection to no one else's repository. How do I do that?

Since Git is a distributed Source Control Manager, you don't have to be connected to any server in order to use a local repository, even if that repository was created as a clone of another one. So it's really easy to setup a new local repository. Move to a folder of your choice, i.e. c:\dev\repos\mynewproj. Then enter the following from the command line:

> git init

That's it, you're done!

I want to check out files in order to edit them?

Git doesn't use the notion of checking out files. If you want to edit a file, just edit it. If you want to add a file, just add it. See next section about how to check in pending changes to understand how this works.

I want to check in pending changes, but how?

So check in pending changes is a two stage operation in Git. First you need to tell Git what changes it should care about and once that is done you commit those changes to your local repository. Something that is really different and important to understand compared to using TFS or any other centralized source control system is that those changes then only gets committed locally on your computer. So let's start by first committing to your local repository and I'll explain how to "push" your changes back to the central repository later on.

First we tell Git what to include in the coming commit by using the command add:

> git add .

NOTICE the "dot" after add!

You can specify exactly what files to add by specifying those as arguments after "git add" or you can just tell Git to add every file within the current folder including any sub folders by using the "git add ." syntax. This command has told Git that we (soon) want to commit changes made to every changed, added or removed file in my folder (or subfolders). Let's continue to commit those changes:

> git commit –m "your comment here"

So now you have "checked in your pending changes" in your locally repository. Remember those changes has not yet left your computer, so continue and read coming sections in order to understand how we can "push" those changes to someone else.

I did a "git commit" but forgot to enter a comment using –m. What the #!"¤#!" happened?

Ok, first of all, keep calm and sit down in the boat. If you enter "git commit" but omit to enter a comment using the "–m" parameter. Git will open up the default editor for you to edit your check in note. By default that is Vim. From the home page you can read:

"Vim is an advanced text editor that seeks to provide the power of the de-facto Unix editor 'Vi', with a more complete feature set."

Ok, so what might just be presented in front of you is a text editor, hosted inside your console shell (i.e. PowerShell for me). Vim is a very power full editor if you know how to use it but it also has "quite a high" threshold to learn… and all you want to do is write a commit message. I won't go into how you use Vim, but here is how you can get on with your commit.

Alternative 1 – Exit Vim without entering any comment

A blank or unsaved comment will be counted as an aborted attempt to commit your changes and you can exit Vim by following these steps:

  1. Press <Esc> to make sure you are not in edit mode (you can press Esc several time if you are uncertain)
  2. Press :q! <enter>
    (that is <colon><letter q><exclamation mark><enter>, this tells Vim to discard any changes and exit)

Git will then respond: "Aborting commit due to empty commit message" and you are once again free to commit using:

> git commit –m "your comment here"

Alternative 2 – Use Vim to write a comment

Follow the following steps to use Vim for writing your comments

  1. Press <i> to enter Edit Mode (or Insert Mode).
  2. That will leave you with a blinking cursor on the first line. Add your comment.
  3. Press <Esc> to make sure you are not in edit mode (you can press Esc several time if you are uncertain)
  4. Press :wq <enter>
    (that is <colon><letter w><letter q><enter>, this will tell Vim to save changes and exit)

Git responds that your commit has gone through as you would expect.

If you want to, you can use any other editor by configuring Git with another default editor, but I won't go into that right now. Either you love Vim and use it or you don't and then you'll remember to add the "–m" parameter from now on.

Ok, I get it how to "check in pending changes locally" but how can I get those changes back to my colleagues in the project?

So this is how a distributed source control system like Git really differs to a centralized one like TFS. If you were to "check in pending changes" using TFS traditional Source Control system, then your changes would be on the server by now, but since we are using Git right now and if you've done a "commit" (see section above) then your changes is still locally on your computer.

In order to get your changes to a remote server you use a command called "push". So let's start simple and do some assumptions before we continue. Let's assume you have created a local repository by cloning a remote repository and let's also assume that you are the only one working on that project right now, i.e. no other changes is going on in the source code right now.

So you now have locally committed changes that you want to share with a remote repository. This is done using a command called "git push". The push command will take the current state of your local repository and update the remote repository with the same changes. As long as the above assumptions are correct (that you've cloned your repository from an external one) then you only need to write:

> git push

If everything worked according to plans, then your changes are now available on the server for others to use.

How do I "get latest version" using Git?

A fundamental thing to remember here is that Git is a distributed source control system, i.e. when you say "get latest version" you really have to think about it like "I want to get the latest version according to THAT repository". But to keep it more in line with a centralized source control system like for example TFS, you could say that you want to incorporate all changes available on the server that I originally cloned from.

> git pull

That's it! Or is that it? So even though the command "git pull" seems simple and receives the latest version from the server, this command is source for discussion. "git pull" is actually two commands in one. By default "git pull" equals "git fetch" + "git merge" but let's talk some more about this in next section.

When using Git, I don't have to handle merge conflicts, right? At least that's what I've heard.

Ok, this is a really interesting question or more of a rumor that goes on out there. I've heard it several times from close friends that: -"Git is so much easier to use than TFS Source Control since I don't have to handle merge conflicts!". This is absolutely wrong! You do have to handle merge conflicts in Git as well. Let's just face the following example:

Person A changes file "readme.txt" locally on her computer. Person B also change information in his version of "readme.txt", in his local repository. They have both cloned their repositories from "The Server", so they both have the some origin. Person A does a local commit (i.e. "git add ." and "git commit") and then pushes her changes up to "The Server" (i.e. "git push"). Person B is now ready to push his changes to the server and tries to push them to "The Server" using "git push". Git will respond with an error message, telling Person B that his local repository is running behind the repository on "The Server".

In order to go ahead with pushing his changes to the server, Person B first need to update his local repository to the same state as the servers state and he does that by doing a "git pull". As you remember "git pull" is actually two commands executed at once, first "git fetch" and then (by default) "git merge". "git fetch" fetches and updates the local repository with changes made to the remote repository. "git merge" tries to incorporate those changes into your code that you have locally on your computer and might succeed, but in this case, since both Person A and Person B has changed the same file and perhaps at the same place, a merge conflict will occur.

CONFLICT (content): Merge conflict in readme.txt
Automatic merge failed; fix conflicts and then commit the result.

What Person B now have to do is to once again open up "readme.txt". Look at the comments added by Git (look for a lot of arrows pointing to the left or right) and then resolve the conflicts manually. When conflicts are resolved, Person A does a "add" and a new "commit" and then can push the changes up to the remote repository… that is as long as no one else already made another update of the remote repository.

There are books (and blog posts) about how to handle merges and merge strategies and I won't go any further on this topic right now, but be reassured. You will have some "fun" merge conflicts to handle even when using Git.

To round it up…

There is a whole lot more to learn about Git, but all of that is not part of Git 101. Have a look and even though there are a lot of graphical user interfaces to be used out there, make sure you give the command line option a try, it's not as bad as you might first think. If you find any errors or incorrectness, please let me know.

  • Great post, I like the simplistic approach you took, everything sounds easy :)

    One thing only - shouldn't it say "What Person B now have to do" instead of person A in conflict resolution?A has already pushed successfully, so it's the later commit that needs to be resolved, right?

  • There is a 3rd alternative to avoid ending up in Vim when you do a "git commit" without "-m xxx". It's to set Notepas as the default editor : github.com/.../975-gitpad-write-your-commits-in-notepad

  • N0therDev, thanks. You are correct I've changed the article :-)

  • Michel, thanks for pointing that one out. The Git command to change the default editor is:

    git gonfig --global core.editor "path-to-your-editor-here"

Page 1 of 1 (4 items)
Leave a Comment
  • Please add 1 and 6 and type the answer here:
  • Post
Disclaimer

All postings on this weblog, including code, scripts, labs and demos are provided "AS IS" with no warranties, and confer no rights. This weblog does not represent the thoughts, intentions, plans or strategies of Microsoft. It is solely my opinion. Because a weblog is intended to provide a semi-permanent point-in-time snapshot, you should not consider out of date posts to reflect current thoughts and opinions.