… or something like that… I planned to write a short note about how to start with using git-svn so I can provide a pointer to some of my colleagues. It turned out that git has too many nice features that you should be aware of. :) Hopefully my notes (now being a reference for myself as well, thx to gebi for all the help and feedback) are useful anyway. If you think something (more or less essential, or at least something most of us should be aware of) is missing: please feel free to mention that in the comment section of my blog entry, thanks.
Disclaimer: I’m still happy with mercurial for what I – and we at grml in general – use it: linear, but anyway distributed development. git on the other hand provides some really nice features. Rebasing and branching with git is really great – so non-linear development just works. As usual: use the right tool for the right job.
git is a bit complicate to use. Not only but especially in the beginning. On the other hand I’m not such a big friend of subversion. If you wanthave to use subversion (Graz University of Technology for example provides a svn service to their students and employees) but prefer to work with git instead you should be aware of git-svn. git-svn gives you bidirectional operation between subversion and git.
First of all make sure you have all you might need when working with git. Make sure to use a current version of git (I’m refering to version >=1.5.3). Just execute the following command line on your Debian system to install all relevant packages:
aptitude install \\
git-buildpackage git-core git-cvs git-daemon-run \\
git-doc git-email git-gui git-load-dirs git-svn \\
gitk gitweb qgit
Now let’s start with some general and basic configuration:
# Remove directories from the SVN tree if there
# are no files left behind, configure it globaly:
git config --global svn.rmdir=true
# Want some more global, personal git configuration?
for line in \
user.name=Michael Prokop \
user.email=foo@example.invalid \
color.diff=auto \
color.diff.new=cyan \
color.diff.old=magenta \
color.diff.frag=yellow \
color.diff.meta=green \
color.diff.commit=normal \
do
git config --global $line
done
Check out man git-config for much more details about configuration options.
First tip: set ‘g’ as an alias for git so you don’t have to type that much. I’ll write the long version in the following examples so copy/paste works for everyone. Make sure to use the short options of git itself as well: use ‘git co’ for example instead of ‘git checkout’. You can define your own aliases inside git as well – either manually in ~/.gitconfig or running something like:
git config --global alias.st status
Enough pre-configuration for now. It’s time to checkout the SVN repository:
# Check out the SVN repository and set 'svn/' as
# prefix for the branches:
git svn clone -s --prefix=svn/ \\
https://svn.tugraz.at/svn/$project foobar && \
cd foobar
# Adjust svn:ignore settings within git:
git svn show-ignore >> .git/info/exclude
# List all branches:
git branch -a
# List all remote branches:
git branch -r
# Rebase your local changes against the
# latest changes in SVN (kind of 'svn up'):
git svn rebase
# Checkout a specific branch:
git checkout $branch
Ok so far? But what do we have to do if we want to work on the upstream source and are allowed to commit/push directly to the repository? Let’s see how to work on that without using branches:
# Hack:
$EDITOR foobar
# Check status
git st[atus]
# List diff:
git diff [foobar]
# Commit it with a commit message using $EDITOR:
git commit -a
# Now commit your changes (that were committed
# previously using git) to SVN, as well as
# automatically updating your working HEAD:
git svn dcommit
But what should we do if we do not have commit rights? Let’s create our own branch and send a patch via mail to upstream:
# Make a new branch:
git checkout -b mikas_demo_patch
# and hack...
$EDITOR
# Commit all changes:
git ci -a -m 'Best patch but worst commit msg ever'
# ... and prepare patch[es]:
git format-patch -s -p -n master
# Now send mail(s) either use git-send-email:
git send-email --to foo@example.invalid *.patch
# ... or if you prefer mutt instead (short zsh syntax):
for f in *.patch ; mutt -H $f
You got a mail from someone else and would like to incorporate changes from the attached patch in your repository? Just store the mail in a seperate mailbox (use save-message in mutt for example, keybinding ‘s’ by default), then execute:
# Apply a [series of] patch[es] from a mailbox
git am /path/to/mailbox
Want to work on a seperate branch and rebase your work with upstream?
# First of all make sure to use recent sources...
# So pull when using plain git:
git pull -u
# .. or when using git-svn use:
git svn rebase
# Then create a new branch:
git checkout -b mika
# Hack:
$EDITOR
# Commit:
git ci -a -m 'Best patch but worst commit msg ever'
# Switch to master branch:
git checkout master
# Pull again when using plain git:
git pull -u
# .. or when using git-svn use:
git svn rebase
# Finally switch back
git checkout mika
# Now rebase it with plain git using:
git rebase origin/master
# ... or when using git-svn:
git svn rebase
# Now check out the last 5 commits:
git log -n5
Another branch-session might look like:
git co -b foo
$EDITOR
git ci -a -m 'foo changes'
git co master
git co -b bar
$EDITOR
git ci -a -m 'bar changes''
git co foo
git rebase bar
git log -n5
git st
git branch
Pfuhhh? Right. :) Now it’s time to check out another cool feature: git stash, which is just great when pulling into a dirty tree or when suffering from interrupted workflow. Demo:
git stash
git pull / fetch+rebase
$EDITOR # fix conflicts
git commit -a -m "Fix in a hurry"
git stash apply
git stash clear # unless you want to keep the stash
git reset rocks as well:
# List all recent actions:
git reflog
# Now undo the last action:
git reset --hard HEAD@{0}
How to get rid of branches?
# Delete a branch. The branch must be fully merged:
git branch -d remove_me_branch
# Delete a branch irrespective of its index status:
git branch -D remove_me_branch
# Delete a remote branch:
git push reponame :branch
Repack a git repository to minimize its disk usage:
git pack-refs --prune
git reflog expire --all
git repack -a -d -f -l
git prune
git rerere gc
Use git cherry to find commits not merged upstream.
Another really cool feature is the interactive rebasing: git rebase –interactive
Make sure you are aware of gitk:

… and don’t forget to set readable fonts for gitk, like:
[ -r ~/.gitk ] || cat > ~/.gitk << EOF
set mainfont {Arial 10}
set textfont { Courier 10}
set uifont {Arial 10 bold}
EOF
If you prefer a Qt based interface check out qgit.
Useful ressources: