Introduction to Git, Part 1

This entry is part 1 of 2 in the series Introduction to Git

Introduction to Git

Git is a (distributed) version control system. What is that? A version control system is software that allows a programmer to track and manage the history of a project, where such a project could be a single file, a set of files, or an entire open source project with multiple programmers contributing from around the world.

The distinction of “distributed” means that there is no central server where the source code and history of a project lives. When a Git project is cloned (“clone” is Git’s word for the initial checkout of a project), you receive the entire history of the project from the current state all the way back to the beginning of time. Having the entire project stored locally on your computer without a central server coordinating everything makes for extremely fast merging, diffing, and log history lookups.

Some of the more commonly used version control systems that you have likely heard about are CVS and Subversion. This tutorial will take a “forget everything you know about CVS or Subversion” approach. As someone who has used all three of these systems in the professional realm, I can testify that some knowledge of CVS or Subversion can be useful when approaching Git, but it is not necessary. The best way to learn Git is to start using Git for what Git is.

Why use Git?

That’s a perfectly cromulent question. If I am just one person working on my own website, why should I bother with version control? I have a pretty good memory and I know others won’t be overwriting my code.

Maybe you have a set of files for a website you are developing for a client, looking something like this.

sean@beerhaus:~/Workspace$ ls
images/  templates/  index.php.save1  index.php.save3
js/      index.php   index.php.save2  index.php.save4

Here, index.php is your current file and index.php.save# are a set of backups from previous days’ work.

Now you are editing index.php. You have just added a pretty neat feature after an overdue but deserved moment of inspiration. To be smart, you make a backup of this file called index.php.save5. The next day you go back to work on index.php and you decide the new feature from yesterday isn’t really going to work and you remove it from the file. A few weeks go by and by this time you’ve saved index.php.save27. The current state of the project is pretty stable so you no longer need the previous 27 saved files, and so you delete them all.

Several days after your cleanup you feel that feature from index.php.save5 deserves a second chance, but now it is gone forever. Sure, you might have some extra backup copies, and you might even have a file undelete tool. But is that really the best way to be managing your source code?

The problem gets worse when you add more people to your project. Even with two people working on the same project, there will be some unintentionally deleted and overwritten files. Maybe you email tarballs of the source code back and forth and you can look up and old email to get the archive with files you have just deleted. Good luck.

This is the part where 99 out of 100 tutorials would predictably repeat the prized cliche “enter Git.”

How to use Git

The first step in using Git is to get Git. If you are using an a variety of Linux, this is pretty easy. (Related fact: Git was initially designed and developed for distributed development on the Linux kernel by the same guy who created the kernel, Linus Torvalds.) Whatever distribution of Linux you are running, the package you are going to need will most likely be called “git” or “git-core”. If you are using Windows or Mac, or would just like to build Git from source, see www.git-scm.com for download and installation options.

Creating a Repository

Once you have Git installed you’ll want to add some information about yourself. This will be helpful in identifying who has committed what code when looking at the Git log for history information.

sean@beerhaus:~$ git config --global user.name "FirstName LastName"
sean@beerhaus:~$ git config --global user.email "your@email"

Now it’s time to create a repository. There are two ways to do this, but essentially one command. If you are starting a new project from scratch and you would like Git to look after it during its whole life span, you can create your directory that will contain all project files and initialize the directory for use with Git:

sean@beerhaus:~/$ mkdir new_project
sean@beerhaus:~/$ cd new_project/
sean@beerhaus:~/new_project$ git init
Initialized empty Git repository in /home/sean/new_project/.git/

You now have an empty Git repository ready for use. If you run a listing of all hidden files in your new directory, you will notice the hidden directory .git was created:

sean@beerhaus:~/new_project$ ls -al
total 12
drwxr-xr-x 3 sean sean 4096 2011-11-19 16:09 .
drwxr-xr-x 5 sean sean 4096 2011-11-19 16:09 ..
drwxr-xr-x 7 sean sean 4096 2011-11-19 16:09 .git

The .git directory is where Git stores all the information and history it needs to track your repository, and so it’s best to leave it alone.

git init will also work if you have a directory of existing source code. Simply enter your directory and run git init as I did in this example.

Adding/Staging Files

You should still be in your new_project directory that you’ve just initialized for Git. In version control terminology, this is now called a working directory, meaning it is a directory that is under the watch of some version control system.

Let’s create some files for Git to track, starting with a configuration file. Create the file config.php with the following contents in your editor of choice:

<?php
$database = array(
    "driver"   => "mysql",
    "host"     => "locahost",
    "username" => "user",
    "password" => "pass",
    "database" => "new_project");

Once you have saved the file as config.php we can run another Git command, git status.

sean@beerhaus:~/new_project$ git status
# On branch master
#
# Initial commit
#
# Untracked files:
#   (use "git add <file>..." to include in what will be committed)
#
#	config.php
nothing added to commit but untracked files present (use "git add" to track)

