Git for Gnome, Take Two

In my last post, I discussed the basics of using git with a central repository, doing the sorts of things that we do in Gnome. There were some very helpful comments, and I’d like to share some of that information for the benefit of everybody else.

Branching

My instructions for creating and working on a local branch went like this:

git branch whizbang-feature master
git checkout whizbang-feature

Behdad pointed out that you can use the -b argument with git checkout to create a branch and check it out, all in one command. So those two commands become

git checkout -b whizbang-feature master

Of course, as with git branch, if you omit the last argument, it defaults to branching from whatever you currently have checked out.

Updating

My instructions for getting updates from the server were

git pull origin

Behdad, Marko, and daniel all pointed out that this isn’t optimal. You very likely have changes in your local repository. What you want is to get the remote changes and merge your local changes on top, as if they were developed from the now-current remote repository all along.

git fetch

This fetches the changes from the remote repository and puts them in your local repository. They are not merged in with your local checkout, just the local repository that’s sitting in .git.

It should be pointed out that git pull is basically just a shortcut for git fetch && git merge. But git merge attempts to merge the two development histories (remote updates and local changes) together, rather than just sticking your local changes on the end. So instead of git merge, we’ll call

git rebase origin/master

The git-rebase(1) man page has a nice ASCII diagram to help you visualize what’s happening.

Git for Gnome

This is not a “let’s use git” post. This is a “here’s how we’d use git, if we did” post. With all the recent git talk, I decided I’d try learning it with one of my on-again-off-again projects, Pulse. Caveat: I am not an SCM geek. I don’t enjoy learning SCM systems for the fun of it. I just want to be sure that whatever we use fits our needs. (Further disclaimer: I actually like CVS more than I like SVN. Infer what you will from that.)

If you go looking for documentation on git, you’ll find information on how to set up your own repository, how to clone other people’s repositories, how to make your own little personal branches (and why you should), and how to push/pull/merge. What they generally don’t discuss is how to work with a central repository.

So here’s my day-to-day Gnome SCM activities, translated into git. These instructions assume that Yelp is stored in the mythical git repository ssh://git.gnome.org/yelp.git. If any git people spot something braindead, point it out.

Checking Out

git clone ssh://git.gnome.org/yelp.git

This will clone the entire Yelp repository into a new directory called yelp. Initially, that directory will be working on a local branch called master, which is branched from the master branch on the server. The alias origin is created to refer to the repository on the server.

To get updates from the remote repository (the analog to cvs|svn update), run

git pull origin

If you’re using lots of remote branches, you may need to run somethinng like

git pull origin master

Committing

So you’ve made some changes to some files. To see what’s been changed, run

git diff

Without any options, this shows the differences between the data on your file system and the data in the index. The index is basically all those local changes that you’ve told git you want to commit. Let’s say you’ve modified yelp-document.[ch]. To add your changes to the index, run

git add src/yelp-document.c src/yelp-document.h

Now git diff shows no changes, because all the changes are in the index. But they haven’t actually been committed to the repository yet. To see the differences between the index and the repository, run

git diff --cached

To commit these changes, run

git commit

If you’re thinking there must be a way to skip the git add step, you’re right.

git commit -a

This will find all the differences between your local files and the repository, add them to the index, and commit them. Of course, you still need to use git add to add new files.

Committing Remotely

All you’ve done in the steps above is commit to your local repository. Git people will tell you you should do this early and often, and then push your local changes when a suitable chunk of work has been done. So to commit your work to the central repository, there’s one more step to take.

git push origin

Remember that git clone set up origin as an alias for the remote repository you cloned. Without any extra options, this will merge the changes on your local branch (master) to the branch of the same name on the remote repository.

Branching

Git people will tell you to create a new local branch for any set of changes you’re working on. If you’re working on fixing some bug, make a branch for that bug fix. If you’re implementing some whizbang feature, make another branch for that. You can easily switch between these branches. To create a new branch, run

git branch whizbang-feature

This creates a local branch, branched from whatever you currently have checked out. If you currently have the stupid-bug branch checked out, and you want whizbang-feature to branch from master instead, run

git branch whizbang-feature master

This just creates the branch. Your local copy is still a checkout of whatever it was before you called git branch. To start working on the new branch, you’ll want to check it out from your local repository:

git checkout whizbang-feature

You can always see your local branches by running

git branch

Remote Branches

If you check out Yelp and run git branch, you’ll only see your own local branch, master. But Yelp has lots of branches in the central repository. We make them for every stable release series. So where are they?

git branch -r

The -r argument causes git to show the branches on the remote repository you cloned from. You refer to the remote branches by prefixing them with origin/, which you’ll recall is the alias for the remote repository. If you want to look at the stable gnome-2-18 branch, you could run

git checkout origin/gnome-2-20

But if you want to make changes, you should really create your own local branch instead.

git branch gnome-2-20 origin/gnome-2-20

Now you can commit your changes to your local branch, then git push them to the remote branch.

Creating Remote Branches

In Gnome, we create branches for each stable release series. As a maintainer, you need to create branches in the central repository. So you can create a branch like this

git branch gnome-2-20

But that branch is just in your local repository. To push the branch to the central repository, run

git push origin gnome-2-20

Now other users will see this branch when they run git branch -r.

Tagging
In Gnome, we tag our central repository for releases. So if you release Yelp 2.20.0, you need to create the tag YELP_2_20_0. Creating a tag in your local repository is simple:

git tag YELP_2_20_0

But we need this tag to be in the central repository. To do this, we git push the tag up:

git push origin tag YELP_2_20_0

When you clone a repository, you get all its tags. To see all the tags in the repository, run

git tag -l

And So On

Obviously, there’s a lot more to learn to make really effective use of git. But most of that information is readily available elsewhere. I mosty wanted to address how to work with (and maintain) a central repository, because most git documentation doesn’t. Comments welcome.

Creative Commons Attribution 3.0 United States
This work by Shaun McCance is licensed under a Creative Commons Attribution 3.0 United States.