@matheusbsbs / matheus-bagliano / commits / 6111b93499
Fork 0

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>

Eric Wong committed Nov 15, 2009 at 18:57 UTC 6111b934991f3ea670ac2442806c976defc7b61c
4 files changed +139 -2
Documentation/git-svn.txt
+7
@@ -320,6 +320,13 @@ Any other arguments are passed directly to 'git log'
320 directories. The output is suitable for appending to
321 the $GIT_DIR/info/exclude file.
322
323 +'mkdirs'::
324 + Attempts to recreate empty directories that core git cannot track
325 + based on information in $GIT_DIR/svn/<refname>/unhandled.log files.
326 + Empty directories are automatically recreated when using
327 + "git svn clone" and "git svn rebase", so "mkdirs" is intended
328 + for use after commands like "git checkout" or "git reset".
329 +
330 'commit-diff'::
331 Commits the diff of two tree-ish arguments from the
332 command-line. This command does not rely on being inside an `git svn
git-svn.perl
+45
@@ -168,6 +168,9 @@ my %cmd = (
168 'Create a .gitignore per svn:ignore',
169 { 'revision|r=i' => \$_revision
170 } ],
171 + 'mkdirs' => [ \&cmd_mkdirs ,
172 + "recreate empty directories after a checkout",
173 + { 'revision|r=i' => \$_revision } ],
174 'propget' => [ \&cmd_propget,
175 'Print the value of a property on a file or directory',
176 { 'revision|r=i' => \$_revision } ],
@@ -769,6 +772,7 @@ sub cmd_rebase {
772 $_fetch_all ? $gs->fetch_all : $gs->fetch;
773 }
774 command_noisy(rebase_cmd(), $gs->refname);
775 + $gs->mkemptydirs;
776 }
777
778 sub cmd_show_ignore {
@@ -830,6 +834,12 @@ sub cmd_create_ignore {
834 });
835 }
836
837 +sub cmd_mkdirs {
838 + my ($url, $rev, $uuid, $gs) = working_head_info('HEAD');
839 + $gs ||= Git::SVN->new;
840 + $gs->mkemptydirs($_revision);
841 +}
842 +
843 sub canonicalize_path {
844 my ($path) = @_;
845 my $dot_slash_added = 0;
@@ -1196,6 +1206,7 @@ sub post_fetch_checkout {
1206 command_noisy(qw/read-tree -m -u -v HEAD HEAD/);
1207 print STDERR "Checked out HEAD:\n ",
1208 $gs->full_url, " r", $gs->last_rev, "\n";
1209 + $gs->mkemptydirs($gs->last_rev);
1210 }
1211
1212 sub complete_svn_url {
@@ -2724,6 +2735,34 @@ sub do_fetch {
2735 $self->make_log_entry($rev, \@parents, $ed);
2736 }
2737
2738 +sub mkemptydirs {
2739 + my ($self, $r) = @_;
2740 + my %empty_dirs = ();
2741 +
2742 + open my $fh, '<', "$self->{dir}/unhandled.log" or return;
2743 + binmode $fh or croak "binmode: $!";
2744 + while (<$fh>) {
2745 + if (defined $r && /^r(\d+)$/) {
2746 + last if $1 > $r;
2747 + } elsif (/^ \+empty_dir: (.+)$/) {
2748 + $empty_dirs{$1} = 1;
2749 + } elsif (/^ \-empty_dir: (.+)$/) {
2750 + delete $empty_dirs{$1};
2751 + }
2752 + }
2753 + close $fh;
2754 + foreach my $d (sort keys %empty_dirs) {
2755 + $d = uri_decode($d);
2756 + next if -d $d;
2757 + if (-e _) {
2758 + warn "$d exists but is not a directory\n";
2759 + } else {
2760 + print "creating empty directory: $d\n";
2761 + mkpath([$d]);
2762 + }
2763 + }
2764 +}
2765 +
2766 sub get_untracked {
2767 my ($self, $ed) = @_;
2768 my @out;
@@ -3556,6 +3595,12 @@ sub uri_encode {
3595 $f
3596 }
3597
3598 +sub uri_decode {
3599 + my ($f) = @_;
3600 + $f =~ s#%([0-9a-fA-F]{2})#chr(hex($1))#eg;
3601 + $f
3602 +}
3603 +
3604 sub remove_username {
3605 $_[0] =~ s{^([^:]*://)[^@]+@}{$1};
3606 }
t/t9115-git-svn-dcommit-funky-renames.sh
+2 -2
@@ -19,7 +19,7 @@ test_expect_success 'init and fetch repository' '
19 '
20
21 test_expect_success 'create file in existing ugly and empty dir' '
22 - mkdir "#{bad_directory_name}" &&
22 + mkdir -p "#{bad_directory_name}" &&
23 echo hi > "#{bad_directory_name}/ foo" &&
24 git update-index --add "#{bad_directory_name}/ foo" &&
25 git commit -m "new file in ugly parent" &&
@@ -37,7 +37,7 @@ test_expect_success 'rename pretty file' '
37 git update-index --add pretty &&
38 git commit -m "pretty :x" &&
39 git svn dcommit &&
40 - mkdir regular_dir_name &&
40 + mkdir -p regular_dir_name &&
41 git mv pretty regular_dir_name/pretty &&
42 git commit -m "moved pretty file" &&
43 git svn dcommit
t/t9146-git-svn-empty-dirs.sh new
+85
@@ -0,0 +1,85 @@
1 +#!/bin/sh
2 +#
3 +# Copyright (c) 2009 Eric Wong
4 +
5 +test_description='git svn creates empty directories'
6 +. ./lib-git-svn.sh
7 +
8 +test_expect_success 'initialize repo' '
9 + for i in a b c d d/e d/e/f "weird file name"
10 + do
11 + svn_cmd mkdir -m "mkdir $i" "$svnrepo"/"$i"
12 + done
13 +'
14 +
15 +test_expect_success 'clone' 'git svn clone "$svnrepo" cloned'
16 +
17 +test_expect_success 'empty directories exist' '
18 + (
19 + cd cloned &&
20 + for i in a b c d d/e d/e/f "weird file name"
21 + do
22 + if ! test -d "$i"
23 + then
24 + echo >&2 "$i does not exist"
25 + exit 1
26 + fi
27 + done
28 + )
29 +'
30 +
31 +test_expect_success 'more emptiness' '
32 + svn_cmd mkdir -m "bang bang" "$svnrepo"/"! !"
33 +'
34 +
35 +test_expect_success 'git svn rebase creates empty directory' '
36 + ( cd cloned && git svn rebase )
37 + test -d cloned/"! !"
38 +'
39 +
40 +test_expect_success 'git svn mkdirs recreates empty directories' '
41 + (
42 + cd cloned &&
43 + rm -r * &&
44 + git svn mkdirs &&
45 + for i in a b c d d/e d/e/f "weird file name" "! !"
46 + do
47 + if ! test -d "$i"
48 + then
49 + echo >&2 "$i does not exist"
50 + exit 1
51 + fi
52 + done
53 + )
54 +'
55 +
56 +test_expect_success 'git svn mkdirs -r works' '
57 + (
58 + cd cloned &&
59 + rm -r * &&
60 + git svn mkdirs -r7 &&
61 + for i in a b c d d/e d/e/f "weird file name"
62 + do
63 + if ! test -d "$i"
64 + then
65 + echo >&2 "$i does not exist"
66 + exit 1
67 + fi
68 + done
69 +
70 + if test -d "! !"
71 + then
72 + echo >&2 "$i should not exist"
73 + exit 1
74 + fi
75 +
76 + git svn mkdirs -r8 &&
77 + if ! test -d "! !"
78 + then
79 + echo >&2 "$i not exist"
80 + exit 1
81 + fi
82 + )
83 +'
84 +
85 +test_done