Getting the most out of Git in GNOME
Getting the most out of Git in GNOME
- Setting up Git
- Getting Code
- Contributing patches
- Applying Patches
- Publishing your tree
- Increased Trust
- Working as a module maintainer
- See also
- Other languages
Git is a powerful method of allowing many developers to work on the same source code. It is used extensively within the GNOME project and often proves to be the first hurdle for new developers that are attracted to the GNOME project.
Each developer clones a copy of the repository of the source code from Git and then is able to work on their own personal clone separately from other developers. When they have made changes, they commit them locally. After they are satisfied with their commits they push them back to the Git repository. This way a series of commits can be prepared and tested locally and then pushed as a single event.
With git everybody has all the tools available and can do whatever they want to do with their local copy. Moreover, almost all operations are local, so the operations are fast, and can be done without connection to the original repository.
The GNOME project has also set up online browsing of its Git repository.
If you would like to track the changes that occur in various GNOME Git projects, subscribe to the commits-list mailing list, a high volume, read-only list that receives mail every time somebody checks something into the repository. You can filter mail from this list by the title of the projects you are interested in.
Setting up Git
The first thing you should do is configure git to know who you are:
git config --global user.name "Rupert Monkey" git config --global user.email firstname.lastname@example.org
You can omit --global to change it for a single checked-out repository.
If you like pretty colors in your terminal output, you can enable those as well:
git config --global color.ui auto
git config --global color.diff auto git config --global color.status auto git config --global color.branch auto
If after turning on pretty colors, you instead see garbage in your output, you might need to add this line to your ~/.bashrc
To clone all the history and branches of a project into a subfolder of the current directory on your local harddrive, from a shell:
git clone git://git.gnome.org/[project]
The new subfolder will be named after the project.
With Git 1.6.6 and newer, http is possible too (please use the git protocol though!):
git clone http://git.gnome.org/browse/[project]
You should replace [project] with the name of the project you want. If you want the check-out to be put in a folder that is not the same as the project name, specify your own folder name as a second argument to git clone.
If you have a GNOME Git account already you can use their SSH key to authenticate themselves to the Git server so that they may also push changes back to the Git repositories. They use a slightly different URL to clone and deal with Git projects:
git clone ssh://[login@]git.gnome.org/git/[project]
In this case, if your local login is not the same as your GNOME developer login, you will also need to specify it in the URL.
An alternative to providing your GNOME developer login directly in the URL is to configure your SSH to automatically provide it when an attempt is made to connect to the git.gnome.org host. To do so, simply include the following in ~/.ssh/config :
Host git.gnome.org User [login] Compression yes CompressionLevel 3 # Following keeps a connection around, speeding up jhbuild # requires a new enough openssh client ControlPersist 5m
Convert anonymous repository to developer access
Suppose you've been contributing patches to gtk+ and now you've been given developer access, you don't need to git clone again the 200 MB size of a gtk+ repository, just change the origin url of your anonymous repository, like so:
git config remote.origin.url ssh://[login@]git.gnome.org/git/[project]
gnome: clone alias
Since all gnome modules have a common url prefix, it can be convenient to set up a clone alias:
git config --global url.ssh://[login@]git.gnome.org/git/.insteadof gnome:
Then the clone line becomes much shorter:
git clone gnome:[project]
Some gnome modules may contain git submodules inside it (eg. libgd inside nautilus), in that case you need to add --recursive to clone command so to retrieve code for any existent submodule, like so:
git clone --recursive git://git.gnome.org/[project]
For already cloned modules, that have added new submodules afterwards, you can just execute the following command at the root of the relevant git module to retrieve code for any new submodule:
git submodule update --init --recursive
When the clone has been completed, you will start to notice that many projects in Git GNOME contain similar files:
- .git: This directory is present in the root directory of a given project. It contains information about version numbers, where the source code came from, etc.. You can ignore it for all purposes, but you should not delete it.
- autogen.sh: This is a wrapper script around gettextize, intltoolize, libtoolize, aclocal, autoheader, automake and autoconf which you use to start building the project. For example
./autogen.sh --prefix=/usr/local will start the build process checking your system, generating all the necessary Makefiles before you are ready to type 'make' and 'make install'.
- README: This generally gives information about the Git project in terms of project requirements, where to report bugs etc..
- HACKING: This file usually specifies the rules [if any] for development in the project.
- [project].doap: This file lists the people who are responsible for the day to day maintenance of the project. Generally these are the people you should send patches to. It also lists some other metadata for the project, such as a description, homepage, mailing list, etc..
- MAINTAINERS: This file lists the maintainers, in a similar way to the DOAP file. It is no longer required to have a MAINTAINERS file, but a lot of projects still use them.
Git allows you to isolate changes onto a separate line of development, known as a branch. Quite often in GNOME, there are stable and unstable branches of development for a given project - as a result, the main branch [also known as 'master'] may not be suitable for your needs. Stable branches in GNOME Git are generally a mixture of lowercase alphabetic and numeric characters separated by dashes ie. of the form:
where major, minor are version numbers. For example:
In Git, branches and tags are simply references to a commit. For a list of the available local branches for a given project you can use:
For a list of the available remote branches for a given project you can use:
git branch -r
Checking Out a Branch
You can check out an existing local branch using the following command:
git checkout -b [branch name] origin/[branch name]
That specifies a local branch that will be created, to track the remote (origin/) branch. You must use a local branch, and you must give it the same name as the remote branch, or things will get very complicated when you try to push your commits later. If you do it as we show here, then a simple "git push" will work.
Note that before switching branches your working tree must be clean. If it is not, you can stash your changes (explained below) or commit them temporarily.
The following example will check out gnome-utils master and then check out the 'gnome-2-26' branch:
$ git clone git://git.gnome.org/gnome-utils $ cd gnome-utils $ git checkout -b gnome-2-26 origin/gnome-2-26
See #Branching about creating remote branches at git.gnome.org.
A local branch is a local snapshot of the repository branched so you can do work without changing the master branch. This makes it possible for you to work on several issues at the same time in different branches. A useful feature in cases where something urgent comes up while you are working on something else. Creating a local branch means that the branch is only available to you. The local branch is not created remotely.
You can create a local branch using:
git branch my-branch
You can create a local branch tracking a remote branch by using:
git branch my-branch origin/my-branch
You can create a new branch and check out it at the same time with:
git checkout -b my-branch origin/my-branch
- If you have a version of git greater than 1.6.1 you can also use:
git checkout --track origin/my-branch
which will create a local branch called my-branch tracking the origin/my-branch remote branch.
- If you already created a local branch you can switch easily between them using:
# Switch to my-branch git checkout my-branch # Switch back to master git checkout master
Maintainers 'tag' their projects in GNOME Git to mark releases. Tags in GNOME Git are generally a mixture of uppercase alphabetic and numeric characters separated by underscores ie. of the form
where MAJOR, MINOR and MICRO are version numbers. For example
For a list of the available tags for a given project:
git tag -l
As all the data is local you can examine the history very fast. To see the history up to the current revision:
git log -p gitk
where the '-p' is to see the patch and the last one is a graphical viewer.
Checking Out a Tag
You can check out a tag with the same command as you checkout a branch:
git checkout [tag name]
The following examples will check out the gnome-utils 2.0.2 tag and the 1.8.0 from Banshee respectively:
$ git clone git://git.gnome.org/gnome-utils $ cd gnome-utils $ git checkout GNOME_UTILS_2_0_2
$ git clone git://git.gnome.org/banshee $ cd banshee $ git checkout 1.8.0
Git is designed so that whenever there were any changes in the source code, you don't need to remove your sources and re-check out. The following command syncs up your code with what is stored in the Git repository
git pull --rebase
When you pull, you will notice a summary of the changes transferred (updated/new branches and tags) and a diffstat of the changes applied to your working copy. If you have local commits then the --rebase option will ensure that your local commits will first be removed temporarily, then the new changes from the remote git repository are fetched and applied, after which your local commits are reapplied on top of the new changes. If you do not use --rebase and you have local commits, your local commits will be merged with the new changes introducing a new commit which is often undesired.
Stashing Local Changes
If you have conflicting changes in your working copy the changes will not be applied. You can stash them first, do the pull, and apply you changes again with:
git stash git pull --rebase git stash pop
If you still have conflicts, you must resolve these, in general, before being able to rebuild the source code.
Check the output of 'git status' to know in which stage is each file and what you can do.
Note: The pull command should do what is called a fast-forward - that is, just update to a later revision.
Now that you have successfully checked out a GNOME Git project and hopefully managed to build it, you are ready to move forward and become a GNOME contributor.
GNOME contributors send 'patches' [sometimes called 'diffs'] to each other and attach them to bug reports in bugzilla.gnome.org. A 'patch' describes changes in some files. Generally, you will use git format-patch to create a patch suitable for mailing or attaching to bugzilla, which looks like:
From 5eaf4b1061621ba5bc3157777f749237150b4cc8 Mon Sep 17 00:00:00 2001 From: Joe Bloggs <email@example.com> Date: Fri, 17 Apr 2009 12:35:45 -0700 Subject: [PATCH] Add myself to AUTHORS. Fixes bug #12345. --- AUTHORS | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) diff --git a/AUTHORS b/AUTHORS index 15c2e37..12731aa 100644 --- a/AUTHORS +++ b/AUTHORS @@ -8,3 +8,4 @@ Sandy Armstrong <firstname.lastname@example.org> Sebastian Rittau <email@example.com> Kevin Kubasik <firstname.lastname@example.org> Stefan Schweizer <email@example.com> +Joe Bloggs <firstname.lastname@example.org> -- 184.108.40.206
Here you can see the lines added prepended with a '+'. If you had removed [or edited] a line of code, you would have been likely to see a line prepended with '-'. Notice it also shows you the revision of the file you are creating a patch against (in the index line). Because you created the patch with git format-patch, your name and email address show up along with your commit message.
Once you make changes to some given files you can generate a patch very easily.
First, see which files you've modified with git status, which should have output like:
# On branch master # Changed but not updated: # (use "git add <file>..." to update what will be committed) # (use "git checkout -- <file>..." to discard changes in working directory) # # modified: AUTHORS # no changes added to commit (use "git add" and/or "git commit -a")
Here you can see the the "AUTHORS" file is modified, and that if you want to undo your change, you can use git checkout -- AUTHORS.
If you want to see the actual changes of the modified files, you can with:
git diff [files]
Then you have to commit your changes with:
git commit [files]
where [files] are the files that have changed, or use '-a' to commit all the changes. You should then be prompted with your favorite editor to add a descriptive commit message for this commit. Alternatively, you can also use '-m "Add myself to AUTHORS. Fixes bug #12345."' with the command written above.
After committing, you can use the git-bz extension to git to submit a bug directly to bugzilla.gnome.org:
git-bz file product/component HEAD
Substitute product and component with the Bugzilla identifiers, like gnome-panel/general. Or you can can generate a patch file manually with:
git format-patch HEAD^
- This makes a patch out of your last commit, including the changes, the commit message, and your contact information.
Note: If your patch is big or does many different things you may want to split it to make the review easier.
Setting the following global config and the git log command will decorate local commits:
git config --global log.decorate short
If you are the one that gets sent a 'patch', then you can apply the commit in the patch with the following command:
git am [patch]
- If you have a patch based on an old version of the project and you want to update it to the current version you can do it with:
git pull --rebase
- Note that you may need to resolve some conflicts and commit afterwards.
Remember that git is a very flexible tool, and there are many different ways to use it. The above workflow is convenient for working on small patches, or for those who are just getting started with git.
Publishing your tree
If you are working on a large change, or need to make your patches available frequently, you may want to publish your tree somewhere where other people can clone from it.
Publishing your tree on github
github is a free (but not libre) web-based git hosting service. To publish a GNOME git tree to github:
Create an "Open Source" account, at http://github.com/signup/free. (Free accounts only let you create public source code repositories; paid accounts let you create private repos as well.)
After creating your account, click the link marked "(create a new one)" next to "Your repositories".
- Fill in the name and description, and click "Create Repository".
- It will then give you instructions on how to fill in your repository; however, since you are going to be pulling from git.gnome.org but pushing to github.com, you need to do something slightly different from what they say:
- Look at the directions under "Existing Git Repo?"
cd to your git checkout, and copy the git remote add command from the git page, but change "origin" to "github"
to push all of your local branches to github, type: git push --all github
Now you can continue to pull and merge changes from git.gnome.org as described above, and create as many local branches as you want, and just do "git push --all github" to push all of your branches to github, where other developers can see them, and clone their own copies of your repository.
Applying for your own Git account
To apply for your own Git account, please read the New Account instructions.
Pushing your changes upstream
As you supply more and more patches to a given maintainer, or attach them to bugs in bugzilla.gnome.org, the maintainer may ask you to obtain your own Git account to make your own source code check ins. To push your local commits back to the central repository, you would typically:
git pull --rebase
check that everything looks OK, test it,... You can also check what would be pushed with:
git push --dry-run
to finally push the new commits with:
If you do not pull beforehand, and changes have occurred that you never pulled, you may receive an error when you try to push. So, it is always best to pull before you push.
Git, by default, pushes all the local branches which exist also in the remote repository. That may not be what you want so git displays this warning:
warning: You did not specify any refspecs to push, and the current remote warning: has not configured any push refspecs. The default action in this warning: case is to push all matching refspecs, that is, all branches warning: that exist both locally and remotely will be updated. This may warning: not necessarily be what you want to happen. warning: warning: You can specify what action you want to take in this case, and warning: avoid seeing this message again, by configuring 'push.default' to: warning: 'nothing' : Do not push anything warning: 'matching' : Push all matching branches (default) warning: 'tracking' : Push the current branch to whatever it is tracking warning: 'current' : Push the current branch
(comment: is it advisable to change push.default?) To only push the current branch to the remote repository use:
git push origin HEAD
or configure the remote to push only the current branch with:
git config remote.origin.push HEAD
Working as a module maintainer
With an increased amount of trust and responsibility, you may even be asked to start maintaining a project within GNOME Git - or indeed, one of your own that you may have imported.
Committing on behalf of a contributor
When committing code on behalf of others use the --author option, e.g.:
git commit -a --author "Joe Coder <email@example.com>"
This makes it easier to know who has contributed the code. You will still appear as committer.
Maintainers must make tarball releases of their projects. This is well-documented at MaintainersCorner/Releasing.
At some point, you will need to branch your project for a stable set of releases, while continuing development on master; this works very much like tagging. This is documented at MaintainersCorner#branches.
A good git cheat sheet is available from here.