Git: Not Just Source Control
At FreshBooks, we really like git for our source control. Git provides us with easy branch management, reliable source control, and the commands are intuitive. But git’s usefulness isn’t limited to source control. We’ve discovered that git’s elegant interface and potent functionality make it useful for all sorts of applications.
For example, a couple of months ago our internal Jabber server was down for maintenance and the maintenance window lasted a bit longer than expected (something about Erlang packages and CentOS, I think). I was working on a project with some other developers located dozens of feet apart and we had been collaborating with each other using Jabber to save the walk to each other’s desks. With the Jabber server down, and facing the productivity hit of having to walk across the office, we did what any developer would do and worked around the problem.
Someone said, “well, we already share code using git, why not use that for messages too?” It seemed so obvious once it was put like that. It was dead simple.
We started out by setting up private message repositories on our local hosts, and a shared project message repository on a central host, then everyone cloned all of the repositories and we set about making the necessary enhancements to our systems to make use git as the transport for a proper messaging system. And then when new people join the team, they create their own messages repository as well, and clone each of the other developers’ messages repositories. Then they have to clone the project repositories. Then every developer has to clone the newbie’s personal repository before they can send him or her messages. But, git is fast, so no big deal.
Sending a message is simple:
jason@jason:~$ echo "This project is the bomb, yo" >> team_msg_01 jason@jason:~$ git add team_msg_01 jason@jason:~$ git commit -m "Message about the project being the bomb, yo" jason@jason:~$ git push origin
Some people felt that four commands to send a message was too much work, so we rolled up a bit of automation:
#!/bin/sh # gitmsg.sh # # usage: gitmsg recipient message # # sends 'message' to 'recipient' using git # expects ~/gitmsg/recipient to exist and to be a git repository pushd ~/gitmsg/$1 git pull origin master #use a concatenation of the current username and timestamp for the filename FILENAME=`whoami``date +%s` echo message > $FILENAME git add $FILENAME git commit -m "New message at `date`" git pull --rebase git push origin master popd
Now sending a message to the project team is a simple one-liner at the terminal prompt:
jason@jason:~$ ./gitmsg.sh sekret_project "I ate all the m&m's, sorry guys" ~/gitmsg/sekret_project ~ [master dbbe3a0] New message at Thu 29 Mar 2012 08:05:55 EDT 1 files changed, 1 insertions(+), 0 deletions(-) create mode 100644 jason1333022755 Counting objects: 3, done. Delta compression using up to 4 threads. Compressing objects: 100% (2/2), done. Writing objects: 100% (2/2), 305 bytes, done. Total 2 (delta 0), reused 0 (delta 0) Unpacking objects: 100% (2/2), done. To ssh://gitmsgserver/git/sekret_project.git/ d648e38..dbbe3a0 master -> master
Of course, sending messages is only half the problem, we need to display them too. Since everyone on the FreshBooks dev team always has at least one terminal window open, this part is easy, we just install git hooks to read new messages as they arrive and display them in the terminal window.
For my private messages repo, I use a local-to-my-computer bare repo that anyone can push messages to, so I need a post-receive hook to display the messages when they arrive:
#!/bin/bash #gitmsg post-receive hook #install in local message repos to output messages as they arrive # while read line do #get the range of commits passed to the hook START=`echo $line|cut -f1 -d ' '` END=`echo $line|cut -f2 -d ' '` commits=`git rev-list --abbrev-commit $END ^$START` for commit in $commits do #get the author information from the commit from=`git log -n1 --format='%aN'` #get the list of files (messages) in the commit files=`git show --pretty="format:" --name-only $commit` #extract the contents (message) from each file for file in $files do message="Message from $from\n\t`git show $commit:$file`" #find terminals that don't look like they're running an editor editor_terminals=`ps -a|egrep -v "(vi|vim|emacs)\ "|grep tty.*|cut -f2 -d' '|uniq` non_editor_terminals=`ps -a|egrep "(vi|vim|emacs)\ "|grep tty.*|cut -f2 -d' '|uniq` terminals=`comm -3 <(echo $editor_terminals |tr ' ' '\n' |sort) <(echo $non_editor_terminals| tr ' ' '\n' |sort)` for terminal in $terminals do echo -e $message|write jason $terminal done #and pop up a growl notification echo -e $message|growlnotify done done done
Of course, each developer maintains their own post-receive hooks so they can tune the notifications however they want. This is what it looks like when I send myself a message using gitmsg:
(The terminal on the left is sending the message, and the terminal on the right is receiving it.)
Git is really amazing. Now that it's supplanted our need for Jabber, we're thinking of using it for even more things. Our bug tracker is looking a little long in the tooth, and everyone's had enough of email so those are certainly candidates!
If you've found new uses for this great tool, share them with us in the comments!