{"thread":{"id":"4524","subject":"[PATCH 3/3] git-svn: Eliminate temp file usage in libsvn_get_file()","startedAt":"2006-06-15T20:55:29Z","lastAt":"2006-06-16T17:57:26Z","messageCount":8,"participants":["Eric Wong"],"isPatch":true,"patchVersion":1,"patchTotal":3},"messages":[{"id":"21851","messageId":"11504049313192-git-send-email-normalperson@yhbt.net","threadId":"4524","inReplyTo":null,"subject":"[PATCH 1/3] git-svn: avoid creating some small files","fromName":"Eric Wong","fromEmail":"normalperson@yhbt.net","sentAt":"2006-06-15T20:55:29Z","receivedAt":"2006-06-15T20:55:29Z","isPatch":true,"sender":{"key":"e@80x24.org","avatar":null},"body":"repo_path_split() is already pretty fast, and is already\noptimized via caching.\n\nWe also don't need to create an exclude file if we're\nrelying on the SVN libraries.\n\nSigned-off-by: Eric Wong <normalperson@yhbt.net>\n---\n contrib/git-svn/git-svn.perl |   26 ++++++++------------------\n 1 files changed, 8 insertions(+), 18 deletions(-)\n\ndiff --git a/contrib/git-svn/git-svn.perl b/contrib/git-svn/git-svn.perl\nindex 884969e..88af9c5 100755\n--- a/contrib/git-svn/git-svn.perl\n+++ b/contrib/git-svn/git-svn.perl\n@@ -1005,12 +1005,6 @@ sub setup_git_svn {\n \tclose $fh;\n \ts_to_file($SVN_URL,\"$GIT_SVN_DIR/info/url\");\n \n-\topen my $fd, '>>', \"$GIT_SVN_DIR/info/exclude\" or croak $!;\n-\tprint $fd '.svn',\"\\n\";\n-\tclose $fd or croak $!;\n-\tmy ($url, $path) = repo_path_split($SVN_URL);\n-\ts_to_file($url, \"$GIT_SVN_DIR/info/repo_url\");\n-\ts_to_file($path, \"$GIT_SVN_DIR/info/repo_path\");\n }\n \n sub assert_svn_wc_clean {\n@@ -1649,6 +1643,12 @@ sub do_update_index {\n \n sub index_changes {\n \treturn if $_use_lib;\n+\n+\tif (!-f \"$GIT_SVN_DIR/info/exclude\") {\n+\t\topen my $fd, '>>', \"$GIT_SVN_DIR/info/exclude\" or croak $!;\n+\t\tprint $fd '.svn',\"\\n\";\n+\t\tclose $fd or croak $!;\n+\t}\n \tmy $no_text_base = shift;\n \tdo_update_index([qw/git-diff-files --name-only -z/],\n \t\t\t'remove',\n@@ -2018,9 +2018,6 @@ sub migration_check {\n \t\tmy $dn = dirname(\"$GIT_DIR/svn/$x\");\n \t\tmkpath([$dn]) unless -d $dn;\n \t\trename \"$GIT_DIR/$x\", \"$GIT_DIR/svn/$x\" or croak \"$!: $x\";\n-\t\tmy ($url, $path) = repo_path_split($u);\n-\t\ts_to_file($url, \"$GIT_DIR/svn/$x/info/repo_url\");\n-\t\ts_to_file($path, \"$GIT_DIR/svn/$x/info/repo_path\");\n \t}\n \tmigrate_revdb() if (-d $GIT_SVN_DIR && !-w $REVDB);\n \tprint \"Done upgrading.\\n\";\n@@ -2138,15 +2135,8 @@ sub write_grafts {\n sub read_url_paths {\n \tmy $l_map = {};\n \tgit_svn_each(sub { my $x = shift;\n-\t\t\tmy $u = file_to_s(\"$GIT_DIR/svn/$x/info/repo_url\");\n-\t\t\tmy $p = file_to_s(\"$GIT_DIR/svn/$x/info/repo_path\");\n-\t\t\t# we hate trailing slashes\n-\t\t\tif ($u =~ s#(?:^\\/+|\\/+$)##g) {\n-\t\t\t\ts_to_file($u,\"$GIT_DIR/svn/$x/info/repo_url\");\n-\t\t\t}\n-\t\t\tif ($p =~ s#(?:^\\/+|\\/+$)##g) {\n-\t\t\t\ts_to_file($p,\"$GIT_DIR/svn/$x/info/repo_path\");\n-\t\t\t}\n+\t\t\tmy $url = file_to_s(\"$GIT_DIR/svn/$x/info/url\");\n+\t\t\tmy ($u, $p) = repo_path_split($url);\n \t\t\t$l_map->{$u}->{$p} = $x;\n \t\t\t});\n \treturn $l_map;\n-- \n1.4.0\n"},{"id":"21850","messageId":"11504049322660-git-send-email-normalperson@yhbt.net","threadId":"4524","inReplyTo":"11504049313192-git-send-email-normalperson@yhbt.net","subject":"[PATCH 2/3] git-svn: fix several small bugs, enable branch optimization","fromName":"Eric Wong","fromEmail":"normalperson@yhbt.net","sentAt":"2006-06-15T20:55:30Z","receivedAt":"2006-06-15T20:55:30Z","isPatch":true,"sender":{"key":"e@80x24.org","avatar":null},"body":"Share the repack counter between branches when doing\nmulti-fetch.\n\nPass the -d flag to git repack by default.  That's the\nmain reason we will want automatic pack generation, to\nsave space and improve disk cache performance.  I won't\nadd -a by default since it can generate extremely large\npacks that make RAM-starved systems unhappy.\n\nWe no longer generate the .git/svn/$GIT_SVN_ID/info/uuid\nfile, either.  It was never read in the first place.\n\nCheck for and create .rev_db if we need to during fetch (in case\nsomebody manually blew away their .rev_db and wanted to start\nover.  Mainly makes debugging easier).\n\nCroak with $? instead of $! if there's an error closing pipes\n\nQuiet down some of the chatter, too.\n\nSigned-off-by: Eric Wong <normalperson@yhbt.net>\n---\n contrib/git-svn/git-svn.perl |  146 +++++++++++++++++++++++-------------------\n 1 files changed, 81 insertions(+), 65 deletions(-)\n\ndiff --git a/contrib/git-svn/git-svn.perl b/contrib/git-svn/git-svn.perl\nindex 88af9c5..27f1d68 100755\n--- a/contrib/git-svn/git-svn.perl\n+++ b/contrib/git-svn/git-svn.perl\n@@ -368,7 +368,6 @@ sub fetch_lib {\n \t\tdefined(my $pid = fork) or croak $!;\n \t\tif (!$pid) {\n \t\t\t$SVN::Error::handler = \\&libsvn_skip_unknown_revs;\n-\t\t\tprint \"Fetching revisions $min .. $max\\n\";\n \n \t\t\t# Yes I'm perfectly aware that the fourth argument\n \t\t\t# below is the limit revisions number.  Unfortunately\n@@ -391,7 +390,6 @@ sub fetch_lib {\n \t\t\t\t\t\t\t$log_msg, @parents);\n \t\t\t\t\t}\n \t\t\t\t});\n-\t\t\t$SVN::Error::handler = sub { 'quiet warnings' };\n \t\t\texit 0;\n \t\t}\n \t\twaitpid $pid, 0;\n@@ -463,7 +461,7 @@ sub commit_lib {\n \tmy (@revs) = @_;\n \tmy ($r_last, $cmt_last) = svn_grab_base_rev();\n \tdefined $r_last or die \"Must have an existing revision to commit\\n\";\n-\tmy $fetched = fetch_lib();\n+\tmy $fetched = fetch();\n \tif ($r_last != $fetched->{revision}) {\n \t\tprint STDERR \"There are new revisions that were fetched \",\n \t\t\t\t\"and need to be merged (or acknowledged) \",\n@@ -523,7 +521,7 @@ sub commit_lib {\n \t\t\t\t$no = 1;\n \t\t\t}\n \t\t}\n-\t\tclose $fh or croak $!;\n+\t\tclose $fh or croak $?;\n \t\tif (! defined $r_new && ! defined $cmt_new) {\n \t\t\tunless ($no) {\n \t\t\t\tdie \"Failed to parse revision information\\n\";\n@@ -633,17 +631,8 @@ sub multi_init {\n sub multi_fetch {\n \t# try to do trunk first, since branches/tags\n \t# may be descended from it.\n-\tif (-d \"$GIT_DIR/svn/trunk\") {\n-\t\tprint \"Fetching trunk\\n\";\n-\t\tdefined(my $pid = fork) or croak $!;\n-\t\tif (!$pid) {\n-\t\t\t$GIT_SVN = $ENV{GIT_SVN_ID} = 'trunk';\n-\t\t\tinit_vars();\n-\t\t\tfetch(@_);\n-\t\t\texit 0;\n-\t\t}\n-\t\twaitpid $pid, 0;\n-\t\tcroak $? if $?;\n+\tif (-e \"$GIT_DIR/svn/trunk/info/url\") {\n+\t\tfetch_child_id('trunk', @_);\n \t}\n \trec_fetch('', \"$GIT_DIR/svn\", @_);\n }\n@@ -725,6 +714,41 @@ out:\n \n ########################### utility functions #########################\n \n+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+\tif (!$pid) {\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}\n+\tclose $fh;\n+}\n+\n sub rec_fetch {\n \tmy ($pfx, $p, @args) = @_;\n \tmy @dir;\n@@ -733,16 +757,7 @@ sub rec_fetch {\n \t\t\t$pfx .= '/' if $pfx && $pfx !~ m!/$!;\n \t\t\tmy $id = $pfx . basename $_;\n \t\t\tnext if $id eq 'trunk';\n-\t\t\tprint \"Fetching $id\\n\";\n-\t\t\tdefined(my $pid = fork) or croak $!;\n-\t\t\tif (!$pid) {\n-\t\t\t\t$GIT_SVN = $ENV{GIT_SVN_ID} = $id;\n-\t\t\t\tinit_vars();\n-\t\t\t\tfetch(@args);\n-\t\t\t\texit 0;\n-\t\t\t}\n-\t\t\twaitpid $pid, 0;\n-\t\t\tcroak $? if $?;\n+\t\t\tfetch_child_id($id, @args);\n \t\t} elsif (-d $_) {\n \t\t\tpush @dir, $_;\n \t\t}\n@@ -943,7 +958,6 @@ sub read_uuid {\n \t\t$SVN_UUID = $info->{'Repository UUID'} or\n \t\t\t\t\tcroak \"Repository UUID unreadable\\n\";\n \t}\n-\ts_to_file($SVN_UUID,\"$GIT_SVN_DIR/info/uuid\");\n }\n \n sub quiet_run {\n@@ -1107,7 +1121,7 @@ sub parse_diff_tree {\n \t\t\tcroak \"Error parsing $_\\n\";\n \t\t}\n \t}\n-\tclose $diff_fh or croak $!;\n+\tclose $diff_fh or croak $?;\n \n \treturn \\@mods;\n }\n@@ -1348,7 +1362,7 @@ sub get_commit_message {\n \t\t\t\tprint $msg $_ or croak $!;\n \t\t\t}\n \t\t}\n-\t\tclose $msg_fh or croak $!;\n+\t\tclose $msg_fh or croak $?;\n \t}\n \tclose $msg or croak $!;\n \n@@ -1562,7 +1576,7 @@ sub svn_info {\n \t\t\tpush @{$ret->{-order}}, $1;\n \t\t}\n \t}\n-\tclose $info_fh or croak $!;\n+\tclose $info_fh or croak $?;\n \treturn $ret;\n }\n \n@@ -1638,7 +1652,7 @@ sub do_update_index {\n \t\t}\n \t\tprint $ui $x,\"\\0\";\n \t}\n-\tclose $ui or croak $!;\n+\tclose $ui or croak $?;\n }\n \n sub index_changes {\n@@ -1765,11 +1779,15 @@ sub git_commit {\n \n \t# this output is read via pipe, do not change:\n \tprint \"r$log_msg->{revision} = $commit\\n\";\n+\tcheck_repack();\n+\treturn $commit;\n+}\n+\n+sub check_repack {\n \tif ($_repack && (--$_repack_nr == 0)) {\n \t\t$_repack_nr = $_repack;\n \t\tsys(\"git repack $_repack_flags\");\n \t}\n-\treturn $commit;\n }\n \n sub set_commit_env {\n@@ -1877,6 +1895,10 @@ sub svn_cmd_checkout {\n }\n \n sub check_upgrade_needed {\n+\tif (!-r $REVDB) {\n+\t\topen my $fh, '>>',$REVDB or croak $!;\n+\t\tclose $fh;\n+\t}\n \tmy $old = eval {\n \t\tmy $pid = open my $child, '-|';\n \t\tdefined $pid or croak $!;\n@@ -2026,7 +2048,8 @@ sub migration_check {\n sub find_rev_before {\n \tmy ($r, $id, $eq_ok) = @_;\n \tmy $f = \"$GIT_DIR/svn/$id/.rev_db\";\n-\t# --$r unless $eq_ok;\n+\treturn (undef,undef) unless -r $f;\n+\t--$r unless $eq_ok;\n \twhile ($r > 0) {\n \t\tif (my $c = revdb_get($f, $r)) {\n \t\t\treturn ($r, $c);\n@@ -2072,7 +2095,7 @@ sub set_default_vals {\n \tif (defined $_repack) {\n \t\t$_repack = 1000 if ($_repack <= 0);\n \t\t$_repack_nr = $_repack;\n-\t\t$_repack_flags ||= '';\n+\t\t$_repack_flags ||= '-d';\n \t}\n }\n \n@@ -2352,7 +2375,7 @@ sub libsvn_get_file {\n \tclose $ho or croak $?;\n \t$hash =~ /^$sha1$/o or die \"not a sha1: $hash\\n\";\n \tprint $gui $mode,' ',$hash,\"\\t\",$p,\"\\0\" or croak $!;\n-\tclose $fd or croak $!;\n+\tclose $fd or croak $?;\n }\n \n sub libsvn_log_entry {\n@@ -2381,7 +2404,7 @@ sub process_rm {\n \t\twhile (<$ls>) {\n \t\t\tprint $gui '0 ',0 x 40,\"\\t\",$_ or croak $!;\n \t\t}\n-\t\tclose $ls or croak $!;\n+\t\tclose $ls or croak $?;\n \t} else {\n \t\tprint $gui '0 ',0 x 40,\"\\t\",$f,\"\\0\" or croak $!;\n \t}\n@@ -2411,7 +2434,7 @@ sub libsvn_fetch {\n \t\t$pool->clear;\n \t}\n \tlibsvn_get_file($gui, $_, $rev) foreach (@amr);\n-\tclose $gui or croak $!;\n+\tclose $gui or croak $?;\n \treturn libsvn_log_entry($rev, $author, $date, $msg, [$last_commit]);\n }\n \n@@ -2514,36 +2537,30 @@ sub revisions_eq {\n }\n \n sub libsvn_find_parent_branch {\n-\treturn undef; # XXX this function is disabled atm (not tested enough)\n \tmy ($paths, $rev, $author, $date, $msg) = @_;\n \tmy $svn_path = '/'.$SVN_PATH;\n \n \t# look for a parent from another branch:\n-\tforeach (keys %$paths) {\n-\t\tnext if ($_ ne $svn_path);\n-\t\tmy $i = $paths->{$_};\n-\t\tmy $branch_from = $i->copyfrom_path or next;\n-\t\tmy $r = $i->copyfrom_rev;\n-\t\tprint STDERR  \"Found possible branch point: \",\n-\t\t\t\t\t\"$branch_from => $svn_path, $r\\n\";\n-\t\t$branch_from =~ s#^/##;\n-\t\tmy $l_map = read_url_paths();\n-\t\tmy $url = $SVN->{url};\n-\t\tdefined $l_map->{$url} or next;\n-\t\tmy $id  = $l_map->{$url}->{$branch_from} or next;\n-\t\tmy ($r0, $parent) = find_rev_before($r,$id,1);\n-\t\tif (defined $r0 && defined $parent &&\n-\t\t\t\t\trevisions_eq($branch_from, $r0, $r)) {\n-\t\t\tunlink $GIT_SVN_INDEX;\n-\t\t\tprint STDERR \"Found branch parent: $parent\\n\";\n-\t\t\tsys(qw/git-read-tree/, $parent);\n-\t\t\treturn libsvn_fetch($parent, $paths, $rev,\n-\t\t\t\t\t\t$author, $date, $msg);\n-\t\t} else {\n-\t\t\tprint STDERR\n-\t\t\t\t\"Nope, branch point not imported or unknown\\n\";\n-\t\t}\n-\t}\n+\tmy $i = $paths->{$svn_path} or return;\n+\tmy $branch_from = $i->copyfrom_path or return;\n+\tmy $r = $i->copyfrom_rev;\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 $url = $SVN->{url};\n+\tdefined $l_map->{$url} or return;\n+\tmy $id = $l_map->{$url}->{$branch_from} or return;\n+\tmy ($r0, $parent) = find_rev_before($r,$id,1);\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\tsys(qw/git-read-tree/, $parent);\n+\t\treturn libsvn_fetch($parent, $paths, $rev,\n+\t\t\t\t\t$author, $date, $msg);\n+\t}\n+\tprint STDERR \"Nope, branch point not imported or unknown\\n\";\n \treturn undef;\n }\n \n@@ -2556,7 +2573,7 @@ sub libsvn_new_tree {\n \tmy $pool = SVN::Pool->new;\n \tlibsvn_traverse($gui, '', $SVN_PATH, $rev, $pool);\n \t$pool->clear;\n-\tclose $gui or croak $!;\n+\tclose $gui or croak $?;\n \treturn libsvn_log_entry($rev, $author, $date, $msg);\n }\n \n@@ -2630,7 +2647,7 @@ sub libsvn_commit_cb {\n \t\t\texit 1;\n \t\t}\n \t} else {\n-\t\tfetch_lib(\"$rev=$c\");\n+\t\tfetch(\"$rev=$c\");\n \t}\n }\n \n@@ -2664,7 +2681,6 @@ sub libsvn_skip_unknown_revs {\n \t# 175002 - http(s)://\n \t#   More codes may be discovered later...\n \tif ($errno == 175002 || $errno == 160013) {\n-\t\tprint STDERR \"directory non-existent\\n\";\n \t\treturn;\n \t}\n \tcroak \"Error from SVN, ($errno): \", $err->expanded_message,\"\\n\";\n-- \n1.4.0\n"},{"id":"21849","messageId":"11504049343825-git-send-email-normalperson@yhbt.net","threadId":"4524","inReplyTo":"11504049322660-git-send-email-normalperson@yhbt.net","subject":"[PATCH 3/3] git-svn: Eliminate temp file usage in libsvn_get_file()","fromName":"Eric Wong","fromEmail":"normalperson@yhbt.net","sentAt":"2006-06-15T20:55:31Z","receivedAt":"2006-06-15T20:55:31Z","isPatch":true,"sender":{"key":"e@80x24.org","avatar":null},"body":"This means we'll have a loose object when we encounter a symlink\nbut that's not the common case.\n\nWe also don't have to worry about svn:eol-style when using the\nSVN libraries, either.  So remove the code to deal with that.\n\nSigned-off-by: Eric Wong <normalperson@yhbt.net>\n---\n contrib/git-svn/git-svn.perl |   56 +++++++++++++++++-------------------------\n 1 files changed, 23 insertions(+), 33 deletions(-)\n\ndiff --git a/contrib/git-svn/git-svn.perl b/contrib/git-svn/git-svn.perl\nindex 27f1d68..149149f 100755\n--- a/contrib/git-svn/git-svn.perl\n+++ b/contrib/git-svn/git-svn.perl\n@@ -31,6 +31,7 @@ use File::Path qw/mkpath/;\n use Getopt::Long qw/:config gnu_getopt no_ignore_case auto_abbrev pass_through/;\n use File::Spec qw//;\n use POSIX qw/strftime/;\n+use IPC::Open3;\n use Memoize;\n memoize('revisions_eq');\n \n@@ -2335,47 +2336,36 @@ sub libsvn_get_file {\n \tmy $p = $f;\n \treturn unless ($p =~ s#^\\Q$SVN_PATH\\E/?##);\n \n-\tmy $fd = IO::File->new_tmpfile or croak $!;\n+\tmy ($hash, $pid, $in, $out);\n \tmy $pool = SVN::Pool->new;\n-\tmy ($r, $props) = $SVN->get_file($f, $rev, $fd, $pool);\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$in->flush == 0 or croak $!;\n+\tclose $in or croak $!;\n \t$pool->clear;\n-\t$fd->flush == 0 or croak $!;\n-\tseek $fd, 0, 0 or croak $!;\n-\tif (my $es = $props->{'svn:eol-style'}) {\n-\t\tmy $new_fd = IO::File->new_tmpfile or croak $!;\n-\t\teol_cp_fd($fd, $new_fd, $es);\n-\t\tclose $fd or croak $!;\n-\t\t$fd = $new_fd;\n-\t\tseek $fd, 0, 0 or croak $!;\n-\t\t$fd->flush == 0 or croak $!;\n-\t}\n-\tmy $mode = '100644';\n-\tif (exists $props->{'svn:executable'}) {\n-\t\t$mode = '100755';\n-\t}\n+\tchomp($hash = do { local $/; <$out> });\n+\tclose $out or croak $!;\n+\twaitpid $pid, 0;\n+\t$hash =~ /^$sha1$/o or die \"not a sha1: $hash\\n\";\n+\n+\tmy $mode = exists $props->{'svn:executable'} ? '100755' : '100644';\n \tif (exists $props->{'svn:special'}) {\n \t\t$mode = '120000';\n-\t\tlocal $/;\n-\t\tmy $link = <$fd>;\n+\t\tmy $link = `git-cat-file blob $hash`;\n \t\t$link =~ s/^link // or die \"svn:special file with contents: <\",\n \t\t\t\t\t\t$link, \"> is not understood\\n\";\n-\t\tseek $fd, 0, 0 or croak $!;\n-\t\ttruncate $fd, 0 or croak $!;\n-\t\tprint $fd $link or croak $!;\n-\t\tseek $fd, 0, 0 or croak $!;\n-\t\t$fd->flush == 0 or croak $!;\n-\t}\n-\tmy $pid = open my $ho, '-|';\n-\tdefined $pid or croak $!;\n-\tif (!$pid) {\n-\t\topen STDIN, '<&', $fd or croak $!;\n-\t\texec qw/git-hash-object -w --stdin/ or croak $!;\n+\t\tdefined($pid = open3($in, $out, '>&STDERR',\n+\t\t\t\tqw/git-hash-object -w --stdin/)) or croak $!;\n+\t\tprint $in $link;\n+\t\t$in->flush == 0 or croak $!;\n+\t\tclose $in or croak $!;\n+\t\tchomp($hash = do { local $/; <$out> });\n+\t\tclose $out or croak $!;\n+\t\twaitpid $pid, 0;\n+\t\t$hash =~ /^$sha1$/o or die \"not a sha1: $hash\\n\";\n \t}\n-\tchomp(my $hash = do { local $/; <$ho> });\n-\tclose $ho or croak $?;\n-\t$hash =~ /^$sha1$/o or die \"not a sha1: $hash\\n\";\n \tprint $gui $mode,' ',$hash,\"\\t\",$p,\"\\0\" or croak $!;\n-\tclose $fd or croak $?;\n }\n \n sub libsvn_log_entry {\n-- \n1.4.0\n"},{"id":"21894","messageId":"11504806463470-git-send-email-normalperson@yhbt.net","threadId":"4524","inReplyTo":"11504049343825-git-send-email-normalperson@yhbt.net","subject":"[PATCH 0/4] git-svn: more improvements","fromName":"Eric Wong","fromEmail":"normalperson@yhbt.net","sentAt":"2006-06-16T17:57:22Z","receivedAt":"2006-06-16T17:57:22Z","isPatch":true,"sender":{"key":"e@80x24.org","avatar":null},"body":"Another round of patches to git-svn, all depending on previous patches.\n\nI've also setup a pullable repo here for all my latest git-svn stuff:\n\tgit://git.bogomips.org/git-svn.git\n\t(http:// also works)\n\n-- \nEric Wong\n"},{"id":"21893","messageId":"11504806472857-git-send-email-normalperson@yhbt.net","threadId":"4524","inReplyTo":"11504806463470-git-send-email-normalperson@yhbt.net","subject":"[PATCH 1/4] git-svn: bugfix and optimize the 'log' command","fromName":"Eric Wong","fromEmail":"normalperson@yhbt.net","sentAt":"2006-06-16T17:57:23Z","receivedAt":"2006-06-16T17:57:23Z","isPatch":true,"sender":{"key":"e@80x24.org","avatar":null},"body":"Revisions with long commit messages were being skipped, since\nthe 'git-svn-id' metadata line was at the end and git-log uses a\n32k buffer to print the commits.\n\nAlso the last 'git-svn-id' metadata line in a commit is always\nthe valid one, so make sure we use that, as well.\n\nMade the verbose flag work by passing the correct option switch\n('--summary') to git-log.\n\nFinally, optimize -r/--revision argument handling by passing\nthe appropriate limits to revision\n\nSigned-off-by: Eric Wong <normalperson@yhbt.net>\n---\n contrib/git-svn/git-svn.perl |   60 ++++++++++++++++++++++++++++++++++++------\n 1 files changed, 52 insertions(+), 8 deletions(-)\n\ndiff --git a/contrib/git-svn/git-svn.perl b/contrib/git-svn/git-svn.perl\nindex 149149f..417fcf1 100755\n--- a/contrib/git-svn/git-svn.perl\n+++ b/contrib/git-svn/git-svn.perl\n@@ -663,17 +663,15 @@ sub show_log {\n \tmy $pid = open(my $log,'-|');\n \tdefined $pid or croak $!;\n \tif (!$pid) {\n-\t\tmy @rl = (qw/git-log --abbrev-commit --pretty=raw\n-\t\t\t\t--default/, \"remotes/$GIT_SVN\");\n-\t\tpush @rl, '--raw' if $_verbose;\n-\t\texec(@rl, @args) or croak $!;\n+\t\texec(git_svn_log_cmd($r_min,$r_max), @args) or croak $!;\n \t}\n \tsetup_pager();\n \tmy (@k, $c, $d);\n+\n \twhile (<$log>) {\n \t\tif (/^commit ($sha1_short)/o) {\n \t\t\tmy $cmt = $1;\n-\t\t\tif ($c && defined $c->{r} && $c->{r} != $r_last) {\n+\t\t\tif ($c && cmt_showable($c) && $c->{r} != $r_last) {\n \t\t\t\t$r_last = $c->{r};\n \t\t\t\tprocess_commit($c, $r_min, $r_max, \\@k) or\n \t\t\t\t\t\t\t\tgoto out;\n@@ -692,8 +690,7 @@ sub show_log {\n \t\t} elsif ($d) {\n \t\t\tpush @{$c->{diff}}, $_;\n \t\t} elsif (/^    (git-svn-id:.+)$/) {\n-\t\t\tmy ($url, $rev, $uuid) = extract_metadata($1);\n-\t\t\t$c->{r} = $rev;\n+\t\t\t(undef, $c->{r}, undef) = extract_metadata($1);\n \t\t} elsif (s/^    //) {\n \t\t\tpush @{$c->{l}}, $_;\n \t\t}\n@@ -715,6 +712,52 @@ out:\n \n ########################### utility functions #########################\n \n+sub cmt_showable {\n+\tmy ($c) = @_;\n+\treturn 1 if defined $c->{r};\n+\tif ($c->{l} && $c->{l}->[-1] eq \"...\\n\" &&\n+\t\t\t\t$c->{a_raw} =~ /\\@([a-f\\d\\-]+)>$/) {\n+\t\tmy @msg = safe_qx(qw/git-cat-file commit/, $c->{c});\n+\t\tshift @msg while ($msg[0] ne \"\\n\");\n+\t\tshift @msg;\n+\t\t@{$c->{l}} = grep !/^git-svn-id: /, @msg;\n+\n+\t\t(undef, $c->{r}, undef) = extract_metadata(\n+\t\t\t\t(grep(/^git-svn-id: /, @msg))[-1]);\n+\t}\n+\treturn defined $c->{r};\n+}\n+\n+sub git_svn_log_cmd {\n+\tmy ($r_min, $r_max) = @_;\n+\tmy @cmd = (qw/git-log --abbrev-commit --pretty=raw\n+\t\t\t--default/, \"refs/remotes/$GIT_SVN\");\n+\tpush @cmd, '--summary' if $_verbose;\n+\treturn @cmd unless defined $r_max;\n+\tif ($r_max == $r_min) {\n+\t\tpush @cmd, '--max-count=1';\n+\t\tif (my $c = revdb_get($REVDB, $r_max)) {\n+\t\t\tpush @cmd, $c;\n+\t\t}\n+\t} else {\n+\t\tmy ($c_min, $c_max);\n+\t\t$c_max = revdb_get($REVDB, $r_max);\n+\t\t$c_min = revdb_get($REVDB, $r_min);\n+\t\tif ($c_min && $c_max) {\n+\t\t\tif ($r_max > $r_max) {\n+\t\t\t\tpush @cmd, \"$c_min..$c_max\";\n+\t\t\t} else {\n+\t\t\t\tpush @cmd, \"$c_max..$c_min\";\n+\t\t\t}\n+\t\t} elsif ($r_max > $r_min) {\n+\t\t\tpush @cmd, $c_max;\n+\t\t} else {\n+\t\t\tpush @cmd, $c_min;\n+\t\t}\n+\t}\n+\treturn @cmd;\n+}\n+\n sub fetch_child_id {\n \tmy $id = shift;\n \tprint \"Fetching $id\\n\";\n@@ -2206,6 +2249,7 @@ sub setup_pager { # translated to Perl f\n sub get_author_info {\n \tmy ($dest, $author, $t, $tz) = @_;\n \t$author =~ s/(?:^\\s*|\\s*$)//g;\n+\t$dest->{a_raw} = $author;\n \tmy $_a;\n \tif ($_authors) {\n \t\t$_a = $rusers{$author} || undef;\n@@ -2440,7 +2484,7 @@ sub svn_grab_base_rev {\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)))[0]);\n+\t\t\tsafe_qx(qw/git-cat-file commit/, $c)))[-1]);\n \t\treturn ($rev, $c);\n \t}\n \treturn (undef, undef);\n-- \n1.4.0\n"},{"id":"21895","messageId":"11504806481800-git-send-email-normalperson@yhbt.net","threadId":"4524","inReplyTo":"11504806472857-git-send-email-normalperson@yhbt.net","subject":"[PATCH 2/4] git-svn: tests no longer fail if LC_ALL is not a UTF-8 locale","fromName":"Eric Wong","fromEmail":"normalperson@yhbt.net","sentAt":"2006-06-16T17:57:24Z","receivedAt":"2006-06-16T17:57:24Z","isPatch":true,"sender":{"key":"e@80x24.org","avatar":null},"body":"Signed-off-by: Eric Wong <normalperson@yhbt.net>\n---\n contrib/git-svn/Makefile                   |    5 +++--\n contrib/git-svn/t/t0000-contrib-git-svn.sh |    8 ++++++--\n 2 files changed, 9 insertions(+), 4 deletions(-)\n\ndiff --git a/contrib/git-svn/Makefile b/contrib/git-svn/Makefile\nindex d73aa56..6aedb10 100644\n--- a/contrib/git-svn/Makefile\n+++ b/contrib/git-svn/Makefile\n@@ -32,9 +32,10 @@ test: git-svn\n \tcd t && $(SHELL) ./t0000-contrib-git-svn.sh $(TEST_FLAGS)\n \tcd t && $(SHELL) ./t0001-contrib-git-svn-props.sh $(TEST_FLAGS)\n \n+# we can test NO_OPTIMIZE_COMMITS independently of LC_ALL\n full-test:\n-\t$(MAKE) test GIT_SVN_NO_LIB=1 GIT_SVN_NO_OPTIMIZE_COMMITS=1\n-\t$(MAKE) test GIT_SVN_NO_LIB=0 GIT_SVN_NO_OPTIMIZE_COMMITS=1\n+\t$(MAKE) test GIT_SVN_NO_LIB=1 GIT_SVN_NO_OPTIMIZE_COMMITS=1 LC_ALL=C\n+\t$(MAKE) test GIT_SVN_NO_LIB=0 GIT_SVN_NO_OPTIMIZE_COMMITS=1 LC_ALL=C\n \t$(MAKE) test GIT_SVN_NO_LIB=1 GIT_SVN_NO_OPTIMIZE_COMMITS=0 \\\n \t\t\t\t\t\t\tLC_ALL=en_US.UTF-8\n \t$(MAKE) test GIT_SVN_NO_LIB=0 GIT_SVN_NO_OPTIMIZE_COMMITS=0 \\\ndiff --git a/contrib/git-svn/t/t0000-contrib-git-svn.sh b/contrib/git-svn/t/t0000-contrib-git-svn.sh\nindex f896e2c..0f52746 100644\n--- a/contrib/git-svn/t/t0000-contrib-git-svn.sh\n+++ b/contrib/git-svn/t/t0000-contrib-git-svn.sh\n@@ -194,8 +194,12 @@ test_expect_success \"$name\" \\\n      diff -u a b\"\n \n name='check imported tree checksums expected tree checksums'\n-cat > expected <<\\EOF\n-tree f735671b89a7eb30cab1d8597de35bd4271ab813\n+rm -f expected\n+if test -n \"$GIT_SVN_LC_ALL\" && echo $GIT_SVN_LC_ALL | grep -q '\\.UTF-8$'\n+then\n+\techo tree f735671b89a7eb30cab1d8597de35bd4271ab813 > expected\n+fi\n+cat >> expected <<\\EOF\n tree 4b9af72bb861eaed053854ec502cf7df72618f0f\n tree 031b8d557afc6fea52894eaebb45bec52f1ba6d1\n tree 0b094cbff17168f24c302e297f55bfac65eb8bd3\n-- \n1.4.0\n"},{"id":"21897","messageId":"11504806492195-git-send-email-normalperson@yhbt.net","threadId":"4524","inReplyTo":"11504806481800-git-send-email-normalperson@yhbt.net","subject":"[PATCH 3/4] git-svn: svn (command-line) 1.0.x compatibility","fromName":"Eric Wong","fromEmail":"normalperson@yhbt.net","sentAt":"2006-06-16T17:57:25Z","receivedAt":"2006-06-16T17:57:25Z","isPatch":true,"sender":{"key":"e@80x24.org","avatar":null},"body":"Tested on a plain Ubuntu Warty installation\nusing subversion 1.0.6-1.2ubuntu3\n\nsvn add --force was never needed, as it only affected\ndirectories, which git (thankfully) doesn't track\n\nThe 1.0.x also didn't support symlinks(!), so allow NO_SYMLINK\nto be defined for running tests\n\nSigned-off-by: Eric Wong <normalperson@yhbt.net>\n---\n contrib/git-svn/git-svn.perl               |    4 +\n contrib/git-svn/t/t0000-contrib-git-svn.sh |   90 +++++++++++++++-------------\n 2 files changed, 51 insertions(+), 43 deletions(-)\n\ndiff --git a/contrib/git-svn/git-svn.perl b/contrib/git-svn/git-svn.perl\nindex 417fcf1..ab1d065 100755\n--- a/contrib/git-svn/git-svn.perl\n+++ b/contrib/git-svn/git-svn.perl\n@@ -1306,12 +1306,12 @@ sub svn_checkout_tree {\n \t\t} elsif ($m->{chg} eq 'T') {\n \t\t\tsys(qw(svn rm --force),$m->{file_b});\n \t\t\tapply_mod_line_blob($m);\n-\t\t\tsys(qw(svn add --force), $m->{file_b});\n+\t\t\tsys(qw(svn add), $m->{file_b});\n \t\t\tsvn_check_prop_executable($m);\n \t\t} elsif ($m->{chg} eq 'A') {\n \t\t\tsvn_ensure_parent_path( $m->{file_b} );\n \t\t\tapply_mod_line_blob($m);\n-\t\t\tsys(qw(svn add --force), $m->{file_b});\n+\t\t\tsys(qw(svn add), $m->{file_b});\n \t\t\tsvn_check_prop_executable($m);\n \t\t} else {\n \t\t\tcroak \"Invalid chg: $m->{chg}\\n\";\ndiff --git a/contrib/git-svn/t/t0000-contrib-git-svn.sh b/contrib/git-svn/t/t0000-contrib-git-svn.sh\nindex 0f52746..443d518 100644\n--- a/contrib/git-svn/t/t0000-contrib-git-svn.sh\n+++ b/contrib/git-svn/t/t0000-contrib-git-svn.sh\n@@ -11,7 +11,10 @@ mkdir import\n cd import\n \n echo foo > foo\n-ln -s foo foo.link\n+if test -z \"$NO_SYMLINK\"\n+then\n+\tln -s foo foo.link\n+fi\n mkdir -p dir/a/b/c/d/e\n echo 'deep dir' > dir/a/b/c/d/e/file\n mkdir -p bar\n@@ -129,46 +132,45 @@ test_expect_success \"$name\" \\\n \n \n \n-name='executable file becomes a symlink to bar/zzz (file)'\n-rm exec.sh\n-ln -s bar/zzz exec.sh\n-git update-index exec.sh\n-git commit -m \"$name\"\n-\n-test_expect_success \"$name\" \\\n-    \"git-svn commit --find-copies-harder --rmdir remotes/git-svn..mybranch5 &&\n-     svn up $SVN_TREE &&\n-     test -L $SVN_TREE/exec.sh\"\n-\n-\n-\n-name='new symlink is added to a file that was also just made executable'\n-chmod +x bar/zzz\n-ln -s bar/zzz exec-2.sh\n-git update-index --add bar/zzz exec-2.sh\n-git commit -m \"$name\"\n-\n-test_expect_success \"$name\" \\\n-    \"git-svn commit --find-copies-harder --rmdir remotes/git-svn..mybranch5 &&\n-     svn up $SVN_TREE &&\n-     test -x $SVN_TREE/bar/zzz &&\n-     test -L $SVN_TREE/exec-2.sh\"\n-\n-\n-\n-name='modify a symlink to become a file'\n-git help > help || true\n-rm exec-2.sh\n-cp help exec-2.sh\n-git update-index exec-2.sh\n-git commit -m \"$name\"\n-\n-test_expect_success \"$name\" \\\n-    \"git-svn commit --find-copies-harder --rmdir remotes/git-svn..mybranch5 &&\n-     svn up $SVN_TREE &&\n-     test -f $SVN_TREE/exec-2.sh &&\n-     test ! -L $SVN_TREE/exec-2.sh &&\n-     diff -u help $SVN_TREE/exec-2.sh\"\n+if test -z \"$NO_SYMLINK\"\n+then\n+\tname='executable file becomes a symlink to bar/zzz (file)'\n+\trm exec.sh\n+\tln -s bar/zzz exec.sh\n+\tgit update-index exec.sh\n+\tgit commit -m \"$name\"\n+\n+\ttest_expect_success \"$name\" \\\n+\t    \"git-svn commit --find-copies-harder --rmdir remotes/git-svn..mybranch5 &&\n+\t     svn up $SVN_TREE &&\n+\t     test -L $SVN_TREE/exec.sh\"\n+\n+\tname='new symlink is added to a file that was also just made executable'\n+\tchmod +x bar/zzz\n+\tln -s bar/zzz exec-2.sh\n+\tgit update-index --add bar/zzz exec-2.sh\n+\tgit commit -m \"$name\"\n+\n+\ttest_expect_success \"$name\" \\\n+\t    \"git-svn commit --find-copies-harder --rmdir remotes/git-svn..mybranch5 &&\n+\t     svn up $SVN_TREE &&\n+\t     test -x $SVN_TREE/bar/zzz &&\n+\t     test -L $SVN_TREE/exec-2.sh\"\n+\n+\tname='modify a symlink to become a file'\n+\tgit help > help || true\n+\trm exec-2.sh\n+\tcp help exec-2.sh\n+\tgit update-index exec-2.sh\n+\tgit commit -m \"$name\"\n+\n+\ttest_expect_success \"$name\" \\\n+\t    \"git-svn commit --find-copies-harder --rmdir remotes/git-svn..mybranch5 &&\n+\t     svn up $SVN_TREE &&\n+\t     test -f $SVN_TREE/exec-2.sh &&\n+\t     test ! -L $SVN_TREE/exec-2.sh &&\n+\t     diff -u help $SVN_TREE/exec-2.sh\"\n+fi\n \n \n if test -n \"$GIT_SVN_LC_ALL\" && echo $GIT_SVN_LC_ALL | grep -q '\\.UTF-8$'\n@@ -193,6 +195,12 @@ test_expect_success \"$name\" \\\n      git-rev-list --pretty=raw remotes/alt | grep ^tree | uniq > b &&\n      diff -u a b\"\n \n+if test -n \"$NO_SYMLINK\"\n+then\n+\ttest_done\n+\texit 0\n+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-- \n1.4.0\n"},{"id":"21896","messageId":"11504806511326-git-send-email-normalperson@yhbt.net","threadId":"4524","inReplyTo":"11504806492195-git-send-email-normalperson@yhbt.net","subject":"[PATCH 4/4] git-svn: rebuild convenience and bugfixes","fromName":"Eric Wong","fromEmail":"normalperson@yhbt.net","sentAt":"2006-06-16T17:57:26Z","receivedAt":"2006-06-16T17:57:26Z","isPatch":true,"sender":{"key":"e@80x24.org","avatar":null},"body":"We will now automatically fetch the refs/remotes/git-svn ref\nfrom origin and store a Pull: line for it.\n\n--remote=<origin> may be passed if your remote is named something\nother than 'origin'\n\nAlso, remember to make GIT_SVN_DIR whenever we need to create\n.rev_db\n\nSigned-off-by: Eric Wong <normalperson@yhbt.net>\n---\n contrib/git-svn/git-svn.perl |   21 +++++++++++++++++++--\n 1 files changed, 19 insertions(+), 2 deletions(-)\n\ndiff --git a/contrib/git-svn/git-svn.perl b/contrib/git-svn/git-svn.perl\nindex ab1d065..da0ff9a 100755\n--- a/contrib/git-svn/git-svn.perl\n+++ b/contrib/git-svn/git-svn.perl\n@@ -42,7 +42,7 @@ my $_optimize_commits = 1 unless $ENV{GI\n 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,\n+\t$_find_copies_harder, $_l, $_cp_similarity, $_cp_remote,\n \t$_repack, $_repack_nr, $_repack_flags,\n \t$_template, $_shared, $_no_default_regex, $_no_graft_copy,\n \t$_limit, $_verbose, $_incremental, $_oneline, $_l_fmt, $_show_commit,\n@@ -86,6 +86,7 @@ my %cmd = (\n \t\t\t{ 'revision|r=i' => \\$_revision } ],\n \trebuild => [ \\&rebuild, \"Rebuild git-svn metadata (after git clone)\",\n \t\t\t{ 'no-ignore-externals' => \\$_no_ignore_ext,\n+\t\t\t  'copy-remote|remote=s' => \\$_cp_remote,\n \t\t\t  'upgrade' => \\$_upgrade } ],\n \t'graft-branches' => [ \\&graft_branches,\n \t\t\t'Detect merges/branches from already imported history',\n@@ -134,7 +135,7 @@ init_vars();\n load_authors() if $_authors;\n load_all_refs() if $_branch_all_refs;\n svn_compat_check();\n-migration_check() unless $cmd =~ /^(?:init|multi-init)$/;\n+migration_check() unless $cmd =~ /^(?:init|rebuild|multi-init)$/;\n $cmd{$cmd}->[0]->(@ARGV);\n exit 0;\n \n@@ -174,6 +175,9 @@ sub version {\n }\n \n sub rebuild {\n+\tif (quiet_run(qw/git-rev-parse --verify/,\"refs/remotes/$GIT_SVN^0\")) {\n+\t\tcopy_remote_ref();\n+\t}\n \t$SVN_URL = shift or undef;\n \tmy $newest_rev = 0;\n \tif ($_upgrade) {\n@@ -1940,6 +1944,7 @@ sub svn_cmd_checkout {\n \n sub check_upgrade_needed {\n \tif (!-r $REVDB) {\n+\t\t-d $GIT_SVN_DIR or mkpath([$GIT_SVN_DIR]);\n \t\topen my $fh, '>>',$REVDB or croak $!;\n \t\tclose $fh;\n \t}\n@@ -2052,6 +2057,7 @@ sub migrate_revdb {\n \t\t\tinit_vars();\n \t\t\texit 0 if -r $REVDB;\n \t\t\tprint \"Upgrading svn => git mapping...\\n\";\n+\t\t\t-d $GIT_SVN_DIR or mkpath([$GIT_SVN_DIR]);\n \t\t\topen my $fh, '>>',$REVDB or croak $!;\n \t\t\tclose $fh;\n \t\t\trebuild();\n@@ -2763,6 +2769,17 @@ sub revdb_get {\n \treturn $ret;\n }\n \n+sub copy_remote_ref {\n+\tmy $origin = $_cp_remote ? $_cp_remote : 'origin';\n+\tmy $ref = \"refs/remotes/$GIT_SVN\";\n+\tif (safe_qx('git-ls-remote', $origin, $ref)) {\n+\t\tsys(qw/git fetch/, $origin, \"$ref:$ref\");\n+\t} else {\n+\t\tdie \"Unable to find remote reference: \",\n+\t\t\t\t\"refs/remotes/$GIT_SVN on $origin\\n\";\n+\t}\n+}\n+\n package SVN::Git::Editor;\n use vars qw/@ISA/;\n use strict;\n-- \n1.4.0\n"}]}