Skip to content

Commit

Permalink
git svn: attempt to create empty dirs on clone+rebase
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Eric Wong committed Nov 16, 2009
1 parent e2f8617 commit 6111b93
Show file tree
Hide file tree
Showing 4 changed files with 139 additions and 2 deletions.
7 changes: 7 additions & 0 deletions Documentation/git-svn.txt
Original file line number Diff line number Diff line change
Expand Up @@ -320,6 +320,13 @@ Any other arguments are passed directly to 'git log'
directories. The output is suitable for appending to
the $GIT_DIR/info/exclude file.

'mkdirs'::
Attempts to recreate empty directories that core git cannot track
based on information in $GIT_DIR/svn/<refname>/unhandled.log files.
Empty directories are automatically recreated when using
"git svn clone" and "git svn rebase", so "mkdirs" is intended
for use after commands like "git checkout" or "git reset".

'commit-diff'::
Commits the diff of two tree-ish arguments from the
command-line. This command does not rely on being inside an `git svn
Expand Down
45 changes: 45 additions & 0 deletions git-svn.perl
Original file line number Diff line number Diff line change
Expand Up @@ -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 } ],
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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};
}
Expand Down
4 changes: 2 additions & 2 deletions t/t9115-git-svn-dcommit-funky-renames.sh
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ test_expect_success 'init and fetch repository' '
'

test_expect_success 'create file in existing ugly and empty dir' '
mkdir "#{bad_directory_name}" &&
mkdir -p "#{bad_directory_name}" &&
echo hi > "#{bad_directory_name}/ foo" &&
git update-index --add "#{bad_directory_name}/ foo" &&
git commit -m "new file in ugly parent" &&
Expand All @@ -37,7 +37,7 @@ test_expect_success 'rename pretty file' '
git update-index --add pretty &&
git commit -m "pretty :x" &&
git svn dcommit &&
mkdir regular_dir_name &&
mkdir -p regular_dir_name &&
git mv pretty regular_dir_name/pretty &&
git commit -m "moved pretty file" &&
git svn dcommit
Expand Down
85 changes: 85 additions & 0 deletions t/t9146-git-svn-empty-dirs.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
#!/bin/sh
#
# Copyright (c) 2009 Eric Wong

test_description='git svn creates empty directories'
. ./lib-git-svn.sh

test_expect_success 'initialize repo' '
for i in a b c d d/e d/e/f "weird file name"
do
svn_cmd mkdir -m "mkdir $i" "$svnrepo"/"$i"
done
'

test_expect_success 'clone' 'git svn clone "$svnrepo" cloned'

test_expect_success 'empty directories exist' '
(
cd cloned &&
for i in a b c d d/e d/e/f "weird file name"
do
if ! test -d "$i"
then
echo >&2 "$i does not exist"
exit 1
fi
done
)
'

test_expect_success 'more emptiness' '
svn_cmd mkdir -m "bang bang" "$svnrepo"/"! !"
'

test_expect_success 'git svn rebase creates empty directory' '
( cd cloned && git svn rebase )
test -d cloned/"! !"
'

test_expect_success 'git svn mkdirs recreates empty directories' '
(
cd cloned &&
rm -r * &&
git svn mkdirs &&
for i in a b c d d/e d/e/f "weird file name" "! !"
do
if ! test -d "$i"
then
echo >&2 "$i does not exist"
exit 1
fi
done
)
'

test_expect_success 'git svn mkdirs -r works' '
(
cd cloned &&
rm -r * &&
git svn mkdirs -r7 &&
for i in a b c d d/e d/e/f "weird file name"
do
if ! test -d "$i"
then
echo >&2 "$i does not exist"
exit 1
fi
done
if test -d "! !"
then
echo >&2 "$i should not exist"
exit 1
fi
git svn mkdirs -r8 &&
if ! test -d "! !"
then
echo >&2 "$i not exist"
exit 1
fi
)
'

test_done

0 comments on commit 6111b93

Please sign in to comment.