This weekend I had the opportunity to attend Scott Chacon’s Advanced Git class at Jumpstart Lab. Scott works for Github and maintains the Git project’s website. He’s also written a book, ProGit, and the handy reference site Git Reference.

Scott spent a good bit of time going over the fundamentals of Git–the different types of objects stored in its database and how they point to one another. I had seen all this before when I first started using Git, but I wasn’t ready to really understand it then. If you’ve ever felt that Git was a bit mysterious or scary I’d highly recommend going over the basics again. Try this article and these twosections of Scott’s book.

Here are some other useful tips I picked up:

Ever go to commit a file and realize that only some of your changes are relevant to the current commit? Use

git add -p

to stage just parts of a file.
– Don’t know how all of your branches relate to the current branch?

git branch --merge

shows all the branches that have already been merged into the current branch, and

git branch --no-merge

shows branches that have not been merged.
– Ever work for a little while on master, then realize you really should have been in a topic branch? It’s not too late! Create your branch with

git branch myTopic.

Then put master back to the state is was at in the last pull:

git reset --hard origin/master.

You could also put the SHA of a particular commit if you don’t want to go that far back. Then switch back to your new branch with

git checkout myTopc

and keep working.
– Not sure who the last person to change some particular piece of code was? Use

git blame

to show which user last touched each line of a file. Want to know how code has been copied between files? Use

git blame -C

to show when parts of a file were copied out of another file.

There are also a whole slew of shortcuts git uses for naming commits. The basic ways to reference a particular point in the history are by a branch name, tag name, or SHA-1 (full or prefix.) In addition, git provides the following relative specifiers, which can be based off of any branch, tag or SHA:

master~ is the parent commit of master.

master~2 is the grandparent. master~3 is the great-grandparent, and so on.

master^2 is the second parent of a merge commit. master~2^2 is the second parent of the grandparent of the commit.

master@{yesterday} is the last state of master yesterday.

master@{3.weeks.ago} is the state of master three weeks ago.

HEAD@{1} is the previous state of HEAD, which could be many commits away if there was a fast-forward merge.

Some commands, like log or show, can also take a range of commits.

git log master..myBranch

shows all commits since myBranch diverged from master. Leaving off either commit implies HEAD. So

git log origin/master..

shows how your local master has progressed since the last fetch. Or if you’ve just done a fetch,

git log ..origin/master

shows what’s new from origin.

Got any of your own tips to share? Did I get something wrong? Feel free to leave a comment.