git-svn: added an --include-path flag
authorPaul Walmsley <pjwhams@gmail.com>
Fri, 3 May 2013 23:10:18 +0000 (00:10 +0100)
committerEric Wong <normalperson@yhbt.net>
Thu, 9 May 2013 01:13:36 +0000 (01:13 +0000)
The SVN::Fetcher module is now able to filter for inclusion as well
as exclusion (as used by --ignore-path). Also added tests, documentation
changes and git completion script.

If you have an SVN repository with many top level directories and you
only want a git-svn clone of some of them then using --ignore-path is
difficult as it requires a very long regexp. In this case it's much
easier to filter for inclusion.

[ew: remove trailing whitespace]

Signed-off-by: Paul Walmsley <pjwhams@gmail.com>
Signed-off-by: Eric Wong <normalperson@yhbt.net>
Documentation/git-svn.txt
contrib/completion/git-completion.bash
git-svn.perl
perl/Git/SVN/Fetcher.pm
t/t9147-git-svn-include-paths.sh [new file with mode: 0755]
index 7706d41c8704679c00a302306651628e5b99d1c1..58b6d540ca6173e03bbc2dc01686f5483e01ae27 100644 (file)
@@ -85,6 +85,10 @@ COMMANDS
        When passed to 'init' or 'clone' this regular expression will
        be preserved as a config key.  See 'fetch' for a description
        of '--ignore-paths'.
+--include-paths=<regex>;;
+       When passed to 'init' or 'clone' this regular expression will
+       be preserved as a config key.  See 'fetch' for a description
+       of '--include-paths'.
 --no-minimize-url;;
        When tracking multiple directories (using --stdlayout,
        --branches, or --tags options), git svn will attempt to connect
@@ -146,6 +150,14 @@ Skip "branches" and "tags" of first level directories;;
 ------------------------------------------------------------------------
 --
 
+--include-paths=<regex>;;
+       This allows one to specify a Perl regular expression that will
+       cause the inclusion of only matching paths from checkout from SVN.
+       The '--include-paths' option should match for every 'fetch'
+       (including automatic fetches due to 'clone', 'dcommit',
+       'rebase', etc) on a given repository. '--ignore-paths' takes
+       precedence over '--include-paths'.
+
 --log-window-size=<n>;;
     Fetch <n> log entries per request when scanning Subversion history.
     The default is 100. For very large Subversion repositories, larger
index b97162f38196d82b2f39f2b151e279d0569f8440..a98c2fd2de4dbd7ed659daee9303389be91bf8ac 100644 (file)
@@ -2451,7 +2451,7 @@ _git_svn ()
                        --no-metadata --use-svm-props --use-svnsync-props
                        --log-window-size= --no-checkout --quiet
                        --repack-flags --use-log-author --localtime
-                       --ignore-paths= $remote_opts
+                       --ignore-paths= --include-paths= $remote_opts
                        "
                local init_opts="
                        --template= --shared= --trunk= --tags=
