Applying git patch emails to subversion

Reading time: 2 minutes

I prefer git, but have been spending a lot with subversion working on Module::Build. To give myself local version control when offline (I was on an airplane), I layered a local git repository on top of the subversion checkout. (Yes, there might be better ways to do this with “git svn” but not as easily once already offline!)

Once I had taught git to ignore .svn directories and taught svn to ignore .git and .gitignore, I imported the whole project to git and proceeded with my normal workflow, creating separate branches for different things I was working on.

Once I was back online, I wanted to merge my work back to the subversion tree, while still preserving the commit history from when I was offline. A short bit of Perl programming later and I was done. For each of the git branches I had created, I generated a series of patch emails with “git format-patch”. Then, after having subversion revert all files back to the latest commit, I passed the patches on the command line to this program:

#!/usr/bin/env perl
use 5.010;
use strict;
use warnings;
use Email::Simple;
use Path::Class;
use File::Temp;

die "$0: This is not an svn repo\n"
  unless -d '.svn';

for my $f (sort @ARGV) {
  say "*** $f ***";
  # try to apply patch
  system("patch -p1 < $f");
  die "Patch failed!  Aborting!\n" if $?;

  # extract commit info
  my $email = Email::Simple->new( scalar file($f)->slurp );
  my $subject = $email->header("Subject");
  $subject =~ s{^\[PATCH[^\]]*\]\s+}{};
  my $body = $email->body;
  $body =~ s{\A(.*?)---.*$}{$1}ms;

  # write commit info to tempfile and commit it
  my $temp = File::Temp->new;
  say {$temp} $subject;
  print {$temp} "\n$body" if $body;

  system("svn commit -F $temp");
  die "Commit failed!  Aborting!\n" if $?;

I wouldn’t want this kind of hybrid VCS to be part of my regular workflow, but in a pinch when I wanted offline version control, it worked remarkably well.

•      •      •

If you enjoyed this or have feedback, please let me know by or