Get Started with Git
Issue № 317

Get Started with Git

If you’re a designer or developer, you’ve probably heard about Git, and you might know that it has become immensely popular, especially among the open source community. Though it may seem cryptic at first, this version control system could change the way you work with text, whether you’re writing code, or a novel.

Article Continues Below

This article covers why version control is important, how to install the Git version control system, and how to get started with your first repository. Once you start using Git, you’ll want to throw everything into it, from full-blown apps to blog post drafts, because it’s so easy and versatile.

Why do I need version control?#section1

While it may be obvious that large development teams should have sophisticated code-management systems to track releases and bugs, and to avoid stepping on each others’ toes, it might not be immediately clear why individuals would need version control—especially designers or writers.

But take a look at a site like Wikipedia, which is built around collaborative user content editing. One of Wikipedia’s best features is the ability to compare two versions of an article. When you do this, you’re actually performing a diff, one of version control’s central concepts. And when you decide to add or change content, you’re committing a revision. With Git, you can add this Wikipedia-like functionality to any folder, and it will automatically start looking for changes in files contained within it, even if they’re not text files. In Git parlance, that folder becomes your repository.

With Git, though, you can do much more. Branching and merging are powerful tools for integrating changes without compromising more stable work that might, for example, be running on a production website. Remotes are copies of whole repositories that are transferred over a network, and are really helpful for collaborating on projects with people both in your office and over the internet.

No more circus file naming#section2

At the very least, Git can save you the tedium of file name versioning (e.g., avoiding untitled-1-new-v2.html). At best, it can help you work faster by saving your changes, managing different ideas and features in your project, and even serving as a backup strategy. Because Git unobtrusively operates on whole folders, it won’t interfere in your day-to-day work until you explicitly ask it to save a project snapshot at any given time. And permanently removing Git from a folder is just one command away.

Git changes the way you work by making risk cheaper. Unlike haphazard “multiple undo” and “autosave” features common in many editors and graphics packages, Git expects you to control how and when to commit changes to a project, and, in doing so, allows your project to evolve from any one of these changes. Plus, it does this without having any extra administrative debris around versioning (think labels, markers, and extra files) in your project. Any of these changes can be merged automatically, so you never have to repeat yourself or try to figure out how to redo something you overwrote. For this reason, Joel Spolsky called Git a “change control system” instead of a version control system because rather than presenting a project linearly (the “undo” mentality), Git just sees a handful of commits always ready to be reshuffled or squashed together:

When you manage changes instead of managing versions, merging works better, and therefore, you can branch any time your organizational goals require it, because merging back will be a piece of cake.

In the beginning was the command line#section3

Git is unlike most modern OS-native applications in that there is (mostly) no graphical user interface; it is totally controlled via the command line. This may seem daunting at first, but the few common commands will quickly become second nature. If you’re new to the command line, I highly recommend Dan Benjamin’s screencast, Meet the Command Line, as a quick crash course.

For the more visually inclined, there are a few graphical tools to browse and manipulate Git repositories. Git comes with two programs, one called gitk for browsing your project history, and another called git-gui for adding files and creating commits. With these two mini apps, you won’t need to use the command line interface much; but you may be surprised to find that it is actually quicker to use the Git commands than git-gui or gitk, especially if you upload your project to GitHub, which has an excellent source browser. Mac OS X users should check out GitX, a prettier version of gitk/git-gui to visualize and edit repositories. The official wiki has a comprehensive list of graphical interfaces for Git.

Housekeeping, before we get started#section4

When referring to the terminal, I’ll use prompt> to represent the command prompt and what to type after it. Everything under the prompt> line is what will be displayed after you hit return. The Unix shell is terse, meaning, it won’t tell you if something went right—only if something goes wrong. Git is pretty good about telling you what it’s doing, but don’t be alarmed if not every command gives you a response.

Installing Git#section5

There are many ways to get and install Git: The quickest way is to download and and compile it from source—here is a great walkthrough on how to do that in Mac OS X. Alternatively, Mac users can also download the graphical Git installer and use it to install Git like any other Mac program. On Ubuntu Linux, run apt-get install git-core; Windows users should check out msysgit.

The free book Pro Git also has a great section about installing Git on different platforms.

Creating a repository#section6

Now that Git is installed, we’ll get started with a repository (or repo, for short). First, let’s make sure it’s installed properly:

prompt> git --version
git version 1.7.2.2

