{"thread":{"id":"13636","subject":"[PATCH 6/8] git-svn: Speed up fetch","startedAt":"2008-05-23T14:19:35Z","lastAt":"2008-05-23T14:19:44Z","messageCount":10,"participants":["Michele Ballabio"],"isPatch":true,"patchVersion":1,"patchTotal":8},"messages":[{"id":"77547","messageId":"1211552384-29636-1-git-send-email-barra_cuda@katamail.com","threadId":"13636","inReplyTo":null,"subject":"[PATCH 0/8] Speed up git-svn","fromName":"Michele Ballabio","fromEmail":"barra_cuda@katamail.com","sentAt":"2008-05-23T14:19:35Z","receivedAt":"2008-05-23T14:19:35Z","isPatch":true,"sender":{"key":"barra_cuda@katamail.com","avatar":"https://avatars.githubusercontent.com/u/16371673?v=4"},"body":"This is a respin of the patches by Adam Roben that follow\nthe ones that are now in \"pu\".\n\n\nAdam Roben (6):\n  Move git-hash-object tests from t5303 to t1007\n  Add more tests for git hash-object\n  git-hash-object: Add --stdin-paths option\n  Git.pm: Add command_bidi_pipe and command_close_bidi_pipe\n  Git.pm: Add hash_and_insert_object and cat_blob\n  git-svn: Speed up fetch\n\nThese patches have the changes suggested in the old thread to\nremove some warnings and fix the tests, plus formatting changes in\nthe tests. The patches on Git.pm and git-svn.perl are the same as\nbefore, patches 2 and 3 are the ones I have touched.\n\n\nMichele Ballabio (2):\n  builtin-cat-file.c: use parse_options()\n  change quoting in test t1006-cat-file.sh\n\nThese are independent changes, but are always to be applied on top\nof what's in \"pu\" (on top of ar/batch-cat, actually). The first\ntries to simplify the code about the option parsing. The second\none is only for readability.\n\n\n Documentation/git-hash-object.txt |    5 +-\n builtin-cat-file.c                |  119 ++++++++-------------\n git-svn.perl                      |   42 ++++----\n hash-object.c                     |   45 ++++++++-\n perl/Git.pm                       |  208 ++++++++++++++++++++++++++++++++++++-\n t/t1006-cat-file.sh               |    6 +-\n t/t1007-hash-object.sh            |  133 +++++++++++++++++++++++\n t/t5303-hash-object.sh            |   35 ------\n 8 files changed, 456 insertions(+), 137 deletions(-)\n create mode 100755 t/t1007-hash-object.sh\n delete mode 100755 t/t5303-hash-object.sh\n"},{"id":"77545","messageId":"1211552384-29636-2-git-send-email-barra_cuda@katamail.com","threadId":"13636","inReplyTo":"1211552384-29636-1-git-send-email-barra_cuda@katamail.com","subject":"[PATCH 1/8] Move git-hash-object tests from t5303 to t1007","fromName":"Michele Ballabio","fromEmail":"barra_cuda@katamail.com","sentAt":"2008-05-23T14:19:36Z","receivedAt":"2008-05-23T14:19:36Z","isPatch":true,"sender":{"key":"barra_cuda@katamail.com","avatar":"https://avatars.githubusercontent.com/u/16371673?v=4"},"body":"From: Adam Roben <aroben@apple.com>\n\nThis is a more appropriate location according to t/README.\n\nSigned-off-by: Adam Roben <aroben@apple.com>\n---\n t/{t5303-hash-object.sh => t1007-hash-object.sh} |    0 \n 1 files changed, 0 insertions(+), 0 deletions(-)\n rename t/{t5303-hash-object.sh => t1007-hash-object.sh} (100%)\n\ndiff --git a/t/t5303-hash-object.sh b/t/t1007-hash-object.sh\nsimilarity index 100%\nrename from t/t5303-hash-object.sh\nrename to t/t1007-hash-object.sh\n-- \n1.5.5.1\n"},{"id":"77549","messageId":"1211552384-29636-3-git-send-email-barra_cuda@katamail.com","threadId":"13636","inReplyTo":"1211552384-29636-1-git-send-email-barra_cuda@katamail.com","subject":"[PATCH 2/8] Add more tests for git hash-object","fromName":"Michele Ballabio","fromEmail":"barra_cuda@katamail.com","sentAt":"2008-05-23T14:19:37Z","receivedAt":"2008-05-23T14:19:37Z","isPatch":true,"sender":{"key":"barra_cuda@katamail.com","avatar":"https://avatars.githubusercontent.com/u/16371673?v=4"},"body":"From: Adam Roben <aroben@apple.com>\n\nSigned-off-by: Adam Roben <aroben@apple.com>\n---\n t/t1007-hash-object.sh |  120 +++++++++++++++++++++++++++++++++++++-----------\n 1 files changed, 93 insertions(+), 27 deletions(-)\n\ndiff --git a/t/t1007-hash-object.sh b/t/t1007-hash-object.sh\nindex 543c078..2019ea7 100755\n--- a/t/t1007-hash-object.sh\n+++ b/t/t1007-hash-object.sh\n@@ -4,32 +4,98 @@ test_description=git-hash-object\n \n . ./test-lib.sh\n \n-test_expect_success \\\n-    'git hash-object -w --stdin saves the object' \\\n-    'obname=$(echo foo | git hash-object -w --stdin) &&\n-    obpath=$(echo $obname | sed -e \"s/\\(..\\)/\\1\\//\") &&\n-    test -r .git/objects/\"$obpath\" &&\n-    rm -f .git/objects/\"$obpath\"'\n-    \n-test_expect_success \\\n-    'git hash-object --stdin -w saves the object' \\\n-    'obname=$(echo foo | git hash-object --stdin -w) &&\n-    obpath=$(echo $obname | sed -e \"s/\\(..\\)/\\1\\//\") &&\n-    test -r .git/objects/\"$obpath\" &&\n-    rm -f .git/objects/\"$obpath\"'    \n-\n-test_expect_success \\\n-    'git hash-object --stdin file1 <file0 first operates on file0, then file1' \\\n-    'echo foo > file1 &&\n-    obname0=$(echo bar | git hash-object --stdin) &&\n-    obname1=$(git hash-object file1) &&\n-    obname0new=$(echo bar | git hash-object --stdin file1 | sed -n -e 1p) &&\n-    obname1new=$(echo bar | git hash-object --stdin file1 | sed -n -e 2p) &&\n-    test \"$obname0\" = \"$obname0new\" &&\n-    test \"$obname1\" = \"$obname1new\"'\n-\n-test_expect_success \\\n-    'git hash-object refuses multiple --stdin arguments' \\\n-    '! git hash-object --stdin --stdin < file1'\n+echo_without_newline() {\n+\tprintf '%s' \"$*\"\n+}\n+\n+test_blob_does_not_exist() {\n+\ttest_expect_success 'blob does not exist in database' \"\n+\t\ttest_must_fail git cat-file blob $1\n+\t\"\n+}\n+\n+test_blob_exists() {\n+\ttest_expect_success 'blob exists in database' \"\n+\t\tgit cat-file blob $1\n+\t\"\n+}\n+\n+hello_content=\"Hello World\"\n+hello_sha1=5e1c309dae7f45e0f39b1bf3ac3cd9db12e7d689\n+\n+example_content=\"This is an example\"\n+example_sha1=ddd3f836d3e3fbb7ae289aa9ae83536f76956399\n+\n+setup_repo() {\n+\techo_without_newline \"$hello_content\" > hello\n+\techo_without_newline \"$example_content\" > example\n+}\n+\n+test_repo=test\n+push_repo() {\n+\ttest_create_repo $test_repo\n+\tcd $test_repo\n+\n+\tsetup_repo\n+}\n+\n+pop_repo() {\n+\tcd ..\n+\trm -rf $test_repo\n+}\n+\n+setup_repo\n+\n+# Argument checking\n+\n+test_expect_success \"multiple '--stdin's are rejected\" '\n+\ttest_must_fail git hash-object --stdin --stdin < example\n+'\n+\n+# Behavior\n+\n+push_repo\n+\n+test_expect_success 'hash a file' '\n+\ttest $hello_sha1 = $(git hash-object hello)\n+'\n+\n+test_blob_does_not_exist $hello_sha1\n+\n+test_expect_success 'hash from stdin' '\n+\ttest $example_sha1 = $(git hash-object --stdin < example)\n+'\n+\n+test_blob_does_not_exist $example_sha1\n+\n+test_expect_success 'hash a file and write to database' '\n+\ttest $hello_sha1 = $(git hash-object -w hello)\n+'\n+\n+test_blob_exists $hello_sha1\n+\n+test_expect_success 'git hash-object --stdin file1 <file0 first operates on file0, then file1' '\n+\techo foo > file1 &&\n+\tobname0=$(echo bar | git hash-object --stdin) &&\n+\tobname1=$(git hash-object file1) &&\n+\tobname0new=$(echo bar | git hash-object --stdin file1 | sed -n -e 1p) &&\n+\tobname1new=$(echo bar | git hash-object --stdin file1 | sed -n -e 2p) &&\n+\ttest \"$obname0\" = \"$obname0new\" &&\n+\ttest \"$obname1\" = \"$obname1new\"\n+'\n+\n+pop_repo\n+\n+for args in \"-w --stdin\" \"--stdin -w\"; do\n+\tpush_repo\n+\n+\ttest_expect_success \"hash from stdin and write to database ($args)\" '\n+\t\ttest $example_sha1 = $(git hash-object $args < example)\n+\t'\n+\n+\ttest_blob_exists $example_sha1\n+\n+\tpop_repo\n+done\n \n test_done\n-- \n1.5.5.1\n"},{"id":"77550","messageId":"1211552384-29636-4-git-send-email-barra_cuda@katamail.com","threadId":"13636","inReplyTo":"1211552384-29636-1-git-send-email-barra_cuda@katamail.com","subject":"[PATCH 3/8] git-hash-object: Add --stdin-paths option","fromName":"Michele Ballabio","fromEmail":"barra_cuda@katamail.com","sentAt":"2008-05-23T14:19:38Z","receivedAt":"2008-05-23T14:19:38Z","isPatch":true,"sender":{"key":"barra_cuda@katamail.com","avatar":"https://avatars.githubusercontent.com/u/16371673?v=4"},"body":"From: Adam Roben <aroben@apple.com>\n\nThis allows multiple paths to be specified on stdin.\n\nSigned-off-by: Adam Roben <aroben@apple.com>\n---\n Documentation/git-hash-object.txt |    5 +++-\n hash-object.c                     |   45 ++++++++++++++++++++++++++++++++++++-\n t/t1007-hash-object.sh            |   32 ++++++++++++++++++++++++++\n 3 files changed, 80 insertions(+), 2 deletions(-)\n\ndiff --git a/Documentation/git-hash-object.txt b/Documentation/git-hash-object.txt\nindex 33030c0..99a2143 100644\n--- a/Documentation/git-hash-object.txt\n+++ b/Documentation/git-hash-object.txt\n@@ -8,7 +8,7 @@ git-hash-object - Compute object ID and optionally creates a blob from a file\n \n SYNOPSIS\n --------\n-'git-hash-object' [-t <type>] [-w] [--stdin] [--] <file>...\n+'git-hash-object' [-t <type>] [-w] [--stdin | --stdin-paths] [--] <file>...\n \n DESCRIPTION\n -----------\n@@ -32,6 +32,9 @@ OPTIONS\n --stdin::\n \tRead the object from standard input instead of from a file.\n \n+--stdin-paths::\n+\tRead file names from stdin instead of from the command-line.\n+\n Author\n ------\n Written by Junio C Hamano <junkio@cox.net>\ndiff --git a/hash-object.c b/hash-object.c\nindex 61e7160..0a7ac2f 100644\n--- a/hash-object.c\n+++ b/hash-object.c\n@@ -6,6 +6,7 @@\n  */\n #include \"cache.h\"\n #include \"blob.h\"\n+#include \"quote.h\"\n \n static void hash_object(const char *path, enum object_type type, int write_object)\n {\n@@ -20,6 +21,7 @@ static void hash_object(const char *path, enum object_type type, int write_objec\n \t\t    ? \"Unable to add %s to database\"\n \t\t    : \"Unable to hash %s\", path);\n \tprintf(\"%s\\n\", sha1_to_hex(sha1));\n+\tmaybe_flush_or_die(stdout, \"hash to stdout\");\n }\n \n static void hash_stdin(const char *type, int write_object)\n@@ -30,8 +32,27 @@ static void hash_stdin(const char *type, int write_object)\n \tprintf(\"%s\\n\", sha1_to_hex(sha1));\n }\n \n+static void hash_stdin_paths(const char *type, int write_objects)\n+{\n+\tstruct strbuf buf, nbuf;\n+\n+\tstrbuf_init(&buf, 0);\n+\tstrbuf_init(&nbuf, 0);\n+\twhile (strbuf_getline(&buf, stdin, '\\n') != EOF) {\n+\t\tif (buf.buf[0] == '\"') {\n+\t\t\tstrbuf_reset(&nbuf);\n+\t\t\tif (unquote_c_style(&nbuf, buf.buf, NULL))\n+\t\t\t\tdie(\"line is badly quoted\");\n+\t\t\tstrbuf_swap(&buf, &nbuf);\n+\t\t}\n+\t\thash_object(buf.buf, type_from_string(type), write_objects);\n+\t}\n+\tstrbuf_release(&buf);\n+\tstrbuf_release(&nbuf);\n+}\n+\n static const char hash_object_usage[] =\n-\"git-hash-object [-t <type>] [-w] [--stdin] <file>...\";\n+\"git-hash-object [ [-t <type>] [-w] [--stdin] <file>... | --stdin-paths < <list-of-paths> ]\";\n \n int main(int argc, char **argv)\n {\n@@ -42,6 +63,7 @@ int main(int argc, char **argv)\n \tint prefix_length = -1;\n \tint no_more_flags = 0;\n \tint hashstdin = 0;\n+\tint stdin_paths = 0;\n \n \tgit_config(git_default_config);\n \n@@ -65,7 +87,19 @@ int main(int argc, char **argv)\n \t\t\t}\n \t\t\telse if (!strcmp(argv[i], \"--help\"))\n \t\t\t\tusage(hash_object_usage);\n+\t\t\telse if (!strcmp(argv[i], \"--stdin-paths\")) {\n+\t\t\t\tif (hashstdin) {\n+\t\t\t\t\terror(\"Can't use --stdin-paths with --stdin\");\n+\t\t\t\t\tusage(hash_object_usage);\n+\t\t\t\t}\n+\t\t\t\tstdin_paths = 1;\n+\n+\t\t\t}\n \t\t\telse if (!strcmp(argv[i], \"--stdin\")) {\n+\t\t\t\tif (stdin_paths) {\n+\t\t\t\t\terror(\"Can't use %s with --stdin-paths\", argv[i]);\n+\t\t\t\t\tusage(hash_object_usage);\n+\t\t\t\t}\n \t\t\t\tif (hashstdin)\n \t\t\t\t\tdie(\"Multiple --stdin arguments are not supported\");\n \t\t\t\thashstdin = 1;\n@@ -76,6 +110,11 @@ int main(int argc, char **argv)\n \t\telse {\n \t\t\tconst char *arg = argv[i];\n \n+\t\t\tif (stdin_paths) {\n+\t\t\t\terror(\"Can't specify files (such as \\\"%s\\\") with --stdin-paths\", arg);\n+\t\t\t\tusage(hash_object_usage);\n+\t\t\t}\n+\n \t\t\tif (hashstdin) {\n \t\t\t\thash_stdin(type, write_object);\n \t\t\t\thashstdin = 0;\n@@ -87,6 +126,10 @@ int main(int argc, char **argv)\n \t\t\tno_more_flags = 1;\n \t\t}\n \t}\n+\n+\tif (stdin_paths)\n+\t\thash_stdin_paths(type, write_object);\n+\n \tif (hashstdin)\n \t\thash_stdin(type, write_object);\n \treturn 0;\ndiff --git a/t/t1007-hash-object.sh b/t/t1007-hash-object.sh\nindex 2019ea7..0526295 100755\n--- a/t/t1007-hash-object.sh\n+++ b/t/t1007-hash-object.sh\n@@ -52,6 +52,15 @@ test_expect_success \"multiple '--stdin's are rejected\" '\n \ttest_must_fail git hash-object --stdin --stdin < example\n '\n \n+test_expect_success \"Can't use --stdin and --stdin-paths together\" '\n+\ttest_must_fail git hash-object --stdin --stdin-paths &&\n+\ttest_must_fail git hash-object --stdin-paths --stdin\n+'\n+\n+test_expect_success \"Can't pass filenames as arguments with --stdin-paths\" '\n+\ttest_must_fail git hash-object --stdin-paths hello < example\n+'\n+\n # Behavior\n \n push_repo\n@@ -98,4 +107,27 @@ for args in \"-w --stdin\" \"--stdin -w\"; do\n \tpop_repo\n done\n \n+filenames=\"hello\n+example\"\n+\n+sha1s=\"$hello_sha1\n+$example_sha1\"\n+\n+test_expect_success \"hash two files with names on stdin\" '\n+\ttest \"$sha1s\" = \"$(echo_without_newline \"$filenames\" | git hash-object --stdin-paths)\"\n+'\n+\n+for args in \"-w --stdin-paths\" \"--stdin-paths -w\"; do\n+\tpush_repo\n+\n+\ttest_expect_success \"hash two files with names on stdin and write to database ($args)\" '\n+\t\ttest \"$sha1s\" = \"$(echo_without_newline \"$filenames\" | git hash-object $args)\"\n+\t'\n+\n+\ttest_blob_exists $hello_sha1\n+\ttest_blob_exists $example_sha1\n+\n+\tpop_repo\n+done\n+\n test_done\n-- \n1.5.5.1\n"},{"id":"77546","messageId":"1211552384-29636-5-git-send-email-barra_cuda@katamail.com","threadId":"13636","inReplyTo":"1211552384-29636-1-git-send-email-barra_cuda@katamail.com","subject":"[PATCH 4/8] Git.pm: Add command_bidi_pipe and command_close_bidi_pipe","fromName":"Michele Ballabio","fromEmail":"barra_cuda@katamail.com","sentAt":"2008-05-23T14:19:39Z","receivedAt":"2008-05-23T14:19:39Z","isPatch":true,"sender":{"key":"barra_cuda@katamail.com","avatar":"https://avatars.githubusercontent.com/u/16371673?v=4"},"body":"From: Adam Roben <aroben@apple.com>\n\ncommand_bidi_pipe hands back the stdin and stdout file handles from the\nexecuted command. command_close_bidi_pipe closes these handles and terminates\nthe process.\n\nSigned-off-by: Adam Roben <aroben@apple.com>\n---\n perl/Git.pm |   56 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n 1 files changed, 56 insertions(+), 0 deletions(-)\n\ndiff --git a/perl/Git.pm b/perl/Git.pm\nindex 2e7f896..d766974 100644\n--- a/perl/Git.pm\n+++ b/perl/Git.pm\n@@ -51,6 +51,7 @@ require Exporter;\n # Methods which can be called as standalone functions as well:\n @EXPORT_OK = qw(command command_oneline command_noisy\n                 command_output_pipe command_input_pipe command_close_pipe\n+                command_bidi_pipe command_close_bidi_pipe\n                 version exec_path hash_object git_cmd_try);\n \n \n@@ -92,6 +93,7 @@ increate nonwithstanding).\n use Carp qw(carp croak); # but croak is bad - throw instead\n use Error qw(:try);\n use Cwd qw(abs_path);\n+use IPC::Open2 qw(open2);\n \n }\n \n@@ -375,6 +377,60 @@ sub command_close_pipe {\n \t_cmd_close($fh, $ctx);\n }\n \n+=item command_bidi_pipe ( COMMAND [, ARGUMENTS... ] )\n+\n+Execute the given C<COMMAND> in the same way as command_output_pipe()\n+does but return both an input pipe filehandle and an output pipe filehandle.\n+\n+The function will return return C<($pid, $pipe_in, $pipe_out, $ctx)>.\n+See C<command_close_bidi_pipe()> for details.\n+\n+=cut\n+\n+sub command_bidi_pipe {\n+\tmy ($pid, $in, $out);\n+\t$pid = open2($in, $out, 'git', @_);\n+\treturn ($pid, $in, $out, join(' ', @_));\n+}\n+\n+=item command_close_bidi_pipe ( PID, PIPE_IN, PIPE_OUT [, CTX] )\n+\n+Close the C<PIPE_IN> and C<PIPE_OUT> as returned from C<command_bidi_pipe()>,\n+checking whether the command finished successfully. The optional C<CTX>\n+argument is required if you want to see the command name in the error message,\n+and it is the fourth value returned by C<command_bidi_pipe()>.  The call idiom\n+is:\n+\n+\tmy ($pid, $in, $out, $ctx) = $r->command_bidi_pipe('cat-file --batch-check');\n+\tprint \"000000000\\n\" $out;\n+\twhile (<$in>) { ... }\n+\t$r->command_close_bidi_pipe($pid, $in, $out, $ctx);\n+\n+Note that you should not rely on whatever actually is in C<CTX>;\n+currently it is simply the command name but in future the context might\n+have more complicated structure.\n+\n+=cut\n+\n+sub command_close_bidi_pipe {\n+\tmy ($pid, $in, $out, $ctx) = @_;\n+\tforeach my $fh ($in, $out) {\n+\t\tunless (close $fh) {\n+\t\t\tif ($!) {\n+\t\t\t\tcarp \"error closing pipe: $!\";\n+\t\t\t} elsif ($? >> 8) {\n+\t\t\t\tthrow Git::Error::Command($ctx, $? >>8);\n+\t\t\t}\n+\t\t}\n+\t}\n+\n+\twaitpid $pid, 0;\n+\n+\tif ($? >> 8) {\n+\t\tthrow Git::Error::Command($ctx, $? >>8);\n+\t}\n+}\n+\n \n =item command_noisy ( COMMAND [, ARGUMENTS... ] )\n \n-- \n1.5.5.1\n"},{"id":"77544","messageId":"1211552384-29636-6-git-send-email-barra_cuda@katamail.com","threadId":"13636","inReplyTo":"1211552384-29636-1-git-send-email-barra_cuda@katamail.com","subject":"[PATCH 5/8] Git.pm: Add hash_and_insert_object and cat_blob","fromName":"Michele Ballabio","fromEmail":"barra_cuda@katamail.com","sentAt":"2008-05-23T14:19:40Z","receivedAt":"2008-05-23T14:19:40Z","isPatch":true,"sender":{"key":"barra_cuda@katamail.com","avatar":"https://avatars.githubusercontent.com/u/16371673?v=4"},"body":"From: Adam Roben <aroben@apple.com>\n\nThese functions are more efficient ways of executing `git hash-object -w` and\n`git cat-file blob` when you are dealing with many files/objects.\n\nSigned-off-by: Adam Roben <aroben@apple.com>\n---\n perl/Git.pm |  152 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-\n 1 files changed, 150 insertions(+), 2 deletions(-)\n\ndiff --git a/perl/Git.pm b/perl/Git.pm\nindex d766974..6ba8ee5 100644\n--- a/perl/Git.pm\n+++ b/perl/Git.pm\n@@ -39,6 +39,10 @@ $VERSION = '0.01';\n   my $lastrev = $repo->command_oneline( [ 'rev-list', '--all' ],\n                                         STDERR => 0 );\n \n+  my $sha1 = $repo->hash_and_insert_object('file.txt');\n+  my $tempfile = tempfile();\n+  my $size = $repo->cat_blob($sha1, $tempfile);\n+\n =cut\n \n \n@@ -218,7 +222,6 @@ sub repository {\n \tbless $self, $class;\n }\n \n-\n =back\n \n =head1 METHODS\n@@ -734,6 +737,147 @@ sub hash_object {\n }\n \n \n+=item hash_and_insert_object ( FILENAME )\n+\n+Compute the SHA1 object id of the given C<FILENAME> and add the object to the\n+object database.\n+\n+The function returns the SHA1 hash.\n+\n+=cut\n+\n+# TODO: Support for passing FILEHANDLE instead of FILENAME\n+sub hash_and_insert_object {\n+\tmy ($self, $filename) = @_;\n+\n+\tcarp \"Bad filename \\\"$filename\\\"\" if $filename =~ /[\\r\\n]/;\n+\n+\t$self->_open_hash_and_insert_object_if_needed();\n+\tmy ($in, $out) = ($self->{hash_object_in}, $self->{hash_object_out});\n+\n+\tunless (print $out $filename, \"\\n\") {\n+\t\t$self->_close_hash_and_insert_object();\n+\t\tthrow Error::Simple(\"out pipe went bad\");\n+\t}\n+\n+\tchomp(my $hash = <$in>);\n+\tunless (defined($hash)) {\n+\t\t$self->_close_hash_and_insert_object();\n+\t\tthrow Error::Simple(\"in pipe went bad\");\n+\t}\n+\n+\treturn $hash;\n+}\n+\n+sub _open_hash_and_insert_object_if_needed {\n+\tmy ($self) = @_;\n+\n+\treturn if defined($self->{hash_object_pid});\n+\n+\t($self->{hash_object_pid}, $self->{hash_object_in},\n+\t $self->{hash_object_out}, $self->{hash_object_ctx}) =\n+\t\tcommand_bidi_pipe(qw(hash-object -w --stdin-paths));\n+}\n+\n+sub _close_hash_and_insert_object {\n+\tmy ($self) = @_;\n+\n+\treturn unless defined($self->{hash_object_pid});\n+\n+\tmy @vars = map { 'hash_object_' . $_ } qw(pid in out ctx);\n+\n+\tcommand_close_bidi_pipe($self->{@vars});\n+\tdelete $self->{@vars};\n+}\n+\n+=item cat_blob ( SHA1, FILEHANDLE )\n+\n+Prints the contents of the blob identified by C<SHA1> to C<FILEHANDLE> and\n+returns the number of bytes printed.\n+\n+=cut\n+\n+sub cat_blob {\n+\tmy ($self, $sha1, $fh) = @_;\n+\n+\t$self->_open_cat_blob_if_needed();\n+\tmy ($in, $out) = ($self->{cat_blob_in}, $self->{cat_blob_out});\n+\n+\tunless (print $out $sha1, \"\\n\") {\n+\t\t$self->_close_cat_blob();\n+\t\tthrow Error::Simple(\"out pipe went bad\");\n+\t}\n+\n+\tmy $description = <$in>;\n+\tif ($description =~ / missing$/) {\n+\t\tcarp \"$sha1 doesn't exist in the repository\";\n+\t\treturn 0;\n+\t}\n+\n+\tif ($description !~ /^[0-9a-fA-F]{40} \\S+ (\\d+)$/) {\n+\t\tcarp \"Unexpected result returned from git cat-file\";\n+\t\treturn 0;\n+\t}\n+\n+\tmy $size = $1;\n+\n+\tmy $blob;\n+\tmy $bytesRead = 0;\n+\n+\twhile (1) {\n+\t\tmy $bytesLeft = $size - $bytesRead;\n+\t\tlast unless $bytesLeft;\n+\n+\t\tmy $bytesToRead = $bytesLeft < 1024 ? $bytesLeft : 1024;\n+\t\tmy $read = read($in, $blob, $bytesToRead, $bytesRead);\n+\t\tunless (defined($read)) {\n+\t\t\t$self->_close_cat_blob();\n+\t\t\tthrow Error::Simple(\"in pipe went bad\");\n+\t\t}\n+\n+\t\t$bytesRead += $read;\n+\t}\n+\n+\t# Skip past the trailing newline.\n+\tmy $newline;\n+\tmy $read = read($in, $newline, 1);\n+\tunless (defined($read)) {\n+\t\t$self->_close_cat_blob();\n+\t\tthrow Error::Simple(\"in pipe went bad\");\n+\t}\n+\tunless ($read == 1 && $newline eq \"\\n\") {\n+\t\t$self->_close_cat_blob();\n+\t\tthrow Error::Simple(\"didn't find newline after blob\");\n+\t}\n+\n+\tunless (print $fh $blob) {\n+\t\t$self->_close_cat_blob();\n+\t\tthrow Error::Simple(\"couldn't write to passed in filehandle\");\n+\t}\n+\n+\treturn $size;\n+}\n+\n+sub _open_cat_blob_if_needed {\n+\tmy ($self) = @_;\n+\n+\treturn if defined($self->{cat_blob_pid});\n+\n+\t($self->{cat_blob_pid}, $self->{cat_blob_in},\n+\t $self->{cat_blob_out}, $self->{cat_blob_ctx}) =\n+\t\tcommand_bidi_pipe(qw(cat-file --batch));\n+}\n+\n+sub _close_cat_blob {\n+\tmy ($self) = @_;\n+\n+\treturn unless defined($self->{cat_blob_pid});\n+\n+\tmy @vars = map { 'cat_blob_' . $_ } qw(pid in out ctx);\n+\n+\tcommand_close_bidi_pipe($self->{@vars});\n+\tdelete $self->{@vars};\n+}\n \n =back\n \n@@ -951,7 +1095,11 @@ sub _cmd_close {\n }\n \n \n-sub DESTROY { }\n+sub DESTROY {\n+\tmy ($self) = @_;\n+\t$self->_close_hash_and_insert_object();\n+\t$self->_close_cat_blob();\n+}\n \n \n # Pipe implementation for ActiveState Perl.\n-- \n1.5.5.1\n"},{"id":"77543","messageId":"1211552384-29636-7-git-send-email-barra_cuda@katamail.com","threadId":"13636","inReplyTo":"1211552384-29636-1-git-send-email-barra_cuda@katamail.com","subject":"[PATCH 6/8] git-svn: Speed up fetch","fromName":"Michele Ballabio","fromEmail":"barra_cuda@katamail.com","sentAt":"2008-05-23T14:19:41Z","receivedAt":"2008-05-23T14:19:41Z","isPatch":true,"sender":{"key":"barra_cuda@katamail.com","avatar":"https://avatars.githubusercontent.com/u/16371673?v=4"},"body":"From: Adam Roben <aroben@apple.com>\n\nWe were spending a lot of time forking/execing git-cat-file and\ngit-hash-object. We now maintain a global Git repository object in order to use\nGit.pm's more efficient hash_and_insert_object and cat_blob methods.\n\nSigned-off-by: Adam Roben <aroben@apple.com>\n---\n git-svn.perl |   42 ++++++++++++++++++++----------------------\n 1 files changed, 20 insertions(+), 22 deletions(-)\n\ndiff --git a/git-svn.perl b/git-svn.perl\nindex b70f8ef..33e9266 100755\n--- a/git-svn.perl\n+++ b/git-svn.perl\n@@ -4,7 +4,7 @@\n use warnings;\n use strict;\n use vars qw/\t$AUTHOR $VERSION\n-\t\t$sha1 $sha1_short $_revision\n+\t\t$sha1 $sha1_short $_revision $_repository\n \t\t$_q $_authors %users/;\n $AUTHOR = 'Eric Wong <normalperson@yhbt.net>';\n $VERSION = '@@GIT_VERSION@@';\n@@ -220,6 +220,7 @@ unless ($cmd && $cmd =~ /(?:clone|init|multi-init)$/) {\n \t\t}\n \t\t$ENV{GIT_DIR} = $git_dir;\n \t}\n+\t$_repository = Git->repository(Repository => $ENV{GIT_DIR});\n }\n \n my %opts = %{$cmd{$cmd}->[2]} if (defined $cmd);\n@@ -301,6 +302,7 @@ sub do_git_init_db {\n \t\t\t}\n \t\t}\n \t\tcommand_noisy(@init_db);\n+\t\t$_repository = Git->repository(Repository => \".git\");\n \t}\n \tmy $set;\n \tmy $pfx = \"svn-remote.$Git::SVN::default_repo_id\";\n@@ -317,6 +319,7 @@ sub init_subdir {\n \tmkpath([$repo_path]) unless -d $repo_path;\n \tchdir $repo_path or die \"Couldn't chdir to $repo_path: $!\\n\";\n \t$ENV{GIT_DIR} = '.git';\n+\t$_repository = Git->repository(Repository => $ENV{GIT_DIR});\n }\n \n sub cmd_clone {\n@@ -3017,6 +3020,7 @@ use vars qw/@ISA/;\n use strict;\n use warnings;\n use Carp qw/croak/;\n+use File::Temp qw/tempfile/;\n use IO::File qw//;\n \n # file baton members: path, mode_a, mode_b, pool, fh, blob, base\n@@ -3172,14 +3176,9 @@ sub apply_textdelta {\n \tmy $base = IO::File->new_tmpfile;\n \t$base->autoflush(1);\n \tif ($fb->{blob}) {\n-\t\tdefined (my $pid = fork) or croak $!;\n-\t\tif (!$pid) {\n-\t\t\topen STDOUT, '>&', $base or croak $!;\n-\t\t\tprint STDOUT 'link ' if ($fb->{mode_a} == 120000);\n-\t\t\texec qw/git-cat-file blob/, $fb->{blob} or croak $!;\n-\t\t}\n-\t\twaitpid $pid, 0;\n-\t\tcroak $? if $?;\n+\t\tprint $base 'link ' if ($fb->{mode_a} == 120000);\n+\t\tmy $size = $::_repository->cat_blob($fb->{blob}, $base);\n+\t\tdie \"Failed to read object $fb->{blob}\" unless $size;\n \n \t\tif (defined $exp) {\n \t\t\tseek $base, 0, 0 or croak $!;\n@@ -3220,14 +3219,18 @@ sub close_file {\n \t\t\t\tsysseek($fh, 0, 0) or croak $!;\n \t\t\t}\n \t\t}\n-\t\tdefined(my $pid = open my $out,'-|') or die \"Can't fork: $!\\n\";\n-\t\tif (!$pid) {\n-\t\t\topen STDIN, '<&', $fh or croak $!;\n-\t\t\texec qw/git-hash-object -w --stdin/ or croak $!;\n+\n+\t\tmy ($tmp_fh, $tmp_filename) = File::Temp::tempfile(UNLINK => 1);\n+\t\tmy $result;\n+\t\twhile ($result = sysread($fh, my $string, 1024)) {\n+\t\t\tsyswrite($tmp_fh, $string, $result);\n \t\t}\n-\t\tchomp($hash = do { local $/; <$out> });\n-\t\tclose $out or croak $!;\n+\t\tdefined $result or croak $!;\n+\t\tclose $tmp_fh or croak $!;\n+\n \t\tclose $fh or croak $!;\n+\n+\t\t$hash = $::_repository->hash_and_insert_object($tmp_filename);\n \t\t$hash =~ /^[a-f\\d]{40}$/ or die \"not a sha1: $hash\\n\";\n \t\tclose $fb->{base} or croak $!;\n \t} else {\n@@ -3553,13 +3556,8 @@ sub chg_file {\n \t} elsif ($m->{mode_a} =~ /^120/ && $m->{mode_b} !~ /^120/) {\n \t\t$self->change_file_prop($fbat,'svn:special',undef);\n \t}\n-\tdefined(my $pid = fork) or croak $!;\n-\tif (!$pid) {\n-\t\topen STDOUT, '>&', $fh or croak $!;\n-\t\texec qw/git-cat-file blob/, $m->{sha1_b} or croak $!;\n-\t}\n-\twaitpid $pid, 0;\n-\tcroak $? if $?;\n+\tmy $size = $::_repository->cat_blob($m->{sha1_b}, $fh);\n+\tcroak \"Failed to read object $m->{sha1_b}\" unless $size;\n \t$fh->flush == 0 or croak $!;\n \tseek $fh, 0, 0 or croak $!;\n \n-- \n1.5.5.1\n"},{"id":"77548","messageId":"1211552384-29636-8-git-send-email-barra_cuda@katamail.com","threadId":"13636","inReplyTo":"1211552384-29636-1-git-send-email-barra_cuda@katamail.com","subject":"[PATCH 7/8] builtin-cat-file.c: use parse_options()","fromName":"Michele Ballabio","fromEmail":"barra_cuda@katamail.com","sentAt":"2008-05-23T14:19:42Z","receivedAt":"2008-05-23T14:19:42Z","isPatch":true,"sender":{"key":"barra_cuda@katamail.com","avatar":"https://avatars.githubusercontent.com/u/16371673?v=4"},"body":"This simplifies the option parsing.\n\nSigned-off-by: Michele Ballabio <barra_cuda@katamail.com>\n---\n builtin-cat-file.c |  119 ++++++++++++++++++++--------------------------------\n 1 files changed, 46 insertions(+), 73 deletions(-)\n\ndiff --git a/builtin-cat-file.c b/builtin-cat-file.c\nindex b4d0c25..5ef15a4 100644\n--- a/builtin-cat-file.c\n+++ b/builtin-cat-file.c\n@@ -8,6 +8,10 @@\n #include \"tag.h\"\n #include \"tree.h\"\n #include \"builtin.h\"\n+#include \"parse-options.h\"\n+\n+#define BATCH 1\n+#define BATCH_CHECK 2\n \n static void pprint_tag(const unsigned char *sha1, const char *buf, unsigned long size)\n {\n@@ -158,7 +162,7 @@ static int batch_one_object(const char *obj_name, int print_contents)\n \t\treturn 0;\n \t}\n \n-\tif (print_contents)\n+\tif (print_contents == BATCH)\n \t\tcontents = read_sha1_file(sha1, &type, &size);\n \telse\n \t\ttype = sha1_object_info(sha1, &size);\n@@ -169,7 +173,7 @@ static int batch_one_object(const char *obj_name, int print_contents)\n \tprintf(\"%s %s %lu\\n\", sha1_to_hex(sha1), typename(type), size);\n \tfflush(stdout);\n \n-\tif (print_contents) {\n+\tif (print_contents == BATCH) {\n \t\twrite_or_die(1, contents, size);\n \t\tprintf(\"\\n\");\n \t\tfflush(stdout);\n@@ -192,89 +196,58 @@ static int batch_objects(int print_contents)\n \treturn 0;\n }\n \n-static const char cat_file_usage[] = \"git-cat-file [ [-t|-s|-e|-p|<type>] <sha1> | [--batch|--batch-check] < <list_of_sha1s> ]\";\n+static const char * const cat_file_usage[] = {\n+\t\"git-cat-file [-t|-s|-e|-p|<type>] <sha1>\",\n+\t\"git-cat-file [--batch|--batch-check] < <list_of_sha1s>\",\n+\tNULL\n+};\n \n int cmd_cat_file(int argc, const char **argv, const char *prefix)\n {\n-\tint i, opt = 0, batch = 0, batch_check = 0;\n+\tint opt = 0, batch = 0;\n \tconst char *exp_type = NULL, *obj_name = NULL;\n \n-\tgit_config(git_default_config);\n-\n-\tfor (i = 1; i < argc; ++i) {\n-\t\tconst char *arg = argv[i];\n-\t\tint is_batch = 0, is_batch_check = 0;\n-\n-\t\tis_batch = !strcmp(arg, \"--batch\");\n-\t\tif (!is_batch)\n-\t\t\tis_batch_check = !strcmp(arg, \"--batch-check\");\n-\n-\t\tif (is_batch || is_batch_check) {\n-\t\t\tif (opt) {\n-\t\t\t\terror(\"git-cat-file: Can't use %s with -%c\", arg, opt);\n-\t\t\t\tusage(cat_file_usage);\n-\t\t\t} else if (exp_type) {\n-\t\t\t\terror(\"git-cat-file: Can't use %s when a type (\\\"%s\\\") is specified\", arg, exp_type);\n-\t\t\t\tusage(cat_file_usage);\n-\t\t\t} else if (obj_name) {\n-\t\t\t\terror(\"git-cat-file: Can't use %s when an object (\\\"%s\\\") is specified\", arg, obj_name);\n-\t\t\t\tusage(cat_file_usage);\n-\t\t\t}\n-\n-\t\t\tif ((is_batch && batch_check) || (is_batch_check && batch)) {\n-\t\t\t\terror(\"git-cat-file: Can't use %s with %s\", arg, is_batch ? \"--batch-check\" : \"--batch\");\n-\t\t\t\tusage(cat_file_usage);\n-\t\t\t}\n-\n-\t\t\tif (is_batch)\n-\t\t\t\tbatch = 1;\n-\t\t\telse\n-\t\t\t\tbatch_check = 1;\n+\tconst struct option options[] = {\n+\t\tOPT_GROUP(\"<type> can be one of: blob, tree, commit, tag\"),\n+\t\tOPT_SET_INT('t', NULL, &opt, \"show object type\", 't'),\n+\t\tOPT_SET_INT('s', NULL, &opt, \"show object size\", 's'),\n+\t\tOPT_SET_INT('e', NULL, &opt,\n+\t\t\t    \"exit with zero when there's no error\", 'e'),\n+\t\tOPT_SET_INT('p', NULL, &opt, \"pretty-print object's content\", 'p'),\n+\t\tOPT_SET_INT(0, \"batch\", &batch,\n+\t\t\t    \"show info and content of objects feeded on stdin\", BATCH),\n+\t\tOPT_SET_INT(0, \"batch-check\", &batch,\n+\t\t\t    \"show info about objects feeded on stdin\",\n+\t\t\t    BATCH_CHECK),\n+\t\tOPT_END()\n+\t};\n \n-\t\t\tcontinue;\n-\t\t}\n-\n-\t\tif (!strcmp(arg, \"-t\") || !strcmp(arg, \"-s\") || !strcmp(arg, \"-e\") || !strcmp(arg, \"-p\")) {\n-\t\t\tif (batch || batch_check) {\n-\t\t\t\terror(\"git-cat-file: Can't use %s with %s\", arg, batch ? \"--batch\" : \"--batch-check\");\n-\t\t\t\tusage(cat_file_usage);\n-\t\t\t}\n-\n-\t\t\texp_type = arg;\n-\t\t\topt = exp_type[1];\n-\t\t\tcontinue;\n-\t\t}\n-\n-\t\tif (arg[0] == '-')\n-\t\t\tusage(cat_file_usage);\n-\n-\t\tif (!exp_type) {\n-\t\t\tif (batch || batch_check) {\n-\t\t\t\terror(\"git-cat-file: Can't specify a type (\\\"%s\\\") with %s\", arg, batch ? \"--batch\" : \"--batch-check\");\n-\t\t\t\tusage(cat_file_usage);\n-\t\t\t}\n-\n-\t\t\texp_type = arg;\n-\t\t\tcontinue;\n-\t\t}\n+\tgit_config(git_default_config);\n \n-\t\tif (obj_name)\n-\t\t\tusage(cat_file_usage);\n+\tif (argc != 3 && argc != 2)\n+\t\tusage_with_options(cat_file_usage, options);\n \n-\t\t// We should have hit one of the earlier if (batch || batch_check) cases before\n-\t\t// getting here.\n-\t\tassert(!batch);\n-\t\tassert(!batch_check);\n+\targc = parse_options(argc, argv, options, cat_file_usage, 0);\n \n-\t\tobj_name = arg;\n-\t\tbreak;\n+\tif (opt) {\n+\t\tif (argc == 1)\n+\t\t\tobj_name = argv[0];\n+\t\telse\n+\t\t\tusage_with_options(cat_file_usage, options);\n+\t}\n+\tif (!opt && !batch) {\n+\t\tif (argc == 2) {\n+\t\t\texp_type = argv[0];\n+\t\t\tobj_name = argv[1];\n+\t\t} else\n+\t\t\tusage_with_options(cat_file_usage, options);\n+\t}\n+\tif (batch && (opt || argc)) {\n+\t\tusage_with_options(cat_file_usage, options);\n \t}\n \n-\tif (batch || batch_check)\n+\tif (batch)\n \t\treturn batch_objects(batch);\n \n-\tif (!exp_type || !obj_name)\n-\t\tusage(cat_file_usage);\n-\n \treturn cat_one_file(opt, exp_type, obj_name);\n }\n-- \n1.5.5.1\n"},{"id":"77551","messageId":"1211552384-29636-9-git-send-email-barra_cuda@katamail.com","threadId":"13636","inReplyTo":"1211552384-29636-1-git-send-email-barra_cuda@katamail.com","subject":"[PATCH 8/8] change quoting in test t1006-cat-file.sh","fromName":"Michele Ballabio","fromEmail":"barra_cuda@katamail.com","sentAt":"2008-05-23T14:19:43Z","receivedAt":"2008-05-23T14:19:43Z","isPatch":true,"sender":{"key":"barra_cuda@katamail.com","avatar":"https://avatars.githubusercontent.com/u/16371673?v=4"},"body":"Signed-off-by: Michele Ballabio <barra_cuda@katamail.com>\n---\n t/t1006-cat-file.sh |    6 +++---\n 1 files changed, 3 insertions(+), 3 deletions(-)\n\ndiff --git a/t/t1006-cat-file.sh b/t/t1006-cat-file.sh\nindex d569676..cb1fbe5 100755\n--- a/t/t1006-cat-file.sh\n+++ b/t/t1006-cat-file.sh\n@@ -199,9 +199,9 @@ $tag_content\n deadbeef missing\n  missing\"\n \n-test_expect_success \\\n-    \"--batch with multiple sha1s gives correct format\" \\\n-    \"test \\\"\\$(maybe_remove_timestamp \\\"$batch_output\\\" 1)\\\" = \\\"\\$(maybe_remove_timestamp \\\"\\$(echo_without_newline \\\"$batch_input\\\" | git cat-file --batch)\\\" 1)\\\"\"\n+test_expect_success '--batch with multiple sha1s gives correct format' '\n+\ttest \"$(maybe_remove_timestamp \"$batch_output\" 1)\" = \"$(maybe_remove_timestamp \"$(echo_without_newline \"$batch_input\" | git cat-file --batch)\" 1)\"\n+'\n \n batch_check_input=\"$hello_sha1\n $tree_sha1\n-- \n1.5.5.1\n"},{"id":"77552","messageId":"1211552384-29636-10-git-send-email-barra_cuda@katamail.com","threadId":"13636","inReplyTo":"1211552384-29636-1-git-send-email-barra_cuda@katamail.com","subject":"Re: [PATCH 0/8] Speed up git-svn","fromName":"Michele Ballabio","fromEmail":"barra_cuda@katamail.com","sentAt":"2008-05-23T14:19:44Z","receivedAt":"2008-05-23T14:19:44Z","isPatch":true,"sender":{"key":"barra_cuda@katamail.com","avatar":"https://avatars.githubusercontent.com/u/16371673?v=4"},"body":"Output of \"git diff -w\" against the old version by Adam Roben of\npatches 2 and 3:\n\ndiff --git a/hash-object.c b/hash-object.c\nindex 1b39162..0a7ac2f 100644\n--- a/hash-object.c\n+++ b/hash-object.c\n@@ -6,6 +6,7 @@\n  */\n #include \"cache.h\"\n #include \"blob.h\"\n+#include \"quote.h\"\n \n static void hash_object(const char *path, enum object_type type, int write_object)\n {\n@@ -31,7 +32,7 @@ static void hash_stdin(const char *type, int write_object)\n \tprintf(\"%s\\n\", sha1_to_hex(sha1));\n }\n \n-static int hash_stdin_paths(const char *type, int write_objects)\n+static void hash_stdin_paths(const char *type, int write_objects)\n {\n \tstruct strbuf buf, nbuf;\n \n@@ -127,7 +128,7 @@ int main(int argc, char **argv)\n \t}\n \n \tif (stdin_paths)\n-\t\treturn hash_stdin_paths(type, write_object);\n+\t\thash_stdin_paths(type, write_object);\n \n \tif (hashstdin)\n \t\thash_stdin(type, write_object);\ndiff --git a/t/t1007-hash-object.sh b/t/t1007-hash-object.sh\nindex dbb4129..0526295 100755\n--- a/t/t1007-hash-object.sh\n+++ b/t/t1007-hash-object.sh\n@@ -4,23 +4,20 @@ test_description=git-hash-object\n \n . ./test-lib.sh\n \n-function echo_without_newline()\n-{\n-    echo \"$@\\c\"\n+echo_without_newline() {\n+\tprintf '%s' \"$*\"\n }\n \n-function test_blob_does_not_exist()\n-{\n-    test_expect_success \\\n-        \"blob does not exist in database\" \\\n-        \"test_must_fail git cat-file blob $1\"\n+test_blob_does_not_exist() {\n+\ttest_expect_success 'blob does not exist in database' \"\n+\t\ttest_must_fail git cat-file blob $1\n+\t\"\n }\n \n-function test_blob_exists()\n-{\n-    test_expect_success \\\n-        \"blob exists in database\" \\\n-        \"git cat-file blob $1\"\n+test_blob_exists() {\n+\ttest_expect_success 'blob exists in database' \"\n+\t\tgit cat-file blob $1\n+\t\"\n }\n \n hello_content=\"Hello World\"\n@@ -29,23 +26,20 @@ hello_sha1=5e1c309dae7f45e0f39b1bf3ac3cd9db12e7d689\n example_content=\"This is an example\"\n example_sha1=ddd3f836d3e3fbb7ae289aa9ae83536f76956399\n \n-function setup_repo()\n-{\n+setup_repo() {\n     echo_without_newline \"$hello_content\" > hello\n     echo_without_newline \"$example_content\" > example\n }\n \n test_repo=test\n-function push_repo()\n-{\n+push_repo() {\n     test_create_repo $test_repo\n     cd $test_repo\n \n     setup_repo\n }\n \n-function pop_repo()\n-{\n+pop_repo() {\n     cd ..\n     rm -rf $test_repo\n }\n@@ -54,59 +48,59 @@ setup_repo\n \n # Argument checking\n \n-test_expect_success \\\n-    \"multiple '--stdin's are rejected\" \\\n-    \"test_must_fail git hash-object --stdin --stdin < example\"\n+test_expect_success \"multiple '--stdin's are rejected\" '\n+\ttest_must_fail git hash-object --stdin --stdin < example\n+'\n \n-test_expect_success \\\n-    \"Can't use --stdin and --stdin-paths together\" \\\n-    \"test_must_fail git hash-object --stdin --stdin-paths &&\n-     test_must_fail git hash-object --stdin-paths --stdin\"\n+test_expect_success \"Can't use --stdin and --stdin-paths together\" '\n+\ttest_must_fail git hash-object --stdin --stdin-paths &&\n+\ttest_must_fail git hash-object --stdin-paths --stdin\n+'\n \n-test_expect_success \\\n-    \"Can't pass filenames as arguments with --stdin-paths\" \\\n-    \"test_must_fail git hash-object --stdin-paths hello < example\"\n+test_expect_success \"Can't pass filenames as arguments with --stdin-paths\" '\n+\ttest_must_fail git hash-object --stdin-paths hello < example\n+'\n \n # Behavior\n \n push_repo\n \n-    test_expect_success \\\n-        \"hash a file\" \\\n-        \"test $hello_sha1 = \\$(git hash-object hello)\"\n+test_expect_success 'hash a file' '\n+\ttest $hello_sha1 = $(git hash-object hello)\n+'\n \n     test_blob_does_not_exist $hello_sha1\n \n-    test_expect_success \\\n-        \"hash from stdin\" \\\n-        \"test $example_sha1 = \\$(git hash-object --stdin < example)\"\n+test_expect_success 'hash from stdin' '\n+\ttest $example_sha1 = $(git hash-object --stdin < example)\n+'\n \n     test_blob_does_not_exist $example_sha1\n \n-    test_expect_success \\\n-        \"hash a file and write to database\" \\\n-        \"test $hello_sha1 = \\$(git hash-object -w hello)\"\n+test_expect_success 'hash a file and write to database' '\n+\ttest $hello_sha1 = $(git hash-object -w hello)\n+'\n \n     test_blob_exists $hello_sha1\n \n-    test_expect_success \\\n-        'git hash-object --stdin file1 <file0 first operates on file0, then file1' \\\n-        'echo foo > file1 &&\n+test_expect_success 'git hash-object --stdin file1 <file0 first operates on file0, then file1' '\n+\techo foo > file1 &&\n         obname0=$(echo bar | git hash-object --stdin) &&\n         obname1=$(git hash-object file1) &&\n         obname0new=$(echo bar | git hash-object --stdin file1 | sed -n -e 1p) &&\n         obname1new=$(echo bar | git hash-object --stdin file1 | sed -n -e 2p) &&\n         test \"$obname0\" = \"$obname0new\" &&\n-        test \"$obname1\" = \"$obname1new\"'\n+\ttest \"$obname1\" = \"$obname1new\"\n+'\n \n pop_repo\n \n for args in \"-w --stdin\" \"--stdin -w\"; do\n     push_repo\n \n-        test_expect_success \\\n-            \"hash from stdin and write to database ($args)\" \\\n-            \"test $example_sha1 = \\$(git hash-object $args < example)\"\n+\ttest_expect_success \"hash from stdin and write to database ($args)\" '\n+\t\ttest $example_sha1 = $(git hash-object $args < example)\n+\t'\n \n         test_blob_exists $example_sha1\n \n@@ -119,16 +113,16 @@ example\"\n sha1s=\"$hello_sha1\n $example_sha1\"\n \n-test_expect_success \\\n-    \"hash two files with names on stdin\" \\\n-    \"test \\\"$sha1s\\\" = \\\"\\$(echo_without_newline \\\"$filenames\\\" | git hash-object --stdin-paths)\\\"\"\n+test_expect_success \"hash two files with names on stdin\" '\n+\ttest \"$sha1s\" = \"$(echo_without_newline \"$filenames\" | git hash-object --stdin-paths)\"\n+'\n \n for args in \"-w --stdin-paths\" \"--stdin-paths -w\"; do\n     push_repo\n \n-        test_expect_success \\\n-            \"hash two files with names on stdin and write to database ($args)\" \\\n-            \"test \\\"$sha1s\\\" = \\\"\\$(echo_without_newline \\\"$filenames\\\" | git hash-object $args)\\\"\"\n+\ttest_expect_success \"hash two files with names on stdin and write to database ($args)\" '\n+\t\ttest \"$sha1s\" = \"$(echo_without_newline \"$filenames\" | git hash-object $args)\"\n+\t'\n \n         test_blob_exists $hello_sha1\n         test_blob_exists $example_sha1\n"}]}