Contents
Git for GNOME developers
Git is the revision control system used for the Linux kernel, Xorg, Freedesktop projects, Cairo, and many other projects. This page documents how you can use Git to do GNOME development.
DISCLAIMER: This page is NOT about switching GNOME to use Git instead of Subversion. Do not even comment about that here; it's not the right place to do it. This is about using Git in conjunction with GNOME's existing infrastructure.
See also Shaun's basic Git workflow: part 1 and part 2.
Why Git?
Roughly in order of importance / convenience:
- Offline operation. You can commit, create branches, merge branches, etc., without having to be online. This is a huge benefit for hackers with laptops.
Fast! Since git operates locally unless instructed to go to the network, operations are very fast. Most operations take less than 10 seconds, even for huge projects like the Mozilla tree (confirmed by FedericoMenaQuintero).
- Distributed. There is no central point of control (except if you use Git to mirror SVN, of course), and all the cool kids are doing it anyway.
- Merging branches is very pleasant. CVS and SVN always made this hard.
- Repository size. A git-svn repository with dozens of branches still "weights" like the original SVN checkout (if not slightly less).
- Full history. When you clone a repository you have the entire history available, so you can roll back, diff or check out to any point in time without ever hitting the original repository.
- Fully scriptable. Many of the commands available are scripts or combinations of basic commands. You are encouraged in creating scripts and aliases to ease your workflow, once you find out that you're repeating certain sets of operations.
Git concepts
Cloning - When you "clone" a repository, you do just that: you bring the whole development history into your computer. Git uses an efficient representation of the data so that it doesn't use a lot of space.
Master branch - The main branch in your local Git repository. Normally this reflects the contents of a remote repository. You shouldn't really hack on it; instead, create a branch based on the master and work on that one. You can merge your changes into the master branch later.
HEAD - The tip of a branch, i.e. the latest revision within a branch.
How do I use Git to hack on an existing GNOME project?
As of January 2007, GNOME uses Subversion as its revision control system. Fortunately, Git has good tools to let you use a SVN repository as the "mothership" while you enjoy most of Git's features on your own computer.
Getting Git
What version of Git is required? Ubuntu Feisty has Git and git-svn 1.4.4.2 but git-svn clone doesn't seem to be supported.
Git 1.5 is absolutely recommended; the current stable version is 1.5.5. In the 1.5 versions, git learned a much more pleasant interface and is partly because of that being used more and more.
Getting the code
Reuse an existing clone
The quickest way to get the code for an existing GNOME project is to reuse someone elses git-svn conversion. A list of such conversions is found towards the bottom of the page. In some cases the conversion may come as a tarball. If the directory .git/svn exists already then you should be good to go. Just run
git-svn rebase
and git will fetch any new commits to bring your local copy up to date. If the .git/svn file doesn't exist or you only have a git mirror from which you've made a clone, you need to reconstruct the git-svn metadata. To do this you need to find the original subversion url for the project and then run this command:
git-svn init http://svn.gnome.org/svn/modulename -s --rewrite-root svn+ssh://svn.gnome.org/svn/modulename
This tells git-svn that it should fetch from the http url but that it should record the svn+ssh url in its metadata; this allows anonymous users to update the git repository and also authenticated users to commit back. Next bring the local git-svn repository up to date:
git-svn rebase
Creating a fresh clone from subversion
The first thing to do is to clone an existing GNOME project. This means getting a copy of that project's whole or partial SVN history. For newish projects you may be able to download their whole history relatively quickly; for older/big projects like GTK+ you may prefer to download only part of the history (say, the past three months, or whatever is convenient for you).
First setup ssh to use your gnome.org user name by default by adding the following to your ~/.ssh/config file:
Host svn.gnome.org
User username
Compression yes
CompressionLevel 3
# ovitters: Do NOT do something like ControlMaster! It will break your committing with SVN!
# ControlMaster yesBy doing this it will enable the cloned repository to be used by other users. The reason for doing this is so that your username is not part of the url used, as git uses this to be able to reconstruct the svn history.
Downloading a project's whole history:
#the -s options assumes a standard trunk/branches/tags layout - if the repository is laid out differently this won't work #read the man pages for git-svn for more information on the correct arguments in this case git-svn clone http://svn.gnome.org/svn/modulename -s --rewrite-root svn+ssh://svn.gnome.org/svn/modulename
or only for trunk:
git-svn clone svn+ssh://svn.gnome.org/svn/modulename/trunk modulename
This will create a local repository with modulename's whole development history in a directory called ./modulename (if you want another name, mv it or change the end of the git-svn command line). This will take some time depending on the size of the project's history.
Alternatively, you can clone starting at certain SVN revision up to HEAD:
git-svn clone -r revnum svn+ssh://svn.gnome.org/svn/modulename/trunk modulename cd modulename git-svn rebase
First you need to find out a suitable revision number. You can use "svn log" as usual to get this.
If you want a branch other than trunk, substitute "trunk" for "branches/modulename" and the last modulename by the name of the branch in your call to git-svn
Doing local development
The cardinal rule of doing development with Git is: don't use the master branch. Think of the master branch as the "pristine copy" of upstream's sources.
Create a branch:
cd modulename git checkout -b mybranch
This creates a branch starting from wherever you are, which at this point usually means "HEAD in the master branch".
With Git it is customary to do many small, logical commits, instead of big commits which modify many things at once.
Modify some files:
emacs file1.c file2.c ChangeLog
Mark them and commit them:
git add file1.c file2.c ChangeLog git commit -m "Colorize the frobs in funny ways"
Note you need to tell Git what to commit: the "add" and "commit" steps are separate. This is useful when you need to keep a modified file around but not commit it just yet.
Merging your branch and committing to SVN
Once you are finished with your work in mybranch, you'll want to merge it to your master branch (remember, that's the one which tracks the upstream SVN repository) and then actually push the changes to SVN.
Switch to your master branch:
git checkout master
Merge the changes from your branch:
git merge --squash mybranch
IMPORTANT: The --squash option is important. Git keeps information about what got merged where, but SVN doesn't. Git-svn cannot handle "normal" merges as done with Git; the --squash option tells "git merge" to act as if this were a manual commit, not a merge (more info). Notice that in the upstream Git repo some patches which would allow git-svn to use a real merge instead of the faked one with --squash are already included (Link to Git commit).
Commit the changes:
git commit -a -m "Merge mybranch into the master branch to implement feature X"
Finally, send the changes to the SVN repository:
git-svn dcommit
Updating from SVN periodically
Most of your work will happen offline, that is, you won't need to contact the svn.gnome.org since git-svn already took care of mirroring the development history for you. However, you'll periodically want to update your sources to the latest from upstream.
Get the latest changes from svn.gnome.org:
git checkout master git-svn rebase
Using git with jhbuild
JHBuild has support for using git to manage svn and cvs repositories. To enable this support add the following to your .jhbuildrc file:
svn_program = git-svn cvs_program = git-cvsimport
This will then cause jhbuild to check out cvs and svn repositories using git, from the current revision. If you want the full development history you need to checkout the module as described above.
Note: This will not convert existing cvs/svn checkouts to use git and thus requires you to manually delete any existing svn/cvs checkouts before using this feature
Sending patches
Git encourages you to do many small, self-contained commits. For example, say you want to add a feature to a program, but first you need to refactor the code a bit to allow your feature to fit in. A first patch would do just the refactoring. A second patch would actually add your feature. A third patch would update the documentation. If your feature is very complex, you may want to add stub functions in a commit, then actually fill them in in further commits, etc.
The idea is to submit small patches for review by maintainers, instead of burdening them with the information overload of a single mega-patch.
Let's say you created a branch mybranch off the master branch. Hopefully this is not your original work branch, but instead a "cleaned up" branch with actual logical commits, which you would be proud to show to your mom, instead of experimental / "fix whitespace" / "remove debug printf" commits that you had in the work branch. You have several commits in that branch. If you are in mybranch, you could generate a patchset like this:
mkdir ~/patchset git format-patch -n -o ~/patchset master
This will create ~/patchset/0001-xxx.patch, ~/patchset/0002-yyy.patch, etc., for all the commits in your branch. Each file is intended to be a separate mail message which contains your commit message, a diffstat, and the actual patch. These files are in Unix MBOX format; you can import them into Evolution or your mailer of choice to send them out to the maintainer. If you import them in Evolution, you can then select "Edit as new message" from the context menu of one of those mails to enter the To: header and actually send out the mail.
If you want to attach a patch or an entire patchset to GNOME's Bugzilla, you can use the most excellent git-send-bugzilla script written by Steve Frécinaux. This Perl script will attach a set of commits as single patches, complete with commit message and diffstat, to a bug given its number.
Full repository checkouts
libwnck or git clone http://git.jsharpe.net/libwnck.git
gnome-control-center or git clone http://git.jsharpe.net/gnome-control-center.git
gnome-settings-daemon or git clone http://git.jsharpe.net/gnome-settings-daemon.git
gnome-desktop or git clone http://git.jsharpe.net/gnome-desktop.git