The default branch in Git is known as master. This is the same idea as “trunk” in other version control systems. A branch is simply a line of development that Git is tracking.

Untracked files are files that exist in your working directory, but are not yet tracked by Git because you have not yet told Git to track them.

The output of git status also provides helpful messages, like the message one line down:

(use "git add <file>..." to include in what will be committed)

Go ahead and add congif.php file to Git’s list of tracked files.

sean@beerhaus:~/new_project$ git add config.php

Now if you run git status again you’ll see what has changed.

sean@beerhaus:~/new_project$ git status
# On branch master
#
# Initial commit
#
# Changes to be committed:
#   (use "git rm --cached <file>..." to unstage)
#
#	new file:   config.php
#

config.php is now being tracked by Git, as you can see by the change from “untracked file” to “new file”.

With Git, adding files in this fashion is known as staging. The staging area is the step after a file has been added but before it has been committed. The term adding does not have to refer to a new file. It can also mean a set of changes made to an existing file that will be included in the next commit. The staging area allows us to pick and choose which files to include in a commit before the commit takes place.

Committing Files

Now you can commit the file. Committing a file is how you tell Git to record a “snapshot” of the current state of your project. It is important that with each commit you provide a commit message. The message is helpful to remind yourself (or others) later what the purpose of each change was. You should keep it short but informative.

The quickest way to provide a commit message is to use the -m option with the git commit command. If you leave the -m option out of the command, an editor window will pop up and you can type your commit message there.

To configure which editor will be used, you can run git config --global core.editor vim. In my case I use vim, but emacs, pico, or any other editor should do.

sean@beerhaus:~/new_project$ git commit config.php -m "Initial commit. Added a configuration file."
[master (root-commit) c1d55de] Initial commit. Added a configuration file.
 1 files changed, 7 insertions(+), 0 deletions(-)
 create mode 100644 config.php

Now if you run git status again you’ll get a message that tells you there have been no new changes since the last commit.

sean@beerhaus:~/new_project$ git status
# On branch master
nothing to commit (working directory clean)

Viewing Project History

The git log command is a very helpful tool for viewing the timeline of your project. You can see each commit in detail, including the date and and who made the commit.

sean@beerhaus:~/new_project$ git log
commit c1d55debc7be8f50e363df462f84672ad029b703
Author: FirstName LastName <your@email>
Date:   Sat Nov 19 16:45:35 2011 -0400

    Initial commit. Added a configuration file.

There are a few things to note here:

  1. The name and email address is the information you provided with git config.
  2. The commit message is the message you provided in the first commit.
  3. The word “commit” is followed by a 40-digit hex string.

The 40-character string of hexadecimal numbers is known as commit hash, in reference to the SHA1 cryptographic hash function used to generate it. All information related to a commit is stored in a commit object. The commit hash is the output of the hash function applied to the contents of the object, and is then used as a unique reference to that particular commit.

If you wanted to look up the log entry for a single commit, you can provide the commit hash:

sean@beerhaus:~/new_project$ git log c1d55debc7be8f50e363df462f84672ad029b703

To see which files were involved in a commit, you can use the --stat option:

sean@beerhaus:~/new_project$ git log --stat c1d55debc7be8f50e363df462f84672ad029b703

The log message now contains:

 config.php |    7 +++++++
 1 files changed, 7 insertions(+), 0 deletions(-)

Viewing Commit Diffs

Now lets makes some changes to config.php in order to see what git diff has to offer. Start with a simple change; change the database username to “Foo”. When you save the file and run git status, this time you’ll see config.php is now in the modified state:

sean@beerhaus:~/new_project$ git status
# On branch master
# Changes not staged for commit:
#   (use "git add <file>..." to update what will be committed)
#   (use "git checkout -- <file>..." to discard changes in working directory)
#
#	modified:   config.php
#
no changes added to commit (use "git add" and/or "git commit -a")

To see what has been modified, use git diff.

sean@beerhaus:~/new_project$ git diff
diff --git a/config.php b/config.php
index ab6e11d..02d30f8 100644
--- a/config.php
+++ b/config.php
@@ -2,6 +2,6 @@
 $database = array(
     "driver"   => "mysql",
     "host"     => "locahost",
-    "username" => "user",
+    "username" => "Foo",
     "password" => "pass",
     "database" => "new_project");

Your changes are pretty easy to spot. The leading minus tells you the line has been removed, and the leading plus tells you the line has been added.

The command git diff by default will compare the current state of your project with the previous commit. You can pass arguments to git diff command, such as a commit hash or the special pointer HEAD, which refers to the most recent commit of your current project.

Go ahead and commit the changed file so you can compare some commit hashes.

sean@beerhaus:~/new_project$ git commit -am "Changed database username to Foo."
[master e69a7f9] Changed database username to Foo.
 1 files changed, 1 insertions(+), 1 deletions(-)

