Skip to content

Commit 643faee

Browse files
committed
Merge git://git.bogomips.org/git-svn
* git://git.bogomips.org/git-svn: Document git-svn's first-parent rule git svn: attempt to create empty dirs on clone+rebase git svn: add authorsfile test case for ~/.gitconfig git svn: read global+system config for clone+init git svn: handle SVN merges from revisions past the tip of the branch
2 parents 785c58e + ce45a45 commit 643faee

File tree

8 files changed

+545
-65
lines changed

8 files changed

+545
-65
lines changed

Documentation/git-svn.txt

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -320,6 +320,13 @@ Any other arguments are passed directly to 'git log'
320320
directories. The output is suitable for appending to
321321
the $GIT_DIR/info/exclude file.
322322

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+
323330
'commit-diff'::
324331
Commits the diff of two tree-ish arguments from the
325332
command-line. This command does not rely on being inside an `git svn
@@ -735,6 +742,16 @@ merges you've made. Furthermore, if you merge or pull from a git branch
735742
that is a mirror of an SVN branch, 'dcommit' may commit to the wrong
736743
branch.
737744

745+
If you do merge, note the following rule: 'git svn dcommit' will
746+
attempt to commit on top of the SVN commit named in
747+
------------------------------------------------------------------------
748+
git log --grep=^git-svn-id: --first-parent -1
749+
------------------------------------------------------------------------
750+
You 'must' therefore ensure that the most recent commit of the branch
751+
you want to dcommit to is the 'first' parent of the merge. Chaos will
752+
ensue otherwise, especially if the first parent is an older commit on
753+
the same SVN branch.
754+
738755
'git clone' does not clone branches under the refs/remotes/ hierarchy or
739756
any 'git svn' metadata, or config. So repositories created and managed with
740757
using 'git svn' should use 'rsync' for cloning, if cloning is to be done

git-svn.perl

Lines changed: 52 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -168,6 +168,9 @@ BEGIN
168168
'Create a .gitignore per svn:ignore',
169169
{ 'revision|r=i' => \$_revision
170170
} ],
171+
'mkdirs' => [ \&cmd_mkdirs ,
172+
"recreate empty directories after a checkout",
173+
{ 'revision|r=i' => \$_revision } ],
171174
'propget' => [ \&cmd_propget,
172175
'Print the value of a property on a file or directory',
173176
{ 'revision|r=i' => \$_revision } ],
@@ -274,7 +277,7 @@ BEGIN
274277

275278
my %opts = %{$cmd{$cmd}->[2]} if (defined $cmd);
276279

277-
read_repo_config(\%opts);
280+
read_git_config(\%opts);
278281
if ($cmd && ($cmd eq 'log' || $cmd eq 'blame')) {
279282
Getopt::Long::Configure('pass_through');
280283
}
@@ -769,6 +772,7 @@ sub cmd_rebase {
769772
$_fetch_all ? $gs->fetch_all : $gs->fetch;
770773
}
771774
command_noisy(rebase_cmd(), $gs->refname);
775+
$gs->mkemptydirs;
772776
}
773777

774778
sub cmd_show_ignore {
@@ -830,6 +834,12 @@ sub cmd_create_ignore {
830834
});
831835
}
832836

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+
833843
sub canonicalize_path {
834844
my ($path) = @_;
835845
my $dot_slash_added = 0;
@@ -1196,6 +1206,7 @@ sub post_fetch_checkout {
11961206
command_noisy(qw/read-tree -m -u -v HEAD HEAD/);
11971207
print STDERR "Checked out HEAD:\n ",
11981208
$gs->full_url, " r", $gs->last_rev, "\n";
1209+
$gs->mkemptydirs($gs->last_rev);
11991210
}
12001211

12011212
sub complete_svn_url {
@@ -1390,8 +1401,7 @@ sub load_authors {
13901401
}
13911402

13921403
# convert GetOpt::Long specs for use by git-config
1393-
sub read_repo_config {
1394-
return unless -d $ENV{GIT_DIR};
1404+
sub read_git_config {
13951405
my $opts = shift;
13961406
my @config_only;
13971407
foreach my $o (keys %$opts) {
@@ -2725,6 +2735,34 @@ sub do_fetch {
27252735
$self->make_log_entry($rev, \@parents, $ed);
27262736
}
27272737

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+
27282766
sub get_untracked {
27292767
my ($self, $ed) = @_;
27302768
my @out;
@@ -2950,8 +2988,11 @@ sub find_extra_svn_parents {
29502988
my $bottom_commit =
29512989
$gs->rev_map_get($bottom, $self->ra_uuid) ||
29522990
$gs->rev_map_get($bottom+1, $self->ra_uuid);
2953-
my $top_commit =
2954-
$gs->rev_map_get($top, $self->ra_uuid);
2991+
my $top_commit;
2992+
for (; !$top_commit && $top >= $bottom; --$top) {
2993+
$top_commit =
2994+
$gs->rev_map_get($top, $self->ra_uuid);
2995+
}
29552996

29562997
unless ($top_commit and $bottom_commit) {
29572998
warn "W:unknown path/rev in svn:mergeinfo "
@@ -3554,6 +3595,12 @@ sub uri_encode {
35543595
$f
35553596
}
35563597

3598+
sub uri_decode {
3599+
my ($f) = @_;
3600+
$f =~ s#%([0-9a-fA-F]{2})#chr(hex($1))#eg;
3601+
$f
3602+
}
3603+
35573604
sub remove_username {
35583605
$_[0] =~ s{^([^:]*://)[^@]+@}{$1};
35593606
}

t/t9115-git-svn-dcommit-funky-renames.sh

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@ test_expect_success 'init and fetch repository' '
1919
'
2020

2121
test_expect_success 'create file in existing ugly and empty dir' '
22-
mkdir "#{bad_directory_name}" &&
22+
mkdir -p "#{bad_directory_name}" &&
2323
echo hi > "#{bad_directory_name}/ foo" &&
2424
git update-index --add "#{bad_directory_name}/ foo" &&
2525
git commit -m "new file in ugly parent" &&
@@ -37,7 +37,7 @@ test_expect_success 'rename pretty file' '
3737
git update-index --add pretty &&
3838
git commit -m "pretty :x" &&
3939
git svn dcommit &&
40-
mkdir regular_dir_name &&
40+
mkdir -p regular_dir_name &&
4141
git mv pretty regular_dir_name/pretty &&
4242
git commit -m "moved pretty file" &&
4343
git svn dcommit

t/t9130-git-svn-authors-file.sh

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,4 +91,27 @@ test_expect_success 'fetch continues after authors-file is fixed' '
9191
)
9292
'
9393

94+
test_expect_success 'fresh clone with svn.authors-file in config' '
95+
(
96+
rm -r "$GIT_DIR" &&
97+
test x = x"$(git config svn.authorsfile)" &&
98+
HOME="`pwd`" &&
99+
export HOME &&
100+
test_config="$HOME"/.gitconfig &&
101+
unset GIT_CONFIG_NOGLOBAL &&
102+
unset GIT_DIR &&
103+
unset GIT_CONFIG &&
104+
git config --global \
105+
svn.authorsfile "$HOME"/svn-authors &&
106+
test x"$HOME"/svn-authors = x"$(git config svn.authorsfile)" &&
107+
git svn clone "$svnrepo" gitconfig.clone &&
108+
cd gitconfig.clone &&
109+
nr_ex=$(git log | grep "^Author:.*example.com" | wc -l) &&
110+
nr_rev=$(git rev-list HEAD | wc -l) &&
111+
test $nr_rev -eq $nr_ex
112+
)
113+
'
114+
115+
test_debug 'GIT_DIR=gitconfig.clone/.git git log'
116+
94117
test_done

t/t9146-git-svn-empty-dirs.sh

Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -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

t/t9151-svn-mergeinfo.sh

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,11 @@ test_expect_success 'load svn dump' "
1515
git svn fetch --all
1616
"
1717

18-
test_expect_success 'svn merges were represented coming in' "
18+
test_expect_success 'represent svn merges without intervening commits' "
19+
[ `git cat-file commit HEAD^1 | grep parent | wc -l` -eq 2 ]
20+
"
21+
22+
test_expect_success 'represent svn merges with intervening commits' "
1923
[ `git cat-file commit HEAD | grep parent | wc -l` -eq 2 ]
2024
"
2125

t/t9151/make-svnmerge-dump

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,10 @@ svn cp trunk branches/left
2828

2929
echo "Committing BRANCH POINT"
3030
svn commit -m "make left branch"
31+
svn cp trunk branches/right
32+
33+
echo "Committing other BRANCH POINT"
34+
svn commit -m "make right branch"
3135
cd branches/left/
3236

3337
#$sm init
@@ -64,7 +68,33 @@ git cat-file blob b51ad431:Makefile > Makefile
6468

6569
svn resolved Makefile
6670

67-
svn commit -m "Merge trunk"
71+
svn commit -m "Merge trunk 1"
72+
73+
# create commits on both branches
74+
75+
cd ../branches/left
76+
git cat-file blob ff5ebe39:Makefile > Makefile
77+
echo "Committing BRANCH UPDATE 4"
78+
svn commit -m "left update 4"
79+
80+
cd ../right
81+
git cat-file blob b5039db6:Makefile > Makefile
82+
echo "Committing other BRANCH UPDATE 1"
83+
svn commit -m "right update 1"
84+
85+
# merge to trun again
86+
87+
cd ../..
88+
svn update
89+
cd trunk
90+
91+
svn merge ../branches/left --accept postpone
92+
93+
git cat-file blob b51ad431:Makefile > Makefile
94+
95+
svn resolved Makefile
96+
97+
svn commit -m "Merge trunk 2"
6898

6999
cd ../..
70100

0 commit comments

Comments
 (0)