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.