{"thread":{"id":"4688","subject":"[PATCH 3/5] git-svn: add the commit-diff command","startedAt":"2006-06-28T02:39:09Z","lastAt":"2006-06-28T10:07:14Z","messageCount":8,"participants":["Eric Wong","Junio C Hamano"],"isPatch":true,"patchVersion":1,"patchTotal":5},"messages":[{"id":"22700","messageId":"11514623542848-git-send-email-normalperson@yhbt.net","threadId":"4688","inReplyTo":null,"subject":"[PATCH 0/5] git-svn: more cool features","fromName":"Eric Wong","fromEmail":"normalperson@yhbt.net","sentAt":"2006-06-28T02:39:09Z","receivedAt":"2006-06-28T02:39:09Z","isPatch":true,"sender":{"key":"e@80x24.org","avatar":null},"body":"[PATCH 1/5] git-svn: SVN 1.1.x library compatibility\n\tDebian Sarge and Ubuntu Hoary users shall be pleased.\n\n[PATCH 2/5] git-svn: several graft-branches improvements\n\tStill an experimental feature, but kinda fun.\n\n[PATCH 3/5] git-svn: add the commit-diff command\n\tgit-svnimport users may find this useful.\n\n[PATCH 4/5] git-svn: add --follow-parent and --no-metadata options to fetch\n\tWe should be closer to being able to do everything that git-svnimport\n\tdoes with this patch.  The only thing we can't do yet is automatically\n\tfind dead-end branches that got deleted.\n\n[PATCH 5/5] git-svn: be verbose by default on fetch/commit, add -q/--quiet option\n\tI actually thought I broke something and had an infinite loop\n\tin git-svn where one day :x\n\n-- \nEric Wong\n"},{"id":"22701","messageId":"11514623563534-git-send-email-normalperson@yhbt.net","threadId":"4688","inReplyTo":"11514623542848-git-send-email-normalperson@yhbt.net","subject":"[PATCH 1/5] git-svn: SVN 1.1.x library compatibility","fromName":"Eric Wong","fromEmail":"normalperson@yhbt.net","sentAt":"2006-06-28T02:39:10Z","receivedAt":"2006-06-28T02:39:10Z","isPatch":true,"sender":{"key":"e@80x24.org","avatar":null},"body":"Tested on a plain Ubuntu Hoary installation\nusing subversion 1.1.1-2ubuntu3\n\n1.1.x issues I had to deal with:\n\n* Avoid the noisy command-line client compatibility check if we\n  use the libraries.\n\n* get_log() arguments differ.\n\n* get_file() is picky about what kind of file handles it gets,\n  so I ended up redirecting STDOUT.  I'm probably overflushing\n  my file handles, but that's the safest thing to do...\n\n* BDB kept segfaulting on me during tests, so svnadmin will use FSFS\n  whenever we can.\n\n* If somebody used an expanded CVS $Id$ line inside a file, then\n  propsetting it to use svn:keywords will cause the original CVS\n  $Id$ to be retained when asked for the original file.  As far as\n  I can see, this is a server-side issue.  We won't care in the\n  test anymore, as long as it's not expanded by SVN, a static\n  CVS $Id$ line is fine.\n\nWhile we're at making ourselves more compatible, avoid using the\n-q flag in grep, which is GNU-specific.\n\nSigned-off-by: Eric Wong <normalperson@yhbt.net>\n---\n contrib/git-svn/git-svn.perl                     |   26 ++++++++++++++++------\n contrib/git-svn/t/lib-git-svn.sh                 |    8 ++++++-\n contrib/git-svn/t/t0000-contrib-git-svn.sh       |    4 ++-\n contrib/git-svn/t/t0001-contrib-git-svn-props.sh |    4 ++-\n 4 files changed, 30 insertions(+), 12 deletions(-)\n\ndiff --git a/contrib/git-svn/git-svn.perl b/contrib/git-svn/git-svn.perl\nindex 08c3010..711b558 100755\n--- a/contrib/git-svn/git-svn.perl\n+++ b/contrib/git-svn/git-svn.perl\n@@ -134,7 +134,7 @@ usage(1) unless defined $cmd;\n init_vars();\n load_authors() if $_authors;\n load_all_refs() if $_branch_all_refs;\n-svn_compat_check();\n+svn_compat_check() unless $_use_lib;\n migration_check() unless $cmd =~ /^(?:init|rebuild|multi-init)$/;\n $cmd{$cmd}->[0]->(@ARGV);\n exit 0;\n@@ -379,7 +379,9 @@ sub fetch_lib {\n \t\t\t# performance sucks with it enabled, so it's much\n \t\t\t# faster to fetch revision ranges instead of relying\n \t\t\t# on the limiter.\n-\t\t\t$SVN_LOG->get_log( '/'.$SVN_PATH, $min, $max, 0, 1, 1,\n+\t\t\t$SVN_LOG->get_log( '/'.$SVN_PATH, $min, $max,\n+\t\t\t\t($SVN::Core::VERSION ge '1.2.0') ? (0) : (),\n+\t\t\t\t1, 1,\n \t\t\t\tsub {\n \t\t\t\t\tmy $log_msg;\n \t\t\t\t\tif ($last_commit) {\n@@ -924,7 +926,9 @@ sub graft_file_copy_lib {\n \t$SVN::Error::handler = \\&libsvn_skip_unknown_revs;\n \twhile (1) {\n \t\tmy $pool = SVN::Pool->new;\n-\t\t$SVN_LOG->get_log( \"/$path\", $min, $max, 0, 1, 1,\n+\t\t$SVN_LOG->get_log( \"/$path\", $min, $max,\n+\t\t\t\t($SVN::Core::VERSION ge '1.2.0') ? (0) : (),\n+\t\t\t\t1, 1,\n \t\t\tsub {\n \t\t\t\tlibsvn_graft_file_copies($grafts, $tree_paths,\n \t\t\t\t\t\t\t$path, @_);\n@@ -2358,8 +2362,8 @@ sub libsvn_load {\n \treturn unless $_use_lib;\n \t$_use_lib = eval {\n \t\trequire SVN::Core;\n-\t\tif ($SVN::Core::VERSION lt '1.2.1') {\n-\t\t\tdie \"Need SVN::Core 1.2.1 or better \",\n+\t\tif ($SVN::Core::VERSION lt '1.1.0') {\n+\t\t\tdie \"Need SVN::Core 1.1.0 or better \",\n \t\t\t\t\t\"(got $SVN::Core::VERSION) \",\n \t\t\t\t\t\"Falling back to command-line svn\\n\";\n \t\t}\n@@ -2392,9 +2396,15 @@ sub libsvn_get_file {\n \tmy $pool = SVN::Pool->new;\n \tdefined($pid = open3($in, $out, '>&STDERR',\n \t\t\t\tqw/git-hash-object -w --stdin/)) or croak $!;\n-\tmy ($r, $props) = $SVN->get_file($f, $rev, $in, $pool);\n+\t# redirect STDOUT for SVN 1.1.x compatibility\n+\topen my $stdout, '>&', \\*STDOUT or croak $!;\n+\topen STDOUT, '>&', $in or croak $!;\n+\t$| = 1; # not sure if this is necessary, better safe than sorry...\n+\tmy ($r, $props) = $SVN->get_file($f, $rev, \\*STDOUT, $pool);\n \t$in->flush == 0 or croak $!;\n+\topen STDOUT, '>&', $stdout or croak $!;\n \tclose $in or croak $!;\n+\tclose $stdout or croak $!;\n \t$pool->clear;\n \tchomp($hash = do { local $/; <$out> });\n \tclose $out or croak $!;\n@@ -2566,7 +2576,9 @@ sub revisions_eq {\n \tif ($_use_lib) {\n \t\t# should be OK to use Pool here (r1 - r0) should be small\n \t\tmy $pool = SVN::Pool->new;\n-\t\t$SVN->get_log(\"/$path\", $r0, $r1, 0, 1, 1, sub {$nr++},$pool);\n+\t\t$SVN->get_log(\"/$path\", $r0, $r1,\n+\t\t\t\t($SVN::Core::VERSION ge '1.2.0') ? (0) : (),\n+\t\t\t\t1, 1, sub {$nr++});#, $pool);\n \t\t$pool->clear;\n \t} else {\n \t\tmy ($url, undef) = repo_path_split($SVN_URL);\ndiff --git a/contrib/git-svn/t/lib-git-svn.sh b/contrib/git-svn/t/lib-git-svn.sh\nindex 2843258..d7f972a 100644\n--- a/contrib/git-svn/t/lib-git-svn.sh\n+++ b/contrib/git-svn/t/lib-git-svn.sh\n@@ -33,7 +33,13 @@ svnrepo=$PWD/svnrepo\n \n set -e\n \n-svnadmin create $svnrepo\n+if svnadmin create --help | grep fs-type >/dev/null\n+then\n+\tsvnadmin create --fs-type fsfs \"$svnrepo\"\n+else\n+\tsvnadmin create \"$svnrepo\"\n+fi\n+\n svnrepo=\"file://$svnrepo/test-git-svn\"\n \n \ndiff --git a/contrib/git-svn/t/t0000-contrib-git-svn.sh b/contrib/git-svn/t/t0000-contrib-git-svn.sh\nindex 443d518..3c14ad8 100644\n--- a/contrib/git-svn/t/t0000-contrib-git-svn.sh\n+++ b/contrib/git-svn/t/t0000-contrib-git-svn.sh\n@@ -173,7 +173,7 @@ then\n fi\n \n \n-if test -n \"$GIT_SVN_LC_ALL\" && echo $GIT_SVN_LC_ALL | grep -q '\\.UTF-8$'\n+if test -n \"$GIT_SVN_LC_ALL\" && echo $GIT_SVN_LC_ALL |grep '\\.UTF-8$' >/dev/null\n then\n \tname=\"commit with UTF-8 message: locale: $GIT_SVN_LC_ALL\"\n \techo '# hello' >> exec-2.sh\n@@ -203,7 +203,7 @@ fi\n \n name='check imported tree checksums expected tree checksums'\n rm -f expected\n-if test -n \"$GIT_SVN_LC_ALL\" && echo $GIT_SVN_LC_ALL | grep -q '\\.UTF-8$'\n+if test -n \"$GIT_SVN_LC_ALL\" && echo $GIT_SVN_LC_ALL |grep '\\.UTF-8$' >/dev/null\n then\n \techo tree f735671b89a7eb30cab1d8597de35bd4271ab813 > expected\n fi\ndiff --git a/contrib/git-svn/t/t0001-contrib-git-svn-props.sh b/contrib/git-svn/t/t0001-contrib-git-svn-props.sh\nindex 54e0ed7..a5a235f 100644\n--- a/contrib/git-svn/t/t0001-contrib-git-svn-props.sh\n+++ b/contrib/git-svn/t/t0001-contrib-git-svn-props.sh\n@@ -21,8 +21,8 @@ a_empty_crlf=\n \n cd import\n \tcat >> kw.c <<\\EOF\n-/* Make it look like somebody copied a file from CVS into SVN: */\n-/* $Id: kw.c,v 1.1.1.1 1994/03/06 00:00:00 eric Exp $ */\n+/* Somebody prematurely put a keyword into this file */\n+/* $Id$ */\n EOF\n \n \tprintf \"Hello\\r\\nWorld\\r\\n\" > crlf\n-- \n1.4.1.rc1.g3cc8\n"},{"id":"22703","messageId":"11514623571599-git-send-email-normalperson@yhbt.net","threadId":"4688","inReplyTo":"11514623542848-git-send-email-normalperson@yhbt.net","subject":"[PATCH 2/5] git-svn: several graft-branches improvements","fromName":"Eric Wong","fromEmail":"normalperson@yhbt.net","sentAt":"2006-06-28T02:39:11Z","receivedAt":"2006-06-28T02:39:11Z","isPatch":true,"sender":{"key":"e@80x24.org","avatar":null},"body":"The 'graft-branches' command can now analyze tree matches for\nmerge detection after commits are done, when --branch or\n--branch-all-refs options are used.\n\nWe ensure that tree joins (--branch and --branch-all-refs\noptions) during commit time only add SVN parents that occurred\nbefore the commit we're importing\n\nAlso fixed branch detection via merge messages, this manner of\nmerge detection (a la git-svnimport) is really all fuzzy, but at\nleast it actually works now :)\n\nAdd some new tests to go along with these fixes, too.\n\nSigned-off-by: Eric Wong <normalperson@yhbt.net>\n---\n contrib/git-svn/git-svn.perl              |  180 +++++++++++++++++++++++++++--\n contrib/git-svn/t/t0003-graft-branches.sh |   63 ++++++++++\n 2 files changed, 230 insertions(+), 13 deletions(-)\n\ndiff --git a/contrib/git-svn/git-svn.perl b/contrib/git-svn/git-svn.perl\nindex 711b558..4fafe7a 100755\n--- a/contrib/git-svn/git-svn.perl\n+++ b/contrib/git-svn/git-svn.perl\n@@ -34,6 +34,8 @@ use POSIX qw/strftime/;\n use IPC::Open3;\n use Memoize;\n memoize('revisions_eq');\n+memoize('cmt_metadata');\n+memoize('get_commit_time');\n \n my ($SVN_PATH, $SVN, $SVN_LOG, $_use_lib);\n $_use_lib = 1 unless $ENV{GIT_SVN_NO_LIB};\n@@ -91,6 +93,8 @@ my %cmd = (\n \t'graft-branches' => [ \\&graft_branches,\n \t\t\t'Detect merges/branches from already imported history',\n \t\t\t{ 'merge-rx|m' => \\@_opt_m,\n+\t\t\t  'branch|b=s' => \\@_branch_from,\n+\t\t\t  'branch-all-refs|B' => \\$_branch_all_refs,\n \t\t\t  'no-default-regex' => \\$_no_default_regex,\n \t\t\t  'no-graft-copy' => \\$_no_graft_copy } ],\n \t'multi-init' => [ \\&multi_init,\n@@ -591,13 +595,14 @@ sub graft_branches {\n \tmy $l_map = read_url_paths();\n \tmy @re = map { qr/$_/is } @_opt_m if @_opt_m;\n \tunless ($_no_default_regex) {\n-\t\tpush @re, (\tqr/\\b(?:merge|merging|merged)\\s+(\\S.+)/is,\n-\t\t\t\tqr/\\b(?:from|of)\\s+(\\S.+)/is );\n+\t\tpush @re, (qr/\\b(?:merge|merging|merged)\\s+with\\s+([\\w\\.\\-]+)/i,\n+\t\t\tqr/\\b(?:merge|merging|merged)\\s+([\\w\\.\\-]+)/i,\n+\t\t\tqr/\\b(?:from|of)\\s+([\\w\\.\\-]+)/i );\n \t}\n \tforeach my $u (keys %$l_map) {\n \t\tif (@re) {\n \t\t\tforeach my $p (keys %{$l_map->{$u}}) {\n-\t\t\t\tgraft_merge_msg($grafts,$l_map,$u,$p);\n+\t\t\t\tgraft_merge_msg($grafts,$l_map,$u,$p,@re);\n \t\t\t}\n \t\t}\n \t\tunless ($_no_graft_copy) {\n@@ -608,6 +613,7 @@ sub graft_branches {\n \t\t\t}\n \t\t}\n \t}\n+\tgraft_tree_joins($grafts);\n \n \twrite_grafts($grafts, $comments, $gr_file);\n \tunlink \"$gr_file~$gr_sha1\" if $gr_sha1;\n@@ -880,6 +886,77 @@ sub common_prefix {\n \treturn '';\n }\n \n+# grafts set here are 'stronger' in that they're based on actual tree\n+# matches, and won't be deleted from merge-base checking in write_grafts()\n+sub graft_tree_joins {\n+\tmy $grafts = shift;\n+\tmap_tree_joins() if (@_branch_from && !%tree_map);\n+\treturn unless %tree_map;\n+\n+\tgit_svn_each(sub {\n+\t\tmy $i = shift;\n+\t\tdefined(my $pid = open my $fh, '-|') or croak $!;\n+\t\tif (!$pid) {\n+\t\t\texec qw/git-rev-list --pretty=raw/,\n+\t\t\t\t\t\"refs/remotes/$i\" or croak $!;\n+\t\t}\n+\t\twhile (<$fh>) {\n+\t\t\tnext unless /^commit ($sha1)$/o;\n+\t\t\tmy $c = $1;\n+\t\t\tmy ($t) = (<$fh> =~ /^tree ($sha1)$/o);\n+\t\t\tnext unless $tree_map{$t};\n+\n+\t\t\tmy $l;\n+\t\t\tdo {\n+\t\t\t\t$l = readline $fh;\n+\t\t\t} until ($l =~ /^committer (?:.+) (\\d+) ([\\-\\+]?\\d+)$/);\n+\n+\t\t\tmy ($s, $tz) = ($1, $2);\n+\t\t\tif ($tz =~ s/^\\+//) {\n+\t\t\t\t$s += tz_to_s_offset($tz);\n+\t\t\t} elsif ($tz =~ s/^\\-//) {\n+\t\t\t\t$s -= tz_to_s_offset($tz);\n+\t\t\t}\n+\n+\t\t\tmy ($url_a, $r_a, $uuid_a) = cmt_metadata($c);\n+\n+\t\t\tforeach my $p (@{$tree_map{$t}}) {\n+\t\t\t\tnext if $p eq $c;\n+\t\t\t\tmy $mb = eval {\n+\t\t\t\t\tsafe_qx('git-merge-base', $c, $p)\n+\t\t\t\t};\n+\t\t\t\tnext unless ($@ || $?);\n+\t\t\t\tif (defined $r_a) {\n+\t\t\t\t\t# see if SVN says it's a relative\n+\t\t\t\t\tmy ($url_b, $r_b, $uuid_b) =\n+\t\t\t\t\t\t\tcmt_metadata($p);\n+\t\t\t\t\tnext if (defined $url_b &&\n+\t\t\t\t\t\t\tdefined $url_a &&\n+\t\t\t\t\t\t\t($url_a eq $url_b) &&\n+\t\t\t\t\t\t\t($uuid_a eq $uuid_b));\n+\t\t\t\t\tif ($uuid_a eq $uuid_b) {\n+\t\t\t\t\t\tif ($r_b < $r_a) {\n+\t\t\t\t\t\t\t$grafts->{$c}->{$p} = 2;\n+\t\t\t\t\t\t\tnext;\n+\t\t\t\t\t\t} elsif ($r_b > $r_a) {\n+\t\t\t\t\t\t\t$grafts->{$p}->{$c} = 2;\n+\t\t\t\t\t\t\tnext;\n+\t\t\t\t\t\t}\n+\t\t\t\t\t}\n+\t\t\t\t}\n+\t\t\t\tmy $ct = get_commit_time($p);\n+\t\t\t\tif ($ct < $s) {\n+\t\t\t\t\t$grafts->{$c}->{$p} = 2;\n+\t\t\t\t} elsif ($ct > $s) {\n+\t\t\t\t\t$grafts->{$p}->{$c} = 2;\n+\t\t\t\t}\n+\t\t\t\t# what should we do when $ct == $s ?\n+\t\t\t}\n+\t\t}\n+\t\tclose $fh or croak $?;\n+\t});\n+}\n+\n # this isn't funky-filename safe, but good enough for now...\n sub graft_file_copy_cmd {\n \tmy ($grafts, $l_map, $u) = @_;\n@@ -960,7 +1037,7 @@ sub process_merge_msg_matches {\n \t\tmy $re = qr/\\Q$w\\E/i;\n \t\tforeach (keys %{$l_map->{$u}}) {\n \t\t\tif (/$re/) {\n-\t\t\t\tpush @strong, $_;\n+\t\t\t\tpush @strong, $l_map->{$u}->{$_};\n \t\t\t\tlast;\n \t\t\t}\n \t\t}\n@@ -969,7 +1046,7 @@ sub process_merge_msg_matches {\n \t\t$re = qr/\\Q$w\\E/i;\n \t\tforeach (keys %{$l_map->{$u}}) {\n \t\t\tif (/$re/) {\n-\t\t\t\tpush @strong, $_;\n+\t\t\t\tpush @strong, $l_map->{$u}->{$_};\n \t\t\t\tlast;\n \t\t\t}\n \t\t}\n@@ -982,7 +1059,7 @@ sub process_merge_msg_matches {\n \t\treturn unless defined $rev;\n \t}\n \tforeach my $m (@strong) {\n-\t\tmy ($r0, $s0) = find_rev_before($rev, $m);\n+\t\tmy ($r0, $s0) = find_rev_before($rev, $m, 1);\n \t\t$grafts->{$c->{c}}->{$s0} = 1 if defined $s0;\n \t}\n }\n@@ -1794,7 +1871,26 @@ sub git_commit {\n \t\trestore_index($index);\n \t}\n \tif (exists $tree_map{$tree}) {\n-\t\tpush @tmp_parents, @{$tree_map{$tree}};\n+\t\tforeach my $p (@{$tree_map{$tree}}) {\n+\t\t\tmy $skip;\n+\t\t\tforeach (@tmp_parents) {\n+\t\t\t\t# see if a common parent is found\n+\t\t\t\tmy $mb = eval {\n+\t\t\t\t\tsafe_qx('git-merge-base', $_, $p)\n+\t\t\t\t};\n+\t\t\t\tnext if ($@ || $?);\n+\t\t\t\t$skip = 1;\n+\t\t\t\tlast;\n+\t\t\t}\n+\t\t\tnext if $skip;\n+\t\t\tmy ($url_p, $r_p, $uuid_p) = cmt_metadata($p);\n+\t\t\tnext if (($SVN_UUID eq $uuid_p) &&\n+\t\t\t\t\t\t($log_msg->{revision} > $r_p));\n+\t\t\tnext if (defined $url_p && defined $SVN_URL &&\n+\t\t\t\t\t\t($SVN_UUID eq $uuid_p) &&\n+\t\t\t\t\t\t($url_p eq $SVN_URL));\n+\t\t\tpush @tmp_parents, $p;\n+\t\t}\n \t}\n \tforeach (@tmp_parents) {\n \t\tnext if $seen_parent{$_};\n@@ -2122,6 +2218,7 @@ sub init_vars {\n \t$GIT_SVN_INDEX = \"$GIT_SVN_DIR/index\";\n \t$SVN_URL = undef;\n \t$SVN_WC = \"$GIT_SVN_DIR/tree\";\n+\t%tree_map = ();\n }\n \n # convert GetOpt::Long specs for use by git-repo-config\n@@ -2189,6 +2286,7 @@ sub write_grafts {\n \t\t\tprint $fh $_ foreach @{$comments->{$c}};\n \t\t}\n \t\tmy $p = $grafts->{$c};\n+\t\tmy %x; # real parents\n \t\tdelete $p->{$c}; # commits are not self-reproducing...\n \t\tmy $pid = open my $ch, '-|';\n \t\tdefined $pid or croak $!;\n@@ -2196,13 +2294,41 @@ sub write_grafts {\n \t\t\texec(qw/git-cat-file commit/, $c) or croak $!;\n \t\t}\n \t\twhile (<$ch>) {\n-\t\t\tif (/^parent ([a-f\\d]{40})/) {\n-\t\t\t\t$p->{$1} = 1;\n+\t\t\tif (/^parent ($sha1)/) {\n+\t\t\t\t$x{$1} = $p->{$1} = 1;\n \t\t\t} else {\n-\t\t\t\tlast unless /^\\S/i;\n+\t\t\t\tlast unless /^\\S/;\n \t\t\t}\n \t\t}\n \t\tclose $ch; # breaking the pipe\n+\n+\t\t# if real parents are the only ones in the grafts, drop it\n+\t\tnext if join(' ',sort keys %$p) eq join(' ',sort keys %x);\n+\n+\t\tmy (@ip, @jp, $mb);\n+\t\tmy %del = %x;\n+\t\t@ip = @jp = keys %$p;\n+\t\tforeach my $i (@ip) {\n+\t\t\tnext if $del{$i} || $p->{$i} == 2;\n+\t\t\tforeach my $j (@jp) {\n+\t\t\t\tnext if $i eq $j || $del{$j} || $p->{$j} == 2;\n+\t\t\t\t$mb = eval { safe_qx('git-merge-base',$i,$j) };\n+\t\t\t\tnext unless $mb;\n+\t\t\t\tchomp $mb;\n+\t\t\t\tnext if $x{$mb};\n+\t\t\t\tif ($mb eq $j) {\n+\t\t\t\t\tdelete $p->{$i};\n+\t\t\t\t\t$del{$i} = 1;\n+\t\t\t\t} elsif ($mb eq $i) {\n+\t\t\t\t\tdelete $p->{$j};\n+\t\t\t\t\t$del{$j} = 1;\n+\t\t\t\t}\n+\t\t\t}\n+\t\t}\n+\n+\t\t# if real parents are the only ones in the grafts, drop it\n+\t\tnext if join(' ',sort keys %$p) eq join(' ',sort keys %x);\n+\n \t\tprint $fh $c, ' ', join(' ', sort keys %$p),\"\\n\";\n \t}\n \tif ($comments->{'END'}) {\n@@ -2222,7 +2348,7 @@ sub read_url_paths {\n }\n \n sub extract_metadata {\n-\tmy $id = shift;\n+\tmy $id = shift or return (undef, undef, undef);\n \tmy ($url, $rev, $uuid) = ($id =~ /^git-svn-id:\\s(\\S+?)\\@(\\d+)\n \t\t\t\t\t\t\t\\s([a-f\\d\\-]+)$/x);\n \tif (!$rev || !$uuid || !$url) {\n@@ -2233,6 +2359,31 @@ sub extract_metadata {\n \treturn ($url, $rev, $uuid);\n }\n \n+sub cmt_metadata {\n+\treturn extract_metadata((grep(/^git-svn-id: /,\n+\t\tsafe_qx(qw/git-cat-file commit/, shift)))[-1]);\n+}\n+\n+sub get_commit_time {\n+\tmy $cmt = shift;\n+\tdefined(my $pid = open my $fh, '-|') or croak $!;\n+\tif (!$pid) {\n+\t\texec qw/git-rev-list --pretty=raw -n1/, $cmt or croak $!;\n+\t}\n+\twhile (<$fh>) {\n+\t\t/^committer\\s(?:.+) (\\d+) ([\\-\\+]?\\d+)$/ or next;\n+\t\tmy ($s, $tz) = ($1, $2);\n+\t\tif ($tz =~ s/^\\+//) {\n+\t\t\t$s += tz_to_s_offset($tz);\n+\t\t} elsif ($tz =~ s/^\\-//) {\n+\t\t\t$s -= tz_to_s_offset($tz);\n+\t\t}\n+\t\tclose $fh;\n+\t\treturn $s;\n+\t}\n+\tdie \"Can't get commit time for commit: $cmt\\n\";\n+}\n+\n sub tz_to_s_offset {\n \tmy ($tz) = @_;\n \t$tz =~ s/(\\d\\d)$//;\n@@ -2501,8 +2652,7 @@ sub svn_grab_base_rev {\n \tchomp(my $c = do { local $/; <$fh> });\n \tclose $fh;\n \tif (defined $c && length $c) {\n-\t\tmy ($url, $rev, $uuid) = extract_metadata((grep(/^git-svn-id: /,\n-\t\t\tsafe_qx(qw/git-cat-file commit/, $c)))[-1]);\n+\t\tmy ($url, $rev, $uuid) = cmt_metadata($c);\n \t\treturn ($rev, $c);\n \t}\n \treturn (undef, undef);\n@@ -2651,6 +2801,10 @@ sub find_graft_path_parents {\n \t\tmy $i = $tree_paths->{$x};\n \t\tmy ($r, $parent) = find_rev_before($r0, $i, 1);\n \t\tif (defined $r && defined $parent && revisions_eq($x,$r,$r0)) {\n+\t\t\tmy ($url_b, undef, $uuid_b) = cmt_metadata($c);\n+\t\t\tmy ($url_a, undef, $uuid_a) = cmt_metadata($parent);\n+\t\t\tnext if ($url_a && $url_b && $url_a eq $url_b &&\n+\t\t\t\t\t\t\t$uuid_b eq $uuid_a);\n \t\t\t$grafts->{$c}->{$parent} = 1;\n \t\t}\n \t}\ndiff --git a/contrib/git-svn/t/t0003-graft-branches.sh b/contrib/git-svn/t/t0003-graft-branches.sh\nnew file mode 100644\nindex 0000000..cc62d4e\n--- /dev/null\n+++ b/contrib/git-svn/t/t0003-graft-branches.sh\n@@ -0,0 +1,63 @@\n+test_description='git-svn graft-branches'\n+. ./lib-git-svn.sh\n+\n+test_expect_success 'initialize repo' \"\n+\tmkdir import &&\n+\tcd import &&\n+\tmkdir -p trunk branches tags &&\n+\techo hello > trunk/readme &&\n+\tsvn import -m 'import for git-svn' . $svnrepo &&\n+\tcd .. &&\n+\tsvn cp -m 'tag a' $svnrepo/trunk $svnrepo/tags/a &&\n+\tsvn cp -m 'branch a' $svnrepo/trunk $svnrepo/branches/a &&\n+\tsvn co $svnrepo wc &&\n+\tcd wc &&\n+\techo feedme >> branches/a/readme &&\n+\tsvn commit -m hungry &&\n+\tsvn up &&\n+\tcd trunk &&\n+\tsvn merge -r3:4 $svnrepo/branches/a &&\n+\tsvn commit -m 'merge with a' &&\n+\tcd ../.. &&\n+\tsvn log -v $svnrepo &&\n+\tgit-svn init -i trunk $svnrepo/trunk &&\n+\tgit-svn init -i a $svnrepo/branches/a &&\n+\tgit-svn init -i tags/a $svnrepo/tags/a &&\n+\tgit-svn fetch -i tags/a &&\n+\tgit-svn fetch -i a &&\n+\tgit-svn fetch -i trunk\n+\t\"\n+\n+r1=`git-rev-list remotes/trunk | tail -n1`\n+r2=`git-rev-list remotes/tags/a | tail -n1`\n+r3=`git-rev-list remotes/a | tail -n1`\n+r4=`git-rev-list remotes/a | head -n1`\n+r5=`git-rev-list remotes/trunk | head -n1`\n+\n+test_expect_success 'test graft-branches regexes and copies' \"\n+\ttest -n \"$r1\" &&\n+\ttest -n \"$r2\" &&\n+\ttest -n \"$r3\" &&\n+\ttest -n \"$r4\" &&\n+\ttest -n \"$r5\" &&\n+\tgit-svn graft-branches &&\n+\tgrep '^$r2 $r1' $GIT_DIR/info/grafts &&\n+\tgrep '^$r3 $r1' $GIT_DIR/info/grafts &&\n+\tgrep '^$r5 ' $GIT_DIR/info/grafts | grep '$r4' | grep '$r1'\n+\t\"\n+\n+test_debug 'gitk --all & sleep 1'\n+\n+test_expect_success 'test graft-branches with tree-joins' \"\n+\trm $GIT_DIR/info/grafts &&\n+\tgit-svn graft-branches --no-default-regex --no-graft-copy -B &&\n+\tgrep '^$r3 ' $GIT_DIR/info/grafts | grep '$r1' | grep '$r2' &&\n+\tgrep '^$r2 $r1' $GIT_DIR/info/grafts &&\n+\tgrep '^$r5 ' $GIT_DIR/info/grafts | grep '$r1' | grep '$r4'\n+\t\"\n+\n+# the result of this is kinda funky, we have a strange history and\n+# this is just a test :)\n+test_debug 'gitk --all &'\n+\n+test_done\n-- \n1.4.1.rc1.g3cc8\n"},{"id":"22699","messageId":"1151462358888-git-send-email-normalperson@yhbt.net","threadId":"4688","inReplyTo":"11514623542848-git-send-email-normalperson@yhbt.net","subject":"[PATCH 3/5] git-svn: add the commit-diff command","fromName":"Eric Wong","fromEmail":"normalperson@yhbt.net","sentAt":"2006-06-28T02:39:12Z","receivedAt":"2006-06-28T02:39:12Z","isPatch":true,"sender":{"key":"e@80x24.org","avatar":null},"body":"This is intended for interoperability with git-svnimport.\n\nSigned-off-by: Eric Wong <normalperson@yhbt.net>\n---\n contrib/git-svn/git-svn.perl           |   90 +++++++++++++++++++++++++-------\n contrib/git-svn/t/t0005-commit-diff.sh |   41 +++++++++++++++\n 2 files changed, 112 insertions(+), 19 deletions(-)\n\ndiff --git a/contrib/git-svn/git-svn.perl b/contrib/git-svn/git-svn.perl\nindex 4fafe7a..73b339a 100755\n--- a/contrib/git-svn/git-svn.perl\n+++ b/contrib/git-svn/git-svn.perl\n@@ -46,6 +46,7 @@ my $sha1_short = qr/[a-f\\d]{4,40}/;\n my ($_revision,$_stdin,$_no_ignore_ext,$_no_stop_copy,$_help,$_rmdir,$_edit,\n \t$_find_copies_harder, $_l, $_cp_similarity, $_cp_remote,\n \t$_repack, $_repack_nr, $_repack_flags,\n+\t$_message, $_file,\n \t$_template, $_shared, $_no_default_regex, $_no_graft_copy,\n \t$_limit, $_verbose, $_incremental, $_oneline, $_l_fmt, $_show_commit,\n \t$_version, $_upgrade, $_authors, $_branch_all_refs, @_opt_m);\n@@ -65,6 +66,12 @@ my %multi_opts = ( 'trunk|T=s' => \\$_tru\n \t\t'tags|t=s' => \\$_tags,\n \t\t'branches|b=s' => \\$_branches );\n my %init_opts = ( 'template=s' => \\$_template, 'shared' => \\$_shared );\n+my %cmt_opts = ( 'edit|e' => \\$_edit,\n+\t\t'rmdir' => \\$_rmdir,\n+\t\t'find-copies-harder' => \\$_find_copies_harder,\n+\t\t'l=i' => \\$_l,\n+\t\t'copy-similarity|C=i'=> \\$_cp_similarity\n+);\n \n # yes, 'native' sets \"\\n\".  Patches to fix this for non-*nix systems welcome:\n my %EOL = ( CR => \"\\015\", LF => \"\\012\", CRLF => \"\\015\\012\", native => \"\\012\" );\n@@ -76,14 +83,7 @@ my %cmd = (\n \t\t\t  \" (requires URL argument)\",\n \t\t\t  \\%init_opts ],\n \tcommit => [ \\&commit, \"Commit git revisions to SVN\",\n-\t\t\t{\t'stdin|' => \\$_stdin,\n-\t\t\t\t'edit|e' => \\$_edit,\n-\t\t\t\t'rmdir' => \\$_rmdir,\n-\t\t\t\t'find-copies-harder' => \\$_find_copies_harder,\n-\t\t\t\t'l=i' => \\$_l,\n-\t\t\t\t'copy-similarity|C=i'=> \\$_cp_similarity,\n-\t\t\t\t%fc_opts,\n-\t\t\t} ],\n+\t\t\t{\t'stdin|' => \\$_stdin, %cmt_opts, %fc_opts, } ],\n \t'show-ignore' => [ \\&show_ignore, \"Show svn:ignore listings\",\n \t\t\t{ 'revision|r=i' => \\$_revision } ],\n \trebuild => [ \\&rebuild, \"Rebuild git-svn metadata (after git clone)\",\n@@ -112,6 +112,10 @@ my %cmd = (\n \t\t\t  'show-commit' => \\$_show_commit,\n \t\t\t  'authors-file|A=s' => \\$_authors,\n \t\t\t} ],\n+\t'commit-diff' => [ \\&commit_diff, 'Commit a diff between two trees',\n+\t\t\t{ 'message|m=s' => \\$_message,\n+\t\t\t  'file|F=s' => \\$_file,\n+\t\t\t%cmt_opts } ],\n );\n \n my $cmd;\n@@ -485,11 +489,7 @@ sub commit_lib {\n \tmy @lock = $SVN::Core::VERSION ge '1.2.0' ? (undef, 0) : ();\n \tmy $commit_msg = \"$GIT_SVN_DIR/.svn-commit.tmp.$$\";\n \n-\tif (defined $LC_ALL) {\n-\t\t$ENV{LC_ALL} = $LC_ALL;\n-\t} else {\n-\t\tdelete $ENV{LC_ALL};\n-\t}\n+\tset_svn_commit_env();\n \tforeach my $c (@revs) {\n \t\tmy $log_msg = get_commit_message($c, $commit_msg);\n \n@@ -724,6 +724,55 @@ out:\n \tprint '-' x72,\"\\n\" unless $_incremental || $_oneline;\n }\n \n+sub commit_diff_usage {\n+\tprint STDERR \"Usage: $0 commit-diff <tree-ish> <tree-ish> [<URL>]\\n\";\n+\texit 1\n+}\n+\n+sub commit_diff {\n+\tif (!$_use_lib) {\n+\t\tprint STDERR \"commit-diff must be used with SVN libraries\\n\";\n+\t\texit 1;\n+\t}\n+\tmy $ta = shift or commit_diff_usage();\n+\tmy $tb = shift or commit_diff_usage();\n+\tif (!eval { $SVN_URL = shift || file_to_s(\"$GIT_SVN_DIR/info/url\") }) {\n+\t\tprint STDERR \"Needed URL or usable git-svn id command-line\\n\";\n+\t\tcommit_diff_usage();\n+\t}\n+\tif (defined $_message && defined $_file) {\n+\t\tprint STDERR \"Both --message/-m and --file/-F specified \",\n+\t\t\t\t\"for the commit message.\\n\",\n+\t\t\t\t\"I have no idea what you mean\\n\";\n+\t\texit 1;\n+\t}\n+\tif (defined $_file) {\n+\t\t$_message = file_to_s($_message);\n+\t} else {\n+\t\t$_message ||= get_commit_message($tb,\n+\t\t\t\t\t\"$GIT_DIR/.svn-commit.tmp.$$\")->{msg};\n+\t}\n+\tmy $repo;\n+\t($repo, $SVN_PATH) = repo_path_split($SVN_URL);\n+\t$SVN_LOG ||= libsvn_connect($repo);\n+\t$SVN ||= libsvn_connect($repo);\n+\tmy @lock = $SVN::Core::VERSION ge '1.2.0' ? (undef, 0) : ();\n+\tmy $ed = SVN::Git::Editor->new({\tr => $SVN->get_latest_revnum,\n+\t\t\t\t\t\tra => $SVN, c => $tb,\n+\t\t\t\t\t\tsvn_path => $SVN_PATH\n+\t\t\t\t\t},\n+\t\t\t\t$SVN->get_commit_editor($_message,\n+\t\t\t\t\tsub {print \"Committed $_[0]\\n\"},@lock)\n+\t\t\t\t);\n+\tmy $mods = libsvn_checkout_tree($ta, $tb, $ed);\n+\tif (@$mods == 0) {\n+\t\tprint \"No changes\\n$ta == $tb\\n\";\n+\t\t$ed->abort_edit;\n+\t} else {\n+\t\t$ed->close_edit;\n+\t}\n+}\n+\n ########################### utility functions #########################\n \n sub cmt_showable {\n@@ -1473,7 +1522,6 @@ sub get_commit_message {\n \tmy %log_msg = ( msg => '' );\n \topen my $msg, '>', $commit_msg or croak $!;\n \n-\tprint \"commit: $commit\\n\";\n \tchomp(my $type = `git-cat-file -t $commit`);\n \tif ($type eq 'commit') {\n \t\tmy $pid = open my $msg_fh, '-|';\n@@ -1510,6 +1558,14 @@ sub get_commit_message {\n \treturn \\%log_msg;\n }\n \n+sub set_svn_commit_env {\n+\tif (defined $LC_ALL) {\n+\t\t$ENV{LC_ALL} = $LC_ALL;\n+\t} else {\n+\t\tdelete $ENV{LC_ALL};\n+\t}\n+}\n+\n sub svn_commit_tree {\n \tmy ($last, $commit) = @_;\n \tmy $commit_msg = \"$GIT_SVN_DIR/.svn-commit.tmp.$$\";\n@@ -1517,11 +1573,7 @@ sub svn_commit_tree {\n \tmy ($oneline) = ($log_msg->{msg} =~ /([^\\n\\r]+)/);\n \tprint \"Committing $commit: $oneline\\n\";\n \n-\tif (defined $LC_ALL) {\n-\t\t$ENV{LC_ALL} = $LC_ALL;\n-\t} else {\n-\t\tdelete $ENV{LC_ALL};\n-\t}\n+\tset_svn_commit_env();\n \tmy @ci_output = safe_qx(qw(svn commit -F),$commit_msg);\n \t$ENV{LC_ALL} = 'C';\n \tunlink $commit_msg;\ndiff --git a/contrib/git-svn/t/t0005-commit-diff.sh b/contrib/git-svn/t/t0005-commit-diff.sh\nnew file mode 100644\nindex 0000000..f994b72\n--- /dev/null\n+++ b/contrib/git-svn/t/t0005-commit-diff.sh\n@@ -0,0 +1,41 @@\n+#!/bin/sh\n+#\n+# Copyright (c) 2006 Eric Wong\n+test_description='git-svn commit-diff'\n+. ./lib-git-svn.sh\n+\n+if test -n \"$GIT_SVN_NO_LIB\" && test \"$GIT_SVN_NO_LIB\" -ne 0\n+then\n+\techo 'Skipping: commit-diff needs SVN libraries'\n+\ttest_done\n+\texit 0\n+fi\n+\n+test_expect_success 'initialize repo' \"\n+\tmkdir import &&\n+\tcd import &&\n+\techo hello > readme &&\n+\tsvn import -m 'initial' . $svnrepo &&\n+\tcd .. &&\n+\techo hello > readme &&\n+\tgit update-index --add readme &&\n+\tgit commit -a -m 'initial' &&\n+\techo world >> readme &&\n+\tgit commit -a -m 'another'\n+\t\"\n+\n+head=`git rev-parse --verify HEAD^0`\n+prev=`git rev-parse --verify HEAD^1`\n+\n+# the internals of the commit-diff command are the same as the regular\n+# commit, so only a basic test of functionality is needed since we've\n+# already tested commit extensively elsewhere\n+\n+test_expect_success 'test the commit-diff command' \"\n+\ttest -n '$prev' && test -n '$head' &&\n+\tgit-svn commit-diff '$prev' '$head' '$svnrepo' &&\n+\tsvn co $svnrepo wc &&\n+\tcmp readme wc/readme\n+\t\"\n+\n+test_done\n-- \n1.4.1.rc1.g3cc8\n"},{"id":"22704","messageId":"11514623601954-git-send-email-normalperson@yhbt.net","threadId":"4688","inReplyTo":"11514623542848-git-send-email-normalperson@yhbt.net","subject":"[PATCH 4/5] git-svn: add --follow-parent and --no-metadata options to fetch","fromName":"Eric Wong","fromEmail":"normalperson@yhbt.net","sentAt":"2006-06-28T02:39:13Z","receivedAt":"2006-06-28T02:39:13Z","isPatch":true,"sender":{"key":"e@80x24.org","avatar":null},"body":"--follow-parent:\n  This is especially helpful when we're tracking a directory\n  that has been moved around within the repository, or if we\n  started tracking a branch and never tracked the trunk it was\n  descended from.\n\n  This relies on the SVN::* libraries to work.  We can't\n  reliably parse path info from the svn command-line client\n  without relying on XML, so it's better just to have the SVN::*\n  libs installed.\n\n  This also removes oldvalue verification when calling update-ref\n\n  In SVN, branches can be deleted, and then recreated under the\n  same path as the original one with different ancestry\n  information, causing parent information to be mismatched /\n  misordered.\n\n  Also force the current ref, if existing, to be a parent,\n  regardless of whether or not it was specified.\n\n--no-metadata:\n  This gets rid of the git-svn-id: lines at the end of every commit.\n\n  With this, you lose the ability to use the rebuild command.  If\n  you ever lose your .git/svn/git-svn/.rev_db file, you won't be\n  able to fetch again, either.  This is fine for one-shot imports.\n\n  Also fix some issues with multi-fetch --follow-parent that were\n  exposed while testing this.  Additionally, repack checking is\n  simplified greatly.\n\n  git-svn log will not work on repositories using this, either.\n\nSigned-off-by: Eric Wong <normalperson@yhbt.net>\n---\n contrib/git-svn/git-svn.perl             |  169 ++++++++++++++++++++++--------\n contrib/git-svn/t/t0004-follow-parent.sh |   44 ++++++++\n 2 files changed, 167 insertions(+), 46 deletions(-)\n\ndiff --git a/contrib/git-svn/git-svn.perl b/contrib/git-svn/git-svn.perl\nindex 73b339a..33fd82a 100755\n--- a/contrib/git-svn/git-svn.perl\n+++ b/contrib/git-svn/git-svn.perl\n@@ -19,6 +19,7 @@ my $TZ = $ENV{TZ};\n # make sure the svn binary gives consistent output between locales and TZs:\n $ENV{TZ} = 'UTC';\n $ENV{LC_ALL} = 'C';\n+$| = 1; # unbuffer STDOUT\n \n # If SVN:: library support is added, please make the dependencies\n # optional and preserve the capability to use the command-line client.\n@@ -46,7 +47,7 @@ my $sha1_short = qr/[a-f\\d]{4,40}/;\n my ($_revision,$_stdin,$_no_ignore_ext,$_no_stop_copy,$_help,$_rmdir,$_edit,\n \t$_find_copies_harder, $_l, $_cp_similarity, $_cp_remote,\n \t$_repack, $_repack_nr, $_repack_flags,\n-\t$_message, $_file,\n+\t$_message, $_file, $_follow_parent, $_no_metadata,\n \t$_template, $_shared, $_no_default_regex, $_no_graft_copy,\n \t$_limit, $_verbose, $_incremental, $_oneline, $_l_fmt, $_show_commit,\n \t$_version, $_upgrade, $_authors, $_branch_all_refs, @_opt_m);\n@@ -56,9 +57,11 @@ my @repo_path_split_cache;\n \n my %fc_opts = ( 'no-ignore-externals' => \\$_no_ignore_ext,\n \t\t'branch|b=s' => \\@_branch_from,\n+\t\t'follow-parent|follow' => \\$_follow_parent,\n \t\t'branch-all-refs|B' => \\$_branch_all_refs,\n \t\t'authors-file|A=s' => \\$_authors,\n \t\t'repack:i' => \\$_repack,\n+\t\t'no-metadata' => \\$_no_metadata,\n \t\t'repack-flags|repack-args|repack-opts=s' => \\$_repack_flags);\n \n my ($_trunk, $_tags, $_branches);\n@@ -825,35 +828,19 @@ sub fetch_child_id {\n \tmy $id = shift;\n \tprint \"Fetching $id\\n\";\n \tmy $ref = \"$GIT_DIR/refs/remotes/$id\";\n-\tmy $ca = file_to_s($ref) if (-r $ref);\n-\tdefined(my $pid = fork) or croak $!;\n+\tdefined(my $pid = open my $fh, '-|') or croak $!;\n \tif (!$pid) {\n+\t\t$_repack = undef;\n \t\t$GIT_SVN = $ENV{GIT_SVN_ID} = $id;\n \t\tinit_vars();\n \t\tfetch(@_);\n \t\texit 0;\n \t}\n-\twaitpid $pid, 0;\n-\tcroak $? if $?;\n-\treturn unless $_repack || -r $ref;\n-\n-\tmy $cb = file_to_s($ref);\n-\n-\tdefined($pid = open my $fh, '-|') or croak $!;\n-\tmy $url = file_to_s(\"$GIT_DIR/svn/$id/info/url\");\n-\t$url = qr/\\Q$url\\E/;\n-\tif (!$pid) {\n-\t\texec qw/git-rev-list --pretty=raw/,\n-\t\t\t\t$ca ? \"$ca..$cb\" : $cb or croak $!;\n-\t}\n \twhile (<$fh>) {\n-\t\tif (/^    git-svn-id: $url\\@\\d+ [a-f0-9\\-]+$/) {\n-\t\t\tcheck_repack();\n-\t\t} elsif (/^    git-svn-id: \\S+\\@\\d+ [a-f0-9\\-]+$/) {\n-\t\t\tlast;\n-\t\t}\n+\t\tprint $_;\n+\t\tcheck_repack() if (/^r\\d+ = $sha1/);\n \t}\n-\tclose $fh;\n+\tclose $fh or croak $?;\n }\n \n sub rec_fetch {\n@@ -1922,6 +1909,13 @@ sub git_commit {\n \t\tcroak $? if $?;\n \t\trestore_index($index);\n \t}\n+\n+\t# just in case we clobber the existing ref, we still want that ref\n+\t# as our parent:\n+\tif (my $cur = eval { file_to_s(\"$GIT_DIR/refs/remotes/$GIT_SVN\") }) {\n+\t\tpush @tmp_parents, $cur;\n+\t}\n+\n \tif (exists $tree_map{$tree}) {\n \t\tforeach my $p (@{$tree_map{$tree}}) {\n \t\t\tmy $skip;\n@@ -1952,31 +1946,26 @@ sub git_commit {\n \t\tlast if @exec_parents > 16;\n \t}\n \n-\tdefined(my $pid = open my $out_fh, '-|') or croak $!;\n-\tif ($pid == 0) {\n-\t\tmy $msg_fh = IO::File->new_tmpfile or croak $!;\n-\t\tprint $msg_fh $log_msg->{msg}, \"\\ngit-svn-id: \",\n-\t\t\t\t\t\"$SVN_URL\\@$log_msg->{revision}\",\n+\tset_commit_env($log_msg);\n+\tmy @exec = ('git-commit-tree', $tree);\n+\tpush @exec, '-p', $_  foreach @exec_parents;\n+\tdefined(my $pid = open3(my $msg_fh, my $out_fh, '>&STDERR', @exec))\n+\t\t\t\t\t\t\t\tor croak $!;\n+\tprint $msg_fh $log_msg->{msg} or croak $!;\n+\tunless ($_no_metadata) {\n+\t\tprint $msg_fh \"\\ngit-svn-id: $SVN_URL\\@$log_msg->{revision}\",\n \t\t\t\t\t\" $SVN_UUID\\n\" or croak $!;\n-\t\t$msg_fh->flush == 0 or croak $!;\n-\t\tseek $msg_fh, 0, 0 or croak $!;\n-\t\tset_commit_env($log_msg);\n-\t\tmy @exec = ('git-commit-tree',$tree);\n-\t\tpush @exec, '-p', $_  foreach @exec_parents;\n-\t\topen STDIN, '<&', $msg_fh or croak $!;\n-\t\texec @exec or croak $!;\n \t}\n+\t$msg_fh->flush == 0 or croak $!;\n+\tclose $msg_fh or croak $!;\n \tchomp(my $commit = do { local $/; <$out_fh> });\n-\tclose $out_fh or croak $?;\n+\tclose $out_fh or croak $!;\n+\twaitpid $pid, 0;\n+\tcroak $? if $?;\n \tif ($commit !~ /^$sha1$/o) {\n-\t\tcroak \"Failed to commit, invalid sha1: $commit\\n\";\n+\t\tdie \"Failed to commit, invalid sha1: $commit\\n\";\n \t}\n-\tmy @update_ref = ('git-update-ref',\"refs/remotes/$GIT_SVN\",$commit);\n-\tif (my $primary_parent = shift @exec_parents) {\n-\t\tquiet_run(qw/git-rev-parse --verify/,\"refs/remotes/$GIT_SVN^0\");\n-\t\tpush @update_ref, $primary_parent unless $?;\n-\t}\n-\tsys(@update_ref);\n+\tsys('git-update-ref',\"refs/remotes/$GIT_SVN\",$commit);\n \trevdb_set($REVDB, $log_msg->{revision}, $commit);\n \n \t# this output is read via pipe, do not change:\n@@ -2061,6 +2050,11 @@ sub safe_qx {\n }\n \n sub svn_compat_check {\n+\tif ($_follow_parent) {\n+\t\tprint STDERR 'E: --follow-parent functionality is only ',\n+\t\t\t\t\"available when SVN libraries are used\\n\";\n+\t\texit 1;\n+\t}\n \tmy @co_help = safe_qx(qw(svn co -h));\n \tunless (grep /ignore-externals/,@co_help) {\n \t\tprint STDERR \"W: Installed svn version does not support \",\n@@ -2389,6 +2383,28 @@ sub write_grafts {\n \tclose $fh or croak $!;\n }\n \n+sub read_url_paths_all {\n+\tmy ($l_map, $pfx, $p) = @_;\n+\tmy @dir;\n+\tforeach (<$p/*>) {\n+\t\tif (-r \"$_/info/url\") {\n+\t\t\t$pfx .= '/' if $pfx && $pfx !~ m!/$!;\n+\t\t\tmy $id = $pfx . basename $_;\n+\t\t\tmy $url = file_to_s(\"$_/info/url\");\n+\t\t\tmy ($u, $p) = repo_path_split($url);\n+\t\t\t$l_map->{$u}->{$p} = $id;\n+\t\t} elsif (-d $_) {\n+\t\t\tpush @dir, $_;\n+\t\t}\n+\t}\n+\tforeach (@dir) {\n+\t\tmy $x = $_;\n+\t\t$x =~ s!^\\Q$GIT_DIR\\E/svn/!!o;\n+\t\tread_url_paths_all($l_map, $x, $_);\n+\t}\n+}\n+\n+# this one only gets ids that have been imported, not new ones\n sub read_url_paths {\n \tmy $l_map = {};\n \tgit_svn_each(sub { my $x = shift;\n@@ -2602,7 +2618,6 @@ sub libsvn_get_file {\n \t# redirect STDOUT for SVN 1.1.x compatibility\n \topen my $stdout, '>&', \\*STDOUT or croak $!;\n \topen STDOUT, '>&', $in or croak $!;\n-\t$| = 1; # not sure if this is necessary, better safe than sorry...\n \tmy ($r, $props) = $SVN->get_file($f, $rev, \\*STDOUT, $pool);\n \t$in->flush == 0 or croak $!;\n \topen STDOUT, '>&', $stdout or croak $!;\n@@ -2705,6 +2720,28 @@ sub svn_grab_base_rev {\n \tclose $fh;\n \tif (defined $c && length $c) {\n \t\tmy ($url, $rev, $uuid) = cmt_metadata($c);\n+\t\treturn ($rev, $c) if defined $rev;\n+\t}\n+\tif ($_no_metadata) {\n+\t\tmy $offset = -41; # from tail\n+\t\tmy $rl;\n+\t\topen my $fh, '<', $REVDB or\n+\t\t\tdie \"--no-metadata specified and $REVDB not readable\\n\";\n+\t\tseek $fh, $offset, 2;\n+\t\t$rl = readline $fh;\n+\t\tdefined $rl or return (undef, undef);\n+\t\tchomp $rl;\n+\t\twhile ($c ne $rl && tell $fh != 0) {\n+\t\t\t$offset -= 41;\n+\t\t\tseek $fh, $offset, 2;\n+\t\t\t$rl = readline $fh;\n+\t\t\tdefined $rl or return (undef, undef);\n+\t\t\tchomp $rl;\n+\t\t}\n+\t\tmy $rev = tell $fh;\n+\t\tcroak $! if ($rev < -1);\n+\t\t$rev =  ($rev - 41) / 41;\n+\t\tclose $fh or croak $!;\n \t\treturn ($rev, $c);\n \t}\n \treturn (undef, undef);\n@@ -2803,15 +2840,45 @@ sub libsvn_find_parent_branch {\n \tprint STDERR  \"Found possible branch point: \",\n \t\t\t\t\"$branch_from => $svn_path, $r\\n\";\n \t$branch_from =~ s#^/##;\n-\tmy $l_map = read_url_paths();\n+\tmy $l_map = {};\n+\tread_url_paths_all($l_map, '', \"$GIT_DIR/svn\");\n \tmy $url = $SVN->{url};\n \tdefined $l_map->{$url} or return;\n-\tmy $id = $l_map->{$url}->{$branch_from} or return;\n+\tmy $id = $l_map->{$url}->{$branch_from};\n+\tif (!defined $id && $_follow_parent) {\n+\t\tprint STDERR \"Following parent: $branch_from\\@$r\\n\";\n+\t\t# auto create a new branch and follow it\n+\t\t$id = basename($branch_from);\n+\t\t$id .= '@'.$r if -r \"$GIT_DIR/svn/$id\";\n+\t\twhile (-r \"$GIT_DIR/svn/$id\") {\n+\t\t\t# just grow a tail if we're not unique enough :x\n+\t\t\t$id .= '-';\n+\t\t}\n+\t}\n+\treturn unless defined $id;\n+\n \tmy ($r0, $parent) = find_rev_before($r,$id,1);\n+\tif ($_follow_parent && (!defined $r0 || !defined $parent)) {\n+\t\tdefined(my $pid = fork) or croak $!;\n+\t\tif (!$pid) {\n+\t\t\t$GIT_SVN = $ENV{GIT_SVN_ID} = $id;\n+\t\t\tinit_vars();\n+\t\t\t$SVN_URL = \"$url/$branch_from\";\n+\t\t\t$SVN_LOG = $SVN = undef;\n+\t\t\tsetup_git_svn();\n+\t\t\t# we can't assume SVN_URL exists at r+1:\n+\t\t\t$_revision = \"0:$r\";\n+\t\t\tfetch_lib();\n+\t\t\texit 0;\n+\t\t}\n+\t\twaitpid $pid, 0;\n+\t\tcroak $? if $?;\n+\t\t($r0, $parent) = find_rev_before($r,$id,1);\n+\t}\n \treturn unless (defined $r0 && defined $parent);\n \tif (revisions_eq($branch_from, $r0, $r)) {\n \t\tunlink $GIT_SVN_INDEX;\n-\t\tprint STDERR \"Found branch parent: $parent\\n\";\n+\t\tprint STDERR \"Found branch parent: ($GIT_SVN) $parent\\n\";\n \t\tsys(qw/git-read-tree/, $parent);\n \t\treturn libsvn_fetch($parent, $paths, $rev,\n \t\t\t\t\t$author, $date, $msg);\n@@ -3270,6 +3337,16 @@ diff-index line ($m hash)\n }\n ;\n \n+# retval of read_url_paths{,_all}();\n+$l_map = {\n+\t# repository root url\n+\t'https://svn.musicpd.org' => {\n+\t\t# repository path \t\t# GIT_SVN_ID\n+\t\t'mpd/trunk'\t\t=>\t'trunk',\n+\t\t'mpd/tags/0.11.5'\t=>\t'tags/0.11.5',\n+\t},\n+}\n+\n Notes:\n \tI don't trust the each() function on unless I created %hash myself\n \tbecause the internal iterator may not have started at base.\ndiff --git a/contrib/git-svn/t/t0004-follow-parent.sh b/contrib/git-svn/t/t0004-follow-parent.sh\nnew file mode 100644\nindex 0000000..01488ff\n--- /dev/null\n+++ b/contrib/git-svn/t/t0004-follow-parent.sh\n@@ -0,0 +1,44 @@\n+#!/bin/sh\n+#\n+# Copyright (c) 2006 Eric Wong\n+#\n+\n+test_description='git-svn --follow-parent fetching'\n+. ./lib-git-svn.sh\n+\n+if test -n \"$GIT_SVN_NO_LIB\" && test \"$GIT_SVN_NO_LIB\" -ne 0\n+then\n+\techo 'Skipping: --follow-parent needs SVN libraries'\n+\ttest_done\n+\texit 0\n+fi\n+\n+test_expect_success 'initialize repo' \"\n+\tmkdir import &&\n+\tcd import &&\n+\tmkdir -p trunk &&\n+\techo hello > trunk/readme &&\n+\tsvn import -m 'initial' . $svnrepo &&\n+\tcd .. &&\n+\tsvn co $svnrepo wc &&\n+\tcd wc &&\n+\techo world >> trunk/readme &&\n+\tsvn commit -m 'another commit' &&\n+\tsvn up &&\n+\tsvn mv -m 'rename to thunk' trunk thunk &&\n+\tsvn up &&\n+\techo goodbye >> thunk/readme &&\n+\tsvn commit -m 'bye now' &&\n+\tcd ..\n+\t\"\n+\n+test_expect_success 'init and fetch --follow-parent a moved directory' \"\n+\tgit-svn init -i thunk $svnrepo/thunk &&\n+\tgit-svn fetch --follow-parent -i thunk &&\n+\tgit-rev-parse --verify refs/remotes/trunk &&\n+\ttest '$?' -eq '0'\n+\t\"\n+\n+test_debug 'gitk --all &'\n+\n+test_done\n-- \n1.4.1.rc1.g3cc8\n"},{"id":"22702","messageId":"11514623622980-git-send-email-normalperson@yhbt.net","threadId":"4688","inReplyTo":"11514623542848-git-send-email-normalperson@yhbt.net","subject":"[PATCH 5/5] git-svn: be verbose by default on fetch/commit, add -q/--quiet option","fromName":"Eric Wong","fromEmail":"normalperson@yhbt.net","sentAt":"2006-06-28T02:39:14Z","receivedAt":"2006-06-28T02:39:14Z","isPatch":true,"sender":{"key":"e@80x24.org","avatar":null},"body":"Slower connections can make git-svn look as if it's doing\nnothing for a long time; leaving the user wondering if we're\nactually doing anything.  Now we print some file progress just\nto assure the user that something is going on while they're\nwaiting.\n\nAdded the -q/--quiet option to users to revert to the old method\nif they preferred it.\n\nSigned-off-by: Eric Wong <normalperson@yhbt.net>\n---\n contrib/git-svn/git-svn.perl |   34 +++++++++++++++++++++++-----------\n 1 files changed, 23 insertions(+), 11 deletions(-)\n\ndiff --git a/contrib/git-svn/git-svn.perl b/contrib/git-svn/git-svn.perl\nindex 33fd82a..464d94e 100755\n--- a/contrib/git-svn/git-svn.perl\n+++ b/contrib/git-svn/git-svn.perl\n@@ -46,7 +46,7 @@ my $sha1 = qr/[a-f\\d]{40}/;\n my $sha1_short = qr/[a-f\\d]{4,40}/;\n my ($_revision,$_stdin,$_no_ignore_ext,$_no_stop_copy,$_help,$_rmdir,$_edit,\n \t$_find_copies_harder, $_l, $_cp_similarity, $_cp_remote,\n-\t$_repack, $_repack_nr, $_repack_flags,\n+\t$_repack, $_repack_nr, $_repack_flags, $_q,\n \t$_message, $_file, $_follow_parent, $_no_metadata,\n \t$_template, $_shared, $_no_default_regex, $_no_graft_copy,\n \t$_limit, $_verbose, $_incremental, $_oneline, $_l_fmt, $_show_commit,\n@@ -62,6 +62,7 @@ my %fc_opts = ( 'no-ignore-externals' =>\n \t\t'authors-file|A=s' => \\$_authors,\n \t\t'repack:i' => \\$_repack,\n \t\t'no-metadata' => \\$_no_metadata,\n+\t\t'quiet|q' => \\$_q,\n \t\t'repack-flags|repack-args|repack-opts=s' => \\$_repack_flags);\n \n my ($_trunk, $_tags, $_branches);\n@@ -1457,12 +1458,12 @@ sub libsvn_checkout_tree {\n \tforeach my $m (sort { $o{$a->{chg}} <=> $o{$b->{chg}} } @$mods) {\n \t\tmy $f = $m->{chg};\n \t\tif (defined $o{$f}) {\n-\t\t\t$ed->$f($m);\n+\t\t\t$ed->$f($m, $_q);\n \t\t} else {\n \t\t\tcroak \"Invalid change type: $f\\n\";\n \t\t}\n \t}\n-\t$ed->rmdirs if $_rmdir;\n+\t$ed->rmdirs($_q) if $_rmdir;\n \treturn $mods;\n }\n \n@@ -2688,6 +2689,7 @@ sub libsvn_fetch {\n \t\tmy $m = $paths->{$f}->action();\n \t\t$f =~ s#^/+##;\n \t\tif ($m =~ /^[DR]$/) {\n+\t\t\tprint \"\\t$m\\t$f\\n\" unless $_q;\n \t\t\tprocess_rm($gui, $last_commit, $f);\n \t\t\tnext if $m eq 'D';\n \t\t\t# 'R' can be file replacements, too, right?\n@@ -2696,14 +2698,17 @@ sub libsvn_fetch {\n \t\tmy $t = $SVN->check_path($f, $rev, $pool);\n \t\tif ($t == $SVN::Node::file) {\n \t\t\tif ($m =~ /^[AMR]$/) {\n-\t\t\t\tpush @amr, $f;\n+\t\t\t\tpush @amr, [ $m, $f ];\n \t\t\t} else {\n \t\t\t\tdie \"Unrecognized action: $m, ($f r$rev)\\n\";\n \t\t\t}\n \t\t}\n \t\t$pool->clear;\n \t}\n-\tlibsvn_get_file($gui, $_, $rev) foreach (@amr);\n+\tforeach (@amr) {\n+\t\tprint \"\\t$_->[0]\\t$_->[1]\\n\" unless $_q;\n+\t\tlibsvn_get_file($gui, $_->[1], $rev)\n+\t}\n \tclose $gui or croak $?;\n \treturn libsvn_log_entry($rev, $author, $date, $msg, [$last_commit]);\n }\n@@ -2776,6 +2781,7 @@ sub libsvn_traverse {\n \t\tif ($t == $SVN::Node::dir) {\n \t\t\tlibsvn_traverse($gui, $cwd, $d, $rev);\n \t\t} elsif ($t == $SVN::Node::file) {\n+\t\t\tprint \"\\tA\\t$cwd/$d\\n\" unless $_q;\n \t\t\tlibsvn_get_file($gui, \"$cwd/$d\", $rev);\n \t\t}\n \t}\n@@ -3105,7 +3111,7 @@ sub url_path {\n }\n \n sub rmdirs {\n-\tmy ($self) = @_;\n+\tmy ($self, $q) = @_;\n \tmy $rm = $self->{rm};\n \tdelete $rm->{''}; # we never delete the url we're tracking\n \treturn unless %$rm;\n@@ -3146,6 +3152,7 @@ sub rmdirs {\n \tforeach my $d (sort { $b =~ tr#/#/# <=> $a =~ tr#/#/# } keys %$rm) {\n \t\t$self->close_directory($bat->{$d}, $p);\n \t\tmy ($dn) = ($d =~ m#^(.*?)/?(?:[^/]+)$#);\n+\t\tprint \"\\tD+\\t/$d/\\n\" unless $q;\n \t\t$self->SUPER::delete_entry($d, $r, $bat->{$dn}, $p);\n \t\tdelete $bat->{$d};\n \t}\n@@ -3186,21 +3193,23 @@ sub ensure_path {\n }\n \n sub A {\n-\tmy ($self, $m) = @_;\n+\tmy ($self, $m, $q) = @_;\n \tmy ($dir, $file) = split_path($m->{file_b});\n \tmy $pbat = $self->ensure_path($dir);\n \tmy $fbat = $self->add_file($self->repo_path($m->{file_b}), $pbat,\n \t\t\t\t\tundef, -1);\n+\tprint \"\\tA\\t$m->{file_b}\\n\" unless $q;\n \t$self->chg_file($fbat, $m);\n \t$self->close_file($fbat,undef,$self->{pool});\n }\n \n sub C {\n-\tmy ($self, $m) = @_;\n+\tmy ($self, $m, $q) = @_;\n \tmy ($dir, $file) = split_path($m->{file_b});\n \tmy $pbat = $self->ensure_path($dir);\n \tmy $fbat = $self->add_file($self->repo_path($m->{file_b}), $pbat,\n \t\t\t\t$self->url_path($m->{file_a}), $self->{r});\n+\tprint \"\\tC\\t$m->{file_a} => $m->{file_b}\\n\" unless $q;\n \t$self->chg_file($fbat, $m);\n \t$self->close_file($fbat,undef,$self->{pool});\n }\n@@ -3214,11 +3223,12 @@ sub delete_entry {\n }\n \n sub R {\n-\tmy ($self, $m) = @_;\n+\tmy ($self, $m, $q) = @_;\n \tmy ($dir, $file) = split_path($m->{file_b});\n \tmy $pbat = $self->ensure_path($dir);\n \tmy $fbat = $self->add_file($self->repo_path($m->{file_b}), $pbat,\n \t\t\t\t$self->url_path($m->{file_a}), $self->{r});\n+\tprint \"\\tR\\t$m->{file_a} => $m->{file_b}\\n\" unless $q;\n \t$self->chg_file($fbat, $m);\n \t$self->close_file($fbat,undef,$self->{pool});\n \n@@ -3228,11 +3238,12 @@ sub R {\n }\n \n sub M {\n-\tmy ($self, $m) = @_;\n+\tmy ($self, $m, $q) = @_;\n \tmy ($dir, $file) = split_path($m->{file_b});\n \tmy $pbat = $self->ensure_path($dir);\n \tmy $fbat = $self->open_file($self->repo_path($m->{file_b}),\n \t\t\t\t$pbat,$self->{r},$self->{pool});\n+\tprint \"\\t$m->{chg}\\t$m->{file_b}\\n\" unless $q;\n \t$self->chg_file($fbat, $m);\n \t$self->close_file($fbat,undef,$self->{pool});\n }\n@@ -3281,9 +3292,10 @@ sub chg_file {\n }\n \n sub D {\n-\tmy ($self, $m) = @_;\n+\tmy ($self, $m, $q) = @_;\n \tmy ($dir, $file) = split_path($m->{file_b});\n \tmy $pbat = $self->ensure_path($dir);\n+\tprint \"\\tD\\t$m->{file_b}\\n\" unless $q;\n \t$self->delete_entry($m->{file_b}, $pbat);\n }\n \n-- \n1.4.1.rc1.g3cc8\n"},{"id":"22715","messageId":"7virml4pqg.fsf@assigned-by-dhcp.cox.net","threadId":"4688","inReplyTo":"11514623563534-git-send-email-normalperson@yhbt.net","subject":"Re: [PATCH 1/5] git-svn: SVN 1.1.x library compatibility","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2006-06-28T09:02:47Z","receivedAt":"2006-06-28T09:02:47Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Eric Wong <normalperson@yhbt.net> writes:\n\n> Tested on a plain Ubuntu Hoary installation\n> using subversion 1.1.1-2ubuntu3\n>\n> 1.1.x issues I had to deal with:\n>\n> * Avoid the noisy command-line client compatibility check if we\n>   use the libraries.\n>\n> * get_log() arguments differ.\n\nMaybe you would want to have a single wrapper sub {} for this,\ninstead of repeating it all over, perhaps like this:\n\n\tsub log_get {\n        \tmy ($SVN_LOG, @args) = @_;\n        \tif ($SVN::CORE::VERSION ge '1.2.0') {\n                \tsplice(@args, 3, 0, 0);\n                }\n                $SVN_LOG->get_log(@args);\n\t}\n\n> -if test -n \"$GIT_SVN_LC_ALL\" && echo $GIT_SVN_LC_ALL | grep -q '\\.UTF-8$'\n> +if test -n \"$GIT_SVN_LC_ALL\" && echo $GIT_SVN_LC_ALL |grep '\\.UTF-8$' >/dev/null\n>  then\n\nHmph.  I tend to do something like this instead of pipeing echo\nto grep:\n\n\tcase \"$LC_ALL\" in\n        *.UTF-8)\n        \t# it is utf-8\n                ;;\n        *)\n        \t# otherwise\n                ;;\n\tesac\n"},{"id":"22731","messageId":"20060628100714.GB23948@soma","threadId":"4688","inReplyTo":"7virml4pqg.fsf@assigned-by-dhcp.cox.net","subject":"[PATCH] git-svn: SVN 1.1.x library compatibility","fromName":"Eric Wong","fromEmail":"normalperson@yhbt.net","sentAt":"2006-06-28T10:07:14Z","receivedAt":"2006-06-28T10:07:14Z","isPatch":true,"sender":{"key":"e@80x24.org","avatar":null},"body":"Tested on a plain Ubuntu Hoary installation\nusing subversion 1.1.1-2ubuntu3\n\n1.1.x issues I had to deal with:\n\n* Avoid the noisy command-line client compatibility check if we\n  use the libraries.\n\n* get_log() arguments differ (now using a nice wrapper from\n  Junio's suggestion)\n\n* get_file() is picky about what kind of file handles it gets,\n  so I ended up redirecting STDOUT.  I'm probably overflushing\n  my file handles, but that's the safest thing to do...\n\n* BDB kept segfaulting on me during tests, so svnadmin will use FSFS\n  whenever we can.\n\n* If somebody used an expanded CVS $Id$ line inside a file, then\n  propsetting it to use svn:keywords will cause the original CVS\n  $Id$ to be retained when asked for the original file.  As far as\n  I can see, this is a server-side issue.  We won't care in the\n  test anymore, as long as it's not expanded by SVN, a static\n  CVS $Id$ line is fine.\n\nWhile we're at making ourselves more compatible, avoid grep\nalong with the -q flag, which is GNU-specific. (grep avoidance\ntip from Junio, too)\n\nSigned-off-by: Eric Wong <normalperson@yhbt.net>\n---\n Junio C Hamano <junkio@cox.net> wrote:\n > Eric Wong <normalperson@yhbt.net> writes:\n > > * get_log() arguments differ.\n > \n > Maybe you would want to have a single wrapper sub {} for this,\n > instead of repeating it all over, perhaps like this:\n > \n > \tsub log_get {\n >         \tmy ($SVN_LOG, @args) = @_;\n >         \tif ($SVN::CORE::VERSION ge '1.2.0') {\n >                 \tsplice(@args, 3, 0, 0);\n >                 }\n >                 $SVN_LOG->get_log(@args);\n > \t}\n\n I actually did it backwards (le) in case I want create something that\n could take advantage of the limit arg for newer versions but degrade\n gracefully for 1.1.x\n\n contrib/git-svn/git-svn.perl                     |   30 +++++++++++++++++-----\n contrib/git-svn/t/lib-git-svn.sh                 |    8 +++++-\n contrib/git-svn/t/t0000-contrib-git-svn.sh       |   14 +++++++++-\n contrib/git-svn/t/t0001-contrib-git-svn-props.sh |    4 +--\n 4 files changed, 44 insertions(+), 12 deletions(-)\n\ndiff --git a/contrib/git-svn/git-svn.perl b/contrib/git-svn/git-svn.perl\nindex 08c3010..f026b24 100755\n--- a/contrib/git-svn/git-svn.perl\n+++ b/contrib/git-svn/git-svn.perl\n@@ -134,7 +134,7 @@ usage(1) unless defined $cmd;\n init_vars();\n load_authors() if $_authors;\n load_all_refs() if $_branch_all_refs;\n-svn_compat_check();\n+svn_compat_check() unless $_use_lib;\n migration_check() unless $cmd =~ /^(?:init|rebuild|multi-init)$/;\n $cmd{$cmd}->[0]->(@ARGV);\n exit 0;\n@@ -379,7 +379,8 @@ sub fetch_lib {\n \t\t\t# performance sucks with it enabled, so it's much\n \t\t\t# faster to fetch revision ranges instead of relying\n \t\t\t# on the limiter.\n-\t\t\t$SVN_LOG->get_log( '/'.$SVN_PATH, $min, $max, 0, 1, 1,\n+\t\t\tlibsvn_get_log($SVN_LOG, '/'.$SVN_PATH,\n+\t\t\t\t\t$min, $max, 0, 1, 1,\n \t\t\t\tsub {\n \t\t\t\t\tmy $log_msg;\n \t\t\t\t\tif ($last_commit) {\n@@ -924,7 +925,7 @@ sub graft_file_copy_lib {\n \t$SVN::Error::handler = \\&libsvn_skip_unknown_revs;\n \twhile (1) {\n \t\tmy $pool = SVN::Pool->new;\n-\t\t$SVN_LOG->get_log( \"/$path\", $min, $max, 0, 1, 1,\n+\t\tlibsvn_get_log($SVN_LOG, \"/$path\", $min, $max, 0, 1, 1,\n \t\t\tsub {\n \t\t\t\tlibsvn_graft_file_copies($grafts, $tree_paths,\n \t\t\t\t\t\t\t$path, @_);\n@@ -2358,8 +2359,8 @@ sub libsvn_load {\n \treturn unless $_use_lib;\n \t$_use_lib = eval {\n \t\trequire SVN::Core;\n-\t\tif ($SVN::Core::VERSION lt '1.2.1') {\n-\t\t\tdie \"Need SVN::Core 1.2.1 or better \",\n+\t\tif ($SVN::Core::VERSION lt '1.1.0') {\n+\t\t\tdie \"Need SVN::Core 1.1.0 or better \",\n \t\t\t\t\t\"(got $SVN::Core::VERSION) \",\n \t\t\t\t\t\"Falling back to command-line svn\\n\";\n \t\t}\n@@ -2392,9 +2393,15 @@ sub libsvn_get_file {\n \tmy $pool = SVN::Pool->new;\n \tdefined($pid = open3($in, $out, '>&STDERR',\n \t\t\t\tqw/git-hash-object -w --stdin/)) or croak $!;\n-\tmy ($r, $props) = $SVN->get_file($f, $rev, $in, $pool);\n+\t# redirect STDOUT for SVN 1.1.x compatibility\n+\topen my $stdout, '>&', \\*STDOUT or croak $!;\n+\topen STDOUT, '>&', $in or croak $!;\n+\t$| = 1; # not sure if this is necessary, better safe than sorry...\n+\tmy ($r, $props) = $SVN->get_file($f, $rev, \\*STDOUT, $pool);\n \t$in->flush == 0 or croak $!;\n+\topen STDOUT, '>&', $stdout or croak $!;\n \tclose $in or croak $!;\n+\tclose $stdout or croak $!;\n \t$pool->clear;\n \tchomp($hash = do { local $/; <$out> });\n \tclose $out or croak $!;\n@@ -2566,7 +2573,8 @@ sub revisions_eq {\n \tif ($_use_lib) {\n \t\t# should be OK to use Pool here (r1 - r0) should be small\n \t\tmy $pool = SVN::Pool->new;\n-\t\t$SVN->get_log(\"/$path\", $r0, $r1, 0, 1, 1, sub {$nr++},$pool);\n+\t\tlibsvn_get_log($SVN, \"/$path\", $r0, $r1,\n+\t\t\t\t0, 1, 1, sub {$nr++}, $pool);\n \t\t$pool->clear;\n \t} else {\n \t\tmy ($url, undef) = repo_path_split($SVN_URL);\n@@ -2606,6 +2614,14 @@ sub libsvn_find_parent_branch {\n \treturn undef;\n }\n \n+sub libsvn_get_log {\n+\tmy ($ra, @args) = @_;\n+\tif ($SVN::Core::VERSION le '1.2.0') {\n+\t\tsplice(@args, 3, 1);\n+\t}\n+\t$ra->get_log(@args);\n+}\n+\n sub libsvn_new_tree {\n \tif (my $log_entry = libsvn_find_parent_branch(@_)) {\n \t\treturn $log_entry;\ndiff --git a/contrib/git-svn/t/lib-git-svn.sh b/contrib/git-svn/t/lib-git-svn.sh\nindex 2843258..d7f972a 100644\n--- a/contrib/git-svn/t/lib-git-svn.sh\n+++ b/contrib/git-svn/t/lib-git-svn.sh\n@@ -33,7 +33,13 @@ svnrepo=$PWD/svnrepo\n \n set -e\n \n-svnadmin create $svnrepo\n+if svnadmin create --help | grep fs-type >/dev/null\n+then\n+\tsvnadmin create --fs-type fsfs \"$svnrepo\"\n+else\n+\tsvnadmin create \"$svnrepo\"\n+fi\n+\n svnrepo=\"file://$svnrepo/test-git-svn\"\n \n \ndiff --git a/contrib/git-svn/t/t0000-contrib-git-svn.sh b/contrib/git-svn/t/t0000-contrib-git-svn.sh\nindex 443d518..b482bb6 100644\n--- a/contrib/git-svn/t/t0000-contrib-git-svn.sh\n+++ b/contrib/git-svn/t/t0000-contrib-git-svn.sh\n@@ -5,6 +5,16 @@ #\n \n test_description='git-svn tests'\n GIT_SVN_LC_ALL=$LC_ALL\n+\n+case \"$LC_ALL\" in\n+*.UTF-8)\n+\thave_utf8=t\n+\t;;\n+*)\n+\thave_utf8=\n+\t;;\n+esac\n+\n . ./lib-git-svn.sh\n \n mkdir import\n@@ -173,7 +183,7 @@ then\n fi\n \n \n-if test -n \"$GIT_SVN_LC_ALL\" && echo $GIT_SVN_LC_ALL | grep -q '\\.UTF-8$'\n+if test \"$have_utf8\" = t\n then\n \tname=\"commit with UTF-8 message: locale: $GIT_SVN_LC_ALL\"\n \techo '# hello' >> exec-2.sh\n@@ -203,7 +213,7 @@ fi\n \n name='check imported tree checksums expected tree checksums'\n rm -f expected\n-if test -n \"$GIT_SVN_LC_ALL\" && echo $GIT_SVN_LC_ALL | grep -q '\\.UTF-8$'\n+if test \"$have_utf8\" = t\n then\n \techo tree f735671b89a7eb30cab1d8597de35bd4271ab813 > expected\n fi\ndiff --git a/contrib/git-svn/t/t0001-contrib-git-svn-props.sh b/contrib/git-svn/t/t0001-contrib-git-svn-props.sh\nindex 54e0ed7..a5a235f 100644\n--- a/contrib/git-svn/t/t0001-contrib-git-svn-props.sh\n+++ b/contrib/git-svn/t/t0001-contrib-git-svn-props.sh\n@@ -21,8 +21,8 @@ a_empty_crlf=\n \n cd import\n \tcat >> kw.c <<\\EOF\n-/* Make it look like somebody copied a file from CVS into SVN: */\n-/* $Id: kw.c,v 1.1.1.1 1994/03/06 00:00:00 eric Exp $ */\n+/* Somebody prematurely put a keyword into this file */\n+/* $Id$ */\n EOF\n \n \tprintf \"Hello\\r\\nWorld\\r\\n\" > crlf\n-- \n1.4.1.rc1.gc7c5\n"}]}