When you run git log this time, you’ll see a timeline of changes building up.

sean@beerhaus:~/new_project$ git log
commit e69a7f9b3b55c116a5c2edf730cd03df7e093eda
Author: FirstName LastName <your@email>
Date:   Sun Nov 20 14:16:43 2011 -0400

    Changed database username to Foo.

commit c1d55debc7be8f50e363df462f84672ad029b703
Author: FirstName LastName <your@email>
Date:   Sat Nov 19 16:45:35 2011 -0400

    Initial commit. Added a configuration file.

When you run git diff using the two commit hashes, the output is identical to the diff you looked at before the last commit.

sean@beerhaus:~/new_project$ git diff c1d55debc7be8f50e363df462f84672ad029b703 e69a7f9b3b55c116a5c2edf730cd03df7e093eda
diff --git a/config.php b/config.php
index ab6e11d..02d30f8 100644
--- a/config.php
+++ b/config.php
@@ -2,6 +2,6 @@
 $database = array(
     "driver"   => "mysql",
     "host"     => "locahost",
-    "username" => "user",
+    "username" => "Foo",
     "password" => "pass",
     "database" => "new_project");

Try it again using the --color option. This makes changes a little more easier to see.

Summary

After getting used to Git and its cycle of file edits, git add, and git commit, you will never look back to the days of using file backups or your favorite editor’s undo feature as a substitute for proper version control. In this article I showed you the essential commands you’ll need to get started with Git. Other topics including branching, merging, and remote repositories will follow.

Introduction to Git

Introduction to Git, Part 2 >>

Win an Annual Membership to Learnable,

SitePoint's Learning Platform

  • Bombero

    Thanks for clear explanations of the basics. Now I think I’ll start using git.

  • http://www.eastdevonit.co.uk Daniel

    Thanks Sean, I’ve been trying to get my head around Git for some time, and this post has given me the best understanding of it!
    The only thing I’m still not clear on is if two people are working on the same file, can git merge the two without everything going horribly wrong!?!

    • http://www.yoga-singapore.com Kian Ann

      I’ve a feeling that GIT only helps to identify conflicts (i.e. two people editing the same file) but its up to the user to combine the code… I’m looking fwd to part 2!

    • Sean Hudgston

      It is possible for git to merge two people’s edits without going horribly wrong, but it usually requires human intervention. This is covered in part 2.

  • http://www.yoga-singapore.com Kian Ann

    BTW – what is the “standard” way of coding and deploying changes to a website? Since I have a good Internet connection most of the time and work with multiple computers, I prefer to just set up a dummy domain and hosting to work on a “live” staging site, instead of on my local computer on XAMPP or MAMP. I’ve found this to be useful because its easier to mimic the deployment configuration and not be involved in the hosting configuration and settings.

    Is there anyway GIT can be used to track changes in this scenario?

    • http://eggdude.com taiger

      I recently switched from WAMP to running kubuntu on to an old laptop with Samba. I can still use photoshop on my XP machine but with a better dev environment than WAMP.
      I think it is possible to use git outside of linux but its not ideal.

  • websage

    Very good tutorial, though what I am always experiencing issues with using git through ssh with multiple user accounts where it really gets interesting. That would be an interesting subject for part 2.

  • Fellow traveller

    Hello, I think You made a mistake when talking about git log –stat c1d55debc7be8f50e363df462f84672ad029b703 etc. Revision filtering is done differently with git log. I’m not sure, so please correct ME if I’m wrong :).

    • Sean Hudgston

      Yes, in my example git log –stat SHA showed only one commit because of the limited history I was using. If there were hundreds of commits, you would have seen your SHA target at the top of the list followed by every other commit made before it.
      To get the same output as I showed in a repository with hundreds of commits, you can add the -n[#] flag to limit the log output.
      git log –stat -n1 c1d55debc7be8f50e363df462f84672ad029b703

  • Tim

    Shame this tutorial is for Linux. Guess I’ll need to find one for Windows as that’s what I develop on.

    • http://zaemis.blogspot.com Timothy Boronczyk

      @Tim
      You can still follow along with this tutorial even if you are on Windows (I’m a Windows user 40% of the time myself, the other 60% spent with various Linux distributions). If you follow the first portion (Download and Install Git) of the guide at GitHub Set Up Git on Windows you’ll have access to the Git Bash shell. That will provide you with a unix-like environment to use commands like ls and mkdir. Or, you can also use the Windows command console; all the git-specific commands work the same.

      • Tim

        @Timothy Boronczyk
        Excellent, thanks for the tip, I’ll check it out. I use Linux for leisure and am forced to use Windows for work so that’s an ideal solution.

  • greg

    part 2 please

    !:-D!

  • Dennis

    Great article, but I would strongly advice against having your config in your repo, also if it eventually would get up on a remote. Instead, add the config.php to your .gitignore and keep a config.sample.php the same place, to provide a template for other developers.