Intro to Git

What is Git?

Git is a VCS, or Version Control System. Version Control Systems record changes made to files so that you can compare and track changes over time, revert single files to a previous state, or even revert an entire project to an earlier version.

Installing Git

Windows

There are two good ways to install Git on Windows.

  • The official build is available at git-scm.com/download/win.
  • You can also use the GitHub GUI tool at windows.github.com. During the installation of this tool you can choose to install command-line tools as well (i.e. Git's command-line interface).

Mac

There are three ways to install Git on Mac.

  • A git installer is available at git-scm.com/download/mac.
  • You can download the GitHub GUI tool at mac.github.com. During the installation of this tool you can choose to install command-line tools as well (i.e. Git's command-line interface).
  • You can install the Xcode Command-Line Tools. On Mavericks (10.9) or above you can do this simply by trying to run git from the Terminal the very first time. If you don’t have it installed already, it will prompt you to install it.

Linux

You can use the package management system that comes with your distribution.

On Debian based distributions like Ubuntu, use apt-get:

sudo apt-get install git-all


See Git - Installing Git for more detailed information.

Basic Command-Line Git Usage

Initializing your project

Creating a project from scratch

(On Mac OSX and Linux use the terminal, on Windows use Git Bash)

For this example, we'll create a project to keep track of a todo list, and we'll do it entirely from the command line. The first thing we need is a place to store our todo file, so let's create a new directory. Use the cd command to navigate to the directory you want the project in, and then use the command mkdir todo to create a directory called todo.

Type cd todo to navigate inside our project directory. This way when we initialize the git project it will be in the proper location.

Type git init to initialize the project. This creates a directory called .git. Everything git needs in order to keep track of the project will be stored inside this directory. (A nice side effect of this is that if you ever want to remove your project from git, all you need to do is rm .git.)

Your first commit

Before we can commit something to this project, we need to have something to commit!

Let's create the text file we'll put our todo list in. Type touch todo.txt. The touch command creates a file, but does not open a text editor (like nano or vim would).

Next we need to track todo.txt in git. If you type the command git status, git will tell you the current status of the project. At this point you should see something like this:

On branch master

Initial commit

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

	todo.txt

nothing added to commit but untracked files present (use "git add" to track)

Type git add . to add all files in the current directory (represented as . in the filesystem) to the git project, and stage them as changes in the commit. You will need to use git add each time you commit in order for your new/modified files to be committed. You can use this to your advantage to only commit certain files in any given commit. Now if you run git status, then you should see this:

On branch master

Initial commit

Changes to be committed:
  (use "git rm --cached ..." to unstage)

	new file:   todo.txt

Now that we are tracking our files with git, we can save our changes by committing. Type git commit -m "Initial commit" to commit our added files with the message "Initial commit". If you do not use the -m flag, you will be taken to a text editor to write your commit message. Just write your message and save the file to commit.

So we have our project all set up, and we've made our first commit, but what if we want to add this project to GitHub? Luckily, it's super easy.

Go ahead and create a new repository on GitHub (preferably named the same as your project directory). Then, copy the clone URL.

Type the command git remote add origin <your clone url here>. This adds the remote repository on GitHub as a source for our local repository. Now we can pull from and push to this repository, and potentially collaborate with others on our project. origin is a user-defined name, meaning you can call it whatever you want. This comes in handy for telling multiple remote repositories apart.

Then type git pull origin master. This downloads any new/changed files in the remote repository to our local repository. This means that we'll get those nice README.md and LICENSE files that we created in GitHub. origin master means the remote repository origin (which we defined earlier), and the branch master within that repository.

Now that we have an up-to-date project, type git push origin master. This pushes our new/changed files to the remote repository on branch master.

Recap:
# Create project directory
mkdir todo
# Navigate to project directory
cd todo
# Initialize the git repository
git init
# Create our first file
touch todo.txt
# Track the file (and the contents of todo with git)
git add .
# ^ Add the remote repository as a source
git remote add origin git@github.com:YourUsername/example-project-url.git
# Download the GitHub created files
git pull origin master
# Upload todo.txt
git push origin master

Cloning a project from another source (e.g. GitHub)

Cloning an existing project is super easy. All you have to do is navigate to the directory where you want the project, and then run git clone <your clone url here>. A directory will be created with your project name. cd into your project and you can use git normally.

Project Management

Collaborating

Git can be used as a one-person VCS, but it is also an incredibly powerful collaboration tool. This section elaborates on some of git's collaboration features.

git pull, and the difference between git merge and git rebase

Git pull is used to download changes from a remote repository. The situation in which you would mostly use this is for grabbing changes your teammates have made.

The command git pull actually aliases to two other commands: git fetch and git merge, in that order. In contrast, the command git pull --rebase aliases to git fetch and then git rebase.

git fetch downloads the changes, but does not integrate them into the repository.

git merge and git rebase integrate the changes into the repository in two different ways.

git merge creates a new "merge commit" that ties the local and remote changes together.

git rebase adds the commits from the remote project onto the end of the local project.

Branching

A git branch is just another line of development. Git branches allow you to work on a copy of the repository while you're adding a feature/fixing a bug/etc., and then merge those changes back into the main project once that feature is done. By using branches, you don't have to worry about conflicts during the actual development of the feature, and no unstable code is ever committed to the master branch.

When you're pulling changes from your teammates, all you're doing is merging their branches into yours.

Branch commands

git branch foo will create a new branch called foo.
git checkout foo will update your project to reflect the changes in branch foo, as well as point the HEAD to branch foo. You need to do this in order to make changes to branch foo.
git checkout -b foo will run git branch foo and then git checkout foo.
git branch -d foo will try to delete the branch. If the branch has unmerged changes it will fail.
git branch -D foo will force delete the branch, even if there are unmerged changes.
git branch -m foo will rename the branch.
git merge foo merges branch foo into the current branch.

How branches really work

In most other VCSs, branches are actual physical copies of the entire project. In git, however, branches are just pointers to commits. By default, there is only one branch (master), and therefore only one pointer, and it always points to the latest commit. The HEAD is just git's way of referring to whatever the current branch is. When you git checkout foo, the HEAD points to foo. When you create a new branch the only thing that happens is a new pointer is created (pointing to the most recent commit).

Things get a little more tricky when you start committing to new branches.

Say we have two branches, master and foo. You want to start working on a new feature, so you git checkout foo, and begin editing files. Once you've made your changes, you git commit -m "Made some changes". Now the two pointers (master and foo) are pointing to different commits. master is one commit behind, while foo has changes and is one commit ahead.

At this point, there are a couple things that can happen.

Fast-Forward Merges

If there were no changes to the master branch while we were working in foo, then a fast-forward merge takes place. The master pointer is simply updated to point to the most recent commit in foo, thereby syncing the branches.

3-Way Merges

If there were changes to master while we were working on foo, then a 3-way merge takes place. Git uses the two existing branch tips to create a third commit composed of the merged changes from both branches (hence the name 3-way merge).

Creating a branch, making changes, and merging it to master

These are the commands you would run if you were to create a new branch called new-feature, add a feature to ImportantClass.php, and then merge the branch back to master.

git checkout -b new-feature
vim ImportantClass.php # make changes to a file
git add .
git commit
git checkout master
git commit -m "Added some feature"
git checkout master # so we can merge and delete new-feature
git merge new-feature
git branch -d new-feature # delete branch new-feature since we no longer need it