{"thread":{"id":"43161","subject":"[PATCH 2/3] git-svn: allow dcommit to take an alternate head","startedAt":"2006-12-12T22:47:00Z","lastAt":"2006-12-13T02:26:00Z","messageCount":6,"participants":["Eric Wong","Junio C Hamano"],"isPatch":true,"patchVersion":1,"patchTotal":3},"messages":[{"id":"297762","messageId":"11659636223725-git-send-email-normalperson@yhbt.net","threadId":"43161","inReplyTo":null,"subject":"[PATCH 1/3] git-svn: enable logging of information not supported by git","fromName":"Eric Wong","fromEmail":"normalperson@yhbt.net","sentAt":"2006-12-12T22:47:00Z","receivedAt":"2006-12-12T22:47:00Z","isPatch":true,"sender":{"key":"e@80x24.org","avatar":null},"body":"The changes are now tracked in\n  $GIT_DIR/svn/$GIT_SVN_ID/untracked.log\n\nInformation in the untracked.log include:\n  * the addition and removal of empty directories\n    (changes of these will also warn the user)\n  * file and directory property changes, including (but not\n    limited to) svk:merge and svn:externals\n  * revision properties (revprops) are also tracked\n  * users will be warned of 'absent' file and directories\n    (if users are forbidden access)\n\nFields in entries are separated by spaces; \"unsafe\" characters\nare URI-encoded so that each entry takes exactly one line.\n\nThere is currently no automated parser for dealing with the data\nin untracked.log, but it should be possible to write one to\ncreate empty directories on checkout and manage\nexternals/subprojects.\n\nSigned-off-by: Eric Wong <normalperson@yhbt.net>\n---\n git-svn.perl |  202 ++++++++++++++++++++++++++++++++++++++++++++++++++++-----\n 1 files changed, 184 insertions(+), 18 deletions(-)\n\ndiff --git a/git-svn.perl b/git-svn.perl\nindex 1f8a3b0..06e89ff 100755\n--- a/git-svn.perl\n+++ b/git-svn.perl\n@@ -21,6 +21,16 @@ $ENV{TZ} = 'UTC';\n $ENV{LC_ALL} = 'C';\n $| = 1; # unbuffer STDOUT\n \n+# properties that we do not log:\n+my %SKIP = ( 'svn:wc:ra_dav:version-url' => 1,\n+             'svn:special' => 1,\n+             'svn:executable' => 1,\n+             'svn:entry:committed-rev' => 1,\n+             'svn:entry:last-author' => 1,\n+             'svn:entry:uuid' => 1,\n+             'svn:entry:committed-date' => 1,\n+);\n+\n sub fatal (@) { print STDERR $@; exit 1 }\n # If SVN:: library support is added, please make the dependencies\n # optional and preserve the capability to use the command-line client.\n@@ -2902,7 +2912,7 @@ sub libsvn_dup_ra {\n }\n \n sub libsvn_get_file {\n-\tmy ($gui, $f, $rev, $chg) = @_;\n+\tmy ($gui, $f, $rev, $chg, $untracked) = @_;\n \t$f =~ s#^/##;\n \tprint \"\\t$chg\\t$f\\n\" unless $_q;\n \n@@ -2940,11 +2950,25 @@ sub libsvn_get_file {\n \t\twaitpid $pid, 0;\n \t\t$hash =~ /^$sha1$/o or die \"not a sha1: $hash\\n\";\n \t}\n+\t%{$untracked->{file_prop}->{$f}} = %$props;\n \tprint $gui $mode,' ',$hash,\"\\t\",$f,\"\\0\" or croak $!;\n }\n \n+sub uri_encode {\n+\tmy ($f) = @_;\n+\t$f =~ s#([^a-zA-Z0-9\\*!\\:_\\./\\-])#uc sprintf(\"%%%02x\",ord($1))#eg;\n+\t$f\n+}\n+\n+sub uri_decode {\n+\tmy ($f) = @_;\n+\t$f =~ tr/+/ /;\n+\t$f =~ s/%([A-F0-9]{2})/chr hex($1)/ge;\n+\t$f\n+}\n+\n sub libsvn_log_entry {\n-\tmy ($rev, $author, $date, $msg, $parents) = @_;\n+\tmy ($rev, $author, $date, $msg, $parents, $untracked) = @_;\n \tmy ($Y,$m,$d,$H,$M,$S) = ($date =~ /^(\\d{4})\\-(\\d\\d)\\-(\\d\\d)T\n \t\t\t\t\t (\\d\\d)\\:(\\d\\d)\\:(\\d\\d).\\d+Z$/x)\n \t\t\t\tor die \"Unable to parse date: $date\\n\";\n@@ -2952,8 +2976,65 @@ sub libsvn_log_entry {\n \t\tdie \"Author: $author not defined in $_authors file\\n\";\n \t}\n \t$msg = '' if ($rev == 0 && !defined $msg);\n-\treturn { revision => $rev, date => \"+0000 $Y-$m-$d $H:$M:$S\",\n-\t\tauthor => $author, msg => $msg.\"\\n\", parents => $parents || [] }\n+\n+\topen my $un, '>>', \"$GIT_SVN_DIR/unhandled.log\" or croak $!;\n+\tmy $h;\n+\tprint $un \"r$rev\\n\" or croak $!;\n+\t$h = $untracked->{empty};\n+\tforeach (sort keys %$h) {\n+\t\tmy $act = $h->{$_} ? '+empty_dir' : '-empty_dir';\n+\t\tprint $un \"  $act: \", uri_encode($_), \"\\n\" or croak $!;\n+\t\twarn \"W: $act: $_\\n\";\n+\t}\n+\tforeach my $t (qw/dir_prop file_prop/) {\n+\t\t$h = $untracked->{$t} or next;\n+\t\tforeach my $path (sort keys %$h) {\n+\t\t\tmy $ppath = $path eq '' ? '.' : $path;\n+\t\t\tforeach my $prop (sort keys %{$h->{$path}}) {\n+\t\t\t\tnext if $SKIP{$prop};\n+\t\t\t\tmy $v = $h->{$path}->{$prop};\n+\t\t\t\tif (defined $v) {\n+\t\t\t\t\tprint $un \"  +$t: \",\n+\t\t\t\t\t\t  uri_encode($ppath), ' ',\n+\t\t\t\t\t\t  uri_encode($prop), ' ',\n+\t\t\t\t\t\t  uri_encode($v), \"\\n\"\n+\t\t\t\t\t\t  or croak $!;\n+\t\t\t\t} else {\n+\t\t\t\t\tprint $un \"  -$t: \",\n+\t\t\t\t\t\t  uri_encode($ppath), ' ',\n+\t\t\t\t\t\t  uri_encode($prop), \"\\n\"\n+\t\t\t\t\t\t  or croak $!;\n+\t\t\t\t}\n+\t\t\t}\n+\t\t}\n+\t}\n+\tforeach my $t (qw/absent_file absent_directory/) {\n+\t\t$h = $untracked->{$t} or next;\n+\t\tforeach my $parent (sort keys %$h) {\n+\t\t\tforeach my $path (sort @{$h->{$parent}}) {\n+\t\t\t\tprint $un \"  $t: \",\n+\t\t\t\t      uri_encode(\"$parent/$path\"), \"\\n\"\n+\t\t\t\t      or croak $!;\n+\t\t\t\twarn \"W: $t: $parent/$path \",\n+\t\t\t\t     \"Insufficient permissions?\\n\";\n+\t\t\t}\n+\t\t}\n+\t}\n+\n+\t# revprops (make this optional? it's an extra network trip...)\n+\tmy $pool = SVN::Pool->new;\n+\tmy $rp = $SVN->rev_proplist($rev, $pool);\n+\tforeach (sort keys %$rp) {\n+\t\tnext if /^svn:(?:author|date|log)$/;\n+\t\tprint $un \"  rev_prop: \", uri_encode($_), ' ',\n+\t\t          uri_encode($rp->{$_}), \"\\n\";\n+\t}\n+\t$pool->clear;\n+\tclose $un or croak $!;\n+\n+\t{ revision => $rev, date => \"+0000 $Y-$m-$d $H:$M:$S\",\n+\t  author => $author, msg => $msg.\"\\n\", parents => $parents || [],\n+\t  revprops => $rp }\n }\n \n sub process_rm {\n@@ -2972,9 +3053,11 @@ sub process_rm {\n \t\t}\n \t\tprint \"\\tD\\t$f/\\n\" unless $q;\n \t\tclose $ls or croak $?;\n+\t\treturn $SVN::Node::dir;\n \t} else {\n \t\tprint $gui '0 ',0 x 40,\"\\t\",$f,\"\\0\" or croak $!;\n \t\tprint \"\\tD\\t$f\\n\" unless $q;\n+\t\treturn $SVN::Node::file;\n \t}\n }\n \n@@ -2995,13 +3078,14 @@ sub libsvn_fetch_delta {\n \tunless ($ed->{git_commit_ok}) {\n \t\tdie \"SVN connection failed somewhere...\\n\";\n \t}\n-\tlibsvn_log_entry($rev, $author, $date, $msg, [$last_commit]);\n+\tlibsvn_log_entry($rev, $author, $date, $msg, [$last_commit], $ed);\n }\n \n sub libsvn_fetch_full {\n \tmy ($last_commit, $paths, $rev, $author, $date, $msg) = @_;\n \topen my $gui, '| git-update-index -z --index-info' or croak $!;\n \tmy %amr;\n+\tmy $ut = { empty => {}, dir_prop => {}, file_prop => {} };\n \tmy $p = $SVN->{svn_path};\n \tforeach my $f (keys %$paths) {\n \t\tmy $m = $paths->{$f}->action();\n@@ -3012,8 +3096,11 @@ sub libsvn_fetch_full {\n \t\t\t$f =~ s#^/##;\n \t\t}\n \t\tif ($m =~ /^[DR]$/) {\n-\t\t\tprocess_rm($gui, $last_commit, $f, $_q);\n-\t\t\tnext if $m eq 'D';\n+\t\t\tmy $t = process_rm($gui, $last_commit, $f, $_q);\n+\t\t\tif ($m eq 'D') {\n+\t\t\t\t$ut->{empty}->{$f} = 0 if $t == $SVN::Node::dir;\n+\t\t\t\tnext;\n+\t\t\t}\n \t\t\t# 'R' can be file replacements, too, right?\n \t\t}\n \t\tmy $pool = SVN::Pool->new;\n@@ -3026,18 +3113,32 @@ sub libsvn_fetch_full {\n \t\t\t}\n \t\t} elsif ($t == $SVN::Node::dir && $m =~ /^[AR]$/) {\n \t\t\tmy @traversed = ();\n-\t\t\tlibsvn_traverse($gui, '', $f, $rev, \\@traversed);\n-\t\t\tforeach (@traversed) {\n-\t\t\t\t$amr{$_} = $m;\n+\t\t\tlibsvn_traverse($gui, '', $f, $rev, \\@traversed, $ut);\n+\t\t\tif (@traversed) {\n+\t\t\t\tforeach (@traversed) {\n+\t\t\t\t\t$amr{$_} = $m;\n+\t\t\t\t}\n+\t\t\t} else {\n+\t\t\t\tmy ($dir, $file) = ($f =~ m#^(.*?)/?([^/]+)$#);\n+\t\t\t\tdelete $ut->{empty}->{$dir};\n+\t\t\t\t$ut->{empty}->{$f} = 1;\n \t\t\t}\n \t\t}\n \t\t$pool->clear;\n \t}\n \tforeach (keys %amr) {\n-\t\tlibsvn_get_file($gui, $_, $rev, $amr{$_});\n+\t\tlibsvn_get_file($gui, $_, $rev, $amr{$_}, $ut);\n+\t\tmy ($d) = ($_ =~ m#^(.*?)/?(?:[^/]+)$#);\n+\t\tdelete $ut->{empty}->{$d};\n+\t}\n+\tunless (exists $ut->{dir_prop}->{''}) {\n+\t\tmy $pool = SVN::Pool->new;\n+\t\tmy (undef, undef, $props) = $SVN->get_dir('', $rev, $pool);\n+\t\t%{$ut->{dir_prop}->{''}} = %$props;\n+\t\t$pool->clear;\n \t}\n \tclose $gui or croak $?;\n-\treturn libsvn_log_entry($rev, $author, $date, $msg, [$last_commit]);\n+\tlibsvn_log_entry($rev, $author, $date, $msg, [$last_commit], $ut);\n }\n \n sub svn_grab_base_rev {\n@@ -3098,25 +3199,38 @@ sub libsvn_parse_revision {\n }\n \n sub libsvn_traverse {\n-\tmy ($gui, $pfx, $path, $rev, $files) = @_;\n+\tmy ($gui, $pfx, $path, $rev, $files, $untracked) = @_;\n \tmy $cwd = length $pfx ? \"$pfx/$path\" : $path;\n \tmy $pool = SVN::Pool->new;\n \t$cwd =~ s#^\\Q$SVN->{svn_path}\\E##;\n+\tmy $nr = 0;\n \tmy ($dirent, $r, $props) = $SVN->get_dir($cwd, $rev, $pool);\n+\t%{$untracked->{dir_prop}->{$cwd}} = %$props;\n \tforeach my $d (keys %$dirent) {\n \t\tmy $t = $dirent->{$d}->kind;\n \t\tif ($t == $SVN::Node::dir) {\n-\t\t\tlibsvn_traverse($gui, $cwd, $d, $rev, $files);\n+\t\t\tmy $i = libsvn_traverse($gui, $cwd, $d, $rev,\n+\t\t\t                        $files, $untracked);\n+\t\t\tif ($i) {\n+\t\t\t\t$nr += $i;\n+\t\t\t} else {\n+\t\t\t\t$untracked->{empty}->{\"$cwd/$d\"} = 1;\n+\t\t\t}\n \t\t} elsif ($t == $SVN::Node::file) {\n+\t\t\t$nr++;\n \t\t\tmy $file = \"$cwd/$d\";\n \t\t\tif (defined $files) {\n \t\t\t\tpush @$files, $file;\n \t\t\t} else {\n-\t\t\t\tlibsvn_get_file($gui, $file, $rev, 'A');\n+\t\t\t\tlibsvn_get_file($gui, $file, $rev, 'A',\n+\t\t\t\t                $untracked);\n+\t\t\t\tmy ($dir) = ($file =~ m#^(.*?)/?(?:[^/]+)$#);\n+\t\t\t\tdelete $untracked->{empty}->{$dir};\n \t\t\t}\n \t\t}\n \t}\n \t$pool->clear;\n+\t$nr;\n }\n \n sub libsvn_traverse_ignore {\n@@ -3255,6 +3369,7 @@ sub libsvn_new_tree {\n \t\treturn $log_entry;\n \t}\n \tmy ($paths, $rev, $author, $date, $msg) = @_;\n+\tmy $ut;\n \tif ($_xfer_delta) {\n \t\tmy $pool = SVN::Pool->new;\n \t\tmy $ed = SVN::Git::Fetcher->new({q => $_q});\n@@ -3266,12 +3381,14 @@ sub libsvn_new_tree {\n \t\tunless ($ed->{git_commit_ok}) {\n \t\t\tdie \"SVN connection failed somewhere...\\n\";\n \t\t}\n+\t\t$ut = $ed;\n \t} else {\n+\t\t$ut = { empty => {}, dir_prop => {}, file_prop => {} };\n \t\topen my $gui, '| git-update-index -z --index-info' or croak $!;\n-\t\tlibsvn_traverse($gui, '', $SVN->{svn_path}, $rev);\n+\t\tlibsvn_traverse($gui, '', $SVN->{svn_path}, $rev, undef, $ut);\n \t\tclose $gui or croak $?;\n \t}\n-\treturn libsvn_log_entry($rev, $author, $date, $msg);\n+\tlibsvn_log_entry($rev, $author, $date, $msg, [], $ut);\n }\n \n sub find_graft_path_commit {\n@@ -3456,13 +3573,28 @@ sub new {\n \t$self->{gui} = $gui;\n \t$self->{c} = $git_svn->{c} if exists $git_svn->{c};\n \t$self->{q} = $git_svn->{q};\n+\t$self->{empty} = {};\n+\t$self->{dir_prop} = {};\n+\t$self->{file_prop} = {};\n+\t$self->{absent_dir} = {};\n+\t$self->{absent_file} = {};\n \trequire Digest::MD5;\n \t$self;\n }\n \n+sub open_root {\n+\t{ path => '' };\n+}\n+\n+sub open_directory {\n+\tmy ($self, $path, $pb, $rev) = @_;\n+\t{ path => $path };\n+}\n+\n sub delete_entry {\n \tmy ($self, $path, $rev, $pb) = @_;\n-\tprocess_rm($self->{gui}, $self->{c}, $path, $self->{q});\n+\tmy $t = process_rm($self->{gui}, $self->{c}, $path, $self->{q});\n+\t$self->{empty}->{$path} = 0 if $t == $SVN::Node::dir;\n \tundef;\n }\n \n@@ -3479,10 +3611,41 @@ sub open_file {\n \n sub add_file {\n \tmy ($self, $path, $pb, $cp_path, $cp_rev) = @_;\n+\tmy ($dir, $file) = ($path =~ m#^(.*?)/?([^/]+)$#);\n+\tdelete $self->{empty}->{$dir};\n \t{ path => $path, mode_a => 100644, mode_b => 100644,\n \t  pool => SVN::Pool->new, action => 'A' };\n }\n \n+sub add_directory {\n+\tmy ($self, $path, $cp_path, $cp_rev) = @_;\n+\tmy ($dir, $file) = ($path =~ m#^(.*?)/?([^/]+)$#);\n+\tdelete $self->{empty}->{$dir};\n+\t$self->{empty}->{$path} = 1;\n+\t{ path => $path };\n+}\n+\n+sub change_dir_prop {\n+\tmy ($self, $db, $prop, $value) = @_;\n+\t$self->{dir_prop}->{$db->{path}} ||= {};\n+\t$self->{dir_prop}->{$db->{path}}->{$prop} = $value;\n+\tundef;\n+}\n+\n+sub absent_directory {\n+\tmy ($self, $path, $pb) = @_;\n+\t$self->{absent_dir}->{$pb->{path}} ||= [];\n+\tpush @{$self->{absent_dir}->{$pb->{path}}}, $path;\n+\tundef;\n+}\n+\n+sub absent_file {\n+\tmy ($self, $path, $pb) = @_;\n+\t$self->{absent_file}->{$pb->{path}} ||= [];\n+\tpush @{$self->{absent_file}->{$pb->{path}}}, $path;\n+\tundef;\n+}\n+\n sub change_file_prop {\n \tmy ($self, $fb, $prop, $value) = @_;\n \tif ($prop eq 'svn:executable') {\n@@ -3491,6 +3654,9 @@ sub change_file_prop {\n \t\t}\n \t} elsif ($prop eq 'svn:special') {\n \t\t$fb->{mode_b} = defined $value ? 120000 : 100644;\n+\t} else {\n+\t\t$self->{file_prop}->{$fb->{path}} ||= {};\n+\t\t$self->{file_prop}->{$fb->{path}}->{$prop} = $value;\n \t}\n \tundef;\n }\n-- \n1.4.4.2.g6f98\n"},{"id":"293950","messageId":"1165963624339-git-send-email-normalperson@yhbt.net","threadId":"43161","inReplyTo":"11659636223725-git-send-email-normalperson@yhbt.net","subject":"[PATCH 2/3] git-svn: allow dcommit to take an alternate head","fromName":"Eric Wong","fromEmail":"normalperson@yhbt.net","sentAt":"2006-12-12T22:47:01Z","receivedAt":"2006-12-12T22:47:01Z","isPatch":true,"sender":{"key":"e@80x24.org","avatar":null},"body":"Previously dcommit would unconditionally commit all patches\nup-to and including the current HEAD.  Now if an optional\ncommand-line argument is specified, it will only commit\nup to the specified revision.\n\nSigned-off-by: Eric Wong <normalperson@yhbt.net>\n---\n Documentation/git-svn.txt |    6 ++++--\n git-svn.perl              |   11 ++++++-----\n 2 files changed, 10 insertions(+), 7 deletions(-)\n\ndiff --git a/Documentation/git-svn.txt b/Documentation/git-svn.txt\nindex a45067e..c589a98 100644\n--- a/Documentation/git-svn.txt\n+++ b/Documentation/git-svn.txt\n@@ -57,11 +57,13 @@ See '<<fetch-args,Additional Fetch Arguments>>' if you are interested in\n manually joining branches on commit.\n \n 'dcommit'::\n-\tCommit all diffs from the current HEAD directly to the SVN\n+\tCommit all diffs from a specified head directly to the SVN\n \trepository, and then rebase or reset (depending on whether or\n-\tnot there is a diff between SVN and HEAD).  It is recommended\n+\tnot there is a diff between SVN and head).  It is recommended\n \tthat you run git-svn fetch and rebase (not pull) your commits\n \tagainst the latest changes in the SVN repository.\n+\tAn optional command-line argument may be specified as an\n+\talternative to HEAD.\n \tThis is advantageous over 'commit' (below) because it produces\n \tcleaner, more linear history.\n \ndiff --git a/git-svn.perl b/git-svn.perl\nindex 06e89ff..819584b 100755\n--- a/git-svn.perl\n+++ b/git-svn.perl\n@@ -604,8 +604,9 @@ sub commit_lib {\n }\n \n sub dcommit {\n+\tmy $head = shift || 'HEAD';\n \tmy $gs = \"refs/remotes/$GIT_SVN\";\n-\tchomp(my @refs = safe_qx(qw/git-rev-list --no-merges/, \"$gs..HEAD\"));\n+\tchomp(my @refs = safe_qx(qw/git-rev-list --no-merges/, \"$gs..$head\"));\n \tmy $last_rev;\n \tforeach my $d (reverse @refs) {\n \t\tif (quiet_run('git-rev-parse','--verify',\"$d~1\") != 0) {\n@@ -632,16 +633,16 @@ sub dcommit {\n \t}\n \treturn if $_dry_run;\n \tfetch();\n-\tmy @diff = safe_qx(qw/git-diff-tree HEAD/, $gs);\n+\tmy @diff = safe_qx('git-diff-tree', $head, $gs);\n \tmy @finish;\n \tif (@diff) {\n \t\t@finish = qw/rebase/;\n \t\tpush @finish, qw/--merge/ if $_merge;\n \t\tpush @finish, \"--strategy=$_strategy\" if $_strategy;\n-\t\tprint STDERR \"W: HEAD and $gs differ, using @finish:\\n\", @diff;\n+\t\tprint STDERR \"W: $head and $gs differ, using @finish:\\n\", @diff;\n \t} else {\n-\t\tprint \"No changes between current HEAD and $gs\\n\",\n-\t\t      \"Hard resetting to the latest $gs\\n\";\n+\t\tprint \"No changes between current $head and $gs\\n\",\n+\t\t      \"Resetting to the latest $gs\\n\";\n \t\t@finish = qw/reset --mixed/;\n \t}\n \tsys('git', @finish, $gs);\n-- \n1.4.4.2.g6f98\n"},{"id":"298715","messageId":"11659636263755-git-send-email-normalperson@yhbt.net","threadId":"43161","inReplyTo":"11659636223725-git-send-email-normalperson@yhbt.net","subject":"[PATCH 3/3] git-svn: correctly display fatal() error messages","fromName":"Eric Wong","fromEmail":"normalperson@yhbt.net","sentAt":"2006-12-12T22:47:02Z","receivedAt":"2006-12-12T22:47:02Z","isPatch":true,"sender":{"key":"e@80x24.org","avatar":null},"body":"If I wanted to print $@, I'd pass $@ to fatal().  This looks like\na stupid typo on my part.\n\nSigned-off-by: Eric Wong <normalperson@yhbt.net>\n---\n git-svn.perl |    2 +-\n 1 files changed, 1 insertions(+), 1 deletions(-)\n\ndiff --git a/git-svn.perl b/git-svn.perl\nindex 819584b..c746a3c 100755\n--- a/git-svn.perl\n+++ b/git-svn.perl\n@@ -31,7 +31,7 @@ my %SKIP = ( 'svn:wc:ra_dav:version-url' => 1,\n              'svn:entry:committed-date' => 1,\n );\n \n-sub fatal (@) { print STDERR $@; exit 1 }\n+sub fatal (@) { print STDERR @_; exit 1 }\n # If SVN:: library support is added, please make the dependencies\n # optional and preserve the capability to use the command-line client.\n # use eval { require SVN::... } to make it lazy load\n-- \n1.4.4.2.g6f98\n"},{"id":"296689","messageId":"20061213004500.GA17811@localdomain","threadId":"43161","inReplyTo":"11659636263755-git-send-email-normalperson@yhbt.net","subject":"[PATCH 4/3] git-svn: correctly handle packed-refs in refs/remotes/","fromName":"Eric Wong","fromEmail":"normalperson@yhbt.net","sentAt":"2006-12-13T00:45:00Z","receivedAt":"2006-12-13T00:45:00Z","isPatch":true,"sender":{"key":"e@80x24.org","avatar":null},"body":"We now use git-rev-parse universally to read refs, instead\nof our own file_to_s function (which I plan on removing).\n\nSigned-off-by: Eric Wong <normalperson@yhbt.net>\n---\n git-svn.perl |   10 +++++++++-\n 1 files changed, 9 insertions(+), 1 deletions(-)\n\ndiff --git a/git-svn.perl b/git-svn.perl\nindex 1f8a3b0..aac8f73 100755\n--- a/git-svn.perl\n+++ b/git-svn.perl\n@@ -2016,9 +2016,17 @@ sub git_commit {\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+\topen my $null, '>', '/dev/null' or croak $!;\n+\topen my $stderr, '>&', \\*STDERR or croak $!;\n+\topen STDERR, '>&', $null or croak $!;\n+\tif (my $cur = eval { safe_qx('git-rev-parse',\n+\t                             \"refs/remotes/$GIT_SVN^0\") }) {\n+\t\tchomp $cur;\n \t\tpush @tmp_parents, $cur;\n \t}\n+\topen STDERR, '>&', $stderr or croak $!;\n+\tclose $stderr or croak $!;\n+\tclose $null or croak $!;\n \n \tif (exists $tree_map{$tree}) {\n \t\tforeach my $p (@{$tree_map{$tree}}) {\n-- \n1.4.4.2.g6f98\n"},{"id":"297389","messageId":"7vlklcmvoo.fsf@assigned-by-dhcp.cox.net","threadId":"43161","inReplyTo":"20061213004500.GA17811@localdomain","subject":"Re: [PATCH 4/3] git-svn: correctly handle packed-refs in refs/remotes/","fromName":"Junio C Hamano","fromEmail":"junkio@cox.net","sentAt":"2006-12-13T01:27:51Z","receivedAt":"2006-12-13T01:27:51Z","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> We now use git-rev-parse universally to read refs, instead\n> of our own file_to_s function (which I plan on removing).\n>\n> Signed-off-by: Eric Wong <normalperson@yhbt.net>\n> ---\n>  git-svn.perl |   10 +++++++++-\n>  1 files changed, 9 insertions(+), 1 deletions(-)\n>\n> diff --git a/git-svn.perl b/git-svn.perl\n> index 1f8a3b0..aac8f73 100755\n> --- a/git-svn.perl\n> +++ b/git-svn.perl\n> @@ -2016,9 +2016,17 @@ sub git_commit {\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> +\topen my $null, '>', '/dev/null' or croak $!;\n> +\topen my $stderr, '>&', \\*STDERR or croak $!;\n> +\topen STDERR, '>&', $null or croak $!;\n> +\tif (my $cur = eval { safe_qx('git-rev-parse',\n> +\t                             \"refs/remotes/$GIT_SVN^0\") }) {\n> +\t\tchomp $cur;\n>  \t\tpush @tmp_parents, $cur;\n>  \t}\n> +\topen STDERR, '>&', $stderr or croak $!;\n> +\tclose $stderr or croak $!;\n> +\tclose $null or croak $!;\n>  \n>  \tif (exists $tree_map{$tree}) {\n>  \t\tforeach my $p (@{$tree_map{$tree}}) {\n\nIt's a neat trick you do to stash away STDERR and redirect to\n/dev/null ;-).  It might be worth doing something like this:\n\n\tsub without_stderr {\n        \tmy ($cmd, @param) = @_;\n                # stash away magic\n                my @return = eval {\n                \tsafe_qx($cmd, @param);\n                };\n                # restore magic\n                return @return;\n\t}\n\nin Git.pm?\n\nThen the caller would do something like this instead:\n\n\tsub git_commit {\n        \t...\n\t\tif (my ($cur) = without_stderr(qw(git rev-parse --verify),\n\t\t\t\"refs/remotes/$GIT_SVN^0\")) {\n                \t...\n\n"},{"id":"294761","messageId":"20061213022600.GB18036@localdomain","threadId":"43161","inReplyTo":"7vlklcmvoo.fsf@assigned-by-dhcp.cox.net","subject":"Re: [PATCH 4/3] git-svn: correctly handle packed-refs in refs/remotes/","fromName":"Eric Wong","fromEmail":"normalperson@yhbt.net","sentAt":"2006-12-13T02:26:00Z","receivedAt":"2006-12-13T02:26:00Z","isPatch":true,"sender":{"key":"e@80x24.org","avatar":null},"body":"Junio C Hamano <junkio@cox.net> wrote:\n> Eric Wong <normalperson@yhbt.net> writes:\n> \n> > We now use git-rev-parse universally to read refs, instead\n> > of our own file_to_s function (which I plan on removing).\n> >\n> > Signed-off-by: Eric Wong <normalperson@yhbt.net>\n> > ---\n> >  git-svn.perl |   10 +++++++++-\n> >  1 files changed, 9 insertions(+), 1 deletions(-)\n> >\n> > diff --git a/git-svn.perl b/git-svn.perl\n> > index 1f8a3b0..aac8f73 100755\n> > --- a/git-svn.perl\n> > +++ b/git-svn.perl\n> > @@ -2016,9 +2016,17 @@ sub git_commit {\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> > +\topen my $null, '>', '/dev/null' or croak $!;\n> > +\topen my $stderr, '>&', \\*STDERR or croak $!;\n> > +\topen STDERR, '>&', $null or croak $!;\n> > +\tif (my $cur = eval { safe_qx('git-rev-parse',\n> > +\t                             \"refs/remotes/$GIT_SVN^0\") }) {\n> > +\t\tchomp $cur;\n> >  \t\tpush @tmp_parents, $cur;\n> >  \t}\n> > +\topen STDERR, '>&', $stderr or croak $!;\n> > +\tclose $stderr or croak $!;\n> > +\tclose $null or croak $!;\n> >  \n> >  \tif (exists $tree_map{$tree}) {\n> >  \t\tforeach my $p (@{$tree_map{$tree}}) {\n> \n> It's a neat trick you do to stash away STDERR and redirect to\n> /dev/null ;-).  It might be worth doing something like this:\n\nI also did it for libsvn_get_file() with STDOUT :)\n\n> \tsub without_stderr {\n>         \tmy ($cmd, @param) = @_;\n>                 # stash away magic\n>                 my @return = eval {\n>                 \tsafe_qx($cmd, @param);\n>                 };\n>                 # restore magic\n>                 return @return;\n> \t}\n> \n> in Git.pm?\n\nLooking at Git.pm for the first time, it seems that _command_common_pipe\n(and all it's users) already support closing/redirecting STDERR.\n\nI'll look into revamping git-svn to use Git.pm sometime tonight or\ntomorrow.\n\n-- \n"}]}