git-svn: added an --include-path flag

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>

Paul Walmsley committed May 4, 2013 at 00:10 UTC a7b102302ad9495fb4eb5088ffcb09c44a406c06
5 files changed +180 -3
Documentation/git-svn.txt
+12
@@ -85,6 +85,10 @@ COMMANDS
85 When passed to 'init' or 'clone' this regular expression will
86 be preserved as a config key. See 'fetch' for a description
87 of '--ignore-paths'.
88 +--include-paths=<regex>;;
89 + When passed to 'init' or 'clone' this regular expression will
90 + be preserved as a config key. See 'fetch' for a description
91 + of '--include-paths'.
92 --no-minimize-url;;
93 When tracking multiple directories (using --stdlayout,
94 --branches, or --tags options), git svn will attempt to connect
@@ -146,6 +150,14 @@ Skip "branches" and "tags" of first level directories;;
150 ------------------------------------------------------------------------
151 --
152
153 +--include-paths=<regex>;;
154 + This allows one to specify a Perl regular expression that will
155 + cause the inclusion of only matching paths from checkout from SVN.
156 + The '--include-paths' option should match for every 'fetch'
157 + (including automatic fetches due to 'clone', 'dcommit',
158 + 'rebase', etc) on a given repository. '--ignore-paths' takes
159 + precedence over '--include-paths'.
160 +
161 --log-window-size=<n>;;
162 Fetch <n> log entries per request when scanning Subversion history.
163 The default is 100. For very large Subversion repositories, larger
contrib/completion/git-completion.bash
+1 -1
@@ -2451,7 +2451,7 @@ _git_svn ()
2451 --no-metadata --use-svm-props --use-svnsync-props
2452 --log-window-size= --no-checkout --quiet
2453 --repack-flags --use-log-author --localtime
2454 - --ignore-paths= $remote_opts
2454 + --ignore-paths= --include-paths= $remote_opts
2455 "
2456 local init_opts="
2457 --template= --shared= --trunk= --tags=
git-svn.perl
+4
@@ -126,6 +126,7 @@ my %remote_opts = ( 'username=s' => \$Git::SVN::Prompt::_username,
126 'config-dir=s' => \$Git::SVN::Ra::config_dir,
127 'no-auth-cache' => \$Git::SVN::Prompt::_no_auth_cache,
128 'ignore-paths=s' => \$Git::SVN::Fetcher::_ignore_regex,
129 + 'include-paths=s' => \$Git::SVN::Fetcher::_include_regex,
130 'ignore-refs=s' => \$Git::SVN::Ra::_ignore_refs_regex );
131 my %fc_opts = ( 'follow-parent|follow!' => \$Git::SVN::_follow_parent,
132 'authors-file|A=s' => \$_authors,
@@ -470,6 +471,9 @@ sub do_git_init_db {
471 my $ignore_paths_regex = \$Git::SVN::Fetcher::_ignore_regex;
472 command_noisy('config', "$pfx.ignore-paths", $$ignore_paths_regex)
473 if defined $$ignore_paths_regex;
474 + my $include_paths_regex = \$Git::SVN::Fetcher::_include_regex;
475 + command_noisy('config', "$pfx.include-paths", $$include_paths_regex)
476 + if defined $$include_paths_regex;
477 my $ignore_refs_regex = \$Git::SVN::Ra::_ignore_refs_regex;
478 command_noisy('config', "$pfx.ignore-refs", $$ignore_refs_regex)
479 if defined $$ignore_refs_regex;
perl/Git/SVN/Fetcher.pm
+14 -2
@@ -1,6 +1,7 @@
1 package Git::SVN::Fetcher;
2 -use vars qw/@ISA $_ignore_regex $_preserve_empty_dirs $_placeholder_filename
3 - @deleted_gpath %added_placeholder $repo_id/;
2 +use vars qw/@ISA $_ignore_regex $_include_regex $_preserve_empty_dirs
3 + $_placeholder_filename @deleted_gpath %added_placeholder
4 + $repo_id/;
5 use strict;
6 use warnings;
7 use SVN::Delta;
@@ -33,6 +34,10 @@ sub new {
34 my $v = eval { command_oneline('config', '--get', $k) };
35 $self->{ignore_regex} = $v;
36
37 + $k = "svn-remote.$repo_id.include-paths";
38 + $v = eval { command_oneline('config', '--get', $k) };
39 + $self->{include_regex} = $v;
40 +
41 $k = "svn-remote.$repo_id.preserve-empty-dirs";
42 $v = eval { command_oneline('config', '--get', '--bool', $k) };
43 if ($v && $v eq 'true') {
@@ -117,11 +122,18 @@ sub in_dot_git {
122 }
123
124 # return value: 0 -- don't ignore, 1 -- ignore
125 +# This will also check whether the path is explicitly included
126 sub is_path_ignored {
127 my ($self, $path) = @_;
128 return 1 if in_dot_git($path);
129 return 1 if defined($self->{ignore_regex}) &&
130 $path =~ m!$self->{ignore_regex}!;
131 + return 0 if defined($self->{include_regex}) &&
132 + $path =~ m!$self->{include_regex}!;
133 + return 0 if defined($_include_regex) &&
134 + $path =~ m!$_include_regex!;
135 + return 1 if defined($self->{include_regex});
136 + return 1 if defined($_include_regex);
137 return 0 unless defined($_ignore_regex);
138 return 1 if $path =~ m!$_ignore_regex!o;
139 return 0;
t/t9147-git-svn-include-paths.sh new
+149
@@ -0,0 +1,149 @@
1 +#!/bin/sh
2 +#
3 +# Copyright (c) 2013 Paul Walmsley - based on t9134 by Vitaly Shukela
4 +#
5 +
6 +test_description='git svn property tests'
7 +. ./lib-git-svn.sh
8 +
9 +test_expect_success 'setup test repository' '
10 + svn_cmd co "$svnrepo" s &&
11 + (
12 + cd s &&
13 + mkdir qqq www xxx &&
14 + echo test_qqq > qqq/test_qqq.txt &&
15 + echo test_www > www/test_www.txt &&
16 + echo test_xxx > xxx/test_xxx.txt &&
17 + svn_cmd add qqq &&
18 + svn_cmd add www &&
19 + svn_cmd add xxx &&
20 + svn_cmd commit -m "create some files" &&
21 + svn_cmd up &&
22 + echo hi >> www/test_www.txt &&
23 + svn_cmd commit -m "modify www/test_www.txt" &&
24 + svn_cmd up
25 + )
26 +'
27 +
28 +test_expect_success 'clone an SVN repository with filter to include qqq directory' '
29 + git svn clone --include-paths="qqq" "$svnrepo" g &&
30 + echo test_qqq > expect &&
31 + for i in g/*/*.txt; do cat $i >> expect2; done &&
32 + test_cmp expect expect2
33 +'
34 +
35 +
36 +test_expect_success 'init+fetch an SVN repository with included qqq directory' '
37 + git svn init "$svnrepo" c &&
38 + ( cd c && git svn fetch --include-paths="qqq" ) &&
39 + rm expect2 &&
40 + echo test_qqq > expect &&
41 + for i in c/*/*.txt; do cat $i >> expect2; done &&
42 + test_cmp expect expect2
43 +'
44 +
45 +test_expect_success 'verify include-paths config saved by clone' '
46 + (
47 + cd g &&
48 + git config --get svn-remote.svn.include-paths | fgrep "qqq"
49 + )
50 +'
51 +
52 +test_expect_success 'SVN-side change outside of www' '
53 + (
54 + cd s &&
55 + echo b >> qqq/test_qqq.txt &&
56 + svn_cmd commit -m "SVN-side change outside of www" &&
57 + svn_cmd up &&
58 + svn_cmd log -v | fgrep "SVN-side change outside of www"
59 + )
60 +'
61 +
62 +test_expect_success 'update git svn-cloned repo (config include)' '
63 + (
64 + cd g &&
65 + git svn rebase &&
66 + printf "test_qqq\nb\n" > expect &&
67 + for i in */*.txt; do cat $i >> expect2; done &&
68 + test_cmp expect2 expect &&
69 + rm expect expect2
70 + )
71 +'
72 +
73 +test_expect_success 'update git svn-cloned repo (option include)' '
74 + (
75 + cd c &&
76 + git svn rebase --include-paths="qqq" &&
77 + printf "test_qqq\nb\n" > expect &&
78 + for i in */*.txt; do cat $i >> expect2; done &&
79 + test_cmp expect2 expect &&
80 + rm expect expect2
81 + )
82 +'
83 +
84 +test_expect_success 'SVN-side change inside of ignored www' '
85 + (
86 + cd s &&
87 + echo zaq >> www/test_www.txt
88 + svn_cmd commit -m "SVN-side change inside of www/test_www.txt" &&
89 + svn_cmd up &&
90 + svn_cmd log -v | fgrep "SVN-side change inside of www/test_www.txt"
91 + )
92 +'
93 +
94 +test_expect_success 'update git svn-cloned repo (config include)' '
95 + (
96 + cd g &&
97 + git svn rebase &&
98 + printf "test_qqq\nb\n" > expect &&
99 + for i in */*.txt; do cat $i >> expect2; done &&
100 + test_cmp expect2 expect &&
101 + rm expect expect2
102 + )
103 +'
104 +
105 +test_expect_success 'update git svn-cloned repo (option include)' '
106 + (
107 + cd c &&
108 + git svn rebase --include-paths="qqq" &&
109 + printf "test_qqq\nb\n" > expect &&
110 + for i in */*.txt; do cat $i >> expect2; done &&
111 + test_cmp expect2 expect &&
112 + rm expect expect2
113 + )
114 +'
115 +
116 +test_expect_success 'SVN-side change in and out of included qqq' '
117 + (
118 + cd s &&
119 + echo cvf >> www/test_www.txt
120 + echo ygg >> qqq/test_qqq.txt
121 + svn_cmd commit -m "SVN-side change in and out of ignored www" &&
122 + svn_cmd up &&
123 + svn_cmd log -v | fgrep "SVN-side change in and out of ignored www"
124 + )
125 +'
126 +
127 +test_expect_success 'update git svn-cloned repo again (config include)' '
128 + (
129 + cd g &&
130 + git svn rebase &&
131 + printf "test_qqq\nb\nygg\n" > expect &&
132 + for i in */*.txt; do cat $i >> expect2; done &&
133 + test_cmp expect2 expect &&
134 + rm expect expect2
135 + )
136 +'
137 +
138 +test_expect_success 'update git svn-cloned repo again (option include)' '
139 + (
140 + cd c &&
141 + git svn rebase --include-paths="qqq" &&
142 + printf "test_qqq\nb\nygg\n" > expect &&
143 + for i in */*.txt; do cat $i >> expect2; done &&
144 + test_cmp expect2 expect &&
145 + rm expect expect2
146 + )
147 +'
148 +
149 +test_done