Increasingly, if you want to collaborate with other web developers on any kind of project, GitHub is where you’ll go. GitHub, at its core, is an online host of Git repositories. What’s Git, you ask? Git is a revision control system (also called a source code management, or version control system). If you’ve ever found yourself working on a site and had a number of folders, each named mysite_version1, mysite_version2, and so on, you’ve inadvertently created your own revision control system, albeit a very inefficient one.
Using Git (or any other revision control system) allows you a far greater degree of control over those revisions, and it also greatly facilitates collaboration between different developers (often in different locations) working on the same project. Let’s look at a few situations where revision control comes in really handy. Let’s say you have a website, and you want to experiment with a different layout. Because this will involve rewriting big chunks of your CSS, you’d normally have a few options: create an entirely separate copy of the website in a separate folder, or perhaps just comment out all your existing layout CSS temporarily.
Both of these approaches have significant drawbacks: in the first case, you might wind up making changes to other aspects of the CSS (say, fonts or colours) in the primary (live) version of your site, which you’d lose if you simply copied your alternate layout CSS over the top of it when you were done. In the second case, you’d actually be unable to make changes to your current layout until you were done with the new one, since they both live in the same file.
It only gets worse if you’re working on a team: another developer may have made changes to the main CSS file, unbeknown to you, which you’d then accidentally squash when you copy in your updated version of the file. Messy. Revision control solves these issues and makes it easy to combine different changes made to the same files (even when those changes are made in parallel by multiple developers), experiment with alternate versions of your code while retaining the ability to switch back to the primary version painlessly, and keep a complete log of all the changes you’ve made.
Before we can grab a project on GitHub and start contributing to it, we’ll need to learn a bit about how Git works independently of GitHub.First things first, that means installing Git. Head over to git-scm.com/downloads and follow the instructions for your platform of choice. For all the examples in this article, we’ll be working with Git from the command line. On Linux and Mac, this will be your built-in terminal application. On Windows, use the Git Bash application provided by the Git installer.
Before we start, we have a few quick configuration steps to go through. Git not only stores a record of the changes made to a project, but a record of who made those changes. For this to work properly, we first need to tell Git who we are.
Open up your terminal (or the Git Bash program if you happen to be using Windows), and run the following two commands, using your own name and email address:
001 git config --global user.name “Louis Simoneau” 002 git config --global user.email “email@example.com”
Now you’re ready to start using Git!
Let’s create a simple Git repository that we can use to learn all of Git’s basic commands.
Create an empty directory, and then navigate to it in your terminal. Windows users can right-click on the directory and select the Git Bash option to open a new Git terminal in that directory. For these examples, we’ll create a directory called hello_git.
The most basic Git command, and the one you’ll likely find yourself using the most often, is:
001 git status
This will give you information about the status of the current repository. Go ahead and try it out in the new hello_git directory: type git status and hit Enter.
001 $ git status 002 fatal: Not a git repository (or any of the parent directories)
Whoops! Our new directory isn’t a Git repository (yet), so Git is complaining that it can’t tell us the status.
Fortunately, turning our newly-created directory into a Git repository couldn’t be easier. Simply type git init and press Enter:
001 $ git init 002 Initialized empty Git repository in c:/Users/Louis/hello_git/.git/
If you’re using the Git Bash terminal on Windows, you’ll now see the word master in parentheses at the end of your command prompt. This refers to the current branch your repository is on, but don’t worry about that for now. We are going to discuss branches in more detail later on. Now that your directory is a Git repository, try running git status again, and this time you’ll be rewarded with a bit more information:
001 $ git status 002 # On branch master 003 # 004 # Initial commit 005 # 006 nothing to commit (create/copy files and use “git add” to track)
The key bit there is nothing to commit. This is Git’s way of telling us that there’s nothing new in the directory for it to track (in fact, there’s nothing at all in the directory, but the message would be the same if nothing had changed).
The basic unit of change that Git deals with is a commit. Your basic workflow when working with Git will involve making changes to one or more files, then committing those changes to Git. This creates a new commit, with a unique identifier that allows you to access it later on (for example, to return your repository to the state it was in at that commit).
Let’s create the first commit for our hello_git repository. Create a file in the directory with some text in. If you’re familiar with command-line editors like Vim or nano you can use those, but otherwise simply create a file in your editor of choice and save it inside the hello_git directory.
Let’s say we created a file called hello.txt with the contents Hello, Git!. Now, when we run git status again, it notices our new file and lists it in a section called Untracked files:
001 $ git status 002 # On branch master 003 # 004 # Initial commit 005 # 006 # Untracked files: 007 # (use “git add <file>...” to include in what will be committed) 008 # 009 # hello.txt 010 nothing added to commit but untracked files present (use “git add” to track)
On the last line of code above, Git is informing us that there’s nothing to commit, even though we’ve added
a new file. This is because Git won’t track every file in the directory by default: it is up to us to tell it which
files to track. As the output above states, we are going to need to use the git add command to tell Git to track our file.
Creating a commit involves two steps: first, stage the files you want to commit to the staging area, and second, commit them.
To stage files for a commit, go ahead and use the git add command:
001 git add hello.txt
This produces no output, but you can simply run git status again to verify that it worked. Now you’ll see the hello.txt file in the changes to be committed section. Now that the file is staged, we want to commit them. Each commit in Git is accompanied by a message explaining what changes it contains. To add the message, include it in quotes after the -m flag, like so:
001 git commit -m “initial commit, added the hello.txt file”
This produces the following output:
001 $ git commit -m “initial commit, added the hello.txt file” 002 [master (root-commit) 4f73b98] initial commit, added the hello.txt file 003 1 files changed, 1 insertions(+), 0 deletions(-) 004 create mode 100644 hello.txt
Git provides a brief description of all the changes that are contained in this new commit, like how many files were changed, and how many lines of code were inserted and deleted.
At any time in a Git repository, you can see a history of all the commits leading up to your current state by running the git log command. At the moment, our repository only has one commit, so running git log only shows us that commit:
001 $ git log 002 commit 4f73b989922b0ec6e528209b95cbd99c9f28858e 003 Author: Louis Simoneau <firstname.lastname@example.org> 004 Date: Sat Jul 14 13:57:02 2012 +1000 005 initial commit, added the hello.txt file
Git uses long alphanumeric strings to uniquely identify each commit, ours is 4f73b989922b0ec6e528209b95cbd99c9f28858e. (The hash will be different on your machine.) You can see a shortened version of this string (containing only the first few characters) in the output from the git commit command.
You can use the git show command to display all the changes made in a given commit by providing its identifier (the short version works fine here too):
001 $ git show 4f73b989922b0ec6e528209b95cbd99c9f28858e 002 commit 4f73b989922b0ec6e528209b95cbd99c9f28858e 003 Author: Louis Simoneau <email@example.com> 004 Date: Sat Jul 14 13:57:02 2012 +1000 005 006 initial commit, added the hello.txt file 007 008 diff --git a/hello.txt b/hello.txt 009 new file mode 100644 010 index 0000000..670a245 011 --- /dev/null 012 +++ b/hello.txt 013 @@ -0,0 +1 @@ 014 +Hello, Git!
Lines preceded with a plus symbol (+) were added in this commit. Lines preceded by a minus (-) were deleted (our example commit only has one line added, and none removed). If you make changes to a line, Git will show you the old version of the line as deleted and the new version as added, so you can easily compare both versions to see the changes.
That’s all there is to committing changes to a Git repository; we edit some files, add them to the staging area with git add <filename>, then commit them with git commit -m “<commit message>”.
Then, at any time, you can review the history of your changes with git log, or review the changes made in a specific commit with git show <commit>.
Branching and merging
So far we’ve only seen the simplest features of Git: adding files to a repository and committing changes. If that’s all Git was capable of, it probably wouldn’t be worth using. Now it’s time to look at Git’s real killer features: branching and merging.
Git branches allow you to have several versions of your project side-by-side. For example, if you’re working on an experimental feature, you can do all that work on a branch. If you discover a bug in your application that needs fixing urgently, you can simply save your work on the experimental branch by committing it, switch back to the main branch, commit your fixes there, and deploy the fixed code. When you switch back to your experimental branch, all your work will still be there.
When you’re done working on your new feature, you merge that branch back into the main branch. Git will automatically combine the changes made on each branch for you. If there are conflicts – if, for example, you made different changes to the same line of the same file in both branches – you can pick which change you want to keep.
As we noticed earlier, our Git repository is currently on the master branch: this is the default primary branch for any repository. To switch between branches, you use the git checkout command, followed by the name of the branch you want to check out.
Let’s create a new branch in the hello_git repository. To do this, we pass the -b flag to git checkout:
001 $ git checkout -b test_branch 002 Switched to a new branch ‘test_branch’
The new branch will inherit all the commits of the branch you’re on up to this point. Think of it like a real branch on a tree, where the bottom of the trunk is
the first commit. The new branch will have all the history down to the bottom of the tree, but any new commits on the master branch (known as the trunk) won’t be visible on the branch, and vice versa. So if you type git log at this point, you’ll still be able to see your initial commit.
To verify that you’re on the new branch, you can either type git status again, or use the git branch command. git branch will give you a list of all the branches of your repository:
001 $ git branch 002 master 003 * test_branch
Now let’s make some changes on our new branch. Create a new file, called goodbye.txt, with a line of text in it, and commit it:
001 $ git add goodbye.txt 002 $ git commit -m “add goodbye message” 003 [test_branch 1e1285e] add goodbye message 004 1 files changed, 1 insertions(+), 0 deletions(-) 005 create mode 100644 goodbye.txt
Verify that your new commit is there using git log, then switch back to master by typing:
001 git checkout master
At this point, if you inspect the directory, you’ll note that goodbye.txt is nowhere to be found. That’s normal; it’s tucked away on the test_branch branch. If you want, you can switch back and forth from master to test_branch to see the file appear and disappear. The same thing would be happening to the contents of your files if you had changes to them on a branch. When you check out a branch, the files on disk will be changed to match the latest commit on that branch. Let’s say that we’re satisfied with the new feature on test_branch, and we want to incorporate it into the project. We want to merge the test_branch branch into the master branch.
Make sure you have master checked out, then type:
001 git merge test_branch
Now all your changes to test_branch will be brought over into master. You can verify that this is the case with git log:
001 $ git log 002 commit 1e1285e896491b7757987f091682a17613d5f74d 003 Author: Louis Simoneau <firstname.lastname@example.org> 004 Date: Sun Jul 15 11:46:52 2012 +1000 005 add goodbye message 006 007 commit 4f73b989922b0ec6e528209b95cbd99c9f28858e 008 Author: Louis Simoneau <email@example.com> 009 Date: Sat Jul 14 13:57:02 2012 +1000 010 011 initial commit, added the hello.txt file 012 013 Remember: when merging, you should start from the branch you want to merge the changes into.
Okay, now that we have learned how to commit and review changes, and switch and merge branches, we’re finally ready to start sharing our code with the world, using GitHub.
We’ll first learn how to upload our new repository to GitHub and keep it up to date with our changes, and then we’ll have a quick look at contributing to some of the existing projects.
Head over to github.com and sign up for a new account if you don’t already have one (GitHub is free for open-source projects, you only need a paid account if you want to keep some of your repositories private). Then locate the link to add a new repository (it’s a little icon next to your username in the top-right, with a book and a plus icon) and click it. Enter in the name for your repository (in our case, hello_git), and submit the form.
As soon as you’ve created your repository, GitHub helpfully provides a page of instructions for setting up a new repository or uploading an existing one. Jump to the section titled Existing Git Repo? and follow those instructions. After entering the directory where your existing repo lives, there are two more steps: git remote add and git push -u:
001 git remote add origin firstname.lastname@example.org:rssaddict/hello_git.git 002 git push -u origin master
In Git terminology, a remote is a version of your repository that’s stored elsewhere. This could be on a co-worker’s machine, on a local server, or somewhere on the Internet. In this case, it will be hosted by GitHub.
The first command, git remote add, is telling Git that our repository has a remote, called origin, that lives at the provided address (this will be different for your project, since it contains your GitHub username.)
The next command, git push, is telling Git to take the local commit history on the master branch, and send it to the master branch of the remote named origin (which is GitHub.) The -u option is only required the first time you push your changes to GitHub.
When you run the git push command, Git will ask you for your GitHub username and password. Type them in, and your code will be pushed to GitHub. You can see it published on the site by refreshing your repository page.
Contributing to an existing project
Now that you know how to upload your own projects to GitHub, it’s time to learn how to contribute to other people’s projects. After all, that’s exactly what open source is all about!
Of course, you can’t push directly to a project you don’t own – that would be chaos. However, GitHub introduced the concept of forking – making a copy of a GitHub repository inside your own account.
To fork a project, just navigate to that project’s page on GitHub and click the fork button in the top-right corner. As an example, let’s try forking Modernizr. Go to github.com/modernizer/modernizer and click Fork. After a few seconds, you’ll land on your own copy of the Modernizr repository.
Now you need to download a copy of the repo to your computer so you can work on it. Copy the URL from the box at the top of the page (it will look something like https://github.com/rssaddict/Modernizr.git). Open your home directory in the terminal, and issue the git clone command, passing in the GitHub URL you just copied:
001 git clone https://github.com/rssaddict/Modernizr.git
This will copy the entire repository to a directory with the same name on your machine. You can now make changes, commit them, and push them back up to GitHub however you like.
If you make changes that you think would be valuable for all users of the project, or fix a bug, you can submit a pull request, which invites the owners of the repository you forked to incorporate your changes. There’s a pull request button conveniently located at the top of the page when you’re viewing any of your forked repositories.
Now that you’ve mastered the basics of Git and GitHub, you’ll be in a far better position to contribute to open-source web projects. Not only can you share your own work with others, you’ll also be able to help out the community by fixing bugs and improving on the work of those who’ve come before.
This article has only skimmed the surface of what’s possible with Git, and if you want to start using it as part of your workflow you’ll have a bit more learning to do. Here are some of the best places to polish up on your Git skills:
git help: type git help in your terminal to get a list of available commands, and git help <command> to get a detailed description of the command and all the available options.
The Git Book: the Git website has an entire book about Git, available completely for free online. This is a fantastic resource that goes into a lot more detail about Git. git-scm.com/book.
Git Immersion: Git Immersion is a fantastic online tutorial that walks you through a series of short exercises to learn all of Git’s features, from the most basic to the more advanced. gitimmersion.com.