GCC GIT mirror

For the gcc svn repository exists also an read only git mirror. So you can use git for your daily gcc development.

The git repository is available at:


Get the source code of trunk

% mkdir gcc
% cd gcc
% git init
Initialized empty Git repository in /usr/home/Alice/gcc/.git/
% git remote add origin git+ssh://alice@gcc.gnu.org/git/gcc.git
% git fetch
remote: Counting objects: 870677, done.
% git branch -a

remote: Compressing objects: 100% (201036/201036), done.
Receiving objects: 100% (870677/870677), 296.70 MiB | 808 KiB/s, done.
Resolving deltas: 100% (706094/706094), done.
From git+ssh://alice@gcc.gnu.org/git/gcc
 * [new branch]      master     -> origin/master
 * [new branch]      pre-globals-git -> origin/pre-globals-git
 * [new branch]      restrict-git -> origin/restrict-git

Get svn branches

The git repository we cloned does not contain all branches. To do e.g. some graphite development we have to get the graphite branch.

% git config --add remote.origin.fetch '+refs/remotes/graphite:refs/remotes/origin/graphite'
% git fetch
remote: Counting objects: 86896, done.
remote: Compressing objects: 100% (41232/41232), done.
remote: Total 76919 (delta 49977), reused 59333 (delta 34708)
Receiving objects: 100% (76919/76919), 72.07 MiB | 695 KiB/s, done.
Resolving deltas: 100% (49977/49977), completed with 5347 local objects.
From git+ssh://alice@gcc.gnu.org/git/gcc
 * [new branch]      graphite   -> origin/graphite
% git branch -a

To get all branches use:

% git config --add remote.origin.fetch '+refs/remotes/*:refs/remotes/origin/*'
% git fetch

Update repository from git

To get new commits just use "git fetch" or "git pull". The git mirror is updated at least every 30 minutes so you should get new code really fast.

Using git-svn

Until now we did git only development. But there are two reasons to get git-svn in the game:

!! I just figured out how to make it work for one branch

Initialize git svn

If you have cloned a repos from other developers, there is a quick way for you to rebuilding the git-svn metadata. For a detailed description of git-svn, you can read this post: An introduction to git-svn for Subversion/SVK users and deserters

Here your working directory is your cloned repos:

# Initialize git-svn locally [1]
% git svn init svn+ssh://alice@gcc.gnu.org/svn/gcc/branches/graphite

# Pull the latest changes from Subversion [2]
% cp .git/refs/remotes/origin/graphite .git/refs/remotes/git-svn

# Update git from svn
% git svn fetch
Rebuilding .git/svn/git-svn/.rev_map.138bc75d-0d04-0410-961f-82ee72b054a4 ...
r115015 = b948ba9b92a300e4ad87fee28f9c530504b2d835
Done rebuilding .git/svn/git-svn/.rev_map.138bc75d-0d04-0410-961f-82ee72b054a4

1. IMPORTANT: If the repos you cloned from initialize using git svn init svn+ssh://alice@gcc.gnu.org/svn/gcc/branches/graphite You must use exactly the same except the username. This means you CAN'T use svn:// or http:// instead of svn+ssh://. If you want to know details, see 3 after you reading 2.

2. This line of code

cp .git/refs/remotes/origin/graphite .git/refs/remotes/git-svn

will copy your HEAD's SHA number to file git-svn. SHA is a 40 digits number which looks like b948ba9b92a300e4ad87fee28f9c530504b2d835. So you can just simple run git log and then copy the 40 digits number to the file git-svn. The simple reason in 1 is that any different thing in a commit will cause the different SHA.

3. The reason why we do this(see 1) because every commit corresponding to a SHA number, which looks like 78ad11bf2f61b35e1cb32a978ab546d198be8a2e. If two commit has the same SHA, then they are exactly the same. This will including timestamps/commiter/patch, as well as what we mentioned in 1. If you use svn+ssh://, then it will corresponding a line like

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/branches/graphite@145404 138bc75d-0d04-0410-961f-82ee72b054a4

git-svn-id: svn://gcc.gnu.org/svn/gcc/branches/graphite@145404 138bc75d-0d04-0410-961f-82ee72b054a4

4. If you didn't clone a git repos from a developer, you can rebuild your own with the following instructions , feel free to use http:// svn:// or svn+ssh:// that

anything you can easily access. But this might cause you about 50 hours(for me) to rebuild the metadata.

% git svn init svn+ssh://alice@gcc.gnu.org/svn/gcc/branches/graphite
% git svn fetch

For a detailed workflow of this usage, you can refer to this post:

git-svn workflow

Update git svn

% git svn fetch

Commit to svn branch

% git svn dcommit

!! Check documentation to not commit a lot of strange stuff to the gcc repository.

Alternative git-svn procedure (Jason Merrill)

Here's what seems to me to be the optimal way of using git-svn with the GCC repository:

mkdir gcc-git
cd gcc-git
git init
git remote add origin git://gcc.gnu.org/git/gcc.git
# Need to use this exact url for gcc.git and git-svn to work together.
git svn init svn+ssh://gcc.gnu.org/svn/gcc -T trunk
git config remote.origin.fetch refs/remotes/trunk:refs/remotes/trunk
# Setup 'git pull' to do the appropriate thing for interacting with SVN.
git config branch.master.remote origin
git config branch.master.merge refs/remotes/trunk
git config --add remote.origin.fetch refs/remotes/gcc-4_4-branch:refs/remotes/gcc-4_4-branch
git config --add svn-remote.svn.fetch branches/gcc-4_4-branch:refs/remotes/gcc-4_4-branch
# Repeat previous two lines for all the other branches you want
git pull
git config branch.master.rebase true
git svn show-ignore >> .git/info/exclude

and you're all set to start hacking. Note that the first remote.origin.fetch line doesn't use --add because we aren't interested in origin's heads, just its remotes that track SVN.

Note also that the commands above only pull down specific branches. If you want all branches, use "+remote/refs/*:remote/refs/*" on the remote.origin.fetch line, and add -b branches -t tags to the git svn init line. But you probably don't want all branches; they double the size of the repository.

If you want a branch that lives in a subdirectory of branches, such as redhat/gcc-4_4-branch, you can't get it from the gcc.git mirror for some reason, so leave out the remote.origin.fetch line for that branch, and do a git svn fetch to fetch all our branches from SVN. Normally we can get away with just letting rebase fetch the branch we're currently working on.

This process only uses gcc.git for the initial fetch, to save us the (large) processing time involved in the initial import from SVN. Once our setup is complete, we can just interact with the SVN repository directly with git svn rebase/dcommit, so we unset all the origin fetch lines so we don't try to fetch from gcc.git later on.

Pull changes from the git mirror as desired using

% git pull

or from the SVN repository (e.g. if you need a change that isn't in the git mirror yet) using

% git svn rebase

If you want to work on the 4.4 branch, do

% git branch gcc4.4 gcc-4_4-branch
% git checkout gcc4.4

to get back to the trunk, do

% git checkout master

To push all of your local commits to the SVN server, use

% git svn dcommit

Before long you'll get frustrated with git's handling of ChangeLog merges, which is just as bad as SVN's. But there's a fix for that!

$ git clone git://git.savannah.gnu.org/gnulib.git
$ cd gnulib
$ gnulib-tool --create-testdir --dir=/tmp/testdir123 git-merge-changelog
$ cd /tmp/testdir123
$ ./configure
$ make
$ make install
$ git config --global merge.merge-changelog.name "GNU-style ChangeLog merge driver"
$ git config --global merge.merge-changelog.driver "/usr/local/bin/git-merge-changelog %O %A %B"
$ echo "ChangeLog   merge=merge-changelog" >> ~/gcc-git/.git/info/attributes

To make a local clone for hacking on another branch at the same time, you can do

% mkdir gcc44-git
% cd gcc44-git
% git init
# Tell git to use the objects from the other repository directly rather than copy them
% echo ~/gcc-git/.git/objects >> .git/objects/info/alternates
% git remote add origin ~/gcc-git
# For a local clone we might as well use wildcards, since we won't be making any copies
% git config remote.origin.fetch 'refs/remotes/*:refs/remotes/*'
% git svn init -s svn+ssh://gcc.gnu.org/svn/gcc
% git fetch
% git config --unset-all remote.origin.fetch
% git merge gcc-4_4-branch
% cp ~/gcc-git/.git/info/{attributes,exclude} .git/info/

And then do rebase/commit as with your main repository. After the initial fetch we don't use the gcc-git repository anymore (apart from sharing objects); it would be possible to do one git svn fetch in gcc-git, and then git fetch in gcc44-git, but git-svn gets confused if git fetch brings in an older version of the branch than we already had from git-svn, so better to just use git-svn. UPDATE: Not using '+' in the fetch line will prevent git fetch from rewinding the tracking branch to an older state.

FIXME can we use gcc.git as the origin for this one too and still share objects with ~/gcc-git? That would avoid the problem of having to remember to fetch in one directory and then the other.

Note that you shouldn't use git cherry-pick to copy changes between SVN branches, as that brings along svn metadata which could confuse git-svn into thinking you're on a different SVN branch. Better I think to use git show/git apply, or do the merge in SVN directly.

I'm also finding Stacked Git useful for hacking on GCC, since it makes it easy to pop off patches that I'm still working on so I can apply the one I've just finished testing. See the StGit webpage for information on general usage; for using it with git-svn what I find works best is to do

# Update to current git head:
% stg pull

# Commit patch FOO to SVN:
% stg pop -a
% stg push FOO
% stg commit
% git svn dcommit
% stg push -am