It’s working! (If you got something different, try re-installing.) Now, we’re ready to create our first repo. First, make a new folder anywhere in the Finder, then navigate to that folder from the terminal:

prompt> cd /Users/alshaw/testrepo

To make this folder a Git repo, just type (Line wraps marked » —Ed.):

prompt> git init
Initialized empty Git repository in /Users/alshaw/»
testrepo/.git/prompt> git status  
# On branch master
#
# Initial commit
#

Behind the scenes, this creates a hidden .git directory inside the folder that will keep track of your changes. Just to make sure, we’ll test it:

prompt> ls -a 
.       ..      .git

Git won’t ever touch your files, or do anything outside the .git directory, unless you tell it to. If you ever decide you don’t want the folder to be a Git repo anymore, just delete the .git folder:

prompt> rm -rf .git

And a quick test that we have really de-Gitted “testrepo”:

prompt> git status
fatal: Not a git repository (or any of the parent »
directories): .git

Another way to start working with a repository is to git-clone an existing repository. Let’s say we’re writing a new web app, and we want to make use of Paul Irish’s shiny new HTML5 Boilerplate as a jumping-off point. Since Paul has his source code in a Git repository on GitHub, we can grab it and start modifying it without leaving the command line:

prompt> git clone git://github.com/paulirish/»
html5-boilerplate.git
Cloning into html5-boilerplate…
remote: Counting objects: 932, done.
remote: Compressing objects: 100% (820/820), done.
remote: Total 932 (delta 477), reused 196 »
(delta 88)
Receiving objects: 100% (932/932), 1.54 MiB | 349 »
KiB/s, done.
Resolving deltas: 100% (477/477), done.prompt> cd html5-boilerplate

Sweet, now we have the whole history of the project! Let’s see what he’s been working on with git-log:

prompt> git log
commit 75b34e5962b155238bcb711e87b34a6409787e78
Author: paulirish 
Date:   Tue Aug 24 22:12:59 2010 -0700    minified dd_belated png… you probably dont »
    need the full one.
[snip]

With git-log you’ll get a list of every commit, the commit’s SHA1 hash (a unique string assigned to each commit), the author, and a message he or she wrote to describe the change.

If we want to see specifically what changed in this version, we can use git-diff to compare it to previous changes. Let’s look at the difference between the current version and an earlier commit. To do that, we’ll use git-diff with the prior commit’s hash id as its argument:

prompt> git diff b59c1cc00e1f6a25a12a224080a70287fa33e4da
[snip]
diff --git a/.htaccess b/.htaccess
index 9879e5e..5451611 100644
--- a/.htaccess
+++ b/.htaccess
@@ -68,7 +68,7 @@ AddType text/x-component htc
 # Disabled by default. # 
-#         Options +IncludesNOEXEC
+#         Options +Includes
 #         SetOutputFilter INCLUDES
 # 
 [snip]
 

This is just an excerpt of that diff, which shows a change in this sample .htaccess file. The author added one line (marked with +) and deleted another (marked with -).

Adding and committing#section7

Now that we’ve taken a look at this repo, why don’t we make some changes of our own to make it work in our app? Let’s say we’re going to be using Google Ads, so we really shouldn’t redefine document.write(). We’ll take that function out of plugins.js. Also, let’s kill the hot pink text selection rule in style.css; not sure what they were thinking with that.

I fire up my text editor, delete those two hunks of code, and save the files. Back at the command line, I type:

prompt> git status
# On branch master
# Changed but not updated:
#   (use "git add ..." to update what »
will be committed)
#   (use "git checkout -- ..." to »
discard changes in working directory)
#
#       modified:   css/style.css
#       modified:   js/plugins.js
#

Cool, Git knows I made changes to those two files. Now we’ll want to commit the changes. But first, just for fun, we can see what Git knows about what we changed. In this commit, we’ve deleted several lines:

