git svn: attempt to create empty dirs on clone+rebase
[gitweb.git] / git-svn.perl
index 6a3b501d24ebaa50e297511ccf0b18e3bbd2bb16..ab0a8dd0990ac030db046efdcdae74978a2d8c46 100755 (executable)
@@ -168,6 +168,9 @@ BEGIN
                             '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 } ],
@@ -274,7 +277,7 @@ BEGIN
 
 my %opts = %{$cmd{$cmd}->[2]} if (defined $cmd);
 
-read_repo_config(\%opts);
+read_git_config(\%opts);
 if ($cmd && ($cmd eq 'log' || $cmd eq 'blame')) {
        Getopt::Long::Configure('pass_through');
 }
@@ -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 {
@@ -1390,8 +1401,7 @@ sub load_authors {
 }
 
 # convert GetOpt::Long specs for use by git-config
-sub read_repo_config {
-       return unless -d $ENV{GIT_DIR};
+sub read_git_config {
        my $opts = shift;
        my @config_only;
        foreach my $o (keys %$opts) {
@@ -2725,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;
@@ -2950,8 +2988,11 @@ sub find_extra_svn_parents {
                        my $bottom_commit =
                                $gs->rev_map_get($bottom, $self->ra_uuid) ||
                                $gs->rev_map_get($bottom+1, $self->ra_uuid);
-                       my $top_commit =
-                               $gs->rev_map_get($top, $self->ra_uuid);
+                       my $top_commit;
+                       for (; !$top_commit && $top >= $bottom; --$top) {
+                               $top_commit =
+                                       $gs->rev_map_get($top, $self->ra_uuid);
+                       }
 
                        unless ($top_commit and $bottom_commit) {
                                warn "W:unknown path/rev in svn:mergeinfo "
@@ -3554,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};
 }