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.
Examples: The '--ignore-paths' option should match for every 'fetch'
(including automatic fetches due to 'clone', 'dcommit',
'rebase', etc) on a given repository.
--ignore-paths="^doc" - skip "doc*" directory for every fetch. config key: svn-remote.<name>.ignore-paths
--ignore-paths="^[^/]+/(?:branches|tags)" - skip "branches" If the ignore-paths config key is set and the command
and "tags" of first level directories. line option is also given, both regular expressions
will be used.
Regular expression is not persistent, you should specify Examples:
it every time when fetching.
--ignore-paths="^doc" - skip "doc*" directory for every
fetch.
--ignore-paths="^[^/]+/(?:branches|tags)" - skip
"branches" and "tags" of first level directories.
'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 &&