index 705f5ab4c8c4d893f65300494751cc833f146bcc..ccabe065f3d2b7c18b0104bf3c9e568b5ab4011b 100755 (executable)
@@ -126,6 +126,7 @@ sub _req_svn {
                     'config-dir=s' => \$Git::SVN::Ra::config_dir,
                     'no-auth-cache' => \$Git::SVN::Prompt::_no_auth_cache,
                     'ignore-paths=s' => \$Git::SVN::Fetcher::_ignore_regex,
+                    'include-paths=s' => \$Git::SVN::Fetcher::_include_regex,
                     'ignore-refs=s' => \$Git::SVN::Ra::_ignore_refs_regex );
 my %fc_opts = ( 'follow-parent|follow!' => \$Git::SVN::_follow_parent,
                'authors-file|A=s' => \$_authors,
@@ -470,6 +471,9 @@ sub do_git_init_db {
        my $ignore_paths_regex = \$Git::SVN::Fetcher::_ignore_regex;
        command_noisy('config', "$pfx.ignore-paths", $$ignore_paths_regex)
                if defined $$ignore_paths_regex;
+       my $include_paths_regex = \$Git::SVN::Fetcher::_include_regex;
+       command_noisy('config', "$pfx.include-paths", $$include_paths_regex)
+               if defined $$include_paths_regex;
        my $ignore_refs_regex = \$Git::SVN::Ra::_ignore_refs_regex;
        command_noisy('config', "$pfx.ignore-refs", $$ignore_refs_regex)
                if defined $$ignore_refs_regex;
index 72150af687d4e997409afa92add46747913f420b..bd174189b98fda05f781697be26db94c9cd53364 100644 (file)
@@ -1,6 +1,7 @@
 package Git::SVN::Fetcher;
-use vars qw/@ISA $_ignore_regex $_preserve_empty_dirs $_placeholder_filename
-            @deleted_gpath %added_placeholder $repo_id/;
+use vars qw/@ISA $_ignore_regex $_include_regex $_preserve_empty_dirs
+            $_placeholder_filename @deleted_gpath %added_placeholder
+            $repo_id/;
 use strict;
 use warnings;
 use SVN::Delta;
@@ -33,6 +34,10 @@ sub new {
        my $v = eval { command_oneline('config', '--get', $k) };
        $self->{ignore_regex} = $v;
 
+       $k = "svn-remote.$repo_id.include-paths";
+       $v = eval { command_oneline('config', '--get', $k) };
+       $self->{include_regex} = $v;
+
        $k = "svn-remote.$repo_id.preserve-empty-dirs";
        $v = eval { command_oneline('config', '--get', '--bool', $k) };
        if ($v && $v eq 'true') {
@@ -117,11 +122,18 @@ sub in_dot_git {
 }
 
 # return value: 0 -- don't ignore, 1 -- ignore
+# This will also check whether the path is explicitly included
 sub is_path_ignored {
        my ($self, $path) = @_;
        return 1 if in_dot_git($path);
        return 1 if defined($self->{ignore_regex}) &&
                    $path =~ m!$self->{ignore_regex}!;
+       return 0 if defined($self->{include_regex}) &&
+                   $path =~ m!$self->{include_regex}!;
+       return 0 if defined($_include_regex) &&
+                   $path =~ m!$_include_regex!;
+       return 1 if defined($self->{include_regex});
+       return 1 if defined($_include_regex);
        return 0 unless defined($_ignore_regex);
        return 1 if $path =~ m!$_ignore_regex!o;
        return 0;
diff --git a/t/t9147-git-svn-include-paths.sh b/t/t9147-git-svn-include-paths.sh
new file mode 100755 (executable)
index 0000000..a90ff58
--- /dev/null
@@ -0,0 +1,149 @@
+#!/bin/sh
+#
+# Copyright (c) 2013 Paul Walmsley - based on t9134 by Vitaly Shukela
+#
+
+test_description='git svn property tests'
+. ./lib-git-svn.sh
+
+test_expect_success 'setup test repository' '
+       svn_cmd co "$svnrepo" s &&
+       (
+               cd s &&
+               mkdir qqq www xxx &&
+               echo test_qqq > qqq/test_qqq.txt &&
+               echo test_www > www/test_www.txt &&
+               echo test_xxx > xxx/test_xxx.txt &&
+               svn_cmd add qqq &&
+               svn_cmd add www &&
+               svn_cmd add xxx &&
+               svn_cmd commit -m "create some files" &&
+               svn_cmd up &&
+               echo hi >> www/test_www.txt &&
+               svn_cmd commit -m "modify www/test_www.txt" &&
+               svn_cmd up
+       )
+'
+
+test_expect_success 'clone an SVN repository with filter to include qqq directory' '
+       git svn clone --include-paths="qqq" "$svnrepo" g &&
+       echo test_qqq > expect &&
+       for i in g/*/*.txt; do cat $i >> expect2; done &&
+       test_cmp expect expect2
+'
+
+
+test_expect_success 'init+fetch an SVN repository with included qqq directory' '
+       git svn init "$svnrepo" c &&
+       ( cd c && git svn fetch --include-paths="qqq" ) &&
+       rm expect2 &&
+       echo test_qqq > expect &&
+       for i in c/*/*.txt; do cat $i >> expect2; done &&
+       test_cmp expect expect2
+'
+
+test_expect_success 'verify include-paths config saved by clone' '
+       (
+           cd g &&
+           git config --get svn-remote.svn.include-paths | fgrep "qqq"
+       )
+'
+
+test_expect_success 'SVN-side change outside of www' '
+       (
+               cd s &&
+               echo b >> qqq/test_qqq.txt &&
+               svn_cmd commit -m "SVN-side change outside of www" &&
+               svn_cmd up &&
+               svn_cmd log -v | fgrep "SVN-side change outside of www"
+       )
+'
+
+test_expect_success 'update git svn-cloned repo (config include)' '
+       (
+               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 include)' '
+       (
+               cd c &&
+               git svn rebase --include-paths="qqq" &&
+               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 'SVN-side change inside of ignored www' '
+       (
+               cd s &&
+               echo zaq >> www/test_www.txt
+               svn_cmd commit -m "SVN-side change inside of www/test_www.txt" &&
+               svn_cmd up &&
+               svn_cmd log -v | fgrep "SVN-side change inside of www/test_www.txt"
+       )
+'
+
+test_expect_success 'update git svn-cloned repo (config include)' '
+       (
+               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 include)' '
+       (
+               cd c &&
+               git svn rebase --include-paths="qqq" &&
+               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 'SVN-side change in and out of included qqq' '
+       (
+               cd s &&
+               echo cvf >> www/test_www.txt
+               echo ygg >> qqq/test_qqq.txt
+               svn_cmd commit -m "SVN-side change in and out of ignored www" &&
+               svn_cmd up &&
+               svn_cmd log -v | fgrep "SVN-side change in and out of ignored www"
+       )
+'
+
+test_expect_success 'update git svn-cloned repo again (config include)' '
+       (
+               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 include)' '
+       (
+               cd c &&
+               git svn rebase --include-paths="qqq" &&
+               printf "test_qqq\nb\nygg\n" > expect &&
+               for i in */*.txt; do cat $i >> expect2; done &&
+               test_cmp expect2 expect &&
+               rm expect expect2
+       )
+'
+
+test_done