Converting SVN Commits to Git Patches
In case you find yourself in need of a way to turn an svn revision into a git patch that can be applied with ‘git am’, keeping the commit message and authorship information, here’s a script I used recently:
#!/usr/bin/python
#
# svnrev2git.py - Convert an SVN revsion to a Git patch.
#
# Author: James Bowes <jbowes@repl.ca>
#
# Usage:
# $> cd my-svn-repo
# $> python svnrev2git.py [AUTHORS_FILE] [REV_RANGE | REVSION [REVISION..]]
#
# AUTHORS_FILE - a CSV of svn username, full name, email
# REV_RANGE - an svn revision range, like 100-700
# REVISION - a single svn revision
#
# You may specify either a revision range, or a series of individual
# svn revisions
#
# Output:
# A series of git style patch files, one per svn revision, which can then be
# applied with 'git am'
#
# Why use this instead of 'git svn'?
# I had done a large repo conversion via git svn where we wanted no downtime
# for the switchover. After removing the git svn specific info from our git
# commits, I used this tool to bring in commits from svn, keeping svn and git
# in sync, until we were ready to switch.
import sys
import commands
def svnlog_to_gitlog(authors, svnlog):
lines = svnlog.split("\n")
lines = lines[1:-1]
metainfo = lines[0].split(" | ")
subject = lines[2]
description = lines[3:]
author = metainfo[1]
day = metainfo[2].split("(")[1][:-1]
time = metainfo[2].split(" ")[1]
offset = metainfo[2].split(" ")[2]
gitlog = []
gitlog += ["From: %s <%s>" % authors[author]]
gitlog += ["Date: %s %s %s" % (day, time, offset)]
gitlog += ["Subject: [PATCH] %s" % subject]
gitlog += [""]
gitlog += description
gitlog += [""]
return '\n'.join(gitlog)
def svndiff_to_gitdiff(svndiff):
lines = svndiff.split("\n")
gitdiff = []
for line in lines:
if line.startswith("--- "):
gitdiff.append("--- a/" + line[4:])
elif line.startswith("+++ "):
gitdiff.append("+++ b/" + line[4:])
else:
gitdiff.append(line)
return '\n'.join(gitdiff)
def make_patch(authors, rev):
out = commands.getoutput("svn log -c %s ." % rev)
if len(out.split("\n")) < 2:
print "skipping r%s" % rev
return
patch = open(rev + ".patch", 'w')
patch.write(svnlog_to_gitlog(authors, out))
patch.write("---\n\n")
out = commands.getoutput("svn diff -c %s ." % rev)
patch.write(svndiff_to_gitdiff(out))
patch.write("\n---\n")
patch.write("svnrev2git.py\n")
patch.close()
print "wrote %s.patch" % rev
def main(args):
author_file = open(args[0])
authors = {}
print "loading authors"
for line in author_file.readlines():
parts = line.strip().split(", ")
authors[parts[0]] = (parts[1], parts[2])
author_file.close()
revs = args[1:]
if len(revs) == 1 and '-' in revs[0]:
start, end = revs[0].split('-')
start = int(start)
end = int(end)
revs = [str(x) for x in range(start, end + 1)]
for rev in revs:
make_patch(authors, rev)
if __name__ == "__main__":
main(sys.argv[1:])
DIY Velcro Cable Ties
Making your own velcro cable ties is a great idea. $2 in materials made as many cable ties as Wal-Mart was selling for $13. Thrifty!
I’d suggest sewing the velcro together vs stapling, especially if you have cats that are far too curious about staples.
Perceptions of Toronto
Growing up on the east coast of Canada, this is how I imagined Toronto to be, like, 24/7.
I’ve been here for nine months or so, and have yet to be invited to any trendy VICE parties. Just so you know, VICE, I am very willing to grow out some stubble and wear vintage clothing or an ironic t-shirt for the event.
Toronto is great though, even without the free Red Stripe.
Graphing Git Repository Activity In ASCII
Here’s a quick little script I wrote up (adapted from this perlmonks post) to show git repository activity as an ascii graph, like so:
The X axis represents a day, with the current day being on the far right. The Y axis is no. of lines added + no. of lines deleted during that day.
EDIT (2009/02/03):
WordPress.com won’t let me attach a .pl file, so here’s the contents:
#!/usr/bin/perl
#
# git-graph.pl - Generate an ascii graph of git repository activity
#
# Copyright (C) 2008 James Bowes <jbowes@dangerouslyinc.com>
#
# Graphing routine Adapted from http://www.perlmonks.org/?node_id=336907
sub get_activity {
my $day = shift;
my $git_cmd = 'git diff --shortstat "@{' . ($day + 1) .' day ago}" "@{' .
($day or "0") . ' day ago}"';
$res = `$git_cmd 2> /dev/null`;
$res =~ /, (.*?) insertions\(\+\), (.*?) deletions\(-\)/;
$activity = $1 + $2;
return $activity;
}
@deltas = ();
foreach $day (0..70) {
push (@deltas, get_activity ($day));
}
print ("\n");
print graph(@deltas);
print ("\n");
sub graph {
my( $i, $magic, $m, $p, $top, @g ) = ( 0, 20, 7, 70, 0, () );
foreach $pad (0..($p - scalar(@_))) {
push (@_, 0);
}
@_ = reverse @_;
for (0..($p)) {
$top = ($top > $_[$_]) ? $top : $_[$_];
}
$top = $top - ($top % 100) + 100;
my $s = $top > $magic ? ( $top / $magic ) : 1; ### calculate scale
for (0..$magic) {
$g[$_] = sprintf("%" . ($m - 1) . "d |", $_ * $s) .
($_ % 5 == 0 ? '_' : ' ') x ($p);
for $i (0..($p)) {
substr($g[$_], ($i + $m), 1) = '#' if ($_[$i] / $s) > $_;
}
}
join( "\n", reverse( @g ), ' Date: ' . '^^^^^^|' x ( $p / 7 ));
} # end sub graph
__END__
Installing ruby gems in your home directory
I found it hard to find good instructions for installing ruby gems as a non-root user without installing the gem package locally as well. Here’s what I figured out; hopefully this will save someone else some time in the future:
Make a directory for gem installation:
$> mkdir ~/.gems
Set up your .gemrc for gem install-time configuration:
$> cat << EOF > ~/.gemrc
gemhome: $HOME/gems
gempath:
- $HOME/gems
- /usr/lib/ruby/gems/1.8
EOF
Set up some environment variables for run-time:
$> cat << EOF >> ~/.bashrc
export GEM_HOME=$HOME/gems
export GEM_PATH=$HOME/gems:/usr/lib/ruby/gems/1.8/
export PATH=$PATH:$HOME/gems/bin
EOF
Source your bashrc and you’re all set.
UPDATE (Apr 18, 2009): gem seems to do this on its own now, so just adding
export PATH=$PATH:$HOME/.gem/ruby/1.8/bin
to your .bash_profile should be enough.
Shell HIstory Meme
[jbowes@laptop ~]$ history | awk '{a[$2]++ } END{for(i in a){print a[i] " " i}}'|sort -rn|head
211 git
148 fg
107 ls
99 cd
89 python
43 make
26 vim
23 sudo
20 nosetests
19 player/swfplay
[jbowes@workstation ~]$ history | awk '{a[$2]++ } END{for(i in a){print a[i] " " i}}'|sort -rn|head -n 12
163 ls
156 cd
115 svn
76 vim
70 screen
55 fg
47 exit
35 sudo
30 git
21 yasql
Cat News
Our boy cat Julius passed away a few weeks ago. It was pretty shocking, as he was quite young and his passing was sudden and unexpected. While we miss him terribly, Cherie and I didn’t want Spook to get too used to being an only cat again.
So this weekend we picked up a new little fellow from the Toronto Humane Society:
He doesn’t have a name yet, but he sure has quite a pair of ears on him!
2% Genius
Agile Tsar Dmitri Dolguikh pointed out Project Euler yesterday, which is a website containing a series of short programming problems. It reads a bit like bonus questions on a math exam, which is actually quite refreshing compared to the day-to-day problems at work. For added fun, I’m trying to run through the problems in Common Lisp.
So far I have completed 4 out of 179 problems, which makes me 2% genius, according to the site.
Mission Accomplished!
A lot of people are linking to this article about the state of the practice in CS curriculum and its use of Java creating dull replaceable drones.
mdehaan points out a wonderful section wherein the authors relate Java programming to a plumber in a hardware store, finding pieces and putting them together to solve a problem, rather than their unmentioned alternative (maybe an artist molding clay?)
If this is true, then we, the software industry and software engineering fields, are done. We have found the holy grail: true modularity and reusable software components. Drop whatever language you’re using and switch to Java.





