git svn: attempt to create empty dirs on clone+rebase

We parse unhandled.log files for empty_dir statements and make a
best effort attempt to recreate empty directories on fresh
clones and rebase.  This should cover the majority of cases
where users work off a single branch or for projects where
branches do not differ in empty directories.

Since this cannot affect "normal" git commands like "checkout"
or "reset", so users switching between branches in a single
working directory should use the new "git svn mkdirs" command
after switching branches.

Signed-off-by: Eric Wong <normalperson@yhbt.net>
This commit is contained in:
Eric Wong
2009-11-15 18:57:16 -08:00
parent e2f8617b26
commit 6111b93499
4 changed files with 139 additions and 2 deletions

View File

@ -168,6 +168,9 @@ my %cmd = (
'Create a .gitignore per svn:ignore',
{ 'revision|r=i' => \$_revision
} ],
'mkdirs' => [ \&cmd_mkdirs ,
"recreate empty directories after a checkout",
{ 'revision|r=i' => \$_revision } ],
'propget' => [ \&cmd_propget,
'Print the value of a property on a file or directory',
{ 'revision|r=i' => \$_revision } ],
@ -769,6 +772,7 @@ sub cmd_rebase {
$_fetch_all ? $gs->fetch_all : $gs->fetch;
}
command_noisy(rebase_cmd(), $gs->refname);
$gs->mkemptydirs;
}
sub cmd_show_ignore {
@ -830,6 +834,12 @@ sub cmd_create_ignore {
});
}
sub cmd_mkdirs {
my ($url, $rev, $uuid, $gs) = working_head_info('HEAD');
$gs ||= Git::SVN->new;
$gs->mkemptydirs($_revision);
}
sub canonicalize_path {
my ($path) = @_;
my $dot_slash_added = 0;
@ -1196,6 +1206,7 @@ sub post_fetch_checkout {
command_noisy(qw/read-tree -m -u -v HEAD HEAD/);
print STDERR "Checked out HEAD:\n ",
$gs->full_url, " r", $gs->last_rev, "\n";
$gs->mkemptydirs($gs->last_rev);
}
sub complete_svn_url {
@ -2724,6 +2735,34 @@ sub do_fetch {
$self->make_log_entry($rev, \@parents, $ed);
}
sub mkemptydirs {
my ($self, $r) = @_;
my %empty_dirs = ();
open my $fh, '<', "$self->{dir}/unhandled.log" or return;
binmode $fh or croak "binmode: $!";
while (<$fh>) {
if (defined $r && /^r(\d+)$/) {
last if $1 > $r;
} elsif (/^ \+empty_dir: (.+)$/) {
$empty_dirs{$1} = 1;
} elsif (/^ \-empty_dir: (.+)$/) {
delete $empty_dirs{$1};
}
}
close $fh;
foreach my $d (sort keys %empty_dirs) {
$d = uri_decode($d);
next if -d $d;
if (-e _) {
warn "$d exists but is not a directory\n";
} else {
print "creating empty directory: $d\n";
mkpath([$d]);
}
}
}
sub get_untracked {
my ($self, $ed) = @_;
my @out;
@ -3556,6 +3595,12 @@ sub uri_encode {
$f
}
sub uri_decode {
my ($f) = @_;
$f =~ s#%([0-9a-fA-F]{2})#chr(hex($1))#eg;
$f
}
sub remove_username {
$_[0] =~ s{^([^:]*://)[^@]+@}{$1};
}