Purpose

After reading this you should understand the git repository model. Also you should be able to init, clone, push, pull, fetch, merge, checkout, and commit documents.

Making a New Repository

git init

To start a new project with git you can use either init. If you want to create a new project, then create a new folder, or go into an existing folder that you want to turn into a git repository. From inside that folder, run the command

git init
This creates a new git repository! Note that unlike other version control systems such as SVN, the repo is living in your folder. In fact there is a .git directory, if you run ls -a you can see it (directories beginning with a dot are usually not reported by the ls command). In fact you can run the command ls .git and see that there are some folders in this directory. It is not important what these folders do, what is important is realizing that the whole repository is stored in this .git folder. What is not the repository is whatever files or folders that appear when you type ls. Nor is it located on some server, or even somewhere else on this server.

git clone

Perhaps you want to collaborate with somebody, or just want a copy of somebody else's work. If they are storing their work in a git repository, you can clone that repository to get a copy of it. Let say there are some design specs that you need in /home/lcalrissian/falcon on your local computer, and you want to create your copy. To create a copy into your home directory, you can run

git clone /home/lcalrissian/falcon
this creates a new folder falcon in the directory you ran the command from. Alternatively, if this is stored on another server, say docs.cloudcity.com you can run the command,
git clone git@docs.cloudcity.com:falcon
Note : the command differs by server and setup, read the server's or project's documentation to clone the repository. Once again, this creates a repository in falcon/.git.

Managing your Repository

Adding Files and Making Changes

Adding data to the repository requires two steps, first you have to stage your changes. Then you commit staged changes to the repository. If you have a file jabba/debts.txt, you can stage that file as

git add jabba/debts.txt
You can check the current state of the repository at any time with
git status
and the new data that is added with
git diff --staged
Commit the changes with
git commit
or unstage the changes by using
git reset -- .
or just that particular file
git reset -- jabba/debts.txt

Git doesn't differentiate new files or changes to files. Git doesn't keep track of files, instead it keeps track of the contents of the files. Therefore modifying the data requires the same steps as adding a new file.

Removing a file

To tell git to remove a file is just as easy. If you no longer need a file, just say, jabba/debts.txt run

git rm jabba/debts.txt
to commit the changes you can run
git commit

Checking Out an Old Commit

If it turns out you need an older version of a file, you can always check it out again. For instance if you need to get the file jabba/debts.txt back, you can run

git checkout HEAD~1 jabba/debts.txt
this checks out the jabba/debts.txt from the repository into your working directory. The HEAD~1 is shorthand for the previous commit, (HEAD~2 would be two commits ago). If you made some changes to a file, but don't like them, you can just run
git checkout jabba/debts.txt
which will get you a fresh copy of what you started with. Alternatively you can look up the commit name, and reference that instead. Since you probably don't remember commit names, you can run
git log
to look at the commit log, then run
git checkout 1337 jabba/debts.txt
assuming 1337 is a commit hash (or a unique beginning of one). If you know that you will be using a commit in the future you can tag it, for instance
git tag -l 'ep_IV'
and then instead of using the hash, you can just use the tag name,
git checkout ep_IV jabba/debts.txt

Branching

Sometimes you will want to make changes to the repository and keep a clean version around as well. You can use branches to do so. For instance if you want to modify the hyperdrive, but want to have a working copy at all times, you can run

git branch hyperdrive
at any time you can switch to that branch by using
git checkout hyperdrive
and view a list of all branches with
git branch
(Note : the default branch is master).

Making Changes Across Branches

If you run into a bug while developing a branch, but it applies to more than just that branch then you should only apply the change once. Make the change on the root branch, say master and commit it, then propagate the change by merging it with every other branch. Checkout a branch the fix applies to, say hyperdrive and run the command,

git merge master
It makes sense to keep around common ancestors of multiple branches for just this purpose. This helps git keep track of which changes represent what so that it recognizes one single bug fix, instead of two different ones.

Checkout Out Files

Just as you can checkout files from commits, you can also checkout files from other branches. However odds are you really want to merge, as that keeps commit history. If you ever find yourself copying a file between branches, you should stop and think whether you could have modified the file at a common ancestor and merged changes into both branches.

Collaborating

While git is useful as a version control tool, it is structured such that it can be a very powerful collaboration tool. By keeping track of modifications as opposed to files, git allows many users to easily modify the contents of a large project.

Remotes

Just like tags allow you to rename commits from inconvient SHA hashes to nice names, git allows you to rename long locations of repositories to shorter remote names. For the rest of this section we will be using the short remote names, but you could use a full path to a repository instead. To set up a remote, you can run the command

git remote add rebels git@rebels.yavin4.gov:falcon
This means when you reference rebels you will really be referencing git@rebels.yavin4.gov:falcon. By default origin refers to whatever repository you cloned. (Note : remote names are not shared between repositories)

Fetching Changes

Sometimes your collaborators will make changes to their repository that you may want. If that is the case, you can fetch those changes using the git fetch command.

git fetch rebels
fetches all of the changes made in the rebels repository. The command will print out a list of all the branches in that repository. To merge branch rebel-hyperdrive with your local branch hyperdrive, make your current branch hyperdrive and run
git merge rebels/rebel-hyperdrive
You can compress those two steps into one by running
git pull rebels rebel-hyperdrive:hyperdrive

Pushing Changes

Some repositories are only used for distributing documents, and nobody is using them locally. If for instance the rebels also keep a github account for keeping the latest and greatest falcon documentation, you may wish to push to there. Pushing your dev branch to the remote hyperdrive branch requires the command,

git push github dev:hyperdrive
(Note: the branch ordering is reversed from the pull command)

A few comments on the previous command, first the command assumed that github was a valid remote. Second, the hyperdrive branch must not exist, or you must have in dev's history the latest commit to that branch. Otherwise you will have to merge in those changes by using the instructions in the fetching changes section. Finally, the remote must be a bare repository, bare repositories do not have local commits and can only be used as a common distribution point.