Skip to content

Commit

Permalink
Merge git://git.bogomips.org/git-svn
Browse files Browse the repository at this point in the history
* 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
  • Loading branch information
Junio C Hamano committed Nov 17, 2009
2 parents 785c58e + ce45a45 commit 643faee
Show file tree
Hide file tree
Showing 8 changed files with 545 additions and 65 deletions.
17 changes: 17 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 Expand Up @@ -735,6 +742,16 @@ merges you've made. Furthermore, if you merge or pull from a git branch
that is a mirror of an SVN branch, 'dcommit' may commit to the wrong
branch.

If you do merge, note the following rule: 'git svn dcommit' will
attempt to commit on top of the SVN commit named in
------------------------------------------------------------------------
git log --grep=^git-svn-id: --first-parent -1
------------------------------------------------------------------------
You 'must' therefore ensure that the most recent commit of the branch
you want to dcommit to is the 'first' parent of the merge. Chaos will
ensue otherwise, especially if the first parent is an older commit on
the same SVN branch.

'git clone' does not clone branches under the refs/remotes/ hierarchy or
any 'git svn' metadata, or config. So repositories created and managed with
using 'git svn' should use 'rsync' for cloning, if cloning is to be done
Expand Down
57 changes: 52 additions & 5 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 @@ -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');
}
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 @@ -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) {
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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 "
Expand Down Expand Up @@ -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};
}
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
23 changes: 23 additions & 0 deletions t/t9130-git-svn-authors-file.sh
Original file line number Diff line number Diff line change
Expand Up @@ -91,4 +91,27 @@ test_expect_success 'fetch continues after authors-file is fixed' '
)
'

test_expect_success 'fresh clone with svn.authors-file in config' '
(
rm -r "$GIT_DIR" &&
test x = x"$(git config svn.authorsfile)" &&
HOME="`pwd`" &&
export HOME &&
test_config="$HOME"/.gitconfig &&
unset GIT_CONFIG_NOGLOBAL &&
unset GIT_DIR &&
unset GIT_CONFIG &&
git config --global \
svn.authorsfile "$HOME"/svn-authors &&
test x"$HOME"/svn-authors = x"$(git config svn.authorsfile)" &&
git svn clone "$svnrepo" gitconfig.clone &&
cd gitconfig.clone &&
nr_ex=$(git log | grep "^Author:.*example.com" | wc -l) &&
nr_rev=$(git rev-list HEAD | wc -l) &&
test $nr_rev -eq $nr_ex
)
'

test_debug 'GIT_DIR=gitconfig.clone/.git git log'

test_done
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
6 changes: 5 additions & 1 deletion t/t9151-svn-mergeinfo.sh
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,11 @@ test_expect_success 'load svn dump' "
git svn fetch --all
"

test_expect_success 'svn merges were represented coming in' "
test_expect_success 'represent svn merges without intervening commits' "
[ `git cat-file commit HEAD^1 | grep parent | wc -l` -eq 2 ]
"

test_expect_success 'represent svn merges with intervening commits' "
[ `git cat-file commit HEAD | grep parent | wc -l` -eq 2 ]
"

Expand Down
32 changes: 31 additions & 1 deletion t/t9151/make-svnmerge-dump
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,10 @@ svn cp trunk branches/left

echo "Committing BRANCH POINT"
svn commit -m "make left branch"
svn cp trunk branches/right

echo "Committing other BRANCH POINT"
svn commit -m "make right branch"
cd branches/left/

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

svn resolved Makefile

svn commit -m "Merge trunk"
svn commit -m "Merge trunk 1"

# create commits on both branches

cd ../branches/left
git cat-file blob ff5ebe39:Makefile > Makefile
echo "Committing BRANCH UPDATE 4"
svn commit -m "left update 4"

cd ../right
git cat-file blob b5039db6:Makefile > Makefile
echo "Committing other BRANCH UPDATE 1"
svn commit -m "right update 1"

# merge to trun again

cd ../..
svn update
cd trunk

svn merge ../branches/left --accept postpone

git cat-file blob b51ad431:Makefile > Makefile

svn resolved Makefile

svn commit -m "Merge trunk 2"

cd ../..

Expand Down
Loading

0 comments on commit 643faee

Please sign in to comment.