git is the second project that Linus Torvalds has named after himself. It is now on the workstation image.
git is a distributed version control system (DVCS), which offer many advantages over centralised version control systems such as subversion. For git in particular:
- Ability to use version control without the internet access required to access the wwmm server. I now have the complete history of our code on my laptop. No wifi needed! :-). It also means I can do sequential commits without needing internet access.
- Branching and merging are *easy* and *lightweight*. This has changed how I work...
- git-svn provides an interface (in both directions) with a subversion repository. This means that we get all the advantages of using subversion (a centralised server which is backed up and maintain Oed by someone other than us, subversion is installed on more systems, can work with people who are using subversion and don't want to change) with none of the disadvantages (subversion makes branches an absolute pain, especially if you want to just try something out and have a play without polluting the server). The interface is so slick, that I can use git and everyone else use subversion and not know that I'm using git (but I may have just let the cat out of the bag on that one).
- It's fast.
- It doesn't screw around with my history or lose files.
- It's cryptographically secure. (This isn't as bizarre as it sounds!)
- Linus Torvalds is much smarter than us. Seriously. Oh, and he calls everyone using subversion (and cvs) stupid. Repeatedly. He managed to convince me...
It is somewhat less user friendly in places, but far more powerful, than subversion. It has wonderful graphical interfaces for viewing branches (gitk and qgit).
Things I really miss when I have to use svn:
- branching and merging.
- tab completion on the subcommands (e.g. git commit and svn commit) and a PS1 containing the branch information (see below).
- git diff plays nicely with graphical diffs (svn is meant to, but good luck on getting it working with xxdiff).
- git pros
- Funky commits and tangled workflows
- you can always recover in git
- git wiki is incredibly useful.
Accessing remote git repositories
If you have a git repository on your workstation and you wish to clone it, push to it or pull from it one another computer, then you have 3 options:
- Use git-svn to commit to the wwmm svn server, and then pull the changes from there.
- Use a central git repository (e.g. ) to push/pull via, rather than a svn server.
- Connect directly over ssh.
I didn't want to use a central repository (more faff) and often I'm working on a branch which I don't want to push to svn (because, for example, it breaks everything). This leaves me with option 3. The syntax for cloning a remote repository over ssh is (from git help clone):
Because of the firewall, we first need to set up an ssh tunnel. I did:
ssh -f -L20001:keiko.ch.cam.ac.uk:22 -l jss43 -N chimaera.ch.cam.ac.uk -g git clone ssh://jss43@localhost:20001/path/to/repo.git cloned-repo-dir
Once you've specified the remote address, git by default will use that address for all remote (push, pull, etc) operations. You will need to set up the ssh tunnel each session. Unless you set up alternate remote addresses, you will have to use the same port (in my example, 20001) each time. I had some problems with the ssh tunnel being dropped (which I assume is firewall related---at least it was in the past).
meld and git diff
Set up git diff to use meld or xxdiff rather than outputting a unified diff by adding, e.g.,
[diff] external = meld
Unfortunately git tries to pass more information than xxdiff or meld can handle. Instead add:
[diff] external = ~/bin/diff.sh
to ~/.gitconfig where ~/bin/diff.sh contains:
#!/bin/bash meld $2 $5
and enjoy graphical diff wonderland.
The version of git on the 10.3 image (1.5.6) includes a controversial patch which enables the pager for the output of all commands, even when the output is less than a screen. I find this is incredibly annoying. This is being made into a configuration option, but for now we can work round it:
export GIT_PAGER='less -FX'
git config --global core.pager 'less -FX'
This will stop paging if the output is less than one screen. It has the disadvantage that long output (e.g. from git log) is printed to screen (rather than existing only in the pager), but this is much like the behaviour of svn log, so at least it's no worse. This can be overcome by using pipes if you really want to...
Add tab completion for the git subcommands: completion script. Follow the instructions within to set up tab completion. It also contains a handy function that adds the current branch to your PS1. I added:
PS1='\u@\h:\w$(__git_ps1 " [%s]")\$ '
to my .bashrc. This only adds something when I am in a git-controlled directory. If I change directories, it remembers what branch I am in:
james@maruchon:~/work/src$ cd CPMD-NECI james@maruchon:~/work/src/CPMD-NECI [master]$ git branch * master test james@maruchon:~/work/src/CPMD-NECI [master]$ git checkout test Switched to branch "test" james@maruchon:~/work/src/CPMD-NECI [test]$ cd NECI/ james@maruchon:~/work/src/CPMD-NECI/NECI [master]$ git branch exp * master james@maruchon:~/work/src/CPMD-NECI/NECI [master]$ git checkout exp cd -Switched to branch "exp" james@maruchon:~/work/src/CPMD-NECI/NECI [exp]$ cd - /home/james/work/src/CPMD-NECI james@maruchon:~/work/src/CPMD-NECI [test]$ git checkout master Switched to branch "master" james@maruchon:~/work/src/CPMD-NECI [master]$ cd NECI/ james@maruchon:~/work/src/CPMD-NECI/NECI [exp]$ git checkout master Switched to branch "master" james@maruchon:~/work/src/CPMD-NECI/NECI [master]$ cd james@maruchon:~$
This is very useful (especially as git encourages branching so much!).
Subversion migration using git
My project is to take an SVN repository Cambridge on server cam and SVN repository Berkeley on server berk and allow changes back and forth between the two. Cambridge is the initial repository, and we will create Berkeley from it (Berkeley is an initialized and blank SVN repository directory). Both Berekeley and Cambridge will be indepenedently modified, and the aim is to keep the two in sync via git.
First, we must create the Berekeley respository from the Cambridge
e.g. starting in /git :
git-svn clone svn://cam/Cambridge Cambridge git clone file:///git/Cambridge Berkeley cd Berkeley git-svn init svn://berk/Berkeley git-svn fetch git rebase git-svn master git-svn dcommit
Plenty more to come...
Next we modify the Cambridge repository by adding file CamFile4 and move the changes to Berkeley
athom@down:~/git/Berkeley [origin/HEAD]$ cd ../Cambridge/ athom@down:~/git/Cambridge [master]$ ls CamFile1 CamFile2 CamFile3 athom@down:~/git/Cambridge [master]$ git svn rebase First, rewinding head to replay your work on top of it... HEAD is now at 62b3628... A post-import file Fast-forwarded master to refs/remotes/git-svn. athom@down:~/git/Cambridge [master]$ ls CamFile1 CamFile2 CamFile3 CamFile4 athom@down:~/git/Cambridge [master]$ cd ../Berkeley/ athom@down:~/git/Berkeley [origin/HEAD]$ git svn fetch athom@down:~/git/Berkeley [origin/HEAD]$ ls CamFile1 CamFile2 CamFile3 athom@down:~/git/Berkeley [master]$ git pull remote: Generating pack... remote: Done counting 4 objects. Result has 3 objects. remote: Deltifying 3 objects... 100% (3/3) done remote: Total 3 (delta 1), reused 0 (delta 0) Unpacking 3 objects... 100% (3/3) done * refs/remotes/origin/master: fast forward to branch 'master' of file:///Users/athom/tmp/git/tmp/Cambridge old..new: 880aefd..62b3628 Merge made by recursive. CamFile4 | 1 + 1 files changed, 1 insertions(+), 0 deletions(-) create mode 100644 CamFile4 athom@down:~/git/Berkeley [master]$ git svn dcommit Committing to svn+ssh://localhost/Berkeley ... A CamFile4 Committed r8 A CamFile4 r8 = b94ff7d1a466cfe5d75e97e90d2c5629a9364e04 (git-svn) No changes between current HEAD and refs/remotes/git-svn Resetting to the latest refs/remotes/git-svn athom@down:~/git/Berkeley [master]$
--alex 07:21, 6 August 2008 (BST)