git-svn: Add per-svn-remote ignore-paths config

The --ignore-paths option to fetch is very useful for working on a subset
of a SVN repository.  For proper operation, every command that causes a
fetch (explicit or implied) must include a matching --ignore-paths option.

This patch adds a persistent svn-remote.$repo_id.ignore-paths config by
promoting Fetcher::is_path_ignored to a member function and initializing
$self->{ignore_regex} in Fetcher::new.  Command line --ignore-paths is
still recognized and acts in addition to the config value.

Signed-off-by: Ben Jackson <ben@ben.com>
Acked-by: Eric Wong <normalperson@yhbt.net>
This commit is contained in:
Ben Jackson
2009-04-11 10:46:17 -07:00
committed by Eric Wong
parent 6ea4203288
commit 0d8bee71af
3 changed files with 82 additions and 21 deletions

View File

@ -107,17 +107,25 @@ repository, either don't use this option or you should both use it in
the same local timezone. the same local timezone.
--ignore-paths=<regex>;; --ignore-paths=<regex>;;
This allows one to specify Perl regular expression that will This allows one to specify a Perl regular expression that will
cause skipping of all matching paths from checkout from SVN. cause skipping of all matching paths from checkout from SVN.
The '--ignore-paths' option should match for every 'fetch'
(including automatic fetches due to 'clone', 'dcommit',
'rebase', etc) on a given repository.
config key: svn-remote.<name>.ignore-paths
If the ignore-paths config key is set and the command
line option is also given, both regular expressions
will be used.
Examples: Examples:
--ignore-paths="^doc" - skip "doc*" directory for every fetch. --ignore-paths="^doc" - skip "doc*" directory for every
fetch.
--ignore-paths="^[^/]+/(?:branches|tags)" - skip "branches" --ignore-paths="^[^/]+/(?:branches|tags)" - skip
and "tags" of first level directories. "branches" and "tags" of first level directories.
Regular expression is not persistent, you should specify
it every time when fetching.
'clone':: 'clone'::
Runs 'init' and 'fetch'. It will automatically create a Runs 'init' and 'fetch'. It will automatically create a

View File