prompt> git diff
diff --git a/css/style.css b/css/style.css
index daf8d54..d47b608 100644
--- a/css/style.css
+++ b/css/style.css
@@ -155,11 +155,6 @@ input:invalid {
 .no-boxshadow input:invalid { background-color: »
 #f0dddd; }
-/* These selection declarations have to be separate.
-   No text-shadow: twitter.com/miketaylr/status/12228805301 
-   Also: hot pink. */
-::-moz-selection{ background: #FF5E99; color:#fff; »
text-shadow: none; }
-::selection { background:#FF5E99; color:#fff; »
text-shadow: none; } 
[snip]

Hot pink, be gone!

The staging area#section8

Before we make our first commit, we note that the staging area (also known as the index), is an important quirk about Git that we should know about. (It isn’t in many other version control systems.) If we were using Subversion, we would now svn commit and record our change. In Git, there is one more step, and it’s there for a good reason. Before you can commit a change, you need to git-add the file to what is called the “staging area” so that it can be committed. We could skip this step altogether by typing:

prompt> git commit -am "my message"

(where the -a flag means add). But the staging area is designed so you can craft your commits regardless of when you edit the actual code that composes them. In this round of editing, we changed two totally separate parts of the project—a CSS block and a JavaScript function. Logically, that should be submitted as two separate commits, since the edits are not dependent on one another. The staging area helps you break down your commits by features rather than by when you edited the text files containing them.

Let’s just add the CSS file first:

prompt> git add css/style.cssprompt> git status
# On branch master
# Changes to be committed:
#   (use "git reset HEAD ..." to unstage)
#
#       modified:   css/style.css
#
# Changed but not updated:
#   (use "git add ..." to update what »
will be committed)
#   (use "git checkout -- ..." to »
discard changes in working directory)
#
#       modified:   js/plugins.js
#

Now, since we just added style.css, Git is telling us we can commit it:

prompt> git commit -m "killed the hot pink »
selector"
[master e54357d] killed the hot pink selector
 1 files changed, 0 insertions(+), 5 deletions(-)

And a quick sanity check:

prompt> git log
commit e54357d66498870072c4348168f16cafcd0496e7
Author: Al Shaw 
Date:   Wed Aug 25 22:48:29 2010 -0400    killed the hot pink selector
[snip]

Now you’ll notice that if you run git-status, only plugins.js remains modified. We can then commit it separately with its own message. Because Git is really a change tracker rather than a version tracker, organizing commits by feature allows you to move those features around easily later on. For example, if you want to bring a whole set of features from one branch to another (more on branching below), it’s much easier to have them within their own commits. For this reason, many developers adopt a “commit often” philosophy and go back to organize the commits later.

The staging area as a solution to the “tangled working copy problem” just scratches the surface of Git’s efforts to help you keep your code organized by feature. It gets even better: Despite how it appears, Git doesn’t actually see your code as discrete files; instead, it sees everything in your repository as just one big hunk of text—that’s how it can keep track of diffs (and renames) across files within a repository. Git’s “stupid” nature is part of its good design. This comes in handy when you’re working on two different features that may happen to be in the same file, and you want to break them into separate commits. There is a special option called git add—patch for that, which allows you to “stage” code by “hunk” rather than by whole file. Here’s a good overview from Ryan Tomayko on all the possibilities of the git index, and how to use add—patch.

One more thing about git-add I didn’t mention: If you create a brand new file that Git has never seen before, you’ll also need to use git-add so Git can start keeping track of it. This use of git-add, however, won’t put it directly in the staging area. Here I created a new file in the html5-boilerplate directory, filled in some text, and then saved it in my text editor. Git noticed there’s a new file in the directory that isn’t part of the repo yet:

prompt> git status
# Untracked files:
#   (use "git add ..." to include in »
what will be committed)
#
#       newfile.txt

If I want to commit that, I’ll first have to add it to the repo, then add it again (git add . adds every file it can find) to get it into the staging area. This time since there’s only one file, we’ll use the -a flag to add and commit at the same time:

prompt> git add .
prompt> git commit -am "added some random text"
[master d5c2ed1] added some random text
 1 files changed, 1 insertions(+), 0 deletions(-)
 create mode 100644 newfile.txt
 

With git-init, git-status, git-log, git-add, git-commit, and git-clone you have 90% of the tools you need to get stuff done with Git. But there are still a few more goodies to sweeten the pot.

Branching and merging#section9

At some point, you’ll have an idea for an experimental new feature that is too big for a single commit. In this case, you may want to consider creating a branch. New branches are just copies of the state of a repository at any commit. In fact, we’ve been on a branch this whole time without knowing it. The default branch every Git repository starts out with is called “master.” There’s nothing special about master, but by convention, it is usually considered the “stable” branch alongside a development or experimental branch for new features or bug fixes.

To see all branches, and to create new branches, we use git-branch:

prompt> git branch
* master

There’s only one local branch in our html5-boilerplate example. Let’s make a new one and move to it:

