In git, you don’t checkout code, you clone a repository. You end up with a local repository on your filesystem, which behaves as both the repo and as your working copy. In git, you always clone the whole repo, not a subdirectory, and the metadata is all stored at the top level, in a directory called
When you are ready to clone the repo, create the directory to store it in and change into it. Then type:
git clone [url]
Here’s an example, showing a clone of my private joind.in repo on github.
$ git clone [email protected]:lornajane/joind.in.git Initialized empty Git repository in /home/lorna/svndir/joindin/thinkvit/joind.in/.git/ remote: Counting objects: 7295, done. remote: Compressing objects: 100% (2212/2212), done. remote: Total 7295 (delta 5360), reused 6884 (delta 5004) Receiving objects: 100% (7295/7295), 2.62 MiB | 1.27 MiB/s, done. Resolving deltas: 100% (5360/5360), done. $
On github, there are different URL formats. Some are public, some are private so you need permission to push for those. If you are checking out your own project and you want to be able to push your changes back to it, then you need to use one of the private URLs and set up an ssh key to use with it.
Just like with Subversion, the status command shows us what state our repository is in. With git, you can have local changes, and you can also commit to the local repo and not push the changes to the location you cloned from yet, and the status command gives this information all in one go.
$ git status # On branch master # Changes to be committed: # (use "git reset HEAD
..." to unstage) # # modified: README # $ $ git status # On branch master # Your branch is ahead of 'origin/master' by 1 commit. # nothing to commit (working directory clean) $
Git has a way of adding shortcuts to repository URLs that you are likely to use a lot. A great example is the instructions given in the github forking guide which recommends setting up an “upstream” alias to make it easy to pull in changes from there. To add and then check these aliases, use the git remote command:
$ git remote add upstream git://github.com/joindin/joind.in.git
$ git remote origin upstream
This shows the
upstream remote we just created, and the
origin which is made by default when you clone a repo to point to the repo that was cloned.
Keeping Up To Date with Fetch+Merge or Pull
When you want to bring in changes from another repository, you can simply use pull to bring them in and apply them to your repo. If the changes all apply cleanly, git will automatically commit them for you (more on committing changes later), which surprises a lot of people when they see it for the first time! The syntax is simple, especially if you have the other repo set up as a remote:
$ git pull upstream master
You’ll see information about which files have changed and how much was added/removed in them. If the changes apply cleanly, git will automatically then commit these changes for you – you will see these in your history with a message like “Merge branch ‘master’ of git://github.com/joindin/joind.in”.
You may also prefer to pull down the changes and then look at them before applying them to your branch. You can do this by using
fetch and then
merge instead of the
pull command; in fact the pull command is a wrapper which runs fetch followed by merge so these approaches are equivalent.
Viewing History: Git Log
The log command in git is, much like the rest of the tool, somewhat overly powerful. In fact there’s a great quote in the bazaar docs about it:
…read and compare the help for the log command across the various tools: 4 pages for bzr log, one page for svn log, 26 pages for git log, and one page for hg log.
That said, the simplest case makes sense, and if you just run git log from your local directory, you get a list of changes with the commit hashes, date and time, author and headline message, with the newest first:
$ git log commit 7f415d6b30cb3e5f4079f3bf84481baaf607b304 Merge: beb8d28 94aa4e6 Author: Lorna
Date: Mon Sep 13 11:02:40 2010 +0100 Merge branch 'master' of git://github.com/joindin/joind.in commit beb8d28351bdeab77d4c6a9a77182cf7f7e0cba1 Author: Lorna Date: Mon Sep 13 10:52:15 2010 +0100 Adding test info to README Updated the readme file with the tests directory, info about the phing task and the dependency on pecl_http commit 94aa4e6c661cabf8db25799a265256a0f1010a88 Author: Chris Cornutt Date: Fri Sep 10 21:23:22 2010 -0500 adding gravatar refresh to user/main, changing the title on the user/view page
One thing which is different about git from other version control systems, is that you must expressly re-add every file that you change in order for these to be included in the commit, rather than just needing to add new ones. As a result, you’ll be using the
git add command a lot! Use
git status to see which files have been added or modified, and then add whichever you need (git will understand if you refer to them relative to your current position on the filesystem):
$ git add
When you have made some changes since the last commit, but would like to undo them on one or more files, git uses the checkout command (slightly confusing for those of us coming from subversion!) which basically takes a new copy of the code from the HEAD of the repository and replaces the current version of the file with this. Simply do:
git checkout --
-- tells the command line that you have stopped supplying switches so everything else should be interpreted as the final argument, i.e. the files.
It might seem a little late to be talking about comitting, but now we’ve covered all the other commands you need to get your working copy ready to do it. The command in git is just as you would expect – “git commit” – but do make sure to run
git status first and check that any changes you wanted to include are shown in the correct section of the output (remembering that you have to expressly add files in git!). When you commit, you will be prompted to enter a message, which is in two parts. The first line of the file will be the main commit message, and then if you enter a blank line, everything after it will be the detail, visible if someone drills in to view it in detail.
It is possible to specify the message on the same line as the commit command with
-m, however if you just type “git commit” then git will launch your default editor with a file that looks like this:
Adding test info to README Updated the readme file with the tests directory, info about the phing task and the dependency on pecl_http # Please enter the commit message for your changes. Lines starting # with '#' will be ignored, and an empty message aborts the commit. # On branch master # Changes to be committed: # (use "git reset HEAD
..." to unstage) # # modified: README
When you save and quit, you’ll see some feedback:
[master beb8d28] Adding test info to README 1 files changed, 11 insertions(+), 0 deletions(-)
If you have cloned a remote repo, for example when I work with joind.in I clone my own github project, you probably want to apply your changes to that location, and this does not happen automatically. Git makes no assumptions about where your changes should go, so the commit only applies to the local repo, and anything else you move yourself – by design.
To put your changes into the remote repo, simply use the “git push” command, supplying the repository and branch names as appropriate:
$ git push origin master Counting objects: 588, done. Delta compression using up to 2 threads. Compressing objects: 100% (93/93), done. Writing objects: 100% (466/466), 100.43 KiB, done. Total 466 (delta 369), reused 460 (delta 366) To git@GitHub:lornajane/joind.in.git 47da577..7f415d6 master -> master
Other Git Features
This is only really an introduction for being able to do the basics with git; there are many more features in this tool though and these are well worth some investigation! Branching in git is much easier than with a centralised version control system since you can have private branches, switch your local changes between branches, and it is generally much easier to work across multiple branches.
Git also has some really neat, small-but-perfectly-formed features. One is the cherry-pick, which allows you to apply a single change from somewhere else to a particular branch. Since git works on the basis of changesets rather than revision numbers which are a full snapshot of the codebase, this functionality works really well and is super-useful! Another favourite feature that I use is the “stash” command – the ability to temporarily shelve all your local changes, then make and commit some others. Very useful for those emergency situations where you need to quickly push a small change!
Resources and Further Reading
My favourite git resources are the github help pages – I linked to the one about forking projects but also check out the right hand bar on that page for many, many more resources on all aspects of using git. Recently I also saw a very nice cheat sheet at http://wiki.spheredev.org/Git_for_the_lazy which is a great resource and would make a good next step if you liked what you read here.
(this post was once published at thinkvitamin, but they disappeared off the internet and so I have reproduced it here)