@ -3331,6 +3331,8 @@ sub new {
$self->{empty_symlinks} = $self->{empty_symlinks} =
_mark_empty_symlinks($git_svn, $switch_path); _mark_empty_symlinks($git_svn, $switch_path);
} }
$self->{ignore_regex} = eval { command_oneline('config', '--get',
"svn-remote.$git_svn->{repo_id}.ignore-paths") };
$self->{empty} = {}; $self->{empty} = {};
$self->{dir_prop} = {}; $self->{dir_prop} = {};
$self->{file_prop} = {}; $self->{file_prop} = {};
@ -3395,8 +3397,10 @@ sub in_dot_git {
# return value: 0 -- don't ignore, 1 -- ignore # return value: 0 -- don't ignore, 1 -- ignore
sub is_path_ignored { sub is_path_ignored {
my ($path) = @_; my ($self, $path) = @_;
return 1 if in_dot_git($path); return 1 if in_dot_git($path);
return 1 if defined($self->{ignore_regex}) &&
$path =~ m!$self->{ignore_regex}!;
return 0 unless defined($_ignore_regex); return 0 unless defined($_ignore_regex);
return 1 if $path =~ m!$_ignore_regex!o; return 1 if $path =~ m!$_ignore_regex!o;
return 0; return 0;
@ -3427,7 +3431,7 @@ sub git_path {
sub delete_entry { sub delete_entry {
my ($self, $path, $rev, $pb) = @_; my ($self, $path, $rev, $pb) = @_;
return undef if is_path_ignored($path); return undef if $self->is_path_ignored($path);
my $gpath = $self->git_path($path); my $gpath = $self->git_path($path);
return undef if ($gpath eq ''); return undef if ($gpath eq '');
@ -3460,7 +3464,7 @@ sub open_file {
my ($self, $path, $pb, $rev) = @_; my ($self, $path, $pb, $rev) = @_;
my ($mode, $blob); my ($mode, $blob);
goto out if is_path_ignored($path); goto out if $self->is_path_ignored($path);
my $gpath = $self->git_path($path); my $gpath = $self->git_path($path);
($mode, $blob) = (command('ls-tree', '-z', $self->{c}, "./$gpath") ($mode, $blob) = (command('ls-tree', '-z', $self->{c}, "./$gpath")
@ -3480,7 +3484,7 @@ sub add_file {
my ($self, $path, $pb, $cp_path, $cp_rev) = @_; my ($self, $path, $pb, $cp_path, $cp_rev) = @_;
my $mode; my $mode;
if (!is_path_ignored($path)) { if (!$self->is_path_ignored($path)) {
my ($dir, $file) = ($path =~ m#^(.*?)/?([^/]+)$#); my ($dir, $file) = ($path =~ m#^(.*?)/?([^/]+)$#);
delete $self->{empty}->{$dir}; delete $self->{empty}->{$dir};
$mode = '100644'; $mode = '100644';
@ -3491,7 +3495,7 @@ sub add_file {
sub add_directory { sub add_directory {
my ($self, $path, $cp_path, $cp_rev) = @_; my ($self, $path, $cp_path, $cp_rev) = @_;
goto out if is_path_ignored($path); goto out if $self->is_path_ignored($path);
my $gpath = $self->git_path($path); my $gpath = $self->git_path($path);
if ($gpath eq '') { if ($gpath eq '') {
my ($ls, $ctx) = command_output_pipe(qw/ls-tree my ($ls, $ctx) = command_output_pipe(qw/ls-tree
@ -3515,7 +3519,7 @@ out:
sub change_dir_prop { sub change_dir_prop {
my ($self, $db, $prop, $value) = @_; my ($self, $db, $prop, $value) = @_;
return undef if is_path_ignored($db->{path}); return undef if $self->is_path_ignored($db->{path});
$self->{dir_prop}->{$db->{path}} ||= {}; $self->{dir_prop}->{$db->{path}} ||= {};
$self->{dir_prop}->{$db->{path}}->{$prop} = $value; $self->{dir_prop}->{$db->{path}}->{$prop} = $value;
undef; undef;
@ -3523,7 +3527,7 @@ sub change_dir_prop {
sub absent_directory { sub absent_directory {
my ($self, $path, $pb) = @_; my ($self, $path, $pb) = @_;
return undef if is_path_ignored($path); return undef if $self->is_path_ignored($path);
$self->{absent_dir}->{$pb->{path}} ||= []; $self->{absent_dir}->{$pb->{path}} ||= [];
push @{$self->{absent_dir}->{$pb->{path}}}, $path; push @{$self->{absent_dir}->{$pb->{path}}}, $path;
undef; undef;
@ -3531,7 +3535,7 @@ sub absent_directory {
sub absent_file { sub absent_file {
my ($self, $path, $pb) = @_; my ($self, $path, $pb) = @_;
return undef if is_path_ignored($path); return undef if $self->is_path_ignored($path);
$self->{absent_file}->{$pb->{path}} ||= []; $self->{absent_file}->{$pb->{path}} ||= [];
push @{$self->{absent_file}->{$pb->{path}}}, $path; push @{$self->{absent_file}->{$pb->{path}}}, $path;
undef; undef;
@ -3539,7 +3543,7 @@ sub absent_file {
sub change_file_prop { sub change_file_prop {
my ($self, $fb, $prop, $value) = @_; my ($self, $fb, $prop, $value) = @_;
return undef if is_path_ignored($fb->{path}); return undef if $self->is_path_ignored($fb->{path});
if ($prop eq 'svn:executable') { if ($prop eq 'svn:executable') {
if ($fb->{mode_b} != 120000) { if ($fb->{mode_b} != 120000) {
$fb->{mode_b} = defined $value ? 100755 : 100644; $fb->{mode_b} = defined $value ? 100755 : 100644;
@ -3555,7 +3559,7 @@ sub change_file_prop {
sub apply_textdelta { sub apply_textdelta {
my ($self, $fb, $exp) = @_; my ($self, $fb, $exp) = @_;
return undef if is_path_ignored($fb->{path}); return undef if $self->is_path_ignored($fb->{path});
my $fh = $::_repository->temp_acquire('svn_delta'); my $fh = $::_repository->temp_acquire('svn_delta');
# $fh gets auto-closed() by SVN::TxDelta::apply(), # $fh gets auto-closed() by SVN::TxDelta::apply(),
# (but $base does not,) so dup() it for reading in close_file # (but $base does not,) so dup() it for reading in close_file
@ -3602,7 +3606,7 @@ sub apply_textdelta {
sub close_file { sub close_file {
my ($self, $fb, $exp) = @_; my ($self, $fb, $exp) = @_;
return undef if is_path_ignored($fb->{path}); return undef if $self->is_path_ignored($fb->{path});
my $hash; my $hash;
my $path = $self->git_path($fb->{path}); my $path = $self->git_path($fb->{path});

View File

@ -31,6 +31,22 @@ test_expect_success 'clone an SVN repository with ignored www directory' '
test_cmp expect expect2 test_cmp expect expect2
' '
test_expect_success 'init+fetch an SVN repository with ignored www directory' '
git svn init "$svnrepo" c &&
( cd c && git svn fetch --ignore-paths="^www" ) &&
rm expect2 &&
echo test_qqq > expect &&
for i in c/*/*.txt; do cat $i >> expect2; done &&
test_cmp expect expect2
'
test_expect_success 'set persistent ignore-paths config' '
(
cd g &&
git config svn-remote.svn.ignore-paths "^www"
)
'
test_expect_success 'SVN-side change outside of www' ' test_expect_success 'SVN-side change outside of www' '
( (
cd s && cd s &&
@ -41,9 +57,20 @@ test_expect_success 'SVN-side change outside of www' '
) )
' '
test_expect_success 'update git svn-cloned repo' ' test_expect_success 'update git svn-cloned repo (config ignore)' '
( (
cd g && cd g &&
git svn rebase &&
printf "test_qqq\nb\n" > expect &&
for i in */*.txt; do cat $i >> expect2; done &&
test_cmp expect2 expect &&
rm expect expect2
)
'
test_expect_success 'update git svn-cloned repo (option ignore)' '
(
cd c &&
git svn rebase --ignore-paths="^www" && git svn rebase --ignore-paths="^www" &&
printf "test_qqq\nb\n" > expect && printf "test_qqq\nb\n" > expect &&
for i in */*.txt; do cat $i >> expect2; done && for i in */*.txt; do cat $i >> expect2; done &&
@ -62,9 +89,20 @@ test_expect_success 'SVN-side change inside of ignored www' '
) )
' '
test_expect_success 'update git svn-cloned repo' ' test_expect_success 'update git svn-cloned repo (config ignore)' '
( (
cd g && cd g &&
git svn rebase &&
printf "test_qqq\nb\n" > expect &&
for i in */*.txt; do cat $i >> expect2; done &&
test_cmp expect2 expect &&
rm expect expect2
)
'
test_expect_success 'update git svn-cloned repo (option ignore)' '
(
cd c &&
git svn rebase --ignore-paths="^www" && git svn rebase --ignore-paths="^www" &&
printf "test_qqq\nb\n" > expect && printf "test_qqq\nb\n" > expect &&
for i in */*.txt; do cat $i >> expect2; done && for i in */*.txt; do cat $i >> expect2; done &&
@ -84,9 +122,20 @@ test_expect_success 'SVN-side change in and out of ignored www' '
) )
' '
test_expect_success 'update git svn-cloned repo again' ' test_expect_success 'update git svn-cloned repo again (config ignore)' '
( (
cd g && cd g &&
git svn rebase &&
printf "test_qqq\nb\nygg\n" > expect &&
for i in */*.txt; do cat $i >> expect2; done &&
test_cmp expect2 expect &&
rm expect expect2
)
'
test_expect_success 'update git svn-cloned repo again (option ignore)' '
(
cd c &&
git svn rebase --ignore-paths="^www" && git svn rebase --ignore-paths="^www" &&
printf "test_qqq\nb\nygg\n" > expect && printf "test_qqq\nb\nygg\n" > expect &&
for i in */*.txt; do cat $i >> expect2; done && for i in */*.txt; do cat $i >> expect2; done &&