prompt> git checkout -b development
Switched to a new branch 'development'
prompt> git branch
* development
  master

We now have two branches in the local repository. The star marks the current one. Git will always keep track of which branch you’re “sitting on” and it will stay there unless you explicitly checkout another branch. This will be important when we decide to merge.

Note that when you checkout a branch, the files in your working directory will change in place to wherever the code happens to be in that branch. By that, I mean that Git will actually “edit” your files to match the versions in the branch you are checking out, and you’ll see the changes “flip” in your text editor. Nothing will be lost as long as it’s committed (in one branch or another), just make sure you have saved files in your text editor before checking out another branch as your non Git-aware changes could be overwritten.

Let’s suppose we finished our new feature on this new development branch, and want to merge it into our master branch (because it’s ready to ship). To merge, we always checkout the branch we want to merge into and then merge the target branch into it:

prompt> git checkout master
Switched to branch 'master'prompt> git merge development
Updating d5c2ed1..9a66cbf
Fast-forward
 newfile.txt |    3 ++-
 1 files changed, 2 insertions(+), 1 deletions(-)

Now all your changes in development have been merged with master. Since that feature is done, we’ll delete the development branch:

prompt> git branch -d development
Deleted branch development (was 9a66cbf).

Developer Vincent Driessen has a good sketch of a Git branching workflow incorporating infinite master and development branches alongside mini deletable feature branches.

One more hint on branching: git-checkout has another, more controversial use that sometimes doesn’t have to do with branching at all. In fact, it’s usually thought of as a destructive command. If I made a change to newfile.txt, but did not stage it, and then ran git checkout newfile.txt, it would revert that file to the state it was in at the last commit with no undo. Like the “revert” option in Photoshop, it rewinds to the last state you told Git about the file. This can be dangerous but it can also be useful for digging yourself out of a rabbit hole (remember, Git doesn’t care about when you use an application’s save function, only when you deliberately use the commit command).

Likewise, you can use git-checkout to pluck a file out of another branch into your current branch. Say I’m on the master branch and I want the version of a file I committed on development, I could git checkout development myfile.txt and it would replace only that file in the current branch with the development version of the file. Think of git-checkout as a more destructive merge. It won’t ask questions before stomping over your work, so use it with caution.

Next steps…#section10

There’s much more to Git that’s beyond the scope of this article. Working with remote repositories, for example, is a large and exciting aspect of the Git workflow, and the cornerstone of the popular “social coding” site GitHub. Whether you’re a programmer, blogger, or designer, Git is an excellent way to keep track of, share, and backup your work.

Additional resources#section11

