Size: 15917
Comment: Regroup a little bit
|
Size: 15917
Comment:
|
Deletions are marked like this. | Additions are marked like this. |
Line 244: | Line 244: |
~/gcc> git push repo-pr-cz mylocalbranch | ~/gcc> git push repo-or-cz mylocalbranch |
Line 249: | Line 249: |
~/gcc> git push repo-pr-cz | ~/gcc> git push repo-or-cz |
GCC GIT mirror
There is a read-only git mirror of the gcc svn repository available at:
http://gcc.gnu.org/git/gcc.git git://gcc.gnu.org/git/gcc.git git+ssh://gcc.gnu.org/git/gcc.git
It can be browsed at repo.or.cz.
Getting started - Read-Only
To work with get a local clone of the public repository is required. This is close to a svn checkout, however copies the complete history. Therefore commands like "git log", "git status", "git diff", "git blame" can be executed very fast and without internet connect.
Create the clone (git <= 1.6.4 warning)
> git clone git://gcc.gnu.org/git/gcc.git
Now the repository is available in "gcc". Try some commands
> cd gcc ~/gcc> git status # On branch trunk nothing to commit (working directory clean)
To fetch changes from the official svn-mirror repository into trunk
~/gcc> git pull --rebase
To extract patches for submission, use
~/gcc> git format-patch origin/trunk
On branches
Our repository already contains a set of important gcc branches
List the available branches
~/gcc> git branch -a * trunk remotes/origin/HEAD -> origin/trunk remotes/origin/fortran-dev remotes/origin/gc-improv remotes/origin/gcc-4_0-branch remotes/origin/gcc-4_1-branch remotes/origin/gcc-4_2-branch remotes/origin/gcc-4_3-branch remotes/origin/gcc-4_4-branch remotes/origin/gccgo remotes/origin/graphite remotes/origin/ifunc remotes/origin/ix86 remotes/origin/lw-ipo remotes/origin/master remotes/origin/melt-branch remotes/origin/microblaze remotes/origin/profile-stdlib remotes/origin/reload-v2a remotes/origin/split remotes/origin/spu-4_5-branch remotes/origin/transactional-memory remotes/origin/trunk
To work with one of these branches we need a local branch we can edit.
~/gcc> git checkout -b gccgo origin/gccgo Checking out files: 100% (2204/2204), done. Branch gccgo set up to track remote branch gccgo from origin.
Updates are the same as for trunk
~/gcc> git pull --rebase
Advanced Usage
The above works fine for browsing the repository and simple hacking, but has various issues. Here's what seems to me to be the optimal way of using git-svn with the GCC repository. Please email (jason) or grosser@ if you have any questions/issues with these instructions.
Commit upstream (git-svn)
The simple repository we create above is only read only. To commit changes upstream patches have to be extracted and committed using svn. However there is a way to commit changes directly out of git: git-svn
Commit on trunk
We start based with the read only repository create above.
Add git-svn support to be able to commit
# Use this exact SVN url for gcc.git and git-svn to work together. # Adding an SSH username to the url is ok. # git svn init -s svn+ssh://username@gcc.gnu.org/svn/gcc ~/gcc> git svn init -Ttrunk --prefix=origin/ svn+ssh://gcc.gnu.org/svn/gcc # Update index and fetch changes ~/gcc> git fetch # Ignore the same files that SVN does. ~/gcc> git svn show-ignore >> .git/info/exclude
Integrate the latest upstream changes in the local repository
~/gcc> git pull --rebase
See the list of changes we are going to commit
~/gcc> git diff origin/trunk..trunk
Commit our local changes into the official gcc subversion repository
~/gcc> git svn dcommit
Commit on branches
A single branch
To commit on a branch available in origin/* just add it git-svn
~/gcc> git config --add svn-remote.svn.fetch branches/gccgo:refs/remotes/origin/gccgo ~/gcc> git svn fetch
"git svn dcommit" commits automatically to the svn branch that the local branch you are working on was created from. So if you start with
~/gcc> git checkout -b gccgo origin/gccgo
and keep committing on top of this, the dcommit will commit onto the gccgo branch in svn.
All branches
~/gcc> git config --add remote.origin.fetch refs/remotes/*:refs/remotes/origin/* ~/gcc> git config --add svn-remote.svn.fetch branches/*:refs/remotes/origin/* ~/gcc> git svn fetch
Pulling all branches increases the size of the .git directory by about 30% over just trunk and release branches.
The various release branches
# GCC ~/gcc> for f in 2_95 3_0 3_1 3_2 3_3 3_4 ; do git config --add remote.origin.fetch refs/remotes/gcc-$f-branch:refs/remotes/origin/gcc-$f-branch; done ~/gcc> for f in 2_95 3_0 3_1 3_2 3_3 3_4 ; do git config --add svn-remote.svn.fetch branches/gcc-$f-branch:refs/remotes/origin/gcc-$f-branch; done # egcs ~/gcc> for f in 1_00 1_1; do git config --add remote.origin.fetch refs/remotes/egcs_${f}_branch:refs/remotes/origin/egcs_${f}_branch; done ~/gcc> for f in 1_00 1_1; do git config --add svn-remote.svn.fetch branches/egcs_${f}_branch:refs/remotes/origin/egcs_${f}_branch; done ~/gcc> git svn fetch
Subdirectory branches
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 don't use the wildcard fetch commented out above), and use git svn fetch to fetch the branch from SVN:
~/gcc> git config --add svn-remote.svn.fetch branches/redhat/gcc-4_4-branch:refs/remotes/origin/redhat/gcc-4_4-branch ~/gcc> git svn fetch
Usage
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, or are working on a branch that isn't in the git mirror) using
git svn rebase
I routinely do both of these to update my tree, depending on the circumstance: * git pull without --rebase gives a nice summary of what files have been updated, and will pull into a dirty working tree, and preserves the timestamps on files that aren't affected by the pull, but does a merge if I have any local commits; * git svn rebase grabs any very recent changes and rebases my local commits on top of the current SVN head in preparation for a checkin.
You probably don't want to use git svn fetch other than for the initial import of a branch, as shown above.
To look at your local changes, use
git log -p trunk..
To push all of them to the SVN server, use
git svn dcommit
Working with other branches
To switch your current working directory to a different branch, first set up a local tracking branch:
git checkout -b gcc44 gcc-4_4-branch
Then you can switch between branches with
git checkout master git checkout gcc44
To make a separate working directory for hacking on another branch at the same time, you can do
BRANCH=mybranch mkdir $BRANCH cd $BRANCH git init # Tell git not to re-fetch shared objects in your main repository echo ~/gcc-git/.git/objects >> .git/objects/info/alternates cp ~/gcc-git/.git/info/{attributes,exclude} .git/info/ git svn init -s svn+ssh://gcc.gnu.org/svn/gcc git remote add origin git://gcc.gnu.org/git/gcc.git git config remote.origin.fetch refs/remotes/trunk:refs/remotes/trunk git config --add remote.origin.fetch refs/remotes/$BRANCH:refs/remotes/$BRANCH # Make sure the main repository is up to date; see below (cd ~/gcc-git; git fetch) git fetch git checkout -b master $BRANCH
And then do pull/rebase/dcommit as with your main repository. This repository should be significantly smaller than the main one as it only contains the changes on the branch itself; it uses your main repository for anything on the trunk. In fact, if you do this for a branch that's already in your main repository, the .git directory in the new repository will be less than 10MB. If you pull in this repository sooner than in the main one, you'll get a few duplicate objects here, but you can clean them up with 'git gc'. You can use this repository without doing anything in your trunk repository as long as you don't delete the trunk repository or remove branches that this one is using.
The double fetch is to work around an apparent shortcoming of the "alternates" functionality (at least with 1.6.4): if the alternate repository doesn't have the objects at the heads of *all* the branches you are fetching with the initial fetch, git's quickfetch fails and it will download everything. So if your main repository is even one commit behind the head of any branch, git will re-download the whole shebang all over again. So we need to make sure that the main repository is fully up to date before we do the initial fetch.
Note that using git cherry-pick to copy changes between SVN branches brings along svn metadata which could confuse git-svn into thinking you're on a different SVN branch, so be sure to do a git commit --amend to edit the commit message before dcommitting to the new branch.
Make your changes available online
To allow others to view your changes online or to pull your changes in their repositories you can make (parts) of your git repository available on services like repo.or.cz or gitorious.org.
Already available gcc forks at repo.or.cz
Let's start with creating a fork of the gcc git mirror. Go to the "Fork" page, select "push" mode and add project name, password, email and captcha. For this example the fork is called "fancyfork".
Now you have to signup as user here with login, email, and ssh public key. If you "edit" your new repository you can add the new user as committer.
Add our online repository to the local one
~/gcc> git remote add repo-or-cz ssh://repo.or.cz/srv/git/official-gcc/fancyfork.git
To make the local branch "mylocalbranch" available, push the branch to repo-or-cz
~/gcc> git push repo-or-cz mylocalbranch
New changes to already published branches can be pushed by just using
~/gcc> git push repo-or-cz
Others can now watch your activities online, add your fork as another remote repository to their local repository or just clone your fork.
Usage hints for git
git-merge-changelog
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
NOTE: git-merge-changelog used to be extremely slow for cherry-picking changes from trunk to release branches, but this was fixed with a change on 2009-07-02.
Update bash function
Here's my generic "update this source tree" bash function. When I want to rebase, I do that manually either with 'git svn rebase' or 'git rebase -i trunk'
up() { if [ -d CVS ]; then cvs -q update "$@"; elif [ -d .svn ]; then svn up "$@"; elif gitd=`git rev-parse --git-dir 2>/dev/null`; then if [ -f $gitd/objects/info/alternates ]; then for d in `cat $gitd/objects/info/alternates`; do (cd $d; git fetch) done fi if [ -d $gitd/patches ] && `stg top 2>/dev/null`; then stg pull else git pull fi fi; }
rebase -i
git rebase -i is a very useful tool for organizing local changes for svn dcommit.
If I want to update a patch other than the current one, I just check in my current work and use git rebase -i to move it up the list and squash it into my earlier patch. Another approach would be to stash my current changes, tell rebase -i to edit the patch I want to change, pop the stash and then commit --amend.
If I want to apply some but not all of my current commits to SVN, I use git rebase -i to move the ones I want to apply to the top of the list, select "edit" for the last one I want to apply, and do git svn dcommit before git rebase --continue.
Useful aliases
Here are some aliases I'm finding useful (to add to your ~/.gitconfig). Note that these only work with the advanced setup due to differences in the branch.$BRANCH.merge config.
[alias] st = status ci = commit br = branch co = checkout sr = svn rebase sci = svn dcommit # The current branch. cbr = "!expr `git symbolic-ref HEAD` : 'refs/heads/\\(.*\\)'" # The branch being tracked by the current branch. track = "!git config --get branch.`git cbr`.merge" # Show all the local commits on this branch. lg = "!git log -p `git track`.." # Write all the local commits to ~/patch, filtering out modifications to ChangeLog files lgp = "!git log -p `git track`.. | filterdiff -x '*/ChangeLog' | sed -e '/^diff.*ChangeLog/{N;d}' > ~/patch" # Show all the local changes on this branch as one big diff. df = "!git diff `git track`" dfc = diff --cached # Reorganize the local commits on this branch. rb = "!git rebase -i `git track`" rc = rebase --continue # 'git rmerge mybranch' to reintegrate a temporary branch onto the top of the current branch rmerge = "!f(){ cur=`git cbr`; git rebase $cur $1; git rebase $1 $cur; }; f"
Old Information
Below here is information that no longer describes my use of git, but that other people might find interesting.
Stacked Git
I used to find 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 check the one I've just finished testing into SVN. But lately I've stopped using it and just use git branches directly.
With stg, if I want to remove a commit from my tree temporarily and come back to it later, I do
stg uncommit mypatchname [myotherpatchname...] stg pop -a
and then when I want to work on it again,
stg push mypatchname [myotherpatchname...] stg commit
This way stg only knows about unapplied patches, so it won't get confused when I do a 'git pull'.
And I periodically look at the list of suspended patches with
stg series
Making Patches
I currently make patches for gcc-patches using my 'git lgp' alias, below.
However, git always produces unified diffs, while the GCC project policy is to prefer context diffs. I don't bother with this, but if you really want to make a context diff, you can create a wrapper script somewhere:
cat > ~/bin/git_diff_wrapper <<EOF #! /bin/sh exec diff -p -L "$1" "$2" "$5" | cat EOF chmod +x ~/bin/git_diff_wrapper
and when you want to make a context diff for submitting a patch, do
GIT_EXTERNAL_DIFF=git_diff_wrapper git diff trunk
Further Reading
An introduction to git-svn for Subversion/SVK users and deserters