Setting Up and Using Git
Introduction
GIT is a decentralized version control system. This differs from CVS, SVN, and various other VCS's in that there is no need for a central repository though one can be used if desired. All working directories are self contained and complete projects in their own right. In the dynamic collaboration environments typically found in research and open source communities this is particularly appealing. It is suited for small projects and very large projects alike and is extremely fast for either. Further, branching and merging (often a royal pain in other version control environments) are first class citizens. They are the natural way to make changes. Typical work flow involves branching, then merging with the trunk all in the course of one session.
This is NOT a complete git tutorial. It's only a quick walk through and is not intended to be either exhaustive in even the loosest sense of the word.
For full information on Git please see the GIT home site or any of the many, many tutorials found with a simple google search.
Windows
GIT is primarily designed for UNIX based systems. Specifically, it was written by Linus Torvalds as a BitKeeper replacement for the linux kernel project. There is a Windows client, however this tutorial focuses on installation via Cygwin. Not because I view it as superior, I have no experience with the windows client to make a fair comparison, but because it is what I am most familiar and comfortable with.
Installing CygWin + GIT
Installing Cygwin couldn't be simpler.
- Download the Setup.exe
- Double click for installation
- Accept the defaults until you reach the package selection screen
- Select the following packages (if you click 'View' until it is set to 'Full', you get an alphabetized list)
- openssl
- openssh
- git
- git-gui (graphical front end for git, basic but alright)
- Click next and watch the pretty color bars move to the left.
If you ever want to add or update packages to cygwin, you just rerun the setup. It'll auto-detect a previous install and run in update/upgrade mode.
OS X
First, install MacPorts. Their documentation is thorough and complete, so the process is not repeated here. Next, issue the following commands
$ sudo port selfupdate $ sudo port install git-core
That's it, you're done.
Help! I got a 'command not found: port' error!
You skipped the MacPorts installation instructions didn't you? *hint* check the part about modifying your PATH.
Using Public/Private Keys with GIT
GIT operates over SSH and it's very common to use public/private key authentication for interacting with remote repositories. This section walks you through creating these keys, setting up a ssh config entry for the repository, and doing a quick "clone, branch, change, merge, push" cycle. This is a typical development cycle.
Creating public/private keys
For more information on public/private key authentication please see IBM's tutorial. The following command initiates the creation of a DSA public/private key pair.
$ ssh-keygen -t dsa
This walks you through a series prompts, the first of which is:
$ ssh-keygen -t dsa Generating public/private dsa key pair. Enter file in which to save the key (/home/James/.ssh/id_dsa):
Since we're creating a pub/priv key for git, let's save the key as "git_dsa". Then you are then prompted for a password. Choose a decent password for your new key.
Enter file in which to save the key (/home/James/.ssh/id_dsa): /home/James/.ssh/git_dsa Created directory '/home/James/.ssh'. Enter passphrase (empty for no passphrase): Enter same passphrase again: Your identification has been saved in /home/James/.ssh/git_dsa. Your public key has been saved in /home/James/.ssh/git_dsa.pub. The key fingerprint is: 1f:d8:9b:9f:69:94:3d:ed:bc:cc:62:0f:18:2b:6a:34 James@James-PC The key's randomart image is: +--[ DSA 1024]----+ | | | | | | | o | | S o. o . | | E . +* o .| | . ..++ . + | | .. ...=+ o| | .. .= o=.| +-----------------+
Notice that we gave the full path to the new key and the ~/.ssh directory is created for us.
That's all there is to creating a key.
Setting up the ssh config file
This is covered in great detail in the Creating_SSH_Shortcuts_Using_SSH_Config tutorial on the HowTo_Pages, so here we'll just show a typical configuration for a git host. Open up your ~/.ssh/config with your favorite text editor and create the following entry:
Host git Hostname mygit.host.com User gituser IdentityFile /home/James/.ssh/git_dsa
Notice that we've specified the key to use with the full path to our git_dsa created in the previous step.
Important!
If this is your first time creating a .ssh/config file you likely need to correct the permissions. This is done by
$ chmod 600 ~/.ssh/config
Giving out public key to the git host
The final step to gain access is giving our *public* key to the git host. It is very important that you only give your *public* key (this is the file ending in .pub). You should never, ever, not even on threat of having to watch endless repeats of Family Ties for the rest of your life give anyone your private key file.
You can do this via email, or scp if you own the account you're using the key for. If you control the host/account you wish to log into simply copy the contents of the git_dsa.pub into the ~/.ssh/authorized_keys file. If it does not exist, create it.
Then you can log in via:
$ ssh git
Using SSH Agent for single password
Windows/Cygwin PreRequisite
On windows there are a few extra steps, but we're used to that by now. First, we need to modify our ~/.bashrc to contain the following (thank you Web Weaver Tech):
export SSH_AUTH_SOCK=/tmp/.ssh-socket ssh-add -l 2>&1 >/dev/null if [ $? = 2 ]; then # Exit status 2 means couldn't connect to ssh-agent; start one now ssh-agent -a $SSH_AUTH_SOCK >/tmp/.ssh-script . /tmp/.ssh-script echo $SSH_AGENT_PID >/tmp/.ssh-agent-pid fi function kill-agent { pid=`cat /tmp/.ssh-agent-pid` kill $pid }
Next, enter the following in your environment variables (Control Panel => System => Advanced Settings => Environment Variables):
NAME: SSH_AUTH_SOCK VALUE: /tmp/.ssh-socket
After this, the standard directions below should work for you.
All Other Platforms
You may notice you still have to use a password to login, so why all the trouble of creating a public/private key? Well, actually, with the SSH Agent you only need to enter your password once. There is a fix for this though. Upon opening terminal, issue the following command
$ ssh-add ~/.ssh/git_dsa
Where 'git_dsa' is the name of the key you wish to add. You can add as many as you like and, obviously, the names may differ. After entering your password, you'll be able to log into any host using this key without a pass for as long as you're logged in. If using our previous host example, we would clone a project called "Foo" by using the full path to the project.
Cloning a project over ssh
Now we can fetch projects from our git user. If you were on windows, I know it feels like a lot of work. But we're almost there!
$ git clone ssh://git/full/path/too/Foo.git
From there on out, it's standard git management.
Git Work Flow
This is just a quickie run through of a git work flow. We're going to assume you've cloned a git project named Foo.
Create and Checkout a Working Branch
As mentioned before, branching is a first class citizen. Before we make any changes, let's create a working branch. We'll call it "development".
$ git branch development
To see our branches, execute the branch command with no arguments.
$ git branch development * master
The 'master' branch is the default main branch. The development branch is the one we just created. The '*' prepended to the master indicates this is the branch we're currently in.
To actually use the development branch, we must first check it out
$ git checkout development
Now we see the '*' by development
$ git branch * development master
The above two steps can be condensed into a single step by:
$ git checkout -b development
This means 'checkout the development branch and create it if it doesn't exist'.
Modify Files and Commit changes
Open a file and make some trivial change and close it. In this case, I modify a file called "temp". Now let's commit our changes:
$ git commit -a -m "Edited the temp file" Created commit c75b3d3: Edited the temp file 1 files changed, 3 insertions(+), 0 deletions(-)
- -a commits all changes
- -m says we're going to enter the comment inline. otherwise a text editor is opened for the commit comment.
Merge development with master
In git, we merge by "pulling" from one branch to another. So to merge with the master branch, we first check out master than 'pull' development into it.
$ git checkout master $ git pull . development From . * branch development -> FETCH_HEAD Updating 6d26cca..c75b3d3 Fast forward temp | 3 +++ 1 files changed, 3 insertions(+), 0 deletions(-)
If you check the temp file, you'll see our changes are available. If there were any conflicts you'd be prompted to resolve them. The process should be familiar to anyone used to version control. Since we no longer need it, we can delete the development branch if we wish
$ git branch -d development Deleted branch development.
Send Our Changes to the Main Repository
All of the steps above only modify our local repository. They have absolutely no effect on the main repository we cloned earlier. If we wish to send these changes upstream we "push" our changes.
But before we do this, we need to catch up to any changes that other developer's may have made with our remote repository. To do this, we should do a git rebase.
$ git rebase origin
This will "sync" our two repositories. Technically, it first rewinds the commits we've made locally, pulls the remote commits, then replays our local commits on top of them. Again, resolve any conflicts that need resolving.
Pushing of changes should *only* be done on bare repositories. If another developer wants your changes, they should "pull" from your repository into theirs.
Finally,
$ git push origin master
Alternate Git Work Flow (working with a remote development branch)
This walks through working with a remote development branch (instead of merging a local branch into master).
List remote branches
$ git branch -r
You'll get output similar to this (assuming the remote is named "origin")
origin/HEAD -> origin/master origin/dev origin/development origin/master
Checkout the remote branch
$ git checkout -b development origin/development
This will create a local branch named development that is a clone of the remote branch development on origin.
Checking out a remote branch with tracking
You can also check out a remote branch with tracking. Tracking "links" a branch with a specific remote branch. The benefit is that you no longer have to specific the remote branch when pulling, rebasing, or pushing changes.
So, instead of:
$ git push origin development
Or:
$ git rebase origin development
You'd simply have to do:
$ git rebase $ git push
To check out a remote branch with tracking:
$ git branch --track development origin/development && git checkout development
Rebase the development branch
Next, you rebase against the remote development branch, this is pretty much the same as the previous example except we must specify the remote branch name
$ git rebase origin/development
Again, resolve any conflicts that might occur.
Push our changes to the central repository
$ git push origin development