17 Reader Comments

  1. I’m a developer of Gitbox – a mac app for Git which makes core concepts easy to understand and work with. In particular, I’m fixing two usability issues: branches and the stage.

    Many people do not create additional branches because of a fear: command-line interface does not make it easy to understand where you are. Also, many do not understand what the stage (index) is and why you should “git add” before committing the stuff.

    To fix these issues, Gitbox has very simple branch controls which let you always see what branch you are on and where will it push: just two popup lists for the local and remote branches and simple pull/push button in the middle.

    The stage is represented by a list of changes with checkboxes showing the staged status. Also, if you simply select some changes and hit the “Commit” button, the selected changes are added to the stage automatically.

    Also, instead of showing incomprehensible trees of branches, it shows a difference between currently selected branches right in the history log (local vs. remote or local vs. other local).

    Check it out on http://gitboxapp.com/

  2. The article fails to mention this, but the easiest way to install and update Git on OS X is by using “homebrew”:http://github.com/mxcl/homebrew. It only takes one command to install homebrew; after that, just enter `brew install git` to install Git.

    After that, you can update Git to the latest version at any time, just by entering `brew update git`.

  3. What’s meant by needing to add a new file twice? In the example below, I add a new file just once and it works fine.

    pre.
    ~/test-repo|master$ touch blah
    ~/test-repo|master$ git status
    # On branch master
    # Untracked files:
    # (use “git add …” to include in what will be committed)
    #
    # blah
    nothing added to commit but untracked files present (use “git add” to track)
    ~/test-repo|master$ git add blah
    ~/test-repo|master$ git commit -m ‘Add blah’
    [master f477efd] Add blah
    0 files changed, 0 insertions(+), 0 deletions(-)
    create mode 100644 blah
    ~/test-repo|master$ git status
    # On branch master
    nothing to commit (working directory clean)

  4. Just a recommendation for those inspired by this article: Travis Swicegood’s _Pragmatic Version Control Using Git_ is a thorough practical and conceptual treatment of Git. His follow-along-at-home examples are actually based on a simple website and therefore readily accessible to a web designer/developer audience. He also spends an entire chapter covering the use of Git in shops that already have SVN in place for version control.

  5. @marcel I should have been more specific. If you add a file and commit it right away, yes you’ll be able to just commit -m. However, if you add an untracked file and then make local changes to it, you’ll need to add once again to stage it. But yes, you are correct.

  6. In the last year I’ve been using Bazaar to manage html, css and js. Bazaar is a non-centralised VCS developed by Canonical and used in the development of Ubuntu.

    I agree with Linus Torvalds that a distributed revision control has huge advantages over a centralised revision control. The problem is that there are too many popular distributed vcs’s out there. If you join a new team and start a new project, everybody will want to use the tools they are familiar with and in the end you might have to learn a new tool.

    I know projects that use Git, but also Bazaar and Mercurial. And there are others… And on the centralised side you have Subversion, CVS…

    Compared with Bazaar, the concepts behind git are more complex and it takes longer to learn how to use git than Bazaar. Bazaar can also be used as a centralised VCS.

  7. In theory Git looks like everything we want. We are stugging to impliment it though – we get mysterious error messages when trying to init git on a new machine (windows) or trying to merge. Finding a clear simple guide is difficult and the git UI seems suspect. We are trying to figuer out whats wrong, but lack of a centralised forum is not helping. We have yet to find a good forum. We’d even be happy to host one.

  8. @Osvaldo: There are a lot of DVCSs at the moment, but I think it’s clear that git is in the lead, so I think it’s an easy choice to make as far as deciding which to invest in. And git can be used like a centralised VCS if you wish – after all, look at github.

    @sad developer: As far as I’m concerned, either “msysgit”:http://code.google.com/p/msysgit/ or “Cygwin”:http://www.cygwin.com/ are the way to go with git on Windows. msysgit is very straightforward to install, but Cygwin gives you all the other Unix tools should you decide to go further down the Unix/Linux rabbit hole.

  9. I’m the only designer in my office that uses Git. It’s too technical for the average artsy-fartsy type to “get” git. I wish there was “Mindless Git”. For instance, “Dropbox”:dropbox.com does versioning on its synced folders. I know every save gets versioned away in the ionosphere, mindlessly. Mac needs that built-in. Time Machine isn’t frequent — or powerful — enough.

  10. Good article, Al. I’ve been reading about Git for ages and been meaning to get around to trying it and after reading this article (or should I say while), I finally have. Now I’ve just got to start using it. 😉

  11. You’re right, you don’t have to be a code writer to need a tool like this. As a web developer, I’m often creating dated filenames, dated directories, pre, post, active, you name it…just to try and keep up with everything that’s archive, current, and future.

    I may give this a rey.

  12. I don’t think that’s really getting started. Maybe you like the command line a lot but, for most tasks, Git GUI is sufficient and is far more illustrative of what Git actually does, especially for those new to VCSs.

    I love Git and use msysgit every day. I don’t have to use the command line very much to be productive.

    I like my favourite bash commands set as (often global) tools in the in the Tools menu. I have *stash* _git stash save_, *unstash* _git stash pop_, great for quickly stopping what you’re doing to do something else then, going back to it without any branching. For regular exporting, I use some variation of _git archive –format=zip -9 master > ../latest_version.zip_, that one archives adjacent to the repository directory.

  13. Thanks so much for this article, I finally clicked on the ‘staging area’ and so much more of git makes sense now.

    The key thing was your explanation of how to turn a somewhat tangled set of changes into a sequence of well-organised commits.

    The “double-add” discussion with Marcel underlines this nicely – to a new user it would be easier to understand if the initial add was called something like “git-include” (ie include this file in the repository) that auto-committed the change. Then the need for a “git-add” later, if changes were made to the file, would seem natural.

    This is the first time I’ve seen (in a *lot* of reading about git) such a vivid example of what the staging area is good for. I encourage you to try to get this example into the git reference documentation; it’s one every user of a text editor can relate to.

  14. I would imagine what they were thinking with the hot pink was to remind people you can style the selection, being a starter’s kit and all. Regardless it’s still a good example.

Got something to say?

We have turned off comments, but you can see what folks had to say before we did so.

More from ALA